/[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 295 - (hide annotations) (download) (as text)
Tue Nov 16 15:26:18 2004 UTC (19 years, 4 months ago) by capela
File MIME type: text/x-c++hdr
File size: 54717 byte(s)
* Sampler channels strips are just created if, and only if,
  the respective channel setup dialog is actually accepted,
  following common user-interface guidelines.

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

  ViewVC Help
Powered by ViewVC