Add the context menu for the icons in the folder view, and add

the "Create New", "Undo" and "Paste" actions to the applet's
context menu.

CCBUG: 155057
BUG: 163043

svn path=/trunk/KDE/kdebase/apps/; revision=818609
This commit is contained in:
Fredrik Höglund 2008-06-08 23:49:24 +00:00
parent 55e7f80ee3
commit 2726b5cf10
3 changed files with 334 additions and 13 deletions

View file

@ -6,7 +6,7 @@ set(folderview_SRCS
kde4_add_ui_files(folderview_SRCS folderviewConfig.ui)
kde4_add_plugin(plasma_applet_folderview ${folderview_SRCS})
target_link_libraries(plasma_applet_folderview plasma ${KDE4_KIO_LIBS})
target_link_libraries(plasma_applet_folderview plasma konq ${KDE4_KIO_LIBS})
install(TARGETS plasma_applet_folderview DESTINATION ${PLUGIN_INSTALL_DIR})
install(FILES plasma-applet-folderview.desktop DESTINATION ${SERVICES_INSTALL_DIR})

View file

@ -21,26 +21,42 @@
#include "folderview.moc"
#include <QApplication>
#include <QClipboard>
#include <QDebug>
#include <QDrag>
#include <QGraphicsView>
#include <QGraphicsSceneHoverEvent>
#include <QGraphicsSceneMouseEvent>
#include <QItemSelectionModel>
#include <QPainter>
#include <QStyleOptionGraphicsItem>
#include <KAction>
#include <KAuthorized>
#include <KBookmarkManager>
#include <KConfigDialog>
#include <KDirLister>
#include <KDirModel>
#include <KFileItemDelegate>
#include <KGlobalSettings>
#include <KMenu>
#include <KStandardShortcut>
#include <kio/fileundomanager.h>
#include <kio/paste.h>
#include <KParts/BrowserExtension>
#include <knewmenu.h>
#include <konqmimedata.h>
#include <konq_operations.h>
#include <konq_popupmenu.h>
#include "proxymodel.h"
#include "plasma/theme.h"
FolderView::FolderView(QObject *parent, const QVariantList &args)
: Plasma::Applet(parent, args)
: Plasma::Applet(parent, args), m_actionCollection(this)
{
setAspectRatioMode(Plasma::IgnoreAspectRatio);
setHasConfigurationInterface(true);
@ -65,6 +81,7 @@ FolderView::FolderView(QObject *parent, const QVariantList &args)
m_delegate = new KFileItemDelegate(this);
m_selectionModel = new QItemSelectionModel(m_model, this);
m_newMenu = 0;
m_layoutValid = false;
m_doubleClick = false;
m_dragInProgress = false;
@ -94,10 +111,13 @@ void FolderView::init()
m_model->setFilterFixedString(m_filterFiles);
m_dirModel->setDirLister(lister);
connect(QApplication::clipboard(), SIGNAL(dataChanged()), SLOT(clipboardDataChanged()));
}
FolderView::~FolderView()
{
delete m_newMenu;
}
void FolderView::createConfigurationInterface(KConfigDialog *parent)
@ -193,6 +213,29 @@ void FolderView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bott
update();
}
void FolderView::clipboardDataChanged()
{
const QMimeData *mimeData = QApplication::clipboard()->mimeData();
if (KonqMimeData::decodeIsCutSelection(mimeData)) {
KUrl::List urls = KUrl::List::fromMimeData(mimeData);
// TODO Mark the cut icons as cut
}
// Update the paste action
if (QAction *action = m_actionCollection.action("paste"))
{
const QString actionText = KIO::pasteActionText();
if (!actionText.isEmpty()) {
action->setText(actionText);
action->setEnabled(true);
} else {
action->setText(i18n("&Paste"));
action->setEnabled(false);
}
}
}
int FolderView::columnsForWidth(qreal width) const
{
int spacing = 10;
@ -334,6 +377,245 @@ void FolderView::constraintsEvent(Plasma::Constraints constraints)
}
}
void FolderView::createActions()
{
KIO::FileUndoManager *manager = KIO::FileUndoManager::self();
// Remove the Shift+Delete shortcut from the cut action, since it's used for deleting files
KAction *cut = KStandardAction::cut(this, SLOT(cut()), this);
KShortcut cutShortCut = cut->shortcut();
cutShortCut.remove(Qt::SHIFT + Qt::Key_Delete);
cut->setShortcut(cutShortCut);
KAction *copy = KStandardAction::copy(this, SLOT(copy()), this);
KAction *undo = KStandardAction::undo(manager, SLOT(undo()), this);
connect(manager, SIGNAL(undoAvailable(bool)), undo, SLOT(setEnabled(bool)));
connect(manager, SIGNAL(undoTextChanged(QString)), SLOT(undoTextChanged(QString)));
undo->setEnabled(manager->undoAvailable());
KAction *paste = KStandardAction::paste(this, SLOT(paste()), this);
KAction *pasteTo = KStandardAction::paste(this, SLOT(pasteTo()), this);
pasteTo->setEnabled(false); // Only enabled during popupMenu()
QString actionText = KIO::pasteActionText();
if (!actionText.isEmpty()) {
paste->setText(actionText);
} else {
paste->setEnabled(false);
}
KAction *reload = new KAction(i18n("&Reload"), this);
reload->setShortcut(KStandardShortcut::reload());
connect(reload, SIGNAL(triggered()), SLOT(refreshIcons()));
KAction *rename = new KAction(KIcon("edit-rename"), i18n("&Rename"), this);
rename->setShortcut(Qt::Key_F2);
connect(rename, SIGNAL(triggered()), SLOT(renameSelectedIcon()));
KAction *trash = new KAction(KIcon("user-trash"), i18n("&Move to Trash"), this);
trash->setShortcut(Qt::Key_Delete);
connect(trash, SIGNAL(triggered(Qt::MouseButtons, Qt::KeyboardModifiers)),
SLOT(moveToTrash(Qt::MouseButtons, Qt::KeyboardModifiers)));
KAction *del = new KAction(i18n("&Delete"), this);
del->setShortcut(Qt::SHIFT + Qt::Key_Delete);
connect(del, SIGNAL(triggered()), SLOT(deleteSelectedIcons()));
m_actionCollection.addAction("cut", cut);
m_actionCollection.addAction("undo", undo);
m_actionCollection.addAction("copy", copy);
m_actionCollection.addAction("paste", paste);
m_actionCollection.addAction("pasteto", pasteTo);
m_actionCollection.addAction("reload", reload);
m_actionCollection.addAction("rename", rename);
m_actionCollection.addAction("trash", trash);
m_actionCollection.addAction("del", del);
// Create the new menu
if (KAuthorized::authorize("editable_desktop_icons")) {
m_newMenu = new KNewMenu(&m_actionCollection, view(), "new_menu");
connect(m_newMenu->menu(), SIGNAL(aboutToShow()), this, SLOT(aboutToShowCreateNew()));
}
// Note: We have to create our own action collection, because the one Plasma::Applet
// provides can only be manipulated indirectly, and we need to be able to pass
// a pointer to the collection to KNewMenu and KonqPopupMenu.
// But we still have to add all the actions to the collection in Plasma::Applet
// in order for the shortcuts to work.
addAction("cut", cut);
addAction("undo", undo);
addAction("copy", copy);
addAction("paste", paste);
addAction("reload", reload);
addAction("rename", rename);
addAction("trash", trash);
addAction("del", del);
}
QList<QAction*> FolderView::contextualActions()
{
QList<QAction*> actions;
if (KAuthorized::authorize("action/kdesktop_rmb"))
{
if (m_actionCollection.isEmpty()) {
createActions();
}
if (QAction *action = m_actionCollection.action("new_menu")) {
actions.append(action);
QAction *separator = new QAction(this);
separator->setSeparator(true);
actions.append(separator);
}
actions.append(m_actionCollection.action("undo"));
actions.append(m_actionCollection.action("paste"));
QAction *separator = new QAction(this);
separator->setSeparator(true);
actions.append(separator);
}
return actions;
}
void FolderView::aboutToShowCreateNew()
{
if (m_newMenu) {
m_newMenu->slotCheckUpToDate();
m_newMenu->setPopupFiles(m_url);
}
}
KUrl::List FolderView::selectedUrls() const
{
KUrl::List urls;
foreach (const QModelIndex &index, m_selectionModel->selectedIndexes())
{
KFileItem item = m_model->itemForIndex(index);
// Prefer the local URL if there is one, since we can't trash remote URL's
const QString path = item.localPath();
if (!path.isEmpty()) {
urls.append(path);
} else {
urls.append(item.url());
}
}
return urls;
}
void FolderView::copy()
{
QMimeData *mimeData = new QMimeData;
KonqMimeData::populateMimeData(mimeData, selectedUrls(), KUrl::List(), false);
QApplication::clipboard()->setMimeData(mimeData);
}
void FolderView::cut()
{
QMimeData *mimeData = new QMimeData;
KonqMimeData::populateMimeData(mimeData, selectedUrls(), KUrl::List(), true);
QApplication::clipboard()->setMimeData(mimeData);
}
void FolderView::paste()
{
KonqOperations::doPaste(view(), m_url);
}
void FolderView::pasteTo()
{
KUrl::List urls = selectedUrls();
Q_ASSERT(urls.count() == 1);
KonqOperations::doPaste(view(), urls.first());
}
void FolderView::refreshIcons()
{
// TODO Implement me!
}
void FolderView::renameSelectedIcon()
{
// TODO Implement me!
}
void FolderView::moveToTrash(Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
{
Q_UNUSED(buttons)
KonqOperations::Operation op = (modifiers & Qt::ShiftModifier) ?
KonqOperations::DEL : KonqOperations::TRASH;
KonqOperations::del(view(), op, selectedUrls());
}
void FolderView::deleteSelectedIcons()
{
KonqOperations::del(view(), KonqOperations::DEL, selectedUrls());
}
void FolderView::undoTextChanged(const QString &text)
{
if (QAction *action = m_actionCollection.action("undo")) {
action->setText(text);
}
}
void FolderView::showContextMenu(QWidget *widget, const QPoint &pos, const QModelIndexList &indexes)
{
if (!KAuthorized::authorize("action/kdesktop_rmb")) {
return;
}
if (m_actionCollection.isEmpty()) {
createActions();
}
KFileItemList items;
bool hasRemoteFiles = false;
foreach (const QModelIndex &index, indexes) {
KFileItem item = m_model->itemForIndex(index);
hasRemoteFiles |= item.localPath().isEmpty();
items.append(item);
}
QAction* pasteTo = m_actionCollection.action("pasteto");
if (pasteTo) {
pasteTo->setEnabled(m_actionCollection.action("paste")->isEnabled());
pasteTo->setText(m_actionCollection.action("paste")->text());
}
QList<QAction*> editActions;
editActions.append(m_actionCollection.action("rename"));
if (!hasRemoteFiles) {
editActions.append(m_actionCollection.action("trash"));
} else {
editActions.append(m_actionCollection.action("del"));
}
KParts::BrowserExtension::ActionGroupMap actionGroups;
actionGroups.insert("editactions", editActions);
KParts::BrowserExtension::PopupFlags flags =
KParts::BrowserExtension::ShowUrlOperations | KParts::BrowserExtension::ShowProperties;
KonqPopupMenu *contextMenu = new KonqPopupMenu(items, m_url, m_actionCollection, m_newMenu,
KonqPopupMenu::ShowNewWindow, flags, widget,
KBookmarkManager::userBookmarksManager(),
actionGroups);
contextMenu->exec(pos);
delete contextMenu;
if (pasteTo) {
pasteTo->setEnabled(false);
}
}
void FolderView::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
const QModelIndex index = indexAt(event->pos());
@ -363,6 +645,28 @@ void FolderView::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
void FolderView::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (!contentsRect().contains(event->pos())) {
Plasma::Applet::mousePressEvent(event);
return;
}
if (event->button() == Qt::RightButton) {
const QModelIndex index = indexAt(event->pos());
if (index.isValid()) {
if (!m_selectionModel->isSelected(index)) {
m_selectionModel->select(index, QItemSelectionModel::ClearAndSelect);
m_selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
update();
}
showContextMenu(event->widget(), event->screenPos(), m_selectionModel->selectedIndexes());
} else if (m_selectionModel->hasSelection()) {
m_selectionModel->clearSelection();
update();
}
event->accept();
return;
}
if (event->button() == Qt::LeftButton) {
const QModelIndex index = indexAt(event->pos());
@ -384,19 +688,14 @@ void FolderView::mousePressEvent(QGraphicsSceneMouseEvent *event)
}
// If empty space was pressed
if (contentsRect().contains(event->pos()))
{
m_pressedIndex = QModelIndex();
if (m_selectionModel->hasSelection()) {
m_selectionModel->clearSelection();
update();
}
event->accept();
return;
m_pressedIndex = QModelIndex();
if (m_selectionModel->hasSelection()) {
m_selectionModel->clearSelection();
update();
}
event->accept();
}
Plasma::Applet::mousePressEvent(event);
}
void FolderView::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)

View file

@ -23,11 +23,14 @@
#include <QPersistentModelIndex>
#include <QStyleOption>
#include <KActionCollection>
#include <plasma/applet.h>
#include "ui_folderviewConfig.h"
class KDirModel;
class KFileItemDelegate;
class KNewMenu;
class QItemSelectionModel;
class ProxyModel;
@ -50,8 +53,9 @@ public:
protected:
void createConfigurationInterface(KConfigDialog *parent);
QList<QAction*> contextualActions();
private slots:
private slots:
void rowsInserted(const QModelIndex &parent, int first, int last);
void rowsRemoved(const QModelIndex &parent, int first, int last);
void modelReset();
@ -59,8 +63,24 @@ private slots:
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
void configAccepted();
void customFolderToggled(bool checked);
void aboutToShowCreateNew();
void clipboardDataChanged();
// These slots are for KonqPopupMenu
void copy();
void cut();
void paste();
void pasteTo();
void refreshIcons();
void renameSelectedIcon();
void moveToTrash(Qt::MouseButtons, Qt::KeyboardModifiers);
void deleteSelectedIcons();
void undoTextChanged(const QString &text);
private:
void createActions();
KUrl::List selectedUrls() const;
void showContextMenu(QWidget *widget, const QPoint &pos, const QModelIndexList &indexes);
int columnsForWidth(qreal width) const;
void layoutItems() const;
QModelIndex indexAt(const QPointF &point) const;
@ -89,6 +109,8 @@ private:
KUrl m_url;
QString m_filterFiles;
QFont m_font;
KNewMenu *m_newMenu;
KActionCollection m_actionCollection;
mutable QVector<ViewItem> m_items;
mutable int m_columns;
mutable bool m_layoutValid;