File indexing completed on 2024-04-28 04:20:22

0001 
0002 /*
0003    Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
0004    All rights reserved.
0005 
0006    Redistribution and use in source and binary forms, with or without
0007    modification, are permitted provided that the following conditions
0008    are met:
0009 
0010    1. Redistributions of source code must retain the above copyright
0011       notice, this list of conditions and the following disclaimer.
0012    2. Redistributions in binary form must reproduce the above copyright
0013       notice, this list of conditions and the following disclaimer in the
0014       documentation and/or other materials provided with the distribution.
0015 
0016    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0017    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0018    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
0019    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
0020    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
0021    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0022    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0023    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0024    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
0025    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0026 */
0027 
0028 
0029 #include "mainWindow/kpMainWindow.h"
0030 #include "kpMainWindowPrivate.h"
0031 #include "kpLogCategories.h"
0032 
0033 #include <QTimer>
0034 
0035 #include <KSharedConfig>
0036 #include <KConfigGroup>
0037 #include <KToggleAction>
0038 #include <KActionCollection>
0039 #include <KLocalizedString>
0040 
0041 #include "kpDefs.h"
0042 #include "document/kpDocument.h"
0043 #include "kpThumbnail.h"
0044 #include "tools/kpTool.h"
0045 #include "widgets/toolbars/kpToolToolBar.h"
0046 #include "views/kpUnzoomedThumbnailView.h"
0047 #include "views/manager/kpViewManager.h"
0048 #include "kpViewScrollableContainer.h"
0049 #include "generic/kpWidgetMapper.h"
0050 #include "views/kpZoomedView.h"
0051 #include "views/kpZoomedThumbnailView.h"
0052 
0053 
0054 // private
0055 void kpMainWindow::setupViewMenuThumbnailActions ()
0056 {
0057     d->thumbnailSaveConfigTimer = nullptr;
0058 
0059     KActionCollection *ac = actionCollection ();
0060 
0061 
0062     d->actionShowThumbnail = ac->add <KToggleAction> (QStringLiteral("view_show_thumbnail"));
0063     d->actionShowThumbnail->setText (i18n ("Show T&humbnail"));
0064     // TODO: This doesn't work when the thumbnail has focus.
0065     //       Testcase: Press CTRL+H twice on a fresh KolourPaint.
0066     //                 The second CTRL+H doesn't close the thumbnail.
0067     ac->setDefaultShortcut (d->actionShowThumbnail, Qt::CTRL | Qt::Key_H);
0068     //d->actionShowThumbnail->setCheckedState (KGuiItem(i18n ("Hide T&humbnail")));
0069     connect (d->actionShowThumbnail, &KToggleAction::triggered,
0070              this, &kpMainWindow::slotShowThumbnailToggled);
0071 
0072     // Please do not use setCheckedState() here - it wouldn't make sense
0073     d->actionZoomedThumbnail = ac->add <KToggleAction> (QStringLiteral("view_zoomed_thumbnail"));
0074     d->actionZoomedThumbnail->setText (i18n ("Zoo&med Thumbnail Mode"));
0075     connect (d->actionZoomedThumbnail, &KToggleAction::triggered,
0076              this, &kpMainWindow::slotZoomedThumbnailToggled);
0077 
0078     // For consistency with the above action, don't use setCheckedState()
0079     //
0080     // Also, don't use "Show Thumbnail Rectangle" because if entire doc
0081     // can be seen in scrollView, checking option won't "Show" anything
0082     // since rect _surrounds_ entire doc (hence, won't be rendered).
0083     d->actionShowThumbnailRectangle = ac->add <KToggleAction> (QStringLiteral("view_show_thumbnail_rectangle"));
0084     d->actionShowThumbnailRectangle->setText (i18n ("Enable Thumbnail &Rectangle"));
0085     connect (d->actionShowThumbnailRectangle, &KToggleAction::triggered,
0086              this, &kpMainWindow::slotThumbnailShowRectangleToggled);
0087 }
0088 
0089 // private
0090 void kpMainWindow::enableViewMenuThumbnailDocumentActions (bool enable)
0091 {
0092     d->actionShowThumbnail->setEnabled (enable);
0093     enableThumbnailOptionActions (enable);
0094 }
0095 
0096 // private slot
0097 void kpMainWindow::slotDestroyThumbnail ()
0098 {
0099 #if DEBUG_KP_MAIN_WINDOW
0100     qCDebug(kpLogMainWindow) << "kpMainWindow::slotDestroyThumbnail()";
0101 #endif
0102 
0103     d->actionShowThumbnail->setChecked (false);
0104     enableThumbnailOptionActions (false);
0105     updateThumbnail ();
0106 }
0107 
0108 // private slot
0109 void kpMainWindow::slotDestroyThumbnailInitatedByUser ()
0110 {
0111 #if DEBUG_KP_MAIN_WINDOW
0112     qCDebug(kpLogMainWindow) << "kpMainWindow::slotDestroyThumbnailInitiatedByUser()";
0113 #endif
0114 
0115     d->actionShowThumbnail->setChecked (false);
0116     slotShowThumbnailToggled ();
0117 }
0118 
0119 // private slot
0120 void kpMainWindow::slotCreateThumbnail ()
0121 {
0122 #if DEBUG_KP_MAIN_WINDOW
0123     qCDebug(kpLogMainWindow) << "kpMainWindow::slotCreateThumbnail()";
0124 #endif
0125 
0126     d->actionShowThumbnail->setChecked (true);
0127     enableThumbnailOptionActions (true);
0128     updateThumbnail ();
0129 }
0130 
0131 // public
0132 void kpMainWindow::notifyThumbnailGeometryChanged ()
0133 {
0134 #if DEBUG_KP_MAIN_WINDOW
0135     qCDebug(kpLogMainWindow) << "kpMainWindow::notifyThumbnailGeometryChanged()";
0136 #endif
0137 
0138     if (!d->thumbnailSaveConfigTimer)
0139     {
0140         d->thumbnailSaveConfigTimer = new QTimer (this);
0141         d->thumbnailSaveConfigTimer->setSingleShot (true);
0142         connect (d->thumbnailSaveConfigTimer, &QTimer::timeout,
0143                  this, &kpMainWindow::slotSaveThumbnailGeometry);
0144     }
0145 
0146     // (single shot)
0147     d->thumbnailSaveConfigTimer->start (500/*msec*/);
0148 }
0149 
0150 // private slot
0151 void kpMainWindow::slotSaveThumbnailGeometry ()
0152 {
0153 #if DEBUG_KP_MAIN_WINDOW
0154     qCDebug(kpLogMainWindow) << "kpMainWindow::saveThumbnailGeometry()";
0155 #endif
0156 
0157     if (!d->thumbnail) {
0158         return;
0159     }
0160 
0161     QRect rect (d->thumbnail->x (), d->thumbnail->y (),
0162                 d->thumbnail->width (), d->thumbnail->height ());
0163 #if DEBUG_KP_MAIN_WINDOW
0164     qCDebug(kpLogMainWindow) << "\tthumbnail relative geometry=" << rect;
0165 #endif
0166 
0167     d->configThumbnailGeometry = mapFromGlobal (rect);
0168 
0169 #if DEBUG_KP_MAIN_WINDOW
0170     qCDebug(kpLogMainWindow) << "\tCONFIG: saving thumbnail geometry "
0171                 << d->configThumbnailGeometry;
0172 #endif
0173 
0174     KConfigGroup cfg (KSharedConfig::openConfig (), QStringLiteral(kpSettingsGroupThumbnail));
0175 
0176     cfg.writeEntry (kpSettingThumbnailGeometry, d->configThumbnailGeometry);
0177     cfg.sync ();
0178 }
0179 
0180 // private slot
0181 void kpMainWindow::slotShowThumbnailToggled ()
0182 {
0183 #if DEBUG_KP_MAIN_WINDOW
0184     qCDebug(kpLogMainWindow) << "kpMainWindow::slotShowThumbnailToggled()";
0185 #endif
0186 
0187     d->configThumbnailShown = d->actionShowThumbnail->isChecked ();
0188 
0189     KConfigGroup cfg (KSharedConfig::openConfig (), QStringLiteral(kpSettingsGroupThumbnail));
0190 
0191     cfg.writeEntry (kpSettingThumbnailShown, d->configThumbnailShown);
0192     cfg.sync ();
0193 
0194 
0195     enableThumbnailOptionActions (d->actionShowThumbnail->isChecked ());
0196     updateThumbnail ();
0197 }
0198 
0199 // private slot
0200 void kpMainWindow::updateThumbnailZoomed ()
0201 {
0202 #if DEBUG_KP_MAIN_WINDOW
0203     qCDebug(kpLogMainWindow) << "kpMainWindow::updateThumbnailZoomed() zoomed="
0204                << d->actionZoomedThumbnail->isChecked ();
0205 #endif
0206 
0207     if (!d->thumbnailView) {
0208         return;
0209     }
0210 
0211     destroyThumbnailView ();
0212     createThumbnailView ();
0213 }
0214 
0215 // private slot
0216 void kpMainWindow::slotZoomedThumbnailToggled ()
0217 {
0218 #if DEBUG_KP_MAIN_WINDOW
0219     qCDebug(kpLogMainWindow) << "kpMainWindow::slotZoomedThumbnailToggled()";
0220 #endif
0221 
0222     d->configZoomedThumbnail = d->actionZoomedThumbnail->isChecked ();
0223 
0224     KConfigGroup cfg (KSharedConfig::openConfig (), QStringLiteral(kpSettingsGroupThumbnail));
0225 
0226     cfg.writeEntry (kpSettingThumbnailZoomed, d->configZoomedThumbnail);
0227     cfg.sync ();
0228 
0229 
0230     updateThumbnailZoomed ();
0231 }
0232 
0233 // private slot
0234 void kpMainWindow::slotThumbnailShowRectangleToggled ()
0235 {
0236 #if DEBUG_KP_MAIN_WINDOW
0237     qCDebug(kpLogMainWindow) << "kpMainWindow::slotThumbnailShowRectangleToggled()";
0238 #endif
0239 
0240     d->configThumbnailShowRectangle = d->actionShowThumbnailRectangle->isChecked ();
0241 
0242     KConfigGroup cfg (KSharedConfig::openConfig (), QStringLiteral(kpSettingsGroupThumbnail));
0243 
0244     cfg.writeEntry (kpSettingThumbnailShowRectangle, d->configThumbnailShowRectangle);
0245     cfg.sync ();
0246 
0247 
0248     if (d->thumbnailView)
0249     {
0250         d->thumbnailView->showBuddyViewScrollableContainerRectangle (
0251             d->actionShowThumbnailRectangle->isChecked ());
0252     }
0253 }
0254 
0255 // private
0256 void kpMainWindow::enableViewZoomedThumbnail (bool enable)
0257 {
0258 #if DEBUG_KP_MAIN_WINDOW
0259     qCDebug(kpLogMainWindow) << "kpMainWindow::enableSettingsViewZoomedThumbnail()";
0260 #endif
0261 
0262     d->actionZoomedThumbnail->setEnabled (enable &&
0263         d->actionShowThumbnail->isChecked ());
0264 
0265     // Note: Don't uncheck if disabled - being able to see the zoomed state
0266     //       before turning on the thumbnail can be useful.
0267     d->actionZoomedThumbnail->setChecked (d->configZoomedThumbnail);
0268 }
0269 
0270 // private
0271 void kpMainWindow::enableViewShowThumbnailRectangle (bool enable)
0272 {
0273 #if DEBUG_KP_MAIN_WINDOW
0274     qCDebug(kpLogMainWindow) << "kpMainWindow::enableViewShowThumbnailRectangle()";
0275 #endif
0276 
0277     d->actionShowThumbnailRectangle->setEnabled (enable &&
0278         d->actionShowThumbnail->isChecked ());
0279 
0280     // Note: Don't uncheck if disabled for consistency with
0281     //       enableViewZoomedThumbnail()
0282     d->actionShowThumbnailRectangle->setChecked (
0283         d->configThumbnailShowRectangle);
0284 }
0285 
0286 // private
0287 void kpMainWindow::enableThumbnailOptionActions (bool enable)
0288 {
0289     enableViewZoomedThumbnail (enable);
0290     enableViewShowThumbnailRectangle (enable);
0291 }
0292 
0293 
0294 // private
0295 void kpMainWindow::createThumbnailView ()
0296 {
0297 #if DEBUG_KP_MAIN_WINDOW
0298     qCDebug(kpLogMainWindow) << "\t\tcreating new kpView:";
0299 #endif
0300 
0301     if (d->thumbnailView)
0302     {
0303         qCDebug(kpLogMainWindow) << "kpMainWindow::createThumbnailView() had to destroy view";
0304         destroyThumbnailView ();
0305     }
0306 
0307     if (d->actionZoomedThumbnail->isChecked ())
0308     {
0309         d->thumbnailView = new kpZoomedThumbnailView (
0310             d->document, d->toolToolBar, d->viewManager,
0311             d->mainView,
0312             nullptr/*scrollableContainer*/,
0313             d->thumbnail);
0314         d->thumbnailView->setObjectName ( QStringLiteral("thumbnailView" ));
0315     }
0316     else
0317     {
0318         d->thumbnailView = new kpUnzoomedThumbnailView (
0319             d->document, d->toolToolBar, d->viewManager,
0320             d->mainView,
0321             nullptr/*scrollableContainer*/,
0322             d->thumbnail);
0323         d->thumbnailView->setObjectName ( QStringLiteral("thumbnailView" ));
0324     }
0325 
0326     d->thumbnailView->showBuddyViewScrollableContainerRectangle (
0327         d->actionShowThumbnailRectangle->isChecked ());
0328 
0329 
0330 #if DEBUG_KP_MAIN_WINDOW
0331     qCDebug(kpLogMainWindow) << "\t\tgive kpThumbnail the kpView:";
0332 #endif
0333 
0334     if (d->thumbnail) {
0335         d->thumbnail->setView (d->thumbnailView);
0336     }
0337     else {
0338         qCCritical(kpLogMainWindow) << "kpMainWindow::createThumbnailView() no thumbnail";
0339     }
0340 
0341 #if DEBUG_KP_MAIN_WINDOW
0342     qCDebug(kpLogMainWindow) << "\t\tregistering the kpView:";
0343 #endif
0344     if (d->viewManager) {
0345         d->viewManager->registerView (d->thumbnailView);
0346     }
0347 }
0348 
0349 // private
0350 void kpMainWindow::destroyThumbnailView ()
0351 {
0352     if (!d->thumbnailView) {
0353         return;
0354     }
0355 
0356     if (d->viewManager) {
0357         d->viewManager->unregisterView (d->thumbnailView);
0358     }
0359 
0360     if (d->thumbnail) {
0361         d->thumbnail->setView (nullptr);
0362     }
0363 
0364     d->thumbnailView->deleteLater (); d->thumbnailView = nullptr;
0365 }
0366 
0367 
0368 // private
0369 void kpMainWindow::updateThumbnail ()
0370 {
0371 #if DEBUG_KP_MAIN_WINDOW
0372     qCDebug(kpLogMainWindow) << "kpMainWindow::updateThumbnail()";
0373 #endif
0374     bool enable = d->actionShowThumbnail->isChecked ();
0375 
0376 #if DEBUG_KP_MAIN_WINDOW
0377     qCDebug(kpLogMainWindow) << "\tthumbnail="
0378                << bool (d->thumbnail)
0379                << " action_isChecked="
0380                << enable;
0381 #endif
0382 
0383     if (bool (d->thumbnail) == enable) {
0384         return;
0385     }
0386 
0387     if (!d->thumbnail)
0388     {
0389     #if DEBUG_KP_MAIN_WINDOW
0390         qCDebug(kpLogMainWindow) << "\tcreating thumbnail";
0391     #endif
0392 
0393         // Read last saved geometry before creating thumbnail & friends
0394         // in case they call notifyThumbnailGeometryChanged()
0395         QRect thumbnailGeometry = d->configThumbnailGeometry;
0396     #if DEBUG_KP_MAIN_WINDOW
0397         qCDebug(kpLogMainWindow) << "\t\tlast used geometry=" << thumbnailGeometry;
0398     #endif
0399 
0400         d->thumbnail = new kpThumbnail (this);
0401 
0402         createThumbnailView ();
0403 
0404     #if DEBUG_KP_MAIN_WINDOW
0405         qCDebug(kpLogMainWindow) << "\t\tmoving thumbnail to right place";
0406     #endif
0407         if (!thumbnailGeometry.isEmpty () &&
0408             QRect (0, 0, width (), height ()).intersects (thumbnailGeometry))
0409         {
0410             const QRect geometry = mapToGlobal (thumbnailGeometry);
0411             d->thumbnail->resize (geometry.size ());
0412             d->thumbnail->move (geometry.topLeft ());
0413         }
0414         else
0415         {
0416             if (d->scrollView)
0417             {
0418                 const int margin = 20;
0419                 const int initialWidth = 160, initialHeight = 120;
0420 
0421                 QRect geometryRect (width () - initialWidth - margin * 2,
0422                                     d->scrollView->y () + margin,
0423                                     initialWidth,
0424                                     initialHeight);
0425 
0426             #if DEBUG_KP_MAIN_WINDOW
0427                 qCDebug(kpLogMainWindow) << "\t\tcreating geometry=" << geometryRect;
0428             #endif
0429 
0430                 geometryRect = mapToGlobal (geometryRect);
0431             #if DEBUG_KP_MAIN_WINDOW
0432                 qCDebug(kpLogMainWindow) << "\t\tmap to global=" << geometryRect;
0433             #endif
0434                 d->thumbnail->resize (geometryRect.size ());
0435                 d->thumbnail->move (geometryRect.topLeft ());
0436             }
0437         }
0438 
0439     #if DEBUG_KP_MAIN_WINDOW
0440         qCDebug(kpLogMainWindow) << "\t\tshowing thumbnail";
0441     #endif
0442         d->thumbnail->show ();
0443 
0444     #if DEBUG_KP_MAIN_WINDOW
0445         qCDebug(kpLogMainWindow) << "\t\tconnecting signal thumbnail::windowClosed to destroy slot";
0446     #endif
0447         connect (d->thumbnail, &kpThumbnail::windowClosed,
0448                  this, &kpMainWindow::slotDestroyThumbnailInitatedByUser);
0449     #if DEBUG_KP_MAIN_WINDOW
0450         qCDebug(kpLogMainWindow) << "\t\tDONE";
0451     #endif
0452     }
0453     else
0454     {
0455     #if DEBUG_KP_MAIN_WINDOW
0456         qCDebug(kpLogMainWindow) << "\tdestroying thumbnail d->thumbnail="
0457             << d->thumbnail;
0458     #endif
0459 
0460         if (d->thumbnailSaveConfigTimer && d->thumbnailSaveConfigTimer->isActive ())
0461         {
0462             d->thumbnailSaveConfigTimer->stop ();
0463             slotSaveThumbnailGeometry ();
0464         }
0465 
0466         // Must be done before hiding the thumbnail to avoid triggering
0467         // this signal - re-entering this code.
0468         disconnect (d->thumbnail, &kpThumbnail::windowClosed,
0469                     this, &kpMainWindow::slotDestroyThumbnailInitatedByUser);
0470 
0471         // Avoid change/flicker of caption due to view delete
0472         // (destroyThumbnailView())
0473         d->thumbnail->hide ();
0474 
0475         destroyThumbnailView ();
0476 
0477         d->thumbnail->deleteLater (); d->thumbnail = nullptr;
0478     }
0479 }