File indexing completed on 2025-04-27 03:58:32

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2013-04-29
0007  * Description : digiKam XML GUI window
0008  *
0009  * SPDX-FileCopyrightText: 2013-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 "dxmlguiwindow_p.h"
0016 
0017 namespace Digikam
0018 {
0019 
0020 DXmlGuiWindow::DXmlGuiWindow(QWidget* const parent, Qt::WindowFlags f)
0021     : KXmlGuiWindow(parent, f),
0022       m_winLoaded  (false),
0023       m_maximized  (false),
0024       d            (new Private)
0025 {
0026     m_animLogo = nullptr;
0027 
0028     installEventFilter(this);
0029 }
0030 
0031 DXmlGuiWindow::~DXmlGuiWindow()
0032 {
0033     delete d;
0034 }
0035 
0036 void DXmlGuiWindow::setConfigGroupName(const QString& name)
0037 {
0038     d->configGroupName = name;
0039 }
0040 
0041 QString DXmlGuiWindow::configGroupName() const
0042 {
0043     return d->configGroupName;
0044 }
0045 
0046 void DXmlGuiWindow::showEvent(QShowEvent* e)
0047 {
0048     KXmlGuiWindow::showEvent(e);
0049 
0050     restoreWindowSize();
0051 }
0052 
0053 void DXmlGuiWindow::closeEvent(QCloseEvent* e)
0054 {
0055     checkFullScreenBeforeClosing();
0056 
0057     if (!testAttribute(Qt::WA_DeleteOnClose))
0058     {
0059 
0060 #ifdef Q_OS_WIN
0061 
0062         m_maximized = (windowState() &
0063                        Qt::WindowMaximized);
0064 
0065 #endif
0066 
0067         e->ignore();
0068         return;
0069     }
0070 
0071     saveWindowSize();
0072 
0073     KXmlGuiWindow::closeEvent(e);
0074 }
0075 
0076 bool DXmlGuiWindow::slotClose()
0077 {
0078     checkFullScreenBeforeClosing();
0079 
0080     return close();
0081 }
0082 
0083 void DXmlGuiWindow::slotShowMenuBar()
0084 {
0085     menuBar()->setVisible(d->showMenuBarAction->isChecked());
0086 }
0087 
0088 void DXmlGuiWindow::slotShowStatusBar()
0089 {
0090     statusBar()->setVisible(d->showStatusBarAction->isChecked());
0091 }
0092 
0093 void DXmlGuiWindow::slotConfNotifications()
0094 {
0095 
0096 #ifdef HAVE_KNOTIFYCONFIG
0097 
0098     QDialog* const dialog             = new QDialog(this);
0099     dialog->setWindowTitle(i18n("Configure Notifications"));
0100 
0101     KNotifyConfigWidget* const w      = new KNotifyConfigWidget(dialog);
0102 
0103     QDialogButtonBox* const buttonBox = new QDialogButtonBox(dialog);
0104     buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel| QDialogButtonBox::Help);
0105     buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
0106 
0107     QVBoxLayout* const layout         = new QVBoxLayout(dialog);
0108     layout->addWidget(w);
0109     layout->addWidget(buttonBox);
0110 
0111     connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()),
0112             w, SLOT(save()));
0113 
0114     connect(buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()),
0115             w, SLOT(save()));
0116 
0117     connect(buttonBox->button(QDialogButtonBox::Help), &QPushButton::clicked,
0118             this, []()
0119         {
0120             openOnlineDocumentation(QLatin1String("setup_application"), QLatin1String("notifications_settings"));
0121         }
0122     );
0123 
0124     connect(w, SIGNAL(changed(bool)),
0125             buttonBox->button(QDialogButtonBox::Apply), SLOT(setEnabled(bool)));
0126 
0127     connect(buttonBox, SIGNAL(accepted()),
0128             dialog, SLOT(accept()));
0129 
0130     connect(buttonBox, SIGNAL(rejected()),
0131             dialog, SLOT(reject()));
0132 
0133     w->setApplication(QString());
0134     dialog->setAttribute(Qt::WA_DeleteOnClose);
0135     dialog->show();
0136 
0137 #endif
0138 
0139 }
0140 
0141 void DXmlGuiWindow::editKeyboardShortcuts(KActionCollection* const extraac, const QString& actitle)
0142 {
0143     KShortcutsDialog dialog(KShortcutsEditor::AllActions,
0144                             KShortcutsEditor::LetterShortcutsAllowed, this);
0145     dialog.addCollection(actionCollection(), i18nc("general keyboard shortcuts", "General"));
0146 
0147     QDialogButtonBox* const btnbox = dialog.findChild<QDialogButtonBox*>();
0148 
0149     if (btnbox)
0150     {
0151         btnbox->setStandardButtons(btnbox->standardButtons() | QDialogButtonBox::Help);
0152 
0153         connect(btnbox->button(QDialogButtonBox::Help), &QPushButton::clicked,
0154                 this, []()
0155             {
0156                 openOnlineDocumentation(QLatin1String("setup_application"), QLatin1String("shortcuts_settings"));
0157             }
0158         );
0159     }
0160 
0161     if (extraac)
0162     {
0163         dialog.addCollection(extraac, actitle);
0164     }
0165 
0166     dialog.configure();
0167 }
0168 
0169 bool DXmlGuiWindow::eventFilter(QObject* obj, QEvent* ev)
0170 {
0171     if (obj == this)
0172     {
0173         if (ev && (ev->type() == QEvent::HoverMove) && fullScreenIsActive())
0174         {
0175             // We will handle a stand alone FullScreen button action on top/right corner of screen
0176             // only if managed window tool bar is hidden, and if we switched already in Full Screen mode.
0177 
0178             KToolBar* const mainbar = mainToolBar();
0179 
0180             if (mainbar)
0181             {
0182                 if (((d->fsOptions & FS_TOOLBARS) && d->fullScreenHideToolBars) || !mainbar->isVisible())
0183                 {
0184                     QHoverEvent* const mev = dynamic_cast<QHoverEvent*>(ev);
0185 
0186                     if (mev)
0187                     {
0188 
0189 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
0190 
0191                         QPoint pos(mev->position().toPoint());
0192 
0193 #else
0194 
0195                         QPoint pos(mev->pos());
0196 
0197 #endif
0198 
0199                         QRect  desktopRect = windowHandle()->screen()->geometry();
0200 
0201                         QRect sizeRect(QPoint(0, 0), d->fullScreenBtn->size());
0202                         QRect topLeft, topRight;
0203                         QRect topRightLarger;
0204 
0205                         desktopRect        = QRect(desktopRect.y(), desktopRect.y(), desktopRect.width(), desktopRect.height());
0206                         topLeft            = sizeRect;
0207                         topRight           = sizeRect;
0208 
0209                         topLeft.moveTo(desktopRect.x(), desktopRect.y());
0210                         topRight.moveTo(desktopRect.x() + desktopRect.width() - sizeRect.width() - 1, topLeft.y());
0211 
0212                         topRightLarger     = topRight.adjusted(-25, 0, 0, 10);
0213 
0214                         if (topRightLarger.contains(pos))
0215                         {
0216                             d->fullScreenBtn->move(topRight.topLeft());
0217                             d->fullScreenBtn->show();
0218                         }
0219                         else
0220                         {
0221                             d->fullScreenBtn->hide();
0222                         }
0223 
0224                         return false;
0225                     }
0226                 }
0227             }
0228         }
0229     }
0230 
0231     // pass the event on to the parent class
0232 
0233     return QObject::eventFilter(obj, ev);
0234 }
0235 
0236 void DXmlGuiWindow::keyPressEvent(QKeyEvent* e)
0237 {
0238     if (e->key() == Qt::Key_Escape)
0239     {
0240         if (fullScreenIsActive())
0241         {
0242             d->fullScreenAction->activate(QAction::Trigger);
0243         }
0244     }
0245 }
0246 
0247 void DXmlGuiWindow::showSideBars(bool visible)
0248 {
0249     Q_UNUSED(visible);
0250 }
0251 
0252 void DXmlGuiWindow::showThumbBar(bool visible)
0253 {
0254     Q_UNUSED(visible);
0255 }
0256 
0257 bool DXmlGuiWindow::thumbbarVisibility() const
0258 {
0259     return true;
0260 }
0261 
0262 void DXmlGuiWindow::slotHelpContents()
0263 {
0264     openOnlineDocumentation(d->handbookSection);
0265 }
0266 
0267 void DXmlGuiWindow::unminimizeAndActivateWindow()
0268 {
0269     if (isMinimized())
0270     {
0271         setWindowState(windowState() & ~Qt::WindowMinimized);
0272     }
0273 
0274 #ifdef Q_OS_WIN
0275 
0276     if (m_maximized)
0277     {
0278         setWindowState(windowState() | Qt::WindowMaximized);
0279     }
0280 
0281 #endif
0282 
0283     setWindowState(windowState() | Qt::WindowActive);
0284     raise();
0285 }
0286 
0287 bool DXmlGuiWindow::restoreWindowSize(QWindow* const win, const KConfigGroup& group)
0288 {
0289 
0290 #ifdef Q_OS_WIN
0291 
0292     int  w   = group.readEntry(QLatin1String("DK Width"),     win->width());
0293     int  h   = group.readEntry(QLatin1String("DK Height"),    win->height());
0294     int  x   = group.readEntry(QLatin1String("DK PositionX"), win->geometry().x());
0295     int  y   = group.readEntry(QLatin1String("DK PositionY"), win->geometry().y());
0296     bool max = group.readEntry(QLatin1String("DK Maximized"), (bool)(win->windowState() &
0297                                                                      Qt::WindowMaximized));
0298 
0299     if (win->screen()->availableVirtualGeometry().contains(QRect(x, y, w, h)))
0300     {
0301         win->setPosition(x, y);
0302     }
0303 
0304     if (max)
0305     {
0306         // we don't use showMaximized() because it also calls
0307         // setVisible() it would create an infinite loop.
0308 
0309         win->setWindowState(Qt::WindowMaximized);
0310     }
0311     else
0312     {
0313         win->resize(w, h);
0314     }
0315 
0316     return max;
0317 
0318 #else
0319 
0320     KWindowConfig::restoreWindowSize(win, group);
0321 
0322     return false;
0323 
0324 #endif
0325 
0326 }
0327 
0328 void DXmlGuiWindow::saveWindowSize(QWindow* const win, KConfigGroup& group)
0329 {
0330 
0331 #ifdef Q_OS_WIN
0332 
0333     group.writeEntry(QLatin1String("DK Width"),     win->width());
0334     group.writeEntry(QLatin1String("DK Height"),    win->height());
0335     group.writeEntry(QLatin1String("DK PositionX"), win->geometry().x());
0336     group.writeEntry(QLatin1String("DK PositionY"), win->geometry().y());
0337     group.writeEntry(QLatin1String("DK Maximized"), (bool)(win->windowState() &
0338                                                            Qt::WindowMaximized));
0339 
0340 #else
0341 
0342     KWindowConfig::saveWindowSize(win, group);
0343 
0344 #endif
0345 
0346 }
0347 
0348 void DXmlGuiWindow::restoreWindowSize()
0349 {
0350 
0351 #ifdef Q_OS_WIN
0352 
0353     if (!m_winLoaded)
0354     {
0355         winId();
0356 
0357         m_winLoaded               = true;
0358         KSharedConfig::Ptr config = KSharedConfig::openConfig();
0359         KConfigGroup group        = config->group(configGroupName());
0360         m_maximized               = restoreWindowSize(windowHandle(), group);
0361     }
0362 
0363 #endif
0364 
0365 }
0366 
0367 void DXmlGuiWindow::saveWindowSize()
0368 {
0369 
0370 #ifdef Q_OS_WIN
0371 
0372     if (m_maximized)
0373     {
0374         windowHandle()->setWindowState(Qt::WindowMaximized);
0375     }
0376 
0377     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0378     KConfigGroup group        = config->group(configGroupName());
0379 
0380     saveWindowSize(windowHandle(), group);
0381 
0382 #endif
0383 
0384 }
0385 
0386 void DXmlGuiWindow::setGoodDefaultWindowSize(QWindow* const win)
0387 {
0388     QScreen* const screen = win->screen();
0389     QRect srect           = screen->availableGeometry();
0390     int height            = qRound(log10(srect.height() / 60) * 600);
0391     int width             = qRound(log10(srect.width()  / 80) * 800);
0392 
0393     win->resize(width  > srect.width()  ? srect.width()  : width,
0394                 height > srect.height() ? srect.height() : height);
0395 }
0396 
0397 void DXmlGuiWindow::slotRawCameraList()
0398 {
0399     showRawCameraList();
0400 }
0401 
0402 void DXmlGuiWindow::slotSolidHardwareList()
0403 {
0404     SolidHardwareDlg* const dlg = new SolidHardwareDlg(qApp->activeWindow());
0405     (void)dlg->exec();
0406 }
0407 
0408 void DXmlGuiWindow::slotDonateMoney()
0409 {
0410     QUrl url(QLatin1String("https://www.digikam.org/donate/"));
0411 
0412 #ifdef HAVE_QWEBENGINE
0413 
0414     WebBrowserDlg* const browser = new WebBrowserDlg(url, qApp->activeWindow());
0415     browser->show();
0416 
0417 #else
0418 
0419     QDesktopServices::openUrl(url);
0420 
0421 #endif
0422 
0423 }
0424 
0425 void DXmlGuiWindow::slotRecipesBook()
0426 {
0427     QUrl url(QLatin1String("https://www.digikam.org/recipes_book/"));
0428 
0429 #ifdef HAVE_QWEBENGINE
0430 
0431     WebBrowserDlg* const browser = new WebBrowserDlg(url, qApp->activeWindow());
0432     browser->show();
0433 
0434 #else
0435 
0436     QDesktopServices::openUrl(url);
0437 
0438 #endif
0439 
0440 }
0441 
0442 void DXmlGuiWindow::slotContribute()
0443 {
0444     QUrl url(QLatin1String("https://www.digikam.org/contribute/"));
0445 
0446 #ifdef HAVE_QWEBENGINE
0447 
0448     WebBrowserDlg* const browser = new WebBrowserDlg(url, qApp->activeWindow());
0449     browser->show();
0450 
0451 #else
0452 
0453     QDesktopServices::openUrl(url);
0454 
0455 #endif
0456 
0457 }
0458 
0459 void DXmlGuiWindow::setupIconTheme()
0460 {
0461     // Let QStandardPaths handle this, it will look for app local stuff
0462     // this means e.g. for mac: "<APPDIR>/../Resources" and for win: "<APPDIR>/data".
0463 
0464     bool hasBreeze                = false;
0465     const QString breezeIcons     = QStandardPaths::locate(QStandardPaths::AppDataLocation,
0466                                                            QLatin1String("breeze.rcc"));
0467 
0468     if (!breezeIcons.isEmpty() && QFile::exists(breezeIcons))
0469     {
0470         qCDebug(DIGIKAM_WIDGETS_LOG) << "Breeze icons resource file found";
0471         QResource::registerResource(breezeIcons);
0472         hasBreeze = true;
0473     }
0474 
0475     bool hasBreezeDark            = false;
0476     const QString breezeDarkIcons = QStandardPaths::locate(QStandardPaths::AppDataLocation,
0477                                                            QLatin1String("breeze-dark.rcc"));
0478 
0479     if (!breezeDarkIcons.isEmpty() && QFile::exists(breezeDarkIcons))
0480     {
0481         qCDebug(DIGIKAM_WIDGETS_LOG) << "Breeze-dark icons resource file found";
0482         QResource::registerResource(breezeDarkIcons);
0483         hasBreezeDark = true;
0484     }
0485 
0486     if (hasBreeze || hasBreezeDark)
0487     {
0488         // Tell Qt about the theme
0489 
0490         QIcon::setThemeSearchPaths(QStringList() << QLatin1String(":/icons"));
0491 
0492         const QStringList iconsDirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation,
0493                                                                 QLatin1String("icons"),
0494                                                                 QStandardPaths::LocateDirectory);
0495 
0496         if (!iconsDirs.isEmpty())
0497         {
0498             QIcon::setThemeSearchPaths(QStringList() << QIcon::themeSearchPaths() << iconsDirs);
0499         }
0500 
0501         if      (hasBreeze)
0502         {
0503             QIcon::setThemeName(QLatin1String("breeze"));
0504         }
0505         else if (hasBreezeDark)
0506         {
0507             QIcon::setThemeName(QLatin1String("breeze-dark"));
0508         }
0509     }
0510     else
0511     {
0512         qCDebug(DIGIKAM_WIDGETS_LOG) << "Use installed icons";
0513     }
0514 }
0515 
0516 } // namespace Digikam
0517 
0518 #include "moc_dxmlguiwindow.cpp"