/[svn]/qsampler/trunk/src/qsamplerMainForm.ui.h
ViewVC logotype

Contents of /qsampler/trunk/src/qsamplerMainForm.ui.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 456 - (show annotations) (download) (as text)
Mon Mar 14 14:02:30 2005 UTC (19 years ago) by capela
File MIME type: text/x-c++hdr
File size: 64110 byte(s)
Device configuration is now included and saved on session files (ufix).

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

  ViewVC Help
Powered by ViewVC