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

Legend:
Removed from v.1474  
changed lines
  Added in v.3760

  ViewVC Help
Powered by ViewVC