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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 115 - (hide 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 capela 109 // 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 capela 115 ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannelID << " " << pChannel->audioDriver() << endl;
548 capela 109 ts << "SET CHANNEL MIDI_INPUT_TYPE " << iChannelID << " " << pChannel->midiDriver() << endl;
549 capela 115 // ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannelID << " " << pChannel->midiPort() << endl;
550 capela 109 ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannelID << " " << pChannel->midiChannel() << endl;
551 capela 115 ts << "LOAD ENGINE " << pChannel->engineName() << " " << iChannelID << endl;
552     ts << "LOAD INSTRUMENT " << pChannel->instrumentFile() << " " << pChannel->instrumentNr() << " " << iChannelID << endl;
553 capela 109 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