/[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 297 - (hide annotations) (download) (as text)
Wed Nov 17 12:40:25 2004 UTC (19 years, 5 months ago) by capela
File MIME type: text/x-c++hdr
File size: 54817 byte(s)
Deferred channel info update fix.

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

  ViewVC Help
Powered by ViewVC