]> ToastFreeware Gitweb - toast/confclerk.git/blob - src/mvc/delegate.cpp
conflicts refactoring
[toast/confclerk.git] / src / mvc / delegate.cpp
1 #include "delegate.h"
2 #include "eventmodel.h"
3 #include <track.h>
4
5 #include <QDebug>
6 #include <QPainter>
7
8 const int RADIUS = 10;
9 const int SPACER = 10;
10
11 const double scaleFactor1 = 0.4;
12 const double scaleFactor2 = 0.8;
13
14 Delegate::Delegate(QTreeView *aParent)
15     : QItemDelegate(aParent)
16     , mViewPtr(aParent)
17 {
18     mControls.clear();
19     defineControls();
20 }
21
22 Delegate::~Delegate()
23 {
24     QListIterator<ControlId> i(mControls.keys());
25     while (i.hasNext())
26     {
27         delete mControls[i.next()]->image();
28     }
29 }
30
31 void Delegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
32 {
33     if(!mViewPtr)
34         return;
35
36     painter->save();
37     QColor bkgrColor = Qt::cyan;
38
39     QPen borderPen(bkgrColor.darker());
40     //QColor bkgrColor = QColor(0,0,113);
41     //QPen borderPen(Qt::cyan);
42     if(hasParent(index))
43     {
44         int aux = option.rect.height() - mControls[FavouriteControlOn]->drawPoint().y() - mControls[FavouriteControlOn]->image()->height();
45         // font SMALL
46         QFont fontSmall = option.font;
47         fontSmall.setBold(false);
48         fontSmall.setPixelSize(aux*0.2);
49         QFontMetrics fmSmall(fontSmall);
50         // font SMALL bold
51         QFont fontSmallB = fontSmall;
52         fontSmallB.setBold(true);
53         QFontMetrics fmSmallB(fontSmallB);
54
55         // font BIG
56         QFont fontBig = option.font;
57         fontBig.setBold(false);
58         fontBig.setPixelSize(aux*0.33);
59         QFontMetrics fmBig(fontBig);
60         // font BIG bold
61         QFont fontBigB = fontBig;
62         fontBigB.setBold(true);
63         QFontMetrics fmBigB(fontBigB);
64
65         //int spacer = (fmSmall.boundingRect("999").width() < SPACER) ? SPACER : fmSmall.boundingRect("999").width();
66
67         //Time conflicts are colored differently
68         if(hasTimeConflict(index, index.parent()))
69         {
70             bkgrColor = Qt::yellow;
71         }
72
73         if(isLast(index))
74         {
75             QLinearGradient lastGradient(option.rect.topLeft(), option.rect.bottomLeft());
76             lastGradient.setColorAt(0.0, Qt::white);
77             lastGradient.setColorAt(0.5, bkgrColor);
78             lastGradient.setColorAt(1.0, Qt::white);
79
80             QPainterPath endPath;
81             endPath.moveTo(option.rect.topLeft());
82             endPath.lineTo(option.rect.bottomLeft()-QPoint(0, RADIUS));
83             endPath.arcTo(option.rect.left(), option.rect.bottom()-2*RADIUS, 2*RADIUS, 2*RADIUS, 180, 90);
84             endPath.lineTo(option.rect.bottomRight()-QPoint(RADIUS, 0));
85             endPath.arcTo(option.rect.right()-2*RADIUS, option.rect.bottom()-2*RADIUS, 2*RADIUS, 2*RADIUS, 270, 90);
86             endPath.lineTo(option.rect.topRight());
87
88             painter->setBrush( bkgrColor );
89             //painter->setBrush(lastGradient);
90             painter->setPen(borderPen);
91             painter->drawPath(endPath);
92
93             painter->setFont(option.font);
94         }
95         else // middle elements
96         {
97             QLinearGradient middleGradient(option.rect.topLeft(), option.rect.bottomLeft());
98             middleGradient.setColorAt(0.0, Qt::white);
99             middleGradient.setColorAt(0.25, bkgrColor);
100             middleGradient.setColorAt(0.5, Qt::white);
101             middleGradient.setColorAt(0.75, bkgrColor);
102             middleGradient.setColorAt(1.0, Qt::white);
103
104             painter->setBrush( bkgrColor );
105             //painter->setBrush(middleGradient);
106             painter->setPen(Qt::NoPen);
107             painter->drawRect(option.rect);
108
109             painter->setPen(borderPen);
110             // vertical lines
111             painter->drawLine(option.rect.topLeft(), option.rect.bottomLeft());
112             painter->drawLine(option.rect.topRight(), option.rect.bottomRight());
113             // horizontal lines
114             painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
115
116             painter->setFont(option.font);
117         }
118
119         // draw Controls
120         // favourite
121         if(static_cast<Event*>(index.internalPointer())->isFavourite())
122             painter->drawImage(mControls[FavouriteControlOn]->drawPoint(option.rect),*mControls[FavouriteControlOn]->image());
123         else
124             painter->drawImage(mControls[FavouriteControlOff]->drawPoint(option.rect),*mControls[FavouriteControlOff]->image());
125 #ifdef MAEMO
126         // alarm
127         if(static_cast<Event*>(index.internalPointer())->hasAlarm())
128             painter->drawImage(mControls[AlarmControlOn]->drawPoint(option.rect),*mControls[AlarmControlOn]->image());
129         else
130             painter->drawImage(mControls[AlarmControlOff]->drawPoint(option.rect),*mControls[AlarmControlOff]->image());
131 #endif
132         // map
133         painter->drawImage(mControls[MapControl]->drawPoint(option.rect),*mControls[MapControl]->image());
134         // Time conflict
135         //if(static_cast<Event*>(index.internalPointer())->hasTimeConflict())
136
137         if(hasTimeConflict(index, index.parent()))
138             painter->drawImage(mControls[WarningControl]->drawPoint(option.rect),*mControls[WarningControl]->image());
139
140         // draw texts
141         Event *event = static_cast<Event*>(index.internalPointer());
142         QPointF titlePointF(mControls[FavouriteControlOn]->drawPoint(option.rect));
143         titlePointF.setX(option.rect.x()+SPACER);
144         titlePointF.setY(titlePointF.y()+mControls[FavouriteControlOn]->image()->height());
145         QTime start = event->start().time();
146         painter->setFont(fontBig);
147         painter->drawText(titlePointF,start.toString("hh:mm") + "-" + start.addSecs(event->duration()).toString("hh:mm") + ", " + event->room());
148         // title
149         titlePointF.setY(titlePointF.y()+fmBig.height()-fmBig.descent());
150         painter->setFont(fontBigB);
151         QString title = event->title();
152         if(fmBigB.boundingRect(title).width() > (option.rect.width()-2*SPACER)) // the title won't fit the screen
153         {
154             // chop words from the end
155             while( (fmBigB.boundingRect(title + "...").width() > (option.rect.width()-2*SPACER)) && !title.isEmpty())
156             {
157                 title.chop(1);
158                 // chop characters one-by-one from the end
159                 while( (!title.at(title.length()-1).isSpace()) && !title.isEmpty())
160                 {
161                     title.chop(1);
162                 }
163             }
164             title += "...";
165         }
166         painter->drawText(titlePointF,title);
167         // persons
168         titlePointF.setY(titlePointF.y()+fmSmall.height()-fmSmall.descent());
169         painter->setFont(fontSmall);
170         painter->drawText(titlePointF,"Presenter(s): " + event->persons().join(" and "));
171         // track
172         titlePointF.setY(titlePointF.y()+fmSmall.height()-fmSmall.descent());
173         painter->drawText(titlePointF,"Track: " + Track::retrieveTrackName(event->trackId()));
174     }
175     else // doesn't have parent - time-groups' elements (top items)
176     {
177         QFont fontSmall = option.font;
178         fontSmall.setBold(true);
179         fontSmall.setPixelSize(option.rect.height()*scaleFactor1);
180         QFontMetrics fmSmall(fontSmall);
181
182         QFont fontBig = option.font;
183         fontBig.setBold(true);
184         fontBig.setPixelSize(option.rect.height()*scaleFactor2);
185         QFontMetrics fmBig(fontBig);
186
187         int spacer = (fmSmall.boundingRect("999").width() < SPACER) ? SPACER : fmSmall.boundingRect("999").width();
188
189         QLinearGradient titleGradient(option.rect.topLeft(), option.rect.topRight());
190         //titleGradient.setColorAt(0.0, Qt::white);
191         titleGradient.setColorAt(0.0, bkgrColor);
192         titleGradient.setColorAt(0.5, Qt::white);
193         titleGradient.setColorAt(1.0, bkgrColor);
194
195         QPainterPath titlePath;
196         if(isExpanded(index))
197         {
198             titlePath.moveTo(option.rect.bottomLeft());
199             titlePath.lineTo(option.rect.topLeft()+QPoint(0, RADIUS));
200             titlePath.arcTo(option.rect.left(), option.rect.top(), 2*RADIUS, 2*RADIUS, 180, -90);
201             titlePath.lineTo(option.rect.topRight()-QPoint(RADIUS, 0));
202             titlePath.arcTo(option.rect.right()-2*RADIUS, option.rect.top(), 2*RADIUS, 2*RADIUS, 90, -90);
203             titlePath.lineTo(option.rect.bottomRight());
204             titlePath.closeSubpath();
205         }
206         else
207         {
208             titlePath.lineTo(option.rect.topLeft()+QPoint(0, RADIUS));
209             titlePath.arcTo(option.rect.left(), option.rect.top(), 2*RADIUS, 2*RADIUS, 180, -90);
210             titlePath.lineTo(option.rect.topRight()-QPoint(RADIUS, 0));
211             titlePath.arcTo(option.rect.right()-2*RADIUS, option.rect.top(), 2*RADIUS, 2*RADIUS, 90, -90);
212             titlePath.lineTo(option.rect.bottomRight()-QPoint(0, RADIUS));
213             titlePath.arcTo(option.rect.right()-2*RADIUS, option.rect.bottom()-2*RADIUS, 2*RADIUS, 2*RADIUS, 0, -90);
214             titlePath.lineTo(option.rect.bottomLeft()+QPoint(RADIUS, 0));
215             titlePath.arcTo(option.rect.left(), option.rect.bottom()-2*RADIUS, 2*RADIUS, 2*RADIUS, 270, -90);      
216             titlePath.closeSubpath();
217         }
218
219         painter->setBrush(titleGradient);
220         painter->setPen(borderPen);
221         painter->drawPath(titlePath);
222
223         // draw icons 
224         painter->setFont(fontSmall);
225         QPoint drawPoint =
226             option.rect.topRight()
227             - QPoint(
228                     spacer + mControls[FavouriteControlOn]->image()->width(),
229                     - option.rect.height()/2 + mControls[FavouriteControlOn]->image()->height()/2);
230         painter->drawImage(drawPoint,*mControls[FavouriteControlOn]->image());
231         painter->drawText(drawPoint+QPoint(mControls[FavouriteControlOn]->image()->width()+2, option.rect.height()/2),
232                 QString::number(numberOfFavourities(index)));
233 #ifdef MAEMO
234         drawPoint.setX(drawPoint.x() - spacer - mControls[FavouriteControlOn]->image()->width());
235         painter->drawImage(drawPoint,*mControls[AlarmControlOn]->image());
236         painter->drawText(drawPoint+QPoint(mControls[FavouriteControlOn]->image()->width()+2, option.rect.height()/2),
237                 QString::number(numberOfAlarms(index)));
238 #endif
239         // draw texts
240         QString numEvents = QString::number(index.model()->rowCount(index)).append("/");
241         drawPoint.setX(drawPoint.x() - spacer - fmSmall.boundingRect(numEvents).width());
242         drawPoint.setY(drawPoint.y() + option.rect.height()/2);
243         painter->drawText(drawPoint,numEvents);
244
245         QPointF titlePointF = QPoint(
246                 option.rect.x()+SPACER,
247                 option.rect.y()+option.rect.height()-fmBig.descent());
248         painter->setFont(fontBig);
249
250         painter->drawText(titlePointF,qVariantValue<QString>(index.data()));
251     }
252
253     //// HIGHLIGHTING SELECTED ITEM
254     //if (option.state & QStyle::State_Selected)
255         //painter->fillRect(option.rect, option.palette.highlight());
256
257     painter->restore();
258 }
259
260 QSize Delegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
261 {
262     Q_UNUSED(option)
263
264     if (index.internalId() == 0) // time group
265     {
266         return QSize(40,40);
267     }
268     else // event
269     {
270         return QSize(100,100);
271     }
272 }
273
274 bool Delegate::hasParent( const QModelIndex &index ) const
275 {
276     if( index.parent().isValid() )
277         return true;
278     else
279         return false;
280 }
281   
282 bool Delegate::isLast( const QModelIndex &index ) const
283 {
284     if(!hasParent(index))
285         return false; // what should be returned here?
286
287     if(index.row() >= (index.model()->rowCount(index.parent())-1))
288         return true;
289     else
290         return false;
291 }
292
293 bool Delegate::isExpanded( const QModelIndex &index ) const
294 {
295     if( !mViewPtr )
296         return false;
297     else
298         return mViewPtr->isExpanded( index );
299 }
300
301 Delegate::ControlId Delegate::whichControlClicked(const QModelIndex &aIndex, const QPoint &aPoint) const
302 {
303     if(!hasParent(aIndex)) // time-group item (root item)
304         return ControlNone;
305
306     QListIterator<ControlId> i(mControls.keys());
307     while (i.hasNext())
308     {
309         ControlId id = i.next();
310         if(mControls[id]->drawRect(static_cast<QTreeView*>(parent())->visualRect(aIndex)).contains(aPoint))
311         {
312             if(id == WarningControl)
313             {
314                 if(mControls[id]->hasConflict)
315                     return id;
316             }
317             else
318                 return id;
319         }
320     }
321
322     return ControlNone;
323 }
324
325 void Delegate::defineControls()
326 {
327     Control *control;
328     QPoint p(0,0);
329     // FAVOURITE ICONs
330     // on
331     control = new Control(FavouriteControlOn,QString(":icons/favourite-onBig.png"));
332     p = QPoint(0,SPACER);
333     p.setX(p.x()-control->image()->width()-SPACER);
334     control->setDrawPoint(p);
335     mControls.insert(FavouriteControlOn,control);
336     // off
337     control = new Control(FavouriteControlOff,QString(":icons/favourite-offBig.png"));
338     p = QPoint(0,SPACER);
339     p.setX(p.x()-control->image()->width()-SPACER);
340     control->setDrawPoint(p);
341     mControls.insert(FavouriteControlOff,control);
342
343 #ifdef MAEMO
344     // ALARM ICONs
345     // on
346     control = new Control(AlarmControlOn,QString(":icons/alarm-onBig.png"));
347     p = mControls[FavouriteControlOn]->drawPoint();
348     p.setX(p.x()-control->image()->width()-SPACER);
349     control->setDrawPoint(p);
350     mControls.insert(AlarmControlOn,control);
351     // off
352     control = new Control(AlarmControlOff,QString(":icons/alarm-offBig.png"));
353     p = mControls[FavouriteControlOff]->drawPoint();
354     p.setX(p.x()-control->image()->width()-SPACER);
355     control->setDrawPoint(p);
356     mControls.insert(AlarmControlOff,control);
357
358     // MAP ICON
359     control = new Control(MapControl,QString(":icons/compassBig.png"));
360     p = mControls[AlarmControlOn]->drawPoint();
361     p.setX(p.x()-control->image()->width()-SPACER);
362     control->setDrawPoint(p);
363     mControls.insert(MapControl,control);
364 #else
365     // MAP ICON
366     control = new Control(MapControl,QString(":icons/compassBig.png"));
367     p = mControls[FavouriteControlOn]->drawPoint();
368     p.setX(p.x()-control->image()->width()-SPACER);
369     control->setDrawPoint(p);
370     mControls.insert(MapControl,control);
371 #endif
372
373     // WARNING ICON
374     control = new Control(WarningControl,QString(":icons/exclamation.png"));
375     p = mControls[MapControl]->drawPoint();
376     control->hasConflict = false;
377     p.setX(p.x()-control->image()->width()-SPACER);
378     control->setDrawPoint(p);
379     mControls.insert(WarningControl,control);
380 }
381
382 bool Delegate::isPointFromRect(const QPoint &aPoint, const QRect &aRect) const
383 {
384     if( (aPoint.x()>=aRect.left() && aPoint.x()<=aRect.right()) && (aPoint.y()>=aRect.top() && aPoint.y()<=aRect.bottom()) )
385         return true;
386
387     return false;
388 }
389
390 int Delegate::numberOfFavourities(const QModelIndex &index) const
391 {
392     if(index.parent().isValid()) // it's event, not time-group
393         return 0;
394
395     int nrofFavs = 0;
396     for(int i=0; i<index.model()->rowCount(index); i++)
397         if(static_cast<Event*>(index.child(i,0).internalPointer())->isFavourite())
398             nrofFavs++;
399
400     return nrofFavs;
401 }
402
403 int Delegate::numberOfAlarms(const QModelIndex &index) const
404 {
405     if(index.parent().isValid()) // it's event, not time-group
406         return 0;
407
408     int nrofAlarms = 0;
409     for(int i=0; i<index.model()->rowCount(index); i++)
410         if(static_cast<Event*>(index.child(i,0).internalPointer())->hasAlarm())
411             nrofAlarms++;
412
413     return nrofAlarms;
414 }
415
416 bool Delegate::hasTimeConflict(const QModelIndex &index, const QModelIndex &parent) const
417 {
418     Event *event = static_cast<Event*>(index.internalPointer());
419     QTime start = event->start().time();
420     QTime end = start.addSecs(event->duration());
421     for(int i=0; i<parent.model()->rowCount(parent); i++)
422     {
423         if((event->id()!=static_cast<Event*>(parent.child(i,0).internalPointer())->id())
424         &&
425         (static_cast<Event*>(parent.child(i,0).internalPointer())->isFavourite()))
426         {
427             if (((start >= static_cast<Event*>(parent.child(i,0).internalPointer())->start().time())
428             &&
429             (start < static_cast<Event*>(parent.child(i,0).internalPointer())->start().time().addSecs(static_cast<Event*>(parent.child(i,0).internalPointer())->duration())))
430             ||
431             ((end > static_cast<Event*>(parent.child(i,0).internalPointer())->start().time())
432             &&
433             (end <= static_cast<Event*>(parent.child(i,0).internalPointer())->start().time().addSecs(static_cast<Event*>(parent.child(i,0).internalPointer())->duration()))))
434             {
435                 return true;
436             }
437         }
438     }
439     return false;
440 }
441