00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kfileplacesview.h"
00021
00022 #include <QtCore/QTimeLine>
00023 #include <QtCore/QTimer>
00024 #include <QtGui/QMenu>
00025 #include <QtGui/QPainter>
00026 #include <QtGui/QStyledItemDelegate>
00027 #include <QtGui/QKeyEvent>
00028
00029 #include <kdebug.h>
00030
00031 #include <kcomponentdata.h>
00032 #include <kdirnotify.h>
00033 #include <kglobalsettings.h>
00034 #include <kiconloader.h>
00035 #include <klocale.h>
00036 #include <kmessagebox.h>
00037 #include <knotification.h>
00038 #include <kio/job.h>
00039 #include <kio/jobuidelegate.h>
00040 #include <kjob.h>
00041 #include <solid/storageaccess.h>
00042 #include <solid/storagedrive.h>
00043 #include <solid/storagevolume.h>
00044 #include <solid/opticaldrive.h>
00045 #include <solid/opticaldisc.h>
00046
00047 #include "kfileplaceeditdialog.h"
00048 #include "kfileplacesmodel.h"
00049
00050 class KFilePlacesViewDelegate : public QStyledItemDelegate
00051 {
00052 public:
00053 KFilePlacesViewDelegate(KFilePlacesView *parent);
00054 virtual ~KFilePlacesViewDelegate();
00055 virtual QSize sizeHint(const QStyleOptionViewItem &option,
00056 const QModelIndex &index) const;
00057 virtual void paint(QPainter *painter,
00058 const QStyleOptionViewItem &option,
00059 const QModelIndex &index) const;
00060
00061 int iconSize() const;
00062 void setIconSize(int newSize);
00063
00064 void addAppearingItem(const QModelIndex &index);
00065 void setAppearingItemProgress(qreal value);
00066 void addDisappearingItem(const QModelIndex &index);
00067 void setDisappearingItemProgress(qreal value);
00068
00069 void setShowHoverIndication(bool show);
00070
00071 private:
00072 KFilePlacesView *m_view;
00073 int m_iconSize;
00074
00075 QList<QPersistentModelIndex> m_appearingItems;
00076 int m_appearingIconSize;
00077 qreal m_appearingOpacity;
00078
00079 QList<QPersistentModelIndex> m_disappearingItems;
00080 int m_disappearingIconSize;
00081 qreal m_disappearingOpacity;
00082
00083 bool m_showHoverIndication;
00084 };
00085
00086 KFilePlacesViewDelegate::KFilePlacesViewDelegate(KFilePlacesView *parent) :
00087 QStyledItemDelegate(parent),
00088 m_view(parent),
00089 m_iconSize(48),
00090 m_appearingIconSize(0),
00091 m_appearingOpacity(0.0),
00092 m_disappearingIconSize(0),
00093 m_disappearingOpacity(0.0),
00094 m_showHoverIndication(true)
00095 {
00096 }
00097
00098 KFilePlacesViewDelegate::~KFilePlacesViewDelegate()
00099 {
00100 }
00101
00102 QSize KFilePlacesViewDelegate::sizeHint(const QStyleOptionViewItem &option,
00103 const QModelIndex &index) const
00104 {
00105 QSize size = QStyledItemDelegate::sizeHint(option, index);
00106 int iconSize = m_iconSize;
00107 if (m_appearingItems.contains(index)) {
00108 iconSize = m_appearingIconSize;
00109 } else if (m_disappearingItems.contains(index)) {
00110 iconSize = m_disappearingIconSize;
00111 }
00112
00113 size.setHeight(iconSize + KDialog::marginHint());
00114 return size;
00115 }
00116
00117 void KFilePlacesViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
00118 {
00119 painter->save();
00120
00121 if (m_appearingItems.contains(index)) {
00122 painter->setOpacity(m_appearingOpacity);
00123 } else if (m_disappearingItems.contains(index)) {
00124 painter->setOpacity(m_disappearingOpacity);
00125 }
00126
00127 QStyleOptionViewItemV4 opt = option;
00128 opt.decorationSize = QSize(m_iconSize, m_iconSize);
00129 if (!m_showHoverIndication) {
00130 opt.state &= ~QStyle::State_MouseOver;
00131 }
00132 QStyledItemDelegate::paint(painter, opt, index);
00133
00134 painter->restore();
00135 }
00136
00137 int KFilePlacesViewDelegate::iconSize() const
00138 {
00139 return m_iconSize;
00140 }
00141
00142 void KFilePlacesViewDelegate::setIconSize(int newSize)
00143 {
00144 m_iconSize = newSize;
00145 }
00146
00147 void KFilePlacesViewDelegate::addAppearingItem(const QModelIndex &index)
00148 {
00149 m_appearingItems << index;
00150 }
00151
00152 void KFilePlacesViewDelegate::setAppearingItemProgress(qreal value)
00153 {
00154 if (value<=0.25) {
00155 m_appearingOpacity = 0.0;
00156 m_appearingIconSize = iconSize()*value*4;
00157
00158 if (m_appearingIconSize>=m_iconSize) {
00159 m_appearingIconSize = m_iconSize;
00160 }
00161 } else {
00162 m_appearingIconSize = m_iconSize;
00163 m_appearingOpacity = (value-0.25)*4/3;
00164
00165 if (value>=1.0) {
00166 m_appearingItems.clear();
00167 }
00168 }
00169 }
00170
00171 void KFilePlacesViewDelegate::addDisappearingItem(const QModelIndex &index)
00172 {
00173 m_disappearingItems << index;
00174 }
00175
00176 void KFilePlacesViewDelegate::setDisappearingItemProgress(qreal value)
00177 {
00178 value = 1.0 - value;
00179
00180 if (value<=0.25) {
00181 m_disappearingOpacity = 0.0;
00182 m_disappearingIconSize = iconSize()*value*4;
00183
00184 if (m_disappearingIconSize>=m_iconSize) {
00185 m_disappearingIconSize = m_iconSize;
00186 }
00187
00188 if (value<=0.0) {
00189 m_disappearingItems.clear();
00190 }
00191 } else {
00192 m_disappearingIconSize = m_iconSize;
00193 m_disappearingOpacity = (value-0.25)*4/3;
00194 }
00195 }
00196
00197 void KFilePlacesViewDelegate::setShowHoverIndication(bool show)
00198 {
00199 m_showHoverIndication = show;
00200 }
00201
00202 class KFilePlacesView::Private
00203 {
00204 public:
00205 Private(KFilePlacesView *parent) : q(parent) { }
00206
00207 KFilePlacesView * const q;
00208
00209 KUrl currentUrl;
00210 bool autoResizeItems;
00211 bool showAll;
00212 bool smoothItemResizing;
00213 bool dropOnPlace;
00214 bool dragging;
00215 Solid::StorageAccess *lastClickedStorage;
00216 QPersistentModelIndex lastClickedIndex;
00217
00218 QRect dropRect;
00219
00220 void setCurrentIndex(const QModelIndex &index);
00221 void adaptItemSize();
00222 void updateHiddenRows();
00223 bool insertAbove(const QRect &itemRect, const QPoint &pos) const;
00224 bool insertBelow(const QRect &itemRect, const QPoint &pos) const;
00225 int insertIndicatorHeight(int itemHeight) const;
00226
00227 void _k_placeClicked(const QModelIndex &index);
00228 void _k_placeActivated(const QModelIndex &index);
00229 void _k_storageSetupDone(const QModelIndex &index, bool success);
00230 void _k_adaptItemsUpdate(qreal value);
00231 void _k_itemAppearUpdate(qreal value);
00232 void _k_itemDisappearUpdate(qreal value);
00233 void _k_enableSmoothItemResizing();
00234 void _k_trashUpdated(KJob *job);
00235
00236 QTimeLine adaptItemsTimeline;
00237 int oldSize, endSize;
00238
00239 QTimeLine itemAppearTimeline;
00240 QTimeLine itemDisappearTimeline;
00241 };
00242
00243 KFilePlacesView::KFilePlacesView(QWidget *parent)
00244 : QListView(parent), d(new Private(this))
00245 {
00246 d->showAll = false;
00247 d->smoothItemResizing = false;
00248 d->dropOnPlace = false;
00249 d->autoResizeItems = true;
00250 d->dragging = false;
00251 d->lastClickedStorage = 0;
00252
00253 setSelectionRectVisible(false);
00254 setSelectionMode(SingleSelection);
00255
00256 setDragEnabled(true);
00257 setAcceptDrops(true);
00258 setDropIndicatorShown(false);
00259 setFrameStyle(QFrame::NoFrame);
00260
00261 setResizeMode(Adjust);
00262 setItemDelegate(new KFilePlacesViewDelegate(this));
00263
00264 QPalette palette = viewport()->palette();
00265 palette.setColor(viewport()->backgroundRole(), Qt::transparent);
00266 viewport()->setPalette(palette);
00267
00268 connect(this, SIGNAL(clicked(const QModelIndex&)),
00269 this, SLOT(_k_placeClicked(const QModelIndex&)));
00270 connect(this, SIGNAL(activated(const QModelIndex&)),
00271 this, SLOT(_k_placeActivated(const QModelIndex&)));
00272
00273 connect(&d->adaptItemsTimeline, SIGNAL(valueChanged(qreal)),
00274 this, SLOT(_k_adaptItemsUpdate(qreal)));
00275 d->adaptItemsTimeline.setDuration(500);
00276 d->adaptItemsTimeline.setUpdateInterval(5);
00277 d->adaptItemsTimeline.setCurveShape(QTimeLine::EaseInOutCurve);
00278
00279 connect(&d->itemAppearTimeline, SIGNAL(valueChanged(qreal)),
00280 this, SLOT(_k_itemAppearUpdate(qreal)));
00281 d->itemAppearTimeline.setDuration(500);
00282 d->itemAppearTimeline.setUpdateInterval(5);
00283 d->itemAppearTimeline.setCurveShape(QTimeLine::EaseInOutCurve);
00284
00285 connect(&d->itemDisappearTimeline, SIGNAL(valueChanged(qreal)),
00286 this, SLOT(_k_itemDisappearUpdate(qreal)));
00287 d->itemDisappearTimeline.setDuration(500);
00288 d->itemDisappearTimeline.setUpdateInterval(5);
00289 d->itemDisappearTimeline.setCurveShape(QTimeLine::EaseInOutCurve);
00290 }
00291
00292 KFilePlacesView::~KFilePlacesView()
00293 {
00294 delete d;
00295 }
00296
00297 void KFilePlacesView::setDropOnPlaceEnabled(bool enabled)
00298 {
00299 d->dropOnPlace = enabled;
00300 }
00301
00302 bool KFilePlacesView::isDropOnPlaceEnabled() const
00303 {
00304 return d->dropOnPlace;
00305 }
00306
00307 void KFilePlacesView::setAutoResizeItemsEnabled(bool enabled)
00308 {
00309 d->autoResizeItems = enabled;
00310 }
00311
00312 bool KFilePlacesView::isAutoResizeItemsEnabled() const
00313 {
00314 return d->autoResizeItems;
00315 }
00316
00317 void KFilePlacesView::setUrl(const KUrl &url)
00318 {
00319 KUrl oldUrl = d->currentUrl;
00320 KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(model());
00321
00322 if (placesModel==0) return;
00323
00324 QModelIndex index = placesModel->closestItem(url);
00325 QModelIndex current = selectionModel()->currentIndex();
00326
00327 if (index.isValid()) {
00328 if (current!=index && placesModel->isHidden(current)) {
00329 KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(itemDelegate());
00330 delegate->addDisappearingItem(current);
00331
00332 if (d->itemDisappearTimeline.state()!=QTimeLine::Running) {
00333 delegate->setDisappearingItemProgress(0.0);
00334 d->itemDisappearTimeline.start();
00335 }
00336 }
00337
00338 if (current!=index && placesModel->isHidden(index)) {
00339 KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(itemDelegate());
00340 delegate->addAppearingItem(index);
00341
00342 if (d->itemAppearTimeline.state()!=QTimeLine::Running) {
00343 delegate->setAppearingItemProgress(0.0);
00344 d->itemAppearTimeline.start();
00345 }
00346
00347 setRowHidden(index.row(), false);
00348 }
00349
00350 d->currentUrl = url;
00351 selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
00352 } else {
00353 d->currentUrl = KUrl();
00354 selectionModel()->clear();
00355 }
00356
00357 if (!current.isValid()) {
00358 d->updateHiddenRows();
00359 }
00360 }
00361
00362 void KFilePlacesView::setShowAll(bool showAll)
00363 {
00364 KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(model());
00365
00366 if (placesModel==0) return;
00367
00368 d->showAll = showAll;
00369
00370 KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(itemDelegate());
00371
00372 int rowCount = placesModel->rowCount();
00373 QModelIndex current = placesModel->closestItem(d->currentUrl);
00374
00375 if (showAll) {
00376 d->updateHiddenRows();
00377
00378 for (int i=0; i<rowCount; ++i) {
00379 QModelIndex index = placesModel->index(i, 0);
00380 if (index!=current && placesModel->isHidden(index)) {
00381 delegate->addAppearingItem(index);
00382 }
00383 }
00384
00385 if (d->itemAppearTimeline.state()!=QTimeLine::Running) {
00386 delegate->setAppearingItemProgress(0.0);
00387 d->itemAppearTimeline.start();
00388 }
00389 } else {
00390 for (int i=0; i<rowCount; ++i) {
00391 QModelIndex index = placesModel->index(i, 0);
00392 if (index!=current && placesModel->isHidden(index)) {
00393 delegate->addDisappearingItem(index);
00394 }
00395 }
00396
00397 if (d->itemDisappearTimeline.state()!=QTimeLine::Running) {
00398 delegate->setDisappearingItemProgress(0.0);
00399 d->itemDisappearTimeline.start();
00400 }
00401 }
00402 }
00403
00404 void KFilePlacesView::contextMenuEvent(QContextMenuEvent *event)
00405 {
00406 KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(model());
00407 KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(itemDelegate());
00408
00409 if (placesModel==0) return;
00410
00411 QModelIndex index = indexAt(event->pos());
00412 QString label = placesModel->text(index).replace('&',"&&");
00413
00414 QMenu menu;
00415
00416 QAction *edit = 0;
00417 QAction *hide = 0;
00418 QAction *emptyTrash = 0;
00419 if (index.isValid()) {
00420 if (!placesModel->isDevice(index)) {
00421 if (placesModel->url(index) == KUrl("trash:/")) {
00422 emptyTrash = menu.addAction(KIcon("trash-empty"), i18nc("@action:inmenu", "Empty Trash"));
00423 KConfig trashConfig("trashrc", KConfig::SimpleConfig);
00424 emptyTrash->setEnabled(!trashConfig.group("Status").readEntry("Empty", true));
00425 menu.addSeparator();
00426 }
00427
00428 edit = menu.addAction(KIcon("document-properties"), i18n("&Edit '%1'...", label));
00429 }
00430
00431 hide = menu.addAction(i18n("&Hide '%1'", label));
00432 hide->setCheckable(true);
00433 hide->setChecked(placesModel->isHidden(index));
00434 }
00435
00436 QAction *showAll = 0;
00437 if (placesModel->hiddenCount()>0) {
00438 showAll = menu.addAction(i18n("&Show All Entries"));
00439 showAll->setCheckable(true);
00440 showAll->setChecked(d->showAll);
00441 }
00442
00443 QAction* remove = 0L;
00444 QAction* teardown = 0L;
00445 if (index.isValid()) {
00446 if (!placesModel->isDevice(index)) {
00447 menu.addSeparator();
00448 remove = menu.addAction( KIcon("edit-delete"), i18n("&Remove '%1'", label));
00449 } else {
00450 teardown = placesModel->teardownActionForIndex(index);
00451 if (teardown!=0) {
00452 teardown->setParent(&menu);
00453 menu.addSeparator();
00454 menu.addAction(teardown);
00455 }
00456 }
00457 }
00458
00459 if (menu.isEmpty()) return;
00460
00461 QAction *result = menu.exec(event->globalPos());
00462
00463 if (emptyTrash != 0 && result == emptyTrash) {
00464 const QString text = i18nc("@info", "Do you really want to empty the Trash? All items will be deleted.");
00465 const bool del = KMessageBox::warningContinueCancel(window(),
00466 text,
00467 QString(),
00468 KGuiItem(i18nc("@action:button", "Empty Trash"),
00469 KIcon("user-trash"))
00470 ) == KMessageBox::Continue;
00471 if (del) {
00472 QByteArray packedArgs;
00473 QDataStream stream(&packedArgs, QIODevice::WriteOnly);
00474 stream << int(1);
00475 KIO::Job *job = KIO::special(KUrl("trash:/"), packedArgs);
00476 KNotification::event("Trash: emptied", QString() , QPixmap() , 0, KNotification::DefaultEvent);
00477 job->ui()->setWindow(parentWidget());
00478 connect(job, SIGNAL(result(KJob*)), SLOT(_k_trashUpdated(KJob*)));
00479 }
00480 } else if (edit != 0 && result == edit) {
00481 KBookmark bookmark = placesModel->bookmarkForIndex(index);
00482 KUrl url = bookmark.url();
00483 QString description = bookmark.text();
00484 QString iconName = bookmark.icon();
00485 bool appLocal = !bookmark.metaDataItem("OnlyInApp").isEmpty();
00486
00487 if (KFilePlaceEditDialog::getInformation(true, url, description,
00488 iconName, appLocal, 64, this))
00489 {
00490 QString appName;
00491 if (appLocal) appName = KGlobal::mainComponent().componentName();
00492
00493 placesModel->editPlace(index, description, url, iconName, appName);
00494 }
00495
00496 } else if (remove != 0 && result == remove) {
00497 placesModel->removePlace(index);
00498 } else if (hide != 0 && result == hide) {
00499 placesModel->setPlaceHidden(index, hide->isChecked());
00500 QModelIndex current = placesModel->closestItem(d->currentUrl);
00501
00502 if (index!=current && !d->showAll && hide->isChecked()) {
00503 delegate->addDisappearingItem(index);
00504
00505 if (d->itemDisappearTimeline.state()!=QTimeLine::Running) {
00506 delegate->setDisappearingItemProgress(0.0);
00507 d->itemDisappearTimeline.start();
00508 }
00509 }
00510 } else if (showAll != 0 && result == showAll) {
00511 setShowAll(showAll->isChecked());
00512 } else if (teardown != 0 && result == teardown) {
00513 placesModel->requestTeardown(index);
00514 }
00515
00516 index = placesModel->closestItem(d->currentUrl);
00517 selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
00518 }
00519
00520 void KFilePlacesView::resizeEvent(QResizeEvent *event)
00521 {
00522 QListView::resizeEvent(event);
00523 d->adaptItemSize();
00524 }
00525
00526 void KFilePlacesView::showEvent(QShowEvent *event)
00527 {
00528 QListView::showEvent(event);
00529 QTimer::singleShot(100, this, SLOT(_k_enableSmoothItemResizing()));
00530 }
00531
00532 void KFilePlacesView::hideEvent(QHideEvent *event)
00533 {
00534 QListView::hideEvent(event);
00535 d->smoothItemResizing = false;
00536 }
00537
00538 void KFilePlacesView::dragEnterEvent(QDragEnterEvent *event)
00539 {
00540 QListView::dragEnterEvent(event);
00541 d->dragging = true;
00542
00543 KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(itemDelegate());
00544 delegate->setShowHoverIndication(false);
00545
00546 d->dropRect = QRect();
00547 }
00548
00549 void KFilePlacesView::dragLeaveEvent(QDragLeaveEvent *event)
00550 {
00551 QListView::dragLeaveEvent(event);
00552 d->dragging = false;
00553
00554 KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(itemDelegate());
00555 delegate->setShowHoverIndication(true);
00556
00557 setDirtyRegion(d->dropRect);
00558 }
00559
00560 void KFilePlacesView::dragMoveEvent(QDragMoveEvent *event)
00561 {
00562 QListView::dragMoveEvent(event);
00563
00564
00565 const QPoint pos = event->pos();
00566 const QModelIndex index = indexAt(pos);
00567 setDirtyRegion(d->dropRect);
00568 if (index.isValid()) {
00569 const QRect rect = visualRect(index);
00570 const int gap = d->insertIndicatorHeight(rect.height());
00571 if (d->insertAbove(rect, pos)) {
00572
00573 d->dropRect = QRect(rect.left(), rect.top() - gap / 2,
00574 rect.width(), gap);
00575 } else if (d->insertBelow(rect, pos)) {
00576
00577 d->dropRect = QRect(rect.left(), rect.bottom() + 1 - gap / 2,
00578 rect.width(), gap);
00579 } else {
00580
00581 d->dropRect = rect;
00582 }
00583 }
00584
00585 setDirtyRegion(d->dropRect);
00586 }
00587
00588 void KFilePlacesView::dropEvent(QDropEvent *event)
00589 {
00590 const QPoint pos = event->pos();
00591 const QModelIndex index = indexAt(pos);
00592 if (index.isValid()) {
00593 const QRect rect = visualRect(index);
00594 if (!d->insertAbove(rect, pos) && !d->insertBelow(rect, pos)) {
00595 KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(model());
00596 Q_ASSERT(placesModel != 0);
00597 emit urlsDropped(placesModel->url(index), event, this);
00598 event->acceptProposedAction();
00599 }
00600 }
00601
00602 QListView::dropEvent(event);
00603 d->dragging = false;
00604
00605 KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(itemDelegate());
00606 delegate->setShowHoverIndication(true);
00607 }
00608
00609 void KFilePlacesView::paintEvent(QPaintEvent* event)
00610 {
00611 QListView::paintEvent(event);
00612 if (d->dragging && !d->dropRect.isEmpty()) {
00613
00614 QPainter painter(viewport());
00615
00616 const QModelIndex index = indexAt(d->dropRect.topLeft());
00617 const QRect itemRect = visualRect(index);
00618 const bool drawInsertIndicator = !d->dropOnPlace ||
00619 d->dropRect.height() <= d->insertIndicatorHeight(itemRect.height());
00620
00621 if (drawInsertIndicator) {
00622
00623 QBrush blendedBrush = viewOptions().palette.brush(QPalette::Normal, QPalette::Highlight);
00624 QColor color = blendedBrush.color();
00625
00626 const int y = (d->dropRect.top() + d->dropRect.bottom()) / 2;
00627 const int thickness = d->dropRect.height() / 2;
00628 Q_ASSERT(thickness >= 1);
00629 int alpha = 255;
00630 const int alphaDec = alpha / (thickness + 1);
00631 for (int i = 0; i < thickness; i++) {
00632 color.setAlpha(alpha);
00633 alpha -= alphaDec;
00634 painter.setPen(color);
00635 painter.drawLine(d->dropRect.left(), y - i, d->dropRect.right(), y - i);
00636 painter.drawLine(d->dropRect.left(), y + i, d->dropRect.right(), y + i);
00637 }
00638 } else {
00639
00640 QStyleOptionViewItemV4 opt;
00641 opt.initFrom(this);
00642 opt.rect = itemRect;
00643 opt.state = QStyle::State_Enabled | QStyle::State_MouseOver;
00644 style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, &painter, this);
00645 }
00646 }
00647 }
00648
00649 void KFilePlacesView::setModel(QAbstractItemModel *model)
00650 {
00651 QListView::setModel(model);
00652 d->updateHiddenRows();
00653 connect(model, SIGNAL(rowsRemoved(const QModelIndex&, int, int)),
00654 this, SLOT(adaptItemSize()));
00655 }
00656
00657 void KFilePlacesView::rowsInserted(const QModelIndex &parent, int start, int end)
00658 {
00659 QListView::rowsInserted(parent, start, end);
00660 setUrl(d->currentUrl);
00661
00662 KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(itemDelegate());
00663 KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(model());
00664
00665 for (int i=start; i<=end; ++i) {
00666 QModelIndex index = placesModel->index(i, 0, parent);
00667 if (d->showAll || !placesModel->isHidden(index)) {
00668 delegate->addAppearingItem(index);
00669 } else {
00670 setRowHidden(i, true);
00671 }
00672 }
00673
00674 if (d->itemAppearTimeline.state()!=QTimeLine::Running) {
00675 delegate->setAppearingItemProgress(0.0);
00676 d->itemAppearTimeline.start();
00677 }
00678
00679 d->adaptItemSize();
00680 }
00681
00682 QSize KFilePlacesView::sizeHint() const
00683 {
00684 KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(model());
00685 const int height = QListView::sizeHint().height();
00686 QFontMetrics fm = d->q->fontMetrics();
00687 int textWidth = 0;
00688
00689 for (int i=0; i<placesModel->rowCount(); ++i) {
00690 QModelIndex index = placesModel->index(i, 0);
00691 if (!placesModel->isHidden(index))
00692 textWidth = qMax(textWidth,fm.width(index.data(Qt::DisplayRole).toString()));
00693 }
00694
00695 const int iconSize = KIconLoader::global()->currentSize(KIconLoader::Dialog);
00696 return QSize(iconSize + textWidth + 2*KDialog::marginHint(), height);
00697 }
00698
00699 void KFilePlacesView::Private::setCurrentIndex(const QModelIndex &index)
00700 {
00701 KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(q->model());
00702
00703 if (placesModel==0) return;
00704
00705 KUrl url = placesModel->url(index);
00706
00707 if (url.isValid()) {
00708 currentUrl = url;
00709 updateHiddenRows();
00710 emit q->urlChanged(url);
00711 } else {
00712 q->setUrl(currentUrl);
00713 }
00714 }
00715
00716 void KFilePlacesView::Private::adaptItemSize()
00717 {
00718 KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(q->itemDelegate());
00719 if (!delegate) return;
00720
00721 if (!autoResizeItems) {
00722 int size = q->iconSize().width();
00723 delegate->setIconSize(size);
00724 q->scheduleDelayedItemsLayout();
00725 return;
00726 }
00727
00728 KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(q->model());
00729
00730 if (placesModel==0) return;
00731
00732 int rowCount = placesModel->rowCount();
00733
00734 if (!showAll) {
00735 rowCount-= placesModel->hiddenCount();
00736
00737 QModelIndex current = placesModel->closestItem(currentUrl);
00738
00739 if (placesModel->isHidden(current)) {
00740 rowCount++;
00741 }
00742 }
00743
00744 if (rowCount==0) return;
00745
00746 const int minSize = 16;
00747 const int maxSize = 64;
00748
00749 int textWidth = 0;
00750 QFontMetrics fm = q->fontMetrics();
00751 for (int i=0; i<placesModel->rowCount(); ++i) {
00752 QModelIndex index = placesModel->index(i, 0);
00753
00754 if (!placesModel->isHidden(index))
00755 textWidth = qMax(textWidth,fm.width(index.data(Qt::DisplayRole).toString()));
00756 }
00757
00758 const int margin = q->style()->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, q) + 1;
00759 const int maxWidth = q->viewport()->width() - textWidth - 4 * margin - 1;
00760 const int maxHeight = ((q->height() - KDialog::marginHint() * rowCount) / rowCount) - 1;
00761
00762 int size = qMin(maxHeight, maxWidth);
00763
00764 if (size<minSize) {
00765 size = minSize;
00766 } else if (size>maxSize) {
00767 size = maxSize;
00768 } else {
00769
00770 size &= ~0xf;
00771 }
00772
00773 if (size==delegate->iconSize()) return;
00774
00775 if (smoothItemResizing) {
00776 oldSize = delegate->iconSize();
00777 endSize = size;
00778 if (adaptItemsTimeline.state()!=QTimeLine::Running) {
00779 adaptItemsTimeline.start();
00780 }
00781 } else {
00782 delegate->setIconSize(size);
00783 q->scheduleDelayedItemsLayout();
00784 }
00785 }
00786
00787 void KFilePlacesView::Private::updateHiddenRows()
00788 {
00789 KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(q->model());
00790
00791 if (placesModel==0) return;
00792
00793 int rowCount = placesModel->rowCount();
00794 QModelIndex current = placesModel->closestItem(currentUrl);
00795
00796 for (int i=0; i<rowCount; ++i) {
00797 QModelIndex index = placesModel->index(i, 0);
00798 if (index!=current && placesModel->isHidden(index) && !showAll) {
00799 q->setRowHidden(i, true);
00800 } else {
00801 q->setRowHidden(i, false);
00802 }
00803 }
00804
00805 adaptItemSize();
00806 }
00807
00808 bool KFilePlacesView::Private::insertAbove(const QRect &itemRect, const QPoint &pos) const
00809 {
00810 if (dropOnPlace) {
00811 return pos.y() < itemRect.top() + insertIndicatorHeight(itemRect.height()) / 2;
00812 }
00813
00814 return pos.y() < itemRect.top() + (itemRect.height() / 2);
00815 }
00816
00817 bool KFilePlacesView::Private::insertBelow(const QRect &itemRect, const QPoint &pos) const
00818 {
00819 if (dropOnPlace) {
00820 return pos.y() > itemRect.bottom() - insertIndicatorHeight(itemRect.height()) / 2;
00821 }
00822
00823 return pos.y() >= itemRect.top() + (itemRect.height() / 2);
00824 }
00825
00826 int KFilePlacesView::Private::insertIndicatorHeight(int itemHeight) const
00827 {
00828 const int min = 4;
00829 const int max = 12;
00830
00831 int height = itemHeight / 4;
00832 if (height < min) {
00833 height = min;
00834 } else if (height > max) {
00835 height = max;
00836 }
00837 return height;
00838 }
00839
00840 void KFilePlacesView::Private::_k_placeClicked(const QModelIndex &index)
00841 {
00842 if (!KGlobalSettings::singleClick()) {
00843
00844 _k_placeActivated(index);
00845 }
00846 }
00847
00848 void KFilePlacesView::Private::_k_placeActivated(const QModelIndex &index)
00849 {
00850 KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(q->model());
00851
00852 if (placesModel==0) return;
00853
00854 lastClickedIndex = QPersistentModelIndex();
00855
00856 if (placesModel->setupNeeded(index)) {
00857 QObject::connect(placesModel, SIGNAL(setupDone(const QModelIndex &, bool)),
00858 q, SLOT(_k_storageSetupDone(const QModelIndex &, bool)));
00859
00860 lastClickedIndex = index;
00861 placesModel->requestSetup(index);
00862 return;
00863 }
00864
00865 setCurrentIndex(index);
00866 }
00867
00868 void KFilePlacesView::Private::_k_storageSetupDone(const QModelIndex &index, bool success)
00869 {
00870 if (index!=lastClickedIndex) {
00871 return;
00872 }
00873
00874 KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(q->model());
00875
00876 QObject::disconnect(placesModel, SIGNAL(setupDone(const QModelIndex &, bool)),
00877 q, SLOT(_k_storageSetupDone(const QModelIndex &, bool)));
00878
00879 if (success) {
00880 setCurrentIndex(lastClickedIndex);
00881 } else {
00882 q->setUrl(currentUrl);
00883 }
00884
00885 lastClickedIndex = QPersistentModelIndex();
00886 }
00887
00888 void KFilePlacesView::Private::_k_adaptItemsUpdate(qreal value)
00889 {
00890 int add = (endSize-oldSize)*value;
00891
00892 int size = oldSize+add;
00893
00894 KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(q->itemDelegate());
00895 delegate->setIconSize(size);
00896 q->scheduleDelayedItemsLayout();
00897 }
00898
00899 void KFilePlacesView::Private::_k_itemAppearUpdate(qreal value)
00900 {
00901 KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(q->itemDelegate());
00902
00903 delegate->setAppearingItemProgress(value);
00904 q->scheduleDelayedItemsLayout();
00905 }
00906
00907 void KFilePlacesView::Private::_k_itemDisappearUpdate(qreal value)
00908 {
00909 KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(q->itemDelegate());
00910
00911 delegate->setDisappearingItemProgress(value);
00912
00913 if (value>=1.0) {
00914 updateHiddenRows();
00915 }
00916
00917 q->scheduleDelayedItemsLayout();
00918 }
00919
00920 void KFilePlacesView::Private::_k_enableSmoothItemResizing()
00921 {
00922 smoothItemResizing = true;
00923 }
00924
00925 void KFilePlacesView::Private::_k_trashUpdated(KJob *job)
00926 {
00927 if (job->error()) {
00928 static_cast<KIO::Job*>(job)->ui()->showErrorMessage();
00929 }
00930 org::kde::KDirNotify::emitFilesAdded("trash:/");
00931 }
00932
00933 void KFilePlacesView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
00934 {
00935 QListView::dataChanged(topLeft, bottomRight);
00936 }
00937
00938 #include "kfileplacesview.moc"