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

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

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

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

Legend:
Removed from v.1470  
changed lines
  Added in v.3437

  ViewVC Help
Powered by ViewVC