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