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

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

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

revision 1474 by schoenebeck, Mon Nov 5 20:47:38 2007 UTC revision 3518 by capela, Sun Jun 30 16:58:30 2019 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-2019, rncbc aka Rui Nuno Capela. All rights reserved.
5     Copyright (C) 2007, Christian Schoenebeck     Copyright (C) 2007,2008,2015 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 >= 0x050000
62    #include <QMimeData>
63    #endif
64    
65    #if QT_VERSION < 0x040500
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 = NULL;
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 = NULL;
217    
218      // All child forms are to be created later, not earlier than setup.          // All child forms are to be created later, not earlier than setup.
219      m_pMessages = NULL;          m_pMessages = NULL;
220      m_pInstrumentListForm = NULL;          m_pInstrumentListForm = NULL;
221      m_pDeviceForm = NULL;          m_pDeviceForm = NULL;
222    
223      // We'll start clean.          // We'll start clean.
224      m_iUntitled   = 0;          m_iUntitled   = 0;
225      m_iDirtyCount = 0;          m_iDirtySetup = 0;
226            m_iDirtyCount = 0;
227    
228      m_pServer = NULL;          m_pServer = NULL;
229      m_pClient = NULL;          m_pClient = NULL;
230    
231      m_iStartDelay = 0;          m_iStartDelay = 0;
232      m_iTimerDelay = 0;          m_iTimerDelay = 0;
233    
234      m_iTimerSlot = 0;          m_iTimerSlot = 0;
235    
236    #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, NULL);
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, NULL);
276            ::sigaction(SIGQUIT, &sigterm, NULL);
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 = NULL;
285            m_pSigtermNotifier = NULL;
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...
334            QLabel *pLabel;
335            // Client status.
336            pLabel = new QLabel(tr("Connected"), this);
337            pLabel->setAlignment(Qt::AlignLeft);
338            pLabel->setMinimumSize(pLabel->sizeHint());
339            m_statusItem[QSAMPLER_STATUS_CLIENT] = pLabel;
340            statusBar()->addWidget(pLabel);
341            // Server address.
342            pLabel = new QLabel(this);
343            pLabel->setAlignment(Qt::AlignLeft);
344            m_statusItem[QSAMPLER_STATUS_SERVER] = pLabel;
345            statusBar()->addWidget(pLabel, 1);
346            // Channel title.
347            pLabel = new QLabel(this);
348            pLabel->setAlignment(Qt::AlignLeft);
349            m_statusItem[QSAMPLER_STATUS_CHANNEL] = pLabel;
350            statusBar()->addWidget(pLabel, 2);
351            // Session modification status.
352            pLabel = new QLabel(tr("MOD"), this);
353            pLabel->setAlignment(Qt::AlignHCenter);
354            pLabel->setMinimumSize(pLabel->sizeHint());
355            m_statusItem[QSAMPLER_STATUS_SESSION] = pLabel;
356            statusBar()->addWidget(pLabel);
357    
358    #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
359            WSAStartup(MAKEWORD(1, 1), &_wsaData);
360    #endif
361    
362            // Some actions surely need those
363            // shortcuts firmly attached...
364            addAction(m_ui.viewMenubarAction);
365            addAction(m_ui.viewToolbarAction);
366    
367      // Create some statusbar labels...          QObject::connect(m_ui.fileNewAction,
368      QLabel *pLabel;                  SIGNAL(triggered()),
     // Client status.  
     pLabel = new QLabel(tr("Connected"), this);  
     pLabel->setAlignment(Qt::AlignLeft);  
     pLabel->setMinimumSize(pLabel->sizeHint());  
     m_statusItem[QSAMPLER_STATUS_CLIENT] = pLabel;  
     statusBar()->addWidget(pLabel);  
     // Server address.  
     pLabel = new QLabel(this);  
     pLabel->setAlignment(Qt::AlignLeft);  
     m_statusItem[QSAMPLER_STATUS_SERVER] = pLabel;  
     statusBar()->addWidget(pLabel, 1);  
     // Channel title.  
     pLabel = new QLabel(this);  
     pLabel->setAlignment(Qt::AlignLeft);  
     m_statusItem[QSAMPLER_STATUS_CHANNEL] = pLabel;  
     statusBar()->addWidget(pLabel, 2);  
     // Session modification status.  
     pLabel = new QLabel(tr("MOD"), this);  
     pLabel->setAlignment(Qt::AlignHCenter);  
     pLabel->setMinimumSize(pLabel->sizeHint());  
     m_statusItem[QSAMPLER_STATUS_SESSION] = pLabel;  
     statusBar()->addWidget(pLabel);  
   
     // Create the recent files sub-menu.  
     m_pRecentFilesMenu = new Q3PopupMenu(this);  
     ui.fileMenu->insertSeparator(4);  
     ui.fileMenu->insertItem(tr("Recent &Files"), m_pRecentFilesMenu, 0, 5);  
   
 #if defined(WIN32)  
     WSAStartup(MAKEWORD(1, 1), &_wsaData);  
 #endif  
   
         QObject::connect(ui.fileNewAction,  
                 SIGNAL(activated()),  
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)  #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
460      WSACleanup();          WSACleanup();
461  #endif  #endif
462    
463      // Finally drop any widgets around...  #if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H)
464      if (m_pDeviceForm)          if (m_pSigusr1Notifier)
465          delete m_pDeviceForm;                  delete m_pSigusr1Notifier;
466      if (m_pInstrumentListForm)          if (m_pSigtermNotifier)
467          delete m_pInstrumentListForm;                  delete m_pSigtermNotifier;
468      if (m_pMessages)  #endif
469          delete m_pMessages;  
470      if (m_pWorkspace)          // Finally drop any widgets around...
471          delete m_pWorkspace;          if (m_pDeviceForm)
472                    delete m_pDeviceForm;
473      // Delete status item labels one by one.          if (m_pInstrumentListForm)
474      if (m_statusItem[QSAMPLER_STATUS_CLIENT])                  delete m_pInstrumentListForm;
475          delete m_statusItem[QSAMPLER_STATUS_CLIENT];          if (m_pMessages)
476      if (m_statusItem[QSAMPLER_STATUS_SERVER])                  delete m_pMessages;
477          delete m_statusItem[QSAMPLER_STATUS_SERVER];          if (m_pWorkspace)
478      if (m_statusItem[QSAMPLER_STATUS_CHANNEL])                  delete m_pWorkspace;
479          delete m_statusItem[QSAMPLER_STATUS_CHANNEL];  
480      if (m_statusItem[QSAMPLER_STATUS_SESSION])          // Delete status item labels one by one.
481          delete m_statusItem[QSAMPLER_STATUS_SESSION];          if (m_statusItem[QSAMPLER_STATUS_CLIENT])
482                    delete m_statusItem[QSAMPLER_STATUS_CLIENT];
483            if (m_statusItem[QSAMPLER_STATUS_SERVER])
484                    delete m_statusItem[QSAMPLER_STATUS_SERVER];
485            if (m_statusItem[QSAMPLER_STATUS_CHANNEL])
486                    delete m_statusItem[QSAMPLER_STATUS_CHANNEL];
487            if (m_statusItem[QSAMPLER_STATUS_SESSION])
488                    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 = NULL;
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.          }
     m_pOptions->loadWidgetGeometry(this);  
     m_pOptions->loadWidgetGeometry(m_pInstrumentListForm);  
     m_pOptions->loadWidgetGeometry(m_pDeviceForm);  
   
     // Final startup stabilization...  
     updateMaxVolume();  
     updateRecentFilesMenu();  
     stabilizeForm();  
559    
560      // Make it ready :-)          // Try to restore old window positioning and initial visibility.
561      statusBar()->message(tr("Ready"), 3000);          m_pOptions->loadWidgetGeometry(this, true);
562            m_pOptions->loadWidgetGeometry(m_pInstrumentListForm);
563            m_pOptions->loadWidgetGeometry(m_pDeviceForm);
564    
565            // Final startup stabilization...
566            updateMaxVolume();
567            updateRecentFilesMenu();
568            stabilizeForm();
569    
570      // We'll try to start immediately...          // Make it ready :-)
571      startSchedule(0);          statusBar()->showMessage(tr("Ready"), 3000);
572    
573      // Register the first timer slot.          // We'll try to start immediately...
574      QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));          startSchedule(0);
575    
576            // Register the first timer slot.
577            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() == NULL
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 == NULL)
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 == NULL)
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.                  QSAMPLER_TITLE ": " + 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 == NULL)
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.                          QSAMPLER_TITLE ": " + 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"),                                  QSAMPLER_TITLE ": " + 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?          // Are we dirty enough to prompt it?
942      if (m_iDirtyCount > 0) {          if (m_iDirtyCount > 0) {
943          switch (QMessageBox::warning(this,                  switch (QMessageBox::warning(this,
944                          QSAMPLER_TITLE ": " + tr("Warning"),                          QSAMPLER_TITLE ": " + tr("Warning"),
945              tr("The current session has been changed:\n\n"                          tr("The current session has been changed:\n\n"
946              "\"%1\"\n\n"                          "\"%1\"\n\n"
947              "Do you want to save the changes?")                          "Do you want to save the changes?")
948              .arg(sessionName(m_sFilename)),                          .arg(sessionName(m_sFilename)),
949              tr("Save"), tr("Discard"), tr("Cancel"))) {                          QMessageBox::Save |
950          case 0:     // Save...                          QMessageBox::Discard |
951              bClose = saveSession(false);                          QMessageBox::Cancel)) {
952              // Fall thru....                  case QMessageBox::Save:
953          case 1:     // Discard                          bClose = saveSession(false);
954              break;                          // Fall thru....
955          default:    // Cancel.                  case QMessageBox::Discard:
956              bClose = false;                          break;
957              break;                  default:    // Cancel.
958          }                          bClose = false;
959      }                          break;
960                    }
961      // 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;  
     }  
962    
963      return bClose;          // If we may close it, dot it.
964            if (bClose) {
965                    // Remove all channel strips from sight...
966                    m_pWorkspace->setUpdatesEnabled(false);
967                    const QList<QMdiSubWindow *>& wlist
968                            = m_pWorkspace->subWindowList();
969                    const int iStripCount = wlist.count();
970                    for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
971                            ChannelStrip *pChannelStrip = NULL;
972                            QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
973                            if (pMdiSubWindow)
974                                    pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
975                            if (pChannelStrip) {
976                                    Channel *pChannel = pChannelStrip->channel();
977                                    if (bForce && pChannel)
978                                            pChannel->removeChannel();
979                                    delete pChannelStrip;
980                            }
981                            if (pMdiSubWindow)
982                                    delete pMdiSubWindow;
983                    }
984                    m_pWorkspace->setUpdatesEnabled(true);
985                    // We're now clean, for sure.
986                    m_iDirtyCount = 0;
987            }
988    
989            return bClose;
990  }  }
991    
992    
993  // Load a session from specific file path.  // Load a session from specific file path.
994  bool MainForm::loadSessionFile ( const QString& sFilename )  bool MainForm::loadSessionFile ( const QString& sFilename )
995  {  {
996      if (m_pClient == NULL)          if (m_pClient == NULL)
997          return false;                  return false;
998    
999      // Open and read from real file.          // Open and read from real file.
1000      QFile file(sFilename);          QFile file(sFilename);
1001      if (!file.open(IO_ReadOnly)) {          if (!file.open(QIODevice::ReadOnly)) {
1002          appendMessagesError(tr("Could not open \"%1\" session file.\n\nSorry.").arg(sFilename));                  appendMessagesError(
1003          return false;                          tr("Could not open \"%1\" session file.\n\nSorry.")
1004      }                          .arg(sFilename));
1005                    return false;
1006            }
1007    
1008          // Tell the world we'll take some time...          // Tell the world we'll take some time...
1009          QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));          QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1010    
1011      // Read the file.          // Read the file.
1012          int iLine = 0;          int iLine = 0;
1013      int iErrors = 0;          int iErrors = 0;
1014      QTextStream ts(&file);          QTextStream ts(&file);
1015      while (!ts.atEnd()) {          while (!ts.atEnd()) {
1016          // Read the line.                  // Read the line.
1017          QString sCommand = ts.readLine().stripWhiteSpace();                  QString sCommand = ts.readLine().trimmed();
1018                  iLine++;                  iLine++;
1019          // If not empty, nor a comment, call the server...                  // If not empty, nor a comment, call the server...
1020          if (!sCommand.isEmpty() && sCommand[0] != '#') {                  if (!sCommand.isEmpty() && sCommand[0] != '#') {
1021                          // Remember that, no matter what,                          // Remember that, no matter what,
1022                          // all LSCP commands are CR/LF terminated.                          // all LSCP commands are CR/LF terminated.
1023                          sCommand += "\r\n";                          sCommand += "\r\n";
1024                          if (::lscp_client_query(m_pClient, sCommand.latin1()) != LSCP_OK) {                          if (::lscp_client_query(m_pClient, sCommand.toUtf8().constData())
1025                                    != LSCP_OK) {
1026                                  appendMessagesColor(QString("%1(%2): %3")                                  appendMessagesColor(QString("%1(%2): %3")
1027                                          .arg(QFileInfo(sFilename).fileName()).arg(iLine)                                          .arg(QFileInfo(sFilename).fileName()).arg(iLine)
1028                                          .arg(sCommand.simplifyWhiteSpace()), "#996633");                                          .arg(sCommand.simplified()), "#996633");
1029                                  appendMessagesClient("lscp_client_query");                                  appendMessagesClient("lscp_client_query");
1030                                  iErrors++;                                  iErrors++;
1031                          }                          }
1032          }                  }
1033          // Try to make it snappy :)                  // Try to make it snappy :)
1034          QApplication::processEvents(QEventLoop::ExcludeUserInput);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1035      }          }
1036    
1037      // Ok. we've read it.          // Ok. we've read it.
1038      file.close();          file.close();
1039    
1040          // Now we'll try to create (update) the whole GUI session.          // Now we'll try to create (update) the whole GUI session.
1041          updateSession();          updateSession();
# Line 800  bool MainForm::loadSessionFile ( const Q Line 1044  bool MainForm::loadSessionFile ( const Q
1044          QApplication::restoreOverrideCursor();          QApplication::restoreOverrideCursor();
1045    
1046          // Have we any errors?          // Have we any errors?
1047          if (iErrors > 0)          if (iErrors > 0) {
1048                  appendMessagesError(tr("Session loaded with errors\nfrom \"%1\".\n\nSorry.").arg(sFilename));                  appendMessagesError(
1049                            tr("Session loaded with errors\nfrom \"%1\".\n\nSorry.")
1050                            .arg(sFilename));
1051            }
1052    
1053      // Save as default session directory.          // Save as default session directory.
1054      if (m_pOptions)          if (m_pOptions)
1055          m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);                  m_pOptions->sSessionDir = QFileInfo(sFilename).dir().absolutePath();
1056          // We're not dirty anymore, if loaded without errors,          // We're not dirty anymore, if loaded without errors,
1057          m_iDirtyCount = iErrors;          m_iDirtyCount = iErrors;
1058      // Stabilize form...          // Stabilize form...
1059      m_sFilename = sFilename;          m_sFilename = sFilename;
1060      updateRecentFiles(sFilename);          updateRecentFiles(sFilename);
1061      appendMessages(tr("Open session: \"%1\".").arg(sessionName(m_sFilename)));          appendMessages(tr("Open session: \"%1\".").arg(sessionName(m_sFilename)));
1062    
1063      // Make that an overall update.          // Make that an overall update.
1064      stabilizeForm();          stabilizeForm();
1065      return true;          return true;
1066  }  }
1067    
1068    
# Line 831  bool MainForm::saveSessionFile ( const Q Line 1078  bool MainForm::saveSessionFile ( const Q
1078                  return false;                  return false;
1079          }          }
1080    
1081      // Open and write into real file.          // Open and write into real file.
1082      QFile file(sFilename);          QFile file(sFilename);
1083      if (!file.open(IO_WriteOnly | IO_Truncate)) {          if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
1084          appendMessagesError(tr("Could not open \"%1\" session file.\n\nSorry.").arg(sFilename));                  appendMessagesError(
1085          return false;                          tr("Could not open \"%1\" session file.\n\nSorry.")
1086      }                          .arg(sFilename));
1087                    return false;
1088            }
1089    
1090          // Tell the world we'll take some time...          // Tell the world we'll take some time...
1091          QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));          QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1092    
1093      // Write the file.          // Write the file.
1094      int  iErrors = 0;          int iErrors = 0;
1095      QTextStream ts(&file);          QTextStream ts(&file);
1096      ts << "# " << QSAMPLER_TITLE " - " << tr(QSAMPLER_SUBTITLE) << endl;          ts << "# " << QSAMPLER_TITLE " - " << tr(QSAMPLER_SUBTITLE) << endl;
1097      ts << "# " << tr("Version")          ts << "# " << tr("Version") << ": " CONFIG_BUILD_VERSION << endl;
1098         << ": " QSAMPLER_VERSION << endl;  //      ts << "# " << tr("Build") << ": " CONFIG_BUILD_DATE << endl;
1099      ts << "# " << tr("Build")          ts << "#"  << endl;
1100         << ": " __DATE__ " " __TIME__ << endl;          ts << "# " << tr("File")
1101      ts << "#"  << endl;          << ": " << QFileInfo(sFilename).fileName() << endl;
1102      ts << "# " << tr("File")          ts << "# " << tr("Date")
1103         << ": " << QFileInfo(sFilename).fileName() << endl;          << ": " << QDate::currentDate().toString("MMM dd yyyy")
1104      ts << "# " << tr("Date")          << " "  << QTime::currentTime().toString("hh:mm:ss") << endl;
1105         << ": " << QDate::currentDate().toString("MMM dd yyyy")          ts << "#"  << endl;
1106         << " "  << QTime::currentTime().toString("hh:mm:ss") << endl;          ts << endl;
     ts << "#"  << endl;  
     ts << endl;  
1107    
1108          // It is assumed that this new kind of device+session file          // It is assumed that this new kind of device+session file
1109          // will be loaded from a complete initialized server...          // will be loaded from a complete initialized server...
1110          int *piDeviceIDs;          int *piDeviceIDs;
1111          int  iDevice;          int  i, iDevice;
1112          ts << "RESET" << endl;          ts << "RESET" << endl;
1113    
1114          // Audio device mapping.          // Audio device mapping.
1115          QMap<int, int> audioDeviceMap;          QMap<int, int> audioDeviceMap; iDevice = 0;
1116          piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Audio);          piDeviceIDs = Device::getDevices(m_pClient, Device::Audio);
1117          for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {          for (i = 0; piDeviceIDs && piDeviceIDs[i] >= 0; ++i) {
1118                  ts << endl;                  Device device(Device::Audio, piDeviceIDs[i]);
1119                  qsamplerDevice device(qsamplerDevice::Audio, piDeviceIDs[iDevice]);                  // Avoid plug-in driver devices...
1120                    if (device.driverName().toUpper() == "PLUGIN")
1121                            continue;
1122                  // Audio device specification...                  // Audio device specification...
1123                    ts << endl;
1124                  ts << "# " << device.deviceTypeName() << " " << device.driverName()                  ts << "# " << device.deviceTypeName() << " " << device.driverName()
1125                          << " " << tr("Device") << " " << iDevice << endl;                          << " " << tr("Device") << " " << iDevice << endl;
1126                  ts << "CREATE AUDIO_OUTPUT_DEVICE " << device.driverName();                  ts << "CREATE AUDIO_OUTPUT_DEVICE " << device.driverName();
1127                  qsamplerDeviceParamMap::ConstIterator deviceParam;                  DeviceParamMap::ConstIterator deviceParam;
1128                  for (deviceParam = device.params().begin();                  for (deviceParam = device.params().begin();
1129                                  deviceParam != device.params().end();                                  deviceParam != device.params().end();
1130                                          ++deviceParam) {                                          ++deviceParam) {
1131                          const qsamplerDeviceParam& param = deviceParam.data();                          const DeviceParam& param = deviceParam.value();
1132                          if (param.value.isEmpty()) ts << "# ";                          if (param.value.isEmpty()) ts << "# ";
1133                          ts << " " << deviceParam.key() << "='" << param.value << "'";                          ts << " " << deviceParam.key() << "='" << param.value << "'";
1134                  }                  }
1135                  ts << endl;                  ts << endl;
1136                  // Audio channel parameters...                  // Audio channel parameters...
1137                  int iPort = 0;                  int iPort = 0;
1138                  for (qsamplerDevicePort *pPort = device.ports().first();                  QListIterator<DevicePort *> iter(device.ports());
1139                                  pPort;                  while (iter.hasNext()) {
1140                                          pPort = device.ports().next(), ++iPort) {                          DevicePort *pPort = iter.next();
1141                          qsamplerDeviceParamMap::ConstIterator portParam;                          DeviceParamMap::ConstIterator portParam;
1142                          for (portParam = pPort->params().begin();                          for (portParam = pPort->params().begin();
1143                                          portParam != pPort->params().end();                                          portParam != pPort->params().end();
1144                                                  ++portParam) {                                                  ++portParam) {
1145                                  const qsamplerDeviceParam& param = portParam.data();                                  const DeviceParam& param = portParam.value();
1146                                  if (param.fix || param.value.isEmpty()) ts << "# ";                                  if (param.fix || param.value.isEmpty()) ts << "# ";
1147                                  ts << "SET AUDIO_OUTPUT_CHANNEL_PARAMETER " << iDevice                                  ts << "SET AUDIO_OUTPUT_CHANNEL_PARAMETER " << iDevice
1148                                          << " " << iPort << " " << portParam.key()                                          << " " << iPort << " " << portParam.key()
1149                                          << "='" << param.value << "'" << endl;                                          << "='" << param.value << "'" << endl;
1150                          }                          }
1151                            iPort++;
1152                  }                  }
1153                  // Audio device index/id mapping.                  // Audio device index/id mapping.
1154                  audioDeviceMap[device.deviceID()] = iDevice;                  audioDeviceMap.insert(device.deviceID(), iDevice++);
1155                  // Try to keep it snappy :)                  // Try to keep it snappy :)
1156                  QApplication::processEvents(QEventLoop::ExcludeUserInput);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1157          }          }
1158    
1159          // MIDI device mapping.          // MIDI device mapping.
1160          QMap<int, int> midiDeviceMap;          QMap<int, int> midiDeviceMap; iDevice = 0;
1161          piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Midi);          piDeviceIDs = Device::getDevices(m_pClient, Device::Midi);
1162          for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {          for (i = 0; piDeviceIDs && piDeviceIDs[i] >= 0; ++i) {
1163                  ts << endl;                  Device device(Device::Midi, piDeviceIDs[i]);
1164                  qsamplerDevice device(qsamplerDevice::Midi, piDeviceIDs[iDevice]);                  // Avoid plug-in driver devices...
1165                    if (device.driverName().toUpper() == "PLUGIN")
1166                            continue;
1167                  // MIDI device specification...                  // MIDI device specification...
1168                    ts << endl;
1169                  ts << "# " << device.deviceTypeName() << " " << device.driverName()                  ts << "# " << device.deviceTypeName() << " " << device.driverName()
1170                          << " " << tr("Device") << " " << iDevice << endl;                          << " " << tr("Device") << " " << iDevice << endl;
1171                  ts << "CREATE MIDI_INPUT_DEVICE " << device.driverName();                  ts << "CREATE MIDI_INPUT_DEVICE " << device.driverName();
1172                  qsamplerDeviceParamMap::ConstIterator deviceParam;                  DeviceParamMap::ConstIterator deviceParam;
1173                  for (deviceParam = device.params().begin();                  for (deviceParam = device.params().begin();
1174                                  deviceParam != device.params().end();                                  deviceParam != device.params().end();
1175                                          ++deviceParam) {                                          ++deviceParam) {
1176                          const qsamplerDeviceParam& param = deviceParam.data();                          const DeviceParam& param = deviceParam.value();
1177                          if (param.value.isEmpty()) ts << "# ";                          if (param.value.isEmpty()) ts << "# ";
1178                          ts << " " << deviceParam.key() << "='" << param.value << "'";                          ts << " " << deviceParam.key() << "='" << param.value << "'";
1179                  }                  }
1180                  ts << endl;                  ts << endl;
1181                  // MIDI port parameters...                  // MIDI port parameters...
1182                  int iPort = 0;                  int iPort = 0;
1183                  for (qsamplerDevicePort *pPort = device.ports().first();                  QListIterator<DevicePort *> iter(device.ports());
1184                                  pPort;                  while (iter.hasNext()) {
1185                                          pPort = device.ports().next(), ++iPort) {                          DevicePort *pPort = iter.next();
1186                          qsamplerDeviceParamMap::ConstIterator portParam;                          DeviceParamMap::ConstIterator portParam;
1187                          for (portParam = pPort->params().begin();                          for (portParam = pPort->params().begin();
1188                                          portParam != pPort->params().end();                                          portParam != pPort->params().end();
1189                                                  ++portParam) {                                                  ++portParam) {
1190                                  const qsamplerDeviceParam& param = portParam.data();                                  const DeviceParam& param = portParam.value();
1191                                  if (param.fix || param.value.isEmpty()) ts << "# ";                                  if (param.fix || param.value.isEmpty()) ts << "# ";
1192                                  ts << "SET MIDI_INPUT_PORT_PARAMETER " << iDevice                                  ts << "SET MIDI_INPUT_PORT_PARAMETER " << iDevice
1193                                     << " " << iPort << " " << portParam.key()                                  << " " << iPort << " " << portParam.key()
1194                                     << "='" << param.value << "'" << endl;                                  << "='" << param.value << "'" << endl;
1195                          }                          }
1196                            iPort++;
1197                  }                  }
1198                  // MIDI device index/id mapping.                  // MIDI device index/id mapping.
1199                  midiDeviceMap[device.deviceID()] = iDevice;                  midiDeviceMap.insert(device.deviceID(), iDevice++);
1200                  // Try to keep it snappy :)                  // Try to keep it snappy :)
1201                  QApplication::processEvents(QEventLoop::ExcludeUserInput);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1202          }          }
1203          ts << endl;          ts << endl;
1204    
# Line 952  bool MainForm::saveSessionFile ( const Q Line 1207  bool MainForm::saveSessionFile ( const Q
1207          QMap<int, int> midiInstrumentMap;          QMap<int, int> midiInstrumentMap;
1208          int *piMaps = ::lscp_list_midi_instrument_maps(m_pClient);          int *piMaps = ::lscp_list_midi_instrument_maps(m_pClient);
1209          for (int iMap = 0; piMaps && piMaps[iMap] >= 0; iMap++) {          for (int iMap = 0; piMaps && piMaps[iMap] >= 0; iMap++) {
1210                  int iMidiMap = piMaps[iMap];                  const int iMidiMap = piMaps[iMap];
1211                  const char *pszMapName                  const char *pszMapName
1212                          = ::lscp_get_midi_instrument_map_name(m_pClient, iMidiMap);                          = ::lscp_get_midi_instrument_map_name(m_pClient, iMidiMap);
1213                  ts << "# " << tr("MIDI instrument map") << " " << iMap;                  ts << "# " << tr("MIDI instrument map") << " " << iMap;
# Line 1000  bool MainForm::saveSessionFile ( const Q Line 1255  bool MainForm::saveSessionFile ( const Q
1255                                  iErrors++;                                  iErrors++;
1256                          }                          }
1257                          // Try to keep it snappy :)                          // Try to keep it snappy :)
1258                          QApplication::processEvents(QEventLoop::ExcludeUserInput);                          QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1259                  }                  }
1260                  ts << endl;                  ts << endl;
1261                  // Check for errors...                  // Check for errors...
# Line 1009  bool MainForm::saveSessionFile ( const Q Line 1264  bool MainForm::saveSessionFile ( const Q
1264                          iErrors++;                          iErrors++;
1265                  }                  }
1266                  // MIDI strument index/id mapping.                  // MIDI strument index/id mapping.
1267                  midiInstrumentMap[iMidiMap] = iMap;                  midiInstrumentMap.insert(iMidiMap, iMap);
1268          }          }
1269          // Check for errors...          // Check for errors...
1270          if (piMaps == NULL && ::lscp_client_get_errno(m_pClient)) {          if (piMaps == NULL && ::lscp_client_get_errno(m_pClient)) {
# Line 1018  bool MainForm::saveSessionFile ( const Q Line 1273  bool MainForm::saveSessionFile ( const Q
1273          }          }
1274  #endif  // CONFIG_MIDI_INSTRUMENT  #endif  // CONFIG_MIDI_INSTRUMENT
1275    
1276          // Sampler channel mapping.          // Sampler channel mapping...
1277      QWidgetList wlist = m_pWorkspace->windowList();          int iChannelID = 0;
1278      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          const QList<QMdiSubWindow *>& wlist
1279          ChannelStrip* pChannelStrip                  = m_pWorkspace->subWindowList();
1280                          = static_cast<ChannelStrip *> (wlist.at(iChannel));          const int iStripCount = wlist.count();
1281          if (pChannelStrip) {          for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
1282              qsamplerChannel *pChannel = pChannelStrip->channel();                  ChannelStrip *pChannelStrip = NULL;
1283              if (pChannel) {                  QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
1284                  ts << "# " << tr("Channel") << " " << iChannel << endl;                  if (pMdiSubWindow)
1285                  ts << "ADD CHANNEL" << endl;                          pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
1286                    if (pChannelStrip) {
1287                            Channel *pChannel = pChannelStrip->channel();
1288                            if (pChannel) {
1289                                    // Avoid "artifial" plug-in devices...
1290                                    const int iAudioDevice = pChannel->audioDevice();
1291                                    if (!audioDeviceMap.contains(iAudioDevice))
1292                                            continue;
1293                                    const int iMidiDevice = pChannel->midiDevice();
1294                                    if (!midiDeviceMap.contains(iMidiDevice))
1295                                            continue;
1296                                    // Go for regular, canonical devices...
1297                                    ts << "# " << tr("Channel") << " " << iChannelID << endl;
1298                                    ts << "ADD CHANNEL" << endl;
1299                                  if (audioDeviceMap.isEmpty()) {                                  if (audioDeviceMap.isEmpty()) {
1300                                          ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannel                                          ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannelID
1301                                                  << " " << pChannel->audioDriver() << endl;                                                  << " " << pChannel->audioDriver() << endl;
1302                                  } else {                                  } else {
1303                                          ts << "SET CHANNEL AUDIO_OUTPUT_DEVICE " << iChannel                                          ts << "SET CHANNEL AUDIO_OUTPUT_DEVICE " << iChannelID
1304                                                  << " " << audioDeviceMap[pChannel->audioDevice()] << endl;                                                  << " " << audioDeviceMap.value(iAudioDevice) << endl;
1305                                  }                                  }
1306                                  if (midiDeviceMap.isEmpty()) {                                  if (midiDeviceMap.isEmpty()) {
1307                                          ts << "SET CHANNEL MIDI_INPUT_TYPE " << iChannel                                          ts << "SET CHANNEL MIDI_INPUT_TYPE " << iChannelID
1308                                                  << " " << pChannel->midiDriver() << endl;                                                  << " " << pChannel->midiDriver() << endl;
1309                                  } else {                                  } else {
1310                                          ts << "SET CHANNEL MIDI_INPUT_DEVICE " << iChannel                                          ts << "SET CHANNEL MIDI_INPUT_DEVICE " << iChannelID
1311                                                  << " " << midiDeviceMap[pChannel->midiDevice()] << endl;                                                  << " " << midiDeviceMap.value(iMidiDevice) << endl;
1312                                  }                                  }
1313                                  ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannel                                  ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannelID
1314                                          << " " << pChannel->midiPort() << endl;                                          << " " << pChannel->midiPort() << endl;
1315                  ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannel << " ";                                  ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannelID << " ";
1316                  if (pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL)                                  if (pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL)
1317                      ts << "ALL";                                          ts << "ALL";
1318                  else                                  else
1319                      ts << pChannel->midiChannel();                                          ts << pChannel->midiChannel();
1320                  ts << endl;                                  ts << endl;
1321                  ts << "LOAD ENGINE " << pChannel->engineName() << " " << iChannel << endl;                                  ts << "LOAD ENGINE " << pChannel->engineName()
1322                                            << " " << iChannelID << endl;
1323                                  if (pChannel->instrumentStatus() < 100) ts << "# ";                                  if (pChannel->instrumentStatus() < 100) ts << "# ";
1324                                  ts << "LOAD INSTRUMENT NON_MODAL '" << pChannel->instrumentFile() << "' "                                  ts << "LOAD INSTRUMENT NON_MODAL '"
1325                                          << pChannel->instrumentNr() << " " << iChannel << endl;                                          << pChannel->instrumentFile() << "' "
1326                                  qsamplerChannelRoutingMap::ConstIterator audioRoute;                                          << pChannel->instrumentNr() << " " << iChannelID << endl;
1327                                    ChannelRoutingMap::ConstIterator audioRoute;
1328                                  for (audioRoute = pChannel->audioRouting().begin();                                  for (audioRoute = pChannel->audioRouting().begin();
1329                                                  audioRoute != pChannel->audioRouting().end();                                                  audioRoute != pChannel->audioRouting().end();
1330                                                          ++audioRoute) {                                                          ++audioRoute) {
1331                                          ts << "SET CHANNEL AUDIO_OUTPUT_CHANNEL " << iChannel                                          ts << "SET CHANNEL AUDIO_OUTPUT_CHANNEL " << iChannelID
1332                                                  << " " << audioRoute.key()                                                  << " " << audioRoute.key()
1333                                                  << " " << audioRoute.data() << endl;                                                  << " " << audioRoute.value() << endl;
1334                                  }                                  }
1335                                  ts << "SET CHANNEL VOLUME " << iChannel                                  ts << "SET CHANNEL VOLUME " << iChannelID
1336                                          << " " << pChannel->volume() << endl;                                          << " " << pChannel->volume() << endl;
1337                                  if (pChannel->channelMute())                                  if (pChannel->channelMute())
1338                                          ts << "SET CHANNEL MUTE " << iChannel << " 1" << endl;                                          ts << "SET CHANNEL MUTE " << iChannelID << " 1" << endl;
1339                                  if (pChannel->channelSolo())                                  if (pChannel->channelSolo())
1340                                          ts << "SET CHANNEL SOLO " << iChannel << " 1" << endl;                                          ts << "SET CHANNEL SOLO " << iChannelID << " 1" << endl;
1341  #ifdef CONFIG_MIDI_INSTRUMENT                          #ifdef CONFIG_MIDI_INSTRUMENT
1342                                  if (pChannel->midiMap() >= 0) {                                  const int iMidiMap = pChannel->midiMap();
1343                                          ts << "SET CHANNEL MIDI_INSTRUMENT_MAP " << iChannel                                  if (midiInstrumentMap.contains(iMidiMap)) {
1344                                                  << " " << midiInstrumentMap[pChannel->midiMap()] << endl;                                          ts << "SET CHANNEL MIDI_INSTRUMENT_MAP " << iChannelID
1345                                                    << " " << midiInstrumentMap.value(iMidiMap) << endl;
1346                                  }                                  }
1347  #endif                          #endif
1348  #ifdef CONFIG_FXSEND                          #ifdef CONFIG_FXSEND
                                 int iChannelID = pChannel->channelID();  
1349                                  int *piFxSends = ::lscp_list_fxsends(m_pClient, iChannelID);                                  int *piFxSends = ::lscp_list_fxsends(m_pClient, iChannelID);
1350                                  for (int iFxSend = 0;                                  for (int iFxSend = 0;
1351                                                  piFxSends && piFxSends[iFxSend] >= 0;                                                  piFxSends && piFxSends[iFxSend] >= 0;
# Line 1083  bool MainForm::saveSessionFile ( const Q Line 1353  bool MainForm::saveSessionFile ( const Q
1353                                          lscp_fxsend_info_t *pFxSendInfo = ::lscp_get_fxsend_info(                                          lscp_fxsend_info_t *pFxSendInfo = ::lscp_get_fxsend_info(
1354                                                  m_pClient, iChannelID, piFxSends[iFxSend]);                                                  m_pClient, iChannelID, piFxSends[iFxSend]);
1355                                          if (pFxSendInfo) {                                          if (pFxSendInfo) {
1356                                                  ts << "CREATE FX_SEND " << iChannel                                                  ts << "CREATE FX_SEND " << iChannelID
1357                                                          << " " << pFxSendInfo->midi_controller;                                                          << " " << pFxSendInfo->midi_controller;
1358                                                  if (pFxSendInfo->name)                                                  if (pFxSendInfo->name)
1359                                                          ts << " '" << pFxSendInfo->name << "'";                                                          ts << " '" << pFxSendInfo->name << "'";
# Line 1093  bool MainForm::saveSessionFile ( const Q Line 1363  bool MainForm::saveSessionFile ( const Q
1363                                                                  piRouting && piRouting[iAudioSrc] >= 0;                                                                  piRouting && piRouting[iAudioSrc] >= 0;
1364                                                                          iAudioSrc++) {                                                                          iAudioSrc++) {
1365                                                          ts << "SET FX_SEND AUDIO_OUTPUT_CHANNEL "                                                          ts << "SET FX_SEND AUDIO_OUTPUT_CHANNEL "
1366                                                                  << iChannel                                                                  << iChannelID
1367                                                                  << " " << iFxSend                                                                  << " " << iFxSend
1368                                                                  << " " << iAudioSrc                                                                  << " " << iAudioSrc
1369                                                                  << " " << piRouting[iAudioSrc] << endl;                                                                  << " " << piRouting[iAudioSrc] << endl;
1370                                                  }                                                  }
1371  #ifdef CONFIG_FXSEND_LEVEL                                          #ifdef CONFIG_FXSEND_LEVEL
1372                                                  ts << "SET FX_SEND LEVEL " << iChannel                                                  ts << "SET FX_SEND LEVEL " << iChannelID
1373                                                          << " " << iFxSend                                                          << " " << iFxSend
1374                                                          << " " << pFxSendInfo->level << endl;                                                          << " " << pFxSendInfo->level << endl;
1375  #endif                                          #endif
1376                                          }       // Check for errors...                                          }       // Check for errors...
1377                                          else if (::lscp_client_get_errno(m_pClient)) {                                          else if (::lscp_client_get_errno(m_pClient)) {
1378                                                  appendMessagesClient("lscp_get_fxsend_info");                                                  appendMessagesClient("lscp_get_fxsend_info");
1379                                                  iErrors++;                                                  iErrors++;
1380                                          }                                          }
1381                                  }                                  }
1382  #endif                          #endif
1383                  ts << endl;                                  ts << endl;
1384              }                                  // Go for next channel...
1385          }                                  ++iChannelID;
1386          // Try to keep it snappy :)                          }
1387          QApplication::processEvents(QEventLoop::ExcludeUserInput);                  }
1388      }                  // Try to keep it snappy :)
1389                    QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1390            }
1391    
1392  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
1393          ts << "# " << tr("Global volume level") << endl;          ts << "# " << tr("Global volume level") << endl;
# Line 1123  bool MainForm::saveSessionFile ( const Q Line 1395  bool MainForm::saveSessionFile ( const Q
1395          ts << endl;          ts << endl;
1396  #endif  #endif
1397    
1398      // Ok. we've wrote it.          // Ok. we've wrote it.
1399      file.close();          file.close();
1400    
1401          // We're fornerly done.          // We're fornerly done.
1402          QApplication::restoreOverrideCursor();          QApplication::restoreOverrideCursor();
1403    
1404      // Have we any errors?          // Have we any errors?
1405      if (iErrors > 0)          if (iErrors > 0) {
1406          appendMessagesError(tr("Some settings could not be saved\nto \"%1\" session file.\n\nSorry.").arg(sFilename));                  appendMessagesError(
1407                            tr("Some settings could not be saved\n"
1408      // Save as default session directory.                          "to \"%1\" session file.\n\nSorry.")
1409      if (m_pOptions)                          .arg(sFilename));
1410          m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);          }
1411      // We're not dirty anymore.  
1412      m_iDirtyCount = 0;          // Save as default session directory.
1413      // Stabilize form...          if (m_pOptions)
1414      m_sFilename = sFilename;                  m_pOptions->sSessionDir = QFileInfo(sFilename).dir().absolutePath();
1415      updateRecentFiles(sFilename);          // We're not dirty anymore.
1416      appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename)));          m_iDirtyCount = 0;
1417      stabilizeForm();          // Stabilize form...
1418      return true;          m_sFilename = sFilename;
1419            updateRecentFiles(sFilename);
1420            appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename)));
1421            stabilizeForm();
1422            return true;
1423  }  }
1424    
1425    
1426  // Session change receiver slot.  // Session change receiver slot.
1427  void MainForm::sessionDirty (void)  void MainForm::sessionDirty (void)
1428  {  {
1429      // Just mark the dirty form.          // Just mark the dirty form.
1430      m_iDirtyCount++;          m_iDirtyCount++;
1431      // and update the form status...          // and update the form status...
1432      stabilizeForm();          stabilizeForm();
1433  }  }
1434    
1435    
1436  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
1437  // qsamplerMainForm -- File Action slots.  // QSampler::MainForm -- File Action slots.
1438    
1439  // Create a new sampler session.  // Create a new sampler session.
1440  void MainForm::fileNew (void)  void MainForm::fileNew (void)
1441  {  {
1442      // Of course we'll start clean new.          // Of course we'll start clean new.
1443      newSession();          newSession();
1444  }  }
1445    
1446    
1447  // Open an existing sampler session.  // Open an existing sampler session.
1448  void MainForm::fileOpen (void)  void MainForm::fileOpen (void)
1449  {  {
1450      // Open it right away.          // Open it right away.
1451      openSession();          openSession();
1452  }  }
1453    
1454    
1455  // Open a recent file session.  // Open a recent file session.
1456  void MainForm::fileOpenRecent ( int iIndex )  void MainForm::fileOpenRecent (void)
1457  {  {
1458      // Check if we can safely close the current session...          // Retrive filename index from action data...
1459      if (m_pOptions && closeSession(true)) {          QAction *pAction = qobject_cast<QAction *> (sender());
1460          QString sFilename = m_pOptions->recentFiles[iIndex];          if (pAction && m_pOptions) {
1461          loadSessionFile(sFilename);                  const int iIndex = pAction->data().toInt();
1462      }                  if (iIndex >= 0 && iIndex < m_pOptions->recentFiles.count()) {
1463                            QString sFilename = m_pOptions->recentFiles[iIndex];
1464                            // Check if we can safely close the current session...
1465                            if (!sFilename.isEmpty() && closeSession(true))
1466                                    loadSessionFile(sFilename);
1467                    }
1468            }
1469  }  }
1470    
1471    
1472  // Save current sampler session.  // Save current sampler session.
1473  void MainForm::fileSave (void)  void MainForm::fileSave (void)
1474  {  {
1475      // Save it right away.          // Save it right away.
1476      saveSession(false);          saveSession(false);
1477  }  }
1478    
1479    
1480  // Save current sampler session with another name.  // Save current sampler session with another name.
1481  void MainForm::fileSaveAs (void)  void MainForm::fileSaveAs (void)
1482  {  {
1483      // Save it right away, maybe with another name.          // Save it right away, maybe with another name.
1484      saveSession(true);          saveSession(true);
1485  }  }
1486    
1487    
1488  // Reset the sampler instance.  // Reset the sampler instance.
1489  void MainForm::fileReset (void)  void MainForm::fileReset (void)
1490  {  {
1491      if (m_pClient == NULL)          if (m_pClient == NULL)
1492          return;                  return;
1493    
1494      // Ask user whether he/she want's an internal sampler reset...          // Ask user whether he/she want's an internal sampler reset...
1495      if (QMessageBox::warning(this,          if (m_pOptions && m_pOptions->bConfirmReset) {
1496                  QSAMPLER_TITLE ": " + tr("Warning"),                  const QString& sTitle = QSAMPLER_TITLE ": " + tr("Warning");
1497          tr("Resetting the sampler instance will close\n"                  const QString& sText = tr(
1498             "all device and channel configurations.\n\n"                          "Resetting the sampler instance will close\n"
1499             "Please note that this operation may cause\n"                          "all device and channel configurations.\n\n"
1500             "temporary MIDI and Audio disruption.\n\n"                          "Please note that this operation may cause\n"
1501             "Do you want to reset the sampler engine now?"),                          "temporary MIDI and Audio disruption.\n\n"
1502          tr("Reset"), tr("Cancel")) > 0)                          "Do you want to reset the sampler engine now?");
1503          return;          #if 0
1504                    if (QMessageBox::warning(this, sTitle, sText,
1505                            QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
1506                            return;
1507            #else
1508                    QMessageBox mbox(this);
1509                    mbox.setIcon(QMessageBox::Warning);
1510                    mbox.setWindowTitle(sTitle);
1511                    mbox.setText(sText);
1512                    mbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
1513                    QCheckBox cbox(tr("Don't ask this again"));
1514                    cbox.setChecked(false);
1515                    cbox.blockSignals(true);
1516                    mbox.addButton(&cbox, QMessageBox::ActionRole);
1517                    if (mbox.exec() == QMessageBox::Cancel)
1518                            return;
1519                    if (cbox.isChecked())
1520                            m_pOptions->bConfirmReset = false;
1521            #endif
1522            }
1523    
1524          // Trye closing the current session, first...          // Trye closing the current session, first...
1525          if (!closeSession(true))          if (!closeSession(true))
1526                  return;                  return;
1527    
1528      // Just do the reset, after closing down current session...          // Just do the reset, after closing down current session...
1529          // Do the actual sampler reset...          // Do the actual sampler reset...
1530          if (::lscp_reset_sampler(m_pClient) != LSCP_OK) {          if (::lscp_reset_sampler(m_pClient) != LSCP_OK) {
1531                  appendMessagesClient("lscp_reset_sampler");                  appendMessagesClient("lscp_reset_sampler");
# Line 1232  void MainForm::fileReset (void) Line 1533  void MainForm::fileReset (void)
1533                  return;                  return;
1534          }          }
1535    
1536      // Log this.          // Log this.
1537      appendMessages(tr("Sampler reset."));          appendMessages(tr("Sampler reset."));
1538    
1539          // Make it a new session...          // Make it a new session...
1540          newSession();          newSession();
# Line 1243  void MainForm::fileReset (void) Line 1544  void MainForm::fileReset (void)
1544  // Restart the client/server instance.  // Restart the client/server instance.
1545  void MainForm::fileRestart (void)  void MainForm::fileRestart (void)
1546  {  {
1547      if (m_pOptions == NULL)          if (m_pOptions == NULL)
1548          return;                  return;
1549    
1550      bool bRestart = true;          bool bRestart = true;
1551    
1552      // Ask user whether he/she want's a complete restart...          // Ask user whether he/she want's a complete restart...
1553      // (if we're currently up and running)          // (if we're currently up and running)
1554      if (bRestart && m_pClient) {          if (m_pOptions && m_pOptions->bConfirmRestart) {
1555          bRestart = (QMessageBox::warning(this,                  const QString& sTitle = QSAMPLER_TITLE ": " + tr("Warning");
1556                          QSAMPLER_TITLE ": " + tr("Warning"),                  const QString& sText = tr(
1557              tr("New settings will be effective after\n"                          "New settings will be effective after\n"
1558                 "restarting the client/server connection.\n\n"                          "restarting the client/server connection.\n\n"
1559                 "Please note that this operation may cause\n"                          "Please note that this operation may cause\n"
1560                 "temporary MIDI and Audio disruption.\n\n"                          "temporary MIDI and Audio disruption.\n\n"
1561                 "Do you want to restart the connection now?"),                          "Do you want to restart the connection now?");
1562              tr("Restart"), tr("Cancel")) == 0);          #if 0
1563      }                  if (QMessageBox::warning(this, sTitle, sText,
1564                            QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
1565      // Are we still for it?                          bRestart = false;
1566      if (bRestart && closeSession(true)) {          #else
1567          // Stop server, it will force the client too.                  QMessageBox mbox(this);
1568          stopServer();                  mbox.setIcon(QMessageBox::Warning);
1569          // Reschedule a restart...                  mbox.setWindowTitle(sTitle);
1570          startSchedule(m_pOptions->iStartDelay);                  mbox.setText(sText);
1571      }                  mbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
1572                    QCheckBox cbox(tr("Don't ask this again"));
1573                    cbox.setChecked(false);
1574                    cbox.blockSignals(true);
1575                    mbox.addButton(&cbox, QMessageBox::ActionRole);
1576                    if (mbox.exec() == QMessageBox::Cancel)
1577                            bRestart = false;
1578                    else
1579                    if (cbox.isChecked())
1580                            m_pOptions->bConfirmRestart = false;
1581            #endif
1582            }
1583    
1584            // Are we still for it?
1585            if (bRestart && closeSession(true)) {
1586                    // Stop server, it will force the client too.
1587                    stopServer();
1588                    // Reschedule a restart...
1589                    startSchedule(m_pOptions->iStartDelay);
1590            }
1591  }  }
1592    
1593    
1594  // Exit application program.  // Exit application program.
1595  void MainForm::fileExit (void)  void MainForm::fileExit (void)
1596  {  {
1597      // Go for close the whole thing.          // Go for close the whole thing.
1598      close();          close();
1599  }  }
1600    
1601    
1602  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
1603  // qsamplerMainForm -- Edit Action slots.  // QSampler::MainForm -- Edit Action slots.
1604    
1605  // Add a new sampler channel.  // Add a new sampler channel.
1606  void MainForm::editAddChannel (void)  void MainForm::editAddChannel (void)
1607  {  {
1608      if (m_pClient == NULL)          ++m_iDirtySetup;
1609          return;          addChannelStrip();
1610            --m_iDirtySetup;
1611    }
1612    
1613      // Just create the channel instance...  void MainForm::addChannelStrip (void)
1614      qsamplerChannel *pChannel = new qsamplerChannel();  {
1615      if (pChannel == NULL)          if (m_pClient == NULL)
1616          return;                  return;
1617    
1618      // Before we show it up, may be we'll          // Just create the channel instance...
1619      // better ask for some initial values?          Channel *pChannel = new Channel();
1620      if (!pChannel->channelSetup(this)) {          if (pChannel == NULL)
1621          delete pChannel;                  return;
1622          return;  
1623      }          // Before we show it up, may be we'll
1624            // better ask for some initial values?
1625      // And give it to the strip (will own the channel instance, if successful).          if (!pChannel->channelSetup(this)) {
1626      if (!createChannelStrip(pChannel)) {                  delete pChannel;
1627          delete pChannel;                  return;
1628          return;          }
1629      }  
1630            // And give it to the strip...
1631      // Make that an overall update.          // (will own the channel instance, if successful).
1632      m_iDirtyCount++;          if (!createChannelStrip(pChannel)) {
1633      stabilizeForm();                  delete pChannel;
1634                    return;
1635            }
1636    
1637            // Do we auto-arrange?
1638            channelsArrangeAuto();
1639    
1640            // Make that an overall update.
1641            m_iDirtyCount++;
1642            stabilizeForm();
1643  }  }
1644    
1645    
1646  // Remove current sampler channel.  // Remove current sampler channel.
1647  void MainForm::editRemoveChannel (void)  void MainForm::editRemoveChannel (void)
1648  {  {
1649      if (m_pClient == NULL)          ++m_iDirtySetup;
1650          return;          removeChannelStrip();
1651            --m_iDirtySetup;
1652    }
1653    
1654      ChannelStrip* pChannelStrip = activeChannelStrip();  void MainForm::removeChannelStrip (void)
1655      if (pChannelStrip == NULL)  {
1656          return;          if (m_pClient == NULL)
1657                    return;
1658      qsamplerChannel *pChannel = pChannelStrip->channel();  
1659      if (pChannel == NULL)          ChannelStrip *pChannelStrip = activeChannelStrip();
1660          return;          if (pChannelStrip == NULL)
1661                    return;
1662      // Prompt user if he/she's sure about this...  
1663      if (m_pOptions && m_pOptions->bConfirmRemove) {          Channel *pChannel = pChannelStrip->channel();
1664          if (QMessageBox::warning(this,          if (pChannel == NULL)
1665                          QSAMPLER_TITLE ": " + tr("Warning"),                  return;
1666              tr("About to remove channel:\n\n"  
1667                 "%1\n\n"          // Prompt user if he/she's sure about this...
1668                 "Are you sure?")          if (m_pOptions && m_pOptions->bConfirmRemove) {
1669                 .arg(pChannelStrip->caption()),                  const QString& sTitle = QSAMPLER_TITLE ": " + tr("Warning");
1670              tr("OK"), tr("Cancel")) > 0)                  const QString& sText = tr(
1671              return;                          "About to remove channel:\n\n"
1672      }                          "%1\n\n"
1673                            "Are you sure?")
1674      // Remove the existing sampler channel.                          .arg(pChannelStrip->windowTitle());
1675      if (!pChannel->removeChannel())          #if 0
1676          return;                  if (QMessageBox::warning(this, sTitle, sText,
1677                            QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
1678      // Just delete the channel strip.                          return;
1679      delete pChannelStrip;          #else
1680                    QMessageBox mbox(this);
1681      // Do we auto-arrange?                  mbox.setIcon(QMessageBox::Warning);
1682      if (m_pOptions && m_pOptions->bAutoArrange)                  mbox.setWindowTitle(sTitle);
1683          channelsArrange();                  mbox.setText(sText);
1684                    mbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
1685      // We'll be dirty, for sure...                  QCheckBox cbox(tr("Don't ask this again"));
1686      m_iDirtyCount++;                  cbox.setChecked(false);
1687      stabilizeForm();                  cbox.blockSignals(true);
1688                    mbox.addButton(&cbox, QMessageBox::ActionRole);
1689                    if (mbox.exec() == QMessageBox::Cancel)
1690                            return;
1691                    if (cbox.isChecked())
1692                            m_pOptions->bConfirmRemove = false;
1693            #endif
1694            }
1695    
1696            // Remove the existing sampler channel.
1697            if (!pChannel->removeChannel())
1698                    return;
1699    
1700            // Just delete the channel strip.
1701            destroyChannelStrip(pChannelStrip);
1702    
1703            // We'll be dirty, for sure...
1704            m_iDirtyCount++;
1705            stabilizeForm();
1706  }  }
1707    
1708    
1709  // Setup current sampler channel.  // Setup current sampler channel.
1710  void MainForm::editSetupChannel (void)  void MainForm::editSetupChannel (void)
1711  {  {
1712      if (m_pClient == NULL)          if (m_pClient == NULL)
1713          return;                  return;
1714    
1715      ChannelStrip* pChannelStrip = activeChannelStrip();          ChannelStrip *pChannelStrip = activeChannelStrip();
1716      if (pChannelStrip == NULL)          if (pChannelStrip == NULL)
1717          return;                  return;
1718    
1719      // Just invoque the channel strip procedure.          // Just invoque the channel strip procedure.
1720      pChannelStrip->channelSetup();          pChannelStrip->channelSetup();
1721  }  }
1722    
1723    
1724  // Edit current sampler channel.  // Edit current sampler channel.
1725  void MainForm::editEditChannel (void)  void MainForm::editEditChannel (void)
1726  {  {
1727      if (m_pClient == NULL)          if (m_pClient == NULL)
1728          return;                  return;
1729    
1730      ChannelStrip* pChannelStrip = activeChannelStrip();          ChannelStrip *pChannelStrip = activeChannelStrip();
1731      if (pChannelStrip == NULL)          if (pChannelStrip == NULL)
1732          return;                  return;
1733    
1734      // Just invoque the channel strip procedure.          // Just invoque the channel strip procedure.
1735      pChannelStrip->channelEdit();          pChannelStrip->channelEdit();
1736  }  }
1737    
1738    
1739  // Reset current sampler channel.  // Reset current sampler channel.
1740  void MainForm::editResetChannel (void)  void MainForm::editResetChannel (void)
1741  {  {
1742      if (m_pClient == NULL)          if (m_pClient == NULL)
1743          return;                  return;
1744    
1745      ChannelStrip* pChannelStrip = activeChannelStrip();          ChannelStrip *pChannelStrip = activeChannelStrip();
1746      if (pChannelStrip == NULL)          if (pChannelStrip == NULL)
1747          return;                  return;
1748    
1749      // Just invoque the channel strip procedure.          // Just invoque the channel strip procedure.
1750      pChannelStrip->channelReset();          pChannelStrip->channelReset();
1751  }  }
1752    
1753    
# Line 1409  void MainForm::editResetAllChannels (voi Line 1760  void MainForm::editResetAllChannels (voi
1760          // Invoque the channel strip procedure,          // Invoque the channel strip procedure,
1761          // for all channels out there...          // for all channels out there...
1762          m_pWorkspace->setUpdatesEnabled(false);          m_pWorkspace->setUpdatesEnabled(false);
1763          QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
1764          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {                  = m_pWorkspace->subWindowList();
1765                  ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);          const int iStripCount = wlist.count();
1766            for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
1767                    ChannelStrip *pChannelStrip = NULL;
1768                    QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
1769                    if (pMdiSubWindow)
1770                            pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
1771                  if (pChannelStrip)                  if (pChannelStrip)
1772                          pChannelStrip->channelReset();                          pChannelStrip->channelReset();
1773          }          }
# Line 1420  void MainForm::editResetAllChannels (voi Line 1776  void MainForm::editResetAllChannels (voi
1776    
1777    
1778  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
1779  // qsamplerMainForm -- View Action slots.  // QSampler::MainForm -- View Action slots.
1780    
1781  // Show/hide the main program window menubar.  // Show/hide the main program window menubar.
1782  void MainForm::viewMenubar ( bool bOn )  void MainForm::viewMenubar ( bool bOn )
1783  {  {
1784      if (bOn)          if (bOn)
1785          ui.MenuBar->show();                  m_ui.MenuBar->show();
1786      else          else
1787          ui.MenuBar->hide();                  m_ui.MenuBar->hide();
1788  }  }
1789    
1790    
1791  // Show/hide the main program window toolbar.  // Show/hide the main program window toolbar.
1792  void MainForm::viewToolbar ( bool bOn )  void MainForm::viewToolbar ( bool bOn )
1793  {  {
1794      if (bOn) {          if (bOn) {
1795          ui.fileToolbar->show();                  m_ui.fileToolbar->show();
1796          ui.editToolbar->show();                  m_ui.editToolbar->show();
1797          ui.channelsToolbar->show();                  m_ui.channelsToolbar->show();
1798      } else {          } else {
1799          ui.fileToolbar->hide();                  m_ui.fileToolbar->hide();
1800          ui.editToolbar->hide();                  m_ui.editToolbar->hide();
1801          ui.channelsToolbar->hide();                  m_ui.channelsToolbar->hide();
1802      }          }
1803  }  }
1804    
1805    
1806  // Show/hide the main program window statusbar.  // Show/hide the main program window statusbar.
1807  void MainForm::viewStatusbar ( bool bOn )  void MainForm::viewStatusbar ( bool bOn )
1808  {  {
1809      if (bOn)          if (bOn)
1810          statusBar()->show();                  statusBar()->show();
1811      else          else
1812          statusBar()->hide();                  statusBar()->hide();
1813  }  }
1814    
1815    
1816  // Show/hide the messages window logger.  // Show/hide the messages window logger.
1817  void MainForm::viewMessages ( bool bOn )  void MainForm::viewMessages ( bool bOn )
1818  {  {
1819      if (bOn)          if (bOn)
1820          m_pMessages->show();                  m_pMessages->show();
1821      else          else
1822          m_pMessages->hide();                  m_pMessages->hide();
1823  }  }
1824    
1825    
# Line 1480  void MainForm::viewInstruments (void) Line 1836  void MainForm::viewInstruments (void)
1836                  } else {                  } else {
1837                          m_pInstrumentListForm->show();                          m_pInstrumentListForm->show();
1838                          m_pInstrumentListForm->raise();                          m_pInstrumentListForm->raise();
1839                          m_pInstrumentListForm->setActiveWindow();                          m_pInstrumentListForm->activateWindow();
1840                  }                  }
1841          }          }
1842  }  }
# Line 1499  void MainForm::viewDevices (void) Line 1855  void MainForm::viewDevices (void)
1855                  } else {                  } else {
1856                          m_pDeviceForm->show();                          m_pDeviceForm->show();
1857                          m_pDeviceForm->raise();                          m_pDeviceForm->raise();
1858                          m_pDeviceForm->setActiveWindow();                          m_pDeviceForm->activateWindow();
1859                  }                  }
1860          }          }
1861  }  }
# Line 1508  void MainForm::viewDevices (void) Line 1864  void MainForm::viewDevices (void)
1864  // Show options dialog.  // Show options dialog.
1865  void MainForm::viewOptions (void)  void MainForm::viewOptions (void)
1866  {  {
1867      if (m_pOptions == NULL)          if (m_pOptions == NULL)
1868          return;                  return;
1869    
1870      OptionsForm* pOptionsForm = new OptionsForm(this);          OptionsForm* pOptionsForm = new OptionsForm(this);
1871      if (pOptionsForm) {          if (pOptionsForm) {
1872          // Check out some initial nullities(tm)...                  // Check out some initial nullities(tm)...
1873          ChannelStrip* pChannelStrip = activeChannelStrip();                  ChannelStrip *pChannelStrip = activeChannelStrip();
1874          if (m_pOptions->sDisplayFont.isEmpty() && pChannelStrip)                  if (m_pOptions->sDisplayFont.isEmpty() && pChannelStrip)
1875              m_pOptions->sDisplayFont = pChannelStrip->displayFont().toString();                          m_pOptions->sDisplayFont = pChannelStrip->displayFont().toString();
1876          if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages)                  if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages)
1877              m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();                          m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();
1878          // To track down deferred or immediate changes.                  // To track down deferred or immediate changes.
1879          QString sOldServerHost      = m_pOptions->sServerHost;                  const QString sOldServerHost      = m_pOptions->sServerHost;
1880          int     iOldServerPort      = m_pOptions->iServerPort;                  const int     iOldServerPort      = m_pOptions->iServerPort;
1881          int     iOldServerTimeout   = m_pOptions->iServerTimeout;                  const int     iOldServerTimeout   = m_pOptions->iServerTimeout;
1882          bool    bOldServerStart     = m_pOptions->bServerStart;                  const bool    bOldServerStart     = m_pOptions->bServerStart;
1883          QString sOldServerCmdLine   = m_pOptions->sServerCmdLine;                  const QString sOldServerCmdLine   = m_pOptions->sServerCmdLine;
1884          QString sOldDisplayFont     = m_pOptions->sDisplayFont;                  const bool    bOldMessagesLog     = m_pOptions->bMessagesLog;
1885          bool    bOldDisplayEffect   = m_pOptions->bDisplayEffect;                  const QString sOldMessagesLogPath = m_pOptions->sMessagesLogPath;
1886          int     iOldMaxVolume       = m_pOptions->iMaxVolume;                  const QString sOldDisplayFont     = m_pOptions->sDisplayFont;
1887          QString sOldMessagesFont    = m_pOptions->sMessagesFont;                  const bool    bOldDisplayEffect   = m_pOptions->bDisplayEffect;
1888          bool    bOldKeepOnTop       = m_pOptions->bKeepOnTop;                  const int     iOldMaxVolume       = m_pOptions->iMaxVolume;
1889          bool    bOldStdoutCapture   = m_pOptions->bStdoutCapture;                  const QString sOldMessagesFont    = m_pOptions->sMessagesFont;
1890          int     bOldMessagesLimit   = m_pOptions->bMessagesLimit;                  const bool    bOldKeepOnTop       = m_pOptions->bKeepOnTop;
1891          int     iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines;                  const bool    bOldStdoutCapture   = m_pOptions->bStdoutCapture;
1892          bool    bOldCompletePath    = m_pOptions->bCompletePath;                  const int     bOldMessagesLimit   = m_pOptions->bMessagesLimit;
1893          bool    bOldInstrumentNames = m_pOptions->bInstrumentNames;                  const int     iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines;
1894          int     iOldMaxRecentFiles  = m_pOptions->iMaxRecentFiles;                  const bool    bOldCompletePath    = m_pOptions->bCompletePath;
1895          // Load the current setup settings.                  const bool    bOldInstrumentNames = m_pOptions->bInstrumentNames;
1896          pOptionsForm->setup(m_pOptions);                  const int     iOldMaxRecentFiles  = m_pOptions->iMaxRecentFiles;
1897          // Show the setup dialog...                  const int     iOldBaseFontSize    = m_pOptions->iBaseFontSize;
1898          if (pOptionsForm->exec()) {                  // Load the current setup settings.
1899              // Warn if something will be only effective on next run.                  pOptionsForm->setup(m_pOptions);
1900              if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) ||                  // Show the setup dialog...
1901                  (!bOldStdoutCapture &&  m_pOptions->bStdoutCapture) ||                  if (pOptionsForm->exec()) {
1902                  ( bOldKeepOnTop     && !m_pOptions->bKeepOnTop)     ||                          // Warn if something will be only effective on next run.
1903                  (!bOldKeepOnTop     &&  m_pOptions->bKeepOnTop)) {                          if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) ||
1904                  QMessageBox::information(this,                                  (!bOldStdoutCapture &&  m_pOptions->bStdoutCapture) ||
1905                                    ( bOldKeepOnTop     && !m_pOptions->bKeepOnTop)     ||
1906                                    (!bOldKeepOnTop     &&  m_pOptions->bKeepOnTop)     ||
1907                                    (iOldBaseFontSize   !=  m_pOptions->iBaseFontSize)) {
1908                                    QMessageBox::information(this,
1909                                          QSAMPLER_TITLE ": " + tr("Information"),                                          QSAMPLER_TITLE ": " + tr("Information"),
1910                      tr("Some settings may be only effective\n"                                          tr("Some settings may be only effective\n"
1911                         "next time you start this program."), tr("OK"));                                          "next time you start this program."));
1912                  updateMessagesCapture();                                  updateMessagesCapture();
1913              }                          }
1914              // Check wheather something immediate has changed.                          // Check wheather something immediate has changed.
1915              if (( bOldCompletePath && !m_pOptions->bCompletePath) ||                          if (( bOldMessagesLog && !m_pOptions->bMessagesLog) ||
1916                  (!bOldCompletePath &&  m_pOptions->bCompletePath) ||                                  (!bOldMessagesLog &&  m_pOptions->bMessagesLog) ||
1917                  (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles))                                  (sOldMessagesLogPath != m_pOptions->sMessagesLogPath))
1918                  updateRecentFilesMenu();                                  m_pMessages->setLogging(
1919              if (( bOldInstrumentNames && !m_pOptions->bInstrumentNames) ||                                          m_pOptions->bMessagesLog, m_pOptions->sMessagesLogPath);
1920                  (!bOldInstrumentNames &&  m_pOptions->bInstrumentNames))                          if (( bOldCompletePath && !m_pOptions->bCompletePath) ||
1921                  updateInstrumentNames();                                  (!bOldCompletePath &&  m_pOptions->bCompletePath) ||
1922              if (( bOldDisplayEffect && !m_pOptions->bDisplayEffect) ||                                  (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles))
1923                  (!bOldDisplayEffect &&  m_pOptions->bDisplayEffect))                                  updateRecentFilesMenu();
1924                  updateDisplayEffect();                          if (( bOldInstrumentNames && !m_pOptions->bInstrumentNames) ||
1925              if (sOldDisplayFont != m_pOptions->sDisplayFont)                                  (!bOldInstrumentNames &&  m_pOptions->bInstrumentNames))
1926                  updateDisplayFont();                                  updateInstrumentNames();
1927              if (iOldMaxVolume != m_pOptions->iMaxVolume)                          if (( bOldDisplayEffect && !m_pOptions->bDisplayEffect) ||
1928                  updateMaxVolume();                                  (!bOldDisplayEffect &&  m_pOptions->bDisplayEffect))
1929              if (sOldMessagesFont != m_pOptions->sMessagesFont)                                  updateDisplayEffect();
1930                  updateMessagesFont();                          if (sOldDisplayFont != m_pOptions->sDisplayFont)
1931              if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) ||                                  updateDisplayFont();
1932                  (!bOldMessagesLimit &&  m_pOptions->bMessagesLimit) ||                          if (iOldMaxVolume != m_pOptions->iMaxVolume)
1933                  (iOldMessagesLimitLines !=  m_pOptions->iMessagesLimitLines))                                  updateMaxVolume();
1934                  updateMessagesLimit();                          if (sOldMessagesFont != m_pOptions->sMessagesFont)
1935              // And now the main thing, whether we'll do client/server recycling?                                  updateMessagesFont();
1936              if ((sOldServerHost != m_pOptions->sServerHost) ||                          if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) ||
1937                  (iOldServerPort != m_pOptions->iServerPort) ||                                  (!bOldMessagesLimit &&  m_pOptions->bMessagesLimit) ||
1938                  (iOldServerTimeout != m_pOptions->iServerTimeout) ||                                  (iOldMessagesLimitLines !=  m_pOptions->iMessagesLimitLines))
1939                  ( bOldServerStart && !m_pOptions->bServerStart) ||                                  updateMessagesLimit();
1940                  (!bOldServerStart &&  m_pOptions->bServerStart) ||                          // And now the main thing, whether we'll do client/server recycling?
1941                  (sOldServerCmdLine != m_pOptions->sServerCmdLine && m_pOptions->bServerStart))                          if ((sOldServerHost != m_pOptions->sServerHost) ||
1942                  fileRestart();                                  (iOldServerPort != m_pOptions->iServerPort) ||
1943          }                                  (iOldServerTimeout != m_pOptions->iServerTimeout) ||
1944          // Done.                                  ( bOldServerStart && !m_pOptions->bServerStart) ||
1945          delete pOptionsForm;                                  (!bOldServerStart &&  m_pOptions->bServerStart) ||
1946      }                                  (sOldServerCmdLine != m_pOptions->sServerCmdLine
1947                                    && m_pOptions->bServerStart))
1948                                    fileRestart();
1949                    }
1950                    // Done.
1951                    delete pOptionsForm;
1952            }
1953    
1954      // This makes it.          // This makes it.
1955      stabilizeForm();          stabilizeForm();
1956  }  }
1957    
1958    
1959  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
1960  // qsamplerMainForm -- Channels action slots.  // QSampler::MainForm -- Channels action slots.
1961    
1962  // Arrange channel strips.  // Arrange channel strips.
1963  void MainForm::channelsArrange (void)  void MainForm::channelsArrange (void)
1964  {  {
1965      // Full width vertical tiling          // Full width vertical tiling
1966      QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
1967      if (wlist.isEmpty())                  = m_pWorkspace->subWindowList();
1968          return;          if (wlist.isEmpty())
1969                    return;
     m_pWorkspace->setUpdatesEnabled(false);  
     int y = 0;  
     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {  
         ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);  
     /*  if (pChannelStrip->testWState(WState_Maximized | WState_Minimized)) {  
             // Prevent flicker...  
             pChannelStrip->hide();  
             pChannelStrip->showNormal();  
         }   */  
         pChannelStrip->adjustSize();  
         int iWidth  = m_pWorkspace->width();  
         if (iWidth < pChannelStrip->width())  
             iWidth = pChannelStrip->width();  
     //  int iHeight = pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();  
         int iHeight = pChannelStrip->parentWidget()->frameGeometry().height();  
         pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight);  
         y += iHeight;  
     }  
     m_pWorkspace->setUpdatesEnabled(true);  
1970    
1971      stabilizeForm();          m_pWorkspace->setUpdatesEnabled(false);
1972            int y = 0;
1973            const int iStripCount = wlist.count();
1974            for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
1975                    QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
1976                    if (pMdiSubWindow) {
1977                            pMdiSubWindow->adjustSize();
1978                            int iWidth = m_pWorkspace->width();
1979                            if (iWidth < pMdiSubWindow->width())
1980                                    iWidth = pMdiSubWindow->width();
1981                            const int iHeight = pMdiSubWindow->frameGeometry().height();
1982                            pMdiSubWindow->setGeometry(0, y, iWidth, iHeight);
1983                            y += iHeight;
1984                    }
1985            }
1986            m_pWorkspace->setUpdatesEnabled(true);
1987    
1988            stabilizeForm();
1989  }  }
1990    
1991    
1992  // Auto-arrange channel strips.  // Auto-arrange channel strips.
1993  void MainForm::channelsAutoArrange ( bool bOn )  void MainForm::channelsAutoArrange ( bool bOn )
1994  {  {
1995      if (m_pOptions == NULL)          if (m_pOptions == NULL)
1996          return;                  return;
1997    
1998            // Toggle the auto-arrange flag.
1999            m_pOptions->bAutoArrange = bOn;
2000    
2001            // If on, update whole workspace...
2002            channelsArrangeAuto();
2003    }
2004    
     // Toggle the auto-arrange flag.  
     m_pOptions->bAutoArrange = bOn;  
2005    
2006      // If on, update whole workspace...  void MainForm::channelsArrangeAuto (void)
2007      if (m_pOptions->bAutoArrange)  {
2008          channelsArrange();          if (m_pOptions && m_pOptions->bAutoArrange)
2009                    channelsArrange();
2010  }  }
2011    
2012    
2013  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2014  // qsamplerMainForm -- Help Action slots.  // QSampler::MainForm -- Help Action slots.
2015    
2016  // Show information about the Qt toolkit.  // Show information about the Qt toolkit.
2017  void MainForm::helpAboutQt (void)  void MainForm::helpAboutQt (void)
2018  {  {
2019      QMessageBox::aboutQt(this);          QMessageBox::aboutQt(this);
2020  }  }
2021    
2022    
2023  // Show information about application program.  // Show information about application program.
2024  void MainForm::helpAbout (void)  void MainForm::helpAbout (void)
2025  {  {
2026      // 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";  
2027  #ifdef CONFIG_DEBUG  #ifdef CONFIG_DEBUG
2028      sText += "<small><font color=\"red\">";          list << tr("Debugging option enabled.");
     sText += tr("Debugging option enabled.");  
     sText += "</font></small><br />";  
2029  #endif  #endif
2030  #ifndef CONFIG_LIBGIG  #ifndef CONFIG_LIBGIG
2031      sText += "<small><font color=\"red\">";          list << tr("GIG (libgig) file support disabled.");
     sText += tr("GIG (libgig) file support disabled.");  
     sText += "</font></small><br />";  
2032  #endif  #endif
2033  #ifndef CONFIG_INSTRUMENT_NAME  #ifndef CONFIG_INSTRUMENT_NAME
2034      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 />";  
2035  #endif  #endif
2036  #ifndef CONFIG_MUTE_SOLO  #ifndef CONFIG_MUTE_SOLO
2037      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 />";  
2038  #endif  #endif
2039  #ifndef CONFIG_AUDIO_ROUTING  #ifndef CONFIG_AUDIO_ROUTING
2040      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 />";  
2041  #endif  #endif
2042  #ifndef CONFIG_FXSEND  #ifndef CONFIG_FXSEND
2043      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 />";  
2044  #endif  #endif
2045  #ifndef CONFIG_VOLUME  #ifndef CONFIG_VOLUME
2046      sText += "<small><font color=\"red\">";          list << tr("Global volume support disabled.");
     sText += tr("Global volume support disabled.");  
     sText += "</font></small><br />";  
2047  #endif  #endif
2048  #ifndef CONFIG_MIDI_INSTRUMENT  #ifndef CONFIG_MIDI_INSTRUMENT
2049      sText += "<small><font color=\"red\">";          list << tr("MIDI instrument mapping support disabled.");
     sText += tr("MIDI instrument mapping support disabled.");  
     sText += "</font></small><br />";  
2050  #endif  #endif
2051  #ifndef CONFIG_EDIT_INSTRUMENT  #ifndef CONFIG_EDIT_INSTRUMENT
2052      sText += "<small><font color=\"red\">";          list << tr("Instrument editing support disabled.");
2053      sText += tr("Instrument editing support disabled.");  #endif
2054      sText += "</font></small><br />";  #ifndef CONFIG_EVENT_CHANNEL_MIDI
2055  #endif          list << tr("Channel MIDI event support disabled.");
2056      sText += "<br />\n";  #endif
2057      sText += tr("Using") + ": ";  #ifndef CONFIG_EVENT_DEVICE_MIDI
2058      sText += ::lscp_client_package();          list << tr("Device MIDI event support disabled.");
2059      sText += " ";  #endif
2060      sText += ::lscp_client_version();  #ifndef CONFIG_MAX_VOICES
2061            list << tr("Runtime max. voices / disk streams support disabled.");
2062    #endif
2063    
2064            // Stuff the about box text...
2065            QString sText = "<p>\n";
2066            sText += "<b>" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "</b><br />\n";
2067            sText += "<br />\n";
2068            sText += tr("Version") + ": <b>" CONFIG_BUILD_VERSION "</b><br />\n";
2069    //      sText += "<small>" + tr("Build") + ": " CONFIG_BUILD_DATE "</small><br />\n";
2070            if (!list.isEmpty()) {
2071                    sText += "<small><font color=\"red\">";
2072                    sText += list.join("<br />\n");
2073                    sText += "</font></small>";
2074            }
2075            sText += "<br />\n";
2076            sText += tr("Using") + ": ";
2077            sText += ::lscp_client_package();
2078            sText += " ";
2079            sText += ::lscp_client_version();
2080  #ifdef CONFIG_LIBGIG  #ifdef CONFIG_LIBGIG
2081      sText += ", ";          sText += ", ";
2082      sText += gig::libraryName().c_str();          sText += gig::libraryName().c_str();
2083      sText += " ";          sText += " ";
2084      sText += gig::libraryVersion().c_str();          sText += gig::libraryVersion().c_str();
2085  #endif  #endif
2086      sText += "<br />\n";          sText += "<br />\n";
2087      sText += "<br />\n";          sText += "<br />\n";
2088      sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";          sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";
2089      sText += "<br />\n";          sText += "<br />\n";
2090      sText += "<small>";          sText += "<small>";
2091      sText += QSAMPLER_COPYRIGHT "<br />\n";          sText += QSAMPLER_COPYRIGHT "<br />\n";
2092      sText += QSAMPLER_COPYRIGHT2 "<br />\n";          sText += QSAMPLER_COPYRIGHT2 "<br />\n";
2093      sText += "<br />\n";          sText += "<br />\n";
2094      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";
2095      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.");
2096      sText += "</small>";          sText += "</small>";
2097      sText += "</p>\n";          sText += "</p>\n";
2098    
2099      QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText);          QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText);
2100  }  }
2101    
2102    
2103  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2104  // qsamplerMainForm -- Main window stabilization.  // QSampler::MainForm -- Main window stabilization.
2105    
2106  void MainForm::stabilizeForm (void)  void MainForm::stabilizeForm (void)
2107  {  {
2108      // Update the main application caption...          // Update the main application caption...
2109      QString sSessionName = sessionName(m_sFilename);          QString sSessionName = sessionName(m_sFilename);
2110      if (m_iDirtyCount > 0)          if (m_iDirtyCount > 0)
2111          sSessionName += " *";                  sSessionName += " *";
2112      setCaption(tr(QSAMPLER_TITLE " - [%1]").arg(sSessionName));          setWindowTitle(tr(QSAMPLER_TITLE " - [%1]").arg(sSessionName));
2113    
2114      // Update the main menu state...          // Update the main menu state...
2115      ChannelStrip* pChannelStrip = activeChannelStrip();          ChannelStrip *pChannelStrip = activeChannelStrip();
2116      bool bHasClient  = (m_pOptions != NULL && m_pClient != NULL);          const QList<QMdiSubWindow *>& wlist = m_pWorkspace->subWindowList();
2117      bool bHasChannel = (bHasClient && pChannelStrip != NULL);          const bool bHasClient = (m_pOptions != NULL && m_pClient != NULL);
2118      ui.fileNewAction->setEnabled(bHasClient);          const bool bHasChannel = (bHasClient && pChannelStrip != NULL);
2119      ui.fileOpenAction->setEnabled(bHasClient);          const bool bHasChannels = (bHasClient && wlist.count() > 0);
2120      ui.fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);          m_ui.fileNewAction->setEnabled(bHasClient);
2121      ui.fileSaveAsAction->setEnabled(bHasClient);          m_ui.fileOpenAction->setEnabled(bHasClient);
2122      ui.fileResetAction->setEnabled(bHasClient);          m_ui.fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);
2123      ui.fileRestartAction->setEnabled(bHasClient || m_pServer == NULL);          m_ui.fileSaveAsAction->setEnabled(bHasClient);
2124      ui.editAddChannelAction->setEnabled(bHasClient);          m_ui.fileResetAction->setEnabled(bHasClient);
2125      ui.editRemoveChannelAction->setEnabled(bHasChannel);          m_ui.fileRestartAction->setEnabled(bHasClient || m_pServer == NULL);
2126      ui.editSetupChannelAction->setEnabled(bHasChannel);          m_ui.editAddChannelAction->setEnabled(bHasClient);
2127            m_ui.editRemoveChannelAction->setEnabled(bHasChannel);
2128            m_ui.editSetupChannelAction->setEnabled(bHasChannel);
2129  #ifdef CONFIG_EDIT_INSTRUMENT  #ifdef CONFIG_EDIT_INSTRUMENT
2130      ui.editEditChannelAction->setEnabled(bHasChannel);          m_ui.editEditChannelAction->setEnabled(bHasChannel);
2131  #else  #else
2132      ui.editEditChannelAction->setEnabled(false);          m_ui.editEditChannelAction->setEnabled(false);
2133  #endif  #endif
2134      ui.editResetChannelAction->setEnabled(bHasChannel);          m_ui.editResetChannelAction->setEnabled(bHasChannel);
2135      ui.editResetAllChannelsAction->setEnabled(bHasChannel);          m_ui.editResetAllChannelsAction->setEnabled(bHasChannels);
2136      ui.viewMessagesAction->setOn(m_pMessages && m_pMessages->isVisible());          m_ui.viewMessagesAction->setChecked(m_pMessages && m_pMessages->isVisible());
2137  #ifdef CONFIG_MIDI_INSTRUMENT  #ifdef CONFIG_MIDI_INSTRUMENT
2138          ui.viewInstrumentsAction->setOn(m_pInstrumentListForm          m_ui.viewInstrumentsAction->setChecked(m_pInstrumentListForm
2139                  && m_pInstrumentListForm->isVisible());                  && m_pInstrumentListForm->isVisible());
2140          ui.viewInstrumentsAction->setEnabled(bHasClient);          m_ui.viewInstrumentsAction->setEnabled(bHasClient);
2141  #else  #else
2142          ui.viewInstrumentsAction->setEnabled(false);          m_ui.viewInstrumentsAction->setEnabled(false);
2143  #endif  #endif
2144          ui.viewDevicesAction->setOn(m_pDeviceForm          m_ui.viewDevicesAction->setChecked(m_pDeviceForm
2145                  && m_pDeviceForm->isVisible());                  && m_pDeviceForm->isVisible());
2146      ui.viewDevicesAction->setEnabled(bHasClient);          m_ui.viewDevicesAction->setEnabled(bHasClient);
2147      ui.channelsArrangeAction->setEnabled(bHasChannel);          m_ui.viewMidiDeviceStatusMenu->setEnabled(
2148                    DeviceStatusForm::getInstances().size() > 0);
2149            m_ui.channelsArrangeAction->setEnabled(bHasChannels);
2150    
2151  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
2152          // Toolbar widgets are also affected...          // Toolbar widgets are also affected...
2153      m_pVolumeSlider->setEnabled(bHasClient);          m_pVolumeSlider->setEnabled(bHasClient);
2154      m_pVolumeSpinBox->setEnabled(bHasClient);          m_pVolumeSpinBox->setEnabled(bHasClient);
2155  #endif  #endif
2156    
2157      // Client/Server status...          // Client/Server status...
2158      if (bHasClient) {          if (bHasClient) {
2159          m_statusItem[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));                  m_statusItem[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));
2160          m_statusItem[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost + ":" + QString::number(m_pOptions->iServerPort));                  m_statusItem[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost
2161      } else {                          + ':' + QString::number(m_pOptions->iServerPort));
2162          m_statusItem[QSAMPLER_STATUS_CLIENT]->clear();          } else {
2163          m_statusItem[QSAMPLER_STATUS_SERVER]->clear();                  m_statusItem[QSAMPLER_STATUS_CLIENT]->clear();
2164      }                  m_statusItem[QSAMPLER_STATUS_SERVER]->clear();
2165      // Channel status...          }
2166      if (bHasChannel)          // Channel status...
2167          m_statusItem[QSAMPLER_STATUS_CHANNEL]->setText(pChannelStrip->caption());          if (bHasChannel)
2168      else                  m_statusItem[QSAMPLER_STATUS_CHANNEL]->setText(pChannelStrip->windowTitle());
2169          m_statusItem[QSAMPLER_STATUS_CHANNEL]->clear();          else
2170      // Session status...                  m_statusItem[QSAMPLER_STATUS_CHANNEL]->clear();
2171      if (m_iDirtyCount > 0)          // Session status...
2172          m_statusItem[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));          if (m_iDirtyCount > 0)
2173      else                  m_statusItem[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));
2174          m_statusItem[QSAMPLER_STATUS_SESSION]->clear();          else
2175                    m_statusItem[QSAMPLER_STATUS_SESSION]->clear();
2176    
2177      // Recent files menu.          // Recent files menu.
2178      m_pRecentFilesMenu->setEnabled(bHasClient && m_pOptions->recentFiles.count() > 0);          m_ui.fileOpenRecentMenu->setEnabled(m_pOptions->recentFiles.count() > 0);
2179  }  }
2180    
2181    
# Line 1823  void MainForm::volumeChanged ( int iVolu Line 2196  void MainForm::volumeChanged ( int iVolu
2196                  m_pVolumeSpinBox->setValue(iVolume);                  m_pVolumeSpinBox->setValue(iVolume);
2197    
2198          // Do it as commanded...          // Do it as commanded...
2199          float fVolume = 0.01f * float(iVolume);          const float fVolume = 0.01f * float(iVolume);
2200          if (::lscp_set_volume(m_pClient, fVolume) == LSCP_OK)          if (::lscp_set_volume(m_pClient, fVolume) == LSCP_OK)
2201                  appendMessages(QObject::tr("Volume: %1.").arg(fVolume));                  appendMessages(QObject::tr("Volume: %1.").arg(fVolume));
2202          else          else
# Line 1839  void MainForm::volumeChanged ( int iVolu Line 2212  void MainForm::volumeChanged ( int iVolu
2212    
2213    
2214  // Channel change receiver slot.  // Channel change receiver slot.
2215  void MainForm::channelStripChanged(ChannelStrip* pChannelStrip)  void MainForm::channelStripChanged ( ChannelStrip *pChannelStrip )
2216  {  {
2217          // Add this strip to the changed list...          // Add this strip to the changed list...
2218          if (m_changedStrips.containsRef(pChannelStrip) == 0) {          if (!m_changedStrips.contains(pChannelStrip)) {
2219                  m_changedStrips.append(pChannelStrip);                  m_changedStrips.append(pChannelStrip);
2220                  pChannelStrip->resetErrorCount();                  pChannelStrip->resetErrorCount();
2221          }          }
2222    
2223      // Just mark the dirty form.          // Just mark the dirty form.
2224      m_iDirtyCount++;          m_iDirtyCount++;
2225      // and update the form status...          // and update the form status...
2226      stabilizeForm();          stabilizeForm();
2227  }  }
2228    
2229    
# Line 1858  void MainForm::channelStripChanged(Chann Line 2231  void MainForm::channelStripChanged(Chann
2231  void MainForm::updateSession (void)  void MainForm::updateSession (void)
2232  {  {
2233  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
2234          int iVolume = ::lroundf(100.0f * ::lscp_get_volume(m_pClient));          const int iVolume = ::lroundf(100.0f * ::lscp_get_volume(m_pClient));
2235          m_iVolumeChanging++;          m_iVolumeChanging++;
2236          m_pVolumeSlider->setValue(iVolume);          m_pVolumeSlider->setValue(iVolume);
2237          m_pVolumeSpinBox->setValue(iVolume);          m_pVolumeSpinBox->setValue(iVolume);
# Line 1866  void MainForm::updateSession (void) Line 2239  void MainForm::updateSession (void)
2239  #endif  #endif
2240  #ifdef CONFIG_MIDI_INSTRUMENT  #ifdef CONFIG_MIDI_INSTRUMENT
2241          // FIXME: Make some room for default instrument maps...          // FIXME: Make some room for default instrument maps...
2242          int iMaps = ::lscp_get_midi_instrument_maps(m_pClient);          const int iMaps = ::lscp_get_midi_instrument_maps(m_pClient);
2243          if (iMaps < 0)          if (iMaps < 0)
2244                  appendMessagesClient("lscp_get_midi_instrument_maps");                  appendMessagesClient("lscp_get_midi_instrument_maps");
2245          else if (iMaps < 1) {          else if (iMaps < 1) {
2246                  ::lscp_add_midi_instrument_map(m_pClient, tr("Chromatic").latin1());                  ::lscp_add_midi_instrument_map(m_pClient,
2247                  ::lscp_add_midi_instrument_map(m_pClient, tr("Drum Kits").latin1());                          tr("Chromatic").toUtf8().constData());
2248                    ::lscp_add_midi_instrument_map(m_pClient,
2249                            tr("Drum Kits").toUtf8().constData());
2250          }          }
2251  #endif  #endif
2252    
2253            updateAllChannelStrips(false);
2254    
2255            // Do we auto-arrange?
2256            channelsArrangeAuto();
2257    
2258            // Remember to refresh devices and instruments...
2259            if (m_pInstrumentListForm)
2260                    m_pInstrumentListForm->refreshInstruments();
2261            if (m_pDeviceForm)
2262                    m_pDeviceForm->refreshDevices();
2263    }
2264    
2265    
2266    void MainForm::updateAllChannelStrips ( bool bRemoveDeadStrips )
2267    {
2268            // Skip if setting up a new channel strip...
2269            if (m_iDirtySetup > 0)
2270                    return;
2271    
2272          // Retrieve the current channel list.          // Retrieve the current channel list.
2273          int *piChannelIDs = ::lscp_list_channels(m_pClient);          int *piChannelIDs = ::lscp_list_channels(m_pClient);
2274          if (piChannelIDs == NULL) {          if (piChannelIDs == NULL) {
2275                  if (::lscp_client_get_errno(m_pClient)) {                  if (::lscp_client_get_errno(m_pClient)) {
2276                          appendMessagesClient("lscp_list_channels");                          appendMessagesClient("lscp_list_channels");
2277                          appendMessagesError(tr("Could not get current list of channels.\n\nSorry."));                          appendMessagesError(
2278                                    tr("Could not get current list of channels.\n\nSorry."));
2279                  }                  }
2280          } else {          } else {
2281                  // Try to (re)create each channel.                  // Try to (re)create each channel.
2282                  m_pWorkspace->setUpdatesEnabled(false);                  m_pWorkspace->setUpdatesEnabled(false);
2283                  for (int iChannel = 0; piChannelIDs[iChannel] >= 0; iChannel++) {                  for (int iChannel = 0; piChannelIDs[iChannel] >= 0; ++iChannel) {
2284                          // Check if theres already a channel strip for this one...                          // Check if theres already a channel strip for this one...
2285                          if (!channelStrip(piChannelIDs[iChannel]))                          if (!channelStrip(piChannelIDs[iChannel]))
2286                                  createChannelStrip(new qsamplerChannel(piChannelIDs[iChannel]));                                  createChannelStrip(new Channel(piChannelIDs[iChannel]));
2287                    }
2288                    // Do we auto-arrange?
2289                    channelsArrangeAuto();
2290                    // remove dead channel strips
2291                    if (bRemoveDeadStrips) {
2292                            const QList<QMdiSubWindow *>& wlist
2293                                    = m_pWorkspace->subWindowList();
2294                            const int iStripCount = wlist.count();
2295                            for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
2296                                    ChannelStrip *pChannelStrip = NULL;
2297                                    QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2298                                    if (pMdiSubWindow)
2299                                            pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2300                                    if (pChannelStrip) {
2301                                            bool bExists = false;
2302                                            for (int iChannel = 0; piChannelIDs[iChannel] >= 0; ++iChannel) {
2303                                                    Channel *pChannel = pChannelStrip->channel();
2304                                                    if (pChannel == NULL)
2305                                                            break;
2306                                                    if (piChannelIDs[iChannel] == pChannel->channelID()) {
2307                                                            // strip exists, don't touch it
2308                                                            bExists = true;
2309                                                            break;
2310                                                    }
2311                                            }
2312                                            if (!bExists)
2313                                                    destroyChannelStrip(pChannelStrip);
2314                                    }
2315                            }
2316                  }                  }
2317                  m_pWorkspace->setUpdatesEnabled(true);                  m_pWorkspace->setUpdatesEnabled(true);
2318          }          }
2319    
2320      // 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();  
2321  }  }
2322    
2323    
2324  // Update the recent files list and menu.  // Update the recent files list and menu.
2325  void MainForm::updateRecentFiles ( const QString& sFilename )  void MainForm::updateRecentFiles ( const QString& sFilename )
2326  {  {
2327      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2328          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);  
2329    
2330      // May update the menu.          // Remove from list if already there (avoid duplicates)
2331      updateRecentFilesMenu();          const int iIndex = m_pOptions->recentFiles.indexOf(sFilename);
2332            if (iIndex >= 0)
2333                    m_pOptions->recentFiles.removeAt(iIndex);
2334            // Put it to front...
2335            m_pOptions->recentFiles.push_front(sFilename);
2336  }  }
2337    
2338    
2339  // Update the recent files list and menu.  // Update the recent files list and menu.
2340  void MainForm::updateRecentFilesMenu (void)  void MainForm::updateRecentFilesMenu (void)
2341  {  {
2342      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2343          return;                  return;
2344    
2345      // Time to keep the list under limits.          // Time to keep the list under limits.
2346      int iRecentFiles = m_pOptions->recentFiles.count();          int iRecentFiles = m_pOptions->recentFiles.count();
2347      while (iRecentFiles > m_pOptions->iMaxRecentFiles) {          while (iRecentFiles > m_pOptions->iMaxRecentFiles) {
2348          m_pOptions->recentFiles.pop_back();                  m_pOptions->recentFiles.pop_back();
2349          iRecentFiles--;                  iRecentFiles--;
2350      }          }
2351    
2352      // rebuild the recent files menu...          // Rebuild the recent files menu...
2353      m_pRecentFilesMenu->clear();          m_ui.fileOpenRecentMenu->clear();
2354      for (int i = 0; i < iRecentFiles; i++) {          for (int i = 0; i < iRecentFiles; i++) {
2355          const QString& sFilename = m_pOptions->recentFiles[i];                  const QString& sFilename = m_pOptions->recentFiles[i];
2356          if (QFileInfo(sFilename).exists()) {                  if (QFileInfo(sFilename).exists()) {
2357              m_pRecentFilesMenu->insertItem(QString("&%1 %2")                          QAction *pAction = m_ui.fileOpenRecentMenu->addAction(
2358                  .arg(i + 1).arg(sessionName(sFilename)),                                  QString("&%1 %2").arg(i + 1).arg(sessionName(sFilename)),
2359                  this, SLOT(fileOpenRecent(int)), 0, i);                                  this, SLOT(fileOpenRecent()));
2360          }                          pAction->setData(i);
2361      }                  }
2362            }
2363  }  }
2364    
2365    
2366  // Force update of the channels instrument names mode.  // Force update of the channels instrument names mode.
2367  void MainForm::updateInstrumentNames (void)  void MainForm::updateInstrumentNames (void)
2368  {  {
2369      // Full channel list update...          // Full channel list update...
2370      QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
2371      if (wlist.isEmpty())                  = m_pWorkspace->subWindowList();
2372          return;          if (wlist.isEmpty())
2373                    return;
2374      m_pWorkspace->setUpdatesEnabled(false);  
2375      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          m_pWorkspace->setUpdatesEnabled(false);
2376          ChannelStrip *pChannelStrip = (ChannelStrip *) wlist.at(iChannel);          const int iStripCount = wlist.count();
2377          if (pChannelStrip)          for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
2378              pChannelStrip->updateInstrumentName(true);                  ChannelStrip *pChannelStrip = NULL;
2379      }                  QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2380      m_pWorkspace->setUpdatesEnabled(true);                  if (pMdiSubWindow)
2381                            pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2382                    if (pChannelStrip)
2383                            pChannelStrip->updateInstrumentName(true);
2384            }
2385            m_pWorkspace->setUpdatesEnabled(true);
2386  }  }
2387    
2388    
2389  // Force update of the channels display font.  // Force update of the channels display font.
2390  void MainForm::updateDisplayFont (void)  void MainForm::updateDisplayFont (void)
2391  {  {
2392      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2393          return;                  return;
2394    
2395            // Check if display font is legal.
2396            if (m_pOptions->sDisplayFont.isEmpty())
2397                    return;
2398    
2399            // Realize it.
2400            QFont font;
2401            if (!font.fromString(m_pOptions->sDisplayFont))
2402                    return;
2403    
2404            // Full channel list update...
2405            const QList<QMdiSubWindow *>& wlist
2406                    = m_pWorkspace->subWindowList();
2407            if (wlist.isEmpty())
2408                    return;
2409    
2410      // Check if display font is legal.          m_pWorkspace->setUpdatesEnabled(false);
2411      if (m_pOptions->sDisplayFont.isEmpty())          const int iStripCount = wlist.count();
2412          return;          for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
2413      // Realize it.                  ChannelStrip *pChannelStrip = NULL;
2414      QFont font;                  QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2415      if (!font.fromString(m_pOptions->sDisplayFont))                  if (pMdiSubWindow)
2416          return;                          pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2417                    if (pChannelStrip)
2418      // Full channel list update...                          pChannelStrip->setDisplayFont(font);
2419      QWidgetList wlist = m_pWorkspace->windowList();          }
2420      if (wlist.isEmpty())          m_pWorkspace->setUpdatesEnabled(true);
         return;  
   
     m_pWorkspace->setUpdatesEnabled(false);  
     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {  
         ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);  
         if (pChannelStrip)  
             pChannelStrip->setDisplayFont(font);  
     }  
     m_pWorkspace->setUpdatesEnabled(true);  
2421  }  }
2422    
2423    
2424  // Update channel strips background effect.  // Update channel strips background effect.
2425  void MainForm::updateDisplayEffect (void)  void MainForm::updateDisplayEffect (void)
2426  {  {
2427     QPixmap pm;          // Full channel list update...
2428      if (m_pOptions->bDisplayEffect)          const QList<QMdiSubWindow *>& wlist
2429          pm = QPixmap(":/qsampler/pixmaps/displaybg1.png");                  = m_pWorkspace->subWindowList();
2430            if (wlist.isEmpty())
2431      // Full channel list update...                  return;
2432      QWidgetList wlist = m_pWorkspace->windowList();  
2433      if (wlist.isEmpty())          m_pWorkspace->setUpdatesEnabled(false);
2434          return;          const int iStripCount = wlist.count();
2435            for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
2436      m_pWorkspace->setUpdatesEnabled(false);                  ChannelStrip *pChannelStrip = NULL;
2437      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {                  QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2438          ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);                  if (pMdiSubWindow)
2439          if (pChannelStrip)                          pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2440              pChannelStrip->setDisplayBackground(pm);                  if (pChannelStrip)
2441      }                          pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
2442      m_pWorkspace->setUpdatesEnabled(true);          }
2443            m_pWorkspace->setUpdatesEnabled(true);
2444  }  }
2445    
2446    
2447  // Force update of the channels maximum volume setting.  // Force update of the channels maximum volume setting.
2448  void MainForm::updateMaxVolume (void)  void MainForm::updateMaxVolume (void)
2449  {  {
2450      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2451          return;                  return;
2452    
2453  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
2454          m_iVolumeChanging++;          m_iVolumeChanging++;
2455          m_pVolumeSlider->setMaxValue(m_pOptions->iMaxVolume);          m_pVolumeSlider->setMaximum(m_pOptions->iMaxVolume);
2456          m_pVolumeSpinBox->setMaxValue(m_pOptions->iMaxVolume);          m_pVolumeSpinBox->setMaximum(m_pOptions->iMaxVolume);
2457          m_iVolumeChanging--;          m_iVolumeChanging--;
2458  #endif  #endif
2459    
2460      // Full channel list update...          // Full channel list update...
2461      QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
2462      if (wlist.isEmpty())                  = m_pWorkspace->subWindowList();
2463          return;          if (wlist.isEmpty())
2464                    return;
2465      m_pWorkspace->setUpdatesEnabled(false);  
2466      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          m_pWorkspace->setUpdatesEnabled(false);
2467          ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);          const int iStripCount = wlist.count();
2468          if (pChannelStrip)          for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
2469              pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);                  ChannelStrip *pChannelStrip = NULL;
2470      }                  QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2471      m_pWorkspace->setUpdatesEnabled(true);                  if (pMdiSubWindow)
2472                            pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2473                    if (pChannelStrip)
2474                            pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
2475            }
2476            m_pWorkspace->setUpdatesEnabled(true);
2477  }  }
2478    
2479    
2480  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2481  // qsamplerMainForm -- Messages window form handlers.  // QSampler::MainForm -- Messages window form handlers.
2482    
2483  // Messages output methods.  // Messages output methods.
2484  void MainForm::appendMessages( const QString& s )  void MainForm::appendMessages( const QString& s )
2485  {  {
2486      if (m_pMessages)          if (m_pMessages)
2487          m_pMessages->appendMessages(s);                  m_pMessages->appendMessages(s);
2488    
2489      statusBar()->message(s, 3000);          statusBar()->showMessage(s, 3000);
2490  }  }
2491    
2492  void MainForm::appendMessagesColor( const QString& s, const QString& c )  void MainForm::appendMessagesColor( const QString& s, const QString& c )
2493  {  {
2494      if (m_pMessages)          if (m_pMessages)
2495          m_pMessages->appendMessagesColor(s, c);                  m_pMessages->appendMessagesColor(s, c);
2496    
2497      statusBar()->message(s, 3000);          statusBar()->showMessage(s, 3000);
2498  }  }
2499    
2500  void MainForm::appendMessagesText( const QString& s )  void MainForm::appendMessagesText( const QString& s )
2501  {  {
2502      if (m_pMessages)          if (m_pMessages)
2503          m_pMessages->appendMessagesText(s);                  m_pMessages->appendMessagesText(s);
2504  }  }
2505    
2506  void MainForm::appendMessagesError( const QString& s )  void MainForm::appendMessagesError( const QString& sText )
2507  {  {
2508      if (m_pMessages)          if (m_pMessages)
2509          m_pMessages->show();                  m_pMessages->show();
2510    
2511      appendMessagesColor(s.simplified(), "#ff0000");          appendMessagesColor(sText.simplified(), "#ff0000");
2512    
2513          // Make it look responsive...:)          // Make it look responsive...:)
2514          QApplication::processEvents(QEventLoop::ExcludeUserInput);          QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2515    
2516      QMessageBox::critical(this,          if (m_pOptions && m_pOptions->bConfirmError) {
2517                  QSAMPLER_TITLE ": " + tr("Error"), s, tr("Cancel"));                  const QString& sTitle = QSAMPLER_TITLE ": " + tr("Error");
2518            #if 0
2519                    QMessageBox::critical(this, sTitle, sText, QMessageBox::Cancel);
2520            #else
2521                    QMessageBox mbox(this);
2522                    mbox.setIcon(QMessageBox::Critical);
2523                    mbox.setWindowTitle(sTitle);
2524                    mbox.setText(sText);
2525                    mbox.setStandardButtons(QMessageBox::Cancel);
2526                    QCheckBox cbox(tr("Don't show this again"));
2527                    cbox.setChecked(false);
2528                    cbox.blockSignals(true);
2529                    mbox.addButton(&cbox, QMessageBox::ActionRole);
2530                    if (mbox.exec() && cbox.isChecked())
2531                            m_pOptions->bConfirmError = false;
2532            #endif
2533            }
2534  }  }
2535    
2536    
2537  // This is a special message format, just for client results.  // This is a special message format, just for client results.
2538  void MainForm::appendMessagesClient( const QString& s )  void MainForm::appendMessagesClient( const QString& s )
2539  {  {
2540      if (m_pClient == NULL)          if (m_pClient == NULL)
2541          return;                  return;
2542    
2543      appendMessagesColor(s + QString(": %1 (errno=%2)")          appendMessagesColor(s + QString(": %1 (errno=%2)")
2544          .arg(::lscp_client_get_result(m_pClient))                  .arg(::lscp_client_get_result(m_pClient))
2545          .arg(::lscp_client_get_errno(m_pClient)), "#996666");                  .arg(::lscp_client_get_errno(m_pClient)), "#996666");
2546    
2547          // Make it look responsive...:)          // Make it look responsive...:)
2548          QApplication::processEvents(QEventLoop::ExcludeUserInput);          QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2549  }  }
2550    
2551    
2552  // Force update of the messages font.  // Force update of the messages font.
2553  void MainForm::updateMessagesFont (void)  void MainForm::updateMessagesFont (void)
2554  {  {
2555      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2556          return;                  return;
2557    
2558      if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {          if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {
2559          QFont font;                  QFont font;
2560          if (font.fromString(m_pOptions->sMessagesFont))                  if (font.fromString(m_pOptions->sMessagesFont))
2561              m_pMessages->setMessagesFont(font);                          m_pMessages->setMessagesFont(font);
2562      }          }
2563  }  }
2564    
2565    
2566  // Update messages window line limit.  // Update messages window line limit.
2567  void MainForm::updateMessagesLimit (void)  void MainForm::updateMessagesLimit (void)
2568  {  {
2569      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2570          return;                  return;
2571    
2572      if (m_pMessages) {          if (m_pMessages) {
2573          if (m_pOptions->bMessagesLimit)                  if (m_pOptions->bMessagesLimit)
2574              m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);                          m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);
2575          else                  else
2576              m_pMessages->setMessagesLimit(-1);                          m_pMessages->setMessagesLimit(-1);
2577      }          }
2578  }  }
2579    
2580    
2581  // Enablement of the messages capture feature.  // Enablement of the messages capture feature.
2582  void MainForm::updateMessagesCapture (void)  void MainForm::updateMessagesCapture (void)
2583  {  {
2584      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2585          return;                  return;
2586    
2587      if (m_pMessages)          if (m_pMessages)
2588          m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);                  m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);
2589  }  }
2590    
2591    
2592  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2593  // qsamplerMainForm -- MDI channel strip management.  // QSampler::MainForm -- MDI channel strip management.
2594    
2595  // The channel strip creation executive.  // The channel strip creation executive.
2596  ChannelStrip* MainForm::createChannelStrip(qsamplerChannel* pChannel)  ChannelStrip *MainForm::createChannelStrip ( Channel *pChannel )
2597  {  {
2598      if (m_pClient == NULL || pChannel == NULL)          if (m_pClient == NULL || pChannel == NULL)
2599          return NULL;                  return NULL;
2600    
2601      // Prepare for auto-arrange?          // Add a new channel itema...
2602      ChannelStrip* pChannelStrip = NULL;          ChannelStrip *pChannelStrip = new ChannelStrip();
2603      int y = 0;          if (pChannelStrip == NULL)
2604      if (m_pOptions && m_pOptions->bAutoArrange) {                  return NULL;
         QWidgetList wlist = m_pWorkspace->windowList();  
         for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {  
             pChannelStrip = (ChannelStrip *) wlist.at(iChannel);  
                         if (pChannelStrip) {  
                         //  y += pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();  
                                 y += pChannelStrip->parentWidget()->frameGeometry().height();  
                         }  
         }  
     }  
2605    
2606      // Add a new channel itema...          // Set some initial channel strip options...
2607      pChannelStrip = new ChannelStrip(m_pWorkspace);          if (m_pOptions) {
2608      if (pChannelStrip == NULL)                  // Background display effect...
2609          return NULL;                  pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
2610                    // We'll need a display font.
2611                    QFont font;
2612                    if (!m_pOptions->sDisplayFont.isEmpty() &&
2613                            font.fromString(m_pOptions->sDisplayFont))
2614                            pChannelStrip->setDisplayFont(font);
2615                    // Maximum allowed volume setting.
2616                    pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
2617            }
2618    
2619            // Add it to workspace...
2620            m_pWorkspace->addSubWindow(pChannelStrip,
2621                    Qt::SubWindow | Qt::FramelessWindowHint);
2622    
2623            // Actual channel strip setup...
2624            pChannelStrip->setup(pChannel);
2625    
     // Actual channel strip setup...  
     pChannelStrip->setup(pChannel);  
2626          QObject::connect(pChannelStrip,          QObject::connect(pChannelStrip,
2627                  SIGNAL(channelChanged(qsamplerChannelStrip *)),                  SIGNAL(channelChanged(ChannelStrip *)),
2628                  SLOT(channelStripChanged(qsamplerChannelStrip *)));                  SLOT(channelStripChanged(ChannelStrip *)));
2629      // Set some initial aesthetic options...  
2630      if (m_pOptions) {          // Now we show up us to the world.
2631          // 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);  
     }  
2632    
2633          // This is pretty new, so we'll watch for it closely.          // This is pretty new, so we'll watch for it closely.
2634          channelStripChanged(pChannelStrip);          channelStripChanged(pChannelStrip);
2635    
2636      // Return our successful reference...          // Return our successful reference...
2637      return pChannelStrip;          return pChannelStrip;
2638    }
2639    
2640    
2641    void MainForm::destroyChannelStrip ( ChannelStrip *pChannelStrip )
2642    {
2643            QMdiSubWindow *pMdiSubWindow
2644                    = static_cast<QMdiSubWindow *> (pChannelStrip->parentWidget());
2645            if (pMdiSubWindow == NULL)
2646                    return;
2647    
2648            // Just delete the channel strip.
2649            delete pChannelStrip;
2650            delete pMdiSubWindow;
2651    
2652            // Do we auto-arrange?
2653            channelsArrangeAuto();
2654  }  }
2655    
2656    
2657  // Retrieve the active channel strip.  // Retrieve the active channel strip.
2658  ChannelStrip* MainForm::activeChannelStrip (void)  ChannelStrip *MainForm::activeChannelStrip (void)
2659  {  {
2660      return (ChannelStrip*) m_pWorkspace->activeWindow();          QMdiSubWindow *pMdiSubWindow = m_pWorkspace->activeSubWindow();
2661            if (pMdiSubWindow)
2662                    return static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2663            else
2664                    return NULL;
2665  }  }
2666    
2667    
2668  // Retrieve a channel strip by index.  // Retrieve a channel strip by index.
2669  ChannelStrip* MainForm::channelStripAt ( int iChannel )  ChannelStrip *MainForm::channelStripAt ( int iStrip )
2670  {  {
2671      QWidgetList wlist = m_pWorkspace->windowList();          if (!m_pWorkspace) return NULL;
2672      if (wlist.isEmpty())  
2673          return NULL;          const QList<QMdiSubWindow *>& wlist
2674                    = m_pWorkspace->subWindowList();
2675            if (wlist.isEmpty())
2676                    return NULL;
2677    
2678            if (iStrip < 0 || iStrip >= wlist.count())
2679                    return NULL;
2680    
2681      return (ChannelStrip*) wlist.at(iChannel);          QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2682            if (pMdiSubWindow)
2683                    return static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2684            else
2685                    return NULL;
2686  }  }
2687    
2688    
2689  // Retrieve a channel strip by sampler channel id.  // Retrieve a channel strip by sampler channel id.
2690  ChannelStrip* MainForm::channelStrip ( int iChannelID )  ChannelStrip *MainForm::channelStrip ( int iChannelID )
2691  {  {
2692          QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
2693                    = m_pWorkspace->subWindowList();
2694          if (wlist.isEmpty())          if (wlist.isEmpty())
2695                  return NULL;                  return NULL;
2696    
2697          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          const int iStripCount = wlist.count();
2698                  ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);          for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
2699                    ChannelStrip *pChannelStrip = NULL;
2700                    QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2701                    if (pMdiSubWindow)
2702                            pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2703                  if (pChannelStrip) {                  if (pChannelStrip) {
2704                          qsamplerChannel *pChannel = pChannelStrip->channel();                          Channel *pChannel = pChannelStrip->channel();
2705                          if (pChannel && pChannel->channelID() == iChannelID)                          if (pChannel && pChannel->channelID() == iChannelID)
2706                                  return pChannelStrip;                                  return pChannelStrip;
2707                  }                  }
# Line 2246  ChannelStrip* MainForm::channelStrip ( i Line 2715  ChannelStrip* MainForm::channelStrip ( i
2715  // Construct the windows menu.  // Construct the windows menu.
2716  void MainForm::channelsMenuAboutToShow (void)  void MainForm::channelsMenuAboutToShow (void)
2717  {  {
2718      ui.channelsMenu->clear();          m_ui.channelsMenu->clear();
2719      ui.channelsArrangeAction->addTo(ui.channelsMenu);          m_ui.channelsMenu->addAction(m_ui.channelsArrangeAction);
2720      ui.channelsAutoArrangeAction->addTo(ui.channelsMenu);          m_ui.channelsMenu->addAction(m_ui.channelsAutoArrangeAction);
2721    
2722      QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
2723      if (!wlist.isEmpty()) {                  = m_pWorkspace->subWindowList();
2724          ui.channelsMenu->insertSeparator();          if (!wlist.isEmpty()) {
2725          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {                  m_ui.channelsMenu->addSeparator();
2726              ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);                  const int iStripCount = wlist.count();
2727              if (pChannelStrip) {                  for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
2728                  int iItemID = ui.channelsMenu->insertItem(pChannelStrip->caption(), this, SLOT(channelsMenuActivated(int)));                          ChannelStrip *pChannelStrip = NULL;
2729                  ui.channelsMenu->setItemParameter(iItemID, iChannel);                          QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2730                  ui.channelsMenu->setItemChecked(iItemID, activeChannelStrip() == pChannelStrip);                          if (pMdiSubWindow)
2731              }                                  pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2732          }                          if (pChannelStrip) {
2733      }                                  QAction *pAction = m_ui.channelsMenu->addAction(
2734                                            pChannelStrip->windowTitle(),
2735                                            this, SLOT(channelsMenuActivated()));
2736                                    pAction->setCheckable(true);
2737                                    pAction->setChecked(activeChannelStrip() == pChannelStrip);
2738                                    pAction->setData(iStrip);
2739                            }
2740                    }
2741            }
2742  }  }
2743    
2744    
2745  // Windows menu activation slot  // Windows menu activation slot
2746  void MainForm::channelsMenuActivated ( int iChannel )  void MainForm::channelsMenuActivated (void)
2747  {  {
2748      ChannelStrip* pChannelStrip = channelStripAt(iChannel);          // Retrive channel index from action data...
2749      if (pChannelStrip)          QAction *pAction = qobject_cast<QAction *> (sender());
2750          pChannelStrip->showNormal();          if (pAction == NULL)
2751      pChannelStrip->setFocus();                  return;
2752    
2753            ChannelStrip *pChannelStrip = channelStripAt(pAction->data().toInt());
2754            if (pChannelStrip) {
2755                    pChannelStrip->showNormal();
2756                    pChannelStrip->setFocus();
2757            }
2758  }  }
2759    
2760    
2761  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2762  // qsamplerMainForm -- Timer stuff.  // QSampler::MainForm -- Timer stuff.
2763    
2764  // Set the pseudo-timer delay schedule.  // Set the pseudo-timer delay schedule.
2765  void MainForm::startSchedule ( int iStartDelay )  void MainForm::startSchedule ( int iStartDelay )
2766  {  {
2767      m_iStartDelay  = 1 + (iStartDelay * 1000);          m_iStartDelay  = 1 + (iStartDelay * 1000);
2768      m_iTimerDelay  = 0;          m_iTimerDelay  = 0;
2769  }  }
2770    
2771  // Suspend the pseudo-timer delay schedule.  // Suspend the pseudo-timer delay schedule.
2772  void MainForm::stopSchedule (void)  void MainForm::stopSchedule (void)
2773  {  {
2774      m_iStartDelay  = 0;          m_iStartDelay  = 0;
2775      m_iTimerDelay  = 0;          m_iTimerDelay  = 0;
2776  }  }
2777    
2778  // Timer slot funtion.  // Timer slot funtion.
2779  void MainForm::timerSlot (void)  void MainForm::timerSlot (void)
2780  {  {
2781      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2782          return;                  return;
2783    
2784      // Is it the first shot on server start after a few delay?          // Is it the first shot on server start after a few delay?
2785      if (m_iTimerDelay < m_iStartDelay) {          if (m_iTimerDelay < m_iStartDelay) {
2786          m_iTimerDelay += QSAMPLER_TIMER_MSECS;                  m_iTimerDelay += QSAMPLER_TIMER_MSECS;
2787          if (m_iTimerDelay >= m_iStartDelay) {                  if (m_iTimerDelay >= m_iStartDelay) {
2788              // If we cannot start it now, maybe a lil'mo'later ;)                          // If we cannot start it now, maybe a lil'mo'later ;)
2789              if (!startClient()) {                          if (!startClient()) {
2790                  m_iStartDelay += m_iTimerDelay;                                  m_iStartDelay += m_iTimerDelay;
2791                  m_iTimerDelay  = 0;                                  m_iTimerDelay  = 0;
2792              }                          }
2793          }                  }
2794      }          }
2795    
2796          if (m_pClient) {          if (m_pClient) {
2797                  // Update the channel information for each pending strip...                  // Update the channel information for each pending strip...
2798                  if (m_changedStrips.count() > 0) {                  QListIterator<ChannelStrip *> iter(m_changedStrips);
2799                          for (ChannelStrip* pChannelStrip = m_changedStrips.first();                  while (iter.hasNext()) {
2800                                          pChannelStrip; pChannelStrip = m_changedStrips.next()) {                          ChannelStrip *pChannelStrip = iter.next();
2801                                  // If successfull, remove from pending list...                          // If successfull, remove from pending list...
2802                                  if (pChannelStrip->updateChannelInfo())                          if (pChannelStrip->updateChannelInfo()) {
2803                                          m_changedStrips.remove(pChannelStrip);                                  const int iChannelStrip = m_changedStrips.indexOf(pChannelStrip);
2804                                    if (iChannelStrip >= 0)
2805                                            m_changedStrips.removeAt(iChannelStrip);
2806                          }                          }
2807                  }                  }
2808                  // Refresh each channel usage, on each period...                  // Refresh each channel usage, on each period...
# Line 2326  void MainForm::timerSlot (void) Line 2811  void MainForm::timerSlot (void)
2811                          if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime)  {                          if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime)  {
2812                                  m_iTimerSlot = 0;                                  m_iTimerSlot = 0;
2813                                  // Update the channel stream usage for each strip...                                  // Update the channel stream usage for each strip...
2814                                  QWidgetList wlist = m_pWorkspace->windowList();                                  const QList<QMdiSubWindow *>& wlist
2815                                  for (int iChannel = 0;                                          = m_pWorkspace->subWindowList();
2816                                                  iChannel < (int) wlist.count(); iChannel++) {                                  const int iStripCount = wlist.count();
2817                                          ChannelStrip* pChannelStrip                                  for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
2818                                                  = (ChannelStrip*) wlist.at(iChannel);                                          ChannelStrip *pChannelStrip = NULL;
2819                                            QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2820                                            if (pMdiSubWindow)
2821                                                    pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2822                                          if (pChannelStrip && pChannelStrip->isVisible())                                          if (pChannelStrip && pChannelStrip->isVisible())
2823                                                  pChannelStrip->updateChannelUsage();                                                  pChannelStrip->updateChannelUsage();
2824                                  }                                  }
# Line 2338  void MainForm::timerSlot (void) Line 2826  void MainForm::timerSlot (void)
2826                  }                  }
2827          }          }
2828    
2829      // Register the next timer slot.          // Register the next timer slot.
2830      QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));          QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
2831  }  }
2832    
2833    
2834  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2835  // qsamplerMainForm -- Server stuff.  // QSampler::MainForm -- Server stuff.
2836    
2837  // Start linuxsampler server...  // Start linuxsampler server...
2838  void MainForm::startServer (void)  void MainForm::startServer (void)
2839  {  {
2840      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2841          return;                  return;
2842    
2843      // Aren't already a client, are we?          // Aren't already a client, are we?
2844      if (!m_pOptions->bServerStart || m_pClient)          if (!m_pOptions->bServerStart || m_pClient)
2845          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()));  
2846    
2847      // Build process arguments...          // Is the server process instance still here?
2848      QStringList serverCmdLine = QStringList::split(' ', m_pOptions->sServerCmdLine);          if (m_pServer) {
2849                    if (QMessageBox::warning(this,
2850                            QSAMPLER_TITLE ": " + tr("Warning"),
2851                            tr("Could not start the LinuxSampler server.\n\n"
2852                            "Maybe it is already started."),
2853                            QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) {
2854                            m_pServer->terminate();
2855                            m_pServer->kill();
2856                    }
2857                    return;
2858            }
2859    
2860      appendMessages(tr("Server is starting..."));          // Reset our timer counters...
2861      appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");          stopSchedule();
2862    
2863            // Verify we have something to start with...
2864            if (m_pOptions->sServerCmdLine.isEmpty())
2865                    return;
2866    
2867            // OK. Let's build the startup process...
2868            m_pServer = new QProcess();
2869            m_bForceServerStop = true;
2870    
2871      const QString prog = (serverCmdLine.size() > 0) ? serverCmdLine[0] : QString();          // Setup stdout/stderr capture...
2872      const QStringList args = serverCmdLine.mid(1);          m_pServer->setProcessChannelMode(QProcess::ForwardedChannels);
2873            QObject::connect(m_pServer,
2874                    SIGNAL(readyReadStandardOutput()),
2875                    SLOT(readServerStdout()));
2876            QObject::connect(m_pServer,
2877                    SIGNAL(readyReadStandardError()),
2878                    SLOT(readServerStdout()));
2879    
2880      // Go jack, go...          // The unforgiveable signal communication...
2881      m_pServer->start(prog, args);          QObject::connect(m_pServer,
2882      if (!m_pServer->waitForStarted()) {                  SIGNAL(finished(int, QProcess::ExitStatus)),
2883          appendMessagesError(tr("Could not start server.\n\nSorry."));                  SLOT(processServerExit()));
         processServerExit();  
         return;  
     }  
2884    
2885      // Show startup results...          // Build process arguments...
2886      appendMessages(tr("Server was started with PID=%1.").arg((long) m_pServer->pid()));          QStringList args = m_pOptions->sServerCmdLine.split(' ');
2887            QString sCommand = args[0];
2888            args.removeAt(0);
2889    
2890            appendMessages(tr("Server is starting..."));
2891            appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");
2892    
2893            // Go linuxsampler, go...
2894            m_pServer->start(sCommand, args);
2895            if (!m_pServer->waitForStarted()) {
2896                    appendMessagesError(tr("Could not start server.\n\nSorry."));
2897                    processServerExit();
2898                    return;
2899            }
2900    
2901      // Reset (yet again) the timer counters,          // Show startup results...
2902      // but this time is deferred as the user opted.          appendMessages(
2903      startSchedule(m_pOptions->iStartDelay);                  tr("Server was started with PID=%1.").arg((long) m_pServer->pid()));
2904      stabilizeForm();  
2905            // Reset (yet again) the timer counters,
2906            // but this time is deferred as the user opted.
2907            startSchedule(m_pOptions->iStartDelay);
2908            stabilizeForm();
2909  }  }
2910    
2911    
2912  // Stop linuxsampler server...  // Stop linuxsampler server...
2913  void MainForm::stopServer (void)  void MainForm::stopServer ( bool bInteractive )
2914  {  {
2915      // Stop client code.          // Stop client code.
2916      stopClient();          stopClient();
2917    
2918      // And try to stop server.          if (m_pServer && bInteractive) {
2919      if (m_pServer) {                  if (QMessageBox::question(this,
2920          appendMessages(tr("Server is stopping..."));                          QSAMPLER_TITLE ": " + tr("The backend's fate ..."),
2921          if (m_pServer->state() == QProcess::Running)                          tr("You have the option to keep the sampler backend (LinuxSampler)\n"
2922              m_pServer->terminate();                          "running in the background. The sampler would continue to work\n"
2923       }                          "according to your current sampler session and you could alter the\n"
2924                            "sampler session at any time by relaunching QSampler.\n\n"
2925      // Give it some time to terminate gracefully and stabilize...                          "Do you want LinuxSampler to stop?"),
2926      QTime t;                          QMessageBox::Yes | QMessageBox::No,
2927      t.start();                          QMessageBox::Yes) == QMessageBox::No) {
2928      while (t.elapsed() < QSAMPLER_TIMER_MSECS)                          m_bForceServerStop = false;
2929          QApplication::processEvents(QEventLoop::ExcludeUserInput);                  }
2930            }
2931    
2932       // Do final processing anyway.          bool bGraceWait = true;
2933       processServerExit();  
2934            // And try to stop server.
2935            if (m_pServer && m_bForceServerStop) {
2936                    appendMessages(tr("Server is stopping..."));
2937                    if (m_pServer->state() == QProcess::Running) {
2938                    #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
2939                            // Try harder...
2940                            m_pServer->kill();
2941                    #else
2942                            // Try softly...
2943                            m_pServer->terminate();
2944                            bool bFinished = m_pServer->waitForFinished(QSAMPLER_TIMER_MSECS * 1000);
2945                            if (bFinished) bGraceWait = false;
2946                    #endif
2947                    }
2948            }       // Do final processing anyway.
2949            else processServerExit();
2950    
2951            // Give it some time to terminate gracefully and stabilize...
2952            if (bGraceWait) {
2953                    QTime t;
2954                    t.start();
2955                    while (t.elapsed() < QSAMPLER_TIMER_MSECS)
2956                            QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2957            }
2958  }  }
2959    
2960    
2961  // Stdout handler...  // Stdout handler...
2962  void MainForm::readServerStdout (void)  void MainForm::readServerStdout (void)
2963  {  {
2964      if (m_pMessages)          if (m_pMessages)
2965          m_pMessages->appendStdoutBuffer(m_pServer->readAllStandardOutput());                  m_pMessages->appendStdoutBuffer(m_pServer->readAllStandardOutput());
2966  }  }
2967    
2968    
2969  // Linuxsampler server cleanup.  // Linuxsampler server cleanup.
2970  void MainForm::processServerExit (void)  void MainForm::processServerExit (void)
2971  {  {
2972      // Force client code cleanup.          // Force client code cleanup.
2973      stopClient();          stopClient();
2974    
2975      // Flush anything that maybe pending...          // Flush anything that maybe pending...
2976      if (m_pMessages)          if (m_pMessages)
2977          m_pMessages->flushStdoutBuffer();                  m_pMessages->flushStdoutBuffer();
2978    
2979      if (m_pServer) {          if (m_pServer && m_bForceServerStop) {
2980          // Force final server shutdown...                  if (m_pServer->state() != QProcess::NotRunning) {
2981          appendMessages(tr("Server was stopped with exit status %1.").arg(m_pServer->exitStatus()));                          appendMessages(tr("Server is being forced..."));
2982          m_pServer->terminate();                          // Force final server shutdown...
2983          if (!m_pServer->waitForFinished(2000))                          m_pServer->kill();
2984              m_pServer->kill();                          // Give it some time to terminate gracefully and stabilize...
2985          // Destroy it.                          QTime t;
2986          delete m_pServer;                          t.start();
2987          m_pServer = NULL;                          while (t.elapsed() < QSAMPLER_TIMER_MSECS)
2988      }                                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2989                    }
2990                    // Force final server shutdown...
2991                    appendMessages(
2992                            tr("Server was stopped with exit status %1.")
2993                            .arg(m_pServer->exitStatus()));
2994                    delete m_pServer;
2995                    m_pServer = NULL;
2996            }
2997    
2998      // Again, make status visible stable.          // Again, make status visible stable.
2999      stabilizeForm();          stabilizeForm();
3000  }  }
3001    
3002    
3003  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
3004  // qsamplerMainForm -- Client stuff.  // QSampler::MainForm -- Client stuff.
3005    
3006  // The LSCP client callback procedure.  // The LSCP client callback procedure.
3007  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*/,
3008            lscp_event_t event, const char *pchData, int cchData, void *pvData )
3009  {  {
3010      MainForm* pMainForm = (MainForm *) pvData;          MainForm* pMainForm = (MainForm *) pvData;
3011      if (pMainForm == NULL)          if (pMainForm == NULL)
3012          return LSCP_FAILED;                  return LSCP_FAILED;
3013    
3014      // ATTN: DO NOT EVER call any GUI code here,          // ATTN: DO NOT EVER call any GUI code here,
3015      // as this is run under some other thread context.          // as this is run under some other thread context.
3016      // A custom event must be posted here...          // A custom event must be posted here...
3017      QApplication::postEvent(pMainForm, new qsamplerCustomEvent(event, pchData, cchData));          QApplication::postEvent(pMainForm,
3018                    new LscpEvent(event, pchData, cchData));
3019    
3020      return LSCP_OK;          return LSCP_OK;
3021  }  }
3022    
3023    
3024  // Start our almighty client...  // Start our almighty client...
3025  bool MainForm::startClient (void)  bool MainForm::startClient (void)
3026  {  {
3027      // Have it a setup?          // Have it a setup?
3028      if (m_pOptions == NULL)          if (m_pOptions == NULL)
3029          return false;                  return false;
3030    
3031      // Aren't we already started, are we?          // Aren't we already started, are we?
3032      if (m_pClient)          if (m_pClient)
3033          return true;                  return true;
3034    
3035      // Log prepare here.          // Log prepare here.
3036      appendMessages(tr("Client connecting..."));          appendMessages(tr("Client connecting..."));
3037    
3038      // Create the client handle...          // Create the client handle...
3039      m_pClient = ::lscp_client_create(m_pOptions->sServerHost.latin1(), m_pOptions->iServerPort, qsampler_client_callback, this);          m_pClient = ::lscp_client_create(
3040      if (m_pClient == NULL) {                  m_pOptions->sServerHost.toUtf8().constData(),
3041          // Is this the first try?                  m_pOptions->iServerPort, qsampler_client_callback, this);
3042          // maybe we need to start a local server...          if (m_pClient == NULL) {
3043          if ((m_pServer && m_pServer->state() == QProcess::Running) || !m_pOptions->bServerStart)                  // Is this the first try?
3044              appendMessagesError(tr("Could not connect to server as client.\n\nSorry."));                  // maybe we need to start a local server...
3045          else                  if ((m_pServer && m_pServer->state() == QProcess::Running)
3046              startServer();                          || !m_pOptions->bServerStart) {
3047          // This is always a failure.                          appendMessagesError(
3048          stabilizeForm();                                  tr("Could not connect to server as client.\n\nSorry."));
3049          return false;                  } else {
3050      }                          startServer();
3051      // Just set receive timeout value, blindly.                  }
3052      ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);                  // This is always a failure.
3053      appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));                  stabilizeForm();
3054                    return false;
3055            }
3056    
3057            // Just set receive timeout value, blindly.
3058            ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);
3059            appendMessages(
3060                    tr("Client receive timeout is set to %1 msec.")
3061                    .arg(::lscp_client_get_timeout(m_pClient)));
3062    
3063          // Subscribe to channel info change notifications...          // Subscribe to channel info change notifications...
3064            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_COUNT) != LSCP_OK)
3065                    appendMessagesClient("lscp_client_subscribe(CHANNEL_COUNT)");
3066          if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO) != LSCP_OK)          if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO) != LSCP_OK)
3067                  appendMessagesClient("lscp_client_subscribe");                  appendMessagesClient("lscp_client_subscribe(CHANNEL_INFO)");
3068    
3069      // We may stop scheduling around.          DeviceStatusForm::onDevicesChanged(); // initialize
3070      stopSchedule();          updateViewMidiDeviceStatusMenu();
3071            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT) != LSCP_OK)
3072                    appendMessagesClient("lscp_client_subscribe(MIDI_INPUT_DEVICE_COUNT)");
3073            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_INFO) != LSCP_OK)
3074                    appendMessagesClient("lscp_client_subscribe(MIDI_INPUT_DEVICE_INFO)");
3075            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT) != LSCP_OK)
3076                    appendMessagesClient("lscp_client_subscribe(AUDIO_OUTPUT_DEVICE_COUNT)");
3077            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO) != LSCP_OK)
3078                    appendMessagesClient("lscp_client_subscribe(AUDIO_OUTPUT_DEVICE_INFO)");
3079    
3080    #if CONFIG_EVENT_CHANNEL_MIDI
3081            // Subscribe to channel MIDI data notifications...
3082            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_MIDI) != LSCP_OK)
3083                    appendMessagesClient("lscp_client_subscribe(CHANNEL_MIDI)");
3084    #endif
3085    
3086    #if CONFIG_EVENT_DEVICE_MIDI
3087            // Subscribe to channel MIDI data notifications...
3088            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_DEVICE_MIDI) != LSCP_OK)
3089                    appendMessagesClient("lscp_client_subscribe(DEVICE_MIDI)");
3090    #endif
3091    
3092      // We'll accept drops from now on...          // We may stop scheduling around.
3093      setAcceptDrops(true);          stopSchedule();
3094    
3095      // Log success here.          // We'll accept drops from now on...
3096      appendMessages(tr("Client connected."));          setAcceptDrops(true);
3097    
3098            // Log success here.
3099            appendMessages(tr("Client connected."));
3100    
3101          // Hard-notify instrumnet and device configuration forms,          // Hard-notify instrumnet and device configuration forms,
3102          // if visible, that we're ready...          // if visible, that we're ready...
3103          if (m_pInstrumentListForm)          if (m_pInstrumentListForm)
3104              m_pInstrumentListForm->refreshInstruments();                  m_pInstrumentListForm->refreshInstruments();
3105          if (m_pDeviceForm)          if (m_pDeviceForm)
3106              m_pDeviceForm->refreshDevices();                  m_pDeviceForm->refreshDevices();
3107    
3108            // Is any session pending to be loaded?
3109            if (!m_pOptions->sSessionFile.isEmpty()) {
3110                    // Just load the prabably startup session...
3111                    if (loadSessionFile(m_pOptions->sSessionFile)) {
3112                            m_pOptions->sSessionFile = QString();
3113                            return true;
3114                    }
3115            }
3116    
3117      // Is any session pending to be loaded?          // send the current / loaded fine tuning settings to the sampler
3118      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;  
         }  
     }  
3119    
3120      // Make a new session          // Make a new session
3121      return newSession();          return newSession();
3122  }  }
3123    
3124    
3125  // Stop client...  // Stop client...
3126  void MainForm::stopClient (void)  void MainForm::stopClient (void)
3127  {  {
3128      if (m_pClient == NULL)          if (m_pClient == NULL)
3129          return;                  return;
   
     // Log prepare here.  
     appendMessages(tr("Client disconnecting..."));  
3130    
3131      // Clear timer counters...          // Log prepare here.
3132      stopSchedule();          appendMessages(tr("Client disconnecting..."));
3133    
3134      // We'll reject drops from now on...          // Clear timer counters...
3135      setAcceptDrops(false);          stopSchedule();
3136    
3137      // Force any channel strips around, but          // We'll reject drops from now on...
3138      // but avoid removing the corresponding          setAcceptDrops(false);
     // channels from the back-end server.  
     m_iDirtyCount = 0;  
     closeSession(false);  
3139    
3140      // Close us as a client...          // Force any channel strips around, but
3141            // but avoid removing the corresponding
3142            // channels from the back-end server.
3143            m_iDirtyCount = 0;
3144            closeSession(false);
3145    
3146            // Close us as a client...
3147    #if CONFIG_EVENT_DEVICE_MIDI
3148            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_DEVICE_MIDI);
3149    #endif
3150    #if CONFIG_EVENT_CHANNEL_MIDI
3151            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_MIDI);
3152    #endif
3153            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO);
3154            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT);
3155            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_INFO);
3156            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT);
3157          ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO);          ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO);
3158      ::lscp_client_destroy(m_pClient);          ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_COUNT);
3159      m_pClient = NULL;          ::lscp_client_destroy(m_pClient);
3160            m_pClient = NULL;
3161    
3162          // Hard-notify instrumnet and device configuration forms,          // Hard-notify instrumnet and device configuration forms,
3163          // if visible, that we're running out...          // if visible, that we're running out...
3164          if (m_pInstrumentListForm)          if (m_pInstrumentListForm)
3165              m_pInstrumentListForm->refreshInstruments();                  m_pInstrumentListForm->refreshInstruments();
3166          if (m_pDeviceForm)          if (m_pDeviceForm)
3167              m_pDeviceForm->refreshDevices();                  m_pDeviceForm->refreshDevices();
3168    
3169      // Log final here.          // Log final here.
3170      appendMessages(tr("Client disconnected."));          appendMessages(tr("Client disconnected."));
3171    
3172      // Make visible status.          // Make visible status.
3173      stabilizeForm();          stabilizeForm();
3174  }  }
3175    
3176    
3177    // Channel strip activation/selection.
3178    void MainForm::activateStrip ( QMdiSubWindow *pMdiSubWindow )
3179    {
3180            ChannelStrip *pChannelStrip = NULL;
3181            if (pMdiSubWindow)
3182                    pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
3183            if (pChannelStrip)
3184                    pChannelStrip->setSelected(true);
3185    
3186            stabilizeForm();
3187    }
3188    
3189    
3190    // Channel toolbar orientation change.
3191    void MainForm::channelsToolbarOrientation ( Qt::Orientation orientation )
3192    {
3193    #ifdef CONFIG_VOLUME
3194            m_pVolumeSlider->setOrientation(orientation);
3195            if (orientation == Qt::Horizontal) {
3196                    m_pVolumeSlider->setMinimumHeight(24);
3197                    m_pVolumeSlider->setMaximumHeight(32);
3198                    m_pVolumeSlider->setMinimumWidth(120);
3199                    m_pVolumeSlider->setMaximumWidth(640);
3200                    m_pVolumeSpinBox->setMaximumWidth(64);
3201                    m_pVolumeSpinBox->setButtonSymbols(QSpinBox::UpDownArrows);
3202            } else {
3203                    m_pVolumeSlider->setMinimumHeight(120);
3204                    m_pVolumeSlider->setMaximumHeight(480);
3205                    m_pVolumeSlider->setMinimumWidth(24);
3206                    m_pVolumeSlider->setMaximumWidth(32);
3207                    m_pVolumeSpinBox->setMaximumWidth(32);
3208                    m_pVolumeSpinBox->setButtonSymbols(QSpinBox::NoButtons);
3209            }
3210    #endif
3211    }
3212    
3213    
3214  } // namespace QSampler  } // namespace QSampler
3215    
3216    

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

  ViewVC Help
Powered by ViewVC