File indexing completed on 2024-05-12 05:13:14

0001 /*
0002   SPDX-FileCopyrightText: 2000, 2001 Cornelius Schumacher <schumacher@kde.org>
0003   SPDX-FileCopyrightText: 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
0004 
0005   SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0
0006 */
0007 
0008 // ArchiveDialog -- archive/delete past events.
0009 
0010 #include "archivedialog.h"
0011 #include "eventarchiver.h"
0012 #include "kcalprefs.h"
0013 
0014 #include <Akonadi/IncidenceChanger>
0015 
0016 #include <KDateComboBox>
0017 #include <KLineEdit>
0018 #include <KLocalizedString>
0019 #include <KMessageBox>
0020 #include <KUrlRequester>
0021 #include <QComboBox>
0022 #include <QHBoxLayout>
0023 #include <QUrl>
0024 
0025 #include <QButtonGroup>
0026 #include <QCheckBox>
0027 #include <QDialogButtonBox>
0028 #include <QFrame>
0029 #include <QGroupBox>
0030 #include <QLabel>
0031 #include <QPushButton>
0032 #include <QRadioButton>
0033 #include <QSpinBox>
0034 #include <QVBoxLayout>
0035 #include <QWhatsThis>
0036 
0037 using namespace CalendarSupport;
0038 
0039 ArchiveDialog::ArchiveDialog(const Akonadi::ETMCalendar::Ptr &cal, Akonadi::IncidenceChanger *changer, QWidget *parent)
0040     : QDialog(parent)
0041     , mUser1Button(new QPushButton(this))
0042 {
0043     setWindowTitle(i18nc("@title:window", "Archive/Delete Past Events and To-dos"));
0044     auto mainLayout = new QVBoxLayout(this);
0045     auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel, this);
0046     buttonBox->addButton(mUser1Button, QDialogButtonBox::ActionRole);
0047     connect(buttonBox, &QDialogButtonBox::rejected, this, &ArchiveDialog::reject);
0048     mUser1Button->setDefault(true);
0049     setModal(false);
0050     mUser1Button->setText(i18nc("@action:button", "&Archive"));
0051     mCalendar = cal;
0052     mChanger = changer;
0053 
0054     auto topFrame = new QFrame(this);
0055     mainLayout->addWidget(topFrame);
0056     mainLayout->addWidget(buttonBox);
0057 
0058     auto topLayout = new QVBoxLayout(topFrame);
0059     topLayout->setContentsMargins(0, 0, 0, 0);
0060     auto descLabel = new QLabel(topFrame);
0061     descLabel->setText(xi18nc("@info:whatsthis",
0062                               "Archiving saves old items into the given file and "
0063                               "then deletes them in the current calendar. If the archive file "
0064                               "already exists they will be added. "
0065                               "(<link url=\"#\">How to restore</link>)"));
0066     descLabel->setWhatsThis(i18nc("@info:whatsthis",
0067                                   "In order to add an archive to your calendar, use the Merge Calendar "
0068                                   "function. You can view an archive by opening it like you would any "
0069                                   "other calendar. It is not saved in a special format, but as "
0070                                   "vCalendar."));
0071     descLabel->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard | Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard);
0072     descLabel->setWordWrap(true);
0073     descLabel->setContextMenuPolicy(Qt::NoContextMenu);
0074     topLayout->addWidget(descLabel);
0075     connect(descLabel, &QLabel::linkActivated, this, &ArchiveDialog::showWhatsThis);
0076 
0077     auto radioBG = new QButtonGroup(this);
0078     connect(radioBG, &QButtonGroup::buttonClicked, this, &ArchiveDialog::slotActionChanged);
0079 
0080     auto dateLayout = new QHBoxLayout();
0081     dateLayout->setContentsMargins(0, 0, 0, 0);
0082     mArchiveOnceRB = new QRadioButton(i18nc("@option:radio", "Archive now items older than:"), topFrame);
0083     mArchiveOnceRB->setToolTip(i18nc("@info:tooltip", "Enable one time archiving or purging of older items"));
0084     mArchiveOnceRB->setWhatsThis(i18nc("@info:whatsthis",
0085                                        "If you check this box, events and to-dos older than the specified age "
0086                                        "will be archived or purged. The items will be archived unless the "
0087                                        "\"Delete only\" option is enabled; else the items will be purged "
0088                                        "and not saved."));
0089 
0090     dateLayout->addWidget(mArchiveOnceRB);
0091     radioBG->addButton(mArchiveOnceRB);
0092     mDateEdit = new KDateComboBox(topFrame);
0093     mDateEdit->setToolTip(i18nc("@info:tooltip", "Set the one time archiving cut-off date"));
0094     mDateEdit->setWhatsThis(i18nc("@info:whatsthis",
0095                                   "The date before which items should be archived. All older events "
0096                                   "and to-dos will be saved and deleted, the newer (and events "
0097                                   "exactly on that date) will be kept."));
0098     dateLayout->addWidget(mDateEdit);
0099     topLayout->addLayout(dateLayout);
0100 
0101     // Checkbox, numinput and combo for auto-archiving (similar to kmail's
0102     // mExpireFolderCheckBox/mReadExpiryTimeNumInput in kmfolderdia.cpp)
0103     auto autoArchiveHBox = new QWidget(topFrame);
0104     auto autoArchiveHBoxHBoxLayout = new QHBoxLayout(autoArchiveHBox);
0105     autoArchiveHBoxHBoxLayout->setContentsMargins(0, 0, 0, 0);
0106     topLayout->addWidget(autoArchiveHBox);
0107     mAutoArchiveRB = new QRadioButton(i18nc("@option:radio", "Automaticall&y archive items older than:"), autoArchiveHBox);
0108     mAutoArchiveRB->setToolTip(i18nc("@info:tooltip", "Enable automatic archiving or purging of older items"));
0109     mAutoArchiveRB->setWhatsThis(i18nc("@info:whatsthis",
0110                                        "If this feature is enabled, the application will regularly check if "
0111                                        "events and to-dos have to be archived; this means you will not "
0112                                        "need to use this dialog box again, except to change the settings."));
0113     radioBG->addButton(mAutoArchiveRB);
0114     autoArchiveHBoxHBoxLayout->addWidget(mAutoArchiveRB);
0115 
0116     mExpiryTimeNumInput = new QSpinBox(autoArchiveHBox);
0117     autoArchiveHBoxHBoxLayout->addWidget(mExpiryTimeNumInput);
0118     mExpiryTimeNumInput->setRange(1, 500);
0119     mExpiryTimeNumInput->setSingleStep(1);
0120 
0121     mExpiryTimeNumInput->setEnabled(false);
0122     mExpiryTimeNumInput->setValue(7);
0123     mExpiryTimeNumInput->setToolTip(i18nc("@info:tooltip", "Set the archival age in days, weeks or months"));
0124     mExpiryTimeNumInput->setWhatsThis(i18nc("@info:whatsthis",
0125                                             "The age of the events and to-dos to archive. All older items "
0126                                             "will be saved and deleted, the newer will be kept."));
0127 
0128     mExpiryUnitsComboBox = new QComboBox(autoArchiveHBox);
0129     autoArchiveHBoxHBoxLayout->addWidget(mExpiryUnitsComboBox);
0130     mExpiryUnitsComboBox->setToolTip(i18nc("@info:tooltip", "Set the units for the automatic archive age"));
0131     mExpiryUnitsComboBox->setWhatsThis(i18nc("@info:whatsthis", "Select the time units (days, weeks or months) for automatic archiving."));
0132     // Those items must match the "Expiry Unit" enum in the kcfg file!
0133     mExpiryUnitsComboBox->addItem(i18nc("@item:inlistbox expires in daily units", "Day(s)"));
0134     mExpiryUnitsComboBox->addItem(i18nc("@item:inlistbox expiration in weekly units", "Week(s)"));
0135     mExpiryUnitsComboBox->addItem(i18nc("@item:inlistbox expiration in monthly units", "Month(s)"));
0136     mExpiryUnitsComboBox->setEnabled(false);
0137 
0138     auto fileLayout = new QHBoxLayout();
0139     fileLayout->setContentsMargins(0, 0, 0, 0);
0140     auto l = new QLabel(i18nc("@label", "Archive &file:"), topFrame);
0141     fileLayout->addWidget(l);
0142     mArchiveFile = new KUrlRequester(QUrl::fromLocalFile(KCalPrefs::instance()->mArchiveFile), topFrame);
0143     mArchiveFile->setMode(KFile::File);
0144     mArchiveFile->setNameFilter(i18nc("@label filter for KUrlRequester", "iCalendar Files (*.ics)"));
0145     mArchiveFile->setToolTip(i18nc("@info:tooltip", "Set the location of the archive"));
0146     mArchiveFile->setWhatsThis(i18nc("@info:whatsthis",
0147                                      "The path of the archive file. The events and to-dos will be appended "
0148                                      "to the specified file, so any events that are already in the file "
0149                                      "will not be modified or deleted. You can later load or merge the "
0150                                      "file like any other calendar. It is not saved in a special "
0151                                      "format, it uses the iCalendar format."));
0152     l->setBuddy(mArchiveFile->lineEdit());
0153     fileLayout->addWidget(mArchiveFile);
0154     topLayout->addLayout(fileLayout);
0155 
0156     auto typeBox = new QGroupBox(i18nc("@title:group", "Type of Items to Archive"));
0157     typeBox->setWhatsThis(i18nc("@info:whatsthis",
0158                                 "Here you can select which items "
0159                                 "should be archived. Events are archived if they "
0160                                 "ended before the date given above; to-dos are archived if "
0161                                 "they were finished before the date."));
0162 
0163     topLayout->addWidget(typeBox);
0164     QBoxLayout *typeLayout = new QVBoxLayout(typeBox);
0165 
0166     mEvents = new QCheckBox(i18nc("@option:check", "Archive &Events"));
0167     mEvents->setToolTip(i18nc("@option:check", "Archive or purge events"));
0168     mEvents->setWhatsThis(i18nc("@info:whatsthis", "Select this option to archive events if they ended before the date given above."));
0169     typeLayout->addWidget(mEvents);
0170 
0171     mTodos = new QCheckBox(i18nc("@option:check", "Archive Completed &To-dos"));
0172     mTodos->setToolTip(i18nc("@option:check", "Archive or purge completed to-dos"));
0173     mTodos->setWhatsThis(i18nc("@info:whatsthis",
0174                                "Select this option to archive to-dos if they were completed "
0175                                "before the date given above."));
0176     typeLayout->addWidget(mTodos);
0177 
0178     mDeleteCb = new QCheckBox(i18nc("@option:check", "&Delete only, do not save"), topFrame);
0179     mDeleteCb->setToolTip(i18nc("@info:tooltip", "Purge the old items without saving them"));
0180     mDeleteCb->setWhatsThis(i18nc("@info:whatsthis",
0181                                   "Select this option to delete old events and to-dos without saving "
0182                                   "them. It is not possible to recover the events later."));
0183     topLayout->addWidget(mDeleteCb);
0184     connect(mDeleteCb, &QCheckBox::toggled, mArchiveFile, &KUrlRequester::setDisabled);
0185     connect(mDeleteCb, &QCheckBox::toggled, this, &ArchiveDialog::slotEnableUser1);
0186     connect(mArchiveFile->lineEdit(), &QLineEdit::textChanged, this, &ArchiveDialog::slotEnableUser1);
0187 
0188     // Load settings from KCalPrefs
0189     mExpiryTimeNumInput->setValue(KCalPrefs::instance()->mExpiryTime);
0190     mExpiryUnitsComboBox->setCurrentIndex(KCalPrefs::instance()->mExpiryUnit);
0191     mDeleteCb->setChecked(KCalPrefs::instance()->mArchiveAction == KCalPrefs::actionDelete);
0192     mEvents->setChecked(KCalPrefs::instance()->mArchiveEvents);
0193     mTodos->setChecked(KCalPrefs::instance()->mArchiveTodos);
0194 
0195     slotEnableUser1();
0196 
0197     // The focus should go to a useful field by default, not to the top richtext-label
0198     if (KCalPrefs::instance()->mAutoArchive) {
0199         mAutoArchiveRB->setChecked(true);
0200         mAutoArchiveRB->setFocus();
0201     } else {
0202         mArchiveOnceRB->setChecked(true);
0203         mArchiveOnceRB->setFocus();
0204     }
0205     slotActionChanged();
0206     connect(mUser1Button, &QPushButton::clicked, this, &ArchiveDialog::slotUser1);
0207 }
0208 
0209 ArchiveDialog::~ArchiveDialog() = default;
0210 
0211 void ArchiveDialog::slotEnableUser1()
0212 {
0213     const bool state = (mDeleteCb->isChecked() || !mArchiveFile->lineEdit()->text().trimmed().isEmpty());
0214     mUser1Button->setEnabled(state);
0215 }
0216 
0217 void ArchiveDialog::slotActionChanged()
0218 {
0219     mDateEdit->setEnabled(mArchiveOnceRB->isChecked());
0220     mExpiryTimeNumInput->setEnabled(mAutoArchiveRB->isChecked());
0221     mExpiryUnitsComboBox->setEnabled(mAutoArchiveRB->isChecked());
0222 }
0223 
0224 // Archive old events
0225 void ArchiveDialog::slotUser1()
0226 {
0227     EventArchiver archiver;
0228     connect(&archiver, &EventArchiver::eventsDeleted, this, &ArchiveDialog::slotEventsDeleted);
0229 
0230     KCalPrefs::instance()->mAutoArchive = mAutoArchiveRB->isChecked();
0231     KCalPrefs::instance()->mExpiryTime = mExpiryTimeNumInput->value();
0232     KCalPrefs::instance()->mExpiryUnit = mExpiryUnitsComboBox->currentIndex();
0233 
0234     if (mDeleteCb->isChecked()) {
0235         KCalPrefs::instance()->mArchiveAction = KCalPrefs::actionDelete;
0236     } else {
0237         KCalPrefs::instance()->mArchiveAction = KCalPrefs::actionArchive;
0238 
0239         // Get destination URL
0240         QUrl destUrl(mArchiveFile->url());
0241         if (!destUrl.isValid()) {
0242             KMessageBox::error(this, i18nc("@info", "The archive file name is not valid."));
0243             return;
0244         }
0245         // Force filename to be ending with vCalendar extension
0246         QString filename = destUrl.fileName();
0247         if (!filename.endsWith(QLatin1StringView(".vcs")) && !filename.endsWith(QLatin1StringView(".ics"))) {
0248             filename.append(QLatin1StringView(".ics"));
0249             destUrl = destUrl.adjusted(QUrl::RemoveFilename);
0250             destUrl.setPath(destUrl.path() + filename);
0251         }
0252 
0253         KCalPrefs::instance()->mArchiveFile = destUrl.url();
0254     }
0255     if (KCalPrefs::instance()->mAutoArchive) {
0256         archiver.runAuto(mCalendar, mChanger, this, true /*with gui*/);
0257         Q_EMIT autoArchivingSettingsModified();
0258         accept();
0259     } else {
0260         archiver.runOnce(mCalendar, mChanger, mDateEdit->date(), this);
0261         accept();
0262     }
0263 }
0264 
0265 void ArchiveDialog::slotEventsDeleted()
0266 {
0267     Q_EMIT eventsDeleted();
0268     if (!KCalPrefs::instance()->mAutoArchive) {
0269         accept();
0270     }
0271 }
0272 
0273 void ArchiveDialog::showWhatsThis()
0274 {
0275     QWidget *widget = qobject_cast<QWidget *>(sender());
0276     if (widget && !widget->whatsThis().isEmpty()) {
0277         QWhatsThis::showText(QCursor::pos(), widget->whatsThis());
0278     }
0279 }
0280 
0281 #include "moc_archivedialog.cpp"