File indexing completed on 2025-01-19 04:46:56
0001 /* 0002 SPDX-FileCopyrightText: 2014-2024 Laurent Montel <montel@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "eventedit.h" 0008 #include "createeventplugin_debug.h" 0009 #include "eventdatetimewidget.h" 0010 #include <CalendarSupport/KCalPrefs> 0011 #include <CalendarSupport/Utils> 0012 #include <messageviewer/globalsettings_messageviewer.h> 0013 0014 #include <KLocalizedString> 0015 #include <QDateTime> 0016 #include <QIcon> 0017 #include <QLineEdit> 0018 0019 #include <QEvent> 0020 #include <QHBoxLayout> 0021 #include <QKeyEvent> 0022 #include <QLabel> 0023 0024 #include <Akonadi/CollectionComboBox> 0025 #include <QPushButton> 0026 0027 #include <IncidenceEditor/IncidenceDialog> 0028 #include <IncidenceEditor/IncidenceDialogFactory> 0029 #include <KGuiItem> 0030 #include <KStandardGuiItem> 0031 0032 namespace MessageViewer 0033 { 0034 QAbstractItemModel *_k_eventEditStubModel = nullptr; 0035 } 0036 0037 using namespace MessageViewer; 0038 0039 EventEdit::EventEdit(QWidget *parent) 0040 : QWidget(parent) 0041 , mEventEdit(new QLineEdit(this)) 0042 , mStartDateTimeEdit(new EventDateTimeWidget(this)) 0043 , mEndDateTimeEdit(new EventDateTimeWidget(this)) 0044 , mSaveButton(new QPushButton(QIcon::fromTheme(QStringLiteral("appointment-new")), i18n("&Save"), this)) 0045 , mOpenEditorButton(new QPushButton(i18n("Open &Editor..."), this)) 0046 { 0047 auto vbox = new QVBoxLayout(this); 0048 vbox->setContentsMargins(5, 5, 5, 5); 0049 vbox->setSpacing(2); 0050 0051 auto hbox = new QHBoxLayout; 0052 hbox->setContentsMargins({}); 0053 hbox->setSpacing(2); 0054 vbox->addLayout(hbox); 0055 0056 auto lab = new QLabel(i18n("Event:"), this); 0057 hbox->addWidget(lab); 0058 0059 mEventEdit->setClearButtonEnabled(true); 0060 mEventEdit->setObjectName(QLatin1StringView("eventedit")); 0061 mEventEdit->setFocus(); 0062 connect(mEventEdit, &QLineEdit::returnPressed, this, &EventEdit::slotReturnPressed); 0063 connect(mEventEdit, &QLineEdit::textChanged, this, &EventEdit::slotUpdateButtons); 0064 hbox->addWidget(mEventEdit); 0065 0066 hbox->addSpacing(5); 0067 0068 mCollectionCombobox = new Akonadi::CollectionComboBox(_k_eventEditStubModel, this); 0069 mCollectionCombobox->setAccessRightsFilter(Akonadi::Collection::CanCreateItem); 0070 mCollectionCombobox->setMinimumWidth(250); 0071 mCollectionCombobox->setMimeTypeFilter(QStringList() << KCalendarCore::Event::eventMimeType()); 0072 mCollectionCombobox->setObjectName(QLatin1StringView("akonadicombobox")); 0073 #ifndef QT_NO_ACCESSIBILITY 0074 mCollectionCombobox->setAccessibleDescription(i18n("Calendar where the new event will be stored.")); 0075 #endif 0076 mCollectionCombobox->setToolTip(i18n("Calendar where the new event will be stored")); 0077 0078 connect(mCollectionCombobox, &Akonadi::CollectionComboBox::currentIndexChanged, this, &EventEdit::slotCollectionChanged); 0079 connect(mCollectionCombobox, &Akonadi::CollectionComboBox::activated, this, &EventEdit::slotCollectionChanged); 0080 0081 connect(mCollectionCombobox->model(), &QAbstractItemModel::rowsInserted, this, &EventEdit::comboboxRowInserted); 0082 hbox->addWidget(mCollectionCombobox); 0083 0084 hbox = new QHBoxLayout; 0085 hbox->setContentsMargins({}); 0086 hbox->setSpacing(2); 0087 vbox->addLayout(hbox); 0088 0089 lab = new QLabel(i18n("Start:"), this); 0090 hbox->addWidget(lab); 0091 QDateTime currentDateTime = QDateTime::currentDateTime(); 0092 mStartDateTimeEdit->setObjectName(QLatin1StringView("startdatetimeedit")); 0093 mStartDateTimeEdit->setDateTime(currentDateTime); 0094 #ifndef QT_NO_ACCESSIBILITY 0095 mStartDateTimeEdit->setAccessibleDescription(i18n("Select start time for event.")); 0096 #endif 0097 connect(mStartDateTimeEdit, &EventDateTimeWidget::dateTimeChanged, this, &EventEdit::slotStartDateTimeChanged); 0098 hbox->addWidget(mStartDateTimeEdit); 0099 0100 hbox->addSpacing(5); 0101 0102 lab = new QLabel(i18n("End:"), this); 0103 hbox->addWidget(lab); 0104 mEndDateTimeEdit->setObjectName(QLatin1StringView("enddatetimeedit")); 0105 mEndDateTimeEdit->setDateTime(currentDateTime.addSecs(3600)); 0106 #ifndef QT_NO_ACCESSIBILITY 0107 mEndDateTimeEdit->setAccessibleDescription(i18n("Select end time for event.")); 0108 #endif 0109 connect(mEndDateTimeEdit, &EventDateTimeWidget::dateTimeChanged, this, &EventEdit::slotEndDateTimeChanged); 0110 0111 hbox->addWidget(mEndDateTimeEdit); 0112 0113 hbox->addStretch(1); 0114 0115 hbox = new QHBoxLayout; 0116 hbox->setSpacing(2); 0117 hbox->setContentsMargins({}); 0118 vbox->addLayout(hbox); 0119 0120 hbox->addStretch(1); 0121 0122 mSaveButton->setObjectName(QLatin1StringView("save-button")); 0123 mSaveButton->setEnabled(false); 0124 #ifndef QT_NO_ACCESSIBILITY 0125 mSaveButton->setAccessibleDescription(i18n("Create new event and close this widget.")); 0126 #endif 0127 connect(mSaveButton, &QPushButton::clicked, this, &EventEdit::slotReturnPressed); 0128 hbox->addWidget(mSaveButton); 0129 0130 #ifndef QT_NO_ACCESSIBILITY 0131 mOpenEditorButton->setAccessibleDescription(i18n("Open event editor, where more details can be changed.")); 0132 #endif 0133 mOpenEditorButton->setObjectName(QLatin1StringView("open-editor-button")); 0134 mOpenEditorButton->setEnabled(false); 0135 connect(mOpenEditorButton, &QPushButton::clicked, this, &EventEdit::slotOpenEditor); 0136 hbox->addWidget(mOpenEditorButton); 0137 0138 auto btn = new QPushButton(this); 0139 KGuiItem::assign(btn, KStandardGuiItem::cancel()); 0140 btn->setObjectName(QLatin1StringView("close-button")); 0141 #ifndef QT_NO_ACCESSIBILITY 0142 btn->setAccessibleDescription(i18n("Close the widget for creating new events.")); 0143 #endif 0144 connect(btn, &QPushButton::clicked, this, &EventEdit::slotCloseWidget); 0145 hbox->addWidget(btn); 0146 0147 readConfig(); 0148 setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); 0149 installEventFilter(this); 0150 mCollectionCombobox->installEventFilter(this); 0151 } 0152 0153 EventEdit::~EventEdit() 0154 { 0155 writeConfig(); 0156 } 0157 0158 void EventEdit::comboboxRowInserted() 0159 { 0160 slotUpdateButtons(mEventEdit->text()); 0161 } 0162 0163 void EventEdit::writeConfig() 0164 { 0165 const Akonadi::Collection col = mCollectionCombobox->currentCollection(); 0166 // col might not be valid if the collection wasn't found yet (the combo is async), skip saving in that case. 0167 if (col.isValid() && col.id() != MessageViewer::MessageViewerSettingsBase::self()->lastEventSelectedFolder()) { 0168 MessageViewer::MessageViewerSettingsBase::self()->setLastEventSelectedFolder(col.id()); 0169 MessageViewer::MessageViewerSettingsBase::self()->save(); 0170 } 0171 } 0172 0173 void EventEdit::slotUpdateButtons(const QString &subject) 0174 { 0175 const bool subjectIsNotEmpty = !subject.trimmed().isEmpty(); 0176 const bool collectionComboboxEmpty = (mCollectionCombobox->count() < 1); 0177 mSaveButton->setEnabled(subjectIsNotEmpty && !collectionComboboxEmpty); 0178 mOpenEditorButton->setEnabled(subjectIsNotEmpty && !collectionComboboxEmpty); 0179 } 0180 0181 void EventEdit::showEventEdit() 0182 { 0183 mEventEdit->setFocus(); 0184 QDateTime currentDateTime = QDateTime::currentDateTime(); 0185 mStartDateTimeEdit->setDateTime(currentDateTime); 0186 mEndDateTimeEdit->setDateTime(currentDateTime.addSecs(3600)); 0187 show(); 0188 } 0189 0190 void EventEdit::readConfig() 0191 { 0192 const qint64 id = MessageViewer::MessageViewerSettingsBase::self()->lastEventSelectedFolder(); 0193 if (id >= 0) { 0194 mCollectionCombobox->setDefaultCollection(Akonadi::Collection(id)); 0195 } 0196 } 0197 0198 Akonadi::Collection EventEdit::collection() const 0199 { 0200 return mCollection; 0201 } 0202 0203 void EventEdit::slotCollectionChanged(int /*index*/) 0204 { 0205 setCollection(mCollectionCombobox->currentCollection()); 0206 } 0207 0208 void EventEdit::setCollection(const Akonadi::Collection &value) 0209 { 0210 if (mCollection != value) { 0211 mCollection = value; 0212 Q_EMIT collectionChanged(mCollection); 0213 } 0214 } 0215 0216 KMime::Message::Ptr EventEdit::message() const 0217 { 0218 return mMessage; 0219 } 0220 0221 void EventEdit::setMessage(const KMime::Message::Ptr &value) 0222 { 0223 if (mMessage != value) { 0224 mMessage = value; 0225 const KMime::Headers::Subject *const subject = mMessage ? mMessage->subject(false) : nullptr; 0226 if (subject) { 0227 mEventEdit->setText(subject->asUnicodeString()); 0228 mEventEdit->selectAll(); 0229 mEventEdit->setFocus(); 0230 } else { 0231 mEventEdit->clear(); 0232 } 0233 Q_EMIT messageChanged(mMessage); 0234 } 0235 } 0236 0237 void EventEdit::slotCloseWidget() 0238 { 0239 if (isVisible()) { 0240 writeConfig(); 0241 mEventEdit->clear(); 0242 mMessage = KMime::Message::Ptr(); 0243 hide(); 0244 } 0245 } 0246 0247 void EventEdit::slotReturnPressed() 0248 { 0249 if (!mMessage) { 0250 qCDebug(CREATEEVENTPLUGIN_LOG) << " Message is null"; 0251 return; 0252 } 0253 const Akonadi::Collection collection = mCollectionCombobox->currentCollection(); 0254 if (!collection.isValid()) { 0255 qCDebug(CREATEEVENTPLUGIN_LOG) << " Collection is not valid"; 0256 return; 0257 } 0258 0259 const QDateTime dtstart = mStartDateTimeEdit->dateTime(); 0260 const QDateTime dtend = mEndDateTimeEdit->dateTime(); 0261 if (!dtstart.isValid() || !dtend.isValid()) { 0262 qCDebug(CREATEEVENTPLUGIN_LOG) << " date is not valid !"; 0263 return; 0264 } 0265 0266 if (!mEventEdit->text().trimmed().isEmpty()) { 0267 KCalendarCore::Event::Ptr event = createEventItem(); 0268 Q_EMIT createEvent(event, collection); 0269 hide(); 0270 } 0271 } 0272 0273 bool EventEdit::eventFilter(QObject *object, QEvent *e) 0274 { 0275 // Close the bar when pressing Escape. 0276 // Not using a QShortcut for this because it could conflict with 0277 // window-global actions (e.g. Emil Sedgh binds Esc to "close tab"). 0278 // With a shortcut override we can catch this before it gets to kactions. 0279 const bool shortCutOverride = (e->type() == QEvent::ShortcutOverride); 0280 if (shortCutOverride) { 0281 auto kev = static_cast<QKeyEvent *>(e); 0282 if (kev->key() == Qt::Key_Escape) { 0283 e->accept(); 0284 slotCloseWidget(); 0285 return true; 0286 } else if (kev->key() == Qt::Key_Enter || kev->key() == Qt::Key_Return || kev->key() == Qt::Key_Space) { 0287 e->accept(); 0288 if (object == mCollectionCombobox) { 0289 mCollectionCombobox->showPopup(); 0290 } 0291 return true; 0292 } 0293 } 0294 return QWidget::eventFilter(object, e); 0295 } 0296 0297 void EventEdit::slotEndDateTimeChanged(const QDateTime &newDateTime) 0298 { 0299 if (!newDateTime.isValid()) { 0300 return; 0301 } 0302 QDateTime currentDateTime = QDateTime::currentDateTime(); 0303 if (newDateTime.date() > currentDateTime.date()) { 0304 QDateTime newDateDate = newDateTime; 0305 newDateDate.setTime(QTime(0, 0, 0)); 0306 mEndDateTimeEdit->setMinimumDateTime(newDateDate); 0307 } 0308 } 0309 0310 void EventEdit::slotStartDateTimeChanged(const QDateTime &newDateTime) 0311 { 0312 if (!newDateTime.isValid()) { 0313 return; 0314 } 0315 0316 if (mEndDateTimeEdit->date() == newDateTime.date() && mEndDateTimeEdit->time() < newDateTime.time()) { 0317 mEndDateTimeEdit->setTime(newDateTime.time()); 0318 } 0319 if (mEndDateTimeEdit->date() < newDateTime.date()) { 0320 mEndDateTimeEdit->setDate(newDateTime.date()); 0321 } 0322 0323 mEndDateTimeEdit->setMinimumDateTime(newDateTime); 0324 } 0325 0326 KCalendarCore::Event::Ptr EventEdit::createEventItem() 0327 { 0328 if (mMessage) { 0329 KCalendarCore::Attachment attachment(mMessage->encodedContent().toBase64(), KMime::Message::mimeType()); 0330 const KMime::Headers::Subject *const subject = mMessage->subject(false); 0331 if (subject) { 0332 attachment.setLabel(subject->asUnicodeString()); 0333 } 0334 KCalendarCore::Event::Ptr event(new KCalendarCore::Event); 0335 event->setSummary(mEventEdit->text()); 0336 event->setDtStart(mStartDateTimeEdit->dateTime()); 0337 event->setDtEnd(mEndDateTimeEdit->dateTime()); 0338 event->addAttachment(attachment); 0339 0340 if (CalendarSupport::KCalPrefs::instance()->defaultEventReminders()) { 0341 KCalendarCore::Alarm::Ptr alm = event->newAlarm(); 0342 CalendarSupport::createAlarmReminder(alm, event->type()); 0343 } 0344 0345 return event; 0346 } 0347 return {}; 0348 } 0349 0350 void EventEdit::slotOpenEditor() 0351 { 0352 KCalendarCore::Event::Ptr event = createEventItem(); 0353 if (event) { 0354 Akonadi::Item item; 0355 item.setPayload<KCalendarCore::Event::Ptr>(event); 0356 item.setMimeType(KCalendarCore::Event::eventMimeType()); 0357 0358 IncidenceEditorNG::IncidenceDialog *dlg = 0359 IncidenceEditorNG::IncidenceDialogFactory::create(true, KCalendarCore::IncidenceBase::TypeEvent, nullptr, this); 0360 dlg->selectCollection(mCollectionCombobox->currentCollection()); 0361 connect(dlg, &IncidenceEditorNG::IncidenceDialog::finished, this, &EventEdit::slotCloseWidget); 0362 dlg->load(item); 0363 dlg->open(); 0364 } 0365 } 0366 0367 #include "moc_eventedit.cpp"