You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
575 lines
16 KiB
575 lines
16 KiB
/*
|
|
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 "TriggerSegmentManager.h"
|
|
#include "TriggerManagerItem.h"
|
|
#include <tqlayout.h>
|
|
#include <tdeapplication.h>
|
|
|
|
#include "base/BaseProperties.h"
|
|
#include <tdelocale.h>
|
|
#include <kstddirs.h>
|
|
#include "misc/Debug.h"
|
|
#include "misc/Strings.h"
|
|
#include "base/Clipboard.h"
|
|
#include "base/Composition.h"
|
|
#include "base/CompositionTimeSliceAdapter.h"
|
|
#include "base/RealTime.h"
|
|
#include "base/Segment.h"
|
|
#include "base/TriggerSegment.h"
|
|
#include "commands/segment/AddTriggerSegmentCommand.h"
|
|
#include "commands/segment/DeleteTriggerSegmentCommand.h"
|
|
#include "commands/segment/PasteToTriggerSegmentCommand.h"
|
|
#include "document/MultiViewCommandHistory.h"
|
|
#include "document/RosegardenGUIDoc.h"
|
|
#include "document/ConfigGroups.h"
|
|
#include "gui/dialogs/TimeDialog.h"
|
|
#include "gui/general/MidiPitchLabel.h"
|
|
#include <tdeaction.h>
|
|
#include <kcommand.h>
|
|
#include <tdeglobal.h>
|
|
#include <tdelistview.h>
|
|
#include <tdemainwindow.h>
|
|
#include <tdemessagebox.h>
|
|
#include <tdestdaccel.h>
|
|
#include <kstdaction.h>
|
|
#include <tdeconfig.h>
|
|
#include <tqaccel.h>
|
|
#include <tqdialog.h>
|
|
#include <tqframe.h>
|
|
#include <tqiconset.h>
|
|
#include <tqlistview.h>
|
|
#include <tqpushbutton.h>
|
|
#include <tqsizepolicy.h>
|
|
#include <tqstring.h>
|
|
#include <tqtooltip.h>
|
|
#include <tqvbox.h>
|
|
#include <tqwidget.h>
|
|
#include <tqcanvas.h>
|
|
|
|
|
|
namespace Rosegarden
|
|
{
|
|
|
|
TriggerSegmentManager::TriggerSegmentManager(TQWidget *parent,
|
|
RosegardenGUIDoc *doc):
|
|
TDEMainWindow(parent, "triggereditordialog"),
|
|
m_doc(doc),
|
|
m_modified(false)
|
|
{
|
|
TQVBox* mainFrame = new TQVBox(this);
|
|
setCentralWidget(mainFrame);
|
|
|
|
setCaption(i18n("Manage Triggered Segments"));
|
|
|
|
m_listView = new TDEListView(mainFrame);
|
|
m_listView->addColumn("Index");
|
|
m_listView->addColumn(i18n("ID"));
|
|
m_listView->addColumn(i18n("Label"));
|
|
m_listView->addColumn(i18n("Duration"));
|
|
m_listView->addColumn(i18n("Base pitch"));
|
|
m_listView->addColumn(i18n("Base velocity"));
|
|
m_listView->addColumn(i18n("Triggers"));
|
|
|
|
// Align centrally
|
|
for (int i = 0; i < 2; ++i)
|
|
m_listView->setColumnAlignment(i, TQt::AlignHCenter);
|
|
|
|
TQFrame* btnBox = new TQFrame(mainFrame);
|
|
|
|
btnBox->setSizePolicy(
|
|
TQSizePolicy(TQSizePolicy::Minimum, TQSizePolicy::Fixed));
|
|
|
|
TQHBoxLayout* layout = new TQHBoxLayout(btnBox, 4, 10);
|
|
|
|
m_addButton = new TQPushButton(i18n("Add"), btnBox);
|
|
m_deleteButton = new TQPushButton(i18n("Delete"), btnBox);
|
|
m_deleteAllButton = new TQPushButton(i18n("Delete All"), btnBox);
|
|
|
|
m_closeButton = new TQPushButton(i18n("Close"), btnBox);
|
|
|
|
TQToolTip::add
|
|
(m_addButton,
|
|
i18n("Add a Triggered Segment"));
|
|
|
|
TQToolTip::add
|
|
(m_deleteButton,
|
|
i18n("Delete a Triggered Segment"));
|
|
|
|
TQToolTip::add
|
|
(m_deleteAllButton,
|
|
i18n("Delete All Triggered Segments"));
|
|
|
|
TQToolTip::add
|
|
(m_closeButton,
|
|
i18n("Close the Triggered Segment Manager"));
|
|
|
|
layout->addStretch(10);
|
|
layout->addWidget(m_addButton);
|
|
layout->addWidget(m_deleteButton);
|
|
layout->addWidget(m_deleteAllButton);
|
|
layout->addSpacing(30);
|
|
|
|
layout->addWidget(m_closeButton);
|
|
layout->addSpacing(5);
|
|
|
|
connect(m_addButton, TQT_SIGNAL(released()),
|
|
TQT_SLOT(slotAdd()));
|
|
|
|
connect(m_deleteButton, TQT_SIGNAL(released()),
|
|
TQT_SLOT(slotDelete()));
|
|
|
|
connect(m_closeButton, TQT_SIGNAL(released()),
|
|
TQT_SLOT(slotClose()));
|
|
|
|
connect(m_deleteAllButton, TQT_SIGNAL(released()),
|
|
TQT_SLOT(slotDeleteAll()));
|
|
|
|
setupActions();
|
|
|
|
m_doc->getCommandHistory()->attachView(actionCollection());
|
|
connect(m_doc->getCommandHistory(), TQT_SIGNAL(commandExecuted()),
|
|
this, TQT_SLOT(slotUpdate()));
|
|
|
|
connect(m_listView, TQT_SIGNAL(doubleClicked(TQListViewItem *)),
|
|
TQT_SLOT(slotEdit(TQListViewItem *)));
|
|
|
|
connect(m_listView, TQT_SIGNAL(pressed(TQListViewItem *)),
|
|
this, TQT_SLOT(slotItemClicked(TQListViewItem *)));
|
|
|
|
// Highlight all columns - enable extended selection mode
|
|
//
|
|
m_listView->setAllColumnsShowFocus(true);
|
|
m_listView->setSelectionMode(TQListView::Extended);
|
|
m_listView->setItemsRenameable(true);
|
|
|
|
initDialog();
|
|
|
|
setAutoSaveSettings(TriggerManagerConfigGroup, true);
|
|
|
|
m_accelerators = new TQAccel(this);
|
|
}
|
|
|
|
TriggerSegmentManager::~TriggerSegmentManager()
|
|
{
|
|
RG_DEBUG << "TriggerSegmentManager::~TriggerSegmentManager" << endl;
|
|
|
|
m_listView->saveLayout(kapp->config(), TriggerManagerConfigGroup);
|
|
|
|
if (m_doc)
|
|
m_doc->getCommandHistory()->detachView(actionCollection());
|
|
}
|
|
|
|
void
|
|
TriggerSegmentManager::initDialog()
|
|
{
|
|
RG_DEBUG << "TriggerSegmentManager::initDialog" << endl;
|
|
slotUpdate();
|
|
}
|
|
|
|
void
|
|
TriggerSegmentManager::slotUpdate()
|
|
{
|
|
RG_DEBUG << "TriggerSegmentManager::slotUpdate" << endl;
|
|
|
|
TriggerManagerItem *item;
|
|
|
|
m_listView->clear();
|
|
|
|
Composition &comp = m_doc->getComposition();
|
|
|
|
const Composition::triggersegmentcontainer &triggers =
|
|
comp.getTriggerSegments();
|
|
|
|
Composition::triggersegmentcontainerconstiterator it;
|
|
|
|
kapp->config()->setGroup(TriggerManagerConfigGroup);
|
|
int timeMode = kapp->config()->readNumEntry("timemode", 0);
|
|
|
|
int i = 0;
|
|
|
|
for (it = triggers.begin(); it != triggers.end(); ++it) {
|
|
|
|
// duration is as of first usage, or 0
|
|
|
|
int uses = 0;
|
|
timeT first = 0;
|
|
std::set
|
|
<int> tracks;
|
|
|
|
CompositionTimeSliceAdapter tsa(&m_doc->getComposition());
|
|
for (CompositionTimeSliceAdapter::iterator ci = tsa.begin();
|
|
ci != tsa.end(); ++ci) {
|
|
if ((*ci)->has(BaseProperties::TRIGGER_SEGMENT_ID) &&
|
|
(*ci)->get
|
|
<Int>(BaseProperties::TRIGGER_SEGMENT_ID) == (long)(*it)->getId()) {
|
|
++uses;
|
|
if (tracks.empty()) {
|
|
first = (*ci)->getAbsoluteTime();
|
|
}
|
|
tracks.insert(ci.getTrack());
|
|
}
|
|
}
|
|
|
|
timeT duration =
|
|
(*it)->getSegment()->getEndMarkerTime() -
|
|
(*it)->getSegment()->getStartTime();
|
|
|
|
TQString timeString = makeDurationString
|
|
(first, duration, timeMode);
|
|
|
|
TQString label = strtoqstr((*it)->getSegment()->getLabel());
|
|
if (label == "")
|
|
label = i18n("<no label>");
|
|
|
|
TQString used = i18n("%1 on 1 track",
|
|
"%1 on %n tracks",
|
|
tracks.size()).arg(uses);
|
|
|
|
TQString pitch = TQString("%1 (%2)")
|
|
.arg(MidiPitchLabel((*it)->getBasePitch()).getTQString())
|
|
.arg((*it)->getBasePitch());
|
|
|
|
TQString velocity = TQString("%1").arg((*it)->getBaseVelocity());
|
|
|
|
item = new TriggerManagerItem
|
|
(m_listView, TQString("%1").arg(i + 1), TQString("%1").arg((*it)->getId()),
|
|
label, timeString, pitch, velocity, used);
|
|
|
|
item->setRawDuration(duration);
|
|
item->setId((*it)->getId());
|
|
item->setUsage(uses);
|
|
item->setPitch((*it)->getBasePitch());
|
|
|
|
m_listView->insertItem(item);
|
|
++i;
|
|
}
|
|
|
|
if (m_listView->childCount() == 0) {
|
|
TQListViewItem *item =
|
|
new TriggerManagerItem(m_listView, i18n("<none>"));
|
|
m_listView->insertItem(item);
|
|
|
|
m_listView->setSelectionMode(TQListView::NoSelection);
|
|
} else {
|
|
m_listView->setSelectionMode(TQListView::Extended);
|
|
}
|
|
}
|
|
|
|
void
|
|
TriggerSegmentManager::slotDeleteAll()
|
|
{
|
|
if (KMessageBox::warningContinueCancel(this, i18n("This will remove all triggered segments from the whole composition. Are you sure?")) != KMessageBox::Continue)
|
|
return ;
|
|
|
|
RG_DEBUG << "TriggerSegmentManager::slotDeleteAll" << endl;
|
|
KMacroCommand *command = new KMacroCommand(i18n("Remove all triggered segments"));
|
|
|
|
TQListViewItem *it = m_listView->firstChild();
|
|
|
|
do {
|
|
|
|
TriggerManagerItem *item =
|
|
dynamic_cast<TriggerManagerItem*>(it);
|
|
|
|
if (!item)
|
|
continue;
|
|
|
|
DeleteTriggerSegmentCommand *c =
|
|
new DeleteTriggerSegmentCommand(m_doc,
|
|
item->getId());
|
|
command->addCommand(c);
|
|
|
|
} while ((it = it->nextSibling()));
|
|
|
|
addCommandToHistory(command);
|
|
}
|
|
|
|
void
|
|
TriggerSegmentManager::slotAdd()
|
|
{
|
|
TimeDialog dialog(this, i18n("Trigger Segment Duration"),
|
|
&m_doc->getComposition(),
|
|
0, 3840, false);
|
|
|
|
if (dialog.exec() == TQDialog::Accepted) {
|
|
addCommandToHistory(new AddTriggerSegmentCommand
|
|
(m_doc, dialog.getTime(), 64));
|
|
}
|
|
}
|
|
|
|
void
|
|
TriggerSegmentManager::slotDelete()
|
|
{
|
|
RG_DEBUG << "TriggerSegmentManager::slotDelete" << endl;
|
|
|
|
TriggerManagerItem *item =
|
|
dynamic_cast<TriggerManagerItem*>(m_listView->currentItem());
|
|
|
|
if (!item)
|
|
return ;
|
|
|
|
if (item->getUsage() > 0) {
|
|
if (KMessageBox::warningContinueCancel(this, i18n("This triggered segment is used 1 time in the current composition. Are you sure you want to remove it?",
|
|
"This triggered segment is used %n times in the current composition. Are you sure you want to remove it?", item->getUsage())) != KMessageBox::Continue)
|
|
return ;
|
|
}
|
|
|
|
DeleteTriggerSegmentCommand *command =
|
|
new DeleteTriggerSegmentCommand(m_doc, item->getId());
|
|
|
|
addCommandToHistory(command);
|
|
}
|
|
|
|
void
|
|
TriggerSegmentManager::slotPasteAsNew()
|
|
{
|
|
Clipboard *clipboard = m_doc->getClipboard();
|
|
|
|
if (clipboard->isEmpty()) {
|
|
KMessageBox::information(this, i18n("Clipboard is empty"));
|
|
return ;
|
|
}
|
|
|
|
addCommandToHistory(new PasteToTriggerSegmentCommand
|
|
(&m_doc->getComposition(),
|
|
clipboard,
|
|
"",
|
|
-1));
|
|
}
|
|
|
|
void
|
|
TriggerSegmentManager::slotClose()
|
|
{
|
|
RG_DEBUG << "TriggerSegmentManager::slotClose" << endl;
|
|
|
|
if (m_doc)
|
|
m_doc->getCommandHistory()->detachView(actionCollection());
|
|
m_doc = 0;
|
|
|
|
close();
|
|
}
|
|
|
|
void
|
|
TriggerSegmentManager::setupActions()
|
|
{
|
|
TDEAction* close = KStdAction::close(this,
|
|
TQT_SLOT(slotClose()),
|
|
actionCollection());
|
|
|
|
m_closeButton->setText(close->text());
|
|
connect(m_closeButton, TQT_SIGNAL(released()), this, TQT_SLOT(slotClose()));
|
|
|
|
TQString pixmapDir = TDEGlobal::dirs()->findResource("appdata", "pixmaps/");
|
|
|
|
// some adjustments
|
|
new TDEToolBarPopupAction(i18n("Und&o"),
|
|
"edit-undo",
|
|
TDEStdAccel::key(TDEStdAccel::Undo),
|
|
actionCollection(),
|
|
KStdAction::stdName(KStdAction::Undo));
|
|
|
|
new TDEToolBarPopupAction(i18n("Re&do"),
|
|
"edit-redo",
|
|
TDEStdAccel::key(TDEStdAccel::Redo),
|
|
actionCollection(),
|
|
KStdAction::stdName(KStdAction::Redo));
|
|
|
|
new TDEAction(i18n("Pa&ste as New Triggered Segment"), CTRL + SHIFT + Key_V, this,
|
|
TQT_SLOT(slotPasteAsNew()), actionCollection(),
|
|
"paste_to_trigger_segment");
|
|
|
|
kapp->config()->setGroup(TriggerManagerConfigGroup);
|
|
int timeMode = kapp->config()->readNumEntry("timemode", 0);
|
|
|
|
TDERadioAction *action;
|
|
|
|
TQCanvasPixmap pixmap(pixmapDir + "/toolbar/time-musical.png");
|
|
TQIconSet icon(pixmap);
|
|
|
|
action = new TDERadioAction(i18n("&Musical Times"), icon, 0, this,
|
|
TQT_SLOT(slotMusicalTime()),
|
|
actionCollection(), "time_musical");
|
|
action->setExclusiveGroup("timeMode");
|
|
if (timeMode == 0)
|
|
action->setChecked(true);
|
|
|
|
pixmap.load(pixmapDir + "/toolbar/time-real.png");
|
|
icon = TQIconSet(pixmap);
|
|
|
|
action = new TDERadioAction(i18n("&Real Times"), icon, 0, this,
|
|
TQT_SLOT(slotRealTime()),
|
|
actionCollection(), "time_real");
|
|
action->setExclusiveGroup("timeMode");
|
|
if (timeMode == 1)
|
|
action->setChecked(true);
|
|
|
|
pixmap.load(pixmapDir + "/toolbar/time-raw.png");
|
|
icon = TQIconSet(pixmap);
|
|
|
|
action = new TDERadioAction(i18n("Ra&w Times"), icon, 0, this,
|
|
TQT_SLOT(slotRawTime()),
|
|
actionCollection(), "time_raw");
|
|
action->setExclusiveGroup("timeMode");
|
|
if (timeMode == 2)
|
|
action->setChecked(true);
|
|
|
|
createGUI("triggermanager.rc");
|
|
}
|
|
|
|
void
|
|
TriggerSegmentManager::addCommandToHistory(KCommand *command)
|
|
{
|
|
getCommandHistory()->addCommand(command);
|
|
setModified(false);
|
|
}
|
|
|
|
MultiViewCommandHistory*
|
|
TriggerSegmentManager::getCommandHistory()
|
|
{
|
|
return m_doc->getCommandHistory();
|
|
}
|
|
|
|
void
|
|
TriggerSegmentManager::setModified(bool modified)
|
|
{
|
|
RG_DEBUG << "TriggerSegmentManager::setModified(" << modified << ")" << endl;
|
|
|
|
m_modified = modified;
|
|
}
|
|
|
|
void
|
|
TriggerSegmentManager::checkModified()
|
|
{
|
|
RG_DEBUG << "TriggerSegmentManager::checkModified(" << m_modified << ")"
|
|
<< endl;
|
|
|
|
}
|
|
|
|
void
|
|
TriggerSegmentManager::slotEdit(TQListViewItem *i)
|
|
{
|
|
RG_DEBUG << "TriggerSegmentManager::slotEdit" << endl;
|
|
|
|
TriggerManagerItem *item =
|
|
dynamic_cast<TriggerManagerItem*>(i);
|
|
|
|
if (!item)
|
|
return ;
|
|
|
|
TriggerSegmentId id = item->getId();
|
|
|
|
RG_DEBUG << "id is " << id << endl;
|
|
|
|
emit editTriggerSegment(id);
|
|
}
|
|
|
|
void
|
|
TriggerSegmentManager::closeEvent(TQCloseEvent *e)
|
|
{
|
|
emit closing();
|
|
TDEMainWindow::closeEvent(e);
|
|
}
|
|
|
|
void
|
|
TriggerSegmentManager::setDocument(RosegardenGUIDoc *doc)
|
|
{
|
|
// reset our pointers
|
|
m_doc = doc;
|
|
m_modified = false;
|
|
|
|
slotUpdate();
|
|
}
|
|
|
|
void
|
|
TriggerSegmentManager::slotItemClicked(TQListViewItem *item)
|
|
{
|
|
RG_DEBUG << "TriggerSegmentManager::slotItemClicked" << endl;
|
|
}
|
|
|
|
TQString
|
|
TriggerSegmentManager::makeDurationString(timeT time,
|
|
timeT duration, int timeMode)
|
|
{
|
|
//!!! duplication with EventView::makeDurationString -- merge somewhere?
|
|
|
|
switch (timeMode) {
|
|
|
|
case 0: // musical time
|
|
{
|
|
int bar, beat, fraction, remainder;
|
|
m_doc->getComposition().getMusicalTimeForDuration
|
|
(time, duration, bar, beat, fraction, remainder);
|
|
return TQString("%1%2%3-%4%5-%6%7-%8%9 ")
|
|
.arg(bar / 100)
|
|
.arg((bar % 100) / 10)
|
|
.arg(bar % 10)
|
|
.arg(beat / 10)
|
|
.arg(beat % 10)
|
|
.arg(fraction / 10)
|
|
.arg(fraction % 10)
|
|
.arg(remainder / 10)
|
|
.arg(remainder % 10);
|
|
}
|
|
|
|
case 1: // real time
|
|
{
|
|
RealTime rt =
|
|
m_doc->getComposition().getRealTimeDifference
|
|
(time, time + duration);
|
|
// return TQString("%1 ").arg(rt.toString().c_str());
|
|
return TQString("%1 ").arg(rt.toText().c_str());
|
|
}
|
|
|
|
default:
|
|
return TQString("%1 ").arg(duration);
|
|
}
|
|
}
|
|
|
|
void
|
|
TriggerSegmentManager::slotMusicalTime()
|
|
{
|
|
kapp->config()->setGroup(TriggerManagerConfigGroup);
|
|
kapp->config()->writeEntry("timemode", 0);
|
|
slotUpdate();
|
|
}
|
|
|
|
void
|
|
TriggerSegmentManager::slotRealTime()
|
|
{
|
|
kapp->config()->setGroup(TriggerManagerConfigGroup);
|
|
kapp->config()->writeEntry("timemode", 1);
|
|
slotUpdate();
|
|
}
|
|
|
|
void
|
|
TriggerSegmentManager::slotRawTime()
|
|
{
|
|
kapp->config()->setGroup(TriggerManagerConfigGroup);
|
|
kapp->config()->writeEntry("timemode", 2);
|
|
slotUpdate();
|
|
}
|
|
|
|
}
|
|
#include "TriggerSegmentManager.moc"
|