File indexing completed on 2024-05-05 05:50:40

0001 /*
0002     SPDX-FileCopyrightText: 2016 Ragnar Thomsen <rthomsen6@gmail.com>
0003 
0004     SPDX-License-Identifier: BSD-2-Clause
0005 */
0006 
0007 #include "compressionoptionswidget.h"
0008 #include "ark_debug.h"
0009 #include "pluginmanager.h"
0010 #include "settings.h"
0011 
0012 #include <KColorScheme>
0013 #include <KPluginMetaData>
0014 
0015 #include <QMimeDatabase>
0016 
0017 namespace Kerfuffle
0018 {
0019 CompressionOptionsWidget::CompressionOptionsWidget(QWidget *parent, const CompressionOptions &opts)
0020     : QWidget(parent)
0021     , m_opts(opts)
0022 {
0023     setupUi(this);
0024 
0025     KColorScheme colorScheme(QPalette::Active, KColorScheme::View);
0026     pwdWidget->setBackgroundWarningColor(colorScheme.background(KColorScheme::NegativeBackground).color());
0027     pwdWidget->setPasswordStrengthMeterVisible(false);
0028 
0029     connect(multiVolumeCheckbox, &QCheckBox::stateChanged, this, &CompressionOptionsWidget::slotMultiVolumeChecked);
0030     connect(compMethodComboBox, &QComboBox::currentTextChanged, this, &CompressionOptionsWidget::slotCompMethodChanged);
0031     connect(encMethodComboBox, &QComboBox::currentTextChanged, this, &CompressionOptionsWidget::slotEncryptionMethodChanged);
0032 
0033     if (m_opts.isVolumeSizeSet()) {
0034         multiVolumeCheckbox->setChecked(true);
0035         // Convert from kilobytes.
0036         volumeSizeSpinbox->setValue(static_cast<double>(m_opts.volumeSize()) / 1024);
0037     }
0038 
0039     warningMsgWidget->setWordWrap(true);
0040 }
0041 
0042 CompressionOptions CompressionOptionsWidget::commpressionOptions() const
0043 {
0044     CompressionOptions opts;
0045     opts.setCompressionLevel(compLevelSlider->value());
0046     if (multiVolumeCheckbox->isChecked()) {
0047         opts.setVolumeSize(volumeSize());
0048     }
0049     if (!compMethodComboBox->currentText().isEmpty()) {
0050         opts.setCompressionMethod(compMethodComboBox->currentText());
0051     }
0052 
0053     return opts;
0054 }
0055 
0056 int CompressionOptionsWidget::compressionLevel() const
0057 {
0058     if (compLevelSlider->isEnabled()) {
0059         return compLevelSlider->value();
0060     } else {
0061         return -1;
0062     }
0063 }
0064 
0065 QString CompressionOptionsWidget::compressionMethod() const
0066 {
0067     return compMethodComboBox->currentText();
0068 }
0069 
0070 ulong CompressionOptionsWidget::volumeSize() const
0071 {
0072     if (collapsibleMultiVolume->isEnabled() && multiVolumeCheckbox->isChecked()) {
0073         // Convert to kilobytes.
0074         return static_cast<ulong>(volumeSizeSpinbox->value() * 1024);
0075     } else {
0076         return 0;
0077     }
0078 }
0079 
0080 void CompressionOptionsWidget::setEncryptionVisible(bool visible)
0081 {
0082     collapsibleEncryption->setVisible(visible);
0083 }
0084 
0085 QString CompressionOptionsWidget::password() const
0086 {
0087     return pwdWidget->password();
0088 }
0089 
0090 ArchiveFormat CompressionOptionsWidget::archiveFormat() const
0091 {
0092     const KPluginMetaData metadata = PluginManager().preferredPluginFor(m_mimetype)->metaData();
0093     return ArchiveFormat::fromMetadata(m_mimetype, metadata);
0094 }
0095 
0096 void CompressionOptionsWidget::updateWidgets()
0097 {
0098     const ArchiveFormat archiveFormat = this->archiveFormat();
0099     Q_ASSERT(archiveFormat.isValid());
0100 
0101     if (archiveFormat.encryptionType() != Archive::Unencrypted) {
0102         collapsibleEncryption->setEnabled(true);
0103         collapsibleEncryption->setToolTip(QString());
0104 
0105         encMethodComboBox->clear();
0106         encMethodComboBox->insertItems(0, archiveFormat.encryptionMethods());
0107 
0108         if (!m_opts.encryptionMethod().isEmpty() && encMethodComboBox->findText(m_opts.encryptionMethod()) > -1) {
0109             encMethodComboBox->setCurrentText(m_opts.encryptionMethod());
0110         } else {
0111             encMethodComboBox->setCurrentText(archiveFormat.defaultEncryptionMethod());
0112         }
0113 
0114         if (!archiveFormat.encryptionMethods().isEmpty()) {
0115             lblEncMethod->setEnabled(true);
0116             encMethodComboBox->setEnabled(true);
0117         }
0118 
0119         pwdWidget->setEnabled(true);
0120 
0121         if (archiveFormat.encryptionType() == Archive::HeaderEncrypted) {
0122             encryptHeaderCheckBox->setEnabled(true);
0123             encryptHeaderCheckBox->setToolTip(QString());
0124         } else {
0125             encryptHeaderCheckBox->setEnabled(false);
0126             // Show the tooltip only if the encryption is still enabled.
0127             // This is needed because if the new filter is e.g. tar, the whole encryption group gets disabled.
0128             if (collapsibleEncryption->isEnabled() && collapsibleEncryption->isExpanded()) {
0129                 encryptHeaderCheckBox->setToolTip(i18n("Protection of the list of files is not possible with the %1 format.", m_mimetype.comment()));
0130             } else {
0131                 encryptHeaderCheckBox->setToolTip(QString());
0132             }
0133         }
0134 
0135     } else {
0136         collapsibleEncryption->setEnabled(false);
0137         collapsibleEncryption->setToolTip(i18n("Protection of the archive with password is not possible with the %1 format.", m_mimetype.comment()));
0138         lblEncMethod->setEnabled(false);
0139         encMethodComboBox->setEnabled(false);
0140         encMethodComboBox->clear();
0141         pwdWidget->setEnabled(false);
0142         encryptHeaderCheckBox->setToolTip(QString());
0143     }
0144 
0145     collapsibleCompression->setEnabled(true);
0146     if (archiveFormat.maxCompressionLevel() == 0) {
0147         compLevelSlider->setEnabled(false);
0148         lblCompLevel1->setEnabled(false);
0149         lblCompLevel2->setEnabled(false);
0150         lblCompLevel3->setEnabled(false);
0151         compLevelSlider->setToolTip(i18n("It is not possible to set compression level for the %1 format.", m_mimetype.comment()));
0152     } else {
0153         compLevelSlider->setEnabled(true);
0154         lblCompLevel1->setEnabled(true);
0155         lblCompLevel2->setEnabled(true);
0156         lblCompLevel3->setEnabled(true);
0157         compLevelSlider->setToolTip(QString());
0158         compLevelSlider->setMinimum(archiveFormat.minCompressionLevel());
0159         compLevelSlider->setMaximum(archiveFormat.maxCompressionLevel());
0160         if (m_opts.isCompressionLevelSet()) {
0161             compLevelSlider->setValue(m_opts.compressionLevel());
0162         } else {
0163             compLevelSlider->setValue(archiveFormat.defaultCompressionLevel());
0164         }
0165     }
0166 
0167     if (archiveFormat.compressionMethods().isEmpty()) {
0168         lblCompMethod->setEnabled(false);
0169         compMethodComboBox->setEnabled(false);
0170         compMethodComboBox->setToolTip(i18n("It is not possible to set compression method for the %1 format.", m_mimetype.comment()));
0171         compMethodComboBox->clear();
0172     } else {
0173         lblCompMethod->setEnabled(true);
0174         compMethodComboBox->setEnabled(true);
0175         compMethodComboBox->setToolTip(QString());
0176         compMethodComboBox->clear();
0177         compMethodComboBox->insertItems(0, archiveFormat.compressionMethods().keys());
0178         if (!m_opts.compressionMethod().isEmpty() && compMethodComboBox->findText(m_opts.compressionMethod()) > -1) {
0179             compMethodComboBox->setCurrentText(m_opts.compressionMethod());
0180         } else {
0181             compMethodComboBox->setCurrentText(archiveFormat.defaultCompressionMethod());
0182         }
0183     }
0184     collapsibleCompression->setEnabled(compLevelSlider->isEnabled() || compMethodComboBox->isEnabled());
0185 
0186     if (archiveFormat.supportsMultiVolume()) {
0187         collapsibleMultiVolume->setEnabled(true);
0188         collapsibleMultiVolume->setToolTip(QString());
0189     } else {
0190         collapsibleMultiVolume->setEnabled(false);
0191         collapsibleMultiVolume->setToolTip(i18n("The %1 format does not support multi-volume archives.", m_mimetype.comment()));
0192     }
0193 }
0194 
0195 void CompressionOptionsWidget::setMimeType(const QMimeType &mimeType)
0196 {
0197     m_mimetype = mimeType;
0198     updateWidgets();
0199 }
0200 
0201 bool CompressionOptionsWidget::isEncryptionAvailable() const
0202 {
0203     return collapsibleEncryption->isEnabled();
0204 }
0205 
0206 bool CompressionOptionsWidget::isEncryptionEnabled() const
0207 {
0208     return isEncryptionAvailable() && collapsibleEncryption->isExpanded();
0209 }
0210 
0211 bool CompressionOptionsWidget::isHeaderEncryptionAvailable() const
0212 {
0213     return isEncryptionEnabled() && encryptHeaderCheckBox->isEnabled();
0214 }
0215 
0216 bool CompressionOptionsWidget::isHeaderEncryptionEnabled() const
0217 {
0218     return isHeaderEncryptionAvailable() && encryptHeaderCheckBox->isChecked();
0219 }
0220 
0221 KNewPasswordWidget::PasswordStatus CompressionOptionsWidget::passwordStatus() const
0222 {
0223     return pwdWidget->passwordStatus();
0224 }
0225 
0226 QString CompressionOptionsWidget::encryptionMethod() const
0227 {
0228     if (encMethodComboBox->isEnabled() && encMethodComboBox->count() > 1 && !password().isEmpty()) {
0229         return encMethodComboBox->currentText();
0230     }
0231     return QString();
0232 }
0233 
0234 void CompressionOptionsWidget::slotMultiVolumeChecked(int state)
0235 {
0236     if (state == Qt::Checked) {
0237         lblVolumeSize->setEnabled(true);
0238         volumeSizeSpinbox->setEnabled(true);
0239     } else {
0240         lblVolumeSize->setEnabled(false);
0241         volumeSizeSpinbox->setEnabled(false);
0242     }
0243 }
0244 
0245 void CompressionOptionsWidget::slotCompMethodChanged(const QString &value)
0246 {
0247     // This hack is needed for the RAR format because the available encryption
0248     // method is dependent on the selected compression method. Rar uses AES128
0249     // for RAR4 format and AES256 for RAR5 format.
0250 
0251     if (m_mimetype == QMimeDatabase().mimeTypeForName(QStringLiteral("application/vnd.rar"))
0252         || m_mimetype == QMimeDatabase().mimeTypeForName(QStringLiteral("application/x-rar"))) {
0253         encMethodComboBox->clear();
0254         if (value == QLatin1String("RAR4")) {
0255             encMethodComboBox->insertItem(0, QStringLiteral("AES128"));
0256         } else {
0257             encMethodComboBox->insertItem(0, QStringLiteral("AES256"));
0258         }
0259     }
0260 
0261     const ArchiveFormat archiveFormat = this->archiveFormat();
0262     Q_ASSERT(archiveFormat.isValid());
0263 
0264     if (m_mimetype == QMimeDatabase().mimeTypeForName(QStringLiteral("application/zip"))) {
0265         if (value == QLatin1String("Zstd")) {
0266             compLevelSlider->setMaximum(22);
0267         } else {
0268             compLevelSlider->setMaximum(archiveFormat.maxCompressionLevel());
0269         }
0270     }
0271 }
0272 
0273 void CompressionOptionsWidget::slotEncryptionMethodChanged(const QString &value)
0274 {
0275     if (value.isEmpty() || m_mimetype != QMimeDatabase().mimeTypeForName(QStringLiteral("application/zip"))) {
0276         warningMsgWidget->hide();
0277         return;
0278     }
0279 
0280     // AES encryption is not supported by unzip, warn the users if they are creating a zip.
0281     warningMsgWidget->setVisible(value != QLatin1String("ZipCrypto") && ArkSettings::showEncryptionWarning());
0282 }
0283 
0284 }
0285 
0286 #include "moc_compressionoptionswidget.cpp"