/[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 388 - (hide annotations) (download) (as text)
Thu Feb 17 17:27:59 2005 UTC (19 years, 1 month ago) by capela
File MIME type: text/x-c++hdr
File size: 57626 byte(s)
* Drag-and-drop of either session files (LSCP scripts) or
  instrument files (GIG) are now supported. Multiple files
  drop is allowed, but it only makes sense for instrument
  files, each one prompting to create a new sampler channel.

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

  ViewVC Help
Powered by ViewVC