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

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

  ViewVC Help
Powered by ViewVC