/*
    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 "EditView.h"
#include <tqlayout.h>

#include "base/BaseProperties.h"
#include <tdelocale.h>
#include <tdeconfig.h>
#include "misc/Debug.h"
#include "misc/Strings.h"
#include "ActiveItem.h"
#include "base/AnalysisTypes.h"
#include "base/Composition.h"
#include "base/CompositionTimeSliceAdapter.h"
#include "base/Controllable.h"
#include "base/ControlParameter.h"
#include "base/Device.h"
#include "base/Event.h"
#include "base/Exception.h"
#include "base/Instrument.h"
#include "base/MidiDevice.h"
#include "base/MidiProgram.h"
#include "base/MidiTypes.h"
#include "base/NotationTypes.h"
#include "base/Profiler.h"
#include "base/Property.h"
#include "base/PropertyName.h"
#include "base/RulerScale.h"
#include "base/Segment.h"
#include "base/Selection.h"
#include "base/SoftSynthDevice.h"
#include "base/Staff.h"
#include "base/Studio.h"
#include "base/ViewElement.h"
#include "commands/edit/InvertCommand.h"
#include "commands/edit/MoveCommand.h"
#include "commands/edit/RescaleCommand.h"
#include "commands/edit/RetrogradeCommand.h"
#include "commands/edit/RetrogradeInvertCommand.h"
#include "commands/edit/TransposeCommand.h"
#include "commands/segment/AddTempoChangeCommand.h"
#include "commands/segment/AddTimeSignatureAndNormalizeCommand.h"
#include "commands/segment/AddTimeSignatureCommand.h"
#include "document/MultiViewCommandHistory.h"
#include "document/RosegardenGUIDoc.h"
#include "document/ConfigGroups.h"
#include "EditViewBase.h"
#include "gui/dialogs/RescaleDialog.h"
#include "gui/dialogs/TempoDialog.h"
#include "gui/dialogs/IntervalDialog.h"
#include "gui/dialogs/TimeSignatureDialog.h"
#include "gui/rulers/StandardRuler.h"
#include "gui/kdeext/KTmpStatusMsg.h"
#include "gui/kdeext/QCanvasGroupableItem.h"
#include "gui/rulers/ControllerEventsRuler.h"
#include "gui/rulers/ControlRuler.h"
#include "gui/rulers/PropertyControlRuler.h"
#include "RosegardenCanvasView.h"
#include <tdeaction.h>
#include <kcommand.h>
#include <kdockwidget.h>
#include <tdeglobal.h>
#include <kiconloader.h>
#include <kstandarddirs.h>
#include <ktabwidget.h>
#include <kxmlguiclient.h>
#include <tqaccel.h>
#include <tqbutton.h>
#include <tqdialog.h>
#include <tqframe.h>
#include <tqinputdialog.h>
#include <tqlabel.h>
#include <tqobjectlist.h>
#include <tqpopupmenu.h>
#include <tqsize.h>
#include <tqstring.h>
#include <tqtabwidget.h>
#include <tqvbox.h>
#include <tqwidget.h>
#include <tqwmatrix.h>


namespace Rosegarden
{

const unsigned int EditView::CONTROLS_ROW         = 0;
const unsigned int EditView::RULERS_ROW           = CONTROLS_ROW + 1;
const unsigned int EditView::TOPBARBUTTONS_ROW    = RULERS_ROW + 1;
const unsigned int EditView::CANVASVIEW_ROW       = TOPBARBUTTONS_ROW + 1;
const unsigned int EditView::CONTROLRULER_ROW     = CANVASVIEW_ROW + 1;

// Just some simple features we might want to show - make them bit maskable
//
static int FeatureShowVelocity = 0x00001; // show the velocity ruler

EditView::EditView(RosegardenGUIDoc *doc,
                   std::vector<Segment *> segments,
                   unsigned int cols,
                   TQWidget *parent, const char *name) :
        EditViewBase(doc, segments, cols, parent, name),
        m_currentEventSelection(0),
        m_activeItem(0),
        m_canvasView(0),
        m_rulerBox(new TQVBoxLayout),  // top ruler box - added to grid later on
        m_rulerBoxFiller(0),          // On the left of m_rulerBox
        m_controlBox(new TQVBoxLayout),  // top control ruler box - added to grid later on
        m_bottomBox(new TQVBox(this, "bottomframe")),  // bottom box - added to bottom of canvas view by setCanvasView()
        m_topStandardRuler(0),
        m_bottomStandardRuler(0),
        m_controlRuler(0),
        m_controlRulers(new KTabWidget(getBottomWidget(), "controlrulers"))
{
    m_controlRulers->setHoverCloseButton(true);
    m_controlRulers->setHoverCloseButtonDelayed(false);
    connect(m_controlRulers, TQ_SIGNAL(closeRequest(TQWidget*)),
            this, TQ_SLOT(slotRemoveControlRuler(TQWidget*)));

    (dynamic_cast<TQBoxLayout*>(m_bottomBox->layout()))->setDirection(TQBoxLayout::BottomToTop);

    // m_rulerBoxFiller is a white label used to keep m_rulerBox exactly
    // above the scrolling part of the view (and never above the
    // RosegardenCanvasView::m_leftWidget).
    TQGridLayout * gl = new TQGridLayout(1, 2); 
    gl->setColStretch(0, 0);
    gl->setColStretch(1, 1);
    gl->addLayout(m_rulerBox, 0, 1);
    m_rulerBoxFiller = new TQLabel(getCentralWidget());
    gl->addWidget(m_rulerBoxFiller, 0, 0);
    m_rulerBoxFiller->hide();

    m_grid->addLayout(gl, RULERS_ROW, m_mainCol);

    m_grid->addMultiCellLayout(m_controlBox, CONTROLS_ROW, CONTROLS_ROW, 0, 1);
    m_controlBox->setAlignment(AlignRight);
    //     m_grid->addWidget(m_controlRulers, CONTROLRULER_ROW, 2);

    m_controlRulers->hide();
    m_controlRulers->setTabPosition(TQTabWidget::Bottom);
}

EditView::~EditView()
{
    delete m_currentEventSelection;
    m_currentEventSelection = 0;
}

void EditView::updateBottomWidgetGeometry()
{
    getBottomWidget()->layout()->invalidate();
    getBottomWidget()->updateGeometry();
    getCanvasView()->updateBottomWidgetGeometry();
}

void EditView::paintEvent(TQPaintEvent* e)
{
    RG_DEBUG << "EditView::paintEvent()\n";
    EditViewBase::paintEvent(e);

    if (m_needUpdate) {
        RG_DEBUG << "EditView::paintEvent() - calling updateView\n";
        updateView();
        getCanvasView()->slotUpdate();

        // update rulers
        TQLayoutIterator it = m_rulerBox->iterator();
        TQLayoutItem *child;
        while ( (child = it.current()) != 0 ) {
            if (child->widget())
                child->widget()->update();
            ++it;
        }

        updateControlRulers();

    } else {

        getCanvasView()->slotUpdate();
        updateControlRulers();

    }

    m_needUpdate = false;
}

void EditView::updateControlRulers(bool updateHPos)
{
    for (int i = 0; i < m_controlRulers->count(); ++i) {
        ControlRuler* ruler = dynamic_cast<ControlRuler*>(m_controlRulers->page(i));
        if (ruler) {
            if (updateHPos)
                ruler->slotUpdateElementsHPos();
            else
                ruler->slotUpdate();
        }
    }
}

void EditView::setControlRulersZoom(TQWMatrix zoomMatrix)
{
    m_currentRulerZoomMatrix = zoomMatrix;

    for (int i = 0; i < m_controlRulers->count(); ++i) {
        ControlRuler* ruler = dynamic_cast<ControlRuler*>(m_controlRulers->page(i));
        if (ruler)
            ruler->setWorldMatrix(zoomMatrix);
    }
}

void EditView::setControlRulersCurrentSegment()
{
    RG_DEBUG << "EditView::setControlRulersCurrentSegment: visible is " << m_controlRulers->isVisible() << endl;

    bool visible = m_controlRulers->isVisible();

    delete m_controlRulers;
    m_controlRulers = new KTabWidget(getBottomWidget(), "controlrulers");

    bool haveTabs = setupControllerTabs();
    setupAddControlRulerMenu();

    if (haveTabs)
        m_controlRulers->show();
    else
        m_controlRulers->hide();

    updateBottomWidgetGeometry();

    /*
        for (int i = 0; i < m_controlRulers->count(); ++i) {
     
            PropertyControlRuler *pcr = dynamic_cast<PropertyControlRuler *>
    	    (m_controlRulers->page(i));
     
            if (pcr) pcr->setStaff(getCurrentStaff());
    	else {
     
    	    ControllerEventsRuler *cer = dynamic_cast<ControllerEventsRuler *>
    		(m_controlRulers->page(i));
     
    	    if (cer) cer->setSegment(getCurrentSegment());
    	}
        }
    */
}

void EditView::setTopStandardRuler(StandardRuler* w, TQWidget *leftBox)
{
    delete m_topStandardRuler;
    m_topStandardRuler = w;

    TQGridLayout * gl = new TQGridLayout(1, 2); 
    gl->setColStretch(0, 0);
    gl->setColStretch(1, 1);

    gl->addWidget(w, 0, 1);
    if (leftBox) {
        gl->addWidget(leftBox, 0, 0);
    }

    m_grid->addLayout(gl, TOPBARBUTTONS_ROW, m_mainCol);

    if (m_canvasView) {
        connect(m_canvasView->horizontalScrollBar(), TQ_SIGNAL(valueChanged(int)),
                m_topStandardRuler, TQ_SLOT(slotScrollHoriz(int)));
        connect(m_canvasView->horizontalScrollBar(), TQ_SIGNAL(sliderMoved(int)),
                m_topStandardRuler, TQ_SLOT(slotScrollHoriz(int)));
    }
}

void EditView::setBottomStandardRuler(StandardRuler* w)
{
    delete m_bottomStandardRuler;
    m_bottomStandardRuler = w;

    //     m_bottomBox->insertWidget(0, w);

    if (m_canvasView) {
        connect(m_canvasView->horizontalScrollBar(), TQ_SIGNAL(valueChanged(int)),
                m_bottomStandardRuler, TQ_SLOT(slotScrollHoriz(int)));
        connect(m_canvasView->horizontalScrollBar(), TQ_SIGNAL(sliderMoved(int)),
                m_bottomStandardRuler, TQ_SLOT(slotScrollHoriz(int)));
    }
}

void EditView::setRewFFwdToAutoRepeat()
{
    TQWidget* transportToolbar = factory()->container("Transport Toolbar", this);

    if (transportToolbar) {
        TQObjectList *l = transportToolbar->queryList();
        TQObjectListIt it(*l); // iterate over the buttons
        TQObject *obj;

        while ( (obj = it.current()) != 0 ) {
            // for each found object...
            ++it;
            //             RG_DEBUG << "EditView::setRewFFwdToAutoRepeat() : obj name : " << obj->name() << endl;
            TQString objName = obj->name();

            if (objName.endsWith("playback_pointer_back_bar") || objName.endsWith("playback_pointer_forward_bar")) {
                TQButton* btn = dynamic_cast<TQButton*>(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 EditView::addRuler(TQWidget* w)
{
    m_rulerBox->addWidget(w);

    if (m_canvasView) {
        connect(m_canvasView->horizontalScrollBar(), TQ_SIGNAL(valueChanged(int)),
                w, TQ_SLOT(slotScrollHoriz(int)));
        connect(m_canvasView->horizontalScrollBar(), TQ_SIGNAL(sliderMoved(int)),
                w, TQ_SLOT(slotScrollHoriz(int)));
    }
}

void EditView::addPropertyBox(TQWidget *w)
{
    m_controlBox->addWidget(w);
}

void EditView::addControlRuler(ControlRuler* ruler)
{
    ruler->setWorldMatrix(m_currentRulerZoomMatrix);
    m_controlRulers->addTab(ruler, TDEGlobal::iconLoader()->loadIconSet("window-close", TDEIcon::Small),
                            ruler->getName());
    m_controlRulers->showPage(ruler);

    if (m_canvasView) {
        connect(m_canvasView->horizontalScrollBar(), TQ_SIGNAL(valueChanged(int)),
                ruler->horizontalScrollBar(), TQ_SIGNAL(valueChanged(int)));
        connect(m_canvasView->horizontalScrollBar(), TQ_SIGNAL(sliderMoved(int)),
                ruler->horizontalScrollBar(), TQ_SIGNAL(sliderMoved(int)));
    }

    connect(ruler, TQ_SIGNAL(stateChange(const TQString&, bool)),
            this, TQ_SLOT(slotStateChanged(const TQString&, bool)));

    stateChanged("have_control_ruler", KXMLGUIClient::StateReverse);
}

void EditView::readjustViewSize(TQSize requestedSize, bool exact)
{
    Profiler profiler("EditView::readjustViewSize", true);

    if (exact) {
        RG_DEBUG << "EditView::readjustViewSize: exact size requested ("
        << requestedSize.width() << ", " << requestedSize.height()
        << ")\n";

        setViewSize(requestedSize);
        getCanvasView()->slotUpdate();
        return ;
    }

    int requestedWidth = requestedSize.width(),
        requestedHeight = requestedSize.height(),
        windowWidth = width(),
        windowHeight = height();

    TQSize newSize;

    newSize.setWidth(((requestedWidth / windowWidth) + 1) * windowWidth);
    newSize.setHeight(((requestedHeight / windowHeight) + 1) * windowHeight);

    RG_DEBUG << "EditView::readjustViewSize: requested ("
    << requestedSize.width() << ", " << requestedSize.height()
    << "), getting (" << newSize.width() << ", "
    << newSize.height() << ")" << endl;

    setViewSize(newSize);

    getCanvasView()->slotUpdate();
}

void EditView::setCanvasView(RosegardenCanvasView *canvasView)
{
    delete m_canvasView;
    m_canvasView = canvasView;
    m_grid->addWidget(m_canvasView, CANVASVIEW_ROW, m_mainCol);
    m_canvasView->setBottomFixedWidget(m_bottomBox);

    // TODO : connect canvas view's horiz. scrollbar to top/bottom bars and rulers

    //     m_horizontalScrollBar->setRange(m_canvasView->horizontalScrollBar()->minValue(),
    //                                     m_canvasView->horizontalScrollBar()->maxValue());

    //     m_horizontalScrollBar->setSteps(m_canvasView->horizontalScrollBar()->lineStep(),
    //                                     m_canvasView->horizontalScrollBar()->pageStep());

    //     connect(m_horizontalScrollBar, TQ_SIGNAL(valueChanged(int)),
    //             m_canvasView->horizontalScrollBar(), TQ_SIGNAL(valueChanged(int)));
    //     connect(m_horizontalScrollBar, TQ_SIGNAL(sliderMoved(int)),
    //             m_canvasView->horizontalScrollBar(), TQ_SIGNAL(sliderMoved(int)));

}

Device *
EditView::getCurrentDevice()
{
    Segment *segment = getCurrentSegment();
    if (!segment)
        return 0;

    Studio &studio = getDocument()->getStudio();
    Instrument *instrument =
        studio.getInstrumentById
        (segment->getComposition()->getTrackById(segment->getTrack())->
         getInstrument());
    if (!instrument)
        return 0;

    return instrument->getDevice();
}

timeT
EditView::getInsertionTime(Clef &clef,
                           Rosegarden::Key &key)
{
    timeT t = getInsertionTime();
    Segment *segment = getCurrentSegment();

    if (segment) {
        clef = segment->getClefAtTime(t);
        key = segment->getKeyAtTime(t);
    } else {
        clef = Clef();
        key = ::Rosegarden::Key();
    }

    return t;
}

void EditView::slotActiveItemPressed(TQMouseEvent* e,
                                     TQCanvasItem* item)
{
    if (!item)
        return ;

    // Check if it's a groupable item, if so get its group
    //
    QCanvasGroupableItem *gitem = dynamic_cast<QCanvasGroupableItem*>(item);
    if (gitem)
        item = gitem->group();

    // Check if it's an active item
    //
    ActiveItem *activeItem = dynamic_cast<ActiveItem*>(item);

    if (activeItem) {

        setActiveItem(activeItem);
        activeItem->handleMousePress(e);
        updateView();

    }
}

void
EditView::slotStepBackward()
{
    Staff *staff = getCurrentStaff();
    if (!staff)
        return ;
    ViewElementList *vel = staff->getViewElementList();

    timeT time = getInsertionTime();
    ViewElementList::iterator i = vel->findTime(time);

    while (i != vel->begin() &&
            (i == vel->end() || (*i)->getViewAbsoluteTime() >= time))
        --i;

    if (i != vel->end())
        slotSetInsertCursorPosition((*i)->getViewAbsoluteTime());
}

void
EditView::slotStepForward()
{
    Staff *staff = getCurrentStaff();
    if (!staff)
        return ;
    ViewElementList *vel = staff->getViewElementList();

    timeT time = getInsertionTime();
    ViewElementList::iterator i = vel->findTime(time);

    while (i != vel->end() &&
            (*i)->getViewAbsoluteTime() <= time)
        ++i;

    if (i == vel->end()) {
        slotSetInsertCursorPosition(staff->getSegment().getEndMarkerTime());
    } else {
        slotSetInsertCursorPosition((*i)->getViewAbsoluteTime());
    }
}

void
EditView::slotJumpBackward()
{
    Segment *segment = getCurrentSegment();
    if (!segment)
        return ;
    timeT time = getInsertionTime();
    time = segment->getBarStartForTime(time - 1);
    slotSetInsertCursorPosition(time);
}

void
EditView::slotJumpForward()
{
    Segment *segment = getCurrentSegment();
    if (!segment)
        return ;
    timeT time = getInsertionTime();
    time = segment->getBarEndForTime(time);
    slotSetInsertCursorPosition(time);
}

void
EditView::slotJumpToStart()
{
    Segment *segment = getCurrentSegment();
    if (!segment)
        return ;
    timeT time = segment->getStartTime();
    slotSetInsertCursorPosition(time);
}

void
EditView::slotJumpToEnd()
{
    Segment *segment = getCurrentSegment();
    if (!segment)
        return ;
    timeT time = segment->getEndMarkerTime();
    slotSetInsertCursorPosition(time);
}

void EditView::slotExtendSelectionBackward()
{
    slotExtendSelectionBackward(false);
}

void EditView::slotExtendSelectionBackwardBar()
{
    slotExtendSelectionBackward(true);
}

void EditView::slotExtendSelectionBackward(bool bar)
{
    // If there is no current selection, or the selection is entirely
    // to the right of the cursor, move the cursor left and add to the
    // selection

    timeT oldTime = getInsertionTime();
    if (bar)
        slotJumpBackward();
    else
        slotStepBackward();
    timeT newTime = getInsertionTime();

    Staff *staff = getCurrentStaff();
    if (!staff)
        return ;
    Segment *segment = &staff->getSegment();
    ViewElementList *vel = staff->getViewElementList();

    EventSelection *es = new EventSelection(*segment);
    if (m_currentEventSelection &&
            &m_currentEventSelection->getSegment() == segment)
        es->addFromSelection(m_currentEventSelection);

    if (!m_currentEventSelection ||
            &m_currentEventSelection->getSegment() != segment ||
            m_currentEventSelection->getSegmentEvents().size() == 0 ||
            m_currentEventSelection->getStartTime() >= oldTime) {

        ViewElementList::iterator extendFrom = vel->findTime(oldTime);

        while (extendFrom != vel->begin() &&
                (*--extendFrom)->getViewAbsoluteTime() >= newTime) {
            if ((*extendFrom)->event()->isa(Note::EventType)) {
                es->addEvent((*extendFrom)->event());
            }
        }

    } else { // remove an event

        EventSelection::eventcontainer::iterator i =
            es->getSegmentEvents().end();

        std::vector<Event *> toErase;

        while (i != es->getSegmentEvents().begin() &&
                (*--i)->getAbsoluteTime() >= newTime) {
            toErase.push_back(*i);
        }

        for (unsigned int j = 0; j < toErase.size(); ++j) {
            es->removeEvent(toErase[j]);
        }
    }

    setCurrentSelection(es);
}

void EditView::slotExtendSelectionForward()
{
    slotExtendSelectionForward(false);
}

void EditView::slotExtendSelectionForwardBar()
{
    slotExtendSelectionForward(true);
}

void EditView::slotExtendSelectionForward(bool bar)
{
    // If there is no current selection, or the selection is entirely
    // to the left of the cursor, move the cursor right and add to the
    // selection

    timeT oldTime = getInsertionTime();
    if (bar)
        slotJumpForward();
    else
        slotStepForward();
    timeT newTime = getInsertionTime();

    Staff *staff = getCurrentStaff();
    if (!staff)
        return ;
    Segment *segment = &staff->getSegment();
    ViewElementList *vel = staff->getViewElementList();

    EventSelection *es = new EventSelection(*segment);
    if (m_currentEventSelection &&
            &m_currentEventSelection->getSegment() == segment)
        es->addFromSelection(m_currentEventSelection);

    if (!m_currentEventSelection ||
            &m_currentEventSelection->getSegment() != segment ||
            m_currentEventSelection->getSegmentEvents().size() == 0 ||
            m_currentEventSelection->getEndTime() <= oldTime) {

        ViewElementList::iterator extendFrom = vel->findTime(oldTime);

        while (extendFrom != vel->end() &&
                (*extendFrom)->getViewAbsoluteTime() < newTime) {
            if ((*extendFrom)->event()->isa(Note::EventType)) {
                es->addEvent((*extendFrom)->event());
            }
            ++extendFrom;
        }

    } else { // remove an event

        EventSelection::eventcontainer::iterator i =
            es->getSegmentEvents().begin();

        std::vector<Event *> toErase;

        while (i != es->getSegmentEvents().end() &&
                (*i)->getAbsoluteTime() < newTime) {
            toErase.push_back(*i);
            ++i;
        }

        for (unsigned int j = 0; j < toErase.size(); ++j) {
            es->removeEvent(toErase[j]);
        }
    }

    setCurrentSelection(es);
}

void
EditView::setupActions()
{
    createInsertPitchActionMenu();

    //
    // Tempo and time signature changes
    //
    TQString pixmapDir = TDEGlobal::dirs()->findResource("appdata", "pixmaps/");
    TQCanvasPixmap pixmap(pixmapDir + "/toolbar/event-insert-tempo.png");
    TQIconSet icon = TQIconSet(pixmap);
    new TDEAction(AddTempoChangeCommand::getGlobalName(),
		icon, 0,
		this, TQ_SLOT(slotAddTempo()),
		actionCollection(), "add_tempo");

    pixmap.load(pixmapDir + "/toolbar/event-insert-timesig.png");
    icon = TQIconSet(pixmap);
    new TDEAction(AddTimeSignatureCommand::getGlobalName(),
		icon, 0,
		this, TQ_SLOT(slotAddTimeSignature()),
		actionCollection(), "add_time_signature");

    //
    // Transforms
    //
    new TDEAction(i18n("&Halve Durations"), Key_H + CTRL, this,
                TQ_SLOT(slotHalveDurations()), actionCollection(),
                "halve_durations");

    new TDEAction(i18n("&Double Durations"), Key_H + CTRL + SHIFT, this,
                TQ_SLOT(slotDoubleDurations()), actionCollection(),
                "double_durations");

    new TDEAction(RescaleCommand::getGlobalName(), 0, this,
                TQ_SLOT(slotRescale()), actionCollection(),
                "rescale");

    new TDEAction(TransposeCommand::getGlobalName(1), 0,
                Key_Up, this,
                TQ_SLOT(slotTransposeUp()), actionCollection(),
                "transpose_up");

    new TDEAction(TransposeCommand::getGlobalName(12), 0,
                Key_Up + CTRL, this,
                TQ_SLOT(slotTransposeUpOctave()), actionCollection(),
                "transpose_up_octave");

    new TDEAction(TransposeCommand::getGlobalName( -1), 0,
                Key_Down, this,
                TQ_SLOT(slotTransposeDown()), actionCollection(),
                "transpose_down");

    new TDEAction(TransposeCommand::getGlobalName( -12), 0,
                Key_Down + CTRL, this,
                TQ_SLOT(slotTransposeDownOctave()), actionCollection(),
                "transpose_down_octave");

    new TDEAction(TransposeCommand::getGlobalName(0), 0, this,
                TQ_SLOT(slotTranspose()), actionCollection(),
                "general_transpose");

    new TDEAction(TransposeCommand::getDiatonicGlobalName(0,0), 0, this,
                TQ_SLOT(slotDiatonicTranspose()), actionCollection(),
                "general_diatonic_transpose");

    new TDEAction(InvertCommand::getGlobalName(0), 0, this,
                TQ_SLOT(slotInvert()), actionCollection(),
                "invert");

    new TDEAction(RetrogradeCommand::getGlobalName(0), 0, this,
                TQ_SLOT(slotRetrograde()), actionCollection(),
                "retrograde");

    new TDEAction(RetrogradeInvertCommand::getGlobalName(0), 0, this,
                TQ_SLOT(slotRetrogradeInvert()), actionCollection(),
                "retrograde_invert");

    new TDEAction(i18n("Jog &Left"), Key_Left + ALT, this,
                TQ_SLOT(slotJogLeft()), actionCollection(),
                "jog_left");

    new TDEAction(i18n("Jog &Right"), Key_Right + ALT, this,
                TQ_SLOT(slotJogRight()), actionCollection(),
                "jog_right");

    // Control rulers
    //
    new TDEAction(i18n("Show Velocity Property Ruler"), 0, this,
                TQ_SLOT(slotShowVelocityControlRuler()), actionCollection(),
                "show_velocity_control_ruler");

    /*
    new TDEAction(i18n("Show Controllers Events Ruler"), 0, this,
                TQ_SLOT(slotShowControllerEventsRuler()), actionCollection(),
                "show_controller_events_ruler");
                */

    // Disabled for now
    //
    //     new TDEAction(i18n("Add Control Ruler..."), 0, this,
    //                 TQ_SLOT(slotShowPropertyControlRuler()), actionCollection(),
    //                 "add_control_ruler");

    //
    // Control Ruler context menu
    //
    new TDEAction(i18n("Insert item"), 0, this,
                TQ_SLOT(slotInsertControlRulerItem()), actionCollection(),
                "insert_control_ruler_item");

    // This was on Key_Delete, but that conflicts with existing Delete commands
    // on individual edit views
    new TDEAction(i18n("Erase selected items"), 0, this,
                TQ_SLOT(slotEraseControlRulerItem()), actionCollection(),
                "erase_control_ruler_item");

    new TDEAction(i18n("Clear ruler"), 0, this,
                TQ_SLOT(slotClearControlRulerItem()), actionCollection(),
                "clear_control_ruler_item");

    new TDEAction(i18n("Insert line of controllers"), 0, this,
                TQ_SLOT(slotStartControlLineItem()), actionCollection(),
                "start_control_line_item");

    new TDEAction(i18n("Flip forward"), Key_BracketRight, this,
                TQ_SLOT(slotFlipForwards()), actionCollection(),
                "flip_control_events_forward");

    new TDEAction(i18n("Flip backwards"), Key_BracketLeft, this,
                TQ_SLOT(slotFlipBackwards()), actionCollection(),
                "flip_control_events_back");

    new TDEAction(i18n("Draw property line"), 0, this,
                TQ_SLOT(slotDrawPropertyLine()), actionCollection(),
                "draw_property_line");

    new TDEAction(i18n("Select all property values"), 0, this,
                TQ_SLOT(slotSelectAllProperties()), actionCollection(),
                "select_all_properties");
}

void
EditView::setupAddControlRulerMenu()
{
    RG_DEBUG << "EditView::setupAddControlRulerMenu" << endl;

    TQPopupMenu* addControlRulerMenu = dynamic_cast<TQPopupMenu*>
                                      (factory()->container("add_control_ruler", this));

    if (addControlRulerMenu) {

        addControlRulerMenu->clear();

        //!!! problem here with notation view -- current segment can
        // change after construction, but this function isn't used again

        Controllable *c =
            dynamic_cast<MidiDevice *>(getCurrentDevice());
        if (!c) {
            c = dynamic_cast<SoftSynthDevice *>(getCurrentDevice());
            if (!c)
                return ;
        }

        const ControlList &list = c->getControlParameters();

        int i = 0;
        TQString itemStr;

        for (ControlList::const_iterator it = list.begin();
                it != list.end(); ++it) {
            if (it->getType() == Controller::EventType) {
                TQString hexValue;
                hexValue.sprintf("(0x%x)", it->getControllerValue());

                itemStr = i18n("%1 Controller %2 %3").arg(strtoqstr(it->getName()))
                          .arg(it->getControllerValue())
                          .arg(hexValue);

            } else if (it->getType() == PitchBend::EventType)
                itemStr = i18n("Pitch Bend");
            else
                itemStr = i18n("Unsupported Event Type");

            addControlRulerMenu->insertItem(itemStr, i++);
        }

        connect(addControlRulerMenu, TQ_SIGNAL(activated(int)),
                TQ_SLOT(slotAddControlRuler(int)));
    }

}

bool
EditView::setupControllerTabs()
{
    bool have = false;

    // Setup control rulers the Segment already has some stored against it.
    //
    Segment *segment = getCurrentSegment();
    Segment::EventRulerList list = segment->getEventRulerList();

    RG_DEBUG << "EditView::setupControllerTabs - got " << list.size() << " EventRulers" << endl;

    RG_DEBUG << "Segment view features: " << segment->getViewFeatures() << endl;
    if (segment->getViewFeatures() & FeatureShowVelocity) {
        showPropertyControlRuler(BaseProperties::VELOCITY);
        have = true;
    }

    if (list.size()) {
        Controllable *c =
            dynamic_cast<MidiDevice *>(getCurrentDevice());
        if (!c) {
            c = dynamic_cast<SoftSynthDevice *>(getCurrentDevice());
            if (!c)
                return have;
        }

        have = true;

        Segment::EventRulerListIterator it;

        for (it = list.begin(); it != list.end(); ++it) {
            // Get ControlParameter object from controller value
            //
            const ControlParameter *controlParameter =
                c->getControlParameter((*it)->m_type,
                                       MidiByte((*it)->m_controllerValue));

            RG_DEBUG << "EditView::setupControllerTabs - "
            << "Control Parameter type = " << (*it)->m_type << endl;

            if (controlParameter) {
                ControllerEventsRuler* controlRuler = makeControllerEventRuler(controlParameter);
                addControlRuler(controlRuler);
                RG_DEBUG << "EditView::setupControllerTabs - adding Ruler" << endl;
            }
        }

        if (!m_controlRulers->isVisible())
            m_controlRulers->show();

        updateBottomWidgetGeometry();
    }

    return have;
}

void
EditView::slotAddControlRuler(int controller)
{
    RG_DEBUG << "EditView::slotAddControlRuler - item = "
    << controller << endl;

    Controllable *c =
        dynamic_cast<MidiDevice *>(getCurrentDevice());
    if (!c) {
        c = dynamic_cast<SoftSynthDevice *>(getCurrentDevice());
        if (!c)
            return ;
    }

    const ControlList &list = c->getControlParameters();
    ControlParameter control = list[controller];

    int index = 0;

    ControlRuler* existingRuler = findRuler(control, index);

    if (existingRuler) {

        m_controlRulers->setCurrentPage(index);

    } else {

        // Create control ruler to a specific controller.  This duplicates
        // the control parameter in the supplied pointer.
        ControllerEventsRuler* controlRuler = makeControllerEventRuler(&control);

        addControlRuler(controlRuler);
    }

    if (!m_controlRulers->isVisible()) {
        m_controlRulers->show();
    }

    updateBottomWidgetGeometry();

    // Add the controller to the segment so the views can
    // remember what we've opened against it.
    //
    Staff *staff = getCurrentStaff();
    staff->getSegment().addEventRuler(control.getType(), control.getControllerValue());

    getDocument()->slotDocumentModified();
}

void EditView::slotRemoveControlRuler(TQWidget* w)
{
    ControllerEventsRuler* ruler = dynamic_cast<ControllerEventsRuler*>(w);

    if (ruler) {
        ControlParameter *controller = ruler->getControlParameter();

        // remove the control parameter from the "showing controllers" list on the segment
        //
        if (controller) {
            Staff *staff = getCurrentStaff();
            bool value = staff->getSegment().
                         deleteEventRuler(controller->getType(), controller->getControllerValue());

            if (value)
                RG_DEBUG << "slotRemoveControlRuler : removed controller from segment\n";
            else
                RG_DEBUG << "slotRemoveControlRuler : couldn't remove controller from segment - "
                << int(controller->getControllerValue())
                << endl;

        }
    } else { // else it's probably a velocity ruler
        PropertyControlRuler *propertyRuler = dynamic_cast<PropertyControlRuler*>(w);

        if (propertyRuler) {
            Segment &seg = getCurrentStaff()->getSegment();
            seg.setViewFeatures(0); // for the moment we only have one view feature so
            // we can just blank it out

            RG_DEBUG << "slotRemoveControlRuler : removed velocity ruler" << endl;
        }
    }

    delete w;

    if (m_controlRulers->count() == 0) {
        m_controlRulers->hide();
        updateBottomWidgetGeometry();
    }

    getDocument()->slotDocumentModified();
}

void
EditView::createInsertPitchActionMenu()
{
    TQString notePitchNames[] = {
                                   i18n("I"), i18n("II"), i18n("III"), i18n("IV"),
                                   i18n("V"), i18n("VI"), i18n("VII"), i18n("VIII")
                               };
    TQString flat = i18n("%1 flat");
    TQString sharp = i18n("%1 sharp");

    const Key notePitchKeys[3][7] = {
                                        {
                                            Key_A, Key_S, Key_D, Key_F, Key_J, Key_K, Key_L,
                                        },
                                        {
                                            Key_Q, Key_W, Key_E, Key_R, Key_U, Key_I, Key_O,
                                        },
                                        {
                                            Key_Z, Key_X, Key_C, Key_V, Key_B, Key_N, Key_M,
                                        },
                                    };

    TDEActionMenu *insertPitchActionMenu =
        new TDEActionMenu(i18n("&Insert Note"), this, "insert_note_actionmenu");

    for (int octave = 0; octave <= 2; ++octave) {

        TDEActionMenu *menu = insertPitchActionMenu;
        if (octave == 1) {
            menu = new TDEActionMenu(i18n("&Upper Octave"), this,
                                   "insert_note_actionmenu_upper_octave");
            insertPitchActionMenu->insert(new TDEActionSeparator(this));
            insertPitchActionMenu->insert(menu);
        } else if (octave == 2) {
            menu = new TDEActionMenu(i18n("&Lower Octave"), this,
                                   "insert_note_actionmenu_lower_octave");
            insertPitchActionMenu->insert(menu);
        }

        for (unsigned int i = 0; i < 7; ++i) {

            TDEAction *insertPitchAction = 0;

            TQString octaveSuffix;
            if (octave == 1)
                octaveSuffix = "_high";
            else if (octave == 2)
                octaveSuffix = "_low";

            // do and fa lack a flat

            if (i != 0 && i != 3) {

                insertPitchAction =
                    new TDEAction
                    (flat.arg(notePitchNames[i]),
                     CTRL + SHIFT + notePitchKeys[octave][i],
                     this, TQ_SLOT(slotInsertNoteFromAction()), actionCollection(),
                     TQString("insert_%1_flat%2").arg(i).arg(octaveSuffix).ascii());

                menu->insert(insertPitchAction);
            }

            insertPitchAction =
                new TDEAction
                (notePitchNames[i],
                 notePitchKeys[octave][i],
                 this, TQ_SLOT(slotInsertNoteFromAction()), actionCollection(),
                 TQString("insert_%1%2").arg(i).arg(octaveSuffix).ascii());

            menu->insert(insertPitchAction);

            // and mi and ti lack a sharp

            if (i != 2 && i != 6) {

                insertPitchAction =
                    new TDEAction
                    (sharp.arg(notePitchNames[i]),
                     SHIFT + notePitchKeys[octave][i],
                     this, TQ_SLOT(slotInsertNoteFromAction()), actionCollection(),
                     TQString("insert_%1_sharp%2").arg(i).arg(octaveSuffix).ascii());

                menu->insert(insertPitchAction);
            }

            if (i < 6)
                menu->insert(new TDEActionSeparator(this));
        }
    }

    actionCollection()->insert(insertPitchActionMenu);
}

int
EditView::getPitchFromNoteInsertAction(TQString name,
                                       Accidental &accidental,
                                       const Clef &clef,
                                       const ::Rosegarden::Key &key)
{
    using namespace Accidentals;

    accidental = NoAccidental;

    if (name.left(7) == "insert_") {

        name = name.right(name.length() - 7);

        int modify = 0;
        int octave = 0;

        if (name.right(5) == "_high") {

            octave = 1;
            name = name.left(name.length() - 5);

        } else if (name.right(4) == "_low") {

            octave = -1;
            name = name.left(name.length() - 4);
        }

        if (name.right(6) == "_sharp") {

            modify = 1;
            accidental = Sharp;
            name = name.left(name.length() - 6);

        } else if (name.right(5) == "_flat") {

            modify = -1;
            accidental = Flat;
            name = name.left(name.length() - 5);
        }

        int scalePitch = name.toInt();

        if (scalePitch < 0 || scalePitch > 7) {
            NOTATION_DEBUG << "EditView::getPitchFromNoteInsertAction: pitch "
            << scalePitch << " out of range, using 0" << endl;
            scalePitch = 0;
        }

        Pitch pitch
        (scalePitch, 4 + octave + clef.getOctave(), key, accidental);
        return pitch.getPerformancePitch();

    } else {

        throw Exception("Not an insert action",
                        __FILE__, __LINE__);
    }
}

void EditView::slotAddTempo()
{
    timeT insertionTime = getInsertionTime();

    TempoDialog tempoDlg(this, getDocument());

    connect(&tempoDlg,
            TQ_SIGNAL(changeTempo(timeT,
                               tempoT,
                               tempoT,
                               TempoDialog::TempoDialogAction)),
            this,
            TQ_SIGNAL(changeTempo(timeT,
                               tempoT,
                               tempoT,
                               TempoDialog::TempoDialogAction)));

    tempoDlg.setTempoPosition(insertionTime);
    tempoDlg.exec();
}

void EditView::slotAddTimeSignature()
{
    Segment *segment = getCurrentSegment();
    if (!segment)
        return ;
    Composition *composition = segment->getComposition();
    timeT insertionTime = getInsertionTime();

    TimeSignatureDialog *dialog = 0;
    int timeSigNo = composition->getTimeSignatureNumberAt(insertionTime);

    if (timeSigNo >= 0) {

        dialog = new TimeSignatureDialog
                 (this, composition, insertionTime,
                  composition->getTimeSignatureAt(insertionTime));

    } else {

        timeT endTime = composition->getDuration();
        if (composition->getTimeSignatureCount() > 0) {
            endTime = composition->getTimeSignatureChange(0).first;
        }

        CompositionTimeSliceAdapter adapter
        (composition, insertionTime, endTime);
        AnalysisHelper helper;
        TimeSignature timeSig = helper.guessTimeSignature(adapter);

        dialog = new TimeSignatureDialog
                 (this, composition, insertionTime, timeSig, false,
                  i18n("Estimated time signature shown"));
    }

    if (dialog->exec() == TQDialog::Accepted) {

        insertionTime = dialog->getTime();

        if (dialog->shouldNormalizeRests()) {

            addCommandToHistory(new AddTimeSignatureAndNormalizeCommand
                                (composition, insertionTime,
                                 dialog->getTimeSignature()));

        } else {

            addCommandToHistory(new AddTimeSignatureCommand
                                (composition, insertionTime,
                                 dialog->getTimeSignature()));
        }
    }

    delete dialog;
}

void EditView::showPropertyControlRuler(PropertyName propertyName)
{
    int index = 0;

    ControlRuler* existingRuler = findRuler(propertyName, index);

    if (existingRuler) {

        m_controlRulers->setCurrentPage(index);

    } else {

        PropertyControlRuler* controlRuler = makePropertyControlRuler(propertyName);
        addControlRuler(controlRuler);
    }

    if (!m_controlRulers->isVisible()) {
        m_controlRulers->show();
    }

    updateBottomWidgetGeometry();
}

void EditView::slotShowVelocityControlRuler()
{
    showPropertyControlRuler(BaseProperties::VELOCITY);
    Segment &seg = getCurrentStaff()->getSegment();
    seg.setViewFeatures(seg.getViewFeatures() | FeatureShowVelocity);
    getDocument()->slotDocumentModified();
}

void EditView::slotShowControllerEventsRuler()
{

    //     int index = 0;

    //     ControlRuler* existingRuler = findRuler(propertyName, index);

    //     if (existingRuler) {

    //         m_controlRulers->setCurrentPage(index);

    //     } else {

    //         ControllerEventsRuler* controlRuler = makeControllerEventRuler();
    //         addControlRuler(controlRuler);
    //     }

    //     if (!m_controlRulers->isVisible()) {
    //         m_controlRulers->show();
    //     }

    //     updateBottomWidgetGeometry();
}

void EditView::slotShowPropertyControlRuler()
{
    /*
        KDialogBase propChooserDialog(this, "propertychooserdialog", true, i18n("Select event property"),
                                      KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok);
        
        TDEListBox* propList = new TDEListBox(propChooserDialog.makeVBoxMainWidget());
        new TQListBoxRGProperty(propList, BaseProperties::VELOCITY.c_str());
     
        int rc = propChooserDialog.exec();
        if (rc == TQDialog::Accepted) {
            // fix for KDE 3.0
            //TQListBoxRGProperty* item = dynamic_cast<TQListBoxRGProperty*>(propList->selectedItem());
            TQListBoxRGProperty* item = dynamic_cast<TQListBoxRGProperty*>
                (propList->item(propList->currentItem()));
     
            if (item) {
                PropertyName property = item->getPropertyName();
                showPropertyControlRuler(property);
            }
        }
    */
}

void
EditView::slotInsertControlRulerItem()
{
    ControllerEventsRuler* ruler = dynamic_cast<ControllerEventsRuler*>(getCurrentControlRuler());
    if (ruler)
        ruler->insertControllerEvent();
}

void
EditView::slotEraseControlRulerItem()
{
    ControllerEventsRuler* ruler = dynamic_cast<ControllerEventsRuler*>(getCurrentControlRuler());
    if (ruler)
        ruler->eraseControllerEvent();
}

void
EditView::slotStartControlLineItem()
{
    ControllerEventsRuler* ruler = dynamic_cast<ControllerEventsRuler*>(getCurrentControlRuler());
    if (ruler)
        ruler->startControlLine();
}

void
EditView::slotDrawPropertyLine()
{
    int index = 0;
    PropertyControlRuler* ruler = dynamic_cast<PropertyControlRuler*>
                                  (findRuler(BaseProperties::VELOCITY, index));

    if (ruler)
        ruler->startPropertyLine();
}

void
EditView::slotSelectAllProperties()
{
    int index = 0;
    PropertyControlRuler* ruler = dynamic_cast<PropertyControlRuler*>
                                  (findRuler(BaseProperties::VELOCITY, index));

    if (ruler)
        ruler->selectAllProperties();
}

void
EditView::slotClearControlRulerItem()
{
    ControllerEventsRuler* ruler = dynamic_cast<ControllerEventsRuler*>(getCurrentControlRuler());
    if (ruler)
        ruler->clearControllerEvents();
}

void
EditView::slotHalveDurations()
{
    if (!m_currentEventSelection)
        return ;

    KTmpStatusMsg msg(i18n("Halving durations..."), this);

    addCommandToHistory(
        new RescaleCommand(*m_currentEventSelection,
                           m_currentEventSelection->getTotalDuration() / 2,
                           false));
}

void
EditView::slotDoubleDurations()
{
    if (!m_currentEventSelection)
        return ;

    KTmpStatusMsg msg(i18n("Doubling durations..."), this);

    addCommandToHistory(
        new RescaleCommand(*m_currentEventSelection,
                           m_currentEventSelection->getTotalDuration() * 2,
                           false));
}

void
EditView::slotRescale()
{
    if (!m_currentEventSelection)
        return ;

    RescaleDialog dialog
    (this,
     &getDocument()->getComposition(),
     m_currentEventSelection->getStartTime(),
     m_currentEventSelection->getEndTime() -
     m_currentEventSelection->getStartTime(),
     true,
     true);

    if (dialog.exec() == TQDialog::Accepted) {
        KTmpStatusMsg msg(i18n("Rescaling..."), this);
        addCommandToHistory(new RescaleCommand
                            (*m_currentEventSelection,
                             dialog.getNewDuration(),
                             dialog.shouldCloseGap()));
    }
}

void EditView::slotTranspose()
{
    if (!m_currentEventSelection)
        return ;

    m_config->setGroup(EditViewConfigGroup);

    int dialogDefault = m_config->readNumEntry("lasttransposition", 0);

    bool ok = false;
    int semitones = TQInputDialog::getInteger
                    (i18n("Transpose"),
                     i18n("By number of semitones: "),
                     dialogDefault, -127, 127, 1, &ok, this);
    if (!ok || semitones == 0) return;

    m_config->setGroup(EditViewConfigGroup);
    m_config->writeEntry("lasttransposition", semitones);

    KTmpStatusMsg msg(i18n("Transposing..."), this);
    addCommandToHistory(new TransposeCommand
                        (semitones, *m_currentEventSelection));
}

void EditView::slotDiatonicTranspose()
{
    if (!m_currentEventSelection)
        return ;

    m_config->setGroup(EditViewConfigGroup);

    IntervalDialog intervalDialog(this);
    int ok = intervalDialog.exec();
	//int dialogDefault = m_config->readNumEntry("lasttransposition", 0);
    int semitones = intervalDialog.getChromaticDistance();
    int steps = intervalDialog.getDiatonicDistance();

    if (!ok || (semitones == 0 && steps == 0)) return;

    m_config->setGroup(EditViewConfigGroup);

    KTmpStatusMsg msg(i18n("Transposing..."), this);
    if (intervalDialog.getChangeKey())
    {
		std::cout << "Transposing changing keys is not currently supported on selections" << std::endl;
    }
    else
    {
	// Transpose within key
		//std::cout << "Transposing semitones, steps: " << semitones << ", " << steps << std::endl;
		addCommandToHistory(new TransposeCommand
                        (semitones, steps, *m_currentEventSelection));
    }
}

void EditView::slotTransposeUp()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Transposing up one semitone..."), this);

    addCommandToHistory(new TransposeCommand(1, *m_currentEventSelection));
}

void EditView::slotTransposeUpOctave()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Transposing up one octave..."), this);

    addCommandToHistory(new TransposeCommand(12, *m_currentEventSelection));
}

void EditView::slotTransposeDown()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Transposing down one semitone..."), this);

    addCommandToHistory(new TransposeCommand( -1, *m_currentEventSelection));
}

void EditView::slotTransposeDownOctave()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Transposing down one octave..."), this);

    addCommandToHistory(new TransposeCommand( -12, *m_currentEventSelection));
}

void EditView::slotInvert()
{
    if (!m_currentEventSelection)
        return ;

    int semitones = 0;

    KTmpStatusMsg msg(i18n("Inverting..."), this);
    addCommandToHistory(new InvertCommand
                        (semitones, *m_currentEventSelection));
}

void EditView::slotRetrograde()
{
    if (!m_currentEventSelection)
        return ;

    int semitones = 0;

    KTmpStatusMsg msg(i18n("Retrograding..."), this);
    addCommandToHistory(new RetrogradeCommand
                        (semitones, *m_currentEventSelection));
}

void EditView::slotRetrogradeInvert()
{
    if (!m_currentEventSelection)
        return ;

    int semitones = 0;

    KTmpStatusMsg msg(i18n("Retrograde inverting..."), this);
    addCommandToHistory(new RetrogradeInvertCommand
                        (semitones, *m_currentEventSelection));
}

void EditView::slotJogLeft()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Jogging left..."), this);

    RG_DEBUG << "EditView::slotJogLeft" << endl;

    addCommandToHistory(
        new MoveCommand(*getCurrentSegment(),
                        -Note(Note::Demisemiquaver).getDuration(),
                        false,  // don't use notation timings
                        *m_currentEventSelection));
}

void EditView::slotJogRight()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Jogging right..."), this);

    RG_DEBUG << "EditView::slotJogRight" << endl;

    addCommandToHistory(
        new MoveCommand(*getCurrentSegment(),
                        Note(Note::Demisemiquaver).getDuration(),
                        false,  // don't use notation timings
                        *m_currentEventSelection));
}

void
EditView::slotFlipForwards()
{
    RG_DEBUG << "EditView::slotFlipForwards" << endl;
    ControlRuler* ruler = getCurrentControlRuler();
    if (ruler) ruler->flipForwards();
}

void
EditView::slotFlipBackwards()
{
    RG_DEBUG << "EditView::slotFlipBackwards" << endl;
    ControlRuler* ruler = getCurrentControlRuler();
    if (ruler) ruler->flipBackwards();
}

ControlRuler* EditView::getCurrentControlRuler()
{
    return dynamic_cast<ControlRuler*>(m_controlRulers->currentPage());
}

ControlRuler* EditView::findRuler(PropertyName propertyName, int &index)
{
    for(index = 0; index < m_controlRulers->count(); ++index) {
        PropertyControlRuler* ruler = dynamic_cast<PropertyControlRuler*>(m_controlRulers->page(index));
        if (ruler && ruler->getPropertyName() == propertyName) return ruler;
    }

    return 0;
}

ControlRuler* EditView::findRuler(const ControlParameter& controller, int &index)
{
    for(index = 0; index < m_controlRulers->count(); ++index) {
        ControllerEventsRuler* ruler = dynamic_cast<ControllerEventsRuler*>(m_controlRulers->page(index));
        if (ruler && *(ruler->getControlParameter()) == controller) return ruler;
    }

    return 0;
}

PropertyControlRuler* EditView::makePropertyControlRuler(PropertyName propertyName)
{
    TQCanvas* controlRulerCanvas = new TQCanvas(this);
    TQSize viewSize = getViewSize();
    controlRulerCanvas->resize(viewSize.width(), ControlRuler::DefaultRulerHeight); // TODO - keep it in sync with main canvas size

//     TQCanvas* controlRulerCanvas = ControlRulerCanvasRepository::getCanvas(getCurrentSegment(), propertyName,
//                                                                           getViewSize());

    PropertyControlRuler* controlRuler = new PropertyControlRuler
    (propertyName, getCurrentStaff(), getHLayout(), this,
     controlRulerCanvas, m_controlRulers);

    controlRuler->setMainHorizontalScrollBar(m_canvasView->horizontalScrollBar());

    return controlRuler;
}

ControllerEventsRuler* EditView::makeControllerEventRuler(const ControlParameter *controller)
{
    TQCanvas* controlRulerCanvas = new TQCanvas(this);
    TQSize viewSize = getViewSize();
    controlRulerCanvas->resize(viewSize.width(), ControlRuler::DefaultRulerHeight); // TODO - keep it in sync with main canvas size
//     TQCanvas* controlRulerCanvas = ControlRulerCanvasRepository::getCanvas(getCurrentSegment(), controller,
//                                                                           getViewSize());
    

    ControllerEventsRuler* controlRuler = new ControllerEventsRuler
    (getCurrentSegment(), getHLayout(), this,
     controlRulerCanvas, m_controlRulers, controller);

    controlRuler->setMainHorizontalScrollBar(m_canvasView->horizontalScrollBar());

    return controlRuler;
}

RosegardenCanvasView* EditView::getCanvasView()
{
    return m_canvasView;
}

}
#include "EditView.moc"
