ImageLayer.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 "ImageLayer.h"
00017 
00018 #include "data/model/Model.h"
00019 #include "base/RealTime.h"
00020 #include "base/Profiler.h"
00021 #include "view/View.h"
00022 
00023 #include "data/model/ImageModel.h"
00024 #include "data/fileio/FileSource.h"
00025 
00026 #include "widgets/ImageDialog.h"
00027 
00028 #include <QPainter>
00029 #include <QMouseEvent>
00030 #include <QInputDialog>
00031 #include <QMutexLocker>
00032 #include <QTextStream>
00033 #include <QMessageBox>
00034 
00035 #include <iostream>
00036 #include <cmath>
00037 
00038 ImageLayer::ImageMap
00039 ImageLayer::m_images;
00040 
00041 QMutex
00042 ImageLayer::m_imageMapMutex;
00043 
00044 ImageLayer::ImageLayer() :
00045     Layer(),
00046     m_model(0),
00047     m_editing(false),
00048     m_originalPoint(0, "", ""),
00049     m_editingPoint(0, "", ""),
00050     m_editingCommand(0)
00051 {
00052 }
00053 
00054 ImageLayer::~ImageLayer()
00055 {
00056     for (FileSourceMap::iterator i = m_remoteFiles.begin();
00057          i != m_remoteFiles.end(); ++i) {
00058         delete i->second;
00059     }
00060 }
00061 
00062 void
00063 ImageLayer::setModel(ImageModel *model)
00064 {
00065     if (m_model == model) return;
00066     m_model = model;
00067 
00068     connectSignals(m_model);
00069 
00070     emit modelReplaced();
00071 }
00072 
00073 Layer::PropertyList
00074 ImageLayer::getProperties() const
00075 {
00076     return Layer::getProperties();
00077 }
00078 
00079 QString
00080 ImageLayer::getPropertyLabel(const PropertyName &name) const
00081 {
00082     return "";
00083 }
00084 
00085 Layer::PropertyType
00086 ImageLayer::getPropertyType(const PropertyName &name) const
00087 {
00088     return Layer::getPropertyType(name);
00089 }
00090 
00091 int
00092 ImageLayer::getPropertyRangeAndValue(const PropertyName &name,
00093                                     int *min, int *max, int *deflt) const
00094 {
00095     return Layer::getPropertyRangeAndValue(name, min, max, deflt);
00096 }
00097 
00098 QString
00099 ImageLayer::getPropertyValueLabel(const PropertyName &name,
00100                                  int value) const
00101 {
00102     return Layer::getPropertyValueLabel(name, value);
00103 }
00104 
00105 void
00106 ImageLayer::setProperty(const PropertyName &name, int value)
00107 {
00108     Layer::setProperty(name, value);
00109 }
00110 
00111 bool
00112 ImageLayer::getValueExtents(float &, float &, bool &, QString &) const
00113 {
00114     return false;
00115 }
00116 
00117 bool
00118 ImageLayer::isLayerScrollable(const View *v) const
00119 {
00120     return true;
00121 }
00122 
00123 
00124 ImageModel::PointList
00125 ImageLayer::getLocalPoints(View *v, int x, int y) const
00126 {
00127     if (!m_model) return ImageModel::PointList();
00128 
00129 //    std::cerr << "ImageLayer::getLocalPoints(" << x << "," << y << "):";
00130     const ImageModel::PointList &points(m_model->getPoints());
00131 
00132     ImageModel::PointList rv;
00133 
00134     for (ImageModel::PointList::const_iterator i = points.begin();
00135          i != points.end(); ) {
00136 
00137         const ImageModel::Point &p(*i);
00138         int px = v->getXForFrame(p.frame);
00139         if (px > x) break;
00140 
00141         ++i;
00142         if (i != points.end()) {
00143             int nx = v->getXForFrame((*i).frame);
00144             if (nx < x) {
00145                 // as we aim not to overlap the images, if the following
00146                 // image begins to the left of a point then the current
00147                 // one may be assumed to end to the left of it as well.
00148                 continue;
00149             }
00150         }
00151 
00152         // this image is a candidate, test it properly
00153 
00154         int width = 32;
00155         if (m_scaled[v].find(p.image) != m_scaled[v].end()) {
00156             width = m_scaled[v][p.image].width();
00157 //            std::cerr << "scaled width = " << width << std::endl;
00158         }
00159 
00160         if (x >= px && x < px + width) {
00161             rv.insert(p);
00162         }
00163     }
00164 
00165 //    std::cerr << rv.size() << " point(s)" << std::endl;
00166 
00167     return rv;
00168 }
00169 
00170 QString
00171 ImageLayer::getFeatureDescription(View *v, QPoint &pos) const
00172 {
00173     int x = pos.x();
00174 
00175     if (!m_model || !m_model->getSampleRate()) return "";
00176 
00177     ImageModel::PointList points = getLocalPoints(v, x, pos.y());
00178 
00179     if (points.empty()) {
00180         if (!m_model->isReady()) {
00181             return tr("In progress");
00182         } else {
00183             return "";
00184         }
00185     }
00186 
00187     long useFrame = points.begin()->frame;
00188 
00189     RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate());
00190 
00191     QString text;
00192 /*    
00193     if (points.begin()->label == "") {
00194         text = QString(tr("Time:\t%1\nHeight:\t%2\nLabel:\t%3"))
00195             .arg(rt.toText(true).c_str())
00196             .arg(points.begin()->height)
00197             .arg(points.begin()->label);
00198     }
00199 
00200     pos = QPoint(v->getXForFrame(useFrame),
00201                  getYForHeight(v, points.begin()->height));
00202 */
00203     return text;
00204 }
00205 
00206 
00208 
00209 bool
00210 ImageLayer::snapToFeatureFrame(View *v, int &frame,
00211                               size_t &resolution,
00212                               SnapType snap) const
00213 {
00214     if (!m_model) {
00215         return Layer::snapToFeatureFrame(v, frame, resolution, snap);
00216     }
00217 
00218     resolution = m_model->getResolution();
00219     ImageModel::PointList points;
00220 
00221     if (snap == SnapNeighbouring) {
00222         
00223         points = getLocalPoints(v, v->getXForFrame(frame), -1);
00224         if (points.empty()) return false;
00225         frame = points.begin()->frame;
00226         return true;
00227     }    
00228 
00229     points = m_model->getPoints(frame, frame);
00230     int snapped = frame;
00231     bool found = false;
00232 
00233     for (ImageModel::PointList::const_iterator i = points.begin();
00234          i != points.end(); ++i) {
00235 
00236         if (snap == SnapRight) {
00237 
00238             if (i->frame > frame) {
00239                 snapped = i->frame;
00240                 found = true;
00241                 break;
00242             }
00243 
00244         } else if (snap == SnapLeft) {
00245 
00246             if (i->frame <= frame) {
00247                 snapped = i->frame;
00248                 found = true; // don't break, as the next may be better
00249             } else {
00250                 break;
00251             }
00252 
00253         } else { // nearest
00254 
00255             ImageModel::PointList::const_iterator j = i;
00256             ++j;
00257 
00258             if (j == points.end()) {
00259 
00260                 snapped = i->frame;
00261                 found = true;
00262                 break;
00263 
00264             } else if (j->frame >= frame) {
00265 
00266                 if (j->frame - frame < frame - i->frame) {
00267                     snapped = j->frame;
00268                 } else {
00269                     snapped = i->frame;
00270                 }
00271                 found = true;
00272                 break;
00273             }
00274         }
00275     }
00276 
00277     frame = snapped;
00278     return found;
00279 }
00280 
00281 void
00282 ImageLayer::paint(View *v, QPainter &paint, QRect rect) const
00283 {
00284     if (!m_model || !m_model->isOK()) return;
00285 
00286     int sampleRate = m_model->getSampleRate();
00287     if (!sampleRate) return;
00288 
00289 //    Profiler profiler("ImageLayer::paint", true);
00290 
00291 //    int x0 = rect.left(), x1 = rect.right();
00292     int x0 = 0, x1 = v->width();
00293 
00294     long frame0 = v->getFrameForX(x0);
00295     long frame1 = v->getFrameForX(x1);
00296 
00297     ImageModel::PointList points(m_model->getPoints(frame0, frame1));
00298     if (points.empty()) return;
00299 
00300     paint.save();
00301     paint.setClipRect(rect.x(), 0, rect.width(), v->height());
00302 
00303     QColor penColour;
00304     penColour = v->getForeground();
00305 
00306     QColor brushColour;
00307     brushColour = v->getBackground();
00308 
00309     int h, s, val;
00310     brushColour.getHsv(&h, &s, &val);
00311     brushColour.setHsv(h, s, 255, 240);
00312 
00313     paint.setPen(penColour);
00314     paint.setBrush(brushColour);
00315     paint.setRenderHint(QPainter::Antialiasing, true);
00316 
00317     for (ImageModel::PointList::const_iterator i = points.begin();
00318          i != points.end(); ++i) {
00319 
00320         const ImageModel::Point &p(*i);
00321 
00322         int x = v->getXForFrame(p.frame);
00323 
00324         int nx = x + 2000;
00325         ImageModel::PointList::const_iterator j = i;
00326         ++j;
00327         if (j != points.end()) {
00328             int jx = v->getXForFrame(j->frame);
00329             if (jx < nx) nx = jx;
00330         }
00331 
00332         drawImage(v, paint, p, x, nx);
00333     }
00334 
00335     paint.setRenderHint(QPainter::Antialiasing, false);
00336     paint.restore();
00337 }
00338 
00339 void
00340 ImageLayer::drawImage(View *v, QPainter &paint, const ImageModel::Point &p,
00341                       int x, int nx) const
00342 {
00343     QString label = p.label;
00344     QString imageName = p.image;
00345 
00346     QImage image;
00347     QString additionalText;
00348 
00349     QSize imageSize;
00350     if (!getImageOriginalSize(imageName, imageSize)) {
00351         image = QImage(":icons/emptypage.png");
00352         imageSize = image.size();
00353         additionalText = imageName;
00354     }
00355 
00356     int topMargin = 10;
00357     int bottomMargin = 10;
00358     int spacing = 5;
00359 
00360     if (v->height() < 100) {
00361         topMargin = 5;
00362         bottomMargin = 5;
00363     }
00364 
00365     int maxBoxHeight = v->height() - topMargin - bottomMargin;
00366 
00367     int availableWidth = nx - x - 3;
00368     if (availableWidth < 20) availableWidth = 20;
00369 
00370     QRect labelRect;
00371 
00372     if (label != "") {
00373 
00374         int likelyHeight = v->height() / 4;
00375 
00376         int likelyWidth = // available height times image aspect
00377             ((maxBoxHeight - likelyHeight) * imageSize.width())
00378             / imageSize.height();
00379 
00380         if (likelyWidth > imageSize.width()) {
00381             likelyWidth = imageSize.width();
00382         }
00383 
00384         if (likelyWidth > availableWidth) {
00385             likelyWidth = availableWidth;
00386         }
00387 
00388         int singleWidth = paint.fontMetrics().width(label);
00389         if (singleWidth < availableWidth && singleWidth < likelyWidth * 2) {
00390             likelyWidth = singleWidth + 4;
00391         }
00392 
00393         labelRect = paint.fontMetrics().boundingRect
00394             (QRect(0, 0, likelyWidth, likelyHeight),
00395              Qt::AlignCenter | Qt::TextWordWrap, label);
00396 
00397         labelRect.setWidth(labelRect.width() + 6);
00398     }
00399 
00400     if (image.isNull()) {
00401         image = getImage(v, imageName,
00402                          QSize(availableWidth,
00403                                maxBoxHeight - labelRect.height()));
00404     }
00405 
00406     int boxWidth = image.width();
00407     if (boxWidth < labelRect.width()) {
00408         boxWidth = labelRect.width();
00409     }
00410 
00411     int boxHeight = image.height();
00412     if (label != "") {
00413         boxHeight += labelRect.height() + spacing;
00414     }
00415 
00416     int division = image.height();
00417 
00418     if (additionalText != "") {
00419 
00420         paint.save();
00421 
00422         QFont font(paint.font());
00423         font.setItalic(true);
00424         paint.setFont(font);
00425 
00426         int tw = paint.fontMetrics().width(additionalText);
00427         if (tw > availableWidth) {
00428             tw = availableWidth;
00429         }
00430         if (boxWidth < tw) {
00431             boxWidth = tw;
00432         }
00433         boxHeight += paint.fontMetrics().height();
00434         division += paint.fontMetrics().height();
00435     }                
00436 
00437     bottomMargin = v->height() - topMargin - boxHeight;
00438     if (bottomMargin > topMargin + v->height()/7) {
00439         topMargin += v->height()/8;
00440         bottomMargin -= v->height()/8;
00441     }
00442 
00443     paint.drawRect(x - 1,
00444                    topMargin - 1,
00445                    boxWidth + 2,
00446                    boxHeight + 2);
00447 
00448     int imageY;
00449     if (label != "") {
00450         imageY = topMargin + labelRect.height() + spacing;
00451     } else {
00452         imageY = topMargin;
00453     }
00454 
00455     paint.drawImage(x + (boxWidth - image.width())/2,
00456                     imageY,
00457                     image);
00458 
00459     if (additionalText != "") {
00460         paint.drawText(x,
00461                        imageY + image.height() + paint.fontMetrics().ascent(),
00462                        additionalText);
00463         paint.restore();
00464     }
00465 
00466     if (label != "") {
00467         paint.drawLine(x,
00468                        topMargin + labelRect.height() + spacing,
00469                        x + boxWidth, 
00470                        topMargin + labelRect.height() + spacing);
00471 
00472         paint.drawText(QRect(x,
00473                              topMargin,
00474                              boxWidth,
00475                              labelRect.height()),
00476                        Qt::AlignCenter | Qt::TextWordWrap,
00477                        label);
00478     }
00479 }
00480 
00481 void
00482 ImageLayer::setLayerDormant(const View *v, bool dormant)
00483 {
00484     if (dormant) {
00485         // Delete the images named in the view's scaled map from the
00486         // general image map as well.  They can always be re-loaded
00487         // if it turns out another view still needs them.
00488         QMutexLocker locker(&m_imageMapMutex);
00489         for (ImageMap::iterator i = m_scaled[v].begin();
00490              i != m_scaled[v].end(); ++i) {
00491             m_images.erase(i->first);
00492         }
00493         m_scaled.erase(v);
00494     }
00495 }
00496 
00498 
00499 bool
00500 ImageLayer::getImageOriginalSize(QString name, QSize &size) const
00501 {
00502 //    std::cerr << "getImageOriginalSize: \"" << name.toStdString() << "\"" << std::endl;
00503 
00504     QMutexLocker locker(&m_imageMapMutex);
00505     if (m_images.find(name) == m_images.end()) {
00506 //        std::cerr << "don't have, trying to open local" << std::endl;
00507         m_images[name] = QImage(getLocalFilename(name));
00508     }
00509     if (m_images[name].isNull()) {
00510 //        std::cerr << "null image" << std::endl;
00511         return false;
00512     } else {
00513         size = m_images[name].size();
00514         return true;
00515     }
00516 }
00517 
00518 QImage 
00519 ImageLayer::getImage(View *v, QString name, QSize maxSize) const
00520 {
00521     bool need = false;
00522 
00523 //    std::cerr << "ImageLayer::getImage(" << v << ", " << name.toStdString() << ", ("
00524 //              << maxSize.width() << "x" << maxSize.height() << "))" << std::endl;
00525 
00526     if (!m_scaled[v][name].isNull()  &&
00527         ((m_scaled[v][name].width()  == maxSize.width() &&
00528           m_scaled[v][name].height() <= maxSize.height()) ||
00529          (m_scaled[v][name].width()  <= maxSize.width() &&
00530           m_scaled[v][name].height() == maxSize.height()))) {
00531 //        std::cerr << "cache hit" << std::endl;
00532         return m_scaled[v][name];
00533     }
00534 
00535     QMutexLocker locker(&m_imageMapMutex);
00536 
00537     if (m_images.find(name) == m_images.end()) {
00538         m_images[name] = QImage(getLocalFilename(name));
00539     }
00540 
00541     if (m_images[name].isNull()) {
00542 //        std::cerr << "null image" << std::endl;
00543         m_scaled[v][name] = QImage();
00544     } else if (m_images[name].width() <= maxSize.width() &&
00545                m_images[name].height() <= maxSize.height()) {
00546         m_scaled[v][name] = m_images[name];
00547     } else {
00548         m_scaled[v][name] =
00549             m_images[name].scaled(maxSize,
00550                                   Qt::KeepAspectRatio,
00551                                   Qt::SmoothTransformation);
00552     }
00553 
00554     return m_scaled[v][name];
00555 }
00556 
00557 void
00558 ImageLayer::drawStart(View *v, QMouseEvent *e)
00559 {
00560 //    std::cerr << "ImageLayer::drawStart(" << e->x() << "," << e->y() << ")" << std::endl;
00561 
00562     if (!m_model) {
00563         std::cerr << "ImageLayer::drawStart: no model" << std::endl;
00564         return;
00565     }
00566 
00567     long frame = v->getFrameForX(e->x());
00568     if (frame < 0) frame = 0;
00569     frame = frame / m_model->getResolution() * m_model->getResolution();
00570 
00571     m_editingPoint = ImageModel::Point(frame, "", "");
00572     m_originalPoint = m_editingPoint;
00573 
00574     if (m_editingCommand) m_editingCommand->finish();
00575     m_editingCommand = new ImageModel::EditCommand(m_model, "Add Image");
00576     m_editingCommand->addPoint(m_editingPoint);
00577 
00578     m_editing = true;
00579 }
00580 
00581 void
00582 ImageLayer::drawDrag(View *v, QMouseEvent *e)
00583 {
00584 //    std::cerr << "ImageLayer::drawDrag(" << e->x() << "," << e->y() << ")" << std::endl;
00585 
00586     if (!m_model || !m_editing) return;
00587 
00588     long frame = v->getFrameForX(e->x());
00589     if (frame < 0) frame = 0;
00590     frame = frame / m_model->getResolution() * m_model->getResolution();
00591 
00592     m_editingCommand->deletePoint(m_editingPoint);
00593     m_editingPoint.frame = frame;
00594     m_editingCommand->addPoint(m_editingPoint);
00595 }
00596 
00597 void
00598 ImageLayer::drawEnd(View *v, QMouseEvent *)
00599 {
00600 //    std::cerr << "ImageLayer::drawEnd(" << e->x() << "," << e->y() << ")" << std::endl;
00601     if (!m_model || !m_editing) return;
00602 
00603     bool ok = false;
00604 
00605     ImageDialog dialog(tr("Select image"), "", "");
00606 
00607     if (dialog.exec() == QDialog::Accepted) {
00608 
00609         checkAddRemote(dialog.getImage());
00610 
00611         ImageModel::ChangeImageCommand *command =
00612             new ImageModel::ChangeImageCommand
00613             (m_model, m_editingPoint, dialog.getImage(), dialog.getLabel());
00614         m_editingCommand->addCommand(command);
00615     } else {
00616         m_editingCommand->deletePoint(m_editingPoint);
00617     }
00618 
00619     m_editingCommand->finish();
00620     m_editingCommand = 0;
00621     m_editing = false;
00622 }
00623 
00624 bool
00625 ImageLayer::addImage(long frame, QString url)
00626 {
00627     QImage image(getLocalFilename(url));
00628     if (image.isNull()) {
00629         delete m_remoteFiles[url];
00630         m_remoteFiles.erase(url);
00631         return false;
00632     }
00633 
00634     ImageModel::Point point(frame, url, "");
00635     ImageModel::EditCommand *command =
00636         new ImageModel::EditCommand(m_model, "Add Image");
00637     command->addPoint(point);
00638     command->finish();
00639     return true;
00640 }
00641 
00642 void
00643 ImageLayer::editStart(View *v, QMouseEvent *e)
00644 {
00645 //    std::cerr << "ImageLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl;
00646 
00647     if (!m_model) return;
00648 
00649     ImageModel::PointList points = getLocalPoints(v, e->x(), e->y());
00650     if (points.empty()) return;
00651 
00652     m_editOrigin = e->pos();
00653     m_editingPoint = *points.begin();
00654     m_originalPoint = m_editingPoint;
00655 
00656     if (m_editingCommand) {
00657         m_editingCommand->finish();
00658         m_editingCommand = 0;
00659     }
00660 
00661     m_editing = true;
00662 }
00663 
00664 void
00665 ImageLayer::editDrag(View *v, QMouseEvent *e)
00666 {
00667     if (!m_model || !m_editing) return;
00668 
00669     long frameDiff = v->getFrameForX(e->x()) - v->getFrameForX(m_editOrigin.x());
00670     long frame = m_originalPoint.frame + frameDiff;
00671 
00672     if (frame < 0) frame = 0;
00673     frame = (frame / m_model->getResolution()) * m_model->getResolution();
00674 
00675     if (!m_editingCommand) {
00676         m_editingCommand = new ImageModel::EditCommand(m_model, tr("Move Image"));
00677     }
00678 
00679     m_editingCommand->deletePoint(m_editingPoint);
00680     m_editingPoint.frame = frame;
00681     m_editingCommand->addPoint(m_editingPoint);
00682 }
00683 
00684 void
00685 ImageLayer::editEnd(View *, QMouseEvent *)
00686 {
00687 //    std::cerr << "ImageLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl;
00688     if (!m_model || !m_editing) return;
00689 
00690     if (m_editingCommand) {
00691         m_editingCommand->finish();
00692     }
00693     
00694     m_editingCommand = 0;
00695     m_editing = false;
00696 }
00697 
00698 bool
00699 ImageLayer::editOpen(View *v, QMouseEvent *e)
00700 {
00701     if (!m_model) return false;
00702 
00703     ImageModel::PointList points = getLocalPoints(v, e->x(), e->y());
00704     if (points.empty()) return false;
00705 
00706     QString image = points.begin()->image;
00707     QString label = points.begin()->label;
00708 
00709     ImageDialog dialog(tr("Select image"),
00710                        image,
00711                        label);
00712 
00713     if (dialog.exec() == QDialog::Accepted) {
00714 
00715         checkAddRemote(dialog.getImage());
00716 
00717         ImageModel::ChangeImageCommand *command =
00718             new ImageModel::ChangeImageCommand
00719             (m_model, *points.begin(), dialog.getImage(), dialog.getLabel());
00720 
00721         CommandHistory::getInstance()->addCommand(command);
00722     }
00723 
00724     return true;
00725 }    
00726 
00727 void
00728 ImageLayer::moveSelection(Selection s, size_t newStartFrame)
00729 {
00730     if (!m_model) return;
00731 
00732     ImageModel::EditCommand *command =
00733         new ImageModel::EditCommand(m_model, tr("Drag Selection"));
00734 
00735     ImageModel::PointList points =
00736         m_model->getPoints(s.getStartFrame(), s.getEndFrame());
00737 
00738     for (ImageModel::PointList::iterator i = points.begin();
00739          i != points.end(); ++i) {
00740 
00741         if (s.contains(i->frame)) {
00742             ImageModel::Point newPoint(*i);
00743             newPoint.frame = i->frame + newStartFrame - s.getStartFrame();
00744             command->deletePoint(*i);
00745             command->addPoint(newPoint);
00746         }
00747     }
00748 
00749     command->finish();
00750 }
00751 
00752 void
00753 ImageLayer::resizeSelection(Selection s, Selection newSize)
00754 {
00755     if (!m_model) return;
00756 
00757     ImageModel::EditCommand *command =
00758         new ImageModel::EditCommand(m_model, tr("Resize Selection"));
00759 
00760     ImageModel::PointList points =
00761         m_model->getPoints(s.getStartFrame(), s.getEndFrame());
00762 
00763     double ratio =
00764         double(newSize.getEndFrame() - newSize.getStartFrame()) /
00765         double(s.getEndFrame() - s.getStartFrame());
00766 
00767     for (ImageModel::PointList::iterator i = points.begin();
00768          i != points.end(); ++i) {
00769 
00770         if (s.contains(i->frame)) {
00771 
00772             double target = i->frame;
00773             target = newSize.getStartFrame() + 
00774                 double(target - s.getStartFrame()) * ratio;
00775 
00776             ImageModel::Point newPoint(*i);
00777             newPoint.frame = lrint(target);
00778             command->deletePoint(*i);
00779             command->addPoint(newPoint);
00780         }
00781     }
00782 
00783     command->finish();
00784 }
00785 
00786 void
00787 ImageLayer::deleteSelection(Selection s)
00788 {
00789     if (!m_model) return;
00790 
00791     ImageModel::EditCommand *command =
00792         new ImageModel::EditCommand(m_model, tr("Delete Selection"));
00793 
00794     ImageModel::PointList points =
00795         m_model->getPoints(s.getStartFrame(), s.getEndFrame());
00796 
00797     for (ImageModel::PointList::iterator i = points.begin();
00798          i != points.end(); ++i) {
00799         if (s.contains(i->frame)) command->deletePoint(*i);
00800     }
00801 
00802     command->finish();
00803 }
00804 
00805 void
00806 ImageLayer::copy(View *v, Selection s, Clipboard &to)
00807 {
00808     if (!m_model) return;
00809 
00810     ImageModel::PointList points =
00811         m_model->getPoints(s.getStartFrame(), s.getEndFrame());
00812 
00813     for (ImageModel::PointList::iterator i = points.begin();
00814          i != points.end(); ++i) {
00815         if (s.contains(i->frame)) {
00816             Clipboard::Point point(i->frame, i->label);
00817             point.setReferenceFrame(alignToReference(v, i->frame));
00818             to.addPoint(point);
00819         }
00820     }
00821 }
00822 
00823 bool
00824 ImageLayer::paste(View *v, const Clipboard &from, int frameOffset, bool /* interactive */)
00825 {
00826     if (!m_model) return false;
00827 
00828     const Clipboard::PointList &points = from.getPoints();
00829 
00830     bool realign = false;
00831 
00832     if (clipboardHasDifferentAlignment(v, from)) {
00833 
00834         QMessageBox::StandardButton button =
00835             QMessageBox::question(v, tr("Re-align pasted items?"),
00836                                   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?"),
00837                                   QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
00838                                   QMessageBox::Yes);
00839 
00840         if (button == QMessageBox::Cancel) {
00841             return false;
00842         }
00843 
00844         if (button == QMessageBox::Yes) {
00845             realign = true;
00846         }
00847     }
00848 
00849     ImageModel::EditCommand *command =
00850         new ImageModel::EditCommand(m_model, tr("Paste"));
00851 
00852     for (Clipboard::PointList::const_iterator i = points.begin();
00853          i != points.end(); ++i) {
00854         
00855         if (!i->haveFrame()) continue;
00856 
00857         size_t frame = 0;
00858 
00859         if (!realign) {
00860             
00861             frame = i->getFrame();
00862 
00863         } else {
00864 
00865             if (i->haveReferenceFrame()) {
00866                 frame = i->getReferenceFrame();
00867                 frame = alignFromReference(v, frame);
00868             } else {
00869                 frame = i->getFrame();
00870             }
00871         }
00872 
00873         ImageModel::Point newPoint(frame);
00874 
00876         
00877         if (i->haveLabel()) {
00878             newPoint.label = i->getLabel();
00879         } else if (i->haveValue()) {
00880             newPoint.label = QString("%1").arg(i->getValue());
00881         } else {
00882             newPoint.label = tr("New Point");
00883         }
00884         
00885         command->addPoint(newPoint);
00886     }
00887 
00888     command->finish();
00889     return true;
00890 }
00891 
00892 QString
00893 ImageLayer::getLocalFilename(QString img) const
00894 {
00895     if (m_remoteFiles.find(img) == m_remoteFiles.end()) {
00896         checkAddRemote(img);
00897         if (m_remoteFiles.find(img) == m_remoteFiles.end()) {
00898             return img;
00899         }
00900     }
00901     return m_remoteFiles[img]->getLocalFilename();
00902 }
00903 
00904 void
00905 ImageLayer::checkAddRemote(QString img) const
00906 {
00907     if (FileSource::isRemote(img)) {
00908 
00909         std::cerr << "ImageLayer::checkAddRemote(" << img.toStdString() << "): yes, trying..." << std::endl;
00910 
00911         if (m_remoteFiles.find(img) != m_remoteFiles.end()) {
00912             return;
00913         }
00914 
00915         FileSource *rf = new FileSource(img, FileSource::ProgressDialog);
00916         if (rf->isOK()) {
00917             std::cerr << "ok, adding it (local filename = " << rf->getLocalFilename().toStdString() << ")" << std::endl;
00918             m_remoteFiles[img] = rf;
00919             connect(rf, SIGNAL(ready()), this, SLOT(remoteFileReady()));
00920         } else {
00921             delete rf;
00922         }
00923     }
00924 }
00925 
00926 void
00927 ImageLayer::checkAddRemotes()
00928 {
00929     const ImageModel::PointList &points(m_model->getPoints());
00930 
00931     for (ImageModel::PointList::const_iterator i = points.begin();
00932          i != points.end(); ++i) {
00933         
00934         checkAddRemote((*i).image);
00935     }
00936 }
00937 
00938 void
00939 ImageLayer::remoteFileReady()
00940 {
00941 //    std::cerr << "ImageLayer::remoteFileReady" << std::endl;
00942 
00943     FileSource *rf = dynamic_cast<FileSource *>(sender());
00944     if (!rf) return;
00945 
00946     QString img;
00947     for (FileSourceMap::const_iterator i = m_remoteFiles.begin();
00948          i != m_remoteFiles.end(); ++i) {
00949         if (i->second == rf) {
00950             img = i->first;
00951 //            std::cerr << "it's image \"" << img.toStdString() << "\"" << std::endl;
00952             break;
00953         }
00954     }
00955     if (img == "") return;
00956 
00957     QMutexLocker locker(&m_imageMapMutex);
00958     m_images.erase(img);
00959     for (ViewImageMap::iterator i = m_scaled.begin(); i != m_scaled.end(); ++i) {
00960         i->second.erase(img);
00961         emit modelChanged();
00962     }
00963 }
00964 
00965 void
00966 ImageLayer::toXml(QTextStream &stream,
00967                   QString indent, QString extraAttributes) const
00968 {
00969     Layer::toXml(stream, indent, extraAttributes);
00970 }
00971 
00972 void
00973 ImageLayer::setProperties(const QXmlAttributes &attributes)
00974 {
00975 }
00976 

Generated on Wed Feb 20 15:45:25 2008 for SonicVisualiser by  doxygen 1.5.1