/[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 122 - (hide annotations) (download) (as text)
Sat Jun 12 13:21:35 2004 UTC (19 years, 9 months ago) by capela
File MIME type: text/x-c++hdr
File size: 50509 byte(s)
* Added small wait event loop on qsamplerMainForm::stopServer(),
  so let local server terminate gracefully and stabilize, and
  avoiding a probable segfault on exit, which was preventing the
  correct salvage of settings and configuration.

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 capela 119 int iOldMaxVolume = m_pOptions->iMaxVolume;
847 capela 109 QString sOldMessagesFont = m_pOptions->sMessagesFont;
848     bool bOldStdoutCapture = m_pOptions->bStdoutCapture;
849     int bOldMessagesLimit = m_pOptions->bMessagesLimit;
850     int iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines;
851     bool bOldCompletePath = m_pOptions->bCompletePath;
852     int iOldMaxRecentFiles = m_pOptions->iMaxRecentFiles;
853     // Load the current setup settings.
854     pOptionsForm->setup(m_pOptions);
855     // Show the setup dialog...
856     if (pOptionsForm->exec()) {
857     // Warn if something will be only effective on next run.
858     if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) ||
859     (!bOldStdoutCapture && m_pOptions->bStdoutCapture)) {
860     QMessageBox::information(this, tr("Information"),
861     tr("Some settings may be only effective\n"
862     "next time you start this program."), tr("OK"));
863     updateMessagesCapture();
864     }
865     // Check wheather something immediate has changed.
866     if (( bOldCompletePath && !m_pOptions->bCompletePath) ||
867     (!bOldCompletePath && m_pOptions->bCompletePath) ||
868     (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles))
869     updateRecentFilesMenu();
870     if (sOldDisplayFont != m_pOptions->sDisplayFont)
871     updateDisplayFont();
872 capela 119 if (iOldMaxVolume != m_pOptions->iMaxVolume)
873     updateMaxVolume();
874 capela 109 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 capela 119 // Force update of the channels maximum volume setting.
1131     void qsamplerMainForm::updateMaxVolume (void)
1132     {
1133     if (m_pOptions == NULL)
1134     return;
1135    
1136     // Full channel list update...
1137     QWidgetList wlist = m_pWorkspace->windowList();
1138     if (wlist.isEmpty())
1139     return;
1140    
1141     m_pWorkspace->setUpdatesEnabled(false);
1142     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1143     qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1144     pChannel->setMaxVolume(m_pOptions->iMaxVolume);
1145     }
1146     m_pWorkspace->setUpdatesEnabled(true);
1147     }
1148    
1149    
1150 capela 109 //-------------------------------------------------------------------------
1151     // qsamplerMainForm -- Messages window form handlers.
1152    
1153     // Messages output methods.
1154     void qsamplerMainForm::appendMessages( const QString& s )
1155     {
1156     if (m_pMessages)
1157     m_pMessages->appendMessages(s);
1158    
1159     statusBar()->message(s, 3000);
1160     }
1161    
1162     void qsamplerMainForm::appendMessagesColor( const QString& s, const QString& c )
1163     {
1164     if (m_pMessages)
1165     m_pMessages->appendMessagesColor(s, c);
1166    
1167     statusBar()->message(s, 3000);
1168     }
1169    
1170     void qsamplerMainForm::appendMessagesText( const QString& s )
1171     {
1172     if (m_pMessages)
1173     m_pMessages->appendMessagesText(s);
1174     }
1175    
1176     void qsamplerMainForm::appendMessagesError( const QString& s )
1177     {
1178     if (m_pMessages)
1179     m_pMessages->show();
1180    
1181     appendMessagesColor(s.simplifyWhiteSpace(), "#ff0000");
1182    
1183     QMessageBox::critical(this, tr("Error"), s, tr("Cancel"));
1184     }
1185    
1186    
1187     // This is a special message format, just for client results.
1188     void qsamplerMainForm::appendMessagesClient( const QString& s )
1189     {
1190     if (m_pClient == NULL)
1191     return;
1192    
1193     appendMessagesColor(s + QString(": %1 (errno=%2)")
1194     .arg(::lscp_client_get_result(m_pClient))
1195     .arg(::lscp_client_get_errno(m_pClient)), "#996666");
1196     }
1197    
1198    
1199     // Force update of the messages font.
1200     void qsamplerMainForm::updateMessagesFont (void)
1201     {
1202     if (m_pOptions == NULL)
1203     return;
1204    
1205     if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {
1206     QFont font;
1207     if (font.fromString(m_pOptions->sMessagesFont))
1208     m_pMessages->setMessagesFont(font);
1209     }
1210     }
1211    
1212    
1213     // Update messages window line limit.
1214     void qsamplerMainForm::updateMessagesLimit (void)
1215     {
1216     if (m_pOptions == NULL)
1217     return;
1218    
1219     if (m_pMessages) {
1220     if (m_pOptions->bMessagesLimit)
1221     m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);
1222     else
1223     m_pMessages->setMessagesLimit(0);
1224     }
1225     }
1226    
1227    
1228     // Enablement of the messages capture feature.
1229     void qsamplerMainForm::updateMessagesCapture (void)
1230     {
1231     if (m_pOptions == NULL)
1232     return;
1233    
1234     if (m_pMessages)
1235     m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);
1236     }
1237    
1238    
1239     //-------------------------------------------------------------------------
1240     // qsamplerMainForm -- MDI channel strip management.
1241    
1242     // The channel strip creation executive.
1243     void qsamplerMainForm::createChannel ( int iChannelID, bool bPrompt )
1244     {
1245     if (m_pClient == NULL)
1246     return;
1247    
1248     // Prepare for auto-arrange?
1249     qsamplerChannelStrip *pChannel = NULL;
1250     int y = 0;
1251     if (m_pOptions && m_pOptions->bAutoArrange) {
1252     QWidgetList wlist = m_pWorkspace->windowList();
1253     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1254     pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1255     // y += pChannel->height() + pChannel->parentWidget()->baseSize().height();
1256     y += pChannel->parentWidget()->frameGeometry().height();
1257     }
1258     }
1259    
1260     // Add a new channel itema...
1261     WFlags wflags = Qt::WStyle_Customize | Qt::WStyle_Tool | Qt::WStyle_Title | Qt::WStyle_NoBorder;
1262     pChannel = new qsamplerChannelStrip(m_pWorkspace, 0, wflags);
1263 capela 119 pChannel->setMaxVolume(m_pOptions->iMaxVolume);
1264 capela 109 pChannel->setup(this, iChannelID);
1265     // We'll need a display font.
1266     QFont font;
1267     if (m_pOptions && font.fromString(m_pOptions->sDisplayFont))
1268     pChannel->setDisplayFont(font);
1269     // Track channel setup changes.
1270     QObject::connect(pChannel, SIGNAL(channelChanged(qsamplerChannelStrip *)), this, SLOT(channelChanged(qsamplerChannelStrip *)));
1271     // Before we show it up, may be we'll
1272     // better ask for some initial values?
1273     if (bPrompt)
1274     pChannel->channelSetup();
1275     // Now we show up us to the world.
1276     pChannel->show();
1277     // Only then, we'll auto-arrange...
1278     if (m_pOptions && m_pOptions->bAutoArrange) {
1279     int iWidth = m_pWorkspace->width();
1280     // int iHeight = pChannel->height() + pChannel->parentWidget()->baseSize().height();
1281     int iHeight = pChannel->parentWidget()->frameGeometry().height();
1282     pChannel->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1283     }
1284     }
1285    
1286    
1287     // Retrieve the active channel strip.
1288     qsamplerChannelStrip *qsamplerMainForm::activeChannel (void)
1289     {
1290     return (qsamplerChannelStrip *) m_pWorkspace->activeWindow();
1291     }
1292    
1293    
1294     // Retrieve a channel strip by index.
1295     qsamplerChannelStrip *qsamplerMainForm::channelAt ( int iChannel )
1296     {
1297     QWidgetList wlist = m_pWorkspace->windowList();
1298     if (wlist.isEmpty())
1299     return 0;
1300    
1301     return (qsamplerChannelStrip *) wlist.at(iChannel);
1302     }
1303    
1304    
1305     // Construct the windows menu.
1306     void qsamplerMainForm::channelsMenuAboutToShow (void)
1307     {
1308     channelsMenu->clear();
1309     channelsArrangeAction->addTo(channelsMenu);
1310     channelsAutoArrangeAction->addTo(channelsMenu);
1311    
1312     QWidgetList wlist = m_pWorkspace->windowList();
1313     if (!wlist.isEmpty()) {
1314     channelsMenu->insertSeparator();
1315     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1316     qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1317     int iItemID = channelsMenu->insertItem(pChannel->caption(), this, SLOT(channelsMenuActivated(int)));
1318     channelsMenu->setItemParameter(iItemID, iChannel);
1319     channelsMenu->setItemChecked(iItemID, activeChannel() == pChannel);
1320     }
1321     }
1322     }
1323    
1324    
1325     // Windows menu activation slot
1326     void qsamplerMainForm::channelsMenuActivated ( int iChannel )
1327     {
1328     qsamplerChannelStrip *pChannel = channelAt(iChannel);
1329     if (pChannel)
1330     pChannel->showNormal();
1331     pChannel->setFocus();
1332     }
1333    
1334    
1335     //-------------------------------------------------------------------------
1336     // qsamplerMainForm -- Timer stuff.
1337    
1338     // Set the pseudo-timer delay schedule.
1339     void qsamplerMainForm::startSchedule ( int iStartDelay )
1340     {
1341     m_iStartDelay = 1 + (iStartDelay * 1000);
1342     m_iTimerDelay = 0;
1343     }
1344    
1345     // Suspend the pseudo-timer delay schedule.
1346     void qsamplerMainForm::stopSchedule (void)
1347     {
1348     m_iStartDelay = 0;
1349     m_iTimerDelay = 0;
1350     }
1351    
1352     // Timer slot funtion.
1353     void qsamplerMainForm::timerSlot (void)
1354     {
1355     if (m_pOptions == NULL)
1356     return;
1357    
1358     // Is it the first shot on server start after a few delay?
1359     if (m_iTimerDelay < m_iStartDelay) {
1360     m_iTimerDelay += QSAMPLER_TIMER_MSECS;
1361     if (m_iTimerDelay >= m_iStartDelay) {
1362     // If we cannot start it now, maybe a lil'mo'later ;)
1363     if (!startClient()) {
1364     m_iStartDelay += m_iTimerDelay;
1365     m_iTimerDelay = 0;
1366     }
1367     }
1368     }
1369    
1370     // Refresh each channel usage, on each period...
1371     if (m_pClient && m_pOptions->bAutoRefresh && m_pWorkspace->isUpdatesEnabled()) {
1372     m_iTimerSlot += QSAMPLER_TIMER_MSECS;
1373     if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime) {
1374     m_iTimerSlot = 0;
1375     QWidgetList wlist = m_pWorkspace->windowList();
1376     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1377     qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1378     if (pChannel->isVisible())
1379     pChannel->updateChannelUsage();
1380     }
1381     }
1382     }
1383    
1384     // Register the next timer slot.
1385     QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
1386     }
1387    
1388    
1389     //-------------------------------------------------------------------------
1390     // qsamplerMainForm -- Server stuff.
1391    
1392     // Start linuxsampler server...
1393     void qsamplerMainForm::startServer (void)
1394     {
1395     if (m_pOptions == NULL)
1396     return;
1397    
1398     // Aren't already a client, are we?
1399     if (!m_pOptions->bServerStart || m_pClient)
1400     return;
1401    
1402     // Is the server process instance still here?
1403     if (m_pServer) {
1404     switch (QMessageBox::warning(this, tr("Warning"),
1405     tr("Could not start the LinuxSampler server.\n\n"
1406     "Maybe it ss already started."),
1407     tr("Stop"), tr("Kill"), tr("Cancel"))) {
1408     case 0:
1409     m_pServer->tryTerminate();
1410     break;
1411     case 1:
1412     m_pServer->kill();
1413     break;
1414     }
1415     return;
1416     }
1417    
1418     // Reset our timer counters...
1419     stopSchedule();
1420    
1421     // OK. Let's build the startup process...
1422     m_pServer = new QProcess(this);
1423    
1424     // Setup stdout/stderr capture...
1425     //if (m_pOptions->bStdoutCapture) {
1426     m_pServer->setCommunication(QProcess::Stdout | QProcess::Stderr | QProcess::DupStderr);
1427     QObject::connect(m_pServer, SIGNAL(readyReadStdout()), this, SLOT(readServerStdout()));
1428     QObject::connect(m_pServer, SIGNAL(readyReadStderr()), this, SLOT(readServerStdout()));
1429     //}
1430     // The unforgiveable signal communication...
1431     QObject::connect(m_pServer, SIGNAL(processExited()), this, SLOT(processServerExit()));
1432    
1433     // Build process arguments...
1434     m_pServer->setArguments(QStringList::split(' ', m_pOptions->sServerCmdLine));
1435    
1436     appendMessages(tr("Server is starting..."));
1437     appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");
1438    
1439     // Go jack, go...
1440     if (!m_pServer->start()) {
1441     appendMessagesError(tr("Could not start server.\n\nSorry."));
1442     processServerExit();
1443     return;
1444     }
1445    
1446     // Show startup results...
1447     appendMessages(tr("Server was started with PID=%1.").arg((long) m_pServer->processIdentifier()));
1448    
1449     // Reset (yet again) the timer counters,
1450     // but this time is deferred as the user opted.
1451     startSchedule(m_pOptions->iStartDelay);
1452     stabilizeForm();
1453     }
1454    
1455    
1456     // Stop linuxsampler server...
1457     void qsamplerMainForm::stopServer (void)
1458     {
1459     // Stop client code.
1460     stopClient();
1461    
1462     // And try to stop server.
1463     if (m_pServer) {
1464     appendMessages(tr("Server is stopping..."));
1465 capela 122 if (m_pServer->isRunning())
1466 capela 109 m_pServer->tryTerminate();
1467     }
1468    
1469 capela 122 // Give it some time to terminate gracefully and stabilize...
1470     QTime t;
1471     t.start();
1472     while (t.elapsed() < QSAMPLER_TIMER_MSECS)
1473     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
1474    
1475 capela 109 // Do final processing anyway.
1476     processServerExit();
1477     }
1478    
1479    
1480     // Stdout handler...
1481     void qsamplerMainForm::readServerStdout (void)
1482     {
1483     if (m_pMessages)
1484     m_pMessages->appendStdoutBuffer(m_pServer->readStdout());
1485     }
1486    
1487    
1488     // Linuxsampler server cleanup.
1489     void qsamplerMainForm::processServerExit (void)
1490     {
1491     // Force client code cleanup.
1492     stopClient();
1493    
1494     // Flush anything that maybe pending...
1495     if (m_pMessages)
1496     m_pMessages->flushStdoutBuffer();
1497    
1498     if (m_pServer) {
1499     // Force final server shutdown...
1500     appendMessages(tr("Server was stopped with exit status %1.").arg(m_pServer->exitStatus()));
1501     if (!m_pServer->normalExit())
1502     m_pServer->kill();
1503     // Destroy it.
1504     delete m_pServer;
1505     m_pServer = NULL;
1506     }
1507    
1508     // Again, make status visible stable.
1509     stabilizeForm();
1510     }
1511    
1512    
1513     //-------------------------------------------------------------------------
1514     // qsamplerMainForm -- Client stuff.
1515    
1516    
1517     // The LSCP client callback procedure.
1518     lscp_status_t qsampler_client_callback ( lscp_client_t *pClient, const char *pchBuffer, int cchBuffer, void *pvData )
1519     {
1520     qsamplerMainForm *pMainForm = (qsamplerMainForm *) pvData;
1521     if (pMainForm == NULL)
1522     return LSCP_FAILED;
1523    
1524     char *pszBuffer = (char *) malloc(cchBuffer + 1);
1525     if (pszBuffer == NULL)
1526     return LSCP_FAILED;
1527    
1528     memcpy(pszBuffer, pchBuffer, cchBuffer);
1529     pszBuffer[cchBuffer] = (char) 0;
1530     pMainForm->appendMessagesColor(pszBuffer, "#996699");
1531     free(pszBuffer);
1532    
1533     return LSCP_OK;
1534     }
1535    
1536    
1537     // Start our almighty client...
1538     bool qsamplerMainForm::startClient (void)
1539     {
1540     // Have it a setup?
1541     if (m_pOptions == NULL)
1542     return false;
1543    
1544     // Aren't we already started, are we?
1545     if (m_pClient)
1546     return true;
1547    
1548     // Log prepare here.
1549     appendMessages(tr("Client connecting..."));
1550    
1551     // Create the client handle...
1552     m_pClient = ::lscp_client_create(m_pOptions->sServerHost.latin1(), m_pOptions->iServerPort, qsampler_client_callback, this);
1553     if (m_pClient == NULL) {
1554     // Is this the first try?
1555     // maybe we need to start a local server...
1556     if ((m_pServer && m_pServer->isRunning()) || !m_pOptions->bServerStart)
1557     appendMessagesError(tr("Could not connect to server as client.\n\nSorry."));
1558     else
1559     startServer();
1560     // This is always a failure.
1561     stabilizeForm();
1562     return false;
1563     }
1564     // Just set receive timeout value, blindly.
1565     ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);
1566     appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));
1567    
1568     // We may stop scheduling around.
1569     stopSchedule();
1570    
1571     // We'll accept drops from now on...
1572     setAcceptDrops(true);
1573    
1574     // Log success here.
1575     appendMessages(tr("Client connected."));
1576    
1577     // Is any session pending to be loaded?
1578     if (!m_pOptions->sSessionFile.isEmpty()) {
1579     // Just load the prabably startup session...
1580     if (loadSessionFile(m_pOptions->sSessionFile)) {
1581     m_pOptions->sSessionFile = QString::null;
1582     return true;
1583     }
1584     }
1585    
1586     // Make a new session
1587     return newSession();
1588     }
1589    
1590    
1591     // Stop client...
1592     void qsamplerMainForm::stopClient (void)
1593     {
1594     if (m_pClient == NULL)
1595     return;
1596    
1597     // Log prepare here.
1598     appendMessages(tr("Client disconnecting..."));
1599    
1600     // Clear timer counters...
1601     stopSchedule();
1602    
1603     // We'll reject drops from now on...
1604     setAcceptDrops(false);
1605    
1606     // Force any channel strips around, but
1607     // but avoid removing the corresponding
1608     // channels from the back-end server.
1609     m_iDirtyCount = 0;
1610     closeSession(false);
1611    
1612     // Close us as a client...
1613     lscp_client_destroy(m_pClient);
1614     m_pClient = NULL;
1615    
1616     // Log final here.
1617     appendMessages(tr("Client disconnected."));
1618    
1619     // Make visible status.
1620     stabilizeForm();
1621     }
1622    
1623    
1624     // end of qsamplerMainForm.ui.h

  ViewVC Help
Powered by ViewVC