/[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 127 - (hide annotations) (download) (as text)
Mon Jun 14 21:05:20 2004 UTC (19 years, 9 months ago) by capela
File MIME type: text/x-c++hdr
File size: 50720 byte(s)
* The channel context menu is also accessible by right-clicking
  over the empty workspace area.

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

  ViewVC Help
Powered by ViewVC