/[svn]/qsampler/trunk/src/qsamplerMainForm.cpp
ViewVC logotype

Diff of /qsampler/trunk/src/qsamplerMainForm.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1470 by schoenebeck, Sun Nov 4 23:37:47 2007 UTC revision 3508 by capela, Mon Apr 1 22:36:26 2019 UTC
# Line 1  Line 1 
1  // qsamplerMainForm.cpp  // qsamplerMainForm.cpp
2  //  //
3  /****************************************************************************  /****************************************************************************
4     Copyright (C) 2004-2007, rncbc aka Rui Nuno Capela. All rights reserved.     Copyright (C) 2004-2019, rncbc aka Rui Nuno Capela. All rights reserved.
5     Copyright (C) 2007, Christian Schoenebeck     Copyright (C) 2007,2008,2015 Christian Schoenebeck
6    
7     This program is free software; you can redistribute it and/or     This program is free software; you can redistribute it and/or
8     modify it under the terms of the GNU General Public License     modify it under the terms of the GNU General Public License
# Line 20  Line 20 
20    
21  *****************************************************************************/  *****************************************************************************/
22    
23    #include "qsamplerAbout.h"
24  #include "qsamplerMainForm.h"  #include "qsamplerMainForm.h"
25    
 #include <qapplication.h>  
 #include <qeventloop.h>  
 #include <qworkspace.h>  
 #include <qprocess.h>  
 #include <qmessagebox.h>  
 //#include <qdragobject.h>  
 #include <qregexp.h>  
 #include <qfiledialog.h>  
 #include <qfileinfo.h>  
 #include <qfile.h>  
 #include <qtextstream.h>  
 #include <qstatusbar.h>  
 #include <qslider.h>  
 #include <qspinbox.h>  
 #include <qlabel.h>  
 #include <qtimer.h>  
 #include <qtooltip.h>  
   
 #include "qsamplerAbout.h"  
26  #include "qsamplerOptions.h"  #include "qsamplerOptions.h"
27  #include "qsamplerChannel.h"  #include "qsamplerChannel.h"
28  #include "qsamplerMessages.h"  #include "qsamplerMessages.h"
# Line 51  Line 33 
33  #include "qsamplerInstrumentListForm.h"  #include "qsamplerInstrumentListForm.h"
34  #include "qsamplerDeviceForm.h"  #include "qsamplerDeviceForm.h"
35  #include "qsamplerOptionsForm.h"  #include "qsamplerOptionsForm.h"
36    #include "qsamplerDeviceStatusForm.h"
37    
38    #include <QMdiArea>
39    #include <QMdiSubWindow>
40    
41    #include <QApplication>
42    #include <QProcess>
43    #include <QMessageBox>
44    
45    #include <QRegExp>
46    #include <QTextStream>
47    #include <QFileDialog>
48    #include <QFileInfo>
49    #include <QFile>
50    #include <QUrl>
51    
52    #include <QDragEnterEvent>
53    
54    #include <QStatusBar>
55    #include <QSpinBox>
56    #include <QSlider>
57    #include <QLabel>
58    #include <QTimer>
59    #include <QDateTime>
60    
61    #if QT_VERSION >= 0x050000
62    #include <QMimeData>
63    #endif
64    
65    #if QT_VERSION < 0x040500
66    namespace Qt {
67    const WindowFlags WindowCloseButtonHint = WindowFlags(0x08000000);
68    }
69    #endif
70    
71  #ifdef HAVE_SIGNAL_H  #ifdef HAVE_SIGNAL_H
72  #include <signal.h>  #include <signal.h>
# Line 73  static inline long lroundf ( float x ) Line 89  static inline long lroundf ( float x )
89  }  }
90  #endif  #endif
91    
92    
93    // All winsock apps needs this.
94    #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
95    static WSADATA _wsaData;
96    #endif
97    
98    
99    //-------------------------------------------------------------------------
100    // LADISH Level 1 support stuff.
101    
102    #if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H)
103    
104    #include <QSocketNotifier>
105    
106    #include <sys/types.h>
107    #include <sys/socket.h>
108    
109    #include <signal.h>
110    
111    // File descriptor for SIGUSR1 notifier.
112    static int g_fdSigusr1[2];
113    
114    // Unix SIGUSR1 signal handler.
115    static void qsampler_sigusr1_handler ( int /* signo */ )
116    {
117            char c = 1;
118    
119            (::write(g_fdSigusr1[0], &c, sizeof(c)) > 0);
120    }
121    
122    // File descriptor for SIGTERM notifier.
123    static int g_fdSigterm[2];
124    
125    // Unix SIGTERM signal handler.
126    static void qsampler_sigterm_handler ( int /* signo */ )
127    {
128            char c = 1;
129    
130            (::write(g_fdSigterm[0], &c, sizeof(c)) > 0);
131    }
132    
133    #endif  // HAVE_SIGNAL_H
134    
135    
136    //-------------------------------------------------------------------------
137    // QSampler -- namespace
138    
139    
140    namespace QSampler {
141    
142  // Timer constant stuff.  // Timer constant stuff.
143  #define QSAMPLER_TIMER_MSECS    200  #define QSAMPLER_TIMER_MSECS    200
144    
# Line 83  static inline long lroundf ( float x ) Line 149  static inline long lroundf ( float x )
149  #define QSAMPLER_STATUS_SESSION 3       // Current session modification state.  #define QSAMPLER_STATUS_SESSION 3       // Current session modification state.
150    
151    
152  // All winsock apps needs this.  // Specialties for thread-callback comunication.
153  #if defined(WIN32)  #define QSAMPLER_LSCP_EVENT   QEvent::Type(QEvent::User + 1)
 static WSADATA _wsaData;  
 #endif  
154    
155    
156  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
157  // qsamplerCustomEvent -- specialty for callback comunication.  // QSampler::LscpEvent -- specialty for LSCP callback comunication.
   
 #define QSAMPLER_CUSTOM_EVENT   QEvent::Type(QEvent::User + 0)  
158    
159  class qsamplerCustomEvent : public QEvent  class LscpEvent : public QEvent
160  {  {
161  public:  public:
162    
163      // Constructor.          // Constructor.
164      qsamplerCustomEvent(lscp_event_t event, const char *pchData, int cchData)          LscpEvent(lscp_event_t event, const char *pchData, int cchData)
165          : QEvent(QSAMPLER_CUSTOM_EVENT)                  : QEvent(QSAMPLER_LSCP_EVENT)
166      {          {
167          m_event = event;                  m_event = event;
168          m_data.setLatin1(pchData, cchData);                  m_data  = QString::fromUtf8(pchData, cchData);
169      }          }
170    
171      // Accessors.          // Accessors.
172      lscp_event_t event() { return m_event; }          lscp_event_t  event() { return m_event; }
173      QString&     data()  { return m_data;  }          const QString& data() { return m_data;  }
174    
175  private:  private:
176    
177      // The proper event type.          // The proper event type.
178      lscp_event_t m_event;          lscp_event_t m_event;
179      // The event data as a string.          // The event data as a string.
180      QString      m_data;          QString      m_data;
181  };  };
182    
183    
184  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
185  // qsamplerMainForm -- Main window form implementation.  // QSampler::Workspace -- Main window workspace (MDI Area) decl.
186    
187  namespace QSampler {  class Workspace : public QMdiArea
188    {
189    public:
190    
191            Workspace(MainForm *pMainForm) : QMdiArea(pMainForm) {}
192    
193    protected:
194    
195            void resizeEvent(QResizeEvent *)
196            {
197                    MainForm *pMainForm = static_cast<MainForm *> (parentWidget());
198                    if (pMainForm)
199                            pMainForm->channelsArrangeAuto();
200            }
201    };
202    
203    
204    //-------------------------------------------------------------------------
205    // QSampler::MainForm -- Main window form implementation.
206    
207  // Kind of singleton reference.  // Kind of singleton reference.
208  MainForm* MainForm::g_pMainForm = NULL;  MainForm *MainForm::g_pMainForm = NULL;
209    
210  MainForm::MainForm(QWidget* parent) : QMainWindow(parent) {  MainForm::MainForm ( QWidget *pParent )
211      ui.setupUi(this);          : QMainWindow(pParent)
212    {
213            m_ui.setupUi(this);
214    
215          // Pseudo-singleton reference setup.          // Pseudo-singleton reference setup.
216          g_pMainForm = this;          g_pMainForm = this;
217    
218      // Initialize some pointer references.          // Initialize some pointer references.
219      m_pOptions = NULL;          m_pOptions = NULL;
220    
221      // All child forms are to be created later, not earlier than setup.          // All child forms are to be created later, not earlier than setup.
222      m_pMessages = NULL;          m_pMessages = NULL;
223      m_pInstrumentListForm = NULL;          m_pInstrumentListForm = NULL;
224      m_pDeviceForm = NULL;          m_pDeviceForm = NULL;
225    
226      // We'll start clean.          // We'll start clean.
227      m_iUntitled   = 0;          m_iUntitled   = 0;
228      m_iDirtyCount = 0;          m_iDirtySetup = 0;
229            m_iDirtyCount = 0;
230    
231      m_pServer = NULL;          m_pServer = NULL;
232      m_pClient = NULL;          m_pClient = NULL;
233    
234      m_iStartDelay = 0;          m_iStartDelay = 0;
235      m_iTimerDelay = 0;          m_iTimerDelay = 0;
236    
237      m_iTimerSlot = 0;          m_iTimerSlot = 0;
238    
239    #if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H)
240    
 #ifdef HAVE_SIGNAL_H  
241          // Set to ignore any fatal "Broken pipe" signals.          // Set to ignore any fatal "Broken pipe" signals.
242          ::signal(SIGPIPE, SIG_IGN);          ::signal(SIGPIPE, SIG_IGN);
243  #endif  
244            // LADISH Level 1 suport.
245    
246            // Initialize file descriptors for SIGUSR1 socket notifier.
247            ::socketpair(AF_UNIX, SOCK_STREAM, 0, g_fdSigusr1);
248            m_pSigusr1Notifier
249                    = new QSocketNotifier(g_fdSigusr1[1], QSocketNotifier::Read, this);
250    
251            QObject::connect(m_pSigusr1Notifier,
252                    SIGNAL(activated(int)),
253                    SLOT(handle_sigusr1()));
254    
255            // Install SIGUSR1 signal handler.
256        struct sigaction sigusr1;
257        sigusr1.sa_handler = qsampler_sigusr1_handler;
258        sigemptyset(&sigusr1.sa_mask);
259        sigusr1.sa_flags = 0;
260        sigusr1.sa_flags |= SA_RESTART;
261        ::sigaction(SIGUSR1, &sigusr1, NULL);
262    
263            // Initialize file descriptors for SIGTERM socket notifier.
264            ::socketpair(AF_UNIX, SOCK_STREAM, 0, g_fdSigterm);
265            m_pSigtermNotifier
266                    = new QSocketNotifier(g_fdSigterm[1], QSocketNotifier::Read, this);
267    
268            QObject::connect(m_pSigtermNotifier,
269                    SIGNAL(activated(int)),
270                    SLOT(handle_sigterm()));
271    
272            // Install SIGTERM signal handler.
273            struct sigaction sigterm;
274            sigterm.sa_handler = qsampler_sigterm_handler;
275            ::sigemptyset(&sigterm.sa_mask);
276            sigterm.sa_flags = 0;
277            sigterm.sa_flags |= SA_RESTART;
278            ::sigaction(SIGTERM, &sigterm, NULL);
279            ::sigaction(SIGQUIT, &sigterm, NULL);
280    
281            // Ignore SIGHUP/SIGINT signals.
282            ::signal(SIGHUP, SIG_IGN);
283            ::signal(SIGINT, SIG_IGN);
284    
285    #else   // HAVE_SIGNAL_H
286    
287            m_pSigusr1Notifier = NULL;
288            m_pSigtermNotifier = NULL;
289            
290    #endif  // !HAVE_SIGNAL_H
291    
292  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
293      // Make some extras into the toolbar...          // Make some extras into the toolbar...
294          const QString& sVolumeText = tr("Master volume");          const QString& sVolumeText = tr("Master volume");
295          m_iVolumeChanging = 0;          m_iVolumeChanging = 0;
296          // Volume slider...          // Volume slider...
297          ui.channelsToolbar->addSeparator();          m_ui.channelsToolbar->addSeparator();
298          m_pVolumeSlider = new QSlider(Qt::Horizontal, ui.channelsToolbar);          m_pVolumeSlider = new QSlider(Qt::Horizontal, m_ui.channelsToolbar);
299          m_pVolumeSlider->setTickmarks(QSlider::Below);          m_pVolumeSlider->setTickPosition(QSlider::TicksBothSides);
300          m_pVolumeSlider->setTickInterval(10);          m_pVolumeSlider->setTickInterval(10);
301          m_pVolumeSlider->setPageStep(10);          m_pVolumeSlider->setPageStep(10);
302          m_pVolumeSlider->setRange(0, 100);          m_pVolumeSlider->setSingleStep(10);
303            m_pVolumeSlider->setMinimum(0);
304            m_pVolumeSlider->setMaximum(100);
305          m_pVolumeSlider->setMaximumHeight(26);          m_pVolumeSlider->setMaximumHeight(26);
306          m_pVolumeSlider->setMinimumWidth(160);          m_pVolumeSlider->setMinimumWidth(160);
307          QToolTip::add(m_pVolumeSlider, sVolumeText);          m_pVolumeSlider->setToolTip(sVolumeText);
308          QObject::connect(m_pVolumeSlider,          QObject::connect(m_pVolumeSlider,
309                  SIGNAL(valueChanged(int)),                  SIGNAL(valueChanged(int)),
310                  SLOT(volumeChanged(int)));                  SLOT(volumeChanged(int)));
311          //ui.channelsToolbar->setHorizontallyStretchable(true);          m_ui.channelsToolbar->addWidget(m_pVolumeSlider);
         //ui.channelsToolbar->setStretchableWidget(m_pVolumeSlider);  
     ui.channelsToolbar->addWidget(m_pVolumeSlider);  
312          // Volume spin-box          // Volume spin-box
313          ui.channelsToolbar->addSeparator();          m_ui.channelsToolbar->addSeparator();
314          m_pVolumeSpinBox = new QSpinBox(ui.channelsToolbar);          m_pVolumeSpinBox = new QSpinBox(m_ui.channelsToolbar);
315          m_pVolumeSpinBox->setSuffix(" %");          m_pVolumeSpinBox->setSuffix(" %");
316          m_pVolumeSpinBox->setRange(0, 100);          m_pVolumeSpinBox->setMinimum(0);
317          QToolTip::add(m_pVolumeSpinBox, sVolumeText);          m_pVolumeSpinBox->setMaximum(100);
318            m_pVolumeSpinBox->setToolTip(sVolumeText);
319          QObject::connect(m_pVolumeSpinBox,          QObject::connect(m_pVolumeSpinBox,
320                  SIGNAL(valueChanged(int)),                  SIGNAL(valueChanged(int)),
321                  SLOT(volumeChanged(int)));                  SLOT(volumeChanged(int)));
322      ui.channelsToolbar->addWidget(m_pVolumeSpinBox);          m_ui.channelsToolbar->addWidget(m_pVolumeSpinBox);
323  #endif  #endif
324    
325      // Make it an MDI workspace.          // Make it an MDI workspace.
326      m_pWorkspace = new QWorkspace(this);          m_pWorkspace = new Workspace(this);
327      m_pWorkspace->setScrollBarsEnabled(true);          m_pWorkspace->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
328            m_pWorkspace->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
329          // Set the activation connection.          // Set the activation connection.
330          QObject::connect(m_pWorkspace,          QObject::connect(m_pWorkspace,
331                  SIGNAL(windowActivated(QWidget *)),                  SIGNAL(subWindowActivated(QMdiSubWindow *)),
332                  SLOT(stabilizeForm()));                  SLOT(activateStrip(QMdiSubWindow *)));
333      // Make it shine :-)          // Make it shine :-)
334      setCentralWidget(m_pWorkspace);          setCentralWidget(m_pWorkspace);
335    
336      // Create some statusbar labels...          // Create some statusbar labels...
337      QLabel *pLabel;          QLabel *pLabel;
338      // Client status.          // Client status.
339      pLabel = new QLabel(tr("Connected"), this);          pLabel = new QLabel(tr("Connected"), this);
340      pLabel->setAlignment(Qt::AlignLeft);          pLabel->setAlignment(Qt::AlignLeft);
341      pLabel->setMinimumSize(pLabel->sizeHint());          pLabel->setMinimumSize(pLabel->sizeHint());
342      m_statusItem[QSAMPLER_STATUS_CLIENT] = pLabel;          m_statusItem[QSAMPLER_STATUS_CLIENT] = pLabel;
343      statusBar()->addWidget(pLabel);          statusBar()->addWidget(pLabel);
344      // Server address.          // Server address.
345      pLabel = new QLabel(this);          pLabel = new QLabel(this);
346      pLabel->setAlignment(Qt::AlignLeft);          pLabel->setAlignment(Qt::AlignLeft);
347      m_statusItem[QSAMPLER_STATUS_SERVER] = pLabel;          m_statusItem[QSAMPLER_STATUS_SERVER] = pLabel;
348      statusBar()->addWidget(pLabel, 1);          statusBar()->addWidget(pLabel, 1);
349      // Channel title.          // Channel title.
350      pLabel = new QLabel(this);          pLabel = new QLabel(this);
351      pLabel->setAlignment(Qt::AlignLeft);          pLabel->setAlignment(Qt::AlignLeft);
352      m_statusItem[QSAMPLER_STATUS_CHANNEL] = pLabel;          m_statusItem[QSAMPLER_STATUS_CHANNEL] = pLabel;
353      statusBar()->addWidget(pLabel, 2);          statusBar()->addWidget(pLabel, 2);
354      // Session modification status.          // Session modification status.
355      pLabel = new QLabel(tr("MOD"), this);          pLabel = new QLabel(tr("MOD"), this);
356      pLabel->setAlignment(Qt::AlignHCenter);          pLabel->setAlignment(Qt::AlignHCenter);
357      pLabel->setMinimumSize(pLabel->sizeHint());          pLabel->setMinimumSize(pLabel->sizeHint());
358      m_statusItem[QSAMPLER_STATUS_SESSION] = pLabel;          m_statusItem[QSAMPLER_STATUS_SESSION] = pLabel;
359      statusBar()->addWidget(pLabel);          statusBar()->addWidget(pLabel);
360    
361      // Create the recent files sub-menu.  #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
362      m_pRecentFilesMenu = new Q3PopupMenu(this);          WSAStartup(MAKEWORD(1, 1), &_wsaData);
363      ui.fileMenu->insertSeparator(4);  #endif
364      ui.fileMenu->insertItem(tr("Recent &Files"), m_pRecentFilesMenu, 0, 5);  
365            // Some actions surely need those
366  #if defined(WIN32)          // shortcuts firmly attached...
367      WSAStartup(MAKEWORD(1, 1), &_wsaData);          addAction(m_ui.viewMenubarAction);
368  #endif          addAction(m_ui.viewToolbarAction);
369    
370          QObject::connect(ui.fileNewAction,          QObject::connect(m_ui.fileNewAction,
371                  SIGNAL(activated()),                  SIGNAL(triggered()),
372                  SLOT(fileNew()));                  SLOT(fileNew()));
373          QObject::connect(ui.fileOpenAction,          QObject::connect(m_ui.fileOpenAction,
374                  SIGNAL(activated()),                  SIGNAL(triggered()),
375                  SLOT(fileOpen()));                  SLOT(fileOpen()));
376          QObject::connect(ui.fileSaveAction,          QObject::connect(m_ui.fileSaveAction,
377                  SIGNAL(activated()),                  SIGNAL(triggered()),
378                  SLOT(fileSave()));                  SLOT(fileSave()));
379          QObject::connect(ui.fileSaveAsAction,          QObject::connect(m_ui.fileSaveAsAction,
380                  SIGNAL(activated()),                  SIGNAL(triggered()),
381                  SLOT(fileSaveAs()));                  SLOT(fileSaveAs()));
382          QObject::connect(ui.fileResetAction,          QObject::connect(m_ui.fileResetAction,
383                  SIGNAL(activated()),                  SIGNAL(triggered()),
384                  SLOT(fileReset()));                  SLOT(fileReset()));
385          QObject::connect(ui.fileRestartAction,          QObject::connect(m_ui.fileRestartAction,
386                  SIGNAL(activated()),                  SIGNAL(triggered()),
387                  SLOT(fileRestart()));                  SLOT(fileRestart()));
388          QObject::connect(ui.fileExitAction,          QObject::connect(m_ui.fileExitAction,
389                  SIGNAL(activated()),                  SIGNAL(triggered()),
390                  SLOT(fileExit()));                  SLOT(fileExit()));
391          QObject::connect(ui.editAddChannelAction,          QObject::connect(m_ui.editAddChannelAction,
392                  SIGNAL(activated()),                  SIGNAL(triggered()),
393                  SLOT(editAddChannel()));                  SLOT(editAddChannel()));
394          QObject::connect(ui.editRemoveChannelAction,          QObject::connect(m_ui.editRemoveChannelAction,
395                  SIGNAL(activated()),                  SIGNAL(triggered()),
396                  SLOT(editRemoveChannel()));                  SLOT(editRemoveChannel()));
397          QObject::connect(ui.editSetupChannelAction,          QObject::connect(m_ui.editSetupChannelAction,
398                  SIGNAL(activated()),                  SIGNAL(triggered()),
399                  SLOT(editSetupChannel()));                  SLOT(editSetupChannel()));
400          QObject::connect(ui.editEditChannelAction,          QObject::connect(m_ui.editEditChannelAction,
401                  SIGNAL(activated()),                  SIGNAL(triggered()),
402                  SLOT(editEditChannel()));                  SLOT(editEditChannel()));
403          QObject::connect(ui.editResetChannelAction,          QObject::connect(m_ui.editResetChannelAction,
404                  SIGNAL(activated()),                  SIGNAL(triggered()),
405                  SLOT(editResetChannel()));                  SLOT(editResetChannel()));
406          QObject::connect(ui.editResetAllChannelsAction,          QObject::connect(m_ui.editResetAllChannelsAction,
407                  SIGNAL(activated()),                  SIGNAL(triggered()),
408                  SLOT(editResetAllChannels()));                  SLOT(editResetAllChannels()));
409          QObject::connect(ui.viewMenubarAction,          QObject::connect(m_ui.viewMenubarAction,
410                  SIGNAL(toggled(bool)),                  SIGNAL(toggled(bool)),
411                  SLOT(viewMenubar(bool)));                  SLOT(viewMenubar(bool)));
412          QObject::connect(ui.viewToolbarAction,          QObject::connect(m_ui.viewToolbarAction,
413                  SIGNAL(toggled(bool)),                  SIGNAL(toggled(bool)),
414                  SLOT(viewToolbar(bool)));                  SLOT(viewToolbar(bool)));
415          QObject::connect(ui.viewStatusbarAction,          QObject::connect(m_ui.viewStatusbarAction,
416                  SIGNAL(toggled(bool)),                  SIGNAL(toggled(bool)),
417                  SLOT(viewStatusbar(bool)));                  SLOT(viewStatusbar(bool)));
418          QObject::connect(ui.viewMessagesAction,          QObject::connect(m_ui.viewMessagesAction,
419                  SIGNAL(toggled(bool)),                  SIGNAL(toggled(bool)),
420                  SLOT(viewMessages(bool)));                  SLOT(viewMessages(bool)));
421          QObject::connect(ui.viewInstrumentsAction,          QObject::connect(m_ui.viewInstrumentsAction,
422                  SIGNAL(activated()),                  SIGNAL(triggered()),
423                  SLOT(viewInstruments()));                  SLOT(viewInstruments()));
424          QObject::connect(ui.viewDevicesAction,          QObject::connect(m_ui.viewDevicesAction,
425                  SIGNAL(activated()),                  SIGNAL(triggered()),
426                  SLOT(viewDevices()));                  SLOT(viewDevices()));
427          QObject::connect(ui.viewOptionsAction,          QObject::connect(m_ui.viewOptionsAction,
428                  SIGNAL(activated()),                  SIGNAL(triggered()),
429                  SLOT(viewOptions()));                  SLOT(viewOptions()));
430          QObject::connect(ui.channelsArrangeAction,          QObject::connect(m_ui.channelsArrangeAction,
431                  SIGNAL(activated()),                  SIGNAL(triggered()),
432                  SLOT(channelsArrange()));                  SLOT(channelsArrange()));
433          QObject::connect(ui.channelsAutoArrangeAction,          QObject::connect(m_ui.channelsAutoArrangeAction,
434                  SIGNAL(toggled(bool)),                  SIGNAL(toggled(bool)),
435                  SLOT(channelsAutoArrange(bool)));                  SLOT(channelsAutoArrange(bool)));
436          QObject::connect(ui.helpAboutAction,          QObject::connect(m_ui.helpAboutAction,
437                  SIGNAL(activated()),                  SIGNAL(triggered()),
438                  SLOT(helpAbout()));                  SLOT(helpAbout()));
439          QObject::connect(ui.helpAboutQtAction,          QObject::connect(m_ui.helpAboutQtAction,
440                  SIGNAL(activated()),                  SIGNAL(triggered()),
441                  SLOT(helpAboutQt()));                  SLOT(helpAboutQt()));
442    
443            QObject::connect(m_ui.fileMenu,
444                    SIGNAL(aboutToShow()),
445                    SLOT(updateRecentFilesMenu()));
446            QObject::connect(m_ui.channelsMenu,
447                    SIGNAL(aboutToShow()),
448                    SLOT(channelsMenuAboutToShow()));
449    #ifdef CONFIG_VOLUME
450            QObject::connect(m_ui.channelsToolbar,
451                    SIGNAL(orientationChanged(Qt::Orientation)),
452                    SLOT(channelsToolbarOrientation(Qt::Orientation)));
453    #endif
454  }  }
455    
456  // Destructor.  // Destructor.
457  MainForm::~MainForm()  MainForm::~MainForm()
458  {  {
459      // Do final processing anyway.          // Do final processing anyway.
460      processServerExit();          processServerExit();
461    
462  #if defined(WIN32)  #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
463      WSACleanup();          WSACleanup();
464  #endif  #endif
465    
466      // Finally drop any widgets around...  #if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H)
467      if (m_pDeviceForm)          if (m_pSigusr1Notifier)
468          delete m_pDeviceForm;                  delete m_pSigusr1Notifier;
469      if (m_pInstrumentListForm)          if (m_pSigtermNotifier)
470          delete m_pInstrumentListForm;                  delete m_pSigtermNotifier;
471      if (m_pMessages)  #endif
472          delete m_pMessages;  
473      if (m_pWorkspace)          // Finally drop any widgets around...
474          delete m_pWorkspace;          if (m_pDeviceForm)
475                    delete m_pDeviceForm;
476      // Delete status item labels one by one.          if (m_pInstrumentListForm)
477      if (m_statusItem[QSAMPLER_STATUS_CLIENT])                  delete m_pInstrumentListForm;
478          delete m_statusItem[QSAMPLER_STATUS_CLIENT];          if (m_pMessages)
479      if (m_statusItem[QSAMPLER_STATUS_SERVER])                  delete m_pMessages;
480          delete m_statusItem[QSAMPLER_STATUS_SERVER];          if (m_pWorkspace)
481      if (m_statusItem[QSAMPLER_STATUS_CHANNEL])                  delete m_pWorkspace;
482          delete m_statusItem[QSAMPLER_STATUS_CHANNEL];  
483      if (m_statusItem[QSAMPLER_STATUS_SESSION])          // Delete status item labels one by one.
484          delete m_statusItem[QSAMPLER_STATUS_SESSION];          if (m_statusItem[QSAMPLER_STATUS_CLIENT])
485                    delete m_statusItem[QSAMPLER_STATUS_CLIENT];
486            if (m_statusItem[QSAMPLER_STATUS_SERVER])
487                    delete m_statusItem[QSAMPLER_STATUS_SERVER];
488            if (m_statusItem[QSAMPLER_STATUS_CHANNEL])
489                    delete m_statusItem[QSAMPLER_STATUS_CHANNEL];
490            if (m_statusItem[QSAMPLER_STATUS_SESSION])
491                    delete m_statusItem[QSAMPLER_STATUS_SESSION];
492    
493  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
494          delete m_pVolumeSpinBox;          delete m_pVolumeSpinBox;
495          delete m_pVolumeSlider;          delete m_pVolumeSlider;
496  #endif  #endif
497    
     // Delete recentfiles menu.  
     if (m_pRecentFilesMenu)  
         delete m_pRecentFilesMenu;  
   
498          // Pseudo-singleton reference shut-down.          // Pseudo-singleton reference shut-down.
499          g_pMainForm = NULL;          g_pMainForm = NULL;
500  }  }
501    
502    
503  // Make and set a proper setup options step.  // Make and set a proper setup options step.
504  void MainForm::setup ( qsamplerOptions *pOptions )  void MainForm::setup ( Options *pOptions )
505  {  {
506      // We got options?          // We got options?
507      m_pOptions = pOptions;          m_pOptions = pOptions;
508    
509      // What style do we create these forms?          // What style do we create these forms?
510          Qt::WFlags wflags = Qt::WStyle_Customize          Qt::WindowFlags wflags = Qt::Window
511                  | Qt::WStyle_NormalBorder                  | Qt::CustomizeWindowHint
512                  | Qt::WStyle_Title                  | Qt::WindowTitleHint
513                  | Qt::WStyle_SysMenu                  | Qt::WindowSystemMenuHint
514                  | Qt::WStyle_MinMax                  | Qt::WindowMinMaxButtonsHint
515                  | Qt::WType_TopLevel;                  | Qt::WindowCloseButtonHint;
516      if (m_pOptions->bKeepOnTop)          if (m_pOptions->bKeepOnTop)
517          wflags |= Qt::WStyle_Tool;                  wflags |= Qt::Tool;
518      // Some child forms are to be created right now.  
519      m_pMessages = new qsamplerMessages(this);          // Some child forms are to be created right now.
520      m_pDeviceForm = new DeviceForm(this, wflags);          m_pMessages = new Messages(this);
521            m_pDeviceForm = new DeviceForm(this, wflags);
522  #ifdef CONFIG_MIDI_INSTRUMENT  #ifdef CONFIG_MIDI_INSTRUMENT
523      m_pInstrumentListForm = new InstrumentListForm(this, wflags);          m_pInstrumentListForm = new InstrumentListForm(this, wflags);
         QObject::connect(&m_pInstrumentListForm->model,  
                 SIGNAL(instrumentsChanged()),  
                 SLOT(sessionDirty()));  
524  #else  #else
525          viewInstrumentsAction->setEnabled(false);          m_ui.viewInstrumentsAction->setEnabled(false);
526  #endif  #endif
527      // Set message defaults...  
528      updateMessagesFont();          // Setup messages logging appropriately...
529      updateMessagesLimit();          m_pMessages->setLogging(
530      updateMessagesCapture();                  m_pOptions->bMessagesLog,
531      // Set the visibility signal.                  m_pOptions->sMessagesLogPath);
532    
533            // Set message defaults...
534            updateMessagesFont();
535            updateMessagesLimit();
536            updateMessagesCapture();
537    
538            // Set the visibility signal.
539          QObject::connect(m_pMessages,          QObject::connect(m_pMessages,
540                  SIGNAL(visibilityChanged(bool)),                  SIGNAL(visibilityChanged(bool)),
541                  SLOT(stabilizeForm()));                  SLOT(stabilizeForm()));
542    
543      // Initial decorations toggle state.          // Initial decorations toggle state.
544      ui.viewMenubarAction->setOn(m_pOptions->bMenubar);          m_ui.viewMenubarAction->setChecked(m_pOptions->bMenubar);
545      ui.viewToolbarAction->setOn(m_pOptions->bToolbar);          m_ui.viewToolbarAction->setChecked(m_pOptions->bToolbar);
546      ui.viewStatusbarAction->setOn(m_pOptions->bStatusbar);          m_ui.viewStatusbarAction->setChecked(m_pOptions->bStatusbar);
547      ui.channelsAutoArrangeAction->setOn(m_pOptions->bAutoArrange);          m_ui.channelsAutoArrangeAction->setChecked(m_pOptions->bAutoArrange);
548    
549      // Initial decorations visibility state.          // Initial decorations visibility state.
550      viewMenubar(m_pOptions->bMenubar);          viewMenubar(m_pOptions->bMenubar);
551      viewToolbar(m_pOptions->bToolbar);          viewToolbar(m_pOptions->bToolbar);
552      viewStatusbar(m_pOptions->bStatusbar);          viewStatusbar(m_pOptions->bStatusbar);
553    
554      addDockWidget(Qt::BottomDockWidgetArea, m_pMessages);          addDockWidget(Qt::BottomDockWidgetArea, m_pMessages);
555    
556      // Restore whole toolbar & dock windows states.          // Restore whole dock windows state.
557      QString sDockables = m_pOptions->settings().readEntry("/Layout/DockWindowsBase64" , QString::null);          QByteArray aDockables = m_pOptions->settings().value(
558      if (!sDockables.isEmpty()) {                  "/Layout/DockWindows").toByteArray();
559          restoreState(QByteArray::fromBase64(sDockables.toAscii()));          if (!aDockables.isEmpty()) {
560      }                  restoreState(aDockables);
561      // Try to restore old window positioning and initial visibility.          }
562      m_pOptions->loadWidgetGeometry(this);  
563      m_pOptions->loadWidgetGeometry(m_pInstrumentListForm);          // Try to restore old window positioning and initial visibility.
564      m_pOptions->loadWidgetGeometry(m_pDeviceForm);          m_pOptions->loadWidgetGeometry(this, true);
565            m_pOptions->loadWidgetGeometry(m_pInstrumentListForm);
566      // Final startup stabilization...          m_pOptions->loadWidgetGeometry(m_pDeviceForm);
567      updateMaxVolume();  
568      updateRecentFilesMenu();          // Final startup stabilization...
569      stabilizeForm();          updateMaxVolume();
570            updateRecentFilesMenu();
571            stabilizeForm();
572    
573      // Make it ready :-)          // Make it ready :-)
574      statusBar()->message(tr("Ready"), 3000);          statusBar()->showMessage(tr("Ready"), 3000);
575    
576      // We'll try to start immediately...          // We'll try to start immediately...
577      startSchedule(0);          startSchedule(0);
578    
579      // Register the first timer slot.          // Register the first timer slot.
580      QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));          QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
581  }  }
582    
583    
584  // Window close event handlers.  // Window close event handlers.
585  bool MainForm::queryClose (void)  bool MainForm::queryClose (void)
586  {  {
587      bool bQueryClose = closeSession(false);          bool bQueryClose = closeSession(false);
588    
589      // Try to save current general state...          // Try to save current general state...
590      if (m_pOptions) {          if (m_pOptions) {
591          // Some windows default fonts is here on demand too.                  // Some windows default fonts is here on demand too.
592          if (bQueryClose && m_pMessages)                  if (bQueryClose && m_pMessages)
593              m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();                          m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();
594          // Try to save current positioning.                  // Try to save current positioning.
595          if (bQueryClose) {                  if (bQueryClose) {
596              // Save decorations state.                          // Save decorations state.
597              m_pOptions->bMenubar = ui.MenuBar->isVisible();                          m_pOptions->bMenubar = m_ui.MenuBar->isVisible();
598              m_pOptions->bToolbar = (ui.fileToolbar->isVisible() || ui.editToolbar->isVisible() || ui.channelsToolbar->isVisible());                          m_pOptions->bToolbar = (m_ui.fileToolbar->isVisible()
599              m_pOptions->bStatusbar = statusBar()->isVisible();                                  || m_ui.editToolbar->isVisible()
600              // Save the dock windows state.                                  || m_ui.channelsToolbar->isVisible());
601              const QString sDockables = saveState().toBase64().data();                          m_pOptions->bStatusbar = statusBar()->isVisible();
602              m_pOptions->settings().writeEntry("/Layout/DockWindowsBase64", sDockables);                          // Save the dock windows state.
603              // And the children, and the main windows state,.                          m_pOptions->settings().setValue("/Layout/DockWindows", saveState());
604                            // And the children, and the main windows state,.
605                          m_pOptions->saveWidgetGeometry(m_pDeviceForm);                          m_pOptions->saveWidgetGeometry(m_pDeviceForm);
606                          m_pOptions->saveWidgetGeometry(m_pInstrumentListForm);                          m_pOptions->saveWidgetGeometry(m_pInstrumentListForm);
607                          m_pOptions->saveWidgetGeometry(this);                          m_pOptions->saveWidgetGeometry(this, true);
608                          // Close popup widgets.                          // Close popup widgets.
609                          if (m_pInstrumentListForm)                          if (m_pInstrumentListForm)
610                                  m_pInstrumentListForm->close();                                  m_pInstrumentListForm->close();
611                          if (m_pDeviceForm)                          if (m_pDeviceForm)
612                                  m_pDeviceForm->close();                                  m_pDeviceForm->close();
613              // Stop client and/or server, gracefully.                          // Stop client and/or server, gracefully.
614              stopServer();                          stopServer(true /*interactive*/);
615          }                  }
616      }          }
617    
618      return bQueryClose;          return bQueryClose;
619  }  }
620    
621    
622  void MainForm::closeEvent ( QCloseEvent *pCloseEvent )  void MainForm::closeEvent ( QCloseEvent *pCloseEvent )
623  {  {
624      if (queryClose())          if (queryClose()) {
625          pCloseEvent->accept();                  DeviceStatusForm::deleteAllInstances();
626      else                  pCloseEvent->accept();
627          pCloseEvent->ignore();          } else
628  }                  pCloseEvent->ignore();
   
   
 // Drag'n'drop file handler.  
 bool MainForm::decodeDragFiles ( const QMimeSource *pEvent, QStringList& files )  
 {  
     bool bDecode = false;  
   
     if (Q3TextDrag::canDecode(pEvent)) {  
         QString sText;  
         bDecode = Q3TextDrag::decode(pEvent, sText);  
         if (bDecode) {  
             files = QStringList::split('\n', sText);  
             for (QStringList::Iterator iter = files.begin(); iter != files.end(); iter++)  
                 *iter = QUrl((*iter).stripWhiteSpace().replace(QRegExp("^file:"), QString::null)).path();  
         }  
     }  
   
     return bDecode;  
629  }  }
630    
631    
632  // Window drag-n-drop event handlers.  // Window drag-n-drop event handlers.
633  void MainForm::dragEnterEvent ( QDragEnterEvent* pDragEnterEvent )  void MainForm::dragEnterEvent ( QDragEnterEvent* pDragEnterEvent )
634  {  {
635          QStringList files;          // Accept external drags only...
636          pDragEnterEvent->accept(decodeDragFiles(pDragEnterEvent, files));          if (pDragEnterEvent->source() == NULL
637                    && pDragEnterEvent->mimeData()->hasUrls()) {
638                    pDragEnterEvent->accept();
639            } else {
640                    pDragEnterEvent->ignore();
641            }
642  }  }
643    
644    
645  void MainForm::dropEvent ( QDropEvent* pDropEvent )  void MainForm::dropEvent ( QDropEvent *pDropEvent )
646  {  {
647      QStringList files;          // Accept externally originated drops only...
648            if (pDropEvent->source())
649                    return;
650    
651      if (!decodeDragFiles(pDropEvent, files))          const QMimeData *pMimeData = pDropEvent->mimeData();
652          return;          if (pMimeData->hasUrls()) {
653                    QListIterator<QUrl> iter(pMimeData->urls());
654          for (QStringList::Iterator iter = files.begin(); iter != files.end(); iter++) {                  while (iter.hasNext()) {
655                  const QString& sPath = *iter;                          const QString& sPath = iter.next().toLocalFile();
656                  if (qsamplerChannel::isInstrumentFile(sPath)) {                  //      if (Channel::isDlsInstrumentFile(sPath)) {
657                          // Try to create a new channel from instrument file...                          if (QFileInfo(sPath).exists()) {
658                          qsamplerChannel *pChannel = new qsamplerChannel();                                  // Try to create a new channel from instrument file...
659                          if (pChannel == NULL)                                  Channel *pChannel = new Channel();
660                                  return;                                  if (pChannel == NULL)
661                          // Start setting the instrument filename...                                          return;
662                          pChannel->setInstrument(sPath, 0);                                  // Start setting the instrument filename...
663                          // Before we show it up, may be we'll                                  pChannel->setInstrument(sPath, 0);
664                          // better ask for some initial values?                                  // Before we show it up, may be we'll
665                          if (!pChannel->channelSetup(this)) {                                  // better ask for some initial values?
666                                  delete pChannel;                                  if (!pChannel->channelSetup(this)) {
667                                  return;                                          delete pChannel;
668                          }                                          return;
669                          // Finally, give it to a new channel strip...                                  }
670                          if (!createChannelStrip(pChannel)) {                                  // Finally, give it to a new channel strip...
671                                  delete pChannel;                                  if (!createChannelStrip(pChannel)) {
672                                  return;                                          delete pChannel;
673                                            return;
674                                    }
675                                    // Make that an overall update.
676                                    m_iDirtyCount++;
677                                    stabilizeForm();
678                            }   // Otherwise, load an usual session file (LSCP script)...
679                            else if (closeSession(true)) {
680                                    loadSessionFile(sPath);
681                                    break;
682                          }                          }
                         // Make that an overall update.  
                         m_iDirtyCount++;  
                         stabilizeForm();  
                 }   // Otherwise, load an usual session file (LSCP script)...  
                 else if (closeSession(true)) {  
                         loadSessionFile(sPath);  
                         break;  
683                  }                  }
684                  // Make it look responsive...:)                  // Make it look responsive...:)
685                  QApplication::processEvents(QEventLoop::ExcludeUserInput);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
686          }          }
687  }  }
688    
689    
690  // Custome event handler.  // Custome event handler.
691  void MainForm::customEvent(QEvent* pCustomEvent)  void MainForm::customEvent ( QEvent* pEvent )
692  {  {
693      // For the time being, just pump it to messages.          // For the time being, just pump it to messages.
694      if (pCustomEvent->type() == QSAMPLER_CUSTOM_EVENT) {          if (pEvent->type() == QSAMPLER_LSCP_EVENT) {
695          qsamplerCustomEvent *pEvent = (qsamplerCustomEvent *) pCustomEvent;                  LscpEvent *pLscpEvent = static_cast<LscpEvent *> (pEvent);
696                  if (pEvent->event() == LSCP_EVENT_CHANNEL_INFO) {                  switch (pLscpEvent->event()) {
697                          int iChannelID = pEvent->data().toInt();                          case LSCP_EVENT_CHANNEL_COUNT:
698                          ChannelStrip *pChannelStrip = channelStrip(iChannelID);                                  updateAllChannelStrips(true);
699                          if (pChannelStrip)                                  break;
700                                  channelStripChanged(pChannelStrip);                          case LSCP_EVENT_CHANNEL_INFO: {
701                  } else {                                  const int iChannelID = pLscpEvent->data().toInt();
702                          appendMessagesColor(tr("Notify event: %1 data: %2")                                  ChannelStrip *pChannelStrip = channelStrip(iChannelID);
703                                  .arg(::lscp_event_to_text(pEvent->event()))                                  if (pChannelStrip)
704                                  .arg(pEvent->data()), "#996699");                                          channelStripChanged(pChannelStrip);
705                                    break;
706                            }
707                            case LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT:
708                                    if (m_pDeviceForm) m_pDeviceForm->refreshDevices();
709                                    DeviceStatusForm::onDevicesChanged();
710                                    updateViewMidiDeviceStatusMenu();
711                                    break;
712                            case LSCP_EVENT_MIDI_INPUT_DEVICE_INFO: {
713                                    if (m_pDeviceForm) m_pDeviceForm->refreshDevices();
714                                    const int iDeviceID = pLscpEvent->data().section(' ', 0, 0).toInt();
715                                    DeviceStatusForm::onDeviceChanged(iDeviceID);
716                                    break;
717                            }
718                            case LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT:
719                                    if (m_pDeviceForm) m_pDeviceForm->refreshDevices();
720                                    break;
721                            case LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO:
722                                    if (m_pDeviceForm) m_pDeviceForm->refreshDevices();
723                                    break;
724                    #if CONFIG_EVENT_CHANNEL_MIDI
725                            case LSCP_EVENT_CHANNEL_MIDI: {
726                                    const int iChannelID = pLscpEvent->data().section(' ', 0, 0).toInt();
727                                    ChannelStrip *pChannelStrip = channelStrip(iChannelID);
728                                    if (pChannelStrip)
729                                            pChannelStrip->midiActivityLedOn();
730                                    break;
731                            }
732                    #endif
733                    #if CONFIG_EVENT_DEVICE_MIDI
734                            case LSCP_EVENT_DEVICE_MIDI: {
735                                    const int iDeviceID = pLscpEvent->data().section(' ', 0, 0).toInt();
736                                    const int iPortID   = pLscpEvent->data().section(' ', 1, 1).toInt();
737                                    DeviceStatusForm *pDeviceStatusForm
738                                            = DeviceStatusForm::getInstance(iDeviceID);
739                                    if (pDeviceStatusForm)
740                                            pDeviceStatusForm->midiArrived(iPortID);
741                                    break;
742                            }
743                    #endif
744                            default:
745                                    appendMessagesColor(tr("LSCP Event: %1 data: %2")
746                                            .arg(::lscp_event_to_text(pLscpEvent->event()))
747                                            .arg(pLscpEvent->data()), "#996699");
748                  }                  }
749      }          }
750    }
751    
752    
753    // LADISH Level 1 -- SIGUSR1 signal handler.
754    void MainForm::handle_sigusr1 (void)
755    {
756    #if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H)
757    
758            char c;
759    
760            if (::read(g_fdSigusr1[1], &c, sizeof(c)) > 0)
761                    saveSession(false);
762    
763    #endif
764    }
765    
766    
767    void MainForm::handle_sigterm (void)
768    {
769    #if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H)
770    
771            char c;
772    
773            if (::read(g_fdSigterm[1], &c, sizeof(c)) > 0)
774                    close();
775    
776    #endif
777    }
778    
779    
780    void MainForm::updateViewMidiDeviceStatusMenu (void)
781    {
782            m_ui.viewMidiDeviceStatusMenu->clear();
783            const std::map<int, DeviceStatusForm *> statusForms
784                    = DeviceStatusForm::getInstances();
785            std::map<int, DeviceStatusForm *>::const_iterator iter
786                    = statusForms.begin();
787            for ( ; iter != statusForms.end(); ++iter) {
788                    DeviceStatusForm *pStatusForm = iter->second;
789                    m_ui.viewMidiDeviceStatusMenu->addAction(
790                            pStatusForm->visibleAction());
791            }
792  }  }
793    
794    
795  // Context menu event handler.  // Context menu event handler.
796  void MainForm::contextMenuEvent( QContextMenuEvent *pEvent )  void MainForm::contextMenuEvent( QContextMenuEvent *pEvent )
797  {  {
798      stabilizeForm();          stabilizeForm();
799    
800      ui.editMenu->exec(pEvent->globalPos());          m_ui.editMenu->exec(pEvent->globalPos());
801  }  }
802    
803    
804  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
805  // qsamplerMainForm -- Brainless public property accessors.  // QSampler::MainForm -- Brainless public property accessors.
806    
807  // The global options settings property.  // The global options settings property.
808  qsamplerOptions *MainForm::options (void)  Options *MainForm::options (void) const
809  {  {
810      return m_pOptions;          return m_pOptions;
811  }  }
812    
813    
814  // The LSCP client descriptor property.  // The LSCP client descriptor property.
815  lscp_client_t *MainForm::client (void)  lscp_client_t *MainForm::client (void) const
816  {  {
817      return m_pClient;          return m_pClient;
818  }  }
819    
820    
# Line 592  MainForm *MainForm::getInstance (void) Line 826  MainForm *MainForm::getInstance (void)
826    
827    
828  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
829  // qsamplerMainForm -- Session file stuff.  // QSampler::MainForm -- Session file stuff.
830    
831  // Format the displayable session filename.  // Format the displayable session filename.
832  QString MainForm::sessionName ( const QString& sFilename )  QString MainForm::sessionName ( const QString& sFilename )
833  {  {
834      bool bCompletePath = (m_pOptions && m_pOptions->bCompletePath);          const bool bCompletePath = (m_pOptions && m_pOptions->bCompletePath);
835      QString sSessionName = sFilename;          QString sSessionName = sFilename;
836      if (sSessionName.isEmpty())          if (sSessionName.isEmpty())
837          sSessionName = tr("Untitled") + QString::number(m_iUntitled);                  sSessionName = tr("Untitled") + QString::number(m_iUntitled);
838      else if (!bCompletePath)          else if (!bCompletePath)
839          sSessionName = QFileInfo(sSessionName).fileName();                  sSessionName = QFileInfo(sSessionName).fileName();
840      return sSessionName;          return sSessionName;
841  }  }
842    
843    
844  // Create a new session file from scratch.  // Create a new session file from scratch.
845  bool MainForm::newSession (void)  bool MainForm::newSession (void)
846  {  {
847      // Check if we can do it.          // Check if we can do it.
848      if (!closeSession(true))          if (!closeSession(true))
849          return false;                  return false;
850    
851          // Give us what the server has, right now...          // Give us what the server has, right now...
852          updateSession();          updateSession();
853    
854      // Ok increment untitled count.          // Ok increment untitled count.
855      m_iUntitled++;          m_iUntitled++;
856    
857      // Stabilize form.          // Stabilize form.
858      m_sFilename = QString::null;          m_sFilename = QString::null;
859      m_iDirtyCount = 0;          m_iDirtyCount = 0;
860      appendMessages(tr("New session: \"%1\".").arg(sessionName(m_sFilename)));          appendMessages(tr("New session: \"%1\".").arg(sessionName(m_sFilename)));
861      stabilizeForm();          stabilizeForm();
862    
863      return true;          return true;
864  }  }
865    
866    
867  // Open an existing sampler session.  // Open an existing sampler session.
868  bool MainForm::openSession (void)  bool MainForm::openSession (void)
869  {  {
870      if (m_pOptions == NULL)          if (m_pOptions == NULL)
871          return false;                  return false;
872    
873            // Ask for the filename to open...
874            QString sFilename = QFileDialog::getOpenFileName(this,
875                    QSAMPLER_TITLE ": " + tr("Open Session"), // Caption.
876                    m_pOptions->sSessionDir,                  // Start here.
877                    tr("LSCP Session files") + " (*.lscp)"    // Filter (LSCP files)
878            );
879    
880      // Ask for the filename to open...          // Have we cancelled?
881      QString sFilename = QFileDialog::getOpenFileName(          if (sFilename.isEmpty())
882                  m_pOptions->sSessionDir,                // Start here.                  return false;
883                  tr("LSCP Session files") + " (*.lscp)", // Filter (LSCP files)  
884                  this, 0,                                // Parent and name (none)          // Check if we're going to discard safely the current one...
885                  QSAMPLER_TITLE ": " + tr("Open Session")        // Caption.          if (!closeSession(true))
886      );                  return false;
   
     // Have we cancelled?  
     if (sFilename.isEmpty())  
         return false;  
   
     // Check if we're going to discard safely the current one...  
     if (!closeSession(true))  
         return false;  
887    
888      // Load it right away.          // Load it right away.
889      return loadSessionFile(sFilename);          return loadSessionFile(sFilename);
890  }  }
891    
892    
893  // Save current sampler session with another name.  // Save current sampler session with another name.
894  bool MainForm::saveSession ( bool bPrompt )  bool MainForm::saveSession ( bool bPrompt )
895  {  {
896      if (m_pOptions == NULL)          if (m_pOptions == NULL)
897          return false;                  return false;
898    
899      QString sFilename = m_sFilename;          QString sFilename = m_sFilename;
900    
901      // Ask for the file to save, if there's none...          // Ask for the file to save, if there's none...
902      if (bPrompt || sFilename.isEmpty()) {          if (bPrompt || sFilename.isEmpty()) {
903          // If none is given, assume default directory.                  // If none is given, assume default directory.
904          if (sFilename.isEmpty())                  if (sFilename.isEmpty())
905              sFilename = m_pOptions->sSessionDir;                          sFilename = m_pOptions->sSessionDir;
906          // Prompt the guy...                  // Prompt the guy...
907          sFilename = QFileDialog::getSaveFileName(                  sFilename = QFileDialog::getSaveFileName(this,
908                          sFilename,                              // Start here.                          QSAMPLER_TITLE ": " + tr("Save Session"), // Caption.
909                          tr("LSCP Session files") + " (*.lscp)", // Filter (LSCP files)                          sFilename,                                // Start here.
910                          this, 0,                                // Parent and name (none)                          tr("LSCP Session files") + " (*.lscp)"    // Filter (LSCP files)
911                          QSAMPLER_TITLE ": " + tr("Save Session")        // Caption.                  );
912          );                  // Have we cancelled it?
913          // Have we cancelled it?                  if (sFilename.isEmpty())
914          if (sFilename.isEmpty())                          return false;
915              return false;                  // Enforce .lscp extension...
916          // Enforce .lscp extension...                  if (QFileInfo(sFilename).suffix().isEmpty())
917          if (QFileInfo(sFilename).extension().isEmpty())                          sFilename += ".lscp";
918              sFilename += ".lscp";          #if 0
919          // Check if already exists...                  // Check if already exists...
920          if (sFilename != m_sFilename && QFileInfo(sFilename).exists()) {                  if (sFilename != m_sFilename && QFileInfo(sFilename).exists()) {
921              if (QMessageBox::warning(this,                          if (QMessageBox::warning(this,
922                                  QSAMPLER_TITLE ": " + tr("Warning"),                                  QSAMPLER_TITLE ": " + tr("Warning"),
923                  tr("The file already exists:\n\n"                                  tr("The file already exists:\n\n"
924                     "\"%1\"\n\n"                                  "\"%1\"\n\n"
925                     "Do you want to replace it?")                                  "Do you want to replace it?")
926                     .arg(sFilename),                                  .arg(sFilename),
927                  tr("Replace"), tr("Cancel")) > 0)                                  QMessageBox::Yes | QMessageBox::No)
928                  return false;                                  == QMessageBox::No)
929          }                                  return false;
930      }                  }
931            #endif
932            }
933    
934      // Save it right away.          // Save it right away.
935      return saveSessionFile(sFilename);          return saveSessionFile(sFilename);
936  }  }
937    
938    
939  // Close current session.  // Close current session.
940  bool MainForm::closeSession ( bool bForce )  bool MainForm::closeSession ( bool bForce )
941  {  {
942      bool bClose = true;          bool bClose = true;
943    
944      // Are we dirty enough to prompt it?          // Are we dirty enough to prompt it?
945      if (m_iDirtyCount > 0) {          if (m_iDirtyCount > 0) {
946          switch (QMessageBox::warning(this,                  switch (QMessageBox::warning(this,
947                          QSAMPLER_TITLE ": " + tr("Warning"),                          QSAMPLER_TITLE ": " + tr("Warning"),
948              tr("The current session has been changed:\n\n"                          tr("The current session has been changed:\n\n"
949              "\"%1\"\n\n"                          "\"%1\"\n\n"
950              "Do you want to save the changes?")                          "Do you want to save the changes?")
951              .arg(sessionName(m_sFilename)),                          .arg(sessionName(m_sFilename)),
952              tr("Save"), tr("Discard"), tr("Cancel"))) {                          QMessageBox::Save |
953          case 0:     // Save...                          QMessageBox::Discard |
954              bClose = saveSession(false);                          QMessageBox::Cancel)) {
955              // Fall thru....                  case QMessageBox::Save:
956          case 1:     // Discard                          bClose = saveSession(false);
957              break;                          // Fall thru....
958          default:    // Cancel.                  case QMessageBox::Discard:
959              bClose = false;                          break;
960              break;                  default:    // Cancel.
961          }                          bClose = false;
962      }                          break;
963                    }
964      // If we may close it, dot it.          }
965      if (bClose) {  
966          // Remove all channel strips from sight...          // If we may close it, dot it.
967          m_pWorkspace->setUpdatesEnabled(false);          if (bClose) {
968          QWidgetList wlist = m_pWorkspace->windowList();                  // Remove all channel strips from sight...
969          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {                  m_pWorkspace->setUpdatesEnabled(false);
970              ChannelStrip *pChannelStrip = (ChannelStrip*) wlist.at(iChannel);                  const QList<QMdiSubWindow *>& wlist
971              if (pChannelStrip) {                          = m_pWorkspace->subWindowList();
972                  qsamplerChannel *pChannel = pChannelStrip->channel();                  const int iStripCount = wlist.count();
973                  if (bForce && pChannel)                  for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
974                      pChannel->removeChannel();                          ChannelStrip *pChannelStrip = NULL;
975                  delete pChannelStrip;                          QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
976              }                          if (pMdiSubWindow)
977          }                                  pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
978          m_pWorkspace->setUpdatesEnabled(true);                          if (pChannelStrip) {
979          // We're now clean, for sure.                                  Channel *pChannel = pChannelStrip->channel();
980          m_iDirtyCount = 0;                                  if (bForce && pChannel)
981      }                                          pChannel->removeChannel();
982                                    delete pChannelStrip;
983                            }
984                            if (pMdiSubWindow)
985                                    delete pMdiSubWindow;
986                    }
987                    m_pWorkspace->setUpdatesEnabled(true);
988                    // We're now clean, for sure.
989                    m_iDirtyCount = 0;
990            }
991    
992      return bClose;          return bClose;
993  }  }
994    
995    
996  // Load a session from specific file path.  // Load a session from specific file path.
997  bool MainForm::loadSessionFile ( const QString& sFilename )  bool MainForm::loadSessionFile ( const QString& sFilename )
998  {  {
999      if (m_pClient == NULL)          if (m_pClient == NULL)
1000          return false;                  return false;
1001    
1002      // Open and read from real file.          // Open and read from real file.
1003      QFile file(sFilename);          QFile file(sFilename);
1004      if (!file.open(IO_ReadOnly)) {          if (!file.open(QIODevice::ReadOnly)) {
1005          appendMessagesError(tr("Could not open \"%1\" session file.\n\nSorry.").arg(sFilename));                  appendMessagesError(
1006          return false;                          tr("Could not open \"%1\" session file.\n\nSorry.")
1007      }                          .arg(sFilename));
1008                    return false;
1009            }
1010    
1011          // Tell the world we'll take some time...          // Tell the world we'll take some time...
1012          QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));          QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1013    
1014      // Read the file.          // Read the file.
1015          int iLine = 0;          int iLine = 0;
1016      int iErrors = 0;          int iErrors = 0;
1017      QTextStream ts(&file);          QTextStream ts(&file);
1018      while (!ts.atEnd()) {          while (!ts.atEnd()) {
1019          // Read the line.                  // Read the line.
1020          QString sCommand = ts.readLine().stripWhiteSpace();                  QString sCommand = ts.readLine().trimmed();
1021                  iLine++;                  iLine++;
1022          // If not empty, nor a comment, call the server...                  // If not empty, nor a comment, call the server...
1023          if (!sCommand.isEmpty() && sCommand[0] != '#') {                  if (!sCommand.isEmpty() && sCommand[0] != '#') {
1024                          // Remember that, no matter what,                          // Remember that, no matter what,
1025                          // all LSCP commands are CR/LF terminated.                          // all LSCP commands are CR/LF terminated.
1026                          sCommand += "\r\n";                          sCommand += "\r\n";
1027                          if (::lscp_client_query(m_pClient, sCommand.latin1()) != LSCP_OK) {                          if (::lscp_client_query(m_pClient, sCommand.toUtf8().constData())
1028                                    != LSCP_OK) {
1029                                  appendMessagesColor(QString("%1(%2): %3")                                  appendMessagesColor(QString("%1(%2): %3")
1030                                          .arg(QFileInfo(sFilename).fileName()).arg(iLine)                                          .arg(QFileInfo(sFilename).fileName()).arg(iLine)
1031                                          .arg(sCommand.simplifyWhiteSpace()), "#996633");                                          .arg(sCommand.simplified()), "#996633");
1032                                  appendMessagesClient("lscp_client_query");                                  appendMessagesClient("lscp_client_query");
1033                                  iErrors++;                                  iErrors++;
1034                          }                          }
1035          }                  }
1036          // Try to make it snappy :)                  // Try to make it snappy :)
1037          QApplication::processEvents(QEventLoop::ExcludeUserInput);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1038      }          }
1039    
1040      // Ok. we've read it.          // Ok. we've read it.
1041      file.close();          file.close();
1042    
1043          // Now we'll try to create (update) the whole GUI session.          // Now we'll try to create (update) the whole GUI session.
1044          updateSession();          updateSession();
# Line 800  bool MainForm::loadSessionFile ( const Q Line 1047  bool MainForm::loadSessionFile ( const Q
1047          QApplication::restoreOverrideCursor();          QApplication::restoreOverrideCursor();
1048    
1049          // Have we any errors?          // Have we any errors?
1050          if (iErrors > 0)          if (iErrors > 0) {
1051                  appendMessagesError(tr("Session loaded with errors\nfrom \"%1\".\n\nSorry.").arg(sFilename));                  appendMessagesError(
1052                            tr("Session loaded with errors\nfrom \"%1\".\n\nSorry.")
1053                            .arg(sFilename));
1054            }
1055    
1056      // Save as default session directory.          // Save as default session directory.
1057      if (m_pOptions)          if (m_pOptions)
1058          m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);                  m_pOptions->sSessionDir = QFileInfo(sFilename).dir().absolutePath();
1059          // We're not dirty anymore, if loaded without errors,          // We're not dirty anymore, if loaded without errors,
1060          m_iDirtyCount = iErrors;          m_iDirtyCount = iErrors;
1061      // Stabilize form...          // Stabilize form...
1062      m_sFilename = sFilename;          m_sFilename = sFilename;
1063      updateRecentFiles(sFilename);          updateRecentFiles(sFilename);
1064      appendMessages(tr("Open session: \"%1\".").arg(sessionName(m_sFilename)));          appendMessages(tr("Open session: \"%1\".").arg(sessionName(m_sFilename)));
1065    
1066      // Make that an overall update.          // Make that an overall update.
1067      stabilizeForm();          stabilizeForm();
1068      return true;          return true;
1069  }  }
1070    
1071    
# Line 831  bool MainForm::saveSessionFile ( const Q Line 1081  bool MainForm::saveSessionFile ( const Q
1081                  return false;                  return false;
1082          }          }
1083    
1084      // Open and write into real file.          // Open and write into real file.
1085      QFile file(sFilename);          QFile file(sFilename);
1086      if (!file.open(IO_WriteOnly | IO_Truncate)) {          if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
1087          appendMessagesError(tr("Could not open \"%1\" session file.\n\nSorry.").arg(sFilename));                  appendMessagesError(
1088          return false;                          tr("Could not open \"%1\" session file.\n\nSorry.")
1089      }                          .arg(sFilename));
1090                    return false;
1091            }
1092    
1093          // Tell the world we'll take some time...          // Tell the world we'll take some time...
1094          QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));          QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1095    
1096      // Write the file.          // Write the file.
1097      int  iErrors = 0;          int iErrors = 0;
1098      QTextStream ts(&file);          QTextStream ts(&file);
1099      ts << "# " << QSAMPLER_TITLE " - " << tr(QSAMPLER_SUBTITLE) << endl;          ts << "# " << QSAMPLER_TITLE " - " << tr(QSAMPLER_SUBTITLE) << endl;
1100      ts << "# " << tr("Version")          ts << "# " << tr("Version") << ": " CONFIG_BUILD_VERSION << endl;
1101         << ": " QSAMPLER_VERSION << endl;  //      ts << "# " << tr("Build") << ": " CONFIG_BUILD_DATE << endl;
1102      ts << "# " << tr("Build")          ts << "#"  << endl;
1103         << ": " __DATE__ " " __TIME__ << endl;          ts << "# " << tr("File")
1104      ts << "#"  << endl;          << ": " << QFileInfo(sFilename).fileName() << endl;
1105      ts << "# " << tr("File")          ts << "# " << tr("Date")
1106         << ": " << QFileInfo(sFilename).fileName() << endl;          << ": " << QDate::currentDate().toString("MMM dd yyyy")
1107      ts << "# " << tr("Date")          << " "  << QTime::currentTime().toString("hh:mm:ss") << endl;
1108         << ": " << QDate::currentDate().toString("MMM dd yyyy")          ts << "#"  << endl;
1109         << " "  << QTime::currentTime().toString("hh:mm:ss") << endl;          ts << endl;
     ts << "#"  << endl;  
     ts << endl;  
1110    
1111          // It is assumed that this new kind of device+session file          // It is assumed that this new kind of device+session file
1112          // will be loaded from a complete initialized server...          // will be loaded from a complete initialized server...
1113          int *piDeviceIDs;          int *piDeviceIDs;
1114          int  iDevice;          int  i, iDevice;
1115          ts << "RESET" << endl;          ts << "RESET" << endl;
1116    
1117          // Audio device mapping.          // Audio device mapping.
1118          QMap<int, int> audioDeviceMap;          QMap<int, int> audioDeviceMap; iDevice = 0;
1119          piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Audio);          piDeviceIDs = Device::getDevices(m_pClient, Device::Audio);
1120          for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {          for (i = 0; piDeviceIDs && piDeviceIDs[i] >= 0; ++i) {
1121                  ts << endl;                  Device device(Device::Audio, piDeviceIDs[i]);
1122                  qsamplerDevice device(qsamplerDevice::Audio, piDeviceIDs[iDevice]);                  // Avoid plug-in driver devices...
1123                    if (device.driverName().toUpper() == "PLUGIN")
1124                            continue;
1125                  // Audio device specification...                  // Audio device specification...
1126                    ts << endl;
1127                  ts << "# " << device.deviceTypeName() << " " << device.driverName()                  ts << "# " << device.deviceTypeName() << " " << device.driverName()
1128                          << " " << tr("Device") << " " << iDevice << endl;                          << " " << tr("Device") << " " << iDevice << endl;
1129                  ts << "CREATE AUDIO_OUTPUT_DEVICE " << device.driverName();                  ts << "CREATE AUDIO_OUTPUT_DEVICE " << device.driverName();
1130                  qsamplerDeviceParamMap::ConstIterator deviceParam;                  DeviceParamMap::ConstIterator deviceParam;
1131                  for (deviceParam = device.params().begin();                  for (deviceParam = device.params().begin();
1132                                  deviceParam != device.params().end();                                  deviceParam != device.params().end();
1133                                          ++deviceParam) {                                          ++deviceParam) {
1134                          const qsamplerDeviceParam& param = deviceParam.data();                          const DeviceParam& param = deviceParam.value();
1135                          if (param.value.isEmpty()) ts << "# ";                          if (param.value.isEmpty()) ts << "# ";
1136                          ts << " " << deviceParam.key() << "='" << param.value << "'";                          ts << " " << deviceParam.key() << "='" << param.value << "'";
1137                  }                  }
1138                  ts << endl;                  ts << endl;
1139                  // Audio channel parameters...                  // Audio channel parameters...
1140                  int iPort = 0;                  int iPort = 0;
1141                  for (qsamplerDevicePort *pPort = device.ports().first();                  QListIterator<DevicePort *> iter(device.ports());
1142                                  pPort;                  while (iter.hasNext()) {
1143                                          pPort = device.ports().next(), ++iPort) {                          DevicePort *pPort = iter.next();
1144                          qsamplerDeviceParamMap::ConstIterator portParam;                          DeviceParamMap::ConstIterator portParam;
1145                          for (portParam = pPort->params().begin();                          for (portParam = pPort->params().begin();
1146                                          portParam != pPort->params().end();                                          portParam != pPort->params().end();
1147                                                  ++portParam) {                                                  ++portParam) {
1148                                  const qsamplerDeviceParam& param = portParam.data();                                  const DeviceParam& param = portParam.value();
1149                                  if (param.fix || param.value.isEmpty()) ts << "# ";                                  if (param.fix || param.value.isEmpty()) ts << "# ";
1150                                  ts << "SET AUDIO_OUTPUT_CHANNEL_PARAMETER " << iDevice                                  ts << "SET AUDIO_OUTPUT_CHANNEL_PARAMETER " << iDevice
1151                                          << " " << iPort << " " << portParam.key()                                          << " " << iPort << " " << portParam.key()
1152                                          << "='" << param.value << "'" << endl;                                          << "='" << param.value << "'" << endl;
1153                          }                          }
1154                            iPort++;
1155                  }                  }
1156                  // Audio device index/id mapping.                  // Audio device index/id mapping.
1157                  audioDeviceMap[device.deviceID()] = iDevice;                  audioDeviceMap.insert(device.deviceID(), iDevice++);
1158                  // Try to keep it snappy :)                  // Try to keep it snappy :)
1159                  QApplication::processEvents(QEventLoop::ExcludeUserInput);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1160          }          }
1161    
1162          // MIDI device mapping.          // MIDI device mapping.
1163          QMap<int, int> midiDeviceMap;          QMap<int, int> midiDeviceMap; iDevice = 0;
1164          piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Midi);          piDeviceIDs = Device::getDevices(m_pClient, Device::Midi);
1165          for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {          for (i = 0; piDeviceIDs && piDeviceIDs[i] >= 0; ++i) {
1166                  ts << endl;                  Device device(Device::Midi, piDeviceIDs[i]);
1167                  qsamplerDevice device(qsamplerDevice::Midi, piDeviceIDs[iDevice]);                  // Avoid plug-in driver devices...
1168                    if (device.driverName().toUpper() == "PLUGIN")
1169                            continue;
1170                  // MIDI device specification...                  // MIDI device specification...
1171                    ts << endl;
1172                  ts << "# " << device.deviceTypeName() << " " << device.driverName()                  ts << "# " << device.deviceTypeName() << " " << device.driverName()
1173                          << " " << tr("Device") << " " << iDevice << endl;                          << " " << tr("Device") << " " << iDevice << endl;
1174                  ts << "CREATE MIDI_INPUT_DEVICE " << device.driverName();                  ts << "CREATE MIDI_INPUT_DEVICE " << device.driverName();
1175                  qsamplerDeviceParamMap::ConstIterator deviceParam;                  DeviceParamMap::ConstIterator deviceParam;
1176                  for (deviceParam = device.params().begin();                  for (deviceParam = device.params().begin();
1177                                  deviceParam != device.params().end();                                  deviceParam != device.params().end();
1178                                          ++deviceParam) {                                          ++deviceParam) {
1179                          const qsamplerDeviceParam& param = deviceParam.data();                          const DeviceParam& param = deviceParam.value();
1180                          if (param.value.isEmpty()) ts << "# ";                          if (param.value.isEmpty()) ts << "# ";
1181                          ts << " " << deviceParam.key() << "='" << param.value << "'";                          ts << " " << deviceParam.key() << "='" << param.value << "'";
1182                  }                  }
1183                  ts << endl;                  ts << endl;
1184                  // MIDI port parameters...                  // MIDI port parameters...
1185                  int iPort = 0;                  int iPort = 0;
1186                  for (qsamplerDevicePort *pPort = device.ports().first();                  QListIterator<DevicePort *> iter(device.ports());
1187                                  pPort;                  while (iter.hasNext()) {
1188                                          pPort = device.ports().next(), ++iPort) {                          DevicePort *pPort = iter.next();
1189                          qsamplerDeviceParamMap::ConstIterator portParam;                          DeviceParamMap::ConstIterator portParam;
1190                          for (portParam = pPort->params().begin();                          for (portParam = pPort->params().begin();
1191                                          portParam != pPort->params().end();                                          portParam != pPort->params().end();
1192                                                  ++portParam) {                                                  ++portParam) {
1193                                  const qsamplerDeviceParam& param = portParam.data();                                  const DeviceParam& param = portParam.value();
1194                                  if (param.fix || param.value.isEmpty()) ts << "# ";                                  if (param.fix || param.value.isEmpty()) ts << "# ";
1195                                  ts << "SET MIDI_INPUT_PORT_PARAMETER " << iDevice                                  ts << "SET MIDI_INPUT_PORT_PARAMETER " << iDevice
1196                                     << " " << iPort << " " << portParam.key()                                  << " " << iPort << " " << portParam.key()
1197                                     << "='" << param.value << "'" << endl;                                  << "='" << param.value << "'" << endl;
1198                          }                          }
1199                            iPort++;
1200                  }                  }
1201                  // MIDI device index/id mapping.                  // MIDI device index/id mapping.
1202                  midiDeviceMap[device.deviceID()] = iDevice;                  midiDeviceMap.insert(device.deviceID(), iDevice++);
1203                  // Try to keep it snappy :)                  // Try to keep it snappy :)
1204                  QApplication::processEvents(QEventLoop::ExcludeUserInput);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1205          }          }
1206          ts << endl;          ts << endl;
1207    
# Line 952  bool MainForm::saveSessionFile ( const Q Line 1210  bool MainForm::saveSessionFile ( const Q
1210          QMap<int, int> midiInstrumentMap;          QMap<int, int> midiInstrumentMap;
1211          int *piMaps = ::lscp_list_midi_instrument_maps(m_pClient);          int *piMaps = ::lscp_list_midi_instrument_maps(m_pClient);
1212          for (int iMap = 0; piMaps && piMaps[iMap] >= 0; iMap++) {          for (int iMap = 0; piMaps && piMaps[iMap] >= 0; iMap++) {
1213                  int iMidiMap = piMaps[iMap];                  const int iMidiMap = piMaps[iMap];
1214                  const char *pszMapName                  const char *pszMapName
1215                          = ::lscp_get_midi_instrument_map_name(m_pClient, iMidiMap);                          = ::lscp_get_midi_instrument_map_name(m_pClient, iMidiMap);
1216                  ts << "# " << tr("MIDI instrument map") << " " << iMap;                  ts << "# " << tr("MIDI instrument map") << " " << iMap;
# Line 1000  bool MainForm::saveSessionFile ( const Q Line 1258  bool MainForm::saveSessionFile ( const Q
1258                                  iErrors++;                                  iErrors++;
1259                          }                          }
1260                          // Try to keep it snappy :)                          // Try to keep it snappy :)
1261                          QApplication::processEvents(QEventLoop::ExcludeUserInput);                          QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1262                  }                  }
1263                  ts << endl;                  ts << endl;
1264                  // Check for errors...                  // Check for errors...
# Line 1009  bool MainForm::saveSessionFile ( const Q Line 1267  bool MainForm::saveSessionFile ( const Q
1267                          iErrors++;                          iErrors++;
1268                  }                  }
1269                  // MIDI strument index/id mapping.                  // MIDI strument index/id mapping.
1270                  midiInstrumentMap[iMidiMap] = iMap;                  midiInstrumentMap.insert(iMidiMap, iMap);
1271          }          }
1272          // Check for errors...          // Check for errors...
1273          if (piMaps == NULL && ::lscp_client_get_errno(m_pClient)) {          if (piMaps == NULL && ::lscp_client_get_errno(m_pClient)) {
# Line 1018  bool MainForm::saveSessionFile ( const Q Line 1276  bool MainForm::saveSessionFile ( const Q
1276          }          }
1277  #endif  // CONFIG_MIDI_INSTRUMENT  #endif  // CONFIG_MIDI_INSTRUMENT
1278    
1279          // Sampler channel mapping.          // Sampler channel mapping...
1280      QWidgetList wlist = m_pWorkspace->windowList();          int iChannelID = 0;
1281      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          const QList<QMdiSubWindow *>& wlist
1282          ChannelStrip* pChannelStrip                  = m_pWorkspace->subWindowList();
1283                          = static_cast<ChannelStrip *> (wlist.at(iChannel));          const int iStripCount = wlist.count();
1284          if (pChannelStrip) {          for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
1285              qsamplerChannel *pChannel = pChannelStrip->channel();                  ChannelStrip *pChannelStrip = NULL;
1286              if (pChannel) {                  QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
1287                  ts << "# " << tr("Channel") << " " << iChannel << endl;                  if (pMdiSubWindow)
1288                  ts << "ADD CHANNEL" << endl;                          pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
1289                    if (pChannelStrip) {
1290                            Channel *pChannel = pChannelStrip->channel();
1291                            if (pChannel) {
1292                                    // Avoid "artifial" plug-in devices...
1293                                    const int iAudioDevice = pChannel->audioDevice();
1294                                    if (!audioDeviceMap.contains(iAudioDevice))
1295                                            continue;
1296                                    const int iMidiDevice = pChannel->midiDevice();
1297                                    if (!midiDeviceMap.contains(iMidiDevice))
1298                                            continue;
1299                                    // Go for regular, canonical devices...
1300                                    ts << "# " << tr("Channel") << " " << iChannelID << endl;
1301                                    ts << "ADD CHANNEL" << endl;
1302                                  if (audioDeviceMap.isEmpty()) {                                  if (audioDeviceMap.isEmpty()) {
1303                                          ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannel                                          ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannelID
1304                                                  << " " << pChannel->audioDriver() << endl;                                                  << " " << pChannel->audioDriver() << endl;
1305                                  } else {                                  } else {
1306                                          ts << "SET CHANNEL AUDIO_OUTPUT_DEVICE " << iChannel                                          ts << "SET CHANNEL AUDIO_OUTPUT_DEVICE " << iChannelID
1307                                                  << " " << audioDeviceMap[pChannel->audioDevice()] << endl;                                                  << " " << audioDeviceMap.value(iAudioDevice) << endl;
1308                                  }                                  }
1309                                  if (midiDeviceMap.isEmpty()) {                                  if (midiDeviceMap.isEmpty()) {
1310                                          ts << "SET CHANNEL MIDI_INPUT_TYPE " << iChannel                                          ts << "SET CHANNEL MIDI_INPUT_TYPE " << iChannelID
1311                                                  << " " << pChannel->midiDriver() << endl;                                                  << " " << pChannel->midiDriver() << endl;
1312                                  } else {                                  } else {
1313                                          ts << "SET CHANNEL MIDI_INPUT_DEVICE " << iChannel                                          ts << "SET CHANNEL MIDI_INPUT_DEVICE " << iChannelID
1314                                                  << " " << midiDeviceMap[pChannel->midiDevice()] << endl;                                                  << " " << midiDeviceMap.value(iMidiDevice) << endl;
1315                                  }                                  }
1316                                  ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannel                                  ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannelID
1317                                          << " " << pChannel->midiPort() << endl;                                          << " " << pChannel->midiPort() << endl;
1318                  ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannel << " ";                                  ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannelID << " ";
1319                  if (pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL)                                  if (pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL)
1320                      ts << "ALL";                                          ts << "ALL";
1321                  else                                  else
1322                      ts << pChannel->midiChannel();                                          ts << pChannel->midiChannel();
1323                  ts << endl;                                  ts << endl;
1324                  ts << "LOAD ENGINE " << pChannel->engineName() << " " << iChannel << endl;                                  ts << "LOAD ENGINE " << pChannel->engineName()
1325                                            << " " << iChannelID << endl;
1326                                  if (pChannel->instrumentStatus() < 100) ts << "# ";                                  if (pChannel->instrumentStatus() < 100) ts << "# ";
1327                                  ts << "LOAD INSTRUMENT NON_MODAL '" << pChannel->instrumentFile() << "' "                                  ts << "LOAD INSTRUMENT NON_MODAL '"
1328                                          << pChannel->instrumentNr() << " " << iChannel << endl;                                          << pChannel->instrumentFile() << "' "
1329                                  qsamplerChannelRoutingMap::ConstIterator audioRoute;                                          << pChannel->instrumentNr() << " " << iChannelID << endl;
1330                                    ChannelRoutingMap::ConstIterator audioRoute;
1331                                  for (audioRoute = pChannel->audioRouting().begin();                                  for (audioRoute = pChannel->audioRouting().begin();
1332                                                  audioRoute != pChannel->audioRouting().end();                                                  audioRoute != pChannel->audioRouting().end();
1333                                                          ++audioRoute) {                                                          ++audioRoute) {
1334                                          ts << "SET CHANNEL AUDIO_OUTPUT_CHANNEL " << iChannel                                          ts << "SET CHANNEL AUDIO_OUTPUT_CHANNEL " << iChannelID
1335                                                  << " " << audioRoute.key()                                                  << " " << audioRoute.key()
1336                                                  << " " << audioRoute.data() << endl;                                                  << " " << audioRoute.value() << endl;
1337                                  }                                  }
1338                                  ts << "SET CHANNEL VOLUME " << iChannel                                  ts << "SET CHANNEL VOLUME " << iChannelID
1339                                          << " " << pChannel->volume() << endl;                                          << " " << pChannel->volume() << endl;
1340                                  if (pChannel->channelMute())                                  if (pChannel->channelMute())
1341                                          ts << "SET CHANNEL MUTE " << iChannel << " 1" << endl;                                          ts << "SET CHANNEL MUTE " << iChannelID << " 1" << endl;
1342                                  if (pChannel->channelSolo())                                  if (pChannel->channelSolo())
1343                                          ts << "SET CHANNEL SOLO " << iChannel << " 1" << endl;                                          ts << "SET CHANNEL SOLO " << iChannelID << " 1" << endl;
1344  #ifdef CONFIG_MIDI_INSTRUMENT                          #ifdef CONFIG_MIDI_INSTRUMENT
1345                                  if (pChannel->midiMap() >= 0) {                                  const int iMidiMap = pChannel->midiMap();
1346                                          ts << "SET CHANNEL MIDI_INSTRUMENT_MAP " << iChannel                                  if (midiInstrumentMap.contains(iMidiMap)) {
1347                                                  << " " << midiInstrumentMap[pChannel->midiMap()] << endl;                                          ts << "SET CHANNEL MIDI_INSTRUMENT_MAP " << iChannelID
1348                                                    << " " << midiInstrumentMap.value(iMidiMap) << endl;
1349                                  }                                  }
1350  #endif                          #endif
1351  #ifdef CONFIG_FXSEND                          #ifdef CONFIG_FXSEND
                                 int iChannelID = pChannel->channelID();  
1352                                  int *piFxSends = ::lscp_list_fxsends(m_pClient, iChannelID);                                  int *piFxSends = ::lscp_list_fxsends(m_pClient, iChannelID);
1353                                  for (int iFxSend = 0;                                  for (int iFxSend = 0;
1354                                                  piFxSends && piFxSends[iFxSend] >= 0;                                                  piFxSends && piFxSends[iFxSend] >= 0;
# Line 1083  bool MainForm::saveSessionFile ( const Q Line 1356  bool MainForm::saveSessionFile ( const Q
1356                                          lscp_fxsend_info_t *pFxSendInfo = ::lscp_get_fxsend_info(                                          lscp_fxsend_info_t *pFxSendInfo = ::lscp_get_fxsend_info(
1357                                                  m_pClient, iChannelID, piFxSends[iFxSend]);                                                  m_pClient, iChannelID, piFxSends[iFxSend]);
1358                                          if (pFxSendInfo) {                                          if (pFxSendInfo) {
1359                                                  ts << "CREATE FX_SEND " << iChannel                                                  ts << "CREATE FX_SEND " << iChannelID
1360                                                          << " " << pFxSendInfo->midi_controller;                                                          << " " << pFxSendInfo->midi_controller;
1361                                                  if (pFxSendInfo->name)                                                  if (pFxSendInfo->name)
1362                                                          ts << " '" << pFxSendInfo->name << "'";                                                          ts << " '" << pFxSendInfo->name << "'";
# Line 1093  bool MainForm::saveSessionFile ( const Q Line 1366  bool MainForm::saveSessionFile ( const Q
1366                                                                  piRouting && piRouting[iAudioSrc] >= 0;                                                                  piRouting && piRouting[iAudioSrc] >= 0;
1367                                                                          iAudioSrc++) {                                                                          iAudioSrc++) {
1368                                                          ts << "SET FX_SEND AUDIO_OUTPUT_CHANNEL "                                                          ts << "SET FX_SEND AUDIO_OUTPUT_CHANNEL "
1369                                                                  << iChannel                                                                  << iChannelID
1370                                                                  << " " << iFxSend                                                                  << " " << iFxSend
1371                                                                  << " " << iAudioSrc                                                                  << " " << iAudioSrc
1372                                                                  << " " << piRouting[iAudioSrc] << endl;                                                                  << " " << piRouting[iAudioSrc] << endl;
1373                                                  }                                                  }
1374  #ifdef CONFIG_FXSEND_LEVEL                                          #ifdef CONFIG_FXSEND_LEVEL
1375                                                  ts << "SET FX_SEND LEVEL " << iChannel                                                  ts << "SET FX_SEND LEVEL " << iChannelID
1376                                                          << " " << iFxSend                                                          << " " << iFxSend
1377                                                          << " " << pFxSendInfo->level << endl;                                                          << " " << pFxSendInfo->level << endl;
1378  #endif                                          #endif
1379                                          }       // Check for errors...                                          }       // Check for errors...
1380                                          else if (::lscp_client_get_errno(m_pClient)) {                                          else if (::lscp_client_get_errno(m_pClient)) {
1381                                                  appendMessagesClient("lscp_get_fxsend_info");                                                  appendMessagesClient("lscp_get_fxsend_info");
1382                                                  iErrors++;                                                  iErrors++;
1383                                          }                                          }
1384                                  }                                  }
1385  #endif                          #endif
1386                  ts << endl;                                  ts << endl;
1387              }                                  // Go for next channel...
1388          }                                  ++iChannelID;
1389          // Try to keep it snappy :)                          }
1390          QApplication::processEvents(QEventLoop::ExcludeUserInput);                  }
1391      }                  // Try to keep it snappy :)
1392                    QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1393            }
1394    
1395  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
1396          ts << "# " << tr("Global volume level") << endl;          ts << "# " << tr("Global volume level") << endl;
# Line 1123  bool MainForm::saveSessionFile ( const Q Line 1398  bool MainForm::saveSessionFile ( const Q
1398          ts << endl;          ts << endl;
1399  #endif  #endif
1400    
1401      // Ok. we've wrote it.          // Ok. we've wrote it.
1402      file.close();          file.close();
1403    
1404          // We're fornerly done.          // We're fornerly done.
1405          QApplication::restoreOverrideCursor();          QApplication::restoreOverrideCursor();
1406    
1407      // Have we any errors?          // Have we any errors?
1408      if (iErrors > 0)          if (iErrors > 0) {
1409          appendMessagesError(tr("Some settings could not be saved\nto \"%1\" session file.\n\nSorry.").arg(sFilename));                  appendMessagesError(
1410                            tr("Some settings could not be saved\n"
1411      // Save as default session directory.                          "to \"%1\" session file.\n\nSorry.")
1412      if (m_pOptions)                          .arg(sFilename));
1413          m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);          }
1414      // We're not dirty anymore.  
1415      m_iDirtyCount = 0;          // Save as default session directory.
1416      // Stabilize form...          if (m_pOptions)
1417      m_sFilename = sFilename;                  m_pOptions->sSessionDir = QFileInfo(sFilename).dir().absolutePath();
1418      updateRecentFiles(sFilename);          // We're not dirty anymore.
1419      appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename)));          m_iDirtyCount = 0;
1420      stabilizeForm();          // Stabilize form...
1421      return true;          m_sFilename = sFilename;
1422            updateRecentFiles(sFilename);
1423            appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename)));
1424            stabilizeForm();
1425            return true;
1426  }  }
1427    
1428    
1429  // Session change receiver slot.  // Session change receiver slot.
1430  void MainForm::sessionDirty (void)  void MainForm::sessionDirty (void)
1431  {  {
1432      // Just mark the dirty form.          // Just mark the dirty form.
1433      m_iDirtyCount++;          m_iDirtyCount++;
1434      // and update the form status...          // and update the form status...
1435      stabilizeForm();          stabilizeForm();
1436  }  }
1437    
1438    
1439  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
1440  // qsamplerMainForm -- File Action slots.  // QSampler::MainForm -- File Action slots.
1441    
1442  // Create a new sampler session.  // Create a new sampler session.
1443  void MainForm::fileNew (void)  void MainForm::fileNew (void)
1444  {  {
1445      // Of course we'll start clean new.          // Of course we'll start clean new.
1446      newSession();          newSession();
1447  }  }
1448    
1449    
1450  // Open an existing sampler session.  // Open an existing sampler session.
1451  void MainForm::fileOpen (void)  void MainForm::fileOpen (void)
1452  {  {
1453      // Open it right away.          // Open it right away.
1454      openSession();          openSession();
1455  }  }
1456    
1457    
1458  // Open a recent file session.  // Open a recent file session.
1459  void MainForm::fileOpenRecent ( int iIndex )  void MainForm::fileOpenRecent (void)
1460  {  {
1461      // Check if we can safely close the current session...          // Retrive filename index from action data...
1462      if (m_pOptions && closeSession(true)) {          QAction *pAction = qobject_cast<QAction *> (sender());
1463          QString sFilename = m_pOptions->recentFiles[iIndex];          if (pAction && m_pOptions) {
1464          loadSessionFile(sFilename);                  const int iIndex = pAction->data().toInt();
1465      }                  if (iIndex >= 0 && iIndex < m_pOptions->recentFiles.count()) {
1466                            QString sFilename = m_pOptions->recentFiles[iIndex];
1467                            // Check if we can safely close the current session...
1468                            if (!sFilename.isEmpty() && closeSession(true))
1469                                    loadSessionFile(sFilename);
1470                    }
1471            }
1472  }  }
1473    
1474    
1475  // Save current sampler session.  // Save current sampler session.
1476  void MainForm::fileSave (void)  void MainForm::fileSave (void)
1477  {  {
1478      // Save it right away.          // Save it right away.
1479      saveSession(false);          saveSession(false);
1480  }  }
1481    
1482    
1483  // Save current sampler session with another name.  // Save current sampler session with another name.
1484  void MainForm::fileSaveAs (void)  void MainForm::fileSaveAs (void)
1485  {  {
1486      // Save it right away, maybe with another name.          // Save it right away, maybe with another name.
1487      saveSession(true);          saveSession(true);
1488  }  }
1489    
1490    
1491  // Reset the sampler instance.  // Reset the sampler instance.
1492  void MainForm::fileReset (void)  void MainForm::fileReset (void)
1493  {  {
1494      if (m_pClient == NULL)          if (m_pClient == NULL)
1495          return;                  return;
1496    
1497      // Ask user whether he/she want's an internal sampler reset...          // Ask user whether he/she want's an internal sampler reset...
1498      if (QMessageBox::warning(this,          if (m_pOptions && m_pOptions->bConfirmReset) {
1499                  QSAMPLER_TITLE ": " + tr("Warning"),                  const QString& sTitle = QSAMPLER_TITLE ": " + tr("Warning");
1500          tr("Resetting the sampler instance will close\n"                  const QString& sText = tr(
1501             "all device and channel configurations.\n\n"                          "Resetting the sampler instance will close\n"
1502             "Please note that this operation may cause\n"                          "all device and channel configurations.\n\n"
1503             "temporary MIDI and Audio disruption.\n\n"                          "Please note that this operation may cause\n"
1504             "Do you want to reset the sampler engine now?"),                          "temporary MIDI and Audio disruption.\n\n"
1505          tr("Reset"), tr("Cancel")) > 0)                          "Do you want to reset the sampler engine now?");
1506          return;          #if 0
1507                    if (QMessageBox::warning(this, sTitle, sText,
1508                            QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
1509                            return;
1510            #else
1511                    QMessageBox mbox(this);
1512                    mbox.setIcon(QMessageBox::Warning);
1513                    mbox.setWindowTitle(sTitle);
1514                    mbox.setText(sText);
1515                    mbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
1516                    QCheckBox cbox(tr("Don't ask this again"));
1517                    cbox.setChecked(false);
1518                    cbox.blockSignals(true);
1519                    mbox.addButton(&cbox, QMessageBox::ActionRole);
1520                    if (mbox.exec() == QMessageBox::Cancel)
1521                            return;
1522                    if (cbox.isChecked())
1523                            m_pOptions->bConfirmReset = false;
1524            #endif
1525            }
1526    
1527          // Trye closing the current session, first...          // Trye closing the current session, first...
1528          if (!closeSession(true))          if (!closeSession(true))
1529                  return;                  return;
1530    
1531      // Just do the reset, after closing down current session...          // Just do the reset, after closing down current session...
1532          // Do the actual sampler reset...          // Do the actual sampler reset...
1533          if (::lscp_reset_sampler(m_pClient) != LSCP_OK) {          if (::lscp_reset_sampler(m_pClient) != LSCP_OK) {
1534                  appendMessagesClient("lscp_reset_sampler");                  appendMessagesClient("lscp_reset_sampler");
# Line 1232  void MainForm::fileReset (void) Line 1536  void MainForm::fileReset (void)
1536                  return;                  return;
1537          }          }
1538    
1539      // Log this.          // Log this.
1540      appendMessages(tr("Sampler reset."));          appendMessages(tr("Sampler reset."));
1541    
1542          // Make it a new session...          // Make it a new session...
1543          newSession();          newSession();
# Line 1243  void MainForm::fileReset (void) Line 1547  void MainForm::fileReset (void)
1547  // Restart the client/server instance.  // Restart the client/server instance.
1548  void MainForm::fileRestart (void)  void MainForm::fileRestart (void)
1549  {  {
1550      if (m_pOptions == NULL)          if (m_pOptions == NULL)
1551          return;                  return;
1552    
1553      bool bRestart = true;          bool bRestart = true;
1554    
1555      // Ask user whether he/she want's a complete restart...          // Ask user whether he/she want's a complete restart...
1556      // (if we're currently up and running)          // (if we're currently up and running)
1557      if (bRestart && m_pClient) {          if (m_pOptions && m_pOptions->bConfirmRestart) {
1558          bRestart = (QMessageBox::warning(this,                  const QString& sTitle = QSAMPLER_TITLE ": " + tr("Warning");
1559                          QSAMPLER_TITLE ": " + tr("Warning"),                  const QString& sText = tr(
1560              tr("New settings will be effective after\n"                          "New settings will be effective after\n"
1561                 "restarting the client/server connection.\n\n"                          "restarting the client/server connection.\n\n"
1562                 "Please note that this operation may cause\n"                          "Please note that this operation may cause\n"
1563                 "temporary MIDI and Audio disruption.\n\n"                          "temporary MIDI and Audio disruption.\n\n"
1564                 "Do you want to restart the connection now?"),                          "Do you want to restart the connection now?");
1565              tr("Restart"), tr("Cancel")) == 0);          #if 0
1566      }                  if (QMessageBox::warning(this, sTitle, sText,
1567                            QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
1568      // Are we still for it?                          bRestart = false;
1569      if (bRestart && closeSession(true)) {          #else
1570          // Stop server, it will force the client too.                  QMessageBox mbox(this);
1571          stopServer();                  mbox.setIcon(QMessageBox::Warning);
1572          // Reschedule a restart...                  mbox.setWindowTitle(sTitle);
1573          startSchedule(m_pOptions->iStartDelay);                  mbox.setText(sText);
1574      }                  mbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
1575                    QCheckBox cbox(tr("Don't ask this again"));
1576                    cbox.setChecked(false);
1577                    cbox.blockSignals(true);
1578                    mbox.addButton(&cbox, QMessageBox::ActionRole);
1579                    if (mbox.exec() == QMessageBox::Cancel)
1580                            bRestart = false;
1581                    else
1582                    if (cbox.isChecked())
1583                            m_pOptions->bConfirmRestart = false;
1584            #endif
1585            }
1586    
1587            // Are we still for it?
1588            if (bRestart && closeSession(true)) {
1589                    // Stop server, it will force the client too.
1590                    stopServer();
1591                    // Reschedule a restart...
1592                    startSchedule(m_pOptions->iStartDelay);
1593            }
1594  }  }
1595    
1596    
1597  // Exit application program.  // Exit application program.
1598  void MainForm::fileExit (void)  void MainForm::fileExit (void)
1599  {  {
1600      // Go for close the whole thing.          // Go for close the whole thing.
1601      close();          close();
1602  }  }
1603    
1604    
1605  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
1606  // qsamplerMainForm -- Edit Action slots.  // QSampler::MainForm -- Edit Action slots.
1607    
1608  // Add a new sampler channel.  // Add a new sampler channel.
1609  void MainForm::editAddChannel (void)  void MainForm::editAddChannel (void)
1610  {  {
1611      if (m_pClient == NULL)          ++m_iDirtySetup;
1612          return;          addChannelStrip();
1613            --m_iDirtySetup;
1614    }
1615    
1616      // Just create the channel instance...  void MainForm::addChannelStrip (void)
1617      qsamplerChannel *pChannel = new qsamplerChannel();  {
1618      if (pChannel == NULL)          if (m_pClient == NULL)
1619          return;                  return;
1620    
1621      // Before we show it up, may be we'll          // Just create the channel instance...
1622      // better ask for some initial values?          Channel *pChannel = new Channel();
1623      if (!pChannel->channelSetup(this)) {          if (pChannel == NULL)
1624          delete pChannel;                  return;
1625          return;  
1626      }          // Before we show it up, may be we'll
1627            // better ask for some initial values?
1628      // And give it to the strip (will own the channel instance, if successful).          if (!pChannel->channelSetup(this)) {
1629      if (!createChannelStrip(pChannel)) {                  delete pChannel;
1630          delete pChannel;                  return;
1631          return;          }
1632      }  
1633            // And give it to the strip...
1634      // Make that an overall update.          // (will own the channel instance, if successful).
1635      m_iDirtyCount++;          if (!createChannelStrip(pChannel)) {
1636      stabilizeForm();                  delete pChannel;
1637                    return;
1638            }
1639    
1640            // Do we auto-arrange?
1641            channelsArrangeAuto();
1642    
1643            // Make that an overall update.
1644            m_iDirtyCount++;
1645            stabilizeForm();
1646  }  }
1647    
1648    
1649  // Remove current sampler channel.  // Remove current sampler channel.
1650  void MainForm::editRemoveChannel (void)  void MainForm::editRemoveChannel (void)
1651  {  {
1652      if (m_pClient == NULL)          ++m_iDirtySetup;
1653          return;          removeChannelStrip();
1654            --m_iDirtySetup;
1655    }
1656    
1657      ChannelStrip* pChannelStrip = activeChannelStrip();  void MainForm::removeChannelStrip (void)
1658      if (pChannelStrip == NULL)  {
1659          return;          if (m_pClient == NULL)
1660                    return;
1661      qsamplerChannel *pChannel = pChannelStrip->channel();  
1662      if (pChannel == NULL)          ChannelStrip *pChannelStrip = activeChannelStrip();
1663          return;          if (pChannelStrip == NULL)
1664                    return;
1665      // Prompt user if he/she's sure about this...  
1666      if (m_pOptions && m_pOptions->bConfirmRemove) {          Channel *pChannel = pChannelStrip->channel();
1667          if (QMessageBox::warning(this,          if (pChannel == NULL)
1668                          QSAMPLER_TITLE ": " + tr("Warning"),                  return;
1669              tr("About to remove channel:\n\n"  
1670                 "%1\n\n"          // Prompt user if he/she's sure about this...
1671                 "Are you sure?")          if (m_pOptions && m_pOptions->bConfirmRemove) {
1672                 .arg(pChannelStrip->caption()),                  const QString& sTitle = QSAMPLER_TITLE ": " + tr("Warning");
1673              tr("OK"), tr("Cancel")) > 0)                  const QString& sText = tr(
1674              return;                          "About to remove channel:\n\n"
1675      }                          "%1\n\n"
1676                            "Are you sure?")
1677      // Remove the existing sampler channel.                          .arg(pChannelStrip->windowTitle());
1678      if (!pChannel->removeChannel())          #if 0
1679          return;                  if (QMessageBox::warning(this, sTitle, sText,
1680                            QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
1681      // Just delete the channel strip.                          return;
1682      delete pChannelStrip;          #else
1683                    QMessageBox mbox(this);
1684      // Do we auto-arrange?                  mbox.setIcon(QMessageBox::Warning);
1685      if (m_pOptions && m_pOptions->bAutoArrange)                  mbox.setWindowTitle(sTitle);
1686          channelsArrange();                  mbox.setText(sText);
1687                    mbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
1688      // We'll be dirty, for sure...                  QCheckBox cbox(tr("Don't ask this again"));
1689      m_iDirtyCount++;                  cbox.setChecked(false);
1690      stabilizeForm();                  cbox.blockSignals(true);
1691                    mbox.addButton(&cbox, QMessageBox::ActionRole);
1692                    if (mbox.exec() == QMessageBox::Cancel)
1693                            return;
1694                    if (cbox.isChecked())
1695                            m_pOptions->bConfirmRemove = false;
1696            #endif
1697            }
1698    
1699            // Remove the existing sampler channel.
1700            if (!pChannel->removeChannel())
1701                    return;
1702    
1703            // Just delete the channel strip.
1704            destroyChannelStrip(pChannelStrip);
1705    
1706            // We'll be dirty, for sure...
1707            m_iDirtyCount++;
1708            stabilizeForm();
1709  }  }
1710    
1711    
1712  // Setup current sampler channel.  // Setup current sampler channel.
1713  void MainForm::editSetupChannel (void)  void MainForm::editSetupChannel (void)
1714  {  {
1715      if (m_pClient == NULL)          if (m_pClient == NULL)
1716          return;                  return;
1717    
1718      ChannelStrip* pChannelStrip = activeChannelStrip();          ChannelStrip *pChannelStrip = activeChannelStrip();
1719      if (pChannelStrip == NULL)          if (pChannelStrip == NULL)
1720          return;                  return;
1721    
1722      // Just invoque the channel strip procedure.          // Just invoque the channel strip procedure.
1723      pChannelStrip->channelSetup();          pChannelStrip->channelSetup();
1724  }  }
1725    
1726    
1727  // Edit current sampler channel.  // Edit current sampler channel.
1728  void MainForm::editEditChannel (void)  void MainForm::editEditChannel (void)
1729  {  {
1730      if (m_pClient == NULL)          if (m_pClient == NULL)
1731          return;                  return;
1732    
1733      ChannelStrip* pChannelStrip = activeChannelStrip();          ChannelStrip *pChannelStrip = activeChannelStrip();
1734      if (pChannelStrip == NULL)          if (pChannelStrip == NULL)
1735          return;                  return;
1736    
1737      // Just invoque the channel strip procedure.          // Just invoque the channel strip procedure.
1738      pChannelStrip->channelEdit();          pChannelStrip->channelEdit();
1739  }  }
1740    
1741    
1742  // Reset current sampler channel.  // Reset current sampler channel.
1743  void MainForm::editResetChannel (void)  void MainForm::editResetChannel (void)
1744  {  {
1745      if (m_pClient == NULL)          if (m_pClient == NULL)
1746          return;                  return;
1747    
1748      ChannelStrip* pChannelStrip = activeChannelStrip();          ChannelStrip *pChannelStrip = activeChannelStrip();
1749      if (pChannelStrip == NULL)          if (pChannelStrip == NULL)
1750          return;                  return;
1751    
1752      // Just invoque the channel strip procedure.          // Just invoque the channel strip procedure.
1753      pChannelStrip->channelReset();          pChannelStrip->channelReset();
1754  }  }
1755    
1756    
# Line 1409  void MainForm::editResetAllChannels (voi Line 1763  void MainForm::editResetAllChannels (voi
1763          // Invoque the channel strip procedure,          // Invoque the channel strip procedure,
1764          // for all channels out there...          // for all channels out there...
1765          m_pWorkspace->setUpdatesEnabled(false);          m_pWorkspace->setUpdatesEnabled(false);
1766          QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
1767          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {                  = m_pWorkspace->subWindowList();
1768                  ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);          const int iStripCount = wlist.count();
1769            for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
1770                    ChannelStrip *pChannelStrip = NULL;
1771                    QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
1772                    if (pMdiSubWindow)
1773                            pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
1774                  if (pChannelStrip)                  if (pChannelStrip)
1775                          pChannelStrip->channelReset();                          pChannelStrip->channelReset();
1776          }          }
# Line 1420  void MainForm::editResetAllChannels (voi Line 1779  void MainForm::editResetAllChannels (voi
1779    
1780    
1781  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
1782  // qsamplerMainForm -- View Action slots.  // QSampler::MainForm -- View Action slots.
1783    
1784  // Show/hide the main program window menubar.  // Show/hide the main program window menubar.
1785  void MainForm::viewMenubar ( bool bOn )  void MainForm::viewMenubar ( bool bOn )
1786  {  {
1787      if (bOn)          if (bOn)
1788          ui.MenuBar->show();                  m_ui.MenuBar->show();
1789      else          else
1790          ui.MenuBar->hide();                  m_ui.MenuBar->hide();
1791  }  }
1792    
1793    
1794  // Show/hide the main program window toolbar.  // Show/hide the main program window toolbar.
1795  void MainForm::viewToolbar ( bool bOn )  void MainForm::viewToolbar ( bool bOn )
1796  {  {
1797      if (bOn) {          if (bOn) {
1798          ui.fileToolbar->show();                  m_ui.fileToolbar->show();
1799          ui.editToolbar->show();                  m_ui.editToolbar->show();
1800          ui.channelsToolbar->show();                  m_ui.channelsToolbar->show();
1801      } else {          } else {
1802          ui.fileToolbar->hide();                  m_ui.fileToolbar->hide();
1803          ui.editToolbar->hide();                  m_ui.editToolbar->hide();
1804          ui.channelsToolbar->hide();                  m_ui.channelsToolbar->hide();
1805      }          }
1806  }  }
1807    
1808    
1809  // Show/hide the main program window statusbar.  // Show/hide the main program window statusbar.
1810  void MainForm::viewStatusbar ( bool bOn )  void MainForm::viewStatusbar ( bool bOn )
1811  {  {
1812      if (bOn)          if (bOn)
1813          statusBar()->show();                  statusBar()->show();
1814      else          else
1815          statusBar()->hide();                  statusBar()->hide();
1816  }  }
1817    
1818    
1819  // Show/hide the messages window logger.  // Show/hide the messages window logger.
1820  void MainForm::viewMessages ( bool bOn )  void MainForm::viewMessages ( bool bOn )
1821  {  {
1822      if (bOn)          if (bOn)
1823          m_pMessages->show();                  m_pMessages->show();
1824      else          else
1825          m_pMessages->hide();                  m_pMessages->hide();
1826  }  }
1827    
1828    
# Line 1480  void MainForm::viewInstruments (void) Line 1839  void MainForm::viewInstruments (void)
1839                  } else {                  } else {
1840                          m_pInstrumentListForm->show();                          m_pInstrumentListForm->show();
1841                          m_pInstrumentListForm->raise();                          m_pInstrumentListForm->raise();
1842                          m_pInstrumentListForm->setActiveWindow();                          m_pInstrumentListForm->activateWindow();
1843                  }                  }
1844          }          }
1845  }  }
# Line 1499  void MainForm::viewDevices (void) Line 1858  void MainForm::viewDevices (void)
1858                  } else {                  } else {
1859                          m_pDeviceForm->show();                          m_pDeviceForm->show();
1860                          m_pDeviceForm->raise();                          m_pDeviceForm->raise();
1861                          m_pDeviceForm->setActiveWindow();                          m_pDeviceForm->activateWindow();
1862                  }                  }
1863          }          }
1864  }  }
# Line 1508  void MainForm::viewDevices (void) Line 1867  void MainForm::viewDevices (void)
1867  // Show options dialog.  // Show options dialog.
1868  void MainForm::viewOptions (void)  void MainForm::viewOptions (void)
1869  {  {
1870      if (m_pOptions == NULL)          if (m_pOptions == NULL)
1871          return;                  return;
1872    
1873      OptionsForm* pOptionsForm = new OptionsForm(this);          OptionsForm* pOptionsForm = new OptionsForm(this);
1874      if (pOptionsForm) {          if (pOptionsForm) {
1875          // Check out some initial nullities(tm)...                  // Check out some initial nullities(tm)...
1876          ChannelStrip* pChannelStrip = activeChannelStrip();                  ChannelStrip *pChannelStrip = activeChannelStrip();
1877          if (m_pOptions->sDisplayFont.isEmpty() && pChannelStrip)                  if (m_pOptions->sDisplayFont.isEmpty() && pChannelStrip)
1878              m_pOptions->sDisplayFont = pChannelStrip->displayFont().toString();                          m_pOptions->sDisplayFont = pChannelStrip->displayFont().toString();
1879          if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages)                  if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages)
1880              m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();                          m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();
1881          // To track down deferred or immediate changes.                  // To track down deferred or immediate changes.
1882          QString sOldServerHost      = m_pOptions->sServerHost;                  const QString sOldServerHost      = m_pOptions->sServerHost;
1883          int     iOldServerPort      = m_pOptions->iServerPort;                  const int     iOldServerPort      = m_pOptions->iServerPort;
1884          int     iOldServerTimeout   = m_pOptions->iServerTimeout;                  const int     iOldServerTimeout   = m_pOptions->iServerTimeout;
1885          bool    bOldServerStart     = m_pOptions->bServerStart;                  const bool    bOldServerStart     = m_pOptions->bServerStart;
1886          QString sOldServerCmdLine   = m_pOptions->sServerCmdLine;                  const QString sOldServerCmdLine   = m_pOptions->sServerCmdLine;
1887          QString sOldDisplayFont     = m_pOptions->sDisplayFont;                  const bool    bOldMessagesLog     = m_pOptions->bMessagesLog;
1888          bool    bOldDisplayEffect   = m_pOptions->bDisplayEffect;                  const QString sOldMessagesLogPath = m_pOptions->sMessagesLogPath;
1889          int     iOldMaxVolume       = m_pOptions->iMaxVolume;                  const QString sOldDisplayFont     = m_pOptions->sDisplayFont;
1890          QString sOldMessagesFont    = m_pOptions->sMessagesFont;                  const bool    bOldDisplayEffect   = m_pOptions->bDisplayEffect;
1891          bool    bOldKeepOnTop       = m_pOptions->bKeepOnTop;                  const int     iOldMaxVolume       = m_pOptions->iMaxVolume;
1892          bool    bOldStdoutCapture   = m_pOptions->bStdoutCapture;                  const QString sOldMessagesFont    = m_pOptions->sMessagesFont;
1893          int     bOldMessagesLimit   = m_pOptions->bMessagesLimit;                  const bool    bOldKeepOnTop       = m_pOptions->bKeepOnTop;
1894          int     iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines;                  const bool    bOldStdoutCapture   = m_pOptions->bStdoutCapture;
1895          bool    bOldCompletePath    = m_pOptions->bCompletePath;                  const int     bOldMessagesLimit   = m_pOptions->bMessagesLimit;
1896          bool    bOldInstrumentNames = m_pOptions->bInstrumentNames;                  const int     iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines;
1897          int     iOldMaxRecentFiles  = m_pOptions->iMaxRecentFiles;                  const bool    bOldCompletePath    = m_pOptions->bCompletePath;
1898          // Load the current setup settings.                  const bool    bOldInstrumentNames = m_pOptions->bInstrumentNames;
1899          pOptionsForm->setup(m_pOptions);                  const int     iOldMaxRecentFiles  = m_pOptions->iMaxRecentFiles;
1900          // Show the setup dialog...                  const int     iOldBaseFontSize    = m_pOptions->iBaseFontSize;
1901          if (pOptionsForm->exec()) {                  // Load the current setup settings.
1902              // Warn if something will be only effective on next run.                  pOptionsForm->setup(m_pOptions);
1903              if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) ||                  // Show the setup dialog...
1904                  (!bOldStdoutCapture &&  m_pOptions->bStdoutCapture) ||                  if (pOptionsForm->exec()) {
1905                  ( bOldKeepOnTop     && !m_pOptions->bKeepOnTop)     ||                          // Warn if something will be only effective on next run.
1906                  (!bOldKeepOnTop     &&  m_pOptions->bKeepOnTop)) {                          if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) ||
1907                  QMessageBox::information(this,                                  (!bOldStdoutCapture &&  m_pOptions->bStdoutCapture) ||
1908                                    ( bOldKeepOnTop     && !m_pOptions->bKeepOnTop)     ||
1909                                    (!bOldKeepOnTop     &&  m_pOptions->bKeepOnTop)     ||
1910                                    (iOldBaseFontSize   !=  m_pOptions->iBaseFontSize)) {
1911                                    QMessageBox::information(this,
1912                                          QSAMPLER_TITLE ": " + tr("Information"),                                          QSAMPLER_TITLE ": " + tr("Information"),
1913                      tr("Some settings may be only effective\n"                                          tr("Some settings may be only effective\n"
1914                         "next time you start this program."), tr("OK"));                                          "next time you start this program."));
1915                  updateMessagesCapture();                                  updateMessagesCapture();
1916              }                          }
1917              // Check wheather something immediate has changed.                          // Check wheather something immediate has changed.
1918              if (( bOldCompletePath && !m_pOptions->bCompletePath) ||                          if (( bOldMessagesLog && !m_pOptions->bMessagesLog) ||
1919                  (!bOldCompletePath &&  m_pOptions->bCompletePath) ||                                  (!bOldMessagesLog &&  m_pOptions->bMessagesLog) ||
1920                  (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles))                                  (sOldMessagesLogPath != m_pOptions->sMessagesLogPath))
1921                  updateRecentFilesMenu();                                  m_pMessages->setLogging(
1922              if (( bOldInstrumentNames && !m_pOptions->bInstrumentNames) ||                                          m_pOptions->bMessagesLog, m_pOptions->sMessagesLogPath);
1923                  (!bOldInstrumentNames &&  m_pOptions->bInstrumentNames))                          if (( bOldCompletePath && !m_pOptions->bCompletePath) ||
1924                  updateInstrumentNames();                                  (!bOldCompletePath &&  m_pOptions->bCompletePath) ||
1925              if (( bOldDisplayEffect && !m_pOptions->bDisplayEffect) ||                                  (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles))
1926                  (!bOldDisplayEffect &&  m_pOptions->bDisplayEffect))                                  updateRecentFilesMenu();
1927                  updateDisplayEffect();                          if (( bOldInstrumentNames && !m_pOptions->bInstrumentNames) ||
1928              if (sOldDisplayFont != m_pOptions->sDisplayFont)                                  (!bOldInstrumentNames &&  m_pOptions->bInstrumentNames))
1929                  updateDisplayFont();                                  updateInstrumentNames();
1930              if (iOldMaxVolume != m_pOptions->iMaxVolume)                          if (( bOldDisplayEffect && !m_pOptions->bDisplayEffect) ||
1931                  updateMaxVolume();                                  (!bOldDisplayEffect &&  m_pOptions->bDisplayEffect))
1932              if (sOldMessagesFont != m_pOptions->sMessagesFont)                                  updateDisplayEffect();
1933                  updateMessagesFont();                          if (sOldDisplayFont != m_pOptions->sDisplayFont)
1934              if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) ||                                  updateDisplayFont();
1935                  (!bOldMessagesLimit &&  m_pOptions->bMessagesLimit) ||                          if (iOldMaxVolume != m_pOptions->iMaxVolume)
1936                  (iOldMessagesLimitLines !=  m_pOptions->iMessagesLimitLines))                                  updateMaxVolume();
1937                  updateMessagesLimit();                          if (sOldMessagesFont != m_pOptions->sMessagesFont)
1938              // And now the main thing, whether we'll do client/server recycling?                                  updateMessagesFont();
1939              if ((sOldServerHost != m_pOptions->sServerHost) ||                          if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) ||
1940                  (iOldServerPort != m_pOptions->iServerPort) ||                                  (!bOldMessagesLimit &&  m_pOptions->bMessagesLimit) ||
1941                  (iOldServerTimeout != m_pOptions->iServerTimeout) ||                                  (iOldMessagesLimitLines !=  m_pOptions->iMessagesLimitLines))
1942                  ( bOldServerStart && !m_pOptions->bServerStart) ||                                  updateMessagesLimit();
1943                  (!bOldServerStart &&  m_pOptions->bServerStart) ||                          // And now the main thing, whether we'll do client/server recycling?
1944                  (sOldServerCmdLine != m_pOptions->sServerCmdLine && m_pOptions->bServerStart))                          if ((sOldServerHost != m_pOptions->sServerHost) ||
1945                  fileRestart();                                  (iOldServerPort != m_pOptions->iServerPort) ||
1946          }                                  (iOldServerTimeout != m_pOptions->iServerTimeout) ||
1947          // Done.                                  ( bOldServerStart && !m_pOptions->bServerStart) ||
1948          delete pOptionsForm;                                  (!bOldServerStart &&  m_pOptions->bServerStart) ||
1949      }                                  (sOldServerCmdLine != m_pOptions->sServerCmdLine
1950                                    && m_pOptions->bServerStart))
1951                                    fileRestart();
1952                    }
1953                    // Done.
1954                    delete pOptionsForm;
1955            }
1956    
1957      // This makes it.          // This makes it.
1958      stabilizeForm();          stabilizeForm();
1959  }  }
1960    
1961    
1962  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
1963  // qsamplerMainForm -- Channels action slots.  // QSampler::MainForm -- Channels action slots.
1964    
1965  // Arrange channel strips.  // Arrange channel strips.
1966  void MainForm::channelsArrange (void)  void MainForm::channelsArrange (void)
1967  {  {
1968      // Full width vertical tiling          // Full width vertical tiling
1969      QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
1970      if (wlist.isEmpty())                  = m_pWorkspace->subWindowList();
1971          return;          if (wlist.isEmpty())
1972                    return;
1973      m_pWorkspace->setUpdatesEnabled(false);  
1974      int y = 0;          m_pWorkspace->setUpdatesEnabled(false);
1975      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          int y = 0;
1976          ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);          const int iStripCount = wlist.count();
1977      /*  if (pChannelStrip->testWState(WState_Maximized | WState_Minimized)) {          for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
1978              // Prevent flicker...                  QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
1979              pChannelStrip->hide();                  if (pMdiSubWindow) {
1980              pChannelStrip->showNormal();                          pMdiSubWindow->adjustSize();
1981          }   */                          int iWidth = m_pWorkspace->width();
1982          pChannelStrip->adjustSize();                          if (iWidth < pMdiSubWindow->width())
1983          int iWidth  = m_pWorkspace->width();                                  iWidth = pMdiSubWindow->width();
1984          if (iWidth < pChannelStrip->width())                          const int iHeight = pMdiSubWindow->frameGeometry().height();
1985              iWidth = pChannelStrip->width();                          pMdiSubWindow->setGeometry(0, y, iWidth, iHeight);
1986      //  int iHeight = pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();                          y += iHeight;
1987          int iHeight = pChannelStrip->parentWidget()->frameGeometry().height();                  }
1988          pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight);          }
1989          y += iHeight;          m_pWorkspace->setUpdatesEnabled(true);
     }  
     m_pWorkspace->setUpdatesEnabled(true);  
1990    
1991      stabilizeForm();          stabilizeForm();
1992  }  }
1993    
1994    
1995  // Auto-arrange channel strips.  // Auto-arrange channel strips.
1996  void MainForm::channelsAutoArrange ( bool bOn )  void MainForm::channelsAutoArrange ( bool bOn )
1997  {  {
1998      if (m_pOptions == NULL)          if (m_pOptions == NULL)
1999          return;                  return;
2000    
2001            // Toggle the auto-arrange flag.
2002            m_pOptions->bAutoArrange = bOn;
2003    
2004            // If on, update whole workspace...
2005            channelsArrangeAuto();
2006    }
2007    
     // Toggle the auto-arrange flag.  
     m_pOptions->bAutoArrange = bOn;  
2008    
2009      // If on, update whole workspace...  void MainForm::channelsArrangeAuto (void)
2010      if (m_pOptions->bAutoArrange)  {
2011          channelsArrange();          if (m_pOptions && m_pOptions->bAutoArrange)
2012                    channelsArrange();
2013  }  }
2014    
2015    
2016  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2017  // qsamplerMainForm -- Help Action slots.  // QSampler::MainForm -- Help Action slots.
2018    
2019  // Show information about the Qt toolkit.  // Show information about the Qt toolkit.
2020  void MainForm::helpAboutQt (void)  void MainForm::helpAboutQt (void)
2021  {  {
2022      QMessageBox::aboutQt(this);          QMessageBox::aboutQt(this);
2023  }  }
2024    
2025    
2026  // Show information about application program.  // Show information about application program.
2027  void MainForm::helpAbout (void)  void MainForm::helpAbout (void)
2028  {  {
2029      // Stuff the about box text...          QStringList list;
     QString sText = "<p>\n";  
     sText += "<b>" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "</b><br />\n";  
     sText += "<br />\n";  
     sText += tr("Version") + ": <b>" QSAMPLER_VERSION "</b><br />\n";  
     sText += "<small>" + tr("Build") + ": " __DATE__ " " __TIME__ "</small><br />\n";  
2030  #ifdef CONFIG_DEBUG  #ifdef CONFIG_DEBUG
2031      sText += "<small><font color=\"red\">";          list << tr("Debugging option enabled.");
     sText += tr("Debugging option enabled.");  
     sText += "</font></small><br />";  
2032  #endif  #endif
2033  #ifndef CONFIG_LIBGIG  #ifndef CONFIG_LIBGIG
2034      sText += "<small><font color=\"red\">";          list << tr("GIG (libgig) file support disabled.");
     sText += tr("GIG (libgig) file support disabled.");  
     sText += "</font></small><br />";  
2035  #endif  #endif
2036  #ifndef CONFIG_INSTRUMENT_NAME  #ifndef CONFIG_INSTRUMENT_NAME
2037      sText += "<small><font color=\"red\">";          list << tr("LSCP (liblscp) instrument_name support disabled.");
     sText += tr("LSCP (liblscp) instrument_name support disabled.");  
     sText += "</font></small><br />";  
2038  #endif  #endif
2039  #ifndef CONFIG_MUTE_SOLO  #ifndef CONFIG_MUTE_SOLO
2040      sText += "<small><font color=\"red\">";          list << tr("Sampler channel Mute/Solo support disabled.");
     sText += tr("Sampler channel Mute/Solo support disabled.");  
     sText += "</font></small><br />";  
2041  #endif  #endif
2042  #ifndef CONFIG_AUDIO_ROUTING  #ifndef CONFIG_AUDIO_ROUTING
2043      sText += "<small><font color=\"red\">";          list << tr("LSCP (liblscp) audio_routing support disabled.");
     sText += tr("LSCP (liblscp) audio_routing support disabled.");  
     sText += "</font></small><br />";  
2044  #endif  #endif
2045  #ifndef CONFIG_FXSEND  #ifndef CONFIG_FXSEND
2046      sText += "<small><font color=\"red\">";          list << tr("Sampler channel Effect Sends support disabled.");
     sText += tr("Sampler channel Effect Sends support disabled.");  
     sText += "</font></small><br />";  
2047  #endif  #endif
2048  #ifndef CONFIG_VOLUME  #ifndef CONFIG_VOLUME
2049      sText += "<small><font color=\"red\">";          list << tr("Global volume support disabled.");
     sText += tr("Global volume support disabled.");  
     sText += "</font></small><br />";  
2050  #endif  #endif
2051  #ifndef CONFIG_MIDI_INSTRUMENT  #ifndef CONFIG_MIDI_INSTRUMENT
2052      sText += "<small><font color=\"red\">";          list << tr("MIDI instrument mapping support disabled.");
     sText += tr("MIDI instrument mapping support disabled.");  
     sText += "</font></small><br />";  
2053  #endif  #endif
2054  #ifndef CONFIG_EDIT_INSTRUMENT  #ifndef CONFIG_EDIT_INSTRUMENT
2055      sText += "<small><font color=\"red\">";          list << tr("Instrument editing support disabled.");
2056      sText += tr("Instrument editing support disabled.");  #endif
2057      sText += "</font></small><br />";  #ifndef CONFIG_EVENT_CHANNEL_MIDI
2058  #endif          list << tr("Channel MIDI event support disabled.");
2059      sText += "<br />\n";  #endif
2060      sText += tr("Using") + ": ";  #ifndef CONFIG_EVENT_DEVICE_MIDI
2061      sText += ::lscp_client_package();          list << tr("Device MIDI event support disabled.");
2062      sText += " ";  #endif
2063      sText += ::lscp_client_version();  #ifndef CONFIG_MAX_VOICES
2064            list << tr("Runtime max. voices / disk streams support disabled.");
2065    #endif
2066    
2067            // Stuff the about box text...
2068            QString sText = "<p>\n";
2069            sText += "<b>" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "</b><br />\n";
2070            sText += "<br />\n";
2071            sText += tr("Version") + ": <b>" CONFIG_BUILD_VERSION "</b><br />\n";
2072    //      sText += "<small>" + tr("Build") + ": " CONFIG_BUILD_DATE "</small><br />\n";
2073            if (!list.isEmpty()) {
2074                    sText += "<small><font color=\"red\">";
2075                    sText += list.join("<br />\n");
2076                    sText += "</font></small>";
2077            }
2078            sText += "<br />\n";
2079            sText += tr("Using") + ": ";
2080            sText += ::lscp_client_package();
2081            sText += " ";
2082            sText += ::lscp_client_version();
2083  #ifdef CONFIG_LIBGIG  #ifdef CONFIG_LIBGIG
2084      sText += ", ";          sText += ", ";
2085      sText += gig::libraryName().c_str();          sText += gig::libraryName().c_str();
2086      sText += " ";          sText += " ";
2087      sText += gig::libraryVersion().c_str();          sText += gig::libraryVersion().c_str();
2088  #endif  #endif
2089      sText += "<br />\n";          sText += "<br />\n";
2090      sText += "<br />\n";          sText += "<br />\n";
2091      sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";          sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";
2092      sText += "<br />\n";          sText += "<br />\n";
2093      sText += "<small>";          sText += "<small>";
2094      sText += QSAMPLER_COPYRIGHT "<br />\n";          sText += QSAMPLER_COPYRIGHT "<br />\n";
2095      sText += QSAMPLER_COPYRIGHT2 "<br />\n";          sText += QSAMPLER_COPYRIGHT2 "<br />\n";
2096      sText += "<br />\n";          sText += "<br />\n";
2097      sText += tr("This program is free software; you can redistribute it and/or modify it") + "<br />\n";          sText += tr("This program is free software; you can redistribute it and/or modify it") + "<br />\n";
2098      sText += tr("under the terms of the GNU General Public License version 2 or later.");          sText += tr("under the terms of the GNU General Public License version 2 or later.");
2099      sText += "</small>";          sText += "</small>";
2100      sText += "</p>\n";          sText += "</p>\n";
2101    
2102      QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText);          QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText);
2103  }  }
2104    
2105    
2106  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2107  // qsamplerMainForm -- Main window stabilization.  // QSampler::MainForm -- Main window stabilization.
2108    
2109  void MainForm::stabilizeForm (void)  void MainForm::stabilizeForm (void)
2110  {  {
2111      // Update the main application caption...          // Update the main application caption...
2112      QString sSessionName = sessionName(m_sFilename);          QString sSessionName = sessionName(m_sFilename);
2113      if (m_iDirtyCount > 0)          if (m_iDirtyCount > 0)
2114          sSessionName += " *";                  sSessionName += " *";
2115      setCaption(tr(QSAMPLER_TITLE " - [%1]").arg(sSessionName));          setWindowTitle(tr(QSAMPLER_TITLE " - [%1]").arg(sSessionName));
2116    
2117      // Update the main menu state...          // Update the main menu state...
2118      ChannelStrip* pChannelStrip = activeChannelStrip();          ChannelStrip *pChannelStrip = activeChannelStrip();
2119      bool bHasClient  = (m_pOptions != NULL && m_pClient != NULL);          const QList<QMdiSubWindow *>& wlist = m_pWorkspace->subWindowList();
2120      bool bHasChannel = (bHasClient && pChannelStrip != NULL);          const bool bHasClient = (m_pOptions != NULL && m_pClient != NULL);
2121      ui.fileNewAction->setEnabled(bHasClient);          const bool bHasChannel = (bHasClient && pChannelStrip != NULL);
2122      ui.fileOpenAction->setEnabled(bHasClient);          const bool bHasChannels = (bHasClient && wlist.count() > 0);
2123      ui.fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);          m_ui.fileNewAction->setEnabled(bHasClient);
2124      ui.fileSaveAsAction->setEnabled(bHasClient);          m_ui.fileOpenAction->setEnabled(bHasClient);
2125      ui.fileResetAction->setEnabled(bHasClient);          m_ui.fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);
2126      ui.fileRestartAction->setEnabled(bHasClient || m_pServer == NULL);          m_ui.fileSaveAsAction->setEnabled(bHasClient);
2127      ui.editAddChannelAction->setEnabled(bHasClient);          m_ui.fileResetAction->setEnabled(bHasClient);
2128      ui.editRemoveChannelAction->setEnabled(bHasChannel);          m_ui.fileRestartAction->setEnabled(bHasClient || m_pServer == NULL);
2129      ui.editSetupChannelAction->setEnabled(bHasChannel);          m_ui.editAddChannelAction->setEnabled(bHasClient);
2130            m_ui.editRemoveChannelAction->setEnabled(bHasChannel);
2131            m_ui.editSetupChannelAction->setEnabled(bHasChannel);
2132  #ifdef CONFIG_EDIT_INSTRUMENT  #ifdef CONFIG_EDIT_INSTRUMENT
2133      ui.editEditChannelAction->setEnabled(bHasChannel);          m_ui.editEditChannelAction->setEnabled(bHasChannel);
2134  #else  #else
2135      ui.editEditChannelAction->setEnabled(false);          m_ui.editEditChannelAction->setEnabled(false);
2136  #endif  #endif
2137      ui.editResetChannelAction->setEnabled(bHasChannel);          m_ui.editResetChannelAction->setEnabled(bHasChannel);
2138      ui.editResetAllChannelsAction->setEnabled(bHasChannel);          m_ui.editResetAllChannelsAction->setEnabled(bHasChannels);
2139      ui.viewMessagesAction->setOn(m_pMessages && m_pMessages->isVisible());          m_ui.viewMessagesAction->setChecked(m_pMessages && m_pMessages->isVisible());
2140  #ifdef CONFIG_MIDI_INSTRUMENT  #ifdef CONFIG_MIDI_INSTRUMENT
2141          ui.viewInstrumentsAction->setOn(m_pInstrumentListForm          m_ui.viewInstrumentsAction->setChecked(m_pInstrumentListForm
2142                  && m_pInstrumentListForm->isVisible());                  && m_pInstrumentListForm->isVisible());
2143          ui.viewInstrumentsAction->setEnabled(bHasClient);          m_ui.viewInstrumentsAction->setEnabled(bHasClient);
2144  #else  #else
2145          ui.viewInstrumentsAction->setEnabled(false);          m_ui.viewInstrumentsAction->setEnabled(false);
2146  #endif  #endif
2147          ui.viewDevicesAction->setOn(m_pDeviceForm          m_ui.viewDevicesAction->setChecked(m_pDeviceForm
2148                  && m_pDeviceForm->isVisible());                  && m_pDeviceForm->isVisible());
2149      ui.viewDevicesAction->setEnabled(bHasClient);          m_ui.viewDevicesAction->setEnabled(bHasClient);
2150      ui.channelsArrangeAction->setEnabled(bHasChannel);          m_ui.viewMidiDeviceStatusMenu->setEnabled(
2151                    DeviceStatusForm::getInstances().size() > 0);
2152            m_ui.channelsArrangeAction->setEnabled(bHasChannels);
2153    
2154  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
2155          // Toolbar widgets are also affected...          // Toolbar widgets are also affected...
2156      m_pVolumeSlider->setEnabled(bHasClient);          m_pVolumeSlider->setEnabled(bHasClient);
2157      m_pVolumeSpinBox->setEnabled(bHasClient);          m_pVolumeSpinBox->setEnabled(bHasClient);
2158  #endif  #endif
2159    
2160      // Client/Server status...          // Client/Server status...
2161      if (bHasClient) {          if (bHasClient) {
2162          m_statusItem[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));                  m_statusItem[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));
2163          m_statusItem[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost + ":" + QString::number(m_pOptions->iServerPort));                  m_statusItem[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost
2164      } else {                          + ':' + QString::number(m_pOptions->iServerPort));
2165          m_statusItem[QSAMPLER_STATUS_CLIENT]->clear();          } else {
2166          m_statusItem[QSAMPLER_STATUS_SERVER]->clear();                  m_statusItem[QSAMPLER_STATUS_CLIENT]->clear();
2167      }                  m_statusItem[QSAMPLER_STATUS_SERVER]->clear();
2168      // Channel status...          }
2169      if (bHasChannel)          // Channel status...
2170          m_statusItem[QSAMPLER_STATUS_CHANNEL]->setText(pChannelStrip->caption());          if (bHasChannel)
2171      else                  m_statusItem[QSAMPLER_STATUS_CHANNEL]->setText(pChannelStrip->windowTitle());
2172          m_statusItem[QSAMPLER_STATUS_CHANNEL]->clear();          else
2173      // Session status...                  m_statusItem[QSAMPLER_STATUS_CHANNEL]->clear();
2174      if (m_iDirtyCount > 0)          // Session status...
2175          m_statusItem[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));          if (m_iDirtyCount > 0)
2176      else                  m_statusItem[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));
2177          m_statusItem[QSAMPLER_STATUS_SESSION]->clear();          else
2178                    m_statusItem[QSAMPLER_STATUS_SESSION]->clear();
2179    
2180      // Recent files menu.          // Recent files menu.
2181      m_pRecentFilesMenu->setEnabled(bHasClient && m_pOptions->recentFiles.count() > 0);          m_ui.fileOpenRecentMenu->setEnabled(m_pOptions->recentFiles.count() > 0);
2182  }  }
2183    
2184    
# Line 1823  void MainForm::volumeChanged ( int iVolu Line 2199  void MainForm::volumeChanged ( int iVolu
2199                  m_pVolumeSpinBox->setValue(iVolume);                  m_pVolumeSpinBox->setValue(iVolume);
2200    
2201          // Do it as commanded...          // Do it as commanded...
2202          float fVolume = 0.01f * float(iVolume);          const float fVolume = 0.01f * float(iVolume);
2203          if (::lscp_set_volume(m_pClient, fVolume) == LSCP_OK)          if (::lscp_set_volume(m_pClient, fVolume) == LSCP_OK)
2204                  appendMessages(QObject::tr("Volume: %1.").arg(fVolume));                  appendMessages(QObject::tr("Volume: %1.").arg(fVolume));
2205          else          else
# Line 1839  void MainForm::volumeChanged ( int iVolu Line 2215  void MainForm::volumeChanged ( int iVolu
2215    
2216    
2217  // Channel change receiver slot.  // Channel change receiver slot.
2218  void MainForm::channelStripChanged(ChannelStrip* pChannelStrip)  void MainForm::channelStripChanged ( ChannelStrip *pChannelStrip )
2219  {  {
2220          // Add this strip to the changed list...          // Add this strip to the changed list...
2221          if (m_changedStrips.containsRef(pChannelStrip) == 0) {          if (!m_changedStrips.contains(pChannelStrip)) {
2222                  m_changedStrips.append(pChannelStrip);                  m_changedStrips.append(pChannelStrip);
2223                  pChannelStrip->resetErrorCount();                  pChannelStrip->resetErrorCount();
2224          }          }
2225    
2226      // Just mark the dirty form.          // Just mark the dirty form.
2227      m_iDirtyCount++;          m_iDirtyCount++;
2228      // and update the form status...          // and update the form status...
2229      stabilizeForm();          stabilizeForm();
2230  }  }
2231    
2232    
# Line 1858  void MainForm::channelStripChanged(Chann Line 2234  void MainForm::channelStripChanged(Chann
2234  void MainForm::updateSession (void)  void MainForm::updateSession (void)
2235  {  {
2236  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
2237          int iVolume = ::lroundf(100.0f * ::lscp_get_volume(m_pClient));          const int iVolume = ::lroundf(100.0f * ::lscp_get_volume(m_pClient));
2238          m_iVolumeChanging++;          m_iVolumeChanging++;
2239          m_pVolumeSlider->setValue(iVolume);          m_pVolumeSlider->setValue(iVolume);
2240          m_pVolumeSpinBox->setValue(iVolume);          m_pVolumeSpinBox->setValue(iVolume);
# Line 1866  void MainForm::updateSession (void) Line 2242  void MainForm::updateSession (void)
2242  #endif  #endif
2243  #ifdef CONFIG_MIDI_INSTRUMENT  #ifdef CONFIG_MIDI_INSTRUMENT
2244          // FIXME: Make some room for default instrument maps...          // FIXME: Make some room for default instrument maps...
2245          int iMaps = ::lscp_get_midi_instrument_maps(m_pClient);          const int iMaps = ::lscp_get_midi_instrument_maps(m_pClient);
2246          if (iMaps < 0)          if (iMaps < 0)
2247                  appendMessagesClient("lscp_get_midi_instrument_maps");                  appendMessagesClient("lscp_get_midi_instrument_maps");
2248          else if (iMaps < 1) {          else if (iMaps < 1) {
2249                  ::lscp_add_midi_instrument_map(m_pClient, tr("Chromatic").latin1());                  ::lscp_add_midi_instrument_map(m_pClient,
2250                  ::lscp_add_midi_instrument_map(m_pClient, tr("Drum Kits").latin1());                          tr("Chromatic").toUtf8().constData());
2251                    ::lscp_add_midi_instrument_map(m_pClient,
2252                            tr("Drum Kits").toUtf8().constData());
2253          }          }
2254  #endif  #endif
2255    
2256            updateAllChannelStrips(false);
2257    
2258            // Do we auto-arrange?
2259            channelsArrangeAuto();
2260    
2261            // Remember to refresh devices and instruments...
2262            if (m_pInstrumentListForm)
2263                    m_pInstrumentListForm->refreshInstruments();
2264            if (m_pDeviceForm)
2265                    m_pDeviceForm->refreshDevices();
2266    }
2267    
2268    
2269    void MainForm::updateAllChannelStrips ( bool bRemoveDeadStrips )
2270    {
2271            // Skip if setting up a new channel strip...
2272            if (m_iDirtySetup > 0)
2273                    return;
2274    
2275          // Retrieve the current channel list.          // Retrieve the current channel list.
2276          int *piChannelIDs = ::lscp_list_channels(m_pClient);          int *piChannelIDs = ::lscp_list_channels(m_pClient);
2277          if (piChannelIDs == NULL) {          if (piChannelIDs == NULL) {
2278                  if (::lscp_client_get_errno(m_pClient)) {                  if (::lscp_client_get_errno(m_pClient)) {
2279                          appendMessagesClient("lscp_list_channels");                          appendMessagesClient("lscp_list_channels");
2280                          appendMessagesError(tr("Could not get current list of channels.\n\nSorry."));                          appendMessagesError(
2281                                    tr("Could not get current list of channels.\n\nSorry."));
2282                  }                  }
2283          } else {          } else {
2284                  // Try to (re)create each channel.                  // Try to (re)create each channel.
2285                  m_pWorkspace->setUpdatesEnabled(false);                  m_pWorkspace->setUpdatesEnabled(false);
2286                  for (int iChannel = 0; piChannelIDs[iChannel] >= 0; iChannel++) {                  for (int iChannel = 0; piChannelIDs[iChannel] >= 0; ++iChannel) {
2287                          // Check if theres already a channel strip for this one...                          // Check if theres already a channel strip for this one...
2288                          if (!channelStrip(piChannelIDs[iChannel]))                          if (!channelStrip(piChannelIDs[iChannel]))
2289                                  createChannelStrip(new qsamplerChannel(piChannelIDs[iChannel]));                                  createChannelStrip(new Channel(piChannelIDs[iChannel]));
2290                    }
2291                    // Do we auto-arrange?
2292                    channelsArrangeAuto();
2293                    // remove dead channel strips
2294                    if (bRemoveDeadStrips) {
2295                            const QList<QMdiSubWindow *>& wlist
2296                                    = m_pWorkspace->subWindowList();
2297                            const int iStripCount = wlist.count();
2298                            for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
2299                                    ChannelStrip *pChannelStrip = NULL;
2300                                    QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2301                                    if (pMdiSubWindow)
2302                                            pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2303                                    if (pChannelStrip) {
2304                                            bool bExists = false;
2305                                            for (int iChannel = 0; piChannelIDs[iChannel] >= 0; ++iChannel) {
2306                                                    Channel *pChannel = pChannelStrip->channel();
2307                                                    if (pChannel == NULL)
2308                                                            break;
2309                                                    if (piChannelIDs[iChannel] == pChannel->channelID()) {
2310                                                            // strip exists, don't touch it
2311                                                            bExists = true;
2312                                                            break;
2313                                                    }
2314                                            }
2315                                            if (!bExists)
2316                                                    destroyChannelStrip(pChannelStrip);
2317                                    }
2318                            }
2319                  }                  }
2320                  m_pWorkspace->setUpdatesEnabled(true);                  m_pWorkspace->setUpdatesEnabled(true);
2321          }          }
2322    
2323      // Do we auto-arrange?          stabilizeForm();
     if (m_pOptions && m_pOptions->bAutoArrange)  
         channelsArrange();  
   
         // Remember to refresh devices and instruments...  
         if (m_pInstrumentListForm)  
             m_pInstrumentListForm->refreshInstruments();  
         if (m_pDeviceForm)  
             m_pDeviceForm->refreshDevices();  
2324  }  }
2325    
2326    
2327  // Update the recent files list and menu.  // Update the recent files list and menu.
2328  void MainForm::updateRecentFiles ( const QString& sFilename )  void MainForm::updateRecentFiles ( const QString& sFilename )
2329  {  {
2330      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2331          return;                  return;
   
     // Remove from list if already there (avoid duplicates)  
     QStringList::Iterator iter = m_pOptions->recentFiles.find(sFilename);  
     if (iter != m_pOptions->recentFiles.end())  
         m_pOptions->recentFiles.remove(iter);  
     // Put it to front...  
     m_pOptions->recentFiles.push_front(sFilename);  
2332    
2333      // May update the menu.          // Remove from list if already there (avoid duplicates)
2334      updateRecentFilesMenu();          const int iIndex = m_pOptions->recentFiles.indexOf(sFilename);
2335            if (iIndex >= 0)
2336                    m_pOptions->recentFiles.removeAt(iIndex);
2337            // Put it to front...
2338            m_pOptions->recentFiles.push_front(sFilename);
2339  }  }
2340    
2341    
2342  // Update the recent files list and menu.  // Update the recent files list and menu.
2343  void MainForm::updateRecentFilesMenu (void)  void MainForm::updateRecentFilesMenu (void)
2344  {  {
2345      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2346          return;                  return;
2347    
2348      // Time to keep the list under limits.          // Time to keep the list under limits.
2349      int iRecentFiles = m_pOptions->recentFiles.count();          int iRecentFiles = m_pOptions->recentFiles.count();
2350      while (iRecentFiles > m_pOptions->iMaxRecentFiles) {          while (iRecentFiles > m_pOptions->iMaxRecentFiles) {
2351          m_pOptions->recentFiles.pop_back();                  m_pOptions->recentFiles.pop_back();
2352          iRecentFiles--;                  iRecentFiles--;
2353      }          }
2354    
2355      // rebuild the recent files menu...          // Rebuild the recent files menu...
2356      m_pRecentFilesMenu->clear();          m_ui.fileOpenRecentMenu->clear();
2357      for (int i = 0; i < iRecentFiles; i++) {          for (int i = 0; i < iRecentFiles; i++) {
2358          const QString& sFilename = m_pOptions->recentFiles[i];                  const QString& sFilename = m_pOptions->recentFiles[i];
2359          if (QFileInfo(sFilename).exists()) {                  if (QFileInfo(sFilename).exists()) {
2360              m_pRecentFilesMenu->insertItem(QString("&%1 %2")                          QAction *pAction = m_ui.fileOpenRecentMenu->addAction(
2361                  .arg(i + 1).arg(sessionName(sFilename)),                                  QString("&%1 %2").arg(i + 1).arg(sessionName(sFilename)),
2362                  this, SLOT(fileOpenRecent(int)), 0, i);                                  this, SLOT(fileOpenRecent()));
2363          }                          pAction->setData(i);
2364      }                  }
2365            }
2366  }  }
2367    
2368    
2369  // Force update of the channels instrument names mode.  // Force update of the channels instrument names mode.
2370  void MainForm::updateInstrumentNames (void)  void MainForm::updateInstrumentNames (void)
2371  {  {
2372      // Full channel list update...          // Full channel list update...
2373      QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
2374      if (wlist.isEmpty())                  = m_pWorkspace->subWindowList();
2375          return;          if (wlist.isEmpty())
2376                    return;
2377      m_pWorkspace->setUpdatesEnabled(false);  
2378      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          m_pWorkspace->setUpdatesEnabled(false);
2379          ChannelStrip *pChannelStrip = (ChannelStrip *) wlist.at(iChannel);          const int iStripCount = wlist.count();
2380          if (pChannelStrip)          for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
2381              pChannelStrip->updateInstrumentName(true);                  ChannelStrip *pChannelStrip = NULL;
2382      }                  QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2383      m_pWorkspace->setUpdatesEnabled(true);                  if (pMdiSubWindow)
2384                            pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2385                    if (pChannelStrip)
2386                            pChannelStrip->updateInstrumentName(true);
2387            }
2388            m_pWorkspace->setUpdatesEnabled(true);
2389  }  }
2390    
2391    
2392  // Force update of the channels display font.  // Force update of the channels display font.
2393  void MainForm::updateDisplayFont (void)  void MainForm::updateDisplayFont (void)
2394  {  {
2395      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2396          return;                  return;
2397    
2398            // Check if display font is legal.
2399            if (m_pOptions->sDisplayFont.isEmpty())
2400                    return;
2401    
2402            // Realize it.
2403            QFont font;
2404            if (!font.fromString(m_pOptions->sDisplayFont))
2405                    return;
2406    
2407      // Check if display font is legal.          // Full channel list update...
2408      if (m_pOptions->sDisplayFont.isEmpty())          const QList<QMdiSubWindow *>& wlist
2409          return;                  = m_pWorkspace->subWindowList();
2410      // Realize it.          if (wlist.isEmpty())
2411      QFont font;                  return;
2412      if (!font.fromString(m_pOptions->sDisplayFont))  
2413          return;          m_pWorkspace->setUpdatesEnabled(false);
2414            const int iStripCount = wlist.count();
2415      // Full channel list update...          for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
2416      QWidgetList wlist = m_pWorkspace->windowList();                  ChannelStrip *pChannelStrip = NULL;
2417      if (wlist.isEmpty())                  QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2418          return;                  if (pMdiSubWindow)
2419                            pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2420      m_pWorkspace->setUpdatesEnabled(false);                  if (pChannelStrip)
2421      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {                          pChannelStrip->setDisplayFont(font);
2422          ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);          }
2423          if (pChannelStrip)          m_pWorkspace->setUpdatesEnabled(true);
             pChannelStrip->setDisplayFont(font);  
     }  
     m_pWorkspace->setUpdatesEnabled(true);  
2424  }  }
2425    
2426    
2427  // Update channel strips background effect.  // Update channel strips background effect.
2428  void MainForm::updateDisplayEffect (void)  void MainForm::updateDisplayEffect (void)
2429  {  {
2430     QPixmap pm;          // Full channel list update...
2431      if (m_pOptions->bDisplayEffect)          const QList<QMdiSubWindow *>& wlist
2432          pm = QPixmap(":/qsampler/pixmaps/displaybg1.png");                  = m_pWorkspace->subWindowList();
2433            if (wlist.isEmpty())
2434      // Full channel list update...                  return;
2435      QWidgetList wlist = m_pWorkspace->windowList();  
2436      if (wlist.isEmpty())          m_pWorkspace->setUpdatesEnabled(false);
2437          return;          const int iStripCount = wlist.count();
2438            for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
2439      m_pWorkspace->setUpdatesEnabled(false);                  ChannelStrip *pChannelStrip = NULL;
2440      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {                  QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2441          ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);                  if (pMdiSubWindow)
2442          if (pChannelStrip)                          pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2443              pChannelStrip->setDisplayBackground(pm);                  if (pChannelStrip)
2444      }                          pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
2445      m_pWorkspace->setUpdatesEnabled(true);          }
2446            m_pWorkspace->setUpdatesEnabled(true);
2447  }  }
2448    
2449    
2450  // Force update of the channels maximum volume setting.  // Force update of the channels maximum volume setting.
2451  void MainForm::updateMaxVolume (void)  void MainForm::updateMaxVolume (void)
2452  {  {
2453      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2454          return;                  return;
2455    
2456  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
2457          m_iVolumeChanging++;          m_iVolumeChanging++;
2458          m_pVolumeSlider->setMaxValue(m_pOptions->iMaxVolume);          m_pVolumeSlider->setMaximum(m_pOptions->iMaxVolume);
2459          m_pVolumeSpinBox->setMaxValue(m_pOptions->iMaxVolume);          m_pVolumeSpinBox->setMaximum(m_pOptions->iMaxVolume);
2460          m_iVolumeChanging--;          m_iVolumeChanging--;
2461  #endif  #endif
2462    
2463      // Full channel list update...          // Full channel list update...
2464      QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
2465      if (wlist.isEmpty())                  = m_pWorkspace->subWindowList();
2466          return;          if (wlist.isEmpty())
2467                    return;
2468      m_pWorkspace->setUpdatesEnabled(false);  
2469      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          m_pWorkspace->setUpdatesEnabled(false);
2470          ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);          const int iStripCount = wlist.count();
2471          if (pChannelStrip)          for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
2472              pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);                  ChannelStrip *pChannelStrip = NULL;
2473      }                  QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2474      m_pWorkspace->setUpdatesEnabled(true);                  if (pMdiSubWindow)
2475                            pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2476                    if (pChannelStrip)
2477                            pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
2478            }
2479            m_pWorkspace->setUpdatesEnabled(true);
2480  }  }
2481    
2482    
2483  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2484  // qsamplerMainForm -- Messages window form handlers.  // QSampler::MainForm -- Messages window form handlers.
2485    
2486  // Messages output methods.  // Messages output methods.
2487  void MainForm::appendMessages( const QString& s )  void MainForm::appendMessages( const QString& s )
2488  {  {
2489      if (m_pMessages)          if (m_pMessages)
2490          m_pMessages->appendMessages(s);                  m_pMessages->appendMessages(s);
2491    
2492      statusBar()->message(s, 3000);          statusBar()->showMessage(s, 3000);
2493  }  }
2494    
2495  void MainForm::appendMessagesColor( const QString& s, const QString& c )  void MainForm::appendMessagesColor( const QString& s, const QString& c )
2496  {  {
2497      if (m_pMessages)          if (m_pMessages)
2498          m_pMessages->appendMessagesColor(s, c);                  m_pMessages->appendMessagesColor(s, c);
2499    
2500      statusBar()->message(s, 3000);          statusBar()->showMessage(s, 3000);
2501  }  }
2502    
2503  void MainForm::appendMessagesText( const QString& s )  void MainForm::appendMessagesText( const QString& s )
2504  {  {
2505      if (m_pMessages)          if (m_pMessages)
2506          m_pMessages->appendMessagesText(s);                  m_pMessages->appendMessagesText(s);
2507  }  }
2508    
2509  void MainForm::appendMessagesError( const QString& s )  void MainForm::appendMessagesError( const QString& sText )
2510  {  {
2511      if (m_pMessages)          if (m_pMessages)
2512          m_pMessages->show();                  m_pMessages->show();
2513    
2514      appendMessagesColor(s.simplifyWhiteSpace(), "#ff0000");          appendMessagesColor(sText.simplified(), "#ff0000");
2515    
2516          // Make it look responsive...:)          // Make it look responsive...:)
2517          QApplication::processEvents(QEventLoop::ExcludeUserInput);          QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2518    
2519      QMessageBox::critical(this,          if (m_pOptions && m_pOptions->bConfirmError) {
2520                  QSAMPLER_TITLE ": " + tr("Error"), s, tr("Cancel"));                  const QString& sTitle = QSAMPLER_TITLE ": " + tr("Error");
2521            #if 0
2522                    QMessageBox::critical(this, sTitle, sText, QMessageBox::Cancel);
2523            #else
2524                    QMessageBox mbox(this);
2525                    mbox.setIcon(QMessageBox::Critical);
2526                    mbox.setWindowTitle(sTitle);
2527                    mbox.setText(sText);
2528                    mbox.setStandardButtons(QMessageBox::Cancel);
2529                    QCheckBox cbox(tr("Don't show this again"));
2530                    cbox.setChecked(false);
2531                    cbox.blockSignals(true);
2532                    mbox.addButton(&cbox, QMessageBox::ActionRole);
2533                    if (mbox.exec() && cbox.isChecked())
2534                            m_pOptions->bConfirmError = false;
2535            #endif
2536            }
2537  }  }
2538    
2539    
2540  // This is a special message format, just for client results.  // This is a special message format, just for client results.
2541  void MainForm::appendMessagesClient( const QString& s )  void MainForm::appendMessagesClient( const QString& s )
2542  {  {
2543      if (m_pClient == NULL)          if (m_pClient == NULL)
2544          return;                  return;
2545    
2546      appendMessagesColor(s + QString(": %1 (errno=%2)")          appendMessagesColor(s + QString(": %1 (errno=%2)")
2547          .arg(::lscp_client_get_result(m_pClient))                  .arg(::lscp_client_get_result(m_pClient))
2548          .arg(::lscp_client_get_errno(m_pClient)), "#996666");                  .arg(::lscp_client_get_errno(m_pClient)), "#996666");
2549    
2550          // Make it look responsive...:)          // Make it look responsive...:)
2551          QApplication::processEvents(QEventLoop::ExcludeUserInput);          QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2552  }  }
2553    
2554    
2555  // Force update of the messages font.  // Force update of the messages font.
2556  void MainForm::updateMessagesFont (void)  void MainForm::updateMessagesFont (void)
2557  {  {
2558      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2559          return;                  return;
2560    
2561      if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {          if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {
2562          QFont font;                  QFont font;
2563          if (font.fromString(m_pOptions->sMessagesFont))                  if (font.fromString(m_pOptions->sMessagesFont))
2564              m_pMessages->setMessagesFont(font);                          m_pMessages->setMessagesFont(font);
2565      }          }
2566  }  }
2567    
2568    
2569  // Update messages window line limit.  // Update messages window line limit.
2570  void MainForm::updateMessagesLimit (void)  void MainForm::updateMessagesLimit (void)
2571  {  {
2572      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2573          return;                  return;
2574    
2575      if (m_pMessages) {          if (m_pMessages) {
2576          if (m_pOptions->bMessagesLimit)                  if (m_pOptions->bMessagesLimit)
2577              m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);                          m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);
2578          else                  else
2579              m_pMessages->setMessagesLimit(-1);                          m_pMessages->setMessagesLimit(-1);
2580      }          }
2581  }  }
2582    
2583    
2584  // Enablement of the messages capture feature.  // Enablement of the messages capture feature.
2585  void MainForm::updateMessagesCapture (void)  void MainForm::updateMessagesCapture (void)
2586  {  {
2587      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2588          return;                  return;
2589    
2590      if (m_pMessages)          if (m_pMessages)
2591          m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);                  m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);
2592  }  }
2593    
2594    
2595  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2596  // qsamplerMainForm -- MDI channel strip management.  // QSampler::MainForm -- MDI channel strip management.
2597    
2598  // The channel strip creation executive.  // The channel strip creation executive.
2599  ChannelStrip* MainForm::createChannelStrip(qsamplerChannel* pChannel)  ChannelStrip *MainForm::createChannelStrip ( Channel *pChannel )
2600  {  {
2601      if (m_pClient == NULL || pChannel == NULL)          if (m_pClient == NULL || pChannel == NULL)
2602          return NULL;                  return NULL;
2603    
2604      // Prepare for auto-arrange?          // Add a new channel itema...
2605      ChannelStrip* pChannelStrip = NULL;          ChannelStrip *pChannelStrip = new ChannelStrip();
2606      int y = 0;          if (pChannelStrip == NULL)
2607      if (m_pOptions && m_pOptions->bAutoArrange) {                  return NULL;
2608          QWidgetList wlist = m_pWorkspace->windowList();  
2609          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          // Set some initial channel strip options...
2610              pChannelStrip = (ChannelStrip *) wlist.at(iChannel);          if (m_pOptions) {
2611                          if (pChannelStrip) {                  // Background display effect...
2612                          //  y += pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();                  pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
2613                                  y += pChannelStrip->parentWidget()->frameGeometry().height();                  // We'll need a display font.
2614                          }                  QFont font;
2615          }                  if (!m_pOptions->sDisplayFont.isEmpty() &&
2616      }                          font.fromString(m_pOptions->sDisplayFont))
2617                            pChannelStrip->setDisplayFont(font);
2618                    // Maximum allowed volume setting.
2619                    pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
2620            }
2621    
2622            // Add it to workspace...
2623            m_pWorkspace->addSubWindow(pChannelStrip,
2624                    Qt::SubWindow | Qt::FramelessWindowHint);
2625    
2626      // Add a new channel itema...          // Actual channel strip setup...
2627      Qt::WFlags wflags = Qt::WStyle_Customize | Qt::WStyle_Tool | Qt::WStyle_Title | Qt::WStyle_NoBorder;          pChannelStrip->setup(pChannel);
     pChannelStrip = new ChannelStrip(m_pWorkspace, wflags);  
     if (pChannelStrip == NULL)  
         return NULL;  
2628    
     // Actual channel strip setup...  
     pChannelStrip->setup(pChannel);  
2629          QObject::connect(pChannelStrip,          QObject::connect(pChannelStrip,
2630                  SIGNAL(channelChanged(qsamplerChannelStrip *)),                  SIGNAL(channelChanged(ChannelStrip *)),
2631                  SLOT(channelStripChanged(qsamplerChannelStrip *)));                  SLOT(channelStripChanged(ChannelStrip *)));
2632      // Set some initial aesthetic options...  
2633      if (m_pOptions) {          // Now we show up us to the world.
2634          // Background display effect...          pChannelStrip->show();
         pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);  
         // We'll need a display font.  
         QFont font;  
         if (font.fromString(m_pOptions->sDisplayFont))  
             pChannelStrip->setDisplayFont(font);  
         // Maximum allowed volume setting.  
         pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);  
     }  
   
     // Now we show up us to the world.  
     pChannelStrip->show();  
     // Only then, we'll auto-arrange...  
     if (m_pOptions && m_pOptions->bAutoArrange) {  
         int iWidth  = m_pWorkspace->width();  
     //  int iHeight = pChannel->height() + pChannel->parentWidget()->baseSize().height();  
         int iHeight = pChannelStrip->parentWidget()->frameGeometry().height();        pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight);  
     }  
2635    
2636          // This is pretty new, so we'll watch for it closely.          // This is pretty new, so we'll watch for it closely.
2637          channelStripChanged(pChannelStrip);          channelStripChanged(pChannelStrip);
2638    
2639      // Return our successful reference...          // Return our successful reference...
2640      return pChannelStrip;          return pChannelStrip;
2641    }
2642    
2643    
2644    void MainForm::destroyChannelStrip ( ChannelStrip *pChannelStrip )
2645    {
2646            QMdiSubWindow *pMdiSubWindow
2647                    = static_cast<QMdiSubWindow *> (pChannelStrip->parentWidget());
2648            if (pMdiSubWindow == NULL)
2649                    return;
2650    
2651            // Just delete the channel strip.
2652            delete pChannelStrip;
2653            delete pMdiSubWindow;
2654    
2655            // Do we auto-arrange?
2656            channelsArrangeAuto();
2657  }  }
2658    
2659    
2660  // Retrieve the active channel strip.  // Retrieve the active channel strip.
2661  ChannelStrip* MainForm::activeChannelStrip (void)  ChannelStrip *MainForm::activeChannelStrip (void)
2662  {  {
2663      return (ChannelStrip*) m_pWorkspace->activeWindow();          QMdiSubWindow *pMdiSubWindow = m_pWorkspace->activeSubWindow();
2664            if (pMdiSubWindow)
2665                    return static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2666            else
2667                    return NULL;
2668  }  }
2669    
2670    
2671  // Retrieve a channel strip by index.  // Retrieve a channel strip by index.
2672  ChannelStrip* MainForm::channelStripAt ( int iChannel )  ChannelStrip *MainForm::channelStripAt ( int iStrip )
2673  {  {
2674      QWidgetList wlist = m_pWorkspace->windowList();          if (!m_pWorkspace) return NULL;
2675      if (wlist.isEmpty())  
2676          return NULL;          const QList<QMdiSubWindow *>& wlist
2677                    = m_pWorkspace->subWindowList();
2678            if (wlist.isEmpty())
2679                    return NULL;
2680    
2681            if (iStrip < 0 || iStrip >= wlist.count())
2682                    return NULL;
2683    
2684      return (ChannelStrip*) wlist.at(iChannel);          QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2685            if (pMdiSubWindow)
2686                    return static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2687            else
2688                    return NULL;
2689  }  }
2690    
2691    
2692  // Retrieve a channel strip by sampler channel id.  // Retrieve a channel strip by sampler channel id.
2693  ChannelStrip* MainForm::channelStrip ( int iChannelID )  ChannelStrip *MainForm::channelStrip ( int iChannelID )
2694  {  {
2695          QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
2696                    = m_pWorkspace->subWindowList();
2697          if (wlist.isEmpty())          if (wlist.isEmpty())
2698                  return NULL;                  return NULL;
2699    
2700          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          const int iStripCount = wlist.count();
2701                  ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);          for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
2702                    ChannelStrip *pChannelStrip = NULL;
2703                    QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2704                    if (pMdiSubWindow)
2705                            pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2706                  if (pChannelStrip) {                  if (pChannelStrip) {
2707                          qsamplerChannel *pChannel = pChannelStrip->channel();                          Channel *pChannel = pChannelStrip->channel();
2708                          if (pChannel && pChannel->channelID() == iChannelID)                          if (pChannel && pChannel->channelID() == iChannelID)
2709                                  return pChannelStrip;                                  return pChannelStrip;
2710                  }                  }
# Line 2247  ChannelStrip* MainForm::channelStrip ( i Line 2718  ChannelStrip* MainForm::channelStrip ( i
2718  // Construct the windows menu.  // Construct the windows menu.
2719  void MainForm::channelsMenuAboutToShow (void)  void MainForm::channelsMenuAboutToShow (void)
2720  {  {
2721      ui.channelsMenu->clear();          m_ui.channelsMenu->clear();
2722      ui.channelsArrangeAction->addTo(ui.channelsMenu);          m_ui.channelsMenu->addAction(m_ui.channelsArrangeAction);
2723      ui.channelsAutoArrangeAction->addTo(ui.channelsMenu);          m_ui.channelsMenu->addAction(m_ui.channelsAutoArrangeAction);
2724    
2725      QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
2726      if (!wlist.isEmpty()) {                  = m_pWorkspace->subWindowList();
2727          ui.channelsMenu->insertSeparator();          if (!wlist.isEmpty()) {
2728          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {                  m_ui.channelsMenu->addSeparator();
2729              ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);                  const int iStripCount = wlist.count();
2730              if (pChannelStrip) {                  for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
2731                  int iItemID = ui.channelsMenu->insertItem(pChannelStrip->caption(), this, SLOT(channelsMenuActivated(int)));                          ChannelStrip *pChannelStrip = NULL;
2732                  ui.channelsMenu->setItemParameter(iItemID, iChannel);                          QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2733                  ui.channelsMenu->setItemChecked(iItemID, activeChannelStrip() == pChannelStrip);                          if (pMdiSubWindow)
2734              }                                  pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2735          }                          if (pChannelStrip) {
2736      }                                  QAction *pAction = m_ui.channelsMenu->addAction(
2737                                            pChannelStrip->windowTitle(),
2738                                            this, SLOT(channelsMenuActivated()));
2739                                    pAction->setCheckable(true);
2740                                    pAction->setChecked(activeChannelStrip() == pChannelStrip);
2741                                    pAction->setData(iStrip);
2742                            }
2743                    }
2744            }
2745  }  }
2746    
2747    
2748  // Windows menu activation slot  // Windows menu activation slot
2749  void MainForm::channelsMenuActivated ( int iChannel )  void MainForm::channelsMenuActivated (void)
2750  {  {
2751      ChannelStrip* pChannelStrip = channelStripAt(iChannel);          // Retrive channel index from action data...
2752      if (pChannelStrip)          QAction *pAction = qobject_cast<QAction *> (sender());
2753          pChannelStrip->showNormal();          if (pAction == NULL)
2754      pChannelStrip->setFocus();                  return;
2755    
2756            ChannelStrip *pChannelStrip = channelStripAt(pAction->data().toInt());
2757            if (pChannelStrip) {
2758                    pChannelStrip->showNormal();
2759                    pChannelStrip->setFocus();
2760            }
2761  }  }
2762    
2763    
2764  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2765  // qsamplerMainForm -- Timer stuff.  // QSampler::MainForm -- Timer stuff.
2766    
2767  // Set the pseudo-timer delay schedule.  // Set the pseudo-timer delay schedule.
2768  void MainForm::startSchedule ( int iStartDelay )  void MainForm::startSchedule ( int iStartDelay )
2769  {  {
2770      m_iStartDelay  = 1 + (iStartDelay * 1000);          m_iStartDelay  = 1 + (iStartDelay * 1000);
2771      m_iTimerDelay  = 0;          m_iTimerDelay  = 0;
2772  }  }
2773    
2774  // Suspend the pseudo-timer delay schedule.  // Suspend the pseudo-timer delay schedule.
2775  void MainForm::stopSchedule (void)  void MainForm::stopSchedule (void)
2776  {  {
2777      m_iStartDelay  = 0;          m_iStartDelay  = 0;
2778      m_iTimerDelay  = 0;          m_iTimerDelay  = 0;
2779  }  }
2780    
2781  // Timer slot funtion.  // Timer slot funtion.
2782  void MainForm::timerSlot (void)  void MainForm::timerSlot (void)
2783  {  {
2784      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2785          return;                  return;
2786    
2787      // Is it the first shot on server start after a few delay?          // Is it the first shot on server start after a few delay?
2788      if (m_iTimerDelay < m_iStartDelay) {          if (m_iTimerDelay < m_iStartDelay) {
2789          m_iTimerDelay += QSAMPLER_TIMER_MSECS;                  m_iTimerDelay += QSAMPLER_TIMER_MSECS;
2790          if (m_iTimerDelay >= m_iStartDelay) {                  if (m_iTimerDelay >= m_iStartDelay) {
2791              // If we cannot start it now, maybe a lil'mo'later ;)                          // If we cannot start it now, maybe a lil'mo'later ;)
2792              if (!startClient()) {                          if (!startClient()) {
2793                  m_iStartDelay += m_iTimerDelay;                                  m_iStartDelay += m_iTimerDelay;
2794                  m_iTimerDelay  = 0;                                  m_iTimerDelay  = 0;
2795              }                          }
2796          }                  }
2797      }          }
2798    
2799          if (m_pClient) {          if (m_pClient) {
2800                  // Update the channel information for each pending strip...                  // Update the channel information for each pending strip...
2801                  if (m_changedStrips.count() > 0) {                  QListIterator<ChannelStrip *> iter(m_changedStrips);
2802                          for (ChannelStrip* pChannelStrip = m_changedStrips.first();                  while (iter.hasNext()) {
2803                                          pChannelStrip; pChannelStrip = m_changedStrips.next()) {                          ChannelStrip *pChannelStrip = iter.next();
2804                                  // If successfull, remove from pending list...                          // If successfull, remove from pending list...
2805                                  if (pChannelStrip->updateChannelInfo())                          if (pChannelStrip->updateChannelInfo()) {
2806                                          m_changedStrips.remove(pChannelStrip);                                  const int iChannelStrip = m_changedStrips.indexOf(pChannelStrip);
2807                                    if (iChannelStrip >= 0)
2808                                            m_changedStrips.removeAt(iChannelStrip);
2809                          }                          }
2810                  }                  }
2811                  // Refresh each channel usage, on each period...                  // Refresh each channel usage, on each period...
# Line 2327  void MainForm::timerSlot (void) Line 2814  void MainForm::timerSlot (void)
2814                          if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime)  {                          if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime)  {
2815                                  m_iTimerSlot = 0;                                  m_iTimerSlot = 0;
2816                                  // Update the channel stream usage for each strip...                                  // Update the channel stream usage for each strip...
2817                                  QWidgetList wlist = m_pWorkspace->windowList();                                  const QList<QMdiSubWindow *>& wlist
2818                                  for (int iChannel = 0;                                          = m_pWorkspace->subWindowList();
2819                                                  iChannel < (int) wlist.count(); iChannel++) {                                  const int iStripCount = wlist.count();
2820                                          ChannelStrip* pChannelStrip                                  for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
2821                                                  = (ChannelStrip*) wlist.at(iChannel);                                          ChannelStrip *pChannelStrip = NULL;
2822                                            QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2823                                            if (pMdiSubWindow)
2824                                                    pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2825                                          if (pChannelStrip && pChannelStrip->isVisible())                                          if (pChannelStrip && pChannelStrip->isVisible())
2826                                                  pChannelStrip->updateChannelUsage();                                                  pChannelStrip->updateChannelUsage();
2827                                  }                                  }
# Line 2339  void MainForm::timerSlot (void) Line 2829  void MainForm::timerSlot (void)
2829                  }                  }
2830          }          }
2831    
2832      // Register the next timer slot.          // Register the next timer slot.
2833      QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));          QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
2834  }  }
2835    
2836    
2837  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2838  // qsamplerMainForm -- Server stuff.  // QSampler::MainForm -- Server stuff.
2839    
2840  // Start linuxsampler server...  // Start linuxsampler server...
2841  void MainForm::startServer (void)  void MainForm::startServer (void)
2842  {  {
2843      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2844          return;                  return;
2845    
2846      // Aren't already a client, are we?          // Aren't already a client, are we?
2847      if (!m_pOptions->bServerStart || m_pClient)          if (!m_pOptions->bServerStart || m_pClient)
2848          return;                  return;
   
     // Is the server process instance still here?  
     if (m_pServer) {  
         switch (QMessageBox::warning(this,  
                         QSAMPLER_TITLE ": " + tr("Warning"),  
             tr("Could not start the LinuxSampler server.\n\n"  
                "Maybe it ss already started."),  
             tr("Stop"), tr("Kill"), tr("Cancel"))) {  
           case 0:  
             m_pServer->terminate();  
             break;  
           case 1:  
             m_pServer->kill();  
             break;  
         }  
         return;  
     }  
   
     // Reset our timer counters...  
     stopSchedule();  
   
     // OK. Let's build the startup process...  
     m_pServer = new QProcess(this);  
   
     // Setup stdout/stderr capture...  
         //      if (m_pOptions->bStdoutCapture) {  
                 //m_pServer->setProcessChannelMode(  
                 //      QProcess::StandardOutput);  
                 QObject::connect(m_pServer,  
                         SIGNAL(readyReadStandardOutput()),  
                         SLOT(readServerStdout()));  
                 QObject::connect(m_pServer,  
                         SIGNAL(readyReadStandardError()),  
                         SLOT(readServerStdout()));  
         //      }  
         // The unforgiveable signal communication...  
         QObject::connect(m_pServer,  
                 SIGNAL(finished(int,QProcess::ExitStatus)),  
                 SLOT(processServerExit()));  
2849    
2850      // Build process arguments...          // Is the server process instance still here?
2851      QStringList serverCmdLine = QStringList::split(' ', m_pOptions->sServerCmdLine);          if (m_pServer) {
2852                    if (QMessageBox::warning(this,
2853                            QSAMPLER_TITLE ": " + tr("Warning"),
2854                            tr("Could not start the LinuxSampler server.\n\n"
2855                            "Maybe it is already started."),
2856                            QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) {
2857                            m_pServer->terminate();
2858                            m_pServer->kill();
2859                    }
2860                    return;
2861            }
2862    
2863      appendMessages(tr("Server is starting..."));          // Reset our timer counters...
2864      appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");          stopSchedule();
2865    
2866            // Verify we have something to start with...
2867            if (m_pOptions->sServerCmdLine.isEmpty())
2868                    return;
2869    
2870            // OK. Let's build the startup process...
2871            m_pServer = new QProcess();
2872            m_bForceServerStop = true;
2873    
2874      const QString prog = (serverCmdLine.size() > 0) ? serverCmdLine[0] : QString();          // Setup stdout/stderr capture...
2875      const QStringList args = serverCmdLine.mid(1);          m_pServer->setProcessChannelMode(QProcess::ForwardedChannels);
2876            QObject::connect(m_pServer,
2877                    SIGNAL(readyReadStandardOutput()),
2878                    SLOT(readServerStdout()));
2879            QObject::connect(m_pServer,
2880                    SIGNAL(readyReadStandardError()),
2881                    SLOT(readServerStdout()));
2882    
2883      // Go jack, go...          // The unforgiveable signal communication...
2884      m_pServer->start(prog, args);          QObject::connect(m_pServer,
2885      if (!m_pServer->waitForStarted()) {                  SIGNAL(finished(int, QProcess::ExitStatus)),
2886          appendMessagesError(tr("Could not start server.\n\nSorry."));                  SLOT(processServerExit()));
         processServerExit();  
         return;  
     }  
2887    
2888      // Show startup results...          // Build process arguments...
2889      appendMessages(tr("Server was started with PID=%1.").arg((long) m_pServer->pid()));          QStringList args = m_pOptions->sServerCmdLine.split(' ');
2890            QString sCommand = args[0];
2891            args.removeAt(0);
2892    
2893            appendMessages(tr("Server is starting..."));
2894            appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");
2895    
2896            // Go linuxsampler, go...
2897            m_pServer->start(sCommand, args);
2898            if (!m_pServer->waitForStarted()) {
2899                    appendMessagesError(tr("Could not start server.\n\nSorry."));
2900                    processServerExit();
2901                    return;
2902            }
2903    
2904      // Reset (yet again) the timer counters,          // Show startup results...
2905      // but this time is deferred as the user opted.          appendMessages(
2906      startSchedule(m_pOptions->iStartDelay);                  tr("Server was started with PID=%1.").arg((long) m_pServer->pid()));
2907      stabilizeForm();  
2908            // Reset (yet again) the timer counters,
2909            // but this time is deferred as the user opted.
2910            startSchedule(m_pOptions->iStartDelay);
2911            stabilizeForm();
2912  }  }
2913    
2914    
2915  // Stop linuxsampler server...  // Stop linuxsampler server...
2916  void MainForm::stopServer (void)  void MainForm::stopServer ( bool bInteractive )
2917  {  {
2918      // Stop client code.          // Stop client code.
2919      stopClient();          stopClient();
2920    
2921      // And try to stop server.          if (m_pServer && bInteractive) {
2922      if (m_pServer) {                  if (QMessageBox::question(this,
2923          appendMessages(tr("Server is stopping..."));                          QSAMPLER_TITLE ": " + tr("The backend's fate ..."),
2924          if (m_pServer->state() == QProcess::Running)                          tr("You have the option to keep the sampler backend (LinuxSampler)\n"
2925              m_pServer->terminate();                          "running in the background. The sampler would continue to work\n"
2926       }                          "according to your current sampler session and you could alter the\n"
2927                            "sampler session at any time by relaunching QSampler.\n\n"
2928      // Give it some time to terminate gracefully and stabilize...                          "Do you want LinuxSampler to stop?"),
2929      QTime t;                          QMessageBox::Yes | QMessageBox::No,
2930      t.start();                          QMessageBox::Yes) == QMessageBox::No) {
2931      while (t.elapsed() < QSAMPLER_TIMER_MSECS)                          m_bForceServerStop = false;
2932          QApplication::processEvents(QEventLoop::ExcludeUserInput);                  }
2933            }
2934    
2935       // Do final processing anyway.          bool bGraceWait = true;
2936       processServerExit();  
2937            // And try to stop server.
2938            if (m_pServer && m_bForceServerStop) {
2939                    appendMessages(tr("Server is stopping..."));
2940                    if (m_pServer->state() == QProcess::Running) {
2941                    #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
2942                            // Try harder...
2943                            m_pServer->kill();
2944                    #else
2945                            // Try softly...
2946                            m_pServer->terminate();
2947                            bool bFinished = m_pServer->waitForFinished(QSAMPLER_TIMER_MSECS * 1000);
2948                            if (bFinished) bGraceWait = false;
2949                    #endif
2950                    }
2951            }       // Do final processing anyway.
2952            else processServerExit();
2953    
2954            // Give it some time to terminate gracefully and stabilize...
2955            if (bGraceWait) {
2956                    QTime t;
2957                    t.start();
2958                    while (t.elapsed() < QSAMPLER_TIMER_MSECS)
2959                            QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2960            }
2961  }  }
2962    
2963    
2964  // Stdout handler...  // Stdout handler...
2965  void MainForm::readServerStdout (void)  void MainForm::readServerStdout (void)
2966  {  {
2967      if (m_pMessages)          if (m_pMessages)
2968          m_pMessages->appendStdoutBuffer(m_pServer->readAllStandardOutput());                  m_pMessages->appendStdoutBuffer(m_pServer->readAllStandardOutput());
2969  }  }
2970    
2971    
2972  // Linuxsampler server cleanup.  // Linuxsampler server cleanup.
2973  void MainForm::processServerExit (void)  void MainForm::processServerExit (void)
2974  {  {
2975      // Force client code cleanup.          // Force client code cleanup.
2976      stopClient();          stopClient();
2977    
2978      // Flush anything that maybe pending...          // Flush anything that maybe pending...
2979      if (m_pMessages)          if (m_pMessages)
2980          m_pMessages->flushStdoutBuffer();                  m_pMessages->flushStdoutBuffer();
2981    
2982      if (m_pServer) {          if (m_pServer && m_bForceServerStop) {
2983          // Force final server shutdown...                  if (m_pServer->state() != QProcess::NotRunning) {
2984          appendMessages(tr("Server was stopped with exit status %1.").arg(m_pServer->exitStatus()));                          appendMessages(tr("Server is being forced..."));
2985          m_pServer->terminate();                          // Force final server shutdown...
2986          if (!m_pServer->waitForFinished(2000))                          m_pServer->kill();
2987              m_pServer->kill();                          // Give it some time to terminate gracefully and stabilize...
2988          // Destroy it.                          QTime t;
2989          delete m_pServer;                          t.start();
2990          m_pServer = NULL;                          while (t.elapsed() < QSAMPLER_TIMER_MSECS)
2991      }                                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2992                    }
2993                    // Force final server shutdown...
2994                    appendMessages(
2995                            tr("Server was stopped with exit status %1.")
2996                            .arg(m_pServer->exitStatus()));
2997                    delete m_pServer;
2998                    m_pServer = NULL;
2999            }
3000    
3001      // Again, make status visible stable.          // Again, make status visible stable.
3002      stabilizeForm();          stabilizeForm();
3003  }  }
3004    
3005    
3006  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
3007  // qsamplerMainForm -- Client stuff.  // QSampler::MainForm -- Client stuff.
3008    
3009  // The LSCP client callback procedure.  // The LSCP client callback procedure.
3010  lscp_status_t qsampler_client_callback ( lscp_client_t */*pClient*/, lscp_event_t event, const char *pchData, int cchData, void *pvData )  lscp_status_t qsampler_client_callback ( lscp_client_t */*pClient*/,
3011            lscp_event_t event, const char *pchData, int cchData, void *pvData )
3012  {  {
3013      MainForm* pMainForm = (MainForm *) pvData;          MainForm* pMainForm = (MainForm *) pvData;
3014      if (pMainForm == NULL)          if (pMainForm == NULL)
3015          return LSCP_FAILED;                  return LSCP_FAILED;
3016    
3017      // ATTN: DO NOT EVER call any GUI code here,          // ATTN: DO NOT EVER call any GUI code here,
3018      // as this is run under some other thread context.          // as this is run under some other thread context.
3019      // A custom event must be posted here...          // A custom event must be posted here...
3020      QApplication::postEvent(pMainForm, new qsamplerCustomEvent(event, pchData, cchData));          QApplication::postEvent(pMainForm,
3021                    new LscpEvent(event, pchData, cchData));
3022    
3023      return LSCP_OK;          return LSCP_OK;
3024  }  }
3025    
3026    
3027  // Start our almighty client...  // Start our almighty client...
3028  bool MainForm::startClient (void)  bool MainForm::startClient (void)
3029  {  {
3030      // Have it a setup?          // Have it a setup?
3031      if (m_pOptions == NULL)          if (m_pOptions == NULL)
3032          return false;                  return false;
3033    
3034      // Aren't we already started, are we?          // Aren't we already started, are we?
3035      if (m_pClient)          if (m_pClient)
3036          return true;                  return true;
3037    
3038      // Log prepare here.          // Log prepare here.
3039      appendMessages(tr("Client connecting..."));          appendMessages(tr("Client connecting..."));
3040    
3041      // Create the client handle...          // Create the client handle...
3042      m_pClient = ::lscp_client_create(m_pOptions->sServerHost.latin1(), m_pOptions->iServerPort, qsampler_client_callback, this);          m_pClient = ::lscp_client_create(
3043      if (m_pClient == NULL) {                  m_pOptions->sServerHost.toUtf8().constData(),
3044          // Is this the first try?                  m_pOptions->iServerPort, qsampler_client_callback, this);
3045          // maybe we need to start a local server...          if (m_pClient == NULL) {
3046          if ((m_pServer && m_pServer->state() == QProcess::Running) || !m_pOptions->bServerStart)                  // Is this the first try?
3047              appendMessagesError(tr("Could not connect to server as client.\n\nSorry."));                  // maybe we need to start a local server...
3048          else                  if ((m_pServer && m_pServer->state() == QProcess::Running)
3049              startServer();                          || !m_pOptions->bServerStart) {
3050          // This is always a failure.                          appendMessagesError(
3051          stabilizeForm();                                  tr("Could not connect to server as client.\n\nSorry."));
3052          return false;                  } else {
3053      }                          startServer();
3054      // Just set receive timeout value, blindly.                  }
3055      ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);                  // This is always a failure.
3056      appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));                  stabilizeForm();
3057                    return false;
3058            }
3059    
3060            // Just set receive timeout value, blindly.
3061            ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);
3062            appendMessages(
3063                    tr("Client receive timeout is set to %1 msec.")
3064                    .arg(::lscp_client_get_timeout(m_pClient)));
3065    
3066          // Subscribe to channel info change notifications...          // Subscribe to channel info change notifications...
3067            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_COUNT) != LSCP_OK)
3068                    appendMessagesClient("lscp_client_subscribe(CHANNEL_COUNT)");
3069          if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO) != LSCP_OK)          if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO) != LSCP_OK)
3070                  appendMessagesClient("lscp_client_subscribe");                  appendMessagesClient("lscp_client_subscribe(CHANNEL_INFO)");
3071    
3072      // We may stop scheduling around.          DeviceStatusForm::onDevicesChanged(); // initialize
3073      stopSchedule();          updateViewMidiDeviceStatusMenu();
3074            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT) != LSCP_OK)
3075                    appendMessagesClient("lscp_client_subscribe(MIDI_INPUT_DEVICE_COUNT)");
3076            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_INFO) != LSCP_OK)
3077                    appendMessagesClient("lscp_client_subscribe(MIDI_INPUT_DEVICE_INFO)");
3078            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT) != LSCP_OK)
3079                    appendMessagesClient("lscp_client_subscribe(AUDIO_OUTPUT_DEVICE_COUNT)");
3080            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO) != LSCP_OK)
3081                    appendMessagesClient("lscp_client_subscribe(AUDIO_OUTPUT_DEVICE_INFO)");
3082    
3083    #if CONFIG_EVENT_CHANNEL_MIDI
3084            // Subscribe to channel MIDI data notifications...
3085            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_MIDI) != LSCP_OK)
3086                    appendMessagesClient("lscp_client_subscribe(CHANNEL_MIDI)");
3087    #endif
3088    
3089    #if CONFIG_EVENT_DEVICE_MIDI
3090            // Subscribe to channel MIDI data notifications...
3091            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_DEVICE_MIDI) != LSCP_OK)
3092                    appendMessagesClient("lscp_client_subscribe(DEVICE_MIDI)");
3093    #endif
3094    
3095      // We'll accept drops from now on...          // We may stop scheduling around.
3096      setAcceptDrops(true);          stopSchedule();
3097    
3098      // Log success here.          // We'll accept drops from now on...
3099      appendMessages(tr("Client connected."));          setAcceptDrops(true);
3100    
3101            // Log success here.
3102            appendMessages(tr("Client connected."));
3103    
3104          // Hard-notify instrumnet and device configuration forms,          // Hard-notify instrumnet and device configuration forms,
3105          // if visible, that we're ready...          // if visible, that we're ready...
3106          if (m_pInstrumentListForm)          if (m_pInstrumentListForm)
3107              m_pInstrumentListForm->refreshInstruments();                  m_pInstrumentListForm->refreshInstruments();
3108          if (m_pDeviceForm)          if (m_pDeviceForm)
3109              m_pDeviceForm->refreshDevices();                  m_pDeviceForm->refreshDevices();
3110    
3111            // Is any session pending to be loaded?
3112            if (!m_pOptions->sSessionFile.isEmpty()) {
3113                    // Just load the prabably startup session...
3114                    if (loadSessionFile(m_pOptions->sSessionFile)) {
3115                            m_pOptions->sSessionFile = QString::null;
3116                            return true;
3117                    }
3118            }
3119    
3120      // Is any session pending to be loaded?          // send the current / loaded fine tuning settings to the sampler
3121      if (!m_pOptions->sSessionFile.isEmpty()) {          m_pOptions->sendFineTuningSettings();
         // Just load the prabably startup session...  
         if (loadSessionFile(m_pOptions->sSessionFile)) {  
             m_pOptions->sSessionFile = QString::null;  
             return true;  
         }  
     }  
3122    
3123      // Make a new session          // Make a new session
3124      return newSession();          return newSession();
3125  }  }
3126    
3127    
3128  // Stop client...  // Stop client...
3129  void MainForm::stopClient (void)  void MainForm::stopClient (void)
3130  {  {
3131      if (m_pClient == NULL)          if (m_pClient == NULL)
3132          return;                  return;
   
     // Log prepare here.  
     appendMessages(tr("Client disconnecting..."));  
3133    
3134      // Clear timer counters...          // Log prepare here.
3135      stopSchedule();          appendMessages(tr("Client disconnecting..."));
3136    
3137      // We'll reject drops from now on...          // Clear timer counters...
3138      setAcceptDrops(false);          stopSchedule();
3139    
3140      // Force any channel strips around, but          // We'll reject drops from now on...
3141      // but avoid removing the corresponding          setAcceptDrops(false);
     // channels from the back-end server.  
     m_iDirtyCount = 0;  
     closeSession(false);  
3142    
3143      // Close us as a client...          // Force any channel strips around, but
3144            // but avoid removing the corresponding
3145            // channels from the back-end server.
3146            m_iDirtyCount = 0;
3147            closeSession(false);
3148    
3149            // Close us as a client...
3150    #if CONFIG_EVENT_DEVICE_MIDI
3151            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_DEVICE_MIDI);
3152    #endif
3153    #if CONFIG_EVENT_CHANNEL_MIDI
3154            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_MIDI);
3155    #endif
3156            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO);
3157            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT);
3158            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_INFO);
3159            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT);
3160          ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO);          ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO);
3161      ::lscp_client_destroy(m_pClient);          ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_COUNT);
3162      m_pClient = NULL;          ::lscp_client_destroy(m_pClient);
3163            m_pClient = NULL;
3164    
3165          // Hard-notify instrumnet and device configuration forms,          // Hard-notify instrumnet and device configuration forms,
3166          // if visible, that we're running out...          // if visible, that we're running out...
3167          if (m_pInstrumentListForm)          if (m_pInstrumentListForm)
3168              m_pInstrumentListForm->refreshInstruments();                  m_pInstrumentListForm->refreshInstruments();
3169          if (m_pDeviceForm)          if (m_pDeviceForm)
3170              m_pDeviceForm->refreshDevices();                  m_pDeviceForm->refreshDevices();
3171    
3172      // Log final here.          // Log final here.
3173      appendMessages(tr("Client disconnected."));          appendMessages(tr("Client disconnected."));
3174    
3175      // Make visible status.          // Make visible status.
3176      stabilizeForm();          stabilizeForm();
3177  }  }
3178    
3179    
3180    // Channel strip activation/selection.
3181    void MainForm::activateStrip ( QMdiSubWindow *pMdiSubWindow )
3182    {
3183            ChannelStrip *pChannelStrip = NULL;
3184            if (pMdiSubWindow)
3185                    pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
3186            if (pChannelStrip)
3187                    pChannelStrip->setSelected(true);
3188    
3189            stabilizeForm();
3190    }
3191    
3192    
3193    // Channel toolbar orientation change.
3194    void MainForm::channelsToolbarOrientation ( Qt::Orientation orientation )
3195    {
3196    #ifdef CONFIG_VOLUME
3197            m_pVolumeSlider->setOrientation(orientation);
3198            if (orientation == Qt::Horizontal) {
3199                    m_pVolumeSlider->setMinimumHeight(24);
3200                    m_pVolumeSlider->setMaximumHeight(32);
3201                    m_pVolumeSlider->setMinimumWidth(120);
3202                    m_pVolumeSlider->setMaximumWidth(640);
3203                    m_pVolumeSpinBox->setMaximumWidth(64);
3204                    m_pVolumeSpinBox->setButtonSymbols(QSpinBox::UpDownArrows);
3205            } else {
3206                    m_pVolumeSlider->setMinimumHeight(120);
3207                    m_pVolumeSlider->setMaximumHeight(480);
3208                    m_pVolumeSlider->setMinimumWidth(24);
3209                    m_pVolumeSlider->setMaximumWidth(32);
3210                    m_pVolumeSpinBox->setMaximumWidth(32);
3211                    m_pVolumeSpinBox->setButtonSymbols(QSpinBox::NoButtons);
3212            }
3213    #endif
3214    }
3215    
3216    
3217  } // namespace QSampler  } // namespace QSampler
3218    
3219    

Legend:
Removed from v.1470  
changed lines
  Added in v.3508

  ViewVC Help
Powered by ViewVC