File indexing completed on 2024-05-05 16:13:52

0001 /*
0002     SPDX-FileCopyrightText: 2008 Tobias Koenig <tokoe@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "kcmtrash.h"
0008 #include "discspaceutil.h"
0009 #include "trashimpl.h"
0010 
0011 #include <QCheckBox>
0012 #include <QComboBox>
0013 #include <QDoubleSpinBox>
0014 #include <QFormLayout>
0015 #include <QLabel>
0016 #include <QListWidget>
0017 #include <QListWidgetItem>
0018 
0019 #include <KConfig>
0020 #include <KConfigGroup>
0021 #include <KFormat>
0022 #include <KLocalizedString>
0023 #include <KPluginFactory>
0024 #include <QDialog>
0025 #include <QIcon>
0026 #include <QSpinBox>
0027 
0028 K_PLUGIN_CLASS_WITH_JSON(TrashConfigModule, "kcmtrash.json")
0029 
0030 TrashConfigModule::TrashConfigModule(QWidget *parent, const QVariantList &args)
0031     : KCModule(parent, args)
0032     , trashInitialize(false)
0033 {
0034     mTrashImpl = new TrashImpl();
0035     mTrashImpl->init();
0036 
0037     readConfig();
0038 
0039     setupGui();
0040 
0041     useTypeChanged();
0042 
0043     connect(mUseTimeLimit, &QAbstractButton::toggled, this, &TrashConfigModule::markAsChanged);
0044     connect(mUseTimeLimit, &QAbstractButton::toggled, this, &TrashConfigModule::useTypeChanged);
0045     connect(mDays, qOverload<int>(&QSpinBox::valueChanged), this, &TrashConfigModule::markAsChanged);
0046     connect(mUseSizeLimit, &QAbstractButton::toggled, this, &TrashConfigModule::markAsChanged);
0047     connect(mUseSizeLimit, &QAbstractButton::toggled, this, &TrashConfigModule::useTypeChanged);
0048     connect(mPercent, qOverload<double>(&QDoubleSpinBox::valueChanged), this, &TrashConfigModule::percentChanged);
0049     connect(mPercent, qOverload<double>(&QDoubleSpinBox::valueChanged), this, &TrashConfigModule::markAsChanged);
0050     connect(mLimitReachedAction, qOverload<int>(&QComboBox::currentIndexChanged), this, &TrashConfigModule::markAsChanged);
0051 
0052     trashChanged(0);
0053     trashInitialize = true;
0054 }
0055 
0056 TrashConfigModule::~TrashConfigModule()
0057 {
0058 }
0059 
0060 void TrashConfigModule::save()
0061 {
0062     if (!mCurrentTrash.isEmpty()) {
0063         ConfigEntry entry;
0064         entry.useTimeLimit = mUseTimeLimit->isChecked();
0065         entry.days = mDays->value();
0066         entry.useSizeLimit = mUseSizeLimit->isChecked();
0067         entry.percent = mPercent->value(), entry.actionType = mLimitReachedAction->currentIndex();
0068         mConfigMap.insert(mCurrentTrash, entry);
0069     }
0070 
0071     writeConfig();
0072 }
0073 
0074 void TrashConfigModule::defaults()
0075 {
0076     ConfigEntry entry;
0077     entry.useTimeLimit = false;
0078     entry.days = 7;
0079     entry.useSizeLimit = true;
0080     entry.percent = 10.0;
0081     entry.actionType = 0;
0082     mConfigMap.insert(mCurrentTrash, entry);
0083     trashInitialize = false;
0084     trashChanged(0);
0085 }
0086 
0087 void TrashConfigModule::percentChanged(double percent)
0088 {
0089     DiscSpaceUtil util(mCurrentTrash);
0090 
0091     qint64 partitionSize = util.size();
0092     double size = static_cast<double>(partitionSize / 100) * percent;
0093 
0094     KFormat format;
0095     mSizeLabel->setText(QLatin1Char('(') + format.formatByteSize(size, 2) + QLatin1Char(')'));
0096 }
0097 
0098 void TrashConfigModule::trashChanged(QListWidgetItem *item)
0099 {
0100     trashChanged(item->data(Qt::UserRole).toInt());
0101 }
0102 
0103 void TrashConfigModule::trashChanged(int value)
0104 {
0105     const TrashImpl::TrashDirMap map = mTrashImpl->trashDirectories();
0106 
0107     if (!mCurrentTrash.isEmpty() && trashInitialize) {
0108         ConfigEntry entry;
0109         entry.useTimeLimit = mUseTimeLimit->isChecked();
0110         entry.days = mDays->value();
0111         entry.useSizeLimit = mUseSizeLimit->isChecked();
0112         entry.percent = mPercent->value(), entry.actionType = mLimitReachedAction->currentIndex();
0113         mConfigMap.insert(mCurrentTrash, entry);
0114     }
0115 
0116     mCurrentTrash = map[value];
0117     const auto currentTrashIt = mConfigMap.constFind(mCurrentTrash);
0118     if (currentTrashIt != mConfigMap.constEnd()) {
0119         const ConfigEntry &entry = *currentTrashIt;
0120         mUseTimeLimit->setChecked(entry.useTimeLimit);
0121         mDays->setValue(entry.days);
0122         mUseSizeLimit->setChecked(entry.useSizeLimit);
0123         mPercent->setValue(entry.percent);
0124         mLimitReachedAction->setCurrentIndex(entry.actionType);
0125     } else {
0126         mUseTimeLimit->setChecked(false);
0127         mDays->setValue(7);
0128         mUseSizeLimit->setChecked(true);
0129         mPercent->setValue(10.0);
0130         mLimitReachedAction->setCurrentIndex(0);
0131     }
0132     mDays->setSuffix(i18n(" days")); // missing in Qt: plural form handling
0133 
0134     percentChanged(mPercent->value());
0135 }
0136 
0137 void TrashConfigModule::useTypeChanged()
0138 {
0139     mDays->setEnabled(mUseTimeLimit->isChecked());
0140     mPercent->setEnabled(mUseSizeLimit->isChecked());
0141     mSizeLabel->setEnabled(mUseSizeLimit->isChecked());
0142 }
0143 
0144 void TrashConfigModule::readConfig()
0145 {
0146     KConfig config(QStringLiteral("ktrashrc"));
0147     mConfigMap.clear();
0148 
0149     const QStringList groups = config.groupList();
0150     for (const auto &name : groups) {
0151         if (name.startsWith(QLatin1Char('/'))) {
0152             const KConfigGroup group = config.group(name);
0153 
0154             ConfigEntry entry;
0155             entry.useTimeLimit = group.readEntry("UseTimeLimit", false);
0156             entry.days = group.readEntry("Days", 7);
0157             entry.useSizeLimit = group.readEntry("UseSizeLimit", true);
0158             entry.percent = group.readEntry("Percent", 10.0);
0159             entry.actionType = group.readEntry("LimitReachedAction", 0);
0160             mConfigMap.insert(name, entry);
0161         }
0162     }
0163 }
0164 
0165 void TrashConfigModule::writeConfig()
0166 {
0167     KConfig config(QStringLiteral("ktrashrc"));
0168 
0169     // first delete all existing groups
0170     const QStringList groups = config.groupList();
0171     for (const auto &name : groups) {
0172         if (name.startsWith(QLatin1Char('/'))) {
0173             config.deleteGroup(name);
0174         }
0175     }
0176 
0177     QMapIterator<QString, ConfigEntry> it(mConfigMap);
0178     while (it.hasNext()) {
0179         it.next();
0180         KConfigGroup group = config.group(it.key());
0181 
0182         const ConfigEntry entry = it.value();
0183         group.writeEntry("UseTimeLimit", entry.useTimeLimit);
0184         group.writeEntry("Days", entry.days);
0185         group.writeEntry("UseSizeLimit", entry.useSizeLimit);
0186         group.writeEntry("Percent", entry.percent);
0187         group.writeEntry("LimitReachedAction", entry.actionType);
0188     }
0189     config.sync();
0190 }
0191 
0192 void TrashConfigModule::setupGui()
0193 {
0194     QVBoxLayout *layout = new QVBoxLayout(this);
0195 
0196 #ifdef Q_OS_OSX
0197     QLabel *infoText = new QLabel(i18n("<para>KDE's wastebin is configured to use the <b>Finder</b>'s Trash.<br></para>"));
0198     infoText->setWhatsThis(i18nc("@info:whatsthis",
0199                                  "<para>Emptying KDE's wastebin will remove only KDE's trash items, while<br>"
0200                                  "emptying the Trash through the Finder will delete everything.</para>"
0201                                  "<para>KDE's trash items will show up in a folder called KDE.trash, in the Trash can.</para>"));
0202     layout->addWidget(infoText);
0203 #endif
0204 
0205     TrashImpl::TrashDirMap map = mTrashImpl->trashDirectories();
0206     if (map.count() != 1) {
0207         // If we have multiple trashes, we setup a widget to choose
0208         // which trash to configure
0209         QListWidget *mountPoints = new QListWidget(this);
0210         layout->addWidget(mountPoints);
0211 
0212         QMapIterator<int, QString> it(map);
0213         while (it.hasNext()) {
0214             it.next();
0215             DiscSpaceUtil util(it.value());
0216             QListWidgetItem *item = new QListWidgetItem(QIcon(QStringLiteral("folder")), util.mountPoint());
0217             item->setData(Qt::UserRole, it.key());
0218 
0219             mountPoints->addItem(item);
0220         }
0221 
0222         mountPoints->setCurrentRow(0);
0223 
0224         connect(mountPoints, &QListWidget::currentItemChanged, this, qOverload<QListWidgetItem *>(&TrashConfigModule::trashChanged));
0225     } else {
0226         mCurrentTrash = map.value(0);
0227     }
0228 
0229     QFormLayout *formLayout = new QFormLayout();
0230     layout->addLayout(formLayout);
0231 
0232     QHBoxLayout *daysLayout = new QHBoxLayout();
0233 
0234     mUseTimeLimit = new QCheckBox(i18n("Delete files older than"), this);
0235     mUseTimeLimit->setWhatsThis(
0236         xi18nc("@info:whatsthis",
0237                "<para>Check this box to allow <emphasis strong='true'>automatic deletion</emphasis> of files that are older than the value specified. "
0238                "Leave this disabled to <emphasis strong='true'>not</emphasis> automatically delete any items after a certain timespan</para>"));
0239     daysLayout->addWidget(mUseTimeLimit);
0240     mDays = new QSpinBox(this);
0241 
0242     mDays->setRange(1, 365);
0243     mDays->setSingleStep(1);
0244     mDays->setSuffix(i18np(" day", " days", mDays->value()));
0245     mDays->setWhatsThis(xi18nc("@info:whatsthis",
0246                                "<para>Set the number of days that files can remain in the trash. "
0247                                "Any files older than this will be automatically deleted.</para>"));
0248     daysLayout->addWidget(mDays);
0249     daysLayout->addStretch();
0250     formLayout->addRow(i18n("Cleanup:"), daysLayout);
0251 
0252     QHBoxLayout *maximumSizeLayout = new QHBoxLayout();
0253     mUseSizeLimit = new QCheckBox(i18n("Limit to"), this);
0254     mUseSizeLimit->setWhatsThis(xi18nc("@info:whatsthis",
0255                                        "<para>Check this box to limit the trash to the maximum amount of disk space that you specify below. "
0256                                        "Otherwise, it will be unlimited.</para>"));
0257     maximumSizeLayout->addWidget(mUseSizeLimit);
0258     formLayout->addRow(i18n("Size:"), maximumSizeLayout);
0259 
0260     mPercent = new QDoubleSpinBox(this);
0261     mPercent->setRange(0.01, 100);
0262     mPercent->setDecimals(2);
0263     mPercent->setSingleStep(1);
0264     mPercent->setSuffix(QStringLiteral(" %"));
0265     mPercent->setWhatsThis(xi18nc("@info:whatsthis", "<para>This is the maximum percent of disk space that will be used for the trash.</para>"));
0266     maximumSizeLayout->addWidget(mPercent);
0267 
0268     mSizeLabel = new QLabel(this);
0269     mSizeLabel->setWhatsThis(
0270         xi18nc("@info:whatsthis", "<para>This is the calculated amount of disk space that will be allowed for the trash, the maximum.</para>"));
0271     maximumSizeLayout->addWidget(mSizeLabel);
0272 
0273     mLimitReachedAction = new QComboBox();
0274     mLimitReachedAction->addItem(i18n("Show a Warning"));
0275     mLimitReachedAction->addItem(i18n("Delete Oldest Files From Trash"));
0276     mLimitReachedAction->addItem(i18n("Delete Biggest Files From Trash"));
0277     mLimitReachedAction->setWhatsThis(xi18nc("@info:whatsthis",
0278                                              "<para>When the size limit is reached, it will prefer to delete the type of files that you specify, first. "
0279                                              "If this is set to warn you, it will do so instead of automatically deleting files.</para>"));
0280     formLayout->addRow(i18n("Full Trash:"), mLimitReachedAction);
0281 
0282     layout->addStretch();
0283 }
0284 
0285 #include "kcmtrash.moc"
0286 #include "moc_kcmtrash.cpp"