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