comparison layer/ImageLayer.cpp @ 305:013a37723c0a

* Add support for remote files to image layer
author Chris Cannam
date Fri, 05 Oct 2007 15:52:52 +0000
parents 4b7e8da8f069
children 90b9cfb5b0bb
comparison
equal deleted inserted replaced
304:4b7e8da8f069 305:013a37723c0a
19 #include "base/RealTime.h" 19 #include "base/RealTime.h"
20 #include "base/Profiler.h" 20 #include "base/Profiler.h"
21 #include "view/View.h" 21 #include "view/View.h"
22 22
23 #include "data/model/ImageModel.h" 23 #include "data/model/ImageModel.h"
24 #include "data/fileio/RemoteFile.h"
24 25
25 #include "widgets/ImageDialog.h" 26 #include "widgets/ImageDialog.h"
26 27
27 #include <QPainter> 28 #include <QPainter>
28 #include <QMouseEvent> 29 #include <QMouseEvent>
29 #include <QInputDialog> 30 #include <QInputDialog>
31 #include <QMutexLocker>
30 32
31 #include <iostream> 33 #include <iostream>
32 #include <cmath> 34 #include <cmath>
33 35
34 ImageLayer::ImageMap 36 ImageLayer::ImageMap
35 ImageLayer::m_images; 37 ImageLayer::m_images;
38
39 QMutex
40 ImageLayer::m_imageMapMutex;
36 41
37 ImageLayer::ImageLayer() : 42 ImageLayer::ImageLayer() :
38 Layer(), 43 Layer(),
39 m_model(0), 44 m_model(0),
40 m_editing(false), 45 m_editing(false),
41 m_originalPoint(0, "", ""), 46 m_originalPoint(0, "", ""),
42 m_editingPoint(0, "", ""), 47 m_editingPoint(0, "", ""),
43 m_editingCommand(0) 48 m_editingCommand(0)
44 { 49 {
45 50 }
51
52 ImageLayer::~ImageLayer()
53 {
54 for (RemoteFileMap::iterator i = m_remoteFiles.begin();
55 i != m_remoteFiles.end(); ++i) {
56 delete i->second;
57 }
46 } 58 }
47 59
48 void 60 void
49 ImageLayer::setModel(ImageModel *model) 61 ImageLayer::setModel(ImageModel *model)
50 { 62 {
51 if (m_model == model) return; 63 if (m_model == model) return;
52 m_model = model; 64 m_model = model;
53 65
54 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged())); 66 connect(m_model, SIGNAL(modelChanged()),
67 this, SIGNAL(modelChanged()));
55 connect(m_model, SIGNAL(modelChanged(size_t, size_t)), 68 connect(m_model, SIGNAL(modelChanged(size_t, size_t)),
56 this, SIGNAL(modelChanged(size_t, size_t))); 69 this, SIGNAL(modelChanged(size_t, size_t)));
57 70
58 connect(m_model, SIGNAL(completionChanged()), 71 connect(m_model, SIGNAL(completionChanged()),
59 this, SIGNAL(modelCompletionChanged())); 72 this, SIGNAL(modelCompletionChanged()));
60 73
74 // connect(m_model, SIGNAL(modelChanged()),
75 // this, SLOT(checkAddRemotes()));
76
61 // std::cerr << "ImageLayer::setModel(" << model << ")" << std::endl; 77 // std::cerr << "ImageLayer::setModel(" << model << ")" << std::endl;
78
79 // checkAddRemotes();
62 80
63 emit modelReplaced(); 81 emit modelReplaced();
64 } 82 }
65 83
66 Layer::PropertyList 84 Layer::PropertyList
145 // this image is a candidate, test it properly 163 // this image is a candidate, test it properly
146 164
147 int width = 32; 165 int width = 32;
148 if (m_scaled[v].find(p.image) != m_scaled[v].end()) { 166 if (m_scaled[v].find(p.image) != m_scaled[v].end()) {
149 width = m_scaled[v][p.image].width(); 167 width = m_scaled[v][p.image].width();
150 std::cerr << "scaled width = " << width << std::endl; 168 // std::cerr << "scaled width = " << width << std::endl;
151 } 169 }
152 170
153 if (x >= px && x < px + width) { 171 if (x >= px && x < px + width) {
154 rv.insert(p); 172 rv.insert(p);
155 } 173 }
476 { 494 {
477 if (dormant) { 495 if (dormant) {
478 // Delete the images named in the view's scaled map from the 496 // Delete the images named in the view's scaled map from the
479 // general image map as well. They can always be re-loaded 497 // general image map as well. They can always be re-loaded
480 // if it turns out another view still needs them. 498 // if it turns out another view still needs them.
499 QMutexLocker locker(&m_imageMapMutex);
481 for (ImageMap::iterator i = m_scaled[v].begin(); 500 for (ImageMap::iterator i = m_scaled[v].begin();
482 i != m_scaled[v].end(); ++i) { 501 i != m_scaled[v].end(); ++i) {
483 m_images.erase(i->first); 502 m_images.erase(i->first);
484 } 503 }
485 m_scaled.erase(v); 504 m_scaled.erase(v);
489 //!!! how to reap no-longer-used images? 508 //!!! how to reap no-longer-used images?
490 509
491 bool 510 bool
492 ImageLayer::getImageOriginalSize(QString name, QSize &size) const 511 ImageLayer::getImageOriginalSize(QString name, QSize &size) const
493 { 512 {
513 // std::cerr << "getImageOriginalSize: \"" << name.toStdString() << "\"" << std::endl;
514
515 QMutexLocker locker(&m_imageMapMutex);
494 if (m_images.find(name) == m_images.end()) { 516 if (m_images.find(name) == m_images.end()) {
495 m_images[name] = QImage(name); 517 // std::cerr << "don't have, trying to open local" << std::endl;
518 m_images[name] = QImage(getLocalFilename(name));
496 } 519 }
497 if (m_images[name].isNull()) { 520 if (m_images[name].isNull()) {
521 // std::cerr << "null image" << std::endl;
498 return false; 522 return false;
499 } else { 523 } else {
500 size = m_images[name].size(); 524 size = m_images[name].size();
501 return true; 525 return true;
502 } 526 }
505 QImage 529 QImage
506 ImageLayer::getImage(View *v, QString name, QSize maxSize) const 530 ImageLayer::getImage(View *v, QString name, QSize maxSize) const
507 { 531 {
508 bool need = false; 532 bool need = false;
509 533
510 std::cerr << "ImageLayer::getImage(" << v << ", " << name.toStdString() << ", (" 534 // std::cerr << "ImageLayer::getImage(" << v << ", " << name.toStdString() << ", ("
511 << maxSize.width() << "x" << maxSize.height() << "))" << std::endl; 535 // << maxSize.width() << "x" << maxSize.height() << "))" << std::endl;
512 536
513 if (!m_scaled[v][name].isNull() && 537 if (!m_scaled[v][name].isNull() &&
514 ((m_scaled[v][name].width() == maxSize.width() && 538 ((m_scaled[v][name].width() == maxSize.width() &&
515 m_scaled[v][name].height() <= maxSize.height()) || 539 m_scaled[v][name].height() <= maxSize.height()) ||
516 (m_scaled[v][name].width() <= maxSize.width() && 540 (m_scaled[v][name].width() <= maxSize.width() &&
517 m_scaled[v][name].height() == maxSize.height()))) { 541 m_scaled[v][name].height() == maxSize.height()))) {
518 std::cerr << "cache hit" << std::endl; 542 // std::cerr << "cache hit" << std::endl;
519 return m_scaled[v][name]; 543 return m_scaled[v][name];
520 } 544 }
521 545
546 QMutexLocker locker(&m_imageMapMutex);
547
522 if (m_images.find(name) == m_images.end()) { 548 if (m_images.find(name) == m_images.end()) {
523 m_images[name] = QImage(name); 549 m_images[name] = QImage(getLocalFilename(name));
524 } 550 }
525 551
526 if (m_images[name].isNull()) { 552 if (m_images[name].isNull()) {
527 std::cerr << "null image" << std::endl; 553 // std::cerr << "null image" << std::endl;
528 m_scaled[v][name] = QImage(); 554 m_scaled[v][name] = QImage();
529 } else if (m_images[name].width() <= maxSize.width() && 555 } else if (m_images[name].width() <= maxSize.width() &&
530 m_images[name].height() <= maxSize.height()) { 556 m_images[name].height() <= maxSize.height()) {
531 m_scaled[v][name] = m_images[name]; 557 m_scaled[v][name] = m_images[name];
532 } else { 558 } else {
586 if (!m_model || !m_editing) return; 612 if (!m_model || !m_editing) return;
587 613
588 bool ok = false; 614 bool ok = false;
589 615
590 ImageDialog dialog(tr("Select image"), "", tr("<no label>")); 616 ImageDialog dialog(tr("Select image"), "", tr("<no label>"));
617
591 if (dialog.exec() == QDialog::Accepted) { 618 if (dialog.exec() == QDialog::Accepted) {
619
620 checkAddRemote(dialog.getImage());
621
592 ImageModel::ChangeImageCommand *command = 622 ImageModel::ChangeImageCommand *command =
593 new ImageModel::ChangeImageCommand 623 new ImageModel::ChangeImageCommand
594 (m_model, m_editingPoint, dialog.getImage(), dialog.getLabel()); 624 (m_model, m_editingPoint, dialog.getImage(), dialog.getLabel());
595 m_editingCommand->addCommand(command); 625 m_editingCommand->addCommand(command);
596 } 626 }
670 ImageDialog dialog(tr("Select image"), 700 ImageDialog dialog(tr("Select image"),
671 image, 701 image,
672 label); 702 label);
673 703
674 if (dialog.exec() == QDialog::Accepted) { 704 if (dialog.exec() == QDialog::Accepted) {
705
706 checkAddRemote(dialog.getImage());
707
675 ImageModel::ChangeImageCommand *command = 708 ImageModel::ChangeImageCommand *command =
676 new ImageModel::ChangeImageCommand 709 new ImageModel::ChangeImageCommand
677 (m_model, *points.begin(), dialog.getImage(), dialog.getLabel()); 710 (m_model, *points.begin(), dialog.getImage(), dialog.getLabel());
711
678 CommandHistory::getInstance()->addCommand(command); 712 CommandHistory::getInstance()->addCommand(command);
679 } 713 }
680 714
681 return true; 715 return true;
682 } 716 }
813 command->finish(); 847 command->finish();
814 return true; 848 return true;
815 } 849 }
816 850
817 QString 851 QString
852 ImageLayer::getLocalFilename(QString img) const
853 {
854 if (m_remoteFiles.find(img) == m_remoteFiles.end()) {
855 checkAddRemote(img);
856 return img;
857 }
858 return m_remoteFiles[img]->getLocalFilename();
859 }
860
861 void
862 ImageLayer::checkAddRemote(QString img) const
863 {
864 if (RemoteFile::isRemote(img)) {
865
866 if (m_remoteFiles.find(img) != m_remoteFiles.end()) {
867 return;
868 }
869
870 QUrl url(img);
871 if (RemoteFile::canHandleScheme(url)) {
872 RemoteFile *rf = new RemoteFile(url);
873 if (rf->isOK()) {
874 m_remoteFiles[img] = rf;
875 connect(rf, SIGNAL(ready()), this, SLOT(remoteFileReady()));
876 } else {
877 delete rf;
878 }
879 }
880 }
881 }
882
883 void
884 ImageLayer::checkAddRemotes()
885 {
886 const ImageModel::PointList &points(m_model->getPoints());
887
888 for (ImageModel::PointList::const_iterator i = points.begin();
889 i != points.end(); ++i) {
890
891 checkAddRemote((*i).image);
892 }
893 }
894
895 void
896 ImageLayer::remoteFileReady()
897 {
898 // std::cerr << "ImageLayer::remoteFileReady" << std::endl;
899
900 RemoteFile *rf = dynamic_cast<RemoteFile *>(sender());
901 if (!rf) return;
902
903 QString img;
904 for (RemoteFileMap::const_iterator i = m_remoteFiles.begin();
905 i != m_remoteFiles.end(); ++i) {
906 if (i->second == rf) {
907 img = i->first;
908 // std::cerr << "it's image \"" << img.toStdString() << "\"" << std::endl;
909 break;
910 }
911 }
912 if (img == "") return;
913
914 QMutexLocker locker(&m_imageMapMutex);
915 m_images.erase(img);
916 for (ViewImageMap::iterator i = m_scaled.begin(); i != m_scaled.end(); ++i) {
917 i->second.erase(img);
918 const_cast<View *>(i->first)->update();
919 }
920 }
921
922 QString
818 ImageLayer::toXmlString(QString indent, QString extraAttributes) const 923 ImageLayer::toXmlString(QString indent, QString extraAttributes) const
819 { 924 {
820 return Layer::toXmlString(indent, extraAttributes); 925 return Layer::toXmlString(indent, extraAttributes);
821 } 926 }
822 927