summaryrefslogtreecommitdiffstats
path: root/src/gui/studio/DeviceEditorDialog.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/studio/DeviceEditorDialog.cpp')
-rw-r--r--src/gui/studio/DeviceEditorDialog.cpp406
1 files changed, 406 insertions, 0 deletions
diff --git a/src/gui/studio/DeviceEditorDialog.cpp b/src/gui/studio/DeviceEditorDialog.cpp
new file mode 100644
index 0000000..29c9dd4
--- /dev/null
+++ b/src/gui/studio/DeviceEditorDialog.cpp
@@ -0,0 +1,406 @@
+/* -*- 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 <[email protected]>,
+ Chris Cannam <[email protected]>,
+ Richard Bown <[email protected]>
+
+ 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 "DeviceEditorDialog.h"
+
+#include <klocale.h>
+#include "misc/Debug.h"
+#include "misc/Strings.h"
+#include "base/Device.h"
+#include "base/MidiDevice.h"
+#include "base/Studio.h"
+#include "commands/studio/CreateOrDeleteDeviceCommand.h"
+#include "commands/studio/ReconnectDeviceCommand.h"
+#include "commands/studio/RenameDeviceCommand.h"
+#include "document/RosegardenGUIDoc.h"
+#include "document/MultiViewCommandHistory.h"
+#include "gui/application/RosegardenApplication.h"
+#include <kdialogbase.h>
+#include <kmessagebox.h>
+#include <qcstring.h>
+#include <qdatastream.h>
+#include <qhbox.h>
+#include <qpushbutton.h>
+#include <qregexp.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qtable.h>
+#include <qvbox.h>
+#include <qwidget.h>
+#include <algorithm>
+
+
+namespace Rosegarden
+{
+
+DeviceEditorDialog::DeviceEditorDialog(QWidget *parent,
+ RosegardenGUIDoc *document) :
+ KDialogBase(parent, "deviceeditordialog", true,
+ i18n("Manage MIDI Devices"), Ok | Apply | Close, Ok, true),
+ m_document(document),
+ m_studio(&document->getStudio()),
+ m_modified(false)
+{
+ QVBox *mainBox = makeVBoxMainWidget();
+
+ m_table = new QTable(0, 4, mainBox);
+ m_table->setSorting(false);
+ m_table->setRowMovingEnabled(false);
+ m_table->setColumnMovingEnabled(false);
+ m_table->setShowGrid(false);
+ m_table->horizontalHeader()->setLabel(0, i18n("Device"));
+ m_table->horizontalHeader()->setLabel(1, i18n("Name"));
+ m_table->horizontalHeader()->setLabel(2, i18n("Type"));
+ m_table->horizontalHeader()->setLabel(3, i18n("Connection"));
+ m_table->horizontalHeader()->show();
+ m_table->verticalHeader()->hide();
+ m_table->setLeftMargin(0);
+ m_table->setSelectionMode(QTable::SingleRow);
+ m_table->setColumnReadOnly(0, true);
+ m_table->setColumnReadOnly(2, true);
+
+ makeConnectionList((unsigned int)MidiDevice::Play,
+ m_playConnections);
+ makeConnectionList((unsigned int)MidiDevice::Record,
+ m_recordConnections);
+
+ populate();
+
+ QHBox *hbox = new QHBox(mainBox);
+ QPushButton *addButton = new QPushButton(i18n("Add Play Device"), hbox);
+ QPushButton *addRButton = new QPushButton(i18n("Add Record Device"), hbox);
+ QPushButton *deleteButton = new QPushButton(i18n("Delete Device"), hbox);
+ connect(addButton, SIGNAL(clicked()), this, SLOT(slotAddPlayDevice()));
+ connect(addRButton, SIGNAL(clicked()), this, SLOT(slotAddRecordDevice()));
+ connect(deleteButton, SIGNAL(clicked()), this, SLOT(slotDeleteDevice()));
+ connect(m_table, SIGNAL(valueChanged(int, int)),
+ this, SLOT(slotValueChanged (int, int)));
+
+ setMinimumHeight(250);
+
+ enableButtonOK(false);
+ enableButtonApply(false);
+}
+
+DeviceEditorDialog::~DeviceEditorDialog()
+{
+ // nothing -- don't need to clear device list (the devices were
+ // just aliases for those in the studio)
+}
+
+void
+DeviceEditorDialog::populate()
+{
+ DeviceList *devices = m_studio->getDevices();
+ DeviceListIterator it;
+ m_devices.clear();
+
+ for (it = devices->begin(); it != devices->end(); ++it) {
+ if ((*it)->getType() == Device::Midi) {
+ MidiDevice *md =
+ dynamic_cast<MidiDevice *>(*it);
+ if (md)
+ m_devices.push_back(md);
+ }
+ }
+
+ while (m_table->numRows() > 0) {
+ m_table->removeRow(m_table->numRows() - 1);
+ }
+
+ int deviceCount = 0;
+
+#define NAME_COL 0
+#define LABEL_COL 1
+#define DIRECTION_COL 2
+#define CONNECTION_COL 3
+
+ for (it = m_devices.begin(); it != m_devices.end(); ++it) {
+
+ m_table->insertRows(deviceCount, 1);
+
+ // we know we only put MidiDevices in m_devices
+ MidiDevice *md = static_cast<MidiDevice *>(*it);
+
+ // if you change this string ("Device %1"), change test in slotApply
+ QString deviceName = i18n("Device %1").arg(md->getId() + 1);
+ QString deviceLabel = strtoqstr(md->getName());
+ QString connectionName = strtoqstr(md->getConnection());
+
+ m_table->setText(deviceCount, NAME_COL, deviceName);
+ m_table->setText(deviceCount, LABEL_COL, deviceLabel);
+ m_table->setText(deviceCount, DIRECTION_COL,
+ (md->getDirection() == MidiDevice::Play ?
+ i18n("Play") : i18n("Record")));
+
+ QStringList &list(md->getDirection() == MidiDevice::Play ?
+ m_playConnections : m_recordConnections);
+ int currentConnectionIndex = list.size() - 1;
+ for (unsigned int i = 0; i < list.size(); ++i) {
+ if (list[i] == connectionName)
+ currentConnectionIndex = i;
+ }
+
+ QComboTableItem *item = new QComboTableItem(m_table, list, false);
+ item->setCurrentItem(currentConnectionIndex);
+ m_table->setItem(deviceCount, CONNECTION_COL, item);
+
+ m_table->adjustRow(deviceCount);
+ ++deviceCount;
+ }
+
+ int minColumnWidths[] = { 80, 120, 100, 250 };
+ for (int i = 0; i < 4; ++i) {
+ m_table->adjustColumn(i);
+ if (m_table->columnWidth(i) < minColumnWidths[i])
+ m_table->setColumnWidth(i, minColumnWidths[i]);
+ }
+}
+
+void
+DeviceEditorDialog::makeConnectionList(unsigned int direction,
+ QStringList &list)
+{
+ QByteArray data;
+ QByteArray replyData;
+ QCString replyType;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << (int)Device::Midi;
+ arg << direction;
+
+ if (!rgapp->sequencerCall("getConnections(int, unsigned int)", replyType, replyData, data)) {
+ RG_DEBUG << "DeviceEditorDialog: can't call Sequencer" << endl;
+ list.append(i18n("No connection"));
+ return ;
+ }
+
+ QDataStream reply(replyData, IO_ReadOnly);
+ unsigned int connections = 0;
+ if (replyType == "unsigned int")
+ reply >> connections;
+
+ for (unsigned int i = 0; i < connections; ++i) {
+
+ QByteArray data;
+ QByteArray replyData;
+ QCString replyType;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << (int)Device::Midi;
+ arg << direction;
+ arg << i;
+
+
+ if (!rgapp->sequencerCall("getConnection(int, unsigned int, unsigned int)",
+ replyType, replyData, data)) {
+ RG_DEBUG << "DeviceEditorDialog: can't call Sequencer" << endl;
+ list.append(i18n("No connection"));
+ return ;
+ }
+
+ QDataStream reply(replyData, IO_ReadOnly);
+ QString connection;
+ if (replyType == "QString") {
+ reply >> connection;
+ list.append(connection);
+ }
+ }
+
+ list.append(i18n("No connection"));
+}
+
+void
+DeviceEditorDialog::setModified(bool m)
+{
+ if (m_modified == m)
+ return ;
+ enableButtonOK(m);
+ enableButtonApply(m);
+ m_modified = m;
+}
+
+void
+DeviceEditorDialog::slotOk()
+{
+ slotApply();
+ accept();
+}
+
+void
+DeviceEditorDialog::slotClose()
+{
+ if (m_modified) {
+
+ int reply = KMessageBox::questionYesNo(this,
+ i18n("Apply pending changes?"));
+
+ if (reply == KMessageBox::Yes)
+ slotApply();
+ }
+
+ reject();
+}
+
+void
+DeviceEditorDialog::slotApply()
+{
+ KMacroCommand *command = new KMacroCommand("Edit Devices");
+
+ // first delete deleted devices, in reverse order of id (so that
+ // if we undo this command we'll get the original ids back... probably)
+
+ std::vector<DeviceId> ids;
+
+ for (DeviceListIterator i = m_devices.begin();
+ i != m_devices.end(); ++i) {
+ if (m_deletedDevices.find((*i)->getId()) != m_deletedDevices.end()) {
+ ids.push_back((*i)->getId());
+ }
+ }
+
+ std::sort(ids.begin(), ids.end());
+
+ for (int i = ids.size() - 1; i >= 0; --i) {
+ command->addCommand(new CreateOrDeleteDeviceCommand(m_studio, ids[i]));
+ }
+
+ // create the new devices, and rename and/or set connections for
+ // any others that have changed
+
+ for (int i = 0; i < m_table->numRows(); ++i) {
+ int deviceId = getDeviceIdAt(i);
+ if (deviceId < 0) { // new device
+ command->addCommand(new CreateOrDeleteDeviceCommand
+ (m_studio,
+ qstrtostr(m_table->text(i, LABEL_COL)),
+ Device::Midi,
+ m_table->text(i, DIRECTION_COL) == "Play" ?
+ MidiDevice::Play :
+ MidiDevice::Record,
+ qstrtostr(m_table->text(i, CONNECTION_COL))));
+ } else { // existing device
+ Device *device = m_studio->getDevice(deviceId);
+ if (!device) {
+ /*
+ std::cerr <<
+ "WARNING: DeviceEditorDialog::slotApply(): device at row "
+ << i << " (id " << deviceId
+ << ") claims not to be new, but isn't in the studio"
+ << std::endl;
+ */
+ } else {
+ std::string name = qstrtostr(m_table->text(i, LABEL_COL));
+ std::string conn = qstrtostr(m_table->text(i, CONNECTION_COL));
+ if (device->getName() != name) {
+ command->addCommand(new RenameDeviceCommand
+ (m_studio, deviceId, name));
+ }
+ if (device->getConnection() != conn) {
+ command->addCommand(new ReconnectDeviceCommand
+ (m_studio, deviceId, conn));
+ }
+ }
+ }
+ }
+
+ m_document->getCommandHistory()->addCommand(command);
+
+ m_deletedDevices.clear();
+
+ populate();
+ setModified(false);
+}
+
+int
+DeviceEditorDialog::getDeviceIdAt(int row) // -1 for new device w/o an id yet
+{
+ QString t(m_table->text(row, 0));
+
+ QRegExp re("^.*(\\d+).*$");
+ re.search(t);
+
+ QString number = re.cap(1);
+ int id = -1;
+
+ if (number && number != "")
+ {
+ id = number.toInt() - 1; // displayed device numbers are 1-based
+ }
+
+ return id;
+}
+
+void
+DeviceEditorDialog::slotAddPlayDevice()
+{
+ int n = m_table->numRows();
+ m_table->insertRows(n, 1);
+ m_table->setText(n, 0, i18n("<new device>"));
+ m_table->setText(n, 1, i18n("New Device"));
+ m_table->setText(n, 2, i18n("Play"));
+
+ QComboTableItem *item =
+ new QComboTableItem(m_table, m_playConnections, false);
+ item->setCurrentItem(m_playConnections.size() - 1);
+ m_table->setItem(n, 3, item);
+ m_table->adjustRow(n);
+
+ setModified(true);
+}
+
+void
+DeviceEditorDialog::slotAddRecordDevice()
+{
+ int n = m_table->numRows();
+ m_table->insertRows(n, 1);
+ m_table->setText(n, 0, i18n("<new device>"));
+ m_table->setText(n, 1, i18n("New Device"));
+ m_table->setText(n, 2, i18n("Record"));
+
+ QComboTableItem *item =
+ new QComboTableItem(m_table, m_recordConnections, false);
+ item->setCurrentItem(m_recordConnections.size() - 1);
+ m_table->setItem(n, 3, item);
+ m_table->adjustRow(n);
+
+ setModified(true);
+}
+
+void
+DeviceEditorDialog::slotDeleteDevice()
+{
+ int n = m_table->currentRow();
+ m_deletedDevices.insert(getDeviceIdAt(n));
+ m_table->removeRow(n);
+ setModified(true);
+}
+
+void
+DeviceEditorDialog::slotValueChanged(int, int)
+{
+ setModified(true);
+}
+
+}
+#include "DeviceEditorDialog.moc"