/[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 301 - (hide annotations) (download) (as text)
Wed Nov 17 16:43:49 2004 UTC (19 years, 5 months ago) by capela
File MIME type: text/x-c++hdr
File size: 54938 byte(s)
Channel info update fix on session load.

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

  ViewVC Help
Powered by ViewVC