| 1 | /**************************************************************************** |
| 2 | ** |
| 3 | ** Copyright (C) 2015 The Qt Company Ltd. |
| 4 | ** Contact: http://www.qt.io/licensing/ |
| 5 | ** |
| 6 | ** This file is part of the examples of the Qt Toolkit. |
| 7 | ** |
| 8 | ** $QT_BEGIN_LICENSE:BSD$ |
| 9 | ** You may use this file under the terms of the BSD license as follows: |
| 10 | ** |
| 11 | ** "Redistribution and use in source and binary forms, with or without |
| 12 | ** modification, are permitted provided that the following conditions are |
| 13 | ** met: |
| 14 | ** * Redistributions of source code must retain the above copyright |
| 15 | ** notice, this list of conditions and the following disclaimer. |
| 16 | ** * Redistributions in binary form must reproduce the above copyright |
| 17 | ** notice, this list of conditions and the following disclaimer in |
| 18 | ** the documentation and/or other materials provided with the |
| 19 | ** distribution. |
| 20 | ** * Neither the name of The Qt Company Ltd nor the names of its |
| 21 | ** contributors may be used to endorse or promote products derived |
| 22 | ** from this software without specific prior written permission. |
| 23 | ** |
| 24 | ** |
| 25 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 26 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 27 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 28 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 29 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 30 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 31 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 32 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 33 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 34 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 35 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
| 36 | ** |
| 37 | ** $QT_END_LICENSE$ |
| 38 | ** |
| 39 | ****************************************************************************/ |
| 40 | #include "eventeditpage.h" |
| 41 | |
| 42 | #include <QtWidgets> |
| 43 | #include <QtOrganizer/qorganizer.h> |
| 44 | |
| 45 | QTORGANIZER_USE_NAMESPACE |
| 46 | |
| 47 | EventEditPage::EventEditPage(QWidget *parent) |
| 48 | :QWidget(parent), |
| 49 | m_manager(0), |
| 50 | m_alarmComboBox(0), |
| 51 | m_typeComboBox(0), |
| 52 | m_subjectEdit(0), |
| 53 | m_countSpinBox(0), |
| 54 | m_repeatUntilDate(0) |
| 55 | { |
| 56 | //create asynch request to save an item |
| 57 | m_saveItemRequest = new QOrganizerItemSaveRequest(this); |
| 58 | // Create widgets |
| 59 | QLabel *subjectLabel = new QLabel("Subject:" , this); |
| 60 | m_subjectEdit = new QLineEdit(this); |
| 61 | QLabel *startTimeLabel = new QLabel("Start time:" , this); |
| 62 | m_startTimeEdit = new QDateTimeEdit(this); |
| 63 | m_startTimeEdit->setDisplayFormat(QString("yyyy-MM-dd hh:mm:ss AP" )); |
| 64 | QLabel *endTimeLabel = new QLabel("End time:" , this); |
| 65 | m_endTimeEdit = new QDateTimeEdit(this); |
| 66 | m_endTimeEdit->setDisplayFormat(QString("yyyy-MM-dd hh:mm:ss AP" )); |
| 67 | QLabel *repeatLabel = new QLabel("Repeat:" , this); |
| 68 | QLabel *alarmLabel = new QLabel("Alarm:" , this); |
| 69 | QLabel *calendarLabel = new QLabel("Calendar:" , this); |
| 70 | m_alarmComboBox = new QComboBox(this); |
| 71 | m_typeComboBox = new QComboBox(this); |
| 72 | m_typeComboBox->addItem(atext: "None" ); |
| 73 | m_typeComboBox->addItem(atext: "Daily" ); |
| 74 | m_typeComboBox->addItem(atext: "Weekly" ); |
| 75 | m_typeComboBox->addItem(atext: "Monthly" ); |
| 76 | m_typeComboBox->addItem(atext: "Yearly" ); |
| 77 | connect(sender: m_typeComboBox, SIGNAL(currentIndexChanged(const QString&)), receiver: this, |
| 78 | SLOT(frequencyChanged(const QString&))); |
| 79 | QStringList alarmList; |
| 80 | alarmList << "None" |
| 81 | << "0 minutes before" |
| 82 | << "5 minutes before" |
| 83 | << "15 minutes before" |
| 84 | << "30 minutes before" |
| 85 | << "1 hour before" ; |
| 86 | m_alarmComboBox->addItems(texts: alarmList); |
| 87 | connect(sender: m_alarmComboBox, SIGNAL(currentIndexChanged(const QString)), receiver: this, |
| 88 | SLOT(alarmIndexChanged(const QString))); |
| 89 | |
| 90 | m_endConditionComboBox = new QComboBox(this); |
| 91 | m_endConditionComboBox->addItem(atext: "Forever" ); |
| 92 | m_endConditionComboBox->addItem(atext: "Until a date" ); |
| 93 | m_endConditionComboBox->addItem(atext: "For a number of occurrences" ); |
| 94 | m_endConditionComboBox->setVisible(false); |
| 95 | connect(sender: m_endConditionComboBox, SIGNAL(currentIndexChanged(const QString&)), |
| 96 | receiver: this, SLOT(endConditionChanged(const QString&))); |
| 97 | |
| 98 | m_countSpinBox = new QSpinBox(this); |
| 99 | m_countSpinBox->setRange(min: 1, max: 100); |
| 100 | m_countSpinBox->setSingleStep(1); |
| 101 | m_countSpinBox->setVisible(false); |
| 102 | connect(sender: m_countSpinBox, SIGNAL(valueChanged(int)), receiver: this, SLOT(countChanged(int))); |
| 103 | |
| 104 | m_repeatUntilDate = new QDateEdit(this); |
| 105 | m_repeatUntilDate->setVisible(false); |
| 106 | connect(sender: m_repeatUntilDate, SIGNAL(dateChanged(QDate)), receiver: this, SLOT(untilChanged(QDate))); |
| 107 | |
| 108 | m_calendarComboBox = new QComboBox(this); |
| 109 | // the calendar names are not know here, fill the combo box later... |
| 110 | |
| 111 | // Add push buttons |
| 112 | QHBoxLayout* hbLayout = new QHBoxLayout(); |
| 113 | QPushButton *okButton = new QPushButton("Save" , this); |
| 114 | connect(sender: okButton,SIGNAL(clicked()),receiver: this,SLOT(saveClicked())); |
| 115 | hbLayout->addWidget(okButton); |
| 116 | QPushButton *cancelButton = new QPushButton("Cancel" , this); |
| 117 | connect(sender: cancelButton,SIGNAL(clicked()),receiver: this,SLOT(cancelClicked())); |
| 118 | hbLayout->addWidget(cancelButton); |
| 119 | |
| 120 | // check to see whether we support alarms. |
| 121 | QOrganizerManager defaultManager; |
| 122 | QList<QOrganizerItemDetail::DetailType> supportedDetails = defaultManager.supportedItemDetails(itemType: QOrganizerItemType::TypeEvent); |
| 123 | |
| 124 | QVBoxLayout *scrollAreaLayout = new QVBoxLayout(); |
| 125 | scrollAreaLayout->addWidget(subjectLabel); |
| 126 | scrollAreaLayout->addWidget(m_subjectEdit); |
| 127 | scrollAreaLayout->addWidget(startTimeLabel); |
| 128 | scrollAreaLayout->addWidget(m_startTimeEdit); |
| 129 | scrollAreaLayout->addWidget(endTimeLabel); |
| 130 | scrollAreaLayout->addWidget(m_endTimeEdit); |
| 131 | if (supportedDetails.contains(t: QOrganizerItemDetail::TypeVisualReminder)) { |
| 132 | scrollAreaLayout->addWidget(alarmLabel); |
| 133 | scrollAreaLayout->addWidget(m_alarmComboBox); |
| 134 | } |
| 135 | scrollAreaLayout->addWidget(repeatLabel); |
| 136 | scrollAreaLayout->addWidget(m_typeComboBox); |
| 137 | scrollAreaLayout->addWidget(m_endConditionComboBox); |
| 138 | scrollAreaLayout->addWidget(m_countSpinBox); |
| 139 | scrollAreaLayout->addWidget(m_repeatUntilDate); |
| 140 | scrollAreaLayout->addWidget(calendarLabel); |
| 141 | scrollAreaLayout->addWidget(m_calendarComboBox); |
| 142 | scrollAreaLayout->addStretch(); |
| 143 | scrollAreaLayout->addLayout(layout: hbLayout); |
| 144 | |
| 145 | QScrollArea *scrollArea = new QScrollArea(this); |
| 146 | scrollArea->setWidgetResizable(true); |
| 147 | QWidget *formContainer = new QWidget(scrollArea); |
| 148 | formContainer->setLayout(scrollAreaLayout); |
| 149 | scrollArea->setWidget(formContainer); |
| 150 | |
| 151 | QVBoxLayout *mainLayout = new QVBoxLayout(); |
| 152 | mainLayout->addWidget(scrollArea); |
| 153 | setLayout(mainLayout); |
| 154 | |
| 155 | m_listOfEvents.clear(); |
| 156 | } |
| 157 | |
| 158 | EventEditPage::~EventEditPage() |
| 159 | { |
| 160 | |
| 161 | } |
| 162 | |
| 163 | void EventEditPage::eventChanged(QOrganizerManager *manager, const QOrganizerEvent &event) |
| 164 | { |
| 165 | m_manager = manager; |
| 166 | m_organizerEvent = event; |
| 167 | m_subjectEdit->setText(event.displayLabel()); |
| 168 | m_startTimeEdit->setDateTime(event.startDateTime()); |
| 169 | m_endTimeEdit->setDateTime(event.endDateTime()); |
| 170 | QSet<QOrganizerRecurrenceRule> rrules(m_organizerEvent.recurrenceRules()); |
| 171 | // Check whether existing entry and if it is repeating. |
| 172 | if (rrules.count() != 0) { |
| 173 | QOrganizerRecurrenceRule rrule(rrules.values().at(i: 0)); |
| 174 | QOrganizerRecurrenceRule::Frequency freq(rrule.frequency()); |
| 175 | switch (freq) { |
| 176 | case QOrganizerRecurrenceRule::Daily: |
| 177 | m_typeComboBox->setCurrentIndex(1); |
| 178 | break; |
| 179 | case QOrganizerRecurrenceRule::Weekly: |
| 180 | m_typeComboBox->setCurrentIndex(2); |
| 181 | break; |
| 182 | case QOrganizerRecurrenceRule::Monthly: |
| 183 | m_typeComboBox->setCurrentIndex(3); |
| 184 | break; |
| 185 | case QOrganizerRecurrenceRule::Yearly: |
| 186 | m_typeComboBox->setCurrentIndex(4); |
| 187 | break; |
| 188 | case QOrganizerRecurrenceRule::Invalid: |
| 189 | m_typeComboBox->setCurrentIndex(0); // No repeat |
| 190 | return; |
| 191 | } |
| 192 | if (rrule.limitType() == QOrganizerRecurrenceRule::DateLimit) { |
| 193 | m_endConditionComboBox->setCurrentIndex(1); // End date specified |
| 194 | m_repeatUntilDate->setDate(rrule.limitDate()); |
| 195 | } else if (rrule.limitType() == QOrganizerRecurrenceRule::CountLimit) { |
| 196 | m_endConditionComboBox->setCurrentIndex(2); // Count specified |
| 197 | m_countSpinBox->setValue(rrule.limitCount()); |
| 198 | } |
| 199 | } else { |
| 200 | m_typeComboBox->setCurrentIndex(0); // No repeat |
| 201 | } |
| 202 | |
| 203 | // set calendar selection |
| 204 | m_calendarComboBox->clear(); |
| 205 | |
| 206 | QOrganizerItemReminder reminder = event.detail(detailType: QOrganizerItemDetail::TypeReminder); |
| 207 | if (!reminder.isEmpty()) { |
| 208 | // Alarm combo is only able to handle certain time limits correctly; for example time |
| 209 | // limit 3 minutes is rounded up to 5 minutes |
| 210 | if (reminder.secondsBeforeStart() == 0) |
| 211 | m_alarmComboBox->setCurrentIndex(1); |
| 212 | else if (reminder.secondsBeforeStart() < 300) |
| 213 | m_alarmComboBox->setCurrentIndex(2); |
| 214 | else if (reminder.secondsBeforeStart() < 900) |
| 215 | m_alarmComboBox->setCurrentIndex(3); |
| 216 | else if (reminder.secondsBeforeStart() < 1800) |
| 217 | m_alarmComboBox->setCurrentIndex(4); |
| 218 | else |
| 219 | m_alarmComboBox->setCurrentIndex(5); |
| 220 | } else { |
| 221 | m_alarmComboBox->setCurrentIndex(0); |
| 222 | } |
| 223 | |
| 224 | // resolve metadata field that contains calendar name (if any) |
| 225 | m_collections = m_manager->collections(); |
| 226 | int index = 0; |
| 227 | int eventCalendarIndex = -1; |
| 228 | foreach(QOrganizerCollection collection, m_collections) { |
| 229 | // We currently have no way of stringifying ids |
| 230 | //QString visibleName = "Calendar id = " + QString::number(collection.id().localId()); |
| 231 | QString visibleName = collection.metaData(key: QOrganizerCollection::KeyName).toString(); |
| 232 | if (visibleName.isEmpty()) |
| 233 | visibleName = "Calendar " + QString::number(index); |
| 234 | |
| 235 | m_calendarComboBox->addItem(atext: visibleName); |
| 236 | if (collection.id() == event.collectionId()) |
| 237 | eventCalendarIndex = index; |
| 238 | ++index; |
| 239 | } |
| 240 | |
| 241 | if (eventCalendarIndex > -1) { |
| 242 | m_calendarComboBox->setCurrentIndex(eventCalendarIndex); |
| 243 | m_calendarComboBox->setEnabled(false); // when modifying existing events, the calendar can't be changed anymore |
| 244 | } |
| 245 | else { |
| 246 | m_calendarComboBox->setEnabled(true); |
| 247 | } |
| 248 | } |
| 249 | |
| 250 | void EventEditPage::cancelClicked() |
| 251 | { |
| 252 | emit showDayPage(); |
| 253 | } |
| 254 | |
| 255 | void EventEditPage::saveClicked() |
| 256 | { |
| 257 | QDateTime start(m_startTimeEdit->dateTime()); |
| 258 | QDateTime end(m_endTimeEdit->dateTime()); |
| 259 | if (start > end) { |
| 260 | QMessageBox::warning(parent: this, title: "Failed!" , text: "Start date is not before end date" ); |
| 261 | return; |
| 262 | } |
| 263 | |
| 264 | m_organizerEvent.setDisplayLabel(m_subjectEdit->text()); |
| 265 | m_organizerEvent.setStartDateTime(start); |
| 266 | m_organizerEvent.setEndDateTime(end); |
| 267 | m_listOfEvents.append(t: m_organizerEvent); |
| 268 | if (m_calendarComboBox->currentIndex() > 0) { |
| 269 | m_organizerEvent.setCollectionId(m_collections[m_calendarComboBox->currentIndex()].id()); |
| 270 | } |
| 271 | m_manager->saveItem(item: &m_organizerEvent); |
| 272 | if (m_manager->error()) |
| 273 | QMessageBox::warning(parent: this, title: "Failed!" , text: QString("Failed to save event!\n(error code %1)" ).arg(a: m_manager->error())); |
| 274 | else |
| 275 | emit showDayPage(); |
| 276 | } |
| 277 | |
| 278 | void EventEditPage::frequencyChanged(const QString& frequency) |
| 279 | { |
| 280 | QOrganizerRecurrenceRule rrule; |
| 281 | |
| 282 | if (frequency != "None" ) { |
| 283 | m_endConditionComboBox->setVisible(true); |
| 284 | |
| 285 | if (frequency == "Daily" ) { |
| 286 | rrule.setFrequency(QOrganizerRecurrenceRule::Daily); |
| 287 | } else if (frequency == "Weekly" ) { |
| 288 | rrule.setFrequency(QOrganizerRecurrenceRule::Weekly); |
| 289 | } else if (frequency == "Monthly" ) { |
| 290 | rrule.setFrequency(QOrganizerRecurrenceRule::Monthly); |
| 291 | } else if (frequency == "Yearly" ) { |
| 292 | rrule.setFrequency(QOrganizerRecurrenceRule::Yearly); |
| 293 | } |
| 294 | m_organizerEvent.setRecurrenceRule(rrule); |
| 295 | } else { |
| 296 | m_endConditionComboBox->setCurrentIndex(0); |
| 297 | m_endConditionComboBox->setVisible(false); |
| 298 | } |
| 299 | } |
| 300 | |
| 301 | void EventEditPage::alarmIndexChanged(const QString time) |
| 302 | { |
| 303 | bool noVisualReminders = !m_manager->supportedItemDetails(itemType: QOrganizerItemType::TypeEvent).contains(t: QOrganizerItemDetail::TypeVisualReminder); |
| 304 | |
| 305 | QScopedPointer<QOrganizerItemReminder> reminder; |
| 306 | if (noVisualReminders) { |
| 307 | reminder.reset(other: new QOrganizerItemReminder()); |
| 308 | } else { |
| 309 | reminder.reset(other: new QOrganizerItemVisualReminder()); |
| 310 | static_cast<QOrganizerItemVisualReminder *>(reminder.data())->setMessage(m_subjectEdit->text()); |
| 311 | } |
| 312 | |
| 313 | if (time == "None" ) { |
| 314 | QOrganizerItemVisualReminder fetchedReminder = m_organizerEvent.detail(detailType: QOrganizerItemDetail::TypeVisualReminder); |
| 315 | m_organizerEvent.removeDetail(detail: &fetchedReminder); |
| 316 | return; |
| 317 | } else if (time == "0 minutes before" ) { |
| 318 | reminder->setSecondsBeforeStart(0); |
| 319 | } else if (time == "5 minutes before" ) { |
| 320 | reminder->setSecondsBeforeStart(5*60); |
| 321 | } else if (time == "15 minutes before" ) { |
| 322 | reminder->setSecondsBeforeStart(15*60); |
| 323 | } else if (time == "30 minutes before" ) { |
| 324 | reminder->setSecondsBeforeStart(30*60); |
| 325 | } else if (time == "1 hour before" ) { |
| 326 | reminder->setSecondsBeforeStart(60*60); |
| 327 | } |
| 328 | |
| 329 | m_organizerEvent.saveDetail(detail: reminder.data()); |
| 330 | } |
| 331 | |
| 332 | void EventEditPage::showEvent(QShowEvent *event) |
| 333 | { |
| 334 | window()->setWindowTitle("Edit event" ); |
| 335 | QWidget::showEvent(event); |
| 336 | } |
| 337 | |
| 338 | void EventEditPage::countChanged(int i) |
| 339 | { |
| 340 | QOrganizerRecurrenceRule rrule; |
| 341 | rrule.setFrequency(m_organizerEvent.recurrenceRules().values().at(i: 0).frequency()); |
| 342 | rrule.setLimit(i); |
| 343 | m_organizerEvent.setRecurrenceRule(rrule); |
| 344 | } |
| 345 | |
| 346 | void EventEditPage::untilChanged(QDate date) |
| 347 | { |
| 348 | QOrganizerRecurrenceRule rrule; |
| 349 | rrule.setFrequency(m_organizerEvent.recurrenceRules().values().at(i: 0).frequency()); |
| 350 | rrule.setLimit(date); |
| 351 | m_organizerEvent.setRecurrenceRule(rrule); |
| 352 | } |
| 353 | |
| 354 | void EventEditPage::endConditionChanged(const QString& endCondition) { |
| 355 | if (endCondition == "Forever" ) { |
| 356 | m_countSpinBox->setVisible(false); |
| 357 | m_repeatUntilDate->setVisible(false); |
| 358 | } else if (endCondition == "Until a date" ) { |
| 359 | setRepeatUntilField(); |
| 360 | } else if (endCondition == "For a number of occurrences" ) { |
| 361 | setCountField(); |
| 362 | } |
| 363 | } |
| 364 | |
| 365 | void EventEditPage::setCountField() |
| 366 | { |
| 367 | m_countSpinBox->setVisible(true); |
| 368 | m_repeatUntilDate->setVisible(false); |
| 369 | m_countSpinBox->setValue(5); |
| 370 | countChanged(i: 5); // default value. |
| 371 | } |
| 372 | |
| 373 | void EventEditPage::setRepeatUntilField() |
| 374 | { |
| 375 | m_countSpinBox->setVisible(false); |
| 376 | m_repeatUntilDate->setVisible(true); |
| 377 | m_repeatUntilDate->setDate(m_endTimeEdit->date()); |
| 378 | untilChanged(date: m_endTimeEdit->date()); // default value. |
| 379 | } |
| 380 | |