/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ /* Rosegarden A MIDI and audio sequencer and musical notation editor. Copyright 2000-2011 the Rosegarden development team. 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 "NotationWidget.h" #include "NotationScene.h" #include "NotationCommandRegistry.h" #include "NoteStyleFactory.h" #include "NoteFontFactory.h" #include "NotationStrings.h" #include "NoteRestInserter.h" #include "NotationSelector.h" #include "HeadersGroup.h" #include "NotationHLayout.h" #include "NotationStaff.h" #include "NotationElement.h" #include "NotePixmapFactory.h" #include "document/RosegardenDocument.h" #include "document/CommandHistory.h" #include "misc/ConfigGroups.h" #include "base/Clipboard.h" #include "base/Selection.h" #include "base/NotationQuantizer.h" #include "base/NotationTypes.h" #include "base/NotationRules.h" #include "base/BaseProperties.h" #include "base/CompositionTimeSliceAdapter.h" #include "base/AnalysisTypes.h" #include "base/MidiDevice.h" #include "base/MidiTypes.h" #include "base/Controllable.h" #include "base/Studio.h" #include "base/Instrument.h" #include "base/Device.h" #include "base/SoftSynthDevice.h" #include "commands/edit/CopyCommand.h" #include "commands/edit/CutCommand.h" #include "commands/edit/CutAndCloseCommand.h" #include "commands/edit/EraseCommand.h" #include "commands/edit/PasteEventsCommand.h" #include "commands/edit/InsertTriggerNoteCommand.h" #include "commands/edit/SetTriggerCommand.h" #include "commands/edit/ClearTriggersCommand.h" #include "commands/edit/ChangeVelocityCommand.h" #include "commands/edit/RescaleCommand.h" #include "commands/edit/TransposeCommand.h" #include "commands/edit/InvertCommand.h" #include "commands/edit/RetrogradeCommand.h" #include "commands/edit/RetrogradeInvertCommand.h" #include "commands/edit/MoveCommand.h" #include "commands/edit/EventQuantizeCommand.h" #include "commands/edit/SetLyricsCommand.h" #include "commands/edit/EventEditCommand.h" #include "commands/edit/CollapseNotesCommand.h" #include "commands/edit/AddDotCommand.h" #include "commands/edit/SetNoteTypeCommand.h" #include "commands/segment/AddTempoChangeCommand.h" #include "commands/segment/AddTimeSignatureAndNormalizeCommand.h" #include "commands/segment/AddTimeSignatureCommand.h" #include "commands/segment/AddLayerCommand.h" #include "commands/notation/InterpretCommand.h" #include "commands/notation/ClefInsertionCommand.h" #include "commands/notation/KeyInsertionCommand.h" #include "commands/notation/MultiKeyInsertionCommand.h" #include "commands/notation/SustainInsertionCommand.h" #include "commands/notation/TupletCommand.h" #include "commands/notation/TextInsertionCommand.h" #include "commands/notation/ClefInsertionCommand.h" #include "commands/notation/KeyInsertionCommand.h" #include "commands/notation/EraseEventCommand.h" #include "commands/notation/NormalizeRestsCommand.h" #include "commands/notation/CycleSlashesCommand.h" #include "commands/segment/PasteToTriggerSegmentCommand.h" #include "commands/segment/SegmentTransposeCommand.h" #include "commands/segment/SegmentSyncCommand.h" #include "gui/dialogs/PasteNotationDialog.h" #include "gui/dialogs/InterpretDialog.h" #include "gui/dialogs/MakeOrnamentDialog.h" #include "gui/dialogs/UseOrnamentDialog.h" #include "gui/dialogs/ClefDialog.h" #include "gui/dialogs/LilyPondOptionsDialog.h" #include "gui/dialogs/EventFilterDialog.h" #include "gui/dialogs/EventParameterDialog.h" #include "gui/dialogs/PitchBendSequenceDialog.h" #include "gui/dialogs/KeySignatureDialog.h" #include "gui/dialogs/IntervalDialog.h" #include "gui/dialogs/TupletDialog.h" #include "gui/dialogs/InsertTupletDialog.h" #include "gui/dialogs/RescaleDialog.h" #include "gui/dialogs/TempoDialog.h" #include "gui/dialogs/TimeSignatureDialog.h" #include "gui/dialogs/QuantizeDialog.h" #include "gui/dialogs/LyricEditDialog.h" #include "gui/dialogs/AboutDialog.h" #include "gui/dialogs/EventEditDialog.h" #include "gui/dialogs/TextEventDialog.h" #include "gui/dialogs/SimpleEventEditDialog.h" #include "gui/dialogs/ConfigureDialog.h" #include "gui/general/IconLoader.h" #include "gui/general/LilyPondProcessor.h" #include "gui/general/PresetHandlerDialog.h" #include "gui/general/ClefIndex.h" #include "gui/widgets/TmpStatusMsg.h" #include "gui/application/RosegardenMainWindow.h" #include "gui/application/RosegardenMainViewWidget.h" #include "gui/editors/parameters/TrackParameterBox.h" #include "document/io/LilyPondExporter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Rosegarden { using namespace Accidentals; NotationView::NotationView(RosegardenDocument *doc, std::vector segments, QWidget *parent) : EditViewBase(doc, segments, parent), m_document(doc), m_durationMode(InsertingRests), m_durationPressed(0), m_accidentalPressed(0), m_selectionCounter(0), m_insertModeLabel(0), m_annotationsLabel(0), m_lilyPondDirectivesLabel(0), m_currentNotePixmap(0), m_hoveredOverNoteName(0), m_hoveredOverAbsoluteTime(0), m_fontCombo(0), m_fontSizeCombo(0), m_spacingCombo(0), m_segments(segments) { m_notationWidget = new NotationWidget(); setCentralWidget(m_notationWidget); m_notationWidget->suspendLayoutUpdates(); m_notationWidget->setSegments(doc, segments); // connect the editElement signal from NotationSelector, relayed through // NotationWidget to be acted upon here in NotationView connect(m_notationWidget, SIGNAL(editElement(NotationStaff *, NotationElement *, bool)), this, SLOT(slotEditElement(NotationStaff *, NotationElement *, bool))); // Many actions are created here m_commandRegistry = new NotationCommandRegistry(this); setupActions(); createGUI("notation.rc"); slotUpdateMenuStates(); slotTestClipboard(); setIcon(IconLoader().loadPixmap("window-notation")); connect(CommandHistory::getInstance(), SIGNAL(commandExecuted()), this, SLOT(slotUpdateMenuStates())); connect(m_notationWidget->getScene(), SIGNAL(selectionChanged()), this, SLOT(slotUpdateMenuStates())); //Initialize NoteRestInserter and DurationToolbar initializeNoteRestInserter(); // Determine default action stolen from MatrixView.cpp // Toggle the desired tool off and then trigger it on again, to // make sure its signal is called at least once (as would not // happen if the tool was on by default otherwise) QAction *toolAction = 0; if (!m_notationWidget->segmentsContainNotes()) { toolAction = findAction("draw"); } else { toolAction = findAction("select"); } if (toolAction) { NOTATION_DEBUG << "initial state for action '" << toolAction->objectName() << "' is " << toolAction->isChecked() << endl; if (toolAction->isChecked()) toolAction->toggle(); NOTATION_DEBUG << "newer state for action '" << toolAction->objectName() << "' is " << toolAction->isChecked() << endl; toolAction->trigger(); NOTATION_DEBUG << "newest state for action '" << toolAction->objectName() << "' is " << toolAction->isChecked() << endl; } // Set display configuration bool visible; QSettings settings; settings.beginGroup(GeneralOptionsConfigGroup); m_Thorn = settings.value("use_thorn_style", true).toBool(); settings.endGroup(); settings.beginGroup(NotationViewConfigGroup); // Set font size for single or multiple staffs (hopefully this happens // before we've drawn anything, so there's no penalty changing it) m_fontSize = NoteFontFactory::getDefaultSize(m_fontName); if (m_notationWidget->getScene()->getVisibleStaffCount() > 1) { m_fontSize = settings.value("multistaffnotesize", 6).toInt(); //std::cout << "setting multi staff size to " << size << std::endl; } else { m_fontSize = settings.value("singlestaffnotesize", 8).toInt(); //std::cout << "setting single staff size to " << size << std::endl; } m_notationWidget->slotSetFontSize(m_fontSize); //Update Font Size pulldown menu QString action = QString("note_font_size_%1").arg(m_fontSize); findAction(action)->setChecked(true); // Set initial notation layout mode int layoutMode = settings.value("layoutmode", 0).toInt(); switch (layoutMode) { case 0 : findAction("linear_mode")->setChecked(true); findAction("continuous_page_mode")->setChecked(false); findAction("multi_page_mode")->setChecked(false); slotLinearMode(); break; case 1 : findAction("linear_mode")->setChecked(false); findAction("continuous_page_mode")->setChecked(true); findAction("multi_page_mode")->setChecked(false); slotContinuousPageMode(); break; case 2 : findAction("linear_mode")->setChecked(false); findAction("continuous_page_mode")->setChecked(false); findAction("multi_page_mode")->setChecked(true); slotMultiPageMode(); break; } // Set initial visibility of chord name ruler, ... visible = settings.value("Chords ruler shown", findAction("show_chords_ruler")->isChecked() ).toBool(); findAction("show_chords_ruler")->setChecked(visible); m_notationWidget->setChordNameRulerVisible(visible); // ... raw note ruler, ... visible = settings.value("Raw note ruler shown", findAction("show_raw_note_ruler")->isChecked() ).toBool(); findAction("show_raw_note_ruler")->setChecked(visible); m_notationWidget->setRawNoteRulerVisible(visible); // ... and tempo ruler. visible = settings.value("Tempo ruler shown", findAction("show_tempo_ruler")->isChecked() ).toBool(); findAction("show_tempo_ruler")->setChecked(visible); m_notationWidget->setTempoRulerVisible(visible); settings.endGroup(); if (segments.size() > 1) { enterActionState("have_multiple_staffs"); } else { leaveActionState("have_multiple_staffs"); } initLayoutToolbar(); initRulersToolbar(); initStatusBar(); slotUpdateWindowTitle(); connect(m_document, SIGNAL(documentModified(bool)), this, SLOT(slotUpdateWindowTitle(bool))); // Restore window geometry and toolbar/dock state settings.beginGroup(WindowGeometryConfigGroup); this->restoreGeometry(settings.value("Notation_View_Geometry").toByteArray()); this->restoreState(settings.value("Notation_View_State").toByteArray()); settings.endGroup(); connect(m_notationWidget, SIGNAL(segmentDeleted(Segment *)), this, SLOT(slotSegmentDeleted(Segment *))); connect(m_notationWidget, SIGNAL(sceneDeleted()), this, SLOT(slotSceneDeleted())); // do the auto repeat thingie on the <<< << >> >>> buttons setRewFFwdToAutoRepeat(); m_notationWidget->resumeLayoutUpdates(); // Connection to update the "Show staff headers" check box in the menu // (Must be done before setting the initial visibility of the headers) connect(m_notationWidget, SIGNAL(headersVisibilityChanged(bool)), this, SLOT(slotCheckShowHeadersMenu(bool))); // Set initial visibility of staff headers. // (Could not be done earlier because both view size and headers size are // needed to know what should be done when the "show when needed" option // is selected). settings.beginGroup(NotationViewConfigGroup); switch (settings.value("shownotationheader", HeadersGroup::DefaultShowMode).toInt()) { case HeadersGroup::ShowNever : m_notationWidget->setHeadersVisible(false); break; case HeadersGroup::ShowWhenNeeded : m_notationWidget->setHeadersVisibleIfNeeded(); break; case HeadersGroup::ShowAlways : m_notationWidget->setHeadersVisible(true); break; default : std::cerr << "NotationView: settings.value(\"shownotationheader\") " << "returned an unexpected value. This is a bug." << std::endl; } settings.endGroup(); // Show the pointer as soon as notation editor opens m_notationWidget->slotUpdatePointerPosition(); readOptions(); } NotationView::~NotationView() { NOTATION_DEBUG << "Deleting notation view" << endl; delete m_commandRegistry; } void NotationView::closeEvent(QCloseEvent *event) { // Save window geometry and toolbar/dock state QSettings settings; settings.beginGroup(WindowGeometryConfigGroup); std::cerr << "storing window geometry for notation view" << std::endl; settings.setValue("Notation_View_Geometry", this->saveGeometry()); settings.setValue("Notation_View_State", this->saveState()); settings.endGroup(); QWidget::closeEvent(event); } void NotationView::setupActions() { //setup actions common to all views. setupBaseActions(true); //"file" MenuBar menu // "file_save" // Created in EditViewBase::setupActions() via creatAction() createAction("file_print_lilypond", SLOT(slotPrintLilyPond())); createAction("file_preview_lilypond", SLOT(slotPreviewLilyPond())); // "file_close" // Created in EditViewBase::setupActions() via creatAction() // "edit" MenuBar menu // "edit_undo" // Created in EditViewBase::setupActions() via creatAction() // "edit_redo" // Created in EditViewBase::setupActions() via creatAction() createAction("cut_and_close", SLOT(slotEditCutAndClose())); createAction("general_paste", SLOT(slotEditGeneralPaste())); createAction("delete", SLOT(slotEditDelete())); createAction("move_events_up_staff", SLOT(slotMoveEventsUpStaff())); createAction("move_events_down_staff", SLOT(slotMoveEventsDownStaff())); createAction("select_from_start", SLOT(slotEditSelectFromStart())); createAction("select_to_end", SLOT(slotEditSelectToEnd())); createAction("select_whole_staff", SLOT(slotEditSelectWholeStaff())); createAction("clear_selection", SLOT(slotClearSelection())); createAction("filter_selection", SLOT(slotFilterSelection())); createAction("pitch_bend_sequence", SLOT(slotPitchBendSequence())); //"view" MenuBar menu // "note_font_actionmenu" subMenu // Custom Code. Coded below. // "note_font_size_actionmenu" subMenu // Custom Code. Coded below. // "stretch_actionmenu" subMenu // Custom Code. Coded below. // Code deactivated. // "proportion_actionmenu" subMenu // Custom Code. Coded below. // Code deactivated. // "layout" submenu createAction("add_layer", SLOT(slotAddLayer())); createAction("linear_mode", SLOT(slotLinearMode())); createAction("continuous_page_mode", SLOT(slotContinuousPageMode())); createAction("multi_page_mode", SLOT(slotMultiPageMode())); createAction("lyric_editor", SLOT(slotEditLyrics())); createAction("show_track_headers", SLOT(slotShowHeadersGroup())); //"document" Menubar menu createAction("add_tempo", SLOT(slotAddTempo())); createAction("add_time_signature", SLOT(slotAddTimeSignature())); //"segment" Menubar menu // "open-with" subMenu // Created in EditViewBase::setupActions() via creatAction() createAction("add_clef", SLOT(slotEditAddClef())); createAction("add_key_signature", SLOT(slotEditAddKeySignature())); createAction("add_sustain_down", SLOT(slotEditAddSustainDown())); createAction("add_sustain_up", SLOT(slotEditAddSustainUp())); // "set_segment_start" // Created in EditViewBase::setupActions() via creatAction() // "set_segment_duration" // Created in EditViewBase::setupActions() via creatAction() createAction("transpose_segment", SLOT(slotEditTranspose())); createAction("switch_preset", SLOT(slotEditSwitchPreset())); //"Notes" Menubar menu // "Marks" subMenu //Created in Constructor via NotationCommandRegistry() //with AddMarkCommand::registerCommand() //with RemoveMarksCommand::registerCommand() // "ornaments" subMenu createAction("use_ornament", SLOT(slotUseOrnament())); createAction("make_ornament", SLOT(slotMakeOrnament())); createAction("remove_ornament", SLOT(slotRemoveOrnament())); // "Fingering" subMenu // Created in Constructor via NotationCommandRegistry() // with AddFingeringMarkCommand::registerCommand() // with RemoveFingeringMarksCommand::registerCommand() // "Slashes" subMenu // Created in Constructor via NotationCommandRegistry() // with AddSlashesCommand::registerCommand() // "note_style_actionmenu" subMenu // Created in Constructor via NotationCommandRegistry() // with ChangeStyleCommand::registerCommand() // actionCreate really should be a custon code. Oh, well. // "Respell" subMenu // Created in Constructor via NotationCommandRegistry() // with RespellCommand::registerCommand() // "stem_up" // Created in Constructor via NotationCommandRegistry() // with ChangeStemsCommand::registerCommand() // "stem_down" // Created in Constructor via NotationCommandRegistry() // with ChangeStemsCommand::registerCommand() // "restore_stems" // Created in Constructor via NotationCommandRegistry() // with RestoreStemsCommand::registerCommand(); //"Phrase" Menubar menu // "make_chord" // Created in Constructor via NotationCommandRegistry() // with MakeChordCommand::registerCommand(); // "beam" // Created in Constructor via NotationCommandRegistry() // with BeamCommand::registerCommand(); // "auto_beam" // Created in Constructor via NotationCommandRegistry() // with AutoBeamCommand::registerCommand(); // "break_group" // Created in Constructor via NotationCommandRegistry() // with BreakCommand::registerCommand(); // "remove_indications" createAction("simple_tuplet", SLOT(slotGroupSimpleTuplet())); createAction("tuplet", SLOT(slotGroupGeneralTuplet())); //Where are "break_tuplet", "slur", & "phrasing_slur" created? //"Slurs" subMenu //where are "restore_slurs", "slurs_above", "slurs_below" created? //Where are "tie_notes", "untie_notes", created? //"Ties" subMenu //"restore_ties", "ties_above", & "ties_below" created? //Where are "crescendo" & "decrescendo" created? //"octaves" subMenu //Where are "octave_2up", "octave_up", "octave_down", //"octave_down", & "octave_2down" created? //Actions first appear in "Adjust" Menubar menu //"rests" subMenu createAction("normalize_rests", SLOT(slotTransformsNormalizeRests())); //Where is "collapse_rests_aggresively" created? //"transform_notes" subMenu createAction("collapse_notes", SLOT(slotTransformsCollapseNotes())); //Where are "make_notes_viable" & "de_counterpoint" created? //Quantitize subMenu createAction("quantize", SLOT(slotTransformsQuantize())); //Where are "fix_quantization" & "remove_quantization" created? createAction("interpret", SLOT(slotTransformsInterpret())); //"Rescale" subMenu createAction("halve_durations", SLOT(slotHalveDurations())); createAction("double_durations", SLOT(slotDoubleDurations())); createAction("rescale", SLOT(slotRescale())); //"Transpose" subMenu createAction("transpose_up", SLOT(slotTransposeUp())); createAction("transpose_down", SLOT(slotTransposeDown())); createAction("transpose_up_octave", SLOT(slotTransposeUpOctave())); createAction("transpose_down_octave", SLOT(slotTransposeDownOctave())); createAction("general_transpose", SLOT(slotTranspose())); createAction("general_diatonic_transpose", SLOT(slotDiatonicTranspose())); //"Convert" subMenu createAction("invert", SLOT(slotInvert())); createAction("retrograde", SLOT(slotRetrograde())); createAction("retrograde_invert", SLOT(slotRetrogradeInvert())); //"velocities" subMenu createAction("velocity_up", SLOT(slotVelocityUp())); createAction("velocity_down", SLOT(slotVelocityDown())); createAction("set_velocities", SLOT(slotSetVelocities())); //"fine_positioning" subMenu //Where are "fine_position_restore", "fine_position_left", //"fine_position_right", "fine_position_up" & //"fine_position_down" created? //"fine_timing" subMenu createAction("jog_left", SLOT(slotJogLeft())); createAction("jog_right", SLOT(slotJogRight())); //"visibility" subMenu //Where are "make_invisible" & "make_visible" created? //Actions first appear in "Tools" Menubar menu createAction("select", SLOT(slotSetSelectTool())); createAction("erase", SLOT(slotSetEraseTool())); createAction("draw", SLOT(slotSetNoteRestInserter())); // These actions do as their names imply, and in this case, the toggle will // call one or the other of these // These rely on .rc script keeping the right state visible createAction("switch_to_rests", SLOT(slotSwitchToRests())); createAction("switch_to_notes", SLOT(slotSwitchToNotes())); // These actions always just pass straight to the toggle. // These rely on .rc script keeping the right state visible createAction("switch_dots_on", SLOT(slotToggleDot())); createAction("switch_dots_off", SLOT(slotToggleDot())); // Menu uses now "Switch to Notes", "Switch to Rests" and "Durations". createAction("duration_breve", SLOT(slotNoteAction())); createAction("duration_semibreve", SLOT(slotNoteAction())); createAction("duration_minim", SLOT(slotNoteAction())); createAction("duration_crotchet", SLOT(slotNoteAction())); createAction("duration_quaver", SLOT(slotNoteAction())); createAction("duration_semiquaver", SLOT(slotNoteAction())); createAction("duration_demisemi", SLOT(slotNoteAction())); createAction("duration_hemidemisemi", SLOT(slotNoteAction())); createAction("duration_dotted_breve", SLOT(slotNoteAction())); createAction("duration_dotted_semibreve", SLOT(slotNoteAction())); createAction("duration_dotted_minim", SLOT(slotNoteAction())); createAction("duration_dotted_crotchet", SLOT(slotNoteAction())); createAction("duration_dotted_quaver", SLOT(slotNoteAction())); createAction("duration_dotted_semiquaver", SLOT(slotNoteAction())); createAction("duration_dotted_demisemi", SLOT(slotNoteAction())); createAction("duration_dotted_hemidemisemi", SLOT(slotNoteAction())); // since we can't create toolbars with disabled icons, and to avoid having // to draw a lot of fancy icons for disabled durations, we have this dummy // filler to keep spacing the same across all toolbars, and there have to // two of them createAction("dummy_1", SLOT()); //"NoteTool" subMenu //NEED to create action methods createAction("breve", SLOT(slotNoteAction())); createAction("semibreve", SLOT(slotNoteAction())); createAction("minim", SLOT(slotNoteAction())); createAction("crotchet", SLOT(slotNoteAction())); createAction("quaver", SLOT(slotNoteAction())); createAction("semiquaver", SLOT(slotNoteAction())); createAction("demisemi", SLOT(slotNoteAction())); createAction("hemidemisemi", SLOT(slotNoteAction())); createAction("dotted_breve", SLOT(slotNoteAction())); createAction("dotted_semibreve", SLOT(slotNoteAction())); createAction("dotted_minim", SLOT(slotNoteAction())); createAction("dotted_crotchet", SLOT(slotNoteAction())); createAction("dotted_quaver", SLOT(slotNoteAction())); createAction("dotted_semiquaver", SLOT(slotNoteAction())); createAction("dotted_demisemi", SLOT(slotNoteAction())); createAction("dotted_hemidemisemi", SLOT(slotNoteAction())); //"RestTool" subMenu //NEED to create action methods createAction("rest_breve", SLOT(slotNoteAction())); createAction("rest_semibreve", SLOT(slotNoteAction())); createAction("rest_minim", SLOT(slotNoteAction())); createAction("rest_crotchet", SLOT(slotNoteAction())); createAction("rest_quaver", SLOT(slotNoteAction())); createAction("rest_semiquaver", SLOT(slotNoteAction())); createAction("rest_demisemi", SLOT(slotNoteAction())); createAction("rest_hemidemisemi", SLOT(slotNoteAction())); createAction("rest_dotted_breve", SLOT(slotNoteAction())); createAction("rest_dotted_semibreve", SLOT(slotNoteAction())); createAction("rest_dotted_minim", SLOT(slotNoteAction())); createAction("rest_dotted_crotchet", SLOT(slotNoteAction())); createAction("rest_dotted_quaver", SLOT(slotNoteAction())); createAction("rest_dotted_semiquaver", SLOT(slotNoteAction())); createAction("rest_dotted_demisemi", SLOT(slotNoteAction())); createAction("rest_dotted_hemidemisemi", SLOT(slotNoteAction())); //"Accidentals" submenu createAction("no_accidental", SLOT(slotNoAccidental())); createAction("follow_accidental", SLOT(slotFollowAccidental())); createAction("sharp_accidental", SLOT(slotSharp())); createAction("flat_accidental", SLOT(slotFlat())); createAction("natural_accidental", SLOT(slotNatural())); createAction("double_sharp_accidental", SLOT(slotDoubleSharp())); createAction("double_flat_accidental", SLOT(slotDoubleFlat())); //JAS "Clefs" subMenu createAction("treble_clef", SLOT(slotClefAction())); createAction("alto_clef", SLOT(slotClefAction())); createAction("tenor_clef", SLOT(slotClefAction())); createAction("bass_clef", SLOT(slotClefAction())); createAction("text", SLOT(slotText())); createAction("guitarchord", SLOT(slotGuitarChord())); // "Symbols" (sub)Menu createAction("add_segno", SLOT(slotSymbolAction())); createAction("add_coda", SLOT(slotSymbolAction())); createAction("add_breath", SLOT(slotSymbolAction())); //JAS "Move" subMenu createAction("extend_selection_backward", SLOT(slotExtendSelectionBackward())); createAction("extend_selection_forward", SLOT(slotExtendSelectionForward())); createAction("preview_selection", SLOT(slotPreviewSelection())); createAction("clear_loop", SLOT(slotClearLoop())); createAction("cursor_up_staff", SLOT(slotCurrentStaffUp())); createAction("cursor_down_staff", SLOT(slotCurrentStaffDown())); createAction("cursor_prior_segment", SLOT(slotCurrentSegmentPrior())); createAction("cursor_next_segment", SLOT(slotCurrentSegmentNext())); //"Transport" subMenu createAction("play", SIGNAL(play())); createAction("stop", SIGNAL(stop())); //Step Backward/Forward are protected signals // so the pitch tracker (our derrived class) can see them // Because they're protected, we'll connect them here. createAction("cursor_back", SIGNAL(stepBackward())); connect(this, SIGNAL(stepBackward()), this, SLOT(slotStepBackward())); createAction("cursor_forward", SIGNAL(stepForward())); connect(this, SIGNAL(stepForward()), this, SLOT(slotStepForward())); createAction("playback_pointer_back_bar", SIGNAL(rewindPlayback())); createAction("playback_pointer_forward_bar", SIGNAL(fastForwardPlayback())); createAction("playback_pointer_start", SIGNAL(rewindPlaybackToBeginning())); createAction("playback_pointer_end", SIGNAL(fastForwardPlaybackToEnd())); createAction("toggle_solo", SLOT(slotToggleSolo())); createAction("toggle_tracking", SLOT(slotToggleTracking())); createAction("panic", SIGNAL(panic())); //"insert_note_actionmenu" coded below. createAction("chord_mode", SLOT(slotUpdateInsertModeStatus())); createAction("triplet_mode", SLOT(slotUpdateInsertModeStatusTriplet())); createAction("tuplet_mode", SLOT(slotUpdateInsertModeStatusTuplet())); createAction("grace_mode", SLOT(slotUpdateInsertModeStatus())); createAction("toggle_step_by_step", SLOT(slotToggleStepByStep())); createAction("manual", SLOT(slotHelp())); createAction("tutorial", SLOT(slotTutorial())); createAction("guidelines", SLOT(slotBugGuidelines())); createAction("help_about_app", SLOT(slotHelpAbout())); createAction("help_about_qt", SLOT(slotHelpAboutQt())); createAction("donate", SLOT(slotDonate())); createAction("toggle_velocity_ruler", SLOT(slotToggleVelocityRuler())); createAction("toggle_pitchbend_ruler", SLOT(slotTogglePitchbendRuler())); createAction("add_control_ruler", ""); createAction("cycle_slashes", SLOT(slotCycleSlashes())); QMenu *addControlRulerMenu = new QMenu; Controllable *c = dynamic_cast(getCurrentDevice()); if (!c) { c = dynamic_cast(getCurrentDevice()); } if (c) { const ControlList &list = c->getControlParameters(); QString itemStr; for (ControlList::const_iterator it = list.begin(); it != list.end(); ++it) { // Pitch Bend is treated separately now, and there's no // point in adding "unsupported" controllers to the menu, // so skip everything else if (it->getType() != Controller::EventType) continue; QString hexValue; hexValue.sprintf("(0x%x)", it->getControllerValue()); // strings extracted from data files must be QObject::tr() itemStr = QObject::tr("%1 Controller %2 %3") .arg(QObject::tr(strtoqstr(it->getName()))) .arg(it->getControllerValue()) .arg(hexValue); addControlRulerMenu->addAction(itemStr); } } connect(addControlRulerMenu, SIGNAL(triggered(QAction*)), SLOT(slotAddControlRuler(QAction*))); connect(m_notationWidget, SIGNAL(hoveredOverNoteChanged(const QString&)), SLOT (slotHoveredOverNoteChanged(const QString&))); findAction("add_control_ruler")->setMenu(addControlRulerMenu); //Actions first appear in "settings" Menubar menu //"toolbars" subMenu createAction("options_show_toolbar", SLOT(slotToggleGeneralToolBar())); createAction("show_tools_toolbar", SLOT(slotToggleToolsToolBar())); createAction("show_duration_toolbar", SLOT(slotToggleDurationToolBar())); createAction("show_accidentals_toolbar", SLOT(slotToggleAccidentalsToolBar())); createAction("show_clefs_toolbar", SLOT(slotToggleClefsToolBar())); createAction("show_marks_toolbar", SLOT(slotToggleMarksToolBar())); createAction("show_group_toolbar", SLOT(slotToggleGroupToolBar())); createAction("show_symbol_toolbar", SLOT(slotToggleSymbolsToolBar())); createAction("show_transport_toolbar", SLOT(slotToggleTransportToolBar())); createAction("show_layout_toolbar", SLOT(slotToggleLayoutToolBar())); createAction("show_layer_toolbar", SLOT(slotToggleLayerToolBar())); createAction("show_rulers_toolbar", SLOT(slotToggleRulersToolBar())); createAction("show_duration_toolbar", SLOT(slotToggleDurationToolBar())); //"rulers" subMenu createAction("show_chords_ruler", SLOT(slotToggleChordsRuler())); createAction("show_raw_note_ruler", SLOT(slotToggleRawNoteRuler())); createAction("show_tempo_ruler", SLOT(slotToggleTempoRuler())); createAction("show_annotations", SLOT(slotToggleAnnotations())); createAction("show_lilypond_directives", SLOT(slotToggleLilyPondDirectives())); createAction("extend_selection_backward_bar", SLOT(slotExtendSelectionBackwardBar())); createAction("extend_selection_forward_bar", SLOT(slotExtendSelectionForwardBar())); //!!! not here yet createAction("move_selection_left", SLOT(slotMoveSelectionLeft())); //&&& NB Play has two shortcuts (Enter and Ctrl+Return) -- need to // ensure both get carried across somehow createAction("add_dot", SLOT(slotAddDot())); createAction("add_notation_dot", SLOT(slotAddDotNotationOnly())); //set duration of notes by CTRL+ createAction("set_note_type_doublewhole",SLOT(slotSetNoteType())); createAction("set_note_type_whole",SLOT(slotSetNoteType())); createAction("set_note_type_half",SLOT(slotSetNoteType())); createAction("set_note_type_quarter",SLOT(slotSetNoteType())); createAction("set_note_type_eighth",SLOT(slotSetNoteType())); createAction("set_note_type_sixteenth",SLOT(slotSetNoteType())); createAction("set_note_type_thirtysecond",SLOT(slotSetNoteType())); createAction("set_note_type_sixtyfourth",SLOT(slotSetNoteType())); //set duration of notes by CTRL+ALT+ createAction("set_note_type_notation_doublewhole",SLOT(slotSetNoteTypeNotationOnly())); createAction("set_note_type_notation_whole",SLOT(slotSetNoteTypeNotationOnly())); createAction("set_note_type_notation_half",SLOT(slotSetNoteTypeNotationOnly())); createAction("set_note_type_notation_quarter",SLOT(slotSetNoteTypeNotationOnly())); createAction("set_note_type_notation_eighth",SLOT(slotSetNoteTypeNotationOnly())); createAction("set_note_type_notation_sixteenth",SLOT(slotSetNoteTypeNotationOnly())); createAction("set_note_type_notation_thirtysecond",SLOT(slotSetNoteTypeNotationOnly())); createAction("set_note_type_notation_sixtyfourth",SLOT(slotSetNoteTypeNotationOnly())); //JAS insert note section is a rewrite //JAS from EditView::createInsertPitchActionMenu() for (int octave = 0; octave <= 2; ++octave) { QString octaveSuffix; if (octave == 1) octaveSuffix = "_high"; else if (octave == 2) octaveSuffix = "_low"; createAction(QString("insert_0%1").arg(octaveSuffix), SLOT(slotInsertNoteFromAction())); createAction(QString("insert_0_sharp%1").arg(octaveSuffix), SLOT(slotInsertNoteFromAction())); createAction(QString("insert_1_flat%1").arg(octaveSuffix), SLOT(slotInsertNoteFromAction())); createAction(QString("insert_1%1").arg(octaveSuffix), SLOT(slotInsertNoteFromAction())); createAction(QString("insert_1_sharp%1").arg(octaveSuffix), SLOT(slotInsertNoteFromAction())); createAction(QString("insert_2_flat%1").arg(octaveSuffix), SLOT(slotInsertNoteFromAction())); createAction(QString("insert_2%1").arg(octaveSuffix), SLOT(slotInsertNoteFromAction())); createAction(QString("insert_3%1").arg(octaveSuffix), SLOT(slotInsertNoteFromAction())); createAction(QString("insert_3_sharp%1").arg(octaveSuffix), SLOT(slotInsertNoteFromAction())); createAction(QString("insert_4_flat%1").arg(octaveSuffix), SLOT(slotInsertNoteFromAction())); createAction(QString("insert_4%1").arg(octaveSuffix), SLOT(slotInsertNoteFromAction())); createAction(QString("insert_4_sharp%1").arg(octaveSuffix), SLOT(slotInsertNoteFromAction())); createAction(QString("insert_5_flat%1").arg(octaveSuffix), SLOT(slotInsertNoteFromAction())); createAction(QString("insert_5%1").arg(octaveSuffix), SLOT(slotInsertNoteFromAction())); createAction(QString("insert_5_sharp%1").arg(octaveSuffix), SLOT(slotInsertNoteFromAction())); createAction(QString("insert_6_flat%1").arg(octaveSuffix), SLOT(slotInsertNoteFromAction())); createAction(QString("insert_6%1").arg(octaveSuffix), SLOT(slotInsertNoteFromAction())); } createAction(QString("insert_rest"),SLOT(slotInsertRestFromAction())); std::set fs(NoteFontFactory::getFontNames()); std::vector f; for (std::set::const_iterator i = fs.begin(); i != fs.end(); ++i) { f.push_back(*i); } std::sort(f.begin(), f.end()); // Custom Note Font Menu creator QMenu *fontActionMenu = new QMenu(tr("Note &Font"), this); fontActionMenu->setObjectName("note_font_actionmenu"); QActionGroup *ag = new QActionGroup(this); QSettings settings; settings.beginGroup(NotationViewConfigGroup); m_fontName = settings.value("notefont", NoteFontFactory::getDefaultFontName()).toString(); for (std::vector::iterator i = f.begin(); i != f.end(); ++i) { QString fontQName(*i); m_availableFontNames.push_back(fontQName); QAction *a = createAction("note_font_" + fontQName, SLOT(slotChangeFontFromAction())); ag->addAction(a); a->setText(fontQName); a->setCheckable(true); a->setChecked(*i == m_fontName); fontActionMenu->addAction(a); } QMenu *fontSizeActionMenu = new QMenu(tr("Si&ze"), this); fontSizeActionMenu->setObjectName("note_font_size_actionmenu"); ag = new QActionGroup(this); m_availableFontSizes = NoteFontFactory::getScreenSizes(m_fontName); for (unsigned int i = 0; i < m_availableFontSizes.size(); ++i) { QString actionName = QString("note_font_size_%1").arg(m_availableFontSizes[i]); QAction *sizeAction = createAction(actionName, SLOT(slotChangeFontSizeFromAction())); sizeAction->setText(tr("%n pixel(s)", "", m_availableFontSizes[i])); sizeAction->setCheckable(true); ag->addAction(sizeAction); sizeAction->setChecked(m_availableFontSizes[i] == m_fontSize); fontSizeActionMenu->addAction(sizeAction); } QMenu *spacingActionMenu = new QMenu(tr("S&pacing"), this); spacingActionMenu->setObjectName("stretch_actionmenu"); m_spacing = settings.value("spacing", m_notationWidget->getScene()->getHSpacing()).toInt(); m_notationWidget->getScene()->setHSpacing(m_spacing); m_availableSpacings = NotationHLayout::getAvailableSpacings(); ag = new QActionGroup(this); for (std::vector::iterator i = m_availableSpacings.begin(); i != m_availableSpacings.end(); ++i) { QAction *a = createAction(QString("spacing_%1").arg(*i), SLOT(slotChangeSpacingFromAction())); ag->addAction(a); a->setText(QString("%1%").arg(*i)); a->setCheckable(true); a->setChecked(*i == m_spacing); spacingActionMenu->addAction(a); } // no more duration factor controls settings.endGroup(); // connect up the segment changer signals connect(m_notationWidget, SIGNAL(currentSegmentNext()), SLOT(slotCurrentSegmentNext())); connect(m_notationWidget, SIGNAL(currentSegmentPrior()), SLOT(slotCurrentSegmentPrior())); } void NotationView::slotUpdateMenuStates() { NOTATION_DEBUG << "NotationView::slotUpdateMenuStates" << endl; // 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) leaveActionState("have_selection"); leaveActionState("have_notes_in_selection"); leaveActionState("have_rests_in_selection"); leaveActionState("have_clefs_in_selection"); leaveActionState("have_symbols_in_selection"); if (!m_notationWidget) return; EventSelection *selection = m_notationWidget->getSelection(); if (selection) { NOTATION_DEBUG << "NotationView::slotUpdateMenuStates: Have selection; it's " << selection << " covering range from " << selection->getStartTime() << " to " << selection->getEndTime() << " (" << selection->getSegmentEvents().size() << " events)" << endl; enterActionState("have_selection"); if (selection->contains(Note::EventType)) { enterActionState("have_notes_in_selection"); } if (selection->contains(Note::EventRestType)) { enterActionState("have_rests_in_selection"); } if (selection->contains(Clef::EventType)) { enterActionState("have_clefs_in_selection"); } if (selection->contains(Symbol::EventType)) { enterActionState("have_symbols_in_selection"); } } else { NOTATION_DEBUG << "Do not have a selection" << endl; } // 2. set inserter-related states NoteRestInserter *currentTool = dynamic_cast(m_notationWidget->getCurrentTool()); if (currentTool) { NOTATION_DEBUG << "Have NoteRestInserter " << endl; enterActionState("note_rest_tool_current"); } else { NOTATION_DEBUG << "Do not have NoteRestInserter " << endl; leaveActionState("note_rest_tool_current"); } if (m_selectionCounter) { if (selection && !selection->getSegmentEvents().empty()) { m_selectionCounter->setText(tr(" %n event(s) selected ", "", selection->getSegmentEvents().size())); } else { m_selectionCounter->setText(tr(" No selection ")); } } } void NotationView::initLayoutToolbar() { QToolBar *layoutToolbar = findToolbar("Layout Toolbar"); if (!layoutToolbar) { std::cerr << "NotationView::initLayoutToolbar() : layout toolbar not found" << std::endl; return; } // something missed in the stylesheet and at this point I feel like just // whacking the mole in the head with a hammer and moving on QString labelStyle("color: black"); QLabel *label = new QLabel(tr(" Font: "), layoutToolbar); if (m_Thorn) label->setStyleSheet("color: black"); layoutToolbar->addWidget(label); // There's some way to do this kind of thing with states or properties or // something, but I couldn't ever get it to work. So, again, I'll just use // another hacky hard coded internal stylesheet. // QString comboStyle("QComboBox::enabled,QComboBox{ border: 1px solid #AAAAAA; border-radius: 3px; padding: 0 5px 0 5px; min-width: 2em; color: #000000; } QComboBox::enabled:hover, QComboBox:hover, QComboBox::drop-down:hover { background-color: #CCDFFF; } QComboBox::!editable, QComboBox::drop-down:!editable { background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 #EEEEEE, stop:1 #DDDDDD); } QComboBox::!editable:on, QComboBox::drop-down:editable:on, { background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 #E0E0E0, stop:1 #EEEEEE); } QComboBox::on { padding-top: 3px; padding-left: 4px; } QComboBox::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 15px; } QComboBox::down-arrow { image: url(:pixmaps/style/arrow-down-small.png); } QComboBox::down-arrow:on { top: 1px; left: 1px; } QComboBox QAbstractItemView { border-image: url(:pixmaps/style/combo-dropdown.png) 1; selection-background-color: #80AFFF; selection-color: #FFFFFF; color: #000000; }"); // // font combo // m_fontCombo = new QComboBox(layoutToolbar); m_fontCombo->setEditable(false); if (m_Thorn) m_fontCombo->setStyleSheet(comboStyle); layoutToolbar->addWidget(m_fontCombo); bool foundFont = false; for (std::vector::const_iterator i = m_availableFontNames.begin(); i != m_availableFontNames.end(); ++i) { QString fontQName(*i); m_fontCombo->addItem(fontQName); if (fontQName.toLower() == m_fontName.toLower()) { m_fontCombo->setCurrentIndex(m_fontCombo->count() - 1); foundFont = true; } } if (!foundFont) { // don't annoy user with stupid internal warning dialog (except while // debugging) QMessageBox::warning (this, tr("Rosegarden"), tr("Unknown font \"%1\", using default") .arg(m_fontName) ); m_fontName = NoteFontFactory::getDefaultFontName(); } connect(m_fontCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(slotFontComboChanged(int))); label = new QLabel(tr(" Size: "), layoutToolbar); if (m_Thorn) label->setStyleSheet("color: black"); layoutToolbar->addWidget(label); QString value; // // font size combo // m_fontSizeCombo = new QComboBox(layoutToolbar); if (m_Thorn) m_fontSizeCombo->setStyleSheet(comboStyle); layoutToolbar->addWidget(m_fontSizeCombo); for (std::vector::iterator i = m_availableFontSizes.begin(); i != m_availableFontSizes.end(); ++i) { value.setNum(*i); m_fontSizeCombo->addItem(value); if ((*i) == m_fontSize) { m_fontSizeCombo->setCurrentIndex(m_fontSizeCombo->count() - 1); } } connect(m_fontSizeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(slotSizeComboChanged(int))); label = new QLabel(tr(" Spacing: "), layoutToolbar); if (m_Thorn) label->setStyleSheet("color: black"); layoutToolbar->addWidget(label); // // spacing combo // int spacing = m_notationWidget->getScene()->getHSpacing(); m_availableSpacings = NotationHLayout::getAvailableSpacings(); m_spacingCombo = new QComboBox(layoutToolbar); if (m_Thorn) m_spacingCombo->setStyleSheet(comboStyle); for (std::vector::iterator i = m_availableSpacings.begin(); i != m_availableSpacings.end(); ++i) { value.setNum(*i); value += "%"; m_spacingCombo->addItem(value); if ((*i) == spacing) { m_spacingCombo->setCurrentIndex(m_spacingCombo->count() - 1); } } connect(m_spacingCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(slotSpacingComboChanged(int))); layoutToolbar->addWidget(m_spacingCombo); } void NotationView::initRulersToolbar() { QToolBar *rulersToolbar = findToolbar("Rulers Toolbar"); if (!rulersToolbar) { std::cerr << "NotationView::initRulersToolbar() - rulers toolbar not found!" << std::endl; return; } // set the "ruler n" tool button to pop up its menu instantly QToolButton *tb = dynamic_cast(findToolbar("Rulers Toolbar")->widgetForAction(findAction("add_control_ruler"))); if (tb) { tb->setPopupMode(QToolButton::InstantPopup); } } void NotationView::initStatusBar() { QStatusBar* sb = statusBar(); m_hoveredOverNoteName = new QLabel(sb); m_hoveredOverNoteName->setMinimumWidth(32); sb->addPermanentWidget(m_hoveredOverNoteName); m_hoveredOverAbsoluteTime = new QLabel(sb); m_hoveredOverAbsoluteTime->setMinimumWidth(160); sb->addPermanentWidget(m_hoveredOverAbsoluteTime); m_currentNotePixmap = new QLabel(sb); m_currentNotePixmap->setMinimumWidth(20); sb->addPermanentWidget(m_currentNotePixmap); m_insertModeLabel = new QLabel(sb); sb->addPermanentWidget(m_insertModeLabel); m_annotationsLabel = new QLabel(sb); sb->addPermanentWidget(m_annotationsLabel); m_lilyPondDirectivesLabel = new QLabel(sb); sb->addPermanentWidget(m_lilyPondDirectivesLabel); m_selectionCounter = new QLabel(sb); sb->addWidget(m_selectionCounter); sb->setContentsMargins(0, 0, 0, 0); } void NotationView::readOptions() { setCheckBoxState("options_show_toolbar", "General Toolbar"); setCheckBoxState("show_tools_toolbar", "Tools Toolbar"); setCheckBoxState("show_accidentals_toolbar", "Accidentals Toolbar"); setCheckBoxState("show_clefs_toolbar", "Clefs Toolbar"); setCheckBoxState("show_marks_toolbar", "Marks Toolbar"); setCheckBoxState("show_group_toolbar", "Group Toolbar"); setCheckBoxState("show_symbol_toolbar", "Symbols Toolbar"); setCheckBoxState("show_transport_toolbar", "Transport Toolbar"); setCheckBoxState("show_layout_toolbar", "Layout Toolbar"); setCheckBoxState("show_layer_toolbar", "Layer Toolbar"); setCheckBoxState("show_rulers_toolbar", "Rulers Toolbar"); setCheckBoxState("show_duration_toolbar", "Duration Toolbar"); } void NotationView::setCurrentNotePixmap(QPixmap p) { if (!m_currentNotePixmap) return; QPixmap ip = IconLoader().invert(p); if (ip.height() > 16) { ip = ip.scaledToHeight(16, Qt::SmoothTransformation); } m_currentNotePixmap->setPixmap(ip); } void NotationView::setCurrentNotePixmapFrom(QAction *a) { if (!a) return; setCurrentNotePixmap(a->icon().pixmap()); } bool NotationView::exportLilyPondFile(QString file, bool forPreview) { QString caption = "", heading = ""; if (forPreview) { caption = tr("LilyPond Preview Options"); heading = tr("LilyPond preview options"); } LilyPondOptionsDialog dialog(this, m_doc, caption, heading); if (dialog.exec() != QDialog::Accepted) { return false; } LilyPondExporter e(this, m_doc, std::string(QFile::encodeName(file))); if (!e.write()) { QMessageBox::warning(this, tr("Rosegarden"), tr("Export failed. The file could not be opened for writing.")); return false; } return true; } void NotationView::slotPrintLilyPond() { TmpStatusMsg msg(tr("Printing with LilyPond..."), this); QString filename = getLilyPondTmpFilename(); if (filename.isEmpty()) return; if (!exportLilyPondFile(filename, true)) { return ; } LilyPondProcessor *dialog = new LilyPondProcessor(this, LilyPondProcessor::Print, filename); dialog->exec(); } void NotationView::slotPreviewLilyPond() { TmpStatusMsg msg(tr("Previewing with LilyPond..."), this); QString filename = getLilyPondTmpFilename(); if (filename.isEmpty()) return; if (!exportLilyPondFile(filename, true)) { return ; } LilyPondProcessor *dialog = new LilyPondProcessor(this, LilyPondProcessor::Preview, filename); dialog->exec(); } QString NotationView::getLilyPondTmpFilename() { QString mask = QString("%1/rosegarden_tmp_XXXXXX.ly").arg(QDir::tempPath()); std::cerr << "NotationView::getLilyPondTmpName() - using tmp file: " << qstrtostr(mask) << std::endl; QTemporaryFile *file = new QTemporaryFile(mask); file->setAutoRemove(true); if (!file->open()) { QMessageBox::warning(this, tr("Rosegarden"), tr("

Failed to open a temporary file for LilyPond export.

" "

This probably means you have run out of disk space on

%1

"). arg(QDir::tempPath())); delete file; return QString(); } QString filename = file->fileName(); // must call this before close() file->close(); // we just want the filename return filename; } void NotationView::slotLinearMode() { enterActionState("linear_mode"); if (m_notationWidget) m_notationWidget->slotSetLinearMode(); } void NotationView::slotContinuousPageMode() { leaveActionState("linear_mode"); if (m_notationWidget) m_notationWidget->slotSetContinuousPageMode(); } void NotationView::slotMultiPageMode() { leaveActionState("linear_mode"); if (m_notationWidget) m_notationWidget->slotSetMultiPageMode(); } void NotationView::slotShowHeadersGroup() { if (m_notationWidget) m_notationWidget->toggleHeadersView(); } void NotationView::slotChangeFontFromAction() { const QObject *s = sender(); QString name = s->objectName(); if (name.left(10) == "note_font_") { name = name.right(name.length() - 10); if (m_notationWidget) m_notationWidget->slotSetFontName(name); for (uint i = 0; i < m_availableFontNames.size(); ++i) { if (m_availableFontNames[i] == name) { m_fontCombo->setCurrentIndex(i); break; } } } else { QMessageBox::warning (this, tr("Rosegarden"), tr("Unknown font action %1").arg(name)); } } void NotationView::slotChangeFontSizeFromAction() { const QObject *s = sender(); QString name = s->objectName(); if (name.left(15) == "note_font_size_") { name = name.right(name.length() - 15); bool ok = false; int size = name.toInt(&ok); if (ok) { if (m_notationWidget) m_notationWidget->slotSetFontSize(size); for (uint i = 0; i < m_availableFontSizes.size(); ++i) { if (m_availableFontSizes[i] == size) { m_fontSizeCombo->setCurrentIndex(i); break; } } return; } } QMessageBox::warning (this, tr("Rosegarden"), tr("Unknown font size action %1").arg(name)); } void NotationView::slotChangeSpacingFromAction() { const QObject *s = sender(); QString name = s->objectName(); if (name.left(8) == "spacing_") { name = name.right(name.length() - 8); bool ok = false; int spacing = name.toInt(&ok); if (ok) { if (m_notationWidget) m_notationWidget->getScene()->setHSpacing(spacing); for (uint i = 0; i < m_availableSpacings.size(); ++i) { if (m_availableSpacings[i] == spacing) { m_spacingCombo->setCurrentIndex(i); break; } } return; } } QMessageBox::warning (this, tr("Rosegarden"), tr("Unknown spacing action %1").arg(name)); } Segment * NotationView::getCurrentSegment() { if (m_notationWidget) return m_notationWidget->getCurrentSegment(); else return 0; } EventSelection * NotationView::getSelection() const { if (m_notationWidget) return m_notationWidget->getSelection(); else return 0; } void NotationView::setSelection(EventSelection *selection, bool preview) { if (m_notationWidget) m_notationWidget->setSelection(selection, preview); } timeT NotationView::getInsertionTime() const { if (m_notationWidget) return m_notationWidget->getInsertionTime(); else return 0; } void NotationView::slotEditCut() { EventSelection *selection = getSelection(); if (!selection) return; CommandHistory::getInstance()->addCommand (new CutCommand(*selection, m_document->getClipboard())); } void NotationView::slotEditDelete() { EventSelection *selection = getSelection(); if (!selection) return; CommandHistory::getInstance()->addCommand(new EraseCommand(*selection)); } void NotationView::slotEditCopy() { EventSelection *selection = getSelection(); if (!selection) return; CommandHistory::getInstance()->addCommand (new CopyCommand(*selection, m_document->getClipboard())); } void NotationView::slotEditCutAndClose() { EventSelection *selection = getSelection(); if (!selection) return; CommandHistory::getInstance()->addCommand (new CutAndCloseCommand(*selection, m_document->getClipboard())); } void NotationView::slotEditPaste() { Clipboard *clipboard = m_document->getClipboard(); if (clipboard->isEmpty()) return; if (!clipboard->isSingleSegment()) { slotStatusHelpMsg(tr("Can't paste multiple Segments into one")); return; } Segment *segment = getCurrentSegment(); if (!segment) return; // Paste at cursor position // timeT insertionTime = getInsertionTime(); timeT endTime = insertionTime + (clipboard->getSingleSegment()->getEndTime() - clipboard->getSingleSegment()->getStartTime()); QSettings settings; settings.beginGroup(NotationViewConfigGroup); PasteEventsCommand::PasteType defaultType = (PasteEventsCommand::PasteType) settings.value("pastetype", PasteEventsCommand::Restricted).toUInt(); PasteEventsCommand *command = new PasteEventsCommand (*segment, clipboard, insertionTime, defaultType); if (!command->isPossible()) { // NOTES: To get a reasonable presentation of the standard and detailed // text, we have to build up our own QMessageBox // // The old RESTRICTED_PASTE_DESCRIPTION was removed because it was // impossible to get the translation, which had to be done in the // QObject::tr() context, to work in this context here. Qt is really // quirky that way. Instead, I'm just block copying all of this now // that I've reworked it. Is this copy you're looking at the original, // or the copy? Only I know for sure, and I'll never tell! Bwa haha! QMessageBox msgBox; msgBox.setWindowTitle(tr("Rosegarden")); msgBox.setIcon(QMessageBox::Warning); msgBox.setText(tr("Couldn't paste at this point.")); msgBox.setInformativeText(tr("

The Restricted paste type requires enough empty space (containing only rests) at the paste position to hold all of the events to be pasted.

Not enough space was found.

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.

")); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setDefaultButton(QMessageBox::Ok); msgBox.exec(); delete command; } else { CommandHistory::getInstance()->addCommand(command); setSelection(new EventSelection(command->getPastedEvents()), false); //!!! slotSetInsertCursorPosition(endTime, true, false); m_document->slotSetPointerPosition(endTime); } settings.endGroup(); } void NotationView::slotEditGeneralPaste() { Clipboard *clipboard = getDocument()->getClipboard(); if (clipboard->isEmpty()) { slotStatusHelpMsg(tr("Clipboard is empty")); return ; } slotStatusHelpMsg(tr("Inserting clipboard contents...")); Segment *segment = getCurrentSegment(); if (!segment) return; QSettings settings; settings.beginGroup(NotationViewConfigGroup); PasteEventsCommand::PasteType defaultType = (PasteEventsCommand::PasteType) settings.value("pastetype", PasteEventsCommand::Restricted).toUInt(); PasteNotationDialog dialog(this, defaultType); if (dialog.exec() == QDialog::Accepted) { PasteEventsCommand::PasteType type = dialog.getPasteType(); if (dialog.setAsDefault()) { //###settings.beginGroup( NotationViewConfigGroup ); settings.setValue("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()) { // NOTES: To get a reasonable presentation of the standard and detailed // text, we have to build up our own QMessageBox // // The old RESTRICTED_PASTE_DESCRIPTION was removed because it was // impossible to get the translation, which had to be done in the // QObject::tr() context, to work in this context here. Qt is really // quirky that way. Instead, I'm just block copying all of this now // that I've reworked it. Is this copy you're looking at the original, // or the copy? Only I know for sure, and I'll never tell! Bwa haha! QMessageBox msgBox; msgBox.setWindowTitle(tr("Rosegarden")); msgBox.setIcon(QMessageBox::Warning); msgBox.setText(tr("Couldn't paste at this point.")); msgBox.setInformativeText(tr("

The Restricted paste type requires enough empty space (containing only rests) at the paste position to hold all of the events to be pasted.

Not enough space was found.

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.

")); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setDefaultButton(QMessageBox::Ok); msgBox.exec(); delete command; } else { CommandHistory::getInstance()->addCommand(command); setSelection(new EventSelection(*segment, insertionTime, endTime), false); //!!! slotSetInsertCursorPosition(endTime, true, false); m_document->slotSetPointerPosition(endTime); } } settings.endGroup(); } void NotationView::slotPreviewSelection() { if (!getSelection()) return ; getDocument()->slotSetLoop(getSelection()->getStartTime(), getSelection()->getEndTime()); } 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(m_notationWidget->getCurrentTool()); if (!selector) { slotSetSelectTool(); } else { setSelection(0, false); } } void NotationView::slotEditSelectFromStart() { timeT t = getInsertionTime(); Segment *segment = getCurrentSegment(); setSelection(new EventSelection(*segment, segment->getStartTime(), t), false); } void NotationView::slotEditSelectToEnd() { timeT t = getInsertionTime(); Segment *segment = getCurrentSegment(); setSelection(new EventSelection(*segment, t, segment->getEndMarkerTime()), false); } void NotationView::slotEditSelectWholeStaff() { Segment *segment = getCurrentSegment(); setSelection(new EventSelection(*segment, segment->getStartTime(), segment->getEndMarkerTime()), false); } void NotationView::slotFilterSelection() { NOTATION_DEBUG << "NotationView::slotFilterSelection" << endl; Segment *segment = getCurrentSegment(); EventSelection *existingSelection = getSelection(); 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) { setSelection(newSelection, false); } else { setSelection(0, false); } } } void NotationView::slotVelocityUp() { if (!getSelection()) return ; TmpStatusMsg msg(tr("Raising velocities..."), this); CommandHistory::getInstance()->addCommand(new ChangeVelocityCommand( 10, *getSelection())); } void NotationView::slotVelocityDown() { if (!getSelection()) return ; TmpStatusMsg msg(tr("Lowering velocities..."), this); CommandHistory::getInstance()->addCommand(new ChangeVelocityCommand( -10, *getSelection())); } int NotationView::getVelocityFromSelection() { if (!getSelection()) return 0; float totalVelocity = 0; int count = 0; for (EventSelection::eventcontainer::iterator i = getSelection()->getSegmentEvents().begin(); i != getSelection()->getSegmentEvents().end(); ++i) { if ((*i)->has(BaseProperties::VELOCITY)) { totalVelocity += (*i)->get(BaseProperties::VELOCITY); ++count; } } if (count > 0) { return (totalVelocity / count) + 0.5; } return 0; } void NotationView::slotSetVelocities() { if (!getSelection()) return ; EventParameterDialog dialog(this, tr("Set Event Velocities"), BaseProperties::VELOCITY, getVelocityFromSelection()); if (dialog.exec() == QDialog::Accepted) { TmpStatusMsg msg(tr("Setting Velocities..."), this); CommandHistory::getInstance()->addCommand( new SelectionPropertyCommand( getSelection(), BaseProperties::VELOCITY, dialog.getPattern(), dialog.getValue1(), dialog.getValue2())); } } void NotationView::slotClearLoop() { getDocument()->slotSetLoop(0, 0); } void NotationView::slotCurrentStaffUp() { NotationScene *scene = m_notationWidget->getScene(); if (!scene) return; NotationStaff *staff = scene->getStaffAbove(); if (!staff) return; scene->setCurrentStaff(staff); } void NotationView::slotCurrentStaffDown() { NotationScene *scene = m_notationWidget->getScene(); if (!scene) return; NotationStaff *staff = scene->getStaffBelow(); if (!staff) return; scene->setCurrentStaff(staff); } void NotationView::slotCurrentSegmentPrior() { NotationScene *scene = m_notationWidget->getScene(); if (!scene) return; NotationStaff *staff = scene->getPriorStaffOnTrack(); if (!staff) return; scene->setCurrentStaff(staff); slotEditSelectWholeStaff(); } void NotationView::slotCurrentSegmentNext() { NotationScene *scene = m_notationWidget->getScene(); if (!scene) return; NotationStaff *staff = scene->getNextStaffOnTrack(); if (!staff) return; scene->setCurrentStaff(staff); slotEditSelectWholeStaff(); } void NotationView::slotToggleGeneralToolBar() { toggleNamedToolBar("General Toolbar"); } void NotationView::slotToggleToolsToolBar() { toggleNamedToolBar("Tools Toolbar"); } void NotationView::slotToggleDurationToolBar() { toggleNamedToolBar("Duration Toolbar"); } void NotationView::slotToggleAccidentalsToolBar() { toggleNamedToolBar("Accidentals Toolbar"); } void NotationView::slotToggleClefsToolBar() { toggleNamedToolBar("Clefs Toolbar"); } void NotationView::slotToggleMarksToolBar() { toggleNamedToolBar("Marks Toolbar"); } void NotationView::slotToggleGroupToolBar() { toggleNamedToolBar("Group Toolbar"); } void NotationView::slotToggleSymbolsToolBar() { toggleNamedToolBar("Symbols Toolbar"); } void NotationView::slotToggleLayoutToolBar() { toggleNamedToolBar("Layout Toolbar"); } void NotationView::slotToggleRulersToolBar() { toggleNamedToolBar("Rulers Toolbar"); } void NotationView::slotToggleTransportToolBar() { toggleNamedToolBar("Transport Toolbar"); } void NotationView::slotToggleLayerToolBar() { toggleNamedToolBar("Layer Toolbar"); } void NotationView::toggleNamedToolBar(const QString& toolBarName, bool* force) { // QToolBar *namedToolBar = toolBar(toolBarName); QToolBar *namedToolBar = findChild(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(); //&&& not required ? } void NotationView::slotSetSelectTool() { if (m_notationWidget) m_notationWidget->slotSetSelectTool(); slotUpdateMenuStates(); } void NotationView::slotSetEraseTool() { if (m_notationWidget) m_notationWidget->slotSetEraseTool(); slotUpdateMenuStates(); } void NotationView::slotSetNoteRestInserter() { NOTATION_DEBUG << "NotationView::slotSetNoteRestInserter : entered. " << endl; if (m_notationWidget) m_notationWidget->slotSetNoteRestInserter(); //Must ensure it is set since may be called from multiple actions. findAction("draw")->setChecked(true); slotUpdateMenuStates(); } void NotationView::slotSwitchToNotes() { NOTATION_DEBUG << "NotationView::slotSwitchToNotes : entered. " << endl; QString actionName = ""; NoteRestInserter *currentInserter = NULL; if (m_notationWidget) { currentInserter = dynamic_cast (m_notationWidget->getCurrentTool()); if (!currentInserter) { // Switch to NoteRestInserter slotSetNoteRestInserter(); NOTATION_DEBUG << "NotationView::slotSwitchToNotes() : " << "NoteRestInserter not current. Attempted to switch. " << endl; //Try again to see if tool is set. currentInserter = dynamic_cast (m_notationWidget->getCurrentTool()); if (!currentInserter) { NOTATION_DEBUG << "NotationView::slotSwitchToNotes() : expected" << " NoteRestInserter as current tool & " << "could not switch to it. Silent exit." << endl; return; } } Note::Type unitType = currentInserter->getCurrentNote() .getNoteType(); int dots = (currentInserter->getCurrentNote().getDots() ? 1 : 0); actionName = NotationStrings::getReferenceName(Note(unitType,dots)); actionName.replace(QRegExp("-"), "_"); m_notationWidget->slotSetNoteInserter(); } //Must set duration_ shortcuts to false to fix bug when in rest mode // and a duration shortcut key is pressed (or selected from dur. menu). findAction(QString("duration_%1").arg(actionName))->setChecked(false); QAction *currentAction = findAction(actionName); currentAction->setChecked(true); // This code and last line above used to maintain exclusive state // of the Duration Toolbar so we can reactivate the NoteRestInserter // even when from a pressed button on the bar. // Now un-select previous pressed button pressed if (currentAction != m_durationPressed) { m_durationPressed->setChecked(false); m_durationPressed = currentAction; } morphDurationMonobar(); slotUpdateMenuStates(); } void NotationView::slotSwitchToRests() { NOTATION_DEBUG << "NotationView::slotSwitchToRests : entered. " << endl; QString actionName = ""; NoteRestInserter *currentInserter = NULL; if (m_notationWidget) { currentInserter = dynamic_cast (m_notationWidget->getCurrentTool()); if (!currentInserter) { // Switch to NoteRestInserter slotSetNoteRestInserter(); NOTATION_DEBUG << "NotationView::slotSwitchToRests() : " << "NoteRestInserter not current. Attempted to switch. " << endl; //Try again to see if tool is set. currentInserter = dynamic_cast (m_notationWidget->getCurrentTool()); if (!currentInserter) { NOTATION_DEBUG << "NotationView::slotSwitchToRests() : expected" << " NoteRestInserter as current tool & " << "could not switch to it. Silent exit." << endl; return; } } Note::Type unitType = currentInserter->getCurrentNote() .getNoteType(); int dots = (currentInserter->getCurrentNote().getDots() ? 1 : 0); actionName = NotationStrings::getReferenceName(Note(unitType,dots)); actionName.replace(QRegExp("-"), "_"); m_notationWidget->slotSetRestInserter(); } //Must set duration_ shortcuts to false to fix bug when in rest mode // and a duration shortcut key is pressed (or selected from dur. menu). findAction(QString("duration_%1").arg(actionName))->setChecked(false); findAction(QString("rest_%1").arg(actionName))->setChecked(true); //Must set duration_ shortcuts to false to fix bug when in rest mode // and a duration shortcut key is pressed (or selected from dur. menu). findAction(QString("duration_%1").arg(actionName))->setChecked(false); QAction *currentAction = findAction(QString("rest_%1").arg(actionName)); currentAction->setChecked(true); // This code and last line above used to maintain exclusive state // of the Duration Toolbar so we can reactivate the NoteRestInserter // even when from a pressed button on the bar. // Now un-select previous pressed button pressed if (currentAction != m_durationPressed) { m_durationPressed->setChecked(false); m_durationPressed = currentAction; } morphDurationMonobar(); slotUpdateMenuStates(); } void NotationView::morphDurationMonobar() { NOTATION_DEBUG << "NotationView::morphDurationMonobar : entered. " << endl; NoteRestInserter *currentInserter = 0; if (m_notationWidget) { currentInserter = dynamic_cast (m_notationWidget->getCurrentTool()); } if (!currentInserter) { // Morph called when NoteRestInserter not set as current tool NOTATION_DEBUG << "NotationView::morphNotationToolbar() : expected" << " NoteRestInserter. Silent Exit." << endl; return; } // Retrieve duration and dot values int dots = currentInserter->getCurrentNote().getDots(); Note::Type note = currentInserter->getCurrentNote().getNoteType(); // Determine duration tooolbar mode DurationMonobarModeType newMode = InsertingNotes; if (currentInserter->isaRestInserter()) { newMode = (dots ? InsertingDottedRests : InsertingRests); } else { newMode = (dots ? InsertingDottedNotes : InsertingNotes); } //Convert to English for debug purposes. std::string modeStr; switch (newMode) { case InsertingNotes: modeStr = "Notes Toolbar"; break; case InsertingDottedNotes: modeStr = "Dotted Notes Toolbar"; break; case InsertingRests: modeStr = "Rests Toolbar"; break; case InsertingDottedRests: modeStr = "Dotted Rests Toolbar"; break; default: modeStr = "WTF? This won't be pretty."; } NOTATION_DEBUG << "NotationView::morphDurationMonobar: morphing to " << modeStr << endl; if (newMode == m_durationMode && note != Note::Shortest && dots) { NOTATION_DEBUG << "NotationView::morphDurationMonobar: new " << "mode and last mode are the same. exit wothout morphing." << endl; return; } // Turn off current state (or last state--depending on perspective.) switch (m_durationMode) { case InsertingNotes: leaveActionState("note_0_dot_mode"); break; case InsertingDottedNotes: leaveActionState("note_1_dot_mode"); break; case InsertingRests: leaveActionState("rest_0_dot_mode"); break; case InsertingDottedRests: leaveActionState("rest_1_dot_mode"); break; default: NOTATION_DEBUG << "NotationView::morphDurationMonobar: None of " << "The standard four modes were selected for m_durationMode. " << "How did that happen?" << endl; } // transfer new mode to member for next recall. m_durationMode = newMode; // Now morph to new state. switch (newMode) { case InsertingNotes: enterActionState("note_0_dot_mode"); break; case InsertingDottedNotes: enterActionState("note_1_dot_mode"); break; case InsertingRests: enterActionState("rest_0_dot_mode"); break; case InsertingDottedRests: enterActionState("rest_1_dot_mode"); break; default: NOTATION_DEBUG << "NotationView::morphDurationMonobar: None of " << "The standard four modes were selected for newMode. " << "How did that happen?" << endl; } // This code to manage shortest dotted note selection. // Disable the shortcut in the menu for shortest duration. if (note == Note::Shortest && !dots) { NOTATION_DEBUG << "NotationView::morphDurationMonobar: shortest " << "note / no dots. disable off +. action"; QAction *switchDots = findAction("switch_dots_on"); switchDots->setEnabled(false); } } void NotationView::initializeNoteRestInserter() { // Set Default Duration based on Time Signature denominator. // The default unitType is taken from the denominator of the time signature: // e.g. 4/4 -> 1/4, 6/8 -> 1/8, 2/2 -> 1/2. TimeSignature sig = getDocument()->getComposition().getTimeSignatureAt(getInsertionTime()); Note::Type unitType = sig.getUnit(); QString actionName = NotationStrings::getReferenceName(Note(unitType,0)); actionName.replace(QRegExp("-"), "_"); //Initialize Duration Toolbar (hide all buttons) leaveActionState("note_0_dot_mode"); leaveActionState("note_1_dot_mode"); leaveActionState("rest_0_dot_mode"); leaveActionState("rest_1_dot_mode"); //Change exclusive settings so we can retrigger Duration Toolbar //actions when button needed is pressed. //exclusive state maintianed via slotSwitchToRests() / slotSwitchToNotes(). findGroup("duration_toolbar")->setExclusive(false); // Initialize the m_durationPressed so we don't have to null check elswhere. m_durationPressed = findAction(QString("duration_%1").arg(actionName)); // Counting on a InsertingRests to be stored in NoteRestInserter:: // m_durationMode which it was passed in the constructor. This will // ensure morphDurationMonobar always fires correctly since // a duration_ shortcut is always tied to the note palette. m_durationPressed->trigger(); //Change exclusive settings so we can retrigger Accidental Toolbar //actions when button needed is pressed. //exclusive state maintianed via manageAccidentalAction(). findGroup("accidentals")->setExclusive(false); // Initialize the m_durationPressed so we don't have to null check elswhere. m_accidentalPressed = findAction("no_accidental"); } int NotationView::getPitchFromNoteInsertAction(QString name, Accidental &accidental, const Clef &clef, const Rosegarden::Key &key) { using namespace Accidentals; accidental = NoAccidental; if (name.left(7) == "insert_") { name = name.right(name.length() - 7); int modify = 0; int octave = 0; if (name.right(5) == "_high") { octave = 1; name = name.left(name.length() - 5); } else if (name.right(4) == "_low") { octave = -1; name = name.left(name.length() - 4); } if (name.right(6) == "_sharp") { modify = 1; accidental = Sharp; name = name.left(name.length() - 6); } else if (name.right(5) == "_flat") { modify = -1; accidental = Flat; name = name.left(name.length() - 5); } int scalePitch = name.toInt(); if (scalePitch < 0 || scalePitch > 7) { std::cerr << "NotationView::getPitchFromNoteInsertAction: pitch " << scalePitch << " out of range, using 0" << std::endl; scalePitch = 0; } Pitch clefPitch(clef.getAxisHeight(), clef, key, NoAccidental); int clefOctave = clefPitch.getOctave(); int pitchOctave = clefOctave + octave; NOTATION_DEBUG << "NotationView::getPitchFromNoteInsertAction:" << " key = " << key.getName() << ", clef = " << clef.getClefType() << ", octaveoffset = " << clef.getOctaveOffset() << endl; NOTATION_DEBUG << "NotationView::getPitchFromNoteInsertAction: octave = " << pitchOctave << endl; // Rewrite to fix bug #2997303 : // // We want to make sure that // (i) The lowest note in scale (with octave = -1) is drawn below // the staff // (ii) The highest note in scale (with octave = +1) is drawn above // the staff // // Let lnh be the height on staff of this lowest note and let hnh be // the height on staff of this highest note. // (iii) hnh = lnh + 7 + 7 + 6 = lnh + 20 // // (iv) One way to have (i) and (ii) verified is to make the middle // of lnh and hnh, i.e. (lnh + hnh) / 2, as near as possible of // the middle of the staff, i.e. 4. // // (iii) and (iv) result in lnh being as near as possible of -6, // i.e. -10 < lnh < -2. int lowestNoteInScale = 0; Pitch lowestPitch(lowestNoteInScale, clefOctave - 1, key, NoAccidental); int lnh = lowestPitch.getHeightOnStaff(clef, key); for (; lnh < -9; lnh += 7) pitchOctave++; for (; lnh > -3; lnh -= 7) pitchOctave--; NOTATION_DEBUG << "NotationView::getPitchFromNoteInsertAction: octave = " << pitchOctave << " (adjusted)" << endl; Pitch pitch(scalePitch, pitchOctave, key, accidental); return pitch.getPerformancePitch(); } else { throw Exception("Not an insert action", __FILE__, __LINE__); } } void NotationView::slotPitchBendSequence() { timeT startTime=0; timeT endTime=0; if (getSelection()) { startTime=getSelection()->getStartTime(); endTime=getSelection()->getEndTime(); } else { startTime = getInsertionTime(); } PitchBendSequenceDialog dialog(this, getCurrentSegment(), startTime, endTime); dialog.exec(); } void NotationView::slotInsertNoteFromAction() { const QObject *s = sender(); QString name = s->objectName(); Segment *segment = getCurrentSegment(); if (!segment) return; NoteRestInserter *currentInserter = 0; if(m_notationWidget) { currentInserter = dynamic_cast (m_notationWidget->getCurrentTool()); if(!currentInserter) { //set the NoteRestInserter as current slotSetNoteRestInserter(); //re-fetch the current tool for analysis currentInserter = dynamic_cast (m_notationWidget->getCurrentTool()); } if (currentInserter) { if (currentInserter->isaRestInserter()) { slotSwitchToNotes(); } int pitch = 0; Accidental accidental = Accidentals::NoAccidental; timeT insertionTime = getInsertionTime(); Rosegarden::Key key = segment->getKeyAtTime(insertionTime); Clef clef = segment->getClefAtTime(insertionTime); try { std::cerr << "NotationView::slotInsertNoteFromAction: time = " << insertionTime << ", key = " << key.getName() << ", clef = " << clef.getClefType() << ", octaveoffset = " << clef.getOctaveOffset() << std::endl; pitch = getPitchFromNoteInsertAction(name, accidental, clef, key); } catch (...) { QMessageBox::warning (this, tr("Rosegarden"), tr("Unknown note insert action %1").arg(name)); return ; } TmpStatusMsg msg(tr("Inserting note"), this); NOTATION_DEBUG << "Inserting note at pitch " << pitch << endl; currentInserter->insertNote(*segment, insertionTime, pitch, accidental, 100); // Velocity hard coded for now. } } } void NotationView::slotInsertRestFromAction() { Segment *segment = getCurrentSegment(); if (!segment) return; NoteRestInserter *currentInserter = 0; if(m_notationWidget) { currentInserter = dynamic_cast (m_notationWidget->getCurrentTool()); if(!currentInserter) { //set the NoteRestInserter as current slotSetNoteRestInserter(); //re-fetch the current tool for analysis currentInserter = dynamic_cast (m_notationWidget->getCurrentTool()); } if (currentInserter) { if (!currentInserter->isaRestInserter()) { slotSwitchToRests(); } timeT insertionTime = getInsertionTime(); currentInserter->insertNote(*segment, insertionTime, 0, Accidentals::NoAccidental, true); } } } void NotationView::slotToggleDot() { NOTATION_DEBUG << "NotationView::slotToggleDot : entered. " << endl; NoteRestInserter *currentInserter = NULL; if (m_notationWidget) { currentInserter = dynamic_cast (m_notationWidget->getCurrentTool()); if (!currentInserter) { // Switch to NoteRestInserter slotSetNoteRestInserter(); NOTATION_DEBUG << "NotationView::slotToggleDot() : " << "NoteRestInserter not current. Attempted to switch. " << endl; //Try again to see if tool is set. currentInserter = dynamic_cast (m_notationWidget->getCurrentTool()); if (!currentInserter) { NOTATION_DEBUG << "NotationView::slotToggleDot() : expected" << " NoteRestInserter as current tool & " << "could not switch to it. Silent exit." << endl; return; } } Note note = currentInserter->getCurrentNote(); Note::Type noteType = note.getNoteType(); int noteDots = (note.getDots() ? 0 : 1); // Toggle the dot state if (noteDots && noteType == Note::Shortest) { // This might have been invoked via a keboard shortcut or other // toggling the +. button when the shortest note was pressed. // RG does not render dotted versions of its shortest duration // and rounds it up to the next duration. // Following RG's lead on this makes the inteface feel off since // This moves the toggle to the next longest duration without // switching the pallete to dots. // So just leave the duration alone and don't toggle the dot // in this case. noteDots = 0; } QString actionName(NotationStrings::getReferenceName(Note(noteType,noteDots))); actionName.replace(QRegExp("-"), "_"); m_notationWidget->slotSetInsertedNote(noteType, noteDots); if (currentInserter->isaRestInserter()) { slotSwitchToRests(); } else { slotSwitchToNotes(); } } } void NotationView::slotNoteAction() { NOTATION_DEBUG << "NotationView::slotNoteAction : entered. " << endl; QObject *s = sender(); QAction *a = dynamic_cast(s); QString name = s->objectName(); QString noteToolbarName; //Set defaults for duration_ shortcut calls bool rest = false; int dots = 0; if (m_notationWidget) { NoteRestInserter *currentTool = dynamic_cast (m_notationWidget->getCurrentTool()); if (!currentTool) { //Must select NoteRestInserter tool as current Tool slotSetNoteRestInserter(); //Now re-fetch the current tool for analysis. currentTool = dynamic_cast(m_notationWidget ->getCurrentTool()); } if (name.startsWith("duration_")) { name = name.replace("duration_", ""); NOTATION_DEBUG << "NotationView::slotNoteAction : " << "Duration shortcut called." << endl; //duration shortcut called from keyboard or menu. //Must switch to insert Notes mode. } else if (currentTool->isaRestInserter()) { NOTATION_DEBUG << "NotationView::slotNoteAction : " << "Have rest inserter." << endl; if (name.startsWith("rest_")) { name = name.replace("rest_", ""); } rest = true; } else { NOTATION_DEBUG << "NotationView::slotNoteAction : " << "Have note inserter." << endl; } } if (name.startsWith("dotted_")) { dots = 1; name = name.replace("dotted_", ""); } Note::Type type = NotationStrings::getNoteForName(name).getNoteType(); if (m_notationWidget) { m_notationWidget->slotSetInsertedNote(type, dots); if (rest) { slotSwitchToRests(); } else { slotSwitchToNotes(); } } setCurrentNotePixmapFrom(a); } void NotationView::manageAccidentalAction(QString actionName) { NOTATION_DEBUG << "NotationView::manageAccidentalAction: enter. " << "actionName = " << actionName << "." << endl; // Manage exclusive group setting since group->isExclusive() == false. QAction *currentAction = findAction(actionName); // Force the current button to be pressed currentAction->setChecked(true); if (m_accidentalPressed != currentAction) { m_accidentalPressed->setChecked(false); m_accidentalPressed = currentAction; } // Set The Note / Rest Inserter Tool as curretn tool if needed. if (m_notationWidget) { NoteRestInserter *currentInserter = dynamic_cast (m_notationWidget->getCurrentTool()); if (!currentInserter) { slotSetNoteRestInserter(); // re-fetch tool for analysis. currentInserter = dynamic_cast (m_notationWidget->getCurrentTool()); } if (currentInserter->isaRestInserter()) { slotSwitchToNotes(); } } } void NotationView::slotNoAccidental() { QObject *s = sender(); QString name = s->objectName(); manageAccidentalAction(name); if (m_notationWidget) m_notationWidget->slotSetAccidental(NoAccidental, false); } void NotationView::slotFollowAccidental() { QObject *s = sender(); QString name = s->objectName(); manageAccidentalAction(name); if (m_notationWidget) m_notationWidget->slotSetAccidental(NoAccidental, true); } void NotationView::slotSharp() { QObject *s = sender(); QString name = s->objectName(); manageAccidentalAction(name); if (m_notationWidget) m_notationWidget->slotSetAccidental(Sharp, false); } void NotationView::slotFlat() { QObject *s = sender(); QString name = s->objectName(); manageAccidentalAction(name); if (m_notationWidget) m_notationWidget->slotSetAccidental(Flat, false); } void NotationView::slotNatural() { QObject *s = sender(); QString name = s->objectName(); manageAccidentalAction(name); if (m_notationWidget) m_notationWidget->slotSetAccidental(Natural, false); } void NotationView::slotDoubleSharp() { QObject *s = sender(); QString name = s->objectName(); manageAccidentalAction(name); if (m_notationWidget) m_notationWidget->slotSetAccidental(DoubleSharp, false); } void NotationView::slotDoubleFlat() { QObject *s = sender(); QString name = s->objectName(); manageAccidentalAction(name); if (m_notationWidget) m_notationWidget->slotSetAccidental(DoubleFlat, false); } void NotationView::slotClefAction() { QObject *s = sender(); QAction *a = dynamic_cast(s); QString n = s->objectName(); Clef type = Clef::Treble; if (n == "treble_clef") type = Clef::Treble; else if (n == "alto_clef") type = Clef::Alto; else if (n == "tenor_clef") type = Clef::Tenor; else if (n == "bass_clef") type = Clef::Bass; setCurrentNotePixmapFrom(a); if (!m_notationWidget) return; m_notationWidget->slotSetClefInserter(); m_notationWidget->slotSetInsertedClef(type); slotUpdateMenuStates(); } void NotationView::slotText() { QObject *s = sender(); setCurrentNotePixmapFrom(dynamic_cast(s)); if (!m_notationWidget) return; m_notationWidget->slotSetTextInserter(); slotUpdateMenuStates(); } void NotationView::slotGuitarChord() { QObject *s = sender(); setCurrentNotePixmapFrom(dynamic_cast(s)); if (!m_notationWidget) return; m_notationWidget->slotSetGuitarChordInserter(); slotUpdateMenuStates(); } void NotationView::slotTransformsQuantize() { EventSelection *selection = getSelection(); if (!selection) return; QuantizeDialog dialog(this, true); if (dialog.exec() == QDialog::Accepted) { CommandHistory::getInstance()->addCommand (new EventQuantizeCommand (*selection, dialog.getQuantizer())); } } void NotationView::slotTransformsInterpret() { EventSelection *selection = getSelection(); if (!selection) return; InterpretDialog dialog(this); if (dialog.exec() == QDialog::Accepted) { CommandHistory::getInstance()->addCommand (new InterpretCommand (*selection, getDocument()->getComposition().getNotationQuantizer(), dialog.getInterpretations())); } } void NotationView::slotMakeOrnament() { if (!getSelection()) return ; EventSelection::eventcontainer &ec = getSelection()->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(BaseProperties::PITCH); style = NoteStyleFactory::getStyleForEvent(*i); if (baseVelocity != -1) break; } if ((*i)->has(BaseProperties::VELOCITY)) { baseVelocity = (*i)->get(BaseProperties::VELOCITY); if (basePitch != -1) break; } } } Segment *segment = getCurrentSegment(); if (!segment) return; timeT absTime = getSelection()->getStartTime(); timeT duration = getSelection()->getTotalDuration(); Note note(Note::getNearestNote(duration)); Track *track = segment->getComposition()->getTrackById(segment->getTrack()); QString name; int barNo = segment->getComposition()->getBarNumber(absTime); if (track) { name = QString(tr("Ornament track %1 bar %2").arg(track->getPosition() + 1).arg(barNo + 1)); } else { name = QString(tr("Ornament bar %1").arg(barNo + 1)); } MakeOrnamentDialog dialog(this, name, basePitch); if (dialog.exec() != QDialog::Accepted) return ; name = dialog.getName(); basePitch = dialog.getBasePitch(); MacroCommand *command = new MacroCommand(tr("Make Ornament")); command->addCommand(new CopyCommand (*getSelection(), getDocument()->getClipboard())); command->addCommand(new CutCommand (*getSelection(), 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)); CommandHistory::getInstance()->addCommand(command); } void NotationView::slotUseOrnament() { // Take an existing note and match an ornament to it. if (!getSelection()) return ; UseOrnamentDialog dialog(this, &getDocument()->getComposition()); if (dialog.exec() != QDialog::Accepted) return ; CommandHistory::getInstance()->addCommand( new SetTriggerCommand(*getSelection(), dialog.getId(), true, dialog.getRetune(), dialog.getTimeAdjust(), dialog.getMark(), tr("Use Ornament"))); } void NotationView::slotRemoveOrnament() { if (!getSelection()) return ; CommandHistory::getInstance()->addCommand( new ClearTriggersCommand(*getSelection(), tr("Remove Ornaments"))); } void NotationView::slotEditAddClef() { Segment *segment = getCurrentSegment(); timeT insertionTime = getInsertionTime(); static Clef lastClef = segment->getClefAtTime(insertionTime); NotationScene *scene = m_notationWidget->getScene(); if (!scene) return; // Fix bug #2997311 : don't use a NotePixmapFactory in selection mode // to draw inside the dialog NotePixmapFactory npf = *scene->getNotePixmapFactory(); npf.setSelected(false); ClefDialog dialog(this, &npf, lastClef); if (dialog.exec() == QDialog::Accepted) { ClefDialog::ConversionType conversion = dialog.getConversionType(); bool shouldChangeOctave = (conversion != ClefDialog::NoConversion); bool shouldTranspose = (conversion == ClefDialog::Transpose); CommandHistory::getInstance()->addCommand( new ClefInsertionCommand(*segment, insertionTime, dialog.getClef(), shouldChangeOctave, shouldTranspose)); lastClef = dialog.getClef(); } } void NotationView::slotEditAddKeySignature() { Segment *segment = getCurrentSegment(); timeT insertionTime = getInsertionTime(); Clef clef = segment->getClefAtTime(insertionTime); Key key = segment->getKeyAtTime(insertionTime); //!!! experimental: CompositionTimeSliceAdapter adapter (&getDocument()->getComposition(), insertionTime, getDocument()->getComposition().getDuration()); AnalysisHelper helper; key = helper.guessKey(adapter); NotationScene *scene = m_notationWidget->getScene(); if (!scene) return; // Fix bug #2997311 : don't use a NotePixmapFactory in selection mode // to draw inside the dialog NotePixmapFactory npf = *scene->getNotePixmapFactory(); npf.setSelected(false); KeySignatureDialog dialog(this, &npf, clef, key, true, true, tr("Estimated key signature shown")); if (dialog.exec() == QDialog::Accepted && dialog.isValid()) { KeySignatureDialog::ConversionType conversion = dialog.getConversionType(); bool transposeKey = dialog.shouldBeTransposed(); bool applyToAll = dialog.shouldApplyToAll(); bool ignorePercussion = dialog.shouldIgnorePercussion(); if (applyToAll) { CommandHistory::getInstance()->addCommand( new MultiKeyInsertionCommand( getDocument(), insertionTime, dialog.getKey(), conversion == KeySignatureDialog::Convert, conversion == KeySignatureDialog::Transpose, transposeKey, ignorePercussion)); } else { CommandHistory::getInstance()->addCommand( new KeyInsertionCommand(*segment, insertionTime, dialog.getKey(), conversion == KeySignatureDialog::Convert, conversion == KeySignatureDialog::Transpose, transposeKey, false)); } } } void NotationView::slotEditAddSustain(bool down) { Segment *segment = getCurrentSegment(); 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 (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()) == tr("Sustain"))) { CommandHistory::getInstance()->addCommand( new SustainInsertionCommand(*segment, insertionTime, down, i->getControllerValue())); return ; } } } else if (instrument->getDevice() && instrument->getDevice()->getType() == Device::SoftSynth) { CommandHistory::getInstance()->addCommand( new SustainInsertionCommand(*segment, insertionTime, down, 64)); } } } QMessageBox::warning(this, tr("Rosegarden"), tr("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 (size_t i = 0; i < m_segments.size(); i++) { CommandHistory::getInstance()->addCommand(new SegmentTransposeCommand( *(m_segments[i]), intervalDialog.getChangeKey(), steps, semitones, intervalDialog.getTransposeSegmentBack())); } // Fix #1885520 (Update track parameter widget when transpose changed from notation) RosegardenMainWindow::self()->getView()->getTrackParameterBox()->slotUpdateControls(-1); } void NotationView::slotEditSwitchPreset() { PresetHandlerDialog dialog(this, true); if (dialog.exec() != QDialog::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( qstrtostr(dialog.getName()) ); track->setClef(dialog.getClef()); track->setTranspose(dialog.getTranspose()); track->setLowestPlayable(dialog.getLowRange()); track->setHighestPlayable(dialog.getHighRange()); CommandHistory::getInstance()->addCommand(new SegmentSyncCommand( comp.getSegments(), selectedTrack, dialog.getTranspose(), dialog.getLowRange(), dialog.getHighRange(), clefIndexToClef(dialog.getClef()))); } else { CommandHistory::getInstance()->addCommand(new SegmentSyncCommand( m_segments, dialog.getTranspose(), dialog.getLowRange(), dialog.getHighRange(), clefIndexToClef(dialog.getClef()))); } m_doc->slotDocumentModified(); // Fix #1885520 (Update track parameter widget when preset changed from notation) RosegardenMainWindow::self()->getView()->getTrackParameterBox()->slotUpdateControls(-1); } void NotationView::slotToggleChordsRuler() { bool visible = findAction("show_chords_ruler")->isChecked(); m_notationWidget->setChordNameRulerVisible(visible); QSettings settings; settings.beginGroup(NotationViewConfigGroup); settings.setValue("Chords ruler shown", visible); settings.endGroup(); } void NotationView::slotToggleTempoRuler() { bool visible = findAction("show_tempo_ruler")->isChecked(); m_notationWidget->setTempoRulerVisible(visible); QSettings settings; settings.beginGroup(NotationViewConfigGroup); settings.setValue("Tempo ruler shown", visible); settings.endGroup(); } // start of code formerly located in EditView.cpp // -- void NotationView::slotAddTempo() { timeT insertionTime = getInsertionTime(); TempoDialog tempoDlg(this, getDocument()); connect(&tempoDlg, SIGNAL(changeTempo(timeT, tempoT, tempoT, TempoDialog::TempoDialogAction)), this, SIGNAL(changeTempo(timeT, tempoT, tempoT, TempoDialog::TempoDialogAction))); tempoDlg.setTempoPosition(insertionTime); tempoDlg.exec(); } void NotationView::slotAddTimeSignature() { Segment *segment = getCurrentSegment(); if (!segment) return ; Composition *composition = segment->getComposition(); timeT insertionTime = getInsertionTime(); TimeSignatureDialog *dialog = 0; int timeSigNo = composition->getTimeSignatureNumberAt(insertionTime); if (timeSigNo >= 0) { dialog = new TimeSignatureDialog (this, composition, insertionTime, composition->getTimeSignatureAt(insertionTime)); } else { timeT endTime = composition->getDuration(); if (composition->getTimeSignatureCount() > 0) { endTime = composition->getTimeSignatureChange(0).first; } CompositionTimeSliceAdapter adapter (composition, insertionTime, endTime); AnalysisHelper helper; TimeSignature timeSig = helper.guessTimeSignature(adapter); dialog = new TimeSignatureDialog (this, composition, insertionTime, timeSig, false, tr("Estimated time signature shown")); } if (dialog->exec() == QDialog::Accepted) { insertionTime = dialog->getTime(); if (dialog->shouldNormalizeRests()) { CommandHistory::getInstance()->addCommand(new AddTimeSignatureAndNormalizeCommand (composition, insertionTime, dialog->getTimeSignature())); } else { CommandHistory::getInstance()->addCommand(new AddTimeSignatureCommand (composition, insertionTime, dialog->getTimeSignature())); } } delete dialog; } void NotationView::slotToggleRawNoteRuler() { bool visible = findAction("show_raw_note_ruler")->isChecked(); m_notationWidget->setRawNoteRulerVisible(visible); QSettings settings; settings.beginGroup(NotationViewConfigGroup); settings.setValue("Raw note ruler shown", visible); settings.endGroup(); } void NotationView::slotToggleTracking() { if (m_notationWidget) m_notationWidget->slotTogglePlayTracking(); } void NotationView::slotSegmentDeleted(Segment *s) { NOTATION_DEBUG << "NotationView::slotSegmentDeleted: " << s << endl; // remove from vector for (std::vector::iterator i = m_segments.begin(); i != m_segments.end(); ++i) { if (*i == s) { m_segments.erase(i); NOTATION_DEBUG << "NotationView::slotSegmentDeleted: Erased segment from vector, have " << m_segments.size() << " segment(s) remaining" << endl; // Fix bug #2960243: // When a segment is deleted : remove the selection rect NotationTool * tool = m_notationWidget->getCurrentTool(); if (tool) tool->stow(); // and regenerate the whole notation widget . m_notationWidget->setSegments(m_document, m_segments); return; } } } void NotationView::slotSceneDeleted() { NOTATION_DEBUG << "NotationView::slotSceneDeleted" << endl; m_segments.clear(); close(); } void NotationView::slotUpdateWindowTitle(bool m) { QString indicator = (m ? "*" : ""); if (m_segments.empty()) return; 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; setWindowTitle(tr("%1%2 - Segment Track #%3 - Notation") .arg(indicator) .arg(getDocument()->getTitle()) .arg(trackPosition + 1)); } else if (m_segments.size() == getDocument()->getComposition().getNbSegments()) { setWindowTitle(tr("%1%2 - All Segments - Notation") .arg(indicator) .arg(getDocument()->getTitle())); } else { setWindowTitle(tr("%1%2 - %n Segment(s) - Notation", "", m_segments.size()) .arg(indicator) .arg(getDocument()->getTitle())); } } 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; EventSelection *selection = getSelection(); if (selection) { t = selection->getStartTime(); timeT duration = selection->getTotalDuration(); Note::Type unitType = Note::getNearestNote(duration / 3, 0) .getNoteType(); unit = Note(unitType).getDuration(); if (!simple) { TupletDialog dialog(this, unitType, duration); if (dialog.exec() != QDialog::Accepted) return ; unit = Note(dialog.getUnitType()).getDuration(); tupled = dialog.getTupledCount(); untupled = dialog.getUntupledCount(); hasTimingAlready = dialog.hasTimingAlready(); } segment = &selection->getSegment(); } else { t = getInsertionTime(); NoteRestInserter *currentInserter = dynamic_cast (m_notationWidget->getCurrentTool()); Note::Type unitType; // Should fix this too (maybe go fetch the NoteRestTool and check its duration). if (currentInserter) { unitType = currentInserter->getCurrentNote().getNoteType(); } else { unitType = Note::Quaver; } unit = Note(unitType).getDuration(); if (!simple) { TupletDialog dialog(this, unitType); if (dialog.exec() != QDialog::Accepted) return ; unit = Note(dialog.getUnitType()).getDuration(); tupled = dialog.getTupledCount(); untupled = dialog.getUntupledCount(); hasTimingAlready = dialog.hasTimingAlready(); } segment = getCurrentSegment(); } CommandHistory::getInstance()->addCommand(new TupletCommand (*segment, t, unit, untupled, tupled, hasTimingAlready)); if (!hasTimingAlready) { // slotSetInsertCursorPosition(t + (unit * tupled), true, false); m_document->slotSetPointerPosition(t + (unit * tupled)); } } void NotationView::slotUpdateInsertModeStatusTriplet() { if (isInTripletMode()) { m_notationWidget->setTupletMode(true); m_notationWidget->setTupledCount(); m_notationWidget->setUntupledCount(); (findAction("tuplet_mode"))->setChecked(false); } else m_notationWidget->setTupletMode(false); slotUpdateInsertModeStatus(); } void NotationView::slotUpdateInsertModeStatusTuplet() { if (isInTupletMode()) { m_notationWidget->setTupletMode(true); InsertTupletDialog dialog(this, m_notationWidget->getUntupledCount(), m_notationWidget->getTupledCount()); if (dialog.exec() == QDialog::Accepted) { m_notationWidget->setTupledCount(dialog.getTupledCount()); m_notationWidget->setUntupledCount(dialog.getUntupledCount()); } (findAction("triplet_mode"))->setChecked(false); } else m_notationWidget->setTupletMode(false); slotUpdateInsertModeStatus(); } void NotationView::slotUpdateInsertModeStatus() { QString tripletMessage = tr("Tuplet"); QString chordMessage = tr("Chord"); QString graceMessage = tr("Grace"); QString message; m_notationWidget->setChordMode(isInChordMode()); m_notationWidget->setGraceMode(isInGraceMode()); if (isInTripletMode()||isInTupletMode()) { message = tr("%1 %2").arg(message).arg(tripletMessage); } if (isInChordMode()) { message = tr("%1 %2").arg(message).arg(chordMessage); } if (isInGraceMode()) { message = tr("%1 %2").arg(message).arg(graceMessage); } m_insertModeLabel->setText(message); } bool NotationView::isInChordMode() { QAction* tac = findAction("chord_mode"); return tac->isChecked(); } bool NotationView::isInTripletMode() { QAction* tac = findAction("triplet_mode"); return tac->isChecked(); } bool NotationView::isInTupletMode() { QAction* tac = findAction("tuplet_mode"); return tac->isChecked(); } bool NotationView::isInGraceMode() { QAction* tac = findAction("grace_mode"); return tac->isChecked(); } void NotationView::slotSymbolAction() { QObject *s = sender(); setCurrentNotePixmapFrom(dynamic_cast(s)); QString n = s->objectName(); Symbol type = Symbol::Segno; if (n == "add_segno") type = Symbol::Segno; else if (n == "add_coda") type = Symbol::Coda; else if (n == "add_breath") type = Symbol::Breath; if (!m_notationWidget) return; m_notationWidget->slotSetSymbolInserter(); m_notationWidget->slotSetInsertedSymbol(type); slotUpdateMenuStates(); } void NotationView::slotHalveDurations() { if (!getSelection()) return ; CommandHistory::getInstance()->addCommand(new RescaleCommand(*getSelection(), getSelection()->getTotalDuration() / 2, false)); } void NotationView::slotDoubleDurations() { if (!getSelection()) return ; CommandHistory::getInstance()->addCommand(new RescaleCommand(*getSelection(), getSelection()->getTotalDuration() * 2, false)); } void NotationView::slotRescale() { if (!getSelection()) return ; RescaleDialog dialog (this, &getDocument()->getComposition(), getSelection()->getStartTime(), getSelection()->getEndTime() - getSelection()->getStartTime(), 1, true, true); if (dialog.exec() == QDialog::Accepted) { CommandHistory::getInstance()->addCommand(new RescaleCommand (*getSelection(), dialog.getNewDuration(), dialog.shouldCloseGap())); } } void NotationView::slotTransposeUp() { if (!getSelection()) return ; CommandHistory::getInstance()->addCommand(new TransposeCommand (1, *getSelection())); } void NotationView::slotTransposeDown() { if (!getSelection()) return ; CommandHistory::getInstance()->addCommand(new TransposeCommand ( -1, *getSelection())); } void NotationView::slotTransposeUpOctave() { if (!getSelection()) return ; CommandHistory::getInstance()->addCommand(new TransposeCommand (12, *getSelection())); } void NotationView::slotTransposeDownOctave() { if (!getSelection()) return ; CommandHistory::getInstance()->addCommand(new TransposeCommand ( -12, *getSelection())); } void NotationView::slotTranspose() { EventSelection *selection = getSelection(); if (!selection) std::cout << "Hint: selection is NULL in slotTranpose() " << std::endl; if (!selection) return; QSettings settings; settings.beginGroup(NotationViewConfigGroup); int dialogDefault = settings.value("lasttransposition", 0).toInt() ; bool ok = false; int semitones = QInputDialog::getInteger (tr("Transpose"), tr("By number of semitones: "), dialogDefault, -127, 127, 1, &ok, this); if (!ok || semitones == 0) return; settings.setValue("lasttransposition", semitones); CommandHistory::getInstance()->addCommand(new TransposeCommand (semitones, *selection)); settings.endGroup(); } void NotationView::slotDiatonicTranspose() { if (!getSelection()) return ; QSettings settings; settings.beginGroup(NotationViewConfigGroup); IntervalDialog intervalDialog(this); int ok = intervalDialog.exec(); //int dialogDefault = settings.value("lasttransposition", 0).toInt() ; int semitones = intervalDialog.getChromaticDistance(); int steps = intervalDialog.getDiatonicDistance(); settings.endGroup(); if (!ok || (semitones == 0 && steps == 0)) return; if (intervalDialog.getChangeKey()) { std::cout << "Transposing changing keys is not currently supported on selections" << std::endl; } else { // Transpose within key //std::cout << "Transposing semitones, steps: " << semitones << ", " << steps << std::endl; CommandHistory::getInstance()->addCommand(new TransposeCommand (semitones, steps, *getSelection())); } } void NotationView::slotInvert() { if (!getSelection()) return; int semitones = 0; CommandHistory::getInstance()->addCommand(new InvertCommand (semitones, *getSelection())); } void NotationView::slotRetrograde() { if (!getSelection()) return; int semitones = 0; CommandHistory::getInstance()->addCommand(new RetrogradeCommand (semitones, *getSelection())); } void NotationView::slotRetrogradeInvert() { if (!getSelection()) return; int semitones = 0; CommandHistory::getInstance()->addCommand(new RetrogradeInvertCommand (semitones, *getSelection())); } void NotationView::slotJogLeft() { EventSelection *selection = getSelection(); if (!selection) return ; RG_DEBUG << "NotationView::slotJogLeft" << endl; bool useNotationTimings = true; CommandHistory::getInstance()->addCommand(new MoveCommand (*getCurrentSegment(), -Note(Note::Demisemiquaver).getDuration(), useNotationTimings, *selection)); } void NotationView::slotJogRight() { EventSelection *selection = getSelection(); if (!selection) return ; RG_DEBUG << "NotationView::slotJogRight"<< endl; bool useNotationTimings = true; CommandHistory::getInstance()->addCommand(new MoveCommand (*getCurrentSegment(), Note(Note::Demisemiquaver).getDuration(), useNotationTimings, *selection)); } void NotationView::slotStepBackward() { Segment *segment = getCurrentSegment(); if (!segment) return; timeT time = getInsertionTime(); Segment::iterator i = segment->findTime(time); while (i != segment->begin() && (i == segment->end() || (*i)->getNotationAbsoluteTime() >= time)){ --i; } if (i != segment->end()){ m_document->slotSetPointerPosition((*i)->getNotationAbsoluteTime()); } } void NotationView::slotStepForward() { Segment *segment = getCurrentSegment(); if (!segment) return; timeT time = getInsertionTime(); Segment::iterator i = segment->findTime(time); while (i != segment->end() && (*i)->getNotationAbsoluteTime() <= time) ++i; if (i == segment->end()){ m_document->slotSetPointerPosition(segment->getEndMarkerTime()); } else { m_document->slotSetPointerPosition((*i)->getNotationAbsoluteTime()); } } 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 //!!! shut up compiler warning about unused 'velocity' but left original intact // because it would be a good thing to make use of velocity one day //NotationView::slotInsertableNoteEventReceived(int pitch, int velocity, bool noteOn) NotationView::slotInsertableNoteEventReceived(int pitch, int velocity, bool noteOn) { // NOTE: these next comments are from before 1.0, and that should be // understood when considering them in relation to Thorn // //!!! 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? /* was toggle */ // QAction *action = dynamic_cast // (actionCollection()->action("toggle_step_by_step")); QAction *action = findAction("toggle_step_by_step"); if (!action) { NOTATION_DEBUG << "WARNING: No toggle_step_by_step action" << endl; return ; } if (!action->isChecked()) return ; Segment *segment = getCurrentSegment(); NoteRestInserter *noteInserter = dynamic_cast (m_notationWidget->getCurrentTool()); if (!noteInserter) { static bool showingError = false; if (showingError) return ; showingError = true; QMessageBox::warning(this, tr("Rosegarden"), tr("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(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(); // TmpStatusMsg msg(tr("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, velocity, 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, velocity, true); } } } void NotationView::slotEditLyrics() { Segment *segment = getCurrentSegment(); int oldVerseCount = 1; // The loop below is identical with the one in LyricEditDialog::countVerses() // Maybe countVerses() should be moved to a Segment manipulating class ? (hjj) for (Segment::iterator i = segment->begin(); segment->isBeforeEndMarker(i); ++i) { if ((*i)->isa(Text::EventType)) { std::string textType; if ((*i)->get(Text::TextTypePropertyName, textType) && textType == Text::Lyric) { long verse = 0; (*i)->get(Text::LyricVersePropertyName, verse); if (verse >= oldVerseCount) oldVerseCount = verse + 1; } } } LyricEditDialog dialog(this, segment); if (dialog.exec() == QDialog::Accepted) { MacroCommand *macro = new MacroCommand (SetLyricsCommand::getGlobalName()); for (int i = 0; i < dialog.getVerseCount(); ++i) { SetLyricsCommand *command = new SetLyricsCommand (segment, i, dialog.getLyricData(i)); macro->addCommand(command); } for (int i = dialog.getVerseCount(); i < oldVerseCount; ++i) { // (hjj) verse count decreased, delete extra verses. SetLyricsCommand *command = new SetLyricsCommand (segment, i, QString("")); macro->addCommand(command); } CommandHistory::getInstance()->addCommand(macro); } } void NotationView::slotHoveredOverNoteChanged(const QString ¬eName) { m_hoveredOverNoteName->setText(QString(" ") + 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); // QString message; // QString format("%ld (%ld.%03lds)"); // format = tr("Time: %1").arg(format); // message.sprintf(format, t, rt.sec, ms); QString message = tr("Time: %1 (%2.%3s)") .arg(QString("%1-%2-%3-%4") .arg(QString("%1").arg(bar + 1).rightJustified(3, '0')) .arg(QString("%1").arg(beat).rightJustified(2, '0')) .arg(QString("%1").arg(fraction).rightJustified(2, '0')) .arg(QString("%1").arg(remainder).rightJustified(2, '0'))) .arg(rt.sec) .arg(QString("%1").arg(ms).rightJustified(3, '0')); m_hoveredOverAbsoluteTime->setText(message); } void NotationView::slotFontComboChanged(int index) { QString name = m_availableFontNames[index]; if (m_notationWidget) m_notationWidget->slotSetFontName(name); m_fontName = name; QString action = QString("note_font_%1").arg(name); findAction(action)->setChecked(true); } void NotationView::slotSizeComboChanged(int index) { int size = m_availableFontSizes[index]; if (m_notationWidget) m_notationWidget->slotSetFontSize(size); m_fontSize = size; QString action = QString("note_font_size_%1").arg(size); findAction(action)->setChecked(true); } void NotationView::slotSpacingComboChanged(int index) { int spacing = m_availableSpacings[index]; if (m_notationWidget) m_notationWidget->getScene()->setHSpacing(spacing); m_spacing = spacing; QString action = QString("spacing_%1").arg(spacing); findAction(action)->setChecked(true); } void NotationView::slotToggleVelocityRuler() { m_notationWidget->slotToggleVelocityRuler(); } void NotationView::slotTogglePitchbendRuler() { m_notationWidget->slotTogglePitchbendRuler(); } void NotationView::slotAddControlRuler(QAction *action) { m_notationWidget->slotAddControlRuler(action); } Device * NotationView::getCurrentDevice() { if (m_notationWidget) return m_notationWidget->getCurrentDevice(); else return 0; } void NotationView::slotHelp() { // TRANSLATORS: if the manual is translated into your language, you can // change the two-letter language code in this URL to point to your language // version, eg. "http://rosegardenmusic.com/wiki/doc:manual-es" for the // Spanish version. If your language doesn't yet have a translation, feel // free to create one. QString helpURL = tr("http://rosegardenmusic.com/wiki/doc:notation-en"); QDesktopServices::openUrl(QUrl(helpURL)); } void NotationView::slotTutorial() { QString tutorialURL = tr("http://www.rosegardenmusic.com/tutorials/en/chapter-0.html"); QDesktopServices::openUrl(QUrl(tutorialURL)); } void NotationView::slotBugGuidelines() { QString glURL = tr("http://rosegarden.sourceforge.net/tutorial/bug-guidelines.html"); QDesktopServices::openUrl(QUrl(glURL)); } void NotationView::slotHelpAbout() { new AboutDialog(this); } void NotationView::slotHelpAboutQt() { QMessageBox::aboutQt(this, tr("Rosegarden")); } void NotationView::slotDonate() { QString url("https://sourceforge.net/project/project_donations.php?group_id=4932"); QDesktopServices::openUrl(QUrl(url)); } void NotationView::slotToggleStepByStep() { QAction *action = findAction("toggle_step_by_step"); if (!action) { MATRIX_DEBUG << "WARNING: No toggle_step_by_step action" << endl; return ; } if (action->isChecked()) { emit stepByStepTargetRequested(this); } else { emit stepByStepTargetRequested(0); } } void NotationView::slotStepByStepTargetRequested(QObject *obj) { QAction *action = findAction("toggle_step_by_step"); if (!action) { MATRIX_DEBUG << "WARNING: No toggle_step_by_step action" << endl; return ; } action->setChecked(obj == this); } void NotationView::slotMoveEventsUpStaff() { EventSelection *selection = getSelection(); if (!selection) return; NotationScene *scene = m_notationWidget->getScene(); if (!scene) return; NotationStaff *target_staff = scene->getStaffAbove(); if (!target_staff) return; Segment *segment = &target_staff->getSegment(); MacroCommand *command = new MacroCommand(tr("Move Events to Staff Above")); timeT insertionTime = selection->getStartTime(); Clipboard *c = new Clipboard; CopyCommand *cc = new CopyCommand(*selection, c); cc->execute(); command->addCommand(new EraseCommand(*selection)); command->addCommand(new PasteEventsCommand (*segment, c, insertionTime, PasteEventsCommand::NoteOverlay)); CommandHistory::getInstance()->addCommand(command); delete c; } void NotationView::slotMoveEventsDownStaff() { EventSelection *selection = getSelection(); if (!selection) return; NotationScene *scene = m_notationWidget->getScene(); if (!scene) return; NotationStaff *target_staff = scene->getStaffBelow(); if (!target_staff) return; Segment *segment = &target_staff->getSegment(); MacroCommand *command = new MacroCommand(tr("Move Events to Staff Below")); timeT insertionTime = selection->getStartTime(); Clipboard *c = new Clipboard; CopyCommand *cc = new CopyCommand(*selection, c); cc->execute(); command->addCommand(new EraseCommand(*selection)); command->addCommand(new PasteEventsCommand (*segment, c, insertionTime, PasteEventsCommand::NoteOverlay)); CommandHistory::getInstance()->addCommand(command); delete c; } void NotationView::slotEditElement(NotationStaff *staff, NotationElement *element, bool advanced) { NOTATION_DEBUG << "NotationView::slotEditElement()" << endl; NotationScene *scene = m_notationWidget->getScene(); if (!scene) return; NotePixmapFactory *npf = scene->getNotePixmapFactory(); 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()); CommandHistory::getInstance()->addCommand(command); } } else if (element->event()->isa(Clef::EventType)) { try { ClefDialog dialog(this, npf, Clef(*element->event())); if (dialog.exec() == QDialog::Accepted) { ClefDialog::ConversionType conversion = dialog.getConversionType(); bool shouldChangeOctave = (conversion != ClefDialog::NoConversion); bool shouldTranspose = (conversion == ClefDialog::Transpose); CommandHistory::getInstance()->addCommand (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, npf, clef, Rosegarden::Key(*element->event()), false, true); if (dialog.exec() == QDialog::Accepted && dialog.isValid()) { KeySignatureDialog::ConversionType conversion = dialog.getConversionType(); CommandHistory::getInstance()->addCommand (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, npf, Text(*element->event())); if (dialog.exec() == QDialog::Accepted) { TextInsertionCommand *command = new TextInsertionCommand (staff->getSegment(), element->event()->getAbsoluteTime(), dialog.getText()); MacroCommand *macroCommand = new MacroCommand(tr("Edit Text Event")); macroCommand->addCommand(new EraseEventCommand(staff->getSegment(), element->event(), false)); macroCommand->addCommand(command); CommandHistory::getInstance()->addCommand(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 (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()); CommandHistory::getInstance()->addCommand(command); } } } void NotationView::slotTransformsNormalizeRests() { EventSelection *selection = m_notationWidget->getSelection(); if (!selection) return ; TmpStatusMsg msg(tr("Normalizing rests..."), this); CommandHistory::getInstance()-> addCommand(new NormalizeRestsCommand(*selection)); } void NotationView::slotTransformsCollapseNotes() { EventSelection *selection = m_notationWidget->getSelection(); if (!selection) return ; TmpStatusMsg msg(tr("Collapsing notes..."), this); CommandHistory::getInstance()-> addCommand(new CollapseNotesCommand(*selection)); } void NotationView::slotExtendSelectionBackward() { slotExtendSelectionBackward(false); } void NotationView::slotExtendSelectionBackwardBar() { slotExtendSelectionBackward(true); } void NotationView::slotExtendSelectionBackward(bool bar) { // If there is no current selection, or the selection is entirely // to the right of the cursor, move the cursor left and add to the // selection timeT oldTime = getInsertionTime(); if (bar) emit rewindPlayback(); else slotStepBackward(); timeT newTime = getInsertionTime(); Segment *segment = getCurrentSegment(); if (!segment) return; NotationStaff *currentStaff = m_notationWidget->getScene()->getCurrentStaff(); if (!currentStaff) return; // ho ho, there is no NotationViewSegment whatever because a NotationStaff // is a subclass of ViewSegment ViewSegment *vs = dynamic_cast(currentStaff); ViewElementList *vel = vs->getViewElementList(); EventSelection *s = getSelection(); EventSelection *es = new EventSelection(*segment); if (s && &s->getSegment() == segment) es->addFromSelection(s); if (!s || &s->getSegment() != segment || s->getSegmentEvents().size() == 0 || s->getStartTime() >= oldTime) { ViewElementList::iterator extendFrom = vel->findTime(oldTime); while (extendFrom != vel->begin() && (*--extendFrom)->getViewAbsoluteTime() >= newTime) { //!!! This should actually grab every sort of event, and not just // notes, but making that change makes the selection die every time // the endpoint of an indication is encountered, and I'm just not // seeing why, so I'm giving up on that and leaving it in the same // stupid state I found it in (and it's probably in this state // because the last guy had the same problem with indications.) // // I don't like this, because it makes it very easy to go along and // orphan indications, text events, controllers, and all sorts of // whatnot. However, I have to call it quits for today, and have no // idea if I'll ever remember to come back to this, so I'm leaving a // reminder to someone that all of this is stupid. if ((*extendFrom)->event()->isa(Note::EventType)) { es->addEvent((*extendFrom)->event()); } } } else { // remove an event EventSelection::eventcontainer::iterator i = es->getSegmentEvents().end(); std::vector toErase; while (i != es->getSegmentEvents().begin() && (*--i)->getAbsoluteTime() >= newTime) { toErase.push_back(*i); } for (unsigned int j = 0; j < toErase.size(); ++j) { es->removeEvent(toErase[j]); } } setSelection(es, true); } void NotationView::slotExtendSelectionForward() { slotExtendSelectionForward(false); } void NotationView::slotExtendSelectionForwardBar() { slotExtendSelectionForward(true); } void NotationView::slotExtendSelectionForward(bool bar) { // If there is no current selection, or the selection is entirely // to the right of the cursor, move the cursor left and add to the // selection timeT oldTime = getInsertionTime(); if (bar) emit fastForwardPlayback(); else slotStepForward(); timeT newTime = getInsertionTime(); Segment *segment = getCurrentSegment(); if (!segment) return; NotationStaff *currentStaff = m_notationWidget->getScene()->getCurrentStaff(); if (!currentStaff) return; // ho ho, there is no NotationViewSegment whatever because a NotationStaff // is a subclass of ViewSegment ViewSegment *vs = dynamic_cast(currentStaff); ViewElementList *vel = vs->getViewElementList(); EventSelection *s = getSelection(); EventSelection *es = new EventSelection(*segment); if (s && &s->getSegment() == segment) es->addFromSelection(s); if (!s || &s->getSegment() != segment || s->getSegmentEvents().size() == 0 || s->getEndTime() <= oldTime) { ViewElementList::iterator extendFrom = vel->findTime(oldTime); while (extendFrom != vel->end() && (*extendFrom)->getViewAbsoluteTime() < newTime) { if ((*extendFrom)->event()->isa(Note::EventType)) { es->addEvent((*extendFrom)->event()); } ++extendFrom; } } else { // remove an event EventSelection::eventcontainer::iterator i = es->getSegmentEvents().begin(); std::vector toErase; while (i != es->getSegmentEvents().end() && (*i)->getAbsoluteTime() < newTime) { toErase.push_back(*i); ++i; } for (unsigned int j = 0; j < toErase.size(); ++j) { es->removeEvent(toErase[j]); } } setSelection(es, true); } void NotationView::slotAddDot() { EventSelection *selection = getSelection(); if (!selection) return; TmpStatusMsg msg(tr("Adding dot..."), this); CommandHistory::getInstance()->addCommand (new AddDotCommand(*selection, false)); } void NotationView::slotAddDotNotationOnly() { EventSelection *selection = getSelection(); if (!selection) return; TmpStatusMsg msg(tr("Adding dot..."), this); CommandHistory::getInstance()->addCommand (new AddDotCommand(*selection, true)); } void NotationView::slotSetNoteType() { QObject *s = sender(); QString name = s->objectName(); int note=Note::WholeNote; EventSelection *selection = getSelection(); if (!selection) return; TmpStatusMsg msg(tr("Set Note Type..."), this); if (name == "set_note_type_doublewhole") note=Note::DoubleWholeNote; else if (name == "set_note_type_whole") note=Note::WholeNote; else if (name == "set_note_type_half") note=Note::HalfNote; else if (name == "set_note_type_quarter") note=Note::QuarterNote; else if (name == "set_note_type_eighth") note=Note::EighthNote; else if (name == "set_note_type_sixteenth") note=Note::SixteenthNote; else if (name == "set_note_type_thirtysecond") note=Note::ThirtySecondNote; else if (name == "set_note_type_sixtyfourth") note=Note::SixtyFourthNote; CommandHistory::getInstance()->addCommand (new SetNoteTypeCommand(*selection, note, false)); } void NotationView::slotSetNoteTypeNotationOnly() { QObject *s = sender(); QString name = s->objectName(); int note=Note::WholeNote; EventSelection *selection = getSelection(); if (!selection) return; TmpStatusMsg msg(tr("Set Note Type notation only..."), this); if (name == "set_note_type_notation_doublewhole") note=Note::DoubleWholeNote; else if (name == "set_note_type_notation_whole") note=Note::WholeNote; else if (name == "set_note_type_notation_half") note=Note::HalfNote; else if (name == "set_note_type_notation_quarter") note=Note::QuarterNote; else if (name == "set_note_type_notation_eighth") note=Note::EighthNote; else if (name == "set_note_type_notation_sixteenth") note=Note::SixteenthNote; else if (name == "set_note_type_notation_thirtysecond") note=Note::ThirtySecondNote; else if (name == "set_note_type_notation_sixtyfourth") note=Note::SixtyFourthNote; CommandHistory::getInstance()->addCommand (new SetNoteTypeCommand(*selection, note, true)); } void NotationView::slotCycleSlashes() { EventSelection *selection = getSelection(); if (!selection) return; TmpStatusMsg msg(tr("Cycling slashes..."), this); CommandHistory::getInstance()->addCommand(new CycleSlashesCommand(*selection)); } void NotationView::slotAddLayer() { // switch to the pencil, as we are about to create an empty segment for // editing // //!!! This also detours around at least three related but distinct crashes // in NotationSelector, although I do not fully fathom why this is so, and am // worried about memory leaks or other obnoxious gotchas waiting in the // wings. slotSetNoteRestInserter(); AddLayerCommand *command = new AddLayerCommand(getCurrentSegment(), getDocument()->getComposition()); CommandHistory::getInstance()->addCommand(command); // get the pointer to the segment we just created and add it to m_segments m_segments.push_back(command->getSegment()); // re-invoke setSegments with the ammended m_segments m_notationWidget->setSegments(m_doc, m_segments); // try to make the new segment active immediately slotCurrentSegmentNext(); // Undoing this goes kaboom bigtime. What to do about that? Make the // command's undo emit a signal or something? The notation widget needs to // pick up the change and reboot itself again on the smaller set of // segments, or at least close gracefully instead of crashing, the way it // does when you undo the creation of a segment that was displayed in this // view. // // I suppose it would be most ideal to have some mechanism in place whereby // undoing segment creation in general triggered successive calls to // setSegments() until there was only one segment left, and then we'd blink // out of existence only after undoing that final one in a multi-segment // context. } void NotationView::setRewFFwdToAutoRepeat() { // This one didn't work in Classic either. Looking at it as a fresh // problem, it was tricky. The QAction has an objectName() of "rewind" // but the QToolButton associated with that action has no object name at // all. We kind of have to go around our ass to get to our elbow on // this one. // get pointers to the actual actions QAction *rewAction = findAction("playback_pointer_back_bar"); // rewind QAction *ffwAction = findAction("playback_pointer_forward_bar"); // fast forward QAction *cbkAction = findAction("cursor_back"); // <<< QAction *cfwAction = findAction("cursor_forward"); // >>> QWidget* transportToolbar = this->findToolbar("Transport Toolbar"); if (transportToolbar) { // get a list of all the toolbar's children (presumably they're // QToolButtons, but use this kind of thing with caution on customized // QToolBars!) QList widgets = transportToolbar->findChildren(); // iterate through the entire list of children for (QList::iterator i = widgets.begin(); i != widgets.end(); ++i) { // get a pointer to the button's default action QAction *act = (*i)->defaultAction(); // compare pointers, if they match, we've found the button // associated with that action // // we then have to not only setAutoRepeat() on it, but also connect // it up differently from what it got in createAction(), as // determined empirically (bleargh!!) if (act == rewAction) { connect((*i), SIGNAL(clicked()), this, SIGNAL(rewindPlayback())); } else if (act == ffwAction) { connect((*i), SIGNAL(clicked()), this, SIGNAL(fastForwardPlayback())); } else if (act == cbkAction) { connect((*i), SIGNAL(clicked()), this, SIGNAL(stepBackward())); } else if (act == cfwAction) { connect((*i), SIGNAL(clicked()), this, SIGNAL(stepForward())); } else { continue; } // Must have found an button to update (*i)->removeAction(act); (*i)->setAutoRepeat(true); } } } void NotationView::slotConfigure() { ConfigureDialog *configDlg = new ConfigureDialog(getDocument(), this); configDlg->setNotationPage(); configDlg->show(); } void NotationView::slotCheckShowHeadersMenu(bool checked) { findAction("show_track_headers")->setChecked(checked); } } // end namespace Rosegarden #include "NotationView.moc"