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

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

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

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

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

  ViewVC Help
Powered by ViewVC