/[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 265 - (hide annotations) (download) (as text)
Wed Sep 29 16:05:24 2004 UTC (19 years, 6 months ago) by capela
File MIME type: text/x-c++hdr
File size: 54324 byte(s)
Continued rewrite of sampler channel strips internal control structures.

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

  ViewVC Help
Powered by ViewVC