1
/***************************************************************************
2
* Copyright (C) 2009-2012 by Savoir-Faire Linux *
3
* Author : Emmanuel Lepage Valle <emmanuel.lepage@savoirfairelinux.com >*
5
* This program is free software; you can redistribute it and/or modify *
6
* it under the terms of the GNU General Public License as published by *
7
* the Free Software Foundation; either version 3 of the License, or *
8
* (at your option) any later version. *
10
* This program is distributed in the hope that it will be useful, *
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13
* GNU General Public License for more details. *
15
* You should have received a copy of the GNU General Public License *
16
* along with this program; if not, write to the *
17
* Free Software Foundation, Inc., *
18
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19
**************************************************************************/
22
#include "HistoryDock.h"
25
#include <QtCore/QString>
26
#include <QtCore/QDate>
27
#include <QtGui/QTreeWidget>
28
#include <QtGui/QComboBox>
29
#include <QtGui/QPushButton>
30
#include <QtGui/QLabel>
31
#include <QtGui/QTreeWidgetItem>
32
#include <QtGui/QCheckBox>
33
#include <QtGui/QGridLayout>
34
#include <QtGui/QHeaderView>
40
#include <KDateWidget>
44
#include "widgets/HistoryTreeItem.h"
45
#include "AkonadiBackend.h"
46
#include "conf/ConfigurationSkeleton.h"
49
#include "lib/sflphone_const.h"
51
///Qt lack official functional sorting algo, so this hack around it
52
class QNumericTreeWidgetItem : public QTreeWidgetItem {
54
QNumericTreeWidgetItem(QTreeWidget* parent):QTreeWidgetItem(parent),widget(0),weight(-1){}
55
QNumericTreeWidgetItem(QTreeWidgetItem* parent):QTreeWidgetItem(parent),widget(0),weight(-1){}
56
HistoryTreeItem* widget;
59
bool operator<(const QTreeWidgetItem & other) const {
60
int column = treeWidget()->sortColumn();
61
if (dynamic_cast<QNumericTreeWidgetItem*>((QTreeWidgetItem*)&other)) {
62
if (widget !=0 && dynamic_cast<QNumericTreeWidgetItem*>((QTreeWidgetItem*)&other)->widget != 0)
63
return widget->getTimeStamp() < dynamic_cast<QNumericTreeWidgetItem*>((QTreeWidgetItem*)&other)->widget->getTimeStamp();
64
else if (weight > 0 && dynamic_cast<QNumericTreeWidgetItem*>((QTreeWidgetItem*)&other)->weight > 0)
65
return weight > dynamic_cast<QNumericTreeWidgetItem*>((QTreeWidgetItem*)&other)->weight;
67
return text(column) < other.text(column);
71
///Event filter allowing to write text on the Tree widget to filter it.
72
bool KeyPressEater::eventFilter(QObject *obj, QEvent *event)
74
if (event->type() == QEvent::KeyPress) {
75
m_pDock->keyPressEvent((QKeyEvent*)event);
78
// standard event processing
79
return QObject::eventFilter(obj, event);
84
HistoryDock::HistoryDock(QWidget* parent) : QDockWidget(parent)
86
setObjectName("historyDock");
87
setMinimumSize(250,0);
88
setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum);
89
m_pFilterLE = new KLineEdit();
90
m_pItemView = new HistoryTree(this);
91
m_pSortByCBB = new QComboBox();
92
m_pSortByL = new QLabel(i18n("Sort by:"));
93
m_pFromL = new QLabel(i18n("From:"));
94
m_pToL = new QLabel(i18n("To:"));
95
m_pFromDW = new KDateWidget();
96
m_pToDW = new KDateWidget();
97
m_pAllTimeCB = new QCheckBox(i18n("Display all"));
98
m_pLinkPB = new QPushButton(this);
100
m_pAllTimeCB->setChecked(ConfigurationSkeleton::displayDataRange());
101
enableDateRange(ConfigurationSkeleton::displayDataRange());
103
m_pSortByL->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Preferred);
104
m_pSortByCBB->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
105
m_pLinkPB->setMaximumSize(20,9999999);
106
m_pLinkPB->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Expanding);
107
m_pLinkPB->setCheckable(true);
109
m_pItemView->headerItem()->setText(0,i18n("Calls") );
110
m_pItemView->header ()->setClickable(true );
111
m_pItemView->header ()->setSortIndicatorShown(true );
112
m_pItemView->setAlternatingRowColors(true );
113
m_pItemView->setAcceptDrops( true );
114
m_pItemView->setDragEnabled( true );
115
KeyPressEater *keyPressEater = new KeyPressEater(this);
116
m_pItemView->installEventFilter(keyPressEater);
118
m_pFilterLE->setPlaceholderText(i18n("Filter"));
119
m_pFilterLE->setClearButtonShown(true);
122
sortBy << "Date" << "Name" << "Popularity" << "Duration";
123
m_pSortByCBB->addItems(sortBy);
125
QWidget* mainWidget = new QWidget(this);
126
setWidget(mainWidget);
128
QGridLayout* mainLayout = new QGridLayout(mainWidget);
130
mainLayout->addWidget(m_pSortByL ,0,0 );
131
mainLayout->addWidget(m_pSortByCBB ,0,1,1,2 );
132
mainLayout->addWidget(m_pAllTimeCB ,1,0,1,3 );
133
mainLayout->addWidget(m_pLinkPB ,3,2,3,1 );
134
mainLayout->addWidget(m_pFromL ,2,0,1,2 );
135
mainLayout->addWidget(m_pFromDW ,3,0,1,2 );
136
mainLayout->addWidget(m_pToL ,4,0,1,2 );
137
mainLayout->addWidget(m_pToDW ,5,0,1,2 );
138
mainLayout->addWidget(m_pItemView ,6,0,1,3 );
139
mainLayout->addWidget(m_pFilterLE ,7,0,1,3 );
141
setWindowTitle(i18n("History"));
143
QDate date(2000,1,1);
144
m_pFromDW->setDate(date);
147
m_CurrentFromDate = m_pFromDW->date();
148
m_CurrentToDate = m_pToDW->date();
150
connect(m_pAllTimeCB, SIGNAL(toggled(bool)), this, SLOT(enableDateRange(bool) ));
151
connect(m_pFilterLE, SIGNAL(textChanged(QString)), this, SLOT(filter(QString) ));
152
connect(m_pFromDW , SIGNAL(changed(QDate)), this, SLOT(updateLinkedFromDate(QDate) ));
153
connect(m_pToDW , SIGNAL(changed(QDate)), this, SLOT(updateLinkedToDate(QDate) ));
154
connect(m_pSortByCBB, SIGNAL(currentIndexChanged(int)), this, SLOT(reload() ));
155
connect(AkonadiBackend::getInstance(), SIGNAL(collectionChanged()), this, SLOT(updateContactInfo() ));
159
HistoryDock::~HistoryDock()
164
/*****************************************************************************
168
****************************************************************************/
170
///Return the identity of the call caller
171
QString HistoryDock::getIdentity(HistoryTreeItem* item)
173
if (item->getName().trimmed().isEmpty())
174
return item->getPhoneNumber();
176
return item->getName();
180
/*****************************************************************************
184
****************************************************************************/
186
///Update informations
187
void HistoryDock::updateContactInfo()
189
foreach(HistoryTreeItem* hitem, m_History) {
194
///Reload the history list
195
void HistoryDock::reload()
197
m_pItemView->clear();
198
foreach(HistoryTreeItem* hitem, m_History) {
202
foreach (Call* call, SFLPhone::app()->model()->getHistory()) {
203
if (!m_pAllTimeCB->isChecked() || (QDateTime(m_pFromDW->date()).toTime_t() < call->getStartTimeStamp().toUInt() && QDateTime(m_pToDW->date().addDays(1)).toTime_t() > call->getStartTimeStamp().toUInt() )) {
204
HistoryTreeItem* callItem = new HistoryTreeItem(m_pItemView);
205
callItem->setCall(call);
206
m_History << callItem;
209
switch (m_pSortByCBB->currentIndex()) {
211
foreach(HistoryTreeItem* hitem, m_History) {
212
QNumericTreeWidgetItem* item = new QNumericTreeWidgetItem(m_pItemView);
213
item->widget = hitem;
214
hitem->setItem(item);
215
m_pItemView->addTopLevelItem(item);
216
m_pItemView->setItemWidget(item,0,hitem);
220
QHash<QString,QTreeWidgetItem*> group;
221
foreach(HistoryTreeItem* item, m_History) {
222
if (!group[getIdentity(item)]) {
223
group[getIdentity(item)] = new QTreeWidgetItem(m_pItemView);
224
group[getIdentity(item)]->setText(0,getIdentity(item));
225
m_pItemView->addTopLevelItem(group[getIdentity(item)]);
227
QNumericTreeWidgetItem* twItem = new QNumericTreeWidgetItem(group[getIdentity(item)]);
228
item->setItem(twItem);
229
twItem->widget = item;
230
m_pItemView->setItemWidget(twItem,0,item);
235
QHash<QString,QNumericTreeWidgetItem*> group;
236
foreach(HistoryTreeItem* item, m_History) {
237
if (!group[getIdentity(item)]) {
238
group[getIdentity(item)] = new QNumericTreeWidgetItem(m_pItemView);
239
group[getIdentity(item)]->weight = 0;
240
m_pItemView->addTopLevelItem(group[getIdentity(item)]);
242
group[getIdentity(item)]->weight++;
243
group[getIdentity(item)]->setText(0,getIdentity(item)+" ("+QString::number(group[getIdentity(item)]->weight)+")");
244
QNumericTreeWidgetItem* twItem = new QNumericTreeWidgetItem(group[getIdentity(item)]);
245
item->setItem(twItem);
246
twItem->widget = item;
247
m_pItemView->setItemWidget(twItem,0,item);
252
foreach(HistoryTreeItem* hitem, m_History) {
253
QNumericTreeWidgetItem* item = new QNumericTreeWidgetItem(m_pItemView);
254
item->weight = hitem->getDuration();
255
hitem->setItem(item);
256
m_pItemView->addTopLevelItem(item);
257
m_pItemView->setItemWidget(item,0,hitem);
261
m_pItemView->sortItems(0,Qt::AscendingOrder);
264
///Enable the ability to set a date range like 1 month to limit history
265
void HistoryDock::enableDateRange(bool enable)
267
m_pFromL->setVisible(enable);
268
m_pToL->setVisible(enable);
269
m_pFromDW->setVisible(enable);
270
m_pToDW->setVisible(enable);
271
m_pLinkPB->setVisible(enable);
273
ConfigurationSkeleton::setDisplayDataRange(enable);
276
///Filter the history
277
void HistoryDock::filter(QString text)
279
foreach(HistoryTreeItem* item, m_History) {
280
bool visible = (item->getName().toLower().indexOf(text) != -1) || (item->getPhoneNumber().toLower().indexOf(text) != -1);
281
item->getItem()-> setHidden(!visible);
283
m_pItemView->expandAll();
286
///When the data range is linked, change the opposite value when editing the first
287
void HistoryDock::updateLinkedDate(KDateWidget* item, QDate& prevDate, QDate& newDate)
289
if (m_pLinkPB->isChecked()) {
290
if (prevDate.day() != newDate.day()) {
291
QDate tmp = item->date();
292
tmp = tmp.addDays(newDate.day() - prevDate.day());
295
if (prevDate.month() != newDate.month()) {
296
QDate tmp = item->date();
297
tmp = tmp.addMonths(newDate.month() - prevDate.month());
300
if (prevDate.year() != newDate.year()) {
301
QDate tmp = item->date();
302
tmp = tmp.addYears(newDate.year() - prevDate.year());
309
///The signals have to be disabled to prevent an ifinite loop
310
void HistoryDock::updateLinkedFromDate(QDate date)
312
disconnect (m_pToDW , SIGNAL(changed(QDate)), this, SLOT(updateLinkedToDate(QDate)));
313
updateLinkedDate(m_pToDW,m_CurrentFromDate,date);
314
connect (m_pToDW , SIGNAL(changed(QDate)), this, SLOT(updateLinkedToDate(QDate)));
317
///The signals have to be disabled to prevent an ifinite loop
318
void HistoryDock::updateLinkedToDate(QDate date)
320
disconnect(m_pFromDW , SIGNAL(changed(QDate)), this, SLOT(updateLinkedFromDate(QDate)));
321
updateLinkedDate(m_pFromDW,m_CurrentToDate,date);
322
connect (m_pFromDW , SIGNAL(changed(QDate)), this, SLOT(updateLinkedFromDate(QDate)));
326
/*****************************************************************************
330
****************************************************************************/
332
///Generate serializerd version of the content
333
QMimeData* HistoryTree::mimeData( const QList<QTreeWidgetItem *> items) const
335
kDebug() << "An history call is being dragged";
336
if (items.size() < 1) {
340
QMimeData *mimeData = new QMimeData();
343
if (dynamic_cast<QNumericTreeWidgetItem*>(items[0])) {
344
QNumericTreeWidgetItem* item = dynamic_cast<QNumericTreeWidgetItem*>(items[0]);
345
if (item->widget != 0) {
346
mimeData->setData(MIME_PHONENUMBER, item->widget->call()->getPeerPhoneNumber().toUtf8());
350
kDebug() << "the item is not a call";
355
///Handle what happen when serialized data is dropped
356
bool HistoryTree::dropMimeData(QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action)
362
QByteArray encodedData = data->data(MIME_CALLID);
364
kDebug() << "In history import"<< QString(encodedData);
370
/*****************************************************************************
372
* Keyboard handling *
374
****************************************************************************/
376
///Handle keyboard input and redirect them to the filterbox
377
void HistoryDock::keyPressEvent(QKeyEvent* event) {
378
int key = event->key();
379
if(key == Qt::Key_Escape)
380
m_pFilterLE->setText(QString());
381
else if(key == Qt::Key_Return || key == Qt::Key_Enter) {}
382
else if((key == Qt::Key_Backspace) && (m_pFilterLE->text().size()))
383
m_pFilterLE->setText(m_pFilterLE->text().left( m_pFilterLE->text().size()-1 ));
384
else if (!event->text().isEmpty() && !(key == Qt::Key_Backspace))
385
m_pFilterLE->setText(m_pFilterLE->text()+event->text());
b'\\ No newline at end of file'