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