Incidenceeditor

visualfreebusywidget.cpp
1/*
2 SPDX-FileCopyrightText: 2010 Casey Link <unnamedrambler@gmail.com>
3 SPDX-FileCopyrightText: 2009-2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "visualfreebusywidget.h"
9#include "freebusyganttproxymodel.h"
10#include <CalendarSupport/FreeBusyItemModel>
11
12#include <KGanttAbstractRowController>
13#include <KGanttDateTimeGrid>
14#include <KGanttGraphicsView>
15#include <KGanttView>
16
17#include "incidenceeditor_debug.h"
18#include <KLocalizedString>
19#include <QComboBox>
20
21#include <QHeaderView>
22#include <QLabel>
23#include <QPointer>
24#include <QPushButton>
25#include <QScrollBar>
26#include <QSplitter>
27#include <QTreeView>
28#include <QVBoxLayout>
29
30using namespace IncidenceEditorNG;
31
32namespace IncidenceEditorNG
33{
34class RowController : public KGantt::AbstractRowController
35{
36private:
37 static const int ROW_HEIGHT;
39
40public:
41 RowController()
42 {
43 mRowHeight = 20;
44 }
45
46 void setModel(QAbstractItemModel *model)
47 {
48 m_model = model;
49 }
50
51 [[nodiscard]] int headerHeight() const override
52 {
53 return 2 * mRowHeight + 10;
54 }
55
56 [[nodiscard]] bool isRowVisible(const QModelIndex &) const override
57 {
58 return true;
59 }
60
61 [[nodiscard]] bool isRowExpanded(const QModelIndex &) const override
62 {
63 return false;
64 }
65
66 [[nodiscard]] KGantt::Span rowGeometry(const QModelIndex &idx) const override
67 {
68 return KGantt::Span(idx.row() * mRowHeight, mRowHeight);
69 }
70
71 [[nodiscard]] int maximumItemHeight() const override
72 {
73 return mRowHeight / 2;
74 }
75
76 [[nodiscard]] int totalHeight() const override
77 {
78 return m_model->rowCount() * mRowHeight;
79 }
80
81 [[nodiscard]] QModelIndex indexAt(int height) const override
82 {
83 return m_model->index(height / mRowHeight, 0);
84 }
85
86 [[nodiscard]] QModelIndex indexBelow(const QModelIndex &idx) const override
87 {
88 if (!idx.isValid()) {
89 return QModelIndex();
90 }
91 return idx.model()->index(idx.row() + 1, idx.column(), idx.parent());
92 }
93
94 [[nodiscard]] QModelIndex indexAbove(const QModelIndex &idx) const override
95 {
96 if (!idx.isValid()) {
97 return QModelIndex();
98 }
99 return idx.model()->index(idx.row() - 1, idx.column(), idx.parent());
100 }
101
102 void setRowHeight(int height)
103 {
104 mRowHeight = height;
105 }
106
107private:
108 int mRowHeight;
109};
110
111class GanttHeaderView : public QHeaderView
112{
113public:
114 explicit GanttHeaderView(QWidget *parent = nullptr)
116 {
117 }
118
119 [[nodiscard]] QSize sizeHint() const override
120 {
122 s.rheight() *= 2;
123 return s;
124 }
125};
126}
127
128VisualFreeBusyWidget::VisualFreeBusyWidget(CalendarSupport::FreeBusyItemModel *model, int spacing, QWidget *parent)
129 : QWidget(parent)
130{
131 auto topLayout = new QVBoxLayout(this);
132 topLayout->setSpacing(spacing);
133
134 // The control panel for the gantt widget
135 QBoxLayout *controlLayout = new QHBoxLayout();
136 controlLayout->setSpacing(topLayout->spacing());
137 topLayout->addItem(controlLayout);
138
139 auto label = new QLabel(i18nc("@label", "Scale: "), this);
140 controlLayout->addWidget(label);
141
142 mScaleCombo = new QComboBox(this);
143 mScaleCombo->setToolTip(i18nc("@info:tooltip", "Set the Gantt chart zoom level"));
144 mScaleCombo->setWhatsThis(xi18nc("@info:whatsthis",
145 "Select the Gantt chart zoom level from one of the following:<nl/>"
146 "'Hour' shows a range of several hours,<nl/>"
147 "'Day' shows a range of a few days,<nl/>"
148 "'Week' shows a range of a few weeks,<nl/>"
149 "and 'Month' shows a range of a few months,<nl/>"
150 "while 'Automatic' selects the range most "
151 "appropriate for the current event or to-do."));
152 mScaleCombo->addItem(i18nc("@item:inlistbox range in hours", "Hour"), QVariant::fromValue<int>(KGantt::DateTimeGrid::ScaleHour));
153 mScaleCombo->addItem(i18nc("@item:inlistbox range in days", "Day"), QVariant::fromValue<int>(KGantt::DateTimeGrid::ScaleDay));
154 mScaleCombo->addItem(i18nc("@item:inlistbox range in weeks", "Week"), QVariant::fromValue<int>(KGantt::DateTimeGrid::ScaleWeek));
155 mScaleCombo->addItem(i18nc("@item:inlistbox range in months", "Month"), QVariant::fromValue<int>(KGantt::DateTimeGrid::ScaleMonth));
156 mScaleCombo->addItem(i18nc("@item:inlistbox range is computed automatically", "Automatic"), QVariant::fromValue<int>(KGantt::DateTimeGrid::ScaleAuto));
157 mScaleCombo->setCurrentIndex(0); // start with "hour"
158 connect(mScaleCombo, &QComboBox::activated, this, &VisualFreeBusyWidget::slotScaleChanged);
159 controlLayout->addWidget(mScaleCombo);
160
161 auto button = new QPushButton(i18nc("@action:button", "Center on Start"), this);
162 button->setToolTip(i18nc("@info:tooltip", "Center the Gantt chart on the event start date and time"));
163 button->setWhatsThis(i18nc("@info:whatsthis",
164 "Click this button to center the Gantt chart on the start "
165 "time and day of this event."));
166 connect(button, &QPushButton::clicked, this, &VisualFreeBusyWidget::slotCenterOnStart);
167 controlLayout->addWidget(button);
168
169 controlLayout->addStretch(1);
170
171 button = new QPushButton(i18nc("@action:button", "Pick Date"), this);
172 button->setToolTip(i18nc("@info:tooltip",
173 "Move the event to a date and time when all "
174 "attendees are available"));
175 button->setWhatsThis(i18nc("@info:whatsthis",
176 "Click this button to move the event to a date "
177 "and time when all the attendees have time "
178 "available in their Free/Busy lists."));
179 button->setEnabled(false);
180 connect(button, &QPushButton::clicked, this, &VisualFreeBusyWidget::slotPickDate);
181 controlLayout->addWidget(button);
182
183 controlLayout->addStretch(1);
184
185 button = new QPushButton(i18nc("@action:button reload freebusy data", "Reload"), this);
186 button->setToolTip(i18nc("@info:tooltip", "Reload Free/Busy data for all attendees"));
187 button->setWhatsThis(i18nc("@info:whatsthis",
188 "Pressing this button will cause the Free/Busy data for all "
189 "attendees to be reloaded from their corresponding servers."));
190 controlLayout->addWidget(button);
191 connect(button, &QPushButton::clicked, this, &VisualFreeBusyWidget::manualReload);
192
193 auto splitter = new QSplitter(Qt::Horizontal, this);
194 connect(splitter, &QSplitter::splitterMoved, this, &VisualFreeBusyWidget::splitterMoved);
195 mLeftView = new QTreeView(this);
196 mLeftView->setModel(model);
197 mLeftView->setHeader(new GanttHeaderView);
198 mLeftView->header()->setStretchLastSection(true);
199 mLeftView->setToolTip(i18nc("@info:tooltip", "Shows the tree list of all data"));
200 mLeftView->setWhatsThis(i18nc("@info:whatsthis", "Shows the tree list of all data"));
201 mLeftView->setRootIsDecorated(false);
202 mLeftView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
203 mLeftView->setContextMenuPolicy(Qt::CustomContextMenu);
204 mGanttGraphicsView = new KGantt::GraphicsView(this);
205 mGanttGraphicsView->setObjectName(QLatin1StringView("mGanttGraphicsView"));
206 mGanttGraphicsView->setToolTip(i18nc("@info:tooltip", "Shows the Free/Busy status of all attendees"));
207 mGanttGraphicsView->setWhatsThis(i18nc("@info:whatsthis",
208 "Shows the Free/Busy status of all attendees. "
209 "Double-clicking on an attendee's entry in the "
210 "list will allow you to enter the location of "
211 "their Free/Busy Information."));
212 mModel = new FreeBusyGanttProxyModel(this);
213 mModel->setSourceModel(model);
214
215 mRowController = new RowController;
216 mRowController->setRowHeight(fontMetrics().height()); // TODO: detect
217
218 mRowController->setModel(mModel);
219 mGanttGraphicsView->setRowController(mRowController);
220
221 mGanttGrid = new KGantt::DateTimeGrid;
223 mGanttGrid->setDayWidth(800);
224 mGanttGrid->setRowSeparators(true);
225 mGanttGraphicsView->setGrid(mGanttGrid);
226 mGanttGraphicsView->setModel(mModel);
227 mGanttGraphicsView->viewport()->setFixedWidth(800 * 30);
228
229 splitter->addWidget(mLeftView);
230 splitter->addWidget(mGanttGraphicsView);
231
232 topLayout->addWidget(splitter);
233 topLayout->setStretchFactor(splitter, 100);
234
235 // Initially, show 15 days back and forth
236 // set start to even hours, i.e. to 12:AM 0 Min 0 Sec
237 const QDateTime horizonStart = QDateTime(QDateTime::currentDateTime().addDays(-15).date().startOfDay());
238 mGanttGrid->setStartDateTime(horizonStart);
239
240 connect(mLeftView, &QTreeView::customContextMenuRequested, this, &VisualFreeBusyWidget::showAttendeeStatusMenu);
241}
242
243VisualFreeBusyWidget::~VisualFreeBusyWidget()
244{
245}
246
247void VisualFreeBusyWidget::showAttendeeStatusMenu()
248{
249}
250
251void VisualFreeBusyWidget::slotCenterOnStart()
252{
253 auto grid = static_cast<KGantt::DateTimeGrid *>(mGanttGraphicsView->grid());
254 int daysTo = grid->startDateTime().daysTo(mDtStart);
255 mGanttGraphicsView->horizontalScrollBar()->setValue(daysTo * 800);
256}
257
258void VisualFreeBusyWidget::slotIntervalColorRectangleMoved(const QDateTime &start, const QDateTime &end)
259{
260 mDtStart = start;
261 mDtEnd = end;
262 Q_EMIT dateTimesChanged(start, end);
263}
264
265/*!
266 This slot is called when the user clicks the "Pick a date" button.
267*/
268void VisualFreeBusyWidget::slotPickDate()
269{
270}
271
272void VisualFreeBusyWidget::slotScaleChanged(int newScale)
273{
274 const QVariant var = mScaleCombo->itemData(newScale);
275 Q_ASSERT(var.isValid());
276
277 int value = var.toInt();
278 mGanttGrid->setScale((KGantt::DateTimeGrid::Scale)value);
279}
280
281void VisualFreeBusyWidget::slotUpdateIncidenceStartEnd(const QDateTime &dtFrom, const QDateTime &dtTo)
282{
283 mDtStart = dtFrom;
284 mDtEnd = dtTo;
285 QDateTime horizonStart = QDateTime(dtFrom.addDays(-15).date().startOfDay());
286
287 auto grid = static_cast<KGantt::DateTimeGrid *>(mGanttGraphicsView->grid());
289 slotCenterOnStart();
290 mGanttGrid->setStartDateTime(horizonStart);
291}
292
293void VisualFreeBusyWidget::slotZoomToTime()
294{
295#if 0
296 mGanttGraphicsView->zoomToFit();
297#else
298 qCDebug(INCIDENCEEDITOR_LOG) << "Disabled code, port to KDGantt2";
299#endif
300}
301
302void VisualFreeBusyWidget::splitterMoved()
303{
304}
305
306#include "moc_visualfreebusywidget.cpp"
This is a private proxy model, that wraps the free busy data exposed by the FreeBusyItemModel for use...
QDateTime startDateTime() const
void setStartDateTime(const QDateTime &dt)
void setScale(Scale s)
AbstractGrid * grid() const
Q_SCRIPTABLE Q_NOREPLY void start()
QString xi18nc(const char *context, const char *text, const TYPE &arg...)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString label(StandardShortcut id)
const QList< QKeySequence > & end()
void clicked(bool checked)
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const=0
QScrollBar * horizontalScrollBar() const const
void setValue(int)
void addStretch(int stretch)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
virtual void setSpacing(int spacing) override
void activated(int index)
QVariant itemData(int index, int role) const const
QDateTime currentDateTime()
qint64 daysTo(const QDateTime &other) const const
virtual QSize sizeHint() const const override
int column() const const
bool isValid() const const
const QAbstractItemModel * model() const const
QModelIndex parent() const const
int row() const const
Q_EMITQ_EMIT
QObject * parent() const const
T qobject_cast(QObject *object)
void splitterMoved(int pos, int index)
CustomContextMenu
Horizontal
ScrollBarAlwaysOff
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void customContextMenuRequested(const QPoint &pos)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:19:37 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.