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

Legend:
Removed from v.1499  
changed lines
  Added in v.2978

  ViewVC Help
Powered by ViewVC