/[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 463 - (hide annotations) (download) (as text)
Tue Mar 15 15:32:29 2005 UTC (19 years ago) by capela
File MIME type: text/x-c++hdr
File size: 65100 byte(s)
* Device port/channel configuration is now complete (EXPERIMENTAL).

1 capela 109 // qsamplerMainForm.ui.h
2     //
3     // ui.h extension file, included from the uic-generated form implementation.
4     /****************************************************************************
5 capela 341 Copyright (C) 2004-2005, rncbc aka Rui Nuno Capela. All rights reserved.
6 capela 109
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 capela 388 #include <qregexp.h>
30 capela 109 #include <qfiledialog.h>
31     #include <qfileinfo.h>
32     #include <qfile.h>
33     #include <qtextstream.h>
34     #include <qstatusbar.h>
35     #include <qlabel.h>
36     #include <qtimer.h>
37    
38     #include "qsamplerAbout.h"
39     #include "qsamplerOptions.h"
40 capela 264 #include "qsamplerChannel.h"
41 capela 109 #include "qsamplerMessages.h"
42    
43     #include "qsamplerChannelStrip.h"
44 capela 428
45     #include "qsamplerDeviceForm.h"
46 capela 109 #include "qsamplerOptionsForm.h"
47    
48     #include "config.h"
49    
50 capela 340 #ifdef HAVE_SIGNAL_H
51     #include <signal.h>
52     #endif
53 capela 109
54     // Timer constant stuff.
55     #define QSAMPLER_TIMER_MSECS 200
56    
57     // Status bar item indexes
58     #define QSAMPLER_STATUS_CLIENT 0 // Client connection state.
59     #define QSAMPLER_STATUS_SERVER 1 // Currenr server address (host:port)
60     #define QSAMPLER_STATUS_CHANNEL 2 // Active channel caption.
61     #define QSAMPLER_STATUS_SESSION 3 // Current session modification state.
62    
63    
64 capela 149 // All winsock apps needs this.
65 capela 109 #if defined(WIN32)
66     static WSADATA _wsaData;
67     #endif
68    
69 capela 149
70 capela 109 //-------------------------------------------------------------------------
71 capela 149 // qsamplerCustomEvent -- specialty for callback comunication.
72    
73     #define QSAMPLER_CUSTOM_EVENT 1000
74    
75     class qsamplerCustomEvent : public QCustomEvent
76     {
77     public:
78    
79     // Constructor.
80     qsamplerCustomEvent(lscp_event_t event, const char *pchData, int cchData)
81     : QCustomEvent(QSAMPLER_CUSTOM_EVENT)
82     {
83     m_event = event;
84     m_data.setLatin1(pchData, cchData);
85     }
86    
87     // Accessors.
88     lscp_event_t event() { return m_event; }
89     QString& data() { return m_data; }
90    
91     private:
92    
93     // The proper event type.
94     lscp_event_t m_event;
95     // The event data as a string.
96     QString m_data;
97     };
98    
99    
100     //-------------------------------------------------------------------------
101 capela 109 // qsamplerMainForm -- Main window form implementation.
102    
103     // Kind of constructor.
104     void qsamplerMainForm::init (void)
105     {
106     // Initialize some pointer references.
107     m_pOptions = NULL;
108    
109     // All child forms are to be created later, not earlier than setup.
110 capela 428 m_pMessages = NULL;
111     m_pDeviceForm = NULL;
112 capela 109
113     // We'll start clean.
114 capela 400 m_iUntitled = 0;
115     m_iDirtyCount = 0;
116 capela 109
117     m_pServer = NULL;
118     m_pClient = NULL;
119    
120     m_iStartDelay = 0;
121     m_iTimerDelay = 0;
122    
123     m_iTimerSlot = 0;
124    
125 capela 340 #ifdef HAVE_SIGNAL_H
126     // Set to ignore any fatal "Broken pipe" signals.
127     ::signal(SIGPIPE, SIG_IGN);
128     #endif
129    
130 capela 109 // Make it an MDI workspace.
131     m_pWorkspace = new QWorkspace(this);
132     m_pWorkspace->setScrollBarsEnabled(true);
133     // Set the activation connection.
134     QObject::connect(m_pWorkspace, SIGNAL(windowActivated(QWidget *)), this, SLOT(stabilizeForm()));
135     // Make it shine :-)
136     setCentralWidget(m_pWorkspace);
137    
138     // Create some statusbar labels...
139     QLabel *pLabel;
140     // Client status.
141     pLabel = new QLabel(tr("Connected"), this);
142     pLabel->setAlignment(Qt::AlignLeft);
143     pLabel->setMinimumSize(pLabel->sizeHint());
144 capela 428 m_statusItem[QSAMPLER_STATUS_CLIENT] = pLabel;
145 capela 109 statusBar()->addWidget(pLabel);
146     // Server address.
147     pLabel = new QLabel(this);
148     pLabel->setAlignment(Qt::AlignLeft);
149 capela 428 m_statusItem[QSAMPLER_STATUS_SERVER] = pLabel;
150 capela 109 statusBar()->addWidget(pLabel, 1);
151     // Channel title.
152     pLabel = new QLabel(this);
153     pLabel->setAlignment(Qt::AlignLeft);
154 capela 428 m_statusItem[QSAMPLER_STATUS_CHANNEL] = pLabel;
155 capela 109 statusBar()->addWidget(pLabel, 2);
156     // Session modification status.
157     pLabel = new QLabel(tr("MOD"), this);
158     pLabel->setAlignment(Qt::AlignHCenter);
159     pLabel->setMinimumSize(pLabel->sizeHint());
160 capela 428 m_statusItem[QSAMPLER_STATUS_SESSION] = pLabel;
161 capela 109 statusBar()->addWidget(pLabel);
162    
163     // Create the recent files sub-menu.
164     m_pRecentFilesMenu = new QPopupMenu(this);
165     fileMenu->insertSeparator(4);
166     fileMenu->insertItem(tr("Recent &Files"), m_pRecentFilesMenu, 0, 5);
167    
168     #if defined(WIN32)
169     WSAStartup(MAKEWORD(1, 1), &_wsaData);
170     #endif
171     }
172    
173    
174     // Kind of destructor.
175     void qsamplerMainForm::destroy (void)
176     {
177     // Do final processing anyway.
178     processServerExit();
179 capela 418
180     #if defined(WIN32)
181     WSACleanup();
182     #endif
183    
184     // Finally drop any widgets around...
185 capela 428 if (m_pDeviceForm)
186     delete m_pDeviceForm;
187 capela 418 if (m_pMessages)
188     delete m_pMessages;
189     if (m_pWorkspace)
190     delete m_pWorkspace;
191    
192 capela 109 // Delete status item labels one by one.
193 capela 428 if (m_statusItem[QSAMPLER_STATUS_CLIENT])
194     delete m_statusItem[QSAMPLER_STATUS_CLIENT];
195     if (m_statusItem[QSAMPLER_STATUS_SERVER])
196     delete m_statusItem[QSAMPLER_STATUS_SERVER];
197     if (m_statusItem[QSAMPLER_STATUS_CHANNEL])
198     delete m_statusItem[QSAMPLER_STATUS_CHANNEL];
199     if (m_statusItem[QSAMPLER_STATUS_SESSION])
200     delete m_statusItem[QSAMPLER_STATUS_SESSION];
201 capela 109
202 capela 418 // Delete recentfiles menu.
203     if (m_pRecentFilesMenu)
204     delete m_pRecentFilesMenu;
205 capela 109 }
206    
207    
208     // Make and set a proper setup options step.
209     void qsamplerMainForm::setup ( qsamplerOptions *pOptions )
210     {
211     // We got options?
212     m_pOptions = pOptions;
213    
214 capela 454 // What style do we create these forms?
215     WFlags wflags = Qt::WType_TopLevel;
216     if (m_pOptions->bKeepOnTop)
217     wflags |= Qt::WStyle_Tool;
218 capela 109 // Some child forms are to be created right now.
219     m_pMessages = new qsamplerMessages(this);
220 capela 454 m_pDeviceForm = new qsamplerDeviceForm(this, 0, wflags);
221 capela 109 // Set message defaults...
222     updateMessagesFont();
223     updateMessagesLimit();
224     updateMessagesCapture();
225     // Set the visibility signal.
226     QObject::connect(m_pMessages, SIGNAL(visibilityChanged(bool)), this, SLOT(stabilizeForm()));
227    
228     // Initial decorations toggle state.
229     viewMenubarAction->setOn(m_pOptions->bMenubar);
230     viewToolbarAction->setOn(m_pOptions->bToolbar);
231     viewStatusbarAction->setOn(m_pOptions->bStatusbar);
232     channelsAutoArrangeAction->setOn(m_pOptions->bAutoArrange);
233    
234     // Initial decorations visibility state.
235     viewMenubar(m_pOptions->bMenubar);
236     viewToolbar(m_pOptions->bToolbar);
237     viewStatusbar(m_pOptions->bStatusbar);
238    
239     // Restore whole dock windows state.
240     QString sDockables = m_pOptions->settings().readEntry("/Layout/DockWindows" , QString::null);
241     if (sDockables.isEmpty()) {
242     // Message window is forced to dock on the bottom.
243     moveDockWindow(m_pMessages, Qt::DockBottom);
244     } else {
245     // Make it as the last time.
246     QTextIStream istr(&sDockables);
247     istr >> *this;
248     }
249 capela 428 // Try to restore old window positioning and initial visibility.
250 capela 109 m_pOptions->loadWidgetGeometry(this);
251 capela 428 m_pOptions->loadWidgetGeometry(m_pDeviceForm);
252 capela 109
253     // Final startup stabilization...
254     updateRecentFilesMenu();
255     stabilizeForm();
256    
257     // Make it ready :-)
258     statusBar()->message(tr("Ready"), 3000);
259    
260     // We'll try to start immediately...
261     startSchedule(0);
262    
263     // Register the first timer slot.
264     QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
265     }
266    
267    
268     // Window close event handlers.
269     bool qsamplerMainForm::queryClose (void)
270     {
271     bool bQueryClose = closeSession(false);
272    
273     // Try to save current general state...
274     if (m_pOptions) {
275     // Some windows default fonts is here on demand too.
276     if (bQueryClose && m_pMessages)
277     m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();
278     // Try to save current positioning.
279     if (bQueryClose) {
280     // Save decorations state.
281     m_pOptions->bMenubar = MenuBar->isVisible();
282     m_pOptions->bToolbar = (fileToolbar->isVisible() || editToolbar->isVisible() || channelsToolbar->isVisible());
283     m_pOptions->bStatusbar = statusBar()->isVisible();
284     // Save the dock windows state.
285     QString sDockables;
286     QTextOStream ostr(&sDockables);
287     ostr << *this;
288     m_pOptions->settings().writeEntry("/Layout/DockWindows", sDockables);
289 capela 428 // And the children, and the main windows state,.
290     m_pOptions->saveWidgetGeometry(m_pDeviceForm);
291 capela 109 m_pOptions->saveWidgetGeometry(this);
292 capela 428 // Close popup widgets.
293     if (m_pDeviceForm)
294     m_pDeviceForm->close();
295 capela 109 // Stop client and/or server, gracefully.
296     stopServer();
297     }
298     }
299    
300     return bQueryClose;
301     }
302    
303    
304     void qsamplerMainForm::closeEvent ( QCloseEvent *pCloseEvent )
305     {
306     if (queryClose())
307     pCloseEvent->accept();
308     else
309     pCloseEvent->ignore();
310     }
311    
312    
313 capela 388 // Drag'n'drop file handler.
314     bool qsamplerMainForm::decodeDragFiles ( const QMimeSource *pEvent, QStringList& files )
315 capela 109 {
316 capela 388 bool bDecode = false;
317 capela 109
318 capela 388 if (QTextDrag::canDecode(pEvent)) {
319     QString sText;
320     bDecode = QTextDrag::decode(pEvent, sText);
321     if (bDecode) {
322     files = QStringList::split('\n', sText);
323     for (QStringList::Iterator iter = files.begin(); iter != files.end(); iter++)
324 capela 409 *iter = QUrl((*iter).stripWhiteSpace().replace(QRegExp("^file:"), QString::null)).path();
325 capela 388 }
326 capela 109 }
327    
328 capela 388 return bDecode;
329 capela 109 }
330    
331    
332 capela 388 // Window drag-n-drop event handlers.
333     void qsamplerMainForm::dragEnterEvent ( QDragEnterEvent* pDragEnterEvent )
334     {
335 capela 395 QStringList files;
336     pDragEnterEvent->accept(decodeDragFiles(pDragEnterEvent, files));
337 capela 388 }
338    
339    
340 capela 109 void qsamplerMainForm::dropEvent ( QDropEvent* pDropEvent )
341     {
342 capela 388 QStringList files;
343 capela 391
344     if (!decodeDragFiles(pDropEvent, files))
345     return;
346    
347     for (QStringList::Iterator iter = files.begin(); iter != files.end(); iter++) {
348 capela 409 const QString& sPath = *iter;
349 capela 391 if (qsamplerChannel::isInstrumentFile(sPath)) {
350     // Try to create a new channel from instrument file...
351     qsamplerChannel *pChannel = new qsamplerChannel(this);
352     if (pChannel == NULL)
353     return;
354     // Start setting the instrument filename...
355     pChannel->setInstrument(sPath, 0);
356     // Before we show it up, may be we'll
357     // better ask for some initial values?
358     if (!pChannel->channelSetup(this)) {
359     delete pChannel;
360     return;
361     }
362     // Finally, give it to a new channel strip...
363     if (!createChannelStrip(pChannel)) {
364     delete pChannel;
365     return;
366     }
367     // Make that an overall update.
368     m_iDirtyCount++;
369     stabilizeForm();
370     } // Otherwise, load an usual session file (LSCP script)...
371     else if (closeSession(true))
372     loadSessionFile(sPath);
373     // Make it look responsive...:)
374     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
375     }
376 capela 109 }
377    
378    
379 capela 149 // Custome event handler.
380     void qsamplerMainForm::customEvent ( QCustomEvent *pCustomEvent )
381     {
382     // For the time being, just pump it to messages.
383     if (pCustomEvent->type() == QSAMPLER_CUSTOM_EVENT) {
384     qsamplerCustomEvent *pEvent = (qsamplerCustomEvent *) pCustomEvent;
385     appendMessagesColor(tr("Notify event: %1 data: %2")
386     .arg(::lscp_event_to_text(pEvent->event()))
387     .arg(pEvent->data()), "#996699");
388     }
389     }
390    
391    
392 capela 127 // Context menu event handler.
393     void qsamplerMainForm::contextMenuEvent( QContextMenuEvent *pEvent )
394     {
395     stabilizeForm();
396    
397     editMenu->exec(pEvent->globalPos());
398     }
399    
400    
401 capela 109 //-------------------------------------------------------------------------
402     // qsamplerMainForm -- Brainless public property accessors.
403    
404     // The global options settings property.
405     qsamplerOptions *qsamplerMainForm::options (void)
406     {
407     return m_pOptions;
408     }
409    
410     // The LSCP client descriptor property.
411     lscp_client_t *qsamplerMainForm::client (void)
412     {
413     return m_pClient;
414     }
415    
416    
417     //-------------------------------------------------------------------------
418     // qsamplerMainForm -- Session file stuff.
419    
420     // Format the displayable session filename.
421     QString qsamplerMainForm::sessionName ( const QString& sFilename )
422     {
423     bool bCompletePath = (m_pOptions && m_pOptions->bCompletePath);
424     QString sSessionName = sFilename;
425     if (sSessionName.isEmpty())
426     sSessionName = tr("Untitled") + QString::number(m_iUntitled);
427     else if (!bCompletePath)
428     sSessionName = QFileInfo(sSessionName).fileName();
429     return sSessionName;
430     }
431    
432    
433     // Create a new session file from scratch.
434     bool qsamplerMainForm::newSession (void)
435     {
436     // Check if we can do it.
437     if (!closeSession(true))
438     return false;
439    
440 capela 395 // Give us what the server has, right now...
441     updateSession();
442    
443 capela 109 // Ok increment untitled count.
444     m_iUntitled++;
445    
446     // Stabilize form.
447     m_sFilename = QString::null;
448     m_iDirtyCount = 0;
449     appendMessages(tr("New session: \"%1\".").arg(sessionName(m_sFilename)));
450     stabilizeForm();
451    
452     return true;
453     }
454    
455    
456     // Open an existing sampler session.
457     bool qsamplerMainForm::openSession (void)
458     {
459     if (m_pOptions == NULL)
460     return false;
461    
462     // Ask for the filename to open...
463     QString sFilename = QFileDialog::getOpenFileName(
464     m_pOptions->sSessionDir, // Start here.
465     tr("LSCP Session files") + " (*.lscp)", // Filter (LSCP files)
466     this, 0, // Parent and name (none)
467     tr("Open Session") // Caption.
468     );
469    
470     // Have we cancelled?
471     if (sFilename.isEmpty())
472     return false;
473    
474     // Check if we're going to discard safely the current one...
475     if (!closeSession(true))
476     return false;
477    
478     // Load it right away.
479     return loadSessionFile(sFilename);
480     }
481    
482    
483     // Save current sampler session with another name.
484     bool qsamplerMainForm::saveSession ( bool bPrompt )
485     {
486     if (m_pOptions == NULL)
487     return false;
488    
489     QString sFilename = m_sFilename;
490    
491     // Ask for the file to save, if there's none...
492     if (bPrompt || sFilename.isEmpty()) {
493     // If none is given, assume default directory.
494     if (sFilename.isEmpty())
495     sFilename = m_pOptions->sSessionDir;
496     // Prompt the guy...
497     sFilename = QFileDialog::getSaveFileName(
498     sFilename, // Start here.
499     tr("LSCP Session files") + " (*.lscp)", // Filter (LSCP files)
500     this, 0, // Parent and name (none)
501     tr("Save Session") // Caption.
502     );
503     // Have we cancelled it?
504     if (sFilename.isEmpty())
505     return false;
506     // Enforce .lscp extension...
507     if (QFileInfo(sFilename).extension().isEmpty())
508     sFilename += ".lscp";
509     // Check if already exists...
510     if (sFilename != m_sFilename && QFileInfo(sFilename).exists()) {
511     if (QMessageBox::warning(this, tr("Warning"),
512     tr("The file already exists:\n\n"
513     "\"%1\"\n\n"
514     "Do you want to replace it?")
515     .arg(sFilename),
516     tr("Replace"), tr("Cancel")) > 0)
517     return false;
518     }
519     }
520    
521     // Save it right away.
522     return saveSessionFile(sFilename);
523     }
524    
525    
526     // Close current session.
527     bool qsamplerMainForm::closeSession ( bool bForce )
528     {
529     bool bClose = true;
530    
531     // Are we dirty enough to prompt it?
532     if (m_iDirtyCount > 0) {
533     switch (QMessageBox::warning(this, tr("Warning"),
534     tr("The current session has been changed:\n\n"
535     "\"%1\"\n\n"
536     "Do you want to save the changes?")
537     .arg(sessionName(m_sFilename)),
538     tr("Save"), tr("Discard"), tr("Cancel"))) {
539     case 0: // Save...
540     bClose = saveSession(false);
541     // Fall thru....
542     case 1: // Discard
543     break;
544     default: // Cancel.
545     bClose = false;
546     break;
547     }
548     }
549    
550     // If we may close it, dot it.
551     if (bClose) {
552     // Remove all channel strips from sight...
553     m_pWorkspace->setUpdatesEnabled(false);
554     QWidgetList wlist = m_pWorkspace->windowList();
555     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
556 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
557     if (pChannelStrip) {
558     qsamplerChannel *pChannel = pChannelStrip->channel();
559 capela 295 if (bForce && pChannel)
560     pChannel->removeChannel();
561 capela 264 delete pChannelStrip;
562     }
563 capela 109 }
564     m_pWorkspace->setUpdatesEnabled(true);
565     // We're now clean, for sure.
566     m_iDirtyCount = 0;
567     }
568    
569     return bClose;
570     }
571    
572    
573     // Load a session from specific file path.
574     bool qsamplerMainForm::loadSessionFile ( const QString& sFilename )
575     {
576     if (m_pClient == NULL)
577     return false;
578    
579     // Open and read from real file.
580     QFile file(sFilename);
581     if (!file.open(IO_ReadOnly)) {
582     appendMessagesError(tr("Could not open \"%1\" session file.\n\nSorry.").arg(sFilename));
583     return false;
584     }
585    
586     // Read the file.
587     int iErrors = 0;
588     QTextStream ts(&file);
589     while (!ts.atEnd()) {
590     // Read the line.
591     QString sCommand = ts.readLine().simplifyWhiteSpace();
592     // If not empty, nor a comment, call the server...
593     if (!sCommand.isEmpty() && sCommand[0] != '#') {
594     appendMessagesColor(sCommand, "#996633");
595     // Remember that, no matter what,
596     // all LSCP commands are CR/LF terminated.
597     sCommand += "\r\n";
598     if (::lscp_client_query(m_pClient, sCommand.latin1()) != LSCP_OK) {
599     appendMessagesClient("lscp_client_query");
600     iErrors++;
601 capela 388 break;
602 capela 109 }
603     }
604     // Try to make it snappy :)
605     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
606     }
607    
608     // Ok. we've read it.
609     file.close();
610    
611     // Have we any errors?
612     if (iErrors > 0)
613 capela 388 appendMessagesError(tr("Session could not be loaded\nfrom \"%1\".\n\nSorry.").arg(sFilename));
614 capela 109
615 capela 395 // Now we'll try to create (update) the whole GUI session.
616     updateSession();
617 capela 109
618     // Save as default session directory.
619     if (m_pOptions)
620     m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);
621     // We're not dirty anymore.
622     m_iDirtyCount = 0;
623     // Stabilize form...
624     m_sFilename = sFilename;
625     updateRecentFiles(sFilename);
626     appendMessages(tr("Open session: \"%1\".").arg(sessionName(m_sFilename)));
627 capela 301
628     // Make that an overall update.
629 capela 109 stabilizeForm();
630     return true;
631     }
632    
633    
634     // Save current session to specific file path.
635     bool qsamplerMainForm::saveSessionFile ( const QString& sFilename )
636     {
637     // Open and write into real file.
638     QFile file(sFilename);
639     if (!file.open(IO_WriteOnly | IO_Truncate)) {
640     appendMessagesError(tr("Could not open \"%1\" session file.\n\nSorry.").arg(sFilename));
641     return false;
642     }
643    
644     // Write the file.
645 capela 455 int iErrors = 0;
646 capela 109 QTextStream ts(&file);
647     ts << "# " << QSAMPLER_TITLE " - " << tr(QSAMPLER_SUBTITLE) << endl;
648     ts << "# " << tr("Version")
649     << ": " QSAMPLER_VERSION << endl;
650     ts << "# " << tr("Build")
651     << ": " __DATE__ " " __TIME__ << endl;
652     ts << "#" << endl;
653     ts << "# " << tr("File")
654     << ": " << QFileInfo(sFilename).fileName() << endl;
655     ts << "# " << tr("Date")
656 capela 455 << ": " << QDate::currentDate().toString("MMM dd yyyy")
657 capela 109 << " " << QTime::currentTime().toString("hh:mm:ss") << endl;
658     ts << "#" << endl;
659     ts << endl;
660 capela 455 // It is assumed that this new kind of device+session file
661     // will be loaded from a complete
662     int *piDeviceIDs;
663     int iDevice;
664     ts << "RESET" << endl;
665     // Audio device mapping.
666     QMap<int, int> audioDeviceMap;
667     piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Audio);
668     for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {
669 capela 463 ts << endl;
670 capela 455 qsamplerDevice device(m_pClient, qsamplerDevice::Audio, piDeviceIDs[iDevice]);
671 capela 463 // Audio device specification...
672 capela 455 ts << "# " << device.deviceTypeName() << " " << device.driverName()
673     << " " << tr("Device") << " " << iDevice << endl;
674     ts << "CREATE AUDIO_OUTPUT_DEVICE " << device.driverName();
675 capela 463 qsamplerDeviceParamMap::ConstIterator deviceParam;
676     for (deviceParam = device.params().begin();
677     deviceParam != device.params().end();
678     ++deviceParam) {
679     ts << " " << deviceParam.key()
680     << "='" << deviceParam.data().value << "'";
681     }
682 capela 455 ts << endl;
683 capela 463 // Audio channel parameters...
684     int iPort = 0;
685     for (qsamplerDevicePort *pPort = device.ports().first();
686     pPort;
687     pPort = device.ports().next(), ++iPort) {
688     qsamplerDeviceParamMap::ConstIterator portParam;
689     for (portParam = pPort->params().begin();
690     portParam != pPort->params().end();
691     ++portParam) {
692     ts << "SET AUDIO_OUTPUT_CHANNEL_PARAMETER " << iDevice
693     << " " << iPort << " " << portParam.key()
694     << "='" << portParam.data().value << "'" << endl;
695     }
696     }
697     // Set device index/id mapping.
698 capela 455 audioDeviceMap[device.deviceID()] = iDevice;
699     // Try to keep it snappy :)
700     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
701     }
702     // MIDI device mapping.
703     QMap<int, int> midiDeviceMap;
704     piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Midi);
705     for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {
706 capela 463 ts << endl;
707 capela 455 qsamplerDevice device(m_pClient, qsamplerDevice::Midi, piDeviceIDs[iDevice]);
708 capela 463 // MIDI device specification...
709 capela 455 ts << "# " << device.deviceTypeName() << " " << device.driverName()
710     << " " << tr("Device") << " " << iDevice << endl;
711     ts << "CREATE MIDI_INPUT_DEVICE " << device.driverName();
712 capela 463 qsamplerDeviceParamMap::ConstIterator deviceParam;
713     for (deviceParam = device.params().begin();
714     deviceParam != device.params().end();
715     ++deviceParam) {
716     ts << " " << deviceParam.key()
717     << "='" << deviceParam.data().value << "'";
718     }
719 capela 455 ts << endl;
720 capela 463 // MIDI port parameters...
721     int iPort = 0;
722     for (qsamplerDevicePort *pPort = device.ports().first();
723     pPort;
724     pPort = device.ports().next(), ++iPort) {
725     qsamplerDeviceParamMap::ConstIterator portParam;
726     for (portParam = pPort->params().begin();
727     portParam != pPort->params().end();
728     ++portParam) {
729     ts << "SET MIDI_INPUT_PORT_PARAMETER " << iDevice
730     << " " << iPort << " " << portParam.key()
731     << "='" << portParam.data().value << "'" << endl;
732     }
733     }
734 capela 455 }
735     ts << endl;
736     // Sampler channel mapping.
737 capela 109 QWidgetList wlist = m_pWorkspace->windowList();
738     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
739 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
740     if (pChannelStrip) {
741     qsamplerChannel *pChannel = pChannelStrip->channel();
742     if (pChannel) {
743 capela 455 ts << "# " << tr("Channel") << " " << iChannel << endl;
744 capela 264 ts << "ADD CHANNEL" << endl;
745 capela 455 if (audioDeviceMap.isEmpty()) {
746     ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannel
747     << " " << pChannel->audioDriver() << endl;
748     } else {
749     ts << "SET CHANNEL AUDIO_OUTPUT_DEVICE " << iChannel
750     << " " << audioDeviceMap[pChannel->audioDevice()] << endl;
751     }
752     if (midiDeviceMap.isEmpty()) {
753     ts << "SET CHANNEL MIDI_INPUT_TYPE " << iChannel
754     << " " << pChannel->midiDriver() << endl;
755     } else {
756     ts << "SET CHANNEL MIDI_INPUT_DEVICE " << iChannel
757     << " " << midiDeviceMap[pChannel->midiDevice()] << endl;
758     }
759     ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannel
760     << " " << pChannel->midiPort() << endl;
761 capela 409 ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannel << " ";
762 capela 304 if (pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL)
763     ts << "ALL";
764     else
765 capela 264 ts << pChannel->midiChannel();
766     ts << endl;
767 capela 409 ts << "LOAD ENGINE " << pChannel->engineName() << " " << iChannel << endl;
768     ts << "LOAD INSTRUMENT NON_MODAL '" << pChannel->instrumentFile() << "' " << pChannel->instrumentNr() << " " << iChannel << endl;
769     ts << "SET CHANNEL VOLUME " << iChannel << " " << pChannel->volume() << endl;
770 capela 264 ts << endl;
771     }
772     }
773 capela 109 // Try to keep it snappy :)
774     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
775     }
776    
777     // Ok. we've wrote it.
778     file.close();
779    
780     // Have we any errors?
781     if (iErrors > 0)
782     appendMessagesError(tr("Some settings could not be saved\nto \"%1\" session file.\n\nSorry.").arg(sFilename));
783    
784     // Save as default session directory.
785     if (m_pOptions)
786     m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);
787     // We're not dirty anymore.
788     m_iDirtyCount = 0;
789     // Stabilize form...
790     m_sFilename = sFilename;
791     updateRecentFiles(sFilename);
792     appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename)));
793     stabilizeForm();
794     return true;
795     }
796    
797    
798 capela 433 // Session change receiver slot.
799     void qsamplerMainForm::sessionDirty (void)
800     {
801     // Just mark the dirty form.
802     m_iDirtyCount++;
803     // and update the form status...
804     stabilizeForm();
805     }
806    
807    
808 capela 109 //-------------------------------------------------------------------------
809     // qsamplerMainForm -- File Action slots.
810    
811     // Create a new sampler session.
812     void qsamplerMainForm::fileNew (void)
813     {
814     // Of course we'll start clean new.
815     newSession();
816     }
817    
818    
819     // Open an existing sampler session.
820     void qsamplerMainForm::fileOpen (void)
821     {
822     // Open it right away.
823     openSession();
824     }
825    
826    
827     // Open a recent file session.
828     void qsamplerMainForm::fileOpenRecent ( int iIndex )
829     {
830     // Check if we can safely close the current session...
831     if (m_pOptions && closeSession(true)) {
832     QString sFilename = m_pOptions->recentFiles[iIndex];
833     loadSessionFile(sFilename);
834     }
835     }
836    
837    
838     // Save current sampler session.
839     void qsamplerMainForm::fileSave (void)
840     {
841     // Save it right away.
842     saveSession(false);
843     }
844    
845    
846     // Save current sampler session with another name.
847     void qsamplerMainForm::fileSaveAs (void)
848     {
849     // Save it right away, maybe with another name.
850     saveSession(true);
851     }
852    
853    
854 capela 255 // Reset the sampler instance.
855     void qsamplerMainForm::fileReset (void)
856     {
857     if (m_pClient == NULL)
858     return;
859    
860     // Ask user whether he/she want's an internal sampler reset...
861     if (QMessageBox::warning(this, tr("Warning"),
862     tr("Resetting the sampler instance will close\n"
863     "all device and channel configurations.\n\n"
864     "Please note that this operation may cause\n"
865     "temporary MIDI and Audio disruption\n\n"
866     "Do you want to reset the sampler engine now?"),
867     tr("Reset"), tr("Cancel")) > 0)
868     return;
869    
870     // Just do the reset, after closing down current session...
871 capela 261 if (closeSession(true) && ::lscp_reset_sampler(m_pClient) != LSCP_OK) {
872 capela 255 appendMessagesClient("lscp_reset_sampler");
873 capela 261 appendMessagesError(tr("Could not reset sampler instance.\n\nSorry."));
874     return;
875     }
876    
877     // Log this.
878     appendMessages(tr("Sampler reset."));
879 capela 395
880     // Make it a new session...
881     newSession();
882 capela 255 }
883    
884    
885 capela 109 // Restart the client/server instance.
886     void qsamplerMainForm::fileRestart (void)
887     {
888     if (m_pOptions == NULL)
889     return;
890    
891     bool bRestart = true;
892    
893     // Ask user whether he/she want's a complete restart...
894     // (if we're currently up and running)
895     if (bRestart && m_pClient) {
896     bRestart = (QMessageBox::warning(this, tr("Warning"),
897     tr("New settings will be effective after\n"
898     "restarting the client/server connection.\n\n"
899     "Please note that this operation may cause\n"
900     "temporary MIDI and Audio disruption\n\n"
901     "Do you want to restart the connection now?"),
902     tr("Restart"), tr("Cancel")) == 0);
903     }
904    
905     // Are we still for it?
906     if (bRestart && closeSession(true)) {
907     // Stop server, it will force the client too.
908     stopServer();
909     // Reschedule a restart...
910     startSchedule(m_pOptions->iStartDelay);
911     }
912     }
913    
914    
915     // Exit application program.
916     void qsamplerMainForm::fileExit (void)
917     {
918     // Go for close the whole thing.
919     close();
920     }
921    
922    
923     //-------------------------------------------------------------------------
924     // qsamplerMainForm -- Edit Action slots.
925    
926     // Add a new sampler channel.
927     void qsamplerMainForm::editAddChannel (void)
928     {
929     if (m_pClient == NULL)
930     return;
931    
932 capela 303 // Just create the channel instance...
933     qsamplerChannel *pChannel = new qsamplerChannel(this);
934     if (pChannel == NULL)
935     return;
936    
937     // Before we show it up, may be we'll
938     // better ask for some initial values?
939     if (!pChannel->channelSetup(this)) {
940     delete pChannel;
941     return;
942     }
943    
944     // And give it to the strip (will own the channel instance, if successful).
945     if (!createChannelStrip(pChannel)) {
946     delete pChannel;
947     return;
948     }
949    
950     // Make that an overall update.
951     m_iDirtyCount++;
952     stabilizeForm();
953 capela 109 }
954    
955    
956     // Remove current sampler channel.
957     void qsamplerMainForm::editRemoveChannel (void)
958     {
959     if (m_pClient == NULL)
960     return;
961    
962 capela 264 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
963     if (pChannelStrip == NULL)
964     return;
965    
966     qsamplerChannel *pChannel = pChannelStrip->channel();
967 capela 109 if (pChannel == NULL)
968     return;
969    
970     // Prompt user if he/she's sure about this...
971     if (m_pOptions && m_pOptions->bConfirmRemove) {
972     if (QMessageBox::warning(this, tr("Warning"),
973     tr("About to remove channel:\n\n"
974     "%1\n\n"
975     "Are you sure?")
976 capela 264 .arg(pChannelStrip->caption()),
977 capela 109 tr("OK"), tr("Cancel")) > 0)
978     return;
979     }
980    
981     // Remove the existing sampler channel.
982 capela 295 if (!pChannel->removeChannel())
983 capela 109 return;
984    
985     // Just delete the channel strip.
986 capela 265 delete pChannelStrip;
987    
988 capela 109 // Do we auto-arrange?
989     if (m_pOptions && m_pOptions->bAutoArrange)
990     channelsArrange();
991    
992     // We'll be dirty, for sure...
993     m_iDirtyCount++;
994     stabilizeForm();
995     }
996    
997    
998     // Setup current sampler channel.
999     void qsamplerMainForm::editSetupChannel (void)
1000     {
1001     if (m_pClient == NULL)
1002     return;
1003    
1004 capela 264 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
1005     if (pChannelStrip == NULL)
1006 capela 109 return;
1007    
1008     // Just invoque the channel strip procedure.
1009 capela 295 pChannelStrip->channelSetup();
1010 capela 109 }
1011    
1012    
1013     // Reset current sampler channel.
1014     void qsamplerMainForm::editResetChannel (void)
1015     {
1016     if (m_pClient == NULL)
1017     return;
1018    
1019 capela 264 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
1020     if (pChannelStrip == NULL)
1021     return;
1022    
1023 capela 400 // Just invoque the channel strip procedure.
1024     pChannelStrip->channelReset();
1025 capela 109 }
1026    
1027    
1028 capela 404 // Reset all sampler channels.
1029     void qsamplerMainForm::editResetAllChannels (void)
1030     {
1031     if (m_pClient == NULL)
1032     return;
1033    
1034     // Invoque the channel strip procedure,
1035     // for all channels out there...
1036     m_pWorkspace->setUpdatesEnabled(false);
1037     QWidgetList wlist = m_pWorkspace->windowList();
1038     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1039     qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1040     if (pChannelStrip)
1041     pChannelStrip->channelReset();
1042     }
1043     m_pWorkspace->setUpdatesEnabled(true);
1044     }
1045    
1046    
1047 capela 109 //-------------------------------------------------------------------------
1048     // qsamplerMainForm -- View Action slots.
1049    
1050     // Show/hide the main program window menubar.
1051     void qsamplerMainForm::viewMenubar ( bool bOn )
1052     {
1053     if (bOn)
1054     MenuBar->show();
1055     else
1056     MenuBar->hide();
1057     }
1058    
1059    
1060     // Show/hide the main program window toolbar.
1061     void qsamplerMainForm::viewToolbar ( bool bOn )
1062     {
1063     if (bOn) {
1064     fileToolbar->show();
1065     editToolbar->show();
1066     channelsToolbar->show();
1067     } else {
1068     fileToolbar->hide();
1069     editToolbar->hide();
1070     channelsToolbar->hide();
1071     }
1072     }
1073    
1074    
1075     // Show/hide the main program window statusbar.
1076     void qsamplerMainForm::viewStatusbar ( bool bOn )
1077     {
1078     if (bOn)
1079     statusBar()->show();
1080     else
1081     statusBar()->hide();
1082     }
1083    
1084    
1085     // Show/hide the messages window logger.
1086     void qsamplerMainForm::viewMessages ( bool bOn )
1087     {
1088     if (bOn)
1089     m_pMessages->show();
1090     else
1091     m_pMessages->hide();
1092     }
1093    
1094    
1095 capela 428 // Show/hide the device configurator form.
1096     void qsamplerMainForm::viewDevices (void)
1097     {
1098     if (m_pOptions == NULL)
1099     return;
1100    
1101     if (m_pDeviceForm) {
1102     m_pOptions->saveWidgetGeometry(m_pDeviceForm);
1103     m_pDeviceForm->setClient(m_pClient);
1104     if (m_pDeviceForm->isVisible()) {
1105     m_pDeviceForm->hide();
1106     } else {
1107     m_pDeviceForm->show();
1108     m_pDeviceForm->raise();
1109     m_pDeviceForm->setActiveWindow();
1110     }
1111     }
1112     }
1113    
1114    
1115 capela 109 // Show options dialog.
1116     void qsamplerMainForm::viewOptions (void)
1117     {
1118     if (m_pOptions == NULL)
1119     return;
1120    
1121     qsamplerOptionsForm *pOptionsForm = new qsamplerOptionsForm(this);
1122     if (pOptionsForm) {
1123     // Check out some initial nullities(tm)...
1124 capela 264 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
1125     if (m_pOptions->sDisplayFont.isEmpty() && pChannelStrip)
1126     m_pOptions->sDisplayFont = pChannelStrip->displayFont().toString();
1127 capela 109 if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages)
1128     m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();
1129     // To track down deferred or immediate changes.
1130     QString sOldServerHost = m_pOptions->sServerHost;
1131     int iOldServerPort = m_pOptions->iServerPort;
1132     int iOldServerTimeout = m_pOptions->iServerTimeout;
1133     bool bOldServerStart = m_pOptions->bServerStart;
1134     QString sOldServerCmdLine = m_pOptions->sServerCmdLine;
1135     QString sOldDisplayFont = m_pOptions->sDisplayFont;
1136 capela 267 bool bOldDisplayEffect = m_pOptions->bDisplayEffect;
1137 capela 119 int iOldMaxVolume = m_pOptions->iMaxVolume;
1138 capela 109 QString sOldMessagesFont = m_pOptions->sMessagesFont;
1139 capela 454 bool bOldKeepOnTop = m_pOptions->bKeepOnTop;
1140 capela 109 bool bOldStdoutCapture = m_pOptions->bStdoutCapture;
1141     int bOldMessagesLimit = m_pOptions->bMessagesLimit;
1142     int iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines;
1143     bool bOldCompletePath = m_pOptions->bCompletePath;
1144 capela 371 bool bOldInstrumentNames = m_pOptions->bInstrumentNames;
1145 capela 109 int iOldMaxRecentFiles = m_pOptions->iMaxRecentFiles;
1146     // Load the current setup settings.
1147     pOptionsForm->setup(m_pOptions);
1148     // Show the setup dialog...
1149     if (pOptionsForm->exec()) {
1150     // Warn if something will be only effective on next run.
1151     if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) ||
1152 capela 454 (!bOldStdoutCapture && m_pOptions->bStdoutCapture) ||
1153     ( bOldKeepOnTop && !m_pOptions->bKeepOnTop) ||
1154     (!bOldKeepOnTop && m_pOptions->bKeepOnTop)) {
1155 capela 109 QMessageBox::information(this, tr("Information"),
1156     tr("Some settings may be only effective\n"
1157     "next time you start this program."), tr("OK"));
1158     updateMessagesCapture();
1159     }
1160     // Check wheather something immediate has changed.
1161     if (( bOldCompletePath && !m_pOptions->bCompletePath) ||
1162     (!bOldCompletePath && m_pOptions->bCompletePath) ||
1163     (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles))
1164     updateRecentFilesMenu();
1165 capela 371 if (( bOldInstrumentNames && !m_pOptions->bInstrumentNames) ||
1166     (!bOldInstrumentNames && m_pOptions->bInstrumentNames))
1167     updateInstrumentNames();
1168 capela 267 if (( bOldDisplayEffect && !m_pOptions->bDisplayEffect) ||
1169     (!bOldDisplayEffect && m_pOptions->bDisplayEffect))
1170     updateDisplayEffect();
1171 capela 109 if (sOldDisplayFont != m_pOptions->sDisplayFont)
1172     updateDisplayFont();
1173 capela 119 if (iOldMaxVolume != m_pOptions->iMaxVolume)
1174     updateMaxVolume();
1175 capela 109 if (sOldMessagesFont != m_pOptions->sMessagesFont)
1176     updateMessagesFont();
1177     if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) ||
1178     (!bOldMessagesLimit && m_pOptions->bMessagesLimit) ||
1179     (iOldMessagesLimitLines != m_pOptions->iMessagesLimitLines))
1180     updateMessagesLimit();
1181     // And now the main thing, whether we'll do client/server recycling?
1182     if ((sOldServerHost != m_pOptions->sServerHost) ||
1183     (iOldServerPort != m_pOptions->iServerPort) ||
1184     (iOldServerTimeout != m_pOptions->iServerTimeout) ||
1185     ( bOldServerStart && !m_pOptions->bServerStart) ||
1186     (!bOldServerStart && m_pOptions->bServerStart) ||
1187     (sOldServerCmdLine != m_pOptions->sServerCmdLine && m_pOptions->bServerStart))
1188     fileRestart();
1189     }
1190     // Done.
1191     delete pOptionsForm;
1192     }
1193    
1194     // This makes it.
1195     stabilizeForm();
1196     }
1197    
1198    
1199     //-------------------------------------------------------------------------
1200     // qsamplerMainForm -- Channels action slots.
1201    
1202     // Arrange channel strips.
1203     void qsamplerMainForm::channelsArrange (void)
1204     {
1205     // Full width vertical tiling
1206     QWidgetList wlist = m_pWorkspace->windowList();
1207     if (wlist.isEmpty())
1208     return;
1209    
1210     m_pWorkspace->setUpdatesEnabled(false);
1211     int y = 0;
1212     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1213 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1214     /* if (pChannelStrip->testWState(WState_Maximized | WState_Minimized)) {
1215 capela 109 // Prevent flicker...
1216 capela 264 pChannelStrip->hide();
1217     pChannelStrip->showNormal();
1218 capela 109 } */
1219 capela 264 pChannelStrip->adjustSize();
1220 capela 109 int iWidth = m_pWorkspace->width();
1221 capela 264 if (iWidth < pChannelStrip->width())
1222     iWidth = pChannelStrip->width();
1223     // int iHeight = pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();
1224     int iHeight = pChannelStrip->parentWidget()->frameGeometry().height();
1225     pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1226 capela 109 y += iHeight;
1227     }
1228     m_pWorkspace->setUpdatesEnabled(true);
1229    
1230     stabilizeForm();
1231     }
1232    
1233    
1234     // Auto-arrange channel strips.
1235     void qsamplerMainForm::channelsAutoArrange ( bool bOn )
1236     {
1237     if (m_pOptions == NULL)
1238     return;
1239    
1240     // Toggle the auto-arrange flag.
1241     m_pOptions->bAutoArrange = bOn;
1242    
1243     // If on, update whole workspace...
1244     if (m_pOptions->bAutoArrange)
1245     channelsArrange();
1246     }
1247    
1248    
1249     //-------------------------------------------------------------------------
1250     // qsamplerMainForm -- Help Action slots.
1251    
1252     // Show information about the Qt toolkit.
1253     void qsamplerMainForm::helpAboutQt (void)
1254     {
1255     QMessageBox::aboutQt(this);
1256     }
1257    
1258    
1259     // Show information about application program.
1260     void qsamplerMainForm::helpAbout (void)
1261     {
1262     // Stuff the about box text...
1263     QString sText = "<p>\n";
1264     sText += "<b>" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "</b><br />\n";
1265     sText += "<br />\n";
1266     sText += tr("Version") + ": <b>" QSAMPLER_VERSION "</b><br />\n";
1267     sText += "<small>" + tr("Build") + ": " __DATE__ " " __TIME__ "</small><br />\n";
1268     #ifdef CONFIG_DEBUG
1269     sText += "<small><font color=\"red\">";
1270     sText += tr("Debugging option enabled.");
1271     sText += "</font></small><br />";
1272     #endif
1273 capela 176 #ifndef CONFIG_LIBGIG
1274     sText += "<small><font color=\"red\">";
1275     sText += tr("GIG (libgig) file support disabled.");
1276     sText += "</font></small><br />";
1277     #endif
1278 capela 382 #ifndef CONFIG_INSTRUMENT_NAME
1279     sText += "<small><font color=\"red\">";
1280     sText += tr("LSCP (liblscp) instrument_name support disabled.");
1281     sText += "</font></small><br />";
1282     #endif
1283 capela 109 sText += "<br />\n";
1284     sText += tr("Using") + ": ";
1285     sText += ::lscp_client_package();
1286     sText += " ";
1287     sText += ::lscp_client_version();
1288     sText += "<br />\n";
1289     sText += "<br />\n";
1290     sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";
1291     sText += "<br />\n";
1292     sText += "<small>";
1293     sText += QSAMPLER_COPYRIGHT "<br />\n";
1294     sText += "<br />\n";
1295     sText += tr("This program is free software; you can redistribute it and/or modify it") + "<br />\n";
1296     sText += tr("under the terms of the GNU General Public License version 2 or later.");
1297     sText += "</small>";
1298     sText += "</p>\n";
1299    
1300     QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText);
1301     }
1302    
1303    
1304     //-------------------------------------------------------------------------
1305     // qsamplerMainForm -- Main window stabilization.
1306    
1307     void qsamplerMainForm::stabilizeForm (void)
1308     {
1309     // Update the main application caption...
1310 capela 418 QString sSessionName = sessionName(m_sFilename);
1311 capela 109 if (m_iDirtyCount > 0)
1312 capela 418 sSessionName += '*';
1313     setCaption(tr(QSAMPLER_TITLE " - [%1]").arg(sSessionName));
1314 capela 109
1315     // Update the main menu state...
1316 capela 264 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
1317 capela 109 bool bHasClient = (m_pOptions != NULL && m_pClient != NULL);
1318 capela 264 bool bHasChannel = (bHasClient && pChannelStrip != NULL);
1319 capela 109 fileNewAction->setEnabled(bHasClient);
1320     fileOpenAction->setEnabled(bHasClient);
1321     fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);
1322     fileSaveAsAction->setEnabled(bHasClient);
1323 capela 255 fileResetAction->setEnabled(bHasClient);
1324 capela 109 fileRestartAction->setEnabled(bHasClient || m_pServer == NULL);
1325     editAddChannelAction->setEnabled(bHasClient);
1326     editRemoveChannelAction->setEnabled(bHasChannel);
1327     editSetupChannelAction->setEnabled(bHasChannel);
1328     editResetChannelAction->setEnabled(bHasChannel);
1329 capela 404 editResetAllChannelsAction->setEnabled(bHasChannel);
1330 capela 428 viewMessagesAction->setOn(m_pMessages && m_pMessages->isVisible());
1331     viewDevicesAction->setOn(m_pDeviceForm && m_pDeviceForm->isVisible());
1332     viewDevicesAction->setEnabled(bHasClient);
1333 capela 109 channelsArrangeAction->setEnabled(bHasChannel);
1334    
1335     // Client/Server status...
1336     if (bHasClient) {
1337 capela 428 m_statusItem[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));
1338     m_statusItem[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost + ":" + QString::number(m_pOptions->iServerPort));
1339 capela 109 } else {
1340 capela 428 m_statusItem[QSAMPLER_STATUS_CLIENT]->clear();
1341     m_statusItem[QSAMPLER_STATUS_SERVER]->clear();
1342 capela 109 }
1343     // Channel status...
1344     if (bHasChannel)
1345 capela 428 m_statusItem[QSAMPLER_STATUS_CHANNEL]->setText(pChannelStrip->caption());
1346 capela 109 else
1347 capela 428 m_statusItem[QSAMPLER_STATUS_CHANNEL]->clear();
1348 capela 109 // Session status...
1349     if (m_iDirtyCount > 0)
1350 capela 428 m_statusItem[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));
1351 capela 109 else
1352 capela 428 m_statusItem[QSAMPLER_STATUS_SESSION]->clear();
1353 capela 109
1354     // Recent files menu.
1355     m_pRecentFilesMenu->setEnabled(bHasClient && m_pOptions->recentFiles.count() > 0);
1356    
1357     // Always make the latest message visible.
1358     if (m_pMessages)
1359     m_pMessages->scrollToBottom();
1360     }
1361    
1362    
1363     // Channel change receiver slot.
1364 capela 400 void qsamplerMainForm::channelStripChanged( qsamplerChannelStrip *pChannelStrip )
1365 capela 109 {
1366 capela 400 // Add this strip to the changed list...
1367     if (m_changedStrips.containsRef(pChannelStrip) == 0)
1368     m_changedStrips.append(pChannelStrip);
1369    
1370 capela 109 // Just mark the dirty form.
1371     m_iDirtyCount++;
1372     // and update the form status...
1373     stabilizeForm();
1374     }
1375    
1376    
1377 capela 395 // Grab and restore current sampler channels session.
1378     void qsamplerMainForm::updateSession (void)
1379     {
1380     // Retrieve the current channel list.
1381     int *piChannelIDs = ::lscp_list_channels(m_pClient);
1382     if (piChannelIDs == NULL) {
1383     if (::lscp_client_get_errno(m_pClient)) {
1384     appendMessagesClient("lscp_list_channels");
1385     appendMessagesError(tr("Could not get current list of channels.\n\nSorry."));
1386     }
1387     return;
1388     }
1389    
1390     // Try to (re)create each channel.
1391     m_pWorkspace->setUpdatesEnabled(false);
1392     for (int iChannel = 0; piChannelIDs[iChannel] >= 0; iChannel++) {
1393     // Check if theres already a channel strip for this one...
1394     if (!channelStrip(piChannelIDs[iChannel]))
1395     createChannelStrip(new qsamplerChannel(this, piChannelIDs[iChannel]));
1396     // Make it visibly responsive...
1397     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
1398     }
1399     m_pWorkspace->setUpdatesEnabled(true);
1400     }
1401    
1402    
1403 capela 109 // Update the recent files list and menu.
1404     void qsamplerMainForm::updateRecentFiles ( const QString& sFilename )
1405     {
1406     if (m_pOptions == NULL)
1407     return;
1408    
1409     // Remove from list if already there (avoid duplicates)
1410     QStringList::Iterator iter = m_pOptions->recentFiles.find(sFilename);
1411     if (iter != m_pOptions->recentFiles.end())
1412     m_pOptions->recentFiles.remove(iter);
1413     // Put it to front...
1414     m_pOptions->recentFiles.push_front(sFilename);
1415    
1416     // May update the menu.
1417     updateRecentFilesMenu();
1418     }
1419    
1420    
1421     // Update the recent files list and menu.
1422     void qsamplerMainForm::updateRecentFilesMenu (void)
1423     {
1424     if (m_pOptions == NULL)
1425     return;
1426    
1427     // Time to keep the list under limits.
1428     int iRecentFiles = m_pOptions->recentFiles.count();
1429     while (iRecentFiles > m_pOptions->iMaxRecentFiles) {
1430     m_pOptions->recentFiles.pop_back();
1431     iRecentFiles--;
1432     }
1433    
1434     // rebuild the recent files menu...
1435     m_pRecentFilesMenu->clear();
1436     for (int i = 0; i < iRecentFiles; i++) {
1437     const QString& sFilename = m_pOptions->recentFiles[i];
1438     if (QFileInfo(sFilename).exists()) {
1439     m_pRecentFilesMenu->insertItem(QString("&%1 %2")
1440     .arg(i + 1).arg(sessionName(sFilename)),
1441     this, SLOT(fileOpenRecent(int)), 0, i);
1442     }
1443     }
1444     }
1445    
1446    
1447 capela 371 // Force update of the channels instrument names mode.
1448     void qsamplerMainForm::updateInstrumentNames (void)
1449     {
1450     // Full channel list update...
1451     QWidgetList wlist = m_pWorkspace->windowList();
1452     if (wlist.isEmpty())
1453     return;
1454    
1455     m_pWorkspace->setUpdatesEnabled(false);
1456     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1457     qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1458     if (pChannelStrip)
1459     pChannelStrip->updateInstrumentName(true);
1460     }
1461     m_pWorkspace->setUpdatesEnabled(true);
1462     }
1463    
1464    
1465 capela 109 // Force update of the channels display font.
1466     void qsamplerMainForm::updateDisplayFont (void)
1467     {
1468     if (m_pOptions == NULL)
1469     return;
1470    
1471     // Check if display font is legal.
1472     if (m_pOptions->sDisplayFont.isEmpty())
1473     return;
1474     // Realize it.
1475     QFont font;
1476     if (!font.fromString(m_pOptions->sDisplayFont))
1477     return;
1478    
1479     // Full channel list update...
1480     QWidgetList wlist = m_pWorkspace->windowList();
1481     if (wlist.isEmpty())
1482     return;
1483    
1484     m_pWorkspace->setUpdatesEnabled(false);
1485     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1486 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1487     if (pChannelStrip)
1488     pChannelStrip->setDisplayFont(font);
1489 capela 109 }
1490     m_pWorkspace->setUpdatesEnabled(true);
1491     }
1492    
1493    
1494 capela 267 // Update channel strips background effect.
1495     void qsamplerMainForm::updateDisplayEffect (void)
1496     {
1497     QPixmap pm;
1498     if (m_pOptions->bDisplayEffect)
1499     pm = QPixmap::fromMimeSource("displaybg1.png");
1500    
1501     // Full channel list update...
1502     QWidgetList wlist = m_pWorkspace->windowList();
1503     if (wlist.isEmpty())
1504     return;
1505    
1506     m_pWorkspace->setUpdatesEnabled(false);
1507     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1508     qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1509     if (pChannelStrip)
1510     pChannelStrip->setDisplayBackground(pm);
1511     }
1512     m_pWorkspace->setUpdatesEnabled(true);
1513     }
1514    
1515    
1516 capela 119 // Force update of the channels maximum volume setting.
1517     void qsamplerMainForm::updateMaxVolume (void)
1518     {
1519     if (m_pOptions == NULL)
1520     return;
1521    
1522     // Full channel list update...
1523     QWidgetList wlist = m_pWorkspace->windowList();
1524     if (wlist.isEmpty())
1525     return;
1526    
1527     m_pWorkspace->setUpdatesEnabled(false);
1528     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1529 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1530     if (pChannelStrip)
1531     pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
1532 capela 119 }
1533     m_pWorkspace->setUpdatesEnabled(true);
1534     }
1535    
1536    
1537 capela 109 //-------------------------------------------------------------------------
1538     // qsamplerMainForm -- Messages window form handlers.
1539    
1540     // Messages output methods.
1541     void qsamplerMainForm::appendMessages( const QString& s )
1542     {
1543     if (m_pMessages)
1544     m_pMessages->appendMessages(s);
1545    
1546     statusBar()->message(s, 3000);
1547     }
1548    
1549     void qsamplerMainForm::appendMessagesColor( const QString& s, const QString& c )
1550     {
1551     if (m_pMessages)
1552     m_pMessages->appendMessagesColor(s, c);
1553    
1554     statusBar()->message(s, 3000);
1555     }
1556    
1557     void qsamplerMainForm::appendMessagesText( const QString& s )
1558     {
1559     if (m_pMessages)
1560     m_pMessages->appendMessagesText(s);
1561     }
1562    
1563     void qsamplerMainForm::appendMessagesError( const QString& s )
1564     {
1565     if (m_pMessages)
1566     m_pMessages->show();
1567    
1568     appendMessagesColor(s.simplifyWhiteSpace(), "#ff0000");
1569    
1570     QMessageBox::critical(this, tr("Error"), s, tr("Cancel"));
1571     }
1572    
1573    
1574     // This is a special message format, just for client results.
1575     void qsamplerMainForm::appendMessagesClient( const QString& s )
1576     {
1577     if (m_pClient == NULL)
1578     return;
1579    
1580     appendMessagesColor(s + QString(": %1 (errno=%2)")
1581     .arg(::lscp_client_get_result(m_pClient))
1582     .arg(::lscp_client_get_errno(m_pClient)), "#996666");
1583     }
1584    
1585    
1586     // Force update of the messages font.
1587     void qsamplerMainForm::updateMessagesFont (void)
1588     {
1589     if (m_pOptions == NULL)
1590     return;
1591    
1592     if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {
1593     QFont font;
1594     if (font.fromString(m_pOptions->sMessagesFont))
1595     m_pMessages->setMessagesFont(font);
1596     }
1597     }
1598    
1599    
1600     // Update messages window line limit.
1601     void qsamplerMainForm::updateMessagesLimit (void)
1602     {
1603     if (m_pOptions == NULL)
1604     return;
1605    
1606     if (m_pMessages) {
1607     if (m_pOptions->bMessagesLimit)
1608     m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);
1609     else
1610     m_pMessages->setMessagesLimit(0);
1611     }
1612     }
1613    
1614    
1615     // Enablement of the messages capture feature.
1616     void qsamplerMainForm::updateMessagesCapture (void)
1617     {
1618     if (m_pOptions == NULL)
1619     return;
1620    
1621     if (m_pMessages)
1622     m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);
1623     }
1624    
1625    
1626     //-------------------------------------------------------------------------
1627     // qsamplerMainForm -- MDI channel strip management.
1628    
1629     // The channel strip creation executive.
1630 capela 303 qsamplerChannelStrip *qsamplerMainForm::createChannelStrip ( qsamplerChannel *pChannel )
1631 capela 109 {
1632 capela 303 if (m_pClient == NULL || pChannel == NULL)
1633 capela 295 return NULL;
1634 capela 109
1635     // Prepare for auto-arrange?
1636 capela 264 qsamplerChannelStrip *pChannelStrip = NULL;
1637 capela 109 int y = 0;
1638     if (m_pOptions && m_pOptions->bAutoArrange) {
1639     QWidgetList wlist = m_pWorkspace->windowList();
1640     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1641 capela 264 pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1642 capela 395 if (pChannelStrip) {
1643     // y += pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();
1644     y += pChannelStrip->parentWidget()->frameGeometry().height();
1645     }
1646 capela 109 }
1647     }
1648    
1649     // Add a new channel itema...
1650     WFlags wflags = Qt::WStyle_Customize | Qt::WStyle_Tool | Qt::WStyle_Title | Qt::WStyle_NoBorder;
1651 capela 264 pChannelStrip = new qsamplerChannelStrip(m_pWorkspace, 0, wflags);
1652 capela 303 if (pChannelStrip == NULL)
1653     return NULL;
1654    
1655     // Actual channel strip setup...
1656     pChannelStrip->setup(pChannel);
1657 capela 295 QObject::connect(pChannelStrip, SIGNAL(channelChanged(qsamplerChannelStrip *)), this, SLOT(channelStripChanged(qsamplerChannelStrip *)));
1658 capela 267 // Set some initial aesthetic options...
1659     if (m_pOptions) {
1660     // Background display effect...
1661     pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
1662     // We'll need a display font.
1663     QFont font;
1664     if (font.fromString(m_pOptions->sDisplayFont))
1665     pChannelStrip->setDisplayFont(font);
1666     // Maximum allowed volume setting.
1667     pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
1668     }
1669 capela 295
1670 capela 109 // Now we show up us to the world.
1671 capela 264 pChannelStrip->show();
1672 capela 109 // Only then, we'll auto-arrange...
1673     if (m_pOptions && m_pOptions->bAutoArrange) {
1674     int iWidth = m_pWorkspace->width();
1675     // int iHeight = pChannel->height() + pChannel->parentWidget()->baseSize().height();
1676 capela 264 int iHeight = pChannelStrip->parentWidget()->frameGeometry().height();
1677     pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1678 capela 109 }
1679 capela 400
1680     // This is pretty new, so we'll watch for it closely.
1681     channelStripChanged(pChannelStrip);
1682    
1683 capela 295 // Return our successful reference...
1684     return pChannelStrip;
1685 capela 109 }
1686    
1687    
1688     // Retrieve the active channel strip.
1689 capela 264 qsamplerChannelStrip *qsamplerMainForm::activeChannelStrip (void)
1690 capela 109 {
1691     return (qsamplerChannelStrip *) m_pWorkspace->activeWindow();
1692     }
1693    
1694    
1695     // Retrieve a channel strip by index.
1696 capela 264 qsamplerChannelStrip *qsamplerMainForm::channelStripAt ( int iChannel )
1697 capela 109 {
1698     QWidgetList wlist = m_pWorkspace->windowList();
1699     if (wlist.isEmpty())
1700 capela 395 return NULL;
1701 capela 109
1702     return (qsamplerChannelStrip *) wlist.at(iChannel);
1703     }
1704    
1705    
1706 capela 395 // Retrieve a channel strip by sampler channel id.
1707     qsamplerChannelStrip *qsamplerMainForm::channelStrip ( int iChannelID )
1708     {
1709     QWidgetList wlist = m_pWorkspace->windowList();
1710     if (wlist.isEmpty())
1711     return NULL;
1712    
1713     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1714     qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1715     if (pChannelStrip) {
1716     qsamplerChannel *pChannel = pChannelStrip->channel();
1717     if (pChannel && pChannel->channelID() == iChannelID)
1718     return pChannelStrip;
1719     }
1720     }
1721    
1722     // Not found.
1723     return NULL;
1724     }
1725    
1726    
1727 capela 109 // Construct the windows menu.
1728     void qsamplerMainForm::channelsMenuAboutToShow (void)
1729     {
1730     channelsMenu->clear();
1731     channelsArrangeAction->addTo(channelsMenu);
1732     channelsAutoArrangeAction->addTo(channelsMenu);
1733    
1734     QWidgetList wlist = m_pWorkspace->windowList();
1735     if (!wlist.isEmpty()) {
1736     channelsMenu->insertSeparator();
1737     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1738 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1739     if (pChannelStrip) {
1740     int iItemID = channelsMenu->insertItem(pChannelStrip->caption(), this, SLOT(channelsMenuActivated(int)));
1741     channelsMenu->setItemParameter(iItemID, iChannel);
1742     channelsMenu->setItemChecked(iItemID, activeChannelStrip() == pChannelStrip);
1743     }
1744 capela 109 }
1745     }
1746     }
1747    
1748    
1749     // Windows menu activation slot
1750     void qsamplerMainForm::channelsMenuActivated ( int iChannel )
1751     {
1752 capela 264 qsamplerChannelStrip *pChannelStrip = channelStripAt(iChannel);
1753     if (pChannelStrip)
1754     pChannelStrip->showNormal();
1755     pChannelStrip->setFocus();
1756 capela 109 }
1757    
1758    
1759     //-------------------------------------------------------------------------
1760     // qsamplerMainForm -- Timer stuff.
1761    
1762     // Set the pseudo-timer delay schedule.
1763     void qsamplerMainForm::startSchedule ( int iStartDelay )
1764     {
1765     m_iStartDelay = 1 + (iStartDelay * 1000);
1766     m_iTimerDelay = 0;
1767     }
1768    
1769     // Suspend the pseudo-timer delay schedule.
1770     void qsamplerMainForm::stopSchedule (void)
1771     {
1772     m_iStartDelay = 0;
1773     m_iTimerDelay = 0;
1774     }
1775    
1776     // Timer slot funtion.
1777     void qsamplerMainForm::timerSlot (void)
1778     {
1779     if (m_pOptions == NULL)
1780     return;
1781    
1782     // Is it the first shot on server start after a few delay?
1783     if (m_iTimerDelay < m_iStartDelay) {
1784     m_iTimerDelay += QSAMPLER_TIMER_MSECS;
1785     if (m_iTimerDelay >= m_iStartDelay) {
1786     // If we cannot start it now, maybe a lil'mo'later ;)
1787     if (!startClient()) {
1788     m_iStartDelay += m_iTimerDelay;
1789     m_iTimerDelay = 0;
1790     }
1791     }
1792     }
1793    
1794     // Refresh each channel usage, on each period...
1795 capela 400 if (m_pClient && (m_changedStrips.count() > 0 || m_pOptions->bAutoRefresh)) {
1796 capela 109 m_iTimerSlot += QSAMPLER_TIMER_MSECS;
1797 capela 296 if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime && m_pWorkspace->isUpdatesEnabled()) {
1798 capela 109 m_iTimerSlot = 0;
1799 capela 400 // Update the channel information for each pending strip...
1800     for (qsamplerChannelStrip *pChannelStrip = m_changedStrips.first();
1801     pChannelStrip;
1802     pChannelStrip = m_changedStrips.next()) {
1803     // If successfull, remove from pending list...
1804     if (pChannelStrip->updateChannelInfo())
1805     m_changedStrips.remove(pChannelStrip);
1806     }
1807     // Update the channel stream usage for each strip...
1808 capela 109 QWidgetList wlist = m_pWorkspace->windowList();
1809     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1810 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1811 capela 400 if (pChannelStrip && pChannelStrip->isVisible())
1812     pChannelStrip->updateChannelUsage();
1813 capela 109 }
1814     }
1815     }
1816    
1817     // Register the next timer slot.
1818     QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
1819     }
1820    
1821    
1822     //-------------------------------------------------------------------------
1823     // qsamplerMainForm -- Server stuff.
1824    
1825     // Start linuxsampler server...
1826     void qsamplerMainForm::startServer (void)
1827     {
1828     if (m_pOptions == NULL)
1829     return;
1830    
1831     // Aren't already a client, are we?
1832     if (!m_pOptions->bServerStart || m_pClient)
1833     return;
1834    
1835     // Is the server process instance still here?
1836     if (m_pServer) {
1837     switch (QMessageBox::warning(this, tr("Warning"),
1838     tr("Could not start the LinuxSampler server.\n\n"
1839     "Maybe it ss already started."),
1840     tr("Stop"), tr("Kill"), tr("Cancel"))) {
1841     case 0:
1842     m_pServer->tryTerminate();
1843     break;
1844     case 1:
1845     m_pServer->kill();
1846     break;
1847     }
1848     return;
1849     }
1850    
1851     // Reset our timer counters...
1852     stopSchedule();
1853    
1854     // OK. Let's build the startup process...
1855     m_pServer = new QProcess(this);
1856    
1857     // Setup stdout/stderr capture...
1858     //if (m_pOptions->bStdoutCapture) {
1859     m_pServer->setCommunication(QProcess::Stdout | QProcess::Stderr | QProcess::DupStderr);
1860     QObject::connect(m_pServer, SIGNAL(readyReadStdout()), this, SLOT(readServerStdout()));
1861     QObject::connect(m_pServer, SIGNAL(readyReadStderr()), this, SLOT(readServerStdout()));
1862     //}
1863     // The unforgiveable signal communication...
1864     QObject::connect(m_pServer, SIGNAL(processExited()), this, SLOT(processServerExit()));
1865    
1866     // Build process arguments...
1867     m_pServer->setArguments(QStringList::split(' ', m_pOptions->sServerCmdLine));
1868    
1869     appendMessages(tr("Server is starting..."));
1870     appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");
1871    
1872     // Go jack, go...
1873     if (!m_pServer->start()) {
1874     appendMessagesError(tr("Could not start server.\n\nSorry."));
1875     processServerExit();
1876     return;
1877     }
1878    
1879     // Show startup results...
1880     appendMessages(tr("Server was started with PID=%1.").arg((long) m_pServer->processIdentifier()));
1881    
1882     // Reset (yet again) the timer counters,
1883     // but this time is deferred as the user opted.
1884     startSchedule(m_pOptions->iStartDelay);
1885     stabilizeForm();
1886     }
1887    
1888    
1889     // Stop linuxsampler server...
1890     void qsamplerMainForm::stopServer (void)
1891     {
1892     // Stop client code.
1893     stopClient();
1894    
1895     // And try to stop server.
1896     if (m_pServer) {
1897     appendMessages(tr("Server is stopping..."));
1898 capela 122 if (m_pServer->isRunning())
1899 capela 109 m_pServer->tryTerminate();
1900     }
1901    
1902 capela 122 // Give it some time to terminate gracefully and stabilize...
1903     QTime t;
1904     t.start();
1905     while (t.elapsed() < QSAMPLER_TIMER_MSECS)
1906     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
1907    
1908 capela 109 // Do final processing anyway.
1909     processServerExit();
1910     }
1911    
1912    
1913     // Stdout handler...
1914     void qsamplerMainForm::readServerStdout (void)
1915     {
1916     if (m_pMessages)
1917     m_pMessages->appendStdoutBuffer(m_pServer->readStdout());
1918     }
1919    
1920    
1921     // Linuxsampler server cleanup.
1922     void qsamplerMainForm::processServerExit (void)
1923     {
1924     // Force client code cleanup.
1925     stopClient();
1926    
1927     // Flush anything that maybe pending...
1928     if (m_pMessages)
1929     m_pMessages->flushStdoutBuffer();
1930    
1931     if (m_pServer) {
1932     // Force final server shutdown...
1933     appendMessages(tr("Server was stopped with exit status %1.").arg(m_pServer->exitStatus()));
1934     if (!m_pServer->normalExit())
1935     m_pServer->kill();
1936     // Destroy it.
1937     delete m_pServer;
1938     m_pServer = NULL;
1939     }
1940    
1941     // Again, make status visible stable.
1942     stabilizeForm();
1943     }
1944    
1945    
1946     //-------------------------------------------------------------------------
1947     // qsamplerMainForm -- Client stuff.
1948    
1949     // The LSCP client callback procedure.
1950 capela 149 lscp_status_t qsampler_client_callback ( lscp_client_t */*pClient*/, lscp_event_t event, const char *pchData, int cchData, void *pvData )
1951 capela 109 {
1952 capela 149 qsamplerMainForm *pMainForm = (qsamplerMainForm *) pvData;
1953     if (pMainForm == NULL)
1954     return LSCP_FAILED;
1955    
1956     // ATTN: DO NOT EVER call any GUI code here,
1957 capela 145 // as this is run under some other thread context.
1958     // A custom event must be posted here...
1959 capela 149 QApplication::postEvent(pMainForm, new qsamplerCustomEvent(event, pchData, cchData));
1960 capela 109
1961     return LSCP_OK;
1962     }
1963    
1964    
1965     // Start our almighty client...
1966     bool qsamplerMainForm::startClient (void)
1967     {
1968     // Have it a setup?
1969     if (m_pOptions == NULL)
1970     return false;
1971    
1972     // Aren't we already started, are we?
1973     if (m_pClient)
1974     return true;
1975    
1976     // Log prepare here.
1977     appendMessages(tr("Client connecting..."));
1978    
1979     // Create the client handle...
1980     m_pClient = ::lscp_client_create(m_pOptions->sServerHost.latin1(), m_pOptions->iServerPort, qsampler_client_callback, this);
1981     if (m_pClient == NULL) {
1982     // Is this the first try?
1983     // maybe we need to start a local server...
1984     if ((m_pServer && m_pServer->isRunning()) || !m_pOptions->bServerStart)
1985     appendMessagesError(tr("Could not connect to server as client.\n\nSorry."));
1986     else
1987     startServer();
1988     // This is always a failure.
1989     stabilizeForm();
1990     return false;
1991     }
1992     // Just set receive timeout value, blindly.
1993     ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);
1994     appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));
1995    
1996     // We may stop scheduling around.
1997     stopSchedule();
1998    
1999     // We'll accept drops from now on...
2000     setAcceptDrops(true);
2001    
2002     // Log success here.
2003     appendMessages(tr("Client connected."));
2004    
2005 capela 428 // Hard-notify device configuration form,
2006     // if visible, that we're ready...
2007     if (m_pDeviceForm && m_pDeviceForm->isVisible())
2008     m_pDeviceForm->setClient(m_pClient);
2009    
2010 capela 109 // Is any session pending to be loaded?
2011     if (!m_pOptions->sSessionFile.isEmpty()) {
2012     // Just load the prabably startup session...
2013     if (loadSessionFile(m_pOptions->sSessionFile)) {
2014     m_pOptions->sSessionFile = QString::null;
2015     return true;
2016     }
2017     }
2018    
2019     // Make a new session
2020     return newSession();
2021     }
2022    
2023    
2024     // Stop client...
2025     void qsamplerMainForm::stopClient (void)
2026     {
2027     if (m_pClient == NULL)
2028     return;
2029    
2030 capela 428 // Hard-notify device configuration form,
2031     // if visible, that we're running out...
2032     if (m_pDeviceForm && m_pDeviceForm->isVisible())
2033     m_pDeviceForm->setClient(NULL);
2034    
2035 capela 109 // Log prepare here.
2036     appendMessages(tr("Client disconnecting..."));
2037    
2038     // Clear timer counters...
2039     stopSchedule();
2040    
2041     // We'll reject drops from now on...
2042     setAcceptDrops(false);
2043    
2044     // Force any channel strips around, but
2045     // but avoid removing the corresponding
2046     // channels from the back-end server.
2047     m_iDirtyCount = 0;
2048     closeSession(false);
2049    
2050     // Close us as a client...
2051     lscp_client_destroy(m_pClient);
2052     m_pClient = NULL;
2053    
2054     // Log final here.
2055     appendMessages(tr("Client disconnected."));
2056    
2057     // Make visible status.
2058     stabilizeForm();
2059     }
2060    
2061    
2062     // end of qsamplerMainForm.ui.h

  ViewVC Help
Powered by ViewVC