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

Legend:
Removed from v.1507  
changed lines
  Added in v.3789

  ViewVC Help
Powered by ViewVC