File indexing completed on 2024-05-19 05:40:35

0001 /***************************************************************************
0002  *  Copyright (C) 2021 by Renaud Guezennec                               *
0003  *   http://www.rolisteam.org/contact                                      *
0004  *                                                                         *
0005  *   This software is free software; you can redistribute it and/or modify *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  *                                                                         *
0010  *   This program is distributed in the hope that it will be useful,       *
0011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0013  *   GNU General Public License for more details.                          *
0014  *                                                                         *
0015  *   You should have received a copy of the GNU General Public License     *
0016  *   along with this program; if not, write to the                         *
0017  *   Free Software Foundation, Inc.,                                       *
0018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
0019  ***************************************************************************/
0020 #include "controller/view_controller/imageselectorcontroller.h"
0021 
0022 #include <QClipboard>
0023 #include <QGuiApplication>
0024 #include <QMimeData>
0025 #include <QNetworkReply>
0026 #include <QtConcurrent>
0027 
0028 #include "utils/iohelper.h"
0029 #include "worker/iohelper.h"
0030 #include "worker/utilshelper.h"
0031 
0032 ImageSelectorController::ImageSelectorController(bool askPath, Sources sources, Shape shape, const QString& directory,
0033                                                  QObject* parent)
0034     : QObject(parent), m_sources(sources), m_shape(shape), m_askPath(askPath), m_currentDir(directory)
0035 {
0036 #ifdef HAVE_QT_NETWORK
0037     m_manager.reset(new QNetworkAccessManager());
0038     connect(m_manager.get(), &QNetworkAccessManager::finished, this,
0039             [this](QNetworkReply* reply) { setImageData(reply->readAll()); });
0040 #endif
0041 
0042     auto updateImage= [this]()
0043     {
0044         helper::utils::setContinuation<std::pair<QPixmap, QPixmap>>(
0045             QtConcurrent::run(
0046                 [this]()
0047                 {
0048                     if(m_data.isEmpty())
0049                         return std::pair<QPixmap, QPixmap>();
0050                     auto main= QImage::fromData(m_data);
0051                     return std::make_pair(QPixmap::fromImage(main),
0052                                           QPixmap::fromImage(main).scaled(m_visualSize, Qt::KeepAspectRatio));
0053                 }),
0054             this,
0055             [this](const std::pair<QPixmap, QPixmap>& imgs)
0056             {
0057                 if(m_pixmap.isNull() && imgs.first.isNull())
0058                     return;
0059 
0060                 m_pixmap= imgs.first;
0061 
0062                 m_thumbnail= imgs.second;
0063 
0064                 m_factor= static_cast<qreal>(m_pixmap.width()) / static_cast<qreal>(m_thumbnail.width());
0065                 emit pixmapChanged();
0066             });
0067     };
0068 
0069     connect(this, &ImageSelectorController::imageDataChanged, this, updateImage);
0070     connect(this, &ImageSelectorController::visualSizeChanged, this, updateImage);
0071 
0072     auto clipboard= QGuiApplication::clipboard();
0073     connect(clipboard, &QClipboard::dataChanged, this, &ImageSelectorController::contentToPasteChanged);
0074 }
0075 
0076 bool ImageSelectorController::canDrop() const
0077 {
0078     return m_sources & DragAndDrop;
0079 }
0080 
0081 bool ImageSelectorController::canPaste() const
0082 {
0083     return m_sources & Clipboard;
0084 }
0085 
0086 bool ImageSelectorController::canDownload() const
0087 {
0088 #ifdef HAVE_QT_NETWORK
0089     return m_sources & Web;
0090 #else
0091     return false;
0092 #endif
0093 }
0094 
0095 bool ImageSelectorController::askPath() const
0096 {
0097     return m_askPath;
0098 }
0099 
0100 bool ImageSelectorController::validData() const
0101 {
0102     auto const& validMovie= isMovie();
0103     auto const& validImg= !pixmap().isNull();
0104 
0105     return (validImg || validMovie);
0106 }
0107 
0108 QPixmap ImageSelectorController::pixmap() const
0109 {
0110     return m_pixmap; // QPixmap::fromImage(QImage::fromData(m_data));
0111 }
0112 
0113 QPixmap ImageSelectorController::thumbnail() const
0114 {
0115     return m_thumbnail; // QPixmap::fromImage();
0116 }
0117 
0118 QByteArray ImageSelectorController::imageData() const
0119 {
0120     return m_data;
0121 }
0122 
0123 ImageSelectorController::Shape ImageSelectorController::shape() const
0124 {
0125     return m_shape;
0126 }
0127 
0128 ImageSelectorController::Sources ImageSelectorController::sources() const
0129 {
0130     return m_sources;
0131 }
0132 
0133 QString ImageSelectorController::title() const
0134 {
0135     return m_title;
0136 }
0137 
0138 QString ImageSelectorController::address() const
0139 {
0140     return m_address.toString();
0141 }
0142 
0143 QString ImageSelectorController::currentDir() const
0144 {
0145     return m_currentDir;
0146 }
0147 
0148 bool ImageSelectorController::hasContentToPaste() const
0149 {
0150     auto clipboard= QGuiApplication::clipboard();
0151     if(!clipboard)
0152         return false;
0153     const QMimeData* mimeData= clipboard->mimeData();
0154     if(!mimeData)
0155         return false;
0156 
0157     return mimeData->hasImage();
0158 }
0159 
0160 bool ImageSelectorController::dataInShape() const
0161 {
0162     auto dataGeo= computeDataGeometry();
0163     bool res= dataGeo.isValid();
0164     if(m_shape == Square)
0165         res&= (dataGeo.height() == dataGeo.width());
0166     return res;
0167 }
0168 
0169 QSize ImageSelectorController::visualSize() const
0170 {
0171     return m_visualSize;
0172 }
0173 
0174 bool ImageSelectorController::rectInShape() const
0175 {
0176     bool res= computeDataGeometry().contains(QRect(m_rect.x()*m_factor,m_rect.y()*m_factor,m_rect.width()*m_factor,m_rect.height()*m_factor));
0177     if(m_shape == Square)
0178         res&= (m_rect.height() == m_rect.width());
0179     return res;
0180 }
0181 
0182 bool ImageSelectorController::isMovie() const
0183 {
0184     return m_movie.isValid() && m_movie.frameCount() > 1;
0185 }
0186 
0187 void ImageSelectorController::imageFromClipboard()
0188 {
0189     auto clipboard= QGuiApplication::clipboard();
0190 
0191     if(!clipboard)
0192         return;
0193     const QMimeData* mimeData= clipboard->mimeData();
0194     if(!mimeData)
0195         return;
0196 
0197     if(mimeData->hasImage())
0198     {
0199         auto pix= qvariant_cast<QPixmap>(mimeData->imageData());
0200         if(pix.isNull())
0201             return;
0202         setImageData(IOHelper::pixmapToData(pix));
0203     }
0204     else if(mimeData->hasUrls())
0205     {
0206         auto urls= mimeData->urls();
0207         if(urls.isEmpty())
0208             return;
0209         auto url= urls.first();
0210         downloadImageFrom(url);
0211     }
0212 }
0213 
0214 void ImageSelectorController::downloadImageFrom(const QUrl& url)
0215 {
0216     setAddressPrivate(url);
0217     if(m_address.isLocalFile())
0218     {
0219         openImageFromFile();
0220     }
0221     else
0222     {
0223 #ifdef HAVE_QT_NETWORK
0224         setTitle(url.fileName());
0225         m_manager->get(QNetworkRequest(m_address));
0226 #endif
0227     }
0228 }
0229 
0230 QMovie* ImageSelectorController::movie()
0231 {
0232     return &m_movie;
0233 }
0234 
0235 QRect ImageSelectorController::rect() const
0236 {
0237     return m_rect;
0238 }
0239 
0240 void ImageSelectorController::openImageFromFile()
0241 {
0242     auto local= m_address.toLocalFile();
0243     QFileInfo info(local);
0244     setTitle(info.baseName());
0245     setImageData(utils::IOHelper::loadFile(local));
0246 }
0247 
0248 QByteArray ImageSelectorController::finalImageData() const
0249 {
0250     auto data= imageData();
0251     if(m_shape != AnyShape)
0252     {
0253         auto rect= QRect(m_rect.x() * m_factor, m_rect.y() * m_factor, m_rect.width() * m_factor,
0254                          m_rect.height() * m_factor);
0255         data= IOHelper::pixmapToData(m_pixmap.copy(rect));
0256     }
0257     return data;
0258 }
0259 
0260 void ImageSelectorController::setTitle(const QString& title)
0261 {
0262     if(title == m_title)
0263         return;
0264     m_title= title;
0265     emit titleChanged();
0266 }
0267 
0268 void ImageSelectorController::setAddressPrivate(const QUrl& url)
0269 {
0270     if(m_address == url)
0271         return;
0272     m_address= url;
0273     emit addressChanged();
0274 }
0275 
0276 QRect ImageSelectorController::computeDataGeometry() const
0277 {
0278     QRect res;
0279     auto pix= pixmap();
0280     if(!pix.isNull())
0281         res= pix.rect();
0282     else if(isMovie())
0283         res= m_movie.frameRect();
0284 
0285     return res;
0286 }
0287 
0288 void ImageSelectorController::setAddress(const QString& address)
0289 {
0290     if(this->address() == QUrl::fromUserInput(address).toString())
0291         return;
0292     m_address= QUrl::fromUserInput(address);
0293     emit addressChanged();
0294 }
0295 
0296 void ImageSelectorController::setRect(const QRect& rect)
0297 {
0298     if(rect == m_rect)
0299         return;
0300     m_rect= rect;
0301     emit rectChanged();
0302 }
0303 
0304 void ImageSelectorController::setVisualSize(const QSize& visualSize)
0305 {
0306     if(visualSize == m_visualSize)
0307         return;
0308     m_visualSize= visualSize;
0309     emit visualSizeChanged();
0310 }
0311 
0312 void ImageSelectorController::setImageData(const QByteArray& array)
0313 {
0314     if(array == m_data)
0315         return;
0316     m_data= array;
0317 
0318     m_buffer.setData(m_data);
0319     m_movie.setDevice(&m_buffer);
0320     emit imageDataChanged();
0321 }