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

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

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

revision 1470 by schoenebeck, Sun Nov 4 23:37:47 2007 UTC revision 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 <qapplication.h>  
 #include <qeventloop.h>  
 #include <qworkspace.h>  
 #include <qprocess.h>  
 #include <qmessagebox.h>  
 //#include <qdragobject.h>  
 #include <qregexp.h>  
 #include <qfiledialog.h>  
 #include <qfileinfo.h>  
 #include <qfile.h>  
 #include <qtextstream.h>  
 #include <qstatusbar.h>  
 #include <qslider.h>  
 #include <qspinbox.h>  
 #include <qlabel.h>  
 #include <qtimer.h>  
 #include <qtooltip.h>  
   
 #include "qsamplerAbout.h"  
26  #include "qsamplerOptions.h"  #include "qsamplerOptions.h"
27  #include "qsamplerChannel.h"  #include "qsamplerChannel.h"
28  #include "qsamplerMessages.h"  #include "qsamplerMessages.h"
# Line 51  Line 33 
33  #include "qsamplerInstrumentListForm.h"  #include "qsamplerInstrumentListForm.h"
34  #include "qsamplerDeviceForm.h"  #include "qsamplerDeviceForm.h"
35  #include "qsamplerOptionsForm.h"  #include "qsamplerOptionsForm.h"
36    #include "qsamplerDeviceStatusForm.h"
37    
38    #include <QMdiArea>
39    #include <QMdiSubWindow>
40    
41    #include <QApplication>
42    #include <QProcess>
43    #include <QMessageBox>
44    
45    #include <QRegExp>
46    #include <QTextStream>
47    #include <QFileDialog>
48    #include <QFileInfo>
49    #include <QFile>
50    #include <QUrl>
51    
52    #include <QDragEnterEvent>
53    
54    #include <QStatusBar>
55    #include <QSpinBox>
56    #include <QSlider>
57    #include <QLabel>
58    #include <QTimer>
59    #include <QDateTime>
60    
61    #if QT_VERSION >= 0x050000
62    #include <QMimeData>
63    #endif
64    
65    #if QT_VERSION < 0x040500
66    namespace Qt {
67    const WindowFlags WindowCloseButtonHint = WindowFlags(0x08000000);
68    }
69    #endif
70    
71  #ifdef HAVE_SIGNAL_H  #ifdef HAVE_SIGNAL_H
72  #include <signal.h>  #include <signal.h>
# Line 73  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 83  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.setLatin1(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->setTickmarks(QSlider::Below);          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->setRange(0, 100);          m_pVolumeSlider->setSingleStep(10);
250            m_pVolumeSlider->setMinimum(0);
251            m_pVolumeSlider->setMaximum(100);
252          m_pVolumeSlider->setMaximumHeight(26);          m_pVolumeSlider->setMaximumHeight(26);
253          m_pVolumeSlider->setMinimumWidth(160);          m_pVolumeSlider->setMinimumWidth(160);
254          QToolTip::add(m_pVolumeSlider, sVolumeText);          m_pVolumeSlider->setToolTip(sVolumeText);
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->setRange(0, 100);          m_pVolumeSpinBox->setMinimum(0);
264          QToolTip::add(m_pVolumeSpinBox, sVolumeText);          m_pVolumeSpinBox->setMaximum(100);
265            m_pVolumeSpinBox->setToolTip(sVolumeText);
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);
   
     // Create the recent files sub-menu.  
     m_pRecentFilesMenu = new Q3PopupMenu(this);  
     ui.fileMenu->insertSeparator(4);  
     ui.fileMenu->insertItem(tr("Recent &Files"), m_pRecentFilesMenu, 0, 5);  
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                  SIGNAL(activated()),          // shortcuts firmly attached...
314            addAction(m_ui.viewMenubarAction);
315            addAction(m_ui.viewToolbarAction);
316    
317            QObject::connect(m_ui.fileNewAction,
318                    SIGNAL(triggered()),
319                  SLOT(fileNew()));                  SLOT(fileNew()));
320          QObject::connect(ui.fileOpenAction,          QObject::connect(m_ui.fileOpenAction,
321                  SIGNAL(activated()),                  SIGNAL(triggered()),
322                  SLOT(fileOpen()));                  SLOT(fileOpen()));
323          QObject::connect(ui.fileSaveAction,          QObject::connect(m_ui.fileSaveAction,
324                  SIGNAL(activated()),                  SIGNAL(triggered()),
325                  SLOT(fileSave()));                  SLOT(fileSave()));
326          QObject::connect(ui.fileSaveAsAction,          QObject::connect(m_ui.fileSaveAsAction,
327                  SIGNAL(activated()),                  SIGNAL(triggered()),
328                  SLOT(fileSaveAs()));                  SLOT(fileSaveAs()));
329          QObject::connect(ui.fileResetAction,          QObject::connect(m_ui.fileResetAction,
330                  SIGNAL(activated()),                  SIGNAL(triggered()),
331                  SLOT(fileReset()));                  SLOT(fileReset()));
332          QObject::connect(ui.fileRestartAction,          QObject::connect(m_ui.fileRestartAction,
333                  SIGNAL(activated()),                  SIGNAL(triggered()),
334                  SLOT(fileRestart()));                  SLOT(fileRestart()));
335          QObject::connect(ui.fileExitAction,          QObject::connect(m_ui.fileExitAction,
336                  SIGNAL(activated()),                  SIGNAL(triggered()),
337                  SLOT(fileExit()));                  SLOT(fileExit()));
338          QObject::connect(ui.editAddChannelAction,          QObject::connect(m_ui.editAddChannelAction,
339                  SIGNAL(activated()),                  SIGNAL(triggered()),
340                  SLOT(editAddChannel()));                  SLOT(editAddChannel()));
341          QObject::connect(ui.editRemoveChannelAction,          QObject::connect(m_ui.editRemoveChannelAction,
342                  SIGNAL(activated()),                  SIGNAL(triggered()),
343                  SLOT(editRemoveChannel()));                  SLOT(editRemoveChannel()));
344          QObject::connect(ui.editSetupChannelAction,          QObject::connect(m_ui.editSetupChannelAction,
345                  SIGNAL(activated()),                  SIGNAL(triggered()),
346                  SLOT(editSetupChannel()));                  SLOT(editSetupChannel()));
347          QObject::connect(ui.editEditChannelAction,          QObject::connect(m_ui.editEditChannelAction,
348                  SIGNAL(activated()),                  SIGNAL(triggered()),
349                  SLOT(editEditChannel()));                  SLOT(editEditChannel()));
350          QObject::connect(ui.editResetChannelAction,          QObject::connect(m_ui.editResetChannelAction,
351                  SIGNAL(activated()),                  SIGNAL(triggered()),
352                  SLOT(editResetChannel()));                  SLOT(editResetChannel()));
353          QObject::connect(ui.editResetAllChannelsAction,          QObject::connect(m_ui.editResetAllChannelsAction,
354                  SIGNAL(activated()),                  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(activated()),                  SIGNAL(triggered()),
370                  SLOT(viewInstruments()));                  SLOT(viewInstruments()));
371          QObject::connect(ui.viewDevicesAction,          QObject::connect(m_ui.viewDevicesAction,
372                  SIGNAL(activated()),                  SIGNAL(triggered()),
373                  SLOT(viewDevices()));                  SLOT(viewDevices()));
374          QObject::connect(ui.viewOptionsAction,          QObject::connect(m_ui.viewOptionsAction,
375                  SIGNAL(activated()),                  SIGNAL(triggered()),
376                  SLOT(viewOptions()));                  SLOT(viewOptions()));
377          QObject::connect(ui.channelsArrangeAction,          QObject::connect(m_ui.channelsArrangeAction,
378                  SIGNAL(activated()),                  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(activated()),                  SIGNAL(triggered()),
385                  SLOT(helpAbout()));                  SLOT(helpAbout()));
386          QObject::connect(ui.helpAboutQtAction,          QObject::connect(m_ui.helpAboutQtAction,
387                  SIGNAL(activated()),                  SIGNAL(triggered()),
388                  SLOT(helpAboutQt()));                  SLOT(helpAboutQt()));
389    
390            QObject::connect(m_ui.fileMenu,
391                    SIGNAL(aboutToShow()),
392                    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  #endif
412    
413      // Finally drop any widgets around...  #if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H)
414      if (m_pDeviceForm)          if (m_pUsr1Notifier)
415          delete m_pDeviceForm;                  delete m_pUsr1Notifier;
416      if (m_pInstrumentListForm)  #endif
417          delete m_pInstrumentListForm;  
418      if (m_pMessages)          // Finally drop any widgets around...
419          delete m_pMessages;          if (m_pDeviceForm)
420      if (m_pWorkspace)                  delete m_pDeviceForm;
421          delete m_pWorkspace;          if (m_pInstrumentListForm)
422                    delete m_pInstrumentListForm;
423      // Delete status item labels one by one.          if (m_pMessages)
424      if (m_statusItem[QSAMPLER_STATUS_CLIENT])                  delete m_pMessages;
425          delete m_statusItem[QSAMPLER_STATUS_CLIENT];          if (m_pWorkspace)
426      if (m_statusItem[QSAMPLER_STATUS_SERVER])                  delete m_pWorkspace;
427          delete m_statusItem[QSAMPLER_STATUS_SERVER];  
428      if (m_statusItem[QSAMPLER_STATUS_CHANNEL])          // Delete status item labels one by one.
429          delete m_statusItem[QSAMPLER_STATUS_CHANNEL];          if (m_statusItem[QSAMPLER_STATUS_CLIENT])
430      if (m_statusItem[QSAMPLER_STATUS_SESSION])                  delete m_statusItem[QSAMPLER_STATUS_CLIENT];
431          delete m_statusItem[QSAMPLER_STATUS_SESSION];          if (m_statusItem[QSAMPLER_STATUS_SERVER])
432                    delete m_statusItem[QSAMPLER_STATUS_SERVER];
433            if (m_statusItem[QSAMPLER_STATUS_CHANNEL])
434                    delete m_statusItem[QSAMPLER_STATUS_CHANNEL];
435            if (m_statusItem[QSAMPLER_STATUS_SESSION])
436                    delete m_statusItem[QSAMPLER_STATUS_SESSION];
437    
438  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
439          delete m_pVolumeSpinBox;          delete m_pVolumeSpinBox;
440          delete m_pVolumeSlider;          delete m_pVolumeSlider;
441  #endif  #endif
442    
     // Delete recentfiles menu.  
     if (m_pRecentFilesMenu)  
         delete m_pRecentFilesMenu;  
   
443          // Pseudo-singleton reference shut-down.          // Pseudo-singleton reference shut-down.
444          g_pMainForm = NULL;          g_pMainForm = NULL;
445  }  }
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::WFlags wflags = Qt::WStyle_Customize          Qt::WindowFlags wflags = Qt::Window
456                  | Qt::WStyle_NormalBorder                  | Qt::CustomizeWindowHint
457                  | Qt::WStyle_Title                  | Qt::WindowTitleHint
458                  | Qt::WStyle_SysMenu                  | Qt::WindowSystemMenuHint
459                  | Qt::WStyle_MinMax                  | Qt::WindowMinMaxButtonsHint
460                  | Qt::WType_TopLevel;                  | Qt::WindowCloseButtonHint;
461      if (m_pOptions->bKeepOnTop)          if (m_pOptions->bKeepOnTop)
462          wflags |= Qt::WStyle_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->setOn(m_pOptions->bMenubar);          m_ui.viewMenubarAction->setChecked(m_pOptions->bMenubar);
490      ui.viewToolbarAction->setOn(m_pOptions->bToolbar);          m_ui.viewToolbarAction->setChecked(m_pOptions->bToolbar);
491      ui.viewStatusbarAction->setOn(m_pOptions->bStatusbar);          m_ui.viewStatusbarAction->setChecked(m_pOptions->bStatusbar);
492      ui.channelsAutoArrangeAction->setOn(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 toolbar & dock windows states.          // Restore whole dock windows state.
502      QString sDockables = m_pOptions->settings().readEntry("/Layout/DockWindowsBase64" , QString::null);          QByteArray aDockables = m_pOptions->settings().value(
503      if (!sDockables.isEmpty()) {                  "/Layout/DockWindows").toByteArray();
504          restoreState(QByteArray::fromBase64(sDockables.toAscii()));          if (!aDockables.isEmpty()) {
505      }                  restoreState(aDockables);
506      // Try to restore old window positioning and initial visibility.          }
507      m_pOptions->loadWidgetGeometry(this);  
508      m_pOptions->loadWidgetGeometry(m_pInstrumentListForm);          // Try to restore old window positioning and initial visibility.
509      m_pOptions->loadWidgetGeometry(m_pDeviceForm);          m_pOptions->loadWidgetGeometry(this, true);
510            m_pOptions->loadWidgetGeometry(m_pInstrumentListForm);
511      // Final startup stabilization...          m_pOptions->loadWidgetGeometry(m_pDeviceForm);
512      updateMaxVolume();  
513      updateRecentFilesMenu();          // Final startup stabilization...
514      stabilizeForm();          updateMaxVolume();
515            updateRecentFilesMenu();
516            stabilizeForm();
517    
518      // Make it ready :-)          // Make it ready :-)
519      statusBar()->message(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              m_pOptions->settings().writeEntry("/Layout/DockWindowsBase64", sDockables);                          // Save the dock windows state.
548              // And the children, and the main windows state,.                          m_pOptions->settings().setValue("/Layout/DockWindows", saveState());
549                            // 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();
   
   
 // Drag'n'drop file handler.  
 bool MainForm::decodeDragFiles ( const QMimeSource *pEvent, QStringList& files )  
 {  
     bool bDecode = false;  
   
     if (Q3TextDrag::canDecode(pEvent)) {  
         QString sText;  
         bDecode = Q3TextDrag::decode(pEvent, sText);  
         if (bDecode) {  
             files = QStringList::split('\n', sText);  
             for (QStringList::Iterator iter = files.begin(); iter != files.end(); iter++)  
                 *iter = QUrl((*iter).stripWhiteSpace().replace(QRegExp("^file:"), QString::null)).path();  
         }  
     }  
   
     return bDecode;  
574  }  }
575    
576    
577  // Window drag-n-drop event handlers.  // Window drag-n-drop event handlers.
578  void MainForm::dragEnterEvent ( QDragEnterEvent* pDragEnterEvent )  void MainForm::dragEnterEvent ( QDragEnterEvent* pDragEnterEvent )
579  {  {
580          QStringList files;          // Accept external drags only...
581          pDragEnterEvent->accept(decodeDragFiles(pDragEnterEvent, files));          if (pDragEnterEvent->source() == NULL
582                    && pDragEnterEvent->mimeData()->hasUrls()) {
583                    pDragEnterEvent->accept();
584            } else {
585                    pDragEnterEvent->ignore();
586            }
587  }  }
588    
589    
590  void MainForm::dropEvent ( QDropEvent* pDropEvent )  void MainForm::dropEvent ( QDropEvent *pDropEvent )
591  {  {
592      QStringList files;          // Accept externally originated drops only...
593            if (pDropEvent->source())
594                    return;
595    
596      if (!decodeDragFiles(pDropEvent, files))          const QMimeData *pMimeData = pDropEvent->mimeData();
597          return;          if (pMimeData->hasUrls()) {
598                    QListIterator<QUrl> iter(pMimeData->urls());
599          for (QStringList::Iterator iter = files.begin(); iter != files.end(); iter++) {                  while (iter.hasNext()) {
600                  const QString& sPath = *iter;                          const QString& sPath = iter.next().toLocalFile();
601                  if (qsamplerChannel::isInstrumentFile(sPath)) {                  //      if (Channel::isDlsInstrumentFile(sPath)) {
602                          // Try to create a new channel from instrument file...                          if (QFileInfo(sPath).exists()) {
603                          qsamplerChannel *pChannel = new qsamplerChannel();                                  // Try to create a new channel from instrument file...
604                          if (pChannel == NULL)                                  Channel *pChannel = new Channel();
605                                  return;                                  if (pChannel == NULL)
606                          // Start setting the instrument filename...                                          return;
607                          pChannel->setInstrument(sPath, 0);                                  // Start setting the instrument filename...
608                          // Before we show it up, may be we'll                                  pChannel->setInstrument(sPath, 0);
609                          // better ask for some initial values?                                  // Before we show it up, may be we'll
610                          if (!pChannel->channelSetup(this)) {                                  // better ask for some initial values?
611                                  delete pChannel;                                  if (!pChannel->channelSetup(this)) {
612                                  return;                                          delete pChannel;
613                          }                                          return;
614                          // Finally, give it to a new channel strip...                                  }
615                          if (!createChannelStrip(pChannel)) {                                  // Finally, give it to a new channel strip...
616                                  delete pChannel;                                  if (!createChannelStrip(pChannel)) {
617                                  return;                                          delete pChannel;
618                                            return;
619                                    }
620                                    // Make that an overall update.
621                                    m_iDirtyCount++;
622                                    stabilizeForm();
623                            }   // Otherwise, load an usual session file (LSCP script)...
624                            else if (closeSession(true)) {
625                                    loadSessionFile(sPath);
626                                    break;
627                          }                          }
                         // Make that an overall update.  
                         m_iDirtyCount++;  
                         stabilizeForm();  
                 }   // Otherwise, load an usual session file (LSCP script)...  
                 else if (closeSession(true)) {  
                         loadSessionFile(sPath);  
                         break;  
628                  }                  }
629                  // Make it look responsive...:)                  // Make it look responsive...:)
630                  QApplication::processEvents(QEventLoop::ExcludeUserInput);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
631          }          }
632  }  }
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 571  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 597  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(          QString sFilename = QFileDialog::getOpenFileName(this,
815                  m_pOptions->sSessionDir,                // Start here.                  QSAMPLER_TITLE ": " + tr("Open Session"), // Caption.
816                  tr("LSCP Session files") + " (*.lscp)", // Filter (LSCP files)                  m_pOptions->sSessionDir,                  // Start here.
817                  this, 0,                                // Parent and name (none)                  tr("LSCP Session files") + " (*.lscp)"    // Filter (LSCP files)
818                  QSAMPLER_TITLE ": " + tr("Open Session")        // Caption.          );
     );  
   
     // Have we cancelled?  
     if (sFilename.isEmpty())  
         return false;  
   
     // Check if we're going to discard safely the current one...  
     if (!closeSession(true))  
         return false;  
819    
820      // Load it right away.          // Have we cancelled?
821      return loadSessionFile(sFilename);          if (sFilename.isEmpty())
822                    return false;
823    
824            // Check if we're going to discard safely the current one...
825            if (!closeSession(true))
826                    return false;
827    
828            // Load it right away.
829            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(                  sFilename = QFileDialog::getSaveFileName(this,
848                          sFilename,                              // Start here.                          QSAMPLER_TITLE ": " + tr("Save Session"), // Caption.
849                          tr("LSCP Session files") + " (*.lscp)", // Filter (LSCP files)                          sFilename,                                // Start here.
850                          this, 0,                                // Parent and name (none)                          tr("LSCP Session files") + " (*.lscp)"    // Filter (LSCP files)
851                          QSAMPLER_TITLE ": " + tr("Save Session")        // Caption.                  );
852          );                  // Have we cancelled it?
853          // Have we cancelled it?                  if (sFilename.isEmpty())
854          if (sFilename.isEmpty())                          return false;
855              return false;                  // Enforce .lscp extension...
856          // Enforce .lscp extension...                  if (QFileInfo(sFilename).suffix().isEmpty())
857          if (QFileInfo(sFilename).extension().isEmpty())                          sFilename += ".lscp";
858              sFilename += ".lscp";                  // Check if already exists...
859          // Check if already exists...                  if (sFilename != m_sFilename && QFileInfo(sFilename).exists()) {
860          if (sFilename != m_sFilename && QFileInfo(sFilename).exists()) {                          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.          }
     if (bClose) {  
         // Remove all channel strips from sight...  
         m_pWorkspace->setUpdatesEnabled(false);  
         QWidgetList wlist = m_pWorkspace->windowList();  
         for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {  
             ChannelStrip *pChannelStrip = (ChannelStrip*) wlist.at(iChannel);  
             if (pChannelStrip) {  
                 qsamplerChannel *pChannel = pChannelStrip->channel();  
                 if (bForce && pChannel)  
                     pChannel->removeChannel();  
                 delete pChannelStrip;  
             }  
         }  
         m_pWorkspace->setUpdatesEnabled(true);  
         // We're now clean, for sure.  
         m_iDirtyCount = 0;  
     }  
903    
904      return bClose;          // If we may close it, dot it.
905            if (bClose) {
906                    // Remove all channel strips from sight...
907                    m_pWorkspace->setUpdatesEnabled(false);
908                    const QList<QMdiSubWindow *>& wlist
909                            = m_pWorkspace->subWindowList();
910                    const int iStripCount = wlist.count();
911                    for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
912                            ChannelStrip *pChannelStrip = NULL;
913                            QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
914                            if (pMdiSubWindow)
915                                    pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
916                            if (pChannelStrip) {
917                                    Channel *pChannel = pChannelStrip->channel();
918                                    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;
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(IO_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().stripWhiteSpace();                  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";
965                          if (::lscp_client_query(m_pClient, sCommand.latin1()) != LSCP_OK) {                          if (::lscp_client_query(m_pClient, sCommand.toUtf8().constData())
966                                    != LSCP_OK) {
967                                  appendMessagesColor(QString("%1(%2): %3")                                  appendMessagesColor(QString("%1(%2): %3")
968                                          .arg(QFileInfo(sFilename).fileName()).arg(iLine)                                          .arg(QFileInfo(sFilename).fileName()).arg(iLine)
969                                          .arg(sCommand.simplifyWhiteSpace()), "#996633");                                          .arg(sCommand.simplified()), "#996633");
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::ExcludeUserInput);                  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 800  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).dirPath(true);                  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 831  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(IO_WriteOnly | IO_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 866  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.data();                          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                  for (qsamplerDevicePort *pPort = device.ports().first();                  QListIterator<DevicePort *> iter(device.ports());
1079                                  pPort;                  while (iter.hasNext()) {
1080                                          pPort = device.ports().next(), ++iPort) {                          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.data();                                  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()
1089                                          << "='" << param.value << "'" << endl;                                          << "='" << param.value << "'" << endl;
1090                          }                          }
1091                            iPort++;
1092                  }                  }
1093                  // Audio device index/id mapping.                  // Audio device index/id mapping.
1094                  audioDeviceMap[device.deviceID()] = iDevice;                  audioDeviceMap[device.deviceID()] = iDevice;
1095                  // Try to keep it snappy :)                  // Try to keep it snappy :)
1096                  QApplication::processEvents(QEventLoop::ExcludeUserInput);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1097          }          }
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.data();                          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                  for (qsamplerDevicePort *pPort = device.ports().first();                  QListIterator<DevicePort *> iter(device.ports());
1121                                  pPort;                  while (iter.hasNext()) {
1122                                          pPort = device.ports().next(), ++iPort) {                          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.data();                                  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++;
1134                  }                  }
1135                  // MIDI device index/id mapping.                  // MIDI device index/id mapping.
1136                  midiDeviceMap[device.deviceID()] = iDevice;                  midiDeviceMap[device.deviceID()] = iDevice;
1137                  // Try to keep it snappy :)                  // Try to keep it snappy :)
1138                  QApplication::processEvents(QEventLoop::ExcludeUserInput);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1139          }          }
1140          ts << endl;          ts << endl;
1141    
# Line 952  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 1000  bool MainForm::saveSessionFile ( const Q Line 1192  bool MainForm::saveSessionFile ( const Q
1192                                  iErrors++;                                  iErrors++;
1193                          }                          }
1194                          // Try to keep it snappy :)                          // Try to keep it snappy :)
1195                          QApplication::processEvents(QEventLoop::ExcludeUserInput);                          QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1196                  }                  }
1197                  ts << endl;                  ts << endl;
1198                  // Check for errors...                  // Check for errors...
# Line 1019  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.data() << 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 1083  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 1093  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::ExcludeUserInput);                  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 1123  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).dirPath(true);          }
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 1163  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    
1381  // Open a recent file session.  // Open a recent file session.
1382  void MainForm::fileOpenRecent ( int iIndex )  void MainForm::fileOpenRecent (void)
1383  {  {
1384      // Check if we can safely close the current session...          // Retrive filename index from action data...
1385      if (m_pOptions && closeSession(true)) {          QAction *pAction = qobject_cast<QAction *> (sender());
1386          QString sFilename = m_pOptions->recentFiles[iIndex];          if (pAction && m_pOptions) {
1387          loadSessionFile(sFilename);                  const int iIndex = pAction->data().toInt();
1388      }                  if (iIndex >= 0 && iIndex < m_pOptions->recentFiles.count()) {
1389                            QString sFilename = m_pOptions->recentFiles[iIndex];
1390                            // Check if we can safely close the current session...
1391                            if (!sFilename.isEmpty() && closeSession(true))
1392                                    loadSessionFile(sFilename);
1393                    }
1394            }
1395  }  }
1396    
1397    
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 1232  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 1243  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 1285  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      // Just create the channel instance...  void MainForm::addChannelStrip (void)
1540      qsamplerChannel *pChannel = new qsamplerChannel();  {
1541      if (pChannel == NULL)          if (m_pClient == NULL)
1542          return;                  return;
1543    
1544      // Before we show it up, may be we'll          // Just create the channel instance...
1545      // better ask for some initial values?          Channel *pChannel = new Channel();
1546      if (!pChannel->channelSetup(this)) {          if (pChannel == NULL)
1547          delete pChannel;                  return;
1548          return;  
1549      }          // Before we show it up, may be we'll
1550            // better ask for some initial values?
1551      // And give it to the strip (will own the channel instance, if successful).          if (!pChannel->channelSetup(this)) {
1552      if (!createChannelStrip(pChannel)) {                  delete pChannel;
1553          delete pChannel;                  return;
1554          return;          }
1555      }  
1556            // And give it to the strip...
1557      // Make that an overall update.          // (will own the channel instance, if successful).
1558      m_iDirtyCount++;          if (!createChannelStrip(pChannel)) {
1559      stabilizeForm();                  delete pChannel;
1560                    return;
1561            }
1562    
1563            // Do we auto-arrange?
1564            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      ChannelStrip* pChannelStrip = activeChannelStrip();  void MainForm::removeChannelStrip (void)
1582      if (pChannelStrip == NULL)  {
1583          return;          if (m_pClient == NULL)
1584                    return;
1585      qsamplerChannel *pChannel = pChannelStrip->channel();  
1586      if (pChannel == NULL)          ChannelStrip *pChannelStrip = activeChannelStrip();
1587          return;          if (pChannelStrip == NULL)
1588                    return;
1589      // Prompt user if he/she's sure about this...  
1590      if (m_pOptions && m_pOptions->bConfirmRemove) {          Channel *pChannel = pChannelStrip->channel();
1591          if (QMessageBox::warning(this,          if (pChannel == NULL)
1592                          QSAMPLER_TITLE ": " + tr("Warning"),                  return;
1593              tr("About to remove channel:\n\n"  
1594                 "%1\n\n"          // Prompt user if he/she's sure about this...
1595                 "Are you sure?")          if (m_pOptions && m_pOptions->bConfirmRemove) {
1596                 .arg(pChannelStrip->caption()),                  const QString& sTitle = QSAMPLER_TITLE ": " + tr("Warning");
1597              tr("OK"), tr("Cancel")) > 0)                  const QString& sText = tr(
1598              return;                          "About to remove channel:\n\n"
1599      }                          "%1\n\n"
1600                            "Are you sure?")
1601      // Remove the existing sampler channel.                          .arg(pChannelStrip->windowTitle());
1602      if (!pChannel->removeChannel())          #if 0
1603          return;                  if (QMessageBox::warning(this, sTitle, sText,
1604                            QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
1605      // Just delete the channel strip.                          return;
1606      delete pChannelStrip;          #else
1607                    QMessageBox mbox(this);
1608      // Do we auto-arrange?                  mbox.setIcon(QMessageBox::Warning);
1609      if (m_pOptions && m_pOptions->bAutoArrange)                  mbox.setWindowTitle(sTitle);
1610          channelsArrange();                  mbox.setText(sText);
1611                    mbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
1612      // We'll be dirty, for sure...                  QCheckBox cbox(tr("Don't ask this again"));
1613      m_iDirtyCount++;                  cbox.setChecked(false);
1614      stabilizeForm();                  cbox.blockSignals(true);
1615                    mbox.addButton(&cbox, QMessageBox::ActionRole);
1616                    if (mbox.exec() == QMessageBox::Cancel)
1617                            return;
1618                    if (cbox.isChecked())
1619                            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 1409  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 1425  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 1480  void MainForm::viewInstruments (void) Line 1763  void MainForm::viewInstruments (void)
1763                  } else {                  } else {
1764                          m_pInstrumentListForm->show();                          m_pInstrumentListForm->show();
1765                          m_pInstrumentListForm->raise();                          m_pInstrumentListForm->raise();
1766                          m_pInstrumentListForm->setActiveWindow();                          m_pInstrumentListForm->activateWindow();
1767                  }                  }
1768          }          }
1769  }  }
# Line 1499  void MainForm::viewDevices (void) Line 1782  void MainForm::viewDevices (void)
1782                  } else {                  } else {
1783                          m_pDeviceForm->show();                          m_pDeviceForm->show();
1784                          m_pDeviceForm->raise();                          m_pDeviceForm->raise();
1785                          m_pDeviceForm->setActiveWindow();                          m_pDeviceForm->activateWindow();
1786                  }                  }
1787          }          }
1788  }  }
# Line 1508  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 1596  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 1646  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 1737  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      setCaption(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->setOn(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->setOn(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->setOn(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->caption());          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      m_pRecentFilesMenu->setEnabled(bHasClient && m_pOptions->recentFiles.count() > 0);          m_ui.fileOpenRecentMenu->setEnabled(m_pOptions->recentFiles.count() > 0);
2117  }  }
2118    
2119    
# Line 1823  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 1839  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.containsRef(pChannelStrip) == 0) {          if (!m_changedStrips.contains(pChannelStrip)) {
2157                  m_changedStrips.append(pChannelStrip);                  m_changedStrips.append(pChannelStrip);
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 1858  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 1866  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) {
2184                  ::lscp_add_midi_instrument_map(m_pClient, tr("Chromatic").latin1());                  ::lscp_add_midi_instrument_map(m_pClient,
2185                  ::lscp_add_midi_instrument_map(m_pClient, tr("Drum Kits").latin1());                          tr("Chromatic").toUtf8().constData());
2186                    ::lscp_add_midi_instrument_map(m_pClient,
2187                            tr("Drum Kits").toUtf8().constData());
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;
   
     // Remove from list if already there (avoid duplicates)  
     QStringList::Iterator iter = m_pOptions->recentFiles.find(sFilename);  
     if (iter != m_pOptions->recentFiles.end())  
         m_pOptions->recentFiles.remove(iter);  
     // Put it to front...  
     m_pOptions->recentFiles.push_front(sFilename);  
2269    
2270      // May update the menu.          // Remove from list if already there (avoid duplicates)
2271      updateRecentFilesMenu();          const int iIndex = m_pOptions->recentFiles.indexOf(sFilename);
2272            if (iIndex >= 0)
2273                    m_pOptions->recentFiles.removeAt(iIndex);
2274            // Put it to front...
2275            m_pOptions->recentFiles.push_front(sFilename);
2276  }  }
2277    
2278    
2279  // Update the recent files list and menu.  // Update the recent files list and menu.
2280  void MainForm::updateRecentFilesMenu (void)  void MainForm::updateRecentFilesMenu (void)
2281  {  {
2282      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2283          return;                  return;
2284    
2285            // Time to keep the list under limits.
2286            int iRecentFiles = m_pOptions->recentFiles.count();
2287            while (iRecentFiles > m_pOptions->iMaxRecentFiles) {
2288                    m_pOptions->recentFiles.pop_back();
2289                    iRecentFiles--;
2290            }
2291    
2292      // Time to keep the list under limits.          // Rebuild the recent files menu...
2293      int iRecentFiles = m_pOptions->recentFiles.count();          m_ui.fileOpenRecentMenu->clear();
2294      while (iRecentFiles > m_pOptions->iMaxRecentFiles) {          for (int i = 0; i < iRecentFiles; i++) {
2295          m_pOptions->recentFiles.pop_back();                  const QString& sFilename = m_pOptions->recentFiles[i];
2296          iRecentFiles--;                  if (QFileInfo(sFilename).exists()) {
2297      }                          QAction *pAction = m_ui.fileOpenRecentMenu->addAction(
2298                                    QString("&%1 %2").arg(i + 1).arg(sessionName(sFilename)),
2299      // rebuild the recent files menu...                                  this, SLOT(fileOpenRecent()));
2300      m_pRecentFilesMenu->clear();                          pAction->setData(i);
2301      for (int i = 0; i < iRecentFiles; i++) {                  }
2302          const QString& sFilename = m_pOptions->recentFiles[i];          }
         if (QFileInfo(sFilename).exists()) {  
             m_pRecentFilesMenu->insertItem(QString("&%1 %2")  
                 .arg(i + 1).arg(sessionName(sFilename)),  
                 this, SLOT(fileOpenRecent(int)), 0, i);  
         }  
     }  
2303  }  }
2304    
2305    
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            // Realize it.
2340            QFont font;
2341            if (!font.fromString(m_pOptions->sDisplayFont))
2342                    return;
2343    
2344      // Check if display font is legal.          // Full channel list update...
2345      if (m_pOptions->sDisplayFont.isEmpty())          const QList<QMdiSubWindow *>& wlist
2346          return;                  = m_pWorkspace->subWindowList();
2347      // Realize it.          if (wlist.isEmpty())
2348      QFont font;                  return;
2349      if (!font.fromString(m_pOptions->sDisplayFont))  
2350          return;          m_pWorkspace->setUpdatesEnabled(false);
2351            const int iStripCount = wlist.count();
2352      // Full channel list update...          for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
2353      QWidgetList wlist = m_pWorkspace->windowList();                  ChannelStrip *pChannelStrip = NULL;
2354      if (wlist.isEmpty())                  QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2355          return;                  if (pMdiSubWindow)
2356                            pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2357      m_pWorkspace->setUpdatesEnabled(false);                  if (pChannelStrip)
2358      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {                          pChannelStrip->setDisplayFont(font);
2359          ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);          }
2360          if (pChannelStrip)          m_pWorkspace->setUpdatesEnabled(true);
             pChannelStrip->setDisplayFont(font);  
     }  
     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     QPixmap pm;          // Full channel list update...
2368      if (m_pOptions->bDisplayEffect)          const QList<QMdiSubWindow *>& wlist
2369          pm = QPixmap(":/qsampler/pixmaps/displaybg1.png");                  = m_pWorkspace->subWindowList();
2370            if (wlist.isEmpty())
2371      // Full channel list update...                  return;
2372      QWidgetList wlist = m_pWorkspace->windowList();  
2373      if (wlist.isEmpty())          m_pWorkspace->setUpdatesEnabled(false);
2374          return;          const int iStripCount = wlist.count();
2375            for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
2376      m_pWorkspace->setUpdatesEnabled(false);                  ChannelStrip *pChannelStrip = NULL;
2377      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {                  QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2378          ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);                  if (pMdiSubWindow)
2379          if (pChannelStrip)                          pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2380              pChannelStrip->setDisplayBackground(pm);                  if (pChannelStrip)
2381      }                          pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
2382      m_pWorkspace->setUpdatesEnabled(true);          }
2383            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++;
2395          m_pVolumeSlider->setMaxValue(m_pOptions->iMaxVolume);          m_pVolumeSlider->setMaximum(m_pOptions->iMaxVolume);
2396          m_pVolumeSpinBox->setMaxValue(m_pOptions->iMaxVolume);          m_pVolumeSpinBox->setMaximum(m_pOptions->iMaxVolume);
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 2052  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()->message(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()->message(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.simplifyWhiteSpace(), "#ff0000");          appendMessagesColor(sText.simplified(), "#ff0000");
2452    
2453          // Make it look responsive...:)          // Make it look responsive...:)
2454          QApplication::processEvents(QEventLoop::ExcludeUserInput);          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::ExcludeUserInput);          QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2489  }  }
2490    
2491    
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 2146  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 = (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      Qt::WFlags wflags = Qt::WStyle_Customize | Qt::WStyle_Tool | Qt::WStyle_Title | Qt::WStyle_NoBorder;          if (m_pOptions) {
2548      pChannelStrip = new ChannelStrip(m_pWorkspace, wflags);                  // Background display effect...
2549      if (pChannelStrip == NULL)                  pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
2550          return NULL;                  // 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            // 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(qsamplerChannelStrip *)),                  SIGNAL(channelChanged(ChannelStrip *)),
2568                  SLOT(channelStripChanged(qsamplerChannelStrip *)));                  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 (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;
     if (wlist.isEmpty())  
         return NULL;  
2613    
2614      return (ChannelStrip*) wlist.at(iChannel);          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            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 = (ChannelStrip*) wlist.at(iChannel);          for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
2640                    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.channelsArrangeAction->addTo(ui.channelsMenu);          m_ui.channelsMenu->addAction(m_ui.channelsArrangeAction);
2661      ui.channelsAutoArrangeAction->addTo(ui.channelsMenu);          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->insertSeparator();          if (!wlist.isEmpty()) {
2666          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {                  m_ui.channelsMenu->addSeparator();
2667              ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);                  const int iStripCount = wlist.count();
2668              if (pChannelStrip) {                  for (int iStrip = 0; iStrip < iStripCount; ++iStrip) {
2669                  int iItemID = ui.channelsMenu->insertItem(pChannelStrip->caption(), this, SLOT(channelsMenuActivated(int)));                          ChannelStrip *pChannelStrip = NULL;
2670                  ui.channelsMenu->setItemParameter(iItemID, iChannel);                          QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2671                  ui.channelsMenu->setItemChecked(iItemID, activeChannelStrip() == pChannelStrip);                          if (pMdiSubWindow)
2672              }                                  pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2673          }                          if (pChannelStrip) {
2674      }                                  QAction *pAction = m_ui.channelsMenu->addAction(
2675                                            pChannelStrip->windowTitle(),
2676                                            this, SLOT(channelsMenuActivated()));
2677                                    pAction->setCheckable(true);
2678                                    pAction->setChecked(activeChannelStrip() == pChannelStrip);
2679                                    pAction->setData(iStrip);
2680                            }
2681                    }
2682            }
2683  }  }
2684    
2685    
2686  // Windows menu activation slot  // Windows menu activation slot
2687  void MainForm::channelsMenuActivated ( int iChannel )  void MainForm::channelsMenuActivated (void)
2688  {  {
2689      ChannelStrip* pChannelStrip = channelStripAt(iChannel);          // Retrive channel index from action data...
2690      if (pChannelStrip)          QAction *pAction = qobject_cast<QAction *> (sender());
2691          pChannelStrip->showNormal();          if (pAction == NULL)
2692      pChannelStrip->setFocus();                  return;
2693    
2694            ChannelStrip *pChannelStrip = channelStripAt(pAction->data().toInt());
2695            if (pChannelStrip) {
2696                    pChannelStrip->showNormal();
2697                    pChannelStrip->setFocus();
2698            }
2699  }  }
2700    
2701    
# Line 2282  void MainForm::channelsMenuActivated ( i Line 2705  void MainForm::channelsMenuActivated ( i
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...
2739                  if (m_changedStrips.count() > 0) {                  QListIterator<ChannelStrip *> iter(m_changedStrips);
2740                          for (ChannelStrip* pChannelStrip = m_changedStrips.first();                  while (iter.hasNext()) {
2741                                          pChannelStrip; pChannelStrip = m_changedStrips.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                                          m_changedStrips.remove(pChannelStrip);                                  const int iChannelStrip = m_changedStrips.indexOf(pChannelStrip);
2745                                    if (iChannelStrip >= 0)
2746                                            m_changedStrips.removeAt(iChannelStrip);
2747                          }                          }
2748                  }                  }
2749                  // Refresh each channel usage, on each period...                  // Refresh each channel usage, on each period...
# Line 2327  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 2339  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 2350  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 = QStringList::split(' ', m_pOptions->sServerCmdLine);          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      // And try to stop server.          if (m_pServer && bInteractive) {
2860      if (m_pServer) {                  if (QMessageBox::question(this,
2861          appendMessages(tr("Server is stopping..."));                          QSAMPLER_TITLE ": " + tr("The backend's fate ..."),
2862          if (m_pServer->state() == QProcess::Running)                          tr("You have the option to keep the sampler backend (LinuxSampler)\n"
2863              m_pServer->terminate();                          "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      // Give it some time to terminate gracefully and stabilize...                          "Do you want LinuxSampler to stop?"),
2867      QTime t;                          QMessageBox::Yes | QMessageBox::No,
2868      t.start();                          QMessageBox::Yes) == QMessageBox::No)
2869      while (t.elapsed() < QSAMPLER_TIMER_MSECS)                  {
2870          QApplication::processEvents(QEventLoop::ExcludeUserInput);                          bForceServerStop = false;
2871                    }
2872            }
2873    
2874            // And try to stop server.
2875            if (m_pServer && bForceServerStop) {
2876                    appendMessages(tr("Server is stopping..."));
2877                    if (m_pServer->state() == QProcess::Running) {
2878                    #if defined(WIN32)
2879                            // Try harder...
2880                            m_pServer->kill();
2881                    #else
2882                            // Try softly...
2883                            m_pServer->terminate();
2884                    #endif
2885                    }
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 2487  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;
2966    
2967      // Aren't we already started, are we?          // Aren't we already started, are we?
2968      if (m_pClient)          if (m_pClient)
2969          return true;                  return true;
2970    
2971      // Log prepare here.          // Log prepare here.
2972      appendMessages(tr("Client connecting..."));          appendMessages(tr("Client connecting..."));
2973    
2974      // Create the client handle...          // Create the client handle...
2975      m_pClient = ::lscp_client_create(m_pOptions->sServerHost.latin1(), m_pOptions->iServerPort, qsampler_client_callback, this);          m_pClient = ::lscp_client_create(
2976      if (m_pClient == NULL) {                  m_pOptions->sServerHost.toUtf8().constData(),
2977          // Is this the first try?                  m_pOptions->iServerPort, qsampler_client_callback, this);
2978          // maybe we need to start a local server...          if (m_pClient == NULL) {
2979          if ((m_pServer && m_pServer->state() == QProcess::Running) || !m_pOptions->bServerStart)                  // Is this the first try?
2980              appendMessagesError(tr("Could not connect to server as client.\n\nSorry."));                  // maybe we need to start a local server...
2981          else                  if ((m_pServer && m_pServer->state() == QProcess::Running)
2982              startServer();                          || !m_pOptions->bServerStart) {
2983          // This is always a failure.                          appendMessagesError(
2984          stabilizeForm();                                  tr("Could not connect to server as client.\n\nSorry."));
2985          return false;                  } else {
2986      }                          startServer();
2987      // Just set receive timeout value, blindly.                  }
2988      ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);                  // This is always a failure.
2989      appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));                  stabilizeForm();
2990                    return false;
2991            }
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            DeviceStatusForm::onDevicesChanged(); // initialize
3005            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 may stop scheduling around.          // We may stop scheduling around.
3028      stopSchedule();          stopSchedule();
3029    
3030      // We'll accept drops from now on...          // We'll accept drops from now on...
3031      setAcceptDrops(true);          setAcceptDrops(true);
3032    
3033      // Log success here.          // Log success here.
3034      appendMessages(tr("Client connected."));          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?          // Is any session pending to be loaded?
3044      if (!m_pOptions->sSessionFile.isEmpty()) {          if (!m_pOptions->sSessionFile.isEmpty()) {
3045          // Just load the prabably startup session...                  // Just load the prabably startup session...
3046          if (loadSessionFile(m_pOptions->sSessionFile)) {                  if (loadSessionFile(m_pOptions->sSessionFile)) {
3047              m_pOptions->sSessionFile = QString::null;                          m_pOptions->sSessionFile = QString::null;
3048              return true;                          return true;
3049          }                  }
3050      }          }
3051    
3052            // send the current / loaded fine tuning settings to the sampler
3053            m_pOptions->sendFineTuningSettings();
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.1470  
changed lines
  Added in v.2978

  ViewVC Help
Powered by ViewVC