Mercurial > hg > svgui
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 |