/[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 382 - (show annotations) (download) (as text)
Mon Feb 14 15:42:38 2005 UTC (19 years, 1 month ago) by capela
File MIME type: text/x-c++hdr
File size: 56451 byte(s)
* Added support for INSTRUMENT_NAME field from GET CHANNEL INFO command.

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

  ViewVC Help
Powered by ViewVC