/[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 297 - (show annotations) (download) (as text)
Wed Nov 17 12:40:25 2004 UTC (19 years, 4 months ago) by capela
File MIME type: text/x-c++hdr
File size: 54817 byte(s)
Deferred channel info update fix.

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 stabilizeForm();
571 return true;
572 }
573
574
575 // Save current session to specific file path.
576 bool qsamplerMainForm::saveSessionFile ( const QString& sFilename )
577 {
578 // Open and write into real file.
579 QFile file(sFilename);
580 if (!file.open(IO_WriteOnly | IO_Truncate)) {
581 appendMessagesError(tr("Could not open \"%1\" session file.\n\nSorry.").arg(sFilename));
582 return false;
583 }
584
585 // Write the file.
586 int iErrors = 0;
587 QTextStream ts(&file);
588 ts << "# " << QSAMPLER_TITLE " - " << tr(QSAMPLER_SUBTITLE) << endl;
589 ts << "# " << tr("Version")
590 << ": " QSAMPLER_VERSION << endl;
591 ts << "# " << tr("Build")
592 << ": " __DATE__ " " __TIME__ << endl;
593 ts << "#" << endl;
594 ts << "# " << tr("File")
595 << ": " << QFileInfo(sFilename).fileName() << endl;
596 ts << "# " << tr("Date")
597 << ": " << QDate::currentDate().toString("MMMM dd yyyy")
598 << " " << QTime::currentTime().toString("hh:mm:ss") << endl;
599 ts << "#" << endl;
600 ts << endl;
601 QWidgetList wlist = m_pWorkspace->windowList();
602 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
603 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
604 if (pChannelStrip) {
605 qsamplerChannel *pChannel = pChannelStrip->channel();
606 if (pChannel) {
607 int iChannelID = pChannel->channelID();
608 ts << "# " << pChannelStrip->caption() << endl;
609 ts << "ADD CHANNEL" << endl;
610 ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannelID << " " << pChannel->audioDriver() << endl;
611 ts << "SET CHANNEL MIDI_INPUT_TYPE " << iChannelID << " " << pChannel->midiDriver() << endl;
612 ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannelID << " " << pChannel->midiPort() << endl;
613 ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannelID << " ";
614 if (pChannel->midiChannel() > 0)
615 ts << pChannel->midiChannel();
616 else
617 ts << "ALL";
618 ts << endl;
619 ts << "LOAD ENGINE " << pChannel->engineName() << " " << iChannelID << endl;
620 ts << "LOAD INSTRUMENT NON_MODAL '" << pChannel->instrumentFile() << "' " << pChannel->instrumentNr() << " " << iChannelID << endl;
621 ts << "SET CHANNEL VOLUME " << iChannelID << " " << pChannel->volume() << endl;
622 ts << endl;
623 }
624 }
625 // Try to keep it snappy :)
626 QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
627 }
628
629 // Ok. we've wrote it.
630 file.close();
631
632 // Have we any errors?
633 if (iErrors > 0)
634 appendMessagesError(tr("Some settings could not be saved\nto \"%1\" session file.\n\nSorry.").arg(sFilename));
635
636 // Save as default session directory.
637 if (m_pOptions)
638 m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);
639 // We're not dirty anymore.
640 m_iDirtyCount = 0;
641 // Stabilize form...
642 m_sFilename = sFilename;
643 updateRecentFiles(sFilename);
644 appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename)));
645 stabilizeForm();
646 return true;
647 }
648
649
650 //-------------------------------------------------------------------------
651 // qsamplerMainForm -- File Action slots.
652
653 // Create a new sampler session.
654 void qsamplerMainForm::fileNew (void)
655 {
656 // Of course we'll start clean new.
657 newSession();
658 }
659
660
661 // Open an existing sampler session.
662 void qsamplerMainForm::fileOpen (void)
663 {
664 // Open it right away.
665 openSession();
666 }
667
668
669 // Open a recent file session.
670 void qsamplerMainForm::fileOpenRecent ( int iIndex )
671 {
672 // Check if we can safely close the current session...
673 if (m_pOptions && closeSession(true)) {
674 QString sFilename = m_pOptions->recentFiles[iIndex];
675 loadSessionFile(sFilename);
676 }
677 }
678
679
680 // Save current sampler session.
681 void qsamplerMainForm::fileSave (void)
682 {
683 // Save it right away.
684 saveSession(false);
685 }
686
687
688 // Save current sampler session with another name.
689 void qsamplerMainForm::fileSaveAs (void)
690 {
691 // Save it right away, maybe with another name.
692 saveSession(true);
693 }
694
695
696 // Reset the sampler instance.
697 void qsamplerMainForm::fileReset (void)
698 {
699 if (m_pClient == NULL)
700 return;
701
702 // Ask user whether he/she want's an internal sampler reset...
703 if (QMessageBox::warning(this, tr("Warning"),
704 tr("Resetting the sampler instance will close\n"
705 "all device and channel configurations.\n\n"
706 "Please note that this operation may cause\n"
707 "temporary MIDI and Audio disruption\n\n"
708 "Do you want to reset the sampler engine now?"),
709 tr("Reset"), tr("Cancel")) > 0)
710 return;
711
712 // Just do the reset, after closing down current session...
713 if (closeSession(true) && ::lscp_reset_sampler(m_pClient) != LSCP_OK) {
714 appendMessagesClient("lscp_reset_sampler");
715 appendMessagesError(tr("Could not reset sampler instance.\n\nSorry."));
716 return;
717 }
718
719 // Log this.
720 appendMessages(tr("Sampler reset."));
721 }
722
723
724 // Restart the client/server instance.
725 void qsamplerMainForm::fileRestart (void)
726 {
727 if (m_pOptions == NULL)
728 return;
729
730 bool bRestart = true;
731
732 // Ask user whether he/she want's a complete restart...
733 // (if we're currently up and running)
734 if (bRestart && m_pClient) {
735 bRestart = (QMessageBox::warning(this, tr("Warning"),
736 tr("New settings will be effective after\n"
737 "restarting the client/server connection.\n\n"
738 "Please note that this operation may cause\n"
739 "temporary MIDI and Audio disruption\n\n"
740 "Do you want to restart the connection now?"),
741 tr("Restart"), tr("Cancel")) == 0);
742 }
743
744 // Are we still for it?
745 if (bRestart && closeSession(true)) {
746 // Stop server, it will force the client too.
747 stopServer();
748 // Reschedule a restart...
749 startSchedule(m_pOptions->iStartDelay);
750 }
751 }
752
753
754 // Exit application program.
755 void qsamplerMainForm::fileExit (void)
756 {
757 // Go for close the whole thing.
758 close();
759 }
760
761
762 //-------------------------------------------------------------------------
763 // qsamplerMainForm -- Edit Action slots.
764
765 // Add a new sampler channel.
766 void qsamplerMainForm::editAddChannel (void)
767 {
768 if (m_pClient == NULL)
769 return;
770
771 // Just create the channel strip,
772 // by giving an invalid channel id.
773 createChannelStrip(-1);
774 }
775
776
777 // Remove current sampler channel.
778 void qsamplerMainForm::editRemoveChannel (void)
779 {
780 if (m_pClient == NULL)
781 return;
782
783 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
784 if (pChannelStrip == NULL)
785 return;
786
787 qsamplerChannel *pChannel = pChannelStrip->channel();
788 if (pChannel == NULL)
789 return;
790
791 // Prompt user if he/she's sure about this...
792 if (m_pOptions && m_pOptions->bConfirmRemove) {
793 if (QMessageBox::warning(this, tr("Warning"),
794 tr("About to remove channel:\n\n"
795 "%1\n\n"
796 "Are you sure?")
797 .arg(pChannelStrip->caption()),
798 tr("OK"), tr("Cancel")) > 0)
799 return;
800 }
801
802 // Remove the existing sampler channel.
803 if (!pChannel->removeChannel())
804 return;
805
806 // Just delete the channel strip.
807 delete pChannelStrip;
808
809 // Do we auto-arrange?
810 if (m_pOptions && m_pOptions->bAutoArrange)
811 channelsArrange();
812
813 // We'll be dirty, for sure...
814 m_iDirtyCount++;
815 stabilizeForm();
816 }
817
818
819 // Setup current sampler channel.
820 void qsamplerMainForm::editSetupChannel (void)
821 {
822 if (m_pClient == NULL)
823 return;
824
825 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
826 if (pChannelStrip == NULL)
827 return;
828
829 // Just invoque the channel strip procedure.
830 pChannelStrip->channelSetup();
831 }
832
833
834 // Reset current sampler channel.
835 void qsamplerMainForm::editResetChannel (void)
836 {
837 if (m_pClient == NULL)
838 return;
839
840 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
841 if (pChannelStrip == NULL)
842 return;
843
844 qsamplerChannel *pChannel = pChannelStrip->channel();
845 if (pChannel == NULL)
846 return;
847
848 // Reset the existing sampler channel.
849 pChannel->resetChannel();
850
851 // Refresh channel strip info.
852 pChannelStrip->updateChannelInfo();
853 }
854
855
856 //-------------------------------------------------------------------------
857 // qsamplerMainForm -- View Action slots.
858
859 // Show/hide the main program window menubar.
860 void qsamplerMainForm::viewMenubar ( bool bOn )
861 {
862 if (bOn)
863 MenuBar->show();
864 else
865 MenuBar->hide();
866 }
867
868
869 // Show/hide the main program window toolbar.
870 void qsamplerMainForm::viewToolbar ( bool bOn )
871 {
872 if (bOn) {
873 fileToolbar->show();
874 editToolbar->show();
875 channelsToolbar->show();
876 } else {
877 fileToolbar->hide();
878 editToolbar->hide();
879 channelsToolbar->hide();
880 }
881 }
882
883
884 // Show/hide the main program window statusbar.
885 void qsamplerMainForm::viewStatusbar ( bool bOn )
886 {
887 if (bOn)
888 statusBar()->show();
889 else
890 statusBar()->hide();
891 }
892
893
894 // Show/hide the messages window logger.
895 void qsamplerMainForm::viewMessages ( bool bOn )
896 {
897 if (bOn)
898 m_pMessages->show();
899 else
900 m_pMessages->hide();
901 }
902
903
904 // Show options dialog.
905 void qsamplerMainForm::viewOptions (void)
906 {
907 if (m_pOptions == NULL)
908 return;
909
910 qsamplerOptionsForm *pOptionsForm = new qsamplerOptionsForm(this);
911 if (pOptionsForm) {
912 // Check out some initial nullities(tm)...
913 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
914 if (m_pOptions->sDisplayFont.isEmpty() && pChannelStrip)
915 m_pOptions->sDisplayFont = pChannelStrip->displayFont().toString();
916 if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages)
917 m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();
918 // To track down deferred or immediate changes.
919 QString sOldServerHost = m_pOptions->sServerHost;
920 int iOldServerPort = m_pOptions->iServerPort;
921 int iOldServerTimeout = m_pOptions->iServerTimeout;
922 bool bOldServerStart = m_pOptions->bServerStart;
923 QString sOldServerCmdLine = m_pOptions->sServerCmdLine;
924 QString sOldDisplayFont = m_pOptions->sDisplayFont;
925 bool bOldDisplayEffect = m_pOptions->bDisplayEffect;
926 int iOldMaxVolume = m_pOptions->iMaxVolume;
927 QString sOldMessagesFont = m_pOptions->sMessagesFont;
928 bool bOldStdoutCapture = m_pOptions->bStdoutCapture;
929 int bOldMessagesLimit = m_pOptions->bMessagesLimit;
930 int iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines;
931 bool bOldCompletePath = m_pOptions->bCompletePath;
932 int iOldMaxRecentFiles = m_pOptions->iMaxRecentFiles;
933 // Load the current setup settings.
934 pOptionsForm->setup(m_pOptions);
935 // Show the setup dialog...
936 if (pOptionsForm->exec()) {
937 // Warn if something will be only effective on next run.
938 if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) ||
939 (!bOldStdoutCapture && m_pOptions->bStdoutCapture)) {
940 QMessageBox::information(this, tr("Information"),
941 tr("Some settings may be only effective\n"
942 "next time you start this program."), tr("OK"));
943 updateMessagesCapture();
944 }
945 // Check wheather something immediate has changed.
946 if (( bOldCompletePath && !m_pOptions->bCompletePath) ||
947 (!bOldCompletePath && m_pOptions->bCompletePath) ||
948 (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles))
949 updateRecentFilesMenu();
950 if (( bOldDisplayEffect && !m_pOptions->bDisplayEffect) ||
951 (!bOldDisplayEffect && m_pOptions->bDisplayEffect))
952 updateDisplayEffect();
953 if (sOldDisplayFont != m_pOptions->sDisplayFont)
954 updateDisplayFont();
955 if (iOldMaxVolume != m_pOptions->iMaxVolume)
956 updateMaxVolume();
957 if (sOldMessagesFont != m_pOptions->sMessagesFont)
958 updateMessagesFont();
959 if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) ||
960 (!bOldMessagesLimit && m_pOptions->bMessagesLimit) ||
961 (iOldMessagesLimitLines != m_pOptions->iMessagesLimitLines))
962 updateMessagesLimit();
963 // And now the main thing, whether we'll do client/server recycling?
964 if ((sOldServerHost != m_pOptions->sServerHost) ||
965 (iOldServerPort != m_pOptions->iServerPort) ||
966 (iOldServerTimeout != m_pOptions->iServerTimeout) ||
967 ( bOldServerStart && !m_pOptions->bServerStart) ||
968 (!bOldServerStart && m_pOptions->bServerStart) ||
969 (sOldServerCmdLine != m_pOptions->sServerCmdLine && m_pOptions->bServerStart))
970 fileRestart();
971 }
972 // Done.
973 delete pOptionsForm;
974 }
975
976 // This makes it.
977 stabilizeForm();
978 }
979
980
981 //-------------------------------------------------------------------------
982 // qsamplerMainForm -- Channels action slots.
983
984 // Arrange channel strips.
985 void qsamplerMainForm::channelsArrange (void)
986 {
987 // Full width vertical tiling
988 QWidgetList wlist = m_pWorkspace->windowList();
989 if (wlist.isEmpty())
990 return;
991
992 m_pWorkspace->setUpdatesEnabled(false);
993 int y = 0;
994 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
995 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
996 /* if (pChannelStrip->testWState(WState_Maximized | WState_Minimized)) {
997 // Prevent flicker...
998 pChannelStrip->hide();
999 pChannelStrip->showNormal();
1000 } */
1001 pChannelStrip->adjustSize();
1002 int iWidth = m_pWorkspace->width();
1003 if (iWidth < pChannelStrip->width())
1004 iWidth = pChannelStrip->width();
1005 // int iHeight = pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();
1006 int iHeight = pChannelStrip->parentWidget()->frameGeometry().height();
1007 pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1008 y += iHeight;
1009 }
1010 m_pWorkspace->setUpdatesEnabled(true);
1011
1012 stabilizeForm();
1013 }
1014
1015
1016 // Auto-arrange channel strips.
1017 void qsamplerMainForm::channelsAutoArrange ( bool bOn )
1018 {
1019 if (m_pOptions == NULL)
1020 return;
1021
1022 // Toggle the auto-arrange flag.
1023 m_pOptions->bAutoArrange = bOn;
1024
1025 // If on, update whole workspace...
1026 if (m_pOptions->bAutoArrange)
1027 channelsArrange();
1028 }
1029
1030
1031 //-------------------------------------------------------------------------
1032 // qsamplerMainForm -- Help Action slots.
1033
1034 // Show information about the Qt toolkit.
1035 void qsamplerMainForm::helpAboutQt (void)
1036 {
1037 QMessageBox::aboutQt(this);
1038 }
1039
1040
1041 // Show information about application program.
1042 void qsamplerMainForm::helpAbout (void)
1043 {
1044 // Stuff the about box text...
1045 QString sText = "<p>\n";
1046 sText += "<b>" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "</b><br />\n";
1047 sText += "<br />\n";
1048 sText += tr("Version") + ": <b>" QSAMPLER_VERSION "</b><br />\n";
1049 sText += "<small>" + tr("Build") + ": " __DATE__ " " __TIME__ "</small><br />\n";
1050 #ifdef CONFIG_DEBUG
1051 sText += "<small><font color=\"red\">";
1052 sText += tr("Debugging option enabled.");
1053 sText += "</font></small><br />";
1054 #endif
1055 #ifndef CONFIG_LIBGIG
1056 sText += "<small><font color=\"red\">";
1057 sText += tr("GIG (libgig) file support disabled.");
1058 sText += "</font></small><br />";
1059 #endif
1060 sText += "<br />\n";
1061 sText += tr("Using") + ": ";
1062 sText += ::lscp_client_package();
1063 sText += " ";
1064 sText += ::lscp_client_version();
1065 sText += "<br />\n";
1066 sText += "<br />\n";
1067 sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";
1068 sText += "<br />\n";
1069 sText += "<small>";
1070 sText += QSAMPLER_COPYRIGHT "<br />\n";
1071 sText += "<br />\n";
1072 sText += tr("This program is free software; you can redistribute it and/or modify it") + "<br />\n";
1073 sText += tr("under the terms of the GNU General Public License version 2 or later.");
1074 sText += "</small>";
1075 sText += "</p>\n";
1076
1077 QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText);
1078 }
1079
1080
1081 //-------------------------------------------------------------------------
1082 // qsamplerMainForm -- Main window stabilization.
1083
1084 void qsamplerMainForm::stabilizeForm (void)
1085 {
1086 // Update the main application caption...
1087 QString sSessioName = sessionName(m_sFilename);
1088 if (m_iDirtyCount > 0)
1089 sSessioName += '*';
1090 setCaption(tr(QSAMPLER_TITLE " - [%1]").arg(sSessioName));
1091
1092 // Update the main menu state...
1093 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
1094 bool bHasClient = (m_pOptions != NULL && m_pClient != NULL);
1095 bool bHasChannel = (bHasClient && pChannelStrip != NULL);
1096 fileNewAction->setEnabled(bHasClient);
1097 fileOpenAction->setEnabled(bHasClient);
1098 fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);
1099 fileSaveAsAction->setEnabled(bHasClient);
1100 fileResetAction->setEnabled(bHasClient);
1101 fileRestartAction->setEnabled(bHasClient || m_pServer == NULL);
1102 editAddChannelAction->setEnabled(bHasClient);
1103 editRemoveChannelAction->setEnabled(bHasChannel);
1104 editSetupChannelAction->setEnabled(bHasChannel);
1105 editResetChannelAction->setEnabled(bHasChannel);
1106 channelsArrangeAction->setEnabled(bHasChannel);
1107 viewMessagesAction->setOn(m_pMessages && m_pMessages->isVisible());
1108
1109 // Client/Server status...
1110 if (bHasClient) {
1111 m_status[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));
1112 m_status[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost + ":" + QString::number(m_pOptions->iServerPort));
1113 } else {
1114 m_status[QSAMPLER_STATUS_CLIENT]->clear();
1115 m_status[QSAMPLER_STATUS_SERVER]->clear();
1116 }
1117 // Channel status...
1118 if (bHasChannel)
1119 m_status[QSAMPLER_STATUS_CHANNEL]->setText(pChannelStrip->caption());
1120 else
1121 m_status[QSAMPLER_STATUS_CHANNEL]->clear();
1122 // Session status...
1123 if (m_iDirtyCount > 0)
1124 m_status[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));
1125 else
1126 m_status[QSAMPLER_STATUS_SESSION]->clear();
1127
1128 // Recent files menu.
1129 m_pRecentFilesMenu->setEnabled(bHasClient && m_pOptions->recentFiles.count() > 0);
1130
1131 // Always make the latest message visible.
1132 if (m_pMessages)
1133 m_pMessages->scrollToBottom();
1134 }
1135
1136
1137 // Channel change receiver slot.
1138 void qsamplerMainForm::channelStripChanged( qsamplerChannelStrip * )
1139 {
1140 // Flag that we're update those channel strips.
1141 m_iChangeCount++;
1142 // Just mark the dirty form.
1143 m_iDirtyCount++;
1144 // and update the form status...
1145 stabilizeForm();
1146 }
1147
1148
1149 // Update the recent files list and menu.
1150 void qsamplerMainForm::updateRecentFiles ( const QString& sFilename )
1151 {
1152 if (m_pOptions == NULL)
1153 return;
1154
1155 // Remove from list if already there (avoid duplicates)
1156 QStringList::Iterator iter = m_pOptions->recentFiles.find(sFilename);
1157 if (iter != m_pOptions->recentFiles.end())
1158 m_pOptions->recentFiles.remove(iter);
1159 // Put it to front...
1160 m_pOptions->recentFiles.push_front(sFilename);
1161
1162 // May update the menu.
1163 updateRecentFilesMenu();
1164 }
1165
1166
1167 // Update the recent files list and menu.
1168 void qsamplerMainForm::updateRecentFilesMenu (void)
1169 {
1170 if (m_pOptions == NULL)
1171 return;
1172
1173 // Time to keep the list under limits.
1174 int iRecentFiles = m_pOptions->recentFiles.count();
1175 while (iRecentFiles > m_pOptions->iMaxRecentFiles) {
1176 m_pOptions->recentFiles.pop_back();
1177 iRecentFiles--;
1178 }
1179
1180 // rebuild the recent files menu...
1181 m_pRecentFilesMenu->clear();
1182 for (int i = 0; i < iRecentFiles; i++) {
1183 const QString& sFilename = m_pOptions->recentFiles[i];
1184 if (QFileInfo(sFilename).exists()) {
1185 m_pRecentFilesMenu->insertItem(QString("&%1 %2")
1186 .arg(i + 1).arg(sessionName(sFilename)),
1187 this, SLOT(fileOpenRecent(int)), 0, i);
1188 }
1189 }
1190 }
1191
1192
1193 // Force update of the channels display font.
1194 void qsamplerMainForm::updateDisplayFont (void)
1195 {
1196 if (m_pOptions == NULL)
1197 return;
1198
1199 // Check if display font is legal.
1200 if (m_pOptions->sDisplayFont.isEmpty())
1201 return;
1202 // Realize it.
1203 QFont font;
1204 if (!font.fromString(m_pOptions->sDisplayFont))
1205 return;
1206
1207 // Full channel list update...
1208 QWidgetList wlist = m_pWorkspace->windowList();
1209 if (wlist.isEmpty())
1210 return;
1211
1212 m_pWorkspace->setUpdatesEnabled(false);
1213 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1214 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1215 if (pChannelStrip)
1216 pChannelStrip->setDisplayFont(font);
1217 }
1218 m_pWorkspace->setUpdatesEnabled(true);
1219 }
1220
1221
1222 // Update channel strips background effect.
1223 void qsamplerMainForm::updateDisplayEffect (void)
1224 {
1225 QPixmap pm;
1226 if (m_pOptions->bDisplayEffect)
1227 pm = QPixmap::fromMimeSource("displaybg1.png");
1228
1229 // Full channel list update...
1230 QWidgetList wlist = m_pWorkspace->windowList();
1231 if (wlist.isEmpty())
1232 return;
1233
1234 m_pWorkspace->setUpdatesEnabled(false);
1235 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1236 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1237 if (pChannelStrip)
1238 pChannelStrip->setDisplayBackground(pm);
1239 }
1240 m_pWorkspace->setUpdatesEnabled(true);
1241 }
1242
1243
1244 // Force update of the channels maximum volume setting.
1245 void qsamplerMainForm::updateMaxVolume (void)
1246 {
1247 if (m_pOptions == NULL)
1248 return;
1249
1250 // Full channel list update...
1251 QWidgetList wlist = m_pWorkspace->windowList();
1252 if (wlist.isEmpty())
1253 return;
1254
1255 m_pWorkspace->setUpdatesEnabled(false);
1256 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1257 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1258 if (pChannelStrip)
1259 pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
1260 }
1261 m_pWorkspace->setUpdatesEnabled(true);
1262 }
1263
1264
1265 //-------------------------------------------------------------------------
1266 // qsamplerMainForm -- Messages window form handlers.
1267
1268 // Messages output methods.
1269 void qsamplerMainForm::appendMessages( const QString& s )
1270 {
1271 if (m_pMessages)
1272 m_pMessages->appendMessages(s);
1273
1274 statusBar()->message(s, 3000);
1275 }
1276
1277 void qsamplerMainForm::appendMessagesColor( const QString& s, const QString& c )
1278 {
1279 if (m_pMessages)
1280 m_pMessages->appendMessagesColor(s, c);
1281
1282 statusBar()->message(s, 3000);
1283 }
1284
1285 void qsamplerMainForm::appendMessagesText( const QString& s )
1286 {
1287 if (m_pMessages)
1288 m_pMessages->appendMessagesText(s);
1289 }
1290
1291 void qsamplerMainForm::appendMessagesError( const QString& s )
1292 {
1293 if (m_pMessages)
1294 m_pMessages->show();
1295
1296 appendMessagesColor(s.simplifyWhiteSpace(), "#ff0000");
1297
1298 QMessageBox::critical(this, tr("Error"), s, tr("Cancel"));
1299 }
1300
1301
1302 // This is a special message format, just for client results.
1303 void qsamplerMainForm::appendMessagesClient( const QString& s )
1304 {
1305 if (m_pClient == NULL)
1306 return;
1307
1308 appendMessagesColor(s + QString(": %1 (errno=%2)")
1309 .arg(::lscp_client_get_result(m_pClient))
1310 .arg(::lscp_client_get_errno(m_pClient)), "#996666");
1311 }
1312
1313
1314 // Force update of the messages font.
1315 void qsamplerMainForm::updateMessagesFont (void)
1316 {
1317 if (m_pOptions == NULL)
1318 return;
1319
1320 if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {
1321 QFont font;
1322 if (font.fromString(m_pOptions->sMessagesFont))
1323 m_pMessages->setMessagesFont(font);
1324 }
1325 }
1326
1327
1328 // Update messages window line limit.
1329 void qsamplerMainForm::updateMessagesLimit (void)
1330 {
1331 if (m_pOptions == NULL)
1332 return;
1333
1334 if (m_pMessages) {
1335 if (m_pOptions->bMessagesLimit)
1336 m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);
1337 else
1338 m_pMessages->setMessagesLimit(0);
1339 }
1340 }
1341
1342
1343 // Enablement of the messages capture feature.
1344 void qsamplerMainForm::updateMessagesCapture (void)
1345 {
1346 if (m_pOptions == NULL)
1347 return;
1348
1349 if (m_pMessages)
1350 m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);
1351 }
1352
1353
1354 //-------------------------------------------------------------------------
1355 // qsamplerMainForm -- MDI channel strip management.
1356
1357 // The channel strip creation executive.
1358 qsamplerChannelStrip *qsamplerMainForm::createChannelStrip ( int iChannelID )
1359 {
1360 if (m_pClient == NULL)
1361 return NULL;
1362
1363 // Prepare for auto-arrange?
1364 qsamplerChannelStrip *pChannelStrip = NULL;
1365 int y = 0;
1366 if (m_pOptions && m_pOptions->bAutoArrange) {
1367 QWidgetList wlist = m_pWorkspace->windowList();
1368 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1369 pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1370 // y += pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();
1371 y += pChannelStrip->parentWidget()->frameGeometry().height();
1372 }
1373 }
1374
1375 // Add a new channel itema...
1376 WFlags wflags = Qt::WStyle_Customize | Qt::WStyle_Tool | Qt::WStyle_Title | Qt::WStyle_NoBorder;
1377 pChannelStrip = new qsamplerChannelStrip(m_pWorkspace, 0, wflags);
1378 // Actual channel setup.
1379 pChannelStrip->setup(this, iChannelID);
1380 QObject::connect(pChannelStrip, SIGNAL(channelChanged(qsamplerChannelStrip *)), this, SLOT(channelStripChanged(qsamplerChannelStrip *)));
1381 // Before we show it up, may be we'll
1382 // better ask for some initial values?
1383 if (iChannelID < 0 && !pChannelStrip->channelSetup()) {
1384 // No luck, bail out...
1385 delete pChannelStrip;
1386 return NULL;
1387 }
1388
1389 // Set some initial aesthetic options...
1390 if (m_pOptions) {
1391 // Background display effect...
1392 pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
1393 // We'll need a display font.
1394 QFont font;
1395 if (font.fromString(m_pOptions->sDisplayFont))
1396 pChannelStrip->setDisplayFont(font);
1397 // Maximum allowed volume setting.
1398 pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
1399 }
1400
1401 // Now we show up us to the world.
1402 pChannelStrip->show();
1403 // Only then, we'll auto-arrange...
1404 if (m_pOptions && m_pOptions->bAutoArrange) {
1405 int iWidth = m_pWorkspace->width();
1406 // int iHeight = pChannel->height() + pChannel->parentWidget()->baseSize().height();
1407 int iHeight = pChannelStrip->parentWidget()->frameGeometry().height();
1408 pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1409 }
1410
1411 // Return our successful reference...
1412 return pChannelStrip;
1413 }
1414
1415
1416 // Retrieve the active channel strip.
1417 qsamplerChannelStrip *qsamplerMainForm::activeChannelStrip (void)
1418 {
1419 return (qsamplerChannelStrip *) m_pWorkspace->activeWindow();
1420 }
1421
1422
1423 // Retrieve a channel strip by index.
1424 qsamplerChannelStrip *qsamplerMainForm::channelStripAt ( int iChannel )
1425 {
1426 QWidgetList wlist = m_pWorkspace->windowList();
1427 if (wlist.isEmpty())
1428 return 0;
1429
1430 return (qsamplerChannelStrip *) wlist.at(iChannel);
1431 }
1432
1433
1434 // Construct the windows menu.
1435 void qsamplerMainForm::channelsMenuAboutToShow (void)
1436 {
1437 channelsMenu->clear();
1438 channelsArrangeAction->addTo(channelsMenu);
1439 channelsAutoArrangeAction->addTo(channelsMenu);
1440
1441 QWidgetList wlist = m_pWorkspace->windowList();
1442 if (!wlist.isEmpty()) {
1443 channelsMenu->insertSeparator();
1444 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1445 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1446 if (pChannelStrip) {
1447 int iItemID = channelsMenu->insertItem(pChannelStrip->caption(), this, SLOT(channelsMenuActivated(int)));
1448 channelsMenu->setItemParameter(iItemID, iChannel);
1449 channelsMenu->setItemChecked(iItemID, activeChannelStrip() == pChannelStrip);
1450 }
1451 }
1452 }
1453 }
1454
1455
1456 // Windows menu activation slot
1457 void qsamplerMainForm::channelsMenuActivated ( int iChannel )
1458 {
1459 qsamplerChannelStrip *pChannelStrip = channelStripAt(iChannel);
1460 if (pChannelStrip)
1461 pChannelStrip->showNormal();
1462 pChannelStrip->setFocus();
1463 }
1464
1465
1466 //-------------------------------------------------------------------------
1467 // qsamplerMainForm -- Timer stuff.
1468
1469 // Set the pseudo-timer delay schedule.
1470 void qsamplerMainForm::startSchedule ( int iStartDelay )
1471 {
1472 m_iStartDelay = 1 + (iStartDelay * 1000);
1473 m_iTimerDelay = 0;
1474 }
1475
1476 // Suspend the pseudo-timer delay schedule.
1477 void qsamplerMainForm::stopSchedule (void)
1478 {
1479 m_iStartDelay = 0;
1480 m_iTimerDelay = 0;
1481 }
1482
1483 // Timer slot funtion.
1484 void qsamplerMainForm::timerSlot (void)
1485 {
1486 if (m_pOptions == NULL)
1487 return;
1488
1489 // Is it the first shot on server start after a few delay?
1490 if (m_iTimerDelay < m_iStartDelay) {
1491 m_iTimerDelay += QSAMPLER_TIMER_MSECS;
1492 if (m_iTimerDelay >= m_iStartDelay) {
1493 // If we cannot start it now, maybe a lil'mo'later ;)
1494 if (!startClient()) {
1495 m_iStartDelay += m_iTimerDelay;
1496 m_iTimerDelay = 0;
1497 }
1498 }
1499 }
1500
1501 // Refresh each channel usage, on each period...
1502 if (m_pClient && (m_iChangeCount > 0 || m_pOptions->bAutoRefresh)) {
1503 m_iTimerSlot += QSAMPLER_TIMER_MSECS;
1504 if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime && m_pWorkspace->isUpdatesEnabled()) {
1505 m_iTimerSlot = 0;
1506 m_iChangeCount = 0;
1507 QWidgetList wlist = m_pWorkspace->windowList();
1508 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1509 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1510 if (pChannelStrip && pChannelStrip->isVisible()) {
1511 // If we can't make it clean, try next time.
1512 if (!pChannelStrip->updateChannelUsage())
1513 m_iChangeCount++;
1514 }
1515 }
1516 }
1517 }
1518
1519 // Register the next timer slot.
1520 QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
1521 }
1522
1523
1524 //-------------------------------------------------------------------------
1525 // qsamplerMainForm -- Server stuff.
1526
1527 // Start linuxsampler server...
1528 void qsamplerMainForm::startServer (void)
1529 {
1530 if (m_pOptions == NULL)
1531 return;
1532
1533 // Aren't already a client, are we?
1534 if (!m_pOptions->bServerStart || m_pClient)
1535 return;
1536
1537 // Is the server process instance still here?
1538 if (m_pServer) {
1539 switch (QMessageBox::warning(this, tr("Warning"),
1540 tr("Could not start the LinuxSampler server.\n\n"
1541 "Maybe it ss already started."),
1542 tr("Stop"), tr("Kill"), tr("Cancel"))) {
1543 case 0:
1544 m_pServer->tryTerminate();
1545 break;
1546 case 1:
1547 m_pServer->kill();
1548 break;
1549 }
1550 return;
1551 }
1552
1553 // Reset our timer counters...
1554 stopSchedule();
1555
1556 // OK. Let's build the startup process...
1557 m_pServer = new QProcess(this);
1558
1559 // Setup stdout/stderr capture...
1560 //if (m_pOptions->bStdoutCapture) {
1561 m_pServer->setCommunication(QProcess::Stdout | QProcess::Stderr | QProcess::DupStderr);
1562 QObject::connect(m_pServer, SIGNAL(readyReadStdout()), this, SLOT(readServerStdout()));
1563 QObject::connect(m_pServer, SIGNAL(readyReadStderr()), this, SLOT(readServerStdout()));
1564 //}
1565 // The unforgiveable signal communication...
1566 QObject::connect(m_pServer, SIGNAL(processExited()), this, SLOT(processServerExit()));
1567
1568 // Build process arguments...
1569 m_pServer->setArguments(QStringList::split(' ', m_pOptions->sServerCmdLine));
1570
1571 appendMessages(tr("Server is starting..."));
1572 appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");
1573
1574 // Go jack, go...
1575 if (!m_pServer->start()) {
1576 appendMessagesError(tr("Could not start server.\n\nSorry."));
1577 processServerExit();
1578 return;
1579 }
1580
1581 // Show startup results...
1582 appendMessages(tr("Server was started with PID=%1.").arg((long) m_pServer->processIdentifier()));
1583
1584 // Reset (yet again) the timer counters,
1585 // but this time is deferred as the user opted.
1586 startSchedule(m_pOptions->iStartDelay);
1587 stabilizeForm();
1588 }
1589
1590
1591 // Stop linuxsampler server...
1592 void qsamplerMainForm::stopServer (void)
1593 {
1594 // Stop client code.
1595 stopClient();
1596
1597 // And try to stop server.
1598 if (m_pServer) {
1599 appendMessages(tr("Server is stopping..."));
1600 if (m_pServer->isRunning())
1601 m_pServer->tryTerminate();
1602 }
1603
1604 // Give it some time to terminate gracefully and stabilize...
1605 QTime t;
1606 t.start();
1607 while (t.elapsed() < QSAMPLER_TIMER_MSECS)
1608 QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
1609
1610 // Do final processing anyway.
1611 processServerExit();
1612 }
1613
1614
1615 // Stdout handler...
1616 void qsamplerMainForm::readServerStdout (void)
1617 {
1618 if (m_pMessages)
1619 m_pMessages->appendStdoutBuffer(m_pServer->readStdout());
1620 }
1621
1622
1623 // Linuxsampler server cleanup.
1624 void qsamplerMainForm::processServerExit (void)
1625 {
1626 // Force client code cleanup.
1627 stopClient();
1628
1629 // Flush anything that maybe pending...
1630 if (m_pMessages)
1631 m_pMessages->flushStdoutBuffer();
1632
1633 if (m_pServer) {
1634 // Force final server shutdown...
1635 appendMessages(tr("Server was stopped with exit status %1.").arg(m_pServer->exitStatus()));
1636 if (!m_pServer->normalExit())
1637 m_pServer->kill();
1638 // Destroy it.
1639 delete m_pServer;
1640 m_pServer = NULL;
1641 }
1642
1643 // Again, make status visible stable.
1644 stabilizeForm();
1645 }
1646
1647
1648 //-------------------------------------------------------------------------
1649 // qsamplerMainForm -- Client stuff.
1650
1651 // The LSCP client callback procedure.
1652 lscp_status_t qsampler_client_callback ( lscp_client_t */*pClient*/, lscp_event_t event, const char *pchData, int cchData, void *pvData )
1653 {
1654 qsamplerMainForm *pMainForm = (qsamplerMainForm *) pvData;
1655 if (pMainForm == NULL)
1656 return LSCP_FAILED;
1657
1658 // ATTN: DO NOT EVER call any GUI code here,
1659 // as this is run under some other thread context.
1660 // A custom event must be posted here...
1661 QApplication::postEvent(pMainForm, new qsamplerCustomEvent(event, pchData, cchData));
1662
1663 return LSCP_OK;
1664 }
1665
1666
1667 // Start our almighty client...
1668 bool qsamplerMainForm::startClient (void)
1669 {
1670 // Have it a setup?
1671 if (m_pOptions == NULL)
1672 return false;
1673
1674 // Aren't we already started, are we?
1675 if (m_pClient)
1676 return true;
1677
1678 // Log prepare here.
1679 appendMessages(tr("Client connecting..."));
1680
1681 // Create the client handle...
1682 m_pClient = ::lscp_client_create(m_pOptions->sServerHost.latin1(), m_pOptions->iServerPort, qsampler_client_callback, this);
1683 if (m_pClient == NULL) {
1684 // Is this the first try?
1685 // maybe we need to start a local server...
1686 if ((m_pServer && m_pServer->isRunning()) || !m_pOptions->bServerStart)
1687 appendMessagesError(tr("Could not connect to server as client.\n\nSorry."));
1688 else
1689 startServer();
1690 // This is always a failure.
1691 stabilizeForm();
1692 return false;
1693 }
1694 // Just set receive timeout value, blindly.
1695 ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);
1696 appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));
1697
1698 // We may stop scheduling around.
1699 stopSchedule();
1700
1701 // We'll accept drops from now on...
1702 setAcceptDrops(true);
1703
1704 // Log success here.
1705 appendMessages(tr("Client connected."));
1706
1707 // Is any session pending to be loaded?
1708 if (!m_pOptions->sSessionFile.isEmpty()) {
1709 // Just load the prabably startup session...
1710 if (loadSessionFile(m_pOptions->sSessionFile)) {
1711 m_pOptions->sSessionFile = QString::null;
1712 return true;
1713 }
1714 }
1715
1716 // Make a new session
1717 return newSession();
1718 }
1719
1720
1721 // Stop client...
1722 void qsamplerMainForm::stopClient (void)
1723 {
1724 if (m_pClient == NULL)
1725 return;
1726
1727 // Log prepare here.
1728 appendMessages(tr("Client disconnecting..."));
1729
1730 // Clear timer counters...
1731 stopSchedule();
1732
1733 // We'll reject drops from now on...
1734 setAcceptDrops(false);
1735
1736 // Force any channel strips around, but
1737 // but avoid removing the corresponding
1738 // channels from the back-end server.
1739 m_iDirtyCount = 0;
1740 closeSession(false);
1741
1742 // Close us as a client...
1743 lscp_client_destroy(m_pClient);
1744 m_pClient = NULL;
1745
1746 // Log final here.
1747 appendMessages(tr("Client disconnected."));
1748
1749 // Make visible status.
1750 stabilizeForm();
1751 }
1752
1753
1754 // end of qsamplerMainForm.ui.h

  ViewVC Help
Powered by ViewVC