1 | /* This file is part of the KDE project |
2 | Copyright (C) 2007 Kevin Ottens <ervin@kde.org> |
3 | Copyright (C) 2008 Rafael Fernández López <ereslibre@kde.org> |
4 | |
5 | This library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Library General Public |
7 | License version 2 as published by the Free Software Foundation. |
8 | |
9 | This library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Library General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Library General Public License |
15 | along with this library; see the file COPYING.LIB. If not, write to |
16 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
17 | Boston, MA 02110-1301, USA. |
18 | |
19 | */ |
20 | |
21 | #include "kfileplacesview.h" |
22 | #include "kfileplacesview_p.h" |
23 | |
24 | #include <QtCore/QTimeLine> |
25 | #include <QtCore/QTimer> |
26 | #include <QtGui/QPainter> |
27 | #include <QtGui/QAbstractItemDelegate> |
28 | #include <QtGui/QKeyEvent> |
29 | #include <QtGui/QApplication> |
30 | #include <QtGui/QScrollBar> |
31 | |
32 | #include <kdebug.h> |
33 | |
34 | #include <kmenu.h> |
35 | #include <kcomponentdata.h> |
36 | #include <kdirnotify.h> |
37 | #include <kglobalsettings.h> |
38 | #include <kiconloader.h> |
39 | #include <klocale.h> |
40 | #include <kmessagebox.h> |
41 | #include <knotification.h> |
42 | #include <kio/job.h> |
43 | #include <kio/jobuidelegate.h> |
44 | #include <kjob.h> |
45 | #include <kcapacitybar.h> |
46 | #include <kdiskfreespaceinfo.h> |
47 | #include <solid/storageaccess.h> |
48 | #include <solid/storagedrive.h> |
49 | #include <solid/storagevolume.h> |
50 | #include <solid/opticaldrive.h> |
51 | #include <solid/opticaldisc.h> |
52 | |
53 | #include "kfileplaceeditdialog.h" |
54 | #include "kfileplacesmodel.h" |
55 | |
56 | #define LATERAL_MARGIN 4 |
57 | #define CAPACITYBAR_HEIGHT 6 |
58 | |
59 | class KFilePlacesViewDelegate : public QAbstractItemDelegate |
60 | { |
61 | public: |
62 | KFilePlacesViewDelegate(KFilePlacesView *parent); |
63 | virtual ~KFilePlacesViewDelegate(); |
64 | virtual QSize sizeHint(const QStyleOptionViewItem &option, |
65 | const QModelIndex &index) const; |
66 | virtual void paint(QPainter *painter, |
67 | const QStyleOptionViewItem &option, |
68 | const QModelIndex &index) const; |
69 | |
70 | int iconSize() const; |
71 | void setIconSize(int newSize); |
72 | |
73 | void addAppearingItem(const QModelIndex &index); |
74 | void setAppearingItemProgress(qreal value); |
75 | void addDisappearingItem(const QModelIndex &index); |
76 | void setDisappearingItemProgress(qreal value); |
77 | |
78 | void setShowHoverIndication(bool show); |
79 | |
80 | void addFadeAnimation(const QModelIndex &index, QTimeLine *timeLine); |
81 | void removeFadeAnimation(const QModelIndex &index); |
82 | QModelIndex indexForFadeAnimation(QTimeLine *timeLine) const; |
83 | QTimeLine *fadeAnimationForIndex(const QModelIndex &index) const; |
84 | |
85 | qreal contentsOpacity(const QModelIndex &index) const; |
86 | |
87 | private: |
88 | KFilePlacesView *m_view; |
89 | int m_iconSize; |
90 | |
91 | QList<QPersistentModelIndex> m_appearingItems; |
92 | int m_appearingIconSize; |
93 | qreal m_appearingOpacity; |
94 | |
95 | QList<QPersistentModelIndex> m_disappearingItems; |
96 | int m_disappearingIconSize; |
97 | qreal m_disappearingOpacity; |
98 | |
99 | bool m_showHoverIndication; |
100 | |
101 | QMap<QPersistentModelIndex, QTimeLine*> m_timeLineMap; |
102 | QMap<QTimeLine*, QPersistentModelIndex> m_timeLineInverseMap; |
103 | }; |
104 | |
105 | KFilePlacesViewDelegate::KFilePlacesViewDelegate(KFilePlacesView *parent) : |
106 | QAbstractItemDelegate(parent), |
107 | m_view(parent), |
108 | m_iconSize(48), |
109 | m_appearingIconSize(0), |
110 | m_appearingOpacity(0.0), |
111 | m_disappearingIconSize(0), |
112 | m_disappearingOpacity(0.0), |
113 | m_showHoverIndication(true) |
114 | { |
115 | } |
116 | |
117 | KFilePlacesViewDelegate::~KFilePlacesViewDelegate() |
118 | { |
119 | } |
120 | |
121 | QSize KFilePlacesViewDelegate::sizeHint(const QStyleOptionViewItem &option, |
122 | const QModelIndex &index) const |
123 | { |
124 | int iconSize = m_iconSize; |
125 | if (m_appearingItems.contains(index)) { |
126 | iconSize = m_appearingIconSize; |
127 | } else if (m_disappearingItems.contains(index)) { |
128 | iconSize = m_disappearingIconSize; |
129 | } |
130 | |
131 | const KFilePlacesModel *filePlacesModel = static_cast<const KFilePlacesModel*>(index.model()); |
132 | Solid::Device device = filePlacesModel->deviceForIndex(index); |
133 | |
134 | return QSize(option.rect.width(), option.fontMetrics.height() / 2 + qMax(iconSize, option.fontMetrics.height())); |
135 | } |
136 | |
137 | void KFilePlacesViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const |
138 | { |
139 | painter->save(); |
140 | |
141 | if (m_appearingItems.contains(index)) { |
142 | painter->setOpacity(m_appearingOpacity); |
143 | } else if (m_disappearingItems.contains(index)) { |
144 | painter->setOpacity(m_disappearingOpacity); |
145 | } |
146 | |
147 | QStyleOptionViewItemV4 opt = option; |
148 | if (!m_showHoverIndication) { |
149 | opt.state &= ~QStyle::State_MouseOver; |
150 | } |
151 | QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter); |
152 | const KFilePlacesModel *placesModel = static_cast<const KFilePlacesModel*>(index.model()); |
153 | |
154 | bool isLTR = option.direction == Qt::LeftToRight; |
155 | |
156 | QIcon icon = index.model()->data(index, Qt::DecorationRole).value<QIcon>(); |
157 | QPixmap pm = icon.pixmap(m_iconSize, m_iconSize); |
158 | QPoint point(isLTR ? option.rect.left() + LATERAL_MARGIN |
159 | : option.rect.right() - LATERAL_MARGIN - m_iconSize, option.rect.top() + (option.rect.height() - m_iconSize) / 2); |
160 | painter->drawPixmap(point, pm); |
161 | |
162 | if (option.state & QStyle::State_Selected) { |
163 | QPalette::ColorGroup cg = QPalette::Active; |
164 | if (!(option.state & QStyle::State_Enabled)) { |
165 | cg = QPalette::Disabled; |
166 | } else if (!(option.state & QStyle::State_Active)) { |
167 | cg = QPalette::Inactive; |
168 | } |
169 | painter->setPen(option.palette.color(cg, QPalette::HighlightedText)); |
170 | } |
171 | |
172 | QRect rectText; |
173 | |
174 | const KUrl url = placesModel->url(index); |
175 | bool drawCapacityBar = false; |
176 | if (url.isLocalFile()) { |
177 | const QString mountPointPath = placesModel->url(index).toLocalFile(); |
178 | const KDiskFreeSpaceInfo info = KDiskFreeSpaceInfo::freeSpaceInfo(mountPointPath); |
179 | drawCapacityBar = info.size() != 0 && |
180 | placesModel->data(index, KFilePlacesModel::CapacityBarRecommendedRole).toBool(); |
181 | |
182 | if (drawCapacityBar && contentsOpacity(index) > 0) |
183 | { |
184 | painter->save(); |
185 | painter->setOpacity(painter->opacity() * contentsOpacity(index)); |
186 | |
187 | int height = option.fontMetrics.height() + CAPACITYBAR_HEIGHT; |
188 | rectText = QRect(isLTR ? m_iconSize + LATERAL_MARGIN * 2 + option.rect.left() |
189 | : 0, option.rect.top() + (option.rect.height() / 2 - height / 2), option.rect.width() - m_iconSize - LATERAL_MARGIN * 2, option.fontMetrics.height()); |
190 | painter->drawText(rectText, Qt::AlignLeft | Qt::AlignTop, option.fontMetrics.elidedText(index.model()->data(index).toString(), Qt::ElideRight, rectText.width())); |
191 | QRect capacityRect(isLTR ? rectText.x() : LATERAL_MARGIN, rectText.bottom() - 1, rectText.width() - LATERAL_MARGIN, CAPACITYBAR_HEIGHT); |
192 | KCapacityBar capacityBar(KCapacityBar::DrawTextInline); |
193 | capacityBar.setValue((info.used() * 100) / info.size()); |
194 | capacityBar.drawCapacityBar(painter, capacityRect); |
195 | |
196 | painter->restore(); |
197 | |
198 | painter->save(); |
199 | painter->setOpacity(painter->opacity() * (1 - contentsOpacity(index))); |
200 | } |
201 | } |
202 | |
203 | rectText = QRect(isLTR ? m_iconSize + LATERAL_MARGIN * 2 + option.rect.left() |
204 | : 0, option.rect.top(), option.rect.width() - m_iconSize - LATERAL_MARGIN * 2, option.rect.height()); |
205 | painter->drawText(rectText, Qt::AlignLeft | Qt::AlignVCenter, option.fontMetrics.elidedText(index.model()->data(index).toString(), Qt::ElideRight, rectText.width())); |
206 | |
207 | if (drawCapacityBar && contentsOpacity(index) > 0) { |
208 | painter->restore(); |
209 | } |
210 | |
211 | painter->restore(); |
212 | } |
213 | |
214 | int KFilePlacesViewDelegate::iconSize() const |
215 | { |
216 | return m_iconSize; |
217 | } |
218 | |
219 | void KFilePlacesViewDelegate::setIconSize(int newSize) |
220 | { |
221 | m_iconSize = newSize; |
222 | } |
223 | |
224 | void KFilePlacesViewDelegate::addAppearingItem(const QModelIndex &index) |
225 | { |
226 | m_appearingItems << index; |
227 | } |
228 | |
229 | void KFilePlacesViewDelegate::setAppearingItemProgress(qreal value) |
230 | { |
231 | if (value<=0.25) { |
232 | m_appearingOpacity = 0.0; |
233 | m_appearingIconSize = iconSize()*value*4; |
234 | |
235 | if (m_appearingIconSize>=m_iconSize) { |
236 | m_appearingIconSize = m_iconSize; |
237 | } |
238 | } else { |
239 | m_appearingIconSize = m_iconSize; |
240 | m_appearingOpacity = (value-0.25)*4/3; |
241 | |
242 | if (value>=1.0) { |
243 | m_appearingItems.clear(); |
244 | } |
245 | } |
246 | } |
247 | |
248 | void KFilePlacesViewDelegate::addDisappearingItem(const QModelIndex &index) |
249 | { |
250 | m_disappearingItems << index; |
251 | } |
252 | |
253 | void KFilePlacesViewDelegate::setDisappearingItemProgress(qreal value) |
254 | { |
255 | value = 1.0 - value; |
256 | |
257 | if (value<=0.25) { |
258 | m_disappearingOpacity = 0.0; |
259 | m_disappearingIconSize = iconSize()*value*4; |
260 | |
261 | if (m_disappearingIconSize>=m_iconSize) { |
262 | m_disappearingIconSize = m_iconSize; |
263 | } |
264 | |
265 | if (value<=0.0) { |
266 | m_disappearingItems.clear(); |
267 | } |
268 | } else { |
269 | m_disappearingIconSize = m_iconSize; |
270 | m_disappearingOpacity = (value-0.25)*4/3; |
271 | } |
272 | } |
273 | |
274 | void KFilePlacesViewDelegate::setShowHoverIndication(bool show) |
275 | { |
276 | m_showHoverIndication = show; |
277 | } |
278 | |
279 | void KFilePlacesViewDelegate::addFadeAnimation(const QModelIndex &index, QTimeLine *timeLine) |
280 | { |
281 | m_timeLineMap.insert(index, timeLine); |
282 | m_timeLineInverseMap.insert(timeLine, index); |
283 | } |
284 | |
285 | void KFilePlacesViewDelegate::removeFadeAnimation(const QModelIndex &index) |
286 | { |
287 | QTimeLine *timeLine = m_timeLineMap.value(index, 0); |
288 | m_timeLineMap.remove(index); |
289 | m_timeLineInverseMap.remove(timeLine); |
290 | } |
291 | |
292 | QModelIndex KFilePlacesViewDelegate::indexForFadeAnimation(QTimeLine *timeLine) const |
293 | { |
294 | return m_timeLineInverseMap.value(timeLine, QModelIndex()); |
295 | } |
296 | |
297 | QTimeLine *KFilePlacesViewDelegate::fadeAnimationForIndex(const QModelIndex &index) const |
298 | { |
299 | return m_timeLineMap.value(index, 0); |
300 | } |
301 | |
302 | qreal KFilePlacesViewDelegate::contentsOpacity(const QModelIndex &index) const |
303 | { |
304 | QTimeLine *timeLine = fadeAnimationForIndex(index); |
305 | if (timeLine) { |
306 | return timeLine->currentValue(); |
307 | } |
308 | return 0; |
309 | } |
310 | |
311 | class KFilePlacesView::Private |
312 | { |
313 | public: |
314 | Private(KFilePlacesView *parent) : q(parent), watcher(new KFilePlacesEventWatcher(q)) { } |
315 | |
316 | enum FadeType { |
317 | FadeIn = 0, |
318 | FadeOut |
319 | }; |
320 | |
321 | KFilePlacesView * const q; |
322 | |
323 | KUrl currentUrl; |
324 | bool autoResizeItems; |
325 | bool showAll; |
326 | bool smoothItemResizing; |
327 | bool dropOnPlace; |
328 | bool dragging; |
329 | Solid::StorageAccess *lastClickedStorage; |
330 | QPersistentModelIndex lastClickedIndex; |
331 | |
332 | QRect dropRect; |
333 | |
334 | void setCurrentIndex(const QModelIndex &index); |
335 | void adaptItemSize(); |
336 | void updateHiddenRows(); |
337 | bool insertAbove(const QRect &itemRect, const QPoint &pos) const; |
338 | bool insertBelow(const QRect &itemRect, const QPoint &pos) const; |
339 | int insertIndicatorHeight(int itemHeight) const; |
340 | void fadeCapacityBar(const QModelIndex &index, FadeType fadeType); |
341 | |
342 | void _k_placeClicked(const QModelIndex &index); |
343 | void _k_placeEntered(const QModelIndex &index); |
344 | void _k_placeLeft(const QModelIndex &index); |
345 | void _k_storageSetupDone(const QModelIndex &index, bool success); |
346 | void _k_adaptItemsUpdate(qreal value); |
347 | void _k_itemAppearUpdate(qreal value); |
348 | void _k_itemDisappearUpdate(qreal value); |
349 | void _k_enableSmoothItemResizing(); |
350 | void _k_trashUpdated(KJob *job); |
351 | void _k_capacityBarFadeValueChanged(); |
352 | void _k_triggerDevicePolling(); |
353 | |
354 | QTimeLine adaptItemsTimeline; |
355 | int oldSize, endSize; |
356 | |
357 | QTimeLine itemAppearTimeline; |
358 | QTimeLine itemDisappearTimeline; |
359 | |
360 | KFilePlacesEventWatcher *const watcher; |
361 | KFilePlacesViewDelegate *delegate; |
362 | QTimer pollDevices; |
363 | int pollingRequestCount; |
364 | }; |
365 | |
366 | KFilePlacesView::KFilePlacesView(QWidget *parent) |
367 | : QListView(parent), d(new Private(this)) |
368 | { |
369 | d->showAll = false; |
370 | d->smoothItemResizing = false; |
371 | d->dropOnPlace = false; |
372 | d->autoResizeItems = true; |
373 | d->dragging = false; |
374 | d->lastClickedStorage = 0; |
375 | d->pollingRequestCount = 0; |
376 | d->delegate = new KFilePlacesViewDelegate(this); |
377 | |
378 | setSelectionRectVisible(false); |
379 | setSelectionMode(SingleSelection); |
380 | |
381 | setDragEnabled(true); |
382 | setAcceptDrops(true); |
383 | setMouseTracking(true); |
384 | setDropIndicatorShown(false); |
385 | setFrameStyle(QFrame::NoFrame); |
386 | |
387 | setResizeMode(Adjust); |
388 | setItemDelegate(d->delegate); |
389 | |
390 | QPalette palette = viewport()->palette(); |
391 | palette.setColor(viewport()->backgroundRole(), Qt::transparent); |
392 | palette.setColor(viewport()->foregroundRole(), palette.color(QPalette::WindowText)); |
393 | viewport()->setPalette(palette); |
394 | |
395 | connect(this, SIGNAL(clicked(QModelIndex)), |
396 | this, SLOT(_k_placeClicked(QModelIndex))); |
397 | // Note: Don't connect to the activated() signal, as the behavior when it is |
398 | // committed depends on the used widget style. The click behavior of |
399 | // KFilePlacesView should be style independent. |
400 | |
401 | connect(&d->adaptItemsTimeline, SIGNAL(valueChanged(qreal)), |
402 | this, SLOT(_k_adaptItemsUpdate(qreal))); |
403 | d->adaptItemsTimeline.setDuration(500); |
404 | d->adaptItemsTimeline.setUpdateInterval(5); |
405 | d->adaptItemsTimeline.setCurveShape(QTimeLine::EaseInOutCurve); |
406 | |
407 | connect(&d->itemAppearTimeline, SIGNAL(valueChanged(qreal)), |
408 | this, SLOT(_k_itemAppearUpdate(qreal))); |
409 | d->itemAppearTimeline.setDuration(500); |
410 | d->itemAppearTimeline.setUpdateInterval(5); |
411 | d->itemAppearTimeline.setCurveShape(QTimeLine::EaseInOutCurve); |
412 | |
413 | connect(&d->itemDisappearTimeline, SIGNAL(valueChanged(qreal)), |
414 | this, SLOT(_k_itemDisappearUpdate(qreal))); |
415 | d->itemDisappearTimeline.setDuration(500); |
416 | d->itemDisappearTimeline.setUpdateInterval(5); |
417 | d->itemDisappearTimeline.setCurveShape(QTimeLine::EaseInOutCurve); |
418 | |
419 | viewport()->installEventFilter(d->watcher); |
420 | connect(d->watcher, SIGNAL(entryEntered(QModelIndex)), |
421 | this, SLOT(_k_placeEntered(QModelIndex))); |
422 | connect(d->watcher, SIGNAL(entryLeft(QModelIndex)), |
423 | this, SLOT(_k_placeLeft(QModelIndex))); |
424 | |
425 | d->pollDevices.setInterval(5000); |
426 | connect(&d->pollDevices, SIGNAL(timeout()), this, SLOT(_k_triggerDevicePolling())); |
427 | |
428 | // FIXME: this is necessary to avoid flashes of black with some widget styles. |
429 | // could be a bug in Qt (e.g. QAbstractScrollArea) or KFilePlacesView, but has not |
430 | // yet been tracked down yet. until then, this works and is harmlessly enough. |
431 | // in fact, some QStyle (Oxygen, Skulpture, others?) do this already internally. |
432 | // See br #242358 for more information |
433 | verticalScrollBar()->setAttribute(Qt::WA_OpaquePaintEvent, false); |
434 | } |
435 | |
436 | KFilePlacesView::~KFilePlacesView() |
437 | { |
438 | delete d; |
439 | } |
440 | |
441 | void KFilePlacesView::setDropOnPlaceEnabled(bool enabled) |
442 | { |
443 | d->dropOnPlace = enabled; |
444 | } |
445 | |
446 | bool KFilePlacesView::isDropOnPlaceEnabled() const |
447 | { |
448 | return d->dropOnPlace; |
449 | } |
450 | |
451 | void KFilePlacesView::setAutoResizeItemsEnabled(bool enabled) |
452 | { |
453 | d->autoResizeItems = enabled; |
454 | } |
455 | |
456 | bool KFilePlacesView::isAutoResizeItemsEnabled() const |
457 | { |
458 | return d->autoResizeItems; |
459 | } |
460 | |
461 | void KFilePlacesView::setUrl(const KUrl &url) |
462 | { |
463 | KUrl oldUrl = d->currentUrl; |
464 | KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(model()); |
465 | |
466 | if (placesModel==0) return; |
467 | |
468 | QModelIndex index = placesModel->closestItem(url); |
469 | QModelIndex current = selectionModel()->currentIndex(); |
470 | |
471 | if (index.isValid()) { |
472 | if (current!=index && placesModel->isHidden(current) && !d->showAll) { |
473 | KFilePlacesViewDelegate *delegate = static_cast<KFilePlacesViewDelegate*>(itemDelegate()); |
474 | delegate->addDisappearingItem(current); |
475 | |
476 | if (d->itemDisappearTimeline.state()!=QTimeLine::Running) { |
477 | delegate->setDisappearingItemProgress(0.0); |
478 | d->itemDisappearTimeline.start(); |
479 | } |
480 | } |
481 | |
482 | if (current!=index && placesModel->isHidden(index) && !d->showAll) { |
483 | KFilePlacesViewDelegate *delegate = static_cast<KFilePlacesViewDelegate*>(itemDelegate()); |
484 | delegate->addAppearingItem(index); |
485 | |
486 | if (d->itemAppearTimeline.state()!=QTimeLine::Running) { |
487 | delegate->setAppearingItemProgress(0.0); |
488 | d->itemAppearTimeline.start(); |
489 | } |
490 | |
491 | setRowHidden(index.row(), false); |
492 | } |
493 | |
494 | d->currentUrl = url; |
495 | selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect); |
496 | } else { |
497 | d->currentUrl = KUrl(); |
498 | selectionModel()->clear(); |
499 | } |
500 | |
501 | if (!current.isValid()) { |
502 | d->updateHiddenRows(); |
503 | } |
504 | } |
505 | |
506 | void KFilePlacesView::setShowAll(bool showAll) |
507 | { |
508 | KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(model()); |
509 | |
510 | if (placesModel==0) return; |
511 | |
512 | d->showAll = showAll; |
513 | |
514 | KFilePlacesViewDelegate *delegate = static_cast<KFilePlacesViewDelegate*>(itemDelegate()); |
515 | |
516 | int rowCount = placesModel->rowCount(); |
517 | QModelIndex current = placesModel->closestItem(d->currentUrl); |
518 | |
519 | if (showAll) { |
520 | d->updateHiddenRows(); |
521 | |
522 | for (int i=0; i<rowCount; ++i) { |
523 | QModelIndex index = placesModel->index(i, 0); |
524 | if (index!=current && placesModel->isHidden(index)) { |
525 | delegate->addAppearingItem(index); |
526 | } |
527 | } |
528 | |
529 | if (d->itemAppearTimeline.state()!=QTimeLine::Running) { |
530 | delegate->setAppearingItemProgress(0.0); |
531 | d->itemAppearTimeline.start(); |
532 | } |
533 | } else { |
534 | for (int i=0; i<rowCount; ++i) { |
535 | QModelIndex index = placesModel->index(i, 0); |
536 | if (index!=current && placesModel->isHidden(index)) { |
537 | delegate->addDisappearingItem(index); |
538 | } |
539 | } |
540 | |
541 | if (d->itemDisappearTimeline.state()!=QTimeLine::Running) { |
542 | delegate->setDisappearingItemProgress(0.0); |
543 | d->itemDisappearTimeline.start(); |
544 | } |
545 | } |
546 | } |
547 | |
548 | void KFilePlacesView::keyPressEvent(QKeyEvent *event) |
549 | { |
550 | QListView::keyPressEvent(event); |
551 | if ((event->key() == Qt::Key_Return) || (event->key() == Qt::Key_Enter)) { |
552 | d->_k_placeClicked(currentIndex()); |
553 | } |
554 | } |
555 | |
556 | void KFilePlacesView::(QContextMenuEvent *event) |
557 | { |
558 | KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(model()); |
559 | KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(itemDelegate()); |
560 | |
561 | if (placesModel==0) return; |
562 | |
563 | QModelIndex index = indexAt(event->pos()); |
564 | QString label = placesModel->text(index).replace('&',"&&" ); |
565 | |
566 | KMenu ; |
567 | |
568 | QAction *edit = 0; |
569 | QAction *hide = 0; |
570 | QAction *emptyTrash = 0; |
571 | QAction *eject = 0; |
572 | QAction *teardown = 0; |
573 | QAction *add = 0; |
574 | QAction *mainSeparator = 0; |
575 | |
576 | if (index.isValid()) { |
577 | if (!placesModel->isDevice(index)) { |
578 | if (placesModel->url(index) == KUrl("trash:/" )) { |
579 | emptyTrash = menu.addAction(KIcon("trash-empty" ), i18nc("@action:inmenu" , "Empty Trash" )); |
580 | KConfig trashConfig("trashrc" , KConfig::SimpleConfig); |
581 | emptyTrash->setEnabled(!trashConfig.group("Status" ).readEntry("Empty" , true)); |
582 | menu.addSeparator(); |
583 | } |
584 | add = menu.addAction(KIcon("document-new" ), i18n("Add Entry..." )); |
585 | mainSeparator = menu.addSeparator(); |
586 | edit = menu.addAction(KIcon("document-properties" ), i18n("&Edit Entry '%1'..." , label)); |
587 | } else { |
588 | eject = placesModel->ejectActionForIndex(index); |
589 | if (eject!=0) { |
590 | eject->setParent(&menu); |
591 | menu.addAction(eject); |
592 | } |
593 | |
594 | teardown = placesModel->teardownActionForIndex(index); |
595 | if (teardown!=0) { |
596 | teardown->setParent(&menu); |
597 | menu.addAction(teardown); |
598 | } |
599 | |
600 | if (teardown!=0 || eject!=0) { |
601 | mainSeparator = menu.addSeparator(); |
602 | } |
603 | } |
604 | if (add == 0) { |
605 | add = menu.addAction(KIcon("document-new" ), i18n("Add Entry..." )); |
606 | } |
607 | |
608 | hide = menu.addAction(i18n("&Hide Entry '%1'" , label)); |
609 | hide->setCheckable(true); |
610 | hide->setChecked(placesModel->isHidden(index)); |
611 | } else { |
612 | add = menu.addAction(KIcon("document-new" ), i18n("Add Entry..." )); |
613 | } |
614 | |
615 | QAction *showAll = 0; |
616 | if (placesModel->hiddenCount()>0) { |
617 | showAll = new QAction(i18n("&Show All Entries" ), &menu); |
618 | showAll->setCheckable(true); |
619 | showAll->setChecked(d->showAll); |
620 | if (mainSeparator == 0) { |
621 | mainSeparator = menu.addSeparator(); |
622 | } |
623 | menu.insertAction(mainSeparator, showAll); |
624 | } |
625 | |
626 | QAction* remove = 0; |
627 | if (index.isValid() && !placesModel->isDevice(index)) { |
628 | remove = menu.addAction( KIcon("edit-delete" ), i18n("&Remove Entry '%1'" , label)); |
629 | } |
630 | |
631 | menu.addActions(actions()); |
632 | |
633 | if (menu.isEmpty()) { |
634 | return; |
635 | } |
636 | |
637 | QAction *result = menu.exec(event->globalPos()); |
638 | |
639 | if (emptyTrash != 0 && result == emptyTrash) { |
640 | const QString text = i18nc("@info" , "Do you really want to empty the Trash? All items will be deleted." ); |
641 | const bool del = KMessageBox::warningContinueCancel(window(), |
642 | text, |
643 | QString(), |
644 | KGuiItem(i18nc("@action:button" , "Empty Trash" ), |
645 | KIcon("user-trash" )) |
646 | ) == KMessageBox::Continue; |
647 | if (del) { |
648 | QByteArray packedArgs; |
649 | QDataStream stream(&packedArgs, QIODevice::WriteOnly); |
650 | stream << int(1); |
651 | KIO::Job *job = KIO::special(KUrl("trash:/" ), packedArgs); |
652 | KNotification::event("Trash: emptied" , QString() , QPixmap() , 0, KNotification::DefaultEvent); |
653 | job->ui()->setWindow(parentWidget()); |
654 | connect(job, SIGNAL(result(KJob*)), SLOT(_k_trashUpdated(KJob*))); |
655 | } |
656 | } else if (edit != 0 && result == edit) { |
657 | KBookmark bookmark = placesModel->bookmarkForIndex(index); |
658 | KUrl url = bookmark.url(); |
659 | QString label = bookmark.text(); |
660 | QString iconName = bookmark.icon(); |
661 | bool appLocal = !bookmark.metaDataItem("OnlyInApp" ).isEmpty(); |
662 | |
663 | if (KFilePlaceEditDialog::getInformation(true, url, label, |
664 | iconName, false, appLocal, 64, this)) |
665 | { |
666 | QString appName; |
667 | if (appLocal) appName = KGlobal::mainComponent().componentName(); |
668 | |
669 | placesModel->editPlace(index, label, url, iconName, appName); |
670 | } |
671 | |
672 | } else if (remove != 0 && result == remove) { |
673 | placesModel->removePlace(index); |
674 | } else if (hide != 0 && result == hide) { |
675 | placesModel->setPlaceHidden(index, hide->isChecked()); |
676 | QModelIndex current = placesModel->closestItem(d->currentUrl); |
677 | |
678 | if (index!=current && !d->showAll && hide->isChecked()) { |
679 | delegate->addDisappearingItem(index); |
680 | |
681 | if (d->itemDisappearTimeline.state()!=QTimeLine::Running) { |
682 | delegate->setDisappearingItemProgress(0.0); |
683 | d->itemDisappearTimeline.start(); |
684 | } |
685 | } |
686 | } else if (showAll != 0 && result == showAll) { |
687 | setShowAll(showAll->isChecked()); |
688 | } else if (teardown != 0 && result == teardown) { |
689 | placesModel->requestTeardown(index); |
690 | } else if (eject != 0 && result == eject) { |
691 | placesModel->requestEject(index); |
692 | } else if (add != 0 && result == add) { |
693 | KUrl url = d->currentUrl; |
694 | QString label; |
695 | QString iconName = "folder" ; |
696 | bool appLocal = true; |
697 | if (KFilePlaceEditDialog::getInformation(true, url, label, |
698 | iconName, true, appLocal, 64, this)) |
699 | { |
700 | QString appName; |
701 | if (appLocal) appName = KGlobal::mainComponent().componentName(); |
702 | |
703 | placesModel->addPlace(label, url, iconName, appName, index); |
704 | } |
705 | } |
706 | |
707 | index = placesModel->closestItem(d->currentUrl); |
708 | selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect); |
709 | } |
710 | |
711 | void KFilePlacesView::resizeEvent(QResizeEvent *event) |
712 | { |
713 | QListView::resizeEvent(event); |
714 | d->adaptItemSize(); |
715 | } |
716 | |
717 | void KFilePlacesView::showEvent(QShowEvent *event) |
718 | { |
719 | QListView::showEvent(event); |
720 | QTimer::singleShot(100, this, SLOT(_k_enableSmoothItemResizing())); |
721 | } |
722 | |
723 | void KFilePlacesView::hideEvent(QHideEvent *event) |
724 | { |
725 | QListView::hideEvent(event); |
726 | d->smoothItemResizing = false; |
727 | } |
728 | |
729 | void KFilePlacesView::dragEnterEvent(QDragEnterEvent *event) |
730 | { |
731 | QListView::dragEnterEvent(event); |
732 | d->dragging = true; |
733 | |
734 | KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(itemDelegate()); |
735 | delegate->setShowHoverIndication(false); |
736 | |
737 | d->dropRect = QRect(); |
738 | } |
739 | |
740 | void KFilePlacesView::dragLeaveEvent(QDragLeaveEvent *event) |
741 | { |
742 | QListView::dragLeaveEvent(event); |
743 | d->dragging = false; |
744 | |
745 | KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(itemDelegate()); |
746 | delegate->setShowHoverIndication(true); |
747 | |
748 | setDirtyRegion(d->dropRect); |
749 | } |
750 | |
751 | void KFilePlacesView::dragMoveEvent(QDragMoveEvent *event) |
752 | { |
753 | QListView::dragMoveEvent(event); |
754 | |
755 | // update the drop indicator |
756 | const QPoint pos = event->pos(); |
757 | const QModelIndex index = indexAt(pos); |
758 | setDirtyRegion(d->dropRect); |
759 | if (index.isValid()) { |
760 | const QRect rect = visualRect(index); |
761 | const int gap = d->insertIndicatorHeight(rect.height()); |
762 | if (d->insertAbove(rect, pos)) { |
763 | // indicate that the item will be inserted above the current place |
764 | d->dropRect = QRect(rect.left(), rect.top() - gap / 2, |
765 | rect.width(), gap); |
766 | } else if (d->insertBelow(rect, pos)) { |
767 | // indicate that the item will be inserted below the current place |
768 | d->dropRect = QRect(rect.left(), rect.bottom() + 1 - gap / 2, |
769 | rect.width(), gap); |
770 | } else { |
771 | // indicate that the item be dropped above the current place |
772 | d->dropRect = rect; |
773 | } |
774 | } |
775 | |
776 | setDirtyRegion(d->dropRect); |
777 | } |
778 | |
779 | void KFilePlacesView::dropEvent(QDropEvent *event) |
780 | { |
781 | const QPoint pos = event->pos(); |
782 | const QModelIndex index = indexAt(pos); |
783 | if (index.isValid()) { |
784 | const QRect rect = visualRect(index); |
785 | if (!d->insertAbove(rect, pos) && !d->insertBelow(rect, pos)) { |
786 | KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(model()); |
787 | Q_ASSERT(placesModel != 0); |
788 | emit urlsDropped(placesModel->url(index), event, this); |
789 | event->acceptProposedAction(); |
790 | } |
791 | } |
792 | |
793 | QListView::dropEvent(event); |
794 | d->dragging = false; |
795 | |
796 | KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(itemDelegate()); |
797 | delegate->setShowHoverIndication(true); |
798 | } |
799 | |
800 | void KFilePlacesView::paintEvent(QPaintEvent* event) |
801 | { |
802 | QListView::paintEvent(event); |
803 | if (d->dragging && !d->dropRect.isEmpty()) { |
804 | // draw drop indicator |
805 | QPainter painter(viewport()); |
806 | |
807 | const QModelIndex index = indexAt(d->dropRect.topLeft()); |
808 | const QRect itemRect = visualRect(index); |
809 | const bool drawInsertIndicator = !d->dropOnPlace || |
810 | d->dropRect.height() <= d->insertIndicatorHeight(itemRect.height()); |
811 | |
812 | if (drawInsertIndicator) { |
813 | // draw indicator for inserting items |
814 | QBrush blendedBrush = viewOptions().palette.brush(QPalette::Normal, QPalette::Highlight); |
815 | QColor color = blendedBrush.color(); |
816 | |
817 | const int y = (d->dropRect.top() + d->dropRect.bottom()) / 2; |
818 | const int thickness = d->dropRect.height() / 2; |
819 | Q_ASSERT(thickness >= 1); |
820 | int alpha = 255; |
821 | const int alphaDec = alpha / (thickness + 1); |
822 | for (int i = 0; i < thickness; i++) { |
823 | color.setAlpha(alpha); |
824 | alpha -= alphaDec; |
825 | painter.setPen(color); |
826 | painter.drawLine(d->dropRect.left(), y - i, d->dropRect.right(), y - i); |
827 | painter.drawLine(d->dropRect.left(), y + i, d->dropRect.right(), y + i); |
828 | } |
829 | } else { |
830 | // draw indicator for copying/moving/linking to items |
831 | QStyleOptionViewItemV4 opt; |
832 | opt.initFrom(this); |
833 | opt.rect = itemRect; |
834 | opt.state = QStyle::State_Enabled | QStyle::State_MouseOver; |
835 | style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, &painter, this); |
836 | } |
837 | } |
838 | } |
839 | |
840 | void KFilePlacesView::setModel(QAbstractItemModel *model) |
841 | { |
842 | QListView::setModel(model); |
843 | d->updateHiddenRows(); |
844 | // Uses Qt::QueuedConnection to delay the time when the slot will be |
845 | // called. In case of an item move the remove+add will be done before |
846 | // we adapt the item size (otherwise we'd get it wrong as we'd execute |
847 | // it after the remove only). |
848 | connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), |
849 | this, SLOT(adaptItemSize()), Qt::QueuedConnection); |
850 | connect(selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), |
851 | d->watcher, SLOT(currentIndexChanged(QModelIndex))); |
852 | } |
853 | |
854 | void KFilePlacesView::rowsInserted(const QModelIndex &parent, int start, int end) |
855 | { |
856 | QListView::rowsInserted(parent, start, end); |
857 | setUrl(d->currentUrl); |
858 | |
859 | KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(itemDelegate()); |
860 | KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(model()); |
861 | |
862 | for (int i=start; i<=end; ++i) { |
863 | QModelIndex index = placesModel->index(i, 0, parent); |
864 | if (d->showAll || !placesModel->isHidden(index)) { |
865 | delegate->addAppearingItem(index); |
866 | } else { |
867 | setRowHidden(i, true); |
868 | } |
869 | } |
870 | |
871 | if (d->itemAppearTimeline.state()!=QTimeLine::Running) { |
872 | delegate->setAppearingItemProgress(0.0); |
873 | d->itemAppearTimeline.start(); |
874 | } |
875 | |
876 | d->adaptItemSize(); |
877 | } |
878 | |
879 | QSize KFilePlacesView::sizeHint() const |
880 | { |
881 | KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(model()); |
882 | if (!placesModel) { |
883 | return QListView::sizeHint(); |
884 | } |
885 | const int height = QListView::sizeHint().height(); |
886 | QFontMetrics fm = d->q->fontMetrics(); |
887 | int textWidth = 0; |
888 | |
889 | for (int i=0; i<placesModel->rowCount(); ++i) { |
890 | QModelIndex index = placesModel->index(i, 0); |
891 | if (!placesModel->isHidden(index)) |
892 | textWidth = qMax(textWidth,fm.width(index.data(Qt::DisplayRole).toString())); |
893 | } |
894 | |
895 | const int iconSize = KIconLoader::global()->currentSize(KIconLoader::Small) + 3 * LATERAL_MARGIN; |
896 | return QSize(iconSize + textWidth + fm.height() / 2, height); |
897 | } |
898 | |
899 | void KFilePlacesView::Private::setCurrentIndex(const QModelIndex &index) |
900 | { |
901 | KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(q->model()); |
902 | |
903 | if (placesModel==0) return; |
904 | |
905 | KUrl url = placesModel->url(index); |
906 | |
907 | if (url.isValid()) { |
908 | currentUrl = url; |
909 | updateHiddenRows(); |
910 | emit q->urlChanged(url); |
911 | if (showAll) { |
912 | q->setShowAll(false); |
913 | } |
914 | } else { |
915 | q->setUrl(currentUrl); |
916 | } |
917 | } |
918 | |
919 | void KFilePlacesView::Private::adaptItemSize() |
920 | { |
921 | KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(q->itemDelegate()); |
922 | if (!delegate) return; |
923 | |
924 | if (!autoResizeItems) { |
925 | int size = q->iconSize().width(); // Assume width == height |
926 | delegate->setIconSize(size); |
927 | q->scheduleDelayedItemsLayout(); |
928 | return; |
929 | } |
930 | |
931 | KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(q->model()); |
932 | |
933 | if (placesModel==0) return; |
934 | |
935 | int rowCount = placesModel->rowCount(); |
936 | |
937 | if (!showAll) { |
938 | rowCount-= placesModel->hiddenCount(); |
939 | |
940 | QModelIndex current = placesModel->closestItem(currentUrl); |
941 | |
942 | if (placesModel->isHidden(current)) { |
943 | rowCount++; |
944 | } |
945 | } |
946 | |
947 | if (rowCount==0) return; // We've nothing to display anyway |
948 | |
949 | const int minSize = IconSize(KIconLoader::Small); |
950 | const int maxSize = 64; |
951 | |
952 | int textWidth = 0; |
953 | QFontMetrics fm = q->fontMetrics(); |
954 | for (int i=0; i<placesModel->rowCount(); ++i) { |
955 | QModelIndex index = placesModel->index(i, 0); |
956 | |
957 | if (!placesModel->isHidden(index)) |
958 | textWidth = qMax(textWidth,fm.width(index.data(Qt::DisplayRole).toString())); |
959 | } |
960 | |
961 | const int margin = q->style()->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, q) + 1; |
962 | const int maxWidth = q->viewport()->width() - textWidth - 4 * margin - 1; |
963 | const int maxHeight = ((q->height() - (fm.height() / 2) * rowCount) / rowCount) - 1; |
964 | |
965 | int size = qMin(maxHeight, maxWidth); |
966 | |
967 | if (size<minSize) { |
968 | size = minSize; |
969 | } else if (size>maxSize) { |
970 | size = maxSize; |
971 | } else { |
972 | // Make it a multiple of 16 |
973 | size &= ~0xf; |
974 | } |
975 | |
976 | if (size==delegate->iconSize()) return; |
977 | |
978 | if (smoothItemResizing) { |
979 | oldSize = delegate->iconSize(); |
980 | endSize = size; |
981 | if (adaptItemsTimeline.state()!=QTimeLine::Running) { |
982 | adaptItemsTimeline.start(); |
983 | } |
984 | } else { |
985 | delegate->setIconSize(size); |
986 | q->scheduleDelayedItemsLayout(); |
987 | } |
988 | } |
989 | |
990 | void KFilePlacesView::Private::updateHiddenRows() |
991 | { |
992 | KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(q->model()); |
993 | |
994 | if (placesModel==0) return; |
995 | |
996 | int rowCount = placesModel->rowCount(); |
997 | QModelIndex current = placesModel->closestItem(currentUrl); |
998 | |
999 | for (int i=0; i<rowCount; ++i) { |
1000 | QModelIndex index = placesModel->index(i, 0); |
1001 | if (index!=current && placesModel->isHidden(index) && !showAll) { |
1002 | q->setRowHidden(i, true); |
1003 | } else { |
1004 | q->setRowHidden(i, false); |
1005 | } |
1006 | } |
1007 | |
1008 | adaptItemSize(); |
1009 | } |
1010 | |
1011 | bool KFilePlacesView::Private::insertAbove(const QRect &itemRect, const QPoint &pos) const |
1012 | { |
1013 | if (dropOnPlace) { |
1014 | return pos.y() < itemRect.top() + insertIndicatorHeight(itemRect.height()) / 2; |
1015 | } |
1016 | |
1017 | return pos.y() < itemRect.top() + (itemRect.height() / 2); |
1018 | } |
1019 | |
1020 | bool KFilePlacesView::Private::insertBelow(const QRect &itemRect, const QPoint &pos) const |
1021 | { |
1022 | if (dropOnPlace) { |
1023 | return pos.y() > itemRect.bottom() - insertIndicatorHeight(itemRect.height()) / 2; |
1024 | } |
1025 | |
1026 | return pos.y() >= itemRect.top() + (itemRect.height() / 2); |
1027 | } |
1028 | |
1029 | int KFilePlacesView::Private::insertIndicatorHeight(int itemHeight) const |
1030 | { |
1031 | const int min = 4; |
1032 | const int max = 12; |
1033 | |
1034 | int height = itemHeight / 4; |
1035 | if (height < min) { |
1036 | height = min; |
1037 | } else if (height > max) { |
1038 | height = max; |
1039 | } |
1040 | return height; |
1041 | } |
1042 | |
1043 | void KFilePlacesView::Private::fadeCapacityBar(const QModelIndex &index, FadeType fadeType) |
1044 | { |
1045 | QTimeLine *timeLine = delegate->fadeAnimationForIndex(index); |
1046 | delete timeLine; |
1047 | delegate->removeFadeAnimation(index); |
1048 | timeLine = new QTimeLine(250, q); |
1049 | connect(timeLine, SIGNAL(valueChanged(qreal)), q, SLOT(_k_capacityBarFadeValueChanged())); |
1050 | if (fadeType == FadeIn) { |
1051 | timeLine->setDirection(QTimeLine::Forward); |
1052 | timeLine->setCurrentTime(0); |
1053 | } else { |
1054 | timeLine->setDirection(QTimeLine::Backward); |
1055 | timeLine->setCurrentTime(250); |
1056 | } |
1057 | delegate->addFadeAnimation(index, timeLine); |
1058 | timeLine->start(); |
1059 | } |
1060 | |
1061 | void KFilePlacesView::Private::_k_placeClicked(const QModelIndex &index) |
1062 | { |
1063 | KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(q->model()); |
1064 | |
1065 | if (placesModel==0) return; |
1066 | |
1067 | lastClickedIndex = QPersistentModelIndex(); |
1068 | |
1069 | if (placesModel->setupNeeded(index)) { |
1070 | QObject::connect(placesModel, SIGNAL(setupDone(QModelIndex,bool)), |
1071 | q, SLOT(_k_storageSetupDone(QModelIndex,bool))); |
1072 | |
1073 | lastClickedIndex = index; |
1074 | placesModel->requestSetup(index); |
1075 | return; |
1076 | } |
1077 | |
1078 | setCurrentIndex(index); |
1079 | } |
1080 | |
1081 | void KFilePlacesView::Private::_k_placeEntered(const QModelIndex &index) |
1082 | { |
1083 | fadeCapacityBar(index, FadeIn); |
1084 | pollingRequestCount++; |
1085 | if (pollingRequestCount == 1) { |
1086 | pollDevices.start(); |
1087 | } |
1088 | } |
1089 | |
1090 | void KFilePlacesView::Private::_k_placeLeft(const QModelIndex &index) |
1091 | { |
1092 | fadeCapacityBar(index, FadeOut); |
1093 | pollingRequestCount--; |
1094 | if (!pollingRequestCount) { |
1095 | pollDevices.stop(); |
1096 | } |
1097 | } |
1098 | |
1099 | void KFilePlacesView::Private::_k_storageSetupDone(const QModelIndex &index, bool success) |
1100 | { |
1101 | if (index!=lastClickedIndex) { |
1102 | return; |
1103 | } |
1104 | |
1105 | KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(q->model()); |
1106 | |
1107 | QObject::disconnect(placesModel, SIGNAL(setupDone(QModelIndex,bool)), |
1108 | q, SLOT(_k_storageSetupDone(QModelIndex,bool))); |
1109 | |
1110 | if (success) { |
1111 | setCurrentIndex(lastClickedIndex); |
1112 | } else { |
1113 | q->setUrl(currentUrl); |
1114 | } |
1115 | |
1116 | lastClickedIndex = QPersistentModelIndex(); |
1117 | } |
1118 | |
1119 | void KFilePlacesView::Private::_k_adaptItemsUpdate(qreal value) |
1120 | { |
1121 | int add = (endSize-oldSize)*value; |
1122 | |
1123 | int size = oldSize+add; |
1124 | |
1125 | KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(q->itemDelegate()); |
1126 | delegate->setIconSize(size); |
1127 | q->scheduleDelayedItemsLayout(); |
1128 | } |
1129 | |
1130 | void KFilePlacesView::Private::_k_itemAppearUpdate(qreal value) |
1131 | { |
1132 | KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(q->itemDelegate()); |
1133 | |
1134 | delegate->setAppearingItemProgress(value); |
1135 | q->scheduleDelayedItemsLayout(); |
1136 | } |
1137 | |
1138 | void KFilePlacesView::Private::_k_itemDisappearUpdate(qreal value) |
1139 | { |
1140 | KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(q->itemDelegate()); |
1141 | |
1142 | delegate->setDisappearingItemProgress(value); |
1143 | |
1144 | if (value>=1.0) { |
1145 | updateHiddenRows(); |
1146 | } |
1147 | |
1148 | q->scheduleDelayedItemsLayout(); |
1149 | } |
1150 | |
1151 | void KFilePlacesView::Private::_k_enableSmoothItemResizing() |
1152 | { |
1153 | smoothItemResizing = true; |
1154 | } |
1155 | |
1156 | void KFilePlacesView::Private::_k_trashUpdated(KJob *job) |
1157 | { |
1158 | if (job->error()) { |
1159 | static_cast<KIO::Job*>(job)->ui()->showErrorMessage(); |
1160 | } |
1161 | org::kde::KDirNotify::emitFilesAdded("trash:/" ); |
1162 | } |
1163 | |
1164 | void KFilePlacesView::Private::_k_capacityBarFadeValueChanged() |
1165 | { |
1166 | const QModelIndex index = delegate->indexForFadeAnimation(static_cast<QTimeLine*>(q->sender())); |
1167 | if (!index.isValid()) { |
1168 | return; |
1169 | } |
1170 | q->update(index); |
1171 | } |
1172 | |
1173 | void KFilePlacesView::Private::_k_triggerDevicePolling() |
1174 | { |
1175 | const QModelIndex hoveredIndex = watcher->hoveredIndex(); |
1176 | if (hoveredIndex.isValid()) { |
1177 | const KFilePlacesModel *placesModel = static_cast<const KFilePlacesModel*>(hoveredIndex.model()); |
1178 | if (placesModel->isDevice(hoveredIndex)) { |
1179 | q->update(hoveredIndex); |
1180 | } |
1181 | } |
1182 | const QModelIndex focusedIndex = watcher->focusedIndex(); |
1183 | if (focusedIndex.isValid() && focusedIndex != hoveredIndex) { |
1184 | const KFilePlacesModel *placesModel = static_cast<const KFilePlacesModel*>(focusedIndex.model()); |
1185 | if (placesModel->isDevice(focusedIndex)) { |
1186 | q->update(focusedIndex); |
1187 | } |
1188 | } |
1189 | } |
1190 | |
1191 | void KFilePlacesView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) |
1192 | { |
1193 | QListView::dataChanged(topLeft, bottomRight); |
1194 | d->adaptItemSize(); |
1195 | } |
1196 | |
1197 | #include "kfileplacesview.moc" |
1198 | #include "kfileplacesview_p.moc" |
1199 | |