/[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 1466 by capela, Thu Nov 1 19:25:10 2007 UTC revision 3837 by capela, Tue Dec 1 17:46:41 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    void MainForm::removeChannelStrip (void)
1658    {
1659            if (m_pClient == nullptr)
1660                    return;
1661    
1662            ChannelStrip *pChannelStrip = activeChannelStrip();
1663            if (pChannelStrip == nullptr)
1664                    return;
1665    
1666            Channel *pChannel = pChannelStrip->channel();
1667            if (pChannel == nullptr)
1668                    return;
1669    
1670            // Prompt user if he/she's sure about this...
1671            if (m_pOptions && m_pOptions->bConfirmRemove) {
1672                    const QString& sTitle = tr("Warning");
1673                    const QString& sText = tr(
1674                            "About to remove channel:\n\n"
1675                            "%1\n\n"
1676                            "Are you sure?")
1677                            .arg(pChannelStrip->windowTitle());
1678            #if 0
1679                    if (QMessageBox::warning(this, sTitle, sText,
1680                            QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
1681                            return;
1682            #else
1683                    QMessageBox mbox(this);
1684                    mbox.setIcon(QMessageBox::Warning);
1685                    mbox.setWindowTitle(sTitle);
1686                    mbox.setText(sText);
1687                    mbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
1688                    QCheckBox cbox(tr("Don't ask this again"));
1689                    cbox.setChecked(false);
1690                    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      ChannelStrip* pChannelStrip = activeChannelStrip();          // Remove the existing sampler channel.
1700      if (pChannelStrip == NULL)          if (!pChannel->removeChannel())
1701          return;                  return;
1702    
1703      qsamplerChannel *pChannel = pChannelStrip->channel();          // Just delete the channel strip.
1704      if (pChannel == NULL)          destroyChannelStrip(pChannelStrip);
1705          return;  
1706            // We'll be dirty, for sure...
1707      // Prompt user if he/she's sure about this...          m_iDirtyCount++;
1708      if (m_pOptions && m_pOptions->bConfirmRemove) {          stabilizeForm();
         if (QMessageBox::warning(this,  
                         QSAMPLER_TITLE ": " + tr("Warning"),  
             tr("About to remove channel:\n\n"  
                "%1\n\n"  
                "Are you sure?")  
                .arg(pChannelStrip->caption()),  
             tr("OK"), tr("Cancel")) > 0)  
             return;  
     }  
   
     // Remove the existing sampler channel.  
     if (!pChannel->removeChannel())  
         return;  
   
     // Just delete the channel strip.  
     delete pChannelStrip;  
   
     // Do we auto-arrange?  
     if (m_pOptions && m_pOptions->bAutoArrange)  
         channelsArrange();  
   
     // We'll be dirty, for sure...  
     m_iDirtyCount++;  
     stabilizeForm();  
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;
1999      m_pWorkspace->setUpdatesEnabled(false);  
2000      int y = 0;          m_pWorkspace->setUpdatesEnabled(false);
2001      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          int y = 0;
2002          ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);          foreach (QMdiSubWindow *pMdiSubWindow, wlist) {
2003      /*  if (pChannelStrip->testWState(WState_Maximized | WState_Minimized)) {                  pMdiSubWindow->adjustSize();
2004              // Prevent flicker...                  const QRect& frameRect
2005              pChannelStrip->hide();                          = pMdiSubWindow->frameGeometry();
2006              pChannelStrip->showNormal();                  int w = m_pWorkspace->width();
2007          }   */                  if (w < frameRect.width())
2008          pChannelStrip->adjustSize();                          w = frameRect.width();
2009          int iWidth  = m_pWorkspace->width();                  const int h = frameRect.height();
2010          if (iWidth < pChannelStrip->width())                  pMdiSubWindow->setGeometry(0, y, w, h);
2011              iWidth = pChannelStrip->width();                  y += h;
2012      //  int iHeight = pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();          }
2013          int iHeight = pChannelStrip->parentWidget()->frameGeometry().height();          m_pWorkspace->setUpdatesEnabled(true);
         pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight);  
         y += iHeight;  
     }  
     m_pWorkspace->setUpdatesEnabled(true);  
2014    
2015      stabilizeForm();          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: Qt %1").arg(qVersion());
2104    #if defined(QT_STATIC)
2105            sText += "-static";
2106    #endif
2107            sText += ", ";
2108            sText += ::lscp_client_package();
2109            sText += " ";
2110            sText += ::lscp_client_version();
2111  #ifdef CONFIG_LIBGIG  #ifdef CONFIG_LIBGIG
2112      sText += ", ";          sText += ", ";
2113      sText += gig::libraryName().c_str();          sText += gig::libraryName().c_str();
2114      sText += " ";          sText += " ";
2115      sText += gig::libraryVersion().c_str();          sText += gig::libraryVersion().c_str();
2116  #endif  #endif
2117      sText += "<br />\n";          sText += "<br />\n";
2118      sText += "<br />\n";          sText += "<br />\n";
2119      sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";          sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";
2120      sText += "<br />\n";          sText += "<br />\n";
2121      sText += "<small>";          sText += "<small>";
2122      sText += QSAMPLER_COPYRIGHT "<br />\n";          sText += QSAMPLER_COPYRIGHT "<br />\n";
2123      sText += QSAMPLER_COPYRIGHT2 "<br />\n";          sText += QSAMPLER_COPYRIGHT2 "<br />\n";
2124      sText += "<br />\n";          sText += "<br />\n";
2125      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";
2126      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.");
2127      sText += "</small>";          sText += "</small>";
2128      sText += "</p>\n";          sText += "</p>\n";
2129    
2130      QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText);          QMessageBox::about(this, tr("About"), sText);
2131  }  }
2132    
2133    
2134  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2135  // qsamplerMainForm -- Main window stabilization.  // QSampler::MainForm -- Main window stabilization.
2136    
2137  void MainForm::stabilizeForm (void)  void MainForm::stabilizeForm (void)
2138  {  {
2139      // Update the main application caption...          // Update the main application caption...
2140      QString sSessionName = sessionName(m_sFilename);          QString sSessionName = sessionName(m_sFilename);
2141      if (m_iDirtyCount > 0)          if (m_iDirtyCount > 0)
2142          sSessionName += " *";                  sSessionName += " *";
2143      setCaption(tr(QSAMPLER_TITLE " - [%1]").arg(sSessionName));          setWindowTitle(sSessionName);
2144    
2145      // Update the main menu state...          // Update the main menu state...
2146      ChannelStrip* pChannelStrip = activeChannelStrip();          ChannelStrip *pChannelStrip = activeChannelStrip();
2147      bool bHasClient  = (m_pOptions != NULL && m_pClient != NULL);          const QList<QMdiSubWindow *>& wlist = m_pWorkspace->subWindowList();
2148      bool bHasChannel = (bHasClient && pChannelStrip != NULL);          const bool bHasClient = (m_pOptions != nullptr && m_pClient != nullptr);
2149      ui.fileNewAction->setEnabled(bHasClient);          const bool bHasChannel = (bHasClient && pChannelStrip != nullptr);
2150      ui.fileOpenAction->setEnabled(bHasClient);          const bool bHasChannels = (bHasClient && wlist.count() > 0);
2151      ui.fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);          m_ui.fileNewAction->setEnabled(bHasClient);
2152      ui.fileSaveAsAction->setEnabled(bHasClient);          m_ui.fileOpenAction->setEnabled(bHasClient);
2153      ui.fileResetAction->setEnabled(bHasClient);          m_ui.fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);
2154      ui.fileRestartAction->setEnabled(bHasClient || m_pServer == NULL);          m_ui.fileSaveAsAction->setEnabled(bHasClient);
2155      ui.editAddChannelAction->setEnabled(bHasClient);          m_ui.fileResetAction->setEnabled(bHasClient);
2156      ui.editRemoveChannelAction->setEnabled(bHasChannel);          m_ui.fileRestartAction->setEnabled(bHasClient || m_pServer == nullptr);
2157      ui.editSetupChannelAction->setEnabled(bHasChannel);          m_ui.editAddChannelAction->setEnabled(bHasClient);
2158            m_ui.editRemoveChannelAction->setEnabled(bHasChannel);
2159            m_ui.editSetupChannelAction->setEnabled(bHasChannel);
2160  #ifdef CONFIG_EDIT_INSTRUMENT  #ifdef CONFIG_EDIT_INSTRUMENT
2161      ui.editEditChannelAction->setEnabled(bHasChannel);          m_ui.editEditChannelAction->setEnabled(bHasChannel);
2162  #else  #else
2163      ui.editEditChannelAction->setEnabled(false);          m_ui.editEditChannelAction->setEnabled(false);
2164  #endif  #endif
2165      ui.editResetChannelAction->setEnabled(bHasChannel);          m_ui.editResetChannelAction->setEnabled(bHasChannel);
2166      ui.editResetAllChannelsAction->setEnabled(bHasChannel);          m_ui.editResetAllChannelsAction->setEnabled(bHasChannels);
2167      ui.viewMessagesAction->setOn(m_pMessages && m_pMessages->isVisible());          m_ui.viewMessagesAction->setChecked(m_pMessages && m_pMessages->isVisible());
2168  #ifdef CONFIG_MIDI_INSTRUMENT  #ifdef CONFIG_MIDI_INSTRUMENT
2169          ui.viewInstrumentsAction->setOn(m_pInstrumentListForm          m_ui.viewInstrumentsAction->setChecked(m_pInstrumentListForm
2170                  && m_pInstrumentListForm->isVisible());                  && m_pInstrumentListForm->isVisible());
2171          ui.viewInstrumentsAction->setEnabled(bHasClient);          m_ui.viewInstrumentsAction->setEnabled(bHasClient);
2172  #else  #else
2173          ui.viewInstrumentsAction->setEnabled(false);          m_ui.viewInstrumentsAction->setEnabled(false);
2174  #endif  #endif
2175          ui.viewDevicesAction->setOn(m_pDeviceForm          m_ui.viewDevicesAction->setChecked(m_pDeviceForm
2176                  && m_pDeviceForm->isVisible());                  && m_pDeviceForm->isVisible());
2177      ui.viewDevicesAction->setEnabled(bHasClient);          m_ui.viewDevicesAction->setEnabled(bHasClient);
2178      ui.channelsArrangeAction->setEnabled(bHasChannel);          m_ui.viewMidiDeviceStatusMenu->setEnabled(
2179                    DeviceStatusForm::getInstances().size() > 0);
2180            m_ui.channelsArrangeAction->setEnabled(bHasChannels);
2181    
2182  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
2183          // Toolbar widgets are also affected...          // Toolbar widgets are also affected...
2184      m_pVolumeSlider->setEnabled(bHasClient);          m_pVolumeSlider->setEnabled(bHasClient);
2185      m_pVolumeSpinBox->setEnabled(bHasClient);          m_pVolumeSpinBox->setEnabled(bHasClient);
2186  #endif  #endif
2187    
2188      // Client/Server status...          // Client/Server status...
2189      if (bHasClient) {          if (bHasClient) {
2190          m_statusItem[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));                  m_statusItem[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));
2191          m_statusItem[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost + ":" + QString::number(m_pOptions->iServerPort));                  m_statusItem[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost
2192      } else {                          + ':' + QString::number(m_pOptions->iServerPort));
2193          m_statusItem[QSAMPLER_STATUS_CLIENT]->clear();          } else {
2194          m_statusItem[QSAMPLER_STATUS_SERVER]->clear();                  m_statusItem[QSAMPLER_STATUS_CLIENT]->clear();
2195      }                  m_statusItem[QSAMPLER_STATUS_SERVER]->clear();
2196      // Channel status...          }
2197      if (bHasChannel)          // Channel status...
2198          m_statusItem[QSAMPLER_STATUS_CHANNEL]->setText(pChannelStrip->caption());          if (bHasChannel)
2199      else                  m_statusItem[QSAMPLER_STATUS_CHANNEL]->setText(pChannelStrip->windowTitle());
2200          m_statusItem[QSAMPLER_STATUS_CHANNEL]->clear();          else
2201      // Session status...                  m_statusItem[QSAMPLER_STATUS_CHANNEL]->clear();
2202      if (m_iDirtyCount > 0)          // Session status...
2203          m_statusItem[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));          if (m_iDirtyCount > 0)
2204      else                  m_statusItem[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));
2205          m_statusItem[QSAMPLER_STATUS_SESSION]->clear();          else
2206                    m_statusItem[QSAMPLER_STATUS_SESSION]->clear();
2207    
2208      // Recent files menu.          // Recent files menu.
2209      m_pRecentFilesMenu->setEnabled(bHasClient && m_pOptions->recentFiles.count() > 0);          m_ui.fileOpenRecentMenu->setEnabled(m_pOptions->recentFiles.count() > 0);
2210  }  }
2211    
2212    
# Line 1823  void MainForm::volumeChanged ( int iVolu Line 2227  void MainForm::volumeChanged ( int iVolu
2227                  m_pVolumeSpinBox->setValue(iVolume);                  m_pVolumeSpinBox->setValue(iVolume);
2228    
2229          // Do it as commanded...          // Do it as commanded...
2230          float fVolume = 0.01f * float(iVolume);          const float fVolume = 0.01f * float(iVolume);
2231          if (::lscp_set_volume(m_pClient, fVolume) == LSCP_OK)          if (::lscp_set_volume(m_pClient, fVolume) == LSCP_OK)
2232                  appendMessages(QObject::tr("Volume: %1.").arg(fVolume));                  appendMessages(QObject::tr("Volume: %1.").arg(fVolume));
2233          else          else
# Line 1839  void MainForm::volumeChanged ( int iVolu Line 2243  void MainForm::volumeChanged ( int iVolu
2243    
2244    
2245  // Channel change receiver slot.  // Channel change receiver slot.
2246  void MainForm::channelStripChanged(ChannelStrip* pChannelStrip)  void MainForm::channelStripChanged ( ChannelStrip *pChannelStrip )
2247  {  {
2248          // Add this strip to the changed list...          // Add this strip to the changed list...
2249          if (m_changedStrips.containsRef(pChannelStrip) == 0) {          if (!m_changedStrips.contains(pChannelStrip)) {
2250                  m_changedStrips.append(pChannelStrip);                  m_changedStrips.append(pChannelStrip);
2251                  pChannelStrip->resetErrorCount();                  pChannelStrip->resetErrorCount();
2252          }          }
2253    
2254      // Just mark the dirty form.          // Just mark the dirty form.
2255      m_iDirtyCount++;          m_iDirtyCount++;
2256      // and update the form status...          // and update the form status...
2257      stabilizeForm();          stabilizeForm();
2258  }  }
2259    
2260    
# Line 1858  void MainForm::channelStripChanged(Chann Line 2262  void MainForm::channelStripChanged(Chann
2262  void MainForm::updateSession (void)  void MainForm::updateSession (void)
2263  {  {
2264  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
2265          int iVolume = ::lroundf(100.0f * ::lscp_get_volume(m_pClient));          const int iVolume = ::lroundf(100.0f * ::lscp_get_volume(m_pClient));
2266          m_iVolumeChanging++;          m_iVolumeChanging++;
2267          m_pVolumeSlider->setValue(iVolume);          m_pVolumeSlider->setValue(iVolume);
2268          m_pVolumeSpinBox->setValue(iVolume);          m_pVolumeSpinBox->setValue(iVolume);
# Line 1866  void MainForm::updateSession (void) Line 2270  void MainForm::updateSession (void)
2270  #endif  #endif
2271  #ifdef CONFIG_MIDI_INSTRUMENT  #ifdef CONFIG_MIDI_INSTRUMENT
2272          // FIXME: Make some room for default instrument maps...          // FIXME: Make some room for default instrument maps...
2273          int iMaps = ::lscp_get_midi_instrument_maps(m_pClient);          const int iMaps = ::lscp_get_midi_instrument_maps(m_pClient);
2274          if (iMaps < 0)          if (iMaps < 0)
2275                  appendMessagesClient("lscp_get_midi_instrument_maps");                  appendMessagesClient("lscp_get_midi_instrument_maps");
2276          else if (iMaps < 1) {          else if (iMaps < 1) {
2277                  ::lscp_add_midi_instrument_map(m_pClient, tr("Chromatic").latin1());                  ::lscp_add_midi_instrument_map(m_pClient,
2278                  ::lscp_add_midi_instrument_map(m_pClient, tr("Drum Kits").latin1());                          tr("Chromatic").toUtf8().constData());
2279                    ::lscp_add_midi_instrument_map(m_pClient,
2280                            tr("Drum Kits").toUtf8().constData());
2281          }          }
2282  #endif  #endif
2283    
2284            updateAllChannelStrips(false);
2285    
2286            // Do we auto-arrange?
2287            channelsArrangeAuto();
2288    
2289            // Remember to refresh devices and instruments...
2290            if (m_pInstrumentListForm)
2291                    m_pInstrumentListForm->refreshInstruments();
2292            if (m_pDeviceForm)
2293                    m_pDeviceForm->refreshDevices();
2294    }
2295    
2296    
2297    void MainForm::updateAllChannelStrips ( bool bRemoveDeadStrips )
2298    {
2299            // Skip if setting up a new channel strip...
2300            if (m_iDirtySetup > 0)
2301                    return;
2302    
2303          // Retrieve the current channel list.          // Retrieve the current channel list.
2304          int *piChannelIDs = ::lscp_list_channels(m_pClient);          int *piChannelIDs = ::lscp_list_channels(m_pClient);
2305          if (piChannelIDs == NULL) {          if (piChannelIDs == nullptr) {
2306                  if (::lscp_client_get_errno(m_pClient)) {                  if (::lscp_client_get_errno(m_pClient)) {
2307                          appendMessagesClient("lscp_list_channels");                          appendMessagesClient("lscp_list_channels");
2308                          appendMessagesError(tr("Could not get current list of channels.\n\nSorry."));                          appendMessagesError(
2309                                    tr("Could not get current list of channels.\n\nSorry."));
2310                  }                  }
2311          } else {          } else {
2312                  // Try to (re)create each channel.                  // Try to (re)create each channel.
2313                  m_pWorkspace->setUpdatesEnabled(false);                  m_pWorkspace->setUpdatesEnabled(false);
2314                  for (int iChannel = 0; piChannelIDs[iChannel] >= 0; iChannel++) {                  for (int iChannel = 0; piChannelIDs[iChannel] >= 0; ++iChannel) {
2315                          // Check if theres already a channel strip for this one...                          // Check if theres already a channel strip for this one...
2316                          if (!channelStrip(piChannelIDs[iChannel]))                          if (!channelStrip(piChannelIDs[iChannel]))
2317                                  createChannelStrip(new qsamplerChannel(piChannelIDs[iChannel]));                                  createChannelStrip(new Channel(piChannelIDs[iChannel]));
2318                    }
2319                    // Do we auto-arrange?
2320                    channelsArrangeAuto();
2321                    // remove dead channel strips
2322                    if (bRemoveDeadStrips) {
2323                            const QList<QMdiSubWindow *>& wlist
2324                                    = m_pWorkspace->subWindowList();
2325                            foreach (QMdiSubWindow *pMdiSubWindow, wlist) {
2326                                    ChannelStrip *pChannelStrip
2327                                            = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2328                                    if (pChannelStrip) {
2329                                            bool bExists = false;
2330                                            for (int iChannel = 0; piChannelIDs[iChannel] >= 0; ++iChannel) {
2331                                                    Channel *pChannel = pChannelStrip->channel();
2332                                                    if (pChannel == nullptr)
2333                                                            break;
2334                                                    if (piChannelIDs[iChannel] == pChannel->channelID()) {
2335                                                            // strip exists, don't touch it
2336                                                            bExists = true;
2337                                                            break;
2338                                                    }
2339                                            }
2340                                            if (!bExists)
2341                                                    destroyChannelStrip(pChannelStrip);
2342                                    }
2343                            }
2344                  }                  }
2345                  m_pWorkspace->setUpdatesEnabled(true);                  m_pWorkspace->setUpdatesEnabled(true);
2346          }          }
2347    
2348      // 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();  
2349  }  }
2350    
2351    
2352  // Update the recent files list and menu.  // Update the recent files list and menu.
2353  void MainForm::updateRecentFiles ( const QString& sFilename )  void MainForm::updateRecentFiles ( const QString& sFilename )
2354  {  {
2355      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
2356          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);  
2357    
2358      // May update the menu.          // Remove from list if already there (avoid duplicates)
2359      updateRecentFilesMenu();          const int iIndex = m_pOptions->recentFiles.indexOf(sFilename);
2360            if (iIndex >= 0)
2361                    m_pOptions->recentFiles.removeAt(iIndex);
2362            // Put it to front...
2363            m_pOptions->recentFiles.push_front(sFilename);
2364  }  }
2365    
2366    
2367  // Update the recent files list and menu.  // Update the recent files list and menu.
2368  void MainForm::updateRecentFilesMenu (void)  void MainForm::updateRecentFilesMenu (void)
2369  {  {
2370      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
2371          return;                  return;
2372    
2373            // Time to keep the list under limits.
2374            int iRecentFiles = m_pOptions->recentFiles.count();
2375            while (iRecentFiles > m_pOptions->iMaxRecentFiles) {
2376                    m_pOptions->recentFiles.pop_back();
2377                    iRecentFiles--;
2378            }
2379    
2380      // Time to keep the list under limits.          // Rebuild the recent files menu...
2381      int iRecentFiles = m_pOptions->recentFiles.count();          m_ui.fileOpenRecentMenu->clear();
2382      while (iRecentFiles > m_pOptions->iMaxRecentFiles) {          for (int i = 0; i < iRecentFiles; i++) {
2383          m_pOptions->recentFiles.pop_back();                  const QString& sFilename = m_pOptions->recentFiles[i];
2384          iRecentFiles--;                  if (QFileInfo(sFilename).exists()) {
2385      }                          QAction *pAction = m_ui.fileOpenRecentMenu->addAction(
2386                                    QString("&%1 %2").arg(i + 1).arg(sessionName(sFilename)),
2387      // rebuild the recent files menu...                                  this, SLOT(fileOpenRecent()));
2388      m_pRecentFilesMenu->clear();                          pAction->setData(i);
2389      for (int i = 0; i < iRecentFiles; i++) {                  }
2390          const QString& sFilename = m_pOptions->recentFiles[i];          }
         if (QFileInfo(sFilename).exists()) {  
             m_pRecentFilesMenu->insertItem(QString("&%1 %2")  
                 .arg(i + 1).arg(sessionName(sFilename)),  
                 this, SLOT(fileOpenRecent(int)), 0, i);  
         }  
     }  
2391  }  }
2392    
2393    
2394  // Force update of the channels instrument names mode.  // Force update of the channels instrument names mode.
2395  void MainForm::updateInstrumentNames (void)  void MainForm::updateInstrumentNames (void)
2396  {  {
2397      // Full channel list update...          // Full channel list update...
2398      QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
2399      if (wlist.isEmpty())                  = m_pWorkspace->subWindowList();
2400          return;          if (wlist.isEmpty())
2401                    return;
2402      m_pWorkspace->setUpdatesEnabled(false);  
2403      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          m_pWorkspace->setUpdatesEnabled(false);
2404          ChannelStrip *pChannelStrip = (ChannelStrip *) wlist.at(iChannel);          foreach (QMdiSubWindow *pMdiSubWindow, wlist) {
2405          if (pChannelStrip)                  ChannelStrip *pChannelStrip
2406              pChannelStrip->updateInstrumentName(true);                          = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2407      }                  if (pChannelStrip)
2408      m_pWorkspace->setUpdatesEnabled(true);                          pChannelStrip->updateInstrumentName(true);
2409            }
2410            m_pWorkspace->setUpdatesEnabled(true);
2411  }  }
2412    
2413    
2414  // Force update of the channels display font.  // Force update of the channels display font.
2415  void MainForm::updateDisplayFont (void)  void MainForm::updateDisplayFont (void)
2416  {  {
2417      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
2418          return;                  return;
2419    
2420            // Check if display font is legal.
2421            if (m_pOptions->sDisplayFont.isEmpty())
2422                    return;
2423    
2424      // Check if display font is legal.          // Realize it.
2425      if (m_pOptions->sDisplayFont.isEmpty())          QFont font;
2426          return;          if (!font.fromString(m_pOptions->sDisplayFont))
2427      // Realize it.                  return;
2428      QFont font;  
2429      if (!font.fromString(m_pOptions->sDisplayFont))          // Full channel list update...
2430          return;          const QList<QMdiSubWindow *>& wlist
2431                    = m_pWorkspace->subWindowList();
2432      // Full channel list update...          if (wlist.isEmpty())
2433      QWidgetList wlist = m_pWorkspace->windowList();                  return;
2434      if (wlist.isEmpty())  
2435          return;          m_pWorkspace->setUpdatesEnabled(false);
2436            foreach (QMdiSubWindow *pMdiSubWindow, wlist) {
2437      m_pWorkspace->setUpdatesEnabled(false);                  ChannelStrip *pChannelStrip
2438      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {                          = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2439          ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);                  if (pChannelStrip)
2440          if (pChannelStrip)                          pChannelStrip->setDisplayFont(font);
2441              pChannelStrip->setDisplayFont(font);          }
2442      }          m_pWorkspace->setUpdatesEnabled(true);
     m_pWorkspace->setUpdatesEnabled(true);  
2443  }  }
2444    
2445    
2446  // Update channel strips background effect.  // Update channel strips background effect.
2447  void MainForm::updateDisplayEffect (void)  void MainForm::updateDisplayEffect (void)
2448  {  {
2449     QPixmap pm;          // Full channel list update...
2450      if (m_pOptions->bDisplayEffect)          const QList<QMdiSubWindow *>& wlist
2451          pm = QPixmap(":/qsampler/pixmaps/displaybg1.png");                  = m_pWorkspace->subWindowList();
2452            if (wlist.isEmpty())
2453      // Full channel list update...                  return;
2454      QWidgetList wlist = m_pWorkspace->windowList();  
2455      if (wlist.isEmpty())          m_pWorkspace->setUpdatesEnabled(false);
2456          return;          foreach (QMdiSubWindow *pMdiSubWindow, wlist) {
2457                    ChannelStrip *pChannelStrip
2458      m_pWorkspace->setUpdatesEnabled(false);                          = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2459      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {                  if (pChannelStrip)
2460          ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);                          pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
2461          if (pChannelStrip)          }
2462              pChannelStrip->setDisplayBackground(pm);          m_pWorkspace->setUpdatesEnabled(true);
     }  
     m_pWorkspace->setUpdatesEnabled(true);  
2463  }  }
2464    
2465    
2466  // Force update of the channels maximum volume setting.  // Force update of the channels maximum volume setting.
2467  void MainForm::updateMaxVolume (void)  void MainForm::updateMaxVolume (void)
2468  {  {
2469      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
2470          return;                  return;
2471    
2472  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
2473          m_iVolumeChanging++;          m_iVolumeChanging++;
2474          m_pVolumeSlider->setMaxValue(m_pOptions->iMaxVolume);          m_pVolumeSlider->setMaximum(m_pOptions->iMaxVolume);
2475          m_pVolumeSpinBox->setMaxValue(m_pOptions->iMaxVolume);          m_pVolumeSpinBox->setMaximum(m_pOptions->iMaxVolume);
2476          m_iVolumeChanging--;          m_iVolumeChanging--;
2477  #endif  #endif
2478    
2479      // Full channel list update...          // Full channel list update...
2480      QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
2481      if (wlist.isEmpty())                  = m_pWorkspace->subWindowList();
2482          return;          if (wlist.isEmpty())
2483                    return;
2484      m_pWorkspace->setUpdatesEnabled(false);  
2485      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          m_pWorkspace->setUpdatesEnabled(false);
2486          ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);          foreach (QMdiSubWindow *pMdiSubWindow, wlist) {
2487          if (pChannelStrip)                  ChannelStrip *pChannelStrip
2488              pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);                          = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2489      }                  if (pChannelStrip)
2490      m_pWorkspace->setUpdatesEnabled(true);                          pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
2491            }
2492            m_pWorkspace->setUpdatesEnabled(true);
2493  }  }
2494    
2495    
2496  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2497  // qsamplerMainForm -- Messages window form handlers.  // QSampler::MainForm -- Messages window form handlers.
2498    
2499  // Messages output methods.  // Messages output methods.
2500  void MainForm::appendMessages( const QString& s )  void MainForm::appendMessages ( const QString& s )
2501  {  {
2502      if (m_pMessages)          if (m_pMessages)
2503          m_pMessages->appendMessages(s);                  m_pMessages->appendMessages(s);
2504    
2505      statusBar()->message(s, 3000);          statusBar()->showMessage(s, 3000);
2506  }  }
2507    
2508  void MainForm::appendMessagesColor( const QString& s, const QString& c )  void MainForm::appendMessagesColor ( const QString& s, const QColor& rgb )
2509  {  {
2510      if (m_pMessages)          if (m_pMessages)
2511          m_pMessages->appendMessagesColor(s, c);                  m_pMessages->appendMessagesColor(s, rgb);
2512    
2513      statusBar()->message(s, 3000);          statusBar()->showMessage(s, 3000);
2514  }  }
2515    
2516  void MainForm::appendMessagesText( const QString& s )  void MainForm::appendMessagesText ( const QString& s )
2517  {  {
2518      if (m_pMessages)          if (m_pMessages)
2519          m_pMessages->appendMessagesText(s);                  m_pMessages->appendMessagesText(s);
2520  }  }
2521    
2522  void MainForm::appendMessagesError( const QString& s )  void MainForm::appendMessagesError ( const QString& s )
2523  {  {
2524      if (m_pMessages)          if (m_pMessages)
2525          m_pMessages->show();                  m_pMessages->show();
2526    
2527      appendMessagesColor(s.simplifyWhiteSpace(), "#ff0000");          appendMessagesColor(s.simplified(), Qt::red);
2528    
2529          // Make it look responsive...:)          // Make it look responsive...:)
2530          QApplication::processEvents(QEventLoop::ExcludeUserInput);          QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2531    
2532      QMessageBox::critical(this,          if (m_pOptions && m_pOptions->bConfirmError) {
2533                  QSAMPLER_TITLE ": " + tr("Error"), s, tr("Cancel"));                  const QString& sTitle = tr("Error");
2534            #if 0
2535                    QMessageBox::critical(this, sTitle, sText, QMessageBox::Cancel);
2536            #else
2537                    QMessageBox mbox(this);
2538                    mbox.setIcon(QMessageBox::Critical);
2539                    mbox.setWindowTitle(sTitle);
2540                    mbox.setText(s);
2541                    mbox.setStandardButtons(QMessageBox::Cancel);
2542                    QCheckBox cbox(tr("Don't show this again"));
2543                    cbox.setChecked(false);
2544                    cbox.blockSignals(true);
2545                    mbox.addButton(&cbox, QMessageBox::ActionRole);
2546                    if (mbox.exec() && cbox.isChecked())
2547                            m_pOptions->bConfirmError = false;
2548            #endif
2549            }
2550  }  }
2551    
2552    
2553  // This is a special message format, just for client results.  // This is a special message format, just for client results.
2554  void MainForm::appendMessagesClient( const QString& s )  void MainForm::appendMessagesClient( const QString& s )
2555  {  {
2556      if (m_pClient == NULL)          if (m_pClient == nullptr)
2557          return;                  return;
2558    
2559      appendMessagesColor(s + QString(": %1 (errno=%2)")          appendMessagesColor(s + QString(": %1 (errno=%2)")
2560          .arg(::lscp_client_get_result(m_pClient))                  .arg(::lscp_client_get_result(m_pClient))
2561          .arg(::lscp_client_get_errno(m_pClient)), "#996666");                  .arg(::lscp_client_get_errno(m_pClient)), "#996666");
2562    
2563          // Make it look responsive...:)          // Make it look responsive...:)
2564          QApplication::processEvents(QEventLoop::ExcludeUserInput);          QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2565  }  }
2566    
2567    
2568  // Force update of the messages font.  // Force update of the messages font.
2569  void MainForm::updateMessagesFont (void)  void MainForm::updateMessagesFont (void)
2570  {  {
2571      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
2572          return;                  return;
2573    
2574      if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {          if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {
2575          QFont font;                  QFont font;
2576          if (font.fromString(m_pOptions->sMessagesFont))                  if (font.fromString(m_pOptions->sMessagesFont))
2577              m_pMessages->setMessagesFont(font);                          m_pMessages->setMessagesFont(font);
2578      }          }
2579  }  }
2580    
2581    
2582  // Update messages window line limit.  // Update messages window line limit.
2583  void MainForm::updateMessagesLimit (void)  void MainForm::updateMessagesLimit (void)
2584  {  {
2585      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
2586          return;                  return;
2587    
2588      if (m_pMessages) {          if (m_pMessages) {
2589          if (m_pOptions->bMessagesLimit)                  if (m_pOptions->bMessagesLimit)
2590              m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);                          m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);
2591          else                  else
2592              m_pMessages->setMessagesLimit(-1);                          m_pMessages->setMessagesLimit(-1);
2593      }          }
2594  }  }
2595    
2596    
2597  // Enablement of the messages capture feature.  // Enablement of the messages capture feature.
2598  void MainForm::updateMessagesCapture (void)  void MainForm::updateMessagesCapture (void)
2599  {  {
2600      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
2601          return;                  return;
2602    
2603      if (m_pMessages)          if (m_pMessages)
2604          m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);                  m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);
2605  }  }
2606    
2607    
2608  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2609  // qsamplerMainForm -- MDI channel strip management.  // QSampler::MainForm -- MDI channel strip management.
2610    
2611  // The channel strip creation executive.  // The channel strip creation executive.
2612  ChannelStrip* MainForm::createChannelStrip(qsamplerChannel* pChannel)  ChannelStrip *MainForm::createChannelStrip ( Channel *pChannel )
2613  {  {
2614      if (m_pClient == NULL || pChannel == NULL)          if (m_pClient == nullptr || pChannel == nullptr)
2615          return NULL;                  return nullptr;
2616    
2617      // Prepare for auto-arrange?          // Add a new channel itema...
2618      ChannelStrip* pChannelStrip = NULL;          ChannelStrip *pChannelStrip = new ChannelStrip();
2619      int y = 0;          if (pChannelStrip == nullptr)
2620      if (m_pOptions && m_pOptions->bAutoArrange) {                  return nullptr;
2621          QWidgetList wlist = m_pWorkspace->windowList();  
2622          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          // Set some initial channel strip options...
2623              pChannelStrip = (ChannelStrip *) wlist.at(iChannel);          if (m_pOptions) {
2624                          if (pChannelStrip) {                  // Background display effect...
2625                          //  y += pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();                  pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
2626                                  y += pChannelStrip->parentWidget()->frameGeometry().height();                  // We'll need a display font.
2627                          }                  QFont font;
2628          }                  if (!m_pOptions->sDisplayFont.isEmpty() &&
2629      }                          font.fromString(m_pOptions->sDisplayFont))
2630                            pChannelStrip->setDisplayFont(font);
2631                    // Maximum allowed volume setting.
2632                    pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
2633            }
2634    
2635            // Add it to workspace...
2636            QMdiSubWindow *pMdiSubWindow
2637                    = m_pWorkspace->addSubWindow(pChannelStrip,
2638                            Qt::SubWindow | Qt::FramelessWindowHint);
2639            pMdiSubWindow->setAttribute(Qt::WA_DeleteOnClose);
2640    
2641      // Add a new channel itema...          // Actual channel strip setup...
2642      Qt::WFlags wflags = Qt::WStyle_Customize | Qt::WStyle_Tool | Qt::WStyle_Title | Qt::WStyle_NoBorder;          pChannelStrip->setup(pChannel);
     pChannelStrip = new ChannelStrip(m_pWorkspace, wflags);  
     if (pChannelStrip == NULL)  
         return NULL;  
2643    
     // Actual channel strip setup...  
     pChannelStrip->setup(pChannel);  
2644          QObject::connect(pChannelStrip,          QObject::connect(pChannelStrip,
2645                  SIGNAL(channelChanged(qsamplerChannelStrip *)),                  SIGNAL(channelChanged(ChannelStrip *)),
2646                  SLOT(channelStripChanged(qsamplerChannelStrip *)));                  SLOT(channelStripChanged(ChannelStrip *)));
2647      // Set some initial aesthetic options...  
2648      if (m_pOptions) {          // Now we show up us to the world.
2649          // 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);  
     }  
2650    
2651          // This is pretty new, so we'll watch for it closely.          // This is pretty new, so we'll watch for it closely.
2652          channelStripChanged(pChannelStrip);          channelStripChanged(pChannelStrip);
2653    
2654      // Return our successful reference...          // Return our successful reference...
2655      return pChannelStrip;          return pChannelStrip;
2656    }
2657    
2658    
2659    void MainForm::destroyChannelStrip ( ChannelStrip *pChannelStrip )
2660    {
2661            QMdiSubWindow *pMdiSubWindow
2662                    = static_cast<QMdiSubWindow *> (pChannelStrip->parentWidget());
2663            if (pMdiSubWindow == nullptr)
2664                    return;
2665    
2666            // Just delete the channel strip.
2667            delete pChannelStrip;
2668            delete pMdiSubWindow;
2669    
2670            // Do we auto-arrange?
2671            channelsArrangeAuto();
2672  }  }
2673    
2674    
2675  // Retrieve the active channel strip.  // Retrieve the active channel strip.
2676  ChannelStrip* MainForm::activeChannelStrip (void)  ChannelStrip *MainForm::activeChannelStrip (void)
2677  {  {
2678      return (ChannelStrip*) m_pWorkspace->activeWindow();          QMdiSubWindow *pMdiSubWindow = m_pWorkspace->activeSubWindow();
2679            if (pMdiSubWindow)
2680                    return static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2681            else
2682                    return nullptr;
2683  }  }
2684    
2685    
2686  // Retrieve a channel strip by index.  // Retrieve a channel strip by index.
2687  ChannelStrip* MainForm::channelStripAt ( int iChannel )  ChannelStrip *MainForm::channelStripAt ( int iStrip )
2688  {  {
2689      QWidgetList wlist = m_pWorkspace->windowList();          if (!m_pWorkspace) return nullptr;
     if (wlist.isEmpty())  
         return NULL;  
2690    
2691      return (ChannelStrip*) wlist.at(iChannel);          const QList<QMdiSubWindow *>& wlist
2692                    = m_pWorkspace->subWindowList();
2693            if (wlist.isEmpty())
2694                    return nullptr;
2695    
2696            if (iStrip < 0 || iStrip >= wlist.count())
2697                    return nullptr;
2698    
2699            QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2700            if (pMdiSubWindow)
2701                    return static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2702            else
2703                    return nullptr;
2704  }  }
2705    
2706    
2707  // Retrieve a channel strip by sampler channel id.  // Retrieve a channel strip by sampler channel id.
2708  ChannelStrip* MainForm::channelStrip ( int iChannelID )  ChannelStrip *MainForm::channelStrip ( int iChannelID )
2709  {  {
2710          QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
2711                    = m_pWorkspace->subWindowList();
2712          if (wlist.isEmpty())          if (wlist.isEmpty())
2713                  return NULL;                  return nullptr;
2714    
2715          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          foreach (QMdiSubWindow *pMdiSubWindow, wlist) {
2716                  ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);                  ChannelStrip *pChannelStrip
2717                            = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2718                  if (pChannelStrip) {                  if (pChannelStrip) {
2719                          qsamplerChannel *pChannel = pChannelStrip->channel();                          Channel *pChannel = pChannelStrip->channel();
2720                          if (pChannel && pChannel->channelID() == iChannelID)                          if (pChannel && pChannel->channelID() == iChannelID)
2721                                  return pChannelStrip;                                  return pChannelStrip;
2722                  }                  }
2723          }          }
2724    
2725          // Not found.          // Not found.
2726          return NULL;          return nullptr;
2727  }  }
2728    
2729    
2730  // Construct the windows menu.  // Construct the windows menu.
2731  void MainForm::channelsMenuAboutToShow (void)  void MainForm::channelsMenuAboutToShow (void)
2732  {  {
2733      ui.channelsMenu->clear();          m_ui.channelsMenu->clear();
2734      ui.channelsArrangeAction->addTo(ui.channelsMenu);          m_ui.channelsMenu->addAction(m_ui.channelsArrangeAction);
2735      ui.channelsAutoArrangeAction->addTo(ui.channelsMenu);          m_ui.channelsMenu->addAction(m_ui.channelsAutoArrangeAction);
2736    
2737      QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
2738      if (!wlist.isEmpty()) {                  = m_pWorkspace->subWindowList();
2739          ui.channelsMenu->insertSeparator();          if (!wlist.isEmpty()) {
2740          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {                  m_ui.channelsMenu->addSeparator();
2741              ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);                  int iStrip = 0;
2742              if (pChannelStrip) {                  foreach (QMdiSubWindow *pMdiSubWindow, wlist) {
2743                  int iItemID = ui.channelsMenu->insertItem(pChannelStrip->caption(), this, SLOT(channelsMenuActivated(int)));                          ChannelStrip *pChannelStrip
2744                  ui.channelsMenu->setItemParameter(iItemID, iChannel);                                  = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2745                  ui.channelsMenu->setItemChecked(iItemID, activeChannelStrip() == pChannelStrip);                          if (pChannelStrip) {
2746              }                                  QAction *pAction = m_ui.channelsMenu->addAction(
2747          }                                          pChannelStrip->windowTitle(),
2748      }                                          this, SLOT(channelsMenuActivated()));
2749                                    pAction->setCheckable(true);
2750                                    pAction->setChecked(activeChannelStrip() == pChannelStrip);
2751                                    pAction->setData(iStrip);
2752                            }
2753                            ++iStrip;
2754                    }
2755            }
2756  }  }
2757    
2758    
2759  // Windows menu activation slot  // Windows menu activation slot
2760  void MainForm::channelsMenuActivated ( int iChannel )  void MainForm::channelsMenuActivated (void)
2761  {  {
2762      ChannelStrip* pChannelStrip = channelStripAt(iChannel);          // Retrive channel index from action data...
2763      if (pChannelStrip)          QAction *pAction = qobject_cast<QAction *> (sender());
2764          pChannelStrip->showNormal();          if (pAction == nullptr)
2765      pChannelStrip->setFocus();                  return;
2766    
2767            ChannelStrip *pChannelStrip = channelStripAt(pAction->data().toInt());
2768            if (pChannelStrip) {
2769                    pChannelStrip->showNormal();
2770                    pChannelStrip->setFocus();
2771            }
2772  }  }
2773    
2774    
2775  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2776  // qsamplerMainForm -- Timer stuff.  // QSampler::MainForm -- Timer stuff.
2777    
2778  // Set the pseudo-timer delay schedule.  // Set the pseudo-timer delay schedule.
2779  void MainForm::startSchedule ( int iStartDelay )  void MainForm::startSchedule ( int iStartDelay )
2780  {  {
2781      m_iStartDelay  = 1 + (iStartDelay * 1000);          m_iStartDelay  = 1 + (iStartDelay * 1000);
2782      m_iTimerDelay  = 0;          m_iTimerDelay  = 0;
2783  }  }
2784    
2785  // Suspend the pseudo-timer delay schedule.  // Suspend the pseudo-timer delay schedule.
2786  void MainForm::stopSchedule (void)  void MainForm::stopSchedule (void)
2787  {  {
2788      m_iStartDelay  = 0;          m_iStartDelay  = 0;
2789      m_iTimerDelay  = 0;          m_iTimerDelay  = 0;
2790  }  }
2791    
2792  // Timer slot funtion.  // Timer slot funtion.
2793  void MainForm::timerSlot (void)  void MainForm::timerSlot (void)
2794  {  {
2795      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
2796          return;                  return;
2797    
2798      // Is it the first shot on server start after a few delay?          // Is it the first shot on server start after a few delay?
2799      if (m_iTimerDelay < m_iStartDelay) {          if (m_iTimerDelay < m_iStartDelay) {
2800          m_iTimerDelay += QSAMPLER_TIMER_MSECS;                  m_iTimerDelay += QSAMPLER_TIMER_MSECS;
2801          if (m_iTimerDelay >= m_iStartDelay) {                  if (m_iTimerDelay >= m_iStartDelay) {
2802              // If we cannot start it now, maybe a lil'mo'later ;)                          // If we cannot start it now, maybe a lil'mo'later ;)
2803              if (!startClient()) {                          if (!startClient()) {
2804                  m_iStartDelay += m_iTimerDelay;                                  m_iStartDelay += m_iTimerDelay;
2805                  m_iTimerDelay  = 0;                                  m_iTimerDelay  = 0;
2806              }                          }
2807          }                  }
2808      }          }
2809    
2810          if (m_pClient) {          if (m_pClient) {
2811                  // Update the channel information for each pending strip...                  // Update the channel information for each pending strip...
2812                  if (m_changedStrips.count() > 0) {                  QListIterator<ChannelStrip *> iter(m_changedStrips);
2813                          for (ChannelStrip* pChannelStrip = m_changedStrips.first();                  while (iter.hasNext()) {
2814                                          pChannelStrip; pChannelStrip = m_changedStrips.next()) {                          ChannelStrip *pChannelStrip = iter.next();
2815                                  // If successfull, remove from pending list...                          // If successfull, remove from pending list...
2816                                  if (pChannelStrip->updateChannelInfo())                          if (pChannelStrip->updateChannelInfo()) {
2817                                          m_changedStrips.remove(pChannelStrip);                                  const int iChannelStrip = m_changedStrips.indexOf(pChannelStrip);
2818                                    if (iChannelStrip >= 0)
2819                                            m_changedStrips.removeAt(iChannelStrip);
2820                          }                          }
2821                  }                  }
2822                  // Refresh each channel usage, on each period...                  // Refresh each channel usage, on each period...
# Line 2327  void MainForm::timerSlot (void) Line 2825  void MainForm::timerSlot (void)
2825                          if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime)  {                          if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime)  {
2826                                  m_iTimerSlot = 0;                                  m_iTimerSlot = 0;
2827                                  // Update the channel stream usage for each strip...                                  // Update the channel stream usage for each strip...
2828                                  QWidgetList wlist = m_pWorkspace->windowList();                                  const QList<QMdiSubWindow *>& wlist
2829                                  for (int iChannel = 0;                                          = m_pWorkspace->subWindowList();
2830                                                  iChannel < (int) wlist.count(); iChannel++) {                                  foreach (QMdiSubWindow *pMdiSubWindow, wlist) {
2831                                          ChannelStrip* pChannelStrip                                          ChannelStrip *pChannelStrip
2832                                                  = (ChannelStrip*) wlist.at(iChannel);                                                  = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2833                                          if (pChannelStrip && pChannelStrip->isVisible())                                          if (pChannelStrip && pChannelStrip->isVisible())
2834                                                  pChannelStrip->updateChannelUsage();                                                  pChannelStrip->updateChannelUsage();
2835                                  }                                  }
2836                          }                          }
2837                  }                  }
2838    
2839            #if CONFIG_LSCP_CLIENT_CONNECTION_LOST
2840                    // If we lost connection to server: Try to automatically reconnect if we
2841                    // did not start the server.
2842                    //
2843                    // TODO: If we started the server, then we might inform the user that
2844                    // the server probably crashed and asking user ONCE whether we should
2845                    // restart the server.
2846                    if (lscp_client_connection_lost(m_pClient) && !m_pServer)
2847                            startAutoReconnectClient();
2848            #endif // CONFIG_LSCP_CLIENT_CONNECTION_LOST
2849          }          }
2850    
2851      // Register the next timer slot.          // Register the next timer slot.
2852      QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));          QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
2853  }  }
2854    
2855    
2856  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2857  // qsamplerMainForm -- Server stuff.  // QSampler::MainForm -- Server stuff.
2858    
2859  // Start linuxsampler server...  // Start linuxsampler server...
2860  void MainForm::startServer (void)  void MainForm::startServer (void)
2861  {  {
2862      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
2863          return;                  return;
2864    
2865      // Aren't already a client, are we?          // Aren't already a client, are we?
2866      if (!m_pOptions->bServerStart || m_pClient)          if (!m_pOptions->bServerStart || m_pClient)
2867          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(readyReadStdout()),  
                         SLOT(readServerStdout()));  
                 QObject::connect(m_pServer,  
                         SIGNAL(readyReadStderr()),  
                         SLOT(readServerStdout()));  
         //      }  
         // The unforgiveable signal communication...  
         QObject::connect(m_pServer,  
                 SIGNAL(processExited()),  
                 SLOT(processServerExit()));  
2868    
2869      // Build process arguments...          // Is the server process instance still here?
2870      QStringList serverCmdLine = QStringList::split(' ', m_pOptions->sServerCmdLine);          if (m_pServer) {
2871                    if (QMessageBox::warning(this,
2872                            tr("Warning"),
2873                            tr("Could not start the LinuxSampler server.\n\n"
2874                            "Maybe it is already started."),
2875                            QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) {
2876                            m_pServer->terminate();
2877                            m_pServer->kill();
2878                    }
2879                    return;
2880            }
2881    
2882      appendMessages(tr("Server is starting..."));          // Reset our timer counters...
2883      appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");          stopSchedule();
2884    
2885            // Verify we have something to start with...
2886            if (m_pOptions->sServerCmdLine.isEmpty())
2887                    return;
2888    
2889            // OK. Let's build the startup process...
2890            m_pServer = new QProcess();
2891            m_bForceServerStop = true;
2892    
2893      const QString prog = (serverCmdLine.size() > 0) ? serverCmdLine[0] : QString();          // Setup stdout/stderr capture...
2894      const QStringList args = serverCmdLine.mid(1);          m_pServer->setProcessChannelMode(QProcess::ForwardedChannels);
2895            QObject::connect(m_pServer,
2896                    SIGNAL(readyReadStandardOutput()),
2897                    SLOT(readServerStdout()));
2898            QObject::connect(m_pServer,
2899                    SIGNAL(readyReadStandardError()),
2900                    SLOT(readServerStdout()));
2901    
2902      // Go jack, go...          // The unforgiveable signal communication...
2903      m_pServer->start(prog, args);          QObject::connect(m_pServer,
2904      if (!m_pServer->waitForStarted()) {                  SIGNAL(finished(int, QProcess::ExitStatus)),
2905          appendMessagesError(tr("Could not start server.\n\nSorry."));                  SLOT(processServerExit()));
         processServerExit();  
         return;  
     }  
2906    
2907      // Show startup results...          // Build process arguments...
2908      appendMessages(tr("Server was started with PID=%1.").arg((long) m_pServer->pid()));          QStringList args = m_pOptions->sServerCmdLine.split(' ');
2909            QString sCommand = args[0];
2910            args.removeAt(0);
2911    
2912            appendMessages(tr("Server is starting..."));
2913            appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");
2914    
2915            // Go linuxsampler, go...
2916            m_pServer->start(sCommand, args);
2917            if (!m_pServer->waitForStarted()) {
2918                    appendMessagesError(tr("Could not start server.\n\nSorry."));
2919                    processServerExit();
2920                    return;
2921            }
2922    
2923      // Reset (yet again) the timer counters,          // Show startup results...
2924      // but this time is deferred as the user opted.          appendMessages(
2925      startSchedule(m_pOptions->iStartDelay);                  tr("Server was started with PID=%1.")
2926      stabilizeForm();                  #if QT_VERSION < QT_VERSION_CHECK(5, 3, 0)
2927                            .arg(quint64(m_pServer->pid())));
2928                    #else
2929                            .arg(quint64(m_pServer->processId())));
2930                    #endif
2931    
2932            // Reset (yet again) the timer counters,
2933            // but this time is deferred as the user opted.
2934            startSchedule(m_pOptions->iStartDelay);
2935            stabilizeForm();
2936  }  }
2937    
2938    
2939  // Stop linuxsampler server...  // Stop linuxsampler server...
2940  void MainForm::stopServer (void)  void MainForm::stopServer ( bool bInteractive )
2941  {  {
2942      // Stop client code.          // Stop client code.
2943      stopClient();          stopClient();
2944    
2945            if (m_pServer && bInteractive) {
2946                    if (QMessageBox::question(this,
2947                            tr("The backend's fate ..."),
2948                            tr("You have the option to keep the sampler backend (LinuxSampler)\n"
2949                            "running in the background. The sampler would continue to work\n"
2950                            "according to your current sampler session and you could alter the\n"
2951                            "sampler session at any time by relaunching QSampler.\n\n"
2952                            "Do you want LinuxSampler to stop?"),
2953                            QMessageBox::Yes | QMessageBox::No,
2954                            QMessageBox::Yes) == QMessageBox::No) {
2955                            m_bForceServerStop = false;
2956                    }
2957            }
2958    
2959      // And try to stop server.          bool bGraceWait = true;
2960      if (m_pServer) {  
2961          appendMessages(tr("Server is stopping..."));          // And try to stop server.
2962          if (m_pServer->state() == QProcess::Running)          if (m_pServer && m_bForceServerStop) {
2963              m_pServer->terminate();                  appendMessages(tr("Server is stopping..."));
2964       }                  if (m_pServer->state() == QProcess::Running) {
2965                    #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
2966      // Give it some time to terminate gracefully and stabilize...                          // Try harder...
2967      QTime t;                          m_pServer->kill();
2968      t.start();                  #else
2969      while (t.elapsed() < QSAMPLER_TIMER_MSECS)                          // Try softly...
2970          QApplication::processEvents(QEventLoop::ExcludeUserInput);                          m_pServer->terminate();
2971                            bool bFinished = m_pServer->waitForFinished(QSAMPLER_TIMER_MSECS * 1000);
2972                            if (bFinished) bGraceWait = false;
2973                    #endif
2974                    }
2975            }       // Do final processing anyway.
2976            else processServerExit();
2977    
2978       // Do final processing anyway.          // Give it some time to terminate gracefully and stabilize...
2979       processServerExit();          if (bGraceWait) {
2980                    QElapsedTimer timer;
2981                    timer.start();
2982                    while (timer.elapsed() < QSAMPLER_TIMER_MSECS)
2983                            QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2984            }
2985  }  }
2986    
2987    
2988  // Stdout handler...  // Stdout handler...
2989  void MainForm::readServerStdout (void)  void MainForm::readServerStdout (void)
2990  {  {
2991      if (m_pMessages)          if (m_pMessages)
2992          m_pMessages->appendStdoutBuffer(m_pServer->readAllStandardOutput());                  m_pMessages->appendStdoutBuffer(m_pServer->readAllStandardOutput());
2993  }  }
2994    
2995    
2996  // Linuxsampler server cleanup.  // Linuxsampler server cleanup.
2997  void MainForm::processServerExit (void)  void MainForm::processServerExit (void)
2998  {  {
2999      // Force client code cleanup.          // Force client code cleanup.
3000      stopClient();          stopClient();
3001    
3002      // Flush anything that maybe pending...          // Flush anything that maybe pending...
3003      if (m_pMessages)          if (m_pMessages)
3004          m_pMessages->flushStdoutBuffer();                  m_pMessages->flushStdoutBuffer();
3005    
3006      if (m_pServer) {          if (m_pServer && m_bForceServerStop) {
3007          // Force final server shutdown...                  if (m_pServer->state() != QProcess::NotRunning) {
3008          appendMessages(tr("Server was stopped with exit status %1.").arg(m_pServer->exitStatus()));                          appendMessages(tr("Server is being forced..."));
3009          m_pServer->terminate();                          // Force final server shutdown...
3010          if (!m_pServer->waitForFinished(2000))                          m_pServer->kill();
3011              m_pServer->kill();                          // Give it some time to terminate gracefully and stabilize...
3012          // Destroy it.                          QElapsedTimer timer;
3013          delete m_pServer;                          timer.start();
3014          m_pServer = NULL;                          while (timer.elapsed() < QSAMPLER_TIMER_MSECS)
3015      }                                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
3016                    }
3017                    // Force final server shutdown...
3018                    appendMessages(
3019                            tr("Server was stopped with exit status %1.")
3020                            .arg(m_pServer->exitStatus()));
3021                    delete m_pServer;
3022                    m_pServer = nullptr;
3023            }
3024    
3025      // Again, make status visible stable.          // Again, make status visible stable.
3026      stabilizeForm();          stabilizeForm();
3027  }  }
3028    
3029    
3030  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
3031  // qsamplerMainForm -- Client stuff.  // QSampler::MainForm -- Client stuff.
3032    
3033  // The LSCP client callback procedure.  // The LSCP client callback procedure.
3034  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*/,
3035            lscp_event_t event, const char *pchData, int cchData, void *pvData )
3036  {  {
3037      MainForm* pMainForm = (MainForm *) pvData;          MainForm* pMainForm = (MainForm *) pvData;
3038      if (pMainForm == NULL)          if (pMainForm == nullptr)
3039          return LSCP_FAILED;                  return LSCP_FAILED;
3040    
3041      // ATTN: DO NOT EVER call any GUI code here,          // ATTN: DO NOT EVER call any GUI code here,
3042      // as this is run under some other thread context.          // as this is run under some other thread context.
3043      // A custom event must be posted here...          // A custom event must be posted here...
3044      QApplication::postEvent(pMainForm, new qsamplerCustomEvent(event, pchData, cchData));          QApplication::postEvent(pMainForm,
3045                    new LscpEvent(event, pchData, cchData));
3046    
3047      return LSCP_OK;          return LSCP_OK;
3048  }  }
3049    
3050    
3051  // Start our almighty client...  // Start our almighty client...
3052  bool MainForm::startClient (void)  bool MainForm::startClient (bool bReconnectOnly)
3053  {  {
3054      // Have it a setup?          // Have it a setup?
3055      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
3056          return false;                  return false;
3057    
3058      // Aren't we already started, are we?          // Aren't we already started, are we?
3059      if (m_pClient)          if (m_pClient)
3060          return true;                  return true;
3061    
3062      // Log prepare here.          // Log prepare here.
3063      appendMessages(tr("Client connecting..."));          appendMessages(tr("Client connecting..."));
3064    
3065      // Create the client handle...          // Create the client handle...
3066      m_pClient = ::lscp_client_create(m_pOptions->sServerHost.latin1(), m_pOptions->iServerPort, qsampler_client_callback, this);          m_pClient = ::lscp_client_create(
3067      if (m_pClient == NULL) {                  m_pOptions->sServerHost.toUtf8().constData(),
3068          // Is this the first try?                  m_pOptions->iServerPort, qsampler_client_callback, this);
3069          // maybe we need to start a local server...          if (m_pClient == nullptr) {
3070          if ((m_pServer && m_pServer->state() == QProcess::Running) || !m_pOptions->bServerStart)                  // Is this the first try?
3071              appendMessagesError(tr("Could not connect to server as client.\n\nSorry."));                  // maybe we need to start a local server...
3072          else                  if ((m_pServer && m_pServer->state() == QProcess::Running)
3073              startServer();                          || !m_pOptions->bServerStart || bReconnectOnly)
3074          // This is always a failure.                  {
3075          stabilizeForm();                          // if this method is called from autoReconnectClient()
3076          return false;                          // then don't bother user with an error message...
3077      }                          if (!bReconnectOnly) {
3078      // Just set receive timeout value, blindly.                                  appendMessagesError(
3079      ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);                                          tr("Could not connect to server as client.\n\nSorry.")
3080      appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));                                  );
3081                            }
3082                    } else {
3083                            startServer();
3084                    }
3085                    // This is always a failure.
3086                    stabilizeForm();
3087                    return false;
3088            }
3089    
3090            // Just set receive timeout value, blindly.
3091            ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);
3092            appendMessages(
3093                    tr("Client receive timeout is set to %1 msec.")
3094                    .arg(::lscp_client_get_timeout(m_pClient)));
3095    
3096          // Subscribe to channel info change notifications...          // Subscribe to channel info change notifications...
3097            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_COUNT) != LSCP_OK)
3098                    appendMessagesClient("lscp_client_subscribe(CHANNEL_COUNT)");
3099          if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO) != LSCP_OK)          if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO) != LSCP_OK)
3100                  appendMessagesClient("lscp_client_subscribe");                  appendMessagesClient("lscp_client_subscribe(CHANNEL_INFO)");
3101    
3102            DeviceStatusForm::onDevicesChanged(); // initialize
3103            updateViewMidiDeviceStatusMenu();
3104            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT) != LSCP_OK)
3105                    appendMessagesClient("lscp_client_subscribe(MIDI_INPUT_DEVICE_COUNT)");
3106            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_INFO) != LSCP_OK)
3107                    appendMessagesClient("lscp_client_subscribe(MIDI_INPUT_DEVICE_INFO)");
3108            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT) != LSCP_OK)
3109                    appendMessagesClient("lscp_client_subscribe(AUDIO_OUTPUT_DEVICE_COUNT)");
3110            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO) != LSCP_OK)
3111                    appendMessagesClient("lscp_client_subscribe(AUDIO_OUTPUT_DEVICE_INFO)");
3112    
3113    #if CONFIG_EVENT_CHANNEL_MIDI
3114            // Subscribe to channel MIDI data notifications...
3115            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_MIDI) != LSCP_OK)
3116                    appendMessagesClient("lscp_client_subscribe(CHANNEL_MIDI)");
3117    #endif
3118    
3119    #if CONFIG_EVENT_DEVICE_MIDI
3120            // Subscribe to channel MIDI data notifications...
3121            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_DEVICE_MIDI) != LSCP_OK)
3122                    appendMessagesClient("lscp_client_subscribe(DEVICE_MIDI)");
3123    #endif
3124    
3125      // We may stop scheduling around.          // We may stop scheduling around.
3126      stopSchedule();          stopSchedule();
3127    
3128      // We'll accept drops from now on...          // We'll accept drops from now on...
3129      setAcceptDrops(true);          setAcceptDrops(true);
3130    
3131      // Log success here.          // Log success here.
3132      appendMessages(tr("Client connected."));          appendMessages(tr("Client connected."));
3133    
3134          // Hard-notify instrumnet and device configuration forms,          // Hard-notify instrumnet and device configuration forms,
3135          // if visible, that we're ready...          // if visible, that we're ready...
3136          if (m_pInstrumentListForm)          if (m_pInstrumentListForm)
3137              m_pInstrumentListForm->refreshInstruments();                  m_pInstrumentListForm->refreshInstruments();
3138          if (m_pDeviceForm)          if (m_pDeviceForm)
3139              m_pDeviceForm->refreshDevices();                  m_pDeviceForm->refreshDevices();
3140    
3141            // Is any session pending to be loaded?
3142            if (!m_pOptions->sSessionFile.isEmpty()) {
3143                    // Just load the prabably startup session...
3144                    if (loadSessionFile(m_pOptions->sSessionFile)) {
3145                            m_pOptions->sSessionFile = QString();
3146                            return true;
3147                    }
3148            }
3149    
3150      // Is any session pending to be loaded?          // send the current / loaded fine tuning settings to the sampler
3151      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;  
         }  
     }  
3152    
3153      // Make a new session          // Make a new session
3154      return newSession();          return newSession();
3155  }  }
3156    
3157    
3158  // Stop client...  // Stop client...
3159  void MainForm::stopClient (void)  void MainForm::stopClient (void)
3160  {  {
3161      if (m_pClient == NULL)          if (m_pClient == nullptr)
3162          return;                  return;
   
     // Log prepare here.  
     appendMessages(tr("Client disconnecting..."));  
3163    
3164      // Clear timer counters...          // Log prepare here.
3165      stopSchedule();          appendMessages(tr("Client disconnecting..."));
3166    
3167      // We'll reject drops from now on...          // Clear timer counters...
3168      setAcceptDrops(false);          stopSchedule();
3169    
3170      // Force any channel strips around, but          // We'll reject drops from now on...
3171      // but avoid removing the corresponding          setAcceptDrops(false);
     // channels from the back-end server.  
     m_iDirtyCount = 0;  
     closeSession(false);  
3172    
3173      // Close us as a client...          // Force any channel strips around, but
3174            // but avoid removing the corresponding
3175            // channels from the back-end server.
3176            m_iDirtyCount = 0;
3177            closeSession(false);
3178    
3179            // Close us as a client...
3180    #if CONFIG_EVENT_DEVICE_MIDI
3181            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_DEVICE_MIDI);
3182    #endif
3183    #if CONFIG_EVENT_CHANNEL_MIDI
3184            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_MIDI);
3185    #endif
3186            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO);
3187            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT);
3188            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_INFO);
3189            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT);
3190          ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO);          ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO);
3191      ::lscp_client_destroy(m_pClient);          ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_COUNT);
3192      m_pClient = NULL;          ::lscp_client_destroy(m_pClient);
3193            m_pClient = nullptr;
3194    
3195          // Hard-notify instrumnet and device configuration forms,          // Hard-notify instrumnet and device configuration forms,
3196          // if visible, that we're running out...          // if visible, that we're running out...
3197          if (m_pInstrumentListForm)          if (m_pInstrumentListForm)
3198              m_pInstrumentListForm->refreshInstruments();                  m_pInstrumentListForm->refreshInstruments();
3199          if (m_pDeviceForm)          if (m_pDeviceForm)
3200              m_pDeviceForm->refreshDevices();                  m_pDeviceForm->refreshDevices();
3201    
3202            // Log final here.
3203            appendMessages(tr("Client disconnected."));
3204    
3205            // Make visible status.
3206            stabilizeForm();
3207    }
3208    
     // Log final here.  
     appendMessages(tr("Client disconnected."));  
3209    
3210      // Make visible status.  void MainForm::startAutoReconnectClient (void)
3211      stabilizeForm();  {
3212            stopClient();
3213            appendMessages(tr("Trying to reconnect..."));
3214            QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(autoReconnectClient()));
3215  }  }
3216    
3217    
3218    void MainForm::autoReconnectClient (void)
3219    {
3220            const bool bSuccess = startClient(true);
3221            if (!bSuccess)
3222                    QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(autoReconnectClient()));
3223    }
3224    
3225    
3226    // Channel strip activation/selection.
3227    void MainForm::activateStrip ( QMdiSubWindow *pMdiSubWindow )
3228    {
3229            ChannelStrip *pChannelStrip = nullptr;
3230            if (pMdiSubWindow)
3231                    pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
3232            if (pChannelStrip)
3233                    pChannelStrip->setSelected(true);
3234    
3235            stabilizeForm();
3236    }
3237    
3238    
3239    // Channel toolbar orientation change.
3240    void MainForm::channelsToolbarOrientation ( Qt::Orientation orientation )
3241    {
3242    #ifdef CONFIG_VOLUME
3243            m_pVolumeSlider->setOrientation(orientation);
3244            if (orientation == Qt::Horizontal) {
3245                    m_pVolumeSlider->setMinimumHeight(24);
3246                    m_pVolumeSlider->setMaximumHeight(32);
3247                    m_pVolumeSlider->setMinimumWidth(120);
3248                    m_pVolumeSlider->setMaximumWidth(640);
3249                    m_pVolumeSpinBox->setMaximumWidth(64);
3250                    m_pVolumeSpinBox->setButtonSymbols(QSpinBox::UpDownArrows);
3251            } else {
3252                    m_pVolumeSlider->setMinimumHeight(120);
3253                    m_pVolumeSlider->setMaximumHeight(480);
3254                    m_pVolumeSlider->setMinimumWidth(24);
3255                    m_pVolumeSlider->setMaximumWidth(32);
3256                    m_pVolumeSpinBox->setMaximumWidth(32);
3257                    m_pVolumeSpinBox->setButtonSymbols(QSpinBox::NoButtons);
3258            }
3259    #endif
3260    }
3261    
3262    
3263  } // namespace QSampler  } // namespace QSampler
3264    
3265    

Legend:
Removed from v.1466  
changed lines
  Added in v.3837

  ViewVC Help
Powered by ViewVC