/[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 341 - (hide annotations) (download) (as text)
Tue Jan 18 11:29:01 2005 UTC (19 years, 2 months ago) by capela
File MIME type: text/x-c++hdr
File size: 55856 byte(s)
* Actual instrument names are now optionally retrieved
  from the instrument file, even though libgig is available,
  avoiding excessively annoying load times while on the
  channel dialog, when huge instrument files are selected.

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

  ViewVC Help
Powered by ViewVC