File indexing completed on 2024-04-28 05:11:38

0001 /*
0002   SPDX-FileCopyrightText: 2010 Casey Link <unnamedrambler@gmail.com>
0003   SPDX-FileCopyrightText: 2009-2010 Klaralvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
0004 
0005   SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "schedulingdialog.h"
0009 #include "conflictresolver.h"
0010 #include "visualfreebusywidget.h"
0011 #include <CalendarSupport/FreePeriodModel>
0012 #include <KCalUtils/Stringify>
0013 
0014 #include <KLocalizedString>
0015 
0016 #include <QDialogButtonBox>
0017 #include <QLocale>
0018 #include <QPushButton>
0019 #include <QVBoxLayout>
0020 
0021 using namespace IncidenceEditorNG;
0022 
0023 SchedulingDialog::SchedulingDialog(QDate startDate, QTime startTime, int duration, ConflictResolver *resolver, QWidget *parent)
0024     : QDialog(parent)
0025     , mResolver(resolver)
0026     , mPeriodModel(new CalendarSupport::FreePeriodModel(this))
0027 {
0028     setWindowTitle(i18nc("@title:window", "Scheduling"));
0029     auto mainLayout = new QVBoxLayout(this);
0030     auto w = new QWidget(this);
0031     setupUi(w);
0032     auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
0033     QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
0034     okButton->setDefault(true);
0035     okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
0036     connect(buttonBox, &QDialogButtonBox::accepted, this, &SchedulingDialog::accept);
0037     connect(buttonBox, &QDialogButtonBox::rejected, this, &SchedulingDialog::reject);
0038 
0039     mainLayout->addWidget(w);
0040     mainLayout->addWidget(buttonBox);
0041     fillCombos();
0042 
0043     Q_ASSERT(duration > 0);
0044     mDuration = duration;
0045 
0046     mVisualWidget = new VisualFreeBusyWidget(resolver->model(), 8);
0047     auto ganttlayout = new QVBoxLayout(mGanttTab);
0048 
0049     mGanttTab->setLayout(ganttlayout);
0050     ganttlayout->addWidget(mVisualWidget);
0051 
0052     connect(mStartDate, &KDateComboBox::dateEdited, mResolver, &ConflictResolver::setEarliestDate);
0053     connect(mStartTime, &KTimeComboBox::timeEdited, mResolver, &ConflictResolver::setEarliestTime);
0054     connect(mEndDate, &KDateComboBox::dateEdited, mResolver, &ConflictResolver::setLatestDate);
0055     connect(mEndTime, &KTimeComboBox::timeEdited, mResolver, &ConflictResolver::setLatestTime);
0056 
0057     connect(mStartDate, &KDateComboBox::dateEdited, this, &SchedulingDialog::slotStartDateChanged);
0058 
0059     connect(mWeekdayCombo, &IncidenceEditorNG::KWeekdayCheckCombo::checkedItemsChanged, this, &SchedulingDialog::slotWeekdaysChanged);
0060     connect(mWeekdayCombo, &IncidenceEditorNG::KWeekdayCheckCombo::checkedItemsChanged, this, &SchedulingDialog::slotMandatoryRolesChanged);
0061 
0062     connect(mResolver, &ConflictResolver::freeSlotsAvailable, mPeriodModel, &CalendarSupport::FreePeriodModel::slotNewFreePeriods);
0063     connect(mMoveBeginTimeEdit, &KTimeComboBox::timeEdited, this, &SchedulingDialog::slotSetEndTimeLabel);
0064 
0065     mTableView->setModel(mPeriodModel);
0066     connect(mTableView->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &SchedulingDialog::slotRowSelectionChanged);
0067 
0068     mStartDate->setDate(startDate);
0069     mEndDate->setDate(mStartDate->date().addDays(7));
0070     mStartTime->setTime(startTime);
0071     mEndTime->setTime(startTime);
0072 
0073     mResolver->setEarliestDate(mStartDate->date());
0074     mResolver->setEarliestTime(mStartTime->time());
0075     mResolver->setLatestDate(mEndDate->date());
0076     mResolver->setLatestTime(mEndTime->time());
0077 
0078     mMoveApptGroupBox->hide();
0079 }
0080 
0081 SchedulingDialog::~SchedulingDialog() = default;
0082 
0083 void SchedulingDialog::slotUpdateIncidenceStartEnd(const QDateTime &startDateTime, const QDateTime &endDateTime)
0084 {
0085     mVisualWidget->slotUpdateIncidenceStartEnd(startDateTime, endDateTime);
0086 }
0087 
0088 void SchedulingDialog::fillCombos()
0089 {
0090     // Note: we depend on the following order
0091     mRolesCombo->addItem(QIcon::fromTheme(QStringLiteral("meeting-participant")), KCalUtils::Stringify::attendeeRole(KCalendarCore::Attendee::ReqParticipant));
0092     mRolesCombo->addItem(QIcon::fromTheme(QStringLiteral("meeting-participant-optional")),
0093                          KCalUtils::Stringify::attendeeRole(KCalendarCore::Attendee::OptParticipant));
0094     mRolesCombo->addItem(QIcon::fromTheme(QStringLiteral("meeting-observer")), KCalUtils::Stringify::attendeeRole(KCalendarCore::Attendee::NonParticipant));
0095     mRolesCombo->addItem(QIcon::fromTheme(QStringLiteral("meeting-chair")), KCalUtils::Stringify::attendeeRole(KCalendarCore::Attendee::Chair));
0096 
0097     mRolesCombo->setWhatsThis(i18nc("@info:whatsthis", "Edits the role of the attendee."));
0098 
0099     mRolesCombo->setItemCheckState(0, Qt::Checked);
0100     mRolesCombo->setItemCheckState(1, Qt::Checked);
0101     mRolesCombo->setItemCheckState(2, Qt::Checked);
0102     mRolesCombo->setItemCheckState(3, Qt::Checked);
0103 
0104     QBitArray days(7);
0105     days.setBit(0); // Monday
0106     days.setBit(1); // Tuesday
0107     days.setBit(2); // Wednesday
0108     days.setBit(3); // Thursday
0109     days.setBit(4); // Friday.. surprise!
0110 
0111     mWeekdayCombo->setDays(days);
0112     mResolver->setAllowedWeekdays(days);
0113 }
0114 
0115 void SchedulingDialog::slotStartDateChanged(const QDate &newDate)
0116 {
0117     QDate oldDate = mStDate;
0118     mStDate = newDate;
0119     if (newDate.isValid() && oldDate.isValid()) {
0120         updateWeekDays(oldDate);
0121     }
0122 }
0123 
0124 void SchedulingDialog::updateWeekDays(const QDate &oldDate)
0125 {
0126     const int oldStartDayIndex = mWeekdayCombo->weekdayIndex(oldDate);
0127     const int newStartDayIndex = mWeekdayCombo->weekdayIndex(mStDate);
0128 
0129     mWeekdayCombo->setItemCheckState(oldStartDayIndex, Qt::Unchecked);
0130     mWeekdayCombo->setItemEnabled(oldStartDayIndex, true);
0131     mWeekdayCombo->setItemCheckState(newStartDayIndex, Qt::Checked);
0132     mWeekdayCombo->setItemEnabled(newStartDayIndex, false);
0133 }
0134 
0135 void SchedulingDialog::slotWeekdaysChanged()
0136 {
0137     // notify the resolver
0138     mResolver->setAllowedWeekdays(mWeekdayCombo->days());
0139 }
0140 
0141 void SchedulingDialog::slotMandatoryRolesChanged()
0142 {
0143     QSet<KCalendarCore::Attendee::Role> roles;
0144     for (int i = 0; i < mRolesCombo->count(); ++i) {
0145         if (mRolesCombo->itemCheckState(i) == Qt::Checked) {
0146             roles << KCalendarCore::Attendee::Role(i);
0147         }
0148     }
0149     mResolver->setMandatoryRoles(roles);
0150 }
0151 
0152 void SchedulingDialog::slotRowSelectionChanged(const QModelIndex &current, const QModelIndex &previous)
0153 {
0154     Q_UNUSED(previous)
0155     if (!current.isValid()) {
0156         mMoveApptGroupBox->hide();
0157         return;
0158     }
0159     auto period = current.data(CalendarSupport::FreePeriodModel::PeriodRole).value<KCalendarCore::Period>();
0160     const QDate startDate = period.start().date();
0161 
0162     const int dayOfWeek = startDate.dayOfWeek();
0163     const QString dayLabel = ki18nc(
0164                                  "@label Day of week followed by day of the month, then the month. "
0165                                  "Example: Monday, 12 June",
0166                                  "%1, %2 %3")
0167                                  .subs(QLocale::system().dayName(dayOfWeek, QLocale::LongFormat))
0168                                  .subs(startDate.day())
0169                                  .subs(QLocale::system().monthName(startDate.month(), QLocale::LongFormat))
0170                                  .toString();
0171 
0172     mMoveDayLabel->setText(dayLabel);
0173     mMoveBeginTimeEdit->setTimeRange(period.start().time(), period.end().addSecs(-mDuration).time());
0174     mMoveBeginTimeEdit->setTime(period.start().time());
0175     slotSetEndTimeLabel(period.start().time());
0176     mMoveApptGroupBox->show();
0177 
0178     mSelectedDate = startDate;
0179 }
0180 
0181 void SchedulingDialog::slotSetEndTimeLabel(const QTime &startTime)
0182 {
0183     const QTime endTime = startTime.addSecs(mDuration);
0184     const QString endTimeLabel = ki18nc(
0185                                      "@label This is a suffix following a time selecting widget. "
0186                                      "Example: [timeedit] to 10:00am",
0187                                      "to %1")
0188                                      .subs(QLocale::system().toString(endTime))
0189                                      .toString();
0190 
0191     mMoveEndTimeLabel->setText(endTimeLabel);
0192     mSelectedTime = startTime;
0193 }
0194 
0195 QDate SchedulingDialog::selectedStartDate() const
0196 {
0197     return mSelectedDate;
0198 }
0199 
0200 QTime SchedulingDialog::selectedStartTime() const
0201 {
0202     return mSelectedTime;
0203 }
0204 
0205 #include "moc_schedulingdialog.cpp"