/[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 295 - (show annotations) (download) (as text)
Tue Nov 16 15:26:18 2004 UTC (19 years, 5 months ago) by capela
File MIME type: text/x-c++hdr
File size: 54717 byte(s)
* Sampler channels strips are just created if, and only if,
  the respective channel setup dialog is actually accepted,
  following common user-interface guidelines.

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

  ViewVC Help
Powered by ViewVC