/[svn]/qsampler/trunk/src/qsamplerMainForm.ui.h
ViewVC logotype

Contents of /qsampler/trunk/src/qsamplerMainForm.ui.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 115 - (show annotations) (download) (as text)
Mon Jun 7 21:41:43 2004 UTC (19 years, 9 months ago) by capela
File MIME type: text/x-c++hdr
File size: 49523 byte(s)
* Comment SET CHANNEL MIDI_INPUT_PORT command from
  saveSessionFile(), it has no effect.

* Insert a n #include <unistd.h> on qsamplerMessages.h, between

* An initial non zero value (0.8) should be set for the channel
  volume, while GET CHANNEL INFO command is pending implementation.

* The order to load/save and setup channel settings is now as
  suggested in the following lines:

    SET CHANNEL AUDIO_OUTPUT_TYPE ...
    SET CHANNEL MIDI_INPUT_TYPE ...
    SET CHANNEL MIDI_INPUT_CHANNEL ...
    LOAD ENGINE ...
    LOAD INSTRUMENT ...
    SET CHANNEL VOLUME ...

1 // qsamplerMainForm.ui.h
2 //
3 // ui.h extension file, included from the uic-generated form implementation.
4 /****************************************************************************
5 Copyright (C) 2004, rncbc aka Rui Nuno Capela. All rights reserved.
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
21 *****************************************************************************/
22
23 #include <qapplication.h>
24 #include <qeventloop.h>
25 #include <qworkspace.h>
26 #include <qprocess.h>
27 #include <qmessagebox.h>
28 #include <qdragobject.h>
29 #include <qfiledialog.h>
30 #include <qfileinfo.h>
31 #include <qfile.h>
32 #include <qtextstream.h>
33 #include <qstatusbar.h>
34 #include <qlabel.h>
35 #include <qtimer.h>
36
37 #include "qsamplerAbout.h"
38 #include "qsamplerOptions.h"
39 #include "qsamplerMessages.h"
40
41 #include "qsamplerChannelStrip.h"
42 #include "qsamplerOptionsForm.h"
43
44 #include "config.h"
45
46
47 // Timer constant stuff.
48 #define QSAMPLER_TIMER_MSECS 200
49
50 // Status bar item indexes
51 #define QSAMPLER_STATUS_CLIENT 0 // Client connection state.
52 #define QSAMPLER_STATUS_SERVER 1 // Currenr server address (host:port)
53 #define QSAMPLER_STATUS_CHANNEL 2 // Active channel caption.
54 #define QSAMPLER_STATUS_SESSION 3 // Current session modification state.
55
56
57 #if defined(WIN32)
58 static WSADATA _wsaData;
59 #endif
60
61 //-------------------------------------------------------------------------
62 // qsamplerMainForm -- Main window form implementation.
63
64 // Kind of constructor.
65 void qsamplerMainForm::init (void)
66 {
67 // Initialize some pointer references.
68 m_pOptions = NULL;
69
70 // All child forms are to be created later, not earlier than setup.
71 m_pMessages = NULL;
72
73 // We'll start clean.
74 m_iUntitled = 0;
75 m_iDirtyCount = 0;
76
77 m_pServer = NULL;
78 m_pClient = NULL;
79
80 m_iStartDelay = 0;
81 m_iTimerDelay = 0;
82
83 m_iTimerSlot = 0;
84
85 // Make it an MDI workspace.
86 m_pWorkspace = new QWorkspace(this);
87 m_pWorkspace->setScrollBarsEnabled(true);
88 // Set the activation connection.
89 QObject::connect(m_pWorkspace, SIGNAL(windowActivated(QWidget *)), this, SLOT(stabilizeForm()));
90 // Make it shine :-)
91 setCentralWidget(m_pWorkspace);
92
93 // Create some statusbar labels...
94 QLabel *pLabel;
95 // Client status.
96 pLabel = new QLabel(tr("Connected"), this);
97 pLabel->setAlignment(Qt::AlignLeft);
98 pLabel->setMinimumSize(pLabel->sizeHint());
99 m_status[QSAMPLER_STATUS_CLIENT] = pLabel;
100 statusBar()->addWidget(pLabel);
101 // Server address.
102 pLabel = new QLabel(this);
103 pLabel->setAlignment(Qt::AlignLeft);
104 m_status[QSAMPLER_STATUS_SERVER] = pLabel;
105 statusBar()->addWidget(pLabel, 1);
106 // Channel title.
107 pLabel = new QLabel(this);
108 pLabel->setAlignment(Qt::AlignLeft);
109 m_status[QSAMPLER_STATUS_CHANNEL] = pLabel;
110 statusBar()->addWidget(pLabel, 2);
111 // Session modification status.
112 pLabel = new QLabel(tr("MOD"), this);
113 pLabel->setAlignment(Qt::AlignHCenter);
114 pLabel->setMinimumSize(pLabel->sizeHint());
115 m_status[QSAMPLER_STATUS_SESSION] = pLabel;
116 statusBar()->addWidget(pLabel);
117
118 // Create the recent files sub-menu.
119 m_pRecentFilesMenu = new QPopupMenu(this);
120 fileMenu->insertSeparator(4);
121 fileMenu->insertItem(tr("Recent &Files"), m_pRecentFilesMenu, 0, 5);
122
123 #if defined(WIN32)
124 WSAStartup(MAKEWORD(1, 1), &_wsaData);
125 #endif
126 }
127
128
129 // Kind of destructor.
130 void qsamplerMainForm::destroy (void)
131 {
132 // Do final processing anyway.
133 processServerExit();
134
135 // Delete recentfiles menu.
136 if (m_pRecentFilesMenu)
137 delete m_pRecentFilesMenu;
138 // Delete status item labels one by one.
139 if (m_status[QSAMPLER_STATUS_CLIENT])
140 delete m_status[QSAMPLER_STATUS_CLIENT];
141 if (m_status[QSAMPLER_STATUS_SERVER])
142 delete m_status[QSAMPLER_STATUS_SERVER];
143 if (m_status[QSAMPLER_STATUS_CHANNEL])
144 delete m_status[QSAMPLER_STATUS_CHANNEL];
145 if (m_status[QSAMPLER_STATUS_SESSION])
146 delete m_status[QSAMPLER_STATUS_SESSION];
147
148 // Finally drop any widgets around...
149 if (m_pMessages)
150 delete m_pMessages;
151 if (m_pWorkspace)
152 delete m_pWorkspace;
153
154 #if defined(WIN32)
155 WSACleanup();
156 #endif
157 }
158
159
160 // Make and set a proper setup options step.
161 void qsamplerMainForm::setup ( qsamplerOptions *pOptions )
162 {
163 // We got options?
164 m_pOptions = pOptions;
165
166 // Some child forms are to be created right now.
167 m_pMessages = new qsamplerMessages(this);
168 // Set message defaults...
169 updateMessagesFont();
170 updateMessagesLimit();
171 updateMessagesCapture();
172 // Set the visibility signal.
173 QObject::connect(m_pMessages, SIGNAL(visibilityChanged(bool)), this, SLOT(stabilizeForm()));
174
175 // Initial decorations toggle state.
176 viewMenubarAction->setOn(m_pOptions->bMenubar);
177 viewToolbarAction->setOn(m_pOptions->bToolbar);
178 viewStatusbarAction->setOn(m_pOptions->bStatusbar);
179 channelsAutoArrangeAction->setOn(m_pOptions->bAutoArrange);
180
181 // Initial decorations visibility state.
182 viewMenubar(m_pOptions->bMenubar);
183 viewToolbar(m_pOptions->bToolbar);
184 viewStatusbar(m_pOptions->bStatusbar);
185
186 // Restore whole dock windows state.
187 QString sDockables = m_pOptions->settings().readEntry("/Layout/DockWindows" , QString::null);
188 if (sDockables.isEmpty()) {
189 // Message window is forced to dock on the bottom.
190 moveDockWindow(m_pMessages, Qt::DockBottom);
191 } else {
192 // Make it as the last time.
193 QTextIStream istr(&sDockables);
194 istr >> *this;
195 }
196 // Try to restore old window positioning.
197 m_pOptions->loadWidgetGeometry(this);
198
199 // Final startup stabilization...
200 updateRecentFilesMenu();
201 stabilizeForm();
202
203 // Make it ready :-)
204 statusBar()->message(tr("Ready"), 3000);
205
206 // We'll try to start immediately...
207 startSchedule(0);
208
209 // Register the first timer slot.
210 QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
211 }
212
213
214 // Window close event handlers.
215 bool qsamplerMainForm::queryClose (void)
216 {
217 bool bQueryClose = closeSession(false);
218
219 // Try to save current general state...
220 if (m_pOptions) {
221 // Some windows default fonts is here on demand too.
222 if (bQueryClose && m_pMessages)
223 m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();
224 // Try to save current positioning.
225 if (bQueryClose) {
226 // Save decorations state.
227 m_pOptions->bMenubar = MenuBar->isVisible();
228 m_pOptions->bToolbar = (fileToolbar->isVisible() || editToolbar->isVisible() || channelsToolbar->isVisible());
229 m_pOptions->bStatusbar = statusBar()->isVisible();
230 // Save the dock windows state.
231 QString sDockables;
232 QTextOStream ostr(&sDockables);
233 ostr << *this;
234 m_pOptions->settings().writeEntry("/Layout/DockWindows", sDockables);
235 // And the main windows state.
236 m_pOptions->saveWidgetGeometry(this);
237 // Stop client and/or server, gracefully.
238 stopServer();
239 }
240 }
241
242 return bQueryClose;
243 }
244
245
246 void qsamplerMainForm::closeEvent ( QCloseEvent *pCloseEvent )
247 {
248 if (queryClose())
249 pCloseEvent->accept();
250 else
251 pCloseEvent->ignore();
252 }
253
254
255 void qsamplerMainForm::dragEnterEvent ( QDragEnterEvent* pDragEnterEvent )
256 {
257 bool bAccept = false;
258
259 if (QTextDrag::canDecode(pDragEnterEvent)) {
260 QString sUrl;
261 if (QTextDrag::decode(pDragEnterEvent, sUrl) && m_pClient)
262 bAccept = QFileInfo(QUrl(sUrl).path()).exists();
263 }
264
265 pDragEnterEvent->accept(bAccept);
266 }
267
268
269 void qsamplerMainForm::dropEvent ( QDropEvent* pDropEvent )
270 {
271 if (QTextDrag::canDecode(pDropEvent)) {
272 QString sUrl;
273 if (QTextDrag::decode(pDropEvent, sUrl) && closeSession(true))
274 loadSessionFile(QUrl(sUrl).path());
275 }
276 }
277
278
279 //-------------------------------------------------------------------------
280 // qsamplerMainForm -- Brainless public property accessors.
281
282 // The global options settings property.
283 qsamplerOptions *qsamplerMainForm::options (void)
284 {
285 return m_pOptions;
286 }
287
288 // The LSCP client descriptor property.
289 lscp_client_t *qsamplerMainForm::client (void)
290 {
291 return m_pClient;
292 }
293
294
295 //-------------------------------------------------------------------------
296 // qsamplerMainForm -- Session file stuff.
297
298 // Format the displayable session filename.
299 QString qsamplerMainForm::sessionName ( const QString& sFilename )
300 {
301 bool bCompletePath = (m_pOptions && m_pOptions->bCompletePath);
302 QString sSessionName = sFilename;
303 if (sSessionName.isEmpty())
304 sSessionName = tr("Untitled") + QString::number(m_iUntitled);
305 else if (!bCompletePath)
306 sSessionName = QFileInfo(sSessionName).fileName();
307 return sSessionName;
308 }
309
310
311 // Create a new session file from scratch.
312 bool qsamplerMainForm::newSession (void)
313 {
314 // Check if we can do it.
315 if (!closeSession(true))
316 return false;
317
318 // Ok increment untitled count.
319 m_iUntitled++;
320
321 // Stabilize form.
322 m_sFilename = QString::null;
323 m_iDirtyCount = 0;
324 appendMessages(tr("New session: \"%1\".").arg(sessionName(m_sFilename)));
325 stabilizeForm();
326
327 return true;
328 }
329
330
331 // Open an existing sampler session.
332 bool qsamplerMainForm::openSession (void)
333 {
334 if (m_pOptions == NULL)
335 return false;
336
337 // Ask for the filename to open...
338 QString sFilename = QFileDialog::getOpenFileName(
339 m_pOptions->sSessionDir, // Start here.
340 tr("LSCP Session files") + " (*.lscp)", // Filter (LSCP files)
341 this, 0, // Parent and name (none)
342 tr("Open Session") // Caption.
343 );
344
345 // Have we cancelled?
346 if (sFilename.isEmpty())
347 return false;
348
349 // Check if we're going to discard safely the current one...
350 if (!closeSession(true))
351 return false;
352
353 // Load it right away.
354 return loadSessionFile(sFilename);
355 }
356
357
358 // Save current sampler session with another name.
359 bool qsamplerMainForm::saveSession ( bool bPrompt )
360 {
361 if (m_pOptions == NULL)
362 return false;
363
364 QString sFilename = m_sFilename;
365
366 // Ask for the file to save, if there's none...
367 if (bPrompt || sFilename.isEmpty()) {
368 // If none is given, assume default directory.
369 if (sFilename.isEmpty())
370 sFilename = m_pOptions->sSessionDir;
371 // Prompt the guy...
372 sFilename = QFileDialog::getSaveFileName(
373 sFilename, // Start here.
374 tr("LSCP Session files") + " (*.lscp)", // Filter (LSCP files)
375 this, 0, // Parent and name (none)
376 tr("Save Session") // Caption.
377 );
378 // Have we cancelled it?
379 if (sFilename.isEmpty())
380 return false;
381 // Enforce .lscp extension...
382 if (QFileInfo(sFilename).extension().isEmpty())
383 sFilename += ".lscp";
384 // Check if already exists...
385 if (sFilename != m_sFilename && QFileInfo(sFilename).exists()) {
386 if (QMessageBox::warning(this, tr("Warning"),
387 tr("The file already exists:\n\n"
388 "\"%1\"\n\n"
389 "Do you want to replace it?")
390 .arg(sFilename),
391 tr("Replace"), tr("Cancel")) > 0)
392 return false;
393 }
394 }
395
396 // Save it right away.
397 return saveSessionFile(sFilename);
398 }
399
400
401 // Close current session.
402 bool qsamplerMainForm::closeSession ( bool bForce )
403 {
404 bool bClose = true;
405
406 // Are we dirty enough to prompt it?
407 if (m_iDirtyCount > 0) {
408 switch (QMessageBox::warning(this, tr("Warning"),
409 tr("The current session has been changed:\n\n"
410 "\"%1\"\n\n"
411 "Do you want to save the changes?")
412 .arg(sessionName(m_sFilename)),
413 tr("Save"), tr("Discard"), tr("Cancel"))) {
414 case 0: // Save...
415 bClose = saveSession(false);
416 // Fall thru....
417 case 1: // Discard
418 break;
419 default: // Cancel.
420 bClose = false;
421 break;
422 }
423 }
424
425 // If we may close it, dot it.
426 if (bClose) {
427 // Remove all channel strips from sight...
428 m_pWorkspace->setUpdatesEnabled(false);
429 QWidgetList wlist = m_pWorkspace->windowList();
430 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
431 qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
432 if (bForce && ::lscp_remove_channel(m_pClient, pChannel->channelID()) != LSCP_OK)
433 appendMessagesClient("lscp_remove_channel");
434 delete pChannel;
435 }
436 m_pWorkspace->setUpdatesEnabled(true);
437 // We're now clean, for sure.
438 m_iDirtyCount = 0;
439 }
440
441 return bClose;
442 }
443
444
445 // Load a session from specific file path.
446 bool qsamplerMainForm::loadSessionFile ( const QString& sFilename )
447 {
448 if (m_pClient == NULL)
449 return false;
450
451 // Open and read from real file.
452 QFile file(sFilename);
453 if (!file.open(IO_ReadOnly)) {
454 appendMessagesError(tr("Could not open \"%1\" session file.\n\nSorry.").arg(sFilename));
455 return false;
456 }
457
458 // Read the file.
459 int iErrors = 0;
460 QTextStream ts(&file);
461 while (!ts.atEnd()) {
462 // Read the line.
463 QString sCommand = ts.readLine().simplifyWhiteSpace();
464 // If not empty, nor a comment, call the server...
465 if (!sCommand.isEmpty() && sCommand[0] != '#') {
466 appendMessagesColor(sCommand, "#996633");
467 // Remember that, no matter what,
468 // all LSCP commands are CR/LF terminated.
469 sCommand += "\r\n";
470 if (::lscp_client_query(m_pClient, sCommand.latin1()) != LSCP_OK) {
471 appendMessagesClient("lscp_client_query");
472 iErrors++;
473 }
474 }
475 // Try to make it snappy :)
476 QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
477 }
478
479 // Ok. we've read it.
480 file.close();
481
482 // Have we any errors?
483 if (iErrors > 0)
484 appendMessagesError(tr("Some setttings could not be loaded\nfrom \"%1\" session file.\n\nSorry.").arg(sFilename));
485
486 // Now we'll try to create the whole GUI session.
487 int iChannels = ::lscp_get_channels(m_pClient);
488 if (iChannels < 0) {
489 appendMessagesClient("lscp_get_channels");
490 appendMessagesError(tr("Could not get current number of channels.\n\nSorry."));
491 }
492
493 // Try to (re)create each channel.
494 m_pWorkspace->setUpdatesEnabled(false);
495 for (int iChannelID = 0; iChannelID < iChannels; iChannelID++) {
496 createChannel(iChannelID, false);
497 QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
498 }
499 m_pWorkspace->setUpdatesEnabled(true);
500
501 // Save as default session directory.
502 if (m_pOptions)
503 m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);
504 // We're not dirty anymore.
505 m_iDirtyCount = 0;
506 // Stabilize form...
507 m_sFilename = sFilename;
508 updateRecentFiles(sFilename);
509 appendMessages(tr("Open session: \"%1\".").arg(sessionName(m_sFilename)));
510 stabilizeForm();
511 return true;
512 }
513
514
515 // Save current session to specific file path.
516 bool qsamplerMainForm::saveSessionFile ( const QString& sFilename )
517 {
518 // Open and write into real file.
519 QFile file(sFilename);
520 if (!file.open(IO_WriteOnly | IO_Truncate)) {
521 appendMessagesError(tr("Could not open \"%1\" session file.\n\nSorry.").arg(sFilename));
522 return false;
523 }
524
525 // Write the file.
526 int iErrors = 0;
527 QTextStream ts(&file);
528 ts << "# " << QSAMPLER_TITLE " - " << tr(QSAMPLER_SUBTITLE) << endl;
529 ts << "# " << tr("Version")
530 << ": " QSAMPLER_VERSION << endl;
531 ts << "# " << tr("Build")
532 << ": " __DATE__ " " __TIME__ << endl;
533 ts << "#" << endl;
534 ts << "# " << tr("File")
535 << ": " << QFileInfo(sFilename).fileName() << endl;
536 ts << "# " << tr("Date")
537 << ": " << QDate::currentDate().toString("MMMM dd yyyy")
538 << " " << QTime::currentTime().toString("hh:mm:ss") << endl;
539 ts << "#" << endl;
540 ts << endl;
541 QWidgetList wlist = m_pWorkspace->windowList();
542 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
543 qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
544 int iChannelID = pChannel->channelID();
545 ts << "# " << pChannel->caption() << endl;
546 ts << "ADD CHANNEL" << endl;
547 ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannelID << " " << pChannel->audioDriver() << endl;
548 ts << "SET CHANNEL MIDI_INPUT_TYPE " << iChannelID << " " << pChannel->midiDriver() << endl;
549 // ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannelID << " " << pChannel->midiPort() << endl;
550 ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannelID << " " << pChannel->midiChannel() << endl;
551 ts << "LOAD ENGINE " << pChannel->engineName() << " " << iChannelID << endl;
552 ts << "LOAD INSTRUMENT " << pChannel->instrumentFile() << " " << pChannel->instrumentNr() << " " << iChannelID << endl;
553 ts << "SET CHANNEL VOLUME " << iChannelID << " " << pChannel->volume() << endl;
554 ts << endl;
555 // Try to keep it snappy :)
556 QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
557 }
558
559 // Ok. we've wrote it.
560 file.close();
561
562 // Have we any errors?
563 if (iErrors > 0)
564 appendMessagesError(tr("Some settings could not be saved\nto \"%1\" session file.\n\nSorry.").arg(sFilename));
565
566 // Save as default session directory.
567 if (m_pOptions)
568 m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);
569 // We're not dirty anymore.
570 m_iDirtyCount = 0;
571 // Stabilize form...
572 m_sFilename = sFilename;
573 updateRecentFiles(sFilename);
574 appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename)));
575 stabilizeForm();
576 return true;
577 }
578
579
580 //-------------------------------------------------------------------------
581 // qsamplerMainForm -- File Action slots.
582
583 // Create a new sampler session.
584 void qsamplerMainForm::fileNew (void)
585 {
586 // Of course we'll start clean new.
587 newSession();
588 }
589
590
591 // Open an existing sampler session.
592 void qsamplerMainForm::fileOpen (void)
593 {
594 // Open it right away.
595 openSession();
596 }
597
598
599 // Open a recent file session.
600 void qsamplerMainForm::fileOpenRecent ( int iIndex )
601 {
602 // Check if we can safely close the current session...
603 if (m_pOptions && closeSession(true)) {
604 QString sFilename = m_pOptions->recentFiles[iIndex];
605 loadSessionFile(sFilename);
606 }
607 }
608
609
610 // Save current sampler session.
611 void qsamplerMainForm::fileSave (void)
612 {
613 // Save it right away.
614 saveSession(false);
615 }
616
617
618 // Save current sampler session with another name.
619 void qsamplerMainForm::fileSaveAs (void)
620 {
621 // Save it right away, maybe with another name.
622 saveSession(true);
623 }
624
625
626 // Restart the client/server instance.
627 void qsamplerMainForm::fileRestart (void)
628 {
629 if (m_pOptions == NULL)
630 return;
631
632 bool bRestart = true;
633
634 // Ask user whether he/she want's a complete restart...
635 // (if we're currently up and running)
636 if (bRestart && m_pClient) {
637 bRestart = (QMessageBox::warning(this, tr("Warning"),
638 tr("New settings will be effective after\n"
639 "restarting the client/server connection.\n\n"
640 "Please note that this operation may cause\n"
641 "temporary MIDI and Audio disruption\n\n"
642 "Do you want to restart the connection now?"),
643 tr("Restart"), tr("Cancel")) == 0);
644 }
645
646 // Are we still for it?
647 if (bRestart && closeSession(true)) {
648 // Stop server, it will force the client too.
649 stopServer();
650 // Reschedule a restart...
651 startSchedule(m_pOptions->iStartDelay);
652 }
653 }
654
655
656 // Exit application program.
657 void qsamplerMainForm::fileExit (void)
658 {
659 // Go for close the whole thing.
660 close();
661 }
662
663
664 //-------------------------------------------------------------------------
665 // qsamplerMainForm -- Edit Action slots.
666
667 // Add a new sampler channel.
668 void qsamplerMainForm::editAddChannel (void)
669 {
670 if (m_pClient == NULL)
671 return;
672
673 // Create the new sampler channel.
674 int iChannelID = ::lscp_add_channel(m_pClient);
675 if (iChannelID < 0) {
676 appendMessagesClient("lscp_add_channel");
677 appendMessagesError(tr("Could not create the new channel.\n\nSorry."));
678 return;
679 }
680
681 // Log this happening.
682 appendMessages(tr("Channel %1 created.").arg(iChannelID));
683
684 // Just create the channel strip with given id.
685 createChannel(iChannelID, true);
686
687 // We'll be dirty, for sure...
688 m_iDirtyCount++;
689 // Stabilize form anyway.
690 stabilizeForm();
691 }
692
693
694 // Remove current sampler channel.
695 void qsamplerMainForm::editRemoveChannel (void)
696 {
697 if (m_pClient == NULL)
698 return;
699
700 qsamplerChannelStrip *pChannel = activeChannel();
701 if (pChannel == NULL)
702 return;
703
704 // Prompt user if he/she's sure about this...
705 if (m_pOptions && m_pOptions->bConfirmRemove) {
706 if (QMessageBox::warning(this, tr("Warning"),
707 tr("About to remove channel:\n\n"
708 "%1\n\n"
709 "Are you sure?")
710 .arg(pChannel->caption()),
711 tr("OK"), tr("Cancel")) > 0)
712 return;
713 }
714
715 // Remove the existing sampler channel.
716 if (::lscp_remove_channel(m_pClient, pChannel->channelID()) != LSCP_OK) {
717 appendMessagesClient("lscp_remove_channel");
718 appendMessagesError(tr("Could not remove channel.\n\nSorry."));
719 return;
720 }
721
722 // Log this happening.
723 appendMessages(tr("Channel %1 removed.").arg(pChannel->channelID()));
724
725 // Just delete the channel strip.
726 delete pChannel;
727 // Do we auto-arrange?
728 if (m_pOptions && m_pOptions->bAutoArrange)
729 channelsArrange();
730
731 // We'll be dirty, for sure...
732 m_iDirtyCount++;
733 stabilizeForm();
734 }
735
736
737 // Setup current sampler channel.
738 void qsamplerMainForm::editSetupChannel (void)
739 {
740 if (m_pClient == NULL)
741 return;
742
743 qsamplerChannelStrip *pChannel = activeChannel();
744 if (pChannel == NULL)
745 return;
746
747 // Just invoque the channel strip procedure.
748 pChannel->channelSetup();
749 }
750
751
752 // Reset current sampler channel.
753 void qsamplerMainForm::editResetChannel (void)
754 {
755 if (m_pClient == NULL)
756 return;
757
758 qsamplerChannelStrip *pChannel = activeChannel();
759 if (pChannel == NULL)
760 return;
761
762 // Remove the existing sampler channel.
763 if (::lscp_reset_channel(m_pClient, pChannel->channelID()) != LSCP_OK) {
764 appendMessagesClient("lscp_reset_channel");
765 appendMessagesError(tr("Could not reset channel.\n\nSorry."));
766 return;
767 }
768
769 // Log this.
770 appendMessages(tr("Channel %1 reset.").arg(pChannel->channelID()));
771
772 // Refresh channel strip info.
773 pChannel->updateChannelInfo();
774 }
775
776
777 //-------------------------------------------------------------------------
778 // qsamplerMainForm -- View Action slots.
779
780 // Show/hide the main program window menubar.
781 void qsamplerMainForm::viewMenubar ( bool bOn )
782 {
783 if (bOn)
784 MenuBar->show();
785 else
786 MenuBar->hide();
787 }
788
789
790 // Show/hide the main program window toolbar.
791 void qsamplerMainForm::viewToolbar ( bool bOn )
792 {
793 if (bOn) {
794 fileToolbar->show();
795 editToolbar->show();
796 channelsToolbar->show();
797 } else {
798 fileToolbar->hide();
799 editToolbar->hide();
800 channelsToolbar->hide();
801 }
802 }
803
804
805 // Show/hide the main program window statusbar.
806 void qsamplerMainForm::viewStatusbar ( bool bOn )
807 {
808 if (bOn)
809 statusBar()->show();
810 else
811 statusBar()->hide();
812 }
813
814
815 // Show/hide the messages window logger.
816 void qsamplerMainForm::viewMessages ( bool bOn )
817 {
818 if (bOn)
819 m_pMessages->show();
820 else
821 m_pMessages->hide();
822 }
823
824
825 // Show options dialog.
826 void qsamplerMainForm::viewOptions (void)
827 {
828 if (m_pOptions == NULL)
829 return;
830
831 qsamplerOptionsForm *pOptionsForm = new qsamplerOptionsForm(this);
832 if (pOptionsForm) {
833 // Check out some initial nullities(tm)...
834 qsamplerChannelStrip *pChannel = activeChannel();
835 if (m_pOptions->sDisplayFont.isEmpty() && pChannel)
836 m_pOptions->sDisplayFont = pChannel->displayFont().toString();
837 if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages)
838 m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();
839 // To track down deferred or immediate changes.
840 QString sOldServerHost = m_pOptions->sServerHost;
841 int iOldServerPort = m_pOptions->iServerPort;
842 int iOldServerTimeout = m_pOptions->iServerTimeout;
843 bool bOldServerStart = m_pOptions->bServerStart;
844 QString sOldServerCmdLine = m_pOptions->sServerCmdLine;
845 QString sOldDisplayFont = m_pOptions->sDisplayFont;
846 QString sOldMessagesFont = m_pOptions->sMessagesFont;
847 bool bOldStdoutCapture = m_pOptions->bStdoutCapture;
848 int bOldMessagesLimit = m_pOptions->bMessagesLimit;
849 int iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines;
850 bool bOldCompletePath = m_pOptions->bCompletePath;
851 int iOldMaxRecentFiles = m_pOptions->iMaxRecentFiles;
852 // Load the current setup settings.
853 pOptionsForm->setup(m_pOptions);
854 // Show the setup dialog...
855 if (pOptionsForm->exec()) {
856 // Warn if something will be only effective on next run.
857 if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) ||
858 (!bOldStdoutCapture && m_pOptions->bStdoutCapture)) {
859 QMessageBox::information(this, tr("Information"),
860 tr("Some settings may be only effective\n"
861 "next time you start this program."), tr("OK"));
862 updateMessagesCapture();
863 }
864 // Check wheather something immediate has changed.
865 if (( bOldCompletePath && !m_pOptions->bCompletePath) ||
866 (!bOldCompletePath && m_pOptions->bCompletePath) ||
867 (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles))
868 updateRecentFilesMenu();
869 if (sOldDisplayFont != m_pOptions->sDisplayFont)
870 updateDisplayFont();
871 if (sOldMessagesFont != m_pOptions->sMessagesFont)
872 updateMessagesFont();
873 if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) ||
874 (!bOldMessagesLimit && m_pOptions->bMessagesLimit) ||
875 (iOldMessagesLimitLines != m_pOptions->iMessagesLimitLines))
876 updateMessagesLimit();
877 // And now the main thing, whether we'll do client/server recycling?
878 if ((sOldServerHost != m_pOptions->sServerHost) ||
879 (iOldServerPort != m_pOptions->iServerPort) ||
880 (iOldServerTimeout != m_pOptions->iServerTimeout) ||
881 ( bOldServerStart && !m_pOptions->bServerStart) ||
882 (!bOldServerStart && m_pOptions->bServerStart) ||
883 (sOldServerCmdLine != m_pOptions->sServerCmdLine && m_pOptions->bServerStart))
884 fileRestart();
885 }
886 // Done.
887 delete pOptionsForm;
888 }
889
890 // This makes it.
891 stabilizeForm();
892 }
893
894
895 //-------------------------------------------------------------------------
896 // qsamplerMainForm -- Channels action slots.
897
898 // Arrange channel strips.
899 void qsamplerMainForm::channelsArrange (void)
900 {
901 // Full width vertical tiling
902 QWidgetList wlist = m_pWorkspace->windowList();
903 if (wlist.isEmpty())
904 return;
905
906 m_pWorkspace->setUpdatesEnabled(false);
907 int y = 0;
908 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
909 qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
910 /* if (pChannel->testWState(WState_Maximized | WState_Minimized)) {
911 // Prevent flicker...
912 pChannel->hide();
913 pChannel->showNormal();
914 } */
915 pChannel->adjustSize();
916 int iWidth = m_pWorkspace->width();
917 if (iWidth < pChannel->width())
918 iWidth = pChannel->width();
919 // int iHeight = pChannel->height() + pChannel->parentWidget()->baseSize().height();
920 int iHeight = pChannel->parentWidget()->frameGeometry().height();
921 pChannel->parentWidget()->setGeometry(0, y, iWidth, iHeight);
922 y += iHeight;
923 }
924 m_pWorkspace->setUpdatesEnabled(true);
925
926 stabilizeForm();
927 }
928
929
930 // Auto-arrange channel strips.
931 void qsamplerMainForm::channelsAutoArrange ( bool bOn )
932 {
933 if (m_pOptions == NULL)
934 return;
935
936 // Toggle the auto-arrange flag.
937 m_pOptions->bAutoArrange = bOn;
938
939 // If on, update whole workspace...
940 if (m_pOptions->bAutoArrange)
941 channelsArrange();
942 }
943
944
945 //-------------------------------------------------------------------------
946 // qsamplerMainForm -- Help Action slots.
947
948 // Show information about the Qt toolkit.
949 void qsamplerMainForm::helpAboutQt (void)
950 {
951 QMessageBox::aboutQt(this);
952 }
953
954
955 // Show information about application program.
956 void qsamplerMainForm::helpAbout (void)
957 {
958 // Stuff the about box text...
959 QString sText = "<p>\n";
960 sText += "<b>" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "</b><br />\n";
961 sText += "<br />\n";
962 sText += tr("Version") + ": <b>" QSAMPLER_VERSION "</b><br />\n";
963 sText += "<small>" + tr("Build") + ": " __DATE__ " " __TIME__ "</small><br />\n";
964 #ifdef CONFIG_DEBUG
965 sText += "<small><font color=\"red\">";
966 sText += tr("Debugging option enabled.");
967 sText += "</font></small><br />";
968 #endif
969 sText += "<br />\n";
970 sText += tr("Using") + ": ";
971 sText += ::lscp_client_package();
972 sText += " ";
973 sText += ::lscp_client_version();
974 sText += "<br />\n";
975 sText += "<br />\n";
976 sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";
977 sText += "<br />\n";
978 sText += "<small>";
979 sText += QSAMPLER_COPYRIGHT "<br />\n";
980 sText += "<br />\n";
981 sText += tr("This program is free software; you can redistribute it and/or modify it") + "<br />\n";
982 sText += tr("under the terms of the GNU General Public License version 2 or later.");
983 sText += "</small>";
984 sText += "</p>\n";
985
986 QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText);
987 }
988
989
990 //-------------------------------------------------------------------------
991 // qsamplerMainForm -- Main window stabilization.
992
993 void qsamplerMainForm::stabilizeForm (void)
994 {
995 // Update the main application caption...
996 QString sSessioName = sessionName(m_sFilename);
997 if (m_iDirtyCount > 0)
998 sSessioName += '*';
999 setCaption(tr(QSAMPLER_TITLE " - [%1]").arg(sSessioName));
1000
1001 // Update the main menu state...
1002 qsamplerChannelStrip *pChannel = activeChannel();
1003 bool bHasClient = (m_pOptions != NULL && m_pClient != NULL);
1004 bool bHasChannel = (bHasClient && pChannel != NULL);
1005 fileNewAction->setEnabled(bHasClient);
1006 fileOpenAction->setEnabled(bHasClient);
1007 fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);
1008 fileSaveAsAction->setEnabled(bHasClient);
1009 fileRestartAction->setEnabled(bHasClient || m_pServer == NULL);
1010 editAddChannelAction->setEnabled(bHasClient);
1011 editRemoveChannelAction->setEnabled(bHasChannel);
1012 editSetupChannelAction->setEnabled(bHasChannel);
1013 editResetChannelAction->setEnabled(bHasChannel);
1014 channelsArrangeAction->setEnabled(bHasChannel);
1015 viewMessagesAction->setOn(m_pMessages && m_pMessages->isVisible());
1016
1017 // Client/Server status...
1018 if (bHasClient) {
1019 m_status[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));
1020 m_status[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost + ":" + QString::number(m_pOptions->iServerPort));
1021 } else {
1022 m_status[QSAMPLER_STATUS_CLIENT]->clear();
1023 m_status[QSAMPLER_STATUS_SERVER]->clear();
1024 }
1025 // Channel status...
1026 if (bHasChannel)
1027 m_status[QSAMPLER_STATUS_CHANNEL]->setText(pChannel->caption());
1028 else
1029 m_status[QSAMPLER_STATUS_CHANNEL]->clear();
1030 // Session status...
1031 if (m_iDirtyCount > 0)
1032 m_status[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));
1033 else
1034 m_status[QSAMPLER_STATUS_SESSION]->clear();
1035
1036 // Recent files menu.
1037 m_pRecentFilesMenu->setEnabled(bHasClient && m_pOptions->recentFiles.count() > 0);
1038
1039 // Always make the latest message visible.
1040 if (m_pMessages)
1041 m_pMessages->scrollToBottom();
1042 }
1043
1044
1045 // Channel change receiver slot.
1046 void qsamplerMainForm::channelChanged( qsamplerChannelStrip * )
1047 {
1048 // Just mark the dirty form.
1049 m_iDirtyCount++;
1050 // and update the form status...
1051 stabilizeForm();
1052 }
1053
1054
1055 // Update the recent files list and menu.
1056 void qsamplerMainForm::updateRecentFiles ( const QString& sFilename )
1057 {
1058 if (m_pOptions == NULL)
1059 return;
1060
1061 // Remove from list if already there (avoid duplicates)
1062 QStringList::Iterator iter = m_pOptions->recentFiles.find(sFilename);
1063 if (iter != m_pOptions->recentFiles.end())
1064 m_pOptions->recentFiles.remove(iter);
1065 // Put it to front...
1066 m_pOptions->recentFiles.push_front(sFilename);
1067
1068 // May update the menu.
1069 updateRecentFilesMenu();
1070 }
1071
1072
1073 // Update the recent files list and menu.
1074 void qsamplerMainForm::updateRecentFilesMenu (void)
1075 {
1076 if (m_pOptions == NULL)
1077 return;
1078
1079 // Time to keep the list under limits.
1080 int iRecentFiles = m_pOptions->recentFiles.count();
1081 while (iRecentFiles > m_pOptions->iMaxRecentFiles) {
1082 m_pOptions->recentFiles.pop_back();
1083 iRecentFiles--;
1084 }
1085
1086 // rebuild the recent files menu...
1087 m_pRecentFilesMenu->clear();
1088 for (int i = 0; i < iRecentFiles; i++) {
1089 const QString& sFilename = m_pOptions->recentFiles[i];
1090 if (QFileInfo(sFilename).exists()) {
1091 m_pRecentFilesMenu->insertItem(QString("&%1 %2")
1092 .arg(i + 1).arg(sessionName(sFilename)),
1093 this, SLOT(fileOpenRecent(int)), 0, i);
1094 }
1095 }
1096 }
1097
1098
1099 // Force update of the channels display font.
1100 void qsamplerMainForm::updateDisplayFont (void)
1101 {
1102 if (m_pOptions == NULL)
1103 return;
1104
1105 // Check if display font is legal.
1106 if (m_pOptions->sDisplayFont.isEmpty())
1107 return;
1108 // Realize it.
1109 QFont font;
1110 if (!font.fromString(m_pOptions->sDisplayFont))
1111 return;
1112
1113 // Full channel list update...
1114 QWidgetList wlist = m_pWorkspace->windowList();
1115 if (wlist.isEmpty())
1116 return;
1117
1118 m_pWorkspace->setUpdatesEnabled(false);
1119 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1120 qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1121 pChannel->setDisplayFont(font);
1122 }
1123 m_pWorkspace->setUpdatesEnabled(true);
1124 }
1125
1126
1127 //-------------------------------------------------------------------------
1128 // qsamplerMainForm -- Messages window form handlers.
1129
1130 // Messages output methods.
1131 void qsamplerMainForm::appendMessages( const QString& s )
1132 {
1133 if (m_pMessages)
1134 m_pMessages->appendMessages(s);
1135
1136 statusBar()->message(s, 3000);
1137 }
1138
1139 void qsamplerMainForm::appendMessagesColor( const QString& s, const QString& c )
1140 {
1141 if (m_pMessages)
1142 m_pMessages->appendMessagesColor(s, c);
1143
1144 statusBar()->message(s, 3000);
1145 }
1146
1147 void qsamplerMainForm::appendMessagesText( const QString& s )
1148 {
1149 if (m_pMessages)
1150 m_pMessages->appendMessagesText(s);
1151 }
1152
1153 void qsamplerMainForm::appendMessagesError( const QString& s )
1154 {
1155 if (m_pMessages)
1156 m_pMessages->show();
1157
1158 appendMessagesColor(s.simplifyWhiteSpace(), "#ff0000");
1159
1160 QMessageBox::critical(this, tr("Error"), s, tr("Cancel"));
1161 }
1162
1163
1164 // This is a special message format, just for client results.
1165 void qsamplerMainForm::appendMessagesClient( const QString& s )
1166 {
1167 if (m_pClient == NULL)
1168 return;
1169
1170 appendMessagesColor(s + QString(": %1 (errno=%2)")
1171 .arg(::lscp_client_get_result(m_pClient))
1172 .arg(::lscp_client_get_errno(m_pClient)), "#996666");
1173 }
1174
1175
1176 // Force update of the messages font.
1177 void qsamplerMainForm::updateMessagesFont (void)
1178 {
1179 if (m_pOptions == NULL)
1180 return;
1181
1182 if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {
1183 QFont font;
1184 if (font.fromString(m_pOptions->sMessagesFont))
1185 m_pMessages->setMessagesFont(font);
1186 }
1187 }
1188
1189
1190 // Update messages window line limit.
1191 void qsamplerMainForm::updateMessagesLimit (void)
1192 {
1193 if (m_pOptions == NULL)
1194 return;
1195
1196 if (m_pMessages) {
1197 if (m_pOptions->bMessagesLimit)
1198 m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);
1199 else
1200 m_pMessages->setMessagesLimit(0);
1201 }
1202 }
1203
1204
1205 // Enablement of the messages capture feature.
1206 void qsamplerMainForm::updateMessagesCapture (void)
1207 {
1208 if (m_pOptions == NULL)
1209 return;
1210
1211 if (m_pMessages)
1212 m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);
1213 }
1214
1215
1216 //-------------------------------------------------------------------------
1217 // qsamplerMainForm -- MDI channel strip management.
1218
1219 // The channel strip creation executive.
1220 void qsamplerMainForm::createChannel ( int iChannelID, bool bPrompt )
1221 {
1222 if (m_pClient == NULL)
1223 return;
1224
1225 // Prepare for auto-arrange?
1226 qsamplerChannelStrip *pChannel = NULL;
1227 int y = 0;
1228 if (m_pOptions && m_pOptions->bAutoArrange) {
1229 QWidgetList wlist = m_pWorkspace->windowList();
1230 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1231 pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1232 // y += pChannel->height() + pChannel->parentWidget()->baseSize().height();
1233 y += pChannel->parentWidget()->frameGeometry().height();
1234 }
1235 }
1236
1237 // Add a new channel itema...
1238 WFlags wflags = Qt::WStyle_Customize | Qt::WStyle_Tool | Qt::WStyle_Title | Qt::WStyle_NoBorder;
1239 pChannel = new qsamplerChannelStrip(m_pWorkspace, 0, wflags);
1240 pChannel->setup(this, iChannelID);
1241 // We'll need a display font.
1242 QFont font;
1243 if (m_pOptions && font.fromString(m_pOptions->sDisplayFont))
1244 pChannel->setDisplayFont(font);
1245 // Track channel setup changes.
1246 QObject::connect(pChannel, SIGNAL(channelChanged(qsamplerChannelStrip *)), this, SLOT(channelChanged(qsamplerChannelStrip *)));
1247 // Before we show it up, may be we'll
1248 // better ask for some initial values?
1249 if (bPrompt)
1250 pChannel->channelSetup();
1251 // Now we show up us to the world.
1252 pChannel->show();
1253 // Only then, we'll auto-arrange...
1254 if (m_pOptions && m_pOptions->bAutoArrange) {
1255 int iWidth = m_pWorkspace->width();
1256 // int iHeight = pChannel->height() + pChannel->parentWidget()->baseSize().height();
1257 int iHeight = pChannel->parentWidget()->frameGeometry().height();
1258 pChannel->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1259 }
1260 }
1261
1262
1263 // Retrieve the active channel strip.
1264 qsamplerChannelStrip *qsamplerMainForm::activeChannel (void)
1265 {
1266 return (qsamplerChannelStrip *) m_pWorkspace->activeWindow();
1267 }
1268
1269
1270 // Retrieve a channel strip by index.
1271 qsamplerChannelStrip *qsamplerMainForm::channelAt ( int iChannel )
1272 {
1273 QWidgetList wlist = m_pWorkspace->windowList();
1274 if (wlist.isEmpty())
1275 return 0;
1276
1277 return (qsamplerChannelStrip *) wlist.at(iChannel);
1278 }
1279
1280
1281 // Construct the windows menu.
1282 void qsamplerMainForm::channelsMenuAboutToShow (void)
1283 {
1284 channelsMenu->clear();
1285 channelsArrangeAction->addTo(channelsMenu);
1286 channelsAutoArrangeAction->addTo(channelsMenu);
1287
1288 QWidgetList wlist = m_pWorkspace->windowList();
1289 if (!wlist.isEmpty()) {
1290 channelsMenu->insertSeparator();
1291 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1292 qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1293 int iItemID = channelsMenu->insertItem(pChannel->caption(), this, SLOT(channelsMenuActivated(int)));
1294 channelsMenu->setItemParameter(iItemID, iChannel);
1295 channelsMenu->setItemChecked(iItemID, activeChannel() == pChannel);
1296 }
1297 }
1298 }
1299
1300
1301 // Windows menu activation slot
1302 void qsamplerMainForm::channelsMenuActivated ( int iChannel )
1303 {
1304 qsamplerChannelStrip *pChannel = channelAt(iChannel);
1305 if (pChannel)
1306 pChannel->showNormal();
1307 pChannel->setFocus();
1308 }
1309
1310
1311 //-------------------------------------------------------------------------
1312 // qsamplerMainForm -- Timer stuff.
1313
1314 // Set the pseudo-timer delay schedule.
1315 void qsamplerMainForm::startSchedule ( int iStartDelay )
1316 {
1317 m_iStartDelay = 1 + (iStartDelay * 1000);
1318 m_iTimerDelay = 0;
1319 }
1320
1321 // Suspend the pseudo-timer delay schedule.
1322 void qsamplerMainForm::stopSchedule (void)
1323 {
1324 m_iStartDelay = 0;
1325 m_iTimerDelay = 0;
1326 }
1327
1328 // Timer slot funtion.
1329 void qsamplerMainForm::timerSlot (void)
1330 {
1331 if (m_pOptions == NULL)
1332 return;
1333
1334 // Is it the first shot on server start after a few delay?
1335 if (m_iTimerDelay < m_iStartDelay) {
1336 m_iTimerDelay += QSAMPLER_TIMER_MSECS;
1337 if (m_iTimerDelay >= m_iStartDelay) {
1338 // If we cannot start it now, maybe a lil'mo'later ;)
1339 if (!startClient()) {
1340 m_iStartDelay += m_iTimerDelay;
1341 m_iTimerDelay = 0;
1342 }
1343 }
1344 }
1345
1346 // Refresh each channel usage, on each period...
1347 if (m_pClient && m_pOptions->bAutoRefresh && m_pWorkspace->isUpdatesEnabled()) {
1348 m_iTimerSlot += QSAMPLER_TIMER_MSECS;
1349 if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime) {
1350 m_iTimerSlot = 0;
1351 QWidgetList wlist = m_pWorkspace->windowList();
1352 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1353 qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1354 if (pChannel->isVisible())
1355 pChannel->updateChannelUsage();
1356 }
1357 }
1358 }
1359
1360 // Register the next timer slot.
1361 QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
1362 }
1363
1364
1365 //-------------------------------------------------------------------------
1366 // qsamplerMainForm -- Server stuff.
1367
1368 // Start linuxsampler server...
1369 void qsamplerMainForm::startServer (void)
1370 {
1371 if (m_pOptions == NULL)
1372 return;
1373
1374 // Aren't already a client, are we?
1375 if (!m_pOptions->bServerStart || m_pClient)
1376 return;
1377
1378 // Is the server process instance still here?
1379 if (m_pServer) {
1380 switch (QMessageBox::warning(this, tr("Warning"),
1381 tr("Could not start the LinuxSampler server.\n\n"
1382 "Maybe it ss already started."),
1383 tr("Stop"), tr("Kill"), tr("Cancel"))) {
1384 case 0:
1385 m_pServer->tryTerminate();
1386 break;
1387 case 1:
1388 m_pServer->kill();
1389 break;
1390 }
1391 return;
1392 }
1393
1394 // Reset our timer counters...
1395 stopSchedule();
1396
1397 // OK. Let's build the startup process...
1398 m_pServer = new QProcess(this);
1399
1400 // Setup stdout/stderr capture...
1401 //if (m_pOptions->bStdoutCapture) {
1402 m_pServer->setCommunication(QProcess::Stdout | QProcess::Stderr | QProcess::DupStderr);
1403 QObject::connect(m_pServer, SIGNAL(readyReadStdout()), this, SLOT(readServerStdout()));
1404 QObject::connect(m_pServer, SIGNAL(readyReadStderr()), this, SLOT(readServerStdout()));
1405 //}
1406 // The unforgiveable signal communication...
1407 QObject::connect(m_pServer, SIGNAL(processExited()), this, SLOT(processServerExit()));
1408
1409 // Build process arguments...
1410 m_pServer->setArguments(QStringList::split(' ', m_pOptions->sServerCmdLine));
1411
1412 appendMessages(tr("Server is starting..."));
1413 appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");
1414
1415 // Go jack, go...
1416 if (!m_pServer->start()) {
1417 appendMessagesError(tr("Could not start server.\n\nSorry."));
1418 processServerExit();
1419 return;
1420 }
1421
1422 // Show startup results...
1423 appendMessages(tr("Server was started with PID=%1.").arg((long) m_pServer->processIdentifier()));
1424
1425 // Reset (yet again) the timer counters,
1426 // but this time is deferred as the user opted.
1427 startSchedule(m_pOptions->iStartDelay);
1428 stabilizeForm();
1429 }
1430
1431
1432 // Stop linuxsampler server...
1433 void qsamplerMainForm::stopServer (void)
1434 {
1435 // Stop client code.
1436 stopClient();
1437
1438 // And try to stop server.
1439 if (m_pServer) {
1440 appendMessages(tr("Server is stopping..."));
1441 if (m_pServer->isRunning()) {
1442 m_pServer->tryTerminate();
1443 return;
1444 }
1445 }
1446
1447 // Do final processing anyway.
1448 processServerExit();
1449 }
1450
1451
1452 // Stdout handler...
1453 void qsamplerMainForm::readServerStdout (void)
1454 {
1455 if (m_pMessages)
1456 m_pMessages->appendStdoutBuffer(m_pServer->readStdout());
1457 }
1458
1459
1460 // Linuxsampler server cleanup.
1461 void qsamplerMainForm::processServerExit (void)
1462 {
1463 // Force client code cleanup.
1464 stopClient();
1465
1466 // Flush anything that maybe pending...
1467 if (m_pMessages)
1468 m_pMessages->flushStdoutBuffer();
1469
1470 if (m_pServer) {
1471 // Force final server shutdown...
1472 appendMessages(tr("Server was stopped with exit status %1.").arg(m_pServer->exitStatus()));
1473 if (!m_pServer->normalExit())
1474 m_pServer->kill();
1475 // Destroy it.
1476 delete m_pServer;
1477 m_pServer = NULL;
1478 }
1479
1480 // Again, make status visible stable.
1481 stabilizeForm();
1482 }
1483
1484
1485 //-------------------------------------------------------------------------
1486 // qsamplerMainForm -- Client stuff.
1487
1488
1489 // The LSCP client callback procedure.
1490 lscp_status_t qsampler_client_callback ( lscp_client_t *pClient, const char *pchBuffer, int cchBuffer, void *pvData )
1491 {
1492 qsamplerMainForm *pMainForm = (qsamplerMainForm *) pvData;
1493 if (pMainForm == NULL)
1494 return LSCP_FAILED;
1495
1496 char *pszBuffer = (char *) malloc(cchBuffer + 1);
1497 if (pszBuffer == NULL)
1498 return LSCP_FAILED;
1499
1500 memcpy(pszBuffer, pchBuffer, cchBuffer);
1501 pszBuffer[cchBuffer] = (char) 0;
1502 pMainForm->appendMessagesColor(pszBuffer, "#996699");
1503 free(pszBuffer);
1504
1505 return LSCP_OK;
1506 }
1507
1508
1509 // Start our almighty client...
1510 bool qsamplerMainForm::startClient (void)
1511 {
1512 // Have it a setup?
1513 if (m_pOptions == NULL)
1514 return false;
1515
1516 // Aren't we already started, are we?
1517 if (m_pClient)
1518 return true;
1519
1520 // Log prepare here.
1521 appendMessages(tr("Client connecting..."));
1522
1523 // Create the client handle...
1524 m_pClient = ::lscp_client_create(m_pOptions->sServerHost.latin1(), m_pOptions->iServerPort, qsampler_client_callback, this);
1525 if (m_pClient == NULL) {
1526 // Is this the first try?
1527 // maybe we need to start a local server...
1528 if ((m_pServer && m_pServer->isRunning()) || !m_pOptions->bServerStart)
1529 appendMessagesError(tr("Could not connect to server as client.\n\nSorry."));
1530 else
1531 startServer();
1532 // This is always a failure.
1533 stabilizeForm();
1534 return false;
1535 }
1536 // Just set receive timeout value, blindly.
1537 ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);
1538 appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));
1539
1540 // We may stop scheduling around.
1541 stopSchedule();
1542
1543 // We'll accept drops from now on...
1544 setAcceptDrops(true);
1545
1546 // Log success here.
1547 appendMessages(tr("Client connected."));
1548
1549 // Is any session pending to be loaded?
1550 if (!m_pOptions->sSessionFile.isEmpty()) {
1551 // Just load the prabably startup session...
1552 if (loadSessionFile(m_pOptions->sSessionFile)) {
1553 m_pOptions->sSessionFile = QString::null;
1554 return true;
1555 }
1556 }
1557
1558 // Make a new session
1559 return newSession();
1560 }
1561
1562
1563 // Stop client...
1564 void qsamplerMainForm::stopClient (void)
1565 {
1566 if (m_pClient == NULL)
1567 return;
1568
1569 // Log prepare here.
1570 appendMessages(tr("Client disconnecting..."));
1571
1572 // Clear timer counters...
1573 stopSchedule();
1574
1575 // We'll reject drops from now on...
1576 setAcceptDrops(false);
1577
1578 // Force any channel strips around, but
1579 // but avoid removing the corresponding
1580 // channels from the back-end server.
1581 m_iDirtyCount = 0;
1582 closeSession(false);
1583
1584 // Close us as a client...
1585 lscp_client_destroy(m_pClient);
1586 m_pClient = NULL;
1587
1588 // Log final here.
1589 appendMessages(tr("Client disconnected."));
1590
1591 // Make visible status.
1592 stabilizeForm();
1593 }
1594
1595
1596 // end of qsamplerMainForm.ui.h

  ViewVC Help
Powered by ViewVC