File indexing completed on 2025-01-19 03:53:52

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2008-03-13
0007  * Description : Image files selection dialog - Improved Qt based file dialog.
0008  *
0009  * SPDX-FileCopyrightText: 2008-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "imagedialog_p.h"
0016 
0017 namespace Digikam
0018 {
0019 
0020 class Q_DECL_HIDDEN ImageDialog::Private
0021 {
0022 
0023 public:
0024 
0025     explicit Private()
0026         : dlg         (nullptr),
0027           provider    (nullptr),
0028           showToolTips(true),
0029           toolTipTimer(nullptr),
0030           toolTip     (nullptr),
0031           toolTipView (nullptr)
0032     {
0033     }
0034 
0035     QStringList               fileFormats;
0036     QList<QUrl>               urls;
0037     DFileDialog*              dlg;
0038     ImageDialogIconProvider*  provider;
0039     bool                      showToolTips;
0040     QTimer*                   toolTipTimer;
0041     ImageDialogToolTip*       toolTip;
0042     QAbstractItemView*        toolTipView;
0043     QModelIndex               toolTipIndex;
0044     QUrl                      toolTipUrl;
0045 };
0046 
0047 ImageDialog::ImageDialog(QWidget* const parent, const QUrl& url, bool singleSelect, const QString& caption)
0048     : QObject(parent),
0049       d      (new Private)
0050 {
0051     QString all;
0052     d->fileFormats = supportedImageMimeTypes(QIODevice::ReadOnly, all);
0053     qCDebug(DIGIKAM_GENERAL_LOG) << "file formats=" << d->fileFormats;
0054 
0055     d->toolTip       = new ImageDialogToolTip();
0056     d->toolTipTimer  = new QTimer(this);
0057 
0058     connect(d->toolTipTimer, SIGNAL(timeout()),
0059             this, SLOT(slotToolTip()));
0060 
0061     d->provider    = new ImageDialogIconProvider();
0062     d->dlg         = new DFileDialog(parent);
0063     d->dlg->setWindowTitle(caption);
0064     d->dlg->setDirectoryUrl(url);
0065     d->dlg->setIconProvider(d->provider);
0066     d->dlg->setNameFilters(d->fileFormats);
0067     d->dlg->selectNameFilter(d->fileFormats.last());
0068     d->dlg->setAcceptMode(QFileDialog::AcceptOpen);
0069     d->dlg->setFileMode(singleSelect ? QFileDialog::ExistingFile : QFileDialog::ExistingFiles);
0070 
0071     for (auto* item : d->dlg->findChildren<QAbstractItemView*>())
0072     {
0073         qCDebug(DIGIKAM_GENERAL_LOG) << item;
0074         item->installEventFilter(this);
0075         item->setMouseTracking(true);
0076     }
0077 
0078     d->dlg->exec();
0079 
0080     if (d->dlg && d->dlg->hasAcceptedUrls())
0081     {
0082         d->urls = d->dlg->selectedUrls();
0083     }
0084 }
0085 
0086 ImageDialog::~ImageDialog()
0087 {
0088     delete d->toolTip;
0089     delete d->dlg;
0090     delete d->provider;
0091     delete d;
0092 }
0093 
0094 void ImageDialog::setEnableToolTips(bool val)
0095 {
0096     d->showToolTips = val;
0097 
0098     if (!val)
0099     {
0100         hideToolTip();
0101     }
0102 }
0103 
0104 void ImageDialog::hideToolTip()
0105 {
0106     d->toolTipIndex = QModelIndex();
0107     d->toolTipTimer->stop();
0108     slotToolTip();
0109 }
0110 
0111 void ImageDialog::slotToolTip()
0112 {
0113     d->toolTip->setData(d->toolTipView, d->toolTipIndex, d->toolTipUrl);
0114 }
0115 
0116 bool ImageDialog::acceptToolTip(const QUrl& url) const
0117 {
0118     if (url.isValid())
0119     {
0120         QFileInfo info(url.toLocalFile());
0121 
0122         if (info.isFile() && !info.isSymLink() && !info.isDir() && !info.isRoot())
0123         {
0124             return true;
0125         }
0126     }
0127 
0128     return false;
0129 }
0130 
0131 bool ImageDialog::eventFilter(QObject* obj, QEvent* ev)
0132 {
0133     if (d->dlg)
0134     {
0135         QAbstractItemView* const view = dynamic_cast<QAbstractItemView*>(obj);
0136 
0137         if (view)
0138         {
0139             if      ((ev->type() == QEvent::HoverMove) && (qApp->mouseButtons() == Qt::NoButton))
0140             {
0141                 QHoverEvent* const hev = dynamic_cast<QHoverEvent*>(ev);
0142 
0143                 if (hev)
0144                 {
0145                     QModelIndex index = view->indexAt(view->viewport()->mapFromGlobal(QCursor::pos()));
0146 
0147                     if (index.isValid())
0148                     {
0149                         QString name = index.data(Qt::DisplayRole).toString();
0150 
0151                         if (!name.isEmpty())
0152                         {
0153                             QUrl url = QUrl::fromLocalFile(QDir::fromNativeSeparators(d->dlg->directoryUrl().toLocalFile() +
0154                                                                                       QLatin1Char('/') + name));
0155 
0156                             if (d->showToolTips)
0157                             {
0158                                 if (!d->dlg->isActiveWindow())
0159                                 {
0160                                     hideToolTip();
0161                                     return false;
0162                                 }
0163 
0164                                 if (index != d->toolTipIndex)
0165                                 {
0166                                     hideToolTip();
0167 
0168                                     if (acceptToolTip(url))
0169                                     {
0170                                         d->toolTipView  = view;
0171                                         d->toolTipIndex = index;
0172                                         d->toolTipUrl   = url;
0173                                         d->toolTipTimer->setSingleShot(true);
0174                                         d->toolTipTimer->start(500);
0175                                     }
0176                                 }
0177 
0178                                 if ((index == d->toolTipIndex) && !acceptToolTip(url))
0179                                 {
0180                                     hideToolTip();
0181                                 }
0182                             }
0183 
0184                             return false;
0185                         }
0186                     }
0187                     else
0188                     {
0189                          hideToolTip();
0190                          return false;
0191                     }
0192                 }
0193             }
0194             else if ((ev->type() == QEvent::HoverLeave) ||
0195                      (ev->type() == QEvent::FocusOut)   ||
0196                      (ev->type() == QEvent::Wheel)      ||
0197                      (ev->type() == QEvent::KeyPress)   ||
0198                      (ev->type() == QEvent::Paint))
0199             {
0200                 hideToolTip();
0201                 return false;
0202             }
0203         }
0204     }
0205 
0206     // pass the event on to the parent class
0207 
0208     return QObject::eventFilter(obj, ev);
0209 }
0210 
0211 QStringList ImageDialog::fileFormats() const
0212 {
0213     return d->fileFormats;
0214 }
0215 
0216 QUrl ImageDialog::url() const
0217 {
0218     if (d->urls.isEmpty())
0219     {
0220         return QUrl();
0221     }
0222 
0223     return d->urls.first();
0224 }
0225 
0226 QList<QUrl> ImageDialog::urls() const
0227 {
0228     return d->urls;
0229 }
0230 
0231 QUrl ImageDialog::getImageURL(QWidget* const parent, const QUrl& url, const QString& caption)
0232 {
0233     ImageDialog dlg(parent, url, true, caption.isEmpty() ? i18n("Select an Item") : caption);
0234 
0235     if (dlg.url() != QUrl())
0236     {
0237         return dlg.url();
0238     }
0239     else
0240     {
0241         return QUrl();
0242     }
0243 }
0244 
0245 QList<QUrl> ImageDialog::getImageURLs(QWidget* const parent, const QUrl& url, const QString& caption)
0246 {
0247     ImageDialog dlg(parent, url, false, caption.isEmpty() ? i18n("Select Items") : caption);
0248 
0249     if (!dlg.urls().isEmpty())
0250     {
0251         return dlg.urls();
0252     }
0253     else
0254     {
0255         return QList<QUrl>();
0256     }
0257 }
0258 
0259 } // namespace Digikam
0260 
0261 #include "moc_imagedialog.cpp"