/[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 255 - (hide annotations) (download) (as text)
Tue Sep 28 16:17:43 2004 UTC (19 years, 6 months ago) by capela
File MIME type: text/x-c++hdr
File size: 53004 byte(s)
* Sampler reset command action added to menu and toolbar.

* MIDI channel selection is now a dropdown list, allowing
  the explicit selection for "All" channels input per sampler
  channel (omni).

* Channel strip display glass effect has changed background
  color to black (was green).

* Minor configure fixes.

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

  ViewVC Help
Powered by ViewVC