1 /*
2 SPDX-FileCopyrightText: 2007 Joris Guisson <joris.guisson@gmail.com>
3 SPDX-FileCopyrightText: 2007 Ivan Vasic <ivasic@gmail.com>
4 SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "weekscene.h"
8
9 #include <cmath>
10
11 #include <KFormat>
12 #include <KLocalizedString>
13
14 #include <QFontMetricsF>
15 #include <QGraphicsLineItem>
16 #include <QGraphicsRectItem>
17 #include <QGraphicsSceneMouseEvent>
18 #include <QGraphicsTextItem>
19 #include <QPalette>
20
21 #include "bwschedulerpluginsettings.h"
22 #include "guidanceline.h"
23 #include "schedule.h"
24 #include "schedulegraphicsitem.h"
25 #include <util/functions.h>
26 #include <util/log.h>
27
28 using namespace bt;
29
30 namespace kt
31 {
WeekScene(QObject * parent)32 WeekScene::WeekScene(QObject *parent)
33 : QGraphicsScene(parent)
34 , schedule(nullptr)
35 {
36 addCalendar();
37 }
38
~WeekScene()39 WeekScene::~WeekScene()
40 {
41 }
42
LongestDayWidth(const QFontMetricsF & fm)43 qreal LongestDayWidth(const QFontMetricsF &fm)
44 {
45 qreal wd = 0;
46 for (int i = 1; i <= 7; i++) {
47 qreal w = fm.width(QLocale::system().dayName(i));
48 if (w > wd)
49 wd = w;
50 }
51 return wd;
52 }
53
updateStatusText(int up,int down,bool suspended,bool enabled)54 void WeekScene::updateStatusText(int up, int down, bool suspended, bool enabled)
55 {
56 static KFormat format;
57 QString msg;
58 if (suspended)
59 msg = i18n("Current schedule: suspended");
60 else if (up > 0 && down > 0)
61 msg = i18n("Current schedule: %1/s download, %2/s upload", format.formatByteSize(down * 1024), format.formatByteSize(up * 1024));
62 else if (up > 0)
63 msg = i18n("Current schedule: unlimited download, %1/s upload", format.formatByteSize(up * 1024));
64 else if (down > 0)
65 msg = i18n("Current schedule: %1/s download, unlimited upload", format.formatByteSize(down * 1024));
66 else
67 msg = i18n("Current schedule: unlimited upload and download");
68
69 if (!enabled)
70 msg += i18n(" (scheduler disabled)");
71
72 status->setPlainText(msg);
73 }
74
addCalendar()75 void WeekScene::addCalendar()
76 {
77 QGraphicsTextItem *tmp = addText(QStringLiteral("Dinges"));
78 QFontMetricsF fm(tmp->font());
79 removeItem(tmp);
80 delete tmp;
81
82 // first add 7 rectangles for each day of the week
83 xoff = fm.width(QStringLiteral("00:00")) + 10;
84 yoff = 2 * fm.height() + 10;
85 day_width = LongestDayWidth(fm) * 1.5;
86 hour_height = fm.height() * 1.5;
87
88 status = addText(i18n("Current schedule:"));
89 status->setPos(QPointF(0, 0));
90 status->setZValue(2);
91
92 QPen pen(SchedulerPluginSettings::scheduleLineColor());
93 QBrush brush(SchedulerPluginSettings::scheduleBackgroundColor());
94
95 for (int i = 0; i < 7; i++) {
96 QGraphicsRectItem *item = addRect(xoff + day_width * i, yoff, day_width, 24 * hour_height, pen, brush);
97 item->setZValue(1);
98
99 QString day = QLocale::system().dayName(i + 1);
100
101 // make sure day is centered in the middle of the column
102 qreal dlen = fm.width(day);
103 qreal mid = xoff + day_width * (i + 0.5);
104 qreal start = mid - dlen * 0.5;
105
106 QGraphicsTextItem *t = addText(day);
107 t->setPos(QPointF(start, fm.height() + 5));
108 t->setZValue(2);
109
110 rects.append(item);
111 }
112
113 // draw hour lines
114 for (int i = 0; i <= 24; i++) {
115 QGraphicsLineItem *item = addLine(0, yoff + i * hour_height, xoff + 7 * day_width, yoff + i * hour_height, pen);
116 item->setZValue(2);
117
118 if (i < 24) {
119 QGraphicsTextItem *t = addText(QStringLiteral("%1:00").arg(i));
120 t->setPos(QPointF(0, yoff + i * hour_height));
121 t->setZValue(2);
122 }
123 lines.append(item);
124 }
125
126 ;
127 gline[0] = new GuidanceLine(xoff, yoff, xoff + 7 * day_width + 10);
128 gline[0]->setVisible(false);
129 gline[1] = new GuidanceLine(xoff, yoff, xoff + 7 * day_width + 10);
130 gline[1]->setVisible(false);
131 addItem(gline[0]);
132 addItem(gline[1]);
133
134 QRectF r = sceneRect();
135 r.setHeight(r.height() + 10);
136 setSceneRect(r);
137 }
138
addScheduleItem(ScheduleItem * item)139 QGraphicsItem *WeekScene::addScheduleItem(ScheduleItem *item)
140 {
141 QTime midnight(0, 0, 0, 0);
142 qreal x = xoff + (item->start_day - 1) * day_width;
143 // qreal min_h = hour_height / 60.0;
144 qreal y = timeToY(item->start);
145 qreal ye = timeToY(item->end);
146
147 QRectF rect(x, y, day_width * (item->end_day - item->start_day + 1), ye - y);
148 QRectF cst(xoff, yoff, 7 * day_width, 24 * hour_height);
149 ScheduleGraphicsItem *gi = new ScheduleGraphicsItem(item, rect, cst, this);
150 addItem(gi);
151 gi->update(rect);
152 return gi;
153 }
154
mouseDoubleClickEvent(QGraphicsSceneMouseEvent * ev)155 void WeekScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *ev)
156 {
157 const QList<QGraphicsItem *> gis = items(ev->scenePos());
158 for (QGraphicsItem *gi : gis) {
159 if (gi->zValue() == 3) {
160 itemDoubleClicked(gi);
161 break;
162 }
163 }
164 }
165
mousePressEvent(QGraphicsSceneMouseEvent * ev)166 void WeekScene::mousePressEvent(QGraphicsSceneMouseEvent *ev)
167 {
168 if (ev->button() == Qt::RightButton) {
169 const QList<QGraphicsItem *> gis = items(ev->scenePos());
170 for (QGraphicsItem *gi : gis) {
171 if (gi->zValue() == 3) {
172 clearSelection();
173 gi->setSelected(true);
174 break;
175 }
176 }
177 } else
178 QGraphicsScene::mousePressEvent(ev);
179 }
180
timeToY(const QTime & time)181 qreal WeekScene::timeToY(const QTime &time)
182 {
183 QTime midnight(0, 0, 0, 0);
184 qreal min_h = hour_height / 60.0;
185 return (midnight.secsTo(time) / 60.0) * min_h + yoff;
186 }
187
yToTime(qreal y)188 QTime WeekScene::yToTime(qreal y)
189 {
190 y = y - yoff; // get rid of offset
191 qreal min_h = hour_height / 60.0;
192 return QTime(0, 0, 0, 0).addSecs((y / min_h) * 60);
193 }
194
itemMoved(ScheduleItem * item,const QPointF & np)195 void WeekScene::itemMoved(ScheduleItem *item, const QPointF &np)
196 {
197 QTime start = yToTime(np.y());
198 int d = item->start.secsTo(item->end); // duration in seconds
199 QTime end = start.addSecs(d);
200
201 int start_day = 1 + floor((np.x() + day_width * 0.5 - xoff) / day_width);
202 if (start_day < 1)
203 start_day = 1;
204 else if (start_day > 7)
205 start_day = 7;
206
207 int end_day = start_day + (item->end_day - item->start_day);
208 if (end_day < 1)
209 end_day = 1;
210 else if (end_day > 7)
211 end_day = 7;
212 itemMoved(item, start, end, start_day, end_day);
213 }
214
validMove(ScheduleItem * item,const QPointF & np)215 bool WeekScene::validMove(ScheduleItem *item, const QPointF &np)
216 {
217 if (!schedule)
218 return true;
219
220 QTime start = yToTime(np.y());
221 int d = item->start.secsTo(item->end); // duration in seconds
222 QTime end = start.addSecs(d);
223
224 int start_day = 1 + floor((np.x() + day_width * 0.5 - xoff) / day_width);
225 int end_day = start_day + (item->end_day - item->start_day);
226 if (end_day > 7)
227 end_day = 7;
228 return schedule->validModify(item, start, end, start_day, end_day);
229 }
230
itemResized(ScheduleItem * item,const QRectF & r)231 void WeekScene::itemResized(ScheduleItem *item, const QRectF &r)
232 {
233 QTime start = yToTime(r.y());
234 QTime end = yToTime(r.y() + r.height());
235
236 int start_day = 1 + floor((r.x() + day_width * 0.5 - xoff) / day_width);
237 int end_day = 1 + floor((r.x() + r.width() - day_width * 0.5 - xoff) / day_width);
238 if (start_day < 1)
239 start_day = 1;
240 else if (start_day > 7)
241 start_day = 7;
242
243 if (end_day < 1)
244 end_day = 1;
245 else if (end_day > 7)
246 end_day = 7;
247
248 itemMoved(item, start, end, start_day, end_day);
249 }
250
validResize(ScheduleItem * item,const QRectF & r)251 bool WeekScene::validResize(ScheduleItem *item, const QRectF &r)
252 {
253 QTime start = yToTime(r.y());
254 QTime end = yToTime(r.y() + r.height());
255 return schedule->validModify(item, start, end, item->start_day, item->end_day);
256 }
257
itemChanged(ScheduleItem * item,QGraphicsItem * gi)258 void WeekScene::itemChanged(ScheduleItem *item, QGraphicsItem *gi)
259 {
260 ScheduleGraphicsItem *sgi = (ScheduleGraphicsItem *)gi;
261 qreal x = xoff + (item->start_day - 1) * day_width;
262 qreal y = timeToY(item->start);
263 qreal ye = timeToY(item->end);
264 sgi->update(QRectF(x, y, day_width * (item->end_day - item->start_day + 1), ye - y));
265 }
266
colorsChanged()267 void WeekScene::colorsChanged()
268 {
269 QPen pen(SchedulerPluginSettings::scheduleLineColor());
270 QBrush brush(SchedulerPluginSettings::scheduleBackgroundColor());
271
272 for (QGraphicsLineItem *line : qAsConst(lines))
273 line->setPen(pen);
274
275 for (QGraphicsRectItem *rect : qAsConst(rects)) {
276 rect->setPen(pen);
277 rect->setBrush(brush);
278 }
279
280 pen.setStyle(Qt::DashLine);
281 gline[0]->setPen(pen);
282 gline[1]->setPen(pen);
283 }
284
setShowGuidanceLines(bool on)285 void WeekScene::setShowGuidanceLines(bool on)
286 {
287 gline[0]->setVisible(on);
288 gline[1]->setVisible(on);
289 }
290
updateGuidanceLines(qreal y1,qreal y2)291 void WeekScene::updateGuidanceLines(qreal y1, qreal y2)
292 {
293 const QString FORMAT = QStringLiteral("hh:mm");
294 gline[0]->update(xoff, y1, yToTime(y1).toString(FORMAT));
295 gline[1]->update(xoff, y2, yToTime(y2).toString(FORMAT));
296 }
297 }
298