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

Legend:
Removed from v.1499  
changed lines
  Added in v.4038

  ViewVC Help
Powered by ViewVC