/[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 369 - (hide annotations) (download) (as text)
Fri Feb 11 13:30:21 2005 UTC (19 years, 1 month ago) by capela
File MIME type: text/x-c++hdr
File size: 55424 byte(s)
Fixed bug on session load, on lscp_list_channels() failure.

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

  ViewVC Help
Powered by ViewVC