/[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 162 - (hide annotations) (download) (as text)
Tue Jun 29 22:17:59 2004 UTC (19 years, 9 months ago) by capela
File MIME type: text/x-c++hdr
File size: 51908 byte(s)
Effective MIDI input port setting on channel dialog. (fix)

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     pChannel->channelSetup();
804     }
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     sText += "<br />\n";
1028     sText += tr("Using") + ": ";
1029     sText += ::lscp_client_package();
1030     sText += " ";
1031     sText += ::lscp_client_version();
1032     sText += "<br />\n";
1033     sText += "<br />\n";
1034     sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";
1035     sText += "<br />\n";
1036     sText += "<small>";
1037     sText += QSAMPLER_COPYRIGHT "<br />\n";
1038     sText += "<br />\n";
1039     sText += tr("This program is free software; you can redistribute it and/or modify it") + "<br />\n";
1040     sText += tr("under the terms of the GNU General Public License version 2 or later.");
1041     sText += "</small>";
1042     sText += "</p>\n";
1043    
1044     QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText);
1045     }
1046    
1047    
1048     //-------------------------------------------------------------------------
1049     // qsamplerMainForm -- Main window stabilization.
1050    
1051     void qsamplerMainForm::stabilizeForm (void)
1052     {
1053     // Update the main application caption...
1054     QString sSessioName = sessionName(m_sFilename);
1055     if (m_iDirtyCount > 0)
1056     sSessioName += '*';
1057     setCaption(tr(QSAMPLER_TITLE " - [%1]").arg(sSessioName));
1058    
1059     // Update the main menu state...
1060     qsamplerChannelStrip *pChannel = activeChannel();
1061     bool bHasClient = (m_pOptions != NULL && m_pClient != NULL);
1062     bool bHasChannel = (bHasClient && pChannel != NULL);
1063     fileNewAction->setEnabled(bHasClient);
1064     fileOpenAction->setEnabled(bHasClient);
1065     fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);
1066     fileSaveAsAction->setEnabled(bHasClient);
1067     fileRestartAction->setEnabled(bHasClient || m_pServer == NULL);
1068     editAddChannelAction->setEnabled(bHasClient);
1069     editRemoveChannelAction->setEnabled(bHasChannel);
1070     editSetupChannelAction->setEnabled(bHasChannel);
1071     editResetChannelAction->setEnabled(bHasChannel);
1072     channelsArrangeAction->setEnabled(bHasChannel);
1073     viewMessagesAction->setOn(m_pMessages && m_pMessages->isVisible());
1074    
1075     // Client/Server status...
1076     if (bHasClient) {
1077     m_status[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));
1078     m_status[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost + ":" + QString::number(m_pOptions->iServerPort));
1079     } else {
1080     m_status[QSAMPLER_STATUS_CLIENT]->clear();
1081     m_status[QSAMPLER_STATUS_SERVER]->clear();
1082     }
1083     // Channel status...
1084     if (bHasChannel)
1085     m_status[QSAMPLER_STATUS_CHANNEL]->setText(pChannel->caption());
1086     else
1087     m_status[QSAMPLER_STATUS_CHANNEL]->clear();
1088     // Session status...
1089     if (m_iDirtyCount > 0)
1090     m_status[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));
1091     else
1092     m_status[QSAMPLER_STATUS_SESSION]->clear();
1093    
1094     // Recent files menu.
1095     m_pRecentFilesMenu->setEnabled(bHasClient && m_pOptions->recentFiles.count() > 0);
1096    
1097     // Always make the latest message visible.
1098     if (m_pMessages)
1099     m_pMessages->scrollToBottom();
1100     }
1101    
1102    
1103     // Channel change receiver slot.
1104     void qsamplerMainForm::channelChanged( qsamplerChannelStrip * )
1105     {
1106     // Just mark the dirty form.
1107     m_iDirtyCount++;
1108     // and update the form status...
1109     stabilizeForm();
1110     }
1111    
1112    
1113     // Update the recent files list and menu.
1114     void qsamplerMainForm::updateRecentFiles ( const QString& sFilename )
1115     {
1116     if (m_pOptions == NULL)
1117     return;
1118    
1119     // Remove from list if already there (avoid duplicates)
1120     QStringList::Iterator iter = m_pOptions->recentFiles.find(sFilename);
1121     if (iter != m_pOptions->recentFiles.end())
1122     m_pOptions->recentFiles.remove(iter);
1123     // Put it to front...
1124     m_pOptions->recentFiles.push_front(sFilename);
1125    
1126     // May update the menu.
1127     updateRecentFilesMenu();
1128     }
1129    
1130    
1131     // Update the recent files list and menu.
1132     void qsamplerMainForm::updateRecentFilesMenu (void)
1133     {
1134     if (m_pOptions == NULL)
1135     return;
1136    
1137     // Time to keep the list under limits.
1138     int iRecentFiles = m_pOptions->recentFiles.count();
1139     while (iRecentFiles > m_pOptions->iMaxRecentFiles) {
1140     m_pOptions->recentFiles.pop_back();
1141     iRecentFiles--;
1142     }
1143    
1144     // rebuild the recent files menu...
1145     m_pRecentFilesMenu->clear();
1146     for (int i = 0; i < iRecentFiles; i++) {
1147     const QString& sFilename = m_pOptions->recentFiles[i];
1148     if (QFileInfo(sFilename).exists()) {
1149     m_pRecentFilesMenu->insertItem(QString("&%1 %2")
1150     .arg(i + 1).arg(sessionName(sFilename)),
1151     this, SLOT(fileOpenRecent(int)), 0, i);
1152     }
1153     }
1154     }
1155    
1156    
1157     // Force update of the channels display font.
1158     void qsamplerMainForm::updateDisplayFont (void)
1159     {
1160     if (m_pOptions == NULL)
1161     return;
1162    
1163     // Check if display font is legal.
1164     if (m_pOptions->sDisplayFont.isEmpty())
1165     return;
1166     // Realize it.
1167     QFont font;
1168     if (!font.fromString(m_pOptions->sDisplayFont))
1169     return;
1170    
1171     // Full channel list update...
1172     QWidgetList wlist = m_pWorkspace->windowList();
1173     if (wlist.isEmpty())
1174     return;
1175    
1176     m_pWorkspace->setUpdatesEnabled(false);
1177     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1178     qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1179     pChannel->setDisplayFont(font);
1180     }
1181     m_pWorkspace->setUpdatesEnabled(true);
1182     }
1183    
1184    
1185 capela 119 // Force update of the channels maximum volume setting.
1186     void qsamplerMainForm::updateMaxVolume (void)
1187     {
1188     if (m_pOptions == NULL)
1189     return;
1190    
1191     // Full channel list update...
1192     QWidgetList wlist = m_pWorkspace->windowList();
1193     if (wlist.isEmpty())
1194     return;
1195    
1196     m_pWorkspace->setUpdatesEnabled(false);
1197     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1198     qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1199     pChannel->setMaxVolume(m_pOptions->iMaxVolume);
1200     }
1201     m_pWorkspace->setUpdatesEnabled(true);
1202     }
1203    
1204    
1205 capela 109 //-------------------------------------------------------------------------
1206     // qsamplerMainForm -- Messages window form handlers.
1207    
1208     // Messages output methods.
1209     void qsamplerMainForm::appendMessages( const QString& s )
1210     {
1211     if (m_pMessages)
1212     m_pMessages->appendMessages(s);
1213    
1214     statusBar()->message(s, 3000);
1215     }
1216    
1217     void qsamplerMainForm::appendMessagesColor( const QString& s, const QString& c )
1218     {
1219     if (m_pMessages)
1220     m_pMessages->appendMessagesColor(s, c);
1221    
1222     statusBar()->message(s, 3000);
1223     }
1224    
1225     void qsamplerMainForm::appendMessagesText( const QString& s )
1226     {
1227     if (m_pMessages)
1228     m_pMessages->appendMessagesText(s);
1229     }
1230    
1231     void qsamplerMainForm::appendMessagesError( const QString& s )
1232     {
1233     if (m_pMessages)
1234     m_pMessages->show();
1235    
1236     appendMessagesColor(s.simplifyWhiteSpace(), "#ff0000");
1237    
1238     QMessageBox::critical(this, tr("Error"), s, tr("Cancel"));
1239     }
1240    
1241    
1242     // This is a special message format, just for client results.
1243     void qsamplerMainForm::appendMessagesClient( const QString& s )
1244     {
1245     if (m_pClient == NULL)
1246     return;
1247    
1248     appendMessagesColor(s + QString(": %1 (errno=%2)")
1249     .arg(::lscp_client_get_result(m_pClient))
1250     .arg(::lscp_client_get_errno(m_pClient)), "#996666");
1251     }
1252    
1253    
1254     // Force update of the messages font.
1255     void qsamplerMainForm::updateMessagesFont (void)
1256     {
1257     if (m_pOptions == NULL)
1258     return;
1259    
1260     if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {
1261     QFont font;
1262     if (font.fromString(m_pOptions->sMessagesFont))
1263     m_pMessages->setMessagesFont(font);
1264     }
1265     }
1266    
1267    
1268     // Update messages window line limit.
1269     void qsamplerMainForm::updateMessagesLimit (void)
1270     {
1271     if (m_pOptions == NULL)
1272     return;
1273    
1274     if (m_pMessages) {
1275     if (m_pOptions->bMessagesLimit)
1276     m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);
1277     else
1278     m_pMessages->setMessagesLimit(0);
1279     }
1280     }
1281    
1282    
1283     // Enablement of the messages capture feature.
1284     void qsamplerMainForm::updateMessagesCapture (void)
1285     {
1286     if (m_pOptions == NULL)
1287     return;
1288    
1289     if (m_pMessages)
1290     m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);
1291     }
1292    
1293    
1294     //-------------------------------------------------------------------------
1295     // qsamplerMainForm -- MDI channel strip management.
1296    
1297     // The channel strip creation executive.
1298     void qsamplerMainForm::createChannel ( int iChannelID, bool bPrompt )
1299     {
1300     if (m_pClient == NULL)
1301     return;
1302    
1303     // Prepare for auto-arrange?
1304     qsamplerChannelStrip *pChannel = NULL;
1305     int y = 0;
1306     if (m_pOptions && m_pOptions->bAutoArrange) {
1307     QWidgetList wlist = m_pWorkspace->windowList();
1308     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1309     pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1310     // y += pChannel->height() + pChannel->parentWidget()->baseSize().height();
1311     y += pChannel->parentWidget()->frameGeometry().height();
1312     }
1313     }
1314    
1315     // Add a new channel itema...
1316     WFlags wflags = Qt::WStyle_Customize | Qt::WStyle_Tool | Qt::WStyle_Title | Qt::WStyle_NoBorder;
1317     pChannel = new qsamplerChannelStrip(m_pWorkspace, 0, wflags);
1318 capela 119 pChannel->setMaxVolume(m_pOptions->iMaxVolume);
1319 capela 109 pChannel->setup(this, iChannelID);
1320     // We'll need a display font.
1321     QFont font;
1322     if (m_pOptions && font.fromString(m_pOptions->sDisplayFont))
1323     pChannel->setDisplayFont(font);
1324     // Track channel setup changes.
1325     QObject::connect(pChannel, SIGNAL(channelChanged(qsamplerChannelStrip *)), this, SLOT(channelChanged(qsamplerChannelStrip *)));
1326     // Before we show it up, may be we'll
1327     // better ask for some initial values?
1328     if (bPrompt)
1329     pChannel->channelSetup();
1330     // Now we show up us to the world.
1331     pChannel->show();
1332     // Only then, we'll auto-arrange...
1333     if (m_pOptions && m_pOptions->bAutoArrange) {
1334     int iWidth = m_pWorkspace->width();
1335     // int iHeight = pChannel->height() + pChannel->parentWidget()->baseSize().height();
1336     int iHeight = pChannel->parentWidget()->frameGeometry().height();
1337     pChannel->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1338     }
1339     }
1340    
1341    
1342     // Retrieve the active channel strip.
1343     qsamplerChannelStrip *qsamplerMainForm::activeChannel (void)
1344     {
1345     return (qsamplerChannelStrip *) m_pWorkspace->activeWindow();
1346     }
1347    
1348    
1349     // Retrieve a channel strip by index.
1350     qsamplerChannelStrip *qsamplerMainForm::channelAt ( int iChannel )
1351     {
1352     QWidgetList wlist = m_pWorkspace->windowList();
1353     if (wlist.isEmpty())
1354     return 0;
1355    
1356     return (qsamplerChannelStrip *) wlist.at(iChannel);
1357     }
1358    
1359    
1360     // Construct the windows menu.
1361     void qsamplerMainForm::channelsMenuAboutToShow (void)
1362     {
1363     channelsMenu->clear();
1364     channelsArrangeAction->addTo(channelsMenu);
1365     channelsAutoArrangeAction->addTo(channelsMenu);
1366    
1367     QWidgetList wlist = m_pWorkspace->windowList();
1368     if (!wlist.isEmpty()) {
1369     channelsMenu->insertSeparator();
1370     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1371     qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1372     int iItemID = channelsMenu->insertItem(pChannel->caption(), this, SLOT(channelsMenuActivated(int)));
1373     channelsMenu->setItemParameter(iItemID, iChannel);
1374     channelsMenu->setItemChecked(iItemID, activeChannel() == pChannel);
1375     }
1376     }
1377     }
1378    
1379    
1380     // Windows menu activation slot
1381     void qsamplerMainForm::channelsMenuActivated ( int iChannel )
1382     {
1383     qsamplerChannelStrip *pChannel = channelAt(iChannel);
1384     if (pChannel)
1385     pChannel->showNormal();
1386     pChannel->setFocus();
1387     }
1388    
1389    
1390     //-------------------------------------------------------------------------
1391     // qsamplerMainForm -- Timer stuff.
1392    
1393     // Set the pseudo-timer delay schedule.
1394     void qsamplerMainForm::startSchedule ( int iStartDelay )
1395     {
1396     m_iStartDelay = 1 + (iStartDelay * 1000);
1397     m_iTimerDelay = 0;
1398     }
1399    
1400     // Suspend the pseudo-timer delay schedule.
1401     void qsamplerMainForm::stopSchedule (void)
1402     {
1403     m_iStartDelay = 0;
1404     m_iTimerDelay = 0;
1405     }
1406    
1407     // Timer slot funtion.
1408     void qsamplerMainForm::timerSlot (void)
1409     {
1410     if (m_pOptions == NULL)
1411     return;
1412    
1413     // Is it the first shot on server start after a few delay?
1414     if (m_iTimerDelay < m_iStartDelay) {
1415     m_iTimerDelay += QSAMPLER_TIMER_MSECS;
1416     if (m_iTimerDelay >= m_iStartDelay) {
1417     // If we cannot start it now, maybe a lil'mo'later ;)
1418     if (!startClient()) {
1419     m_iStartDelay += m_iTimerDelay;
1420     m_iTimerDelay = 0;
1421     }
1422     }
1423     }
1424    
1425     // Refresh each channel usage, on each period...
1426     if (m_pClient && m_pOptions->bAutoRefresh && m_pWorkspace->isUpdatesEnabled()) {
1427     m_iTimerSlot += QSAMPLER_TIMER_MSECS;
1428     if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime) {
1429     m_iTimerSlot = 0;
1430     QWidgetList wlist = m_pWorkspace->windowList();
1431     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1432     qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1433     if (pChannel->isVisible())
1434     pChannel->updateChannelUsage();
1435     }
1436     }
1437     }
1438    
1439     // Register the next timer slot.
1440     QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
1441     }
1442    
1443    
1444     //-------------------------------------------------------------------------
1445     // qsamplerMainForm -- Server stuff.
1446    
1447     // Start linuxsampler server...
1448     void qsamplerMainForm::startServer (void)
1449     {
1450     if (m_pOptions == NULL)
1451     return;
1452    
1453     // Aren't already a client, are we?
1454     if (!m_pOptions->bServerStart || m_pClient)
1455     return;
1456    
1457     // Is the server process instance still here?
1458     if (m_pServer) {
1459     switch (QMessageBox::warning(this, tr("Warning"),
1460     tr("Could not start the LinuxSampler server.\n\n"
1461     "Maybe it ss already started."),
1462     tr("Stop"), tr("Kill"), tr("Cancel"))) {
1463     case 0:
1464     m_pServer->tryTerminate();
1465     break;
1466     case 1:
1467     m_pServer->kill();
1468     break;
1469     }
1470     return;
1471     }
1472    
1473     // Reset our timer counters...
1474     stopSchedule();
1475    
1476     // OK. Let's build the startup process...
1477     m_pServer = new QProcess(this);
1478    
1479     // Setup stdout/stderr capture...
1480     //if (m_pOptions->bStdoutCapture) {
1481     m_pServer->setCommunication(QProcess::Stdout | QProcess::Stderr | QProcess::DupStderr);
1482     QObject::connect(m_pServer, SIGNAL(readyReadStdout()), this, SLOT(readServerStdout()));
1483     QObject::connect(m_pServer, SIGNAL(readyReadStderr()), this, SLOT(readServerStdout()));
1484     //}
1485     // The unforgiveable signal communication...
1486     QObject::connect(m_pServer, SIGNAL(processExited()), this, SLOT(processServerExit()));
1487    
1488     // Build process arguments...
1489     m_pServer->setArguments(QStringList::split(' ', m_pOptions->sServerCmdLine));
1490    
1491     appendMessages(tr("Server is starting..."));
1492     appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");
1493    
1494     // Go jack, go...
1495     if (!m_pServer->start()) {
1496     appendMessagesError(tr("Could not start server.\n\nSorry."));
1497     processServerExit();
1498     return;
1499     }
1500    
1501     // Show startup results...
1502     appendMessages(tr("Server was started with PID=%1.").arg((long) m_pServer->processIdentifier()));
1503    
1504     // Reset (yet again) the timer counters,
1505     // but this time is deferred as the user opted.
1506     startSchedule(m_pOptions->iStartDelay);
1507     stabilizeForm();
1508     }
1509    
1510    
1511     // Stop linuxsampler server...
1512     void qsamplerMainForm::stopServer (void)
1513     {
1514     // Stop client code.
1515     stopClient();
1516    
1517     // And try to stop server.
1518     if (m_pServer) {
1519     appendMessages(tr("Server is stopping..."));
1520 capela 122 if (m_pServer->isRunning())
1521 capela 109 m_pServer->tryTerminate();
1522     }
1523    
1524 capela 122 // Give it some time to terminate gracefully and stabilize...
1525     QTime t;
1526     t.start();
1527     while (t.elapsed() < QSAMPLER_TIMER_MSECS)
1528     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
1529    
1530 capela 109 // Do final processing anyway.
1531     processServerExit();
1532     }
1533    
1534    
1535     // Stdout handler...
1536     void qsamplerMainForm::readServerStdout (void)
1537     {
1538     if (m_pMessages)
1539     m_pMessages->appendStdoutBuffer(m_pServer->readStdout());
1540     }
1541    
1542    
1543     // Linuxsampler server cleanup.
1544     void qsamplerMainForm::processServerExit (void)
1545     {
1546     // Force client code cleanup.
1547     stopClient();
1548    
1549     // Flush anything that maybe pending...
1550     if (m_pMessages)
1551     m_pMessages->flushStdoutBuffer();
1552    
1553     if (m_pServer) {
1554     // Force final server shutdown...
1555     appendMessages(tr("Server was stopped with exit status %1.").arg(m_pServer->exitStatus()));
1556     if (!m_pServer->normalExit())
1557     m_pServer->kill();
1558     // Destroy it.
1559     delete m_pServer;
1560     m_pServer = NULL;
1561     }
1562    
1563     // Again, make status visible stable.
1564     stabilizeForm();
1565     }
1566    
1567    
1568     //-------------------------------------------------------------------------
1569     // qsamplerMainForm -- Client stuff.
1570    
1571     // The LSCP client callback procedure.
1572 capela 149 lscp_status_t qsampler_client_callback ( lscp_client_t */*pClient*/, lscp_event_t event, const char *pchData, int cchData, void *pvData )
1573 capela 109 {
1574 capela 149 qsamplerMainForm *pMainForm = (qsamplerMainForm *) pvData;
1575     if (pMainForm == NULL)
1576     return LSCP_FAILED;
1577    
1578     // ATTN: DO NOT EVER call any GUI code here,
1579 capela 145 // as this is run under some other thread context.
1580     // A custom event must be posted here...
1581 capela 149 QApplication::postEvent(pMainForm, new qsamplerCustomEvent(event, pchData, cchData));
1582 capela 109
1583     return LSCP_OK;
1584     }
1585    
1586    
1587     // Start our almighty client...
1588     bool qsamplerMainForm::startClient (void)
1589     {
1590     // Have it a setup?
1591     if (m_pOptions == NULL)
1592     return false;
1593    
1594     // Aren't we already started, are we?
1595     if (m_pClient)
1596     return true;
1597    
1598     // Log prepare here.
1599     appendMessages(tr("Client connecting..."));
1600    
1601     // Create the client handle...
1602     m_pClient = ::lscp_client_create(m_pOptions->sServerHost.latin1(), m_pOptions->iServerPort, qsampler_client_callback, this);
1603     if (m_pClient == NULL) {
1604     // Is this the first try?
1605     // maybe we need to start a local server...
1606     if ((m_pServer && m_pServer->isRunning()) || !m_pOptions->bServerStart)
1607     appendMessagesError(tr("Could not connect to server as client.\n\nSorry."));
1608     else
1609     startServer();
1610     // This is always a failure.
1611     stabilizeForm();
1612     return false;
1613     }
1614     // Just set receive timeout value, blindly.
1615     ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);
1616     appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));
1617    
1618     // We may stop scheduling around.
1619     stopSchedule();
1620    
1621     // We'll accept drops from now on...
1622     setAcceptDrops(true);
1623    
1624     // Log success here.
1625     appendMessages(tr("Client connected."));
1626    
1627     // Is any session pending to be loaded?
1628     if (!m_pOptions->sSessionFile.isEmpty()) {
1629     // Just load the prabably startup session...
1630     if (loadSessionFile(m_pOptions->sSessionFile)) {
1631     m_pOptions->sSessionFile = QString::null;
1632     return true;
1633     }
1634     }
1635    
1636     // Make a new session
1637     return newSession();
1638     }
1639    
1640    
1641     // Stop client...
1642     void qsamplerMainForm::stopClient (void)
1643     {
1644     if (m_pClient == NULL)
1645     return;
1646    
1647     // Log prepare here.
1648     appendMessages(tr("Client disconnecting..."));
1649    
1650     // Clear timer counters...
1651     stopSchedule();
1652    
1653     // We'll reject drops from now on...
1654     setAcceptDrops(false);
1655    
1656     // Force any channel strips around, but
1657     // but avoid removing the corresponding
1658     // channels from the back-end server.
1659     m_iDirtyCount = 0;
1660     closeSession(false);
1661    
1662     // Close us as a client...
1663     lscp_client_destroy(m_pClient);
1664     m_pClient = NULL;
1665    
1666     // Log final here.
1667     appendMessages(tr("Client disconnected."));
1668    
1669     // Make visible status.
1670     stabilizeForm();
1671     }
1672    
1673    
1674     // end of qsamplerMainForm.ui.h

  ViewVC Help
Powered by ViewVC