/[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 382 - (hide annotations) (download) (as text)
Mon Feb 14 15:42:38 2005 UTC (19 years, 1 month ago) by capela
File MIME type: text/x-c++hdr
File size: 56451 byte(s)
* Added support for INSTRUMENT_NAME field from GET CHANNEL INFO command.

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

  ViewVC Help
Powered by ViewVC