/[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 264 - (hide annotations) (download) (as text)
Wed Sep 29 13:12:45 2004 UTC (19 years, 6 months ago) by capela
File MIME type: text/x-c++hdr
File size: 54314 byte(s)
Initial rewrite of sampler channel strips internal control structures.

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

  ViewVC Help
Powered by ViewVC