/[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 371 - (show annotations) (download) (as text)
Fri Feb 11 15:36:06 2005 UTC (15 years, 8 months ago) by capela
File MIME type: text/x-c++hdr
File size: 56262 byte(s)
Instrument names display mode update on all channels.

1 // qsamplerMainForm.ui.h
2 //
3 // ui.h extension file, included from the uic-generated form implementation.
4 /****************************************************************************
5 Copyright (C) 2004-2005, 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 } else {
560 // Try to (re)create each channel.
561 m_pWorkspace->setUpdatesEnabled(false);
562 for (int iChannel = 0; piChannelIDs[iChannel] >= 0; iChannel++) {
563 createChannelStrip(new qsamplerChannel(this, piChannelIDs[iChannel]));
564 QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
565 }
566 m_pWorkspace->setUpdatesEnabled(true);
567 }
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 bool bOldInstrumentNames = m_pOptions->bInstrumentNames;
963 int iOldMaxRecentFiles = m_pOptions->iMaxRecentFiles;
964 // Load the current setup settings.
965 pOptionsForm->setup(m_pOptions);
966 // Show the setup dialog...
967 if (pOptionsForm->exec()) {
968 // Warn if something will be only effective on next run.
969 if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) ||
970 (!bOldStdoutCapture && m_pOptions->bStdoutCapture)) {
971 QMessageBox::information(this, tr("Information"),
972 tr("Some settings may be only effective\n"
973 "next time you start this program."), tr("OK"));
974 updateMessagesCapture();
975 }
976 // Check wheather something immediate has changed.
977 if (( bOldCompletePath && !m_pOptions->bCompletePath) ||
978 (!bOldCompletePath && m_pOptions->bCompletePath) ||
979 (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles))
980 updateRecentFilesMenu();
981 if (( bOldInstrumentNames && !m_pOptions->bInstrumentNames) ||
982 (!bOldInstrumentNames && m_pOptions->bInstrumentNames))
983 updateInstrumentNames();
984 if (( bOldDisplayEffect && !m_pOptions->bDisplayEffect) ||
985 (!bOldDisplayEffect && m_pOptions->bDisplayEffect))
986 updateDisplayEffect();
987 if (sOldDisplayFont != m_pOptions->sDisplayFont)
988 updateDisplayFont();
989 if (iOldMaxVolume != m_pOptions->iMaxVolume)
990 updateMaxVolume();
991 if (sOldMessagesFont != m_pOptions->sMessagesFont)
992 updateMessagesFont();
993 if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) ||
994 (!bOldMessagesLimit && m_pOptions->bMessagesLimit) ||
995 (iOldMessagesLimitLines != m_pOptions->iMessagesLimitLines))
996 updateMessagesLimit();
997 // And now the main thing, whether we'll do client/server recycling?
998 if ((sOldServerHost != m_pOptions->sServerHost) ||
999 (iOldServerPort != m_pOptions->iServerPort) ||
1000 (iOldServerTimeout != m_pOptions->iServerTimeout) ||
1001 ( bOldServerStart && !m_pOptions->bServerStart) ||
1002 (!bOldServerStart && m_pOptions->bServerStart) ||
1003 (sOldServerCmdLine != m_pOptions->sServerCmdLine && m_pOptions->bServerStart))
1004 fileRestart();
1005 }
1006 // Done.
1007 delete pOptionsForm;
1008 }
1009
1010 // This makes it.
1011 stabilizeForm();
1012 }
1013
1014
1015 //-------------------------------------------------------------------------
1016 // qsamplerMainForm -- Channels action slots.
1017
1018 // Arrange channel strips.
1019 void qsamplerMainForm::channelsArrange (void)
1020 {
1021 // Full width vertical tiling
1022 QWidgetList wlist = m_pWorkspace->windowList();
1023 if (wlist.isEmpty())
1024 return;
1025
1026 m_pWorkspace->setUpdatesEnabled(false);
1027 int y = 0;
1028 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1029 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1030 /* if (pChannelStrip->testWState(WState_Maximized | WState_Minimized)) {
1031 // Prevent flicker...
1032 pChannelStrip->hide();
1033 pChannelStrip->showNormal();
1034 } */
1035 pChannelStrip->adjustSize();
1036 int iWidth = m_pWorkspace->width();
1037 if (iWidth < pChannelStrip->width())
1038 iWidth = pChannelStrip->width();
1039 // int iHeight = pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();
1040 int iHeight = pChannelStrip->parentWidget()->frameGeometry().height();
1041 pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1042 y += iHeight;
1043 }
1044 m_pWorkspace->setUpdatesEnabled(true);
1045
1046 stabilizeForm();
1047 }
1048
1049
1050 // Auto-arrange channel strips.
1051 void qsamplerMainForm::channelsAutoArrange ( bool bOn )
1052 {
1053 if (m_pOptions == NULL)
1054 return;
1055
1056 // Toggle the auto-arrange flag.
1057 m_pOptions->bAutoArrange = bOn;
1058
1059 // If on, update whole workspace...
1060 if (m_pOptions->bAutoArrange)
1061 channelsArrange();
1062 }
1063
1064
1065 //-------------------------------------------------------------------------
1066 // qsamplerMainForm -- Help Action slots.
1067
1068 // Show information about the Qt toolkit.
1069 void qsamplerMainForm::helpAboutQt (void)
1070 {
1071 QMessageBox::aboutQt(this);
1072 }
1073
1074
1075 // Show information about application program.
1076 void qsamplerMainForm::helpAbout (void)
1077 {
1078 // Stuff the about box text...
1079 QString sText = "<p>\n";
1080 sText += "<b>" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "</b><br />\n";
1081 sText += "<br />\n";
1082 sText += tr("Version") + ": <b>" QSAMPLER_VERSION "</b><br />\n";
1083 sText += "<small>" + tr("Build") + ": " __DATE__ " " __TIME__ "</small><br />\n";
1084 #ifdef CONFIG_DEBUG
1085 sText += "<small><font color=\"red\">";
1086 sText += tr("Debugging option enabled.");
1087 sText += "</font></small><br />";
1088 #endif
1089 #ifndef CONFIG_LIBGIG
1090 sText += "<small><font color=\"red\">";
1091 sText += tr("GIG (libgig) file support disabled.");
1092 sText += "</font></small><br />";
1093 #endif
1094 sText += "<br />\n";
1095 sText += tr("Using") + ": ";
1096 sText += ::lscp_client_package();
1097 sText += " ";
1098 sText += ::lscp_client_version();
1099 sText += "<br />\n";
1100 sText += "<br />\n";
1101 sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";
1102 sText += "<br />\n";
1103 sText += "<small>";
1104 sText += QSAMPLER_COPYRIGHT "<br />\n";
1105 sText += "<br />\n";
1106 sText += tr("This program is free software; you can redistribute it and/or modify it") + "<br />\n";
1107 sText += tr("under the terms of the GNU General Public License version 2 or later.");
1108 sText += "</small>";
1109 sText += "</p>\n";
1110
1111 QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText);
1112 }
1113
1114
1115 //-------------------------------------------------------------------------
1116 // qsamplerMainForm -- Main window stabilization.
1117
1118 void qsamplerMainForm::stabilizeForm (void)
1119 {
1120 // Update the main application caption...
1121 QString sSessioName = sessionName(m_sFilename);
1122 if (m_iDirtyCount > 0)
1123 sSessioName += '*';
1124 setCaption(tr(QSAMPLER_TITLE " - [%1]").arg(sSessioName));
1125
1126 // Update the main menu state...
1127 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
1128 bool bHasClient = (m_pOptions != NULL && m_pClient != NULL);
1129 bool bHasChannel = (bHasClient && pChannelStrip != NULL);
1130 fileNewAction->setEnabled(bHasClient);
1131 fileOpenAction->setEnabled(bHasClient);
1132 fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);
1133 fileSaveAsAction->setEnabled(bHasClient);
1134 fileResetAction->setEnabled(bHasClient);
1135 fileRestartAction->setEnabled(bHasClient || m_pServer == NULL);
1136 editAddChannelAction->setEnabled(bHasClient);
1137 editRemoveChannelAction->setEnabled(bHasChannel);
1138 editSetupChannelAction->setEnabled(bHasChannel);
1139 editResetChannelAction->setEnabled(bHasChannel);
1140 channelsArrangeAction->setEnabled(bHasChannel);
1141 viewMessagesAction->setOn(m_pMessages && m_pMessages->isVisible());
1142
1143 // Client/Server status...
1144 if (bHasClient) {
1145 m_status[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));
1146 m_status[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost + ":" + QString::number(m_pOptions->iServerPort));
1147 } else {
1148 m_status[QSAMPLER_STATUS_CLIENT]->clear();
1149 m_status[QSAMPLER_STATUS_SERVER]->clear();
1150 }
1151 // Channel status...
1152 if (bHasChannel)
1153 m_status[QSAMPLER_STATUS_CHANNEL]->setText(pChannelStrip->caption());
1154 else
1155 m_status[QSAMPLER_STATUS_CHANNEL]->clear();
1156 // Session status...
1157 if (m_iDirtyCount > 0)
1158 m_status[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));
1159 else
1160 m_status[QSAMPLER_STATUS_SESSION]->clear();
1161
1162 // Recent files menu.
1163 m_pRecentFilesMenu->setEnabled(bHasClient && m_pOptions->recentFiles.count() > 0);
1164
1165 // Always make the latest message visible.
1166 if (m_pMessages)
1167 m_pMessages->scrollToBottom();
1168 }
1169
1170
1171 // Channel change receiver slot.
1172 void qsamplerMainForm::channelStripChanged( qsamplerChannelStrip * )
1173 {
1174 // Flag that we're update those channel strips.
1175 m_iChangeCount++;
1176 // Just mark the dirty form.
1177 m_iDirtyCount++;
1178 // and update the form status...
1179 stabilizeForm();
1180 }
1181
1182
1183 // Update the recent files list and menu.
1184 void qsamplerMainForm::updateRecentFiles ( const QString& sFilename )
1185 {
1186 if (m_pOptions == NULL)
1187 return;
1188
1189 // Remove from list if already there (avoid duplicates)
1190 QStringList::Iterator iter = m_pOptions->recentFiles.find(sFilename);
1191 if (iter != m_pOptions->recentFiles.end())
1192 m_pOptions->recentFiles.remove(iter);
1193 // Put it to front...
1194 m_pOptions->recentFiles.push_front(sFilename);
1195
1196 // May update the menu.
1197 updateRecentFilesMenu();
1198 }
1199
1200
1201 // Update the recent files list and menu.
1202 void qsamplerMainForm::updateRecentFilesMenu (void)
1203 {
1204 if (m_pOptions == NULL)
1205 return;
1206
1207 // Time to keep the list under limits.
1208 int iRecentFiles = m_pOptions->recentFiles.count();
1209 while (iRecentFiles > m_pOptions->iMaxRecentFiles) {
1210 m_pOptions->recentFiles.pop_back();
1211 iRecentFiles--;
1212 }
1213
1214 // rebuild the recent files menu...
1215 m_pRecentFilesMenu->clear();
1216 for (int i = 0; i < iRecentFiles; i++) {
1217 const QString& sFilename = m_pOptions->recentFiles[i];
1218 if (QFileInfo(sFilename).exists()) {
1219 m_pRecentFilesMenu->insertItem(QString("&%1 %2")
1220 .arg(i + 1).arg(sessionName(sFilename)),
1221 this, SLOT(fileOpenRecent(int)), 0, i);
1222 }
1223 }
1224 }
1225
1226
1227 // Force update of the channels instrument names mode.
1228 void qsamplerMainForm::updateInstrumentNames (void)
1229 {
1230 // Full channel list update...
1231 QWidgetList wlist = m_pWorkspace->windowList();
1232 if (wlist.isEmpty())
1233 return;
1234
1235 m_pWorkspace->setUpdatesEnabled(false);
1236 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1237 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1238 if (pChannelStrip)
1239 pChannelStrip->updateInstrumentName(true);
1240 }
1241 m_pWorkspace->setUpdatesEnabled(true);
1242 }
1243
1244
1245 // Force update of the channels display font.
1246 void qsamplerMainForm::updateDisplayFont (void)
1247 {
1248 if (m_pOptions == NULL)
1249 return;
1250
1251 // Check if display font is legal.
1252 if (m_pOptions->sDisplayFont.isEmpty())
1253 return;
1254 // Realize it.
1255 QFont font;
1256 if (!font.fromString(m_pOptions->sDisplayFont))
1257 return;
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->setDisplayFont(font);
1269 }
1270 m_pWorkspace->setUpdatesEnabled(true);
1271 }
1272
1273
1274 // Update channel strips background effect.
1275 void qsamplerMainForm::updateDisplayEffect (void)
1276 {
1277 QPixmap pm;
1278 if (m_pOptions->bDisplayEffect)
1279 pm = QPixmap::fromMimeSource("displaybg1.png");
1280
1281 // Full channel list update...
1282 QWidgetList wlist = m_pWorkspace->windowList();
1283 if (wlist.isEmpty())
1284 return;
1285
1286 m_pWorkspace->setUpdatesEnabled(false);
1287 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1288 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1289 if (pChannelStrip)
1290 pChannelStrip->setDisplayBackground(pm);
1291 }
1292 m_pWorkspace->setUpdatesEnabled(true);
1293 }
1294
1295
1296 // Force update of the channels maximum volume setting.
1297 void qsamplerMainForm::updateMaxVolume (void)
1298 {
1299 if (m_pOptions == NULL)
1300 return;
1301
1302 // Full channel list update...
1303 QWidgetList wlist = m_pWorkspace->windowList();
1304 if (wlist.isEmpty())
1305 return;
1306
1307 m_pWorkspace->setUpdatesEnabled(false);
1308 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1309 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1310 if (pChannelStrip)
1311 pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
1312 }
1313 m_pWorkspace->setUpdatesEnabled(true);
1314 }
1315
1316
1317 //-------------------------------------------------------------------------
1318 // qsamplerMainForm -- Messages window form handlers.
1319
1320 // Messages output methods.
1321 void qsamplerMainForm::appendMessages( const QString& s )
1322 {
1323 if (m_pMessages)
1324 m_pMessages->appendMessages(s);
1325
1326 statusBar()->message(s, 3000);
1327 }
1328
1329 void qsamplerMainForm::appendMessagesColor( const QString& s, const QString& c )
1330 {
1331 if (m_pMessages)
1332 m_pMessages->appendMessagesColor(s, c);
1333
1334 statusBar()->message(s, 3000);
1335 }
1336
1337 void qsamplerMainForm::appendMessagesText( const QString& s )
1338 {
1339 if (m_pMessages)
1340 m_pMessages->appendMessagesText(s);
1341 }
1342
1343 void qsamplerMainForm::appendMessagesError( const QString& s )
1344 {
1345 if (m_pMessages)
1346 m_pMessages->show();
1347
1348 appendMessagesColor(s.simplifyWhiteSpace(), "#ff0000");
1349
1350 QMessageBox::critical(this, tr("Error"), s, tr("Cancel"));
1351 }
1352
1353
1354 // This is a special message format, just for client results.
1355 void qsamplerMainForm::appendMessagesClient( const QString& s )
1356 {
1357 if (m_pClient == NULL)
1358 return;
1359
1360 appendMessagesColor(s + QString(": %1 (errno=%2)")
1361 .arg(::lscp_client_get_result(m_pClient))
1362 .arg(::lscp_client_get_errno(m_pClient)), "#996666");
1363 }
1364
1365
1366 // Force update of the messages font.
1367 void qsamplerMainForm::updateMessagesFont (void)
1368 {
1369 if (m_pOptions == NULL)
1370 return;
1371
1372 if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {
1373 QFont font;
1374 if (font.fromString(m_pOptions->sMessagesFont))
1375 m_pMessages->setMessagesFont(font);
1376 }
1377 }
1378
1379
1380 // Update messages window line limit.
1381 void qsamplerMainForm::updateMessagesLimit (void)
1382 {
1383 if (m_pOptions == NULL)
1384 return;
1385
1386 if (m_pMessages) {
1387 if (m_pOptions->bMessagesLimit)
1388 m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);
1389 else
1390 m_pMessages->setMessagesLimit(0);
1391 }
1392 }
1393
1394
1395 // Enablement of the messages capture feature.
1396 void qsamplerMainForm::updateMessagesCapture (void)
1397 {
1398 if (m_pOptions == NULL)
1399 return;
1400
1401 if (m_pMessages)
1402 m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);
1403 }
1404
1405
1406 //-------------------------------------------------------------------------
1407 // qsamplerMainForm -- MDI channel strip management.
1408
1409 // The channel strip creation executive.
1410 qsamplerChannelStrip *qsamplerMainForm::createChannelStrip ( qsamplerChannel *pChannel )
1411 {
1412 if (m_pClient == NULL || pChannel == NULL)
1413 return NULL;
1414
1415 // Prepare for auto-arrange?
1416 qsamplerChannelStrip *pChannelStrip = NULL;
1417 int y = 0;
1418 if (m_pOptions && m_pOptions->bAutoArrange) {
1419 QWidgetList wlist = m_pWorkspace->windowList();
1420 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1421 pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1422 // y += pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();
1423 y += pChannelStrip->parentWidget()->frameGeometry().height();
1424 }
1425 }
1426
1427 // Add a new channel itema...
1428 WFlags wflags = Qt::WStyle_Customize | Qt::WStyle_Tool | Qt::WStyle_Title | Qt::WStyle_NoBorder;
1429 pChannelStrip = new qsamplerChannelStrip(m_pWorkspace, 0, wflags);
1430 if (pChannelStrip == NULL)
1431 return NULL;
1432
1433 // Actual channel strip setup...
1434 pChannelStrip->setup(pChannel);
1435 QObject::connect(pChannelStrip, SIGNAL(channelChanged(qsamplerChannelStrip *)), this, SLOT(channelStripChanged(qsamplerChannelStrip *)));
1436 // Set some initial aesthetic options...
1437 if (m_pOptions) {
1438 // Background display effect...
1439 pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
1440 // We'll need a display font.
1441 QFont font;
1442 if (font.fromString(m_pOptions->sDisplayFont))
1443 pChannelStrip->setDisplayFont(font);
1444 // Maximum allowed volume setting.
1445 pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
1446 }
1447
1448 // Now we show up us to the world.
1449 pChannelStrip->show();
1450 // Only then, we'll auto-arrange...
1451 if (m_pOptions && m_pOptions->bAutoArrange) {
1452 int iWidth = m_pWorkspace->width();
1453 // int iHeight = pChannel->height() + pChannel->parentWidget()->baseSize().height();
1454 int iHeight = pChannelStrip->parentWidget()->frameGeometry().height();
1455 pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1456 }
1457
1458 // Return our successful reference...
1459 return pChannelStrip;
1460 }
1461
1462
1463 // Retrieve the active channel strip.
1464 qsamplerChannelStrip *qsamplerMainForm::activeChannelStrip (void)
1465 {
1466 return (qsamplerChannelStrip *) m_pWorkspace->activeWindow();
1467 }
1468
1469
1470 // Retrieve a channel strip by index.
1471 qsamplerChannelStrip *qsamplerMainForm::channelStripAt ( int iChannel )
1472 {
1473 QWidgetList wlist = m_pWorkspace->windowList();
1474 if (wlist.isEmpty())
1475 return 0;
1476
1477 return (qsamplerChannelStrip *) wlist.at(iChannel);
1478 }
1479
1480
1481 // Construct the windows menu.
1482 void qsamplerMainForm::channelsMenuAboutToShow (void)
1483 {
1484 channelsMenu->clear();
1485 channelsArrangeAction->addTo(channelsMenu);
1486 channelsAutoArrangeAction->addTo(channelsMenu);
1487
1488 QWidgetList wlist = m_pWorkspace->windowList();
1489 if (!wlist.isEmpty()) {
1490 channelsMenu->insertSeparator();
1491 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1492 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1493 if (pChannelStrip) {
1494 int iItemID = channelsMenu->insertItem(pChannelStrip->caption(), this, SLOT(channelsMenuActivated(int)));
1495 channelsMenu->setItemParameter(iItemID, iChannel);
1496 channelsMenu->setItemChecked(iItemID, activeChannelStrip() == pChannelStrip);
1497 }
1498 }
1499 }
1500 }
1501
1502
1503 // Windows menu activation slot
1504 void qsamplerMainForm::channelsMenuActivated ( int iChannel )
1505 {
1506 qsamplerChannelStrip *pChannelStrip = channelStripAt(iChannel);
1507 if (pChannelStrip)
1508 pChannelStrip->showNormal();
1509 pChannelStrip->setFocus();
1510 }
1511
1512
1513 //-------------------------------------------------------------------------
1514 // qsamplerMainForm -- Timer stuff.
1515
1516 // Set the pseudo-timer delay schedule.
1517 void qsamplerMainForm::startSchedule ( int iStartDelay )
1518 {
1519 m_iStartDelay = 1 + (iStartDelay * 1000);
1520 m_iTimerDelay = 0;
1521 }
1522
1523 // Suspend the pseudo-timer delay schedule.
1524 void qsamplerMainForm::stopSchedule (void)
1525 {
1526 m_iStartDelay = 0;
1527 m_iTimerDelay = 0;
1528 }
1529
1530 // Timer slot funtion.
1531 void qsamplerMainForm::timerSlot (void)
1532 {
1533 if (m_pOptions == NULL)
1534 return;
1535
1536 // Is it the first shot on server start after a few delay?
1537 if (m_iTimerDelay < m_iStartDelay) {
1538 m_iTimerDelay += QSAMPLER_TIMER_MSECS;
1539 if (m_iTimerDelay >= m_iStartDelay) {
1540 // If we cannot start it now, maybe a lil'mo'later ;)
1541 if (!startClient()) {
1542 m_iStartDelay += m_iTimerDelay;
1543 m_iTimerDelay = 0;
1544 }
1545 }
1546 }
1547
1548 // Refresh each channel usage, on each period...
1549 if (m_pClient && (m_iChangeCount > 0 || m_pOptions->bAutoRefresh)) {
1550 m_iTimerSlot += QSAMPLER_TIMER_MSECS;
1551 if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime && m_pWorkspace->isUpdatesEnabled()) {
1552 m_iTimerSlot = 0;
1553 m_iChangeCount = 0;
1554 QWidgetList wlist = m_pWorkspace->windowList();
1555 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1556 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1557 if (pChannelStrip && pChannelStrip->isVisible()) {
1558 // If we can't make it clean, try next time.
1559 if (!pChannelStrip->updateChannelUsage())
1560 m_iChangeCount++;
1561 }
1562 }
1563 }
1564 }
1565
1566 // Register the next timer slot.
1567 QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
1568 }
1569
1570
1571 //-------------------------------------------------------------------------
1572 // qsamplerMainForm -- Server stuff.
1573
1574 // Start linuxsampler server...
1575 void qsamplerMainForm::startServer (void)
1576 {
1577 if (m_pOptions == NULL)
1578 return;
1579
1580 // Aren't already a client, are we?
1581 if (!m_pOptions->bServerStart || m_pClient)
1582 return;
1583
1584 // Is the server process instance still here?
1585 if (m_pServer) {
1586 switch (QMessageBox::warning(this, tr("Warning"),
1587 tr("Could not start the LinuxSampler server.\n\n"
1588 "Maybe it ss already started."),
1589 tr("Stop"), tr("Kill"), tr("Cancel"))) {
1590 case 0:
1591 m_pServer->tryTerminate();
1592 break;
1593 case 1:
1594 m_pServer->kill();
1595 break;
1596 }
1597 return;
1598 }
1599
1600 // Reset our timer counters...
1601 stopSchedule();
1602
1603 // OK. Let's build the startup process...
1604 m_pServer = new QProcess(this);
1605
1606 // Setup stdout/stderr capture...
1607 //if (m_pOptions->bStdoutCapture) {
1608 m_pServer->setCommunication(QProcess::Stdout | QProcess::Stderr | QProcess::DupStderr);
1609 QObject::connect(m_pServer, SIGNAL(readyReadStdout()), this, SLOT(readServerStdout()));
1610 QObject::connect(m_pServer, SIGNAL(readyReadStderr()), this, SLOT(readServerStdout()));
1611 //}
1612 // The unforgiveable signal communication...
1613 QObject::connect(m_pServer, SIGNAL(processExited()), this, SLOT(processServerExit()));
1614
1615 // Build process arguments...
1616 m_pServer->setArguments(QStringList::split(' ', m_pOptions->sServerCmdLine));
1617
1618 appendMessages(tr("Server is starting..."));
1619 appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");
1620
1621 // Go jack, go...
1622 if (!m_pServer->start()) {
1623 appendMessagesError(tr("Could not start server.\n\nSorry."));
1624 processServerExit();
1625 return;
1626 }
1627
1628 // Show startup results...
1629 appendMessages(tr("Server was started with PID=%1.").arg((long) m_pServer->processIdentifier()));
1630
1631 // Reset (yet again) the timer counters,
1632 // but this time is deferred as the user opted.
1633 startSchedule(m_pOptions->iStartDelay);
1634 stabilizeForm();
1635 }
1636
1637
1638 // Stop linuxsampler server...
1639 void qsamplerMainForm::stopServer (void)
1640 {
1641 // Stop client code.
1642 stopClient();
1643
1644 // And try to stop server.
1645 if (m_pServer) {
1646 appendMessages(tr("Server is stopping..."));
1647 if (m_pServer->isRunning())
1648 m_pServer->tryTerminate();
1649 }
1650
1651 // Give it some time to terminate gracefully and stabilize...
1652 QTime t;
1653 t.start();
1654 while (t.elapsed() < QSAMPLER_TIMER_MSECS)
1655 QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
1656
1657 // Do final processing anyway.
1658 processServerExit();
1659 }
1660
1661
1662 // Stdout handler...
1663 void qsamplerMainForm::readServerStdout (void)
1664 {
1665 if (m_pMessages)
1666 m_pMessages->appendStdoutBuffer(m_pServer->readStdout());
1667 }
1668
1669
1670 // Linuxsampler server cleanup.
1671 void qsamplerMainForm::processServerExit (void)
1672 {
1673 // Force client code cleanup.
1674 stopClient();
1675
1676 // Flush anything that maybe pending...
1677 if (m_pMessages)
1678 m_pMessages->flushStdoutBuffer();
1679
1680 if (m_pServer) {
1681 // Force final server shutdown...
1682 appendMessages(tr("Server was stopped with exit status %1.").arg(m_pServer->exitStatus()));
1683 if (!m_pServer->normalExit())
1684 m_pServer->kill();
1685 // Destroy it.
1686 delete m_pServer;
1687 m_pServer = NULL;
1688 }
1689
1690 // Again, make status visible stable.
1691 stabilizeForm();
1692 }
1693
1694
1695 //-------------------------------------------------------------------------
1696 // qsamplerMainForm -- Client stuff.
1697
1698 // The LSCP client callback procedure.
1699 lscp_status_t qsampler_client_callback ( lscp_client_t */*pClient*/, lscp_event_t event, const char *pchData, int cchData, void *pvData )
1700 {
1701 qsamplerMainForm *pMainForm = (qsamplerMainForm *) pvData;
1702 if (pMainForm == NULL)
1703 return LSCP_FAILED;
1704
1705 // ATTN: DO NOT EVER call any GUI code here,
1706 // as this is run under some other thread context.
1707 // A custom event must be posted here...
1708 QApplication::postEvent(pMainForm, new qsamplerCustomEvent(event, pchData, cchData));
1709
1710 return LSCP_OK;
1711 }
1712
1713
1714 // Start our almighty client...
1715 bool qsamplerMainForm::startClient (void)
1716 {
1717 // Have it a setup?
1718 if (m_pOptions == NULL)
1719 return false;
1720
1721 // Aren't we already started, are we?
1722 if (m_pClient)
1723 return true;
1724
1725 // Log prepare here.
1726 appendMessages(tr("Client connecting..."));
1727
1728 // Create the client handle...
1729 m_pClient = ::lscp_client_create(m_pOptions->sServerHost.latin1(), m_pOptions->iServerPort, qsampler_client_callback, this);
1730 if (m_pClient == NULL) {
1731 // Is this the first try?
1732 // maybe we need to start a local server...
1733 if ((m_pServer && m_pServer->isRunning()) || !m_pOptions->bServerStart)
1734 appendMessagesError(tr("Could not connect to server as client.\n\nSorry."));
1735 else
1736 startServer();
1737 // This is always a failure.
1738 stabilizeForm();
1739 return false;
1740 }
1741 // Just set receive timeout value, blindly.
1742 ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);
1743 appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));
1744
1745 // We may stop scheduling around.
1746 stopSchedule();
1747
1748 // We'll accept drops from now on...
1749 setAcceptDrops(true);
1750
1751 // Log success here.
1752 appendMessages(tr("Client connected."));
1753
1754 // Is any session pending to be loaded?
1755 if (!m_pOptions->sSessionFile.isEmpty()) {
1756 // Just load the prabably startup session...
1757 if (loadSessionFile(m_pOptions->sSessionFile)) {
1758 m_pOptions->sSessionFile = QString::null;
1759 return true;
1760 }
1761 }
1762
1763 // Make a new session
1764 return newSession();
1765 }
1766
1767
1768 // Stop client...
1769 void qsamplerMainForm::stopClient (void)
1770 {
1771 if (m_pClient == NULL)
1772 return;
1773
1774 // Log prepare here.
1775 appendMessages(tr("Client disconnecting..."));
1776
1777 // Clear timer counters...
1778 stopSchedule();
1779
1780 // We'll reject drops from now on...
1781 setAcceptDrops(false);
1782
1783 // Force any channel strips around, but
1784 // but avoid removing the corresponding
1785 // channels from the back-end server.
1786 m_iDirtyCount = 0;
1787 closeSession(false);
1788
1789 // Close us as a client...
1790 lscp_client_destroy(m_pClient);
1791 m_pClient = NULL;
1792
1793 // Log final here.
1794 appendMessages(tr("Client disconnected."));
1795
1796 // Make visible status.
1797 stabilizeForm();
1798 }
1799
1800
1801 // end of qsamplerMainForm.ui.h

  ViewVC Help
Powered by ViewVC