/[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 109 - (hide annotations) (download) (as text)
Sat Jun 5 11:37:06 2004 UTC (19 years, 9 months ago) by capela
File MIME type: text/x-c++hdr
File size: 49570 byte(s)
Initial alpha release.

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

  ViewVC Help
Powered by ViewVC