/[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 109 - (show annotations) (download) (as text)
Sat Jun 5 11:37:06 2004 UTC (19 years, 9 months ago) by capela
File MIME type: text/x-c++hdr
File size: 49570 byte(s)
Initial alpha release.

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

  ViewVC Help
Powered by ViewVC