/[svn]/qsampler/trunk/src/qsamplerMainForm.ui.h
ViewVC logotype

Diff of /qsampler/trunk/src/qsamplerMainForm.ui.h

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

revision 463 by capela, Tue Mar 15 15:32:29 2005 UTC revision 1025 by capela, Fri Jan 12 21:21:16 2007 UTC
# Line 2  Line 2 
2  //  //
3  // ui.h extension file, included from the uic-generated form implementation.  // ui.h extension file, included from the uic-generated form implementation.
4  /****************************************************************************  /****************************************************************************
5     Copyright (C) 2004-2005, rncbc aka Rui Nuno Capela. All rights reserved.     Copyright (C) 2004-2007, rncbc aka Rui Nuno Capela. All rights reserved.
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 14  Line 14 
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.     GNU General Public License for more details.
16    
17     You should have received a copy of the GNU General Public License     You should have received a copy of the GNU General Public License along
18     along with this program; if not, write to the Free Software     with this program; if not, write to the Free Software Foundation, Inc.,
19     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20    
21  *****************************************************************************/  *****************************************************************************/
22    
# Line 41  Line 41 
41  #include "qsamplerMessages.h"  #include "qsamplerMessages.h"
42    
43  #include "qsamplerChannelStrip.h"  #include "qsamplerChannelStrip.h"
44    #include "qsamplerInstrumentList.h"
45    
46    #include "qsamplerInstrumentListForm.h"
47  #include "qsamplerDeviceForm.h"  #include "qsamplerDeviceForm.h"
48  #include "qsamplerOptionsForm.h"  #include "qsamplerOptionsForm.h"
49    
 #include "config.h"  
   
50  #ifdef HAVE_SIGNAL_H  #ifdef HAVE_SIGNAL_H
51  #include <signal.h>  #include <signal.h>
52  #endif  #endif
53    
54    #ifdef CONFIG_LIBGIG
55    #include <gig.h>
56    #endif
57    
58  // Timer constant stuff.  // Timer constant stuff.
59  #define QSAMPLER_TIMER_MSECS    200  #define QSAMPLER_TIMER_MSECS    200
60    
# Line 100  private: Line 104  private:
104  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
105  // qsamplerMainForm -- Main window form implementation.  // qsamplerMainForm -- Main window form implementation.
106    
107    // Kind of singleton reference.
108    qsamplerMainForm *qsamplerMainForm::g_pMainForm = NULL;
109    
110    
111  // Kind of constructor.  // Kind of constructor.
112  void qsamplerMainForm::init (void)  void qsamplerMainForm::init (void)
113  {  {
114            // Pseudo-singleton reference setup.
115            g_pMainForm = this;
116    
117      // Initialize some pointer references.      // Initialize some pointer references.
118      m_pOptions = NULL;      m_pOptions = NULL;
119    
120      // All child forms are to be created later, not earlier than setup.      // All child forms are to be created later, not earlier than setup.
121      m_pMessages   = NULL;      m_pMessages = NULL;
122        m_pInstrumentListForm = NULL;
123      m_pDeviceForm = NULL;      m_pDeviceForm = NULL;
124    
125      // We'll start clean.      // We'll start clean.
# Line 130  void qsamplerMainForm::init (void) Line 142  void qsamplerMainForm::init (void)
142      // Make it an MDI workspace.      // Make it an MDI workspace.
143      m_pWorkspace = new QWorkspace(this);      m_pWorkspace = new QWorkspace(this);
144      m_pWorkspace->setScrollBarsEnabled(true);      m_pWorkspace->setScrollBarsEnabled(true);
145      // Set the activation connection.          // Set the activation connection.
146      QObject::connect(m_pWorkspace, SIGNAL(windowActivated(QWidget *)), this, SLOT(stabilizeForm()));          QObject::connect(m_pWorkspace,
147                    SIGNAL(windowActivated(QWidget *)),
148                    SLOT(stabilizeForm()));
149      // Make it shine :-)      // Make it shine :-)
150      setCentralWidget(m_pWorkspace);      setCentralWidget(m_pWorkspace);
151    
# Line 184  void qsamplerMainForm::destroy (void) Line 198  void qsamplerMainForm::destroy (void)
198      // Finally drop any widgets around...      // Finally drop any widgets around...
199      if (m_pDeviceForm)      if (m_pDeviceForm)
200          delete m_pDeviceForm;          delete m_pDeviceForm;
201        if (m_pInstrumentListForm)
202            delete m_pInstrumentListForm;
203      if (m_pMessages)      if (m_pMessages)
204          delete m_pMessages;          delete m_pMessages;
205      if (m_pWorkspace)      if (m_pWorkspace)
# Line 202  void qsamplerMainForm::destroy (void) Line 218  void qsamplerMainForm::destroy (void)
218      // Delete recentfiles menu.      // Delete recentfiles menu.
219      if (m_pRecentFilesMenu)      if (m_pRecentFilesMenu)
220          delete m_pRecentFilesMenu;          delete m_pRecentFilesMenu;
221    
222            // Pseudo-singleton reference shut-down.
223            g_pMainForm = NULL;
224  }  }
225    
226    
# Line 212  void qsamplerMainForm::setup ( qsamplerO Line 231  void qsamplerMainForm::setup ( qsamplerO
231      m_pOptions = pOptions;      m_pOptions = pOptions;
232    
233      // What style do we create these forms?      // What style do we create these forms?
234      WFlags wflags = Qt::WType_TopLevel;          Qt::WFlags wflags = Qt::WStyle_Customize
235                    | Qt::WStyle_NormalBorder
236                    | Qt::WStyle_Title
237                    | Qt::WStyle_SysMenu
238                    | Qt::WStyle_MinMax
239                    | Qt::WType_TopLevel;
240      if (m_pOptions->bKeepOnTop)      if (m_pOptions->bKeepOnTop)
241          wflags |= Qt::WStyle_Tool;          wflags |= Qt::WStyle_Tool;
242      // Some child forms are to be created right now.      // Some child forms are to be created right now.
243      m_pMessages = new qsamplerMessages(this);      m_pMessages = new qsamplerMessages(this);
244      m_pDeviceForm = new qsamplerDeviceForm(this, 0, wflags);      m_pDeviceForm = new qsamplerDeviceForm(this, 0, wflags);
245    #ifdef CONFIG_MIDI_INSTRUMENT
246        m_pInstrumentListForm = new qsamplerInstrumentListForm(this, 0, wflags);
247            QObject::connect(m_pInstrumentListForm->InstrumentList,
248                    SIGNAL(instrumentsChanged()),
249                    SLOT(sessionDirty()));
250    #else
251            viewInstrumentsAction->setEnabled(false);
252    #endif
253      // Set message defaults...      // Set message defaults...
254      updateMessagesFont();      updateMessagesFont();
255      updateMessagesLimit();      updateMessagesLimit();
256      updateMessagesCapture();      updateMessagesCapture();
257      // Set the visibility signal.      // Set the visibility signal.
258      QObject::connect(m_pMessages, SIGNAL(visibilityChanged(bool)), this, SLOT(stabilizeForm()));          QObject::connect(m_pMessages,
259                    SIGNAL(visibilityChanged(bool)),
260                    SLOT(stabilizeForm()));
261    
262      // Initial decorations toggle state.      // Initial decorations toggle state.
263      viewMenubarAction->setOn(m_pOptions->bMenubar);      viewMenubarAction->setOn(m_pOptions->bMenubar);
# Line 248  void qsamplerMainForm::setup ( qsamplerO Line 282  void qsamplerMainForm::setup ( qsamplerO
282      }      }
283      // Try to restore old window positioning and initial visibility.      // Try to restore old window positioning and initial visibility.
284      m_pOptions->loadWidgetGeometry(this);      m_pOptions->loadWidgetGeometry(this);
285        m_pOptions->loadWidgetGeometry(m_pInstrumentListForm);
286      m_pOptions->loadWidgetGeometry(m_pDeviceForm);      m_pOptions->loadWidgetGeometry(m_pDeviceForm);
287    
288      // Final startup stabilization...      // Final startup stabilization...
# Line 287  bool qsamplerMainForm::queryClose (void) Line 322  bool qsamplerMainForm::queryClose (void)
322              ostr << *this;              ostr << *this;
323              m_pOptions->settings().writeEntry("/Layout/DockWindows", sDockables);              m_pOptions->settings().writeEntry("/Layout/DockWindows", sDockables);
324              // And the children, and the main windows state,.              // And the children, and the main windows state,.
325                  m_pOptions->saveWidgetGeometry(m_pDeviceForm);                          m_pOptions->saveWidgetGeometry(m_pDeviceForm);
326              m_pOptions->saveWidgetGeometry(this);                          m_pOptions->saveWidgetGeometry(m_pInstrumentListForm);
327                  // Close popup widgets.                          m_pOptions->saveWidgetGeometry(this);
328                  if (m_pDeviceForm)                          // Close popup widgets.
329                      m_pDeviceForm->close();                          if (m_pInstrumentListForm)
330                                    m_pInstrumentListForm->close();
331                            if (m_pDeviceForm)
332                                    m_pDeviceForm->close();
333              // Stop client and/or server, gracefully.              // Stop client and/or server, gracefully.
334              stopServer();              stopServer();
335          }          }
# Line 344  void qsamplerMainForm::dropEvent ( QDrop Line 382  void qsamplerMainForm::dropEvent ( QDrop
382      if (!decodeDragFiles(pDropEvent, files))      if (!decodeDragFiles(pDropEvent, files))
383          return;          return;
384    
385      for (QStringList::Iterator iter = files.begin(); iter != files.end(); iter++) {          for (QStringList::Iterator iter = files.begin(); iter != files.end(); iter++) {
386                  const QString& sPath = *iter;                  const QString& sPath = *iter;
387                  if (qsamplerChannel::isInstrumentFile(sPath)) {                  if (qsamplerChannel::isInstrumentFile(sPath)) {
388                          // Try to create a new channel from instrument file...                          // Try to create a new channel from instrument file...
389                      qsamplerChannel *pChannel = new qsamplerChannel(this);                          qsamplerChannel *pChannel = new qsamplerChannel();
390                      if (pChannel == NULL)                          if (pChannel == NULL)
391                          return;                                  return;
392                          // Start setting the instrument filename...                          // Start setting the instrument filename...
393                          pChannel->setInstrument(sPath, 0);                          pChannel->setInstrument(sPath, 0);
394                      // Before we show it up, may be we'll                          // Before we show it up, may be we'll
395                      // better ask for some initial values?                          // better ask for some initial values?
396                      if (!pChannel->channelSetup(this)) {                          if (!pChannel->channelSetup(this)) {
397                          delete pChannel;                                  delete pChannel;
398                          return;                                  return;
399                      }                          }
400                      // Finally, give it to a new channel strip...                          // Finally, give it to a new channel strip...
401                          if (!createChannelStrip(pChannel)) {                          if (!createChannelStrip(pChannel)) {
402                          delete pChannel;                                  delete pChannel;
403                          return;                                  return;
404                          }                          }
405                      // Make that an overall update.                          // Make that an overall update.
406                      m_iDirtyCount++;                          m_iDirtyCount++;
407                      stabilizeForm();                          stabilizeForm();
408                  }   // Otherwise, load an usual session file (LSCP script)...                  }   // Otherwise, load an usual session file (LSCP script)...
409                  else if (closeSession(true))                  else if (closeSession(true)) {
410                          loadSessionFile(sPath);                          loadSessionFile(sPath);
411                            break;
412                    }
413                  // Make it look responsive...:)                  // Make it look responsive...:)
414                  QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);                  QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
415          }          }
# Line 382  void qsamplerMainForm::customEvent ( QCu Line 422  void qsamplerMainForm::customEvent ( QCu
422      // For the time being, just pump it to messages.      // For the time being, just pump it to messages.
423      if (pCustomEvent->type() == QSAMPLER_CUSTOM_EVENT) {      if (pCustomEvent->type() == QSAMPLER_CUSTOM_EVENT) {
424          qsamplerCustomEvent *pEvent = (qsamplerCustomEvent *) pCustomEvent;          qsamplerCustomEvent *pEvent = (qsamplerCustomEvent *) pCustomEvent;
425          appendMessagesColor(tr("Notify event: %1 data: %2")                  if (pEvent->event() == LSCP_EVENT_CHANNEL_INFO) {
426              .arg(::lscp_event_to_text(pEvent->event()))                          int iChannelID = pEvent->data().toInt();
427              .arg(pEvent->data()), "#996699");                          qsamplerChannelStrip *pChannelStrip = channelStrip(iChannelID);
428                            if (pChannelStrip)
429                                    channelStripChanged(pChannelStrip);
430                    } else {
431                            appendMessagesColor(tr("Notify event: %1 data: %2")
432                                    .arg(::lscp_event_to_text(pEvent->event()))
433                                    .arg(pEvent->data()), "#996699");
434                    }
435      }      }
436  }  }
437    
# Line 393  void qsamplerMainForm::customEvent ( QCu Line 440  void qsamplerMainForm::customEvent ( QCu
440  void qsamplerMainForm::contextMenuEvent( QContextMenuEvent *pEvent )  void qsamplerMainForm::contextMenuEvent( QContextMenuEvent *pEvent )
441  {  {
442      stabilizeForm();      stabilizeForm();
443        
444      editMenu->exec(pEvent->globalPos());      editMenu->exec(pEvent->globalPos());
445  }  }
446    
# Line 407  qsamplerOptions *qsamplerMainForm::optio Line 454  qsamplerOptions *qsamplerMainForm::optio
454      return m_pOptions;      return m_pOptions;
455  }  }
456    
457    
458  // The LSCP client descriptor property.  // The LSCP client descriptor property.
459  lscp_client_t *qsamplerMainForm::client (void)  lscp_client_t *qsamplerMainForm::client (void)
460  {  {
# Line 414  lscp_client_t *qsamplerMainForm::client Line 462  lscp_client_t *qsamplerMainForm::client
462  }  }
463    
464    
465    // The pseudo-singleton instance accessor.
466    qsamplerMainForm *qsamplerMainForm::getInstance (void)
467    {
468            return g_pMainForm;
469    }
470    
471    
472  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
473  // qsamplerMainForm -- Session file stuff.  // qsamplerMainForm -- Session file stuff.
474    
# Line 461  bool qsamplerMainForm::openSession (void Line 516  bool qsamplerMainForm::openSession (void
516    
517      // Ask for the filename to open...      // Ask for the filename to open...
518      QString sFilename = QFileDialog::getOpenFileName(      QString sFilename = QFileDialog::getOpenFileName(
519              m_pOptions->sSessionDir,                // Start here.                  m_pOptions->sSessionDir,                // Start here.
520              tr("LSCP Session files") + " (*.lscp)", // Filter (LSCP files)                  tr("LSCP Session files") + " (*.lscp)", // Filter (LSCP files)
521              this, 0,                                // Parent and name (none)                  this, 0,                                // Parent and name (none)
522              tr("Open Session")                      // Caption.                  QSAMPLER_TITLE ": " + tr("Open Session")        // Caption.
523      );      );
524    
525      // Have we cancelled?      // Have we cancelled?
# Line 495  bool qsamplerMainForm::saveSession ( boo Line 550  bool qsamplerMainForm::saveSession ( boo
550              sFilename = m_pOptions->sSessionDir;              sFilename = m_pOptions->sSessionDir;
551          // Prompt the guy...          // Prompt the guy...
552          sFilename = QFileDialog::getSaveFileName(          sFilename = QFileDialog::getSaveFileName(
553                  sFilename,                              // Start here.                          sFilename,                              // Start here.
554                  tr("LSCP Session files") + " (*.lscp)", // Filter (LSCP files)                          tr("LSCP Session files") + " (*.lscp)", // Filter (LSCP files)
555                  this, 0,                                // Parent and name (none)                          this, 0,                                // Parent and name (none)
556                  tr("Save Session")                      // Caption.                          QSAMPLER_TITLE ": " + tr("Save Session")        // Caption.
557          );          );
558          // Have we cancelled it?          // Have we cancelled it?
559          if (sFilename.isEmpty())          if (sFilename.isEmpty())
# Line 508  bool qsamplerMainForm::saveSession ( boo Line 563  bool qsamplerMainForm::saveSession ( boo
563              sFilename += ".lscp";              sFilename += ".lscp";
564          // Check if already exists...          // Check if already exists...
565          if (sFilename != m_sFilename && QFileInfo(sFilename).exists()) {          if (sFilename != m_sFilename && QFileInfo(sFilename).exists()) {
566              if (QMessageBox::warning(this, tr("Warning"),              if (QMessageBox::warning(this,
567                                    QSAMPLER_TITLE ": " + tr("Warning"),
568                  tr("The file already exists:\n\n"                  tr("The file already exists:\n\n"
569                     "\"%1\"\n\n"                     "\"%1\"\n\n"
570                     "Do you want to replace it?")                     "Do you want to replace it?")
# Line 530  bool qsamplerMainForm::closeSession ( bo Line 586  bool qsamplerMainForm::closeSession ( bo
586    
587      // Are we dirty enough to prompt it?      // Are we dirty enough to prompt it?
588      if (m_iDirtyCount > 0) {      if (m_iDirtyCount > 0) {
589          switch (QMessageBox::warning(this, tr("Warning"),          switch (QMessageBox::warning(this,
590                            QSAMPLER_TITLE ": " + tr("Warning"),
591              tr("The current session has been changed:\n\n"              tr("The current session has been changed:\n\n"
592              "\"%1\"\n\n"              "\"%1\"\n\n"
593              "Do you want to save the changes?")              "Do you want to save the changes?")
# Line 583  bool qsamplerMainForm::loadSessionFile ( Line 640  bool qsamplerMainForm::loadSessionFile (
640          return false;          return false;
641      }      }
642    
643            // Tell the world we'll take some time...
644            QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
645    
646      // Read the file.      // Read the file.
647            int iLine = 0;
648      int iErrors = 0;      int iErrors = 0;
649      QTextStream ts(&file);      QTextStream ts(&file);
650      while (!ts.atEnd()) {      while (!ts.atEnd()) {
651          // Read the line.          // Read the line.
652          QString sCommand = ts.readLine().simplifyWhiteSpace();          QString sCommand = ts.readLine().stripWhiteSpace();
653                    iLine++;
654          // If not empty, nor a comment, call the server...          // If not empty, nor a comment, call the server...
655          if (!sCommand.isEmpty() && sCommand[0] != '#') {          if (!sCommand.isEmpty() && sCommand[0] != '#') {
656              appendMessagesColor(sCommand, "#996633");                          // Remember that, no matter what,
657              // Remember that, no matter what,                          // all LSCP commands are CR/LF terminated.
658              // all LSCP commands are CR/LF terminated.                          sCommand += "\r\n";
659              sCommand += "\r\n";                          if (::lscp_client_query(m_pClient, sCommand.latin1()) != LSCP_OK) {
660              if (::lscp_client_query(m_pClient, sCommand.latin1()) != LSCP_OK) {                                  appendMessagesColor(QString("%1(%2): %3")
661                  appendMessagesClient("lscp_client_query");                                          .arg(QFileInfo(sFilename).fileName()).arg(iLine)
662                  iErrors++;                                          .arg(sCommand.simplifyWhiteSpace()), "#996633");
663                  break;                                  appendMessagesClient("lscp_client_query");
664              }                                  iErrors++;
665                            }
666          }          }
667          // Try to make it snappy :)          // Try to make it snappy :)
668          QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);          QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
# Line 608  bool qsamplerMainForm::loadSessionFile ( Line 671  bool qsamplerMainForm::loadSessionFile (
671      // Ok. we've read it.      // Ok. we've read it.
672      file.close();      file.close();
673    
     // Have we any errors?  
     if (iErrors > 0)  
         appendMessagesError(tr("Session could not be loaded\nfrom \"%1\".\n\nSorry.").arg(sFilename));  
   
674          // Now we'll try to create (update) the whole GUI session.          // Now we'll try to create (update) the whole GUI session.
675          updateSession();          updateSession();
676    
677            // We're fornerly done.
678            QApplication::restoreOverrideCursor();
679    
680            // Have we any errors?
681            if (iErrors > 0)
682                    appendMessagesError(tr("Session loaded with errors\nfrom \"%1\".\n\nSorry.").arg(sFilename));
683    
684      // Save as default session directory.      // Save as default session directory.
685      if (m_pOptions)      if (m_pOptions)
686          m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);          m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);
687      // We're not dirty anymore.          // We're not dirty anymore, if loaded without errors,
688      m_iDirtyCount = 0;          m_iDirtyCount = iErrors;
689      // Stabilize form...      // Stabilize form...
690      m_sFilename = sFilename;      m_sFilename = sFilename;
691      updateRecentFiles(sFilename);      updateRecentFiles(sFilename);
692      appendMessages(tr("Open session: \"%1\".").arg(sessionName(m_sFilename)));      appendMessages(tr("Open session: \"%1\".").arg(sessionName(m_sFilename)));
693        
694      // Make that an overall update.      // Make that an overall update.
695      stabilizeForm();      stabilizeForm();
696      return true;      return true;
# Line 634  bool qsamplerMainForm::loadSessionFile ( Line 700  bool qsamplerMainForm::loadSessionFile (
700  // Save current session to specific file path.  // Save current session to specific file path.
701  bool qsamplerMainForm::saveSessionFile ( const QString& sFilename )  bool qsamplerMainForm::saveSessionFile ( const QString& sFilename )
702  {  {
703            if (m_pClient == NULL)
704                    return false;
705    
706            // Check whether server is apparently OK...
707            if (::lscp_get_channels(m_pClient) < 0) {
708                    appendMessagesClient("lscp_get_channels");
709                    return false;
710            }
711    
712      // Open and write into real file.      // Open and write into real file.
713      QFile file(sFilename);      QFile file(sFilename);
714      if (!file.open(IO_WriteOnly | IO_Truncate)) {      if (!file.open(IO_WriteOnly | IO_Truncate)) {
# Line 641  bool qsamplerMainForm::saveSessionFile ( Line 716  bool qsamplerMainForm::saveSessionFile (
716          return false;          return false;
717      }      }
718    
719            // Tell the world we'll take some time...
720            QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
721    
722      // Write the file.      // Write the file.
723      int  iErrors = 0;      int  iErrors = 0;
724      QTextStream ts(&file);      QTextStream ts(&file);
# Line 657  bool qsamplerMainForm::saveSessionFile ( Line 735  bool qsamplerMainForm::saveSessionFile (
735         << " "  << QTime::currentTime().toString("hh:mm:ss") << endl;         << " "  << QTime::currentTime().toString("hh:mm:ss") << endl;
736      ts << "#"  << endl;      ts << "#"  << endl;
737      ts << endl;      ts << endl;
738    
739          // It is assumed that this new kind of device+session file          // It is assumed that this new kind of device+session file
740          // will be loaded from a complete          // will be loaded from a complete initialized server...
741          int *piDeviceIDs;          int *piDeviceIDs;
742          int  iDevice;          int  iDevice;
743          ts << "RESET" << endl;          ts << "RESET" << endl;
744    
745          // Audio device mapping.          // Audio device mapping.
746          QMap<int, int> audioDeviceMap;          QMap<int, int> audioDeviceMap;
747          piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Audio);          piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Audio);
748          for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {          for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {
749                  ts << endl;                  ts << endl;
750                  qsamplerDevice device(m_pClient, qsamplerDevice::Audio, piDeviceIDs[iDevice]);                  qsamplerDevice device(qsamplerDevice::Audio, piDeviceIDs[iDevice]);
751                  // Audio device specification...                  // Audio device specification...
752          ts << "# " << device.deviceTypeName() << " " << device.driverName()                  ts << "# " << device.deviceTypeName() << " " << device.driverName()
753                     << " " << tr("Device") << " " << iDevice << endl;                          << " " << tr("Device") << " " << iDevice << endl;
754                  ts << "CREATE AUDIO_OUTPUT_DEVICE " << device.driverName();                  ts << "CREATE AUDIO_OUTPUT_DEVICE " << device.driverName();
755                  qsamplerDeviceParamMap::ConstIterator deviceParam;                  qsamplerDeviceParamMap::ConstIterator deviceParam;
756                  for (deviceParam = device.params().begin();                  for (deviceParam = device.params().begin();
757                                  deviceParam != device.params().end();                                  deviceParam != device.params().end();
758                                          ++deviceParam) {                                          ++deviceParam) {
759                          ts << " " << deviceParam.key()                          const qsamplerDeviceParam& param = deviceParam.data();
760                             << "='" << deviceParam.data().value << "'";                          if (param.value.isEmpty()) ts << "# ";
761                            ts << " " << deviceParam.key() << "='" << param.value << "'";
762                  }                  }
763                  ts << endl;                  ts << endl;
764                  // Audio channel parameters...                  // Audio channel parameters...
# Line 689  bool qsamplerMainForm::saveSessionFile ( Line 770  bool qsamplerMainForm::saveSessionFile (
770                          for (portParam = pPort->params().begin();                          for (portParam = pPort->params().begin();
771                                          portParam != pPort->params().end();                                          portParam != pPort->params().end();
772                                                  ++portParam) {                                                  ++portParam) {
773                                    const qsamplerDeviceParam& param = portParam.data();
774                                    if (param.fix || param.value.isEmpty()) ts << "# ";
775                                  ts << "SET AUDIO_OUTPUT_CHANNEL_PARAMETER " << iDevice                                  ts << "SET AUDIO_OUTPUT_CHANNEL_PARAMETER " << iDevice
776                                     << " " << iPort << " " << portParam.key()                                          << " " << iPort << " " << portParam.key()
777                                     << "='" << portParam.data().value << "'" << endl;                                          << "='" << param.value << "'" << endl;
778                          }                          }
779                  }                  }
780                  // Set device index/id mapping.                  // Audio device index/id mapping.
781                  audioDeviceMap[device.deviceID()] = iDevice;                  audioDeviceMap[device.deviceID()] = iDevice;
782          // Try to keep it snappy :)                  // Try to keep it snappy :)
783          QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);                  QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
784          }          }
785    
786          // MIDI device mapping.          // MIDI device mapping.
787          QMap<int, int> midiDeviceMap;          QMap<int, int> midiDeviceMap;
788          piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Midi);          piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Midi);
789          for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {          for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {
790                  ts << endl;                  ts << endl;
791                  qsamplerDevice device(m_pClient, qsamplerDevice::Midi, piDeviceIDs[iDevice]);                  qsamplerDevice device(qsamplerDevice::Midi, piDeviceIDs[iDevice]);
792                  // MIDI device specification...                  // MIDI device specification...
793          ts << "# " << device.deviceTypeName() << " " << device.driverName()                  ts << "# " << device.deviceTypeName() << " " << device.driverName()
794                     << " " << tr("Device") << " " << iDevice << endl;                          << " " << tr("Device") << " " << iDevice << endl;
795                  ts << "CREATE MIDI_INPUT_DEVICE " << device.driverName();                  ts << "CREATE MIDI_INPUT_DEVICE " << device.driverName();
796                  qsamplerDeviceParamMap::ConstIterator deviceParam;                  qsamplerDeviceParamMap::ConstIterator deviceParam;
797                  for (deviceParam = device.params().begin();                  for (deviceParam = device.params().begin();
798                                  deviceParam != device.params().end();                                  deviceParam != device.params().end();
799                                          ++deviceParam) {                                          ++deviceParam) {
800                          ts << " " << deviceParam.key()                          const qsamplerDeviceParam& param = deviceParam.data();
801                             << "='" << deviceParam.data().value << "'";                          if (param.value.isEmpty()) ts << "# ";
802                            ts << " " << deviceParam.key() << "='" << param.value << "'";
803                  }                  }
804                  ts << endl;                  ts << endl;
805                  // MIDI port parameters...                  // MIDI port parameters...
# Line 726  bool qsamplerMainForm::saveSessionFile ( Line 811  bool qsamplerMainForm::saveSessionFile (
811                          for (portParam = pPort->params().begin();                          for (portParam = pPort->params().begin();
812                                          portParam != pPort->params().end();                                          portParam != pPort->params().end();
813                                                  ++portParam) {                                                  ++portParam) {
814                                    const qsamplerDeviceParam& param = portParam.data();
815                                    if (param.fix || param.value.isEmpty()) ts << "# ";
816                                  ts << "SET MIDI_INPUT_PORT_PARAMETER " << iDevice                                  ts << "SET MIDI_INPUT_PORT_PARAMETER " << iDevice
817                                     << " " << iPort << " " << portParam.key()                                     << " " << iPort << " " << portParam.key()
818                                     << "='" << portParam.data().value << "'" << endl;                                     << "='" << param.value << "'" << endl;
819                          }                          }
820                  }                  }
821                    // MIDI device index/id mapping.
822                    midiDeviceMap[device.deviceID()] = iDevice;
823                    // Try to keep it snappy :)
824                    QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
825          }          }
826          ts << endl;          ts << endl;
827    
828    #ifdef CONFIG_MIDI_INSTRUMENT
829            // MIDI instrument mapping...
830            QMap<int, int> midiInstrumentMap;
831            int *piMaps = ::lscp_list_midi_instrument_maps(m_pClient);
832            for (int iMap = 0; piMaps && piMaps[iMap] >= 0; iMap++) {
833                    int iMidiMap = piMaps[iMap];
834                    const char *pszMapName
835                            = ::lscp_get_midi_instrument_map_name(m_pClient, iMidiMap);
836                    ts << "# " << tr("MIDI instrument map") << " " << iMap;
837                    if (pszMapName)
838                            ts << " - " << pszMapName;
839                    ts << endl;
840                    ts << "ADD MIDI_INSTRUMENT_MAP";
841                    if (pszMapName)
842                            ts << " '" << pszMapName << "'";
843                    ts << endl;
844                    // MIDI instrument mapping...
845                    lscp_midi_instrument_t *pInstrs
846                            = ::lscp_list_midi_instruments(m_pClient, iMidiMap);
847                    for (int iInstr = 0; pInstrs && pInstrs[iInstr].map >= 0; iInstr++) {
848                            lscp_midi_instrument_info_t *pInstrInfo
849                                    = ::lscp_get_midi_instrument_info(m_pClient, &pInstrs[iInstr]);
850                            if (pInstrInfo) {
851                                    ts << "MAP MIDI_INSTRUMENT "
852                                            << iMap                        << " "
853                                            << pInstrs[iInstr].bank        << " "
854                                            << pInstrs[iInstr].prog        << " "
855                                            << pInstrInfo->engine_name     << " '"
856                                            << pInstrInfo->instrument_file << "' "
857                                            << pInstrInfo->instrument_nr   << " "
858                                            << pInstrInfo->volume          << " ";
859                                    switch (pInstrInfo->load_mode) {
860                                            case LSCP_LOAD_PERSISTENT:
861                                                    ts << "PERSISTENT";
862                                                    break;
863                                            case LSCP_LOAD_ON_DEMAND_HOLD:
864                                                    ts << "ON_DEMAND_HOLD";
865                                                    break;
866                                            case LSCP_LOAD_ON_DEMAND:
867                                            case LSCP_LOAD_DEFAULT:
868                                            default:
869                                                    ts << "ON_DEMAND";
870                                                    break;
871                                    }
872                                    if (pInstrInfo->name)
873                                            ts << " '" << pInstrInfo->name << "'";
874                                    ts << endl;
875                            }       // Check for errors...
876                            else if (::lscp_client_get_errno(m_pClient)) {
877                                    appendMessagesClient("lscp_get_midi_instrument_info");
878                                    iErrors++;
879                            }
880                            // Try to keep it snappy :)
881                            QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
882                    }
883                    ts << endl;
884                    // Check for errors...
885                    if (pInstrs == NULL && ::lscp_client_get_errno(m_pClient)) {
886                            appendMessagesClient("lscp_list_midi_instruments");
887                            iErrors++;
888                    }
889                    // MIDI strument index/id mapping.
890                    midiInstrumentMap[iMidiMap] = iMap;
891            }
892            // Check for errors...
893            if (piMaps == NULL && ::lscp_client_get_errno(m_pClient)) {
894                    appendMessagesClient("lscp_list_midi_instrument_maps");
895                    iErrors++;
896            }
897    #endif  // CONFIG_MIDI_INSTRUMENT
898    
899          // Sampler channel mapping.          // Sampler channel mapping.
900      QWidgetList wlist = m_pWorkspace->windowList();      QWidgetList wlist = m_pWorkspace->windowList();
901      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
902          qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);          qsamplerChannelStrip *pChannelStrip
903                            = static_cast<qsamplerChannelStrip *> (wlist.at(iChannel));
904          if (pChannelStrip) {          if (pChannelStrip) {
905              qsamplerChannel *pChannel = pChannelStrip->channel();              qsamplerChannel *pChannel = pChannelStrip->channel();
906              if (pChannel) {              if (pChannel) {
907                  ts << "# " << tr("Channel") << " " << iChannel << endl;                  ts << "# " << tr("Channel") << " " << iChannel << endl;
908                  ts << "ADD CHANNEL" << endl;                  ts << "ADD CHANNEL" << endl;
909                  if (audioDeviceMap.isEmpty()) {                                  if (audioDeviceMap.isEmpty()) {
910                          ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannel                                          ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannel
911                                              << " " << pChannel->audioDriver() << endl;                                                  << " " << pChannel->audioDriver() << endl;
912                              } else {                                  } else {
913                          ts << "SET CHANNEL AUDIO_OUTPUT_DEVICE " << iChannel                                          ts << "SET CHANNEL AUDIO_OUTPUT_DEVICE " << iChannel
914                                             << " " << audioDeviceMap[pChannel->audioDevice()] << endl;                                                  << " " << audioDeviceMap[pChannel->audioDevice()] << endl;
915                                    }
916                                    if (midiDeviceMap.isEmpty()) {
917                                            ts << "SET CHANNEL MIDI_INPUT_TYPE " << iChannel
918                                                    << " " << pChannel->midiDriver() << endl;
919                                    } else {
920                                            ts << "SET CHANNEL MIDI_INPUT_DEVICE " << iChannel
921                                                    << " " << midiDeviceMap[pChannel->midiDevice()] << endl;
922                                  }                                  }
923                  if (midiDeviceMap.isEmpty()) {                                  ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannel
924                          ts << "SET CHANNEL MIDI_INPUT_TYPE " << iChannel                                          << " " << pChannel->midiPort() << endl;
                                        << " " << pChannel->midiDriver() << endl;  
                             } else {  
                         ts << "SET CHANNEL MIDI_INPUT_DEVICE " << iChannel  
                                            << " " << midiDeviceMap[pChannel->midiDevice()] << endl;  
                             }  
                 ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannel  
                                << " " << pChannel->midiPort() << endl;  
925                  ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannel << " ";                  ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannel << " ";
926                  if (pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL)                  if (pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL)
927                      ts << "ALL";                      ts << "ALL";
# Line 765  bool qsamplerMainForm::saveSessionFile ( Line 929  bool qsamplerMainForm::saveSessionFile (
929                      ts << pChannel->midiChannel();                      ts << pChannel->midiChannel();
930                  ts << endl;                  ts << endl;
931                  ts << "LOAD ENGINE " << pChannel->engineName() << " " << iChannel << endl;                  ts << "LOAD ENGINE " << pChannel->engineName() << " " << iChannel << endl;
932                  ts << "LOAD INSTRUMENT NON_MODAL '" << pChannel->instrumentFile() << "' " << pChannel->instrumentNr() << " " << iChannel << endl;                                  if (pChannel->instrumentStatus() < 100) ts << "# ";
933                  ts << "SET CHANNEL VOLUME " << iChannel << " " << pChannel->volume() << endl;                                  ts << "LOAD INSTRUMENT NON_MODAL '" << pChannel->instrumentFile() << "' "
934                                            << pChannel->instrumentNr() << " " << iChannel << endl;
935                                    qsamplerChannelRoutingMap::ConstIterator audioRoute;
936                                    for (audioRoute = pChannel->audioRouting().begin();
937                                                    audioRoute != pChannel->audioRouting().end();
938                                                            ++audioRoute) {
939                                            ts << "SET CHANNEL AUDIO_OUTPUT_CHANNEL " << iChannel
940                                                    << " " << audioRoute.key()
941                                                    << " " << audioRoute.data() << endl;
942                                    }
943                                    ts << "SET CHANNEL VOLUME " << iChannel
944                                            << " " << pChannel->volume() << endl;
945                                    if (pChannel->channelMute())
946                                            ts << "SET CHANNEL MUTE " << iChannel << " 1" << endl;
947                                    if (pChannel->channelSolo())
948                                            ts << "SET CHANNEL SOLO " << iChannel << " 1" << endl;
949    #ifdef CONFIG_MIDI_INSTRUMENT
950                                    if (pChannel->midiMap() >= 0) {
951                                            ts << "SET CHANNEL MIDI_INSTRUMENT_MAP " << iChannel
952                                                    << " " << midiInstrumentMap[pChannel->midiMap()] << endl;
953                                    }
954    #endif
955    #ifdef CONFIG_FXSEND
956                                    int iChannelID = pChannel->channelID();
957                                    int *piFxSends = ::lscp_list_fxsends(m_pClient, iChannelID);
958                                    for (int iFxSend = 0;
959                                                    piFxSends && piFxSends[iFxSend] >= 0;
960                                                            iFxSend++) {
961                                            lscp_fxsend_info_t *pFxSendInfo = ::lscp_get_fxsend_info(
962                                                    m_pClient, iChannelID, piFxSends[iFxSend]);
963                                            if (pFxSendInfo) {
964                                                    ts << "CREATE FX_SEND " << iChannel
965                                                            << " " << pFxSendInfo->midi_controller;
966                                                    if (pFxSendInfo->name)
967                                                            ts << " '" << pFxSendInfo->name << "'";
968                                                    ts << endl;
969                                                    int *piRouting = pFxSendInfo->audio_routing;
970                                                    for (int iAudioSrc = 0;
971                                                                    piRouting && piRouting[iAudioSrc] >= 0;
972                                                                            iAudioSrc++) {
973                                                            ts << "SET FX_SEND AUDIO_OUTPUT_CHANNEL "
974                                                                    << iChannel
975                                                                    << " " << iFxSend
976                                                                    << " " << iAudioSrc
977                                                                    << " " << piRouting[iAudioSrc] << endl;
978                                                    }
979                                            }       // Check for errors...
980                                            else if (::lscp_client_get_errno(m_pClient)) {
981                                                    appendMessagesClient("lscp_get_fxsend_info");
982                                                    iErrors++;
983                                            }
984                                    }
985    #endif
986                  ts << endl;                  ts << endl;
987              }              }
988          }          }
# Line 777  bool qsamplerMainForm::saveSessionFile ( Line 993  bool qsamplerMainForm::saveSessionFile (
993      // Ok. we've wrote it.      // Ok. we've wrote it.
994      file.close();      file.close();
995    
996            // We're fornerly done.
997            QApplication::restoreOverrideCursor();
998    
999      // Have we any errors?      // Have we any errors?
1000      if (iErrors > 0)      if (iErrors > 0)
1001          appendMessagesError(tr("Some settings could not be saved\nto \"%1\" session file.\n\nSorry.").arg(sFilename));          appendMessagesError(tr("Some settings could not be saved\nto \"%1\" session file.\n\nSorry.").arg(sFilename));
# Line 858  void qsamplerMainForm::fileReset (void) Line 1077  void qsamplerMainForm::fileReset (void)
1077          return;          return;
1078    
1079      // Ask user whether he/she want's an internal sampler reset...      // Ask user whether he/she want's an internal sampler reset...
1080      if (QMessageBox::warning(this, tr("Warning"),      if (QMessageBox::warning(this,
1081                    QSAMPLER_TITLE ": " + tr("Warning"),
1082          tr("Resetting the sampler instance will close\n"          tr("Resetting the sampler instance will close\n"
1083             "all device and channel configurations.\n\n"             "all device and channel configurations.\n\n"
1084             "Please note that this operation may cause\n"             "Please note that this operation may cause\n"
1085             "temporary MIDI and Audio disruption\n\n"             "temporary MIDI and Audio disruption.\n\n"
1086             "Do you want to reset the sampler engine now?"),             "Do you want to reset the sampler engine now?"),
1087          tr("Reset"), tr("Cancel")) > 0)          tr("Reset"), tr("Cancel")) > 0)
1088          return;          return;
1089    
1090            // Trye closing the current session, first...
1091            if (!closeSession(true))
1092                    return;
1093    
1094      // Just do the reset, after closing down current session...      // Just do the reset, after closing down current session...
1095      if (closeSession(true) && ::lscp_reset_sampler(m_pClient) != LSCP_OK) {          // Do the actual sampler reset...
1096          appendMessagesClient("lscp_reset_sampler");          if (::lscp_reset_sampler(m_pClient) != LSCP_OK) {
1097          appendMessagesError(tr("Could not reset sampler instance.\n\nSorry."));                  appendMessagesClient("lscp_reset_sampler");
1098          return;                  appendMessagesError(tr("Could not reset sampler instance.\n\nSorry."));
1099      }                  return;
1100            }
1101    
1102      // Log this.      // Log this.
1103      appendMessages(tr("Sampler reset."));      appendMessages(tr("Sampler reset."));
# Line 887  void qsamplerMainForm::fileRestart (void Line 1112  void qsamplerMainForm::fileRestart (void
1112  {  {
1113      if (m_pOptions == NULL)      if (m_pOptions == NULL)
1114          return;          return;
1115            
1116      bool bRestart = true;      bool bRestart = true;
1117        
1118      // Ask user whether he/she want's a complete restart...      // Ask user whether he/she want's a complete restart...
1119      // (if we're currently up and running)      // (if we're currently up and running)
1120      if (bRestart && m_pClient) {      if (bRestart && m_pClient) {
1121          bRestart = (QMessageBox::warning(this, tr("Warning"),          bRestart = (QMessageBox::warning(this,
1122                            QSAMPLER_TITLE ": " + tr("Warning"),
1123              tr("New settings will be effective after\n"              tr("New settings will be effective after\n"
1124                 "restarting the client/server connection.\n\n"                 "restarting the client/server connection.\n\n"
1125                 "Please note that this operation may cause\n"                 "Please note that this operation may cause\n"
1126                 "temporary MIDI and Audio disruption\n\n"                 "temporary MIDI and Audio disruption.\n\n"
1127                 "Do you want to restart the connection now?"),                 "Do you want to restart the connection now?"),
1128              tr("Restart"), tr("Cancel")) == 0);              tr("Restart"), tr("Cancel")) == 0);
1129      }      }
# Line 930  void qsamplerMainForm::editAddChannel (v Line 1156  void qsamplerMainForm::editAddChannel (v
1156          return;          return;
1157    
1158      // Just create the channel instance...      // Just create the channel instance...
1159      qsamplerChannel *pChannel = new qsamplerChannel(this);      qsamplerChannel *pChannel = new qsamplerChannel();
1160      if (pChannel == NULL)      if (pChannel == NULL)
1161          return;          return;
1162    
# Line 940  void qsamplerMainForm::editAddChannel (v Line 1166  void qsamplerMainForm::editAddChannel (v
1166          delete pChannel;          delete pChannel;
1167          return;          return;
1168      }      }
1169        
1170      // And give it to the strip (will own the channel instance, if successful).      // And give it to the strip (will own the channel instance, if successful).
1171      if (!createChannelStrip(pChannel)) {      if (!createChannelStrip(pChannel)) {
1172          delete pChannel;          delete pChannel;
# Line 962  void qsamplerMainForm::editRemoveChannel Line 1188  void qsamplerMainForm::editRemoveChannel
1188      qsamplerChannelStrip *pChannelStrip = activeChannelStrip();      qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
1189      if (pChannelStrip == NULL)      if (pChannelStrip == NULL)
1190          return;          return;
1191            
1192      qsamplerChannel *pChannel = pChannelStrip->channel();      qsamplerChannel *pChannel = pChannelStrip->channel();
1193      if (pChannel == NULL)      if (pChannel == NULL)
1194          return;          return;
1195    
1196      // Prompt user if he/she's sure about this...      // Prompt user if he/she's sure about this...
1197      if (m_pOptions && m_pOptions->bConfirmRemove) {      if (m_pOptions && m_pOptions->bConfirmRemove) {
1198          if (QMessageBox::warning(this, tr("Warning"),          if (QMessageBox::warning(this,
1199                            QSAMPLER_TITLE ": " + tr("Warning"),
1200              tr("About to remove channel:\n\n"              tr("About to remove channel:\n\n"
1201                 "%1\n\n"                 "%1\n\n"
1202                 "Are you sure?")                 "Are you sure?")
# Line 984  void qsamplerMainForm::editRemoveChannel Line 1211  void qsamplerMainForm::editRemoveChannel
1211    
1212      // Just delete the channel strip.      // Just delete the channel strip.
1213      delete pChannelStrip;      delete pChannelStrip;
1214        
1215      // Do we auto-arrange?      // Do we auto-arrange?
1216      if (m_pOptions && m_pOptions->bAutoArrange)      if (m_pOptions && m_pOptions->bAutoArrange)
1217          channelsArrange();          channelsArrange();
# Line 1028  void qsamplerMainForm::editResetChannel Line 1255  void qsamplerMainForm::editResetChannel
1255  // Reset all sampler channels.  // Reset all sampler channels.
1256  void qsamplerMainForm::editResetAllChannels (void)  void qsamplerMainForm::editResetAllChannels (void)
1257  {  {
1258      if (m_pClient == NULL)          if (m_pClient == NULL)
1259          return;                  return;
1260    
1261      // Invoque the channel strip procedure,          // Invoque the channel strip procedure,
1262          // for all channels out there...          // for all channels out there...
1263      m_pWorkspace->setUpdatesEnabled(false);          m_pWorkspace->setUpdatesEnabled(false);
1264      QWidgetList wlist = m_pWorkspace->windowList();          QWidgetList wlist = m_pWorkspace->windowList();
1265      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1266          qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);                  qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1267          if (pChannelStrip)                  if (pChannelStrip)
1268                  pChannelStrip->channelReset();                          pChannelStrip->channelReset();
1269      }          }
1270      m_pWorkspace->setUpdatesEnabled(true);          m_pWorkspace->setUpdatesEnabled(true);
1271  }  }
1272    
1273    
# Line 1092  void qsamplerMainForm::viewMessages ( bo Line 1319  void qsamplerMainForm::viewMessages ( bo
1319  }  }
1320    
1321    
1322    // Show/hide the MIDI instrument list-view form.
1323    void qsamplerMainForm::viewInstruments (void)
1324    {
1325            if (m_pOptions == NULL)
1326                    return;
1327    
1328            if (m_pInstrumentListForm) {
1329                    m_pOptions->saveWidgetGeometry(m_pInstrumentListForm);
1330                    if (m_pInstrumentListForm->isVisible()) {
1331                            m_pInstrumentListForm->hide();
1332                    } else {
1333                            m_pInstrumentListForm->show();
1334                            m_pInstrumentListForm->raise();
1335                            m_pInstrumentListForm->setActiveWindow();
1336                    }
1337            }
1338    }
1339    
1340    
1341  // Show/hide the device configurator form.  // Show/hide the device configurator form.
1342  void qsamplerMainForm::viewDevices (void)  void qsamplerMainForm::viewDevices (void)
1343  {  {
1344      if (m_pOptions == NULL)          if (m_pOptions == NULL)
1345          return;                  return;
1346    
1347      if (m_pDeviceForm) {          if (m_pDeviceForm) {
1348          m_pOptions->saveWidgetGeometry(m_pDeviceForm);                  m_pOptions->saveWidgetGeometry(m_pDeviceForm);
1349                  m_pDeviceForm->setClient(m_pClient);                  if (m_pDeviceForm->isVisible()) {
1350          if (m_pDeviceForm->isVisible()) {                          m_pDeviceForm->hide();
1351              m_pDeviceForm->hide();                  } else {
1352          } else {                          m_pDeviceForm->show();
1353              m_pDeviceForm->show();                          m_pDeviceForm->raise();
1354              m_pDeviceForm->raise();                          m_pDeviceForm->setActiveWindow();
1355              m_pDeviceForm->setActiveWindow();                  }
1356          }          }
     }  
1357  }  }
1358    
1359    
# Line 1152  void qsamplerMainForm::viewOptions (void Line 1397  void qsamplerMainForm::viewOptions (void
1397                  (!bOldStdoutCapture &&  m_pOptions->bStdoutCapture) ||                  (!bOldStdoutCapture &&  m_pOptions->bStdoutCapture) ||
1398                  ( bOldKeepOnTop     && !m_pOptions->bKeepOnTop)     ||                  ( bOldKeepOnTop     && !m_pOptions->bKeepOnTop)     ||
1399                  (!bOldKeepOnTop     &&  m_pOptions->bKeepOnTop)) {                  (!bOldKeepOnTop     &&  m_pOptions->bKeepOnTop)) {
1400                  QMessageBox::information(this, tr("Information"),                  QMessageBox::information(this,
1401                                            QSAMPLER_TITLE ": " + tr("Information"),
1402                      tr("Some settings may be only effective\n"                      tr("Some settings may be only effective\n"
1403                         "next time you start this program."), tr("OK"));                         "next time you start this program."), tr("OK"));
1404                  updateMessagesCapture();                  updateMessagesCapture();
# Line 1226  void qsamplerMainForm::channelsArrange ( Line 1472  void qsamplerMainForm::channelsArrange (
1472          y += iHeight;          y += iHeight;
1473      }      }
1474      m_pWorkspace->setUpdatesEnabled(true);      m_pWorkspace->setUpdatesEnabled(true);
1475        
1476      stabilizeForm();      stabilizeForm();
1477  }  }
1478    
# Line 1280  void qsamplerMainForm::helpAbout (void) Line 1526  void qsamplerMainForm::helpAbout (void)
1526      sText += tr("LSCP (liblscp) instrument_name support disabled.");      sText += tr("LSCP (liblscp) instrument_name support disabled.");
1527      sText += "</font></small><br />";      sText += "</font></small><br />";
1528  #endif  #endif
1529    #ifndef CONFIG_MUTE_SOLO
1530        sText += "<small><font color=\"red\">";
1531        sText += tr("Sampler channel Mute/Solo support disabled.");
1532        sText += "</font></small><br />";
1533    #endif
1534    #ifndef CONFIG_AUDIO_ROUTING
1535        sText += "<small><font color=\"red\">";
1536        sText += tr("LSCP (liblscp) audio_routing support disabled.");
1537        sText += "</font></small><br />";
1538    #endif
1539    #ifndef CONFIG_FXSEND
1540        sText += "<small><font color=\"red\">";
1541        sText += tr("Sampler channel Effect Sends support disabled.");
1542        sText += "</font></small><br />";
1543    #endif
1544    #ifndef CONFIG_MIDI_INSTRUMENT
1545        sText += "<small><font color=\"red\">";
1546        sText += tr("MIDI instrument mapping support disabled.");
1547        sText += "</font></small><br />";
1548    #endif
1549      sText += "<br />\n";      sText += "<br />\n";
1550      sText += tr("Using") + ": ";      sText += tr("Using") + ": ";
1551      sText += ::lscp_client_package();      sText += ::lscp_client_package();
1552      sText += " ";      sText += " ";
1553      sText += ::lscp_client_version();      sText += ::lscp_client_version();
1554    #ifdef CONFIG_LIBGIG
1555        sText += ", ";
1556        sText += gig::libraryName().c_str();
1557        sText += " ";
1558        sText += gig::libraryVersion().c_str();
1559    #endif
1560      sText += "<br />\n";      sText += "<br />\n";
1561      sText += "<br />\n";      sText += "<br />\n";
1562      sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";      sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";
# Line 1309  void qsamplerMainForm::stabilizeForm (vo Line 1581  void qsamplerMainForm::stabilizeForm (vo
1581      // Update the main application caption...      // Update the main application caption...
1582      QString sSessionName = sessionName(m_sFilename);      QString sSessionName = sessionName(m_sFilename);
1583      if (m_iDirtyCount > 0)      if (m_iDirtyCount > 0)
1584          sSessionName += '*';          sSessionName += " *";
1585      setCaption(tr(QSAMPLER_TITLE " - [%1]").arg(sSessionName));      setCaption(tr(QSAMPLER_TITLE " - [%1]").arg(sSessionName));
1586    
1587      // Update the main menu state...      // Update the main menu state...
# Line 1328  void qsamplerMainForm::stabilizeForm (vo Line 1600  void qsamplerMainForm::stabilizeForm (vo
1600      editResetChannelAction->setEnabled(bHasChannel);      editResetChannelAction->setEnabled(bHasChannel);
1601      editResetAllChannelsAction->setEnabled(bHasChannel);      editResetAllChannelsAction->setEnabled(bHasChannel);
1602      viewMessagesAction->setOn(m_pMessages && m_pMessages->isVisible());      viewMessagesAction->setOn(m_pMessages && m_pMessages->isVisible());
1603      viewDevicesAction->setOn(m_pDeviceForm && m_pDeviceForm->isVisible());  #ifdef CONFIG_MIDI_INSTRUMENT
1604            viewInstrumentsAction->setOn(m_pInstrumentListForm
1605                    && m_pInstrumentListForm->isVisible());
1606            viewInstrumentsAction->setEnabled(bHasClient);
1607    #endif
1608            viewDevicesAction->setOn(m_pDeviceForm
1609                    && m_pDeviceForm->isVisible());
1610      viewDevicesAction->setEnabled(bHasClient);      viewDevicesAction->setEnabled(bHasClient);
1611      channelsArrangeAction->setEnabled(bHasChannel);      channelsArrangeAction->setEnabled(bHasChannel);
1612    
# Line 1364  void qsamplerMainForm::stabilizeForm (vo Line 1642  void qsamplerMainForm::stabilizeForm (vo
1642  void qsamplerMainForm::channelStripChanged( qsamplerChannelStrip *pChannelStrip )  void qsamplerMainForm::channelStripChanged( qsamplerChannelStrip *pChannelStrip )
1643  {  {
1644          // Add this strip to the changed list...          // Add this strip to the changed list...
1645          if (m_changedStrips.containsRef(pChannelStrip) == 0)          if (m_changedStrips.containsRef(pChannelStrip) == 0) {
1646                  m_changedStrips.append(pChannelStrip);                  m_changedStrips.append(pChannelStrip);
1647                    pChannelStrip->resetErrorCount();
1648            }
1649    
1650      // Just mark the dirty form.      // Just mark the dirty form.
1651      m_iDirtyCount++;      m_iDirtyCount++;
# Line 1377  void qsamplerMainForm::channelStripChang Line 1657  void qsamplerMainForm::channelStripChang
1657  // Grab and restore current sampler channels session.  // Grab and restore current sampler channels session.
1658  void qsamplerMainForm::updateSession (void)  void qsamplerMainForm::updateSession (void)
1659  {  {
1660    #ifdef CONFIG_MIDI_INSTRUMENT
1661            // FIXME: Make some room for default instrument maps...
1662            int iMaps = ::lscp_get_midi_instrument_maps(m_pClient);
1663            if (iMaps < 0)
1664                    appendMessagesClient("lscp_get_midi_instrument_maps");
1665            else if (iMaps < 1) {
1666                    ::lscp_add_midi_instrument_map(m_pClient, tr("Chromatic").latin1());
1667                    ::lscp_add_midi_instrument_map(m_pClient, tr("Drum Kits").latin1());
1668            }
1669    #endif
1670    
1671          // Retrieve the current channel list.          // Retrieve the current channel list.
1672          int *piChannelIDs = ::lscp_list_channels(m_pClient);          int *piChannelIDs = ::lscp_list_channels(m_pClient);
1673          if (piChannelIDs == NULL) {          if (piChannelIDs == NULL) {
# Line 1384  void qsamplerMainForm::updateSession (vo Line 1675  void qsamplerMainForm::updateSession (vo
1675                          appendMessagesClient("lscp_list_channels");                          appendMessagesClient("lscp_list_channels");
1676                          appendMessagesError(tr("Could not get current list of channels.\n\nSorry."));                          appendMessagesError(tr("Could not get current list of channels.\n\nSorry."));
1677                  }                  }
1678                  return;          } else {
1679                    // Try to (re)create each channel.
1680                    m_pWorkspace->setUpdatesEnabled(false);
1681                    for (int iChannel = 0; piChannelIDs[iChannel] >= 0; iChannel++) {
1682                            // Check if theres already a channel strip for this one...
1683                            if (!channelStrip(piChannelIDs[iChannel]))
1684                                    createChannelStrip(new qsamplerChannel(piChannelIDs[iChannel]));
1685                    }
1686                    m_pWorkspace->setUpdatesEnabled(true);
1687          }          }
1688    
1689          // Try to (re)create each channel.      // Do we auto-arrange?
1690          m_pWorkspace->setUpdatesEnabled(false);      if (m_pOptions && m_pOptions->bAutoArrange)
1691          for (int iChannel = 0; piChannelIDs[iChannel] >= 0; iChannel++) {          channelsArrange();
1692                  // Check if theres already a channel strip for this one...  
1693                  if (!channelStrip(piChannelIDs[iChannel]))          // Remember to refresh devices and instruments...
1694                          createChannelStrip(new qsamplerChannel(this, piChannelIDs[iChannel]));          if (m_pInstrumentListForm)
1695                  // Make it visibly responsive...              m_pInstrumentListForm->refreshInstruments();
1696                  QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);          if (m_pDeviceForm)
1697          }              m_pDeviceForm->refreshDevices();
         m_pWorkspace->setUpdatesEnabled(true);  
1698  }  }
1699    
1700    
# Line 1567  void qsamplerMainForm::appendMessagesErr Line 1865  void qsamplerMainForm::appendMessagesErr
1865    
1866      appendMessagesColor(s.simplifyWhiteSpace(), "#ff0000");      appendMessagesColor(s.simplifyWhiteSpace(), "#ff0000");
1867    
1868      QMessageBox::critical(this, tr("Error"), s, tr("Cancel"));          // Make it look responsive...:)
1869            QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
1870    
1871        QMessageBox::critical(this,
1872                    QSAMPLER_TITLE ": " + tr("Error"), s, tr("Cancel"));
1873  }  }
1874    
1875    
# Line 1580  void qsamplerMainForm::appendMessagesCli Line 1882  void qsamplerMainForm::appendMessagesCli
1882      appendMessagesColor(s + QString(": %1 (errno=%2)")      appendMessagesColor(s + QString(": %1 (errno=%2)")
1883          .arg(::lscp_client_get_result(m_pClient))          .arg(::lscp_client_get_result(m_pClient))
1884          .arg(::lscp_client_get_errno(m_pClient)), "#996666");          .arg(::lscp_client_get_errno(m_pClient)), "#996666");
1885    
1886            // Make it look responsive...:)
1887            QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
1888  }  }
1889    
1890    
# Line 1607  void qsamplerMainForm::updateMessagesLim Line 1912  void qsamplerMainForm::updateMessagesLim
1912          if (m_pOptions->bMessagesLimit)          if (m_pOptions->bMessagesLimit)
1913              m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);              m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);
1914          else          else
1915              m_pMessages->setMessagesLimit(0);              m_pMessages->setMessagesLimit(-1);
1916      }      }
1917  }  }
1918    
# Line 1651  qsamplerChannelStrip *qsamplerMainForm:: Line 1956  qsamplerChannelStrip *qsamplerMainForm::
1956      pChannelStrip = new qsamplerChannelStrip(m_pWorkspace, 0, wflags);      pChannelStrip = new qsamplerChannelStrip(m_pWorkspace, 0, wflags);
1957      if (pChannelStrip == NULL)      if (pChannelStrip == NULL)
1958          return NULL;          return NULL;
1959            
1960      // Actual channel strip setup...      // Actual channel strip setup...
1961      pChannelStrip->setup(pChannel);      pChannelStrip->setup(pChannel);
1962      QObject::connect(pChannelStrip, SIGNAL(channelChanged(qsamplerChannelStrip *)), this, SLOT(channelStripChanged(qsamplerChannelStrip *)));          QObject::connect(pChannelStrip,
1963                    SIGNAL(channelChanged(qsamplerChannelStrip *)),
1964                    SLOT(channelStripChanged(qsamplerChannelStrip *)));
1965      // Set some initial aesthetic options...      // Set some initial aesthetic options...
1966      if (m_pOptions) {      if (m_pOptions) {
1967          // Background display effect...          // Background display effect...
# Line 1709  qsamplerChannelStrip *qsamplerMainForm:: Line 2016  qsamplerChannelStrip *qsamplerMainForm::
2016          QWidgetList wlist = m_pWorkspace->windowList();          QWidgetList wlist = m_pWorkspace->windowList();
2017          if (wlist.isEmpty())          if (wlist.isEmpty())
2018                  return NULL;                  return NULL;
2019            
2020          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
2021                  qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);                  qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
2022                  if (pChannelStrip) {                  if (pChannelStrip) {
# Line 1790  void qsamplerMainForm::timerSlot (void) Line 2097  void qsamplerMainForm::timerSlot (void)
2097              }              }
2098          }          }
2099      }      }
2100        
2101          // Refresh each channel usage, on each period...          if (m_pClient) {
2102      if (m_pClient && (m_changedStrips.count() > 0 || m_pOptions->bAutoRefresh)) {                  // Update the channel information for each pending strip...
2103          m_iTimerSlot += QSAMPLER_TIMER_MSECS;                  if (m_changedStrips.count() > 0) {
2104          if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime && m_pWorkspace->isUpdatesEnabled())  {                          for (qsamplerChannelStrip *pChannelStrip = m_changedStrips.first();
2105              m_iTimerSlot = 0;                                          pChannelStrip; pChannelStrip = m_changedStrips.next()) {
             // Update the channel information for each pending strip...  
             for (qsamplerChannelStrip *pChannelStrip = m_changedStrips.first();  
                     pChannelStrip;  
                                                 pChannelStrip = m_changedStrips.next()) {  
2106                                  // If successfull, remove from pending list...                                  // If successfull, remove from pending list...
2107                                  if (pChannelStrip->updateChannelInfo())                                  if (pChannelStrip->updateChannelInfo())
2108                      m_changedStrips.remove(pChannelStrip);                                          m_changedStrips.remove(pChannelStrip);
2109                          }                          }
2110              // Update the channel stream usage for each strip...                  }
2111              QWidgetList wlist = m_pWorkspace->windowList();                  // Refresh each channel usage, on each period...
2112              for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {                  if (m_pOptions->bAutoRefresh) {
2113                  qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);                          m_iTimerSlot += QSAMPLER_TIMER_MSECS;
2114                  if (pChannelStrip && pChannelStrip->isVisible())                          if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime)  {
2115                      pChannelStrip->updateChannelUsage();                                  m_iTimerSlot = 0;
2116              }                                  // Update the channel stream usage for each strip...
2117          }                                  QWidgetList wlist = m_pWorkspace->windowList();
2118      }                                  for (int iChannel = 0;
2119                                                    iChannel < (int) wlist.count(); iChannel++) {
2120                                            qsamplerChannelStrip *pChannelStrip
2121                                                    = (qsamplerChannelStrip *) wlist.at(iChannel);
2122                                            if (pChannelStrip && pChannelStrip->isVisible())
2123                                                    pChannelStrip->updateChannelUsage();
2124                                    }
2125                            }
2126                    }
2127            }
2128    
2129      // Register the next timer slot.      // Register the next timer slot.
2130      QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));      QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
# Line 1834  void qsamplerMainForm::startServer (void Line 2146  void qsamplerMainForm::startServer (void
2146    
2147      // Is the server process instance still here?      // Is the server process instance still here?
2148      if (m_pServer) {      if (m_pServer) {
2149          switch (QMessageBox::warning(this, tr("Warning"),          switch (QMessageBox::warning(this,
2150                            QSAMPLER_TITLE ": " + tr("Warning"),
2151              tr("Could not start the LinuxSampler server.\n\n"              tr("Could not start the LinuxSampler server.\n\n"
2152                 "Maybe it ss already started."),                 "Maybe it ss already started."),
2153              tr("Stop"), tr("Kill"), tr("Cancel"))) {              tr("Stop"), tr("Kill"), tr("Cancel"))) {
# Line 1855  void qsamplerMainForm::startServer (void Line 2168  void qsamplerMainForm::startServer (void
2168      m_pServer = new QProcess(this);      m_pServer = new QProcess(this);
2169    
2170      // Setup stdout/stderr capture...      // Setup stdout/stderr capture...
2171      //if (m_pOptions->bStdoutCapture) {          //      if (m_pOptions->bStdoutCapture) {
2172          m_pServer->setCommunication(QProcess::Stdout | QProcess::Stderr | QProcess::DupStderr);                  m_pServer->setCommunication(
2173          QObject::connect(m_pServer, SIGNAL(readyReadStdout()), this, SLOT(readServerStdout()));                          QProcess::Stdout | QProcess::Stderr | QProcess::DupStderr);
2174          QObject::connect(m_pServer, SIGNAL(readyReadStderr()), this, SLOT(readServerStdout()));                  QObject::connect(m_pServer,
2175      //}                          SIGNAL(readyReadStdout()),
2176      // The unforgiveable signal communication...                          SLOT(readServerStdout()));
2177      QObject::connect(m_pServer, SIGNAL(processExited()), this, SLOT(processServerExit()));                  QObject::connect(m_pServer,
2178                            SIGNAL(readyReadStderr()),
2179                            SLOT(readServerStdout()));
2180            //      }
2181            // The unforgiveable signal communication...
2182            QObject::connect(m_pServer,
2183                    SIGNAL(processExited()),
2184                    SLOT(processServerExit()));
2185    
2186      // Build process arguments...      // Build process arguments...
2187      m_pServer->setArguments(QStringList::split(' ', m_pOptions->sServerCmdLine));      m_pServer->setArguments(QStringList::split(' ', m_pOptions->sServerCmdLine));
# Line 1993  bool qsamplerMainForm::startClient (void Line 2313  bool qsamplerMainForm::startClient (void
2313      ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);      ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);
2314      appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));      appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));
2315    
2316            // Subscribe to channel info change notifications...
2317            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO) != LSCP_OK)
2318                    appendMessagesClient("lscp_client_subscribe");
2319    
2320      // We may stop scheduling around.      // We may stop scheduling around.
2321      stopSchedule();      stopSchedule();
2322    
# Line 2002  bool qsamplerMainForm::startClient (void Line 2326  bool qsamplerMainForm::startClient (void
2326      // Log success here.      // Log success here.
2327      appendMessages(tr("Client connected."));      appendMessages(tr("Client connected."));
2328    
2329          // Hard-notify device configuration form,          // Hard-notify instrumnet and device configuration forms,
2330          // if visible, that we're ready...          // if visible, that we're ready...
2331          if (m_pDeviceForm && m_pDeviceForm->isVisible())          if (m_pInstrumentListForm)
2332              m_pDeviceForm->setClient(m_pClient);              m_pInstrumentListForm->refreshInstruments();
2333                        if (m_pDeviceForm)
2334                m_pDeviceForm->refreshDevices();
2335    
2336      // Is any session pending to be loaded?      // Is any session pending to be loaded?
2337      if (!m_pOptions->sSessionFile.isEmpty()) {      if (!m_pOptions->sSessionFile.isEmpty()) {
2338          // Just load the prabably startup session...          // Just load the prabably startup session...
# Line 2027  void qsamplerMainForm::stopClient (void) Line 2353  void qsamplerMainForm::stopClient (void)
2353      if (m_pClient == NULL)      if (m_pClient == NULL)
2354          return;          return;
2355    
         // Hard-notify device configuration form,  
         // if visible, that we're running out...  
         if (m_pDeviceForm && m_pDeviceForm->isVisible())  
             m_pDeviceForm->setClient(NULL);  
   
2356      // Log prepare here.      // Log prepare here.
2357      appendMessages(tr("Client disconnecting..."));      appendMessages(tr("Client disconnecting..."));
2358    
# Line 2046  void qsamplerMainForm::stopClient (void) Line 2367  void qsamplerMainForm::stopClient (void)
2367      // channels from the back-end server.      // channels from the back-end server.
2368      m_iDirtyCount = 0;      m_iDirtyCount = 0;
2369      closeSession(false);      closeSession(false);
2370        
2371      // Close us as a client...      // Close us as a client...
2372      lscp_client_destroy(m_pClient);          ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO);
2373        ::lscp_client_destroy(m_pClient);
2374      m_pClient = NULL;      m_pClient = NULL;
2375    
2376            // Hard-notify instrumnet and device configuration forms,
2377            // if visible, that we're running out...
2378            if (m_pInstrumentListForm)
2379                m_pInstrumentListForm->refreshInstruments();
2380            if (m_pDeviceForm)
2381                m_pDeviceForm->refreshDevices();
2382    
2383      // Log final here.      // Log final here.
2384      appendMessages(tr("Client disconnected."));      appendMessages(tr("Client disconnected."));
2385    

Legend:
Removed from v.463  
changed lines
  Added in v.1025

  ViewVC Help
Powered by ViewVC