/[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 265 - (show annotations) (download) (as text)
Wed Sep 29 16:05:24 2004 UTC (19 years, 6 months ago) by capela
File MIME type: text/x-c++hdr
File size: 54324 byte(s)
Continued rewrite of sampler channel strips internal control structures.

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

  ViewVC Help
Powered by ViewVC