/[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 267 - (hide annotations) (download) (as text)
Wed Oct 6 15:42:59 2004 UTC (19 years, 6 months ago) by capela
File MIME type: text/x-c++hdr
File size: 55467 byte(s)
* Channel strip display glass effect is now an option.

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

  ViewVC Help
Powered by ViewVC