File indexing completed on 2024-04-21 15:12:02

0001 /************************************************************************
0002  *                                  *
0003  *  This file is part of Kooka, a scanning/OCR application using    *
0004  *  Qt <http://www.qt.io> and KDE Frameworks <http://www.kde.org>.  *
0005  *                                  *
0006  *  Copyright (C) 2008-2016 Jonathan Marten <jjm@keelhaul.me.uk>    *
0007  *                                  *
0008  *  Kooka is free software; you can redistribute it and/or modify it    *
0009  *  under the terms of the GNU Library General Public License as    *
0010  *  published by the Free Software Foundation and appearing in the  *
0011  *  file COPYING included in the packaging of this file;  either    *
0012  *  version 2 of the License, or (at your option) any later version.    *
0013  *                                  *
0014  *  As a special exception, permission is given to link this program    *
0015  *  with any version of the KADMOS OCR/ICR engine (a product of     *
0016  *  reRecognition GmbH, Kreuzlingen), and distribute the resulting  *
0017  *  executable without including the source code for KADMOS in the  *
0018  *  source distribution.                        *
0019  *                                  *
0020  *  This program is distributed in the hope that it will be useful, *
0021  *  but WITHOUT ANY WARRANTY; without even the implied warranty of  *
0022  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   *
0023  *  GNU General Public License for more details.            *
0024  *                                  *
0025  *  You should have received a copy of the GNU General Public       *
0026  *  License along with this program;  see the file COPYING.  If     *
0027  *  not, see <http://www.gnu.org/licenses/>.                *
0028  *                                  *
0029  ************************************************************************/
0030 
0031 #include "formatdialog.h"
0032 
0033 #include <qlayout.h>
0034 #include <qlabel.h>
0035 #include <qcheckbox.h>
0036 #include <qcombobox.h>
0037 #include <qpushbutton.h>
0038 #include <qlineedit.h>
0039 #include <qlistwidget.h>
0040 #include <qicon.h>
0041 #include <qmimetype.h>
0042 #include <qmimedatabase.h>
0043 #include <qimagewriter.h>
0044 
0045 #include <kseparator.h>
0046 #include <klocalizedstring.h>
0047 #include <kconfigskeleton.h>
0048 
0049 #include "imageformat.h"
0050 #include "kookasettings.h"
0051 #include "kooka_logging.h"
0052 
0053 
0054 // The ImageType can be OR-ed here to make a set of possible formats
0055 Q_DECLARE_OPERATORS_FOR_FLAGS(ScanImage::ImageTypes)
0056 
0057 // Information for a format.  Static, so only POD allowed.
0058 struct FormatInfo {
0059     // A semicolon-separated list of MIME types that make up this format.
0060     const char *mime;
0061     // An I18N_NOOP()'ed help string for the format.
0062     const char *helpString;
0063     // An OR-ed set of image types that this format is recommended for.
0064     // ScanImage::None means that it is not recommended for any image type.
0065     ScanImage::ImageTypes recForTypes;
0066     // An OR-ed set of image types that this format can be used for.
0067     // ScanImage::None means that it can be used for any image type.
0068     ScanImage::ImageTypes okForTypes;
0069 };
0070 
0071 // Known formats with help text and compatibility recommendations
0072 static struct FormatInfo formats[] =
0073 {
0074     {
0075         "image/bmp",                    // BMP
0076         I18N_NOOP(
0077             "<b>Bitmap Picture</b> is a widely used format for images under MS Windows. \
0078 It is suitable for color, grayscale and line art images.\
0079 <p>This format is widely supported but is not recommended, use an open format \
0080 instead."),
0081         ScanImage::None,
0082         ScanImage::None
0083     },
0084 
0085     {
0086         "image/x-portable-bitmap",          // PBM
0087         I18N_NOOP(
0088             "<b>Portable Bitmap</b>, as used by Netpbm, is an uncompressed format for line art \
0089 (bitmap) images. Only 1 bit per pixel depth is supported."),
0090         ScanImage::BlackWhite,
0091         ScanImage::BlackWhite
0092     },
0093 
0094     {
0095         "image/x-portable-graymap",         // PGM
0096         I18N_NOOP(
0097             "<b>Portable Greymap</b>, as used by Netpbm, is an uncompressed format for grayscale \
0098 images. Only 8 bit per pixel depth is supported."),
0099         ScanImage::Greyscale,
0100         ScanImage::Greyscale
0101     },
0102 
0103     {
0104         "image/x-portable-pixmap",          // PPM
0105         I18N_NOOP(
0106             "<b>Portable Pixmap</b>, as used by Netpbm, is an uncompressed format for full color \
0107 images. Only 24 bit per pixel RGB is supported."),
0108         ScanImage::LowColour | ScanImage::HighColour,
0109         ScanImage::LowColour | ScanImage::HighColour
0110     },
0111 
0112     {
0113         "image/x-pcx;image/vnd.zbrush.pcx",     // PCX
0114         I18N_NOOP(
0115             "<b>PCX</b> is a lossless compressed format which is often supported by PC imaging \
0116 applications, although it is rather old and unsophisticated.  It is suitable for \
0117 color and grayscale images.\
0118 <p>This format is not recommended, use an open format instead."),
0119         ScanImage::None,
0120         ScanImage::None
0121     },
0122 
0123     {
0124         "image/x-xbitmap",              // XBM
0125         I18N_NOOP(
0126             "<b>X Bitmap</b> is often used by the X Window System to store cursor and icon bitmaps.\
0127 <p>Unless required for this purpose, use a general purpose format instead."),
0128         ScanImage::None,
0129         ScanImage::BlackWhite
0130     },
0131 
0132     {
0133         "image/x-xpixmap",              // XPM
0134         I18N_NOOP(
0135             "<b>X Pixmap</b> is often used by the X Window System for color icons and other images.\
0136 <p>Unless required for this purpose, use a general purpose format instead."),
0137         ScanImage::None,
0138         ScanImage::LowColour | ScanImage::HighColour
0139     },
0140 
0141     {
0142         "image/png",                    // PNG
0143         I18N_NOOP(
0144             "<b>Portable Network Graphics</b> is a lossless compressed format designed to be \
0145 portable and extensible. It is suitable for any type of color or grayscale images, \
0146 indexed or true color.\
0147 <p>PNG is an open format which is widely supported."),
0148         ScanImage::BlackWhite | ScanImage::LowColour | ScanImage::Greyscale | ScanImage::HighColour,
0149         ScanImage::None
0150     },
0151 
0152     {
0153         "image/jpeg",                   // JPEG JPG
0154         I18N_NOOP(
0155             "<b>JPEG</b> is a compressed format suitable for true color or grayscale images. \
0156 It is a lossy format, so it is not recommended for archiving or for repeated loading \
0157 and saving.\
0158 <p>This is an open format which is widely supported."),
0159         ScanImage::HighColour | ScanImage::Greyscale,
0160         ScanImage::LowColour | ScanImage::Greyscale | ScanImage::HighColour
0161     },
0162 
0163     {
0164         "image/jp2",                    // JP2
0165         I18N_NOOP(
0166             "<b>JPEG 2000</b> was intended as an update to the JPEG format, with the option of \
0167 lossless compression, but so far is not widely supported. It is suitable for true \
0168 color or grayscale images."),
0169         ScanImage::None,
0170         ScanImage::LowColour | ScanImage::Greyscale | ScanImage::HighColour
0171     },
0172 
0173     {
0174         "image/x-eps",                  // EPS EPSF EPSI
0175         I18N_NOOP(
0176             "<b>Encapsulated PostScript</b> is derived from the PostScript&trade; \
0177 page description language.  Use this format for importing into other \
0178 applications, or to use with (e.g.) TeX."),
0179         ScanImage::None,
0180         ScanImage::None
0181     },
0182 
0183     {
0184         "image/x-tga",                  // TGA
0185         I18N_NOOP(
0186             "<b>Truevision Targa</b> can store full color images with an alpha channel, and is \
0187 used extensively by animation and video applications.\
0188 <p>This format is not recommended, use an open format instead."),
0189         ScanImage::None,
0190         ScanImage::LowColour | ScanImage::Greyscale | ScanImage::HighColour
0191     },
0192 
0193     {
0194         "image/gif",                    // GIF
0195         I18N_NOOP(                  // writing may not be supported
0196             "<b>Graphics Interchange Format</b> is a popular but patent-encumbered format often \
0197 used for web graphics.  It uses lossless compression with up to 256 colors and \
0198 optional transparency.\
0199 <p>For legal reasons this format is not recommended, use an open format instead."),
0200         ScanImage::None,
0201         ScanImage::LowColour | ScanImage::Greyscale
0202     },
0203 
0204     {
0205         "image/tiff",                   // TIF TIFF
0206         I18N_NOOP(                  // writing may not be supported
0207             "<b>Tagged Image File Format</b> is a versatile and extensible file format widely \
0208 supported by imaging and publishing applications. It supports indexed and true color \
0209 images with alpha transparency.\
0210 <p>Because there are many variations, there may sometimes be compatibility problems. \
0211 Unless required for use with other applications, use an open format instead."),
0212         ScanImage::BlackWhite | ScanImage::LowColour | ScanImage::Greyscale | ScanImage::HighColour,
0213         ScanImage::None
0214     },
0215 
0216     {
0217         "video/x-mng",                  // MNG
0218         I18N_NOOP(
0219             "<b>Multiple-image Network Graphics</b> is derived from the PNG standard and is \
0220 intended for animated images.  It is an open format suitable for all types of \
0221 images.\
0222 <p>Images produced by a scanner will not be animated, so unless specifically \
0223 required for use with other applications use PNG instead."),
0224         ScanImage::None,
0225         ScanImage::None
0226     },
0227 
0228     {
0229         "image/x-sgi",                  // SGI
0230         I18N_NOOP(
0231             "This is the <b>Silicon Graphics</b> native image file format, supporting 24 bit \
0232 true color images with optional lossless compression.\
0233 <p>Unless specifically required, use an open format instead."),
0234         ScanImage::None,
0235         ScanImage::LowColour | ScanImage::HighColour
0236     },
0237 
0238     {
0239         "image/vnd.wap.wbmp",               // WBMP
0240         I18N_NOOP(
0241             "<b>Wireless Bitmap</b> is a monochrome bitmap format optimised \
0242 for WAP mobile devices.  It supports black and white bitmaps only.\
0243 <p>Unless specifically required, use an general purpose format instead."),
0244         ScanImage::None,
0245         ScanImage::BlackWhite
0246     },
0247 
0248     {
0249         "image/webp",                   // WEBP
0250         I18N_NOOP(
0251             "<b>WebP</b> is intended to be an open standard for true colour \
0252 images with optional transparency.  It is widely supported by modern \
0253 web browsers and graphics software.\
0254 <p>Various compression methods, both lossy and lossless, are supported. \
0255 Lossy compression is not recommended for archiving or for repeated loading \
0256 and saving."),
0257         ScanImage::HighColour | ScanImage::Greyscale,
0258         ScanImage::LowColour | ScanImage::Greyscale | ScanImage::HighColour
0259     },
0260 
0261     { nullptr, nullptr, ScanImage::None, ScanImage::None }
0262 };
0263 
0264 static QString sLastFormat;             // format last used, whether
0265                             // remembered or not
0266 
0267 FormatDialog::FormatDialog(QWidget *parent, ScanImage::ImageType type,
0268                            bool askForFormat, const ImageFormat &format,
0269                            bool askForFilename, const QString &filename)
0270     : DialogBase(parent),
0271       mFormat(format),                  // save these to return, if
0272       mFilename(filename)               // they are not requested
0273 {
0274     setObjectName("FormatDialog");
0275 
0276     setModal(true);
0277     // KDE4 buttons: Ok  Cancel  User1=SelectFormat
0278     // KF5 buttons:  Ok  Cancel  Yes=SelectFormat
0279     setButtons(QDialogButtonBox::Ok|QDialogButtonBox::Cancel|QDialogButtonBox::Yes);
0280     setWindowTitle(askForFormat ? i18n("Save Assistant") : i18n("Save Scan"));
0281 
0282     QWidget *page = new QWidget(this);
0283     setMainWidget(page);
0284 
0285     mHelpLabel = nullptr;
0286     mSubformatCombo = nullptr;
0287     mFormatList = nullptr;
0288     mSubformatLabel = nullptr;
0289     mDontAskCheck = nullptr;
0290     mRecOnlyCheck = nullptr;
0291     mExtensionLabel = nullptr;
0292     mFilenameEdit = nullptr;
0293 
0294     if (!mFormat.isValid()) askForFormat = true;    // must ask if none
0295     mWantAssistant = false;
0296 
0297     QGridLayout *gl = new QGridLayout(page);
0298     gl->setMargin(0);
0299     int row = 0;
0300 
0301     QLabel *l1;
0302     KSeparator *sep;
0303 
0304     if (askForFormat)                   // format selector section
0305     {
0306         l1 = new QLabel(xi18nc("@info", "Select a format to save the scanned image.<nl/>This is a <emphasis strong=\"1\">%1</emphasis>.",
0307                                ImgSaver::picTypeAsString(type)), page);
0308         gl->addWidget(l1, row, 0, 1, 3);
0309         ++row;
0310 
0311         sep = new KSeparator(Qt::Horizontal, page);
0312         gl->addWidget(sep, row, 0, 1, 3);
0313         ++row;
0314 
0315         // Insert scrolled list for formats
0316         l1 = new QLabel(i18n("File format:"), page);
0317         gl->addWidget(l1, row, 0, Qt::AlignLeft);
0318 
0319         mFormatList = new QListWidget(page);
0320         // The list box is filled later.
0321 
0322         mImageType = type;
0323         connect(mFormatList, &QListWidget::currentItemChanged, this, &FormatDialog::formatSelected);
0324         l1->setBuddy(mFormatList);
0325         gl->addWidget(mFormatList, row + 1, 0);
0326         gl->setRowStretch(row + 1, 1);
0327 
0328         // Insert label for help text
0329         mHelpLabel = new QLabel(page);
0330         mHelpLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken);
0331         mHelpLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop);
0332         mHelpLabel->setMinimumSize(230, 200);
0333         mHelpLabel->setWordWrap(true);
0334         mHelpLabel->setMargin(4);
0335         gl->addWidget(mHelpLabel, row, 1, 4, 2);
0336 
0337         // Insert selection box for subformat
0338         mSubformatLabel = new QLabel(i18n("Image sub-format:"), page);
0339         mSubformatLabel->setEnabled(false);
0340         gl->addWidget(mSubformatLabel, row + 2, 0, Qt::AlignLeft);
0341 
0342         mSubformatCombo = new QComboBox(page);
0343         mSubformatCombo->setEnabled(false);     // not yet implemented
0344         gl->addWidget(mSubformatCombo, row + 3, 0);
0345         mSubformatLabel->setBuddy(mSubformatCombo);
0346         row += 4;
0347 
0348         sep = new KSeparator(Qt::Horizontal, page);
0349         gl->addWidget(sep, row, 0, 1, 3);
0350         ++row;
0351 
0352         // Checkbox to store setting
0353         const KConfigSkeletonItem *ski = KookaSettings::self()->saverOnlyRecommendedTypesItem();
0354         Q_ASSERT(ski!=nullptr);
0355         mRecOnlyCheck = new QCheckBox(ski->label(), page);
0356         mRecOnlyCheck->setToolTip(ski->toolTip());
0357         mRecOnlyCheck->setChecked(KookaSettings::saverOnlyRecommendedTypes());
0358         connect(mRecOnlyCheck, &QCheckBox::toggled, this, &FormatDialog::buildFormatList);
0359         gl->addWidget(mRecOnlyCheck, row, 0, 1, 3, Qt::AlignLeft);
0360         ++row;
0361 
0362         ski = KookaSettings::self()->saverAlwaysUseFormatItem();
0363         Q_ASSERT(ski!=nullptr);
0364         mDontAskCheck  = new QCheckBox(ski->label(), page);
0365         mDontAskCheck->setToolTip(ski->toolTip());
0366         gl->addWidget(mDontAskCheck, row, 0, 1, 3, Qt::AlignLeft);
0367         ++row;
0368 
0369         buildFormatList(mRecOnlyCheck->isChecked());    // now have this setting
0370                             // don't want this button
0371         buttonBox()->button(QDialogButtonBox::Yes)->setVisible(false);
0372     }
0373 
0374     gl->setColumnStretch(1, 1);
0375     gl->setColumnMinimumWidth(1, horizontalSpacing());
0376 
0377     if (askForFormat && askForFilename) {
0378         sep = new KSeparator(Qt::Horizontal, page);
0379         gl->addWidget(sep, row, 0, 1, 3);
0380         ++row;
0381     }
0382 
0383     if (askForFilename) {               // file name section
0384         l1 = new QLabel(i18n("File name:"), page);
0385         gl->addWidget(l1, row, 0, 1, 3);
0386         ++row;
0387 
0388         mFilenameEdit = new QLineEdit(filename, page);
0389         connect(mFilenameEdit, &QLineEdit::textChanged, this, &FormatDialog::checkValid);
0390         l1->setBuddy(mFilenameEdit);
0391         gl->addWidget(mFilenameEdit, row, 0, 1, 2);
0392 
0393         mExtensionLabel = new QLabel("", page);
0394         gl->addWidget(mExtensionLabel, row, 2, Qt::AlignLeft);
0395         ++row;
0396 
0397         if (!askForFormat) {
0398             buttonBox()->button(QDialogButtonBox::Yes)->setText(i18n("Select Format..."));
0399         }
0400     }
0401 
0402     if (mFormatList != nullptr)             // have the format selector
0403     {
0404         setSelectedFormat(format);          // preselect the remembered format
0405     }
0406     else                        // no format selector, but
0407     {                           // asking for a file name
0408         showExtension(format);              // show extension it will have
0409     }
0410 
0411     connect(buttonBox()->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &FormatDialog::slotOk);
0412     connect(buttonBox()->button(QDialogButtonBox::Yes), &QPushButton::clicked, this, &FormatDialog::slotUser1);
0413 }
0414 
0415 void FormatDialog::showEvent(QShowEvent *ev)
0416 {
0417     DialogBase::showEvent(ev);
0418 
0419     if (mFilenameEdit != nullptr) {         // asking for a file name
0420         mFilenameEdit->setFocus();          // set focus to that
0421         mFilenameEdit->selectAll();         // highlight for editing
0422     }
0423 }
0424 
0425 void FormatDialog::showExtension(const ImageFormat &format)
0426 {
0427     if (mExtensionLabel == nullptr) return;     // not showing this
0428     mExtensionLabel->setText("." + format.extension()); // show extension it will have
0429 }
0430 
0431 void FormatDialog::formatSelected(QListWidgetItem *item)
0432 {
0433     if (mHelpLabel == nullptr) return;          // not showing this
0434 
0435     if (item == nullptr) {                  // nothing is selected
0436         mHelpLabel->setText(i18n("No format selected."));
0437         setButtonEnabled(QDialogButtonBox::Ok, false);
0438 
0439         mFormatList->clearSelection();
0440         if (mExtensionLabel != nullptr) {
0441             mExtensionLabel->setText(".???");
0442         }
0443         return;
0444     }
0445 
0446     mFormatList->setCurrentItem(item);          // focus highlight -> select
0447 
0448     // Locate the help text for the format
0449     const char *helptxt = nullptr;
0450     const QByteArray mimename = item->data(Qt::UserRole).toByteArray();
0451     for (const FormatInfo *ip = &formats[0]; ip->mime!=nullptr; ++ip)
0452     {
0453         const QList<QByteArray> mimetypes = QByteArray(ip->mime).split(';');
0454         if (mimetypes.contains(mimename))
0455         {
0456             helptxt = ip->helpString;
0457             break;
0458         }
0459     }
0460 
0461     QMimeDatabase db;
0462     QMimeType mime = db.mimeTypeForName(mimename);
0463     ImageFormat format = ImageFormat::formatForMime(mime);
0464     qCDebug(KOOKA_LOG) << "MIME" << mimename << "format" << format;
0465 
0466     if (helptxt != nullptr) {               // found some help text
0467         mHelpLabel->setText(i18n(helptxt));     // set the hint
0468         check_subformat(format);            // and check subformats
0469     } else {
0470         mHelpLabel->setText(i18n("No information is available for this format."));
0471     }
0472 
0473     if (mDontAskCheck != nullptr) {
0474         mDontAskCheck->setChecked(ImgSaver::isRememberedFormat(mImageType, format));
0475     }
0476 
0477     showExtension(format);
0478     checkValid();
0479 }
0480 
0481 // TODO: implement subtypes
0482 void FormatDialog::check_subformat(const ImageFormat &format)
0483 {
0484     if (mSubformatCombo == nullptr) return;     // not showing this
0485 
0486     mSubformatCombo->setEnabled(false);         // not yet implemented
0487     mSubformatLabel->setEnabled(false);
0488 }
0489 
0490 void FormatDialog::setSelectedFormat(const ImageFormat &format)
0491 {
0492     if (mFormatList == nullptr) return;         // not showing this
0493 
0494     if (format.isValid())               // valid format to select
0495     {
0496         const QMimeType mime = format.mime();
0497         if (!mime.isValid()) return;
0498 
0499         for (int i = 0; i < mFormatList->count(); ++i) {
0500             QListWidgetItem *item = mFormatList->item(i);
0501             if (item == nullptr) {
0502                 continue;
0503             }
0504             QString mimename = item->data(Qt::UserRole).toString();
0505             if (mime.inherits(mimename)) {
0506                 mFormatList->setCurrentItem(item);
0507                 return;
0508             }
0509         }
0510     }
0511 
0512     // If that selected nothing, then select the last-used format (regardless
0513     // of the "always use" option setting).  The last-used format is saved
0514     // in getFormat() for that purpose.  This helps when scanning a series of
0515     // similar images yet where the user doesn't want to permanently save the
0516     // format for some reason.
0517     //
0518     // This is safe if the last-used format is not applicable to and so is not
0519     // displayed for the current image type - it just does nothing.
0520     if (!sLastFormat.isEmpty()) {
0521         for (int i = 0; i < mFormatList->count(); ++i) {
0522             QListWidgetItem *item = mFormatList->item(i);
0523             if (item == nullptr) {
0524                 continue;
0525             }
0526             QString mimename = item->data(Qt::UserRole).toString();
0527             // We know the MIME name is canonical here, so can use string compare
0528             if (mimename == sLastFormat) {
0529                 mFormatList->setCurrentItem(item);
0530                 return;
0531             }
0532         }
0533     }
0534 }
0535 
0536 ImageFormat FormatDialog::getFormat() const
0537 {
0538     if (mFormatList == nullptr) return (mFormat);       // no UI for this
0539 
0540     QMimeDatabase db;
0541     const QListWidgetItem *item = mFormatList->currentItem();
0542     if (item != nullptr) {
0543         QString mimename = item->data(Qt::UserRole).toString();
0544         const QMimeType mime = db.mimeTypeForName(mimename);
0545         if (mime.isValid()) {
0546             sLastFormat = mime.name();
0547             return (ImageFormat::formatForMime(mime));
0548         }
0549     }
0550 
0551     return (ImageFormat("PNG"));            // a sensible default
0552 }
0553 
0554 QString FormatDialog::getFilename() const
0555 {
0556     if (mFilenameEdit == nullptr) return (mFilename);   // no UI for this
0557     return (mFilenameEdit->text());
0558 }
0559 
0560 QByteArray FormatDialog::getSubFormat() const
0561 {
0562     return ("");                    // Not supported yet...
0563 }
0564 
0565 void FormatDialog::checkValid()
0566 {
0567     bool ok = true;                 // so far, anyway
0568 
0569     if (mFormatList != nullptr && mFormatList->selectedItems().count() == 0) ok = false;
0570     if (mFilenameEdit != nullptr && mFilenameEdit->text().isEmpty()) ok = false;
0571     setButtonEnabled(QDialogButtonBox::Ok, ok);
0572 }
0573 
0574 
0575 static const FormatInfo *findKnownFormat(const QMimeType &mime)
0576 {
0577     for (const FormatInfo *fi = &formats[0]; fi->mime!=nullptr; ++fi)
0578     {                           // search for format info
0579         const QList<QByteArray> mimetypes = QByteArray(fi->mime).split(';');
0580         for (const QByteArray &mimetype : mimetypes)
0581         {
0582             if (mime.inherits(mimetype)) return (fi);   // matching that MIME type
0583         }
0584     }
0585 
0586     return (nullptr);                   // nothing found
0587 }
0588 
0589 
0590 void FormatDialog::buildFormatList(bool recOnly)
0591 {
0592     if (mFormatList == nullptr) return;         // not showing this
0593     qCDebug(KOOKA_LOG) << "recOnly" << recOnly << "for type" << mImageType;
0594 
0595     mFormatList->clear();
0596     const QList<QMimeType> *mimeTypes = ImageFormat::mimeTypes();
0597     for (const QMimeType &mime : qAsConst(*mimeTypes))  // for all known MIME types
0598     {
0599         const FormatInfo *fi = findKnownFormat(mime);   // look for format information
0600         if (fi==nullptr)                // nothing for that MIME type
0601         {
0602             if (recOnly) continue;          // never show for recommended
0603         }                       // but always show otherwise
0604         else
0605         {
0606             ScanImage::ImageTypes okTypes = fi->okForTypes;
0607             if (okTypes!=0)             // format has allowed types
0608             {
0609                 if (!(okTypes & mImageType)) continue;  // but not for this image type
0610             }
0611 
0612             if (recOnly)                // want only recommended types
0613             {
0614                 if (!(fi->recForTypes & mImageType))    // check for recommended format
0615                 {
0616                     continue;               // not for this image type
0617                 }
0618             }
0619         }
0620 
0621         // add format to list
0622         QListWidgetItem *item = new QListWidgetItem(QIcon::fromTheme(mime.iconName()),
0623                 mime.comment(), mFormatList);
0624         // Not sure whether a QMimeType can safely be stored in a
0625         // QVariant, so storing the MIME type name instead.
0626         item->setData(Qt::UserRole, mime.name());
0627         mFormatList->addItem(item);
0628     }
0629 
0630     formatSelected(nullptr);                // selection has been cleared
0631 }
0632 
0633 void FormatDialog::slotOk()
0634 {
0635     if (mRecOnlyCheck != nullptr) {         // have UI for this
0636         KookaSettings::setSaverOnlyRecommendedTypes(mRecOnlyCheck->isChecked());
0637         KookaSettings::self()->save();          // save state of this option
0638     }
0639 }
0640 
0641 void FormatDialog::slotUser1()
0642 {
0643     mWantAssistant = true;
0644     accept();
0645 }
0646 
0647 
0648 /* static */ void FormatDialog::forgetRemembered()
0649 {
0650     const KConfigSkeletonItem *ski = KookaSettings::self()->saverAlwaysUseFormatItem();
0651     Q_ASSERT(ski!=nullptr);
0652     KConfigGroup grp = KookaSettings::self()->config()->group(ski->group());
0653     grp.deleteGroup();
0654 
0655     KookaSettings::self()->save();          // ensure the config is saved
0656     KookaSettings::self()->read();          // and internal values are up to date
0657 }
0658 
0659 
0660 bool FormatDialog::alwaysUseFormat() const
0661 {
0662     return (mDontAskCheck != nullptr ? mDontAskCheck->isChecked() : false);
0663 }
0664 
0665 
0666 /* static */ bool FormatDialog::isCompatible(const QMimeType &mime, ScanImage::ImageType type, bool recOnly)
0667 {
0668     //qCDebug(KOOKA_LOG) << "mime" << mime << "type" << type << "recOnly" << recOnly;
0669     for (const FormatInfo *ip = &formats[0]; ip->mime!=nullptr; ++ip)
0670     {                           // scan the format descriptions
0671         if (mime.inherits(ip->mime))            // found format for the MIME type
0672         {
0673             const ScanImage::ImageTypes types = (recOnly ? ip->recForTypes : ip->okForTypes);
0674             if (!recOnly && types==ScanImage::None) return (true);
0675                             // allowed for all formats
0676             return (types & type);          // check image type mask
0677         }
0678     }
0679 
0680     return (false);
0681 }