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

Legend:
Removed from v.1470  
changed lines
  Added in v.3761

  ViewVC Help
Powered by ViewVC