/[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 255 - (show annotations) (download) (as text)
Tue Sep 28 16:17:43 2004 UTC (19 years, 6 months ago) by capela
File MIME type: text/x-c++hdr
File size: 53004 byte(s)
* Sampler reset command action added to menu and toolbar.

* MIDI channel selection is now a dropdown list, allowing
  the explicit selection for "All" channels input per sampler
  channel (omni).

* Channel strip display glass effect has changed background
  color to black (was green).

* Minor configure fixes.

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

  ViewVC Help
Powered by ViewVC