diff --git a/app/arkui.rc b/app/arkui.rc --- a/app/arkui.rc +++ b/app/arkui.rc @@ -1,5 +1,5 @@ - + &Archive @@ -13,6 +13,8 @@ + + diff --git a/kerfuffle/CMakeLists.txt b/kerfuffle/CMakeLists.txt --- a/kerfuffle/CMakeLists.txt +++ b/kerfuffle/CMakeLists.txt @@ -10,10 +10,11 @@ createdialog.cpp extractiondialog.cpp adddialog.cpp + propertiesdialog.cpp queries.cpp addtoarchive.cpp cliinterface.cpp - ) +) kconfig_add_kcfg_files(kerfuffle_SRCS settings.kcfgc) @@ -23,6 +24,7 @@ extractiondialog.ui extractionsettings.ui previewsettings.ui + propertiesdialog.ui ) ecm_qt_declare_logging_category(kerfuffle_SRCS diff --git a/kerfuffle/archive_kerfuffle.h b/kerfuffle/archive_kerfuffle.h --- a/kerfuffle/archive_kerfuffle.h +++ b/kerfuffle/archive_kerfuffle.h @@ -135,8 +135,24 @@ class KERFUFFLE_EXPORT Archive : public QObject { Q_OBJECT + Q_PROPERTY(QString fileName READ fileName) + Q_PROPERTY(QString mimeType READ mimeType) + Q_PROPERTY(bool isReadOnly READ isReadOnly) + Q_PROPERTY(bool isPasswordProtected READ isPasswordProtected) + Q_PROPERTY(bool hasComment READ hasComment) + Q_PROPERTY(qulonglong numberOfFiles READ numberOfFiles) + Q_PROPERTY(qulonglong unpackedSize READ unpackedSize) + Q_PROPERTY(qulonglong packedSize READ packedSize) public: + QString fileName() const; + QString mimeType() const; + qulonglong numberOfFiles() const; + bool isReadOnly() const; + bool isPasswordProtected(); + bool hasComment() const; + qulonglong unpackedSize() const; + qulonglong packedSize() const; static bool comparePlugins(const KPluginMetaData &p1, const KPluginMetaData &p2); static QString determineMimeType(const QString& filename); @@ -148,15 +164,13 @@ ArchiveError error() const; bool isValid() const; - QString fileName() const; + /** * @return QFileInfo(fileName()).completeBaseName() without the "tar" extension (if any). */ QString completeBaseName() const; - bool isReadOnly() const; - KJob* open(); KJob* create(); ListJob* list(); @@ -180,7 +194,6 @@ bool isSingleFolderArchive(); QString subfolderName(); - bool isPasswordProtected(); void setPassword(const QString &password); void enableHeaderEncryption(bool enable); @@ -190,6 +203,7 @@ void onListFinished(KJob*); void onAddFinished(KJob*); void onUserQuery(Kerfuffle::Query*); + void onNewEntry(const ArchiveEntry &entry); private: Archive(ReadOnlyArchiveInterface *archiveInterface, bool isReadOnly, QObject *parent = 0); @@ -203,8 +217,9 @@ bool m_isSingleFolderArchive; QString m_subfolderName; - qlonglong m_extractedFilesSize; + qulonglong m_extractedFilesSize; ArchiveError m_error; + int m_numberOfFiles; }; KERFUFFLE_EXPORT QSet supportedMimeTypes(); diff --git a/kerfuffle/archive_kerfuffle.cpp b/kerfuffle/archive_kerfuffle.cpp --- a/kerfuffle/archive_kerfuffle.cpp +++ b/kerfuffle/archive_kerfuffle.cpp @@ -207,35 +207,82 @@ , m_isPasswordProtected(false) , m_isSingleFolderArchive(false) , m_error(NoError) + , m_numberOfFiles(0) { qCDebug(ARK) << "Created archive instance"; Q_ASSERT(archiveInterface); archiveInterface->setParent(this); QMetaType::registerComparators(); QMetaType::registerDebugStreamOperator(); + + connect(m_iface, &ReadOnlyArchiveInterface::entry, this, &Archive::onNewEntry); } + Archive::~Archive() { } -bool Archive::isValid() const +QString Archive::fileName() const { - return (m_error == NoError); + return m_iface->filename(); } -ArchiveError Archive::error() const +QString Archive::mimeType() const { - return m_error; + return determineMimeType(fileName()); } bool Archive::isReadOnly() const { return (m_iface->isReadOnly() || m_isReadOnly); } +bool Archive::isPasswordProtected() +{ + listIfNotListed(); + return m_isPasswordProtected; +} + +bool Archive::hasComment() const +{ + return !m_iface->comment().isEmpty(); +} + +qulonglong Archive::numberOfFiles() const +{ + return m_numberOfFiles; +} + +qulonglong Archive::unpackedSize() const +{ + return m_extractedFilesSize; +} + +qulonglong Archive::packedSize() const +{ + return QFileInfo(fileName()).size(); +} + +void Archive::onNewEntry(const ArchiveEntry &entry) +{ + if (!entry[IsDirectory].toBool()) { + m_numberOfFiles++; + } +} + +bool Archive::isValid() const +{ + return (m_error == NoError); +} + +ArchiveError Archive::error() const +{ + return m_error; +} + KJob* Archive::open() { return 0; @@ -293,11 +340,6 @@ return newJob; } -QString Archive::fileName() const -{ - return m_iface->filename(); -} - QString Archive::completeBaseName() const { QString base = QFileInfo(fileName()).completeBaseName(); @@ -363,12 +405,6 @@ return m_isSingleFolderArchive; } -bool Archive::isPasswordProtected() -{ - listIfNotListed(); - return m_isPasswordProtected; -} - QString Archive::comment() const { return m_iface->comment(); diff --git a/kerfuffle/archiveinterface.h b/kerfuffle/archiveinterface.h --- a/kerfuffle/archiveinterface.h +++ b/kerfuffle/archiveinterface.h @@ -101,6 +101,8 @@ virtual bool isCliBased() const; virtual bool findExecutables(bool isReadWrite); + bool isHeaderEncryptionEnabled() const; + signals: void cancelled(); void error(const QString &message, const QString &details = QString()); @@ -120,7 +122,7 @@ * the operation. */ void setWaitForFinishedSignal(bool value); - bool isHeaderEncryptionEnabled() const; + void setCorrupt(bool isCorrupt); bool isCorrupt() const; QString m_comment; diff --git a/kerfuffle/propertiesdialog.h b/kerfuffle/propertiesdialog.h new file mode 100644 --- /dev/null +++ b/kerfuffle/propertiesdialog.h @@ -0,0 +1,48 @@ +/* + * ark -- archiver for the KDE project + * + * Copyright (C) 2016 Ragnar Thomsen + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PROPERTIESDIALOG_H +#define PROPERTIESDIALOG_H + +#include "kerfuffle/archive_kerfuffle.h" + +#include + +namespace Kerfuffle +{ +class KERFUFFLE_EXPORT PropertiesDialog : public QDialog +{ + Q_OBJECT + +public: + explicit PropertiesDialog(QWidget *parent, Archive *archive); +private: + class PropertiesDialogUI *m_ui; +}; +} + +#endif diff --git a/kerfuffle/propertiesdialog.cpp b/kerfuffle/propertiesdialog.cpp new file mode 100644 --- /dev/null +++ b/kerfuffle/propertiesdialog.cpp @@ -0,0 +1,85 @@ +/* + * ark -- archiver for the KDE project + * + * Copyright (C) 2016 Ragnar Thomsen + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "propertiesdialog.h" +#include "ark_debug.h" +#include "ui_propertiesdialog.h" + +#include +#include +#include + +#include +#include + +namespace Kerfuffle +{ +class PropertiesDialogUI: public QWidget, public Ui::PropertiesDialog +{ +public: + PropertiesDialogUI(QWidget *parent = 0) + : QWidget(parent) { + setupUi(this); + } +}; + +PropertiesDialog::PropertiesDialog(QWidget *parent, Archive *archive) + : QDialog(parent, Qt::Dialog) +{ + qCDebug(ARK) << "PropertiesDialog loaded"; + + QFileInfo fi(archive->fileName()); + + setWindowTitle(i18nc("@title:window", "Properties for %1", fi.fileName())); + setModal(true); + + m_ui = new PropertiesDialogUI(this); + m_ui->lblArchiveName->setText(archive->fileName()); + m_ui->lblArchiveType->setText(archive->mimeType()); + m_ui->lblReadOnly->setText(archive->isReadOnly() ? i18n("yes") : i18n("no")); + m_ui->lblPasswordProtected->setText(archive->isPasswordProtected() ? i18n("yes") : i18n("no")); + m_ui->lblHasComment->setText(archive->hasComment() ? i18n("yes") : i18n("no")); + m_ui->lblNumberOfFiles->setText(QString::number(archive->numberOfFiles())); + m_ui->lblUnpackedSize->setText(KIO::convertSize(archive->unpackedSize())); + m_ui->lblPackedSize->setText(KIO::convertSize(archive->packedSize())); + m_ui->lblCompressionRatio->setText(QString::number(float(archive->unpackedSize()) / float(archive->packedSize()), 'f', 1)); + m_ui->lblLastModified->setText(fi.lastModified().toString(QStringLiteral("yyyy-MM-dd HH:mm"))); + + // Show an icon representing the mimetype of the archive. + QMimeDatabase db; + QIcon icon; + icon = QIcon::fromTheme(db.mimeTypeForName(archive->mimeType()).iconName()); + m_ui->lblIcon->setPixmap(icon.pixmap(IconSize(KIconLoader::Desktop), IconSize(KIconLoader::Desktop))); + + connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + + m_ui->adjustSize(); + setFixedSize(m_ui->size()); +} + + +} diff --git a/kerfuffle/propertiesdialog.ui b/kerfuffle/propertiesdialog.ui new file mode 100644 --- /dev/null +++ b/kerfuffle/propertiesdialog.ui @@ -0,0 +1,203 @@ + + + PropertiesDialog + + + + 0 + 0 + 349 + 316 + + + + + 12 + + + 12 + + + 12 + + + 12 + + + + + + + + + + + + + Archive name: + + + + + + + lblArchiveNamed + + + + + + + Archive type: + + + + + + + lblArchiveType + + + + + + + Opened read-only: + + + + + + + lblReadOnly + + + + + + + Password-protected: + + + + + + + lblPasswordProtected + + + + + + + Has comment: + + + + + + + lblHasComment + + + + + + + Number of files: + + + + + + + lblNumberOfFiles + + + + + + + Unpacked size: + + + + + + + lblUnpackedSize + + + + + + + Packed size: + + + + + + + lblPackedSize + + + + + + + Compression ratio: + + + + + + + lblCompressionRatio + + + + + + + Last modified: + + + + + + + lblModified + + + + + + + + + lblIcon + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + + + QDialogButtonBox::Ok + + + false + + + + + + + + diff --git a/part/ark_part.rc b/part/ark_part.rc --- a/part/ark_part.rc +++ b/part/ark_part.rc @@ -1,13 +1,14 @@ - + &Archive + &File diff --git a/part/part.h b/part/part.h --- a/part/part.h +++ b/part/part.h @@ -95,6 +95,7 @@ void slotAddFilesDone(KJob*); void slotDeleteFiles(); void slotDeleteFilesDone(KJob*); + void slotShowProperties(); void slotShowContextMenu(); void slotActivated(QModelIndex); void slotToggleInfoPanel(bool); @@ -136,6 +137,7 @@ QAction *m_addDirAction; QAction *m_deleteFilesAction; QAction *m_saveAsAction; + QAction *m_propertiesAction; KToggleAction *m_showInfoPanelAction; InfoPanel *m_infoPanel; QSplitter *m_splitter; diff --git a/part/part.cpp b/part/part.cpp --- a/part/part.cpp +++ b/part/part.cpp @@ -35,6 +35,7 @@ #include "kerfuffle/jobs.h" #include "kerfuffle/settings.h" #include "kerfuffle/previewsettingspage.h" +#include "kerfuffle/propertiesdialog.h" #include #include @@ -357,6 +358,14 @@ connect(m_deleteFilesAction, &QAction::triggered, this, &Part::slotDeleteFiles); + m_propertiesAction = actionCollection()->addAction(QStringLiteral("properties")); + m_propertiesAction->setIcon(QIcon::fromTheme(QStringLiteral("document-properties"))); + m_propertiesAction->setText(i18nc("@action:inmenu", "&Properties")); + actionCollection()->setDefaultShortcut(m_propertiesAction, Qt::ALT + Qt::Key_Return); + m_propertiesAction->setToolTip(i18nc("@info:tooltip", "Click to see properties for archive")); + connect(m_propertiesAction, &QAction::triggered, + this, &Part::slotShowProperties); + connect(m_signalMapper, SIGNAL(mapped(int)), this, SLOT(slotOpenEntry(int))); updateActions(); @@ -402,6 +411,8 @@ isPreviewable && !isDirectory && (selectedEntriesCount == 1)); + m_propertiesAction->setEnabled(!isBusy() && + m_model->archive()); // TODO: why do we even update these menus here? // It should be enough to update them when a new dir is appended to the history. @@ -1147,6 +1158,13 @@ job->start(); } +void Part::slotShowProperties() +{ + QPointer dialog(new Kerfuffle::PropertiesDialog(0, + m_model->archive())); + dialog.data()->show(); +} + void Part::slotToggleInfoPanel(bool visible) { if (visible) {