diff --git a/src/widgets/editorview.cpp b/src/widgets/editorview.cpp index a2b12509..d273e2b2 100644 --- a/src/widgets/editorview.cpp +++ b/src/widgets/editorview.cpp @@ -1,588 +1,611 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "editorview.h" #include "recurrencewidget.h" #include "editorwidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kdateedit.h" +#include #include "addressline/addresseelineedit.h" #include "presentation/metatypes.h" #include #include #include #include #include #include "domain/artifact.h" #include "domain/task.h" #include "domain/relation.h" using namespace Widgets; EditorView::EditorView(QWidget *parent) : QWidget(parent), m_model(0), m_delegateLabel(new QLabel(this)), m_titleEdit(new QLineEdit(this)), m_textEdit(new EditorWidget(this)), m_taskGroup(new QWidget(this)), m_startDateEdit(new KPIM::KDateEdit(m_taskGroup)), + m_startTimeEdit(new KTimeComboBox(m_taskGroup)), m_dueDateEdit(new KPIM::KDateEdit(m_taskGroup)), + m_dueTimeEdit(new KTimeComboBox(m_taskGroup)), m_startTodayButton(new QPushButton(tr("Start today"), m_taskGroup)), m_delegateEdit(0), m_statusComboBox(new QComboBox(m_taskGroup)), m_progressEdit(new QSpinBox(m_taskGroup)), m_relationsLayout(new QVBoxLayout), m_attachmentsLayout(new QVBoxLayout), m_addAttachmentButton(new QPushButton(tr("Add attachment"), m_taskGroup)) { // To avoid having unit tests talking to akonadi // while we don't need the completion for them if (qgetenv("ZANSHIN_UNIT_TEST_RUN").isEmpty()) m_delegateEdit = new KPIM::AddresseeLineEdit(this); else m_delegateEdit = new KLineEdit(this); m_delegateLabel->setObjectName("delegateLabel"); m_delegateEdit->setObjectName("delegateEdit"); m_textEdit->setObjectName("textEdit"); m_titleEdit->setObjectName("titleEdit"); m_startDateEdit->setObjectName("startDateEdit"); + m_startTimeEdit->setObjectName("startTimeEdit"); m_dueDateEdit->setObjectName("dueDateEdit"); + m_dueTimeEdit->setObjectName("dueTimeEdit"); m_startTodayButton->setObjectName("startTodayButton"); m_statusComboBox->setObjectName("statusComboBox"); m_progressEdit->setObjectName("progressEdit"); m_startDateEdit->setMinimumContentsLength(10); m_dueDateEdit->setMinimumContentsLength(10); m_progressEdit->setRange(0, 100); m_statusComboBox->addItem(tr("None"), Domain::Task::None); m_statusComboBox->addItem(tr("Needs action"), Domain::Task::NeedsAction); m_statusComboBox->addItem(tr("In process"), Domain::Task::InProcess); m_statusComboBox->addItem(tr("Completed"), Domain::Task::Complete); m_statusComboBox->addItem(tr("Cancelled"), Domain::Task::Cancelled); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(m_delegateLabel); layout->addWidget(m_titleEdit); layout->addWidget(m_textEdit); layout->addLayout(m_relationsLayout); layout->addWidget(m_taskGroup); setLayout(layout); connect(m_addAttachmentButton, SIGNAL(clicked()), this, SLOT(onAddAttachmentClicked())); QVBoxLayout *vbox = new QVBoxLayout; vbox->addLayout(m_attachmentsLayout); QHBoxLayout *attachmentsHBox = new QHBoxLayout; attachmentsHBox->addWidget(m_addAttachmentButton); attachmentsHBox->addStretch(); vbox->addLayout(attachmentsHBox); auto delegateHBox = new QHBoxLayout; delegateHBox->addWidget(new QLabel(tr("Delegate to"), m_taskGroup)); delegateHBox->addWidget(m_delegateEdit); vbox->addLayout(delegateHBox); QHBoxLayout *datesHBox = new QHBoxLayout; datesHBox->addWidget(new QLabel(tr("Start date"), m_taskGroup)); datesHBox->addWidget(m_startDateEdit, 1); + datesHBox->addWidget(m_startTimeEdit, 1); datesHBox->addWidget(new QLabel(tr("Due date"), m_taskGroup)); datesHBox->addWidget(m_dueDateEdit, 1); + datesHBox->addWidget(m_dueTimeEdit, 1); vbox->addLayout(datesHBox); QHBoxLayout *bottomHBox = new QHBoxLayout; bottomHBox->addWidget(m_startTodayButton); bottomHBox->addStretch(); vbox->addLayout(bottomHBox); auto progressHBox = new QHBoxLayout; progressHBox->addWidget(new QLabel(tr("Progress"), m_taskGroup)); progressHBox->addWidget(m_progressEdit, 1); vbox->addLayout(progressHBox); auto statusHBox = new QHBoxLayout; statusHBox->addWidget(new QLabel(tr("Status"), m_taskGroup)); statusHBox->addWidget(m_statusComboBox, 1); vbox->addLayout(statusHBox); m_recurrenceWidget = new RecurrenceWidget; vbox->addWidget(m_recurrenceWidget); m_taskGroup->setLayout(vbox); // Make sure our minimum width is always the one with // the task group visible layout->activate(); setMinimumWidth(minimumSizeHint().width()); m_delegateLabel->setVisible(false); m_taskGroup->setVisible(false); auto editMenu = new QMenu; for(auto action : m_textEdit->editActions()) { editMenu->addAction(action); } auto menuAction = new QAction(0); menuAction->setText(tr("Edit")); menuAction->setMenu(editMenu); addAction(menuAction); for(auto action : m_textEdit->actions()) { addAction(action); } connect(m_textEdit, SIGNAL(fullscreenToggled(bool)), SLOT(toggleFullscreenEditor())); auto action = new QAction(this); action->setText(tr("Fullscreen &Editor")); action->setIcon(KIcon("go-up")); action->setShortcut(QKeySequence(Qt::Key_F5)); connect(action, SIGNAL(triggered()), SLOT(toggleFullscreenEditor())); addAction(action); connect(m_textEdit->editor(), SIGNAL(textChanged()), this, SLOT(onTextEditChanged())); connect(m_titleEdit, SIGNAL(editingFinished()), this, SLOT(onTextEditChanged())); connect(m_startDateEdit, SIGNAL(dateEntered(QDate)), this, SLOT(onStartEditEntered(QDate))); + connect(m_startTimeEdit, SIGNAL(timeEntered(QTime)), this, SLOT(onStartTimeEntered(QTime))); connect(m_dueDateEdit, SIGNAL(dateEntered(QDate)), this, SLOT(onDueEditEntered(QDate))); + connect(m_dueTimeEdit, SIGNAL(timeEntered(QTime)), this, SLOT(onDueTimeEntered(QTime))); connect(m_startTodayButton, SIGNAL(clicked()), this, SLOT(onStartTodayClicked())); connect(m_delegateEdit, SIGNAL(returnPressed()), this, SLOT(onDelegateEntered())); connect(m_progressEdit, SIGNAL(valueChanged(int)), this, SLOT(onProgressChanged(int))); connect(m_statusComboBox, SIGNAL(activated(int)), this, SLOT(onStatusChanged(int))); setEnabled(false); } void EditorView::toggleFullscreenEditor() { if (m_textEdit->windowState() & Qt::WindowFullScreen) { m_textEdit->setParent(this); static_cast(layout())->insertWidget(2, m_textEdit); } else { m_textEdit->setParent(0); } m_textEdit->setWindowState(m_textEdit->windowState() ^ Qt::WindowFullScreen); m_textEdit->show(); } QObject *EditorView::model() const { return m_model; } void EditorView::setModel(QObject *model) { if (model == m_model) return; if (m_model) { disconnect(m_model, 0, this, 0); disconnect(this, 0, m_model, 0); } m_model = model; onArtifactChanged(); onTextOrTitleChanged(); onHasTaskPropertiesChanged(); onStartDateChanged(); onDueDateChanged(); onDelegateTextChanged(); onProgressChanged(); onRecurrenceChanged(); onRelationsChanged(); onAttachmentsChanged(); onStatusChanged(); connect(m_model, SIGNAL(artifactChanged(Domain::Artifact::Ptr)), this, SLOT(onArtifactChanged())); connect(m_model, SIGNAL(hasTaskPropertiesChanged(bool)), this, SLOT(onHasTaskPropertiesChanged())); connect(m_model, SIGNAL(titleChanged(QString)), this, SLOT(onTextOrTitleChanged())); connect(m_model, SIGNAL(textChanged(QString)), this, SLOT(onTextOrTitleChanged())); connect(m_model, SIGNAL(startDateChanged(QDateTime)), this, SLOT(onStartDateChanged())); connect(m_model, SIGNAL(startDateChanged(QDateTime)), m_recurrenceWidget, SLOT(setStartDate(QDateTime))); connect(m_model, SIGNAL(dueDateChanged(QDateTime)), this, SLOT(onDueDateChanged())); connect(m_model, SIGNAL(delegateTextChanged(QString)), this, SLOT(onDelegateTextChanged())); connect(m_model, SIGNAL(progressChanged(int)), this, SLOT(onProgressChanged())); connect(m_model, SIGNAL(statusChanged(int)), this, SLOT(onStatusChanged())); connect(m_model, SIGNAL(recurrenceChanged(Domain::Recurrence::Ptr)), this, SLOT(onRecurrenceChanged())); connect(m_model, SIGNAL(relationsChanged(QList)), this, SLOT(onRelationsChanged())); connect(m_model, SIGNAL(attachmentsChanged(Domain::Artifact::Attachment::List)), this, SLOT(onAttachmentsChanged())); connect(this, SIGNAL(titleChanged(QString)), m_model, SLOT(setTitle(QString))); connect(this, SIGNAL(textChanged(QString)), m_model, SLOT(setText(QString))); connect(this, SIGNAL(startDateChanged(QDateTime)), m_model, SLOT(setStartDate(QDateTime))); connect(this, SIGNAL(dueDateChanged(QDateTime)), m_model, SLOT(setDueDate(QDateTime))); connect(this, SIGNAL(delegateChanged(QString, QString)), m_model, SLOT(setDelegate(QString, QString))); connect(this, SIGNAL(progressChanged(int)), m_model, SLOT(setProgress(int))); connect(this, SIGNAL(statusChanged(int)), m_model, SLOT(setStatus(int))); connect(m_recurrenceWidget, SIGNAL(frequencyChanged(Domain::Recurrence::Frequency,int)), m_model, SLOT(setFrequency(Domain::Recurrence::Frequency, int))); connect(m_recurrenceWidget, SIGNAL(endChanged(QDateTime)), m_model, SLOT(setRepeatEnd(QDateTime))); connect(m_recurrenceWidget, SIGNAL(endChanged(int)), m_model, SLOT(setRepeatEnd(int))); connect(m_recurrenceWidget, SIGNAL(noEnd()), m_model, SLOT(setRepeatEndless())); connect(m_recurrenceWidget, SIGNAL(exceptionDatesChanged(QList)), m_model, SLOT(setExceptionDates(QList))); connect(m_recurrenceWidget, SIGNAL(byDayChanged(QList)), m_model, SLOT(setByDay(QList))); connect(m_recurrenceWidget, SIGNAL(byMonthChanged(QList)), m_model, SLOT(setByMonth(QList))); connect(m_recurrenceWidget, SIGNAL(byMonthDaysChanged(QList)), m_model, SLOT(setByMonthDays(QList))); connect(m_recurrenceWidget, SIGNAL(byDayPositionChanged(Domain::Recurrence::WeekPosition)), m_model, SLOT(setByDayPosition(Domain::Recurrence::WeekPosition))); } void EditorView::onArtifactChanged() { auto artifact = m_model->property("artifact").value(); setEnabled(artifact); } void EditorView::onHasTaskPropertiesChanged() { m_taskGroup->setVisible(m_model->property("hasTaskProperties").toBool()); } void EditorView::onTextOrTitleChanged() { //We have to temporarilly disconnect these signals to avoid triggering a save when setting the content of the editor. disconnect(m_textEdit->editor(), SIGNAL(textChanged()), this, SLOT(onTextEditChanged())); disconnect(m_titleEdit, SIGNAL(editingFinished()), this, SLOT(onTextEditChanged())); const QString text = m_model->property("text").toString(); if (text != m_textEdit->editor()->toHtml()) m_textEdit->editor()->setText(text); const QString title = m_model->property("title").toString(); if (title != m_titleEdit->text()) m_titleEdit->setText(title); connect(m_textEdit->editor(), SIGNAL(textChanged()), this, SLOT(onTextEditChanged())); connect(m_titleEdit, SIGNAL(editingFinished()), this, SLOT(onTextEditChanged())); } void EditorView::onStartDateChanged() { m_startDateEdit->setDate(m_model->property("startDate").toDateTime().date()); + m_startTimeEdit->setTime(m_model->property("startDate").toDateTime().time()); } void EditorView::onDueDateChanged() { m_dueDateEdit->setDate(m_model->property("dueDate").toDateTime().date()); + m_dueTimeEdit->setTime(m_model->property("dueDate").toDateTime().time()); } void EditorView::onProgressChanged() { m_progressEdit->setValue(m_model->property("progress").toInt()); } void EditorView::onStatusChanged() { for (int i = 0; i < m_statusComboBox->count(); i++) { if (m_statusComboBox->itemData(i).toInt() == m_model->property("status").toInt()) { m_statusComboBox->setCurrentIndex(i); return; } } m_statusComboBox->setCurrentIndex(0); } void EditorView::onDelegateTextChanged() { const auto delegateText = m_model->property("delegateText").toString(); const auto labelText = delegateText.isEmpty() ? QString() : tr("Delegated to: %1").arg(delegateText); m_delegateLabel->setVisible(!labelText.isEmpty()); m_delegateLabel->setText(labelText); m_delegateEdit->clear(); } void EditorView::onRelationsChanged() { const auto relations = m_model->property("relations").value >(); for (auto widget : m_relationWidgets) { m_relationsLayout->removeWidget(widget); delete widget; } m_relationWidgets.clear(); for (auto relation : relations) { auto widget = new QWidget(this); auto layout = new QHBoxLayout(widget); widget->setLayout(layout); auto labelText = QString("%2").arg(relation->url().toString()).arg(relation->name()); auto label = new QLabel(widget); label->setTextInteractionFlags(Qt::LinksAccessibleByMouse); label->setTextFormat(Qt::RichText); label->setText(labelText); connect(label, SIGNAL(linkActivated(QString)), this, SLOT(onLinkActivated(QString))); layout->addWidget(label); auto button = new QPushButton(widget); button->setProperty("relation", QVariant::fromValue(relation)); button->setIcon(QIcon::fromTheme("list-remove")); connect(button, SIGNAL(clicked()), this, SLOT(onRemoveRelationClicked())); layout->addWidget(button); layout->addStretch(); m_relationsLayout->addWidget(widget); m_relationWidgets << widget; } } void EditorView::onAttachmentsChanged() { const auto attachments = m_model->property("attachments").value(); for (auto widget : m_attachmentWidgets) { m_attachmentsLayout->removeWidget(widget); delete widget; } m_attachmentWidgets.clear(); for (const auto &attachment : attachments) { auto widget = new QWidget(this); auto layout = new QHBoxLayout(widget); widget->setLayout(layout); auto labelText = QString("%2").arg("attachmentDummyUrl").arg(attachment->label); auto label = new QLabel(widget); label->setTextInteractionFlags(Qt::LinksAccessibleByMouse); label->setTextFormat(Qt::RichText); label->setText(labelText); label->setProperty("attachment", QVariant::fromValue(attachment)); connect(label, SIGNAL(linkActivated(QString)), this, SLOT(onAttachmentLinkActivated(QString))); layout->addWidget(label); auto button = new QPushButton(widget); button->setProperty("attachment", QVariant::fromValue(attachment)); button->setIcon(QIcon::fromTheme("list-remove")); connect(button, SIGNAL(clicked()), this, SLOT(onRemoveAttachmentClicked())); layout->addWidget(button); layout->addStretch(); m_attachmentsLayout->addWidget(widget); m_attachmentWidgets << widget; } } void EditorView::onRecurrenceChanged() { const auto recurrence = m_model->property("recurrence").value(); m_recurrenceWidget->blockSignals(true); if (recurrence) { m_recurrenceWidget->setRecurrenceType(recurrence->frequency()); m_recurrenceWidget->setRecurrenceIntervall(recurrence->interval()); m_recurrenceWidget->setExceptionDateTimes(recurrence->exceptionDates()); m_recurrenceWidget->setByDayPosition(recurrence->byDayPosition()); m_recurrenceWidget->setByDay(recurrence->byday()); m_recurrenceWidget->setByMonth(recurrence->bymonth()); m_recurrenceWidget->setByMonthDay(recurrence->bymonthday()); if (recurrence->end().isValid()) { m_recurrenceWidget->setEnd(recurrence->end()); } else if (recurrence->count() >= 0) { m_recurrenceWidget->setEnd(recurrence->count()); } else if (recurrence->count() == -1) { m_recurrenceWidget->setNoEnd(); } } else { m_recurrenceWidget->clear(); } m_recurrenceWidget->blockSignals(false); if (recurrence && !m_statusComboBox->itemData(5).isValid()) { m_statusComboBox->addItem(tr("All ocurrences completed"), Domain::Task::FullComplete); onStatusChanged(); } else if (!recurrence && m_statusComboBox->itemData(5).isValid()) { m_statusComboBox->removeItem(5); } } void EditorView::onRemoveRelationClicked() { auto relation = sender()->property("relation").value(); QMetaObject::invokeMethod(m_model, "removeRelation", Q_ARG(Domain::Relation::Ptr, relation)); } void EditorView::onLinkActivated(const QString &link) { KRun::run("kmail --view %u", KUrl::List() << KUrl(link), 0); } void EditorView::onRemoveAttachmentClicked() { auto attachment = sender()->property("attachment").value(); QMetaObject::invokeMethod(m_model, "removeAttachment", Q_ARG(Domain::Artifact::Attachment::Ptr, attachment)); } void EditorView::onAddAttachmentClicked() { auto attachmentFileUrl = KFileDialog::getOpenUrl(KUrl(), QString(), 0, tr("Add Attachment")); auto attachment = Domain::Artifact::Attachment::Ptr::create(); attachment->label = attachmentFileUrl.fileName(KUrl::DirectoryOption::IgnoreTrailingSlash); auto mimeType = KMimeType::findByUrl(attachmentFileUrl); attachment->mimetype = mimeType->name(); QString tmpFile; if (KIO::NetAccess::download(attachmentFileUrl, tmpFile, this)) { QFile f(tmpFile); if (!f.open(QIODevice::ReadOnly)) { return; } QByteArray data = f.readAll(); f.close(); attachment->data = data; } KIO::NetAccess::removeTempFile(tmpFile); QMetaObject::invokeMethod(m_model, "addAttachment", Q_ARG(Domain::Artifact::Attachment::Ptr, attachment)); } KUrl tempFileForAttachment(const Domain::Artifact::Attachment::Ptr &attachment) { KTemporaryFile *file = new KTemporaryFile(); QStringList patterns = KMimeType::mimeType(attachment->mimetype)->patterns(); if (!patterns.empty()) { file->setSuffix(QString(patterns.first()).remove('*')); } file->setAutoRemove(true); file->open(); // read-only not to give the idea that it could be written to file->setPermissions(QFile::ReadUser); file->write(attachment->data); file->close(); return file->fileName(); } void EditorView::onAttachmentLinkActivated(const QString &link) { const auto attachment = sender()->property("attachment").value(); if (!attachment) { qWarning() << "Couldn't find attachment"; } QString saveAsFile = KFileDialog::getSaveFileName(attachment->label, QString(), 0, tr("Save Attachment")); if (saveAsFile.isEmpty() || (QFile(saveAsFile).exists() && (KMessageBox::warningYesNo(0,tr("%1 already exists. Do you want to overwrite it?").arg(saveAsFile)) == KMessageBox::No))) { return; } KUrl sourceUrl = tempFileForAttachment(attachment); // save the attachment url if (!KIO::NetAccess::file_copy(sourceUrl, KUrl(saveAsFile)) && KIO::NetAccess::lastError()) { KMessageBox::error(0, KIO::NetAccess::lastErrorString()); } } void EditorView::onTextEditChanged() { emit titleChanged(m_titleEdit->text()); emit textChanged(m_textEdit->editor()->toHtml()); } void EditorView::onStartEditEntered(const QDate &start) { - emit startDateChanged(QDateTime(start)); + emit startDateChanged(QDateTime(start, m_startTimeEdit->time())); } +void EditorView::onStartTimeEntered(const QTime &start) +{ + emit startDateChanged(QDateTime(m_startDateEdit->date() , start)); +} + + void EditorView::onDueEditEntered(const QDate &due) { - emit dueDateChanged(QDateTime(due)); + emit dueDateChanged(QDateTime(due, m_dueTimeEdit->time())); } +void EditorView::onDueTimeEntered(const QTime &due) +{ + emit dueDateChanged(QDateTime(m_dueDateEdit->date(), due)); +} + + void EditorView::onStartTodayClicked() { QDate today(QDate::currentDate()); m_startDateEdit->setDate(today); emit startDateChanged(QDateTime(today)); } void EditorView::onDelegateEntered() { const auto input = m_delegateEdit->text(); auto name = QString(); auto email = QString(); auto gotMatch = false; QRegExp fullRx("\\s*(.*) <([\\w\\.]+@[\\w\\.]+)>\\s*"); QRegExp emailOnlyRx("\\s*?\\s*"); if (input.contains(fullRx)) { name = fullRx.cap(1); email = fullRx.cap(2); gotMatch = true; } else if (input.contains(emailOnlyRx)) { email = emailOnlyRx.cap(1); gotMatch = true; } if (gotMatch) { QMetaObject::invokeMethod(m_model, "delegate", Q_ARG(QString, name), Q_ARG(QString, email)); } emit delegateChanged(name, email); } void EditorView::onProgressChanged(int progress) { emit progressChanged(progress); } void EditorView::onStatusChanged(int index) { emit statusChanged(m_statusComboBox->itemData(index).toInt()); } diff --git a/src/widgets/editorview.h b/src/widgets/editorview.h index 1e696fe7..b7a21445 100644 --- a/src/widgets/editorview.h +++ b/src/widgets/editorview.h @@ -1,124 +1,129 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef WIDGETS_EDITORVIEW_H #define WIDGETS_EDITORVIEW_H #include #include class QAbstractButton; class QLabel; class QLineEdit; class QComboBox; class QSpinBox; class QVBoxLayout; class QListWidget; class KLineEdit; +class KTimeComboBox; namespace KPIM { class KDateEdit; } namespace Widgets { class RecurrenceWidget; class EditorWidget; class EditorView : public QWidget { Q_OBJECT public: explicit EditorView(QWidget *parent = 0); virtual ~EditorView() {}; QObject *model() const; public slots: void setModel(QObject *model); signals: void textChanged(const QString &text); void titleChanged(const QString &title); void startDateChanged(const QDateTime &start); void dueDateChanged(const QDateTime &due); void delegateChanged(const QString &name, const QString &email); void progressChanged(int progress); void statusChanged(int status); private slots: void onArtifactChanged(); void onHasTaskPropertiesChanged(); void onTextOrTitleChanged(); void onStartDateChanged(); void onDueDateChanged(); void onDelegateTextChanged(); void onProgressChanged(); void onStatusChanged(); void onRelationsChanged(); void onAttachmentsChanged(); void onRecurrenceChanged(); void onTextEditChanged(); void onStartEditEntered(const QDate &start); void onDueEditEntered(const QDate &due); void onStartTodayClicked(); void onDelegateEntered(); void onProgressChanged(int progress); void onStatusChanged(int status); void onLinkActivated(const QString &link); void onRemoveRelationClicked(); void onAttachmentLinkActivated(const QString &link); void onRemoveAttachmentClicked(); void onAddAttachmentClicked(); + void onStartTimeEntered(const QTime &start); + void onDueTimeEntered(const QTime &due); void toggleFullscreenEditor(); private: QObject *m_model; QLabel *m_delegateLabel; QLineEdit *m_titleEdit; EditorWidget *m_textEdit; QWidget *m_taskGroup; KPIM::KDateEdit *m_startDateEdit; + KTimeComboBox *m_startTimeEdit; KPIM::KDateEdit *m_dueDateEdit; + KTimeComboBox *m_dueTimeEdit; QAbstractButton *m_startTodayButton; KLineEdit *m_delegateEdit; QComboBox *m_statusComboBox; QSpinBox *m_progressEdit; QList m_relationWidgets; QVBoxLayout *m_relationsLayout; QList m_attachmentWidgets; QVBoxLayout *m_attachmentsLayout; QAbstractButton *m_addAttachmentButton; RecurrenceWidget *m_recurrenceWidget; }; } #endif // WIDGETS_EDITORVIEW_H