1 /* This file is part of the KDE project
3 Copyright (C) 2006 Dario Massarin <nekkar@libero.it>
4 Copyright (C) 2007 by Javier Goday <jgoday@gmail.com>
5 Copyright (C) 2008 Lukas Appelhans <l.appelhans@gmx.de>
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
13 #include "ui/transfersviewdelegate.h"
15 #include "transferdetails.h"
16 #include "ui/contextmenu.h"
17 #include "core/kget.h"
18 #include "core/observer.h"
19 #include "core/transferhandler.h"
20 #include "core/transfergrouphandler.h"
21 #include "core/transfertreemodel.h"
22 #include "core/transfertreeselectionmodel.h"
30 #include <QApplication>
32 #include <QMouseEvent>
33 #include <QModelIndex>
34 #include <QButtonGroup>
35 #include <QHBoxLayout>
38 #include <QAbstractItemView>
40 GroupStatusButton::GroupStatusButton(const QModelIndex
& index
, QWidget
* parent
)
41 : QToolButton(parent
),
48 setAttribute(Qt::WA_NoSystemBackground
);
51 void GroupStatusButton::checkStateSet()
53 // kDebug(5001) << "GroupStatusButton::checkStateSet";
55 QToolButton::checkStateSet();
67 m_status
= Deselecting
;
70 setMouseTracking(!isChecked());
73 m_timerId
= startTimer(100);
76 void GroupStatusButton::enterEvent(QEvent
* event
)
85 m_timerId
= startTimer(100);
87 if(m_status
== !BlinkingExiting
)
93 void GroupStatusButton::leaveEvent(QEvent
* event
)
96 if(m_status
== Blinking
)
97 m_status
= BlinkingExiting
;
100 void GroupStatusButton::paintEvent(QPaintEvent
* event
)
106 int offset
= (event
->rect().width() - m_iconSize
) / 2;
108 if(m_gradientId
== 0)
109 m_gradientId
= isChecked() ? 1 : 0.7;
111 QRadialGradient
gradient(event
->rect().topLeft() + QPoint(event
->rect().width() / 2, event
->rect().height() / 2), event
->rect().width() / 2);
115 if(KGet::selectionModel()->isSelected(m_index
))
117 gradient
.setColorAt(0, palette().color(QPalette::AlternateBase
));
118 gradient
.setColorAt(m_gradientId
, Qt::transparent
);
119 gradient
.setColorAt(1, Qt::transparent
);
120 pen
.setColor(palette().color(QPalette::AlternateBase
));
124 gradient
.setColorAt(0, palette().color(QPalette::Highlight
));
125 gradient
.setColorAt(m_gradientId
, Qt::transparent
);
126 gradient
.setColorAt(1, Qt::transparent
);
127 pen
.setColor(palette().color(QPalette::Highlight
));
130 QRect r
= event
->rect().adjusted(0,0,0,1);
132 p
.fillRect(r
, gradient
);
134 p
.setRenderHint(QPainter::Antialiasing
);
140 p
.drawEllipse(event
->rect().x()+5, event
->rect().y()+4, event
->rect().width()-10, event
->rect().width()-10);
143 p
.drawPixmap(event
->rect().topLeft() + QPoint(offset
, offset
-1),
144 icon().pixmap(m_iconSize
, isChecked() || m_status
== Blinking
?
145 QIcon::Normal
: QIcon::Disabled
));
148 void GroupStatusButton::timerEvent(QTimerEvent
*event
)
152 if(m_status
== Selecting
)
156 if(m_gradientId
>= 1)
160 killTimer(m_timerId
);
164 else if(m_status
== Deselecting
)
168 if(m_gradientId
<= 0.7)
172 killTimer(m_timerId
);
176 else if(m_status
== Blinking
)
180 m_status
= Selecting
;
187 if(m_gradientId
<= 0.7)
192 else if(m_status
== BlinkingExiting
)
196 if(m_gradientId
<= 0.7)
200 killTimer(m_timerId
);
208 GroupStatusEditor::GroupStatusEditor(const QModelIndex
& index
, const TransfersViewDelegate
* delegate
, QWidget
* parent
)
210 m_delegate(delegate
),
215 m_layout
= new QHBoxLayout();
216 m_layout
->addStretch();
219 m_btGroup
= new QButtonGroup(this);
220 m_btGroup
->setExclusive(true);
222 m_startBt
= new GroupStatusButton(m_index
, this);
223 m_startBt
->setCheckable(true);
224 m_startBt
->setAutoRaise(true);
225 m_startBt
->setIcon(KIcon("media-playback-start"));
226 m_startBt
->setFixedSize(36, 36);
227 m_startBt
->setIconSize(QSize(22, 22));
228 m_startBt
->installEventFilter(const_cast<TransfersViewDelegate
*>(delegate
));
229 m_layout
->addWidget(m_startBt
);
230 m_btGroup
->addButton(m_startBt
);
232 m_stopBt
= new GroupStatusButton(m_index
, this);
233 m_stopBt
->setCheckable(true);
234 m_stopBt
->setAutoRaise(true);
235 m_stopBt
->setIcon(KIcon("media-playback-pause"));
236 m_stopBt
->setFixedSize(36, 36);
237 m_stopBt
->setIconSize(QSize(22, 22));
238 m_stopBt
->installEventFilter(const_cast<TransfersViewDelegate
*>(delegate
));
239 m_layout
->addWidget(m_stopBt
);
240 m_btGroup
->addButton(m_stopBt
);
242 m_stopBt
->setChecked(true);
244 m_layout
->addStretch();
245 m_layout
->setMargin(1);
247 connect(m_startBt
, SIGNAL(toggled(bool)),
248 this, SLOT(slotStatusChanged(bool)));
251 void GroupStatusEditor::setRunning(bool running
)
253 if(running
== m_startBt
->isChecked())
257 m_startBt
->setChecked(true);
259 m_stopBt
->setChecked(true);
262 bool GroupStatusEditor::isRunning()
264 return m_startBt
->isChecked();
267 void GroupStatusEditor::slotStatusChanged(bool running
)
271 emit
const_cast<TransfersViewDelegate
*>(m_delegate
)->commitData(this);
274 TransfersViewDelegate::TransfersViewDelegate(QAbstractItemView
*parent
)
275 : KExtendableItemDelegate(parent
)
277 Q_ASSERT(qobject_cast
<QAbstractItemView
*>(parent
));
278 setExtendPixmap(SmallIcon("arrow-right"));
279 setContractPixmap(SmallIcon("arrow-down"));
280 connect(parent
, SIGNAL(activated(QModelIndex
)), this, SLOT(itemActivated(QModelIndex
)));
283 void TransfersViewDelegate::paint(QPainter
* painter
, const QStyleOptionViewItem
& option
, const QModelIndex
& index
) const
285 const TransferTreeModel
* transferTreeModel
= static_cast<const TransferTreeModel
*>(index
.model());
287 if(transferTreeModel
->isTransferGroup(index
))
291 if (option
.state
& QStyle::State_Selected
)
296 static bool backgroundInitialized
= false;
297 static QPixmap
groupBackground(64, 35);
298 static QPalette
palette(QApplication::palette());
300 if(!backgroundInitialized
|| palette
!= QApplication::palette())
302 const QRect rect
= groupBackground
.rect();
303 QPainter
p(&groupBackground
);
305 QLinearGradient
gradient(rect
.x(), rect
.y(),
306 rect
.x(), (rect
.y() + rect
.height()));
308 gradient
.setColorAt(0, QApplication::palette().color(QPalette::Base
));
309 gradient
.setColorAt(0.5, QApplication::palette().color(QPalette::AlternateBase
).darker(110));
310 gradient
.setColorAt(1, QApplication::palette().color(QPalette::Base
));
312 p
.fillRect(rect
, gradient
);
313 backgroundInitialized
= true;
316 painter
->drawTiledPixmap(option
.rect
, groupBackground
);
319 KExtendableItemDelegate::paint(painter
, option
, index
);
324 if (KGet::selectionModel()->isSelected(index
))
325 painter
->fillRect(option
.rect
, QApplication::palette().color(option
.state
& QStyle::State_Active
?
326 QPalette::Active
: QPalette::Inactive
,
327 QPalette::Highlight
));
329 KExtendableItemDelegate::paint(painter
, option
, index
);
331 if (index
.column() == 3 && !isExtended(transferTreeModel
->index(index
.row(), 0, index
.parent()))) { // the percent column
332 TransferHandler
*transferHandler
= static_cast<TransferHandler
*>(index
.internalPointer());
334 // following progressbar code has mostly been taken from Qt4 examples/network/torrent/mainview.cpp
335 // Set up a QStyleOptionProgressBar to precisely mimic the
336 // environment of a progress bar.
337 QStyleOptionProgressBar progressBarOption
;
338 progressBarOption
.state
= QStyle::State_Enabled
;
339 progressBarOption
.direction
= QApplication::layoutDirection();
340 progressBarOption
.rect
= option
.rect
;
341 progressBarOption
.fontMetrics
= QApplication::fontMetrics();
342 progressBarOption
.minimum
= 0;
343 progressBarOption
.maximum
= 100;
344 progressBarOption
.textAlignment
= Qt::AlignCenter
;
345 progressBarOption
.textVisible
= true;
347 // Set the progress and text values of the style option.
348 int progress
= transferHandler
->percent();
349 if (progress
>= 0 && progress
<= 100) {
350 progressBarOption
.progress
= progress
;
351 progressBarOption
.text
= QString().sprintf("%d%%", progressBarOption
.progress
);
353 progressBarOption
.text
= i18nc("not available", "n/a");
356 progressBarOption
.rect
.setY(progressBarOption
.rect
.y() +
357 (option
.rect
.height() - QApplication::fontMetrics().height()) / 2);
358 progressBarOption
.rect
.setHeight(QApplication::fontMetrics().height());
360 // Draw the progress bar onto the view.
361 QApplication::style()->drawControl(QStyle::CE_ProgressBar
, &progressBarOption
, painter
);
365 /// These lines are just for testing purposes. Uncomment them to show on the view the repaint events.
367 // kDebug(5001) << "paint!!! " << i++ << " " << index.internalPointer() << " " << index.column();
369 // painter->drawRect(option.rect);
370 // painter->drawText(option.rect.topLeft(), QString::number(i));
373 void TransfersViewDelegate::drawFocus(QPainter
* painter
, const QStyleOptionViewItem
& option
, const
381 QSize
TransfersViewDelegate::sizeHint(const QStyleOptionViewItem
& option
, const QModelIndex
& index
) const
385 const TransferTreeModel
* transferTreeModel
= static_cast<const TransferTreeModel
*>(index
.model());
387 if(transferTreeModel
->isTransferGroup(index
))
392 QSize
ret(KExtendableItemDelegate::sizeHint(option
, index
));
398 QWidget
* TransfersViewDelegate::createEditor(QWidget
*parent
, const QStyleOptionViewItem
& option
, const QModelIndex
& index
) const
403 GroupStatusEditor
* groupsStatusEditor
= new GroupStatusEditor(index
, this, parent
);
405 return groupsStatusEditor
;
408 bool TransfersViewDelegate::editorEvent(QEvent
* event
, QAbstractItemModel
* model
, const QStyleOptionViewItem
& option
, const QModelIndex
& index
)
412 QMouseEvent
* mouseEvent
= dynamic_cast<QMouseEvent
*>(event
);
416 if(mouseEvent
->button() == Qt::RightButton
)
418 // kDebug(5001) << "TransfersViewDelegate::editorEvent() -> rightClick";
422 TransferTreeModel
* transferTreeModel
= static_cast<TransferTreeModel
*>(model
);
424 if(transferTreeModel
->isTransferGroup(index
))
426 // kDebug(5001) << "isTransferGroup = true";
427 TransferGroupHandler
* transferGroupHandler
= static_cast<TransferGroupHandler
*>(index
.internalPointer());
429 popup
= ContextMenu::createTransferGroupContextMenu(transferGroupHandler
, qobject_cast
<QWidget
*>(this));
434 // kDebug(5001) << "isTransferGroup = false";
436 TransferHandler
* transferHandler
= static_cast<TransferHandler
*>(index
.internalPointer());
438 popup
= ContextMenu::createTransferContextMenu(transferHandler
, qobject_cast
<QWidget
*>(this));
442 popup
->exec(QCursor::pos());
443 popup
->deleteLater();
451 void TransfersViewDelegate::setEditorData(QWidget
* editor
, const QModelIndex
& index
) const
453 GroupStatusEditor
* groupEditor
= static_cast<GroupStatusEditor
*>(editor
);
455 groupEditor
->setRunning((static_cast<TransferGroupHandler
*>(index
.internalPointer())->status()) == JobQueue::Running
);
458 void TransfersViewDelegate::setModelData(QWidget
* editor
, QAbstractItemModel
* model
, const QModelIndex
& index
) const
462 GroupStatusEditor
* groupEditor
= static_cast<GroupStatusEditor
*>(editor
);
464 TransferGroupHandler
* groupHandler
= static_cast<TransferGroupHandler
*>(index
.internalPointer());
466 if (groupEditor
->isRunning())
467 groupHandler
->start();
469 groupHandler
->stop();
472 void TransfersViewDelegate::closeExpandableDetails(const QModelIndex
&transferIndex
)
474 if(transferIndex
.isValid()) {
475 removeTransferObserver(transferIndex
);
476 contractItem(transferIndex
);
477 m_editingIndexes
.removeAll(transferIndex
);
480 foreach(const QModelIndex
&index
, m_editingIndexes
) {
481 removeTransferObserver(index
);
485 m_editingIndexes
.clear();
489 QWidget
*TransfersViewDelegate::getDetailsWidgetForTransfer(TransferHandler
*handler
)
491 QGroupBox
*groupBox
= new QGroupBox(i18n("Transfer details"));
493 QVBoxLayout
*layout
= new QVBoxLayout(groupBox
);
494 QWidget
*detailsWidget
= TransferDetails::detailsWidget(handler
);
495 layout
->addWidget(detailsWidget
);
497 // if the details widget is a transfer observer
498 // we add into the transfers_map to delete it when
499 // the extendableitem is closed before the widget or the transfer
500 TransferObserver
*observer
= dynamic_cast <TransferObserver
*> (detailsWidget
);
502 m_transfersMap
.insert(handler
, observer
);
508 void TransfersViewDelegate::itemActivated(const QModelIndex
&index
)
510 const TransferTreeModel
* transferTreeModel
= static_cast <const TransferTreeModel
*> (index
.model());
512 if(!transferTreeModel
->isTransferGroup(index
) && Settings::showExpandableTransferDetails() && index
.column() == 0) {
513 if(!isExtended(index
)) {
514 TransferHandler
*handler
= static_cast <TransferHandler
*> (index
.internalPointer());
515 QWidget
*widget
= getDetailsWidgetForTransfer(handler
);
517 m_editingIndexes
.append(index
);
518 extendItem(widget
, index
);
521 removeTransferObserver(index
);
523 m_editingIndexes
.removeAll(index
);
529 void TransfersViewDelegate::removeTransferObserver(const QModelIndex
&index
)
531 TransferHandler
*handler
= static_cast <TransferHandler
*> (index
.internalPointer());
533 // remove the observer from the handler
534 if (m_transfersMap
.contains(handler
)) {
535 TransferObserver
*observer
= m_transfersMap
.value(handler
);
536 m_transfersMap
.remove(handler
);
537 handler
->delObserver(observer
);
542 #include "transfersviewdelegate.moc"