Added FriendListView methods to ListView.
[situare] / src / ui / friendlistitem.cpp
1 /*
2    Situare - A location system for Facebook
3    Copyright (C) 2010  Ixonos Plc. Authors:
4
5        Jussi Laitinen - jussi.laitinen@ixonos.com
6
7    Situare is free software; you can redistribute it and/or
8    modify it under the terms of the GNU General Public License
9    version 2 as published by the Free Software Foundation.
10
11    Situare is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with Situare; if not, write to the Free Software
18    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
19    USA.
20 */
21
22 #include <QVBoxLayout>
23 #include <QPushButton>
24 #include <QPainter>
25 #include <QDebug>
26 #include <QPaintEvent>
27 #include <QLabel>
28 #include <QPixmap>
29 #include <QFormLayout>
30 #include <QSpacerItem>
31 #include <QStylePainter>
32 #include <math.h>
33
34 #include "friendlistitem.h"
35 #include "../user/user.h"
36 #include "imagebutton.h"
37 #include "../common.h"
38
39 const int ITEM_WIDTH = 368;
40 const int ICON_HEIGHT = 24;     ///< Icon height
41 const int ICON_WIDTH = 24;       ///< Icon width
42 const int IMAGE_HEIGHT = 64; ///< Friend image height
43 const int IMAGE_WIDTH = 64;  ///< Friend image width
44 const int ITEM_MIN_HEIGHT = 141; ///< Minimum height for item
45 const int MARGIN = 5;   ///< Icon margin
46 const int MOUSE_PRESS_AREA_WIDTH = 20;  ///< Area width for item height toggling
47 const int MOUSE_PRESS_AREA_HEIGHT = 20; ///< Area height for item height toggling
48
49 /**
50 * @var NAME_LABEL_MAX_WIDTH
51 *
52 * @brief Name label's maximum width
53 */
54 const int NAME_LABEL_MAX_WIDTH = ITEM_WIDTH - 3*MARGIN - IMAGE_WIDTH;
55
56 /**
57 * @var LABEL_MAX_WIDTH
58 *
59 * @brief All label's maximum width
60 */
61 const int LABEL_MAX_WIDTH = ITEM_WIDTH - 3 * MARGIN - IMAGE_WIDTH - MARGIN - ICON_WIDTH - MARGIN;
62
63 const int WALK_DISTANCE = 5;        ///< Walk distance limit for distance icon
64 const int CAR_DISTANCE = 500;       ///< Car distance limit for distance icon
65 const int AEROPLANE_DISTANCE = 5000;///< Aeroplane distance limit for distance icon
66
67 FriendListItem::FriendListItem()
68     : m_expanded(false)
69     , m_user(0)
70 {
71     qDebug() << __PRETTY_FUNCTION__;
72
73     setData(Qt::SizeHintRole, QSize(ITEM_WIDTH, ITEM_MIN_HEIGHT));
74
75 //    m_distanceTextLabel = new QLabel();
76 //    m_distanceTextLabel->setFixedHeight(ICON_HEIGHT);
77
78 //    m_distanceImageLabel = new QLabel();
79 //    m_distanceImageLabel->setFixedSize(ICON_WIDTH, ICON_HEIGHT);
80
81 //    m_findButton = new ImageButton(this);
82
83 //    m_updatedLabel = new QLabel();
84 //    m_updatedLabel->setWordWrap(true);
85 //    m_statusTextLabel = new QLabel();
86 //    m_statusTextLabel->setWordWrap(true);
87 //    m_locationLabel = new QLabel();
88 //    m_locationLabel->setWordWrap(true);
89
90 //    distanceLayout->addWidget(m_distanceImageLabel, 0, Qt::AlignRight);
91 //    distanceLayout->addWidget(m_distanceTextLabel, 0, Qt::AlignRight);
92
93 //    infoLayout->addRow(envelopeLabel, m_statusTextLabel);
94 //    infoLayout->addRow(compassLabel, m_locationLabel);
95 //    infoLayout->addRow(clockLabel, m_updatedLabel);
96
97 //    topLayout->addWidget(m_findButton);
98 //    topLayout->addWidget(m_nameLabel, 1);
99 //    topLayout->addLayout(distanceLayout);
100
101 //    bottomLayout->addSpacing(IMAGE_WIDTH);
102 //    bottomLayout->addLayout(infoLayout);
103
104 //    layout->addLayout(topLayout, 0);
105 //    layout->addLayout(bottomLayout, 1);
106
107 //    setMinimumSize(ITEM_WIDTH, ITEM_MIN_HEIGHT);
108 //    setMaximumWidth(ITEM_WIDTH);
109
110 //    setFont(NOKIA_FONT_SMALL);
111 //    m_nameLabel->setFont(NOKIA_FONT_NORMAL);
112 //    QPalette itemPalette = palette();
113 //    itemPalette.setColor(QPalette::Foreground, COLOR_GRAY);
114 //    setPalette(itemPalette);
115 //    QPalette namePalette = m_nameLabel->palette();
116 //    namePalette.setColor(QPalette::Foreground, Qt::white);
117 //    m_nameLabel->setPalette(namePalette);
118
119 //    m_backgroundTopImage.load(":/res/images/list_item_top.png");
120 //    m_backgroundMiddleImage.load(":/res/images/list_item_middle.png");
121 //    m_backgroundBottomImage.load(":/res/images/list_item_bottom.png");
122
123 //    connect(m_findButton, SIGNAL(clicked()),
124 //        this, SLOT(findButtonClicked()));
125 }
126
127 void FriendListItem::calculateTextRects()
128 {
129     QFontMetrics otherLabelsMetrics = QFontMetrics(NOKIA_FONT_SMALL);
130
131     QRect statusTextRect = otherLabelsMetrics.boundingRect(QRect(0, 0, LABEL_MAX_WIDTH,
132                                                                              1000), Qt::AlignLeft,
133                                                                        m_user->note());
134     QRect updatedRect = otherLabelsMetrics.boundingRect(QRect(0, 0, LABEL_MAX_WIDTH,
135                                                                              1000), Qt::AlignLeft,
136                                                                        m_user->timestamp());
137     QRect locationRect = otherLabelsMetrics.boundingRect(QRect(0, 0, LABEL_MAX_WIDTH,
138                                                                              1000), Qt::AlignLeft,
139                                                                        m_user->address());
140
141
142     qDebug() << m_shortenedStatusText;
143
144     int statusTextFactor = statusTextRect.width() / LABEL_MAX_WIDTH;
145     statusTextFactor++;
146     m_statusTextRect = QRect(0, 0, LABEL_MAX_WIDTH, 24 * statusTextFactor);
147     int updatedFactor = updatedRect.width() / LABEL_MAX_WIDTH;
148     updatedFactor++;
149     m_updatedRect = QRect(0, 0, LABEL_MAX_WIDTH, 24 * updatedFactor);
150     int locationFactor = locationRect.width() / LABEL_MAX_WIDTH;
151     locationFactor++;
152     m_locationRect = QRect(0, 0, LABEL_MAX_WIDTH, 24 * locationFactor);
153
154     qDebug() << statusTextRect;
155     qDebug() << updatedRect;
156     qDebug() << locationRect;
157
158     qDebug() << m_statusTextRect;
159     qDebug() << m_updatedRect;
160     qDebug() << m_locationRect;
161
162     m_expandedHeight = ITEM_MIN_HEIGHT + ((statusTextFactor + updatedFactor + locationFactor - 3)*ICON_HEIGHT);
163 }
164
165 void FriendListItem::setId(const QString &id)
166 {
167     qDebug() << __PRETTY_FUNCTION__;
168 }
169
170 QString FriendListItem::id() const
171 {
172     return m_user->userId();
173 }
174
175 void FriendListItem::setUserData(User *user)
176 {
177     qDebug() << __PRETTY_FUNCTION__;
178
179     if(user) {
180         m_user = user;
181
182         if (!m_user->profileImage().isNull())
183             setData(Qt::DecorationRole, m_user->profileImage());
184
185         QString unit;
186         double value;
187         m_user->distance(value, unit);
188         m_distanceText = QString::number(value) + " " + unit;
189         setData(Qt::UserRole + 3, m_distanceText);
190         setDistanceIcon(value, unit);
191
192         shortenTexts();
193         calculateTextRects();
194         setText(false);
195     }
196 }
197
198 void FriendListItem::setDistanceIcon(double value, const QString &unit)
199 {
200     QPixmap distanceImage;
201
202     if ((unit == "m") || (value < WALK_DISTANCE))
203         distanceImage.load(":/res/images/walk_icon_gray.png");
204     else if (value < CAR_DISTANCE)
205         distanceImage.load(":/res/images/car_icon_gray.png");
206     else if (value < AEROPLANE_DISTANCE)
207         distanceImage.load(":/res/images/aeroplane_icon_gray.png");
208     else
209         distanceImage.load(":/res/images/rocket_icon_gray.png");
210
211     qDebug() << __PRETTY_FUNCTION__ << distanceImage.isNull();
212
213     setData(Qt::UserRole + 4, distanceImage);
214 }
215
216 void FriendListItem::shortenTexts()
217 {
218     qDebug() << __PRETTY_FUNCTION__;
219
220     QFontMetrics nameLabelMetrics = QFontMetrics(NOKIA_FONT_NORMAL);
221     QFontMetrics otherLabelsMetrics = QFontMetrics(NOKIA_FONT_SMALL);
222
223     QString name = m_user->name();
224     QString updated = m_user->timestamp();
225     QString statusText = m_user->note();
226     QString location = m_user->address();
227
228     int nameIndex = name.indexOf('\n');
229     int updatedIndex = updated.indexOf('\n');
230     int statusTextIndex = statusText.indexOf('\n');
231     int locationIndex = location.indexOf('\n');
232
233     if (nameIndex > 0) {
234         name.truncate(nameIndex);
235         name.append("...");
236     }
237     if (updatedIndex > 0) {
238         updated.truncate(updatedIndex);
239         updated.append("...");
240     }
241     if (statusTextIndex > 0) {
242         statusText.truncate(statusTextIndex);
243         statusText.append("...");
244     }
245     if (locationIndex > 0) {
246         location.truncate(locationIndex);
247         location.append("...");
248     }
249
250     int distanceLabelWidth = otherLabelsMetrics.width(m_distanceText) + 24;
251     m_shortenedName = nameLabelMetrics.elidedText(name, Qt::ElideRight, NAME_LABEL_MAX_WIDTH
252                                                   - distanceLabelWidth);
253     m_shortenedStatusText = otherLabelsMetrics.elidedText(statusText, Qt::ElideRight,
254                                                           LABEL_MAX_WIDTH - 70);
255     m_shortenedUpdated = otherLabelsMetrics.elidedText(updated, Qt::ElideRight, LABEL_MAX_WIDTH - 70);
256     m_shortenedLocation = otherLabelsMetrics.elidedText(location, Qt::ElideRight, LABEL_MAX_WIDTH - 70);
257
258     setData(Qt::SizeHintRole + 4, QRect(0, 0, distanceLabelWidth, 24));
259 }
260
261 QString FriendListItem::elideText(int width, const QString &text)
262 {
263     QFontMetrics otherLabelsMetrics = QFontMetrics(NOKIA_FONT_SMALL);
264     int widthSum = 0;
265     QString t = text;
266
267     for (int i = 0; i < text.size(); ++i) {
268         QChar c = text.at(i);
269
270         widthSum += otherLabelsMetrics.width(c);
271
272         if (widthSum > width) {
273             t.truncate(i - 3);
274             t.append("...");
275             break;
276         }
277     }
278
279     return t;
280 }
281
282 void FriendListItem::setText(bool expanded)
283 {
284     qDebug() << __PRETTY_FUNCTION__;
285
286     setData(Qt::DisplayRole, m_shortenedName);
287
288     if (expanded) {
289         setData(Qt::UserRole, m_user->note());
290         setData(Qt::UserRole + 1, m_user->timestamp());
291         setData(Qt::UserRole + 2, m_user->address());
292
293         setData(Qt::SizeHintRole + 1, m_statusTextRect);
294         setData(Qt::SizeHintRole + 2, m_updatedRect);
295         setData(Qt::SizeHintRole + 3, m_locationRect);
296     }
297     else {
298         setData(Qt::UserRole, m_shortenedStatusText);
299         setData(Qt::UserRole + 1, m_shortenedUpdated);
300         setData(Qt::UserRole + 2, m_shortenedLocation);
301
302         setData(Qt::SizeHintRole + 1, QRect(0, 0, LABEL_MAX_WIDTH, ICON_HEIGHT));
303         setData(Qt::SizeHintRole + 2, QRect(0, 0, LABEL_MAX_WIDTH, ICON_HEIGHT));
304         setData(Qt::SizeHintRole + 3, QRect(0, 0, LABEL_MAX_WIDTH, ICON_HEIGHT));
305     }
306 }
307
308 void FriendListItem::toggleHeight()
309 {
310     if (m_expanded) {
311         m_expanded = false;
312         setText(false);
313         setData(Qt::SizeHintRole, QSize(ITEM_WIDTH, ITEM_MIN_HEIGHT));
314     }
315     else {
316         m_expanded = true;
317         setText(true);
318         setData(Qt::SizeHintRole, QSize(ITEM_WIDTH, m_expandedHeight));
319     }
320 }
321
322 void FriendListItem::setExpanded(bool expanded)
323 {
324     m_expanded = expanded;
325
326     if (m_expanded) {
327         setText(true);
328         setData(Qt::SizeHintRole, QSize(ITEM_WIDTH, m_expandedHeight));
329     }
330     else {
331         setText(false);
332         setData(Qt::SizeHintRole, QSize(ITEM_WIDTH, ITEM_MIN_HEIGHT));
333     }
334 }