1 #include "weightgraphview.h"
7 #include <QtGui/QX11Info>
11 WeightGraphView::WeightGraphView(WeightDataModel *wdm,
12 const QString &id, QWidget *parent) :
13 QWidget(parent), id(id), wdm(wdm),
14 period(Settings::graphSettings(id).defaultTimeInterval)
16 setWindowTitle("WeightGraph");
18 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
20 connect(wdm, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
21 this, SLOT(update()));
22 connect(wdm, SIGNAL(rowsInserted(const QModelIndex&,int,int)),
23 this, SLOT(update()));
24 connect(wdm, SIGNAL(rowsRemoved(const QModelIndex&,int,int)),
25 this, SLOT(update()));
26 connect(Settings::self(), SIGNAL(settingChanged()),
27 this, SLOT(update()));
30 void WeightGraphView::mousePressEvent(QMouseEvent *)
35 QSize WeightGraphView::sizeHint() const
37 return QSize(300, 400);
40 void WeightGraphView::keyPressEvent(QKeyEvent* event)
42 //qDebug() << "Key pressed: " << event->key();
43 switch (event->key()) {
54 QWidget::keyPressEvent(event);
57 // Macros to transform dates and weights to paintdevice coords
58 #define D_X(d) ((d)*qreal(width())/days)
59 #define DW_X(dw) D_X(f.daysTo((dw).date))
60 #define W_Y(w) (height()*(maxW-(w))/weightInterval)
61 #define DW_Y(dw) W_Y((dw).weight)
62 #define DW_POINT(dw) QPointF(DW_X(dw), DW_Y(dw))
64 inline double weightIntervalToMult(double wi)
66 if (wi <= 0.2) return 0.01;
67 else if (wi <= 0.5) return 0.025;
68 else if (wi <= 1.0) return 0.05;
69 else if (wi <= 2.0) return 0.1;
70 else if (wi <= 5.0) return 0.25;
71 else if (wi <= 10.0) return 0.5;
72 else if (wi <= 20.0) return 1.0;
73 else if (wi <= 50.0) return 2.5;
74 else if (wi <= 100.0) return 5.0;
75 else if (wi <= 200.0) return 10.0;
76 else if (wi <= 500.0) return 25.0;
77 else if (wi <= 1000.0) return 50.0;
81 void WeightGraphView::paintEvent(QPaintEvent *)
83 QPainter painter(this);
84 painter.setRenderHint(QPainter::Antialiasing);
86 GraphSettings gs = Settings::graphSettings(id);
87 const QList<DW> &allWeights = wdm->getWeights();
91 const DW *beforeFirst = NULL;
92 if (allWeights.size() < 2) {
97 bool firstFound = false;
100 const QDate &l = allWeights.last().date;
101 for(int i=0; i < allWeights.size(); i++) {
102 if (period == 0 || firstFound || allWeights[i].date.daysTo(l) <= period) {
103 weights.append(allWeights[i]);
104 if (allWeights[i].weight < min)
105 min = allWeights[i].weight;
106 if (allWeights[i].weight > max)
107 max = allWeights[i].weight;
111 beforeFirst = &allWeights[i];
115 if (gs.weightIntervalMode == GraphSettings::AutomaticWithGoalWeight
116 && gs.goalWeightEnabled) {
117 min = qMin(min, Settings::goalWeightMin());
118 max = qMax(max, Settings::goalWeightMax());
120 else if(gs.weightIntervalMode == GraphSettings::Manual) {
121 if (gs.weightIntervalMax > gs.weightIntervalMin) {
122 min = gs.weightIntervalMin;
123 max = gs.weightIntervalMax;
126 // else default is min and max of actual data
128 double margin = (max - min)*0.03;
129 double minW = min - margin;
130 double maxW = max + margin;
131 double weightInterval = maxW-minW;
132 if (maxW-minW < 0.1) {
135 weightInterval = maxW - minW;
139 if (weights.size() < 2) {
140 l = QDate::currentDate();
144 else if (period==0) {
145 f = weights.first().date;
146 l = weights.last().date;
149 l = weights.last().date;
150 f = l.addDays(-period);
154 // Interpolate to fill gap in left part of the graph
155 if (weights.first().date != f && beforeFirst != NULL) {
158 dw.weight = (weights.first().weight - beforeFirst->weight)
159 /beforeFirst->date.daysTo(weights.first().date)
160 *beforeFirst->date.daysTo(f)
161 +beforeFirst->weight;
165 painter.setWindow(-50, 0, width()+85, height()+25);
167 if (gs.goalWeightEnabled
168 && ((Settings::goalWeightMin() > minW && Settings::goalWeightMin() < maxW)
169 ||(Settings::goalWeightMax() > minW && Settings::goalWeightMax() < maxW))) {
170 QPen oldPen = painter.pen();
171 QBrush oldBrush = painter.brush();
172 painter.setPen(Qt::NoPen);
173 painter.setBrush(QColor(0,255,0,100));
174 painter.setClipRect(QRectF(0,0,width(),height()));
175 painter.drawRect(QRectF(QPointF(0, W_Y(Settings::goalWeightMax())),
176 QPointF(width(), W_Y(Settings::goalWeightMin()))));
177 painter.setClipping(false);
178 painter.setPen(oldPen);
179 painter.setBrush(oldBrush);
183 QFont font = painter.font();
184 font.setPixelSize(16);
185 painter.setFont(font);
186 painter.drawLine(QPointF(0.0,0.0), QPointF(0,height()));
187 double mult = weightIntervalToMult(weightInterval);
189 for(double w=ceil(minW/mult)*mult; w < maxW; w += mult, count++) {
190 double len = count%5==0 ? 7.0 : 4.0;
191 painter.drawLine(QPointF(-len,W_Y(w)),QPointF(len,W_Y(w)));
193 QPen p = painter.pen();
194 painter.setPen(QColor(50,50,50));
195 painter.drawLine(QPointF(len,W_Y(w)),QPointF(width(),W_Y(w)));
197 QString text = tr("%1").arg(double(w),0,'f', mult <= 0.25 ? 2 : 1);
198 QSize textSize = painter.fontMetrics().size(0, text);
199 painter.drawText(QPointF(-len-3-textSize.width(), W_Y(w)+6), text);
204 font.setPixelSize(13);
205 painter.setFont(font);
206 double endOfLastDate = -1e6;
208 painter.drawLine(QPointF(0.0,height()), QPointF(width(),height()));
209 for(int day=0; day <= days; day+=mult) {
210 QString text = f.addDays(day).toString(Qt::ISODate);
211 QSize textSize = painter.fontMetrics().size(0, text);
213 if (D_X(day)-textSize.width()/2 > endOfLastDate + 10) {
215 painter.drawText(QPointF(D_X(day)-textSize.width()/2,
216 W_Y(minW)+18), text);
217 endOfLastDate = D_X(day)+textSize.width()/2;
221 painter.drawLine(QPointF(D_X(day), W_Y(minW)-tickLen),
222 QPointF(D_X(day), W_Y(minW)+tickLen));
226 QPolygonF linepoints;
227 foreach(DW dw, weights) {
228 linepoints << DW_POINT(dw);
230 painter.drawPolyline(linepoints);
233 void WeightGraphView::show()
236 grabZoomKeys(Settings::grabZoomKeys()); //Need to be regrabbed somewhy
237 //Work around a bug: hidden graphs don't update. Must wait for the
238 //graph to actually show up, then call update.
239 QTimer *tmp = new QTimer(this);
240 tmp->setSingleShot(true);
241 tmp->setInterval(500);
242 connect(tmp, SIGNAL(timeout()), this, SLOT(update()));
246 void WeightGraphView::grabZoomKeys(bool grab)
249 qWarning("Can't grab keys unless we have a window id");
253 unsigned long val = (grab) ? 1 : 0;
254 Atom atom = XInternAtom(QX11Info::display(), "_HILDON_ZOOM_KEY_ATOM", False);
256 qWarning("Unable to obtain _HILDON_ZOOM_KEY_ATOM. This example will only work "
257 "on a Maemo 5 device!");
262 XChangeProperty (QX11Info::display(),
268 reinterpret_cast<unsigned char *>(&val),
271 //qDebug() << "Grabbed for winId " << winId();