/[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 296 - (hide annotations) (download) (as text)
Wed Nov 17 11:51:49 2004 UTC (19 years, 4 months ago) by capela
File MIME type: text/x-c++hdr
File size: 54685 byte(s)
Deferred channel info updates.

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     if (pChannelStrip && pChannelStrip->isVisible())
1511     pChannelStrip->updateChannelUsage();
1512 capela 109 }
1513     }
1514     }
1515    
1516     // Register the next timer slot.
1517     QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
1518     }
1519    
1520    
1521     //-------------------------------------------------------------------------
1522     // qsamplerMainForm -- Server stuff.
1523    
1524     // Start linuxsampler server...
1525     void qsamplerMainForm::startServer (void)
1526     {
1527     if (m_pOptions == NULL)
1528     return;
1529    
1530     // Aren't already a client, are we?
1531     if (!m_pOptions->bServerStart || m_pClient)
1532     return;
1533    
1534     // Is the server process instance still here?
1535     if (m_pServer) {
1536     switch (QMessageBox::warning(this, tr("Warning"),
1537     tr("Could not start the LinuxSampler server.\n\n"
1538     "Maybe it ss already started."),
1539     tr("Stop"), tr("Kill"), tr("Cancel"))) {
1540     case 0:
1541     m_pServer->tryTerminate();
1542     break;
1543     case 1:
1544     m_pServer->kill();
1545     break;
1546     }
1547     return;
1548     }
1549    
1550     // Reset our timer counters...
1551     stopSchedule();
1552    
1553     // OK. Let's build the startup process...
1554     m_pServer = new QProcess(this);
1555    
1556     // Setup stdout/stderr capture...
1557     //if (m_pOptions->bStdoutCapture) {
1558     m_pServer->setCommunication(QProcess::Stdout | QProcess::Stderr | QProcess::DupStderr);
1559     QObject::connect(m_pServer, SIGNAL(readyReadStdout()), this, SLOT(readServerStdout()));
1560     QObject::connect(m_pServer, SIGNAL(readyReadStderr()), this, SLOT(readServerStdout()));
1561     //}
1562     // The unforgiveable signal communication...
1563     QObject::connect(m_pServer, SIGNAL(processExited()), this, SLOT(processServerExit()));
1564    
1565     // Build process arguments...
1566     m_pServer->setArguments(QStringList::split(' ', m_pOptions->sServerCmdLine));
1567    
1568     appendMessages(tr("Server is starting..."));
1569     appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");
1570    
1571     // Go jack, go...
1572     if (!m_pServer->start()) {
1573     appendMessagesError(tr("Could not start server.\n\nSorry."));
1574     processServerExit();
1575     return;
1576     }
1577    
1578     // Show startup results...
1579     appendMessages(tr("Server was started with PID=%1.").arg((long) m_pServer->processIdentifier()));
1580    
1581     // Reset (yet again) the timer counters,
1582     // but this time is deferred as the user opted.
1583     startSchedule(m_pOptions->iStartDelay);
1584     stabilizeForm();
1585     }
1586    
1587    
1588     // Stop linuxsampler server...
1589     void qsamplerMainForm::stopServer (void)
1590     {
1591     // Stop client code.
1592     stopClient();
1593    
1594     // And try to stop server.
1595     if (m_pServer) {
1596     appendMessages(tr("Server is stopping..."));
1597 capela 122 if (m_pServer->isRunning())
1598 capela 109 m_pServer->tryTerminate();
1599     }
1600    
1601 capela 122 // Give it some time to terminate gracefully and stabilize...
1602     QTime t;
1603     t.start();
1604     while (t.elapsed() < QSAMPLER_TIMER_MSECS)
1605     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
1606    
1607 capela 109 // Do final processing anyway.
1608     processServerExit();
1609     }
1610    
1611    
1612     // Stdout handler...
1613     void qsamplerMainForm::readServerStdout (void)
1614     {
1615     if (m_pMessages)
1616     m_pMessages->appendStdoutBuffer(m_pServer->readStdout());
1617     }
1618    
1619    
1620     // Linuxsampler server cleanup.
1621     void qsamplerMainForm::processServerExit (void)
1622     {
1623     // Force client code cleanup.
1624     stopClient();
1625    
1626     // Flush anything that maybe pending...
1627     if (m_pMessages)
1628     m_pMessages->flushStdoutBuffer();
1629    
1630     if (m_pServer) {
1631     // Force final server shutdown...
1632     appendMessages(tr("Server was stopped with exit status %1.").arg(m_pServer->exitStatus()));
1633     if (!m_pServer->normalExit())
1634     m_pServer->kill();
1635     // Destroy it.
1636     delete m_pServer;
1637     m_pServer = NULL;
1638     }
1639    
1640     // Again, make status visible stable.
1641     stabilizeForm();
1642     }
1643    
1644    
1645     //-------------------------------------------------------------------------
1646     // qsamplerMainForm -- Client stuff.
1647    
1648     // The LSCP client callback procedure.
1649 capela 149 lscp_status_t qsampler_client_callback ( lscp_client_t */*pClient*/, lscp_event_t event, const char *pchData, int cchData, void *pvData )
1650 capela 109 {
1651 capela 149 qsamplerMainForm *pMainForm = (qsamplerMainForm *) pvData;
1652     if (pMainForm == NULL)
1653     return LSCP_FAILED;
1654    
1655     // ATTN: DO NOT EVER call any GUI code here,
1656 capela 145 // as this is run under some other thread context.
1657     // A custom event must be posted here...
1658 capela 149 QApplication::postEvent(pMainForm, new qsamplerCustomEvent(event, pchData, cchData));
1659 capela 109
1660     return LSCP_OK;
1661     }
1662    
1663    
1664     // Start our almighty client...
1665     bool qsamplerMainForm::startClient (void)
1666     {
1667     // Have it a setup?
1668     if (m_pOptions == NULL)
1669     return false;
1670    
1671     // Aren't we already started, are we?
1672     if (m_pClient)
1673     return true;
1674    
1675     // Log prepare here.
1676     appendMessages(tr("Client connecting..."));
1677    
1678     // Create the client handle...
1679     m_pClient = ::lscp_client_create(m_pOptions->sServerHost.latin1(), m_pOptions->iServerPort, qsampler_client_callback, this);
1680     if (m_pClient == NULL) {
1681     // Is this the first try?
1682     // maybe we need to start a local server...
1683     if ((m_pServer && m_pServer->isRunning()) || !m_pOptions->bServerStart)
1684     appendMessagesError(tr("Could not connect to server as client.\n\nSorry."));
1685     else
1686     startServer();
1687     // This is always a failure.
1688     stabilizeForm();
1689     return false;
1690     }
1691     // Just set receive timeout value, blindly.
1692     ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);
1693     appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));
1694    
1695     // We may stop scheduling around.
1696     stopSchedule();
1697    
1698     // We'll accept drops from now on...
1699     setAcceptDrops(true);
1700    
1701     // Log success here.
1702     appendMessages(tr("Client connected."));
1703    
1704     // Is any session pending to be loaded?
1705     if (!m_pOptions->sSessionFile.isEmpty()) {
1706     // Just load the prabably startup session...
1707     if (loadSessionFile(m_pOptions->sSessionFile)) {
1708     m_pOptions->sSessionFile = QString::null;
1709     return true;
1710     }
1711     }
1712    
1713     // Make a new session
1714     return newSession();
1715     }
1716    
1717    
1718     // Stop client...
1719     void qsamplerMainForm::stopClient (void)
1720     {
1721     if (m_pClient == NULL)
1722     return;
1723    
1724     // Log prepare here.
1725     appendMessages(tr("Client disconnecting..."));
1726    
1727     // Clear timer counters...
1728     stopSchedule();
1729    
1730     // We'll reject drops from now on...
1731     setAcceptDrops(false);
1732    
1733     // Force any channel strips around, but
1734     // but avoid removing the corresponding
1735     // channels from the back-end server.
1736     m_iDirtyCount = 0;
1737     closeSession(false);
1738    
1739     // Close us as a client...
1740     lscp_client_destroy(m_pClient);
1741     m_pClient = NULL;
1742    
1743     // Log final here.
1744     appendMessages(tr("Client disconnected."));
1745    
1746     // Make visible status.
1747     stabilizeForm();
1748     }
1749    
1750    
1751     // end of qsamplerMainForm.ui.h

  ViewVC Help
Powered by ViewVC