confirm when cleaning up unused images

Add config confirm_images_clean_up.
This commit is contained in:
Le Tan 2017-09-16 14:48:39 +08:00
parent cdcab4884a
commit 2b78711eb4
12 changed files with 273 additions and 22 deletions

View File

@ -0,0 +1,163 @@
#include "vconfirmdeletiondialog.h"
#include <QtWidgets>
#include "utils/vutils.h"
#include "vconfigmanager.h"
extern VConfigManager *g_config;
class ConfirmItemWidget : public QWidget
{
public:
explicit ConfirmItemWidget(QWidget *p_parent = NULL)
: QWidget(p_parent)
{
setupUI();
}
ConfirmItemWidget(bool p_checked, const QString &p_file, QWidget *p_parent = NULL)
: QWidget(p_parent)
{
setupUI();
m_checkBox->setChecked(p_checked);
m_fileLabel->setText(p_file);
}
bool isChecked() const
{
return m_checkBox->isChecked();
}
QString getFile() const
{
return m_fileLabel->text();
}
private:
void setupUI()
{
m_checkBox = new QCheckBox;
m_fileLabel = new QLabel;
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(m_checkBox);
mainLayout->addWidget(m_fileLabel);
mainLayout->addStretch();
mainLayout->setContentsMargins(3, 0, 0, 0);
setLayout(mainLayout);
}
QCheckBox *m_checkBox;
QLabel *m_fileLabel;
};
VConfirmDeletionDialog::VConfirmDeletionDialog(const QString &p_title,
const QString &p_info,
const QVector<QString> &p_files,
QWidget *p_parent)
: QDialog(p_parent)
{
setupUI(p_title, p_info);
initFileItems(p_files);
}
void VConfirmDeletionDialog::setupUI(const QString &p_title, const QString &p_info)
{
QLabel *infoLabel = new QLabel(p_info);
m_listWidget = new QListWidget();
connect(m_listWidget, &QListWidget::currentRowChanged,
this, &VConfirmDeletionDialog::currentFileChanged);
m_previewer = new QLabel();
m_askAgainCB = new QCheckBox(tr("Just delete them and do not ask for confirmation again"));
m_askAgainCB->setChecked(!g_config->getConfirmImagesCleanUp());
// Ok is the default button.
m_btnBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(m_btnBox, &QDialogButtonBox::accepted,
this, [this]() {
g_config->setConfirmImagesCleanUp(!m_askAgainCB->isChecked());
QDialog::accept();
});
connect(m_btnBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
QHBoxLayout *midLayout = new QHBoxLayout;
midLayout->addWidget(m_listWidget);
midLayout->addStretch();
midLayout->addWidget(m_previewer);
midLayout->addStretch();
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(infoLabel);
mainLayout->addWidget(m_askAgainCB);
mainLayout->addWidget(m_btnBox);
mainLayout->addLayout(midLayout);
setLayout(mainLayout);
setWindowTitle(p_title);
}
QVector<QString> VConfirmDeletionDialog::getConfirmedFiles() const
{
QVector<QString> files;
for (int i = 0; i < m_listWidget->count(); ++i) {
ConfirmItemWidget *widget = getItemWidget(m_listWidget->item(i));
if (widget->isChecked()) {
files.push_back(widget->getFile());
}
}
return files;
}
void VConfirmDeletionDialog::initFileItems(const QVector<QString> &p_files)
{
m_listWidget->clear();
for (int i = 0; i < p_files.size(); ++i) {
ConfirmItemWidget *itemWidget = new ConfirmItemWidget(true,
p_files[i],
this);
QListWidgetItem *item = new QListWidgetItem();
QSize size = itemWidget->sizeHint();
size.setHeight(size.height() * 2);
item->setSizeHint(size);
m_listWidget->addItem(item);
m_listWidget->setItemWidget(item, itemWidget);
}
m_listWidget->setMinimumSize(m_listWidget->sizeHint());
m_listWidget->setCurrentRow(-1);
m_listWidget->setCurrentRow(0);
}
void VConfirmDeletionDialog::currentFileChanged(int p_row)
{
bool succeed = false;
if (p_row > -1) {
ConfirmItemWidget *widget = getItemWidget(m_listWidget->item(p_row));
if (widget) {
QPixmap image(widget->getFile());
if (!image.isNull()) {
int width = 512 * VUtils::calculateScaleFactor();
QSize previewSize(width, width);
m_previewer->setPixmap(image.scaled(previewSize));
succeed = true;
}
}
}
m_previewer->setVisible(succeed);
}
ConfirmItemWidget *VConfirmDeletionDialog::getItemWidget(QListWidgetItem *p_item) const
{
QWidget *wid = m_listWidget->itemWidget(p_item);
return dynamic_cast<ConfirmItemWidget *>(wid);
}

View File

@ -0,0 +1,42 @@
#ifndef VCONFIRMDELETIONDIALOG_H
#define VCONFIRMDELETIONDIALOG_H
#include <QDialog>
#include <QVector>
class QLabel;
class QPushButton;
class QDialogButtonBox;
class QListWidget;
class QListWidgetItem;
class ConfirmItemWidget;
class QCheckBox;
class VConfirmDeletionDialog : public QDialog
{
Q_OBJECT
public:
VConfirmDeletionDialog(const QString &p_title,
const QString &p_info,
const QVector<QString> &p_files,
QWidget *p_parent = 0);
QVector<QString> getConfirmedFiles() const;
private slots:
void currentFileChanged(int p_row);
private:
void setupUI(const QString &p_title, const QString &p_info);
void initFileItems(const QVector<QString> &p_files);
ConfirmItemWidget *getItemWidget(QListWidgetItem *p_item) const;
QListWidget *m_listWidget;
QLabel *m_previewer;
QDialogButtonBox *m_btnBox;
QCheckBox *m_askAgainCB;
};
#endif // VCONFIRMDELETIONDIALOG_H

View File

@ -2,6 +2,7 @@
#include <QValidator>
#include <QRegExp>
#include "vinsertimagedialog.h"
#include "utils/vutils.h"
VInsertImageDialog::VInsertImageDialog(const QString &title, const QString &defaultImageTitle,
const QString &defaultPath, QWidget *parent)
@ -112,7 +113,8 @@ void VInsertImageDialog::handleBrowseBtnClicked()
void VInsertImageDialog::setImage(const QImage &image)
{
Q_ASSERT(!image.isNull());
QSize previewSize(256, 256);
int width = 512 * VUtils::calculateScaleFactor();
QSize previewSize(width, width);
if (!this->image) {
this->image = new QImage(image);
} else {

View File

@ -45,6 +45,8 @@ void VNewFileDialog::setupUI()
topLayout->addRow(nameLabel, nameEdit);
topLayout->addWidget(m_insertTitleCB);
nameEdit->setMinimumWidth(m_insertTitleCB->sizeHint().width());
m_warnLabel = new QLabel();
m_warnLabel->setWordWrap(true);
m_warnLabel->hide();
@ -54,9 +56,6 @@ void VNewFileDialog::setupUI()
connect(m_btnBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(m_btnBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
QPushButton *okBtn = m_btnBox->button(QDialogButtonBox::Ok);
nameEdit->setMinimumWidth(okBtn->sizeHint().width() * 3);
QVBoxLayout *mainLayout = new QVBoxLayout();
if (infoLabel) {
mainLayout->addWidget(infoLabel);

View File

@ -11,7 +11,7 @@ VNewNotebookDialog::VNewNotebookDialog(const QString &title, const QString &info
const QString &defaultName, const QString &defaultPath,
const QVector<VNotebook *> &p_notebooks,
QWidget *parent)
: QDialog(parent), infoLabel(NULL),
: QDialog(parent),
title(title), info(info), defaultName(defaultName), defaultPath(defaultPath),
m_importNotebook(false), m_manualPath(false), m_manualName(false),
m_notebooks(p_notebooks)
@ -27,12 +27,13 @@ VNewNotebookDialog::VNewNotebookDialog(const QString &title, const QString &info
void VNewNotebookDialog::setupUI()
{
QLabel *infoLabel = NULL;
if (!info.isEmpty()) {
infoLabel = new QLabel(info);
infoLabel->setWordWrap(true);
}
nameLabel = new QLabel(tr("Notebook &name:"));
QLabel *nameLabel = new QLabel(tr("Notebook &name:"));
nameEdit = new QLineEdit(defaultName);
nameLabel->setBuddy(nameEdit);

View File

@ -7,7 +7,6 @@
class QLabel;
class QLineEdit;
class QPushButton;
class QString;
class QDialogButtonBox;
class VNotebook;
@ -49,8 +48,6 @@ private:
// Returns true if name or path is modified.
bool autoComplete();
QLabel *infoLabel;
QLabel *nameLabel;
QLineEdit *nameEdit;
QLineEdit *pathEdit;
QPushButton *browseBtn;

View File

@ -110,6 +110,9 @@ markdownit_opt_linkify=true
; Default name of the recycle bin of notebook
recycle_bin_folder=_v_recycle_bin
; Confirm before deleting unused images
confirm_images_clean_up=true
[session]
tools_dock_checked=true

View File

@ -73,7 +73,8 @@ SOURCES += main.cpp\
dialog/vupdater.cpp \
dialog/vorphanfileinfodialog.cpp \
vtextblockdata.cpp \
utils/vpreviewutils.cpp
utils/vpreviewutils.cpp \
dialog/vconfirmdeletiondialog.cpp
HEADERS += vmainwindow.h \
vdirectorytree.h \
@ -134,7 +135,8 @@ HEADERS += vmainwindow.h \
dialog/vupdater.h \
dialog/vorphanfileinfodialog.h \
vtextblockdata.h \
utils/vpreviewutils.h
utils/vpreviewutils.h \
dialog/vconfirmdeletiondialog.h
RESOURCES += \
vnote.qrc \

View File

@ -200,6 +200,9 @@ void VConfigManager::initialize()
m_recycleBinFolder = getConfigFromSettings("global",
"recycle_bin_folder").toString();
m_confirmImagesCleanUp = getConfigFromSettings("global",
"confirm_images_clean_up").toBool();
}
void VConfigManager::readPredefinedColorsFromSettings()

View File

@ -266,6 +266,9 @@ public:
const QString &getRecycleBinFolder() const;
bool getConfirmImagesCleanUp() const;
void setConfirmImagesCleanUp(bool p_enabled);
// Return the configured key sequence of @p_operation.
// Return empty if there is no corresponding config.
QString getShortcutKeySequence(const QString &p_operation) const;
@ -536,6 +539,9 @@ private:
// Default name of the recycle bin folder of notebook.
QString m_recycleBinFolder;
// Confirm before deleting unused images.
bool m_confirmImagesCleanUp;
// The name of the config file in each directory, obsolete.
// Use c_dirConfigFile instead.
static const QString c_obsoleteDirConfigFile;
@ -1387,4 +1393,20 @@ inline const QString &VConfigManager::getRecycleBinFolder() const
return m_recycleBinFolder;
}
inline bool VConfigManager::getConfirmImagesCleanUp() const
{
return m_confirmImagesCleanUp;
}
inline void VConfigManager::setConfirmImagesCleanUp(bool p_enabled)
{
if (m_confirmImagesCleanUp == p_enabled) {
return;
}
m_confirmImagesCleanUp = p_enabled;
setConfigToSettings("global",
"confirm_images_clean_up",
m_confirmImagesCleanUp);
}
#endif // VCONFIGMANAGER_H

View File

@ -176,9 +176,6 @@ bool VEdit::isModified() const
void VEdit::setModified(bool p_modified)
{
document()->setModified(p_modified);
if (m_file) {
m_file->setModified(p_modified);
}
}
void VEdit::insertImage()

View File

@ -10,6 +10,7 @@
#include "utils/veditutils.h"
#include "utils/vpreviewutils.h"
#include "dialog/vselectdialog.h"
#include "dialog/vconfirmdeletiondialog.h"
#include "vimagepreviewer.h"
#include "vtextblockdata.h"
@ -238,6 +239,8 @@ void VMdEdit::clearUnusedImages()
QVector<ImageLink> images = VUtils::fetchImagesFromMarkdownFile(m_file,
ImageLink::LocalRelativeInternal);
QVector<QString> unusedImages;
if (!m_insertedImages.isEmpty()) {
for (int i = 0; i < m_insertedImages.size(); ++i) {
const ImageLink &link = m_insertedImages[i];
@ -255,11 +258,7 @@ void VMdEdit::clearUnusedImages()
// This inserted image is no longer in the file.
if (j == images.size()) {
if (!VUtils::deleteFile(m_file->getNotebook(), link.m_path, false)) {
qWarning() << "fail to delete unused inserted image" << link.m_path;
} else {
qDebug() << "delete unused inserted image" << link.m_path;
}
unusedImages.push_back(link.m_path);
}
}
@ -280,10 +279,31 @@ void VMdEdit::clearUnusedImages()
// Original local relative image is no longer in the file.
if (j == images.size()) {
if (!VUtils::deleteFile(m_file->getNotebook(), link.m_path, false)) {
qWarning() << "fail to delete unused original image" << link.m_path;
unusedImages.push_back(link.m_path);
}
}
if (!unusedImages.isEmpty()) {
if (g_config->getConfirmImagesCleanUp()) {
QString info = tr("Following images seems not to be used in this note anymore. "
"Please confirm the deletion of these images.<br>"
"Click \"Cancel\" to leave them untouched.");
VConfirmDeletionDialog dialog(tr("Confirm Cleaning Up Unused Images"),
info,
unusedImages,
this);
if (dialog.exec()) {
unusedImages = dialog.getConfirmedFiles();
} else {
qDebug() << "delete unused original image" << link.m_path;
unusedImages.clear();
}
}
for (int i = 0; i < unusedImages.size(); ++i) {
if (!VUtils::deleteFile(m_file->getNotebook(), unusedImages[i], false)) {
qWarning() << "fail to delete unused original image" << unusedImages[i];
} else {
qDebug() << "delete unused image" << unusedImages[i];
}
}
}