/[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 263 - (hide annotations) (download) (as text)
Wed Sep 29 09:01:35 2004 UTC (19 years, 6 months ago) by capela
File MIME type: text/x-c++hdr
File size: 53176 byte(s)
Channel strip setup dialog invokation 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 255 ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannelID << " ";
606     if (pChannel->midiChannel() > 0)
607     ts << pChannel->midiChannel();
608     else
609     ts << "ALL";
610     ts << endl;
611 capela 115 ts << "LOAD ENGINE " << pChannel->engineName() << " " << iChannelID << endl;
612 capela 150 ts << "LOAD INSTRUMENT NON_MODAL '" << pChannel->instrumentFile() << "' " << pChannel->instrumentNr() << " " << iChannelID << endl;
613 capela 109 ts << "SET CHANNEL VOLUME " << iChannelID << " " << pChannel->volume() << endl;
614     ts << endl;
615     // Try to keep it snappy :)
616     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
617     }
618    
619     // Ok. we've wrote it.
620     file.close();
621    
622     // Have we any errors?
623     if (iErrors > 0)
624     appendMessagesError(tr("Some settings could not be saved\nto \"%1\" session file.\n\nSorry.").arg(sFilename));
625    
626     // Save as default session directory.
627     if (m_pOptions)
628     m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);
629     // We're not dirty anymore.
630     m_iDirtyCount = 0;
631     // Stabilize form...
632     m_sFilename = sFilename;
633     updateRecentFiles(sFilename);
634     appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename)));
635     stabilizeForm();
636     return true;
637     }
638    
639    
640     //-------------------------------------------------------------------------
641     // qsamplerMainForm -- File Action slots.
642    
643     // Create a new sampler session.
644     void qsamplerMainForm::fileNew (void)
645     {
646     // Of course we'll start clean new.
647     newSession();
648     }
649    
650    
651     // Open an existing sampler session.
652     void qsamplerMainForm::fileOpen (void)
653     {
654     // Open it right away.
655     openSession();
656     }
657    
658    
659     // Open a recent file session.
660     void qsamplerMainForm::fileOpenRecent ( int iIndex )
661     {
662     // Check if we can safely close the current session...
663     if (m_pOptions && closeSession(true)) {
664     QString sFilename = m_pOptions->recentFiles[iIndex];
665     loadSessionFile(sFilename);
666     }
667     }
668    
669    
670     // Save current sampler session.
671     void qsamplerMainForm::fileSave (void)
672     {
673     // Save it right away.
674     saveSession(false);
675     }
676    
677    
678     // Save current sampler session with another name.
679     void qsamplerMainForm::fileSaveAs (void)
680     {
681     // Save it right away, maybe with another name.
682     saveSession(true);
683     }
684    
685    
686 capela 255 // Reset the sampler instance.
687     void qsamplerMainForm::fileReset (void)
688     {
689     if (m_pClient == NULL)
690     return;
691    
692     // Ask user whether he/she want's an internal sampler reset...
693     if (QMessageBox::warning(this, tr("Warning"),
694     tr("Resetting the sampler instance will close\n"
695     "all device and channel configurations.\n\n"
696     "Please note that this operation may cause\n"
697     "temporary MIDI and Audio disruption\n\n"
698     "Do you want to reset the sampler engine now?"),
699     tr("Reset"), tr("Cancel")) > 0)
700     return;
701    
702     // Just do the reset, after closing down current session...
703 capela 261 if (closeSession(true) && ::lscp_reset_sampler(m_pClient) != LSCP_OK) {
704 capela 255 appendMessagesClient("lscp_reset_sampler");
705 capela 261 appendMessagesError(tr("Could not reset sampler instance.\n\nSorry."));
706     return;
707     }
708    
709     // Log this.
710     appendMessages(tr("Sampler reset."));
711 capela 255 }
712    
713    
714 capela 109 // Restart the client/server instance.
715     void qsamplerMainForm::fileRestart (void)
716     {
717     if (m_pOptions == NULL)
718     return;
719    
720     bool bRestart = true;
721    
722     // Ask user whether he/she want's a complete restart...
723     // (if we're currently up and running)
724     if (bRestart && m_pClient) {
725     bRestart = (QMessageBox::warning(this, tr("Warning"),
726     tr("New settings will be effective after\n"
727     "restarting the client/server connection.\n\n"
728     "Please note that this operation may cause\n"
729     "temporary MIDI and Audio disruption\n\n"
730     "Do you want to restart the connection now?"),
731     tr("Restart"), tr("Cancel")) == 0);
732     }
733    
734     // Are we still for it?
735     if (bRestart && closeSession(true)) {
736     // Stop server, it will force the client too.
737     stopServer();
738     // Reschedule a restart...
739     startSchedule(m_pOptions->iStartDelay);
740     }
741     }
742    
743    
744     // Exit application program.
745     void qsamplerMainForm::fileExit (void)
746     {
747     // Go for close the whole thing.
748     close();
749     }
750    
751    
752     //-------------------------------------------------------------------------
753     // qsamplerMainForm -- Edit Action slots.
754    
755     // Add a new sampler channel.
756     void qsamplerMainForm::editAddChannel (void)
757     {
758     if (m_pClient == NULL)
759     return;
760    
761     // Create the new sampler channel.
762     int iChannelID = ::lscp_add_channel(m_pClient);
763     if (iChannelID < 0) {
764     appendMessagesClient("lscp_add_channel");
765     appendMessagesError(tr("Could not create the new channel.\n\nSorry."));
766     return;
767     }
768    
769     // Log this happening.
770     appendMessages(tr("Channel %1 created.").arg(iChannelID));
771    
772     // Just create the channel strip with given id.
773     createChannel(iChannelID, true);
774    
775     // We'll be dirty, for sure...
776     m_iDirtyCount++;
777     // Stabilize form anyway.
778     stabilizeForm();
779     }
780    
781    
782     // Remove current sampler channel.
783     void qsamplerMainForm::editRemoveChannel (void)
784     {
785     if (m_pClient == NULL)
786     return;
787    
788     qsamplerChannelStrip *pChannel = activeChannel();
789     if (pChannel == NULL)
790     return;
791    
792     // Prompt user if he/she's sure about this...
793     if (m_pOptions && m_pOptions->bConfirmRemove) {
794     if (QMessageBox::warning(this, tr("Warning"),
795     tr("About to remove channel:\n\n"
796     "%1\n\n"
797     "Are you sure?")
798     .arg(pChannel->caption()),
799     tr("OK"), tr("Cancel")) > 0)
800     return;
801     }
802    
803     // Remove the existing sampler channel.
804     if (::lscp_remove_channel(m_pClient, pChannel->channelID()) != LSCP_OK) {
805     appendMessagesClient("lscp_remove_channel");
806     appendMessagesError(tr("Could not remove channel.\n\nSorry."));
807     return;
808     }
809    
810     // Log this happening.
811     appendMessages(tr("Channel %1 removed.").arg(pChannel->channelID()));
812    
813     // Just delete the channel strip.
814     delete pChannel;
815     // Do we auto-arrange?
816     if (m_pOptions && m_pOptions->bAutoArrange)
817     channelsArrange();
818    
819     // We'll be dirty, for sure...
820     m_iDirtyCount++;
821     stabilizeForm();
822     }
823    
824    
825     // Setup current sampler channel.
826     void qsamplerMainForm::editSetupChannel (void)
827     {
828     if (m_pClient == NULL)
829     return;
830    
831     qsamplerChannelStrip *pChannel = activeChannel();
832     if (pChannel == NULL)
833     return;
834    
835     // Just invoque the channel strip procedure.
836 capela 263 pChannel->showChannelSetup(false);
837 capela 109 }
838    
839    
840     // Reset current sampler channel.
841     void qsamplerMainForm::editResetChannel (void)
842     {
843     if (m_pClient == NULL)
844     return;
845    
846     qsamplerChannelStrip *pChannel = activeChannel();
847     if (pChannel == NULL)
848     return;
849    
850     // Remove the existing sampler channel.
851     if (::lscp_reset_channel(m_pClient, pChannel->channelID()) != LSCP_OK) {
852     appendMessagesClient("lscp_reset_channel");
853     appendMessagesError(tr("Could not reset channel.\n\nSorry."));
854     return;
855     }
856    
857     // Log this.
858     appendMessages(tr("Channel %1 reset.").arg(pChannel->channelID()));
859    
860     // Refresh channel strip info.
861     pChannel->updateChannelInfo();
862     }
863    
864    
865     //-------------------------------------------------------------------------
866     // qsamplerMainForm -- View Action slots.
867    
868     // Show/hide the main program window menubar.
869     void qsamplerMainForm::viewMenubar ( bool bOn )
870     {
871     if (bOn)
872     MenuBar->show();
873     else
874     MenuBar->hide();
875     }
876    
877    
878     // Show/hide the main program window toolbar.
879     void qsamplerMainForm::viewToolbar ( bool bOn )
880     {
881     if (bOn) {
882     fileToolbar->show();
883     editToolbar->show();
884     channelsToolbar->show();
885     } else {
886     fileToolbar->hide();
887     editToolbar->hide();
888     channelsToolbar->hide();
889     }
890     }
891    
892    
893     // Show/hide the main program window statusbar.
894     void qsamplerMainForm::viewStatusbar ( bool bOn )
895     {
896     if (bOn)
897     statusBar()->show();
898     else
899     statusBar()->hide();
900     }
901    
902    
903     // Show/hide the messages window logger.
904     void qsamplerMainForm::viewMessages ( bool bOn )
905     {
906     if (bOn)
907     m_pMessages->show();
908     else
909     m_pMessages->hide();
910     }
911    
912    
913     // Show options dialog.
914     void qsamplerMainForm::viewOptions (void)
915     {
916     if (m_pOptions == NULL)
917     return;
918    
919     qsamplerOptionsForm *pOptionsForm = new qsamplerOptionsForm(this);
920     if (pOptionsForm) {
921     // Check out some initial nullities(tm)...
922     qsamplerChannelStrip *pChannel = activeChannel();
923     if (m_pOptions->sDisplayFont.isEmpty() && pChannel)
924     m_pOptions->sDisplayFont = pChannel->displayFont().toString();
925     if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages)
926     m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();
927     // To track down deferred or immediate changes.
928     QString sOldServerHost = m_pOptions->sServerHost;
929     int iOldServerPort = m_pOptions->iServerPort;
930     int iOldServerTimeout = m_pOptions->iServerTimeout;
931     bool bOldServerStart = m_pOptions->bServerStart;
932     QString sOldServerCmdLine = m_pOptions->sServerCmdLine;
933     QString sOldDisplayFont = m_pOptions->sDisplayFont;
934 capela 119 int iOldMaxVolume = m_pOptions->iMaxVolume;
935 capela 109 QString sOldMessagesFont = m_pOptions->sMessagesFont;
936     bool bOldStdoutCapture = m_pOptions->bStdoutCapture;
937     int bOldMessagesLimit = m_pOptions->bMessagesLimit;
938     int iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines;
939     bool bOldCompletePath = m_pOptions->bCompletePath;
940     int iOldMaxRecentFiles = m_pOptions->iMaxRecentFiles;
941     // Load the current setup settings.
942     pOptionsForm->setup(m_pOptions);
943     // Show the setup dialog...
944     if (pOptionsForm->exec()) {
945     // Warn if something will be only effective on next run.
946     if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) ||
947     (!bOldStdoutCapture && m_pOptions->bStdoutCapture)) {
948     QMessageBox::information(this, tr("Information"),
949     tr("Some settings may be only effective\n"
950     "next time you start this program."), tr("OK"));
951     updateMessagesCapture();
952     }
953     // Check wheather something immediate has changed.
954     if (( bOldCompletePath && !m_pOptions->bCompletePath) ||
955     (!bOldCompletePath && m_pOptions->bCompletePath) ||
956     (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles))
957     updateRecentFilesMenu();
958     if (sOldDisplayFont != m_pOptions->sDisplayFont)
959     updateDisplayFont();
960 capela 119 if (iOldMaxVolume != m_pOptions->iMaxVolume)
961     updateMaxVolume();
962 capela 109 if (sOldMessagesFont != m_pOptions->sMessagesFont)
963     updateMessagesFont();
964     if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) ||
965     (!bOldMessagesLimit && m_pOptions->bMessagesLimit) ||
966     (iOldMessagesLimitLines != m_pOptions->iMessagesLimitLines))
967     updateMessagesLimit();
968     // And now the main thing, whether we'll do client/server recycling?
969     if ((sOldServerHost != m_pOptions->sServerHost) ||
970     (iOldServerPort != m_pOptions->iServerPort) ||
971     (iOldServerTimeout != m_pOptions->iServerTimeout) ||
972     ( bOldServerStart && !m_pOptions->bServerStart) ||
973     (!bOldServerStart && m_pOptions->bServerStart) ||
974     (sOldServerCmdLine != m_pOptions->sServerCmdLine && m_pOptions->bServerStart))
975     fileRestart();
976     }
977     // Done.
978     delete pOptionsForm;
979     }
980    
981     // This makes it.
982     stabilizeForm();
983     }
984    
985    
986     //-------------------------------------------------------------------------
987     // qsamplerMainForm -- Channels action slots.
988    
989     // Arrange channel strips.
990     void qsamplerMainForm::channelsArrange (void)
991     {
992     // Full width vertical tiling
993     QWidgetList wlist = m_pWorkspace->windowList();
994     if (wlist.isEmpty())
995     return;
996    
997     m_pWorkspace->setUpdatesEnabled(false);
998     int y = 0;
999     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1000     qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1001     /* if (pChannel->testWState(WState_Maximized | WState_Minimized)) {
1002     // Prevent flicker...
1003     pChannel->hide();
1004     pChannel->showNormal();
1005     } */
1006     pChannel->adjustSize();
1007     int iWidth = m_pWorkspace->width();
1008     if (iWidth < pChannel->width())
1009     iWidth = pChannel->width();
1010     // int iHeight = pChannel->height() + pChannel->parentWidget()->baseSize().height();
1011     int iHeight = pChannel->parentWidget()->frameGeometry().height();
1012     pChannel->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1013     y += iHeight;
1014     }
1015     m_pWorkspace->setUpdatesEnabled(true);
1016    
1017     stabilizeForm();
1018     }
1019    
1020    
1021     // Auto-arrange channel strips.
1022     void qsamplerMainForm::channelsAutoArrange ( bool bOn )
1023     {
1024     if (m_pOptions == NULL)
1025     return;
1026    
1027     // Toggle the auto-arrange flag.
1028     m_pOptions->bAutoArrange = bOn;
1029    
1030     // If on, update whole workspace...
1031     if (m_pOptions->bAutoArrange)
1032     channelsArrange();
1033     }
1034    
1035    
1036     //-------------------------------------------------------------------------
1037     // qsamplerMainForm -- Help Action slots.
1038    
1039     // Show information about the Qt toolkit.
1040     void qsamplerMainForm::helpAboutQt (void)
1041     {
1042     QMessageBox::aboutQt(this);
1043     }
1044    
1045    
1046     // Show information about application program.
1047     void qsamplerMainForm::helpAbout (void)
1048     {
1049     // Stuff the about box text...
1050     QString sText = "<p>\n";
1051     sText += "<b>" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "</b><br />\n";
1052     sText += "<br />\n";
1053     sText += tr("Version") + ": <b>" QSAMPLER_VERSION "</b><br />\n";
1054     sText += "<small>" + tr("Build") + ": " __DATE__ " " __TIME__ "</small><br />\n";
1055     #ifdef CONFIG_DEBUG
1056     sText += "<small><font color=\"red\">";
1057     sText += tr("Debugging option enabled.");
1058     sText += "</font></small><br />";
1059     #endif
1060 capela 176 #ifndef CONFIG_LIBGIG
1061     sText += "<small><font color=\"red\">";
1062     sText += tr("GIG (libgig) file support disabled.");
1063     sText += "</font></small><br />";
1064     #endif
1065 capela 109 sText += "<br />\n";
1066     sText += tr("Using") + ": ";
1067     sText += ::lscp_client_package();
1068     sText += " ";
1069     sText += ::lscp_client_version();
1070     sText += "<br />\n";
1071     sText += "<br />\n";
1072     sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";
1073     sText += "<br />\n";
1074     sText += "<small>";
1075     sText += QSAMPLER_COPYRIGHT "<br />\n";
1076     sText += "<br />\n";
1077     sText += tr("This program is free software; you can redistribute it and/or modify it") + "<br />\n";
1078     sText += tr("under the terms of the GNU General Public License version 2 or later.");
1079     sText += "</small>";
1080     sText += "</p>\n";
1081    
1082     QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText);
1083     }
1084    
1085    
1086     //-------------------------------------------------------------------------
1087     // qsamplerMainForm -- Main window stabilization.
1088    
1089     void qsamplerMainForm::stabilizeForm (void)
1090     {
1091     // Update the main application caption...
1092     QString sSessioName = sessionName(m_sFilename);
1093     if (m_iDirtyCount > 0)
1094     sSessioName += '*';
1095     setCaption(tr(QSAMPLER_TITLE " - [%1]").arg(sSessioName));
1096    
1097     // Update the main menu state...
1098     qsamplerChannelStrip *pChannel = activeChannel();
1099     bool bHasClient = (m_pOptions != NULL && m_pClient != NULL);
1100     bool bHasChannel = (bHasClient && pChannel != NULL);
1101     fileNewAction->setEnabled(bHasClient);
1102     fileOpenAction->setEnabled(bHasClient);
1103     fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);
1104     fileSaveAsAction->setEnabled(bHasClient);
1105 capela 255 fileResetAction->setEnabled(bHasClient);
1106 capela 109 fileRestartAction->setEnabled(bHasClient || m_pServer == NULL);
1107     editAddChannelAction->setEnabled(bHasClient);
1108     editRemoveChannelAction->setEnabled(bHasChannel);
1109     editSetupChannelAction->setEnabled(bHasChannel);
1110     editResetChannelAction->setEnabled(bHasChannel);
1111     channelsArrangeAction->setEnabled(bHasChannel);
1112     viewMessagesAction->setOn(m_pMessages && m_pMessages->isVisible());
1113    
1114     // Client/Server status...
1115     if (bHasClient) {
1116     m_status[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));
1117     m_status[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost + ":" + QString::number(m_pOptions->iServerPort));
1118     } else {
1119     m_status[QSAMPLER_STATUS_CLIENT]->clear();
1120     m_status[QSAMPLER_STATUS_SERVER]->clear();
1121     }
1122     // Channel status...
1123     if (bHasChannel)
1124     m_status[QSAMPLER_STATUS_CHANNEL]->setText(pChannel->caption());
1125     else
1126     m_status[QSAMPLER_STATUS_CHANNEL]->clear();
1127     // Session status...
1128     if (m_iDirtyCount > 0)
1129     m_status[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));
1130     else
1131     m_status[QSAMPLER_STATUS_SESSION]->clear();
1132    
1133     // Recent files menu.
1134     m_pRecentFilesMenu->setEnabled(bHasClient && m_pOptions->recentFiles.count() > 0);
1135    
1136     // Always make the latest message visible.
1137     if (m_pMessages)
1138     m_pMessages->scrollToBottom();
1139     }
1140    
1141    
1142     // Channel change receiver slot.
1143     void qsamplerMainForm::channelChanged( qsamplerChannelStrip * )
1144     {
1145     // Just mark the dirty form.
1146     m_iDirtyCount++;
1147     // and update the form status...
1148     stabilizeForm();
1149     }
1150    
1151    
1152     // Update the recent files list and menu.
1153     void qsamplerMainForm::updateRecentFiles ( const QString& sFilename )
1154     {
1155     if (m_pOptions == NULL)
1156     return;
1157    
1158     // Remove from list if already there (avoid duplicates)
1159     QStringList::Iterator iter = m_pOptions->recentFiles.find(sFilename);
1160     if (iter != m_pOptions->recentFiles.end())
1161     m_pOptions->recentFiles.remove(iter);
1162     // Put it to front...
1163     m_pOptions->recentFiles.push_front(sFilename);
1164    
1165     // May update the menu.
1166     updateRecentFilesMenu();
1167     }
1168    
1169    
1170     // Update the recent files list and menu.
1171     void qsamplerMainForm::updateRecentFilesMenu (void)
1172     {
1173     if (m_pOptions == NULL)
1174     return;
1175    
1176     // Time to keep the list under limits.
1177     int iRecentFiles = m_pOptions->recentFiles.count();
1178     while (iRecentFiles > m_pOptions->iMaxRecentFiles) {
1179     m_pOptions->recentFiles.pop_back();
1180     iRecentFiles--;
1181     }
1182    
1183     // rebuild the recent files menu...
1184     m_pRecentFilesMenu->clear();
1185     for (int i = 0; i < iRecentFiles; i++) {
1186     const QString& sFilename = m_pOptions->recentFiles[i];
1187     if (QFileInfo(sFilename).exists()) {
1188     m_pRecentFilesMenu->insertItem(QString("&%1 %2")
1189     .arg(i + 1).arg(sessionName(sFilename)),
1190     this, SLOT(fileOpenRecent(int)), 0, i);
1191     }
1192     }
1193     }
1194    
1195    
1196     // Force update of the channels display font.
1197     void qsamplerMainForm::updateDisplayFont (void)
1198     {
1199     if (m_pOptions == NULL)
1200     return;
1201    
1202     // Check if display font is legal.
1203     if (m_pOptions->sDisplayFont.isEmpty())
1204     return;
1205     // Realize it.
1206     QFont font;
1207     if (!font.fromString(m_pOptions->sDisplayFont))
1208     return;
1209    
1210     // Full channel list update...
1211     QWidgetList wlist = m_pWorkspace->windowList();
1212     if (wlist.isEmpty())
1213     return;
1214    
1215     m_pWorkspace->setUpdatesEnabled(false);
1216     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1217     qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1218     pChannel->setDisplayFont(font);
1219     }
1220     m_pWorkspace->setUpdatesEnabled(true);
1221     }
1222    
1223    
1224 capela 119 // Force update of the channels maximum volume setting.
1225     void qsamplerMainForm::updateMaxVolume (void)
1226     {
1227     if (m_pOptions == NULL)
1228     return;
1229    
1230     // Full channel list update...
1231     QWidgetList wlist = m_pWorkspace->windowList();
1232     if (wlist.isEmpty())
1233     return;
1234    
1235     m_pWorkspace->setUpdatesEnabled(false);
1236     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1237     qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1238     pChannel->setMaxVolume(m_pOptions->iMaxVolume);
1239     }
1240     m_pWorkspace->setUpdatesEnabled(true);
1241     }
1242    
1243    
1244 capela 109 //-------------------------------------------------------------------------
1245     // qsamplerMainForm -- Messages window form handlers.
1246    
1247     // Messages output methods.
1248     void qsamplerMainForm::appendMessages( const QString& s )
1249     {
1250     if (m_pMessages)
1251     m_pMessages->appendMessages(s);
1252    
1253     statusBar()->message(s, 3000);
1254     }
1255    
1256     void qsamplerMainForm::appendMessagesColor( const QString& s, const QString& c )
1257     {
1258     if (m_pMessages)
1259     m_pMessages->appendMessagesColor(s, c);
1260    
1261     statusBar()->message(s, 3000);
1262     }
1263    
1264     void qsamplerMainForm::appendMessagesText( const QString& s )
1265     {
1266     if (m_pMessages)
1267     m_pMessages->appendMessagesText(s);
1268     }
1269    
1270     void qsamplerMainForm::appendMessagesError( const QString& s )
1271     {
1272     if (m_pMessages)
1273     m_pMessages->show();
1274    
1275     appendMessagesColor(s.simplifyWhiteSpace(), "#ff0000");
1276    
1277     QMessageBox::critical(this, tr("Error"), s, tr("Cancel"));
1278     }
1279    
1280    
1281     // This is a special message format, just for client results.
1282     void qsamplerMainForm::appendMessagesClient( const QString& s )
1283     {
1284     if (m_pClient == NULL)
1285     return;
1286    
1287     appendMessagesColor(s + QString(": %1 (errno=%2)")
1288     .arg(::lscp_client_get_result(m_pClient))
1289     .arg(::lscp_client_get_errno(m_pClient)), "#996666");
1290     }
1291    
1292    
1293     // Force update of the messages font.
1294     void qsamplerMainForm::updateMessagesFont (void)
1295     {
1296     if (m_pOptions == NULL)
1297     return;
1298    
1299     if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {
1300     QFont font;
1301     if (font.fromString(m_pOptions->sMessagesFont))
1302     m_pMessages->setMessagesFont(font);
1303     }
1304     }
1305    
1306    
1307     // Update messages window line limit.
1308     void qsamplerMainForm::updateMessagesLimit (void)
1309     {
1310     if (m_pOptions == NULL)
1311     return;
1312    
1313     if (m_pMessages) {
1314     if (m_pOptions->bMessagesLimit)
1315     m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);
1316     else
1317     m_pMessages->setMessagesLimit(0);
1318     }
1319     }
1320    
1321    
1322     // Enablement of the messages capture feature.
1323     void qsamplerMainForm::updateMessagesCapture (void)
1324     {
1325     if (m_pOptions == NULL)
1326     return;
1327    
1328     if (m_pMessages)
1329     m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);
1330     }
1331    
1332    
1333     //-------------------------------------------------------------------------
1334     // qsamplerMainForm -- MDI channel strip management.
1335    
1336     // The channel strip creation executive.
1337     void qsamplerMainForm::createChannel ( int iChannelID, bool bPrompt )
1338     {
1339     if (m_pClient == NULL)
1340     return;
1341    
1342     // Prepare for auto-arrange?
1343     qsamplerChannelStrip *pChannel = NULL;
1344     int y = 0;
1345     if (m_pOptions && m_pOptions->bAutoArrange) {
1346     QWidgetList wlist = m_pWorkspace->windowList();
1347     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1348     pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1349     // y += pChannel->height() + pChannel->parentWidget()->baseSize().height();
1350     y += pChannel->parentWidget()->frameGeometry().height();
1351     }
1352     }
1353    
1354     // Add a new channel itema...
1355     WFlags wflags = Qt::WStyle_Customize | Qt::WStyle_Tool | Qt::WStyle_Title | Qt::WStyle_NoBorder;
1356     pChannel = new qsamplerChannelStrip(m_pWorkspace, 0, wflags);
1357 capela 119 pChannel->setMaxVolume(m_pOptions->iMaxVolume);
1358 capela 109 pChannel->setup(this, iChannelID);
1359     // We'll need a display font.
1360     QFont font;
1361     if (m_pOptions && font.fromString(m_pOptions->sDisplayFont))
1362     pChannel->setDisplayFont(font);
1363     // Track channel setup changes.
1364     QObject::connect(pChannel, SIGNAL(channelChanged(qsamplerChannelStrip *)), this, SLOT(channelChanged(qsamplerChannelStrip *)));
1365     // Before we show it up, may be we'll
1366     // better ask for some initial values?
1367     if (bPrompt)
1368 capela 263 pChannel->showChannelSetup(true);
1369 capela 109 // Now we show up us to the world.
1370     pChannel->show();
1371     // Only then, we'll auto-arrange...
1372     if (m_pOptions && m_pOptions->bAutoArrange) {
1373     int iWidth = m_pWorkspace->width();
1374     // int iHeight = pChannel->height() + pChannel->parentWidget()->baseSize().height();
1375     int iHeight = pChannel->parentWidget()->frameGeometry().height();
1376     pChannel->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1377     }
1378     }
1379    
1380    
1381     // Retrieve the active channel strip.
1382     qsamplerChannelStrip *qsamplerMainForm::activeChannel (void)
1383     {
1384     return (qsamplerChannelStrip *) m_pWorkspace->activeWindow();
1385     }
1386    
1387    
1388     // Retrieve a channel strip by index.
1389     qsamplerChannelStrip *qsamplerMainForm::channelAt ( int iChannel )
1390     {
1391     QWidgetList wlist = m_pWorkspace->windowList();
1392     if (wlist.isEmpty())
1393     return 0;
1394    
1395     return (qsamplerChannelStrip *) wlist.at(iChannel);
1396     }
1397    
1398    
1399     // Construct the windows menu.
1400     void qsamplerMainForm::channelsMenuAboutToShow (void)
1401     {
1402     channelsMenu->clear();
1403     channelsArrangeAction->addTo(channelsMenu);
1404     channelsAutoArrangeAction->addTo(channelsMenu);
1405    
1406     QWidgetList wlist = m_pWorkspace->windowList();
1407     if (!wlist.isEmpty()) {
1408     channelsMenu->insertSeparator();
1409     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1410     qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1411     int iItemID = channelsMenu->insertItem(pChannel->caption(), this, SLOT(channelsMenuActivated(int)));
1412     channelsMenu->setItemParameter(iItemID, iChannel);
1413     channelsMenu->setItemChecked(iItemID, activeChannel() == pChannel);
1414     }
1415     }
1416     }
1417    
1418    
1419     // Windows menu activation slot
1420     void qsamplerMainForm::channelsMenuActivated ( int iChannel )
1421     {
1422     qsamplerChannelStrip *pChannel = channelAt(iChannel);
1423     if (pChannel)
1424     pChannel->showNormal();
1425     pChannel->setFocus();
1426     }
1427    
1428    
1429     //-------------------------------------------------------------------------
1430     // qsamplerMainForm -- Timer stuff.
1431    
1432     // Set the pseudo-timer delay schedule.
1433     void qsamplerMainForm::startSchedule ( int iStartDelay )
1434     {
1435     m_iStartDelay = 1 + (iStartDelay * 1000);
1436     m_iTimerDelay = 0;
1437     }
1438    
1439     // Suspend the pseudo-timer delay schedule.
1440     void qsamplerMainForm::stopSchedule (void)
1441     {
1442     m_iStartDelay = 0;
1443     m_iTimerDelay = 0;
1444     }
1445    
1446     // Timer slot funtion.
1447     void qsamplerMainForm::timerSlot (void)
1448     {
1449     if (m_pOptions == NULL)
1450     return;
1451    
1452     // Is it the first shot on server start after a few delay?
1453     if (m_iTimerDelay < m_iStartDelay) {
1454     m_iTimerDelay += QSAMPLER_TIMER_MSECS;
1455     if (m_iTimerDelay >= m_iStartDelay) {
1456     // If we cannot start it now, maybe a lil'mo'later ;)
1457     if (!startClient()) {
1458     m_iStartDelay += m_iTimerDelay;
1459     m_iTimerDelay = 0;
1460     }
1461     }
1462     }
1463    
1464     // Refresh each channel usage, on each period...
1465     if (m_pClient && m_pOptions->bAutoRefresh && m_pWorkspace->isUpdatesEnabled()) {
1466     m_iTimerSlot += QSAMPLER_TIMER_MSECS;
1467     if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime) {
1468     m_iTimerSlot = 0;
1469     QWidgetList wlist = m_pWorkspace->windowList();
1470     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1471     qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1472     if (pChannel->isVisible())
1473     pChannel->updateChannelUsage();
1474     }
1475     }
1476     }
1477    
1478     // Register the next timer slot.
1479     QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
1480     }
1481    
1482    
1483     //-------------------------------------------------------------------------
1484     // qsamplerMainForm -- Server stuff.
1485    
1486     // Start linuxsampler server...
1487     void qsamplerMainForm::startServer (void)
1488     {
1489     if (m_pOptions == NULL)
1490     return;
1491    
1492     // Aren't already a client, are we?
1493     if (!m_pOptions->bServerStart || m_pClient)
1494     return;
1495    
1496     // Is the server process instance still here?
1497     if (m_pServer) {
1498     switch (QMessageBox::warning(this, tr("Warning"),
1499     tr("Could not start the LinuxSampler server.\n\n"
1500     "Maybe it ss already started."),
1501     tr("Stop"), tr("Kill"), tr("Cancel"))) {
1502     case 0:
1503     m_pServer->tryTerminate();
1504     break;
1505     case 1:
1506     m_pServer->kill();
1507     break;
1508     }
1509     return;
1510     }
1511    
1512     // Reset our timer counters...
1513     stopSchedule();
1514    
1515     // OK. Let's build the startup process...
1516     m_pServer = new QProcess(this);
1517    
1518     // Setup stdout/stderr capture...
1519     //if (m_pOptions->bStdoutCapture) {
1520     m_pServer->setCommunication(QProcess::Stdout | QProcess::Stderr | QProcess::DupStderr);
1521     QObject::connect(m_pServer, SIGNAL(readyReadStdout()), this, SLOT(readServerStdout()));
1522     QObject::connect(m_pServer, SIGNAL(readyReadStderr()), this, SLOT(readServerStdout()));
1523     //}
1524     // The unforgiveable signal communication...
1525     QObject::connect(m_pServer, SIGNAL(processExited()), this, SLOT(processServerExit()));
1526    
1527     // Build process arguments...
1528     m_pServer->setArguments(QStringList::split(' ', m_pOptions->sServerCmdLine));
1529    
1530     appendMessages(tr("Server is starting..."));
1531     appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");
1532    
1533     // Go jack, go...
1534     if (!m_pServer->start()) {
1535     appendMessagesError(tr("Could not start server.\n\nSorry."));
1536     processServerExit();
1537     return;
1538     }
1539    
1540     // Show startup results...
1541     appendMessages(tr("Server was started with PID=%1.").arg((long) m_pServer->processIdentifier()));
1542    
1543     // Reset (yet again) the timer counters,
1544     // but this time is deferred as the user opted.
1545     startSchedule(m_pOptions->iStartDelay);
1546     stabilizeForm();
1547     }
1548    
1549    
1550     // Stop linuxsampler server...
1551     void qsamplerMainForm::stopServer (void)
1552     {
1553     // Stop client code.
1554     stopClient();
1555    
1556     // And try to stop server.
1557     if (m_pServer) {
1558     appendMessages(tr("Server is stopping..."));
1559 capela 122 if (m_pServer->isRunning())
1560 capela 109 m_pServer->tryTerminate();
1561     }
1562    
1563 capela 122 // Give it some time to terminate gracefully and stabilize...
1564     QTime t;
1565     t.start();
1566     while (t.elapsed() < QSAMPLER_TIMER_MSECS)
1567     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
1568    
1569 capela 109 // Do final processing anyway.
1570     processServerExit();
1571     }
1572    
1573    
1574     // Stdout handler...
1575     void qsamplerMainForm::readServerStdout (void)
1576     {
1577     if (m_pMessages)
1578     m_pMessages->appendStdoutBuffer(m_pServer->readStdout());
1579     }
1580    
1581    
1582     // Linuxsampler server cleanup.
1583     void qsamplerMainForm::processServerExit (void)
1584     {
1585     // Force client code cleanup.
1586     stopClient();
1587    
1588     // Flush anything that maybe pending...
1589     if (m_pMessages)
1590     m_pMessages->flushStdoutBuffer();
1591    
1592     if (m_pServer) {
1593     // Force final server shutdown...
1594     appendMessages(tr("Server was stopped with exit status %1.").arg(m_pServer->exitStatus()));
1595     if (!m_pServer->normalExit())
1596     m_pServer->kill();
1597     // Destroy it.
1598     delete m_pServer;
1599     m_pServer = NULL;
1600     }
1601    
1602     // Again, make status visible stable.
1603     stabilizeForm();
1604     }
1605    
1606    
1607     //-------------------------------------------------------------------------
1608     // qsamplerMainForm -- Client stuff.
1609    
1610     // The LSCP client callback procedure.
1611 capela 149 lscp_status_t qsampler_client_callback ( lscp_client_t */*pClient*/, lscp_event_t event, const char *pchData, int cchData, void *pvData )
1612 capela 109 {
1613 capela 149 qsamplerMainForm *pMainForm = (qsamplerMainForm *) pvData;
1614     if (pMainForm == NULL)
1615     return LSCP_FAILED;
1616    
1617     // ATTN: DO NOT EVER call any GUI code here,
1618 capela 145 // as this is run under some other thread context.
1619     // A custom event must be posted here...
1620 capela 149 QApplication::postEvent(pMainForm, new qsamplerCustomEvent(event, pchData, cchData));
1621 capela 109
1622     return LSCP_OK;
1623     }
1624    
1625    
1626     // Start our almighty client...
1627     bool qsamplerMainForm::startClient (void)
1628     {
1629     // Have it a setup?
1630     if (m_pOptions == NULL)
1631     return false;
1632    
1633     // Aren't we already started, are we?
1634     if (m_pClient)
1635     return true;
1636    
1637     // Log prepare here.
1638     appendMessages(tr("Client connecting..."));
1639    
1640     // Create the client handle...
1641     m_pClient = ::lscp_client_create(m_pOptions->sServerHost.latin1(), m_pOptions->iServerPort, qsampler_client_callback, this);
1642     if (m_pClient == NULL) {
1643     // Is this the first try?
1644     // maybe we need to start a local server...
1645     if ((m_pServer && m_pServer->isRunning()) || !m_pOptions->bServerStart)
1646     appendMessagesError(tr("Could not connect to server as client.\n\nSorry."));
1647     else
1648     startServer();
1649     // This is always a failure.
1650     stabilizeForm();
1651     return false;
1652     }
1653     // Just set receive timeout value, blindly.
1654     ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);
1655     appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));
1656    
1657     // We may stop scheduling around.
1658     stopSchedule();
1659    
1660     // We'll accept drops from now on...
1661     setAcceptDrops(true);
1662    
1663     // Log success here.
1664     appendMessages(tr("Client connected."));
1665    
1666     // Is any session pending to be loaded?
1667     if (!m_pOptions->sSessionFile.isEmpty()) {
1668     // Just load the prabably startup session...
1669     if (loadSessionFile(m_pOptions->sSessionFile)) {
1670     m_pOptions->sSessionFile = QString::null;
1671     return true;
1672     }
1673     }
1674    
1675     // Make a new session
1676     return newSession();
1677     }
1678    
1679    
1680     // Stop client...
1681     void qsamplerMainForm::stopClient (void)
1682     {
1683     if (m_pClient == NULL)
1684     return;
1685    
1686     // Log prepare here.
1687     appendMessages(tr("Client disconnecting..."));
1688    
1689     // Clear timer counters...
1690     stopSchedule();
1691    
1692     // We'll reject drops from now on...
1693     setAcceptDrops(false);
1694    
1695     // Force any channel strips around, but
1696     // but avoid removing the corresponding
1697     // channels from the back-end server.
1698     m_iDirtyCount = 0;
1699     closeSession(false);
1700    
1701     // Close us as a client...
1702     lscp_client_destroy(m_pClient);
1703     m_pClient = NULL;
1704    
1705     // Log final here.
1706     appendMessages(tr("Client disconnected."));
1707    
1708     // Make visible status.
1709     stabilizeForm();
1710     }
1711    
1712    
1713     // end of qsamplerMainForm.ui.h

  ViewVC Help
Powered by ViewVC