/[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 456 - (hide annotations) (download) (as text)
Mon Mar 14 14:02:30 2005 UTC (19 years ago) by capela
File MIME type: text/x-c++hdr
File size: 64110 byte(s)
Device configuration is now included and saved on session files (ufix).

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     qsamplerDevice device(m_pClient, qsamplerDevice::Audio, piDeviceIDs[iDevice]);
670     ts << endl;
671     ts << "# " << device.deviceTypeName() << " " << device.driverName()
672     << " " << tr("Device") << " " << iDevice << endl;
673     ts << "CREATE AUDIO_OUTPUT_DEVICE " << device.driverName();
674     qsamplerDeviceParamMap& params = device.params();
675     qsamplerDeviceParamMap::ConstIterator iter;
676     for (iter = params.begin(); iter != params.end(); ++iter)
677     ts << " " << iter.key() << "='" << iter.data().value << "'";
678     ts << endl;
679     audioDeviceMap[device.deviceID()] = iDevice;
680     // Try to keep it snappy :)
681     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
682     }
683     // MIDI device mapping.
684     QMap<int, int> midiDeviceMap;
685     piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Midi);
686     for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {
687     qsamplerDevice device(m_pClient, qsamplerDevice::Midi, piDeviceIDs[iDevice]);
688 capela 456 ts << endl;
689 capela 455 ts << "# " << device.deviceTypeName() << " " << device.driverName()
690     << " " << tr("Device") << " " << iDevice << endl;
691     ts << "CREATE MIDI_INPUT_DEVICE " << device.driverName();
692     qsamplerDeviceParamMap& params = device.params();
693     qsamplerDeviceParamMap::ConstIterator iter;
694     for (iter = params.begin(); iter != params.end(); ++iter)
695     ts << " " << iter.key() << "='" << iter.data().value << "'";
696     ts << endl;
697     midiDeviceMap[device.deviceID()] = iDevice;
698     // Try to keep it snappy :)
699     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
700     }
701     ts << endl;
702     // Sampler channel mapping.
703 capela 109 QWidgetList wlist = m_pWorkspace->windowList();
704     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
705 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
706     if (pChannelStrip) {
707     qsamplerChannel *pChannel = pChannelStrip->channel();
708     if (pChannel) {
709 capela 455 ts << "# " << tr("Channel") << " " << iChannel << endl;
710 capela 264 ts << "ADD CHANNEL" << endl;
711 capela 455 if (audioDeviceMap.isEmpty()) {
712     ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannel
713     << " " << pChannel->audioDriver() << endl;
714     } else {
715     ts << "SET CHANNEL AUDIO_OUTPUT_DEVICE " << iChannel
716     << " " << audioDeviceMap[pChannel->audioDevice()] << endl;
717     }
718     if (midiDeviceMap.isEmpty()) {
719     ts << "SET CHANNEL MIDI_INPUT_TYPE " << iChannel
720     << " " << pChannel->midiDriver() << endl;
721     } else {
722     ts << "SET CHANNEL MIDI_INPUT_DEVICE " << iChannel
723     << " " << midiDeviceMap[pChannel->midiDevice()] << endl;
724     }
725     ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannel
726     << " " << pChannel->midiPort() << endl;
727 capela 409 ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannel << " ";
728 capela 304 if (pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL)
729     ts << "ALL";
730     else
731 capela 264 ts << pChannel->midiChannel();
732     ts << endl;
733 capela 409 ts << "LOAD ENGINE " << pChannel->engineName() << " " << iChannel << endl;
734     ts << "LOAD INSTRUMENT NON_MODAL '" << pChannel->instrumentFile() << "' " << pChannel->instrumentNr() << " " << iChannel << endl;
735     ts << "SET CHANNEL VOLUME " << iChannel << " " << pChannel->volume() << endl;
736 capela 264 ts << endl;
737     }
738     }
739 capela 109 // Try to keep it snappy :)
740     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
741     }
742    
743     // Ok. we've wrote it.
744     file.close();
745    
746     // Have we any errors?
747     if (iErrors > 0)
748     appendMessagesError(tr("Some settings could not be saved\nto \"%1\" session file.\n\nSorry.").arg(sFilename));
749    
750     // Save as default session directory.
751     if (m_pOptions)
752     m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);
753     // We're not dirty anymore.
754     m_iDirtyCount = 0;
755     // Stabilize form...
756     m_sFilename = sFilename;
757     updateRecentFiles(sFilename);
758     appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename)));
759     stabilizeForm();
760     return true;
761     }
762    
763    
764 capela 433 // Session change receiver slot.
765     void qsamplerMainForm::sessionDirty (void)
766     {
767     // Just mark the dirty form.
768     m_iDirtyCount++;
769     // and update the form status...
770     stabilizeForm();
771     }
772    
773    
774 capela 109 //-------------------------------------------------------------------------
775     // qsamplerMainForm -- File Action slots.
776    
777     // Create a new sampler session.
778     void qsamplerMainForm::fileNew (void)
779     {
780     // Of course we'll start clean new.
781     newSession();
782     }
783    
784    
785     // Open an existing sampler session.
786     void qsamplerMainForm::fileOpen (void)
787     {
788     // Open it right away.
789     openSession();
790     }
791    
792    
793     // Open a recent file session.
794     void qsamplerMainForm::fileOpenRecent ( int iIndex )
795     {
796     // Check if we can safely close the current session...
797     if (m_pOptions && closeSession(true)) {
798     QString sFilename = m_pOptions->recentFiles[iIndex];
799     loadSessionFile(sFilename);
800     }
801     }
802    
803    
804     // Save current sampler session.
805     void qsamplerMainForm::fileSave (void)
806     {
807     // Save it right away.
808     saveSession(false);
809     }
810    
811    
812     // Save current sampler session with another name.
813     void qsamplerMainForm::fileSaveAs (void)
814     {
815     // Save it right away, maybe with another name.
816     saveSession(true);
817     }
818    
819    
820 capela 255 // Reset the sampler instance.
821     void qsamplerMainForm::fileReset (void)
822     {
823     if (m_pClient == NULL)
824     return;
825    
826     // Ask user whether he/she want's an internal sampler reset...
827     if (QMessageBox::warning(this, tr("Warning"),
828     tr("Resetting the sampler instance will close\n"
829     "all device and channel configurations.\n\n"
830     "Please note that this operation may cause\n"
831     "temporary MIDI and Audio disruption\n\n"
832     "Do you want to reset the sampler engine now?"),
833     tr("Reset"), tr("Cancel")) > 0)
834     return;
835    
836     // Just do the reset, after closing down current session...
837 capela 261 if (closeSession(true) && ::lscp_reset_sampler(m_pClient) != LSCP_OK) {
838 capela 255 appendMessagesClient("lscp_reset_sampler");
839 capela 261 appendMessagesError(tr("Could not reset sampler instance.\n\nSorry."));
840     return;
841     }
842    
843     // Log this.
844     appendMessages(tr("Sampler reset."));
845 capela 395
846     // Make it a new session...
847     newSession();
848 capela 255 }
849    
850    
851 capela 109 // Restart the client/server instance.
852     void qsamplerMainForm::fileRestart (void)
853     {
854     if (m_pOptions == NULL)
855     return;
856    
857     bool bRestart = true;
858    
859     // Ask user whether he/she want's a complete restart...
860     // (if we're currently up and running)
861     if (bRestart && m_pClient) {
862     bRestart = (QMessageBox::warning(this, tr("Warning"),
863     tr("New settings will be effective after\n"
864     "restarting the client/server connection.\n\n"
865     "Please note that this operation may cause\n"
866     "temporary MIDI and Audio disruption\n\n"
867     "Do you want to restart the connection now?"),
868     tr("Restart"), tr("Cancel")) == 0);
869     }
870    
871     // Are we still for it?
872     if (bRestart && closeSession(true)) {
873     // Stop server, it will force the client too.
874     stopServer();
875     // Reschedule a restart...
876     startSchedule(m_pOptions->iStartDelay);
877     }
878     }
879    
880    
881     // Exit application program.
882     void qsamplerMainForm::fileExit (void)
883     {
884     // Go for close the whole thing.
885     close();
886     }
887    
888    
889     //-------------------------------------------------------------------------
890     // qsamplerMainForm -- Edit Action slots.
891    
892     // Add a new sampler channel.
893     void qsamplerMainForm::editAddChannel (void)
894     {
895     if (m_pClient == NULL)
896     return;
897    
898 capela 303 // Just create the channel instance...
899     qsamplerChannel *pChannel = new qsamplerChannel(this);
900     if (pChannel == NULL)
901     return;
902    
903     // Before we show it up, may be we'll
904     // better ask for some initial values?
905     if (!pChannel->channelSetup(this)) {
906     delete pChannel;
907     return;
908     }
909    
910     // And give it to the strip (will own the channel instance, if successful).
911     if (!createChannelStrip(pChannel)) {
912     delete pChannel;
913     return;
914     }
915    
916     // Make that an overall update.
917     m_iDirtyCount++;
918     stabilizeForm();
919 capela 109 }
920    
921    
922     // Remove current sampler channel.
923     void qsamplerMainForm::editRemoveChannel (void)
924     {
925     if (m_pClient == NULL)
926     return;
927    
928 capela 264 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
929     if (pChannelStrip == NULL)
930     return;
931    
932     qsamplerChannel *pChannel = pChannelStrip->channel();
933 capela 109 if (pChannel == NULL)
934     return;
935    
936     // Prompt user if he/she's sure about this...
937     if (m_pOptions && m_pOptions->bConfirmRemove) {
938     if (QMessageBox::warning(this, tr("Warning"),
939     tr("About to remove channel:\n\n"
940     "%1\n\n"
941     "Are you sure?")
942 capela 264 .arg(pChannelStrip->caption()),
943 capela 109 tr("OK"), tr("Cancel")) > 0)
944     return;
945     }
946    
947     // Remove the existing sampler channel.
948 capela 295 if (!pChannel->removeChannel())
949 capela 109 return;
950    
951     // Just delete the channel strip.
952 capela 265 delete pChannelStrip;
953    
954 capela 109 // Do we auto-arrange?
955     if (m_pOptions && m_pOptions->bAutoArrange)
956     channelsArrange();
957    
958     // We'll be dirty, for sure...
959     m_iDirtyCount++;
960     stabilizeForm();
961     }
962    
963    
964     // Setup current sampler channel.
965     void qsamplerMainForm::editSetupChannel (void)
966     {
967     if (m_pClient == NULL)
968     return;
969    
970 capela 264 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
971     if (pChannelStrip == NULL)
972 capela 109 return;
973    
974     // Just invoque the channel strip procedure.
975 capela 295 pChannelStrip->channelSetup();
976 capela 109 }
977    
978    
979     // Reset current sampler channel.
980     void qsamplerMainForm::editResetChannel (void)
981     {
982     if (m_pClient == NULL)
983     return;
984    
985 capela 264 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
986     if (pChannelStrip == NULL)
987     return;
988    
989 capela 400 // Just invoque the channel strip procedure.
990     pChannelStrip->channelReset();
991 capela 109 }
992    
993    
994 capela 404 // Reset all sampler channels.
995     void qsamplerMainForm::editResetAllChannels (void)
996     {
997     if (m_pClient == NULL)
998     return;
999    
1000     // Invoque the channel strip procedure,
1001     // for all channels out there...
1002     m_pWorkspace->setUpdatesEnabled(false);
1003     QWidgetList wlist = m_pWorkspace->windowList();
1004     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1005     qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1006     if (pChannelStrip)
1007     pChannelStrip->channelReset();
1008     }
1009     m_pWorkspace->setUpdatesEnabled(true);
1010     }
1011    
1012    
1013 capela 109 //-------------------------------------------------------------------------
1014     // qsamplerMainForm -- View Action slots.
1015    
1016     // Show/hide the main program window menubar.
1017     void qsamplerMainForm::viewMenubar ( bool bOn )
1018     {
1019     if (bOn)
1020     MenuBar->show();
1021     else
1022     MenuBar->hide();
1023     }
1024    
1025    
1026     // Show/hide the main program window toolbar.
1027     void qsamplerMainForm::viewToolbar ( bool bOn )
1028     {
1029     if (bOn) {
1030     fileToolbar->show();
1031     editToolbar->show();
1032     channelsToolbar->show();
1033     } else {
1034     fileToolbar->hide();
1035     editToolbar->hide();
1036     channelsToolbar->hide();
1037     }
1038     }
1039    
1040    
1041     // Show/hide the main program window statusbar.
1042     void qsamplerMainForm::viewStatusbar ( bool bOn )
1043     {
1044     if (bOn)
1045     statusBar()->show();
1046     else
1047     statusBar()->hide();
1048     }
1049    
1050    
1051     // Show/hide the messages window logger.
1052     void qsamplerMainForm::viewMessages ( bool bOn )
1053     {
1054     if (bOn)
1055     m_pMessages->show();
1056     else
1057     m_pMessages->hide();
1058     }
1059    
1060    
1061 capela 428 // Show/hide the device configurator form.
1062     void qsamplerMainForm::viewDevices (void)
1063     {
1064     if (m_pOptions == NULL)
1065     return;
1066    
1067     if (m_pDeviceForm) {
1068     m_pOptions->saveWidgetGeometry(m_pDeviceForm);
1069     m_pDeviceForm->setClient(m_pClient);
1070     if (m_pDeviceForm->isVisible()) {
1071     m_pDeviceForm->hide();
1072     } else {
1073     m_pDeviceForm->show();
1074     m_pDeviceForm->raise();
1075     m_pDeviceForm->setActiveWindow();
1076     }
1077     }
1078     }
1079    
1080    
1081 capela 109 // Show options dialog.
1082     void qsamplerMainForm::viewOptions (void)
1083     {
1084     if (m_pOptions == NULL)
1085     return;
1086    
1087     qsamplerOptionsForm *pOptionsForm = new qsamplerOptionsForm(this);
1088     if (pOptionsForm) {
1089     // Check out some initial nullities(tm)...
1090 capela 264 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
1091     if (m_pOptions->sDisplayFont.isEmpty() && pChannelStrip)
1092     m_pOptions->sDisplayFont = pChannelStrip->displayFont().toString();
1093 capela 109 if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages)
1094     m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();
1095     // To track down deferred or immediate changes.
1096     QString sOldServerHost = m_pOptions->sServerHost;
1097     int iOldServerPort = m_pOptions->iServerPort;
1098     int iOldServerTimeout = m_pOptions->iServerTimeout;
1099     bool bOldServerStart = m_pOptions->bServerStart;
1100     QString sOldServerCmdLine = m_pOptions->sServerCmdLine;
1101     QString sOldDisplayFont = m_pOptions->sDisplayFont;
1102 capela 267 bool bOldDisplayEffect = m_pOptions->bDisplayEffect;
1103 capela 119 int iOldMaxVolume = m_pOptions->iMaxVolume;
1104 capela 109 QString sOldMessagesFont = m_pOptions->sMessagesFont;
1105 capela 454 bool bOldKeepOnTop = m_pOptions->bKeepOnTop;
1106 capela 109 bool bOldStdoutCapture = m_pOptions->bStdoutCapture;
1107     int bOldMessagesLimit = m_pOptions->bMessagesLimit;
1108     int iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines;
1109     bool bOldCompletePath = m_pOptions->bCompletePath;
1110 capela 371 bool bOldInstrumentNames = m_pOptions->bInstrumentNames;
1111 capela 109 int iOldMaxRecentFiles = m_pOptions->iMaxRecentFiles;
1112     // Load the current setup settings.
1113     pOptionsForm->setup(m_pOptions);
1114     // Show the setup dialog...
1115     if (pOptionsForm->exec()) {
1116     // Warn if something will be only effective on next run.
1117     if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) ||
1118 capela 454 (!bOldStdoutCapture && m_pOptions->bStdoutCapture) ||
1119     ( bOldKeepOnTop && !m_pOptions->bKeepOnTop) ||
1120     (!bOldKeepOnTop && m_pOptions->bKeepOnTop)) {
1121 capela 109 QMessageBox::information(this, tr("Information"),
1122     tr("Some settings may be only effective\n"
1123     "next time you start this program."), tr("OK"));
1124     updateMessagesCapture();
1125     }
1126     // Check wheather something immediate has changed.
1127     if (( bOldCompletePath && !m_pOptions->bCompletePath) ||
1128     (!bOldCompletePath && m_pOptions->bCompletePath) ||
1129     (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles))
1130     updateRecentFilesMenu();
1131 capela 371 if (( bOldInstrumentNames && !m_pOptions->bInstrumentNames) ||
1132     (!bOldInstrumentNames && m_pOptions->bInstrumentNames))
1133     updateInstrumentNames();
1134 capela 267 if (( bOldDisplayEffect && !m_pOptions->bDisplayEffect) ||
1135     (!bOldDisplayEffect && m_pOptions->bDisplayEffect))
1136     updateDisplayEffect();
1137 capela 109 if (sOldDisplayFont != m_pOptions->sDisplayFont)
1138     updateDisplayFont();
1139 capela 119 if (iOldMaxVolume != m_pOptions->iMaxVolume)
1140     updateMaxVolume();
1141 capela 109 if (sOldMessagesFont != m_pOptions->sMessagesFont)
1142     updateMessagesFont();
1143     if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) ||
1144     (!bOldMessagesLimit && m_pOptions->bMessagesLimit) ||
1145     (iOldMessagesLimitLines != m_pOptions->iMessagesLimitLines))
1146     updateMessagesLimit();
1147     // And now the main thing, whether we'll do client/server recycling?
1148     if ((sOldServerHost != m_pOptions->sServerHost) ||
1149     (iOldServerPort != m_pOptions->iServerPort) ||
1150     (iOldServerTimeout != m_pOptions->iServerTimeout) ||
1151     ( bOldServerStart && !m_pOptions->bServerStart) ||
1152     (!bOldServerStart && m_pOptions->bServerStart) ||
1153     (sOldServerCmdLine != m_pOptions->sServerCmdLine && m_pOptions->bServerStart))
1154     fileRestart();
1155     }
1156     // Done.
1157     delete pOptionsForm;
1158     }
1159    
1160     // This makes it.
1161     stabilizeForm();
1162     }
1163    
1164    
1165     //-------------------------------------------------------------------------
1166     // qsamplerMainForm -- Channels action slots.
1167    
1168     // Arrange channel strips.
1169     void qsamplerMainForm::channelsArrange (void)
1170     {
1171     // Full width vertical tiling
1172     QWidgetList wlist = m_pWorkspace->windowList();
1173     if (wlist.isEmpty())
1174     return;
1175    
1176     m_pWorkspace->setUpdatesEnabled(false);
1177     int y = 0;
1178     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1179 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1180     /* if (pChannelStrip->testWState(WState_Maximized | WState_Minimized)) {
1181 capela 109 // Prevent flicker...
1182 capela 264 pChannelStrip->hide();
1183     pChannelStrip->showNormal();
1184 capela 109 } */
1185 capela 264 pChannelStrip->adjustSize();
1186 capela 109 int iWidth = m_pWorkspace->width();
1187 capela 264 if (iWidth < pChannelStrip->width())
1188     iWidth = pChannelStrip->width();
1189     // int iHeight = pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();
1190     int iHeight = pChannelStrip->parentWidget()->frameGeometry().height();
1191     pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1192 capela 109 y += iHeight;
1193     }
1194     m_pWorkspace->setUpdatesEnabled(true);
1195    
1196     stabilizeForm();
1197     }
1198    
1199    
1200     // Auto-arrange channel strips.
1201     void qsamplerMainForm::channelsAutoArrange ( bool bOn )
1202     {
1203     if (m_pOptions == NULL)
1204     return;
1205    
1206     // Toggle the auto-arrange flag.
1207     m_pOptions->bAutoArrange = bOn;
1208    
1209     // If on, update whole workspace...
1210     if (m_pOptions->bAutoArrange)
1211     channelsArrange();
1212     }
1213    
1214    
1215     //-------------------------------------------------------------------------
1216     // qsamplerMainForm -- Help Action slots.
1217    
1218     // Show information about the Qt toolkit.
1219     void qsamplerMainForm::helpAboutQt (void)
1220     {
1221     QMessageBox::aboutQt(this);
1222     }
1223    
1224    
1225     // Show information about application program.
1226     void qsamplerMainForm::helpAbout (void)
1227     {
1228     // Stuff the about box text...
1229     QString sText = "<p>\n";
1230     sText += "<b>" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "</b><br />\n";
1231     sText += "<br />\n";
1232     sText += tr("Version") + ": <b>" QSAMPLER_VERSION "</b><br />\n";
1233     sText += "<small>" + tr("Build") + ": " __DATE__ " " __TIME__ "</small><br />\n";
1234     #ifdef CONFIG_DEBUG
1235     sText += "<small><font color=\"red\">";
1236     sText += tr("Debugging option enabled.");
1237     sText += "</font></small><br />";
1238     #endif
1239 capela 176 #ifndef CONFIG_LIBGIG
1240     sText += "<small><font color=\"red\">";
1241     sText += tr("GIG (libgig) file support disabled.");
1242     sText += "</font></small><br />";
1243     #endif
1244 capela 382 #ifndef CONFIG_INSTRUMENT_NAME
1245     sText += "<small><font color=\"red\">";
1246     sText += tr("LSCP (liblscp) instrument_name support disabled.");
1247     sText += "</font></small><br />";
1248     #endif
1249 capela 109 sText += "<br />\n";
1250     sText += tr("Using") + ": ";
1251     sText += ::lscp_client_package();
1252     sText += " ";
1253     sText += ::lscp_client_version();
1254     sText += "<br />\n";
1255     sText += "<br />\n";
1256     sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";
1257     sText += "<br />\n";
1258     sText += "<small>";
1259     sText += QSAMPLER_COPYRIGHT "<br />\n";
1260     sText += "<br />\n";
1261     sText += tr("This program is free software; you can redistribute it and/or modify it") + "<br />\n";
1262     sText += tr("under the terms of the GNU General Public License version 2 or later.");
1263     sText += "</small>";
1264     sText += "</p>\n";
1265    
1266     QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText);
1267     }
1268    
1269    
1270     //-------------------------------------------------------------------------
1271     // qsamplerMainForm -- Main window stabilization.
1272    
1273     void qsamplerMainForm::stabilizeForm (void)
1274     {
1275     // Update the main application caption...
1276 capela 418 QString sSessionName = sessionName(m_sFilename);
1277 capela 109 if (m_iDirtyCount > 0)
1278 capela 418 sSessionName += '*';
1279     setCaption(tr(QSAMPLER_TITLE " - [%1]").arg(sSessionName));
1280 capela 109
1281     // Update the main menu state...
1282 capela 264 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
1283 capela 109 bool bHasClient = (m_pOptions != NULL && m_pClient != NULL);
1284 capela 264 bool bHasChannel = (bHasClient && pChannelStrip != NULL);
1285 capela 109 fileNewAction->setEnabled(bHasClient);
1286     fileOpenAction->setEnabled(bHasClient);
1287     fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);
1288     fileSaveAsAction->setEnabled(bHasClient);
1289 capela 255 fileResetAction->setEnabled(bHasClient);
1290 capela 109 fileRestartAction->setEnabled(bHasClient || m_pServer == NULL);
1291     editAddChannelAction->setEnabled(bHasClient);
1292     editRemoveChannelAction->setEnabled(bHasChannel);
1293     editSetupChannelAction->setEnabled(bHasChannel);
1294     editResetChannelAction->setEnabled(bHasChannel);
1295 capela 404 editResetAllChannelsAction->setEnabled(bHasChannel);
1296 capela 428 viewMessagesAction->setOn(m_pMessages && m_pMessages->isVisible());
1297     viewDevicesAction->setOn(m_pDeviceForm && m_pDeviceForm->isVisible());
1298     viewDevicesAction->setEnabled(bHasClient);
1299 capela 109 channelsArrangeAction->setEnabled(bHasChannel);
1300    
1301     // Client/Server status...
1302     if (bHasClient) {
1303 capela 428 m_statusItem[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));
1304     m_statusItem[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost + ":" + QString::number(m_pOptions->iServerPort));
1305 capela 109 } else {
1306 capela 428 m_statusItem[QSAMPLER_STATUS_CLIENT]->clear();
1307     m_statusItem[QSAMPLER_STATUS_SERVER]->clear();
1308 capela 109 }
1309     // Channel status...
1310     if (bHasChannel)
1311 capela 428 m_statusItem[QSAMPLER_STATUS_CHANNEL]->setText(pChannelStrip->caption());
1312 capela 109 else
1313 capela 428 m_statusItem[QSAMPLER_STATUS_CHANNEL]->clear();
1314 capela 109 // Session status...
1315     if (m_iDirtyCount > 0)
1316 capela 428 m_statusItem[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));
1317 capela 109 else
1318 capela 428 m_statusItem[QSAMPLER_STATUS_SESSION]->clear();
1319 capela 109
1320     // Recent files menu.
1321     m_pRecentFilesMenu->setEnabled(bHasClient && m_pOptions->recentFiles.count() > 0);
1322    
1323     // Always make the latest message visible.
1324     if (m_pMessages)
1325     m_pMessages->scrollToBottom();
1326     }
1327    
1328    
1329     // Channel change receiver slot.
1330 capela 400 void qsamplerMainForm::channelStripChanged( qsamplerChannelStrip *pChannelStrip )
1331 capela 109 {
1332 capela 400 // Add this strip to the changed list...
1333     if (m_changedStrips.containsRef(pChannelStrip) == 0)
1334     m_changedStrips.append(pChannelStrip);
1335    
1336 capela 109 // Just mark the dirty form.
1337     m_iDirtyCount++;
1338     // and update the form status...
1339     stabilizeForm();
1340     }
1341    
1342    
1343 capela 395 // Grab and restore current sampler channels session.
1344     void qsamplerMainForm::updateSession (void)
1345     {
1346     // Retrieve the current channel list.
1347     int *piChannelIDs = ::lscp_list_channels(m_pClient);
1348     if (piChannelIDs == NULL) {
1349     if (::lscp_client_get_errno(m_pClient)) {
1350     appendMessagesClient("lscp_list_channels");
1351     appendMessagesError(tr("Could not get current list of channels.\n\nSorry."));
1352     }
1353     return;
1354     }
1355    
1356     // Try to (re)create each channel.
1357     m_pWorkspace->setUpdatesEnabled(false);
1358     for (int iChannel = 0; piChannelIDs[iChannel] >= 0; iChannel++) {
1359     // Check if theres already a channel strip for this one...
1360     if (!channelStrip(piChannelIDs[iChannel]))
1361     createChannelStrip(new qsamplerChannel(this, piChannelIDs[iChannel]));
1362     // Make it visibly responsive...
1363     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
1364     }
1365     m_pWorkspace->setUpdatesEnabled(true);
1366     }
1367    
1368    
1369 capela 109 // Update the recent files list and menu.
1370     void qsamplerMainForm::updateRecentFiles ( const QString& sFilename )
1371     {
1372     if (m_pOptions == NULL)
1373     return;
1374    
1375     // Remove from list if already there (avoid duplicates)
1376     QStringList::Iterator iter = m_pOptions->recentFiles.find(sFilename);
1377     if (iter != m_pOptions->recentFiles.end())
1378     m_pOptions->recentFiles.remove(iter);
1379     // Put it to front...
1380     m_pOptions->recentFiles.push_front(sFilename);
1381    
1382     // May update the menu.
1383     updateRecentFilesMenu();
1384     }
1385    
1386    
1387     // Update the recent files list and menu.
1388     void qsamplerMainForm::updateRecentFilesMenu (void)
1389     {
1390     if (m_pOptions == NULL)
1391     return;
1392    
1393     // Time to keep the list under limits.
1394     int iRecentFiles = m_pOptions->recentFiles.count();
1395     while (iRecentFiles > m_pOptions->iMaxRecentFiles) {
1396     m_pOptions->recentFiles.pop_back();
1397     iRecentFiles--;
1398     }
1399    
1400     // rebuild the recent files menu...
1401     m_pRecentFilesMenu->clear();
1402     for (int i = 0; i < iRecentFiles; i++) {
1403     const QString& sFilename = m_pOptions->recentFiles[i];
1404     if (QFileInfo(sFilename).exists()) {
1405     m_pRecentFilesMenu->insertItem(QString("&%1 %2")
1406     .arg(i + 1).arg(sessionName(sFilename)),
1407     this, SLOT(fileOpenRecent(int)), 0, i);
1408     }
1409     }
1410     }
1411    
1412    
1413 capela 371 // Force update of the channels instrument names mode.
1414     void qsamplerMainForm::updateInstrumentNames (void)
1415     {
1416     // Full channel list update...
1417     QWidgetList wlist = m_pWorkspace->windowList();
1418     if (wlist.isEmpty())
1419     return;
1420    
1421     m_pWorkspace->setUpdatesEnabled(false);
1422     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1423     qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1424     if (pChannelStrip)
1425     pChannelStrip->updateInstrumentName(true);
1426     }
1427     m_pWorkspace->setUpdatesEnabled(true);
1428     }
1429    
1430    
1431 capela 109 // Force update of the channels display font.
1432     void qsamplerMainForm::updateDisplayFont (void)
1433     {
1434     if (m_pOptions == NULL)
1435     return;
1436    
1437     // Check if display font is legal.
1438     if (m_pOptions->sDisplayFont.isEmpty())
1439     return;
1440     // Realize it.
1441     QFont font;
1442     if (!font.fromString(m_pOptions->sDisplayFont))
1443     return;
1444    
1445     // Full channel list update...
1446     QWidgetList wlist = m_pWorkspace->windowList();
1447     if (wlist.isEmpty())
1448     return;
1449    
1450     m_pWorkspace->setUpdatesEnabled(false);
1451     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1452 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1453     if (pChannelStrip)
1454     pChannelStrip->setDisplayFont(font);
1455 capela 109 }
1456     m_pWorkspace->setUpdatesEnabled(true);
1457     }
1458    
1459    
1460 capela 267 // Update channel strips background effect.
1461     void qsamplerMainForm::updateDisplayEffect (void)
1462     {
1463     QPixmap pm;
1464     if (m_pOptions->bDisplayEffect)
1465     pm = QPixmap::fromMimeSource("displaybg1.png");
1466    
1467     // Full channel list update...
1468     QWidgetList wlist = m_pWorkspace->windowList();
1469     if (wlist.isEmpty())
1470     return;
1471    
1472     m_pWorkspace->setUpdatesEnabled(false);
1473     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1474     qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1475     if (pChannelStrip)
1476     pChannelStrip->setDisplayBackground(pm);
1477     }
1478     m_pWorkspace->setUpdatesEnabled(true);
1479     }
1480    
1481    
1482 capela 119 // Force update of the channels maximum volume setting.
1483     void qsamplerMainForm::updateMaxVolume (void)
1484     {
1485     if (m_pOptions == NULL)
1486     return;
1487    
1488     // Full channel list update...
1489     QWidgetList wlist = m_pWorkspace->windowList();
1490     if (wlist.isEmpty())
1491     return;
1492    
1493     m_pWorkspace->setUpdatesEnabled(false);
1494     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1495 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1496     if (pChannelStrip)
1497     pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
1498 capela 119 }
1499     m_pWorkspace->setUpdatesEnabled(true);
1500     }
1501    
1502    
1503 capela 109 //-------------------------------------------------------------------------
1504     // qsamplerMainForm -- Messages window form handlers.
1505    
1506     // Messages output methods.
1507     void qsamplerMainForm::appendMessages( const QString& s )
1508     {
1509     if (m_pMessages)
1510     m_pMessages->appendMessages(s);
1511    
1512     statusBar()->message(s, 3000);
1513     }
1514    
1515     void qsamplerMainForm::appendMessagesColor( const QString& s, const QString& c )
1516     {
1517     if (m_pMessages)
1518     m_pMessages->appendMessagesColor(s, c);
1519    
1520     statusBar()->message(s, 3000);
1521     }
1522    
1523     void qsamplerMainForm::appendMessagesText( const QString& s )
1524     {
1525     if (m_pMessages)
1526     m_pMessages->appendMessagesText(s);
1527     }
1528    
1529     void qsamplerMainForm::appendMessagesError( const QString& s )
1530     {
1531     if (m_pMessages)
1532     m_pMessages->show();
1533    
1534     appendMessagesColor(s.simplifyWhiteSpace(), "#ff0000");
1535    
1536     QMessageBox::critical(this, tr("Error"), s, tr("Cancel"));
1537     }
1538    
1539    
1540     // This is a special message format, just for client results.
1541     void qsamplerMainForm::appendMessagesClient( const QString& s )
1542     {
1543     if (m_pClient == NULL)
1544     return;
1545    
1546     appendMessagesColor(s + QString(": %1 (errno=%2)")
1547     .arg(::lscp_client_get_result(m_pClient))
1548     .arg(::lscp_client_get_errno(m_pClient)), "#996666");
1549     }
1550    
1551    
1552     // Force update of the messages font.
1553     void qsamplerMainForm::updateMessagesFont (void)
1554     {
1555     if (m_pOptions == NULL)
1556     return;
1557    
1558     if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {
1559     QFont font;
1560     if (font.fromString(m_pOptions->sMessagesFont))
1561     m_pMessages->setMessagesFont(font);
1562     }
1563     }
1564    
1565    
1566     // Update messages window line limit.
1567     void qsamplerMainForm::updateMessagesLimit (void)
1568     {
1569     if (m_pOptions == NULL)
1570     return;
1571    
1572     if (m_pMessages) {
1573     if (m_pOptions->bMessagesLimit)
1574     m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);
1575     else
1576     m_pMessages->setMessagesLimit(0);
1577     }
1578     }
1579    
1580    
1581     // Enablement of the messages capture feature.
1582     void qsamplerMainForm::updateMessagesCapture (void)
1583     {
1584     if (m_pOptions == NULL)
1585     return;
1586    
1587     if (m_pMessages)
1588     m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);
1589     }
1590    
1591    
1592     //-------------------------------------------------------------------------
1593     // qsamplerMainForm -- MDI channel strip management.
1594    
1595     // The channel strip creation executive.
1596 capela 303 qsamplerChannelStrip *qsamplerMainForm::createChannelStrip ( qsamplerChannel *pChannel )
1597 capela 109 {
1598 capela 303 if (m_pClient == NULL || pChannel == NULL)
1599 capela 295 return NULL;
1600 capela 109
1601     // Prepare for auto-arrange?
1602 capela 264 qsamplerChannelStrip *pChannelStrip = NULL;
1603 capela 109 int y = 0;
1604     if (m_pOptions && m_pOptions->bAutoArrange) {
1605     QWidgetList wlist = m_pWorkspace->windowList();
1606     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1607 capela 264 pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1608 capela 395 if (pChannelStrip) {
1609     // y += pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();
1610     y += pChannelStrip->parentWidget()->frameGeometry().height();
1611     }
1612 capela 109 }
1613     }
1614    
1615     // Add a new channel itema...
1616     WFlags wflags = Qt::WStyle_Customize | Qt::WStyle_Tool | Qt::WStyle_Title | Qt::WStyle_NoBorder;
1617 capela 264 pChannelStrip = new qsamplerChannelStrip(m_pWorkspace, 0, wflags);
1618 capela 303 if (pChannelStrip == NULL)
1619     return NULL;
1620    
1621     // Actual channel strip setup...
1622     pChannelStrip->setup(pChannel);
1623 capela 295 QObject::connect(pChannelStrip, SIGNAL(channelChanged(qsamplerChannelStrip *)), this, SLOT(channelStripChanged(qsamplerChannelStrip *)));
1624 capela 267 // Set some initial aesthetic options...
1625     if (m_pOptions) {
1626     // Background display effect...
1627     pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
1628     // We'll need a display font.
1629     QFont font;
1630     if (font.fromString(m_pOptions->sDisplayFont))
1631     pChannelStrip->setDisplayFont(font);
1632     // Maximum allowed volume setting.
1633     pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
1634     }
1635 capela 295
1636 capela 109 // Now we show up us to the world.
1637 capela 264 pChannelStrip->show();
1638 capela 109 // Only then, we'll auto-arrange...
1639     if (m_pOptions && m_pOptions->bAutoArrange) {
1640     int iWidth = m_pWorkspace->width();
1641     // int iHeight = pChannel->height() + pChannel->parentWidget()->baseSize().height();
1642 capela 264 int iHeight = pChannelStrip->parentWidget()->frameGeometry().height();
1643     pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1644 capela 109 }
1645 capela 400
1646     // This is pretty new, so we'll watch for it closely.
1647     channelStripChanged(pChannelStrip);
1648    
1649 capela 295 // Return our successful reference...
1650     return pChannelStrip;
1651 capela 109 }
1652    
1653    
1654     // Retrieve the active channel strip.
1655 capela 264 qsamplerChannelStrip *qsamplerMainForm::activeChannelStrip (void)
1656 capela 109 {
1657     return (qsamplerChannelStrip *) m_pWorkspace->activeWindow();
1658     }
1659    
1660    
1661     // Retrieve a channel strip by index.
1662 capela 264 qsamplerChannelStrip *qsamplerMainForm::channelStripAt ( int iChannel )
1663 capela 109 {
1664     QWidgetList wlist = m_pWorkspace->windowList();
1665     if (wlist.isEmpty())
1666 capela 395 return NULL;
1667 capela 109
1668     return (qsamplerChannelStrip *) wlist.at(iChannel);
1669     }
1670    
1671    
1672 capela 395 // Retrieve a channel strip by sampler channel id.
1673     qsamplerChannelStrip *qsamplerMainForm::channelStrip ( int iChannelID )
1674     {
1675     QWidgetList wlist = m_pWorkspace->windowList();
1676     if (wlist.isEmpty())
1677     return NULL;
1678    
1679     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1680     qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1681     if (pChannelStrip) {
1682     qsamplerChannel *pChannel = pChannelStrip->channel();
1683     if (pChannel && pChannel->channelID() == iChannelID)
1684     return pChannelStrip;
1685     }
1686     }
1687    
1688     // Not found.
1689     return NULL;
1690     }
1691    
1692    
1693 capela 109 // Construct the windows menu.
1694     void qsamplerMainForm::channelsMenuAboutToShow (void)
1695     {
1696     channelsMenu->clear();
1697     channelsArrangeAction->addTo(channelsMenu);
1698     channelsAutoArrangeAction->addTo(channelsMenu);
1699    
1700     QWidgetList wlist = m_pWorkspace->windowList();
1701     if (!wlist.isEmpty()) {
1702     channelsMenu->insertSeparator();
1703     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1704 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1705     if (pChannelStrip) {
1706     int iItemID = channelsMenu->insertItem(pChannelStrip->caption(), this, SLOT(channelsMenuActivated(int)));
1707     channelsMenu->setItemParameter(iItemID, iChannel);
1708     channelsMenu->setItemChecked(iItemID, activeChannelStrip() == pChannelStrip);
1709     }
1710 capela 109 }
1711     }
1712     }
1713    
1714    
1715     // Windows menu activation slot
1716     void qsamplerMainForm::channelsMenuActivated ( int iChannel )
1717     {
1718 capela 264 qsamplerChannelStrip *pChannelStrip = channelStripAt(iChannel);
1719     if (pChannelStrip)
1720     pChannelStrip->showNormal();
1721     pChannelStrip->setFocus();
1722 capela 109 }
1723    
1724    
1725     //-------------------------------------------------------------------------
1726     // qsamplerMainForm -- Timer stuff.
1727    
1728     // Set the pseudo-timer delay schedule.
1729     void qsamplerMainForm::startSchedule ( int iStartDelay )
1730     {
1731     m_iStartDelay = 1 + (iStartDelay * 1000);
1732     m_iTimerDelay = 0;
1733     }
1734    
1735     // Suspend the pseudo-timer delay schedule.
1736     void qsamplerMainForm::stopSchedule (void)
1737     {
1738     m_iStartDelay = 0;
1739     m_iTimerDelay = 0;
1740     }
1741    
1742     // Timer slot funtion.
1743     void qsamplerMainForm::timerSlot (void)
1744     {
1745     if (m_pOptions == NULL)
1746     return;
1747    
1748     // Is it the first shot on server start after a few delay?
1749     if (m_iTimerDelay < m_iStartDelay) {
1750     m_iTimerDelay += QSAMPLER_TIMER_MSECS;
1751     if (m_iTimerDelay >= m_iStartDelay) {
1752     // If we cannot start it now, maybe a lil'mo'later ;)
1753     if (!startClient()) {
1754     m_iStartDelay += m_iTimerDelay;
1755     m_iTimerDelay = 0;
1756     }
1757     }
1758     }
1759    
1760     // Refresh each channel usage, on each period...
1761 capela 400 if (m_pClient && (m_changedStrips.count() > 0 || m_pOptions->bAutoRefresh)) {
1762 capela 109 m_iTimerSlot += QSAMPLER_TIMER_MSECS;
1763 capela 296 if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime && m_pWorkspace->isUpdatesEnabled()) {
1764 capela 109 m_iTimerSlot = 0;
1765 capela 400 // Update the channel information for each pending strip...
1766     for (qsamplerChannelStrip *pChannelStrip = m_changedStrips.first();
1767     pChannelStrip;
1768     pChannelStrip = m_changedStrips.next()) {
1769     // If successfull, remove from pending list...
1770     if (pChannelStrip->updateChannelInfo())
1771     m_changedStrips.remove(pChannelStrip);
1772     }
1773     // Update the channel stream usage for each strip...
1774 capela 109 QWidgetList wlist = m_pWorkspace->windowList();
1775     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1776 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1777 capela 400 if (pChannelStrip && pChannelStrip->isVisible())
1778     pChannelStrip->updateChannelUsage();
1779 capela 109 }
1780     }
1781     }
1782    
1783     // Register the next timer slot.
1784     QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
1785     }
1786    
1787    
1788     //-------------------------------------------------------------------------
1789     // qsamplerMainForm -- Server stuff.
1790    
1791     // Start linuxsampler server...
1792     void qsamplerMainForm::startServer (void)
1793     {
1794     if (m_pOptions == NULL)
1795     return;
1796    
1797     // Aren't already a client, are we?
1798     if (!m_pOptions->bServerStart || m_pClient)
1799     return;
1800    
1801     // Is the server process instance still here?
1802     if (m_pServer) {
1803     switch (QMessageBox::warning(this, tr("Warning"),
1804     tr("Could not start the LinuxSampler server.\n\n"
1805     "Maybe it ss already started."),
1806     tr("Stop"), tr("Kill"), tr("Cancel"))) {
1807     case 0:
1808     m_pServer->tryTerminate();
1809     break;
1810     case 1:
1811     m_pServer->kill();
1812     break;
1813     }
1814     return;
1815     }
1816    
1817     // Reset our timer counters...
1818     stopSchedule();
1819    
1820     // OK. Let's build the startup process...
1821     m_pServer = new QProcess(this);
1822    
1823     // Setup stdout/stderr capture...
1824     //if (m_pOptions->bStdoutCapture) {
1825     m_pServer->setCommunication(QProcess::Stdout | QProcess::Stderr | QProcess::DupStderr);
1826     QObject::connect(m_pServer, SIGNAL(readyReadStdout()), this, SLOT(readServerStdout()));
1827     QObject::connect(m_pServer, SIGNAL(readyReadStderr()), this, SLOT(readServerStdout()));
1828     //}
1829     // The unforgiveable signal communication...
1830     QObject::connect(m_pServer, SIGNAL(processExited()), this, SLOT(processServerExit()));
1831    
1832     // Build process arguments...
1833     m_pServer->setArguments(QStringList::split(' ', m_pOptions->sServerCmdLine));
1834    
1835     appendMessages(tr("Server is starting..."));
1836     appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");
1837    
1838     // Go jack, go...
1839     if (!m_pServer->start()) {
1840     appendMessagesError(tr("Could not start server.\n\nSorry."));
1841     processServerExit();
1842     return;
1843     }
1844    
1845     // Show startup results...
1846     appendMessages(tr("Server was started with PID=%1.").arg((long) m_pServer->processIdentifier()));
1847    
1848     // Reset (yet again) the timer counters,
1849     // but this time is deferred as the user opted.
1850     startSchedule(m_pOptions->iStartDelay);
1851     stabilizeForm();
1852     }
1853    
1854    
1855     // Stop linuxsampler server...
1856     void qsamplerMainForm::stopServer (void)
1857     {
1858     // Stop client code.
1859     stopClient();
1860    
1861     // And try to stop server.
1862     if (m_pServer) {
1863     appendMessages(tr("Server is stopping..."));
1864 capela 122 if (m_pServer->isRunning())
1865 capela 109 m_pServer->tryTerminate();
1866     }
1867    
1868 capela 122 // Give it some time to terminate gracefully and stabilize...
1869     QTime t;
1870     t.start();
1871     while (t.elapsed() < QSAMPLER_TIMER_MSECS)
1872     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
1873    
1874 capela 109 // Do final processing anyway.
1875     processServerExit();
1876     }
1877    
1878    
1879     // Stdout handler...
1880     void qsamplerMainForm::readServerStdout (void)
1881     {
1882     if (m_pMessages)
1883     m_pMessages->appendStdoutBuffer(m_pServer->readStdout());
1884     }
1885    
1886    
1887     // Linuxsampler server cleanup.
1888     void qsamplerMainForm::processServerExit (void)
1889     {
1890     // Force client code cleanup.
1891     stopClient();
1892    
1893     // Flush anything that maybe pending...
1894     if (m_pMessages)
1895     m_pMessages->flushStdoutBuffer();
1896    
1897     if (m_pServer) {
1898     // Force final server shutdown...
1899     appendMessages(tr("Server was stopped with exit status %1.").arg(m_pServer->exitStatus()));
1900     if (!m_pServer->normalExit())
1901     m_pServer->kill();
1902     // Destroy it.
1903     delete m_pServer;
1904     m_pServer = NULL;
1905     }
1906    
1907     // Again, make status visible stable.
1908     stabilizeForm();
1909     }
1910    
1911    
1912     //-------------------------------------------------------------------------
1913     // qsamplerMainForm -- Client stuff.
1914    
1915     // The LSCP client callback procedure.
1916 capela 149 lscp_status_t qsampler_client_callback ( lscp_client_t */*pClient*/, lscp_event_t event, const char *pchData, int cchData, void *pvData )
1917 capela 109 {
1918 capela 149 qsamplerMainForm *pMainForm = (qsamplerMainForm *) pvData;
1919     if (pMainForm == NULL)
1920     return LSCP_FAILED;
1921    
1922     // ATTN: DO NOT EVER call any GUI code here,
1923 capela 145 // as this is run under some other thread context.
1924     // A custom event must be posted here...
1925 capela 149 QApplication::postEvent(pMainForm, new qsamplerCustomEvent(event, pchData, cchData));
1926 capela 109
1927     return LSCP_OK;
1928     }
1929    
1930    
1931     // Start our almighty client...
1932     bool qsamplerMainForm::startClient (void)
1933     {
1934     // Have it a setup?
1935     if (m_pOptions == NULL)
1936     return false;
1937    
1938     // Aren't we already started, are we?
1939     if (m_pClient)
1940     return true;
1941    
1942     // Log prepare here.
1943     appendMessages(tr("Client connecting..."));
1944    
1945     // Create the client handle...
1946     m_pClient = ::lscp_client_create(m_pOptions->sServerHost.latin1(), m_pOptions->iServerPort, qsampler_client_callback, this);
1947     if (m_pClient == NULL) {
1948     // Is this the first try?
1949     // maybe we need to start a local server...
1950     if ((m_pServer && m_pServer->isRunning()) || !m_pOptions->bServerStart)
1951     appendMessagesError(tr("Could not connect to server as client.\n\nSorry."));
1952     else
1953     startServer();
1954     // This is always a failure.
1955     stabilizeForm();
1956     return false;
1957     }
1958     // Just set receive timeout value, blindly.
1959     ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);
1960     appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));
1961    
1962     // We may stop scheduling around.
1963     stopSchedule();
1964    
1965     // We'll accept drops from now on...
1966     setAcceptDrops(true);
1967    
1968     // Log success here.
1969     appendMessages(tr("Client connected."));
1970    
1971 capela 428 // Hard-notify device configuration form,
1972     // if visible, that we're ready...
1973     if (m_pDeviceForm && m_pDeviceForm->isVisible())
1974     m_pDeviceForm->setClient(m_pClient);
1975    
1976 capela 109 // Is any session pending to be loaded?
1977     if (!m_pOptions->sSessionFile.isEmpty()) {
1978     // Just load the prabably startup session...
1979     if (loadSessionFile(m_pOptions->sSessionFile)) {
1980     m_pOptions->sSessionFile = QString::null;
1981     return true;
1982     }
1983     }
1984    
1985     // Make a new session
1986     return newSession();
1987     }
1988    
1989    
1990     // Stop client...
1991     void qsamplerMainForm::stopClient (void)
1992     {
1993     if (m_pClient == NULL)
1994     return;
1995    
1996 capela 428 // Hard-notify device configuration form,
1997     // if visible, that we're running out...
1998     if (m_pDeviceForm && m_pDeviceForm->isVisible())
1999     m_pDeviceForm->setClient(NULL);
2000    
2001 capela 109 // Log prepare here.
2002     appendMessages(tr("Client disconnecting..."));
2003    
2004     // Clear timer counters...
2005     stopSchedule();
2006    
2007     // We'll reject drops from now on...
2008     setAcceptDrops(false);
2009    
2010     // Force any channel strips around, but
2011     // but avoid removing the corresponding
2012     // channels from the back-end server.
2013     m_iDirtyCount = 0;
2014     closeSession(false);
2015    
2016     // Close us as a client...
2017     lscp_client_destroy(m_pClient);
2018     m_pClient = NULL;
2019    
2020     // Log final here.
2021     appendMessages(tr("Client disconnected."));
2022    
2023     // Make visible status.
2024     stabilizeForm();
2025     }
2026    
2027    
2028     // end of qsamplerMainForm.ui.h

  ViewVC Help
Powered by ViewVC