summaryrefslogtreecommitdiffstats
path: root/src/gui/application
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/application')
-rw-r--r--src/gui/application/LircClient.cpp100
-rw-r--r--src/gui/application/LircClient.h71
-rw-r--r--src/gui/application/LircCommander.cpp170
-rw-r--r--src/gui/application/LircCommander.h112
-rw-r--r--src/gui/application/RosegardenApplication.cpp145
-rw-r--r--src/gui/application/RosegardenApplication.h97
-rw-r--r--src/gui/application/RosegardenDCOP.h50
-rw-r--r--src/gui/application/RosegardenGUIApp.cpp8073
-rw-r--r--src/gui/application/RosegardenGUIApp.cpp.orig8043
-rw-r--r--src/gui/application/RosegardenGUIApp.h1691
-rw-r--r--src/gui/application/RosegardenGUIView.cpp2041
-rw-r--r--src/gui/application/RosegardenGUIView.h347
-rw-r--r--src/gui/application/RosegardenIface.cpp82
-rw-r--r--src/gui/application/RosegardenIface.h130
-rw-r--r--src/gui/application/SetWaitCursor.cpp95
-rw-r--r--src/gui/application/SetWaitCursor.h58
-rw-r--r--src/gui/application/StartupTester.cpp248
-rw-r--r--src/gui/application/StartupTester.h88
-rw-r--r--src/gui/application/main.cpp741
19 files changed, 22382 insertions, 0 deletions
diff --git a/src/gui/application/LircClient.cpp b/src/gui/application/LircClient.cpp
new file mode 100644
index 0000000..ae731d7
--- /dev/null
+++ b/src/gui/application/LircClient.cpp
@@ -0,0 +1,100 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+ Rosegarden
+ A MIDI and audio sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <richard.bown@ferventsoftware.com>
+
+ This file is Copyright 2005
+ Toni Arnold <toni__arnold@bluewin.ch>
+
+ The moral rights of Guillaume Laurent, Chris Cannam, and Richard
+ Bown to claim authorship of this work have been asserted.
+
+ Other copyrights also apply to some parts of this work. Please
+ see the AUTHORS file and individual file headers for details.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+
+#include "LircClient.h"
+
+#ifdef HAVE_LIRC
+
+#include "misc/Debug.h"
+#include "base/Exception.h"
+#include <qobject.h>
+#include <qsocketnotifier.h>
+#include <fcntl.h>
+#include <cstdlib>
+
+namespace Rosegarden
+{
+
+LircClient::LircClient(void)
+ : QObject()
+{
+ int socketFlags;
+
+ // socket setup with nonblock
+ m_socket = lirc_init("rosegarden", 1);
+ if (m_socket == -1) {
+ throw Exception("Failed to connect to LIRC");
+ }
+
+ if (lirc_readconfig(NULL, &m_config, NULL) == -1) {
+ throw Exception("Failed reading LIRC config file");
+ }
+
+ fcntl(m_socket, F_GETOWN, getpid());
+ socketFlags = fcntl(m_socket, F_GETFL, 0);
+ if (socketFlags != -1) {
+ fcntl(socketFlags, F_SETFL, socketFlags | O_NONBLOCK);
+ }
+
+ m_socketNotifier = new QSocketNotifier(m_socket, QSocketNotifier::Read, 0);
+ connect(m_socketNotifier, SIGNAL(activated(int)), this, SLOT(readButton()) );
+
+ RG_DEBUG << "LircClient::LircClient: connected to socket: " << m_socket << endl;
+}
+
+LircClient::~LircClient()
+{
+ lirc_freeconfig(m_config);
+ delete m_socketNotifier;
+ lirc_deinit();
+
+ RG_DEBUG << "LircClient::~LircClient: cleaned up" << endl;
+}
+
+void LircClient::readButton()
+{
+ char *code;
+ int ret;
+
+ RG_DEBUG << "LircClient::readButton" << endl;
+
+ if (lirc_nextcode(&code) == 0 && code != NULL) { // no error && a string is available
+ // handle any command attached to that button
+ while ( (ret = lirc_code2char(m_config, code, &m_command)) == 0 && m_command != NULL )
+ {
+ emit buttonPressed(m_command);
+ }
+ free(code);
+ }
+}
+
+}
+
+#include "LircClient.moc"
+
+#endif
diff --git a/src/gui/application/LircClient.h b/src/gui/application/LircClient.h
new file mode 100644
index 0000000..b80d3d7
--- /dev/null
+++ b/src/gui/application/LircClient.h
@@ -0,0 +1,71 @@
+
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+ Rosegarden
+ A MIDI and audio sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <richard.bown@ferventsoftware.com>
+
+ This file is Copyright 2005
+ Toni Arnold <toni__arnold@bluewin.ch>
+
+ The moral rights of Guillaume Laurent, Chris Cannam, and Richard
+ Bown to claim authorship of this work have been asserted.
+
+ Other copyrights also apply to some parts of this work. Please
+ see the AUTHORS file and individual file headers for details.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+#ifndef _RG_LIRCCLIENT_H_
+#define _RG_LIRCCLIENT_H_
+
+#ifdef HAVE_LIRC
+
+#include <qobject.h>
+#include <lirc/lirc_client.h>
+
+class QSocketNotifier;
+
+
+namespace Rosegarden
+{
+
+
+
+class LircClient : public QObject
+{
+ Q_OBJECT
+public:
+ LircClient(void);
+ ~LircClient();
+
+public slots:
+ void readButton();
+
+signals:
+ void buttonPressed(char *);
+
+private:
+ int m_socket;
+ QSocketNotifier *m_socketNotifier;
+ struct lirc_config *m_config;
+ char *m_command;
+};
+
+
+
+}
+
+#endif
+
+#endif
diff --git a/src/gui/application/LircCommander.cpp b/src/gui/application/LircCommander.cpp
new file mode 100644
index 0000000..53562ca
--- /dev/null
+++ b/src/gui/application/LircCommander.cpp
@@ -0,0 +1,170 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+ Rosegarden
+ A MIDI and audio sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <richard.bown@ferventsoftware.com>
+
+ This file is Copyright 2005
+ Toni Arnold <toni__arnold@bluewin.ch>
+
+ The moral rights of Guillaume Laurent, Chris Cannam, and Richard
+ Bown to claim authorship of this work have been asserted.
+
+ Other copyrights also apply to some parts of this work. Please
+ see the AUTHORS file and individual file headers for details.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+#include "LircCommander.h"
+#include "LircClient.h"
+
+#ifdef HAVE_LIRC
+
+#include "misc/Debug.h"
+#include "document/RosegardenGUIDoc.h"
+#include "gui/editors/segment/TrackButtons.h"
+#include "RosegardenGUIApp.h"
+#include "RosegardenGUIView.h"
+
+#include <qobject.h>
+
+
+namespace Rosegarden
+{
+
+LircCommander::LircCommander(LircClient *lirc, RosegardenGUIApp *rgGUIApp)
+ : QObject()
+{
+ m_lirc = lirc;
+ m_rgGUIApp = rgGUIApp;
+ connect(m_lirc, SIGNAL(buttonPressed(char *)),
+ this, SLOT(slotExecute(char *)) );
+
+ connect(this, SIGNAL(play()),
+ m_rgGUIApp, SLOT(slotPlay()) );
+ connect(this, SIGNAL(stop()),
+ m_rgGUIApp, SLOT(slotStop()) );
+ connect(this, SIGNAL(record()),
+ m_rgGUIApp, SLOT(slotRecord()) );
+ connect(this, SIGNAL(rewind()),
+ m_rgGUIApp, SLOT(slotRewind()) );
+ connect(this, SIGNAL(rewindToBeginning()),
+ m_rgGUIApp, SLOT(slotRewindToBeginning()) );
+ connect(this, SIGNAL(fastForward()),
+ m_rgGUIApp, SLOT(slotFastforward()) );
+ connect(this, SIGNAL(fastForwardToEnd()),
+ m_rgGUIApp, SLOT(slotFastForwardToEnd()) );
+ connect(this, SIGNAL(toggleRecord()),
+ m_rgGUIApp, SLOT(slotToggleRecord()) );
+ connect(this, SIGNAL(trackDown()),
+ m_rgGUIApp, SLOT(slotTrackDown()) );
+ connect(this, SIGNAL(trackUp()),
+ m_rgGUIApp, SLOT(slotTrackUp()) );
+ connect(this, SIGNAL(trackMute()),
+ m_rgGUIApp, SLOT(slotToggleMutedCurrentTrack()) );
+ connect(this, SIGNAL(trackRecord()),
+ m_rgGUIApp, SLOT(slotToggleRecordCurrentTrack()) );
+}
+
+LircCommander::command LircCommander::commands[] =
+ {
+ { "FORWARD", cmd_fastForward },
+ { "FORWARDTOEND", cmd_fastForwardToEnd },
+ { "PLAY", cmd_play },
+ { "PUNCHINRECORD", cmd_toggleRecord },
+ { "RECORD", cmd_record },
+ { "REWIND", cmd_rewind },
+ { "REWINDTOBEGINNING", cmd_rewindToBeginning },
+ { "STOP", cmd_stop },
+ { "TRACK+", cmd_trackUp },
+ { "TRACK-", cmd_trackDown },
+ { "TRACK-MUTE", cmd_trackMute },
+ { "TRACK-RECORD", cmd_trackRecord },
+ };
+
+
+int LircCommander::compareCommandName(const void *c1, const void *c2)
+{
+ return (strcmp(((struct command *)c1)->name, ((struct command *)c2)->name));
+}
+
+void LircCommander::slotExecute(char *command)
+{
+ struct command tmp, *res;
+
+ RG_DEBUG << "LircCommander::slotExecute: invoking command: " << command << endl;
+
+ // find the function for the name
+ tmp.name = command;
+ res = (struct command *)bsearch(&tmp, commands,
+ sizeof(commands) / sizeof(struct command),
+ sizeof(struct command),
+ compareCommandName);
+ if (res != NULL)
+ {
+ switch (res->code)
+ {
+ case cmd_play:
+ emit play();
+ break;
+ case cmd_stop:
+ emit stop();
+ break;
+ case cmd_record:
+ emit record();
+ break;
+ case cmd_rewind:
+ emit rewind();
+ break;
+ case cmd_rewindToBeginning:
+ emit rewindToBeginning();
+ break;
+ case cmd_fastForward:
+ emit fastForward();
+ break;
+ case cmd_fastForwardToEnd:
+ emit fastForwardToEnd();
+ break;
+ case cmd_toggleRecord:
+ emit toggleRecord();
+ break;
+ case cmd_trackDown:
+ emit trackDown();
+ break;
+ case cmd_trackUp:
+ emit trackUp();
+ break;
+ case cmd_trackMute:
+ emit trackMute();
+ break;
+ case cmd_trackRecord:
+ emit trackRecord();
+ break;
+ default:
+ RG_DEBUG << "LircCommander::slotExecute: unhandled command " << command << endl;
+ return;
+ }
+ RG_DEBUG << "LircCommander::slotExecute: handled command: " << command << endl;
+ }
+ else
+ {
+ RG_DEBUG << "LircCommander::slotExecute: invoking command: " << command
+ << " failed (command not defined in LircCommander::commands[])" << endl;
+ };
+}
+
+}
+
+#include "LircCommander.moc"
+
+#endif
diff --git a/src/gui/application/LircCommander.h b/src/gui/application/LircCommander.h
new file mode 100644
index 0000000..84a857e
--- /dev/null
+++ b/src/gui/application/LircCommander.h
@@ -0,0 +1,112 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+ Rosegarden
+ A MIDI and audio sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <richard.bown@ferventsoftware.com>
+
+ This file is Copyright 2005
+ Toni Arnold <toni__arnold@bluewin.ch>
+
+ The moral rights of Guillaume Laurent, Chris Cannam, and Richard
+ Bown to claim authorship of this work have been asserted.
+
+ Other copyrights also apply to some parts of this work. Please
+ see the AUTHORS file and individual file headers for details.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+#ifndef _RG_LIRCCOMMANDER_H_
+#define _RG_LIRCCOMMANDER_H_
+
+#ifdef HAVE_LIRC
+
+#include <qobject.h>
+#include "base/Track.h"
+
+
+namespace Rosegarden
+{
+
+class RosegardenGUIApp;
+class RosegardenGUIDoc;
+class TrackButtons;
+class LircClient;
+
+
+class LircCommander : public QObject
+{
+ Q_OBJECT
+public:
+ LircCommander(LircClient *lirc, RosegardenGUIApp *rgGUIApp);
+
+signals:
+ //for RosegardenGUIApp
+ void play();
+ void stop();
+ void record();
+ void rewind();
+ void rewindToBeginning();
+ void fastForward();
+ void fastForwardToEnd();
+ void toggleRecord();
+ void trackDown();
+ void trackUp();
+ void trackMute();
+ void trackRecord();
+
+private slots:
+ void slotExecute(char *);
+ //void slotDocumentChanged(RosegardenGUIDoc *);
+
+private:
+ LircClient *m_lirc;
+ RosegardenGUIApp *m_rgGUIApp;
+ //TrackButtons *m_trackButtons;
+
+ // commands invoked by lirc
+ enum commandCode {
+ cmd_play,
+ cmd_stop,
+ cmd_record,
+ cmd_rewind,
+ cmd_rewindToBeginning,
+ cmd_fastForward,
+ cmd_fastForwardToEnd,
+ cmd_toggleRecord,
+ cmd_trackDown,
+ cmd_trackUp,
+ cmd_trackMute,
+ cmd_trackRecord
+ };
+
+
+ // the command -> method mapping table
+ static struct command
+ {
+ char *name; /* command name */
+ commandCode code; /* function to process it */
+ }
+ commands[];
+
+ // utilities
+ static int compareCommandName(const void *c1, const void *c2);
+
+};
+
+
+
+}
+
+#endif
+
+#endif
diff --git a/src/gui/application/RosegardenApplication.cpp b/src/gui/application/RosegardenApplication.cpp
new file mode 100644
index 0000000..6e85aab
--- /dev/null
+++ b/src/gui/application/RosegardenApplication.cpp
@@ -0,0 +1,145 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+ Rosegarden
+ A MIDI and audio sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <richard.bown@ferventsoftware.com>
+
+ The moral rights of Guillaume Laurent, Chris Cannam, and Richard
+ Bown to claim authorship of this work have been asserted.
+
+ Other copyrights also apply to some parts of this work. Please
+ see the AUTHORS file and individual file headers for details.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+
+#include "RosegardenApplication.h"
+
+#include "misc/Debug.h"
+#include "document/ConfigGroups.h"
+#include "document/RosegardenGUIDoc.h"
+#include "gui/application/RosegardenDCOP.h"
+#include "gui/kdeext/KTmpStatusMsg.h"
+#include "RosegardenGUIApp.h"
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include <kmainwindow.h>
+#include <kmessagebox.h>
+#include <kprocess.h>
+#include <kuniqueapplication.h>
+#include <qcstring.h>
+#include <qeventloop.h>
+#include <qsessionmanager.h>
+#include <qstring.h>
+#include <dcopclient.h>
+#include <kconfig.h>
+#include <kstatusbar.h>
+
+
+namespace Rosegarden
+{
+
+int RosegardenApplication::newInstance()
+{
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ if (RosegardenGUIApp::self() && args->count() &&
+ RosegardenGUIApp::self()->getDocument() &&
+ RosegardenGUIApp::self()->getDocument()->saveIfModified()) {
+ // Check for modifications and save if necessary - if cancelled
+ // then don't load the new file.
+ //
+ RosegardenGUIApp::self()->openFile(args->arg(0));
+ }
+
+ return KUniqueApplication::newInstance();
+}
+
+bool RosegardenApplication::isSequencerRegistered()
+{
+ if (noSequencerMode())
+ return false;
+ return dcopClient()->isApplicationRegistered(ROSEGARDEN_SEQUENCER_APP_NAME);
+}
+
+bool RosegardenApplication::sequencerSend(QCString dcopCall, QByteArray params)
+{
+ if (noSequencerMode())
+ return false;
+
+ return dcopClient()->send(ROSEGARDEN_SEQUENCER_APP_NAME,
+ ROSEGARDEN_SEQUENCER_IFACE_NAME,
+ dcopCall, params);
+}
+
+bool RosegardenApplication::sequencerCall(QCString dcopCall, QCString& replyType, QByteArray& replyData,
+ QByteArray params, bool useEventLoop)
+{
+ if (noSequencerMode())
+ return false;
+ return dcopClient()->call(ROSEGARDEN_SEQUENCER_APP_NAME,
+ ROSEGARDEN_SEQUENCER_IFACE_NAME,
+ dcopCall, params, replyType, replyData, useEventLoop);
+}
+
+void RosegardenApplication::sfxLoadExited(KProcess *proc)
+{
+ if (!proc->normalExit()) {
+ QString configGroup = config()->group();
+ config()->setGroup(SequencerOptionsConfigGroup);
+ QString soundFontPath = config()->readEntry("soundfontpath", "");
+ config()->setGroup(configGroup);
+
+ KMessageBox::error(mainWidget(),
+ i18n("Failed to load soundfont %1").arg(soundFontPath));
+ } else {
+ RG_DEBUG << "RosegardenApplication::sfxLoadExited() : sfxload exited normally\n";
+ }
+
+}
+
+void RosegardenApplication::slotSetStatusMessage(QString msg)
+{
+ KMainWindow* mainWindow = dynamic_cast<KMainWindow*>(mainWidget());
+ if (mainWindow) {
+ if (msg.isEmpty())
+ msg = KTmpStatusMsg::getDefaultMsg();
+ mainWindow->statusBar()->changeItem(QString(" %1").arg(msg), KTmpStatusMsg::getDefaultId());
+ }
+
+}
+
+void
+RosegardenApplication::refreshGUI(int maxTime)
+{
+ eventLoop()->processEvents(QEventLoop::ExcludeUserInput |
+ QEventLoop::ExcludeSocketNotifiers,
+ maxTime);
+}
+
+void RosegardenApplication::saveState(QSessionManager& sm)
+{
+ emit aboutToSaveState();
+ KUniqueApplication::saveState(sm);
+}
+
+RosegardenApplication* RosegardenApplication::rgApp()
+{
+ return dynamic_cast<RosegardenApplication*>(kApplication());
+}
+
+QByteArray RosegardenApplication::Empty;
+
+}
+
+#include "RosegardenApplication.moc"
diff --git a/src/gui/application/RosegardenApplication.h b/src/gui/application/RosegardenApplication.h
new file mode 100644
index 0000000..4541308
--- /dev/null
+++ b/src/gui/application/RosegardenApplication.h
@@ -0,0 +1,97 @@
+
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+ Rosegarden
+ A MIDI and audio sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <richard.bown@ferventsoftware.com>
+
+ The moral rights of Guillaume Laurent, Chris Cannam, and Richard
+ Bown to claim authorship of this work have been asserted.
+
+ Other copyrights also apply to some parts of this work. Please
+ see the AUTHORS file and individual file headers for details.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+#ifndef _RG_ROSEGARDENAPPLICATION_H_
+#define _RG_ROSEGARDENAPPLICATION_H_
+
+#include <kuniqueapplication.h>
+#include <qcstring.h>
+#include <qstring.h>
+
+
+class QSessionManager;
+class KProcess;
+
+
+namespace Rosegarden
+{
+
+
+
+/**
+ * RosegardenApplication
+ *
+ * Handles RosegardenGUIApps perceived uniqueness for us.
+ *
+ */
+class RosegardenApplication : public KUniqueApplication
+{
+ Q_OBJECT
+public:
+ RosegardenApplication(): KUniqueApplication(), m_noSequencerMode(false) {}
+
+ /**
+ * Handle the attempt at creation of a new instance -
+ * only accept new file names which we attempt to load
+ * into the existing instance (if it exists)
+ */
+ virtual int newInstance();
+
+ void refreshGUI(int maxTime);
+
+ bool isSequencerRegistered();
+ bool sequencerSend(QCString dcopCall, QByteArray params = Empty);
+ bool sequencerCall(QCString dcopCall, QCString& replyType,
+ QByteArray& replyData, QByteArray params = Empty, bool useEventLoop = false);
+
+ static RosegardenApplication* rgApp();
+
+ static QByteArray Empty;
+
+ void setNoSequencerMode(bool m=true) { m_noSequencerMode = m; }
+ bool noSequencerMode() { return m_noSequencerMode; }
+
+ virtual void saveState(QSessionManager&);
+
+signals:
+ // connect this to RosegardenGUIApp
+ void aboutToSaveState();
+
+public slots:
+ void sfxLoadExited(KProcess *proc);
+ void slotSetStatusMessage(QString txt);
+
+protected:
+ //--------------- Data members ---------------------------------
+
+ bool m_noSequencerMode;
+};
+
+#define rgapp RosegardenApplication::rgApp()
+
+
+}
+
+#endif
diff --git a/src/gui/application/RosegardenDCOP.h b/src/gui/application/RosegardenDCOP.h
new file mode 100644
index 0000000..2689945
--- /dev/null
+++ b/src/gui/application/RosegardenDCOP.h
@@ -0,0 +1,50 @@
+// -*- c-basic-offset: 4 -*-
+/*
+ Rosegarden
+ A sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <bownie@bownie.com>
+
+ The moral right of the authors to claim authorship of this work
+ has been asserted.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+
+#ifndef _ROSEGARDEN_DCOP_H_
+#define _ROSEGARDEN_DCOP_H_
+
+
+// The names of our applications and interfaces that we share
+//
+#define ROSEGARDEN_SEQUENCER_APP_NAME "rosegardensequencer"
+#define ROSEGARDEN_SEQUENCER_IFACE_NAME "RosegardenSequencerIface"
+
+#define ROSEGARDEN_GUI_APP_NAME "rosegarden"
+#define ROSEGARDEN_GUI_IFACE_NAME "RosegardenIface"
+
+
+// Sequencer communicates its state through this enum
+//
+typedef enum
+{
+ STOPPED,
+ PLAYING,
+ RECORDING,
+ STOPPING,
+ STARTING_TO_PLAY,
+ STARTING_TO_RECORD,
+ RECORDING_ARMED, // gui only state
+ QUIT
+} TransportStatus;
+
+
+#endif // _ROSEGARDEN_DCOP_H_
diff --git a/src/gui/application/RosegardenGUIApp.cpp b/src/gui/application/RosegardenGUIApp.cpp
new file mode 100644
index 0000000..608ad58
--- /dev/null
+++ b/src/gui/application/RosegardenGUIApp.cpp
@@ -0,0 +1,8073 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+ Rosegarden
+ A MIDI and audio sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <richard.bown@ferventsoftware.com>
+
+ The moral rights of Guillaume Laurent, Chris Cannam, and Richard
+ Bown to claim authorship of this work have been asserted.
+
+ Other copyrights also apply to some parts of this work. Please
+ see the AUTHORS file and individual file headers for details.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+
+#include "RosegardenGUIApp.h"
+#include <kapplication.h>
+
+#include "gui/editors/segment/TrackEditor.h"
+#include "gui/editors/segment/TrackButtons.h"
+#include "misc/Debug.h"
+#include "misc/Strings.h"
+#include "gui/application/RosegardenDCOP.h"
+#include "base/AnalysisTypes.h"
+#include "base/AudioPluginInstance.h"
+#include "base/Clipboard.h"
+#include "base/Composition.h"
+#include "base/CompositionTimeSliceAdapter.h"
+#include "base/Configuration.h"
+#include "base/Device.h"
+#include "base/Exception.h"
+#include "base/Instrument.h"
+#include "base/MidiDevice.h"
+#include "base/MidiProgram.h"
+#include "base/NotationTypes.h"
+#include "base/Profiler.h"
+#include "base/RealTime.h"
+#include "base/Segment.h"
+#include "base/SegmentNotationHelper.h"
+#include "base/Selection.h"
+#include "base/Studio.h"
+#include "base/Track.h"
+#include "commands/edit/CopyCommand.h"
+#include "commands/edit/CutCommand.h"
+#include "commands/edit/EventQuantizeCommand.h"
+#include "commands/edit/PasteSegmentsCommand.h"
+#include "commands/edit/TransposeCommand.h"
+#include "commands/edit/AddMarkerCommand.h"
+#include "commands/edit/ModifyMarkerCommand.h"
+#include "commands/edit/RemoveMarkerCommand.h"
+#include "commands/notation/KeyInsertionCommand.h"
+#include "commands/segment/AddTempoChangeCommand.h"
+#include "commands/segment/AddTimeSignatureAndNormalizeCommand.h"
+#include "commands/segment/AddTimeSignatureCommand.h"
+#include "commands/segment/AudioSegmentAutoSplitCommand.h"
+#include "commands/segment/AudioSegmentRescaleCommand.h"
+#include "commands/segment/AudioSegmentSplitCommand.h"
+#include "commands/segment/ChangeCompositionLengthCommand.h"
+#include "commands/segment/CreateTempoMapFromSegmentCommand.h"
+#include "commands/segment/CutRangeCommand.h"
+#include "commands/segment/DeleteRangeCommand.h"
+#include "commands/segment/InsertRangeCommand.h"
+#include "commands/segment/ModifyDefaultTempoCommand.h"
+#include "commands/segment/MoveTracksCommand.h"
+#include "commands/segment/PasteRangeCommand.h"
+#include "commands/segment/RemoveTempoChangeCommand.h"
+#include "commands/segment/SegmentAutoSplitCommand.h"
+#include "commands/segment/SegmentChangeTransposeCommand.h"
+#include "commands/segment/SegmentJoinCommand.h"
+#include "commands/segment/SegmentLabelCommand.h"
+#include "commands/segment/SegmentReconfigureCommand.h"
+#include "commands/segment/SegmentRescaleCommand.h"
+#include "commands/segment/SegmentSplitByPitchCommand.h"
+#include "commands/segment/SegmentSplitByRecordingSrcCommand.h"
+#include "commands/segment/SegmentSplitCommand.h"
+#include "commands/segment/SegmentTransposeCommand.h"
+#include "commands/studio/CreateOrDeleteDeviceCommand.h"
+#include "commands/studio/ModifyDeviceCommand.h"
+#include "document/io/CsoundExporter.h"
+#include "document/io/HydrogenLoader.h"
+#include "document/io/LilyPondExporter.h"
+#include "document/MultiViewCommandHistory.h"
+#include "document/io/RG21Loader.h"
+#include "document/io/MupExporter.h"
+#include "document/io/MusicXmlExporter.h"
+#include "document/RosegardenGUIDoc.h"
+#include "document/ConfigGroups.h"
+#include "gui/application/RosegardenApplication.h"
+#include "gui/dialogs/AddTracksDialog.h"
+#include "gui/dialogs/AudioManagerDialog.h"
+#include "gui/dialogs/AudioPluginDialog.h"
+#include "gui/dialogs/AudioSplitDialog.h"
+#include "gui/dialogs/BeatsBarsDialog.h"
+#include "gui/dialogs/CompositionLengthDialog.h"
+#include "gui/dialogs/ConfigureDialog.h"
+#include "gui/dialogs/CountdownDialog.h"
+#include "gui/dialogs/DocumentConfigureDialog.h"
+#include "gui/dialogs/FileMergeDialog.h"
+#include "gui/dialogs/IdentifyTextCodecDialog.h"
+#include "gui/dialogs/IntervalDialog.h"
+#include "gui/dialogs/LilyPondOptionsDialog.h"
+#include "gui/dialogs/ManageMetronomeDialog.h"
+#include "gui/dialogs/QuantizeDialog.h"
+#include "gui/dialogs/RescaleDialog.h"
+#include "gui/dialogs/SplitByPitchDialog.h"
+#include "gui/dialogs/SplitByRecordingSrcDialog.h"
+#include "gui/dialogs/TempoDialog.h"
+#include "gui/dialogs/TimeDialog.h"
+#include "gui/dialogs/TimeSignatureDialog.h"
+#include "gui/dialogs/TransportDialog.h"
+#include "gui/editors/parameters/InstrumentParameterBox.h"
+#include "gui/editors/parameters/RosegardenParameterArea.h"
+#include "gui/editors/parameters/SegmentParameterBox.h"
+#include "gui/editors/parameters/TrackParameterBox.h"
+#include "gui/editors/segment/segmentcanvas/CompositionView.h"
+#include "gui/editors/segment/ControlEditorDialog.h"
+#include "gui/editors/segment/MarkerEditor.h"
+#include "gui/editors/segment/PlayListDialog.h"
+#include "gui/editors/segment/PlayList.h"
+#include "gui/editors/segment/segmentcanvas/SegmentEraser.h"
+#include "gui/editors/segment/segmentcanvas/SegmentJoiner.h"
+#include "gui/editors/segment/segmentcanvas/SegmentMover.h"
+#include "gui/editors/segment/segmentcanvas/SegmentPencil.h"
+#include "gui/editors/segment/segmentcanvas/SegmentResizer.h"
+#include "gui/editors/segment/segmentcanvas/SegmentSelector.h"
+#include "gui/editors/segment/segmentcanvas/SegmentSplitter.h"
+#include "gui/editors/segment/segmentcanvas/SegmentToolBox.h"
+#include "gui/editors/segment/TrackLabel.h"
+#include "gui/editors/segment/TriggerSegmentManager.h"
+#include "gui/editors/tempo/TempoView.h"
+#include "gui/general/EditViewBase.h"
+#include "gui/kdeext/KStartupLogo.h"
+#include "gui/kdeext/KTmpStatusMsg.h"
+#include "gui/seqmanager/MidiFilterDialog.h"
+#include "gui/seqmanager/SequenceManager.h"
+#include "gui/seqmanager/SequencerMapper.h"
+#include "gui/studio/AudioMixerWindow.h"
+#include "gui/studio/AudioPlugin.h"
+#include "gui/studio/AudioPluginManager.h"
+#include "gui/studio/AudioPluginOSCGUIManager.h"
+#include "gui/studio/BankEditorDialog.h"
+#include "gui/studio/DeviceManagerDialog.h"
+#include "gui/studio/MidiMixerWindow.h"
+#include "gui/studio/RemapInstrumentDialog.h"
+#include "gui/studio/StudioControl.h"
+#include "gui/studio/SynthPluginManagerDialog.h"
+#include "gui/widgets/CurrentProgressDialog.h"
+#include "gui/widgets/ProgressBar.h"
+#include "gui/widgets/ProgressDialog.h"
+#include "LircClient.h"
+#include "LircCommander.h"
+#include "RosegardenGUIView.h"
+#include "RosegardenIface.h"
+#include "SetWaitCursor.h"
+#include "sound/AudioFile.h"
+#include "sound/AudioFileManager.h"
+#include "sound/MappedCommon.h"
+#include "sound/MappedComposition.h"
+#include "sound/MappedEvent.h"
+#include "sound/MappedStudio.h"
+#include "sound/MidiFile.h"
+#include "sound/PluginIdentifier.h"
+#include "sound/SoundDriver.h"
+#include "StartupTester.h"
+#include <dcopclient.h>
+#include <dcopobject.h>
+#include <dcopref.h>
+#include <kaction.h>
+#include <kconfig.h>
+#include <kdcopactionproxy.h>
+#include <kdockwidget.h>
+#include <kedittoolbar.h>
+#include <kfiledialog.h>
+#include <kglobal.h>
+#include <kinputdialog.h>
+#include <kio/netaccess.h>
+#include <kkeydialog.h>
+#include <klocale.h>
+#include <kmainwindow.h>
+#include <kmessagebox.h>
+#include <kmimetype.h>
+#include <kprocess.h>
+#include <kstatusbar.h>
+#include <kstdaccel.h>
+#include <kstdaction.h>
+#include <kstddirs.h>
+#include <ktempfile.h>
+#include <ktip.h>
+#include <ktoolbar.h>
+#include <kurl.h>
+#include <kxmlguiclient.h>
+#include <qaccel.h>
+#include <qcanvas.h>
+#include <qcstring.h>
+#include <qcursor.h>
+#include <qdatastream.h>
+#include <qdialog.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qiconset.h>
+#include <qinputdialog.h>
+#include <qlabel.h>
+#include <qobject.h>
+#include <qobjectlist.h>
+#include <qpixmap.h>
+#include <qpopupmenu.h>
+#include <qpushbutton.h>
+#include <qregexp.h>
+#include <qslider.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qtextcodec.h>
+#include <qtimer.h>
+#include <qvaluevector.h>
+#include <qwidget.h>
+
+#ifdef HAVE_LIBJACK
+#include <jack/jack.h>
+#endif
+
+
+namespace Rosegarden
+{
+
+RosegardenGUIApp::RosegardenGUIApp(bool useSequencer,
+ bool useExistingSequencer,
+ QObject *startupStatusMessageReceiver)
+ : DCOPObject("RosegardenIface"), RosegardenIface(this), KDockMainWindow(0),
+ m_actionsSetup(false),
+ m_fileRecent(0),
+ m_view(0),
+ m_swapView(0),
+ m_mainDockWidget(0),
+ m_dockLeft(0),
+ m_doc(0),
+ m_sequencerProcess(0),
+ m_sequencerCheckedIn(false),
+#ifdef HAVE_LIBJACK
+ m_jackProcess(0),
+#endif
+ m_zoomSlider(0),
+ m_seqManager(0),
+ m_transport(0),
+ m_audioManagerDialog(0),
+ m_originatingJump(false),
+ m_storedLoopStart(0),
+ m_storedLoopEnd(0),
+ m_useSequencer(useSequencer),
+ m_dockVisible(true),
+ m_autoSaveTimer(new QTimer(this)),
+ m_clipboard(new Clipboard),
+ m_playList(0),
+ m_deviceManager(0),
+ m_synthManager(0),
+ m_audioMixer(0),
+ m_midiMixer(0),
+ m_bankEditor(0),
+ m_markerEditor(0),
+ m_tempoView(0),
+ m_triggerSegmentManager(0),
+#ifdef HAVE_LIBLO
+ m_pluginGUIManager(new AudioPluginOSCGUIManager(this)),
+#endif
+ m_playTimer(new QTimer(this)),
+ m_stopTimer(new QTimer(this)),
+ m_startupTester(0),
+#ifdef HAVE_LIRC
+ m_lircClient(0),
+ m_lircCommander(0),
+#endif
+ m_haveAudioImporter(false),
+ m_firstRun(false),
+ m_parameterArea(0)
+{
+ m_myself = this;
+
+
+ if (startupStatusMessageReceiver) {
+ QObject::connect(this, SIGNAL(startupStatusMessage(QString)),
+ startupStatusMessageReceiver,
+ SLOT(slotShowStatusMessage(QString)));
+ }
+
+ // Try to start the sequencer
+ //
+ if (m_useSequencer) {
+
+#ifdef HAVE_LIBJACK
+#define OFFER_JACK_START_OPTION 1
+#ifdef OFFER_JACK_START_OPTION
+ // First we check if jackd is running allready
+
+ std::string jackClientName = "rosegarden";
+
+ // attempt connection to JACK server
+ //
+ jack_client_t* testJackClient;
+ testJackClient = jack_client_new(jackClientName.c_str());
+ if (testJackClient == 0 ) {
+
+ // If no connection to JACK
+ // try to launch JACK - if the configuration wants us to.
+ if (!launchJack()) {
+ KStartupLogo::hideIfStillThere();
+ KMessageBox::error(this, i18n("Attempted to launch JACK audio daemon failed. Audio will be disabled.\nPlease check configuration (Settings -> Configure Rosegarden -> Audio -> Startup)\n and restart."));
+ }
+ } else {
+ //this client was just for testing
+ jack_client_close(testJackClient);
+ }
+#endif // OFFER_JACK_START_OPTION
+#endif // HAVE_LIBJACK
+
+ emit startupStatusMessage(i18n("Starting sequencer..."));
+ launchSequencer(useExistingSequencer);
+
+ } else
+ RG_DEBUG << "RosegardenGUIApp : don't use sequencer\n";
+
+ // Plugin manager
+ //
+ emit startupStatusMessage(i18n("Initializing plugin manager..."));
+ m_pluginManager = new AudioPluginManager();
+
+ // call inits to invoke all other construction parts
+ //
+ emit startupStatusMessage(i18n("Initializing view..."));
+ initStatusBar();
+ setupActions();
+ iFaceDelayedInit(this);
+ initZoomToolbar();
+
+ QPixmap dummyPixmap; // any icon will do
+ m_mainDockWidget = createDockWidget("Rosegarden MainDockWidget", dummyPixmap, 0L, "main_dock_widget");
+ // allow others to dock to the left and right sides only
+ m_mainDockWidget->setDockSite(KDockWidget::DockLeft | KDockWidget::DockRight);
+ // forbit docking abilities of m_mainDockWidget itself
+ m_mainDockWidget->setEnableDocking(KDockWidget::DockNone);
+ setView(m_mainDockWidget); // central widget in a KDE mainwindow
+ setMainDockWidget(m_mainDockWidget); // master dockwidget
+
+ m_dockLeft = createDockWidget("params dock", dummyPixmap, 0L,
+ i18n("Special Parameters"));
+ m_dockLeft->manualDock(m_mainDockWidget, // dock target
+ KDockWidget::DockLeft, // dock site
+ 20); // relation target/this (in percent)
+
+ connect(m_dockLeft, SIGNAL(iMBeingClosed()),
+ this, SLOT(slotParametersClosed()));
+ connect(m_dockLeft, SIGNAL(hasUndocked()),
+ this, SLOT(slotParametersClosed()));
+ // Apparently, hasUndocked() is emitted when the dock widget's
+ // 'close' button on the dock handle is clicked.
+ connect(m_mainDockWidget, SIGNAL(docking(KDockWidget*, KDockWidget::DockPosition)),
+ this, SLOT(slotParametersDockedBack(KDockWidget*, KDockWidget::DockPosition)));
+
+ stateChanged("parametersbox_closed", KXMLGUIClient::StateReverse);
+
+ RosegardenGUIDoc* doc = new RosegardenGUIDoc(this, m_pluginManager);
+
+ m_parameterArea = new RosegardenParameterArea(m_dockLeft);
+ m_dockLeft->setWidget(m_parameterArea);
+
+ // Populate the parameter-box area with the respective
+ // parameter box widgets.
+
+ m_segmentParameterBox = new SegmentParameterBox(doc, m_parameterArea);
+ m_parameterArea->addRosegardenParameterBox(m_segmentParameterBox);
+ m_trackParameterBox = new TrackParameterBox(doc, m_parameterArea);
+ m_parameterArea->addRosegardenParameterBox(m_trackParameterBox);
+ m_instrumentParameterBox = new InstrumentParameterBox(doc, m_parameterArea);
+ m_parameterArea->addRosegardenParameterBox(m_instrumentParameterBox);
+
+ // Lookup the configuration parameter that specifies the default
+ // arrangement, and instantiate it.
+
+ kapp->config()->setGroup(GeneralOptionsConfigGroup);
+ m_parameterArea->setArrangement((RosegardenParameterArea::Arrangement)
+ kapp->config()->readUnsignedNumEntry("sidebarstyle",
+ RosegardenParameterArea::CLASSIC_STYLE));
+
+ m_dockLeft->update();
+
+ connect(m_instrumentParameterBox,
+ SIGNAL(selectPlugin(QWidget *, InstrumentId, int)),
+ this,
+ SLOT(slotShowPluginDialog(QWidget *, InstrumentId, int)));
+
+ connect(m_instrumentParameterBox,
+ SIGNAL(showPluginGUI(InstrumentId, int)),
+ this,
+ SLOT(slotShowPluginGUI(InstrumentId, int)));
+
+ // relay this through our own signal so that others can use it too
+ connect(m_instrumentParameterBox,
+ SIGNAL(instrumentParametersChanged(InstrumentId)),
+ this,
+ SIGNAL(instrumentParametersChanged(InstrumentId)));
+
+ connect(this,
+ SIGNAL(instrumentParametersChanged(InstrumentId)),
+ m_instrumentParameterBox,
+ SLOT(slotInstrumentParametersChanged(InstrumentId)));
+
+ connect(this,
+ SIGNAL(pluginSelected(InstrumentId, int, int)),
+ m_instrumentParameterBox,
+ SLOT(slotPluginSelected(InstrumentId, int, int)));
+
+ connect(this,
+ SIGNAL(pluginBypassed(InstrumentId, int, bool)),
+ m_instrumentParameterBox,
+ SLOT(slotPluginBypassed(InstrumentId, int, bool)));
+
+ // Load the initial document (this includes doc's own autoload)
+ //
+ setDocument(doc);
+
+ emit startupStatusMessage(i18n("Starting sequence manager..."));
+
+ // transport is created by setupActions()
+ m_seqManager = new SequenceManager(m_doc, getTransport());
+
+ if (m_useSequencer) {
+ // Check the sound driver status and warn the user of any
+ // problems. This warning has to happen early, in case it
+ // affects the ability to load plugins etc from a file on the
+ // command line.
+ m_seqManager->checkSoundDriverStatus(true);
+ }
+
+ if (m_view) {
+ connect(m_seqManager, SIGNAL(controllerDeviceEventReceived(MappedEvent *)),
+ m_view, SLOT(slotControllerDeviceEventReceived(MappedEvent *)));
+ }
+
+ if (m_seqManager->getSoundDriverStatus() & AUDIO_OK) {
+ slotStateChanged("got_audio", true);
+ } else {
+ slotStateChanged("got_audio", false);
+ }
+
+ // If we're restarting the gui then make sure any transient
+ // studio objects are cleared away.
+ emit startupStatusMessage(i18n("Clearing studio data..."));
+ m_seqManager->reinitialiseSequencerStudio();
+
+ // Send the transport control statuses for MMC and JACK
+ //
+ m_seqManager->sendTransportControlStatuses();
+
+ // Now autoload
+ //
+ stateChanged("new_file");
+ stateChanged("have_segments", KXMLGUIClient::StateReverse);
+ stateChanged("have_selection", KXMLGUIClient::StateReverse);
+ slotTestClipboard();
+
+ // Check for lack of MIDI devices and disable Studio options accordingly
+ //
+ if (!m_doc->getStudio().haveMidiDevices())
+ stateChanged("got_midi_devices", KXMLGUIClient::StateReverse);
+
+ emit startupStatusMessage(i18n("Starting..."));
+
+ setupFileDialogSpeedbar();
+ readOptions();
+
+ // All toolbars should be created before this is called
+ setAutoSaveSettings(MainWindowConfigGroup, true);
+
+#ifdef HAVE_LIRC
+
+ try {
+ m_lircClient = new LircClient();
+ } catch (Exception e) {
+ RG_DEBUG << e.getMessage().c_str() << endl;
+ // continue without
+ m_lircClient = 0;
+ }
+ if (m_lircClient) {
+ m_lircCommander = new LircCommander(m_lircClient, this);
+ }
+#endif
+
+ stateChanged("have_project_packager", KXMLGUIClient::StateReverse);
+ stateChanged("have_lilypondview", KXMLGUIClient::StateReverse);
+ QTimer::singleShot(1000, this, SLOT(slotTestStartupTester()));
+}
+
+RosegardenGUIApp::~RosegardenGUIApp()
+{
+ RG_DEBUG << "~RosegardenGUIApp()\n";
+
+ if (getView() &&
+ getView()->getTrackEditor() &&
+ getView()->getTrackEditor()->getSegmentCanvas()) {
+ getView()->getTrackEditor()->getSegmentCanvas()->endAudioPreviewGeneration();
+ }
+
+#ifdef HAVE_LIBLO
+ delete m_pluginGUIManager;
+#endif
+
+ if (isSequencerRunning() && !isSequencerExternal()) {
+ m_sequencerProcess->blockSignals(true);
+ rgapp->sequencerSend("quit()");
+ usleep(300000);
+ delete m_sequencerProcess;
+ }
+
+ delete m_jumpToQuickMarkerAction;
+ delete m_setQuickMarkerAction;
+
+ delete m_transport;
+
+ delete m_seqManager;
+
+#ifdef HAVE_LIRC
+
+ delete m_lircCommander;
+ delete m_lircClient;
+#endif
+
+ delete m_doc;
+ Profiles::getInstance()->dump();
+}
+
+void RosegardenGUIApp::setupActions()
+{
+ // setup File menu
+ // New Window ?
+ KStdAction::openNew (this, SLOT(slotFileNew()), actionCollection());
+ KStdAction::open (this, SLOT(slotFileOpen()), actionCollection());
+ m_fileRecent = KStdAction::openRecent(this,
+ SLOT(slotFileOpenRecent(const KURL&)),
+ actionCollection());
+ KStdAction::save (this, SLOT(slotFileSave()), actionCollection());
+ KStdAction::saveAs(this, SLOT(slotFileSaveAs()), actionCollection());
+ KStdAction::revert(this, SLOT(slotRevertToSaved()), actionCollection());
+ KStdAction::close (this, SLOT(slotFileClose()), actionCollection());
+ KStdAction::print (this, SLOT(slotFilePrint()), actionCollection());
+ KStdAction::printPreview (this, SLOT(slotFilePrintPreview()), actionCollection());
+
+ new KAction(i18n("Import Rosegarden &Project file..."), 0, 0, this,
+ SLOT(slotImportProject()), actionCollection(),
+ "file_import_project");
+
+ new KAction(i18n("Import &MIDI file..."), 0, 0, this,
+ SLOT(slotImportMIDI()), actionCollection(),
+ "file_import_midi");
+
+ new KAction(i18n("Import &Rosegarden 2.1 file..."), 0, 0, this,
+ SLOT(slotImportRG21()), actionCollection(),
+ "file_import_rg21");
+
+ new KAction(i18n("Import &Hydrogen file..."), 0, 0, this,
+ SLOT(slotImportHydrogen()), actionCollection(),
+ "file_import_hydrogen");
+
+ new KAction(i18n("Merge &File..."), 0, 0, this,
+ SLOT(slotMerge()), actionCollection(),
+ "file_merge");
+
+ new KAction(i18n("Merge &MIDI file..."), 0, 0, this,
+ SLOT(slotMergeMIDI()), actionCollection(),
+ "file_merge_midi");
+
+ new KAction(i18n("Merge &Rosegarden 2.1 file..."), 0, 0, this,
+ SLOT(slotMergeRG21()), actionCollection(),
+ "file_merge_rg21");
+
+ new KAction(i18n("Merge &Hydrogen file..."), 0, 0, this,
+ SLOT(slotMergeHydrogen()), actionCollection(),
+ "file_merge_hydrogen");
+
+ new KAction(i18n("Export Rosegarden &Project file..."), 0, 0, this,
+ SLOT(slotExportProject()), actionCollection(),
+ "file_export_project");
+
+ new KAction(i18n("Export &MIDI file..."), 0, 0, this,
+ SLOT(slotExportMIDI()), actionCollection(),
+ "file_export_midi");
+
+ new KAction(i18n("Export &LilyPond file..."), 0, 0, this,
+ SLOT(slotExportLilyPond()), actionCollection(),
+ "file_export_lilypond");
+
+ new KAction(i18n("Export Music&XML file..."), 0, 0, this,
+ SLOT(slotExportMusicXml()), actionCollection(),
+ "file_export_musicxml");
+
+ new KAction(i18n("Export &Csound score file..."), 0, 0, this,
+ SLOT(slotExportCsound()), actionCollection(),
+ "file_export_csound");
+
+ new KAction(i18n("Export M&up file..."), 0, 0, this,
+ SLOT(slotExportMup()), actionCollection(),
+ "file_export_mup");
+
+ new KAction(i18n("Print &with LilyPond..."), 0, 0, this,
+ SLOT(slotPrintLilyPond()), actionCollection(),
+ "file_print_lilypond");
+
+ new KAction(i18n("Preview with Lil&yPond..."), 0, 0, this,
+ SLOT(slotPreviewLilyPond()), actionCollection(),
+ "file_preview_lilypond");
+
+ new KAction(i18n("Play&list"), 0, 0, this,
+ SLOT(slotPlayList()), actionCollection(),
+ "file_show_playlist");
+
+ KStdAction::quit (this, SLOT(slotQuit()), actionCollection());
+
+ // help menu
+ new KAction(i18n("Rosegarden &Tutorial"), 0, 0, this,
+ SLOT(slotTutorial()), actionCollection(),
+ "tutorial");
+
+ new KAction(i18n("&Bug Reporting Guidelines"), 0, 0, this,
+ SLOT(slotBugGuidelines()), actionCollection(),
+ "guidelines");
+
+ // setup edit menu
+ KStdAction::cut (this, SLOT(slotEditCut()), actionCollection());
+ KStdAction::copy (this, SLOT(slotEditCopy()), actionCollection());
+ KStdAction::paste (this, SLOT(slotEditPaste()), actionCollection());
+
+ //
+ // undo/redo actions are special in that they are connected to
+ // slots later on, when the current document is set up - see
+ // MultiViewCommandHistory::attachView
+ //
+ new KToolBarPopupAction(i18n("Und&o"),
+ "undo",
+ KStdAccel::shortcut(KStdAccel::Undo),
+ actionCollection(),
+ KStdAction::stdName(KStdAction::Undo));
+
+ new KToolBarPopupAction(i18n("Re&do"),
+ "redo",
+ KStdAccel::shortcut(KStdAccel::Redo),
+ actionCollection(),
+ KStdAction::stdName(KStdAction::Redo));
+ /////
+
+
+
+ // setup Settings menu
+ //
+ m_viewToolBar = KStdAction::showToolbar (this, SLOT(slotToggleToolBar()), actionCollection(),
+ "show_stock_toolbar");
+
+ m_viewToolsToolBar = new KToggleAction(i18n("Show T&ools Toolbar"), 0, this,
+ SLOT(slotToggleToolsToolBar()), actionCollection(),
+ "show_tools_toolbar");
+
+ m_viewTracksToolBar = new KToggleAction(i18n("Show Trac&ks Toolbar"), 0, this,
+ SLOT(slotToggleTracksToolBar()), actionCollection(),
+ "show_tracks_toolbar");
+
+ m_viewEditorsToolBar = new KToggleAction(i18n("Show &Editors Toolbar"), 0, this,
+ SLOT(slotToggleEditorsToolBar()), actionCollection(),
+ "show_editors_toolbar");
+
+ m_viewTransportToolBar = new KToggleAction(i18n("Show Trans&port Toolbar"), 0, this,
+ SLOT(slotToggleTransportToolBar()), actionCollection(),
+ "show_transport_toolbar");
+
+ m_viewZoomToolBar = new KToggleAction(i18n("Show &Zoom Toolbar"), 0, this,
+ SLOT(slotToggleZoomToolBar()), actionCollection(),
+ "show_zoom_toolbar");
+
+ m_viewStatusBar = KStdAction::showStatusbar(this, SLOT(slotToggleStatusBar()),
+ actionCollection(), "show_status_bar");
+
+ m_viewTransport = new KToggleAction(i18n("Show Tra&nsport"), Key_T, this,
+ SLOT(slotToggleTransport()),
+ actionCollection(),
+ "show_transport");
+
+ m_viewTrackLabels = new KToggleAction(i18n("Show Track &Labels"), 0, this,
+ SLOT(slotToggleTrackLabels()),
+ actionCollection(),
+ "show_tracklabels");
+
+ m_viewRulers = new KToggleAction(i18n("Show Playback Position R&uler"), 0, this,
+ SLOT(slotToggleRulers()),
+ actionCollection(),
+ "show_rulers");
+
+ m_viewTempoRuler = new KToggleAction(i18n("Show Te&mpo Ruler"), 0, this,
+ SLOT(slotToggleTempoRuler()),
+ actionCollection(),
+ "show_tempo_ruler");
+
+ m_viewChordNameRuler = new KToggleAction(i18n("Show Cho&rd Name Ruler"), 0, this,
+ SLOT(slotToggleChordNameRuler()),
+ actionCollection(),
+ "show_chord_name_ruler");
+
+
+ m_viewPreviews = new KToggleAction(i18n("Show Segment Pre&views"), 0, this,
+ SLOT(slotTogglePreviews()),
+ actionCollection(),
+ "show_previews");
+
+ new KAction(i18n("Show Special &Parameters"), Key_P, this,
+ SLOT(slotDockParametersBack()),
+ actionCollection(),
+ "show_inst_segment_parameters");
+
+ KStdAction::tipOfDay( this, SLOT( slotShowTip() ), actionCollection() );
+
+ // Standard Actions
+ //
+ KStdAction::saveOptions(this,
+ SLOT(slotSaveOptions()),
+ actionCollection());
+
+ KStdAction::preferences(this,
+ SLOT(slotConfigure()),
+ actionCollection());
+
+ KStdAction::keyBindings(this,
+ SLOT(slotEditKeys()),
+ actionCollection());
+
+ KStdAction::configureToolbars(this,
+ SLOT(slotEditToolbars()),
+ actionCollection());
+
+ KRadioAction *action = 0;
+
+ // Create the select icon
+ //
+ QString pixmapDir = KGlobal::dirs()->findResource("appdata", "pixmaps/");
+ QCanvasPixmap pixmap(pixmapDir + "/toolbar/select.xpm");
+ QIconSet icon = QIconSet(pixmap);
+
+ // TODO : add some shortcuts here
+ action = new KRadioAction(i18n("&Select and Edit"), icon, Key_F2,
+ this, SLOT(slotPointerSelected()),
+ actionCollection(), "select");
+ action->setExclusiveGroup("segmenttools");
+
+ action = new KRadioAction(i18n("&Draw"), "pencil", Key_F3,
+ this, SLOT(slotDrawSelected()),
+ actionCollection(), "draw");
+ action->setExclusiveGroup("segmenttools");
+
+ action = new KRadioAction(i18n("&Erase"), "eraser", Key_F4,
+ this, SLOT(slotEraseSelected()),
+ actionCollection(), "erase");
+ action->setExclusiveGroup("segmenttools");
+
+ action = new KRadioAction(i18n("&Move"), "move", Key_F5,
+ this, SLOT(slotMoveSelected()),
+ actionCollection(), "move");
+ action->setExclusiveGroup("segmenttools");
+
+ pixmap.load(pixmapDir + "/toolbar/resize.xpm");
+ icon = QIconSet(pixmap);
+ action = new KRadioAction(i18n("&Resize"), icon, Key_F6,
+ this, SLOT(slotResizeSelected()),
+ actionCollection(), "resize");
+ action->setExclusiveGroup("segmenttools");
+
+ pixmap.load(pixmapDir + "/toolbar/split.xpm");
+ icon = QIconSet(pixmap);
+ action = new KRadioAction(i18n("&Split"), icon, Key_F7,
+ this, SLOT(slotSplitSelected()),
+ actionCollection(), "split");
+ action->setExclusiveGroup("segmenttools");
+
+ pixmap.load(pixmapDir + "/toolbar/join.xpm");
+ icon = QIconSet(pixmap);
+ action = new KRadioAction(i18n("&Join"), icon, 0,
+ this, SLOT(slotJoinSelected()),
+ actionCollection(), "join");
+ action->setExclusiveGroup("segmenttools");
+
+
+ new KAction(i18n("&Harmonize"), 0, this,
+ SLOT(slotHarmonizeSelection()), actionCollection(),
+ "harmonize_selection");
+
+ pixmap.load(pixmapDir + "/toolbar/event-insert-timesig.png");
+ icon = QIconSet(pixmap);
+ new KAction(AddTimeSignatureCommand::getGlobalName(),
+ icon, 0,
+ this, SLOT(slotEditTimeSignature()),
+ actionCollection(), "add_time_signature");
+
+ new KAction(i18n("Open Tempo and Time Signature Editor"), 0, this,
+ SLOT(slotEditTempos()), actionCollection(), "edit_tempos");
+
+ //
+ // Edit menu
+ //
+ new KAction(i18n("Cut Range"), Key_X + CTRL + SHIFT, this,
+ SLOT(slotCutRange()), actionCollection(),
+ "cut_range");
+
+ new KAction(i18n("Copy Range"), Key_C + CTRL + SHIFT, this,
+ SLOT(slotCopyRange()), actionCollection(),
+ "copy_range");
+
+ new KAction(i18n("Paste Range"), Key_V + CTRL + SHIFT, this,
+ SLOT(slotPasteRange()), actionCollection(),
+ "paste_range");
+/*
+ new KAction(i18n("Delete Range"), Key_Delete + SHIFT, this,
+ SLOT(slotDeleteRange()), actionCollection(),
+ "delete_range");
+*/
+ new KAction(i18n("Insert Range..."), Key_Insert + SHIFT, this,
+ SLOT(slotInsertRange()), actionCollection(),
+ "insert_range");
+
+ new KAction(i18n("De&lete"), Key_Delete, this,
+ SLOT(slotDeleteSelectedSegments()), actionCollection(),
+ "delete");
+
+ new KAction(i18n("Select &All Segments"), Key_A + CTRL, this,
+ SLOT(slotSelectAll()), actionCollection(),
+ "select_all");
+
+ pixmap.load(pixmapDir + "/toolbar/event-insert-tempo.png");
+ icon = QIconSet(pixmap);
+ new KAction(AddTempoChangeCommand::getGlobalName(),
+ icon, 0,
+ this, SLOT(slotEditTempo()),
+ actionCollection(), "add_tempo");
+
+ new KAction(ChangeCompositionLengthCommand::getGlobalName(),
+ 0,
+ this, SLOT(slotChangeCompositionLength()),
+ actionCollection(), "change_composition_length");
+
+ new KAction(i18n("Edit Mar&kers..."), Key_K + CTRL, this,
+ SLOT(slotEditMarkers()),
+ actionCollection(), "edit_markers");
+
+ new KAction(i18n("Edit Document P&roperties..."), 0, this,
+ SLOT(slotEditDocumentProperties()),
+ actionCollection(), "edit_doc_properties");
+
+
+ //
+ // Segments menu
+ //
+ new KAction(i18n("Open in &Default Editor"), Key_Return, this,
+ SLOT(slotEdit()), actionCollection(),
+ "edit_default");
+
+ pixmap.load(pixmapDir + "/toolbar/matrix.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Open in Matri&x Editor"), icon, Key_M, this,
+ SLOT(slotEditInMatrix()), actionCollection(),
+ "edit_matrix");
+
+ pixmap.load(pixmapDir + "/toolbar/matrix-percussion.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Open in &Percussion Matrix Editor"), icon, Key_D, this,
+ SLOT(slotEditInPercussionMatrix()), actionCollection(),
+ "edit_percussion_matrix");
+
+ pixmap.load(pixmapDir + "/toolbar/notation.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Open in &Notation Editor"), icon, Key_N, this,
+ SLOT(slotEditAsNotation()), actionCollection(),
+ "edit_notation");
+
+ pixmap.load(pixmapDir + "/toolbar/eventlist.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Open in &Event List Editor"), icon, Key_E, this,
+ SLOT(slotEditInEventList()), actionCollection(),
+ "edit_event_list");
+
+ pixmap.load(pixmapDir + "/toolbar/quantize.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("&Quantize..."), icon, Key_Equal, this,
+ SLOT(slotQuantizeSelection()), actionCollection(),
+ "quantize_selection");
+
+ new KAction(SegmentLabelCommand::getGlobalName(),
+ 0,
+ this, SLOT(slotRelabelSegments()),
+ actionCollection(), "relabel_segment");
+
+ new KAction(SegmentTransposeCommand::getGlobalName(),
+ 0,
+ this, SLOT(slotTransposeSegments()),
+ actionCollection(), "transpose");
+
+ new KAction(i18n("Repeat Last Quantize"), Key_Plus, this,
+ SLOT(slotRepeatQuantizeSelection()), actionCollection(),
+ "repeat_quantize");
+
+ new KAction(SegmentRescaleCommand::getGlobalName(), 0, this,
+ SLOT(slotRescaleSelection()), actionCollection(),
+ "rescale");
+
+ new KAction(SegmentAutoSplitCommand::getGlobalName(), 0, this,
+ SLOT(slotAutoSplitSelection()), actionCollection(),
+ "auto_split");
+
+ new KAction(SegmentSplitByPitchCommand::getGlobalName(), 0, this,
+ SLOT(slotSplitSelectionByPitch()), actionCollection(),
+ "split_by_pitch");
+
+ new KAction(SegmentSplitByRecordingSrcCommand::getGlobalName(), 0, this,
+ SLOT(slotSplitSelectionByRecordedSrc()), actionCollection(),
+ "split_by_recording");
+
+ new KAction(i18n("Split at Time..."), 0, this,
+ SLOT(slotSplitSelectionAtTime()), actionCollection(),
+ "split_at_time");
+
+ new KAction(i18n("Jog &Left"), Key_Left + ALT, this,
+ SLOT(slotJogLeft()), actionCollection(),
+ "jog_left");
+
+ new KAction(i18n("Jog &Right"), Key_Right + ALT, this,
+ SLOT(slotJogRight()), actionCollection(),
+ "jog_right");
+
+ new KAction(i18n("Set Start Time..."), 0, this,
+ SLOT(slotSetSegmentStartTimes()), actionCollection(),
+ "set_segment_start");
+
+ new KAction(i18n("Set Duration..."), 0, this,
+ SLOT(slotSetSegmentDurations()), actionCollection(),
+ "set_segment_duration");
+
+ new KAction(SegmentJoinCommand::getGlobalName(),
+ Key_J + CTRL,
+ this, SLOT(slotJoinSegments()),
+ actionCollection(), "join_segments");
+
+ new KAction(i18n("Turn Re&peats into Copies"),
+ 0,
+ this, SLOT(slotRepeatingSegments()),
+ actionCollection(), "repeats_to_real_copies");
+
+ new KAction(i18n("Manage Tri&ggered Segments"), 0,
+ this, SLOT(slotManageTriggerSegments()),
+ actionCollection(), "manage_trigger_segments");
+
+ new KAction(i18n("Set Tempos from &Beat Segment"), 0, this,
+ SLOT(slotGrooveQuantize()), actionCollection(),
+ "groove_quantize");
+
+ new KAction(i18n("Set &Tempo to Audio Segment Duration"), 0, this,
+ SLOT(slotTempoToSegmentLength()), actionCollection(),
+ "set_tempo_to_segment_length");
+
+ pixmap.load(pixmapDir + "/toolbar/manage-audio-segments.xpm");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Manage A&udio Files"), icon,
+ Key_U + CTRL,
+ this, SLOT(slotAudioManager()),
+ actionCollection(), "audio_manager");
+
+ m_viewSegmentLabels = new KToggleAction(i18n("Show Segment Labels"), 0, this,
+ SLOT(slotToggleSegmentLabels()), actionCollection(),
+ "show_segment_labels");
+
+ //
+ // Tracks menu
+ //
+ pixmap.load(pixmapDir + "/toolbar/add_tracks.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Add &Track"), icon, CTRL + Key_T,
+ this, SLOT(slotAddTrack()),
+ actionCollection(), "add_track");
+
+ new KAction(i18n("&Add Tracks..."), 0,
+ this, SLOT(slotAddTracks()),
+ actionCollection(), "add_tracks");
+
+ pixmap.load(pixmapDir + "/toolbar/delete_track.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("D&elete Track"), icon, CTRL + Key_D,
+ this, SLOT(slotDeleteTrack()),
+ actionCollection(), "delete_track");
+
+ pixmap.load(pixmapDir + "/toolbar/move_track_down.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Move Track &Down"), icon, SHIFT + Key_Down,
+ this, SLOT(slotMoveTrackDown()),
+ actionCollection(), "move_track_down");
+
+ pixmap.load(pixmapDir + "/toolbar/move_track_up.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Move Track &Up"), icon, SHIFT + Key_Up,
+ this, SLOT(slotMoveTrackUp()),
+ actionCollection(), "move_track_up");
+
+ new KAction(i18n("Select &Next Track"),
+ Key_Down,
+ this, SLOT(slotTrackDown()),
+ actionCollection(), "select_next_track");
+
+ new KAction(i18n("Select &Previous Track"),
+ Key_Up,
+ this, SLOT(slotTrackUp()),
+ actionCollection(), "select_previous_track");
+
+ new KAction(i18n("Mute or Unmute Track"),
+ Key_U,
+ this, SLOT(slotToggleMutedCurrentTrack()),
+ actionCollection(), "toggle_mute_track");
+
+ new KAction(i18n("Arm or Un-arm Track for Record"),
+ Key_R,
+ this, SLOT(slotToggleRecordCurrentTrack()),
+ actionCollection(), "toggle_arm_track");
+
+ pixmap.load(pixmapDir + "/toolbar/mute-all.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("&Mute all Tracks"), icon, 0,
+ this, SLOT(slotMuteAllTracks()),
+ actionCollection(), "mute_all_tracks");
+
+ pixmap.load(pixmapDir + "/toolbar/un-mute-all.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("&Unmute all Tracks"), icon, 0,
+ this, SLOT(slotUnmuteAllTracks()),
+ actionCollection(), "unmute_all_tracks");
+
+ new KAction(i18n("&Remap Instruments..."), 0, this,
+ SLOT(slotRemapInstruments()),
+ actionCollection(), "remap_instruments");
+
+ //
+ // Studio menu
+ //
+ pixmap.load(pixmapDir + "/toolbar/mixer.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("&Audio Mixer"), icon, 0, this,
+ SLOT(slotOpenAudioMixer()),
+ actionCollection(), "audio_mixer");
+
+ pixmap.load(pixmapDir + "/toolbar/midimixer.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Midi Mi&xer"), icon, 0, this,
+ SLOT(slotOpenMidiMixer()),
+ actionCollection(), "midi_mixer");
+
+ pixmap.load(pixmapDir + "/toolbar/manage-midi-devices.xpm");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Manage MIDI &Devices"), icon, 0, this,
+ SLOT(slotManageMIDIDevices()),
+ actionCollection(), "manage_devices");
+
+ pixmap.load(pixmapDir + "/toolbar/manage-synth-plugins.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Manage S&ynth Plugins"), icon, 0, this,
+ SLOT(slotManageSynths()),
+ actionCollection(), "manage_synths");
+
+ new KAction(i18n("Modify MIDI &Filters"), "filter", 0, this,
+ SLOT(slotModifyMIDIFilters()),
+ actionCollection(), "modify_midi_filters");
+
+ m_enableMIDIrouting = new KToggleAction(i18n("MIDI Thru Routing"), 0, this,
+ SLOT(slotEnableMIDIThruRouting()),
+ actionCollection(), "enable_midi_routing");
+
+ pixmap.load(pixmapDir + "/toolbar/time-musical.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Manage &Metronome"), 0, this,
+ SLOT(slotManageMetronome()),
+ actionCollection(), "manage_metronome");
+
+ new KAction(i18n("&Save Current Document as Default Studio"), 0, this,
+ SLOT(slotSaveDefaultStudio()),
+ actionCollection(), "save_default_studio");
+
+ new KAction(i18n("&Import Default Studio"), 0, this,
+ SLOT(slotImportDefaultStudio()),
+ actionCollection(), "load_default_studio");
+
+ new KAction(i18n("Im&port Studio from File..."), 0, this,
+ SLOT(slotImportStudio()),
+ actionCollection(), "load_studio");
+
+ new KAction(i18n("&Reset MIDI Network"), 0, this,
+ SLOT(slotResetMidiNetwork()),
+ actionCollection(), "reset_midi_network");
+
+ m_setQuickMarkerAction = new KAction(i18n("Set Quick Marker at Playback Position"), 0, CTRL + Key_1, this,
+ SLOT(slotSetQuickMarker()), actionCollection(),
+ "set_quick_marker");
+
+ m_jumpToQuickMarkerAction = new KAction(i18n("Jump to Quick Marker"), 0, Key_1, this,
+ SLOT(slotJumpToQuickMarker()), actionCollection(),
+ "jump_to_quick_marker");
+
+ //
+ // Marker Ruler popup menu
+ //
+// new KAction(i18n("Insert Marker"), 0, 0, this,
+// SLOT(slotInsertMarkerHere()), actionCollection(),
+// "insert_marker_here");
+//
+// new KAction(i18n("Insert Marker at Playback Position"), 0, 0, this,
+// SLOT(slotInsertMarkerAtPointer()), actionCollection(),
+// "insert_marker_at_pointer");
+//
+// new KAction(i18n("Delete Marker"), 0, 0, this,
+// SLOT(slotDeleteMarker()), actionCollection(),
+// "delete_marker");
+
+
+
+ //
+ // Transport menu
+ //
+
+ // Transport controls [rwb]
+ //
+ // We set some default key bindings - with numlock off
+ // use 1 (End) and 3 (Page Down) for Rwd and Ffwd and
+ // 0 (insert) and keypad Enter for Play and Stop
+ //
+ pixmap.load(pixmapDir + "/toolbar/transport-play.png");
+ icon = QIconSet(pixmap);
+ m_playTransport = new KAction(i18n("&Play"), icon, Key_Enter, this,
+ SLOT(slotPlay()), actionCollection(),
+ "play");
+ // Alternative shortcut for Play
+ KShortcut playShortcut = m_playTransport->shortcut();
+ playShortcut.append( KKey(Key_Return + CTRL) );
+ m_playTransport->setShortcut(playShortcut);
+ m_playTransport->setGroup(TransportDialogConfigGroup);
+
+ pixmap.load(pixmapDir + "/toolbar/transport-stop.png");
+ icon = QIconSet(pixmap);
+ m_stopTransport = new KAction(i18n("&Stop"), icon, Key_Insert, this,
+ SLOT(slotStop()), actionCollection(),
+ "stop");
+ m_stopTransport->setGroup(TransportDialogConfigGroup);
+
+ pixmap.load(pixmapDir + "/toolbar/transport-ffwd.png");
+ icon = QIconSet(pixmap);
+ m_ffwdTransport = new KAction(i18n("&Fast Forward"), icon, Key_PageDown,
+ this,
+ SLOT(slotFastforward()), actionCollection(),
+ "fast_forward");
+ m_ffwdTransport->setGroup(TransportDialogConfigGroup);
+
+ pixmap.load(pixmapDir + "/toolbar/transport-rewind.png");
+ icon = QIconSet(pixmap);
+ m_rewindTransport = new KAction(i18n("Re&wind"), icon, Key_End, this,
+ SLOT(slotRewind()), actionCollection(),
+ "rewind");
+ m_rewindTransport->setGroup(TransportDialogConfigGroup);
+
+ pixmap.load(pixmapDir + "/toolbar/transport-record.png");
+ icon = QIconSet(pixmap);
+ m_recordTransport = new KAction(i18n("P&unch in Record"), icon, Key_Space, this,
+ SLOT(slotToggleRecord()), actionCollection(),
+ "recordtoggle");
+ m_recordTransport->setGroup(TransportDialogConfigGroup);
+
+ pixmap.load(pixmapDir + "/toolbar/transport-record.png");
+ icon = QIconSet(pixmap);
+ m_recordTransport = new KAction(i18n("&Record"), icon, 0, this,
+ SLOT(slotRecord()), actionCollection(),
+ "record");
+ m_recordTransport->setGroup(TransportDialogConfigGroup);
+
+ pixmap.load(pixmapDir + "/toolbar/transport-rewind-end.png");
+ icon = QIconSet(pixmap);
+ m_rewindEndTransport = new KAction(i18n("Rewind to &Beginning"), icon, 0, this,
+ SLOT(slotRewindToBeginning()), actionCollection(),
+ "rewindtobeginning");
+ m_rewindEndTransport->setGroup(TransportDialogConfigGroup);
+
+ pixmap.load(pixmapDir + "/toolbar/transport-ffwd-end.png");
+ icon = QIconSet(pixmap);
+ m_ffwdEndTransport = new KAction(i18n("Fast Forward to &End"), icon, 0, this,
+ SLOT(slotFastForwardToEnd()), actionCollection(),
+ "fastforwardtoend");
+ m_ffwdEndTransport->setGroup(TransportDialogConfigGroup);
+
+ pixmap.load(pixmapDir + "/toolbar/transport-tracking.png");
+ icon = QIconSet(pixmap);
+ (new KToggleAction(i18n("Scro&ll to Follow Playback"), icon, Key_Pause, this,
+ SLOT(slotToggleTracking()), actionCollection(),
+ "toggle_tracking"))->setChecked(true);
+
+ pixmap.load(pixmapDir + "/toolbar/transport-panic.png");
+ icon = QIconSet(pixmap);
+ new KAction( i18n("Panic"), icon, Key_P + CTRL + ALT, this, SLOT(slotPanic()),
+ actionCollection(), "panic");
+
+ // DEBUG FACILITY
+ new KAction(i18n("Segment Debug Dump "), 0, this,
+ SLOT(slotDebugDump()), actionCollection(),
+ "debug_dump_segments");
+
+ // create main gui
+ //
+ createGUI("rosegardenui.rc", false);
+
+ createAndSetupTransport();
+
+ // transport toolbar is hidden by default - TODO : this should be in options
+ //
+ //toolBar("Transport Toolbar")->hide();
+
+ QPopupMenu* setTrackInstrumentMenu = dynamic_cast<QPopupMenu*>(factory()->container("set_track_instrument", this));
+
+ if (setTrackInstrumentMenu) {
+ connect(setTrackInstrumentMenu, SIGNAL(aboutToShow()),
+ this, SLOT(slotPopulateTrackInstrumentPopup()));
+ } else {
+ RG_DEBUG << "RosegardenGUIApp::setupActions() : couldn't find set_track_instrument menu - check rosegardenui.rcn\n";
+ }
+
+ setRewFFwdToAutoRepeat();
+}
+
+void RosegardenGUIApp::setRewFFwdToAutoRepeat()
+{
+ QWidget* transportToolbar = factory()->container("Transport Toolbar", this);
+
+ if (transportToolbar) {
+ QObjectList *l = transportToolbar->queryList();
+ QObjectListIt it(*l); // iterate over the buttons
+ QObject *obj;
+
+ while ( (obj = it.current()) != 0 ) {
+ // for each found object...
+ ++it;
+ // RG_DEBUG << "obj name : " << obj->name() << endl;
+ QString objName = obj->name();
+
+ if (objName.endsWith("rewind") || objName.endsWith("fast_forward")) {
+ QButton* btn = dynamic_cast<QButton*>(obj);
+ if (!btn) {
+ RG_DEBUG << "Very strange - found widgets in transport_toolbar which aren't buttons\n";
+
+ continue;
+ }
+ btn->setAutoRepeat(true);
+ }
+
+
+ }
+ delete l;
+
+ } else {
+ RG_DEBUG << "transportToolbar == 0\n";
+ }
+
+}
+
+void RosegardenGUIApp::initZoomToolbar()
+{
+ KToolBar *zoomToolbar = toolBar("Zoom Toolbar");
+ if (!zoomToolbar) {
+ RG_DEBUG << "RosegardenGUIApp::initZoomToolbar() : "
+ << "zoom toolbar not found" << endl;
+ return ;
+ }
+
+ new QLabel(i18n(" Zoom: "), zoomToolbar, "kde toolbar widget");
+
+ std::vector<double> zoomSizes; // in units-per-pixel
+ double defaultBarWidth44 = 100.0;
+ double duration44 = TimeSignature(4, 4).getBarDuration();
+ static double factors[] = { 0.025, 0.05, 0.1, 0.2, 0.5,
+ 1.0, 1.5, 2.5, 5.0, 10.0 , 20.0 };
+
+ for (unsigned int i = 0; i < sizeof(factors) / sizeof(factors[0]); ++i) {
+ zoomSizes.push_back(duration44 / (defaultBarWidth44 * factors[i]));
+ }
+
+ // zoom labels
+ QString minZoom = QString("%1%").arg(factors[0] * 100.0);
+ QString maxZoom = QString("%1%").arg(factors[(sizeof(factors) / sizeof(factors[0])) - 1] * 100.0);
+
+ m_zoomSlider = new ZoomSlider<double>
+ (zoomSizes, -1, QSlider::Horizontal, zoomToolbar, "kde toolbar widget");
+ m_zoomSlider->setTracking(true);
+ m_zoomSlider->setFocusPolicy(QWidget::NoFocus);
+ m_zoomLabel = new QLabel(minZoom, zoomToolbar, "kde toolbar widget");
+ m_zoomLabel->setIndent(10);
+
+ connect(m_zoomSlider, SIGNAL(valueChanged(int)),
+ this, SLOT(slotChangeZoom(int)));
+
+ // set initial zoom - we might want to make this a config option
+ // m_zoomSlider->setToDefault();
+
+}
+
+void RosegardenGUIApp::initStatusBar()
+{
+ KTmpStatusMsg::setDefaultMsg("");
+ statusBar()->insertItem(KTmpStatusMsg::getDefaultMsg(),
+ KTmpStatusMsg::getDefaultId(), 1);
+ statusBar()->setItemAlignment(KTmpStatusMsg::getDefaultId(),
+ AlignLeft | AlignVCenter);
+
+ m_progressBar = new ProgressBar(100, true, statusBar());
+ // m_progressBar->setMinimumWidth(100);
+ m_progressBar->setFixedWidth(60);
+ m_progressBar->setFixedHeight(18);
+ m_progressBar->setTextEnabled(false);
+ statusBar()->addWidget(m_progressBar);
+}
+
+void RosegardenGUIApp::initView()
+{
+ ////////////////////////////////////////////////////////////////////
+ // create the main widget here that is managed by KTMainWindow's view-region and
+ // connect the widget to your document to display document contents.
+
+ RG_DEBUG << "RosegardenGUIApp::initView()" << endl;
+
+ Composition &comp = m_doc->getComposition();
+
+ // Ensure that the start and end markers for the piece are set
+ // to something reasonable
+ //
+ if (comp.getStartMarker() == 0 &&
+ comp.getEndMarker() == 0) {
+ int endMarker = comp.getBarRange(100 + comp.getNbBars()).second;
+ comp.setEndMarker(endMarker);
+ }
+
+ m_swapView = new RosegardenGUIView(m_viewTrackLabels->isChecked(),
+ m_segmentParameterBox,
+ m_instrumentParameterBox,
+ m_trackParameterBox, this);
+
+ // Connect up this signal so that we can force tool mode
+ // changes from the view
+ connect(m_swapView, SIGNAL(activateTool(QString)),
+ this, SLOT(slotActivateTool(QString)));
+
+ connect(m_swapView,
+ SIGNAL(segmentsSelected(const SegmentSelection &)),
+ SIGNAL(segmentsSelected(const SegmentSelection &)));
+
+ connect(m_swapView,
+ SIGNAL(addAudioFile(AudioFileId)),
+ SLOT(slotAddAudioFile(AudioFileId)));
+
+ connect(m_swapView, SIGNAL(toggleSolo(bool)), SLOT(slotToggleSolo(bool)));
+
+ m_doc->attachView(m_swapView);
+
+ m_mainDockWidget->setWidget(m_swapView);
+
+ // setCentralWidget(m_swapView);
+ setCaption(m_doc->getTitle());
+
+
+ // Transport setup
+ //
+ std::string transportMode = m_doc->getConfiguration().
+ get
+ <String>
+ (DocumentConfiguration::TransportMode);
+
+
+ slotEnableTransport(true);
+
+ // and the time signature
+ //
+ getTransport()->setTimeSignature(comp.getTimeSignatureAt(comp.getPosition()));
+
+ // set the tempo in the transport
+ //
+ getTransport()->setTempo(comp.getCurrentTempo());
+
+ // bring the transport to the front
+ //
+ getTransport()->raise();
+
+ // set the play metronome button
+ getTransport()->MetronomeButton()->setOn(comp.usePlayMetronome());
+
+ // Set the solo button
+ getTransport()->SoloButton()->setOn(comp.isSolo());
+
+ // set the transport mode found in the configuration
+ getTransport()->setNewMode(transportMode);
+
+ // set the pointer position
+ //
+ slotSetPointerPosition(m_doc->getComposition().getPosition());
+
+ // make sure we show
+ //
+ RosegardenGUIView *oldView = m_view;
+ m_view = m_swapView;
+
+ connect(m_view, SIGNAL(stateChange(QString, bool)),
+ this, SLOT (slotStateChanged(QString, bool)));
+
+ connect(m_view, SIGNAL(instrumentParametersChanged(InstrumentId)),
+ this, SIGNAL(instrumentParametersChanged(InstrumentId)));
+
+ // We only check for the SequenceManager to make sure
+ // we're not on the first pass though - we don't want
+ // to send these toggles twice on initialisation.
+ //
+ // Clunky but we just about get away with it for the
+ // moment.
+ //
+ if (m_seqManager != 0) {
+ slotToggleChordNameRuler();
+ slotToggleRulers();
+ slotToggleTempoRuler();
+ slotTogglePreviews();
+ slotToggleSegmentLabels();
+
+ // Reset any loop on the sequencer
+ //
+ try {
+ if (isUsingSequencer())
+ m_seqManager->setLoop(0, 0);
+ stateChanged("have_range", KXMLGUIClient::StateReverse);
+ } catch (QString s) {
+ KStartupLogo::hideIfStillThere();
+ CurrentProgressDialog::freeze();
+ KMessageBox::error(this, s);
+ CurrentProgressDialog::thaw();
+ }
+
+ connect(m_seqManager, SIGNAL(controllerDeviceEventReceived(MappedEvent *)),
+ m_view, SLOT(slotControllerDeviceEventReceived(MappedEvent *)));
+ }
+
+ // delete m_playList;
+ // m_playList = 0;
+
+ delete m_deviceManager;
+ m_deviceManager = 0;
+
+ delete m_synthManager;
+ m_synthManager = 0;
+
+ delete m_audioMixer;
+ m_audioMixer = 0;
+
+ delete m_bankEditor;
+ m_bankEditor = 0;
+
+ delete m_markerEditor;
+ m_markerEditor = 0;
+
+ delete m_tempoView;
+ m_tempoView = 0;
+
+ delete m_triggerSegmentManager;
+ m_triggerSegmentManager = 0;
+
+ delete oldView;
+
+ // set the highlighted track
+ m_view->slotSelectTrackSegments(comp.getSelectedTrack());
+
+ // play tracking on in the editor by default: turn off if need be
+ KToggleAction *trackingAction = dynamic_cast<KToggleAction *>
+ (actionCollection()->action("toggle_tracking"));
+ if (trackingAction && !trackingAction->isChecked()) {
+ m_view->getTrackEditor()->slotToggleTracking();
+ }
+
+ m_view->show();
+
+ connect(m_view->getTrackEditor()->getSegmentCanvas(),
+ SIGNAL(showContextHelp(const QString &)),
+ this,
+ SLOT(slotShowToolHelp(const QString &)));
+
+ // We have to do this to make sure that the 2nd call ("select")
+ // actually has any effect. Activating the same radio action
+ // doesn't work the 2nd time (like pressing down the same radio
+ // button twice - it doesn't have any effect), so if you load two
+ // files in a row, on the 2nd file a new SegmentCanvas will be
+ // created but its tool won't be set, even though it will appear
+ // to be selected.
+ //
+ actionCollection()->action("move")->activate();
+ if (m_doc->getComposition().getNbSegments() > 0)
+ actionCollection()->action("select")->activate();
+ else
+ actionCollection()->action("draw")->activate();
+
+ int zoomLevel = m_doc->getConfiguration().
+ get
+ <Int>
+ (DocumentConfiguration::ZoomLevel);
+
+ m_zoomSlider->setSize(double(zoomLevel) / 1000.0);
+ slotChangeZoom(zoomLevel);
+
+ //slotChangeZoom(int(m_zoomSlider->getCurrentSize()));
+
+ stateChanged("new_file");
+
+ ProgressDialog::processEvents();
+
+ if (m_viewChordNameRuler->isChecked()) {
+ SetWaitCursor swc;
+ m_view->initChordNameRuler();
+ } else {
+ m_view->initChordNameRuler();
+ }
+}
+
+void RosegardenGUIApp::setDocument(RosegardenGUIDoc* newDocument)
+{
+ if (m_doc == newDocument)
+ return ;
+
+ emit documentAboutToChange();
+ kapp->processEvents(); // to make sure all opened dialogs (mixer, midi devices...) are closed
+
+ // Take care of all subparts which depend on the document
+
+ // Caption
+ //
+ QString caption = kapp->caption();
+ setCaption(caption + ": " + newDocument->getTitle());
+
+ // // reset AudioManagerDialog
+ // //
+ // delete m_audioManagerDialog; // TODO : replace this with a connection to documentAboutToChange() sig.
+ // m_audioManagerDialog = 0;
+
+ RosegardenGUIDoc* oldDoc = m_doc;
+
+ m_doc = newDocument;
+
+ if (m_seqManager) // when we're called at startup, the seq. man. isn't created yet
+ m_seqManager->setDocument(m_doc);
+
+ if (m_markerEditor)
+ m_markerEditor->setDocument(m_doc);
+ if (m_tempoView) {
+ delete m_tempoView;
+ m_tempoView = 0;
+ }
+ if (m_triggerSegmentManager)
+ m_triggerSegmentManager->setDocument(m_doc);
+
+ m_trackParameterBox->setDocument(m_doc);
+ m_segmentParameterBox->setDocument(m_doc);
+ m_instrumentParameterBox->setDocument(m_doc);
+
+#ifdef HAVE_LIBLO
+
+ if (m_pluginGUIManager) {
+ m_pluginGUIManager->stopAllGUIs();
+ m_pluginGUIManager->setStudio(&m_doc->getStudio());
+ }
+#endif
+
+ if (getView() &&
+ getView()->getTrackEditor() &&
+ getView()->getTrackEditor()->getSegmentCanvas()) {
+ getView()->getTrackEditor()->getSegmentCanvas()->endAudioPreviewGeneration();
+ }
+
+ // this will delete all edit views
+ //
+ delete oldDoc;
+
+ // connect needed signals
+ //
+ connect(m_segmentParameterBox, SIGNAL(documentModified()),
+ m_doc, SLOT(slotDocumentModified()));
+
+ connect(m_doc, SIGNAL(pointerPositionChanged(timeT)),
+ this, SLOT(slotSetPointerPosition(timeT)));
+
+ connect(m_doc, SIGNAL(documentModified(bool)),
+ this, SLOT(slotDocumentModified(bool)));
+
+ connect(m_doc, SIGNAL(loopChanged(timeT, timeT)),
+ this, SLOT(slotSetLoop(timeT, timeT)));
+
+ m_doc->getCommandHistory()->attachView(actionCollection());
+
+ connect(m_doc->getCommandHistory(), SIGNAL(commandExecuted()),
+ SLOT(update()));
+ connect(m_doc->getCommandHistory(), SIGNAL(commandExecuted()),
+ SLOT(slotTestClipboard()));
+
+ // connect and start the autosave timer
+ connect(m_autoSaveTimer, SIGNAL(timeout()), this, SLOT(slotAutoSave()));
+ m_autoSaveTimer->start(m_doc->getAutoSavePeriod() * 1000);
+
+ // Connect the playback timer
+ //
+ connect(m_playTimer, SIGNAL(timeout()), this, SLOT(slotUpdatePlaybackPosition()));
+ connect(m_stopTimer, SIGNAL(timeout()), this, SLOT(slotUpdateMonitoring()));
+
+ // finally recreate the main view
+ //
+ initView();
+
+ if (getView() && getView()->getTrackEditor()) {
+ connect(m_doc, SIGNAL(makeTrackVisible(int)),
+ getView()->getTrackEditor(), SLOT(slotScrollToTrack(int)));
+ }
+
+ connect(m_doc, SIGNAL(devicesResyncd()),
+ this, SLOT(slotDocumentDevicesResyncd()));
+
+ m_doc->syncDevices();
+ m_doc->clearModifiedStatus();
+
+ if (newDocument->getStudio().haveMidiDevices()) {
+ stateChanged("got_midi_devices");
+ } else {
+ stateChanged("got_midi_devices", KXMLGUIClient::StateReverse);
+ }
+
+ // Ensure the sequencer knows about any audio files
+ // we've loaded as part of the new Composition
+ //
+ m_doc->prepareAudio();
+
+ // Do not reset instrument prog. changes after all.
+ // if (m_seqManager)
+ // m_seqManager->preparePlayback(true);
+
+ Composition &comp = m_doc->getComposition();
+
+ // Set any loaded loop at the Composition and
+ // on the marker on SegmentCanvas and clients
+ //
+ if (m_seqManager)
+ m_doc->setLoop(comp.getLoopStart(), comp.getLoopEnd());
+
+ emit documentChanged(m_doc);
+
+ m_doc->clearModifiedStatus(); // because it's set as modified by the various
+ // init operations
+ // TODO: this sucks, have to sort it out somehow.
+
+ // Readjust canvas size
+ //
+ m_view->getTrackEditor()->slotReadjustCanvasSize();
+
+ m_stopTimer->start(100);
+}
+
+void
+RosegardenGUIApp::openFile(QString filePath, ImportType type)
+{
+ RG_DEBUG << "RosegardenGUIApp::openFile " << filePath << endl;
+
+ if (type == ImportCheckType && filePath.endsWith(".rgp")) {
+ importProject(filePath);
+ return ;
+ }
+
+ RosegardenGUIDoc *doc = createDocument(filePath, type);
+ if (doc) {
+ setDocument(doc);
+
+ // fix # 1235755, "SPB combo not updating after document swap"
+ RG_DEBUG << "RosegardenGUIApp::openFile(): calling slotDocColoursChanged() in doc" << endl;
+ doc->slotDocColoursChanged();
+
+ kapp->config()->setGroup(GeneralOptionsConfigGroup);
+ if (kapp->config()->readBoolEntry("alwaysusedefaultstudio", false)) {
+
+ QString autoloadFile =
+ KGlobal::dirs()->findResource("appdata", "autoload.rg");
+
+ QFileInfo autoloadFileInfo(autoloadFile);
+ if (autoloadFileInfo.isReadable()) {
+
+ RG_DEBUG << "Importing default studio from " << autoloadFile << endl;
+
+ slotImportStudioFromFile(autoloadFile);
+ }
+ }
+
+ QFileInfo fInfo(filePath);
+ m_fileRecent->addURL(fInfo.absFilePath());
+ }
+}
+
+RosegardenGUIDoc*
+RosegardenGUIApp::createDocument(QString filePath, ImportType importType)
+{
+ QFileInfo info(filePath);
+ RosegardenGUIDoc *doc = 0;
+
+ if (!info.exists()) {
+ // can happen with command-line arg, so...
+ KStartupLogo::hideIfStillThere();
+ KMessageBox::sorry(this, i18n("File \"%1\" does not exist").arg(filePath));
+ return 0;
+ }
+
+ if (info.isDir()) {
+ KStartupLogo::hideIfStillThere();
+ KMessageBox::sorry(this, i18n("File \"%1\" is actually a directory"));
+ return 0;
+ }
+
+ QFile file(filePath);
+
+ if (!file.open(IO_ReadOnly)) {
+ KStartupLogo::hideIfStillThere();
+ QString errStr =
+ i18n("You do not have read permission for \"%1\"").arg(filePath);
+
+ KMessageBox::sorry(this, errStr);
+ return 0;
+ }
+
+ // Stop if playing
+ //
+ if (m_seqManager && m_seqManager->getTransportStatus() == PLAYING)
+ slotStop();
+
+ slotEnableTransport(false);
+
+ if (importType == ImportCheckType) {
+ KMimeType::Ptr fileMimeType = KMimeType::findByPath(filePath);
+ if (fileMimeType->name() == "audio/x-midi")
+ importType = ImportMIDI;
+ else if (fileMimeType->name() == "audio/x-rosegarden")
+ importType = ImportRG4;
+ else if (filePath.endsWith(".rose"))
+ importType = ImportRG21;
+ else if (filePath.endsWith(".h2song"))
+ importType = ImportHydrogen;
+ }
+
+
+ switch (importType) {
+ case ImportMIDI:
+ doc = createDocumentFromMIDIFile(filePath);
+ break;
+ case ImportRG21:
+ doc = createDocumentFromRG21File(filePath);
+ break;
+ case ImportHydrogen:
+ doc = createDocumentFromHydrogenFile(filePath);
+ break;
+ default:
+ doc = createDocumentFromRGFile(filePath);
+ }
+
+ slotEnableTransport(true);
+
+ return doc;
+}
+
+RosegardenGUIDoc*
+RosegardenGUIApp::createDocumentFromRGFile(QString filePath)
+{
+ // Check for an autosaved file to recover
+ QString effectiveFilePath = filePath;
+ bool canRecover = false;
+ QString autoSaveFileName = kapp->checkRecoverFile(filePath, canRecover);
+
+ if (canRecover) {
+ // First check if the auto-save file is more recent than the doc
+ QFileInfo docFileInfo(filePath), autoSaveFileInfo(autoSaveFileName);
+
+ if (docFileInfo.lastModified() < autoSaveFileInfo.lastModified()) {
+
+ RG_DEBUG << "RosegardenGUIApp::openFile : "
+ << "found a more recent autosave file\n";
+
+ // At this point the splash screen may still be there, hide it if
+ // it's the case
+ KStartupLogo::hideIfStillThere();
+
+ // It is, so ask the user if he wants to use the autosave file
+ int reply = KMessageBox::questionYesNo(this,
+ i18n("An auto-save file for this document has been found\nDo you want to open it instead ?"));
+
+ if (reply == KMessageBox::Yes)
+ // open the autosave file instead
+ effectiveFilePath = autoSaveFileName;
+ else {
+ // user doesn't want the autosave, so delete it
+ // so it won't bother us again if we reload
+ canRecover = false;
+ QFile::remove
+ (autoSaveFileName);
+ }
+
+ } else
+ canRecover = false;
+ }
+
+ // Create a new blank document
+ //
+ RosegardenGUIDoc *newDoc = new RosegardenGUIDoc(this, m_pluginManager,
+ true); // skipAutoload
+
+ // ignore return thingy
+ //
+ if (newDoc->openDocument(effectiveFilePath)) {
+ if (canRecover) {
+ // Mark the document as modified,
+ // set the "regular" filepath and name (not those of
+ // the autosaved doc)
+ //
+ newDoc->slotDocumentModified();
+ QFileInfo info(filePath);
+ newDoc->setAbsFilePath(info.absFilePath());
+ newDoc->setTitle(info.fileName());
+ } else {
+ newDoc->clearModifiedStatus();
+ }
+ } else {
+ delete newDoc;
+ return 0;
+ }
+
+ return newDoc;
+}
+
+void RosegardenGUIApp::slotSaveOptions()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotSaveOptions()\n";
+
+#ifdef SETTING_LOG_DEBUG
+
+ _settingLog(QString("SETTING 2 : transport flap extended = %1").arg(getTransport()->isExpanded()));
+ _settingLog(QString("SETTING 2 : show track labels = %1").arg(m_viewTrackLabels->isChecked()));
+#endif
+
+ kapp->config()->setGroup(GeneralOptionsConfigGroup);
+ kapp->config()->writeEntry("Show Transport", m_viewTransport->isChecked());
+ kapp->config()->writeEntry("Expanded Transport", m_transport ? getTransport()->isExpanded() : true);
+ kapp->config()->writeEntry("Show Track labels", m_viewTrackLabels->isChecked());
+ kapp->config()->writeEntry("Show Rulers", m_viewRulers->isChecked());
+ kapp->config()->writeEntry("Show Tempo Ruler", m_viewTempoRuler->isChecked());
+ kapp->config()->writeEntry("Show Chord Name Ruler", m_viewChordNameRuler->isChecked());
+ kapp->config()->writeEntry("Show Previews", m_viewPreviews->isChecked());
+ kapp->config()->writeEntry("Show Segment Labels", m_viewSegmentLabels->isChecked());
+ kapp->config()->writeEntry("Show Parameters", m_dockVisible);
+ kapp->config()->writeEntry("MIDI Thru Routing", m_enableMIDIrouting->isChecked());
+
+#ifdef SETTING_LOG_DEBUG
+
+ RG_DEBUG << "SHOW PARAMETERS = " << m_dockVisible << endl;
+#endif
+
+ m_fileRecent->saveEntries(kapp->config());
+
+ // saveMainWindowSettings(kapp->config(), RosegardenGUIApp::MainWindowConfigGroup); - no need to, done by KMainWindow
+ kapp->config()->sync();
+}
+
+void RosegardenGUIApp::setupFileDialogSpeedbar()
+{
+ KConfig *config = kapp->config();
+
+ config->setGroup("KFileDialog Speedbar");
+
+ RG_DEBUG << "RosegardenGUIApp::setupFileDialogSpeedbar" << endl;
+
+ bool hasSetExamplesItem = config->readBoolEntry("Examples Set", false);
+
+ RG_DEBUG << "RosegardenGUIApp::setupFileDialogSpeedbar: examples set " << hasSetExamplesItem << endl;
+
+ if (!hasSetExamplesItem) {
+
+ unsigned int n = config->readUnsignedNumEntry("Number of Entries", 0);
+
+ config->writeEntry(QString("Description_%1").arg(n), i18n("Example Files"));
+ config->writeEntry(QString("IconGroup_%1").arg(n), 4);
+ config->writeEntry(QString("Icon_%1").arg(n), "folder");
+ config->writeEntry(QString("URL_%1").arg(n),
+ KGlobal::dirs()->findResource("appdata", "examples/"));
+
+ RG_DEBUG << "wrote url " << config->readEntry(QString("URL_%1").arg(n)) << endl;
+
+ config->writeEntry("Examples Set", true);
+ config->writeEntry("Number of Entries", n + 1);
+ config->sync();
+ }
+
+}
+
+void RosegardenGUIApp::readOptions()
+{
+ applyMainWindowSettings(kapp->config(), MainWindowConfigGroup);
+
+ kapp->config()->reparseConfiguration();
+
+ // Statusbar and toolbars toggling action status
+ //
+ m_viewStatusBar ->setChecked(!statusBar() ->isHidden());
+ m_viewToolBar ->setChecked(!toolBar() ->isHidden());
+ m_viewToolsToolBar ->setChecked(!toolBar("Tools Toolbar") ->isHidden());
+ m_viewTracksToolBar ->setChecked(!toolBar("Tracks Toolbar") ->isHidden());
+ m_viewEditorsToolBar ->setChecked(!toolBar("Editors Toolbar") ->isHidden());
+ m_viewTransportToolBar->setChecked(!toolBar("Transport Toolbar")->isHidden());
+ m_viewZoomToolBar ->setChecked(!toolBar("Zoom Toolbar") ->isHidden());
+
+ bool opt;
+
+ kapp->config()->setGroup(GeneralOptionsConfigGroup);
+
+ opt = kapp->config()->readBoolEntry("Show Transport", true);
+ m_viewTransport->setChecked(opt);
+ slotToggleTransport();
+
+ opt = kapp->config()->readBoolEntry("Expanded Transport", true);
+
+#ifdef SETTING_LOG_DEBUG
+
+ _settingLog(QString("SETTING 3 : transport flap extended = %1").arg(opt));
+#endif
+
+ if (opt)
+ getTransport()->slotPanelOpenButtonClicked();
+ else
+ getTransport()->slotPanelCloseButtonClicked();
+
+ opt = kapp->config()->readBoolEntry("Show Track labels", true);
+
+#ifdef SETTING_LOG_DEBUG
+
+ _settingLog(QString("SETTING 3 : show track labels = %1").arg(opt));
+#endif
+
+ m_viewTrackLabels->setChecked(opt);
+ slotToggleTrackLabels();
+
+ opt = kapp->config()->readBoolEntry("Show Rulers", true);
+ m_viewRulers->setChecked(opt);
+ slotToggleRulers();
+
+ opt = kapp->config()->readBoolEntry("Show Tempo Ruler", true);
+ m_viewTempoRuler->setChecked(opt);
+ slotToggleTempoRuler();
+
+ opt = kapp->config()->readBoolEntry("Show Chord Name Ruler", false);
+ m_viewChordNameRuler->setChecked(opt);
+ slotToggleChordNameRuler();
+
+ opt = kapp->config()->readBoolEntry("Show Previews", true);
+ m_viewPreviews->setChecked(opt);
+ slotTogglePreviews();
+
+ opt = kapp->config()->readBoolEntry("Show Segment Labels", true);
+ m_viewSegmentLabels->setChecked(opt);
+ slotToggleSegmentLabels();
+
+ opt = kapp->config()->readBoolEntry("Show Parameters", true);
+ if (!opt) {
+ m_dockLeft->undock();
+ m_dockLeft->hide();
+ stateChanged("parametersbox_closed", KXMLGUIClient::StateNoReverse);
+ m_dockVisible = false;
+ }
+
+ // MIDI Thru routing
+ opt = kapp->config()->readBoolEntry("MIDI Thru Routing", true);
+ m_enableMIDIrouting->setChecked(opt);
+ slotEnableMIDIThruRouting();
+
+ // initialise the recent file list
+ //
+ m_fileRecent->loadEntries(kapp->config());
+
+ m_actionsSetup = true;
+
+}
+
+void RosegardenGUIApp::saveGlobalProperties(KConfig *cfg)
+{
+ if (m_doc->getTitle() != i18n("Untitled") && !m_doc->isModified()) {
+ // saving to tempfile not necessary
+ } else {
+ QString filename = m_doc->getAbsFilePath();
+ cfg->writeEntry("filename", filename);
+ cfg->writeEntry("modified", m_doc->isModified());
+
+ QString tempname = kapp->tempSaveName(filename);
+ QString errMsg;
+ bool res = m_doc->saveDocument(tempname, errMsg);
+ if (!res) {
+ if (errMsg)
+ KMessageBox::error(this, i18n(QString("Could not save document at %1\nError was : %2")
+ .arg(tempname).arg(errMsg)));
+ else
+ KMessageBox::error(this, i18n(QString("Could not save document at %1")
+ .arg(tempname)));
+ }
+ }
+}
+
+void RosegardenGUIApp::readGlobalProperties(KConfig* _cfg)
+{
+ QString filename = _cfg->readEntry("filename", "");
+ bool modified = _cfg->readBoolEntry("modified", false);
+
+ if (modified) {
+ bool canRecover;
+ QString tempname = kapp->checkRecoverFile(filename, canRecover);
+
+ if (canRecover) {
+ slotEnableTransport(false);
+ m_doc->openDocument(tempname);
+ slotEnableTransport(true);
+ m_doc->slotDocumentModified();
+ QFileInfo info(filename);
+ m_doc->setAbsFilePath(info.absFilePath());
+ m_doc->setTitle(info.fileName());
+ }
+ } else {
+ if (!filename.isEmpty()) {
+ slotEnableTransport(false);
+ m_doc->openDocument(filename);
+ slotEnableTransport(true);
+ }
+ }
+
+ QString caption = kapp->caption();
+ setCaption(caption + ": " + m_doc->getTitle());
+}
+
+void RosegardenGUIApp::showEvent(QShowEvent* e)
+{
+ RG_DEBUG << "RosegardenGUIApp::showEvent()\n";
+
+ getTransport()->raise();
+ KMainWindow::showEvent(e);
+}
+
+bool RosegardenGUIApp::queryClose()
+{
+ RG_DEBUG << "RosegardenGUIApp::queryClose" << endl;
+#ifdef SETTING_LOG_DEBUG
+
+ _settingLog(QString("SETTING 1 : transport flap extended = %1").arg(getTransport()->isExpanded()));
+ _settingLog(QString("SETTING 1 : show track labels = %1").arg(m_viewTrackLabels->isChecked()));
+#endif
+
+ QString errMsg;
+
+ bool canClose = m_doc->saveIfModified();
+
+ /*
+ if (canClose && m_transport) {
+
+ // or else the closing of the transport will toggle off the
+ // 'view transport' action, and its state will be saved as
+ // 'off'
+ //
+
+ disconnect(m_transport, SIGNAL(closed()),
+ this, SLOT(slotCloseTransport()));
+ }
+ */
+
+ return canClose;
+
+}
+
+bool RosegardenGUIApp::queryExit()
+{
+ RG_DEBUG << "RosegardenGUIApp::queryExit" << endl;
+ if (m_actionsSetup)
+ slotSaveOptions();
+
+ return true;
+}
+
+void RosegardenGUIApp::slotFileNewWindow()
+{
+ KTmpStatusMsg msg(i18n("Opening a new application window..."), this);
+
+ RosegardenGUIApp *new_window = new RosegardenGUIApp();
+ new_window->show();
+}
+
+void RosegardenGUIApp::slotFileNew()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotFileNew()\n";
+
+ KTmpStatusMsg msg(i18n("Creating new document..."), this);
+
+ bool makeNew = false;
+
+ if (!m_doc->isModified()) {
+ makeNew = true;
+ // m_doc->closeDocument();
+ } else if (m_doc->saveIfModified()) {
+ makeNew = true;
+ }
+
+ if (makeNew) {
+
+ setDocument(new RosegardenGUIDoc(this, m_pluginManager));
+ }
+}
+
+void RosegardenGUIApp::slotOpenDroppedURL(QString url)
+{
+ ProgressDialog::processEvents(); // or else we get a crash because the
+ // track editor is erased too soon - it is the originator of the signal
+ // this slot is connected to.
+
+ if (!m_doc->saveIfModified())
+ return ;
+
+ openURL(KURL(url));
+}
+
+void RosegardenGUIApp::openURL(QString url)
+{
+ RG_DEBUG << "RosegardenGUIApp::openURL: QString " << url << endl;
+ openURL(KURL(url));
+}
+
+void RosegardenGUIApp::openURL(const KURL& url)
+{
+ SetWaitCursor waitCursor;
+
+ QString netFile = url.prettyURL();
+ RG_DEBUG << "RosegardenGUIApp::openURL: KURL " << netFile << endl;
+
+ if (!url.isValid()) {
+ QString string;
+ string = i18n( "Malformed URL\n%1").arg(netFile);
+
+ KMessageBox::sorry(this, string);
+ return ;
+ }
+
+ QString target, caption(url.path());
+
+ if (KIO::NetAccess::download(url, target, this) == false) {
+ KMessageBox::error(this, i18n("Cannot download file %1").arg(url.prettyURL()));
+ return ;
+ }
+
+ RG_DEBUG << "RosegardenGUIApp::openURL: target : " << target << endl;
+
+ if (!m_doc->saveIfModified())
+ return ;
+
+ openFile(target);
+
+ setCaption(caption);
+}
+
+void RosegardenGUIApp::slotFileOpen()
+{
+ slotStatusHelpMsg(i18n("Opening file..."));
+
+ kapp->config()->setGroup(GeneralOptionsConfigGroup);
+
+ QString lastOpenedVersion =
+ kapp->config()->readEntry("Last File Opened Version", "none");
+
+ if (lastOpenedVersion != VERSION) {
+
+ // We haven't opened any files with this version of the
+ // program before. Default to the examples directory.
+
+ QString examplesDir = KGlobal::dirs()->findResource("appdata", "examples/");
+ kapp->config()->setGroup("Recent Dirs");
+ QString recentString = kapp->config()->readEntry("ROSEGARDEN", "");
+ kapp->config()->writeEntry
+ ("ROSEGARDEN", QString("file:%1,%2").arg(examplesDir).arg(recentString));
+ }
+
+ KURL url = KFileDialog::getOpenURL
+ (":ROSEGARDEN",
+ "audio/x-rosegarden audio/x-midi audio/x-rosegarden21", this,
+ i18n("Open File"));
+ if ( url.isEmpty() ) {
+ return ;
+ }
+
+ if (m_doc && !m_doc->saveIfModified())
+ return ;
+
+ kapp->config()->setGroup(GeneralOptionsConfigGroup);
+ kapp->config()->writeEntry("Last File Opened Version", VERSION);
+
+ openURL(url);
+}
+
+void RosegardenGUIApp::slotMerge()
+{
+ KURL url = KFileDialog::getOpenURL
+ (":ROSEGARDEN",
+ "audio/x-rosegarden audio/x-midi audio/x-rosegarden21", this,
+ i18n("Open File"));
+ if ( url.isEmpty() ) {
+ return ;
+ }
+
+
+ QString target;
+
+ if (KIO::NetAccess::download(url, target, this) == false) {
+ KMessageBox::error(this, i18n("Cannot download file %1").arg(url.prettyURL()));
+ return ;
+ }
+
+ mergeFile(target);
+
+ KIO::NetAccess::removeTempFile( target );
+}
+
+void RosegardenGUIApp::slotFileOpenRecent(const KURL &url)
+{
+ KTmpStatusMsg msg(i18n("Opening file..."), this);
+
+ if (m_doc) {
+
+ if (!m_doc->saveIfModified()) {
+ return ;
+
+ }
+ }
+
+ openURL(url);
+}
+
+void RosegardenGUIApp::slotFileSave()
+{
+ if (!m_doc /*|| !m_doc->isModified()*/)
+ return ; // ALWAYS save, even if doc is not modified.
+
+ KTmpStatusMsg msg(i18n("Saving file..."), this);
+
+ // if it's a new file (no file path), or an imported file
+ // (file path doesn't end with .rg), call saveAs
+ //
+ if (!m_doc->isRegularDotRGFile()) {
+
+ slotFileSaveAs();
+
+ } else {
+
+ SetWaitCursor waitCursor;
+ QString errMsg, docFilePath = m_doc->getAbsFilePath();
+
+ bool res = m_doc->saveDocument(docFilePath, errMsg);
+ if (!res) {
+ if (errMsg)
+ KMessageBox::error(this, i18n(QString("Could not save document at %1\nError was : %2")
+ .arg(docFilePath).arg(errMsg)));
+ else
+ KMessageBox::error(this, i18n(QString("Could not save document at %1")
+ .arg(docFilePath)));
+ }
+ }
+}
+
+QString
+RosegardenGUIApp::getValidWriteFile(QString descriptiveExtension,
+ QString label)
+{
+ // extract first extension listed in descriptiveExtension, for instance,
+ // ".rg" from "*.rg|Rosegarden files", or ".mid" from "*.mid *.midi|MIDI Files"
+ //
+ QString extension = descriptiveExtension.left(descriptiveExtension.find('|')).mid(1).section(' ', 0, 0);
+
+ RG_DEBUG << "RosegardenGUIApp::getValidWriteFile() : extension = " << extension << endl;
+
+ // It's too bad there isn't this functionality within
+ // KFileDialog::getSaveFileName
+ KFileDialog saveFileDialog(":ROSEGARDEN", descriptiveExtension, this, label, true);
+ saveFileDialog.setOperationMode(KFileDialog::Saving);
+ if (m_doc) {
+ QString saveFileName = m_doc->getAbsFilePath();
+ // Show filename without the old extension
+ int dotLoc = saveFileName.findRev('.');
+ if (dotLoc >= int(saveFileName.length() - 4)) {
+ saveFileName = saveFileName.left(dotLoc);
+ }
+ saveFileDialog.setSelection(saveFileName);
+ }
+ saveFileDialog.exec();
+ QString name = saveFileDialog.selectedFile();
+
+ // RG_DEBUG << "RosegardenGUIApp::getValidWriteFile() : KFileDialog::getSaveFileName returned "
+ // << name << endl;
+
+
+ if (name.isEmpty())
+ return name;
+
+ // Append extension if we don't have one
+ //
+ if (!extension.isEmpty()) {
+ static QRegExp rgFile("\\..{1,4}$");
+ if (rgFile.match(name) == -1) {
+ name += extension;
+ }
+ }
+
+ KURL *u = new KURL(name);
+
+ if (!u->isValid()) {
+ KMessageBox::sorry(this, i18n("This is not a valid filename.\n"));
+ return "";
+ }
+
+ if (!u->isLocalFile()) {
+ KMessageBox::sorry(this, i18n("This is not a local file.\n"));
+ return "";
+ }
+
+ QFileInfo info(name);
+
+ if (info.isDir()) {
+ KMessageBox::sorry(this, i18n("You have specified a directory"));
+ return "";
+ }
+
+ if (info.exists()) {
+ int overwrite = KMessageBox::questionYesNo
+ (this, i18n("The specified file exists. Overwrite?"));
+
+ if (overwrite != KMessageBox::Yes)
+ return "";
+ }
+
+ return name;
+}
+
+bool RosegardenGUIApp::slotFileSaveAs()
+{
+ if (!m_doc)
+ return false;
+
+ KTmpStatusMsg msg(i18n("Saving file with a new filename..."), this);
+
+ QString newName = getValidWriteFile("*.rg|" + i18n("Rosegarden files") +
+ "\n*|" + i18n("All files"),
+ i18n("Save as..."));
+ if (newName.isEmpty())
+ return false;
+
+ SetWaitCursor waitCursor;
+ QFileInfo saveAsInfo(newName);
+ m_doc->setTitle(saveAsInfo.fileName());
+ m_doc->setAbsFilePath(saveAsInfo.absFilePath());
+ QString errMsg;
+ bool res = m_doc->saveDocument(newName, errMsg);
+ if (!res) {
+ if (errMsg)
+ KMessageBox::error(this, i18n(QString("Could not save document at %1\nError was : %2")
+ .arg(newName).arg(errMsg)));
+ else
+ KMessageBox::error(this, i18n(QString("Could not save document at %1")
+ .arg(newName)));
+
+ } else {
+
+ m_fileRecent->addURL(newName);
+
+ QString caption = kapp->caption();
+ setCaption(caption + ": " + m_doc->getTitle());
+ // update the edit view's captions too
+ emit compositionStateUpdate();
+ }
+
+ return res;
+}
+
+void RosegardenGUIApp::slotFileClose()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotFileClose()" << endl;
+
+ if (!m_doc)
+ return ;
+
+ KTmpStatusMsg msg(i18n("Closing file..."), this);
+
+ if (m_doc->saveIfModified()) {
+ setDocument(new RosegardenGUIDoc(this, m_pluginManager));
+ }
+
+ // Don't close the whole view (i.e. Quit), just close the doc.
+ // close();
+}
+
+void RosegardenGUIApp::slotFilePrint()
+{
+ if (m_doc->getComposition().getNbSegments() == 0) {
+ KMessageBox::sorry(0, "Please create some tracks first (until we implement menu state management)");
+ return ;
+ }
+
+ KTmpStatusMsg msg(i18n("Printing..."), this);
+
+ m_view->print(&m_doc->getComposition());
+}
+
+void RosegardenGUIApp::slotFilePrintPreview()
+{
+ if (m_doc->getComposition().getNbSegments() == 0) {
+ KMessageBox::sorry(0, "Please create some tracks first (until we implement menu state management)");
+ return ;
+ }
+
+ KTmpStatusMsg msg(i18n("Previewing..."), this);
+
+ m_view->print(&m_doc->getComposition(), true);
+}
+
+void RosegardenGUIApp::slotQuit()
+{
+ slotStatusMsg(i18n("Exiting..."));
+
+ Profiles::getInstance()->dump();
+
+ // close the first window, the list makes the next one the first again.
+ // This ensures that queryClose() is called on each window to ask for closing
+ KMainWindow* w;
+ if (memberList) {
+
+ for (w = memberList->first(); w != 0; w = memberList->next()) {
+ // only close the window if the closeEvent is accepted. If
+ // the user presses Cancel on the saveIfModified() dialog,
+ // the window and the application stay open.
+ if (!w->close())
+ break;
+ }
+ }
+}
+
+void RosegardenGUIApp::slotEditCut()
+{
+ if (!m_view->haveSelection())
+ return ;
+ KTmpStatusMsg msg(i18n("Cutting selection..."), this);
+
+ SegmentSelection selection(m_view->getSelection());
+ m_doc->getCommandHistory()->addCommand
+ (new CutCommand(selection, m_clipboard));
+}
+
+void RosegardenGUIApp::slotEditCopy()
+{
+ if (!m_view->haveSelection())
+ return ;
+ KTmpStatusMsg msg(i18n("Copying selection to clipboard..."), this);
+
+ SegmentSelection selection(m_view->getSelection());
+ m_doc->getCommandHistory()->addCommand
+ (new CopyCommand(selection, m_clipboard));
+}
+
+void RosegardenGUIApp::slotEditPaste()
+{
+ if (m_clipboard->isEmpty()) {
+ KTmpStatusMsg msg(i18n("Clipboard is empty"), this);
+ return ;
+ }
+ KTmpStatusMsg msg(i18n("Inserting clipboard contents..."), this);
+
+ // for now, but we could paste at the time of the first copied
+ // segment and then do ghosting drag or something
+ timeT insertionTime = m_doc->getComposition().getPosition();
+ m_doc->getCommandHistory()->addCommand
+ (new PasteSegmentsCommand(&m_doc->getComposition(),
+ m_clipboard, insertionTime,
+ m_doc->getComposition().getSelectedTrack(),
+ false));
+
+ // User preference? Update song pointer position on paste
+ m_doc->slotSetPointerPosition(m_doc->getComposition().getPosition());
+}
+
+void RosegardenGUIApp::slotCutRange()
+{
+ timeT t0 = m_doc->getComposition().getLoopStart();
+ timeT t1 = m_doc->getComposition().getLoopEnd();
+
+ if (t0 == t1)
+ return ;
+
+ m_doc->getCommandHistory()->addCommand
+ (new CutRangeCommand(&m_doc->getComposition(), t0, t1, m_clipboard));
+}
+
+void RosegardenGUIApp::slotCopyRange()
+{
+ timeT t0 = m_doc->getComposition().getLoopStart();
+ timeT t1 = m_doc->getComposition().getLoopEnd();
+
+ if (t0 == t1)
+ return ;
+
+ m_doc->getCommandHistory()->addCommand
+ (new CopyCommand(&m_doc->getComposition(), t0, t1, m_clipboard));
+}
+
+void RosegardenGUIApp::slotPasteRange()
+{
+ if (m_clipboard->isEmpty())
+ return ;
+
+ m_doc->getCommandHistory()->addCommand
+ (new PasteRangeCommand(&m_doc->getComposition(), m_clipboard,
+ m_doc->getComposition().getPosition()));
+
+ m_doc->setLoop(0, 0);
+}
+
+void RosegardenGUIApp::slotDeleteRange()
+{
+ timeT t0 = m_doc->getComposition().getLoopStart();
+ timeT t1 = m_doc->getComposition().getLoopEnd();
+
+ if (t0 == t1)
+ return ;
+
+ m_doc->getCommandHistory()->addCommand
+ (new DeleteRangeCommand(&m_doc->getComposition(), t0, t1));
+
+ m_doc->setLoop(0, 0);
+}
+
+void RosegardenGUIApp::slotInsertRange()
+{
+ timeT t0 = m_doc->getComposition().getPosition();
+ std::pair<timeT, timeT> r = m_doc->getComposition().getBarRangeForTime(t0);
+ TimeDialog dialog(m_view, i18n("Duration of empty range to insert"),
+ &m_doc->getComposition(), t0, r.second - r.first, false);
+ if (dialog.exec() == QDialog::Accepted) {
+ m_doc->getCommandHistory()->addCommand
+ (new InsertRangeCommand(&m_doc->getComposition(), t0, dialog.getTime()));
+ m_doc->setLoop(0, 0);
+ }
+}
+
+void RosegardenGUIApp::slotSelectAll()
+{
+ m_view->slotSelectAllSegments();
+}
+
+void RosegardenGUIApp::slotDeleteSelectedSegments()
+{
+ m_view->getTrackEditor()->slotDeleteSelectedSegments();
+}
+
+void RosegardenGUIApp::slotQuantizeSelection()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ //!!! this should all be in rosegardenguiview
+
+ QuantizeDialog dialog(m_view);
+ if (dialog.exec() != QDialog::Accepted)
+ return ;
+
+ SegmentSelection selection = m_view->getSelection();
+
+ KMacroCommand *command = new KMacroCommand
+ (EventQuantizeCommand::getGlobalName());
+
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+ command->addCommand(new EventQuantizeCommand
+ (**i, (*i)->getStartTime(), (*i)->getEndTime(),
+ dialog.getQuantizer()));
+ }
+
+ m_view->slotAddCommandToHistory(command);
+}
+
+void RosegardenGUIApp::slotRepeatQuantizeSelection()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ //!!! this should all be in rosegardenguiview
+
+ SegmentSelection selection = m_view->getSelection();
+
+ KMacroCommand *command = new KMacroCommand
+ (EventQuantizeCommand::getGlobalName());
+
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+ command->addCommand(new EventQuantizeCommand
+ (**i, (*i)->getStartTime(), (*i)->getEndTime(),
+ "Quantize Dialog Grid", false)); // no i18n (config group name)
+ }
+
+ m_view->slotAddCommandToHistory(command);
+}
+
+void RosegardenGUIApp::slotGrooveQuantize()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ SegmentSelection selection = m_view->getSelection();
+
+ if (selection.size() != 1) {
+ KMessageBox::sorry(this, i18n("This function needs no more than one segment to be selected."));
+ return ;
+ }
+
+ Segment *s = *selection.begin();
+ m_view->slotAddCommandToHistory(new CreateTempoMapFromSegmentCommand(s));
+}
+
+void RosegardenGUIApp::slotJoinSegments()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ //!!! this should all be in rosegardenguiview
+ //!!! should it?
+
+ SegmentSelection selection = m_view->getSelection();
+ if (selection.size() == 0)
+ return ;
+
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+ if ((*i)->getType() != Segment::Internal) {
+ KMessageBox::sorry(this, i18n("Can't join Audio segments"));
+ return ;
+ }
+ }
+
+ m_view->slotAddCommandToHistory(new SegmentJoinCommand(selection));
+ m_view->updateSelectionContents();
+}
+
+void RosegardenGUIApp::slotRescaleSelection()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ //!!! this should all be in rosegardenguiview
+ //!!! should it?
+
+ SegmentSelection selection = m_view->getSelection();
+
+ timeT startTime = 0, endTime = 0;
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+ if ((i == selection.begin()) || ((*i)->getStartTime() < startTime)) {
+ startTime = (*i)->getStartTime();
+ }
+ if ((i == selection.begin()) || ((*i)->getEndMarkerTime() > endTime)) {
+ endTime = (*i)->getEndMarkerTime();
+ }
+ }
+
+ RescaleDialog dialog(m_view, &m_doc->getComposition(),
+ startTime, endTime - startTime,
+ false, false);
+ if (dialog.exec() != QDialog::Accepted)
+ return ;
+
+ std::vector<AudioSegmentRescaleCommand *> asrcs;
+
+ int mult = dialog.getNewDuration();
+ int div = endTime - startTime;
+ float ratio = float(mult) / float(div);
+
+ std::cerr << "slotRescaleSelection: mult = " << mult << ", div = " << div << ", ratio = " << ratio << std::endl;
+
+ KMacroCommand *command = new KMacroCommand
+ (SegmentRescaleCommand::getGlobalName());
+
+ bool pathTested = false;
+
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+ if ((*i)->getType() == Segment::Audio) {
+ if (!pathTested) {
+ testAudioPath(i18n("rescaling an audio file"));
+ pathTested = true;
+ }
+ AudioSegmentRescaleCommand *asrc = new AudioSegmentRescaleCommand
+ (m_doc, *i, ratio);
+ command->addCommand(asrc);
+ asrcs.push_back(asrc);
+ } else {
+ command->addCommand(new SegmentRescaleCommand(*i, mult, div));
+ }
+ }
+
+ ProgressDialog *progressDlg = 0;
+
+ if (!asrcs.empty()) {
+ progressDlg = new ProgressDialog
+ (i18n("Rescaling audio file..."), 100, this);
+ progressDlg->setAutoClose(false);
+ progressDlg->setAutoReset(false);
+ progressDlg->show();
+ for (size_t i = 0; i < asrcs.size(); ++i) {
+ asrcs[i]->connectProgressDialog(progressDlg);
+ }
+ }
+
+ m_view->slotAddCommandToHistory(command);
+
+ if (!asrcs.empty()) {
+
+ progressDlg->setLabel(i18n("Generating audio preview..."));
+
+ for (size_t i = 0; i < asrcs.size(); ++i) {
+ asrcs[i]->disconnectProgressDialog(progressDlg);
+ }
+
+ connect(&m_doc->getAudioFileManager(), SIGNAL(setProgress(int)),
+ progressDlg->progressBar(), SLOT(setValue(int)));
+ connect(progressDlg, SIGNAL(cancelClicked()),
+ &m_doc->getAudioFileManager(), SLOT(slotStopPreview()));
+
+ for (size_t i = 0; i < asrcs.size(); ++i) {
+ int fid = asrcs[i]->getNewAudioFileId();
+ if (fid >= 0) {
+ slotAddAudioFile(fid);
+ m_doc->getAudioFileManager().generatePreview(fid);
+ }
+ }
+ }
+
+ if (progressDlg) delete progressDlg;
+}
+
+bool
+RosegardenGUIApp::testAudioPath(QString op)
+{
+ try {
+ m_doc->getAudioFileManager().testAudioPath();
+ } catch (AudioFileManager::BadAudioPathException) {
+ if (KMessageBox::warningContinueCancel
+ (this,
+ i18n("The audio file path does not exist or is not writable.\nYou must set the audio file path to a valid directory in Document Properties before %1.\nWould you like to set it now?").arg(op),
+ i18n("Warning"),
+ i18n("Set audio file path")) == KMessageBox::Continue) {
+ slotOpenAudioPathSettings();
+ }
+ return false;
+ }
+ return true;
+}
+
+void RosegardenGUIApp::slotAutoSplitSelection()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ //!!! this should all be in rosegardenguiview
+ //!!! or should it?
+
+ SegmentSelection selection = m_view->getSelection();
+
+ KMacroCommand *command = new KMacroCommand
+ (SegmentAutoSplitCommand::getGlobalName());
+
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+
+ if ((*i)->getType() == Segment::Audio) {
+ AudioSplitDialog aSD(this, (*i), m_doc);
+
+ if (aSD.exec() == QDialog::Accepted) {
+ // split to threshold
+ //
+ command->addCommand(
+ new AudioSegmentAutoSplitCommand(m_doc,
+ *i,
+ aSD.getThreshold()));
+ // dmm - verifying that widget->value() accessors *can* work without crashing
+ // std::cout << "SILVAN: getThreshold() = " << aSD.getThreshold() << std::endl;
+ }
+ } else {
+ command->addCommand(new SegmentAutoSplitCommand(*i));
+ }
+ }
+
+ m_view->slotAddCommandToHistory(command);
+}
+
+void RosegardenGUIApp::slotJogLeft()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotJogLeft" << endl;
+ jogSelection( -Note(Note::Demisemiquaver).getDuration());
+}
+
+void RosegardenGUIApp::slotJogRight()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotJogRight" << endl;
+ jogSelection(Note(Note::Demisemiquaver).getDuration());
+}
+
+void RosegardenGUIApp::jogSelection(timeT amount)
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ SegmentSelection selection = m_view->getSelection();
+
+ SegmentReconfigureCommand *command = new SegmentReconfigureCommand(i18n("Jog Selection"));
+
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+
+ command->addSegment((*i),
+ (*i)->getStartTime() + amount,
+ (*i)->getEndMarkerTime() + amount,
+ (*i)->getTrack());
+ }
+
+ m_view->slotAddCommandToHistory(command);
+}
+
+void RosegardenGUIApp::createAndSetupTransport()
+{
+ // create the Transport GUI and add the callbacks to the
+ // buttons and keyboard accelerators
+ //
+ m_transport =
+ new TransportDialog(this);
+ plugAccelerators(m_transport, m_transport->getAccelerators());
+
+ m_transport->getAccelerators()->connectItem
+ (m_transport->getAccelerators()->insertItem(Key_T),
+ this,
+ SLOT(slotHideTransport()));
+
+ // Ensure that the checkbox is unchecked if the dialog
+ // is closed
+ connect(m_transport, SIGNAL(closed()),
+ SLOT(slotCloseTransport()));
+
+ // Handle loop setting and unsetting from the transport loop button
+ //
+
+ connect(m_transport, SIGNAL(setLoop()), SLOT(slotSetLoop()));
+ connect(m_transport, SIGNAL(unsetLoop()), SLOT(slotUnsetLoop()));
+ connect(m_transport, SIGNAL(panic()), SLOT(slotPanic()));
+
+ connect(m_transport, SIGNAL(editTempo(QWidget*)),
+ SLOT(slotEditTempo(QWidget*)));
+
+ connect(m_transport, SIGNAL(editTimeSignature(QWidget*)),
+ SLOT(slotEditTimeSignature(QWidget*)));
+
+ connect(m_transport, SIGNAL(editTransportTime(QWidget*)),
+ SLOT(slotEditTransportTime(QWidget*)));
+
+ // Handle set loop start/stop time buttons.
+ //
+ connect(m_transport, SIGNAL(setLoopStartTime()), SLOT(slotSetLoopStart()));
+ connect(m_transport, SIGNAL(setLoopStopTime()), SLOT(slotSetLoopStop()));
+
+ if (m_seqManager != 0)
+ m_seqManager->setTransport(m_transport);
+
+}
+
+void RosegardenGUIApp::slotSplitSelectionByPitch()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ SplitByPitchDialog dialog(m_view);
+ if (dialog.exec() != QDialog::Accepted)
+ return ;
+
+ SegmentSelection selection = m_view->getSelection();
+
+ KMacroCommand *command = new KMacroCommand
+ (SegmentSplitByPitchCommand::getGlobalName());
+
+ bool haveSomething = false;
+
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+
+ if ((*i)->getType() == Segment::Audio) {
+ // nothing
+ } else {
+ command->addCommand
+ (new SegmentSplitByPitchCommand
+ (*i,
+ dialog.getPitch(),
+ dialog.getShouldRange(),
+ dialog.getShouldDuplicateNonNoteEvents(),
+ (SegmentSplitByPitchCommand::ClefHandling)
+ dialog.getClefHandling()));
+ haveSomething = true;
+ }
+ }
+
+ if (haveSomething)
+ m_view->slotAddCommandToHistory(command);
+ //!!! else complain
+}
+
+void
+RosegardenGUIApp::slotSplitSelectionByRecordedSrc()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ SplitByRecordingSrcDialog dialog(m_view, m_doc);
+ if (dialog.exec() != QDialog::Accepted)
+ return ;
+
+ SegmentSelection selection = m_view->getSelection();
+
+ KMacroCommand *command = new KMacroCommand
+ (SegmentSplitByRecordingSrcCommand::getGlobalName());
+
+ bool haveSomething = false;
+
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+
+ if ((*i)->getType() == Segment::Audio) {
+ // nothing
+ } else {
+ command->addCommand
+ (new SegmentSplitByRecordingSrcCommand(*i,
+ dialog.getChannel(),
+ dialog.getDevice()));
+ haveSomething = true;
+ }
+ }
+ if (haveSomething)
+ m_view->slotAddCommandToHistory(command);
+}
+
+void
+RosegardenGUIApp::slotSplitSelectionAtTime()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ SegmentSelection selection = m_view->getSelection();
+ if (selection.empty())
+ return ;
+
+ timeT now = m_doc->getComposition().getPosition();
+
+ QString title = i18n("Split Segment at Time",
+ "Split %n Segments at Time",
+ selection.size());
+
+ TimeDialog dialog(m_view, title,
+ &m_doc->getComposition(),
+ now, true);
+
+ KMacroCommand *command = new KMacroCommand( title );
+
+ if (dialog.exec() == QDialog::Accepted) {
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+
+ if ((*i)->getType() == Segment::Audio) {
+ command->addCommand(new AudioSegmentSplitCommand(*i, dialog.getTime()));
+ } else {
+ command->addCommand(new SegmentSplitCommand(*i, dialog.getTime()));
+ }
+ }
+ m_view->slotAddCommandToHistory(command);
+ }
+}
+
+void
+RosegardenGUIApp::slotSetSegmentStartTimes()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ SegmentSelection selection = m_view->getSelection();
+ if (selection.empty())
+ return ;
+
+ timeT someTime = (*selection.begin())->getStartTime();
+
+ TimeDialog dialog(m_view, i18n("Segment Start Time"),
+ &m_doc->getComposition(),
+ someTime, false);
+
+ if (dialog.exec() == QDialog::Accepted) {
+
+ bool plural = (selection.size() > 1);
+
+ SegmentReconfigureCommand *command =
+ new SegmentReconfigureCommand(plural ?
+ i18n("Set Segment Start Times") :
+ i18n("Set Segment Start Time"));
+
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+
+ command->addSegment
+ (*i, dialog.getTime(),
+ (*i)->getEndMarkerTime() - (*i)->getStartTime() + dialog.getTime(),
+ (*i)->getTrack());
+ }
+
+ m_view->slotAddCommandToHistory(command);
+ }
+}
+
+void
+RosegardenGUIApp::slotSetSegmentDurations()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ SegmentSelection selection = m_view->getSelection();
+ if (selection.empty())
+ return ;
+
+ timeT someTime =
+ (*selection.begin())->getStartTime();
+
+ timeT someDuration =
+ (*selection.begin())->getEndMarkerTime() -
+ (*selection.begin())->getStartTime();
+
+ TimeDialog dialog(m_view, i18n("Segment Duration"),
+ &m_doc->getComposition(),
+ someTime,
+ someDuration,
+ false);
+
+ if (dialog.exec() == QDialog::Accepted) {
+
+ bool plural = (selection.size() > 1);
+
+ SegmentReconfigureCommand *command =
+ new SegmentReconfigureCommand(plural ?
+ i18n("Set Segment Durations") :
+ i18n("Set Segment Duration"));
+
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+
+ command->addSegment
+ (*i, (*i)->getStartTime(),
+ (*i)->getStartTime() + dialog.getTime(),
+ (*i)->getTrack());
+ }
+
+ m_view->slotAddCommandToHistory(command);
+ }
+}
+
+void RosegardenGUIApp::slotHarmonizeSelection()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ SegmentSelection selection = m_view->getSelection();
+ //!!! This should be somewhere else too
+
+ CompositionTimeSliceAdapter adapter(&m_doc->getComposition(),
+ &selection);
+
+ AnalysisHelper helper;
+ Segment *segment = new Segment;
+ helper.guessHarmonies(adapter, *segment);
+
+ //!!! do nothing with the results yet
+ delete segment;
+}
+
+void RosegardenGUIApp::slotTempoToSegmentLength()
+{
+ slotTempoToSegmentLength(this);
+}
+
+void RosegardenGUIApp::slotTempoToSegmentLength(QWidget* parent)
+{
+ RG_DEBUG << "RosegardenGUIApp::slotTempoToSegmentLength" << endl;
+
+ if (!m_view->haveSelection())
+ return ;
+
+ SegmentSelection selection = m_view->getSelection();
+
+ // Only set for a single selection
+ //
+ if (selection.size() == 1 &&
+ (*selection.begin())->getType() == Segment::Audio) {
+ Composition &comp = m_doc->getComposition();
+ Segment *seg = *selection.begin();
+
+ TimeSignature timeSig =
+ comp.getTimeSignatureAt( seg->getStartTime());
+
+ timeT endTime = seg->getEndTime();
+
+ if (seg->getRawEndMarkerTime())
+ endTime = seg->getEndMarkerTime();
+
+ RealTime segDuration =
+ seg->getAudioEndTime() - seg->getAudioStartTime();
+
+ int beats = 0;
+
+ // Get user to tell us how many beats or bars the segment contains
+ BeatsBarsDialog dialog(parent);
+ if (dialog.exec() == QDialog::Accepted) {
+ beats = dialog.getQuantity(); // beats (or bars)
+ if (dialog.getMode() == 1) // bars (multiply by time sig)
+ beats *= timeSig.getBeatsPerBar();
+#ifdef DEBUG_TEMPO_FROM_AUDIO
+
+ RG_DEBUG << "RosegardenGUIApp::slotTempoToSegmentLength - beats = " << beats
+ << " mode = " << ((dialog.getMode() == 0) ? "bars" : "beats") << endl
+ << " beats per bar = " << timeSig.getBeatsPerBar()
+ << " user quantity = " << dialog.getQuantity()
+ << " user mode = " << dialog.getMode() << endl;
+#endif
+
+ } else {
+ RG_DEBUG << "RosegardenGUIApp::slotTempoToSegmentLength - BeatsBarsDialog aborted"
+ << endl;
+ return ;
+ }
+
+ double beatLengthUsec =
+ double(segDuration.sec * 1000000 + segDuration.usec()) /
+ double(beats);
+
+ // New tempo is a minute divided by time of beat
+ // converted up (#1414252) to a sane value via getTempoFoQpm()
+ //
+ tempoT newTempo =
+ comp.getTempoForQpm(60.0 * 1000000.0 / beatLengthUsec);
+
+#ifdef DEBUG_TEMPO_FROM_AUDIO
+
+ RG_DEBUG << "RosegardenGUIApp::slotTempoToSegmentLength info: " << endl
+ << " beatLengthUsec = " << beatLengthUsec << endl
+ << " segDuration.usec = " << segDuration.usec() << endl
+ << " newTempo = " << newTempo << endl;
+#endif
+
+ KMacroCommand *macro = new KMacroCommand(i18n("Set Global Tempo"));
+
+ // Remove all tempo changes in reverse order so as the index numbers
+ // don't becoming meaningless as the command gets unwound.
+ //
+ for (int i = 0; i < comp.getTempoChangeCount(); i++)
+ macro->addCommand(new RemoveTempoChangeCommand(&comp,
+ (comp.getTempoChangeCount() - 1 - i)));
+
+ // add tempo change at time zero
+ //
+ macro->addCommand(new AddTempoChangeCommand(&comp, 0, newTempo));
+
+ // execute
+ m_doc->getCommandHistory()->addCommand(macro);
+ }
+}
+
+void RosegardenGUIApp::slotToggleSegmentLabels()
+{
+ KToggleAction* act = dynamic_cast<KToggleAction*>(actionCollection()->action("show_segment_labels"));
+ if (act) {
+ m_view->slotShowSegmentLabels(act->isChecked());
+ }
+}
+
+void RosegardenGUIApp::slotEdit()
+{
+ m_view->slotEditSegment(0);
+}
+
+void RosegardenGUIApp::slotEditAsNotation()
+{
+ m_view->slotEditSegmentNotation(0);
+}
+
+void RosegardenGUIApp::slotEditInMatrix()
+{
+ m_view->slotEditSegmentMatrix(0);
+}
+
+void RosegardenGUIApp::slotEditInPercussionMatrix()
+{
+ m_view->slotEditSegmentPercussionMatrix(0);
+}
+
+void RosegardenGUIApp::slotEditInEventList()
+{
+ m_view->slotEditSegmentEventList(0);
+}
+
+void RosegardenGUIApp::slotEditTempos()
+{
+ slotEditTempos(m_doc->getComposition().getPosition());
+}
+
+void RosegardenGUIApp::slotToggleToolBar()
+{
+ KTmpStatusMsg msg(i18n("Toggle the toolbar..."), this);
+
+ if (m_viewToolBar->isChecked())
+ toolBar("mainToolBar")->show();
+ else
+ toolBar("mainToolBar")->hide();
+}
+
+void RosegardenGUIApp::slotToggleToolsToolBar()
+{
+ KTmpStatusMsg msg(i18n("Toggle the tools toolbar..."), this);
+
+ if (m_viewToolsToolBar->isChecked())
+ toolBar("Tools Toolbar")->show();
+ else
+ toolBar("Tools Toolbar")->hide();
+}
+
+void RosegardenGUIApp::slotToggleTracksToolBar()
+{
+ KTmpStatusMsg msg(i18n("Toggle the tracks toolbar..."), this);
+
+ if (m_viewTracksToolBar->isChecked())
+ toolBar("Tracks Toolbar")->show();
+ else
+ toolBar("Tracks Toolbar")->hide();
+}
+
+void RosegardenGUIApp::slotToggleEditorsToolBar()
+{
+ KTmpStatusMsg msg(i18n("Toggle the editor toolbar..."), this);
+
+ if (m_viewEditorsToolBar->isChecked())
+ toolBar("Editors Toolbar")->show();
+ else
+ toolBar("Editors Toolbar")->hide();
+}
+
+void RosegardenGUIApp::slotToggleTransportToolBar()
+{
+ KTmpStatusMsg msg(i18n("Toggle the transport toolbar..."), this);
+
+ if (m_viewTransportToolBar->isChecked())
+ toolBar("Transport Toolbar")->show();
+ else
+ toolBar("Transport Toolbar")->hide();
+}
+
+void RosegardenGUIApp::slotToggleZoomToolBar()
+{
+ KTmpStatusMsg msg(i18n("Toggle the zoom toolbar..."), this);
+
+ if (m_viewZoomToolBar->isChecked())
+ toolBar("Zoom Toolbar")->show();
+ else
+ toolBar("Zoom Toolbar")->hide();
+}
+
+void RosegardenGUIApp::slotToggleTransport()
+{
+ KTmpStatusMsg msg(i18n("Toggle the Transport"), this);
+
+ if (m_viewTransport->isChecked()) {
+ getTransport()->show();
+ getTransport()->raise();
+ getTransport()->blockSignals(false);
+ } else {
+ getTransport()->hide();
+ getTransport()->blockSignals(true);
+ }
+}
+
+void RosegardenGUIApp::slotHideTransport()
+{
+ if (m_viewTransport->isChecked()) {
+ m_viewTransport->blockSignals(true);
+ m_viewTransport->setChecked(false);
+ m_viewTransport->blockSignals(false);
+ }
+ getTransport()->hide();
+ getTransport()->blockSignals(true);
+}
+
+void RosegardenGUIApp::slotToggleTrackLabels()
+{
+ if (m_viewTrackLabels->isChecked()) {
+#ifdef SETTING_LOG_DEBUG
+ _settingLog("toggle track labels on");
+#endif
+
+ m_view->getTrackEditor()->getTrackButtons()->
+ changeTrackInstrumentLabels(TrackLabel::ShowTrack);
+ } else {
+#ifdef SETTING_LOG_DEBUG
+ _settingLog("toggle track labels off");
+#endif
+
+ m_view->getTrackEditor()->getTrackButtons()->
+ changeTrackInstrumentLabels(TrackLabel::ShowInstrument);
+ }
+}
+
+void RosegardenGUIApp::slotToggleRulers()
+{
+ m_view->slotShowRulers(m_viewRulers->isChecked());
+}
+
+void RosegardenGUIApp::slotToggleTempoRuler()
+{
+ m_view->slotShowTempoRuler(m_viewTempoRuler->isChecked());
+}
+
+void RosegardenGUIApp::slotToggleChordNameRuler()
+{
+ m_view->slotShowChordNameRuler(m_viewChordNameRuler->isChecked());
+}
+
+void RosegardenGUIApp::slotTogglePreviews()
+{
+ m_view->slotShowPreviews(m_viewPreviews->isChecked());
+}
+
+void RosegardenGUIApp::slotDockParametersBack()
+{
+ m_dockLeft->dockBack();
+}
+
+void RosegardenGUIApp::slotParametersClosed()
+{
+ stateChanged("parametersbox_closed");
+ m_dockVisible = false;
+}
+
+void RosegardenGUIApp::slotParametersDockedBack(KDockWidget* dw, KDockWidget::DockPosition)
+{
+ if (dw == m_dockLeft) {
+ stateChanged("parametersbox_closed", KXMLGUIClient::StateReverse);
+ m_dockVisible = true;
+ }
+}
+
+void RosegardenGUIApp::slotToggleStatusBar()
+{
+ KTmpStatusMsg msg(i18n("Toggle the statusbar..."), this);
+
+ if (!m_viewStatusBar->isChecked())
+ statusBar()->hide();
+ else
+ statusBar()->show();
+}
+
+void RosegardenGUIApp::slotStatusMsg(QString text)
+{
+ ///////////////////////////////////////////////////////////////////
+ // change status message permanently
+ statusBar()->clear();
+ statusBar()->changeItem(text, EditViewBase::ID_STATUS_MSG);
+}
+
+void RosegardenGUIApp::slotStatusHelpMsg(QString text)
+{
+ ///////////////////////////////////////////////////////////////////
+ // change status message of whole statusbar temporary (text, msec)
+ statusBar()->message(text, 2000);
+}
+
+void RosegardenGUIApp::slotEnableTransport(bool enable)
+{
+ if (m_transport)
+ getTransport()->setEnabled(enable);
+}
+
+void RosegardenGUIApp::slotPointerSelected()
+{
+ m_view->selectTool(SegmentSelector::ToolName);
+}
+
+void RosegardenGUIApp::slotEraseSelected()
+{
+ m_view->selectTool(SegmentEraser::ToolName);
+}
+
+void RosegardenGUIApp::slotDrawSelected()
+{
+ m_view->selectTool(SegmentPencil::ToolName);
+}
+
+void RosegardenGUIApp::slotMoveSelected()
+{
+ m_view->selectTool(SegmentMover::ToolName);
+}
+
+void RosegardenGUIApp::slotResizeSelected()
+{
+ m_view->selectTool(SegmentResizer::ToolName);
+}
+
+void RosegardenGUIApp::slotJoinSelected()
+{
+ KMessageBox::information(this,
+ i18n("The join tool isn't implemented yet. Instead please highlight "
+ "the segments you want to join and then use the menu option:\n\n"
+ " Segments->Collapse Segments.\n"),
+ i18n("Join tool not yet implemented"));
+
+ m_view->selectTool(SegmentJoiner::ToolName);
+}
+
+void RosegardenGUIApp::slotSplitSelected()
+{
+ m_view->selectTool(SegmentSplitter::ToolName);
+}
+
+void RosegardenGUIApp::slotAddTrack()
+{
+ if (!m_view)
+ return ;
+
+ // default to the base number - might not actually exist though
+ //
+ InstrumentId id = MidiInstrumentBase;
+
+ // Get the first Internal/MIDI instrument
+ //
+ DeviceList *devices = m_doc->getStudio().getDevices();
+ bool have = false;
+
+ for (DeviceList::iterator it = devices->begin();
+ it != devices->end() && !have; it++) {
+
+ if ((*it)->getType() != Device::Midi)
+ continue;
+
+ InstrumentList instruments = (*it)->getAllInstruments();
+ for (InstrumentList::iterator iit = instruments.begin();
+ iit != instruments.end(); iit++) {
+
+ if ((*iit)->getId() >= MidiInstrumentBase) {
+ id = (*iit)->getId();
+ have = true;
+ break;
+ }
+ }
+ }
+
+ Composition &comp = m_doc->getComposition();
+ TrackId trackId = comp.getSelectedTrack();
+ Track *track = comp.getTrackById(trackId);
+
+ int pos = -1;
+ if (track) pos = track->getPosition() + 1;
+
+ m_view->slotAddTracks(1, id, pos);
+}
+
+void RosegardenGUIApp::slotAddTracks()
+{
+ if (!m_view)
+ return ;
+
+ // default to the base number - might not actually exist though
+ //
+ InstrumentId id = MidiInstrumentBase;
+
+ // Get the first Internal/MIDI instrument
+ //
+ DeviceList *devices = m_doc->getStudio().getDevices();
+ bool have = false;
+
+ for (DeviceList::iterator it = devices->begin();
+ it != devices->end() && !have; it++) {
+
+ if ((*it)->getType() != Device::Midi)
+ continue;
+
+ InstrumentList instruments = (*it)->getAllInstruments();
+ for (InstrumentList::iterator iit = instruments.begin();
+ iit != instruments.end(); iit++) {
+
+ if ((*iit)->getId() >= MidiInstrumentBase) {
+ id = (*iit)->getId();
+ have = true;
+ break;
+ }
+ }
+ }
+
+ Composition &comp = m_doc->getComposition();
+ TrackId trackId = comp.getSelectedTrack();
+ Track *track = comp.getTrackById(trackId);
+
+ int pos = 0;
+ if (track) pos = track->getPosition();
+
+ bool ok = false;
+
+ AddTracksDialog dialog(this, pos);
+
+ if (dialog.exec() == QDialog::Accepted) {
+ m_view->slotAddTracks(dialog.getTracks(), id,
+ dialog.getInsertPosition());
+ }
+}
+
+void RosegardenGUIApp::slotDeleteTrack()
+{
+ if (!m_view)
+ return ;
+
+ Composition &comp = m_doc->getComposition();
+ TrackId trackId = comp.getSelectedTrack();
+ Track *track = comp.getTrackById(trackId);
+
+ RG_DEBUG << "RosegardenGUIApp::slotDeleteTrack() : about to delete track id "
+ << trackId << endl;
+
+ if (track == 0)
+ return ;
+
+ // Always have at least one track in a composition
+ //
+ if (comp.getNbTracks() == 1)
+ return ;
+
+ // VLADA
+ if (m_view->haveSelection()) {
+
+ SegmentSelection selection = m_view->getSelection();
+ m_view->slotSelectTrackSegments(trackId);
+ m_view->getTrackEditor()->slotDeleteSelectedSegments();
+ m_view->slotPropagateSegmentSelection(selection);
+
+ } else {
+
+ m_view->slotSelectTrackSegments(trackId);
+ m_view->getTrackEditor()->slotDeleteSelectedSegments();
+ }
+ //VLADA
+
+ int position = track->getPosition();
+
+ // Delete the track
+ //
+ std::vector<TrackId> tracks;
+ tracks.push_back(trackId);
+
+ m_view->slotDeleteTracks(tracks);
+
+ // Select a new valid track
+ //
+ if (comp.getTrackByPosition(position))
+ trackId = comp.getTrackByPosition(position)->getId();
+ else if (comp.getTrackByPosition(position - 1))
+ trackId = comp.getTrackByPosition(position - 1)->getId();
+ else {
+ RG_DEBUG << "RosegardenGUIApp::slotDeleteTrack - "
+ << "can't select a highlighted track after delete"
+ << endl;
+ }
+
+ comp.setSelectedTrack(trackId);
+
+ Instrument *inst = m_doc->getStudio().
+ getInstrumentById(comp.getTrackById(trackId)->getInstrument());
+
+ //VLADA
+ // m_view->slotSelectTrackSegments(trackId);
+ //VLADA
+}
+
+void RosegardenGUIApp::slotMoveTrackDown()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotMoveTrackDown" << endl;
+
+ Composition &comp = m_doc->getComposition();
+ Track *srcTrack = comp.getTrackById(comp.getSelectedTrack());
+
+ // Check for track object
+ //
+ if (srcTrack == 0)
+ return ;
+
+ // Check destination track exists
+ //
+ Track *destTrack =
+ comp.getTrackByPosition(srcTrack->getPosition() + 1);
+
+ if (destTrack == 0)
+ return ;
+
+ MoveTracksCommand *command =
+ new MoveTracksCommand(&comp, srcTrack->getId(), destTrack->getId());
+
+ m_doc->getCommandHistory()->addCommand(command);
+
+ // make sure we're showing the right selection
+ m_view->slotSelectTrackSegments(comp.getSelectedTrack());
+
+}
+
+void RosegardenGUIApp::slotMoveTrackUp()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotMoveTrackUp" << endl;
+
+ Composition &comp = m_doc->getComposition();
+ Track *srcTrack = comp.getTrackById(comp.getSelectedTrack());
+
+ // Check for track object
+ //
+ if (srcTrack == 0)
+ return ;
+
+ // Check we're not at the top already
+ //
+ if (srcTrack->getPosition() == 0)
+ return ;
+
+ // Check destination track exists
+ //
+ Track *destTrack =
+ comp.getTrackByPosition(srcTrack->getPosition() - 1);
+
+ if (destTrack == 0)
+ return ;
+
+ MoveTracksCommand *command =
+ new MoveTracksCommand(&comp, srcTrack->getId(), destTrack->getId());
+
+ m_doc->getCommandHistory()->addCommand(command);
+
+ // make sure we're showing the right selection
+ m_view->slotSelectTrackSegments(comp.getSelectedTrack());
+}
+
+void RosegardenGUIApp::slotRevertToSaved()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotRevertToSaved" << endl;
+
+ if (m_doc->isModified()) {
+ int revert =
+ KMessageBox::questionYesNo(this,
+ i18n("Revert modified document to previous saved version?"));
+
+ if (revert == KMessageBox::No)
+ return ;
+
+ openFile(m_doc->getAbsFilePath());
+ }
+}
+
+void RosegardenGUIApp::slotImportProject()
+{
+ if (m_doc && !m_doc->saveIfModified())
+ return ;
+
+ KURL url = KFileDialog::getOpenURL
+ (":RGPROJECT",
+ i18n("*.rgp|Rosegarden Project files\n*|All files"), this,
+ i18n("Import Rosegarden Project File"));
+ if (url.isEmpty()) {
+ return ;
+ }
+
+ QString tmpfile;
+ KIO::NetAccess::download(url, tmpfile, this);
+
+ importProject(tmpfile);
+
+ KIO::NetAccess::removeTempFile(tmpfile);
+}
+
+void RosegardenGUIApp::importProject(QString filePath)
+{
+ KProcess *proc = new KProcess;
+ *proc << "rosegarden-project-package";
+ *proc << "--unpack";
+ *proc << filePath;
+
+ KStartupLogo::hideIfStillThere();
+ proc->start(KProcess::Block, KProcess::All);
+
+ if (!proc->normalExit() || proc->exitStatus()) {
+ CurrentProgressDialog::freeze();
+ KMessageBox::sorry(this, i18n("Failed to import project file \"%1\"").arg(filePath));
+ CurrentProgressDialog::thaw();
+ delete proc;
+ return ;
+ }
+
+ delete proc;
+
+ QString rgFile = filePath;
+ rgFile.replace(QRegExp(".rg.rgp$"), ".rg");
+ rgFile.replace(QRegExp(".rgp$"), ".rg");
+ openURL(rgFile);
+}
+
+void RosegardenGUIApp::slotImportMIDI()
+{
+ if (m_doc && !m_doc->saveIfModified())
+ return ;
+
+ KURL url = KFileDialog::getOpenURL
+ (":MIDI",
+ "audio/x-midi", this,
+ i18n("Open MIDI File"));
+ if (url.isEmpty()) {
+ return ;
+ }
+
+ QString tmpfile;
+ KIO::NetAccess::download(url, tmpfile, this);
+ openFile(tmpfile, ImportMIDI); // does everything including setting the document
+
+ KIO::NetAccess::removeTempFile( tmpfile );
+}
+
+void RosegardenGUIApp::slotMergeMIDI()
+{
+ KURL url = KFileDialog::getOpenURL
+ (":MIDI",
+ "audio/x-midi", this,
+ i18n("Merge MIDI File"));
+ if (url.isEmpty()) {
+ return ;
+ }
+
+ QString tmpfile;
+ KIO::NetAccess::download(url, tmpfile, this);
+ mergeFile(tmpfile, ImportMIDI);
+
+ KIO::NetAccess::removeTempFile( tmpfile );
+}
+
+QTextCodec *
+RosegardenGUIApp::guessTextCodec(std::string text)
+{
+ QTextCodec *codec = 0;
+
+ for (int c = 0; c < text.length(); ++c) {
+ if (text[c] & 0x80) {
+
+ CurrentProgressDialog::freeze();
+ KStartupLogo::hideIfStillThere();
+
+ IdentifyTextCodecDialog dialog(0, text);
+ dialog.exec();
+
+ std::string codecName = dialog.getCodec();
+
+ CurrentProgressDialog::thaw();
+
+ if (codecName != "") {
+ codec = QTextCodec::codecForName(codecName.c_str());
+ }
+ break;
+ }
+ }
+
+ return codec;
+}
+
+void
+RosegardenGUIApp::fixTextEncodings(Composition *c)
+
+{
+ QTextCodec *codec = 0;
+
+ for (Composition::iterator i = c->begin();
+ i != c->end(); ++i) {
+
+ for (Segment::iterator j = (*i)->begin();
+ j != (*i)->end(); ++j) {
+
+ if ((*j)->isa(Text::EventType)) {
+
+ std::string text;
+
+ if ((*j)->get
+ <String>
+ (Text::TextPropertyName, text)) {
+
+ if (!codec)
+ codec = guessTextCodec(text);
+
+ if (codec) {
+ (*j)->set
+ <String>
+ (Text::TextPropertyName,
+ convertFromCodec(text, codec));
+ }
+ }
+ }
+ }
+ }
+
+ if (!codec)
+ codec = guessTextCodec(c->getCopyrightNote());
+ if (codec)
+ c->setCopyrightNote(convertFromCodec(c->getCopyrightNote(), codec));
+
+ for (Composition::trackcontainer::iterator i =
+ c->getTracks().begin(); i != c->getTracks().end(); ++i) {
+ if (!codec)
+ codec = guessTextCodec(i->second->getLabel());
+ if (codec)
+ i->second->setLabel(convertFromCodec(i->second->getLabel(), codec));
+ }
+
+ for (Composition::iterator i = c->begin(); i != c->end(); ++i) {
+ if (!codec)
+ codec = guessTextCodec((*i)->getLabel());
+ if (codec)
+ (*i)->setLabel(convertFromCodec((*i)->getLabel(), codec));
+ }
+}
+
+RosegardenGUIDoc*
+RosegardenGUIApp::createDocumentFromMIDIFile(QString file)
+{
+ //if (!merge && !m_doc->saveIfModified()) return;
+
+ // Create new document (autoload is inherent)
+ //
+ RosegardenGUIDoc *newDoc = new RosegardenGUIDoc(this, m_pluginManager);
+
+ std::string fname(QFile::encodeName(file));
+
+ MidiFile midiFile(fname,
+ &newDoc->getStudio());
+
+ KStartupLogo::hideIfStillThere();
+ ProgressDialog progressDlg(i18n("Importing MIDI file..."),
+ 200,
+ this);
+
+ CurrentProgressDialog::set
+ (&progressDlg);
+
+ connect(&midiFile, SIGNAL(setProgress(int)),
+ progressDlg.progressBar(), SLOT(setValue(int)));
+
+ connect(&midiFile, SIGNAL(incrementProgress(int)),
+ progressDlg.progressBar(), SLOT(advance(int)));
+
+ if (!midiFile.open()) {
+ CurrentProgressDialog::freeze();
+ KMessageBox::error(this, strtoqstr(midiFile.getError())); //!!! i18n
+ delete newDoc;
+ return 0;
+ }
+
+ midiFile.convertToRosegarden(newDoc->getComposition(),
+ MidiFile::CONVERT_REPLACE);
+
+ fixTextEncodings(&newDoc->getComposition());
+
+ // Set modification flag
+ //
+ newDoc->slotDocumentModified();
+
+ // Set the caption
+ //
+ newDoc->setTitle(QFileInfo(file).fileName());
+ newDoc->setAbsFilePath(QFileInfo(file).absFilePath());
+
+ // Clean up for notation purposes (after reinitialise, because that
+ // sets the composition's end marker time which is needed here)
+
+ progressDlg.slotSetOperationName(i18n("Calculating notation..."));
+ ProgressDialog::processEvents();
+
+ Composition *comp = &newDoc->getComposition();
+
+ for (Composition::iterator i = comp->begin();
+ i != comp->end(); ++i) {
+
+ Segment &segment = **i;
+ SegmentNotationHelper helper(segment);
+ segment.insert(helper.guessClef(segment.begin(),
+ segment.getEndMarker()).getAsEvent
+ (segment.getStartTime()));
+ }
+
+ progressDlg.progressBar()->setProgress(100);
+
+ for (Composition::iterator i = comp->begin();
+ i != comp->end(); ++i) {
+
+ // find first key event in each segment (we'd have done the
+ // same for clefs, except there is no MIDI clef event)
+
+ Segment &segment = **i;
+ timeT firstKeyTime = segment.getEndMarkerTime();
+
+ for (Segment::iterator si = segment.begin();
+ segment.isBeforeEndMarker(si); ++si) {
+ if ((*si)->isa(Rosegarden::Key::EventType)) {
+ firstKeyTime = (*si)->getAbsoluteTime();
+ break;
+ }
+ }
+
+ if (firstKeyTime > segment.getStartTime()) {
+ CompositionTimeSliceAdapter adapter
+ (comp, timeT(0), firstKeyTime);
+ AnalysisHelper helper;
+ segment.insert(helper.guessKey(adapter).getAsEvent
+ (segment.getStartTime()));
+ }
+ }
+
+ int progressPer = 100;
+ if (comp->getNbSegments() > 0)
+ progressPer = (int)(100.0 / double(comp->getNbSegments()));
+
+ KMacroCommand *command = new KMacroCommand(i18n("Calculate Notation"));
+
+ for (Composition::iterator i = comp->begin();
+ i != comp->end(); ++i) {
+
+ Segment &segment = **i;
+ timeT startTime(segment.getStartTime());
+ timeT endTime(segment.getEndMarkerTime());
+
+// std::cerr << "segment: start time " << segment.getStartTime() << ", end time " << segment.getEndTime() << ", end marker time " << segment.getEndMarkerTime() << ", events " << segment.size() << std::endl;
+
+ EventQuantizeCommand *subCommand = new EventQuantizeCommand
+ (segment, startTime, endTime, "Notation Options", true);
+
+ subCommand->setProgressTotal(progressPer + 1);
+ QObject::connect(subCommand, SIGNAL(incrementProgress(int)),
+ progressDlg.progressBar(), SLOT(advance(int)));
+
+ command->addCommand(subCommand);
+ }
+
+ newDoc->getCommandHistory()->addCommand(command);
+
+ if (comp->getTimeSignatureCount() == 0) {
+ CompositionTimeSliceAdapter adapter(comp);
+ AnalysisHelper analysisHelper;
+ TimeSignature timeSig =
+ analysisHelper.guessTimeSignature(adapter);
+ comp->addTimeSignature(0, timeSig);
+ }
+
+ return newDoc;
+}
+
+void RosegardenGUIApp::slotImportRG21()
+{
+ if (m_doc && !m_doc->saveIfModified())
+ return ;
+
+ KURL url = KFileDialog::getOpenURL
+ (":ROSEGARDEN21",
+ i18n("*.rose|Rosegarden-2 files\n*|All files"), this,
+ i18n("Open Rosegarden 2.1 File"));
+ if (url.isEmpty()) {
+ return ;
+ }
+
+ QString tmpfile;
+ KIO::NetAccess::download(url, tmpfile, this);
+ openFile(tmpfile, ImportRG21);
+
+ KIO::NetAccess::removeTempFile(tmpfile);
+}
+
+void RosegardenGUIApp::slotMergeRG21()
+{
+ KURL url = KFileDialog::getOpenURL
+ (":ROSEGARDEN21",
+ i18n("*.rose|Rosegarden-2 files\n*|All files"), this,
+ i18n("Open Rosegarden 2.1 File"));
+ if (url.isEmpty()) {
+ return ;
+ }
+
+ QString tmpfile;
+ KIO::NetAccess::download(url, tmpfile, this);
+ mergeFile(tmpfile, ImportRG21);
+
+ KIO::NetAccess::removeTempFile( tmpfile );
+}
+
+RosegardenGUIDoc*
+RosegardenGUIApp::createDocumentFromRG21File(QString file)
+{
+ KStartupLogo::hideIfStillThere();
+ ProgressDialog progressDlg(
+ i18n("Importing Rosegarden 2.1 file..."), 100, this);
+
+ CurrentProgressDialog::set
+ (&progressDlg);
+
+ // Inherent autoload
+ //
+ RosegardenGUIDoc *newDoc = new RosegardenGUIDoc(this, m_pluginManager);
+
+ RG21Loader rg21Loader(&newDoc->getStudio());
+
+ // TODO: make RG21Loader to actually emit these signals
+ //
+ connect(&rg21Loader, SIGNAL(setProgress(int)),
+ progressDlg.progressBar(), SLOT(setValue(int)));
+
+ connect(&rg21Loader, SIGNAL(incrementProgress(int)),
+ progressDlg.progressBar(), SLOT(advance(int)));
+
+ // "your starter for 40%" - helps the "freeze" work
+ //
+ progressDlg.progressBar()->advance(40);
+
+ if (!rg21Loader.load(file, newDoc->getComposition())) {
+ CurrentProgressDialog::freeze();
+ KMessageBox::error(this,
+ i18n("Can't load Rosegarden 2.1 file. It appears to be corrupted."));
+ delete newDoc;
+ return 0;
+ }
+
+ // Set modification flag
+ //
+ newDoc->slotDocumentModified();
+
+ // Set the caption and add recent
+ //
+ newDoc->setTitle(QFileInfo(file).fileName());
+ newDoc->setAbsFilePath(QFileInfo(file).absFilePath());
+
+ return newDoc;
+
+}
+
+void
+RosegardenGUIApp::slotImportHydrogen()
+{
+ if (m_doc && !m_doc->saveIfModified())
+ return ;
+
+ KURL url = KFileDialog::getOpenURL
+ (":HYDROGEN",
+ i18n("*.h2song|Hydrogen files\n*|All files"), this,
+ i18n("Open Hydrogen File"));
+ if (url.isEmpty()) {
+ return ;
+ }
+
+ QString tmpfile;
+ KIO::NetAccess::download(url, tmpfile, this);
+ openFile(tmpfile, ImportHydrogen);
+
+ KIO::NetAccess::removeTempFile(tmpfile);
+}
+
+void RosegardenGUIApp::slotMergeHydrogen()
+{
+ KURL url = KFileDialog::getOpenURL
+ (":HYDROGEN",
+ i18n("*.h2song|Hydrogen files\n*|All files"), this,
+ i18n("Open Hydrogen File"));
+ if (url.isEmpty()) {
+ return ;
+ }
+
+ QString tmpfile;
+ KIO::NetAccess::download(url, tmpfile, this);
+ mergeFile(tmpfile, ImportHydrogen);
+
+ KIO::NetAccess::removeTempFile( tmpfile );
+}
+
+RosegardenGUIDoc*
+RosegardenGUIApp::createDocumentFromHydrogenFile(QString file)
+{
+ KStartupLogo::hideIfStillThere();
+ ProgressDialog progressDlg(
+ i18n("Importing Hydrogen file..."), 100, this);
+
+ CurrentProgressDialog::set
+ (&progressDlg);
+
+ // Inherent autoload
+ //
+ RosegardenGUIDoc *newDoc = new RosegardenGUIDoc(this, m_pluginManager);
+
+ HydrogenLoader hydrogenLoader(&newDoc->getStudio());
+
+ // TODO: make RG21Loader to actually emit these signals
+ //
+ connect(&hydrogenLoader, SIGNAL(setProgress(int)),
+ progressDlg.progressBar(), SLOT(setValue(int)));
+
+ connect(&hydrogenLoader, SIGNAL(incrementProgress(int)),
+ progressDlg.progressBar(), SLOT(advance(int)));
+
+ // "your starter for 40%" - helps the "freeze" work
+ //
+ progressDlg.progressBar()->advance(40);
+
+ if (!hydrogenLoader.load(file, newDoc->getComposition())) {
+ CurrentProgressDialog::freeze();
+ KMessageBox::error(this,
+ i18n("Can't load Hydrogen file. It appears to be corrupted."));
+ delete newDoc;
+ return 0;
+ }
+
+ // Set modification flag
+ //
+ newDoc->slotDocumentModified();
+
+ // Set the caption and add recent
+ //
+ newDoc->setTitle(QFileInfo(file).fileName());
+ newDoc->setAbsFilePath(QFileInfo(file).absFilePath());
+
+ return newDoc;
+
+}
+
+void
+RosegardenGUIApp::mergeFile(QString filePath, ImportType type)
+{
+ RosegardenGUIDoc *doc = createDocument(filePath, type);
+
+ if (doc) {
+ if (m_doc) {
+
+ bool timingsDiffer = false;
+ Composition &c1 = m_doc->getComposition();
+ Composition &c2 = doc->getComposition();
+
+ // compare tempos and time sigs in the two -- rather laborious
+
+ if (c1.getTimeSignatureCount() != c2.getTimeSignatureCount()) {
+ timingsDiffer = true;
+ } else {
+ for (int i = 0; i < c1.getTimeSignatureCount(); ++i) {
+ std::pair<timeT, TimeSignature> t1 =
+ c1.getTimeSignatureChange(i);
+ std::pair<timeT, TimeSignature> t2 =
+ c2.getTimeSignatureChange(i);
+ if (t1.first != t2.first || t1.second != t2.second) {
+ timingsDiffer = true;
+ break;
+ }
+ }
+ }
+
+ if (c1.getTempoChangeCount() != c2.getTempoChangeCount()) {
+ timingsDiffer = true;
+ } else {
+ for (int i = 0; i < c1.getTempoChangeCount(); ++i) {
+ std::pair<timeT, tempoT> t1 = c1.getTempoChange(i);
+ std::pair<timeT, tempoT> t2 = c2.getTempoChange(i);
+ if (t1.first != t2.first || t1.second != t2.second) {
+ timingsDiffer = true;
+ break;
+ }
+ }
+ }
+
+ FileMergeDialog dialog(this, filePath, timingsDiffer);
+ if (dialog.exec() == QDialog::Accepted) {
+ m_doc->mergeDocument(doc, dialog.getMergeOptions());
+ }
+
+ delete doc;
+
+ } else {
+ setDocument(doc);
+ }
+ }
+}
+
+void
+RosegardenGUIApp::slotUpdatePlaybackPosition()
+{
+ static int callbackCount = 0;
+
+ // Either sequencer mappper or the sequence manager could be missing at
+ // this point.
+ //
+ if (!m_seqManager || !m_seqManager->getSequencerMapper())
+ return ;
+
+ SequencerMapper *mapper = m_seqManager->getSequencerMapper();
+
+ MappedEvent ev;
+ bool haveEvent = mapper->getVisual(ev);
+ if (haveEvent)
+ getTransport()->setMidiOutLabel(&ev);
+
+ RealTime position = mapper->getPositionPointer();
+
+ // std::cerr << "RosegardenGUIApp::slotUpdatePlaybackPosition: mapper pos = " << position << std::endl;
+
+ Composition &comp = m_doc->getComposition();
+ timeT elapsedTime = comp.getElapsedTimeForRealTime(position);
+
+ // std::cerr << "RosegardenGUIApp::slotUpdatePlaybackPosition: mapper timeT = " << elapsedTime << std::endl;
+
+ if (m_seqManager->getTransportStatus() == RECORDING) {
+
+ MappedComposition mC;
+ if (mapper->getRecordedEvents(mC) > 0) {
+ m_seqManager->processAsynchronousMidi(mC, 0);
+ m_doc->insertRecordedMidi(mC);
+ }
+
+ m_doc->updateRecordingMIDISegment();
+ m_doc->updateRecordingAudioSegments();
+ }
+
+ m_originatingJump = true;
+ m_doc->slotSetPointerPosition(elapsedTime);
+ m_originatingJump = false;
+
+ if (m_audioMixer && m_audioMixer->isVisible())
+ m_audioMixer->updateMeters(mapper);
+
+ if (m_midiMixer && m_midiMixer->isVisible())
+ m_midiMixer->updateMeters(mapper);
+
+ m_view->updateMeters(mapper);
+
+ if (++callbackCount == 60) {
+ slotUpdateCPUMeter(true);
+ callbackCount = 0;
+ }
+
+ // if (elapsedTime >= comp.getEndMarker())
+ // slotStop();
+}
+
+void
+RosegardenGUIApp::slotUpdateCPUMeter(bool playing)
+{
+ static std::ifstream *statstream = 0;
+ static bool modified = false;
+ static unsigned long lastBusy = 0, lastIdle = 0;
+
+ if (playing) {
+
+ if (!statstream) {
+ statstream = new std::ifstream("/proc/stat", std::ios::in);
+ }
+
+ if (!statstream || !*statstream)
+ return ;
+ statstream->seekg(0, std::ios::beg);
+
+ std::string cpu;
+ unsigned long user, nice, sys, idle;
+ *statstream >> cpu;
+ *statstream >> user;
+ *statstream >> nice;
+ *statstream >> sys;
+ *statstream >> idle;
+
+ unsigned long busy = user + nice + sys;
+ unsigned long count = 0;
+
+ if (lastBusy > 0) {
+ unsigned long bd = busy - lastBusy;
+ unsigned long id = idle - lastIdle;
+ if (bd + id > 0)
+ count = bd * 100 / (bd + id);
+ if (count > 100)
+ count = 100;
+ }
+
+ lastBusy = busy;
+ lastIdle = idle;
+
+ if (m_progressBar) {
+ if (!modified) {
+ m_progressBar->setTextEnabled(true);
+ m_progressBar->setFormat("CPU");
+ }
+ m_progressBar->setProgress(count);
+ }
+
+ modified = true;
+
+ } else if (modified) {
+ if (m_progressBar) {
+ m_progressBar->setTextEnabled(false);
+ m_progressBar->setFormat("%p%");
+ m_progressBar->setProgress(0);
+ }
+ modified = false;
+ }
+}
+
+void
+RosegardenGUIApp::slotUpdateMonitoring()
+{
+ // Either sequencer mappper or the sequence manager could be missing at
+ // this point.
+ //
+ if (!m_seqManager || !m_seqManager->getSequencerMapper())
+ return ;
+
+ SequencerMapper *mapper = m_seqManager->getSequencerMapper();
+
+ if (m_audioMixer && m_audioMixer->isVisible())
+ m_audioMixer->updateMonitorMeters(mapper);
+
+ if (m_midiMixer && m_midiMixer->isVisible())
+ m_midiMixer->updateMonitorMeter(mapper);
+
+ m_view->updateMonitorMeters(mapper);
+
+ slotUpdateCPUMeter(false);
+}
+
+void RosegardenGUIApp::slotSetPointerPosition(timeT t)
+{
+ Composition &comp = m_doc->getComposition();
+
+ // std::cerr << "RosegardenGUIApp::slotSetPointerPosition: t = " << t << std::endl;
+
+ if (m_seqManager) {
+ if ( m_seqManager->getTransportStatus() == PLAYING ||
+ m_seqManager->getTransportStatus() == RECORDING ) {
+ if (t > comp.getEndMarker()) {
+ if (m_seqManager->getTransportStatus() == PLAYING) {
+
+ slotStop();
+ t = comp.getEndMarker();
+ m_doc->slotSetPointerPosition(t); //causes this method to be re-invoked
+ return ;
+
+ } else { // if recording, increase composition duration
+ std::pair<timeT, timeT> timeRange = comp.getBarRangeForTime(t);
+ timeT barDuration = timeRange.second - timeRange.first;
+ timeT newEndMarker = t + 10 * barDuration;
+ comp.setEndMarker(newEndMarker);
+ getView()->getTrackEditor()->slotReadjustCanvasSize();
+ getView()->getTrackEditor()->updateRulers();
+ }
+ }
+ }
+
+ // cc 20050520 - jump at the sequencer even if we're not playing,
+ // because we might be a transport master of some kind
+ try {
+ if (!m_originatingJump) {
+ m_seqManager->sendSequencerJump(comp.getElapsedRealTime(t));
+ }
+ } catch (QString s) {
+ KMessageBox::error(this, s);
+ }
+ }
+
+ // set the time sig
+ getTransport()->setTimeSignature(comp.getTimeSignatureAt(t));
+
+ // and the tempo
+ getTransport()->setTempo(comp.getTempoAtTime(t));
+
+ // and the time
+ //
+ TransportDialog::TimeDisplayMode mode =
+ getTransport()->getCurrentMode();
+
+ if (mode == TransportDialog::BarMode ||
+ mode == TransportDialog::BarMetronomeMode) {
+
+ slotDisplayBarTime(t);
+
+ } else {
+
+ RealTime rT(comp.getElapsedRealTime(t));
+
+ if (getTransport()->isShowingTimeToEnd()) {
+ rT = rT - comp.getElapsedRealTime(comp.getDuration());
+ }
+
+ if (mode == TransportDialog::RealMode) {
+
+ getTransport()->displayRealTime(rT);
+
+ } else if (mode == TransportDialog::SMPTEMode) {
+
+ getTransport()->displaySMPTETime(rT);
+
+ } else {
+
+ getTransport()->displayFrameTime(rT);
+ }
+ }
+
+ // handle transport mode configuration changes
+ std::string modeAsString = getTransport()->getCurrentModeAsString();
+
+ if (m_doc->getConfiguration().get<String>
+ (DocumentConfiguration::TransportMode) != modeAsString) {
+
+ m_doc->getConfiguration().set<String>
+ (DocumentConfiguration::TransportMode, modeAsString);
+
+ //m_doc->slotDocumentModified(); to avoid being prompted for a file change when merely changing the transport display
+ }
+
+ // Update position on the marker editor if it's available
+ //
+ if (m_markerEditor)
+ m_markerEditor->updatePosition();
+}
+
+void RosegardenGUIApp::slotDisplayBarTime(timeT t)
+{
+ Composition &comp = m_doc->getComposition();
+
+ int barNo = comp.getBarNumber(t);
+ timeT barStart = comp.getBarStart(barNo);
+
+ TimeSignature timeSig = comp.getTimeSignatureAt(t);
+ timeT beatDuration = timeSig.getBeatDuration();
+
+ int beatNo = (t - barStart) / beatDuration;
+ int unitNo = (t - barStart) - (beatNo * beatDuration);
+
+ if (getTransport()->isShowingTimeToEnd()) {
+ barNo = barNo + 1 - comp.getNbBars();
+ beatNo = timeSig.getBeatsPerBar() - 1 - beatNo;
+ unitNo = timeSig.getBeatDuration() - 1 - unitNo;
+ } else {
+ // convert to 1-based display bar numbers
+ barNo += 1;
+ beatNo += 1;
+ }
+
+ // show units in hemidemis (or whatever), not in raw time ticks
+ unitNo /= Note(Note::Shortest).getDuration();
+
+ getTransport()->displayBarTime(barNo, beatNo, unitNo);
+}
+
+void RosegardenGUIApp::slotRefreshTimeDisplay()
+{
+ if ( m_seqManager->getTransportStatus() == PLAYING ||
+ m_seqManager->getTransportStatus() == RECORDING ) {
+ return ; // it'll be refreshed in a moment anyway
+ }
+ slotSetPointerPosition(m_doc->getComposition().getPosition());
+}
+
+bool
+RosegardenGUIApp::isTrackEditorPlayTracking() const
+{
+ return m_view->getTrackEditor()->isTracking();
+}
+
+void RosegardenGUIApp::slotToggleTracking()
+{
+ m_view->getTrackEditor()->slotToggleTracking();
+}
+
+void RosegardenGUIApp::slotTestStartupTester()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotTestStartupTester" << endl;
+
+ if (!m_startupTester) {
+ m_startupTester = new StartupTester();
+ connect(m_startupTester, SIGNAL(newerVersionAvailable(QString)),
+ this, SLOT(slotNewerVersionAvailable(QString)));
+ m_startupTester->start();
+ QTimer::singleShot(100, this, SLOT(slotTestStartupTester()));
+ return ;
+ }
+
+ if (!m_startupTester->isReady()) {
+ QTimer::singleShot(100, this, SLOT(slotTestStartupTester()));
+ return ;
+ }
+
+ QStringList missingFeatures;
+ QStringList allMissing;
+
+ QStringList missing;
+ bool have = m_startupTester->haveProjectPackager(&missing);
+
+ stateChanged("have_project_packager",
+ have ?
+ KXMLGUIClient::StateNoReverse : KXMLGUIClient::StateReverse);
+
+ if (!have) {
+ missingFeatures.push_back(i18n("Export and import of Rosegarden Project files"));
+ if (missing.count() == 0) {
+ allMissing.push_back(i18n("The Rosegarden Project Packager helper script"));
+ } else {
+ for (int i = 0; i < missing.count(); ++i) {
+// if (missingFeatures.count() > 1) {
+ allMissing.push_back(i18n("%1 - for project file support").arg(missing[i]));
+// } else {
+// allMissing.push_back(missing[i]);
+// }
+ }
+ }
+ }
+
+ have = m_startupTester->haveLilyPondView(&missing);
+
+ stateChanged("have_lilypondview",
+ have ?
+ KXMLGUIClient::StateNoReverse : KXMLGUIClient::StateReverse);
+
+ if (!have) {
+ missingFeatures.push_back("Notation previews through LilyPond");
+ if (missing.count() == 0) {
+ allMissing.push_back(i18n("The Rosegarden LilyPondView helper script"));
+ } else {
+ for (int i = 0; i < missing.count(); ++i) {
+ if (missingFeatures.count() > 1) {
+ allMissing.push_back(i18n("%1 - for LilyPond preview support").arg(missing[i]));
+ } else {
+ allMissing.push_back(missing[i]);
+ }
+ }
+ }
+ }
+
+#ifdef HAVE_LIBJACK
+ if (m_seqManager && (m_seqManager->getSoundDriverStatus() & AUDIO_OK)) {
+
+ m_haveAudioImporter = m_startupTester->haveAudioFileImporter(&missing);
+
+ if (!m_haveAudioImporter) {
+ missingFeatures.push_back("General audio file import and conversion");
+ if (missing.count() == 0) {
+ allMissing.push_back(i18n("The Rosegarden Audio File Importer helper script"));
+ } else {
+ for (int i = 0; i < missing.count(); ++i) {
+ if (missingFeatures.count() > 1) {
+ allMissing.push_back(i18n("%1 - for audio file import").arg(missing[i]));
+ } else {
+ allMissing.push_back(missing[i]);
+ }
+ }
+ }
+ }
+ }
+#endif
+
+ if (missingFeatures.count() > 0) {
+ QString message = i18n("<h3>Helper programs not found</h3><p>Rosegarden could not find one or more helper programs which it needs to provide some features. The following features will not be available:</p>");
+ message += i18n("<ul>");
+ for (int i = 0; i < missingFeatures.count(); ++i) {
+ message += i18n("<li>%1</li>").arg(missingFeatures[i]);
+ }
+ message += i18n("</ul>");
+ message += i18n("<p>To fix this, you should install the following additional programs:</p>");
+ message += i18n("<ul>");
+ for (int i = 0; i < allMissing.count(); ++i) {
+ message += i18n("<li>%1</li>").arg(allMissing[i]);
+ }
+ message += i18n("</ul>");
+
+ awaitDialogClearance();
+
+ KMessageBox::information
+ (m_view,
+ message,
+ i18n("Helper programs not found"),
+ "startup-helpers-missing");
+ }
+
+ delete m_startupTester;
+ m_startupTester = 0;
+}
+
+void RosegardenGUIApp::slotDebugDump()
+{
+ Composition &comp = m_doc->getComposition();
+ comp.dump(std::cerr);
+}
+
+bool RosegardenGUIApp::launchSequencer(bool useExisting)
+{
+ if (!isUsingSequencer()) {
+ RG_DEBUG << "RosegardenGUIApp::launchSequencer() - not using seq. - returning\n";
+ return false; // no need to launch anything
+ }
+
+ if (isSequencerRunning()) {
+ RG_DEBUG << "RosegardenGUIApp::launchSequencer() - sequencer already running - returning\n";
+ if (m_seqManager) m_seqManager->checkSoundDriverStatus(false);
+ return true;
+ }
+
+ // Check to see if we're clearing down sequencer processes -
+ // if we're not we check DCOP for an existing sequencer and
+ // try to talk to use that (that's the "developer" mode).
+ //
+ // User mode should clear down sequencer processes.
+ //
+ if (kapp->dcopClient()->isApplicationRegistered(
+ QCString(ROSEGARDEN_SEQUENCER_APP_NAME))) {
+ RG_DEBUG << "RosegardenGUIApp::launchSequencer() - "
+ << "existing DCOP registered sequencer found\n";
+
+ if (useExisting) {
+ if (m_seqManager) m_seqManager->checkSoundDriverStatus(false);
+ m_sequencerProcess = (KProcess*)SequencerExternal;
+ return true;
+ }
+
+ KProcess *proc = new KProcess;
+ *proc << "/usr/bin/killall";
+ *proc << "rosegardensequencer";
+ *proc << "lt-rosegardensequencer";
+
+ proc->start(KProcess::Block, KProcess::All);
+
+ if (!proc->normalExit() || proc->exitStatus()) {
+ RG_DEBUG << "couldn't kill any sequencer processes" << endl;
+ }
+ delete proc;
+
+ sleep(1);
+
+ if (kapp->dcopClient()->isApplicationRegistered(
+ QCString(ROSEGARDEN_SEQUENCER_APP_NAME))) {
+ RG_DEBUG << "RosegardenGUIApp::launchSequencer() - "
+ << "failed to kill existing sequencer\n";
+
+ KProcess *proc = new KProcess;
+ *proc << "/usr/bin/killall";
+ *proc << "-9";
+ *proc << "rosegardensequencer";
+ *proc << "lt-rosegardensequencer";
+
+ proc->start(KProcess::Block, KProcess::All);
+
+ if (proc->exitStatus()) {
+ RG_DEBUG << "couldn't kill any sequencer processes" << endl;
+ }
+ delete proc;
+
+ sleep(1);
+ }
+ }
+
+ //
+ // No sequencer is running, so start one
+ //
+ KTmpStatusMsg msg(i18n("Starting the sequencer..."), this);
+
+ if (!m_sequencerProcess) {
+ m_sequencerProcess = new KProcess;
+
+ (*m_sequencerProcess) << "rosegardensequencer";
+
+ // Command line arguments
+ //
+ KConfig *config = kapp->config();
+ config->setGroup(SequencerOptionsConfigGroup);
+ QString options = config->readEntry("commandlineoptions");
+ if (!options.isEmpty()) {
+ (*m_sequencerProcess) << options;
+ RG_DEBUG << "sequencer options \"" << options << "\"" << endl;
+ }
+
+ } else {
+ RG_DEBUG << "RosegardenGUIApp::launchSequencer() - sequencer KProcess already created\n";
+ m_sequencerProcess->disconnect(); // disconnect processExit signal
+ // it will be reconnected later on
+ }
+
+ bool res = m_sequencerProcess->start();
+
+ if (!res) {
+ KMessageBox::error(0, i18n("Couldn't start the sequencer"));
+ RG_DEBUG << "Couldn't start the sequencer\n";
+ m_sequencerProcess = 0;
+ // If starting it didn't even work, fall back to no sequencer mode
+ m_useSequencer = false;
+ } else {
+ // connect processExited only after start, otherwise
+ // a failed startup will call slotSequencerExited()
+ // right away and we don't get to check the result
+ // of m_sequencerProcess->start() and thus make the distinction
+ // between the case where the sequencer was successfully launched
+ // but crashed right away, or the case where the process couldn't
+ // be launched at all (missing executable, etc...)
+ //
+ // We also re-check that the process is still running at this
+ // point in case it crashed between the moment we check res above
+ // and now.
+ //
+ //usleep(1000 * 1000); // even wait half a sec. to make sure it's actually running
+ if (m_sequencerProcess->isRunning()) {
+
+ try {
+ // if (m_seqManager) {
+ // RG_DEBUG << "RosegardenGUIApp::launchSequencer : checking sound driver status\n";
+ // m_seqManager->checkSoundDriverStatus();
+ // }
+
+ stateChanged("sequencer_running");
+ slotEnableTransport(true);
+
+ connect(m_sequencerProcess, SIGNAL(processExited(KProcess*)),
+ this, SLOT(slotSequencerExited(KProcess*)));
+
+ } catch (Exception e) {
+ m_sequencerProcess = 0;
+ m_useSequencer = false;
+ stateChanged("sequencer_running", KXMLGUIClient::StateReverse);
+ slotEnableTransport(false);
+ }
+
+ } else { // if it crashed so fast, it's probably pointless
+ // to try restarting it later, so also fall back to no
+ // sequencer mode
+ m_sequencerProcess = 0;
+ m_useSequencer = false;
+ stateChanged("sequencer_running", KXMLGUIClient::StateReverse);
+ slotEnableTransport(false);
+ }
+
+ }
+
+ // Sync current devices with the sequencer
+ //
+ if (m_doc)
+ m_doc->syncDevices();
+
+ if (m_doc && m_doc->getStudio().haveMidiDevices()) {
+ stateChanged("got_midi_devices");
+ } else {
+ stateChanged("got_midi_devices", KXMLGUIClient::StateReverse);
+ }
+
+ return res;
+}
+
+#ifdef HAVE_LIBJACK
+bool RosegardenGUIApp::launchJack()
+{
+ KConfig* config = kapp->config();
+ config->setGroup(SequencerOptionsConfigGroup);
+
+ bool startJack = config->readBoolEntry("jackstart", false);
+ if (!startJack)
+ return true; // we don't do anything
+
+ QString jackPath = config->readEntry("jackcommand", "");
+
+ emit startupStatusMessage(i18n("Clearing down jackd..."));
+
+ KProcess *proc = new KProcess; // TODO: do it in a less clumsy way
+ *proc << "/usr/bin/killall";
+ *proc << "-9";
+ *proc << "jackd";
+
+ proc->start(KProcess::Block, KProcess::All);
+
+ if (proc->exitStatus())
+ RG_DEBUG << "couldn't kill any jackd processes" << endl;
+ else
+ RG_DEBUG << "killed old jackd processes" << endl;
+
+ emit startupStatusMessage(i18n("Starting jackd..."));
+
+ if (jackPath != "") {
+
+ RG_DEBUG << "starting jack \"" << jackPath << "\"" << endl;
+
+ QStringList splitCommand;
+ splitCommand = QStringList::split(" ", jackPath);
+
+ RG_DEBUG << "RosegardenGUIApp::launchJack() : splitCommand length : "
+ << splitCommand.size() << endl;
+
+ // start jack process
+ m_jackProcess = new KProcess;
+
+ *m_jackProcess << splitCommand;
+
+ m_jackProcess->start();
+ }
+
+
+ return m_jackProcess != 0 ? m_jackProcess->isRunning() : true;
+}
+#endif
+
+void RosegardenGUIApp::slotDocumentDevicesResyncd()
+{
+ m_sequencerCheckedIn = true;
+ m_trackParameterBox->populateDeviceLists();
+}
+
+void RosegardenGUIApp::slotSequencerExited(KProcess*)
+{
+ RG_DEBUG << "RosegardenGUIApp::slotSequencerExited Sequencer exited\n";
+
+ KStartupLogo::hideIfStillThere();
+
+ if (m_sequencerCheckedIn) {
+
+ KMessageBox::error(0, i18n("The Rosegarden sequencer process has exited unexpectedly. Sound and recording will no longer be available for this session.\nPlease exit and restart Rosegarden to restore sound capability."));
+
+ } else {
+
+ KMessageBox::error(0, i18n("The Rosegarden sequencer could not be started, so sound and recording will be unavailable for this session.\nFor assistance with correct audio and MIDI configuration, go to http://rosegardenmusic.com."));
+ }
+
+ m_sequencerProcess = 0; // isSequencerRunning() will return false
+ // but isUsingSequencer() will keep returning true
+ // so pressing the play button may attempt to restart the sequencer
+}
+
+void RosegardenGUIApp::slotExportProject()
+{
+ KTmpStatusMsg msg(i18n("Exporting Rosegarden Project file..."), this);
+
+ QString fileName = getValidWriteFile
+ ("*.rgp|" + i18n("Rosegarden Project files\n") +
+ "\n*|" + i18n("All files"),
+ i18n("Export as..."));
+
+ if (fileName.isEmpty())
+ return ;
+
+ QString rgFile = fileName;
+ rgFile.replace(QRegExp(".rg.rgp$"), ".rg");
+ rgFile.replace(QRegExp(".rgp$"), ".rg");
+
+ CurrentProgressDialog::freeze();
+
+ QString errMsg;
+ if (!m_doc->saveDocument(rgFile, errMsg,
+ true)) { // pretend it's autosave
+ KMessageBox::sorry(this, i18n("Saving Rosegarden file to package failed: %1").arg(errMsg));
+ CurrentProgressDialog::thaw();
+ return ;
+ }
+
+ KProcess *proc = new KProcess;
+ *proc << "rosegarden-project-package";
+ *proc << "--pack";
+ *proc << rgFile;
+ *proc << fileName;
+
+ proc->start(KProcess::Block, KProcess::All);
+
+ if (!proc->normalExit() || proc->exitStatus()) {
+ KMessageBox::sorry(this, i18n("Failed to export to project file \"%1\"").arg(fileName));
+ CurrentProgressDialog::thaw();
+ delete proc;
+ return ;
+ }
+
+ delete proc;
+}
+
+void RosegardenGUIApp::slotExportMIDI()
+{
+ KTmpStatusMsg msg(i18n("Exporting MIDI file..."), this);
+
+ QString fileName = getValidWriteFile
+ ("*.mid *.midi|" + i18n("Standard MIDI files\n") +
+ "\n*|" + i18n("All files"),
+ i18n("Export as..."));
+
+ if (fileName.isEmpty())
+ return ;
+
+ exportMIDIFile(fileName);
+}
+
+void RosegardenGUIApp::exportMIDIFile(QString file)
+{
+ ProgressDialog progressDlg(i18n("Exporting MIDI file..."),
+ 100,
+ this);
+
+ std::string fname(QFile::encodeName(file));
+
+ MidiFile midiFile(fname,
+ &m_doc->getStudio());
+
+ connect(&midiFile, SIGNAL(setProgress(int)),
+ progressDlg.progressBar(), SLOT(setValue(int)));
+
+ connect(&midiFile, SIGNAL(incrementProgress(int)),
+ progressDlg.progressBar(), SLOT(advance(int)));
+
+ midiFile.convertToMidi(m_doc->getComposition());
+
+ if (!midiFile.write()) {
+ CurrentProgressDialog::freeze();
+ KMessageBox::sorry(this, i18n("Export failed. The file could not be opened for writing."));
+ }
+}
+
+void RosegardenGUIApp::slotExportCsound()
+{
+ KTmpStatusMsg msg(i18n("Exporting Csound score file..."), this);
+
+ QString fileName = getValidWriteFile(QString("*|") + i18n("All files"),
+ i18n("Export as..."));
+ if (fileName.isEmpty())
+ return ;
+
+ exportCsoundFile(fileName);
+}
+
+void RosegardenGUIApp::exportCsoundFile(QString file)
+{
+ ProgressDialog progressDlg(i18n("Exporting Csound score file..."),
+ 100,
+ this);
+
+ CsoundExporter e(this, &m_doc->getComposition(), std::string(QFile::encodeName(file)));
+
+ connect(&e, SIGNAL(setProgress(int)),
+ progressDlg.progressBar(), SLOT(setValue(int)));
+
+ connect(&e, SIGNAL(incrementProgress(int)),
+ progressDlg.progressBar(), SLOT(advance(int)));
+
+ if (!e.write()) {
+ CurrentProgressDialog::freeze();
+ KMessageBox::sorry(this, i18n("Export failed. The file could not be opened for writing."));
+ }
+}
+
+void RosegardenGUIApp::slotExportMup()
+{
+ KTmpStatusMsg msg(i18n("Exporting Mup file..."), this);
+
+ QString fileName = getValidWriteFile
+ ("*.mup|" + i18n("Mup files\n") + "\n*|" + i18n("All files"),
+ i18n("Export as..."));
+ if (fileName.isEmpty())
+ return ;
+
+ exportMupFile(fileName);
+}
+
+void RosegardenGUIApp::exportMupFile(QString file)
+{
+ ProgressDialog progressDlg(i18n("Exporting Mup file..."),
+ 100,
+ this);
+
+ MupExporter e(this, &m_doc->getComposition(), std::string(QFile::encodeName(file)));
+
+ connect(&e, SIGNAL(setProgress(int)),
+ progressDlg.progressBar(), SLOT(setValue(int)));
+
+ connect(&e, SIGNAL(incrementProgress(int)),
+ progressDlg.progressBar(), SLOT(advance(int)));
+
+ if (!e.write()) {
+ CurrentProgressDialog::freeze();
+ KMessageBox::sorry(this, i18n("Export failed. The file could not be opened for writing."));
+ }
+}
+
+void RosegardenGUIApp::slotExportLilyPond()
+{
+ KTmpStatusMsg msg(i18n("Exporting LilyPond file..."), this);
+
+ QString fileName = getValidWriteFile
+ (QString("*.ly|") + i18n("LilyPond files") +
+ "\n*|" + i18n("All files"),
+ i18n("Export as..."));
+
+ if (fileName.isEmpty())
+ return ;
+
+ exportLilyPondFile(fileName);
+}
+
+std::map<KProcess *, KTempFile *> RosegardenGUIApp::m_lilyTempFileMap;
+
+
+void RosegardenGUIApp::slotPrintLilyPond()
+{
+ KTmpStatusMsg msg(i18n("Printing LilyPond file..."), this);
+ KTempFile *file = new KTempFile(QString::null, ".ly");
+ file->setAutoDelete(true);
+ if (!file->name()) {
+ CurrentProgressDialog::freeze();
+ KMessageBox::sorry(this, i18n("Failed to open a temporary file for LilyPond export."));
+ delete file;
+ }
+ if (!exportLilyPondFile(file->name(), true)) {
+ return ;
+ }
+ KProcess *proc = new KProcess;
+ *proc << "rosegarden-lilypondview";
+ *proc << "--graphical";
+ *proc << "--print";
+ *proc << file->name();
+ connect(proc, SIGNAL(processExited(KProcess *)),
+ this, SLOT(slotLilyPondViewProcessExited(KProcess *)));
+ m_lilyTempFileMap[proc] = file;
+ proc->start(KProcess::NotifyOnExit);
+}
+
+void RosegardenGUIApp::slotPreviewLilyPond()
+{
+ KTmpStatusMsg msg(i18n("Previewing LilyPond file..."), this);
+ KTempFile *file = new KTempFile(QString::null, ".ly");
+ file->setAutoDelete(true);
+ if (!file->name()) {
+ CurrentProgressDialog::freeze();
+ KMessageBox::sorry(this, i18n("Failed to open a temporary file for LilyPond export."));
+ delete file;
+ }
+ if (!exportLilyPondFile(file->name(), true)) {
+ return ;
+ }
+ KProcess *proc = new KProcess;
+ *proc << "rosegarden-lilypondview";
+ *proc << "--graphical";
+ *proc << "--pdf";
+ *proc << file->name();
+ connect(proc, SIGNAL(processExited(KProcess *)),
+ this, SLOT(slotLilyPondViewProcessExited(KProcess *)));
+ m_lilyTempFileMap[proc] = file;
+ proc->start(KProcess::NotifyOnExit);
+}
+
+void RosegardenGUIApp::slotLilyPondViewProcessExited(KProcess *p)
+{
+ delete m_lilyTempFileMap[p];
+ m_lilyTempFileMap.erase(p);
+ delete p;
+}
+
+bool RosegardenGUIApp::exportLilyPondFile(QString file, bool forPreview)
+{
+ QString caption = "", heading = "";
+ if (forPreview) {
+ caption = i18n("LilyPond Preview Options");
+ heading = i18n("LilyPond preview options");
+ }
+
+ LilyPondOptionsDialog dialog(this, m_doc, caption, heading);
+ if (dialog.exec() != QDialog::Accepted) {
+ return false;
+ }
+
+ ProgressDialog progressDlg(i18n("Exporting LilyPond file..."),
+ 100,
+ this);
+
+ LilyPondExporter e(this, m_doc, std::string(QFile::encodeName(file)));
+
+ connect(&e, SIGNAL(setProgress(int)),
+ progressDlg.progressBar(), SLOT(setValue(int)));
+
+ connect(&e, SIGNAL(incrementProgress(int)),
+ progressDlg.progressBar(), SLOT(advance(int)));
+
+ if (!e.write()) {
+ CurrentProgressDialog::freeze();
+ KMessageBox::sorry(this, i18n("Export failed. The file could not be opened for writing."));
+ return false;
+ }
+
+ return true;
+}
+
+void RosegardenGUIApp::slotExportMusicXml()
+{
+ KTmpStatusMsg msg(i18n("Exporting MusicXML file..."), this);
+
+ QString fileName = getValidWriteFile
+ (QString("*.xml|") + i18n("XML files") +
+ "\n*|" + i18n("All files"), i18n("Export as..."));
+
+ if (fileName.isEmpty())
+ return ;
+
+ exportMusicXmlFile(fileName);
+}
+
+void RosegardenGUIApp::exportMusicXmlFile(QString file)
+{
+ ProgressDialog progressDlg(i18n("Exporting MusicXML file..."),
+ 100,
+ this);
+
+ MusicXmlExporter e(this, m_doc, std::string(QFile::encodeName(file)));
+
+ connect(&e, SIGNAL(setProgress(int)),
+ progressDlg.progressBar(), SLOT(setValue(int)));
+
+ connect(&e, SIGNAL(incrementProgress(int)),
+ progressDlg.progressBar(), SLOT(advance(int)));
+
+ if (!e.write()) {
+ CurrentProgressDialog::freeze();
+ KMessageBox::sorry(this, i18n("Export failed. The file could not be opened for writing."));
+ }
+}
+
+void
+RosegardenGUIApp::slotCloseTransport()
+{
+ m_viewTransport->setChecked(false);
+ slotToggleTransport(); // hides the transport
+}
+
+void
+RosegardenGUIApp::slotDeleteTransport()
+{
+ delete m_transport;
+ m_transport = 0;
+}
+
+void
+RosegardenGUIApp::slotActivateTool(QString toolName)
+{
+ if (toolName == SegmentSelector::ToolName) {
+ actionCollection()->action("select")->activate();
+ }
+}
+
+void
+RosegardenGUIApp::slotToggleMetronome()
+{
+ Composition &comp = m_doc->getComposition();
+
+ if (m_seqManager->getTransportStatus() == STARTING_TO_RECORD ||
+ m_seqManager->getTransportStatus() == RECORDING ||
+ m_seqManager->getTransportStatus() == RECORDING_ARMED) {
+ if (comp.useRecordMetronome())
+ comp.setRecordMetronome(false);
+ else
+ comp.setRecordMetronome(true);
+
+ getTransport()->MetronomeButton()->setOn(comp.useRecordMetronome());
+ } else {
+ if (comp.usePlayMetronome())
+ comp.setPlayMetronome(false);
+ else
+ comp.setPlayMetronome(true);
+
+ getTransport()->MetronomeButton()->setOn(comp.usePlayMetronome());
+ }
+}
+
+void
+RosegardenGUIApp::slotRewindToBeginning()
+{
+ // ignore requests if recording
+ //
+ if (m_seqManager->getTransportStatus() == RECORDING)
+ return ;
+
+ m_seqManager->rewindToBeginning();
+}
+
+void
+RosegardenGUIApp::slotFastForwardToEnd()
+{
+ // ignore requests if recording
+ //
+ if (m_seqManager->getTransportStatus() == RECORDING)
+ return ;
+
+ m_seqManager->fastForwardToEnd();
+}
+
+void
+RosegardenGUIApp::slotSetPlayPosition(timeT time)
+{
+ RG_DEBUG << "RosegardenGUIApp::slotSetPlayPosition(" << time << ")" << endl;
+ if (m_seqManager->getTransportStatus() == RECORDING)
+ return ;
+
+ m_doc->slotSetPointerPosition(time);
+
+ if (m_seqManager->getTransportStatus() == PLAYING)
+ return ;
+
+ slotPlay();
+}
+
+void RosegardenGUIApp::notifySequencerStatus(int status)
+{
+ stateChanged("not_playing",
+ (status == PLAYING ||
+ status == RECORDING) ?
+ KXMLGUIClient::StateReverse : KXMLGUIClient::StateNoReverse);
+
+ if (m_seqManager)
+ m_seqManager->setTransportStatus((TransportStatus) status);
+}
+
+void RosegardenGUIApp::processAsynchronousMidi(const MappedComposition &mC)
+{
+ if (!m_seqManager) {
+ return ; // probably getting this from a not-yet-killed runaway sequencer
+ }
+
+ m_seqManager->processAsynchronousMidi(mC, 0);
+ SequencerMapper *mapper = m_seqManager->getSequencerMapper();
+ if (mapper)
+ m_view->updateMeters(mapper);
+}
+
+void
+RosegardenGUIApp::slotRecord()
+{
+ if (!isUsingSequencer())
+ return ;
+
+ if (!isSequencerRunning()) {
+
+ // Try to launch sequencer and return if we fail
+ //
+ if (!launchSequencer(false))
+ return ;
+ }
+
+ if (m_seqManager->getTransportStatus() == RECORDING) {
+ slotStop();
+ return ;
+ } else if (m_seqManager->getTransportStatus() == PLAYING) {
+ slotToggleRecord();
+ return ;
+ }
+
+ // Attempt to start recording
+ //
+ try {
+ m_seqManager->record(false);
+ } catch (QString s) {
+ // We should already be stopped by this point so just unset
+ // the buttons after clicking the dialog.
+ //
+ KMessageBox::error(this, s);
+
+ getTransport()->MetronomeButton()->setOn(false);
+ getTransport()->RecordButton()->setOn(false);
+ getTransport()->PlayButton()->setOn(false);
+ return ;
+ } catch (AudioFileManager::BadAudioPathException e) {
+ if (KMessageBox::warningContinueCancel
+ (this,
+ i18n("The audio file path does not exist or is not writable.\nPlease set the audio file path to a valid directory in Document Properties before recording audio.\nWould you like to set it now?"),
+ i18n("Warning"),
+ i18n("Set audio file path")) == KMessageBox::Continue) {
+ slotOpenAudioPathSettings();
+ }
+ getTransport()->MetronomeButton()->setOn(false);
+ getTransport()->RecordButton()->setOn(false);
+ getTransport()->PlayButton()->setOn(false);
+ return ;
+ } catch (Exception e) {
+ KMessageBox::error(this, strtoqstr(e.getMessage()));
+
+ getTransport()->MetronomeButton()->setOn(false);
+ getTransport()->RecordButton()->setOn(false);
+ getTransport()->PlayButton()->setOn(false);
+ return ;
+ }
+
+ // plugin the keyboard accelerators for focus on this dialog
+ plugAccelerators(m_seqManager->getCountdownDialog(),
+ m_seqManager->getCountdownDialog()->getAccelerators());
+
+ connect(m_seqManager->getCountdownDialog(), SIGNAL(stopped()),
+ this, SLOT(slotStop()));
+
+ // Start the playback timer - this fetches the current sequencer position &c
+ //
+ m_stopTimer->stop();
+ m_playTimer->start(23); // avoid multiples of 10 just so as
+ // to avoid always having the same digit
+ // in one place on the transport. How
+ // shallow.)
+}
+
+void
+RosegardenGUIApp::slotToggleRecord()
+{
+ if (!isUsingSequencer() ||
+ (!isSequencerRunning() && !launchSequencer(false)))
+ return ;
+
+ try {
+ m_seqManager->record(true);
+ } catch (QString s) {
+ KMessageBox::error(this, s);
+ } catch (AudioFileManager::BadAudioPathException e) {
+ if (KMessageBox::warningContinueCancel
+ (this,
+ i18n("The audio file path does not exist or is not writable.\nPlease set the audio file path to a valid directory in Document Properties before you start to record audio.\nWould you like to set it now?"),
+ i18n("Error"),
+ i18n("Set audio file path")) == KMessageBox::Continue) {
+ slotOpenAudioPathSettings();
+ }
+ } catch (Exception e) {
+ KMessageBox::error(this, strtoqstr(e.getMessage()));
+ }
+
+}
+
+void
+RosegardenGUIApp::slotSetLoop(timeT lhs, timeT rhs)
+{
+ try {
+ m_doc->slotDocumentModified();
+
+ m_seqManager->setLoop(lhs, rhs);
+
+ // toggle the loop button
+ if (lhs != rhs) {
+ getTransport()->LoopButton()->setOn(true);
+ stateChanged("have_range", KXMLGUIClient::StateNoReverse);
+ } else {
+ getTransport()->LoopButton()->setOn(false);
+ stateChanged("have_range", KXMLGUIClient::StateReverse);
+ }
+ } catch (QString s) {
+ KMessageBox::error(this, s);
+ }
+}
+
+void RosegardenGUIApp::alive()
+{
+ if (m_doc)
+ m_doc->syncDevices();
+
+ if (m_doc && m_doc->getStudio().haveMidiDevices()) {
+ stateChanged("got_midi_devices");
+ } else {
+ stateChanged("got_midi_devices", KXMLGUIClient::StateReverse);
+ }
+}
+
+void RosegardenGUIApp::slotPlay()
+{
+ if (!isUsingSequencer())
+ return ;
+
+ if (!isSequencerRunning()) {
+
+ // Try to launch sequencer and return if it fails
+ //
+ if (!launchSequencer(false))
+ return ;
+ }
+
+ if (!m_seqManager)
+ return ;
+
+ // If we're armed and ready to record then do this instead (calling
+ // slotRecord ensures we don't toggle the recording state in
+ // SequenceManager)
+ //
+ if (m_seqManager->getTransportStatus() == RECORDING_ARMED) {
+ slotRecord();
+ return ;
+ }
+
+ // Send the controllers at start of playback if required
+ //
+ KConfig *config = kapp->config();
+ config->setGroup(SequencerOptionsConfigGroup);
+ bool sendControllers = config->readBoolEntry("alwayssendcontrollers", false);
+
+ if (sendControllers)
+ m_doc->initialiseControllers();
+
+ bool pausedPlayback = false;
+
+ try {
+ pausedPlayback = m_seqManager->play(); // this will stop playback (pause) if it's already running
+ // Check the new state of the transport and start or stop timer
+ // accordingly
+ //
+ if (!pausedPlayback) {
+
+ // Start the playback timer - this fetches the current sequencer position &c
+ //
+ m_stopTimer->stop();
+ m_playTimer->start(23);
+ } else {
+ m_playTimer->stop();
+ m_stopTimer->start(100);
+ }
+ } catch (QString s) {
+ KMessageBox::error(this, s);
+ m_playTimer->stop();
+ m_stopTimer->start(100);
+ } catch (Exception e) {
+ KMessageBox::error(this, e.getMessage());
+ m_playTimer->stop();
+ m_stopTimer->start(100);
+ }
+
+}
+
+void RosegardenGUIApp::slotJumpToTime(int sec, int usec)
+{
+ Composition *comp = &m_doc->getComposition();
+ timeT t = comp->getElapsedTimeForRealTime
+ (RealTime(sec, usec * 1000));
+ m_doc->slotSetPointerPosition(t);
+}
+
+void RosegardenGUIApp::slotStartAtTime(int sec, int usec)
+{
+ slotJumpToTime(sec, usec);
+ slotPlay();
+}
+
+void RosegardenGUIApp::slotStop()
+{
+ if (m_seqManager &&
+ m_seqManager->getCountdownDialog()) {
+ disconnect(m_seqManager->getCountdownDialog(), SIGNAL(stopped()),
+ this, SLOT(slotStop()));
+ disconnect(m_seqManager->getCountdownDialog(), SIGNAL(completed()),
+ this, SLOT(slotStop()));
+ }
+
+ try {
+ if (m_seqManager)
+ m_seqManager->stopping();
+ } catch (Exception e) {
+ KMessageBox::error(this, strtoqstr(e.getMessage()));
+ }
+
+ // stop the playback timer
+ m_playTimer->stop();
+ m_stopTimer->start(100);
+}
+
+void RosegardenGUIApp::slotRewind()
+{
+ // ignore requests if recording
+ //
+ if (m_seqManager->getTransportStatus() == RECORDING)
+ return ;
+ if (m_seqManager)
+ m_seqManager->rewind();
+}
+
+void RosegardenGUIApp::slotFastforward()
+{
+ // ignore requests if recording
+ //
+ if (m_seqManager->getTransportStatus() == RECORDING)
+ return ;
+
+ if (m_seqManager)
+ m_seqManager->fastforward();
+}
+
+void
+RosegardenGUIApp::slotSetLoop()
+{
+ // restore loop
+ m_doc->setLoop(m_storedLoopStart, m_storedLoopEnd);
+}
+
+void
+RosegardenGUIApp::slotUnsetLoop()
+{
+ Composition &comp = m_doc->getComposition();
+
+ // store the loop
+ m_storedLoopStart = comp.getLoopStart();
+ m_storedLoopEnd = comp.getLoopEnd();
+
+ // clear the loop at the composition and propagate to the rest
+ // of the display items
+ m_doc->setLoop(0, 0);
+}
+
+void
+RosegardenGUIApp::slotSetLoopStart()
+{
+ // Check so that start time is before endtime, othervise move upp the
+ // endtime to that same pos.
+ if ( m_doc->getComposition().getPosition() < m_doc->getComposition().getLoopEnd() ) {
+ m_doc->setLoop(m_doc->getComposition().getPosition(), m_doc->getComposition().getLoopEnd());
+ } else {
+ m_doc->setLoop(m_doc->getComposition().getPosition(), m_doc->getComposition().getPosition());
+ }
+}
+
+void
+RosegardenGUIApp::slotSetLoopStop()
+{
+ // Check so that end time is after start time, othervise move upp the
+ // start time to that same pos.
+ if ( m_doc->getComposition().getLoopStart() < m_doc->getComposition().getPosition() ) {
+ m_doc->setLoop(m_doc->getComposition().getLoopStart(), m_doc->getComposition().getPosition());
+ } else {
+ m_doc->setLoop(m_doc->getComposition().getPosition(), m_doc->getComposition().getPosition());
+ }
+}
+
+void RosegardenGUIApp::slotToggleSolo(bool value)
+{
+ RG_DEBUG << "RosegardenGUIApp::slotToggleSolo value = " << value << endl;
+
+ m_doc->getComposition().setSolo(value);
+ getTransport()->SoloButton()->setOn(value);
+
+ m_doc->slotDocumentModified();
+
+ emit compositionStateUpdate();
+}
+
+void RosegardenGUIApp::slotTrackUp()
+{
+ Composition &comp = m_doc->getComposition();
+
+ TrackId tid = comp.getSelectedTrack();
+ TrackId pos = comp.getTrackById(tid)->getPosition();
+
+ // If at top already
+ if (pos == 0)
+ return ;
+
+ Track *track = comp.getTrackByPosition(pos - 1);
+
+ // If the track exists
+ if (track) {
+ comp.setSelectedTrack(track->getId());
+ m_view->slotSelectTrackSegments(comp.getSelectedTrack());
+ }
+
+}
+
+void RosegardenGUIApp::slotTrackDown()
+{
+ Composition &comp = m_doc->getComposition();
+
+ TrackId tid = comp.getSelectedTrack();
+ TrackId pos = comp.getTrackById(tid)->getPosition();
+
+ Track *track = comp.getTrackByPosition(pos + 1);
+
+ // If the track exists
+ if (track) {
+ comp.setSelectedTrack(track->getId());
+ m_view->slotSelectTrackSegments(comp.getSelectedTrack());
+ }
+
+}
+
+void RosegardenGUIApp::slotMuteAllTracks()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotMuteAllTracks" << endl;
+
+ Composition &comp = m_doc->getComposition();
+
+ Composition::trackcontainer tracks = comp.getTracks();
+ Composition::trackiterator tit;
+ for (tit = tracks.begin(); tit != tracks.end(); ++tit)
+ m_view->slotSetMute((*tit).second->getInstrument(), true);
+}
+
+void RosegardenGUIApp::slotUnmuteAllTracks()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotUnmuteAllTracks" << endl;
+
+ Composition &comp = m_doc->getComposition();
+
+ Composition::trackcontainer tracks = comp.getTracks();
+ Composition::trackiterator tit;
+ for (tit = tracks.begin(); tit != tracks.end(); ++tit)
+ m_view->slotSetMute((*tit).second->getInstrument(), false);
+}
+
+void RosegardenGUIApp::slotToggleMutedCurrentTrack()
+{
+ Composition &comp = m_doc->getComposition();
+ TrackId tid = comp.getSelectedTrack();
+ Track *track = comp.getTrackById(tid);
+ // If the track exists
+ if (track) {
+ bool isMuted = track->isMuted();
+ m_view->slotSetMuteButton(tid, !isMuted);
+ }
+}
+
+void RosegardenGUIApp::slotToggleRecordCurrentTrack()
+{
+ Composition &comp = m_doc->getComposition();
+ TrackId tid = comp.getSelectedTrack();
+ int pos = comp.getTrackPositionById(tid);
+ m_view->getTrackEditor()->getTrackButtons()->slotToggleRecordTrack(pos);
+}
+
+
+void RosegardenGUIApp::slotConfigure()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotConfigure\n";
+
+ ConfigureDialog *configDlg =
+ new ConfigureDialog(m_doc, kapp->config(), this);
+
+ connect(configDlg, SIGNAL(updateAutoSaveInterval(unsigned int)),
+ this, SLOT(slotUpdateAutoSaveInterval(unsigned int)));
+ connect(configDlg, SIGNAL(updateSidebarStyle(unsigned int)),
+ this, SLOT(slotUpdateSidebarStyle(unsigned int)));
+
+ configDlg->show();
+}
+
+void RosegardenGUIApp::slotEditDocumentProperties()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotEditDocumentProperties\n";
+
+ DocumentConfigureDialog *configDlg =
+ new DocumentConfigureDialog(m_doc, this);
+
+ configDlg->show();
+}
+
+void RosegardenGUIApp::slotOpenAudioPathSettings()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotOpenAudioPathSettings\n";
+
+ DocumentConfigureDialog *configDlg =
+ new DocumentConfigureDialog(m_doc, this);
+
+ configDlg->showAudioPage();
+ configDlg->show();
+}
+
+void RosegardenGUIApp::slotEditKeys()
+{
+ KKeyDialog::configure(actionCollection());
+}
+
+void RosegardenGUIApp::slotEditToolbars()
+{
+ KEditToolbar dlg(actionCollection(), "rosegardenui.rc");
+
+ connect(&dlg, SIGNAL(newToolbarConfig()),
+ SLOT(slotUpdateToolbars()));
+
+ dlg.exec();
+}
+
+void RosegardenGUIApp::slotUpdateToolbars()
+{
+ createGUI("rosegardenui.rc");
+ m_viewToolBar->setChecked(!toolBar()->isHidden());
+}
+
+void RosegardenGUIApp::slotEditTempo()
+{
+ slotEditTempo(this);
+}
+
+void RosegardenGUIApp::slotEditTempo(timeT atTime)
+{
+ slotEditTempo(this, atTime);
+}
+
+void RosegardenGUIApp::slotEditTempo(QWidget *parent)
+{
+ slotEditTempo(parent, m_doc->getComposition().getPosition());
+}
+
+void RosegardenGUIApp::slotEditTempo(QWidget *parent, timeT atTime)
+{
+ RG_DEBUG << "RosegardenGUIApp::slotEditTempo\n";
+
+ TempoDialog tempoDialog(parent, m_doc);
+
+ connect(&tempoDialog,
+ SIGNAL(changeTempo(timeT,
+ tempoT,
+ tempoT,
+ TempoDialog::TempoDialogAction)),
+ SLOT(slotChangeTempo(timeT,
+ tempoT,
+ tempoT,
+ TempoDialog::TempoDialogAction)));
+
+ tempoDialog.setTempoPosition(atTime);
+ tempoDialog.exec();
+}
+
+void RosegardenGUIApp::slotEditTimeSignature()
+{
+ slotEditTimeSignature(this);
+}
+
+void RosegardenGUIApp::slotEditTimeSignature(timeT atTime)
+{
+ slotEditTimeSignature(this, atTime);
+}
+
+void RosegardenGUIApp::slotEditTimeSignature(QWidget *parent)
+{
+ slotEditTimeSignature(parent, m_doc->getComposition().getPosition());
+}
+
+void RosegardenGUIApp::slotEditTimeSignature(QWidget *parent,
+ timeT time)
+{
+ Composition &composition(m_doc->getComposition());
+
+ TimeSignature sig = composition.getTimeSignatureAt(time);
+
+ TimeSignatureDialog dialog(parent, &composition, time, sig);
+
+ if (dialog.exec() == QDialog::Accepted) {
+
+ time = dialog.getTime();
+
+ if (dialog.shouldNormalizeRests()) {
+ m_doc->getCommandHistory()->addCommand
+ (new AddTimeSignatureAndNormalizeCommand
+ (&composition, time, dialog.getTimeSignature()));
+ } else {
+ m_doc->getCommandHistory()->addCommand
+ (new AddTimeSignatureCommand
+ (&composition, time, dialog.getTimeSignature()));
+ }
+ }
+}
+
+void RosegardenGUIApp::slotEditTransportTime()
+{
+ slotEditTransportTime(this);
+}
+
+void RosegardenGUIApp::slotEditTransportTime(QWidget *parent)
+{
+ TimeDialog dialog(parent, i18n("Move playback pointer to time"),
+ &m_doc->getComposition(),
+ m_doc->getComposition().getPosition(),
+ true);
+ if (dialog.exec() == QDialog::Accepted) {
+ m_doc->slotSetPointerPosition(dialog.getTime());
+ }
+}
+
+void RosegardenGUIApp::slotChangeZoom(int)
+{
+ double duration44 = TimeSignature(4, 4).getBarDuration();
+ double value = double(m_zoomSlider->getCurrentSize());
+ m_zoomLabel->setText(i18n("%1%").arg(duration44 / value));
+
+ RG_DEBUG << "RosegardenGUIApp::slotChangeZoom : zoom size = "
+ << m_zoomSlider->getCurrentSize() << endl;
+
+ // initZoomToolbar sets the zoom value. With some old versions of
+ // Qt3.0, this can cause slotChangeZoom() to be called while the
+ // view hasn't been initialized yet, so we need to check it's not
+ // null
+ //
+ if (m_view)
+ m_view->setZoomSize(m_zoomSlider->getCurrentSize());
+
+ long newZoom = int(m_zoomSlider->getCurrentSize() * 1000.0);
+
+ if (m_doc->getConfiguration().get<Int>
+ (DocumentConfiguration::ZoomLevel) != newZoom) {
+
+ m_doc->getConfiguration().set<Int>
+ (DocumentConfiguration::ZoomLevel, newZoom);
+
+ m_doc->slotDocumentModified();
+ }
+}
+
+void
+RosegardenGUIApp::slotZoomIn()
+{
+ m_zoomSlider->increment();
+}
+
+void
+RosegardenGUIApp::slotZoomOut()
+{
+ m_zoomSlider->decrement();
+}
+
+void
+RosegardenGUIApp::slotChangeTempo(timeT time,
+ tempoT value,
+ tempoT target,
+ TempoDialog::TempoDialogAction action)
+{
+ //!!! handle target
+
+ Composition &comp = m_doc->getComposition();
+
+ // We define a macro command here and build up the command
+ // label as we add commands on.
+ //
+ if (action == TempoDialog::AddTempo) {
+ m_doc->getCommandHistory()->addCommand
+ (new AddTempoChangeCommand(&comp, time, value, target));
+ } else if (action == TempoDialog::ReplaceTempo) {
+ int index = comp.getTempoChangeNumberAt(time);
+
+ // if there's no previous tempo change then just set globally
+ //
+ if (index == -1) {
+ m_doc->getCommandHistory()->addCommand
+ (new AddTempoChangeCommand(&comp, 0, value, target));
+ return ;
+ }
+
+ // get time of previous tempo change
+ timeT prevTime = comp.getTempoChange(index).first;
+
+ KMacroCommand *macro =
+ new KMacroCommand(i18n("Replace Tempo Change at %1").arg(time));
+
+ macro->addCommand(new RemoveTempoChangeCommand(&comp, index));
+ macro->addCommand(new AddTempoChangeCommand(&comp, prevTime, value,
+ target));
+
+ m_doc->getCommandHistory()->addCommand(macro);
+
+ } else if (action == TempoDialog::AddTempoAtBarStart) {
+ m_doc->getCommandHistory()->addCommand(new
+ AddTempoChangeCommand(&comp, comp.getBarStartForTime(time),
+ value, target));
+ } else if (action == TempoDialog::GlobalTempo ||
+ action == TempoDialog::GlobalTempoWithDefault) {
+ KMacroCommand *macro = new KMacroCommand(i18n("Set Global Tempo"));
+
+ // Remove all tempo changes in reverse order so as the index numbers
+ // don't becoming meaningless as the command gets unwound.
+ //
+ for (int i = 0; i < comp.getTempoChangeCount(); i++)
+ macro->addCommand(new RemoveTempoChangeCommand(&comp,
+ (comp.getTempoChangeCount() - 1 - i)));
+
+ // add tempo change at time zero
+ //
+ macro->addCommand(new AddTempoChangeCommand(&comp, 0, value, target));
+
+ // are we setting default too?
+ //
+ if (action == TempoDialog::GlobalTempoWithDefault) {
+ macro->setName(i18n("Set Global and Default Tempo"));
+ macro->addCommand(new ModifyDefaultTempoCommand(&comp, value));
+ }
+
+ m_doc->getCommandHistory()->addCommand(macro);
+
+ } else {
+ RG_DEBUG << "RosegardenGUIApp::slotChangeTempo() - "
+ << "unrecognised tempo command" << endl;
+ }
+}
+
+void
+RosegardenGUIApp::slotMoveTempo(timeT oldTime,
+ timeT newTime)
+{
+ Composition &comp = m_doc->getComposition();
+ int index = comp.getTempoChangeNumberAt(oldTime);
+
+ if (index < 0)
+ return ;
+
+ KMacroCommand *macro =
+ new KMacroCommand(i18n("Move Tempo Change"));
+
+ std::pair<timeT, tempoT> tc =
+ comp.getTempoChange(index);
+ std::pair<bool, tempoT> tr =
+ comp.getTempoRamping(index, false);
+
+ macro->addCommand(new RemoveTempoChangeCommand(&comp, index));
+ macro->addCommand(new AddTempoChangeCommand(&comp,
+ newTime,
+ tc.second,
+ tr.first ? tr.second : -1));
+
+ m_doc->getCommandHistory()->addCommand(macro);
+}
+
+void
+RosegardenGUIApp::slotDeleteTempo(timeT t)
+{
+ Composition &comp = m_doc->getComposition();
+ int index = comp.getTempoChangeNumberAt(t);
+
+ if (index < 0)
+ return ;
+
+ m_doc->getCommandHistory()->addCommand(new RemoveTempoChangeCommand
+ (&comp, index));
+}
+
+void
+RosegardenGUIApp::slotAddMarker(timeT time)
+{
+ AddMarkerCommand *command =
+ new AddMarkerCommand(&m_doc->getComposition(),
+ time,
+ i18n("new marker"),
+ i18n("no description"));
+
+ m_doc->getCommandHistory()->addCommand(command);
+}
+
+void
+RosegardenGUIApp::slotDeleteMarker(int id, timeT time, QString name, QString description)
+{
+ RemoveMarkerCommand *command =
+ new RemoveMarkerCommand(&m_doc->getComposition(),
+ id,
+ time,
+ qstrtostr(name),
+ qstrtostr(description));
+
+ m_doc->getCommandHistory()->addCommand(command);
+}
+
+void
+RosegardenGUIApp::slotDocumentModified(bool m)
+{
+ RG_DEBUG << "RosegardenGUIApp::slotDocumentModified(" << m << ") - doc path = "
+ << m_doc->getAbsFilePath() << endl;
+
+ if (!m_doc->getAbsFilePath().isEmpty()) {
+ slotStateChanged("saved_file_modified", m);
+ } else {
+ slotStateChanged("new_file_modified", m);
+ }
+
+}
+
+void
+RosegardenGUIApp::slotStateChanged(QString s,
+ bool noReverse)
+{
+ // RG_DEBUG << "RosegardenGUIApp::slotStateChanged " << s << "," << noReverse << endl;
+
+ stateChanged(s, noReverse ? KXMLGUIClient::StateNoReverse : KXMLGUIClient::StateReverse);
+}
+
+void
+RosegardenGUIApp::slotTestClipboard()
+{
+ if (m_clipboard->isEmpty()) {
+ stateChanged("have_clipboard", KXMLGUIClient::StateReverse);
+ stateChanged("have_clipboard_single_segment",
+ KXMLGUIClient::StateReverse);
+ } else {
+ stateChanged("have_clipboard", KXMLGUIClient::StateNoReverse);
+ stateChanged("have_clipboard_single_segment",
+ (m_clipboard->isSingleSegment() ?
+ KXMLGUIClient::StateNoReverse :
+ KXMLGUIClient::StateReverse));
+ }
+}
+
+void
+RosegardenGUIApp::plugAccelerators(QWidget *widget, QAccel *acc)
+{
+
+ acc->connectItem(acc->insertItem(Key_Enter),
+ this,
+ SLOT(slotPlay()));
+ // Alternative shortcut for Play
+ acc->connectItem(acc->insertItem(Key_Return + CTRL),
+ this,
+ SLOT(slotPlay()));
+
+ acc->connectItem(acc->insertItem(Key_Insert),
+ this,
+ SLOT(slotStop()));
+
+ acc->connectItem(acc->insertItem(Key_PageDown),
+ this,
+ SLOT(slotFastforward()));
+
+ acc->connectItem(acc->insertItem(Key_End),
+ this,
+ SLOT(slotRewind()));
+
+ acc->connectItem(acc->insertItem(Key_Space),
+ this,
+ SLOT(slotToggleRecord()));
+
+ TransportDialog *transport =
+ dynamic_cast<TransportDialog*>(widget);
+
+ if (transport) {
+ acc->connectItem(acc->insertItem(m_jumpToQuickMarkerAction->shortcut()),
+ this,
+ SLOT(slotJumpToQuickMarker()));
+
+ acc->connectItem(acc->insertItem(m_setQuickMarkerAction->shortcut()),
+ this,
+ SLOT(slotSetQuickMarker()));
+
+ connect(transport->PlayButton(),
+ SIGNAL(clicked()),
+ this,
+ SLOT(slotPlay()));
+
+ connect(transport->StopButton(),
+ SIGNAL(clicked()),
+ this,
+ SLOT(slotStop()));
+
+ connect(transport->FfwdButton(),
+ SIGNAL(clicked()),
+ SLOT(slotFastforward()));
+
+ connect(transport->RewindButton(),
+ SIGNAL(clicked()),
+ this,
+ SLOT(slotRewind()));
+
+ connect(transport->RecordButton(),
+ SIGNAL(clicked()),
+ this,
+ SLOT(slotRecord()));
+
+ connect(transport->RewindEndButton(),
+ SIGNAL(clicked()),
+ this,
+ SLOT(slotRewindToBeginning()));
+
+ connect(transport->FfwdEndButton(),
+ SIGNAL(clicked()),
+ this,
+ SLOT(slotFastForwardToEnd()));
+
+ connect(transport->MetronomeButton(),
+ SIGNAL(clicked()),
+ this,
+ SLOT(slotToggleMetronome()));
+
+ connect(transport->SoloButton(),
+ SIGNAL(toggled(bool)),
+ this,
+ SLOT(slotToggleSolo(bool)));
+
+ connect(transport->TimeDisplayButton(),
+ SIGNAL(clicked()),
+ this,
+ SLOT(slotRefreshTimeDisplay()));
+
+ connect(transport->ToEndButton(),
+ SIGNAL(clicked()),
+ SLOT(slotRefreshTimeDisplay()));
+ }
+}
+
+void
+RosegardenGUIApp::setCursor(const QCursor& cursor)
+{
+ KDockMainWindow::setCursor(cursor);
+
+ // play it safe, so we can use this class at anytime even very early in the app init
+ if ((getView() &&
+ getView()->getTrackEditor() &&
+ getView()->getTrackEditor()->getSegmentCanvas() &&
+ getView()->getTrackEditor()->getSegmentCanvas()->viewport())) {
+
+ getView()->getTrackEditor()->getSegmentCanvas()->viewport()->setCursor(cursor);
+ }
+
+ // view, main window...
+ //
+ getView()->setCursor(cursor);
+
+ // toolbars...
+ //
+ QPtrListIterator<KToolBar> tbIter = toolBarIterator();
+ KToolBar* tb = 0;
+ while ((tb = tbIter.current()) != 0) {
+ tb->setCursor(cursor);
+ ++tbIter;
+ }
+
+ m_dockLeft->setCursor(cursor);
+}
+
+QString
+RosegardenGUIApp::createNewAudioFile()
+{
+ AudioFile *aF = 0;
+ try {
+ aF = m_doc->getAudioFileManager().createRecordingAudioFile();
+ if (!aF) {
+ // createRecordingAudioFile doesn't actually write to the disk,
+ // and in principle it shouldn't fail
+ std::cerr << "ERROR: RosegardenGUIApp::createNewAudioFile: Failed to create recording audio file" << std::endl;
+ return "";
+ } else {
+ return aF->getFilename().c_str();
+ }
+ } catch (AudioFileManager::BadAudioPathException e) {
+ delete aF;
+ std::cerr << "ERROR: RosegardenGUIApp::createNewAudioFile: Failed to create recording audio file: " << e.getMessage() << std::endl;
+ return "";
+ }
+}
+
+QValueVector<QString>
+RosegardenGUIApp::createRecordAudioFiles(const QValueVector<InstrumentId> &recordInstruments)
+{
+ QValueVector<QString> qv;
+ for (unsigned int i = 0; i < recordInstruments.size(); ++i) {
+ AudioFile *aF = 0;
+ try {
+ aF = m_doc->getAudioFileManager().createRecordingAudioFile();
+ if (aF) {
+ // createRecordingAudioFile doesn't actually write to the disk,
+ // and in principle it shouldn't fail
+ qv.push_back(aF->getFilename().c_str());
+ m_doc->addRecordAudioSegment(recordInstruments[i],
+ aF->getId());
+ } else {
+ std::cerr << "ERROR: RosegardenGUIApp::createRecordAudioFiles: Failed to create recording audio file" << std::endl;
+ return qv;
+ }
+ } catch (AudioFileManager::BadAudioPathException e) {
+ delete aF;
+ std::cerr << "ERROR: RosegardenGUIApp::createRecordAudioFiles: Failed to create recording audio file: " << e.getMessage() << std::endl;
+ return qv;
+ }
+ }
+ return qv;
+}
+
+QString
+RosegardenGUIApp::getAudioFilePath()
+{
+ return QString(m_doc->getAudioFileManager().getAudioPath().c_str());
+}
+
+QValueVector<InstrumentId>
+RosegardenGUIApp::getArmedInstruments()
+{
+ std::set
+ <InstrumentId> iid;
+
+ const Composition::recordtrackcontainer &tr =
+ m_doc->getComposition().getRecordTracks();
+
+ for (Composition::recordtrackcontainer::const_iterator i =
+ tr.begin(); i != tr.end(); ++i) {
+ TrackId tid = (*i);
+ Track *track = m_doc->getComposition().getTrackById(tid);
+ if (track) {
+ iid.insert(track->getInstrument());
+ } else {
+ std::cerr << "Warning: RosegardenGUIApp::getArmedInstruments: Armed track " << tid << " not found in Composition" << std::endl;
+ }
+ }
+
+ QValueVector<InstrumentId> iv;
+ for (std::set
+ <InstrumentId>::iterator ii = iid.begin();
+ ii != iid.end(); ++ii) {
+ iv.push_back(*ii);
+ }
+ return iv;
+}
+
+void
+RosegardenGUIApp::showError(QString error)
+{
+ KStartupLogo::hideIfStillThere();
+ CurrentProgressDialog::freeze();
+
+ // This is principally used for return values from DSSI plugin
+ // configure() calls. It seems some plugins return a string
+ // telling you when everything's OK, as well as error strings, but
+ // dssi.h does make it reasonably clear that configure() should
+ // only return a string when there is actually a problem, so we're
+ // going to stick with a sorry dialog here rather than an
+ // information one
+
+ KMessageBox::sorry(0, error);
+
+ CurrentProgressDialog::thaw();
+}
+
+void
+RosegardenGUIApp::slotAudioManager()
+{
+ if (m_audioManagerDialog) {
+ m_audioManagerDialog->show();
+ m_audioManagerDialog->raise();
+ m_audioManagerDialog->setActiveWindow();
+ return ;
+ }
+
+ m_audioManagerDialog =
+ new AudioManagerDialog(this, m_doc);
+
+ connect(m_audioManagerDialog,
+ SIGNAL(playAudioFile(AudioFileId,
+ const RealTime &,
+ const RealTime&)),
+ SLOT(slotPlayAudioFile(AudioFileId,
+ const RealTime &,
+ const RealTime &)));
+
+ connect(m_audioManagerDialog,
+ SIGNAL(addAudioFile(AudioFileId)),
+ SLOT(slotAddAudioFile(AudioFileId)));
+
+ connect(m_audioManagerDialog,
+ SIGNAL(deleteAudioFile(AudioFileId)),
+ SLOT(slotDeleteAudioFile(AudioFileId)));
+
+ //
+ // Sync segment selection between audio man. dialog and main window
+ //
+
+ // from dialog to us...
+ connect(m_audioManagerDialog,
+ SIGNAL(segmentsSelected(const SegmentSelection&)),
+ m_view,
+ SLOT(slotPropagateSegmentSelection(const SegmentSelection&)));
+
+ // and from us to dialog
+ connect(this, SIGNAL(segmentsSelected(const SegmentSelection&)),
+ m_audioManagerDialog,
+ SLOT(slotSegmentSelection(const SegmentSelection&)));
+
+
+ connect(m_audioManagerDialog,
+ SIGNAL(deleteSegments(const SegmentSelection&)),
+ SLOT(slotDeleteSegments(const SegmentSelection&)));
+
+ connect(m_audioManagerDialog,
+ SIGNAL(insertAudioSegment(AudioFileId,
+ const RealTime&,
+ const RealTime&)),
+ m_view,
+ SLOT(slotAddAudioSegmentDefaultPosition(AudioFileId,
+ const RealTime&,
+ const RealTime&)));
+ connect(m_audioManagerDialog,
+ SIGNAL(cancelPlayingAudioFile(AudioFileId)),
+ SLOT(slotCancelAudioPlayingFile(AudioFileId)));
+
+ connect(m_audioManagerDialog,
+ SIGNAL(deleteAllAudioFiles()),
+ SLOT(slotDeleteAllAudioFiles()));
+
+ // Make sure we know when the audio man. dialog is closing
+ //
+ connect(m_audioManagerDialog,
+ SIGNAL(closing()),
+ SLOT(slotAudioManagerClosed()));
+
+ // And that it goes away when the current document is changing
+ //
+ connect(this, SIGNAL(documentAboutToChange()),
+ m_audioManagerDialog, SLOT(close()));
+
+ m_audioManagerDialog->setAudioSubsystemStatus(
+ m_seqManager->getSoundDriverStatus() & AUDIO_OK);
+
+ plugAccelerators(m_audioManagerDialog,
+ m_audioManagerDialog->getAccelerators());
+
+ m_audioManagerDialog->show();
+}
+
+void
+RosegardenGUIApp::slotPlayAudioFile(unsigned int id,
+ const RealTime &startTime,
+ const RealTime &duration)
+{
+ AudioFile *aF = m_doc->getAudioFileManager().getAudioFile(id);
+
+ if (aF == 0)
+ return ;
+
+ MappedEvent mE(m_doc->getStudio().
+ getAudioPreviewInstrument(),
+ id,
+ RealTime( -120, 0),
+ duration, // duration
+ startTime); // start index
+
+ StudioControl::sendMappedEvent(mE);
+
+}
+
+void
+RosegardenGUIApp::slotAddAudioFile(unsigned int id)
+{
+ AudioFile *aF = m_doc->getAudioFileManager().getAudioFile(id);
+
+ if (aF == 0)
+ return ;
+
+ QCString replyType;
+ QByteArray replyData;
+ QByteArray data;
+ QDataStream streamOut(data, IO_WriteOnly);
+
+ // We have to pass the filename as a QString
+ //
+ streamOut << QString(strtoqstr(aF->getFilename()));
+ streamOut << (int)aF->getId();
+
+ if (rgapp->sequencerCall("addAudioFile(QString, int)", replyType, replyData, data)) {
+ QDataStream streamIn(replyData, IO_ReadOnly);
+ int result;
+ streamIn >> result;
+ if (!result) {
+ KMessageBox::error(this, i18n("Sequencer failed to add audio file %1").arg(aF->getFilename().c_str()));
+ }
+ }
+}
+
+void
+RosegardenGUIApp::slotDeleteAudioFile(unsigned int id)
+{
+ if (m_doc->getAudioFileManager().removeFile(id) == false)
+ return ;
+
+ QCString replyType;
+ QByteArray replyData;
+ QByteArray data;
+ QDataStream streamOut(data, IO_WriteOnly);
+
+ // file id
+ //
+ streamOut << (int)id;
+
+ if (rgapp->sequencerCall("removeAudioFile(int)", replyType, replyData, data)) {
+ QDataStream streamIn(replyData, IO_ReadOnly);
+ int result;
+ streamIn >> result;
+ if (!result) {
+ KMessageBox::error(this, i18n("Sequencer failed to remove audio file id %1").arg(id));
+ }
+ }
+}
+
+void
+RosegardenGUIApp::slotDeleteSegments(const SegmentSelection &selection)
+{
+ m_view->slotPropagateSegmentSelection(selection);
+ slotDeleteSelectedSegments();
+}
+
+void
+RosegardenGUIApp::slotCancelAudioPlayingFile(AudioFileId id)
+{
+ AudioFile *aF = m_doc->getAudioFileManager().getAudioFile(id);
+
+ if (aF == 0)
+ return ;
+
+ MappedEvent mE(m_doc->getStudio().
+ getAudioPreviewInstrument(),
+ MappedEvent::AudioCancel,
+ id);
+
+ StudioControl::sendMappedEvent(mE);
+}
+
+void
+RosegardenGUIApp::slotDeleteAllAudioFiles()
+{
+ m_doc->getAudioFileManager().clear();
+
+ // Clear at the sequencer
+ //
+ QCString replyType;
+ QByteArray replyData;
+ QByteArray data;
+
+ rgapp->sequencerCall("clearAllAudioFiles()", replyType, replyData, data);
+}
+
+void
+RosegardenGUIApp::slotRepeatingSegments()
+{
+ m_view->getTrackEditor()->slotTurnRepeatingSegmentToRealCopies();
+}
+
+void
+RosegardenGUIApp::slotRelabelSegments()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ SegmentSelection selection(m_view->getSelection());
+ QString editLabel;
+
+ if (selection.size() == 0)
+ return ;
+ else if (selection.size() == 1)
+ editLabel = i18n("Modify Segment label");
+ else
+ editLabel = i18n("Modify Segments label");
+
+ KTmpStatusMsg msg(i18n("Relabelling selection..."), this);
+
+ // Generate label
+ QString label = strtoqstr((*selection.begin())->getLabel());
+
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+ if (strtoqstr((*i)->getLabel()) != label)
+ label = "";
+ }
+
+ bool ok = false;
+
+ QString newLabel = KInputDialog::getText(editLabel,
+ i18n("Enter new label"),
+ label,
+ &ok,
+ this);
+
+ if (ok) {
+ m_doc->getCommandHistory()->addCommand
+ (new SegmentLabelCommand(selection, newLabel));
+ m_view->getTrackEditor()->getSegmentCanvas()->slotUpdateSegmentsDrawBuffer();
+ }
+}
+
+void
+RosegardenGUIApp::slotTransposeSegments()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ IntervalDialog intervalDialog(this, true, true);
+ int ok = intervalDialog.exec();
+
+ int semitones = intervalDialog.getChromaticDistance();
+ int steps = intervalDialog.getDiatonicDistance();
+
+ if (!ok || (semitones == 0 && steps == 0)) return;
+
+ m_doc->getCommandHistory()->addCommand
+ (new SegmentTransposeCommand(m_view->getSelection(), intervalDialog.getChangeKey(), steps, semitones, intervalDialog.getTransposeSegmentBack()));
+}
+
+void
+RosegardenGUIApp::slotChangeCompositionLength()
+{
+ CompositionLengthDialog dialog(this, &m_doc->getComposition());
+
+ if (dialog.exec() == QDialog::Accepted) {
+ ChangeCompositionLengthCommand *command
+ = new ChangeCompositionLengthCommand(
+ &m_doc->getComposition(),
+ dialog.getStartMarker(),
+ dialog.getEndMarker());
+
+ m_view->getTrackEditor()->getSegmentCanvas()->clearSegmentRectsCache(true);
+ m_doc->getCommandHistory()->addCommand(command);
+ }
+}
+
+void
+RosegardenGUIApp::slotManageMIDIDevices()
+{
+ if (m_deviceManager) {
+ m_deviceManager->show();
+ m_deviceManager->raise();
+ m_deviceManager->setActiveWindow();
+ return ;
+ }
+
+ m_deviceManager = new DeviceManagerDialog(this, m_doc);
+
+ connect(m_deviceManager, SIGNAL(closing()),
+ this, SLOT(slotDeviceManagerClosed()));
+
+ connect(this, SIGNAL(documentAboutToChange()),
+ m_deviceManager, SLOT(close()));
+
+ // Cheating way of updating the track/instrument list
+ //
+ connect(m_deviceManager, SIGNAL(deviceNamesChanged()),
+ m_view, SLOT(slotSynchroniseWithComposition()));
+
+ connect(m_deviceManager, SIGNAL(editBanks(DeviceId)),
+ this, SLOT(slotEditBanks(DeviceId)));
+
+ connect(m_deviceManager, SIGNAL(editControllers(DeviceId)),
+ this, SLOT(slotEditControlParameters(DeviceId)));
+
+ if (m_midiMixer) {
+ connect(m_deviceManager, SIGNAL(deviceNamesChanged()),
+ m_midiMixer, SLOT(slotSynchronise()));
+
+ }
+
+
+ m_deviceManager->show();
+}
+
+void
+RosegardenGUIApp::slotManageSynths()
+{
+ if (m_synthManager) {
+ m_synthManager->show();
+ m_synthManager->raise();
+ m_synthManager->setActiveWindow();
+ return ;
+ }
+
+ m_synthManager = new SynthPluginManagerDialog(this, m_doc
+#ifdef HAVE_LIBLO
+ , m_pluginGUIManager
+#endif
+ );
+
+ connect(m_synthManager, SIGNAL(closing()),
+ this, SLOT(slotSynthPluginManagerClosed()));
+
+ connect(this, SIGNAL(documentAboutToChange()),
+ m_synthManager, SLOT(close()));
+
+ connect(m_synthManager,
+ SIGNAL(pluginSelected(InstrumentId, int, int)),
+ this,
+ SLOT(slotPluginSelected(InstrumentId, int, int)));
+
+ connect(m_synthManager,
+ SIGNAL(showPluginDialog(QWidget *, InstrumentId, int)),
+ this,
+ SLOT(slotShowPluginDialog(QWidget *, InstrumentId, int)));
+
+ connect(m_synthManager,
+ SIGNAL(showPluginGUI(InstrumentId, int)),
+ this,
+ SLOT(slotShowPluginGUI(InstrumentId, int)));
+
+ m_synthManager->show();
+}
+
+void
+RosegardenGUIApp::slotOpenAudioMixer()
+{
+ if (m_audioMixer) {
+ m_audioMixer->show();
+ m_audioMixer->raise();
+ m_audioMixer->setActiveWindow();
+ return ;
+ }
+
+ m_audioMixer = new AudioMixerWindow(this, m_doc);
+
+ connect(m_audioMixer, SIGNAL(windowActivated()),
+ m_view, SLOT(slotActiveMainWindowChanged()));
+
+ connect(m_view, SIGNAL(controllerDeviceEventReceived(MappedEvent *, const void *)),
+ m_audioMixer, SLOT(slotControllerDeviceEventReceived(MappedEvent *, const void *)));
+
+ connect(m_audioMixer, SIGNAL(closing()),
+ this, SLOT(slotAudioMixerClosed()));
+
+ connect(m_audioMixer, SIGNAL(selectPlugin(QWidget *, InstrumentId, int)),
+ this, SLOT(slotShowPluginDialog(QWidget *, InstrumentId, int)));
+
+ connect(this,
+ SIGNAL(pluginSelected(InstrumentId, int, int)),
+ m_audioMixer,
+ SLOT(slotPluginSelected(InstrumentId, int, int)));
+
+ connect(this,
+ SIGNAL(pluginBypassed(InstrumentId, int, bool)),
+ m_audioMixer,
+ SLOT(slotPluginBypassed(InstrumentId, int, bool)));
+
+ connect(this, SIGNAL(documentAboutToChange()),
+ m_audioMixer, SLOT(close()));
+
+ connect(m_view, SIGNAL(checkTrackAssignments()),
+ m_audioMixer, SLOT(slotTrackAssignmentsChanged()));
+
+ connect(m_audioMixer, SIGNAL(play()),
+ this, SLOT(slotPlay()));
+ connect(m_audioMixer, SIGNAL(stop()),
+ this, SLOT(slotStop()));
+ connect(m_audioMixer, SIGNAL(fastForwardPlayback()),
+ this, SLOT(slotFastforward()));
+ connect(m_audioMixer, SIGNAL(rewindPlayback()),
+ this, SLOT(slotRewind()));
+ connect(m_audioMixer, SIGNAL(fastForwardPlaybackToEnd()),
+ this, SLOT(slotFastForwardToEnd()));
+ connect(m_audioMixer, SIGNAL(rewindPlaybackToBeginning()),
+ this, SLOT(slotRewindToBeginning()));
+ connect(m_audioMixer, SIGNAL(record()),
+ this, SLOT(slotRecord()));
+ connect(m_audioMixer, SIGNAL(panic()),
+ this, SLOT(slotPanic()));
+
+ connect(m_audioMixer,
+ SIGNAL(instrumentParametersChanged(InstrumentId)),
+ this,
+ SIGNAL(instrumentParametersChanged(InstrumentId)));
+
+ connect(this,
+ SIGNAL(instrumentParametersChanged(InstrumentId)),
+ m_audioMixer,
+ SLOT(slotUpdateInstrument(InstrumentId)));
+
+ if (m_synthManager) {
+ connect(m_synthManager,
+ SIGNAL(pluginSelected(InstrumentId, int, int)),
+ m_audioMixer,
+ SLOT(slotPluginSelected(InstrumentId, int, int)));
+ }
+
+ plugAccelerators(m_audioMixer, m_audioMixer->getAccelerators());
+
+ m_audioMixer->show();
+}
+
+void
+RosegardenGUIApp::slotOpenMidiMixer()
+{
+ if (m_midiMixer) {
+ m_midiMixer->show();
+ m_midiMixer->raise();
+ m_midiMixer->setActiveWindow();
+ return ;
+ }
+
+ m_midiMixer = new MidiMixerWindow(this, m_doc);
+
+ connect(m_midiMixer, SIGNAL(windowActivated()),
+ m_view, SLOT(slotActiveMainWindowChanged()));
+
+ connect(m_view, SIGNAL(controllerDeviceEventReceived(MappedEvent *, const void *)),
+ m_midiMixer, SLOT(slotControllerDeviceEventReceived(MappedEvent *, const void *)));
+
+ connect(m_midiMixer, SIGNAL(closing()),
+ this, SLOT(slotMidiMixerClosed()));
+
+ connect(this, SIGNAL(documentAboutToChange()),
+ m_midiMixer, SLOT(close()));
+
+ connect(m_midiMixer, SIGNAL(play()),
+ this, SLOT(slotPlay()));
+ connect(m_midiMixer, SIGNAL(stop()),
+ this, SLOT(slotStop()));
+ connect(m_midiMixer, SIGNAL(fastForwardPlayback()),
+ this, SLOT(slotFastforward()));
+ connect(m_midiMixer, SIGNAL(rewindPlayback()),
+ this, SLOT(slotRewind()));
+ connect(m_midiMixer, SIGNAL(fastForwardPlaybackToEnd()),
+ this, SLOT(slotFastForwardToEnd()));
+ connect(m_midiMixer, SIGNAL(rewindPlaybackToBeginning()),
+ this, SLOT(slotRewindToBeginning()));
+ connect(m_midiMixer, SIGNAL(record()),
+ this, SLOT(slotRecord()));
+ connect(m_midiMixer, SIGNAL(panic()),
+ this, SLOT(slotPanic()));
+
+ connect(m_midiMixer,
+ SIGNAL(instrumentParametersChanged(InstrumentId)),
+ this,
+ SIGNAL(instrumentParametersChanged(InstrumentId)));
+
+ connect(this,
+ SIGNAL(instrumentParametersChanged(InstrumentId)),
+ m_midiMixer,
+ SLOT(slotUpdateInstrument(InstrumentId)));
+
+ plugAccelerators(m_midiMixer, m_midiMixer->getAccelerators());
+
+ m_midiMixer->show();
+}
+
+void
+RosegardenGUIApp::slotEditControlParameters(DeviceId device)
+{
+ for (std::set
+ <ControlEditorDialog *>::iterator i = m_controlEditors.begin();
+ i != m_controlEditors.end(); ++i) {
+ if ((*i)->getDevice() == device) {
+ (*i)->show();
+ (*i)->raise();
+ (*i)->setActiveWindow();
+ return ;
+ }
+ }
+
+ ControlEditorDialog *controlEditor = new ControlEditorDialog(this, m_doc,
+ device);
+ m_controlEditors.insert(controlEditor);
+
+ RG_DEBUG << "inserting control editor dialog, have " << m_controlEditors.size() << " now" << endl;
+
+ connect(controlEditor, SIGNAL(closing()),
+ SLOT(slotControlEditorClosed()));
+
+ connect(this, SIGNAL(documentAboutToChange()),
+ controlEditor, SLOT(close()));
+
+ connect(m_doc, SIGNAL(devicesResyncd()),
+ controlEditor, SLOT(slotUpdate()));
+
+ controlEditor->show();
+}
+
+void
+RosegardenGUIApp::slotEditBanks()
+{
+ slotEditBanks(Device::NO_DEVICE);
+}
+
+void
+RosegardenGUIApp::slotEditBanks(DeviceId device)
+{
+ if (m_bankEditor) {
+ if (device != Device::NO_DEVICE)
+ m_bankEditor->setCurrentDevice(device);
+ m_bankEditor->show();
+ m_bankEditor->raise();
+ m_bankEditor->setActiveWindow();
+ return ;
+ }
+
+ m_bankEditor = new BankEditorDialog(this, m_doc, device);
+
+ connect(m_bankEditor, SIGNAL(closing()),
+ this, SLOT(slotBankEditorClosed()));
+
+ connect(this, SIGNAL(documentAboutToChange()),
+ m_bankEditor, SLOT(slotFileClose()));
+
+ // Cheating way of updating the track/instrument list
+ //
+ connect(m_bankEditor, SIGNAL(deviceNamesChanged()),
+ m_view, SLOT(slotSynchroniseWithComposition()));
+
+ m_bankEditor->show();
+}
+
+void
+RosegardenGUIApp::slotManageTriggerSegments()
+{
+ if (m_triggerSegmentManager) {
+ m_triggerSegmentManager->show();
+ m_triggerSegmentManager->raise();
+ m_triggerSegmentManager->setActiveWindow();
+ return ;
+ }
+
+ m_triggerSegmentManager = new TriggerSegmentManager(this, m_doc);
+
+ connect(m_triggerSegmentManager, SIGNAL(closing()),
+ SLOT(slotTriggerManagerClosed()));
+
+ connect(m_triggerSegmentManager, SIGNAL(editTriggerSegment(int)),
+ m_view, SLOT(slotEditTriggerSegment(int)));
+
+ m_triggerSegmentManager->show();
+}
+
+void
+RosegardenGUIApp::slotTriggerManagerClosed()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotTriggerManagerClosed" << endl;
+
+ m_triggerSegmentManager = 0;
+}
+
+void
+RosegardenGUIApp::slotEditMarkers()
+{
+ if (m_markerEditor) {
+ m_markerEditor->show();
+ m_markerEditor->raise();
+ m_markerEditor->setActiveWindow();
+ return ;
+ }
+
+ m_markerEditor = new MarkerEditor(this, m_doc);
+
+ connect(m_markerEditor, SIGNAL(closing()),
+ SLOT(slotMarkerEditorClosed()));
+
+ connect(m_markerEditor, SIGNAL(jumpToMarker(timeT)),
+ m_doc, SLOT(slotSetPointerPosition(timeT)));
+
+ plugAccelerators(m_markerEditor, m_markerEditor->getAccelerators());
+
+ m_markerEditor->show();
+}
+
+void
+RosegardenGUIApp::slotMarkerEditorClosed()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotMarkerEditorClosed" << endl;
+
+ m_markerEditor = 0;
+}
+
+void
+RosegardenGUIApp::slotEditTempos(timeT t)
+{
+ if (m_tempoView) {
+ m_tempoView->show();
+ m_tempoView->raise();
+ m_tempoView->setActiveWindow();
+ return ;
+ }
+
+ m_tempoView = new TempoView(m_doc, getView(), t);
+
+ connect(m_tempoView, SIGNAL(closing()),
+ SLOT(slotTempoViewClosed()));
+
+ connect(m_tempoView, SIGNAL(windowActivated()),
+ getView(), SLOT(slotActiveMainWindowChanged()));
+
+ connect(m_tempoView,
+ SIGNAL(changeTempo(timeT,
+ tempoT,
+ tempoT,
+ TempoDialog::TempoDialogAction)),
+ this,
+ SLOT(slotChangeTempo(timeT,
+ tempoT,
+ tempoT,
+ TempoDialog::TempoDialogAction)));
+
+ connect(m_tempoView, SIGNAL(saveFile()), this, SLOT(slotFileSave()));
+
+ plugAccelerators(m_tempoView, m_tempoView->getAccelerators());
+
+ m_tempoView->show();
+}
+
+void
+RosegardenGUIApp::slotTempoViewClosed()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotTempoViewClosed" << endl;
+
+ m_tempoView = 0;
+}
+
+void
+RosegardenGUIApp::slotControlEditorClosed()
+{
+ const QObject *s = sender();
+
+ RG_DEBUG << "RosegardenGUIApp::slotControlEditorClosed" << endl;
+
+ for (std::set
+ <ControlEditorDialog *>::iterator i = m_controlEditors.begin();
+ i != m_controlEditors.end(); ++i) {
+ if (*i == s) {
+ m_controlEditors.erase(i);
+ RG_DEBUG << "removed control editor dialog, have " << m_controlEditors.size() << " left" << endl;
+ return ;
+ }
+ }
+
+ std::cerr << "WARNING: control editor " << s << " closed, but couldn't find it in our control editor list (we have " << m_controlEditors.size() << " editors)" << std::endl;
+}
+
+void
+RosegardenGUIApp::slotShowPluginDialog(QWidget *parent,
+ InstrumentId instrumentId,
+ int index)
+{
+ if (!parent)
+ parent = this;
+
+ int key = (index << 16) + instrumentId;
+
+ if (m_pluginDialogs[key]) {
+ m_pluginDialogs[key]->show();
+ m_pluginDialogs[key]->raise();
+ m_pluginDialogs[key]->setActiveWindow();
+ return ;
+ }
+
+ PluginContainer *container = 0;
+
+ container = m_doc->getStudio().getContainerById(instrumentId);
+ if (!container) {
+ RG_DEBUG << "RosegardenGUIApp::slotShowPluginDialog - "
+ << "no instrument or buss of id " << instrumentId << endl;
+ return ;
+ }
+
+ // only create a dialog if we've got a plugin instance
+ AudioPluginInstance *inst =
+ container->getPlugin(index);
+
+ if (!inst) {
+ RG_DEBUG << "RosegardenGUIApp::slotShowPluginDialog - "
+ << "no AudioPluginInstance found for index "
+ << index << endl;
+ return ;
+ }
+
+ // Create the plugin dialog
+ //
+ AudioPluginDialog *dialog =
+ new AudioPluginDialog(parent,
+ m_doc->getPluginManager(),
+#ifdef HAVE_LIBLO
+ m_pluginGUIManager,
+#endif
+ container,
+ index);
+
+ connect(dialog, SIGNAL(windowActivated()),
+ m_view, SLOT(slotActiveMainWindowChanged()));
+
+/* This feature isn't provided by the plugin dialog
+ connect(m_view, SIGNAL(controllerDeviceEventReceived(MappedEvent *, const void *)),
+ dialog, SLOT(slotControllerDeviceEventReceived(MappedEvent *, const void *)));
+*/
+
+ // Plug the new dialog into the standard keyboard accelerators so
+ // that we can use them still while the plugin has focus.
+ //
+ plugAccelerators(dialog, dialog->getAccelerators());
+
+ connect(dialog,
+ SIGNAL(pluginSelected(InstrumentId, int, int)),
+ this,
+ SLOT(slotPluginSelected(InstrumentId, int, int)));
+
+ connect(dialog,
+ SIGNAL(pluginPortChanged(InstrumentId, int, int)),
+ this,
+ SLOT(slotPluginPortChanged(InstrumentId, int, int)));
+
+ connect(dialog,
+ SIGNAL(pluginProgramChanged(InstrumentId, int)),
+ this,
+ SLOT(slotPluginProgramChanged(InstrumentId, int)));
+
+ connect(dialog,
+ SIGNAL(changePluginConfiguration(InstrumentId, int, bool, QString, QString)),
+ this,
+ SLOT(slotChangePluginConfiguration(InstrumentId, int, bool, QString, QString)));
+
+ connect(dialog,
+ SIGNAL(showPluginGUI(InstrumentId, int)),
+ this,
+ SLOT(slotShowPluginGUI(InstrumentId, int)));
+
+ connect(dialog,
+ SIGNAL(stopPluginGUI(InstrumentId, int)),
+ this,
+ SLOT(slotStopPluginGUI(InstrumentId, int)));
+
+ connect(dialog,
+ SIGNAL(bypassed(InstrumentId, int, bool)),
+ this,
+ SLOT(slotPluginBypassed(InstrumentId, int, bool)));
+
+ connect(dialog,
+ SIGNAL(destroyed(InstrumentId, int)),
+ this,
+ SLOT(slotPluginDialogDestroyed(InstrumentId, int)));
+
+ connect(this, SIGNAL(documentAboutToChange()), dialog, SLOT(close()));
+
+ m_pluginDialogs[key] = dialog;
+ m_pluginDialogs[key]->show();
+
+ // Set modified
+ m_doc->slotDocumentModified();
+}
+
+void
+RosegardenGUIApp::slotPluginSelected(InstrumentId instrumentId,
+ int index, int plugin)
+{
+ const QObject *s = sender();
+
+ bool fromSynthMgr = (s == m_synthManager);
+
+ // It's assumed that ports etc will already have been set up on
+ // the AudioPluginInstance before this is invoked.
+
+ PluginContainer *container = 0;
+
+ container = m_doc->getStudio().getContainerById(instrumentId);
+ if (!container) {
+ RG_DEBUG << "RosegardenGUIApp::slotPluginSelected - "
+ << "no instrument or buss of id " << instrumentId << endl;
+ return ;
+ }
+
+ AudioPluginInstance *inst =
+ container->getPlugin(index);
+
+ if (!inst) {
+ RG_DEBUG << "RosegardenGUIApp::slotPluginSelected - "
+ << "got index of unknown plugin!" << endl;
+ return ;
+ }
+
+ if (plugin == -1) {
+ // Destroy plugin instance
+ //!!! seems iffy -- why can't we just unassign it?
+
+ if (StudioControl::
+ destroyStudioObject(inst->getMappedId())) {
+ RG_DEBUG << "RosegardenGUIApp::slotPluginSelected - "
+ << "cannot destroy Studio object "
+ << inst->getMappedId() << endl;
+ }
+
+ inst->setAssigned(false);
+ } else {
+ // If unassigned then create a sequencer instance of this
+ // AudioPluginInstance.
+ //
+ if (inst->isAssigned()) {
+ RG_DEBUG << "RosegardenGUIApp::slotPluginSelected - "
+ << " setting identifier for mapper id " << inst->getMappedId()
+ << " to " << inst->getIdentifier() << endl;
+
+ StudioControl::setStudioObjectProperty
+ (inst->getMappedId(),
+ MappedPluginSlot::Identifier,
+ strtoqstr(inst->getIdentifier()));
+ } else {
+ // create a studio object at the sequencer
+ MappedObjectId newId =
+ StudioControl::createStudioObject
+ (MappedObject::PluginSlot);
+
+ RG_DEBUG << "RosegardenGUIApp::slotPluginSelected - "
+ << " new MappedObjectId = " << newId << endl;
+
+ // set the new Mapped ID and that this instance
+ // is assigned
+ inst->setMappedId(newId);
+ inst->setAssigned(true);
+
+ // set the instrument id
+ StudioControl::setStudioObjectProperty
+ (newId,
+ MappedObject::Instrument,
+ MappedObjectValue(instrumentId));
+
+ // set the position
+ StudioControl::setStudioObjectProperty
+ (newId,
+ MappedObject::Position,
+ MappedObjectValue(index));
+
+ // set the plugin id
+ StudioControl::setStudioObjectProperty
+ (newId,
+ MappedPluginSlot::Identifier,
+ strtoqstr(inst->getIdentifier()));
+ }
+ }
+
+ int pluginMappedId = inst->getMappedId();
+
+ //!!! much code duplicated here from RosegardenGUIDoc::initialiseStudio
+
+ inst->setConfigurationValue
+ (qstrtostr(PluginIdentifier::RESERVED_PROJECT_DIRECTORY_KEY),
+ m_doc->getAudioFileManager().getAudioPath());
+
+ // Set opaque string configuration data (e.g. for DSSI plugin)
+ //
+ MappedObjectPropertyList config;
+ for (AudioPluginInstance::ConfigMap::const_iterator
+ i = inst->getConfiguration().begin();
+ i != inst->getConfiguration().end(); ++i) {
+ config.push_back(strtoqstr(i->first));
+ config.push_back(strtoqstr(i->second));
+ }
+ StudioControl::setStudioObjectPropertyList
+ (pluginMappedId,
+ MappedPluginSlot::Configuration,
+ config);
+
+ // Set the bypass
+ //
+ StudioControl::setStudioObjectProperty
+ (pluginMappedId,
+ MappedPluginSlot::Bypassed,
+ MappedObjectValue(inst->isBypassed()));
+
+ // Set the program
+ //
+ if (inst->getProgram() != "") {
+ StudioControl::setStudioObjectProperty
+ (pluginMappedId,
+ MappedPluginSlot::Program,
+ strtoqstr(inst->getProgram()));
+ }
+
+ // Set all the port values
+ //
+ PortInstanceIterator portIt;
+
+ for (portIt = inst->begin();
+ portIt != inst->end(); ++portIt) {
+ StudioControl::setStudioPluginPort
+ (pluginMappedId,
+ (*portIt)->number,
+ (*portIt)->value);
+ }
+
+ if (fromSynthMgr) {
+ int key = (index << 16) + instrumentId;
+ if (m_pluginDialogs[key]) {
+ m_pluginDialogs[key]->updatePlugin(plugin);
+ }
+ } else if (m_synthManager) {
+ m_synthManager->updatePlugin(instrumentId, plugin);
+ }
+
+ emit pluginSelected(instrumentId, index, plugin);
+
+ // Set modified
+ m_doc->slotDocumentModified();
+}
+
+void
+RosegardenGUIApp::slotChangePluginPort(InstrumentId instrumentId,
+ int pluginIndex,
+ int portIndex,
+ float value)
+{
+ PluginContainer *container = 0;
+
+ container = m_doc->getStudio().getContainerById(instrumentId);
+ if (!container) {
+ RG_DEBUG << "RosegardenGUIApp::slotChangePluginPort - "
+ << "no instrument or buss of id " << instrumentId << endl;
+ return ;
+ }
+
+ AudioPluginInstance *inst = container->getPlugin(pluginIndex);
+ if (!inst) {
+ RG_DEBUG << "RosegardenGUIApp::slotChangePluginPort - "
+ << "no plugin at index " << pluginIndex << " on " << instrumentId << endl;
+ return ;
+ }
+
+ PluginPortInstance *port = inst->getPort(portIndex);
+ if (!port) {
+ RG_DEBUG << "RosegardenGUIApp::slotChangePluginPort - no port "
+ << portIndex << endl;
+ return ;
+ }
+
+ RG_DEBUG << "RosegardenGUIApp::slotPluginPortChanged - "
+ << "setting plugin port (" << inst->getMappedId()
+ << ", " << portIndex << ") from " << port->value
+ << " to " << value << endl;
+
+ port->setValue(value);
+
+ StudioControl::setStudioPluginPort(inst->getMappedId(),
+ portIndex, port->value);
+
+ m_doc->slotDocumentModified();
+
+ // This modification came from The Outside!
+ int key = (pluginIndex << 16) + instrumentId;
+ if (m_pluginDialogs[key]) {
+ m_pluginDialogs[key]->updatePluginPortControl(portIndex);
+ }
+}
+
+void
+RosegardenGUIApp::slotPluginPortChanged(InstrumentId instrumentId,
+ int pluginIndex,
+ int portIndex)
+{
+ PluginContainer *container = 0;
+
+ container = m_doc->getStudio().getContainerById(instrumentId);
+ if (!container) {
+ RG_DEBUG << "RosegardenGUIApp::slotPluginPortChanged - "
+ << "no instrument or buss of id " << instrumentId << endl;
+ return ;
+ }
+
+ AudioPluginInstance *inst = container->getPlugin(pluginIndex);
+ if (!inst) {
+ RG_DEBUG << "RosegardenGUIApp::slotPluginPortChanged - "
+ << "no plugin at index " << pluginIndex << " on " << instrumentId << endl;
+ return ;
+ }
+
+ PluginPortInstance *port = inst->getPort(portIndex);
+ if (!port) {
+ RG_DEBUG << "RosegardenGUIApp::slotPluginPortChanged - no port "
+ << portIndex << endl;
+ return ;
+ }
+
+ RG_DEBUG << "RosegardenGUIApp::slotPluginPortChanged - "
+ << "setting plugin port (" << inst->getMappedId()
+ << ", " << portIndex << ") to " << port->value << endl;
+
+ StudioControl::setStudioPluginPort(inst->getMappedId(),
+ portIndex, port->value);
+
+ m_doc->slotDocumentModified();
+
+#ifdef HAVE_LIBLO
+ // This modification came from our own plugin dialog, so update
+ // any external GUIs
+ if (m_pluginGUIManager) {
+ m_pluginGUIManager->updatePort(instrumentId,
+ pluginIndex,
+ portIndex);
+ }
+#endif
+}
+
+void
+RosegardenGUIApp::slotChangePluginProgram(InstrumentId instrumentId,
+ int pluginIndex,
+ QString program)
+{
+ PluginContainer *container = 0;
+
+ container = m_doc->getStudio().getContainerById(instrumentId);
+ if (!container) {
+ RG_DEBUG << "RosegardenGUIApp::slotChangePluginProgram - "
+ << "no instrument or buss of id " << instrumentId << endl;
+ return ;
+ }
+
+ AudioPluginInstance *inst = container->getPlugin(pluginIndex);
+ if (!inst) {
+ RG_DEBUG << "RosegardenGUIApp::slotChangePluginProgram - "
+ << "no plugin at index " << pluginIndex << " on " << instrumentId << endl;
+ return ;
+ }
+
+ RG_DEBUG << "RosegardenGUIApp::slotChangePluginProgram - "
+ << "setting plugin program ("
+ << inst->getMappedId() << ") from " << inst->getProgram()
+ << " to " << program << endl;
+
+ inst->setProgram(qstrtostr(program));
+
+ StudioControl::
+ setStudioObjectProperty(inst->getMappedId(),
+ MappedPluginSlot::Program,
+ program);
+
+ PortInstanceIterator portIt;
+
+ for (portIt = inst->begin();
+ portIt != inst->end(); ++portIt) {
+ float value = StudioControl::getStudioPluginPort
+ (inst->getMappedId(),
+ (*portIt)->number);
+ (*portIt)->value = value;
+ }
+
+ // Set modified
+ m_doc->slotDocumentModified();
+
+ int key = (pluginIndex << 16) + instrumentId;
+ if (m_pluginDialogs[key]) {
+ m_pluginDialogs[key]->updatePluginProgramControl();
+ }
+}
+
+void
+RosegardenGUIApp::slotPluginProgramChanged(InstrumentId instrumentId,
+ int pluginIndex)
+{
+ PluginContainer *container = 0;
+
+ container = m_doc->getStudio().getContainerById(instrumentId);
+ if (!container) {
+ RG_DEBUG << "RosegardenGUIApp::slotPluginProgramChanged - "
+ << "no instrument or buss of id " << instrumentId << endl;
+ return ;
+ }
+
+ AudioPluginInstance *inst = container->getPlugin(pluginIndex);
+ if (!inst) {
+ RG_DEBUG << "RosegardenGUIApp::slotPluginProgramChanged - "
+ << "no plugin at index " << pluginIndex << " on " << instrumentId << endl;
+ return ;
+ }
+
+ QString program = strtoqstr(inst->getProgram());
+
+ RG_DEBUG << "RosegardenGUIApp::slotPluginProgramChanged - "
+ << "setting plugin program ("
+ << inst->getMappedId() << ") to " << program << endl;
+
+ StudioControl::
+ setStudioObjectProperty(inst->getMappedId(),
+ MappedPluginSlot::Program,
+ program);
+
+ PortInstanceIterator portIt;
+
+ for (portIt = inst->begin();
+ portIt != inst->end(); ++portIt) {
+ float value = StudioControl::getStudioPluginPort
+ (inst->getMappedId(),
+ (*portIt)->number);
+ (*portIt)->value = value;
+ }
+
+ // Set modified
+ m_doc->slotDocumentModified();
+
+#ifdef HAVE_LIBLO
+
+ if (m_pluginGUIManager)
+ m_pluginGUIManager->updateProgram(instrumentId,
+ pluginIndex);
+#endif
+}
+
+void
+RosegardenGUIApp::slotChangePluginConfiguration(InstrumentId instrumentId,
+ int index,
+ bool global,
+ QString key,
+ QString value)
+{
+ PluginContainer *container = 0;
+
+ container = m_doc->getStudio().getContainerById(instrumentId);
+ if (!container) {
+ RG_DEBUG << "RosegardenGUIApp::slotChangePluginConfiguration - "
+ << "no instrument or buss of id " << instrumentId << endl;
+ return ;
+ }
+
+ AudioPluginInstance *inst = container->getPlugin(index);
+
+ if (global && inst) {
+
+ // Set the same configuration on other plugins in the same
+ // instance group
+
+ AudioPlugin *pl =
+ m_pluginManager->getPluginByIdentifier(strtoqstr(inst->getIdentifier()));
+
+ if (pl && pl->isGrouped()) {
+
+ InstrumentList il =
+ m_doc->getStudio().getAllInstruments();
+
+ for (InstrumentList::iterator i = il.begin();
+ i != il.end(); ++i) {
+
+ for (PluginInstanceIterator pli =
+ (*i)->beginPlugins();
+ pli != (*i)->endPlugins(); ++pli) {
+
+ if (*pli && (*pli)->isAssigned() &&
+ (*pli)->getIdentifier() == inst->getIdentifier() &&
+ (*pli) != inst) {
+
+ slotChangePluginConfiguration
+ ((*i)->getId(), (*pli)->getPosition(),
+ false, key, value);
+
+#ifdef HAVE_LIBLO
+
+ m_pluginGUIManager->updateConfiguration
+ ((*i)->getId(), (*pli)->getPosition(), key);
+#endif
+
+ }
+ }
+ }
+ }
+ }
+
+ if (inst) {
+
+ inst->setConfigurationValue(qstrtostr(key), qstrtostr(value));
+
+ MappedObjectPropertyList config;
+ for (AudioPluginInstance::ConfigMap::const_iterator
+ i = inst->getConfiguration().begin();
+ i != inst->getConfiguration().end(); ++i) {
+ config.push_back(strtoqstr(i->first));
+ config.push_back(strtoqstr(i->second));
+ }
+
+ RG_DEBUG << "RosegardenGUIApp::slotChangePluginConfiguration: setting new config on mapped id " << inst->getMappedId() << endl;
+
+ StudioControl::setStudioObjectPropertyList
+ (inst->getMappedId(),
+ MappedPluginSlot::Configuration,
+ config);
+
+ // Set modified
+ m_doc->slotDocumentModified();
+
+ int key = (index << 16) + instrumentId;
+ if (m_pluginDialogs[key]) {
+ m_pluginDialogs[key]->updatePluginProgramList();
+ }
+ }
+}
+
+void
+RosegardenGUIApp::slotPluginDialogDestroyed(InstrumentId instrumentId,
+ int index)
+{
+ int key = (index << 16) + instrumentId;
+ m_pluginDialogs[key] = 0;
+}
+
+void
+RosegardenGUIApp::slotPluginBypassed(InstrumentId instrumentId,
+ int pluginIndex, bool bp)
+{
+ PluginContainer *container = 0;
+
+ container = m_doc->getStudio().getContainerById(instrumentId);
+ if (!container) {
+ RG_DEBUG << "RosegardenGUIApp::slotPluginBypassed - "
+ << "no instrument or buss of id " << instrumentId << endl;
+ return ;
+ }
+
+ AudioPluginInstance *inst = container->getPlugin(pluginIndex);
+
+ if (inst) {
+ StudioControl::setStudioObjectProperty
+ (inst->getMappedId(),
+ MappedPluginSlot::Bypassed,
+ MappedObjectValue(bp));
+
+ // Set the bypass on the instance
+ //
+ inst->setBypass(bp);
+
+ // Set modified
+ m_doc->slotDocumentModified();
+ }
+
+ emit pluginBypassed(instrumentId, pluginIndex, bp);
+}
+
+void
+RosegardenGUIApp::slotShowPluginGUI(InstrumentId instrument,
+ int index)
+{
+#ifdef HAVE_LIBLO
+ m_pluginGUIManager->showGUI(instrument, index);
+#endif
+}
+
+void
+RosegardenGUIApp::slotStopPluginGUI(InstrumentId instrument,
+ int index)
+{
+#ifdef HAVE_LIBLO
+ m_pluginGUIManager->stopGUI(instrument, index);
+#endif
+}
+
+void
+RosegardenGUIApp::slotPluginGUIExited(InstrumentId instrument,
+ int index)
+{
+ int key = (index << 16) + instrument;
+ if (m_pluginDialogs[key]) {
+ m_pluginDialogs[key]->guiExited();
+ }
+}
+
+void
+RosegardenGUIApp::slotPlayList()
+{
+ if (!m_playList) {
+ m_playList = new PlayListDialog(i18n("Play List"), this);
+ connect(m_playList, SIGNAL(closing()),
+ SLOT(slotPlayListClosed()));
+ connect(m_playList->getPlayList(), SIGNAL(play(QString)),
+ SLOT(slotPlayListPlay(QString)));
+ }
+
+ m_playList->show();
+}
+
+void
+RosegardenGUIApp::slotPlayListPlay(QString url)
+{
+ slotStop();
+ openURL(url);
+ slotPlay();
+}
+
+void
+RosegardenGUIApp::slotPlayListClosed()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotPlayListClosed()\n";
+ m_playList = 0;
+}
+
+void
+RosegardenGUIApp::slotTutorial()
+{
+ QString exe = KStandardDirs::findExe( "x-www-browser" );
+
+ if( exe )
+ {
+ KProcess *proc = new KProcess;
+ *proc << "x-www-browser";
+ *proc << "http://rosegarden.sourceforge.net/tutorial/en/chapter-0.html";
+
+ proc->start(KProcess::DontCare);
+ proc->detach();
+ delete proc;
+ }
+ else
+ {
+ QString tutorialURL = i18n("http://rosegarden.sourceforge.net/tutorial/en/chapter-0.html");
+ kapp->invokeBrowser(tutorialURL);
+ }
+}
+
+void
+RosegardenGUIApp::slotBugGuidelines()
+{
+ QString exe = KStandardDirs::findExe( "x-www-browser" );
+
+ if( exe )
+ {
+ KProcess *proc = new KProcess;
+ *proc << "x-www-browser";
+ *proc << "http://rosegarden.sourceforge.net/tutorial/bug-guidelines.html";
+
+ proc->start(KProcess::DontCare);
+ proc->detach();
+ delete proc;
+ }
+ else
+ {
+ QString tutorialURL = i18n("http://rosegarden.sourceforge.net/tutorial/bug-guidelines.html");
+ kapp->invokeBrowser(tutorialURL);
+ }
+}
+
+void
+RosegardenGUIApp::slotBankEditorClosed()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotBankEditorClosed()\n";
+
+ if (m_doc->isModified()) {
+ if (m_view)
+ m_view->slotSelectTrackSegments(m_doc->getComposition().getSelectedTrack());
+ }
+
+ m_bankEditor = 0;
+}
+
+void
+RosegardenGUIApp::slotDeviceManagerClosed()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotDeviceManagerClosed()\n";
+
+ if (m_doc->isModified()) {
+ if (m_view)
+ m_view->slotSelectTrackSegments(m_doc->getComposition().getSelectedTrack());
+ }
+
+ m_deviceManager = 0;
+}
+
+void
+RosegardenGUIApp::slotSynthPluginManagerClosed()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotSynthPluginManagerClosed()\n";
+
+ m_synthManager = 0;
+}
+
+void
+RosegardenGUIApp::slotAudioMixerClosed()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotAudioMixerClosed()\n";
+
+ m_audioMixer = 0;
+}
+
+void
+RosegardenGUIApp::slotMidiMixerClosed()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotMidiMixerClosed()\n";
+
+ m_midiMixer = 0;
+}
+
+void
+RosegardenGUIApp::slotAudioManagerClosed()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotAudioManagerClosed()\n";
+
+ if (m_doc->isModified()) {
+ if (m_view)
+ m_view->slotSelectTrackSegments(m_doc->getComposition().getSelectedTrack());
+ }
+
+ m_audioManagerDialog = 0;
+}
+
+void
+RosegardenGUIApp::slotPanic()
+{
+ if (m_seqManager) {
+ // Stop the transport before we send a panic as the
+ // playback goes all to hell anyway.
+ //
+ slotStop();
+
+ ProgressDialog progressDlg(i18n("Queueing MIDI panic events for tranmission..."),
+ 100,
+ this);
+ CurrentProgressDialog::set
+ (&progressDlg);
+ ProgressDialog::processEvents();
+
+ connect(m_seqManager, SIGNAL(setProgress(int)),
+ progressDlg.progressBar(), SLOT(setValue(int)));
+ connect(m_seqManager, SIGNAL(incrementProgress(int)),
+ progressDlg.progressBar(), SLOT(advance(int)));
+
+ m_seqManager->panic();
+
+ }
+}
+
+void
+RosegardenGUIApp::slotPopulateTrackInstrumentPopup()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotSetTrackInstrument\n";
+ Composition &comp = m_doc->getComposition();
+ Track *track = comp.getTrackById(comp.getSelectedTrack());
+
+ if (!track) {
+ RG_DEBUG << "Weird: no track available for instrument popup!" << endl;
+ return ;
+ }
+
+ Instrument* instrument = m_doc->getStudio().getInstrumentById(track->getInstrument());
+
+ QPopupMenu* popup = dynamic_cast<QPopupMenu*>(factory()->container("set_track_instrument", this));
+
+ m_view->getTrackEditor()->getTrackButtons()->populateInstrumentPopup(instrument, popup);
+}
+
+void
+RosegardenGUIApp::slotRemapInstruments()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotRemapInstruments\n";
+ RemapInstrumentDialog dialog(this, m_doc);
+
+ connect(&dialog, SIGNAL(applyClicked()),
+ m_view->getTrackEditor()->getTrackButtons(),
+ SLOT(slotSynchroniseWithComposition()));
+
+ if (dialog.exec() == QDialog::Accepted) {
+ RG_DEBUG << "slotRemapInstruments - accepted\n";
+ }
+
+}
+
+void
+RosegardenGUIApp::slotSaveDefaultStudio()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotSaveDefaultStudio\n";
+
+ int reply = KMessageBox::warningYesNo
+ (this, i18n("Are you sure you want to save this as your default studio?"));
+
+ if (reply != KMessageBox::Yes)
+ return ;
+
+ KTmpStatusMsg msg(i18n("Saving current document as default studio..."), this);
+
+ QString autoloadFile = ::locateLocal("appdata", "autoload.rg");
+
+ RG_DEBUG << "RosegardenGUIApp::slotSaveDefaultStudio : saving studio in "
+ << autoloadFile << endl;
+
+ SetWaitCursor waitCursor;
+ QString errMsg;
+ bool res = m_doc->saveDocument(autoloadFile, errMsg);
+ if (!res) {
+ if (errMsg)
+ KMessageBox::error(this, i18n(QString("Could not auto-save document at %1\nError was : %2")
+ .arg(autoloadFile).arg(errMsg)));
+ else
+ KMessageBox::error(this, i18n(QString("Could not auto-save document at %1")
+ .arg(autoloadFile)));
+
+ }
+}
+
+void
+RosegardenGUIApp::slotImportDefaultStudio()
+{
+ int reply = KMessageBox::warningYesNo
+ (this, i18n("Are you sure you want to import your default studio and lose the current one?"));
+
+ if (reply != KMessageBox::Yes)
+ return ;
+
+ QString autoloadFile =
+ KGlobal::dirs()->findResource("appdata", "autoload.rg");
+
+ QFileInfo autoloadFileInfo(autoloadFile);
+
+ if (!autoloadFileInfo.isReadable()) {
+ RG_DEBUG << "RosegardenGUIDoc::slotImportDefaultStudio - "
+ << "can't find autoload file - defaulting" << endl;
+ return ;
+ }
+
+ slotImportStudioFromFile(autoloadFile);
+}
+
+void
+RosegardenGUIApp::slotImportStudio()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotImportStudio()\n";
+
+ QString studioDir = KGlobal::dirs()->findResource("appdata", "library/");
+ QDir dir(studioDir);
+ if (!dir.exists()) {
+ studioDir = ":ROSEGARDENDEVICE";
+ } else {
+ studioDir = "file://" + studioDir;
+ }
+
+ KURL url = KFileDialog::getOpenURL
+ (studioDir,
+ "audio/x-rosegarden-device audio/x-rosegarden",
+ this, i18n("Import Studio from File"));
+
+ if (url.isEmpty())
+ return ;
+
+ QString target;
+ if (KIO::NetAccess::download(url, target, this) == false) {
+ KMessageBox::error(this, i18n("Cannot download file %1")
+ .arg(url.prettyURL()));
+ return ;
+ }
+
+ slotImportStudioFromFile(target);
+}
+
+void
+RosegardenGUIApp::slotImportStudioFromFile(const QString &file)
+{
+ RosegardenGUIDoc *doc = new RosegardenGUIDoc(this, 0, true); // skipAutoload
+
+ Studio &oldStudio = m_doc->getStudio();
+ Studio &newStudio = doc->getStudio();
+
+ // Add some dummy devices for when we open the document. We guess
+ // that the file won't have more than 32 devices.
+ //
+ // for (unsigned int i = 0; i < 32; i++) {
+ // newStudio.addDevice("", i, Device::Midi);
+ // }
+
+ if (doc->openDocument(file, true)) { // true because we actually
+ // do want to create devices
+ // on the sequencer here
+
+ KMacroCommand *command = new KMacroCommand(i18n("Import Studio"));
+ doc->syncDevices();
+
+ // We actually only copy across MIDI play devices... for now
+ std::vector<DeviceId> midiPlayDevices;
+
+ for (DeviceList::const_iterator i =
+ oldStudio.begin(); i != oldStudio.end(); ++i) {
+
+ MidiDevice *md =
+ dynamic_cast<MidiDevice *>(*i);
+
+ if (md && (md->getDirection() == MidiDevice::Play)) {
+ midiPlayDevices.push_back((*i)->getId());
+ }
+ }
+
+ std::vector<DeviceId>::iterator di(midiPlayDevices.begin());
+
+ for (DeviceList::const_iterator i =
+ newStudio.begin(); i != newStudio.end(); ++i) {
+
+ MidiDevice *md =
+ dynamic_cast<MidiDevice *>(*i);
+
+ if (md && (md->getDirection() == MidiDevice::Play)) {
+ if (di != midiPlayDevices.end()) {
+ MidiDevice::VariationType variation
+ (md->getVariationType());
+ BankList bl(md->getBanks());
+ ProgramList pl(md->getPrograms());
+ ControlList cl(md->getControlParameters());
+
+ ModifyDeviceCommand* mdCommand = new ModifyDeviceCommand(&oldStudio,
+ *di,
+ md->getName(),
+ md->getLibrarianName(),
+ md->getLibrarianEmail());
+ mdCommand->setVariation(variation);
+ mdCommand->setBankList(bl);
+ mdCommand->setProgramList(pl);
+ mdCommand->setControlList(cl);
+ mdCommand->setOverwrite(true);
+ mdCommand->setRename(md->getName() != "");
+
+ command->addCommand(mdCommand);
+ ++di;
+ }
+ }
+ }
+
+ while (di != midiPlayDevices.end()) {
+ command->addCommand(new CreateOrDeleteDeviceCommand
+ (&oldStudio,
+ *di));
+ }
+
+ oldStudio.setMIDIThruFilter(newStudio.getMIDIThruFilter());
+ oldStudio.setMIDIRecordFilter(newStudio.getMIDIRecordFilter());
+
+ m_doc->getCommandHistory()->addCommand(command);
+ m_doc->syncDevices();
+ m_doc->initialiseStudio(); // The other document will have reset it
+ }
+
+ delete doc;
+}
+
+void
+RosegardenGUIApp::slotResetMidiNetwork()
+{
+ if (m_seqManager) {
+
+ m_seqManager->preparePlayback(true);
+
+ m_seqManager->resetMidiNetwork();
+ }
+
+}
+
+void
+RosegardenGUIApp::slotModifyMIDIFilters()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotModifyMIDIFilters" << endl;
+
+ MidiFilterDialog dialog(this, m_doc);
+
+ if (dialog.exec() == QDialog::Accepted) {
+ RG_DEBUG << "slotModifyMIDIFilters - accepted" << endl;
+ }
+}
+
+void
+RosegardenGUIApp::slotManageMetronome()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotManageMetronome" << endl;
+
+ ManageMetronomeDialog dialog(this, m_doc);
+
+ if (dialog.exec() == QDialog::Accepted) {
+ RG_DEBUG << "slotManageMetronome - accepted" << endl;
+ }
+}
+
+void
+RosegardenGUIApp::slotAutoSave()
+{
+ if (!m_seqManager ||
+ m_seqManager->getTransportStatus() == PLAYING ||
+ m_seqManager->getTransportStatus() == RECORDING)
+ return ;
+
+ KConfig* config = kapp->config();
+ config->setGroup(GeneralOptionsConfigGroup);
+ if (!config->readBoolEntry("autosave", true))
+ return ;
+
+ m_doc->slotAutoSave();
+}
+
+void
+RosegardenGUIApp::slotUpdateAutoSaveInterval(unsigned int interval)
+{
+ RG_DEBUG << "RosegardenGUIApp::slotUpdateAutoSaveInterval - "
+ << "changed interval to " << interval << endl;
+ m_autoSaveTimer->changeInterval(int(interval) * 1000);
+}
+
+void
+RosegardenGUIApp::slotUpdateSidebarStyle(unsigned int style)
+{
+ RG_DEBUG << "RosegardenGUIApp::slotUpdateSidebarStyle - "
+ << "changed style to " << style << endl;
+ m_parameterArea->setArrangement((RosegardenParameterArea::Arrangement) style);
+}
+
+void
+RosegardenGUIApp::slotShowTip()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotShowTip" << endl;
+ KTipDialog::showTip(this, locate("data", "rosegarden/tips"), true);
+}
+
+void RosegardenGUIApp::slotShowToolHelp(const QString &s)
+{
+ QString msg = s;
+ if (msg != "") msg = " " + msg;
+ slotStatusMsg(msg);
+}
+
+void
+RosegardenGUIApp::slotEnableMIDIThruRouting()
+{
+ m_seqManager->enableMIDIThruRouting(m_enableMIDIrouting->isChecked());
+}
+
+TransportDialog* RosegardenGUIApp::getTransport()
+{
+ if (m_transport == 0)
+ createAndSetupTransport();
+
+ return m_transport;
+}
+
+RosegardenGUIDoc *RosegardenGUIApp::getDocument() const
+{
+ return m_doc;
+}
+
+void
+RosegardenGUIApp::awaitDialogClearance()
+{
+ bool haveDialog = true;
+
+ std::cerr << "RosegardenGUIApp::awaitDialogClearance: entering" << std::endl;
+
+ while (haveDialog) {
+
+ const QObjectList *c = children();
+ if (!c) return;
+
+ haveDialog = false;
+ for (QObjectList::const_iterator i = c->begin(); i != c->end(); ++i) {
+ QDialog *dialog = dynamic_cast<QDialog *>(*i);
+ if (dialog && dialog->isVisible()) {
+ haveDialog = true;
+ break;
+ }
+ }
+
+// std::cerr << "RosegardenGUIApp::awaitDialogClearance: have dialog = "
+// << haveDialog << std::endl;
+
+ if (haveDialog) kapp->processEvents();
+ }
+
+ std::cerr << "RosegardenGUIApp::awaitDialogClearance: exiting" << std::endl;
+}
+
+void
+RosegardenGUIApp::slotNewerVersionAvailable(QString v)
+{
+ if (m_firstRun) return;
+ KStartupLogo::hideIfStillThere();
+ CurrentProgressDialog::freeze();
+ awaitDialogClearance();
+ KMessageBox::information
+ (this,
+ i18n("<h3>Newer version available</h3><p>A newer version of Rosegarden may be available.<br>Please consult the <a href=\"http://www.rosegardenmusic.com/getting/\">Rosegarden website</a> for more information.</p>"),
+ i18n("Newer version available"),
+ QString("version-%1-available-show").arg(v),
+ KMessageBox::AllowLink);
+ CurrentProgressDialog::thaw();
+}
+
+void
+RosegardenGUIApp::slotSetQuickMarker()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotSetQuickMarker" << endl;
+
+ m_doc->setQuickMarker();
+ getView()->getTrackEditor()->updateRulers();
+}
+
+void
+RosegardenGUIApp::slotJumpToQuickMarker()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotJumpToQuickMarker" << endl;
+
+ m_doc->jumpToQuickMarker();
+}
+
+const void* RosegardenGUIApp::SequencerExternal = (void*)-1;
+RosegardenGUIApp *RosegardenGUIApp::m_myself = 0;
+
+}
+#include "RosegardenGUIApp.moc"
diff --git a/src/gui/application/RosegardenGUIApp.cpp.orig b/src/gui/application/RosegardenGUIApp.cpp.orig
new file mode 100644
index 0000000..fa98530
--- /dev/null
+++ b/src/gui/application/RosegardenGUIApp.cpp.orig
@@ -0,0 +1,8043 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+ Rosegarden
+ A MIDI and audio sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <richard.bown@ferventsoftware.com>
+
+ The moral rights of Guillaume Laurent, Chris Cannam, and Richard
+ Bown to claim authorship of this work have been asserted.
+
+ Other copyrights also apply to some parts of this work. Please
+ see the AUTHORS file and individual file headers for details.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+
+#include "RosegardenGUIApp.h"
+#include <kapplication.h>
+
+#include "gui/editors/segment/TrackEditor.h"
+#include "gui/editors/segment/TrackButtons.h"
+#include "misc/Debug.h"
+#include "misc/Strings.h"
+#include "gui/application/RosegardenDCOP.h"
+#include "base/AnalysisTypes.h"
+#include "base/AudioPluginInstance.h"
+#include "base/Clipboard.h"
+#include "base/Composition.h"
+#include "base/CompositionTimeSliceAdapter.h"
+#include "base/Configuration.h"
+#include "base/Device.h"
+#include "base/Exception.h"
+#include "base/Instrument.h"
+#include "base/MidiDevice.h"
+#include "base/MidiProgram.h"
+#include "base/NotationTypes.h"
+#include "base/Profiler.h"
+#include "base/RealTime.h"
+#include "base/Segment.h"
+#include "base/SegmentNotationHelper.h"
+#include "base/Selection.h"
+#include "base/Studio.h"
+#include "base/Track.h"
+#include "commands/edit/CopyCommand.h"
+#include "commands/edit/CutCommand.h"
+#include "commands/edit/EventQuantizeCommand.h"
+#include "commands/edit/PasteSegmentsCommand.h"
+#include "commands/edit/TransposeCommand.h"
+#include "commands/edit/AddMarkerCommand.h"
+#include "commands/edit/ModifyMarkerCommand.h"
+#include "commands/edit/RemoveMarkerCommand.h"
+#include "commands/notation/KeyInsertionCommand.h"
+#include "commands/segment/AddTempoChangeCommand.h"
+#include "commands/segment/AddTimeSignatureAndNormalizeCommand.h"
+#include "commands/segment/AddTimeSignatureCommand.h"
+#include "commands/segment/AudioSegmentAutoSplitCommand.h"
+#include "commands/segment/AudioSegmentRescaleCommand.h"
+#include "commands/segment/AudioSegmentSplitCommand.h"
+#include "commands/segment/ChangeCompositionLengthCommand.h"
+#include "commands/segment/CreateTempoMapFromSegmentCommand.h"
+#include "commands/segment/CutRangeCommand.h"
+#include "commands/segment/DeleteRangeCommand.h"
+#include "commands/segment/InsertRangeCommand.h"
+#include "commands/segment/ModifyDefaultTempoCommand.h"
+#include "commands/segment/MoveTracksCommand.h"
+#include "commands/segment/PasteRangeCommand.h"
+#include "commands/segment/RemoveTempoChangeCommand.h"
+#include "commands/segment/SegmentAutoSplitCommand.h"
+#include "commands/segment/SegmentChangeTransposeCommand.h"
+#include "commands/segment/SegmentJoinCommand.h"
+#include "commands/segment/SegmentLabelCommand.h"
+#include "commands/segment/SegmentReconfigureCommand.h"
+#include "commands/segment/SegmentRescaleCommand.h"
+#include "commands/segment/SegmentSplitByPitchCommand.h"
+#include "commands/segment/SegmentSplitByRecordingSrcCommand.h"
+#include "commands/segment/SegmentSplitCommand.h"
+#include "commands/segment/SegmentTransposeCommand.h"
+#include "commands/studio/CreateOrDeleteDeviceCommand.h"
+#include "commands/studio/ModifyDeviceCommand.h"
+#include "document/io/CsoundExporter.h"
+#include "document/io/HydrogenLoader.h"
+#include "document/io/LilyPondExporter.h"
+#include "document/MultiViewCommandHistory.h"
+#include "document/io/RG21Loader.h"
+#include "document/io/MupExporter.h"
+#include "document/io/MusicXmlExporter.h"
+#include "document/RosegardenGUIDoc.h"
+#include "document/ConfigGroups.h"
+#include "gui/application/RosegardenApplication.h"
+#include "gui/dialogs/AddTracksDialog.h"
+#include "gui/dialogs/AudioManagerDialog.h"
+#include "gui/dialogs/AudioPluginDialog.h"
+#include "gui/dialogs/AudioSplitDialog.h"
+#include "gui/dialogs/BeatsBarsDialog.h"
+#include "gui/dialogs/CompositionLengthDialog.h"
+#include "gui/dialogs/ConfigureDialog.h"
+#include "gui/dialogs/CountdownDialog.h"
+#include "gui/dialogs/DocumentConfigureDialog.h"
+#include "gui/dialogs/FileMergeDialog.h"
+#include "gui/dialogs/IdentifyTextCodecDialog.h"
+#include "gui/dialogs/IntervalDialog.h"
+#include "gui/dialogs/LilyPondOptionsDialog.h"
+#include "gui/dialogs/ManageMetronomeDialog.h"
+#include "gui/dialogs/QuantizeDialog.h"
+#include "gui/dialogs/RescaleDialog.h"
+#include "gui/dialogs/SplitByPitchDialog.h"
+#include "gui/dialogs/SplitByRecordingSrcDialog.h"
+#include "gui/dialogs/TempoDialog.h"
+#include "gui/dialogs/TimeDialog.h"
+#include "gui/dialogs/TimeSignatureDialog.h"
+#include "gui/dialogs/TransportDialog.h"
+#include "gui/editors/parameters/InstrumentParameterBox.h"
+#include "gui/editors/parameters/RosegardenParameterArea.h"
+#include "gui/editors/parameters/SegmentParameterBox.h"
+#include "gui/editors/parameters/TrackParameterBox.h"
+#include "gui/editors/segment/segmentcanvas/CompositionView.h"
+#include "gui/editors/segment/ControlEditorDialog.h"
+#include "gui/editors/segment/MarkerEditor.h"
+#include "gui/editors/segment/PlayListDialog.h"
+#include "gui/editors/segment/PlayList.h"
+#include "gui/editors/segment/segmentcanvas/SegmentEraser.h"
+#include "gui/editors/segment/segmentcanvas/SegmentJoiner.h"
+#include "gui/editors/segment/segmentcanvas/SegmentMover.h"
+#include "gui/editors/segment/segmentcanvas/SegmentPencil.h"
+#include "gui/editors/segment/segmentcanvas/SegmentResizer.h"
+#include "gui/editors/segment/segmentcanvas/SegmentSelector.h"
+#include "gui/editors/segment/segmentcanvas/SegmentSplitter.h"
+#include "gui/editors/segment/segmentcanvas/SegmentToolBox.h"
+#include "gui/editors/segment/TrackLabel.h"
+#include "gui/editors/segment/TriggerSegmentManager.h"
+#include "gui/editors/tempo/TempoView.h"
+#include "gui/general/EditViewBase.h"
+#include "gui/kdeext/KStartupLogo.h"
+#include "gui/kdeext/KTmpStatusMsg.h"
+#include "gui/seqmanager/MidiFilterDialog.h"
+#include "gui/seqmanager/SequenceManager.h"
+#include "gui/seqmanager/SequencerMapper.h"
+#include "gui/studio/AudioMixerWindow.h"
+#include "gui/studio/AudioPlugin.h"
+#include "gui/studio/AudioPluginManager.h"
+#include "gui/studio/AudioPluginOSCGUIManager.h"
+#include "gui/studio/BankEditorDialog.h"
+#include "gui/studio/DeviceManagerDialog.h"
+#include "gui/studio/MidiMixerWindow.h"
+#include "gui/studio/RemapInstrumentDialog.h"
+#include "gui/studio/StudioControl.h"
+#include "gui/studio/SynthPluginManagerDialog.h"
+#include "gui/widgets/CurrentProgressDialog.h"
+#include "gui/widgets/ProgressBar.h"
+#include "gui/widgets/ProgressDialog.h"
+#include "LircClient.h"
+#include "LircCommander.h"
+#include "RosegardenGUIView.h"
+#include "RosegardenIface.h"
+#include "SetWaitCursor.h"
+#include "sound/AudioFile.h"
+#include "sound/AudioFileManager.h"
+#include "sound/MappedCommon.h"
+#include "sound/MappedComposition.h"
+#include "sound/MappedEvent.h"
+#include "sound/MappedStudio.h"
+#include "sound/MidiFile.h"
+#include "sound/PluginIdentifier.h"
+#include "sound/SoundDriver.h"
+#include "StartupTester.h"
+#include <dcopclient.h>
+#include <dcopobject.h>
+#include <dcopref.h>
+#include <kaction.h>
+#include <kconfig.h>
+#include <kdcopactionproxy.h>
+#include <kdockwidget.h>
+#include <kedittoolbar.h>
+#include <kfiledialog.h>
+#include <kglobal.h>
+#include <kinputdialog.h>
+#include <kio/netaccess.h>
+#include <kkeydialog.h>
+#include <klocale.h>
+#include <kmainwindow.h>
+#include <kmessagebox.h>
+#include <kmimetype.h>
+#include <kprocess.h>
+#include <kstatusbar.h>
+#include <kstdaccel.h>
+#include <kstdaction.h>
+#include <kstddirs.h>
+#include <ktempfile.h>
+#include <ktip.h>
+#include <ktoolbar.h>
+#include <kurl.h>
+#include <kxmlguiclient.h>
+#include <qaccel.h>
+#include <qcanvas.h>
+#include <qcstring.h>
+#include <qcursor.h>
+#include <qdatastream.h>
+#include <qdialog.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qiconset.h>
+#include <qinputdialog.h>
+#include <qlabel.h>
+#include <qobject.h>
+#include <qobjectlist.h>
+#include <qpixmap.h>
+#include <qpopupmenu.h>
+#include <qpushbutton.h>
+#include <qregexp.h>
+#include <qslider.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qtextcodec.h>
+#include <qtimer.h>
+#include <qvaluevector.h>
+#include <qwidget.h>
+
+#ifdef HAVE_LIBJACK
+#include <jack/jack.h>
+#endif
+
+
+namespace Rosegarden
+{
+
+RosegardenGUIApp::RosegardenGUIApp(bool useSequencer,
+ bool useExistingSequencer,
+ QObject *startupStatusMessageReceiver)
+ : DCOPObject("RosegardenIface"), RosegardenIface(this), KDockMainWindow(0),
+ m_actionsSetup(false),
+ m_fileRecent(0),
+ m_view(0),
+ m_swapView(0),
+ m_mainDockWidget(0),
+ m_dockLeft(0),
+ m_doc(0),
+ m_sequencerProcess(0),
+ m_sequencerCheckedIn(false),
+#ifdef HAVE_LIBJACK
+ m_jackProcess(0),
+#endif
+ m_zoomSlider(0),
+ m_seqManager(0),
+ m_transport(0),
+ m_audioManagerDialog(0),
+ m_originatingJump(false),
+ m_storedLoopStart(0),
+ m_storedLoopEnd(0),
+ m_useSequencer(useSequencer),
+ m_dockVisible(true),
+ m_autoSaveTimer(new QTimer(this)),
+ m_clipboard(new Clipboard),
+ m_playList(0),
+ m_deviceManager(0),
+ m_synthManager(0),
+ m_audioMixer(0),
+ m_midiMixer(0),
+ m_bankEditor(0),
+ m_markerEditor(0),
+ m_tempoView(0),
+ m_triggerSegmentManager(0),
+#ifdef HAVE_LIBLO
+ m_pluginGUIManager(new AudioPluginOSCGUIManager(this)),
+#endif
+ m_playTimer(new QTimer(this)),
+ m_stopTimer(new QTimer(this)),
+ m_startupTester(0),
+#ifdef HAVE_LIRC
+ m_lircClient(0),
+ m_lircCommander(0),
+#endif
+ m_haveAudioImporter(false),
+ m_firstRun(false),
+ m_parameterArea(0)
+{
+ m_myself = this;
+
+
+ if (startupStatusMessageReceiver) {
+ QObject::connect(this, SIGNAL(startupStatusMessage(QString)),
+ startupStatusMessageReceiver,
+ SLOT(slotShowStatusMessage(QString)));
+ }
+
+ // Try to start the sequencer
+ //
+ if (m_useSequencer) {
+
+#ifdef HAVE_LIBJACK
+#define OFFER_JACK_START_OPTION 1
+#ifdef OFFER_JACK_START_OPTION
+ // First we check if jackd is running allready
+
+ std::string jackClientName = "rosegarden";
+
+ // attempt connection to JACK server
+ //
+ jack_client_t* testJackClient;
+ testJackClient = jack_client_new(jackClientName.c_str());
+ if (testJackClient == 0 ) {
+
+ // If no connection to JACK
+ // try to launch JACK - if the configuration wants us to.
+ if (!launchJack()) {
+ KStartupLogo::hideIfStillThere();
+ KMessageBox::error(this, i18n("Attempted to launch JACK audio daemon failed. Audio will be disabled.\nPlease check configuration (Settings -> Configure Rosegarden -> Audio -> Startup)\n and restart."));
+ }
+ } else {
+ //this client was just for testing
+ jack_client_close(testJackClient);
+ }
+#endif // OFFER_JACK_START_OPTION
+#endif // HAVE_LIBJACK
+
+ emit startupStatusMessage(i18n("Starting sequencer..."));
+ launchSequencer(useExistingSequencer);
+
+ } else
+ RG_DEBUG << "RosegardenGUIApp : don't use sequencer\n";
+
+ // Plugin manager
+ //
+ emit startupStatusMessage(i18n("Initializing plugin manager..."));
+ m_pluginManager = new AudioPluginManager();
+
+ // call inits to invoke all other construction parts
+ //
+ emit startupStatusMessage(i18n("Initializing view..."));
+ initStatusBar();
+ setupActions();
+ iFaceDelayedInit(this);
+ initZoomToolbar();
+
+ QPixmap dummyPixmap; // any icon will do
+ m_mainDockWidget = createDockWidget("Rosegarden MainDockWidget", dummyPixmap, 0L, "main_dock_widget");
+ // allow others to dock to the left and right sides only
+ m_mainDockWidget->setDockSite(KDockWidget::DockLeft | KDockWidget::DockRight);
+ // forbit docking abilities of m_mainDockWidget itself
+ m_mainDockWidget->setEnableDocking(KDockWidget::DockNone);
+ setView(m_mainDockWidget); // central widget in a KDE mainwindow
+ setMainDockWidget(m_mainDockWidget); // master dockwidget
+
+ m_dockLeft = createDockWidget("params dock", dummyPixmap, 0L,
+ i18n("Special Parameters"));
+ m_dockLeft->manualDock(m_mainDockWidget, // dock target
+ KDockWidget::DockLeft, // dock site
+ 20); // relation target/this (in percent)
+
+ connect(m_dockLeft, SIGNAL(iMBeingClosed()),
+ this, SLOT(slotParametersClosed()));
+ connect(m_dockLeft, SIGNAL(hasUndocked()),
+ this, SLOT(slotParametersClosed()));
+ // Apparently, hasUndocked() is emitted when the dock widget's
+ // 'close' button on the dock handle is clicked.
+ connect(m_mainDockWidget, SIGNAL(docking(KDockWidget*, KDockWidget::DockPosition)),
+ this, SLOT(slotParametersDockedBack(KDockWidget*, KDockWidget::DockPosition)));
+
+ stateChanged("parametersbox_closed", KXMLGUIClient::StateReverse);
+
+ RosegardenGUIDoc* doc = new RosegardenGUIDoc(this, m_pluginManager);
+
+ m_parameterArea = new RosegardenParameterArea(m_dockLeft);
+ m_dockLeft->setWidget(m_parameterArea);
+
+ // Populate the parameter-box area with the respective
+ // parameter box widgets.
+
+ m_segmentParameterBox = new SegmentParameterBox(doc, m_parameterArea);
+ m_parameterArea->addRosegardenParameterBox(m_segmentParameterBox);
+ m_trackParameterBox = new TrackParameterBox(doc, m_parameterArea);
+ m_parameterArea->addRosegardenParameterBox(m_trackParameterBox);
+ m_instrumentParameterBox = new InstrumentParameterBox(doc, m_parameterArea);
+ m_parameterArea->addRosegardenParameterBox(m_instrumentParameterBox);
+
+ // Lookup the configuration parameter that specifies the default
+ // arrangement, and instantiate it.
+
+ kapp->config()->setGroup(GeneralOptionsConfigGroup);
+ m_parameterArea->setArrangement((RosegardenParameterArea::Arrangement)
+ kapp->config()->readUnsignedNumEntry("sidebarstyle",
+ RosegardenParameterArea::CLASSIC_STYLE));
+
+ m_dockLeft->update();
+
+ connect(m_instrumentParameterBox,
+ SIGNAL(selectPlugin(QWidget *, InstrumentId, int)),
+ this,
+ SLOT(slotShowPluginDialog(QWidget *, InstrumentId, int)));
+
+ connect(m_instrumentParameterBox,
+ SIGNAL(showPluginGUI(InstrumentId, int)),
+ this,
+ SLOT(slotShowPluginGUI(InstrumentId, int)));
+
+ // relay this through our own signal so that others can use it too
+ connect(m_instrumentParameterBox,
+ SIGNAL(instrumentParametersChanged(InstrumentId)),
+ this,
+ SIGNAL(instrumentParametersChanged(InstrumentId)));
+
+ connect(this,
+ SIGNAL(instrumentParametersChanged(InstrumentId)),
+ m_instrumentParameterBox,
+ SLOT(slotInstrumentParametersChanged(InstrumentId)));
+
+ connect(this,
+ SIGNAL(pluginSelected(InstrumentId, int, int)),
+ m_instrumentParameterBox,
+ SLOT(slotPluginSelected(InstrumentId, int, int)));
+
+ connect(this,
+ SIGNAL(pluginBypassed(InstrumentId, int, bool)),
+ m_instrumentParameterBox,
+ SLOT(slotPluginBypassed(InstrumentId, int, bool)));
+
+ // Load the initial document (this includes doc's own autoload)
+ //
+ setDocument(doc);
+
+ emit startupStatusMessage(i18n("Starting sequence manager..."));
+
+ // transport is created by setupActions()
+ m_seqManager = new SequenceManager(m_doc, getTransport());
+
+ if (m_useSequencer) {
+ // Check the sound driver status and warn the user of any
+ // problems. This warning has to happen early, in case it
+ // affects the ability to load plugins etc from a file on the
+ // command line.
+ m_seqManager->checkSoundDriverStatus(true);
+ }
+
+ if (m_view) {
+ connect(m_seqManager, SIGNAL(controllerDeviceEventReceived(MappedEvent *)),
+ m_view, SLOT(slotControllerDeviceEventReceived(MappedEvent *)));
+ }
+
+ if (m_seqManager->getSoundDriverStatus() & AUDIO_OK) {
+ slotStateChanged("got_audio", true);
+ } else {
+ slotStateChanged("got_audio", false);
+ }
+
+ // If we're restarting the gui then make sure any transient
+ // studio objects are cleared away.
+ emit startupStatusMessage(i18n("Clearing studio data..."));
+ m_seqManager->reinitialiseSequencerStudio();
+
+ // Send the transport control statuses for MMC and JACK
+ //
+ m_seqManager->sendTransportControlStatuses();
+
+ // Now autoload
+ //
+ stateChanged("new_file");
+ stateChanged("have_segments", KXMLGUIClient::StateReverse);
+ stateChanged("have_selection", KXMLGUIClient::StateReverse);
+ slotTestClipboard();
+
+ // Check for lack of MIDI devices and disable Studio options accordingly
+ //
+ if (!m_doc->getStudio().haveMidiDevices())
+ stateChanged("got_midi_devices", KXMLGUIClient::StateReverse);
+
+ emit startupStatusMessage(i18n("Starting..."));
+
+ setupFileDialogSpeedbar();
+ readOptions();
+
+ // All toolbars should be created before this is called
+ setAutoSaveSettings(MainWindowConfigGroup, true);
+
+#ifdef HAVE_LIRC
+
+ try {
+ m_lircClient = new LircClient();
+ } catch (Exception e) {
+ RG_DEBUG << e.getMessage().c_str() << endl;
+ // continue without
+ m_lircClient = 0;
+ }
+ if (m_lircClient) {
+ m_lircCommander = new LircCommander(m_lircClient, this);
+ }
+#endif
+
+ stateChanged("have_project_packager", KXMLGUIClient::StateReverse);
+ stateChanged("have_lilypondview", KXMLGUIClient::StateReverse);
+ QTimer::singleShot(1000, this, SLOT(slotTestStartupTester()));
+}
+
+RosegardenGUIApp::~RosegardenGUIApp()
+{
+ RG_DEBUG << "~RosegardenGUIApp()\n";
+
+ if (getView() &&
+ getView()->getTrackEditor() &&
+ getView()->getTrackEditor()->getSegmentCanvas()) {
+ getView()->getTrackEditor()->getSegmentCanvas()->endAudioPreviewGeneration();
+ }
+
+#ifdef HAVE_LIBLO
+ delete m_pluginGUIManager;
+#endif
+
+ if (isSequencerRunning() && !isSequencerExternal()) {
+ m_sequencerProcess->blockSignals(true);
+ rgapp->sequencerSend("quit()");
+ usleep(300000);
+ delete m_sequencerProcess;
+ }
+
+ delete m_jumpToQuickMarkerAction;
+ delete m_setQuickMarkerAction;
+
+ delete m_transport;
+
+ delete m_seqManager;
+
+#ifdef HAVE_LIRC
+
+ delete m_lircCommander;
+ delete m_lircClient;
+#endif
+
+ delete m_doc;
+ Profiles::getInstance()->dump();
+}
+
+void RosegardenGUIApp::setupActions()
+{
+ // setup File menu
+ // New Window ?
+ KStdAction::openNew (this, SLOT(slotFileNew()), actionCollection());
+ KStdAction::open (this, SLOT(slotFileOpen()), actionCollection());
+ m_fileRecent = KStdAction::openRecent(this,
+ SLOT(slotFileOpenRecent(const KURL&)),
+ actionCollection());
+ KStdAction::save (this, SLOT(slotFileSave()), actionCollection());
+ KStdAction::saveAs(this, SLOT(slotFileSaveAs()), actionCollection());
+ KStdAction::revert(this, SLOT(slotRevertToSaved()), actionCollection());
+ KStdAction::close (this, SLOT(slotFileClose()), actionCollection());
+ KStdAction::print (this, SLOT(slotFilePrint()), actionCollection());
+ KStdAction::printPreview (this, SLOT(slotFilePrintPreview()), actionCollection());
+
+ new KAction(i18n("Import Rosegarden &Project file..."), 0, 0, this,
+ SLOT(slotImportProject()), actionCollection(),
+ "file_import_project");
+
+ new KAction(i18n("Import &MIDI file..."), 0, 0, this,
+ SLOT(slotImportMIDI()), actionCollection(),
+ "file_import_midi");
+
+ new KAction(i18n("Import &Rosegarden 2.1 file..."), 0, 0, this,
+ SLOT(slotImportRG21()), actionCollection(),
+ "file_import_rg21");
+
+ new KAction(i18n("Import &Hydrogen file..."), 0, 0, this,
+ SLOT(slotImportHydrogen()), actionCollection(),
+ "file_import_hydrogen");
+
+ new KAction(i18n("Merge &File..."), 0, 0, this,
+ SLOT(slotMerge()), actionCollection(),
+ "file_merge");
+
+ new KAction(i18n("Merge &MIDI file..."), 0, 0, this,
+ SLOT(slotMergeMIDI()), actionCollection(),
+ "file_merge_midi");
+
+ new KAction(i18n("Merge &Rosegarden 2.1 file..."), 0, 0, this,
+ SLOT(slotMergeRG21()), actionCollection(),
+ "file_merge_rg21");
+
+ new KAction(i18n("Merge &Hydrogen file..."), 0, 0, this,
+ SLOT(slotMergeHydrogen()), actionCollection(),
+ "file_merge_hydrogen");
+
+ new KAction(i18n("Export Rosegarden &Project file..."), 0, 0, this,
+ SLOT(slotExportProject()), actionCollection(),
+ "file_export_project");
+
+ new KAction(i18n("Export &MIDI file..."), 0, 0, this,
+ SLOT(slotExportMIDI()), actionCollection(),
+ "file_export_midi");
+
+ new KAction(i18n("Export &LilyPond file..."), 0, 0, this,
+ SLOT(slotExportLilyPond()), actionCollection(),
+ "file_export_lilypond");
+
+ new KAction(i18n("Export Music&XML file..."), 0, 0, this,
+ SLOT(slotExportMusicXml()), actionCollection(),
+ "file_export_musicxml");
+
+ new KAction(i18n("Export &Csound score file..."), 0, 0, this,
+ SLOT(slotExportCsound()), actionCollection(),
+ "file_export_csound");
+
+ new KAction(i18n("Export M&up file..."), 0, 0, this,
+ SLOT(slotExportMup()), actionCollection(),
+ "file_export_mup");
+
+ new KAction(i18n("Print &with LilyPond..."), 0, 0, this,
+ SLOT(slotPrintLilyPond()), actionCollection(),
+ "file_print_lilypond");
+
+ new KAction(i18n("Preview with Lil&yPond..."), 0, 0, this,
+ SLOT(slotPreviewLilyPond()), actionCollection(),
+ "file_preview_lilypond");
+
+ new KAction(i18n("Play&list"), 0, 0, this,
+ SLOT(slotPlayList()), actionCollection(),
+ "file_show_playlist");
+
+ KStdAction::quit (this, SLOT(slotQuit()), actionCollection());
+
+ // help menu
+ new KAction(i18n("Rosegarden &Tutorial"), 0, 0, this,
+ SLOT(slotTutorial()), actionCollection(),
+ "tutorial");
+
+ new KAction(i18n("&Bug Reporting Guidelines"), 0, 0, this,
+ SLOT(slotBugGuidelines()), actionCollection(),
+ "guidelines");
+
+ // setup edit menu
+ KStdAction::cut (this, SLOT(slotEditCut()), actionCollection());
+ KStdAction::copy (this, SLOT(slotEditCopy()), actionCollection());
+ KStdAction::paste (this, SLOT(slotEditPaste()), actionCollection());
+
+ //
+ // undo/redo actions are special in that they are connected to
+ // slots later on, when the current document is set up - see
+ // MultiViewCommandHistory::attachView
+ //
+ new KToolBarPopupAction(i18n("Und&o"),
+ "undo",
+ KStdAccel::shortcut(KStdAccel::Undo),
+ actionCollection(),
+ KStdAction::stdName(KStdAction::Undo));
+
+ new KToolBarPopupAction(i18n("Re&do"),
+ "redo",
+ KStdAccel::shortcut(KStdAccel::Redo),
+ actionCollection(),
+ KStdAction::stdName(KStdAction::Redo));
+ /////
+
+
+
+ // setup Settings menu
+ //
+ m_viewToolBar = KStdAction::showToolbar (this, SLOT(slotToggleToolBar()), actionCollection(),
+ "show_stock_toolbar");
+
+ m_viewToolsToolBar = new KToggleAction(i18n("Show T&ools Toolbar"), 0, this,
+ SLOT(slotToggleToolsToolBar()), actionCollection(),
+ "show_tools_toolbar");
+
+ m_viewTracksToolBar = new KToggleAction(i18n("Show Trac&ks Toolbar"), 0, this,
+ SLOT(slotToggleTracksToolBar()), actionCollection(),
+ "show_tracks_toolbar");
+
+ m_viewEditorsToolBar = new KToggleAction(i18n("Show &Editors Toolbar"), 0, this,
+ SLOT(slotToggleEditorsToolBar()), actionCollection(),
+ "show_editors_toolbar");
+
+ m_viewTransportToolBar = new KToggleAction(i18n("Show Trans&port Toolbar"), 0, this,
+ SLOT(slotToggleTransportToolBar()), actionCollection(),
+ "show_transport_toolbar");
+
+ m_viewZoomToolBar = new KToggleAction(i18n("Show &Zoom Toolbar"), 0, this,
+ SLOT(slotToggleZoomToolBar()), actionCollection(),
+ "show_zoom_toolbar");
+
+ m_viewStatusBar = KStdAction::showStatusbar(this, SLOT(slotToggleStatusBar()),
+ actionCollection(), "show_status_bar");
+
+ m_viewTransport = new KToggleAction(i18n("Show Tra&nsport"), Key_T, this,
+ SLOT(slotToggleTransport()),
+ actionCollection(),
+ "show_transport");
+
+ m_viewTrackLabels = new KToggleAction(i18n("Show Track &Labels"), 0, this,
+ SLOT(slotToggleTrackLabels()),
+ actionCollection(),
+ "show_tracklabels");
+
+ m_viewRulers = new KToggleAction(i18n("Show Playback Position R&uler"), 0, this,
+ SLOT(slotToggleRulers()),
+ actionCollection(),
+ "show_rulers");
+
+ m_viewTempoRuler = new KToggleAction(i18n("Show Te&mpo Ruler"), 0, this,
+ SLOT(slotToggleTempoRuler()),
+ actionCollection(),
+ "show_tempo_ruler");
+
+ m_viewChordNameRuler = new KToggleAction(i18n("Show Cho&rd Name Ruler"), 0, this,
+ SLOT(slotToggleChordNameRuler()),
+ actionCollection(),
+ "show_chord_name_ruler");
+
+
+ m_viewPreviews = new KToggleAction(i18n("Show Segment Pre&views"), 0, this,
+ SLOT(slotTogglePreviews()),
+ actionCollection(),
+ "show_previews");
+
+ new KAction(i18n("Show Special &Parameters"), Key_P, this,
+ SLOT(slotDockParametersBack()),
+ actionCollection(),
+ "show_inst_segment_parameters");
+
+ KStdAction::tipOfDay( this, SLOT( slotShowTip() ), actionCollection() );
+
+ // Standard Actions
+ //
+ KStdAction::saveOptions(this,
+ SLOT(slotSaveOptions()),
+ actionCollection());
+
+ KStdAction::preferences(this,
+ SLOT(slotConfigure()),
+ actionCollection());
+
+ KStdAction::keyBindings(this,
+ SLOT(slotEditKeys()),
+ actionCollection());
+
+ KStdAction::configureToolbars(this,
+ SLOT(slotEditToolbars()),
+ actionCollection());
+
+ KRadioAction *action = 0;
+
+ // Create the select icon
+ //
+ QString pixmapDir = KGlobal::dirs()->findResource("appdata", "pixmaps/");
+ QCanvasPixmap pixmap(pixmapDir + "/toolbar/select.xpm");
+ QIconSet icon = QIconSet(pixmap);
+
+ // TODO : add some shortcuts here
+ action = new KRadioAction(i18n("&Select and Edit"), icon, Key_F2,
+ this, SLOT(slotPointerSelected()),
+ actionCollection(), "select");
+ action->setExclusiveGroup("segmenttools");
+
+ action = new KRadioAction(i18n("&Draw"), "pencil", Key_F3,
+ this, SLOT(slotDrawSelected()),
+ actionCollection(), "draw");
+ action->setExclusiveGroup("segmenttools");
+
+ action = new KRadioAction(i18n("&Erase"), "eraser", Key_F4,
+ this, SLOT(slotEraseSelected()),
+ actionCollection(), "erase");
+ action->setExclusiveGroup("segmenttools");
+
+ action = new KRadioAction(i18n("&Move"), "move", Key_F5,
+ this, SLOT(slotMoveSelected()),
+ actionCollection(), "move");
+ action->setExclusiveGroup("segmenttools");
+
+ pixmap.load(pixmapDir + "/toolbar/resize.xpm");
+ icon = QIconSet(pixmap);
+ action = new KRadioAction(i18n("&Resize"), icon, Key_F6,
+ this, SLOT(slotResizeSelected()),
+ actionCollection(), "resize");
+ action->setExclusiveGroup("segmenttools");
+
+ pixmap.load(pixmapDir + "/toolbar/split.xpm");
+ icon = QIconSet(pixmap);
+ action = new KRadioAction(i18n("&Split"), icon, Key_F7,
+ this, SLOT(slotSplitSelected()),
+ actionCollection(), "split");
+ action->setExclusiveGroup("segmenttools");
+
+ pixmap.load(pixmapDir + "/toolbar/join.xpm");
+ icon = QIconSet(pixmap);
+ action = new KRadioAction(i18n("&Join"), icon, 0,
+ this, SLOT(slotJoinSelected()),
+ actionCollection(), "join");
+ action->setExclusiveGroup("segmenttools");
+
+
+ new KAction(i18n("&Harmonize"), 0, this,
+ SLOT(slotHarmonizeSelection()), actionCollection(),
+ "harmonize_selection");
+
+ pixmap.load(pixmapDir + "/toolbar/event-insert-timesig.png");
+ icon = QIconSet(pixmap);
+ new KAction(AddTimeSignatureCommand::getGlobalName(),
+ icon, 0,
+ this, SLOT(slotEditTimeSignature()),
+ actionCollection(), "add_time_signature");
+
+ new KAction(i18n("Open Tempo and Time Signature Editor"), 0, this,
+ SLOT(slotEditTempos()), actionCollection(), "edit_tempos");
+
+ //
+ // Edit menu
+ //
+ new KAction(i18n("Cut Range"), Key_X + CTRL + SHIFT, this,
+ SLOT(slotCutRange()), actionCollection(),
+ "cut_range");
+
+ new KAction(i18n("Copy Range"), Key_C + CTRL + SHIFT, this,
+ SLOT(slotCopyRange()), actionCollection(),
+ "copy_range");
+
+ new KAction(i18n("Paste Range"), Key_V + CTRL + SHIFT, this,
+ SLOT(slotPasteRange()), actionCollection(),
+ "paste_range");
+/*
+ new KAction(i18n("Delete Range"), Key_Delete + SHIFT, this,
+ SLOT(slotDeleteRange()), actionCollection(),
+ "delete_range");
+*/
+ new KAction(i18n("Insert Range..."), Key_Insert + SHIFT, this,
+ SLOT(slotInsertRange()), actionCollection(),
+ "insert_range");
+
+ new KAction(i18n("De&lete"), Key_Delete, this,
+ SLOT(slotDeleteSelectedSegments()), actionCollection(),
+ "delete");
+
+ new KAction(i18n("Select &All Segments"), Key_A + CTRL, this,
+ SLOT(slotSelectAll()), actionCollection(),
+ "select_all");
+
+ pixmap.load(pixmapDir + "/toolbar/event-insert-tempo.png");
+ icon = QIconSet(pixmap);
+ new KAction(AddTempoChangeCommand::getGlobalName(),
+ icon, 0,
+ this, SLOT(slotEditTempo()),
+ actionCollection(), "add_tempo");
+
+ new KAction(ChangeCompositionLengthCommand::getGlobalName(),
+ 0,
+ this, SLOT(slotChangeCompositionLength()),
+ actionCollection(), "change_composition_length");
+
+ new KAction(i18n("Edit Mar&kers..."), Key_K + CTRL, this,
+ SLOT(slotEditMarkers()),
+ actionCollection(), "edit_markers");
+
+ new KAction(i18n("Edit Document P&roperties..."), 0, this,
+ SLOT(slotEditDocumentProperties()),
+ actionCollection(), "edit_doc_properties");
+
+
+ //
+ // Segments menu
+ //
+ new KAction(i18n("Open in &Default Editor"), Key_Return, this,
+ SLOT(slotEdit()), actionCollection(),
+ "edit_default");
+
+ pixmap.load(pixmapDir + "/toolbar/matrix.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Open in Matri&x Editor"), icon, Key_M, this,
+ SLOT(slotEditInMatrix()), actionCollection(),
+ "edit_matrix");
+
+ pixmap.load(pixmapDir + "/toolbar/matrix-percussion.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Open in &Percussion Matrix Editor"), icon, Key_D, this,
+ SLOT(slotEditInPercussionMatrix()), actionCollection(),
+ "edit_percussion_matrix");
+
+ pixmap.load(pixmapDir + "/toolbar/notation.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Open in &Notation Editor"), icon, Key_N, this,
+ SLOT(slotEditAsNotation()), actionCollection(),
+ "edit_notation");
+
+ pixmap.load(pixmapDir + "/toolbar/eventlist.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Open in &Event List Editor"), icon, Key_E, this,
+ SLOT(slotEditInEventList()), actionCollection(),
+ "edit_event_list");
+
+ pixmap.load(pixmapDir + "/toolbar/quantize.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("&Quantize..."), icon, Key_Equal, this,
+ SLOT(slotQuantizeSelection()), actionCollection(),
+ "quantize_selection");
+
+ new KAction(SegmentLabelCommand::getGlobalName(),
+ 0,
+ this, SLOT(slotRelabelSegments()),
+ actionCollection(), "relabel_segment");
+
+ new KAction(SegmentTransposeCommand::getGlobalName(),
+ 0,
+ this, SLOT(slotTransposeSegments()),
+ actionCollection(), "transpose");
+
+ new KAction(i18n("Repeat Last Quantize"), Key_Plus, this,
+ SLOT(slotRepeatQuantizeSelection()), actionCollection(),
+ "repeat_quantize");
+
+ new KAction(SegmentRescaleCommand::getGlobalName(), 0, this,
+ SLOT(slotRescaleSelection()), actionCollection(),
+ "rescale");
+
+ new KAction(SegmentAutoSplitCommand::getGlobalName(), 0, this,
+ SLOT(slotAutoSplitSelection()), actionCollection(),
+ "auto_split");
+
+ new KAction(SegmentSplitByPitchCommand::getGlobalName(), 0, this,
+ SLOT(slotSplitSelectionByPitch()), actionCollection(),
+ "split_by_pitch");
+
+ new KAction(SegmentSplitByRecordingSrcCommand::getGlobalName(), 0, this,
+ SLOT(slotSplitSelectionByRecordedSrc()), actionCollection(),
+ "split_by_recording");
+
+ new KAction(i18n("Split at Time..."), 0, this,
+ SLOT(slotSplitSelectionAtTime()), actionCollection(),
+ "split_at_time");
+
+ new KAction(i18n("Jog &Left"), Key_Left + ALT, this,
+ SLOT(slotJogLeft()), actionCollection(),
+ "jog_left");
+
+ new KAction(i18n("Jog &Right"), Key_Right + ALT, this,
+ SLOT(slotJogRight()), actionCollection(),
+ "jog_right");
+
+ new KAction(i18n("Set Start Time..."), 0, this,
+ SLOT(slotSetSegmentStartTimes()), actionCollection(),
+ "set_segment_start");
+
+ new KAction(i18n("Set Duration..."), 0, this,
+ SLOT(slotSetSegmentDurations()), actionCollection(),
+ "set_segment_duration");
+
+ new KAction(SegmentJoinCommand::getGlobalName(),
+ Key_J + CTRL,
+ this, SLOT(slotJoinSegments()),
+ actionCollection(), "join_segments");
+
+ new KAction(i18n("Turn Re&peats into Copies"),
+ 0,
+ this, SLOT(slotRepeatingSegments()),
+ actionCollection(), "repeats_to_real_copies");
+
+ new KAction(i18n("Manage Tri&ggered Segments"), 0,
+ this, SLOT(slotManageTriggerSegments()),
+ actionCollection(), "manage_trigger_segments");
+
+ new KAction(i18n("Set Tempos from &Beat Segment"), 0, this,
+ SLOT(slotGrooveQuantize()), actionCollection(),
+ "groove_quantize");
+
+ new KAction(i18n("Set &Tempo to Audio Segment Duration"), 0, this,
+ SLOT(slotTempoToSegmentLength()), actionCollection(),
+ "set_tempo_to_segment_length");
+
+ pixmap.load(pixmapDir + "/toolbar/manage-audio-segments.xpm");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Manage A&udio Files"), icon,
+ Key_U + CTRL,
+ this, SLOT(slotAudioManager()),
+ actionCollection(), "audio_manager");
+
+ m_viewSegmentLabels = new KToggleAction(i18n("Show Segment Labels"), 0, this,
+ SLOT(slotToggleSegmentLabels()), actionCollection(),
+ "show_segment_labels");
+
+ //
+ // Tracks menu
+ //
+ pixmap.load(pixmapDir + "/toolbar/add_tracks.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Add &Track"), icon, CTRL + Key_T,
+ this, SLOT(slotAddTrack()),
+ actionCollection(), "add_track");
+
+ new KAction(i18n("&Add Tracks..."), 0,
+ this, SLOT(slotAddTracks()),
+ actionCollection(), "add_tracks");
+
+ pixmap.load(pixmapDir + "/toolbar/delete_track.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("D&elete Track"), icon, CTRL + Key_D,
+ this, SLOT(slotDeleteTrack()),
+ actionCollection(), "delete_track");
+
+ pixmap.load(pixmapDir + "/toolbar/move_track_down.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Move Track &Down"), icon, SHIFT + Key_Down,
+ this, SLOT(slotMoveTrackDown()),
+ actionCollection(), "move_track_down");
+
+ pixmap.load(pixmapDir + "/toolbar/move_track_up.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Move Track &Up"), icon, SHIFT + Key_Up,
+ this, SLOT(slotMoveTrackUp()),
+ actionCollection(), "move_track_up");
+
+ new KAction(i18n("Select &Next Track"),
+ Key_Down,
+ this, SLOT(slotTrackDown()),
+ actionCollection(), "select_next_track");
+
+ new KAction(i18n("Select &Previous Track"),
+ Key_Up,
+ this, SLOT(slotTrackUp()),
+ actionCollection(), "select_previous_track");
+
+ new KAction(i18n("Mute or Unmute Track"),
+ Key_U,
+ this, SLOT(slotToggleMutedCurrentTrack()),
+ actionCollection(), "toggle_mute_track");
+
+ new KAction(i18n("Arm or Un-arm Track for Record"),
+ Key_R,
+ this, SLOT(slotToggleRecordCurrentTrack()),
+ actionCollection(), "toggle_arm_track");
+
+ pixmap.load(pixmapDir + "/toolbar/mute-all.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("&Mute all Tracks"), icon, 0,
+ this, SLOT(slotMuteAllTracks()),
+ actionCollection(), "mute_all_tracks");
+
+ pixmap.load(pixmapDir + "/toolbar/un-mute-all.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("&Unmute all Tracks"), icon, 0,
+ this, SLOT(slotUnmuteAllTracks()),
+ actionCollection(), "unmute_all_tracks");
+
+ new KAction(i18n("&Remap Instruments..."), 0, this,
+ SLOT(slotRemapInstruments()),
+ actionCollection(), "remap_instruments");
+
+ //
+ // Studio menu
+ //
+ pixmap.load(pixmapDir + "/toolbar/mixer.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("&Audio Mixer"), icon, 0, this,
+ SLOT(slotOpenAudioMixer()),
+ actionCollection(), "audio_mixer");
+
+ pixmap.load(pixmapDir + "/toolbar/midimixer.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Midi Mi&xer"), icon, 0, this,
+ SLOT(slotOpenMidiMixer()),
+ actionCollection(), "midi_mixer");
+
+ pixmap.load(pixmapDir + "/toolbar/manage-midi-devices.xpm");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Manage MIDI &Devices"), icon, 0, this,
+ SLOT(slotManageMIDIDevices()),
+ actionCollection(), "manage_devices");
+
+ pixmap.load(pixmapDir + "/toolbar/manage-synth-plugins.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Manage S&ynth Plugins"), icon, 0, this,
+ SLOT(slotManageSynths()),
+ actionCollection(), "manage_synths");
+
+ new KAction(i18n("Modify MIDI &Filters"), "filter", 0, this,
+ SLOT(slotModifyMIDIFilters()),
+ actionCollection(), "modify_midi_filters");
+
+ m_enableMIDIrouting = new KToggleAction(i18n("MIDI Thru Routing"), 0, this,
+ SLOT(slotEnableMIDIThruRouting()),
+ actionCollection(), "enable_midi_routing");
+
+ pixmap.load(pixmapDir + "/toolbar/time-musical.png");
+ icon = QIconSet(pixmap);
+ new KAction(i18n("Manage &Metronome"), 0, this,
+ SLOT(slotManageMetronome()),
+ actionCollection(), "manage_metronome");
+
+ new KAction(i18n("&Save Current Document as Default Studio"), 0, this,
+ SLOT(slotSaveDefaultStudio()),
+ actionCollection(), "save_default_studio");
+
+ new KAction(i18n("&Import Default Studio"), 0, this,
+ SLOT(slotImportDefaultStudio()),
+ actionCollection(), "load_default_studio");
+
+ new KAction(i18n("Im&port Studio from File..."), 0, this,
+ SLOT(slotImportStudio()),
+ actionCollection(), "load_studio");
+
+ new KAction(i18n("&Reset MIDI Network"), 0, this,
+ SLOT(slotResetMidiNetwork()),
+ actionCollection(), "reset_midi_network");
+
+ m_setQuickMarkerAction = new KAction(i18n("Set Quick Marker at Playback Position"), 0, CTRL + Key_1, this,
+ SLOT(slotSetQuickMarker()), actionCollection(),
+ "set_quick_marker");
+
+ m_jumpToQuickMarkerAction = new KAction(i18n("Jump to Quick Marker"), 0, Key_1, this,
+ SLOT(slotJumpToQuickMarker()), actionCollection(),
+ "jump_to_quick_marker");
+
+ //
+ // Marker Ruler popup menu
+ //
+// new KAction(i18n("Insert Marker"), 0, 0, this,
+// SLOT(slotInsertMarkerHere()), actionCollection(),
+// "insert_marker_here");
+//
+// new KAction(i18n("Insert Marker at Playback Position"), 0, 0, this,
+// SLOT(slotInsertMarkerAtPointer()), actionCollection(),
+// "insert_marker_at_pointer");
+//
+// new KAction(i18n("Delete Marker"), 0, 0, this,
+// SLOT(slotDeleteMarker()), actionCollection(),
+// "delete_marker");
+
+
+
+ //
+ // Transport menu
+ //
+
+ // Transport controls [rwb]
+ //
+ // We set some default key bindings - with numlock off
+ // use 1 (End) and 3 (Page Down) for Rwd and Ffwd and
+ // 0 (insert) and keypad Enter for Play and Stop
+ //
+ pixmap.load(pixmapDir + "/toolbar/transport-play.png");
+ icon = QIconSet(pixmap);
+ m_playTransport = new KAction(i18n("&Play"), icon, Key_Enter, this,
+ SLOT(slotPlay()), actionCollection(),
+ "play");
+ // Alternative shortcut for Play
+ KShortcut playShortcut = m_playTransport->shortcut();
+ playShortcut.append( KKey(Key_Return + CTRL) );
+ m_playTransport->setShortcut(playShortcut);
+ m_playTransport->setGroup(TransportDialogConfigGroup);
+
+ pixmap.load(pixmapDir + "/toolbar/transport-stop.png");
+ icon = QIconSet(pixmap);
+ m_stopTransport = new KAction(i18n("&Stop"), icon, Key_Insert, this,
+ SLOT(slotStop()), actionCollection(),
+ "stop");
+ m_stopTransport->setGroup(TransportDialogConfigGroup);
+
+ pixmap.load(pixmapDir + "/toolbar/transport-ffwd.png");
+ icon = QIconSet(pixmap);
+ m_ffwdTransport = new KAction(i18n("&Fast Forward"), icon, Key_PageDown,
+ this,
+ SLOT(slotFastforward()), actionCollection(),
+ "fast_forward");
+ m_ffwdTransport->setGroup(TransportDialogConfigGroup);
+
+ pixmap.load(pixmapDir + "/toolbar/transport-rewind.png");
+ icon = QIconSet(pixmap);
+ m_rewindTransport = new KAction(i18n("Re&wind"), icon, Key_End, this,
+ SLOT(slotRewind()), actionCollection(),
+ "rewind");
+ m_rewindTransport->setGroup(TransportDialogConfigGroup);
+
+ pixmap.load(pixmapDir + "/toolbar/transport-record.png");
+ icon = QIconSet(pixmap);
+ m_recordTransport = new KAction(i18n("P&unch in Record"), icon, Key_Space, this,
+ SLOT(slotToggleRecord()), actionCollection(),
+ "recordtoggle");
+ m_recordTransport->setGroup(TransportDialogConfigGroup);
+
+ pixmap.load(pixmapDir + "/toolbar/transport-record.png");
+ icon = QIconSet(pixmap);
+ m_recordTransport = new KAction(i18n("&Record"), icon, 0, this,
+ SLOT(slotRecord()), actionCollection(),
+ "record");
+ m_recordTransport->setGroup(TransportDialogConfigGroup);
+
+ pixmap.load(pixmapDir + "/toolbar/transport-rewind-end.png");
+ icon = QIconSet(pixmap);
+ m_rewindEndTransport = new KAction(i18n("Rewind to &Beginning"), icon, 0, this,
+ SLOT(slotRewindToBeginning()), actionCollection(),
+ "rewindtobeginning");
+ m_rewindEndTransport->setGroup(TransportDialogConfigGroup);
+
+ pixmap.load(pixmapDir + "/toolbar/transport-ffwd-end.png");
+ icon = QIconSet(pixmap);
+ m_ffwdEndTransport = new KAction(i18n("Fast Forward to &End"), icon, 0, this,
+ SLOT(slotFastForwardToEnd()), actionCollection(),
+ "fastforwardtoend");
+ m_ffwdEndTransport->setGroup(TransportDialogConfigGroup);
+
+ pixmap.load(pixmapDir + "/toolbar/transport-tracking.png");
+ icon = QIconSet(pixmap);
+ (new KToggleAction(i18n("Scro&ll to Follow Playback"), icon, Key_Pause, this,
+ SLOT(slotToggleTracking()), actionCollection(),
+ "toggle_tracking"))->setChecked(true);
+
+ pixmap.load(pixmapDir + "/toolbar/transport-panic.png");
+ icon = QIconSet(pixmap);
+ new KAction( i18n("Panic"), icon, Key_P + CTRL + ALT, this, SLOT(slotPanic()),
+ actionCollection(), "panic");
+
+ // DEBUG FACILITY
+ new KAction(i18n("Segment Debug Dump "), 0, this,
+ SLOT(slotDebugDump()), actionCollection(),
+ "debug_dump_segments");
+
+ // create main gui
+ //
+ createGUI("rosegardenui.rc", false);
+
+ createAndSetupTransport();
+
+ // transport toolbar is hidden by default - TODO : this should be in options
+ //
+ //toolBar("Transport Toolbar")->hide();
+
+ QPopupMenu* setTrackInstrumentMenu = dynamic_cast<QPopupMenu*>(factory()->container("set_track_instrument", this));
+
+ if (setTrackInstrumentMenu) {
+ connect(setTrackInstrumentMenu, SIGNAL(aboutToShow()),
+ this, SLOT(slotPopulateTrackInstrumentPopup()));
+ } else {
+ RG_DEBUG << "RosegardenGUIApp::setupActions() : couldn't find set_track_instrument menu - check rosegardenui.rcn\n";
+ }
+
+ setRewFFwdToAutoRepeat();
+}
+
+void RosegardenGUIApp::setRewFFwdToAutoRepeat()
+{
+ QWidget* transportToolbar = factory()->container("Transport Toolbar", this);
+
+ if (transportToolbar) {
+ QObjectList *l = transportToolbar->queryList();
+ QObjectListIt it(*l); // iterate over the buttons
+ QObject *obj;
+
+ while ( (obj = it.current()) != 0 ) {
+ // for each found object...
+ ++it;
+ // RG_DEBUG << "obj name : " << obj->name() << endl;
+ QString objName = obj->name();
+
+ if (objName.endsWith("rewind") || objName.endsWith("fast_forward")) {
+ QButton* btn = dynamic_cast<QButton*>(obj);
+ if (!btn) {
+ RG_DEBUG << "Very strange - found widgets in transport_toolbar which aren't buttons\n";
+
+ continue;
+ }
+ btn->setAutoRepeat(true);
+ }
+
+
+ }
+ delete l;
+
+ } else {
+ RG_DEBUG << "transportToolbar == 0\n";
+ }
+
+}
+
+void RosegardenGUIApp::initZoomToolbar()
+{
+ KToolBar *zoomToolbar = toolBar("Zoom Toolbar");
+ if (!zoomToolbar) {
+ RG_DEBUG << "RosegardenGUIApp::initZoomToolbar() : "
+ << "zoom toolbar not found" << endl;
+ return ;
+ }
+
+ new QLabel(i18n(" Zoom: "), zoomToolbar, "kde toolbar widget");
+
+ std::vector<double> zoomSizes; // in units-per-pixel
+ double defaultBarWidth44 = 100.0;
+ double duration44 = TimeSignature(4, 4).getBarDuration();
+ static double factors[] = { 0.025, 0.05, 0.1, 0.2, 0.5,
+ 1.0, 1.5, 2.5, 5.0, 10.0 , 20.0 };
+
+ for (unsigned int i = 0; i < sizeof(factors) / sizeof(factors[0]); ++i) {
+ zoomSizes.push_back(duration44 / (defaultBarWidth44 * factors[i]));
+ }
+
+ // zoom labels
+ QString minZoom = QString("%1%").arg(factors[0] * 100.0);
+ QString maxZoom = QString("%1%").arg(factors[(sizeof(factors) / sizeof(factors[0])) - 1] * 100.0);
+
+ m_zoomSlider = new ZoomSlider<double>
+ (zoomSizes, -1, QSlider::Horizontal, zoomToolbar, "kde toolbar widget");
+ m_zoomSlider->setTracking(true);
+ m_zoomSlider->setFocusPolicy(QWidget::NoFocus);
+ m_zoomLabel = new QLabel(minZoom, zoomToolbar, "kde toolbar widget");
+ m_zoomLabel->setIndent(10);
+
+ connect(m_zoomSlider, SIGNAL(valueChanged(int)),
+ this, SLOT(slotChangeZoom(int)));
+
+ // set initial zoom - we might want to make this a config option
+ // m_zoomSlider->setToDefault();
+
+}
+
+void RosegardenGUIApp::initStatusBar()
+{
+ KTmpStatusMsg::setDefaultMsg("");
+ statusBar()->insertItem(KTmpStatusMsg::getDefaultMsg(),
+ KTmpStatusMsg::getDefaultId(), 1);
+ statusBar()->setItemAlignment(KTmpStatusMsg::getDefaultId(),
+ AlignLeft | AlignVCenter);
+
+ m_progressBar = new ProgressBar(100, true, statusBar());
+ // m_progressBar->setMinimumWidth(100);
+ m_progressBar->setFixedWidth(60);
+ m_progressBar->setFixedHeight(18);
+ m_progressBar->setTextEnabled(false);
+ statusBar()->addWidget(m_progressBar);
+}
+
+void RosegardenGUIApp::initView()
+{
+ ////////////////////////////////////////////////////////////////////
+ // create the main widget here that is managed by KTMainWindow's view-region and
+ // connect the widget to your document to display document contents.
+
+ RG_DEBUG << "RosegardenGUIApp::initView()" << endl;
+
+ Composition &comp = m_doc->getComposition();
+
+ // Ensure that the start and end markers for the piece are set
+ // to something reasonable
+ //
+ if (comp.getStartMarker() == 0 &&
+ comp.getEndMarker() == 0) {
+ int endMarker = comp.getBarRange(100 + comp.getNbBars()).second;
+ comp.setEndMarker(endMarker);
+ }
+
+ m_swapView = new RosegardenGUIView(m_viewTrackLabels->isChecked(),
+ m_segmentParameterBox,
+ m_instrumentParameterBox,
+ m_trackParameterBox, this);
+
+ // Connect up this signal so that we can force tool mode
+ // changes from the view
+ connect(m_swapView, SIGNAL(activateTool(QString)),
+ this, SLOT(slotActivateTool(QString)));
+
+ connect(m_swapView,
+ SIGNAL(segmentsSelected(const SegmentSelection &)),
+ SIGNAL(segmentsSelected(const SegmentSelection &)));
+
+ connect(m_swapView,
+ SIGNAL(addAudioFile(AudioFileId)),
+ SLOT(slotAddAudioFile(AudioFileId)));
+
+ connect(m_swapView, SIGNAL(toggleSolo(bool)), SLOT(slotToggleSolo(bool)));
+
+ m_doc->attachView(m_swapView);
+
+ m_mainDockWidget->setWidget(m_swapView);
+
+ // setCentralWidget(m_swapView);
+ setCaption(m_doc->getTitle());
+
+
+ // Transport setup
+ //
+ std::string transportMode = m_doc->getConfiguration().
+ get
+ <String>
+ (DocumentConfiguration::TransportMode);
+
+
+ slotEnableTransport(true);
+
+ // and the time signature
+ //
+ getTransport()->setTimeSignature(comp.getTimeSignatureAt(comp.getPosition()));
+
+ // set the tempo in the transport
+ //
+ getTransport()->setTempo(comp.getCurrentTempo());
+
+ // bring the transport to the front
+ //
+ getTransport()->raise();
+
+ // set the play metronome button
+ getTransport()->MetronomeButton()->setOn(comp.usePlayMetronome());
+
+ // Set the solo button
+ getTransport()->SoloButton()->setOn(comp.isSolo());
+
+ // set the transport mode found in the configuration
+ getTransport()->setNewMode(transportMode);
+
+ // set the pointer position
+ //
+ slotSetPointerPosition(m_doc->getComposition().getPosition());
+
+ // make sure we show
+ //
+ RosegardenGUIView *oldView = m_view;
+ m_view = m_swapView;
+
+ connect(m_view, SIGNAL(stateChange(QString, bool)),
+ this, SLOT (slotStateChanged(QString, bool)));
+
+ connect(m_view, SIGNAL(instrumentParametersChanged(InstrumentId)),
+ this, SIGNAL(instrumentParametersChanged(InstrumentId)));
+
+ // We only check for the SequenceManager to make sure
+ // we're not on the first pass though - we don't want
+ // to send these toggles twice on initialisation.
+ //
+ // Clunky but we just about get away with it for the
+ // moment.
+ //
+ if (m_seqManager != 0) {
+ slotToggleChordNameRuler();
+ slotToggleRulers();
+ slotToggleTempoRuler();
+ slotTogglePreviews();
+ slotToggleSegmentLabels();
+
+ // Reset any loop on the sequencer
+ //
+ try {
+ if (isUsingSequencer())
+ m_seqManager->setLoop(0, 0);
+ stateChanged("have_range", KXMLGUIClient::StateReverse);
+ } catch (QString s) {
+ KStartupLogo::hideIfStillThere();
+ CurrentProgressDialog::freeze();
+ KMessageBox::error(this, s);
+ CurrentProgressDialog::thaw();
+ }
+
+ connect(m_seqManager, SIGNAL(controllerDeviceEventReceived(MappedEvent *)),
+ m_view, SLOT(slotControllerDeviceEventReceived(MappedEvent *)));
+ }
+
+ // delete m_playList;
+ // m_playList = 0;
+
+ delete m_deviceManager;
+ m_deviceManager = 0;
+
+ delete m_synthManager;
+ m_synthManager = 0;
+
+ delete m_audioMixer;
+ m_audioMixer = 0;
+
+ delete m_bankEditor;
+ m_bankEditor = 0;
+
+ delete m_markerEditor;
+ m_markerEditor = 0;
+
+ delete m_tempoView;
+ m_tempoView = 0;
+
+ delete m_triggerSegmentManager;
+ m_triggerSegmentManager = 0;
+
+ delete oldView;
+
+ // set the highlighted track
+ m_view->slotSelectTrackSegments(comp.getSelectedTrack());
+
+ // play tracking on in the editor by default: turn off if need be
+ KToggleAction *trackingAction = dynamic_cast<KToggleAction *>
+ (actionCollection()->action("toggle_tracking"));
+ if (trackingAction && !trackingAction->isChecked()) {
+ m_view->getTrackEditor()->slotToggleTracking();
+ }
+
+ m_view->show();
+
+ connect(m_view->getTrackEditor()->getSegmentCanvas(),
+ SIGNAL(showContextHelp(const QString &)),
+ this,
+ SLOT(slotShowToolHelp(const QString &)));
+
+ // We have to do this to make sure that the 2nd call ("select")
+ // actually has any effect. Activating the same radio action
+ // doesn't work the 2nd time (like pressing down the same radio
+ // button twice - it doesn't have any effect), so if you load two
+ // files in a row, on the 2nd file a new SegmentCanvas will be
+ // created but its tool won't be set, even though it will appear
+ // to be selected.
+ //
+ actionCollection()->action("move")->activate();
+ if (m_doc->getComposition().getNbSegments() > 0)
+ actionCollection()->action("select")->activate();
+ else
+ actionCollection()->action("draw")->activate();
+
+ int zoomLevel = m_doc->getConfiguration().
+ get
+ <Int>
+ (DocumentConfiguration::ZoomLevel);
+
+ m_zoomSlider->setSize(double(zoomLevel) / 1000.0);
+ slotChangeZoom(zoomLevel);
+
+ //slotChangeZoom(int(m_zoomSlider->getCurrentSize()));
+
+ stateChanged("new_file");
+
+ ProgressDialog::processEvents();
+
+ if (m_viewChordNameRuler->isChecked()) {
+ SetWaitCursor swc;
+ m_view->initChordNameRuler();
+ } else {
+ m_view->initChordNameRuler();
+ }
+}
+
+void RosegardenGUIApp::setDocument(RosegardenGUIDoc* newDocument)
+{
+ if (m_doc == newDocument)
+ return ;
+
+ emit documentAboutToChange();
+ kapp->processEvents(); // to make sure all opened dialogs (mixer, midi devices...) are closed
+
+ // Take care of all subparts which depend on the document
+
+ // Caption
+ //
+ QString caption = kapp->caption();
+ setCaption(caption + ": " + newDocument->getTitle());
+
+ // // reset AudioManagerDialog
+ // //
+ // delete m_audioManagerDialog; // TODO : replace this with a connection to documentAboutToChange() sig.
+ // m_audioManagerDialog = 0;
+
+ RosegardenGUIDoc* oldDoc = m_doc;
+
+ m_doc = newDocument;
+
+ if (m_seqManager) // when we're called at startup, the seq. man. isn't created yet
+ m_seqManager->setDocument(m_doc);
+
+ if (m_markerEditor)
+ m_markerEditor->setDocument(m_doc);
+ if (m_tempoView) {
+ delete m_tempoView;
+ m_tempoView = 0;
+ }
+ if (m_triggerSegmentManager)
+ m_triggerSegmentManager->setDocument(m_doc);
+
+ m_trackParameterBox->setDocument(m_doc);
+ m_segmentParameterBox->setDocument(m_doc);
+ m_instrumentParameterBox->setDocument(m_doc);
+
+#ifdef HAVE_LIBLO
+
+ if (m_pluginGUIManager) {
+ m_pluginGUIManager->stopAllGUIs();
+ m_pluginGUIManager->setStudio(&m_doc->getStudio());
+ }
+#endif
+
+ if (getView() &&
+ getView()->getTrackEditor() &&
+ getView()->getTrackEditor()->getSegmentCanvas()) {
+ getView()->getTrackEditor()->getSegmentCanvas()->endAudioPreviewGeneration();
+ }
+
+ // this will delete all edit views
+ //
+ delete oldDoc;
+
+ // connect needed signals
+ //
+ connect(m_segmentParameterBox, SIGNAL(documentModified()),
+ m_doc, SLOT(slotDocumentModified()));
+
+ connect(m_doc, SIGNAL(pointerPositionChanged(timeT)),
+ this, SLOT(slotSetPointerPosition(timeT)));
+
+ connect(m_doc, SIGNAL(documentModified(bool)),
+ this, SLOT(slotDocumentModified(bool)));
+
+ connect(m_doc, SIGNAL(loopChanged(timeT, timeT)),
+ this, SLOT(slotSetLoop(timeT, timeT)));
+
+ m_doc->getCommandHistory()->attachView(actionCollection());
+
+ connect(m_doc->getCommandHistory(), SIGNAL(commandExecuted()),
+ SLOT(update()));
+ connect(m_doc->getCommandHistory(), SIGNAL(commandExecuted()),
+ SLOT(slotTestClipboard()));
+
+ // connect and start the autosave timer
+ connect(m_autoSaveTimer, SIGNAL(timeout()), this, SLOT(slotAutoSave()));
+ m_autoSaveTimer->start(m_doc->getAutoSavePeriod() * 1000);
+
+ // Connect the playback timer
+ //
+ connect(m_playTimer, SIGNAL(timeout()), this, SLOT(slotUpdatePlaybackPosition()));
+ connect(m_stopTimer, SIGNAL(timeout()), this, SLOT(slotUpdateMonitoring()));
+
+ // finally recreate the main view
+ //
+ initView();
+
+ if (getView() && getView()->getTrackEditor()) {
+ connect(m_doc, SIGNAL(makeTrackVisible(int)),
+ getView()->getTrackEditor(), SLOT(slotScrollToTrack(int)));
+ }
+
+ connect(m_doc, SIGNAL(devicesResyncd()),
+ this, SLOT(slotDocumentDevicesResyncd()));
+
+ m_doc->syncDevices();
+ m_doc->clearModifiedStatus();
+
+ if (newDocument->getStudio().haveMidiDevices()) {
+ stateChanged("got_midi_devices");
+ } else {
+ stateChanged("got_midi_devices", KXMLGUIClient::StateReverse);
+ }
+
+ // Ensure the sequencer knows about any audio files
+ // we've loaded as part of the new Composition
+ //
+ m_doc->prepareAudio();
+
+ // Do not reset instrument prog. changes after all.
+ // if (m_seqManager)
+ // m_seqManager->preparePlayback(true);
+
+ Composition &comp = m_doc->getComposition();
+
+ // Set any loaded loop at the Composition and
+ // on the marker on SegmentCanvas and clients
+ //
+ if (m_seqManager)
+ m_doc->setLoop(comp.getLoopStart(), comp.getLoopEnd());
+
+ emit documentChanged(m_doc);
+
+ m_doc->clearModifiedStatus(); // because it's set as modified by the various
+ // init operations
+ // TODO: this sucks, have to sort it out somehow.
+
+ // Readjust canvas size
+ //
+ m_view->getTrackEditor()->slotReadjustCanvasSize();
+
+ m_stopTimer->start(100);
+}
+
+void
+RosegardenGUIApp::openFile(QString filePath, ImportType type)
+{
+ RG_DEBUG << "RosegardenGUIApp::openFile " << filePath << endl;
+
+ if (type == ImportCheckType && filePath.endsWith(".rgp")) {
+ importProject(filePath);
+ return ;
+ }
+
+ RosegardenGUIDoc *doc = createDocument(filePath, type);
+ if (doc) {
+ setDocument(doc);
+
+ // fix # 1235755, "SPB combo not updating after document swap"
+ RG_DEBUG << "RosegardenGUIApp::openFile(): calling slotDocColoursChanged() in doc" << endl;
+ doc->slotDocColoursChanged();
+
+ kapp->config()->setGroup(GeneralOptionsConfigGroup);
+ if (kapp->config()->readBoolEntry("alwaysusedefaultstudio", false)) {
+
+ QString autoloadFile =
+ KGlobal::dirs()->findResource("appdata", "autoload.rg");
+
+ QFileInfo autoloadFileInfo(autoloadFile);
+ if (autoloadFileInfo.isReadable()) {
+
+ RG_DEBUG << "Importing default studio from " << autoloadFile << endl;
+
+ slotImportStudioFromFile(autoloadFile);
+ }
+ }
+
+ QFileInfo fInfo(filePath);
+ m_fileRecent->addURL(fInfo.absFilePath());
+ }
+}
+
+RosegardenGUIDoc*
+RosegardenGUIApp::createDocument(QString filePath, ImportType importType)
+{
+ QFileInfo info(filePath);
+ RosegardenGUIDoc *doc = 0;
+
+ if (!info.exists()) {
+ // can happen with command-line arg, so...
+ KStartupLogo::hideIfStillThere();
+ KMessageBox::sorry(this, i18n("File \"%1\" does not exist").arg(filePath));
+ return 0;
+ }
+
+ if (info.isDir()) {
+ KStartupLogo::hideIfStillThere();
+ KMessageBox::sorry(this, i18n("File \"%1\" is actually a directory"));
+ return 0;
+ }
+
+ QFile file(filePath);
+
+ if (!file.open(IO_ReadOnly)) {
+ KStartupLogo::hideIfStillThere();
+ QString errStr =
+ i18n("You do not have read permission for \"%1\"").arg(filePath);
+
+ KMessageBox::sorry(this, errStr);
+ return 0;
+ }
+
+ // Stop if playing
+ //
+ if (m_seqManager && m_seqManager->getTransportStatus() == PLAYING)
+ slotStop();
+
+ slotEnableTransport(false);
+
+ if (importType == ImportCheckType) {
+ KMimeType::Ptr fileMimeType = KMimeType::findByPath(filePath);
+ if (fileMimeType->name() == "audio/x-midi")
+ importType = ImportMIDI;
+ else if (fileMimeType->name() == "audio/x-rosegarden")
+ importType = ImportRG4;
+ else if (filePath.endsWith(".rose"))
+ importType = ImportRG21;
+ else if (filePath.endsWith(".h2song"))
+ importType = ImportHydrogen;
+ }
+
+
+ switch (importType) {
+ case ImportMIDI:
+ doc = createDocumentFromMIDIFile(filePath);
+ break;
+ case ImportRG21:
+ doc = createDocumentFromRG21File(filePath);
+ break;
+ case ImportHydrogen:
+ doc = createDocumentFromHydrogenFile(filePath);
+ break;
+ default:
+ doc = createDocumentFromRGFile(filePath);
+ }
+
+ slotEnableTransport(true);
+
+ return doc;
+}
+
+RosegardenGUIDoc*
+RosegardenGUIApp::createDocumentFromRGFile(QString filePath)
+{
+ // Check for an autosaved file to recover
+ QString effectiveFilePath = filePath;
+ bool canRecover = false;
+ QString autoSaveFileName = kapp->checkRecoverFile(filePath, canRecover);
+
+ if (canRecover) {
+ // First check if the auto-save file is more recent than the doc
+ QFileInfo docFileInfo(filePath), autoSaveFileInfo(autoSaveFileName);
+
+ if (docFileInfo.lastModified() < autoSaveFileInfo.lastModified()) {
+
+ RG_DEBUG << "RosegardenGUIApp::openFile : "
+ << "found a more recent autosave file\n";
+
+ // At this point the splash screen may still be there, hide it if
+ // it's the case
+ KStartupLogo::hideIfStillThere();
+
+ // It is, so ask the user if he wants to use the autosave file
+ int reply = KMessageBox::questionYesNo(this,
+ i18n("An auto-save file for this document has been found\nDo you want to open it instead ?"));
+
+ if (reply == KMessageBox::Yes)
+ // open the autosave file instead
+ effectiveFilePath = autoSaveFileName;
+ else {
+ // user doesn't want the autosave, so delete it
+ // so it won't bother us again if we reload
+ canRecover = false;
+ QFile::remove
+ (autoSaveFileName);
+ }
+
+ } else
+ canRecover = false;
+ }
+
+ // Create a new blank document
+ //
+ RosegardenGUIDoc *newDoc = new RosegardenGUIDoc(this, m_pluginManager,
+ true); // skipAutoload
+
+ // ignore return thingy
+ //
+ if (newDoc->openDocument(effectiveFilePath)) {
+ if (canRecover) {
+ // Mark the document as modified,
+ // set the "regular" filepath and name (not those of
+ // the autosaved doc)
+ //
+ newDoc->slotDocumentModified();
+ QFileInfo info(filePath);
+ newDoc->setAbsFilePath(info.absFilePath());
+ newDoc->setTitle(info.fileName());
+ } else {
+ newDoc->clearModifiedStatus();
+ }
+ } else {
+ delete newDoc;
+ return 0;
+ }
+
+ return newDoc;
+}
+
+void RosegardenGUIApp::slotSaveOptions()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotSaveOptions()\n";
+
+#ifdef SETTING_LOG_DEBUG
+
+ _settingLog(QString("SETTING 2 : transport flap extended = %1").arg(getTransport()->isExpanded()));
+ _settingLog(QString("SETTING 2 : show track labels = %1").arg(m_viewTrackLabels->isChecked()));
+#endif
+
+ kapp->config()->setGroup(GeneralOptionsConfigGroup);
+ kapp->config()->writeEntry("Show Transport", m_viewTransport->isChecked());
+ kapp->config()->writeEntry("Expanded Transport", m_transport ? getTransport()->isExpanded() : true);
+ kapp->config()->writeEntry("Show Track labels", m_viewTrackLabels->isChecked());
+ kapp->config()->writeEntry("Show Rulers", m_viewRulers->isChecked());
+ kapp->config()->writeEntry("Show Tempo Ruler", m_viewTempoRuler->isChecked());
+ kapp->config()->writeEntry("Show Chord Name Ruler", m_viewChordNameRuler->isChecked());
+ kapp->config()->writeEntry("Show Previews", m_viewPreviews->isChecked());
+ kapp->config()->writeEntry("Show Segment Labels", m_viewSegmentLabels->isChecked());
+ kapp->config()->writeEntry("Show Parameters", m_dockVisible);
+ kapp->config()->writeEntry("MIDI Thru Routing", m_enableMIDIrouting->isChecked());
+
+#ifdef SETTING_LOG_DEBUG
+
+ RG_DEBUG << "SHOW PARAMETERS = " << m_dockVisible << endl;
+#endif
+
+ m_fileRecent->saveEntries(kapp->config());
+
+ // saveMainWindowSettings(kapp->config(), RosegardenGUIApp::MainWindowConfigGroup); - no need to, done by KMainWindow
+ kapp->config()->sync();
+}
+
+void RosegardenGUIApp::setupFileDialogSpeedbar()
+{
+ KConfig *config = kapp->config();
+
+ config->setGroup("KFileDialog Speedbar");
+
+ RG_DEBUG << "RosegardenGUIApp::setupFileDialogSpeedbar" << endl;
+
+ bool hasSetExamplesItem = config->readBoolEntry("Examples Set", false);
+
+ RG_DEBUG << "RosegardenGUIApp::setupFileDialogSpeedbar: examples set " << hasSetExamplesItem << endl;
+
+ if (!hasSetExamplesItem) {
+
+ unsigned int n = config->readUnsignedNumEntry("Number of Entries", 0);
+
+ config->writeEntry(QString("Description_%1").arg(n), i18n("Example Files"));
+ config->writeEntry(QString("IconGroup_%1").arg(n), 4);
+ config->writeEntry(QString("Icon_%1").arg(n), "folder");
+ config->writeEntry(QString("URL_%1").arg(n),
+ KGlobal::dirs()->findResource("appdata", "examples/"));
+
+ RG_DEBUG << "wrote url " << config->readEntry(QString("URL_%1").arg(n)) << endl;
+
+ config->writeEntry("Examples Set", true);
+ config->writeEntry("Number of Entries", n + 1);
+ config->sync();
+ }
+
+}
+
+void RosegardenGUIApp::readOptions()
+{
+ applyMainWindowSettings(kapp->config(), MainWindowConfigGroup);
+
+ kapp->config()->reparseConfiguration();
+
+ // Statusbar and toolbars toggling action status
+ //
+ m_viewStatusBar ->setChecked(!statusBar() ->isHidden());
+ m_viewToolBar ->setChecked(!toolBar() ->isHidden());
+ m_viewToolsToolBar ->setChecked(!toolBar("Tools Toolbar") ->isHidden());
+ m_viewTracksToolBar ->setChecked(!toolBar("Tracks Toolbar") ->isHidden());
+ m_viewEditorsToolBar ->setChecked(!toolBar("Editors Toolbar") ->isHidden());
+ m_viewTransportToolBar->setChecked(!toolBar("Transport Toolbar")->isHidden());
+ m_viewZoomToolBar ->setChecked(!toolBar("Zoom Toolbar") ->isHidden());
+
+ bool opt;
+
+ kapp->config()->setGroup(GeneralOptionsConfigGroup);
+
+ opt = kapp->config()->readBoolEntry("Show Transport", true);
+ m_viewTransport->setChecked(opt);
+ slotToggleTransport();
+
+ opt = kapp->config()->readBoolEntry("Expanded Transport", true);
+
+#ifdef SETTING_LOG_DEBUG
+
+ _settingLog(QString("SETTING 3 : transport flap extended = %1").arg(opt));
+#endif
+
+ if (opt)
+ getTransport()->slotPanelOpenButtonClicked();
+ else
+ getTransport()->slotPanelCloseButtonClicked();
+
+ opt = kapp->config()->readBoolEntry("Show Track labels", true);
+
+#ifdef SETTING_LOG_DEBUG
+
+ _settingLog(QString("SETTING 3 : show track labels = %1").arg(opt));
+#endif
+
+ m_viewTrackLabels->setChecked(opt);
+ slotToggleTrackLabels();
+
+ opt = kapp->config()->readBoolEntry("Show Rulers", true);
+ m_viewRulers->setChecked(opt);
+ slotToggleRulers();
+
+ opt = kapp->config()->readBoolEntry("Show Tempo Ruler", true);
+ m_viewTempoRuler->setChecked(opt);
+ slotToggleTempoRuler();
+
+ opt = kapp->config()->readBoolEntry("Show Chord Name Ruler", false);
+ m_viewChordNameRuler->setChecked(opt);
+ slotToggleChordNameRuler();
+
+ opt = kapp->config()->readBoolEntry("Show Previews", true);
+ m_viewPreviews->setChecked(opt);
+ slotTogglePreviews();
+
+ opt = kapp->config()->readBoolEntry("Show Segment Labels", true);
+ m_viewSegmentLabels->setChecked(opt);
+ slotToggleSegmentLabels();
+
+ opt = kapp->config()->readBoolEntry("Show Parameters", true);
+ if (!opt) {
+ m_dockLeft->undock();
+ m_dockLeft->hide();
+ stateChanged("parametersbox_closed", KXMLGUIClient::StateNoReverse);
+ m_dockVisible = false;
+ }
+
+ // MIDI Thru routing
+ opt = kapp->config()->readBoolEntry("MIDI Thru Routing", true);
+ m_enableMIDIrouting->setChecked(opt);
+ slotEnableMIDIThruRouting();
+
+ // initialise the recent file list
+ //
+ m_fileRecent->loadEntries(kapp->config());
+
+ m_actionsSetup = true;
+
+}
+
+void RosegardenGUIApp::saveGlobalProperties(KConfig *cfg)
+{
+ if (m_doc->getTitle() != i18n("Untitled") && !m_doc->isModified()) {
+ // saving to tempfile not necessary
+ } else {
+ QString filename = m_doc->getAbsFilePath();
+ cfg->writeEntry("filename", filename);
+ cfg->writeEntry("modified", m_doc->isModified());
+
+ QString tempname = kapp->tempSaveName(filename);
+ QString errMsg;
+ bool res = m_doc->saveDocument(tempname, errMsg);
+ if (!res) {
+ if (errMsg)
+ KMessageBox::error(this, i18n(QString("Could not save document at %1\nError was : %2")
+ .arg(tempname).arg(errMsg)));
+ else
+ KMessageBox::error(this, i18n(QString("Could not save document at %1")
+ .arg(tempname)));
+ }
+ }
+}
+
+void RosegardenGUIApp::readGlobalProperties(KConfig* _cfg)
+{
+ QString filename = _cfg->readEntry("filename", "");
+ bool modified = _cfg->readBoolEntry("modified", false);
+
+ if (modified) {
+ bool canRecover;
+ QString tempname = kapp->checkRecoverFile(filename, canRecover);
+
+ if (canRecover) {
+ slotEnableTransport(false);
+ m_doc->openDocument(tempname);
+ slotEnableTransport(true);
+ m_doc->slotDocumentModified();
+ QFileInfo info(filename);
+ m_doc->setAbsFilePath(info.absFilePath());
+ m_doc->setTitle(info.fileName());
+ }
+ } else {
+ if (!filename.isEmpty()) {
+ slotEnableTransport(false);
+ m_doc->openDocument(filename);
+ slotEnableTransport(true);
+ }
+ }
+
+ QString caption = kapp->caption();
+ setCaption(caption + ": " + m_doc->getTitle());
+}
+
+void RosegardenGUIApp::showEvent(QShowEvent* e)
+{
+ RG_DEBUG << "RosegardenGUIApp::showEvent()\n";
+
+ getTransport()->raise();
+ KMainWindow::showEvent(e);
+}
+
+bool RosegardenGUIApp::queryClose()
+{
+ RG_DEBUG << "RosegardenGUIApp::queryClose" << endl;
+#ifdef SETTING_LOG_DEBUG
+
+ _settingLog(QString("SETTING 1 : transport flap extended = %1").arg(getTransport()->isExpanded()));
+ _settingLog(QString("SETTING 1 : show track labels = %1").arg(m_viewTrackLabels->isChecked()));
+#endif
+
+ QString errMsg;
+
+ bool canClose = m_doc->saveIfModified();
+
+ /*
+ if (canClose && m_transport) {
+
+ // or else the closing of the transport will toggle off the
+ // 'view transport' action, and its state will be saved as
+ // 'off'
+ //
+
+ disconnect(m_transport, SIGNAL(closed()),
+ this, SLOT(slotCloseTransport()));
+ }
+ */
+
+ return canClose;
+
+}
+
+bool RosegardenGUIApp::queryExit()
+{
+ RG_DEBUG << "RosegardenGUIApp::queryExit" << endl;
+ if (m_actionsSetup)
+ slotSaveOptions();
+
+ return true;
+}
+
+void RosegardenGUIApp::slotFileNewWindow()
+{
+ KTmpStatusMsg msg(i18n("Opening a new application window..."), this);
+
+ RosegardenGUIApp *new_window = new RosegardenGUIApp();
+ new_window->show();
+}
+
+void RosegardenGUIApp::slotFileNew()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotFileNew()\n";
+
+ KTmpStatusMsg msg(i18n("Creating new document..."), this);
+
+ bool makeNew = false;
+
+ if (!m_doc->isModified()) {
+ makeNew = true;
+ // m_doc->closeDocument();
+ } else if (m_doc->saveIfModified()) {
+ makeNew = true;
+ }
+
+ if (makeNew) {
+
+ setDocument(new RosegardenGUIDoc(this, m_pluginManager));
+ }
+}
+
+void RosegardenGUIApp::slotOpenDroppedURL(QString url)
+{
+ ProgressDialog::processEvents(); // or else we get a crash because the
+ // track editor is erased too soon - it is the originator of the signal
+ // this slot is connected to.
+
+ if (!m_doc->saveIfModified())
+ return ;
+
+ openURL(KURL(url));
+}
+
+void RosegardenGUIApp::openURL(QString url)
+{
+ RG_DEBUG << "RosegardenGUIApp::openURL: QString " << url << endl;
+ openURL(KURL(url));
+}
+
+void RosegardenGUIApp::openURL(const KURL& url)
+{
+ SetWaitCursor waitCursor;
+
+ QString netFile = url.prettyURL();
+ RG_DEBUG << "RosegardenGUIApp::openURL: KURL " << netFile << endl;
+
+ if (!url.isValid()) {
+ QString string;
+ string = i18n( "Malformed URL\n%1").arg(netFile);
+
+ KMessageBox::sorry(this, string);
+ return ;
+ }
+
+ QString target, caption(url.path());
+
+ if (KIO::NetAccess::download(url, target, this) == false) {
+ KMessageBox::error(this, i18n("Cannot download file %1").arg(url.prettyURL()));
+ return ;
+ }
+
+ RG_DEBUG << "RosegardenGUIApp::openURL: target : " << target << endl;
+
+ if (!m_doc->saveIfModified())
+ return ;
+
+ openFile(target);
+
+ setCaption(caption);
+}
+
+void RosegardenGUIApp::slotFileOpen()
+{
+ slotStatusHelpMsg(i18n("Opening file..."));
+
+ kapp->config()->setGroup(GeneralOptionsConfigGroup);
+
+ QString lastOpenedVersion =
+ kapp->config()->readEntry("Last File Opened Version", "none");
+
+ if (lastOpenedVersion != VERSION) {
+
+ // We haven't opened any files with this version of the
+ // program before. Default to the examples directory.
+
+ QString examplesDir = KGlobal::dirs()->findResource("appdata", "examples/");
+ kapp->config()->setGroup("Recent Dirs");
+ QString recentString = kapp->config()->readEntry("ROSEGARDEN", "");
+ kapp->config()->writeEntry
+ ("ROSEGARDEN", QString("file:%1,%2").arg(examplesDir).arg(recentString));
+ }
+
+ KURL url = KFileDialog::getOpenURL
+ (":ROSEGARDEN",
+ "audio/x-rosegarden audio/x-midi audio/x-rosegarden21", this,
+ i18n("Open File"));
+ if ( url.isEmpty() ) {
+ return ;
+ }
+
+ if (m_doc && !m_doc->saveIfModified())
+ return ;
+
+ kapp->config()->setGroup(GeneralOptionsConfigGroup);
+ kapp->config()->writeEntry("Last File Opened Version", VERSION);
+
+ openURL(url);
+}
+
+void RosegardenGUIApp::slotMerge()
+{
+ KURL url = KFileDialog::getOpenURL
+ (":ROSEGARDEN",
+ "audio/x-rosegarden audio/x-midi audio/x-rosegarden21", this,
+ i18n("Open File"));
+ if ( url.isEmpty() ) {
+ return ;
+ }
+
+
+ QString target;
+
+ if (KIO::NetAccess::download(url, target, this) == false) {
+ KMessageBox::error(this, i18n("Cannot download file %1").arg(url.prettyURL()));
+ return ;
+ }
+
+ mergeFile(target);
+
+ KIO::NetAccess::removeTempFile( target );
+}
+
+void RosegardenGUIApp::slotFileOpenRecent(const KURL &url)
+{
+ KTmpStatusMsg msg(i18n("Opening file..."), this);
+
+ if (m_doc) {
+
+ if (!m_doc->saveIfModified()) {
+ return ;
+
+ }
+ }
+
+ openURL(url);
+}
+
+void RosegardenGUIApp::slotFileSave()
+{
+ if (!m_doc /*|| !m_doc->isModified()*/)
+ return ; // ALWAYS save, even if doc is not modified.
+
+ KTmpStatusMsg msg(i18n("Saving file..."), this);
+
+ // if it's a new file (no file path), or an imported file
+ // (file path doesn't end with .rg), call saveAs
+ //
+ if (!m_doc->isRegularDotRGFile()) {
+
+ slotFileSaveAs();
+
+ } else {
+
+ SetWaitCursor waitCursor;
+ QString errMsg, docFilePath = m_doc->getAbsFilePath();
+
+ bool res = m_doc->saveDocument(docFilePath, errMsg);
+ if (!res) {
+ if (errMsg)
+ KMessageBox::error(this, i18n(QString("Could not save document at %1\nError was : %2")
+ .arg(docFilePath).arg(errMsg)));
+ else
+ KMessageBox::error(this, i18n(QString("Could not save document at %1")
+ .arg(docFilePath)));
+ }
+ }
+}
+
+QString
+RosegardenGUIApp::getValidWriteFile(QString descriptiveExtension,
+ QString label)
+{
+ // extract first extension listed in descriptiveExtension, for instance,
+ // ".rg" from "*.rg|Rosegarden files", or ".mid" from "*.mid *.midi|MIDI Files"
+ //
+ QString extension = descriptiveExtension.left(descriptiveExtension.find('|')).mid(1).section(' ', 0, 0);
+
+ RG_DEBUG << "RosegardenGUIApp::getValidWriteFile() : extension = " << extension << endl;
+
+ // It's too bad there isn't this functionality within
+ // KFileDialog::getSaveFileName
+ KFileDialog saveFileDialog(":ROSEGARDEN", descriptiveExtension, this, label, true);
+ saveFileDialog.setOperationMode(KFileDialog::Saving);
+ if (m_doc) {
+ QString saveFileName = m_doc->getAbsFilePath();
+ // Show filename without the old extension
+ int dotLoc = saveFileName.findRev('.');
+ if (dotLoc >= int(saveFileName.length() - 4)) {
+ saveFileName = saveFileName.left(dotLoc);
+ }
+ saveFileDialog.setSelection(saveFileName);
+ }
+ saveFileDialog.exec();
+ QString name = saveFileDialog.selectedFile();
+
+ // RG_DEBUG << "RosegardenGUIApp::getValidWriteFile() : KFileDialog::getSaveFileName returned "
+ // << name << endl;
+
+
+ if (name.isEmpty())
+ return name;
+
+ // Append extension if we don't have one
+ //
+ if (!extension.isEmpty()) {
+ static QRegExp rgFile("\\..{1,4}$");
+ if (rgFile.match(name) == -1) {
+ name += extension;
+ }
+ }
+
+ KURL *u = new KURL(name);
+
+ if (!u->isValid()) {
+ KMessageBox::sorry(this, i18n("This is not a valid filename.\n"));
+ return "";
+ }
+
+ if (!u->isLocalFile()) {
+ KMessageBox::sorry(this, i18n("This is not a local file.\n"));
+ return "";
+ }
+
+ QFileInfo info(name);
+
+ if (info.isDir()) {
+ KMessageBox::sorry(this, i18n("You have specified a directory"));
+ return "";
+ }
+
+ if (info.exists()) {
+ int overwrite = KMessageBox::questionYesNo
+ (this, i18n("The specified file exists. Overwrite?"));
+
+ if (overwrite != KMessageBox::Yes)
+ return "";
+ }
+
+ return name;
+}
+
+bool RosegardenGUIApp::slotFileSaveAs()
+{
+ if (!m_doc)
+ return false;
+
+ KTmpStatusMsg msg(i18n("Saving file with a new filename..."), this);
+
+ QString newName = getValidWriteFile("*.rg|" + i18n("Rosegarden files") +
+ "\n*|" + i18n("All files"),
+ i18n("Save as..."));
+ if (newName.isEmpty())
+ return false;
+
+ SetWaitCursor waitCursor;
+ QFileInfo saveAsInfo(newName);
+ m_doc->setTitle(saveAsInfo.fileName());
+ m_doc->setAbsFilePath(saveAsInfo.absFilePath());
+ QString errMsg;
+ bool res = m_doc->saveDocument(newName, errMsg);
+ if (!res) {
+ if (errMsg)
+ KMessageBox::error(this, i18n(QString("Could not save document at %1\nError was : %2")
+ .arg(newName).arg(errMsg)));
+ else
+ KMessageBox::error(this, i18n(QString("Could not save document at %1")
+ .arg(newName)));
+
+ } else {
+
+ m_fileRecent->addURL(newName);
+
+ QString caption = kapp->caption();
+ setCaption(caption + ": " + m_doc->getTitle());
+ // update the edit view's captions too
+ emit compositionStateUpdate();
+ }
+
+ return res;
+}
+
+void RosegardenGUIApp::slotFileClose()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotFileClose()" << endl;
+
+ if (!m_doc)
+ return ;
+
+ KTmpStatusMsg msg(i18n("Closing file..."), this);
+
+ if (m_doc->saveIfModified()) {
+ setDocument(new RosegardenGUIDoc(this, m_pluginManager));
+ }
+
+ // Don't close the whole view (i.e. Quit), just close the doc.
+ // close();
+}
+
+void RosegardenGUIApp::slotFilePrint()
+{
+ if (m_doc->getComposition().getNbSegments() == 0) {
+ KMessageBox::sorry(0, "Please create some tracks first (until we implement menu state management)");
+ return ;
+ }
+
+ KTmpStatusMsg msg(i18n("Printing..."), this);
+
+ m_view->print(&m_doc->getComposition());
+}
+
+void RosegardenGUIApp::slotFilePrintPreview()
+{
+ if (m_doc->getComposition().getNbSegments() == 0) {
+ KMessageBox::sorry(0, "Please create some tracks first (until we implement menu state management)");
+ return ;
+ }
+
+ KTmpStatusMsg msg(i18n("Previewing..."), this);
+
+ m_view->print(&m_doc->getComposition(), true);
+}
+
+void RosegardenGUIApp::slotQuit()
+{
+ slotStatusMsg(i18n("Exiting..."));
+
+ Profiles::getInstance()->dump();
+
+ // close the first window, the list makes the next one the first again.
+ // This ensures that queryClose() is called on each window to ask for closing
+ KMainWindow* w;
+ if (memberList) {
+
+ for (w = memberList->first(); w != 0; w = memberList->next()) {
+ // only close the window if the closeEvent is accepted. If
+ // the user presses Cancel on the saveIfModified() dialog,
+ // the window and the application stay open.
+ if (!w->close())
+ break;
+ }
+ }
+}
+
+void RosegardenGUIApp::slotEditCut()
+{
+ if (!m_view->haveSelection())
+ return ;
+ KTmpStatusMsg msg(i18n("Cutting selection..."), this);
+
+ SegmentSelection selection(m_view->getSelection());
+ m_doc->getCommandHistory()->addCommand
+ (new CutCommand(selection, m_clipboard));
+}
+
+void RosegardenGUIApp::slotEditCopy()
+{
+ if (!m_view->haveSelection())
+ return ;
+ KTmpStatusMsg msg(i18n("Copying selection to clipboard..."), this);
+
+ SegmentSelection selection(m_view->getSelection());
+ m_doc->getCommandHistory()->addCommand
+ (new CopyCommand(selection, m_clipboard));
+}
+
+void RosegardenGUIApp::slotEditPaste()
+{
+ if (m_clipboard->isEmpty()) {
+ KTmpStatusMsg msg(i18n("Clipboard is empty"), this);
+ return ;
+ }
+ KTmpStatusMsg msg(i18n("Inserting clipboard contents..."), this);
+
+ // for now, but we could paste at the time of the first copied
+ // segment and then do ghosting drag or something
+ timeT insertionTime = m_doc->getComposition().getPosition();
+ m_doc->getCommandHistory()->addCommand
+ (new PasteSegmentsCommand(&m_doc->getComposition(),
+ m_clipboard, insertionTime,
+ m_doc->getComposition().getSelectedTrack(),
+ false));
+
+ // User preference? Update song pointer position on paste
+ m_doc->slotSetPointerPosition(m_doc->getComposition().getPosition());
+}
+
+void RosegardenGUIApp::slotCutRange()
+{
+ timeT t0 = m_doc->getComposition().getLoopStart();
+ timeT t1 = m_doc->getComposition().getLoopEnd();
+
+ if (t0 == t1)
+ return ;
+
+ m_doc->getCommandHistory()->addCommand
+ (new CutRangeCommand(&m_doc->getComposition(), t0, t1, m_clipboard));
+}
+
+void RosegardenGUIApp::slotCopyRange()
+{
+ timeT t0 = m_doc->getComposition().getLoopStart();
+ timeT t1 = m_doc->getComposition().getLoopEnd();
+
+ if (t0 == t1)
+ return ;
+
+ m_doc->getCommandHistory()->addCommand
+ (new CopyCommand(&m_doc->getComposition(), t0, t1, m_clipboard));
+}
+
+void RosegardenGUIApp::slotPasteRange()
+{
+ if (m_clipboard->isEmpty())
+ return ;
+
+ m_doc->getCommandHistory()->addCommand
+ (new PasteRangeCommand(&m_doc->getComposition(), m_clipboard,
+ m_doc->getComposition().getPosition()));
+
+ m_doc->setLoop(0, 0);
+}
+
+void RosegardenGUIApp::slotDeleteRange()
+{
+ timeT t0 = m_doc->getComposition().getLoopStart();
+ timeT t1 = m_doc->getComposition().getLoopEnd();
+
+ if (t0 == t1)
+ return ;
+
+ m_doc->getCommandHistory()->addCommand
+ (new DeleteRangeCommand(&m_doc->getComposition(), t0, t1));
+
+ m_doc->setLoop(0, 0);
+}
+
+void RosegardenGUIApp::slotInsertRange()
+{
+ timeT t0 = m_doc->getComposition().getPosition();
+ std::pair<timeT, timeT> r = m_doc->getComposition().getBarRangeForTime(t0);
+ TimeDialog dialog(m_view, i18n("Duration of empty range to insert"),
+ &m_doc->getComposition(), t0, r.second - r.first, false);
+ if (dialog.exec() == QDialog::Accepted) {
+ m_doc->getCommandHistory()->addCommand
+ (new InsertRangeCommand(&m_doc->getComposition(), t0, dialog.getTime()));
+ m_doc->setLoop(0, 0);
+ }
+}
+
+void RosegardenGUIApp::slotSelectAll()
+{
+ m_view->slotSelectAllSegments();
+}
+
+void RosegardenGUIApp::slotDeleteSelectedSegments()
+{
+ m_view->getTrackEditor()->slotDeleteSelectedSegments();
+}
+
+void RosegardenGUIApp::slotQuantizeSelection()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ //!!! this should all be in rosegardenguiview
+
+ QuantizeDialog dialog(m_view);
+ if (dialog.exec() != QDialog::Accepted)
+ return ;
+
+ SegmentSelection selection = m_view->getSelection();
+
+ KMacroCommand *command = new KMacroCommand
+ (EventQuantizeCommand::getGlobalName());
+
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+ command->addCommand(new EventQuantizeCommand
+ (**i, (*i)->getStartTime(), (*i)->getEndTime(),
+ dialog.getQuantizer()));
+ }
+
+ m_view->slotAddCommandToHistory(command);
+}
+
+void RosegardenGUIApp::slotRepeatQuantizeSelection()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ //!!! this should all be in rosegardenguiview
+
+ SegmentSelection selection = m_view->getSelection();
+
+ KMacroCommand *command = new KMacroCommand
+ (EventQuantizeCommand::getGlobalName());
+
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+ command->addCommand(new EventQuantizeCommand
+ (**i, (*i)->getStartTime(), (*i)->getEndTime(),
+ "Quantize Dialog Grid", false)); // no i18n (config group name)
+ }
+
+ m_view->slotAddCommandToHistory(command);
+}
+
+void RosegardenGUIApp::slotGrooveQuantize()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ SegmentSelection selection = m_view->getSelection();
+
+ if (selection.size() != 1) {
+ KMessageBox::sorry(this, i18n("This function needs no more than one segment to be selected."));
+ return ;
+ }
+
+ Segment *s = *selection.begin();
+ m_view->slotAddCommandToHistory(new CreateTempoMapFromSegmentCommand(s));
+}
+
+void RosegardenGUIApp::slotJoinSegments()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ //!!! this should all be in rosegardenguiview
+ //!!! should it?
+
+ SegmentSelection selection = m_view->getSelection();
+ if (selection.size() == 0)
+ return ;
+
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+ if ((*i)->getType() != Segment::Internal) {
+ KMessageBox::sorry(this, i18n("Can't join Audio segments"));
+ return ;
+ }
+ }
+
+ m_view->slotAddCommandToHistory(new SegmentJoinCommand(selection));
+ m_view->updateSelectionContents();
+}
+
+void RosegardenGUIApp::slotRescaleSelection()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ //!!! this should all be in rosegardenguiview
+ //!!! should it?
+
+ SegmentSelection selection = m_view->getSelection();
+
+ timeT startTime = 0, endTime = 0;
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+ if ((i == selection.begin()) || ((*i)->getStartTime() < startTime)) {
+ startTime = (*i)->getStartTime();
+ }
+ if ((i == selection.begin()) || ((*i)->getEndMarkerTime() > endTime)) {
+ endTime = (*i)->getEndMarkerTime();
+ }
+ }
+
+ RescaleDialog dialog(m_view, &m_doc->getComposition(),
+ startTime, endTime - startTime,
+ false, false);
+ if (dialog.exec() != QDialog::Accepted)
+ return ;
+
+ std::vector<AudioSegmentRescaleCommand *> asrcs;
+
+ int mult = dialog.getNewDuration();
+ int div = endTime - startTime;
+ float ratio = float(mult) / float(div);
+
+ std::cerr << "slotRescaleSelection: mult = " << mult << ", div = " << div << ", ratio = " << ratio << std::endl;
+
+ KMacroCommand *command = new KMacroCommand
+ (SegmentRescaleCommand::getGlobalName());
+
+ bool pathTested = false;
+
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+ if ((*i)->getType() == Segment::Audio) {
+ if (!pathTested) {
+ testAudioPath(i18n("rescaling an audio file"));
+ pathTested = true;
+ }
+ AudioSegmentRescaleCommand *asrc = new AudioSegmentRescaleCommand
+ (m_doc, *i, ratio);
+ command->addCommand(asrc);
+ asrcs.push_back(asrc);
+ } else {
+ command->addCommand(new SegmentRescaleCommand(*i, mult, div));
+ }
+ }
+
+ ProgressDialog *progressDlg = 0;
+
+ if (!asrcs.empty()) {
+ progressDlg = new ProgressDialog
+ (i18n("Rescaling audio file..."), 100, this);
+ progressDlg->setAutoClose(false);
+ progressDlg->setAutoReset(false);
+ progressDlg->show();
+ for (size_t i = 0; i < asrcs.size(); ++i) {
+ asrcs[i]->connectProgressDialog(progressDlg);
+ }
+ }
+
+ m_view->slotAddCommandToHistory(command);
+
+ if (!asrcs.empty()) {
+
+ progressDlg->setLabel(i18n("Generating audio preview..."));
+
+ for (size_t i = 0; i < asrcs.size(); ++i) {
+ asrcs[i]->disconnectProgressDialog(progressDlg);
+ }
+
+ connect(&m_doc->getAudioFileManager(), SIGNAL(setProgress(int)),
+ progressDlg->progressBar(), SLOT(setValue(int)));
+ connect(progressDlg, SIGNAL(cancelClicked()),
+ &m_doc->getAudioFileManager(), SLOT(slotStopPreview()));
+
+ for (size_t i = 0; i < asrcs.size(); ++i) {
+ int fid = asrcs[i]->getNewAudioFileId();
+ if (fid >= 0) {
+ slotAddAudioFile(fid);
+ m_doc->getAudioFileManager().generatePreview(fid);
+ }
+ }
+ }
+
+ if (progressDlg) delete progressDlg;
+}
+
+bool
+RosegardenGUIApp::testAudioPath(QString op)
+{
+ try {
+ m_doc->getAudioFileManager().testAudioPath();
+ } catch (AudioFileManager::BadAudioPathException) {
+ if (KMessageBox::warningContinueCancel
+ (this,
+ i18n("The audio file path does not exist or is not writable.\nYou must set the audio file path to a valid directory in Document Properties before %1.\nWould you like to set it now?").arg(op),
+ i18n("Warning"),
+ i18n("Set audio file path")) == KMessageBox::Continue) {
+ slotOpenAudioPathSettings();
+ }
+ return false;
+ }
+ return true;
+}
+
+void RosegardenGUIApp::slotAutoSplitSelection()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ //!!! this should all be in rosegardenguiview
+ //!!! or should it?
+
+ SegmentSelection selection = m_view->getSelection();
+
+ KMacroCommand *command = new KMacroCommand
+ (SegmentAutoSplitCommand::getGlobalName());
+
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+
+ if ((*i)->getType() == Segment::Audio) {
+ AudioSplitDialog aSD(this, (*i), m_doc);
+
+ if (aSD.exec() == QDialog::Accepted) {
+ // split to threshold
+ //
+ command->addCommand(
+ new AudioSegmentAutoSplitCommand(m_doc,
+ *i,
+ aSD.getThreshold()));
+ // dmm - verifying that widget->value() accessors *can* work without crashing
+ // std::cout << "SILVAN: getThreshold() = " << aSD.getThreshold() << std::endl;
+ }
+ } else {
+ command->addCommand(new SegmentAutoSplitCommand(*i));
+ }
+ }
+
+ m_view->slotAddCommandToHistory(command);
+}
+
+void RosegardenGUIApp::slotJogLeft()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotJogLeft" << endl;
+ jogSelection( -Note(Note::Demisemiquaver).getDuration());
+}
+
+void RosegardenGUIApp::slotJogRight()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotJogRight" << endl;
+ jogSelection(Note(Note::Demisemiquaver).getDuration());
+}
+
+void RosegardenGUIApp::jogSelection(timeT amount)
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ SegmentSelection selection = m_view->getSelection();
+
+ SegmentReconfigureCommand *command = new SegmentReconfigureCommand(i18n("Jog Selection"));
+
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+
+ command->addSegment((*i),
+ (*i)->getStartTime() + amount,
+ (*i)->getEndMarkerTime() + amount,
+ (*i)->getTrack());
+ }
+
+ m_view->slotAddCommandToHistory(command);
+}
+
+void RosegardenGUIApp::createAndSetupTransport()
+{
+ // create the Transport GUI and add the callbacks to the
+ // buttons and keyboard accelerators
+ //
+ m_transport =
+ new TransportDialog(this);
+ plugAccelerators(m_transport, m_transport->getAccelerators());
+
+ m_transport->getAccelerators()->connectItem
+ (m_transport->getAccelerators()->insertItem(Key_T),
+ this,
+ SLOT(slotHideTransport()));
+
+ // Ensure that the checkbox is unchecked if the dialog
+ // is closed
+ connect(m_transport, SIGNAL(closed()),
+ SLOT(slotCloseTransport()));
+
+ // Handle loop setting and unsetting from the transport loop button
+ //
+
+ connect(m_transport, SIGNAL(setLoop()), SLOT(slotSetLoop()));
+ connect(m_transport, SIGNAL(unsetLoop()), SLOT(slotUnsetLoop()));
+ connect(m_transport, SIGNAL(panic()), SLOT(slotPanic()));
+
+ connect(m_transport, SIGNAL(editTempo(QWidget*)),
+ SLOT(slotEditTempo(QWidget*)));
+
+ connect(m_transport, SIGNAL(editTimeSignature(QWidget*)),
+ SLOT(slotEditTimeSignature(QWidget*)));
+
+ connect(m_transport, SIGNAL(editTransportTime(QWidget*)),
+ SLOT(slotEditTransportTime(QWidget*)));
+
+ // Handle set loop start/stop time buttons.
+ //
+ connect(m_transport, SIGNAL(setLoopStartTime()), SLOT(slotSetLoopStart()));
+ connect(m_transport, SIGNAL(setLoopStopTime()), SLOT(slotSetLoopStop()));
+
+ if (m_seqManager != 0)
+ m_seqManager->setTransport(m_transport);
+
+}
+
+void RosegardenGUIApp::slotSplitSelectionByPitch()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ SplitByPitchDialog dialog(m_view);
+ if (dialog.exec() != QDialog::Accepted)
+ return ;
+
+ SegmentSelection selection = m_view->getSelection();
+
+ KMacroCommand *command = new KMacroCommand
+ (SegmentSplitByPitchCommand::getGlobalName());
+
+ bool haveSomething = false;
+
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+
+ if ((*i)->getType() == Segment::Audio) {
+ // nothing
+ } else {
+ command->addCommand
+ (new SegmentSplitByPitchCommand
+ (*i,
+ dialog.getPitch(),
+ dialog.getShouldRange(),
+ dialog.getShouldDuplicateNonNoteEvents(),
+ (SegmentSplitByPitchCommand::ClefHandling)
+ dialog.getClefHandling()));
+ haveSomething = true;
+ }
+ }
+
+ if (haveSomething)
+ m_view->slotAddCommandToHistory(command);
+ //!!! else complain
+}
+
+void
+RosegardenGUIApp::slotSplitSelectionByRecordedSrc()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ SplitByRecordingSrcDialog dialog(m_view, m_doc);
+ if (dialog.exec() != QDialog::Accepted)
+ return ;
+
+ SegmentSelection selection = m_view->getSelection();
+
+ KMacroCommand *command = new KMacroCommand
+ (SegmentSplitByRecordingSrcCommand::getGlobalName());
+
+ bool haveSomething = false;
+
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+
+ if ((*i)->getType() == Segment::Audio) {
+ // nothing
+ } else {
+ command->addCommand
+ (new SegmentSplitByRecordingSrcCommand(*i,
+ dialog.getChannel(),
+ dialog.getDevice()));
+ haveSomething = true;
+ }
+ }
+ if (haveSomething)
+ m_view->slotAddCommandToHistory(command);
+}
+
+void
+RosegardenGUIApp::slotSplitSelectionAtTime()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ SegmentSelection selection = m_view->getSelection();
+ if (selection.empty())
+ return ;
+
+ timeT now = m_doc->getComposition().getPosition();
+
+ QString title = i18n("Split Segment at Time",
+ "Split %n Segments at Time",
+ selection.size());
+
+ TimeDialog dialog(m_view, title,
+ &m_doc->getComposition(),
+ now, true);
+
+ KMacroCommand *command = new KMacroCommand( title );
+
+ if (dialog.exec() == QDialog::Accepted) {
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+
+ if ((*i)->getType() == Segment::Audio) {
+ command->addCommand(new AudioSegmentSplitCommand(*i, dialog.getTime()));
+ } else {
+ command->addCommand(new SegmentSplitCommand(*i, dialog.getTime()));
+ }
+ }
+ m_view->slotAddCommandToHistory(command);
+ }
+}
+
+void
+RosegardenGUIApp::slotSetSegmentStartTimes()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ SegmentSelection selection = m_view->getSelection();
+ if (selection.empty())
+ return ;
+
+ timeT someTime = (*selection.begin())->getStartTime();
+
+ TimeDialog dialog(m_view, i18n("Segment Start Time"),
+ &m_doc->getComposition(),
+ someTime, false);
+
+ if (dialog.exec() == QDialog::Accepted) {
+
+ bool plural = (selection.size() > 1);
+
+ SegmentReconfigureCommand *command =
+ new SegmentReconfigureCommand(plural ?
+ i18n("Set Segment Start Times") :
+ i18n("Set Segment Start Time"));
+
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+
+ command->addSegment
+ (*i, dialog.getTime(),
+ (*i)->getEndMarkerTime() - (*i)->getStartTime() + dialog.getTime(),
+ (*i)->getTrack());
+ }
+
+ m_view->slotAddCommandToHistory(command);
+ }
+}
+
+void
+RosegardenGUIApp::slotSetSegmentDurations()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ SegmentSelection selection = m_view->getSelection();
+ if (selection.empty())
+ return ;
+
+ timeT someTime =
+ (*selection.begin())->getStartTime();
+
+ timeT someDuration =
+ (*selection.begin())->getEndMarkerTime() -
+ (*selection.begin())->getStartTime();
+
+ TimeDialog dialog(m_view, i18n("Segment Duration"),
+ &m_doc->getComposition(),
+ someTime,
+ someDuration,
+ false);
+
+ if (dialog.exec() == QDialog::Accepted) {
+
+ bool plural = (selection.size() > 1);
+
+ SegmentReconfigureCommand *command =
+ new SegmentReconfigureCommand(plural ?
+ i18n("Set Segment Durations") :
+ i18n("Set Segment Duration"));
+
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+
+ command->addSegment
+ (*i, (*i)->getStartTime(),
+ (*i)->getStartTime() + dialog.getTime(),
+ (*i)->getTrack());
+ }
+
+ m_view->slotAddCommandToHistory(command);
+ }
+}
+
+void RosegardenGUIApp::slotHarmonizeSelection()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ SegmentSelection selection = m_view->getSelection();
+ //!!! This should be somewhere else too
+
+ CompositionTimeSliceAdapter adapter(&m_doc->getComposition(),
+ &selection);
+
+ AnalysisHelper helper;
+ Segment *segment = new Segment;
+ helper.guessHarmonies(adapter, *segment);
+
+ //!!! do nothing with the results yet
+ delete segment;
+}
+
+void RosegardenGUIApp::slotTempoToSegmentLength()
+{
+ slotTempoToSegmentLength(this);
+}
+
+void RosegardenGUIApp::slotTempoToSegmentLength(QWidget* parent)
+{
+ RG_DEBUG << "RosegardenGUIApp::slotTempoToSegmentLength" << endl;
+
+ if (!m_view->haveSelection())
+ return ;
+
+ SegmentSelection selection = m_view->getSelection();
+
+ // Only set for a single selection
+ //
+ if (selection.size() == 1 &&
+ (*selection.begin())->getType() == Segment::Audio) {
+ Composition &comp = m_doc->getComposition();
+ Segment *seg = *selection.begin();
+
+ TimeSignature timeSig =
+ comp.getTimeSignatureAt( seg->getStartTime());
+
+ timeT endTime = seg->getEndTime();
+
+ if (seg->getRawEndMarkerTime())
+ endTime = seg->getEndMarkerTime();
+
+ RealTime segDuration =
+ seg->getAudioEndTime() - seg->getAudioStartTime();
+
+ int beats = 0;
+
+ // Get user to tell us how many beats or bars the segment contains
+ BeatsBarsDialog dialog(parent);
+ if (dialog.exec() == QDialog::Accepted) {
+ beats = dialog.getQuantity(); // beats (or bars)
+ if (dialog.getMode() == 1) // bars (multiply by time sig)
+ beats *= timeSig.getBeatsPerBar();
+#ifdef DEBUG_TEMPO_FROM_AUDIO
+
+ RG_DEBUG << "RosegardenGUIApp::slotTempoToSegmentLength - beats = " << beats
+ << " mode = " << ((dialog.getMode() == 0) ? "bars" : "beats") << endl
+ << " beats per bar = " << timeSig.getBeatsPerBar()
+ << " user quantity = " << dialog.getQuantity()
+ << " user mode = " << dialog.getMode() << endl;
+#endif
+
+ } else {
+ RG_DEBUG << "RosegardenGUIApp::slotTempoToSegmentLength - BeatsBarsDialog aborted"
+ << endl;
+ return ;
+ }
+
+ double beatLengthUsec =
+ double(segDuration.sec * 1000000 + segDuration.usec()) /
+ double(beats);
+
+ // New tempo is a minute divided by time of beat
+ // converted up (#1414252) to a sane value via getTempoFoQpm()
+ //
+ tempoT newTempo =
+ comp.getTempoForQpm(60.0 * 1000000.0 / beatLengthUsec);
+
+#ifdef DEBUG_TEMPO_FROM_AUDIO
+
+ RG_DEBUG << "RosegardenGUIApp::slotTempoToSegmentLength info: " << endl
+ << " beatLengthUsec = " << beatLengthUsec << endl
+ << " segDuration.usec = " << segDuration.usec() << endl
+ << " newTempo = " << newTempo << endl;
+#endif
+
+ KMacroCommand *macro = new KMacroCommand(i18n("Set Global Tempo"));
+
+ // Remove all tempo changes in reverse order so as the index numbers
+ // don't becoming meaningless as the command gets unwound.
+ //
+ for (int i = 0; i < comp.getTempoChangeCount(); i++)
+ macro->addCommand(new RemoveTempoChangeCommand(&comp,
+ (comp.getTempoChangeCount() - 1 - i)));
+
+ // add tempo change at time zero
+ //
+ macro->addCommand(new AddTempoChangeCommand(&comp, 0, newTempo));
+
+ // execute
+ m_doc->getCommandHistory()->addCommand(macro);
+ }
+}
+
+void RosegardenGUIApp::slotToggleSegmentLabels()
+{
+ KToggleAction* act = dynamic_cast<KToggleAction*>(actionCollection()->action("show_segment_labels"));
+ if (act) {
+ m_view->slotShowSegmentLabels(act->isChecked());
+ }
+}
+
+void RosegardenGUIApp::slotEdit()
+{
+ m_view->slotEditSegment(0);
+}
+
+void RosegardenGUIApp::slotEditAsNotation()
+{
+ m_view->slotEditSegmentNotation(0);
+}
+
+void RosegardenGUIApp::slotEditInMatrix()
+{
+ m_view->slotEditSegmentMatrix(0);
+}
+
+void RosegardenGUIApp::slotEditInPercussionMatrix()
+{
+ m_view->slotEditSegmentPercussionMatrix(0);
+}
+
+void RosegardenGUIApp::slotEditInEventList()
+{
+ m_view->slotEditSegmentEventList(0);
+}
+
+void RosegardenGUIApp::slotEditTempos()
+{
+ slotEditTempos(m_doc->getComposition().getPosition());
+}
+
+void RosegardenGUIApp::slotToggleToolBar()
+{
+ KTmpStatusMsg msg(i18n("Toggle the toolbar..."), this);
+
+ if (m_viewToolBar->isChecked())
+ toolBar("mainToolBar")->show();
+ else
+ toolBar("mainToolBar")->hide();
+}
+
+void RosegardenGUIApp::slotToggleToolsToolBar()
+{
+ KTmpStatusMsg msg(i18n("Toggle the tools toolbar..."), this);
+
+ if (m_viewToolsToolBar->isChecked())
+ toolBar("Tools Toolbar")->show();
+ else
+ toolBar("Tools Toolbar")->hide();
+}
+
+void RosegardenGUIApp::slotToggleTracksToolBar()
+{
+ KTmpStatusMsg msg(i18n("Toggle the tracks toolbar..."), this);
+
+ if (m_viewTracksToolBar->isChecked())
+ toolBar("Tracks Toolbar")->show();
+ else
+ toolBar("Tracks Toolbar")->hide();
+}
+
+void RosegardenGUIApp::slotToggleEditorsToolBar()
+{
+ KTmpStatusMsg msg(i18n("Toggle the editor toolbar..."), this);
+
+ if (m_viewEditorsToolBar->isChecked())
+ toolBar("Editors Toolbar")->show();
+ else
+ toolBar("Editors Toolbar")->hide();
+}
+
+void RosegardenGUIApp::slotToggleTransportToolBar()
+{
+ KTmpStatusMsg msg(i18n("Toggle the transport toolbar..."), this);
+
+ if (m_viewTransportToolBar->isChecked())
+ toolBar("Transport Toolbar")->show();
+ else
+ toolBar("Transport Toolbar")->hide();
+}
+
+void RosegardenGUIApp::slotToggleZoomToolBar()
+{
+ KTmpStatusMsg msg(i18n("Toggle the zoom toolbar..."), this);
+
+ if (m_viewZoomToolBar->isChecked())
+ toolBar("Zoom Toolbar")->show();
+ else
+ toolBar("Zoom Toolbar")->hide();
+}
+
+void RosegardenGUIApp::slotToggleTransport()
+{
+ KTmpStatusMsg msg(i18n("Toggle the Transport"), this);
+
+ if (m_viewTransport->isChecked()) {
+ getTransport()->show();
+ getTransport()->raise();
+ getTransport()->blockSignals(false);
+ } else {
+ getTransport()->hide();
+ getTransport()->blockSignals(true);
+ }
+}
+
+void RosegardenGUIApp::slotHideTransport()
+{
+ if (m_viewTransport->isChecked()) {
+ m_viewTransport->blockSignals(true);
+ m_viewTransport->setChecked(false);
+ m_viewTransport->blockSignals(false);
+ }
+ getTransport()->hide();
+ getTransport()->blockSignals(true);
+}
+
+void RosegardenGUIApp::slotToggleTrackLabels()
+{
+ if (m_viewTrackLabels->isChecked()) {
+#ifdef SETTING_LOG_DEBUG
+ _settingLog("toggle track labels on");
+#endif
+
+ m_view->getTrackEditor()->getTrackButtons()->
+ changeTrackInstrumentLabels(TrackLabel::ShowTrack);
+ } else {
+#ifdef SETTING_LOG_DEBUG
+ _settingLog("toggle track labels off");
+#endif
+
+ m_view->getTrackEditor()->getTrackButtons()->
+ changeTrackInstrumentLabels(TrackLabel::ShowInstrument);
+ }
+}
+
+void RosegardenGUIApp::slotToggleRulers()
+{
+ m_view->slotShowRulers(m_viewRulers->isChecked());
+}
+
+void RosegardenGUIApp::slotToggleTempoRuler()
+{
+ m_view->slotShowTempoRuler(m_viewTempoRuler->isChecked());
+}
+
+void RosegardenGUIApp::slotToggleChordNameRuler()
+{
+ m_view->slotShowChordNameRuler(m_viewChordNameRuler->isChecked());
+}
+
+void RosegardenGUIApp::slotTogglePreviews()
+{
+ m_view->slotShowPreviews(m_viewPreviews->isChecked());
+}
+
+void RosegardenGUIApp::slotDockParametersBack()
+{
+ m_dockLeft->dockBack();
+}
+
+void RosegardenGUIApp::slotParametersClosed()
+{
+ stateChanged("parametersbox_closed");
+ m_dockVisible = false;
+}
+
+void RosegardenGUIApp::slotParametersDockedBack(KDockWidget* dw, KDockWidget::DockPosition)
+{
+ if (dw == m_dockLeft) {
+ stateChanged("parametersbox_closed", KXMLGUIClient::StateReverse);
+ m_dockVisible = true;
+ }
+}
+
+void RosegardenGUIApp::slotToggleStatusBar()
+{
+ KTmpStatusMsg msg(i18n("Toggle the statusbar..."), this);
+
+ if (!m_viewStatusBar->isChecked())
+ statusBar()->hide();
+ else
+ statusBar()->show();
+}
+
+void RosegardenGUIApp::slotStatusMsg(QString text)
+{
+ ///////////////////////////////////////////////////////////////////
+ // change status message permanently
+ statusBar()->clear();
+ statusBar()->changeItem(text, EditViewBase::ID_STATUS_MSG);
+}
+
+void RosegardenGUIApp::slotStatusHelpMsg(QString text)
+{
+ ///////////////////////////////////////////////////////////////////
+ // change status message of whole statusbar temporary (text, msec)
+ statusBar()->message(text, 2000);
+}
+
+void RosegardenGUIApp::slotEnableTransport(bool enable)
+{
+ if (m_transport)
+ getTransport()->setEnabled(enable);
+}
+
+void RosegardenGUIApp::slotPointerSelected()
+{
+ m_view->selectTool(SegmentSelector::ToolName);
+}
+
+void RosegardenGUIApp::slotEraseSelected()
+{
+ m_view->selectTool(SegmentEraser::ToolName);
+}
+
+void RosegardenGUIApp::slotDrawSelected()
+{
+ m_view->selectTool(SegmentPencil::ToolName);
+}
+
+void RosegardenGUIApp::slotMoveSelected()
+{
+ m_view->selectTool(SegmentMover::ToolName);
+}
+
+void RosegardenGUIApp::slotResizeSelected()
+{
+ m_view->selectTool(SegmentResizer::ToolName);
+}
+
+void RosegardenGUIApp::slotJoinSelected()
+{
+ KMessageBox::information(this,
+ i18n("The join tool isn't implemented yet. Instead please highlight "
+ "the segments you want to join and then use the menu option:\n\n"
+ " Segments->Collapse Segments.\n"),
+ i18n("Join tool not yet implemented"));
+
+ m_view->selectTool(SegmentJoiner::ToolName);
+}
+
+void RosegardenGUIApp::slotSplitSelected()
+{
+ m_view->selectTool(SegmentSplitter::ToolName);
+}
+
+void RosegardenGUIApp::slotAddTrack()
+{
+ if (!m_view)
+ return ;
+
+ // default to the base number - might not actually exist though
+ //
+ InstrumentId id = MidiInstrumentBase;
+
+ // Get the first Internal/MIDI instrument
+ //
+ DeviceList *devices = m_doc->getStudio().getDevices();
+ bool have = false;
+
+ for (DeviceList::iterator it = devices->begin();
+ it != devices->end() && !have; it++) {
+
+ if ((*it)->getType() != Device::Midi)
+ continue;
+
+ InstrumentList instruments = (*it)->getAllInstruments();
+ for (InstrumentList::iterator iit = instruments.begin();
+ iit != instruments.end(); iit++) {
+
+ if ((*iit)->getId() >= MidiInstrumentBase) {
+ id = (*iit)->getId();
+ have = true;
+ break;
+ }
+ }
+ }
+
+ Composition &comp = m_doc->getComposition();
+ TrackId trackId = comp.getSelectedTrack();
+ Track *track = comp.getTrackById(trackId);
+
+ int pos = -1;
+ if (track) pos = track->getPosition() + 1;
+
+ m_view->slotAddTracks(1, id, pos);
+}
+
+void RosegardenGUIApp::slotAddTracks()
+{
+ if (!m_view)
+ return ;
+
+ // default to the base number - might not actually exist though
+ //
+ InstrumentId id = MidiInstrumentBase;
+
+ // Get the first Internal/MIDI instrument
+ //
+ DeviceList *devices = m_doc->getStudio().getDevices();
+ bool have = false;
+
+ for (DeviceList::iterator it = devices->begin();
+ it != devices->end() && !have; it++) {
+
+ if ((*it)->getType() != Device::Midi)
+ continue;
+
+ InstrumentList instruments = (*it)->getAllInstruments();
+ for (InstrumentList::iterator iit = instruments.begin();
+ iit != instruments.end(); iit++) {
+
+ if ((*iit)->getId() >= MidiInstrumentBase) {
+ id = (*iit)->getId();
+ have = true;
+ break;
+ }
+ }
+ }
+
+ Composition &comp = m_doc->getComposition();
+ TrackId trackId = comp.getSelectedTrack();
+ Track *track = comp.getTrackById(trackId);
+
+ int pos = 0;
+ if (track) pos = track->getPosition();
+
+ bool ok = false;
+
+ AddTracksDialog dialog(this, pos);
+
+ if (dialog.exec() == QDialog::Accepted) {
+ m_view->slotAddTracks(dialog.getTracks(), id,
+ dialog.getInsertPosition());
+ }
+}
+
+void RosegardenGUIApp::slotDeleteTrack()
+{
+ if (!m_view)
+ return ;
+
+ Composition &comp = m_doc->getComposition();
+ TrackId trackId = comp.getSelectedTrack();
+ Track *track = comp.getTrackById(trackId);
+
+ RG_DEBUG << "RosegardenGUIApp::slotDeleteTrack() : about to delete track id "
+ << trackId << endl;
+
+ if (track == 0)
+ return ;
+
+ // Always have at least one track in a composition
+ //
+ if (comp.getNbTracks() == 1)
+ return ;
+
+ // VLADA
+ if (m_view->haveSelection()) {
+
+ SegmentSelection selection = m_view->getSelection();
+ m_view->slotSelectTrackSegments(trackId);
+ m_view->getTrackEditor()->slotDeleteSelectedSegments();
+ m_view->slotPropagateSegmentSelection(selection);
+
+ } else {
+
+ m_view->slotSelectTrackSegments(trackId);
+ m_view->getTrackEditor()->slotDeleteSelectedSegments();
+ }
+ //VLADA
+
+ int position = track->getPosition();
+
+ // Delete the track
+ //
+ std::vector<TrackId> tracks;
+ tracks.push_back(trackId);
+
+ m_view->slotDeleteTracks(tracks);
+
+ // Select a new valid track
+ //
+ if (comp.getTrackByPosition(position))
+ trackId = comp.getTrackByPosition(position)->getId();
+ else if (comp.getTrackByPosition(position - 1))
+ trackId = comp.getTrackByPosition(position - 1)->getId();
+ else {
+ RG_DEBUG << "RosegardenGUIApp::slotDeleteTrack - "
+ << "can't select a highlighted track after delete"
+ << endl;
+ }
+
+ comp.setSelectedTrack(trackId);
+
+ Instrument *inst = m_doc->getStudio().
+ getInstrumentById(comp.getTrackById(trackId)->getInstrument());
+
+ //VLADA
+ // m_view->slotSelectTrackSegments(trackId);
+ //VLADA
+}
+
+void RosegardenGUIApp::slotMoveTrackDown()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotMoveTrackDown" << endl;
+
+ Composition &comp = m_doc->getComposition();
+ Track *srcTrack = comp.getTrackById(comp.getSelectedTrack());
+
+ // Check for track object
+ //
+ if (srcTrack == 0)
+ return ;
+
+ // Check destination track exists
+ //
+ Track *destTrack =
+ comp.getTrackByPosition(srcTrack->getPosition() + 1);
+
+ if (destTrack == 0)
+ return ;
+
+ MoveTracksCommand *command =
+ new MoveTracksCommand(&comp, srcTrack->getId(), destTrack->getId());
+
+ m_doc->getCommandHistory()->addCommand(command);
+
+ // make sure we're showing the right selection
+ m_view->slotSelectTrackSegments(comp.getSelectedTrack());
+
+}
+
+void RosegardenGUIApp::slotMoveTrackUp()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotMoveTrackUp" << endl;
+
+ Composition &comp = m_doc->getComposition();
+ Track *srcTrack = comp.getTrackById(comp.getSelectedTrack());
+
+ // Check for track object
+ //
+ if (srcTrack == 0)
+ return ;
+
+ // Check we're not at the top already
+ //
+ if (srcTrack->getPosition() == 0)
+ return ;
+
+ // Check destination track exists
+ //
+ Track *destTrack =
+ comp.getTrackByPosition(srcTrack->getPosition() - 1);
+
+ if (destTrack == 0)
+ return ;
+
+ MoveTracksCommand *command =
+ new MoveTracksCommand(&comp, srcTrack->getId(), destTrack->getId());
+
+ m_doc->getCommandHistory()->addCommand(command);
+
+ // make sure we're showing the right selection
+ m_view->slotSelectTrackSegments(comp.getSelectedTrack());
+}
+
+void RosegardenGUIApp::slotRevertToSaved()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotRevertToSaved" << endl;
+
+ if (m_doc->isModified()) {
+ int revert =
+ KMessageBox::questionYesNo(this,
+ i18n("Revert modified document to previous saved version?"));
+
+ if (revert == KMessageBox::No)
+ return ;
+
+ openFile(m_doc->getAbsFilePath());
+ }
+}
+
+void RosegardenGUIApp::slotImportProject()
+{
+ if (m_doc && !m_doc->saveIfModified())
+ return ;
+
+ KURL url = KFileDialog::getOpenURL
+ (":RGPROJECT",
+ i18n("*.rgp|Rosegarden Project files\n*|All files"), this,
+ i18n("Import Rosegarden Project File"));
+ if (url.isEmpty()) {
+ return ;
+ }
+
+ QString tmpfile;
+ KIO::NetAccess::download(url, tmpfile, this);
+
+ importProject(tmpfile);
+
+ KIO::NetAccess::removeTempFile(tmpfile);
+}
+
+void RosegardenGUIApp::importProject(QString filePath)
+{
+ KProcess *proc = new KProcess;
+ *proc << "rosegarden-project-package";
+ *proc << "--unpack";
+ *proc << filePath;
+
+ KStartupLogo::hideIfStillThere();
+ proc->start(KProcess::Block, KProcess::All);
+
+ if (!proc->normalExit() || proc->exitStatus()) {
+ CurrentProgressDialog::freeze();
+ KMessageBox::sorry(this, i18n("Failed to import project file \"%1\"").arg(filePath));
+ CurrentProgressDialog::thaw();
+ delete proc;
+ return ;
+ }
+
+ delete proc;
+
+ QString rgFile = filePath;
+ rgFile.replace(QRegExp(".rg.rgp$"), ".rg");
+ rgFile.replace(QRegExp(".rgp$"), ".rg");
+ openURL(rgFile);
+}
+
+void RosegardenGUIApp::slotImportMIDI()
+{
+ if (m_doc && !m_doc->saveIfModified())
+ return ;
+
+ KURL url = KFileDialog::getOpenURL
+ (":MIDI",
+ "audio/x-midi", this,
+ i18n("Open MIDI File"));
+ if (url.isEmpty()) {
+ return ;
+ }
+
+ QString tmpfile;
+ KIO::NetAccess::download(url, tmpfile, this);
+ openFile(tmpfile, ImportMIDI); // does everything including setting the document
+
+ KIO::NetAccess::removeTempFile( tmpfile );
+}
+
+void RosegardenGUIApp::slotMergeMIDI()
+{
+ KURL url = KFileDialog::getOpenURL
+ (":MIDI",
+ "audio/x-midi", this,
+ i18n("Merge MIDI File"));
+ if (url.isEmpty()) {
+ return ;
+ }
+
+ QString tmpfile;
+ KIO::NetAccess::download(url, tmpfile, this);
+ mergeFile(tmpfile, ImportMIDI);
+
+ KIO::NetAccess::removeTempFile( tmpfile );
+}
+
+QTextCodec *
+RosegardenGUIApp::guessTextCodec(std::string text)
+{
+ QTextCodec *codec = 0;
+
+ for (int c = 0; c < text.length(); ++c) {
+ if (text[c] & 0x80) {
+
+ CurrentProgressDialog::freeze();
+ KStartupLogo::hideIfStillThere();
+
+ IdentifyTextCodecDialog dialog(0, text);
+ dialog.exec();
+
+ std::string codecName = dialog.getCodec();
+
+ CurrentProgressDialog::thaw();
+
+ if (codecName != "") {
+ codec = QTextCodec::codecForName(codecName.c_str());
+ }
+ break;
+ }
+ }
+
+ return codec;
+}
+
+void
+RosegardenGUIApp::fixTextEncodings(Composition *c)
+
+{
+ QTextCodec *codec = 0;
+
+ for (Composition::iterator i = c->begin();
+ i != c->end(); ++i) {
+
+ for (Segment::iterator j = (*i)->begin();
+ j != (*i)->end(); ++j) {
+
+ if ((*j)->isa(Text::EventType)) {
+
+ std::string text;
+
+ if ((*j)->get
+ <String>
+ (Text::TextPropertyName, text)) {
+
+ if (!codec)
+ codec = guessTextCodec(text);
+
+ if (codec) {
+ (*j)->set
+ <String>
+ (Text::TextPropertyName,
+ convertFromCodec(text, codec));
+ }
+ }
+ }
+ }
+ }
+
+ if (!codec)
+ codec = guessTextCodec(c->getCopyrightNote());
+ if (codec)
+ c->setCopyrightNote(convertFromCodec(c->getCopyrightNote(), codec));
+
+ for (Composition::trackcontainer::iterator i =
+ c->getTracks().begin(); i != c->getTracks().end(); ++i) {
+ if (!codec)
+ codec = guessTextCodec(i->second->getLabel());
+ if (codec)
+ i->second->setLabel(convertFromCodec(i->second->getLabel(), codec));
+ }
+
+ for (Composition::iterator i = c->begin(); i != c->end(); ++i) {
+ if (!codec)
+ codec = guessTextCodec((*i)->getLabel());
+ if (codec)
+ (*i)->setLabel(convertFromCodec((*i)->getLabel(), codec));
+ }
+}
+
+RosegardenGUIDoc*
+RosegardenGUIApp::createDocumentFromMIDIFile(QString file)
+{
+ //if (!merge && !m_doc->saveIfModified()) return;
+
+ // Create new document (autoload is inherent)
+ //
+ RosegardenGUIDoc *newDoc = new RosegardenGUIDoc(this, m_pluginManager);
+
+ std::string fname(QFile::encodeName(file));
+
+ MidiFile midiFile(fname,
+ &newDoc->getStudio());
+
+ KStartupLogo::hideIfStillThere();
+ ProgressDialog progressDlg(i18n("Importing MIDI file..."),
+ 200,
+ this);
+
+ CurrentProgressDialog::set
+ (&progressDlg);
+
+ connect(&midiFile, SIGNAL(setProgress(int)),
+ progressDlg.progressBar(), SLOT(setValue(int)));
+
+ connect(&midiFile, SIGNAL(incrementProgress(int)),
+ progressDlg.progressBar(), SLOT(advance(int)));
+
+ if (!midiFile.open()) {
+ CurrentProgressDialog::freeze();
+ KMessageBox::error(this, strtoqstr(midiFile.getError())); //!!! i18n
+ delete newDoc;
+ return 0;
+ }
+
+ midiFile.convertToRosegarden(newDoc->getComposition(),
+ MidiFile::CONVERT_REPLACE);
+
+ fixTextEncodings(&newDoc->getComposition());
+
+ // Set modification flag
+ //
+ newDoc->slotDocumentModified();
+
+ // Set the caption
+ //
+ newDoc->setTitle(QFileInfo(file).fileName());
+ newDoc->setAbsFilePath(QFileInfo(file).absFilePath());
+
+ // Clean up for notation purposes (after reinitialise, because that
+ // sets the composition's end marker time which is needed here)
+
+ progressDlg.slotSetOperationName(i18n("Calculating notation..."));
+ ProgressDialog::processEvents();
+
+ Composition *comp = &newDoc->getComposition();
+
+ for (Composition::iterator i = comp->begin();
+ i != comp->end(); ++i) {
+
+ Segment &segment = **i;
+ SegmentNotationHelper helper(segment);
+ segment.insert(helper.guessClef(segment.begin(),
+ segment.getEndMarker()).getAsEvent
+ (segment.getStartTime()));
+ }
+
+ progressDlg.progressBar()->setProgress(100);
+
+ for (Composition::iterator i = comp->begin();
+ i != comp->end(); ++i) {
+
+ // find first key event in each segment (we'd have done the
+ // same for clefs, except there is no MIDI clef event)
+
+ Segment &segment = **i;
+ timeT firstKeyTime = segment.getEndMarkerTime();
+
+ for (Segment::iterator si = segment.begin();
+ segment.isBeforeEndMarker(si); ++si) {
+ if ((*si)->isa(Rosegarden::Key::EventType)) {
+ firstKeyTime = (*si)->getAbsoluteTime();
+ break;
+ }
+ }
+
+ if (firstKeyTime > segment.getStartTime()) {
+ CompositionTimeSliceAdapter adapter
+ (comp, timeT(0), firstKeyTime);
+ AnalysisHelper helper;
+ segment.insert(helper.guessKey(adapter).getAsEvent
+ (segment.getStartTime()));
+ }
+ }
+
+ int progressPer = 100;
+ if (comp->getNbSegments() > 0)
+ progressPer = (int)(100.0 / double(comp->getNbSegments()));
+
+ KMacroCommand *command = new KMacroCommand(i18n("Calculate Notation"));
+
+ for (Composition::iterator i = comp->begin();
+ i != comp->end(); ++i) {
+
+ Segment &segment = **i;
+ timeT startTime(segment.getStartTime());
+ timeT endTime(segment.getEndMarkerTime());
+
+// std::cerr << "segment: start time " << segment.getStartTime() << ", end time " << segment.getEndTime() << ", end marker time " << segment.getEndMarkerTime() << ", events " << segment.size() << std::endl;
+
+ EventQuantizeCommand *subCommand = new EventQuantizeCommand
+ (segment, startTime, endTime, "Notation Options", true);
+
+ subCommand->setProgressTotal(progressPer + 1);
+ QObject::connect(subCommand, SIGNAL(incrementProgress(int)),
+ progressDlg.progressBar(), SLOT(advance(int)));
+
+ command->addCommand(subCommand);
+ }
+
+ newDoc->getCommandHistory()->addCommand(command);
+
+ if (comp->getTimeSignatureCount() == 0) {
+ CompositionTimeSliceAdapter adapter(comp);
+ AnalysisHelper analysisHelper;
+ TimeSignature timeSig =
+ analysisHelper.guessTimeSignature(adapter);
+ comp->addTimeSignature(0, timeSig);
+ }
+
+ return newDoc;
+}
+
+void RosegardenGUIApp::slotImportRG21()
+{
+ if (m_doc && !m_doc->saveIfModified())
+ return ;
+
+ KURL url = KFileDialog::getOpenURL
+ (":ROSEGARDEN21",
+ i18n("*.rose|Rosegarden-2 files\n*|All files"), this,
+ i18n("Open Rosegarden 2.1 File"));
+ if (url.isEmpty()) {
+ return ;
+ }
+
+ QString tmpfile;
+ KIO::NetAccess::download(url, tmpfile, this);
+ openFile(tmpfile, ImportRG21);
+
+ KIO::NetAccess::removeTempFile(tmpfile);
+}
+
+void RosegardenGUIApp::slotMergeRG21()
+{
+ KURL url = KFileDialog::getOpenURL
+ (":ROSEGARDEN21",
+ i18n("*.rose|Rosegarden-2 files\n*|All files"), this,
+ i18n("Open Rosegarden 2.1 File"));
+ if (url.isEmpty()) {
+ return ;
+ }
+
+ QString tmpfile;
+ KIO::NetAccess::download(url, tmpfile, this);
+ mergeFile(tmpfile, ImportRG21);
+
+ KIO::NetAccess::removeTempFile( tmpfile );
+}
+
+RosegardenGUIDoc*
+RosegardenGUIApp::createDocumentFromRG21File(QString file)
+{
+ KStartupLogo::hideIfStillThere();
+ ProgressDialog progressDlg(
+ i18n("Importing Rosegarden 2.1 file..."), 100, this);
+
+ CurrentProgressDialog::set
+ (&progressDlg);
+
+ // Inherent autoload
+ //
+ RosegardenGUIDoc *newDoc = new RosegardenGUIDoc(this, m_pluginManager);
+
+ RG21Loader rg21Loader(&newDoc->getStudio());
+
+ // TODO: make RG21Loader to actually emit these signals
+ //
+ connect(&rg21Loader, SIGNAL(setProgress(int)),
+ progressDlg.progressBar(), SLOT(setValue(int)));
+
+ connect(&rg21Loader, SIGNAL(incrementProgress(int)),
+ progressDlg.progressBar(), SLOT(advance(int)));
+
+ // "your starter for 40%" - helps the "freeze" work
+ //
+ progressDlg.progressBar()->advance(40);
+
+ if (!rg21Loader.load(file, newDoc->getComposition())) {
+ CurrentProgressDialog::freeze();
+ KMessageBox::error(this,
+ i18n("Can't load Rosegarden 2.1 file. It appears to be corrupted."));
+ delete newDoc;
+ return 0;
+ }
+
+ // Set modification flag
+ //
+ newDoc->slotDocumentModified();
+
+ // Set the caption and add recent
+ //
+ newDoc->setTitle(QFileInfo(file).fileName());
+ newDoc->setAbsFilePath(QFileInfo(file).absFilePath());
+
+ return newDoc;
+
+}
+
+void
+RosegardenGUIApp::slotImportHydrogen()
+{
+ if (m_doc && !m_doc->saveIfModified())
+ return ;
+
+ KURL url = KFileDialog::getOpenURL
+ (":HYDROGEN",
+ i18n("*.h2song|Hydrogen files\n*|All files"), this,
+ i18n("Open Hydrogen File"));
+ if (url.isEmpty()) {
+ return ;
+ }
+
+ QString tmpfile;
+ KIO::NetAccess::download(url, tmpfile, this);
+ openFile(tmpfile, ImportHydrogen);
+
+ KIO::NetAccess::removeTempFile(tmpfile);
+}
+
+void RosegardenGUIApp::slotMergeHydrogen()
+{
+ KURL url = KFileDialog::getOpenURL
+ (":HYDROGEN",
+ i18n("*.h2song|Hydrogen files\n*|All files"), this,
+ i18n("Open Hydrogen File"));
+ if (url.isEmpty()) {
+ return ;
+ }
+
+ QString tmpfile;
+ KIO::NetAccess::download(url, tmpfile, this);
+ mergeFile(tmpfile, ImportHydrogen);
+
+ KIO::NetAccess::removeTempFile( tmpfile );
+}
+
+RosegardenGUIDoc*
+RosegardenGUIApp::createDocumentFromHydrogenFile(QString file)
+{
+ KStartupLogo::hideIfStillThere();
+ ProgressDialog progressDlg(
+ i18n("Importing Hydrogen file..."), 100, this);
+
+ CurrentProgressDialog::set
+ (&progressDlg);
+
+ // Inherent autoload
+ //
+ RosegardenGUIDoc *newDoc = new RosegardenGUIDoc(this, m_pluginManager);
+
+ HydrogenLoader hydrogenLoader(&newDoc->getStudio());
+
+ // TODO: make RG21Loader to actually emit these signals
+ //
+ connect(&hydrogenLoader, SIGNAL(setProgress(int)),
+ progressDlg.progressBar(), SLOT(setValue(int)));
+
+ connect(&hydrogenLoader, SIGNAL(incrementProgress(int)),
+ progressDlg.progressBar(), SLOT(advance(int)));
+
+ // "your starter for 40%" - helps the "freeze" work
+ //
+ progressDlg.progressBar()->advance(40);
+
+ if (!hydrogenLoader.load(file, newDoc->getComposition())) {
+ CurrentProgressDialog::freeze();
+ KMessageBox::error(this,
+ i18n("Can't load Hydrogen file. It appears to be corrupted."));
+ delete newDoc;
+ return 0;
+ }
+
+ // Set modification flag
+ //
+ newDoc->slotDocumentModified();
+
+ // Set the caption and add recent
+ //
+ newDoc->setTitle(QFileInfo(file).fileName());
+ newDoc->setAbsFilePath(QFileInfo(file).absFilePath());
+
+ return newDoc;
+
+}
+
+void
+RosegardenGUIApp::mergeFile(QString filePath, ImportType type)
+{
+ RosegardenGUIDoc *doc = createDocument(filePath, type);
+
+ if (doc) {
+ if (m_doc) {
+
+ bool timingsDiffer = false;
+ Composition &c1 = m_doc->getComposition();
+ Composition &c2 = doc->getComposition();
+
+ // compare tempos and time sigs in the two -- rather laborious
+
+ if (c1.getTimeSignatureCount() != c2.getTimeSignatureCount()) {
+ timingsDiffer = true;
+ } else {
+ for (int i = 0; i < c1.getTimeSignatureCount(); ++i) {
+ std::pair<timeT, TimeSignature> t1 =
+ c1.getTimeSignatureChange(i);
+ std::pair<timeT, TimeSignature> t2 =
+ c2.getTimeSignatureChange(i);
+ if (t1.first != t2.first || t1.second != t2.second) {
+ timingsDiffer = true;
+ break;
+ }
+ }
+ }
+
+ if (c1.getTempoChangeCount() != c2.getTempoChangeCount()) {
+ timingsDiffer = true;
+ } else {
+ for (int i = 0; i < c1.getTempoChangeCount(); ++i) {
+ std::pair<timeT, tempoT> t1 = c1.getTempoChange(i);
+ std::pair<timeT, tempoT> t2 = c2.getTempoChange(i);
+ if (t1.first != t2.first || t1.second != t2.second) {
+ timingsDiffer = true;
+ break;
+ }
+ }
+ }
+
+ FileMergeDialog dialog(this, filePath, timingsDiffer);
+ if (dialog.exec() == QDialog::Accepted) {
+ m_doc->mergeDocument(doc, dialog.getMergeOptions());
+ }
+
+ delete doc;
+
+ } else {
+ setDocument(doc);
+ }
+ }
+}
+
+void
+RosegardenGUIApp::slotUpdatePlaybackPosition()
+{
+ static int callbackCount = 0;
+
+ // Either sequencer mappper or the sequence manager could be missing at
+ // this point.
+ //
+ if (!m_seqManager || !m_seqManager->getSequencerMapper())
+ return ;
+
+ SequencerMapper *mapper = m_seqManager->getSequencerMapper();
+
+ MappedEvent ev;
+ bool haveEvent = mapper->getVisual(ev);
+ if (haveEvent)
+ getTransport()->setMidiOutLabel(&ev);
+
+ RealTime position = mapper->getPositionPointer();
+
+ // std::cerr << "RosegardenGUIApp::slotUpdatePlaybackPosition: mapper pos = " << position << std::endl;
+
+ Composition &comp = m_doc->getComposition();
+ timeT elapsedTime = comp.getElapsedTimeForRealTime(position);
+
+ // std::cerr << "RosegardenGUIApp::slotUpdatePlaybackPosition: mapper timeT = " << elapsedTime << std::endl;
+
+ if (m_seqManager->getTransportStatus() == RECORDING) {
+
+ MappedComposition mC;
+ if (mapper->getRecordedEvents(mC) > 0) {
+ m_seqManager->processAsynchronousMidi(mC, 0);
+ m_doc->insertRecordedMidi(mC);
+ }
+
+ m_doc->updateRecordingMIDISegment();
+ m_doc->updateRecordingAudioSegments();
+ }
+
+ m_originatingJump = true;
+ m_doc->slotSetPointerPosition(elapsedTime);
+ m_originatingJump = false;
+
+ if (m_audioMixer && m_audioMixer->isVisible())
+ m_audioMixer->updateMeters(mapper);
+
+ if (m_midiMixer && m_midiMixer->isVisible())
+ m_midiMixer->updateMeters(mapper);
+
+ m_view->updateMeters(mapper);
+
+ if (++callbackCount == 60) {
+ slotUpdateCPUMeter(true);
+ callbackCount = 0;
+ }
+
+ // if (elapsedTime >= comp.getEndMarker())
+ // slotStop();
+}
+
+void
+RosegardenGUIApp::slotUpdateCPUMeter(bool playing)
+{
+ static std::ifstream *statstream = 0;
+ static bool modified = false;
+ static unsigned long lastBusy = 0, lastIdle = 0;
+
+ if (playing) {
+
+ if (!statstream) {
+ statstream = new std::ifstream("/proc/stat", std::ios::in);
+ }
+
+ if (!statstream || !*statstream)
+ return ;
+ statstream->seekg(0, std::ios::beg);
+
+ std::string cpu;
+ unsigned long user, nice, sys, idle;
+ *statstream >> cpu;
+ *statstream >> user;
+ *statstream >> nice;
+ *statstream >> sys;
+ *statstream >> idle;
+
+ unsigned long busy = user + nice + sys;
+ unsigned long count = 0;
+
+ if (lastBusy > 0) {
+ unsigned long bd = busy - lastBusy;
+ unsigned long id = idle - lastIdle;
+ if (bd + id > 0)
+ count = bd * 100 / (bd + id);
+ if (count > 100)
+ count = 100;
+ }
+
+ lastBusy = busy;
+ lastIdle = idle;
+
+ if (m_progressBar) {
+ if (!modified) {
+ m_progressBar->setTextEnabled(true);
+ m_progressBar->setFormat("CPU");
+ }
+ m_progressBar->setProgress(count);
+ }
+
+ modified = true;
+
+ } else if (modified) {
+ if (m_progressBar) {
+ m_progressBar->setTextEnabled(false);
+ m_progressBar->setFormat("%p%");
+ m_progressBar->setProgress(0);
+ }
+ modified = false;
+ }
+}
+
+void
+RosegardenGUIApp::slotUpdateMonitoring()
+{
+ // Either sequencer mappper or the sequence manager could be missing at
+ // this point.
+ //
+ if (!m_seqManager || !m_seqManager->getSequencerMapper())
+ return ;
+
+ SequencerMapper *mapper = m_seqManager->getSequencerMapper();
+
+ if (m_audioMixer && m_audioMixer->isVisible())
+ m_audioMixer->updateMonitorMeters(mapper);
+
+ if (m_midiMixer && m_midiMixer->isVisible())
+ m_midiMixer->updateMonitorMeter(mapper);
+
+ m_view->updateMonitorMeters(mapper);
+
+ slotUpdateCPUMeter(false);
+}
+
+void RosegardenGUIApp::slotSetPointerPosition(timeT t)
+{
+ Composition &comp = m_doc->getComposition();
+
+ // std::cerr << "RosegardenGUIApp::slotSetPointerPosition: t = " << t << std::endl;
+
+ if (m_seqManager) {
+ if ( m_seqManager->getTransportStatus() == PLAYING ||
+ m_seqManager->getTransportStatus() == RECORDING ) {
+ if (t > comp.getEndMarker()) {
+ if (m_seqManager->getTransportStatus() == PLAYING) {
+
+ slotStop();
+ t = comp.getEndMarker();
+ m_doc->slotSetPointerPosition(t); //causes this method to be re-invoked
+ return ;
+
+ } else { // if recording, increase composition duration
+ std::pair<timeT, timeT> timeRange = comp.getBarRangeForTime(t);
+ timeT barDuration = timeRange.second - timeRange.first;
+ timeT newEndMarker = t + 10 * barDuration;
+ comp.setEndMarker(newEndMarker);
+ getView()->getTrackEditor()->slotReadjustCanvasSize();
+ getView()->getTrackEditor()->updateRulers();
+ }
+ }
+ }
+
+ // cc 20050520 - jump at the sequencer even if we're not playing,
+ // because we might be a transport master of some kind
+ try {
+ if (!m_originatingJump) {
+ m_seqManager->sendSequencerJump(comp.getElapsedRealTime(t));
+ }
+ } catch (QString s) {
+ KMessageBox::error(this, s);
+ }
+ }
+
+ // set the time sig
+ getTransport()->setTimeSignature(comp.getTimeSignatureAt(t));
+
+ // and the tempo
+ getTransport()->setTempo(comp.getTempoAtTime(t));
+
+ // and the time
+ //
+ TransportDialog::TimeDisplayMode mode =
+ getTransport()->getCurrentMode();
+
+ if (mode == TransportDialog::BarMode ||
+ mode == TransportDialog::BarMetronomeMode) {
+
+ slotDisplayBarTime(t);
+
+ } else {
+
+ RealTime rT(comp.getElapsedRealTime(t));
+
+ if (getTransport()->isShowingTimeToEnd()) {
+ rT = rT - comp.getElapsedRealTime(comp.getDuration());
+ }
+
+ if (mode == TransportDialog::RealMode) {
+
+ getTransport()->displayRealTime(rT);
+
+ } else if (mode == TransportDialog::SMPTEMode) {
+
+ getTransport()->displaySMPTETime(rT);
+
+ } else {
+
+ getTransport()->displayFrameTime(rT);
+ }
+ }
+
+ // handle transport mode configuration changes
+ std::string modeAsString = getTransport()->getCurrentModeAsString();
+
+ if (m_doc->getConfiguration().get<String>
+ (DocumentConfiguration::TransportMode) != modeAsString) {
+
+ m_doc->getConfiguration().set<String>
+ (DocumentConfiguration::TransportMode, modeAsString);
+
+ //m_doc->slotDocumentModified(); to avoid being prompted for a file change when merely changing the transport display
+ }
+
+ // Update position on the marker editor if it's available
+ //
+ if (m_markerEditor)
+ m_markerEditor->updatePosition();
+}
+
+void RosegardenGUIApp::slotDisplayBarTime(timeT t)
+{
+ Composition &comp = m_doc->getComposition();
+
+ int barNo = comp.getBarNumber(t);
+ timeT barStart = comp.getBarStart(barNo);
+
+ TimeSignature timeSig = comp.getTimeSignatureAt(t);
+ timeT beatDuration = timeSig.getBeatDuration();
+
+ int beatNo = (t - barStart) / beatDuration;
+ int unitNo = (t - barStart) - (beatNo * beatDuration);
+
+ if (getTransport()->isShowingTimeToEnd()) {
+ barNo = barNo + 1 - comp.getNbBars();
+ beatNo = timeSig.getBeatsPerBar() - 1 - beatNo;
+ unitNo = timeSig.getBeatDuration() - 1 - unitNo;
+ } else {
+ // convert to 1-based display bar numbers
+ barNo += 1;
+ beatNo += 1;
+ }
+
+ // show units in hemidemis (or whatever), not in raw time ticks
+ unitNo /= Note(Note::Shortest).getDuration();
+
+ getTransport()->displayBarTime(barNo, beatNo, unitNo);
+}
+
+void RosegardenGUIApp::slotRefreshTimeDisplay()
+{
+ if ( m_seqManager->getTransportStatus() == PLAYING ||
+ m_seqManager->getTransportStatus() == RECORDING ) {
+ return ; // it'll be refreshed in a moment anyway
+ }
+ slotSetPointerPosition(m_doc->getComposition().getPosition());
+}
+
+bool
+RosegardenGUIApp::isTrackEditorPlayTracking() const
+{
+ return m_view->getTrackEditor()->isTracking();
+}
+
+void RosegardenGUIApp::slotToggleTracking()
+{
+ m_view->getTrackEditor()->slotToggleTracking();
+}
+
+void RosegardenGUIApp::slotTestStartupTester()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotTestStartupTester" << endl;
+
+ if (!m_startupTester) {
+ m_startupTester = new StartupTester();
+ connect(m_startupTester, SIGNAL(newerVersionAvailable(QString)),
+ this, SLOT(slotNewerVersionAvailable(QString)));
+ m_startupTester->start();
+ QTimer::singleShot(100, this, SLOT(slotTestStartupTester()));
+ return ;
+ }
+
+ if (!m_startupTester->isReady()) {
+ QTimer::singleShot(100, this, SLOT(slotTestStartupTester()));
+ return ;
+ }
+
+ QStringList missingFeatures;
+ QStringList allMissing;
+
+ QStringList missing;
+ bool have = m_startupTester->haveProjectPackager(&missing);
+
+ stateChanged("have_project_packager",
+ have ?
+ KXMLGUIClient::StateNoReverse : KXMLGUIClient::StateReverse);
+
+ if (!have) {
+ missingFeatures.push_back(i18n("Export and import of Rosegarden Project files"));
+ if (missing.count() == 0) {
+ allMissing.push_back(i18n("The Rosegarden Project Packager helper script"));
+ } else {
+ for (int i = 0; i < missing.count(); ++i) {
+// if (missingFeatures.count() > 1) {
+ allMissing.push_back(i18n("%1 - for project file support").arg(missing[i]));
+// } else {
+// allMissing.push_back(missing[i]);
+// }
+ }
+ }
+ }
+
+ have = m_startupTester->haveLilyPondView(&missing);
+
+ stateChanged("have_lilypondview",
+ have ?
+ KXMLGUIClient::StateNoReverse : KXMLGUIClient::StateReverse);
+
+ if (!have) {
+ missingFeatures.push_back("Notation previews through LilyPond");
+ if (missing.count() == 0) {
+ allMissing.push_back(i18n("The Rosegarden LilyPondView helper script"));
+ } else {
+ for (int i = 0; i < missing.count(); ++i) {
+ if (missingFeatures.count() > 1) {
+ allMissing.push_back(i18n("%1 - for LilyPond preview support").arg(missing[i]));
+ } else {
+ allMissing.push_back(missing[i]);
+ }
+ }
+ }
+ }
+
+#ifdef HAVE_LIBJACK
+ if (m_seqManager && (m_seqManager->getSoundDriverStatus() & AUDIO_OK)) {
+
+ m_haveAudioImporter = m_startupTester->haveAudioFileImporter(&missing);
+
+ if (!m_haveAudioImporter) {
+ missingFeatures.push_back("General audio file import and conversion");
+ if (missing.count() == 0) {
+ allMissing.push_back(i18n("The Rosegarden Audio File Importer helper script"));
+ } else {
+ for (int i = 0; i < missing.count(); ++i) {
+ if (missingFeatures.count() > 1) {
+ allMissing.push_back(i18n("%1 - for audio file import").arg(missing[i]));
+ } else {
+ allMissing.push_back(missing[i]);
+ }
+ }
+ }
+ }
+ }
+#endif
+
+ if (missingFeatures.count() > 0) {
+ QString message = i18n("<h3>Helper programs not found</h3><p>Rosegarden could not find one or more helper programs which it needs to provide some features. The following features will not be available:</p>");
+ message += i18n("<ul>");
+ for (int i = 0; i < missingFeatures.count(); ++i) {
+ message += i18n("<li>%1</li>").arg(missingFeatures[i]);
+ }
+ message += i18n("</ul>");
+ message += i18n("<p>To fix this, you should install the following additional programs:</p>");
+ message += i18n("<ul>");
+ for (int i = 0; i < allMissing.count(); ++i) {
+ message += i18n("<li>%1</li>").arg(allMissing[i]);
+ }
+ message += i18n("</ul>");
+
+ awaitDialogClearance();
+
+ KMessageBox::information
+ (m_view,
+ message,
+ i18n("Helper programs not found"),
+ "startup-helpers-missing");
+ }
+
+ delete m_startupTester;
+ m_startupTester = 0;
+}
+
+void RosegardenGUIApp::slotDebugDump()
+{
+ Composition &comp = m_doc->getComposition();
+ comp.dump(std::cerr);
+}
+
+bool RosegardenGUIApp::launchSequencer(bool useExisting)
+{
+ if (!isUsingSequencer()) {
+ RG_DEBUG << "RosegardenGUIApp::launchSequencer() - not using seq. - returning\n";
+ return false; // no need to launch anything
+ }
+
+ if (isSequencerRunning()) {
+ RG_DEBUG << "RosegardenGUIApp::launchSequencer() - sequencer already running - returning\n";
+ if (m_seqManager) m_seqManager->checkSoundDriverStatus(false);
+ return true;
+ }
+
+ // Check to see if we're clearing down sequencer processes -
+ // if we're not we check DCOP for an existing sequencer and
+ // try to talk to use that (that's the "developer" mode).
+ //
+ // User mode should clear down sequencer processes.
+ //
+ if (kapp->dcopClient()->isApplicationRegistered(
+ QCString(ROSEGARDEN_SEQUENCER_APP_NAME))) {
+ RG_DEBUG << "RosegardenGUIApp::launchSequencer() - "
+ << "existing DCOP registered sequencer found\n";
+
+ if (useExisting) {
+ if (m_seqManager) m_seqManager->checkSoundDriverStatus(false);
+ m_sequencerProcess = (KProcess*)SequencerExternal;
+ return true;
+ }
+
+ KProcess *proc = new KProcess;
+ *proc << "/usr/bin/killall";
+ *proc << "rosegardensequencer";
+ *proc << "lt-rosegardensequencer";
+
+ proc->start(KProcess::Block, KProcess::All);
+
+ if (!proc->normalExit() || proc->exitStatus()) {
+ RG_DEBUG << "couldn't kill any sequencer processes" << endl;
+ }
+ delete proc;
+
+ sleep(1);
+
+ if (kapp->dcopClient()->isApplicationRegistered(
+ QCString(ROSEGARDEN_SEQUENCER_APP_NAME))) {
+ RG_DEBUG << "RosegardenGUIApp::launchSequencer() - "
+ << "failed to kill existing sequencer\n";
+
+ KProcess *proc = new KProcess;
+ *proc << "/usr/bin/killall";
+ *proc << "-9";
+ *proc << "rosegardensequencer";
+ *proc << "lt-rosegardensequencer";
+
+ proc->start(KProcess::Block, KProcess::All);
+
+ if (proc->exitStatus()) {
+ RG_DEBUG << "couldn't kill any sequencer processes" << endl;
+ }
+ delete proc;
+
+ sleep(1);
+ }
+ }
+
+ //
+ // No sequencer is running, so start one
+ //
+ KTmpStatusMsg msg(i18n("Starting the sequencer..."), this);
+
+ if (!m_sequencerProcess) {
+ m_sequencerProcess = new KProcess;
+
+ (*m_sequencerProcess) << "rosegardensequencer";
+
+ // Command line arguments
+ //
+ KConfig *config = kapp->config();
+ config->setGroup(SequencerOptionsConfigGroup);
+ QString options = config->readEntry("commandlineoptions");
+ if (!options.isEmpty()) {
+ (*m_sequencerProcess) << options;
+ RG_DEBUG << "sequencer options \"" << options << "\"" << endl;
+ }
+
+ } else {
+ RG_DEBUG << "RosegardenGUIApp::launchSequencer() - sequencer KProcess already created\n";
+ m_sequencerProcess->disconnect(); // disconnect processExit signal
+ // it will be reconnected later on
+ }
+
+ bool res = m_sequencerProcess->start();
+
+ if (!res) {
+ KMessageBox::error(0, i18n("Couldn't start the sequencer"));
+ RG_DEBUG << "Couldn't start the sequencer\n";
+ m_sequencerProcess = 0;
+ // If starting it didn't even work, fall back to no sequencer mode
+ m_useSequencer = false;
+ } else {
+ // connect processExited only after start, otherwise
+ // a failed startup will call slotSequencerExited()
+ // right away and we don't get to check the result
+ // of m_sequencerProcess->start() and thus make the distinction
+ // between the case where the sequencer was successfully launched
+ // but crashed right away, or the case where the process couldn't
+ // be launched at all (missing executable, etc...)
+ //
+ // We also re-check that the process is still running at this
+ // point in case it crashed between the moment we check res above
+ // and now.
+ //
+ //usleep(1000 * 1000); // even wait half a sec. to make sure it's actually running
+ if (m_sequencerProcess->isRunning()) {
+
+ try {
+ // if (m_seqManager) {
+ // RG_DEBUG << "RosegardenGUIApp::launchSequencer : checking sound driver status\n";
+ // m_seqManager->checkSoundDriverStatus();
+ // }
+
+ stateChanged("sequencer_running");
+ slotEnableTransport(true);
+
+ connect(m_sequencerProcess, SIGNAL(processExited(KProcess*)),
+ this, SLOT(slotSequencerExited(KProcess*)));
+
+ } catch (Exception e) {
+ m_sequencerProcess = 0;
+ m_useSequencer = false;
+ stateChanged("sequencer_running", KXMLGUIClient::StateReverse);
+ slotEnableTransport(false);
+ }
+
+ } else { // if it crashed so fast, it's probably pointless
+ // to try restarting it later, so also fall back to no
+ // sequencer mode
+ m_sequencerProcess = 0;
+ m_useSequencer = false;
+ stateChanged("sequencer_running", KXMLGUIClient::StateReverse);
+ slotEnableTransport(false);
+ }
+
+ }
+
+ // Sync current devices with the sequencer
+ //
+ if (m_doc)
+ m_doc->syncDevices();
+
+ if (m_doc && m_doc->getStudio().haveMidiDevices()) {
+ stateChanged("got_midi_devices");
+ } else {
+ stateChanged("got_midi_devices", KXMLGUIClient::StateReverse);
+ }
+
+ return res;
+}
+
+#ifdef HAVE_LIBJACK
+bool RosegardenGUIApp::launchJack()
+{
+ KConfig* config = kapp->config();
+ config->setGroup(SequencerOptionsConfigGroup);
+
+ bool startJack = config->readBoolEntry("jackstart", false);
+ if (!startJack)
+ return true; // we don't do anything
+
+ QString jackPath = config->readEntry("jackcommand", "");
+
+ emit startupStatusMessage(i18n("Clearing down jackd..."));
+
+ KProcess *proc = new KProcess; // TODO: do it in a less clumsy way
+ *proc << "/usr/bin/killall";
+ *proc << "-9";
+ *proc << "jackd";
+
+ proc->start(KProcess::Block, KProcess::All);
+
+ if (proc->exitStatus())
+ RG_DEBUG << "couldn't kill any jackd processes" << endl;
+ else
+ RG_DEBUG << "killed old jackd processes" << endl;
+
+ emit startupStatusMessage(i18n("Starting jackd..."));
+
+ if (jackPath != "") {
+
+ RG_DEBUG << "starting jack \"" << jackPath << "\"" << endl;
+
+ QStringList splitCommand;
+ splitCommand = QStringList::split(" ", jackPath);
+
+ RG_DEBUG << "RosegardenGUIApp::launchJack() : splitCommand length : "
+ << splitCommand.size() << endl;
+
+ // start jack process
+ m_jackProcess = new KProcess;
+
+ *m_jackProcess << splitCommand;
+
+ m_jackProcess->start();
+ }
+
+
+ return m_jackProcess != 0 ? m_jackProcess->isRunning() : true;
+}
+#endif
+
+void RosegardenGUIApp::slotDocumentDevicesResyncd()
+{
+ m_sequencerCheckedIn = true;
+ m_trackParameterBox->populateDeviceLists();
+}
+
+void RosegardenGUIApp::slotSequencerExited(KProcess*)
+{
+ RG_DEBUG << "RosegardenGUIApp::slotSequencerExited Sequencer exited\n";
+
+ KStartupLogo::hideIfStillThere();
+
+ if (m_sequencerCheckedIn) {
+
+ KMessageBox::error(0, i18n("The Rosegarden sequencer process has exited unexpectedly. Sound and recording will no longer be available for this session.\nPlease exit and restart Rosegarden to restore sound capability."));
+
+ } else {
+
+ KMessageBox::error(0, i18n("The Rosegarden sequencer could not be started, so sound and recording will be unavailable for this session.\nFor assistance with correct audio and MIDI configuration, go to http://rosegardenmusic.com."));
+ }
+
+ m_sequencerProcess = 0; // isSequencerRunning() will return false
+ // but isUsingSequencer() will keep returning true
+ // so pressing the play button may attempt to restart the sequencer
+}
+
+void RosegardenGUIApp::slotExportProject()
+{
+ KTmpStatusMsg msg(i18n("Exporting Rosegarden Project file..."), this);
+
+ QString fileName = getValidWriteFile
+ ("*.rgp|" + i18n("Rosegarden Project files\n") +
+ "\n*|" + i18n("All files"),
+ i18n("Export as..."));
+
+ if (fileName.isEmpty())
+ return ;
+
+ QString rgFile = fileName;
+ rgFile.replace(QRegExp(".rg.rgp$"), ".rg");
+ rgFile.replace(QRegExp(".rgp$"), ".rg");
+
+ CurrentProgressDialog::freeze();
+
+ QString errMsg;
+ if (!m_doc->saveDocument(rgFile, errMsg,
+ true)) { // pretend it's autosave
+ KMessageBox::sorry(this, i18n("Saving Rosegarden file to package failed: %1").arg(errMsg));
+ CurrentProgressDialog::thaw();
+ return ;
+ }
+
+ KProcess *proc = new KProcess;
+ *proc << "rosegarden-project-package";
+ *proc << "--pack";
+ *proc << rgFile;
+ *proc << fileName;
+
+ proc->start(KProcess::Block, KProcess::All);
+
+ if (!proc->normalExit() || proc->exitStatus()) {
+ KMessageBox::sorry(this, i18n("Failed to export to project file \"%1\"").arg(fileName));
+ CurrentProgressDialog::thaw();
+ delete proc;
+ return ;
+ }
+
+ delete proc;
+}
+
+void RosegardenGUIApp::slotExportMIDI()
+{
+ KTmpStatusMsg msg(i18n("Exporting MIDI file..."), this);
+
+ QString fileName = getValidWriteFile
+ ("*.mid *.midi|" + i18n("Standard MIDI files\n") +
+ "\n*|" + i18n("All files"),
+ i18n("Export as..."));
+
+ if (fileName.isEmpty())
+ return ;
+
+ exportMIDIFile(fileName);
+}
+
+void RosegardenGUIApp::exportMIDIFile(QString file)
+{
+ ProgressDialog progressDlg(i18n("Exporting MIDI file..."),
+ 100,
+ this);
+
+ std::string fname(QFile::encodeName(file));
+
+ MidiFile midiFile(fname,
+ &m_doc->getStudio());
+
+ connect(&midiFile, SIGNAL(setProgress(int)),
+ progressDlg.progressBar(), SLOT(setValue(int)));
+
+ connect(&midiFile, SIGNAL(incrementProgress(int)),
+ progressDlg.progressBar(), SLOT(advance(int)));
+
+ midiFile.convertToMidi(m_doc->getComposition());
+
+ if (!midiFile.write()) {
+ CurrentProgressDialog::freeze();
+ KMessageBox::sorry(this, i18n("Export failed. The file could not be opened for writing."));
+ }
+}
+
+void RosegardenGUIApp::slotExportCsound()
+{
+ KTmpStatusMsg msg(i18n("Exporting Csound score file..."), this);
+
+ QString fileName = getValidWriteFile(QString("*|") + i18n("All files"),
+ i18n("Export as..."));
+ if (fileName.isEmpty())
+ return ;
+
+ exportCsoundFile(fileName);
+}
+
+void RosegardenGUIApp::exportCsoundFile(QString file)
+{
+ ProgressDialog progressDlg(i18n("Exporting Csound score file..."),
+ 100,
+ this);
+
+ CsoundExporter e(this, &m_doc->getComposition(), std::string(QFile::encodeName(file)));
+
+ connect(&e, SIGNAL(setProgress(int)),
+ progressDlg.progressBar(), SLOT(setValue(int)));
+
+ connect(&e, SIGNAL(incrementProgress(int)),
+ progressDlg.progressBar(), SLOT(advance(int)));
+
+ if (!e.write()) {
+ CurrentProgressDialog::freeze();
+ KMessageBox::sorry(this, i18n("Export failed. The file could not be opened for writing."));
+ }
+}
+
+void RosegardenGUIApp::slotExportMup()
+{
+ KTmpStatusMsg msg(i18n("Exporting Mup file..."), this);
+
+ QString fileName = getValidWriteFile
+ ("*.mup|" + i18n("Mup files\n") + "\n*|" + i18n("All files"),
+ i18n("Export as..."));
+ if (fileName.isEmpty())
+ return ;
+
+ exportMupFile(fileName);
+}
+
+void RosegardenGUIApp::exportMupFile(QString file)
+{
+ ProgressDialog progressDlg(i18n("Exporting Mup file..."),
+ 100,
+ this);
+
+ MupExporter e(this, &m_doc->getComposition(), std::string(QFile::encodeName(file)));
+
+ connect(&e, SIGNAL(setProgress(int)),
+ progressDlg.progressBar(), SLOT(setValue(int)));
+
+ connect(&e, SIGNAL(incrementProgress(int)),
+ progressDlg.progressBar(), SLOT(advance(int)));
+
+ if (!e.write()) {
+ CurrentProgressDialog::freeze();
+ KMessageBox::sorry(this, i18n("Export failed. The file could not be opened for writing."));
+ }
+}
+
+void RosegardenGUIApp::slotExportLilyPond()
+{
+ KTmpStatusMsg msg(i18n("Exporting LilyPond file..."), this);
+
+ QString fileName = getValidWriteFile
+ (QString("*.ly|") + i18n("LilyPond files") +
+ "\n*|" + i18n("All files"),
+ i18n("Export as..."));
+
+ if (fileName.isEmpty())
+ return ;
+
+ exportLilyPondFile(fileName);
+}
+
+std::map<KProcess *, KTempFile *> RosegardenGUIApp::m_lilyTempFileMap;
+
+
+void RosegardenGUIApp::slotPrintLilyPond()
+{
+ KTmpStatusMsg msg(i18n("Printing LilyPond file..."), this);
+ KTempFile *file = new KTempFile(QString::null, ".ly");
+ file->setAutoDelete(true);
+ if (!file->name()) {
+ CurrentProgressDialog::freeze();
+ KMessageBox::sorry(this, i18n("Failed to open a temporary file for LilyPond export."));
+ delete file;
+ }
+ if (!exportLilyPondFile(file->name(), true)) {
+ return ;
+ }
+ KProcess *proc = new KProcess;
+ *proc << "rosegarden-lilypondview";
+ *proc << "--graphical";
+ *proc << "--print";
+ *proc << file->name();
+ connect(proc, SIGNAL(processExited(KProcess *)),
+ this, SLOT(slotLilyPondViewProcessExited(KProcess *)));
+ m_lilyTempFileMap[proc] = file;
+ proc->start(KProcess::NotifyOnExit);
+}
+
+void RosegardenGUIApp::slotPreviewLilyPond()
+{
+ KTmpStatusMsg msg(i18n("Previewing LilyPond file..."), this);
+ KTempFile *file = new KTempFile(QString::null, ".ly");
+ file->setAutoDelete(true);
+ if (!file->name()) {
+ CurrentProgressDialog::freeze();
+ KMessageBox::sorry(this, i18n("Failed to open a temporary file for LilyPond export."));
+ delete file;
+ }
+ if (!exportLilyPondFile(file->name(), true)) {
+ return ;
+ }
+ KProcess *proc = new KProcess;
+ *proc << "rosegarden-lilypondview";
+ *proc << "--graphical";
+ *proc << "--pdf";
+ *proc << file->name();
+ connect(proc, SIGNAL(processExited(KProcess *)),
+ this, SLOT(slotLilyPondViewProcessExited(KProcess *)));
+ m_lilyTempFileMap[proc] = file;
+ proc->start(KProcess::NotifyOnExit);
+}
+
+void RosegardenGUIApp::slotLilyPondViewProcessExited(KProcess *p)
+{
+ delete m_lilyTempFileMap[p];
+ m_lilyTempFileMap.erase(p);
+ delete p;
+}
+
+bool RosegardenGUIApp::exportLilyPondFile(QString file, bool forPreview)
+{
+ QString caption = "", heading = "";
+ if (forPreview) {
+ caption = i18n("LilyPond Preview Options");
+ heading = i18n("LilyPond preview options");
+ }
+
+ LilyPondOptionsDialog dialog(this, m_doc, caption, heading);
+ if (dialog.exec() != QDialog::Accepted) {
+ return false;
+ }
+
+ ProgressDialog progressDlg(i18n("Exporting LilyPond file..."),
+ 100,
+ this);
+
+ LilyPondExporter e(this, m_doc, std::string(QFile::encodeName(file)));
+
+ connect(&e, SIGNAL(setProgress(int)),
+ progressDlg.progressBar(), SLOT(setValue(int)));
+
+ connect(&e, SIGNAL(incrementProgress(int)),
+ progressDlg.progressBar(), SLOT(advance(int)));
+
+ if (!e.write()) {
+ CurrentProgressDialog::freeze();
+ KMessageBox::sorry(this, i18n("Export failed. The file could not be opened for writing."));
+ return false;
+ }
+
+ return true;
+}
+
+void RosegardenGUIApp::slotExportMusicXml()
+{
+ KTmpStatusMsg msg(i18n("Exporting MusicXML file..."), this);
+
+ QString fileName = getValidWriteFile
+ (QString("*.xml|") + i18n("XML files") +
+ "\n*|" + i18n("All files"), i18n("Export as..."));
+
+ if (fileName.isEmpty())
+ return ;
+
+ exportMusicXmlFile(fileName);
+}
+
+void RosegardenGUIApp::exportMusicXmlFile(QString file)
+{
+ ProgressDialog progressDlg(i18n("Exporting MusicXML file..."),
+ 100,
+ this);
+
+ MusicXmlExporter e(this, m_doc, std::string(QFile::encodeName(file)));
+
+ connect(&e, SIGNAL(setProgress(int)),
+ progressDlg.progressBar(), SLOT(setValue(int)));
+
+ connect(&e, SIGNAL(incrementProgress(int)),
+ progressDlg.progressBar(), SLOT(advance(int)));
+
+ if (!e.write()) {
+ CurrentProgressDialog::freeze();
+ KMessageBox::sorry(this, i18n("Export failed. The file could not be opened for writing."));
+ }
+}
+
+void
+RosegardenGUIApp::slotCloseTransport()
+{
+ m_viewTransport->setChecked(false);
+ slotToggleTransport(); // hides the transport
+}
+
+void
+RosegardenGUIApp::slotDeleteTransport()
+{
+ delete m_transport;
+ m_transport = 0;
+}
+
+void
+RosegardenGUIApp::slotActivateTool(QString toolName)
+{
+ if (toolName == SegmentSelector::ToolName) {
+ actionCollection()->action("select")->activate();
+ }
+}
+
+void
+RosegardenGUIApp::slotToggleMetronome()
+{
+ Composition &comp = m_doc->getComposition();
+
+ if (m_seqManager->getTransportStatus() == STARTING_TO_RECORD ||
+ m_seqManager->getTransportStatus() == RECORDING ||
+ m_seqManager->getTransportStatus() == RECORDING_ARMED) {
+ if (comp.useRecordMetronome())
+ comp.setRecordMetronome(false);
+ else
+ comp.setRecordMetronome(true);
+
+ getTransport()->MetronomeButton()->setOn(comp.useRecordMetronome());
+ } else {
+ if (comp.usePlayMetronome())
+ comp.setPlayMetronome(false);
+ else
+ comp.setPlayMetronome(true);
+
+ getTransport()->MetronomeButton()->setOn(comp.usePlayMetronome());
+ }
+}
+
+void
+RosegardenGUIApp::slotRewindToBeginning()
+{
+ // ignore requests if recording
+ //
+ if (m_seqManager->getTransportStatus() == RECORDING)
+ return ;
+
+ m_seqManager->rewindToBeginning();
+}
+
+void
+RosegardenGUIApp::slotFastForwardToEnd()
+{
+ // ignore requests if recording
+ //
+ if (m_seqManager->getTransportStatus() == RECORDING)
+ return ;
+
+ m_seqManager->fastForwardToEnd();
+}
+
+void
+RosegardenGUIApp::slotSetPlayPosition(timeT time)
+{
+ RG_DEBUG << "RosegardenGUIApp::slotSetPlayPosition(" << time << ")" << endl;
+ if (m_seqManager->getTransportStatus() == RECORDING)
+ return ;
+
+ m_doc->slotSetPointerPosition(time);
+
+ if (m_seqManager->getTransportStatus() == PLAYING)
+ return ;
+
+ slotPlay();
+}
+
+void RosegardenGUIApp::notifySequencerStatus(int status)
+{
+ stateChanged("not_playing",
+ (status == PLAYING ||
+ status == RECORDING) ?
+ KXMLGUIClient::StateReverse : KXMLGUIClient::StateNoReverse);
+
+ if (m_seqManager)
+ m_seqManager->setTransportStatus((TransportStatus) status);
+}
+
+void RosegardenGUIApp::processAsynchronousMidi(const MappedComposition &mC)
+{
+ if (!m_seqManager) {
+ return ; // probably getting this from a not-yet-killed runaway sequencer
+ }
+
+ m_seqManager->processAsynchronousMidi(mC, 0);
+ SequencerMapper *mapper = m_seqManager->getSequencerMapper();
+ if (mapper)
+ m_view->updateMeters(mapper);
+}
+
+void
+RosegardenGUIApp::slotRecord()
+{
+ if (!isUsingSequencer())
+ return ;
+
+ if (!isSequencerRunning()) {
+
+ // Try to launch sequencer and return if we fail
+ //
+ if (!launchSequencer(false))
+ return ;
+ }
+
+ if (m_seqManager->getTransportStatus() == RECORDING) {
+ slotStop();
+ return ;
+ } else if (m_seqManager->getTransportStatus() == PLAYING) {
+ slotToggleRecord();
+ return ;
+ }
+
+ // Attempt to start recording
+ //
+ try {
+ m_seqManager->record(false);
+ } catch (QString s) {
+ // We should already be stopped by this point so just unset
+ // the buttons after clicking the dialog.
+ //
+ KMessageBox::error(this, s);
+
+ getTransport()->MetronomeButton()->setOn(false);
+ getTransport()->RecordButton()->setOn(false);
+ getTransport()->PlayButton()->setOn(false);
+ return ;
+ } catch (AudioFileManager::BadAudioPathException e) {
+ if (KMessageBox::warningContinueCancel
+ (this,
+ i18n("The audio file path does not exist or is not writable.\nPlease set the audio file path to a valid directory in Document Properties before recording audio.\nWould you like to set it now?"),
+ i18n("Warning"),
+ i18n("Set audio file path")) == KMessageBox::Continue) {
+ slotOpenAudioPathSettings();
+ }
+ getTransport()->MetronomeButton()->setOn(false);
+ getTransport()->RecordButton()->setOn(false);
+ getTransport()->PlayButton()->setOn(false);
+ return ;
+ } catch (Exception e) {
+ KMessageBox::error(this, strtoqstr(e.getMessage()));
+
+ getTransport()->MetronomeButton()->setOn(false);
+ getTransport()->RecordButton()->setOn(false);
+ getTransport()->PlayButton()->setOn(false);
+ return ;
+ }
+
+ // plugin the keyboard accelerators for focus on this dialog
+ plugAccelerators(m_seqManager->getCountdownDialog(),
+ m_seqManager->getCountdownDialog()->getAccelerators());
+
+ connect(m_seqManager->getCountdownDialog(), SIGNAL(stopped()),
+ this, SLOT(slotStop()));
+
+ // Start the playback timer - this fetches the current sequencer position &c
+ //
+ m_stopTimer->stop();
+ m_playTimer->start(23); // avoid multiples of 10 just so as
+ // to avoid always having the same digit
+ // in one place on the transport. How
+ // shallow.)
+}
+
+void
+RosegardenGUIApp::slotToggleRecord()
+{
+ if (!isUsingSequencer() ||
+ (!isSequencerRunning() && !launchSequencer(false)))
+ return ;
+
+ try {
+ m_seqManager->record(true);
+ } catch (QString s) {
+ KMessageBox::error(this, s);
+ } catch (AudioFileManager::BadAudioPathException e) {
+ if (KMessageBox::warningContinueCancel
+ (this,
+ i18n("The audio file path does not exist or is not writable.\nPlease set the audio file path to a valid directory in Document Properties before you start to record audio.\nWould you like to set it now?"),
+ i18n("Error"),
+ i18n("Set audio file path")) == KMessageBox::Continue) {
+ slotOpenAudioPathSettings();
+ }
+ } catch (Exception e) {
+ KMessageBox::error(this, strtoqstr(e.getMessage()));
+ }
+
+}
+
+void
+RosegardenGUIApp::slotSetLoop(timeT lhs, timeT rhs)
+{
+ try {
+ m_doc->slotDocumentModified();
+
+ m_seqManager->setLoop(lhs, rhs);
+
+ // toggle the loop button
+ if (lhs != rhs) {
+ getTransport()->LoopButton()->setOn(true);
+ stateChanged("have_range", KXMLGUIClient::StateNoReverse);
+ } else {
+ getTransport()->LoopButton()->setOn(false);
+ stateChanged("have_range", KXMLGUIClient::StateReverse);
+ }
+ } catch (QString s) {
+ KMessageBox::error(this, s);
+ }
+}
+
+void RosegardenGUIApp::alive()
+{
+ if (m_doc)
+ m_doc->syncDevices();
+
+ if (m_doc && m_doc->getStudio().haveMidiDevices()) {
+ stateChanged("got_midi_devices");
+ } else {
+ stateChanged("got_midi_devices", KXMLGUIClient::StateReverse);
+ }
+}
+
+void RosegardenGUIApp::slotPlay()
+{
+ if (!isUsingSequencer())
+ return ;
+
+ if (!isSequencerRunning()) {
+
+ // Try to launch sequencer and return if it fails
+ //
+ if (!launchSequencer(false))
+ return ;
+ }
+
+ if (!m_seqManager)
+ return ;
+
+ // If we're armed and ready to record then do this instead (calling
+ // slotRecord ensures we don't toggle the recording state in
+ // SequenceManager)
+ //
+ if (m_seqManager->getTransportStatus() == RECORDING_ARMED) {
+ slotRecord();
+ return ;
+ }
+
+ // Send the controllers at start of playback if required
+ //
+ KConfig *config = kapp->config();
+ config->setGroup(SequencerOptionsConfigGroup);
+ bool sendControllers = config->readBoolEntry("alwayssendcontrollers", false);
+
+ if (sendControllers)
+ m_doc->initialiseControllers();
+
+ bool pausedPlayback = false;
+
+ try {
+ pausedPlayback = m_seqManager->play(); // this will stop playback (pause) if it's already running
+ // Check the new state of the transport and start or stop timer
+ // accordingly
+ //
+ if (!pausedPlayback) {
+
+ // Start the playback timer - this fetches the current sequencer position &c
+ //
+ m_stopTimer->stop();
+ m_playTimer->start(23);
+ } else {
+ m_playTimer->stop();
+ m_stopTimer->start(100);
+ }
+ } catch (QString s) {
+ KMessageBox::error(this, s);
+ m_playTimer->stop();
+ m_stopTimer->start(100);
+ } catch (Exception e) {
+ KMessageBox::error(this, e.getMessage());
+ m_playTimer->stop();
+ m_stopTimer->start(100);
+ }
+
+}
+
+void RosegardenGUIApp::slotJumpToTime(int sec, int usec)
+{
+ Composition *comp = &m_doc->getComposition();
+ timeT t = comp->getElapsedTimeForRealTime
+ (RealTime(sec, usec * 1000));
+ m_doc->slotSetPointerPosition(t);
+}
+
+void RosegardenGUIApp::slotStartAtTime(int sec, int usec)
+{
+ slotJumpToTime(sec, usec);
+ slotPlay();
+}
+
+void RosegardenGUIApp::slotStop()
+{
+ if (m_seqManager &&
+ m_seqManager->getCountdownDialog()) {
+ disconnect(m_seqManager->getCountdownDialog(), SIGNAL(stopped()),
+ this, SLOT(slotStop()));
+ disconnect(m_seqManager->getCountdownDialog(), SIGNAL(completed()),
+ this, SLOT(slotStop()));
+ }
+
+ try {
+ if (m_seqManager)
+ m_seqManager->stopping();
+ } catch (Exception e) {
+ KMessageBox::error(this, strtoqstr(e.getMessage()));
+ }
+
+ // stop the playback timer
+ m_playTimer->stop();
+ m_stopTimer->start(100);
+}
+
+void RosegardenGUIApp::slotRewind()
+{
+ // ignore requests if recording
+ //
+ if (m_seqManager->getTransportStatus() == RECORDING)
+ return ;
+ if (m_seqManager)
+ m_seqManager->rewind();
+}
+
+void RosegardenGUIApp::slotFastforward()
+{
+ // ignore requests if recording
+ //
+ if (m_seqManager->getTransportStatus() == RECORDING)
+ return ;
+
+ if (m_seqManager)
+ m_seqManager->fastforward();
+}
+
+void
+RosegardenGUIApp::slotSetLoop()
+{
+ // restore loop
+ m_doc->setLoop(m_storedLoopStart, m_storedLoopEnd);
+}
+
+void
+RosegardenGUIApp::slotUnsetLoop()
+{
+ Composition &comp = m_doc->getComposition();
+
+ // store the loop
+ m_storedLoopStart = comp.getLoopStart();
+ m_storedLoopEnd = comp.getLoopEnd();
+
+ // clear the loop at the composition and propagate to the rest
+ // of the display items
+ m_doc->setLoop(0, 0);
+}
+
+void
+RosegardenGUIApp::slotSetLoopStart()
+{
+ // Check so that start time is before endtime, othervise move upp the
+ // endtime to that same pos.
+ if ( m_doc->getComposition().getPosition() < m_doc->getComposition().getLoopEnd() ) {
+ m_doc->setLoop(m_doc->getComposition().getPosition(), m_doc->getComposition().getLoopEnd());
+ } else {
+ m_doc->setLoop(m_doc->getComposition().getPosition(), m_doc->getComposition().getPosition());
+ }
+}
+
+void
+RosegardenGUIApp::slotSetLoopStop()
+{
+ // Check so that end time is after start time, othervise move upp the
+ // start time to that same pos.
+ if ( m_doc->getComposition().getLoopStart() < m_doc->getComposition().getPosition() ) {
+ m_doc->setLoop(m_doc->getComposition().getLoopStart(), m_doc->getComposition().getPosition());
+ } else {
+ m_doc->setLoop(m_doc->getComposition().getPosition(), m_doc->getComposition().getPosition());
+ }
+}
+
+void RosegardenGUIApp::slotToggleSolo(bool value)
+{
+ RG_DEBUG << "RosegardenGUIApp::slotToggleSolo value = " << value << endl;
+
+ m_doc->getComposition().setSolo(value);
+ getTransport()->SoloButton()->setOn(value);
+
+ m_doc->slotDocumentModified();
+
+ emit compositionStateUpdate();
+}
+
+void RosegardenGUIApp::slotTrackUp()
+{
+ Composition &comp = m_doc->getComposition();
+
+ TrackId tid = comp.getSelectedTrack();
+ TrackId pos = comp.getTrackById(tid)->getPosition();
+
+ // If at top already
+ if (pos == 0)
+ return ;
+
+ Track *track = comp.getTrackByPosition(pos - 1);
+
+ // If the track exists
+ if (track) {
+ comp.setSelectedTrack(track->getId());
+ m_view->slotSelectTrackSegments(comp.getSelectedTrack());
+ }
+
+}
+
+void RosegardenGUIApp::slotTrackDown()
+{
+ Composition &comp = m_doc->getComposition();
+
+ TrackId tid = comp.getSelectedTrack();
+ TrackId pos = comp.getTrackById(tid)->getPosition();
+
+ Track *track = comp.getTrackByPosition(pos + 1);
+
+ // If the track exists
+ if (track) {
+ comp.setSelectedTrack(track->getId());
+ m_view->slotSelectTrackSegments(comp.getSelectedTrack());
+ }
+
+}
+
+void RosegardenGUIApp::slotMuteAllTracks()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotMuteAllTracks" << endl;
+
+ Composition &comp = m_doc->getComposition();
+
+ Composition::trackcontainer tracks = comp.getTracks();
+ Composition::trackiterator tit;
+ for (tit = tracks.begin(); tit != tracks.end(); ++tit)
+ m_view->slotSetMute((*tit).second->getInstrument(), true);
+}
+
+void RosegardenGUIApp::slotUnmuteAllTracks()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotUnmuteAllTracks" << endl;
+
+ Composition &comp = m_doc->getComposition();
+
+ Composition::trackcontainer tracks = comp.getTracks();
+ Composition::trackiterator tit;
+ for (tit = tracks.begin(); tit != tracks.end(); ++tit)
+ m_view->slotSetMute((*tit).second->getInstrument(), false);
+}
+
+void RosegardenGUIApp::slotToggleMutedCurrentTrack()
+{
+ Composition &comp = m_doc->getComposition();
+ TrackId tid = comp.getSelectedTrack();
+ Track *track = comp.getTrackById(tid);
+ // If the track exists
+ if (track) {
+ bool isMuted = track->isMuted();
+ m_view->slotSetMuteButton(tid, !isMuted);
+ }
+}
+
+void RosegardenGUIApp::slotToggleRecordCurrentTrack()
+{
+ Composition &comp = m_doc->getComposition();
+ TrackId tid = comp.getSelectedTrack();
+ int pos = comp.getTrackPositionById(tid);
+ m_view->getTrackEditor()->getTrackButtons()->slotToggleRecordTrack(pos);
+}
+
+
+void RosegardenGUIApp::slotConfigure()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotConfigure\n";
+
+ ConfigureDialog *configDlg =
+ new ConfigureDialog(m_doc, kapp->config(), this);
+
+ connect(configDlg, SIGNAL(updateAutoSaveInterval(unsigned int)),
+ this, SLOT(slotUpdateAutoSaveInterval(unsigned int)));
+ connect(configDlg, SIGNAL(updateSidebarStyle(unsigned int)),
+ this, SLOT(slotUpdateSidebarStyle(unsigned int)));
+
+ configDlg->show();
+}
+
+void RosegardenGUIApp::slotEditDocumentProperties()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotEditDocumentProperties\n";
+
+ DocumentConfigureDialog *configDlg =
+ new DocumentConfigureDialog(m_doc, this);
+
+ configDlg->show();
+}
+
+void RosegardenGUIApp::slotOpenAudioPathSettings()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotOpenAudioPathSettings\n";
+
+ DocumentConfigureDialog *configDlg =
+ new DocumentConfigureDialog(m_doc, this);
+
+ configDlg->showAudioPage();
+ configDlg->show();
+}
+
+void RosegardenGUIApp::slotEditKeys()
+{
+ KKeyDialog::configure(actionCollection());
+}
+
+void RosegardenGUIApp::slotEditToolbars()
+{
+ KEditToolbar dlg(actionCollection(), "rosegardenui.rc");
+
+ connect(&dlg, SIGNAL(newToolbarConfig()),
+ SLOT(slotUpdateToolbars()));
+
+ dlg.exec();
+}
+
+void RosegardenGUIApp::slotUpdateToolbars()
+{
+ createGUI("rosegardenui.rc");
+ m_viewToolBar->setChecked(!toolBar()->isHidden());
+}
+
+void RosegardenGUIApp::slotEditTempo()
+{
+ slotEditTempo(this);
+}
+
+void RosegardenGUIApp::slotEditTempo(timeT atTime)
+{
+ slotEditTempo(this, atTime);
+}
+
+void RosegardenGUIApp::slotEditTempo(QWidget *parent)
+{
+ slotEditTempo(parent, m_doc->getComposition().getPosition());
+}
+
+void RosegardenGUIApp::slotEditTempo(QWidget *parent, timeT atTime)
+{
+ RG_DEBUG << "RosegardenGUIApp::slotEditTempo\n";
+
+ TempoDialog tempoDialog(parent, m_doc);
+
+ connect(&tempoDialog,
+ SIGNAL(changeTempo(timeT,
+ tempoT,
+ tempoT,
+ TempoDialog::TempoDialogAction)),
+ SLOT(slotChangeTempo(timeT,
+ tempoT,
+ tempoT,
+ TempoDialog::TempoDialogAction)));
+
+ tempoDialog.setTempoPosition(atTime);
+ tempoDialog.exec();
+}
+
+void RosegardenGUIApp::slotEditTimeSignature()
+{
+ slotEditTimeSignature(this);
+}
+
+void RosegardenGUIApp::slotEditTimeSignature(timeT atTime)
+{
+ slotEditTimeSignature(this, atTime);
+}
+
+void RosegardenGUIApp::slotEditTimeSignature(QWidget *parent)
+{
+ slotEditTimeSignature(parent, m_doc->getComposition().getPosition());
+}
+
+void RosegardenGUIApp::slotEditTimeSignature(QWidget *parent,
+ timeT time)
+{
+ Composition &composition(m_doc->getComposition());
+
+ TimeSignature sig = composition.getTimeSignatureAt(time);
+
+ TimeSignatureDialog dialog(parent, &composition, time, sig);
+
+ if (dialog.exec() == QDialog::Accepted) {
+
+ time = dialog.getTime();
+
+ if (dialog.shouldNormalizeRests()) {
+ m_doc->getCommandHistory()->addCommand
+ (new AddTimeSignatureAndNormalizeCommand
+ (&composition, time, dialog.getTimeSignature()));
+ } else {
+ m_doc->getCommandHistory()->addCommand
+ (new AddTimeSignatureCommand
+ (&composition, time, dialog.getTimeSignature()));
+ }
+ }
+}
+
+void RosegardenGUIApp::slotEditTransportTime()
+{
+ slotEditTransportTime(this);
+}
+
+void RosegardenGUIApp::slotEditTransportTime(QWidget *parent)
+{
+ TimeDialog dialog(parent, i18n("Move playback pointer to time"),
+ &m_doc->getComposition(),
+ m_doc->getComposition().getPosition(),
+ true);
+ if (dialog.exec() == QDialog::Accepted) {
+ m_doc->slotSetPointerPosition(dialog.getTime());
+ }
+}
+
+void RosegardenGUIApp::slotChangeZoom(int)
+{
+ double duration44 = TimeSignature(4, 4).getBarDuration();
+ double value = double(m_zoomSlider->getCurrentSize());
+ m_zoomLabel->setText(i18n("%1%").arg(duration44 / value));
+
+ RG_DEBUG << "RosegardenGUIApp::slotChangeZoom : zoom size = "
+ << m_zoomSlider->getCurrentSize() << endl;
+
+ // initZoomToolbar sets the zoom value. With some old versions of
+ // Qt3.0, this can cause slotChangeZoom() to be called while the
+ // view hasn't been initialized yet, so we need to check it's not
+ // null
+ //
+ if (m_view)
+ m_view->setZoomSize(m_zoomSlider->getCurrentSize());
+
+ long newZoom = int(m_zoomSlider->getCurrentSize() * 1000.0);
+
+ if (m_doc->getConfiguration().get<Int>
+ (DocumentConfiguration::ZoomLevel) != newZoom) {
+
+ m_doc->getConfiguration().set<Int>
+ (DocumentConfiguration::ZoomLevel, newZoom);
+
+ m_doc->slotDocumentModified();
+ }
+}
+
+void
+RosegardenGUIApp::slotZoomIn()
+{
+ m_zoomSlider->increment();
+}
+
+void
+RosegardenGUIApp::slotZoomOut()
+{
+ m_zoomSlider->decrement();
+}
+
+void
+RosegardenGUIApp::slotChangeTempo(timeT time,
+ tempoT value,
+ tempoT target,
+ TempoDialog::TempoDialogAction action)
+{
+ //!!! handle target
+
+ Composition &comp = m_doc->getComposition();
+
+ // We define a macro command here and build up the command
+ // label as we add commands on.
+ //
+ if (action == TempoDialog::AddTempo) {
+ m_doc->getCommandHistory()->addCommand
+ (new AddTempoChangeCommand(&comp, time, value, target));
+ } else if (action == TempoDialog::ReplaceTempo) {
+ int index = comp.getTempoChangeNumberAt(time);
+
+ // if there's no previous tempo change then just set globally
+ //
+ if (index == -1) {
+ m_doc->getCommandHistory()->addCommand
+ (new AddTempoChangeCommand(&comp, 0, value, target));
+ return ;
+ }
+
+ // get time of previous tempo change
+ timeT prevTime = comp.getTempoChange(index).first;
+
+ KMacroCommand *macro =
+ new KMacroCommand(i18n("Replace Tempo Change at %1").arg(time));
+
+ macro->addCommand(new RemoveTempoChangeCommand(&comp, index));
+ macro->addCommand(new AddTempoChangeCommand(&comp, prevTime, value,
+ target));
+
+ m_doc->getCommandHistory()->addCommand(macro);
+
+ } else if (action == TempoDialog::AddTempoAtBarStart) {
+ m_doc->getCommandHistory()->addCommand(new
+ AddTempoChangeCommand(&comp, comp.getBarStartForTime(time),
+ value, target));
+ } else if (action == TempoDialog::GlobalTempo ||
+ action == TempoDialog::GlobalTempoWithDefault) {
+ KMacroCommand *macro = new KMacroCommand(i18n("Set Global Tempo"));
+
+ // Remove all tempo changes in reverse order so as the index numbers
+ // don't becoming meaningless as the command gets unwound.
+ //
+ for (int i = 0; i < comp.getTempoChangeCount(); i++)
+ macro->addCommand(new RemoveTempoChangeCommand(&comp,
+ (comp.getTempoChangeCount() - 1 - i)));
+
+ // add tempo change at time zero
+ //
+ macro->addCommand(new AddTempoChangeCommand(&comp, 0, value, target));
+
+ // are we setting default too?
+ //
+ if (action == TempoDialog::GlobalTempoWithDefault) {
+ macro->setName(i18n("Set Global and Default Tempo"));
+ macro->addCommand(new ModifyDefaultTempoCommand(&comp, value));
+ }
+
+ m_doc->getCommandHistory()->addCommand(macro);
+
+ } else {
+ RG_DEBUG << "RosegardenGUIApp::slotChangeTempo() - "
+ << "unrecognised tempo command" << endl;
+ }
+}
+
+void
+RosegardenGUIApp::slotMoveTempo(timeT oldTime,
+ timeT newTime)
+{
+ Composition &comp = m_doc->getComposition();
+ int index = comp.getTempoChangeNumberAt(oldTime);
+
+ if (index < 0)
+ return ;
+
+ KMacroCommand *macro =
+ new KMacroCommand(i18n("Move Tempo Change"));
+
+ std::pair<timeT, tempoT> tc =
+ comp.getTempoChange(index);
+ std::pair<bool, tempoT> tr =
+ comp.getTempoRamping(index, false);
+
+ macro->addCommand(new RemoveTempoChangeCommand(&comp, index));
+ macro->addCommand(new AddTempoChangeCommand(&comp,
+ newTime,
+ tc.second,
+ tr.first ? tr.second : -1));
+
+ m_doc->getCommandHistory()->addCommand(macro);
+}
+
+void
+RosegardenGUIApp::slotDeleteTempo(timeT t)
+{
+ Composition &comp = m_doc->getComposition();
+ int index = comp.getTempoChangeNumberAt(t);
+
+ if (index < 0)
+ return ;
+
+ m_doc->getCommandHistory()->addCommand(new RemoveTempoChangeCommand
+ (&comp, index));
+}
+
+void
+RosegardenGUIApp::slotAddMarker(timeT time)
+{
+ AddMarkerCommand *command =
+ new AddMarkerCommand(&m_doc->getComposition(),
+ time,
+ i18n("new marker"),
+ i18n("no description"));
+
+ m_doc->getCommandHistory()->addCommand(command);
+}
+
+void
+RosegardenGUIApp::slotDeleteMarker(int id, timeT time, QString name, QString description)
+{
+ RemoveMarkerCommand *command =
+ new RemoveMarkerCommand(&m_doc->getComposition(),
+ id,
+ time,
+ qstrtostr(name),
+ qstrtostr(description));
+
+ m_doc->getCommandHistory()->addCommand(command);
+}
+
+void
+RosegardenGUIApp::slotDocumentModified(bool m)
+{
+ RG_DEBUG << "RosegardenGUIApp::slotDocumentModified(" << m << ") - doc path = "
+ << m_doc->getAbsFilePath() << endl;
+
+ if (!m_doc->getAbsFilePath().isEmpty()) {
+ slotStateChanged("saved_file_modified", m);
+ } else {
+ slotStateChanged("new_file_modified", m);
+ }
+
+}
+
+void
+RosegardenGUIApp::slotStateChanged(QString s,
+ bool noReverse)
+{
+ // RG_DEBUG << "RosegardenGUIApp::slotStateChanged " << s << "," << noReverse << endl;
+
+ stateChanged(s, noReverse ? KXMLGUIClient::StateNoReverse : KXMLGUIClient::StateReverse);
+}
+
+void
+RosegardenGUIApp::slotTestClipboard()
+{
+ if (m_clipboard->isEmpty()) {
+ stateChanged("have_clipboard", KXMLGUIClient::StateReverse);
+ stateChanged("have_clipboard_single_segment",
+ KXMLGUIClient::StateReverse);
+ } else {
+ stateChanged("have_clipboard", KXMLGUIClient::StateNoReverse);
+ stateChanged("have_clipboard_single_segment",
+ (m_clipboard->isSingleSegment() ?
+ KXMLGUIClient::StateNoReverse :
+ KXMLGUIClient::StateReverse));
+ }
+}
+
+void
+RosegardenGUIApp::plugAccelerators(QWidget *widget, QAccel *acc)
+{
+
+ acc->connectItem(acc->insertItem(Key_Enter),
+ this,
+ SLOT(slotPlay()));
+ // Alternative shortcut for Play
+ acc->connectItem(acc->insertItem(Key_Return + CTRL),
+ this,
+ SLOT(slotPlay()));
+
+ acc->connectItem(acc->insertItem(Key_Insert),
+ this,
+ SLOT(slotStop()));
+
+ acc->connectItem(acc->insertItem(Key_PageDown),
+ this,
+ SLOT(slotFastforward()));
+
+ acc->connectItem(acc->insertItem(Key_End),
+ this,
+ SLOT(slotRewind()));
+
+ acc->connectItem(acc->insertItem(Key_Space),
+ this,
+ SLOT(slotToggleRecord()));
+
+ TransportDialog *transport =
+ dynamic_cast<TransportDialog*>(widget);
+
+ if (transport) {
+ acc->connectItem(acc->insertItem(m_jumpToQuickMarkerAction->shortcut()),
+ this,
+ SLOT(slotJumpToQuickMarker()));
+
+ acc->connectItem(acc->insertItem(m_setQuickMarkerAction->shortcut()),
+ this,
+ SLOT(slotSetQuickMarker()));
+
+ connect(transport->PlayButton(),
+ SIGNAL(clicked()),
+ this,
+ SLOT(slotPlay()));
+
+ connect(transport->StopButton(),
+ SIGNAL(clicked()),
+ this,
+ SLOT(slotStop()));
+
+ connect(transport->FfwdButton(),
+ SIGNAL(clicked()),
+ SLOT(slotFastforward()));
+
+ connect(transport->RewindButton(),
+ SIGNAL(clicked()),
+ this,
+ SLOT(slotRewind()));
+
+ connect(transport->RecordButton(),
+ SIGNAL(clicked()),
+ this,
+ SLOT(slotRecord()));
+
+ connect(transport->RewindEndButton(),
+ SIGNAL(clicked()),
+ this,
+ SLOT(slotRewindToBeginning()));
+
+ connect(transport->FfwdEndButton(),
+ SIGNAL(clicked()),
+ this,
+ SLOT(slotFastForwardToEnd()));
+
+ connect(transport->MetronomeButton(),
+ SIGNAL(clicked()),
+ this,
+ SLOT(slotToggleMetronome()));
+
+ connect(transport->SoloButton(),
+ SIGNAL(toggled(bool)),
+ this,
+ SLOT(slotToggleSolo(bool)));
+
+ connect(transport->TimeDisplayButton(),
+ SIGNAL(clicked()),
+ this,
+ SLOT(slotRefreshTimeDisplay()));
+
+ connect(transport->ToEndButton(),
+ SIGNAL(clicked()),
+ SLOT(slotRefreshTimeDisplay()));
+ }
+}
+
+void
+RosegardenGUIApp::setCursor(const QCursor& cursor)
+{
+ KDockMainWindow::setCursor(cursor);
+
+ // play it safe, so we can use this class at anytime even very early in the app init
+ if ((getView() &&
+ getView()->getTrackEditor() &&
+ getView()->getTrackEditor()->getSegmentCanvas() &&
+ getView()->getTrackEditor()->getSegmentCanvas()->viewport())) {
+
+ getView()->getTrackEditor()->getSegmentCanvas()->viewport()->setCursor(cursor);
+ }
+
+ // view, main window...
+ //
+ getView()->setCursor(cursor);
+
+ // toolbars...
+ //
+ QPtrListIterator<KToolBar> tbIter = toolBarIterator();
+ KToolBar* tb = 0;
+ while ((tb = tbIter.current()) != 0) {
+ tb->setCursor(cursor);
+ ++tbIter;
+ }
+
+ m_dockLeft->setCursor(cursor);
+}
+
+QString
+RosegardenGUIApp::createNewAudioFile()
+{
+ AudioFile *aF = 0;
+ try {
+ aF = m_doc->getAudioFileManager().createRecordingAudioFile();
+ if (!aF) {
+ // createRecordingAudioFile doesn't actually write to the disk,
+ // and in principle it shouldn't fail
+ std::cerr << "ERROR: RosegardenGUIApp::createNewAudioFile: Failed to create recording audio file" << std::endl;
+ return "";
+ } else {
+ return aF->getFilename().c_str();
+ }
+ } catch (AudioFileManager::BadAudioPathException e) {
+ delete aF;
+ std::cerr << "ERROR: RosegardenGUIApp::createNewAudioFile: Failed to create recording audio file: " << e.getMessage() << std::endl;
+ return "";
+ }
+}
+
+QValueVector<QString>
+RosegardenGUIApp::createRecordAudioFiles(const QValueVector<InstrumentId> &recordInstruments)
+{
+ QValueVector<QString> qv;
+ for (unsigned int i = 0; i < recordInstruments.size(); ++i) {
+ AudioFile *aF = 0;
+ try {
+ aF = m_doc->getAudioFileManager().createRecordingAudioFile();
+ if (aF) {
+ // createRecordingAudioFile doesn't actually write to the disk,
+ // and in principle it shouldn't fail
+ qv.push_back(aF->getFilename().c_str());
+ m_doc->addRecordAudioSegment(recordInstruments[i],
+ aF->getId());
+ } else {
+ std::cerr << "ERROR: RosegardenGUIApp::createRecordAudioFiles: Failed to create recording audio file" << std::endl;
+ return qv;
+ }
+ } catch (AudioFileManager::BadAudioPathException e) {
+ delete aF;
+ std::cerr << "ERROR: RosegardenGUIApp::createRecordAudioFiles: Failed to create recording audio file: " << e.getMessage() << std::endl;
+ return qv;
+ }
+ }
+ return qv;
+}
+
+QString
+RosegardenGUIApp::getAudioFilePath()
+{
+ return QString(m_doc->getAudioFileManager().getAudioPath().c_str());
+}
+
+QValueVector<InstrumentId>
+RosegardenGUIApp::getArmedInstruments()
+{
+ std::set
+ <InstrumentId> iid;
+
+ const Composition::recordtrackcontainer &tr =
+ m_doc->getComposition().getRecordTracks();
+
+ for (Composition::recordtrackcontainer::const_iterator i =
+ tr.begin(); i != tr.end(); ++i) {
+ TrackId tid = (*i);
+ Track *track = m_doc->getComposition().getTrackById(tid);
+ if (track) {
+ iid.insert(track->getInstrument());
+ } else {
+ std::cerr << "Warning: RosegardenGUIApp::getArmedInstruments: Armed track " << tid << " not found in Composition" << std::endl;
+ }
+ }
+
+ QValueVector<InstrumentId> iv;
+ for (std::set
+ <InstrumentId>::iterator ii = iid.begin();
+ ii != iid.end(); ++ii) {
+ iv.push_back(*ii);
+ }
+ return iv;
+}
+
+void
+RosegardenGUIApp::showError(QString error)
+{
+ KStartupLogo::hideIfStillThere();
+ CurrentProgressDialog::freeze();
+
+ // This is principally used for return values from DSSI plugin
+ // configure() calls. It seems some plugins return a string
+ // telling you when everything's OK, as well as error strings, but
+ // dssi.h does make it reasonably clear that configure() should
+ // only return a string when there is actually a problem, so we're
+ // going to stick with a sorry dialog here rather than an
+ // information one
+
+ KMessageBox::sorry(0, error);
+
+ CurrentProgressDialog::thaw();
+}
+
+void
+RosegardenGUIApp::slotAudioManager()
+{
+ if (m_audioManagerDialog) {
+ m_audioManagerDialog->show();
+ m_audioManagerDialog->raise();
+ m_audioManagerDialog->setActiveWindow();
+ return ;
+ }
+
+ m_audioManagerDialog =
+ new AudioManagerDialog(this, m_doc);
+
+ connect(m_audioManagerDialog,
+ SIGNAL(playAudioFile(AudioFileId,
+ const RealTime &,
+ const RealTime&)),
+ SLOT(slotPlayAudioFile(AudioFileId,
+ const RealTime &,
+ const RealTime &)));
+
+ connect(m_audioManagerDialog,
+ SIGNAL(addAudioFile(AudioFileId)),
+ SLOT(slotAddAudioFile(AudioFileId)));
+
+ connect(m_audioManagerDialog,
+ SIGNAL(deleteAudioFile(AudioFileId)),
+ SLOT(slotDeleteAudioFile(AudioFileId)));
+
+ //
+ // Sync segment selection between audio man. dialog and main window
+ //
+
+ // from dialog to us...
+ connect(m_audioManagerDialog,
+ SIGNAL(segmentsSelected(const SegmentSelection&)),
+ m_view,
+ SLOT(slotPropagateSegmentSelection(const SegmentSelection&)));
+
+ // and from us to dialog
+ connect(this, SIGNAL(segmentsSelected(const SegmentSelection&)),
+ m_audioManagerDialog,
+ SLOT(slotSegmentSelection(const SegmentSelection&)));
+
+
+ connect(m_audioManagerDialog,
+ SIGNAL(deleteSegments(const SegmentSelection&)),
+ SLOT(slotDeleteSegments(const SegmentSelection&)));
+
+ connect(m_audioManagerDialog,
+ SIGNAL(insertAudioSegment(AudioFileId,
+ const RealTime&,
+ const RealTime&)),
+ m_view,
+ SLOT(slotAddAudioSegmentDefaultPosition(AudioFileId,
+ const RealTime&,
+ const RealTime&)));
+ connect(m_audioManagerDialog,
+ SIGNAL(cancelPlayingAudioFile(AudioFileId)),
+ SLOT(slotCancelAudioPlayingFile(AudioFileId)));
+
+ connect(m_audioManagerDialog,
+ SIGNAL(deleteAllAudioFiles()),
+ SLOT(slotDeleteAllAudioFiles()));
+
+ // Make sure we know when the audio man. dialog is closing
+ //
+ connect(m_audioManagerDialog,
+ SIGNAL(closing()),
+ SLOT(slotAudioManagerClosed()));
+
+ // And that it goes away when the current document is changing
+ //
+ connect(this, SIGNAL(documentAboutToChange()),
+ m_audioManagerDialog, SLOT(close()));
+
+ m_audioManagerDialog->setAudioSubsystemStatus(
+ m_seqManager->getSoundDriverStatus() & AUDIO_OK);
+
+ plugAccelerators(m_audioManagerDialog,
+ m_audioManagerDialog->getAccelerators());
+
+ m_audioManagerDialog->show();
+}
+
+void
+RosegardenGUIApp::slotPlayAudioFile(unsigned int id,
+ const RealTime &startTime,
+ const RealTime &duration)
+{
+ AudioFile *aF = m_doc->getAudioFileManager().getAudioFile(id);
+
+ if (aF == 0)
+ return ;
+
+ MappedEvent mE(m_doc->getStudio().
+ getAudioPreviewInstrument(),
+ id,
+ RealTime( -120, 0),
+ duration, // duration
+ startTime); // start index
+
+ StudioControl::sendMappedEvent(mE);
+
+}
+
+void
+RosegardenGUIApp::slotAddAudioFile(unsigned int id)
+{
+ AudioFile *aF = m_doc->getAudioFileManager().getAudioFile(id);
+
+ if (aF == 0)
+ return ;
+
+ QCString replyType;
+ QByteArray replyData;
+ QByteArray data;
+ QDataStream streamOut(data, IO_WriteOnly);
+
+ // We have to pass the filename as a QString
+ //
+ streamOut << QString(strtoqstr(aF->getFilename()));
+ streamOut << (int)aF->getId();
+
+ if (rgapp->sequencerCall("addAudioFile(QString, int)", replyType, replyData, data)) {
+ QDataStream streamIn(replyData, IO_ReadOnly);
+ int result;
+ streamIn >> result;
+ if (!result) {
+ KMessageBox::error(this, i18n("Sequencer failed to add audio file %1").arg(aF->getFilename().c_str()));
+ }
+ }
+}
+
+void
+RosegardenGUIApp::slotDeleteAudioFile(unsigned int id)
+{
+ if (m_doc->getAudioFileManager().removeFile(id) == false)
+ return ;
+
+ QCString replyType;
+ QByteArray replyData;
+ QByteArray data;
+ QDataStream streamOut(data, IO_WriteOnly);
+
+ // file id
+ //
+ streamOut << (int)id;
+
+ if (rgapp->sequencerCall("removeAudioFile(int)", replyType, replyData, data)) {
+ QDataStream streamIn(replyData, IO_ReadOnly);
+ int result;
+ streamIn >> result;
+ if (!result) {
+ KMessageBox::error(this, i18n("Sequencer failed to remove audio file id %1").arg(id));
+ }
+ }
+}
+
+void
+RosegardenGUIApp::slotDeleteSegments(const SegmentSelection &selection)
+{
+ m_view->slotPropagateSegmentSelection(selection);
+ slotDeleteSelectedSegments();
+}
+
+void
+RosegardenGUIApp::slotCancelAudioPlayingFile(AudioFileId id)
+{
+ AudioFile *aF = m_doc->getAudioFileManager().getAudioFile(id);
+
+ if (aF == 0)
+ return ;
+
+ MappedEvent mE(m_doc->getStudio().
+ getAudioPreviewInstrument(),
+ MappedEvent::AudioCancel,
+ id);
+
+ StudioControl::sendMappedEvent(mE);
+}
+
+void
+RosegardenGUIApp::slotDeleteAllAudioFiles()
+{
+ m_doc->getAudioFileManager().clear();
+
+ // Clear at the sequencer
+ //
+ QCString replyType;
+ QByteArray replyData;
+ QByteArray data;
+
+ rgapp->sequencerCall("clearAllAudioFiles()", replyType, replyData, data);
+}
+
+void
+RosegardenGUIApp::slotRepeatingSegments()
+{
+ m_view->getTrackEditor()->slotTurnRepeatingSegmentToRealCopies();
+}
+
+void
+RosegardenGUIApp::slotRelabelSegments()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ SegmentSelection selection(m_view->getSelection());
+ QString editLabel;
+
+ if (selection.size() == 0)
+ return ;
+ else if (selection.size() == 1)
+ editLabel = i18n("Modify Segment label");
+ else
+ editLabel = i18n("Modify Segments label");
+
+ KTmpStatusMsg msg(i18n("Relabelling selection..."), this);
+
+ // Generate label
+ QString label = strtoqstr((*selection.begin())->getLabel());
+
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+ if (strtoqstr((*i)->getLabel()) != label)
+ label = "";
+ }
+
+ bool ok = false;
+
+ QString newLabel = KInputDialog::getText(editLabel,
+ i18n("Enter new label"),
+ label,
+ &ok,
+ this);
+
+ if (ok) {
+ m_doc->getCommandHistory()->addCommand
+ (new SegmentLabelCommand(selection, newLabel));
+ m_view->getTrackEditor()->getSegmentCanvas()->slotUpdateSegmentsDrawBuffer();
+ }
+}
+
+void
+RosegardenGUIApp::slotTransposeSegments()
+{
+ if (!m_view->haveSelection())
+ return ;
+
+ IntervalDialog intervalDialog(this, true, true);
+ int ok = intervalDialog.exec();
+
+ int semitones = intervalDialog.getChromaticDistance();
+ int steps = intervalDialog.getDiatonicDistance();
+
+ if (!ok || (semitones == 0 && steps == 0)) return;
+
+ m_doc->getCommandHistory()->addCommand
+ (new SegmentTransposeCommand(m_view->getSelection(), intervalDialog.getChangeKey(), steps, semitones, intervalDialog.getTransposeSegmentBack()));
+}
+
+void
+RosegardenGUIApp::slotChangeCompositionLength()
+{
+ CompositionLengthDialog dialog(this, &m_doc->getComposition());
+
+ if (dialog.exec() == QDialog::Accepted) {
+ ChangeCompositionLengthCommand *command
+ = new ChangeCompositionLengthCommand(
+ &m_doc->getComposition(),
+ dialog.getStartMarker(),
+ dialog.getEndMarker());
+
+ m_view->getTrackEditor()->getSegmentCanvas()->clearSegmentRectsCache(true);
+ m_doc->getCommandHistory()->addCommand(command);
+ }
+}
+
+void
+RosegardenGUIApp::slotManageMIDIDevices()
+{
+ if (m_deviceManager) {
+ m_deviceManager->show();
+ m_deviceManager->raise();
+ m_deviceManager->setActiveWindow();
+ return ;
+ }
+
+ m_deviceManager = new DeviceManagerDialog(this, m_doc);
+
+ connect(m_deviceManager, SIGNAL(closing()),
+ this, SLOT(slotDeviceManagerClosed()));
+
+ connect(this, SIGNAL(documentAboutToChange()),
+ m_deviceManager, SLOT(close()));
+
+ // Cheating way of updating the track/instrument list
+ //
+ connect(m_deviceManager, SIGNAL(deviceNamesChanged()),
+ m_view, SLOT(slotSynchroniseWithComposition()));
+
+ connect(m_deviceManager, SIGNAL(editBanks(DeviceId)),
+ this, SLOT(slotEditBanks(DeviceId)));
+
+ connect(m_deviceManager, SIGNAL(editControllers(DeviceId)),
+ this, SLOT(slotEditControlParameters(DeviceId)));
+
+ if (m_midiMixer) {
+ connect(m_deviceManager, SIGNAL(deviceNamesChanged()),
+ m_midiMixer, SLOT(slotSynchronise()));
+
+ }
+
+
+ m_deviceManager->show();
+}
+
+void
+RosegardenGUIApp::slotManageSynths()
+{
+ if (m_synthManager) {
+ m_synthManager->show();
+ m_synthManager->raise();
+ m_synthManager->setActiveWindow();
+ return ;
+ }
+
+ m_synthManager = new SynthPluginManagerDialog(this, m_doc
+#ifdef HAVE_LIBLO
+ , m_pluginGUIManager
+#endif
+ );
+
+ connect(m_synthManager, SIGNAL(closing()),
+ this, SLOT(slotSynthPluginManagerClosed()));
+
+ connect(this, SIGNAL(documentAboutToChange()),
+ m_synthManager, SLOT(close()));
+
+ connect(m_synthManager,
+ SIGNAL(pluginSelected(InstrumentId, int, int)),
+ this,
+ SLOT(slotPluginSelected(InstrumentId, int, int)));
+
+ connect(m_synthManager,
+ SIGNAL(showPluginDialog(QWidget *, InstrumentId, int)),
+ this,
+ SLOT(slotShowPluginDialog(QWidget *, InstrumentId, int)));
+
+ connect(m_synthManager,
+ SIGNAL(showPluginGUI(InstrumentId, int)),
+ this,
+ SLOT(slotShowPluginGUI(InstrumentId, int)));
+
+ m_synthManager->show();
+}
+
+void
+RosegardenGUIApp::slotOpenAudioMixer()
+{
+ if (m_audioMixer) {
+ m_audioMixer->show();
+ m_audioMixer->raise();
+ m_audioMixer->setActiveWindow();
+ return ;
+ }
+
+ m_audioMixer = new AudioMixerWindow(this, m_doc);
+
+ connect(m_audioMixer, SIGNAL(windowActivated()),
+ m_view, SLOT(slotActiveMainWindowChanged()));
+
+ connect(m_view, SIGNAL(controllerDeviceEventReceived(MappedEvent *, const void *)),
+ m_audioMixer, SLOT(slotControllerDeviceEventReceived(MappedEvent *, const void *)));
+
+ connect(m_audioMixer, SIGNAL(closing()),
+ this, SLOT(slotAudioMixerClosed()));
+
+ connect(m_audioMixer, SIGNAL(selectPlugin(QWidget *, InstrumentId, int)),
+ this, SLOT(slotShowPluginDialog(QWidget *, InstrumentId, int)));
+
+ connect(this,
+ SIGNAL(pluginSelected(InstrumentId, int, int)),
+ m_audioMixer,
+ SLOT(slotPluginSelected(InstrumentId, int, int)));
+
+ connect(this,
+ SIGNAL(pluginBypassed(InstrumentId, int, bool)),
+ m_audioMixer,
+ SLOT(slotPluginBypassed(InstrumentId, int, bool)));
+
+ connect(this, SIGNAL(documentAboutToChange()),
+ m_audioMixer, SLOT(close()));
+
+ connect(m_view, SIGNAL(checkTrackAssignments()),
+ m_audioMixer, SLOT(slotTrackAssignmentsChanged()));
+
+ connect(m_audioMixer, SIGNAL(play()),
+ this, SLOT(slotPlay()));
+ connect(m_audioMixer, SIGNAL(stop()),
+ this, SLOT(slotStop()));
+ connect(m_audioMixer, SIGNAL(fastForwardPlayback()),
+ this, SLOT(slotFastforward()));
+ connect(m_audioMixer, SIGNAL(rewindPlayback()),
+ this, SLOT(slotRewind()));
+ connect(m_audioMixer, SIGNAL(fastForwardPlaybackToEnd()),
+ this, SLOT(slotFastForwardToEnd()));
+ connect(m_audioMixer, SIGNAL(rewindPlaybackToBeginning()),
+ this, SLOT(slotRewindToBeginning()));
+ connect(m_audioMixer, SIGNAL(record()),
+ this, SLOT(slotRecord()));
+ connect(m_audioMixer, SIGNAL(panic()),
+ this, SLOT(slotPanic()));
+
+ connect(m_audioMixer,
+ SIGNAL(instrumentParametersChanged(InstrumentId)),
+ this,
+ SIGNAL(instrumentParametersChanged(InstrumentId)));
+
+ connect(this,
+ SIGNAL(instrumentParametersChanged(InstrumentId)),
+ m_audioMixer,
+ SLOT(slotUpdateInstrument(InstrumentId)));
+
+ if (m_synthManager) {
+ connect(m_synthManager,
+ SIGNAL(pluginSelected(InstrumentId, int, int)),
+ m_audioMixer,
+ SLOT(slotPluginSelected(InstrumentId, int, int)));
+ }
+
+ plugAccelerators(m_audioMixer, m_audioMixer->getAccelerators());
+
+ m_audioMixer->show();
+}
+
+void
+RosegardenGUIApp::slotOpenMidiMixer()
+{
+ if (m_midiMixer) {
+ m_midiMixer->show();
+ m_midiMixer->raise();
+ m_midiMixer->setActiveWindow();
+ return ;
+ }
+
+ m_midiMixer = new MidiMixerWindow(this, m_doc);
+
+ connect(m_midiMixer, SIGNAL(windowActivated()),
+ m_view, SLOT(slotActiveMainWindowChanged()));
+
+ connect(m_view, SIGNAL(controllerDeviceEventReceived(MappedEvent *, const void *)),
+ m_midiMixer, SLOT(slotControllerDeviceEventReceived(MappedEvent *, const void *)));
+
+ connect(m_midiMixer, SIGNAL(closing()),
+ this, SLOT(slotMidiMixerClosed()));
+
+ connect(this, SIGNAL(documentAboutToChange()),
+ m_midiMixer, SLOT(close()));
+
+ connect(m_midiMixer, SIGNAL(play()),
+ this, SLOT(slotPlay()));
+ connect(m_midiMixer, SIGNAL(stop()),
+ this, SLOT(slotStop()));
+ connect(m_midiMixer, SIGNAL(fastForwardPlayback()),
+ this, SLOT(slotFastforward()));
+ connect(m_midiMixer, SIGNAL(rewindPlayback()),
+ this, SLOT(slotRewind()));
+ connect(m_midiMixer, SIGNAL(fastForwardPlaybackToEnd()),
+ this, SLOT(slotFastForwardToEnd()));
+ connect(m_midiMixer, SIGNAL(rewindPlaybackToBeginning()),
+ this, SLOT(slotRewindToBeginning()));
+ connect(m_midiMixer, SIGNAL(record()),
+ this, SLOT(slotRecord()));
+ connect(m_midiMixer, SIGNAL(panic()),
+ this, SLOT(slotPanic()));
+
+ connect(m_midiMixer,
+ SIGNAL(instrumentParametersChanged(InstrumentId)),
+ this,
+ SIGNAL(instrumentParametersChanged(InstrumentId)));
+
+ connect(this,
+ SIGNAL(instrumentParametersChanged(InstrumentId)),
+ m_midiMixer,
+ SLOT(slotUpdateInstrument(InstrumentId)));
+
+ plugAccelerators(m_midiMixer, m_midiMixer->getAccelerators());
+
+ m_midiMixer->show();
+}
+
+void
+RosegardenGUIApp::slotEditControlParameters(DeviceId device)
+{
+ for (std::set
+ <ControlEditorDialog *>::iterator i = m_controlEditors.begin();
+ i != m_controlEditors.end(); ++i) {
+ if ((*i)->getDevice() == device) {
+ (*i)->show();
+ (*i)->raise();
+ (*i)->setActiveWindow();
+ return ;
+ }
+ }
+
+ ControlEditorDialog *controlEditor = new ControlEditorDialog(this, m_doc,
+ device);
+ m_controlEditors.insert(controlEditor);
+
+ RG_DEBUG << "inserting control editor dialog, have " << m_controlEditors.size() << " now" << endl;
+
+ connect(controlEditor, SIGNAL(closing()),
+ SLOT(slotControlEditorClosed()));
+
+ connect(this, SIGNAL(documentAboutToChange()),
+ controlEditor, SLOT(close()));
+
+ connect(m_doc, SIGNAL(devicesResyncd()),
+ controlEditor, SLOT(slotUpdate()));
+
+ controlEditor->show();
+}
+
+void
+RosegardenGUIApp::slotEditBanks()
+{
+ slotEditBanks(Device::NO_DEVICE);
+}
+
+void
+RosegardenGUIApp::slotEditBanks(DeviceId device)
+{
+ if (m_bankEditor) {
+ if (device != Device::NO_DEVICE)
+ m_bankEditor->setCurrentDevice(device);
+ m_bankEditor->show();
+ m_bankEditor->raise();
+ m_bankEditor->setActiveWindow();
+ return ;
+ }
+
+ m_bankEditor = new BankEditorDialog(this, m_doc, device);
+
+ connect(m_bankEditor, SIGNAL(closing()),
+ this, SLOT(slotBankEditorClosed()));
+
+ connect(this, SIGNAL(documentAboutToChange()),
+ m_bankEditor, SLOT(slotFileClose()));
+
+ // Cheating way of updating the track/instrument list
+ //
+ connect(m_bankEditor, SIGNAL(deviceNamesChanged()),
+ m_view, SLOT(slotSynchroniseWithComposition()));
+
+ m_bankEditor->show();
+}
+
+void
+RosegardenGUIApp::slotManageTriggerSegments()
+{
+ if (m_triggerSegmentManager) {
+ m_triggerSegmentManager->show();
+ m_triggerSegmentManager->raise();
+ m_triggerSegmentManager->setActiveWindow();
+ return ;
+ }
+
+ m_triggerSegmentManager = new TriggerSegmentManager(this, m_doc);
+
+ connect(m_triggerSegmentManager, SIGNAL(closing()),
+ SLOT(slotTriggerManagerClosed()));
+
+ connect(m_triggerSegmentManager, SIGNAL(editTriggerSegment(int)),
+ m_view, SLOT(slotEditTriggerSegment(int)));
+
+ m_triggerSegmentManager->show();
+}
+
+void
+RosegardenGUIApp::slotTriggerManagerClosed()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotTriggerManagerClosed" << endl;
+
+ m_triggerSegmentManager = 0;
+}
+
+void
+RosegardenGUIApp::slotEditMarkers()
+{
+ if (m_markerEditor) {
+ m_markerEditor->show();
+ m_markerEditor->raise();
+ m_markerEditor->setActiveWindow();
+ return ;
+ }
+
+ m_markerEditor = new MarkerEditor(this, m_doc);
+
+ connect(m_markerEditor, SIGNAL(closing()),
+ SLOT(slotMarkerEditorClosed()));
+
+ connect(m_markerEditor, SIGNAL(jumpToMarker(timeT)),
+ m_doc, SLOT(slotSetPointerPosition(timeT)));
+
+ plugAccelerators(m_markerEditor, m_markerEditor->getAccelerators());
+
+ m_markerEditor->show();
+}
+
+void
+RosegardenGUIApp::slotMarkerEditorClosed()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotMarkerEditorClosed" << endl;
+
+ m_markerEditor = 0;
+}
+
+void
+RosegardenGUIApp::slotEditTempos(timeT t)
+{
+ if (m_tempoView) {
+ m_tempoView->show();
+ m_tempoView->raise();
+ m_tempoView->setActiveWindow();
+ return ;
+ }
+
+ m_tempoView = new TempoView(m_doc, getView(), t);
+
+ connect(m_tempoView, SIGNAL(closing()),
+ SLOT(slotTempoViewClosed()));
+
+ connect(m_tempoView, SIGNAL(windowActivated()),
+ getView(), SLOT(slotActiveMainWindowChanged()));
+
+ connect(m_tempoView,
+ SIGNAL(changeTempo(timeT,
+ tempoT,
+ tempoT,
+ TempoDialog::TempoDialogAction)),
+ this,
+ SLOT(slotChangeTempo(timeT,
+ tempoT,
+ tempoT,
+ TempoDialog::TempoDialogAction)));
+
+ connect(m_tempoView, SIGNAL(saveFile()), this, SLOT(slotFileSave()));
+
+ plugAccelerators(m_tempoView, m_tempoView->getAccelerators());
+
+ m_tempoView->show();
+}
+
+void
+RosegardenGUIApp::slotTempoViewClosed()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotTempoViewClosed" << endl;
+
+ m_tempoView = 0;
+}
+
+void
+RosegardenGUIApp::slotControlEditorClosed()
+{
+ const QObject *s = sender();
+
+ RG_DEBUG << "RosegardenGUIApp::slotControlEditorClosed" << endl;
+
+ for (std::set
+ <ControlEditorDialog *>::iterator i = m_controlEditors.begin();
+ i != m_controlEditors.end(); ++i) {
+ if (*i == s) {
+ m_controlEditors.erase(i);
+ RG_DEBUG << "removed control editor dialog, have " << m_controlEditors.size() << " left" << endl;
+ return ;
+ }
+ }
+
+ std::cerr << "WARNING: control editor " << s << " closed, but couldn't find it in our control editor list (we have " << m_controlEditors.size() << " editors)" << std::endl;
+}
+
+void
+RosegardenGUIApp::slotShowPluginDialog(QWidget *parent,
+ InstrumentId instrumentId,
+ int index)
+{
+ if (!parent)
+ parent = this;
+
+ int key = (index << 16) + instrumentId;
+
+ if (m_pluginDialogs[key]) {
+ m_pluginDialogs[key]->show();
+ m_pluginDialogs[key]->raise();
+ m_pluginDialogs[key]->setActiveWindow();
+ return ;
+ }
+
+ PluginContainer *container = 0;
+
+ container = m_doc->getStudio().getContainerById(instrumentId);
+ if (!container) {
+ RG_DEBUG << "RosegardenGUIApp::slotShowPluginDialog - "
+ << "no instrument or buss of id " << instrumentId << endl;
+ return ;
+ }
+
+ // only create a dialog if we've got a plugin instance
+ AudioPluginInstance *inst =
+ container->getPlugin(index);
+
+ if (!inst) {
+ RG_DEBUG << "RosegardenGUIApp::slotShowPluginDialog - "
+ << "no AudioPluginInstance found for index "
+ << index << endl;
+ return ;
+ }
+
+ // Create the plugin dialog
+ //
+ AudioPluginDialog *dialog =
+ new AudioPluginDialog(parent,
+ m_doc->getPluginManager(),
+#ifdef HAVE_LIBLO
+ m_pluginGUIManager,
+#endif
+ container,
+ index);
+
+ connect(dialog, SIGNAL(windowActivated()),
+ m_view, SLOT(slotActiveMainWindowChanged()));
+
+/* This feature isn't provided by the plugin dialog
+ connect(m_view, SIGNAL(controllerDeviceEventReceived(MappedEvent *, const void *)),
+ dialog, SLOT(slotControllerDeviceEventReceived(MappedEvent *, const void *)));
+*/
+
+ // Plug the new dialog into the standard keyboard accelerators so
+ // that we can use them still while the plugin has focus.
+ //
+ plugAccelerators(dialog, dialog->getAccelerators());
+
+ connect(dialog,
+ SIGNAL(pluginSelected(InstrumentId, int, int)),
+ this,
+ SLOT(slotPluginSelected(InstrumentId, int, int)));
+
+ connect(dialog,
+ SIGNAL(pluginPortChanged(InstrumentId, int, int)),
+ this,
+ SLOT(slotPluginPortChanged(InstrumentId, int, int)));
+
+ connect(dialog,
+ SIGNAL(pluginProgramChanged(InstrumentId, int)),
+ this,
+ SLOT(slotPluginProgramChanged(InstrumentId, int)));
+
+ connect(dialog,
+ SIGNAL(changePluginConfiguration(InstrumentId, int, bool, QString, QString)),
+ this,
+ SLOT(slotChangePluginConfiguration(InstrumentId, int, bool, QString, QString)));
+
+ connect(dialog,
+ SIGNAL(showPluginGUI(InstrumentId, int)),
+ this,
+ SLOT(slotShowPluginGUI(InstrumentId, int)));
+
+ connect(dialog,
+ SIGNAL(stopPluginGUI(InstrumentId, int)),
+ this,
+ SLOT(slotStopPluginGUI(InstrumentId, int)));
+
+ connect(dialog,
+ SIGNAL(bypassed(InstrumentId, int, bool)),
+ this,
+ SLOT(slotPluginBypassed(InstrumentId, int, bool)));
+
+ connect(dialog,
+ SIGNAL(destroyed(InstrumentId, int)),
+ this,
+ SLOT(slotPluginDialogDestroyed(InstrumentId, int)));
+
+ connect(this, SIGNAL(documentAboutToChange()), dialog, SLOT(close()));
+
+ m_pluginDialogs[key] = dialog;
+ m_pluginDialogs[key]->show();
+
+ // Set modified
+ m_doc->slotDocumentModified();
+}
+
+void
+RosegardenGUIApp::slotPluginSelected(InstrumentId instrumentId,
+ int index, int plugin)
+{
+ const QObject *s = sender();
+
+ bool fromSynthMgr = (s == m_synthManager);
+
+ // It's assumed that ports etc will already have been set up on
+ // the AudioPluginInstance before this is invoked.
+
+ PluginContainer *container = 0;
+
+ container = m_doc->getStudio().getContainerById(instrumentId);
+ if (!container) {
+ RG_DEBUG << "RosegardenGUIApp::slotPluginSelected - "
+ << "no instrument or buss of id " << instrumentId << endl;
+ return ;
+ }
+
+ AudioPluginInstance *inst =
+ container->getPlugin(index);
+
+ if (!inst) {
+ RG_DEBUG << "RosegardenGUIApp::slotPluginSelected - "
+ << "got index of unknown plugin!" << endl;
+ return ;
+ }
+
+ if (plugin == -1) {
+ // Destroy plugin instance
+ //!!! seems iffy -- why can't we just unassign it?
+
+ if (StudioControl::
+ destroyStudioObject(inst->getMappedId())) {
+ RG_DEBUG << "RosegardenGUIApp::slotPluginSelected - "
+ << "cannot destroy Studio object "
+ << inst->getMappedId() << endl;
+ }
+
+ inst->setAssigned(false);
+ } else {
+ // If unassigned then create a sequencer instance of this
+ // AudioPluginInstance.
+ //
+ if (inst->isAssigned()) {
+ RG_DEBUG << "RosegardenGUIApp::slotPluginSelected - "
+ << " setting identifier for mapper id " << inst->getMappedId()
+ << " to " << inst->getIdentifier() << endl;
+
+ StudioControl::setStudioObjectProperty
+ (inst->getMappedId(),
+ MappedPluginSlot::Identifier,
+ strtoqstr(inst->getIdentifier()));
+ } else {
+ // create a studio object at the sequencer
+ MappedObjectId newId =
+ StudioControl::createStudioObject
+ (MappedObject::PluginSlot);
+
+ RG_DEBUG << "RosegardenGUIApp::slotPluginSelected - "
+ << " new MappedObjectId = " << newId << endl;
+
+ // set the new Mapped ID and that this instance
+ // is assigned
+ inst->setMappedId(newId);
+ inst->setAssigned(true);
+
+ // set the instrument id
+ StudioControl::setStudioObjectProperty
+ (newId,
+ MappedObject::Instrument,
+ MappedObjectValue(instrumentId));
+
+ // set the position
+ StudioControl::setStudioObjectProperty
+ (newId,
+ MappedObject::Position,
+ MappedObjectValue(index));
+
+ // set the plugin id
+ StudioControl::setStudioObjectProperty
+ (newId,
+ MappedPluginSlot::Identifier,
+ strtoqstr(inst->getIdentifier()));
+ }
+ }
+
+ int pluginMappedId = inst->getMappedId();
+
+ //!!! much code duplicated here from RosegardenGUIDoc::initialiseStudio
+
+ inst->setConfigurationValue
+ (qstrtostr(PluginIdentifier::RESERVED_PROJECT_DIRECTORY_KEY),
+ m_doc->getAudioFileManager().getAudioPath());
+
+ // Set opaque string configuration data (e.g. for DSSI plugin)
+ //
+ MappedObjectPropertyList config;
+ for (AudioPluginInstance::ConfigMap::const_iterator
+ i = inst->getConfiguration().begin();
+ i != inst->getConfiguration().end(); ++i) {
+ config.push_back(strtoqstr(i->first));
+ config.push_back(strtoqstr(i->second));
+ }
+ StudioControl::setStudioObjectPropertyList
+ (pluginMappedId,
+ MappedPluginSlot::Configuration,
+ config);
+
+ // Set the bypass
+ //
+ StudioControl::setStudioObjectProperty
+ (pluginMappedId,
+ MappedPluginSlot::Bypassed,
+ MappedObjectValue(inst->isBypassed()));
+
+ // Set the program
+ //
+ if (inst->getProgram() != "") {
+ StudioControl::setStudioObjectProperty
+ (pluginMappedId,
+ MappedPluginSlot::Program,
+ strtoqstr(inst->getProgram()));
+ }
+
+ // Set all the port values
+ //
+ PortInstanceIterator portIt;
+
+ for (portIt = inst->begin();
+ portIt != inst->end(); ++portIt) {
+ StudioControl::setStudioPluginPort
+ (pluginMappedId,
+ (*portIt)->number,
+ (*portIt)->value);
+ }
+
+ if (fromSynthMgr) {
+ int key = (index << 16) + instrumentId;
+ if (m_pluginDialogs[key]) {
+ m_pluginDialogs[key]->updatePlugin(plugin);
+ }
+ } else if (m_synthManager) {
+ m_synthManager->updatePlugin(instrumentId, plugin);
+ }
+
+ emit pluginSelected(instrumentId, index, plugin);
+
+ // Set modified
+ m_doc->slotDocumentModified();
+}
+
+void
+RosegardenGUIApp::slotChangePluginPort(InstrumentId instrumentId,
+ int pluginIndex,
+ int portIndex,
+ float value)
+{
+ PluginContainer *container = 0;
+
+ container = m_doc->getStudio().getContainerById(instrumentId);
+ if (!container) {
+ RG_DEBUG << "RosegardenGUIApp::slotChangePluginPort - "
+ << "no instrument or buss of id " << instrumentId << endl;
+ return ;
+ }
+
+ AudioPluginInstance *inst = container->getPlugin(pluginIndex);
+ if (!inst) {
+ RG_DEBUG << "RosegardenGUIApp::slotChangePluginPort - "
+ << "no plugin at index " << pluginIndex << " on " << instrumentId << endl;
+ return ;
+ }
+
+ PluginPortInstance *port = inst->getPort(portIndex);
+ if (!port) {
+ RG_DEBUG << "RosegardenGUIApp::slotChangePluginPort - no port "
+ << portIndex << endl;
+ return ;
+ }
+
+ RG_DEBUG << "RosegardenGUIApp::slotPluginPortChanged - "
+ << "setting plugin port (" << inst->getMappedId()
+ << ", " << portIndex << ") from " << port->value
+ << " to " << value << endl;
+
+ port->setValue(value);
+
+ StudioControl::setStudioPluginPort(inst->getMappedId(),
+ portIndex, port->value);
+
+ m_doc->slotDocumentModified();
+
+ // This modification came from The Outside!
+ int key = (pluginIndex << 16) + instrumentId;
+ if (m_pluginDialogs[key]) {
+ m_pluginDialogs[key]->updatePluginPortControl(portIndex);
+ }
+}
+
+void
+RosegardenGUIApp::slotPluginPortChanged(InstrumentId instrumentId,
+ int pluginIndex,
+ int portIndex)
+{
+ PluginContainer *container = 0;
+
+ container = m_doc->getStudio().getContainerById(instrumentId);
+ if (!container) {
+ RG_DEBUG << "RosegardenGUIApp::slotPluginPortChanged - "
+ << "no instrument or buss of id " << instrumentId << endl;
+ return ;
+ }
+
+ AudioPluginInstance *inst = container->getPlugin(pluginIndex);
+ if (!inst) {
+ RG_DEBUG << "RosegardenGUIApp::slotPluginPortChanged - "
+ << "no plugin at index " << pluginIndex << " on " << instrumentId << endl;
+ return ;
+ }
+
+ PluginPortInstance *port = inst->getPort(portIndex);
+ if (!port) {
+ RG_DEBUG << "RosegardenGUIApp::slotPluginPortChanged - no port "
+ << portIndex << endl;
+ return ;
+ }
+
+ RG_DEBUG << "RosegardenGUIApp::slotPluginPortChanged - "
+ << "setting plugin port (" << inst->getMappedId()
+ << ", " << portIndex << ") to " << port->value << endl;
+
+ StudioControl::setStudioPluginPort(inst->getMappedId(),
+ portIndex, port->value);
+
+ m_doc->slotDocumentModified();
+
+#ifdef HAVE_LIBLO
+ // This modification came from our own plugin dialog, so update
+ // any external GUIs
+ if (m_pluginGUIManager) {
+ m_pluginGUIManager->updatePort(instrumentId,
+ pluginIndex,
+ portIndex);
+ }
+#endif
+}
+
+void
+RosegardenGUIApp::slotChangePluginProgram(InstrumentId instrumentId,
+ int pluginIndex,
+ QString program)
+{
+ PluginContainer *container = 0;
+
+ container = m_doc->getStudio().getContainerById(instrumentId);
+ if (!container) {
+ RG_DEBUG << "RosegardenGUIApp::slotChangePluginProgram - "
+ << "no instrument or buss of id " << instrumentId << endl;
+ return ;
+ }
+
+ AudioPluginInstance *inst = container->getPlugin(pluginIndex);
+ if (!inst) {
+ RG_DEBUG << "RosegardenGUIApp::slotChangePluginProgram - "
+ << "no plugin at index " << pluginIndex << " on " << instrumentId << endl;
+ return ;
+ }
+
+ RG_DEBUG << "RosegardenGUIApp::slotChangePluginProgram - "
+ << "setting plugin program ("
+ << inst->getMappedId() << ") from " << inst->getProgram()
+ << " to " << program << endl;
+
+ inst->setProgram(qstrtostr(program));
+
+ StudioControl::
+ setStudioObjectProperty(inst->getMappedId(),
+ MappedPluginSlot::Program,
+ program);
+
+ PortInstanceIterator portIt;
+
+ for (portIt = inst->begin();
+ portIt != inst->end(); ++portIt) {
+ float value = StudioControl::getStudioPluginPort
+ (inst->getMappedId(),
+ (*portIt)->number);
+ (*portIt)->value = value;
+ }
+
+ // Set modified
+ m_doc->slotDocumentModified();
+
+ int key = (pluginIndex << 16) + instrumentId;
+ if (m_pluginDialogs[key]) {
+ m_pluginDialogs[key]->updatePluginProgramControl();
+ }
+}
+
+void
+RosegardenGUIApp::slotPluginProgramChanged(InstrumentId instrumentId,
+ int pluginIndex)
+{
+ PluginContainer *container = 0;
+
+ container = m_doc->getStudio().getContainerById(instrumentId);
+ if (!container) {
+ RG_DEBUG << "RosegardenGUIApp::slotPluginProgramChanged - "
+ << "no instrument or buss of id " << instrumentId << endl;
+ return ;
+ }
+
+ AudioPluginInstance *inst = container->getPlugin(pluginIndex);
+ if (!inst) {
+ RG_DEBUG << "RosegardenGUIApp::slotPluginProgramChanged - "
+ << "no plugin at index " << pluginIndex << " on " << instrumentId << endl;
+ return ;
+ }
+
+ QString program = strtoqstr(inst->getProgram());
+
+ RG_DEBUG << "RosegardenGUIApp::slotPluginProgramChanged - "
+ << "setting plugin program ("
+ << inst->getMappedId() << ") to " << program << endl;
+
+ StudioControl::
+ setStudioObjectProperty(inst->getMappedId(),
+ MappedPluginSlot::Program,
+ program);
+
+ PortInstanceIterator portIt;
+
+ for (portIt = inst->begin();
+ portIt != inst->end(); ++portIt) {
+ float value = StudioControl::getStudioPluginPort
+ (inst->getMappedId(),
+ (*portIt)->number);
+ (*portIt)->value = value;
+ }
+
+ // Set modified
+ m_doc->slotDocumentModified();
+
+#ifdef HAVE_LIBLO
+
+ if (m_pluginGUIManager)
+ m_pluginGUIManager->updateProgram(instrumentId,
+ pluginIndex);
+#endif
+}
+
+void
+RosegardenGUIApp::slotChangePluginConfiguration(InstrumentId instrumentId,
+ int index,
+ bool global,
+ QString key,
+ QString value)
+{
+ PluginContainer *container = 0;
+
+ container = m_doc->getStudio().getContainerById(instrumentId);
+ if (!container) {
+ RG_DEBUG << "RosegardenGUIApp::slotChangePluginConfiguration - "
+ << "no instrument or buss of id " << instrumentId << endl;
+ return ;
+ }
+
+ AudioPluginInstance *inst = container->getPlugin(index);
+
+ if (global && inst) {
+
+ // Set the same configuration on other plugins in the same
+ // instance group
+
+ AudioPlugin *pl =
+ m_pluginManager->getPluginByIdentifier(strtoqstr(inst->getIdentifier()));
+
+ if (pl && pl->isGrouped()) {
+
+ InstrumentList il =
+ m_doc->getStudio().getAllInstruments();
+
+ for (InstrumentList::iterator i = il.begin();
+ i != il.end(); ++i) {
+
+ for (PluginInstanceIterator pli =
+ (*i)->beginPlugins();
+ pli != (*i)->endPlugins(); ++pli) {
+
+ if (*pli && (*pli)->isAssigned() &&
+ (*pli)->getIdentifier() == inst->getIdentifier() &&
+ (*pli) != inst) {
+
+ slotChangePluginConfiguration
+ ((*i)->getId(), (*pli)->getPosition(),
+ false, key, value);
+
+#ifdef HAVE_LIBLO
+
+ m_pluginGUIManager->updateConfiguration
+ ((*i)->getId(), (*pli)->getPosition(), key);
+#endif
+
+ }
+ }
+ }
+ }
+ }
+
+ if (inst) {
+
+ inst->setConfigurationValue(qstrtostr(key), qstrtostr(value));
+
+ MappedObjectPropertyList config;
+ for (AudioPluginInstance::ConfigMap::const_iterator
+ i = inst->getConfiguration().begin();
+ i != inst->getConfiguration().end(); ++i) {
+ config.push_back(strtoqstr(i->first));
+ config.push_back(strtoqstr(i->second));
+ }
+
+ RG_DEBUG << "RosegardenGUIApp::slotChangePluginConfiguration: setting new config on mapped id " << inst->getMappedId() << endl;
+
+ StudioControl::setStudioObjectPropertyList
+ (inst->getMappedId(),
+ MappedPluginSlot::Configuration,
+ config);
+
+ // Set modified
+ m_doc->slotDocumentModified();
+
+ int key = (index << 16) + instrumentId;
+ if (m_pluginDialogs[key]) {
+ m_pluginDialogs[key]->updatePluginProgramList();
+ }
+ }
+}
+
+void
+RosegardenGUIApp::slotPluginDialogDestroyed(InstrumentId instrumentId,
+ int index)
+{
+ int key = (index << 16) + instrumentId;
+ m_pluginDialogs[key] = 0;
+}
+
+void
+RosegardenGUIApp::slotPluginBypassed(InstrumentId instrumentId,
+ int pluginIndex, bool bp)
+{
+ PluginContainer *container = 0;
+
+ container = m_doc->getStudio().getContainerById(instrumentId);
+ if (!container) {
+ RG_DEBUG << "RosegardenGUIApp::slotPluginBypassed - "
+ << "no instrument or buss of id " << instrumentId << endl;
+ return ;
+ }
+
+ AudioPluginInstance *inst = container->getPlugin(pluginIndex);
+
+ if (inst) {
+ StudioControl::setStudioObjectProperty
+ (inst->getMappedId(),
+ MappedPluginSlot::Bypassed,
+ MappedObjectValue(bp));
+
+ // Set the bypass on the instance
+ //
+ inst->setBypass(bp);
+
+ // Set modified
+ m_doc->slotDocumentModified();
+ }
+
+ emit pluginBypassed(instrumentId, pluginIndex, bp);
+}
+
+void
+RosegardenGUIApp::slotShowPluginGUI(InstrumentId instrument,
+ int index)
+{
+#ifdef HAVE_LIBLO
+ m_pluginGUIManager->showGUI(instrument, index);
+#endif
+}
+
+void
+RosegardenGUIApp::slotStopPluginGUI(InstrumentId instrument,
+ int index)
+{
+#ifdef HAVE_LIBLO
+ m_pluginGUIManager->stopGUI(instrument, index);
+#endif
+}
+
+void
+RosegardenGUIApp::slotPluginGUIExited(InstrumentId instrument,
+ int index)
+{
+ int key = (index << 16) + instrument;
+ if (m_pluginDialogs[key]) {
+ m_pluginDialogs[key]->guiExited();
+ }
+}
+
+void
+RosegardenGUIApp::slotPlayList()
+{
+ if (!m_playList) {
+ m_playList = new PlayListDialog(i18n("Play List"), this);
+ connect(m_playList, SIGNAL(closing()),
+ SLOT(slotPlayListClosed()));
+ connect(m_playList->getPlayList(), SIGNAL(play(QString)),
+ SLOT(slotPlayListPlay(QString)));
+ }
+
+ m_playList->show();
+}
+
+void
+RosegardenGUIApp::slotPlayListPlay(QString url)
+{
+ slotStop();
+ openURL(url);
+ slotPlay();
+}
+
+void
+RosegardenGUIApp::slotPlayListClosed()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotPlayListClosed()\n";
+ m_playList = 0;
+}
+
+void
+RosegardenGUIApp::slotTutorial()
+{
+ QString tutorialURL = i18n("http://rosegarden.sourceforge.net/tutorial/en/chapter-0.html");
+ kapp->invokeBrowser(tutorialURL);
+}
+
+void
+RosegardenGUIApp::slotBugGuidelines()
+{
+ QString glURL = i18n("http://rosegarden.sourceforge.net/tutorial/bug-guidelines.html");
+ kapp->invokeBrowser(glURL);
+}
+
+void
+RosegardenGUIApp::slotBankEditorClosed()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotBankEditorClosed()\n";
+
+ if (m_doc->isModified()) {
+ if (m_view)
+ m_view->slotSelectTrackSegments(m_doc->getComposition().getSelectedTrack());
+ }
+
+ m_bankEditor = 0;
+}
+
+void
+RosegardenGUIApp::slotDeviceManagerClosed()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotDeviceManagerClosed()\n";
+
+ if (m_doc->isModified()) {
+ if (m_view)
+ m_view->slotSelectTrackSegments(m_doc->getComposition().getSelectedTrack());
+ }
+
+ m_deviceManager = 0;
+}
+
+void
+RosegardenGUIApp::slotSynthPluginManagerClosed()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotSynthPluginManagerClosed()\n";
+
+ m_synthManager = 0;
+}
+
+void
+RosegardenGUIApp::slotAudioMixerClosed()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotAudioMixerClosed()\n";
+
+ m_audioMixer = 0;
+}
+
+void
+RosegardenGUIApp::slotMidiMixerClosed()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotMidiMixerClosed()\n";
+
+ m_midiMixer = 0;
+}
+
+void
+RosegardenGUIApp::slotAudioManagerClosed()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotAudioManagerClosed()\n";
+
+ if (m_doc->isModified()) {
+ if (m_view)
+ m_view->slotSelectTrackSegments(m_doc->getComposition().getSelectedTrack());
+ }
+
+ m_audioManagerDialog = 0;
+}
+
+void
+RosegardenGUIApp::slotPanic()
+{
+ if (m_seqManager) {
+ // Stop the transport before we send a panic as the
+ // playback goes all to hell anyway.
+ //
+ slotStop();
+
+ ProgressDialog progressDlg(i18n("Queueing MIDI panic events for tranmission..."),
+ 100,
+ this);
+ CurrentProgressDialog::set
+ (&progressDlg);
+ ProgressDialog::processEvents();
+
+ connect(m_seqManager, SIGNAL(setProgress(int)),
+ progressDlg.progressBar(), SLOT(setValue(int)));
+ connect(m_seqManager, SIGNAL(incrementProgress(int)),
+ progressDlg.progressBar(), SLOT(advance(int)));
+
+ m_seqManager->panic();
+
+ }
+}
+
+void
+RosegardenGUIApp::slotPopulateTrackInstrumentPopup()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotSetTrackInstrument\n";
+ Composition &comp = m_doc->getComposition();
+ Track *track = comp.getTrackById(comp.getSelectedTrack());
+
+ if (!track) {
+ RG_DEBUG << "Weird: no track available for instrument popup!" << endl;
+ return ;
+ }
+
+ Instrument* instrument = m_doc->getStudio().getInstrumentById(track->getInstrument());
+
+ QPopupMenu* popup = dynamic_cast<QPopupMenu*>(factory()->container("set_track_instrument", this));
+
+ m_view->getTrackEditor()->getTrackButtons()->populateInstrumentPopup(instrument, popup);
+}
+
+void
+RosegardenGUIApp::slotRemapInstruments()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotRemapInstruments\n";
+ RemapInstrumentDialog dialog(this, m_doc);
+
+ connect(&dialog, SIGNAL(applyClicked()),
+ m_view->getTrackEditor()->getTrackButtons(),
+ SLOT(slotSynchroniseWithComposition()));
+
+ if (dialog.exec() == QDialog::Accepted) {
+ RG_DEBUG << "slotRemapInstruments - accepted\n";
+ }
+
+}
+
+void
+RosegardenGUIApp::slotSaveDefaultStudio()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotSaveDefaultStudio\n";
+
+ int reply = KMessageBox::warningYesNo
+ (this, i18n("Are you sure you want to save this as your default studio?"));
+
+ if (reply != KMessageBox::Yes)
+ return ;
+
+ KTmpStatusMsg msg(i18n("Saving current document as default studio..."), this);
+
+ QString autoloadFile = ::locateLocal("appdata", "autoload.rg");
+
+ RG_DEBUG << "RosegardenGUIApp::slotSaveDefaultStudio : saving studio in "
+ << autoloadFile << endl;
+
+ SetWaitCursor waitCursor;
+ QString errMsg;
+ bool res = m_doc->saveDocument(autoloadFile, errMsg);
+ if (!res) {
+ if (errMsg)
+ KMessageBox::error(this, i18n(QString("Could not auto-save document at %1\nError was : %2")
+ .arg(autoloadFile).arg(errMsg)));
+ else
+ KMessageBox::error(this, i18n(QString("Could not auto-save document at %1")
+ .arg(autoloadFile)));
+
+ }
+}
+
+void
+RosegardenGUIApp::slotImportDefaultStudio()
+{
+ int reply = KMessageBox::warningYesNo
+ (this, i18n("Are you sure you want to import your default studio and lose the current one?"));
+
+ if (reply != KMessageBox::Yes)
+ return ;
+
+ QString autoloadFile =
+ KGlobal::dirs()->findResource("appdata", "autoload.rg");
+
+ QFileInfo autoloadFileInfo(autoloadFile);
+
+ if (!autoloadFileInfo.isReadable()) {
+ RG_DEBUG << "RosegardenGUIDoc::slotImportDefaultStudio - "
+ << "can't find autoload file - defaulting" << endl;
+ return ;
+ }
+
+ slotImportStudioFromFile(autoloadFile);
+}
+
+void
+RosegardenGUIApp::slotImportStudio()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotImportStudio()\n";
+
+ QString studioDir = KGlobal::dirs()->findResource("appdata", "library/");
+ QDir dir(studioDir);
+ if (!dir.exists()) {
+ studioDir = ":ROSEGARDENDEVICE";
+ } else {
+ studioDir = "file://" + studioDir;
+ }
+
+ KURL url = KFileDialog::getOpenURL
+ (studioDir,
+ "audio/x-rosegarden-device audio/x-rosegarden",
+ this, i18n("Import Studio from File"));
+
+ if (url.isEmpty())
+ return ;
+
+ QString target;
+ if (KIO::NetAccess::download(url, target, this) == false) {
+ KMessageBox::error(this, i18n("Cannot download file %1")
+ .arg(url.prettyURL()));
+ return ;
+ }
+
+ slotImportStudioFromFile(target);
+}
+
+void
+RosegardenGUIApp::slotImportStudioFromFile(const QString &file)
+{
+ RosegardenGUIDoc *doc = new RosegardenGUIDoc(this, 0, true); // skipAutoload
+
+ Studio &oldStudio = m_doc->getStudio();
+ Studio &newStudio = doc->getStudio();
+
+ // Add some dummy devices for when we open the document. We guess
+ // that the file won't have more than 32 devices.
+ //
+ // for (unsigned int i = 0; i < 32; i++) {
+ // newStudio.addDevice("", i, Device::Midi);
+ // }
+
+ if (doc->openDocument(file, true)) { // true because we actually
+ // do want to create devices
+ // on the sequencer here
+
+ KMacroCommand *command = new KMacroCommand(i18n("Import Studio"));
+ doc->syncDevices();
+
+ // We actually only copy across MIDI play devices... for now
+ std::vector<DeviceId> midiPlayDevices;
+
+ for (DeviceList::const_iterator i =
+ oldStudio.begin(); i != oldStudio.end(); ++i) {
+
+ MidiDevice *md =
+ dynamic_cast<MidiDevice *>(*i);
+
+ if (md && (md->getDirection() == MidiDevice::Play)) {
+ midiPlayDevices.push_back((*i)->getId());
+ }
+ }
+
+ std::vector<DeviceId>::iterator di(midiPlayDevices.begin());
+
+ for (DeviceList::const_iterator i =
+ newStudio.begin(); i != newStudio.end(); ++i) {
+
+ MidiDevice *md =
+ dynamic_cast<MidiDevice *>(*i);
+
+ if (md && (md->getDirection() == MidiDevice::Play)) {
+ if (di != midiPlayDevices.end()) {
+ MidiDevice::VariationType variation
+ (md->getVariationType());
+ BankList bl(md->getBanks());
+ ProgramList pl(md->getPrograms());
+ ControlList cl(md->getControlParameters());
+
+ ModifyDeviceCommand* mdCommand = new ModifyDeviceCommand(&oldStudio,
+ *di,
+ md->getName(),
+ md->getLibrarianName(),
+ md->getLibrarianEmail());
+ mdCommand->setVariation(variation);
+ mdCommand->setBankList(bl);
+ mdCommand->setProgramList(pl);
+ mdCommand->setControlList(cl);
+ mdCommand->setOverwrite(true);
+ mdCommand->setRename(md->getName() != "");
+
+ command->addCommand(mdCommand);
+ ++di;
+ }
+ }
+ }
+
+ while (di != midiPlayDevices.end()) {
+ command->addCommand(new CreateOrDeleteDeviceCommand
+ (&oldStudio,
+ *di));
+ }
+
+ oldStudio.setMIDIThruFilter(newStudio.getMIDIThruFilter());
+ oldStudio.setMIDIRecordFilter(newStudio.getMIDIRecordFilter());
+
+ m_doc->getCommandHistory()->addCommand(command);
+ m_doc->syncDevices();
+ m_doc->initialiseStudio(); // The other document will have reset it
+ }
+
+ delete doc;
+}
+
+void
+RosegardenGUIApp::slotResetMidiNetwork()
+{
+ if (m_seqManager) {
+
+ m_seqManager->preparePlayback(true);
+
+ m_seqManager->resetMidiNetwork();
+ }
+
+}
+
+void
+RosegardenGUIApp::slotModifyMIDIFilters()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotModifyMIDIFilters" << endl;
+
+ MidiFilterDialog dialog(this, m_doc);
+
+ if (dialog.exec() == QDialog::Accepted) {
+ RG_DEBUG << "slotModifyMIDIFilters - accepted" << endl;
+ }
+}
+
+void
+RosegardenGUIApp::slotManageMetronome()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotManageMetronome" << endl;
+
+ ManageMetronomeDialog dialog(this, m_doc);
+
+ if (dialog.exec() == QDialog::Accepted) {
+ RG_DEBUG << "slotManageMetronome - accepted" << endl;
+ }
+}
+
+void
+RosegardenGUIApp::slotAutoSave()
+{
+ if (!m_seqManager ||
+ m_seqManager->getTransportStatus() == PLAYING ||
+ m_seqManager->getTransportStatus() == RECORDING)
+ return ;
+
+ KConfig* config = kapp->config();
+ config->setGroup(GeneralOptionsConfigGroup);
+ if (!config->readBoolEntry("autosave", true))
+ return ;
+
+ m_doc->slotAutoSave();
+}
+
+void
+RosegardenGUIApp::slotUpdateAutoSaveInterval(unsigned int interval)
+{
+ RG_DEBUG << "RosegardenGUIApp::slotUpdateAutoSaveInterval - "
+ << "changed interval to " << interval << endl;
+ m_autoSaveTimer->changeInterval(int(interval) * 1000);
+}
+
+void
+RosegardenGUIApp::slotUpdateSidebarStyle(unsigned int style)
+{
+ RG_DEBUG << "RosegardenGUIApp::slotUpdateSidebarStyle - "
+ << "changed style to " << style << endl;
+ m_parameterArea->setArrangement((RosegardenParameterArea::Arrangement) style);
+}
+
+void
+RosegardenGUIApp::slotShowTip()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotShowTip" << endl;
+ KTipDialog::showTip(this, locate("data", "rosegarden/tips"), true);
+}
+
+void RosegardenGUIApp::slotShowToolHelp(const QString &s)
+{
+ QString msg = s;
+ if (msg != "") msg = " " + msg;
+ slotStatusMsg(msg);
+}
+
+void
+RosegardenGUIApp::slotEnableMIDIThruRouting()
+{
+ m_seqManager->enableMIDIThruRouting(m_enableMIDIrouting->isChecked());
+}
+
+TransportDialog* RosegardenGUIApp::getTransport()
+{
+ if (m_transport == 0)
+ createAndSetupTransport();
+
+ return m_transport;
+}
+
+RosegardenGUIDoc *RosegardenGUIApp::getDocument() const
+{
+ return m_doc;
+}
+
+void
+RosegardenGUIApp::awaitDialogClearance()
+{
+ bool haveDialog = true;
+
+ std::cerr << "RosegardenGUIApp::awaitDialogClearance: entering" << std::endl;
+
+ while (haveDialog) {
+
+ const QObjectList *c = children();
+ if (!c) return;
+
+ haveDialog = false;
+ for (QObjectList::const_iterator i = c->begin(); i != c->end(); ++i) {
+ QDialog *dialog = dynamic_cast<QDialog *>(*i);
+ if (dialog && dialog->isVisible()) {
+ haveDialog = true;
+ break;
+ }
+ }
+
+// std::cerr << "RosegardenGUIApp::awaitDialogClearance: have dialog = "
+// << haveDialog << std::endl;
+
+ if (haveDialog) kapp->processEvents();
+ }
+
+ std::cerr << "RosegardenGUIApp::awaitDialogClearance: exiting" << std::endl;
+}
+
+void
+RosegardenGUIApp::slotNewerVersionAvailable(QString v)
+{
+ if (m_firstRun) return;
+ KStartupLogo::hideIfStillThere();
+ CurrentProgressDialog::freeze();
+ awaitDialogClearance();
+ KMessageBox::information
+ (this,
+ i18n("<h3>Newer version available</h3><p>A newer version of Rosegarden may be available.<br>Please consult the <a href=\"http://www.rosegardenmusic.com/getting/\">Rosegarden website</a> for more information.</p>"),
+ i18n("Newer version available"),
+ QString("version-%1-available-show").arg(v),
+ KMessageBox::AllowLink);
+ CurrentProgressDialog::thaw();
+}
+
+void
+RosegardenGUIApp::slotSetQuickMarker()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotSetQuickMarker" << endl;
+
+ m_doc->setQuickMarker();
+ getView()->getTrackEditor()->updateRulers();
+}
+
+void
+RosegardenGUIApp::slotJumpToQuickMarker()
+{
+ RG_DEBUG << "RosegardenGUIApp::slotJumpToQuickMarker" << endl;
+
+ m_doc->jumpToQuickMarker();
+}
+
+const void* RosegardenGUIApp::SequencerExternal = (void*)-1;
+RosegardenGUIApp *RosegardenGUIApp::m_myself = 0;
+
+}
+#include "RosegardenGUIApp.moc"
diff --git a/src/gui/application/RosegardenGUIApp.h b/src/gui/application/RosegardenGUIApp.h
new file mode 100644
index 0000000..502d195
--- /dev/null
+++ b/src/gui/application/RosegardenGUIApp.h
@@ -0,0 +1,1691 @@
+
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+ Rosegarden
+ A MIDI and audio sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <richard.bown@ferventsoftware.com>
+
+ The moral rights of Guillaume Laurent, Chris Cannam, and Richard
+ Bown to claim authorship of this work have been asserted.
+
+ Other copyrights also apply to some parts of this work. Please
+ see the AUTHORS file and individual file headers for details.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+#ifndef _RG_ROSEGARDENGUIAPP_H_
+#define _RG_ROSEGARDENGUIAPP_H_
+
+#include <map>
+#include <set>
+#include "base/MidiProgram.h"
+#include "gui/dialogs/TempoDialog.h"
+#include "gui/widgets/ZoomSlider.h"
+#include "RosegardenIface.h"
+#include "base/Event.h"
+#include "sound/AudioFile.h"
+#include "sound/Midi.h"
+#include <kdockwidget.h>
+#include <qstring.h>
+#include <qvaluevector.h>
+
+
+class QWidget;
+class QTimer;
+class QTextCodec;
+class QShowEvent;
+class QObject;
+class QLabel;
+class QCursor;
+class QAccel;
+class KURL;
+class KTempFile;
+class KToggleAction;
+class KRecentFilesAction;
+class KProcess;
+class KConfig;
+class KAction;
+
+
+namespace Rosegarden
+{
+
+class TriggerSegmentManager;
+class TransportDialog;
+class TrackParameterBox;
+class TempoView;
+class SynthPluginManagerDialog;
+class StartupTester;
+class SequenceManager;
+class SegmentSelection;
+class SegmentParameterBox;
+class RosegardenParameterArea;
+class RosegardenGUIView;
+class RosegardenGUIDoc;
+class RealTime;
+class ProgressBar;
+class PlayListDialog;
+class MidiMixerWindow;
+class MarkerEditor;
+class MappedComposition;
+class LircCommander;
+class LircClient;
+class InstrumentParameterBox;
+class DeviceManagerDialog;
+class ControlEditorDialog;
+class Composition;
+class Clipboard;
+class BankEditorDialog;
+class AudioPluginOSCGUIManager;
+class AudioPluginManager;
+class AudioPluginDialog;
+class AudioMixerWindow;
+class AudioManagerDialog;
+
+/**
+ * The base class for RosegardenGUI application windows. It sets up the main
+ * window and reads the config file as well as providing a menubar, toolbar
+ * and statusbar. An instance of RosegardenGUIView creates your center view, which is connected
+ * to the window's Doc object.
+ * RosegardenGUIApp reimplements the methods that KTMainWindow provides for main window handling and supports
+ * full session management as well as keyboard accelerator configuration by using KAccel.
+ * @see KTMainWindow
+ * @see KApplication
+ * @see KConfig
+ * @see KAccel
+ *
+ * @author Source Framework Automatically Generated by KDevelop, (c) The KDevelop Team.
+ * @version KDevelop version 0.4 code generation
+ */
+class RosegardenGUIApp : public KDockMainWindow, virtual public RosegardenIface
+{
+ Q_OBJECT
+
+ friend class RosegardenGUIView;
+
+public:
+
+ /**
+ * construtor of RosegardenGUIApp, calls all init functions to
+ * create the application.
+ * \arg useSequencer : if true, the sequencer is launched
+ * @see initMenuBar initToolBar
+ */
+ RosegardenGUIApp(bool useSequencer = true,
+ bool useExistingSequencer = false,
+ QObject *startupStatusMessageReceiver = 0);
+
+ virtual ~RosegardenGUIApp();
+
+ /*
+ * Get the current copy of the app object
+ */
+ static RosegardenGUIApp *self() { return m_myself; }
+
+ /**
+ * returns a pointer to the current document connected to the
+ * KTMainWindow instance and is used by * the View class to access
+ * the document object's methods
+ */
+ RosegardenGUIDoc *getDocument() const;
+
+ RosegardenGUIView* getView() { return m_view; }
+
+ TransportDialog* getTransport();
+
+ enum ImportType { ImportRG4, ImportMIDI, ImportRG21, ImportHydrogen, ImportCheckType };
+
+ /**
+ * open a Rosegarden file
+ */
+ virtual void openFile(QString filePath) { openFile(filePath, ImportCheckType); }
+
+ /**
+ * open a file, explicitly specifying its type
+ */
+ void openFile(QString filePath, ImportType type);
+
+ /**
+ * decode and open a project file
+ */
+ void importProject(QString filePath);
+
+ /**
+ * open a URL
+ */
+ virtual void openURL(QString url);
+
+ /**
+ * merge a file with the existing document
+ */
+ virtual void mergeFile(QString filePath) { mergeFile(filePath, ImportCheckType); }
+
+ /**
+ * merge a file, explicitly specifying its type
+ */
+ void mergeFile(QString filePath, ImportType type);
+
+ /**
+ * open a URL
+ */
+ void openURL(const KURL &url);
+
+ /**
+ * export a MIDI file
+ */
+ void exportMIDIFile(QString url);
+
+ /**
+ * export a Csound scorefile
+ */
+ void exportCsoundFile(QString url);
+
+ /**
+ * export a Mup file
+ */
+ void exportMupFile(QString url);
+
+ /**
+ * export a LilyPond file
+ */
+ bool exportLilyPondFile(QString url, bool forPreview = false);
+
+ /**
+ * export a MusicXml file
+ */
+ void exportMusicXmlFile(QString url);
+
+ /**
+ * Get the sequence manager object
+ */
+ SequenceManager* getSequenceManager() { return m_seqManager; }
+
+ /**
+ * Get a progress bar
+ */
+ ProgressBar *getProgressBar() { return m_progressBar; }
+
+ /**
+ * Equivalents of the GUI slots, for DCOP use
+ */
+ virtual void fileNew() { slotFileNew(); }
+ virtual void fileSave() { slotFileSave(); }
+ virtual void fileClose() { slotFileClose(); }
+ virtual void quit() { slotQuit(); }
+
+ virtual void play() { slotPlay(); }
+ virtual void stop() { slotStop(); }
+ virtual void rewind() { slotRewind(); }
+ virtual void fastForward() { slotFastforward(); }
+ virtual void record() { slotRecord(); }
+ virtual void rewindToBeginning() { slotRewindToBeginning(); }
+ virtual void fastForwardToEnd() { slotFastForwardToEnd(); }
+ virtual void jumpToTime(int sec, int usec) { slotJumpToTime(sec, usec); }
+ virtual void startAtTime(int sec, int usec) { slotStartAtTime(sec, usec); }
+
+ virtual void trackUp() { slotTrackUp(); }
+ virtual void trackDown() { slotTrackDown(); }
+ virtual void toggleMutedCurrentTrack() { slotToggleMutedCurrentTrack(); }
+ virtual void toggleRecordCurrentTrack() { slotToggleRecordCurrentTrack(); }
+
+ /**
+ * Start the sequencer auxiliary process
+ * (built in the 'sequencer' directory)
+ *
+ * @see slotSequencerExited()
+ */
+ bool launchSequencer(bool useExistingSequencer);
+
+#ifdef HAVE_LIBJACK
+ /*
+ * Launch and control JACK if required to by configuration
+ */
+ bool launchJack();
+
+#endif // HAVE_LIBJACK
+
+
+ /**
+ * Returns whether we're using a sequencer.
+ * false if the '--nosequencer' option was given
+ * true otherwise.
+ * This doesn't give the state of the sequencer
+ * @see #isSequencerRunning
+ */
+ bool isUsingSequencer() { return m_useSequencer; }
+
+ /**
+ * Returns whether there's a sequencer running.
+ * The result is dynamically updated depending on the sequencer's
+ * status.
+ */
+ bool isSequencerRunning() { return m_useSequencer && (m_sequencerProcess != 0); }
+
+ /**
+ * Returns true if the sequencer wasn't started by us
+ */
+ bool isSequencerExternal() { return m_useSequencer && (m_sequencerProcess == SequencerExternal); }
+
+ /**
+ * Set the sequencer status - pass through DCOP as an int
+ */
+ virtual void notifySequencerStatus(int status);
+
+ /**
+ * Handle some random incoming MIDI events.
+ */
+ virtual void processAsynchronousMidi(const MappedComposition &);
+
+ /*
+ * The sequencer calls this method when it's running to
+ * allow us to sync data with it.
+ *
+ */
+ virtual void alive();
+
+ /*
+ * Tell the application whether this is the first time this
+ * version of RG has been run
+ */
+ void setIsFirstRun(bool first) { m_firstRun = first; }
+
+ /*
+ * Wait in a sub-event-loop until all modal dialogs from the main
+ * window have been cleared
+ */
+ void awaitDialogClearance();
+
+ /*
+ * Return the clipboard
+ */
+ Clipboard* getClipboard() { return m_clipboard; }
+
+#ifdef HAVE_LIBLO
+ /**
+ * Return the plugin native GUI manager, if we have one
+ */
+ AudioPluginOSCGUIManager *getPluginGUIManager() { return m_pluginGUIManager; }
+#endif
+
+ /**
+ * Plug a widget into our common accelerators
+ */
+ void plugAccelerators(QWidget *widget, QAccel *accel);
+
+ /**
+ * Override from QWidget
+ * Toolbars and docks need special treatment
+ */
+ virtual void setCursor(const QCursor&);
+
+ bool isTrackEditorPlayTracking() const;
+
+ bool testAudioPath(QString op); // and open the dialog to set it if unset
+ bool haveAudioImporter() const { return m_haveAudioImporter; }
+
+protected:
+
+ /**** File handling code that we don't want the outside world to use ****/
+ /**/
+ /**/
+
+ /**
+ * Create document from a file
+ */
+ RosegardenGUIDoc* createDocument(QString filePath, ImportType type = ImportRG4);
+
+ /**
+ * Create a document from RG file
+ */
+ RosegardenGUIDoc* createDocumentFromRGFile(QString filePath);
+
+ /**
+ * Create document from MIDI file
+ */
+ RosegardenGUIDoc* createDocumentFromMIDIFile(QString filePath);
+
+ /**
+ * Create document from RG21 file
+ */
+ RosegardenGUIDoc* createDocumentFromRG21File(QString filePath);
+
+ /**
+ * Create document from Hydrogen drum machine file
+ */
+ RosegardenGUIDoc* createDocumentFromHydrogenFile(QString filePath);
+
+ /**/
+ /**/
+ /***********************************************************************/
+
+ /**
+ * Set the 'Rewind' and 'Fast Forward' buttons in the transport
+ * toolbar to AutoRepeat
+ */
+ void setRewFFwdToAutoRepeat();
+
+ static const void* SequencerExternal;
+
+ /// Raise the transport along
+ virtual void showEvent(QShowEvent*);
+
+ /**
+ * read general Options again and initialize all variables like
+ * the recent file list
+ */
+ void readOptions();
+
+ /**
+ * add an item pointing to the example files in the KFileDialog speedbar
+ */
+ void setupFileDialogSpeedbar();
+
+ /**
+ * create menus and toolbars
+ */
+ void setupActions();
+
+ /**
+ * sets up the zoom toolbar
+ */
+ void initZoomToolbar();
+
+ /**
+ * sets up the statusbar for the main window by initialzing a
+ * statuslabel.
+ */
+ void initStatusBar();
+
+ /**
+ * creates the centerwidget of the KTMainWindow instance and sets
+ * it as the view
+ */
+ void initView();
+
+ /**
+ * queryClose is called by KTMainWindow on each closeEvent of a
+ * window. Against the default implementation (only returns true),
+ * this calls saveModified() on the document object to ask if the
+ * document shall be saved if Modified; on cancel the closeEvent
+ * is rejected.
+ *
+ * @see KTMainWindow#queryClose
+ * @see KTMainWindow#closeEvent
+ */
+ virtual bool queryClose();
+
+ /**
+ * queryExit is called by KTMainWindow when the last window of the
+ * application is going to be closed during the closeEvent().
+ * Against the default implementation that just returns true, this
+ * calls saveOptions() to save the settings of the last window's
+ * properties.
+ *
+ * @see KTMainWindow#queryExit
+ * @see KTMainWindow#closeEvent
+ */
+ virtual bool queryExit();
+
+ /**
+ * saves the window properties for each open window during session
+ * end to the session config file, including saving the currently
+ * opened file by a temporary filename provided by KApplication.
+ *
+ * @see KTMainWindow#saveProperties
+ */
+ virtual void saveGlobalProperties(KConfig *_cfg);
+
+ /**
+ * reads the session config file and restores the application's
+ * state including the last opened files and documents by reading
+ * the temporary files saved by saveProperties()
+ *
+ * @see KTMainWindow#readProperties
+ */
+ virtual void readGlobalProperties(KConfig *_cfg);
+
+ /**
+ * Create a new audio file for the sequencer and return the
+ * path to it as a QString.
+ */
+ QString createNewAudioFile();
+ QValueVector<QString> createRecordAudioFiles(const QValueVector<InstrumentId> &);
+
+ QString getAudioFilePath();
+
+ //!!!mtr
+ QValueVector<InstrumentId> getArmedInstruments();
+
+ /**
+ * Show a sequencer error to the user. This is for errors from
+ * the framework code; the playback code uses mapped compositions
+ * to send these things back asynchronously.
+ */
+ void showError(QString error);
+
+ /*
+ * Return AudioManagerDialog
+ */
+ AudioManagerDialog* getAudioManagerDialog() { return m_audioManagerDialog; }
+
+ /**
+ * Ask the user for a file to save to, and check that it's
+ * good and that (if it exists) the user agrees to overwrite.
+ * Return a null string if the write should not go ahead.
+ */
+ QString getValidWriteFile(QString extension, QString label);
+
+ /**
+ * Find any non-ASCII strings in a composition that has been
+ * generated by MIDI import or any other procedure that produces
+ * events with unknown text encoding, and ask the user what
+ * encoding to translate them from. This assumes all text strings
+ * in the composition are of the same encoding, and that it is not
+ * (known to be) utf8 (in which case no transcoding would be
+ * necessary).
+ */
+ void fixTextEncodings(Composition *);
+ QTextCodec *guessTextCodec(std::string);
+
+ /**
+ * Set the current document
+ *
+ * Do all the needed housework when the current document changes
+ * (like closing edit views, emitting documentChanged signal, etc...)
+ */
+ void setDocument(RosegardenGUIDoc*);
+
+ /**
+ * Jog a selection of segments by an amount
+ */
+ void jogSelection(timeT amount);
+
+ void createAndSetupTransport();
+
+signals:
+ void startupStatusMessage(QString message);
+
+ /// emitted just before the document is changed
+ void documentAboutToChange();
+
+ /// emitted when the current document changes
+ void documentChanged(RosegardenGUIDoc*);
+
+ /// emitted when the set of selected segments changes (relayed from RosegardenGUIView)
+ void segmentsSelected(const SegmentSelection &);
+
+ /// emitted when the composition state (selected track, solo, etc...) changes
+ void compositionStateUpdate();
+
+ /// emitted when instrument parameters change (relayed from InstrumentParameterBox)
+ void instrumentParametersChanged(InstrumentId);
+
+ /// emitted when a plugin dialog selects a plugin
+ void pluginSelected(InstrumentId, int, int);
+
+ /// emitted when a plugin dialog (un)bypasses a plugin
+ void pluginBypassed(InstrumentId, int, bool);
+
+public slots:
+
+ /**
+ * open a URL - used for Dn'D
+ *
+ * @param url : a string containing a url (protocol://foo/bar/file.rg)
+ */
+ virtual void slotOpenDroppedURL(QString url);
+
+ /**
+ * Open the document properties dialog on the Audio page
+ */
+ virtual void slotOpenAudioPathSettings();
+
+ /**
+ * open a new application window by creating a new instance of
+ * RosegardenGUIApp
+ */
+ void slotFileNewWindow();
+
+ /**
+ * clears the document in the actual view to reuse it as the new
+ * document
+ */
+ void slotFileNew();
+
+ /**
+ * open a file and load it into the document
+ */
+ void slotFileOpen();
+
+ /**
+ * opens a file from the recent files menu
+ */
+ void slotFileOpenRecent(const KURL&);
+
+ /**
+ * save a document
+ */
+ void slotFileSave();
+
+ /**
+ * save a document by a new filename
+ */
+ bool slotFileSaveAs();
+
+ /**
+ * asks for saving if the file is modified, then closes the actual
+ * file and window
+ */
+ void slotFileClose();
+
+ /**
+ * print the actual file
+ */
+ void slotFilePrint();
+
+ /**
+ * print preview
+ */
+ void slotFilePrintPreview();
+
+ /**
+ * Let the user select a Rosegarden Project file for import
+ */
+ void slotImportProject();
+
+ /**
+ * Let the user select a MIDI file for import
+ */
+ void slotImportMIDI();
+
+ /**
+ * Revert to last loaded file
+ */
+ void slotRevertToSaved();
+
+ /**
+ * Let the user select a Rosegarden 2.1 file for import
+ */
+ void slotImportRG21();
+
+ /**
+ * Select a Hydrogen drum machine file for import
+ */
+ void slotImportHydrogen();
+
+ /**
+ * Let the user select a MIDI file for merge
+ */
+ void slotMerge();
+
+ /**
+ * Let the user select a MIDI file for merge
+ */
+ void slotMergeMIDI();
+
+ /**
+ * Let the user select a MIDI file for merge
+ */
+ void slotMergeRG21();
+
+ /**
+ * Select a Hydrogen drum machine file for merge
+ */
+ void slotMergeHydrogen();
+
+ /**
+ * Let the user export a Rosegarden Project file
+ */
+ void slotExportProject();
+
+ /**
+ * Let the user enter a MIDI file to export to
+ */
+ void slotExportMIDI();
+
+ /**
+ * Let the user enter a Csound scorefile to export to
+ */
+ void slotExportCsound();
+
+ /**
+ * Let the user enter a Mup file to export to
+ */
+ void slotExportMup();
+
+ /**
+ * Let the user enter a LilyPond file to export to
+ */
+ void slotExportLilyPond();
+
+ /**
+ * Export to a temporary file and process
+ */
+ void slotPrintLilyPond();
+ void slotPreviewLilyPond();
+ void slotLilyPondViewProcessExited(KProcess *);
+
+ /**
+ * Let the user enter a MusicXml file to export to
+ */
+ void slotExportMusicXml();
+
+ /**
+ * closes all open windows by calling close() on each memberList
+ * item until the list is empty, then quits the application. If
+ * queryClose() returns false because the user canceled the
+ * saveModified() dialog, the closing breaks.
+ */
+ void slotQuit();
+
+ /**
+ * put the marked text/object into the clipboard and remove * it
+ * from the document
+ */
+ void slotEditCut();
+
+ /**
+ * put the marked text/object into the clipboard
+ */
+ void slotEditCopy();
+
+ /**
+ * paste the clipboard into the document
+ */
+ void slotEditPaste();
+
+ /**
+ * Cut a time range (sections of segments, tempo, and time
+ * signature events within that range).
+ */
+ void slotCutRange();
+
+ /**
+ * Copy a time range.
+ */
+ void slotCopyRange();
+
+ /**
+ * Paste the clipboard at the current pointer position, moving all
+ * subsequent material along to make space.
+ */
+ void slotPasteRange();
+
+ /**
+ * Delete a time range.
+ */
+ void slotDeleteRange();
+
+ /**
+ * Insert a time range (asking the user for a duration).
+ */
+ void slotInsertRange();
+
+ /**
+ * select all segments on all tracks
+ */
+ void slotSelectAll();
+
+ /**
+ * delete selected segments, duh
+ */
+ void slotDeleteSelectedSegments();
+
+ /**
+ * Quantize the selected segments (after asking the user how)
+ */
+ void slotQuantizeSelection();
+
+ /**
+ * Quantize the selected segments by repeating the last iterative quantize
+ */
+ void slotRepeatQuantizeSelection();
+
+ /**
+ * Calculate timing/tempo info based on selected segment
+ */
+ void slotGrooveQuantize();
+
+ /**
+ * Rescale the selected segments by a factor requested from
+ * the user
+ */
+ void slotRescaleSelection();
+
+ /**
+ * Split the selected segments on silences (or new timesig, etc)
+ */
+ void slotAutoSplitSelection();
+
+ /**
+ * Jog a selection left or right by an amount
+ */
+ void slotJogRight();
+ void slotJogLeft();
+
+ /**
+ * Split the selected segments by pitch
+ */
+ void slotSplitSelectionByPitch();
+
+ /**
+ * Split the selected segments by recorded source
+ */
+ void slotSplitSelectionByRecordedSrc();
+
+ /**
+ * Split the selected segments at some time
+ */
+ void slotSplitSelectionAtTime();
+
+ /**
+ * Produce a harmony segment from the selected segments
+ */
+ void slotHarmonizeSelection();
+
+ /**
+ * Set the start times of the selected segments
+ */
+ void slotSetSegmentStartTimes();
+
+ /**
+ * Set the durations of the selected segments
+ */
+ void slotSetSegmentDurations();
+
+ /**
+ * Merge the selected segments
+ */
+ void slotJoinSegments();
+
+ /**
+ * Tempo to Segment length
+ */
+ void slotTempoToSegmentLength();
+ void slotTempoToSegmentLength(QWidget* parent);
+
+ /**
+ * toggle segment labels
+ */
+ void slotToggleSegmentLabels();
+
+ /**
+ * open the default editor for each of the currently-selected segments
+ */
+ void slotEdit();
+
+ /**
+ * open an event list view for each of the currently-selected segments
+ */
+ void slotEditInEventList();
+
+ /**
+ * open a matrix view for each of the currently-selected segments
+ */
+ void slotEditInMatrix();
+
+ /**
+ * open a percussion matrix view for each of the currently-selected segments
+ */
+ void slotEditInPercussionMatrix();
+
+ /**
+ * open a notation view with all currently-selected segments in it
+ */
+ void slotEditAsNotation();
+
+ /**
+ * open a tempo/timesig edit view
+ */
+ void slotEditTempos();
+ void slotEditTempos(timeT openAtTime);
+
+ /**
+ * Edit the tempo - called from a Transport signal
+ */
+ void slotEditTempo();
+ void slotEditTempo(timeT atTime);
+ void slotEditTempo(QWidget *parent);
+ void slotEditTempo(QWidget *parent, timeT atTime);
+
+ /**
+ * Edit the time signature - called from a Transport signal
+ */
+ void slotEditTimeSignature();
+ void slotEditTimeSignature(timeT atTime);
+ void slotEditTimeSignature(QWidget *parent);
+ void slotEditTimeSignature(QWidget *parent, timeT atTime);
+
+ /**
+ * Edit the playback pointer position - called from a Transport signal
+ */
+ void slotEditTransportTime();
+ void slotEditTransportTime(QWidget *parent);
+
+ /**
+ * Change the length of the composition
+ */
+ void slotChangeCompositionLength();
+
+ /**
+ * open a dialog for document properties
+ */
+ void slotEditDocumentProperties();
+
+ /**
+ * Manage MIDI Devices
+ */
+ void slotManageMIDIDevices();
+
+ /**
+ * Manage plugin synths
+ */
+ void slotManageSynths();
+
+ /**
+ * Show the mixers
+ */
+ void slotOpenAudioMixer();
+ void slotOpenMidiMixer();
+
+ /**
+ * Edit Banks/Programs
+ */
+ void slotEditBanks();
+
+ /**
+ * Edit Banks/Programs for a particular device
+ */
+ void slotEditBanks(DeviceId);
+
+ /**
+ * Edit Control Parameters for a particular device
+ */
+ void slotEditControlParameters(DeviceId);
+
+ /**
+ * Edit Document Markers
+ */
+ void slotEditMarkers();
+
+ /**
+ * Not an actual action slot : populates the set_track_instrument sub menu
+ */
+ void slotPopulateTrackInstrumentPopup();
+
+ /**
+ * Remap instruments
+ */
+ void slotRemapInstruments();
+
+ /**
+ * Modify MIDI filters
+ */
+ void slotModifyMIDIFilters();
+
+ /**
+ * Manage Metronome
+ */
+ void slotManageMetronome();
+
+ /**
+ * Save Studio as Default
+ */
+ void slotSaveDefaultStudio();
+
+ /**
+ * Import Studio from File
+ */
+ void slotImportStudio();
+
+ /**
+ * Import Studio from Autoload
+ */
+ void slotImportDefaultStudio();
+
+ /**
+ * Import Studio from File
+ */
+ void slotImportStudioFromFile(const QString &file);
+
+ /**
+ * Send MIDI_RESET to all MIDI devices
+ */
+ void slotResetMidiNetwork();
+
+ /**
+ * toggles the toolbar
+ */
+ void slotToggleToolBar();
+
+ /**
+ * toggles the transport window
+ */
+ void slotToggleTransport();
+
+ /**
+ * hides the transport window
+ */
+ void slotHideTransport();
+
+ /**
+ * toggles the tools toolbar
+ */
+ void slotToggleToolsToolBar();
+
+ /**
+ * toggles the tracks toolbar
+ */
+ void slotToggleTracksToolBar();
+
+ /**
+ * toggles the editors toolbar
+ */
+ void slotToggleEditorsToolBar();
+
+ /**
+ * toggles the transport toolbar
+ */
+ void slotToggleTransportToolBar();
+
+ /**
+ * toggles the zoom toolbar
+ */
+ void slotToggleZoomToolBar();
+
+ /**
+ * toggles the statusbar
+ */
+ void slotToggleStatusBar();
+
+ /**
+ * changes the statusbar contents for the standard label
+ * permanently, used to indicate current actions.
+ *
+ * @param text the text that is displayed in the statusbar
+ */
+ void slotStatusMsg(QString text);
+
+ /**
+ * changes the status message of the whole statusbar for two
+ * seconds, then restores the last status. This is used to display
+ * statusbar messages that give information about actions for
+ * toolbar icons and menuentries.
+ *
+ * @param text the text that is displayed in the statusbar
+ */
+ void slotStatusHelpMsg(QString text);
+
+ /**
+ * enables/disables the transport window
+ */
+ void slotEnableTransport(bool);
+
+ /**
+ * segment select tool
+ */
+ void slotPointerSelected();
+
+ /**
+ * segment eraser tool is selected
+ */
+ void slotEraseSelected();
+
+ /**
+ * segment draw tool is selected
+ */
+ void slotDrawSelected();
+
+ /**
+ * segment move tool is selected
+ */
+ void slotMoveSelected();
+
+ /**
+ * segment resize tool is selected
+ */
+ void slotResizeSelected();
+
+ /*
+ * Segment join tool
+ *
+ */
+ void slotJoinSelected();
+
+ /*
+ * Segment split tool
+ *
+ */
+ void slotSplitSelected();
+
+ /**
+ * Add one new track
+ */
+ void slotAddTrack();
+
+ /**
+ * Add new tracks
+ */
+ void slotAddTracks();
+
+ /*
+ * Delete Tracks
+ */
+ void slotDeleteTrack();
+
+ /*
+ * Modify track position
+ */
+ void slotMoveTrackUp();
+ void slotMoveTrackDown();
+
+ /**
+ * timeT version of the same
+ */
+ void slotSetPointerPosition(timeT t);
+
+ /**
+ * Set the pointer position and start playing (from LoopRuler)
+ */
+ void slotSetPlayPosition(timeT position);
+
+ /**
+ * Set a loop
+ */
+ void slotSetLoop(timeT lhs, timeT rhs);
+
+
+ /**
+ * Update the transport with the bar, beat and unit times for
+ * a given timeT
+ */
+ void slotDisplayBarTime(timeT t);
+
+
+ /**
+ * Transport controls
+ */
+ void slotPlay();
+ void slotStop();
+ void slotRewind();
+ void slotFastforward();
+ void slotRecord();
+ void slotToggleRecord();
+ void slotRewindToBeginning();
+ void slotFastForwardToEnd();
+ void slotJumpToTime(int sec, int usec);
+ void slotStartAtTime(int sec, int usec);
+ void slotRefreshTimeDisplay();
+ void slotToggleTracking();
+
+ /**
+ * Called when the sequencer auxiliary process exits
+ */
+ void slotSequencerExited(KProcess*);
+
+ /// When the transport closes
+ void slotCloseTransport();
+
+ /**
+ * called by RosegardenApplication when session management tells
+ * it to save its state. This is to avoid saving the transport as
+ * a 2nd main window
+ */
+ void slotDeleteTransport();
+
+ /**
+ * Put the GUI into a given Tool edit mode
+ */
+ void slotActivateTool(QString toolName);
+
+ /**
+ * Toggles either the play or record metronome according
+ * to Transport status
+ */
+ void slotToggleMetronome();
+
+ /*
+ * Toggle the solo mode
+ */
+ void slotToggleSolo(bool);
+
+ /**
+ * Set and unset the loop from the transport loop button with
+ * these slots.
+ */
+ void slotSetLoop();
+ void slotUnsetLoop();
+
+ /**
+ * Set and unset the loop start/end time from the transport loop start/stop buttons with
+ * these slots.
+ */
+ void slotSetLoopStart();
+ void slotSetLoopStop();
+
+ /**
+ * Toggle the track labels on the TrackEditor
+ */
+ void slotToggleTrackLabels();
+
+ /**
+ * Toggle the rulers on the TrackEditor
+ * (aka bar buttons)
+ */
+ void slotToggleRulers();
+
+ /**
+ * Toggle the tempo ruler on the TrackEditor
+ */
+ void slotToggleTempoRuler();
+
+ /**
+ * Toggle the chord-name ruler on the TrackEditor
+ */
+ void slotToggleChordNameRuler();
+
+ /**
+ * Toggle the segment canvas previews
+ */
+ void slotTogglePreviews();
+
+ /**
+ * Re-dock the parameters box to its initial position
+ */
+ void slotDockParametersBack();
+
+ /**
+ * The parameters box was closed
+ */
+ void slotParametersClosed();
+
+ /**
+ * The parameters box was docked back
+ */
+ void slotParametersDockedBack(KDockWidget*, KDockWidget::DockPosition);
+
+ /**
+ * Display tip-of-day dialog on demand
+ */
+ void slotShowTip();
+
+ /*
+ * Select Track up or down
+ */
+ void slotTrackUp();
+ void slotTrackDown();
+
+ /**
+ * Mute/Unmute
+ */
+ void slotMuteAllTracks();
+ void slotUnmuteAllTracks();
+ void slotToggleMutedCurrentTrack();
+
+ /**
+ * Toggle arm (record) current track
+ */
+ void slotToggleRecordCurrentTrack();
+
+ /**
+ * save general Options like all bar positions and status as well
+ * as the geometry and the recent file list to the configuration
+ * file
+ */
+ void slotSaveOptions();
+
+ /**
+ * Show the configure dialog
+ */
+ void slotConfigure();
+
+ /**
+ * Show the key mappings
+ *
+ */
+ void slotEditKeys();
+
+ /**
+ * Edit toolbars
+ */
+ void slotEditToolbars();
+
+ /**
+ * Update the toolbars after edition
+ */
+ void slotUpdateToolbars();
+
+ /**
+ * Zoom slider moved
+ */
+ void slotChangeZoom(int index);
+
+ void slotZoomIn();
+ void slotZoomOut();
+
+ /**
+ * Modify tempo
+ */
+ void slotChangeTempo(timeT time,
+ tempoT value,
+ tempoT target,
+ TempoDialog::TempoDialogAction action);
+
+ /**
+ * Move a tempo change
+ */
+ void slotMoveTempo(timeT oldTime,
+ timeT newTime);
+
+ /**
+ * Remove a tempo change
+ */
+ void slotDeleteTempo(timeT time);
+
+ /**
+ * Add marker
+ */
+ void slotAddMarker(timeT time);
+
+ /**
+ * Remove a marker
+ */
+ void slotDeleteMarker(int id,
+ timeT time,
+ QString name,
+ QString description);
+
+ /**
+ * Document modified
+ */
+ void slotDocumentModified(bool modified = true);
+
+
+ /**
+ * This slot is here to be connected to RosegardenGUIView's
+ * stateChange signal. We use a bool for the 2nd arg rather than a
+ * KXMLGUIClient::ReverseStateChange to spare the include of
+ * kxmlguiclient.h just for one typedef.
+ *
+ * Hopefully we'll be able to get rid of this eventually,
+ * I should slip this in KMainWindow for KDE 4.
+ */
+ void slotStateChanged(QString, bool noReverse);
+
+ /**
+ * A command has happened; check the clipboard in case we
+ * need to change state
+ */
+ void slotTestClipboard();
+
+ /**
+ * Show a 'play list' dialog
+ */
+ void slotPlayList();
+
+ /**
+ * Play the requested URL
+ *
+ * Stop current playback, close current document,
+ * open specified document and play it.
+ */
+ void slotPlayListPlay(QString url);
+
+ /**
+ * Call up the online tutorial
+ */
+ void slotTutorial();
+
+ /**
+ * Surf to the bug reporting guidelines
+ */
+ void slotBugGuidelines();
+
+ /**
+ * View the trigger segments manager
+ */
+ void slotManageTriggerSegments();
+
+ /**
+ * View the audio file manager - and some associated actions
+ */
+ void slotAudioManager();
+
+ void slotAddAudioFile(AudioFileId);
+ void slotDeleteAudioFile(AudioFileId);
+ void slotPlayAudioFile(AudioFileId,
+ const RealTime &,
+ const RealTime &);
+ void slotCancelAudioPlayingFile(AudioFileId);
+ void slotDeleteAllAudioFiles();
+
+ /**
+ * Reflect segment deletion from the audio manager
+ */
+ void slotDeleteSegments(const SegmentSelection&);
+
+ void slotRepeatingSegments();
+ void slotRelabelSegments();
+ void slotTransposeSegments();
+
+ /// Panic button pressed
+ void slotPanic();
+
+ // Auto-save
+ //
+ void slotAutoSave();
+
+ // Auto-save update interval changes
+ //
+ void slotUpdateAutoSaveInterval(unsigned int interval);
+
+ // Update the side-bar when the configuration page changes its style.
+ //
+ void slotUpdateSidebarStyle(unsigned int style);
+
+ /**
+ * called when the PlayList is being closed
+ */
+ void slotPlayListClosed();
+
+ /**
+ * called when the BankEditor is being closed
+ */
+ void slotBankEditorClosed();
+
+ /**
+ * called when the Device Manager is being closed
+ */
+ void slotDeviceManagerClosed();
+
+ /**
+ * called when the synth manager is being closed
+ */
+ void slotSynthPluginManagerClosed();
+
+ /**
+ * called when the Mixer is being closed
+ */
+ void slotAudioMixerClosed();
+ void slotMidiMixerClosed();
+
+ /**
+ * when ControlEditor is being closed
+ */
+ void slotControlEditorClosed();
+
+ /**
+ * when MarkerEditor is being closed
+ */
+ void slotMarkerEditorClosed();
+
+ /**
+ * when TempoView is being closed
+ */
+ void slotTempoViewClosed();
+
+ /**
+ * when TriggerManager is being closed
+ */
+ void slotTriggerManagerClosed();
+
+ /**
+ * when AudioManagerDialog is being closed
+ */
+ void slotAudioManagerClosed();
+
+ /**
+ * Update the pointer position from the sequencer mmapped file when playing
+ */
+ void slotUpdatePlaybackPosition();
+
+ /**
+ * Update the CPU level meter
+ */
+ void slotUpdateCPUMeter(bool playing);
+
+ /**
+ * Update the monitor levels from the sequencer mmapped file when not playing
+ * (slotUpdatePlaybackPosition does this among other things when playing)
+ */
+ void slotUpdateMonitoring();
+
+ /**
+ * Create a plugin dialog for a given instrument and slot, or
+ * raise an exising one.
+ */
+ void slotShowPluginDialog(QWidget *parent,
+ InstrumentId instrument,
+ int index);
+
+ void slotPluginSelected(InstrumentId instrument,
+ int index, int plugin);
+
+ /**
+ * An external GUI has requested a port change.
+ */
+ void slotChangePluginPort(InstrumentId instrument,
+ int index, int portIndex, float value);
+
+ /**
+ * Our internal GUI has made a port change -- the
+ * PluginPortInstance already contains the new value, but we need
+ * to inform the sequencer and update external GUIs.
+ */
+ void slotPluginPortChanged(InstrumentId instrument,
+ int index, int portIndex);
+
+ /**
+ * An external GUI has requested a program change.
+ */
+ void slotChangePluginProgram(InstrumentId instrument,
+ int index, QString program);
+
+ /**
+ * Our internal GUI has made a program change -- the
+ * AudioPluginInstance already contains the new program, but we
+ * need to inform the sequencer, update external GUIs, and update
+ * the port values for the new program.
+ */
+ void slotPluginProgramChanged(InstrumentId instrument,
+ int index);
+
+ /**
+ * An external GUI has requested a configure call. (This can only
+ * happen from an external GUI, we have no way to manage these
+ * internally.)
+ */
+ void slotChangePluginConfiguration(InstrumentId, int index,
+ bool global, QString key, QString value);
+ void slotPluginDialogDestroyed(InstrumentId instrument,
+ int index);
+ void slotPluginBypassed(InstrumentId,
+ int index, bool bypassed);
+
+ void slotShowPluginGUI(InstrumentId, int index);
+ void slotStopPluginGUI(InstrumentId, int index);
+ void slotPluginGUIExited(InstrumentId, int index);
+
+ void slotDocumentDevicesResyncd();
+
+ void slotTestStartupTester();
+
+ void slotDebugDump();
+
+ /**
+ * Enable or disable the internal MIDI Thru routing.
+ *
+ * This policy is implemented at the sequencer side, controlled
+ * by this flag and also by the MIDI Thru filters.
+ *
+ * @see ControlBlock::isMidiRoutingEnabled()
+ * @see RosegardenSequencerApp::processAsynchronousEvents()
+ * @see RosegardenSequencerApp::processRecordedEvents()
+ */
+ void slotEnableMIDIThruRouting();
+
+ void slotShowToolHelp(const QString &);
+
+ void slotNewerVersionAvailable(QString);
+
+ void slotSetQuickMarker();
+
+ void slotJumpToQuickMarker();
+
+private:
+
+
+ //--------------- Data members ---------------------------------
+
+ bool m_actionsSetup;
+
+ KRecentFilesAction* m_fileRecent;
+
+ /**
+ * view is the main widget which represents your working area. The
+ * View class should handle all events of the view widget. It is
+ * kept empty so you can create your view according to your
+ * application's needs by changing the view class.
+ */
+ RosegardenGUIView* m_view;
+ RosegardenGUIView* m_swapView;
+
+ KDockWidget* m_mainDockWidget;
+ KDockWidget* m_dockLeft;
+
+ /**
+ * doc represents your actual document and is created only
+ * once. It keeps information such as filename and does the
+ * serialization of your files.
+ */
+ RosegardenGUIDoc* m_doc;
+
+ /**
+ * KAction pointers to enable/disable actions
+ */
+ KRecentFilesAction* m_fileOpenRecent;
+
+ KToggleAction* m_viewToolBar;
+ KToggleAction* m_viewToolsToolBar;
+ KToggleAction* m_viewTracksToolBar;
+ KToggleAction* m_viewEditorsToolBar;
+ KToggleAction* m_viewZoomToolBar;
+ KToggleAction* m_viewStatusBar;
+ KToggleAction* m_viewTransport;
+ KToggleAction* m_viewTransportToolBar;
+ KToggleAction* m_viewTrackLabels;
+ KToggleAction* m_viewRulers;
+ KToggleAction* m_viewTempoRuler;
+ KToggleAction* m_viewChordNameRuler;
+ KToggleAction* m_viewPreviews;
+ KToggleAction* m_viewSegmentLabels;
+ KToggleAction* m_enableMIDIrouting;
+
+ KAction *m_playTransport;
+ KAction *m_stopTransport;
+ KAction *m_rewindTransport;
+ KAction *m_ffwdTransport;
+ KAction *m_recordTransport;
+ KAction *m_rewindEndTransport;
+ KAction *m_ffwdEndTransport;
+
+ KProcess* m_sequencerProcess;
+ bool m_sequencerCheckedIn;
+
+#ifdef HAVE_LIBJACK
+ KProcess* m_jackProcess;
+#endif // HAVE_LIBJACK
+
+ ZoomSlider<double> *m_zoomSlider;
+ QLabel *m_zoomLabel;
+
+ ProgressBar *m_progressBar;
+
+ // SequenceManager
+ //
+ SequenceManager *m_seqManager;
+
+ // Transport dialog pointer
+ //
+ TransportDialog *m_transport;
+
+ // Dialogs which depend on the document
+
+ // Audio file manager
+ //
+ AudioManagerDialog *m_audioManagerDialog;
+
+ bool m_originatingJump;
+
+ // Use these in conjucntion with the loop button to
+ // remember where a loop was if we've ever set one.
+ timeT m_storedLoopStart;
+ timeT m_storedLoopEnd;
+
+ bool m_useSequencer;
+ bool m_dockVisible;
+
+ AudioPluginManager *m_pluginManager;
+
+ QTimer* m_autoSaveTimer;
+
+ Clipboard *m_clipboard;
+
+ SegmentParameterBox *m_segmentParameterBox;
+ InstrumentParameterBox *m_instrumentParameterBox;
+ TrackParameterBox *m_trackParameterBox;
+
+ PlayListDialog *m_playList;
+ DeviceManagerDialog *m_deviceManager;
+ SynthPluginManagerDialog *m_synthManager;
+ AudioMixerWindow *m_audioMixer;
+ MidiMixerWindow *m_midiMixer;
+ BankEditorDialog *m_bankEditor;
+ MarkerEditor *m_markerEditor;
+ TempoView *m_tempoView;
+ TriggerSegmentManager *m_triggerSegmentManager;
+ std::set<ControlEditorDialog *> m_controlEditors;
+ std::map<int, AudioPluginDialog*> m_pluginDialogs;
+#ifdef HAVE_LIBLO
+ AudioPluginOSCGUIManager *m_pluginGUIManager;
+#endif
+
+ static RosegardenGUIApp *m_myself;
+
+ static std::map<KProcess *, KTempFile *> m_lilyTempFileMap;
+
+ // Used to fetch the current sequencer position from the mmapped sequencer information file
+ //
+ QTimer *m_playTimer;
+ QTimer *m_stopTimer;
+
+ StartupTester *m_startupTester;
+
+ bool m_firstRun;
+ bool m_haveAudioImporter;
+
+ RosegardenParameterArea *m_parameterArea;
+
+ KAction *m_setQuickMarkerAction;
+ KAction *m_jumpToQuickMarkerAction;
+
+#ifdef HAVE_LIRC
+ LircClient *m_lircClient;
+ LircCommander *m_lircCommander;
+#endif
+};
+
+
+}
+
+#endif
diff --git a/src/gui/application/RosegardenGUIView.cpp b/src/gui/application/RosegardenGUIView.cpp
new file mode 100644
index 0000000..c61b51e
--- /dev/null
+++ b/src/gui/application/RosegardenGUIView.cpp
@@ -0,0 +1,2041 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+ Rosegarden
+ A MIDI and audio sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <richard.bown@ferventsoftware.com>
+
+ The moral rights of Guillaume Laurent, Chris Cannam, and Richard
+ Bown to claim authorship of this work have been asserted.
+
+ Other copyrights also apply to some parts of this work. Please
+ see the AUTHORS file and individual file headers for details.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+
+#include "RosegardenGUIView.h"
+#include <kapplication.h>
+
+#include "sound/Midi.h"
+#include "gui/editors/segment/TrackButtons.h"
+#include <klocale.h>
+#include "misc/Debug.h"
+#include "misc/Strings.h"
+#include "document/ConfigGroups.h"
+#include "gui/application/RosegardenDCOP.h"
+#include "base/AudioLevel.h"
+#include "base/Composition.h"
+#include "base/Instrument.h"
+#include "base/MidiDevice.h"
+#include "base/MidiProgram.h"
+#include "base/NotationTypes.h"
+#include "base/RealTime.h"
+#include "base/RulerScale.h"
+#include "base/Segment.h"
+#include "base/Selection.h"
+#include "base/Studio.h"
+#include "base/Track.h"
+#include "commands/segment/AudioSegmentAutoSplitCommand.h"
+#include "commands/segment/AudioSegmentInsertCommand.h"
+#include "commands/segment/SegmentSingleRepeatToCopyCommand.h"
+#include "document/MultiViewCommandHistory.h"
+#include "document/RosegardenGUIDoc.h"
+#include "RosegardenApplication.h"
+#include "gui/configuration/GeneralConfigurationPage.h"
+#include "gui/configuration/AudioConfigurationPage.h"
+#include "gui/dialogs/AudioSplitDialog.h"
+#include "gui/dialogs/AudioManagerDialog.h"
+#include "gui/dialogs/DocumentConfigureDialog.h"
+#include "gui/dialogs/TempoDialog.h"
+#include "gui/editors/eventlist/EventView.h"
+#include "gui/editors/matrix/MatrixView.h"
+#include "gui/editors/notation/NotationView.h"
+#include "gui/editors/parameters/InstrumentParameterBox.h"
+#include "gui/editors/parameters/SegmentParameterBox.h"
+#include "gui/editors/parameters/TrackParameterBox.h"
+#include "gui/editors/segment/segmentcanvas/CompositionView.h"
+#include "gui/editors/segment/segmentcanvas/SegmentSelector.h"
+#include "gui/editors/segment/TrackEditor.h"
+#include "gui/seqmanager/SequenceManager.h"
+#include "gui/seqmanager/SequencerMapper.h"
+#include "gui/rulers/ChordNameRuler.h"
+#include "gui/rulers/LoopRuler.h"
+#include "gui/rulers/TempoRuler.h"
+#include "gui/rulers/StandardRuler.h"
+#include "gui/widgets/ProgressDialog.h"
+#include "gui/widgets/CurrentProgressDialog.h"
+#include "RosegardenGUIApp.h"
+#include "SetWaitCursor.h"
+#include "sound/AudioFile.h"
+#include "sound/AudioFileManager.h"
+#include "sound/MappedEvent.h"
+#include <kcommand.h>
+#include <kconfig.h>
+#include <kmessagebox.h>
+#include <kprocess.h>
+#include <qapplication.h>
+#include <qcursor.h>
+#include <qdialog.h>
+#include <qfileinfo.h>
+#include <qobject.h>
+#include <qstring.h>
+#include <qvbox.h>
+#include <qwidget.h>
+
+
+namespace Rosegarden
+{
+
+// Use this to define the basic unit of the main QCanvas size.
+//
+// This apparently arbitrary figure is what we think is an
+// appropriate width in pixels for a 4/4 bar. Beware of making it
+// too narrow, as shorter bars will be proportionally smaller --
+// the visual difference between 2/4 and 4/4 is perhaps greater
+// than it sounds.
+//
+static double barWidth44 = 100.0;
+
+const QWidget *RosegardenGUIView::m_lastActiveMainWindow = 0;
+
+// This is the maximum number of matrix, event view or percussion
+// matrix editors to open in a single operation (not the maximum that
+// can be open at a time -- there isn't one)
+//
+static int maxEditorsToOpen = 8;
+
+RosegardenGUIView::RosegardenGUIView(bool showTrackLabels,
+ SegmentParameterBox* segmentParameterBox,
+ InstrumentParameterBox* instrumentParameterBox,
+ TrackParameterBox* trackParameterBox,
+ QWidget *parent,
+ const char* /*name*/)
+ : QVBox(parent),
+ m_rulerScale(0),
+ m_trackEditor(0),
+ m_segmentParameterBox(segmentParameterBox),
+ m_instrumentParameterBox(instrumentParameterBox),
+ m_trackParameterBox(trackParameterBox)
+{
+ RosegardenGUIDoc* doc = getDocument();
+ Composition *comp = &doc->getComposition();
+
+ double unitsPerPixel =
+ TimeSignature(4, 4).getBarDuration() / barWidth44;
+ m_rulerScale = new SimpleRulerScale(comp, 0, unitsPerPixel);
+
+ // Construct the trackEditor first so we can then
+ // query it for placement information
+ //
+ m_trackEditor = new TrackEditor(doc, this,
+ m_rulerScale, showTrackLabels, unitsPerPixel, this /*hbox*/);
+
+ connect(m_trackEditor->getSegmentCanvas(),
+ SIGNAL(editSegment(Segment*)),
+ SLOT(slotEditSegment(Segment*)));
+
+ connect(m_trackEditor->getSegmentCanvas(),
+ SIGNAL(editSegmentNotation(Segment*)),
+ SLOT(slotEditSegmentNotation(Segment*)));
+
+ connect(m_trackEditor->getSegmentCanvas(),
+ SIGNAL(editSegmentMatrix(Segment*)),
+ SLOT(slotEditSegmentMatrix(Segment*)));
+
+ connect(m_trackEditor->getSegmentCanvas(),
+ SIGNAL(editSegmentAudio(Segment*)),
+ SLOT(slotEditSegmentAudio(Segment*)));
+
+ connect(m_trackEditor->getSegmentCanvas(),
+ SIGNAL(audioSegmentAutoSplit(Segment*)),
+ SLOT(slotSegmentAutoSplit(Segment*)));
+
+ connect(m_trackEditor->getSegmentCanvas(),
+ SIGNAL(editSegmentEventList(Segment*)),
+ SLOT(slotEditSegmentEventList(Segment*)));
+
+ connect(m_trackEditor->getSegmentCanvas(),
+ SIGNAL(editRepeat(Segment*, timeT)),
+ SLOT(slotEditRepeat(Segment*, timeT)));
+
+ connect(m_trackEditor->getSegmentCanvas(),
+ SIGNAL(setPointerPosition(timeT)),
+ doc, SLOT(slotSetPointerPosition(timeT)));
+
+ connect(m_trackEditor,
+ SIGNAL(droppedDocument(QString)),
+ parent,
+ SLOT(slotOpenDroppedURL(QString)));
+
+ connect(m_trackEditor,
+ SIGNAL(droppedAudio(QString)),
+ this,
+ SLOT(slotDroppedAudio(QString)));
+
+ connect(m_trackEditor,
+ SIGNAL(droppedNewAudio(QString)),
+ this,
+ SLOT(slotDroppedNewAudio(QString)));
+
+ connect(m_instrumentParameterBox,
+ SIGNAL(changeInstrumentLabel(InstrumentId, QString)),
+ this,
+ SLOT(slotChangeInstrumentLabel(InstrumentId, QString)));
+
+ connect(m_instrumentParameterBox,
+ SIGNAL(changeInstrumentLabel(InstrumentId, QString)),
+ m_trackParameterBox,
+ SLOT(slotInstrumentLabelChanged(InstrumentId, QString)));
+
+ connect(m_trackEditor->getTrackButtons(),
+ SIGNAL(nameChanged()),
+ m_trackParameterBox,
+ SLOT(slotSelectedTrackNameChanged()));
+
+ connect(m_trackEditor->getTrackButtons(),
+ SIGNAL(instrumentSelected(int)),
+ m_trackParameterBox,
+ SLOT(slotUpdateControls(int)));
+
+ connect(m_trackParameterBox,
+ SIGNAL(instrumentSelected(TrackId, int)),
+ m_trackEditor->getTrackButtons(),
+ SLOT(slotTrackInstrumentSelection(TrackId, int)));
+
+ connect(this, SIGNAL(controllerDeviceEventReceived(MappedEvent *, const void *)),
+ this, SLOT(slotControllerDeviceEventReceived(MappedEvent *, const void *)));
+
+ if (doc) {
+ /* signal no longer exists
+ connect(doc, SIGNAL(recordingSegmentUpdated(Segment *,
+ timeT)),
+ this, SLOT(slotUpdateRecordingSegment(Segment *,
+ timeT)));
+ */
+
+ QObject::connect
+ (getCommandHistory(), SIGNAL(commandExecuted()),
+ m_trackEditor->getSegmentCanvas(), SLOT(slotUpdateSegmentsDrawBuffer()));
+ }
+}
+
+RosegardenGUIView::~RosegardenGUIView()
+{
+ RG_DEBUG << "~RosegardenGUIView()" << endl;
+ delete m_rulerScale;
+}
+
+RosegardenGUIDoc*
+RosegardenGUIView::getDocument() const
+{
+ return RosegardenGUIApp::self()->getDocument();
+}
+
+void RosegardenGUIView::print(Composition* p, bool previewOnly)
+{
+ SetWaitCursor waitCursor;
+
+ std::vector<Segment *> segmentsToEdit;
+
+ for (Composition::iterator i = p->begin(); i != p->end(); ++i) {
+ if ((*i)->getType() != Segment::Audio) {
+ segmentsToEdit.push_back(*i);
+ }
+ }
+
+ if (segmentsToEdit.empty()) {
+ KMessageBox::sorry(this, i18n("No non-audio segments in composition"));
+ return ;
+ }
+
+ NotationView *notationView = new NotationView(getDocument(),
+ segmentsToEdit,
+ this,
+ (NotationView *)0);
+
+ if (!notationView->isOK()) {
+ RG_DEBUG << "RosegardenGUIView::print : operation cancelled" << endl;
+ delete notationView;
+ return ;
+ }
+
+ notationView->print(previewOnly);
+
+ delete notationView;
+}
+
+void RosegardenGUIView::selectTool(const QString toolName)
+{
+ m_trackEditor->getSegmentCanvas()->slotSetTool(toolName);
+}
+
+bool
+RosegardenGUIView::haveSelection()
+{
+ return m_trackEditor->getSegmentCanvas()->haveSelection();
+}
+
+SegmentSelection
+RosegardenGUIView::getSelection()
+{
+ return m_trackEditor->getSegmentCanvas()->getSelectedSegments();
+}
+
+void RosegardenGUIView::updateSelectionContents()
+{
+ m_trackEditor->getSegmentCanvas()->updateSelectionContents();
+}
+
+/* hjj: WHAT DO DO WITH THIS ?
+void
+RosegardenGUIView::slotEditMetadata(QString name)
+{
+ const QWidget *ww = dynamic_cast<const QWidget *>(sender());
+ QWidget *w = const_cast<QWidget *>(ww);
+
+ DocumentConfigureDialog *configDlg =
+ new DocumentConfigureDialog(getDocument(), w ? w : this);
+
+ configDlg->selectMetadata(name);
+
+ configDlg->show();
+}
+*/
+
+void RosegardenGUIView::slotEditSegment(Segment* segment)
+{
+ Segment::SegmentType type = Segment::Internal;
+
+ if (segment) {
+ type = segment->getType();
+ } else {
+ if (haveSelection()) {
+
+ bool haveType = false;
+
+ SegmentSelection selection = getSelection();
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+
+ Segment::SegmentType myType = (*i)->getType();
+ if (haveType) {
+ if (myType != type) {
+ KMessageBox::sorry(this, i18n("Selection must contain only audio or non-audio segments"));
+ return ;
+ }
+ } else {
+ type = myType;
+ haveType = true;
+ segment = *i;
+ }
+ }
+ } else
+ return ;
+ }
+
+ if (type == Segment::Audio) {
+ slotEditSegmentAudio(segment);
+ } else {
+
+ KConfig* config = kapp->config();
+ config->setGroup(GeneralOptionsConfigGroup);
+ GeneralConfigurationPage::DoubleClickClient
+ client =
+ (GeneralConfigurationPage::DoubleClickClient)
+ (config->readUnsignedNumEntry("doubleclickclient",
+ (unsigned int)GeneralConfigurationPage::NotationView));
+
+ if (client == GeneralConfigurationPage::MatrixView) {
+
+ bool isPercussion = false;
+ Track *track = getDocument()->getComposition().getTrackById
+ (segment->getTrack());
+ if (track) {
+ InstrumentId iid = track->getInstrument();
+ Instrument *instrument =
+ getDocument()->getStudio().getInstrumentById(iid);
+ if (instrument && instrument->isPercussion()) isPercussion = true;
+ }
+
+ if (isPercussion) {
+ slotEditSegmentPercussionMatrix(segment);
+ } else {
+ slotEditSegmentMatrix(segment);
+ }
+
+ } else if (client == GeneralConfigurationPage::EventView) {
+ slotEditSegmentEventList(segment);
+ } else {
+ slotEditSegmentNotation(segment);
+ }
+ }
+}
+
+void RosegardenGUIView::slotEditRepeat(Segment *segment,
+ timeT time)
+{
+ SegmentSingleRepeatToCopyCommand *command =
+ new SegmentSingleRepeatToCopyCommand(segment, time);
+ slotAddCommandToHistory(command);
+}
+
+void RosegardenGUIView::slotEditSegmentNotation(Segment* p)
+{
+ SetWaitCursor waitCursor;
+ std::vector<Segment *> segmentsToEdit;
+
+ RG_DEBUG << "\n\n\n\nRosegardenGUIView::slotEditSegmentNotation: p is " << p << endl;
+
+ // The logic here is: If we're calling for this operation to
+ // happen on a particular segment, then open that segment and if
+ // it's part of a selection open all other selected segments too.
+ // If we're not calling for any particular segment, then open all
+ // selected segments if there are any.
+
+ if (haveSelection()) {
+
+ SegmentSelection selection = getSelection();
+
+ if (!p || (selection.find(p) != selection.end())) {
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+ if ((*i)->getType() != Segment::Audio) {
+ segmentsToEdit.push_back(*i);
+ }
+ }
+ } else {
+ if (p->getType() != Segment::Audio) {
+ segmentsToEdit.push_back(p);
+ }
+ }
+
+ } else if (p) {
+ if (p->getType() != Segment::Audio) {
+ segmentsToEdit.push_back(p);
+ }
+ } else {
+ return ;
+ }
+
+ if (segmentsToEdit.empty()) {
+ KMessageBox::sorry(this, i18n("No non-audio segments selected"));
+ return ;
+ }
+
+ slotEditSegmentsNotation(segmentsToEdit);
+}
+
+void RosegardenGUIView::slotEditSegmentsNotation(std::vector<Segment *> segmentsToEdit)
+{
+ NotationView *view = createNotationView(segmentsToEdit);
+ if (view)
+ view->show();
+}
+
+NotationView *
+RosegardenGUIView::createNotationView(std::vector<Segment *> segmentsToEdit)
+{
+ NotationView *notationView =
+ new NotationView(getDocument(), segmentsToEdit, this, true);
+
+ if (!notationView->isOK()) {
+ RG_DEBUG << "slotEditSegmentNotation : operation cancelled" << endl;
+ delete notationView;
+ return 0;
+ }
+
+ // For tempo changes (ugh -- it'd be nicer to make a tempo change
+ // command that could interpret all this stuff from the dialog)
+ //
+ connect(notationView, SIGNAL(changeTempo(timeT,
+ tempoT,
+ tempoT,
+ TempoDialog::TempoDialogAction)),
+ RosegardenGUIApp::self(), SLOT(slotChangeTempo(timeT,
+ tempoT,
+ tempoT,
+ TempoDialog::TempoDialogAction)));
+
+
+ connect(notationView, SIGNAL(windowActivated()),
+ this, SLOT(slotActiveMainWindowChanged()));
+
+ connect(notationView, SIGNAL(selectTrack(int)),
+ this, SLOT(slotSelectTrackSegments(int)));
+
+ connect(notationView, SIGNAL(play()),
+ RosegardenGUIApp::self(), SLOT(slotPlay()));
+ connect(notationView, SIGNAL(stop()),
+ RosegardenGUIApp::self(), SLOT(slotStop()));
+ connect(notationView, SIGNAL(fastForwardPlayback()),
+ RosegardenGUIApp::self(), SLOT(slotFastforward()));
+ connect(notationView, SIGNAL(rewindPlayback()),
+ RosegardenGUIApp::self(), SLOT(slotRewind()));
+ connect(notationView, SIGNAL(fastForwardPlaybackToEnd()),
+ RosegardenGUIApp::self(), SLOT(slotFastForwardToEnd()));
+ connect(notationView, SIGNAL(rewindPlaybackToBeginning()),
+ RosegardenGUIApp::self(), SLOT(slotRewindToBeginning()));
+ connect(notationView, SIGNAL(panic()),
+ RosegardenGUIApp::self(), SLOT(slotPanic()));
+
+ connect(notationView, SIGNAL(saveFile()),
+ RosegardenGUIApp::self(), SLOT(slotFileSave()));
+ connect(notationView, SIGNAL(jumpPlaybackTo(timeT)),
+ getDocument(), SLOT(slotSetPointerPosition(timeT)));
+ connect(notationView, SIGNAL(openInNotation(std::vector<Segment *>)),
+ this, SLOT(slotEditSegmentsNotation(std::vector<Segment *>)));
+ connect(notationView, SIGNAL(openInMatrix(std::vector<Segment *>)),
+ this, SLOT(slotEditSegmentsMatrix(std::vector<Segment *>)));
+ connect(notationView, SIGNAL(openInPercussionMatrix(std::vector<Segment *>)),
+ this, SLOT(slotEditSegmentsPercussionMatrix(std::vector<Segment *>)));
+ connect(notationView, SIGNAL(openInEventList(std::vector<Segment *>)),
+ this, SLOT(slotEditSegmentsEventList(std::vector<Segment *>)));
+/* hjj: WHAT DO DO WITH THIS ?
+ connect(notationView, SIGNAL(editMetadata(QString)),
+ this, SLOT(slotEditMetadata(QString)));
+*/
+ connect(notationView, SIGNAL(editTriggerSegment(int)),
+ this, SLOT(slotEditTriggerSegment(int)));
+ connect(notationView, SIGNAL(staffLabelChanged(TrackId, QString)),
+ this, SLOT(slotChangeTrackLabel(TrackId, QString)));
+ connect(notationView, SIGNAL(toggleSolo(bool)),
+ RosegardenGUIApp::self(), SLOT(slotToggleSolo(bool)));
+ connect(notationView, SIGNAL(editTimeSignature(timeT)),
+ RosegardenGUIApp::self(), SLOT(slotEditTempos(timeT)));
+
+ SequenceManager *sM = getDocument()->getSequenceManager();
+
+ connect(sM, SIGNAL(insertableNoteOnReceived(int, int)),
+ notationView, SLOT(slotInsertableNoteOnReceived(int, int)));
+ connect(sM, SIGNAL(insertableNoteOffReceived(int, int)),
+ notationView, SLOT(slotInsertableNoteOffReceived(int, int)));
+
+ connect(notationView, SIGNAL(stepByStepTargetRequested(QObject *)),
+ this, SIGNAL(stepByStepTargetRequested(QObject *)));
+ connect(this, SIGNAL(stepByStepTargetRequested(QObject *)),
+ notationView, SLOT(slotStepByStepTargetRequested(QObject *)));
+ connect(RosegardenGUIApp::self(), SIGNAL(compositionStateUpdate()),
+ notationView, SLOT(slotCompositionStateUpdate()));
+ connect(this, SIGNAL(compositionStateUpdate()),
+ notationView, SLOT(slotCompositionStateUpdate()));
+
+ // Encourage the notation view window to open to the same
+ // interval as the current segment view
+ if (m_trackEditor->getSegmentCanvas()->horizontalScrollBar()->value() > 1) { // don't scroll unless we need to
+ // first find the time at the center of the visible segment canvas
+ int centerX = (int)(m_trackEditor->getSegmentCanvas()->contentsX() +
+ m_trackEditor->getSegmentCanvas()->visibleWidth() / 2);
+ timeT centerSegmentView = m_trackEditor->getRulerScale()->getTimeForX(centerX);
+ // then scroll the notation view to that time, "localized" for the current segment
+ notationView->scrollToTime(centerSegmentView);
+ notationView->updateView();
+ }
+
+ return notationView;
+}
+
+void RosegardenGUIView::slotEditSegmentMatrix(Segment* p)
+{
+ SetWaitCursor waitCursor;
+
+ std::vector<Segment *> segmentsToEdit;
+
+ // unlike notation, if we're calling for this on a particular
+ // segment we don't open all the other selected segments as well
+ // (fine in notation because they're in a single window)
+
+ if (p) {
+ if (p->getType() != Segment::Audio) {
+ segmentsToEdit.push_back(p);
+ }
+ } else {
+ int count = 0;
+ SegmentSelection selection = getSelection();
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+ if ((*i)->getType() != Segment::Audio) {
+ slotEditSegmentMatrix(*i);
+ if (++count == maxEditorsToOpen)
+ break;
+ }
+ }
+ return ;
+ }
+
+ if (segmentsToEdit.empty()) {
+ KMessageBox::sorry(this, i18n("No non-audio segments selected"));
+ return ;
+ }
+
+ slotEditSegmentsMatrix(segmentsToEdit);
+}
+
+void RosegardenGUIView::slotEditSegmentPercussionMatrix(Segment* p)
+{
+ SetWaitCursor waitCursor;
+
+ std::vector<Segment *> segmentsToEdit;
+
+ // unlike notation, if we're calling for this on a particular
+ // segment we don't open all the other selected segments as well
+ // (fine in notation because they're in a single window)
+
+ if (p) {
+ if (p->getType() != Segment::Audio) {
+ segmentsToEdit.push_back(p);
+ }
+ } else {
+ int count = 0;
+ SegmentSelection selection = getSelection();
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+ if ((*i)->getType() != Segment::Audio) {
+ slotEditSegmentPercussionMatrix(*i);
+ if (++count == maxEditorsToOpen)
+ break;
+ }
+ }
+ return ;
+ }
+
+ if (segmentsToEdit.empty()) {
+ KMessageBox::sorry(this, i18n("No non-audio segments selected"));
+ return ;
+ }
+
+ slotEditSegmentsPercussionMatrix(segmentsToEdit);
+}
+
+void RosegardenGUIView::slotEditSegmentsMatrix(std::vector<Segment *> segmentsToEdit)
+{
+ int count = 0;
+ for (std::vector<Segment *>::iterator i = segmentsToEdit.begin();
+ i != segmentsToEdit.end(); ++i) {
+ std::vector<Segment *> tmpvec;
+ tmpvec.push_back(*i);
+ MatrixView *view = createMatrixView(tmpvec, false);
+ if (view) {
+ view->show();
+ if (++count == maxEditorsToOpen)
+ break;
+ }
+ }
+}
+
+void RosegardenGUIView::slotEditSegmentsPercussionMatrix(std::vector<Segment *> segmentsToEdit)
+{
+ int count = 0;
+ for (std::vector<Segment *>::iterator i = segmentsToEdit.begin();
+ i != segmentsToEdit.end(); ++i) {
+ std::vector<Segment *> tmpvec;
+ tmpvec.push_back(*i);
+ MatrixView *view = createMatrixView(tmpvec, true);
+ if (view) {
+ view->show();
+ if (++count == maxEditorsToOpen)
+ break;
+ }
+ }
+}
+
+MatrixView *
+RosegardenGUIView::createMatrixView(std::vector<Segment *> segmentsToEdit, bool drumMode)
+{
+ MatrixView *matrixView = new MatrixView(getDocument(),
+ segmentsToEdit,
+ this,
+ drumMode);
+
+ // For tempo changes (ugh -- it'd be nicer to make a tempo change
+ // command that could interpret all this stuff from the dialog)
+ //
+ connect(matrixView, SIGNAL(changeTempo(timeT,
+ tempoT,
+ tempoT,
+ TempoDialog::TempoDialogAction)),
+ RosegardenGUIApp::self(), SLOT(slotChangeTempo(timeT,
+ tempoT,
+ tempoT,
+ TempoDialog::TempoDialogAction)));
+
+ connect(matrixView, SIGNAL(windowActivated()),
+ this, SLOT(slotActiveMainWindowChanged()));
+
+ connect(matrixView, SIGNAL(selectTrack(int)),
+ this, SLOT(slotSelectTrackSegments(int)));
+
+ connect(matrixView, SIGNAL(play()),
+ RosegardenGUIApp::self(), SLOT(slotPlay()));
+ connect(matrixView, SIGNAL(stop()),
+ RosegardenGUIApp::self(), SLOT(slotStop()));
+ connect(matrixView, SIGNAL(fastForwardPlayback()),
+ RosegardenGUIApp::self(), SLOT(slotFastforward()));
+ connect(matrixView, SIGNAL(rewindPlayback()),
+ RosegardenGUIApp::self(), SLOT(slotRewind()));
+ connect(matrixView, SIGNAL(fastForwardPlaybackToEnd()),
+ RosegardenGUIApp::self(), SLOT(slotFastForwardToEnd()));
+ connect(matrixView, SIGNAL(rewindPlaybackToBeginning()),
+ RosegardenGUIApp::self(), SLOT(slotRewindToBeginning()));
+ connect(matrixView, SIGNAL(panic()),
+ RosegardenGUIApp::self(), SLOT(slotPanic()));
+
+ connect(matrixView, SIGNAL(saveFile()),
+ RosegardenGUIApp::self(), SLOT(slotFileSave()));
+ connect(matrixView, SIGNAL(jumpPlaybackTo(timeT)),
+ getDocument(), SLOT(slotSetPointerPosition(timeT)));
+ connect(matrixView, SIGNAL(openInNotation(std::vector<Segment *>)),
+ this, SLOT(slotEditSegmentsNotation(std::vector<Segment *>)));
+ connect(matrixView, SIGNAL(openInMatrix(std::vector<Segment *>)),
+ this, SLOT(slotEditSegmentsMatrix(std::vector<Segment *>)));
+ connect(matrixView, SIGNAL(openInEventList(std::vector<Segment *>)),
+ this, SLOT(slotEditSegmentsEventList(std::vector<Segment *>)));
+ connect(matrixView, SIGNAL(editTriggerSegment(int)),
+ this, SLOT(slotEditTriggerSegment(int)));
+ connect(matrixView, SIGNAL(toggleSolo(bool)),
+ RosegardenGUIApp::self(), SLOT(slotToggleSolo(bool)));
+ connect(matrixView, SIGNAL(editTimeSignature(timeT)),
+ RosegardenGUIApp::self(), SLOT(slotEditTempos(timeT)));
+
+ SequenceManager *sM = getDocument()->getSequenceManager();
+
+ connect(sM, SIGNAL(insertableNoteOnReceived(int, int)),
+ matrixView, SLOT(slotInsertableNoteOnReceived(int, int)));
+ connect(sM, SIGNAL(insertableNoteOffReceived(int, int)),
+ matrixView, SLOT(slotInsertableNoteOffReceived(int, int)));
+
+ connect(matrixView, SIGNAL(stepByStepTargetRequested(QObject *)),
+ this, SIGNAL(stepByStepTargetRequested(QObject *)));
+ connect(this, SIGNAL(stepByStepTargetRequested(QObject *)),
+ matrixView, SLOT(slotStepByStepTargetRequested(QObject *)));
+ connect(RosegardenGUIApp::self(), SIGNAL(compositionStateUpdate()),
+ matrixView, SLOT(slotCompositionStateUpdate()));
+ connect(this, SIGNAL(compositionStateUpdate()),
+ matrixView, SLOT(slotCompositionStateUpdate()));
+ connect(this,
+ SIGNAL(instrumentLevelsChanged(InstrumentId,
+ const LevelInfo &)),
+ matrixView,
+ SLOT(slotInstrumentLevelsChanged(InstrumentId,
+ const LevelInfo &)));
+
+ // Encourage the matrix view window to open to the same
+ // interval as the current segment view
+ if (m_trackEditor->getSegmentCanvas()->horizontalScrollBar()->value() > 1) { // don't scroll unless we need to
+ // first find the time at the center of the visible segment canvas
+ int centerX = (int)(m_trackEditor->getSegmentCanvas()->contentsX());
+ // Seems to work better for matrix view to scroll to left side
+ // + m_trackEditor->getSegmentCanvas()->visibleWidth() / 2);
+ timeT centerSegmentView = m_trackEditor->getRulerScale()->getTimeForX(centerX);
+ // then scroll the notation view to that time, "localized" for the current segment
+ matrixView->scrollToTime(centerSegmentView);
+ matrixView->updateView();
+ }
+
+ return matrixView;
+}
+
+void RosegardenGUIView::slotEditSegmentEventList(Segment *p)
+{
+ SetWaitCursor waitCursor;
+
+ std::vector<Segment *> segmentsToEdit;
+
+ // unlike notation, if we're calling for this on a particular
+ // segment we don't open all the other selected segments as well
+ // (fine in notation because they're in a single window)
+
+ if (p) {
+ if (p->getType() != Segment::Audio) {
+ segmentsToEdit.push_back(p);
+ }
+ } else {
+ int count = 0;
+ SegmentSelection selection = getSelection();
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+ if ((*i)->getType() != Segment::Audio) {
+ slotEditSegmentEventList(*i);
+ if (++count == maxEditorsToOpen)
+ break;
+ }
+ }
+ return ;
+ }
+
+ if (segmentsToEdit.empty()) {
+ KMessageBox::sorry(this, i18n("No non-audio segments selected"));
+ return ;
+ }
+
+ slotEditSegmentsEventList(segmentsToEdit);
+}
+
+void RosegardenGUIView::slotEditSegmentsEventList(std::vector<Segment *> segmentsToEdit)
+{
+ int count = 0;
+ for (std::vector<Segment *>::iterator i = segmentsToEdit.begin();
+ i != segmentsToEdit.end(); ++i) {
+ std::vector<Segment *> tmpvec;
+ tmpvec.push_back(*i);
+ EventView *view = createEventView(tmpvec);
+ if (view) {
+ view->show();
+ if (++count == maxEditorsToOpen)
+ break;
+ }
+ }
+}
+
+void RosegardenGUIView::slotEditTriggerSegment(int id)
+{
+ SetWaitCursor waitCursor;
+
+ std::vector<Segment *> segmentsToEdit;
+
+ Segment *s = getDocument()->getComposition().getTriggerSegment(id);
+
+ if (s) {
+ segmentsToEdit.push_back(s);
+ } else {
+ return ;
+ }
+
+ slotEditSegmentsEventList(segmentsToEdit);
+}
+
+void RosegardenGUIView::slotSegmentAutoSplit(Segment *segment)
+{
+ AudioSplitDialog aSD(this, segment, getDocument());
+
+ if (aSD.exec() == QDialog::Accepted) {
+ KCommand *command =
+ new AudioSegmentAutoSplitCommand(getDocument(),
+ segment, aSD.getThreshold());
+ slotAddCommandToHistory(command);
+ }
+}
+
+void RosegardenGUIView::slotEditSegmentAudio(Segment *segment)
+{
+ std::cout << "RosegardenGUIView::slotEditSegmentAudio() - "
+ << "starting external audio editor" << std::endl;
+
+ KConfig* config = kapp->config();
+ config->setGroup(GeneralOptionsConfigGroup);
+
+ QString application = config->readEntry("externalaudioeditor", "");
+
+ if (application == "") {
+ application = AudioConfigurationPage::getBestAvailableAudioEditor();
+ }
+
+ QStringList splitCommand = QStringList::split(" ", application);
+
+ if (splitCommand.size() == 0) {
+
+ std::cerr << "RosegardenGUIView::slotEditSegmentAudio() - "
+ << "external editor \"" << application.data()
+ << "\" not found" << std::endl;
+
+ KMessageBox::sorry(this,
+ i18n("You've not yet defined an audio editor for Rosegarden to use.\nSee Settings -> Configure Rosegarden -> Audio."));
+
+ return ;
+ }
+
+ QFileInfo *appInfo = new QFileInfo(splitCommand[0]);
+ if (appInfo->exists() == false || appInfo->isExecutable() == false) {
+ std::cerr << "RosegardenGUIView::slotEditSegmentAudio() - "
+ << "can't execute \"" << splitCommand[0] << "\""
+ << std::endl;
+ return;
+ }
+
+ AudioFile *aF = getDocument()->getAudioFileManager().
+ getAudioFile(segment->getAudioFileId());
+ if (aF == 0) {
+ std::cerr << "RosegardenGUIView::slotEditSegmentAudio() - "
+ << "can't find audio file" << std::endl;
+ return ;
+ }
+
+ // wait cursor
+ QApplication::setOverrideCursor(QCursor(Qt::waitCursor));
+
+ // Prepare the process
+ //
+ KProcess *process = new KProcess();
+ (*process) << splitCommand;
+ (*process) << QString(aF->getFilename().c_str());
+
+ // Start it
+ //
+ if (!process->start()) {
+ std::cerr << "RosegardenGUIView::slotEditSegmentAudio() - "
+ << "can't start external editor" << std::endl;
+ }
+
+ // restore cursor
+ QApplication::restoreOverrideCursor();
+
+}
+
+void RosegardenGUIView::setZoomSize(double size)
+{
+ m_rulerScale->setUnitsPerPixel(size);
+
+ double duration44 = TimeSignature(4, 4).getBarDuration();
+
+ double xScale = duration44 / (size * barWidth44);
+ RG_DEBUG << "RosegardenGUIView::setZoomSize - xScale = " << xScale << endl;
+
+ m_trackEditor->slotSetPointerPosition
+ (getDocument()->getComposition().getPosition());
+
+ m_trackEditor->getSegmentCanvas()->clearSegmentRectsCache(true);
+ m_trackEditor->getSegmentCanvas()->slotUpdateSize();
+ m_trackEditor->getSegmentCanvas()->slotUpdateSegmentsDrawBuffer();
+
+ if (m_trackEditor->getTempoRuler()) {
+ m_trackEditor->getTempoRuler()->repaint();
+ }
+
+ if (m_trackEditor->getChordNameRuler()) {
+ m_trackEditor->getChordNameRuler()->repaint();
+ }
+
+ if (m_trackEditor->getTopStandardRuler()) {
+ m_trackEditor->getTopStandardRuler()->repaint();
+ }
+
+ if (m_trackEditor->getBottomStandardRuler()) {
+ m_trackEditor->getBottomStandardRuler()->repaint();
+ }
+}
+
+void RosegardenGUIView::slotSelectTrackSegments(int trackId)
+{
+ // update the instrument parameter box
+ Composition &comp = getDocument()->getComposition();
+ Track *track = comp.getTrackById(trackId);
+
+ if (track == 0)
+ return ;
+
+ // Show the selection on the track buttons. Find the position.
+ //
+ m_trackEditor->getTrackButtons()->selectLabel(track->getPosition());
+ m_trackEditor->slotScrollToTrack(track->getPosition());
+
+ SegmentSelection segments;
+
+ for (Composition::iterator i =
+ getDocument()->getComposition().begin();
+ i != getDocument()->getComposition().end(); i++) {
+ if (((int)(*i)->getTrack()) == trackId)
+ segments.insert(*i);
+ }
+
+ // Store the selected Track in the Composition
+ //
+ comp.setSelectedTrack(trackId);
+
+ m_trackParameterBox->slotSelectedTrackChanged();
+
+ slotUpdateInstrumentParameterBox(comp.getTrackById(trackId)->
+ getInstrument());
+
+
+ slotPropagateSegmentSelection(segments);
+
+ // inform
+ emit segmentsSelected(segments);
+ emit compositionStateUpdate();
+}
+
+void RosegardenGUIView::slotPropagateSegmentSelection(const SegmentSelection &segments)
+{
+ // Send this signal to the GUI to activate the correct tool
+ // on the toolbar so that we have a SegmentSelector object
+ // to write the Segments into
+ //
+ if (!segments.empty()) {
+ emit activateTool(SegmentSelector::ToolName);
+ }
+
+ // Send the segment list even if it's empty as we
+ // use that to clear any current selection
+ //
+ m_trackEditor->getSegmentCanvas()->slotSelectSegments(segments);
+
+ // update the segment parameter box
+ m_segmentParameterBox->useSegments(segments);
+
+ if (!segments.empty()) {
+ emit stateChange("have_selection", true);
+ if (!segments.hasNonAudioSegment()) {
+ emit stateChange("audio_segment_selected", true);
+ }
+ } else {
+ emit stateChange("have_selection", false);
+ }
+}
+
+void RosegardenGUIView::slotSelectAllSegments()
+{
+ SegmentSelection segments;
+
+ InstrumentId instrument = 0;
+ bool haveInstrument = false;
+ bool multipleInstruments = false;
+
+ Composition &comp = getDocument()->getComposition();
+
+ for (Composition::iterator i = comp.begin(); i != comp.end(); ++i) {
+
+ InstrumentId myInstrument =
+ comp.getTrackById((*i)->getTrack())->getInstrument();
+
+ if (haveInstrument) {
+ if (myInstrument != instrument) {
+ multipleInstruments = true;
+ }
+ } else {
+ instrument = myInstrument;
+ haveInstrument = true;
+ }
+
+ segments.insert(*i);
+ }
+
+ // Send this signal to the GUI to activate the correct tool
+ // on the toolbar so that we have a SegmentSelector object
+ // to write the Segments into
+ //
+ if (!segments.empty()) {
+ emit activateTool(SegmentSelector::ToolName);
+ }
+
+ // Send the segment list even if it's empty as we
+ // use that to clear any current selection
+ //
+ m_trackEditor->getSegmentCanvas()->slotSelectSegments(segments);
+
+ // update the segment parameter box
+ m_segmentParameterBox->useSegments(segments);
+
+ // update the instrument parameter box
+ if (haveInstrument && !multipleInstruments) {
+ slotUpdateInstrumentParameterBox(instrument);
+ } else {
+ m_instrumentParameterBox->useInstrument(0);
+ }
+
+ //!!! similarly, how to set no selected track?
+ //comp.setSelectedTrack(trackId);
+
+ if (!segments.empty()) {
+ emit stateChange("have_selection", true);
+ if (!segments.hasNonAudioSegment()) {
+ emit stateChange("audio_segment_selected", true);
+ }
+ } else {
+ emit stateChange("have_selection", false);
+ }
+
+ // inform
+ //!!! inform what? is this signal actually used?
+ emit segmentsSelected(segments);
+}
+
+void RosegardenGUIView::slotUpdateInstrumentParameterBox(int id)
+{
+ Studio &studio = getDocument()->getStudio();
+ Instrument *instrument = studio.getInstrumentById(id);
+ Composition &comp = getDocument()->getComposition();
+
+ Track *track = comp.getTrackById(comp.getSelectedTrack());
+
+ // Reset the instrument
+ //
+ m_instrumentParameterBox->useInstrument(instrument);
+
+ // Then do this instrument/track fiddling
+ //
+ /*
+ if (track && instrument &&
+ instrument->getType() == Instrument::Audio)
+ {
+ // Set the mute status
+ m_instrumentParameterBox->setMute(track->isMuted());
+
+ // Set the record track
+ m_instrumentParameterBox->setRecord(
+ track->getId() == comp.getRecordTrack());
+
+ // Set solo
+ m_instrumentParameterBox->setSolo(
+ comp.isSolo() && (track->getId() == comp.getSelectedTrack()));
+ }
+ */
+ emit checkTrackAssignments();
+}
+
+void RosegardenGUIView::showVisuals(const MappedEvent *mE)
+{
+ double valueLeft = ((double)mE->getData1()) / 127.0;
+ double valueRight = ((double)mE->getData2()) / 127.0;
+
+ if (mE->getType() == MappedEvent::AudioLevel) {
+
+ // Send to the high sensitivity instrument parameter box
+ // (if any)
+ //
+ if (m_instrumentParameterBox->getSelectedInstrument() &&
+ mE->getInstrument() ==
+ m_instrumentParameterBox->getSelectedInstrument()->getId()) {
+ float dBleft = AudioLevel::fader_to_dB
+ (mE->getData1(), 127, AudioLevel::LongFader);
+ float dBright = AudioLevel::fader_to_dB
+ (mE->getData2(), 127, AudioLevel::LongFader);
+
+ m_instrumentParameterBox->setAudioMeter(dBleft, dBright,
+ AudioLevel::DB_FLOOR,
+ AudioLevel::DB_FLOOR);
+ }
+
+ // Don't always send all audio levels so we don't
+ // get vu meter flickering on track meters
+ //
+ if (valueLeft < 0.05 && valueRight < 0.05)
+ return ;
+
+ } else if (mE->getType() != MappedEvent::MidiNote)
+ return ;
+
+ m_trackEditor->getTrackButtons()->
+ slotSetMetersByInstrument((valueLeft + valueRight) / 2,
+ mE->getInstrument());
+
+}
+
+void
+RosegardenGUIView::updateMeters(SequencerMapper *mapper)
+{
+ const int unknownState = 0, oldState = 1, newState = 2;
+
+ typedef std::map<InstrumentId, int> StateMap;
+ static StateMap states;
+ static StateMap recStates;
+
+ typedef std::map<InstrumentId, LevelInfo> LevelMap;
+ static LevelMap levels;
+ static LevelMap recLevels;
+
+ for (StateMap::iterator i = states.begin(); i != states.end(); ++i) {
+ i->second = unknownState;
+ }
+ for (StateMap::iterator i = recStates.begin(); i != recStates.end(); ++i) {
+ i->second = unknownState;
+ }
+
+ for (Composition::trackcontainer::iterator i =
+ getDocument()->getComposition().getTracks().begin();
+ i != getDocument()->getComposition().getTracks().end(); ++i) {
+
+ Track *track = i->second;
+ if (!track)
+ continue;
+
+ InstrumentId instrumentId = track->getInstrument();
+
+ if (states[instrumentId] == unknownState) {
+ bool isNew = mapper->getInstrumentLevel(instrumentId,
+ levels[instrumentId]);
+ states[instrumentId] = (isNew ? newState : oldState);
+ }
+
+ if (recStates[instrumentId] == unknownState) {
+ bool isNew = mapper->getInstrumentRecordLevel(instrumentId,
+ recLevels[instrumentId]);
+ recStates[instrumentId] = (isNew ? newState : oldState);
+ }
+
+ if (states[instrumentId] == oldState &&
+ recStates[instrumentId] == oldState)
+ continue;
+
+ Instrument *instrument =
+ getDocument()->getStudio().getInstrumentById(instrumentId);
+ if (!instrument)
+ continue;
+
+ // This records the level of this instrument, not neccessarily
+ // caused by notes on this particular track.
+ LevelInfo &info = levels[instrumentId];
+ LevelInfo &recInfo = recLevels[instrumentId];
+
+ if (instrument->getType() == Instrument::Audio ||
+ instrument->getType() == Instrument::SoftSynth) {
+
+ float dBleft = AudioLevel::DB_FLOOR;
+ float dBright = AudioLevel::DB_FLOOR;
+ float recDBleft = AudioLevel::DB_FLOOR;
+ float recDBright = AudioLevel::DB_FLOOR;
+
+ bool toSet = false;
+
+ if (states[instrumentId] == newState &&
+ (getDocument()->getSequenceManager()->getTransportStatus()
+ != STOPPED)) {
+
+ if (info.level != 0 || info.levelRight != 0) {
+ dBleft = AudioLevel::fader_to_dB
+ (info.level, 127, AudioLevel::LongFader);
+ dBright = AudioLevel::fader_to_dB
+ (info.levelRight, 127, AudioLevel::LongFader);
+ }
+ toSet = true;
+ m_trackEditor->getTrackButtons()->slotSetTrackMeter
+ ((info.level + info.levelRight) / 254.0, track->getPosition());
+ }
+
+ if (recStates[instrumentId] == newState &&
+ instrument->getType() == Instrument::Audio &&
+ (getDocument()->getSequenceManager()->getTransportStatus()
+ != PLAYING)) {
+
+ if (recInfo.level != 0 || recInfo.levelRight != 0) {
+ recDBleft = AudioLevel::fader_to_dB
+ (recInfo.level, 127, AudioLevel::LongFader);
+ recDBright = AudioLevel::fader_to_dB
+ (recInfo.levelRight, 127, AudioLevel::LongFader);
+ }
+ toSet = true;
+ }
+
+ if (toSet &&
+ m_instrumentParameterBox->getSelectedInstrument() &&
+ instrument->getId() ==
+ m_instrumentParameterBox->getSelectedInstrument()->getId()) {
+
+ m_instrumentParameterBox->setAudioMeter(dBleft, dBright,
+ recDBleft, recDBright);
+ }
+
+ } else {
+ // Not audio or softsynth
+ if (info.level == 0)
+ continue;
+
+ if (getDocument()->getSequenceManager()->getTransportStatus()
+ != STOPPED) {
+
+ // The information in 'info' is specific for this instrument, not
+ // for this track.
+ //m_trackEditor->getTrackButtons()->slotSetTrackMeter
+ // (info.level / 127.0, track->getPosition());
+ m_trackEditor->getTrackButtons()->slotSetMetersByInstrument
+ (info.level / 127.0, instrumentId);
+ }
+ }
+ }
+
+ for (StateMap::iterator i = states.begin(); i != states.end(); ++i) {
+ if (i->second == newState) {
+ emit instrumentLevelsChanged(i->first, levels[i->first]);
+ }
+ }
+}
+
+void
+RosegardenGUIView::updateMonitorMeters(SequencerMapper *mapper)
+{
+ Instrument *instrument =
+ m_instrumentParameterBox->getSelectedInstrument();
+ if (!instrument ||
+ (instrument->getType() != Instrument::Audio))
+ return ;
+
+ LevelInfo level;
+ if (!mapper->getInstrumentRecordLevel(instrument->getId(), level))
+ return ;
+
+ float dBleft = AudioLevel::fader_to_dB
+ (level.level, 127, AudioLevel::LongFader);
+ float dBright = AudioLevel::fader_to_dB
+ (level.levelRight, 127, AudioLevel::LongFader);
+
+ m_instrumentParameterBox->setAudioMeter
+ (AudioLevel::DB_FLOOR, AudioLevel::DB_FLOOR,
+ dBleft, dBright);
+}
+
+void
+RosegardenGUIView::slotSelectedSegments(const SegmentSelection &segments)
+{
+ // update the segment parameter box
+ m_segmentParameterBox->useSegments(segments);
+
+ if (!segments.empty()) {
+ emit stateChange("have_selection", true);
+ if (!segments.hasNonAudioSegment())
+ emit stateChange("audio_segment_selected", true);
+ } else {
+ emit stateChange("have_selection", false);
+ }
+
+ emit segmentsSelected(segments);
+}
+
+void RosegardenGUIView::slotShowRulers(bool v)
+{
+ if (v) {
+ m_trackEditor->getTopStandardRuler()->getLoopRuler()->show();
+ m_trackEditor->getBottomStandardRuler()->getLoopRuler()->show();
+ } else {
+ m_trackEditor->getTopStandardRuler()->getLoopRuler()->hide();
+ m_trackEditor->getBottomStandardRuler()->getLoopRuler()->hide();
+ }
+}
+
+void RosegardenGUIView::slotShowTempoRuler(bool v)
+{
+ if (v) {
+ m_trackEditor->getTempoRuler()->show();
+ } else {
+ m_trackEditor->getTempoRuler()->hide();
+ }
+}
+
+void RosegardenGUIView::slotShowChordNameRuler(bool v)
+{
+ if (v) {
+ m_trackEditor->getChordNameRuler()->setStudio(&getDocument()->getStudio());
+ m_trackEditor->getChordNameRuler()->show();
+ } else {
+ m_trackEditor->getChordNameRuler()->hide();
+ }
+}
+
+void RosegardenGUIView::slotShowPreviews(bool v)
+{
+ m_trackEditor->getSegmentCanvas()->setShowPreviews(v);
+ m_trackEditor->getSegmentCanvas()->slotUpdateSegmentsDrawBuffer();
+}
+
+void RosegardenGUIView::slotShowSegmentLabels(bool v)
+{
+ m_trackEditor->getSegmentCanvas()->setShowSegmentLabels(v);
+ m_trackEditor->getSegmentCanvas()->slotUpdateSegmentsDrawBuffer();
+}
+
+void RosegardenGUIView::slotAddTracks(unsigned int nbTracks,
+ InstrumentId id, int pos)
+{
+ RG_DEBUG << "RosegardenGUIView::slotAddTracks(" << nbTracks << ", " << pos << ")" << endl;
+ m_trackEditor->slotAddTracks(nbTracks, id, pos);
+}
+
+void RosegardenGUIView::slotDeleteTracks(
+ std::vector<TrackId> tracks)
+{
+ RG_DEBUG << "RosegardenGUIView::slotDeleteTracks - "
+ << "deleting " << tracks.size() << " tracks"
+ << endl;
+
+ m_trackEditor->slotDeleteTracks(tracks);
+}
+
+MultiViewCommandHistory*
+RosegardenGUIView::getCommandHistory()
+{
+ return getDocument()->getCommandHistory();
+}
+
+void
+RosegardenGUIView::slotAddCommandToHistory(KCommand *command)
+{
+ getCommandHistory()->addCommand(command);
+}
+
+void
+RosegardenGUIView::slotChangeInstrumentLabel(InstrumentId id,
+ QString label)
+{
+ m_trackEditor->getTrackButtons()->changeInstrumentLabel(id, label);
+}
+
+void
+RosegardenGUIView::slotChangeTrackLabel(TrackId id,
+ QString label)
+{
+ m_trackEditor->getTrackButtons()->changeTrackLabel(id, label);
+}
+
+void
+RosegardenGUIView::slotAddAudioSegment(AudioFileId audioId,
+ TrackId trackId,
+ timeT position,
+ const RealTime &startTime,
+ const RealTime &endTime)
+{
+ AudioSegmentInsertCommand *command =
+ new AudioSegmentInsertCommand(getDocument(),
+ trackId,
+ position,
+ audioId,
+ startTime,
+ endTime);
+ slotAddCommandToHistory(command);
+
+ Segment *newSegment = command->getNewSegment();
+ if (newSegment) {
+ SegmentSelection selection;
+ selection.insert(newSegment);
+ slotPropagateSegmentSelection(selection);
+ emit segmentsSelected(selection);
+ }
+}
+
+void
+RosegardenGUIView::slotAddAudioSegmentCurrentPosition(AudioFileId audioFileId,
+ const RealTime &startTime,
+ const RealTime &endTime)
+{
+ Composition &comp = getDocument()->getComposition();
+
+ AudioSegmentInsertCommand *command =
+ new AudioSegmentInsertCommand(getDocument(),
+ comp.getSelectedTrack(),
+ comp.getPosition(),
+ audioFileId,
+ startTime,
+ endTime);
+ slotAddCommandToHistory(command);
+
+ Segment *newSegment = command->getNewSegment();
+ if (newSegment) {
+ SegmentSelection selection;
+ selection.insert(newSegment);
+ slotPropagateSegmentSelection(selection);
+ emit segmentsSelected(selection);
+ }
+}
+
+void
+RosegardenGUIView::slotAddAudioSegmentDefaultPosition(AudioFileId audioFileId,
+ const RealTime &startTime,
+ const RealTime &endTime)
+{
+ // Add at current track if it's an audio track, otherwise at first
+ // empty audio track if there is one, otherwise at first audio track.
+ // This behaviour should be of no interest to proficient users (who
+ // should have selected the right track already, or be using drag-
+ // and-drop) but it should save beginners from inserting an audio
+ // segment and being quite unable to work out why it won't play
+
+ Composition &comp = getDocument()->getComposition();
+ Studio &studio = getDocument()->getStudio();
+
+ TrackId currentTrackId = comp.getSelectedTrack();
+ Track *track = comp.getTrackById(currentTrackId);
+
+ if (track) {
+ InstrumentId ii = track->getInstrument();
+ Instrument *instrument = studio.getInstrumentById(ii);
+
+ if (instrument &&
+ instrument->getType() == Instrument::Audio) {
+ slotAddAudioSegment(audioFileId, currentTrackId,
+ comp.getPosition(), startTime, endTime);
+ return ;
+ }
+ }
+
+ // current track is not an audio track, find a more suitable one
+
+ TrackId bestSoFar = currentTrackId;
+
+ for (Composition::trackcontainer::const_iterator
+ ti = comp.getTracks().begin();
+ ti != comp.getTracks().end(); ++ti) {
+
+ InstrumentId ii = ti->second->getInstrument();
+ Instrument *instrument = studio.getInstrumentById(ii);
+
+ if (instrument &&
+ instrument->getType() == Instrument::Audio) {
+
+ if (bestSoFar == currentTrackId)
+ bestSoFar = ti->first;
+ bool haveSegment = false;
+
+ for (Composition::segmentcontainer::const_iterator si =
+ comp.getSegments().begin();
+ si != comp.getSegments().end(); ++si) {
+ if ((*si)->getTrack() == ti->first) {
+ // there's a segment on this track
+ haveSegment = true;
+ break;
+ }
+ }
+
+ if (!haveSegment) { // perfect
+ slotAddAudioSegment(audioFileId, ti->first,
+ comp.getPosition(), startTime, endTime);
+ return ;
+ }
+ }
+ }
+
+ slotAddAudioSegment(audioFileId, bestSoFar,
+ comp.getPosition(), startTime, endTime);
+ return ;
+}
+
+void
+RosegardenGUIView::slotDroppedNewAudio(QString audioDesc)
+{
+ QTextIStream s(&audioDesc);
+
+ QString url;
+ int trackId;
+ timeT time;
+ url = s.readLine();
+ s >> trackId;
+ s >> time;
+
+ std::cerr << "RosegardenGUIView::slotDroppedNewAudio: url " << url << ", trackId " << trackId << ", time " << time << std::endl;
+
+ RosegardenGUIApp *app = RosegardenGUIApp::self();
+ AudioFileManager &aFM = getDocument()->getAudioFileManager();
+
+ AudioFileId audioFileId = 0;
+
+ int sampleRate = 0;
+ if (getDocument()->getSequenceManager()) {
+ sampleRate = getDocument()->getSequenceManager()->getSampleRate();
+ }
+
+ KURL kurl(url);
+ if (!kurl.isLocalFile()) {
+ if (!RosegardenGUIApp::self()->testAudioPath("importing a remote audio file")) return;
+ } else if (aFM.fileNeedsConversion(qstrtostr(kurl.path()), sampleRate)) {
+ if (!RosegardenGUIApp::self()->testAudioPath("importing an audio file that needs to be converted or resampled")) return;
+ }
+
+ ProgressDialog progressDlg(i18n("Adding audio file..."),
+ 100,
+ this);
+
+ CurrentProgressDialog::set(&progressDlg);
+ progressDlg.progressBar()->hide();
+ progressDlg.show();
+
+ // Connect the progress dialog
+ //
+ connect(&aFM, SIGNAL(setProgress(int)),
+ progressDlg.progressBar(), SLOT(setValue(int)));
+ connect(&aFM, SIGNAL(setOperationName(QString)),
+ &progressDlg, SLOT(slotSetOperationName(QString)));
+ connect(&progressDlg, SIGNAL(cancelClicked()),
+ &aFM, SLOT(slotStopImport()));
+
+ try {
+ audioFileId = aFM.importURL(kurl, sampleRate);
+ } catch (AudioFileManager::BadAudioPathException e) {
+ CurrentProgressDialog::freeze();
+ QString errorString = i18n("Can't add dropped file. ") + strtoqstr(e.getMessage());
+ KMessageBox::sorry(this, errorString);
+ return ;
+ } catch (SoundFile::BadSoundFileException e) {
+ CurrentProgressDialog::freeze();
+ QString errorString = i18n("Can't add dropped file. ") + strtoqstr(e.getMessage());
+ KMessageBox::sorry(this, errorString);
+ return ;
+ }
+
+ disconnect(&progressDlg, SIGNAL(cancelClicked()),
+ &aFM, SLOT(slotStopImport()));
+ connect(&progressDlg, SIGNAL(cancelClicked()),
+ &aFM, SLOT(slotStopPreview()));
+ progressDlg.progressBar()->show();
+ progressDlg.slotSetOperationName(i18n("Generating audio preview..."));
+
+ try {
+ aFM.generatePreview(audioFileId);
+ } catch (Exception e) {
+ CurrentProgressDialog::freeze();
+ QString message = strtoqstr(e.getMessage()) + "\n\n" +
+ i18n("Try copying this file to a directory where you have write permission and re-add it");
+ KMessageBox::information(this, message);
+ //return false;
+ }
+
+ disconnect(&progressDlg, SIGNAL(cancelClicked()),
+ &aFM, SLOT(slotStopPreview()));
+
+ // add the file at the sequencer
+ emit addAudioFile(audioFileId);
+
+ // Now fetch file details
+ //
+ AudioFile *aF = aFM.getAudioFile(audioFileId);
+
+ if (aF) {
+ slotAddAudioSegment(audioFileId, trackId, time,
+ RealTime(0, 0), aF->getLength());
+
+ RG_DEBUG << "RosegardenGUIView::slotDroppedNewAudio("
+ << "file = " << url
+ << ", trackid = " << trackId
+ << ", time = " << time << endl;
+ }
+}
+
+void
+RosegardenGUIView::slotDroppedAudio(QString audioDesc)
+{
+ QTextIStream s(&audioDesc);
+
+ AudioFileId audioFileId;
+ TrackId trackId;
+ timeT position;
+ RealTime startTime, endTime;
+
+ // read the audio info
+ s >> audioFileId;
+ s >> trackId;
+ s >> position;
+ s >> startTime.sec;
+ s >> startTime.nsec;
+ s >> endTime.sec;
+ s >> endTime.nsec;
+
+ RG_DEBUG << "RosegardenGUIView::slotDroppedAudio("
+ //<< audioDesc
+ << ") : audioFileId = " << audioFileId
+ << " - trackId = " << trackId
+ << " - position = " << position
+ << " - startTime.sec = " << startTime.sec
+ << " - startTime.nsec = " << startTime.nsec
+ << " - endTime.sec = " << endTime.sec
+ << " - endTime.nsec = " << endTime.nsec
+ << endl;
+
+ slotAddAudioSegment(audioFileId, trackId, position, startTime, endTime);
+}
+
+void
+RosegardenGUIView::slotSetMuteButton(TrackId track, bool value)
+{
+ RG_DEBUG << "RosegardenGUIView::slotSetMuteButton - track id = " << track
+ << ", value = " << value << endl;
+
+ m_trackEditor->getTrackButtons()->setMuteButton(track, value);
+ Track *trackObj = getDocument()->
+ getComposition().getTrackById(track);
+ /*
+ // to fix 739544
+ if (m_instrumentParameterBox->getSelectedInstrument() &&
+ m_instrumentParameterBox->getSelectedInstrument()->getId() ==
+ trackObj->getInstrument())
+ {
+ m_instrumentParameterBox->setMute(value);
+ }
+ */
+ // set the value in the composition
+ trackObj->setMuted(value);
+
+ getDocument()->slotDocumentModified(); // set the modification flag
+
+}
+
+void
+RosegardenGUIView::slotSetMute(InstrumentId id, bool value)
+{
+ RG_DEBUG << "RosegardenGUIView::slotSetMute - "
+ << "id = " << id
+ << ",value = " << value << endl;
+
+ Composition &comp = getDocument()->getComposition();
+ Composition::trackcontainer &tracks = comp.getTracks();
+ Composition::trackiterator it;
+
+ for (it = tracks.begin(); it != tracks.end(); ++it) {
+ if ((*it).second->getInstrument() == id)
+ slotSetMuteButton((*it).second->getId(), value);
+ }
+
+}
+
+void
+RosegardenGUIView::slotSetRecord(InstrumentId id, bool value)
+{
+ RG_DEBUG << "RosegardenGUIView::slotSetRecord - "
+ << "id = " << id
+ << ",value = " << value << endl;
+ /*
+ // IPB
+ //
+ m_instrumentParameterBox->setRecord(value);
+ */
+ Composition &comp = getDocument()->getComposition();
+ Composition::trackcontainer &tracks = comp.getTracks();
+ Composition::trackiterator it;
+#ifdef NOT_DEFINED
+
+ for (it = tracks.begin(); it != tracks.end(); ++it) {
+ if (comp.getSelectedTrack() == (*it).second->getId()) {
+ //!!! MTR m_trackEditor->getTrackButtons()->
+ // setRecordTrack((*it).second->getPosition());
+ //!!! MTR is this needed? I think probably not
+ slotUpdateInstrumentParameterBox((*it).second->getInstrument());
+ }
+ }
+#endif
+ Studio &studio = getDocument()->getStudio();
+ Instrument *instr = studio.getInstrumentById(id);
+}
+
+void
+RosegardenGUIView::slotSetSolo(InstrumentId id, bool value)
+{
+ RG_DEBUG << "RosegardenGUIView::slotSetSolo - "
+ << "id = " << id
+ << ",value = " << value << endl;
+
+ emit toggleSolo(value);
+}
+
+void
+RosegardenGUIView::slotUpdateRecordingSegment(Segment *segment,
+ timeT )
+{
+ // We're only interested in this on the first call per recording segment,
+ // when we possibly create a view for it
+ static Segment *lastRecordingSegment = 0;
+
+ if (segment == lastRecordingSegment)
+ return ;
+ lastRecordingSegment = segment;
+
+ KConfig* config = kapp->config();
+ config->setGroup(GeneralOptionsConfigGroup);
+
+ int tracking = config->readUnsignedNumEntry("recordtracking", 0);
+ if (tracking != 1)
+ return ;
+
+ RG_DEBUG << "RosegardenGUIView::slotUpdateRecordingSegment: segment is " << segment << ", lastRecordingSegment is " << lastRecordingSegment << ", opening a new view" << endl;
+
+ std::vector<Segment *> segments;
+ segments.push_back(segment);
+
+ NotationView *view = createNotationView(segments);
+ if (!view)
+ return ;
+
+ /* signal no longer exists
+ QObject::connect
+ (getDocument(), SIGNAL(recordingSegmentUpdated(Segment *, timeT)),
+ view, SLOT(slotUpdateRecordingSegment(Segment *, timeT)));
+ */
+
+ view->show();
+}
+
+void
+RosegardenGUIView::slotSynchroniseWithComposition()
+{
+ // Track buttons
+ //
+ m_trackEditor->getTrackButtons()->slotSynchroniseWithComposition();
+
+ // Update all IPBs
+ //
+ Composition &comp = getDocument()->getComposition();
+ Track *track = comp.getTrackById(comp.getSelectedTrack());
+ slotUpdateInstrumentParameterBox(track->getInstrument());
+
+ m_instrumentParameterBox->slotUpdateAllBoxes();
+}
+
+void
+RosegardenGUIView::windowActivationChange(bool)
+{
+ if (isActiveWindow()) {
+ slotActiveMainWindowChanged(this);
+ }
+}
+
+void
+RosegardenGUIView::slotActiveMainWindowChanged(const QWidget *w)
+{
+ m_lastActiveMainWindow = w;
+}
+
+void
+RosegardenGUIView::slotActiveMainWindowChanged()
+{
+ const QWidget *w = dynamic_cast<const QWidget *>(sender());
+ if (w)
+ slotActiveMainWindowChanged(w);
+}
+
+void
+RosegardenGUIView::slotControllerDeviceEventReceived(MappedEvent *e)
+{
+ RG_DEBUG << "Controller device event received - send to " << (void *)m_lastActiveMainWindow << " (I am " << this << ")" << endl;
+
+ //!!! So, what _should_ we do with these?
+
+ // -- external controller that sends e.g. volume control for each
+ // of a number of channels -> if mixer present, use control to adjust
+ // tracks on mixer
+
+ // -- external controller that sends e.g. separate controllers on
+ // the same channel for adjusting various parameters -> if IPB
+ // visible, adjust it. Should we use the channel to select the
+ // track? maybe as an option
+
+ // do we actually need the last active main window for either of
+ // these? -- yes, to determine whether to send to mixer or to IPB
+ // in the first place. Send to audio mixer if active, midi mixer
+ // if active, plugin dialog if active, otherwise keep it for
+ // ourselves for the IPB. But, we'll do that by having the edit
+ // views pass it back to us.
+
+ // -- then we need to send back out to device.
+
+ //!!! special cases: controller 81 received by any window ->
+ // select window 0->main, 1->audio mix, 2->midi mix
+
+ //!!! controller 82 received by main window -> select track
+
+ //!!! these obviously should be configurable
+
+ if (e->getType() == MappedEvent::MidiController) {
+
+ if (e->getData1() == 81) {
+
+ // select window
+ int window = e->getData2();
+
+ if (window < 10) { // me
+
+ show();
+ raise();
+ setActiveWindow();
+
+ } else if (window < 20) {
+
+ RosegardenGUIApp::self()->slotOpenAudioMixer();
+
+ } else if (window < 30) {
+
+ RosegardenGUIApp::self()->slotOpenMidiMixer();
+ }
+ }
+ }
+
+ emit controllerDeviceEventReceived(e, m_lastActiveMainWindow);
+}
+
+void
+RosegardenGUIView::slotControllerDeviceEventReceived(MappedEvent *e, const void *preferredCustomer)
+{
+ if (preferredCustomer != this)
+ return ;
+ RG_DEBUG << "RosegardenGUIView::slotControllerDeviceEventReceived: this one's for me" << endl;
+ raise();
+
+ RG_DEBUG << "Event is type: " << int(e->getType()) << ", channel " << int(e->getRecordedChannel()) << ", data1 " << int(e->getData1()) << ", data2 " << int(e->getData2()) << endl;
+
+ Composition &comp = getDocument()->getComposition();
+ Studio &studio = getDocument()->getStudio();
+
+ TrackId currentTrackId = comp.getSelectedTrack();
+ Track *track = comp.getTrackById(currentTrackId);
+
+ // If the event is a control change on channel n, then (if
+ // follow-channel is on) switch to the nth track of the same type
+ // as the current track -- or the first track of the given
+ // channel?, and set the control appropriately. Any controls in
+ // IPB are supported for a MIDI device plus program and bank; only
+ // volume and pan are supported for audio/synth devices.
+ //!!! complete this
+
+ if (e->getType() != MappedEvent::MidiController) {
+
+ if (e->getType() == MappedEvent::MidiProgramChange) {
+ int program = e->getData1();
+ if (!track)
+ return ;
+ InstrumentId ii = track->getInstrument();
+ Instrument *instrument = studio.getInstrumentById(ii);
+ if (!instrument)
+ return ;
+ instrument->setProgramChange(program);
+ emit instrumentParametersChanged(ii);
+ }
+ return ;
+ }
+
+ unsigned int channel = e->getRecordedChannel();
+ MidiByte controller = e->getData1();
+ MidiByte value = e->getData2();
+
+ if (controller == 82) { //!!! magic select-track controller
+ int tracks = comp.getNbTracks();
+ Track *track = comp.getTrackByPosition(value * tracks / 127);
+ if (track) {
+ slotSelectTrackSegments(track->getId());
+ }
+ return ;
+ }
+
+ if (!track)
+ return ;
+
+ InstrumentId ii = track->getInstrument();
+ Instrument *instrument = studio.getInstrumentById(ii);
+
+ if (!instrument)
+ return ;
+
+ switch (instrument->getType()) {
+
+ case Instrument::Midi: {
+ MidiDevice *md = dynamic_cast<MidiDevice *>
+ (instrument->getDevice());
+ if (!md) {
+ std::cerr << "WARNING: MIDI instrument has no MIDI device in slotControllerDeviceEventReceived" << std::endl;
+ return ;
+ }
+
+ //!!! we need a central clearing house for these changes,
+ // for a proper mvc structure. reqd for automation post-1.2.
+ // in the mean time this duplicates much of
+ // MIDIInstrumentParameterPanel::slotControllerChanged etc
+
+ switch (controller) {
+
+ case MIDI_CONTROLLER_VOLUME:
+ RG_DEBUG << "Setting volume for instrument " << instrument->getId() << " to " << value << endl;
+ instrument->setVolume(value);
+ break;
+
+ case MIDI_CONTROLLER_PAN:
+ RG_DEBUG << "Setting pan for instrument " << instrument->getId() << " to " << value << endl;
+ instrument->setPan(value);
+ break;
+
+ default: {
+ ControlList cl = md->getIPBControlParameters();
+ for (ControlList::const_iterator i = cl.begin();
+ i != cl.end(); ++i) {
+ if ((*i).getControllerValue() == controller) {
+ RG_DEBUG << "Setting controller " << controller << " for instrument " << instrument->getId() << " to " << value << endl;
+ instrument->setControllerValue(controller, value);
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case Instrument::SoftSynth:
+ case Instrument::Audio:
+
+ switch (controller) {
+
+ case MIDI_CONTROLLER_VOLUME:
+ RG_DEBUG << "Setting volume for instrument " << instrument->getId() << " to " << value << endl;
+ instrument->setLevel(AudioLevel::fader_to_dB
+ (value, 127, AudioLevel::ShortFader));
+ break;
+
+ case MIDI_CONTROLLER_PAN:
+ RG_DEBUG << "Setting pan for instrument " << instrument->getId() << " to " << value << endl;
+ instrument->setPan(MidiByte((value / 64.0) * 100.0 + 0.01));
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+ }
+
+ emit instrumentParametersChanged(instrument->getId());
+
+ //!!! send out updates via MIDI
+}
+
+void
+RosegardenGUIView::initChordNameRuler()
+{
+ getTrackEditor()->getChordNameRuler()->setReady();
+}
+
+EventView *
+RosegardenGUIView::createEventView(std::vector<Segment *> segmentsToEdit)
+{
+ EventView *eventView = new EventView(getDocument(),
+ segmentsToEdit,
+ this);
+
+ connect(eventView, SIGNAL(windowActivated()),
+ this, SLOT(slotActiveMainWindowChanged()));
+
+ connect(eventView, SIGNAL(selectTrack(int)),
+ this, SLOT(slotSelectTrackSegments(int)));
+
+ connect(eventView, SIGNAL(saveFile()),
+ RosegardenGUIApp::self(), SLOT(slotFileSave()));
+
+ connect(eventView, SIGNAL(openInNotation(std::vector<Segment *>)),
+ this, SLOT(slotEditSegmentsNotation(std::vector<Segment *>)));
+ connect(eventView, SIGNAL(openInMatrix(std::vector<Segment *>)),
+ this, SLOT(slotEditSegmentsMatrix(std::vector<Segment *>)));
+ connect(eventView, SIGNAL(openInPercussionMatrix(std::vector<Segment *>)),
+ this, SLOT(slotEditSegmentsPercussionMatrix(std::vector<Segment *>)));
+ connect(eventView, SIGNAL(openInEventList(std::vector<Segment *>)),
+ this, SLOT(slotEditSegmentsEventList(std::vector<Segment *>)));
+ connect(eventView, SIGNAL(editTriggerSegment(int)),
+ this, SLOT(slotEditTriggerSegment(int)));
+ connect(this, SIGNAL(compositionStateUpdate()),
+ eventView, SLOT(slotCompositionStateUpdate()));
+ connect(RosegardenGUIApp::self(), SIGNAL(compositionStateUpdate()),
+ eventView, SLOT(slotCompositionStateUpdate()));
+ connect(eventView, SIGNAL(toggleSolo(bool)),
+ RosegardenGUIApp::self(), SLOT(slotToggleSolo(bool)));
+
+ // create keyboard accelerators on view
+ //
+ RosegardenGUIApp *par = dynamic_cast<RosegardenGUIApp*>(parent());
+
+ if (par) {
+ par->plugAccelerators(eventView, eventView->getAccelerators());
+ }
+
+ return eventView;
+}
+
+}
+#include "RosegardenGUIView.moc"
diff --git a/src/gui/application/RosegardenGUIView.h b/src/gui/application/RosegardenGUIView.h
new file mode 100644
index 0000000..b3727f3
--- /dev/null
+++ b/src/gui/application/RosegardenGUIView.h
@@ -0,0 +1,347 @@
+
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+ Rosegarden
+ A MIDI and audio sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <richard.bown@ferventsoftware.com>
+
+ The moral rights of Guillaume Laurent, Chris Cannam, and Richard
+ Bown to claim authorship of this work have been asserted.
+
+ Other copyrights also apply to some parts of this work. Please
+ see the AUTHORS file and individual file headers for details.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+#ifndef _RG_ROSEGARDENGUIVIEW_H_
+#define _RG_ROSEGARDENGUIVIEW_H_
+
+#include "base/Event.h"
+#include "base/MidiProgram.h"
+#include "base/Selection.h"
+#include "base/Track.h"
+#include "sound/AudioFile.h"
+#include "gui/editors/segment/TrackEditor.h"
+#include <qstring.h>
+#include <qvbox.h>
+
+
+class QWidget;
+class QObject;
+class LevelInfo;
+class KCommand;
+
+
+namespace Rosegarden
+{
+
+class TrackParameterBox;
+class TrackEditor;
+class SimpleRulerScale;
+class SequencerMapper;
+class SegmentParameterBox;
+class Segment;
+class RosegardenGUIDoc;
+class RealTime;
+class NotationView;
+class MultiViewCommandHistory;
+class MatrixView;
+class MappedEvent;
+class InstrumentParameterBox;
+class EventView;
+class Composition;
+class LevelInfo;
+
+/**
+ * The RosegardenGUIView class provides the view widget for the
+ * RosegardenGUIApp instance. The View instance inherits QWidget as a
+ * base class and represents the view object of a KTMainWindow. As
+ * RosegardenGUIView is part of the docuement-view model, it needs a
+ * reference to the document object connected with it by the
+ * RosegardenGUIApp class to manipulate and display the document
+ * structure provided by the RosegardenGUIDoc class.
+ *
+ * @author Source Framework Automatically Generated by KDevelop, (c) The KDevelop Team.
+ * @version KDevelop version 0.4 code generation
+ */
+class RosegardenGUIView : public QVBox
+{
+ Q_OBJECT
+public:
+
+ /**p
+ * Constructor for the main view
+ */
+ RosegardenGUIView(bool showTrackLabels,
+ SegmentParameterBox*,
+ InstrumentParameterBox*,
+ TrackParameterBox*,
+ QWidget *parent = 0,
+ const char *name=0);
+
+ /**
+ * Destructor for the main view
+ */
+ ~RosegardenGUIView();
+
+ /**
+ * returns a pointer to the document connected to the view
+ * instance. Mind that this method requires a RosegardenGUIApp
+ * instance as a parent widget to get to the window document
+ * pointer by calling the RosegardenGUIApp::getDocument() method.
+ *
+ * @see RosegardenGUIApp#getDocument
+ */
+ RosegardenGUIDoc* getDocument() const;
+
+ /**
+ * Command history
+ */
+ MultiViewCommandHistory* getCommandHistory();
+
+ TrackEditor* getTrackEditor() { return m_trackEditor; }
+
+ /**
+ * contains the implementation for printing functionality
+ */
+ void print(Composition*, bool previewOnly = false);
+
+ // the following aren't slots because they're called from
+ // RosegardenGUIApp
+
+ /**
+ * Select a tool at the SegmentCanvas
+ */
+ void selectTool(QString toolName);
+
+ /**
+ * Show output levels
+ */
+ void showVisuals(const MappedEvent *mE);
+
+ void updateMeters(SequencerMapper *mapper);
+ void updateMonitorMeters(SequencerMapper *mapper);
+
+ /**
+ * Change zoom size -- set the RulerScale's units-per-pixel to size
+ */
+ void setZoomSize(double size);
+
+ void initChordNameRuler();
+
+ bool haveSelection();
+ SegmentSelection getSelection();
+ void updateSelectionContents();
+
+ static bool isMainWindowLastActive(const QWidget *w) {
+ return w == m_lastActiveMainWindow;
+ }
+
+public slots:
+ void slotEditSegment(Segment*);
+ void slotEditSegmentNotation(Segment*);
+ void slotEditSegmentsNotation(std::vector<Segment*>);
+ void slotEditSegmentMatrix(Segment*);
+ void slotEditSegmentsMatrix(std::vector<Segment*>);
+ void slotEditSegmentPercussionMatrix(Segment*);
+ void slotEditSegmentsPercussionMatrix(std::vector<Segment*>);
+ void slotEditSegmentEventList(Segment*);
+ void slotEditSegmentsEventList(std::vector<Segment*>);
+ void slotEditTriggerSegment(int);
+ void slotEditSegmentAudio(Segment*);
+ void slotSegmentAutoSplit(Segment*);
+ void slotEditRepeat(Segment*, timeT);
+/* hjj: WHAT DO DO WITH THIS ?
+ void slotEditMetadata(QString);
+*/
+
+ /**
+ * Highlight all the Segments on a Track because the Track has
+ * been selected * We have to ensure we create a Selector object
+ * before we can highlight * these tracks.
+ *
+ * Called by signal from Track selection routine to highlight
+ * all available Segments on a Track
+ */
+ void slotSelectTrackSegments(int);
+
+ void slotSelectAllSegments();
+
+ void slotUpdateInstrumentParameterBox(int id);
+
+ // This is called from the canvas (actually the selector tool) moving out
+ //
+ void slotSelectedSegments(const SegmentSelection &segments);
+
+ // And this one from the user interface going down
+ //
+ void slotPropagateSegmentSelection(const SegmentSelection &segments);
+
+ void slotShowRulers(bool);
+
+ void slotShowTempoRuler(bool);
+
+ void slotShowChordNameRuler(bool);
+
+ void slotShowPreviews(bool);
+
+ void slotShowSegmentLabels(bool);
+
+ void slotAddTracks(unsigned int count, InstrumentId instrument, int position);
+
+ void slotDeleteTracks(std::vector<TrackId> tracks);
+
+ void slotAddAudioSegmentCurrentPosition(AudioFileId,
+ const RealTime &startTime,
+ const RealTime &endTime);
+
+ void slotAddAudioSegmentDefaultPosition(AudioFileId,
+ const RealTime &startTime,
+ const RealTime &endTime);
+
+ void slotAddAudioSegment(AudioFileId audioId,
+ TrackId trackId,
+ timeT position,
+ const RealTime &startTime,
+ const RealTime &endTime);
+
+ void slotDroppedAudio(QString audioDesc);
+ void slotDroppedNewAudio(QString audioDesc);
+
+ /*
+ * Commands
+ *
+ */
+ void slotAddCommandToHistory(KCommand *command);
+
+ /*
+ * Change the Instrument Label
+ */
+ void slotChangeInstrumentLabel(InstrumentId id, QString label);
+
+ /*
+ * Change the Track Label
+ */
+ void slotChangeTrackLabel(TrackId id, QString label);
+
+ /*
+ * Set the mute button on the track buttons and on the instrument
+ * parameter box
+ */
+ void slotSetMuteButton(TrackId track, bool value);
+
+ /*
+ * Set mute, record and solo by instrument id
+ */
+ void slotSetMute(InstrumentId, bool);
+ void slotSetRecord(InstrumentId, bool);
+ void slotSetSolo(InstrumentId, bool);
+
+ /**
+ * To indicate that we should track the recording segment (despite
+ * no commands being issued on it)
+ */
+ void slotUpdateRecordingSegment(Segment *segment,
+ timeT updatedFrom);
+
+ /**
+ * A manual fudgy way of creating a view update for certain
+ * semi-static data (devices/instrument labels mainly)
+ */
+ void slotSynchroniseWithComposition();
+
+ /**
+ * To indicate that an edit view, mixer, etc (something that might
+ * want to receive MIDI input) has become active. We only send
+ * inputs such as MIDI to a single one of these, in most cases,
+ * and it's whichever was most recently made active. (It doesn't
+ * have to still _be_ active -- we want to allow moving focus to
+ * another application entirely but still receiving MIDI etc in
+ * Rosegarden.)
+ */
+ void slotActiveMainWindowChanged(const QWidget *);
+ void slotActiveMainWindowChanged(); // uses sender()
+
+ /**
+ * An event has been received from a device connected to the
+ * external controller port.
+ */
+ void slotControllerDeviceEventReceived(MappedEvent *);
+ void slotControllerDeviceEventReceived(MappedEvent *, const void *);
+
+signals:
+ void activateTool(QString toolName);
+
+ void stateChange(QString, bool);
+
+ // Inform that we've got a SegmentSelection
+ //
+ void segmentsSelected(const SegmentSelection&);
+
+ void toggleSolo(bool);
+
+ /**
+ * Current used to dispatch things like track select changes, solo, etc...
+ * to edit views
+ */
+ void compositionStateUpdate();
+
+
+ /**
+ * This signal is used to dispatch a notification for a request to
+ * set the step-by-step-editing target window to all candidate targets,
+ * so that they can either know that their request has been granted
+ * (if they match the QObject passed) or else deactivate any step-by-
+ * step editing currently active in their own window (otherwise).
+ */
+ void stepByStepTargetRequested(QObject *);
+
+ /*
+ * Add an audio file at the sequencer - when we drop a new file
+ * on the segment canvas.
+ */
+ void addAudioFile(AudioFileId);
+
+ void checkTrackAssignments();
+
+ void instrumentLevelsChanged(InstrumentId,
+ const LevelInfo &);
+
+ void controllerDeviceEventReceived(MappedEvent *,
+ const void *);
+
+ void instrumentParametersChanged(InstrumentId);
+
+protected:
+ NotationView *createNotationView(std::vector<Segment *>);
+ MatrixView *createMatrixView (std::vector<Segment *>, bool drumMode);
+ EventView *createEventView (std::vector<Segment *>);
+
+ virtual void windowActivationChange(bool);
+
+ //--------------- Data members ---------------------------------
+
+ SimpleRulerScale *m_rulerScale;
+ TrackEditor *m_trackEditor;
+
+ SegmentParameterBox *m_segmentParameterBox;
+ InstrumentParameterBox *m_instrumentParameterBox;
+ TrackParameterBox *m_trackParameterBox;
+
+ static const QWidget *m_lastActiveMainWindow;
+};
+
+
+}
+
+#endif
diff --git a/src/gui/application/RosegardenIface.cpp b/src/gui/application/RosegardenIface.cpp
new file mode 100644
index 0000000..7e07f14
--- /dev/null
+++ b/src/gui/application/RosegardenIface.cpp
@@ -0,0 +1,82 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+ Rosegarden
+ A MIDI and audio sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <richard.bown@ferventsoftware.com>
+
+ The moral rights of Guillaume Laurent, Chris Cannam, and Richard
+ Bown to claim authorship of this work have been asserted.
+
+ Parts of this file are from KDE Konqueror : KonqMainWindowIface
+ Copyright (C) 2000 Simon Hausmann <hausmann@kde.org>
+ Copyright (C) 2000 David Faure <faure@kde.org>
+
+ Other copyrights also apply to some parts of this work. Please
+ see the AUTHORS file and individual file headers for details.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+
+#include "RosegardenIface.h"
+
+#include "sound/MappedComposition.h"
+#include <dcopobject.h>
+#include <dcopref.h>
+#include <kaction.h>
+#include <kdcopactionproxy.h>
+#include <kmainwindow.h>
+#include <qcstring.h>
+#include <qstring.h>
+#include <qvaluelist.h>
+#include <kapplication.h>
+#include <dcopclient.h>
+
+
+namespace Rosegarden
+{
+
+RosegardenIface::RosegardenIface(KMainWindow* mainWindow)
+ : DCOPObject(mainWindow->name()),
+ m_dcopActionProxy(0)
+{}
+
+void RosegardenIface::iFaceDelayedInit(KMainWindow* mainWindow)
+{
+ m_dcopActionProxy = new KDCOPActionProxy(mainWindow->actionCollection(),
+ this);
+}
+
+DCOPRef RosegardenIface::action(const QCString &name)
+{
+ return DCOPRef(kapp->dcopClient()->appId(),
+ m_dcopActionProxy->actionObjectId(name));
+}
+
+QCStringList RosegardenIface::actions()
+{
+ QCStringList res;
+ QValueList<KAction *> lst = m_dcopActionProxy->actions();
+ QValueList<KAction *>::ConstIterator it = lst.begin();
+ QValueList<KAction *>::ConstIterator end = lst.end();
+ for (; it != end; ++it )
+ res.append( (*it)->name() );
+
+ return res;
+}
+
+QMap<QCString,DCOPRef> RosegardenIface::actionMap()
+{
+ return m_dcopActionProxy->actionMap();
+}
+
+}
diff --git a/src/gui/application/RosegardenIface.h b/src/gui/application/RosegardenIface.h
new file mode 100644
index 0000000..baa8b4e
--- /dev/null
+++ b/src/gui/application/RosegardenIface.h
@@ -0,0 +1,130 @@
+
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+ Rosegarden
+ A MIDI and audio sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <richard.bown@ferventsoftware.com>
+
+ The moral rights of Guillaume Laurent, Chris Cannam, and Richard
+ Bown to claim authorship of this work have been asserted.
+
+ Parts of this file are from KDE Konqueror : KonqMainWindowIface
+ Copyright (C) 2000 Simon Hausmann <hausmann@kde.org>
+ Copyright (C) 2000 David Faure <faure@kde.org>
+
+ Other copyrights also apply to some parts of this work. Please
+ see the AUTHORS file and individual file headers for details.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+#ifndef _RG_ROSEGARDENIFACE_H_
+#define _RG_ROSEGARDENIFACE_H_
+
+#include <dcopobject.h>
+#include <dcopref.h>
+#include <qmap.h>
+#include <qstring.h>
+#include <qvaluevector.h>
+
+#include "base/Instrument.h"
+#include "sound/MappedComposition.h"
+
+class QCString;
+class KMainWindow;
+class KDCOPActionProxy;
+
+
+namespace Rosegarden
+{
+
+
+/**
+ * RosegardenGUI DCOP Interface
+ */
+class RosegardenIface : virtual public DCOPObject
+{
+ K_DCOP
+
+public:
+ RosegardenIface(KMainWindow*);
+ void iFaceDelayedInit(KMainWindow*);
+
+k_dcop:
+ virtual void openFile(QString file) = 0;
+ virtual void openURL(QString url) = 0;
+ virtual void mergeFile(QString file) = 0;
+ virtual void fileNew() = 0;
+ virtual void fileSave() = 0;
+ virtual void fileClose() = 0;
+ virtual void quit() = 0;
+
+ virtual void play() = 0;
+ virtual void stop() = 0;
+ virtual void rewind() = 0;
+ virtual void fastForward() = 0;
+ virtual void record() = 0;
+ virtual void rewindToBeginning() = 0;
+ virtual void fastForwardToEnd() = 0;
+ virtual void jumpToTime(int sec, int usec) = 0;
+ virtual void startAtTime(int sec, int usec) = 0;
+
+ // Extra functions used by Infrared Remotes
+ virtual void trackDown() = 0;
+ virtual void trackUp() = 0;
+ virtual void toggleMutedCurrentTrack() = 0;
+ virtual void toggleRecordCurrentTrack() = 0;
+
+ // Sequencer updates GUI with status
+ //
+ virtual void notifySequencerStatus(int status) = 0;
+
+ // Used to map unexpected (async) MIDI events to the user interface.
+ // We can show these on the Transport or on a MIDI Mixer.
+ //
+ virtual void processAsynchronousMidi(const MappedComposition &mC) = 0;
+
+ // The sequencer tries to call this action until it can - then
+ // we can go on and retrive device information
+ //
+ virtual void alive() = 0;
+
+ // The sequencer requests that a new audio file is created - the
+ // gui does so and returns the path of the new file so that the
+ // sequencer can use it.
+ //
+ virtual QString createNewAudioFile() = 0;
+ virtual QValueVector<QString> createRecordAudioFiles
+ (const QValueVector<InstrumentId> &recordInstruments) = 0;
+ virtual QString getAudioFilePath() = 0;
+
+ virtual QValueVector<InstrumentId> getArmedInstruments() = 0;
+
+ virtual void showError(QString error) = 0;
+
+ // Actions proxy
+ //
+ DCOPRef action( const QCString &name );
+ QCStringList actions();
+ QMap<QCString,DCOPRef> actionMap();
+
+protected:
+ //--------------- Data members ---------------------------------
+
+ KDCOPActionProxy *m_dcopActionProxy;
+
+};
+
+
+}
+
+#endif
diff --git a/src/gui/application/SetWaitCursor.cpp b/src/gui/application/SetWaitCursor.cpp
new file mode 100644
index 0000000..7fc0053
--- /dev/null
+++ b/src/gui/application/SetWaitCursor.cpp
@@ -0,0 +1,95 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+ Rosegarden
+ A MIDI and audio sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <richard.bown@ferventsoftware.com>
+
+ The moral rights of Guillaume Laurent, Chris Cannam, and Richard
+ Bown to claim authorship of this work have been asserted.
+
+ Other copyrights also apply to some parts of this work. Please
+ see the AUTHORS file and individual file headers for details.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+
+#include "SetWaitCursor.h"
+
+#include "gui/editors/segment/TrackEditor.h"
+#include "gui/editors/segment/segmentcanvas/CompositionView.h"
+#include "misc/Debug.h"
+#include "RosegardenGUIApp.h"
+#include "RosegardenGUIView.h"
+#include <kcursor.h>
+#include <qcursor.h>
+#include <qwidget.h>
+#include <kapplication.h>
+
+namespace Rosegarden
+{
+
+SetWaitCursor::SetWaitCursor()
+ : m_guiApp(dynamic_cast<RosegardenGUIApp*>(kapp->mainWidget()))
+{
+ if (m_guiApp) {
+
+ // play it safe, so we can use this class at anytime even very early in the app init
+ if ((m_guiApp->getView() &&
+ m_guiApp->getView()->getTrackEditor() &&
+ m_guiApp->getView()->getTrackEditor()->getSegmentCanvas() &&
+ m_guiApp->getView()->getTrackEditor()->getSegmentCanvas()->viewport())) {
+
+ m_saveSegmentCanvasCursor = m_guiApp->getView()->getTrackEditor()->getSegmentCanvas()->viewport()->cursor();
+
+ }
+
+ RG_DEBUG << "SetWaitCursor::SetWaitCursor() : setting waitCursor\n";
+ m_saveCursor = m_guiApp->cursor();
+
+ m_guiApp->setCursor(KCursor::waitCursor());
+ }
+}
+
+SetWaitCursor::~SetWaitCursor()
+{
+ if (m_guiApp) {
+
+ RG_DEBUG << "SetWaitCursor::SetWaitCursor() : restoring normal cursor\n";
+ QWidget* viewport = 0;
+ QCursor currentSegmentCanvasCursor;
+
+ if ((m_guiApp->getView() &&
+ m_guiApp->getView()->getTrackEditor() &&
+ m_guiApp->getView()->getTrackEditor()->getSegmentCanvas() &&
+ m_guiApp->getView()->getTrackEditor()->getSegmentCanvas()->viewport())) {
+ viewport = m_guiApp->getView()->getTrackEditor()->getSegmentCanvas()->viewport();
+ currentSegmentCanvasCursor = viewport->cursor();
+ }
+
+ m_guiApp->setCursor(m_saveCursor);
+
+ if (viewport) {
+ if (currentSegmentCanvasCursor.shape() == KCursor::waitCursor().shape()) {
+ viewport->setCursor(m_saveSegmentCanvasCursor);
+ } else {
+ viewport->setCursor(currentSegmentCanvasCursor); // because m_guiApp->setCursor() has replaced it
+ }
+ }
+
+ // otherwise, it's been modified elsewhere, so leave it as is
+
+ }
+
+}
+
+}
diff --git a/src/gui/application/SetWaitCursor.h b/src/gui/application/SetWaitCursor.h
new file mode 100644
index 0000000..38687c5
--- /dev/null
+++ b/src/gui/application/SetWaitCursor.h
@@ -0,0 +1,58 @@
+
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+ Rosegarden
+ A MIDI and audio sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <richard.bown@ferventsoftware.com>
+
+ The moral rights of Guillaume Laurent, Chris Cannam, and Richard
+ Bown to claim authorship of this work have been asserted.
+
+ Other copyrights also apply to some parts of this work. Please
+ see the AUTHORS file and individual file headers for details.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+#ifndef _RG_SETWAITCURSOR_H_
+#define _RG_SETWAITCURSOR_H_
+
+#include <qcursor.h>
+
+
+
+
+namespace Rosegarden
+{
+
+class RosegardenGUIApp;
+
+
+/**
+ * Temporarily change the global cursor to waitCursor
+ */
+class SetWaitCursor
+{
+public:
+ SetWaitCursor();
+ ~SetWaitCursor();
+
+protected:
+ RosegardenGUIApp* m_guiApp;
+ QCursor m_saveCursor;
+ QCursor m_saveSegmentCanvasCursor;
+};
+
+
+}
+
+#endif
diff --git a/src/gui/application/StartupTester.cpp b/src/gui/application/StartupTester.cpp
new file mode 100644
index 0000000..15940b6
--- /dev/null
+++ b/src/gui/application/StartupTester.cpp
@@ -0,0 +1,248 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+ Rosegarden
+ A MIDI and audio sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <richard.bown@ferventsoftware.com>
+
+ The moral rights of Guillaume Laurent, Chris Cannam, and Richard
+ Bown to claim authorship of this work have been asserted.
+
+ Other copyrights also apply to some parts of this work. Please
+ see the AUTHORS file and individual file headers for details.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+
+#include "StartupTester.h"
+
+#include "misc/Debug.h"
+#include "gui/dialogs/LilyPondOptionsDialog.h"
+
+#include <kprocess.h>
+#include <qmutex.h>
+#include <qthread.h>
+#include <qregexp.h>
+
+
+namespace Rosegarden
+{
+
+StartupTester::StartupTester() :
+ m_ready(false),
+ m_haveProjectPackager(false),
+ m_haveLilyPondView(false),
+ m_haveAudioFileImporter(false)
+{
+ QHttp *http = new QHttp();
+ connect(http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)),
+ this, SLOT(slotHttpResponseHeaderReceived(const QHttpResponseHeader &)));
+ connect(http, SIGNAL(done(bool)),
+ this, SLOT(slotHttpDone(bool)));
+ m_versionHttpFailed = false;
+ http->setHost("www.rosegardenmusic.com");
+ http->get("/latest-version.txt");
+}
+
+StartupTester::~StartupTester()
+{
+}
+
+void
+StartupTester::run()
+{
+ m_projectPackagerMutex.lock();
+ m_lilyPondViewMutex.lock();
+ m_audioFileImporterMutex.lock();
+ m_ready = true;
+
+ KProcess *proc = new KProcess();
+ m_stdoutBuffer = "";
+ QObject::connect(proc, SIGNAL(receivedStdout(KProcess *, char *, int)),
+ this, SLOT(stdoutReceived(KProcess *, char *, int)));
+ *proc << "rosegarden-audiofile-importer";
+ *proc << "--conftest";
+ proc->start(KProcess::Block, KProcess::All);
+ if (!proc->normalExit() || proc->exitStatus()) {
+ RG_DEBUG << "StartupTester - No audio file importer available" << endl;
+ m_haveAudioFileImporter = false;
+ parseStdoutBuffer(m_audioFileImporterMissing);
+ } else {
+ RG_DEBUG << "StartupTester - Audio file importer OK" << endl;
+ m_haveAudioFileImporter = true;
+ }
+ delete proc;
+ m_audioFileImporterMutex.unlock();
+
+ proc = new KProcess;
+ m_stdoutBuffer = "";
+ QObject::connect(proc, SIGNAL(receivedStdout(KProcess *, char *, int)),
+ this, SLOT(stdoutReceived(KProcess *, char *, int)));
+ *proc << "rosegarden-project-package";
+ *proc << "--conftest";
+ proc->start(KProcess::Block, KProcess::All);
+ if (!proc->normalExit() || proc->exitStatus()) {
+ m_haveProjectPackager = false;
+ // rosegarden-project-package ran but exited with an error code
+ RG_DEBUG << "StartupTester - No project packager available" << endl;
+ m_haveProjectPackager = false;
+ parseStdoutBuffer(m_projectPackagerMissing);
+ } else {
+ RG_DEBUG << "StartupTester - Project packager OK" << endl;
+ m_haveProjectPackager = true;
+ }
+ delete proc;
+ m_projectPackagerMutex.unlock();
+
+ proc = new KProcess();
+ m_stdoutBuffer = "";
+ QObject::connect(proc, SIGNAL(receivedStdout(KProcess *, char *, int)),
+ this, SLOT(stdoutReceived(KProcess *, char *, int)));
+ *proc << "rosegarden-lilypondview";
+ *proc << "--conftest";
+ proc->start(KProcess::Block, KProcess::All);
+ if (!proc->normalExit() || proc->exitStatus()) {
+ RG_DEBUG << "StartupTester - No lilypondview available" << endl;
+ m_haveLilyPondView = false;
+ parseStdoutBuffer(m_lilyPondViewMissing);
+ } else {
+ RG_DEBUG << "StartupTester - lilypondview OK" << endl;
+ m_haveLilyPondView = true;
+ QRegExp re("LilyPond version: ([^\n]*)");
+ if (re.search(m_stdoutBuffer) != -1) {
+ LilyPondOptionsDialog::setDefaultLilyPondVersion(re.cap(1));
+ }
+ }
+ delete proc;
+ m_lilyPondViewMutex.unlock();
+}
+
+bool
+StartupTester::isReady()
+{
+ while (!m_ready)
+ usleep(10000);
+ if (m_projectPackagerMutex.tryLock()) {
+ m_projectPackagerMutex.unlock();
+ } else {
+ return false;
+ }
+ if (m_lilyPondViewMutex.tryLock()) {
+ m_lilyPondViewMutex.unlock();
+ } else {
+ return false;
+ }
+ return true;
+}
+
+void
+StartupTester::stdoutReceived(KProcess *, char *buffer, int len)
+{
+ m_stdoutBuffer += QString::fromLatin1(buffer, len);
+}
+
+void
+StartupTester::parseStdoutBuffer(QStringList &target)
+{
+ QRegExp re("Required: ([^\n]*)");
+ if (re.search(m_stdoutBuffer) != -1) {
+ target = QStringList::split(", ", re.cap(1));
+ }
+}
+
+bool
+StartupTester::haveProjectPackager(QStringList *missing)
+{
+ while (!m_ready)
+ usleep(10000);
+ QMutexLocker locker(&m_projectPackagerMutex);
+ if (missing) *missing = m_projectPackagerMissing;
+ return m_haveProjectPackager;
+}
+
+bool
+StartupTester::haveLilyPondView(QStringList *missing)
+{
+ while (!m_ready)
+ usleep(10000);
+ QMutexLocker locker(&m_lilyPondViewMutex);
+ if (missing) *missing = m_lilyPondViewMissing;
+ return m_haveLilyPondView;
+}
+
+bool
+StartupTester::haveAudioFileImporter(QStringList *missing)
+{
+ while (!m_ready)
+ usleep(10000);
+ QMutexLocker locker(&m_audioFileImporterMutex);
+ if (missing) *missing = m_audioFileImporterMissing;
+ return m_haveAudioFileImporter;
+}
+
+bool
+StartupTester::isVersionNewerThan(QString a, QString b)
+{
+ QRegExp re("[._-]");
+ QStringList alist = QStringList::split(re, a);
+ QStringList blist = QStringList::split(re, b);
+ int ae = alist.size();
+ int be = blist.size();
+ int e = std::max(ae, be);
+ for (int i = 0; i < e; ++i) {
+ int an = 0, bn = 0;
+ if (i < ae) {
+ an = alist[i].toInt();
+ if (an == 0) an = -1; // non-numeric field -> "-pre1" etc
+ }
+ if (i < be) {
+ bn = blist[i].toInt();
+ if (bn == 0) bn = -1;
+ }
+ if (an < bn) return false;
+ if (an > bn) return true;
+ }
+ return false;
+}
+
+void
+StartupTester::slotHttpResponseHeaderReceived(const QHttpResponseHeader &h)
+{
+ if (h.statusCode() / 100 != 2) m_versionHttpFailed = true;
+}
+
+void
+StartupTester::slotHttpDone(bool error)
+{
+ QHttp *http = const_cast<QHttp *>(dynamic_cast<const QHttp *>(sender()));
+ if (!http) return;
+ http->deleteLater();
+ if (error) return;
+
+ QByteArray responseData = http->readAll();
+ QString str = QString::fromUtf8(responseData.data());
+ QStringList lines = QStringList::split('\n', str);
+ if (lines.empty()) return;
+
+ QString latestVersion = lines[0];
+ std::cerr << "Comparing current version \"" << VERSION
+ << "\" with latest version \"" << latestVersion << "\""
+ << std::endl;
+ if (isVersionNewerThan(latestVersion, VERSION)) {
+ emit newerVersionAvailable(latestVersion);
+ }
+}
+
+}
+
+#include "StartupTester.moc"
+
diff --git a/src/gui/application/StartupTester.h b/src/gui/application/StartupTester.h
new file mode 100644
index 0000000..9c82e07
--- /dev/null
+++ b/src/gui/application/StartupTester.h
@@ -0,0 +1,88 @@
+
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+ Rosegarden
+ A MIDI and audio sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <richard.bown@ferventsoftware.com>
+
+ The moral rights of Guillaume Laurent, Chris Cannam, and Richard
+ Bown to claim authorship of this work have been asserted.
+
+ Other copyrights also apply to some parts of this work. Please
+ see the AUTHORS file and individual file headers for details.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+#ifndef _RG_STARTUPTESTER_H_
+#define _RG_STARTUPTESTER_H_
+
+#include <qmutex.h>
+#include <qthread.h>
+#include <qstringlist.h>
+#include <qobject.h>
+#include <qhttp.h>
+
+class KProcess;
+
+namespace Rosegarden
+{
+
+class StartupTester : public QObject, public QThread
+{
+ Q_OBJECT
+
+public:
+ StartupTester();
+ virtual ~StartupTester();
+
+ virtual void run();
+
+ bool isReady();
+
+ // If you call one of these methods before the startup test has
+ // completed in the background, then it will block.
+
+ bool haveProjectPackager(QStringList *missingApplications);
+ bool haveLilyPondView(QStringList *missingApplications);
+ bool haveAudioFileImporter(QStringList *missingApplications);
+
+signals:
+ void newerVersionAvailable(QString);
+
+protected slots:
+ void stdoutReceived(KProcess *, char *, int);
+
+ void slotHttpResponseHeaderReceived(const QHttpResponseHeader &);
+ void slotHttpDone(bool);
+
+protected:
+ bool m_ready;
+ QMutex m_projectPackagerMutex;
+ QMutex m_lilyPondViewMutex;
+ QMutex m_audioFileImporterMutex;
+ bool m_haveProjectPackager;
+ QStringList m_projectPackagerMissing;
+ bool m_haveLilyPondView;
+ QStringList m_lilyPondViewMissing;
+ bool m_haveAudioFileImporter;
+ QStringList m_audioFileImporterMissing;
+ QString m_stdoutBuffer;
+ bool m_versionHttpFailed;
+ void parseStdoutBuffer(QStringList &target);
+ bool isVersionNewerThan(QString, QString);
+};
+
+
+}
+
+#endif
diff --git a/src/gui/application/main.cpp b/src/gui/application/main.cpp
new file mode 100644
index 0000000..d7b5779
--- /dev/null
+++ b/src/gui/application/main.cpp
@@ -0,0 +1,741 @@
+// -*- c-basic-offset: 4 -*-
+
+/*
+ Rosegarden
+ A sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <bownie@bownie.com>
+
+ The moral right of the authors to claim authorship of this work
+ has been asserted.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+#include <qtimer.h>
+#include <kapplication.h>
+#include <sys/time.h>
+#include "base/RealTime.h"
+
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+#include <dcopclient.h>
+#include <kconfig.h>
+#include <kmessagebox.h>
+#include <kstddirs.h>
+#include <ktip.h>
+#include <kprocess.h>
+#include <kglobalsettings.h>
+
+#include <qstringlist.h>
+#include <qregexp.h>
+#include <qvbox.h>
+#include <qlabel.h>
+
+#include "document/ConfigGroups.h"
+#include "misc/Strings.h"
+#include "misc/Debug.h"
+#include "gui/application/RosegardenGUIApp.h"
+#include "gui/widgets/CurrentProgressDialog.h"
+#include "document/RosegardenGUIDoc.h"
+#include "gui/kdeext/KStartupLogo.h"
+
+#include "gui/application/RosegardenApplication.h"
+#include "gui/application/RosegardenDCOP.h"
+
+#include "gui/kdeext/klearlook.h"
+
+using namespace Rosegarden;
+
+/*! \mainpage Rosegarden global design
+
+Rosegarden is split into 3 main parts:
+
+\section base Base
+
+The base library holds all of the fundamental "music handling"
+structures, of which the primary ones are Event, Segment, Track,
+Instrument and Composition. It also contains a selection of utility
+and helper classes of a kind that is not specific to any particular
+GUI. Everything here is part of the Rosegarden namespace, and there
+are no dependencies on KDE or Qt (although it uses the STL heavily).
+
+The keyword for the basic structures in use is "flexibility". Our
+Event objects can be extended arbitrarily for the convenience of GUI
+or performance code without having to change their declaration or
+modify anything in the base library. And most of our assumptions
+about the use of the container classes can be violated without
+disastrous side-effects.
+
+\subsection musicstructs Music Structures
+
+ - \link Event Event\endlink is the basic musical element. It's more or less a
+ generalization of the MIDI event. Each note or rest, each key
+ change or tempo change, is an event: there's no "note class" or
+ "rest class" as such, they are simply represented by events whose
+ type happens to be "note" or "rest".
+ Each Event has a type code, absolute time (the moment at which the
+ Event starts, relative only to the start of the Composition) and
+ duration (usually non-zero only for notes and rests), together
+ with an arbitrary set of named and typed properties that can be
+ assigned and queried dynamically by other parts of the
+ application. So, for example, a note event is likely to have an
+ integer property called "pitch", and probably a "velocity", as
+ well as potentially many others -- but this is not fixed anywhere,
+ and there's no definition of what exactly a note is: client code
+ is simply expected to ignore any unrecognised events or properties
+ and to cope if properties that should be there are not.
+
+ - \link Segment Segment\endlink is a series of consecutive Events found on the same Track,
+ automatically ordered by their absolute time. It's the usual
+ container for Events. A Segment has a starting time that can be
+ changed, and a duration that is based solely on the end time of
+ the last Event it contains. Note that in order to facilitate
+ musical notation editing, we explicitly store silences as series
+ of rest Events; thus a Segment really should contain no gaps
+ between its Events. (This isn't checked anywhere and nothing will
+ break very badly if there are gaps, but notation won't quite work
+ correctly.)
+
+ - \link Track Track \endlink is much the same thing as on a mixing table, usually
+ assigned to an instrument, a voice, etc. Although a Track is not
+ a container of Events and is not strictly a container of Segments
+ either, it is referred to by a set of Segments that are therefore
+ mutually associated with the same instruments and parameters. In
+ GUI terms, the Track is a horizontal row on the main Rosegarden
+ window, whereas a Segment is a single blue box within that row, of
+ which there may be any number.
+
+ - \link Instrument Instrument \endlink corresponds broadly to a MIDI or Audio channel, and is
+ the destination for a performed Event. Each Track is mapped to a
+ single Instrument (although many Tracks may have the same
+ Instrument), and the Instrument is indicated in the header at the
+ left of the Track's row in the GUI.
+
+ - \link Composition Composition\endlink is the container for the entire piece of music. It
+ consists of a set of Segments, together with a set of Tracks that
+ the Segments may or may not be associated with, a set of
+ Instruments, and some information about time signature and tempo
+ changes. (The latter are not stored in Segments; they are only
+ stored in the top-level Composition. You can't have differing
+ time signatures or tempos in different Segments.) Any code that
+ wants to know about the locations of bar lines, or request
+ real-time calculations based on tempo changes, talks to the
+ Composition.
+
+
+See also docs/data_struct/units.txt for an explanation of the units we
+use for time and pitch values. See docs/discussion/names.txt for some
+name-related discussion. See docs/code/creating_events.txt for an
+explanation of how to create new Events and add properties to them.
+
+The base directory also contains various music-related helper classes:
+
+ - The NotationTypes.[Ch] files contain classes that help with
+ creating and manipulating events. It's very important to realise
+ that these classes are not the events themselves: although there
+ is a Note class in this file, and a TimeSignature class, and Clef
+ and Key classes, instances of these are rarely stored anywhere.
+ Instead they're created on-the-fly in order to do calculation
+ related to note durations or time signatures or whatever, and they
+ contain getAsEvent() methods that may be used when an event for
+ storage is required. But the class of a stored event is always
+ simply Event.
+
+ The NotationTypes classes also define important constants for the
+ names of common properties in Events. For example, the Note class
+ contains Note::EventType, which is the type of a note Event, and
+ Note::EventRestType, the type of a rest Event; and Key contains
+ Key::EventType, the type of a key change Event, KeyPropertyName,
+ the name of the property that defines the key change, and a set
+ of the valid strings for key changes.
+
+ - BaseProperties.[Ch] contains a set of "standard"-ish Event
+ property names that are not basic enough to go in NotationTypes.
+
+ - \link SegmentNotationHelper SegmentNotationHelper\endlink
+ and \link SegmentPerformanceHelper SegmentPerformanceHelper\endlink
+ do tasks that
+ may be useful to notation-type code and performer code
+ respectively. For example, SegmentNotationHelper is used to
+ manage rests when inserting and deleting notes in a score editor,
+ and to create beamed groups and suchlike; SegmentPerformanceHelper
+ generally does calculations involving real performance time of
+ notes (taking into account tied notes, tuplets and tempo changes).
+ These two lightweight helper classes are also usually constructed
+ on-the-fly for use on the events in a given Segment and then
+ discarded after use.
+
+ - \link Quantizer Quantizer\endlink is used to quantize event timings and set quantized
+ timing properties on those events. Note that quantization is
+ non-destructive, as it takes advantage of the ability to set new
+ Event properties to simply assign the quantized values as separate
+ properties from the original absolute time and duration.
+
+
+\section gui GUI
+
+The GUI directory builds into a KDE/Qt application. Like most KDE
+applications, it follows a document/view model. The document (class
+RosegardenGUIDoc, which wraps a Composition) can have several views
+(class RosegardenGUIView), although at the moment only a single one is
+used.
+
+This view is the TrackEditor, which shows all the Composition's
+Segments organized in Tracks. Each Segment can be edited in two ways:
+notation (score) or matrix (piano roll).
+
+All editor views are derived from EditView. An EditView is the class
+dealing with the edition per se of the events. It uses several
+components:
+
+ - Layout classes, horizontal and vertical: these are the classes
+ which determine the x and y coordinates of the graphic items
+ representing the events (notes or piano-roll rectangles). They
+ are derived from the LayoutEngine base-class in the base library.
+
+ - Tools, which implement each editing function at the GUI (such as
+ insert, erase, cut and paste). These are the tools which appear on
+ the EditView's toolbar.
+
+ - Toolbox, which is a simple string => tool map.
+
+ - Commands, which are the fundamental implementations of editing
+ operations (both menu functions and tool operations) subclassed
+ from KDE's Command and used for undo and redo.
+
+ - a canvas view. Although this isn't a part of the EditView's
+ definition, both of the existing edit views (notation and matrix)
+ use one, because they both use a QCanvas to represent data.
+
+ - LinedStaff, a staff with lines. Like the canvas view, this isn't
+ part of the EditView definition, but both views use one.
+
+
+There are currently two editor views:
+
+ - NotationView, with accompanying classes NotationHLayout,
+ NotationVLayout, NotationStaff, and all the classes in the
+ notationtool and notationcommands files. These are also closely
+ associated with the NotePixmapFactory and NoteFont classes, which
+ are used to generate notes from component pixmap files.
+
+ - MatrixView, with accompanying classes MatrixHLayout,
+ MatrixVLayout, MatrixStaff and other classes in the matrixview
+ files.
+
+The editing process works as follows:
+
+[NOTE : in the following, we're talking both about events as UI events
+or user events (mouse button clicks, mouse move, keystrokes, etc...)
+and Events (our basic music element). To help lift the ambiguity,
+"events" is for UI events, Events is for Event.]
+
+ -# The canvas view gets the user events (see
+ NotationCanvasView::contentsMousePressEvent(QMouseEvent*) for an
+ example). It locates where the event occured in terms of musical
+ element: which note or staff line the user clicked on, which pitch
+ and time this corresponds to, that kind of stuff. (In the
+ Notation and Matrix views, the LinedStaff calculates mappings
+ between coordinates and staff lines: the former is especially
+ complicated because of its support for page layout.)\n
+ -# The canvas view transmits this kind of info as a signal, which is
+ connected to a slot in the parent EditView.
+ -# The EditView delegates action to the current tool.\n
+ -# The tool performs the actual job (inserting or deleting a note,
+ etc...).
+
+Since this action is usually complex (merely inserting a note requires
+dealing with the surrounding Events, rests or notes), it does it
+through a SegmentHelper (for instance, base/SegmentNotationHelper)
+which "wraps" the complexity into simple calls and performs all the
+hidden tasks.
+
+The EditView also maintains (obviously) its visual appearance with the
+layout classes, applying them when appropriate.
+
+\section sequencer Sequencer
+
+The sequencer directory also builds into a KDE/Qt application, but one
+which doesn't have a gui. The Sequencer can be started automatically
+by the main Rosegarden GUI or manually if testing - it's sometimes
+more convenient to do the latter as the Sequencer needs to be connected
+up to the underlying sound system every time it is started.
+
+The Sequencer interfaces directly with \link AlsaDriver ALSA\endlink
+and provides MIDI "play" and "record" ports which can be connected to
+other MIDI clients (MIDI IN and OUT hardware ports or ALSA synth devices)
+using any ALSA MIDI Connection Manager. The Sequencer also supports
+playing and recording of Audio sample files using \link JackDriver Jack\endlink
+
+The GUI and Sequencer communicate using the KDE DCOP communication framework.
+Look in:
+ - \link rosegardenguiiface.h gui/rosegardenguiiface.h\endlink
+ - \link rosegardensequenceriface.h sequencer/rosegardensequenceriface.h\endlink
+
+for definitions of the DCOP interfaces pertinent to the Sequencer
+and GUI. The main DCOP operations from the GUI involve starting and
+stopping the Sequencer, playing and recording, fast forwarding and
+rewinding. Once a play or record cycle is enabled it's the Sequencer
+that does most of the hard work. Events are read from (or written to, when recording)
+a set of mmapped files.
+
+The Sequencer makes use of two libraries libRosegardenSequencer
+and libRosegardenSound:
+
+ - libRosegardenSequencer holds everything pertinent to sequencing
+ for Rosegarden including the
+ Sequencer class itself. This library is only linked into the
+ Rosegarden Sequencer.
+
+ - libRosegardenSound holds the MidiFile class (writing and reading
+ MIDI files) and the MappedEvent and MappedComposition classes (the
+ communication class for transferring events back and forth across
+ DCOP). This library is needed by the GUI as well as the Sequencer.
+
+The main Sequencer state machine is a good starting point and clearly
+visible at the bottom of rosegarden/sequencer/main.cpp.
+
+
+*/
+
+static const char *description =
+ I18N_NOOP("Rosegarden - A sequencer and musical notation editor");
+
+static KCmdLineOptions options[] =
+ {
+ { "nosequencer", I18N_NOOP("Don't use the sequencer (support editing only)"), 0 },
+ { "nosplash", I18N_NOOP("Don't show the splash screen"), 0 },
+ { "nofork", I18N_NOOP("Don't automatically run in the background"), 0 },
+ { "existingsequencer", I18N_NOOP("Attach to a running sequencer process, if found"), 0 },
+ { "ignoreversion", I18N_NOOP("Ignore installed version - for devs only"), 0 },
+ { "+[File]", I18N_NOOP("file to open"), 0 },
+ { 0, 0, 0 }
+ };
+
+
+// -----------------------------------------------------------------
+
+#ifdef Q_WS_X11
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/SM/SMlib.h>
+
+static int _x_errhandler( Display *dpy, XErrorEvent *err )
+{
+ char errstr[256];
+ XGetErrorText( dpy, err->error_code, errstr, 256 );
+ if ( err->error_code != BadWindow )
+ kdWarning() << "Rosegarden: detected X Error: " << errstr << " " << err->error_code
+ << "\n Major opcode: " << err->request_code << endl;
+ return 0;
+}
+#endif
+
+// NOTE: to get a dump of the stack trace from KDE during program execution:
+// std::cerr << kdBacktrace() << std::endl
+// (see kdebug.h)
+
+void testInstalledVersion()
+{
+ QString versionLocation = locate("appdata", "version.txt");
+ QString installedVersion;
+
+ if (versionLocation) {
+ QFile versionFile(versionLocation);
+ if (versionFile.open(IO_ReadOnly)) {
+ QTextStream text(&versionFile);
+ QString s = text.readLine().stripWhiteSpace();
+ versionFile.close();
+ if (s) {
+ if (s == VERSION) return;
+ installedVersion = s;
+ }
+ }
+ }
+
+ if (installedVersion) {
+
+ KMessageBox::detailedError
+ (0,
+ i18n("Installation contains the wrong version of Rosegarden."),
+ i18n(" The wrong versions of Rosegarden's data files were\n"
+ " found in the standard KDE installation directories.\n"
+ " (I am %1, but the installed files are for version %2.)\n\n"
+ " This may mean one of the following:\n\n"
+ " 1. This is a new upgrade of Rosegarden, and it has not yet been\n"
+ " installed. If you compiled it yourself, check that you have\n"
+ " run \"make install\" and that the procedure completed\n"
+ " successfully.\n\n"
+ " 2. The upgrade was installed in a non-standard directory,\n"
+ " and an old version was found in a standard directory. If so,\n"
+ " you will need to add the correct directory to your KDEDIRS\n"
+ " environment variable before you can run it.").arg(VERSION).arg(installedVersion),
+ i18n("Installation problem"));
+
+ } else {
+
+ KMessageBox::detailedError
+ (0,
+ i18n("Rosegarden does not appear to have been installed."),
+ i18n(" One or more of Rosegarden's data files could not be\n"
+ " found in the standard KDE installation directories.\n\n"
+ " This may mean one of the following:\n\n"
+ " 1. Rosegarden has not been correctly installed. If you compiled\n"
+ " it yourself, check that you have run \"make install\" and that\n"
+ " the procedure completed successfully.\n\n"
+ " 2. Rosegarden has been installed in a non-standard directory,\n"
+ " and you need to add this directory to your KDEDIRS environment\n"
+ " variable before you can run it. This may be the case if you\n"
+ " installed into $HOME or a local third-party package directory\n"
+ " like /usr/local or /opt."),
+ i18n("Installation problem"));
+ }
+
+ exit(1);
+}
+
+
+int main(int argc, char *argv[])
+{
+ setsid(); // acquire shiny new process group
+
+ srandom((unsigned int)time(0) * (unsigned int)getpid());
+
+ KAboutData aboutData( "rosegarden", I18N_NOOP("Rosegarden"),
+ VERSION, description, KAboutData::License_GPL,
+ I18N_NOOP("Copyright 2000 - 2008 Guillaume Laurent, Chris Cannam, Richard Bown\nParts copyright 1994 - 2004 Chris Cannam, Andy Green, Richard Bown, Guillaume Laurent\nLilyPond fonts copyright 1997 - 2005 Han-Wen Nienhuys and Jan Nieuwenhuizen"),
+ 0,
+ "http://www.rosegardenmusic.com/",
+ "rosegarden-devel@lists.sourceforge.net");
+
+ aboutData.addAuthor("Guillaume Laurent (lead)", 0, "glaurent@telegraph-road.org", "http://telegraph-road.org");
+ aboutData.addAuthor("Chris Cannam (lead)", 0, "cannam@all-day-breakfast.com", "http://all-day-breakfast.com");
+ aboutData.addAuthor("Richard Bown (lead)", 0, "richard.bown@ferventsoftware.com");
+ aboutData.addAuthor("D. Michael McIntyre", 0, "dmmcintyr@users.sourceforge.net");
+ aboutData.addAuthor("Pedro Lopez-Cabanillas", 0, "plcl@users.sourceforge.net");
+ aboutData.addAuthor("Heikki Johannes Junes", 0, "hjunes@users.sourceforge.net");
+
+ aboutData.addCredit("Randall Farmer", I18N_NOOP("Chord labelling code"), " rfarme@simons-rock.edu");
+ aboutData.addCredit("Hans Kieserman", I18N_NOOP("LilyPond output\nassorted other patches\ni18n-ization"), "hkieserman@mail.com");
+ aboutData.addCredit("Levi Burton", I18N_NOOP("UI improvements\nbug fixes"), "donburton@sbcglobal.net");
+ aboutData.addCredit("Mark Hymers", I18N_NOOP("Segment colours\nOther UI and bug fixes"), "<markh@linuxfromscratch.org>");
+ aboutData.addCredit("Alexandre Prokoudine", I18N_NOOP("Russian translation\ni18n-ization"), "avp@altlinux.ru");
+ aboutData.addCredit("Jörg Schumann", I18N_NOOP("German translation"), "jrschumann@gmx.de");
+ aboutData.addCredit("Eckhard Jokisch", I18N_NOOP("German translation"), "e.jokisch@u-code.de");
+ aboutData.addCredit("Kevin Donnelly", I18N_NOOP("Welsh translation"));
+ aboutData.addCredit("Didier Burli", I18N_NOOP("French translation"), "didierburli@bluewin.ch");
+ aboutData.addCredit("Yves Guillemot", I18N_NOOP("French translation\nBug fixes"), "yc.guillemot@wanadoo.fr");
+ aboutData.addCredit("Daniele Medri", I18N_NOOP("Italian translation"), "madrid@linuxmeeting.net");
+ aboutData.addCredit("Alessandro Musesti", I18N_NOOP("Italian translation"), "a.musesti@dmf.unicatt.it");
+ aboutData.addCredit("Stefan Asserhäll", I18N_NOOP("Swedish translation"), "stefan.asserhall@comhem.se");
+ aboutData.addCredit("Erik Magnus Johansson", I18N_NOOP("Swedish translation"), "erik.magnus.johansson@telia.com");
+ aboutData.addCredit("Hasso Tepper", I18N_NOOP("Estonian translation"), "hasso@estpak.ee");
+ aboutData.addCredit("Jelmer Vernooij", I18N_NOOP("Dutch translation"), "jelmer@samba.org");
+ aboutData.addCredit("Jasper Stein", I18N_NOOP("Dutch translation"), "jasper.stein@12move.nl");
+ aboutData.addCredit("Kevin Liang", I18N_NOOP("HSpinBox class"), "xkliang@rhpcs.mcmaster.ca");
+ aboutData.addCredit("Arnout Engelen", I18N_NOOP("Transposition by interval"));
+ aboutData.addCredit("Thorsten Wilms", I18N_NOOP("Original designs for rotary controllers"), "t_w_@freenet.de");
+ aboutData.addCredit("Oota Toshiya", I18N_NOOP("Japanese translation"), "ribbon@users.sourceforge.net");
+ aboutData.addCredit("William", I18N_NOOP("Auto-scroll deceleration\nRests outside staves and other bug fixes"), "rosegarden4p AT orthoset.com");
+ aboutData.addCredit("Liu Songhe", I18N_NOOP("Simplified Chinese translation"), "jackliu9999@msn.com");
+ aboutData.addCredit("Toni Arnold", I18N_NOOP("LIRC infrared remote-controller support"), "<toni__arnold@bluewin.ch>");
+ aboutData.addCredit("Vince Negri", I18N_NOOP("MTC slave timing implementation"), "vince.negri@gmail.com");
+ aboutData.addCredit("Jan Bína", I18N_NOOP("Czech translation"), "jbina@sky.cz");
+ aboutData.addCredit("Thomas Nagy", I18N_NOOP("SCons/bksys building system"), "tnagy256@yahoo.fr");
+ aboutData.addCredit("Vladimir Savic", I18N_NOOP("icons, icons, icons"), "vladimir@vladimirsavic.net");
+ aboutData.addCredit("Marcos Germán Guglielmetti", I18N_NOOP("Spanish translation"), "marcospcmusica@yahoo.com.ar");
+ aboutData.addCredit("Lisandro Damián Nicanor Pérez Meyer", I18N_NOOP("Spanish translation"), "perezmeyer@infovia.com.ar");
+ aboutData.addCredit("Javier Castrillo", I18N_NOOP("Spanish translation"), "riverplatense@gmail.com");
+ aboutData.addCredit("Lucas Godoy", I18N_NOOP("Spanish translation"), "godoy.lucas@gmail.com");
+ aboutData.addCredit("Feliu Ferrer", I18N_NOOP("Catalan translation"), "mverge2@pie.xtec.es");
+ aboutData.addCredit("Quim Perez i Noguer", I18N_NOOP("Catalan translation"), "noguer@osona.com");
+ aboutData.addCredit("Carolyn McIntyre", I18N_NOOP("1.2.3 splash screen photo\nGave birth to D. Michael McIntyre, bought him a good flute once\nupon a time, and always humored him when he came over to play her\nsome new instrument, even though she really hated his playing.\nBorn October 19, 1951, died September 21, 2007, R. I. P."), "DECEASED");
+ aboutData.addCredit("Stephen Torri", I18N_NOOP("Initial guitar chord editing code"), "storri@torri.org");
+ aboutData.addCredit("Piotr Sawicki", I18N_NOOP("Polish translation"), "pelle@plusnet.pl");
+ aboutData.addCredit("David García-Abad", I18N_NOOP("Basque translation"), "davidgarciabad@telefonica.net");
+ aboutData.addCredit("Joerg C. Koenig, Craig Drummond, Bernhard Rosenkränzer, Preston Brown, Than Ngo", I18N_NOOP("Klearlook theme"), "jck@gmx.org");
+
+ aboutData.setTranslator(I18N_NOOP("_: NAME OF TRANSLATORS\nYour names") , I18N_NOOP("_: EMAIL OF TRANSLATORS\nYour emails"));
+
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
+ KUniqueApplication::addCmdLineOptions(); // Add KUniqueApplication options.
+
+ if (!RosegardenApplication::start())
+ return 0;
+
+ RosegardenApplication app;
+
+ //
+ // Ensure quit on last window close
+ // Register main DCOP interface
+ //
+ QObject::connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));
+ app.dcopClient()->registerAs(app.name(), false);
+ app.dcopClient()->setDefaultObject(ROSEGARDEN_GUI_IFACE_NAME);
+
+ // Parse cmd line args
+ //
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ if (!args->isSet("ignoreversion")) {
+ // Give up immediately if we haven't been installed or if the
+ // installation is out of date
+ //
+ testInstalledVersion();
+ }
+
+ KConfig *config = kapp->config();
+
+ config->setGroup(GeneralOptionsConfigGroup);
+ QString lastVersion = config->readEntry("lastversion", "");
+ bool newVersion = (lastVersion != VERSION);
+ if (newVersion) {
+ std::cerr << "*** This is the first time running this Rosegarden version" << std::endl;
+ config->writeEntry("lastversion", VERSION);
+ }
+
+ // If there is no config setting for the startup window size, set
+ // one now. But base the default on the appropriate desktop size
+ // (i.e. not the entire desktop, if Xinerama is in use). This is
+ // obtained from KGlobalSettings::desktopGeometry(), but we can't
+ // give it a meaningful point to measure from at this stage so we
+ // always use the "leftmost" display (point 0,0).
+
+ // The config keys are "Height X" and "Width Y" where X and Y are
+ // the sizes of the available desktop (i.e. the whole shebang if
+ // under Xinerama). These are obtained from QDesktopWidget.
+
+ config->setGroup("MainView");
+ int windowWidth = 0, windowHeight = 0;
+
+ QDesktopWidget *desktop = KApplication::desktop();
+ if (desktop) {
+ QRect totalRect(desktop->screenGeometry());
+ QRect desktopRect = KGlobalSettings::desktopGeometry(QPoint(0, 0));
+ QSize startupSize;
+ if (desktopRect.height() <= 800) {
+ startupSize = QSize((desktopRect.width() * 6) / 7,
+ (desktopRect.height() * 6) / 7);
+ } else {
+ startupSize = QSize((desktopRect.width() * 4) / 5,
+ (desktopRect.height() * 4) / 5);
+ }
+ QString widthKey = QString("Width %1").arg(totalRect.width());
+ QString heightKey = QString("Height %1").arg(totalRect.height());
+ windowWidth = config->readUnsignedNumEntry
+ (widthKey, startupSize.width());
+ windowHeight = config->readUnsignedNumEntry
+ (heightKey, startupSize.height());
+ }
+
+ config->setGroup("KDE Action Restrictions");
+ config->writeEntry("action/help_report_bug", false);
+
+ config->setGroup(GeneralOptionsConfigGroup);
+ int install = config->readNumEntry("Install Own Theme", 1);
+ if (install == 2 || (install == 1 && !getenv("KDE_FULL_SESSION"))) {
+ kapp->setStyle(new KlearlookStyle);
+ }
+
+ // Show Startup logo
+ // (this code borrowed from KDevelop 2.0,
+ // (c) The KDevelop Development Team
+ //
+ config->setGroup(GeneralOptionsConfigGroup);
+ KStartupLogo* startLogo = 0L;
+
+ // See if the config wants us to control JACK
+ //
+ if (config->readBoolEntry("Logo", true) && (!kapp->isRestored() && args->isSet("splash")) ) {
+ RG_DEBUG << k_funcinfo << "Showing startup logo\n";
+ startLogo = KStartupLogo::getInstance();
+ startLogo->setShowTip(!newVersion);
+ startLogo->show();
+ }
+
+ struct timeval logoShowTime;
+ gettimeofday(&logoShowTime, 0);
+
+ //
+ // Start application
+ //
+ RosegardenGUIApp *rosegardengui = 0;
+
+ if (app.isRestored()) {
+ RG_DEBUG << "Restoring from session\n";
+
+ // RESTORE(RosegardenGUIApp);
+ int n = 1;
+ while (KMainWindow::canBeRestored(n)) {
+ // memory leak if more than one can be restored?
+ RG_DEBUG << "Restoring from session - restoring app #" << n << endl;
+ (rosegardengui = new RosegardenGUIApp)->restore(n);
+ n++;
+ }
+
+ } else {
+
+#ifndef NO_SOUND
+ app.setNoSequencerMode(!args->isSet("sequencer"));
+#else
+
+ app.setNoSequencerMode(true);
+#endif // NO_SOUND
+
+ rosegardengui = new RosegardenGUIApp(!app.noSequencerMode(),
+ args->isSet("existingsequencer"),
+ startLogo);
+
+ rosegardengui->setIsFirstRun(newVersion);
+
+ app.setMainWidget(rosegardengui);
+
+ if (windowWidth != 0 && windowHeight != 0) {
+ rosegardengui->resize(windowWidth, windowHeight);
+ }
+
+ rosegardengui->show();
+
+ // raise start logo
+ //
+ if (startLogo) {
+ startLogo->raise();
+ startLogo->setHideEnabled(true);
+ QApplication::flushX();
+ }
+
+ if (args->count()) {
+ rosegardengui->openFile(QFile::decodeName(args->arg(0)), RosegardenGUIApp::ImportCheckType);
+ } else {
+ // rosegardengui->openDocumentFile();
+ }
+
+ args->clear();
+
+ }
+
+ QObject::connect(&app, SIGNAL(aboutToSaveState()),
+ rosegardengui, SLOT(slotDeleteTransport()));
+
+ // Now that we've started up, raise start logo
+ //
+ if (startLogo) {
+ startLogo->raise();
+ startLogo->setHideEnabled(true);
+ QApplication::flushX();
+ }
+
+ // Check for sequencer and launch if needed
+ //
+ try {
+ rosegardengui->launchSequencer(args->isSet("existingsequencer"));
+ } catch (std::string e) {
+ RG_DEBUG << "RosegardenGUI - " << e << endl;
+ } catch (QString e) {
+ RG_DEBUG << "RosegardenGUI - " << e << endl;
+ } catch (Exception e) {
+ RG_DEBUG << "RosegardenGUI - " << e.getMessage() << endl;
+ }
+
+
+ config->setGroup(SequencerOptionsConfigGroup);
+
+ // See if the config wants us to load a soundfont
+ //
+ if (config->readBoolEntry("sfxloadenabled", false)) {
+ QString sfxLoadPath = config->readEntry("sfxloadpath", "/bin/sfxload");
+ QString soundFontPath = config->readEntry("soundfontpath", "");
+ QFileInfo sfxLoadInfo(sfxLoadPath), soundFontInfo(soundFontPath);
+ if (sfxLoadInfo.isExecutable() && soundFontInfo.isReadable()) {
+ KProcess* sfxLoadProcess = new KProcess;
+ (*sfxLoadProcess) << sfxLoadPath << soundFontPath;
+ RG_DEBUG << "Starting sfxload : " << sfxLoadPath << " " << soundFontPath << endl;
+
+ QObject::connect(sfxLoadProcess, SIGNAL(processExited(KProcess*)),
+ &app, SLOT(sfxLoadExited(KProcess*)));
+
+ sfxLoadProcess->start();
+ } else {
+ RG_DEBUG << "sfxload not executable or soundfont not readable : "
+ << sfxLoadPath << " " << soundFontPath << endl;
+ }
+
+ } else {
+ RG_DEBUG << "sfxload disabled\n";
+ }
+
+
+#ifdef Q_WS_X11
+ XSetErrorHandler( _x_errhandler );
+#endif
+
+ if (startLogo) {
+
+ // pause to ensure the logo has been visible for a reasonable
+ // length of time, just 'cos it looks a bit silly to show it
+ // and remove it immediately
+
+ struct timeval now;
+ gettimeofday(&now, 0);
+
+ RealTime visibleFor =
+ RealTime(now.tv_sec, now.tv_usec * 1000) -
+ RealTime(logoShowTime.tv_sec, logoShowTime.tv_usec * 1000);
+
+ if (visibleFor < RealTime(2, 0)) {
+ int waitTime = visibleFor.sec * 1000 + visibleFor.msec();
+ QTimer::singleShot(2500 - waitTime, startLogo, SLOT(close()));
+ } else {
+ startLogo->close();
+ }
+
+ } else {
+
+ // if the start logo is there, it's responsible for showing this;
+ // otherwise we have to
+
+ if (!newVersion) {
+ RosegardenGUIApp::self()->awaitDialogClearance();
+ KTipDialog::showTip(locate("data", "rosegarden/tips"));
+ }
+ }
+
+ if (newVersion) {
+ KStartupLogo::hideIfStillThere();
+ CurrentProgressDialog::freeze();
+
+ KDialogBase *dialog = new KDialogBase(rosegardengui, "welcome",
+ true, i18n("Welcome!"),
+ KDialogBase::Ok,
+ KDialogBase::Ok, false);
+ QVBox *mw = dialog->makeVBoxMainWidget();
+ QHBox *hb = new QHBox(mw);
+ QLabel *image = new QLabel(hb);
+ image->setAlignment(Qt::AlignTop);
+ QString iconFile = locate("appdata", "pixmaps/misc/welcome-icon.png");
+ if (iconFile) {
+ image->setPixmap(QPixmap(iconFile));
+ }
+ QLabel *label = new QLabel(hb);
+ label->setText(i18n("<h2>Welcome to Rosegarden!</h2><p>Welcome to the Rosegarden audio and MIDI sequencer and musical notation editor.</p><ul><li>If you have not already done so, you may wish to install some DSSI synth plugins, or a separate synth program such as QSynth. Rosegarden does not synthesize sounds from MIDI on its own, so without these you will hear nothing.</li><br><br><li>Rosegarden uses the JACK audio server for recording and playback of audio, and for playback from DSSI synth plugins. These features will only be available if the JACK server is running.</li><br><br><li>Rosegarden has comprehensive documentation: see the Help menu for the handbook, tutorials, and other information!</li></ul><p>Rosegarden was brought to you by a team of volunteers across the world. To learn more, go to <a href=\"http://www.rosegardenmusic.com/\">http://www.rosegardenmusic.com/</a>.</p>"));
+ dialog->showButtonOK(true);
+ rosegardengui->awaitDialogClearance();
+ dialog->exec();
+
+ CurrentProgressDialog::thaw();
+ }
+
+ return kapp->exec();
+}
+