/[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 1466 by capela, Thu Nov 1 19:25:10 2007 UTC revision 1699 by schoenebeck, Sun Feb 17 10:46:17 2008 UTC
# Line 2  Line 2 
2  //  //
3  /****************************************************************************  /****************************************************************************
4     Copyright (C) 2004-2007, rncbc aka Rui Nuno Capela. All rights reserved.     Copyright (C) 2004-2007, rncbc aka Rui Nuno Capela. All rights reserved.
5     Copyright (C) 2007, Christian Schoenebeck     Copyright (C) 2007, 2008 Christian Schoenebeck
6    
7     This program is free software; you can redistribute it and/or     This program is free software; you can redistribute it and/or
8     modify it under the terms of the GNU General Public License     modify it under the terms of the GNU General Public License
# Line 20  Line 20 
20    
21  *****************************************************************************/  *****************************************************************************/
22    
23    #include "qsamplerAbout.h"
24  #include "qsamplerMainForm.h"  #include "qsamplerMainForm.h"
25    
 #include <qapplication.h>  
 #include <qeventloop.h>  
 #include <qworkspace.h>  
 #include <qprocess.h>  
 #include <qmessagebox.h>  
 //#include <qdragobject.h>  
 #include <qregexp.h>  
 #include <qfiledialog.h>  
 #include <qfileinfo.h>  
 #include <qfile.h>  
 #include <qtextstream.h>  
 #include <qstatusbar.h>  
 #include <qslider.h>  
 #include <qspinbox.h>  
 #include <qlabel.h>  
 #include <qtimer.h>  
 #include <qtooltip.h>  
   
 #include "qsamplerAbout.h"  
26  #include "qsamplerOptions.h"  #include "qsamplerOptions.h"
27  #include "qsamplerChannel.h"  #include "qsamplerChannel.h"
28  #include "qsamplerMessages.h"  #include "qsamplerMessages.h"
# Line 51  Line 33 
33  #include "qsamplerInstrumentListForm.h"  #include "qsamplerInstrumentListForm.h"
34  #include "qsamplerDeviceForm.h"  #include "qsamplerDeviceForm.h"
35  #include "qsamplerOptionsForm.h"  #include "qsamplerOptionsForm.h"
36    #include "qsamplerDeviceStatusForm.h"
37    
38    #include <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 73  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 83  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            m_ui.setupUi(this);
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 159  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          ui.channelsToolbar->addSeparator();          m_ui.channelsToolbar->addSeparator();
175          m_pVolumeSlider = new QSlider(Qt::Horizontal, ui.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->setMinimum(0);
181            m_pVolumeSlider->setMaximum(100);
182          m_pVolumeSlider->setMaximumHeight(26);          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          //ui.channelsToolbar->setHorizontallyStretchable(true);          //m_ui.channelsToolbar->setHorizontallyStretchable(true);
189          //ui.channelsToolbar->setStretchableWidget(m_pVolumeSlider);          //m_ui.channelsToolbar->setStretchableWidget(m_pVolumeSlider);
190      ui.channelsToolbar->addWidget(m_pVolumeSlider);          m_ui.channelsToolbar->addWidget(m_pVolumeSlider);
191          // Volume spin-box          // Volume spin-box
192          ui.channelsToolbar->addSeparator();          m_ui.channelsToolbar->addSeparator();
193          m_pVolumeSpinBox = new QSpinBox(ui.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      ui.channelsToolbar->addWidget(m_pVolumeSpinBox);          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          QObject::connect(ui.fileNewAction,          // Some actions surely need those
245                  SIGNAL(activated()),          // 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()));                  SLOT(fileNew()));
252          QObject::connect(ui.fileOpenAction,          QObject::connect(m_ui.fileOpenAction,
253                  SIGNAL(activated()),                  SIGNAL(triggered()),
254                  SLOT(fileOpen()));                  SLOT(fileOpen()));
255          QObject::connect(ui.fileSaveAction,          QObject::connect(m_ui.fileSaveAction,
256                  SIGNAL(activated()),                  SIGNAL(triggered()),
257                  SLOT(fileSave()));                  SLOT(fileSave()));
258          QObject::connect(ui.fileSaveAsAction,          QObject::connect(m_ui.fileSaveAsAction,
259                  SIGNAL(activated()),                  SIGNAL(triggered()),
260                  SLOT(fileSaveAs()));                  SLOT(fileSaveAs()));
261          QObject::connect(ui.fileResetAction,          QObject::connect(m_ui.fileResetAction,
262                  SIGNAL(activated()),                  SIGNAL(triggered()),
263                  SLOT(fileReset()));                  SLOT(fileReset()));
264          QObject::connect(ui.fileRestartAction,          QObject::connect(m_ui.fileRestartAction,
265                  SIGNAL(activated()),                  SIGNAL(triggered()),
266                  SLOT(fileRestart()));                  SLOT(fileRestart()));
267          QObject::connect(ui.fileExitAction,          QObject::connect(m_ui.fileExitAction,
268                  SIGNAL(activated()),                  SIGNAL(triggered()),
269                  SLOT(fileExit()));                  SLOT(fileExit()));
270          QObject::connect(ui.editAddChannelAction,          QObject::connect(m_ui.editAddChannelAction,
271                  SIGNAL(activated()),                  SIGNAL(triggered()),
272                  SLOT(editAddChannel()));                  SLOT(editAddChannel()));
273          QObject::connect(ui.editRemoveChannelAction,          QObject::connect(m_ui.editRemoveChannelAction,
274                  SIGNAL(activated()),                  SIGNAL(triggered()),
275                  SLOT(editRemoveChannel()));                  SLOT(editRemoveChannel()));
276          QObject::connect(ui.editSetupChannelAction,          QObject::connect(m_ui.editSetupChannelAction,
277                  SIGNAL(activated()),                  SIGNAL(triggered()),
278                  SLOT(editSetupChannel()));                  SLOT(editSetupChannel()));
279          QObject::connect(ui.editEditChannelAction,          QObject::connect(m_ui.editEditChannelAction,
280                  SIGNAL(activated()),                  SIGNAL(triggered()),
281                  SLOT(editEditChannel()));                  SLOT(editEditChannel()));
282          QObject::connect(ui.editResetChannelAction,          QObject::connect(m_ui.editResetChannelAction,
283                  SIGNAL(activated()),                  SIGNAL(triggered()),
284                  SLOT(editResetChannel()));                  SLOT(editResetChannel()));
285          QObject::connect(ui.editResetAllChannelsAction,          QObject::connect(m_ui.editResetAllChannelsAction,
286                  SIGNAL(activated()),                  SIGNAL(triggered()),
287                  SLOT(editResetAllChannels()));                  SLOT(editResetAllChannels()));
288          QObject::connect(ui.viewMenubarAction,          QObject::connect(m_ui.viewMenubarAction,
289                  SIGNAL(toggled(bool)),                  SIGNAL(toggled(bool)),
290                  SLOT(viewMenubar(bool)));                  SLOT(viewMenubar(bool)));
291          QObject::connect(ui.viewToolbarAction,          QObject::connect(m_ui.viewToolbarAction,
292                  SIGNAL(toggled(bool)),                  SIGNAL(toggled(bool)),
293                  SLOT(viewToolbar(bool)));                  SLOT(viewToolbar(bool)));
294          QObject::connect(ui.viewStatusbarAction,          QObject::connect(m_ui.viewStatusbarAction,
295                  SIGNAL(toggled(bool)),                  SIGNAL(toggled(bool)),
296                  SLOT(viewStatusbar(bool)));                  SLOT(viewStatusbar(bool)));
297          QObject::connect(ui.viewMessagesAction,          QObject::connect(m_ui.viewMessagesAction,
298                  SIGNAL(toggled(bool)),                  SIGNAL(toggled(bool)),
299                  SLOT(viewMessages(bool)));                  SLOT(viewMessages(bool)));
300          QObject::connect(ui.viewInstrumentsAction,          QObject::connect(m_ui.viewInstrumentsAction,
301                  SIGNAL(activated()),                  SIGNAL(triggered()),
302                  SLOT(viewInstruments()));                  SLOT(viewInstruments()));
303          QObject::connect(ui.viewDevicesAction,          QObject::connect(m_ui.viewDevicesAction,
304                  SIGNAL(activated()),                  SIGNAL(triggered()),
305                  SLOT(viewDevices()));                  SLOT(viewDevices()));
306          QObject::connect(ui.viewOptionsAction,          QObject::connect(m_ui.viewOptionsAction,
307                  SIGNAL(activated()),                  SIGNAL(triggered()),
308                  SLOT(viewOptions()));                  SLOT(viewOptions()));
309          QObject::connect(ui.channelsArrangeAction,          QObject::connect(m_ui.channelsArrangeAction,
310                  SIGNAL(activated()),                  SIGNAL(triggered()),
311                  SLOT(channelsArrange()));                  SLOT(channelsArrange()));
312          QObject::connect(ui.channelsAutoArrangeAction,          QObject::connect(m_ui.channelsAutoArrangeAction,
313                  SIGNAL(toggled(bool)),                  SIGNAL(toggled(bool)),
314                  SLOT(channelsAutoArrange(bool)));                  SLOT(channelsAutoArrange(bool)));
315          QObject::connect(ui.helpAboutAction,          QObject::connect(m_ui.helpAboutAction,
316                  SIGNAL(activated()),                  SIGNAL(triggered()),
317                  SLOT(helpAbout()));                  SLOT(helpAbout()));
318          QObject::connect(ui.helpAboutQtAction,          QObject::connect(m_ui.helpAboutQtAction,
319                  SIGNAL(activated()),                  SIGNAL(triggered()),
320                  SLOT(helpAboutQt()));                  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...          // Set message defaults...
395      updateMessagesFont();          updateMessagesFont();
396      updateMessagesLimit();          updateMessagesLimit();
397      updateMessagesCapture();          updateMessagesCapture();
398      // Set the visibility signal.          // Set the visibility signal.
399          QObject::connect(m_pMessages,          QObject::connect(m_pMessages,
400                  SIGNAL(visibilityChanged(bool)),                  SIGNAL(visibilityChanged(bool)),
401                  SLOT(stabilizeForm()));                  SLOT(stabilizeForm()));
402    
403      // Initial decorations toggle state.          // Initial decorations toggle state.
404      ui.viewMenubarAction->setOn(m_pOptions->bMenubar);          m_ui.viewMenubarAction->setChecked(m_pOptions->bMenubar);
405      ui.viewToolbarAction->setOn(m_pOptions->bToolbar);          m_ui.viewToolbarAction->setChecked(m_pOptions->bToolbar);
406      ui.viewStatusbarAction->setOn(m_pOptions->bStatusbar);          m_ui.viewStatusbarAction->setChecked(m_pOptions->bStatusbar);
407      ui.channelsAutoArrangeAction->setOn(m_pOptions->bAutoArrange);          m_ui.channelsAutoArrangeAction->setChecked(m_pOptions->bAutoArrange);
408    
409      // Initial decorations visibility state.          // Initial decorations visibility state.
410      viewMenubar(m_pOptions->bMenubar);          viewMenubar(m_pOptions->bMenubar);
411      viewToolbar(m_pOptions->bToolbar);          viewToolbar(m_pOptions->bToolbar);
412      viewStatusbar(m_pOptions->bStatusbar);          viewStatusbar(m_pOptions->bStatusbar);
413    
414      addDockWidget(Qt::BottomDockWidgetArea, m_pMessages);          addDockWidget(Qt::BottomDockWidgetArea, m_pMessages);
415    
416      // Restore whole toolbar & dock windows states.          // Restore whole dock windows state.
417      QString sDockables = m_pOptions->settings().readEntry("/Layout/DockWindowsBase64" , QString::null);          QByteArray aDockables = m_pOptions->settings().value(
418      if (!sDockables.isEmpty()) {                  "/Layout/DockWindows").toByteArray();
419          restoreState(QByteArray::fromBase64(sDockables.toAscii()));          if (!aDockables.isEmpty()) {
420      }                  restoreState(aDockables);
421      // Try to restore old window positioning and initial visibility.          }
     m_pOptions->loadWidgetGeometry(this);  
     m_pOptions->loadWidgetGeometry(m_pInstrumentListForm);  
     m_pOptions->loadWidgetGeometry(m_pDeviceForm);  
   
     // Final startup stabilization...  
     updateMaxVolume();  
     updateRecentFilesMenu();  
     stabilizeForm();  
422    
423      // Make it ready :-)          // Try to restore old window positioning and initial visibility.
424      statusBar()->message(tr("Ready"), 3000);          m_pOptions->loadWidgetGeometry(this);
425            m_pOptions->loadWidgetGeometry(m_pInstrumentListForm);
426            m_pOptions->loadWidgetGeometry(m_pDeviceForm);
427    
428            // Final startup stabilization...
429            updateMaxVolume();
430            updateRecentFilesMenu();
431            stabilizeForm();
432    
433            // Make it ready :-)
434            statusBar()->showMessage(tr("Ready"), 3000);
435    
436      // We'll try to start immediately...          // We'll try to start immediately...
437      startSchedule(0);          startSchedule(0);
438    
439      // Register the first timer slot.          // Register the first timer slot.
440      QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));          QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
441  }  }
442    
443    
444  // Window close event handlers.  // Window close event handlers.
445  bool MainForm::queryClose (void)  bool MainForm::queryClose (void)
446  {  {
447      bool bQueryClose = closeSession(false);          bool bQueryClose = closeSession(false);
448    
449      // Try to save current general state...          // Try to save current general state...
450      if (m_pOptions) {          if (m_pOptions) {
451          // Some windows default fonts is here on demand too.                  // Some windows default fonts is here on demand too.
452          if (bQueryClose && m_pMessages)                  if (bQueryClose && m_pMessages)
453              m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();                          m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();
454          // Try to save current positioning.                  // Try to save current positioning.
455          if (bQueryClose) {                  if (bQueryClose) {
456              // Save decorations state.                          // Save decorations state.
457              m_pOptions->bMenubar = ui.MenuBar->isVisible();                          m_pOptions->bMenubar = m_ui.MenuBar->isVisible();
458              m_pOptions->bToolbar = (ui.fileToolbar->isVisible() || ui.editToolbar->isVisible() || ui.channelsToolbar->isVisible());                          m_pOptions->bToolbar = (m_ui.fileToolbar->isVisible()
459              m_pOptions->bStatusbar = statusBar()->isVisible();                                  || m_ui.editToolbar->isVisible()
460              // Save the dock windows state.                                  || m_ui.channelsToolbar->isVisible());
461              const QString sDockables = saveState().toBase64().data();                          m_pOptions->bStatusbar = statusBar()->isVisible();
462              m_pOptions->settings().writeEntry("/Layout/DockWindowsBase64", sDockables);                          // Save the dock windows state.
463              // And the children, and the main windows state,.                          const QString sDockables = saveState().toBase64().data();
464                            m_pOptions->settings().setValue("/Layout/DockWindows", saveState());
465                            // And the children, and the main windows state,.
466                          m_pOptions->saveWidgetGeometry(m_pDeviceForm);                          m_pOptions->saveWidgetGeometry(m_pDeviceForm);
467                          m_pOptions->saveWidgetGeometry(m_pInstrumentListForm);                          m_pOptions->saveWidgetGeometry(m_pInstrumentListForm);
468                          m_pOptions->saveWidgetGeometry(this);                          m_pOptions->saveWidgetGeometry(this);
# Line 454  bool MainForm::queryClose (void) Line 471  bool MainForm::queryClose (void)
471                                  m_pInstrumentListForm->close();                                  m_pInstrumentListForm->close();
472                          if (m_pDeviceForm)                          if (m_pDeviceForm)
473                                  m_pDeviceForm->close();                                  m_pDeviceForm->close();
474              // Stop client and/or server, gracefully.                          // Stop client and/or server, gracefully.
475              stopServer();                          stopServer(true /*interactive*/);
476          }                  }
477      }          }
478    
479      return bQueryClose;          return bQueryClose;
480  }  }
481    
482    
483  void MainForm::closeEvent ( QCloseEvent *pCloseEvent )  void MainForm::closeEvent ( QCloseEvent *pCloseEvent )
484  {  {
485      if (queryClose())          if (queryClose()) {
486          pCloseEvent->accept();                  DeviceStatusForm::deleteAllInstances();
487      else                  pCloseEvent->accept();
488          pCloseEvent->ignore();          } else
489  }                  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;  
490  }  }
491    
492    
493  // Window drag-n-drop event handlers.  // Window drag-n-drop event handlers.
494  void MainForm::dragEnterEvent ( QDragEnterEvent* pDragEnterEvent )  void MainForm::dragEnterEvent ( QDragEnterEvent* pDragEnterEvent )
495  {  {
496          QStringList files;          // Accept external drags only...
497          pDragEnterEvent->accept(decodeDragFiles(pDragEnterEvent, files));          if (pDragEnterEvent->source() == NULL
498                    && pDragEnterEvent->mimeData()->hasUrls()) {
499                    pDragEnterEvent->accept();
500            } else {
501                    pDragEnterEvent->ignore();
502            }
503  }  }
504    
505    
506  void MainForm::dropEvent ( QDropEvent* pDropEvent )  void MainForm::dropEvent ( QDropEvent* pDropEvent )
507  {  {
508      QStringList files;          // Accept externally originated drops only...
509            if (pDropEvent->source())
510      if (!decodeDragFiles(pDropEvent, files))                  return;
         return;  
511    
512          for (QStringList::Iterator iter = files.begin(); iter != files.end(); iter++) {          const QMimeData *pMimeData = pDropEvent->mimeData();
513                  const QString& sPath = *iter;          if (pMimeData->hasUrls()) {
514                  if (qsamplerChannel::isInstrumentFile(sPath)) {                  QListIterator<QUrl> iter(pMimeData->urls());
515                          // Try to create a new channel from instrument file...                  while (iter.hasNext()) {
516                          qsamplerChannel *pChannel = new qsamplerChannel();                          const QString& sPath = iter.next().toLocalFile();
517                          if (pChannel == NULL)                          if (Channel::isInstrumentFile(sPath)) {
518                                  return;                                  // Try to create a new channel from instrument file...
519                          // Start setting the instrument filename...                                  Channel *pChannel = new Channel();
520                          pChannel->setInstrument(sPath, 0);                                  if (pChannel == NULL)
521                          // Before we show it up, may be we'll                                          return;
522                          // better ask for some initial values?                                  // Start setting the instrument filename...
523                          if (!pChannel->channelSetup(this)) {                                  pChannel->setInstrument(sPath, 0);
524                                  delete pChannel;                                  // Before we show it up, may be we'll
525                                  return;                                  // better ask for some initial values?
526                          }                                  if (!pChannel->channelSetup(this)) {
527                          // Finally, give it to a new channel strip...                                          delete pChannel;
528                          if (!createChannelStrip(pChannel)) {                                          return;
529                                  delete pChannel;                                  }
530                                  return;                                  // Finally, give it to a new channel strip...
531                                    if (!createChannelStrip(pChannel)) {
532                                            delete pChannel;
533                                            return;
534                                    }
535                                    // Make that an overall update.
536                                    m_iDirtyCount++;
537                                    stabilizeForm();
538                            }   // Otherwise, load an usual session file (LSCP script)...
539                            else if (closeSession(true)) {
540                                    loadSessionFile(sPath);
541                                    break;
542                          }                          }
                         // Make that an overall update.  
                         m_iDirtyCount++;  
                         stabilizeForm();  
                 }   // Otherwise, load an usual session file (LSCP script)...  
                 else if (closeSession(true)) {  
                         loadSessionFile(sPath);  
                         break;  
543                  }                  }
544                  // Make it look responsive...:)                  // Make it look responsive...:)
545                  QApplication::processEvents(QEventLoop::ExcludeUserInput);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
546          }          }
547  }  }
548    
549    
550  // Custome event handler.  // Custome event handler.
551  void MainForm::customEvent(QEvent* pCustomEvent)  void MainForm::customEvent(QEvent* pCustomEvent)
552  {  {
553      // For the time being, just pump it to messages.          // For the time being, just pump it to messages.
554      if (pCustomEvent->type() == QSAMPLER_CUSTOM_EVENT) {          if (pCustomEvent->type() == QSAMPLER_CUSTOM_EVENT) {
555          qsamplerCustomEvent *pEvent = (qsamplerCustomEvent *) pCustomEvent;                  CustomEvent *pEvent = static_cast<CustomEvent *> (pCustomEvent);
556                  if (pEvent->event() == LSCP_EVENT_CHANNEL_INFO) {                  switch (pEvent->event()) {
557                          int iChannelID = pEvent->data().toInt();                          case LSCP_EVENT_CHANNEL_INFO: {
558                          ChannelStrip *pChannelStrip = channelStrip(iChannelID);                                  int iChannelID = pEvent->data().toInt();
559                          if (pChannelStrip)                                  ChannelStrip *pChannelStrip = channelStrip(iChannelID);
560                                  channelStripChanged(pChannelStrip);                                  if (pChannelStrip)
561                  } else {                                          channelStripChanged(pChannelStrip);
562                          appendMessagesColor(tr("Notify event: %1 data: %2")                                  break;
563                                  .arg(::lscp_event_to_text(pEvent->event()))                          }
564                                  .arg(pEvent->data()), "#996699");                          case LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT:
565                                    if (m_pDeviceForm) m_pDeviceForm->refreshDevices();
566                                    DeviceStatusForm::onDevicesChanged();
567                                    updateViewMidiDeviceStatusMenu();
568                                    break;
569                            case LSCP_EVENT_MIDI_INPUT_DEVICE_INFO: {
570                                    if (m_pDeviceForm) m_pDeviceForm->refreshDevices();
571                                    const int iDeviceID = pEvent->data().section(' ', 0, 0).toInt();
572                                    DeviceStatusForm::onDeviceChanged(iDeviceID);
573                                    break;
574                            }
575    #if CONFIG_LSCP_CHANNEL_MIDI
576                            case LSCP_EVENT_CHANNEL_MIDI: {
577                                    const int iChannelID = pEvent->data().section(' ', 0, 0).toInt();
578                                    ChannelStrip *pChannelStrip = channelStrip(iChannelID);
579                                    if (pChannelStrip)
580                                            pChannelStrip->midiArrived();
581                                    break;
582                            }
583    #endif
584    #if CONFIG_LSCP_DEVICE_MIDI
585                            case LSCP_EVENT_DEVICE_MIDI: {
586                                    const int iDeviceID = pEvent->data().section(' ', 0, 0).toInt();
587                                    const int iPortID   = pEvent->data().section(' ', 1, 1).toInt();
588                                    DeviceStatusForm* pDeviceStatusForm =
589                                            DeviceStatusForm::getInstance(iDeviceID);
590                                    if (pDeviceStatusForm)
591                                            pDeviceStatusForm->midiArrived(iPortID);
592                                    break;
593                            }
594    #endif
595                            default:
596                                    appendMessagesColor(tr("Notify event: %1 data: %2")
597                                            .arg(::lscp_event_to_text(pEvent->event()))
598                                            .arg(pEvent->data()), "#996699");
599                  }                  }
600      }          }
601    }
602    
603    void MainForm::updateViewMidiDeviceStatusMenu() {
604            m_ui.viewMidiDeviceStatusMenu->clear();
605            const std::map<int, DeviceStatusForm*> statusForms =
606                    DeviceStatusForm::getInstances();
607            for (
608                    std::map<int, DeviceStatusForm*>::const_iterator iter = statusForms.begin();
609                    iter != statusForms.end(); ++iter
610            ) {
611                    DeviceStatusForm* pForm = iter->second;
612                    m_ui.viewMidiDeviceStatusMenu->addAction(
613                            pForm->visibleAction()
614                    );
615            }
616  }  }
617    
618  // Context menu event handler.  // Context menu event handler.
619  void MainForm::contextMenuEvent( QContextMenuEvent *pEvent )  void MainForm::contextMenuEvent( QContextMenuEvent *pEvent )
620  {  {
621      stabilizeForm();          stabilizeForm();
622    
623      ui.editMenu->exec(pEvent->globalPos());          m_ui.editMenu->exec(pEvent->globalPos());
624  }  }
625    
626    
# Line 571  void MainForm::contextMenuEvent( QContex Line 628  void MainForm::contextMenuEvent( QContex
628  // qsamplerMainForm -- Brainless public property accessors.  // qsamplerMainForm -- Brainless public property accessors.
629    
630  // The global options settings property.  // The global options settings property.
631  qsamplerOptions *MainForm::options (void)  Options *MainForm::options (void) const
632  {  {
633      return m_pOptions;          return m_pOptions;
634  }  }
635    
636    
637  // The LSCP client descriptor property.  // The LSCP client descriptor property.
638  lscp_client_t *MainForm::client (void)  lscp_client_t *MainForm::client (void) const
639  {  {
640      return m_pClient;          return m_pClient;
641  }  }
642    
643    
# Line 597  MainForm *MainForm::getInstance (void) Line 654  MainForm *MainForm::getInstance (void)
654  // Format the displayable session filename.  // Format the displayable session filename.
655  QString MainForm::sessionName ( const QString& sFilename )  QString MainForm::sessionName ( const QString& sFilename )
656  {  {
657      bool bCompletePath = (m_pOptions && m_pOptions->bCompletePath);          bool bCompletePath = (m_pOptions && m_pOptions->bCompletePath);
658      QString sSessionName = sFilename;          QString sSessionName = sFilename;
659      if (sSessionName.isEmpty())          if (sSessionName.isEmpty())
660          sSessionName = tr("Untitled") + QString::number(m_iUntitled);                  sSessionName = tr("Untitled") + QString::number(m_iUntitled);
661      else if (!bCompletePath)          else if (!bCompletePath)
662          sSessionName = QFileInfo(sSessionName).fileName();                  sSessionName = QFileInfo(sSessionName).fileName();
663      return sSessionName;          return sSessionName;
664  }  }
665    
666    
667  // Create a new session file from scratch.  // Create a new session file from scratch.
668  bool MainForm::newSession (void)  bool MainForm::newSession (void)
669  {  {
670      // Check if we can do it.          // Check if we can do it.
671      if (!closeSession(true))          if (!closeSession(true))
672          return false;                  return false;
673    
674          // Give us what the server has, right now...          // Give us what the server has, right now...
675          updateSession();          updateSession();
676    
677      // Ok increment untitled count.          // Ok increment untitled count.
678      m_iUntitled++;          m_iUntitled++;
679    
680      // Stabilize form.          // Stabilize form.
681      m_sFilename = QString::null;          m_sFilename = QString::null;
682      m_iDirtyCount = 0;          m_iDirtyCount = 0;
683      appendMessages(tr("New session: \"%1\".").arg(sessionName(m_sFilename)));          appendMessages(tr("New session: \"%1\".").arg(sessionName(m_sFilename)));
684      stabilizeForm();          stabilizeForm();
685    
686      return true;          return true;
687  }  }
688    
689    
690  // Open an existing sampler session.  // Open an existing sampler session.
691  bool MainForm::openSession (void)  bool MainForm::openSession (void)
692  {  {
693      if (m_pOptions == NULL)          if (m_pOptions == NULL)
694          return false;                  return false;
695    
696            // Ask for the filename to open...
697            QString sFilename = QFileDialog::getOpenFileName(this,
698                    QSAMPLER_TITLE ": " + tr("Open Session"), // Caption.
699                    m_pOptions->sSessionDir,                  // Start here.
700                    tr("LSCP Session files") + " (*.lscp)"    // Filter (LSCP files)
701            );
702    
703      // Ask for the filename to open...          // Have we cancelled?
704      QString sFilename = QFileDialog::getOpenFileName(          if (sFilename.isEmpty())
705                  m_pOptions->sSessionDir,                // Start here.                  return false;
                 tr("LSCP Session files") + " (*.lscp)", // Filter (LSCP files)  
                 this, 0,                                // Parent and name (none)  
                 QSAMPLER_TITLE ": " + tr("Open Session")        // Caption.  
     );  
   
     // Have we cancelled?  
     if (sFilename.isEmpty())  
         return false;  
   
     // Check if we're going to discard safely the current one...  
     if (!closeSession(true))  
         return false;  
706    
707      // Load it right away.          // Check if we're going to discard safely the current one...
708      return loadSessionFile(sFilename);          if (!closeSession(true))
709                    return false;
710    
711            // Load it right away.
712            return loadSessionFile(sFilename);
713  }  }
714    
715    
716  // Save current sampler session with another name.  // Save current sampler session with another name.
717  bool MainForm::saveSession ( bool bPrompt )  bool MainForm::saveSession ( bool bPrompt )
718  {  {
719      if (m_pOptions == NULL)          if (m_pOptions == NULL)
720          return false;                  return false;
721    
722      QString sFilename = m_sFilename;          QString sFilename = m_sFilename;
723    
724      // Ask for the file to save, if there's none...          // Ask for the file to save, if there's none...
725      if (bPrompt || sFilename.isEmpty()) {          if (bPrompt || sFilename.isEmpty()) {
726          // If none is given, assume default directory.                  // If none is given, assume default directory.
727          if (sFilename.isEmpty())                  if (sFilename.isEmpty())
728              sFilename = m_pOptions->sSessionDir;                          sFilename = m_pOptions->sSessionDir;
729          // Prompt the guy...                  // Prompt the guy...
730          sFilename = QFileDialog::getSaveFileName(                  sFilename = QFileDialog::getSaveFileName(this,
731                          sFilename,                              // Start here.                          QSAMPLER_TITLE ": " + tr("Save Session"), // Caption.
732                          tr("LSCP Session files") + " (*.lscp)", // Filter (LSCP files)                          sFilename,                                // Start here.
733                          this, 0,                                // Parent and name (none)                          tr("LSCP Session files") + " (*.lscp)"    // Filter (LSCP files)
734                          QSAMPLER_TITLE ": " + tr("Save Session")        // Caption.                  );
735          );                  // Have we cancelled it?
736          // Have we cancelled it?                  if (sFilename.isEmpty())
737          if (sFilename.isEmpty())                          return false;
738              return false;                  // Enforce .lscp extension...
739          // Enforce .lscp extension...                  if (QFileInfo(sFilename).suffix().isEmpty())
740          if (QFileInfo(sFilename).extension().isEmpty())                          sFilename += ".lscp";
741              sFilename += ".lscp";                  // Check if already exists...
742          // Check if already exists...                  if (sFilename != m_sFilename && QFileInfo(sFilename).exists()) {
743          if (sFilename != m_sFilename && QFileInfo(sFilename).exists()) {                          if (QMessageBox::warning(this,
             if (QMessageBox::warning(this,  
744                                  QSAMPLER_TITLE ": " + tr("Warning"),                                  QSAMPLER_TITLE ": " + tr("Warning"),
745                  tr("The file already exists:\n\n"                                  tr("The file already exists:\n\n"
746                     "\"%1\"\n\n"                                  "\"%1\"\n\n"
747                     "Do you want to replace it?")                                  "Do you want to replace it?")
748                     .arg(sFilename),                                  .arg(sFilename),
749                  tr("Replace"), tr("Cancel")) > 0)                                  tr("Replace"), tr("Cancel")) > 0)
750                  return false;                                  return false;
751          }                  }
752      }          }
753    
754      // Save it right away.          // Save it right away.
755      return saveSessionFile(sFilename);          return saveSessionFile(sFilename);
756  }  }
757    
758    
759  // Close current session.  // Close current session.
760  bool MainForm::closeSession ( bool bForce )  bool MainForm::closeSession ( bool bForce )
761  {  {
762      bool bClose = true;          bool bClose = true;
763    
764      // Are we dirty enough to prompt it?          // Are we dirty enough to prompt it?
765      if (m_iDirtyCount > 0) {          if (m_iDirtyCount > 0) {
766          switch (QMessageBox::warning(this,                  switch (QMessageBox::warning(this,
767                          QSAMPLER_TITLE ": " + tr("Warning"),                          QSAMPLER_TITLE ": " + tr("Warning"),
768              tr("The current session has been changed:\n\n"                          tr("The current session has been changed:\n\n"
769              "\"%1\"\n\n"                          "\"%1\"\n\n"
770              "Do you want to save the changes?")                          "Do you want to save the changes?")
771              .arg(sessionName(m_sFilename)),                          .arg(sessionName(m_sFilename)),
772              tr("Save"), tr("Discard"), tr("Cancel"))) {                          tr("Save"), tr("Discard"), tr("Cancel"))) {
773          case 0:     // Save...                  case 0:     // Save...
774              bClose = saveSession(false);                          bClose = saveSession(false);
775              // Fall thru....                          // Fall thru....
776          case 1:     // Discard                  case 1:     // Discard
777              break;                          break;
778          default:    // Cancel.                  default:    // Cancel.
779              bClose = false;                          bClose = false;
780              break;                          break;
781          }                  }
782      }          }
783    
784      // If we may close it, dot it.          // If we may close it, dot it.
785      if (bClose) {          if (bClose) {
786          // Remove all channel strips from sight...                  // Remove all channel strips from sight...
787          m_pWorkspace->setUpdatesEnabled(false);                  m_pWorkspace->setUpdatesEnabled(false);
788          QWidgetList wlist = m_pWorkspace->windowList();                  QWidgetList wlist = m_pWorkspace->windowList();
789          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {                  for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
790              ChannelStrip *pChannelStrip = (ChannelStrip*) wlist.at(iChannel);                          ChannelStrip *pChannelStrip = (ChannelStrip*) wlist.at(iChannel);
791              if (pChannelStrip) {                          if (pChannelStrip) {
792                  qsamplerChannel *pChannel = pChannelStrip->channel();                                  Channel *pChannel = pChannelStrip->channel();
793                  if (bForce && pChannel)                                  if (bForce && pChannel)
794                      pChannel->removeChannel();                                          pChannel->removeChannel();
795                  delete pChannelStrip;                                  delete pChannelStrip;
796              }                          }
797          }                  }
798          m_pWorkspace->setUpdatesEnabled(true);                  m_pWorkspace->setUpdatesEnabled(true);
799          // We're now clean, for sure.                  // We're now clean, for sure.
800          m_iDirtyCount = 0;                  m_iDirtyCount = 0;
801      }          }
802    
803      return bClose;          return bClose;
804  }  }
805    
806    
807  // Load a session from specific file path.  // Load a session from specific file path.
808  bool MainForm::loadSessionFile ( const QString& sFilename )  bool MainForm::loadSessionFile ( const QString& sFilename )
809  {  {
810      if (m_pClient == NULL)          if (m_pClient == NULL)
811          return false;                  return false;
812    
813      // Open and read from real file.          // Open and read from real file.
814      QFile file(sFilename);          QFile file(sFilename);
815      if (!file.open(IO_ReadOnly)) {          if (!file.open(QIODevice::ReadOnly)) {
816          appendMessagesError(tr("Could not open \"%1\" session file.\n\nSorry.").arg(sFilename));                  appendMessagesError(
817          return false;                          tr("Could not open \"%1\" session file.\n\nSorry.")
818      }                          .arg(sFilename));
819                    return false;
820            }
821    
822          // Tell the world we'll take some time...          // Tell the world we'll take some time...
823          QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));          QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
824    
825      // Read the file.          // Read the file.
826          int iLine = 0;          int iLine = 0;
827      int iErrors = 0;          int iErrors = 0;
828      QTextStream ts(&file);          QTextStream ts(&file);
829      while (!ts.atEnd()) {          while (!ts.atEnd()) {
830          // Read the line.                  // Read the line.
831          QString sCommand = ts.readLine().stripWhiteSpace();                  QString sCommand = ts.readLine().trimmed();
832                  iLine++;                  iLine++;
833          // If not empty, nor a comment, call the server...                  // If not empty, nor a comment, call the server...
834          if (!sCommand.isEmpty() && sCommand[0] != '#') {                  if (!sCommand.isEmpty() && sCommand[0] != '#') {
835                          // Remember that, no matter what,                          // Remember that, no matter what,
836                          // all LSCP commands are CR/LF terminated.                          // all LSCP commands are CR/LF terminated.
837                          sCommand += "\r\n";                          sCommand += "\r\n";
838                          if (::lscp_client_query(m_pClient, sCommand.latin1()) != LSCP_OK) {                          if (::lscp_client_query(m_pClient, sCommand.toUtf8().constData())
839                                    != LSCP_OK) {
840                                  appendMessagesColor(QString("%1(%2): %3")                                  appendMessagesColor(QString("%1(%2): %3")
841                                          .arg(QFileInfo(sFilename).fileName()).arg(iLine)                                          .arg(QFileInfo(sFilename).fileName()).arg(iLine)
842                                          .arg(sCommand.simplifyWhiteSpace()), "#996633");                                          .arg(sCommand.simplified()), "#996633");
843                                  appendMessagesClient("lscp_client_query");                                  appendMessagesClient("lscp_client_query");
844                                  iErrors++;                                  iErrors++;
845                          }                          }
846          }                  }
847          // Try to make it snappy :)                  // Try to make it snappy :)
848          QApplication::processEvents(QEventLoop::ExcludeUserInput);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
849      }          }
850    
851      // Ok. we've read it.          // Ok. we've read it.
852      file.close();          file.close();
853    
854          // Now we'll try to create (update) the whole GUI session.          // Now we'll try to create (update) the whole GUI session.
855          updateSession();          updateSession();
# Line 800  bool MainForm::loadSessionFile ( const Q Line 858  bool MainForm::loadSessionFile ( const Q
858          QApplication::restoreOverrideCursor();          QApplication::restoreOverrideCursor();
859    
860          // Have we any errors?          // Have we any errors?
861          if (iErrors > 0)          if (iErrors > 0) {
862                  appendMessagesError(tr("Session loaded with errors\nfrom \"%1\".\n\nSorry.").arg(sFilename));                  appendMessagesError(
863                            tr("Session loaded with errors\nfrom \"%1\".\n\nSorry.")
864                            .arg(sFilename));
865            }
866    
867      // Save as default session directory.          // Save as default session directory.
868      if (m_pOptions)          if (m_pOptions)
869          m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);                  m_pOptions->sSessionDir = QFileInfo(sFilename).dir().absolutePath();
870          // We're not dirty anymore, if loaded without errors,          // We're not dirty anymore, if loaded without errors,
871          m_iDirtyCount = iErrors;          m_iDirtyCount = iErrors;
872      // Stabilize form...          // Stabilize form...
873      m_sFilename = sFilename;          m_sFilename = sFilename;
874      updateRecentFiles(sFilename);          updateRecentFiles(sFilename);
875      appendMessages(tr("Open session: \"%1\".").arg(sessionName(m_sFilename)));          appendMessages(tr("Open session: \"%1\".").arg(sessionName(m_sFilename)));
876    
877      // Make that an overall update.          // Make that an overall update.
878      stabilizeForm();          stabilizeForm();
879      return true;          return true;
880  }  }
881    
882    
# Line 831  bool MainForm::saveSessionFile ( const Q Line 892  bool MainForm::saveSessionFile ( const Q
892                  return false;                  return false;
893          }          }
894    
895      // Open and write into real file.          // Open and write into real file.
896      QFile file(sFilename);          QFile file(sFilename);
897      if (!file.open(IO_WriteOnly | IO_Truncate)) {          if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
898          appendMessagesError(tr("Could not open \"%1\" session file.\n\nSorry.").arg(sFilename));                  appendMessagesError(
899          return false;                          tr("Could not open \"%1\" session file.\n\nSorry.")
900      }                          .arg(sFilename));
901                    return false;
902            }
903    
904          // Tell the world we'll take some time...          // Tell the world we'll take some time...
905          QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));          QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
906    
907      // Write the file.          // Write the file.
908      int  iErrors = 0;          int  iErrors = 0;
909      QTextStream ts(&file);          QTextStream ts(&file);
910      ts << "# " << QSAMPLER_TITLE " - " << tr(QSAMPLER_SUBTITLE) << endl;          ts << "# " << QSAMPLER_TITLE " - " << tr(QSAMPLER_SUBTITLE) << endl;
911      ts << "# " << tr("Version")          ts << "# " << tr("Version")
912         << ": " QSAMPLER_VERSION << endl;          << ": " QSAMPLER_VERSION << endl;
913      ts << "# " << tr("Build")          ts << "# " << tr("Build")
914         << ": " __DATE__ " " __TIME__ << endl;          << ": " __DATE__ " " __TIME__ << endl;
915      ts << "#"  << endl;          ts << "#"  << endl;
916      ts << "# " << tr("File")          ts << "# " << tr("File")
917         << ": " << QFileInfo(sFilename).fileName() << endl;          << ": " << QFileInfo(sFilename).fileName() << endl;
918      ts << "# " << tr("Date")          ts << "# " << tr("Date")
919         << ": " << QDate::currentDate().toString("MMM dd yyyy")          << ": " << QDate::currentDate().toString("MMM dd yyyy")
920         << " "  << QTime::currentTime().toString("hh:mm:ss") << endl;          << " "  << QTime::currentTime().toString("hh:mm:ss") << endl;
921      ts << "#"  << endl;          ts << "#"  << endl;
922      ts << endl;          ts << endl;
923    
924          // It is assumed that this new kind of device+session file          // It is assumed that this new kind of device+session file
925          // will be loaded from a complete initialized server...          // will be loaded from a complete initialized server...
# Line 866  bool MainForm::saveSessionFile ( const Q Line 929  bool MainForm::saveSessionFile ( const Q
929    
930          // Audio device mapping.          // Audio device mapping.
931          QMap<int, int> audioDeviceMap;          QMap<int, int> audioDeviceMap;
932          piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Audio);          piDeviceIDs = Device::getDevices(m_pClient, Device::Audio);
933          for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {          for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {
934                  ts << endl;                  ts << endl;
935                  qsamplerDevice device(qsamplerDevice::Audio, piDeviceIDs[iDevice]);                  Device device(Device::Audio, piDeviceIDs[iDevice]);
936                  // Audio device specification...                  // Audio device specification...
937                  ts << "# " << device.deviceTypeName() << " " << device.driverName()                  ts << "# " << device.deviceTypeName() << " " << device.driverName()
938                          << " " << tr("Device") << " " << iDevice << endl;                          << " " << tr("Device") << " " << iDevice << endl;
939                  ts << "CREATE AUDIO_OUTPUT_DEVICE " << device.driverName();                  ts << "CREATE AUDIO_OUTPUT_DEVICE " << device.driverName();
940                  qsamplerDeviceParamMap::ConstIterator deviceParam;                  DeviceParamMap::ConstIterator deviceParam;
941                  for (deviceParam = device.params().begin();                  for (deviceParam = device.params().begin();
942                                  deviceParam != device.params().end();                                  deviceParam != device.params().end();
943                                          ++deviceParam) {                                          ++deviceParam) {
944                          const qsamplerDeviceParam& param = deviceParam.data();                          const DeviceParam& param = deviceParam.value();
945                          if (param.value.isEmpty()) ts << "# ";                          if (param.value.isEmpty()) ts << "# ";
946                          ts << " " << deviceParam.key() << "='" << param.value << "'";                          ts << " " << deviceParam.key() << "='" << param.value << "'";
947                  }                  }
948                  ts << endl;                  ts << endl;
949                  // Audio channel parameters...                  // Audio channel parameters...
950                  int iPort = 0;                  int iPort = 0;
951                  for (qsamplerDevicePort *pPort = device.ports().first();                  QListIterator<DevicePort *> iter(device.ports());
952                                  pPort;                  while (iter.hasNext()) {
953                                          pPort = device.ports().next(), ++iPort) {                          DevicePort *pPort = iter.next();
954                          qsamplerDeviceParamMap::ConstIterator portParam;                          DeviceParamMap::ConstIterator portParam;
955                          for (portParam = pPort->params().begin();                          for (portParam = pPort->params().begin();
956                                          portParam != pPort->params().end();                                          portParam != pPort->params().end();
957                                                  ++portParam) {                                                  ++portParam) {
958                                  const qsamplerDeviceParam& param = portParam.data();                                  const DeviceParam& param = portParam.value();
959                                  if (param.fix || param.value.isEmpty()) ts << "# ";                                  if (param.fix || param.value.isEmpty()) ts << "# ";
960                                  ts << "SET AUDIO_OUTPUT_CHANNEL_PARAMETER " << iDevice                                  ts << "SET AUDIO_OUTPUT_CHANNEL_PARAMETER " << iDevice
961                                          << " " << iPort << " " << portParam.key()                                          << " " << iPort << " " << portParam.key()
962                                          << "='" << param.value << "'" << endl;                                          << "='" << param.value << "'" << endl;
963                          }                          }
964                            iPort++;
965                  }                  }
966                  // Audio device index/id mapping.                  // Audio device index/id mapping.
967                  audioDeviceMap[device.deviceID()] = iDevice;                  audioDeviceMap[device.deviceID()] = iDevice;
968                  // Try to keep it snappy :)                  // Try to keep it snappy :)
969                  QApplication::processEvents(QEventLoop::ExcludeUserInput);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
970          }          }
971    
972          // MIDI device mapping.          // MIDI device mapping.
973          QMap<int, int> midiDeviceMap;          QMap<int, int> midiDeviceMap;
974          piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Midi);          piDeviceIDs = Device::getDevices(m_pClient, Device::Midi);
975          for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {          for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {
976                  ts << endl;                  ts << endl;
977                  qsamplerDevice device(qsamplerDevice::Midi, piDeviceIDs[iDevice]);                  Device device(Device::Midi, piDeviceIDs[iDevice]);
978                  // MIDI device specification...                  // MIDI device specification...
979                  ts << "# " << device.deviceTypeName() << " " << device.driverName()                  ts << "# " << device.deviceTypeName() << " " << device.driverName()
980                          << " " << tr("Device") << " " << iDevice << endl;                          << " " << tr("Device") << " " << iDevice << endl;
981                  ts << "CREATE MIDI_INPUT_DEVICE " << device.driverName();                  ts << "CREATE MIDI_INPUT_DEVICE " << device.driverName();
982                  qsamplerDeviceParamMap::ConstIterator deviceParam;                  DeviceParamMap::ConstIterator deviceParam;
983                  for (deviceParam = device.params().begin();                  for (deviceParam = device.params().begin();
984                                  deviceParam != device.params().end();                                  deviceParam != device.params().end();
985                                          ++deviceParam) {                                          ++deviceParam) {
986                          const qsamplerDeviceParam& param = deviceParam.data();                          const DeviceParam& param = deviceParam.value();
987                          if (param.value.isEmpty()) ts << "# ";                          if (param.value.isEmpty()) ts << "# ";
988                          ts << " " << deviceParam.key() << "='" << param.value << "'";                          ts << " " << deviceParam.key() << "='" << param.value << "'";
989                  }                  }
990                  ts << endl;                  ts << endl;
991                  // MIDI port parameters...                  // MIDI port parameters...
992                  int iPort = 0;                  int iPort = 0;
993                  for (qsamplerDevicePort *pPort = device.ports().first();                  QListIterator<DevicePort *> iter(device.ports());
994                                  pPort;                  while (iter.hasNext()) {
995                                          pPort = device.ports().next(), ++iPort) {                          DevicePort *pPort = iter.next();
996                          qsamplerDeviceParamMap::ConstIterator portParam;                          DeviceParamMap::ConstIterator portParam;
997                          for (portParam = pPort->params().begin();                          for (portParam = pPort->params().begin();
998                                          portParam != pPort->params().end();                                          portParam != pPort->params().end();
999                                                  ++portParam) {                                                  ++portParam) {
1000                                  const qsamplerDeviceParam& param = portParam.data();                                  const DeviceParam& param = portParam.value();
1001                                  if (param.fix || param.value.isEmpty()) ts << "# ";                                  if (param.fix || param.value.isEmpty()) ts << "# ";
1002                                  ts << "SET MIDI_INPUT_PORT_PARAMETER " << iDevice                                  ts << "SET MIDI_INPUT_PORT_PARAMETER " << iDevice
1003                                     << " " << iPort << " " << portParam.key()                                  << " " << iPort << " " << portParam.key()
1004                                     << "='" << param.value << "'" << endl;                                  << "='" << param.value << "'" << endl;
1005                          }                          }
1006                            iPort++;
1007                  }                  }
1008                  // MIDI device index/id mapping.                  // MIDI device index/id mapping.
1009                  midiDeviceMap[device.deviceID()] = iDevice;                  midiDeviceMap[device.deviceID()] = iDevice;
1010                  // Try to keep it snappy :)                  // Try to keep it snappy :)
1011                  QApplication::processEvents(QEventLoop::ExcludeUserInput);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1012          }          }
1013          ts << endl;          ts << endl;
1014    
# Line 1000  bool MainForm::saveSessionFile ( const Q Line 1065  bool MainForm::saveSessionFile ( const Q
1065                                  iErrors++;                                  iErrors++;
1066                          }                          }
1067                          // Try to keep it snappy :)                          // Try to keep it snappy :)
1068                          QApplication::processEvents(QEventLoop::ExcludeUserInput);                          QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1069                  }                  }
1070                  ts << endl;                  ts << endl;
1071                  // Check for errors...                  // Check for errors...
# Line 1019  bool MainForm::saveSessionFile ( const Q Line 1084  bool MainForm::saveSessionFile ( const Q
1084  #endif  // CONFIG_MIDI_INSTRUMENT  #endif  // CONFIG_MIDI_INSTRUMENT
1085    
1086          // Sampler channel mapping.          // Sampler channel mapping.
1087      QWidgetList wlist = m_pWorkspace->windowList();          QWidgetList wlist = m_pWorkspace->windowList();
1088      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1089          ChannelStrip* pChannelStrip                  ChannelStrip* pChannelStrip
1090                          = static_cast<ChannelStrip *> (wlist.at(iChannel));                          = static_cast<ChannelStrip *> (wlist.at(iChannel));
1091          if (pChannelStrip) {                  if (pChannelStrip) {
1092              qsamplerChannel *pChannel = pChannelStrip->channel();                          Channel *pChannel = pChannelStrip->channel();
1093              if (pChannel) {                          if (pChannel) {
1094                  ts << "# " << tr("Channel") << " " << iChannel << endl;                                  ts << "# " << tr("Channel") << " " << iChannel << endl;
1095                  ts << "ADD CHANNEL" << endl;                                  ts << "ADD CHANNEL" << endl;
1096                                  if (audioDeviceMap.isEmpty()) {                                  if (audioDeviceMap.isEmpty()) {
1097                                          ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannel                                          ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannel
1098                                                  << " " << pChannel->audioDriver() << endl;                                                  << " " << pChannel->audioDriver() << endl;
# Line 1044  bool MainForm::saveSessionFile ( const Q Line 1109  bool MainForm::saveSessionFile ( const Q
1109                                  }                                  }
1110                                  ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannel                                  ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannel
1111                                          << " " << pChannel->midiPort() << endl;                                          << " " << pChannel->midiPort() << endl;
1112                  ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannel << " ";                                  ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannel << " ";
1113                  if (pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL)                                  if (pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL)
1114                      ts << "ALL";                                          ts << "ALL";
1115                  else                                  else
1116                      ts << pChannel->midiChannel();                                          ts << pChannel->midiChannel();
1117                  ts << endl;                                  ts << endl;
1118                  ts << "LOAD ENGINE " << pChannel->engineName() << " " << iChannel << endl;                                  ts << "LOAD ENGINE " << pChannel->engineName()
1119                                            << " " << iChannel << endl;
1120                                  if (pChannel->instrumentStatus() < 100) ts << "# ";                                  if (pChannel->instrumentStatus() < 100) ts << "# ";
1121                                  ts << "LOAD INSTRUMENT NON_MODAL '" << pChannel->instrumentFile() << "' "                                  ts << "LOAD INSTRUMENT NON_MODAL '"
1122                                            << pChannel->instrumentFile() << "' "
1123                                          << pChannel->instrumentNr() << " " << iChannel << endl;                                          << pChannel->instrumentNr() << " " << iChannel << endl;
1124                                  qsamplerChannelRoutingMap::ConstIterator audioRoute;                                  ChannelRoutingMap::ConstIterator audioRoute;
1125                                  for (audioRoute = pChannel->audioRouting().begin();                                  for (audioRoute = pChannel->audioRouting().begin();
1126                                                  audioRoute != pChannel->audioRouting().end();                                                  audioRoute != pChannel->audioRouting().end();
1127                                                          ++audioRoute) {                                                          ++audioRoute) {
1128                                          ts << "SET CHANNEL AUDIO_OUTPUT_CHANNEL " << iChannel                                          ts << "SET CHANNEL AUDIO_OUTPUT_CHANNEL " << iChannel
1129                                                  << " " << audioRoute.key()                                                  << " " << audioRoute.key()
1130                                                  << " " << audioRoute.data() << endl;                                                  << " " << audioRoute.value() << endl;
1131                                  }                                  }
1132                                  ts << "SET CHANNEL VOLUME " << iChannel                                  ts << "SET CHANNEL VOLUME " << iChannel
1133                                          << " " << pChannel->volume() << endl;                                          << " " << pChannel->volume() << endl;
# Line 1110  bool MainForm::saveSessionFile ( const Q Line 1177  bool MainForm::saveSessionFile ( const Q
1177                                          }                                          }
1178                                  }                                  }
1179  #endif  #endif
1180                  ts << endl;                                  ts << endl;
1181              }                          }
1182          }                  }
1183          // Try to keep it snappy :)                  // Try to keep it snappy :)
1184          QApplication::processEvents(QEventLoop::ExcludeUserInput);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1185      }          }
1186    
1187  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
1188          ts << "# " << tr("Global volume level") << endl;          ts << "# " << tr("Global volume level") << endl;
# Line 1123  bool MainForm::saveSessionFile ( const Q Line 1190  bool MainForm::saveSessionFile ( const Q
1190          ts << endl;          ts << endl;
1191  #endif  #endif
1192    
1193      // Ok. we've wrote it.          // Ok. we've wrote it.
1194      file.close();          file.close();
1195    
1196          // We're fornerly done.          // We're fornerly done.
1197          QApplication::restoreOverrideCursor();          QApplication::restoreOverrideCursor();
1198    
1199      // Have we any errors?          // Have we any errors?
1200      if (iErrors > 0)          if (iErrors > 0) {
1201          appendMessagesError(tr("Some settings could not be saved\nto \"%1\" session file.\n\nSorry.").arg(sFilename));                  appendMessagesError(
1202                            tr("Some settings could not be saved\n"
1203      // Save as default session directory.                          "to \"%1\" session file.\n\nSorry.")
1204      if (m_pOptions)                          .arg(sFilename));
1205          m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);          }
1206      // We're not dirty anymore.  
1207      m_iDirtyCount = 0;          // Save as default session directory.
1208      // Stabilize form...          if (m_pOptions)
1209      m_sFilename = sFilename;                  m_pOptions->sSessionDir = QFileInfo(sFilename).dir().absolutePath();
1210      updateRecentFiles(sFilename);          // We're not dirty anymore.
1211      appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename)));          m_iDirtyCount = 0;
1212      stabilizeForm();          // Stabilize form...
1213      return true;          m_sFilename = sFilename;
1214            updateRecentFiles(sFilename);
1215            appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename)));
1216            stabilizeForm();
1217            return true;
1218  }  }
1219    
1220    
1221  // Session change receiver slot.  // Session change receiver slot.
1222  void MainForm::sessionDirty (void)  void MainForm::sessionDirty (void)
1223  {  {
1224      // Just mark the dirty form.          // Just mark the dirty form.
1225      m_iDirtyCount++;          m_iDirtyCount++;
1226      // and update the form status...          // and update the form status...
1227      stabilizeForm();          stabilizeForm();
1228  }  }
1229    
1230    
# Line 1163  void MainForm::sessionDirty (void) Line 1234  void MainForm::sessionDirty (void)
1234  // Create a new sampler session.  // Create a new sampler session.
1235  void MainForm::fileNew (void)  void MainForm::fileNew (void)
1236  {  {
1237      // Of course we'll start clean new.          // Of course we'll start clean new.
1238      newSession();          newSession();
1239  }  }
1240    
1241    
1242  // Open an existing sampler session.  // Open an existing sampler session.
1243  void MainForm::fileOpen (void)  void MainForm::fileOpen (void)
1244  {  {
1245      // Open it right away.          // Open it right away.
1246      openSession();          openSession();
1247  }  }
1248    
1249    
1250  // Open a recent file session.  // Open a recent file session.
1251  void MainForm::fileOpenRecent ( int iIndex )  void MainForm::fileOpenRecent (void)
1252  {  {
1253      // Check if we can safely close the current session...          // Retrive filename index from action data...
1254      if (m_pOptions && closeSession(true)) {          QAction *pAction = qobject_cast<QAction *> (sender());
1255          QString sFilename = m_pOptions->recentFiles[iIndex];          if (pAction && m_pOptions) {
1256          loadSessionFile(sFilename);                  int iIndex = pAction->data().toInt();
1257      }                  if (iIndex >= 0 && iIndex < m_pOptions->recentFiles.count()) {
1258                            QString sFilename = m_pOptions->recentFiles[iIndex];
1259                            // Check if we can safely close the current session...
1260                            if (!sFilename.isEmpty() && closeSession(true))
1261                                    loadSessionFile(sFilename);
1262                    }
1263            }
1264  }  }
1265    
1266    
1267  // Save current sampler session.  // Save current sampler session.
1268  void MainForm::fileSave (void)  void MainForm::fileSave (void)
1269  {  {
1270      // Save it right away.          // Save it right away.
1271      saveSession(false);          saveSession(false);
1272  }  }
1273    
1274    
1275  // Save current sampler session with another name.  // Save current sampler session with another name.
1276  void MainForm::fileSaveAs (void)  void MainForm::fileSaveAs (void)
1277  {  {
1278      // Save it right away, maybe with another name.          // Save it right away, maybe with another name.
1279      saveSession(true);          saveSession(true);
1280  }  }
1281    
1282    
1283  // Reset the sampler instance.  // Reset the sampler instance.
1284  void MainForm::fileReset (void)  void MainForm::fileReset (void)
1285  {  {
1286      if (m_pClient == NULL)          if (m_pClient == NULL)
1287          return;                  return;
1288    
1289      // Ask user whether he/she want's an internal sampler reset...          // Ask user whether he/she want's an internal sampler reset...
1290      if (QMessageBox::warning(this,          if (QMessageBox::warning(this,
1291                  QSAMPLER_TITLE ": " + tr("Warning"),                  QSAMPLER_TITLE ": " + tr("Warning"),
1292          tr("Resetting the sampler instance will close\n"                  tr("Resetting the sampler instance will close\n"
1293             "all device and channel configurations.\n\n"                  "all device and channel configurations.\n\n"
1294             "Please note that this operation may cause\n"                  "Please note that this operation may cause\n"
1295             "temporary MIDI and Audio disruption.\n\n"                  "temporary MIDI and Audio disruption.\n\n"
1296             "Do you want to reset the sampler engine now?"),                  "Do you want to reset the sampler engine now?"),
1297          tr("Reset"), tr("Cancel")) > 0)                  tr("Reset"), tr("Cancel")) > 0)
1298          return;                  return;
1299    
1300          // Trye closing the current session, first...          // Trye closing the current session, first...
1301          if (!closeSession(true))          if (!closeSession(true))
1302                  return;                  return;
1303    
1304      // Just do the reset, after closing down current session...          // Just do the reset, after closing down current session...
1305          // Do the actual sampler reset...          // Do the actual sampler reset...
1306          if (::lscp_reset_sampler(m_pClient) != LSCP_OK) {          if (::lscp_reset_sampler(m_pClient) != LSCP_OK) {
1307                  appendMessagesClient("lscp_reset_sampler");                  appendMessagesClient("lscp_reset_sampler");
# Line 1232  void MainForm::fileReset (void) Line 1309  void MainForm::fileReset (void)
1309                  return;                  return;
1310          }          }
1311    
1312      // Log this.          // Log this.
1313      appendMessages(tr("Sampler reset."));          appendMessages(tr("Sampler reset."));
1314    
1315          // Make it a new session...          // Make it a new session...
1316          newSession();          newSession();
# Line 1243  void MainForm::fileReset (void) Line 1320  void MainForm::fileReset (void)
1320  // Restart the client/server instance.  // Restart the client/server instance.
1321  void MainForm::fileRestart (void)  void MainForm::fileRestart (void)
1322  {  {
1323      if (m_pOptions == NULL)          if (m_pOptions == NULL)
1324          return;                  return;
1325    
1326      bool bRestart = true;          bool bRestart = true;
1327    
1328      // Ask user whether he/she want's a complete restart...          // Ask user whether he/she want's a complete restart...
1329      // (if we're currently up and running)          // (if we're currently up and running)
1330      if (bRestart && m_pClient) {          if (bRestart && m_pClient) {
1331          bRestart = (QMessageBox::warning(this,                  bRestart = (QMessageBox::warning(this,
1332                          QSAMPLER_TITLE ": " + tr("Warning"),                          QSAMPLER_TITLE ": " + tr("Warning"),
1333              tr("New settings will be effective after\n"                          tr("New settings will be effective after\n"
1334                 "restarting the client/server connection.\n\n"                          "restarting the client/server connection.\n\n"
1335                 "Please note that this operation may cause\n"                          "Please note that this operation may cause\n"
1336                 "temporary MIDI and Audio disruption.\n\n"                          "temporary MIDI and Audio disruption.\n\n"
1337                 "Do you want to restart the connection now?"),                          "Do you want to restart the connection now?"),
1338              tr("Restart"), tr("Cancel")) == 0);                          tr("Restart"), tr("Cancel")) == 0);
1339      }          }
1340    
1341      // Are we still for it?          // Are we still for it?
1342      if (bRestart && closeSession(true)) {          if (bRestart && closeSession(true)) {
1343          // Stop server, it will force the client too.                  // Stop server, it will force the client too.
1344          stopServer();                  stopServer();
1345          // Reschedule a restart...                  // Reschedule a restart...
1346          startSchedule(m_pOptions->iStartDelay);                  startSchedule(m_pOptions->iStartDelay);
1347      }          }
1348  }  }
1349    
1350    
1351  // Exit application program.  // Exit application program.
1352  void MainForm::fileExit (void)  void MainForm::fileExit (void)
1353  {  {
1354      // Go for close the whole thing.          // Go for close the whole thing.
1355      close();          close();
1356  }  }
1357    
1358    
# Line 1285  void MainForm::fileExit (void) Line 1362  void MainForm::fileExit (void)
1362  // Add a new sampler channel.  // Add a new sampler channel.
1363  void MainForm::editAddChannel (void)  void MainForm::editAddChannel (void)
1364  {  {
1365      if (m_pClient == NULL)          if (m_pClient == NULL)
1366          return;                  return;
1367    
1368      // Just create the channel instance...          // Just create the channel instance...
1369      qsamplerChannel *pChannel = new qsamplerChannel();          Channel *pChannel = new Channel();
1370      if (pChannel == NULL)          if (pChannel == NULL)
1371          return;                  return;
1372    
1373      // Before we show it up, may be we'll          // Before we show it up, may be we'll
1374      // better ask for some initial values?          // better ask for some initial values?
1375      if (!pChannel->channelSetup(this)) {          if (!pChannel->channelSetup(this)) {
1376          delete pChannel;                  delete pChannel;
1377          return;                  return;
1378      }          }
1379    
1380      // And give it to the strip (will own the channel instance, if successful).          // And give it to the strip...
1381      if (!createChannelStrip(pChannel)) {          // (will own the channel instance, if successful).
1382          delete pChannel;          if (!createChannelStrip(pChannel)) {
1383          return;                  delete pChannel;
1384      }                  return;
1385            }
1386      // Make that an overall update.  
1387      m_iDirtyCount++;          // Do we auto-arrange?
1388      stabilizeForm();          if (m_pOptions && m_pOptions->bAutoArrange)
1389                    channelsArrange();
1390    
1391            // Make that an overall update.
1392            m_iDirtyCount++;
1393            stabilizeForm();
1394  }  }
1395    
1396    
1397  // Remove current sampler channel.  // Remove current sampler channel.
1398  void MainForm::editRemoveChannel (void)  void MainForm::editRemoveChannel (void)
1399  {  {
1400      if (m_pClient == NULL)          if (m_pClient == NULL)
1401          return;                  return;
1402    
1403            ChannelStrip* pChannelStrip = activeChannelStrip();
1404            if (pChannelStrip == NULL)
1405                    return;
1406    
1407            Channel *pChannel = pChannelStrip->channel();
1408            if (pChannel == NULL)
1409                    return;
1410    
1411      ChannelStrip* pChannelStrip = activeChannelStrip();          // Prompt user if he/she's sure about this...
1412      if (pChannelStrip == NULL)          if (m_pOptions && m_pOptions->bConfirmRemove) {
1413          return;                  if (QMessageBox::warning(this,
   
     qsamplerChannel *pChannel = pChannelStrip->channel();  
     if (pChannel == NULL)  
         return;  
   
     // Prompt user if he/she's sure about this...  
     if (m_pOptions && m_pOptions->bConfirmRemove) {  
         if (QMessageBox::warning(this,  
1414                          QSAMPLER_TITLE ": " + tr("Warning"),                          QSAMPLER_TITLE ": " + tr("Warning"),
1415              tr("About to remove channel:\n\n"                          tr("About to remove channel:\n\n"
1416                 "%1\n\n"                          "%1\n\n"
1417                 "Are you sure?")                          "Are you sure?")
1418                 .arg(pChannelStrip->caption()),                          .arg(pChannelStrip->windowTitle()),
1419              tr("OK"), tr("Cancel")) > 0)                          tr("OK"), tr("Cancel")) > 0)
1420              return;                          return;
1421      }          }
1422    
1423      // Remove the existing sampler channel.          // Remove the existing sampler channel.
1424      if (!pChannel->removeChannel())          if (!pChannel->removeChannel())
1425          return;                  return;
1426    
1427      // Just delete the channel strip.          // Just delete the channel strip.
1428      delete pChannelStrip;          delete pChannelStrip;
1429    
1430      // Do we auto-arrange?          // Do we auto-arrange?
1431      if (m_pOptions && m_pOptions->bAutoArrange)          if (m_pOptions && m_pOptions->bAutoArrange)
1432          channelsArrange();                  channelsArrange();
1433    
1434      // We'll be dirty, for sure...          // We'll be dirty, for sure...
1435      m_iDirtyCount++;          m_iDirtyCount++;
1436      stabilizeForm();          stabilizeForm();
1437  }  }
1438    
1439    
1440  // Setup current sampler channel.  // Setup current sampler channel.
1441  void MainForm::editSetupChannel (void)  void MainForm::editSetupChannel (void)
1442  {  {
1443      if (m_pClient == NULL)          if (m_pClient == NULL)
1444          return;                  return;
1445    
1446      ChannelStrip* pChannelStrip = activeChannelStrip();          ChannelStrip* pChannelStrip = activeChannelStrip();
1447      if (pChannelStrip == NULL)          if (pChannelStrip == NULL)
1448          return;                  return;
1449    
1450      // Just invoque the channel strip procedure.          // Just invoque the channel strip procedure.
1451      pChannelStrip->channelSetup();          pChannelStrip->channelSetup();
1452  }  }
1453    
1454    
1455  // Edit current sampler channel.  // Edit current sampler channel.
1456  void MainForm::editEditChannel (void)  void MainForm::editEditChannel (void)
1457  {  {
1458      if (m_pClient == NULL)          if (m_pClient == NULL)
1459          return;                  return;
1460    
1461      ChannelStrip* pChannelStrip = activeChannelStrip();          ChannelStrip* pChannelStrip = activeChannelStrip();
1462      if (pChannelStrip == NULL)          if (pChannelStrip == NULL)
1463          return;                  return;
1464    
1465      // Just invoque the channel strip procedure.          // Just invoque the channel strip procedure.
1466      pChannelStrip->channelEdit();          pChannelStrip->channelEdit();
1467  }  }
1468    
1469    
1470  // Reset current sampler channel.  // Reset current sampler channel.
1471  void MainForm::editResetChannel (void)  void MainForm::editResetChannel (void)
1472  {  {
1473      if (m_pClient == NULL)          if (m_pClient == NULL)
1474          return;                  return;
1475    
1476      ChannelStrip* pChannelStrip = activeChannelStrip();          ChannelStrip* pChannelStrip = activeChannelStrip();
1477      if (pChannelStrip == NULL)          if (pChannelStrip == NULL)
1478          return;                  return;
1479    
1480      // Just invoque the channel strip procedure.          // Just invoque the channel strip procedure.
1481      pChannelStrip->channelReset();          pChannelStrip->channelReset();
1482  }  }
1483    
1484    
# Line 1425  void MainForm::editResetAllChannels (voi Line 1507  void MainForm::editResetAllChannels (voi
1507  // Show/hide the main program window menubar.  // Show/hide the main program window menubar.
1508  void MainForm::viewMenubar ( bool bOn )  void MainForm::viewMenubar ( bool bOn )
1509  {  {
1510      if (bOn)          if (bOn)
1511          ui.MenuBar->show();                  m_ui.MenuBar->show();
1512      else          else
1513          ui.MenuBar->hide();                  m_ui.MenuBar->hide();
1514  }  }
1515    
1516    
1517  // Show/hide the main program window toolbar.  // Show/hide the main program window toolbar.
1518  void MainForm::viewToolbar ( bool bOn )  void MainForm::viewToolbar ( bool bOn )
1519  {  {
1520      if (bOn) {          if (bOn) {
1521          ui.fileToolbar->show();                  m_ui.fileToolbar->show();
1522          ui.editToolbar->show();                  m_ui.editToolbar->show();
1523          ui.channelsToolbar->show();                  m_ui.channelsToolbar->show();
1524      } else {          } else {
1525          ui.fileToolbar->hide();                  m_ui.fileToolbar->hide();
1526          ui.editToolbar->hide();                  m_ui.editToolbar->hide();
1527          ui.channelsToolbar->hide();                  m_ui.channelsToolbar->hide();
1528      }          }
1529  }  }
1530    
1531    
1532  // Show/hide the main program window statusbar.  // Show/hide the main program window statusbar.
1533  void MainForm::viewStatusbar ( bool bOn )  void MainForm::viewStatusbar ( bool bOn )
1534  {  {
1535      if (bOn)          if (bOn)
1536          statusBar()->show();                  statusBar()->show();
1537      else          else
1538          statusBar()->hide();                  statusBar()->hide();
1539  }  }
1540    
1541    
1542  // Show/hide the messages window logger.  // Show/hide the messages window logger.
1543  void MainForm::viewMessages ( bool bOn )  void MainForm::viewMessages ( bool bOn )
1544  {  {
1545      if (bOn)          if (bOn)
1546          m_pMessages->show();                  m_pMessages->show();
1547      else          else
1548          m_pMessages->hide();                  m_pMessages->hide();
1549  }  }
1550    
1551    
# Line 1480  void MainForm::viewInstruments (void) Line 1562  void MainForm::viewInstruments (void)
1562                  } else {                  } else {
1563                          m_pInstrumentListForm->show();                          m_pInstrumentListForm->show();
1564                          m_pInstrumentListForm->raise();                          m_pInstrumentListForm->raise();
1565                          m_pInstrumentListForm->setActiveWindow();                          m_pInstrumentListForm->activateWindow();
1566                  }                  }
1567          }          }
1568  }  }
# Line 1499  void MainForm::viewDevices (void) Line 1581  void MainForm::viewDevices (void)
1581                  } else {                  } else {
1582                          m_pDeviceForm->show();                          m_pDeviceForm->show();
1583                          m_pDeviceForm->raise();                          m_pDeviceForm->raise();
1584                          m_pDeviceForm->setActiveWindow();                          m_pDeviceForm->activateWindow();
1585                  }                  }
1586          }          }
1587  }  }
# Line 1508  void MainForm::viewDevices (void) Line 1590  void MainForm::viewDevices (void)
1590  // Show options dialog.  // Show options dialog.
1591  void MainForm::viewOptions (void)  void MainForm::viewOptions (void)
1592  {  {
1593      if (m_pOptions == NULL)          if (m_pOptions == NULL)
1594          return;                  return;
1595    
1596      OptionsForm* pOptionsForm = new OptionsForm(this);          OptionsForm* pOptionsForm = new OptionsForm(this);
1597      if (pOptionsForm) {          if (pOptionsForm) {
1598          // Check out some initial nullities(tm)...                  // Check out some initial nullities(tm)...
1599          ChannelStrip* pChannelStrip = activeChannelStrip();                  ChannelStrip* pChannelStrip = activeChannelStrip();
1600          if (m_pOptions->sDisplayFont.isEmpty() && pChannelStrip)                  if (m_pOptions->sDisplayFont.isEmpty() && pChannelStrip)
1601              m_pOptions->sDisplayFont = pChannelStrip->displayFont().toString();                          m_pOptions->sDisplayFont = pChannelStrip->displayFont().toString();
1602          if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages)                  if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages)
1603              m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();                          m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();
1604          // To track down deferred or immediate changes.                  // To track down deferred or immediate changes.
1605          QString sOldServerHost      = m_pOptions->sServerHost;                  QString sOldServerHost      = m_pOptions->sServerHost;
1606          int     iOldServerPort      = m_pOptions->iServerPort;                  int     iOldServerPort      = m_pOptions->iServerPort;
1607          int     iOldServerTimeout   = m_pOptions->iServerTimeout;                  int     iOldServerTimeout   = m_pOptions->iServerTimeout;
1608          bool    bOldServerStart     = m_pOptions->bServerStart;                  bool    bOldServerStart     = m_pOptions->bServerStart;
1609          QString sOldServerCmdLine   = m_pOptions->sServerCmdLine;                  QString sOldServerCmdLine   = m_pOptions->sServerCmdLine;
1610          QString sOldDisplayFont     = m_pOptions->sDisplayFont;                  QString sOldDisplayFont     = m_pOptions->sDisplayFont;
1611          bool    bOldDisplayEffect   = m_pOptions->bDisplayEffect;                  bool    bOldDisplayEffect   = m_pOptions->bDisplayEffect;
1612          int     iOldMaxVolume       = m_pOptions->iMaxVolume;                  int     iOldMaxVolume       = m_pOptions->iMaxVolume;
1613          QString sOldMessagesFont    = m_pOptions->sMessagesFont;                  QString sOldMessagesFont    = m_pOptions->sMessagesFont;
1614          bool    bOldKeepOnTop       = m_pOptions->bKeepOnTop;                  bool    bOldKeepOnTop       = m_pOptions->bKeepOnTop;
1615          bool    bOldStdoutCapture   = m_pOptions->bStdoutCapture;                  bool    bOldStdoutCapture   = m_pOptions->bStdoutCapture;
1616          int     bOldMessagesLimit   = m_pOptions->bMessagesLimit;                  int     bOldMessagesLimit   = m_pOptions->bMessagesLimit;
1617          int     iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines;                  int     iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines;
1618          bool    bOldCompletePath    = m_pOptions->bCompletePath;                  bool    bOldCompletePath    = m_pOptions->bCompletePath;
1619          bool    bOldInstrumentNames = m_pOptions->bInstrumentNames;                  bool    bOldInstrumentNames = m_pOptions->bInstrumentNames;
1620          int     iOldMaxRecentFiles  = m_pOptions->iMaxRecentFiles;                  int     iOldMaxRecentFiles  = m_pOptions->iMaxRecentFiles;
1621          // Load the current setup settings.                  // Load the current setup settings.
1622          pOptionsForm->setup(m_pOptions);                  pOptionsForm->setup(m_pOptions);
1623          // Show the setup dialog...                  // Show the setup dialog...
1624          if (pOptionsForm->exec()) {                  if (pOptionsForm->exec()) {
1625              // Warn if something will be only effective on next run.                          // Warn if something will be only effective on next run.
1626              if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) ||                          if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) ||
1627                  (!bOldStdoutCapture &&  m_pOptions->bStdoutCapture) ||                                  (!bOldStdoutCapture &&  m_pOptions->bStdoutCapture) ||
1628                  ( bOldKeepOnTop     && !m_pOptions->bKeepOnTop)     ||                                  ( bOldKeepOnTop     && !m_pOptions->bKeepOnTop)     ||
1629                  (!bOldKeepOnTop     &&  m_pOptions->bKeepOnTop)) {                                  (!bOldKeepOnTop     &&  m_pOptions->bKeepOnTop)) {
1630                  QMessageBox::information(this,                                  QMessageBox::information(this,
1631                                          QSAMPLER_TITLE ": " + tr("Information"),                                          QSAMPLER_TITLE ": " + tr("Information"),
1632                      tr("Some settings may be only effective\n"                                          tr("Some settings may be only effective\n"
1633                         "next time you start this program."), tr("OK"));                                          "next time you start this program."), tr("OK"));
1634                  updateMessagesCapture();                                  updateMessagesCapture();
1635              }                          }
1636              // Check wheather something immediate has changed.                          // Check wheather something immediate has changed.
1637              if (( bOldCompletePath && !m_pOptions->bCompletePath) ||                          if (( bOldCompletePath && !m_pOptions->bCompletePath) ||
1638                  (!bOldCompletePath &&  m_pOptions->bCompletePath) ||                                  (!bOldCompletePath &&  m_pOptions->bCompletePath) ||
1639                  (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles))                                  (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles))
1640                  updateRecentFilesMenu();                                  updateRecentFilesMenu();
1641              if (( bOldInstrumentNames && !m_pOptions->bInstrumentNames) ||                          if (( bOldInstrumentNames && !m_pOptions->bInstrumentNames) ||
1642                  (!bOldInstrumentNames &&  m_pOptions->bInstrumentNames))                                  (!bOldInstrumentNames &&  m_pOptions->bInstrumentNames))
1643                  updateInstrumentNames();                                  updateInstrumentNames();
1644              if (( bOldDisplayEffect && !m_pOptions->bDisplayEffect) ||                          if (( bOldDisplayEffect && !m_pOptions->bDisplayEffect) ||
1645                  (!bOldDisplayEffect &&  m_pOptions->bDisplayEffect))                                  (!bOldDisplayEffect &&  m_pOptions->bDisplayEffect))
1646                  updateDisplayEffect();                                  updateDisplayEffect();
1647              if (sOldDisplayFont != m_pOptions->sDisplayFont)                          if (sOldDisplayFont != m_pOptions->sDisplayFont)
1648                  updateDisplayFont();                                  updateDisplayFont();
1649              if (iOldMaxVolume != m_pOptions->iMaxVolume)                          if (iOldMaxVolume != m_pOptions->iMaxVolume)
1650                  updateMaxVolume();                                  updateMaxVolume();
1651              if (sOldMessagesFont != m_pOptions->sMessagesFont)                          if (sOldMessagesFont != m_pOptions->sMessagesFont)
1652                  updateMessagesFont();                                  updateMessagesFont();
1653              if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) ||                          if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) ||
1654                  (!bOldMessagesLimit &&  m_pOptions->bMessagesLimit) ||                                  (!bOldMessagesLimit &&  m_pOptions->bMessagesLimit) ||
1655                  (iOldMessagesLimitLines !=  m_pOptions->iMessagesLimitLines))                                  (iOldMessagesLimitLines !=  m_pOptions->iMessagesLimitLines))
1656                  updateMessagesLimit();                                  updateMessagesLimit();
1657              // And now the main thing, whether we'll do client/server recycling?                          // And now the main thing, whether we'll do client/server recycling?
1658              if ((sOldServerHost != m_pOptions->sServerHost) ||                          if ((sOldServerHost != m_pOptions->sServerHost) ||
1659                  (iOldServerPort != m_pOptions->iServerPort) ||                                  (iOldServerPort != m_pOptions->iServerPort) ||
1660                  (iOldServerTimeout != m_pOptions->iServerTimeout) ||                                  (iOldServerTimeout != m_pOptions->iServerTimeout) ||
1661                  ( bOldServerStart && !m_pOptions->bServerStart) ||                                  ( bOldServerStart && !m_pOptions->bServerStart) ||
1662                  (!bOldServerStart &&  m_pOptions->bServerStart) ||                                  (!bOldServerStart &&  m_pOptions->bServerStart) ||
1663                  (sOldServerCmdLine != m_pOptions->sServerCmdLine && m_pOptions->bServerStart))                                  (sOldServerCmdLine != m_pOptions->sServerCmdLine
1664                  fileRestart();                                  && m_pOptions->bServerStart))
1665          }                                  fileRestart();
1666          // Done.                  }
1667          delete pOptionsForm;                  // Done.
1668      }                  delete pOptionsForm;
1669            }
1670    
1671      // This makes it.          // This makes it.
1672      stabilizeForm();          stabilizeForm();
1673  }  }
1674    
1675    
# Line 1596  void MainForm::viewOptions (void) Line 1679  void MainForm::viewOptions (void)
1679  // Arrange channel strips.  // Arrange channel strips.
1680  void MainForm::channelsArrange (void)  void MainForm::channelsArrange (void)
1681  {  {
1682      // Full width vertical tiling          // Full width vertical tiling
1683      QWidgetList wlist = m_pWorkspace->windowList();          QWidgetList wlist = m_pWorkspace->windowList();
1684      if (wlist.isEmpty())          if (wlist.isEmpty())
1685          return;                  return;
1686    
1687      m_pWorkspace->setUpdatesEnabled(false);          m_pWorkspace->setUpdatesEnabled(false);
1688      int y = 0;          int y = 0;
1689      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1690          ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);                  ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);
1691      /*  if (pChannelStrip->testWState(WState_Maximized | WState_Minimized)) {          /*  if (pChannelStrip->testWState(WState_Maximized | WState_Minimized)) {
1692              // Prevent flicker...                          // Prevent flicker...
1693              pChannelStrip->hide();                          pChannelStrip->hide();
1694              pChannelStrip->showNormal();                          pChannelStrip->showNormal();
1695          }   */                  }   */
1696          pChannelStrip->adjustSize();                  pChannelStrip->adjustSize();
1697          int iWidth  = m_pWorkspace->width();                  int iWidth  = m_pWorkspace->width();
1698          if (iWidth < pChannelStrip->width())                  if (iWidth < pChannelStrip->width())
1699              iWidth = pChannelStrip->width();                          iWidth = pChannelStrip->width();
1700      //  int iHeight = pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();          //  int iHeight = pChannelStrip->height()
1701          int iHeight = pChannelStrip->parentWidget()->frameGeometry().height();          //              + pChannelStrip->parentWidget()->baseSize().height();
1702          pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight);                  int iHeight = pChannelStrip->parentWidget()->frameGeometry().height();
1703          y += iHeight;                  pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1704      }                  y += iHeight;
1705      m_pWorkspace->setUpdatesEnabled(true);          }
1706            m_pWorkspace->setUpdatesEnabled(true);
1707    
1708      stabilizeForm();          stabilizeForm();
1709  }  }
1710    
1711    
1712  // Auto-arrange channel strips.  // Auto-arrange channel strips.
1713  void MainForm::channelsAutoArrange ( bool bOn )  void MainForm::channelsAutoArrange ( bool bOn )
1714  {  {
1715      if (m_pOptions == NULL)          if (m_pOptions == NULL)
1716          return;                  return;
1717    
1718      // Toggle the auto-arrange flag.          // Toggle the auto-arrange flag.
1719      m_pOptions->bAutoArrange = bOn;          m_pOptions->bAutoArrange = bOn;
1720    
1721      // If on, update whole workspace...          // If on, update whole workspace...
1722      if (m_pOptions->bAutoArrange)          if (m_pOptions->bAutoArrange)
1723          channelsArrange();                  channelsArrange();
1724  }  }
1725    
1726    
# Line 1646  void MainForm::channelsAutoArrange ( boo Line 1730  void MainForm::channelsAutoArrange ( boo
1730  // Show information about the Qt toolkit.  // Show information about the Qt toolkit.
1731  void MainForm::helpAboutQt (void)  void MainForm::helpAboutQt (void)
1732  {  {
1733      QMessageBox::aboutQt(this);          QMessageBox::aboutQt(this);
1734  }  }
1735    
1736    
1737  // Show information about application program.  // Show information about application program.
1738  void MainForm::helpAbout (void)  void MainForm::helpAbout (void)
1739  {  {
1740      // Stuff the about box text...          // Stuff the about box text...
1741      QString sText = "<p>\n";          QString sText = "<p>\n";
1742      sText += "<b>" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "</b><br />\n";          sText += "<b>" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "</b><br />\n";
1743      sText += "<br />\n";          sText += "<br />\n";
1744      sText += tr("Version") + ": <b>" QSAMPLER_VERSION "</b><br />\n";          sText += tr("Version") + ": <b>" QSAMPLER_VERSION "</b><br />\n";
1745      sText += "<small>" + tr("Build") + ": " __DATE__ " " __TIME__ "</small><br />\n";          sText += "<small>" + tr("Build") + ": " __DATE__ " " __TIME__ "</small><br />\n";
1746  #ifdef CONFIG_DEBUG  #ifdef CONFIG_DEBUG
1747      sText += "<small><font color=\"red\">";          sText += "<small><font color=\"red\">";
1748      sText += tr("Debugging option enabled.");          sText += tr("Debugging option enabled.");
1749      sText += "</font></small><br />";          sText += "</font></small><br />";
1750  #endif  #endif
1751  #ifndef CONFIG_LIBGIG  #ifndef CONFIG_LIBGIG
1752      sText += "<small><font color=\"red\">";          sText += "<small><font color=\"red\">";
1753      sText += tr("GIG (libgig) file support disabled.");          sText += tr("GIG (libgig) file support disabled.");
1754      sText += "</font></small><br />";          sText += "</font></small><br />";
1755  #endif  #endif
1756  #ifndef CONFIG_INSTRUMENT_NAME  #ifndef CONFIG_INSTRUMENT_NAME
1757      sText += "<small><font color=\"red\">";          sText += "<small><font color=\"red\">";
1758      sText += tr("LSCP (liblscp) instrument_name support disabled.");          sText += tr("LSCP (liblscp) instrument_name support disabled.");
1759      sText += "</font></small><br />";          sText += "</font></small><br />";
1760  #endif  #endif
1761  #ifndef CONFIG_MUTE_SOLO  #ifndef CONFIG_MUTE_SOLO
1762      sText += "<small><font color=\"red\">";          sText += "<small><font color=\"red\">";
1763      sText += tr("Sampler channel Mute/Solo support disabled.");          sText += tr("Sampler channel Mute/Solo support disabled.");
1764      sText += "</font></small><br />";          sText += "</font></small><br />";
1765  #endif  #endif
1766  #ifndef CONFIG_AUDIO_ROUTING  #ifndef CONFIG_AUDIO_ROUTING
1767      sText += "<small><font color=\"red\">";          sText += "<small><font color=\"red\">";
1768      sText += tr("LSCP (liblscp) audio_routing support disabled.");          sText += tr("LSCP (liblscp) audio_routing support disabled.");
1769      sText += "</font></small><br />";          sText += "</font></small><br />";
1770  #endif  #endif
1771  #ifndef CONFIG_FXSEND  #ifndef CONFIG_FXSEND
1772      sText += "<small><font color=\"red\">";          sText += "<small><font color=\"red\">";
1773      sText += tr("Sampler channel Effect Sends support disabled.");          sText += tr("Sampler channel Effect Sends support disabled.");
1774      sText += "</font></small><br />";          sText += "</font></small><br />";
1775  #endif  #endif
1776  #ifndef CONFIG_VOLUME  #ifndef CONFIG_VOLUME
1777      sText += "<small><font color=\"red\">";          sText += "<small><font color=\"red\">";
1778      sText += tr("Global volume support disabled.");          sText += tr("Global volume support disabled.");
1779      sText += "</font></small><br />";          sText += "</font></small><br />";
1780  #endif  #endif
1781  #ifndef CONFIG_MIDI_INSTRUMENT  #ifndef CONFIG_MIDI_INSTRUMENT
1782      sText += "<small><font color=\"red\">";          sText += "<small><font color=\"red\">";
1783      sText += tr("MIDI instrument mapping support disabled.");          sText += tr("MIDI instrument mapping support disabled.");
1784      sText += "</font></small><br />";          sText += "</font></small><br />";
1785  #endif  #endif
1786  #ifndef CONFIG_EDIT_INSTRUMENT  #ifndef CONFIG_EDIT_INSTRUMENT
1787      sText += "<small><font color=\"red\">";          sText += "<small><font color=\"red\">";
1788      sText += tr("Instrument editing support disabled.");          sText += tr("Instrument editing support disabled.");
1789      sText += "</font></small><br />";          sText += "</font></small><br />";
1790  #endif  #endif
1791      sText += "<br />\n";          sText += "<br />\n";
1792      sText += tr("Using") + ": ";          sText += tr("Using") + ": ";
1793      sText += ::lscp_client_package();          sText += ::lscp_client_package();
1794      sText += " ";          sText += " ";
1795      sText += ::lscp_client_version();          sText += ::lscp_client_version();
1796  #ifdef CONFIG_LIBGIG  #ifdef CONFIG_LIBGIG
1797      sText += ", ";          sText += ", ";
1798      sText += gig::libraryName().c_str();          sText += gig::libraryName().c_str();
1799      sText += " ";          sText += " ";
1800      sText += gig::libraryVersion().c_str();          sText += gig::libraryVersion().c_str();
1801  #endif  #endif
1802      sText += "<br />\n";          sText += "<br />\n";
1803      sText += "<br />\n";          sText += "<br />\n";
1804      sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";          sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";
1805      sText += "<br />\n";          sText += "<br />\n";
1806      sText += "<small>";          sText += "<small>";
1807      sText += QSAMPLER_COPYRIGHT "<br />\n";          sText += QSAMPLER_COPYRIGHT "<br />\n";
1808      sText += QSAMPLER_COPYRIGHT2 "<br />\n";          sText += QSAMPLER_COPYRIGHT2 "<br />\n";
1809      sText += "<br />\n";          sText += "<br />\n";
1810      sText += tr("This program is free software; you can redistribute it and/or modify it") + "<br />\n";          sText += tr("This program is free software; you can redistribute it and/or modify it") + "<br />\n";
1811      sText += tr("under the terms of the GNU General Public License version 2 or later.");          sText += tr("under the terms of the GNU General Public License version 2 or later.");
1812      sText += "</small>";          sText += "</small>";
1813      sText += "</p>\n";          sText += "</p>\n";
1814    
1815      QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText);          QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText);
1816  }  }
1817    
1818    
# Line 1737  void MainForm::helpAbout (void) Line 1821  void MainForm::helpAbout (void)
1821    
1822  void MainForm::stabilizeForm (void)  void MainForm::stabilizeForm (void)
1823  {  {
1824      // Update the main application caption...          // Update the main application caption...
1825      QString sSessionName = sessionName(m_sFilename);          QString sSessionName = sessionName(m_sFilename);
1826      if (m_iDirtyCount > 0)          if (m_iDirtyCount > 0)
1827          sSessionName += " *";                  sSessionName += " *";
1828      setCaption(tr(QSAMPLER_TITLE " - [%1]").arg(sSessionName));          setWindowTitle(tr(QSAMPLER_TITLE " - [%1]").arg(sSessionName));
1829    
1830      // Update the main menu state...          // Update the main menu state...
1831      ChannelStrip* pChannelStrip = activeChannelStrip();          ChannelStrip* pChannelStrip = activeChannelStrip();
1832      bool bHasClient  = (m_pOptions != NULL && m_pClient != NULL);          bool bHasClient  = (m_pOptions != NULL && m_pClient != NULL);
1833      bool bHasChannel = (bHasClient && pChannelStrip != NULL);          bool bHasChannel = (bHasClient && pChannelStrip != NULL);
1834      ui.fileNewAction->setEnabled(bHasClient);          m_ui.fileNewAction->setEnabled(bHasClient);
1835      ui.fileOpenAction->setEnabled(bHasClient);          m_ui.fileOpenAction->setEnabled(bHasClient);
1836      ui.fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);          m_ui.fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);
1837      ui.fileSaveAsAction->setEnabled(bHasClient);          m_ui.fileSaveAsAction->setEnabled(bHasClient);
1838      ui.fileResetAction->setEnabled(bHasClient);          m_ui.fileResetAction->setEnabled(bHasClient);
1839      ui.fileRestartAction->setEnabled(bHasClient || m_pServer == NULL);          m_ui.fileRestartAction->setEnabled(bHasClient || m_pServer == NULL);
1840      ui.editAddChannelAction->setEnabled(bHasClient);          m_ui.editAddChannelAction->setEnabled(bHasClient);
1841      ui.editRemoveChannelAction->setEnabled(bHasChannel);          m_ui.editRemoveChannelAction->setEnabled(bHasChannel);
1842      ui.editSetupChannelAction->setEnabled(bHasChannel);          m_ui.editSetupChannelAction->setEnabled(bHasChannel);
1843  #ifdef CONFIG_EDIT_INSTRUMENT  #ifdef CONFIG_EDIT_INSTRUMENT
1844      ui.editEditChannelAction->setEnabled(bHasChannel);          m_ui.editEditChannelAction->setEnabled(bHasChannel);
1845  #else  #else
1846      ui.editEditChannelAction->setEnabled(false);          m_ui.editEditChannelAction->setEnabled(false);
1847  #endif  #endif
1848      ui.editResetChannelAction->setEnabled(bHasChannel);          m_ui.editResetChannelAction->setEnabled(bHasChannel);
1849      ui.editResetAllChannelsAction->setEnabled(bHasChannel);          m_ui.editResetAllChannelsAction->setEnabled(bHasChannel);
1850      ui.viewMessagesAction->setOn(m_pMessages && m_pMessages->isVisible());          m_ui.viewMessagesAction->setChecked(m_pMessages && m_pMessages->isVisible());
1851  #ifdef CONFIG_MIDI_INSTRUMENT  #ifdef CONFIG_MIDI_INSTRUMENT
1852          ui.viewInstrumentsAction->setOn(m_pInstrumentListForm          m_ui.viewInstrumentsAction->setChecked(m_pInstrumentListForm
1853                  && m_pInstrumentListForm->isVisible());                  && m_pInstrumentListForm->isVisible());
1854          ui.viewInstrumentsAction->setEnabled(bHasClient);          m_ui.viewInstrumentsAction->setEnabled(bHasClient);
1855  #else  #else
1856          ui.viewInstrumentsAction->setEnabled(false);          m_ui.viewInstrumentsAction->setEnabled(false);
1857  #endif  #endif
1858          ui.viewDevicesAction->setOn(m_pDeviceForm          m_ui.viewDevicesAction->setChecked(m_pDeviceForm
1859                  && m_pDeviceForm->isVisible());                  && m_pDeviceForm->isVisible());
1860      ui.viewDevicesAction->setEnabled(bHasClient);          m_ui.viewDevicesAction->setEnabled(bHasClient);
1861      ui.channelsArrangeAction->setEnabled(bHasChannel);          m_ui.channelsArrangeAction->setEnabled(bHasChannel);
1862    
1863  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
1864          // Toolbar widgets are also affected...          // Toolbar widgets are also affected...
1865      m_pVolumeSlider->setEnabled(bHasClient);          m_pVolumeSlider->setEnabled(bHasClient);
1866      m_pVolumeSpinBox->setEnabled(bHasClient);          m_pVolumeSpinBox->setEnabled(bHasClient);
1867  #endif  #endif
1868    
1869      // Client/Server status...          // Client/Server status...
1870      if (bHasClient) {          if (bHasClient) {
1871          m_statusItem[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));                  m_statusItem[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));
1872          m_statusItem[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost + ":" + QString::number(m_pOptions->iServerPort));                  m_statusItem[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost
1873      } else {                          + ':' + QString::number(m_pOptions->iServerPort));
1874          m_statusItem[QSAMPLER_STATUS_CLIENT]->clear();          } else {
1875          m_statusItem[QSAMPLER_STATUS_SERVER]->clear();                  m_statusItem[QSAMPLER_STATUS_CLIENT]->clear();
1876      }                  m_statusItem[QSAMPLER_STATUS_SERVER]->clear();
1877      // Channel status...          }
1878      if (bHasChannel)          // Channel status...
1879          m_statusItem[QSAMPLER_STATUS_CHANNEL]->setText(pChannelStrip->caption());          if (bHasChannel)
1880      else                  m_statusItem[QSAMPLER_STATUS_CHANNEL]->setText(pChannelStrip->windowTitle());
1881          m_statusItem[QSAMPLER_STATUS_CHANNEL]->clear();          else
1882      // Session status...                  m_statusItem[QSAMPLER_STATUS_CHANNEL]->clear();
1883      if (m_iDirtyCount > 0)          // Session status...
1884          m_statusItem[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));          if (m_iDirtyCount > 0)
1885      else                  m_statusItem[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));
1886          m_statusItem[QSAMPLER_STATUS_SESSION]->clear();          else
1887                    m_statusItem[QSAMPLER_STATUS_SESSION]->clear();
1888    
1889      // Recent files menu.          // Recent files menu.
1890      m_pRecentFilesMenu->setEnabled(bHasClient && m_pOptions->recentFiles.count() > 0);          m_ui.fileOpenRecentMenu->setEnabled(m_pOptions->recentFiles.count() > 0);
1891  }  }
1892    
1893    
# Line 1842  void MainForm::volumeChanged ( int iVolu Line 1927  void MainForm::volumeChanged ( int iVolu
1927  void MainForm::channelStripChanged(ChannelStrip* pChannelStrip)  void MainForm::channelStripChanged(ChannelStrip* pChannelStrip)
1928  {  {
1929          // Add this strip to the changed list...          // Add this strip to the changed list...
1930          if (m_changedStrips.containsRef(pChannelStrip) == 0) {          if (!m_changedStrips.contains(pChannelStrip)) {
1931                  m_changedStrips.append(pChannelStrip);                  m_changedStrips.append(pChannelStrip);
1932                  pChannelStrip->resetErrorCount();                  pChannelStrip->resetErrorCount();
1933          }          }
1934    
1935      // Just mark the dirty form.          // Just mark the dirty form.
1936      m_iDirtyCount++;          m_iDirtyCount++;
1937      // and update the form status...          // and update the form status...
1938      stabilizeForm();          stabilizeForm();
1939  }  }
1940    
1941    
# Line 1870  void MainForm::updateSession (void) Line 1955  void MainForm::updateSession (void)
1955          if (iMaps < 0)          if (iMaps < 0)
1956                  appendMessagesClient("lscp_get_midi_instrument_maps");                  appendMessagesClient("lscp_get_midi_instrument_maps");
1957          else if (iMaps < 1) {          else if (iMaps < 1) {
1958                  ::lscp_add_midi_instrument_map(m_pClient, tr("Chromatic").latin1());                  ::lscp_add_midi_instrument_map(m_pClient,
1959                  ::lscp_add_midi_instrument_map(m_pClient, tr("Drum Kits").latin1());                          tr("Chromatic").toUtf8().constData());
1960                    ::lscp_add_midi_instrument_map(m_pClient,
1961                            tr("Drum Kits").toUtf8().constData());
1962          }          }
1963  #endif  #endif
1964    
# Line 1880  void MainForm::updateSession (void) Line 1967  void MainForm::updateSession (void)
1967          if (piChannelIDs == NULL) {          if (piChannelIDs == NULL) {
1968                  if (::lscp_client_get_errno(m_pClient)) {                  if (::lscp_client_get_errno(m_pClient)) {
1969                          appendMessagesClient("lscp_list_channels");                          appendMessagesClient("lscp_list_channels");
1970                          appendMessagesError(tr("Could not get current list of channels.\n\nSorry."));                          appendMessagesError(
1971                                    tr("Could not get current list of channels.\n\nSorry."));
1972                  }                  }
1973          } else {          } else {
1974                  // Try to (re)create each channel.                  // Try to (re)create each channel.
# Line 1888  void MainForm::updateSession (void) Line 1976  void MainForm::updateSession (void)
1976                  for (int iChannel = 0; piChannelIDs[iChannel] >= 0; iChannel++) {                  for (int iChannel = 0; piChannelIDs[iChannel] >= 0; iChannel++) {
1977                          // Check if theres already a channel strip for this one...                          // Check if theres already a channel strip for this one...
1978                          if (!channelStrip(piChannelIDs[iChannel]))                          if (!channelStrip(piChannelIDs[iChannel]))
1979                                  createChannelStrip(new qsamplerChannel(piChannelIDs[iChannel]));                                  createChannelStrip(new Channel(piChannelIDs[iChannel]));
1980                  }                  }
1981                  m_pWorkspace->setUpdatesEnabled(true);                  m_pWorkspace->setUpdatesEnabled(true);
1982          }          }
1983    
1984      // Do we auto-arrange?          // Do we auto-arrange?
1985      if (m_pOptions && m_pOptions->bAutoArrange)          if (m_pOptions && m_pOptions->bAutoArrange)
1986          channelsArrange();                  channelsArrange();
1987    
1988          // Remember to refresh devices and instruments...          // Remember to refresh devices and instruments...
1989          if (m_pInstrumentListForm)          if (m_pInstrumentListForm)
1990              m_pInstrumentListForm->refreshInstruments();                  m_pInstrumentListForm->refreshInstruments();
1991          if (m_pDeviceForm)          if (m_pDeviceForm)
1992              m_pDeviceForm->refreshDevices();                  m_pDeviceForm->refreshDevices();
1993  }  }
1994    
1995    
1996  // Update the recent files list and menu.  // Update the recent files list and menu.
1997  void MainForm::updateRecentFiles ( const QString& sFilename )  void MainForm::updateRecentFiles ( const QString& sFilename )
1998  {  {
1999      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2000          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);  
2001    
2002      // May update the menu.          // Remove from list if already there (avoid duplicates)
2003      updateRecentFilesMenu();          int iIndex = m_pOptions->recentFiles.indexOf(sFilename);
2004            if (iIndex >= 0)
2005                    m_pOptions->recentFiles.removeAt(iIndex);
2006            // Put it to front...
2007            m_pOptions->recentFiles.push_front(sFilename);
2008  }  }
2009    
2010    
2011  // Update the recent files list and menu.  // Update the recent files list and menu.
2012  void MainForm::updateRecentFilesMenu (void)  void MainForm::updateRecentFilesMenu (void)
2013  {  {
2014      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2015          return;                  return;
2016    
2017      // Time to keep the list under limits.          // Time to keep the list under limits.
2018      int iRecentFiles = m_pOptions->recentFiles.count();          int iRecentFiles = m_pOptions->recentFiles.count();
2019      while (iRecentFiles > m_pOptions->iMaxRecentFiles) {          while (iRecentFiles > m_pOptions->iMaxRecentFiles) {
2020          m_pOptions->recentFiles.pop_back();                  m_pOptions->recentFiles.pop_back();
2021          iRecentFiles--;                  iRecentFiles--;
2022      }          }
2023    
2024      // rebuild the recent files menu...          // Rebuild the recent files menu...
2025      m_pRecentFilesMenu->clear();          m_ui.fileOpenRecentMenu->clear();
2026      for (int i = 0; i < iRecentFiles; i++) {          for (int i = 0; i < iRecentFiles; i++) {
2027          const QString& sFilename = m_pOptions->recentFiles[i];                  const QString& sFilename = m_pOptions->recentFiles[i];
2028          if (QFileInfo(sFilename).exists()) {                  if (QFileInfo(sFilename).exists()) {
2029              m_pRecentFilesMenu->insertItem(QString("&%1 %2")                          QAction *pAction = m_ui.fileOpenRecentMenu->addAction(
2030                  .arg(i + 1).arg(sessionName(sFilename)),                                  QString("&%1 %2").arg(i + 1).arg(sessionName(sFilename)),
2031                  this, SLOT(fileOpenRecent(int)), 0, i);                                  this, SLOT(fileOpenRecent()));
2032          }                          pAction->setData(i);
2033      }                  }
2034            }
2035  }  }
2036    
2037    
2038  // Force update of the channels instrument names mode.  // Force update of the channels instrument names mode.
2039  void MainForm::updateInstrumentNames (void)  void MainForm::updateInstrumentNames (void)
2040  {  {
2041      // Full channel list update...          // Full channel list update...
2042      QWidgetList wlist = m_pWorkspace->windowList();          QWidgetList wlist = m_pWorkspace->windowList();
2043      if (wlist.isEmpty())          if (wlist.isEmpty())
2044          return;                  return;
2045    
2046      m_pWorkspace->setUpdatesEnabled(false);          m_pWorkspace->setUpdatesEnabled(false);
2047      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
2048          ChannelStrip *pChannelStrip = (ChannelStrip *) wlist.at(iChannel);                  ChannelStrip *pChannelStrip = (ChannelStrip *) wlist.at(iChannel);
2049          if (pChannelStrip)                  if (pChannelStrip)
2050              pChannelStrip->updateInstrumentName(true);                          pChannelStrip->updateInstrumentName(true);
2051      }          }
2052      m_pWorkspace->setUpdatesEnabled(true);          m_pWorkspace->setUpdatesEnabled(true);
2053  }  }
2054    
2055    
2056  // Force update of the channels display font.  // Force update of the channels display font.
2057  void MainForm::updateDisplayFont (void)  void MainForm::updateDisplayFont (void)
2058  {  {
2059      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2060          return;                  return;
2061    
2062            // Check if display font is legal.
2063            if (m_pOptions->sDisplayFont.isEmpty())
2064                    return;
2065            // Realize it.
2066            QFont font;
2067            if (!font.fromString(m_pOptions->sDisplayFont))
2068                    return;
2069    
2070      // Check if display font is legal.          // Full channel list update...
2071      if (m_pOptions->sDisplayFont.isEmpty())          QWidgetList wlist = m_pWorkspace->windowList();
2072          return;          if (wlist.isEmpty())
2073      // Realize it.                  return;
2074      QFont font;  
2075      if (!font.fromString(m_pOptions->sDisplayFont))          m_pWorkspace->setUpdatesEnabled(false);
2076          return;          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
2077                    ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);
2078      // Full channel list update...                  if (pChannelStrip)
2079      QWidgetList wlist = m_pWorkspace->windowList();                          pChannelStrip->setDisplayFont(font);
2080      if (wlist.isEmpty())          }
2081          return;          m_pWorkspace->setUpdatesEnabled(true);
   
     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);  
2082  }  }
2083    
2084    
2085  // Update channel strips background effect.  // Update channel strips background effect.
2086  void MainForm::updateDisplayEffect (void)  void MainForm::updateDisplayEffect (void)
2087  {  {
2088     QPixmap pm;          // Full channel list update...
2089      if (m_pOptions->bDisplayEffect)          QWidgetList wlist = m_pWorkspace->windowList();
2090          pm = QPixmap(":/qsampler/pixmaps/displaybg1.png");          if (wlist.isEmpty())
2091                    return;
2092      // Full channel list update...  
2093      QWidgetList wlist = m_pWorkspace->windowList();          m_pWorkspace->setUpdatesEnabled(false);
2094      if (wlist.isEmpty())          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
2095          return;                  ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);
2096                    if (pChannelStrip)
2097      m_pWorkspace->setUpdatesEnabled(false);                          pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
2098      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          }
2099          ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);          m_pWorkspace->setUpdatesEnabled(true);
         if (pChannelStrip)  
             pChannelStrip->setDisplayBackground(pm);  
     }  
     m_pWorkspace->setUpdatesEnabled(true);  
2100  }  }
2101    
2102    
2103  // Force update of the channels maximum volume setting.  // Force update of the channels maximum volume setting.
2104  void MainForm::updateMaxVolume (void)  void MainForm::updateMaxVolume (void)
2105  {  {
2106      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2107          return;                  return;
2108    
2109  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
2110          m_iVolumeChanging++;          m_iVolumeChanging++;
2111          m_pVolumeSlider->setMaxValue(m_pOptions->iMaxVolume);          m_pVolumeSlider->setMaximum(m_pOptions->iMaxVolume);
2112          m_pVolumeSpinBox->setMaxValue(m_pOptions->iMaxVolume);          m_pVolumeSpinBox->setMaximum(m_pOptions->iMaxVolume);
2113          m_iVolumeChanging--;          m_iVolumeChanging--;
2114  #endif  #endif
2115    
2116      // Full channel list update...          // Full channel list update...
2117      QWidgetList wlist = m_pWorkspace->windowList();          QWidgetList wlist = m_pWorkspace->windowList();
2118      if (wlist.isEmpty())          if (wlist.isEmpty())
2119          return;                  return;
2120    
2121      m_pWorkspace->setUpdatesEnabled(false);          m_pWorkspace->setUpdatesEnabled(false);
2122      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
2123          ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);                  ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);
2124          if (pChannelStrip)                  if (pChannelStrip)
2125              pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);                          pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
2126      }          }
2127      m_pWorkspace->setUpdatesEnabled(true);          m_pWorkspace->setUpdatesEnabled(true);
2128  }  }
2129    
2130    
# Line 2052  void MainForm::updateMaxVolume (void) Line 2134  void MainForm::updateMaxVolume (void)
2134  // Messages output methods.  // Messages output methods.
2135  void MainForm::appendMessages( const QString& s )  void MainForm::appendMessages( const QString& s )
2136  {  {
2137      if (m_pMessages)          if (m_pMessages)
2138          m_pMessages->appendMessages(s);                  m_pMessages->appendMessages(s);
2139    
2140      statusBar()->message(s, 3000);          statusBar()->showMessage(s, 3000);
2141  }  }
2142    
2143  void MainForm::appendMessagesColor( const QString& s, const QString& c )  void MainForm::appendMessagesColor( const QString& s, const QString& c )
2144  {  {
2145      if (m_pMessages)          if (m_pMessages)
2146          m_pMessages->appendMessagesColor(s, c);                  m_pMessages->appendMessagesColor(s, c);
2147    
2148      statusBar()->message(s, 3000);          statusBar()->showMessage(s, 3000);
2149  }  }
2150    
2151  void MainForm::appendMessagesText( const QString& s )  void MainForm::appendMessagesText( const QString& s )
2152  {  {
2153      if (m_pMessages)          if (m_pMessages)
2154          m_pMessages->appendMessagesText(s);                  m_pMessages->appendMessagesText(s);
2155  }  }
2156    
2157  void MainForm::appendMessagesError( const QString& s )  void MainForm::appendMessagesError( const QString& s )
2158  {  {
2159      if (m_pMessages)          if (m_pMessages)
2160          m_pMessages->show();                  m_pMessages->show();
2161    
2162      appendMessagesColor(s.simplifyWhiteSpace(), "#ff0000");          appendMessagesColor(s.simplified(), "#ff0000");
2163    
2164          // Make it look responsive...:)          // Make it look responsive...:)
2165          QApplication::processEvents(QEventLoop::ExcludeUserInput);          QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2166    
2167      QMessageBox::critical(this,          QMessageBox::critical(this,
2168                  QSAMPLER_TITLE ": " + tr("Error"), s, tr("Cancel"));                  QSAMPLER_TITLE ": " + tr("Error"), s, tr("Cancel"));
2169  }  }
2170    
# Line 2090  void MainForm::appendMessagesError( cons Line 2172  void MainForm::appendMessagesError( cons
2172  // This is a special message format, just for client results.  // This is a special message format, just for client results.
2173  void MainForm::appendMessagesClient( const QString& s )  void MainForm::appendMessagesClient( const QString& s )
2174  {  {
2175      if (m_pClient == NULL)          if (m_pClient == NULL)
2176          return;                  return;
2177    
2178      appendMessagesColor(s + QString(": %1 (errno=%2)")          appendMessagesColor(s + QString(": %1 (errno=%2)")
2179          .arg(::lscp_client_get_result(m_pClient))                  .arg(::lscp_client_get_result(m_pClient))
2180          .arg(::lscp_client_get_errno(m_pClient)), "#996666");                  .arg(::lscp_client_get_errno(m_pClient)), "#996666");
2181    
2182          // Make it look responsive...:)          // Make it look responsive...:)
2183          QApplication::processEvents(QEventLoop::ExcludeUserInput);          QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2184  }  }
2185    
2186    
2187  // Force update of the messages font.  // Force update of the messages font.
2188  void MainForm::updateMessagesFont (void)  void MainForm::updateMessagesFont (void)
2189  {  {
2190      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2191          return;                  return;
2192    
2193      if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {          if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {
2194          QFont font;                  QFont font;
2195          if (font.fromString(m_pOptions->sMessagesFont))                  if (font.fromString(m_pOptions->sMessagesFont))
2196              m_pMessages->setMessagesFont(font);                          m_pMessages->setMessagesFont(font);
2197      }          }
2198  }  }
2199    
2200    
2201  // Update messages window line limit.  // Update messages window line limit.
2202  void MainForm::updateMessagesLimit (void)  void MainForm::updateMessagesLimit (void)
2203  {  {
2204      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2205          return;                  return;
2206    
2207      if (m_pMessages) {          if (m_pMessages) {
2208          if (m_pOptions->bMessagesLimit)                  if (m_pOptions->bMessagesLimit)
2209              m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);                          m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);
2210          else                  else
2211              m_pMessages->setMessagesLimit(-1);                          m_pMessages->setMessagesLimit(-1);
2212      }          }
2213  }  }
2214    
2215    
2216  // Enablement of the messages capture feature.  // Enablement of the messages capture feature.
2217  void MainForm::updateMessagesCapture (void)  void MainForm::updateMessagesCapture (void)
2218  {  {
2219      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2220          return;                  return;
2221    
2222      if (m_pMessages)          if (m_pMessages)
2223          m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);                  m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);
2224  }  }
2225    
2226    
# Line 2146  void MainForm::updateMessagesCapture (vo Line 2228  void MainForm::updateMessagesCapture (vo
2228  // qsamplerMainForm -- MDI channel strip management.  // qsamplerMainForm -- MDI channel strip management.
2229    
2230  // The channel strip creation executive.  // The channel strip creation executive.
2231  ChannelStrip* MainForm::createChannelStrip(qsamplerChannel* pChannel)  ChannelStrip* MainForm::createChannelStrip ( Channel *pChannel )
2232  {  {
2233      if (m_pClient == NULL || pChannel == NULL)          if (m_pClient == NULL || pChannel == NULL)
2234          return NULL;                  return NULL;
2235    
2236      // Prepare for auto-arrange?          // Add a new channel itema...
2237      ChannelStrip* pChannelStrip = NULL;          ChannelStrip *pChannelStrip = new ChannelStrip();
2238      int y = 0;          if (pChannelStrip == NULL)
2239      if (m_pOptions && m_pOptions->bAutoArrange) {                  return NULL;
2240          QWidgetList wlist = m_pWorkspace->windowList();  
2241          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          // Set some initial channel strip options...
2242              pChannelStrip = (ChannelStrip *) wlist.at(iChannel);          if (m_pOptions) {
2243                          if (pChannelStrip) {                  // Background display effect...
2244                          //  y += pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();                  pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
2245                                  y += pChannelStrip->parentWidget()->frameGeometry().height();                  // We'll need a display font.
2246                          }                  QFont font;
2247          }                  if (font.fromString(m_pOptions->sDisplayFont))
2248      }                          pChannelStrip->setDisplayFont(font);
2249                    // Maximum allowed volume setting.
2250                    pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
2251            }
2252    
2253            // Add it to workspace...
2254            m_pWorkspace->addWindow(pChannelStrip, Qt::FramelessWindowHint);
2255    
2256      // Add a new channel itema...          // Actual channel strip setup...
2257      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;  
2258    
     // Actual channel strip setup...  
     pChannelStrip->setup(pChannel);  
2259          QObject::connect(pChannelStrip,          QObject::connect(pChannelStrip,
2260                  SIGNAL(channelChanged(qsamplerChannelStrip *)),                  SIGNAL(channelChanged(ChannelStrip*)),
2261                  SLOT(channelStripChanged(qsamplerChannelStrip *)));                  SLOT(channelStripChanged(ChannelStrip*)));
2262      // Set some initial aesthetic options...  
2263      if (m_pOptions) {          // Now we show up us to the world.
2264          // 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);  
     }  
2265    
2266          // This is pretty new, so we'll watch for it closely.          // This is pretty new, so we'll watch for it closely.
2267          channelStripChanged(pChannelStrip);          channelStripChanged(pChannelStrip);
2268    
2269      // Return our successful reference...          // Return our successful reference...
2270      return pChannelStrip;          return pChannelStrip;
2271  }  }
2272    
2273    
2274  // Retrieve the active channel strip.  // Retrieve the active channel strip.
2275  ChannelStrip* MainForm::activeChannelStrip (void)  ChannelStrip* MainForm::activeChannelStrip (void)
2276  {  {
2277      return (ChannelStrip*) m_pWorkspace->activeWindow();          return static_cast<ChannelStrip *> (m_pWorkspace->activeWindow());
2278  }  }
2279    
2280    
2281  // Retrieve a channel strip by index.  // Retrieve a channel strip by index.
2282  ChannelStrip* MainForm::channelStripAt ( int iChannel )  ChannelStrip* MainForm::channelStripAt ( int iChannel )
2283  {  {
2284      QWidgetList wlist = m_pWorkspace->windowList();          QWidgetList wlist = m_pWorkspace->windowList();
2285      if (wlist.isEmpty())          if (wlist.isEmpty())
2286          return NULL;                  return NULL;
2287    
2288      return (ChannelStrip*) wlist.at(iChannel);          return static_cast<ChannelStrip *> (wlist.at(iChannel));
2289  }  }
2290    
2291    
# Line 2231  ChannelStrip* MainForm::channelStrip ( i Line 2297  ChannelStrip* MainForm::channelStrip ( i
2297                  return NULL;                  return NULL;
2298    
2299          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
2300                  ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);                  ChannelStrip* pChannelStrip
2301                            = static_cast<ChannelStrip*> (wlist.at(iChannel));
2302                  if (pChannelStrip) {                  if (pChannelStrip) {
2303                          qsamplerChannel *pChannel = pChannelStrip->channel();                          Channel *pChannel = pChannelStrip->channel();
2304                          if (pChannel && pChannel->channelID() == iChannelID)                          if (pChannel && pChannel->channelID() == iChannelID)
2305                                  return pChannelStrip;                                  return pChannelStrip;
2306                  }                  }
# Line 2247  ChannelStrip* MainForm::channelStrip ( i Line 2314  ChannelStrip* MainForm::channelStrip ( i
2314  // Construct the windows menu.  // Construct the windows menu.
2315  void MainForm::channelsMenuAboutToShow (void)  void MainForm::channelsMenuAboutToShow (void)
2316  {  {
2317      ui.channelsMenu->clear();          m_ui.channelsMenu->clear();
2318      ui.channelsArrangeAction->addTo(ui.channelsMenu);          m_ui.channelsMenu->addAction(m_ui.channelsArrangeAction);
2319      ui.channelsAutoArrangeAction->addTo(ui.channelsMenu);          m_ui.channelsMenu->addAction(m_ui.channelsAutoArrangeAction);
2320    
2321      QWidgetList wlist = m_pWorkspace->windowList();          QWidgetList wlist = m_pWorkspace->windowList();
2322      if (!wlist.isEmpty()) {          if (!wlist.isEmpty()) {
2323          ui.channelsMenu->insertSeparator();                  m_ui.channelsMenu->addSeparator();
2324          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {                  for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
2325              ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);                          ChannelStrip* pChannelStrip
2326              if (pChannelStrip) {                                  = static_cast<ChannelStrip*> (wlist.at(iChannel));
2327                  int iItemID = ui.channelsMenu->insertItem(pChannelStrip->caption(), this, SLOT(channelsMenuActivated(int)));                          if (pChannelStrip) {
2328                  ui.channelsMenu->setItemParameter(iItemID, iChannel);                                  QAction *pAction = m_ui.channelsMenu->addAction(
2329                  ui.channelsMenu->setItemChecked(iItemID, activeChannelStrip() == pChannelStrip);                                          pChannelStrip->windowTitle(),
2330              }                                          this, SLOT(channelsMenuActivated()));
2331          }                                  pAction->setCheckable(true);
2332      }                                  pAction->setChecked(activeChannelStrip() == pChannelStrip);
2333                                    pAction->setData(iChannel);
2334                            }
2335                    }
2336            }
2337  }  }
2338    
2339    
2340  // Windows menu activation slot  // Windows menu activation slot
2341  void MainForm::channelsMenuActivated ( int iChannel )  void MainForm::channelsMenuActivated (void)
2342  {  {
2343      ChannelStrip* pChannelStrip = channelStripAt(iChannel);          // Retrive channel index from action data...
2344      if (pChannelStrip)          QAction *pAction = qobject_cast<QAction *> (sender());
2345          pChannelStrip->showNormal();          if (pAction == NULL)
2346      pChannelStrip->setFocus();                  return;
2347    
2348            ChannelStrip* pChannelStrip = channelStripAt(pAction->data().toInt());
2349            if (pChannelStrip) {
2350                    pChannelStrip->showNormal();
2351                    pChannelStrip->setFocus();
2352            }
2353  }  }
2354    
2355    
# Line 2282  void MainForm::channelsMenuActivated ( i Line 2359  void MainForm::channelsMenuActivated ( i
2359  // Set the pseudo-timer delay schedule.  // Set the pseudo-timer delay schedule.
2360  void MainForm::startSchedule ( int iStartDelay )  void MainForm::startSchedule ( int iStartDelay )
2361  {  {
2362      m_iStartDelay  = 1 + (iStartDelay * 1000);          m_iStartDelay  = 1 + (iStartDelay * 1000);
2363      m_iTimerDelay  = 0;          m_iTimerDelay  = 0;
2364  }  }
2365    
2366  // Suspend the pseudo-timer delay schedule.  // Suspend the pseudo-timer delay schedule.
2367  void MainForm::stopSchedule (void)  void MainForm::stopSchedule (void)
2368  {  {
2369      m_iStartDelay  = 0;          m_iStartDelay  = 0;
2370      m_iTimerDelay  = 0;          m_iTimerDelay  = 0;
2371  }  }
2372    
2373  // Timer slot funtion.  // Timer slot funtion.
2374  void MainForm::timerSlot (void)  void MainForm::timerSlot (void)
2375  {  {
2376      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2377          return;                  return;
2378    
2379      // Is it the first shot on server start after a few delay?          // Is it the first shot on server start after a few delay?
2380      if (m_iTimerDelay < m_iStartDelay) {          if (m_iTimerDelay < m_iStartDelay) {
2381          m_iTimerDelay += QSAMPLER_TIMER_MSECS;                  m_iTimerDelay += QSAMPLER_TIMER_MSECS;
2382          if (m_iTimerDelay >= m_iStartDelay) {                  if (m_iTimerDelay >= m_iStartDelay) {
2383              // If we cannot start it now, maybe a lil'mo'later ;)                          // If we cannot start it now, maybe a lil'mo'later ;)
2384              if (!startClient()) {                          if (!startClient()) {
2385                  m_iStartDelay += m_iTimerDelay;                                  m_iStartDelay += m_iTimerDelay;
2386                  m_iTimerDelay  = 0;                                  m_iTimerDelay  = 0;
2387              }                          }
2388          }                  }
2389      }          }
2390    
2391          if (m_pClient) {          if (m_pClient) {
2392                  // Update the channel information for each pending strip...                  // Update the channel information for each pending strip...
2393                  if (m_changedStrips.count() > 0) {                  QListIterator<ChannelStrip *> iter(m_changedStrips);
2394                          for (ChannelStrip* pChannelStrip = m_changedStrips.first();                  while (iter.hasNext()) {
2395                                          pChannelStrip; pChannelStrip = m_changedStrips.next()) {                          ChannelStrip *pChannelStrip = iter.next();
2396                                  // If successfull, remove from pending list...                          // If successfull, remove from pending list...
2397                                  if (pChannelStrip->updateChannelInfo())                          if (pChannelStrip->updateChannelInfo()) {
2398                                          m_changedStrips.remove(pChannelStrip);                                  int iChannelStrip = m_changedStrips.indexOf(pChannelStrip);
2399                                    if (iChannelStrip >= 0)
2400                                            m_changedStrips.removeAt(iChannelStrip);
2401                          }                          }
2402                  }                  }
2403                  // Refresh each channel usage, on each period...                  // Refresh each channel usage, on each period...
# Line 2339  void MainForm::timerSlot (void) Line 2418  void MainForm::timerSlot (void)
2418                  }                  }
2419          }          }
2420    
2421      // Register the next timer slot.          // Register the next timer slot.
2422      QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));          QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
2423  }  }
2424    
2425    
# Line 2350  void MainForm::timerSlot (void) Line 2429  void MainForm::timerSlot (void)
2429  // Start linuxsampler server...  // Start linuxsampler server...
2430  void MainForm::startServer (void)  void MainForm::startServer (void)
2431  {  {
2432      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2433          return;                  return;
2434    
2435      // Aren't already a client, are we?          // Aren't already a client, are we?
2436      if (!m_pOptions->bServerStart || m_pClient)          if (!m_pOptions->bServerStart || m_pClient)
2437          return;                  return;
2438    
2439      // Is the server process instance still here?          // Is the server process instance still here?
2440      if (m_pServer) {          if (m_pServer) {
2441          switch (QMessageBox::warning(this,                  switch (QMessageBox::warning(this,
2442                          QSAMPLER_TITLE ": " + tr("Warning"),                          QSAMPLER_TITLE ": " + tr("Warning"),
2443              tr("Could not start the LinuxSampler server.\n\n"                          tr("Could not start the LinuxSampler server.\n\n"
2444                 "Maybe it ss already started."),                          "Maybe it is already started."),
2445              tr("Stop"), tr("Kill"), tr("Cancel"))) {                          tr("Stop"), tr("Kill"), tr("Cancel"))) {
2446            case 0:                  case 0:
2447              m_pServer->terminate();                          m_pServer->terminate();
2448              break;                          break;
2449            case 1:                  case 1:
2450              m_pServer->kill();                          m_pServer->kill();
2451              break;                          break;
2452          }                  }
2453          return;                  return;
2454      }          }
2455    
2456      // Reset our timer counters...          // Reset our timer counters...
2457      stopSchedule();          stopSchedule();
2458    
2459      // OK. Let's build the startup process...          // Verify we have something to start with...
2460      m_pServer = new QProcess(this);          if (m_pOptions->sServerCmdLine.isEmpty())
2461                    return;
2462      // Setup stdout/stderr capture...  
2463          //      if (m_pOptions->bStdoutCapture) {          // OK. Let's build the startup process...
2464                  //m_pServer->setProcessChannelMode(          m_pServer = new QProcess();
2465                  //      QProcess::StandardOutput);          bForceServerStop = true;
2466    
2467            // Setup stdout/stderr capture...
2468    //      if (m_pOptions->bStdoutCapture) {
2469    #if QT_VERSION >= 0x040200
2470                    m_pServer->setProcessChannelMode(QProcess::ForwardedChannels);
2471    #endif
2472                  QObject::connect(m_pServer,                  QObject::connect(m_pServer,
2473                          SIGNAL(readyReadStdout()),                          SIGNAL(readyReadStandardOutput()),
2474                          SLOT(readServerStdout()));                          SLOT(readServerStdout()));
2475                  QObject::connect(m_pServer,                  QObject::connect(m_pServer,
2476                          SIGNAL(readyReadStderr()),                          SIGNAL(readyReadStandardError()),
2477                          SLOT(readServerStdout()));                          SLOT(readServerStdout()));
2478          //      }  //      }
2479    
2480          // The unforgiveable signal communication...          // The unforgiveable signal communication...
2481          QObject::connect(m_pServer,          QObject::connect(m_pServer,
2482                  SIGNAL(processExited()),                  SIGNAL(finished(int, QProcess::ExitStatus)),
2483                  SLOT(processServerExit()));                  SLOT(processServerExit()));
2484    
2485      // Build process arguments...          // Build process arguments...
2486      QStringList serverCmdLine = QStringList::split(' ', m_pOptions->sServerCmdLine);          QStringList args = m_pOptions->sServerCmdLine.split(' ');
2487            QString sCommand = args[0];
2488      appendMessages(tr("Server is starting..."));          args.removeAt(0);
2489      appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");  
2490            appendMessages(tr("Server is starting..."));
2491            appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");
2492    
2493      const QString prog = (serverCmdLine.size() > 0) ? serverCmdLine[0] : QString();          // Go linuxsampler, go...
2494      const QStringList args = serverCmdLine.mid(1);          m_pServer->start(sCommand, args);
2495            if (!m_pServer->waitForStarted()) {
2496      // Go jack, go...                  appendMessagesError(tr("Could not start server.\n\nSorry."));
2497      m_pServer->start(prog, args);                  processServerExit();
2498      if (!m_pServer->waitForStarted()) {                  return;
2499          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()));  
2500    
2501      // Reset (yet again) the timer counters,          // Show startup results...
2502      // but this time is deferred as the user opted.          appendMessages(
2503      startSchedule(m_pOptions->iStartDelay);                  tr("Server was started with PID=%1.").arg((long) m_pServer->pid()));
2504      stabilizeForm();  
2505            // Reset (yet again) the timer counters,
2506            // but this time is deferred as the user opted.
2507            startSchedule(m_pOptions->iStartDelay);
2508            stabilizeForm();
2509  }  }
2510    
2511    
2512  // Stop linuxsampler server...  // Stop linuxsampler server...
2513  void MainForm::stopServer (void)  void MainForm::stopServer (bool bInteractive)
2514  {  {
2515      // Stop client code.          // Stop client code.
2516      stopClient();          stopClient();
2517    
2518      // And try to stop server.          if (m_pServer && bInteractive) {
2519      if (m_pServer) {                  if (QMessageBox::question(this,
2520          appendMessages(tr("Server is stopping..."));                          QSAMPLER_TITLE ": " + tr("The backend's fate ..."),
2521          if (m_pServer->state() == QProcess::Running)                          tr("You have the option to keep the sampler backend (LinuxSampler)\n"
2522              m_pServer->terminate();                          "running in the background. The sampler would continue to work\n"
2523       }                          "according to your current sampler session and you could alter the\n"
2524                            "sampler session at any time by relaunching QSampler.\n\n"
2525      // Give it some time to terminate gracefully and stabilize...                          "Do you want LinuxSampler to stop or to keep running in\n"
2526      QTime t;                          "the background?"),
2527      t.start();                          tr("Stop"), tr("Keep Running")) == 1)
2528      while (t.elapsed() < QSAMPLER_TIMER_MSECS)                  {
2529          QApplication::processEvents(QEventLoop::ExcludeUserInput);                          bForceServerStop = false;
2530                    }
2531            }
2532    
2533            // And try to stop server.
2534            if (m_pServer && bForceServerStop) {
2535                    appendMessages(tr("Server is stopping..."));
2536                    if (m_pServer->state() == QProcess::Running) {
2537    #if defined(WIN32)
2538                            // Try harder...
2539                            m_pServer->kill();
2540    #else
2541                            // Try softly...
2542                            m_pServer->terminate();
2543    #endif
2544                    }
2545            }       // Do final processing anyway.
2546            else processServerExit();
2547    
2548       // Do final processing anyway.          // Give it some time to terminate gracefully and stabilize...
2549       processServerExit();          QTime t;
2550            t.start();
2551            while (t.elapsed() < QSAMPLER_TIMER_MSECS)
2552                    QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2553  }  }
2554    
2555    
2556  // Stdout handler...  // Stdout handler...
2557  void MainForm::readServerStdout (void)  void MainForm::readServerStdout (void)
2558  {  {
2559      if (m_pMessages)          if (m_pMessages)
2560          m_pMessages->appendStdoutBuffer(m_pServer->readAllStandardOutput());                  m_pMessages->appendStdoutBuffer(m_pServer->readAllStandardOutput());
2561  }  }
2562    
2563    
2564  // Linuxsampler server cleanup.  // Linuxsampler server cleanup.
2565  void MainForm::processServerExit (void)  void MainForm::processServerExit (void)
2566  {  {
2567      // Force client code cleanup.          // Force client code cleanup.
2568      stopClient();          stopClient();
2569    
2570      // Flush anything that maybe pending...          // Flush anything that maybe pending...
2571      if (m_pMessages)          if (m_pMessages)
2572          m_pMessages->flushStdoutBuffer();                  m_pMessages->flushStdoutBuffer();
2573    
2574      if (m_pServer) {          if (m_pServer && bForceServerStop) {
2575          // Force final server shutdown...                  if (m_pServer->state() != QProcess::NotRunning) {
2576          appendMessages(tr("Server was stopped with exit status %1.").arg(m_pServer->exitStatus()));                          appendMessages(tr("Server is being forced..."));
2577          m_pServer->terminate();                          // Force final server shutdown...
2578          if (!m_pServer->waitForFinished(2000))                          m_pServer->kill();
2579              m_pServer->kill();                          // Give it some time to terminate gracefully and stabilize...
2580          // Destroy it.                          QTime t;
2581          delete m_pServer;                          t.start();
2582          m_pServer = NULL;                          while (t.elapsed() < QSAMPLER_TIMER_MSECS)
2583      }                                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2584                    }
2585                    // Force final server shutdown...
2586                    appendMessages(
2587                            tr("Server was stopped with exit status %1.")
2588                            .arg(m_pServer->exitStatus()));
2589                    delete m_pServer;
2590                    m_pServer = NULL;
2591            }
2592    
2593      // Again, make status visible stable.          // Again, make status visible stable.
2594      stabilizeForm();          stabilizeForm();
2595  }  }
2596    
2597    
# Line 2487  void MainForm::processServerExit (void) Line 2599  void MainForm::processServerExit (void)
2599  // qsamplerMainForm -- Client stuff.  // qsamplerMainForm -- Client stuff.
2600    
2601  // The LSCP client callback procedure.  // The LSCP client callback procedure.
2602  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*/,
2603            lscp_event_t event, const char *pchData, int cchData, void *pvData )
2604  {  {
2605      MainForm* pMainForm = (MainForm *) pvData;          MainForm* pMainForm = (MainForm *) pvData;
2606      if (pMainForm == NULL)          if (pMainForm == NULL)
2607          return LSCP_FAILED;                  return LSCP_FAILED;
2608    
2609      // ATTN: DO NOT EVER call any GUI code here,          // ATTN: DO NOT EVER call any GUI code here,
2610      // as this is run under some other thread context.          // as this is run under some other thread context.
2611      // A custom event must be posted here...          // A custom event must be posted here...
2612      QApplication::postEvent(pMainForm, new qsamplerCustomEvent(event, pchData, cchData));          QApplication::postEvent(pMainForm,
2613                    new CustomEvent(event, pchData, cchData));
2614    
2615      return LSCP_OK;          return LSCP_OK;
2616  }  }
2617    
2618    
2619  // Start our almighty client...  // Start our almighty client...
2620  bool MainForm::startClient (void)  bool MainForm::startClient (void)
2621  {  {
2622      // Have it a setup?          // Have it a setup?
2623      if (m_pOptions == NULL)          if (m_pOptions == NULL)
2624          return false;                  return false;
2625    
2626      // Aren't we already started, are we?          // Aren't we already started, are we?
2627      if (m_pClient)          if (m_pClient)
2628          return true;                  return true;
2629    
2630      // Log prepare here.          // Log prepare here.
2631      appendMessages(tr("Client connecting..."));          appendMessages(tr("Client connecting..."));
2632    
2633      // Create the client handle...          // Create the client handle...
2634      m_pClient = ::lscp_client_create(m_pOptions->sServerHost.latin1(), m_pOptions->iServerPort, qsampler_client_callback, this);          m_pClient = ::lscp_client_create(
2635      if (m_pClient == NULL) {                  m_pOptions->sServerHost.toUtf8().constData(),
2636          // Is this the first try?                  m_pOptions->iServerPort, qsampler_client_callback, this);
2637          // maybe we need to start a local server...          if (m_pClient == NULL) {
2638          if ((m_pServer && m_pServer->state() == QProcess::Running) || !m_pOptions->bServerStart)                  // Is this the first try?
2639              appendMessagesError(tr("Could not connect to server as client.\n\nSorry."));                  // maybe we need to start a local server...
2640          else                  if ((m_pServer && m_pServer->state() == QProcess::Running)
2641              startServer();                          || !m_pOptions->bServerStart) {
2642          // This is always a failure.                          appendMessagesError(
2643          stabilizeForm();                                  tr("Could not connect to server as client.\n\nSorry."));
2644          return false;                  } else {
2645      }                          startServer();
2646      // Just set receive timeout value, blindly.                  }
2647      ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);                  // This is always a failure.
2648      appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));                  stabilizeForm();
2649                    return false;
2650            }
2651            // Just set receive timeout value, blindly.
2652            ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);
2653            appendMessages(
2654                    tr("Client receive timeout is set to %1 msec.")
2655                    .arg(::lscp_client_get_timeout(m_pClient)));
2656    
2657          // Subscribe to channel info change notifications...          // Subscribe to channel info change notifications...
2658          if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO) != LSCP_OK)          if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO) != LSCP_OK)
2659                  appendMessagesClient("lscp_client_subscribe");                  appendMessagesClient("lscp_client_subscribe(CHANNEL_INFO)");
2660    
2661            DeviceStatusForm::onDevicesChanged(); // initialize
2662            updateViewMidiDeviceStatusMenu();
2663            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT) != LSCP_OK)
2664                    appendMessagesClient("lscp_client_subscribe(MIDI_INPUT_DEVICE_COUNT)");
2665            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_INFO) != LSCP_OK)
2666                    appendMessagesClient("lscp_client_subscribe(MIDI_INPUT_DEVICE_INFO)");
2667    
2668    #if CONFIG_LSCP_CHANNEL_MIDI
2669            // Subscribe to channel MIDI data notifications...
2670            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_MIDI) != LSCP_OK)
2671                    appendMessagesClient("lscp_client_subscribe(CHANNEL_MIDI)");
2672    #endif
2673    
2674    #if CONFIG_LSCP_DEVICE_MIDI
2675            // Subscribe to channel MIDI data notifications...
2676            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_DEVICE_MIDI) != LSCP_OK)
2677                    appendMessagesClient("lscp_client_subscribe(DEVICE_MIDI)");
2678    #endif
2679    
2680      // We may stop scheduling around.          // We may stop scheduling around.
2681      stopSchedule();          stopSchedule();
2682    
2683      // We'll accept drops from now on...          // We'll accept drops from now on...
2684      setAcceptDrops(true);          setAcceptDrops(true);
2685    
2686      // Log success here.          // Log success here.
2687      appendMessages(tr("Client connected."));          appendMessages(tr("Client connected."));
2688    
2689          // Hard-notify instrumnet and device configuration forms,          // Hard-notify instrumnet and device configuration forms,
2690          // if visible, that we're ready...          // if visible, that we're ready...
2691          if (m_pInstrumentListForm)          if (m_pInstrumentListForm)
2692              m_pInstrumentListForm->refreshInstruments();                  m_pInstrumentListForm->refreshInstruments();
2693          if (m_pDeviceForm)          if (m_pDeviceForm)
2694              m_pDeviceForm->refreshDevices();                  m_pDeviceForm->refreshDevices();
2695    
2696      // Is any session pending to be loaded?          // Is any session pending to be loaded?
2697      if (!m_pOptions->sSessionFile.isEmpty()) {          if (!m_pOptions->sSessionFile.isEmpty()) {
2698          // Just load the prabably startup session...                  // Just load the prabably startup session...
2699          if (loadSessionFile(m_pOptions->sSessionFile)) {                  if (loadSessionFile(m_pOptions->sSessionFile)) {
2700              m_pOptions->sSessionFile = QString::null;                          m_pOptions->sSessionFile = QString::null;
2701              return true;                          return true;
2702          }                  }
2703      }          }
2704    
2705      // Make a new session          // Make a new session
2706      return newSession();          return newSession();
2707  }  }
2708    
2709    
2710  // Stop client...  // Stop client...
2711  void MainForm::stopClient (void)  void MainForm::stopClient (void)
2712  {  {
2713      if (m_pClient == NULL)          if (m_pClient == NULL)
2714          return;                  return;
   
     // Log prepare here.  
     appendMessages(tr("Client disconnecting..."));  
2715    
2716      // Clear timer counters...          // Log prepare here.
2717      stopSchedule();          appendMessages(tr("Client disconnecting..."));
2718    
2719      // We'll reject drops from now on...          // Clear timer counters...
2720      setAcceptDrops(false);          stopSchedule();
2721    
2722      // Force any channel strips around, but          // We'll reject drops from now on...
2723      // but avoid removing the corresponding          setAcceptDrops(false);
     // channels from the back-end server.  
     m_iDirtyCount = 0;  
     closeSession(false);  
2724    
2725      // Close us as a client...          // Force any channel strips around, but
2726            // but avoid removing the corresponding
2727            // channels from the back-end server.
2728            m_iDirtyCount = 0;
2729            closeSession(false);
2730    
2731            // Close us as a client...
2732    #if CONFIG_LSCP_DEVICE_MIDI
2733            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_DEVICE_MIDI);
2734    #endif
2735    #if CONFIG_LSCP_CHANNEL_MIDI
2736            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_MIDI);
2737    #endif
2738            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_INFO);
2739            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT);
2740          ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO);          ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO);
2741      ::lscp_client_destroy(m_pClient);          ::lscp_client_destroy(m_pClient);
2742      m_pClient = NULL;          m_pClient = NULL;
2743    
2744          // Hard-notify instrumnet and device configuration forms,          // Hard-notify instrumnet and device configuration forms,
2745          // if visible, that we're running out...          // if visible, that we're running out...
2746          if (m_pInstrumentListForm)          if (m_pInstrumentListForm)
2747              m_pInstrumentListForm->refreshInstruments();                  m_pInstrumentListForm->refreshInstruments();
2748          if (m_pDeviceForm)          if (m_pDeviceForm)
2749              m_pDeviceForm->refreshDevices();                  m_pDeviceForm->refreshDevices();
2750    
2751            // Log final here.
2752            appendMessages(tr("Client disconnected."));
2753    
2754            // Make visible status.
2755            stabilizeForm();
2756    }
2757    
2758    
2759      // Log final here.  // Channel strip activation/selection.
2760      appendMessages(tr("Client disconnected."));  void MainForm::activateStrip ( QWidget *pWidget )
2761    {
2762            ChannelStrip *pChannelStrip
2763                    = static_cast<ChannelStrip *> (pWidget);
2764            if (pChannelStrip)
2765                    pChannelStrip->setSelected(true);
2766    
2767      // Make visible status.          stabilizeForm();
     stabilizeForm();  
2768  }  }
2769    
2770    
2771  } // namespace QSampler  } // namespace QSampler
2772    
2773    

Legend:
Removed from v.1466  
changed lines
  Added in v.1699

  ViewVC Help
Powered by ViewVC