/*
    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 "NotationView.h"
#include <list>
#include <tqlayout.h>
#include "misc/Debug.h"
#include <tdeapplication.h>

#include "gui/editors/segment/TrackEditor.h"
#include "gui/editors/segment/TrackButtons.h"
#include "base/BaseProperties.h"
#include <tdelocale.h>
#include <kstandarddirs.h>
#include "misc/Strings.h"
#include "base/AnalysisTypes.h"
#include "base/Clipboard.h"
#include "base/Composition.h"
#include "base/CompositionTimeSliceAdapter.h"
#include "base/Configuration.h"
#include "base/Device.h"
#include "base/Event.h"
#include "base/Exception.h"
#include "base/Instrument.h"
#include "base/MidiDevice.h"
#include "base/MidiTypes.h"
#include "base/NotationTypes.h"
#include "base/Profiler.h"
#include "base/PropertyName.h"
#include "base/NotationQuantizer.h"
#include "base/RealTime.h"
#include "base/RulerScale.h"
#include "base/Segment.h"
#include "base/Selection.h"
#include "base/Staff.h"
#include "base/Studio.h"
#include "base/Track.h"
#include "ClefInserter.h"
#include "commands/edit/AddDotCommand.h"
#include "commands/edit/ClearTriggersCommand.h"
#include "commands/edit/CollapseNotesCommand.h"
#include "commands/edit/CopyCommand.h"
#include "commands/edit/CutAndCloseCommand.h"
#include "commands/edit/CutCommand.h"
#include "commands/edit/EraseCommand.h"
#include "commands/edit/EventEditCommand.h"
#include "commands/edit/EventQuantizeCommand.h"
#include "commands/edit/InsertTriggerNoteCommand.h"
#include "commands/edit/PasteEventsCommand.h"
#include "commands/edit/SetLyricsCommand.h"
#include "commands/edit/SetNoteTypeCommand.h"
#include "commands/edit/SetTriggerCommand.h"
#include "commands/edit/TransposeCommand.h"
#include "commands/notation/AddFingeringMarkCommand.h"
#include "commands/notation/AddIndicationCommand.h"
#include "commands/notation/AddMarkCommand.h"
#include "commands/notation/AddSlashesCommand.h"
#include "commands/notation/AddTextMarkCommand.h"
#include "commands/notation/AutoBeamCommand.h"
#include "commands/notation/BeamCommand.h"
#include "commands/notation/BreakCommand.h"
#include "commands/notation/ChangeSlurPositionCommand.h"
#include "commands/notation/ChangeTiePositionCommand.h"
#include "commands/notation/ChangeStemsCommand.h"
#include "commands/notation/ChangeStyleCommand.h"
#include "commands/notation/ClefInsertionCommand.h"
#include "commands/notation/CollapseRestsCommand.h"
#include "commands/notation/DeCounterpointCommand.h"
#include "commands/notation/EraseEventCommand.h"
#include "commands/notation/FixNotationQuantizeCommand.h"
#include "commands/notation/IncrementDisplacementsCommand.h"
#include "commands/notation/InterpretCommand.h"
#include "commands/notation/KeyInsertionCommand.h"
#include "commands/notation/MakeAccidentalsCautionaryCommand.h"
#include "commands/notation/MakeChordCommand.h"
#include "commands/notation/MakeNotesViableCommand.h"
#include "commands/notation/MultiKeyInsertionCommand.h"
#include "commands/notation/NormalizeRestsCommand.h"
#include "commands/notation/RemoveFingeringMarksCommand.h"
#include "commands/notation/RemoveMarksCommand.h"
#include "commands/notation/RemoveNotationQuantizeCommand.h"
#include "commands/notation/ResetDisplacementsCommand.h"
#include "commands/notation/RespellCommand.h"
#include "commands/notation/RestoreSlursCommand.h"
#include "commands/notation/RestoreTiesCommand.h"
#include "commands/notation/RestoreStemsCommand.h"
#include "commands/notation/SetVisibilityCommand.h"
#include "commands/notation/SustainInsertionCommand.h"
#include "commands/notation/TextInsertionCommand.h"
#include "commands/notation/TieNotesCommand.h"
#include "commands/notation/TupletCommand.h"
#include "commands/notation/UntieNotesCommand.h"
#include "commands/notation/UnTupletCommand.h"
#include "commands/segment/PasteToTriggerSegmentCommand.h"
#include "commands/segment/SegmentSyncCommand.h"
#include "commands/segment/SegmentTransposeCommand.h"
#include "commands/segment/RenameTrackCommand.h"
#include "document/RosegardenGUIDoc.h"
#include "document/ConfigGroups.h"
#include "document/io/LilyPondExporter.h"
#include "GuitarChordInserter.h"
#include "gui/application/SetWaitCursor.h"
#include "gui/application/RosegardenGUIView.h"
#include "gui/dialogs/ClefDialog.h"
#include "gui/dialogs/EventEditDialog.h"
#include "gui/dialogs/InterpretDialog.h"
#include "gui/dialogs/IntervalDialog.h"
#include "gui/dialogs/KeySignatureDialog.h"
#include "gui/dialogs/LilyPondOptionsDialog.h"
#include "gui/dialogs/LyricEditDialog.h"
#include "gui/dialogs/MakeOrnamentDialog.h"
#include "gui/dialogs/PasteNotationDialog.h"
#include "gui/dialogs/QuantizeDialog.h"
#include "gui/dialogs/SimpleEventEditDialog.h"
#include "gui/dialogs/TextEventDialog.h"
#include "gui/dialogs/TupletDialog.h"
#include "gui/dialogs/UseOrnamentDialog.h"
#include "gui/rulers/StandardRuler.h"
#include "gui/general/ActiveItem.h"
#include "gui/general/ClefIndex.h"
#include "gui/general/EditViewBase.h"
#include "gui/general/EditView.h"
#include "gui/general/GUIPalette.h"
#include "gui/general/LinedStaff.h"
#include "gui/general/LinedStaffManager.h"
#include "gui/general/ProgressReporter.h"
#include "gui/general/PresetHandlerDialog.h"
#include "gui/general/RosegardenCanvasView.h"
#include "gui/kdeext/KTmpStatusMsg.h"
#include "gui/kdeext/QCanvasSimpleSprite.h"
#include "gui/rulers/ChordNameRuler.h"
#include "gui/rulers/RawNoteRuler.h"
#include "gui/rulers/TempoRuler.h"
#include "gui/rulers/LoopRuler.h"
#include "gui/studio/StudioControl.h"
#include "gui/dialogs/EventFilterDialog.h"
#include "gui/widgets/ProgressBar.h"
#include "gui/widgets/ProgressDialog.h"
#include "gui/widgets/ScrollBoxDialog.h"
#include "gui/widgets/ScrollBox.h"
#include "gui/widgets/QDeferScrollView.h"
#include "NotationCanvasView.h"
#include "NotationElement.h"
#include "NotationEraser.h"
#include "NotationHLayout.h"
#include "NotationProperties.h"
#include "NotationSelector.h"
#include "NotationStaff.h"
#include "NotationStrings.h"
#include "NotationToolBox.h"
#include "NotationVLayout.h"
#include "NoteFontFactory.h"
#include "NoteInserter.h"
#include "NotePixmapFactory.h"
#include "NoteStyleFactory.h"
#include "NoteStyle.h"
#include "RestInserter.h"
#include "sound/MappedEvent.h"
#include "TextInserter.h"
#include "HeadersGroup.h"
#include <tdeaction.h>
#include <kcombobox.h>
#include <tdeconfig.h>
#include <tdeglobal.h>
#include <klineeditdlg.h>
#include <tdemessagebox.h>
#include <kprinter.h>
#include <kprocess.h>
#include <kprogress.h>
#include <kstatusbar.h>
#include <kstdaction.h>
#include <tdetempfile.h>
#include <tdetoolbar.h>
#include <kxmlguiclient.h>
#include <tqbrush.h>
#include <tqcanvas.h>
#include <tqcursor.h>
#include <tqdialog.h>
#include <tqevent.h>
#include <tqfont.h>
#include <tqfontmetrics.h>
#include <tqhbox.h>
#include <tqiconset.h>
#include <tqlabel.h>
#include <tqobject.h>
#include <tqpaintdevicemetrics.h>
#include <tqpainter.h>
#include <tqpixmap.h>
#include <tqpoint.h>
#include <tqprinter.h>
#include <tqrect.h>
#include <tqregexp.h>
#include <tqsize.h>
#include <tqstring.h>
#include <tqtimer.h>
#include <tqwidget.h>
#include <tqvalidator.h>
#include <algorithm>
#include <tqpushbutton.h>
#include <tqtooltip.h>


namespace Rosegarden
{

class NoteActionData
{
public:
    NoteActionData();
    NoteActionData(const TQString& _title,
		   TQString _actionName,
		   TQString _pixmapName,
		   int _keycode,
		   bool _rest,
		   Note::Type _noteType,
		   int _dots);
    
    TQString title;
    TQString actionName;
    TQString pixmapName;
    int keycode;
    bool rest;
    Note::Type noteType;
    int dots;
};

NoteActionData::NoteActionData()
    : title(0),
      actionName(0),
      pixmapName(0),
      keycode(0),
      rest(false),
      noteType(0),
      dots(0)
{
}

NoteActionData::NoteActionData(const TQString& _title,
			       TQString _actionName,
			       TQString _pixmapName,
			       int _keycode,
			       bool _rest,
			       Note::Type _noteType,
			       int _dots)
    : title(_title),
      actionName(_actionName),
      pixmapName(_pixmapName),
      keycode(_keycode),
      rest(_rest),
      noteType(_noteType),
      dots(_dots)
{
}


class NoteChangeActionData
{
public:
    NoteChangeActionData();
    NoteChangeActionData(const TQString &_title,
			 TQString _actionName,
			 TQString _pixmapName,
			 int _keycode,
			 bool _notationOnly,
			 Note::Type _noteType);

    TQString title;
    TQString actionName;
    TQString pixmapName;
    int keycode;
    bool notationOnly;
    Note::Type noteType;
};

NoteChangeActionData::NoteChangeActionData()
    : title(0),
      actionName(0),
      pixmapName(0),
      keycode(0),
      notationOnly(false),
      noteType(0)
{
}

NoteChangeActionData::NoteChangeActionData(const TQString& _title,
					   TQString _actionName,
					   TQString _pixmapName,
					   int _keycode,
					   bool _notationOnly,
					   Note::Type _noteType)
    : title(_title),
      actionName(_actionName),
      pixmapName(_pixmapName),
      keycode(_keycode),
      notationOnly(_notationOnly),
      noteType(_noteType)
{
}


class MarkActionData
{
public:
    MarkActionData() :
	title(0),
	actionName(0),
	keycode(0) { }

    MarkActionData(const TQString &_title,
		   TQString _actionName,
		   int _keycode,
		   Mark _mark) :
	title(_title),
	actionName(_actionName),
	keycode(_keycode),
	mark(_mark) { }

    TQString title;
    TQString actionName;
    int keycode;
    Mark mark;
};


NotationView::NotationView(RosegardenGUIDoc *doc,
                           std::vector<Segment *> segments,
                           TQWidget *parent,
                           bool showProgressive) :
        EditView(doc, segments, 2, parent, "notationview"),
        m_properties(getViewLocalPropertyPrefix()),
        m_selectionCounter(0),
        m_insertModeLabel(0),
        m_annotationsLabel(0),
        m_lilyPondDirectivesLabel(0),
        m_progressBar(0),
        m_currentNotePixmap(0),
        m_hoveredOverNoteName(0),
        m_hoveredOverAbsoluteTime(0),
        m_currentStaff( -1),
        m_lastFinishingStaff( -1),
        m_title(0),
        m_subtitle(0),
        m_composer(0),
        m_copyright(0),
        m_insertionTime(0),
        m_deferredCursorMove(NoCursorMoveNeeded),
        m_lastNoteAction("crotchet"),
        m_fontName(NoteFontFactory::getDefaultFontName()),
        m_fontSize(NoteFontFactory::getDefaultSize(m_fontName)),
        m_pageMode(LinedStaff::LinearMode),
        m_leftGutter(20),
        m_notePixmapFactory(new NotePixmapFactory(m_fontName, m_fontSize)),
        m_hlayout(new NotationHLayout(&doc->getComposition(), m_notePixmapFactory,
                                      m_properties, this)),
        m_vlayout(new NotationVLayout(&doc->getComposition(), m_notePixmapFactory,
                                      m_properties, this)),
        m_chordNameRuler(0),
        m_tempoRuler(0),
        m_rawNoteRuler(0),
        m_annotationsVisible(false),
        m_lilyPondDirectivesVisible(false),
        m_selectDefaultNote(0),
        m_fontCombo(0),
        m_fontSizeCombo(0),
        m_spacingCombo(0),
        m_fontSizeActionMenu(0),
        m_pannerDialog(new ScrollBoxDialog(this, ScrollBox::FixHeight)),
        m_renderTimer(0),
        m_playTracking(true),
        m_progressDisplayer(PROGRESS_NONE),
        m_inhibitRefresh(true),
        m_ok(false),
        m_printMode(false),
        m_printSize(8), // set in positionStaffs
        m_showHeadersGroup(0),
        m_headersGroupView(0),
        m_headersGroup(0),
        m_headersTopFrame(0),
        m_showHeadersMenuEntry(0)
{
    initActionDataMaps(); // does something only the 1st time it's called

    m_toolBox = new NotationToolBox(this);

    assert(segments.size() > 0);
    NOTATION_DEBUG << "NotationView ctor" << endl;


    // Initialise the display-related defaults that will be needed
    // by both the actions and the layout toolbar

    m_config->setGroup(NotationViewConfigGroup);

    m_showHeadersGroup = m_config->readNumEntry("shownotationheader",
                                                HeadersGroup::DefaultShowMode);

    m_fontName = qstrtostr(m_config->readEntry
                           ("notefont",
                            strtoqstr(NoteFontFactory::getDefaultFontName())));

    try
    {
        (void)NoteFontFactory::getFont
        (m_fontName,
         NoteFontFactory::getDefaultSize(m_fontName));
    } catch (Exception e)
    {
        m_fontName = NoteFontFactory::getDefaultFontName();
    }

    m_fontSize = m_config->readUnsignedNumEntry
                 ((segments.size() > 1 ? "multistaffnotesize" : "singlestaffnotesize"),
                  NoteFontFactory::getDefaultSize(m_fontName));

    int defaultSpacing = m_config->readNumEntry("spacing", 100);
    m_hlayout->setSpacing(defaultSpacing);

    int defaultProportion = m_config->readNumEntry("proportion", 60);
    m_hlayout->setProportion(defaultProportion);

    delete m_notePixmapFactory;
    m_notePixmapFactory = new NotePixmapFactory(m_fontName, m_fontSize);
    m_hlayout->setNotePixmapFactory(m_notePixmapFactory);
    m_vlayout->setNotePixmapFactory(m_notePixmapFactory);

    setupActions();
    //     setupAddControlRulerMenu(); - too early for notation, moved to end of ctor.
    initLayoutToolbar();
    initStatusBar();

    setBackgroundMode(PaletteBase);

    TQCanvas *tCanvas = new TQCanvas(this);
    tCanvas->resize(width() * 2, height() * 2);

    setCanvasView(new NotationCanvasView(*this, tCanvas, getCentralWidget()));

    updateViewCaption();

    m_chordNameRuler = new ChordNameRuler
                       (m_hlayout, doc, segments, m_leftGutter, 20, getCentralWidget());
    addRuler(m_chordNameRuler);
    if (showProgressive)
        m_chordNameRuler->show();

    m_tempoRuler = new TempoRuler
                   (m_hlayout, doc, this, m_leftGutter, 24, false, getCentralWidget());
    addRuler(m_tempoRuler);
    m_tempoRuler->hide();
    static_cast<TempoRuler *>(m_tempoRuler)->connectSignals();

    m_rawNoteRuler = new RawNoteRuler
                     (m_hlayout, segments[0], m_leftGutter, 20, getCentralWidget());
    addRuler(m_rawNoteRuler);
    m_rawNoteRuler->show();

    // All toolbars should be created before this is called
    setAutoSaveSettings("NotationView", true);

    // All rulers must have been created before this is called,
    // or the program will crash
    readOptions();


    setBottomStandardRuler(new StandardRuler(getDocument(), m_hlayout, m_leftGutter, 25,
                                       true, getBottomWidget()));

    for (unsigned int i = 0; i < segments.size(); ++i)
    {
        m_staffs.push_back(new NotationStaff
                           (canvas(), segments[i], 0,  // snap
                            i, this,
                            m_fontName, m_fontSize));
    }


    // HeadersGroup ctor must not be called before m_staffs initialization
    m_headersGroupView = new QDeferScrollView(getCentralWidget());
    TQWidget * vport = m_headersGroupView->viewport();
    m_headersGroup = new HeadersGroup(vport, this, &doc->getComposition());
    m_headersGroupView->setVScrollBarMode(TQScrollView::AlwaysOff);
    m_headersGroupView->setHScrollBarMode(TQScrollView::AlwaysOff);
    m_headersGroupView->setFixedWidth(m_headersGroupView->contentsWidth());
    m_canvasView->setLeftFixedWidget(m_headersGroupView);

    // Add a close button just above the track headers.
    // The grid layout is only here to maintain the button in a
    // right place
    m_headersTopFrame = new TQFrame(getCentralWidget());
    TQGridLayout * headersTopGrid
        = new TQGridLayout(m_headersTopFrame, 2, 2);
    TQString pixmapDir = TDEGlobal::dirs()->findResource("appdata", "pixmaps/");
    TQCanvasPixmap pixmap(pixmapDir + "/misc/close.xpm");
    TQPushButton * hideHeadersButton
        = new TQPushButton(m_headersTopFrame);
    headersTopGrid->addWidget(hideHeadersButton, 1, 1,
                                        TQt::AlignRight | TQt::AlignBottom);
    hideHeadersButton->setIconSet(TQIconSet(pixmap));
    hideHeadersButton->setFlat(true);
    TQToolTip::add(hideHeadersButton, i18n("Close track headers"));
    headersTopGrid->setMargin(4);
    setTopStandardRuler(new StandardRuler(getDocument(),
                                    m_hlayout, m_leftGutter, 25,
                                    false, getCentralWidget()), m_headersTopFrame);

    m_topStandardRuler->getLoopRuler()->setBackgroundColor
        (GUIPalette::getColour(GUIPalette::InsertCursorRuler));

    connect(m_topStandardRuler->getLoopRuler(), TQ_SIGNAL(startMouseMove(int)),
            m_canvasView, TQ_SLOT(startAutoScroll(int)));
    connect(m_topStandardRuler->getLoopRuler(), TQ_SIGNAL(stopMouseMove()),
            m_canvasView, TQ_SLOT(stopAutoScroll()));

    connect(m_bottomStandardRuler->getLoopRuler(), TQ_SIGNAL(startMouseMove(int)),
            m_canvasView, TQ_SLOT(startAutoScroll(int)));
    connect(m_bottomStandardRuler->getLoopRuler(), TQ_SIGNAL(stopMouseMove()),
            m_canvasView, TQ_SLOT(stopAutoScroll()));

    // Following connection have to be done before calling setPageMode())
    connect(m_headersGroup, TQ_SIGNAL(headersResized(int)),
            this, TQ_SLOT(slotHeadersWidthChanged(int)));


    //
    // layout
    //
    ProgressDialog* progressDlg = 0;

    if (showProgressive)
    {
        show();
        ProgressDialog::processEvents();

        NOTATION_DEBUG << "NotationView : setting up progress dialog" << endl;

        progressDlg = new ProgressDialog(i18n("Starting..."),
                                         100, this);
        progressDlg->setAutoClose(false);
        progressDlg->setAutoReset(true);
        progressDlg->setMinimumDuration(1000);
        setupProgress(progressDlg);

        m_progressDisplayer = PROGRESS_DIALOG;
    }

    m_chordNameRuler->setStudio(&getDocument()->getStudio());

    m_currentStaff = 0;
    m_staffs[0]->setCurrent(true);

    m_config->setGroup(NotationViewConfigGroup);
    int layoutMode = m_config->readNumEntry("layoutmode", 0);

    try
    {

        LinedStaff::PageMode mode = LinedStaff::LinearMode;
        if (layoutMode == 1)
            mode = LinedStaff::ContinuousPageMode;
        else if (layoutMode == 2)
            mode = LinedStaff::MultiPageMode;

        setPageMode(mode);

        for (unsigned int i = 0; i < m_staffs.size(); ++i) {
            m_staffs[i]->getSegment().getRefreshStatus
            (m_segmentsRefreshStatusIds[i]).setNeedsRefresh(false);
        }

        m_ok = true;

    } catch (ProgressReporter::Cancelled c)
    {
        // when cancelled, m_ok is false -- checked by calling method
        NOTATION_DEBUG << "NotationView ctor : layout Cancelled" << endl;
    }

    NOTATION_DEBUG << "NotationView ctor : m_ok = " << m_ok << endl;

    delete progressDlg;

    // at this point we can return if operation was cancelled
    if (!isOK())
    {
        setOutOfCtor();
        return ;
    }


    // otherwise, carry on
    setupDefaultProgress();

    //
    // Connect signals
    //

    TQObject::connect
    (getCanvasView(), TQ_SIGNAL(renderRequired(double, double)),
     this, TQ_SLOT(slotCheckRendered(double, double)));

    m_topStandardRuler->connectRulerToDocPointer(doc);
    m_bottomStandardRuler->connectRulerToDocPointer(doc);

    // Disconnect the default connection for this signal from the
    // top ruler, and connect our own instead

    TQObject::disconnect
    (m_topStandardRuler->getLoopRuler(),
     TQ_SIGNAL(setPointerPosition(timeT)), 0, 0);

    TQObject::connect
    (m_topStandardRuler->getLoopRuler(),
     TQ_SIGNAL(setPointerPosition(timeT)),
     this, TQ_SLOT(slotSetInsertCursorPosition(timeT)));

    TQObject::connect
    (m_topStandardRuler,
     TQ_SIGNAL(dragPointerToPosition(timeT)),
     this, TQ_SLOT(slotSetInsertCursorPosition(timeT)));

    connect(m_bottomStandardRuler, TQ_SIGNAL(dragPointerToPosition(timeT)),
            this, TQ_SLOT(slotSetPointerPosition(timeT)));

    TQObject::connect
    (getCanvasView(), TQ_SIGNAL(itemPressed(int, int, TQMouseEvent*, NotationElement*)),
     this, TQ_SLOT (slotItemPressed(int, int, TQMouseEvent*, NotationElement*)));

    TQObject::connect
    (getCanvasView(), TQ_SIGNAL(activeItemPressed(TQMouseEvent*, TQCanvasItem*)),
     this, TQ_SLOT (slotActiveItemPressed(TQMouseEvent*, TQCanvasItem*)));

    TQObject::connect
    (getCanvasView(), TQ_SIGNAL(nonNotationItemPressed(TQMouseEvent*, TQCanvasItem*)),
     this, TQ_SLOT (slotNonNotationItemPressed(TQMouseEvent*, TQCanvasItem*)));

    TQObject::connect
    (getCanvasView(), TQ_SIGNAL(textItemPressed(TQMouseEvent*, TQCanvasItem*)),
     this, TQ_SLOT (slotTextItemPressed(TQMouseEvent*, TQCanvasItem*)));

    TQObject::connect
    (getCanvasView(), TQ_SIGNAL(mouseMoved(TQMouseEvent*)),
     this, TQ_SLOT (slotMouseMoved(TQMouseEvent*)));

    TQObject::connect
    (getCanvasView(), TQ_SIGNAL(mouseReleased(TQMouseEvent*)),
     this, TQ_SLOT (slotMouseReleased(TQMouseEvent*)));

    TQObject::connect
    (getCanvasView(), TQ_SIGNAL(hoveredOverNoteChanged(const TQString&)),
     this, TQ_SLOT (slotHoveredOverNoteChanged(const TQString&)));

    TQObject::connect
    (getCanvasView(), TQ_SIGNAL(hoveredOverAbsoluteTimeChanged(unsigned int)),
     this, TQ_SLOT (slotHoveredOverAbsoluteTimeChanged(unsigned int)));

    TQObject::connect
    (getCanvasView(), TQ_SIGNAL(zoomIn()), this, TQ_SLOT(slotZoomIn()));

    TQObject::connect
    (getCanvasView(), TQ_SIGNAL(zoomOut()), this, TQ_SLOT(slotZoomOut()));

    TQObject::connect
    (m_pannerDialog->scrollbox(), TQ_SIGNAL(valueChanged(const TQPoint &)),
     getCanvasView(), TQ_SLOT(slotSetScrollPos(const TQPoint &)));

    TQObject::connect
    (getCanvasView()->horizontalScrollBar(), TQ_SIGNAL(valueChanged(int)),
     m_pannerDialog->scrollbox(), TQ_SLOT(setViewX(int)));

    TQObject::connect
    (getCanvasView()->verticalScrollBar(), TQ_SIGNAL(valueChanged(int)),
     m_pannerDialog->scrollbox(), TQ_SLOT(setViewY(int)));

    TQObject::connect
    (doc, TQ_SIGNAL(pointerPositionChanged(timeT)),
     this, TQ_SLOT(slotSetPointerPosition(timeT)));

    //
    // Connect vertical scrollbars between canvas and notation header
    TQObject::connect
    (getCanvasView()->verticalScrollBar(), TQ_SIGNAL(valueChanged(int)),
     this, TQ_SLOT(slotVerticalScrollHeadersGroup(int)));

    TQObject::connect
    (getCanvasView()->verticalScrollBar(), TQ_SIGNAL(sliderMoved(int)),
     this, TQ_SLOT(slotVerticalScrollHeadersGroup(int)));

    TQObject::connect
    (m_headersGroupView, TQ_SIGNAL(gotWheelEvent(TQWheelEvent*)),
     getCanvasView(), TQ_SLOT(slotExternalWheelEvent(TQWheelEvent*)));

    // Ensure notation header keeps the right bottom margin when user
    // toggles the canvas view bottom rulers
    connect(getCanvasView(), TQ_SIGNAL(bottomWidgetHeightChanged(int)),
            this, TQ_SLOT(slotCanvasBottomWidgetHeightChanged(int)));

    // Signal canvas horizontal scroll to notation header
     TQObject::connect
     (getCanvasView(), TQ_SIGNAL(contentsMoving(int, int)),
     this, TQ_SLOT(slotUpdateHeaders(int, int)));

    // Connect the close notation headers button
    TQObject::connect(hideHeadersButton, TQ_SIGNAL(clicked()), 
                                  this, TQ_SLOT(slotHideHeadersGroup()));

    stateChanged("have_selection", KXMLGUIClient::StateReverse);
    stateChanged("have_notes_in_selection", KXMLGUIClient::StateReverse);
    stateChanged("have_rests_in_selection", KXMLGUIClient::StateReverse);
    stateChanged("have_multiple_staffs",
                 (m_staffs.size() > 1 ? KXMLGUIClient::StateNoReverse :
                  KXMLGUIClient::StateReverse));
    stateChanged("rest_insert_tool_current", KXMLGUIClient::StateReverse);
    slotTestClipboard();

    if (getSegmentsOnlyRestsAndClefs())
    {
        m_selectDefaultNote->activate();
        stateChanged("note_insert_tool_current",
                     KXMLGUIClient::StateNoReverse);
    } else
    {
        actionCollection()->action("select")->activate();
        stateChanged("note_insert_tool_current",
                     KXMLGUIClient::StateReverse);
    }

    timeT start = doc->getComposition().getLoopStart();
    timeT end = doc->getComposition().getLoopEnd();
    m_topStandardRuler->getLoopRuler()->slotSetLoopMarker(start, end);
    m_bottomStandardRuler->getLoopRuler()->slotSetLoopMarker(start, end);

    slotSetInsertCursorPosition(0);
    slotSetPointerPosition(doc->getComposition().getPosition());
    setCurrentSelection(0, false, true);
    slotUpdateInsertModeStatus();
    m_chordNameRuler->repaint();
    m_tempoRuler->repaint();
    m_rawNoteRuler->repaint();
    m_inhibitRefresh = false;

    //    slotCheckRendered(0, getCanvasView()->visibleWidth());
    //    getCanvasView()->repaintContents();
    updateView();

    TQObject::connect
    (this, TQ_SIGNAL(renderComplete()),
     getCanvasView(), TQ_SLOT(slotRenderComplete()));

    if (parent)
    {
        const TrackButtons * trackLabels =
            ((RosegardenGUIView*)parent)->getTrackEditor()->getTrackButtons();
        TQObject::connect
        (trackLabels, TQ_SIGNAL(nameChanged()),
         this, TQ_SLOT(slotUpdateStaffName()));
    }

    setConfigDialogPageIndex(3);
    setOutOfCtor();

    // Property and Control Rulers
    //
    if (getCurrentSegment()->getViewFeatures())
        slotShowVelocityControlRuler();
    setupControllerTabs();

    setupAddControlRulerMenu();
    setRewFFwdToAutoRepeat();

    slotCompositionStateUpdate();

    NOTATION_DEBUG << "NotationView ctor exiting" << endl;
}

NotationView::NotationView(RosegardenGUIDoc *doc,
                           std::vector<Segment *> segments,
                           TQWidget *parent,
                           NotationView *referenceView)
        : EditView(doc, segments, 1, 0, "printview"),
        m_properties(getViewLocalPropertyPrefix()),
        m_selectionCounter(0),
        m_currentNotePixmap(0),
        m_hoveredOverNoteName(0),
        m_hoveredOverAbsoluteTime(0),
        m_lastFinishingStaff( -1),
        m_title(0),
        m_subtitle(0),
        m_composer(0),
        m_copyright(0),
        m_insertionTime(0),
        m_deferredCursorMove(NoCursorMoveNeeded),
        m_lastNoteAction("crotchet"),
        m_fontName(NoteFontFactory::getDefaultFontName()),
        m_fontSize(NoteFontFactory::getDefaultSize(m_fontName)),
        m_pageMode(LinedStaff::LinearMode),
        m_leftGutter(0),
        m_notePixmapFactory(new NotePixmapFactory(m_fontName, m_fontSize)),
        m_hlayout(new NotationHLayout(&doc->getComposition(), m_notePixmapFactory,
                                      m_properties, this)),
        m_vlayout(new NotationVLayout(&doc->getComposition(), m_notePixmapFactory,
                                      m_properties, this)),
        m_chordNameRuler(0),
        m_tempoRuler(0),
        m_rawNoteRuler(0),
        m_annotationsVisible(false),
        m_lilyPondDirectivesVisible(false),
        m_selectDefaultNote(0),
        m_fontCombo(0),
        m_fontSizeCombo(0),
        m_spacingCombo(0),
        m_fontSizeActionMenu(0),
        m_pannerDialog(0),
        m_renderTimer(0),
        m_playTracking(false),
        m_progressDisplayer(PROGRESS_NONE),
        m_inhibitRefresh(true),
        m_ok(false),
        m_printMode(true),
        m_printSize(8), // set in positionStaffs
        m_showHeadersGroup(0),
        m_headersGroupView(0),
        m_headersGroup(0),
        m_headersTopFrame(0),
        m_showHeadersMenuEntry(0)
{
    assert(segments.size() > 0);
    NOTATION_DEBUG << "NotationView print ctor" << endl;


    // Initialise the display-related defaults that will be needed
    // by both the actions and the layout toolbar

    m_config->setGroup(NotationViewConfigGroup);

    if (referenceView)
    {
        m_fontName = referenceView->m_fontName;
    } else
    {
        m_fontName = qstrtostr(m_config->readEntry
                               ("notefont",
                                strtoqstr(NoteFontFactory::getDefaultFontName())));
    }


    // Force largest font size
    std::vector<int> sizes = NoteFontFactory::getAllSizes(m_fontName);
    m_fontSize = sizes[sizes.size() - 1];

    if (referenceView)
    {
        m_hlayout->setSpacing(referenceView->m_hlayout->getSpacing());
        m_hlayout->setProportion(referenceView->m_hlayout->getProportion());
    } else
    {
        int defaultSpacing = m_config->readNumEntry("spacing", 100);
        m_hlayout->setSpacing(defaultSpacing);
        int defaultProportion = m_config->readNumEntry("proportion", 60);
        m_hlayout->setProportion(defaultProportion);
    }

    delete m_notePixmapFactory;
    m_notePixmapFactory = new NotePixmapFactory(m_fontName, m_fontSize);
    m_hlayout->setNotePixmapFactory(m_notePixmapFactory);
    m_vlayout->setNotePixmapFactory(m_notePixmapFactory);

    setBackgroundMode(PaletteBase);
    m_config->setGroup(NotationViewConfigGroup);

    TQCanvas *tCanvas = new TQCanvas(this);
    tCanvas->resize(width() * 2, height() * 2); //!!!

    setCanvasView(new NotationCanvasView(*this, tCanvas, getCentralWidget()));
    canvas()->retune(128); // tune for larger canvas

    for (unsigned int i = 0; i < segments.size(); ++i)
    {
        m_staffs.push_back(new NotationStaff(canvas(), segments[i], 0,  // snap
                                             i, this,
                                             m_fontName, m_fontSize));
    }

    m_currentStaff = 0;
    m_staffs[0]->setCurrent(true);

    ProgressDialog* progressDlg = 0;

    if (parent)
    {

        ProgressDialog::processEvents();

        NOTATION_DEBUG << "NotationView : setting up progress dialog" << endl;

        progressDlg = new ProgressDialog(i18n("Preparing to print..."),
                                         100, parent);
        progressDlg->setAutoClose(false);
        progressDlg->setAutoReset(true);
        progressDlg->setMinimumDuration(1000);
        setupProgress(progressDlg);

        m_progressDisplayer = PROGRESS_DIALOG;
    }

    try
    {

        setPageMode(LinedStaff::MultiPageMode); // also positions and renders the staffs!

        for (unsigned int i = 0; i < m_staffs.size(); ++i) {
            m_staffs[i]->getSegment().getRefreshStatus
            (m_segmentsRefreshStatusIds[i]).setNeedsRefresh(false);
        }

        m_ok = true;

    } catch (ProgressReporter::Cancelled c)
    {
        // when cancelled, m_ok is false -- checked by calling method
        NOTATION_DEBUG << "NotationView ctor : layout Cancelled" << endl;
    }

    NOTATION_DEBUG << "NotationView ctor : m_ok = " << m_ok << endl;

    delete progressDlg;

    if (!isOK())
    {
        setOutOfCtor();
        return ; // In case more code is added there later
    }

    setOutOfCtor(); // keep this as last call in the ctor
}

NotationView::~NotationView()
{
    NOTATION_DEBUG << "-> ~NotationView()" << endl;

    if (!m_printMode && m_ok)
        slotSaveOptions();

    delete m_chordNameRuler;

    delete m_renderTimer;

    for (unsigned int i = 0; i < m_staffs.size(); ++i) {
        for (Segment::iterator j = m_staffs[i]->getSegment().begin();
                j != m_staffs[i]->getSegment().end(); ++j) {
            removeViewLocalProperties(*j);
        }
        delete m_staffs[i]; // this will erase all "notes" canvas items
    }

    PixmapArrayGC::deleteAll();
    Profiles::getInstance()->dump();

    NOTATION_DEBUG << "<- ~NotationView()" << endl;
}

void
NotationView::removeViewLocalProperties(Event *e)
{
    Event::PropertyNames names(e->getPropertyNames());
    std::string prefix(getViewLocalPropertyPrefix());

    for (Event::PropertyNames::iterator i = names.begin();
            i != names.end(); ++i) {
        if (i->getName().substr(0, prefix.size()) == prefix) {
            e->unset(*i);
        }
    }
}

const NotationProperties &
NotationView::getProperties() const
{
    return m_properties;
}

void NotationView::positionStaffs()
{
    NOTATION_DEBUG << "NotationView::positionStaffs" << endl;

    m_config->setGroup(NotationViewConfigGroup);
    m_printSize = m_config->readUnsignedNumEntry("printingnotesize", 5);

    int minTrack = 0, maxTrack = 0;
    bool haveMinTrack = false;
    typedef std::map<int, int> TrackIntMap;
    TrackIntMap trackHeights;
    TrackIntMap trackCoords;

    int pageWidth, pageHeight, leftMargin, topMargin;
    pageWidth = getPageWidth();
    pageHeight = getPageHeight();
    leftMargin = 0, topMargin = 0;
    getPageMargins(leftMargin, topMargin);

    int accumulatedHeight;
    int rowsPerPage = 1;
    int legerLines = 8;
    if (m_pageMode != LinedStaff::LinearMode)
        legerLines = 7;
    int rowGapPercent = (m_staffs.size() > 1 ? 40 : 10);
    int aimFor = -1;

    bool done = false;

    int titleHeight = 0;

    if (m_title)
        delete m_title;
    if (m_subtitle)
        delete m_subtitle;
    if (m_composer)
        delete m_composer;
    if (m_copyright)
        delete m_copyright;
    m_title = m_subtitle = m_composer = m_copyright = 0;

    if (m_pageMode == LinedStaff::MultiPageMode) {

        const Configuration &metadata =
            getDocument()->getComposition().getMetadata();

        TQFont defaultFont(NotePixmapFactory::defaultSerifFontFamily);
        m_config->setGroup(NotationViewConfigGroup);
        TQFont font = m_config->readFontEntry("textfont", &defaultFont);
        font.setPixelSize(m_fontSize * 5);
        TQFontMetrics metrics(font);

        if (metadata.has(CompositionMetadataKeys::Title)) {
            TQString title(strtoqstr(metadata.get<String>
                                    (CompositionMetadataKeys::Title)));
            m_title = new TQCanvasText(title, font, canvas());
            m_title->setX(m_leftGutter + pageWidth / 2 - metrics.width(title) / 2);
            m_title->setY(20 + topMargin / 4 + metrics.ascent());
            m_title->show();
            titleHeight += metrics.height() * 3 / 2 + topMargin / 4;
        }

        font.setPixelSize(m_fontSize * 3);
        metrics = TQFontMetrics(font);

        if (metadata.has(CompositionMetadataKeys::Subtitle)) {
            TQString subtitle(strtoqstr(metadata.get<String>
                                       (CompositionMetadataKeys::Subtitle)));
            m_subtitle = new TQCanvasText(subtitle, font, canvas());
            m_subtitle->setX(m_leftGutter + pageWidth / 2 - metrics.width(subtitle) / 2);
            m_subtitle->setY(20 + titleHeight + metrics.ascent());
            m_subtitle->show();
            titleHeight += metrics.height() * 3 / 2;
        }

        if (metadata.has(CompositionMetadataKeys::Composer)) {
            TQString composer(strtoqstr(metadata.get<String>
                                       (CompositionMetadataKeys::Composer)));
            m_composer = new TQCanvasText(composer, font, canvas());
            m_composer->setX(m_leftGutter + pageWidth - metrics.width(composer) - leftMargin);
            m_composer->setY(20 + titleHeight + metrics.ascent());
            m_composer->show();
            titleHeight += metrics.height() * 3 / 2;
        }

        font.setPixelSize(m_fontSize * 2);
        metrics = TQFontMetrics(font);

        if (metadata.has(CompositionMetadataKeys::Copyright)) {
            TQString copyright(strtoqstr(metadata.get<String>
                                        (CompositionMetadataKeys::Copyright)));
            m_copyright = new TQCanvasText(copyright, font, canvas());
            m_copyright->setX(m_leftGutter + leftMargin);
            m_copyright->setY(20 + pageHeight - topMargin - metrics.descent());
            m_copyright->show();
        }
    }

    while (1) {

        accumulatedHeight = 0;
        int maxTrackHeight = 0;

        trackHeights.clear();

        for (unsigned int i = 0; i < m_staffs.size(); ++i) {

            m_staffs[i]->setLegerLineCount(legerLines);

            int height = m_staffs[i]->getHeightOfRow();
            TrackId trackId = m_staffs[i]->getSegment().getTrack();
            Track *track =
                m_staffs[i]->getSegment().getComposition()->
                getTrackById(trackId);

            if (!track)
                continue; // This Should Not Happen, My Friend

            int trackPosition = track->getPosition();

            TrackIntMap::iterator hi = trackHeights.find(trackPosition);
            if (hi == trackHeights.end()) {
                trackHeights.insert(TrackIntMap::value_type
                                    (trackPosition, height));
            } else if (height > hi->second) {
                hi->second = height;
            }

            if (height > maxTrackHeight)
                maxTrackHeight = height;

            if (trackPosition < minTrack || !haveMinTrack) {
                minTrack = trackPosition;
                haveMinTrack = true;
            }
            if (trackPosition > maxTrack) {
                maxTrack = trackPosition;
            }
        }

        for (int i = minTrack; i <= maxTrack; ++i) {
            TrackIntMap::iterator hi = trackHeights.find(i);
            if (hi != trackHeights.end()) {
                trackCoords[i] = accumulatedHeight;
                accumulatedHeight += hi->second;
            }
        }

        accumulatedHeight += maxTrackHeight * rowGapPercent / 100;

        if (done)
            break;

        if (m_pageMode != LinedStaff::MultiPageMode) {

            rowsPerPage = 0;
            done = true;
            break;

        } else {

            // Check how well all this stuff actually fits on the
            // page.  If things don't fit as well as we'd like, modify
            // at most one parameter so as to save some space, then
            // loop around again and see if it worked.  This iterative
            // approach is inefficient but the time spent here is
            // neglible in context, and it's a simple way to code it.

            int staffPageHeight = pageHeight - topMargin * 2 - titleHeight;
            rowsPerPage = staffPageHeight / accumulatedHeight;

            if (rowsPerPage < 1) {

                if (legerLines > 5)
                    --legerLines;
                else if (rowGapPercent > 20)
                    rowGapPercent -= 10;
                else if (legerLines > 4)
                    --legerLines;
                else if (rowGapPercent > 0)
                    rowGapPercent -= 10;
                else if (legerLines > 3)
                    --legerLines;
                else if (m_printSize > 3)
                    --m_printSize;
                else { // just accept that we'll have to overflow
                    rowsPerPage = 1;
                    done = true;
                }

            } else {

                if (aimFor == rowsPerPage) {

                    titleHeight +=
                        (staffPageHeight - (rowsPerPage * accumulatedHeight)) / 2;

                    done = true;

                } else {

                    if (aimFor == -1)
                        aimFor = rowsPerPage + 1;

                    // we can perhaps accommodate another row, with care
                    if (legerLines > 5)
                        --legerLines;
                    else if (rowGapPercent > 20)
                        rowGapPercent -= 10;
                    else if (legerLines > 3)
                        --legerLines;
                    else if (rowGapPercent > 0)
                        rowGapPercent -= 10;
                    else { // no, we can't
                        rowGapPercent = 0;
                        legerLines = 8;
                        done = true;
                    }
                }
            }
        }
    }

    m_hlayout->setPageWidth(pageWidth - leftMargin * 2);

    int topGutter = 0;

    if (m_pageMode == LinedStaff::MultiPageMode) {

        topGutter = 20;

    } else if (m_pageMode == LinedStaff::ContinuousPageMode) {

        // fewer leger lines above staff than in linear mode --
        // compensate for this on the top staff
        topGutter = m_notePixmapFactory->getLineSpacing() * 2;
    }

    for (unsigned int i = 0; i < m_staffs.size(); ++i) {

        TrackId trackId = m_staffs[i]->getSegment().getTrack();
        Track *track =
            m_staffs[i]->getSegment().getComposition()->
            getTrackById(trackId);

        if (!track)
            continue; // Once Again, My Friend, You Should Never See Me Here

        int trackPosition = track->getPosition();

        m_staffs[i]->setTitleHeight(titleHeight);
        m_staffs[i]->setRowSpacing(accumulatedHeight);

        if (trackPosition < maxTrack) {
            m_staffs[i]->setConnectingLineLength(trackHeights[trackPosition]);
        }

        if (trackPosition == minTrack &&
                m_pageMode != LinedStaff::LinearMode) {
            m_staffs[i]->setBarNumbersEvery(5);
        } else {
            m_staffs[i]->setBarNumbersEvery(0);
        }

        m_staffs[i]->setX(m_leftGutter);
        m_staffs[i]->setY(topGutter + trackCoords[trackPosition] + topMargin);
        m_staffs[i]->setPageWidth(pageWidth - leftMargin * 2);
        m_staffs[i]->setRowsPerPage(rowsPerPage);
        m_staffs[i]->setPageMode(m_pageMode);
        m_staffs[i]->setMargin(leftMargin);

        NOTATION_DEBUG << "NotationView::positionStaffs: set staff's page width to "
        << (pageWidth - leftMargin * 2) << endl;

    }


    if (!m_printMode) {
        // Destroy then recreate all track headers
        hideHeadersGroup();
        m_headersGroup->removeAllHeaders();
        if (m_pageMode == LinedStaff::LinearMode) {
            for (int i = minTrack; i <= maxTrack; ++i) {
                TrackIntMap::iterator hi = trackHeights.find(i);
                if (hi != trackHeights.end()) {
                    TrackId trackId = getDocument()->getComposition()
                                            .getTrackByPosition(i)->getId();
                    m_headersGroup->addHeader(trackId, trackHeights[i],
                                              trackCoords[i], getCanvasLeftX());
                }
            }

            m_headersGroup->completeToHeight(canvas()->height());

            m_headersGroupView->addChild(m_headersGroup);

            getCanvasView()->updateLeftWidgetGeometry();

            if (    (m_showHeadersGroup == HeadersGroup::ShowAlways)
                || (    (m_showHeadersGroup == HeadersGroup::ShowWhenNeeded)
                      && (m_headersGroup->getUsedHeight()
                              > getCanvasView()->visibleHeight()))) {
                m_headersGroup->slotUpdateAllHeaders(getCanvasLeftX(), 0, true);
                showHeadersGroup();

                // Disable menu entry when headers are shown
                m_showHeadersMenuEntry->setEnabled(false);
            } else {
                // Enable menu entry when headers are hidden
                m_showHeadersMenuEntry->setEnabled(true);
            }
        } else {
            // Disable menu entry when not in linear mode
            m_showHeadersMenuEntry->setEnabled(false);
        }
    }
}

void NotationView::slotCanvasBottomWidgetHeightChanged(int newHeight)
{
    getCanvasView()->updateLeftWidgetGeometry();
}

void NotationView::positionPages()
{
    if (m_printMode)
        return ;

    TQPixmap background;
    TQPixmap deskBackground;
    bool haveBackground = false;

    m_config->setGroup(NotationViewConfigGroup);
    if (m_config->readBoolEntry("backgroundtextures", true)) {
        TQString pixmapDir =
            TDEGlobal::dirs()->findResource("appdata", "pixmaps/");
        if (background.load(TQString("%1/misc/bg-paper-cream.xpm").
                            arg(pixmapDir))) {
            haveBackground = true;
        }
        // we're happy to ignore errors from this one:
        deskBackground.load(TQString("%1/misc/bg-desktop.xpm").arg(pixmapDir));
    }

    int pageWidth = getPageWidth();
    int pageHeight = getPageHeight();
    int leftMargin = 0, topMargin = 0;
    getPageMargins(leftMargin, topMargin);
    int maxPageCount = 1;

    for (unsigned int i = 0; i < m_staffs.size(); ++i) {
        int pageCount = m_staffs[i]->getPageCount();
        if (pageCount > maxPageCount)
            maxPageCount = pageCount;
    }

    for (unsigned int i = 0; i < m_pages.size(); ++i) {
        delete m_pages[i];
        delete m_pageNumbers[i];
    }
    m_pages.clear();
    m_pageNumbers.clear();

    if (m_pageMode != LinedStaff::MultiPageMode) {
        if (haveBackground) {
            canvas()->setBackgroundPixmap(background);
            getCanvasView()->setBackgroundMode(TQt::FixedPixmap);
            getCanvasView()->setPaletteBackgroundPixmap(background);
            getCanvasView()->setErasePixmap(background);
        }
    } else {
        if (haveBackground) {
            canvas()->setBackgroundPixmap(deskBackground);
            getCanvasView()->setBackgroundMode(TQt::FixedPixmap);
            getCanvasView()->setPaletteBackgroundPixmap(background);
            getCanvasView()->setErasePixmap(background);
        }

        TQFont pageNumberFont;
        pageNumberFont.setPixelSize(m_fontSize * 2);
        TQFontMetrics pageNumberMetrics(pageNumberFont);

        for (int page = 0; page < maxPageCount; ++page) {

            int x = m_leftGutter + pageWidth * page + leftMargin / 4;
            int y = 20;
            int w = pageWidth - leftMargin / 2;
            int h = pageHeight;

            TQString str = TQString("%1").arg(page + 1);
            TQCanvasText *text = new TQCanvasText(str, pageNumberFont, canvas());
            text->setX(m_leftGutter + pageWidth * page + pageWidth - pageNumberMetrics.width(str) - leftMargin);
            text->setY(y + h - pageNumberMetrics.descent() - topMargin);
            text->setZ( -999);
            text->show();
            m_pageNumbers.push_back(text);

            TQCanvasRectangle *rect = new TQCanvasRectangle(x, y, w, h, canvas());
            if (haveBackground)
                rect->setBrush(TQBrush(TQt::white, background));
            rect->setPen(TQt::black);
            rect->setZ( -1000);
            rect->show();
            m_pages.push_back(rect);
        }

        updateThumbnails(false);
    }

    m_config->setGroup(NotationViewConfigGroup);
}

void NotationView::slotUpdateStaffName()
{
    LinedStaff *staff = getLinedStaff(m_currentStaff);
    staff->drawStaffName();
    m_headersGroup->slotUpdateAllHeaders(getCanvasLeftX(), 0, true);
}

void NotationView::slotSaveOptions()
{
    m_config->setGroup(NotationViewConfigGroup);

    m_config->writeEntry("Show Chord Name Ruler", getToggleAction("show_chords_ruler")->isChecked());
    m_config->writeEntry("Show Raw Note Ruler", getToggleAction("show_raw_note_ruler")->isChecked());
    m_config->writeEntry("Show Tempo Ruler", getToggleAction("show_tempo_ruler")->isChecked());
    m_config->writeEntry("Show Annotations", m_annotationsVisible);
    m_config->writeEntry("Show LilyPond Directives", m_lilyPondDirectivesVisible);

    m_config->sync();
}

void NotationView::setOneToolbar(const char *actionName,
                                 const char *toolbarName)
{
    TDEToggleAction *action = getToggleAction(actionName);
    if (!action) {
        std::cerr << "WARNING: No such action as " << actionName << std::endl;
        return ;
    }
    TQWidget *toolbar = toolBar(toolbarName);
    if (!toolbar) {
        std::cerr << "WARNING: No such toolbar as " << toolbarName << std::endl;
        return ;
    }
    action->setChecked(!toolbar->isHidden());
}

void NotationView::readOptions()
{
    EditView::readOptions();

    setOneToolbar("show_tools_toolbar", "Tools Toolbar");
    setOneToolbar("show_notes_toolbar", "Notes Toolbar");
    setOneToolbar("show_rests_toolbar", "Rests Toolbar");
    setOneToolbar("show_clefs_toolbar", "Clefs Toolbar");
    setOneToolbar("show_group_toolbar", "Group Toolbar");
    setOneToolbar("show_marks_toolbar", "Marks Toolbar");
    setOneToolbar("show_layout_toolbar", "Layout Toolbar");
    setOneToolbar("show_transport_toolbar", "Transport Toolbar");
    setOneToolbar("show_accidentals_toolbar", "Accidentals Toolbar");
    setOneToolbar("show_meta_toolbar", "Meta Toolbar");

    m_config->setGroup(NotationViewConfigGroup);

    bool opt;

    opt = m_config->readBoolEntry("Show Chord Name Ruler", false);
    getToggleAction("show_chords_ruler")->setChecked(opt);
    slotToggleChordsRuler();

    opt = m_config->readBoolEntry("Show Raw Note Ruler", true);
    getToggleAction("show_raw_note_ruler")->setChecked(opt);
    slotToggleRawNoteRuler();

    opt = m_config->readBoolEntry("Show Tempo Ruler", true);
    getToggleAction("show_tempo_ruler")->setChecked(opt);
    slotToggleTempoRuler();

    opt = m_config->readBoolEntry("Show Annotations", true);
    m_annotationsVisible = opt;
    getToggleAction("show_annotations")->setChecked(opt);
    slotUpdateAnnotationsStatus();
    //    slotToggleAnnotations();

    opt = m_config->readBoolEntry("Show LilyPond Directives", true);
    m_lilyPondDirectivesVisible = opt;
    getToggleAction("show_lilypond_directives")->setChecked(opt);
    slotUpdateLilyPondDirectivesStatus();
}

void NotationView::setupActions()
{
    KStdAction::print(this, TQ_SLOT(slotFilePrint()), actionCollection());
    KStdAction::printPreview(this, TQ_SLOT(slotFilePrintPreview()),
                             actionCollection());

    new TDEAction(i18n("Print &with LilyPond..."), 0, 0, this,
                TQ_SLOT(slotPrintLilyPond()), actionCollection(),
                "file_print_lilypond");

    new TDEAction(i18n("Preview with Lil&yPond..."), 0, 0, this,
                TQ_SLOT(slotPreviewLilyPond()), actionCollection(),
                "file_preview_lilypond");

    EditViewBase::setupActions("notation.rc");
    EditView::setupActions();

    TDERadioAction* noteAction = 0;

    // View menu stuff

    TDEActionMenu *fontActionMenu =
        new TDEActionMenu(i18n("Note &Font"), this, "note_font_actionmenu");

    std::set
        <std::string> fs(NoteFontFactory::getFontNames());
    std::vector<std::string> f(fs.begin(), fs.end());
    std::sort(f.begin(), f.end());

    for (std::vector<std::string>::iterator i = f.begin(); i != f.end(); ++i) {

        TQString fontTQName(strtoqstr(*i));

        TDEToggleAction *fontAction =
            new TDEToggleAction
            (fontTQName, 0, this, TQ_SLOT(slotChangeFontFromAction()),
             actionCollection(), TQString("note_font_" + fontTQName).ascii());

        fontAction->setChecked(*i == m_fontName);
        fontActionMenu->insert(fontAction);
    }

    actionCollection()->insert(fontActionMenu);

    m_fontSizeActionMenu =
        new TDEActionMenu(i18n("Si&ze"), this, "note_font_size_actionmenu");
    setupFontSizeMenu();

    actionCollection()->insert(m_fontSizeActionMenu);

    m_showHeadersMenuEntry
        = new TDEAction(i18n("Show Track Headers"), 0, this,
                            TQ_SLOT(slotShowHeadersGroup()),
                            actionCollection(), "show_track_headers");

    TDEActionMenu *spacingActionMenu =
        new TDEActionMenu(i18n("S&pacing"), this, "stretch_actionmenu");

    int defaultSpacing = m_hlayout->getSpacing();
    std::vector<int> spacings = NotationHLayout::getAvailableSpacings();

    for (std::vector<int>::iterator i = spacings.begin();
            i != spacings.end(); ++i) {

        TDEToggleAction *spacingAction =
            new TDEToggleAction
            (TQString("%1%").arg(*i), 0, this,
             TQ_SLOT(slotChangeSpacingFromAction()),
             actionCollection(), TQString("spacing_%1").arg(*i).ascii());

        spacingAction->setExclusiveGroup("spacing");
        spacingAction->setChecked(*i == defaultSpacing);
        spacingActionMenu->insert(spacingAction);
    }

    actionCollection()->insert(spacingActionMenu);

    TDEActionMenu *proportionActionMenu =
        new TDEActionMenu(i18n("Du&ration Factor"), this, "proportion_actionmenu");

    int defaultProportion = m_hlayout->getProportion();
    std::vector<int> proportions = NotationHLayout::getAvailableProportions();

    for (std::vector<int>::iterator i = proportions.begin();
            i != proportions.end(); ++i) {

        TQString name = TQString("%1%").arg(*i);
        if (*i == 0)
            name = i18n("None");

        TDEToggleAction *proportionAction =
            new TDEToggleAction
            (name, 0, this,
             TQ_SLOT(slotChangeProportionFromAction()),
             actionCollection(), TQString("proportion_%1").arg(*i).ascii());

        proportionAction->setExclusiveGroup("proportion");
        proportionAction->setChecked(*i == defaultProportion);
        proportionActionMenu->insert(proportionAction);
    }

    actionCollection()->insert(proportionActionMenu);

    TDEActionMenu *styleActionMenu =
        new TDEActionMenu(i18n("Note &Style"), this, "note_style_actionmenu");

    std::vector<NoteStyleName> styles
    (NoteStyleFactory::getAvailableStyleNames());

    for (std::vector<NoteStyleName>::iterator i = styles.begin();
            i != styles.end(); ++i) {

        TQString styleTQName(strtoqstr(*i));

        TDEAction *styleAction =
            new TDEAction
            (styleTQName, 0, this, TQ_SLOT(slotSetStyleFromAction()),
             actionCollection(), TQString("style_" + styleTQName).ascii());

        styleActionMenu->insert(styleAction);
    }

    actionCollection()->insert(styleActionMenu);

    TDEActionMenu *ornamentActionMenu =
        new TDEActionMenu(i18n("Use Ornament"), this, "ornament_actionmenu");



    new TDEAction
    (i18n("Insert Rest"), Key_P, this, TQ_SLOT(slotInsertRest()),
     actionCollection(), TQString("insert_rest").ascii());

    new TDEAction
    (i18n("Switch from Note to Rest"), Key_T, this,
     TQ_SLOT(slotSwitchFromNoteToRest()),
     actionCollection(), TQString("switch_from_note_to_rest").ascii());

    new TDEAction
    (i18n("Switch from Rest to Note"), Key_Y, this,
     TQ_SLOT(slotSwitchFromRestToNote()),
     actionCollection(), TQString("switch_from_rest_to_note").ascii());


    // setup Notes menu & toolbar
    TQIconSet icon;

    for (NoteActionDataMap::Iterator actionDataIter = m_noteActionDataMap->begin();
            actionDataIter != m_noteActionDataMap->end();
            ++actionDataIter) {

        NoteActionData noteActionData = **actionDataIter;

        icon = TQIconSet
               (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                                             (noteActionData.pixmapName.ascii())));
        noteAction = new TDERadioAction(noteActionData.title,
                                      icon,
                                      noteActionData.keycode,
                                      this,
                                      TQ_SLOT(slotNoteAction()),
                                      actionCollection(),
                                      noteActionData.actionName.ascii());
        noteAction->setExclusiveGroup("notes");

        if (noteActionData.noteType == Note::Crotchet &&
                noteActionData.dots == 0 && !noteActionData.rest) {
            m_selectDefaultNote = noteAction;
        }
    }

    // Note duration change actions
    for (NoteChangeActionDataMap::Iterator actionDataIter = m_noteChangeActionDataMap->begin();
            actionDataIter != m_noteChangeActionDataMap->end();
            ++actionDataIter) {

        NoteChangeActionData data = **actionDataIter;

        icon = TQIconSet
               (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                                             (data.pixmapName.ascii())));

        TDEAction *action = new TDEAction(data.title,
                                      icon,
                                      data.keycode,
                                      this,
                                      TQ_SLOT(slotNoteChangeAction()),
                                      actionCollection(),
                                      data.actionName.ascii());
    }

    //
    // Accidentals
    //
    static TQString actionsAccidental[][4] =
        {
            { i18n("No accidental"), "1slotNoAccidental()", "no_accidental", "accidental-none" },
            { i18n("Follow previous accidental"), "1slotFollowAccidental()", "follow_accidental", "accidental-follow" },
            { i18n("Sharp"), "1slotSharp()", "sharp_accidental", "accidental-sharp" },
            { i18n("Flat"), "1slotFlat()", "flat_accidental", "accidental-flat" },
            { i18n("Natural"), "1slotNatural()", "natural_accidental", "accidental-natural" },
            { i18n("Double sharp"), "1slotDoubleSharp()", "double_sharp_accidental", "accidental-doublesharp" },
            { i18n("Double flat"), "1slotDoubleFlat()", "double_flat_accidental", "accidental-doubleflat" }
        };

    for (unsigned int i = 0;
            i < sizeof(actionsAccidental) / sizeof(actionsAccidental[0]); ++i) {

        icon = TQIconSet(NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                        (actionsAccidental[i][3].ascii())));
        noteAction = new TDERadioAction(actionsAccidental[i][0], icon, 0, this,
                                      actionsAccidental[i][1].ascii(),
                                      actionCollection(), actionsAccidental[i][2].ascii());
        noteAction->setExclusiveGroup("accidentals");
    }


    //
    // Clefs
    //

    // Treble
    icon = TQIconSet(NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap("clef-treble")));
    noteAction = new TDERadioAction(i18n("&Treble Clef"), icon, 0, this,
                                  TQ_SLOT(slotTrebleClef()),
                                  actionCollection(), "treble_clef");
    noteAction->setExclusiveGroup("notes");

    // Alto
    icon = TQIconSet(NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap("clef-alto")));
    noteAction = new TDERadioAction(i18n("&Alto Clef"), icon, 0, this,
                                  TQ_SLOT(slotAltoClef()),
                                  actionCollection(), "alto_clef");
    noteAction->setExclusiveGroup("notes");

    // Tenor
    icon = TQIconSet(NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap("clef-tenor")));
    noteAction = new TDERadioAction(i18n("Te&nor Clef"), icon, 0, this,
                                  TQ_SLOT(slotTenorClef()),
                                  actionCollection(), "tenor_clef");
    noteAction->setExclusiveGroup("notes");

    // Bass
    icon = TQIconSet(NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap("clef-bass")));
    noteAction = new TDERadioAction(i18n("&Bass Clef"), icon, 0, this,
                                  TQ_SLOT(slotBassClef()),
                                  actionCollection(), "bass_clef");
    noteAction->setExclusiveGroup("notes");


    icon = TQIconSet(NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap("text")));
    noteAction = new TDERadioAction(i18n("&Text"), icon, Key_F8, this,
                                  TQ_SLOT(slotText()),
                                  actionCollection(), "text");
    noteAction->setExclusiveGroup("notes");

    icon = TQIconSet(NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap("guitarchord")));
    noteAction = new TDERadioAction(i18n("&Guitar Chord"), icon, Key_F9, this,
                                  TQ_SLOT(slotGuitarChord()),
                                  actionCollection(), "guitarchord");
    noteAction->setExclusiveGroup("notes");

    /*    icon = TQIconSet(NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap("lilypond")));
        noteAction = new TDERadioAction(i18n("Lil&ypond Directive"), icon, Key_F9, this,
                                      TQ_SLOT(slotLilyPondDirective()),
                                      actionCollection(), "lilypond_directive");
        noteAction->setExclusiveGroup("notes"); */


    //
    // Edition tools (eraser, selector...)
    //
    noteAction = new TDERadioAction(i18n("&Erase"), "eraser", Key_F4,
                                  this, TQ_SLOT(slotEraseSelected()),
                                  actionCollection(), "erase");
    noteAction->setExclusiveGroup("notes");

    icon = TQIconSet(NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap("select")));
    noteAction = new TDERadioAction(i18n("&Select and Edit"), icon, Key_F2,
                                  this, TQ_SLOT(slotSelectSelected()),
                                  actionCollection(), "select");
    noteAction->setExclusiveGroup("notes");

    icon = TQIconSet(NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap("step_by_step")));
    new TDEToggleAction(i18n("Ste&p Recording"), icon, 0, this,
                      TQ_SLOT(slotToggleStepByStep()), actionCollection(),
                      "toggle_step_by_step");


    // Edit menu
    new TDEAction(i18n("Select from Sta&rt"), 0, this,
                TQ_SLOT(slotEditSelectFromStart()), actionCollection(),
                "select_from_start");

    new TDEAction(i18n("Select to &End"), 0, this,
                TQ_SLOT(slotEditSelectToEnd()), actionCollection(),
                "select_to_end");

    new TDEAction(i18n("Select Whole St&aff"), Key_A + CTRL, this,
                TQ_SLOT(slotEditSelectWholeStaff()), actionCollection(),
                "select_whole_staff");

    new TDEAction(i18n("C&ut and Close"), CTRL + SHIFT + Key_X, this,
                TQ_SLOT(slotEditCutAndClose()), actionCollection(),
                "cut_and_close");

    new TDEAction(i18n("Pa&ste..."), CTRL + SHIFT + Key_V, this,
                TQ_SLOT(slotEditGeneralPaste()), actionCollection(),
                "general_paste");

    new TDEAction(i18n("De&lete"), Key_Delete, this,
                TQ_SLOT(slotEditDelete()), actionCollection(),
                "delete");

    new TDEAction(i18n("Move to Staff Above"), 0, this,
                TQ_SLOT(slotMoveEventsUpStaff()), actionCollection(),
                "move_events_up_staff");

    new TDEAction(i18n("Move to Staff Below"), 0, this,
                TQ_SLOT(slotMoveEventsDownStaff()), actionCollection(),
                "move_events_down_staff");

    //
    // Settings menu
    //
    int layoutMode = m_config->readNumEntry("layoutmode", 0);

    TQString pixmapDir = TDEGlobal::dirs()->findResource("appdata", "pixmaps/");

    TQCanvasPixmap pixmap(pixmapDir + "/toolbar/linear-layout.xpm");
    icon = TQIconSet(pixmap);
    TDERadioAction *linearModeAction = new TDERadioAction
                                     (i18n("&Linear Layout"), icon, 0, this, TQ_SLOT(slotLinearMode()),
                                      actionCollection(), "linear_mode");
    linearModeAction->setExclusiveGroup("layoutMode");
    if (layoutMode == 0)
        linearModeAction->setChecked(true);

    pixmap.load(pixmapDir + "/toolbar/continuous-page-mode.xpm");
    icon = TQIconSet(pixmap);
    TDERadioAction *continuousPageModeAction = new TDERadioAction
            (i18n("&Continuous Page Layout"), icon, 0, this, TQ_SLOT(slotContinuousPageMode()),
             actionCollection(), "continuous_page_mode");
    continuousPageModeAction->setExclusiveGroup("layoutMode");
    if (layoutMode == 1)
        continuousPageModeAction->setChecked(true);

    pixmap.load(pixmapDir + "/toolbar/multi-page-mode.xpm");
    icon = TQIconSet(pixmap);
    TDERadioAction *multiPageModeAction = new TDERadioAction
                                        (i18n("&Multiple Page Layout"), icon, 0, this, TQ_SLOT(slotMultiPageMode()),
                                         actionCollection(), "multi_page_mode");
    multiPageModeAction->setExclusiveGroup("layoutMode");
    if (layoutMode == 2)
        multiPageModeAction->setChecked(true);

    new TDEToggleAction(i18n("Show Ch&ord Name Ruler"), 0, this,
                      TQ_SLOT(slotToggleChordsRuler()),
                      actionCollection(), "show_chords_ruler");

    new TDEToggleAction(i18n("Show Ra&w Note Ruler"), 0, this,
                      TQ_SLOT(slotToggleRawNoteRuler()),
                      actionCollection(), "show_raw_note_ruler");

    new TDEToggleAction(i18n("Show &Tempo Ruler"), 0, this,
                      TQ_SLOT(slotToggleTempoRuler()),
                      actionCollection(), "show_tempo_ruler");

    new TDEToggleAction(i18n("Show &Annotations"), 0, this,
                      TQ_SLOT(slotToggleAnnotations()),
                      actionCollection(), "show_annotations");

    new TDEToggleAction(i18n("Show Lily&Pond Directives"), 0, this,
                      TQ_SLOT(slotToggleLilyPondDirectives()),
                      actionCollection(), "show_lilypond_directives");

    new TDEAction(i18n("Open L&yric Editor"), 0, this, TQ_SLOT(slotEditLyrics()),
                actionCollection(), "lyric_editor");

    //
    // Group menu
    //
    icon = TQIconSet
           (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                                         ("group-beam")));

    new TDEAction(BeamCommand::getGlobalName(), icon, Key_B + CTRL, this,
                TQ_SLOT(slotGroupBeam()), actionCollection(), "beam");

    new TDEAction(AutoBeamCommand::getGlobalName(), 0, this,
                TQ_SLOT(slotGroupAutoBeam()), actionCollection(), "auto_beam");

    icon = TQIconSet
           (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                                         ("group-unbeam")));

    new TDEAction(BreakCommand::getGlobalName(), icon, Key_U + CTRL, this,
                TQ_SLOT(slotGroupBreak()), actionCollection(), "break_group");

    icon = TQIconSet
           (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                                         ("group-simple-tuplet")));

    new TDEAction(TupletCommand::getGlobalName(true), icon, Key_R + CTRL, this,
                TQ_SLOT(slotGroupSimpleTuplet()), actionCollection(), "simple_tuplet");

    icon = TQIconSet
           (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                                         ("group-tuplet")));

    new TDEAction(TupletCommand::getGlobalName(false), icon, Key_T + CTRL, this,
                TQ_SLOT(slotGroupGeneralTuplet()), actionCollection(), "tuplet");

    new TDEAction(UnTupletCommand::getGlobalName(), 0, this,
                TQ_SLOT(slotGroupUnTuplet()), actionCollection(), "break_tuplets");

    icon = TQIconSet(NotePixmapFactory::toTQPixmap
                    (NotePixmapFactory::makeToolbarPixmap("triplet")));
    (new TDEToggleAction(i18n("Trip&let Insert Mode"), icon, Key_G,
                       this, TQ_SLOT(slotUpdateInsertModeStatus()),
                       actionCollection(), "triplet_mode"))->
        setChecked(false);

    icon = TQIconSet(NotePixmapFactory::toTQPixmap
                    (NotePixmapFactory::makeToolbarPixmap("chord")));
    (new TDEToggleAction(i18n("C&hord Insert Mode"), icon, Key_H,
                       this, TQ_SLOT(slotUpdateInsertModeStatus()),
                       actionCollection(), "chord_mode"))->
        setChecked(false);

    icon = TQIconSet(NotePixmapFactory::toTQPixmap
                    (NotePixmapFactory::makeToolbarPixmap("group-grace")));
    (new TDEToggleAction(i18n("Grace Insert Mode"), icon, 0,
                       this, TQ_SLOT(slotUpdateInsertModeStatus()),
                       actionCollection(), "grace_mode"))->
        setChecked(false);
/*!!!
    icon = TQIconSet
           (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                                         ("group-grace")));

    new TDEAction(GraceCommand::getGlobalName(), icon, 0, this,
                TQ_SLOT(slotGroupGrace()), actionCollection(), "grace");

    new TDEAction(UnGraceCommand::getGlobalName(), 0, this,
                TQ_SLOT(slotGroupUnGrace()), actionCollection(), "ungrace");
*/
    icon = TQIconSet
           (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                                         ("group-slur")));

    new TDEAction(AddIndicationCommand::getGlobalName
                (Indication::Slur), icon, Key_ParenRight, this,
                TQ_SLOT(slotGroupSlur()), actionCollection(), "slur");

    new TDEAction(AddIndicationCommand::getGlobalName
                (Indication::PhrasingSlur), 0, Key_ParenRight + CTRL, this,
                TQ_SLOT(slotGroupPhrasingSlur()), actionCollection(), "phrasing_slur");

    icon = TQIconSet
           (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                                         ("group-glissando")));

    new TDEAction(AddIndicationCommand::getGlobalName
                (Indication::Glissando), icon, 0, this,
                TQ_SLOT(slotGroupGlissando()), actionCollection(), "glissando");

    icon = TQIconSet
           (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                                         ("group-crescendo")));

    new TDEAction(AddIndicationCommand::getGlobalName
                (Indication::Crescendo), icon, Key_Less, this,
                TQ_SLOT(slotGroupCrescendo()), actionCollection(), "crescendo");

    icon = TQIconSet
           (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                                         ("group-decrescendo")));

    new TDEAction(AddIndicationCommand::getGlobalName
                (Indication::Decrescendo), icon, Key_Greater, this,
                TQ_SLOT(slotGroupDecrescendo()), actionCollection(), "decrescendo");

    new TDEAction(AddIndicationCommand::getGlobalName
                (Indication::QuindicesimaUp), 0, 0, this,
                TQ_SLOT(slotGroupOctave2Up()), actionCollection(), "octave_2up");

    icon = TQIconSet
           (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                                         ("group-ottava")));

    new TDEAction(AddIndicationCommand::getGlobalName
                (Indication::OttavaUp), icon, 0, this,
                TQ_SLOT(slotGroupOctaveUp()), actionCollection(), "octave_up");

    new TDEAction(AddIndicationCommand::getGlobalName
                (Indication::OttavaDown), 0, 0, this,
                TQ_SLOT(slotGroupOctaveDown()), actionCollection(), "octave_down");

    new TDEAction(AddIndicationCommand::getGlobalName
                (Indication::QuindicesimaDown), 0, 0, this,
                TQ_SLOT(slotGroupOctave2Down()), actionCollection(), "octave_2down");

    icon = TQIconSet
           (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                                         ("group-chord")));
    new TDEAction(MakeChordCommand::getGlobalName(), icon, 0, this,
                TQ_SLOT(slotGroupMakeChord()), actionCollection(), "make_chord");

    // setup Transforms menu
    new TDEAction(NormalizeRestsCommand::getGlobalName(), Key_N + CTRL, this,
                TQ_SLOT(slotTransformsNormalizeRests()), actionCollection(),
                "normalize_rests");

    new TDEAction(CollapseRestsCommand::getGlobalName(), 0, this,
                TQ_SLOT(slotTransformsCollapseRests()), actionCollection(),
                "collapse_rests_aggressively");

    new TDEAction(CollapseNotesCommand::getGlobalName(), Key_Equal + CTRL, this,
                TQ_SLOT(slotTransformsCollapseNotes()), actionCollection(),
                "collapse_notes");

    icon = TQIconSet
           (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                                         ("transforms-tie")));

    new TDEAction(TieNotesCommand::getGlobalName(), icon, Key_AsciiTilde, this,
                TQ_SLOT(slotTransformsTieNotes()), actionCollection(),
                "tie_notes");

    new TDEAction(UntieNotesCommand::getGlobalName(), 0, this,
                TQ_SLOT(slotTransformsUntieNotes()), actionCollection(),
                "untie_notes");

    new TDEAction(MakeNotesViableCommand::getGlobalName(), 0, this,
                TQ_SLOT(slotTransformsMakeNotesViable()), actionCollection(),
                "make_notes_viable");

    icon = TQIconSet
           (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                                         ("transforms-decounterpoint")));

    new TDEAction(DeCounterpointCommand::getGlobalName(), icon, 0, this,
                TQ_SLOT(slotTransformsDeCounterpoint()), actionCollection(),
                "de_counterpoint");

    new TDEAction(ChangeStemsCommand::getGlobalName(true),
                0, Key_PageUp + CTRL, this,
                TQ_SLOT(slotTransformsStemsUp()), actionCollection(),
                "stems_up");

    new TDEAction(ChangeStemsCommand::getGlobalName(false),
                0, Key_PageDown + CTRL, this,
                TQ_SLOT(slotTransformsStemsDown()), actionCollection(),
                "stems_down");

    new TDEAction(RestoreStemsCommand::getGlobalName(), 0, this,
                TQ_SLOT(slotTransformsRestoreStems()), actionCollection(),
                "restore_stems");

    new TDEAction(ChangeSlurPositionCommand::getGlobalName(true),
                0, this,
                TQ_SLOT(slotTransformsSlursAbove()), actionCollection(),
                "slurs_above");

    new TDEAction(ChangeSlurPositionCommand::getGlobalName(false),
                0, this,
                TQ_SLOT(slotTransformsSlursBelow()), actionCollection(),
                "slurs_below");

    new TDEAction(RestoreSlursCommand::getGlobalName(), 0, this,
                TQ_SLOT(slotTransformsRestoreSlurs()), actionCollection(),
                "restore_slurs");

    new TDEAction(ChangeTiePositionCommand::getGlobalName(true),
                0, this,
                TQ_SLOT(slotTransformsTiesAbove()), actionCollection(),
                "ties_above");

    new TDEAction(ChangeTiePositionCommand::getGlobalName(false),
                0, this,
                TQ_SLOT(slotTransformsTiesBelow()), actionCollection(),
                "ties_below");

    new TDEAction(RestoreTiesCommand::getGlobalName(), 0, this,
                TQ_SLOT(slotTransformsRestoreTies()), actionCollection(),
                "restore_ties");

    icon = TQIconSet
           (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                                         ("accmenu-doubleflat")));

    new TDEAction(RespellCommand::getGlobalName
                (RespellCommand::Set, Accidentals::DoubleFlat),
                icon, 0, this,
                TQ_SLOT(slotRespellDoubleFlat()), actionCollection(),
                "respell_doubleflat");

    icon = TQIconSet
           (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                                         ("accmenu-flat")));

    new TDEAction(RespellCommand::getGlobalName
                (RespellCommand::Set, Accidentals::Flat),
                icon, 0, this,
                TQ_SLOT(slotRespellFlat()), actionCollection(),
                "respell_flat");

    icon = TQIconSet
           (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                                         ("accmenu-natural")));

    new TDEAction(RespellCommand::getGlobalName
                (RespellCommand::Set, Accidentals::Natural),
                icon, 0, this,
                TQ_SLOT(slotRespellNatural()), actionCollection(),
                "respell_natural");

    icon = TQIconSet
           (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                                         ("accmenu-sharp")));

    new TDEAction(RespellCommand::getGlobalName
                (RespellCommand::Set, Accidentals::Sharp),
                icon, 0, this,
                TQ_SLOT(slotRespellSharp()), actionCollection(),
                "respell_sharp");

    icon = TQIconSet
           (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                                         ("accmenu-doublesharp")));

    new TDEAction(RespellCommand::getGlobalName
                (RespellCommand::Set, Accidentals::DoubleSharp),
                icon, 0, this,
                TQ_SLOT(slotRespellDoubleSharp()), actionCollection(),
                "respell_doublesharp");

    new TDEAction(RespellCommand::getGlobalName
                (RespellCommand::Up, Accidentals::NoAccidental),
                Key_Up + CTRL + SHIFT, this,
                TQ_SLOT(slotRespellUp()), actionCollection(),
                "respell_up");

    new TDEAction(RespellCommand::getGlobalName
                (RespellCommand::Down, Accidentals::NoAccidental),
                Key_Down + CTRL + SHIFT, this,
                TQ_SLOT(slotRespellDown()), actionCollection(),
                "respell_down");

    new TDEAction(RespellCommand::getGlobalName
                (RespellCommand::Restore, Accidentals::NoAccidental),
                0, this,
                TQ_SLOT(slotRespellRestore()), actionCollection(),
                "respell_restore");

    new TDEAction(MakeAccidentalsCautionaryCommand::getGlobalName(true),
                0, this,
                TQ_SLOT(slotShowCautionary()), actionCollection(),
                "show_cautionary");

    new TDEAction(MakeAccidentalsCautionaryCommand::getGlobalName(false),
                0, this,
                TQ_SLOT(slotCancelCautionary()), actionCollection(),
                "cancel_cautionary");

    icon = TQIconSet
           (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                                         ("quantize")));

    new TDEAction(EventQuantizeCommand::getGlobalName(), icon, Key_Equal, this,
                TQ_SLOT(slotTransformsQuantize()), actionCollection(),
                "quantize");

    new TDEAction(FixNotationQuantizeCommand::getGlobalName(), 0,
                this, TQ_SLOT(slotTransformsFixQuantization()), actionCollection(),
                "fix_quantization");

    new TDEAction(RemoveNotationQuantizeCommand::getGlobalName(), 0,
                this, TQ_SLOT(slotTransformsRemoveQuantization()), actionCollection(),
                "remove_quantization");

    new TDEAction(InterpretCommand::getGlobalName(), 0,
                this, TQ_SLOT(slotTransformsInterpret()), actionCollection(),
                "interpret");

    new TDEAction(i18n("&Dump selected events to stderr"), 0, this,
                TQ_SLOT(slotDebugDump()), actionCollection(), "debug_dump");

    for (MarkActionDataMap::Iterator i = m_markActionDataMap->begin();
            i != m_markActionDataMap->end(); ++i) {

        const MarkActionData &markActionData = **i;

        icon = TQIconSet(NotePixmapFactory::toTQPixmap
                        (NotePixmapFactory::makeMarkMenuPixmap(markActionData.mark)));

        new TDEAction(markActionData.title,
                    icon,
                    markActionData.keycode,
                    this,
                    TQ_SLOT(slotAddMark()),
                    actionCollection(),
                    markActionData.actionName.ascii());
    }

    icon = TQIconSet
           (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                                         ("text-mark")));

    new TDEAction(AddTextMarkCommand::getGlobalName(), icon, 0, this,
                TQ_SLOT(slotMarksAddTextMark()), actionCollection(),
                "add_text_mark");

    new TDEAction(AddFingeringMarkCommand::getGlobalName("0"), 0, Key_0 + ALT, this,
                TQ_SLOT(slotMarksAddFingeringMarkFromAction()), actionCollection(),
                "add_fingering_0");

    new TDEAction(AddFingeringMarkCommand::getGlobalName("1"), 0, Key_1 + ALT, this,
                TQ_SLOT(slotMarksAddFingeringMarkFromAction()), actionCollection(),
                "add_fingering_1");

    new TDEAction(AddFingeringMarkCommand::getGlobalName("2"), 0, Key_2 + ALT, this,
                TQ_SLOT(slotMarksAddFingeringMarkFromAction()), actionCollection(),
                "add_fingering_2");

    new TDEAction(AddFingeringMarkCommand::getGlobalName("3"), 0, Key_3 + ALT, this,
                TQ_SLOT(slotMarksAddFingeringMarkFromAction()), actionCollection(),
                "add_fingering_3");

    new TDEAction(AddFingeringMarkCommand::getGlobalName("4"), 0, Key_4 + ALT, this,
                TQ_SLOT(slotMarksAddFingeringMarkFromAction()), actionCollection(),
                "add_fingering_4");

    new TDEAction(AddFingeringMarkCommand::getGlobalName("5"), 0, Key_5 + ALT, this,
                TQ_SLOT(slotMarksAddFingeringMarkFromAction()), actionCollection(),
                "add_fingering_5");

    new TDEAction(AddFingeringMarkCommand::getGlobalName("+"), 0, Key_9 + ALT, this,
                TQ_SLOT(slotMarksAddFingeringMarkFromAction()), actionCollection(),
                "add_fingering_plus");

    new TDEAction(AddFingeringMarkCommand::getGlobalName(), 0, 0, this,
                TQ_SLOT(slotMarksAddFingeringMark()), actionCollection(),
                "add_fingering_mark");

    new TDEAction(RemoveMarksCommand::getGlobalName(), 0, this,
                TQ_SLOT(slotMarksRemoveMarks()), actionCollection(),
                "remove_marks");

    new TDEAction(RemoveFingeringMarksCommand::getGlobalName(), 0, this,
                TQ_SLOT(slotMarksRemoveFingeringMarks()), actionCollection(),
                "remove_fingering_marks");

    new TDEAction(i18n("Ma&ke Ornament..."), 0, this,
                TQ_SLOT(slotMakeOrnament()), actionCollection(),
                "make_ornament");

    new TDEAction(i18n("Trigger &Ornament..."), 0, this,
                TQ_SLOT(slotUseOrnament()), actionCollection(),
                "use_ornament");

    new TDEAction(i18n("Remove Ornament..."), 0, this,
                TQ_SLOT(slotRemoveOrnament()), actionCollection(),
                "remove_ornament");

    static TQString slashTitles[] = {
                                       i18n("&None"), "&1", "&2", "&3", "&4", "&5"
                                   };
    for (int i = 0; i <= 5; ++i) {
        new TDEAction(slashTitles[i], 0, this,
                    TQ_SLOT(slotAddSlashes()), actionCollection(),
                    TQString("slashes_%1").arg(i).ascii());
    }

    new TDEAction(ClefInsertionCommand::getGlobalName(), 0, this,
                TQ_SLOT(slotEditAddClef()), actionCollection(),
                "add_clef");

    new TDEAction(KeyInsertionCommand::getGlobalName(), 0, this,
                TQ_SLOT(slotEditAddKeySignature()), actionCollection(),
                "add_key_signature");

    new TDEAction(SustainInsertionCommand::getGlobalName(true), 0, this,
                TQ_SLOT(slotEditAddSustainDown()), actionCollection(),
                "add_sustain_down");

    new TDEAction(SustainInsertionCommand::getGlobalName(false), 0, this,
                TQ_SLOT(slotEditAddSustainUp()), actionCollection(),
                "add_sustain_up");

    new TDEAction(TransposeCommand::getDiatonicGlobalName(false), 0, this,
                TQ_SLOT(slotEditTranspose()), actionCollection(),
                "transpose_segment");

	new TDEAction(i18n("Convert Notation For..."), 0, this,
                TQ_SLOT(slotEditSwitchPreset()), actionCollection(),
                "switch_preset");


    // setup Settings menu
    static TQString actionsToolbars[][4] =
        {
            { i18n("Show T&ools Toolbar"), "1slotToggleToolsToolBar()", "show_tools_toolbar", "palette-tools" },
            { i18n("Show &Notes Toolbar"), "1slotToggleNotesToolBar()", "show_notes_toolbar", "palette-notes" },
            { i18n("Show &Rests Toolbar"), "1slotToggleRestsToolBar()", "show_rests_toolbar", "palette-rests" },
            { i18n("Show &Accidentals Toolbar"), "1slotToggleAccidentalsToolBar()", "show_accidentals_toolbar", "palette-accidentals" },
            { i18n("Show Cle&fs Toolbar"), "1slotToggleClefsToolBar()", "show_clefs_toolbar",
              "palette-clefs" },
            { i18n("Show &Marks Toolbar"), "1slotToggleMarksToolBar()", "show_marks_toolbar",
              "palette-marks" },
            { i18n("Show &Group Toolbar"), "1slotToggleGroupToolBar()", "show_group_toolbar",
              "palette-group" },
            { i18n("Show &Layout Toolbar"), "1slotToggleLayoutToolBar()", "show_layout_toolbar",
              "palette-font" },
            { i18n("Show Trans&port Toolbar"), "1slotToggleTransportToolBar()", "show_transport_toolbar",
              "palette-transport" },
            { i18n("Show M&eta Toolbar"), "1slotToggleMetaToolBar()", "show_meta_toolbar",
              "palette-meta" }
        };

    for (unsigned int i = 0;
            i < sizeof(actionsToolbars) / sizeof(actionsToolbars[0]); ++i) {

        icon = TQIconSet(NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap(actionsToolbars[i][3].ascii())));

        new TDEToggleAction(actionsToolbars[i][0], icon, 0,
                          this, actionsToolbars[i][1].ascii(),
                          actionCollection(), actionsToolbars[i][2].ascii());
    }

    new TDEAction(i18n("Cursor &Back"), 0, Key_Left, this,
                TQ_SLOT(slotStepBackward()), actionCollection(),
                "cursor_back");

    new TDEAction(i18n("Cursor &Forward"), 0, Key_Right, this,
                TQ_SLOT(slotStepForward()), actionCollection(),
                "cursor_forward");

    new TDEAction(i18n("Cursor Ba&ck Bar"), 0, Key_Left + CTRL, this,
                TQ_SLOT(slotJumpBackward()), actionCollection(),
                "cursor_back_bar");

    new TDEAction(i18n("Cursor For&ward Bar"), 0, Key_Right + CTRL, this,
                TQ_SLOT(slotJumpForward()), actionCollection(),
                "cursor_forward_bar");

    new TDEAction(i18n("Cursor Back and Se&lect"), SHIFT + Key_Left, this,
                TQ_SLOT(slotExtendSelectionBackward()), actionCollection(),
                "extend_selection_backward");

    new TDEAction(i18n("Cursor Forward and &Select"), SHIFT + Key_Right, this,
                TQ_SLOT(slotExtendSelectionForward()), actionCollection(),
                "extend_selection_forward");

    new TDEAction(i18n("Cursor Back Bar and Select"), SHIFT + CTRL + Key_Left, this,
                TQ_SLOT(slotExtendSelectionBackwardBar()), actionCollection(),
                "extend_selection_backward_bar");

    new TDEAction(i18n("Cursor Forward Bar and Select"), SHIFT + CTRL + Key_Right, this,
                TQ_SLOT(slotExtendSelectionForwardBar()), actionCollection(),
                "extend_selection_forward_bar");

    /*!!! not here yet
        new TDEAction(i18n("Move Selection Left"), Key_Minus, this,
    		TQ_SLOT(slotMoveSelectionLeft()), actionCollection(),
    		"move_selection_left");
    */

    new TDEAction(i18n("Cursor to St&art"), 0,
                /* #1025717: conflicting meanings for ctrl+a - dupe with Select All
                  Key_A + CTRL, */ this, 
                TQ_SLOT(slotJumpToStart()), actionCollection(),
                "cursor_start");

    new TDEAction(i18n("Cursor to &End"), 0, Key_E + CTRL, this,
                TQ_SLOT(slotJumpToEnd()), actionCollection(),
                "cursor_end");

    new TDEAction(i18n("Cursor &Up Staff"), 0, Key_Up + SHIFT, this,
                TQ_SLOT(slotCurrentStaffUp()), actionCollection(),
                "cursor_up_staff");

    new TDEAction(i18n("Cursor &Down Staff"), 0, Key_Down + SHIFT, this,
                TQ_SLOT(slotCurrentStaffDown()), actionCollection(),
                "cursor_down_staff");

    new TDEAction(i18n("Cursor Pre&vious Segment"), 0, Key_Prior + ALT, this,
                TQ_SLOT(slotCurrentSegmentPrior()), actionCollection(),
                "cursor_prior_segment");

    new TDEAction(i18n("Cursor Ne&xt Segment"), 0, Key_Next + ALT, this,
                TQ_SLOT(slotCurrentSegmentNext()), actionCollection(),
                "cursor_next_segment");

    icon = TQIconSet(NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                    ("transport-cursor-to-pointer")));
    new TDEAction(i18n("Cursor to &Playback Pointer"), icon, 0, this,
                TQ_SLOT(slotJumpCursorToPlayback()), actionCollection(),
                "cursor_to_playback_pointer");

    icon = TQIconSet(NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                    ("transport-play")));
    TDEAction *play = new TDEAction(i18n("&Play"), icon, Key_Enter, this,
                TQ_SIGNAL(play()), actionCollection(), "play");
    // Alternative shortcut for Play
    TDEShortcut playShortcut = play->shortcut();
    playShortcut.append( KKey(Key_Return + CTRL) );
    play->setShortcut(playShortcut);

    icon = TQIconSet(NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                    ("transport-stop")));
    new TDEAction(i18n("&Stop"), icon, Key_Insert, this,
                TQ_SIGNAL(stop()), actionCollection(), "stop");

    icon = TQIconSet(NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                    ("transport-rewind")));
    new TDEAction(i18n("Re&wind"), icon, Key_End, this,
                TQ_SIGNAL(rewindPlayback()), actionCollection(),
                "playback_pointer_back_bar");

    icon = TQIconSet(NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                    ("transport-ffwd")));
    new TDEAction(i18n("&Fast Forward"), icon, Key_PageDown, this,
                TQ_SIGNAL(fastForwardPlayback()), actionCollection(),
                "playback_pointer_forward_bar");

    icon = TQIconSet(NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                    ("transport-rewind-end")));
    new TDEAction(i18n("Rewind to &Beginning"), icon, 0, this,
                TQ_SIGNAL(rewindPlaybackToBeginning()), actionCollection(),
                "playback_pointer_start");

    icon = TQIconSet(NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                    ("transport-ffwd-end")));
    new TDEAction(i18n("Fast Forward to &End"), icon, 0, this,
                TQ_SIGNAL(fastForwardPlaybackToEnd()), actionCollection(),
                "playback_pointer_end");

    icon = TQIconSet(NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                    ("transport-pointer-to-cursor")));
    new TDEAction(i18n("Playback Pointer to &Cursor"), icon, 0, this,
                TQ_SLOT(slotJumpPlaybackToCursor()), actionCollection(),
                "playback_pointer_to_cursor");

    icon = TQIconSet(NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                    ("transport-solo")));
    new TDEToggleAction(i18n("&Solo"), icon, 0, this,
                      TQ_SLOT(slotToggleSolo()), actionCollection(),
                      "toggle_solo");

    icon = TQIconSet(NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                    ("transport-tracking")));
    (new TDEToggleAction(i18n("Scro&ll to Follow Playback"), icon, Key_Pause, this,
                       TQ_SLOT(slotToggleTracking()), actionCollection(),
                       "toggle_tracking"))->setChecked(m_playTracking);

    icon = TQIconSet(NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap
                    ("transport-panic")));
    new TDEAction(i18n("Panic"), icon, Key_P + CTRL + ALT, this,
                TQ_SIGNAL(panic()), actionCollection(), "panic");

    new TDEAction(i18n("Set Loop to Selection"), Key_Semicolon + CTRL, this,
                TQ_SLOT(slotPreviewSelection()), actionCollection(),
                "preview_selection");

    new TDEAction(i18n("Clear L&oop"), Key_Colon + CTRL, this,
                TQ_SLOT(slotClearLoop()), actionCollection(),
                "clear_loop");

    new TDEAction(i18n("Clear Selection"), Key_Escape, this,
                TQ_SLOT(slotClearSelection()), actionCollection(),
                "clear_selection");

    //    TQString pixmapDir =
    //	TDEGlobal::dirs()->findResource("appdata", "pixmaps/");
    //    icon = TQIconSet(TQCanvasPixmap(pixmapDir + "/toolbar/eventfilter.xpm"));
    new TDEAction(i18n("&Filter Selection"), "filter", Key_F + CTRL, this,
                TQ_SLOT(slotFilterSelection()), actionCollection(),
                "filter_selection");

    new TDEAction(i18n("Push &Left"), 0, this,
                TQ_SLOT(slotFinePositionLeft()), actionCollection(),
                "fine_position_left");

    new TDEAction(i18n("Push &Right"), 0, this,
                TQ_SLOT(slotFinePositionRight()), actionCollection(),
                "fine_position_right");

    new TDEAction(i18n("Push &Up"), 0, this,
                TQ_SLOT(slotFinePositionUp()), actionCollection(),
                "fine_position_up");

    new TDEAction(i18n("Push &Down"), 0, this,
                TQ_SLOT(slotFinePositionDown()), actionCollection(),
                "fine_position_down");

    new TDEAction(i18n("&Restore Positions"), 0, this,
                TQ_SLOT(slotFinePositionRestore()), actionCollection(),
                "fine_position_restore");

    new TDEAction(i18n("Make &Invisible"), 0, this,
                TQ_SLOT(slotMakeInvisible()), actionCollection(),
                "make_invisible");

    new TDEAction(i18n("Make &Visible"), 0, this,
                TQ_SLOT(slotMakeVisible()), actionCollection(),
                "make_visible");

    new TDEAction(i18n("Toggle Dot"), Key_Period, this,
                TQ_SLOT(slotToggleDot()), actionCollection(),
                "toggle_dot");

    new TDEAction(i18n("Add Dot"), Key_Period + CTRL, this,
                TQ_SLOT(slotAddDot()), actionCollection(),
                "add_dot");

    new TDEAction(i18n("Add Dot"), Key_Period + CTRL + ALT, this,
                TQ_SLOT(slotAddDotNotationOnly()), actionCollection(),
                "add_notation_dot");

    createGUI(getRCFileName(), false);
}

bool
NotationView::isInChordMode()
{
    return ((TDEToggleAction *)actionCollection()->action("chord_mode"))->
           isChecked();
}

bool
NotationView::isInTripletMode()
{
    return ((TDEToggleAction *)actionCollection()->action("triplet_mode"))->
           isChecked();
}

bool
NotationView::isInGraceMode()
{
    return ((TDEToggleAction *)actionCollection()->action("grace_mode"))->
           isChecked();
}

void
NotationView::setupFontSizeMenu(std::string oldFontName)
{
    if (oldFontName != "") {

        std::vector<int> sizes = NoteFontFactory::getScreenSizes(oldFontName);

        for (unsigned int i = 0; i < sizes.size(); ++i) {
            TDEAction *action =
                actionCollection()->action
                (TQString("note_font_size_%1").arg(sizes[i]).ascii());
            m_fontSizeActionMenu->remove
            (action);

            // Don't delete -- that could cause a crash when this
            // function is called from the action itself.  Instead
            // we reuse and reinsert existing actions below.
        }
    }

    std::vector<int> sizes = NoteFontFactory::getScreenSizes(m_fontName);

    for (unsigned int i = 0; i < sizes.size(); ++i) {

        TQString actionName = TQString("note_font_size_%1").arg(sizes[i]);

        TDEToggleAction *sizeAction = dynamic_cast<TDEToggleAction *>
                                    (actionCollection()->action(actionName.ascii()));

        if (!sizeAction) {
            sizeAction =
                new TDEToggleAction(i18n("1 pixel", "%n pixels", sizes[i]),
                                  0, this,
                                  TQ_SLOT(slotChangeFontSizeFromAction()),
                                  actionCollection(), actionName.ascii());
        }

        sizeAction->setChecked(sizes[i] == m_fontSize);
        m_fontSizeActionMenu->insert(sizeAction);
    }
}

LinedStaff *
NotationView::getLinedStaff(int i)
{
    return getNotationStaff(i);
}

LinedStaff *
NotationView::getLinedStaff(const Segment &segment)
{
    return getNotationStaff(segment);
}

NotationStaff *
NotationView::getNotationStaff(const Segment &segment)
{
    for (unsigned int i = 0; i < m_staffs.size(); ++i) {
        if (&(m_staffs[i]->getSegment()) == &segment)
            return m_staffs[i];
    }
    return 0;
}

bool NotationView::isCurrentStaff(int i)
{
    return getCurrentSegment() == &(m_staffs[i]->getSegment());
}

void NotationView::initLayoutToolbar()
{
    TDEToolBar *layoutToolbar = toolBar("Layout Toolbar");

    if (!layoutToolbar) {
        std::cerr
        << "NotationView::initLayoutToolbar() : layout toolbar not found"
        << std::endl;
        return ;
    }

    new TQLabel(i18n("  Font:  "), layoutToolbar, "font label");

    //
    // font combo
    //
    m_fontCombo = new KComboBox(layoutToolbar);
    m_fontCombo->setEditable(false);

    std::set
        <std::string> fs(NoteFontFactory::getFontNames());
    std::vector<std::string> f(fs.begin(), fs.end());
    std::sort(f.begin(), f.end());

    bool foundFont = false;

    for (std::vector<std::string>::iterator i = f.begin(); i != f.end(); ++i) {

        TQString fontTQName(strtoqstr(*i));

        m_fontCombo->insertItem(fontTQName);
        if (fontTQName.lower() == strtoqstr(m_fontName).lower()) {
            m_fontCombo->setCurrentItem(m_fontCombo->count() - 1);
            foundFont = true;
        }
    }

    if (!foundFont) {
        KMessageBox::sorry
        (this, i18n("Unknown font \"%1\", using default").arg
         (strtoqstr(m_fontName)));
        m_fontName = NoteFontFactory::getDefaultFontName();
    }

    connect(m_fontCombo, TQ_SIGNAL(activated(const TQString &)),
            this, TQ_SLOT(slotChangeFont(const TQString &)));

    new TQLabel(i18n("  Size:  "), layoutToolbar, "size label");

    TQString value;

    //
    // font size combo
    //
    std::vector<int> sizes = NoteFontFactory::getScreenSizes(m_fontName);
    m_fontSizeCombo = new KComboBox(layoutToolbar, "font size combo");

    for (std::vector<int>::iterator i = sizes.begin(); i != sizes.end(); ++i) {

        value.setNum(*i);
        m_fontSizeCombo->insertItem(value);
    }
    // set combo's current value to default
    value.setNum(m_fontSize);
    m_fontSizeCombo->setCurrentText(value);

    connect(m_fontSizeCombo, TQ_SIGNAL(activated(const TQString&)),
            this, TQ_SLOT(slotChangeFontSizeFromStringValue(const TQString&)));

    new TQLabel(i18n("  Spacing:  "), layoutToolbar, "spacing label");

    //
    // spacing combo
    //
    int defaultSpacing = m_hlayout->getSpacing();
    std::vector<int> spacings = NotationHLayout::getAvailableSpacings();

    m_spacingCombo = new KComboBox(layoutToolbar, "spacing combo");
    for (std::vector<int>::iterator i = spacings.begin(); i != spacings.end(); ++i) {

        value.setNum(*i);
        value += "%";
        m_spacingCombo->insertItem(value);
    }
    // set combo's current value to default
    value.setNum(defaultSpacing);
    value += "%";
    m_spacingCombo->setCurrentText(value);

    connect(m_spacingCombo, TQ_SIGNAL(activated(const TQString&)),
            this, TQ_SLOT(slotChangeSpacingFromStringValue(const TQString&)));
}

void NotationView::initStatusBar()
{
    KStatusBar* sb = statusBar();

    m_hoveredOverNoteName = new TQLabel(sb);
    m_hoveredOverNoteName->setMinimumWidth(32);

    m_hoveredOverAbsoluteTime = new TQLabel(sb);
    m_hoveredOverAbsoluteTime->setMinimumWidth(160);

    sb->addWidget(m_hoveredOverAbsoluteTime);
    sb->addWidget(m_hoveredOverNoteName);

    TQHBox *hbox = new TQHBox(sb);
    m_currentNotePixmap = new TQLabel(hbox);
    m_currentNotePixmap->setMinimumWidth(20);
    m_insertModeLabel = new TQLabel(hbox);
    m_annotationsLabel = new TQLabel(hbox);
    m_lilyPondDirectivesLabel = new TQLabel(hbox);
    sb->addWidget(hbox);

    sb->insertItem(KTmpStatusMsg::getDefaultMsg(),
                   KTmpStatusMsg::getDefaultId(), 1);
    sb->setItemAlignment(KTmpStatusMsg::getDefaultId(),
                         AlignLeft | AlignVCenter);

    m_selectionCounter = new TQLabel(sb);
    sb->addWidget(m_selectionCounter);

    m_progressBar = new ProgressBar(100, true, sb);
    m_progressBar->setMinimumWidth(100);
    sb->addWidget(m_progressBar);
}

TQSize NotationView::getViewSize()
{
    return canvas()->size();
}

void NotationView::setViewSize(TQSize s)
{
    canvas()->resize(s.width(), s.height());

    if (   (m_pageMode == LinedStaff::LinearMode)
        && (m_showHeadersGroup != HeadersGroup::ShowNever)) {
        m_headersGroup->completeToHeight(s.height());
    }
}

void
NotationView::setPageMode(LinedStaff::PageMode pageMode)
{
    m_pageMode = pageMode;

    if (pageMode != LinedStaff::LinearMode) {
        if (m_topStandardRuler)
            m_topStandardRuler->hide();
        if (m_bottomStandardRuler)
            m_bottomStandardRuler->hide();
        if (m_chordNameRuler)
            m_chordNameRuler->hide();
        if (m_rawNoteRuler)
            m_rawNoteRuler->hide();
        if (m_tempoRuler)
            m_tempoRuler->hide();
        hideHeadersGroup();
    } else {
        if (m_topStandardRuler)
            m_topStandardRuler->show();
        if (m_bottomStandardRuler)
            m_bottomStandardRuler->show();
        if (m_chordNameRuler && getToggleAction("show_chords_ruler")->isChecked())
            m_chordNameRuler->show();
        if (m_rawNoteRuler && getToggleAction("show_raw_note_ruler")->isChecked())
            m_rawNoteRuler->show();
        if (m_tempoRuler && getToggleAction("show_tempo_ruler")->isChecked())
            m_tempoRuler->show();
        showHeadersGroup();
    }

    stateChanged("linear_mode",
                 (pageMode == LinedStaff::LinearMode ? KXMLGUIClient::StateNoReverse :
                  KXMLGUIClient::StateReverse));

    int pageWidth = getPageWidth();
    int topMargin = 0, leftMargin = 0;
    getPageMargins(leftMargin, topMargin);

    m_hlayout->setPageMode(pageMode != LinedStaff::LinearMode);
    m_hlayout->setPageWidth(pageWidth - leftMargin * 2);

    NOTATION_DEBUG << "NotationView::setPageMode: set layout's page width to "
    << (pageWidth - leftMargin * 2) << endl;

    positionStaffs();

    bool layoutApplied = applyLayout();
    if (!layoutApplied)
        KMessageBox::sorry(0, "Couldn't apply layout");
    else {
        for (unsigned int i = 0; i < m_staffs.size(); ++i) {
            m_staffs[i]->markChanged();
        }
    }

    if (!m_printMode) {
        // Layout is done : Time related to left of canvas should now
        // correctly be determined and track headers contents be drawn.
        m_headersGroup->slotUpdateAllHeaders(0, 0, true);
    }

    positionPages();

    if (!m_printMode) {
        updateView();
        slotSetInsertCursorPosition(getInsertionTime(), false, false);
        slotSetPointerPosition(getDocument()->getComposition().getPosition(), false);
    }

    Profiles::getInstance()->dump();
}

int
NotationView::getPageWidth()
{
    if (m_pageMode != LinedStaff::MultiPageMode) {

        if (isInPrintMode() && getCanvasView() && getCanvasView()->canvas())
            return getCanvasView()->canvas()->width();

        if (getCanvasView()) {
            return
                getCanvasView()->width() -
                getCanvasView()->verticalScrollBar()->width() -
                m_leftGutter - 10;
        }

        return width() - 50;

    } else {

        //!!! For the moment we use A4 for this calculation

        double printSizeMm = 25.4 * ((double)m_printSize / 72.0);
        double mmPerPixel = printSizeMm / (double)m_notePixmapFactory->getSize();
        return (int)(210.0 / mmPerPixel);
    }
}

int
NotationView::getPageHeight()
{
    if (m_pageMode != LinedStaff::MultiPageMode) {

        if (isInPrintMode() && getCanvasView() && getCanvasView()->canvas())
            return getCanvasView()->canvas()->height();

        if (getCanvasView()) {
            return getCanvasView()->height();
        }

        return (height() > 200 ? height() - 100 : height());

    } else {

        //!!! For the moment we use A4 for this calculation

        double printSizeMm = 25.4 * ((double)m_printSize / 72.0);
        double mmPerPixel = printSizeMm / (double)m_notePixmapFactory->getSize();
        return (int)(297.0 / mmPerPixel);
    }
}

void
NotationView::getPageMargins(int &left, int &top)
{
    if (m_pageMode != LinedStaff::MultiPageMode) {

        left = 0;
        top = 0;

    } else {

        //!!! For the moment we use A4 for this calculation

        double printSizeMm = 25.4 * ((double)m_printSize / 72.0);
        double mmPerPixel = printSizeMm / (double)m_notePixmapFactory->getSize();
        left = (int)(20.0 / mmPerPixel);
        top = (int)(15.0 / mmPerPixel);
    }
}

void
NotationView::scrollToTime(timeT t)
{

    double notationViewLayoutCoord = m_hlayout->getXForTime(t);

    // Doesn't appear to matter which staff we use
    //!!! actually it probably does matter, if they don't have the same extents
    double notationViewCanvasCoord =
        getLinedStaff(0)->getCanvasCoordsForLayoutCoords
        (notationViewLayoutCoord, 0).first;

    // HK: I could have sworn I saw a hard-coded scroll happen somewhere
    // (i.e. a default extra scroll to make up for the staff not beginning on
    // the left edge) but now I can't find it.
    getCanvasView()->slotScrollHorizSmallSteps
    (int(notationViewCanvasCoord)); // + DEFAULT_STAFF_OFFSET);
}

RulerScale*
NotationView::getHLayout()
{
    return m_hlayout;
}

void
NotationView::paintEvent(TQPaintEvent *e)
{
    m_inPaintEvent = true;

    // This is duplicated here from EditViewBase, because (a) we need
    // to know about the segment being removed before we try to check
    // the staff names etc., and (b) it's not safe to call close()
    // from EditViewBase::paintEvent if we're then going to try to do
    // some more work afterwards in this function

    if (isCompositionModified()) {

        // Check if one of the segments we display has been removed
        // from the composition.
        //
        // For the moment we'll have to close the view if any of the
        // segments we handle has been deleted.

        for (unsigned int i = 0; i < m_segments.size(); ++i) {

            if (!m_segments[i]->getComposition()) {
                // oops, I think we've been deleted
                close();
                return ;
            }
        }
    }

    int topMargin = 0, leftMargin = 0;
    getPageMargins(leftMargin, topMargin);

    if (m_pageMode == LinedStaff::ContinuousPageMode) {
        // relayout if the window width changes significantly in continuous page mode
        int diff = int(getPageWidth() - leftMargin * 2 - m_hlayout->getPageWidth());
        if (diff < -10 || diff > 10) {
            setPageMode(m_pageMode);
            refreshSegment(0, 0, 0);
        }

    } else if (m_pageMode == LinedStaff::LinearMode) {
        // resize canvas again if the window height has changed significantly
        if (getCanvasView() && getCanvasView()->canvas()) {
            int diff = int(getPageHeight() - getCanvasView()->canvas()->height());
            if (diff > 10) {
                readjustCanvasSize();
            }
        }
    }

    // check for staff name changes
    for (unsigned int i = 0; i < m_staffs.size(); ++i) {
        if (!m_staffs[i]->isStaffNameUpToDate()) {
            refreshSegment(0);
            break;
        }
    }

    m_inPaintEvent = false;

    EditView::paintEvent(e);

    m_inPaintEvent = false;

    // now deal with any backlog of insertable notes that appeared
    // during paint (because it's not safe to modify a segment from
    // within a sub-event-loop in a processEvents call from a paint)
    if (!m_pendingInsertableNotes.empty()) {
        std::vector<std::pair<int, int> > notes = m_pendingInsertableNotes;
        m_pendingInsertableNotes.clear();
        for (unsigned int i = 0; i < notes.size(); ++i) {
            slotInsertableNoteEventReceived(notes[i].first, notes[i].second, true);
        }
    }

    slotSetOperationNameAndStatus(i18n("  Ready."));
}

bool NotationView::applyLayout(int staffNo, timeT startTime, timeT endTime)
{
    slotSetOperationNameAndStatus(i18n("Laying out score..."));
    ProgressDialog::processEvents();

    m_hlayout->setStaffCount(m_staffs.size());

    Profiler profiler("NotationView::applyLayout");
    unsigned int i;

    for (i = 0; i < m_staffs.size(); ++i) {

        if (staffNo >= 0 && (int)i != staffNo)
            continue;

        slotSetOperationNameAndStatus(i18n("Laying out staff %1...").arg(i + 1));
        ProgressDialog::processEvents();

        m_hlayout->resetStaff(*m_staffs[i], startTime, endTime);
        m_vlayout->resetStaff(*m_staffs[i], startTime, endTime);
        m_hlayout->scanStaff(*m_staffs[i], startTime, endTime);
        m_vlayout->scanStaff(*m_staffs[i], startTime, endTime);
    }

    slotSetOperationNameAndStatus(i18n("Reconciling staffs..."));
    ProgressDialog::processEvents();

    m_hlayout->finishLayout(startTime, endTime);
    m_vlayout->finishLayout(startTime, endTime);

    // find the last finishing staff for future use

    timeT lastFinishingStaffEndTime = 0;
    bool haveEndTime = false;
    m_lastFinishingStaff = -1;

    timeT firstStartingStaffStartTime = 0;
    bool haveStartTime = false;
    int firstStartingStaff = -1;

    for (i = 0; i < m_staffs.size(); ++i) {

        timeT thisStartTime = m_staffs[i]->getSegment().getStartTime();
        if (thisStartTime < firstStartingStaffStartTime || !haveStartTime) {
            firstStartingStaffStartTime = thisStartTime;
            haveStartTime = true;
            firstStartingStaff = i;
        }

        timeT thisEndTime = m_staffs[i]->getSegment().getEndTime();
        if (thisEndTime > lastFinishingStaffEndTime || !haveEndTime) {
            lastFinishingStaffEndTime = thisEndTime;
            haveEndTime = true;
            m_lastFinishingStaff = i;
        }
    }

    readjustCanvasSize();
    if (m_topStandardRuler) {
        m_topStandardRuler->update();
    }
    if (m_bottomStandardRuler) {
        m_bottomStandardRuler->update();
    }
    if (m_tempoRuler && m_tempoRuler->isVisible()) {
        m_tempoRuler->update();
    }
    if (m_rawNoteRuler && m_rawNoteRuler->isVisible()) {
        m_rawNoteRuler->update();
    }

    return true;
}

void NotationView::setCurrentSelectedNote(const char *pixmapName,
                                          bool rest, Note::Type n, int dots)
{
    NoteInserter* inserter = 0;

    if (rest)
        inserter = dynamic_cast<NoteInserter*>(m_toolBox->getTool(RestInserter::ToolName));
    else
        inserter = dynamic_cast<NoteInserter*>(m_toolBox->getTool(NoteInserter::ToolName));

    inserter->slotSetNote(n);
    inserter->slotSetDots(dots);

    setTool(inserter);

    m_currentNotePixmap->setPixmap
        (NotePixmapFactory::toTQPixmap
         (NotePixmapFactory::makeToolbarPixmap(pixmapName, true)));

    emit changeCurrentNote(rest, n);
}

void NotationView::setCurrentSelectedNote(const NoteActionData &noteAction)
{
    setCurrentSelectedNote(noteAction.pixmapName.ascii(),
                           noteAction.rest,
                           noteAction.noteType,
                           noteAction.dots);
}

void NotationView::setCurrentSelection(EventSelection* s, bool preview,
                                       bool redrawNow)
{
    //!!! rather too much here shared with matrixview -- could much of
    // this be in editview?

    if (m_currentEventSelection == s)
        return ;
    NOTATION_DEBUG << "XXX " << endl;

    EventSelection *oldSelection = m_currentEventSelection;
    m_currentEventSelection = s;

    // positionElements is overkill here, but we hope it's not too
    // much overkill (if that's not a contradiction)

    timeT startA, endA, startB, endB;

    if (oldSelection) {
        startA = oldSelection->getStartTime();
        endA = oldSelection->getEndTime();
        startB = s ? s->getStartTime() : startA;
        endB = s ? s->getEndTime() : endA;
    } else {
        // we know they can't both be null -- first thing we tested above
        startA = startB = s->getStartTime();
        endA = endB = s->getEndTime();
    }

    // refreshSegment takes start==end to mean refresh everything
    if (startA == endA)
        ++endA;
    if (startB == endB)
        ++endB;

    bool updateRequired = true;

    // play previews if appropriate -- also permits an optimisation
    // for the case where the selection is unchanged (quite likely
    // when sweeping)

    if (s && preview) {

        bool foundNewEvent = false;

        for (EventSelection::eventcontainer::iterator i =
                    s->getSegmentEvents().begin();
                i != s->getSegmentEvents().end(); ++i) {

            if (oldSelection && oldSelection->getSegment() == s->getSegment()
                    && oldSelection->contains(*i))
                continue;

            foundNewEvent = true;

            long pitch;
            if (!(*i)->get
                    <Int>(BaseProperties::PITCH,
                          pitch)) continue;

            long velocity = -1;
            (void)(*i)->get
            <Int>(BaseProperties::VELOCITY,
                  velocity);

            if (!((*i)->has(BaseProperties::TIED_BACKWARD) &&
                    (*i)->get
                    <Bool>
                    (BaseProperties::TIED_BACKWARD)))
                playNote(s->getSegment(), pitch, velocity);
        }

        if (!foundNewEvent) {
            if (oldSelection &&
                    oldSelection->getSegment() == s->getSegment() &&
                    oldSelection->getSegmentEvents().size() ==
                    s->getSegmentEvents().size())
                updateRequired = false;
        }
    }

    if (updateRequired) {

        if (!s || !oldSelection ||
                (endA >= startB && endB >= startA &&
                 oldSelection->getSegment() == s->getSegment())) {

            // the regions overlap: use their union and just do one refresh

            Segment &segment(s ? s->getSegment() :
                             oldSelection->getSegment());

            if (redrawNow) {
                // recolour the events now
                getLinedStaff(segment)->positionElements(std::min(startA, startB),
                        std::max(endA, endB));
            } else {
                // mark refresh status and then request a repaint
                segment.getRefreshStatus
                (m_segmentsRefreshStatusIds
                 [getLinedStaff(segment)->getId()]).
                push(std::min(startA, startB), std::max(endA, endB));
            }

        } else {
            // do two refreshes, one for each -- here we know neither is null

            if (redrawNow) {
                // recolour the events now
                getLinedStaff(oldSelection->getSegment())->positionElements(startA,
                        endA);

                getLinedStaff(s->getSegment())->positionElements(startB, endB);
            } else {
                // mark refresh status and then request a repaint

                oldSelection->getSegment().getRefreshStatus
                (m_segmentsRefreshStatusIds
                 [getLinedStaff(oldSelection->getSegment())->getId()]).
                push(startA, endA);

                s->getSegment().getRefreshStatus
                (m_segmentsRefreshStatusIds
                 [getLinedStaff(s->getSegment())->getId()]).
                push(startB, endB);
            }
        }

        if (s) {
            // make the staff containing the selection current
            int staffId = getLinedStaff(s->getSegment())->getId();
            if (staffId != m_currentStaff)
                slotSetCurrentStaff(staffId);
        }
    }

    delete oldSelection;

    statusBar()->changeItem(KTmpStatusMsg::getDefaultMsg(),
                            KTmpStatusMsg::getDefaultId());

    if (s) {
        int eventsSelected = s->getSegmentEvents().size();
        m_selectionCounter->setText
        (i18n("  1 event selected ",
              "  %n events selected ", eventsSelected));
    } else {
        m_selectionCounter->setText(i18n("  No selection "));
    }
    m_selectionCounter->update();

    setMenuStates();

    if (redrawNow)
        updateView();
    else
        update();

    NOTATION_DEBUG << "XXX " << endl;
}

void NotationView::setSingleSelectedEvent(int staffNo, Event *event,
        bool preview, bool redrawNow)
{
    setSingleSelectedEvent(getStaff(staffNo)->getSegment(), event,
                           preview, redrawNow);
}

void NotationView::setSingleSelectedEvent(Segment &segment, Event *event,
        bool preview, bool redrawNow)
{
    EventSelection *selection = new EventSelection(segment);
    selection->addEvent(event);
    setCurrentSelection(selection, preview, redrawNow);
}

bool NotationView::canPreviewAnotherNote()
{
    static time_t lastCutOff = 0;
    static int sinceLastCutOff = 0;

    time_t now = time(0);
    ++sinceLastCutOff;

    if ((now - lastCutOff) > 0) {
        sinceLastCutOff = 0;
        lastCutOff = now;
        NOTATION_DEBUG << "NotationView::canPreviewAnotherNote: reset" << endl;
    } else {
        if (sinceLastCutOff >= 20) {
            // don't permit more than 20 notes per second or so, to
            // avoid gungeing up the sound drivers
            NOTATION_DEBUG << "Rejecting preview (too busy)" << endl;
            return false;
        }
        NOTATION_DEBUG << "NotationView::canPreviewAnotherNote: ok" << endl;
    }

    return true;
}

void NotationView::playNote(Segment &s, int pitch, int velocity)
{
    Composition &comp = getDocument()->getComposition();
    Studio &studio = getDocument()->getStudio();
    Track *track = comp.getTrackById(s.getTrack());

    Instrument *ins =
        studio.getInstrumentById(track->getInstrument());

    // check for null instrument
    //
    if (ins == 0)
        return ;

    if (!canPreviewAnotherNote())
        return ;

    if (velocity < 0)
        velocity = MidiMaxValue;

    MappedEvent mE(ins->getId(),
                   MappedEvent::MidiNoteOneShot,
                   pitch + s.getTranspose(),
                   velocity,
                   RealTime::zeroTime,
                   RealTime(0, 250000000),
                   RealTime::zeroTime);

    StudioControl::sendMappedEvent(mE);
}

void NotationView::showPreviewNote(int staffNo, double layoutX,
                                   int pitch, int height,
                                   const Note &note, bool grace,
                                   int velocity)
{
    m_staffs[staffNo]->showPreviewNote(layoutX, height, note, grace);
    playNote(m_staffs[staffNo]->getSegment(), pitch, velocity);
}

void NotationView::clearPreviewNote()
{
    for (unsigned int i = 0; i < m_staffs.size(); ++i) {
        m_staffs[i]->clearPreviewNote();
    }
}

void NotationView::setNotePixmapFactory(NotePixmapFactory* f)
{
    delete m_notePixmapFactory;
    m_notePixmapFactory = f;
    if (m_hlayout)
        m_hlayout->setNotePixmapFactory(m_notePixmapFactory);
    if (m_vlayout)
        m_vlayout->setNotePixmapFactory(m_notePixmapFactory);
}

Segment *
NotationView::getCurrentSegment()
{
    Staff *staff = getCurrentStaff();
    return (staff ? &staff->getSegment() : 0);
}

bool
NotationView::hasSegment(Segment *segment)
{
    for (unsigned int i = 0; i < m_segments.size(); ++i) {
	if (segment == m_segments[i]) return true;
    }
    return false;
}


LinedStaff *
NotationView::getCurrentLinedStaff()
{
    return getLinedStaff(m_currentStaff);
}

LinedStaff *
NotationView::getStaffAbove()
{
    if (m_staffs.size() < 2) return 0;

    Composition *composition =
        m_staffs[m_currentStaff]->getSegment().getComposition();

    Track *track = composition->
        getTrackById(m_staffs[m_currentStaff]->getSegment().getTrack());
    if (!track) return 0;

    int position = track->getPosition();
    Track *newTrack = 0;

    while ((newTrack = composition->getTrackByPosition(--position))) {
        for (unsigned int i = 0; i < m_staffs.size(); ++i) {
            if (m_staffs[i]->getSegment().getTrack() == newTrack->getId()) {
                return m_staffs[i];
            }
        }
    }

    return 0;
}

LinedStaff *
NotationView::getStaffBelow()
{
    if (m_staffs.size() < 2) return 0;

    Composition *composition =
        m_staffs[m_currentStaff]->getSegment().getComposition();

    Track *track = composition->
        getTrackById(m_staffs[m_currentStaff]->getSegment().getTrack());
    if (!track) return 0;

    int position = track->getPosition();
    Track *newTrack = 0;

    while ((newTrack = composition->getTrackByPosition(++position))) {
        for (unsigned int i = 0; i < m_staffs.size(); ++i) {
            if (m_staffs[i]->getSegment().getTrack() == newTrack->getId()) {
                return m_staffs[i];
            }
        }
    }

    return 0;
}

timeT
NotationView::getInsertionTime()
{
    return m_insertionTime;
}

timeT
NotationView::getInsertionTime(Clef &clef,
                               Rosegarden::Key &key)
{
    // This fuss is solely to recover the clef and key: we already
    // set m_insertionTime to the right value when we first placed
    // the insert cursor.  We could get clef and key directly from
    // the segment but the staff has a more efficient lookup

    LinedStaff *staff = m_staffs[m_currentStaff];
    double layoutX = staff->getLayoutXOfInsertCursor();
    if (layoutX < 0) layoutX = 0;
    Event *clefEvt = 0, *keyEvt = 0;
    (void)staff->getElementUnderLayoutX(layoutX, clefEvt, keyEvt);

    if (clefEvt) clef = Clef(*clefEvt);
    else clef = Clef();

    if (keyEvt) key = Rosegarden::Key(*keyEvt);
    else key = Rosegarden::Key();

    return m_insertionTime;
}

LinedStaff*
NotationView::getStaffForCanvasCoords(int x, int y) const
{
    // (i)  Do not change staff, if mouse was clicked within the current staff.
    LinedStaff *s = m_staffs[m_currentStaff];
    if (s->containsCanvasCoords(x, y)) {
        LinedStaff::LinedStaffCoords coords =
            s->getLayoutCoordsForCanvasCoords(x, y);

        timeT t = m_hlayout->getTimeForX(coords.first);
	// In order to find the correct starting and ending bar of the segment,
	// make infinitesimal shifts (+1 and -1) towards its center.
	timeT t0 = getDocument()->getComposition().getBarStartForTime(m_staffs[m_currentStaff]->getSegment().getStartTime()+1);
	timeT t1 = getDocument()->getComposition().getBarEndForTime(m_staffs[m_currentStaff]->getSegment().getEndTime()-1);
        if (t >= t0 && t < t1) {
            return m_staffs[m_currentStaff];
        }
    }
    // (ii) Find staff under cursor, if clicked outside the current staff.
    for (unsigned int i = 0; i < m_staffs.size(); ++i) {

        LinedStaff *s = m_staffs[i];

        if (s->containsCanvasCoords(x, y)) {

            LinedStaff::LinedStaffCoords coords =
                s->getLayoutCoordsForCanvasCoords(x, y);

	    timeT t = m_hlayout->getTimeForX(coords.first);
	    // In order to find the correct starting and ending bar of the segment,
	    // make infinitesimal shifts (+1 and -1) towards its center.
	    timeT t0 = getDocument()->getComposition().getBarStartForTime(m_staffs[i]->getSegment().getStartTime()+1);
	    timeT t1 = getDocument()->getComposition().getBarEndForTime(m_staffs[i]->getSegment().getEndTime()-1);
	    if (t >= t0 && t < t1) {
                return m_staffs[i];
            }
        }
    }

    return 0;
}

void NotationView::updateView()
{
    slotCheckRendered
    (getCanvasView()->contentsX(),
     getCanvasView()->contentsX() + getCanvasView()->visibleWidth());
    canvas()->update();
}

void NotationView::print(bool previewOnly)
{
    if (m_staffs.size() == 0) {
        KMessageBox::error(0, "Nothing to print");
        return ;
    }

    Profiler profiler("NotationView::print");

    // We need to be in multi-page mode at this point

    int pageWidth = getPageWidth();
    int pageHeight = getPageHeight();
    int leftMargin = 0, topMargin = 0;
    getPageMargins(leftMargin, topMargin);
    int maxPageCount = 1;

    for (unsigned int i = 0; i < m_staffs.size(); ++i) {
        int pageCount = m_staffs[i]->getPageCount();
        NOTATION_DEBUG << "NotationView::print(): staff " << i << " reports " << pageCount << " pages " << endl;
        if (pageCount > maxPageCount)
            maxPageCount = pageCount;
    }

    KPrinter printer(true, TQPrinter::HighResolution);

    printer.setPageSelection(KPrinter::ApplicationSide);
    printer.setMinMax(1, maxPageCount + 1);

    if (previewOnly)
        printer.setPreviewOnly(true);
    else if (!printer.setup((TQWidget *)parent()))
        return ;

    TQPaintDeviceMetrics pdm(&printer);
    TQPainter printpainter(&printer);

    // Ideally we should aim to retain the aspect ratio and to move the
    // staffs so as to be centred after scaling.  But because we haven't
    // got around to the latter, let's lose the former too and just
    // expand to fit.

    // Retain aspect ratio when scaling
    double ratioX = (double)pdm.width() / (double)(pageWidth - leftMargin * 2),
                    ratioY = (double)pdm.height() / (double)(pageHeight - topMargin * 2);
    double ratio = std::min(ratioX, ratioY);
    printpainter.scale(ratio, ratio);

    //    printpainter.scale((double)pdm.width()  / (double)(pageWidth - leftMargin*2),
    //		       (double)pdm.height() / (double)(pageHeight - topMargin*2));
    printpainter.translate( -leftMargin, -topMargin);

    TQValueList<int> pages = printer.pageList();

    for (TQValueList<int>::Iterator pli = pages.begin();
            pli != pages.end(); ) { // incremented just below

        int page = *pli - 1;
        ++pli;
        if (page < 0 || page >= maxPageCount)
            continue;

        NOTATION_DEBUG << "Printing page " << page << endl;

        TQRect pageRect(m_leftGutter + leftMargin + pageWidth * page,
                       topMargin,
                       pageWidth - leftMargin,
                       pageHeight - topMargin);

        for (size_t i = 0; i < m_staffs.size(); ++i) {

            LinedStaff *staff = m_staffs[i];

            LinedStaff::LinedStaffCoords cc0 = staff->getLayoutCoordsForCanvasCoords
                                               (pageRect.x(), pageRect.y());

            LinedStaff::LinedStaffCoords cc1 = staff->getLayoutCoordsForCanvasCoords
                                               (pageRect.x() + pageRect.width(), pageRect.y() + pageRect.height());

            timeT t0 = m_hlayout->getTimeForX(cc0.first);
            timeT t1 = m_hlayout->getTimeForX(cc1.first);

            m_staffs[i]->setPrintPainter(&printpainter);
            m_staffs[i]->checkRendered(t0, t1);
        }

        // Supplying doublebuffer==true to this method appears to
        // slow down printing considerably but without it we get
        // all sorts of horrible artifacts (possibly related to
        // mishandling of pixmap masks?) in qt-3.0.  Let's permit
        // it as a "hidden" option.

        m_config->setGroup(NotationViewConfigGroup);

        NOTATION_DEBUG << "NotationView::print: calling TQCanvas::drawArea" << endl;

        {
            Profiler profiler("NotationView::print(TQCanvas::drawArea)");

            if (m_config->readBoolEntry("forcedoublebufferprinting", false)) {
                getCanvasView()->canvas()->drawArea(pageRect, &printpainter, true);
            } else {
                getCanvasView()->canvas()->drawArea(pageRect, &printpainter, false);
            }

        }

        NOTATION_DEBUG << "NotationView::print: TQCanvas::drawArea done" << endl;

        for (size_t i = 0; i < m_staffs.size(); ++i) {

            LinedStaff *staff = m_staffs[i];

            LinedStaff::LinedStaffCoords cc0 = staff->getLayoutCoordsForCanvasCoords
                                               (pageRect.x(), pageRect.y());

            LinedStaff::LinedStaffCoords cc1 = staff->getLayoutCoordsForCanvasCoords
                                               (pageRect.x() + pageRect.width(), pageRect.y() + pageRect.height());

            timeT t0 = m_hlayout->getTimeForX(cc0.first);
            timeT t1 = m_hlayout->getTimeForX(cc1.first);

            m_staffs[i]->renderPrintable(t0, t1);
        }

        printpainter.translate( -pageWidth, 0);

        if (pli != pages.end() && *pli - 1 < maxPageCount)
            printer.newPage();

        for (size_t i = 0; i < m_staffs.size(); ++i) {
            m_staffs[i]->markChanged(); // recover any memory used for this page
            PixmapArrayGC::deleteAll();
        }
    }

    for (size_t i = 0; i < m_staffs.size(); ++i) {
        for (Segment::iterator j = m_staffs[i]->getSegment().begin();
                j != m_staffs[i]->getSegment().end(); ++j) {
            removeViewLocalProperties(*j);
        }
        delete m_staffs[i];
    }
    m_staffs.clear();

    printpainter.end();

    Profiles::getInstance()->dump();
}

void
NotationView::updateThumbnails(bool complete)
{
    if (m_pageMode != LinedStaff::MultiPageMode)
        return ;

    int pageWidth = getPageWidth();
    int pageHeight = getPageHeight();
    int leftMargin = 0, topMargin = 0;
    getPageMargins(leftMargin, topMargin);
    int maxPageCount = 1;

    for (unsigned int i = 0; i < m_staffs.size(); ++i) {
        int pageCount = m_staffs[i]->getPageCount();
        if (pageCount > maxPageCount)
            maxPageCount = pageCount;
    }

    int thumbScale = 20;
    TQPixmap thumbnail(canvas()->width() / thumbScale,
                      canvas()->height() / thumbScale);
    thumbnail.fill(TQt::white);
    TQPainter thumbPainter(&thumbnail);

    if (complete) {

        thumbPainter.scale(1.0 / double(thumbScale), 1.0 / double(thumbScale));
        thumbPainter.setPen(TQt::black);
        thumbPainter.setBrush(TQt::white);

        /*
        	TQCanvas *canvas = getCanvasView()->canvas();
        	canvas->drawArea(TQRect(0, 0, canvas->width(), canvas->height()),
        			 &thumbPainter, false);
        */ 
        // hide small texts, as we get a crash in Xft when trying to
        // render them at this scale
        if (m_title)
            m_title->hide();
        if (m_subtitle)
            m_subtitle->hide();
        if (m_composer)
            m_composer->hide();
        if (m_copyright)
            m_copyright->hide();

        for (size_t page = 0; page < static_cast<size_t>(maxPageCount); ++page) {

            bool havePageNumber = ((m_pageNumbers.size() > page) &&
                                   (m_pageNumbers[page] != 0));
            if (havePageNumber)
                m_pageNumbers[page]->hide();

            TQRect pageRect(m_leftGutter + leftMargin * 2 + pageWidth * page,
                           topMargin * 2,
                           pageWidth - leftMargin*3,
                           pageHeight - topMargin*3);

            TQCanvas *canvas = getCanvasView()->canvas();
            canvas->drawArea(pageRect, &thumbPainter, false);

            if (havePageNumber)
                m_pageNumbers[page]->show();
        }

        if (m_title)
            m_title->show();
        if (m_subtitle)
            m_subtitle->show();
        if (m_composer)
            m_composer->show();
        if (m_copyright)
            m_copyright->show();

    } else {

        thumbPainter.setPen(TQt::black);

        for (int page = 0; page < maxPageCount; ++page) {

            int x = m_leftGutter + pageWidth * page + leftMargin / 4;
            int y = 20;
            int w = pageWidth - leftMargin / 2;
            int h = pageHeight;

            TQString str = TQString("%1").arg(page + 1);

            thumbPainter.drawRect(x / thumbScale, y / thumbScale,
                                  w / thumbScale, h / thumbScale);

            int tx = (x + w / 2) / thumbScale, ty = (y + h / 2) / thumbScale;
            tx -= thumbPainter.fontMetrics().width(str) / 2;
            thumbPainter.drawText(tx, ty, str);
        }
    }

    thumbPainter.end();
    if (m_pannerDialog)
        m_pannerDialog->scrollbox()->setThumbnail(thumbnail);
}

void NotationView::refreshSegment(Segment *segment,
                                  timeT startTime, timeT endTime)
{
    NOTATION_DEBUG << "*** " << endl;

    if (m_inhibitRefresh)
        return ;
    NOTATION_DEBUG << "NotationView::refreshSegment(" << segment << "," << startTime << "," << endTime << ")" << endl;
    Profiler foo("NotationView::refreshSegment");

    emit usedSelection();

    if (segment) {
        LinedStaff *staff = getLinedStaff(*segment);
        if (staff)
            applyLayout(staff->getId(), startTime, endTime);
    } else {
        applyLayout( -1, startTime, endTime);
    }

    for (unsigned int i = 0; i < m_staffs.size(); ++i) {

        Segment *ssegment = &m_staffs[i]->getSegment();
        bool thisStaff = (ssegment == segment || segment == 0);
        m_staffs[i]->markChanged(startTime, endTime, !thisStaff);
    }

    PixmapArrayGC::deleteAll();

    statusBar()->changeItem(KTmpStatusMsg::getDefaultMsg(),
                            KTmpStatusMsg::getDefaultId());

    Event::dumpStats(std::cerr);
    if (m_deferredCursorMove == NoCursorMoveNeeded) {
        slotSetInsertCursorPosition(getInsertionTime(), false, false);
    } else {
        doDeferredCursorMove();
    }
    slotSetPointerPosition(getDocument()->getComposition().getPosition(), false);

    if (m_currentEventSelection &&
            m_currentEventSelection->getSegmentEvents().size() == 0) {
        delete m_currentEventSelection;
        m_currentEventSelection = 0;
        //!!!??? was that the right thing to do?
    }

    setMenuStates();
    slotSetOperationNameAndStatus(i18n("  Ready."));
    NOTATION_DEBUG << "*** " << endl;
}

void NotationView::setMenuStates()
{
    // 1. set selection-related states

    // Clear states first, then enter only those ones that apply
    // (so as to avoid ever clearing one after entering another, in
    // case the two overlap at all)
    stateChanged("have_selection", KXMLGUIClient::StateReverse);
    stateChanged("have_notes_in_selection", KXMLGUIClient::StateReverse);
    stateChanged("have_rests_in_selection", KXMLGUIClient::StateReverse);

    if (m_currentEventSelection) {

        NOTATION_DEBUG << "NotationView::setMenuStates: Have selection; it's " << m_currentEventSelection << " covering range from " << m_currentEventSelection->getStartTime() << " to " << m_currentEventSelection->getEndTime() << " (" << m_currentEventSelection->getSegmentEvents().size() << " events)" << endl;

        stateChanged("have_selection", KXMLGUIClient::StateNoReverse);
        if (m_currentEventSelection->contains
                (Note::EventType)) {
            stateChanged("have_notes_in_selection",
                         KXMLGUIClient::StateNoReverse);
        }
        if (m_currentEventSelection->contains
                (Note::EventRestType)) {
            stateChanged("have_rests_in_selection",
                         KXMLGUIClient::StateNoReverse);
        }
    }

    // 2. set inserter-related states

    // #1372863 -- RestInserter is a subclass of NoteInserter, so we
    // need to test dynamic_cast<RestInserter *> before
    // dynamic_cast<NoteInserter *> (which will succeed for both)

    if (dynamic_cast<RestInserter *>(m_tool)) {
        NOTATION_DEBUG << "Have rest inserter " << endl;
        stateChanged("note_insert_tool_current", StateReverse);
        stateChanged("rest_insert_tool_current", StateNoReverse);
    } else if (dynamic_cast<NoteInserter *>(m_tool)) {
        NOTATION_DEBUG << "Have note inserter " << endl;
        stateChanged("note_insert_tool_current", StateNoReverse);
        stateChanged("rest_insert_tool_current", StateReverse);
    } else {
        NOTATION_DEBUG << "Have neither inserter " << endl;
        stateChanged("note_insert_tool_current", StateReverse);
        stateChanged("rest_insert_tool_current", StateReverse);
    }
}

#define UPDATE_PROGRESS(n) \
	progressCount += (n); \
	if (progressTotal > 0) { \
	    emit setProgress(progressCount * 100 / progressTotal); \
	    ProgressDialog::processEvents(); \
	}

void NotationView::readjustCanvasSize()
{
    Profiler profiler("NotationView::readjustCanvasSize");

    double maxWidth = 0.0;
    int maxHeight = 0;

    slotSetOperationNameAndStatus(i18n("Sizing and allocating canvas..."));
    ProgressDialog::processEvents();

    int progressTotal = m_staffs.size() + 2;
    int progressCount = 0;

    for (unsigned int i = 0; i < m_staffs.size(); ++i) {

        LinedStaff &staff = *m_staffs[i];

        staff.sizeStaff(*m_hlayout);
        UPDATE_PROGRESS(1);

        if (staff.getTotalWidth() + staff.getX() > maxWidth) {
            maxWidth = staff.getTotalWidth() + staff.getX() + 1;
        }

        if (staff.getTotalHeight() + staff.getY() > maxHeight) {
            maxHeight = staff.getTotalHeight() + staff.getY() + 1;
        }
    }

    int topMargin = 0, leftMargin = 0;
    getPageMargins(leftMargin, topMargin);

    int pageWidth = getPageWidth();
    int pageHeight = getPageHeight();

    NOTATION_DEBUG << "NotationView::readjustCanvasSize: maxHeight is "
    << maxHeight << ", page height is " << pageHeight << endl
    << " - maxWidth is " << maxWidth << ", page width is " << pageWidth << endl;


    if (m_pageMode == LinedStaff::LinearMode) {
        maxWidth = ((maxWidth / pageWidth) + 1) * pageWidth;
        if (maxHeight < pageHeight)
            maxHeight = pageHeight;
    } else {
        if (maxWidth < pageWidth)
            maxWidth = pageWidth;
        if (maxHeight < pageHeight + topMargin*2)
            maxHeight = pageHeight + topMargin * 2;
    }

    // now get the EditView to do the biz
    readjustViewSize(TQSize(int(maxWidth), maxHeight), true);

    UPDATE_PROGRESS(2);

    if (m_pannerDialog) {

        if (m_pageMode != LinedStaff::MultiPageMode) {
            m_pannerDialog->hide();

        } else {

            m_pannerDialog->show();

            m_pannerDialog->setPageSize
            (TQSize(canvas()->width(),
                   canvas()->height()));

            m_pannerDialog->scrollbox()->setViewSize
            (TQSize(getCanvasView()->width(),
                   getCanvasView()->height()));
        }
    }

    // Give a correct vertical alignment to track headers
    if ((m_pageMode == LinedStaff::LinearMode) && m_showHeadersGroup) {
        m_headersGroupView->setContentsPos(0, getCanvasView()->contentsY());
    }
}

void NotationView::slotNoteAction()
{
    const TQObject* sigSender = sender();

    NoteActionDataMap::Iterator noteAct =
        m_noteActionDataMap->find(sigSender->name());

    if (noteAct != m_noteActionDataMap->end()) {
        m_lastNoteAction = sigSender->name();
        setCurrentSelectedNote(**noteAct);
        setMenuStates();
    } else {
        std::cerr << "NotationView::slotNoteAction() : couldn't find NoteActionData named '"
        << sigSender->name() << "'\n";
    }
}

void NotationView::slotLastNoteAction()
{
    TDEAction *action = actionCollection()->action(m_lastNoteAction.ascii());
    if (!action)
        action = actionCollection()->action("crotchet");

    if (action) {
        action->activate();
    } else {
        std::cerr << "NotationView::slotNoteAction() : couldn't find action named '"
        << m_lastNoteAction.ascii() << "' or 'crotchet'\n";
    }
}

void NotationView::slotAddMark()
{
    const TQObject *s = sender();
    if (!m_currentEventSelection)
        return ;

    MarkActionDataMap::Iterator i = m_markActionDataMap->find(s->name());

    if (i != m_markActionDataMap->end()) {
        addCommandToHistory(new AddMarkCommand
                            ((**i).mark, *m_currentEventSelection));
    }
}

void NotationView::slotNoteChangeAction()
{
    const TQObject* sigSender = sender();

    NoteChangeActionDataMap::Iterator noteAct =
        m_noteChangeActionDataMap->find(sigSender->name());

    if (noteAct != m_noteChangeActionDataMap->end()) {
        slotSetNoteDurations((**noteAct).noteType, (**noteAct).notationOnly);
    } else {
        std::cerr << "NotationView::slotNoteChangeAction() : couldn't find NoteChangeAction named '"
        << sigSender->name() << "'\n";
    }
}

void NotationView::initActionDataMaps()
{
    static bool called = false;
    static int keys[] =
        { Key_0, Key_3, Key_6, Key_8, Key_4, Key_2, Key_1, Key_5 };

    if (called)
        return ;
    called = true;

    m_noteActionDataMap = new NoteActionDataMap;

    for (int rest = 0; rest < 2; ++rest) {
        for (int dots = 0; dots < 2; ++dots) {
            for (int type = Note::Longest; type >= Note::Shortest; --type) {
                if (dots && (type == Note::Longest))
                    continue;

                TQString refName
                (NotationStrings::getReferenceName(Note(type, dots), rest == 1));

                TQString shortName(refName);
                shortName.replace(TQRegExp("-"), "_");

                TQString titleName
                (NotationStrings::getNoteName(Note(type, dots)));

                titleName = titleName.left(1).upper() +
                            titleName.right(titleName.length() - 1);

                if (rest) {
                    titleName.replace(TQRegExp(i18n("note")), i18n("rest"));
                }

                int keycode = keys[type - Note::Shortest];
                if (dots) // keycode += CTRL; -- used below for note change action
                    keycode = 0;
                if (rest) // keycode += SHIFT; -- can't do shift+numbers
                    keycode = 0;

                m_noteActionDataMap->insert
                    (shortName, new NoteActionData
                     (titleName, shortName, refName, keycode,
                      rest > 0, type, dots));
            }
        }
    }

    m_noteChangeActionDataMap = new NoteChangeActionDataMap;

    for (int notationOnly = 0; notationOnly <= 1; ++notationOnly) {
        for (int type = Note::Longest; type >= Note::Shortest; --type) {

            TQString refName
            (NotationStrings::getReferenceName(Note(type, 0), false));

            TQString shortName(TQString("change_%1%2")
                              .arg(notationOnly ? "notation_" : "").arg(refName));
            shortName.replace(TQRegExp("-"), "_");

            TQString titleName
            (NotationStrings::getNoteName(Note(type, 0)));

            titleName = titleName.left(1).upper() +
                        titleName.right(titleName.length() - 1);

            int keycode = keys[type - Note::Shortest];
            keycode += CTRL;
            if (notationOnly)
                keycode += ALT;

            m_noteChangeActionDataMap->insert
                (shortName, new NoteChangeActionData
                 (titleName, shortName, refName, keycode,
                  notationOnly ? true : false, type));
        }
    }

    m_markActionDataMap = new MarkActionDataMap;

    std::vector<Mark> marks = Marks::getStandardMarks();
    for (unsigned int i = 0; i < marks.size(); ++i) {

        Mark mark = marks[i];
        TQString markName(strtoqstr(mark));
        TQString actionName = TQString("add_%1").arg(markName);

        m_markActionDataMap->insert
            (actionName, new MarkActionData
             (AddMarkCommand::getGlobalName(mark),
              actionName, 0, mark));
    }

}

void NotationView::setupProgress(KProgress* bar)
{
    if (bar) {
        NOTATION_DEBUG << "NotationView::setupProgress(bar)\n";

        connect(m_hlayout, TQ_SIGNAL(setProgress(int)),
                bar, TQ_SLOT(setValue(int)));

        connect(m_hlayout, TQ_SIGNAL(incrementProgress(int)),
                bar, TQ_SLOT(advance(int)));

        connect(this, TQ_SIGNAL(setProgress(int)),
                bar, TQ_SLOT(setValue(int)));

        connect(this, TQ_SIGNAL(incrementProgress(int)),
                bar, TQ_SLOT(advance(int)));

        for (unsigned int i = 0; i < m_staffs.size(); ++i) {
            connect(m_staffs[i], TQ_SIGNAL(setProgress(int)),
                    bar, TQ_SLOT(setValue(int)));

            connect(m_staffs[i], TQ_SIGNAL(incrementProgress(int)),
                    bar, TQ_SLOT(advance(int)));
        }
    }

}

void NotationView::setupProgress(ProgressDialog* dialog)
{
    NOTATION_DEBUG << "NotationView::setupProgress(dialog)" << endl;
    disconnectProgress();

    if (dialog) {
        setupProgress(dialog->progressBar());

        connect(dialog, TQ_SIGNAL(cancelClicked()),
                m_hlayout, TQ_SLOT(slotCancel()));

        for (unsigned int i = 0; i < m_staffs.size(); ++i) {
            connect(m_staffs[i], TQ_SIGNAL(setOperationName(TQString)),
                    this, TQ_SLOT(slotSetOperationNameAndStatus(TQString)));

            connect(dialog, TQ_SIGNAL(cancelClicked()),
                    m_staffs[i], TQ_SLOT(slotCancel()));
        }

        connect(this, TQ_SIGNAL(setOperationName(TQString)),
                dialog, TQ_SLOT(slotSetOperationName(TQString)));
        m_progressDisplayer = PROGRESS_DIALOG;
    }

}

void NotationView::slotSetOperationNameAndStatus(TQString name)
{
    emit setOperationName(name);
    statusBar()->changeItem(TQString("  %1").arg(name),
                            KTmpStatusMsg::getDefaultId());
}

void NotationView::disconnectProgress()
{
    NOTATION_DEBUG << "NotationView::disconnectProgress()" << endl;

    m_hlayout->disconnect();
    disconnect(TQ_SIGNAL(setProgress(int)));
    disconnect(TQ_SIGNAL(incrementProgress(int)));
    disconnect(TQ_SIGNAL(setOperationName(TQString)));

    for (unsigned int i = 0; i < m_staffs.size(); ++i) {
        m_staffs[i]->disconnect();
    }
}

void NotationView::setupDefaultProgress()
{
    if (m_progressDisplayer != PROGRESS_BAR) {
        NOTATION_DEBUG << "NotationView::setupDefaultProgress()" << endl;
        disconnectProgress();
        setupProgress(m_progressBar);
        m_progressDisplayer = PROGRESS_BAR;
    }
}

void NotationView::updateViewCaption()
{
    if (m_segments.size() == 1) {

        TrackId trackId = m_segments[0]->getTrack();
        Track *track =
            m_segments[0]->getComposition()->getTrackById(trackId);

        int trackPosition = -1;
        if (track)
            trackPosition = track->getPosition();
        //	std::cout << std::endl << std::endl << std::endl << "DEBUG TITLE BAR: " << getDocument()->getTitle() << std::endl << std::endl << std::endl;
        setCaption(i18n("%1 - Segment Track #%2 - Notation")
                   .arg(getDocument()->getTitle())
                   .arg(trackPosition + 1));

    } else if (m_segments.size() == getDocument()->getComposition().getNbSegments()) {

        setCaption(i18n("%1 - All Segments - Notation")
                   .arg(getDocument()->getTitle()));

    } else {

        setCaption(i18n("%1 - Segment - Notation", "%1 - %n Segments - Notation", m_segments.size())
                   .arg(getDocument()->getTitle()));

    }
}

NotationView::NoteActionDataMap* NotationView::m_noteActionDataMap = 0;

NotationView::NoteChangeActionDataMap* NotationView::m_noteChangeActionDataMap = 0;

NotationView::MarkActionDataMap* NotationView::m_markActionDataMap = 0;


/// SLOTS


void
NotationView::slotUpdateInsertModeStatus()
{
    TQString tripletMessage = i18n("Triplet");
    TQString chordMessage = i18n("Chord");
    TQString graceMessage = i18n("Grace");
    TQString message;

    if (isInTripletMode()) {
        message = i18n("%1 %2").arg(message).arg(tripletMessage);
    }

    if (isInChordMode()) {
        message = i18n("%1 %2").arg(message).arg(chordMessage);
    }

    if (isInGraceMode()) {
        message = i18n("%1 %2").arg(message).arg(graceMessage);
    }

    m_insertModeLabel->setText(message);
}

void
NotationView::slotUpdateAnnotationsStatus()
{
    if (!areAnnotationsVisible()) {
        for (int i = 0; i < getStaffCount(); ++i) {
            Segment &s = getStaff(i)->getSegment();
            for (Segment::iterator j = s.begin(); j != s.end(); ++j) {
                if ((*j)->isa(Text::EventType) &&
                        ((*j)->get<String>(Text::TextTypePropertyName)
                         == Text::Annotation)) {
                    m_annotationsLabel->setText(i18n("Hidden annotations"));
                    return ;
                }
            }
        }
    }
    m_annotationsLabel->setText("");
    getToggleAction("show_annotations")->setChecked(areAnnotationsVisible());
}

void
NotationView::slotUpdateLilyPondDirectivesStatus()
{
    if (!areLilyPondDirectivesVisible()) {
        for (int i = 0; i < getStaffCount(); ++i) {
            Segment &s = getStaff(i)->getSegment();
            for (Segment::iterator j = s.begin(); j != s.end(); ++j) {
                if ((*j)->isa(Text::EventType) &&
                        ((*j)->get
                         <String>
                         (Text::TextTypePropertyName)
                         == Text::LilyPondDirective)) {
                    m_lilyPondDirectivesLabel->setText(i18n("Hidden LilyPond directives"));
                    return ;
                }
            }
        }
    }
    m_lilyPondDirectivesLabel->setText("");
    getToggleAction("show_lilypond_directives")->setChecked(areLilyPondDirectivesVisible());
}

void
NotationView::slotChangeSpacingFromStringValue(const TQString& spacingT)
{
    // spacingT has a '%' at the end
    //
    int spacing = spacingT.left(spacingT.length() - 1).toInt();
    slotChangeSpacing(spacing);
}

void
NotationView::slotChangeSpacingFromAction()
{
    const TQObject *s = sender();
    TQString name = s->name();

    if (name.left(8) == "spacing_") {
        int spacing = name.right(name.length() - 8).toInt();

        if (spacing > 0)
            slotChangeSpacing(spacing);

    } else {
        KMessageBox::sorry
        (this, i18n("Unknown spacing action %1").arg(name));
    }
}

void
NotationView::slotChangeSpacing(int spacing)
{
    if (m_hlayout->getSpacing() == spacing)
        return ;

    m_hlayout->setSpacing(spacing);

    //     m_spacingSlider->setSize(spacing);

    TDEToggleAction *action = dynamic_cast<TDEToggleAction *>
                            (actionCollection()->action(TQString("spacing_%1").arg(spacing).ascii()));
    if (action)
        action->setChecked(true);
    else {
        std::cerr
        << "WARNING: Expected action \"spacing_" << spacing
        << "\" to be a TDEToggleAction, but it isn't (or doesn't exist)"
        << std::endl;
    }

    positionStaffs();
    applyLayout();

    for (unsigned int i = 0; i < m_staffs.size(); ++i) {
        m_staffs[i]->markChanged();
    }

    positionPages();
    updateControlRulers(true);
    updateView();
}

void
NotationView::slotChangeProportionFromIndex(int n)
{
    std::vector<int> proportions = m_hlayout->getAvailableProportions();
    if (n >= (int)proportions.size())
        n = proportions.size() - 1;
    slotChangeProportion(proportions[n]);
}

void
NotationView::slotChangeProportionFromAction()
{
    const TQObject *s = sender();
    TQString name = s->name();

    if (name.left(11) == "proportion_") {
        int proportion = name.right(name.length() - 11).toInt();
        slotChangeProportion(proportion);

    } else {
        KMessageBox::sorry
        (this, i18n("Unknown proportion action %1").arg(name));
    }
}

void
NotationView::slotChangeProportion(int proportion)
{
    if (m_hlayout->getProportion() == proportion)
        return ;

    m_hlayout->setProportion(proportion);

    //    m_proportionSlider->setSize(proportion);

    TDEToggleAction *action = dynamic_cast<TDEToggleAction *>
                            (actionCollection()->action(TQString("proportion_%1").arg(proportion).ascii()));
    if (action)
        action->setChecked(true);
    else {
        std::cerr
        << "WARNING: Expected action \"proportion_" << proportion
        << "\" to be a TDEToggleAction, but it isn't (or doesn't exist)"
        << std::endl;
    }

    positionStaffs();
    applyLayout();

    for (unsigned int i = 0; i < m_staffs.size(); ++i) {
        m_staffs[i]->markChanged();
    }

    positionPages();
    updateControlRulers(true);
    updateView();
}

void
NotationView::slotChangeFontFromAction()
{
    const TQObject *s = sender();
    TQString name = s->name();
    if (name.left(10) == "note_font_") {
        name = name.right(name.length() - 10);
        slotChangeFont(name);
    } else {
        KMessageBox::sorry
        (this, i18n("Unknown font action %1").arg(name));
    }
}

void
NotationView::slotChangeFontSizeFromAction()
{
    const TQObject *s = sender();
    TQString name = s->name();

    if (name.left(15) == "note_font_size_") {
        name = name.right(name.length() - 15);
        bool ok = false;
        int size = name.toInt(&ok);
        if (ok)
            slotChangeFont(m_fontName, size);
        else {
            KMessageBox::sorry
            (this, i18n("Unknown font size %1").arg(name));
        }
    } else {
        KMessageBox::sorry
        (this, i18n("Unknown font size action %1").arg(name));
    }
}

void
NotationView::slotChangeFont(const TQString &newName)
{
    NOTATION_DEBUG << "changeFont: " << newName << endl;
    slotChangeFont(std::string(newName.utf8()));
}

void
NotationView::slotChangeFont(std::string newName)
{
    int newSize = m_fontSize;

    if (!NoteFontFactory::isAvailableInSize(newName, newSize)) {

        int defaultSize = NoteFontFactory::getDefaultSize(newName);
        newSize = m_config->readUnsignedNumEntry
                  ((getStaffCount() > 1 ?
                    "multistaffnotesize" : "singlestaffnotesize"), defaultSize);

        if (!NoteFontFactory::isAvailableInSize(newName, newSize)) {
            newSize = defaultSize;
        }
    }

    slotChangeFont(newName, newSize);
}

void
NotationView::slotChangeFontSize(int newSize)
{
    slotChangeFont(m_fontName, newSize);
}

void
NotationView::slotChangeFontSizeFromStringValue(const TQString& sizeT)
{
    int size = sizeT.toInt();
    slotChangeFont(m_fontName, size);
}

void
NotationView::slotZoomIn()
{
    std::vector<int> sizes = NoteFontFactory::getScreenSizes(m_fontName);
    for (int i = 0; i + 1 < sizes.size(); ++i) {
        if (sizes[i] == m_fontSize) {
            slotChangeFontSize(sizes[i + 1]);
            return ;
        }
    }
}

void
NotationView::slotZoomOut()
{
    std::vector<int> sizes = NoteFontFactory::getScreenSizes(m_fontName);
    for (int i = 1; i < sizes.size(); ++i) {
        if (sizes[i] == m_fontSize) {
            slotChangeFontSize(sizes[i - 1]);
            return ;
        }
    }
}

void
NotationView::slotChangeFont(std::string newName, int newSize)
{
    if (newName == m_fontName && newSize == m_fontSize)
        return ;

    NotePixmapFactory* npf = 0;

    try {
        npf = new NotePixmapFactory(newName, newSize);
    } catch (...) {
        return ;
    }

    bool changedFont = (newName != m_fontName || newSize != m_fontSize);

    std::string oldName = m_fontName;
    m_fontName = newName;
    m_fontSize = newSize;
    setNotePixmapFactory(npf);

    // update the various GUI elements

    std::set<std::string> fs(NoteFontFactory::getFontNames());
    std::vector<std::string> f(fs.begin(), fs.end());
    std::sort(f.begin(), f.end());

    for (unsigned int i = 0; i < f.size(); ++i) {
        bool thisOne = (f[i] == m_fontName);
        if (thisOne)
            m_fontCombo->setCurrentItem(i);
        TDEToggleAction *action = dynamic_cast<TDEToggleAction *>
                                (actionCollection()->action(TQString("note_font_" + strtoqstr(f[i])).ascii()));
        NOTATION_DEBUG << "inspecting " << f[i] << (action ? ", have action" : ", no action") << endl;
        if (action)
            action->setChecked(thisOne);
        else {
            std::cerr
            << "WARNING: Expected action \"note_font_" << f[i]
            << "\" to be a TDEToggleAction, but it isn't (or doesn't exist)"
            << std::endl;
        }
    }

    NOTATION_DEBUG << "about to reinitialise sizes" << endl;

    std::vector<int> sizes = NoteFontFactory::getScreenSizes(m_fontName);
    m_fontSizeCombo->clear();
    TQString value;
    for (std::vector<int>::iterator i = sizes.begin(); i != sizes.end(); ++i) {
        value.setNum(*i);
        m_fontSizeCombo->insertItem(value);
    }
    value.setNum(m_fontSize);
    m_fontSizeCombo->setCurrentText(value);

    setupFontSizeMenu(oldName);

    if (!changedFont)
        return ; // might have been called to initialise menus etc

    NOTATION_DEBUG << "about to change font" << endl;

    if (m_pageMode == LinedStaff::MultiPageMode) {

        int pageWidth = getPageWidth();
        int topMargin = 0, leftMargin = 0;
        getPageMargins(leftMargin, topMargin);

        m_hlayout->setPageWidth(pageWidth - leftMargin * 2);
    }

    for (unsigned int i = 0; i < m_staffs.size(); ++i) {
        m_staffs[i]->changeFont(m_fontName, m_fontSize);
    }

    NOTATION_DEBUG << "about to position staffs" << endl;

    positionStaffs();

    bool layoutApplied = applyLayout();
    if (!layoutApplied)
        KMessageBox::sorry(0, "Couldn't apply layout");
    else {
        for (unsigned int i = 0; i < m_staffs.size(); ++i) {
            m_staffs[i]->markChanged();
        }
    }

    positionPages();
    updateControlRulers(true);
    updateView();
}

void
NotationView::slotFilePrint()
{
    KTmpStatusMsg msg(i18n("Printing..."), this);

    SetWaitCursor waitCursor;
    NotationView printingView(getDocument(), m_segments,
                              (TQWidget *)parent(), this);

    if (!printingView.isOK()) {
        NOTATION_DEBUG << "Print : operation cancelled\n";
        return ;
    }

    printingView.print();
}

void
NotationView::slotFilePrintPreview()
{
    KTmpStatusMsg msg(i18n("Previewing..."), this);

    SetWaitCursor waitCursor;
    NotationView printingView(getDocument(), m_segments,
                              (TQWidget *)parent(), this);

    if (!printingView.isOK()) {
        NOTATION_DEBUG << "Print preview : operation cancelled\n";
        return ;
    }

    printingView.print(true);
}

std::map<TDEProcess *, KTempFile *> NotationView::m_lilyTempFileMap;

void NotationView::slotPrintLilyPond()
{
    KTmpStatusMsg msg(i18n("Printing LilyPond file..."), this);
    KTempFile *file = new KTempFile(TQString(), ".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 ;
    }
    TDEProcess *proc = new TDEProcess;
    *proc << "rosegarden-lilypondview";
    *proc << "--graphical";
    *proc << "--print";
    *proc << file->name();
    connect(proc, TQ_SIGNAL(processExited(TDEProcess *)),
            this, TQ_SLOT(slotLilyPondViewProcessExited(TDEProcess *)));
    m_lilyTempFileMap[proc] = file;
    proc->start(TDEProcess::NotifyOnExit);
}

void NotationView::slotPreviewLilyPond()
{
    KTmpStatusMsg msg(i18n("Previewing LilyPond file..."), this);
    KTempFile *file = new KTempFile(TQString(), ".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 ;
    }
    TDEProcess *proc = new TDEProcess;
    *proc << "rosegarden-lilypondview";
    *proc << "--graphical";
    *proc << "--pdf";
    *proc << file->name();
    connect(proc, TQ_SIGNAL(processExited(TDEProcess *)),
            this, TQ_SLOT(slotLilyPondViewProcessExited(TDEProcess *)));
    m_lilyTempFileMap[proc] = file;
    proc->start(TDEProcess::NotifyOnExit);
}

void NotationView::slotLilyPondViewProcessExited(TDEProcess *p)
{
    delete m_lilyTempFileMap[p];
    m_lilyTempFileMap.erase(p);
    delete p;
}

bool NotationView::exportLilyPondFile(TQString file, bool forPreview)
{
    TQString caption = "", heading = "";
    if (forPreview) {
        caption = i18n("LilyPond Preview Options");
        heading = i18n("LilyPond preview options");
    }

    LilyPondOptionsDialog dialog(this, m_doc, caption, heading);
    if (dialog.exec() != TQDialog::Accepted) {
        return false;
    }

    ProgressDialog progressDlg(i18n("Exporting LilyPond file..."),
                               100,
                               this);

    LilyPondExporter e(this, m_doc, std::string(TQFile::encodeName(file)));

    connect(&e, TQ_SIGNAL(setProgress(int)),
            progressDlg.progressBar(), TQ_SLOT(setValue(int)));

    connect(&e, TQ_SIGNAL(incrementProgress(int)),
            progressDlg.progressBar(), TQ_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 NotationView::slotEditCut()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Cutting selection to clipboard..."), this);

    addCommandToHistory(new CutCommand(*m_currentEventSelection,
                                       getDocument()->getClipboard()));
}

void NotationView::slotEditDelete()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Deleting selection..."), this);

    addCommandToHistory(new EraseCommand(*m_currentEventSelection));
}

void NotationView::slotEditCopy()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Copying selection to clipboard..."), this);

    addCommandToHistory(new CopyCommand(*m_currentEventSelection,
                                        getDocument()->getClipboard()));
}

void NotationView::slotEditCutAndClose()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Cutting selection to clipboard..."), this);

    addCommandToHistory(new CutAndCloseCommand(*m_currentEventSelection,
                        getDocument()->getClipboard()));
}

static const TQString RESTRICTED_PASTE_FAILED_DESCRIPTION = i18n(
                      "The Restricted paste type requires enough empty " \
                      "space (containing only rests) at the paste position " \
                      "to hold all of the events to be pasted.\n" \
                      "Not enough space was found.\n" \
                      "If you want to paste anyway, consider using one of " \
                      "the other paste types from the \"Paste...\" option " \
                      "on the Edit menu.  You can also change the default " \
                      "paste type to something other than Restricted if " \
                      "you wish."
    );

void NotationView::slotEditPaste()
{
    Clipboard * clipboard = getDocument()->getClipboard();

    if (clipboard->isEmpty()) {
        slotStatusHelpMsg(i18n("Clipboard is empty"));
        return ;
    }
    if (!clipboard->isSingleSegment()) {
        slotStatusHelpMsg(i18n("Can't paste multiple Segments into one"));
        return ;
    }

    slotStatusHelpMsg(i18n("Inserting clipboard contents..."));

    LinedStaff *staff = getCurrentLinedStaff();
    Segment &segment = staff->getSegment();

    // Paste at cursor position
    //
    timeT insertionTime = getInsertionTime();
    timeT endTime = insertionTime +
        (clipboard->getSingleSegment()->getEndTime() -
         clipboard->getSingleSegment()->getStartTime());

    TDEConfig *config = kapp->config();
    config->setGroup(NotationViewConfigGroup);
    PasteEventsCommand::PasteType defaultType = (PasteEventsCommand::PasteType)
        config->readUnsignedNumEntry("pastetype",
                                     PasteEventsCommand::Restricted);

    PasteEventsCommand *command = new PasteEventsCommand
        (segment, clipboard, insertionTime, defaultType);

    if (!command->isPossible()) {
        KMessageBox::detailedError
            (this,
             i18n("Couldn't paste at this point."), RESTRICTED_PASTE_FAILED_DESCRIPTION);
    } else {
        addCommandToHistory(command);
        setCurrentSelection(new EventSelection(command->getPastedEvents()));
        slotSetInsertCursorPosition(endTime, true, false);
    }
}

void NotationView::slotEditGeneralPaste()
{
    Clipboard *clipboard = getDocument()->getClipboard();

    if (clipboard->isEmpty()) {
        slotStatusHelpMsg(i18n("Clipboard is empty"));
        return ;
    }

    slotStatusHelpMsg(i18n("Inserting clipboard contents..."));

    LinedStaff *staff = getCurrentLinedStaff();
    Segment &segment = staff->getSegment();

    TDEConfig *config = kapp->config();
    config->setGroup(NotationViewConfigGroup);
    PasteEventsCommand::PasteType defaultType = (PasteEventsCommand::PasteType)
        config->readUnsignedNumEntry("pastetype",
                                     PasteEventsCommand::Restricted);

    PasteNotationDialog dialog(this, defaultType);

    if (dialog.exec() == TQDialog::Accepted) {

        PasteEventsCommand::PasteType type = dialog.getPasteType();
        if (dialog.setAsDefault()) {
            config->setGroup(NotationViewConfigGroup);
            config->writeEntry("pastetype", type);
        }

        timeT insertionTime = getInsertionTime();
        timeT endTime = insertionTime +
            (clipboard->getSingleSegment()->getEndTime() -
             clipboard->getSingleSegment()->getStartTime());

        PasteEventsCommand *command = new PasteEventsCommand
            (segment, clipboard, insertionTime, type);

        if (!command->isPossible()) {
            KMessageBox::detailedError
                (this,
                 i18n("Couldn't paste at this point."),
                 i18n(RESTRICTED_PASTE_FAILED_DESCRIPTION.ascii()));
        } else {
            addCommandToHistory(command);
            setCurrentSelection(new EventSelection
                                (segment, insertionTime, endTime));
            slotSetInsertCursorPosition(endTime, true, false);
        }
    }
}

void
NotationView::slotMoveEventsUpStaff()
{
    LinedStaff *targetStaff = getStaffAbove();
    if (!targetStaff) return;
    if (!m_currentEventSelection) return;
    Segment &targetSegment = targetStaff->getSegment();
    
    KMacroCommand *command = new KMacroCommand(i18n("Move Events to Staff Above"));

    timeT insertionTime = m_currentEventSelection->getStartTime();

    Clipboard *c = new Clipboard;
    CopyCommand *cc = new CopyCommand(*m_currentEventSelection, c);
    cc->execute();

    command->addCommand(new EraseCommand(*m_currentEventSelection));;

    command->addCommand(new PasteEventsCommand
                        (targetSegment, c,
                         insertionTime,
                         PasteEventsCommand::NoteOverlay));

    addCommandToHistory(command);

    delete c;
}

void
NotationView::slotMoveEventsDownStaff()
{
    LinedStaff *targetStaff = getStaffBelow();
    if (!targetStaff) return;
    if (!m_currentEventSelection) return;
    Segment &targetSegment = targetStaff->getSegment();
    
    KMacroCommand *command = new KMacroCommand(i18n("Move Events to Staff Below"));

    timeT insertionTime = m_currentEventSelection->getStartTime();

    Clipboard *c = new Clipboard;
    CopyCommand *cc = new CopyCommand(*m_currentEventSelection, c);
    cc->execute();

    command->addCommand(new EraseCommand(*m_currentEventSelection));;

    command->addCommand(new PasteEventsCommand
                        (targetSegment, c,
                         insertionTime,
                         PasteEventsCommand::NoteOverlay));

    addCommandToHistory(command);

    delete c;
}

void NotationView::slotPreviewSelection()
{
    if (!m_currentEventSelection)
        return ;

    getDocument()->slotSetLoop(m_currentEventSelection->getStartTime(),
                               m_currentEventSelection->getEndTime());
}

void NotationView::slotClearLoop()
{
    getDocument()->slotSetLoop(0, 0);
}

void NotationView::slotClearSelection()
{
    // Actually we don't clear the selection immediately: if we're
    // using some tool other than the select tool, then the first
    // press switches us back to the select tool.

    NotationSelector *selector = dynamic_cast<NotationSelector *>(m_tool);

    if (!selector) {
        slotSelectSelected();
    } else {
        setCurrentSelection(0);
    }
}

void NotationView::slotEditSelectFromStart()
{
    timeT t = getInsertionTime();
    Segment &segment = m_staffs[m_currentStaff]->getSegment();
    setCurrentSelection(new EventSelection(segment,
                                           segment.getStartTime(),
                                           t));
}

void NotationView::slotEditSelectToEnd()
{
    timeT t = getInsertionTime();
    Segment &segment = m_staffs[m_currentStaff]->getSegment();
    setCurrentSelection(new EventSelection(segment,
                                           t,
                                           segment.getEndMarkerTime()));
}

void NotationView::slotEditSelectWholeStaff()
{
    Segment &segment = m_staffs[m_currentStaff]->getSegment();
    setCurrentSelection(new EventSelection(segment,
                                           segment.getStartTime(),
                                           segment.getEndMarkerTime()));
}

void NotationView::slotFilterSelection()
{
    NOTATION_DEBUG << "NotationView::slotFilterSelection" << endl;

    Segment *segment = getCurrentSegment();
    EventSelection *existingSelection = m_currentEventSelection;
    if (!segment || !existingSelection)
        return ;

    EventFilterDialog dialog(this);
    if (dialog.exec() == TQDialog::Accepted) {
        NOTATION_DEBUG << "slotFilterSelection- accepted" << endl;

        bool haveEvent = false;

        EventSelection *newSelection = new EventSelection(*segment);
        EventSelection::eventcontainer &ec =
            existingSelection->getSegmentEvents();
        for (EventSelection::eventcontainer::iterator i =
                 ec.begin(); i != ec.end(); ++i) {
            if (dialog.keepEvent(*i)) {
                haveEvent = true;
                newSelection->addEvent(*i);
            }
        }

        if (haveEvent)
            setCurrentSelection(newSelection);
        else
            setCurrentSelection(0);
    }
}

void NotationView::slotFinePositionLeft()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Pushing selection left..."), this);

    // half a note body width
    addCommandToHistory(new IncrementDisplacementsCommand
                        (*m_currentEventSelection, -500, 0));
}

void NotationView::slotFinePositionRight()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Pushing selection right..."), this);

    // half a note body width
    addCommandToHistory(new IncrementDisplacementsCommand
                        (*m_currentEventSelection, 500, 0));
}

void NotationView::slotFinePositionUp()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Pushing selection up..."), this);

    // half line height
    addCommandToHistory(new IncrementDisplacementsCommand
                        (*m_currentEventSelection, 0, -500));
}

void NotationView::slotFinePositionDown()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Pushing selection down..."), this);

    // half line height
    addCommandToHistory(new IncrementDisplacementsCommand
                        (*m_currentEventSelection, 0, 500));
}

void NotationView::slotFinePositionRestore()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Restoring computed positions..."), this);

    addCommandToHistory(new ResetDisplacementsCommand(*m_currentEventSelection));
}

void NotationView::slotMakeVisible()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Making visible..."), this);

    addCommandToHistory(new SetVisibilityCommand(*m_currentEventSelection, true));
}

void NotationView::slotMakeInvisible()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Making invisible..."), this);

    addCommandToHistory(new SetVisibilityCommand(*m_currentEventSelection, false));
}

void NotationView::slotToggleToolsToolBar()
{
    toggleNamedToolBar("Tools Toolbar");
}

void NotationView::slotToggleNotesToolBar()
{
    toggleNamedToolBar("Notes Toolbar");
}

void NotationView::slotToggleRestsToolBar()
{
    toggleNamedToolBar("Rests Toolbar");
}

void NotationView::slotToggleAccidentalsToolBar()
{
    toggleNamedToolBar("Accidentals Toolbar");
}

void NotationView::slotToggleClefsToolBar()
{
    toggleNamedToolBar("Clefs Toolbar");
}

void NotationView::slotToggleMetaToolBar()
{
    toggleNamedToolBar("Meta Toolbar");
}

void NotationView::slotToggleMarksToolBar()
{
    toggleNamedToolBar("Marks Toolbar");
}

void NotationView::slotToggleGroupToolBar()
{
    toggleNamedToolBar("Group Toolbar");
}

void NotationView::slotToggleLayoutToolBar()
{
    toggleNamedToolBar("Layout Toolbar");
}

void NotationView::slotToggleTransportToolBar()
{
    toggleNamedToolBar("Transport Toolbar");
}

void NotationView::toggleNamedToolBar(const TQString& toolBarName, bool* force)
{
    TDEToolBar *namedToolBar = toolBar(toolBarName.ascii());

    if (!namedToolBar) {
        NOTATION_DEBUG << "NotationView::toggleNamedToolBar() : toolBar "
                       << toolBarName << " not found" << endl;
        return ;
    }

    if (!force) {

        if (namedToolBar->isVisible())
            namedToolBar->hide();
        else
            namedToolBar->show();
    } else {

        if (*force)
            namedToolBar->show();
        else
            namedToolBar->hide();
    }

    setSettingsDirty();

}

void NotationView::slotGroupBeam()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Beaming group..."), this);

    addCommandToHistory(new BeamCommand
                        (*m_currentEventSelection));
}

void NotationView::slotGroupAutoBeam()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Auto-beaming selection..."), this);

    addCommandToHistory(new AutoBeamCommand
                        (*m_currentEventSelection));
}

void NotationView::slotGroupBreak()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Breaking groups..."), this);

    addCommandToHistory(new BreakCommand
                        (*m_currentEventSelection));
}

void NotationView::slotGroupSimpleTuplet()
{
    slotGroupTuplet(true);
}

void NotationView::slotGroupGeneralTuplet()
{
    slotGroupTuplet(false);
}

void NotationView::slotGroupTuplet(bool simple)
{
    timeT t = 0;
    timeT unit = 0;
    int tupled = 2;
    int untupled = 3;
    Segment *segment = 0;
    bool hasTimingAlready = false;

    if (m_currentEventSelection) {

        t = m_currentEventSelection->getStartTime();

        timeT duration = m_currentEventSelection->getTotalDuration();
        Note::Type unitType =
            Note::getNearestNote(duration / 3, 0).getNoteType();
        unit = Note(unitType).getDuration();

        if (!simple) {
            TupletDialog dialog(this, unitType, duration);
            if (dialog.exec() != TQDialog::Accepted)
                return ;
            unit = Note(dialog.getUnitType()).getDuration();
            tupled = dialog.getTupledCount();
            untupled = dialog.getUntupledCount();
            hasTimingAlready = dialog.hasTimingAlready();
        }

        segment = &m_currentEventSelection->getSegment();

    } else {

        t = getInsertionTime();

        NoteInserter *currentInserter = dynamic_cast<NoteInserter *>
            (m_toolBox->getTool(NoteInserter::ToolName));

        Note::Type unitType;

        if (currentInserter) {
            unitType = currentInserter->getCurrentNote().getNoteType();
        } else {
            unitType = Note::Quaver;
        }

        unit = Note(unitType).getDuration();

        if (!simple) {
            TupletDialog dialog(this, unitType);
            if (dialog.exec() != TQDialog::Accepted)
                return ;
            unit = Note(dialog.getUnitType()).getDuration();
            tupled = dialog.getTupledCount();
            untupled = dialog.getUntupledCount();
            hasTimingAlready = dialog.hasTimingAlready();
        }

        segment = &m_staffs[m_currentStaff]->getSegment();
    }

    addCommandToHistory(new TupletCommand
                        (*segment, t, unit, untupled, tupled, hasTimingAlready));

    if (!hasTimingAlready) {
        slotSetInsertCursorPosition(t + (unit * tupled), true, false);
    }
}

void NotationView::slotGroupUnTuplet()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Untupleting..."), this);

    addCommandToHistory(new UnTupletCommand
                        (*m_currentEventSelection));
}

void NotationView::slotGroupSlur()
{
    KTmpStatusMsg msg(i18n("Adding slur..."), this);
    slotAddIndication(Indication::Slur, i18n("slur"));
}

void NotationView::slotGroupPhrasingSlur()
{
    KTmpStatusMsg msg(i18n("Adding phrasing slur..."), this);
    slotAddIndication(Indication::PhrasingSlur, i18n("phrasing slur"));
}

void NotationView::slotGroupGlissando()
{
    KTmpStatusMsg msg(i18n("Adding glissando..."), this);
    slotAddIndication(Indication::Glissando, i18n("glissando"));
}

void NotationView::slotGroupCrescendo()
{
    KTmpStatusMsg msg(i18n("Adding crescendo..."), this);
    slotAddIndication(Indication::Crescendo, i18n("dynamic"));
}

void NotationView::slotGroupDecrescendo()
{
    KTmpStatusMsg msg(i18n("Adding decrescendo..."), this);
    slotAddIndication(Indication::Decrescendo, i18n("dynamic"));
}

void NotationView::slotGroupOctave2Up()
{
    KTmpStatusMsg msg(i18n("Adding octave..."), this);
    slotAddIndication(Indication::QuindicesimaUp, i18n("ottava"));
}

void NotationView::slotGroupOctaveUp()
{
    KTmpStatusMsg msg(i18n("Adding octave..."), this);
    slotAddIndication(Indication::OttavaUp, i18n("ottava"));
}

void NotationView::slotGroupOctaveDown()
{
    KTmpStatusMsg msg(i18n("Adding octave..."), this);
    slotAddIndication(Indication::OttavaDown, i18n("ottava"));
}

void NotationView::slotGroupOctave2Down()
{
    KTmpStatusMsg msg(i18n("Adding octave..."), this);
    slotAddIndication(Indication::QuindicesimaDown, i18n("ottava"));
}

void NotationView::slotAddIndication(std::string type, TQString desc)
{
    if (!m_currentEventSelection)
        return ;

    AddIndicationCommand *command =
        new AddIndicationCommand(type, *m_currentEventSelection);

    if (command->canExecute()) {
        addCommandToHistory(command);
        setSingleSelectedEvent(m_currentEventSelection->getSegment(),
                               command->getLastInsertedEvent());
    } else {
        KMessageBox::sorry(this, i18n("Can't add overlapping %1 indications").arg(desc)); // TODO PLURAL - how many 'indications' ?
        delete command;
    }
}

void NotationView::slotGroupMakeChord()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Making chord..."), this);

    MakeChordCommand *command =
        new MakeChordCommand(*m_currentEventSelection);

    addCommandToHistory(command);
}

void NotationView::slotTransformsNormalizeRests()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Normalizing rests..."), this);

    addCommandToHistory(new NormalizeRestsCommand
                        (*m_currentEventSelection));
}

void NotationView::slotTransformsCollapseRests()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Collapsing rests..."), this);

    addCommandToHistory(new CollapseRestsCommand
                        (*m_currentEventSelection));
}

void NotationView::slotTransformsCollapseNotes()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Collapsing notes..."), this);

    addCommandToHistory(new CollapseNotesCommand
                        (*m_currentEventSelection));
}

void NotationView::slotTransformsTieNotes()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Tying notes..."), this);

    addCommandToHistory(new TieNotesCommand
                        (*m_currentEventSelection));
}

void NotationView::slotTransformsUntieNotes()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Untying notes..."), this);

    addCommandToHistory(new UntieNotesCommand
                        (*m_currentEventSelection));
}

void NotationView::slotTransformsMakeNotesViable()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Making notes viable..."), this);

    addCommandToHistory(new MakeNotesViableCommand
                        (*m_currentEventSelection));
}

void NotationView::slotTransformsDeCounterpoint()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Removing counterpoint..."), this);

    addCommandToHistory(new DeCounterpointCommand
                        (*m_currentEventSelection));
}

void NotationView::slotTransformsStemsUp()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Pointing stems up..."), this);

    addCommandToHistory(new ChangeStemsCommand
                        (true, *m_currentEventSelection));
}

void NotationView::slotTransformsStemsDown()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Pointing stems down..."), this);

    addCommandToHistory(new ChangeStemsCommand
                        (false, *m_currentEventSelection));

}

void NotationView::slotTransformsRestoreStems()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Restoring computed stem directions..."), this);

    addCommandToHistory(new RestoreStemsCommand
                        (*m_currentEventSelection));
}

void NotationView::slotTransformsSlursAbove()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Positioning slurs..."), this);

    addCommandToHistory(new ChangeSlurPositionCommand
                        (true, *m_currentEventSelection));
}

void NotationView::slotTransformsSlursBelow()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Positioning slurs..."), this);

    addCommandToHistory(new ChangeSlurPositionCommand
                        (false, *m_currentEventSelection));

}

void NotationView::slotTransformsRestoreSlurs()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Restoring slur positions..."), this);

    addCommandToHistory(new RestoreSlursCommand
                        (*m_currentEventSelection));
}

void NotationView::slotTransformsTiesAbove()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Positioning ties..."), this);

    addCommandToHistory(new ChangeTiePositionCommand
                        (true, *m_currentEventSelection));
}

void NotationView::slotTransformsTiesBelow()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Positioning ties..."), this);

    addCommandToHistory(new ChangeTiePositionCommand
                        (false, *m_currentEventSelection));

}

void NotationView::slotTransformsRestoreTies()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Restoring tie positions..."), this);

    addCommandToHistory(new RestoreTiesCommand
                        (*m_currentEventSelection));
}

void NotationView::slotTransformsFixQuantization()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Fixing notation quantization..."), this);

    addCommandToHistory(new FixNotationQuantizeCommand
                        (*m_currentEventSelection));
}

void NotationView::slotTransformsRemoveQuantization()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Removing notation quantization..."), this);

    addCommandToHistory(new RemoveNotationQuantizeCommand
                        (*m_currentEventSelection));
}

void NotationView::slotSetStyleFromAction()
{
    const TQObject *s = sender();
    TQString name = s->name();

    if (!m_currentEventSelection)
        return ;

    if (name.left(6) == "style_") {
        name = name.right(name.length() - 6);

        KTmpStatusMsg msg(i18n("Changing to %1 style...").arg(name),
                          this);

        addCommandToHistory(new ChangeStyleCommand
                            (NoteStyleName(qstrtostr(name)),
                             *m_currentEventSelection));
    } else {
        KMessageBox::sorry
            (this, i18n("Unknown style action %1").arg(name));
    }
}

void NotationView::slotInsertNoteFromAction()
{
    const TQObject *s = sender();
    TQString name = s->name();

    Segment &segment = m_staffs[m_currentStaff]->getSegment();

    NoteInserter *noteInserter = dynamic_cast<NoteInserter *>(m_tool);
    if (!noteInserter) {
        KMessageBox::sorry(this, i18n("No note duration selected"));
        return ;
    }

    int pitch = 0;
    Accidental accidental =
        Accidentals::NoAccidental;

    timeT time(getInsertionTime());
    Rosegarden::Key key = segment.getKeyAtTime(time);
    Clef clef = segment.getClefAtTime(time);

    try {

        pitch = getPitchFromNoteInsertAction(name, accidental, clef, key);

    } catch (...) {

        KMessageBox::sorry
            (this, i18n("Unknown note insert action %1").arg(name));
        return ;
    }

    KTmpStatusMsg msg(i18n("Inserting note"), this);

    NOTATION_DEBUG << "Inserting note at pitch " << pitch << endl;

    noteInserter->insertNote(segment, time, pitch, accidental);
}

void NotationView::slotInsertRest()
{
    Segment &segment = m_staffs[m_currentStaff]->getSegment();
    timeT time = getInsertionTime();

    RestInserter *restInserter = dynamic_cast<RestInserter *>(m_tool);

    if (!restInserter) {

        NoteInserter *noteInserter = dynamic_cast<NoteInserter *>(m_tool);
        if (!noteInserter) {
            KMessageBox::sorry(this, i18n("No note duration selected"));
            return ;
        }

        Note note(noteInserter->getCurrentNote());

        restInserter = dynamic_cast<RestInserter*>
            (m_toolBox->getTool(RestInserter::ToolName));

        restInserter->slotSetNote(note.getNoteType());
        restInserter->slotSetDots(note.getDots());
    }

    restInserter->insertNote(segment, time,
                             0, Accidentals::NoAccidental, true);
}

void NotationView::slotSwitchFromRestToNote()
{
    RestInserter *restInserter = dynamic_cast<RestInserter *>(m_tool);
    if (!restInserter) {
        KMessageBox::sorry(this, i18n("No rest duration selected"));
        return ;
    }

    Note note(restInserter->getCurrentNote());

    TQString actionName = NotationStrings::getReferenceName(note, false);
    actionName = actionName.replace("-", "_");

    TDERadioAction *action = dynamic_cast<TDERadioAction *>
        (actionCollection()->action(actionName.ascii()));

    if (!action) {
        std::cerr << "WARNING: Failed to find note action \""
                  << actionName.ascii() << "\"" << std::endl;
    } else {
        action->activate();
    }

    NoteInserter *noteInserter = dynamic_cast<NoteInserter*>
        (m_toolBox->getTool(NoteInserter::ToolName));

    if (noteInserter) {
        noteInserter->slotSetNote(note.getNoteType());
        noteInserter->slotSetDots(note.getDots());
        setTool(noteInserter);
    }

    setMenuStates();
}

void NotationView::slotSwitchFromNoteToRest()
{
    NoteInserter *noteInserter = dynamic_cast<NoteInserter *>(m_tool);
    if (!noteInserter) {
        KMessageBox::sorry(this, i18n("No note duration selected"));
        return ;
    }

    Note note(noteInserter->getCurrentNote());

    TQString actionName = NotationStrings::getReferenceName(note, true);
    actionName = actionName.replace("-", "_");

    TDERadioAction *action = dynamic_cast<TDERadioAction *>
        (actionCollection()->action(actionName.ascii()));

    if (!action) {
        std::cerr << "WARNING: Failed to find rest action \""
                  << actionName.ascii() << "\"" << std::endl;
    } else {
        action->activate();
    }

    RestInserter *restInserter = dynamic_cast<RestInserter*>
        (m_toolBox->getTool(RestInserter::ToolName));

    if (restInserter) {
        restInserter->slotSetNote(note.getNoteType());
        restInserter->slotSetDots(note.getDots());
        setTool(restInserter);
    }

    setMenuStates();
}

void NotationView::slotToggleDot()
{
    NoteInserter *noteInserter = dynamic_cast<NoteInserter *>(m_tool);
    if (noteInserter) {
        Note note(noteInserter->getCurrentNote());
        if (note.getNoteType() == Note::Shortest ||
            note.getNoteType() == Note::Longest)
            return ;
        noteInserter->slotSetDots(note.getDots() ? 0 : 1);
        setTool(noteInserter);
    } else {
        RestInserter *restInserter = dynamic_cast<RestInserter *>(m_tool);
        if (restInserter) {
            Note note(restInserter->getCurrentNote());
            if (note.getNoteType() == Note::Shortest ||
                note.getNoteType() == Note::Longest)
                return ;
            restInserter->slotSetDots(note.getDots() ? 0 : 1);
            setTool(restInserter);
        } else {
            KMessageBox::sorry(this, i18n("No note or rest duration selected"));
        }
    }

    setMenuStates();
}

void NotationView::slotRespellDoubleFlat()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Forcing accidentals..."), this);

    addCommandToHistory(new RespellCommand(RespellCommand::Set,
                                           Accidentals::DoubleFlat,
                                           *m_currentEventSelection));
}

void NotationView::slotRespellFlat()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Forcing accidentals..."), this);

    addCommandToHistory(new RespellCommand(RespellCommand::Set,
                                           Accidentals::Flat,
                                           *m_currentEventSelection));
}

void NotationView::slotRespellNatural()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Forcing accidentals..."), this);

    addCommandToHistory(new RespellCommand(RespellCommand::Set,
                                           Accidentals::Natural,
                                           *m_currentEventSelection));
}

void NotationView::slotRespellSharp()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Forcing accidentals..."), this);

    addCommandToHistory(new RespellCommand(RespellCommand::Set,
                                           Accidentals::Sharp,
                                           *m_currentEventSelection));
}

void NotationView::slotRespellDoubleSharp()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Forcing accidentals..."), this);

    addCommandToHistory(new RespellCommand(RespellCommand::Set,
                                           Accidentals::DoubleSharp,
                                           *m_currentEventSelection));
}

void NotationView::slotRespellUp()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Forcing accidentals..."), this);

    addCommandToHistory(new RespellCommand(RespellCommand::Up,
                                           Accidentals::NoAccidental,
                                           *m_currentEventSelection));
}

void NotationView::slotRespellDown()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Forcing accidentals..."), this);

    addCommandToHistory(new RespellCommand(RespellCommand::Down,
                                           Accidentals::NoAccidental,
                                           *m_currentEventSelection));
}

void NotationView::slotRespellRestore()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Restoring accidentals..."), this);

    addCommandToHistory(new RespellCommand(RespellCommand::Restore,
                                           Accidentals::NoAccidental,
                                           *m_currentEventSelection));
}

void NotationView::slotShowCautionary()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Showing cautionary accidentals..."), this);

    addCommandToHistory(new MakeAccidentalsCautionaryCommand
                        (true, *m_currentEventSelection));
}

void NotationView::slotCancelCautionary()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Cancelling cautionary accidentals..."), this);

    addCommandToHistory(new MakeAccidentalsCautionaryCommand
                        (false, *m_currentEventSelection));
}

void NotationView::slotTransformsQuantize()
{
    if (!m_currentEventSelection)
        return ;

    QuantizeDialog dialog(this, true);

    if (dialog.exec() == TQDialog::Accepted) {
        KTmpStatusMsg msg(i18n("Quantizing..."), this);
        addCommandToHistory(new EventQuantizeCommand
                            (*m_currentEventSelection,
                             dialog.getQuantizer()));
    }
}

void NotationView::slotTransformsInterpret()
{
    if (!m_currentEventSelection)
        return ;

    InterpretDialog dialog(this);

    if (dialog.exec() == TQDialog::Accepted) {
        KTmpStatusMsg msg(i18n("Interpreting selection..."), this);
        addCommandToHistory(new InterpretCommand
                            (*m_currentEventSelection,
                             getDocument()->getComposition().getNotationQuantizer(),
                             dialog.getInterpretations()));
    }
}

void NotationView::slotSetNoteDurations(Note::Type type, bool notationOnly)
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Setting note durations..."), this);
    addCommandToHistory(new SetNoteTypeCommand(*m_currentEventSelection, type, notationOnly));
}

void NotationView::slotAddDot()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Adding dot..."), this);
    addCommandToHistory(new AddDotCommand(*m_currentEventSelection, false));
}

void NotationView::slotAddDotNotationOnly()
{
    if (!m_currentEventSelection)
        return ;
    KTmpStatusMsg msg(i18n("Adding dot..."), this);
    addCommandToHistory(new AddDotCommand(*m_currentEventSelection, true));
}

void NotationView::slotAddSlashes()
{
    const TQObject *s = sender();
    if (!m_currentEventSelection)
        return ;

    TQString name = s->name();
    int slashes = name.right(1).toInt();

    addCommandToHistory(new AddSlashesCommand
                        (slashes, *m_currentEventSelection));
}

void NotationView::slotMarksAddTextMark()
{
    if (m_currentEventSelection) {
        bool pressedOK = false;

        TQString txt = KLineEditDlg::getText(i18n("Text: "), "", &pressedOK, this);

        if (pressedOK) {
            addCommandToHistory(new AddTextMarkCommand
                                (qstrtostr(txt), *m_currentEventSelection));
        }
    }
}

void NotationView::slotMarksAddFingeringMark()
{
    if (m_currentEventSelection) {
        bool pressedOK = false;

        TQString txt = KLineEditDlg::getText(i18n("Fingering: "), "", &pressedOK, this);

        if (pressedOK) {
            addCommandToHistory(new AddFingeringMarkCommand
                                (qstrtostr(txt), *m_currentEventSelection));
        }
    }
}

void NotationView::slotMarksAddFingeringMarkFromAction()
{
    const TQObject *s = sender();
    TQString name = s->name();

    if (name.left(14) == "add_fingering_") {

        TQString fingering = name.right(name.length() - 14);

        if (fingering == "plus")
            fingering = "+";

        if (m_currentEventSelection) {
            addCommandToHistory(new AddFingeringMarkCommand
                                (qstrtostr(fingering), *m_currentEventSelection));
        }
    }
}

void NotationView::slotMarksRemoveMarks()
{
    if (m_currentEventSelection)
        addCommandToHistory(new RemoveMarksCommand
                            (*m_currentEventSelection));
}

void NotationView::slotMarksRemoveFingeringMarks()
{
    if (m_currentEventSelection)
        addCommandToHistory(new RemoveFingeringMarksCommand
                            (*m_currentEventSelection));
}

void
NotationView::slotMakeOrnament()
{
    if (!m_currentEventSelection)
        return ;

    EventSelection::eventcontainer &ec =
        m_currentEventSelection->getSegmentEvents();

    int basePitch = -1;
    int baseVelocity = -1;
    NoteStyle *style = NoteStyleFactory::getStyle(NoteStyleFactory::DefaultStyle);

    for (EventSelection::eventcontainer::iterator i =
             ec.begin(); i != ec.end(); ++i) {
        if ((*i)->isa(Note::EventType)) {
            if ((*i)->has(BaseProperties::PITCH)) {
                basePitch = (*i)->get
                    <Int>
                    (BaseProperties::PITCH);
                style = NoteStyleFactory::getStyleForEvent(*i);
                if (baseVelocity != -1)
                    break;
            }
            if ((*i)->has(BaseProperties::VELOCITY)) {
                baseVelocity = (*i)->get
                    <Int>
                    (BaseProperties::VELOCITY);
                if (basePitch != -1)
                    break;
            }
        }
    }

    Staff *staff = getCurrentStaff();
    Segment &segment = staff->getSegment();

    timeT absTime = m_currentEventSelection->getStartTime();
    timeT duration = m_currentEventSelection->getTotalDuration();
    Note note(Note::getNearestNote(duration));

    Track *track =
        segment.getComposition()->getTrackById(segment.getTrack());
    TQString name;
    int barNo = segment.getComposition()->getBarNumber(absTime);
    if (track) {
        name = TQString(i18n("Ornament track %1 bar %2").arg(track->getPosition() + 1).arg(barNo + 1));
    } else {
        name = TQString(i18n("Ornament bar %1").arg(barNo + 1));
    }

    MakeOrnamentDialog dialog(this, name, basePitch);
    if (dialog.exec() != TQDialog::Accepted)
        return ;

    name = dialog.getName();
    basePitch = dialog.getBasePitch();

    KMacroCommand *command = new KMacroCommand(i18n("Make Ornament"));

    command->addCommand(new CutCommand
                        (*m_currentEventSelection,
                         getDocument()->getClipboard()));

    command->addCommand(new PasteToTriggerSegmentCommand
                        (&getDocument()->getComposition(),
                         getDocument()->getClipboard(),
                         name, basePitch));

    command->addCommand(new InsertTriggerNoteCommand
                        (segment, absTime, note, basePitch, baseVelocity,
                         style->getName(),
                         getDocument()->getComposition().getNextTriggerSegmentId(),
                         true,
                         BaseProperties::TRIGGER_SEGMENT_ADJUST_SQUISH,
                         Marks::NoMark)); //!!!

    addCommandToHistory(command);
}

void
NotationView::slotUseOrnament()
{
    // Take an existing note and match an ornament to it.

    if (!m_currentEventSelection)
        return ;

    UseOrnamentDialog dialog(this, &getDocument()->getComposition());
    if (dialog.exec() != TQDialog::Accepted)
        return ;

    addCommandToHistory(new SetTriggerCommand(*m_currentEventSelection,
                                              dialog.getId(),
                                              true,
                                              dialog.getRetune(),
                                              dialog.getTimeAdjust(),
                                              dialog.getMark(),
                                              i18n("Use Ornament")));
}

void
NotationView::slotRemoveOrnament()
{
    if (!m_currentEventSelection)
        return ;

    addCommandToHistory(new ClearTriggersCommand(*m_currentEventSelection,
                                                 i18n("Remove Ornaments")));
}

void NotationView::slotEditAddClef()
{
    Staff *staff = getCurrentStaff();
    Segment &segment = staff->getSegment();
    static Clef lastClef;
    Clef clef;
    Rosegarden::Key key;
    timeT insertionTime = getInsertionTime(clef, key);

    ClefDialog dialog(this, m_notePixmapFactory, lastClef);

    if (dialog.exec() == TQDialog::Accepted) {

        ClefDialog::ConversionType conversion = dialog.getConversionType();

        bool shouldChangeOctave = (conversion != ClefDialog::NoConversion);
        bool shouldTranspose = (conversion == ClefDialog::Transpose);

        addCommandToHistory
            (new ClefInsertionCommand
             (segment, insertionTime, dialog.getClef(),
              shouldChangeOctave, shouldTranspose));

        lastClef = dialog.getClef();
    }
}

void NotationView::slotEditAddKeySignature()
{
    Staff *staff = getCurrentStaff();
    Segment &segment = staff->getSegment();
    Clef clef;
    Rosegarden::Key key;
    timeT insertionTime = getInsertionTime(clef, key);

    //!!! experimental:
    CompositionTimeSliceAdapter adapter
        (&getDocument()->getComposition(), insertionTime,
         getDocument()->getComposition().getDuration());
    AnalysisHelper helper;
    key = helper.guessKey(adapter);

    KeySignatureDialog dialog
        (this, m_notePixmapFactory, clef, key, true, true,
         i18n("Estimated key signature shown"));

    if (dialog.exec() == TQDialog::Accepted &&
        dialog.isValid()) {

        KeySignatureDialog::ConversionType conversion =
            dialog.getConversionType();

        bool transposeKey = dialog.shouldBeTransposed();
        bool applyToAll = dialog.shouldApplyToAll();
	bool ignorePercussion = dialog.shouldIgnorePercussion();

        if (applyToAll) {
            addCommandToHistory
                (new MultiKeyInsertionCommand
                 (getDocument(),
                  insertionTime, dialog.getKey(),
                  conversion == KeySignatureDialog::Convert,
                  conversion == KeySignatureDialog::Transpose,
                  transposeKey,
		  ignorePercussion));
        } else {
            addCommandToHistory
                (new KeyInsertionCommand
                 (segment,
                  insertionTime, dialog.getKey(),
                  conversion == KeySignatureDialog::Convert,
                  conversion == KeySignatureDialog::Transpose,
                  transposeKey,
		  false));
        }
    }
}

void NotationView::slotEditAddSustain(bool down)
{
    Staff *staff = getCurrentStaff();
    Segment &segment = staff->getSegment();
    timeT insertionTime = getInsertionTime();

    Studio *studio = &getDocument()->getStudio();
    Track *track = segment.getComposition()->getTrackById(segment.getTrack());

    if (track) {

        Instrument *instrument = studio->getInstrumentById
            (track->getInstrument());
        if (instrument) {
            MidiDevice *device = dynamic_cast<MidiDevice *>
                (instrument->getDevice());
            if (device) {
                for (ControlList::const_iterator i =
                         device->getControlParameters().begin();
                     i != device->getControlParameters().end(); ++i) {

                    if (i->getType() == Controller::EventType &&
                        (i->getName() == "Sustain" ||
                         strtoqstr(i->getName()) == i18n("Sustain"))) {

                        addCommandToHistory
                            (new SustainInsertionCommand(segment, insertionTime, down,
                                                         i->getControllerValue()));
                        return ;
                    }
                }
            } else if (instrument->getDevice() &&
                       instrument->getDevice()->getType() == Device::SoftSynth) {
                addCommandToHistory
                    (new SustainInsertionCommand(segment, insertionTime, down, 64));
            }
        }
    }

    KMessageBox::sorry(this, i18n("There is no sustain controller defined for this device.\nPlease ensure the device is configured correctly in the Manage MIDI Devices dialog in the main window."));
}

void NotationView::slotEditAddSustainDown()
{
    slotEditAddSustain(true);
}

void NotationView::slotEditAddSustainUp()
{
    slotEditAddSustain(false);
}

void NotationView::slotEditTranspose()
{
    IntervalDialog intervalDialog(this, true, true);
    int ok = intervalDialog.exec();
    
    int semitones = intervalDialog.getChromaticDistance();
    int steps = intervalDialog.getDiatonicDistance();

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

    // TODO combine commands into one 
    for (int i = 0; i < m_segments.size(); i++)
    {
        addCommandToHistory(new SegmentTransposeCommand(*(m_segments[i]), 
            intervalDialog.getChangeKey(), steps, semitones, 
            intervalDialog.getTransposeSegmentBack()));
    }
}

void NotationView::slotEditSwitchPreset()
{
    PresetHandlerDialog dialog(this, true);
    
    if (dialog.exec() != TQDialog::Accepted) return;
    
    if (dialog.getConvertAllSegments()) {
        // get all segments for this track and convert them.
        Composition& comp = getDocument()->getComposition();
        TrackId selectedTrack = getCurrentSegment()->getTrack();

	// satisfy #1885251 the way that seems most reasonble to me at the
	// moment, only changing track parameters when acting on all segments on
	// this track from the notation view 
	//
	//!!! This won't be undoable, and I'm not sure if that's seriously
	// wrong, or just mildly wrong, but I'm betting somebody will tell me
	// about it if this was inappropriate
	Track *track = comp.getTrackById(selectedTrack);
	track->setPresetLabel(dialog.getName().ascii());
	track->setClef(dialog.getClef());
	track->setTranspose(dialog.getTranspose());
	track->setLowestPlayable(dialog.getLowRange());
	track->setHighestPlayable(dialog.getHighRange());

        addCommandToHistory(new SegmentSyncCommand(comp.getSegments(), selectedTrack,
                            dialog.getTranspose(), 
                            dialog.getLowRange(), 
                            dialog.getHighRange(),
                            clefIndexToClef(dialog.getClef())));
    } else {
        addCommandToHistory(new SegmentSyncCommand(m_segments, 
                            dialog.getTranspose(), 
                            dialog.getLowRange(), 
                            dialog.getHighRange(),
                            clefIndexToClef(dialog.getClef())));
    }

    m_doc->slotDocumentModified();
    emit updateView();
}

void NotationView::slotEditElement(NotationStaff *staff,
                                   NotationElement *element, bool advanced)
{
    if (advanced) {

        EventEditDialog dialog(this, *element->event(), true);

        if (dialog.exec() == TQDialog::Accepted &&
            dialog.isModified()) {

            EventEditCommand *command = new EventEditCommand
                (staff->getSegment(),
                 element->event(),
                 dialog.getEvent());

            addCommandToHistory(command);
        }

    } else if (element->event()->isa(Clef::EventType)) {

        try {
            ClefDialog dialog(this, m_notePixmapFactory,
                              Clef(*element->event()));

            if (dialog.exec() == TQDialog::Accepted) {

                ClefDialog::ConversionType conversion = dialog.getConversionType();
                bool shouldChangeOctave = (conversion != ClefDialog::NoConversion);
                bool shouldTranspose = (conversion == ClefDialog::Transpose);
                addCommandToHistory
                    (new ClefInsertionCommand
                     (staff->getSegment(), element->event()->getAbsoluteTime(),
                      dialog.getClef(), shouldChangeOctave, shouldTranspose));
            }
        } catch (Exception e) {
            std::cerr << e.getMessage() << std::endl;
        }

        return ;

    } else if (element->event()->isa(Rosegarden::Key::EventType)) {

        try {
            Clef clef(staff->getSegment().getClefAtTime
                      (element->event()->getAbsoluteTime()));
            KeySignatureDialog dialog
                (this, m_notePixmapFactory, clef, Rosegarden::Key(*element->event()),
                 false, true);

            if (dialog.exec() == TQDialog::Accepted &&
                dialog.isValid()) {

                KeySignatureDialog::ConversionType conversion =
                    dialog.getConversionType();

                addCommandToHistory
                    (new KeyInsertionCommand
                     (staff->getSegment(),
                      element->event()->getAbsoluteTime(), dialog.getKey(),
                      conversion == KeySignatureDialog::Convert,
                      conversion == KeySignatureDialog::Transpose,
                      dialog.shouldBeTransposed(),
		      dialog.shouldIgnorePercussion()));
            }

        } catch (Exception e) {
            std::cerr << e.getMessage() << std::endl;
        }

        return ;

    } else if (element->event()->isa(Text::EventType)) {

        try {
            TextEventDialog dialog
                (this, m_notePixmapFactory, Text(*element->event()));
            if (dialog.exec() == TQDialog::Accepted) {
                TextInsertionCommand *command = new TextInsertionCommand
                    (staff->getSegment(),
                     element->event()->getAbsoluteTime(),
                     dialog.getText());
                KMacroCommand *macroCommand = new KMacroCommand(command->name());
                macroCommand->addCommand(new EraseEventCommand(staff->getSegment(),
                                                               element->event(), false));
                macroCommand->addCommand(command);
                addCommandToHistory(macroCommand);
            }
        } catch (Exception e) {
            std::cerr << e.getMessage() << std::endl;
        }

        return ;

    } else if (element->isNote() &&
               element->event()->has(BaseProperties::TRIGGER_SEGMENT_ID)) {

        int id = element->event()->get
            <Int>
            (BaseProperties::TRIGGER_SEGMENT_ID);
        emit editTriggerSegment(id);
        return ;

    } else {

        SimpleEventEditDialog dialog(this, getDocument(), *element->event(), false);

        if (dialog.exec() == TQDialog::Accepted &&
            dialog.isModified()) {

            EventEditCommand *command = new EventEditCommand
                (staff->getSegment(),
                 element->event(),
                 dialog.getEvent());

            addCommandToHistory(command);
        }
    }
}

void NotationView::slotBeginLilyPondRepeat()
{}

void NotationView::slotDebugDump()
{
    if (m_currentEventSelection) {
        EventSelection::eventcontainer &ec =
            m_currentEventSelection->getSegmentEvents();
        int n = 0;
        for (EventSelection::eventcontainer::iterator i =
                 ec.begin();
             i != ec.end(); ++i) {
            std::cerr << "\n" << n++ << " [" << (*i) << "]" << std::endl;
            (*i)->dump(std::cerr);
        }
    }
}

void
NotationView::slotSetPointerPosition(timeT time)
{
    slotSetPointerPosition(time, m_playTracking);
}

void
NotationView::slotSetPointerPosition(timeT time, bool scroll)
{
    Composition &comp = getDocument()->getComposition();
    int barNo = comp.getBarNumber(time);

    int minCy = 0;
    double cx = 0;
    bool haveMinCy = false;

    for (unsigned int i = 0; i < m_staffs.size(); ++i) {

        double layoutX = m_hlayout->getXForTimeByEvent(time);
        Segment &seg = m_staffs[i]->getSegment();

        bool good = true;

        if (barNo >= m_hlayout->getLastVisibleBarOnStaff(*m_staffs[i])) {
            if (seg.isRepeating() && time < seg.getRepeatEndTime()) {
                timeT mappedTime =
                    seg.getStartTime() +
                    ((time - seg.getStartTime()) %
                     (seg.getEndMarkerTime() - seg.getStartTime()));
                layoutX = m_hlayout->getXForTimeByEvent(mappedTime);
            } else {
                good = false;
            }
        } else if (barNo < m_hlayout->getFirstVisibleBarOnStaff(*m_staffs[i])) {
            good = false;
        }

        if (!good) {

            m_staffs[i]->hidePointer();

        } else {

            m_staffs[i]->setPointerPosition(layoutX);

            int cy;
            m_staffs[i]->getPointerPosition(cx, cy);

            if (!haveMinCy || cy < minCy) {
                minCy = cy;
                haveMinCy = true;
            }
        }
    }

    if (m_pageMode == LinedStaff::LinearMode) {
        // be careful not to prevent user from scrolling up and down
        haveMinCy = false;
    }

    if (scroll) {
        getCanvasView()->slotScrollHoriz(int(cx));
        if (haveMinCy) {
            getCanvasView()->slotScrollVertToTop(minCy);
        }
    }

    updateView();
}

void
NotationView::slotUpdateRecordingSegment(Segment *segment,
                                         timeT updateFrom)
{
    NOTATION_DEBUG << "NotationView::slotUpdateRecordingSegment: segment " << segment << ", updateFrom " << updateFrom << ", end time " << segment->getEndMarkerTime() << endl;
    if (updateFrom >= segment->getEndMarkerTime())
        return ;
    for (unsigned int i = 0; i < m_staffs.size(); ++i) {
        if (&m_staffs[i]->getSegment() == segment) {
            refreshSegment(segment, 0, 0);
        }
    }
    NOTATION_DEBUG << "NotationView::slotUpdateRecordingSegment: don't have segment " << segment << endl;
}

void
NotationView::slotSetCurrentStaff(double x, int y)
{
    unsigned int staffNo;
    for (staffNo = 0; staffNo < m_staffs.size(); ++staffNo) {
        if (m_staffs[staffNo]->containsCanvasCoords(x, y))
            break;
    }

    if (staffNo < m_staffs.size()) {
        slotSetCurrentStaff(staffNo);
    }
}

void
NotationView::slotSetCurrentStaff(int staffNo)
{
    NOTATION_DEBUG << "NotationView::slotSetCurrentStaff(" << staffNo << ")" << endl;

    if (m_currentStaff != staffNo) {

        m_staffs[m_currentStaff]->setCurrent(false);

        m_currentStaff = staffNo;

        m_staffs[m_currentStaff]->setCurrent(true);

        Segment *segment = &m_staffs[m_currentStaff]->getSegment();

        m_chordNameRuler->setCurrentSegment(segment);
        m_rawNoteRuler->setCurrentSegment(segment);
        m_rawNoteRuler->repaint();
        setControlRulersCurrentSegment();

        updateView();

        slotSetInsertCursorPosition(getInsertionTime(), false, false);

        m_headersGroup->setCurrent(
                                m_staffs[staffNo]->getSegment().getTrack());
    }
}

void
NotationView::slotCurrentStaffUp()
{
    LinedStaff *staff = getStaffAbove();
    if (!staff) return;
    slotSetCurrentStaff(staff->getId());
}

void
NotationView::slotCurrentStaffDown()
{
    LinedStaff *staff = getStaffBelow();
    if (!staff) return;
    slotSetCurrentStaff(staff->getId());
}

void
NotationView::slotCurrentSegmentPrior()
{
    if (m_staffs.size() < 2)
        return ;

    Composition *composition =
        m_staffs[m_currentStaff]->getSegment().getComposition();

    Track *track = composition->
        getTrackById(m_staffs[m_currentStaff]->getSegment().getTrack());
    if (!track)
        return ;

    int lastStaffOnTrack = -1;

    //
    // TODO: Cycle segments through rather in time order?
    //       Cycle only segments in the field of view?
    //
    for (int i = m_staffs.size()-1; i >= 0; --i) {
        if (m_staffs[i]->getSegment().getTrack() == track->getId()) {
	    if (lastStaffOnTrack < 0) {
                lastStaffOnTrack = i;
	    } 
	    if (i < m_currentStaff) {
		slotSetCurrentStaff(i);
		slotEditSelectWholeStaff();
		return ;
	    }
        }
    }
    if (lastStaffOnTrack >= 0) {
	slotSetCurrentStaff(lastStaffOnTrack);
	slotEditSelectWholeStaff();
	return ;
    }
}

void
NotationView::slotCurrentSegmentNext()
{
    if (m_staffs.size() < 2)
        return ;

    Composition *composition =
        m_staffs[m_currentStaff]->getSegment().getComposition();

    Track *track = composition->
        getTrackById(m_staffs[m_currentStaff]->getSegment().getTrack());
    if (!track)
        return ;

    int firstStaffOnTrack = -1;

    //
    // TODO: Cycle segments through rather in time order?
    //       Cycle only segments in the field of view?
    //
    for (unsigned int i = 0; i < m_staffs.size(); ++i) {
        if (m_staffs[i]->getSegment().getTrack() == track->getId()) {
	    if (firstStaffOnTrack < 0) {
                firstStaffOnTrack = i;
	    } 
	    if (i > m_currentStaff) {
		slotSetCurrentStaff(i);
		slotEditSelectWholeStaff();
		return ;
	    }
        }
    }
    if (firstStaffOnTrack >= 0) {
	slotSetCurrentStaff(firstStaffOnTrack);
	slotEditSelectWholeStaff();
	return ;
    }
}

void
NotationView::slotSetInsertCursorPosition(double x, int y, bool scroll,
                                          bool updateNow)
{
    NOTATION_DEBUG << "NotationView::slotSetInsertCursorPosition: x " << x << ", y " << y << ", scroll " << scroll << ", now " << updateNow << endl;

    slotSetCurrentStaff(x, y);

    LinedStaff *staff = getLinedStaff(m_currentStaff);
    Event *clefEvt, *keyEvt;
    NotationElementList::iterator i =
        staff->getElementUnderCanvasCoords(x, y, clefEvt, keyEvt);

    if (i == staff->getViewElementList()->end()) {
        slotSetInsertCursorPosition(staff->getSegment().getEndTime(), scroll,
                                    updateNow);
    } else {
        slotSetInsertCursorPosition((*i)->getViewAbsoluteTime(), scroll,
                                    updateNow);
    }
}

void
NotationView::slotSetInsertCursorPosition(timeT t, bool scroll, bool updateNow)
{
    NOTATION_DEBUG << "NotationView::slotSetInsertCursorPosition: time " << t << ", scroll " << scroll << ", now " << updateNow << endl;

    m_insertionTime = t;
    if (scroll) {
        m_deferredCursorMove = CursorMoveAndMakeVisible;
    } else {
        m_deferredCursorMove = CursorMoveOnly;
    }
    if (updateNow)
        doDeferredCursorMove();
}

void
NotationView::slotSetInsertCursorAndRecentre(timeT t, double cx, int,
                                             bool updateNow)
{
    NOTATION_DEBUG << "NotationView::slotSetInsertCursorAndRecentre: time " << t << ", cx " << cx << ", now " << updateNow << ", contentsx" << getCanvasView()->contentsX() << ", w " << getCanvasView()->visibleWidth() << endl;

    m_insertionTime = t;

    // We only do the scroll bit if cx is in the right two-thirds of
    // the window

    if (cx < (getCanvasView()->contentsX() +
              getCanvasView()->visibleWidth() / 3)) {

        m_deferredCursorMove = CursorMoveOnly;
    } else {
        m_deferredCursorMove = CursorMoveAndScrollToPosition;
        m_deferredCursorScrollToX = cx;
    }

    if (updateNow)
        doDeferredCursorMove();
}

void
NotationView::doDeferredCursorMove()
{
    NOTATION_DEBUG << "NotationView::doDeferredCursorMove: m_deferredCursorMove == " << m_deferredCursorMove << endl;

    if (m_deferredCursorMove == NoCursorMoveNeeded) {
        return ;
    }

    DeferredCursorMoveType type = m_deferredCursorMove;
    m_deferredCursorMove = NoCursorMoveNeeded;

    timeT t = m_insertionTime;

    if (m_staffs.size() == 0)
        return ;
    LinedStaff *staff = getCurrentLinedStaff();
    Segment &segment = staff->getSegment();

    if (t < segment.getStartTime()) {
        t = segment.getStartTime();
    }
    if (t > segment.getEndTime()) {
        t = segment.getEndTime();
    }

    NotationElementList::iterator i =
        staff->getViewElementList()->findNearestTime(t);

    while (i != staff->getViewElementList()->end() &&
           !static_cast<NotationElement*>(*i)->getCanvasItem())
        ++i;

    if (i == staff->getViewElementList()->end()) {
        //!!! ???
        if (m_insertionTime >= staff->getSegment().getStartTime()) {
            i = staff->getViewElementList()->begin();
        }
        m_insertionTime = staff->getSegment().getStartTime();
    } else {
        m_insertionTime = static_cast<NotationElement*>(*i)->getViewAbsoluteTime();
    }

    if (i == staff->getViewElementList()->end() ||
        t == segment.getEndTime() ||
        t == segment.getBarStartForTime(t)) {

        staff->setInsertCursorPosition(*m_hlayout, t);

        if (type == CursorMoveAndMakeVisible) {
            double cx;
            int cy;
            staff->getInsertCursorPosition(cx, cy);
            getCanvasView()->slotScrollHoriz(int(cx));
            getCanvasView()->slotScrollVertSmallSteps(cy);
        }

    } else {

        // prefer a note or rest, if there is one, to a non-spacing event
        if (!static_cast<NotationElement*>(*i)->isNote() &&
            !static_cast<NotationElement*>(*i)->isRest()) {
            NotationElementList::iterator j = i;
            while (j != staff->getViewElementList()->end()) {
                if (static_cast<NotationElement*>(*j)->getViewAbsoluteTime() !=
                    static_cast<NotationElement*>(*i)->getViewAbsoluteTime())
                    break;
                if (static_cast<NotationElement*>(*j)->getCanvasItem()) {
                    if (static_cast<NotationElement*>(*j)->isNote() ||
                        static_cast<NotationElement*>(*j)->isRest()) {
                        i = j;
                        break;
                    }
                }
                ++j;
            }
        }

        if (static_cast<NotationElement*>(*i)->getCanvasItem()) {

            staff->setInsertCursorPosition
                (static_cast<NotationElement*>(*i)->getCanvasX() - 2,
                 int(static_cast<NotationElement*>(*i)->getCanvasY()));

            if (type == CursorMoveAndMakeVisible) {
                getCanvasView()->slotScrollHoriz
                    (int(static_cast<NotationElement*>(*i)->getCanvasX()) - 4);
            }
        } else {
            std::cerr << "WARNING: No canvas item for this notation element:";
            (*i)->event()->dump(std::cerr);
        }
    }

    if (type == CursorMoveAndScrollToPosition) {

        // get current canvas x of insert cursor, which might not be
        // what we just set

        double ccx = 0.0;

        NotationElementList::iterator i =
            staff->getViewElementList()->findTime(t);

        if (i == staff->getViewElementList()->end()) {
            if (i == staff->getViewElementList()->begin())
                return ;
            double lx, lwidth;
            --i;
            if (static_cast<NotationElement*>(*i)->getCanvasItem()) {
                ccx = static_cast<NotationElement*>(*i)->getCanvasX();
                static_cast<NotationElement*>(*i)->getLayoutAirspace(lx, lwidth);
            } else {
                std::cerr << "WARNING: No canvas item for this notation element*:";
                (*i)->event()->dump(std::cerr);
            }
            ccx += lwidth;
        } else {
            if (static_cast<NotationElement*>(*i)->getCanvasItem()) {
                ccx = static_cast<NotationElement*>(*i)->getCanvasX();
            } else {
                std::cerr << "WARNING: No canvas item for this notation element*:";
                (*i)->event()->dump(std::cerr);
            }
        }

        TQScrollBar* hbar = getCanvasView()->horizontalScrollBar();
        hbar->setValue(int(hbar->value() - (m_deferredCursorScrollToX - ccx)));
    }

    updateView();
}

void
NotationView::slotJumpCursorToPlayback()
{
    slotSetInsertCursorPosition(getDocument()->getComposition().getPosition());
}

void
NotationView::slotJumpPlaybackToCursor()
{
    emit jumpPlaybackTo(getInsertionTime());
}

void
NotationView::slotToggleTracking()
{
    m_playTracking = !m_playTracking;
}

void NotationView::slotNoAccidental()
{
    emit changeAccidental(Accidentals::NoAccidental, false);
}

void NotationView::slotFollowAccidental()
{
    emit changeAccidental(Accidentals::NoAccidental, true);
}

void NotationView::slotSharp()
{
    emit changeAccidental(Accidentals::Sharp, false);
}

void NotationView::slotFlat()
{
    emit changeAccidental(Accidentals::Flat, false);
}

void NotationView::slotNatural()
{
    emit changeAccidental(Accidentals::Natural, false);
}

void NotationView::slotDoubleSharp()
{
    emit changeAccidental(Accidentals::DoubleSharp, false);
}

void NotationView::slotDoubleFlat()
{
    emit changeAccidental(Accidentals::DoubleFlat, false);
}

void NotationView::slotTrebleClef()
{
    m_currentNotePixmap->setPixmap
        (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap("clef-treble")));
    setTool(m_toolBox->getTool(ClefInserter::ToolName));

    dynamic_cast<ClefInserter*>(m_tool)->setClef(Clef::Treble);
    setMenuStates();
}

void NotationView::slotAltoClef()
{
    m_currentNotePixmap->setPixmap
        (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap("clef-alto")));
    setTool(m_toolBox->getTool(ClefInserter::ToolName));

    dynamic_cast<ClefInserter*>(m_tool)->setClef(Clef::Alto);
    setMenuStates();
}

void NotationView::slotTenorClef()
{
    m_currentNotePixmap->setPixmap
        (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap("clef-tenor")));
    setTool(m_toolBox->getTool(ClefInserter::ToolName));

    dynamic_cast<ClefInserter*>(m_tool)->setClef(Clef::Tenor);
    setMenuStates();
}

void NotationView::slotBassClef()
{
    m_currentNotePixmap->setPixmap
        (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap("clef-bass")));
    setTool(m_toolBox->getTool(ClefInserter::ToolName));

    dynamic_cast<ClefInserter*>(m_tool)->setClef(Clef::Bass);
    setMenuStates();
}

void NotationView::slotText()
{
    m_currentNotePixmap->setPixmap
        (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap("text")));
    setTool(m_toolBox->getTool(TextInserter::ToolName));
    setMenuStates();
}

void NotationView::slotGuitarChord()
{
    m_currentNotePixmap->setPixmap
        (NotePixmapFactory::toTQPixmap(NotePixmapFactory::makeToolbarPixmap("guitarchord")));
    setTool(m_toolBox->getTool(GuitarChordInserter::ToolName));
    setMenuStates();
}

void NotationView::slotEraseSelected()
{
    NOTATION_DEBUG << "NotationView::slotEraseSelected()" << endl;
    setTool(m_toolBox->getTool(NotationEraser::ToolName));
    setMenuStates();
}

void NotationView::slotSelectSelected()
{
    NOTATION_DEBUG << "NotationView::slotSelectSelected()" << endl;
    setTool(m_toolBox->getTool(NotationSelector::ToolName));
    setMenuStates();
}

void NotationView::slotLinearMode()
{
    setPageMode(LinedStaff::LinearMode);
}

void NotationView::slotContinuousPageMode()
{
    setPageMode(LinedStaff::ContinuousPageMode);
}

void NotationView::slotMultiPageMode()
{
    setPageMode(LinedStaff::MultiPageMode);
}

void NotationView::slotToggleChordsRuler()
{
    if (m_hlayout->isPageMode())
        return ;
    toggleWidget(m_chordNameRuler, "show_chords_ruler");
}

void NotationView::slotToggleRawNoteRuler()
{
    if (m_hlayout->isPageMode())
        return ;
    toggleWidget(m_rawNoteRuler, "show_raw_note_ruler");
}

void NotationView::slotToggleTempoRuler()
{
    if (m_hlayout->isPageMode())
        return ;
    toggleWidget(m_tempoRuler, "show_tempo_ruler");
}

void NotationView::slotToggleAnnotations()
{
    m_annotationsVisible = !m_annotationsVisible;
    slotUpdateAnnotationsStatus();
    //!!! use refresh mechanism
    refreshSegment(0, 0, 0);
}

void NotationView::slotToggleLilyPondDirectives()
{
    m_lilyPondDirectivesVisible = !m_lilyPondDirectivesVisible;
    slotUpdateLilyPondDirectivesStatus();
    //!!! use refresh mechanism
    refreshSegment(0, 0, 0);
}

void NotationView::slotEditLyrics()
{
    Staff *staff = getCurrentStaff();
    Segment &segment = staff->getSegment();

    LyricEditDialog dialog(this, &segment);

    if (dialog.exec() == TQDialog::Accepted) {

        KMacroCommand *macro = new KMacroCommand
            (SetLyricsCommand::getGlobalName());

        for (int i = 0; i < dialog.getVerseCount(); ++i) {
            SetLyricsCommand *command = new SetLyricsCommand
                (&segment, i, dialog.getLyricData(i));
            macro->addCommand(command);
        }

        addCommandToHistory(macro);
    }
}

void NotationView::slotItemPressed(int height, int staffNo,
                                   TQMouseEvent* e,
                                   NotationElement* el)
{
    NOTATION_DEBUG << "NotationView::slotItemPressed(height = "
                   << height << ", staffNo = " << staffNo
                   << ")" << endl;

    if (staffNo < 0 && el != 0) {
        // We have an element but no staff -- that's because the
        // element extended outside the staff region.  But we need
        // to handle it properly, so we rather laboriously need to
        // find out which staff it was.
        for (unsigned int i = 0; i < m_staffs.size(); ++i) {
            if (m_staffs[i]->getViewElementList()->findSingle(el) !=
                m_staffs[i]->getViewElementList()->end()) {
                staffNo = m_staffs[i]->getId();
                break;
            }
        }
    }

    ButtonState btnState = e->state();

    if (btnState & ControlButton) { // on ctrl-click, set cursor position

        slotSetInsertCursorPosition(e->x(), (int)e->y());

    } else {

        setActiveItem(0);

        timeT unknownTime = 0;

        if (e->type() == TQEvent::MouseButtonDblClick) {
            m_tool->handleMouseDoubleClick(unknownTime, height,
                                           staffNo, e, el);
        } else {
            m_tool->handleMousePress(unknownTime, height,
                                     staffNo, e, el);
        }
    }
}

void NotationView::slotNonNotationItemPressed(TQMouseEvent *e, TQCanvasItem *it)
{
    if (e->type() != TQEvent::MouseButtonDblClick)
        return ;

    Staff *staff = getStaffForCanvasCoords(e->x(), e->y());
    if (!staff)
        return ;

    NOTATION_DEBUG << "NotationView::slotNonNotationItemPressed(doubly)" << endl;

    if (dynamic_cast<QCanvasStaffNameSprite *>(it)) {

        std::string name =
            staff->getSegment().getComposition()->
            getTrackById(staff->getSegment().getTrack())->getLabel();

        bool ok = false;
        TQRegExpValidator validator(TQRegExp(".*"), this); // empty is OK

        TQString newText = KLineEditDlg::getText(TQString("Change staff name"),
                                                TQString("Enter new staff name"),
                                                strtoqstr(name),
                                                &ok,
                                                this,
                                                &validator);

        if (ok) {
            addCommandToHistory(new RenameTrackCommand
                                (staff->getSegment().getComposition(),
                                 staff->getSegment().getTrack(),
                                 qstrtostr(newText)));

            emit staffLabelChanged(staff->getSegment().getTrack(), newText);
        }

    } else if (dynamic_cast<TQCanvasTimeSigSprite *>(it)) {

        double layoutX = (dynamic_cast<TQCanvasTimeSigSprite *>(it))->getLayoutX();
        emit editTimeSignature(m_hlayout->getTimeForX(layoutX));
    }
}

void NotationView::slotTextItemPressed(TQMouseEvent *e, TQCanvasItem *it)
{
    if (e->type() != TQEvent::MouseButtonDblClick)
        return ;

    if (it == m_title) {
        emit editMetadata(strtoqstr(CompositionMetadataKeys::Title.getName()));
    } else if (it == m_subtitle) {
        emit editMetadata(strtoqstr(CompositionMetadataKeys::Subtitle.getName()));
    } else if (it == m_composer) {
        emit editMetadata(strtoqstr(CompositionMetadataKeys::Composer.getName()));
    } else if (it == m_copyright) {
        emit editMetadata(strtoqstr(CompositionMetadataKeys::Copyright.getName()));
    } else {
        return ;
    }

    positionStaffs();
}

void NotationView::slotMouseMoved(TQMouseEvent *e)
{
    if (activeItem()) {
        activeItem()->handleMouseMove(e);
        updateView();
    } else {
        int follow = m_tool->handleMouseMove(0, 0,  // unknown time and height
                                             e);

        if (getCanvasView()->isTimeForSmoothScroll()) {

            if (follow & RosegardenCanvasView::FollowHorizontal) {
                getCanvasView()->slotScrollHorizSmallSteps(e->x());
            }

            if (follow & RosegardenCanvasView::FollowVertical) {
                getCanvasView()->slotScrollVertSmallSteps(e->y());
            }

        }
    }
}

void NotationView::slotMouseReleased(TQMouseEvent *e)
{
    if (activeItem()) {
        activeItem()->handleMouseRelease(e);
        setActiveItem(0);
        updateView();
    } else
        m_tool->handleMouseRelease(0, 0,  // unknown time and height
                                   e);
}

void
NotationView::slotHoveredOverNoteChanged(const TQString &noteName)
{
    m_hoveredOverNoteName->setText(TQString(" ") + noteName);
}

void
NotationView::slotHoveredOverAbsoluteTimeChanged(unsigned int time)
{
    timeT t = time;
    RealTime rt =
        getDocument()->getComposition().getElapsedRealTime(t);
    long ms = rt.msec();

    int bar, beat, fraction, remainder;
    getDocument()->getComposition().getMusicalTimeForAbsoluteTime
        (t, bar, beat, fraction, remainder);

    //    TQString message;
    //    TQString format("%ld (%ld.%03lds)");
    //    format = i18n("Time: %1").arg(format);
    //    message.sprintf(format, t, rt.sec, ms);

    TQString message = i18n("Time: %1 (%2.%3s)")
        .arg(TQString("%1-%2-%3-%4")
             .arg(TQString("%1").arg(bar + 1).rightJustify(3, '0'))
             .arg(TQString("%1").arg(beat).rightJustify(2, '0'))
             .arg(TQString("%1").arg(fraction).rightJustify(2, '0'))
             .arg(TQString("%1").arg(remainder).rightJustify(2, '0')))
        .arg(rt.sec)
        .arg(TQString("%1").arg(ms).rightJustify(3, '0'));

    m_hoveredOverAbsoluteTime->setText(message);
}

void
NotationView::slotInsertableNoteEventReceived(int pitch, int velocity, bool noteOn)
{
    //!!! Problematic.  Ideally we wouldn't insert events into windows
    //that weren't actually visible, otherwise all hell could break
    //loose (metaphorically speaking, I should probably add).  I did
    //think of checking isActiveWindow() and returning if the current
    //window wasn't active, but that will prevent anyone from
    //step-recording from e.g. vkeybd, which cannot be used without
    //losing focus (and thus active-ness) from the Rosegarden window.

    //!!! I know -- we'll keep track of which edit view (or main view,
    //or mixer, etc) is active, and we'll only allow insertion into
    //the most recently activated.  How about that?

    TDEToggleAction *action = dynamic_cast<TDEToggleAction *>
        (actionCollection()->action("toggle_step_by_step"));
    if (!action) {
        NOTATION_DEBUG << "WARNING: No toggle_step_by_step action" << endl;
        return ;
    }
    if (!action->isChecked())
        return ;

    Segment &segment = m_staffs[m_currentStaff]->getSegment();

    NoteInserter *noteInserter = dynamic_cast<NoteInserter *>(m_tool);
    if (!noteInserter) {
        static bool showingError = false;
        if (showingError)
            return ;
        showingError = true;
        KMessageBox::sorry(this, i18n("Can't insert note: No note duration selected"));
        showingError = false;
        return ;
    }

    if (m_inPaintEvent) {
        NOTATION_DEBUG << "NotationView::slotInsertableNoteEventReceived: in paint event already" << endl;
        if (noteOn) {
            m_pendingInsertableNotes.push_back(std::pair<int, int>(pitch, velocity));
        }
        return ;
    }

    // If the segment is transposed, we want to take that into
    // account.  But the note has already been played back to the user
    // at its untransposed pitch, because that's done by the MIDI THRU
    // code in the sequencer which has no way to know whether a note
    // was intended for step recording.  So rather than adjust the
    // pitch for playback according to the transpose setting, we have
    // to adjust the stored pitch in the opposite direction.

    pitch -= segment.getTranspose();

    //    KTmpStatusMsg msg(i18n("Inserting note"), this);

    // We need to ensure that multiple notes hit at once come out as
    // chords, without imposing the interpretation that overlapping
    // notes are always chords and without getting too involved with
    // the actual absolute times of the notes (this is still step
    // editing, not proper recording).

    // First, if we're in chord mode, there's no problem.

    static int numberOfNotesOn = 0;
    static timeT insertionTime = getInsertionTime();
    static time_t lastInsertionTime = 0;

    if (isInChordMode()) {
        if (!noteOn)
            return ;
        NOTATION_DEBUG << "Inserting note in chord at pitch " << pitch << endl;
        noteInserter->insertNote(segment, getInsertionTime(), pitch,
                                 Accidentals::NoAccidental,
                                 true);

    } else {

        if (!noteOn) {
            numberOfNotesOn--;
        } else if (noteOn) {
            // Rules:
            //
            // * If no other note event has turned up within half a
            //   second, insert this note and advance.
            //
            // * Relatedly, if this note is within half a second of
            //   the previous one, they're chords.  Insert the previous
            //   one, don't advance, and use the same rules for this.
            //
            // * If a note event turns up before that time has elapsed,
            //   we need to wait for the note-off events: if the second
            //   note happened less than half way through the first,
            //   it's a chord.
            //
            // We haven't implemented these yet... For now:
            //
            // Rules (hjj):
            //
            // * The overlapping notes are always included in to a chord.
            //   This is the most convenient for step inserting of chords.
            //
            // * The timer resets the numberOfNotesOn, if noteOff signals were
            //   drop out for some reason (which has not been encountered yet).

            time_t now;
            time (&now);
            double elapsed = difftime(now, lastInsertionTime);
            time (&lastInsertionTime);

            if (numberOfNotesOn <= 0 || elapsed > 10.0 ) {
                numberOfNotesOn = 0;
                insertionTime = getInsertionTime();
            }
            numberOfNotesOn++;

            noteInserter->insertNote(segment, insertionTime, pitch,
                                     Accidentals::NoAccidental,
                                     true);
        }
    }
}

void
NotationView::slotInsertableNoteOnReceived(int pitch, int velocity)
{
    NOTATION_DEBUG << "NotationView::slotInsertableNoteOnReceived: " << pitch << endl;
    slotInsertableNoteEventReceived(pitch, velocity, true);
}

void
NotationView::slotInsertableNoteOffReceived(int pitch, int velocity)
{
    NOTATION_DEBUG << "NotationView::slotInsertableNoteOffReceived: " << pitch << endl;
    slotInsertableNoteEventReceived(pitch, velocity, false);
}

void
NotationView::slotInsertableTimerElapsed()
{}

void
NotationView::slotToggleStepByStep()
{
    TDEToggleAction *action = dynamic_cast<TDEToggleAction *>
        (actionCollection()->action("toggle_step_by_step"));
    if (!action) {
        NOTATION_DEBUG << "WARNING: No toggle_step_by_step action" << endl;
        return ;
    }
    if (action->isChecked()) { // after toggling, that is
        emit stepByStepTargetRequested(this);
    } else {
        emit stepByStepTargetRequested(0);
    }
}

void
NotationView::slotStepByStepTargetRequested(TQObject *obj)
{
    TDEToggleAction *action = dynamic_cast<TDEToggleAction *>
        (actionCollection()->action("toggle_step_by_step"));
    if (!action) {
        NOTATION_DEBUG << "WARNING: No toggle_step_by_step action" << endl;
        return ;
    }
    action->setChecked(obj == this);
}

void
NotationView::slotCheckRendered(double cx0, double cx1)
{
    //    NOTATION_DEBUG << "slotCheckRendered(" << cx0 << "," << cx1 << ")" << endl;

    bool something = false;

    for (size_t i = 0; i < m_staffs.size(); ++i) {

        LinedStaff *staff = m_staffs[i];

        LinedStaff::LinedStaffCoords cc0 = staff->getLayoutCoordsForCanvasCoords
            (cx0, 0);

        LinedStaff::LinedStaffCoords cc1 = staff->getLayoutCoordsForCanvasCoords
            (cx1, staff->getTotalHeight() + staff->getY());

        timeT t0 = m_hlayout->getTimeForX(cc0.first);
        timeT t1 = m_hlayout->getTimeForX(cc1.first);

        if (dynamic_cast<NotationStaff *>(staff)->checkRendered(t0, t1)) {
            something = true; //!!!
        }
    }

    if (something) {
        emit renderComplete();
        if (m_renderTimer)
            delete m_renderTimer;
        m_renderTimer = new TQTimer(this);
        connect(m_renderTimer, TQ_SIGNAL(timeout()), TQ_SLOT(slotRenderSomething()));
        m_renderTimer->start(0, true);
    }

    if (m_deferredCursorMove != NoCursorMoveNeeded)
        doDeferredCursorMove();
}

void
NotationView::slotRenderSomething()
{
    delete m_renderTimer;
    m_renderTimer = 0;
    static clock_t lastWork = 0;

    clock_t now = clock();
    long elapsed = ((now - lastWork) * 1000 / CLOCKS_PER_SEC);
    if (elapsed < 70) {
        m_renderTimer = new TQTimer(this);
        connect(m_renderTimer, TQ_SIGNAL(timeout()), TQ_SLOT(slotRenderSomething()));
        m_renderTimer->start(0, true);
        return ;
    }
    lastWork = now;

    for (size_t i = 0; i < m_staffs.size(); ++i) {

        if (m_staffs[i]->doRenderWork(m_staffs[i]->getSegment().getStartTime(),
                                      m_staffs[i]->getSegment().getEndTime())) {
            m_renderTimer = new TQTimer(this);
            connect(m_renderTimer, TQ_SIGNAL(timeout()), TQ_SLOT(slotRenderSomething()));
            m_renderTimer->start(0, true);
            return ;
        }
    }

    PixmapArrayGC::deleteAll();
    NOTATION_DEBUG << "NotationView::slotRenderSomething: updating thumbnails" << endl;
    updateThumbnails(true);

    // Update track headers when rendering is done
    // (better late than never)
    m_headersGroup->slotUpdateAllHeaders(getCanvasLeftX(), 0, true);
    m_headersGroupView->setContentsPos(getCanvasView()->contentsX(),
                                           getCanvasView()->contentsY());
}

NotationCanvasView* NotationView::getCanvasView()
{
    return dynamic_cast<NotationCanvasView *>(m_canvasView);
}

void
NotationView::slotVerticalScrollHeadersGroup(int y)
{
    m_headersGroupView->setContentsPos(0, y);
}

void
NotationView::slotShowHeadersGroup()
{
    m_showHeadersGroup = HeadersGroup::ShowAlways;
    showHeadersGroup();

    // Disable menu entry when headers are shown
    m_showHeadersMenuEntry->setEnabled(false);
}

void
NotationView::slotHideHeadersGroup()
{
    m_showHeadersGroup = HeadersGroup::ShowNever;
    hideHeadersGroup();

    // Enable menu entry when headers are hidden
    m_showHeadersMenuEntry->setEnabled(true);
}

void
NotationView::showHeadersGroup()
{
    if (m_headersGroupView && (m_pageMode == LinedStaff::LinearMode)) {
        m_headersGroupView->show();
        m_headersTopFrame->show();
        m_rulerBoxFiller->show();
    }
}

void
NotationView::hideHeadersGroup()
{
    if (m_headersGroupView) {
        m_headersGroupView->hide();
        m_headersTopFrame->hide();
        m_rulerBoxFiller->hide();
    }
}

void
NotationView::slotUpdateHeaders(int x, int y)
{
    m_headersGroup->slotUpdateAllHeaders(x, y);
    m_headersGroupView->setContentsPos(x, y);
}

void
NotationView::slotHeadersWidthChanged(int w)
{
    m_headersTopFrame->setFixedWidth(w);
    m_rulerBoxFiller->setFixedWidth(w);
    m_canvasView->updateLeftWidgetGeometry();
}


int
NotationView::getCanvasVisibleWidth()
{
    if (getCanvasView()) {
        return getCanvasView()->visibleWidth();
    } else {
        return -1;
    }
}

int
NotationView::getHeadersTopFrameMinWidth()
{
    /// TODO : use a real button width got from a real button

    // 2 buttons (2 x 24) + 2 margins (2 x 4) + buttons spacing (4)
    return 4 + 24 + 4 + 24 + 4;
}

}
#include "NotationView.moc"
