2 * Copyright (C) 2010 Ixonos Plc.
4 * This file is part of fosdem-schedule.
6 * fosdem-schedule is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation, either version 2 of the License, or (at your option)
11 * fosdem-schedule is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * You should have received a copy of the GNU General Public License along with
17 * fosdem-schedule. If not, see <http://www.gnu.org/licenses/>.
20 #include "eventmodel.h"
26 const int RADIUS = 10;
27 const int SPACER = 10;
29 const double scaleFactor1 = 0.4;
30 const double scaleFactor2 = 0.8;
32 Delegate::Delegate(QTreeView *aParent)
33 : QItemDelegate(aParent)
42 QListIterator<ControlId> i(mControls.keys());
45 delete mControls[i.next()]->image();
49 void Delegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
55 QColor bkgrColor = Qt::cyan;
56 //QColor bkgrColor = QColor(0xAA,0xAA,0xAA);
57 QColor conflictColor = Qt::yellow;
59 QPen borderPen(bkgrColor.darker());
62 int aux = option.rect.height() - mControls[FavouriteControlOn]->drawPoint().y() - mControls[FavouriteControlOn]->image()->height();
64 QFont fontSmall = option.font;
65 fontSmall.setBold(false);
66 fontSmall.setPixelSize(aux*0.2);
67 QFontMetrics fmSmall(fontSmall);
69 QFont fontSmallB = fontSmall;
70 fontSmallB.setBold(true);
71 QFontMetrics fmSmallB(fontSmallB);
74 QFont fontBig = option.font;
75 fontBig.setBold(false);
76 fontBig.setPixelSize(aux*0.33);
77 QFontMetrics fmBig(fontBig);
79 QFont fontBigB = fontBig;
80 fontBigB.setBold(true);
81 QFontMetrics fmBigB(fontBigB);
83 //int spacer = (fmSmall.boundingRect("999").width() < SPACER) ? SPACER : fmSmall.boundingRect("999").width();
85 //Time conflicts are colored differently
86 if(static_cast<Event*>(index.internalPointer())->hasTimeConflict())
87 bkgrColor = conflictColor;
89 QLinearGradient itemGradient(option.rect.topLeft(), option.rect.bottomLeft());
90 itemGradient.setColorAt(0.0, Qt::white);
91 itemGradient.setColorAt(0.25, bkgrColor);
92 itemGradient.setColorAt(0.5, bkgrColor);
93 itemGradient.setColorAt(0.75, bkgrColor);
94 itemGradient.setColorAt(1.0, Qt::white);
99 endPath.moveTo(option.rect.topLeft());
100 endPath.lineTo(option.rect.bottomLeft()-QPoint(0, RADIUS));
101 endPath.arcTo(option.rect.left(), option.rect.bottom()-2*RADIUS, 2*RADIUS, 2*RADIUS, 180, 90);
102 endPath.lineTo(option.rect.bottomRight()-QPoint(RADIUS, 0));
103 endPath.arcTo(option.rect.right()-2*RADIUS, option.rect.bottom()-2*RADIUS, 2*RADIUS, 2*RADIUS, 270, 90);
104 endPath.lineTo(option.rect.topRight());
106 //painter->setBrush( bkgrColor );
107 painter->setBrush(itemGradient);
108 painter->setPen(borderPen);
109 painter->drawPath(endPath);
111 painter->setFont(option.font);
113 else // middle elements
115 //painter->setBrush( bkgrColor );
116 painter->setBrush(itemGradient);
117 painter->setPen(Qt::NoPen);
118 painter->drawRect(option.rect);
120 painter->setPen(borderPen);
122 painter->drawLine(option.rect.topLeft(), option.rect.bottomLeft());
123 painter->drawLine(option.rect.topRight(), option.rect.bottomRight());
125 painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
127 painter->setFont(option.font);
132 if(static_cast<Event*>(index.internalPointer())->isFavourite())
133 painter->drawImage(mControls[FavouriteControlOn]->drawPoint(option.rect),*mControls[FavouriteControlOn]->image());
135 painter->drawImage(mControls[FavouriteControlOff]->drawPoint(option.rect),*mControls[FavouriteControlOff]->image());
138 if(static_cast<Event*>(index.internalPointer())->hasAlarm())
139 painter->drawImage(mControls[AlarmControlOn]->drawPoint(option.rect),*mControls[AlarmControlOn]->image());
141 painter->drawImage(mControls[AlarmControlOff]->drawPoint(option.rect),*mControls[AlarmControlOff]->image());
144 painter->drawImage(mControls[MapControl]->drawPoint(option.rect),*mControls[MapControl]->image());
146 if(static_cast<Event*>(index.internalPointer())->hasTimeConflict())
147 painter->drawImage(mControls[WarningControl]->drawPoint(option.rect),*mControls[WarningControl]->image());
150 Event *event = static_cast<Event*>(index.internalPointer());
151 QPointF titlePointF(mControls[FavouriteControlOn]->drawPoint(option.rect));
152 titlePointF.setX(option.rect.x()+SPACER);
153 titlePointF.setY(titlePointF.y()+mControls[FavouriteControlOn]->image()->height());
154 QTime start = event->start().time();
155 painter->setFont(fontBig);
156 painter->drawText(titlePointF,start.toString("hh:mm") + "-" + start.addSecs(event->duration()).toString("hh:mm") + ", " + event->room());
158 titlePointF.setY(titlePointF.y()+fmBig.height()-fmBig.descent());
159 painter->setFont(fontBigB);
160 QString title = event->title();
161 if(fmBigB.boundingRect(title).width() > (option.rect.width()-2*SPACER)) // the title won't fit the screen
163 // chop words from the end
164 while( (fmBigB.boundingRect(title + "...").width() > (option.rect.width()-2*SPACER)) && !title.isEmpty())
167 // chop characters one-by-one from the end
168 while( (!title.at(title.length()-1).isSpace()) && !title.isEmpty())
175 painter->drawText(titlePointF,title);
177 titlePointF.setY(titlePointF.y()+fmSmall.height()-fmSmall.descent());
178 painter->setFont(fontSmall);
179 painter->drawText(titlePointF,"Presenter(s): " + event->persons().join(" and "));
181 titlePointF.setY(titlePointF.y()+fmSmall.height()-fmSmall.descent());
182 painter->drawText(titlePointF,"Track: " + Track::retrieveTrackName(event->trackId()));
184 else // doesn't have parent - time-groups' elements (top items)
186 QFont fontSmall = option.font;
187 fontSmall.setBold(true);
188 fontSmall.setPixelSize(option.rect.height()*scaleFactor1);
189 QFontMetrics fmSmall(fontSmall);
191 QFont fontBig = option.font;
192 fontBig.setBold(true);
193 fontBig.setPixelSize(option.rect.height()*scaleFactor2);
194 QFontMetrics fmBig(fontBig);
196 int spacer = (fmSmall.boundingRect("999").width() < SPACER) ? SPACER : fmSmall.boundingRect("999").width();
198 QLinearGradient titleGradient(option.rect.topLeft(), option.rect.topRight());
199 //titleGradient.setColorAt(0.0, Qt::white);
200 titleGradient.setColorAt(0.0, bkgrColor);
201 titleGradient.setColorAt(0.5, Qt::white);
202 titleGradient.setColorAt(1.0, bkgrColor);
204 QPainterPath titlePath;
205 if(isExpanded(index))
207 titlePath.moveTo(option.rect.bottomLeft());
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());
213 titlePath.closeSubpath();
217 titlePath.lineTo(option.rect.topLeft()+QPoint(0, RADIUS));
218 titlePath.arcTo(option.rect.left(), option.rect.top(), 2*RADIUS, 2*RADIUS, 180, -90);
219 titlePath.lineTo(option.rect.topRight()-QPoint(RADIUS, 0));
220 titlePath.arcTo(option.rect.right()-2*RADIUS, option.rect.top(), 2*RADIUS, 2*RADIUS, 90, -90);
221 titlePath.lineTo(option.rect.bottomRight()-QPoint(0, RADIUS));
222 titlePath.arcTo(option.rect.right()-2*RADIUS, option.rect.bottom()-2*RADIUS, 2*RADIUS, 2*RADIUS, 0, -90);
223 titlePath.lineTo(option.rect.bottomLeft()+QPoint(RADIUS, 0));
224 titlePath.arcTo(option.rect.left(), option.rect.bottom()-2*RADIUS, 2*RADIUS, 2*RADIUS, 270, -90);
225 titlePath.closeSubpath();
228 painter->setBrush(titleGradient);
229 painter->setPen(borderPen);
230 painter->drawPath(titlePath);
233 painter->setFont(fontSmall);
234 QImage *image = mControls[FavouriteControlOn]->image();
236 option.rect.topRight()
238 spacer + image->width(),
239 - option.rect.height()/2 + image->height()/2);
240 painter->drawImage(drawPoint,*image);
241 painter->drawText(drawPoint+QPoint(image->width()+2, image->height() - 2),
242 QString::number(numberOfFavourities(index)));
244 drawPoint.setX(drawPoint.x() - spacer - image->width());
245 painter->drawImage(drawPoint,*mControls[AlarmControlOn]->image());
246 painter->drawText(drawPoint+QPoint(image->width()+2, image->height() - 2),
247 QString::number(numberOfAlarms(index)));
250 QString numEvents = QString::number(index.model()->rowCount(index)).append("/");
251 drawPoint.setX(drawPoint.x() - spacer - fmSmall.boundingRect(numEvents).width());
252 drawPoint.setY(drawPoint.y()+image->height() - 2);
253 painter->drawText(drawPoint,numEvents);
255 QPointF titlePointF = QPoint(
256 option.rect.x()+SPACER,
257 option.rect.y()+option.rect.height()-fmBig.descent());
258 painter->setFont(fontBig);
260 painter->drawText(titlePointF,qVariantValue<QString>(index.data()));
263 //// HIGHLIGHTING SELECTED ITEM
264 //if (option.state & QStyle::State_Selected)
265 //painter->fillRect(option.rect, option.palette.highlight());
270 QSize Delegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
274 if (index.internalId() == 0) // time group
280 return QSize(100,100);
284 bool Delegate::hasParent( const QModelIndex &index ) const
286 if( index.parent().isValid() )
292 bool Delegate::isLast( const QModelIndex &index ) const
294 if(!hasParent(index))
295 return false; // what should be returned here?
297 if(index.row() >= (index.model()->rowCount(index.parent())-1))
303 bool Delegate::isExpanded( const QModelIndex &index ) const
308 return mViewPtr->isExpanded( index );
311 Delegate::ControlId Delegate::whichControlClicked(const QModelIndex &aIndex, const QPoint &aPoint) const
313 if(!hasParent(aIndex)) // time-group item (root item)
316 QListIterator<ControlId> i(mControls.keys());
319 ControlId id = i.next();
320 if(mControls[id]->drawRect(static_cast<QTreeView*>(parent())->visualRect(aIndex)).contains(aPoint))
322 if(id == WarningControl)
324 if(static_cast<Event*>(aIndex.internalPointer())->hasTimeConflict())
335 void Delegate::defineControls()
341 control = new Control(FavouriteControlOn,QString(":icons/favourite-onBig.png"));
342 p = QPoint(0,SPACER);
343 p.setX(p.x()-control->image()->width()-SPACER);
344 control->setDrawPoint(p);
345 mControls.insert(FavouriteControlOn,control);
347 control = new Control(FavouriteControlOff,QString(":icons/favourite-offBig.png"));
348 p = QPoint(0,SPACER);
349 p.setX(p.x()-control->image()->width()-SPACER);
350 control->setDrawPoint(p);
351 mControls.insert(FavouriteControlOff,control);
356 control = new Control(AlarmControlOn,QString(":icons/alarm-onBig.png"));
357 p = mControls[FavouriteControlOn]->drawPoint();
358 p.setX(p.x()-control->image()->width()-SPACER);
359 control->setDrawPoint(p);
360 mControls.insert(AlarmControlOn,control);
362 control = new Control(AlarmControlOff,QString(":icons/alarm-offBig.png"));
363 p = mControls[FavouriteControlOff]->drawPoint();
364 p.setX(p.x()-control->image()->width()-SPACER);
365 control->setDrawPoint(p);
366 mControls.insert(AlarmControlOff,control);
369 control = new Control(MapControl,QString(":icons/compassBig.png"));
370 p = mControls[AlarmControlOn]->drawPoint();
371 p.setX(p.x()-control->image()->width()-SPACER);
372 control->setDrawPoint(p);
373 mControls.insert(MapControl,control);
376 control = new Control(MapControl,QString(":icons/compassBig.png"));
377 p = mControls[FavouriteControlOn]->drawPoint();
378 p.setX(p.x()-control->image()->width()-SPACER);
379 control->setDrawPoint(p);
380 mControls.insert(MapControl,control);
384 control = new Control(WarningControl,QString(":icons/exclamation.png"));
385 p = mControls[MapControl]->drawPoint();
386 p.setX(p.x()-control->image()->width()-SPACER);
387 control->setDrawPoint(p);
388 mControls.insert(WarningControl,control);
391 bool Delegate::isPointFromRect(const QPoint &aPoint, const QRect &aRect) const
393 if( (aPoint.x()>=aRect.left() && aPoint.x()<=aRect.right()) && (aPoint.y()>=aRect.top() && aPoint.y()<=aRect.bottom()) )
399 int Delegate::numberOfFavourities(const QModelIndex &index) const
401 if(index.parent().isValid()) // it's event, not time-group
405 for(int i=0; i<index.model()->rowCount(index); i++)
406 if(static_cast<Event*>(index.child(i,0).internalPointer())->isFavourite())
412 int Delegate::numberOfAlarms(const QModelIndex &index) const
414 if(index.parent().isValid()) // it's event, not time-group
418 for(int i=0; i<index.model()->rowCount(index); i++)
419 if(static_cast<Event*>(index.child(i,0).internalPointer())->hasAlarm())