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

Legend:
Removed from v.1475  
changed lines
  Added in v.3681

  ViewVC Help
Powered by ViewVC