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

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

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

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

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

  ViewVC Help
Powered by ViewVC