svgui  1.9
TextLayer.cpp
Go to the documentation of this file.
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 "TextLayer.h"
00017 
00018 #include "data/model/Model.h"
00019 #include "base/RealTime.h"
00020 #include "base/Profiler.h"
00021 #include "ColourDatabase.h"
00022 #include "view/View.h"
00023 
00024 #include "data/model/TextModel.h"
00025 
00026 #include <QPainter>
00027 #include <QMouseEvent>
00028 #include <QInputDialog>
00029 #include <QTextStream>
00030 #include <QMessageBox>
00031 
00032 #include <iostream>
00033 #include <cmath>
00034 
00035 TextLayer::TextLayer() :
00036     SingleColourLayer(),
00037     m_model(0),
00038     m_editing(false),
00039     m_originalPoint(0, 0.0, tr("Empty Label")),
00040     m_editingPoint(0, 0.0, tr("Empty Label")),
00041     m_editingCommand(0)
00042 {
00043     
00044 }
00045 
00046 void
00047 TextLayer::setModel(TextModel *model)
00048 {
00049     if (m_model == model) return;
00050     m_model = model;
00051 
00052     connectSignals(m_model);
00053 
00054 //    SVDEBUG << "TextLayer::setModel(" << model << ")" << endl;
00055 
00056     emit modelReplaced();
00057 }
00058 
00059 Layer::PropertyList
00060 TextLayer::getProperties() const
00061 {
00062     PropertyList list = SingleColourLayer::getProperties();
00063     return list;
00064 }
00065 
00066 QString
00067 TextLayer::getPropertyLabel(const PropertyName &name) const
00068 {
00069     return SingleColourLayer::getPropertyLabel(name);
00070 }
00071 
00072 Layer::PropertyType
00073 TextLayer::getPropertyType(const PropertyName &name) const
00074 {
00075     return SingleColourLayer::getPropertyType(name);
00076 }
00077 
00078 int
00079 TextLayer::getPropertyRangeAndValue(const PropertyName &name,
00080                                     int *min, int *max, int *deflt) const
00081 {
00082     return SingleColourLayer::getPropertyRangeAndValue(name, min, max, deflt);
00083 }
00084 
00085 QString
00086 TextLayer::getPropertyValueLabel(const PropertyName &name,
00087                                  int value) const
00088 {
00089     return SingleColourLayer::getPropertyValueLabel(name, value);
00090 }
00091 
00092 void
00093 TextLayer::setProperty(const PropertyName &name, int value)
00094 {
00095     SingleColourLayer::setProperty(name, value);
00096 }
00097 
00098 bool
00099 TextLayer::getValueExtents(float &, float &, bool &, QString &) const
00100 {
00101     return false;
00102 }
00103 
00104 bool
00105 TextLayer::isLayerScrollable(const View *v) const
00106 {
00107     QPoint discard;
00108     return !v->shouldIlluminateLocalFeatures(this, discard);
00109 }
00110 
00111 
00112 TextModel::PointList
00113 TextLayer::getLocalPoints(View *v, int x, int y) const
00114 {
00115     if (!m_model) return TextModel::PointList();
00116 
00117     long frame0 = v->getFrameForX(-150);
00118     long frame1 = v->getFrameForX(v->width() + 150);
00119     
00120     TextModel::PointList points(m_model->getPoints(frame0, frame1));
00121 
00122     TextModel::PointList rv;
00123     QFontMetrics metrics = QFontMetrics(QFont());
00124 
00125     for (TextModel::PointList::iterator i = points.begin();
00126          i != points.end(); ++i) {
00127 
00128         const TextModel::Point &p(*i);
00129 
00130         int px = v->getXForFrame(p.frame);
00131         int py = getYForHeight(v, p.height);
00132 
00133         QString label = p.label;
00134         if (label == "") {
00135             label = tr("<no text>");
00136         }
00137 
00138         QRect rect = metrics.boundingRect
00139             (QRect(0, 0, 150, 200),
00140              Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, label);
00141 
00142         if (py + rect.height() > v->height()) {
00143             if (rect.height() > v->height()) py = 0;
00144             else py = v->height() - rect.height() - 1;
00145         }
00146 
00147         if (x >= px && x < px + rect.width() &&
00148             y >= py && y < py + rect.height()) {
00149             rv.insert(p);
00150         }
00151     }
00152 
00153     return rv;
00154 }
00155 
00156 bool
00157 TextLayer::getPointToDrag(View *v, int x, int y, TextModel::Point &p) const
00158 {
00159     if (!m_model) return false;
00160 
00161     long a = v->getFrameForX(x - 120);
00162     long b = v->getFrameForX(x + 10);
00163     TextModel::PointList onPoints = m_model->getPoints(a, b);
00164     if (onPoints.empty()) return false;
00165 
00166     float nearestDistance = -1;
00167 
00168     for (TextModel::PointList::const_iterator i = onPoints.begin();
00169          i != onPoints.end(); ++i) {
00170 
00171         int yd = getYForHeight(v, (*i).height) - y;
00172         int xd = v->getXForFrame((*i).frame) - x;
00173         float distance = sqrtf(yd*yd + xd*xd);
00174 
00175         if (nearestDistance == -1 || distance < nearestDistance) {
00176             nearestDistance = distance;
00177             p = *i;
00178         }
00179     }
00180 
00181     return true;
00182 }
00183 
00184 QString
00185 TextLayer::getFeatureDescription(View *v, QPoint &pos) const
00186 {
00187     int x = pos.x();
00188 
00189     if (!m_model || !m_model->getSampleRate()) return "";
00190 
00191     TextModel::PointList points = getLocalPoints(v, x, pos.y());
00192 
00193     if (points.empty()) {
00194         if (!m_model->isReady()) {
00195             return tr("In progress");
00196         } else {
00197             return "";
00198         }
00199     }
00200 
00201     long useFrame = points.begin()->frame;
00202 
00203     RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate());
00204     
00205     QString text;
00206 
00207     if (points.begin()->label == "") {
00208         text = QString(tr("Time:\t%1\nHeight:\t%2\nLabel:\t%3"))
00209             .arg(rt.toText(true).c_str())
00210             .arg(points.begin()->height)
00211             .arg(points.begin()->label);
00212     }
00213 
00214     pos = QPoint(v->getXForFrame(useFrame),
00215                  getYForHeight(v, points.begin()->height));
00216     return text;
00217 }
00218 
00219 
00221 
00222 bool
00223 TextLayer::snapToFeatureFrame(View *v, int &frame,
00224                               int &resolution,
00225                               SnapType snap) const
00226 {
00227     if (!m_model) {
00228         return Layer::snapToFeatureFrame(v, frame, resolution, snap);
00229     }
00230 
00231     resolution = m_model->getResolution();
00232     TextModel::PointList points;
00233 
00234     if (snap == SnapNeighbouring) {
00235         
00236         points = getLocalPoints(v, v->getXForFrame(frame), -1);
00237         if (points.empty()) return false;
00238         frame = points.begin()->frame;
00239         return true;
00240     }    
00241 
00242     points = m_model->getPoints(frame, frame);
00243     int snapped = frame;
00244     bool found = false;
00245 
00246     for (TextModel::PointList::const_iterator i = points.begin();
00247          i != points.end(); ++i) {
00248 
00249         if (snap == SnapRight) {
00250 
00251             if (i->frame > frame) {
00252                 snapped = i->frame;
00253                 found = true;
00254                 break;
00255             }
00256 
00257         } else if (snap == SnapLeft) {
00258 
00259             if (i->frame <= frame) {
00260                 snapped = i->frame;
00261                 found = true; // don't break, as the next may be better
00262             } else {
00263                 break;
00264             }
00265 
00266         } else { // nearest
00267 
00268             TextModel::PointList::const_iterator j = i;
00269             ++j;
00270 
00271             if (j == points.end()) {
00272 
00273                 snapped = i->frame;
00274                 found = true;
00275                 break;
00276 
00277             } else if (j->frame >= frame) {
00278 
00279                 if (j->frame - frame < frame - i->frame) {
00280                     snapped = j->frame;
00281                 } else {
00282                     snapped = i->frame;
00283                 }
00284                 found = true;
00285                 break;
00286             }
00287         }
00288     }
00289 
00290     frame = snapped;
00291     return found;
00292 }
00293 
00294 int
00295 TextLayer::getYForHeight(View *v, float height) const
00296 {
00297     int h = v->height();
00298     return h - int(height * h);
00299 }
00300 
00301 float
00302 TextLayer::getHeightForY(View *v, int y) const
00303 {
00304     int h = v->height();
00305     return float(h - y) / h;
00306 }
00307 
00308 void
00309 TextLayer::paint(View *v, QPainter &paint, QRect rect) const
00310 {
00311     if (!m_model || !m_model->isOK()) return;
00312 
00313     int sampleRate = m_model->getSampleRate();
00314     if (!sampleRate) return;
00315 
00316 //    Profiler profiler("TextLayer::paint", true);
00317 
00318     int x0 = rect.left(), x1 = rect.right();
00319     long frame0 = v->getFrameForX(x0);
00320     long frame1 = v->getFrameForX(x1);
00321 
00322     TextModel::PointList points(m_model->getPoints(frame0, frame1));
00323     if (points.empty()) return;
00324 
00325     QColor brushColour(getBaseQColor());
00326 
00327     int h, s, val;
00328     brushColour.getHsv(&h, &s, &val);
00329     brushColour.setHsv(h, s, 255, 100);
00330 
00331     QColor penColour;
00332     penColour = v->getForeground();
00333 
00334 //    SVDEBUG << "TextLayer::paint: resolution is "
00335 //            << m_model->getResolution() << " frames" << endl;
00336 
00337     QPoint localPos;
00338     TextModel::Point illuminatePoint(0);
00339     bool shouldIlluminate = false;
00340 
00341     if (v->shouldIlluminateLocalFeatures(this, localPos)) {
00342         shouldIlluminate = getPointToDrag(v, localPos.x(), localPos.y(),
00343                                           illuminatePoint);
00344     }
00345 
00346     int boxMaxWidth = 150;
00347     int boxMaxHeight = 200;
00348 
00349     paint.save();
00350     paint.setClipRect(rect.x(), 0, rect.width() + boxMaxWidth, v->height());
00351     
00352     for (TextModel::PointList::const_iterator i = points.begin();
00353          i != points.end(); ++i) {
00354 
00355         const TextModel::Point &p(*i);
00356 
00357         int x = v->getXForFrame(p.frame);
00358         int y = getYForHeight(v, p.height);
00359 
00360         if (!shouldIlluminate ||
00361             // "illuminatePoint != p"
00362             TextModel::Point::Comparator()(illuminatePoint, p) ||
00363             TextModel::Point::Comparator()(p, illuminatePoint)) {
00364             paint.setPen(penColour);
00365             paint.setBrush(brushColour);
00366         } else {
00367             paint.setBrush(penColour);
00368             paint.setPen(v->getBackground());
00369         }
00370 
00371         QString label = p.label;
00372         if (label == "") {
00373             label = tr("<no text>");
00374         }
00375 
00376         QRect boxRect = paint.fontMetrics().boundingRect
00377             (QRect(0, 0, boxMaxWidth, boxMaxHeight),
00378              Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, label);
00379 
00380         QRect textRect = QRect(3, 2, boxRect.width(), boxRect.height());
00381         boxRect = QRect(0, 0, boxRect.width() + 6, boxRect.height() + 2);
00382 
00383         if (y + boxRect.height() > v->height()) {
00384             if (boxRect.height() > v->height()) y = 0;
00385             else y = v->height() - boxRect.height() - 1;
00386         }
00387 
00388         boxRect = QRect(x, y, boxRect.width(), boxRect.height());
00389         textRect = QRect(x + 3, y + 2, textRect.width(), textRect.height());
00390 
00391 //      boxRect = QRect(x, y, boxRect.width(), boxRect.height());
00392 //      textRect = QRect(x + 3, y + 2, textRect.width(), textRect.height());
00393 
00394         paint.setRenderHint(QPainter::Antialiasing, false);
00395         paint.drawRect(boxRect);
00396 
00397         paint.setRenderHint(QPainter::Antialiasing, true);
00398         paint.drawText(textRect,
00399                        Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap,
00400                        label);
00401 
00405     }
00406 
00407     paint.restore();
00408 
00409     // looks like save/restore doesn't deal with this:
00410     paint.setRenderHint(QPainter::Antialiasing, false);
00411 }
00412 
00413 void
00414 TextLayer::drawStart(View *v, QMouseEvent *e)
00415 {
00416 //    SVDEBUG << "TextLayer::drawStart(" << e->x() << "," << e->y() << ")" << endl;
00417 
00418     if (!m_model) {
00419         SVDEBUG << "TextLayer::drawStart: no model" << endl;
00420         return;
00421     }
00422 
00423     long frame = v->getFrameForX(e->x());
00424     if (frame < 0) frame = 0;
00425     frame = frame / m_model->getResolution() * m_model->getResolution();
00426 
00427     float height = getHeightForY(v, e->y());
00428 
00429     m_editingPoint = TextModel::Point(frame, height, "");
00430     m_originalPoint = m_editingPoint;
00431 
00432     if (m_editingCommand) finish(m_editingCommand);
00433     m_editingCommand = new TextModel::EditCommand(m_model, "Add Label");
00434     m_editingCommand->addPoint(m_editingPoint);
00435 
00436     m_editing = true;
00437 }
00438 
00439 void
00440 TextLayer::drawDrag(View *v, QMouseEvent *e)
00441 {
00442 //    SVDEBUG << "TextLayer::drawDrag(" << e->x() << "," << e->y() << ")" << endl;
00443 
00444     if (!m_model || !m_editing) return;
00445 
00446     long frame = v->getFrameForX(e->x());
00447     if (frame < 0) frame = 0;
00448     frame = frame / m_model->getResolution() * m_model->getResolution();
00449 
00450     float height = getHeightForY(v, e->y());
00451 
00452     m_editingCommand->deletePoint(m_editingPoint);
00453     m_editingPoint.frame = frame;
00454     m_editingPoint.height = height;
00455     m_editingCommand->addPoint(m_editingPoint);
00456 }
00457 
00458 void
00459 TextLayer::drawEnd(View *v, QMouseEvent *)
00460 {
00461 //    SVDEBUG << "TextLayer::drawEnd(" << e->x() << "," << e->y() << ")" << endl;
00462     if (!m_model || !m_editing) return;
00463 
00464     bool ok = false;
00465     QString label = QInputDialog::getText(v, tr("Enter label"),
00466                                           tr("Please enter a new label:"),
00467                                           QLineEdit::Normal, "", &ok);
00468 
00469     if (ok) {
00470         TextModel::RelabelCommand *command =
00471             new TextModel::RelabelCommand(m_model, m_editingPoint, label);
00472         m_editingCommand->addCommand(command);
00473     } else {
00474         m_editingCommand->deletePoint(m_editingPoint);
00475     }
00476 
00477     finish(m_editingCommand);
00478     m_editingCommand = 0;
00479     m_editing = false;
00480 }
00481 
00482 void
00483 TextLayer::eraseStart(View *v, QMouseEvent *e)
00484 {
00485     if (!m_model) return;
00486 
00487     if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) return;
00488 
00489     if (m_editingCommand) {
00490         finish(m_editingCommand);
00491         m_editingCommand = 0;
00492     }
00493 
00494     m_editing = true;
00495 }
00496 
00497 void
00498 TextLayer::eraseDrag(View *, QMouseEvent *)
00499 {
00500 }
00501 
00502 void
00503 TextLayer::eraseEnd(View *v, QMouseEvent *e)
00504 {
00505     if (!m_model || !m_editing) return;
00506 
00507     m_editing = false;
00508 
00509     TextModel::Point p(0);
00510     if (!getPointToDrag(v, e->x(), e->y(), p)) return;
00511     if (p.frame != m_editingPoint.frame || p.height != m_editingPoint.height) return;
00512 
00513     m_editingCommand = new TextModel::EditCommand
00514         (m_model, tr("Erase Point"));
00515 
00516     m_editingCommand->deletePoint(m_editingPoint);
00517 
00518     finish(m_editingCommand);
00519     m_editingCommand = 0;
00520     m_editing = false;
00521 }
00522 
00523 void
00524 TextLayer::editStart(View *v, QMouseEvent *e)
00525 {
00526 //    SVDEBUG << "TextLayer::editStart(" << e->x() << "," << e->y() << ")" << endl;
00527 
00528     if (!m_model) return;
00529 
00530     if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) {
00531         return;
00532     }
00533 
00534     m_editOrigin = e->pos();
00535     m_originalPoint = m_editingPoint;
00536 
00537     if (m_editingCommand) {
00538         finish(m_editingCommand);
00539         m_editingCommand = 0;
00540     }
00541 
00542     m_editing = true;
00543 }
00544 
00545 void
00546 TextLayer::editDrag(View *v, QMouseEvent *e)
00547 {
00548     if (!m_model || !m_editing) return;
00549 
00550     long frameDiff = v->getFrameForX(e->x()) - v->getFrameForX(m_editOrigin.x());
00551     float heightDiff = getHeightForY(v, e->y()) - getHeightForY(v, m_editOrigin.y());
00552 
00553     long frame = m_originalPoint.frame + frameDiff;
00554     float height = m_originalPoint.height + heightDiff;
00555 
00556 //    long frame = v->getFrameForX(e->x());
00557     if (frame < 0) frame = 0;
00558     frame = (frame / m_model->getResolution()) * m_model->getResolution();
00559 
00560 //    float height = getHeightForY(v, e->y());
00561 
00562     if (!m_editingCommand) {
00563         m_editingCommand = new TextModel::EditCommand(m_model, tr("Drag Label"));
00564     }
00565 
00566     m_editingCommand->deletePoint(m_editingPoint);
00567     m_editingPoint.frame = frame;
00568     m_editingPoint.height = height;
00569     m_editingCommand->addPoint(m_editingPoint);
00570 }
00571 
00572 void
00573 TextLayer::editEnd(View *, QMouseEvent *)
00574 {
00575 //    SVDEBUG << "TextLayer::editEnd(" << e->x() << "," << e->y() << ")" << endl;
00576     if (!m_model || !m_editing) return;
00577 
00578     if (m_editingCommand) {
00579 
00580         QString newName = m_editingCommand->getName();
00581 
00582         if (m_editingPoint.frame != m_originalPoint.frame) {
00583             if (m_editingPoint.height != m_originalPoint.height) {
00584                 newName = tr("Move Label");
00585             } else {
00586                 newName = tr("Move Label Horizontally");
00587             }
00588         } else {
00589             newName = tr("Move Label Vertically");
00590         }
00591 
00592         m_editingCommand->setName(newName);
00593         finish(m_editingCommand);
00594     }
00595     
00596     m_editingCommand = 0;
00597     m_editing = false;
00598 }
00599 
00600 bool
00601 TextLayer::editOpen(View *v, QMouseEvent *e)
00602 {
00603     if (!m_model) return false;
00604 
00605     TextModel::Point text(0);
00606     if (!getPointToDrag(v, e->x(), e->y(), text)) return false;
00607 
00608     QString label = text.label;
00609 
00610     bool ok = false;
00611     label = QInputDialog::getText(v, tr("Enter label"),
00612                                   tr("Please enter a new label:"),
00613                                   QLineEdit::Normal, label, &ok);
00614     if (ok && label != text.label) {
00615         TextModel::RelabelCommand *command =
00616             new TextModel::RelabelCommand(m_model, text, label);
00617         CommandHistory::getInstance()->addCommand(command);
00618     }
00619 
00620     return true;
00621 }    
00622 
00623 void
00624 TextLayer::moveSelection(Selection s, int newStartFrame)
00625 {
00626     if (!m_model) return;
00627 
00628     TextModel::EditCommand *command =
00629         new TextModel::EditCommand(m_model, tr("Drag Selection"));
00630 
00631     TextModel::PointList points =
00632         m_model->getPoints(s.getStartFrame(), s.getEndFrame());
00633 
00634     for (TextModel::PointList::iterator i = points.begin();
00635          i != points.end(); ++i) {
00636 
00637         if (s.contains(i->frame)) {
00638             TextModel::Point newPoint(*i);
00639             newPoint.frame = i->frame + newStartFrame - s.getStartFrame();
00640             command->deletePoint(*i);
00641             command->addPoint(newPoint);
00642         }
00643     }
00644 
00645     finish(command);
00646 }
00647 
00648 void
00649 TextLayer::resizeSelection(Selection s, Selection newSize)
00650 {
00651     if (!m_model) return;
00652 
00653     TextModel::EditCommand *command =
00654         new TextModel::EditCommand(m_model, tr("Resize Selection"));
00655 
00656     TextModel::PointList points =
00657         m_model->getPoints(s.getStartFrame(), s.getEndFrame());
00658 
00659     double ratio =
00660         double(newSize.getEndFrame() - newSize.getStartFrame()) /
00661         double(s.getEndFrame() - s.getStartFrame());
00662 
00663     for (TextModel::PointList::iterator i = points.begin();
00664          i != points.end(); ++i) {
00665 
00666         if (s.contains(i->frame)) {
00667 
00668             double target = i->frame;
00669             target = newSize.getStartFrame() + 
00670                 double(target - s.getStartFrame()) * ratio;
00671 
00672             TextModel::Point newPoint(*i);
00673             newPoint.frame = lrint(target);
00674             command->deletePoint(*i);
00675             command->addPoint(newPoint);
00676         }
00677     }
00678 
00679     finish(command);
00680 }
00681 
00682 void
00683 TextLayer::deleteSelection(Selection s)
00684 {
00685     if (!m_model) return;
00686 
00687     TextModel::EditCommand *command =
00688         new TextModel::EditCommand(m_model, tr("Delete Selection"));
00689 
00690     TextModel::PointList points =
00691         m_model->getPoints(s.getStartFrame(), s.getEndFrame());
00692 
00693     for (TextModel::PointList::iterator i = points.begin();
00694          i != points.end(); ++i) {
00695         if (s.contains(i->frame)) command->deletePoint(*i);
00696     }
00697 
00698     finish(command);
00699 }
00700 
00701 void
00702 TextLayer::copy(View *v, Selection s, Clipboard &to)
00703 {
00704     if (!m_model) return;
00705 
00706     TextModel::PointList points =
00707         m_model->getPoints(s.getStartFrame(), s.getEndFrame());
00708 
00709     for (TextModel::PointList::iterator i = points.begin();
00710          i != points.end(); ++i) {
00711         if (s.contains(i->frame)) {
00712             Clipboard::Point point(i->frame, i->height, i->label);
00713             point.setReferenceFrame(alignToReference(v, i->frame));
00714             to.addPoint(point);
00715         }
00716     }
00717 }
00718 
00719 bool
00720 TextLayer::paste(View *v, const Clipboard &from, int /* frameOffset */, bool /* interactive */)
00721 {
00722     if (!m_model) return false;
00723 
00724     const Clipboard::PointList &points = from.getPoints();
00725 
00726     bool realign = false;
00727 
00728     if (clipboardHasDifferentAlignment(v, from)) {
00729 
00730         QMessageBox::StandardButton button =
00731             QMessageBox::question(v, tr("Re-align pasted items?"),
00732                                   tr("The items 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?"),
00733                                   QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
00734                                   QMessageBox::Yes);
00735 
00736         if (button == QMessageBox::Cancel) {
00737             return false;
00738         }
00739 
00740         if (button == QMessageBox::Yes) {
00741             realign = true;
00742         }
00743     }
00744 
00745     TextModel::EditCommand *command =
00746         new TextModel::EditCommand(m_model, tr("Paste"));
00747 
00748     float valueMin = 0.0, valueMax = 1.0;
00749     for (Clipboard::PointList::const_iterator i = points.begin();
00750          i != points.end(); ++i) {
00751         if (i->haveValue()) {
00752             if (i->getValue() < valueMin) valueMin = i->getValue();
00753             if (i->getValue() > valueMax) valueMax = i->getValue();
00754         }
00755     }
00756     if (valueMax < valueMin + 1.0) valueMax = valueMin + 1.0;
00757 
00758     for (Clipboard::PointList::const_iterator i = points.begin();
00759          i != points.end(); ++i) {
00760         
00761         if (!i->haveFrame()) continue;
00762         int frame = 0;
00763         
00764         if (!realign) {
00765             
00766             frame = i->getFrame();
00767 
00768         } else {
00769 
00770             if (i->haveReferenceFrame()) {
00771                 frame = i->getReferenceFrame();
00772                 frame = alignFromReference(v, frame);
00773             } else {
00774                 frame = i->getFrame();
00775             }
00776         }
00777 
00778         TextModel::Point newPoint(frame);
00779 
00780         if (i->haveValue()) {
00781             newPoint.height = (i->getValue() - valueMin) / (valueMax - valueMin);
00782         } else {
00783             newPoint.height = 0.5;
00784         }
00785 
00786         if (i->haveLabel()) {
00787             newPoint.label = i->getLabel();
00788         } else if (i->haveValue()) {
00789             newPoint.label = QString("%1").arg(i->getValue());
00790         } else {
00791             newPoint.label = tr("New Point");
00792         }
00793         
00794         command->addPoint(newPoint);
00795     }
00796 
00797     finish(command);
00798     return true;
00799 }
00800 
00801 int
00802 TextLayer::getDefaultColourHint(bool darkbg, bool &impose)
00803 {
00804     impose = false;
00805     return ColourDatabase::getInstance()->getColourIndex
00806         (QString(darkbg ? "Bright Orange" : "Orange"));
00807 }
00808 
00809 void
00810 TextLayer::toXml(QTextStream &stream,
00811                  QString indent, QString extraAttributes) const
00812 {
00813     SingleColourLayer::toXml(stream, indent, extraAttributes);
00814 }
00815 
00816 void
00817 TextLayer::setProperties(const QXmlAttributes &attributes)
00818 {
00819     SingleColourLayer::setProperties(attributes);
00820 }
00821