/[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 261 - (show annotations) (download) (as text)
Wed Sep 29 07:43:26 2004 UTC (15 years, 3 months ago) by capela
File MIME type: text/x-c++hdr
File size: 53168 byte(s)
Sampler reset info message; asterisk for midi all channels input.

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

  ViewVC Help
Powered by ViewVC