/[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 150 - (show annotations) (download) (as text)
Sat Jun 26 17:40:38 2004 UTC (19 years, 9 months ago) by capela
File MIME type: text/x-c++hdr
File size: 51908 byte(s)
* Save session filename quotes missing on LOAD INSTRUMENT NON_MODAL.

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

  ViewVC Help
Powered by ViewVC