# HG changeset patch # User Chris Cannam # Date 1191599572 0 # Node ID 013a37723c0a86c70bd8b44473b17c08e2416040 # Parent 4b7e8da8f069e8200becf4de148f7f11289fd286 * Add support for remote files to image layer diff -r 4b7e8da8f069 -r 013a37723c0a layer/ImageLayer.cpp --- a/layer/ImageLayer.cpp Fri Oct 05 13:27:21 2007 +0000 +++ b/layer/ImageLayer.cpp Fri Oct 05 15:52:52 2007 +0000 @@ -21,12 +21,14 @@ #include "view/View.h" #include "data/model/ImageModel.h" +#include "data/fileio/RemoteFile.h" #include "widgets/ImageDialog.h" #include #include #include +#include #include #include @@ -34,6 +36,9 @@ ImageLayer::ImageMap ImageLayer::m_images; +QMutex +ImageLayer::m_imageMapMutex; + ImageLayer::ImageLayer() : Layer(), m_model(0), @@ -42,7 +47,14 @@ m_editingPoint(0, "", ""), m_editingCommand(0) { - +} + +ImageLayer::~ImageLayer() +{ + for (RemoteFileMap::iterator i = m_remoteFiles.begin(); + i != m_remoteFiles.end(); ++i) { + delete i->second; + } } void @@ -51,15 +63,21 @@ if (m_model == model) return; m_model = model; - connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged())); + connect(m_model, SIGNAL(modelChanged()), + this, SIGNAL(modelChanged())); connect(m_model, SIGNAL(modelChanged(size_t, size_t)), this, SIGNAL(modelChanged(size_t, size_t))); connect(m_model, SIGNAL(completionChanged()), this, SIGNAL(modelCompletionChanged())); +// connect(m_model, SIGNAL(modelChanged()), +// this, SLOT(checkAddRemotes())); + // std::cerr << "ImageLayer::setModel(" << model << ")" << std::endl; +// checkAddRemotes(); + emit modelReplaced(); } @@ -147,7 +165,7 @@ int width = 32; if (m_scaled[v].find(p.image) != m_scaled[v].end()) { width = m_scaled[v][p.image].width(); - std::cerr << "scaled width = " << width << std::endl; +// std::cerr << "scaled width = " << width << std::endl; } if (x >= px && x < px + width) { @@ -478,6 +496,7 @@ // Delete the images named in the view's scaled map from the // general image map as well. They can always be re-loaded // if it turns out another view still needs them. + QMutexLocker locker(&m_imageMapMutex); for (ImageMap::iterator i = m_scaled[v].begin(); i != m_scaled[v].end(); ++i) { m_images.erase(i->first); @@ -491,10 +510,15 @@ bool ImageLayer::getImageOriginalSize(QString name, QSize &size) const { +// std::cerr << "getImageOriginalSize: \"" << name.toStdString() << "\"" << std::endl; + + QMutexLocker locker(&m_imageMapMutex); if (m_images.find(name) == m_images.end()) { - m_images[name] = QImage(name); +// std::cerr << "don't have, trying to open local" << std::endl; + m_images[name] = QImage(getLocalFilename(name)); } if (m_images[name].isNull()) { +// std::cerr << "null image" << std::endl; return false; } else { size = m_images[name].size(); @@ -507,24 +531,26 @@ { bool need = false; - std::cerr << "ImageLayer::getImage(" << v << ", " << name.toStdString() << ", (" - << maxSize.width() << "x" << maxSize.height() << "))" << std::endl; +// std::cerr << "ImageLayer::getImage(" << v << ", " << name.toStdString() << ", (" +// << maxSize.width() << "x" << maxSize.height() << "))" << std::endl; if (!m_scaled[v][name].isNull() && ((m_scaled[v][name].width() == maxSize.width() && m_scaled[v][name].height() <= maxSize.height()) || (m_scaled[v][name].width() <= maxSize.width() && m_scaled[v][name].height() == maxSize.height()))) { - std::cerr << "cache hit" << std::endl; +// std::cerr << "cache hit" << std::endl; return m_scaled[v][name]; } + QMutexLocker locker(&m_imageMapMutex); + if (m_images.find(name) == m_images.end()) { - m_images[name] = QImage(name); + m_images[name] = QImage(getLocalFilename(name)); } if (m_images[name].isNull()) { - std::cerr << "null image" << std::endl; +// std::cerr << "null image" << std::endl; m_scaled[v][name] = QImage(); } else if (m_images[name].width() <= maxSize.width() && m_images[name].height() <= maxSize.height()) { @@ -588,7 +614,11 @@ bool ok = false; ImageDialog dialog(tr("Select image"), "", tr("")); + if (dialog.exec() == QDialog::Accepted) { + + checkAddRemote(dialog.getImage()); + ImageModel::ChangeImageCommand *command = new ImageModel::ChangeImageCommand (m_model, m_editingPoint, dialog.getImage(), dialog.getLabel()); @@ -672,9 +702,13 @@ label); if (dialog.exec() == QDialog::Accepted) { + + checkAddRemote(dialog.getImage()); + ImageModel::ChangeImageCommand *command = new ImageModel::ChangeImageCommand (m_model, *points.begin(), dialog.getImage(), dialog.getLabel()); + CommandHistory::getInstance()->addCommand(command); } @@ -815,6 +849,77 @@ } QString +ImageLayer::getLocalFilename(QString img) const +{ + if (m_remoteFiles.find(img) == m_remoteFiles.end()) { + checkAddRemote(img); + return img; + } + return m_remoteFiles[img]->getLocalFilename(); +} + +void +ImageLayer::checkAddRemote(QString img) const +{ + if (RemoteFile::isRemote(img)) { + + if (m_remoteFiles.find(img) != m_remoteFiles.end()) { + return; + } + + QUrl url(img); + if (RemoteFile::canHandleScheme(url)) { + RemoteFile *rf = new RemoteFile(url); + if (rf->isOK()) { + m_remoteFiles[img] = rf; + connect(rf, SIGNAL(ready()), this, SLOT(remoteFileReady())); + } else { + delete rf; + } + } + } +} + +void +ImageLayer::checkAddRemotes() +{ + const ImageModel::PointList &points(m_model->getPoints()); + + for (ImageModel::PointList::const_iterator i = points.begin(); + i != points.end(); ++i) { + + checkAddRemote((*i).image); + } +} + +void +ImageLayer::remoteFileReady() +{ +// std::cerr << "ImageLayer::remoteFileReady" << std::endl; + + RemoteFile *rf = dynamic_cast(sender()); + if (!rf) return; + + QString img; + for (RemoteFileMap::const_iterator i = m_remoteFiles.begin(); + i != m_remoteFiles.end(); ++i) { + if (i->second == rf) { + img = i->first; +// std::cerr << "it's image \"" << img.toStdString() << "\"" << std::endl; + break; + } + } + if (img == "") return; + + QMutexLocker locker(&m_imageMapMutex); + m_images.erase(img); + for (ViewImageMap::iterator i = m_scaled.begin(); i != m_scaled.end(); ++i) { + i->second.erase(img); + const_cast(i->first)->update(); + } +} + +QString ImageLayer::toXmlString(QString indent, QString extraAttributes) const { return Layer::toXmlString(indent, extraAttributes); diff -r 4b7e8da8f069 -r 013a37723c0a layer/ImageLayer.h --- a/layer/ImageLayer.h Fri Oct 05 13:27:21 2007 +0000 +++ b/layer/ImageLayer.h Fri Oct 05 15:52:52 2007 +0000 @@ -22,11 +22,13 @@ #include #include #include +#include #include class View; class QPainter; +class RemoteFile; class ImageLayer : public Layer { @@ -34,6 +36,7 @@ public: ImageLayer(); + virtual ~ImageLayer(); virtual void paint(View *v, QPainter &paint, QRect rect) const; @@ -93,6 +96,10 @@ void setProperties(const QXmlAttributes &attributes); +protected slots: + void checkAddRemotes(); + void remoteFileReady(); + protected: ImageModel::PointList getLocalPoints(View *v, int x, int y) const; @@ -106,11 +113,15 @@ typedef std::map ImageMap; typedef std::map ViewImageMap; - - + typedef std::map RemoteFileMap; static ImageMap m_images; + static QMutex m_imageMapMutex; mutable ViewImageMap m_scaled; + mutable RemoteFileMap m_remoteFiles; + + QString getLocalFilename(QString img) const; + void checkAddRemote(QString img) const; ImageModel *m_model; bool m_editing; diff -r 4b7e8da8f069 -r 013a37723c0a widgets/ImageDialog.cpp --- a/widgets/ImageDialog.cpp Fri Oct 05 13:27:21 2007 +0000 +++ b/widgets/ImageDialog.cpp Fri Oct 05 15:52:52 2007 +0000 @@ -23,15 +23,21 @@ #include #include #include +#include +#include +#include "data/fileio/RemoteFile.h" #include "data/fileio/FileFinder.h" +#include + ImageDialog::ImageDialog(QString title, QString image, QString label, QWidget *parent) : QDialog(parent), - m_imagePreview(0) + m_imagePreview(0), + m_remoteFile(0) { setWindowTitle(title); @@ -52,12 +58,15 @@ ++row; - subgrid->addWidget(new QLabel(tr("File:")), row, 0); + subgrid->addWidget(new QLabel(tr("File or URL:")), row, 0); m_imageEdit = new QLineEdit; subgrid->addWidget(m_imageEdit, row, 1, 1, 1); + connect(m_imageEdit, SIGNAL(textEdited(const QString &)), this, SLOT(imageEditEdited(const QString &))); + connect(m_imageEdit, SIGNAL(editingFinished()), + this, SLOT(imageEditEdited())); QPushButton *browse = new QPushButton(tr("Browse...")); connect(browse, SIGNAL(clicked()), this, SLOT(browseClicked())); @@ -100,6 +109,7 @@ ImageDialog::~ImageDialog() { + delete m_remoteFile; } QString @@ -140,7 +150,16 @@ } void -ImageDialog::imageEditEdited(const QString &) +ImageDialog::imageEditEdited(const QString &s) +{ + if (s.startsWith("http:") || s.startsWith("ftp:")) { + return; + } + updatePreview(); +} + +void +ImageDialog::imageEditEdited() { updatePreview(); } @@ -155,7 +174,35 @@ m_okButton->setEnabled(img != ""); if (img != m_loadedImageFile) { - m_loadedImage = QPixmap(img); + + QString fileName = img; + delete m_remoteFile; + m_remoteFile = 0; + + if (RemoteFile::isRemote(fileName)) { + QUrl url(fileName); + if (!RemoteFile::canHandleScheme(url)) { + QMessageBox::critical(this, tr("Unsupported scheme in URL"), + tr("The URL scheme \"%1\" is not supported") + .arg(url.scheme())); + } else { + m_remoteFile = new RemoteFile(url); + m_remoteFile->wait(); + if (!m_remoteFile->isOK()) { + QMessageBox::critical(this, tr("File download failed"), + tr("Failed to download URL \"%1\": %2") + .arg(url.toString()).arg(m_remoteFile->getErrorString())); + delete m_remoteFile; + m_remoteFile = 0; + } else { + fileName = m_remoteFile->getLocalFilename(); + } + } + } + +// std::cerr << "image filename: \"" << fileName.toStdString() << "\"" << std::endl; + + m_loadedImage = QPixmap(fileName); m_loadedImageFile = img; } diff -r 4b7e8da8f069 -r 013a37723c0a widgets/ImageDialog.h --- a/widgets/ImageDialog.h Fri Oct 05 13:27:21 2007 +0000 +++ b/widgets/ImageDialog.h Fri Oct 05 15:52:52 2007 +0000 @@ -22,6 +22,7 @@ class QLineEdit; class QLabel; class QPushButton; +class RemoteFile; class ImageDialog : public QDialog { @@ -50,6 +51,7 @@ protected slots: void browseClicked(); void imageEditEdited(const QString &); + void imageEditEdited(); protected: void resizeEvent(QResizeEvent *); @@ -62,6 +64,8 @@ QPixmap m_loadedImage; QPushButton *m_okButton; + + RemoteFile *m_remoteFile; }; #endif