~ubuntu-branches/ubuntu/wily/kdebase/wily

« back to all changes in this revision

Viewing changes to plasma/applets/folderview/popupview.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Philip Muškovac, Jonathan Riddell, Felix Geyer
  • Date: 2011-03-03 16:25:47 UTC
  • mfrom: (1.1.58 upstream)
  • Revision ID: james.westby@ubuntu.com-20110303162547-2zf9j33cu6j5gj0a
Tags: 4:4.6.1a-0ubuntu1
[ Jonathan Riddell ]
* New upstream release
* Update kde-sc-dev-latest version

[ Felix Geyer ]
* Reduce the x-www-browser priority for konqueror to 30 as rekonq is the
  default Kubuntu browser.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *   Copyright © 2009 Fredrik Höglund <fredrik@kde.org>
 
3
 *
 
4
 *   This library is free software; you can redistribute it and/or
 
5
 *   modify it under the terms of the GNU Library General Public
 
6
 *   License as published by the Free Software Foundation; either
 
7
 *   version 2 of the License, or (at your option) any later version.
 
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
#include "popupview.h"
 
21
 
 
22
#include <QApplication>
 
23
#include <QClipboard>
 
24
#include <QDesktopWidget>
 
25
#include <QGraphicsScene>
 
26
#include <QGraphicsView>
 
27
#include <QGraphicsWidget>
 
28
#include <QItemSelectionModel>
 
29
#include <QStyle>
 
30
 
 
31
#include <KAction>
 
32
#include <KBookmarkManager>
 
33
#include <KDesktopFile>
 
34
#include <KDirModel>
 
35
#include <kfileitemactions.h>
 
36
#include <KFileItemDelegate>
 
37
#include <kfileitemlistproperties.h>
 
38
#include <kfilepreviewgenerator.h>
 
39
#include <knewmenu.h>
 
40
#include <KWindowSystem>
 
41
#include <KMenu>
 
42
 
 
43
#include <kio/fileundomanager.h>
 
44
#include <kio/paste.h>
 
45
 
 
46
#include <konqmimedata.h>
 
47
#include <konq_operations.h>
 
48
#include <konq_popupmenu.h>
 
49
 
 
50
#include "dirlister.h"
 
51
#include "folderviewadapter.h"
 
52
#include "iconview.h"
 
53
#include "proxymodel.h"
 
54
 
 
55
#include <Plasma/Applet>
 
56
#include <Plasma/BusyWidget>
 
57
#include <Plasma/FrameSvg>
 
58
#include <Plasma/Theme>
 
59
#include <Plasma/WindowEffects>
 
60
 
 
61
 
 
62
QTime PopupView::s_lastOpenClose;
 
63
 
 
64
PopupView::PopupView(const QModelIndex &index, const QPoint &pos,
 
65
                     const bool &showPreview, const QStringList &previewPlugins,
 
66
                     const IconView *parentView)
 
67
    : QWidget(0, Qt::X11BypassWindowManagerHint),
 
68
      m_view(0),
 
69
      m_parentView(parentView),
 
70
      m_busyWidget(0),
 
71
      m_iconView(0),
 
72
      m_dirModel(0),
 
73
      m_model(0),
 
74
      m_actionCollection(this),
 
75
      m_newMenu(0),
 
76
      m_itemActions(0),
 
77
      m_showingMenu(false),
 
78
      m_showPreview(showPreview),
 
79
      m_previewPlugins(previewPlugins)
 
80
{
 
81
    setAttribute(Qt::WA_TranslucentBackground);
 
82
#ifdef Q_WS_X11
 
83
    if (KWindowSystem::compositingActive()) {
 
84
        setAttribute(Qt::WA_NoSystemBackground, false);
 
85
    }
 
86
#endif
 
87
 
 
88
#ifdef Q_WS_WIN
 
89
    setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::Tool);
 
90
#endif
 
91
 
 
92
    KWindowSystem::setState(effectiveWinId(), NET::SkipTaskbar | NET::SkipPager);
 
93
 
 
94
    setAcceptDrops(true);
 
95
 
 
96
    QPalette pal = palette();
 
97
    pal.setColor(backgroundRole(), Qt::transparent);
 
98
    pal.setColor(QPalette::Text, Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
 
99
    setPalette(pal);
 
100
 
 
101
    KFileItem item = static_cast<const ProxyModel*>(index.model())->itemForIndex(index);
 
102
    if (item.isDesktopFile()) {
 
103
        KDesktopFile file(item.localPath());
 
104
        m_url = file.readUrl();
 
105
    } else {
 
106
        m_url = item.targetUrl();
 
107
    }
 
108
 
 
109
    m_background = new Plasma::FrameSvg(this);
 
110
    m_background->setImagePath("widgets/tooltip");
 
111
 
 
112
    int left   = m_background->marginSize(Plasma::LeftMargin);
 
113
    int top    = m_background->marginSize(Plasma::TopMargin);
 
114
    int right  = m_background->marginSize(Plasma::RightMargin);
 
115
    int bottom = m_background->marginSize(Plasma::BottomMargin);
 
116
 
 
117
    setContentsMargins(left, top, right, bottom);
 
118
 
 
119
    resize(parentView->sizeForRowsColumns(2, 3) + QSize(left + right, top + bottom));
 
120
 
 
121
    const QRect available = QApplication::desktop()->availableGeometry(pos);
 
122
    QPoint pt = pos;
 
123
 
 
124
    if (pt.x() + width() > available.right()) {
 
125
        pt.rx() -= width();
 
126
    }
 
127
    if (pt.x() < available.left()) {
 
128
        pt.rx() = available.left();
 
129
    }
 
130
 
 
131
    if (pt.y() + height() > available.bottom()) {
 
132
        pt.ry() -= height();
 
133
    }
 
134
    if (pt.y() < available.top()) {
 
135
        pt.ry() = available.top();
 
136
    }
 
137
 
 
138
    Plasma::WindowEffects::overrideShadow(winId(), true);
 
139
 
 
140
    move(pt);
 
141
    show();
 
142
 
 
143
    QTimer::singleShot(10, this, SLOT(init()));
 
144
    s_lastOpenClose.restart();
 
145
}
 
146
 
 
147
PopupView::~PopupView()
 
148
{
 
149
    delete m_newMenu;
 
150
    s_lastOpenClose.restart();
 
151
}
 
152
 
 
153
void PopupView::delayedHide()
 
154
{
 
155
    if (!m_iconView || !m_iconView->dragInProgress()) {
 
156
        m_hideTimer.start(400, this);
 
157
    }
 
158
}
 
159
 
 
160
bool PopupView::dragInProgress()
 
161
{
 
162
    return m_iconView && m_iconView->dragInProgress();
 
163
}
 
164
 
 
165
void PopupView::init()
 
166
{
 
167
    if (m_model) {
 
168
        return;
 
169
    }
 
170
 
 
171
    m_scene = new QGraphicsScene(this);
 
172
    m_view = new QGraphicsView(m_scene, this);
 
173
    m_view->setFrameShape(QFrame::NoFrame);
 
174
    m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
175
    m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
176
    m_view->viewport()->setAutoFillBackground(false);
 
177
    m_view->setGeometry(contentsRect());
 
178
    m_view->show();
 
179
 
 
180
    DirLister *lister = new DirLister(this);
 
181
    lister->setDelayedMimeTypes(true);
 
182
    lister->setAutoErrorHandlingEnabled(false, 0);
 
183
    lister->openUrl(m_url);
 
184
 
 
185
    m_dirModel = new KDirModel(this);
 
186
    m_dirModel->setDropsAllowed(KDirModel::DropOnDirectory | KDirModel::DropOnLocalExecutable);
 
187
    m_dirModel->setDirLister(lister);
 
188
 
 
189
    m_model = new ProxyModel(this);
 
190
    m_model->setSourceModel(m_dirModel);
 
191
    m_model->setSortLocaleAware(true);
 
192
    m_model->setDynamicSortFilter(true);
 
193
    m_model->setFilterCaseSensitivity(Qt::CaseInsensitive);
 
194
    m_model->setParseDesktopFiles(m_url.protocol() == "desktop");
 
195
    m_model->sort(KDirModel::Name, Qt::AscendingOrder);
 
196
 
 
197
    m_delegate = new KFileItemDelegate(this);
 
198
    m_selectionModel = new QItemSelectionModel(m_model, this);
 
199
 
 
200
    m_iconView = new IconView(0);
 
201
    m_iconView->setModel(m_model);
 
202
    m_iconView->setItemDelegate(m_delegate);
 
203
    m_iconView->setSelectionModel(m_selectionModel);
 
204
    m_iconView->setFont(m_parentView->font());
 
205
    m_iconView->setPalette(palette());
 
206
    m_iconView->setDrawShadows(m_parentView->drawShadows());
 
207
    m_iconView->setIconSize(m_parentView->iconSize());
 
208
    m_iconView->setGridSize(m_parentView->gridSize());
 
209
    m_iconView->setWordWrap(m_parentView->wordWrap());
 
210
    m_iconView->setIconsMoveable(false);
 
211
    m_iconView->setClickToViewFolders(false);
 
212
 
 
213
    connect(m_iconView, SIGNAL(activated(QModelIndex)), SLOT(activated(QModelIndex)));
 
214
    connect(m_iconView, SIGNAL(contextMenuRequest(QWidget*,QPoint)), SLOT(contextMenuRequest(QWidget*,QPoint)));
 
215
    connect(m_iconView, SIGNAL(busy(bool)), SLOT(setBusy(bool)));
 
216
    connect(m_iconView, SIGNAL(popupViewClosed()), SLOT(maybeClose()));
 
217
 
 
218
    FolderViewAdapter *adapter = new FolderViewAdapter(m_iconView);
 
219
    m_previewGenerator = new KFilePreviewGenerator(adapter, m_model);
 
220
    m_previewGenerator->setPreviewShown(m_showPreview);
 
221
    m_previewGenerator->setEnabledPlugins(m_previewPlugins);
 
222
 
 
223
    m_iconView->setGeometry(contentsRect());
 
224
    m_iconView->show();
 
225
 
 
226
    m_scene->addItem(m_iconView);
 
227
    setBusy(true);
 
228
}
 
229
 
 
230
void PopupView::createActions()
 
231
{
 
232
    // Remove the Shift+Delete shortcut from the cut action, since it's used for deleting files
 
233
    KAction *cut = KStandardAction::cut(this, SLOT(cut()), this);
 
234
    KShortcut cutShortCut = cut->shortcut();
 
235
    cutShortCut.remove(Qt::SHIFT + Qt::Key_Delete);
 
236
    cut->setShortcut(cutShortCut);
 
237
 
 
238
    KAction *copy = KStandardAction::copy(this, SLOT(copy()), this);
 
239
 
 
240
    KIO::FileUndoManager *manager = KIO::FileUndoManager::self();
 
241
 
 
242
    KAction *undo = KStandardAction::undo(manager, SLOT(undo()), this);
 
243
    connect(manager, SIGNAL(undoAvailable(bool)), undo, SLOT(setEnabled(bool)));
 
244
    connect(manager, SIGNAL(undoTextChanged(QString)), SLOT(undoTextChanged(QString)));
 
245
    undo->setEnabled(manager->undoAvailable());
 
246
 
 
247
    KAction *paste = KStandardAction::paste(this, SLOT(paste()), this);
 
248
    KAction *pasteTo = KStandardAction::paste(this, SLOT(pasteTo()), this);
 
249
    pasteTo->setEnabled(false); // Only enabled during popupMenu()
 
250
 
 
251
    QString actionText = KIO::pasteActionText();
 
252
    if (!actionText.isEmpty()) {
 
253
        paste->setText(actionText);
 
254
    } else {
 
255
        paste->setEnabled(false);
 
256
    }
 
257
 
 
258
    KAction *rename = new KAction(KIcon("edit-rename"), i18n("&Rename"), this);
 
259
    rename->setShortcut(Qt::Key_F2);
 
260
    connect(rename, SIGNAL(triggered()), SLOT(renameSelectedIcon()));
 
261
 
 
262
    KAction *trash = new KAction(KIcon("user-trash"), i18n("&Move to Trash"), this);
 
263
    trash->setShortcut(Qt::Key_Delete);
 
264
    connect(trash, SIGNAL(triggered(Qt::MouseButtons, Qt::KeyboardModifiers)),
 
265
            SLOT(moveToTrash(Qt::MouseButtons, Qt::KeyboardModifiers)));
 
266
 
 
267
    KAction *emptyTrash = new KAction(KIcon("trash-empty"), i18n("&Empty Trash Bin"), this);
 
268
    KConfig trashConfig("trashrc", KConfig::SimpleConfig);
 
269
    emptyTrash->setEnabled(!trashConfig.group("Status").readEntry("Empty", true));
 
270
    connect(emptyTrash, SIGNAL(triggered()), SLOT(emptyTrashBin()));
 
271
 
 
272
    KAction *del = new KAction(i18n("&Delete"), this);
 
273
    del->setIcon(KIcon("edit-delete"));
 
274
    del->setShortcut(Qt::SHIFT + Qt::Key_Delete);
 
275
    connect(del, SIGNAL(triggered()), SLOT(deleteSelectedIcons()));
 
276
 
 
277
    // Create the new menu
 
278
    m_newMenu = new KNewFileMenu(&m_actionCollection, "new_menu", this);
 
279
    connect(m_newMenu->menu(), SIGNAL(aboutToShow()), this, SLOT(aboutToShowCreateNew()));
 
280
 
 
281
    m_actionCollection.addAction("undo", undo);
 
282
    m_actionCollection.addAction("cut", cut);
 
283
    m_actionCollection.addAction("copy", copy);
 
284
    m_actionCollection.addAction("paste", paste);
 
285
    m_actionCollection.addAction("pasteto", pasteTo);
 
286
    m_actionCollection.addAction("rename", rename);
 
287
    m_actionCollection.addAction("trash", trash);
 
288
    m_actionCollection.addAction("del", del);
 
289
    m_actionCollection.addAction("empty_trash", emptyTrash);
 
290
}
 
291
 
 
292
void PopupView::contextMenuRequest(QWidget *widget, const QPoint &screenPos)
 
293
{
 
294
    Q_UNUSED(widget)
 
295
    // contextMenuRequest is only called from the icon view, which is created in init()
 
296
    // which mean m_model should always be initialized
 
297
    Q_ASSERT(m_model);
 
298
 
 
299
    if (m_actionCollection.isEmpty()) {
 
300
        createActions();
 
301
    }
 
302
 
 
303
    KFileItemList items;
 
304
    bool hasRemoteFiles = false;
 
305
    bool isTrashLink = false;
 
306
 
 
307
    foreach (const QModelIndex &index, m_selectionModel->selectedIndexes()) {
 
308
        KFileItem item = m_model->itemForIndex(index);
 
309
        if (!item.isNull()) {
 
310
            hasRemoteFiles |= item.localPath().isEmpty();
 
311
            items.append(item);
 
312
        }
 
313
    }
 
314
 
 
315
    // Check if we're showing the menu for the trash link
 
316
    if (items.count() == 1 && items.at(0).isDesktopFile()) {
 
317
        KDesktopFile file(items.at(0).localPath());
 
318
        if (file.readType() == "Link" && file.readUrl() == "trash:/") {
 
319
            isTrashLink = true;
 
320
        }
 
321
    }
 
322
 
 
323
    QAction* pasteTo = m_actionCollection.action("pasteto");
 
324
    if (pasteTo) {
 
325
        pasteTo->setEnabled(m_actionCollection.action("paste")->isEnabled());
 
326
        pasteTo->setText(m_actionCollection.action("paste")->text());
 
327
    }
 
328
 
 
329
    QList<QAction*> editActions;
 
330
    editActions.append(m_actionCollection.action("rename"));
 
331
 
 
332
    KConfigGroup configGroup(KGlobal::config(), "KDE");
 
333
    bool showDeleteCommand = configGroup.readEntry("ShowDeleteCommand", false);
 
334
 
 
335
    // Don't add the "Move to Trash" action if we're showing the menu for the trash link
 
336
    if (!isTrashLink) {
 
337
        if (!hasRemoteFiles) {
 
338
            editActions.append(m_actionCollection.action("trash"));
 
339
        } else {
 
340
            showDeleteCommand = true;
 
341
        }
 
342
    }
 
343
    if (showDeleteCommand) {
 
344
        editActions.append(m_actionCollection.action("del"));
 
345
    }
 
346
 
 
347
    KParts::BrowserExtension::ActionGroupMap actionGroups;
 
348
    actionGroups.insert("editactions", editActions);
 
349
 
 
350
    KParts::BrowserExtension::PopupFlags flags = KParts::BrowserExtension::ShowProperties;
 
351
    flags |= KParts::BrowserExtension::ShowUrlOperations;
 
352
 
 
353
    // m_newMenu can be NULL here but KonqPopupMenu does handle this.
 
354
    KonqPopupMenu *contextMenu = new KonqPopupMenu(items, m_url, m_actionCollection, m_newMenu,
 
355
                                                   KonqPopupMenu::ShowNewWindow, flags,
 
356
                                                   QApplication::desktop(),
 
357
                                                   KBookmarkManager::userBookmarksManager(),
 
358
                                                   actionGroups);
 
359
 
 
360
    m_showingMenu = true;
 
361
    contextMenu->exec(screenPos);
 
362
    delete contextMenu;
 
363
    m_showingMenu = false;
 
364
 
 
365
    if (pasteTo) {
 
366
        pasteTo->setEnabled(false);
 
367
    }
 
368
}
 
369
 
 
370
KUrl::List PopupView::selectedUrls() const
 
371
{
 
372
    Q_ASSERT(m_model);
 
373
 
 
374
    KUrl::List urls;
 
375
    foreach (const QModelIndex &index, m_selectionModel->selectedIndexes())
 
376
    {
 
377
        KFileItem item = m_model->itemForIndex(index);
 
378
        // Prefer the local URL if there is one, since we can't trash remote URL's
 
379
        const QString path = item.localPath();
 
380
        if (!path.isEmpty()) {
 
381
            urls.append(path);
 
382
        } else {
 
383
            urls.append(item.url());
 
384
        }
 
385
    }
 
386
    return urls;
 
387
}
 
388
 
 
389
void PopupView::cut()
 
390
{
 
391
    QMimeData *mimeData = m_model->mimeData(m_selectionModel->selectedIndexes());
 
392
    KonqMimeData::addIsCutSelection(mimeData, true);
 
393
    QApplication::clipboard()->setMimeData(mimeData);
 
394
}
 
395
 
 
396
void PopupView::copy()
 
397
{
 
398
    QMimeData *mimeData = m_model->mimeData(m_selectionModel->selectedIndexes());
 
399
    QApplication::clipboard()->setMimeData(mimeData);
 
400
}
 
401
 
 
402
void PopupView::paste()
 
403
{
 
404
    KonqOperations::doPaste(QApplication::desktop(), m_url);
 
405
}
 
406
 
 
407
void PopupView::pasteTo()
 
408
{
 
409
    KUrl::List urls = selectedUrls();
 
410
    Q_ASSERT(urls.count() == 1);
 
411
    KonqOperations::doPaste(QApplication::desktop(), urls.first());
 
412
}
 
413
 
 
414
void PopupView::moveToTrash(Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
 
415
{
 
416
    Q_UNUSED(buttons)
 
417
    if (!m_iconView->renameInProgress()) {
 
418
        KonqOperations::Operation op = (modifiers & Qt::ShiftModifier) ?
 
419
                KonqOperations::DEL : KonqOperations::TRASH;
 
420
 
 
421
        KonqOperations::del(QApplication::desktop(), op, selectedUrls());
 
422
    }
 
423
}
 
424
 
 
425
void PopupView::deleteSelectedIcons()
 
426
{
 
427
    if (!m_iconView->renameInProgress()) {
 
428
        KonqOperations::del(QApplication::desktop(), KonqOperations::DEL, selectedUrls());
 
429
    }
 
430
}
 
431
 
 
432
void PopupView::renameSelectedIcon()
 
433
{
 
434
    activateWindow();
 
435
    m_iconView->renameSelectedIcon();
 
436
}
 
437
 
 
438
void PopupView::activated(const QModelIndex &index)
 
439
{
 
440
    const KFileItem item = m_model->itemForIndex(index);
 
441
    item.run();
 
442
 
 
443
    closeThisAndParentPopup();
 
444
}
 
445
 
 
446
void PopupView::setBusy(bool busy)
 
447
{
 
448
    m_busy = busy;
 
449
    if (busy && !m_busyWidget) {
 
450
        QTimer::singleShot(100, this, SLOT(createBusyWidgetIfNeeded()));
 
451
    } else {
 
452
        delete m_busyWidget;
 
453
        m_busyWidget = 0;
 
454
    }
 
455
}
 
456
 
 
457
void PopupView::createBusyWidgetIfNeeded()
 
458
{
 
459
    if (m_busy && !m_busyWidget) {
 
460
        const int size = qMin(width(), height()) * .3;
 
461
        m_busyWidget = new Plasma::BusyWidget;
 
462
        m_busyWidget->setGeometry(QStyle::alignedRect(layoutDirection(), Qt::AlignCenter, QSize(size, size), contentsRect()));
 
463
        m_scene->addItem(m_busyWidget);
 
464
    }
 
465
}
 
466
 
 
467
void PopupView::emptyTrashBin()
 
468
{
 
469
    KonqOperations::emptyTrash(QApplication::desktop());
 
470
}
 
471
 
 
472
void PopupView::undoTextChanged(const QString &text)
 
473
{
 
474
    if (QAction *action = m_actionCollection.action("undo")) {
 
475
        action->setText(text);
 
476
    }
 
477
}
 
478
 
 
479
void PopupView::aboutToShowCreateNew()
 
480
{
 
481
    if (m_newMenu) {
 
482
        m_newMenu->checkUpToDate();
 
483
        m_newMenu->setPopupFiles(m_url);
 
484
    }
 
485
}
 
486
 
 
487
void PopupView::resizeEvent(QResizeEvent *event)
 
488
{
 
489
    Q_UNUSED(event)
 
490
 
 
491
    m_background->resizeFrame(rect().size());
 
492
 
 
493
    if (m_view) {
 
494
        m_view->setGeometry(contentsRect());
 
495
    }
 
496
 
 
497
    if (KWindowSystem::compositingActive()) {
 
498
        Plasma::WindowEffects::enableBlurBehind(winId(), true, m_background->mask());
 
499
    } else {
 
500
        setMask(m_background->mask());
 
501
    }
 
502
}
 
503
 
 
504
void PopupView::paintEvent(QPaintEvent *event)
 
505
{
 
506
    Q_UNUSED(event)
 
507
 
 
508
    QPainter p(this);
 
509
    p.setCompositionMode(QPainter::CompositionMode_Source);
 
510
    p.fillRect(rect(), Qt::transparent);
 
511
    p.setCompositionMode(QPainter::CompositionMode_SourceOver);
 
512
    m_background->paintFrame(&p);
 
513
}
 
514
 
 
515
void PopupView::contextMenuEvent(QContextMenuEvent *event)
 
516
{
 
517
    if (!m_model) {
 
518
        init();
 
519
    }
 
520
 
 
521
    if (m_actionCollection.isEmpty()) {
 
522
        createActions();
 
523
    }
 
524
 
 
525
    KFileItem rootItem = m_model->itemForIndex(QModelIndex());
 
526
    //The root item is invalid (non-existent)
 
527
    if (rootItem.isNull()) {
 
528
        return;
 
529
    }
 
530
    
 
531
    QMenu menu;
 
532
    menu.addAction(m_actionCollection.action("new_menu"));
 
533
    menu.addSeparator();
 
534
    menu.addAction(m_actionCollection.action("undo"));
 
535
    menu.addAction(m_actionCollection.action("paste"));
 
536
    menu.addSeparator();
 
537
 
 
538
    // Add an action for opening the folder in the preferred application.
 
539
    if (!m_itemActions) {
 
540
        // Create a new KFileItem to prevent the target URL in the root item
 
541
        // from being used. In this case we want the configured URL instead.
 
542
        KFileItem item(rootItem.mode(), rootItem.permissions(), m_url);
 
543
 
 
544
        KFileItemListProperties itemList(KFileItemList() << item);
 
545
 
 
546
        m_itemActions = new KFileItemActions(this);
 
547
        m_itemActions->setItemListProperties(itemList);
 
548
    }
 
549
    menu.addAction(m_itemActions->preferredOpenWithAction(QString()));
 
550
 
 
551
    if (m_url.protocol() == "trash") {
 
552
        menu.addAction(m_actionCollection.action("empty_trash"));
 
553
    }
 
554
 
 
555
    m_showingMenu = true;
 
556
    menu.exec(event->globalPos());
 
557
    m_showingMenu = false;
 
558
}
 
559
 
 
560
// This function calls a given method in the parent PopupView, and returns true
 
561
// if successful or false otherwise.
 
562
bool PopupView::callOnParent(const char *method)
 
563
{
 
564
    // Since the scene is a child of the popup view, we can get to the parent view easily
 
565
    PopupView *parentView = qobject_cast<PopupView*>(m_parentView->scene()->parent());
 
566
 
 
567
    if (parentView) {
 
568
        // We use a delayed call to give enter and leave events time be delivered
 
569
        QMetaObject::invokeMethod(parentView, method, Qt::QueuedConnection);
 
570
        return true;
 
571
    }
 
572
 
 
573
    return false;
 
574
}
 
575
 
 
576
void PopupView::maybeClose()
 
577
{
 
578
    if (!underMouse() && !m_showingMenu &&
 
579
        (!m_iconView || (!m_iconView->isUnderMouse() && !m_iconView->dragInProgress())) &&
 
580
        !callOnParent("maybeClose") && !m_hideTimer.isActive()) {
 
581
        m_hideTimer.start(400, this);
 
582
    }
 
583
}
 
584
 
 
585
void PopupView::closeThisAndParentPopup() {
 
586
    hide();
 
587
    deleteLater();
 
588
    callOnParent("closeThisAndParentPopup");
 
589
}
 
590
 
 
591
void PopupView::cancelHideTimer()
 
592
{
 
593
    m_hideTimer.stop();
 
594
 
 
595
    // Propagate the call down the chain of popups
 
596
    callOnParent("cancelHideTimer");
 
597
}
 
598
 
 
599
void PopupView::enterEvent(QEvent *event)
 
600
{
 
601
    Q_UNUSED(event)
 
602
 
 
603
    // Make sure that any hide timer down the popup chain is stopped
 
604
    cancelHideTimer();
 
605
}
 
606
 
 
607
void PopupView::leaveEvent(QEvent *event)
 
608
{
 
609
    Q_UNUSED(event)
 
610
 
 
611
    // The popups are normally closed by the icon views that created them
 
612
    // in response to hover events, but when the cursor leaves a popup and
 
613
    // enters a widget that isn't an icon view in the popup chain, that
 
614
    // mechanism doesn't work.
 
615
    //
 
616
    // To make sure that the popups are closed when this happens, we call
 
617
    // maybeClose() which checks if the popup is under the mouse cursor,
 
618
    // and if it isn't it calls maybeClose() in the next popup in the chain
 
619
    // and so on.  If no popups in the chain is under the mouse cursor,
 
620
    // the root popup will start the hide timer which will close the whole 
 
621
    // chain when it fires. 
 
622
    if (!m_iconView || !m_iconView->popupVisible()) {
 
623
        maybeClose();
 
624
    }
 
625
}
 
626
 
 
627
void PopupView::dragEnterEvent(QDragEnterEvent *event)
 
628
{
 
629
    m_hideTimer.stop();
 
630
    callOnParent("cancelHideTimer");
 
631
 
 
632
    // If the popup is open during a drag and drop operation,
 
633
    // assume that we accept the mimetype.
 
634
    event->setAccepted(true);
 
635
}
 
636
 
 
637
void PopupView::dragLeaveEvent(QDragLeaveEvent *event)
 
638
{
 
639
    if (!m_iconView || !m_iconView->popupVisible()) {
 
640
        maybeClose();
 
641
    }
 
642
 
 
643
    // If the popup is open during a drag and drop operation,
 
644
    // assume that we accept the mimetype.
 
645
    event->setAccepted(true);
 
646
}
 
647
 
 
648
void PopupView::timerEvent(QTimerEvent *event)
 
649
{
 
650
    if (event->timerId() == m_hideTimer.timerId()) {
 
651
        m_hideTimer.stop();
 
652
        emit requestClose();
 
653
    }
 
654
}
 
655
 
 
656
#include "popupview.moc"
 
657