Logo Search packages:      
Sourcecode: rosegarden version File versions  Download package

notationviewslots.cpp

// -*- c-basic-offset: 4 -*-

/*
    Rosegarden-4
    A sequencer and musical notation editor.

    This program is Copyright 2000-2006
        Guillaume Laurent   <glaurent@telegraph-road.org>,
        Chris Cannam        <cannam@all-day-breakfast.com>,
        Richard Bown        <bownie@bownie.com>

    The moral right of the authors to claim authorship of this work
    has been asserted.

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of the
    License, or (at your option) any later version.  See the file
    COPYING included with this distribution for more information.
*/

#include <qlabel.h>
#include <qinputdialog.h>
#include <qvalidator.h>
#include <qtimer.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <kaction.h>
#include <kapp.h>
#include <kconfig.h>
#include <klineeditdlg.h>
#include <kprinter.h>

#include <algorithm>

#include "notationview.h"

#include "NotationTypes.h"
#include "Selection.h"
#include "Segment.h"
#include "Clipboard.h"
#include "CompositionTimeSliceAdapter.h"
#include "AnalysisTypes.h"
#include "MidiTypes.h"

#include "rosegardenguidoc.h"
#include "notationtool.h"
#include "editcommands.h"
#include "notationcommands.h"
#include "segmentcommands.h"
#include "dialogs.h"
#include "chordnameruler.h"
#include "temporuler.h"
#include "rawnoteruler.h"
#include "notationhlayout.h"
#include "notefont.h"
#include "eventfilter.h"
#include "qcanvassimplesprite.h"
#include "tempoview.h"
#include "notationstrings.h"

#include "ktmpstatusmsg.h"

#include <sys/time.h>

using Rosegarden::timeT;
using Rosegarden::Segment;
using Rosegarden::Event;
using Rosegarden::EventSelection;


void
00074 NotationView::slotUpdateInsertModeStatus()
{
    QString message;
    if (isInChordMode()) {
        if (isInTripletMode()) {
            message = i18n(" Triplet Chord");
        } else {
            message = i18n(" Chord");
        }
    } else {
        if (isInTripletMode()) {
            message = i18n(" Triplet");
        } else {
            message = "";
        }
    }
    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(Rosegarden::Text::EventType) &&
                    ((*j)->get<Rosegarden::String>
                     (Rosegarden::Text::TextTypePropertyName)
                     == Rosegarden::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(Rosegarden::Text::EventType) &&
                    ((*j)->get<Rosegarden::String>
                     (Rosegarden::Text::TextTypePropertyName)
                     == Rosegarden::Text::LilypondDirective)) {
                    m_lilypondDirectivesLabel->setText(i18n("Hidden LilyPond directives"));
                    return;
                }
            }
        }
    }
    m_lilypondDirectivesLabel->setText("");
    getToggleAction("show_lilypond_directives")->setChecked(areLilyPondDirectivesVisible());
}

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

void
00145 NotationView::slotChangeSpacingFromAction()
{
    const QObject *s = sender();
    QString 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
00162 NotationView::slotChangeSpacing(int spacing)
{
    if (m_hlayout->getSpacing() == spacing) return;

    m_hlayout->setSpacing(spacing);
    
//     m_spacingSlider->setSize(spacing);

    KToggleAction *action = dynamic_cast<KToggleAction *>
        (actionCollection()->action(QString("spacing_%1").arg(spacing)));
    if (action) action->setChecked(true);
    else {
      std::cerr
            << "WARNING: Expected action \"spacing_" << spacing
            << "\" to be a KToggleAction, 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
00194 NotationView::slotChangeProportionFromIndex(int n)
{
    std::vector<int> proportions = m_hlayout->getAvailableProportions();
    if (n >= (int)proportions.size()) n = proportions.size() - 1;
    slotChangeProportion(proportions[n]);
}

void
00202 NotationView::slotChangeProportionFromAction()
{
    const QObject *s = sender();
    QString 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
00218 NotationView::slotChangeProportion(int proportion)
{
    if (m_hlayout->getProportion() == proportion) return;

    m_hlayout->setProportion(proportion);
    
//    m_proportionSlider->setSize(proportion);

    KToggleAction *action = dynamic_cast<KToggleAction *>
        (actionCollection()->action(QString("proportion_%1").arg(proportion)));
    if (action) action->setChecked(true);
    else {
      std::cerr
            << "WARNING: Expected action \"proportion_" << proportion
            << "\" to be a KToggleAction, 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
00251 NotationView::slotChangeFontFromAction()
{
    const QObject *s = sender();
    QString 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
00265 NotationView::slotChangeFontSizeFromAction()
{
    const QObject *s = sender();
    QString 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
00287 NotationView::slotChangeFont(const QString &newName)
{
    NOTATION_DEBUG << "changeFont: " << newName << endl;
    slotChangeFont(std::string(newName.utf8()));
}


void
00295 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
00316 NotationView::slotChangeFontSize(int newSize)
{
    slotChangeFont(m_fontName, newSize);
}


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

void
00330 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
00342 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
00354 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);
        KToggleAction *action = dynamic_cast<KToggleAction *>
            (actionCollection()->action("note_font_" + strtoqstr(f[i])));
        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 KToggleAction, 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();
    QString 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
00444 NotationView::slotFilePrint()
{
    KTmpStatusMsg msg(i18n("Printing..."), this);

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

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

    printingView.print();
}

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

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

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

    printingView.print(true);
}


//
// Cut, Copy, Paste
//
00481 void NotationView::slotEditCut()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Cutting selection to clipboard..."), this);

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

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

    addCommandToHistory(new EraseCommand(*m_currentEventSelection));
}

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

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

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

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

static const QString RESTRICTED_PASTE_FAILED_DESCRIPTION = i18n(
                      "The Restricted paste type requires enough empty\n" \
                      "space (containing only rests) at the paste position\n" \
                      "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\n" \
                      "the other paste types from the \"Paste...\" option\n" \
                      "on the Edit menu.  You can also change the default\n" \
                      "paste type to something other than Restricted if\n" \
                      "you wish."
    );

00528 void NotationView::slotEditPaste()
{
    Rosegarden::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());

    KConfig *config = kapp->config();
    config->setGroup(NotationView::ConfigGroup);
    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);
        //!!! well, we really just want to select the events
        // we just pasted
        setCurrentSelection(new EventSelection
                            (segment, insertionTime, endTime));
      slotSetInsertCursorPosition(endTime, true, false);
    }
}

00576 void NotationView::slotEditGeneralPaste()
{
    Rosegarden::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();

    KConfig *config = kapp->config();
    config->setGroup(NotationView::ConfigGroup);
    PasteEventsCommand::PasteType defaultType = (PasteEventsCommand::PasteType)
        config->readUnsignedNumEntry("pastetype",
                                     PasteEventsCommand::Restricted);
    
    PasteNotationDialog dialog(this, defaultType);

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

        PasteEventsCommand::PasteType type = dialog.getPasteType();
        if (dialog.setAsDefault()) {
          config->setGroup(NotationView::ConfigGroup);
            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));
        } else {
            addCommandToHistory(command);
            setCurrentSelection(new EventSelection
                                (segment, insertionTime, endTime));
          slotSetInsertCursorPosition(endTime, true, false);
        }
    }
}

00628 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);
    }
}

//!!! these should be in matrix too

00660 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() == QDialog::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));
}

00780 void NotationView::slotToggleToolsToolBar()
{
    toggleNamedToolBar("Tools Toolbar");
}

00785 void NotationView::slotToggleNotesToolBar()
{
    toggleNamedToolBar("Notes Toolbar");
}

00790 void NotationView::slotToggleRestsToolBar()
{
    toggleNamedToolBar("Rests Toolbar");
}

00795 void NotationView::slotToggleAccidentalsToolBar()
{
    toggleNamedToolBar("Accidentals Toolbar");
}

00800 void NotationView::slotToggleClefsToolBar()
{
    toggleNamedToolBar("Clefs Toolbar");
}

00805 void NotationView::slotToggleMetaToolBar()
{
    toggleNamedToolBar("Meta Toolbar");
}

00810 void NotationView::slotToggleMarksToolBar()
{
    toggleNamedToolBar("Marks Toolbar");
}

00815 void NotationView::slotToggleGroupToolBar()
{
    toggleNamedToolBar("Group Toolbar");
}

00820 void NotationView::slotToggleLayoutToolBar()
{
    toggleNamedToolBar("Layout Toolbar");
}

00825 void NotationView::slotToggleTransportToolBar()
{
    toggleNamedToolBar("Transport Toolbar");
}

00830 void NotationView::toggleNamedToolBar(const QString& toolBarName, bool* force)
{
    KToolBar *namedToolBar = toolBar(toolBarName);

    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();

}

//
// Group stuff
//

00862 void NotationView::slotGroupBeam()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Beaming group..."), this);

    addCommandToHistory(new NotesMenuBeamCommand
                        (*m_currentEventSelection));
}

void NotationView::slotGroupAutoBeam()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Auto-beaming selection..."), this);

    addCommandToHistory(new NotesMenuAutoBeamCommand
                        (*m_currentEventSelection));
}

void NotationView::slotGroupBreak()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Breaking groups..."), this);

    addCommandToHistory(new NotesMenuBreakCommand
                        (*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();
        Rosegarden::Note::Type unitType =
            Rosegarden::Note::getNearestNote(duration / 3, 0).getNoteType();
        unit = Rosegarden::Note(unitType).getDuration();

        if (!simple) {
            TupletDialog dialog(this, unitType, duration);
            if (dialog.exec() != QDialog::Accepted) return;
            unit = Rosegarden::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));

        Rosegarden::Note::Type unitType;

        if (currentInserter) {
            unitType = currentInserter->getCurrentNote().getNoteType();
        } else {
            unitType = Rosegarden::Note::Quaver;
        }

        unit = Rosegarden::Note(unitType).getDuration();

        if (!simple) {
            TupletDialog dialog(this, unitType);
            if (dialog.exec() != QDialog::Accepted) return;
            unit = Rosegarden::Note(dialog.getUnitType()).getDuration();
            tupled = dialog.getTupledCount();
            untupled = dialog.getUntupledCount();
          hasTimingAlready = dialog.hasTimingAlready();
        }

        segment = &m_staffs[m_currentStaff]->getSegment();
    }

    addCommandToHistory(new AdjustMenuTupletCommand
                        (*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 AdjustMenuUnTupletCommand
                        (*m_currentEventSelection));
}

void NotationView::slotGroupGrace()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Making grace notes..."), this);

    addCommandToHistory(new AdjustMenuGraceCommand(*m_currentEventSelection));
}

void NotationView::slotGroupUnGrace()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Making non-grace notes..."), this);

    addCommandToHistory(new AdjustMenuUnGraceCommand(*m_currentEventSelection));
}


//
// indications stuff
//

void NotationView::slotGroupSlur()
{
    KTmpStatusMsg msg(i18n("Adding slur..."), this);
    slotAddIndication(Rosegarden::Indication::Slur, i18n("slur"));
} 

void NotationView::slotGroupPhrasingSlur()
{
    KTmpStatusMsg msg(i18n("Adding phrasing slur..."), this);
    slotAddIndication(Rosegarden::Indication::PhrasingSlur, i18n("phrasing slur"));
} 

void NotationView::slotGroupGlissando()
{
    KTmpStatusMsg msg(i18n("Adding glissando..."), this);
    slotAddIndication(Rosegarden::Indication::Glissando, i18n("glissando"));
} 
  
void NotationView::slotGroupCrescendo()
{
    KTmpStatusMsg msg(i18n("Adding crescendo..."), this);
    slotAddIndication(Rosegarden::Indication::Crescendo, i18n("dynamic"));
} 
  
void NotationView::slotGroupDecrescendo()
{
    KTmpStatusMsg msg(i18n("Adding decrescendo..."), this);
    slotAddIndication(Rosegarden::Indication::Decrescendo, i18n("dynamic"));
} 

void NotationView::slotGroupOctave2Up()
{
    KTmpStatusMsg msg(i18n("Adding octave..."), this);
    slotAddIndication(Rosegarden::Indication::QuindicesimaUp, i18n("ottava"));
} 

void NotationView::slotGroupOctaveUp()
{
    KTmpStatusMsg msg(i18n("Adding octave..."), this);
    slotAddIndication(Rosegarden::Indication::OttavaUp, i18n("ottava"));
} 

void NotationView::slotGroupOctaveDown()
{
    KTmpStatusMsg msg(i18n("Adding octave..."), this);
    slotAddIndication(Rosegarden::Indication::OttavaDown, i18n("ottava"));
} 

void NotationView::slotGroupOctave2Down()
{
    KTmpStatusMsg msg(i18n("Adding octave..."), this);
    slotAddIndication(Rosegarden::Indication::QuindicesimaDown, i18n("ottava"));
} 

void NotationView::slotAddIndication(std::string type, QString desc)
{
    if (!m_currentEventSelection) return;

    NotesMenuAddIndicationCommand *command =
        new NotesMenuAddIndicationCommand(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);

    AdjustMenuMakeChordCommand *command =
      new AdjustMenuMakeChordCommand(*m_currentEventSelection);

    addCommandToHistory(command);
}
    
 
// 
// transforms stuff
//
 
01082 void NotationView::slotTransformsNormalizeRests()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Normalizing rests..."), this);

    addCommandToHistory(new AdjustMenuNormalizeRestsCommand
                        (*m_currentEventSelection));
}

void NotationView::slotTransformsCollapseRests()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Collapsing rests..."), this);

    addCommandToHistory(new AdjustMenuCollapseRestsCommand
                        (*m_currentEventSelection));
}

void NotationView::slotTransformsCollapseNotes()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Collapsing notes..."), this);

    addCommandToHistory(new AdjustMenuCollapseNotesCommand
                        (*m_currentEventSelection));
}

void NotationView::slotTransformsTieNotes()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Tying notes..."), this);

    addCommandToHistory(new NotesMenuTieNotesCommand
                        (*m_currentEventSelection));
}

void NotationView::slotTransformsUntieNotes()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Untying notes..."), this);

    addCommandToHistory(new AdjustMenuUntieNotesCommand
                        (*m_currentEventSelection));
}

void NotationView::slotTransformsMakeNotesViable()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Making notes viable..."), this);

    addCommandToHistory(new AdjustMenuMakeNotesViableCommand
                        (*m_currentEventSelection));
}

void NotationView::slotTransformsDeCounterpoint()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Removing counterpoint..."), this);

    addCommandToHistory(new AdjustMenuDeCounterpointCommand
                        (*m_currentEventSelection));
}

void NotationView::slotTransformsStemsUp()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Pointing stems up..."), this);

    addCommandToHistory(new AdjustMenuChangeStemsCommand
                        (true, *m_currentEventSelection));
}

void NotationView::slotTransformsStemsDown()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Pointing stems down..."), this);

    addCommandToHistory(new AdjustMenuChangeStemsCommand
                        (false, *m_currentEventSelection));

}

void NotationView::slotTransformsRestoreStems()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Restoring computed stem directions..."), this);

    addCommandToHistory(new AdjustMenuRestoreStemsCommand
                        (*m_currentEventSelection));
}

void NotationView::slotTransformsSlursAbove()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Positioning slurs..."), this);

    addCommandToHistory(new AdjustMenuChangeSlurPositionCommand
                        (true, *m_currentEventSelection));
}

void NotationView::slotTransformsSlursBelow()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Positioning slurs..."), this);

    addCommandToHistory(new AdjustMenuChangeSlurPositionCommand
                        (false, *m_currentEventSelection));

}

void NotationView::slotTransformsRestoreSlurs()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Restoring slur positions..."), this);

    addCommandToHistory(new AdjustMenuRestoreSlursCommand
                        (*m_currentEventSelection));
}

void NotationView::slotTransformsFixQuantization()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Fixing notation quantization..."), this);

    addCommandToHistory(new AdjustMenuFixNotationQuantizeCommand
                        (*m_currentEventSelection));
}    

void NotationView::slotTransformsRemoveQuantization()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Removing notation quantization..."), this);

    addCommandToHistory(new AdjustMenuRemoveNotationQuantizeCommand
                        (*m_currentEventSelection));
}    

void NotationView::slotSetStyleFromAction()
{
    const QObject *s = sender();
    QString 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 AdjustMenuChangeStyleCommand
                            (NoteStyleName(qstrtostr(name)),
                             *m_currentEventSelection));
    } else {
        KMessageBox::sorry
            (this, i18n("Unknown style action %1").arg(name));
    }
}

void NotationView::slotInsertNoteFromAction()
{
    const QObject *s = sender();
    QString 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;
    Rosegarden::Accidental accidental =
        Rosegarden::Accidentals::NoAccidental;

    Rosegarden::timeT time(getInsertionTime());
    Rosegarden::Key key = segment.getKeyAtTime(time);
    Rosegarden::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;
      }

      Rosegarden::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, Rosegarden::Accidentals::NoAccidental, true);
}

void NotationView::slotSwitchFromRestToNote()
{
    RestInserter *restInserter = dynamic_cast<RestInserter *>(m_tool);
    if (!restInserter) {
        KMessageBox::sorry(this, i18n("No rest duration selected"));
        return;
    }

    Rosegarden::Note note(restInserter->getCurrentNote());

    QString actionName = NotationStrings::getReferenceName(note, false);
    actionName = actionName.replace("-", "_");
    
    KRadioAction *action = dynamic_cast<KRadioAction *>
      (actionCollection()->action(actionName));

    if (!action) {
      std::cerr << "WARNING: Failed to find note action \""
              << actionName << "\"" << 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;
    }

    Rosegarden::Note note(noteInserter->getCurrentNote());
    
    QString actionName = NotationStrings::getReferenceName(note, true);
    actionName = actionName.replace("-", "_");
    
    KRadioAction *action = dynamic_cast<KRadioAction *>
      (actionCollection()->action(actionName));

    if (!action) {
      std::cerr << "WARNING: Failed to find rest action \""
              << actionName << "\"" << 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) {
      Rosegarden::Note note(noteInserter->getCurrentNote());
      if (note.getNoteType() == Rosegarden::Note::Shortest ||
          note.getNoteType() == Rosegarden::Note::Longest) return;
      noteInserter->slotSetDots(note.getDots() ? 0 : 1);
      setTool(noteInserter);
    } else {
      RestInserter *restInserter = dynamic_cast<RestInserter *>(m_tool);
      if (restInserter) {
          Rosegarden::Note note(restInserter->getCurrentNote());
          if (note.getNoteType() == Rosegarden::Note::Shortest ||
            note.getNoteType() == Rosegarden::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,
                                 Rosegarden::Accidentals::DoubleFlat,
                                 *m_currentEventSelection));
}

void NotationView::slotRespellFlat()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Forcing accidentals..."), this);

    addCommandToHistory(new RespellCommand(RespellCommand::Set,
                                 Rosegarden::Accidentals::Flat,
                                 *m_currentEventSelection));
}

void NotationView::slotRespellNatural()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Forcing accidentals..."), this);

    addCommandToHistory(new RespellCommand(RespellCommand::Set,
                                 Rosegarden::Accidentals::Natural,
                                 *m_currentEventSelection));
}

void NotationView::slotRespellSharp()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Forcing accidentals..."), this);

    addCommandToHistory(new RespellCommand(RespellCommand::Set,
                                 Rosegarden::Accidentals::Sharp,
                                 *m_currentEventSelection));
}

void NotationView::slotRespellDoubleSharp()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Forcing accidentals..."), this);

    addCommandToHistory(new RespellCommand(RespellCommand::Set,
                                 Rosegarden::Accidentals::DoubleSharp,
                                 *m_currentEventSelection));
}

void NotationView::slotRespellUp()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Forcing accidentals..."), this);

    addCommandToHistory(new RespellCommand(RespellCommand::Up,
                                 Rosegarden::Accidentals::NoAccidental,
                                 *m_currentEventSelection));
}

void NotationView::slotRespellDown()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Forcing accidentals..."), this);

    addCommandToHistory(new RespellCommand(RespellCommand::Down,
                                 Rosegarden::Accidentals::NoAccidental,
                                 *m_currentEventSelection));
}

void NotationView::slotRespellRestore()
{
    if (!m_currentEventSelection) return;
    KTmpStatusMsg msg(i18n("Restoring accidentals..."), this);

    addCommandToHistory(new RespellCommand(RespellCommand::Restore,
                                 Rosegarden::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() == QDialog::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() == QDialog::Accepted) {
      KTmpStatusMsg msg(i18n("Interpreting selection..."), this);
      addCommandToHistory(new AdjustMenuInterpretCommand
                      (*m_currentEventSelection,
                       getDocument()->getComposition().getNotationQuantizer(),
                       dialog.getInterpretations()));
    }
}
    
void NotationView::slotSetNoteDurations(Rosegarden::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 QObject *s = sender();
    if (!m_currentEventSelection) return;

    QString name = s->name();
    int slashes = name.right(1).toInt();

    addCommandToHistory(new NotesMenuAddSlashesCommand
                        (slashes, *m_currentEventSelection));
}


void NotationView::slotMarksAddTextMark()
{
    if (m_currentEventSelection) {
        bool pressedOK = false;
        
        QString txt = KLineEditDlg::getText(i18n("Text: "), "", &pressedOK, this);
        
        if (pressedOK) {
            addCommandToHistory(new NotesMenuAddTextMarkCommand
                                (qstrtostr(txt), *m_currentEventSelection));
        }
    }
}

void NotationView::slotMarksAddFingeringMark()
{
    if (m_currentEventSelection) {
        bool pressedOK = false;
        
        QString txt = KLineEditDlg::getText(i18n("Fingering: "), "", &pressedOK, this);
        
        if (pressedOK) {
            addCommandToHistory(new NotesMenuAddFingeringMarkCommand
                                (qstrtostr(txt), *m_currentEventSelection));
        }
    }
}

void NotationView::slotMarksAddFingeringMarkFromAction()
{
    const QObject *s = sender();
    QString name = s->name();

    if (name.left(14) == "add_fingering_") {

      QString fingering = name.right(name.length() - 14);

      if (fingering == "plus") fingering = "+";

      if (m_currentEventSelection) {
          addCommandToHistory(new NotesMenuAddFingeringMarkCommand
                        (qstrtostr(fingering), *m_currentEventSelection));
      }
    }
}

void NotationView::slotMarksRemoveMarks()
{
    if (m_currentEventSelection)
        addCommandToHistory(new NotesMenuRemoveMarksCommand
                            (*m_currentEventSelection));
}

void NotationView::slotMarksRemoveFingeringMarks()
{
    if (m_currentEventSelection)
        addCommandToHistory(new NotesMenuRemoveFingeringMarksCommand
                            (*m_currentEventSelection));
}


void
01627 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(Rosegarden::Note::EventType)) {
          if ((*i)->has(Rosegarden::BaseProperties::PITCH)) {
            basePitch = (*i)->get<Rosegarden::Int>
                (Rosegarden::BaseProperties::PITCH);
            style = NoteStyleFactory::getStyleForEvent(*i);
            if (baseVelocity != -1) break;
          }
          if ((*i)->has(Rosegarden::BaseProperties::VELOCITY)) {
            baseVelocity = (*i)->get<Rosegarden::Int>
                (Rosegarden::BaseProperties::VELOCITY);
            if (basePitch != -1) break;
          }
      }
    }

    Rosegarden::Staff *staff = getCurrentStaff();
    Segment &segment = staff->getSegment();
    
    Rosegarden::timeT absTime = m_currentEventSelection->getStartTime();
    Rosegarden::timeT duration = m_currentEventSelection->getTotalDuration();
    Rosegarden::Note note(Rosegarden::Note::getNearestNote(duration));

    Rosegarden::Track *track =
      segment.getComposition()->getTrackById(segment.getTrack());
    QString name;
    int barNo = segment.getComposition()->getBarNumber(absTime);
    if (track) {
      name = QString(i18n("Ornament track %1 bar %2").arg(track->getPosition() + 1).arg(barNo + 1));
    } else {
      name = QString(i18n("Ornament bar %1").arg(barNo + 1));
    }

    MakeOrnamentDialog dialog(this, name, basePitch);
    if (dialog.exec() != QDialog::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,
                   Rosegarden::BaseProperties::TRIGGER_SEGMENT_ADJUST_SQUISH,
                   Rosegarden::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() != QDialog::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()
{
    Rosegarden::Staff *staff = getCurrentStaff();
    Segment &segment = staff->getSegment();
    static Rosegarden::Clef lastClef;
    Rosegarden::Clef clef;
    Rosegarden::Key key;
    timeT insertionTime = getInsertionTime(clef, key);

    ClefDialog dialog(this, m_notePixmapFactory, lastClef);
    
    if (dialog.exec() == QDialog::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();
    }
}                       

01756 void NotationView::slotEditAddKeySignature()
{
    Rosegarden::Staff *staff = getCurrentStaff();
    Segment &segment = staff->getSegment();
    Rosegarden::Clef clef;
    Rosegarden::Key key;
    timeT insertionTime = getInsertionTime(clef, key);

    //!!! experimental:
    Rosegarden::CompositionTimeSliceAdapter adapter
        (&getDocument()->getComposition(), insertionTime,
         getDocument()->getComposition().getDuration());
    Rosegarden::AnalysisHelper helper;
    key = helper.guessKey(adapter);

    KeySignatureDialog dialog
        (this, m_notePixmapFactory, clef, key, true, true,
         i18n("Estimated key signature shown"));
    
    if (dialog.exec() == QDialog::Accepted &&
        dialog.isValid()) {
        
        KeySignatureDialog::ConversionType conversion =
            dialog.getConversionType();
        
      bool transposeKey = dialog.shouldBeTransposed();
        bool applyToAll = dialog.shouldApplyToAll();
        
        if (applyToAll) {
            addCommandToHistory
                (new MultiKeyInsertionCommand
                 (getDocument()->getComposition(),
                  insertionTime, dialog.getKey(),
                  conversion == KeySignatureDialog::Convert,
                  conversion == KeySignatureDialog::Transpose,
              transposeKey));
        } else {
            addCommandToHistory
                (new KeyInsertionCommand
                 (segment,
                  insertionTime, dialog.getKey(),
                  conversion == KeySignatureDialog::Convert,
                  conversion == KeySignatureDialog::Transpose,
              transposeKey));
        }
    }
}                      
 
void NotationView::slotEditAddSustain(bool down)
{
    Rosegarden::Staff *staff = getCurrentStaff();
    Segment &segment = staff->getSegment();
    timeT insertionTime = getInsertionTime();
        
    Rosegarden::Studio *studio = &getDocument()->getStudio();
    Rosegarden::Track *track = segment.getComposition()->getTrackById(segment.getTrack());

    if (track) {

      Rosegarden::Instrument *instrument = studio->getInstrumentById
          (track->getInstrument());
      if (instrument) {
          Rosegarden::MidiDevice *device = dynamic_cast<Rosegarden::MidiDevice *>
            (instrument->getDevice());
          if (device) {
            for (Rosegarden::ControlList::const_iterator i =
                   device->getControlParameters().begin();
                 i != device->getControlParameters().end(); ++i) {

                if (i->getType() == Rosegarden::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() == Rosegarden::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::slotEditElement(NotationStaff *staff,
                           NotationElement *element, bool advanced)
{
    if (advanced) {
      
      EventEditDialog dialog(this, *element->event(), true);
      
      if (dialog.exec() == QDialog::Accepted &&
          dialog.isModified()) {
          
          EventEditCommand *command = new EventEditCommand
            (staff->getSegment(),
             element->event(),
             dialog.getEvent());
          
          addCommandToHistory(command);
      }

    } else if (element->event()->isa(Rosegarden::Clef::EventType)) {

      try {
          ClefDialog dialog(this, m_notePixmapFactory,
                        Rosegarden::Clef(*element->event()));
          
          if (dialog.exec() == QDialog::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 (Rosegarden::Exception e) {
          std::cerr << e.getMessage() << std::endl;
      }
      
      return;
      
    } else if (element->event()->isa(Rosegarden::Key::EventType)) {
      
      try {
          Rosegarden::Clef clef(staff->getSegment().getClefAtTime
                          (element->event()->getAbsoluteTime()));
            KeySignatureDialog dialog
                (this, m_notePixmapFactory, clef, Rosegarden::Key(*element->event()),
                 false, true);
            
            if (dialog.exec() == QDialog::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()));
            }

      } catch (Rosegarden::Exception e) {
          std::cerr << e.getMessage() << std::endl;
      }

      return;

    } else if (element->event()->isa(Rosegarden::Text::EventType)) {
      
      try {
          TextEventDialog dialog
            (this, m_notePixmapFactory, Rosegarden::Text(*element->event()));
          if (dialog.exec() == QDialog::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 (Rosegarden::Exception e) {
          std::cerr << e.getMessage() << std::endl;
      }

      return;

    } else if (element->isNote() &&
             element->event()->has(Rosegarden::BaseProperties::TRIGGER_SEGMENT_ID)) {
          
      int id = element->event()->get<Rosegarden::Int>
          (Rosegarden::BaseProperties::TRIGGER_SEGMENT_ID);
      emit editTriggerSegment(id);
      return;

    } else {

      SimpleEventEditDialog dialog(this, getDocument(), *element->event(), false);
      
      if (dialog.exec() == QDialog::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)
{
    Rosegarden::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(Rosegarden::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, updateFrom, segment->getEndMarkerTime());
          refreshSegment(segment, 0, 0);
      }
    }
    NOTATION_DEBUG << "NotationView::slotUpdateRecordingSegment: don't have segment " << segment << endl;
}


void
02082 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
02095 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);

      Rosegarden::Segment *segment = &m_staffs[m_currentStaff]->getSegment();

      m_chordNameRuler->setCurrentSegment(segment);
      m_rawNoteRuler->setCurrentSegment(segment);
      m_rawNoteRuler->repaint();
      setControlRulersCurrentSegment();

      updateView();
      
      slotSetInsertCursorPosition(getInsertionTime(), false, false);
    }
}    

void
02121 NotationView::slotCurrentStaffUp()
{
    if (m_staffs.size() < 2) return;

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

    int position = track->getPosition();
    Rosegarden::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()) {
            slotSetCurrentStaff(i);
            return;
          }
      }
    }
}

void
02146 NotationView::slotCurrentStaffDown()
{
    if (m_staffs.size() < 2) return;

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

    int position = track->getPosition();
    Rosegarden::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()) {
            slotSetCurrentStaff(i);
            return;
          }
      }
    }
}

void
02171 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
02230 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);
          }
      }
        
      QScrollBar* hbar = getCanvasView()->horizontalScrollBar();
      hbar->setValue(int(hbar->value() - (m_deferredCursorScrollToX - ccx)));
    }

    updateView();
}

void
02359 NotationView::slotJumpCursorToPlayback()
{
    slotSetInsertCursorPosition(getDocument()->getComposition().getPosition());
}

void
02365 NotationView::slotJumpPlaybackToCursor()
{
    emit jumpPlaybackTo(getInsertionTime());
}

void
02371 NotationView::slotToggleTracking()
{
    m_playTracking = !m_playTracking;
}

//----------------------------------------
// Accidentals
//----------------------------------------
02379 void NotationView::slotNoAccidental()
{
    emit changeAccidental(Rosegarden::Accidentals::NoAccidental, false);
}

void NotationView::slotFollowAccidental()
{
    emit changeAccidental(Rosegarden::Accidentals::NoAccidental, true);
}

void NotationView::slotSharp()
{
    emit changeAccidental(Rosegarden::Accidentals::Sharp, false);
}

void NotationView::slotFlat()
{
    emit changeAccidental(Rosegarden::Accidentals::Flat, false);
}

void NotationView::slotNatural()
{
    emit changeAccidental(Rosegarden::Accidentals::Natural, false);
}

void NotationView::slotDoubleSharp()
{
    emit changeAccidental(Rosegarden::Accidentals::DoubleSharp, false);
}

void NotationView::slotDoubleFlat()
{
    emit changeAccidental(Rosegarden::Accidentals::DoubleFlat, false);
}


//----------------------------------------
// Clefs
//----------------------------------------
02418 void NotationView::slotTrebleClef()
{
    m_currentNotePixmap->setPixmap
        (NotePixmapFactory::toQPixmap(NotePixmapFactory::makeToolbarPixmap("clef-treble")));
    setTool(m_toolBox->getTool(ClefInserter::ToolName));

    dynamic_cast<ClefInserter*>(m_tool)->setClef(Rosegarden::Clef::Treble);
    setMenuStates();
}

void NotationView::slotTenorClef()
{
    m_currentNotePixmap->setPixmap
        (NotePixmapFactory::toQPixmap(NotePixmapFactory::makeToolbarPixmap("clef-tenor")));
    setTool(m_toolBox->getTool(ClefInserter::ToolName));

    dynamic_cast<ClefInserter*>(m_tool)->setClef(Rosegarden::Clef::Tenor);
    setMenuStates();
}

void NotationView::slotAltoClef()
{
    m_currentNotePixmap->setPixmap
        (NotePixmapFactory::toQPixmap(NotePixmapFactory::makeToolbarPixmap("clef-alto")));
    setTool(m_toolBox->getTool(ClefInserter::ToolName));

    dynamic_cast<ClefInserter*>(m_tool)->setClef(Rosegarden::Clef::Alto);
    setMenuStates();
}

void NotationView::slotBassClef()
{
    m_currentNotePixmap->setPixmap
        (NotePixmapFactory::toQPixmap(NotePixmapFactory::makeToolbarPixmap("clef-bass")));
    setTool(m_toolBox->getTool(ClefInserter::ToolName));

    dynamic_cast<ClefInserter*>(m_tool)->setClef(Rosegarden::Clef::Bass);
    setMenuStates();
}



02460 void NotationView::slotText()
{
    m_currentNotePixmap->setPixmap
        (NotePixmapFactory::toQPixmap(NotePixmapFactory::makeToolbarPixmap("text")));
    setTool(m_toolBox->getTool(TextInserter::ToolName));
    setMenuStates();
}


02469 void NotationView::slotFretboard()
{
    m_currentNotePixmap->setPixmap
    (NotePixmapFactory::toQPixmap(NotePixmapFactory::makeToolbarPixmap("text")));
    setTool(m_toolBox->getTool(FretboardInserter::ToolName));
    setMenuStates();    
}

/*void NotationView::slotLilypondDirective()
{
    m_currentNotePixmap->setPixmap
        (NotePixmapFactory::toQPixmap(NotePixmapFactory::makeToolbarPixmap("lilypond_directive")));
    setTool(m_toolBox->getTool(LilypondDirectiveInserter::ToolName));
    setMenuStates();
}*/


//----------------------------------------
// Editing Tools
//----------------------------------------

02490 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();
}




02507 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");
}

02540 void NotationView::slotToggleAnnotations()
{
    m_annotationsVisible = !m_annotationsVisible;
    slotUpdateAnnotationsStatus();
//!!! use refresh mechanism
    refreshSegment(0, 0, 0);
}

02548 void NotationView::slotToggleLilyPondDirectives()
{
    m_lilypondDirectivesVisible = !m_lilypondDirectivesVisible;
    slotUpdateLilyPondDirectivesStatus();
//!!! use refresh mechanism
    refreshSegment(0, 0, 0);
}

void NotationView::slotEditLyrics()
{
    Rosegarden::Staff *staff = getCurrentStaff();
    Segment &segment = staff->getSegment();

    LyricEditDialog dialog(this, &segment);

    if (dialog.exec() == QDialog::Accepted) {
        
        SetLyricsCommand *command = new SetLyricsCommand
            (&segment, dialog.getLyricData());

        addCommandToHistory(command);
    }
}

//----------------------------------------------------------------------

02574 void NotationView::slotItemPressed(int height, int staffNo,
                                   QMouseEvent* 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() == QEvent::MouseButtonDblClick) {
            m_tool->handleMouseDoubleClick(unknownTime, height,
                                 staffNo, e, el);
      } else {
            m_tool->handleMousePress(unknownTime, height,
                                     staffNo, e, el);
      }
    }
}

02618 void NotationView::slotNonNotationItemPressed(QMouseEvent *e, QCanvasItem *it)
{
    if (e->type() != QEvent::MouseButtonDblClick) return;

    Rosegarden::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;
      QRegExpValidator validator(QRegExp(".*"), this); // empty is OK

      QString newText = KLineEditDlg::getText(QString("Change staff name"),
                                    QString("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<QCanvasTimeSigSprite *>(it)) {

      double layoutX = (dynamic_cast<QCanvasTimeSigSprite *>(it))->getLayoutX();
      emit editTimeSignature(m_hlayout->getTimeForX(layoutX));
    }
}

02659 void NotationView::slotTextItemPressed(QMouseEvent *e, QCanvasItem *it)
{
    if (e->type() != QEvent::MouseButtonDblClick) return;

    if (it == m_title) {
      emit editMetadata(strtoqstr(Rosegarden::CompositionMetadataKeys::Title.getName()));
    } else if (it == m_subtitle) {
      emit editMetadata(strtoqstr(Rosegarden::CompositionMetadataKeys::Subtitle.getName()));
    } else if (it == m_composer) {
      emit editMetadata(strtoqstr(Rosegarden::CompositionMetadataKeys::Composer.getName()));
    } else if (it == m_copyright) {
      emit editMetadata(strtoqstr(Rosegarden::CompositionMetadataKeys::Copyright.getName()));
    } else {
      return;
    }
   
    positionStaffs();
}

void NotationView::slotMouseMoved(QMouseEvent *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(QMouseEvent *e)
{
    if (activeItem()) {
        activeItem()->handleMouseRelease(e);
        setActiveItem(0);
        updateView();
    }
    else
        m_tool->handleMouseRelease(0, 0, // unknown time and height
                                   e);
}

void
02714 NotationView::slotHoveredOverNoteChanged(const QString &noteName)
{
    m_hoveredOverNoteName->setText(QString(" ") + noteName);
}

void
02720 NotationView::slotHoveredOverAbsoluteTimeChanged(unsigned int time)
{
    timeT t = time;
    Rosegarden::RealTime rt =
        getDocument()->getComposition().getElapsedRealTime(t);
    long ms = rt.msec();

    int bar, beat, fraction, remainder;
    getDocument()->getComposition().getMusicalTimeForAbsoluteTime
      (t, bar, beat, fraction, remainder);

//    QString message;
//    QString format("%ld (%ld.%03lds)");
//    format = i18n("Time: %1").arg(format);
//    message.sprintf(format, t, rt.sec, ms);

    QString message = i18n("Time: %1 (%2.%3s)")
      .arg(QString("%1-%2-%3-%4")
           .arg(QString("%1").arg(bar + 1).rightJustify(3, '0'))
           .arg(QString("%1").arg(beat).rightJustify(2, '0'))
           .arg(QString("%1").arg(fraction).rightJustify(2, '0'))
           .arg(QString("%1").arg(remainder).rightJustify(2, '0')))
      .arg(rt.sec)
      .arg(QString("%1").arg(ms).rightJustify(3, '0'));

    m_hoveredOverAbsoluteTime->setText(message);
}

// Ignore velocity for the moment -- we need the option to use or ignore it
void
02750 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?

    KToggleAction *action = dynamic_cast<KToggleAction *>
      (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,
                         Rosegarden::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,
                             Rosegarden::Accidentals::NoAccidental,
                             true);
      }
    }
}

void
02871 NotationView::slotInsertableNoteOnReceived(int pitch, int velocity)
{
    NOTATION_DEBUG << "NotationView::slotInsertableNoteOnReceived: " << pitch << endl;
    slotInsertableNoteEventReceived(pitch, velocity, true);
}

void
02878 NotationView::slotInsertableNoteOffReceived(int pitch, int velocity)
{
    NOTATION_DEBUG << "NotationView::slotInsertableNoteOffReceived: " << pitch << endl;
    slotInsertableNoteEventReceived(pitch, velocity, false);
}

void
02885 NotationView::slotInsertableTimerElapsed()
{
}

void
NotationView::slotToggleStepByStep()
{
    KToggleAction *action = dynamic_cast<KToggleAction *>
      (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
02906 NotationView::slotStepByStepTargetRequested(QObject *obj)
{
    KToggleAction *action = dynamic_cast<KToggleAction *>
      (actionCollection()->action("toggle_step_by_step"));
    if (!action) {
      NOTATION_DEBUG << "WARNING: No toggle_step_by_step action" << endl;
      return;
    }
    action->setChecked(obj == this);
}

void
02918 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 QTimer(this);
      connect(m_renderTimer, SIGNAL(timeout()), SLOT(slotRenderSomething()));
      m_renderTimer->start(0, true);
    }

    if (m_deferredCursorMove != NoCursorMoveNeeded) doDeferredCursorMove();
}

void
02954 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 QTimer(this);
      connect(m_renderTimer, SIGNAL(timeout()), 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 QTimer(this);
          connect(m_renderTimer, SIGNAL(timeout()), SLOT(slotRenderSomething()));
          m_renderTimer->start(0, true);
          return;
      }
    }

    PixmapArrayGC::deleteAll();
    NOTATION_DEBUG << "NotationView::slotRenderSomething: updating thumbnails" << endl;
    updateThumbnails(true);
}


Generated by  Doxygen 1.6.0   Back to index