Commit 3a22bbd5 authored by Ragnar Thomsen's avatar Ragnar Thomsen
Browse files

Add support for reading archive comments

Add support for reading comments in CLI-based plugins such as rar and
zip. The comment is parsed from the output of ListJob. The comment is
displayed below the file view in a read-only QPlainTextEdit with
monospace font. A QSplitter is used so the user can resize the comment
field.

Support is added to clirar, clizip and cli7z plugins. The 7z-format
doesn't support comments, but the cli7z-plugin supports reading comments
in e.g. zip archives.

BUG: 328790
FIXED-IN: 15.12.0
REVIEW: 124468
parent d4a3b8a5
......@@ -352,6 +352,11 @@ bool Archive::isPasswordProtected()
return m_isPasswordProtected;
}
QString Archive::comment() const
{
return m_iface->comment();
}
QString Archive::subfolderName()
{
listIfNotListed();
......
......@@ -179,6 +179,7 @@ public:
void setPassword(const QString &password);
void enableHeaderEncryption(bool enable);
QString comment() const;
private slots:
void onListFinished(KJob*);
......@@ -195,6 +196,7 @@ private:
bool m_isReadOnly;
bool m_isPasswordProtected;
bool m_isSingleFolderArchive;
QString m_subfolderName;
qlonglong m_extractedFilesSize;
ArchiveError m_error;
......
......@@ -55,6 +55,11 @@ QString ReadOnlyArchiveInterface::filename() const
return m_filename;
}
QString ReadOnlyArchiveInterface::comment() const
{
return m_comment;
}
bool ReadOnlyArchiveInterface::isReadOnly() const
{
return true;
......
......@@ -52,6 +52,11 @@ public:
*/
QString filename() const;
/**
* Returns the comment of the archive.
*/
QString comment() const;
/**
* Returns whether the file can only be read.
*
......@@ -87,7 +92,6 @@ public:
* the user of the error condition.
*/
virtual bool copyFiles(const QList<QVariant> & files, const QString & destinationDirectory, ExtractionOptions options) = 0;
bool waitForFinishedSignal();
virtual bool doKill();
......@@ -119,6 +123,7 @@ protected:
bool isHeaderEncryptionEnabled() const;
void setCorrupt(bool isCorrupt);
bool isCorrupt() const;
QString m_comment;
private:
QString m_filename;
......
......@@ -275,7 +275,6 @@ public:
virtual void resetParsing() = 0;
virtual ParameterList parameterList() const = 0;
virtual bool readListLine(const QString &line) = 0;
bool doKill() Q_DECL_OVERRIDE;
bool doSuspend() Q_DECL_OVERRIDE;
bool doResume() Q_DECL_OVERRIDE;
......
......@@ -67,6 +67,8 @@
#include <QIcon>
#include <QInputDialog>
#include <QFileSystemWatcher>
#include <QGroupBox>
#include <QPlainTextEdit>
using namespace Kerfuffle;
......@@ -101,6 +103,16 @@ Part::Part(QWidget *parentWidget, QObject *parent, const QVariantList& args)
m_view = new ArchiveView;
m_infoPanel = new InfoPanel(m_model);
// Add widgets for the comment field.
m_commentView = new QPlainTextEdit();
m_commentView->setReadOnly(true);
m_commentView->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
m_commentBox = new QGroupBox(i18n("Comment"));
m_commentBox->hide();
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(m_commentView);
m_commentBox->setLayout(vbox);
setWidget(mainWidget);
mainWidget->setLayout(m_vlayout);
......@@ -108,8 +120,15 @@ Part::Part(QWidget *parentWidget, QObject *parent, const QVariantList& args)
m_vlayout->setContentsMargins(0,0,0,0);
m_vlayout->addWidget(m_splitter);
// Add widgets to the QSplitter.
m_splitter->addWidget(m_view);
// Vertical QSplitter for the file view and comment field.
m_commentSplitter = new QSplitter(Qt::Vertical, parentWidget);
m_commentSplitter->setOpaqueResize(false);
m_commentSplitter->addWidget(m_view);
m_commentSplitter->addWidget(m_commentBox);
m_commentSplitter->setCollapsible(0, false);
// Horizontal QSplitter for the file view and infopanel.
m_splitter->addWidget(m_commentSplitter);
m_splitter->addWidget(m_infoPanel);
// Read settings from config file and show/hide infoPanel.
......@@ -552,6 +571,15 @@ void Part::slotLoadingFinished(KJob *job)
m_view->header()->resizeSections(QHeaderView::ResizeToContents);
updateActions();
if (!m_model->archive()->comment().isEmpty()) {
m_commentView->setPlainText(m_model->archive()->comment());
m_commentBox->show();
m_commentSplitter->setSizes(QList<int>() << m_view->height() * 0.6 << 1);
} else {
m_commentView->clear();
m_commentBox->hide();
}
}
void Part::setReadyGui()
......@@ -1084,11 +1112,11 @@ void Part::slotShowContextMenu()
void Part::displayMsgWidget(KMessageWidget::MessageType type, QString msg)
{
KMessageWidget *msgWidget = new KMessageWidget;
msgWidget->setText(msg);
msgWidget->setMessageType(type);
m_vlayout->insertWidget(0, msgWidget);
msgWidget->animatedShow();
KMessageWidget *msgWidget = new KMessageWidget();
msgWidget->setText(msg);
msgWidget->setMessageType(type);
m_vlayout->insertWidget(0, msgWidget);
msgWidget->animatedShow();
}
} // namespace Ark
......
......@@ -47,6 +47,8 @@ class QTemporaryDir;
class QVBoxLayout;
class QSignalMapper;
class QFileSystemWatcher;
class QGroupBox;
class QPlainTextEdit;
namespace Ark
{
......@@ -142,6 +144,9 @@ private:
QVBoxLayout *m_vlayout;
QSignalMapper *m_signalMapper;
QFileSystemWatcher *m_fileWatcher;
QSplitter *m_commentSplitter;
QGroupBox *m_commentBox;
QPlainTextEdit *m_commentView;
};
} // namespace Ark
......
......@@ -39,6 +39,7 @@ CliPlugin::CliPlugin(QObject *parent, const QVariantList & args)
: CliInterface(parent, args)
, m_archiveType(ArchiveType7z)
, m_parseState(ParseStateTitle)
, m_linesComment(0)
{
qCDebug(ARK) << "Loaded cli_7z plugin";
}
......@@ -50,6 +51,7 @@ CliPlugin::~CliPlugin()
void CliPlugin::resetParsing()
{
m_parseState = ParseStateTitle;
m_comment.clear();
}
ParameterList CliPlugin::parameterList() const
......@@ -107,6 +109,7 @@ bool CliPlugin::readListLine(const QString& line)
static const QLatin1String archiveInfoDelimiter1("--"); // 7z 9.13+
static const QLatin1String archiveInfoDelimiter2("----"); // 7z 9.04
static const QLatin1String entryInfoDelimiter("----------");
const QRegularExpression rxComment(QStringLiteral("Comment = .+$"));
if (m_parseState == ParseStateTitle) {
......@@ -157,6 +160,23 @@ bool CliPlugin::readListLine(const QString& line)
qCWarning(ARK) << "Unsupported archive type";
return false;
}
} else if (rxComment.match(line).hasMatch()) {
m_parseState = ParseStateComment;
m_comment.append(line.section(QLatin1Char('='), 1) + QLatin1Char('\n'));
}
} else if (m_parseState == ParseStateComment) {
if (line == entryInfoDelimiter) {
m_parseState = ParseStateEntryInformation;
if (!m_comment.trimmed().isEmpty()) {
m_comment = m_comment.trimmed();
m_linesComment = m_comment.count(QLatin1Char('\n')) + 1;
qCDebug(ARK) << "Found a comment with" << m_linesComment << "lines";
}
} else {
m_comment.append(line + QLatin1Char('\n'));
}
} else if (m_parseState == ParseStateEntryInformation) {
......
......@@ -53,9 +53,11 @@ private:
ParseStateTitle = 0,
ParseStateHeader,
ParseStateArchiveInformation,
ParseStateComment,
ParseStateEntryInformation
} m_parseState;
int m_linesComment;
Kerfuffle::ArchiveEntry m_currentArchiveEntry;
};
......
......@@ -47,6 +47,7 @@ CliPlugin::~CliPlugin()
void CliPlugin::resetParsing()
{
m_parseState = ParseStateHeader;
m_comment.clear();
}
ParameterList CliPlugin::parameterList() const
......
......@@ -65,8 +65,6 @@ private:
int m_remainingIgnoreLines;
int m_linesComment;
QString m_comment;
};
#endif // CLIPLUGIN_H
......@@ -37,6 +37,7 @@ K_PLUGIN_FACTORY( CliPluginFactory, registerPlugin< CliPlugin >(); )
CliPlugin::CliPlugin(QObject *parent, const QVariantList & args)
: CliInterface(parent, args)
, m_parseState(ParseStateHeader)
, m_linesComment(0)
{
qCDebug(ARK) << "Loaded cli_zip plugin";
}
......@@ -48,6 +49,7 @@ CliPlugin::~CliPlugin()
void CliPlugin::resetParsing()
{
m_parseState = ParseStateHeader;
m_comment.clear();
}
// #208091: infozip applies special meanings to some characters, so we
......@@ -85,6 +87,7 @@ ParameterList CliPlugin::parameterList() const
p[ListArgs] = QStringList() << QStringLiteral("-l")
<< QStringLiteral("-T")
<< QStringLiteral("-z")
<< QStringLiteral("$Archive");
p[ExtractArgs] = QStringList() << QStringLiteral("$PreservePathSwitch")
<< QStringLiteral("$PasswordSwitch")
......@@ -124,10 +127,30 @@ bool CliPlugin::readListLine(const QString &line)
static const QRegularExpression entryPattern(QStringLiteral(
"^(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(\\d{8}).(\\d{6})\\s+(.+)$") );
// RegExp to identify the line preceding comments.
const QRegularExpression commentPattern(QStringLiteral("^Archive: .*$"));
// RegExp to identify the line following comments.
const QRegularExpression commentEndPattern(QStringLiteral("^Zip file size: .*$"));
switch (m_parseState) {
case ParseStateHeader:
m_parseState = ParseStateEntry;
if (commentPattern.match(line).hasMatch()) {
m_parseState = ParseStateComment;
} else if (commentEndPattern.match(line).hasMatch()){
m_parseState = ParseStateEntry;
}
break;
case ParseStateComment:
if (commentEndPattern.match(line).hasMatch()) {
m_parseState = ParseStateEntry;
if (!m_comment.trimmed().isEmpty()) {
m_comment = m_comment.trimmed();
m_linesComment = m_comment.count(QLatin1Char('\n')) + 1;
qCDebug(ARK) << "Found a comment with" << m_linesComment << "lines";
}
} else {
m_comment.append(line + QLatin1Char('\n'));
}
case ParseStateEntry:
QRegularExpressionMatch rxMatch = entryPattern.match(line);
if (rxMatch.hasMatch()) {
......@@ -158,4 +181,5 @@ bool CliPlugin::readListLine(const QString &line)
return true;
}
#include "cliplugin.moc"
......@@ -39,8 +39,11 @@ public:
private:
enum ParseState {
ParseStateHeader = 0,
ParseStateComment,
ParseStateEntry
} m_parseState;
int m_linesComment;
};
#endif // CLIPLUGIN_H
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment