/[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 1461 by schoenebeck, Sun Oct 28 23:30:36 2007 UTC revision 1738 by capela, Wed May 14 15:24:22 2008 UTC
# Line 1  Line 1 
1  #include "qsamplerMainForm.h"  // qsamplerMainForm.cpp
2    //
3    /****************************************************************************
4       Copyright (C) 2004-2008, rncbc aka Rui Nuno Capela. All rights reserved.
5       Copyright (C) 2007, 2008 Christian Schoenebeck
6    
7       This program is free software; you can redistribute it and/or
8       modify it under the terms of the GNU General Public License
9       as published by the Free Software Foundation; either version 2
10       of the License, or (at your option) any later version.
11    
12       This program is distributed in the hope that it will be useful,
13       but WITHOUT ANY WARRANTY; without even the implied warranty of
14       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15       GNU General Public License for more details.
16    
17       You should have received a copy of the GNU General Public License along
18       with this program; if not, write to the Free Software Foundation, Inc.,
19       51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20    
21  #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>  
22    
23  #include "qsamplerAbout.h"  #include "qsamplerAbout.h"
24    #include "qsamplerMainForm.h"
25    
26  #include "qsamplerOptions.h"  #include "qsamplerOptions.h"
27  #include "qsamplerChannel.h"  #include "qsamplerChannel.h"
28  #include "qsamplerMessages.h"  #include "qsamplerMessages.h"
# Line 29  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 <QApplication>
39    #include <QWorkspace>
40    #include <QProcess>
41    #include <QMessageBox>
42    
43    #include <QRegExp>
44    #include <QTextStream>
45    #include <QFileDialog>
46    #include <QFileInfo>
47    #include <QFile>
48    #include <QUrl>
49    
50    #include <QDragEnterEvent>
51    
52    #include <QStatusBar>
53    #include <QSpinBox>
54    #include <QSlider>
55    #include <QLabel>
56    #include <QTimer>
57    #include <QDateTime>
58    
59    
60  #ifdef HAVE_SIGNAL_H  #ifdef HAVE_SIGNAL_H
61  #include <signal.h>  #include <signal.h>
# Line 51  static inline long lroundf ( float x ) Line 78  static inline long lroundf ( float x )
78  }  }
79  #endif  #endif
80    
81    
82    // All winsock apps needs this.
83    #if defined(WIN32)
84    static WSADATA _wsaData;
85    #endif
86    
87    
88    namespace QSampler {
89    
90  // Timer constant stuff.  // Timer constant stuff.
91  #define QSAMPLER_TIMER_MSECS    200  #define QSAMPLER_TIMER_MSECS    200
92    
# Line 61  static inline long lroundf ( float x ) Line 97  static inline long lroundf ( float x )
97  #define QSAMPLER_STATUS_SESSION 3       // Current session modification state.  #define QSAMPLER_STATUS_SESSION 3       // Current session modification state.
98    
99    
 // All winsock apps needs this.  
 #if defined(WIN32)  
 static WSADATA _wsaData;  
 #endif  
   
   
100  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
101  // qsamplerCustomEvent -- specialty for callback comunication.  // CustomEvent -- specialty for callback comunication.
102    
103  #define QSAMPLER_CUSTOM_EVENT   QEvent::Type(QEvent::User + 0)  #define QSAMPLER_CUSTOM_EVENT   QEvent::Type(QEvent::User + 0)
104    
105  class qsamplerCustomEvent : public QEvent  class CustomEvent : public QEvent
106  {  {
107  public:  public:
108    
109      // Constructor.          // Constructor.
110      qsamplerCustomEvent(lscp_event_t event, const char *pchData, int cchData)          CustomEvent(lscp_event_t event, const char *pchData, int cchData)
111          : QEvent(QSAMPLER_CUSTOM_EVENT)                  : QEvent(QSAMPLER_CUSTOM_EVENT)
112      {          {
113          m_event = event;                  m_event = event;
114          m_data.setLatin1(pchData, cchData);                  m_data  = QString::fromUtf8(pchData, cchData);
115      }          }
116    
117      // Accessors.          // Accessors.
118      lscp_event_t event() { return m_event; }          lscp_event_t event() { return m_event; }
119      QString&     data()  { return m_data;  }          QString&     data()  { return m_data;  }
120    
121  private:  private:
122    
123      // The proper event type.          // The proper event type.
124      lscp_event_t m_event;          lscp_event_t m_event;
125      // The event data as a string.          // The event data as a string.
126      QString      m_data;          QString      m_data;
127  };  };
128    
129    
130  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
131  // qsamplerMainForm -- Main window form implementation.  // qsamplerMainForm -- Main window form implementation.
132    
 namespace QSampler {  
   
133  // Kind of singleton reference.  // Kind of singleton reference.
134  MainForm* MainForm::g_pMainForm = NULL;  MainForm* MainForm::g_pMainForm = NULL;
135    
136  MainForm::MainForm(QWidget* parent) : QMainWindow(parent) {  MainForm::MainForm ( QWidget *pParent )
137      ui.setupUi(this);          : QMainWindow(pParent)
138    {
139      fileToolbar     = addToolBar(tr("File"));          m_ui.setupUi(this);
     editToolbar     = addToolBar(tr("Edit"));  
     channelsToolbar = addToolBar(tr("Channels"));  
140    
141          // Pseudo-singleton reference setup.          // Pseudo-singleton reference setup.
142          g_pMainForm = this;          g_pMainForm = this;
143    
144      // Initialize some pointer references.          // Initialize some pointer references.
145      m_pOptions = NULL;          m_pOptions = NULL;
146    
147      // All child forms are to be created later, not earlier than setup.          // All child forms are to be created later, not earlier than setup.
148      m_pMessages = NULL;          m_pMessages = NULL;
149      m_pInstrumentListForm = NULL;          m_pInstrumentListForm = NULL;
150      m_pDeviceForm = NULL;          m_pDeviceForm = NULL;
151    
152      // We'll start clean.          // We'll start clean.
153      m_iUntitled   = 0;          m_iUntitled   = 0;
154      m_iDirtyCount = 0;          m_iDirtyCount = 0;
155    
156      m_pServer = NULL;          m_pServer = NULL;
157      m_pClient = NULL;          m_pClient = NULL;
158    
159      m_iStartDelay = 0;          m_iStartDelay = 0;
160      m_iTimerDelay = 0;          m_iTimerDelay = 0;
161    
162      m_iTimerSlot = 0;          m_iTimerSlot = 0;
163    
164  #ifdef HAVE_SIGNAL_H  #ifdef HAVE_SIGNAL_H
165          // Set to ignore any fatal "Broken pipe" signals.          // Set to ignore any fatal "Broken pipe" signals.
# Line 141  MainForm::MainForm(QWidget* parent) : QM Line 167  MainForm::MainForm(QWidget* parent) : QM
167  #endif  #endif
168    
169  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
170      // Make some extras into the toolbar...          // Make some extras into the toolbar...
171          const QString& sVolumeText = tr("Master volume");          const QString& sVolumeText = tr("Master volume");
172          m_iVolumeChanging = 0;          m_iVolumeChanging = 0;
173          // Volume slider...          // Volume slider...
174          channelsToolbar->addSeparator();          m_ui.channelsToolbar->addSeparator();
175          m_pVolumeSlider = new QSlider(Qt::Horizontal, channelsToolbar);          m_pVolumeSlider = new QSlider(Qt::Horizontal, m_ui.channelsToolbar);
176          m_pVolumeSlider->setTickmarks(QSlider::Below);          m_pVolumeSlider->setTickPosition(QSlider::TicksBothSides);
177          m_pVolumeSlider->setTickInterval(10);          m_pVolumeSlider->setTickInterval(10);
178          m_pVolumeSlider->setPageStep(10);          m_pVolumeSlider->setPageStep(10);
179          m_pVolumeSlider->setRange(0, 100);          m_pVolumeSlider->setSingleStep(10);
180          m_pVolumeSlider->setMaximumHeight(22);          m_pVolumeSlider->setMinimum(0);
181            m_pVolumeSlider->setMaximum(100);
182            m_pVolumeSlider->setMaximumHeight(26);
183          m_pVolumeSlider->setMinimumWidth(160);          m_pVolumeSlider->setMinimumWidth(160);
184          QToolTip::add(m_pVolumeSlider, sVolumeText);          m_pVolumeSlider->setToolTip(sVolumeText);
185          QObject::connect(m_pVolumeSlider,          QObject::connect(m_pVolumeSlider,
186                  SIGNAL(valueChanged(int)),                  SIGNAL(valueChanged(int)),
187                  SLOT(volumeChanged(int)));                  SLOT(volumeChanged(int)));
188          //channelsToolbar->setHorizontallyStretchable(true);          //m_ui.channelsToolbar->setHorizontallyStretchable(true);
189          //channelsToolbar->setStretchableWidget(m_pVolumeSlider);          //m_ui.channelsToolbar->setStretchableWidget(m_pVolumeSlider);
190      channelsToolbar->addWidget(m_pVolumeSlider);          m_ui.channelsToolbar->addWidget(m_pVolumeSlider);
191          // Volume spin-box          // Volume spin-box
192          channelsToolbar->addSeparator();          m_ui.channelsToolbar->addSeparator();
193          m_pVolumeSpinBox = new QSpinBox(channelsToolbar);          m_pVolumeSpinBox = new QSpinBox(m_ui.channelsToolbar);
194            m_pVolumeSpinBox->setMaximumHeight(24);
195          m_pVolumeSpinBox->setSuffix(" %");          m_pVolumeSpinBox->setSuffix(" %");
196          m_pVolumeSpinBox->setRange(0, 100);          m_pVolumeSpinBox->setMinimum(0);
197          QToolTip::add(m_pVolumeSpinBox, sVolumeText);          m_pVolumeSpinBox->setMaximum(100);
198            m_pVolumeSpinBox->setToolTip(sVolumeText);
199          QObject::connect(m_pVolumeSpinBox,          QObject::connect(m_pVolumeSpinBox,
200                  SIGNAL(valueChanged(int)),                  SIGNAL(valueChanged(int)),
201                  SLOT(volumeChanged(int)));                  SLOT(volumeChanged(int)));
202            m_ui.channelsToolbar->addWidget(m_pVolumeSpinBox);
203  #endif  #endif
204    
205      // Make it an MDI workspace.          // Make it an MDI workspace.
206      m_pWorkspace = new QWorkspace(this);          m_pWorkspace = new QWorkspace(this);
207      m_pWorkspace->setScrollBarsEnabled(true);          m_pWorkspace->setScrollBarsEnabled(true);
208          // Set the activation connection.          // Set the activation connection.
209          QObject::connect(m_pWorkspace,          QObject::connect(m_pWorkspace,
210                  SIGNAL(windowActivated(QWidget *)),                  SIGNAL(windowActivated(QWidget *)),
211                  SLOT(stabilizeForm()));                  SLOT(activateStrip(QWidget *)));
212      // Make it shine :-)          // Make it shine :-)
213      setCentralWidget(m_pWorkspace);          setCentralWidget(m_pWorkspace);
214    
215      // Create some statusbar labels...          // Create some statusbar labels...
216      QLabel *pLabel;          QLabel *pLabel;
217      // Client status.          // Client status.
218      pLabel = new QLabel(tr("Connected"), this);          pLabel = new QLabel(tr("Connected"), this);
219      pLabel->setAlignment(Qt::AlignLeft);          pLabel->setAlignment(Qt::AlignLeft);
220      pLabel->setMinimumSize(pLabel->sizeHint());          pLabel->setMinimumSize(pLabel->sizeHint());
221      m_statusItem[QSAMPLER_STATUS_CLIENT] = pLabel;          m_statusItem[QSAMPLER_STATUS_CLIENT] = pLabel;
222      statusBar()->addWidget(pLabel);          statusBar()->addWidget(pLabel);
223      // Server address.          // Server address.
224      pLabel = new QLabel(this);          pLabel = new QLabel(this);
225      pLabel->setAlignment(Qt::AlignLeft);          pLabel->setAlignment(Qt::AlignLeft);
226      m_statusItem[QSAMPLER_STATUS_SERVER] = pLabel;          m_statusItem[QSAMPLER_STATUS_SERVER] = pLabel;
227      statusBar()->addWidget(pLabel, 1);          statusBar()->addWidget(pLabel, 1);
228      // Channel title.          // Channel title.
229      pLabel = new QLabel(this);          pLabel = new QLabel(this);
230      pLabel->setAlignment(Qt::AlignLeft);          pLabel->setAlignment(Qt::AlignLeft);
231      m_statusItem[QSAMPLER_STATUS_CHANNEL] = pLabel;          m_statusItem[QSAMPLER_STATUS_CHANNEL] = pLabel;
232      statusBar()->addWidget(pLabel, 2);          statusBar()->addWidget(pLabel, 2);
233      // Session modification status.          // Session modification status.
234      pLabel = new QLabel(tr("MOD"), this);          pLabel = new QLabel(tr("MOD"), this);
235      pLabel->setAlignment(Qt::AlignHCenter);          pLabel->setAlignment(Qt::AlignHCenter);
236      pLabel->setMinimumSize(pLabel->sizeHint());          pLabel->setMinimumSize(pLabel->sizeHint());
237      m_statusItem[QSAMPLER_STATUS_SESSION] = pLabel;          m_statusItem[QSAMPLER_STATUS_SESSION] = pLabel;
238      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);  
239    
240  #if defined(WIN32)  #if defined(WIN32)
241      WSAStartup(MAKEWORD(1, 1), &_wsaData);          WSAStartup(MAKEWORD(1, 1), &_wsaData);
242  #endif  #endif
243    
244            // Some actions surely need those
245            // shortcuts firmly attached...
246            addAction(m_ui.viewMenubarAction);
247            addAction(m_ui.viewToolbarAction);
248    
249            QObject::connect(m_ui.fileNewAction,
250                    SIGNAL(triggered()),
251                    SLOT(fileNew()));
252            QObject::connect(m_ui.fileOpenAction,
253                    SIGNAL(triggered()),
254                    SLOT(fileOpen()));
255            QObject::connect(m_ui.fileSaveAction,
256                    SIGNAL(triggered()),
257                    SLOT(fileSave()));
258            QObject::connect(m_ui.fileSaveAsAction,
259                    SIGNAL(triggered()),
260                    SLOT(fileSaveAs()));
261            QObject::connect(m_ui.fileResetAction,
262                    SIGNAL(triggered()),
263                    SLOT(fileReset()));
264            QObject::connect(m_ui.fileRestartAction,
265                    SIGNAL(triggered()),
266                    SLOT(fileRestart()));
267            QObject::connect(m_ui.fileExitAction,
268                    SIGNAL(triggered()),
269                    SLOT(fileExit()));
270            QObject::connect(m_ui.editAddChannelAction,
271                    SIGNAL(triggered()),
272                    SLOT(editAddChannel()));
273            QObject::connect(m_ui.editRemoveChannelAction,
274                    SIGNAL(triggered()),
275                    SLOT(editRemoveChannel()));
276            QObject::connect(m_ui.editSetupChannelAction,
277                    SIGNAL(triggered()),
278                    SLOT(editSetupChannel()));
279            QObject::connect(m_ui.editEditChannelAction,
280                    SIGNAL(triggered()),
281                    SLOT(editEditChannel()));
282            QObject::connect(m_ui.editResetChannelAction,
283                    SIGNAL(triggered()),
284                    SLOT(editResetChannel()));
285            QObject::connect(m_ui.editResetAllChannelsAction,
286                    SIGNAL(triggered()),
287                    SLOT(editResetAllChannels()));
288            QObject::connect(m_ui.viewMenubarAction,
289                    SIGNAL(toggled(bool)),
290                    SLOT(viewMenubar(bool)));
291            QObject::connect(m_ui.viewToolbarAction,
292                    SIGNAL(toggled(bool)),
293                    SLOT(viewToolbar(bool)));
294            QObject::connect(m_ui.viewStatusbarAction,
295                    SIGNAL(toggled(bool)),
296                    SLOT(viewStatusbar(bool)));
297            QObject::connect(m_ui.viewMessagesAction,
298                    SIGNAL(toggled(bool)),
299                    SLOT(viewMessages(bool)));
300            QObject::connect(m_ui.viewInstrumentsAction,
301                    SIGNAL(triggered()),
302                    SLOT(viewInstruments()));
303            QObject::connect(m_ui.viewDevicesAction,
304                    SIGNAL(triggered()),
305                    SLOT(viewDevices()));
306            QObject::connect(m_ui.viewOptionsAction,
307                    SIGNAL(triggered()),
308                    SLOT(viewOptions()));
309            QObject::connect(m_ui.channelsArrangeAction,
310                    SIGNAL(triggered()),
311                    SLOT(channelsArrange()));
312            QObject::connect(m_ui.channelsAutoArrangeAction,
313                    SIGNAL(toggled(bool)),
314                    SLOT(channelsAutoArrange(bool)));
315            QObject::connect(m_ui.helpAboutAction,
316                    SIGNAL(triggered()),
317                    SLOT(helpAbout()));
318            QObject::connect(m_ui.helpAboutQtAction,
319                    SIGNAL(triggered()),
320                    SLOT(helpAboutQt()));
321    
322            QObject::connect(m_ui.fileMenu,
323                    SIGNAL(aboutToShow()),
324                    SLOT(updateRecentFilesMenu()));
325            QObject::connect(m_ui.channelsMenu,
326                    SIGNAL(aboutToShow()),
327                    SLOT(channelsMenuAboutToShow()));
328  }  }
329    
330  // Destructor.  // Destructor.
331  MainForm::~MainForm()  MainForm::~MainForm()
332  {  {
333      // Do final processing anyway.          // Do final processing anyway.
334      processServerExit();          processServerExit();
335    
336  #if defined(WIN32)  #if defined(WIN32)
337      WSACleanup();          WSACleanup();
338  #endif  #endif
339    
340      // Finally drop any widgets around...          // Finally drop any widgets around...
341      if (m_pDeviceForm)          if (m_pDeviceForm)
342          delete m_pDeviceForm;                  delete m_pDeviceForm;
343      if (m_pInstrumentListForm)          if (m_pInstrumentListForm)
344          delete m_pInstrumentListForm;                  delete m_pInstrumentListForm;
345      if (m_pMessages)          if (m_pMessages)
346          delete m_pMessages;                  delete m_pMessages;
347      if (m_pWorkspace)          if (m_pWorkspace)
348          delete m_pWorkspace;                  delete m_pWorkspace;
349    
350      // Delete status item labels one by one.          // Delete status item labels one by one.
351      if (m_statusItem[QSAMPLER_STATUS_CLIENT])          if (m_statusItem[QSAMPLER_STATUS_CLIENT])
352          delete m_statusItem[QSAMPLER_STATUS_CLIENT];                  delete m_statusItem[QSAMPLER_STATUS_CLIENT];
353      if (m_statusItem[QSAMPLER_STATUS_SERVER])          if (m_statusItem[QSAMPLER_STATUS_SERVER])
354          delete m_statusItem[QSAMPLER_STATUS_SERVER];                  delete m_statusItem[QSAMPLER_STATUS_SERVER];
355      if (m_statusItem[QSAMPLER_STATUS_CHANNEL])          if (m_statusItem[QSAMPLER_STATUS_CHANNEL])
356          delete m_statusItem[QSAMPLER_STATUS_CHANNEL];                  delete m_statusItem[QSAMPLER_STATUS_CHANNEL];
357      if (m_statusItem[QSAMPLER_STATUS_SESSION])          if (m_statusItem[QSAMPLER_STATUS_SESSION])
358          delete m_statusItem[QSAMPLER_STATUS_SESSION];                  delete m_statusItem[QSAMPLER_STATUS_SESSION];
359    
360  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
361          delete m_pVolumeSpinBox;          delete m_pVolumeSpinBox;
362          delete m_pVolumeSlider;          delete m_pVolumeSlider;
363  #endif  #endif
364    
     // Delete recentfiles menu.  
     if (m_pRecentFilesMenu)  
         delete m_pRecentFilesMenu;  
   
365          // Pseudo-singleton reference shut-down.          // Pseudo-singleton reference shut-down.
366          g_pMainForm = NULL;          g_pMainForm = NULL;
367  }  }
368    
369    
370  // Make and set a proper setup options step.  // Make and set a proper setup options step.
371  void MainForm::setup ( qsamplerOptions *pOptions )  void MainForm::setup ( Options *pOptions )
372  {  {
373      // We got options?          // We got options?
374      m_pOptions = pOptions;          m_pOptions = pOptions;
375    
376      // What style do we create these forms?          // What style do we create these forms?
377          Qt::WFlags wflags = Qt::WStyle_Customize          Qt::WindowFlags wflags = Qt::Window
378                  | Qt::WStyle_NormalBorder  #if QT_VERSION >= 0x040200
379                  | Qt::WStyle_Title                  | Qt::CustomizeWindowHint
380                  | Qt::WStyle_SysMenu  #endif
381                  | Qt::WStyle_MinMax                  | Qt::WindowTitleHint
382                  | Qt::WType_TopLevel;                  | Qt::WindowSystemMenuHint
383      if (m_pOptions->bKeepOnTop)                  | Qt::WindowMinMaxButtonsHint;
384          wflags |= Qt::WStyle_Tool;          if (m_pOptions->bKeepOnTop)
385      // Some child forms are to be created right now.                  wflags |= Qt::Tool;
386      m_pMessages = new qsamplerMessages(this);          // Some child forms are to be created right now.
387      m_pDeviceForm = new DeviceForm(this, wflags);          m_pMessages = new Messages(this);
388            m_pDeviceForm = new DeviceForm(this, wflags);
389  #ifdef CONFIG_MIDI_INSTRUMENT  #ifdef CONFIG_MIDI_INSTRUMENT
390      m_pInstrumentListForm = new InstrumentListForm(this, wflags);          m_pInstrumentListForm = new InstrumentListForm(this, wflags);
         QObject::connect(&m_pInstrumentListForm->model,  
                 SIGNAL(instrumentsChanged()),  
                 SLOT(sessionDirty()));  
391  #else  #else
392          viewInstrumentsAction->setEnabled(false);          viewInstrumentsAction->setEnabled(false);
393  #endif  #endif
394      // Set message defaults...          // Setup appropriately...
395      updateMessagesFont();          m_pMessages->setLogging(m_pOptions->bMessagesLog, m_pOptions->sMessagesLogPath);
396      updateMessagesLimit();          // Set message defaults...
397      updateMessagesCapture();          updateMessagesFont();
398      // Set the visibility signal.          updateMessagesLimit();
399            updateMessagesCapture();
400            // Set the visibility signal.
401          QObject::connect(m_pMessages,          QObject::connect(m_pMessages,
402                  SIGNAL(visibilityChanged(bool)),                  SIGNAL(visibilityChanged(bool)),
403                  SLOT(stabilizeForm()));                  SLOT(stabilizeForm()));
404    
405      // Initial decorations toggle state.          // Initial decorations toggle state.
406      ui.viewMenubarAction->setOn(m_pOptions->bMenubar);          m_ui.viewMenubarAction->setChecked(m_pOptions->bMenubar);
407      ui.viewToolbarAction->setOn(m_pOptions->bToolbar);          m_ui.viewToolbarAction->setChecked(m_pOptions->bToolbar);
408      ui.viewStatusbarAction->setOn(m_pOptions->bStatusbar);          m_ui.viewStatusbarAction->setChecked(m_pOptions->bStatusbar);
409      ui.channelsAutoArrangeAction->setOn(m_pOptions->bAutoArrange);          m_ui.channelsAutoArrangeAction->setChecked(m_pOptions->bAutoArrange);
410    
411      // Initial decorations visibility state.          // Initial decorations visibility state.
412      viewMenubar(m_pOptions->bMenubar);          viewMenubar(m_pOptions->bMenubar);
413      viewToolbar(m_pOptions->bToolbar);          viewToolbar(m_pOptions->bToolbar);
414      viewStatusbar(m_pOptions->bStatusbar);          viewStatusbar(m_pOptions->bStatusbar);
415    
416      addDockWidget(Qt::BottomDockWidgetArea, m_pMessages);          addDockWidget(Qt::BottomDockWidgetArea, m_pMessages);
417    
418      // Restore whole toolbar & dock windows states.          // Restore whole dock windows state.
419      QString sDockables = m_pOptions->settings().readEntry("/Layout/DockWindowsBase64" , QString::null);          QByteArray aDockables = m_pOptions->settings().value(
420      if (!sDockables.isEmpty()) {                  "/Layout/DockWindows").toByteArray();
421          restoreState(QByteArray::fromBase64(sDockables.toAscii()));          if (!aDockables.isEmpty()) {
422      }                  restoreState(aDockables);
423      // Try to restore old window positioning and initial visibility.          }
424      m_pOptions->loadWidgetGeometry(this);  
425      m_pOptions->loadWidgetGeometry(m_pInstrumentListForm);          // Try to restore old window positioning and initial visibility.
426      m_pOptions->loadWidgetGeometry(m_pDeviceForm);          m_pOptions->loadWidgetGeometry(this);
427            m_pOptions->loadWidgetGeometry(m_pInstrumentListForm);
428      // Final startup stabilization...          m_pOptions->loadWidgetGeometry(m_pDeviceForm);
429      updateMaxVolume();  
430      updateRecentFilesMenu();          // Final startup stabilization...
431      stabilizeForm();          updateMaxVolume();
432            updateRecentFilesMenu();
433            stabilizeForm();
434    
435      // Make it ready :-)          // Make it ready :-)
436      statusBar()->message(tr("Ready"), 3000);          statusBar()->showMessage(tr("Ready"), 3000);
437    
438      // We'll try to start immediately...          // We'll try to start immediately...
439      startSchedule(0);          startSchedule(0);
440    
441      // Register the first timer slot.          // Register the first timer slot.
442      QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));          QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
443  }  }
444    
445    
446  // Window close event handlers.  // Window close event handlers.
447  bool MainForm::queryClose (void)  bool MainForm::queryClose (void)
448  {  {
449      bool bQueryClose = closeSession(false);          bool bQueryClose = closeSession(false);
450    
451      // Try to save current general state...          // Try to save current general state...
452      if (m_pOptions) {          if (m_pOptions) {
453          // Some windows default fonts is here on demand too.                  // Some windows default fonts is here on demand too.
454          if (bQueryClose && m_pMessages)                  if (bQueryClose && m_pMessages)
455              m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();                          m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();
456          // Try to save current positioning.                  // Try to save current positioning.
457          if (bQueryClose) {                  if (bQueryClose) {
458              // Save decorations state.                          // Save decorations state.
459              m_pOptions->bMenubar = ui.MenuBar->isVisible();                          m_pOptions->bMenubar = m_ui.MenuBar->isVisible();
460              m_pOptions->bToolbar = (fileToolbar->isVisible() || editToolbar->isVisible() || channelsToolbar->isVisible());                          m_pOptions->bToolbar = (m_ui.fileToolbar->isVisible()
461              m_pOptions->bStatusbar = statusBar()->isVisible();                                  || m_ui.editToolbar->isVisible()
462              // Save the dock windows state.                                  || m_ui.channelsToolbar->isVisible());
463              const QString sDockables = saveState().toBase64().data();                          m_pOptions->bStatusbar = statusBar()->isVisible();
464              m_pOptions->settings().writeEntry("/Layout/DockWindowsBase64", sDockables);                          // Save the dock windows state.
465              // And the children, and the main windows state,.                          const QString sDockables = saveState().toBase64().data();
466                            m_pOptions->settings().setValue("/Layout/DockWindows", saveState());
467                            // And the children, and the main windows state,.
468                          m_pOptions->saveWidgetGeometry(m_pDeviceForm);                          m_pOptions->saveWidgetGeometry(m_pDeviceForm);
469                          m_pOptions->saveWidgetGeometry(m_pInstrumentListForm);                          m_pOptions->saveWidgetGeometry(m_pInstrumentListForm);
470                          m_pOptions->saveWidgetGeometry(this);                          m_pOptions->saveWidgetGeometry(this);
# Line 362  bool MainForm::queryClose (void) Line 473  bool MainForm::queryClose (void)
473                                  m_pInstrumentListForm->close();                                  m_pInstrumentListForm->close();
474                          if (m_pDeviceForm)                          if (m_pDeviceForm)
475                                  m_pDeviceForm->close();                                  m_pDeviceForm->close();
476              // Stop client and/or server, gracefully.                          // Stop client and/or server, gracefully.
477              stopServer();                          stopServer(true /*interactive*/);
478          }                  }
479      }          }
480    
481      return bQueryClose;          return bQueryClose;
482  }  }
483    
484    
485  void MainForm::closeEvent ( QCloseEvent *pCloseEvent )  void MainForm::closeEvent ( QCloseEvent *pCloseEvent )
486  {  {
487      if (queryClose())          if (queryClose()) {
488          pCloseEvent->accept();                  DeviceStatusForm::deleteAllInstances();
489      else                  pCloseEvent->accept();
490          pCloseEvent->ignore();          } else
491  }                  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;  
492  }  }
493    
494    
495  // Window drag-n-drop event handlers.  // Window drag-n-drop event handlers.
496  void MainForm::dragEnterEvent ( QDragEnterEvent* pDragEnterEvent )  void MainForm::dragEnterEvent ( QDragEnterEvent* pDragEnterEvent )
497  {  {
498          QStringList files;          // Accept external drags only...
499          pDragEnterEvent->accept(decodeDragFiles(pDragEnterEvent, files));          if (pDragEnterEvent->source() == NULL
500                    && pDragEnterEvent->mimeData()->hasUrls()) {
501                    pDragEnterEvent->accept();
502            } else {
503                    pDragEnterEvent->ignore();
504            }
505  }  }
506    
507    
508  void MainForm::dropEvent ( QDropEvent* pDropEvent )  void MainForm::dropEvent ( QDropEvent* pDropEvent )
509  {  {
510      QStringList files;          // Accept externally originated drops only...
511            if (pDropEvent->source())
512      if (!decodeDragFiles(pDropEvent, files))                  return;
         return;  
513    
514          for (QStringList::Iterator iter = files.begin(); iter != files.end(); iter++) {          const QMimeData *pMimeData = pDropEvent->mimeData();
515                  const QString& sPath = *iter;          if (pMimeData->hasUrls()) {
516                  if (qsamplerChannel::isInstrumentFile(sPath)) {                  QListIterator<QUrl> iter(pMimeData->urls());
517                          // Try to create a new channel from instrument file...                  while (iter.hasNext()) {
518                          qsamplerChannel *pChannel = new qsamplerChannel();                          const QString& sPath = iter.next().toLocalFile();
519                          if (pChannel == NULL)                          if (Channel::isInstrumentFile(sPath)) {
520                                  return;                                  // Try to create a new channel from instrument file...
521                          // Start setting the instrument filename...                                  Channel *pChannel = new Channel();
522                          pChannel->setInstrument(sPath, 0);                                  if (pChannel == NULL)
523                          // Before we show it up, may be we'll                                          return;
524                          // better ask for some initial values?                                  // Start setting the instrument filename...
525                          if (!pChannel->channelSetup(this)) {                                  pChannel->setInstrument(sPath, 0);
526                                  delete pChannel;                                  // Before we show it up, may be we'll
527                                  return;                                  // better ask for some initial values?
528                          }                                  if (!pChannel->channelSetup(this)) {
529                          // Finally, give it to a new channel strip...                                          delete pChannel;
530                          if (!createChannelStrip(pChannel)) {                                          return;
531                                  delete pChannel;                                  }
532                                  return;                                  // Finally, give it to a new channel strip...
533                                    if (!createChannelStrip(pChannel)) {
534                                            delete pChannel;
535                                            return;
536                                    }
537                                    // Make that an overall update.
538                                    m_iDirtyCount++;
539                                    stabilizeForm();
540                            }   // Otherwise, load an usual session file (LSCP script)...
541                            else if (closeSession(true)) {
542                                    loadSessionFile(sPath);
543                                    break;
544                          }                          }
                         // Make that an overall update.  
                         m_iDirtyCount++;  
                         stabilizeForm();  
                 }   // Otherwise, load an usual session file (LSCP script)...  
                 else if (closeSession(true)) {  
                         loadSessionFile(sPath);  
                         break;  
545                  }                  }
546                  // Make it look responsive...:)                  // Make it look responsive...:)
547                  QApplication::processEvents(QEventLoop::ExcludeUserInput);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
548          }          }
549  }  }
550    
551    
552  // Custome event handler.  // Custome event handler.
553  void MainForm::customEvent(QEvent* pCustomEvent)  void MainForm::customEvent(QEvent* pCustomEvent)
554  {  {
555      // For the time being, just pump it to messages.          // For the time being, just pump it to messages.
556      if (pCustomEvent->type() == QSAMPLER_CUSTOM_EVENT) {          if (pCustomEvent->type() == QSAMPLER_CUSTOM_EVENT) {
557          qsamplerCustomEvent *pEvent = (qsamplerCustomEvent *) pCustomEvent;                  CustomEvent *pEvent = static_cast<CustomEvent *> (pCustomEvent);
558                  if (pEvent->event() == LSCP_EVENT_CHANNEL_INFO) {                  switch (pEvent->event()) {
559                          int iChannelID = pEvent->data().toInt();                          case LSCP_EVENT_CHANNEL_COUNT:
560                          ChannelStrip *pChannelStrip = channelStrip(iChannelID);                                  updateAllChannelStrips(true);
561                          if (pChannelStrip)                                  break;
562                                  channelStripChanged(pChannelStrip);                          case LSCP_EVENT_CHANNEL_INFO: {
563                  } else {                                  int iChannelID = pEvent->data().toInt();
564                          appendMessagesColor(tr("Notify event: %1 data: %2")                                  ChannelStrip *pChannelStrip = channelStrip(iChannelID);
565                                  .arg(::lscp_event_to_text(pEvent->event()))                                  if (pChannelStrip)
566                                  .arg(pEvent->data()), "#996699");                                          channelStripChanged(pChannelStrip);
567                                    break;
568                            }
569                            case LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT:
570                                    if (m_pDeviceForm) m_pDeviceForm->refreshDevices();
571                                    DeviceStatusForm::onDevicesChanged();
572                                    updateViewMidiDeviceStatusMenu();
573                                    break;
574                            case LSCP_EVENT_MIDI_INPUT_DEVICE_INFO: {
575                                    if (m_pDeviceForm) m_pDeviceForm->refreshDevices();
576                                    const int iDeviceID = pEvent->data().section(' ', 0, 0).toInt();
577                                    DeviceStatusForm::onDeviceChanged(iDeviceID);
578                                    break;
579                            }
580                            case LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT:
581                                    if (m_pDeviceForm) m_pDeviceForm->refreshDevices();
582                                    break;
583                            case LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO:
584                                    if (m_pDeviceForm) m_pDeviceForm->refreshDevices();
585                                    break;
586    #if CONFIG_EVENT_CHANNEL_MIDI
587                            case LSCP_EVENT_CHANNEL_MIDI: {
588                                    const int iChannelID = pEvent->data().section(' ', 0, 0).toInt();
589                                    ChannelStrip *pChannelStrip = channelStrip(iChannelID);
590                                    if (pChannelStrip)
591                                            pChannelStrip->midiArrived();
592                                    break;
593                            }
594    #endif
595    #if CONFIG_EVENT_DEVICE_MIDI
596                            case LSCP_EVENT_DEVICE_MIDI: {
597                                    const int iDeviceID = pEvent->data().section(' ', 0, 0).toInt();
598                                    const int iPortID   = pEvent->data().section(' ', 1, 1).toInt();
599                                    DeviceStatusForm* pDeviceStatusForm =
600                                            DeviceStatusForm::getInstance(iDeviceID);
601                                    if (pDeviceStatusForm)
602                                            pDeviceStatusForm->midiArrived(iPortID);
603                                    break;
604                            }
605    #endif
606                            default:
607                                    appendMessagesColor(tr("Notify event: %1 data: %2")
608                                            .arg(::lscp_event_to_text(pEvent->event()))
609                                            .arg(pEvent->data()), "#996699");
610                  }                  }
611      }          }
612    }
613    
614    void MainForm::updateViewMidiDeviceStatusMenu() {
615            m_ui.viewMidiDeviceStatusMenu->clear();
616            const std::map<int, DeviceStatusForm*> statusForms =
617                    DeviceStatusForm::getInstances();
618            for (
619                    std::map<int, DeviceStatusForm*>::const_iterator iter = statusForms.begin();
620                    iter != statusForms.end(); ++iter
621            ) {
622                    DeviceStatusForm* pForm = iter->second;
623                    m_ui.viewMidiDeviceStatusMenu->addAction(
624                            pForm->visibleAction()
625                    );
626            }
627  }  }
628    
629  // Context menu event handler.  // Context menu event handler.
630  void MainForm::contextMenuEvent( QContextMenuEvent *pEvent )  void MainForm::contextMenuEvent( QContextMenuEvent *pEvent )
631  {  {
632      stabilizeForm();          stabilizeForm();
633    
634      ui.editMenu->exec(pEvent->globalPos());          m_ui.editMenu->exec(pEvent->globalPos());
635  }  }
636    
637    
# Line 479  void MainForm::contextMenuEvent( QContex Line 639  void MainForm::contextMenuEvent( QContex
639  // qsamplerMainForm -- Brainless public property accessors.  // qsamplerMainForm -- Brainless public property accessors.
640    
641  // The global options settings property.  // The global options settings property.
642  qsamplerOptions *MainForm::options (void)  Options *MainForm::options (void) const
643  {  {
644      return m_pOptions;          return m_pOptions;
645  }  }
646    
647    
648  // The LSCP client descriptor property.  // The LSCP client descriptor property.
649  lscp_client_t *MainForm::client (void)  lscp_client_t *MainForm::client (void) const
650  {  {
651      return m_pClient;          return m_pClient;
652  }  }
653    
654    
# Line 505  MainForm *MainForm::getInstance (void) Line 665  MainForm *MainForm::getInstance (void)
665  // Format the displayable session filename.  // Format the displayable session filename.
666  QString MainForm::sessionName ( const QString& sFilename )  QString MainForm::sessionName ( const QString& sFilename )
667  {  {
668      bool bCompletePath = (m_pOptions && m_pOptions->bCompletePath);          bool bCompletePath = (m_pOptions && m_pOptions->bCompletePath);
669      QString sSessionName = sFilename;          QString sSessionName = sFilename;
670      if (sSessionName.isEmpty())          if (sSessionName.isEmpty())
671          sSessionName = tr("Untitled") + QString::number(m_iUntitled);                  sSessionName = tr("Untitled") + QString::number(m_iUntitled);
672      else if (!bCompletePath)          else if (!bCompletePath)
673          sSessionName = QFileInfo(sSessionName).fileName();                  sSessionName = QFileInfo(sSessionName).fileName();
674      return sSessionName;          return sSessionName;
675  }  }
676    
677    
678  // Create a new session file from scratch.  // Create a new session file from scratch.
679  bool MainForm::newSession (void)  bool MainForm::newSession (void)
680  {  {
681      // Check if we can do it.          // Check if we can do it.
682      if (!closeSession(true))          if (!closeSession(true))
683          return false;                  return false;
684    
685          // Give us what the server has, right now...          // Give us what the server has, right now...
686          updateSession();          updateSession();
687    
688      // Ok increment untitled count.          // Ok increment untitled count.
689      m_iUntitled++;          m_iUntitled++;
690    
691      // Stabilize form.          // Stabilize form.
692      m_sFilename = QString::null;          m_sFilename = QString::null;
693      m_iDirtyCount = 0;          m_iDirtyCount = 0;
694      appendMessages(tr("New session: \"%1\".").arg(sessionName(m_sFilename)));          appendMessages(tr("New session: \"%1\".").arg(sessionName(m_sFilename)));
695      stabilizeForm();          stabilizeForm();
696    
697      return true;          return true;
698  }  }
699    
700    
701  // Open an existing sampler session.  // Open an existing sampler session.
702  bool MainForm::openSession (void)  bool MainForm::openSession (void)
703  {  {
704      if (m_pOptions == NULL)          if (m_pOptions == NULL)
705          return false;                  return false;
706    
707      // Ask for the filename to open...          // Ask for the filename to open...
708      QString sFilename = QFileDialog::getOpenFileName(          QString sFilename = QFileDialog::getOpenFileName(this,
709                  m_pOptions->sSessionDir,                // Start here.                  QSAMPLER_TITLE ": " + tr("Open Session"), // Caption.
710                  tr("LSCP Session files") + " (*.lscp)", // Filter (LSCP files)                  m_pOptions->sSessionDir,                  // Start here.
711                  this, 0,                                // Parent and name (none)                  tr("LSCP Session files") + " (*.lscp)"    // Filter (LSCP files)
712                  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;  
713    
714      // Load it right away.          // Have we cancelled?
715      return loadSessionFile(sFilename);          if (sFilename.isEmpty())
716                    return false;
717    
718            // Check if we're going to discard safely the current one...
719            if (!closeSession(true))
720                    return false;
721    
722            // Load it right away.
723            return loadSessionFile(sFilename);
724  }  }
725    
726    
727  // Save current sampler session with another name.  // Save current sampler session with another name.
728  bool MainForm::saveSession ( bool bPrompt )  bool MainForm::saveSession ( bool bPrompt )
729  {  {
730      if (m_pOptions == NULL)          if (m_pOptions == NULL)
731          return false;                  return false;
732    
733      QString sFilename = m_sFilename;          QString sFilename = m_sFilename;
734    
735      // Ask for the file to save, if there's none...          // Ask for the file to save, if there's none...
736      if (bPrompt || sFilename.isEmpty()) {          if (bPrompt || sFilename.isEmpty()) {
737          // If none is given, assume default directory.                  // If none is given, assume default directory.
738          if (sFilename.isEmpty())                  if (sFilename.isEmpty())
739              sFilename = m_pOptions->sSessionDir;                          sFilename = m_pOptions->sSessionDir;
740          // Prompt the guy...                  // Prompt the guy...
741          sFilename = QFileDialog::getSaveFileName(                  sFilename = QFileDialog::getSaveFileName(this,
742                          sFilename,                              // Start here.                          QSAMPLER_TITLE ": " + tr("Save Session"), // Caption.
743                          tr("LSCP Session files") + " (*.lscp)", // Filter (LSCP files)                          sFilename,                                // Start here.
744                          this, 0,                                // Parent and name (none)                          tr("LSCP Session files") + " (*.lscp)"    // Filter (LSCP files)
745                          QSAMPLER_TITLE ": " + tr("Save Session")        // Caption.                  );
746          );                  // Have we cancelled it?
747          // Have we cancelled it?                  if (sFilename.isEmpty())
748          if (sFilename.isEmpty())                          return false;
749              return false;                  // Enforce .lscp extension...
750          // Enforce .lscp extension...                  if (QFileInfo(sFilename).suffix().isEmpty())
751          if (QFileInfo(sFilename).extension().isEmpty())                          sFilename += ".lscp";
752              sFilename += ".lscp";                  // Check if already exists...
753          // Check if already exists...                  if (sFilename != m_sFilename && QFileInfo(sFilename).exists()) {
754          if (sFilename != m_sFilename && QFileInfo(sFilename).exists()) {                          if (QMessageBox::warning(this,
             if (QMessageBox::warning(this,  
755                                  QSAMPLER_TITLE ": " + tr("Warning"),                                  QSAMPLER_TITLE ": " + tr("Warning"),
756                  tr("The file already exists:\n\n"                                  tr("The file already exists:\n\n"
757                     "\"%1\"\n\n"                                  "\"%1\"\n\n"
758                     "Do you want to replace it?")                                  "Do you want to replace it?")
759                     .arg(sFilename),                                  .arg(sFilename),
760                  tr("Replace"), tr("Cancel")) > 0)                                  tr("Replace"), tr("Cancel")) > 0)
761                  return false;                                  return false;
762          }                  }
763      }          }
764    
765      // Save it right away.          // Save it right away.
766      return saveSessionFile(sFilename);          return saveSessionFile(sFilename);
767  }  }
768    
769    
770  // Close current session.  // Close current session.
771  bool MainForm::closeSession ( bool bForce )  bool MainForm::closeSession ( bool bForce )
772  {  {
773      bool bClose = true;          bool bClose = true;
774    
775      // Are we dirty enough to prompt it?          // Are we dirty enough to prompt it?
776      if (m_iDirtyCount > 0) {          if (m_iDirtyCount > 0) {
777          switch (QMessageBox::warning(this,                  switch (QMessageBox::warning(this,
778                          QSAMPLER_TITLE ": " + tr("Warning"),                          QSAMPLER_TITLE ": " + tr("Warning"),
779              tr("The current session has been changed:\n\n"                          tr("The current session has been changed:\n\n"
780              "\"%1\"\n\n"                          "\"%1\"\n\n"
781              "Do you want to save the changes?")                          "Do you want to save the changes?")
782              .arg(sessionName(m_sFilename)),                          .arg(sessionName(m_sFilename)),
783              tr("Save"), tr("Discard"), tr("Cancel"))) {                          tr("Save"), tr("Discard"), tr("Cancel"))) {
784          case 0:     // Save...                  case 0:     // Save...
785              bClose = saveSession(false);                          bClose = saveSession(false);
786              // Fall thru....                          // Fall thru....
787          case 1:     // Discard                  case 1:     // Discard
788              break;                          break;
789          default:    // Cancel.                  default:    // Cancel.
790              bClose = false;                          bClose = false;
791              break;                          break;
792          }                  }
793      }          }
   
     // 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;  
     }  
794    
795      return bClose;          // If we may close it, dot it.
796            if (bClose) {
797                    // Remove all channel strips from sight...
798                    m_pWorkspace->setUpdatesEnabled(false);
799                    QWidgetList wlist = m_pWorkspace->windowList();
800                    for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
801                            ChannelStrip *pChannelStrip = (ChannelStrip*) wlist.at(iChannel);
802                            if (pChannelStrip) {
803                                    Channel *pChannel = pChannelStrip->channel();
804                                    if (bForce && pChannel)
805                                            pChannel->removeChannel();
806                                    delete pChannelStrip;
807                            }
808                    }
809                    m_pWorkspace->setUpdatesEnabled(true);
810                    // We're now clean, for sure.
811                    m_iDirtyCount = 0;
812            }
813    
814            return bClose;
815  }  }
816    
817    
818  // Load a session from specific file path.  // Load a session from specific file path.
819  bool MainForm::loadSessionFile ( const QString& sFilename )  bool MainForm::loadSessionFile ( const QString& sFilename )
820  {  {
821      if (m_pClient == NULL)          if (m_pClient == NULL)
822          return false;                  return false;
823    
824      // Open and read from real file.          // Open and read from real file.
825      QFile file(sFilename);          QFile file(sFilename);
826      if (!file.open(IO_ReadOnly)) {          if (!file.open(QIODevice::ReadOnly)) {
827          appendMessagesError(tr("Could not open \"%1\" session file.\n\nSorry.").arg(sFilename));                  appendMessagesError(
828          return false;                          tr("Could not open \"%1\" session file.\n\nSorry.")
829      }                          .arg(sFilename));
830                    return false;
831            }
832    
833          // Tell the world we'll take some time...          // Tell the world we'll take some time...
834          QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));          QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
835    
836      // Read the file.          // Read the file.
837          int iLine = 0;          int iLine = 0;
838      int iErrors = 0;          int iErrors = 0;
839      QTextStream ts(&file);          QTextStream ts(&file);
840      while (!ts.atEnd()) {          while (!ts.atEnd()) {
841          // Read the line.                  // Read the line.
842          QString sCommand = ts.readLine().stripWhiteSpace();                  QString sCommand = ts.readLine().trimmed();
843                  iLine++;                  iLine++;
844          // If not empty, nor a comment, call the server...                  // If not empty, nor a comment, call the server...
845          if (!sCommand.isEmpty() && sCommand[0] != '#') {                  if (!sCommand.isEmpty() && sCommand[0] != '#') {
846                          // Remember that, no matter what,                          // Remember that, no matter what,
847                          // all LSCP commands are CR/LF terminated.                          // all LSCP commands are CR/LF terminated.
848                          sCommand += "\r\n";                          sCommand += "\r\n";
849                          if (::lscp_client_query(m_pClient, sCommand.latin1()) != LSCP_OK) {                          if (::lscp_client_query(m_pClient, sCommand.toUtf8().constData())
850                                    != LSCP_OK) {
851                                  appendMessagesColor(QString("%1(%2): %3")                                  appendMessagesColor(QString("%1(%2): %3")
852                                          .arg(QFileInfo(sFilename).fileName()).arg(iLine)                                          .arg(QFileInfo(sFilename).fileName()).arg(iLine)
853                                          .arg(sCommand.simplifyWhiteSpace()), "#996633");                                          .arg(sCommand.simplified()), "#996633");
854                                  appendMessagesClient("lscp_client_query");                                  appendMessagesClient("lscp_client_query");
855                                  iErrors++;                                  iErrors++;
856                          }                          }
857          }                  }
858          // Try to make it snappy :)                  // Try to make it snappy :)
859          QApplication::processEvents(QEventLoop::ExcludeUserInput);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
860      }          }
861    
862      // Ok. we've read it.          // Ok. we've read it.
863      file.close();          file.close();
864    
865          // Now we'll try to create (update) the whole GUI session.          // Now we'll try to create (update) the whole GUI session.
866          updateSession();          updateSession();
# Line 708  bool MainForm::loadSessionFile ( const Q Line 869  bool MainForm::loadSessionFile ( const Q
869          QApplication::restoreOverrideCursor();          QApplication::restoreOverrideCursor();
870    
871          // Have we any errors?          // Have we any errors?
872          if (iErrors > 0)          if (iErrors > 0) {
873                  appendMessagesError(tr("Session loaded with errors\nfrom \"%1\".\n\nSorry.").arg(sFilename));                  appendMessagesError(
874                            tr("Session loaded with errors\nfrom \"%1\".\n\nSorry.")
875                            .arg(sFilename));
876            }
877    
878      // Save as default session directory.          // Save as default session directory.
879      if (m_pOptions)          if (m_pOptions)
880          m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);                  m_pOptions->sSessionDir = QFileInfo(sFilename).dir().absolutePath();
881          // We're not dirty anymore, if loaded without errors,          // We're not dirty anymore, if loaded without errors,
882          m_iDirtyCount = iErrors;          m_iDirtyCount = iErrors;
883      // Stabilize form...          // Stabilize form...
884      m_sFilename = sFilename;          m_sFilename = sFilename;
885      updateRecentFiles(sFilename);          updateRecentFiles(sFilename);
886      appendMessages(tr("Open session: \"%1\".").arg(sessionName(m_sFilename)));          appendMessages(tr("Open session: \"%1\".").arg(sessionName(m_sFilename)));
887    
888      // Make that an overall update.          // Make that an overall update.
889      stabilizeForm();          stabilizeForm();
890      return true;          return true;
891  }  }
892    
893    
# Line 739  bool MainForm::saveSessionFile ( const Q Line 903  bool MainForm::saveSessionFile ( const Q
903                  return false;                  return false;
904          }          }
905    
906      // Open and write into real file.          // Open and write into real file.
907      QFile file(sFilename);          QFile file(sFilename);
908      if (!file.open(IO_WriteOnly | IO_Truncate)) {          if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
909          appendMessagesError(tr("Could not open \"%1\" session file.\n\nSorry.").arg(sFilename));                  appendMessagesError(
910          return false;                          tr("Could not open \"%1\" session file.\n\nSorry.")
911      }                          .arg(sFilename));
912                    return false;
913            }
914    
915          // Tell the world we'll take some time...          // Tell the world we'll take some time...
916          QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));          QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
917    
918      // Write the file.          // Write the file.
919      int  iErrors = 0;          int  iErrors = 0;
920      QTextStream ts(&file);          QTextStream ts(&file);
921      ts << "# " << QSAMPLER_TITLE " - " << tr(QSAMPLER_SUBTITLE) << endl;          ts << "# " << QSAMPLER_TITLE " - " << tr(QSAMPLER_SUBTITLE) << endl;
922      ts << "# " << tr("Version")          ts << "# " << tr("Version")
923         << ": " QSAMPLER_VERSION << endl;          << ": " QSAMPLER_VERSION << endl;
924      ts << "# " << tr("Build")          ts << "# " << tr("Build")
925         << ": " __DATE__ " " __TIME__ << endl;          << ": " __DATE__ " " __TIME__ << endl;
926      ts << "#"  << endl;          ts << "#"  << endl;
927      ts << "# " << tr("File")          ts << "# " << tr("File")
928         << ": " << QFileInfo(sFilename).fileName() << endl;          << ": " << QFileInfo(sFilename).fileName() << endl;
929      ts << "# " << tr("Date")          ts << "# " << tr("Date")
930         << ": " << QDate::currentDate().toString("MMM dd yyyy")          << ": " << QDate::currentDate().toString("MMM dd yyyy")
931         << " "  << QTime::currentTime().toString("hh:mm:ss") << endl;          << " "  << QTime::currentTime().toString("hh:mm:ss") << endl;
932      ts << "#"  << endl;          ts << "#"  << endl;
933      ts << endl;          ts << endl;
934    
935          // It is assumed that this new kind of device+session file          // It is assumed that this new kind of device+session file
936          // will be loaded from a complete initialized server...          // will be loaded from a complete initialized server...
# Line 774  bool MainForm::saveSessionFile ( const Q Line 940  bool MainForm::saveSessionFile ( const Q
940    
941          // Audio device mapping.          // Audio device mapping.
942          QMap<int, int> audioDeviceMap;          QMap<int, int> audioDeviceMap;
943          piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Audio);          piDeviceIDs = Device::getDevices(m_pClient, Device::Audio);
944          for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {          for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {
945                  ts << endl;                  ts << endl;
946                  qsamplerDevice device(qsamplerDevice::Audio, piDeviceIDs[iDevice]);                  Device device(Device::Audio, piDeviceIDs[iDevice]);
947                  // Audio device specification...                  // Audio device specification...
948                  ts << "# " << device.deviceTypeName() << " " << device.driverName()                  ts << "# " << device.deviceTypeName() << " " << device.driverName()
949                          << " " << tr("Device") << " " << iDevice << endl;                          << " " << tr("Device") << " " << iDevice << endl;
950                  ts << "CREATE AUDIO_OUTPUT_DEVICE " << device.driverName();                  ts << "CREATE AUDIO_OUTPUT_DEVICE " << device.driverName();
951                  qsamplerDeviceParamMap::ConstIterator deviceParam;                  DeviceParamMap::ConstIterator deviceParam;
952                  for (deviceParam = device.params().begin();                  for (deviceParam = device.params().begin();
953                                  deviceParam != device.params().end();                                  deviceParam != device.params().end();
954                                          ++deviceParam) {                                          ++deviceParam) {
955                          const qsamplerDeviceParam& param = deviceParam.data();                          const DeviceParam& param = deviceParam.value();
956                          if (param.value.isEmpty()) ts << "# ";                          if (param.value.isEmpty()) ts << "# ";
957                          ts << " " << deviceParam.key() << "='" << param.value << "'";                          ts << " " << deviceParam.key() << "='" << param.value << "'";
958                  }                  }
959                  ts << endl;                  ts << endl;
960                  // Audio channel parameters...                  // Audio channel parameters...
961                  int iPort = 0;                  int iPort = 0;
962                  for (qsamplerDevicePort *pPort = device.ports().first();                  QListIterator<DevicePort *> iter(device.ports());
963                                  pPort;                  while (iter.hasNext()) {
964                                          pPort = device.ports().next(), ++iPort) {                          DevicePort *pPort = iter.next();
965                          qsamplerDeviceParamMap::ConstIterator portParam;                          DeviceParamMap::ConstIterator portParam;
966                          for (portParam = pPort->params().begin();                          for (portParam = pPort->params().begin();
967                                          portParam != pPort->params().end();                                          portParam != pPort->params().end();
968                                                  ++portParam) {                                                  ++portParam) {
969                                  const qsamplerDeviceParam& param = portParam.data();                                  const DeviceParam& param = portParam.value();
970                                  if (param.fix || param.value.isEmpty()) ts << "# ";                                  if (param.fix || param.value.isEmpty()) ts << "# ";
971                                  ts << "SET AUDIO_OUTPUT_CHANNEL_PARAMETER " << iDevice                                  ts << "SET AUDIO_OUTPUT_CHANNEL_PARAMETER " << iDevice
972                                          << " " << iPort << " " << portParam.key()                                          << " " << iPort << " " << portParam.key()
973                                          << "='" << param.value << "'" << endl;                                          << "='" << param.value << "'" << endl;
974                          }                          }
975                            iPort++;
976                  }                  }
977                  // Audio device index/id mapping.                  // Audio device index/id mapping.
978                  audioDeviceMap[device.deviceID()] = iDevice;                  audioDeviceMap[device.deviceID()] = iDevice;
979                  // Try to keep it snappy :)                  // Try to keep it snappy :)
980                  QApplication::processEvents(QEventLoop::ExcludeUserInput);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
981          }          }
982    
983          // MIDI device mapping.          // MIDI device mapping.
984          QMap<int, int> midiDeviceMap;          QMap<int, int> midiDeviceMap;
985          piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Midi);          piDeviceIDs = Device::getDevices(m_pClient, Device::Midi);
986          for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {          for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {
987                  ts << endl;                  ts << endl;
988                  qsamplerDevice device(qsamplerDevice::Midi, piDeviceIDs[iDevice]);                  Device device(Device::Midi, piDeviceIDs[iDevice]);
989                  // MIDI device specification...                  // MIDI device specification...
990                  ts << "# " << device.deviceTypeName() << " " << device.driverName()                  ts << "# " << device.deviceTypeName() << " " << device.driverName()
991                          << " " << tr("Device") << " " << iDevice << endl;                          << " " << tr("Device") << " " << iDevice << endl;
992                  ts << "CREATE MIDI_INPUT_DEVICE " << device.driverName();                  ts << "CREATE MIDI_INPUT_DEVICE " << device.driverName();
993                  qsamplerDeviceParamMap::ConstIterator deviceParam;                  DeviceParamMap::ConstIterator deviceParam;
994                  for (deviceParam = device.params().begin();                  for (deviceParam = device.params().begin();
995                                  deviceParam != device.params().end();                                  deviceParam != device.params().end();
996                                          ++deviceParam) {                                          ++deviceParam) {
997                          const qsamplerDeviceParam& param = deviceParam.data();                          const DeviceParam& param = deviceParam.value();
998                          if (param.value.isEmpty()) ts << "# ";                          if (param.value.isEmpty()) ts << "# ";
999                          ts << " " << deviceParam.key() << "='" << param.value << "'";                          ts << " " << deviceParam.key() << "='" << param.value << "'";
1000                  }                  }
1001                  ts << endl;                  ts << endl;
1002                  // MIDI port parameters...                  // MIDI port parameters...
1003                  int iPort = 0;                  int iPort = 0;
1004                  for (qsamplerDevicePort *pPort = device.ports().first();                  QListIterator<DevicePort *> iter(device.ports());
1005                                  pPort;                  while (iter.hasNext()) {
1006                                          pPort = device.ports().next(), ++iPort) {                          DevicePort *pPort = iter.next();
1007                          qsamplerDeviceParamMap::ConstIterator portParam;                          DeviceParamMap::ConstIterator portParam;
1008                          for (portParam = pPort->params().begin();                          for (portParam = pPort->params().begin();
1009                                          portParam != pPort->params().end();                                          portParam != pPort->params().end();
1010                                                  ++portParam) {                                                  ++portParam) {
1011                                  const qsamplerDeviceParam& param = portParam.data();                                  const DeviceParam& param = portParam.value();
1012                                  if (param.fix || param.value.isEmpty()) ts << "# ";                                  if (param.fix || param.value.isEmpty()) ts << "# ";
1013                                  ts << "SET MIDI_INPUT_PORT_PARAMETER " << iDevice                                  ts << "SET MIDI_INPUT_PORT_PARAMETER " << iDevice
1014                                     << " " << iPort << " " << portParam.key()                                  << " " << iPort << " " << portParam.key()
1015                                     << "='" << param.value << "'" << endl;                                  << "='" << param.value << "'" << endl;
1016                          }                          }
1017                            iPort++;
1018                  }                  }
1019                  // MIDI device index/id mapping.                  // MIDI device index/id mapping.
1020                  midiDeviceMap[device.deviceID()] = iDevice;                  midiDeviceMap[device.deviceID()] = iDevice;
1021                  // Try to keep it snappy :)                  // Try to keep it snappy :)
1022                  QApplication::processEvents(QEventLoop::ExcludeUserInput);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1023          }          }
1024          ts << endl;          ts << endl;
1025    
# Line 908  bool MainForm::saveSessionFile ( const Q Line 1076  bool MainForm::saveSessionFile ( const Q
1076                                  iErrors++;                                  iErrors++;
1077                          }                          }
1078                          // Try to keep it snappy :)                          // Try to keep it snappy :)
1079                          QApplication::processEvents(QEventLoop::ExcludeUserInput);                          QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1080                  }                  }
1081                  ts << endl;                  ts << endl;
1082                  // Check for errors...                  // Check for errors...
# Line 927  bool MainForm::saveSessionFile ( const Q Line 1095  bool MainForm::saveSessionFile ( const Q
1095  #endif  // CONFIG_MIDI_INSTRUMENT  #endif  // CONFIG_MIDI_INSTRUMENT
1096    
1097          // Sampler channel mapping.          // Sampler channel mapping.
1098      QWidgetList wlist = m_pWorkspace->windowList();          QWidgetList wlist = m_pWorkspace->windowList();
1099      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1100          ChannelStrip* pChannelStrip                  ChannelStrip* pChannelStrip
1101                          = static_cast<ChannelStrip *> (wlist.at(iChannel));                          = static_cast<ChannelStrip *> (wlist.at(iChannel));
1102          if (pChannelStrip) {                  if (pChannelStrip) {
1103              qsamplerChannel *pChannel = pChannelStrip->channel();                          Channel *pChannel = pChannelStrip->channel();
1104              if (pChannel) {                          if (pChannel) {
1105                  ts << "# " << tr("Channel") << " " << iChannel << endl;                                  ts << "# " << tr("Channel") << " " << iChannel << endl;
1106                  ts << "ADD CHANNEL" << endl;                                  ts << "ADD CHANNEL" << endl;
1107                                  if (audioDeviceMap.isEmpty()) {                                  if (audioDeviceMap.isEmpty()) {
1108                                          ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannel                                          ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannel
1109                                                  << " " << pChannel->audioDriver() << endl;                                                  << " " << pChannel->audioDriver() << endl;
# Line 952  bool MainForm::saveSessionFile ( const Q Line 1120  bool MainForm::saveSessionFile ( const Q
1120                                  }                                  }
1121                                  ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannel                                  ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannel
1122                                          << " " << pChannel->midiPort() << endl;                                          << " " << pChannel->midiPort() << endl;
1123                  ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannel << " ";                                  ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannel << " ";
1124                  if (pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL)                                  if (pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL)
1125                      ts << "ALL";                                          ts << "ALL";
1126                  else                                  else
1127                      ts << pChannel->midiChannel();                                          ts << pChannel->midiChannel();
1128                  ts << endl;                                  ts << endl;
1129                  ts << "LOAD ENGINE " << pChannel->engineName() << " " << iChannel << endl;                                  ts << "LOAD ENGINE " << pChannel->engineName()
1130                                            << " " << iChannel << endl;
1131                                  if (pChannel->instrumentStatus() < 100) ts << "# ";                                  if (pChannel->instrumentStatus() < 100) ts << "# ";
1132                                  ts << "LOAD INSTRUMENT NON_MODAL '" << pChannel->instrumentFile() << "' "                                  ts << "LOAD INSTRUMENT NON_MODAL '"
1133                                            << pChannel->instrumentFile() << "' "
1134                                          << pChannel->instrumentNr() << " " << iChannel << endl;                                          << pChannel->instrumentNr() << " " << iChannel << endl;
1135                                  qsamplerChannelRoutingMap::ConstIterator audioRoute;                                  ChannelRoutingMap::ConstIterator audioRoute;
1136                                  for (audioRoute = pChannel->audioRouting().begin();                                  for (audioRoute = pChannel->audioRouting().begin();
1137                                                  audioRoute != pChannel->audioRouting().end();                                                  audioRoute != pChannel->audioRouting().end();
1138                                                          ++audioRoute) {                                                          ++audioRoute) {
1139                                          ts << "SET CHANNEL AUDIO_OUTPUT_CHANNEL " << iChannel                                          ts << "SET CHANNEL AUDIO_OUTPUT_CHANNEL " << iChannel
1140                                                  << " " << audioRoute.key()                                                  << " " << audioRoute.key()
1141                                                  << " " << audioRoute.data() << endl;                                                  << " " << audioRoute.value() << endl;
1142                                  }                                  }
1143                                  ts << "SET CHANNEL VOLUME " << iChannel                                  ts << "SET CHANNEL VOLUME " << iChannel
1144                                          << " " << pChannel->volume() << endl;                                          << " " << pChannel->volume() << endl;
# Line 1018  bool MainForm::saveSessionFile ( const Q Line 1188  bool MainForm::saveSessionFile ( const Q
1188                                          }                                          }
1189                                  }                                  }
1190  #endif  #endif
1191                  ts << endl;                                  ts << endl;
1192              }                          }
1193          }                  }
1194          // Try to keep it snappy :)                  // Try to keep it snappy :)
1195          QApplication::processEvents(QEventLoop::ExcludeUserInput);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1196      }          }
1197    
1198  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
1199          ts << "# " << tr("Global volume level") << endl;          ts << "# " << tr("Global volume level") << endl;
# Line 1031  bool MainForm::saveSessionFile ( const Q Line 1201  bool MainForm::saveSessionFile ( const Q
1201          ts << endl;          ts << endl;
1202  #endif  #endif
1203    
1204      // Ok. we've wrote it.          // Ok. we've wrote it.
1205      file.close();          file.close();
1206    
1207          // We're fornerly done.          // We're fornerly done.
1208          QApplication::restoreOverrideCursor();          QApplication::restoreOverrideCursor();
1209    
1210      // Have we any errors?          // Have we any errors?
1211      if (iErrors > 0)          if (iErrors > 0) {
1212          appendMessagesError(tr("Some settings could not be saved\nto \"%1\" session file.\n\nSorry.").arg(sFilename));                  appendMessagesError(
1213                            tr("Some settings could not be saved\n"
1214      // Save as default session directory.                          "to \"%1\" session file.\n\nSorry.")
1215      if (m_pOptions)                          .arg(sFilename));
1216          m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);          }
1217      // We're not dirty anymore.  
1218      m_iDirtyCount = 0;          // Save as default session directory.
1219      // Stabilize form...          if (m_pOptions)
1220      m_sFilename = sFilename;                  m_pOptions->sSessionDir = QFileInfo(sFilename).dir().absolutePath();
1221      updateRecentFiles(sFilename);          // We're not dirty anymore.
1222      appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename)));          m_iDirtyCount = 0;
1223      stabilizeForm();          // Stabilize form...
1224      return true;          m_sFilename = sFilename;
1225            updateRecentFiles(sFilename);
1226            appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename)));
1227            stabilizeForm();
1228            return true;
1229  }  }
1230    
1231    
1232  // Session change receiver slot.  // Session change receiver slot.
1233  void MainForm::sessionDirty (void)  void MainForm::sessionDirty (void)
1234  {  {
1235      // Just mark the dirty form.          // Just mark the dirty form.
1236      m_iDirtyCount++;          m_iDirtyCount++;
1237      // and update the form status...          // and update the form status...
1238      stabilizeForm();          stabilizeForm();
1239  }  }
1240    
1241    
# Line 1071  void MainForm::sessionDirty (void) Line 1245  void MainForm::sessionDirty (void)
1245  // Create a new sampler session.  // Create a new sampler session.
1246  void MainForm::fileNew (void)  void MainForm::fileNew (void)
1247  {  {
1248      // Of course we'll start clean new.          // Of course we'll start clean new.
1249      newSession();          newSession();
1250  }  }
1251    
1252    
1253  // Open an existing sampler session.  // Open an existing sampler session.
1254  void MainForm::fileOpen (void)  void MainForm::fileOpen (void)
1255  {  {
1256      // Open it right away.          // Open it right away.
1257      openSession();          openSession();
1258  }  }
1259    
1260    
1261  // Open a recent file session.  // Open a recent file session.
1262  void MainForm::fileOpenRecent ( int iIndex )  void MainForm::fileOpenRecent (void)
1263  {  {
1264      // Check if we can safely close the current session...          // Retrive filename index from action data...
1265      if (m_pOptions && closeSession(true)) {          QAction *pAction = qobject_cast<QAction *> (sender());
1266          QString sFilename = m_pOptions->recentFiles[iIndex];          if (pAction && m_pOptions) {
1267          loadSessionFile(sFilename);                  int iIndex = pAction->data().toInt();
1268      }                  if (iIndex >= 0 && iIndex < m_pOptions->recentFiles.count()) {
1269                            QString sFilename = m_pOptions->recentFiles[iIndex];
1270                            // Check if we can safely close the current session...
1271                            if (!sFilename.isEmpty() && closeSession(true))
1272                                    loadSessionFile(sFilename);
1273                    }
1274            }
1275  }  }
1276    
1277    
1278  // Save current sampler session.  // Save current sampler session.
1279  void MainForm::fileSave (void)  void MainForm::fileSave (void)
1280  {  {
1281      // Save it right away.          // Save it right away.
1282      saveSession(false);          saveSession(false);
1283  }  }
1284    
1285    
1286  // Save current sampler session with another name.  // Save current sampler session with another name.
1287  void MainForm::fileSaveAs (void)  void MainForm::fileSaveAs (void)
1288  {  {
1289      // Save it right away, maybe with another name.          // Save it right away, maybe with another name.
1290      saveSession(true);          saveSession(true);
1291  }  }
1292    
1293    
1294  // Reset the sampler instance.  // Reset the sampler instance.
1295  void MainForm::fileReset (void)  void MainForm::fileReset (void)
1296  {  {
1297      if (m_pClient == NULL)          if (m_pClient == NULL)
1298          return;                  return;
1299    
1300      // Ask user whether he/she want's an internal sampler reset...          // Ask user whether he/she want's an internal sampler reset...
1301      if (QMessageBox::warning(this,          if (QMessageBox::warning(this,
1302                  QSAMPLER_TITLE ": " + tr("Warning"),                  QSAMPLER_TITLE ": " + tr("Warning"),
1303          tr("Resetting the sampler instance will close\n"                  tr("Resetting the sampler instance will close\n"
1304             "all device and channel configurations.\n\n"                  "all device and channel configurations.\n\n"
1305             "Please note that this operation may cause\n"                  "Please note that this operation may cause\n"
1306             "temporary MIDI and Audio disruption.\n\n"                  "temporary MIDI and Audio disruption.\n\n"
1307             "Do you want to reset the sampler engine now?"),                  "Do you want to reset the sampler engine now?"),
1308          tr("Reset"), tr("Cancel")) > 0)                  tr("Reset"), tr("Cancel")) > 0)
1309          return;                  return;
1310    
1311          // Trye closing the current session, first...          // Trye closing the current session, first...
1312          if (!closeSession(true))          if (!closeSession(true))
1313                  return;                  return;
1314    
1315      // Just do the reset, after closing down current session...          // Just do the reset, after closing down current session...
1316          // Do the actual sampler reset...          // Do the actual sampler reset...
1317          if (::lscp_reset_sampler(m_pClient) != LSCP_OK) {          if (::lscp_reset_sampler(m_pClient) != LSCP_OK) {
1318                  appendMessagesClient("lscp_reset_sampler");                  appendMessagesClient("lscp_reset_sampler");
# Line 1140  void MainForm::fileReset (void) Line 1320  void MainForm::fileReset (void)
1320                  return;                  return;
1321          }          }
1322    
1323      // Log this.          // Log this.
1324      appendMessages(tr("Sampler reset."));          appendMessages(tr("Sampler reset."));
1325    
1326          // Make it a new session...          // Make it a new session...
1327          newSession();          newSession();
# Line 1151  void MainForm::fileReset (void) Line 1331  void MainForm::fileReset (void)
1331  // Restart the client/server instance.  // Restart the client/server instance.
1332  void MainForm::fileRestart (void)  void MainForm::fileRestart (void)
1333  {  {
1334      if (m_pOptions == NULL)          if (m_pOptions == NULL)
1335          return;                  return;
1336    
1337      bool bRestart = true;          bool bRestart = true;
1338    
1339      // Ask user whether he/she want's a complete restart...          // Ask user whether he/she want's a complete restart...
1340      // (if we're currently up and running)          // (if we're currently up and running)
1341      if (bRestart && m_pClient) {          if (bRestart && m_pClient) {
1342          bRestart = (QMessageBox::warning(this,                  bRestart = (QMessageBox::warning(this,
1343                          QSAMPLER_TITLE ": " + tr("Warning"),                          QSAMPLER_TITLE ": " + tr("Warning"),
1344              tr("New settings will be effective after\n"                          tr("New settings will be effective after\n"
1345                 "restarting the client/server connection.\n\n"                          "restarting the client/server connection.\n\n"
1346                 "Please note that this operation may cause\n"                          "Please note that this operation may cause\n"
1347                 "temporary MIDI and Audio disruption.\n\n"                          "temporary MIDI and Audio disruption.\n\n"
1348                 "Do you want to restart the connection now?"),                          "Do you want to restart the connection now?"),
1349              tr("Restart"), tr("Cancel")) == 0);                          tr("Restart"), tr("Cancel")) == 0);
1350      }          }
1351    
1352      // Are we still for it?          // Are we still for it?
1353      if (bRestart && closeSession(true)) {          if (bRestart && closeSession(true)) {
1354          // Stop server, it will force the client too.                  // Stop server, it will force the client too.
1355          stopServer();                  stopServer();
1356          // Reschedule a restart...                  // Reschedule a restart...
1357          startSchedule(m_pOptions->iStartDelay);                  startSchedule(m_pOptions->iStartDelay);
1358      }          }
1359  }  }
1360    
1361    
1362  // Exit application program.  // Exit application program.
1363  void MainForm::fileExit (void)  void MainForm::fileExit (void)
1364  {  {
1365      // Go for close the whole thing.          // Go for close the whole thing.
1366      close();          close();
1367  }  }
1368    
1369    
# Line 1193  void MainForm::fileExit (void) Line 1373  void MainForm::fileExit (void)
1373  // Add a new sampler channel.  // Add a new sampler channel.
1374  void MainForm::editAddChannel (void)  void MainForm::editAddChannel (void)
1375  {  {
1376      if (m_pClient == NULL)          if (m_pClient == NULL)
1377          return;                  return;
1378    
1379            // Just create the channel instance...
1380            Channel *pChannel = new Channel();
1381            if (pChannel == NULL)
1382                    return;
1383    
1384            // Before we show it up, may be we'll
1385            // better ask for some initial values?
1386            if (!pChannel->channelSetup(this)) {
1387                    delete pChannel;
1388                    return;
1389            }
1390    
1391            // And give it to the strip...
1392            // (will own the channel instance, if successful).
1393            if (!createChannelStrip(pChannel)) {
1394                    delete pChannel;
1395                    return;
1396            }
1397    
1398            // Do we auto-arrange?
1399            if (m_pOptions && m_pOptions->bAutoArrange)
1400                    channelsArrange();
1401    
1402      // Just create the channel instance...          // Make that an overall update.
1403      qsamplerChannel *pChannel = new qsamplerChannel();          m_iDirtyCount++;
1404      if (pChannel == NULL)          stabilizeForm();
         return;  
   
     // Before we show it up, may be we'll  
     // better ask for some initial values?  
     if (!pChannel->channelSetup(this)) {  
         delete pChannel;  
         return;  
     }  
   
     // And give it to the strip (will own the channel instance, if successful).  
     if (!createChannelStrip(pChannel)) {  
         delete pChannel;  
         return;  
     }  
   
     // Make that an overall update.  
     m_iDirtyCount++;  
     stabilizeForm();  
1405  }  }
1406    
1407    
1408  // Remove current sampler channel.  // Remove current sampler channel.
1409  void MainForm::editRemoveChannel (void)  void MainForm::editRemoveChannel (void)
1410  {  {
1411      if (m_pClient == NULL)          if (m_pClient == NULL)
1412          return;                  return;
1413    
1414            ChannelStrip* pChannelStrip = activeChannelStrip();
1415            if (pChannelStrip == NULL)
1416                    return;
1417    
1418      ChannelStrip* pChannelStrip = activeChannelStrip();          Channel *pChannel = pChannelStrip->channel();
1419      if (pChannelStrip == NULL)          if (pChannel == NULL)
1420          return;                  return;
1421    
1422      qsamplerChannel *pChannel = pChannelStrip->channel();          // Prompt user if he/she's sure about this...
1423      if (pChannel == NULL)          if (m_pOptions && m_pOptions->bConfirmRemove) {
1424          return;                  if (QMessageBox::warning(this,
   
     // Prompt user if he/she's sure about this...  
     if (m_pOptions && m_pOptions->bConfirmRemove) {  
         if (QMessageBox::warning(this,  
1425                          QSAMPLER_TITLE ": " + tr("Warning"),                          QSAMPLER_TITLE ": " + tr("Warning"),
1426              tr("About to remove channel:\n\n"                          tr("About to remove channel:\n\n"
1427                 "%1\n\n"                          "%1\n\n"
1428                 "Are you sure?")                          "Are you sure?")
1429                 .arg(pChannelStrip->caption()),                          .arg(pChannelStrip->windowTitle()),
1430              tr("OK"), tr("Cancel")) > 0)                          tr("OK"), tr("Cancel")) > 0)
1431              return;                          return;
1432      }          }
1433    
1434      // Remove the existing sampler channel.          // Remove the existing sampler channel.
1435      if (!pChannel->removeChannel())          if (!pChannel->removeChannel())
1436          return;                  return;
1437    
1438      // Just delete the channel strip.          // Just delete the channel strip.
1439      delete pChannelStrip;          delete pChannelStrip;
1440    
1441      // Do we auto-arrange?          // Do we auto-arrange?
1442      if (m_pOptions && m_pOptions->bAutoArrange)          if (m_pOptions && m_pOptions->bAutoArrange)
1443          channelsArrange();                  channelsArrange();
1444    
1445      // We'll be dirty, for sure...          // We'll be dirty, for sure...
1446      m_iDirtyCount++;          m_iDirtyCount++;
1447      stabilizeForm();          stabilizeForm();
1448  }  }
1449    
1450    
1451  // Setup current sampler channel.  // Setup current sampler channel.
1452  void MainForm::editSetupChannel (void)  void MainForm::editSetupChannel (void)
1453  {  {
1454      if (m_pClient == NULL)          if (m_pClient == NULL)
1455          return;                  return;
1456    
1457      ChannelStrip* pChannelStrip = activeChannelStrip();          ChannelStrip* pChannelStrip = activeChannelStrip();
1458      if (pChannelStrip == NULL)          if (pChannelStrip == NULL)
1459          return;                  return;
1460    
1461      // Just invoque the channel strip procedure.          // Just invoque the channel strip procedure.
1462      pChannelStrip->channelSetup();          pChannelStrip->channelSetup();
1463  }  }
1464    
1465    
1466  // Edit current sampler channel.  // Edit current sampler channel.
1467  void MainForm::editEditChannel (void)  void MainForm::editEditChannel (void)
1468  {  {
1469      if (m_pClient == NULL)          if (m_pClient == NULL)
1470          return;                  return;
1471    
1472      ChannelStrip* pChannelStrip = activeChannelStrip();          ChannelStrip* pChannelStrip = activeChannelStrip();
1473      if (pChannelStrip == NULL)          if (pChannelStrip == NULL)
1474          return;                  return;
1475    
1476      // Just invoque the channel strip procedure.          // Just invoque the channel strip procedure.
1477      pChannelStrip->channelEdit();          pChannelStrip->channelEdit();
1478  }  }
1479    
1480    
1481  // Reset current sampler channel.  // Reset current sampler channel.
1482  void MainForm::editResetChannel (void)  void MainForm::editResetChannel (void)
1483  {  {
1484      if (m_pClient == NULL)          if (m_pClient == NULL)
1485          return;                  return;
1486    
1487      ChannelStrip* pChannelStrip = activeChannelStrip();          ChannelStrip* pChannelStrip = activeChannelStrip();
1488      if (pChannelStrip == NULL)          if (pChannelStrip == NULL)
1489          return;                  return;
1490    
1491      // Just invoque the channel strip procedure.          // Just invoque the channel strip procedure.
1492      pChannelStrip->channelReset();          pChannelStrip->channelReset();
1493  }  }
1494    
1495    
# Line 1333  void MainForm::editResetAllChannels (voi Line 1518  void MainForm::editResetAllChannels (voi
1518  // Show/hide the main program window menubar.  // Show/hide the main program window menubar.
1519  void MainForm::viewMenubar ( bool bOn )  void MainForm::viewMenubar ( bool bOn )
1520  {  {
1521      if (bOn)          if (bOn)
1522          ui.MenuBar->show();                  m_ui.MenuBar->show();
1523      else          else
1524          ui.MenuBar->hide();                  m_ui.MenuBar->hide();
1525  }  }
1526    
1527    
1528  // Show/hide the main program window toolbar.  // Show/hide the main program window toolbar.
1529  void MainForm::viewToolbar ( bool bOn )  void MainForm::viewToolbar ( bool bOn )
1530  {  {
1531      if (bOn) {          if (bOn) {
1532          fileToolbar->show();                  m_ui.fileToolbar->show();
1533          editToolbar->show();                  m_ui.editToolbar->show();
1534          channelsToolbar->show();                  m_ui.channelsToolbar->show();
1535      } else {          } else {
1536          fileToolbar->hide();                  m_ui.fileToolbar->hide();
1537          editToolbar->hide();                  m_ui.editToolbar->hide();
1538          channelsToolbar->hide();                  m_ui.channelsToolbar->hide();
1539      }          }
1540  }  }
1541    
1542    
1543  // Show/hide the main program window statusbar.  // Show/hide the main program window statusbar.
1544  void MainForm::viewStatusbar ( bool bOn )  void MainForm::viewStatusbar ( bool bOn )
1545  {  {
1546      if (bOn)          if (bOn)
1547          statusBar()->show();                  statusBar()->show();
1548      else          else
1549          statusBar()->hide();                  statusBar()->hide();
1550  }  }
1551    
1552    
1553  // Show/hide the messages window logger.  // Show/hide the messages window logger.
1554  void MainForm::viewMessages ( bool bOn )  void MainForm::viewMessages ( bool bOn )
1555  {  {
1556      if (bOn)          if (bOn)
1557          m_pMessages->show();                  m_pMessages->show();
1558      else          else
1559          m_pMessages->hide();                  m_pMessages->hide();
1560  }  }
1561    
1562    
# Line 1388  void MainForm::viewInstruments (void) Line 1573  void MainForm::viewInstruments (void)
1573                  } else {                  } else {
1574                          m_pInstrumentListForm->show();                          m_pInstrumentListForm->show();
1575                          m_pInstrumentListForm->raise();                          m_pInstrumentListForm->raise();
1576                          m_pInstrumentListForm->setActiveWindow();                          m_pInstrumentListForm->activateWindow();
1577                  }                  }
1578          }          }
1579  }  }
# Line 1407  void MainForm::viewDevices (void) Line 1592  void MainForm::viewDevices (void)
1592                  } else {                  } else {
1593                          m_pDeviceForm->show();                          m_pDeviceForm->show();
1594                          m_pDeviceForm->raise();                          m_pDeviceForm->raise();
1595                          m_pDeviceForm->setActiveWindow();                          m_pDeviceForm->activateWindow();
1596                  }                  }
1597          }          }
1598  }  }
# Line 1416  void MainForm::viewDevices (void) Line 1601  void MainForm::viewDevices (void)
1601  // Show options dialog.  // Show options dialog.
1602  void MainForm::viewOptions (void)  void MainForm::viewOptions (void)
1603  {  {
1604      if (m_pOptions == NULL)          if (m_pOptions == NULL)
1605          return;                  return;
1606    
1607      OptionsForm* pOptionsForm = new OptionsForm(this);          OptionsForm* pOptionsForm = new OptionsForm(this);
1608      if (pOptionsForm) {          if (pOptionsForm) {
1609          // Check out some initial nullities(tm)...                  // Check out some initial nullities(tm)...
1610          ChannelStrip* pChannelStrip = activeChannelStrip();                  ChannelStrip* pChannelStrip = activeChannelStrip();
1611          if (m_pOptions->sDisplayFont.isEmpty() && pChannelStrip)                  if (m_pOptions->sDisplayFont.isEmpty() && pChannelStrip)
1612              m_pOptions->sDisplayFont = pChannelStrip->displayFont().toString();                          m_pOptions->sDisplayFont = pChannelStrip->displayFont().toString();
1613          if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages)                  if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages)
1614              m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();                          m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();
1615          // To track down deferred or immediate changes.                  // To track down deferred or immediate changes.
1616          QString sOldServerHost      = m_pOptions->sServerHost;                  QString sOldServerHost      = m_pOptions->sServerHost;
1617          int     iOldServerPort      = m_pOptions->iServerPort;                  int     iOldServerPort      = m_pOptions->iServerPort;
1618          int     iOldServerTimeout   = m_pOptions->iServerTimeout;                  int     iOldServerTimeout   = m_pOptions->iServerTimeout;
1619          bool    bOldServerStart     = m_pOptions->bServerStart;                  bool    bOldServerStart     = m_pOptions->bServerStart;
1620          QString sOldServerCmdLine   = m_pOptions->sServerCmdLine;                  QString sOldServerCmdLine   = m_pOptions->sServerCmdLine;
1621          QString sOldDisplayFont     = m_pOptions->sDisplayFont;                  bool    bOldMessagesLog     = m_pOptions->bMessagesLog;
1622          bool    bOldDisplayEffect   = m_pOptions->bDisplayEffect;                  QString sOldMessagesLogPath = m_pOptions->sMessagesLogPath;
1623          int     iOldMaxVolume       = m_pOptions->iMaxVolume;                  QString sOldDisplayFont     = m_pOptions->sDisplayFont;
1624          QString sOldMessagesFont    = m_pOptions->sMessagesFont;                  bool    bOldDisplayEffect   = m_pOptions->bDisplayEffect;
1625          bool    bOldKeepOnTop       = m_pOptions->bKeepOnTop;                  int     iOldMaxVolume       = m_pOptions->iMaxVolume;
1626          bool    bOldStdoutCapture   = m_pOptions->bStdoutCapture;                  QString sOldMessagesFont    = m_pOptions->sMessagesFont;
1627          int     bOldMessagesLimit   = m_pOptions->bMessagesLimit;                  bool    bOldKeepOnTop       = m_pOptions->bKeepOnTop;
1628          int     iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines;                  bool    bOldStdoutCapture   = m_pOptions->bStdoutCapture;
1629          bool    bOldCompletePath    = m_pOptions->bCompletePath;                  int     bOldMessagesLimit   = m_pOptions->bMessagesLimit;
1630          bool    bOldInstrumentNames = m_pOptions->bInstrumentNames;                  int     iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines;
1631          int     iOldMaxRecentFiles  = m_pOptions->iMaxRecentFiles;                  bool    bOldCompletePath    = m_pOptions->bCompletePath;
1632          // Load the current setup settings.                  bool    bOldInstrumentNames = m_pOptions->bInstrumentNames;
1633          pOptionsForm->setup(m_pOptions);                  int     iOldMaxRecentFiles  = m_pOptions->iMaxRecentFiles;
1634          // Show the setup dialog...                  // Load the current setup settings.
1635          if (pOptionsForm->exec()) {                  pOptionsForm->setup(m_pOptions);
1636              // Warn if something will be only effective on next run.                  // Show the setup dialog...
1637              if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) ||                  if (pOptionsForm->exec()) {
1638                  (!bOldStdoutCapture &&  m_pOptions->bStdoutCapture) ||                          // Warn if something will be only effective on next run.
1639                  ( bOldKeepOnTop     && !m_pOptions->bKeepOnTop)     ||                          if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) ||
1640                  (!bOldKeepOnTop     &&  m_pOptions->bKeepOnTop)) {                                  (!bOldStdoutCapture &&  m_pOptions->bStdoutCapture) ||
1641                  QMessageBox::information(this,                                  ( bOldKeepOnTop     && !m_pOptions->bKeepOnTop)     ||
1642                                    (!bOldKeepOnTop     &&  m_pOptions->bKeepOnTop)) {
1643                                    QMessageBox::information(this,
1644                                          QSAMPLER_TITLE ": " + tr("Information"),                                          QSAMPLER_TITLE ": " + tr("Information"),
1645                      tr("Some settings may be only effective\n"                                          tr("Some settings may be only effective\n"
1646                         "next time you start this program."), tr("OK"));                                          "next time you start this program."), tr("OK"));
1647                  updateMessagesCapture();                                  updateMessagesCapture();
1648              }                          }
1649              // Check wheather something immediate has changed.                          // Check wheather something immediate has changed.
1650              if (( bOldCompletePath && !m_pOptions->bCompletePath) ||                          if (( bOldMessagesLog && !m_pOptions->bMessagesLog) ||
1651                  (!bOldCompletePath &&  m_pOptions->bCompletePath) ||                                  (!bOldMessagesLog &&  m_pOptions->bMessagesLog) ||
1652                  (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles))                                  (sOldMessagesLogPath != m_pOptions->sMessagesLogPath))
1653                  updateRecentFilesMenu();                                  m_pMessages->setLogging(
1654              if (( bOldInstrumentNames && !m_pOptions->bInstrumentNames) ||                                          m_pOptions->bMessagesLog, m_pOptions->sMessagesLogPath);
1655                  (!bOldInstrumentNames &&  m_pOptions->bInstrumentNames))                          if (( bOldCompletePath && !m_pOptions->bCompletePath) ||
1656                  updateInstrumentNames();                                  (!bOldCompletePath &&  m_pOptions->bCompletePath) ||
1657              if (( bOldDisplayEffect && !m_pOptions->bDisplayEffect) ||                                  (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles))
1658                  (!bOldDisplayEffect &&  m_pOptions->bDisplayEffect))                                  updateRecentFilesMenu();
1659                  updateDisplayEffect();                          if (( bOldInstrumentNames && !m_pOptions->bInstrumentNames) ||
1660              if (sOldDisplayFont != m_pOptions->sDisplayFont)                                  (!bOldInstrumentNames &&  m_pOptions->bInstrumentNames))
1661                  updateDisplayFont();                                  updateInstrumentNames();
1662              if (iOldMaxVolume != m_pOptions->iMaxVolume)                          if (( bOldDisplayEffect && !m_pOptions->bDisplayEffect) ||
1663                  updateMaxVolume();                                  (!bOldDisplayEffect &&  m_pOptions->bDisplayEffect))
1664              if (sOldMessagesFont != m_pOptions->sMessagesFont)                                  updateDisplayEffect();
1665                  updateMessagesFont();                          if (sOldDisplayFont != m_pOptions->sDisplayFont)
1666              if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) ||                                  updateDisplayFont();
1667                  (!bOldMessagesLimit &&  m_pOptions->bMessagesLimit) ||                          if (iOldMaxVolume != m_pOptions->iMaxVolume)
1668                  (iOldMessagesLimitLines !=  m_pOptions->iMessagesLimitLines))                                  updateMaxVolume();
1669                  updateMessagesLimit();                          if (sOldMessagesFont != m_pOptions->sMessagesFont)
1670              // And now the main thing, whether we'll do client/server recycling?                                  updateMessagesFont();
1671              if ((sOldServerHost != m_pOptions->sServerHost) ||                          if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) ||
1672                  (iOldServerPort != m_pOptions->iServerPort) ||                                  (!bOldMessagesLimit &&  m_pOptions->bMessagesLimit) ||
1673                  (iOldServerTimeout != m_pOptions->iServerTimeout) ||                                  (iOldMessagesLimitLines !=  m_pOptions->iMessagesLimitLines))
1674                  ( bOldServerStart && !m_pOptions->bServerStart) ||                                  updateMessagesLimit();
1675                  (!bOldServerStart &&  m_pOptions->bServerStart) ||                          // And now the main thing, whether we'll do client/server recycling?
1676                  (sOldServerCmdLine != m_pOptions->sServerCmdLine && m_pOptions->bServerStart))                          if ((sOldServerHost != m_pOptions->sServerHost) ||
1677                  fileRestart();                                  (iOldServerPort != m_pOptions->iServerPort) ||
1678          }                                  (iOldServerTimeout != m_pOptions->iServerTimeout) ||
1679          // Done.                                  ( bOldServerStart && !m_pOptions->bServerStart) ||
1680          delete pOptionsForm;                                  (!bOldServerStart &&  m_pOptions->bServerStart) ||
1681      }                                  (sOldServerCmdLine != m_pOptions->sServerCmdLine
1682                                    && m_pOptions->bServerStart))
1683                                    fileRestart();
1684                    }
1685                    // Done.
1686                    delete pOptionsForm;
1687            }
1688    
1689      // This makes it.          // This makes it.
1690      stabilizeForm();          stabilizeForm();
1691  }  }
1692    
1693    
# Line 1504  void MainForm::viewOptions (void) Line 1697  void MainForm::viewOptions (void)
1697  // Arrange channel strips.  // Arrange channel strips.
1698  void MainForm::channelsArrange (void)  void MainForm::channelsArrange (void)
1699  {  {
1700      // Full width vertical tiling          // Full width vertical tiling
1701      QWidgetList wlist = m_pWorkspace->windowList();          QWidgetList wlist = m_pWorkspace->windowList();
1702      if (wlist.isEmpty())          if (wlist.isEmpty())
1703          return;                  return;
   
     m_pWorkspace->setUpdatesEnabled(false);  
     int y = 0;  
     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {  
         ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);  
     /*  if (pChannelStrip->testWState(WState_Maximized | WState_Minimized)) {  
             // Prevent flicker...  
             pChannelStrip->hide();  
             pChannelStrip->showNormal();  
         }   */  
         pChannelStrip->adjustSize();  
         int iWidth  = m_pWorkspace->width();  
         if (iWidth < pChannelStrip->width())  
             iWidth = pChannelStrip->width();  
     //  int iHeight = pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();  
         int iHeight = pChannelStrip->parentWidget()->frameGeometry().height();  
         pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight);  
         y += iHeight;  
     }  
     m_pWorkspace->setUpdatesEnabled(true);  
1704    
1705      stabilizeForm();          m_pWorkspace->setUpdatesEnabled(false);
1706            int y = 0;
1707            for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1708                    ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);
1709            /*  if (pChannelStrip->testWState(WState_Maximized | WState_Minimized)) {
1710                            // Prevent flicker...
1711                            pChannelStrip->hide();
1712                            pChannelStrip->showNormal();
1713                    }   */
1714                    pChannelStrip->adjustSize();
1715                    int iWidth  = m_pWorkspace->width();
1716                    if (iWidth < pChannelStrip->width())
1717                            iWidth = pChannelStrip->width();
1718            //  int iHeight = pChannelStrip->height()
1719            //              + pChannelStrip->parentWidget()->baseSize().height();
1720                    int iHeight = pChannelStrip->parentWidget()->frameGeometry().height();
1721                    pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1722                    y += iHeight;
1723            }
1724            m_pWorkspace->setUpdatesEnabled(true);
1725    
1726            stabilizeForm();
1727  }  }
1728    
1729    
1730  // Auto-arrange channel strips.  // Auto-arrange channel strips.
1731  void MainForm::channelsAutoArrange ( bool bOn )  void MainForm::channelsAutoArrange ( bool bOn )
1732  {  {
1733      if (m_pOptions == NULL)          if (m_pOptions == NULL)
1734          return;                  return;
1735    
1736      // Toggle the auto-arrange flag.          // Toggle the auto-arrange flag.
1737      m_pOptions->bAutoArrange = bOn;          m_pOptions->bAutoArrange = bOn;
1738    
1739      // If on, update whole workspace...          // If on, update whole workspace...
1740      if (m_pOptions->bAutoArrange)          if (m_pOptions->bAutoArrange)
1741          channelsArrange();                  channelsArrange();
1742  }  }
1743    
1744    
# Line 1554  void MainForm::channelsAutoArrange ( boo Line 1748  void MainForm::channelsAutoArrange ( boo
1748  // Show information about the Qt toolkit.  // Show information about the Qt toolkit.
1749  void MainForm::helpAboutQt (void)  void MainForm::helpAboutQt (void)
1750  {  {
1751      QMessageBox::aboutQt(this);          QMessageBox::aboutQt(this);
1752  }  }
1753    
1754    
1755  // Show information about application program.  // Show information about application program.
1756  void MainForm::helpAbout (void)  void MainForm::helpAbout (void)
1757  {  {
1758      // Stuff the about box text...          // Stuff the about box text...
1759      QString sText = "<p>\n";          QString sText = "<p>\n";
1760      sText += "<b>" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "</b><br />\n";          sText += "<b>" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "</b><br />\n";
1761      sText += "<br />\n";          sText += "<br />\n";
1762      sText += tr("Version") + ": <b>" QSAMPLER_VERSION "</b><br />\n";          sText += tr("Version") + ": <b>" QSAMPLER_VERSION "</b><br />\n";
1763      sText += "<small>" + tr("Build") + ": " __DATE__ " " __TIME__ "</small><br />\n";          sText += "<small>" + tr("Build") + ": " __DATE__ " " __TIME__ "</small><br />\n";
1764  #ifdef CONFIG_DEBUG  #ifdef CONFIG_DEBUG
1765      sText += "<small><font color=\"red\">";          sText += "<small><font color=\"red\">";
1766      sText += tr("Debugging option enabled.");          sText += tr("Debugging option enabled.");
1767      sText += "</font></small><br />";          sText += "</font></small><br />";
1768  #endif  #endif
1769  #ifndef CONFIG_LIBGIG  #ifndef CONFIG_LIBGIG
1770      sText += "<small><font color=\"red\">";          sText += "<small><font color=\"red\">";
1771      sText += tr("GIG (libgig) file support disabled.");          sText += tr("GIG (libgig) file support disabled.");
1772      sText += "</font></small><br />";          sText += "</font></small><br />";
1773  #endif  #endif
1774  #ifndef CONFIG_INSTRUMENT_NAME  #ifndef CONFIG_INSTRUMENT_NAME
1775      sText += "<small><font color=\"red\">";          sText += "<small><font color=\"red\">";
1776      sText += tr("LSCP (liblscp) instrument_name support disabled.");          sText += tr("LSCP (liblscp) instrument_name support disabled.");
1777      sText += "</font></small><br />";          sText += "</font></small><br />";
1778  #endif  #endif
1779  #ifndef CONFIG_MUTE_SOLO  #ifndef CONFIG_MUTE_SOLO
1780      sText += "<small><font color=\"red\">";          sText += "<small><font color=\"red\">";
1781      sText += tr("Sampler channel Mute/Solo support disabled.");          sText += tr("Sampler channel Mute/Solo support disabled.");
1782      sText += "</font></small><br />";          sText += "</font></small><br />";
1783  #endif  #endif
1784  #ifndef CONFIG_AUDIO_ROUTING  #ifndef CONFIG_AUDIO_ROUTING
1785      sText += "<small><font color=\"red\">";          sText += "<small><font color=\"red\">";
1786      sText += tr("LSCP (liblscp) audio_routing support disabled.");          sText += tr("LSCP (liblscp) audio_routing support disabled.");
1787      sText += "</font></small><br />";          sText += "</font></small><br />";
1788  #endif  #endif
1789  #ifndef CONFIG_FXSEND  #ifndef CONFIG_FXSEND
1790      sText += "<small><font color=\"red\">";          sText += "<small><font color=\"red\">";
1791      sText += tr("Sampler channel Effect Sends support disabled.");          sText += tr("Sampler channel Effect Sends support disabled.");
1792      sText += "</font></small><br />";          sText += "</font></small><br />";
1793  #endif  #endif
1794  #ifndef CONFIG_VOLUME  #ifndef CONFIG_VOLUME
1795      sText += "<small><font color=\"red\">";          sText += "<small><font color=\"red\">";
1796      sText += tr("Global volume support disabled.");          sText += tr("Global volume support disabled.");
1797      sText += "</font></small><br />";          sText += "</font></small><br />";
1798  #endif  #endif
1799  #ifndef CONFIG_MIDI_INSTRUMENT  #ifndef CONFIG_MIDI_INSTRUMENT
1800      sText += "<small><font color=\"red\">";          sText += "<small><font color=\"red\">";
1801      sText += tr("MIDI instrument mapping support disabled.");          sText += tr("MIDI instrument mapping support disabled.");
1802      sText += "</font></small><br />";          sText += "</font></small><br />";
1803  #endif  #endif
1804  #ifndef CONFIG_EDIT_INSTRUMENT  #ifndef CONFIG_EDIT_INSTRUMENT
1805      sText += "<small><font color=\"red\">";          sText += "<small><font color=\"red\">";
1806      sText += tr("Instrument editing support disabled.");          sText += tr("Instrument editing support disabled.");
1807      sText += "</font></small><br />";          sText += "</font></small><br />";
1808  #endif  #endif
1809      sText += "<br />\n";          sText += "<br />\n";
1810      sText += tr("Using") + ": ";          sText += tr("Using") + ": ";
1811      sText += ::lscp_client_package();          sText += ::lscp_client_package();
1812      sText += " ";          sText += " ";
1813      sText += ::lscp_client_version();          sText += ::lscp_client_version();
1814  #ifdef CONFIG_LIBGIG  #ifdef CONFIG_LIBGIG
1815      sText += ", ";          sText += ", ";
1816      sText += gig::libraryName().c_str();          sText += gig::libraryName().c_str();
1817      sText += " ";          sText += " ";
1818      sText += gig::libraryVersion().c_str();          sText += gig::libraryVersion().c_str();
1819  #endif  #endif
1820      sText += "<br />\n";          sText += "<br />\n";
1821      sText += "<br />\n";          sText += "<br />\n";
1822      sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";          sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";
1823      sText += "<br />\n";          sText += "<br />\n";
1824      sText += "<small>";          sText += "<small>";
1825      sText += QSAMPLER_COPYRIGHT "<br />\n";          sText += QSAMPLER_COPYRIGHT "<br />\n";
1826      sText += "<br />\n";          sText += QSAMPLER_COPYRIGHT2 "<br />\n";
1827      sText += tr("This program is free software; you can redistribute it and/or modify it") + "<br />\n";          sText += "<br />\n";
1828      sText += tr("under the terms of the GNU General Public License version 2 or later.");          sText += tr("This program is free software; you can redistribute it and/or modify it") + "<br />\n";
1829      sText += "</small>";          sText += tr("under the terms of the GNU General Public License version 2 or later.");
1830      sText += "</p>\n";          sText += "</small>";
1831            sText += "</p>\n";
1832    
1833      QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText);          QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText);
1834  }  }
1835    
1836    
# Line 1644  void MainForm::helpAbout (void) Line 1839  void MainForm::helpAbout (void)
1839    
1840  void MainForm::stabilizeForm (void)  void MainForm::stabilizeForm (void)
1841  {  {
1842      // Update the main application caption...          // Update the main application caption...
1843      QString sSessionName = sessionName(m_sFilename);          QString sSessionName = sessionName(m_sFilename);
1844      if (m_iDirtyCount > 0)          if (m_iDirtyCount > 0)
1845          sSessionName += " *";                  sSessionName += " *";
1846      setCaption(tr(QSAMPLER_TITLE " - [%1]").arg(sSessionName));          setWindowTitle(tr(QSAMPLER_TITLE " - [%1]").arg(sSessionName));
1847    
1848      // Update the main menu state...          // Update the main menu state...
1849      ChannelStrip* pChannelStrip = activeChannelStrip();          ChannelStrip* pChannelStrip = activeChannelStrip();
1850      bool bHasClient  = (m_pOptions != NULL && m_pClient != NULL);          bool bHasClient  = (m_pOptions != NULL && m_pClient != NULL);
1851      bool bHasChannel = (bHasClient && pChannelStrip != NULL);          bool bHasChannel = (bHasClient && pChannelStrip != NULL);
1852      ui.fileNewAction->setEnabled(bHasClient);          m_ui.fileNewAction->setEnabled(bHasClient);
1853      ui.fileOpenAction->setEnabled(bHasClient);          m_ui.fileOpenAction->setEnabled(bHasClient);
1854      ui.fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);          m_ui.fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);
1855      ui.fileSaveAsAction->setEnabled(bHasClient);          m_ui.fileSaveAsAction->setEnabled(bHasClient);
1856      ui.fileResetAction->setEnabled(bHasClient);          m_ui.fileResetAction->setEnabled(bHasClient);
1857      ui.fileRestartAction->setEnabled(bHasClient || m_pServer == NULL);          m_ui.fileRestartAction->setEnabled(bHasClient || m_pServer == NULL);
1858      ui.editAddChannelAction->setEnabled(bHasClient);          m_ui.editAddChannelAction->setEnabled(bHasClient);
1859      ui.editRemoveChannelAction->setEnabled(bHasChannel);          m_ui.editRemoveChannelAction->setEnabled(bHasChannel);
1860      ui.editSetupChannelAction->setEnabled(bHasChannel);          m_ui.editSetupChannelAction->setEnabled(bHasChannel);
1861  #ifdef CONFIG_EDIT_INSTRUMENT  #ifdef CONFIG_EDIT_INSTRUMENT
1862      ui.editEditChannelAction->setEnabled(bHasChannel);          m_ui.editEditChannelAction->setEnabled(bHasChannel);
1863  #else  #else
1864      ui.editEditChannelAction->setEnabled(false);          m_ui.editEditChannelAction->setEnabled(false);
1865  #endif  #endif
1866      ui.editResetChannelAction->setEnabled(bHasChannel);          m_ui.editResetChannelAction->setEnabled(bHasChannel);
1867      ui.editResetAllChannelsAction->setEnabled(bHasChannel);          m_ui.editResetAllChannelsAction->setEnabled(bHasChannel);
1868      ui.viewMessagesAction->setOn(m_pMessages && m_pMessages->isVisible());          m_ui.viewMessagesAction->setChecked(m_pMessages && m_pMessages->isVisible());
1869  #ifdef CONFIG_MIDI_INSTRUMENT  #ifdef CONFIG_MIDI_INSTRUMENT
1870          ui.viewInstrumentsAction->setOn(m_pInstrumentListForm          m_ui.viewInstrumentsAction->setChecked(m_pInstrumentListForm
1871                  && m_pInstrumentListForm->isVisible());                  && m_pInstrumentListForm->isVisible());
1872          ui.viewInstrumentsAction->setEnabled(bHasClient);          m_ui.viewInstrumentsAction->setEnabled(bHasClient);
1873  #else  #else
1874          ui.viewInstrumentsAction->setEnabled(false);          m_ui.viewInstrumentsAction->setEnabled(false);
1875  #endif  #endif
1876          ui.viewDevicesAction->setOn(m_pDeviceForm          m_ui.viewDevicesAction->setChecked(m_pDeviceForm
1877                  && m_pDeviceForm->isVisible());                  && m_pDeviceForm->isVisible());
1878      ui.viewDevicesAction->setEnabled(bHasClient);          m_ui.viewDevicesAction->setEnabled(bHasClient);
1879      ui.channelsArrangeAction->setEnabled(bHasChannel);          m_ui.channelsArrangeAction->setEnabled(bHasChannel);
1880    
1881  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
1882          // Toolbar widgets are also affected...          // Toolbar widgets are also affected...
1883      m_pVolumeSlider->setEnabled(bHasClient);          m_pVolumeSlider->setEnabled(bHasClient);
1884      m_pVolumeSpinBox->setEnabled(bHasClient);          m_pVolumeSpinBox->setEnabled(bHasClient);
1885  #endif  #endif
1886    
1887      // Client/Server status...          // Client/Server status...
1888      if (bHasClient) {          if (bHasClient) {
1889          m_statusItem[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));                  m_statusItem[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));
1890          m_statusItem[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost + ":" + QString::number(m_pOptions->iServerPort));                  m_statusItem[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost
1891      } else {                          + ':' + QString::number(m_pOptions->iServerPort));
1892          m_statusItem[QSAMPLER_STATUS_CLIENT]->clear();          } else {
1893          m_statusItem[QSAMPLER_STATUS_SERVER]->clear();                  m_statusItem[QSAMPLER_STATUS_CLIENT]->clear();
1894      }                  m_statusItem[QSAMPLER_STATUS_SERVER]->clear();
1895      // Channel status...          }
1896      if (bHasChannel)          // Channel status...
1897          m_statusItem[QSAMPLER_STATUS_CHANNEL]->setText(pChannelStrip->caption());          if (bHasChannel)
1898      else                  m_statusItem[QSAMPLER_STATUS_CHANNEL]->setText(pChannelStrip->windowTitle());
1899          m_statusItem[QSAMPLER_STATUS_CHANNEL]->clear();          else
1900      // Session status...                  m_statusItem[QSAMPLER_STATUS_CHANNEL]->clear();
1901      if (m_iDirtyCount > 0)          // Session status...
1902          m_statusItem[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));          if (m_iDirtyCount > 0)
1903      else                  m_statusItem[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));
1904          m_statusItem[QSAMPLER_STATUS_SESSION]->clear();          else
1905                    m_statusItem[QSAMPLER_STATUS_SESSION]->clear();
1906      // Recent files menu.  
1907      m_pRecentFilesMenu->setEnabled(bHasClient && m_pOptions->recentFiles.count() > 0);          // Recent files menu.
1908            m_ui.fileOpenRecentMenu->setEnabled(m_pOptions->recentFiles.count() > 0);
     // Always make the latest message visible.  
     if (m_pMessages)  
         m_pMessages->scrollToBottom();  
1909  }  }
1910    
1911    
# Line 1753  void MainForm::volumeChanged ( int iVolu Line 1945  void MainForm::volumeChanged ( int iVolu
1945  void MainForm::channelStripChanged(ChannelStrip* pChannelStrip)  void MainForm::channelStripChanged(ChannelStrip* pChannelStrip)
1946  {  {
1947          // Add this strip to the changed list...          // Add this strip to the changed list...
1948          if (m_changedStrips.containsRef(pChannelStrip) == 0) {          if (!m_changedStrips.contains(pChannelStrip)) {
1949                  m_changedStrips.append(pChannelStrip);                  m_changedStrips.append(pChannelStrip);
1950                  pChannelStrip->resetErrorCount();                  pChannelStrip->resetErrorCount();
1951          }          }
1952    
1953      // Just mark the dirty form.          // Just mark the dirty form.
1954      m_iDirtyCount++;          m_iDirtyCount++;
1955      // and update the form status...          // and update the form status...
1956      stabilizeForm();          stabilizeForm();
1957  }  }
1958    
1959    
# Line 1781  void MainForm::updateSession (void) Line 1973  void MainForm::updateSession (void)
1973          if (iMaps < 0)          if (iMaps < 0)
1974                  appendMessagesClient("lscp_get_midi_instrument_maps");                  appendMessagesClient("lscp_get_midi_instrument_maps");
1975          else if (iMaps < 1) {          else if (iMaps < 1) {
1976                  ::lscp_add_midi_instrument_map(m_pClient, tr("Chromatic").latin1());                  ::lscp_add_midi_instrument_map(m_pClient,
1977                  ::lscp_add_midi_instrument_map(m_pClient, tr("Drum Kits").latin1());                          tr("Chromatic").toUtf8().constData());
1978                    ::lscp_add_midi_instrument_map(m_pClient,
1979                            tr("Drum Kits").toUtf8().constData());
1980          }          }
1981  #endif  #endif
1982    
1983            updateAllChannelStrips(false);
1984    
1985            // Do we auto-arrange?
1986            if (m_pOptions && m_pOptions->bAutoArrange)
1987                    channelsArrange();
1988    
1989            // Remember to refresh devices and instruments...
1990            if (m_pInstrumentListForm)
1991                    m_pInstrumentListForm->refreshInstruments();
1992            if (m_pDeviceForm)
1993                    m_pDeviceForm->refreshDevices();
1994    }
1995    
1996    void MainForm::updateAllChannelStrips(bool bRemoveDeadStrips) {
1997          // Retrieve the current channel list.          // Retrieve the current channel list.
1998          int *piChannelIDs = ::lscp_list_channels(m_pClient);          int *piChannelIDs = ::lscp_list_channels(m_pClient);
1999          if (piChannelIDs == NULL) {          if (piChannelIDs == NULL) {
2000                  if (::lscp_client_get_errno(m_pClient)) {                  if (::lscp_client_get_errno(m_pClient)) {
2001                          appendMessagesClient("lscp_list_channels");                          appendMessagesClient("lscp_list_channels");
2002                          appendMessagesError(tr("Could not get current list of channels.\n\nSorry."));                          appendMessagesError(
2003                                    tr("Could not get current list of channels.\n\nSorry."));
2004                  }                  }
2005          } else {          } else {
2006                  // Try to (re)create each channel.                  // Try to (re)create each channel.
# Line 1799  void MainForm::updateSession (void) Line 2008  void MainForm::updateSession (void)
2008                  for (int iChannel = 0; piChannelIDs[iChannel] >= 0; iChannel++) {                  for (int iChannel = 0; piChannelIDs[iChannel] >= 0; iChannel++) {
2009                          // Check if theres already a channel strip for this one...                          // Check if theres already a channel strip for this one...
2010                          if (!channelStrip(piChannelIDs[iChannel]))                          if (!channelStrip(piChannelIDs[iChannel]))
2011                                  createChannelStrip(new qsamplerChannel(piChannelIDs[iChannel]));                                  createChannelStrip(new Channel(piChannelIDs[iChannel]));
2012                    }
2013    
2014                    // Do we auto-arrange?
2015                    if (m_pOptions && m_pOptions->bAutoArrange)
2016                            channelsArrange();
2017    
2018                    stabilizeForm();
2019    
2020                    // remove dead channel strips
2021                    if (bRemoveDeadStrips) {
2022                            for (int i = 0; channelStripAt(i); ++i) {
2023                                    ChannelStrip* pChannelStrip = channelStripAt(i);
2024                                    bool bExists = false;
2025                                    for (int j = 0; piChannelIDs[j] >= 0; ++j) {
2026                                            if (!pChannelStrip->channel()) break;
2027                                            if (piChannelIDs[j] == pChannelStrip->channel()->channelID()) {
2028                                                    // strip exists, don't touch it
2029                                                    bExists = true;
2030                                                    break;
2031                                            }
2032                                    }
2033                                    if (!bExists) destroyChannelStrip(pChannelStrip);
2034                            }
2035                  }                  }
2036                  m_pWorkspace->setUpdatesEnabled(true);                  m_pWorkspace->setUpdatesEnabled(true);
2037          }          }
   
     // Do we auto-arrange?  
     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();  
2038  }  }
2039    
   
2040  // Update the recent files list and menu.  // Update the recent files list and menu.
2041  void MainForm::updateRecentFiles ( const QString& sFilename )  void MainForm::updateRecentFiles ( const QString& sFilename )
2042  {  {
2043      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2044          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);  
2045    
2046      // May update the menu.          // Remove from list if already there (avoid duplicates)
2047      updateRecentFilesMenu();          int iIndex = m_pOptions->recentFiles.indexOf(sFilename);
2048            if (iIndex >= 0)
2049                    m_pOptions->recentFiles.removeAt(iIndex);
2050            // Put it to front...
2051            m_pOptions->recentFiles.push_front(sFilename);
2052  }  }
2053    
2054    
2055  // Update the recent files list and menu.  // Update the recent files list and menu.
2056  void MainForm::updateRecentFilesMenu (void)  void MainForm::updateRecentFilesMenu (void)
2057  {  {
2058      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2059          return;                  return;
2060    
2061            // Time to keep the list under limits.
2062            int iRecentFiles = m_pOptions->recentFiles.count();
2063            while (iRecentFiles > m_pOptions->iMaxRecentFiles) {
2064                    m_pOptions->recentFiles.pop_back();
2065                    iRecentFiles--;
2066            }
2067    
2068      // Time to keep the list under limits.          // Rebuild the recent files menu...
2069      int iRecentFiles = m_pOptions->recentFiles.count();          m_ui.fileOpenRecentMenu->clear();
2070      while (iRecentFiles > m_pOptions->iMaxRecentFiles) {          for (int i = 0; i < iRecentFiles; i++) {
2071          m_pOptions->recentFiles.pop_back();                  const QString& sFilename = m_pOptions->recentFiles[i];
2072          iRecentFiles--;                  if (QFileInfo(sFilename).exists()) {
2073      }                          QAction *pAction = m_ui.fileOpenRecentMenu->addAction(
2074                                    QString("&%1 %2").arg(i + 1).arg(sessionName(sFilename)),
2075      // rebuild the recent files menu...                                  this, SLOT(fileOpenRecent()));
2076      m_pRecentFilesMenu->clear();                          pAction->setData(i);
2077      for (int i = 0; i < iRecentFiles; i++) {                  }
2078          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);  
         }  
     }  
2079  }  }
2080    
2081    
2082  // Force update of the channels instrument names mode.  // Force update of the channels instrument names mode.
2083  void MainForm::updateInstrumentNames (void)  void MainForm::updateInstrumentNames (void)
2084  {  {
2085      // Full channel list update...          // Full channel list update...
2086      QWidgetList wlist = m_pWorkspace->windowList();          QWidgetList wlist = m_pWorkspace->windowList();
2087      if (wlist.isEmpty())          if (wlist.isEmpty())
2088          return;                  return;
2089    
2090      m_pWorkspace->setUpdatesEnabled(false);          m_pWorkspace->setUpdatesEnabled(false);
2091      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
2092          ChannelStrip *pChannelStrip = (ChannelStrip *) wlist.at(iChannel);                  ChannelStrip *pChannelStrip = (ChannelStrip *) wlist.at(iChannel);
2093          if (pChannelStrip)                  if (pChannelStrip)
2094              pChannelStrip->updateInstrumentName(true);                          pChannelStrip->updateInstrumentName(true);
2095      }          }
2096      m_pWorkspace->setUpdatesEnabled(true);          m_pWorkspace->setUpdatesEnabled(true);
2097  }  }
2098    
2099    
2100  // Force update of the channels display font.  // Force update of the channels display font.
2101  void MainForm::updateDisplayFont (void)  void MainForm::updateDisplayFont (void)
2102  {  {
2103      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2104          return;                  return;
2105    
2106            // Check if display font is legal.
2107            if (m_pOptions->sDisplayFont.isEmpty())
2108                    return;
2109            // Realize it.
2110            QFont font;
2111            if (!font.fromString(m_pOptions->sDisplayFont))
2112                    return;
2113    
2114            // Full channel list update...
2115            QWidgetList wlist = m_pWorkspace->windowList();
2116            if (wlist.isEmpty())
2117                    return;
2118    
2119      // Check if display font is legal.          m_pWorkspace->setUpdatesEnabled(false);
2120      if (m_pOptions->sDisplayFont.isEmpty())          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
2121          return;                  ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);
2122      // Realize it.                  if (pChannelStrip)
2123      QFont font;                          pChannelStrip->setDisplayFont(font);
2124      if (!font.fromString(m_pOptions->sDisplayFont))          }
2125          return;          m_pWorkspace->setUpdatesEnabled(true);
   
     // Full channel list update...  
     QWidgetList wlist = m_pWorkspace->windowList();  
     if (wlist.isEmpty())  
         return;  
   
     m_pWorkspace->setUpdatesEnabled(false);  
     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {  
         ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);  
         if (pChannelStrip)  
             pChannelStrip->setDisplayFont(font);  
     }  
     m_pWorkspace->setUpdatesEnabled(true);  
2126  }  }
2127    
2128    
2129  // Update channel strips background effect.  // Update channel strips background effect.
2130  void MainForm::updateDisplayEffect (void)  void MainForm::updateDisplayEffect (void)
2131  {  {
2132     QPixmap pm;          // Full channel list update...
2133      if (m_pOptions->bDisplayEffect)          QWidgetList wlist = m_pWorkspace->windowList();
2134          pm = QPixmap(":/qsampler/pixmaps/displaybg1.png");          if (wlist.isEmpty())
2135                    return;
2136      // Full channel list update...  
2137      QWidgetList wlist = m_pWorkspace->windowList();          m_pWorkspace->setUpdatesEnabled(false);
2138      if (wlist.isEmpty())          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
2139          return;                  ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);
2140                    if (pChannelStrip)
2141      m_pWorkspace->setUpdatesEnabled(false);                          pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
2142      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          }
2143          ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);          m_pWorkspace->setUpdatesEnabled(true);
         if (pChannelStrip)  
             pChannelStrip->setDisplayBackground(pm);  
     }  
     m_pWorkspace->setUpdatesEnabled(true);  
2144  }  }
2145    
2146    
2147  // Force update of the channels maximum volume setting.  // Force update of the channels maximum volume setting.
2148  void MainForm::updateMaxVolume (void)  void MainForm::updateMaxVolume (void)
2149  {  {
2150      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2151          return;                  return;
2152    
2153  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
2154          m_iVolumeChanging++;          m_iVolumeChanging++;
2155          m_pVolumeSlider->setMaxValue(m_pOptions->iMaxVolume);          m_pVolumeSlider->setMaximum(m_pOptions->iMaxVolume);
2156          m_pVolumeSpinBox->setMaxValue(m_pOptions->iMaxVolume);          m_pVolumeSpinBox->setMaximum(m_pOptions->iMaxVolume);
2157          m_iVolumeChanging--;          m_iVolumeChanging--;
2158  #endif  #endif
2159    
2160      // Full channel list update...          // Full channel list update...
2161      QWidgetList wlist = m_pWorkspace->windowList();          QWidgetList wlist = m_pWorkspace->windowList();
2162      if (wlist.isEmpty())          if (wlist.isEmpty())
2163          return;                  return;
2164    
2165      m_pWorkspace->setUpdatesEnabled(false);          m_pWorkspace->setUpdatesEnabled(false);
2166      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
2167          ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);                  ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);
2168          if (pChannelStrip)                  if (pChannelStrip)
2169              pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);                          pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
2170      }          }
2171      m_pWorkspace->setUpdatesEnabled(true);          m_pWorkspace->setUpdatesEnabled(true);
2172  }  }
2173    
2174    
# Line 1963  void MainForm::updateMaxVolume (void) Line 2178  void MainForm::updateMaxVolume (void)
2178  // Messages output methods.  // Messages output methods.
2179  void MainForm::appendMessages( const QString& s )  void MainForm::appendMessages( const QString& s )
2180  {  {
2181      if (m_pMessages)          if (m_pMessages)
2182          m_pMessages->appendMessages(s);                  m_pMessages->appendMessages(s);
2183    
2184      statusBar()->message(s, 3000);          statusBar()->showMessage(s, 3000);
2185  }  }
2186    
2187  void MainForm::appendMessagesColor( const QString& s, const QString& c )  void MainForm::appendMessagesColor( const QString& s, const QString& c )
2188  {  {
2189      if (m_pMessages)          if (m_pMessages)
2190          m_pMessages->appendMessagesColor(s, c);                  m_pMessages->appendMessagesColor(s, c);
2191    
2192      statusBar()->message(s, 3000);          statusBar()->showMessage(s, 3000);
2193  }  }
2194    
2195  void MainForm::appendMessagesText( const QString& s )  void MainForm::appendMessagesText( const QString& s )
2196  {  {
2197      if (m_pMessages)          if (m_pMessages)
2198          m_pMessages->appendMessagesText(s);                  m_pMessages->appendMessagesText(s);
2199  }  }
2200    
2201  void MainForm::appendMessagesError( const QString& s )  void MainForm::appendMessagesError( const QString& s )
2202  {  {
2203      if (m_pMessages)          if (m_pMessages)
2204          m_pMessages->show();                  m_pMessages->show();
2205    
2206      appendMessagesColor(s.simplifyWhiteSpace(), "#ff0000");          appendMessagesColor(s.simplified(), "#ff0000");
2207    
2208          // Make it look responsive...:)          // Make it look responsive...:)
2209          QApplication::processEvents(QEventLoop::ExcludeUserInput);          QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2210    
2211      QMessageBox::critical(this,          QMessageBox::critical(this,
2212                  QSAMPLER_TITLE ": " + tr("Error"), s, tr("Cancel"));                  QSAMPLER_TITLE ": " + tr("Error"), s, tr("Cancel"));
2213  }  }
2214    
# Line 2001  void MainForm::appendMessagesError( cons Line 2216  void MainForm::appendMessagesError( cons
2216  // This is a special message format, just for client results.  // This is a special message format, just for client results.
2217  void MainForm::appendMessagesClient( const QString& s )  void MainForm::appendMessagesClient( const QString& s )
2218  {  {
2219      if (m_pClient == NULL)          if (m_pClient == NULL)
2220          return;                  return;
2221    
2222      appendMessagesColor(s + QString(": %1 (errno=%2)")          appendMessagesColor(s + QString(": %1 (errno=%2)")
2223          .arg(::lscp_client_get_result(m_pClient))                  .arg(::lscp_client_get_result(m_pClient))
2224          .arg(::lscp_client_get_errno(m_pClient)), "#996666");                  .arg(::lscp_client_get_errno(m_pClient)), "#996666");
2225    
2226          // Make it look responsive...:)          // Make it look responsive...:)
2227          QApplication::processEvents(QEventLoop::ExcludeUserInput);          QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2228  }  }
2229    
2230    
2231  // Force update of the messages font.  // Force update of the messages font.
2232  void MainForm::updateMessagesFont (void)  void MainForm::updateMessagesFont (void)
2233  {  {
2234      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2235          return;                  return;
2236    
2237      if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {          if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {
2238          QFont font;                  QFont font;
2239          if (font.fromString(m_pOptions->sMessagesFont))                  if (font.fromString(m_pOptions->sMessagesFont))
2240              m_pMessages->setMessagesFont(font);                          m_pMessages->setMessagesFont(font);
2241      }          }
2242  }  }
2243    
2244    
2245  // Update messages window line limit.  // Update messages window line limit.
2246  void MainForm::updateMessagesLimit (void)  void MainForm::updateMessagesLimit (void)
2247  {  {
2248      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2249          return;                  return;
2250    
2251      if (m_pMessages) {          if (m_pMessages) {
2252          if (m_pOptions->bMessagesLimit)                  if (m_pOptions->bMessagesLimit)
2253              m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);                          m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);
2254          else                  else
2255              m_pMessages->setMessagesLimit(-1);                          m_pMessages->setMessagesLimit(-1);
2256      }          }
2257  }  }
2258    
2259    
2260  // Enablement of the messages capture feature.  // Enablement of the messages capture feature.
2261  void MainForm::updateMessagesCapture (void)  void MainForm::updateMessagesCapture (void)
2262  {  {
2263      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2264          return;                  return;
2265    
2266      if (m_pMessages)          if (m_pMessages)
2267          m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);                  m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);
2268  }  }
2269    
2270    
# Line 2057  void MainForm::updateMessagesCapture (vo Line 2272  void MainForm::updateMessagesCapture (vo
2272  // qsamplerMainForm -- MDI channel strip management.  // qsamplerMainForm -- MDI channel strip management.
2273    
2274  // The channel strip creation executive.  // The channel strip creation executive.
2275  ChannelStrip* MainForm::createChannelStrip(qsamplerChannel* pChannel)  ChannelStrip* MainForm::createChannelStrip ( Channel *pChannel )
2276  {  {
2277      if (m_pClient == NULL || pChannel == NULL)          if (m_pClient == NULL || pChannel == NULL)
2278          return NULL;                  return NULL;
2279    
2280      // Prepare for auto-arrange?          // Add a new channel itema...
2281      ChannelStrip* pChannelStrip = NULL;          ChannelStrip *pChannelStrip = new ChannelStrip();
2282      int y = 0;          if (pChannelStrip == NULL)
2283      if (m_pOptions && m_pOptions->bAutoArrange) {                  return NULL;
2284          QWidgetList wlist = m_pWorkspace->windowList();  
2285          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          // Set some initial channel strip options...
2286              pChannelStrip = (ChannelStrip *) wlist.at(iChannel);          if (m_pOptions) {
2287                          if (pChannelStrip) {                  // Background display effect...
2288                          //  y += pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();                  pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
2289                                  y += pChannelStrip->parentWidget()->frameGeometry().height();                  // We'll need a display font.
2290                          }                  QFont font;
2291          }                  if (font.fromString(m_pOptions->sDisplayFont))
2292      }                          pChannelStrip->setDisplayFont(font);
2293                    // Maximum allowed volume setting.
2294                    pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
2295            }
2296    
2297            // Add it to workspace...
2298            m_pWorkspace->addWindow(pChannelStrip, Qt::FramelessWindowHint);
2299    
2300      // Add a new channel itema...          // Actual channel strip setup...
2301      Qt::WFlags wflags = Qt::WStyle_Customize | Qt::WStyle_Tool | Qt::WStyle_Title | Qt::WStyle_NoBorder;          pChannelStrip->setup(pChannel);
     pChannelStrip = new ChannelStrip(m_pWorkspace, wflags);  
     if (pChannelStrip == NULL)  
         return NULL;  
2302    
     // Actual channel strip setup...  
     pChannelStrip->setup(pChannel);  
2303          QObject::connect(pChannelStrip,          QObject::connect(pChannelStrip,
2304                  SIGNAL(channelChanged(qsamplerChannelStrip *)),                  SIGNAL(channelChanged(ChannelStrip*)),
2305                  SLOT(channelStripChanged(qsamplerChannelStrip *)));                  SLOT(channelStripChanged(ChannelStrip*)));
2306      // Set some initial aesthetic options...  
2307      if (m_pOptions) {          // Now we show up us to the world.
2308          // 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);  
     }  
2309    
2310          // This is pretty new, so we'll watch for it closely.          // This is pretty new, so we'll watch for it closely.
2311          channelStripChanged(pChannelStrip);          channelStripChanged(pChannelStrip);
2312    
2313      // Return our successful reference...          // Return our successful reference...
2314      return pChannelStrip;          return pChannelStrip;
2315  }  }
2316    
2317    void MainForm::destroyChannelStrip(ChannelStrip* pChannelStrip) {
2318            // Just delete the channel strip.
2319            delete pChannelStrip;
2320    
2321            // Do we auto-arrange?
2322            if (m_pOptions && m_pOptions->bAutoArrange)
2323                    channelsArrange();
2324    
2325            stabilizeForm();
2326    }
2327    
2328  // Retrieve the active channel strip.  // Retrieve the active channel strip.
2329  ChannelStrip* MainForm::activeChannelStrip (void)  ChannelStrip* MainForm::activeChannelStrip (void)
2330  {  {
2331      return (ChannelStrip*) m_pWorkspace->activeWindow();          return static_cast<ChannelStrip *> (m_pWorkspace->activeWindow());
2332  }  }
2333    
2334    
2335  // Retrieve a channel strip by index.  // Retrieve a channel strip by index.
2336  ChannelStrip* MainForm::channelStripAt ( int iChannel )  ChannelStrip* MainForm::channelStripAt ( int iChannel )
2337  {  {
2338      QWidgetList wlist = m_pWorkspace->windowList();          if (!m_pWorkspace) return NULL;
2339      if (wlist.isEmpty())  
2340          return NULL;          QWidgetList wlist = m_pWorkspace->windowList();
2341            if (wlist.isEmpty())
2342                    return NULL;
2343    
2344      return (ChannelStrip*) wlist.at(iChannel);          if (iChannel < 0 || iChannel >= wlist.size())
2345                    return NULL;
2346    
2347            return dynamic_cast<ChannelStrip *> (wlist.at(iChannel));
2348  }  }
2349    
2350    
# Line 2142  ChannelStrip* MainForm::channelStrip ( i Line 2356  ChannelStrip* MainForm::channelStrip ( i
2356                  return NULL;                  return NULL;
2357    
2358          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
2359                  ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);                  ChannelStrip* pChannelStrip
2360                            = static_cast<ChannelStrip*> (wlist.at(iChannel));
2361                  if (pChannelStrip) {                  if (pChannelStrip) {
2362                          qsamplerChannel *pChannel = pChannelStrip->channel();                          Channel *pChannel = pChannelStrip->channel();
2363                          if (pChannel && pChannel->channelID() == iChannelID)                          if (pChannel && pChannel->channelID() == iChannelID)
2364                                  return pChannelStrip;                                  return pChannelStrip;
2365                  }                  }
# Line 2158  ChannelStrip* MainForm::channelStrip ( i Line 2373  ChannelStrip* MainForm::channelStrip ( i
2373  // Construct the windows menu.  // Construct the windows menu.
2374  void MainForm::channelsMenuAboutToShow (void)  void MainForm::channelsMenuAboutToShow (void)
2375  {  {
2376      ui.channelsMenu->clear();          m_ui.channelsMenu->clear();
2377      ui.channelsArrangeAction->addTo(ui.channelsMenu);          m_ui.channelsMenu->addAction(m_ui.channelsArrangeAction);
2378      ui.channelsAutoArrangeAction->addTo(ui.channelsMenu);          m_ui.channelsMenu->addAction(m_ui.channelsAutoArrangeAction);
2379    
2380      QWidgetList wlist = m_pWorkspace->windowList();          QWidgetList wlist = m_pWorkspace->windowList();
2381      if (!wlist.isEmpty()) {          if (!wlist.isEmpty()) {
2382          ui.channelsMenu->insertSeparator();                  m_ui.channelsMenu->addSeparator();
2383          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {                  for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
2384              ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);                          ChannelStrip* pChannelStrip
2385              if (pChannelStrip) {                                  = static_cast<ChannelStrip*> (wlist.at(iChannel));
2386                  int iItemID = ui.channelsMenu->insertItem(pChannelStrip->caption(), this, SLOT(channelsMenuActivated(int)));                          if (pChannelStrip) {
2387                  ui.channelsMenu->setItemParameter(iItemID, iChannel);                                  QAction *pAction = m_ui.channelsMenu->addAction(
2388                  ui.channelsMenu->setItemChecked(iItemID, activeChannelStrip() == pChannelStrip);                                          pChannelStrip->windowTitle(),
2389              }                                          this, SLOT(channelsMenuActivated()));
2390          }                                  pAction->setCheckable(true);
2391      }                                  pAction->setChecked(activeChannelStrip() == pChannelStrip);
2392                                    pAction->setData(iChannel);
2393                            }
2394                    }
2395            }
2396  }  }
2397    
2398    
2399  // Windows menu activation slot  // Windows menu activation slot
2400  void MainForm::channelsMenuActivated ( int iChannel )  void MainForm::channelsMenuActivated (void)
2401  {  {
2402      ChannelStrip* pChannelStrip = channelStripAt(iChannel);          // Retrive channel index from action data...
2403      if (pChannelStrip)          QAction *pAction = qobject_cast<QAction *> (sender());
2404          pChannelStrip->showNormal();          if (pAction == NULL)
2405      pChannelStrip->setFocus();                  return;
2406    
2407            ChannelStrip* pChannelStrip = channelStripAt(pAction->data().toInt());
2408            if (pChannelStrip) {
2409                    pChannelStrip->showNormal();
2410                    pChannelStrip->setFocus();
2411            }
2412  }  }
2413    
2414    
# Line 2193  void MainForm::channelsMenuActivated ( i Line 2418  void MainForm::channelsMenuActivated ( i
2418  // Set the pseudo-timer delay schedule.  // Set the pseudo-timer delay schedule.
2419  void MainForm::startSchedule ( int iStartDelay )  void MainForm::startSchedule ( int iStartDelay )
2420  {  {
2421      m_iStartDelay  = 1 + (iStartDelay * 1000);          m_iStartDelay  = 1 + (iStartDelay * 1000);
2422      m_iTimerDelay  = 0;          m_iTimerDelay  = 0;
2423  }  }
2424    
2425  // Suspend the pseudo-timer delay schedule.  // Suspend the pseudo-timer delay schedule.
2426  void MainForm::stopSchedule (void)  void MainForm::stopSchedule (void)
2427  {  {
2428      m_iStartDelay  = 0;          m_iStartDelay  = 0;
2429      m_iTimerDelay  = 0;          m_iTimerDelay  = 0;
2430  }  }
2431    
2432  // Timer slot funtion.  // Timer slot funtion.
2433  void MainForm::timerSlot (void)  void MainForm::timerSlot (void)
2434  {  {
2435      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2436          return;                  return;
2437    
2438      // Is it the first shot on server start after a few delay?          // Is it the first shot on server start after a few delay?
2439      if (m_iTimerDelay < m_iStartDelay) {          if (m_iTimerDelay < m_iStartDelay) {
2440          m_iTimerDelay += QSAMPLER_TIMER_MSECS;                  m_iTimerDelay += QSAMPLER_TIMER_MSECS;
2441          if (m_iTimerDelay >= m_iStartDelay) {                  if (m_iTimerDelay >= m_iStartDelay) {
2442              // If we cannot start it now, maybe a lil'mo'later ;)                          // If we cannot start it now, maybe a lil'mo'later ;)
2443              if (!startClient()) {                          if (!startClient()) {
2444                  m_iStartDelay += m_iTimerDelay;                                  m_iStartDelay += m_iTimerDelay;
2445                  m_iTimerDelay  = 0;                                  m_iTimerDelay  = 0;
2446              }                          }
2447          }                  }
2448      }          }
2449    
2450          if (m_pClient) {          if (m_pClient) {
2451                  // Update the channel information for each pending strip...                  // Update the channel information for each pending strip...
2452                  if (m_changedStrips.count() > 0) {                  QListIterator<ChannelStrip *> iter(m_changedStrips);
2453                          for (ChannelStrip* pChannelStrip = m_changedStrips.first();                  while (iter.hasNext()) {
2454                                          pChannelStrip; pChannelStrip = m_changedStrips.next()) {                          ChannelStrip *pChannelStrip = iter.next();
2455                                  // If successfull, remove from pending list...                          // If successfull, remove from pending list...
2456                                  if (pChannelStrip->updateChannelInfo())                          if (pChannelStrip->updateChannelInfo()) {
2457                                          m_changedStrips.remove(pChannelStrip);                                  int iChannelStrip = m_changedStrips.indexOf(pChannelStrip);
2458                                    if (iChannelStrip >= 0)
2459                                            m_changedStrips.removeAt(iChannelStrip);
2460                          }                          }
2461                  }                  }
2462                  // Refresh each channel usage, on each period...                  // Refresh each channel usage, on each period...
# Line 2250  void MainForm::timerSlot (void) Line 2477  void MainForm::timerSlot (void)
2477                  }                  }
2478          }          }
2479    
2480      // Register the next timer slot.          // Register the next timer slot.
2481      QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));          QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
2482  }  }
2483    
2484    
# Line 2261  void MainForm::timerSlot (void) Line 2488  void MainForm::timerSlot (void)
2488  // Start linuxsampler server...  // Start linuxsampler server...
2489  void MainForm::startServer (void)  void MainForm::startServer (void)
2490  {  {
2491      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2492          return;                  return;
2493    
2494            // Aren't already a client, are we?
2495            if (!m_pOptions->bServerStart || m_pClient)
2496                    return;
2497    
2498      // Aren't already a client, are we?          // Is the server process instance still here?
2499      if (!m_pOptions->bServerStart || m_pClient)          if (m_pServer) {
2500          return;                  switch (QMessageBox::warning(this,
   
     // Is the server process instance still here?  
     if (m_pServer) {  
         switch (QMessageBox::warning(this,  
2501                          QSAMPLER_TITLE ": " + tr("Warning"),                          QSAMPLER_TITLE ": " + tr("Warning"),
2502              tr("Could not start the LinuxSampler server.\n\n"                          tr("Could not start the LinuxSampler server.\n\n"
2503                 "Maybe it ss already started."),                          "Maybe it is already started."),
2504              tr("Stop"), tr("Kill"), tr("Cancel"))) {                          tr("Stop"), tr("Kill"), tr("Cancel"))) {
2505            case 0:                  case 0:
2506              m_pServer->terminate();                          m_pServer->terminate();
2507              break;                          break;
2508            case 1:                  case 1:
2509              m_pServer->kill();                          m_pServer->kill();
2510              break;                          break;
2511          }                  }
2512          return;                  return;
2513      }          }
2514    
2515      // Reset our timer counters...          // Reset our timer counters...
2516      stopSchedule();          stopSchedule();
2517    
2518      // OK. Let's build the startup process...          // Verify we have something to start with...
2519      m_pServer = new QProcess(this);          if (m_pOptions->sServerCmdLine.isEmpty())
2520                    return;
2521      // Setup stdout/stderr capture...  
2522          //      if (m_pOptions->bStdoutCapture) {          // OK. Let's build the startup process...
2523                  //m_pServer->setProcessChannelMode(          m_pServer = new QProcess();
2524                  //      QProcess::StandardOutput);          bForceServerStop = true;
2525    
2526            // Setup stdout/stderr capture...
2527    //      if (m_pOptions->bStdoutCapture) {
2528    #if QT_VERSION >= 0x040200
2529                    m_pServer->setProcessChannelMode(QProcess::ForwardedChannels);
2530    #endif
2531                  QObject::connect(m_pServer,                  QObject::connect(m_pServer,
2532                          SIGNAL(readyReadStdout()),                          SIGNAL(readyReadStandardOutput()),
2533                          SLOT(readServerStdout()));                          SLOT(readServerStdout()));
2534                  QObject::connect(m_pServer,                  QObject::connect(m_pServer,
2535                          SIGNAL(readyReadStderr()),                          SIGNAL(readyReadStandardError()),
2536                          SLOT(readServerStdout()));                          SLOT(readServerStdout()));
2537          //      }  //      }
2538    
2539          // The unforgiveable signal communication...          // The unforgiveable signal communication...
2540          QObject::connect(m_pServer,          QObject::connect(m_pServer,
2541                  SIGNAL(processExited()),                  SIGNAL(finished(int, QProcess::ExitStatus)),
2542                  SLOT(processServerExit()));                  SLOT(processServerExit()));
2543    
2544      // Build process arguments...          // Build process arguments...
2545      QStringList serverCmdLine = QStringList::split(' ', m_pOptions->sServerCmdLine);          QStringList args = m_pOptions->sServerCmdLine.split(' ');
2546            QString sCommand = args[0];
2547      appendMessages(tr("Server is starting..."));          args.removeAt(0);
2548      appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");  
2549            appendMessages(tr("Server is starting..."));
2550            appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");
2551    
2552      const QString prog = (serverCmdLine.size() > 0) ? serverCmdLine[0] : QString();          // Go linuxsampler, go...
2553      const QStringList args = serverCmdLine.mid(1);          m_pServer->start(sCommand, args);
2554            if (!m_pServer->waitForStarted()) {
2555      // Go jack, go...                  appendMessagesError(tr("Could not start server.\n\nSorry."));
2556      m_pServer->start(prog, args);                  processServerExit();
2557      if (!m_pServer->waitForStarted()) {                  return;
2558          appendMessagesError(tr("Could not start server.\n\nSorry."));          }
         processServerExit();  
         return;  
     }  
   
     // Show startup results...  
     appendMessages(tr("Server was started with PID=%1.").arg((long) m_pServer->pid()));  
2559    
2560      // Reset (yet again) the timer counters,          // Show startup results...
2561      // but this time is deferred as the user opted.          appendMessages(
2562      startSchedule(m_pOptions->iStartDelay);                  tr("Server was started with PID=%1.").arg((long) m_pServer->pid()));
2563      stabilizeForm();  
2564            // Reset (yet again) the timer counters,
2565            // but this time is deferred as the user opted.
2566            startSchedule(m_pOptions->iStartDelay);
2567            stabilizeForm();
2568  }  }
2569    
2570    
2571  // Stop linuxsampler server...  // Stop linuxsampler server...
2572  void MainForm::stopServer (void)  void MainForm::stopServer (bool bInteractive)
2573  {  {
2574      // Stop client code.          // Stop client code.
2575      stopClient();          stopClient();
2576    
2577      // And try to stop server.          if (m_pServer && bInteractive) {
2578      if (m_pServer) {                  if (QMessageBox::question(this,
2579          appendMessages(tr("Server is stopping..."));                          QSAMPLER_TITLE ": " + tr("The backend's fate ..."),
2580          if (m_pServer->state() == QProcess::Running)                          tr("You have the option to keep the sampler backend (LinuxSampler)\n"
2581              m_pServer->terminate();                          "running in the background. The sampler would continue to work\n"
2582       }                          "according to your current sampler session and you could alter the\n"
2583                            "sampler session at any time by relaunching QSampler.\n\n"
2584      // Give it some time to terminate gracefully and stabilize...                          "Do you want LinuxSampler to stop or to keep running in\n"
2585      QTime t;                          "the background?"),
2586      t.start();                          tr("Stop"), tr("Keep Running")) == 1)
2587      while (t.elapsed() < QSAMPLER_TIMER_MSECS)                  {
2588          QApplication::processEvents(QEventLoop::ExcludeUserInput);                          bForceServerStop = false;
2589                    }
2590            }
2591    
2592       // Do final processing anyway.          // And try to stop server.
2593       processServerExit();          if (m_pServer && bForceServerStop) {
2594                    appendMessages(tr("Server is stopping..."));
2595                    if (m_pServer->state() == QProcess::Running) {
2596    #if defined(WIN32)
2597                            // Try harder...
2598                            m_pServer->kill();
2599    #else
2600                            // Try softly...
2601                            m_pServer->terminate();
2602    #endif
2603                    }
2604            }       // Do final processing anyway.
2605            else processServerExit();
2606    
2607            // Give it some time to terminate gracefully and stabilize...
2608            QTime t;
2609            t.start();
2610            while (t.elapsed() < QSAMPLER_TIMER_MSECS)
2611                    QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2612  }  }
2613    
2614    
2615  // Stdout handler...  // Stdout handler...
2616  void MainForm::readServerStdout (void)  void MainForm::readServerStdout (void)
2617  {  {
2618      if (m_pMessages)          if (m_pMessages)
2619          m_pMessages->appendStdoutBuffer(m_pServer->readAllStandardOutput());                  m_pMessages->appendStdoutBuffer(m_pServer->readAllStandardOutput());
2620  }  }
2621    
2622    
2623  // Linuxsampler server cleanup.  // Linuxsampler server cleanup.
2624  void MainForm::processServerExit (void)  void MainForm::processServerExit (void)
2625  {  {
2626      // Force client code cleanup.          // Force client code cleanup.
2627      stopClient();          stopClient();
2628    
2629      // Flush anything that maybe pending...          // Flush anything that maybe pending...
2630      if (m_pMessages)          if (m_pMessages)
2631          m_pMessages->flushStdoutBuffer();                  m_pMessages->flushStdoutBuffer();
2632    
2633      if (m_pServer) {          if (m_pServer && bForceServerStop) {
2634          // Force final server shutdown...                  if (m_pServer->state() != QProcess::NotRunning) {
2635          appendMessages(tr("Server was stopped with exit status %1.").arg(m_pServer->exitStatus()));                          appendMessages(tr("Server is being forced..."));
2636          m_pServer->terminate();                          // Force final server shutdown...
2637          if (!m_pServer->waitForFinished(2000))                          m_pServer->kill();
2638              m_pServer->kill();                          // Give it some time to terminate gracefully and stabilize...
2639          // Destroy it.                          QTime t;
2640          delete m_pServer;                          t.start();
2641          m_pServer = NULL;                          while (t.elapsed() < QSAMPLER_TIMER_MSECS)
2642      }                                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2643                    }
2644                    // Force final server shutdown...
2645                    appendMessages(
2646                            tr("Server was stopped with exit status %1.")
2647                            .arg(m_pServer->exitStatus()));
2648                    delete m_pServer;
2649                    m_pServer = NULL;
2650            }
2651    
2652      // Again, make status visible stable.          // Again, make status visible stable.
2653      stabilizeForm();          stabilizeForm();
2654  }  }
2655    
2656    
# Line 2398  void MainForm::processServerExit (void) Line 2658  void MainForm::processServerExit (void)
2658  // qsamplerMainForm -- Client stuff.  // qsamplerMainForm -- Client stuff.
2659    
2660  // The LSCP client callback procedure.  // The LSCP client callback procedure.
2661  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*/,
2662            lscp_event_t event, const char *pchData, int cchData, void *pvData )
2663  {  {
2664      MainForm* pMainForm = (MainForm *) pvData;          MainForm* pMainForm = (MainForm *) pvData;
2665      if (pMainForm == NULL)          if (pMainForm == NULL)
2666          return LSCP_FAILED;                  return LSCP_FAILED;
2667    
2668      // ATTN: DO NOT EVER call any GUI code here,          // ATTN: DO NOT EVER call any GUI code here,
2669      // as this is run under some other thread context.          // as this is run under some other thread context.
2670      // A custom event must be posted here...          // A custom event must be posted here...
2671      QApplication::postEvent(pMainForm, new qsamplerCustomEvent(event, pchData, cchData));          QApplication::postEvent(pMainForm,
2672                    new CustomEvent(event, pchData, cchData));
2673    
2674      return LSCP_OK;          return LSCP_OK;
2675  }  }
2676    
2677    
2678  // Start our almighty client...  // Start our almighty client...
2679  bool MainForm::startClient (void)  bool MainForm::startClient (void)
2680  {  {
2681      // Have it a setup?          // Have it a setup?
2682      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2683          return false;                  return false;
2684    
2685      // Aren't we already started, are we?          // Aren't we already started, are we?
2686      if (m_pClient)          if (m_pClient)
2687          return true;                  return true;
2688    
2689      // Log prepare here.          // Log prepare here.
2690      appendMessages(tr("Client connecting..."));          appendMessages(tr("Client connecting..."));
2691    
2692      // Create the client handle...          // Create the client handle...
2693      m_pClient = ::lscp_client_create(m_pOptions->sServerHost.latin1(), m_pOptions->iServerPort, qsampler_client_callback, this);          m_pClient = ::lscp_client_create(
2694      if (m_pClient == NULL) {                  m_pOptions->sServerHost.toUtf8().constData(),
2695          // Is this the first try?                  m_pOptions->iServerPort, qsampler_client_callback, this);
2696          // maybe we need to start a local server...          if (m_pClient == NULL) {
2697          if ((m_pServer && m_pServer->state() == QProcess::Running) || !m_pOptions->bServerStart)                  // Is this the first try?
2698              appendMessagesError(tr("Could not connect to server as client.\n\nSorry."));                  // maybe we need to start a local server...
2699          else                  if ((m_pServer && m_pServer->state() == QProcess::Running)
2700              startServer();                          || !m_pOptions->bServerStart) {
2701          // This is always a failure.                          appendMessagesError(
2702          stabilizeForm();                                  tr("Could not connect to server as client.\n\nSorry."));
2703          return false;                  } else {
2704      }                          startServer();
2705      // Just set receive timeout value, blindly.                  }
2706      ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);                  // This is always a failure.
2707      appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));                  stabilizeForm();
2708                    return false;
2709            }
2710            // Just set receive timeout value, blindly.
2711            ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);
2712            appendMessages(
2713                    tr("Client receive timeout is set to %1 msec.")
2714                    .arg(::lscp_client_get_timeout(m_pClient)));
2715    
2716          // Subscribe to channel info change notifications...          // Subscribe to channel info change notifications...
2717            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_COUNT) != LSCP_OK)
2718                    appendMessagesClient("lscp_client_subscribe(CHANNEL_COUNT)");
2719          if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO) != LSCP_OK)          if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO) != LSCP_OK)
2720                  appendMessagesClient("lscp_client_subscribe");                  appendMessagesClient("lscp_client_subscribe(CHANNEL_INFO)");
2721    
2722      // We may stop scheduling around.          DeviceStatusForm::onDevicesChanged(); // initialize
2723      stopSchedule();          updateViewMidiDeviceStatusMenu();
2724            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT) != LSCP_OK)
2725                    appendMessagesClient("lscp_client_subscribe(MIDI_INPUT_DEVICE_COUNT)");
2726            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_INFO) != LSCP_OK)
2727                    appendMessagesClient("lscp_client_subscribe(MIDI_INPUT_DEVICE_INFO)");
2728            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT) != LSCP_OK)
2729                    appendMessagesClient("lscp_client_subscribe(AUDIO_OUTPUT_DEVICE_COUNT)");
2730            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO) != LSCP_OK)
2731                    appendMessagesClient("lscp_client_subscribe(AUDIO_OUTPUT_DEVICE_INFO)");
2732    
2733    #if CONFIG_EVENT_CHANNEL_MIDI
2734            // Subscribe to channel MIDI data notifications...
2735            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_MIDI) != LSCP_OK)
2736                    appendMessagesClient("lscp_client_subscribe(CHANNEL_MIDI)");
2737    #endif
2738    
2739    #if CONFIG_EVENT_DEVICE_MIDI
2740            // Subscribe to channel MIDI data notifications...
2741            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_DEVICE_MIDI) != LSCP_OK)
2742                    appendMessagesClient("lscp_client_subscribe(DEVICE_MIDI)");
2743    #endif
2744    
2745            // We may stop scheduling around.
2746            stopSchedule();
2747    
2748      // We'll accept drops from now on...          // We'll accept drops from now on...
2749      setAcceptDrops(true);          setAcceptDrops(true);
2750    
2751      // Log success here.          // Log success here.
2752      appendMessages(tr("Client connected."));          appendMessages(tr("Client connected."));
2753    
2754          // Hard-notify instrumnet and device configuration forms,          // Hard-notify instrumnet and device configuration forms,
2755          // if visible, that we're ready...          // if visible, that we're ready...
2756          if (m_pInstrumentListForm)          if (m_pInstrumentListForm)
2757              m_pInstrumentListForm->refreshInstruments();                  m_pInstrumentListForm->refreshInstruments();
2758          if (m_pDeviceForm)          if (m_pDeviceForm)
2759              m_pDeviceForm->refreshDevices();                  m_pDeviceForm->refreshDevices();
2760    
2761      // Is any session pending to be loaded?          // Is any session pending to be loaded?
2762      if (!m_pOptions->sSessionFile.isEmpty()) {          if (!m_pOptions->sSessionFile.isEmpty()) {
2763          // Just load the prabably startup session...                  // Just load the prabably startup session...
2764          if (loadSessionFile(m_pOptions->sSessionFile)) {                  if (loadSessionFile(m_pOptions->sSessionFile)) {
2765              m_pOptions->sSessionFile = QString::null;                          m_pOptions->sSessionFile = QString::null;
2766              return true;                          return true;
2767          }                  }
2768      }          }
2769    
2770      // Make a new session          // Make a new session
2771      return newSession();          return newSession();
2772  }  }
2773    
2774    
2775  // Stop client...  // Stop client...
2776  void MainForm::stopClient (void)  void MainForm::stopClient (void)
2777  {  {
2778      if (m_pClient == NULL)          if (m_pClient == NULL)
2779          return;                  return;
   
     // Log prepare here.  
     appendMessages(tr("Client disconnecting..."));  
2780    
2781      // Clear timer counters...          // Log prepare here.
2782      stopSchedule();          appendMessages(tr("Client disconnecting..."));
2783    
2784      // We'll reject drops from now on...          // Clear timer counters...
2785      setAcceptDrops(false);          stopSchedule();
2786    
2787      // Force any channel strips around, but          // We'll reject drops from now on...
2788      // but avoid removing the corresponding          setAcceptDrops(false);
     // channels from the back-end server.  
     m_iDirtyCount = 0;  
     closeSession(false);  
2789    
2790      // Close us as a client...          // Force any channel strips around, but
2791            // but avoid removing the corresponding
2792            // channels from the back-end server.
2793            m_iDirtyCount = 0;
2794            closeSession(false);
2795    
2796            // Close us as a client...
2797    #if CONFIG_EVENT_DEVICE_MIDI
2798            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_DEVICE_MIDI);
2799    #endif
2800    #if CONFIG_EVENT_CHANNEL_MIDI
2801            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_MIDI);
2802    #endif
2803            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO);
2804            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT);
2805            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_INFO);
2806            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT);
2807          ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO);          ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO);
2808      ::lscp_client_destroy(m_pClient);          ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_COUNT);
2809      m_pClient = NULL;          ::lscp_client_destroy(m_pClient);
2810            m_pClient = NULL;
2811    
2812          // Hard-notify instrumnet and device configuration forms,          // Hard-notify instrumnet and device configuration forms,
2813          // if visible, that we're running out...          // if visible, that we're running out...
2814          if (m_pInstrumentListForm)          if (m_pInstrumentListForm)
2815              m_pInstrumentListForm->refreshInstruments();                  m_pInstrumentListForm->refreshInstruments();
2816          if (m_pDeviceForm)          if (m_pDeviceForm)
2817              m_pDeviceForm->refreshDevices();                  m_pDeviceForm->refreshDevices();
2818    
2819      // Log final here.          // Log final here.
2820      appendMessages(tr("Client disconnected."));          appendMessages(tr("Client disconnected."));
2821    
2822      // Make visible status.          // Make visible status.
2823      stabilizeForm();          stabilizeForm();
2824  }  }
2825    
2826    
2827    // Channel strip activation/selection.
2828    void MainForm::activateStrip ( QWidget *pWidget )
2829    {
2830            ChannelStrip *pChannelStrip
2831                    = static_cast<ChannelStrip *> (pWidget);
2832            if (pChannelStrip)
2833                    pChannelStrip->setSelected(true);
2834    
2835            stabilizeForm();
2836    }
2837    
2838    
2839  } // namespace QSampler  } // namespace QSampler
2840    
2841    
2842    // end of qsamplerMainForm.cpp

Legend:
Removed from v.1461  
changed lines
  Added in v.1738

  ViewVC Help
Powered by ViewVC