/[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 267 - (show annotations) (download) (as text)
Wed Oct 6 15:42:59 2004 UTC (19 years, 5 months ago) by capela
File MIME type: text/x-c++hdr
File size: 55467 byte(s)
* Channel strip display glass effect is now an option.

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

  ViewVC Help
Powered by ViewVC