Commit d5bdae6c authored by Bart De Vries's avatar Bart De Vries Committed by Nate Graham
Browse files

Implement KMessageWidget to report import errors.

Summary:
Add a KMessageWidget to report any errors that have occured during
the import:
- Files that have failed to copy into the temporary directory.
- Files that failed to rename/move to their final location.
- Subfolders (as defined by FileRenameFormatter) that failed to
  create.

Depending on the kind of failure(s), the KMessageWidget will contain
one or two actions to show a detailed list of files and/or subfolder
failures.

Test Plan:
Tested extensively with all kinds of errors:
- set file permissions such that files cannot be copied into their
  final location;
- set directory permissions such that subfolders cannot be created.
For each case observed that errors were reported correctly.
Tested that KMessageWidget stays hidden after import without errors.
Tested that previous errors have been correctly cleared when doing
a second import right after the first (without closing the program).

Reviewers: #gwenview, #kde_applications, ngraham

Reviewed By: #gwenview, #kde_applications, ngraham

Subscribers: ngraham

Tags: #gwenview

Differential Revision: https://phabricator.kde.org/D25111
parent 09119995
......@@ -26,12 +26,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA
#include <QList>
#include <QVBoxLayout>
#include <QPushButton>
#include <QAction>
// KDE
#include <KGuiItem>
#include <KMessageBox>
// Local
#include <ui_dialogpage.h>
#include "importdialog.h"
namespace Gwenview
{
......@@ -41,14 +44,81 @@ struct DialogPagePrivate : public Ui_DialogPage
QVBoxLayout* mLayout;
QList<QPushButton*> mButtons;
QEventLoop* mEventLoop;
DialogPage* q;
QStringList failedFileList;
QStringList failedDirList;
QAction* fileDetails;
QAction* dirDetails;
void setupFailedListActions()
{
fileDetails = new QAction(i18n("Show failed files..."));
mErrorMessageWidget->addAction(fileDetails);
QObject::connect(fileDetails, &QAction::triggered,
q, &DialogPage::slotShowFailedFileDetails);
fileDetails->setVisible(false);
dirDetails = new QAction(i18n("Show failed subfolders..."));
mErrorMessageWidget->addAction(dirDetails);
QObject::connect(dirDetails, &QAction::triggered,
q, &DialogPage::slotShowFailedDirDetails);
dirDetails->setVisible(false);
}
void showErrors(const QStringList& files, const QStringList& dirs)
{
mErrorMessageWidget->setVisible(true);
failedFileList.clear();
failedDirList.clear();
QStringList message;
if (files.count() > 0) {
failedFileList = files;
message << i18np("Failed to import %1 document.",
"Failed to import %1 documents.",
files.count());
fileDetails->setVisible(true);
} else fileDetails->setVisible(false);
if (dirs.count() > 0) {
failedDirList = dirs;
message << i18np("Failed to create %1 destination subfolder.",
"Failed to create %1 destination subfolders.",
dirs.count());
dirDetails->setVisible(true);
} else dirDetails->setVisible(false);
mErrorMessageWidget->setText(message.join("<br/>"));
mErrorMessageWidget->animatedShow();
}
void showFailedFileDetails()
{
QString message = i18n("Failed to import documents:");
KMessageBox::errorList(q,
message,
failedFileList
);
}
void showFailedDirDetails()
{
QString message = i18n("Failed to create subfolders:");
KMessageBox::errorList(q,
message,
failedDirList
);
}
};
DialogPage::DialogPage(QWidget* parent)
: QWidget(parent)
, d(new DialogPagePrivate)
{
d->q = this;
d->setupUi(this);
d->mLayout = new QVBoxLayout(d->mButtonContainer);
d->setupFailedListActions();
d->mErrorMessageWidget->hide();
}
DialogPage::~DialogPage()
......@@ -82,6 +152,21 @@ int DialogPage::addButton(const KGuiItem& item)
return id;
}
void DialogPage::slotShowErrors(const QStringList& files, const QStringList& dirs)
{
d->showErrors(files, dirs);
}
void DialogPage::slotShowFailedFileDetails()
{
d->showFailedFileDetails();
}
void DialogPage::slotShowFailedDirDetails()
{
d->showFailedDirDetails();
}
int DialogPage::exec()
{
QEventLoop loop;
......
......@@ -46,6 +46,11 @@ public:
int addButton(const KGuiItem&);
int exec();
public Q_SLOTS:
void slotShowErrors(const QStringList&, const QStringList&);
void slotShowFailedFileDetails();
void slotShowFailedDirDetails();
private:
DialogPagePrivate* const d;
};
......
......@@ -6,18 +6,28 @@
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>239</height>
<width>355</width>
<height>287</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<spacer name="verticalSpacer_3">
<item row="3" column="1">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>55</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
......@@ -27,7 +37,7 @@
</property>
</spacer>
</item>
<item row="1" column="0">
<item row="2" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
......@@ -40,7 +50,7 @@
</property>
</spacer>
</item>
<item row="1" column="1">
<item row="2" column="1">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="mLabel">
......@@ -70,7 +80,7 @@
</item>
</layout>
</item>
<item row="1" column="2">
<item row="2" column="2">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
......@@ -83,34 +93,44 @@
</property>
</spacer>
</item>
<item row="2" column="1">
<spacer name="verticalSpacer_2">
<item row="1" column="1">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>55</height>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
<item row="0" column="0" colspan="3">
<widget class="KMessageWidget" name="mErrorMessageWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
<property name="messageType">
<enum>KMessageWidget::Error</enum>
</property>
</spacer>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KMessageWidget</class>
<extends>QFrame</extends>
<header>kmessagewidget.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
......@@ -58,6 +58,25 @@ public:
DialogPage* mDialogPage;
Importer* mImporter;
void checkForFailedUrls()
{
// First check for errors on file imports or subfolder creation
QList<QUrl> failedUrls = mImporter->failedUrlList();
QList<QUrl> failedSubFolders = mImporter->failedSubFolderList();
int failedUrlCount = failedUrls.count();
int failedSubFolderCount = failedSubFolders.count();
if (failedUrlCount + failedSubFolderCount > 0) {
QStringList files, dirs;
for (int i=0; i<failedUrlCount; i++) {
files << failedUrls[i].toString(QUrl::PreferLocalFile);
}
for (int i=0; i<failedSubFolderCount; i++) {
dirs << failedSubFolders[i].toString(QUrl::PreferLocalFile);
}
emit q->showErrors(files, dirs);
}
}
void deleteImportedUrls()
{
QList<QUrl> importedUrls = mImporter->importedUrlList();
......@@ -204,6 +223,8 @@ ImportDialog::ImportDialog()
this, &QWidget::close);
connect(d->mImporter, &Importer::importFinished,
this, &ImportDialog::slotImportFinished);
connect(this, &ImportDialog::showErrors,
d->mDialogPage, &DialogPage::slotShowErrors);
d->mCentralWidget->setCurrentWidget(d->mThumbnailPage);
......@@ -254,6 +275,7 @@ void ImportDialog::startImport()
void ImportDialog::slotImportFinished()
{
d->checkForFailedUrls();
d->deleteImportedUrls();
d->showWhatNext();
}
......
......@@ -50,6 +50,9 @@ private Q_SLOTS:
void slotImportFinished();
void showImportError(const QString&);
Q_SIGNALS:
void showErrors(const QStringList&, const QStringList&);
private:
ImportDialogPrivate* const d;
};
......
......@@ -62,6 +62,8 @@ struct ImporterPrivate
QList<QUrl> mUrlList;
QList<QUrl> mImportedUrlList;
QList<QUrl> mSkippedUrlList;
QList<QUrl> mFailedUrlList;
QList<QUrl> mFailedSubFolderList;
int mRenamedCount;
int mProgress;
int mJobProgress;
......@@ -138,6 +140,9 @@ struct ImporterPrivate
KJobWidgets::setWindow(job,mAuthWindow);
if (!job->exec()) { // if subfolder creation fails
qWarning() << "Could not create subfolder:" << subFolder;
if (!mFailedSubFolderList.contains(subFolder)) {
mFailedSubFolderList << subFolder;
}
result = FileUtils::RenameFailed;
} else { // if subfolder creation succeeds
result = FileUtils::rename(src, dst, mAuthWindow);
......@@ -155,6 +160,7 @@ struct ImporterPrivate
mSkippedUrlList << mCurrentUrl;
break;
case FileUtils::RenameFailed:
mFailedUrlList << mCurrentUrl;
qWarning() << "Rename failed for" << mCurrentUrl;
}
q->advance();
......@@ -189,6 +195,8 @@ void Importer::start(const QList<QUrl>& list, const QUrl& destination)
d->mUrlList = list;
d->mImportedUrlList.clear();
d->mSkippedUrlList.clear();
d->mFailedUrlList.clear();
d->mFailedSubFolderList.clear();
d->mRenamedCount = 0;
d->mProgress = 0;
d->mJobProgress = 0;
......@@ -208,7 +216,8 @@ void Importer::slotCopyDone(KJob* _job)
KIO::CopyJob* job = static_cast<KIO::CopyJob*>(_job);
QUrl url = job->destUrl();
if (job->error()) {
qWarning() << "FIXME: What do we do with failed urls?";
// Add document to failed url list and proceed with next one
d->mFailedUrlList << d->mCurrentUrl;
advance();
d->importNext();
return;
......@@ -251,6 +260,16 @@ QList<QUrl> Importer::skippedUrlList() const
return d->mSkippedUrlList;
}
QList<QUrl> Importer::failedUrlList() const
{
return d->mFailedUrlList;
}
QList<QUrl> Importer::failedSubFolderList() const
{
return d->mFailedSubFolderList;
}
int Importer::renamedCount() const
{
return d->mRenamedCount;
......
......@@ -57,6 +57,16 @@ public:
*/
QList<QUrl> skippedUrlList() const;
/**
* Documents which have failed during import
*/
QList<QUrl> failedUrlList() const;
/**
* Subfolders which failed to create during import
*/
QList<QUrl> failedSubFolderList() const;
/**
* How many documents have been renamed during import
*/
......
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