diff --git a/ark/part/ark_part.rc b/ark/part/ark_part.rc index 044c11a5..da04d478 100644 --- a/ark/part/ark_part.rc +++ b/ark/part/ark_part.rc @@ -1,5 +1,5 @@ - + &File @@ -12,6 +12,7 @@ + &Settings @@ -25,4 +26,10 @@ + + + + + + diff --git a/ark/part/part.cpp b/ark/part/part.cpp index 09fe1cbf..b1a311e0 100644 --- a/ark/part/part.cpp +++ b/ark/part/part.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +54,7 @@ #include #include #include +#include #include #include @@ -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() << 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(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(factory()->container(QLatin1String("context_menu"), this)); + popup->popup(QCursor::pos()); +} + } // namespace Ark diff --git a/ark/part/part.h b/ark/part/part.h index 5379b9fc..93ed9635 100644 --- a/ark/part/part.h +++ b/ark/part/part.h @@ -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 selectedFiles(); QList 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 m_previewDirList; bool m_busy; + PreviewMode m_previewMode; KAbstractWidgetJobTracker *m_jobTracker; KParts::StatusBarExtension *m_statusBarExtension;