/[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 301 - (show annotations) (download) (as text)
Wed Nov 17 16:43:49 2004 UTC (19 years, 4 months ago) by capela
File MIME type: text/x-c++hdr
File size: 54938 byte(s)
Channel info update fix on session load.

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 iChannels = ::lscp_get_channels(m_pClient);
548 if (iChannels < 0) {
549 appendMessagesClient("lscp_get_channels");
550 appendMessagesError(tr("Could not get current number of channels.\n\nSorry."));
551 }
552
553 // Try to (re)create each channel.
554 m_pWorkspace->setUpdatesEnabled(false);
555 for (int iChannelID = 0; iChannelID < iChannels; iChannelID++) {
556 createChannelStrip(iChannelID);
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 strip,
775 // by giving an invalid channel id.
776 createChannelStrip(-1);
777 }
778
779
780 // Remove current sampler channel.
781 void qsamplerMainForm::editRemoveChannel (void)
782 {
783 if (m_pClient == NULL)
784 return;
785
786 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
787 if (pChannelStrip == NULL)
788 return;
789
790 qsamplerChannel *pChannel = pChannelStrip->channel();
791 if (pChannel == NULL)
792 return;
793
794 // Prompt user if he/she's sure about this...
795 if (m_pOptions && m_pOptions->bConfirmRemove) {
796 if (QMessageBox::warning(this, tr("Warning"),
797 tr("About to remove channel:\n\n"
798 "%1\n\n"
799 "Are you sure?")
800 .arg(pChannelStrip->caption()),
801 tr("OK"), tr("Cancel")) > 0)
802 return;
803 }
804
805 // Remove the existing sampler channel.
806 if (!pChannel->removeChannel())
807 return;
808
809 // Just delete the channel strip.
810 delete pChannelStrip;
811
812 // Do we auto-arrange?
813 if (m_pOptions && m_pOptions->bAutoArrange)
814 channelsArrange();
815
816 // We'll be dirty, for sure...
817 m_iDirtyCount++;
818 stabilizeForm();
819 }
820
821
822 // Setup current sampler channel.
823 void qsamplerMainForm::editSetupChannel (void)
824 {
825 if (m_pClient == NULL)
826 return;
827
828 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
829 if (pChannelStrip == NULL)
830 return;
831
832 // Just invoque the channel strip procedure.
833 pChannelStrip->channelSetup();
834 }
835
836
837 // Reset current sampler channel.
838 void qsamplerMainForm::editResetChannel (void)
839 {
840 if (m_pClient == NULL)
841 return;
842
843 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
844 if (pChannelStrip == NULL)
845 return;
846
847 qsamplerChannel *pChannel = pChannelStrip->channel();
848 if (pChannel == NULL)
849 return;
850
851 // Reset the existing sampler channel.
852 pChannel->resetChannel();
853
854 // Refresh channel strip info.
855 pChannelStrip->updateChannelInfo();
856 // And force a deferred update.
857 m_iChangeCount++;
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 // Flag that we're update those channel strips.
1146 m_iChangeCount++;
1147 // Just mark the dirty form.
1148 m_iDirtyCount++;
1149 // and update the form status...
1150 stabilizeForm();
1151 }
1152
1153
1154 // Update the recent files list and menu.
1155 void qsamplerMainForm::updateRecentFiles ( const QString& sFilename )
1156 {
1157 if (m_pOptions == NULL)
1158 return;
1159
1160 // Remove from list if already there (avoid duplicates)
1161 QStringList::Iterator iter = m_pOptions->recentFiles.find(sFilename);
1162 if (iter != m_pOptions->recentFiles.end())
1163 m_pOptions->recentFiles.remove(iter);
1164 // Put it to front...
1165 m_pOptions->recentFiles.push_front(sFilename);
1166
1167 // May update the menu.
1168 updateRecentFilesMenu();
1169 }
1170
1171
1172 // Update the recent files list and menu.
1173 void qsamplerMainForm::updateRecentFilesMenu (void)
1174 {
1175 if (m_pOptions == NULL)
1176 return;
1177
1178 // Time to keep the list under limits.
1179 int iRecentFiles = m_pOptions->recentFiles.count();
1180 while (iRecentFiles > m_pOptions->iMaxRecentFiles) {
1181 m_pOptions->recentFiles.pop_back();
1182 iRecentFiles--;
1183 }
1184
1185 // rebuild the recent files menu...
1186 m_pRecentFilesMenu->clear();
1187 for (int i = 0; i < iRecentFiles; i++) {
1188 const QString& sFilename = m_pOptions->recentFiles[i];
1189 if (QFileInfo(sFilename).exists()) {
1190 m_pRecentFilesMenu->insertItem(QString("&%1 %2")
1191 .arg(i + 1).arg(sessionName(sFilename)),
1192 this, SLOT(fileOpenRecent(int)), 0, i);
1193 }
1194 }
1195 }
1196
1197
1198 // Force update of the channels display font.
1199 void qsamplerMainForm::updateDisplayFont (void)
1200 {
1201 if (m_pOptions == NULL)
1202 return;
1203
1204 // Check if display font is legal.
1205 if (m_pOptions->sDisplayFont.isEmpty())
1206 return;
1207 // Realize it.
1208 QFont font;
1209 if (!font.fromString(m_pOptions->sDisplayFont))
1210 return;
1211
1212 // Full channel list update...
1213 QWidgetList wlist = m_pWorkspace->windowList();
1214 if (wlist.isEmpty())
1215 return;
1216
1217 m_pWorkspace->setUpdatesEnabled(false);
1218 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1219 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1220 if (pChannelStrip)
1221 pChannelStrip->setDisplayFont(font);
1222 }
1223 m_pWorkspace->setUpdatesEnabled(true);
1224 }
1225
1226
1227 // Update channel strips background effect.
1228 void qsamplerMainForm::updateDisplayEffect (void)
1229 {
1230 QPixmap pm;
1231 if (m_pOptions->bDisplayEffect)
1232 pm = QPixmap::fromMimeSource("displaybg1.png");
1233
1234 // Full channel list update...
1235 QWidgetList wlist = m_pWorkspace->windowList();
1236 if (wlist.isEmpty())
1237 return;
1238
1239 m_pWorkspace->setUpdatesEnabled(false);
1240 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1241 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1242 if (pChannelStrip)
1243 pChannelStrip->setDisplayBackground(pm);
1244 }
1245 m_pWorkspace->setUpdatesEnabled(true);
1246 }
1247
1248
1249 // Force update of the channels maximum volume setting.
1250 void qsamplerMainForm::updateMaxVolume (void)
1251 {
1252 if (m_pOptions == NULL)
1253 return;
1254
1255 // Full channel list update...
1256 QWidgetList wlist = m_pWorkspace->windowList();
1257 if (wlist.isEmpty())
1258 return;
1259
1260 m_pWorkspace->setUpdatesEnabled(false);
1261 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1262 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1263 if (pChannelStrip)
1264 pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
1265 }
1266 m_pWorkspace->setUpdatesEnabled(true);
1267 }
1268
1269
1270 //-------------------------------------------------------------------------
1271 // qsamplerMainForm -- Messages window form handlers.
1272
1273 // Messages output methods.
1274 void qsamplerMainForm::appendMessages( const QString& s )
1275 {
1276 if (m_pMessages)
1277 m_pMessages->appendMessages(s);
1278
1279 statusBar()->message(s, 3000);
1280 }
1281
1282 void qsamplerMainForm::appendMessagesColor( const QString& s, const QString& c )
1283 {
1284 if (m_pMessages)
1285 m_pMessages->appendMessagesColor(s, c);
1286
1287 statusBar()->message(s, 3000);
1288 }
1289
1290 void qsamplerMainForm::appendMessagesText( const QString& s )
1291 {
1292 if (m_pMessages)
1293 m_pMessages->appendMessagesText(s);
1294 }
1295
1296 void qsamplerMainForm::appendMessagesError( const QString& s )
1297 {
1298 if (m_pMessages)
1299 m_pMessages->show();
1300
1301 appendMessagesColor(s.simplifyWhiteSpace(), "#ff0000");
1302
1303 QMessageBox::critical(this, tr("Error"), s, tr("Cancel"));
1304 }
1305
1306
1307 // This is a special message format, just for client results.
1308 void qsamplerMainForm::appendMessagesClient( const QString& s )
1309 {
1310 if (m_pClient == NULL)
1311 return;
1312
1313 appendMessagesColor(s + QString(": %1 (errno=%2)")
1314 .arg(::lscp_client_get_result(m_pClient))
1315 .arg(::lscp_client_get_errno(m_pClient)), "#996666");
1316 }
1317
1318
1319 // Force update of the messages font.
1320 void qsamplerMainForm::updateMessagesFont (void)
1321 {
1322 if (m_pOptions == NULL)
1323 return;
1324
1325 if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {
1326 QFont font;
1327 if (font.fromString(m_pOptions->sMessagesFont))
1328 m_pMessages->setMessagesFont(font);
1329 }
1330 }
1331
1332
1333 // Update messages window line limit.
1334 void qsamplerMainForm::updateMessagesLimit (void)
1335 {
1336 if (m_pOptions == NULL)
1337 return;
1338
1339 if (m_pMessages) {
1340 if (m_pOptions->bMessagesLimit)
1341 m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);
1342 else
1343 m_pMessages->setMessagesLimit(0);
1344 }
1345 }
1346
1347
1348 // Enablement of the messages capture feature.
1349 void qsamplerMainForm::updateMessagesCapture (void)
1350 {
1351 if (m_pOptions == NULL)
1352 return;
1353
1354 if (m_pMessages)
1355 m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);
1356 }
1357
1358
1359 //-------------------------------------------------------------------------
1360 // qsamplerMainForm -- MDI channel strip management.
1361
1362 // The channel strip creation executive.
1363 qsamplerChannelStrip *qsamplerMainForm::createChannelStrip ( int iChannelID )
1364 {
1365 if (m_pClient == NULL)
1366 return NULL;
1367
1368 // Prepare for auto-arrange?
1369 qsamplerChannelStrip *pChannelStrip = NULL;
1370 int y = 0;
1371 if (m_pOptions && m_pOptions->bAutoArrange) {
1372 QWidgetList wlist = m_pWorkspace->windowList();
1373 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1374 pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1375 // y += pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();
1376 y += pChannelStrip->parentWidget()->frameGeometry().height();
1377 }
1378 }
1379
1380 // Add a new channel itema...
1381 WFlags wflags = Qt::WStyle_Customize | Qt::WStyle_Tool | Qt::WStyle_Title | Qt::WStyle_NoBorder;
1382 pChannelStrip = new qsamplerChannelStrip(m_pWorkspace, 0, wflags);
1383 // Actual channel setup.
1384 pChannelStrip->setup(this, iChannelID);
1385 QObject::connect(pChannelStrip, SIGNAL(channelChanged(qsamplerChannelStrip *)), this, SLOT(channelStripChanged(qsamplerChannelStrip *)));
1386 // Before we show it up, may be we'll
1387 // better ask for some initial values?
1388 if (iChannelID < 0 && !pChannelStrip->channelSetup()) {
1389 // No luck, bail out...
1390 delete pChannelStrip;
1391 return NULL;
1392 }
1393
1394 // Set some initial aesthetic options...
1395 if (m_pOptions) {
1396 // Background display effect...
1397 pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
1398 // We'll need a display font.
1399 QFont font;
1400 if (font.fromString(m_pOptions->sDisplayFont))
1401 pChannelStrip->setDisplayFont(font);
1402 // Maximum allowed volume setting.
1403 pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
1404 }
1405
1406 // Now we show up us to the world.
1407 pChannelStrip->show();
1408 // Only then, we'll auto-arrange...
1409 if (m_pOptions && m_pOptions->bAutoArrange) {
1410 int iWidth = m_pWorkspace->width();
1411 // int iHeight = pChannel->height() + pChannel->parentWidget()->baseSize().height();
1412 int iHeight = pChannelStrip->parentWidget()->frameGeometry().height();
1413 pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1414 }
1415
1416 // Return our successful reference...
1417 return pChannelStrip;
1418 }
1419
1420
1421 // Retrieve the active channel strip.
1422 qsamplerChannelStrip *qsamplerMainForm::activeChannelStrip (void)
1423 {
1424 return (qsamplerChannelStrip *) m_pWorkspace->activeWindow();
1425 }
1426
1427
1428 // Retrieve a channel strip by index.
1429 qsamplerChannelStrip *qsamplerMainForm::channelStripAt ( int iChannel )
1430 {
1431 QWidgetList wlist = m_pWorkspace->windowList();
1432 if (wlist.isEmpty())
1433 return 0;
1434
1435 return (qsamplerChannelStrip *) wlist.at(iChannel);
1436 }
1437
1438
1439 // Construct the windows menu.
1440 void qsamplerMainForm::channelsMenuAboutToShow (void)
1441 {
1442 channelsMenu->clear();
1443 channelsArrangeAction->addTo(channelsMenu);
1444 channelsAutoArrangeAction->addTo(channelsMenu);
1445
1446 QWidgetList wlist = m_pWorkspace->windowList();
1447 if (!wlist.isEmpty()) {
1448 channelsMenu->insertSeparator();
1449 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1450 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1451 if (pChannelStrip) {
1452 int iItemID = channelsMenu->insertItem(pChannelStrip->caption(), this, SLOT(channelsMenuActivated(int)));
1453 channelsMenu->setItemParameter(iItemID, iChannel);
1454 channelsMenu->setItemChecked(iItemID, activeChannelStrip() == pChannelStrip);
1455 }
1456 }
1457 }
1458 }
1459
1460
1461 // Windows menu activation slot
1462 void qsamplerMainForm::channelsMenuActivated ( int iChannel )
1463 {
1464 qsamplerChannelStrip *pChannelStrip = channelStripAt(iChannel);
1465 if (pChannelStrip)
1466 pChannelStrip->showNormal();
1467 pChannelStrip->setFocus();
1468 }
1469
1470
1471 //-------------------------------------------------------------------------
1472 // qsamplerMainForm -- Timer stuff.
1473
1474 // Set the pseudo-timer delay schedule.
1475 void qsamplerMainForm::startSchedule ( int iStartDelay )
1476 {
1477 m_iStartDelay = 1 + (iStartDelay * 1000);
1478 m_iTimerDelay = 0;
1479 }
1480
1481 // Suspend the pseudo-timer delay schedule.
1482 void qsamplerMainForm::stopSchedule (void)
1483 {
1484 m_iStartDelay = 0;
1485 m_iTimerDelay = 0;
1486 }
1487
1488 // Timer slot funtion.
1489 void qsamplerMainForm::timerSlot (void)
1490 {
1491 if (m_pOptions == NULL)
1492 return;
1493
1494 // Is it the first shot on server start after a few delay?
1495 if (m_iTimerDelay < m_iStartDelay) {
1496 m_iTimerDelay += QSAMPLER_TIMER_MSECS;
1497 if (m_iTimerDelay >= m_iStartDelay) {
1498 // If we cannot start it now, maybe a lil'mo'later ;)
1499 if (!startClient()) {
1500 m_iStartDelay += m_iTimerDelay;
1501 m_iTimerDelay = 0;
1502 }
1503 }
1504 }
1505
1506 // Refresh each channel usage, on each period...
1507 if (m_pClient && (m_iChangeCount > 0 || m_pOptions->bAutoRefresh)) {
1508 m_iTimerSlot += QSAMPLER_TIMER_MSECS;
1509 if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime && m_pWorkspace->isUpdatesEnabled()) {
1510 m_iTimerSlot = 0;
1511 m_iChangeCount = 0;
1512 QWidgetList wlist = m_pWorkspace->windowList();
1513 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1514 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1515 if (pChannelStrip && pChannelStrip->isVisible()) {
1516 // If we can't make it clean, try next time.
1517 if (!pChannelStrip->updateChannelUsage())
1518 m_iChangeCount++;
1519 }
1520 }
1521 }
1522 }
1523
1524 // Register the next timer slot.
1525 QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
1526 }
1527
1528
1529 //-------------------------------------------------------------------------
1530 // qsamplerMainForm -- Server stuff.
1531
1532 // Start linuxsampler server...
1533 void qsamplerMainForm::startServer (void)
1534 {
1535 if (m_pOptions == NULL)
1536 return;
1537
1538 // Aren't already a client, are we?
1539 if (!m_pOptions->bServerStart || m_pClient)
1540 return;
1541
1542 // Is the server process instance still here?
1543 if (m_pServer) {
1544 switch (QMessageBox::warning(this, tr("Warning"),
1545 tr("Could not start the LinuxSampler server.\n\n"
1546 "Maybe it ss already started."),
1547 tr("Stop"), tr("Kill"), tr("Cancel"))) {
1548 case 0:
1549 m_pServer->tryTerminate();
1550 break;
1551 case 1:
1552 m_pServer->kill();
1553 break;
1554 }
1555 return;
1556 }
1557
1558 // Reset our timer counters...
1559 stopSchedule();
1560
1561 // OK. Let's build the startup process...
1562 m_pServer = new QProcess(this);
1563
1564 // Setup stdout/stderr capture...
1565 //if (m_pOptions->bStdoutCapture) {
1566 m_pServer->setCommunication(QProcess::Stdout | QProcess::Stderr | QProcess::DupStderr);
1567 QObject::connect(m_pServer, SIGNAL(readyReadStdout()), this, SLOT(readServerStdout()));
1568 QObject::connect(m_pServer, SIGNAL(readyReadStderr()), this, SLOT(readServerStdout()));
1569 //}
1570 // The unforgiveable signal communication...
1571 QObject::connect(m_pServer, SIGNAL(processExited()), this, SLOT(processServerExit()));
1572
1573 // Build process arguments...
1574 m_pServer->setArguments(QStringList::split(' ', m_pOptions->sServerCmdLine));
1575
1576 appendMessages(tr("Server is starting..."));
1577 appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");
1578
1579 // Go jack, go...
1580 if (!m_pServer->start()) {
1581 appendMessagesError(tr("Could not start server.\n\nSorry."));
1582 processServerExit();
1583 return;
1584 }
1585
1586 // Show startup results...
1587 appendMessages(tr("Server was started with PID=%1.").arg((long) m_pServer->processIdentifier()));
1588
1589 // Reset (yet again) the timer counters,
1590 // but this time is deferred as the user opted.
1591 startSchedule(m_pOptions->iStartDelay);
1592 stabilizeForm();
1593 }
1594
1595
1596 // Stop linuxsampler server...
1597 void qsamplerMainForm::stopServer (void)
1598 {
1599 // Stop client code.
1600 stopClient();
1601
1602 // And try to stop server.
1603 if (m_pServer) {
1604 appendMessages(tr("Server is stopping..."));
1605 if (m_pServer->isRunning())
1606 m_pServer->tryTerminate();
1607 }
1608
1609 // Give it some time to terminate gracefully and stabilize...
1610 QTime t;
1611 t.start();
1612 while (t.elapsed() < QSAMPLER_TIMER_MSECS)
1613 QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
1614
1615 // Do final processing anyway.
1616 processServerExit();
1617 }
1618
1619
1620 // Stdout handler...
1621 void qsamplerMainForm::readServerStdout (void)
1622 {
1623 if (m_pMessages)
1624 m_pMessages->appendStdoutBuffer(m_pServer->readStdout());
1625 }
1626
1627
1628 // Linuxsampler server cleanup.
1629 void qsamplerMainForm::processServerExit (void)
1630 {
1631 // Force client code cleanup.
1632 stopClient();
1633
1634 // Flush anything that maybe pending...
1635 if (m_pMessages)
1636 m_pMessages->flushStdoutBuffer();
1637
1638 if (m_pServer) {
1639 // Force final server shutdown...
1640 appendMessages(tr("Server was stopped with exit status %1.").arg(m_pServer->exitStatus()));
1641 if (!m_pServer->normalExit())
1642 m_pServer->kill();
1643 // Destroy it.
1644 delete m_pServer;
1645 m_pServer = NULL;
1646 }
1647
1648 // Again, make status visible stable.
1649 stabilizeForm();
1650 }
1651
1652
1653 //-------------------------------------------------------------------------
1654 // qsamplerMainForm -- Client stuff.
1655
1656 // The LSCP client callback procedure.
1657 lscp_status_t qsampler_client_callback ( lscp_client_t */*pClient*/, lscp_event_t event, const char *pchData, int cchData, void *pvData )
1658 {
1659 qsamplerMainForm *pMainForm = (qsamplerMainForm *) pvData;
1660 if (pMainForm == NULL)
1661 return LSCP_FAILED;
1662
1663 // ATTN: DO NOT EVER call any GUI code here,
1664 // as this is run under some other thread context.
1665 // A custom event must be posted here...
1666 QApplication::postEvent(pMainForm, new qsamplerCustomEvent(event, pchData, cchData));
1667
1668 return LSCP_OK;
1669 }
1670
1671
1672 // Start our almighty client...
1673 bool qsamplerMainForm::startClient (void)
1674 {
1675 // Have it a setup?
1676 if (m_pOptions == NULL)
1677 return false;
1678
1679 // Aren't we already started, are we?
1680 if (m_pClient)
1681 return true;
1682
1683 // Log prepare here.
1684 appendMessages(tr("Client connecting..."));
1685
1686 // Create the client handle...
1687 m_pClient = ::lscp_client_create(m_pOptions->sServerHost.latin1(), m_pOptions->iServerPort, qsampler_client_callback, this);
1688 if (m_pClient == NULL) {
1689 // Is this the first try?
1690 // maybe we need to start a local server...
1691 if ((m_pServer && m_pServer->isRunning()) || !m_pOptions->bServerStart)
1692 appendMessagesError(tr("Could not connect to server as client.\n\nSorry."));
1693 else
1694 startServer();
1695 // This is always a failure.
1696 stabilizeForm();
1697 return false;
1698 }
1699 // Just set receive timeout value, blindly.
1700 ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);
1701 appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));
1702
1703 // We may stop scheduling around.
1704 stopSchedule();
1705
1706 // We'll accept drops from now on...
1707 setAcceptDrops(true);
1708
1709 // Log success here.
1710 appendMessages(tr("Client connected."));
1711
1712 // Is any session pending to be loaded?
1713 if (!m_pOptions->sSessionFile.isEmpty()) {
1714 // Just load the prabably startup session...
1715 if (loadSessionFile(m_pOptions->sSessionFile)) {
1716 m_pOptions->sSessionFile = QString::null;
1717 return true;
1718 }
1719 }
1720
1721 // Make a new session
1722 return newSession();
1723 }
1724
1725
1726 // Stop client...
1727 void qsamplerMainForm::stopClient (void)
1728 {
1729 if (m_pClient == NULL)
1730 return;
1731
1732 // Log prepare here.
1733 appendMessages(tr("Client disconnecting..."));
1734
1735 // Clear timer counters...
1736 stopSchedule();
1737
1738 // We'll reject drops from now on...
1739 setAcceptDrops(false);
1740
1741 // Force any channel strips around, but
1742 // but avoid removing the corresponding
1743 // channels from the back-end server.
1744 m_iDirtyCount = 0;
1745 closeSession(false);
1746
1747 // Close us as a client...
1748 lscp_client_destroy(m_pClient);
1749 m_pClient = NULL;
1750
1751 // Log final here.
1752 appendMessages(tr("Client disconnected."));
1753
1754 // Make visible status.
1755 stabilizeForm();
1756 }
1757
1758
1759 // end of qsamplerMainForm.ui.h

  ViewVC Help
Powered by ViewVC