/[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 176 - (show annotations) (download) (as text)
Tue Jul 6 10:54:45 2004 UTC (19 years, 8 months ago) by capela
File MIME type: text/x-c++hdr
File size: 52083 byte(s)
* Channel dialog gets sensible engine and driver defaults
  on create time.

* Implied channel reset on successful instrument load.

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 << " " << pChannel->midiChannel() << endl;
606 ts << "LOAD ENGINE " << pChannel->engineName() << " " << iChannelID << endl;
607 ts << "LOAD INSTRUMENT NON_MODAL '" << pChannel->instrumentFile() << "' " << pChannel->instrumentNr() << " " << iChannelID << endl;
608 ts << "SET CHANNEL VOLUME " << iChannelID << " " << pChannel->volume() << endl;
609 ts << endl;
610 // Try to keep it snappy :)
611 QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
612 }
613
614 // Ok. we've wrote it.
615 file.close();
616
617 // Have we any errors?
618 if (iErrors > 0)
619 appendMessagesError(tr("Some settings could not be saved\nto \"%1\" session file.\n\nSorry.").arg(sFilename));
620
621 // Save as default session directory.
622 if (m_pOptions)
623 m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);
624 // We're not dirty anymore.
625 m_iDirtyCount = 0;
626 // Stabilize form...
627 m_sFilename = sFilename;
628 updateRecentFiles(sFilename);
629 appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename)));
630 stabilizeForm();
631 return true;
632 }
633
634
635 //-------------------------------------------------------------------------
636 // qsamplerMainForm -- File Action slots.
637
638 // Create a new sampler session.
639 void qsamplerMainForm::fileNew (void)
640 {
641 // Of course we'll start clean new.
642 newSession();
643 }
644
645
646 // Open an existing sampler session.
647 void qsamplerMainForm::fileOpen (void)
648 {
649 // Open it right away.
650 openSession();
651 }
652
653
654 // Open a recent file session.
655 void qsamplerMainForm::fileOpenRecent ( int iIndex )
656 {
657 // Check if we can safely close the current session...
658 if (m_pOptions && closeSession(true)) {
659 QString sFilename = m_pOptions->recentFiles[iIndex];
660 loadSessionFile(sFilename);
661 }
662 }
663
664
665 // Save current sampler session.
666 void qsamplerMainForm::fileSave (void)
667 {
668 // Save it right away.
669 saveSession(false);
670 }
671
672
673 // Save current sampler session with another name.
674 void qsamplerMainForm::fileSaveAs (void)
675 {
676 // Save it right away, maybe with another name.
677 saveSession(true);
678 }
679
680
681 // Restart the client/server instance.
682 void qsamplerMainForm::fileRestart (void)
683 {
684 if (m_pOptions == NULL)
685 return;
686
687 bool bRestart = true;
688
689 // Ask user whether he/she want's a complete restart...
690 // (if we're currently up and running)
691 if (bRestart && m_pClient) {
692 bRestart = (QMessageBox::warning(this, tr("Warning"),
693 tr("New settings will be effective after\n"
694 "restarting the client/server connection.\n\n"
695 "Please note that this operation may cause\n"
696 "temporary MIDI and Audio disruption\n\n"
697 "Do you want to restart the connection now?"),
698 tr("Restart"), tr("Cancel")) == 0);
699 }
700
701 // Are we still for it?
702 if (bRestart && closeSession(true)) {
703 // Stop server, it will force the client too.
704 stopServer();
705 // Reschedule a restart...
706 startSchedule(m_pOptions->iStartDelay);
707 }
708 }
709
710
711 // Exit application program.
712 void qsamplerMainForm::fileExit (void)
713 {
714 // Go for close the whole thing.
715 close();
716 }
717
718
719 //-------------------------------------------------------------------------
720 // qsamplerMainForm -- Edit Action slots.
721
722 // Add a new sampler channel.
723 void qsamplerMainForm::editAddChannel (void)
724 {
725 if (m_pClient == NULL)
726 return;
727
728 // Create the new sampler channel.
729 int iChannelID = ::lscp_add_channel(m_pClient);
730 if (iChannelID < 0) {
731 appendMessagesClient("lscp_add_channel");
732 appendMessagesError(tr("Could not create the new channel.\n\nSorry."));
733 return;
734 }
735
736 // Log this happening.
737 appendMessages(tr("Channel %1 created.").arg(iChannelID));
738
739 // Just create the channel strip with given id.
740 createChannel(iChannelID, true);
741
742 // We'll be dirty, for sure...
743 m_iDirtyCount++;
744 // Stabilize form anyway.
745 stabilizeForm();
746 }
747
748
749 // Remove current sampler channel.
750 void qsamplerMainForm::editRemoveChannel (void)
751 {
752 if (m_pClient == NULL)
753 return;
754
755 qsamplerChannelStrip *pChannel = activeChannel();
756 if (pChannel == NULL)
757 return;
758
759 // Prompt user if he/she's sure about this...
760 if (m_pOptions && m_pOptions->bConfirmRemove) {
761 if (QMessageBox::warning(this, tr("Warning"),
762 tr("About to remove channel:\n\n"
763 "%1\n\n"
764 "Are you sure?")
765 .arg(pChannel->caption()),
766 tr("OK"), tr("Cancel")) > 0)
767 return;
768 }
769
770 // Remove the existing sampler channel.
771 if (::lscp_remove_channel(m_pClient, pChannel->channelID()) != LSCP_OK) {
772 appendMessagesClient("lscp_remove_channel");
773 appendMessagesError(tr("Could not remove channel.\n\nSorry."));
774 return;
775 }
776
777 // Log this happening.
778 appendMessages(tr("Channel %1 removed.").arg(pChannel->channelID()));
779
780 // Just delete the channel strip.
781 delete pChannel;
782 // Do we auto-arrange?
783 if (m_pOptions && m_pOptions->bAutoArrange)
784 channelsArrange();
785
786 // We'll be dirty, for sure...
787 m_iDirtyCount++;
788 stabilizeForm();
789 }
790
791
792 // Setup current sampler channel.
793 void qsamplerMainForm::editSetupChannel (void)
794 {
795 if (m_pClient == NULL)
796 return;
797
798 qsamplerChannelStrip *pChannel = activeChannel();
799 if (pChannel == NULL)
800 return;
801
802 // Just invoque the channel strip procedure.
803 pChannel->channelSetup(false);
804 }
805
806
807 // Reset current sampler channel.
808 void qsamplerMainForm::editResetChannel (void)
809 {
810 if (m_pClient == NULL)
811 return;
812
813 qsamplerChannelStrip *pChannel = activeChannel();
814 if (pChannel == NULL)
815 return;
816
817 // Remove the existing sampler channel.
818 if (::lscp_reset_channel(m_pClient, pChannel->channelID()) != LSCP_OK) {
819 appendMessagesClient("lscp_reset_channel");
820 appendMessagesError(tr("Could not reset channel.\n\nSorry."));
821 return;
822 }
823
824 // Log this.
825 appendMessages(tr("Channel %1 reset.").arg(pChannel->channelID()));
826
827 // Refresh channel strip info.
828 pChannel->updateChannelInfo();
829 }
830
831
832 //-------------------------------------------------------------------------
833 // qsamplerMainForm -- View Action slots.
834
835 // Show/hide the main program window menubar.
836 void qsamplerMainForm::viewMenubar ( bool bOn )
837 {
838 if (bOn)
839 MenuBar->show();
840 else
841 MenuBar->hide();
842 }
843
844
845 // Show/hide the main program window toolbar.
846 void qsamplerMainForm::viewToolbar ( bool bOn )
847 {
848 if (bOn) {
849 fileToolbar->show();
850 editToolbar->show();
851 channelsToolbar->show();
852 } else {
853 fileToolbar->hide();
854 editToolbar->hide();
855 channelsToolbar->hide();
856 }
857 }
858
859
860 // Show/hide the main program window statusbar.
861 void qsamplerMainForm::viewStatusbar ( bool bOn )
862 {
863 if (bOn)
864 statusBar()->show();
865 else
866 statusBar()->hide();
867 }
868
869
870 // Show/hide the messages window logger.
871 void qsamplerMainForm::viewMessages ( bool bOn )
872 {
873 if (bOn)
874 m_pMessages->show();
875 else
876 m_pMessages->hide();
877 }
878
879
880 // Show options dialog.
881 void qsamplerMainForm::viewOptions (void)
882 {
883 if (m_pOptions == NULL)
884 return;
885
886 qsamplerOptionsForm *pOptionsForm = new qsamplerOptionsForm(this);
887 if (pOptionsForm) {
888 // Check out some initial nullities(tm)...
889 qsamplerChannelStrip *pChannel = activeChannel();
890 if (m_pOptions->sDisplayFont.isEmpty() && pChannel)
891 m_pOptions->sDisplayFont = pChannel->displayFont().toString();
892 if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages)
893 m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();
894 // To track down deferred or immediate changes.
895 QString sOldServerHost = m_pOptions->sServerHost;
896 int iOldServerPort = m_pOptions->iServerPort;
897 int iOldServerTimeout = m_pOptions->iServerTimeout;
898 bool bOldServerStart = m_pOptions->bServerStart;
899 QString sOldServerCmdLine = m_pOptions->sServerCmdLine;
900 QString sOldDisplayFont = m_pOptions->sDisplayFont;
901 int iOldMaxVolume = m_pOptions->iMaxVolume;
902 QString sOldMessagesFont = m_pOptions->sMessagesFont;
903 bool bOldStdoutCapture = m_pOptions->bStdoutCapture;
904 int bOldMessagesLimit = m_pOptions->bMessagesLimit;
905 int iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines;
906 bool bOldCompletePath = m_pOptions->bCompletePath;
907 int iOldMaxRecentFiles = m_pOptions->iMaxRecentFiles;
908 // Load the current setup settings.
909 pOptionsForm->setup(m_pOptions);
910 // Show the setup dialog...
911 if (pOptionsForm->exec()) {
912 // Warn if something will be only effective on next run.
913 if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) ||
914 (!bOldStdoutCapture && m_pOptions->bStdoutCapture)) {
915 QMessageBox::information(this, tr("Information"),
916 tr("Some settings may be only effective\n"
917 "next time you start this program."), tr("OK"));
918 updateMessagesCapture();
919 }
920 // Check wheather something immediate has changed.
921 if (( bOldCompletePath && !m_pOptions->bCompletePath) ||
922 (!bOldCompletePath && m_pOptions->bCompletePath) ||
923 (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles))
924 updateRecentFilesMenu();
925 if (sOldDisplayFont != m_pOptions->sDisplayFont)
926 updateDisplayFont();
927 if (iOldMaxVolume != m_pOptions->iMaxVolume)
928 updateMaxVolume();
929 if (sOldMessagesFont != m_pOptions->sMessagesFont)
930 updateMessagesFont();
931 if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) ||
932 (!bOldMessagesLimit && m_pOptions->bMessagesLimit) ||
933 (iOldMessagesLimitLines != m_pOptions->iMessagesLimitLines))
934 updateMessagesLimit();
935 // And now the main thing, whether we'll do client/server recycling?
936 if ((sOldServerHost != m_pOptions->sServerHost) ||
937 (iOldServerPort != m_pOptions->iServerPort) ||
938 (iOldServerTimeout != m_pOptions->iServerTimeout) ||
939 ( bOldServerStart && !m_pOptions->bServerStart) ||
940 (!bOldServerStart && m_pOptions->bServerStart) ||
941 (sOldServerCmdLine != m_pOptions->sServerCmdLine && m_pOptions->bServerStart))
942 fileRestart();
943 }
944 // Done.
945 delete pOptionsForm;
946 }
947
948 // This makes it.
949 stabilizeForm();
950 }
951
952
953 //-------------------------------------------------------------------------
954 // qsamplerMainForm -- Channels action slots.
955
956 // Arrange channel strips.
957 void qsamplerMainForm::channelsArrange (void)
958 {
959 // Full width vertical tiling
960 QWidgetList wlist = m_pWorkspace->windowList();
961 if (wlist.isEmpty())
962 return;
963
964 m_pWorkspace->setUpdatesEnabled(false);
965 int y = 0;
966 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
967 qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
968 /* if (pChannel->testWState(WState_Maximized | WState_Minimized)) {
969 // Prevent flicker...
970 pChannel->hide();
971 pChannel->showNormal();
972 } */
973 pChannel->adjustSize();
974 int iWidth = m_pWorkspace->width();
975 if (iWidth < pChannel->width())
976 iWidth = pChannel->width();
977 // int iHeight = pChannel->height() + pChannel->parentWidget()->baseSize().height();
978 int iHeight = pChannel->parentWidget()->frameGeometry().height();
979 pChannel->parentWidget()->setGeometry(0, y, iWidth, iHeight);
980 y += iHeight;
981 }
982 m_pWorkspace->setUpdatesEnabled(true);
983
984 stabilizeForm();
985 }
986
987
988 // Auto-arrange channel strips.
989 void qsamplerMainForm::channelsAutoArrange ( bool bOn )
990 {
991 if (m_pOptions == NULL)
992 return;
993
994 // Toggle the auto-arrange flag.
995 m_pOptions->bAutoArrange = bOn;
996
997 // If on, update whole workspace...
998 if (m_pOptions->bAutoArrange)
999 channelsArrange();
1000 }
1001
1002
1003 //-------------------------------------------------------------------------
1004 // qsamplerMainForm -- Help Action slots.
1005
1006 // Show information about the Qt toolkit.
1007 void qsamplerMainForm::helpAboutQt (void)
1008 {
1009 QMessageBox::aboutQt(this);
1010 }
1011
1012
1013 // Show information about application program.
1014 void qsamplerMainForm::helpAbout (void)
1015 {
1016 // Stuff the about box text...
1017 QString sText = "<p>\n";
1018 sText += "<b>" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "</b><br />\n";
1019 sText += "<br />\n";
1020 sText += tr("Version") + ": <b>" QSAMPLER_VERSION "</b><br />\n";
1021 sText += "<small>" + tr("Build") + ": " __DATE__ " " __TIME__ "</small><br />\n";
1022 #ifdef CONFIG_DEBUG
1023 sText += "<small><font color=\"red\">";
1024 sText += tr("Debugging option enabled.");
1025 sText += "</font></small><br />";
1026 #endif
1027 #ifndef CONFIG_LIBGIG
1028 sText += "<small><font color=\"red\">";
1029 sText += tr("GIG (libgig) file support disabled.");
1030 sText += "</font></small><br />";
1031 #endif
1032 sText += "<br />\n";
1033 sText += tr("Using") + ": ";
1034 sText += ::lscp_client_package();
1035 sText += " ";
1036 sText += ::lscp_client_version();
1037 sText += "<br />\n";
1038 sText += "<br />\n";
1039 sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";
1040 sText += "<br />\n";
1041 sText += "<small>";
1042 sText += QSAMPLER_COPYRIGHT "<br />\n";
1043 sText += "<br />\n";
1044 sText += tr("This program is free software; you can redistribute it and/or modify it") + "<br />\n";
1045 sText += tr("under the terms of the GNU General Public License version 2 or later.");
1046 sText += "</small>";
1047 sText += "</p>\n";
1048
1049 QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText);
1050 }
1051
1052
1053 //-------------------------------------------------------------------------
1054 // qsamplerMainForm -- Main window stabilization.
1055
1056 void qsamplerMainForm::stabilizeForm (void)
1057 {
1058 // Update the main application caption...
1059 QString sSessioName = sessionName(m_sFilename);
1060 if (m_iDirtyCount > 0)
1061 sSessioName += '*';
1062 setCaption(tr(QSAMPLER_TITLE " - [%1]").arg(sSessioName));
1063
1064 // Update the main menu state...
1065 qsamplerChannelStrip *pChannel = activeChannel();
1066 bool bHasClient = (m_pOptions != NULL && m_pClient != NULL);
1067 bool bHasChannel = (bHasClient && pChannel != NULL);
1068 fileNewAction->setEnabled(bHasClient);
1069 fileOpenAction->setEnabled(bHasClient);
1070 fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);
1071 fileSaveAsAction->setEnabled(bHasClient);
1072 fileRestartAction->setEnabled(bHasClient || m_pServer == NULL);
1073 editAddChannelAction->setEnabled(bHasClient);
1074 editRemoveChannelAction->setEnabled(bHasChannel);
1075 editSetupChannelAction->setEnabled(bHasChannel);
1076 editResetChannelAction->setEnabled(bHasChannel);
1077 channelsArrangeAction->setEnabled(bHasChannel);
1078 viewMessagesAction->setOn(m_pMessages && m_pMessages->isVisible());
1079
1080 // Client/Server status...
1081 if (bHasClient) {
1082 m_status[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));
1083 m_status[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost + ":" + QString::number(m_pOptions->iServerPort));
1084 } else {
1085 m_status[QSAMPLER_STATUS_CLIENT]->clear();
1086 m_status[QSAMPLER_STATUS_SERVER]->clear();
1087 }
1088 // Channel status...
1089 if (bHasChannel)
1090 m_status[QSAMPLER_STATUS_CHANNEL]->setText(pChannel->caption());
1091 else
1092 m_status[QSAMPLER_STATUS_CHANNEL]->clear();
1093 // Session status...
1094 if (m_iDirtyCount > 0)
1095 m_status[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));
1096 else
1097 m_status[QSAMPLER_STATUS_SESSION]->clear();
1098
1099 // Recent files menu.
1100 m_pRecentFilesMenu->setEnabled(bHasClient && m_pOptions->recentFiles.count() > 0);
1101
1102 // Always make the latest message visible.
1103 if (m_pMessages)
1104 m_pMessages->scrollToBottom();
1105 }
1106
1107
1108 // Channel change receiver slot.
1109 void qsamplerMainForm::channelChanged( qsamplerChannelStrip * )
1110 {
1111 // Just mark the dirty form.
1112 m_iDirtyCount++;
1113 // and update the form status...
1114 stabilizeForm();
1115 }
1116
1117
1118 // Update the recent files list and menu.
1119 void qsamplerMainForm::updateRecentFiles ( const QString& sFilename )
1120 {
1121 if (m_pOptions == NULL)
1122 return;
1123
1124 // Remove from list if already there (avoid duplicates)
1125 QStringList::Iterator iter = m_pOptions->recentFiles.find(sFilename);
1126 if (iter != m_pOptions->recentFiles.end())
1127 m_pOptions->recentFiles.remove(iter);
1128 // Put it to front...
1129 m_pOptions->recentFiles.push_front(sFilename);
1130
1131 // May update the menu.
1132 updateRecentFilesMenu();
1133 }
1134
1135
1136 // Update the recent files list and menu.
1137 void qsamplerMainForm::updateRecentFilesMenu (void)
1138 {
1139 if (m_pOptions == NULL)
1140 return;
1141
1142 // Time to keep the list under limits.
1143 int iRecentFiles = m_pOptions->recentFiles.count();
1144 while (iRecentFiles > m_pOptions->iMaxRecentFiles) {
1145 m_pOptions->recentFiles.pop_back();
1146 iRecentFiles--;
1147 }
1148
1149 // rebuild the recent files menu...
1150 m_pRecentFilesMenu->clear();
1151 for (int i = 0; i < iRecentFiles; i++) {
1152 const QString& sFilename = m_pOptions->recentFiles[i];
1153 if (QFileInfo(sFilename).exists()) {
1154 m_pRecentFilesMenu->insertItem(QString("&%1 %2")
1155 .arg(i + 1).arg(sessionName(sFilename)),
1156 this, SLOT(fileOpenRecent(int)), 0, i);
1157 }
1158 }
1159 }
1160
1161
1162 // Force update of the channels display font.
1163 void qsamplerMainForm::updateDisplayFont (void)
1164 {
1165 if (m_pOptions == NULL)
1166 return;
1167
1168 // Check if display font is legal.
1169 if (m_pOptions->sDisplayFont.isEmpty())
1170 return;
1171 // Realize it.
1172 QFont font;
1173 if (!font.fromString(m_pOptions->sDisplayFont))
1174 return;
1175
1176 // Full channel list update...
1177 QWidgetList wlist = m_pWorkspace->windowList();
1178 if (wlist.isEmpty())
1179 return;
1180
1181 m_pWorkspace->setUpdatesEnabled(false);
1182 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1183 qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1184 pChannel->setDisplayFont(font);
1185 }
1186 m_pWorkspace->setUpdatesEnabled(true);
1187 }
1188
1189
1190 // Force update of the channels maximum volume setting.
1191 void qsamplerMainForm::updateMaxVolume (void)
1192 {
1193 if (m_pOptions == NULL)
1194 return;
1195
1196 // Full channel list update...
1197 QWidgetList wlist = m_pWorkspace->windowList();
1198 if (wlist.isEmpty())
1199 return;
1200
1201 m_pWorkspace->setUpdatesEnabled(false);
1202 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1203 qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1204 pChannel->setMaxVolume(m_pOptions->iMaxVolume);
1205 }
1206 m_pWorkspace->setUpdatesEnabled(true);
1207 }
1208
1209
1210 //-------------------------------------------------------------------------
1211 // qsamplerMainForm -- Messages window form handlers.
1212
1213 // Messages output methods.
1214 void qsamplerMainForm::appendMessages( const QString& s )
1215 {
1216 if (m_pMessages)
1217 m_pMessages->appendMessages(s);
1218
1219 statusBar()->message(s, 3000);
1220 }
1221
1222 void qsamplerMainForm::appendMessagesColor( const QString& s, const QString& c )
1223 {
1224 if (m_pMessages)
1225 m_pMessages->appendMessagesColor(s, c);
1226
1227 statusBar()->message(s, 3000);
1228 }
1229
1230 void qsamplerMainForm::appendMessagesText( const QString& s )
1231 {
1232 if (m_pMessages)
1233 m_pMessages->appendMessagesText(s);
1234 }
1235
1236 void qsamplerMainForm::appendMessagesError( const QString& s )
1237 {
1238 if (m_pMessages)
1239 m_pMessages->show();
1240
1241 appendMessagesColor(s.simplifyWhiteSpace(), "#ff0000");
1242
1243 QMessageBox::critical(this, tr("Error"), s, tr("Cancel"));
1244 }
1245
1246
1247 // This is a special message format, just for client results.
1248 void qsamplerMainForm::appendMessagesClient( const QString& s )
1249 {
1250 if (m_pClient == NULL)
1251 return;
1252
1253 appendMessagesColor(s + QString(": %1 (errno=%2)")
1254 .arg(::lscp_client_get_result(m_pClient))
1255 .arg(::lscp_client_get_errno(m_pClient)), "#996666");
1256 }
1257
1258
1259 // Force update of the messages font.
1260 void qsamplerMainForm::updateMessagesFont (void)
1261 {
1262 if (m_pOptions == NULL)
1263 return;
1264
1265 if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {
1266 QFont font;
1267 if (font.fromString(m_pOptions->sMessagesFont))
1268 m_pMessages->setMessagesFont(font);
1269 }
1270 }
1271
1272
1273 // Update messages window line limit.
1274 void qsamplerMainForm::updateMessagesLimit (void)
1275 {
1276 if (m_pOptions == NULL)
1277 return;
1278
1279 if (m_pMessages) {
1280 if (m_pOptions->bMessagesLimit)
1281 m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);
1282 else
1283 m_pMessages->setMessagesLimit(0);
1284 }
1285 }
1286
1287
1288 // Enablement of the messages capture feature.
1289 void qsamplerMainForm::updateMessagesCapture (void)
1290 {
1291 if (m_pOptions == NULL)
1292 return;
1293
1294 if (m_pMessages)
1295 m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);
1296 }
1297
1298
1299 //-------------------------------------------------------------------------
1300 // qsamplerMainForm -- MDI channel strip management.
1301
1302 // The channel strip creation executive.
1303 void qsamplerMainForm::createChannel ( int iChannelID, bool bPrompt )
1304 {
1305 if (m_pClient == NULL)
1306 return;
1307
1308 // Prepare for auto-arrange?
1309 qsamplerChannelStrip *pChannel = NULL;
1310 int y = 0;
1311 if (m_pOptions && m_pOptions->bAutoArrange) {
1312 QWidgetList wlist = m_pWorkspace->windowList();
1313 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1314 pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1315 // y += pChannel->height() + pChannel->parentWidget()->baseSize().height();
1316 y += pChannel->parentWidget()->frameGeometry().height();
1317 }
1318 }
1319
1320 // Add a new channel itema...
1321 WFlags wflags = Qt::WStyle_Customize | Qt::WStyle_Tool | Qt::WStyle_Title | Qt::WStyle_NoBorder;
1322 pChannel = new qsamplerChannelStrip(m_pWorkspace, 0, wflags);
1323 pChannel->setMaxVolume(m_pOptions->iMaxVolume);
1324 pChannel->setup(this, iChannelID);
1325 // We'll need a display font.
1326 QFont font;
1327 if (m_pOptions && font.fromString(m_pOptions->sDisplayFont))
1328 pChannel->setDisplayFont(font);
1329 // Track channel setup changes.
1330 QObject::connect(pChannel, SIGNAL(channelChanged(qsamplerChannelStrip *)), this, SLOT(channelChanged(qsamplerChannelStrip *)));
1331 // Before we show it up, may be we'll
1332 // better ask for some initial values?
1333 if (bPrompt)
1334 pChannel->channelSetup(true);
1335 // Now we show up us to the world.
1336 pChannel->show();
1337 // Only then, we'll auto-arrange...
1338 if (m_pOptions && m_pOptions->bAutoArrange) {
1339 int iWidth = m_pWorkspace->width();
1340 // int iHeight = pChannel->height() + pChannel->parentWidget()->baseSize().height();
1341 int iHeight = pChannel->parentWidget()->frameGeometry().height();
1342 pChannel->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1343 }
1344 }
1345
1346
1347 // Retrieve the active channel strip.
1348 qsamplerChannelStrip *qsamplerMainForm::activeChannel (void)
1349 {
1350 return (qsamplerChannelStrip *) m_pWorkspace->activeWindow();
1351 }
1352
1353
1354 // Retrieve a channel strip by index.
1355 qsamplerChannelStrip *qsamplerMainForm::channelAt ( int iChannel )
1356 {
1357 QWidgetList wlist = m_pWorkspace->windowList();
1358 if (wlist.isEmpty())
1359 return 0;
1360
1361 return (qsamplerChannelStrip *) wlist.at(iChannel);
1362 }
1363
1364
1365 // Construct the windows menu.
1366 void qsamplerMainForm::channelsMenuAboutToShow (void)
1367 {
1368 channelsMenu->clear();
1369 channelsArrangeAction->addTo(channelsMenu);
1370 channelsAutoArrangeAction->addTo(channelsMenu);
1371
1372 QWidgetList wlist = m_pWorkspace->windowList();
1373 if (!wlist.isEmpty()) {
1374 channelsMenu->insertSeparator();
1375 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1376 qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1377 int iItemID = channelsMenu->insertItem(pChannel->caption(), this, SLOT(channelsMenuActivated(int)));
1378 channelsMenu->setItemParameter(iItemID, iChannel);
1379 channelsMenu->setItemChecked(iItemID, activeChannel() == pChannel);
1380 }
1381 }
1382 }
1383
1384
1385 // Windows menu activation slot
1386 void qsamplerMainForm::channelsMenuActivated ( int iChannel )
1387 {
1388 qsamplerChannelStrip *pChannel = channelAt(iChannel);
1389 if (pChannel)
1390 pChannel->showNormal();
1391 pChannel->setFocus();
1392 }
1393
1394
1395 //-------------------------------------------------------------------------
1396 // qsamplerMainForm -- Timer stuff.
1397
1398 // Set the pseudo-timer delay schedule.
1399 void qsamplerMainForm::startSchedule ( int iStartDelay )
1400 {
1401 m_iStartDelay = 1 + (iStartDelay * 1000);
1402 m_iTimerDelay = 0;
1403 }
1404
1405 // Suspend the pseudo-timer delay schedule.
1406 void qsamplerMainForm::stopSchedule (void)
1407 {
1408 m_iStartDelay = 0;
1409 m_iTimerDelay = 0;
1410 }
1411
1412 // Timer slot funtion.
1413 void qsamplerMainForm::timerSlot (void)
1414 {
1415 if (m_pOptions == NULL)
1416 return;
1417
1418 // Is it the first shot on server start after a few delay?
1419 if (m_iTimerDelay < m_iStartDelay) {
1420 m_iTimerDelay += QSAMPLER_TIMER_MSECS;
1421 if (m_iTimerDelay >= m_iStartDelay) {
1422 // If we cannot start it now, maybe a lil'mo'later ;)
1423 if (!startClient()) {
1424 m_iStartDelay += m_iTimerDelay;
1425 m_iTimerDelay = 0;
1426 }
1427 }
1428 }
1429
1430 // Refresh each channel usage, on each period...
1431 if (m_pClient && m_pOptions->bAutoRefresh && m_pWorkspace->isUpdatesEnabled()) {
1432 m_iTimerSlot += QSAMPLER_TIMER_MSECS;
1433 if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime) {
1434 m_iTimerSlot = 0;
1435 QWidgetList wlist = m_pWorkspace->windowList();
1436 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1437 qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1438 if (pChannel->isVisible())
1439 pChannel->updateChannelUsage();
1440 }
1441 }
1442 }
1443
1444 // Register the next timer slot.
1445 QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
1446 }
1447
1448
1449 //-------------------------------------------------------------------------
1450 // qsamplerMainForm -- Server stuff.
1451
1452 // Start linuxsampler server...
1453 void qsamplerMainForm::startServer (void)
1454 {
1455 if (m_pOptions == NULL)
1456 return;
1457
1458 // Aren't already a client, are we?
1459 if (!m_pOptions->bServerStart || m_pClient)
1460 return;
1461
1462 // Is the server process instance still here?
1463 if (m_pServer) {
1464 switch (QMessageBox::warning(this, tr("Warning"),
1465 tr("Could not start the LinuxSampler server.\n\n"
1466 "Maybe it ss already started."),
1467 tr("Stop"), tr("Kill"), tr("Cancel"))) {
1468 case 0:
1469 m_pServer->tryTerminate();
1470 break;
1471 case 1:
1472 m_pServer->kill();
1473 break;
1474 }
1475 return;
1476 }
1477
1478 // Reset our timer counters...
1479 stopSchedule();
1480
1481 // OK. Let's build the startup process...
1482 m_pServer = new QProcess(this);
1483
1484 // Setup stdout/stderr capture...
1485 //if (m_pOptions->bStdoutCapture) {
1486 m_pServer->setCommunication(QProcess::Stdout | QProcess::Stderr | QProcess::DupStderr);
1487 QObject::connect(m_pServer, SIGNAL(readyReadStdout()), this, SLOT(readServerStdout()));
1488 QObject::connect(m_pServer, SIGNAL(readyReadStderr()), this, SLOT(readServerStdout()));
1489 //}
1490 // The unforgiveable signal communication...
1491 QObject::connect(m_pServer, SIGNAL(processExited()), this, SLOT(processServerExit()));
1492
1493 // Build process arguments...
1494 m_pServer->setArguments(QStringList::split(' ', m_pOptions->sServerCmdLine));
1495
1496 appendMessages(tr("Server is starting..."));
1497 appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");
1498
1499 // Go jack, go...
1500 if (!m_pServer->start()) {
1501 appendMessagesError(tr("Could not start server.\n\nSorry."));
1502 processServerExit();
1503 return;
1504 }
1505
1506 // Show startup results...
1507 appendMessages(tr("Server was started with PID=%1.").arg((long) m_pServer->processIdentifier()));
1508
1509 // Reset (yet again) the timer counters,
1510 // but this time is deferred as the user opted.
1511 startSchedule(m_pOptions->iStartDelay);
1512 stabilizeForm();
1513 }
1514
1515
1516 // Stop linuxsampler server...
1517 void qsamplerMainForm::stopServer (void)
1518 {
1519 // Stop client code.
1520 stopClient();
1521
1522 // And try to stop server.
1523 if (m_pServer) {
1524 appendMessages(tr("Server is stopping..."));
1525 if (m_pServer->isRunning())
1526 m_pServer->tryTerminate();
1527 }
1528
1529 // Give it some time to terminate gracefully and stabilize...
1530 QTime t;
1531 t.start();
1532 while (t.elapsed() < QSAMPLER_TIMER_MSECS)
1533 QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
1534
1535 // Do final processing anyway.
1536 processServerExit();
1537 }
1538
1539
1540 // Stdout handler...
1541 void qsamplerMainForm::readServerStdout (void)
1542 {
1543 if (m_pMessages)
1544 m_pMessages->appendStdoutBuffer(m_pServer->readStdout());
1545 }
1546
1547
1548 // Linuxsampler server cleanup.
1549 void qsamplerMainForm::processServerExit (void)
1550 {
1551 // Force client code cleanup.
1552 stopClient();
1553
1554 // Flush anything that maybe pending...
1555 if (m_pMessages)
1556 m_pMessages->flushStdoutBuffer();
1557
1558 if (m_pServer) {
1559 // Force final server shutdown...
1560 appendMessages(tr("Server was stopped with exit status %1.").arg(m_pServer->exitStatus()));
1561 if (!m_pServer->normalExit())
1562 m_pServer->kill();
1563 // Destroy it.
1564 delete m_pServer;
1565 m_pServer = NULL;
1566 }
1567
1568 // Again, make status visible stable.
1569 stabilizeForm();
1570 }
1571
1572
1573 //-------------------------------------------------------------------------
1574 // qsamplerMainForm -- Client stuff.
1575
1576 // The LSCP client callback procedure.
1577 lscp_status_t qsampler_client_callback ( lscp_client_t */*pClient*/, lscp_event_t event, const char *pchData, int cchData, void *pvData )
1578 {
1579 qsamplerMainForm *pMainForm = (qsamplerMainForm *) pvData;
1580 if (pMainForm == NULL)
1581 return LSCP_FAILED;
1582
1583 // ATTN: DO NOT EVER call any GUI code here,
1584 // as this is run under some other thread context.
1585 // A custom event must be posted here...
1586 QApplication::postEvent(pMainForm, new qsamplerCustomEvent(event, pchData, cchData));
1587
1588 return LSCP_OK;
1589 }
1590
1591
1592 // Start our almighty client...
1593 bool qsamplerMainForm::startClient (void)
1594 {
1595 // Have it a setup?
1596 if (m_pOptions == NULL)
1597 return false;
1598
1599 // Aren't we already started, are we?
1600 if (m_pClient)
1601 return true;
1602
1603 // Log prepare here.
1604 appendMessages(tr("Client connecting..."));
1605
1606 // Create the client handle...
1607 m_pClient = ::lscp_client_create(m_pOptions->sServerHost.latin1(), m_pOptions->iServerPort, qsampler_client_callback, this);
1608 if (m_pClient == NULL) {
1609 // Is this the first try?
1610 // maybe we need to start a local server...
1611 if ((m_pServer && m_pServer->isRunning()) || !m_pOptions->bServerStart)
1612 appendMessagesError(tr("Could not connect to server as client.\n\nSorry."));
1613 else
1614 startServer();
1615 // This is always a failure.
1616 stabilizeForm();
1617 return false;
1618 }
1619 // Just set receive timeout value, blindly.
1620 ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);
1621 appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));
1622
1623 // We may stop scheduling around.
1624 stopSchedule();
1625
1626 // We'll accept drops from now on...
1627 setAcceptDrops(true);
1628
1629 // Log success here.
1630 appendMessages(tr("Client connected."));
1631
1632 // Is any session pending to be loaded?
1633 if (!m_pOptions->sSessionFile.isEmpty()) {
1634 // Just load the prabably startup session...
1635 if (loadSessionFile(m_pOptions->sSessionFile)) {
1636 m_pOptions->sSessionFile = QString::null;
1637 return true;
1638 }
1639 }
1640
1641 // Make a new session
1642 return newSession();
1643 }
1644
1645
1646 // Stop client...
1647 void qsamplerMainForm::stopClient (void)
1648 {
1649 if (m_pClient == NULL)
1650 return;
1651
1652 // Log prepare here.
1653 appendMessages(tr("Client disconnecting..."));
1654
1655 // Clear timer counters...
1656 stopSchedule();
1657
1658 // We'll reject drops from now on...
1659 setAcceptDrops(false);
1660
1661 // Force any channel strips around, but
1662 // but avoid removing the corresponding
1663 // channels from the back-end server.
1664 m_iDirtyCount = 0;
1665 closeSession(false);
1666
1667 // Close us as a client...
1668 lscp_client_destroy(m_pClient);
1669 m_pClient = NULL;
1670
1671 // Log final here.
1672 appendMessages(tr("Client disconnected."));
1673
1674 // Make visible status.
1675 stabilizeForm();
1676 }
1677
1678
1679 // end of qsamplerMainForm.ui.h

  ViewVC Help
Powered by ViewVC