/[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 968 - (hide annotations) (download) (as text)
Tue Dec 5 12:37:06 2006 UTC (17 years, 4 months ago) by capela
File MIME type: text/x-c++hdr
File size: 70008 byte(s)
* Fixed some compilation warnings due to suspicious type
  casting and unsused header macros.

* Changed deprecated copyright attribute to license
  and added ldconfig to post-(un)install steps
  to liblscp.spec (RPM).

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

  ViewVC Help
Powered by ViewVC