File indexing completed on 2024-05-05 04:21:24

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 #define DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET 0
0029 
0030 
0031 #include "widgets/kpDocumentSaveOptionsWidget.h"
0032 
0033 #include "kpDefs.h"
0034 #include "document/kpDocument.h"
0035 #include "dialogs/kpDocumentSaveOptionsPreviewDialog.h"
0036 #include "pixmapfx/kpPixmapFX.h"
0037 #include "generic/widgets/kpResizeSignallingLabel.h"
0038 #include "dialogs/imagelib/transforms/kpTransformPreviewDialog.h"
0039 #include "generic/kpWidgetMapper.h"
0040 
0041 #include "kpLogCategories.h"
0042 #include <KSharedConfig>
0043 #include <KConfigGroup>
0044 
0045 #include <QApplication>
0046 #include <QBuffer>
0047 #include <QComboBox>
0048 #include <QImage>
0049 #include <QLabel>
0050 #include <QPushButton>
0051 #include <QSpinBox>
0052 #include <QTimer>
0053 #include <QHBoxLayout>
0054 
0055 kpDocumentSaveOptionsWidget::kpDocumentSaveOptionsWidget (
0056         const QImage &docPixmap,
0057         const kpDocumentSaveOptions &saveOptions,
0058         const kpDocumentMetaInfo &metaInfo,
0059         QWidget *parent)
0060     : QWidget (parent),
0061       m_visualParent (parent)
0062 {
0063     init ();
0064     setDocumentSaveOptions (saveOptions);
0065     setDocumentPixmap (docPixmap);
0066     setDocumentMetaInfo (metaInfo);
0067 }
0068 
0069 kpDocumentSaveOptionsWidget::kpDocumentSaveOptionsWidget (
0070         QWidget *parent)
0071     : QWidget (parent),
0072       m_visualParent (parent)
0073 {
0074     init ();
0075 }
0076 
0077 // private
0078 void kpDocumentSaveOptionsWidget::init ()
0079 {
0080     m_documentPixmap = nullptr;
0081     m_previewDialog = nullptr;
0082     m_visualParent = nullptr;
0083 
0084 
0085     m_colorDepthLabel = new QLabel (i18n ("Convert &to:"), this);
0086     m_colorDepthCombo = new QComboBox (this);
0087 
0088     m_colorDepthSpaceWidget = new QWidget (this);
0089 
0090     m_qualityLabel = new QLabel(i18n ("Quali&ty:"), this);
0091     m_qualityInput = new QSpinBox(this);
0092     // Note that we set min to 1 not 0 since "0 Quality" is a bit misleading
0093     // and 101 quality settings would be weird.  So we lose 1 quality setting
0094     // according to QImage::save().
0095     // TODO: 100 quality is also misleading since that implies perfect quality.
0096     m_qualityInput->setRange (1, 100);
0097 
0098     m_previewButton = new QPushButton (i18n ("&Preview"), this);
0099     m_previewButton->setCheckable (true);
0100 
0101 
0102     m_colorDepthLabel->setBuddy (m_colorDepthCombo);
0103 
0104     m_qualityLabel->setBuddy (m_qualityInput);
0105 
0106 
0107     auto *lay = new QHBoxLayout (this);
0108     lay->setContentsMargins(0, 0, 0, 0);
0109 
0110     lay->addWidget (m_colorDepthLabel, 0/*stretch*/, Qt::AlignLeft);
0111     lay->addWidget (m_colorDepthCombo, 0/*stretch*/);
0112 
0113     lay->addWidget (m_colorDepthSpaceWidget, 1/*stretch*/);
0114 
0115     lay->addWidget (m_qualityLabel, 0/*stretch*/, Qt::AlignLeft);
0116     lay->addWidget (m_qualityInput, 2/*stretch*/);
0117 
0118     lay->addWidget (m_previewButton, 0/*stretch*/, Qt::AlignRight);
0119 
0120 
0121     connect (m_colorDepthCombo,
0122              static_cast<void (QComboBox::*)(int)>(&QComboBox::activated),
0123              this, &kpDocumentSaveOptionsWidget::slotColorDepthSelected);
0124 
0125     connect (m_colorDepthCombo,
0126              static_cast<void (QComboBox::*)(int)>(&QComboBox::activated),
0127              this, &kpDocumentSaveOptionsWidget::updatePreview);
0128 
0129     connect (m_qualityInput,
0130              static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
0131              this, &kpDocumentSaveOptionsWidget::updatePreviewDelayed);
0132 
0133     connect (m_previewButton, &QPushButton::toggled,
0134              this, &kpDocumentSaveOptionsWidget::showPreview);
0135 
0136 
0137     m_updatePreviewDelay = 200/*ms*/;
0138 
0139     m_updatePreviewTimer = new QTimer (this);
0140     m_updatePreviewTimer->setSingleShot (true);
0141     connect (m_updatePreviewTimer, &QTimer::timeout,
0142              this, &kpDocumentSaveOptionsWidget::updatePreview);
0143 
0144     m_updatePreviewDialogLastRelativeGeometryTimer = new QTimer (this);
0145     connect (m_updatePreviewDialogLastRelativeGeometryTimer,
0146              &QTimer::timeout,
0147              this, &kpDocumentSaveOptionsWidget::updatePreviewDialogLastRelativeGeometry);
0148 
0149     setMode (None);
0150 
0151     slotColorDepthSelected ();
0152 }
0153 
0154 kpDocumentSaveOptionsWidget::~kpDocumentSaveOptionsWidget ()
0155 {
0156 #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
0157     qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::<dtor>()";
0158 #endif
0159     hidePreview ();
0160 
0161     delete m_documentPixmap;
0162 }
0163 
0164 
0165 // public
0166 void kpDocumentSaveOptionsWidget::setVisualParent (QWidget *visualParent)
0167 {
0168 #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
0169     qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::setVisualParent("
0170                << visualParent << ")" << endl;
0171 #endif
0172 
0173     m_visualParent = visualParent;
0174 }
0175 
0176 
0177 // protected
0178 bool kpDocumentSaveOptionsWidget::mimeTypeHasConfigurableColorDepth () const
0179 {
0180     return kpDocumentSaveOptions::mimeTypeHasConfigurableColorDepth (mimeType ());
0181 }
0182 
0183 // protected
0184 bool kpDocumentSaveOptionsWidget::mimeTypeHasConfigurableQuality () const
0185 {
0186     return kpDocumentSaveOptions::mimeTypeHasConfigurableQuality (mimeType ());
0187 }
0188 
0189 
0190 // public
0191 QString kpDocumentSaveOptionsWidget::mimeType () const
0192 {
0193     return m_baseDocumentSaveOptions.mimeType ();
0194 }
0195 
0196 // public slots
0197 void kpDocumentSaveOptionsWidget::setMimeType (const QString &string)
0198 {
0199 #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
0200     qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::setMimeType(" << string
0201                << ") maxColorDepth="
0202                << kpDocumentSaveOptions::mimeTypeMaximumColorDepth (string)
0203                << endl;
0204 #endif
0205 
0206     const int newMimeTypeMaxDepth =
0207         kpDocumentSaveOptions::mimeTypeMaximumColorDepth (string);
0208 
0209 #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
0210     qCDebug(kpLogWidgets) << "\toldMimeType=" << mimeType ()
0211                << " maxColorDepth="
0212                << kpDocumentSaveOptions::mimeTypeMaximumColorDepth (
0213                       mimeType ())
0214                << endl;
0215 #endif
0216 
0217     if (mimeType ().isEmpty () ||
0218         kpDocumentSaveOptions::mimeTypeMaximumColorDepth (mimeType ()) !=
0219         newMimeTypeMaxDepth)
0220     {
0221         m_colorDepthCombo->clear ();
0222 
0223         m_colorDepthCombo->insertItem (0, i18n ("Monochrome"));
0224         m_colorDepthCombo->insertItem (1, i18n ("Monochrome (Dithered)"));
0225 
0226         if (newMimeTypeMaxDepth >= 8)
0227         {
0228             m_colorDepthCombo->insertItem (2, i18n ("256 Color"));
0229             m_colorDepthCombo->insertItem (3, i18n ("256 Color (Dithered)"));
0230         }
0231 
0232         if (newMimeTypeMaxDepth >= 24)
0233         {
0234             m_colorDepthCombo->insertItem (4, i18n ("24-bit Color"));
0235         }
0236 
0237         if (m_colorDepthComboLastSelectedItem >= 0 &&
0238             m_colorDepthComboLastSelectedItem < m_colorDepthCombo->count ())
0239         {
0240         #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
0241             qCDebug(kpLogWidgets) << "\tsetting colorDepthCombo to "
0242                        << m_colorDepthComboLastSelectedItem << endl;
0243         #endif
0244 
0245             m_colorDepthCombo->setCurrentIndex (m_colorDepthComboLastSelectedItem);
0246         }
0247         else
0248         {
0249         #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
0250             qCDebug(kpLogWidgets) << "\tsetting colorDepthCombo to max item since"
0251                        << " m_colorDepthComboLastSelectedItem="
0252                        << m_colorDepthComboLastSelectedItem
0253                        << " out of range" << endl;
0254         #endif
0255 
0256             m_colorDepthCombo->setCurrentIndex (m_colorDepthCombo->count () - 1);
0257         }
0258     }
0259 
0260 
0261     m_baseDocumentSaveOptions.setMimeType (string);
0262 
0263     if (mimeTypeHasConfigurableColorDepth ()) {
0264         setMode (ColorDepth);
0265     }
0266     else if (mimeTypeHasConfigurableQuality ()) {
0267         setMode (Quality);
0268     }
0269     else {
0270         setMode (None);
0271     }
0272 
0273     updatePreview ();
0274 }
0275 
0276 
0277 // public
0278 int kpDocumentSaveOptionsWidget::colorDepth () const
0279 {
0280     if (mode () & ColorDepth)
0281     {
0282         // The returned values match QImage's supported depths.
0283         switch (m_colorDepthCombo->currentIndex ())
0284         {
0285         case 0:
0286         case 1:
0287             return 1;
0288 
0289         case 2:
0290         case 3:
0291             return 8;
0292 
0293         case 4:
0294             // 24-bit is known as 32-bit with QImage.
0295             return 32;
0296 
0297         default:
0298             return kpDocumentSaveOptions::invalidColorDepth ();
0299         }
0300     }
0301     else
0302     {
0303         return m_baseDocumentSaveOptions.colorDepth ();
0304     }
0305 }
0306 
0307 // public
0308 bool kpDocumentSaveOptionsWidget::dither () const
0309 {
0310     if (mode () & ColorDepth)
0311     {
0312         return (m_colorDepthCombo->currentIndex () == 1 ||
0313                 m_colorDepthCombo->currentIndex () == 3);
0314     }
0315 
0316     return m_baseDocumentSaveOptions.dither ();
0317 }
0318 
0319 // protected static
0320 int kpDocumentSaveOptionsWidget::colorDepthComboItemFromColorDepthAndDither (
0321     int depth, bool dither)
0322 {
0323     switch (depth) {
0324     case 1:
0325         if (!dither) {
0326             return 0;
0327         }
0328         return 1;
0329 
0330     case 8:
0331         if (!dither) {
0332             return 2;
0333         }
0334         return 3;
0335 
0336     case 32:
0337         return 4;
0338 
0339     default:
0340         return -1;
0341     }
0342 }
0343 
0344 // public slots
0345 void kpDocumentSaveOptionsWidget::setColorDepthDither (int newDepth, bool newDither)
0346 {
0347 #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
0348     qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::setColorDepthDither("
0349                << "depth=" << newDepth
0350                << ",dither=" << newDither
0351                << ")" << endl;
0352 #endif
0353 
0354     m_baseDocumentSaveOptions.setColorDepth (newDepth);
0355     m_baseDocumentSaveOptions.setDither (newDither);
0356 
0357 
0358     const int comboItem = colorDepthComboItemFromColorDepthAndDither (
0359                               newDepth, newDither);
0360     // TODO: Ignoring when comboItem >= m_colorDepthCombo->count() is wrong.
0361     //       This happens if this mimeType has configurable colour depth
0362     //       and an incorrect maximum colour depth (less than a QImage of
0363     //       this mimeType, opened by kpDocument).
0364     if (comboItem >= 0 && comboItem < m_colorDepthCombo->count ()) {
0365         m_colorDepthCombo->setCurrentIndex (comboItem);
0366     }
0367 
0368 
0369     slotColorDepthSelected ();
0370 }
0371 
0372 
0373 // protected slot
0374 void kpDocumentSaveOptionsWidget::slotColorDepthSelected ()
0375 {
0376     if (mode () & ColorDepth)
0377     {
0378         m_colorDepthComboLastSelectedItem = m_colorDepthCombo->currentIndex ();
0379     }
0380     else
0381     {
0382         m_colorDepthComboLastSelectedItem =
0383             colorDepthComboItemFromColorDepthAndDither (
0384                 m_baseDocumentSaveOptions.colorDepth (),
0385                 m_baseDocumentSaveOptions.dither ());
0386     }
0387 
0388 #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
0389     qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::slotColorDepthSelected()"
0390                << " mode&ColorDepth=" << (mode () & ColorDepth)
0391                << " colorDepthComboLastSelectedItem="
0392                << m_colorDepthComboLastSelectedItem
0393                << endl;
0394 #endif
0395 }
0396 
0397 
0398 // public
0399 int kpDocumentSaveOptionsWidget::quality () const
0400 {
0401     if (mode () & Quality)
0402     {
0403         return m_qualityInput->value ();
0404     }
0405 
0406     return m_baseDocumentSaveOptions.quality ();
0407 }
0408 
0409 // public
0410 void kpDocumentSaveOptionsWidget::setQuality (int newQuality)
0411 {
0412 #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
0413     qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::setQuality("
0414                << newQuality << ")" << endl;
0415 #endif
0416 
0417     m_baseDocumentSaveOptions.setQuality (newQuality);
0418     m_qualityInput->setValue (newQuality == -1/*QImage::save() default*/ ?
0419                                   75 :
0420                                   newQuality);
0421 }
0422 
0423 
0424 // public
0425 kpDocumentSaveOptions kpDocumentSaveOptionsWidget::documentSaveOptions () const
0426 {
0427     return kpDocumentSaveOptions (mimeType (), colorDepth (), dither (), quality ());
0428 }
0429 
0430 // public
0431 void kpDocumentSaveOptionsWidget::setDocumentSaveOptions (
0432     const kpDocumentSaveOptions &saveOptions)
0433 {
0434     setMimeType (saveOptions.mimeType ());
0435     setColorDepthDither (saveOptions.colorDepth (), saveOptions.dither ());
0436     setQuality (saveOptions.quality ());
0437 }
0438 
0439 
0440 // public
0441 void kpDocumentSaveOptionsWidget::setDocumentPixmap (const QImage &documentPixmap)
0442 {
0443     delete m_documentPixmap;
0444     m_documentPixmap = new QImage (documentPixmap);
0445 
0446     updatePreview ();
0447 }
0448 
0449 // public
0450 void kpDocumentSaveOptionsWidget::setDocumentMetaInfo (
0451     const kpDocumentMetaInfo &metaInfo)
0452 {
0453     m_documentMetaInfo = metaInfo;
0454 
0455     updatePreview ();
0456 }
0457 
0458 
0459 // public
0460 kpDocumentSaveOptionsWidget::Mode kpDocumentSaveOptionsWidget::mode () const
0461 {
0462     return m_mode;
0463 }
0464 
0465 // public
0466 void kpDocumentSaveOptionsWidget::setMode (Mode mode)
0467 {
0468     m_mode = mode;
0469 
0470 
0471     // If mode == None, we show still show the Color Depth widgets but disabled
0472     m_colorDepthLabel->setVisible (mode != Quality);
0473     m_colorDepthCombo->setVisible (mode != Quality);
0474     m_colorDepthSpaceWidget->setVisible (mode != Quality);
0475 
0476     m_qualityLabel->setVisible (mode == Quality);
0477     m_qualityInput->setVisible (mode == Quality);
0478 
0479 
0480     m_colorDepthLabel->setEnabled (mode == ColorDepth);
0481     m_colorDepthCombo->setEnabled (mode == ColorDepth);
0482 
0483     m_qualityLabel->setEnabled (mode == Quality);
0484     m_qualityInput->setEnabled (mode == Quality);
0485 
0486 
0487     // SYNC: HACK: When changing between color depth and quality widgets,
0488     //       we change the height of "this", causing the text on the labels
0489     //       to move but the first instance of the text doesn't get erased.
0490     //       Qt bug.
0491     QTimer::singleShot (0, this, &kpDocumentSaveOptionsWidget::repaintLabels);
0492 }
0493 
0494 // protected slot
0495 void kpDocumentSaveOptionsWidget::repaintLabels ()
0496 {
0497     if (mode () != Quality) {
0498         m_colorDepthLabel->repaint ();
0499     }
0500     if (mode () == Quality) {
0501         m_qualityLabel->repaint ();
0502     }
0503 }
0504 
0505 
0506 // protected slot
0507 void kpDocumentSaveOptionsWidget::showPreview (bool yes)
0508 {
0509 #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
0510     qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::showPreview(" << yes << ")"
0511                << " m_previewDialog=" << bool (m_previewDialog)
0512                << endl;
0513 #endif
0514 
0515     if (yes == bool (m_previewDialog)) {
0516         return;
0517     }
0518 
0519     if (!m_visualParent) {
0520         return;
0521     }
0522 
0523     if (yes)
0524     {
0525         m_previewDialog = new kpDocumentSaveOptionsPreviewDialog( m_visualParent );
0526         m_previewDialog->setObjectName( QStringLiteral( "previewSaveDialog" ) );
0527         updatePreview ();
0528 
0529         connect (m_previewDialog, &kpDocumentSaveOptionsPreviewDialog::finished,
0530                  this, &kpDocumentSaveOptionsWidget::hidePreview);
0531 
0532 
0533         KConfigGroup cfg (KSharedConfig::openConfig (), QStringLiteral(kpSettingsGroupPreviewSave));
0534 
0535         if (cfg.hasKey (kpSettingPreviewSaveUpdateDelay))
0536         {
0537             m_updatePreviewDelay = cfg.readEntry (kpSettingPreviewSaveUpdateDelay, 0);
0538         }
0539         else
0540         {
0541             cfg.writeEntry (kpSettingPreviewSaveUpdateDelay, m_updatePreviewDelay);
0542             cfg.sync ();
0543         }
0544 
0545         if (m_updatePreviewDelay < 0) {
0546             m_updatePreviewDelay = 0;
0547         }
0548     #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
0549         qCDebug(kpLogWidgets) << "\tread cfg preview dialog update delay=" << m_updatePreviewDelay;
0550     #endif
0551 
0552 
0553         if (m_previewDialogLastRelativeGeometry.isEmpty ())
0554         {
0555         #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
0556             qCDebug(kpLogWidgets) << "\tread cfg preview dialog last rel geometry";
0557         #endif
0558             KConfigGroup cfg (KSharedConfig::openConfig (), QStringLiteral(kpSettingsGroupPreviewSave));
0559 
0560             m_previewDialogLastRelativeGeometry = cfg.readEntry (
0561                 kpSettingPreviewSaveGeometry, QRect ());
0562         }
0563 
0564     #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
0565         qCDebug(kpLogWidgets) << "\tpreviewDialogLastRelativeGeometry="
0566                    << m_previewDialogLastRelativeGeometry
0567                    << " visualParent->rect()=" << m_visualParent->rect ()
0568                    << endl;
0569     #endif
0570 
0571         QRect relativeGeometry;
0572         if (!m_previewDialogLastRelativeGeometry.isEmpty () &&
0573             m_visualParent->rect ().intersects (m_previewDialogLastRelativeGeometry))
0574         {
0575         #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
0576             qCDebug(kpLogWidgets) << "\tok";
0577         #endif
0578             relativeGeometry = m_previewDialogLastRelativeGeometry;
0579         }
0580         else
0581         {
0582         #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
0583             qCDebug(kpLogWidgets) << "\t\tinvalid";
0584         #endif
0585             const int margin = 20;
0586 
0587             relativeGeometry =
0588                 QRect (m_visualParent->width () -
0589                            m_previewDialog->preferredMinimumSize ().width () -
0590                                margin,
0591                        margin * 2,  // Avoid folder combo
0592                        m_previewDialog->preferredMinimumSize ().width (),
0593                        m_previewDialog->preferredMinimumSize ().height ());
0594         }
0595 
0596 
0597         const QRect globalGeometry =
0598             kpWidgetMapper::toGlobal (m_visualParent,
0599                                       relativeGeometry);
0600     #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
0601         qCDebug(kpLogWidgets) << "\trelativeGeometry=" << relativeGeometry
0602                    << " globalGeometry=" << globalGeometry
0603                    << endl;
0604     #endif
0605 
0606         m_previewDialog->resize (globalGeometry.size ());
0607         m_previewDialog->move (globalGeometry.topLeft ());
0608 
0609 
0610         m_previewDialog->show ();
0611 
0612 
0613     #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
0614         qCDebug(kpLogWidgets) << "\tgeometry after show="
0615                    << QRect (m_previewDialog->x (), m_previewDialog->y (),
0616                               m_previewDialog->width (), m_previewDialog->height ())
0617                    << endl;
0618     #endif
0619 
0620         updatePreviewDialogLastRelativeGeometry ();
0621 
0622         connect (m_previewDialog, &kpDocumentSaveOptionsPreviewDialog::moved,
0623                  this, &kpDocumentSaveOptionsWidget::updatePreviewDialogLastRelativeGeometry);
0624 
0625         connect (m_previewDialog, &kpDocumentSaveOptionsPreviewDialog::resized,
0626                  this, &kpDocumentSaveOptionsWidget::updatePreviewDialogLastRelativeGeometry);
0627 
0628         m_updatePreviewDialogLastRelativeGeometryTimer->start (200/*ms*/);
0629     }
0630     else
0631     {
0632         m_updatePreviewDialogLastRelativeGeometryTimer->stop ();
0633 
0634         KConfigGroup cfg (KSharedConfig::openConfig (), QStringLiteral(kpSettingsGroupPreviewSave));
0635 
0636         cfg.writeEntry (kpSettingPreviewSaveGeometry, m_previewDialogLastRelativeGeometry);
0637         cfg.sync ();
0638 
0639     #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
0640         qCDebug(kpLogWidgets) << "\tsaving preview geometry "
0641                    << m_previewDialogLastRelativeGeometry
0642                    << " (Qt would have us believe "
0643                    << kpWidgetMapper::fromGlobal (m_visualParent,
0644                           QRect (m_previewDialog->x (), m_previewDialog->y (),
0645                                  m_previewDialog->width (), m_previewDialog->height ()))
0646                    << ")"
0647                    << endl;
0648     #endif
0649 
0650         m_previewDialog->deleteLater ();
0651         m_previewDialog = nullptr;
0652     }
0653 }
0654 
0655 // protected slot
0656 void kpDocumentSaveOptionsWidget::hidePreview ()
0657 {
0658     if (m_previewButton->isChecked ()) {
0659         m_previewButton->toggle ();
0660     }
0661 }
0662 
0663 
0664 // protected slot
0665 void kpDocumentSaveOptionsWidget::updatePreviewDelayed ()
0666 {
0667     // (single shot)
0668     m_updatePreviewTimer->start (m_updatePreviewDelay);
0669 }
0670 
0671 // protected slot
0672 void kpDocumentSaveOptionsWidget::updatePreview ()
0673 {
0674     if (!m_previewDialog || !m_documentPixmap) {
0675         return;
0676     }
0677 
0678 
0679     m_updatePreviewTimer->stop ();
0680 
0681 
0682     QApplication::setOverrideCursor (Qt::WaitCursor);
0683 
0684     QByteArray data;
0685 
0686     QBuffer buffer (&data);
0687     buffer.open (QIODevice::WriteOnly);
0688     bool savedOK = kpDocument::savePixmapToDevice (*m_documentPixmap,
0689                                     &buffer,
0690                                     documentSaveOptions (),
0691                                     m_documentMetaInfo,
0692                                     false/*no lossy prompt*/,
0693                                     this);
0694     buffer.close ();
0695 
0696 
0697     QImage image;
0698 
0699     // Ignore any failed saves.
0700     //
0701     // Failed saves might literally have written half a file.  The final
0702     // save (when the user clicks OK), _will_ fail so we shouldn't have a
0703     // preview even if this "half a file" is actually loadable by
0704     // QImage::loadFormData().
0705     if (savedOK)
0706     {
0707         image.loadFromData(data);
0708     }
0709     else
0710     {
0711         // Leave <image> as invalid.
0712         // TODO: This code path has not been well tested.
0713         //       Will we trigger divide by zero errors in "m_previewDialog"?
0714     }
0715 
0716     // REFACTOR: merge with kpDocument::getPixmapFromFile()
0717     m_previewDialog->setFilePixmapAndSize (image, data.size ());
0718 
0719     QApplication::restoreOverrideCursor ();
0720 }
0721 
0722 // protected slot
0723 void kpDocumentSaveOptionsWidget::updatePreviewDialogLastRelativeGeometry ()
0724 {
0725 #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
0726     qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::"
0727                << "updatePreviewDialogLastRelativeGeometry()"
0728                << endl;
0729 #endif
0730 
0731     if (m_previewDialog && m_previewDialog->isVisible ())
0732     {
0733         m_previewDialogLastRelativeGeometry =
0734             kpWidgetMapper::fromGlobal (m_visualParent,
0735                 QRect (m_previewDialog->x (), m_previewDialog->y (),
0736                        m_previewDialog->width (), m_previewDialog->height ()));
0737     #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
0738         qCDebug(kpLogWidgets) << "\tcaching pos = "
0739                    << m_previewDialogLastRelativeGeometry;
0740     #endif
0741     }
0742     else
0743     {
0744     #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
0745         qCDebug(kpLogWidgets) << "\tnot visible - ignoring geometry";
0746     #endif
0747     }
0748 }
0749 
0750 #include "moc_kpDocumentSaveOptionsWidget.cpp"