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

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

  ViewVC Help
Powered by ViewVC