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

Legend:
Removed from v.1475  
changed lines
  Added in v.3759

  ViewVC Help
Powered by ViewVC