svgui
1.9
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 Sonic Visualiser 00005 An audio file viewer and annotation editor. 00006 Centre for Digital Music, Queen Mary, University of London. 00007 This file copyright 2006 Chris Cannam. 00008 00009 This program is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU General Public License as 00011 published by the Free Software Foundation; either version 2 of the 00012 License, or (at your option) any later version. See the file 00013 COPYING included with this distribution for more information. 00014 */ 00015 00016 #include "TimeInstantLayer.h" 00017 00018 #include "data/model/Model.h" 00019 #include "base/RealTime.h" 00020 #include "view/View.h" 00021 #include "base/Profiler.h" 00022 #include "base/Clipboard.h" 00023 #include "ColourDatabase.h" 00024 00025 #include "data/model/SparseOneDimensionalModel.h" 00026 00027 #include "widgets/ItemEditDialog.h" 00028 #include "widgets/ListInputDialog.h" 00029 00030 #include <QPainter> 00031 #include <QMouseEvent> 00032 #include <QTextStream> 00033 #include <QMessageBox> 00034 00035 #include <iostream> 00036 #include <cmath> 00037 00038 //#define DEBUG_TIME_INSTANT_LAYER 1 00039 00040 TimeInstantLayer::TimeInstantLayer() : 00041 SingleColourLayer(), 00042 m_model(0), 00043 m_editing(false), 00044 m_editingPoint(0, tr("New Point")), 00045 m_editingCommand(0), 00046 m_plotStyle(PlotInstants) 00047 { 00048 } 00049 00050 TimeInstantLayer::~TimeInstantLayer() 00051 { 00052 } 00053 00054 void 00055 TimeInstantLayer::setModel(SparseOneDimensionalModel *model) 00056 { 00057 if (m_model == model) return; 00058 m_model = model; 00059 00060 connectSignals(m_model); 00061 00062 #ifdef DEBUG_TIME_INSTANT_LAYER 00063 cerr << "TimeInstantLayer::setModel(" << model << ")" << endl; 00064 #endif 00065 00066 if (m_model && m_model->getRDFTypeURI().endsWith("Segment")) { 00067 setPlotStyle(PlotSegmentation); 00068 } 00069 00070 emit modelReplaced(); 00071 } 00072 00073 Layer::PropertyList 00074 TimeInstantLayer::getProperties() const 00075 { 00076 PropertyList list = SingleColourLayer::getProperties(); 00077 list.push_back("Plot Type"); 00078 return list; 00079 } 00080 00081 QString 00082 TimeInstantLayer::getPropertyLabel(const PropertyName &name) const 00083 { 00084 if (name == "Plot Type") return tr("Plot Type"); 00085 return SingleColourLayer::getPropertyLabel(name); 00086 } 00087 00088 Layer::PropertyType 00089 TimeInstantLayer::getPropertyType(const PropertyName &name) const 00090 { 00091 if (name == "Plot Type") return ValueProperty; 00092 return SingleColourLayer::getPropertyType(name); 00093 } 00094 00095 int 00096 TimeInstantLayer::getPropertyRangeAndValue(const PropertyName &name, 00097 int *min, int *max, int *deflt) const 00098 { 00099 int val = 0; 00100 00101 if (name == "Plot Type") { 00102 00103 if (min) *min = 0; 00104 if (max) *max = 1; 00105 if (deflt) *deflt = 0; 00106 00107 val = int(m_plotStyle); 00108 00109 } else { 00110 00111 val = SingleColourLayer::getPropertyRangeAndValue(name, min, max, deflt); 00112 } 00113 00114 return val; 00115 } 00116 00117 QString 00118 TimeInstantLayer::getPropertyValueLabel(const PropertyName &name, 00119 int value) const 00120 { 00121 if (name == "Plot Type") { 00122 switch (value) { 00123 default: 00124 case 0: return tr("Instants"); 00125 case 1: return tr("Segmentation"); 00126 } 00127 } 00128 return SingleColourLayer::getPropertyValueLabel(name, value); 00129 } 00130 00131 void 00132 TimeInstantLayer::setProperty(const PropertyName &name, int value) 00133 { 00134 if (name == "Plot Type") { 00135 setPlotStyle(PlotStyle(value)); 00136 } else { 00137 SingleColourLayer::setProperty(name, value); 00138 } 00139 } 00140 00141 void 00142 TimeInstantLayer::setPlotStyle(PlotStyle style) 00143 { 00144 if (m_plotStyle == style) return; 00145 m_plotStyle = style; 00146 emit layerParametersChanged(); 00147 } 00148 00149 bool 00150 TimeInstantLayer::isLayerScrollable(const View *v) const 00151 { 00152 QPoint discard; 00153 return !v->shouldIlluminateLocalFeatures(this, discard); 00154 } 00155 00156 SparseOneDimensionalModel::PointList 00157 TimeInstantLayer::getLocalPoints(View *v, int x) const 00158 { 00159 // Return a set of points that all have the same frame number, the 00160 // nearest to the given x coordinate, and that are within a 00161 // certain fuzz distance of that x coordinate. 00162 00163 if (!m_model) return SparseOneDimensionalModel::PointList(); 00164 00165 long frame = v->getFrameForX(x); 00166 00167 SparseOneDimensionalModel::PointList onPoints = 00168 m_model->getPoints(frame); 00169 00170 if (!onPoints.empty()) { 00171 return onPoints; 00172 } 00173 00174 SparseOneDimensionalModel::PointList prevPoints = 00175 m_model->getPreviousPoints(frame); 00176 SparseOneDimensionalModel::PointList nextPoints = 00177 m_model->getNextPoints(frame); 00178 00179 SparseOneDimensionalModel::PointList usePoints = prevPoints; 00180 00181 if (prevPoints.empty()) { 00182 usePoints = nextPoints; 00183 } else if (long(prevPoints.begin()->frame) < v->getStartFrame() && 00184 !(nextPoints.begin()->frame > v->getEndFrame())) { 00185 usePoints = nextPoints; 00186 } else if (nextPoints.begin()->frame - frame < 00187 frame - prevPoints.begin()->frame) { 00188 usePoints = nextPoints; 00189 } 00190 00191 if (!usePoints.empty()) { 00192 int fuzz = 2; 00193 int px = v->getXForFrame(usePoints.begin()->frame); 00194 if ((px > x && px - x > fuzz) || 00195 (px < x && x - px > fuzz + 1)) { 00196 usePoints.clear(); 00197 } 00198 } 00199 00200 return usePoints; 00201 } 00202 00203 QString 00204 TimeInstantLayer::getLabelPreceding(int frame) const 00205 { 00206 if (!m_model) return ""; 00207 SparseOneDimensionalModel::PointList points = m_model->getPreviousPoints(frame); 00208 for (SparseOneDimensionalModel::PointList::const_iterator i = points.begin(); 00209 i != points.end(); ++i) { 00210 if (i->label != "") return i->label; 00211 } 00212 return ""; 00213 } 00214 00215 QString 00216 TimeInstantLayer::getFeatureDescription(View *v, QPoint &pos) const 00217 { 00218 int x = pos.x(); 00219 00220 if (!m_model || !m_model->getSampleRate()) return ""; 00221 00222 SparseOneDimensionalModel::PointList points = getLocalPoints(v, x); 00223 00224 if (points.empty()) { 00225 if (!m_model->isReady()) { 00226 return tr("In progress"); 00227 } else { 00228 return tr("No local points"); 00229 } 00230 } 00231 00232 long useFrame = points.begin()->frame; 00233 00234 RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate()); 00235 00236 QString text; 00237 00238 if (points.begin()->label == "") { 00239 text = QString(tr("Time:\t%1\nNo label")) 00240 .arg(rt.toText(true).c_str()); 00241 } else { 00242 text = QString(tr("Time:\t%1\nLabel:\t%2")) 00243 .arg(rt.toText(true).c_str()) 00244 .arg(points.begin()->label); 00245 } 00246 00247 pos = QPoint(v->getXForFrame(useFrame), pos.y()); 00248 return text; 00249 } 00250 00251 bool 00252 TimeInstantLayer::snapToFeatureFrame(View *v, int &frame, 00253 int &resolution, 00254 SnapType snap) const 00255 { 00256 if (!m_model) { 00257 return Layer::snapToFeatureFrame(v, frame, resolution, snap); 00258 } 00259 00260 resolution = m_model->getResolution(); 00261 SparseOneDimensionalModel::PointList points; 00262 00263 if (snap == SnapNeighbouring) { 00264 00265 points = getLocalPoints(v, v->getXForFrame(frame)); 00266 if (points.empty()) return false; 00267 frame = points.begin()->frame; 00268 return true; 00269 } 00270 00271 points = m_model->getPoints(frame, frame); 00272 int snapped = frame; 00273 bool found = false; 00274 00275 for (SparseOneDimensionalModel::PointList::const_iterator i = points.begin(); 00276 i != points.end(); ++i) { 00277 00278 if (snap == SnapRight) { 00279 00280 if (i->frame >= frame) { 00281 snapped = i->frame; 00282 found = true; 00283 break; 00284 } 00285 00286 } else if (snap == SnapLeft) { 00287 00288 if (i->frame <= frame) { 00289 snapped = i->frame; 00290 found = true; // don't break, as the next may be better 00291 } else { 00292 break; 00293 } 00294 00295 } else { // nearest 00296 00297 SparseOneDimensionalModel::PointList::const_iterator j = i; 00298 ++j; 00299 00300 if (j == points.end()) { 00301 00302 snapped = i->frame; 00303 found = true; 00304 break; 00305 00306 } else if (j->frame >= frame) { 00307 00308 if (j->frame - frame < frame - i->frame) { 00309 snapped = j->frame; 00310 } else { 00311 snapped = i->frame; 00312 } 00313 found = true; 00314 break; 00315 } 00316 } 00317 } 00318 00319 frame = snapped; 00320 return found; 00321 } 00322 00323 void 00324 TimeInstantLayer::paint(View *v, QPainter &paint, QRect rect) const 00325 { 00326 if (!m_model || !m_model->isOK()) return; 00327 00328 // Profiler profiler("TimeInstantLayer::paint", true); 00329 00330 int x0 = rect.left(), x1 = rect.right(); 00331 00332 long frame0 = v->getFrameForX(x0); 00333 long frame1 = v->getFrameForX(x1); 00334 00335 SparseOneDimensionalModel::PointList points(m_model->getPoints 00336 (frame0, frame1)); 00337 00338 bool odd = false; 00339 if (m_plotStyle == PlotSegmentation && !points.empty()) { 00340 int index = m_model->getIndexOf(*points.begin()); 00341 odd = ((index % 2) == 1); 00342 } 00343 00344 paint.setPen(getBaseQColor()); 00345 00346 QColor brushColour(getBaseQColor()); 00347 brushColour.setAlpha(100); 00348 paint.setBrush(brushColour); 00349 00350 QColor oddBrushColour(brushColour); 00351 if (m_plotStyle == PlotSegmentation) { 00352 if (getBaseQColor() == Qt::black) { 00353 oddBrushColour = Qt::gray; 00354 } else if (getBaseQColor() == Qt::darkRed) { 00355 oddBrushColour = Qt::red; 00356 } else if (getBaseQColor() == Qt::darkBlue) { 00357 oddBrushColour = Qt::blue; 00358 } else if (getBaseQColor() == Qt::darkGreen) { 00359 oddBrushColour = Qt::green; 00360 } else { 00361 oddBrushColour = oddBrushColour.light(150); 00362 } 00363 oddBrushColour.setAlpha(100); 00364 } 00365 00366 // SVDEBUG << "TimeInstantLayer::paint: resolution is " 00367 // << m_model->getResolution() << " frames" << endl; 00368 00369 QPoint localPos; 00370 long illuminateFrame = -1; 00371 00372 if (v->shouldIlluminateLocalFeatures(this, localPos)) { 00373 SparseOneDimensionalModel::PointList localPoints = 00374 getLocalPoints(v, localPos.x()); 00375 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame; 00376 } 00377 00378 int prevX = -1; 00379 int textY = v->getTextLabelHeight(this, paint); 00380 00381 for (SparseOneDimensionalModel::PointList::const_iterator i = points.begin(); 00382 i != points.end(); ++i) { 00383 00384 const SparseOneDimensionalModel::Point &p(*i); 00385 SparseOneDimensionalModel::PointList::const_iterator j = i; 00386 ++j; 00387 00388 int x = v->getXForFrame(p.frame); 00389 if (x == prevX && m_plotStyle == PlotInstants && 00390 p.frame != illuminateFrame) continue; 00391 00392 int iw = v->getXForFrame(p.frame + m_model->getResolution()) - x; 00393 if (iw < 2) { 00394 if (iw < 1) { 00395 iw = 2; 00396 if (j != points.end()) { 00397 int nx = v->getXForFrame(j->frame); 00398 if (nx < x + 3) iw = 1; 00399 } 00400 } else { 00401 iw = 2; 00402 } 00403 } 00404 00405 if (p.frame == illuminateFrame) { 00406 paint.setPen(getForegroundQColor(v)); 00407 } else { 00408 paint.setPen(brushColour); 00409 } 00410 00411 if (m_plotStyle == PlotInstants) { 00412 if (iw > 1) { 00413 paint.drawRect(x, 0, iw - 1, v->height() - 1); 00414 } else { 00415 paint.drawLine(x, 0, x, v->height() - 1); 00416 } 00417 } else { 00418 00419 if (odd) paint.setBrush(oddBrushColour); 00420 else paint.setBrush(brushColour); 00421 00422 int nx; 00423 00424 if (j != points.end()) { 00425 const SparseOneDimensionalModel::Point &q(*j); 00426 nx = v->getXForFrame(q.frame); 00427 } else { 00428 nx = v->getXForFrame(m_model->getEndFrame()); 00429 } 00430 00431 if (nx >= x) { 00432 00433 if (illuminateFrame != p.frame && 00434 (nx < x + 5 || x >= v->width() - 1)) { 00435 paint.setPen(Qt::NoPen); 00436 } 00437 00438 paint.drawRect(x, -1, nx - x, v->height() + 1); 00439 } 00440 00441 odd = !odd; 00442 } 00443 00444 paint.setPen(getBaseQColor()); 00445 00446 if (p.label != "") { 00447 00448 // only draw if there's enough room from here to the next point 00449 00450 int lw = paint.fontMetrics().width(p.label); 00451 bool good = true; 00452 00453 if (j != points.end()) { 00454 int nx = v->getXForFrame(j->frame); 00455 if (nx >= x && nx - x - iw - 3 <= lw) good = false; 00456 } 00457 00458 if (good) { 00459 v->drawVisibleText(paint, x + iw + 2, textY, p.label, View::OutlinedText); 00460 // paint.drawText(x + iw + 2, textY, p.label); 00461 } 00462 } 00463 00464 prevX = x; 00465 } 00466 } 00467 00468 void 00469 TimeInstantLayer::drawStart(View *v, QMouseEvent *e) 00470 { 00471 #ifdef DEBUG_TIME_INSTANT_LAYER 00472 cerr << "TimeInstantLayer::drawStart(" << e->x() << ")" << endl; 00473 #endif 00474 00475 if (!m_model) return; 00476 00477 long frame = v->getFrameForX(e->x()); 00478 if (frame < 0) frame = 0; 00479 frame = frame / m_model->getResolution() * m_model->getResolution(); 00480 00481 m_editingPoint = SparseOneDimensionalModel::Point(frame, tr("New Point")); 00482 00483 if (m_editingCommand) finish(m_editingCommand); 00484 m_editingCommand = new SparseOneDimensionalModel::EditCommand(m_model, 00485 tr("Draw Point")); 00486 m_editingCommand->addPoint(m_editingPoint); 00487 00488 m_editing = true; 00489 } 00490 00491 void 00492 TimeInstantLayer::drawDrag(View *v, QMouseEvent *e) 00493 { 00494 #ifdef DEBUG_TIME_INSTANT_LAYER 00495 cerr << "TimeInstantLayer::drawDrag(" << e->x() << ")" << endl; 00496 #endif 00497 00498 if (!m_model || !m_editing) return; 00499 00500 long frame = v->getFrameForX(e->x()); 00501 if (frame < 0) frame = 0; 00502 frame = frame / m_model->getResolution() * m_model->getResolution(); 00503 m_editingCommand->deletePoint(m_editingPoint); 00504 m_editingPoint.frame = frame; 00505 m_editingCommand->addPoint(m_editingPoint); 00506 } 00507 00508 void 00509 TimeInstantLayer::drawEnd(View *, QMouseEvent *) 00510 { 00511 #ifdef DEBUG_TIME_INSTANT_LAYER 00512 cerr << "TimeInstantLayer::drawEnd(" << e->x() << ")" << endl; 00513 #endif 00514 if (!m_model || !m_editing) return; 00515 QString newName = tr("Add Point at %1 s") 00516 .arg(RealTime::frame2RealTime(m_editingPoint.frame, 00517 m_model->getSampleRate()) 00518 .toText(false).c_str()); 00519 m_editingCommand->setName(newName); 00520 finish(m_editingCommand); 00521 m_editingCommand = 0; 00522 m_editing = false; 00523 } 00524 00525 void 00526 TimeInstantLayer::eraseStart(View *v, QMouseEvent *e) 00527 { 00528 if (!m_model) return; 00529 00530 SparseOneDimensionalModel::PointList points = getLocalPoints(v, e->x()); 00531 if (points.empty()) return; 00532 00533 m_editingPoint = *points.begin(); 00534 00535 if (m_editingCommand) { 00536 finish(m_editingCommand); 00537 m_editingCommand = 0; 00538 } 00539 00540 m_editing = true; 00541 } 00542 00543 void 00544 TimeInstantLayer::eraseDrag(View *, QMouseEvent *) 00545 { 00546 } 00547 00548 void 00549 TimeInstantLayer::eraseEnd(View *v, QMouseEvent *e) 00550 { 00551 if (!m_model || !m_editing) return; 00552 00553 m_editing = false; 00554 00555 SparseOneDimensionalModel::PointList points = getLocalPoints(v, e->x()); 00556 if (points.empty()) return; 00557 if (points.begin()->frame != m_editingPoint.frame) return; 00558 00559 m_editingCommand = new SparseOneDimensionalModel::EditCommand 00560 (m_model, tr("Erase Point")); 00561 00562 m_editingCommand->deletePoint(m_editingPoint); 00563 00564 finish(m_editingCommand); 00565 m_editingCommand = 0; 00566 m_editing = false; 00567 } 00568 00569 void 00570 TimeInstantLayer::editStart(View *v, QMouseEvent *e) 00571 { 00572 #ifdef DEBUG_TIME_INSTANT_LAYER 00573 cerr << "TimeInstantLayer::editStart(" << e->x() << ")" << endl; 00574 #endif 00575 00576 if (!m_model) return; 00577 00578 SparseOneDimensionalModel::PointList points = getLocalPoints(v, e->x()); 00579 if (points.empty()) return; 00580 00581 m_editingPoint = *points.begin(); 00582 00583 if (m_editingCommand) { 00584 finish(m_editingCommand); 00585 m_editingCommand = 0; 00586 } 00587 00588 m_editing = true; 00589 } 00590 00591 void 00592 TimeInstantLayer::editDrag(View *v, QMouseEvent *e) 00593 { 00594 #ifdef DEBUG_TIME_INSTANT_LAYER 00595 cerr << "TimeInstantLayer::editDrag(" << e->x() << ")" << endl; 00596 #endif 00597 00598 if (!m_model || !m_editing) return; 00599 00600 long frame = v->getFrameForX(e->x()); 00601 if (frame < 0) frame = 0; 00602 frame = frame / m_model->getResolution() * m_model->getResolution(); 00603 00604 if (!m_editingCommand) { 00605 m_editingCommand = new SparseOneDimensionalModel::EditCommand(m_model, 00606 tr("Drag Point")); 00607 } 00608 00609 m_editingCommand->deletePoint(m_editingPoint); 00610 m_editingPoint.frame = frame; 00611 m_editingCommand->addPoint(m_editingPoint); 00612 } 00613 00614 void 00615 TimeInstantLayer::editEnd(View *, QMouseEvent *) 00616 { 00617 #ifdef DEBUG_TIME_INSTANT_LAYER 00618 cerr << "TimeInstantLayer::editEnd(" << e->x() << ")" << endl; 00619 #endif 00620 if (!m_model || !m_editing) return; 00621 if (m_editingCommand) { 00622 QString newName = tr("Move Point to %1 s") 00623 .arg(RealTime::frame2RealTime(m_editingPoint.frame, 00624 m_model->getSampleRate()) 00625 .toText(false).c_str()); 00626 m_editingCommand->setName(newName); 00627 finish(m_editingCommand); 00628 } 00629 m_editingCommand = 0; 00630 m_editing = false; 00631 } 00632 00633 bool 00634 TimeInstantLayer::editOpen(View *v, QMouseEvent *e) 00635 { 00636 if (!m_model) return false; 00637 00638 SparseOneDimensionalModel::PointList points = getLocalPoints(v, e->x()); 00639 if (points.empty()) return false; 00640 00641 SparseOneDimensionalModel::Point point = *points.begin(); 00642 00643 ItemEditDialog *dialog = new ItemEditDialog 00644 (m_model->getSampleRate(), 00645 ItemEditDialog::ShowTime | 00646 ItemEditDialog::ShowText); 00647 00648 dialog->setFrameTime(point.frame); 00649 dialog->setText(point.label); 00650 00651 if (dialog->exec() == QDialog::Accepted) { 00652 00653 SparseOneDimensionalModel::Point newPoint = point; 00654 newPoint.frame = dialog->getFrameTime(); 00655 newPoint.label = dialog->getText(); 00656 00657 SparseOneDimensionalModel::EditCommand *command = 00658 new SparseOneDimensionalModel::EditCommand(m_model, tr("Edit Point")); 00659 command->deletePoint(point); 00660 command->addPoint(newPoint); 00661 finish(command); 00662 } 00663 00664 delete dialog; 00665 return true; 00666 } 00667 00668 void 00669 TimeInstantLayer::moveSelection(Selection s, int newStartFrame) 00670 { 00671 if (!m_model) return; 00672 00673 SparseOneDimensionalModel::EditCommand *command = 00674 new SparseOneDimensionalModel::EditCommand(m_model, 00675 tr("Drag Selection")); 00676 00677 SparseOneDimensionalModel::PointList points = 00678 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); 00679 00680 for (SparseOneDimensionalModel::PointList::iterator i = points.begin(); 00681 i != points.end(); ++i) { 00682 00683 if (s.contains(i->frame)) { 00684 SparseOneDimensionalModel::Point newPoint(*i); 00685 newPoint.frame = i->frame + newStartFrame - s.getStartFrame(); 00686 command->deletePoint(*i); 00687 command->addPoint(newPoint); 00688 } 00689 } 00690 00691 finish(command); 00692 } 00693 00694 void 00695 TimeInstantLayer::resizeSelection(Selection s, Selection newSize) 00696 { 00697 if (!m_model) return; 00698 00699 SparseOneDimensionalModel::EditCommand *command = 00700 new SparseOneDimensionalModel::EditCommand(m_model, 00701 tr("Resize Selection")); 00702 00703 SparseOneDimensionalModel::PointList points = 00704 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); 00705 00706 double ratio = 00707 double(newSize.getEndFrame() - newSize.getStartFrame()) / 00708 double(s.getEndFrame() - s.getStartFrame()); 00709 00710 for (SparseOneDimensionalModel::PointList::iterator i = points.begin(); 00711 i != points.end(); ++i) { 00712 00713 if (s.contains(i->frame)) { 00714 00715 double target = i->frame; 00716 target = newSize.getStartFrame() + 00717 double(target - s.getStartFrame()) * ratio; 00718 00719 SparseOneDimensionalModel::Point newPoint(*i); 00720 newPoint.frame = lrint(target); 00721 command->deletePoint(*i); 00722 command->addPoint(newPoint); 00723 } 00724 } 00725 00726 finish(command); 00727 } 00728 00729 void 00730 TimeInstantLayer::deleteSelection(Selection s) 00731 { 00732 if (!m_model) return; 00733 00734 SparseOneDimensionalModel::EditCommand *command = 00735 new SparseOneDimensionalModel::EditCommand(m_model, 00736 tr("Delete Selection")); 00737 00738 SparseOneDimensionalModel::PointList points = 00739 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); 00740 00741 for (SparseOneDimensionalModel::PointList::iterator i = points.begin(); 00742 i != points.end(); ++i) { 00743 if (s.contains(i->frame)) command->deletePoint(*i); 00744 } 00745 00746 finish(command); 00747 } 00748 00749 void 00750 TimeInstantLayer::copy(View *v, Selection s, Clipboard &to) 00751 { 00752 if (!m_model) return; 00753 00754 SparseOneDimensionalModel::PointList points = 00755 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); 00756 00757 for (SparseOneDimensionalModel::PointList::iterator i = points.begin(); 00758 i != points.end(); ++i) { 00759 if (s.contains(i->frame)) { 00760 Clipboard::Point point(i->frame, i->label); 00761 point.setReferenceFrame(alignToReference(v, i->frame)); 00762 to.addPoint(point); 00763 } 00764 } 00765 } 00766 00767 bool 00768 TimeInstantLayer::paste(View *v, const Clipboard &from, int frameOffset, bool) 00769 { 00770 if (!m_model) return false; 00771 00772 const Clipboard::PointList &points = from.getPoints(); 00773 00774 bool realign = false; 00775 00776 if (clipboardHasDifferentAlignment(v, from)) { 00777 00778 QMessageBox::StandardButton button = 00779 QMessageBox::question(v, tr("Re-align pasted instants?"), 00780 tr("The instants you are pasting came from a layer with different source material from this one. Do you want to re-align them in time, to match the source material for this layer?"), 00781 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, 00782 QMessageBox::Yes); 00783 00784 if (button == QMessageBox::Cancel) { 00785 return false; 00786 } 00787 00788 if (button == QMessageBox::Yes) { 00789 realign = true; 00790 } 00791 } 00792 00793 SparseOneDimensionalModel::EditCommand *command = 00794 new SparseOneDimensionalModel::EditCommand(m_model, tr("Paste")); 00795 00796 for (Clipboard::PointList::const_iterator i = points.begin(); 00797 i != points.end(); ++i) { 00798 00799 if (!i->haveFrame()) continue; 00800 00801 int frame = 0; 00802 00803 if (!realign) { 00804 00805 frame = i->getFrame(); 00806 00807 } else { 00808 00809 if (i->haveReferenceFrame()) { 00810 frame = i->getReferenceFrame(); 00811 frame = alignFromReference(v, frame); 00812 } else { 00813 frame = i->getFrame(); 00814 } 00815 } 00816 00817 if (frameOffset > 0) frame += frameOffset; 00818 else if (frameOffset < 0) { 00819 if (frame > -frameOffset) frame += frameOffset; 00820 else frame = 0; 00821 } 00822 00823 SparseOneDimensionalModel::Point newPoint(frame); 00824 if (i->haveLabel()) { 00825 newPoint.label = i->getLabel(); 00826 } else if (i->haveValue()) { 00827 newPoint.label = QString("%1").arg(i->getValue()); 00828 } 00829 00830 command->addPoint(newPoint); 00831 } 00832 00833 finish(command); 00834 return true; 00835 } 00836 00837 int 00838 TimeInstantLayer::getDefaultColourHint(bool darkbg, bool &impose) 00839 { 00840 impose = false; 00841 return ColourDatabase::getInstance()->getColourIndex 00842 (QString(darkbg ? "Bright Purple" : "Purple")); 00843 } 00844 00845 void 00846 TimeInstantLayer::toXml(QTextStream &stream, 00847 QString indent, QString extraAttributes) const 00848 { 00849 SingleColourLayer::toXml(stream, indent, 00850 extraAttributes + 00851 QString(" plotStyle=\"%1\"") 00852 .arg(m_plotStyle)); 00853 } 00854 00855 void 00856 TimeInstantLayer::setProperties(const QXmlAttributes &attributes) 00857 { 00858 SingleColourLayer::setProperties(attributes); 00859 00860 bool ok; 00861 PlotStyle style = (PlotStyle) 00862 attributes.value("plotStyle").toInt(&ok); 00863 if (ok) setPlotStyle(style); 00864 } 00865