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

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

  ViewVC Help
Powered by ViewVC