/[svn]/qsampler/trunk/src/qsamplerMainForm.cpp
ViewVC logotype

Diff of /qsampler/trunk/src/qsamplerMainForm.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

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

  ViewVC Help
Powered by ViewVC