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

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

  ViewVC Help
Powered by ViewVC