/[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 119 - (show annotations) (download) (as text)
Wed Jun 9 20:24:48 2004 UTC (19 years, 9 months ago) by capela
File MIME type: text/x-c++hdr
File size: 50319 byte(s)
* Maximum channel volume percent setting is now a global option,
  provided to override the default (which is 100%).

* Client/server transaction timeout option upper limit has been
  increased from 5000 to 60000 milliseconds.

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 void qsamplerMainForm::dragEnterEvent ( QDragEnterEvent* pDragEnterEvent )
256 {
257 bool bAccept = false;
258
259 if (QTextDrag::canDecode(pDragEnterEvent)) {
260 QString sUrl;
261 if (QTextDrag::decode(pDragEnterEvent, sUrl) && m_pClient)
262 bAccept = QFileInfo(QUrl(sUrl).path()).exists();
263 }
264
265 pDragEnterEvent->accept(bAccept);
266 }
267
268
269 void qsamplerMainForm::dropEvent ( QDropEvent* pDropEvent )
270 {
271 if (QTextDrag::canDecode(pDropEvent)) {
272 QString sUrl;
273 if (QTextDrag::decode(pDropEvent, sUrl) && closeSession(true))
274 loadSessionFile(QUrl(sUrl).path());
275 }
276 }
277
278
279 //-------------------------------------------------------------------------
280 // qsamplerMainForm -- Brainless public property accessors.
281
282 // The global options settings property.
283 qsamplerOptions *qsamplerMainForm::options (void)
284 {
285 return m_pOptions;
286 }
287
288 // The LSCP client descriptor property.
289 lscp_client_t *qsamplerMainForm::client (void)
290 {
291 return m_pClient;
292 }
293
294
295 //-------------------------------------------------------------------------
296 // qsamplerMainForm -- Session file stuff.
297
298 // Format the displayable session filename.
299 QString qsamplerMainForm::sessionName ( const QString& sFilename )
300 {
301 bool bCompletePath = (m_pOptions && m_pOptions->bCompletePath);
302 QString sSessionName = sFilename;
303 if (sSessionName.isEmpty())
304 sSessionName = tr("Untitled") + QString::number(m_iUntitled);
305 else if (!bCompletePath)
306 sSessionName = QFileInfo(sSessionName).fileName();
307 return sSessionName;
308 }
309
310
311 // Create a new session file from scratch.
312 bool qsamplerMainForm::newSession (void)
313 {
314 // Check if we can do it.
315 if (!closeSession(true))
316 return false;
317
318 // Ok increment untitled count.
319 m_iUntitled++;
320
321 // Stabilize form.
322 m_sFilename = QString::null;
323 m_iDirtyCount = 0;
324 appendMessages(tr("New session: \"%1\".").arg(sessionName(m_sFilename)));
325 stabilizeForm();
326
327 return true;
328 }
329
330
331 // Open an existing sampler session.
332 bool qsamplerMainForm::openSession (void)
333 {
334 if (m_pOptions == NULL)
335 return false;
336
337 // Ask for the filename to open...
338 QString sFilename = QFileDialog::getOpenFileName(
339 m_pOptions->sSessionDir, // Start here.
340 tr("LSCP Session files") + " (*.lscp)", // Filter (LSCP files)
341 this, 0, // Parent and name (none)
342 tr("Open Session") // Caption.
343 );
344
345 // Have we cancelled?
346 if (sFilename.isEmpty())
347 return false;
348
349 // Check if we're going to discard safely the current one...
350 if (!closeSession(true))
351 return false;
352
353 // Load it right away.
354 return loadSessionFile(sFilename);
355 }
356
357
358 // Save current sampler session with another name.
359 bool qsamplerMainForm::saveSession ( bool bPrompt )
360 {
361 if (m_pOptions == NULL)
362 return false;
363
364 QString sFilename = m_sFilename;
365
366 // Ask for the file to save, if there's none...
367 if (bPrompt || sFilename.isEmpty()) {
368 // If none is given, assume default directory.
369 if (sFilename.isEmpty())
370 sFilename = m_pOptions->sSessionDir;
371 // Prompt the guy...
372 sFilename = QFileDialog::getSaveFileName(
373 sFilename, // Start here.
374 tr("LSCP Session files") + " (*.lscp)", // Filter (LSCP files)
375 this, 0, // Parent and name (none)
376 tr("Save Session") // Caption.
377 );
378 // Have we cancelled it?
379 if (sFilename.isEmpty())
380 return false;
381 // Enforce .lscp extension...
382 if (QFileInfo(sFilename).extension().isEmpty())
383 sFilename += ".lscp";
384 // Check if already exists...
385 if (sFilename != m_sFilename && QFileInfo(sFilename).exists()) {
386 if (QMessageBox::warning(this, tr("Warning"),
387 tr("The file already exists:\n\n"
388 "\"%1\"\n\n"
389 "Do you want to replace it?")
390 .arg(sFilename),
391 tr("Replace"), tr("Cancel")) > 0)
392 return false;
393 }
394 }
395
396 // Save it right away.
397 return saveSessionFile(sFilename);
398 }
399
400
401 // Close current session.
402 bool qsamplerMainForm::closeSession ( bool bForce )
403 {
404 bool bClose = true;
405
406 // Are we dirty enough to prompt it?
407 if (m_iDirtyCount > 0) {
408 switch (QMessageBox::warning(this, tr("Warning"),
409 tr("The current session has been changed:\n\n"
410 "\"%1\"\n\n"
411 "Do you want to save the changes?")
412 .arg(sessionName(m_sFilename)),
413 tr("Save"), tr("Discard"), tr("Cancel"))) {
414 case 0: // Save...
415 bClose = saveSession(false);
416 // Fall thru....
417 case 1: // Discard
418 break;
419 default: // Cancel.
420 bClose = false;
421 break;
422 }
423 }
424
425 // If we may close it, dot it.
426 if (bClose) {
427 // Remove all channel strips from sight...
428 m_pWorkspace->setUpdatesEnabled(false);
429 QWidgetList wlist = m_pWorkspace->windowList();
430 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
431 qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
432 if (bForce && ::lscp_remove_channel(m_pClient, pChannel->channelID()) != LSCP_OK)
433 appendMessagesClient("lscp_remove_channel");
434 delete pChannel;
435 }
436 m_pWorkspace->setUpdatesEnabled(true);
437 // We're now clean, for sure.
438 m_iDirtyCount = 0;
439 }
440
441 return bClose;
442 }
443
444
445 // Load a session from specific file path.
446 bool qsamplerMainForm::loadSessionFile ( const QString& sFilename )
447 {
448 if (m_pClient == NULL)
449 return false;
450
451 // Open and read from real file.
452 QFile file(sFilename);
453 if (!file.open(IO_ReadOnly)) {
454 appendMessagesError(tr("Could not open \"%1\" session file.\n\nSorry.").arg(sFilename));
455 return false;
456 }
457
458 // Read the file.
459 int iErrors = 0;
460 QTextStream ts(&file);
461 while (!ts.atEnd()) {
462 // Read the line.
463 QString sCommand = ts.readLine().simplifyWhiteSpace();
464 // If not empty, nor a comment, call the server...
465 if (!sCommand.isEmpty() && sCommand[0] != '#') {
466 appendMessagesColor(sCommand, "#996633");
467 // Remember that, no matter what,
468 // all LSCP commands are CR/LF terminated.
469 sCommand += "\r\n";
470 if (::lscp_client_query(m_pClient, sCommand.latin1()) != LSCP_OK) {
471 appendMessagesClient("lscp_client_query");
472 iErrors++;
473 }
474 }
475 // Try to make it snappy :)
476 QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
477 }
478
479 // Ok. we've read it.
480 file.close();
481
482 // Have we any errors?
483 if (iErrors > 0)
484 appendMessagesError(tr("Some setttings could not be loaded\nfrom \"%1\" session file.\n\nSorry.").arg(sFilename));
485
486 // Now we'll try to create the whole GUI session.
487 int iChannels = ::lscp_get_channels(m_pClient);
488 if (iChannels < 0) {
489 appendMessagesClient("lscp_get_channels");
490 appendMessagesError(tr("Could not get current number of channels.\n\nSorry."));
491 }
492
493 // Try to (re)create each channel.
494 m_pWorkspace->setUpdatesEnabled(false);
495 for (int iChannelID = 0; iChannelID < iChannels; iChannelID++) {
496 createChannel(iChannelID, false);
497 QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
498 }
499 m_pWorkspace->setUpdatesEnabled(true);
500
501 // Save as default session directory.
502 if (m_pOptions)
503 m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);
504 // We're not dirty anymore.
505 m_iDirtyCount = 0;
506 // Stabilize form...
507 m_sFilename = sFilename;
508 updateRecentFiles(sFilename);
509 appendMessages(tr("Open session: \"%1\".").arg(sessionName(m_sFilename)));
510 stabilizeForm();
511 return true;
512 }
513
514
515 // Save current session to specific file path.
516 bool qsamplerMainForm::saveSessionFile ( const QString& sFilename )
517 {
518 // Open and write into real file.
519 QFile file(sFilename);
520 if (!file.open(IO_WriteOnly | IO_Truncate)) {
521 appendMessagesError(tr("Could not open \"%1\" session file.\n\nSorry.").arg(sFilename));
522 return false;
523 }
524
525 // Write the file.
526 int iErrors = 0;
527 QTextStream ts(&file);
528 ts << "# " << QSAMPLER_TITLE " - " << tr(QSAMPLER_SUBTITLE) << endl;
529 ts << "# " << tr("Version")
530 << ": " QSAMPLER_VERSION << endl;
531 ts << "# " << tr("Build")
532 << ": " __DATE__ " " __TIME__ << endl;
533 ts << "#" << endl;
534 ts << "# " << tr("File")
535 << ": " << QFileInfo(sFilename).fileName() << endl;
536 ts << "# " << tr("Date")
537 << ": " << QDate::currentDate().toString("MMMM dd yyyy")
538 << " " << QTime::currentTime().toString("hh:mm:ss") << endl;
539 ts << "#" << endl;
540 ts << endl;
541 QWidgetList wlist = m_pWorkspace->windowList();
542 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
543 qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
544 int iChannelID = pChannel->channelID();
545 ts << "# " << pChannel->caption() << endl;
546 ts << "ADD CHANNEL" << endl;
547 ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannelID << " " << pChannel->audioDriver() << endl;
548 ts << "SET CHANNEL MIDI_INPUT_TYPE " << iChannelID << " " << pChannel->midiDriver() << endl;
549 // ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannelID << " " << pChannel->midiPort() << endl;
550 ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannelID << " " << pChannel->midiChannel() << endl;
551 ts << "LOAD ENGINE " << pChannel->engineName() << " " << iChannelID << endl;
552 ts << "LOAD INSTRUMENT " << pChannel->instrumentFile() << " " << pChannel->instrumentNr() << " " << iChannelID << endl;
553 ts << "SET CHANNEL VOLUME " << iChannelID << " " << pChannel->volume() << endl;
554 ts << endl;
555 // Try to keep it snappy :)
556 QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
557 }
558
559 // Ok. we've wrote it.
560 file.close();
561
562 // Have we any errors?
563 if (iErrors > 0)
564 appendMessagesError(tr("Some settings could not be saved\nto \"%1\" session file.\n\nSorry.").arg(sFilename));
565
566 // Save as default session directory.
567 if (m_pOptions)
568 m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);
569 // We're not dirty anymore.
570 m_iDirtyCount = 0;
571 // Stabilize form...
572 m_sFilename = sFilename;
573 updateRecentFiles(sFilename);
574 appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename)));
575 stabilizeForm();
576 return true;
577 }
578
579
580 //-------------------------------------------------------------------------
581 // qsamplerMainForm -- File Action slots.
582
583 // Create a new sampler session.
584 void qsamplerMainForm::fileNew (void)
585 {
586 // Of course we'll start clean new.
587 newSession();
588 }
589
590
591 // Open an existing sampler session.
592 void qsamplerMainForm::fileOpen (void)
593 {
594 // Open it right away.
595 openSession();
596 }
597
598
599 // Open a recent file session.
600 void qsamplerMainForm::fileOpenRecent ( int iIndex )
601 {
602 // Check if we can safely close the current session...
603 if (m_pOptions && closeSession(true)) {
604 QString sFilename = m_pOptions->recentFiles[iIndex];
605 loadSessionFile(sFilename);
606 }
607 }
608
609
610 // Save current sampler session.
611 void qsamplerMainForm::fileSave (void)
612 {
613 // Save it right away.
614 saveSession(false);
615 }
616
617
618 // Save current sampler session with another name.
619 void qsamplerMainForm::fileSaveAs (void)
620 {
621 // Save it right away, maybe with another name.
622 saveSession(true);
623 }
624
625
626 // Restart the client/server instance.
627 void qsamplerMainForm::fileRestart (void)
628 {
629 if (m_pOptions == NULL)
630 return;
631
632 bool bRestart = true;
633
634 // Ask user whether he/she want's a complete restart...
635 // (if we're currently up and running)
636 if (bRestart && m_pClient) {
637 bRestart = (QMessageBox::warning(this, tr("Warning"),
638 tr("New settings will be effective after\n"
639 "restarting the client/server connection.\n\n"
640 "Please note that this operation may cause\n"
641 "temporary MIDI and Audio disruption\n\n"
642 "Do you want to restart the connection now?"),
643 tr("Restart"), tr("Cancel")) == 0);
644 }
645
646 // Are we still for it?
647 if (bRestart && closeSession(true)) {
648 // Stop server, it will force the client too.
649 stopServer();
650 // Reschedule a restart...
651 startSchedule(m_pOptions->iStartDelay);
652 }
653 }
654
655
656 // Exit application program.
657 void qsamplerMainForm::fileExit (void)
658 {
659 // Go for close the whole thing.
660 close();
661 }
662
663
664 //-------------------------------------------------------------------------
665 // qsamplerMainForm -- Edit Action slots.
666
667 // Add a new sampler channel.
668 void qsamplerMainForm::editAddChannel (void)
669 {
670 if (m_pClient == NULL)
671 return;
672
673 // Create the new sampler channel.
674 int iChannelID = ::lscp_add_channel(m_pClient);
675 if (iChannelID < 0) {
676 appendMessagesClient("lscp_add_channel");
677 appendMessagesError(tr("Could not create the new channel.\n\nSorry."));
678 return;
679 }
680
681 // Log this happening.
682 appendMessages(tr("Channel %1 created.").arg(iChannelID));
683
684 // Just create the channel strip with given id.
685 createChannel(iChannelID, true);
686
687 // We'll be dirty, for sure...
688 m_iDirtyCount++;
689 // Stabilize form anyway.
690 stabilizeForm();
691 }
692
693
694 // Remove current sampler channel.
695 void qsamplerMainForm::editRemoveChannel (void)
696 {
697 if (m_pClient == NULL)
698 return;
699
700 qsamplerChannelStrip *pChannel = activeChannel();
701 if (pChannel == NULL)
702 return;
703
704 // Prompt user if he/she's sure about this...
705 if (m_pOptions && m_pOptions->bConfirmRemove) {
706 if (QMessageBox::warning(this, tr("Warning"),
707 tr("About to remove channel:\n\n"
708 "%1\n\n"
709 "Are you sure?")
710 .arg(pChannel->caption()),
711 tr("OK"), tr("Cancel")) > 0)
712 return;
713 }
714
715 // Remove the existing sampler channel.
716 if (::lscp_remove_channel(m_pClient, pChannel->channelID()) != LSCP_OK) {
717 appendMessagesClient("lscp_remove_channel");
718 appendMessagesError(tr("Could not remove channel.\n\nSorry."));
719 return;
720 }
721
722 // Log this happening.
723 appendMessages(tr("Channel %1 removed.").arg(pChannel->channelID()));
724
725 // Just delete the channel strip.
726 delete pChannel;
727 // Do we auto-arrange?
728 if (m_pOptions && m_pOptions->bAutoArrange)
729 channelsArrange();
730
731 // We'll be dirty, for sure...
732 m_iDirtyCount++;
733 stabilizeForm();
734 }
735
736
737 // Setup current sampler channel.
738 void qsamplerMainForm::editSetupChannel (void)
739 {
740 if (m_pClient == NULL)
741 return;
742
743 qsamplerChannelStrip *pChannel = activeChannel();
744 if (pChannel == NULL)
745 return;
746
747 // Just invoque the channel strip procedure.
748 pChannel->channelSetup();
749 }
750
751
752 // Reset current sampler channel.
753 void qsamplerMainForm::editResetChannel (void)
754 {
755 if (m_pClient == NULL)
756 return;
757
758 qsamplerChannelStrip *pChannel = activeChannel();
759 if (pChannel == NULL)
760 return;
761
762 // Remove the existing sampler channel.
763 if (::lscp_reset_channel(m_pClient, pChannel->channelID()) != LSCP_OK) {
764 appendMessagesClient("lscp_reset_channel");
765 appendMessagesError(tr("Could not reset channel.\n\nSorry."));
766 return;
767 }
768
769 // Log this.
770 appendMessages(tr("Channel %1 reset.").arg(pChannel->channelID()));
771
772 // Refresh channel strip info.
773 pChannel->updateChannelInfo();
774 }
775
776
777 //-------------------------------------------------------------------------
778 // qsamplerMainForm -- View Action slots.
779
780 // Show/hide the main program window menubar.
781 void qsamplerMainForm::viewMenubar ( bool bOn )
782 {
783 if (bOn)
784 MenuBar->show();
785 else
786 MenuBar->hide();
787 }
788
789
790 // Show/hide the main program window toolbar.
791 void qsamplerMainForm::viewToolbar ( bool bOn )
792 {
793 if (bOn) {
794 fileToolbar->show();
795 editToolbar->show();
796 channelsToolbar->show();
797 } else {
798 fileToolbar->hide();
799 editToolbar->hide();
800 channelsToolbar->hide();
801 }
802 }
803
804
805 // Show/hide the main program window statusbar.
806 void qsamplerMainForm::viewStatusbar ( bool bOn )
807 {
808 if (bOn)
809 statusBar()->show();
810 else
811 statusBar()->hide();
812 }
813
814
815 // Show/hide the messages window logger.
816 void qsamplerMainForm::viewMessages ( bool bOn )
817 {
818 if (bOn)
819 m_pMessages->show();
820 else
821 m_pMessages->hide();
822 }
823
824
825 // Show options dialog.
826 void qsamplerMainForm::viewOptions (void)
827 {
828 if (m_pOptions == NULL)
829 return;
830
831 qsamplerOptionsForm *pOptionsForm = new qsamplerOptionsForm(this);
832 if (pOptionsForm) {
833 // Check out some initial nullities(tm)...
834 qsamplerChannelStrip *pChannel = activeChannel();
835 if (m_pOptions->sDisplayFont.isEmpty() && pChannel)
836 m_pOptions->sDisplayFont = pChannel->displayFont().toString();
837 if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages)
838 m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();
839 // To track down deferred or immediate changes.
840 QString sOldServerHost = m_pOptions->sServerHost;
841 int iOldServerPort = m_pOptions->iServerPort;
842 int iOldServerTimeout = m_pOptions->iServerTimeout;
843 bool bOldServerStart = m_pOptions->bServerStart;
844 QString sOldServerCmdLine = m_pOptions->sServerCmdLine;
845 QString sOldDisplayFont = m_pOptions->sDisplayFont;
846 int iOldMaxVolume = m_pOptions->iMaxVolume;
847 QString sOldMessagesFont = m_pOptions->sMessagesFont;
848 bool bOldStdoutCapture = m_pOptions->bStdoutCapture;
849 int bOldMessagesLimit = m_pOptions->bMessagesLimit;
850 int iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines;
851 bool bOldCompletePath = m_pOptions->bCompletePath;
852 int iOldMaxRecentFiles = m_pOptions->iMaxRecentFiles;
853 // Load the current setup settings.
854 pOptionsForm->setup(m_pOptions);
855 // Show the setup dialog...
856 if (pOptionsForm->exec()) {
857 // Warn if something will be only effective on next run.
858 if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) ||
859 (!bOldStdoutCapture && m_pOptions->bStdoutCapture)) {
860 QMessageBox::information(this, tr("Information"),
861 tr("Some settings may be only effective\n"
862 "next time you start this program."), tr("OK"));
863 updateMessagesCapture();
864 }
865 // Check wheather something immediate has changed.
866 if (( bOldCompletePath && !m_pOptions->bCompletePath) ||
867 (!bOldCompletePath && m_pOptions->bCompletePath) ||
868 (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles))
869 updateRecentFilesMenu();
870 if (sOldDisplayFont != m_pOptions->sDisplayFont)
871 updateDisplayFont();
872 if (iOldMaxVolume != m_pOptions->iMaxVolume)
873 updateMaxVolume();
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 // Force update of the channels maximum volume setting.
1131 void qsamplerMainForm::updateMaxVolume (void)
1132 {
1133 if (m_pOptions == NULL)
1134 return;
1135
1136 // Full channel list update...
1137 QWidgetList wlist = m_pWorkspace->windowList();
1138 if (wlist.isEmpty())
1139 return;
1140
1141 m_pWorkspace->setUpdatesEnabled(false);
1142 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1143 qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1144 pChannel->setMaxVolume(m_pOptions->iMaxVolume);
1145 }
1146 m_pWorkspace->setUpdatesEnabled(true);
1147 }
1148
1149
1150 //-------------------------------------------------------------------------
1151 // qsamplerMainForm -- Messages window form handlers.
1152
1153 // Messages output methods.
1154 void qsamplerMainForm::appendMessages( const QString& s )
1155 {
1156 if (m_pMessages)
1157 m_pMessages->appendMessages(s);
1158
1159 statusBar()->message(s, 3000);
1160 }
1161
1162 void qsamplerMainForm::appendMessagesColor( const QString& s, const QString& c )
1163 {
1164 if (m_pMessages)
1165 m_pMessages->appendMessagesColor(s, c);
1166
1167 statusBar()->message(s, 3000);
1168 }
1169
1170 void qsamplerMainForm::appendMessagesText( const QString& s )
1171 {
1172 if (m_pMessages)
1173 m_pMessages->appendMessagesText(s);
1174 }
1175
1176 void qsamplerMainForm::appendMessagesError( const QString& s )
1177 {
1178 if (m_pMessages)
1179 m_pMessages->show();
1180
1181 appendMessagesColor(s.simplifyWhiteSpace(), "#ff0000");
1182
1183 QMessageBox::critical(this, tr("Error"), s, tr("Cancel"));
1184 }
1185
1186
1187 // This is a special message format, just for client results.
1188 void qsamplerMainForm::appendMessagesClient( const QString& s )
1189 {
1190 if (m_pClient == NULL)
1191 return;
1192
1193 appendMessagesColor(s + QString(": %1 (errno=%2)")
1194 .arg(::lscp_client_get_result(m_pClient))
1195 .arg(::lscp_client_get_errno(m_pClient)), "#996666");
1196 }
1197
1198
1199 // Force update of the messages font.
1200 void qsamplerMainForm::updateMessagesFont (void)
1201 {
1202 if (m_pOptions == NULL)
1203 return;
1204
1205 if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {
1206 QFont font;
1207 if (font.fromString(m_pOptions->sMessagesFont))
1208 m_pMessages->setMessagesFont(font);
1209 }
1210 }
1211
1212
1213 // Update messages window line limit.
1214 void qsamplerMainForm::updateMessagesLimit (void)
1215 {
1216 if (m_pOptions == NULL)
1217 return;
1218
1219 if (m_pMessages) {
1220 if (m_pOptions->bMessagesLimit)
1221 m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);
1222 else
1223 m_pMessages->setMessagesLimit(0);
1224 }
1225 }
1226
1227
1228 // Enablement of the messages capture feature.
1229 void qsamplerMainForm::updateMessagesCapture (void)
1230 {
1231 if (m_pOptions == NULL)
1232 return;
1233
1234 if (m_pMessages)
1235 m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);
1236 }
1237
1238
1239 //-------------------------------------------------------------------------
1240 // qsamplerMainForm -- MDI channel strip management.
1241
1242 // The channel strip creation executive.
1243 void qsamplerMainForm::createChannel ( int iChannelID, bool bPrompt )
1244 {
1245 if (m_pClient == NULL)
1246 return;
1247
1248 // Prepare for auto-arrange?
1249 qsamplerChannelStrip *pChannel = NULL;
1250 int y = 0;
1251 if (m_pOptions && m_pOptions->bAutoArrange) {
1252 QWidgetList wlist = m_pWorkspace->windowList();
1253 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1254 pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1255 // y += pChannel->height() + pChannel->parentWidget()->baseSize().height();
1256 y += pChannel->parentWidget()->frameGeometry().height();
1257 }
1258 }
1259
1260 // Add a new channel itema...
1261 WFlags wflags = Qt::WStyle_Customize | Qt::WStyle_Tool | Qt::WStyle_Title | Qt::WStyle_NoBorder;
1262 pChannel = new qsamplerChannelStrip(m_pWorkspace, 0, wflags);
1263 pChannel->setMaxVolume(m_pOptions->iMaxVolume);
1264 pChannel->setup(this, iChannelID);
1265 // We'll need a display font.
1266 QFont font;
1267 if (m_pOptions && font.fromString(m_pOptions->sDisplayFont))
1268 pChannel->setDisplayFont(font);
1269 // Track channel setup changes.
1270 QObject::connect(pChannel, SIGNAL(channelChanged(qsamplerChannelStrip *)), this, SLOT(channelChanged(qsamplerChannelStrip *)));
1271 // Before we show it up, may be we'll
1272 // better ask for some initial values?
1273 if (bPrompt)
1274 pChannel->channelSetup();
1275 // Now we show up us to the world.
1276 pChannel->show();
1277 // Only then, we'll auto-arrange...
1278 if (m_pOptions && m_pOptions->bAutoArrange) {
1279 int iWidth = m_pWorkspace->width();
1280 // int iHeight = pChannel->height() + pChannel->parentWidget()->baseSize().height();
1281 int iHeight = pChannel->parentWidget()->frameGeometry().height();
1282 pChannel->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1283 }
1284 }
1285
1286
1287 // Retrieve the active channel strip.
1288 qsamplerChannelStrip *qsamplerMainForm::activeChannel (void)
1289 {
1290 return (qsamplerChannelStrip *) m_pWorkspace->activeWindow();
1291 }
1292
1293
1294 // Retrieve a channel strip by index.
1295 qsamplerChannelStrip *qsamplerMainForm::channelAt ( int iChannel )
1296 {
1297 QWidgetList wlist = m_pWorkspace->windowList();
1298 if (wlist.isEmpty())
1299 return 0;
1300
1301 return (qsamplerChannelStrip *) wlist.at(iChannel);
1302 }
1303
1304
1305 // Construct the windows menu.
1306 void qsamplerMainForm::channelsMenuAboutToShow (void)
1307 {
1308 channelsMenu->clear();
1309 channelsArrangeAction->addTo(channelsMenu);
1310 channelsAutoArrangeAction->addTo(channelsMenu);
1311
1312 QWidgetList wlist = m_pWorkspace->windowList();
1313 if (!wlist.isEmpty()) {
1314 channelsMenu->insertSeparator();
1315 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1316 qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1317 int iItemID = channelsMenu->insertItem(pChannel->caption(), this, SLOT(channelsMenuActivated(int)));
1318 channelsMenu->setItemParameter(iItemID, iChannel);
1319 channelsMenu->setItemChecked(iItemID, activeChannel() == pChannel);
1320 }
1321 }
1322 }
1323
1324
1325 // Windows menu activation slot
1326 void qsamplerMainForm::channelsMenuActivated ( int iChannel )
1327 {
1328 qsamplerChannelStrip *pChannel = channelAt(iChannel);
1329 if (pChannel)
1330 pChannel->showNormal();
1331 pChannel->setFocus();
1332 }
1333
1334
1335 //-------------------------------------------------------------------------
1336 // qsamplerMainForm -- Timer stuff.
1337
1338 // Set the pseudo-timer delay schedule.
1339 void qsamplerMainForm::startSchedule ( int iStartDelay )
1340 {
1341 m_iStartDelay = 1 + (iStartDelay * 1000);
1342 m_iTimerDelay = 0;
1343 }
1344
1345 // Suspend the pseudo-timer delay schedule.
1346 void qsamplerMainForm::stopSchedule (void)
1347 {
1348 m_iStartDelay = 0;
1349 m_iTimerDelay = 0;
1350 }
1351
1352 // Timer slot funtion.
1353 void qsamplerMainForm::timerSlot (void)
1354 {
1355 if (m_pOptions == NULL)
1356 return;
1357
1358 // Is it the first shot on server start after a few delay?
1359 if (m_iTimerDelay < m_iStartDelay) {
1360 m_iTimerDelay += QSAMPLER_TIMER_MSECS;
1361 if (m_iTimerDelay >= m_iStartDelay) {
1362 // If we cannot start it now, maybe a lil'mo'later ;)
1363 if (!startClient()) {
1364 m_iStartDelay += m_iTimerDelay;
1365 m_iTimerDelay = 0;
1366 }
1367 }
1368 }
1369
1370 // Refresh each channel usage, on each period...
1371 if (m_pClient && m_pOptions->bAutoRefresh && m_pWorkspace->isUpdatesEnabled()) {
1372 m_iTimerSlot += QSAMPLER_TIMER_MSECS;
1373 if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime) {
1374 m_iTimerSlot = 0;
1375 QWidgetList wlist = m_pWorkspace->windowList();
1376 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1377 qsamplerChannelStrip *pChannel = (qsamplerChannelStrip *) wlist.at(iChannel);
1378 if (pChannel->isVisible())
1379 pChannel->updateChannelUsage();
1380 }
1381 }
1382 }
1383
1384 // Register the next timer slot.
1385 QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
1386 }
1387
1388
1389 //-------------------------------------------------------------------------
1390 // qsamplerMainForm -- Server stuff.
1391
1392 // Start linuxsampler server...
1393 void qsamplerMainForm::startServer (void)
1394 {
1395 if (m_pOptions == NULL)
1396 return;
1397
1398 // Aren't already a client, are we?
1399 if (!m_pOptions->bServerStart || m_pClient)
1400 return;
1401
1402 // Is the server process instance still here?
1403 if (m_pServer) {
1404 switch (QMessageBox::warning(this, tr("Warning"),
1405 tr("Could not start the LinuxSampler server.\n\n"
1406 "Maybe it ss already started."),
1407 tr("Stop"), tr("Kill"), tr("Cancel"))) {
1408 case 0:
1409 m_pServer->tryTerminate();
1410 break;
1411 case 1:
1412 m_pServer->kill();
1413 break;
1414 }
1415 return;
1416 }
1417
1418 // Reset our timer counters...
1419 stopSchedule();
1420
1421 // OK. Let's build the startup process...
1422 m_pServer = new QProcess(this);
1423
1424 // Setup stdout/stderr capture...
1425 //if (m_pOptions->bStdoutCapture) {
1426 m_pServer->setCommunication(QProcess::Stdout | QProcess::Stderr | QProcess::DupStderr);
1427 QObject::connect(m_pServer, SIGNAL(readyReadStdout()), this, SLOT(readServerStdout()));
1428 QObject::connect(m_pServer, SIGNAL(readyReadStderr()), this, SLOT(readServerStdout()));
1429 //}
1430 // The unforgiveable signal communication...
1431 QObject::connect(m_pServer, SIGNAL(processExited()), this, SLOT(processServerExit()));
1432
1433 // Build process arguments...
1434 m_pServer->setArguments(QStringList::split(' ', m_pOptions->sServerCmdLine));
1435
1436 appendMessages(tr("Server is starting..."));
1437 appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");
1438
1439 // Go jack, go...
1440 if (!m_pServer->start()) {
1441 appendMessagesError(tr("Could not start server.\n\nSorry."));
1442 processServerExit();
1443 return;
1444 }
1445
1446 // Show startup results...
1447 appendMessages(tr("Server was started with PID=%1.").arg((long) m_pServer->processIdentifier()));
1448
1449 // Reset (yet again) the timer counters,
1450 // but this time is deferred as the user opted.
1451 startSchedule(m_pOptions->iStartDelay);
1452 stabilizeForm();
1453 }
1454
1455
1456 // Stop linuxsampler server...
1457 void qsamplerMainForm::stopServer (void)
1458 {
1459 // Stop client code.
1460 stopClient();
1461
1462 // And try to stop server.
1463 if (m_pServer) {
1464 appendMessages(tr("Server is stopping..."));
1465 if (m_pServer->isRunning()) {
1466 m_pServer->tryTerminate();
1467 return;
1468 }
1469 }
1470
1471 // Do final processing anyway.
1472 processServerExit();
1473 }
1474
1475
1476 // Stdout handler...
1477 void qsamplerMainForm::readServerStdout (void)
1478 {
1479 if (m_pMessages)
1480 m_pMessages->appendStdoutBuffer(m_pServer->readStdout());
1481 }
1482
1483
1484 // Linuxsampler server cleanup.
1485 void qsamplerMainForm::processServerExit (void)
1486 {
1487 // Force client code cleanup.
1488 stopClient();
1489
1490 // Flush anything that maybe pending...
1491 if (m_pMessages)
1492 m_pMessages->flushStdoutBuffer();
1493
1494 if (m_pServer) {
1495 // Force final server shutdown...
1496 appendMessages(tr("Server was stopped with exit status %1.").arg(m_pServer->exitStatus()));
1497 if (!m_pServer->normalExit())
1498 m_pServer->kill();
1499 // Destroy it.
1500 delete m_pServer;
1501 m_pServer = NULL;
1502 }
1503
1504 // Again, make status visible stable.
1505 stabilizeForm();
1506 }
1507
1508
1509 //-------------------------------------------------------------------------
1510 // qsamplerMainForm -- Client stuff.
1511
1512
1513 // The LSCP client callback procedure.
1514 lscp_status_t qsampler_client_callback ( lscp_client_t *pClient, const char *pchBuffer, int cchBuffer, void *pvData )
1515 {
1516 qsamplerMainForm *pMainForm = (qsamplerMainForm *) pvData;
1517 if (pMainForm == NULL)
1518 return LSCP_FAILED;
1519
1520 char *pszBuffer = (char *) malloc(cchBuffer + 1);
1521 if (pszBuffer == NULL)
1522 return LSCP_FAILED;
1523
1524 memcpy(pszBuffer, pchBuffer, cchBuffer);
1525 pszBuffer[cchBuffer] = (char) 0;
1526 pMainForm->appendMessagesColor(pszBuffer, "#996699");
1527 free(pszBuffer);
1528
1529 return LSCP_OK;
1530 }
1531
1532
1533 // Start our almighty client...
1534 bool qsamplerMainForm::startClient (void)
1535 {
1536 // Have it a setup?
1537 if (m_pOptions == NULL)
1538 return false;
1539
1540 // Aren't we already started, are we?
1541 if (m_pClient)
1542 return true;
1543
1544 // Log prepare here.
1545 appendMessages(tr("Client connecting..."));
1546
1547 // Create the client handle...
1548 m_pClient = ::lscp_client_create(m_pOptions->sServerHost.latin1(), m_pOptions->iServerPort, qsampler_client_callback, this);
1549 if (m_pClient == NULL) {
1550 // Is this the first try?
1551 // maybe we need to start a local server...
1552 if ((m_pServer && m_pServer->isRunning()) || !m_pOptions->bServerStart)
1553 appendMessagesError(tr("Could not connect to server as client.\n\nSorry."));
1554 else
1555 startServer();
1556 // This is always a failure.
1557 stabilizeForm();
1558 return false;
1559 }
1560 // Just set receive timeout value, blindly.
1561 ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);
1562 appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));
1563
1564 // We may stop scheduling around.
1565 stopSchedule();
1566
1567 // We'll accept drops from now on...
1568 setAcceptDrops(true);
1569
1570 // Log success here.
1571 appendMessages(tr("Client connected."));
1572
1573 // Is any session pending to be loaded?
1574 if (!m_pOptions->sSessionFile.isEmpty()) {
1575 // Just load the prabably startup session...
1576 if (loadSessionFile(m_pOptions->sSessionFile)) {
1577 m_pOptions->sSessionFile = QString::null;
1578 return true;
1579 }
1580 }
1581
1582 // Make a new session
1583 return newSession();
1584 }
1585
1586
1587 // Stop client...
1588 void qsamplerMainForm::stopClient (void)
1589 {
1590 if (m_pClient == NULL)
1591 return;
1592
1593 // Log prepare here.
1594 appendMessages(tr("Client disconnecting..."));
1595
1596 // Clear timer counters...
1597 stopSchedule();
1598
1599 // We'll reject drops from now on...
1600 setAcceptDrops(false);
1601
1602 // Force any channel strips around, but
1603 // but avoid removing the corresponding
1604 // channels from the back-end server.
1605 m_iDirtyCount = 0;
1606 closeSession(false);
1607
1608 // Close us as a client...
1609 lscp_client_destroy(m_pClient);
1610 m_pClient = NULL;
1611
1612 // Log final here.
1613 appendMessages(tr("Client disconnected."));
1614
1615 // Make visible status.
1616 stabilizeForm();
1617 }
1618
1619
1620 // end of qsamplerMainForm.ui.h

  ViewVC Help
Powered by ViewVC