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 }