/[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 304 - (hide annotations) (download) (as text)
Fri Nov 19 11:55:18 2004 UTC (19 years, 4 months ago) by capela
File MIME type: text/x-c++hdr
File size: 55277 byte(s)
Fixed ALL MIDI channel setting of session save.

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

  ViewVC Help
Powered by ViewVC