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

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

  ViewVC Help
Powered by ViewVC