implement context menu for Ark (backport)

this commits is basicly upstream ed3ea7db and 5805c830 commits
This commit is contained in:
Ivailo Monev 2014-12-21 12:48:25 +00:00
parent 2d32bf8477
commit ed5579d05a
3 changed files with 77 additions and 14 deletions

View file

@ -1,5 +1,5 @@
<!DOCTYPE kpartgui>
<kpartgui name="ark_part" version="1">
<kpartgui name="ark_part" version="2">
<MenuBar>
<Menu name="file">
<text>&amp;File</text>
@ -12,6 +12,7 @@
<Action name="delete"/>
<Action name="extract"/>
<Action name="preview"/>
<Action name="openwith"/>
</Menu>
<Menu name="settings">
<text>&amp;Settings</text>
@ -25,4 +26,10 @@
<Action name="extract"/>
<Action name="preview"/>
</ToolBar>
<Menu name="context_menu">
<Action name="delete"/>
<Action name="extract"/>
<Action name="preview"/>
<Action name="openwith"/>
</Menu>
</kpartgui>

View file

@ -45,6 +45,7 @@
#include <KIO/NetAccess>
#include <KIcon>
#include <KInputDialog>
#include <KMenu>
#include <KMessageBox>
#include <KPluginFactory>
#include <KRun>
@ -53,6 +54,7 @@
#include <KStandardGuiItem>
#include <KTempDir>
#include <KToggleAction>
#include <KXMLGUIFactory>
#include <QAction>
#include <QCursor>
@ -137,6 +139,8 @@ Part::Part(QWidget *parentWidget, QObject *parent, const QVariantList& args)
Part::~Part()
{
qDeleteAll(m_previewDirList);
saveSplitterSizes();
m_extractFilesAction->menu()->deleteLater();
@ -210,6 +214,8 @@ void Part::extractSelectedFilesTo(const QString& localPath)
void Part::setupView()
{
m_view->setContextMenuPolicy(Qt::CustomContextMenu);
m_view->setModel(m_model);
m_view->setSortingEnabled(true);
@ -220,8 +226,10 @@ void Part::setupView()
this, SLOT(selectionChanged()));
//TODO: fix an actual eventhandler
connect(m_view, SIGNAL(itemTriggered(QModelIndex)),
this, SLOT(slotPreview(QModelIndex)));
connect(m_view, SIGNAL(activated(const QModelIndex &)),
this, SLOT(slotPreviewWithInternalViewer()));
connect(m_view, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotShowContextMenu()));
connect(m_model, SIGNAL(columnsInserted(QModelIndex,int,int)),
this, SLOT(adjustColumns()));
@ -237,13 +245,19 @@ void Part::setupActions()
m_saveAsAction = KStandardAction::saveAs(this, SLOT(slotSaveAs()), actionCollection());
m_previewChooseAppAction = actionCollection()->addAction(QLatin1String("openwith"));
m_previewChooseAppAction->setText(i18nc("open a file with external program", "Open &With..."));
m_previewChooseAppAction->setIcon(KIcon(QLatin1String("document-open")));
m_previewChooseAppAction->setStatusTip(i18n("Click to open the selected file with an external program"));
connect(m_previewChooseAppAction, SIGNAL(triggered(bool)), this, SLOT(slotPreviewWithExternalProgram()));
m_previewAction = actionCollection()->addAction(QLatin1String( "preview" ));
m_previewAction->setText(i18nc("to preview a file inside an archive", "Pre&view"));
m_previewAction->setIcon(KIcon( QLatin1String( "document-preview-archive" )));
m_previewAction->setStatusTip(i18n("Click to preview the selected file"));
m_previewAction->setShortcuts(QList<QKeySequence>() << Qt::Key_Return << Qt::Key_Space);
connect(m_previewAction, SIGNAL(triggered(bool)),
this, SLOT(slotPreview()));
this, SLOT(slotPreviewWithInternalViewer()));
m_extractFilesAction = actionCollection()->addAction(QLatin1String( "extract" ));
m_extractFilesAction->setText(i18n("E&xtract"));
@ -289,6 +303,8 @@ void Part::updateActions()
m_addDirAction->setEnabled(!isBusy() && isWritable);
m_deleteFilesAction->setEnabled(!isBusy() && (m_view->selectionModel()->selectedRows().count() > 0)
&& isWritable);
m_previewChooseAppAction->setEnabled(!isBusy() && (m_view->selectionModel()->selectedRows().count() > 0)
&& isWritable);
QMenu *menu = m_extractFilesAction->menu();
if (!menu) {
@ -534,12 +550,17 @@ void Part::setFileNameFromArchive()
emit setWindowCaption(prettyName);
}
void Part::slotPreview()
void Part::slotPreviewWithInternalViewer()
{
slotPreview(m_view->selectionModel()->currentIndex());
preview(m_view->selectionModel()->currentIndex(), InternalViewer);
}
void Part::slotPreview(const QModelIndex & index)
void Part::slotPreviewWithExternalProgram()
{
preview(m_view->selectionModel()->currentIndex(), ExternalProgram);
}
void Part::preview(const QModelIndex &index, PreviewMode mode)
{
if (!isPreviewable(index)) {
return;
@ -551,7 +572,10 @@ void Part::slotPreview(const QModelIndex & index)
Kerfuffle::ExtractionOptions options;
options[QLatin1String( "PreservePaths" )] = true;
ExtractJob *job = m_model->extractFile(entry[ InternalID ], m_previewDir.name(), options);
m_previewDirList.append(new KTempDir);
m_previewMode = mode;
ExtractJob *job = m_model->extractFile(entry[InternalID], m_previewDirList.last()->name(), options);
registerJob(job);
connect(job, SIGNAL(result(KJob*)),
this, SLOT(slotPreviewExtracted(KJob*)));
@ -568,15 +592,28 @@ void Part::slotPreviewExtracted(KJob *job)
const ArchiveEntry& entry =
m_model->entryForIndex(m_view->selectionModel()->currentIndex());
QString fullName =
m_previewDir.name() + QLatin1Char('/') + entry[FileName].toString();
ExtractJob *extractJob = qobject_cast<ExtractJob*>(job);
Q_ASSERT(extractJob);
QString fullName = extractJob->destinationDirectory() + entry[FileName].toString();
// Make sure a maliciously crafted archive with parent folders named ".." do
// not cause the previewed file path to be located outside the temporary
// directory, resulting in a directory traversal issue.
fullName.remove(QLatin1String("../"));
ArkViewer::view(fullName, widget());
// TODO: get rid of m_previewMode by extending ExtractJob with a PreviewJob.
// This would prevent race conditions if we ever stop disabling
// the whole UI while extracting a file to preview it.
switch (m_previewMode) {
case InternalViewer:
ArkViewer::view(fullName, widget());
break;
case ExternalProgram:
KUrl::List list;
list.append(KUrl(fullName));
KRun::displayOpenWithDialog(list, widget(), true);
break;
}
} else {
KMessageBox::error(widget(), job->errorString());
}
@ -910,4 +947,14 @@ void Part::slotSaveAs()
}
}
void Part::slotShowContextMenu()
{
if (!factory()) {
return;
}
KMenu *popup = static_cast<KMenu *>(factory()->container(QLatin1String("context_menu"), this));
popup->popup(QCursor::pos());
}
} // namespace Ark

View file

@ -51,6 +51,11 @@ class Part: public KParts::ReadWritePart, public Interface
Q_OBJECT
Q_INTERFACES(Interface)
public:
enum PreviewMode {
InternalViewer,
ExternalProgram
};
Part(QWidget *parentWidget, QObject *parent, const QVariantList &);
~Part();
static KAboutData* createAboutData();
@ -66,8 +71,8 @@ public slots:
private slots:
void slotLoadingStarted();
void slotLoadingFinished(KJob *job);
void slotPreview();
void slotPreview(const QModelIndex & index);
void slotPreviewWithInternalViewer();
void slotPreviewWithExternalProgram();
void slotPreviewExtracted(KJob*);
void slotError(const QString& errorMessage, const QString& details);
void slotExtractFiles();
@ -79,6 +84,7 @@ private slots:
void slotAddFilesDone(KJob*);
void slotDeleteFiles();
void slotDeleteFilesDone(KJob*);
void slotShowContextMenu();
void saveSplitterSizes();
void slotToggleInfoPanel(bool);
void slotSaveAs();
@ -103,9 +109,11 @@ private:
QList<QVariant> selectedFiles();
QList<QVariant> selectedFilesWithChildren();
void registerJob(KJob *job);
void preview(const QModelIndex &index, PreviewMode mode);
ArchiveModel *m_model;
QTreeView *m_view;
KAction *m_previewChooseAppAction;
KAction *m_previewAction;
KAction *m_extractFilesAction;
KAction *m_addFilesAction;
@ -114,8 +122,9 @@ private:
KAction *m_saveAsAction;
InfoPanel *m_infoPanel;
QSplitter *m_splitter;
KTempDir m_previewDir;
QList<KTempDir*> m_previewDirList;
bool m_busy;
PreviewMode m_previewMode;
KAbstractWidgetJobTracker *m_jobTracker;
KParts::StatusBarExtension *m_statusBarExtension;