/[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 341 - (show annotations) (download) (as text)
Tue Jan 18 11:29:01 2005 UTC (19 years, 3 months ago) by capela
File MIME type: text/x-c++hdr
File size: 55856 byte(s)
* Actual instrument names are now optionally retrieved
  from the instrument file, even though libgig is available,
  avoiding excessively annoying load times while on the
  channel dialog, when huge instrument files are selected.

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

  ViewVC Help
Powered by ViewVC