/[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 298 - (hide annotations) (download) (as text)
Wed Nov 17 13:05:42 2004 UTC (19 years, 5 months ago) by capela
File MIME type: text/x-c++hdr
File size: 54875 byte(s)
Deferred channel info update fixed again.

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

  ViewVC Help
Powered by ViewVC