diff --git a/krusader/Panel/CMakeLists.txt b/krusader/Panel/CMakeLists.txt --- a/krusader/Panel/CMakeLists.txt +++ b/krusader/Panel/CMakeLists.txt @@ -28,7 +28,8 @@ krviewfactory.cpp krviewitemdelegate.cpp krmousehandler.cpp - krsearchbar.cpp) + krsearchbar.cpp + krfiletreeview.cpp) add_library(Panel STATIC ${Panel_SRCS}) diff --git a/krusader/Panel/krfiletreeview.h b/krusader/Panel/krfiletreeview.h new file mode 100644 --- /dev/null +++ b/krusader/Panel/krfiletreeview.h @@ -0,0 +1,71 @@ +/***************************************************************************** + * Copyright (C) 2010 Jan Lepper * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This package is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this package; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *****************************************************************************/ + +#ifndef KRFILETREEVIEW_H +#define KRFILETREEVIEW_H + +#include +#include +#include +#include +#include + +#include +#include + +/** + * @brief Shows a generic file tree + */ +class KrFileTreeView : public QTreeView +{ + friend class KrDirModel; + Q_OBJECT + +public: + KrFileTreeView(QWidget *parent = 0); + virtual ~KrFileTreeView() {} + + QUrl currentUrl() const; + bool briefMode() const; + void setBriefMode(bool brief); // show only column with directory names + +public slots: + void setDirOnlyMode(bool enabled); + void setShowHiddenFiles(bool enabled); + void setCurrentUrl(const QUrl &url); + +signals: + void activated(const QUrl &url); + +private slots: + void slotActivated(const QModelIndex&); + void slotExpanded(const QModelIndex&); + void showHeaderContextMenu(); + +protected: + void dropEvent(QDropEvent *event) Q_DECL_OVERRIDE; + +private: + QUrl urlForProxyIndex(const QModelIndex &index) const; + void dropMimeData(const QList & lst, const QUrl &url); + + KDirModel *mSourceModel; + KDirSortFilterProxyModel *mProxyModel; +}; + +#endif // KRFILETREEVIEW_H diff --git a/krusader/Panel/krfiletreeview.cpp b/krusader/Panel/krfiletreeview.cpp new file mode 100644 --- /dev/null +++ b/krusader/Panel/krfiletreeview.cpp @@ -0,0 +1,159 @@ +/***************************************************************************** + * Copyright (C) 2010 Jan Lepper * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This package is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this package; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *****************************************************************************/ +#include "krfiletreeview.h" + +#include "panelfunc.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +class KrDirModel : public KDirModel +{ +public: + KrDirModel(QWidget *parent, KrFileTreeView *ftv) : KDirModel(parent), fileTreeView(ftv) {} + +protected: + virtual Qt::ItemFlags flags(const QModelIndex & index) const Q_DECL_OVERRIDE { + Qt::ItemFlags itflags = KDirModel::flags(index); + if (index.column() != KDirModel::Name) + itflags &= ~Qt::ItemIsDropEnabled; + return itflags; + } +private: + KrFileTreeView * fileTreeView; +}; + +KrFileTreeView::KrFileTreeView(QWidget *parent) + : QTreeView(parent) +{ + mSourceModel = new KrDirModel(this, this); + mProxyModel = new KDirSortFilterProxyModel(this); + mProxyModel->setSourceModel(mSourceModel); + + mSourceModel->setDropsAllowed(KDirModel::DropOnDirectory); + + setModel(mProxyModel); + setItemDelegate(new KFileItemDelegate(this)); + setUniformRowHeights(true); + + mSourceModel->dirLister()->openUrl(QUrl::fromLocalFile(QDir::root().absolutePath()), KDirLister::Keep); + + connect(this, SIGNAL(activated(const QModelIndex&)), + this, SLOT(slotActivated(const QModelIndex&))); + + connect(mSourceModel, SIGNAL(expand(const QModelIndex&)), + this, SLOT(slotExpanded(const QModelIndex&))); + + QFontMetrics fontMetrics(viewport()->font()); + header()->resizeSection(KDirModel::Name, fontMetrics.width("WWWWWWWWWWWWWWW")); + + header()->setContextMenuPolicy(Qt::CustomContextMenu); + connect(header(), SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showHeaderContextMenu())); +} + +QUrl KrFileTreeView::urlForProxyIndex(const QModelIndex &index) const +{ + const KFileItem item = mSourceModel->itemForIndex(mProxyModel->mapToSource(index)); + + return !item.isNull() ? item.url() : QUrl(); +} + +void KrFileTreeView::slotActivated(const QModelIndex &index) +{ + const QUrl url = urlForProxyIndex(index); + if (url.isValid()) + emit activated(url); +} + +void KrFileTreeView::dropEvent(QDropEvent *event) +{ + QUrl destination = urlForProxyIndex(indexAt(event->pos())); + if (destination.isEmpty()) { + return; + } + + KIO::drop(event, destination); + // TODO show error message job result and refresh event source +} + +void KrFileTreeView::slotExpanded(const QModelIndex &baseIndex) +{ + QModelIndex index = mProxyModel->mapFromSource(baseIndex); + + expand(index); // expand view now after model was expanded + selectionModel()->clearSelection(); + selectionModel()->setCurrentIndex(index, QItemSelectionModel::SelectCurrent); + scrollTo(index); +} + +QUrl KrFileTreeView::currentUrl() const +{ + return urlForProxyIndex(currentIndex()); +} + +void KrFileTreeView::setDirOnlyMode(bool enabled) +{ + mSourceModel->dirLister()->setDirOnlyMode(enabled); + mSourceModel->dirLister()->openUrl(mSourceModel->dirLister()->url()); +} + +void KrFileTreeView::setShowHiddenFiles(bool enabled) +{ + mSourceModel->dirLister()->setShowingDotFiles(enabled); + mSourceModel->dirLister()->openUrl(mSourceModel->dirLister()->url()); +} + +void KrFileTreeView::setCurrentUrl(const QUrl &url) +{ + mSourceModel->expandToUrl(url); +} + +void KrFileTreeView::showHeaderContextMenu() +{ + QMenu popup(this); + + QAction *action = popup.addAction(i18n("Show Details")); + action->setCheckable(true); + action->setChecked(!briefMode()); + + if (popup.exec(QCursor::pos())) { // if action was clicked + setBriefMode(!action->isChecked()); + } +} + +bool KrFileTreeView::briefMode() const +{ + return isColumnHidden(mProxyModel->columnCount() - 1); // find out by last column +} + +void KrFileTreeView::setBriefMode(bool brief) +{ + for (int i=1; i < mProxyModel->columnCount(); i++) { // show only first column + setColumnHidden(i, brief); + } +} diff --git a/krusader/Panel/listpanel.h b/krusader/Panel/listpanel.h --- a/krusader/Panel/listpanel.h +++ b/krusader/Panel/listpanel.h @@ -195,10 +195,11 @@ void resetNavigatorMode(); // set navigator mode after focus was lost signals: - void signalStatus(QString msg); // emmited when we need to update the status bar - void pathChanged(ListPanel *panel); - void activate(); // emitted when the user changes panels - void finishedDragging(); // currently + void signalStatus(QString msg); // emmited when we need to update the status bar + void pathChanged(ListPanel *panel); // directory changed or refreshed + void pathChanged(const QUrl &url); // directory changed or refreshed + void activate(); // emitted when the user changes panels + void finishedDragging(); // NOTE: currently not used void refreshColors(bool active); // emitted when we have to update the path label width void refreshPathLabel(); @@ -226,7 +227,7 @@ QToolButton *cdOtherButton; QToolButton *popupPositionBtn; QToolButton *popupBtn; - PanelPopup *popup; + PanelPopup *popup; // lazy initialized KrBookmarkButton *bookmarksButton; KrSqueezedTextLabel *status, *totals, *freeSpace; @@ -238,7 +239,8 @@ KrErrorDisplay *vfsError; private: - int popupPosition(); // 0: West, 1: North, 2: East, 3: South + bool handleDropInternal(QDropEvent *event, const QString &dir); + int popupPosition() const; // 0: West, 1: North, 2: East, 3: South void setPopupPosition(int); private: diff --git a/krusader/Panel/listpanel.cpp b/krusader/Panel/listpanel.cpp --- a/krusader/Panel/listpanel.cpp +++ b/krusader/Panel/listpanel.cpp @@ -535,6 +535,7 @@ QSizePolicy sizePolicy = popup->sizePolicy(); sizePolicy.setVerticalPolicy(QSizePolicy::Ignored); popup->setSizePolicy(sizePolicy); + connect(this, SIGNAL(pathChanged(const QUrl&)), popup, SLOT(onPanelPathChange(const QUrl&))); connect(popup, SIGNAL(selection(const QUrl&)), SLOTS, SLOT(refresh(const QUrl&))); connect(popup, SIGNAL(hideMe()), this, SLOT(togglePanelPopup())); } @@ -740,6 +741,7 @@ _realPath = virtualPath(); urlNavigator->setLocationUrl(virtualPath()); emit pathChanged(this); + emit pathChanged(virtualPath()); slotGetStats(virtualPath()); if (compareMode) @@ -1221,6 +1223,7 @@ // splitter/popup state if (popup && !popup->isHidden()) { + popup->saveSettings(KConfigGroup(&cfg, "PanelPopup")); cfg.writeEntry("PopupPosition", popupPosition()); cfg.writeEntry("SplitterSizes", splt->saveState()); cfg.writeEntry("PopupPage", popup->currentPage()); @@ -1255,6 +1258,7 @@ if (cfg.hasKey("PopupPosition")) { // popup was visible, restore togglePanelPopup(); // create and show + popup->restoreSettings(KConfigGroup(&cfg, "PanelPopup")); setPopupPosition(cfg.readEntry("PopupPosition", 42 /* dummy */)); splt->restoreState(cfg.readEntry("SplitterSizes", QByteArray())); popup->setCurrentPage(cfg.readEntry("PopupPage", 0)); @@ -1264,18 +1268,15 @@ void ListPanel::updatePopupPanel(KrViewItem *item) { // which panel to display on? - PanelPopup *p = 0; + PanelPopup *p; if(popup && !popup->isHidden()) p = popup; else if(otherPanel()->gui->popup && !otherPanel()->gui->popup->isHidden()) p = otherPanel()->gui->popup; else return; - if(item) - p->update(func->files()->vfs_search(item->name())); - else - p->update(0); + p->update(item ? func->files()->vfs_search(item->name()) : 0); } void ListPanel::otherPanelChanged() @@ -1331,12 +1332,14 @@ } } -int ListPanel::popupPosition() { +int ListPanel::popupPosition() const +{ int pos = splt->orientation() == Qt::Vertical ? 1 : 0; return pos + (qobject_cast(splt->widget(0)) == NULL ? 2 : 0); } -void ListPanel::setPopupPosition(int pos) { +void ListPanel::setPopupPosition(int pos) +{ splt->setOrientation(pos % 2 == 0 ? Qt::Horizontal : Qt::Vertical); if ((pos < 2) != (qobject_cast(splt->widget(0)) != NULL)) { splt->insertWidget(0, splt->widget(1)); // swapping widgets in splitter diff --git a/krusader/Panel/panelpopup.h b/krusader/Panel/panelpopup.h --- a/krusader/Panel/panelpopup.h +++ b/krusader/Panel/panelpopup.h @@ -22,31 +22,23 @@ // QtCore #include -#include // QtGui -#include -#include // QtWidgets -#include +#include +#include #include -#include -#include +#include +#include -#include +#include +#include #include #include -class QButtonGroup; -class QSplitter; -class QToolButton; class KrSqueezedTextLabel; -class KLineEdit; -class KComboBox; class PanelViewer; class DiskUsageViewer; class KrFileTreeView; -class KDirModel; -class KDirSortFilterProxyModel; class vfile; class KrMainWindow; @@ -61,10 +53,13 @@ inline int currentPage() const { return stack->currentWidget()->property("KrusaderWidgetId").toInt(); } + void saveSettings(KConfigGroup cfg) const; + void restoreSettings(KConfigGroup cfg); void setCurrentPage(int); public slots: void update(const vfile *vf); + void onPanelPathChange(const QUrl &url); void show(); void hide(); @@ -97,45 +92,4 @@ QSplitter *splitter; }; - -class KrFileTreeView : public QTreeView -{ - friend class KrDirModel; - Q_OBJECT - -public: - KrFileTreeView(QWidget *parent = 0); - virtual ~KrFileTreeView() {} - - QUrl currentUrl() const; - QUrl selectedUrl() const; - QList selectedUrls() const; - QUrl rootUrl() const; - -public Q_SLOTS: - void setDirOnlyMode(bool enabled); - void setShowHiddenFiles(bool enabled); - void setCurrentUrl(const QUrl &url); - void setRootUrl(const QUrl &url); - -Q_SIGNALS: - void activated(const QUrl &url); - void changedUrls(const QUrl &url); - -protected: - void dropEvent(QDropEvent *event) Q_DECL_OVERRIDE; - -private Q_SLOTS: - void slotActivated(const QModelIndex&); - void slotCurrentChanged(const QModelIndex&, const QModelIndex&); - void slotExpanded(const QModelIndex&); - -private: - QUrl urlForProxyIndex(const QModelIndex &index) const; - void dropMimeData(const QList & lst, const QUrl &url); - - KDirModel *mSourceModel; - KDirSortFilterProxyModel *mProxyModel; -}; - #endif diff --git a/krusader/Panel/panelpopup.cpp b/krusader/Panel/panelpopup.cpp --- a/krusader/Panel/panelpopup.cpp +++ b/krusader/Panel/panelpopup.cpp @@ -19,10 +19,11 @@ #include "panelpopup.h" +#include "krfiletreeview.h" #include "krpanel.h" -#include "panelfunc.h" #include "krview.h" #include "krviewitem.h" +#include "panelfunc.h" #include "viewactions.h" #include "../kicons.h" #include "../krmainwindow.h" @@ -32,188 +33,16 @@ #include "../KViewer/diskusageviewer.h" // QtCore -#include -#include #include #include -// QtGui -#include -#include // QtWidgets -#include -#include +#include #include -#include -#include -#include -#include -#include -#include - -#include -#include + #include #include #include -#include -#include -#include -#include -#include - -class KrDirModel : public KDirModel -{ -public: - KrDirModel(QWidget *parent, KrFileTreeView *ftv) : KDirModel(parent), fileTreeView(ftv) {} - -protected: - virtual Qt::ItemFlags flags(const QModelIndex & index) const Q_DECL_OVERRIDE { - Qt::ItemFlags itflags = KDirModel::flags(index); - if (index.column() != KDirModel::Name) - itflags &= ~Qt::ItemIsDropEnabled; - return itflags; - } -private: - KrFileTreeView * fileTreeView; -}; - -KrFileTreeView::KrFileTreeView(QWidget *parent) - : QTreeView(parent) -{ - mSourceModel = new KrDirModel(this, this); - mProxyModel = new KDirSortFilterProxyModel(this); - mProxyModel->setSourceModel(mSourceModel); - - mSourceModel->setDropsAllowed(KDirModel::DropOnDirectory); - - setModel(mProxyModel); - setItemDelegate(new KFileItemDelegate(this)); - setUniformRowHeights(true); - - mSourceModel->dirLister()->openUrl(QUrl::fromLocalFile(QDir::root().absolutePath()), KDirLister::Keep); - - connect(this, SIGNAL(activated(const QModelIndex&)), - this, SLOT(slotActivated(const QModelIndex&))); - connect(selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), - this, SLOT(slotCurrentChanged(const QModelIndex&, const QModelIndex&))); - - connect(mSourceModel, SIGNAL(expand(const QModelIndex&)), - this, SLOT(slotExpanded(const QModelIndex&))); - - QFontMetrics fontMetrics(viewport()->font()); - header()->resizeSection(KDirModel::Name, fontMetrics.width("WWWWWWWWWWWWWWW")); -} - -QUrl KrFileTreeView::urlForProxyIndex(const QModelIndex &index) const -{ - const KFileItem item = mSourceModel->itemForIndex(mProxyModel->mapToSource(index)); - - return !item.isNull() ? item.url() : QUrl(); -} - -void KrFileTreeView::slotActivated(const QModelIndex &index) -{ - const QUrl url = urlForProxyIndex(index); - if (url.isValid()) - emit activated(url); -} - -void KrFileTreeView::dropEvent(QDropEvent *event) -{ - QUrl destination = urlForProxyIndex(indexAt(event->pos())); - if (destination.isEmpty()) { - return; - } - KIO::drop(event, destination); - // TODO show error message job result and refresh event source -} - -void KrFileTreeView::slotCurrentChanged(const QModelIndex ¤tIndex, const QModelIndex&) -{ - const QUrl url = urlForProxyIndex(currentIndex); - if (url.isValid()) - emit changedUrls(url); -} - -void KrFileTreeView::slotExpanded(const QModelIndex &baseIndex) -{ - QModelIndex index = mProxyModel->mapFromSource(baseIndex); - - selectionModel()->clearSelection(); - selectionModel()->setCurrentIndex(index, QItemSelectionModel::SelectCurrent); - scrollTo(index); -} - -QUrl KrFileTreeView::currentUrl() const -{ - return urlForProxyIndex(currentIndex()); -} - -QUrl KrFileTreeView::selectedUrl() const -{ - if (!selectionModel()->hasSelection()) - return QUrl(); - - const QItemSelection selection = selectionModel()->selection(); - const QModelIndex firstIndex = selection.indexes().first(); - - return urlForProxyIndex(firstIndex); -} - -QList KrFileTreeView::selectedUrls() const -{ - QList urls; - - if (!selectionModel()->hasSelection()) - return urls; - - const QModelIndexList indexes = selectionModel()->selection().indexes(); - foreach(const QModelIndex &index, indexes) { - const QUrl url = urlForProxyIndex(index); - if (url.isValid()) - urls.append(url); - } - - return urls; -} - -QUrl KrFileTreeView::rootUrl() const -{ - return mSourceModel->dirLister()->url(); -} - -void KrFileTreeView::setDirOnlyMode(bool enabled) -{ - mSourceModel->dirLister()->setDirOnlyMode(enabled); - mSourceModel->dirLister()->openUrl(mSourceModel->dirLister()->url()); -} - -void KrFileTreeView::setShowHiddenFiles(bool enabled) -{ - mSourceModel->dirLister()->setShowingDotFiles(enabled); - mSourceModel->dirLister()->openUrl(mSourceModel->dirLister()->url()); -} - -void KrFileTreeView::setCurrentUrl(const QUrl &url) -{ - QModelIndex baseIndex = mSourceModel->indexForUrl(url); - - if (!baseIndex.isValid()) { - mSourceModel->expandToUrl(url); - return; - } - - QModelIndex proxyIndex = mProxyModel->mapFromSource(baseIndex); - selectionModel()->clearSelection(); - selectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::SelectCurrent); - scrollTo(proxyIndex); -} - -void KrFileTreeView::setRootUrl(const QUrl &url) -{ - mSourceModel->dirLister()->openUrl(url); -} PanelPopup::PanelPopup(QSplitter *parent, bool left, KrMainWindow *mainWindow) : QWidget(parent), _left(left), _hidden(true), _mainWindow(mainWindow), stack(0), viewer(0), pjob(0), splitterSizes() @@ -279,10 +108,13 @@ tree->setAcceptDrops(true); tree->setDragDropMode(QTreeView::DropOnly); tree->setDropIndicatorShown(true); + tree->setBriefMode(true); tree->setProperty("KrusaderWidgetId", QVariant(Tree)); stack->addWidget(tree); tree->setDirOnlyMode(true); + // NOTE: the F2 key press event is catched before it gets to the tree + tree->setEditTriggers(QAbstractItemView::EditKeyPressed); connect(tree, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(treeSelection())); connect(tree, SIGNAL(activated(const QUrl &)), this, SLOT(treeSelection())); @@ -315,7 +147,20 @@ PanelPopup::~PanelPopup() {} -void PanelPopup::setCurrentPage(int id) { +void PanelPopup::saveSettings(KConfigGroup cfg) const +{ + if (currentPage() == Tree) { + cfg.writeEntry("TreeBriefMode", tree->briefMode()); + } +} + +void PanelPopup::restoreSettings(KConfigGroup cfg) +{ + tree->setBriefMode(cfg.readEntry("TreeBriefMode", true)); +} + +void PanelPopup::setCurrentPage(int id) +{ QAbstractButton * curr = btns->button(id); if (curr) { curr->click(); @@ -446,6 +291,17 @@ } } +void PanelPopup::onPanelPathChange(const QUrl &url) +{ + switch (currentPage()) { + case Tree: + if (url.isLocalFile()) { + tree->setCurrentUrl(url); // synchronize panel path with tree path + } + break; + } +} + // ------------------- tree void PanelPopup::treeSelection()