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

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

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

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

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

  ViewVC Help
Powered by ViewVC