/[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 340 - (show annotations) (download) (as text)
Fri Jan 14 10:40:47 2005 UTC (19 years, 2 months ago) by capela
File MIME type: text/x-c++hdr
File size: 55434 byte(s)
Set to ignore the SIGPIPE (Broken pipe) signal, where available.

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

  ViewVC Help
Powered by ViewVC