/[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 371 - (hide annotations) (download) (as text)
Fri Feb 11 15:36:06 2005 UTC (19 years, 2 months ago) by capela
File MIME type: text/x-c++hdr
File size: 56262 byte(s)
Instrument names display mode update on all channels.

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

  ViewVC Help
Powered by ViewVC