File indexing completed on 2024-11-24 04:48:39
0001 /* 0002 * Copyright (C) 2007 by Thorsten Staerk and Mathias Soeken <msoeken@tzi.de> 0003 * Copyright (C) 2019 Alexander Potashev <aspotashev@gmail.com> 0004 * 0005 * This program is free software; you can redistribute it and/or modify 0006 * it under the terms of the GNU General Public License as published by 0007 * the Free Software Foundation; either version 2 of the License, or 0008 * (at your option) any later version. 0009 * 0010 * This program is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 * GNU General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU General Public License along 0016 * with this program; if not, write to the 0017 * Free Software Foundation, Inc. 0018 * 51 Franklin Street, Fifth Floor 0019 * Boston, MA 02110-1301 USA. 0020 * 0021 */ 0022 0023 #include "historydialog.h" 0024 0025 #include <QDateTimeEdit> 0026 #include <QItemDelegate> 0027 #include <QPushButton> 0028 #include <QSet> 0029 0030 #include <KMessageBox> 0031 #include <KStandardGuiItem> 0032 0033 #include "file/filecalendar.h" 0034 #include "ktt_debug.h" 0035 #include "model/event.h" 0036 #include "model/eventsmodel.h" 0037 #include "model/projectmodel.h" 0038 #include "model/task.h" 0039 #include "model/tasksmodel.h" 0040 0041 const QString HistoryDialog::dateTimeFormat = QStringLiteral("yyyy-MM-dd HH:mm:ss"); 0042 0043 class HistoryWidgetDelegate : public QItemDelegate 0044 { 0045 public: 0046 explicit HistoryWidgetDelegate(QObject *parent) 0047 : QItemDelegate(parent) 0048 { 0049 } 0050 0051 QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex & /*index*/) const override 0052 { 0053 auto* editor = new QDateTimeEdit(parent); 0054 editor->setAutoFillBackground(true); 0055 editor->setPalette(option.palette); 0056 editor->setBackgroundRole(QPalette::Window); 0057 return editor; 0058 } 0059 0060 void setEditorData(QWidget *editor, const QModelIndex &index) const override 0061 { 0062 QDateTime dateTime = QDateTime::fromString(index.model()->data(index, Qt::DisplayRole).toString(), 0063 HistoryDialog::dateTimeFormat); 0064 auto *dateTimeWidget = dynamic_cast<QDateTimeEdit *>(editor); 0065 if (dateTimeWidget) { 0066 dateTimeWidget->setDateTime(dateTime); 0067 } else { 0068 qCWarning(KTT_LOG) << "Cast to QDateTimeEdit failed"; 0069 } 0070 } 0071 0072 void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override 0073 { 0074 auto *dateTimeWidget = dynamic_cast<QDateTimeEdit *>(editor); 0075 if (dateTimeWidget) { 0076 QDateTime dateTime = dateTimeWidget->dateTime(); 0077 model->setData(index, dateTime.toString(HistoryDialog::dateTimeFormat), Qt::EditRole); 0078 } else { 0079 qCWarning(KTT_LOG) << "Cast to QDateTimeEdit failed"; 0080 } 0081 } 0082 0083 void updateEditorGeometry(QWidget *editor, 0084 const QStyleOptionViewItem &option, 0085 const QModelIndex & /*index*/) const override 0086 { 0087 editor->setGeometry(option.rect); 0088 } 0089 }; 0090 0091 HistoryDialog::HistoryDialog(QWidget *parent, ProjectModel *projectModel) 0092 : QDialog(parent) 0093 , m_projectModel(projectModel) 0094 , m_ui() 0095 { 0096 m_ui.setupUi(this); 0097 /* Item Delegate for displaying KDateTimeWidget instead of QLineEdit */ 0098 auto *historyWidgetDelegate = new HistoryWidgetDelegate(m_ui.historytablewidget); 0099 m_ui.historytablewidget->setItemDelegateForColumn(1, historyWidgetDelegate); 0100 m_ui.historytablewidget->setItemDelegateForColumn(2, historyWidgetDelegate); 0101 0102 m_ui.historytablewidget->setEditTriggers(QAbstractItemView::AllEditTriggers); 0103 m_ui.historytablewidget->setColumnCount(5); 0104 m_ui.historytablewidget->setHorizontalHeaderLabels( 0105 QStringList{i18n("Task"), i18n("StartTime"), i18n("EndTime"), i18n("Comment"), QStringLiteral("event UID")}); 0106 m_ui.historytablewidget->horizontalHeader()->setStretchLastSection(true); 0107 m_ui.historytablewidget->setColumnHidden(4, true); // hide the "UID" column 0108 listAllEvents(); 0109 m_ui.historytablewidget->setSortingEnabled(true); 0110 m_ui.historytablewidget->sortItems(1, Qt::DescendingOrder); 0111 m_ui.historytablewidget->resizeColumnsToContents(); 0112 auto *deleteButton = m_ui.buttonbox->addButton(QString(), QDialogButtonBox::ActionRole); 0113 KStandardGuiItem::assign(deleteButton, KStandardGuiItem::Delete); 0114 connect(deleteButton, &QPushButton::clicked, this, &HistoryDialog::onDeleteClicked); 0115 } 0116 0117 QString HistoryDialog::listAllEvents() 0118 { 0119 QString err; 0120 // if sorting is enabled and we write to row x, we cannot be sure row x will 0121 // be in row x some lines later 0122 bool old_sortingenabled = m_ui.historytablewidget->isSortingEnabled(); 0123 m_ui.historytablewidget->setSortingEnabled(false); 0124 connect(m_ui.historytablewidget, &QTableWidget::cellChanged, this, &HistoryDialog::onCellChanged); 0125 0126 for (const auto *event : m_projectModel->eventsModel()->events()) { 0127 int row = m_ui.historytablewidget->rowCount(); 0128 m_ui.historytablewidget->insertRow(row); 0129 0130 // maybe the file is corrupt and (*i)->relatedTo is NULL 0131 if (event->relatedTo().isEmpty()) { 0132 qCDebug(KTT_LOG) << "There is no 'relatedTo' entry for " << event->summary(); 0133 err = QStringLiteral("NoRelatedToForEvent"); 0134 continue; 0135 } 0136 0137 const Task *parent = dynamic_cast<Task *>(m_projectModel->tasksModel()->taskByUID(event->relatedTo())); 0138 if (!parent) { 0139 qCWarning(KTT_LOG) << "Unable to load 'relatedTo' entry for " << event->summary(); 0140 err = QStringLiteral("NoRelatedToForEvent"); 0141 continue; 0142 } 0143 0144 auto *item = new QTableWidgetItem(parent->name()); 0145 item->setFlags(Qt::ItemIsEnabled); 0146 item->setWhatsThis(i18nc("@info:whatsthis", "You can change this task's comment, start time and end time.")); 0147 m_ui.historytablewidget->setItem(row, 0, item); 0148 0149 QDateTime start = event->dtStart(); 0150 QDateTime end = event->dtEnd(); 0151 m_ui.historytablewidget->setItem(row, 1, new QTableWidgetItem(start.toString(dateTimeFormat))); 0152 m_ui.historytablewidget->setItem(row, 2, new QTableWidgetItem(end.toString(dateTimeFormat))); 0153 m_ui.historytablewidget->setItem(row, 4, new QTableWidgetItem(event->uid())); 0154 qDebug() << "event->comments.count() =" << event->comments().count(); 0155 if (event->comments().count() > 0) { 0156 m_ui.historytablewidget->setItem(row, 3, new QTableWidgetItem(event->comments().last())); 0157 } 0158 } 0159 0160 m_ui.historytablewidget->resizeColumnsToContents(); 0161 m_ui.historytablewidget->setColumnWidth(1, 300); 0162 m_ui.historytablewidget->setColumnWidth(2, 300); 0163 setMinimumSize(m_ui.historytablewidget->columnWidth(0) + m_ui.historytablewidget->columnWidth(1) 0164 + m_ui.historytablewidget->columnWidth(2) + m_ui.historytablewidget->columnWidth(3), 0165 height()); 0166 m_ui.historytablewidget->setSortingEnabled(old_sortingenabled); 0167 return err; 0168 } 0169 0170 void HistoryDialog::changeEvent(QEvent *e) 0171 { 0172 QDialog::changeEvent(e); 0173 switch (e->type()) { 0174 case QEvent::LanguageChange: 0175 m_ui.retranslateUi(this); 0176 break; 0177 default: 0178 break; 0179 } 0180 } 0181 0182 void HistoryDialog::onCellChanged(int row, int col) 0183 { 0184 qCDebug(KTT_LOG) << "row =" << row << " col =" << col; 0185 0186 if (!m_ui.historytablewidget->item(row, 4)) { 0187 // the program did the change, not the user 0188 return; 0189 } 0190 0191 switch (col) { 0192 case 1: { 0193 // StartDate changed 0194 qCDebug(KTT_LOG) << "user changed StartDate to" << m_ui.historytablewidget->item(row, col)->text(); 0195 QDateTime datetime = QDateTime::fromString(m_ui.historytablewidget->item(row, col)->text(), dateTimeFormat); 0196 if (!datetime.isValid()) { 0197 KMessageBox::information(nullptr, i18n("This is not a valid Date/Time.")); 0198 break; 0199 } 0200 0201 QString uid = m_ui.historytablewidget->item(row, 4)->text(); 0202 Event *event = m_projectModel->eventsModel()->eventByUID(uid); 0203 0204 event->setDtStart(datetime); 0205 // setDtStart could modify date/time, sync it into our table 0206 m_ui.historytablewidget->item(row, col)->setText(event->dtStart().toString(dateTimeFormat)); 0207 0208 Q_EMIT m_projectModel->eventsModel()->timesChanged(); 0209 qCDebug(KTT_LOG) << "Program SetDtStart to" << m_ui.historytablewidget->item(row, col)->text(); 0210 break; 0211 } 0212 case 2: { 0213 // EndDate changed 0214 qCDebug(KTT_LOG) << "user changed EndDate to" << m_ui.historytablewidget->item(row, col)->text(); 0215 QDateTime datetime = QDateTime::fromString(m_ui.historytablewidget->item(row, col)->text(), dateTimeFormat); 0216 if (!datetime.isValid()) { 0217 KMessageBox::information(nullptr, i18n("This is not a valid Date/Time.")); 0218 break; 0219 } 0220 0221 QString uid = m_ui.historytablewidget->item(row, 4)->text(); 0222 Event *event = m_projectModel->eventsModel()->eventByUID(uid); 0223 0224 event->setDtEnd(datetime); 0225 // setDtStart could modify date/time, sync it into our table 0226 m_ui.historytablewidget->item(row, col)->setText(event->dtEnd().toString(dateTimeFormat)); 0227 0228 Q_EMIT m_projectModel->eventsModel()->timesChanged(); 0229 qCDebug(KTT_LOG) << "Program SetDtEnd to" << m_ui.historytablewidget->item(row, col)->text(); 0230 break; 0231 } 0232 case 3: { 0233 // Comment changed 0234 qCDebug(KTT_LOG) << "user changed Comment to" << m_ui.historytablewidget->item(row, col)->text(); 0235 0236 QString uid = m_ui.historytablewidget->item(row, 4)->text(); 0237 Event *event = m_projectModel->eventsModel()->eventByUID(uid); 0238 qCDebug(KTT_LOG) << "uid =" << uid; 0239 event->addComment(m_ui.historytablewidget->item(row, col)->text()); 0240 qCDebug(KTT_LOG) << "added" << m_ui.historytablewidget->item(row, col)->text(); 0241 break; 0242 } 0243 default: 0244 break; 0245 } 0246 } 0247 0248 QString HistoryDialog::refresh() 0249 { 0250 while (m_ui.historytablewidget->rowCount() > 0) { 0251 m_ui.historytablewidget->removeRow(0); 0252 } 0253 listAllEvents(); 0254 return QString(); 0255 } 0256 0257 void HistoryDialog::onDeleteClicked() 0258 { 0259 // Create a list of rows to delete. 0260 // This includes both the current row (i.e. the row the cursor is on) as 0261 // well as the rows that are part of the current selection. Because these 0262 // can overlap and because the selected items contain one item per cell, not 0263 // just per row, we use a QSet here to get a unique list of rows. 0264 QSet<int> rows; 0265 if (m_ui.historytablewidget->currentRow() >= 0) { // Could be -1 if table is empty or no row is selected 0266 rows.insert(m_ui.historytablewidget->currentRow()); 0267 } 0268 for (const auto &item : m_ui.historytablewidget->selectedItems()) { 0269 rows.insert(item->row()); 0270 } 0271 0272 if (rows.empty()) { 0273 KMessageBox::information(this, i18n("Please select a task to delete.")); 0274 return; 0275 } 0276 0277 bool refresh = false; 0278 for (int row : rows) { 0279 QString uid = m_ui.historytablewidget->item(row, 4)->text(); 0280 qDebug() << "uid =" << uid; 0281 const Event *event = m_projectModel->eventsModel()->eventByUID(uid); 0282 if (event) { 0283 qCDebug(KTT_LOG) << "removing uid " << event->uid(); 0284 m_projectModel->eventsModel()->removeByUID(event->uid()); 0285 refresh = true; 0286 } 0287 } 0288 if (refresh) { 0289 Q_EMIT m_projectModel->eventsModel()->timesChanged(); 0290 this->refresh(); 0291 } 0292 } 0293 0294 void HistoryDialog::on_buttonbox_rejected() 0295 { 0296 m_ui.historytablewidget->setCurrentCell(0, 0); // you need to change the cell to store the value 0297 close(); 0298 } 0299 0300 #include "moc_historydialog.cpp"