/[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 145 - (show annotations) (download) (as text)
Thu Jun 24 18:26:57 2004 UTC (19 years, 9 months ago) by capela
File MIME type: text/x-c++hdr
File size: 50621 byte(s)
* Mon-modal intrument file loading and status experimental support.

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

  ViewVC Help
Powered by ViewVC