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

Legend:
Removed from v.1475  
changed lines
  Added in v.1698

  ViewVC Help
Powered by ViewVC