/[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 176 - (hide annotations) (download) (as text)
Tue Jul 6 10:54:45 2004 UTC (19 years, 8 months ago) by capela
File MIME type: text/x-c++hdr
File size: 52083 byte(s)
* Channel dialog gets sensible engine and driver defaults
  on create time.

* Implied channel reset on successful instrument load.

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

  ViewVC Help
Powered by ViewVC