/[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 303 - (show annotations) (download) (as text)
Fri Nov 19 10:18:59 2004 UTC (19 years, 4 months ago) by capela
File MIME type: text/x-c++hdr
File size: 55257 byte(s)
* Sampler channel is now completely detached from UI strip class.

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

  ViewVC Help
Powered by ViewVC