File indexing completed on 2024-05-12 16:34:17

0001 /* This file is part of the KDE project
0002  * Copyright 2007 Marijn Kruisselbrink <mkruisselbrink@kde.org>
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Library General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2 of the License, or (at your option) any later version.
0008  *
0009  * This library is distributed in the hope that it will be useful,
0010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012  * Library General Public License for more details.
0013  *
0014  * You should have received a copy of the GNU Library General Public License
0015  * along with this library; see the file COPYING.LIB.  If not, write to
0016  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018  */
0019 
0020 #include "SimpleEntryTool.h"
0021 
0022 #include <QPainter>
0023 #include <QMenu>
0024 #include <QBuffer>
0025 #include <QXmlStreamWriter>
0026 #include <QXmlStreamReader>
0027 #include <QInputDialog>
0028 #include <QAction>
0029 #include <QFileDialog>
0030 #include <QUrl>
0031 
0032 #include <klocalizedstring.h>
0033 
0034 #include <KoIcon.h>
0035 #include <KoCanvasBase.h>
0036 #include <KoSelection.h>
0037 #include <KoShapeManager.h>
0038 #include <KoPointerEvent.h>
0039 #include <KoXmlReader.h>
0040 #include <KoXmlWriter.h>
0041 
0042 #include "MusicShape.h"
0043 #include "Renderer.h"
0044 #include "MusicCursor.h"
0045 #include "MusicDebug.h"
0046 
0047 #include "dialogs/SimpleEntryWidget.h"
0048 
0049 #include "actions/NoteEntryAction.h"
0050 #include "actions/AccidentalAction.h"
0051 #include "actions/EraserAction.h"
0052 #include "actions/DotsAction.h"
0053 #include "actions/SetClefAction.h"
0054 #include "actions/TimeSignatureAction.h"
0055 #include "actions/KeySignatureAction.h"
0056 #include "actions/RemoveBarAction.h"
0057 #include "actions/TiedNoteAction.h"
0058 #include "actions/SelectionAction.h"
0059 
0060 #include "commands/AddBarsCommand.h"
0061 #include "commands/CreateChordCommand.h"
0062 #include "commands/AddNoteCommand.h"
0063 
0064 #include "core/Sheet.h"
0065 #include "core/Part.h"
0066 #include "core/Staff.h"
0067 #include "core/Bar.h"
0068 #include "core/Voice.h"
0069 #include "core/VoiceBar.h"
0070 #include "core/Clef.h"
0071 #include "core/StaffSystem.h"
0072 #include "core/MusicXmlReader.h"
0073 #include "core/MusicXmlWriter.h"
0074 #include "core/KeySignature.h"
0075 #include "core/Note.h"
0076 
0077 #include <algorithm>
0078 
0079 using namespace MusicCore;
0080 
0081 SimpleEntryTool::SimpleEntryTool( KoCanvasBase* canvas )
0082     : KoToolBase( canvas ),
0083     m_musicshape(0),
0084     m_voice(0),
0085     m_selectionStart(-1),
0086     m_cursor(0)
0087 {
0088     QActionGroup* actionGroup = new QActionGroup(this);
0089     connect(actionGroup, SIGNAL(triggered(QAction*)), this, SLOT(activeActionChanged(QAction*)));
0090 
0091     QAction * importAction = new QAction(koIcon("document-import"), i18n("Import"), this);
0092     addAction("import", importAction);
0093     connect(importAction, SIGNAL(triggered()), this, SLOT(importSheet()));
0094 
0095     QAction * exportAction = new QAction(koIcon("document-export"), i18n("Export"), this);
0096     addAction("export", exportAction);
0097     connect(exportAction, SIGNAL(triggered()), this, SLOT(exportSheet()));
0098 
0099     QAction * addBars = new QAction(koIcon("list-add"), i18n("Add measures"), this);
0100     addAction("add_bars", addBars);
0101     connect(addBars, SIGNAL(triggered()), this, SLOT(addBars()));
0102 
0103     AbstractMusicAction* actionBreveNote = new NoteEntryAction(BreveNote, false, this);
0104     actionBreveNote->setShortcut(Qt::Key_9);
0105     addAction("note_breve", actionBreveNote);
0106     actionGroup->addAction(actionBreveNote);
0107 
0108     AbstractMusicAction* actionWholeNote = new NoteEntryAction(WholeNote, false, this);
0109     actionWholeNote->setShortcut(Qt::Key_8);
0110     addAction("note_whole", actionWholeNote);
0111     actionGroup->addAction(actionWholeNote);
0112 
0113     AbstractMusicAction* actionHalfNote = new NoteEntryAction(HalfNote, false, this);
0114     actionHalfNote->setShortcut(Qt::Key_7);
0115     addAction("note_half", actionHalfNote);
0116     actionGroup->addAction(actionHalfNote);
0117 
0118     AbstractMusicAction* actionQuarterNote = new NoteEntryAction(QuarterNote, false, this);
0119     actionQuarterNote->setShortcut(Qt::Key_6);
0120     addAction("note_quarter", actionQuarterNote);
0121     actionGroup->addAction(actionQuarterNote);
0122 
0123     AbstractMusicAction* actionNote8 = new NoteEntryAction(EighthNote, false, this);
0124     actionNote8->setShortcut(Qt::Key_5);
0125     addAction("note_eighth", actionNote8);
0126     actionGroup->addAction(actionNote8);
0127 
0128     AbstractMusicAction* actionNote16 = new NoteEntryAction(SixteenthNote, false, this);
0129     actionNote16->setShortcut(Qt::Key_4);
0130     addAction("note_16th", actionNote16);
0131     actionGroup->addAction(actionNote16);
0132 
0133     AbstractMusicAction* actionNote32 = new NoteEntryAction(ThirtySecondNote, false, this);
0134     actionNote32->setShortcut(Qt::Key_3);
0135     addAction("note_32nd", actionNote32);
0136     actionGroup->addAction(actionNote32);
0137 
0138     AbstractMusicAction* actionNote64 = new NoteEntryAction(SixtyFourthNote, false, this);
0139     actionNote64->setShortcut(Qt::Key_2);
0140     addAction("note_64th", actionNote64);
0141     actionGroup->addAction(actionNote64);
0142 
0143     AbstractMusicAction* actionNote128 = new NoteEntryAction(HundredTwentyEighthNote, false, this);
0144     actionNote128->setShortcut(Qt::Key_1);
0145     addAction("note_128th", actionNote128);
0146     actionGroup->addAction(actionNote128);
0147 
0148     AbstractMusicAction* actionBreveRest = new NoteEntryAction(BreveNote, true, this);
0149     addAction("rest_breve", actionBreveRest);
0150     actionGroup->addAction(actionBreveRest);
0151 
0152     AbstractMusicAction* actionWholeRest = new NoteEntryAction(WholeNote, true, this);
0153     addAction("rest_whole", actionWholeRest);
0154     actionGroup->addAction(actionWholeRest);
0155 
0156     AbstractMusicAction* actionHalfRest = new NoteEntryAction(HalfNote, true, this);
0157     addAction("rest_half", actionHalfRest);
0158     actionGroup->addAction(actionHalfRest);
0159 
0160     AbstractMusicAction* actionQuarterRest = new NoteEntryAction(QuarterNote, true, this);
0161     addAction("rest_quarter", actionQuarterRest);
0162     actionGroup->addAction(actionQuarterRest);
0163 
0164     AbstractMusicAction* actionRest8 = new NoteEntryAction(EighthNote, true, this);
0165     addAction("rest_eighth", actionRest8);
0166     actionGroup->addAction(actionRest8);
0167 
0168     AbstractMusicAction* actionRest16 = new NoteEntryAction(SixteenthNote, true, this);
0169     addAction("rest_16th", actionRest16);
0170     actionGroup->addAction(actionRest16);
0171 
0172     AbstractMusicAction* actionRest32 = new NoteEntryAction(ThirtySecondNote, true, this);
0173     addAction("rest_32nd", actionRest32);
0174     actionGroup->addAction(actionRest32);
0175 
0176     AbstractMusicAction* actionRest64 = new NoteEntryAction(SixtyFourthNote, true, this);
0177     addAction("rest_64th", actionRest64);
0178     actionGroup->addAction(actionRest64);
0179 
0180     AbstractMusicAction* actionRest128 = new NoteEntryAction(HundredTwentyEighthNote, true, this);
0181     addAction("rest_128th", actionRest128);
0182     actionGroup->addAction(actionRest128);
0183 
0184     AbstractMusicAction* action;
0185     action = new AccidentalAction(-2, this);
0186     addAction("accidental_doubleflat", action);
0187     actionGroup->addAction(action);
0188 
0189     action = new AccidentalAction(-1, this);
0190     addAction("accidental_flat", action);
0191     actionGroup->addAction(action);
0192 
0193     action = new AccidentalAction(0, this);
0194     addAction("accidental_natural", action);
0195     actionGroup->addAction(action);
0196 
0197     action = new AccidentalAction(1, this);
0198     addAction("accidental_sharp", action);
0199     actionGroup->addAction(action);
0200 
0201     action = new AccidentalAction(2, this);
0202     addAction("accidental_doublesharp", action);
0203     actionGroup->addAction(action);
0204 
0205     action = new EraserAction(this);
0206     addAction("eraser", action);
0207     actionGroup->addAction(action);
0208 
0209     action = new DotsAction(this);
0210     addAction("dots", action);
0211     actionGroup->addAction(action);
0212     
0213     action = new TiedNoteAction(this);
0214     addAction("tiednote", action);
0215     actionGroup->addAction(action);
0216 
0217     action = new SelectionAction(this);
0218     addAction("select", action);
0219     actionGroup->addAction(action);
0220     
0221     actionQuarterNote->setChecked(true);
0222     m_activeAction = actionQuarterNote;
0223 
0224     QMenu* clefMenu = new QMenu();
0225     clefMenu->addAction(action = new SetClefAction(Clef::Trebble, 2, 0, this));
0226     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0227     clefMenu->addAction(action = new SetClefAction(Clef::Bass, 4, 0, this));
0228     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0229     clefMenu->addAction(action = new SetClefAction(Clef::Alto, 3, 0, this));
0230     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0231     clefMenu->addAction(action = new SetClefAction(Clef::Tenor, 4, 0, this));
0232     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0233     clefMenu->addAction(action = new SetClefAction(Clef::Soprano, 1, 0, this));
0234     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0235     m_menus.append(clefMenu);
0236     
0237     QList<QAction*> contextMenu;
0238 
0239     QAction * clefAction = new QAction(i18n("Clef"), this);
0240     clefAction->setMenu(clefMenu);
0241     contextMenu.append(clefAction);
0242 
0243     QMenu* tsMenu = new QMenu();
0244     tsMenu->addAction(action = new TimeSignatureAction(this, 2, 2));
0245     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0246     tsMenu->addAction(action = new TimeSignatureAction(this, 2, 4));
0247     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0248     tsMenu->addAction(action = new TimeSignatureAction(this, 3, 4));
0249     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0250     tsMenu->addAction(action = new TimeSignatureAction(this, 4, 4));
0251     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0252     tsMenu->addAction(action = new TimeSignatureAction(this, 5, 4));
0253     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0254     tsMenu->addAction(action = new TimeSignatureAction(this, 3, 8));
0255     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0256     tsMenu->addAction(action = new TimeSignatureAction(this, 5, 8));
0257     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0258     tsMenu->addAction(action = new TimeSignatureAction(this, 6, 8));
0259     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0260     tsMenu->addAction(action = new TimeSignatureAction(this, 7, 8));
0261     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0262     tsMenu->addAction(action = new TimeSignatureAction(this, 9, 8));
0263     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0264     tsMenu->addAction(action = new TimeSignatureAction(this, 12, 8));
0265     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0266     m_menus.append(tsMenu);
0267     
0268     QAction * timeSigAction = new QAction(i18n("Time signature"), this);
0269     timeSigAction->setMenu(tsMenu);
0270     contextMenu.append(timeSigAction);
0271 
0272     QMenu* ksMenu = new QMenu();
0273     ksMenu->addAction(action = new KeySignatureAction(this, 0));
0274     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0275     ksMenu->addSeparator();
0276     ksMenu->addAction(action = new KeySignatureAction(this, 1));
0277     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0278     ksMenu->addAction(action = new KeySignatureAction(this, 2));
0279     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0280     ksMenu->addAction(action = new KeySignatureAction(this, 3));
0281     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0282     ksMenu->addAction(action = new KeySignatureAction(this, 4));
0283     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0284     ksMenu->addSeparator();
0285     ksMenu->addAction(action = new KeySignatureAction(this, -1));
0286     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0287     ksMenu->addAction(action = new KeySignatureAction(this, -2));
0288     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0289     ksMenu->addAction(action = new KeySignatureAction(this, -3));
0290     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0291     ksMenu->addAction(action = new KeySignatureAction(this, -4));
0292     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0293     ksMenu->addSeparator();
0294     ksMenu->addAction(action = new KeySignatureAction(this));
0295     connect(action, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0296     m_menus.append(ksMenu);
0297     
0298     QAction * keySigAction = new QAction(i18n("Key signature"), this);
0299     keySigAction->setMenu(ksMenu);
0300     contextMenu.append(keySigAction);
0301 
0302     QAction * removeBarAction = new RemoveBarAction(this);
0303     connect(removeBarAction, SIGNAL(triggered()), this, SLOT(actionTriggered()));
0304     contextMenu.append(removeBarAction);
0305 
0306     setPopupActionList(contextMenu);
0307 }
0308 
0309 SimpleEntryTool::~SimpleEntryTool()
0310 {
0311     qDeleteAll(m_menus);
0312 }
0313 
0314 void SimpleEntryTool::activate(ToolActivation toolActivation, const QSet<KoShape*> &shapes)
0315 {
0316     Q_UNUSED(toolActivation);
0317     foreach (KoShape *shape, shapes) {
0318         m_musicshape = dynamic_cast<MusicShape*>( shape );
0319         if ( m_musicshape )
0320         {
0321             //TODO get the cursor that was used the last time for that sheet from some map
0322             m_cursor = new MusicCursor(m_musicshape->sheet(), m_musicshape->sheet());
0323             break;
0324         }
0325     }
0326     if ( !m_musicshape )
0327     {
0328         emit done();
0329         return;
0330     }
0331     useCursor(Qt::ArrowCursor);
0332 }
0333 
0334 void SimpleEntryTool::deactivate()
0335 {
0336     //debugMusic<<"SimpleEntryTool::deactivate";
0337     m_musicshape = 0;
0338     m_cursor = 0;
0339 }
0340 
0341 void SimpleEntryTool::paint( QPainter& painter, const KoViewConverter& viewConverter )
0342 {
0343     Sheet* sheet = m_musicshape->sheet();
0344     int firstSystem = m_musicshape->firstSystem();
0345     int lastSystem = m_musicshape->lastSystem();
0346     int firstBar = sheet->staffSystem(firstSystem)->firstBar();
0347     int lastBar = INT_MAX;
0348     if (lastSystem < sheet->staffSystemCount()-1) {
0349         lastBar = sheet->staffSystem(lastSystem+1)->firstBar()-1;
0350     }
0351 
0352     // somehow check for selections
0353     if (m_selectionStart >= 0) {
0354         // find first shape
0355         MusicShape* shape = m_musicshape;
0356         while (shape->predecessor()) shape = shape->predecessor();
0357 
0358         // now loop over all shapes
0359         while (shape) {
0360             painter.save();
0361             painter.setTransform(shape->absoluteTransformation(&viewConverter) * painter.transform());
0362             KoShape::applyConversion( painter, viewConverter );
0363             painter.setClipRect(QRectF(QPointF(0, 0), shape->size()), Qt::IntersectClip);
0364 
0365             for (int b = qMax(shape->firstBar(), m_selectionStart); b <= m_selectionEnd && b < sheet->barCount() && b <= shape->lastBar(); b++) {
0366                 Bar* bar = sheet->bar(b);
0367                 bool selectedStaff = false;
0368                 for (int p = 0; p < sheet->partCount(); p++) {
0369                     Part* part = sheet->part(p);
0370                     for (int s = 0; s < part->staffCount(); s++) {
0371                         Staff* staff = part->staff(s);
0372                         if (staff == m_selectionStaffStart) {
0373                             selectedStaff = true;
0374                         }
0375                         if (selectedStaff) {
0376                             QPointF p1 = bar->position() + QPointF(0, staff->top());
0377                             QPointF p2 = QPointF(p1.x() + bar->size(), p1.y() + (staff->lineCount()-1) * staff->lineSpacing());
0378                             painter.setBrush(QBrush(Qt::yellow));
0379                             painter.setPen(Qt::NoPen);
0380                             painter.drawRect(QRectF(p1, p2));
0381                         }
0382                         if (staff == m_selectionStaffEnd) {
0383                             selectedStaff = false;
0384                         }
0385                     }
0386                 }
0387             }
0388             for (int p = 0; p < sheet->partCount(); p++) {
0389                 Part* part = sheet->part(p);
0390                 shape->renderer()->renderPart(painter, part, qMax(shape->firstBar(), m_selectionStart), qMin(shape->lastBar(), m_selectionEnd), Qt::black);
0391             }
0392             shape = shape->successor();
0393             painter.restore();
0394         }
0395     }
0396 
0397     painter.setTransform(m_musicshape->absoluteTransformation(&viewConverter) * painter.transform());
0398     KoShape::applyConversion( painter, viewConverter );
0399     painter.setClipRect(QRectF(QPointF(0, 0), m_musicshape->size()), Qt::IntersectClip);
0400         
0401     if (m_activeAction->isVoiceAware()) {
0402         for (int i = 0; i < sheet->partCount(); i++) {
0403             Part* p = sheet->part(i);
0404             if (p->voiceCount() > m_voice) {
0405                 m_musicshape->renderer()->renderVoice(painter, p->voice(m_voice), firstBar, lastBar, Qt::red);
0406             }
0407         }
0408     }
0409     
0410     // draw cursor
0411     if (m_cursor) {
0412         m_activeAction->renderKeyboardPreview(painter, *m_cursor);
0413     }
0414 
0415     m_activeAction->renderPreview(painter, m_point);
0416 }
0417 
0418 void SimpleEntryTool::mousePressEvent( KoPointerEvent* event )
0419 {
0420     if(!m_musicshape->boundingRect().contains(event->point)) {
0421         QRectF area(event->point, QSizeF(1,1));
0422         foreach(KoShape *shape, canvas()->shapeManager()->shapesAt(area, true)) {
0423             MusicShape *musicshape = dynamic_cast<MusicShape*>(shape);
0424             if(musicshape) {
0425                 m_musicshape->update();
0426                 m_musicshape = musicshape;
0427                 m_musicshape->update();
0428                 break; // stop looking.
0429             }
0430         }
0431     }
0432     
0433     QPointF p = m_musicshape->absoluteTransformation(0).inverted().map(event->point);
0434     Sheet *sheet = m_musicshape->sheet();
0435 
0436     p.setY(p.y() + sheet->staffSystem(m_musicshape->firstSystem())->top());
0437 
0438     //debugMusic << "pos:" << p;
0439     // find closest staff system
0440     StaffSystem* system = 0;
0441     for (int i = m_musicshape->firstSystem(); i <= m_musicshape->lastSystem() && i < sheet->staffSystemCount(); i++) {
0442         StaffSystem* ss = sheet->staffSystem(i);
0443         //debugMusic << "system" << i << "has top" << ss->top();
0444         if (ss->top() > p.y()) break;
0445         system = ss;
0446     }
0447 
0448     if(system == 0) {
0449         //debugMusic << "no staff system found";
0450         return;
0451     }
0452 
0453     // find closest staff
0454     Staff* closestStaff = 0;
0455     qreal dist = 1e99;
0456     qreal yrel = p.y() - system->top();
0457     for (int prt = 0; prt < sheet->partCount(); prt++) {
0458         Part* part = sheet->part(prt);
0459         for (int st = 0; st < part->staffCount(); st++) {
0460             Staff* staff = part->staff(st);
0461             qreal top = staff->top();
0462             qreal bot = staff->top() + (staff->lineCount() - 1) * staff->lineSpacing();
0463             if (fabs(top - yrel) < dist) {
0464                 closestStaff = staff;
0465                 dist = fabs(top - yrel);
0466             }
0467             if (fabs(bot - yrel) < dist) {
0468                 closestStaff = staff;
0469                 dist = fabs(bot - yrel);
0470             }
0471         }
0472     }
0473 
0474 //    int line = closestStaff->line(yrel - closestStaff->top());
0475 //    debugMusic << "line: " << line;
0476 
0477     Part* part = closestStaff->part();
0478     for (int i = part->voiceCount(); i <= m_voice; i++) {
0479         part->addVoice();
0480     }
0481 
0482     // find correct bar
0483     Bar* bar = 0;
0484     int barIdx = -1;
0485     bool inPrefix = false;
0486     for (int b = system->firstBar(); b < sheet->barCount(); b++) {
0487         Bar* bb = sheet->bar(b);
0488         if (bb->position().x() <= p.x() && bb->position().x() + bb->size() >= p.x()) {
0489             bar = bb;
0490             barIdx = b;
0491             break;
0492         }
0493         if (bb->prefixPosition().x() <= p.x() && bb->prefixPosition().x() + bb->prefix() >= p.x()) {
0494             bar = bb;
0495             barIdx = b;
0496             inPrefix = true;
0497             break;
0498         }
0499     }
0500 
0501     foreach (QAction* a, popupActionList()) {
0502         a->setVisible(bar);
0503     }
0504 
0505     if (!bar) return;
0506 
0507     QPointF point;
0508     if (inPrefix) {
0509         point = QPointF(p.x() - bar->prefixPosition().x() - bar->prefix(), yrel - closestStaff->top());
0510     } else {
0511         point = QPointF(p.x() - bar->position().x(), yrel - closestStaff->top());
0512     }
0513 
0514     if (event->button() == Qt::RightButton) {
0515         m_contextMenuStaff = closestStaff;
0516         m_contextMenuBar = barIdx;
0517         m_contextMenuPoint = point;
0518         event->ignore();
0519     } else {
0520         m_activeAction->mousePress(closestStaff, barIdx, point);
0521         event->accept();
0522     }
0523 }
0524 
0525 void SimpleEntryTool::mouseMoveEvent( KoPointerEvent* event )
0526 {
0527     if(!m_musicshape->boundingRect().contains(event->point)) {
0528         QRectF area(event->point, QSizeF(1,1));
0529         foreach(KoShape *shape, canvas()->shapeManager()->shapesAt(area, true)) {
0530             MusicShape *musicshape = dynamic_cast<MusicShape*>(shape);
0531             if(musicshape) {
0532                 if (musicshape->sheet() == m_musicshape->sheet() || !event->buttons()) {
0533                     m_musicshape->update();
0534                     m_musicshape = musicshape;
0535                     m_musicshape->update();
0536                     break; // stop looking.
0537                 }
0538             }
0539         }
0540     }
0541     
0542     m_point = m_musicshape->absoluteTransformation(0).inverted().map(event->point);
0543     canvas()->updateCanvas(QRectF(QPointF(event->point.x() - 100, event->point.y() - 100), QSizeF(200, 200)));
0544     if (event->buttons()) {
0545         QPointF p = m_musicshape->absoluteTransformation(0).inverted().map(event->point);
0546         Sheet *sheet = m_musicshape->sheet();
0547         
0548         p.setY(p.y() + sheet->staffSystem(m_musicshape->firstSystem())->top());
0549         // find closest staff system
0550         StaffSystem* system = 0;
0551         for (int i = m_musicshape->firstSystem(); i <= m_musicshape->lastSystem() && i < sheet->staffSystemCount(); i++) {
0552             StaffSystem* ss = sheet->staffSystem(i);
0553             if (ss->top() > p.y()) break;
0554             system = ss;
0555         }
0556         
0557         if(system == 0) {
0558             return;
0559         }
0560         
0561         // find closest staff
0562         Staff* closestStaff = 0;
0563         qreal dist = 1e99;
0564         qreal yrel = p.y() - system->top();
0565         for (int prt = 0; prt < sheet->partCount(); prt++) {
0566             Part* part = sheet->part(prt);
0567             for (int st = 0; st < part->staffCount(); st++) {
0568                 Staff* staff = part->staff(st);
0569                 qreal top = staff->top();
0570                 qreal bot = staff->top() + (staff->lineCount() - 1) * staff->lineSpacing();
0571                 if (fabs(top - yrel) < dist) {
0572                     closestStaff = staff;
0573                     dist = fabs(top - yrel);
0574                 }
0575                 if (fabs(bot - yrel) < dist) {
0576                     closestStaff = staff;
0577                     dist = fabs(bot - yrel);
0578                 }
0579             }
0580         }
0581         
0582         //    int line = closestStaff->line(yrel - closestStaff->top());
0583         //    debugMusic << "line: " << line;
0584         
0585         Part* part = closestStaff->part();
0586         for (int i = part->voiceCount(); i <= m_voice; i++) {
0587             part->addVoice();
0588         }
0589         
0590         // find correct bar
0591         Bar* bar = 0;
0592         int barIdx = -1;
0593         bool inPrefix = false;
0594         for (int b = system->firstBar(); b < sheet->barCount(); b++) {
0595             Bar* bb = sheet->bar(b);
0596             if (bb->position().x() <= p.x() && bb->position().x() + bb->size() >= p.x()) {
0597                 bar = bb;
0598                 barIdx = b;
0599                 break;
0600             }
0601             if (bb->prefixPosition().x() <= p.x() && bb->prefixPosition().x() + bb->prefix() >= p.x()) {
0602                 bar = bb;
0603                 barIdx = b;
0604                 inPrefix = true;
0605                 break;
0606             }
0607         }
0608         
0609         if (!bar) return;
0610         
0611         QPointF point;
0612         if (inPrefix) {
0613             point = QPointF(p.x() - bar->prefixPosition().x() - bar->prefix(), yrel - closestStaff->top());
0614         } else {
0615             point = QPointF(p.x() - bar->position().x(), yrel - closestStaff->top());
0616         }
0617         
0618         m_activeAction->mouseMove(closestStaff, barIdx, point);
0619     }
0620 }
0621 
0622 void SimpleEntryTool::mouseReleaseEvent( KoPointerEvent* )
0623 {
0624 }
0625 
0626 void SimpleEntryTool::keyPressEvent( QKeyEvent *event )
0627 {
0628     event->ignore();
0629     m_activeAction->keyPress(event, *m_cursor);
0630     if (!event->isAccepted()) {
0631         event->accept();
0632         switch (event->key()) {
0633             case Qt::Key_Left:
0634                 m_cursor->moveLeft();
0635                 m_musicshape->update();
0636                 break;
0637             case Qt::Key_Right:
0638                 m_cursor->moveRight();
0639                 m_musicshape->update();
0640                 break;
0641             case Qt::Key_Up:
0642                 m_cursor->moveUp();
0643                 m_musicshape->update();
0644                 break;
0645             case Qt::Key_Down:
0646                 m_cursor->moveDown();
0647                 m_musicshape->update();
0648                 break;
0649             default:
0650                 event->ignore();
0651         }
0652     }
0653 }
0654 
0655 void SimpleEntryTool::addCommand(KUndo2Command* command)
0656 {
0657     canvas()->addCommand(command);
0658 }
0659 
0660 
0661 QWidget * SimpleEntryTool::createOptionWidget()
0662 {
0663     SimpleEntryWidget* widget = new SimpleEntryWidget(this);
0664 
0665     connect(widget, SIGNAL(voiceChanged(int)), this, SLOT(voiceChanged(int)));
0666 
0667     return widget;
0668 }
0669 
0670 void SimpleEntryTool::activeActionChanged(QAction* action)
0671 {
0672     bool oldVoiceAware = m_activeAction->isVoiceAware();
0673     Q_UNUSED(oldVoiceAware);
0674     m_activeAction = qobject_cast<AbstractMusicAction*>(action);
0675     //if (m_activeAction->isVoiceAware() != oldVoiceAware) {
0676         m_musicshape->update();
0677     //    reinterpret_cast<SimpleEntryWidget*>(optionWidget())->setVoiceListEnabled(m_activeAction->isVoiceAware());
0678     //}
0679 }
0680 
0681 void SimpleEntryTool::voiceChanged(int voice)
0682 {
0683     m_cursor->setVoice(voice);
0684     m_voice = voice;
0685     m_musicshape->update();
0686 }
0687 
0688 void SimpleEntryTool::addBars()
0689 {
0690     bool ok;
0691     int barCount = QInputDialog::getInt(0, i18n("Add measures"),
0692                                         i18n("Add how many measures?"),
0693                                         1,
0694                                         1,
0695                                         1000,
0696                                         1, &ok);
0697     if (!ok) return;
0698     addCommand(new AddBarsCommand(m_musicshape, barCount));
0699 }
0700 
0701 void SimpleEntryTool::actionTriggered()
0702 {
0703     AbstractMusicAction* action = dynamic_cast<AbstractMusicAction*>(sender());
0704     if (!action) return;
0705     action->mousePress(m_contextMenuStaff, m_contextMenuBar, m_contextMenuPoint);
0706 }
0707 
0708 MusicShape* SimpleEntryTool::shape()
0709 {
0710     return m_musicshape;
0711 }
0712 
0713 int SimpleEntryTool::voice()
0714 {
0715     return m_voice;
0716 }
0717 
0718 void SimpleEntryTool::setSelection(int firstBar, int lastBar, Staff* startStaff, Staff* endStaff)
0719 {
0720     //debugMusic << "firstBar:" << firstBar << "lastBar:" << lastBar;
0721     m_selectionStart = firstBar;
0722     m_selectionEnd = lastBar;
0723     m_selectionStaffStart = startStaff;
0724     m_selectionStaffEnd = endStaff;
0725     bool foundEnd = false;
0726     Sheet* sheet = m_musicshape->sheet();
0727     for (int p = 0; p < sheet->partCount(); p++) {
0728         Part* part = sheet->part(p);
0729         for (int s = 0; s < part->staffCount(); s++) {
0730             Staff* staff = part->staff(s);
0731             if (staff == m_selectionStaffStart) {
0732                 if (foundEnd) {
0733                     std::swap(m_selectionStaffStart, m_selectionStaffEnd);
0734                 }
0735                 break;
0736             }
0737             if (staff == m_selectionStaffEnd) {
0738                 foundEnd = true;
0739             }
0740         }
0741     }
0742     MusicShape* shape = m_musicshape;
0743     while (shape) {
0744         shape->update();
0745         shape = shape->predecessor();
0746     }
0747     shape = m_musicshape->successor();
0748     while (shape) {
0749         shape->update();
0750         shape = shape->successor();
0751     }
0752 }
0753 
0754 void SimpleEntryTool::importSheet()
0755 {
0756     QString file = QFileDialog::getOpenFileName(0, i18nc("@title:window", "Import"), QString(), i18n("MusicXML files (*.xml)"));
0757     if (file.isEmpty() || file.isNull()) return;
0758     QFile f(file);
0759     f.open(QIODevice::ReadOnly);
0760     KoXmlDocument doc;
0761     KoXml::setDocument(doc, &f, true);
0762     KoXmlElement e = doc.documentElement();
0763     //debugMusic << e.localName() << e.nodeName();
0764     Sheet* sheet = MusicXmlReader(0).loadSheet(doc.documentElement());
0765     if (sheet) {
0766         m_musicshape->setSheet(sheet, 0);
0767         m_musicshape->update();
0768     }
0769 }
0770 
0771 void SimpleEntryTool::exportSheet()
0772 {
0773     QString file = QFileDialog::getSaveFileName(0, i18nc("@title:window", "Export"), QString(), i18n("MusicXML files (*.xml)"));
0774     if (file.isEmpty() || file.isNull()) return;
0775 
0776     QBuffer b;
0777     b.open(QIODevice::ReadWrite);
0778     KoXmlWriter kw(&b);
0779     kw.startDocument("score-partwise", "-//Recordare//DTD MusicXML 2.0 Partwise//EN",
0780                      "http://www.musicxml.org/dtds/partwise.dtd");
0781     MusicXmlWriter().writeSheet(kw, m_musicshape->sheet(), true);
0782     kw.endDocument();
0783 
0784     b.seek(0);
0785 
0786     //debugMusic << b.data();
0787     QFile f(file);
0788     f.open(QIODevice::WriteOnly);
0789     QXmlStreamWriter w(&f);
0790 
0791     QXmlStreamReader xml(&b);
0792     while (!xml.atEnd()) {
0793         xml.readNext();
0794         //debugMusic << xml.tokenType() << xml.tokenString();
0795         //debugMusic << xml.error() << xml.errorString();
0796         if (xml.isCDATA()) {
0797             w.writeCDATA(xml.text().toString());
0798         } else if (xml.isCharacters()) {
0799             w.writeCharacters(xml.text().toString());
0800         } else if (xml.isComment()) {
0801             w.writeComment(xml.text().toString());
0802         } else if (xml.isDTD()) {
0803             w.writeDTD(xml.text().toString());
0804         } else if (xml.isEndDocument()) {
0805             w.writeEndDocument();
0806         } else if (xml.isEndElement()) {
0807             w.writeEndElement();
0808         } else if (xml.isEntityReference()) {
0809             w.writeEntityReference(xml.name().toString());
0810         } else if (xml.isProcessingInstruction()) {
0811             w.writeProcessingInstruction(xml.processingInstructionTarget().toString(), xml.processingInstructionData().toString());
0812         } else if (xml.isStartDocument()) {
0813             w.writeStartDocument();
0814         } else if (xml.isStartElement()) {
0815             w.writeStartElement(xml.name().toString());
0816             QXmlStreamAttributes attr = xml.attributes();
0817             for  (int a = 0; a < attr.count(); a++) {
0818                 w.writeAttribute(attr[a].name().toString(), attr[a].value().toString());
0819             }
0820         }
0821     }
0822 }