Merge pull request #963 from kiwix/moveToTrash

Deleting files move them to trash
This commit is contained in:
Kelson 2023-08-11 20:08:43 +02:00 committed by GitHub
commit 1ad4a72d0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 156 additions and 30 deletions

View File

@ -57,3 +57,15 @@ QPushButton:hover {
min-width: 14px;
font: bold;
}
QCheckBox::indicator {
width: 16px;
height: 16px;
border: 2px solid black;
border-radius: 5px;
padding: 4px;
}
QCheckBox::indicator:checked {
image: url(:/icons/check-solid.svg);
}

View File

@ -151,5 +151,8 @@
"resume-download": "Resume download",
"open-folder": "Open folder",
"couldnt-open-location": "Couldn't open location",
"couldnt-open-location-text": "Kiwix is not able to open folder {{FOLDER}}"
"couldnt-open-location-text": "Kiwix is not able to open folder {{FOLDER}}",
"move-files-to-trash": "Move deleted files to trash",
"move-files-to-trash-text": "This action will move the file to trash.",
"perma-delete-files-text": "This action will permanently delete the file."
}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7 393.4 105.4c12.5-12.5 32.8-12.5 45.3 0z"/></svg>

After

Width:  |  Height:  |  Size: 428 B

View File

@ -60,5 +60,6 @@
<file>icons/caret-right-solid.svg</file>
<file>icons/caret-up-solid.svg</file>
<file>icons/kiwix-logo.svg</file>
<file>icons/check-solid.svg</file>
</qresource>
</RCC>

View File

@ -473,20 +473,43 @@ QString ContentManager::downloadBook(const QString &id)
return QString::fromStdString(download->getDid());
}
void ContentManager::eraseBookFilesFromComputer(const QString dirPath, const QString fileName)
void ContentManager::eraseBookFilesFromComputer(const QString dirPath, const QString fileName, const bool moveToTrash)
{
if (fileName == "*") {
return;
}
QDir dir(dirPath, fileName);
for(const QString& file: dir.entryList()) {
dir.remove(file);
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
if (moveToTrash)
QFile::moveToTrash(dir.filePath(file));
else
#endif
dir.remove(file); // moveToTrash will always be false here, no check required.
}
}
QString formatText(QString text)
{
QString finalText = "<br><br><i>";
finalText += text;
finalText += "</i>";
return finalText;
}
void ContentManager::eraseBook(const QString& id)
{
auto text = gt("delete-book-text");
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
const auto moveToTrash = KiwixApp::instance()->getSettingsManager()->getMoveToTrash();
#else
const auto moveToTrash = false; // we do not support move to trash functionality for qt versions below 5.15
#endif
if (moveToTrash) {
text += formatText(gt("move-files-to-trash-text"));
} else {
text += formatText(gt("perma-delete-files-text"));
}
text = text.replace("{{ZIM}}", QString::fromStdString(mp_library->getBookById(id).getTitle()));
KiwixConfirmBox *dialog = new KiwixConfirmBox(gt("delete-book"), text, false, mp_view);
dialog->show();
@ -496,7 +519,7 @@ void ContentManager::eraseBook(const QString& id)
kiwix::Book book = mp_library->getBookById(id);
QString dirPath = QString::fromStdString(kiwix::removeLastPathElement(book.getPath()));
QString fileName = QString::fromStdString(kiwix::getLastPathElement(book.getPath())) + "*";
eraseBookFilesFromComputer(dirPath, fileName);
eraseBookFilesFromComputer(dirPath, fileName, moveToTrash);
mp_library->removeBookFromLibraryById(id);
mp_library->save();
emit mp_library->bookmarksChanged();
@ -576,7 +599,8 @@ void ContentManager::cancelBook(const QString& id)
}
QString dirPath = QString::fromStdString(kiwix::removeLastPathElement(download->getPath()));
QString filename = QString::fromStdString(kiwix::getLastPathElement(download->getPath())) + "*";
eraseBookFilesFromComputer(dirPath, filename);
// incompleted downloaded file should be perma deleted
eraseBookFilesFromComputer(dirPath, filename, false);
mp_library->removeBookFromLibraryById(id);
mp_library->save();
emit(oneBookChanged(id));

View File

@ -49,7 +49,7 @@ private:
QStringList m_categories;
QStringList getBookIds();
void eraseBookFilesFromComputer(const QString dirPath, const QString filename);
void eraseBookFilesFromComputer(const QString dirPath, const QString filename, const bool moveToTrash);
QList<QMap<QString, QVariant>> getBooksList();
ContentManagerModel *managerModel;
QMutex remoteLibraryLocker;

View File

@ -99,13 +99,17 @@ void KiwixApp::init()
}
});
connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, [=](QString monitorDir) {
m_library.asyncLoadMonitorDir(monitorDir);
m_library.asyncUpdateFromDir(monitorDir);
});
QString monitorDir = m_settingsManager.getMonitorDir();
if (monitorDir != "") {
m_library.setMonitorDirZims(m_library.getLibraryZimsFromDir(monitorDir));
m_watcher.addPath(monitorDir);
m_library.asyncLoadMonitorDir(monitorDir);
QString downloadDir = m_settingsManager.getDownloadDir();
auto dirList = QSet<QString>({monitorDir, downloadDir});
for (auto dir : dirList) {
if (dir != "") {
m_library.setMonitorDirZims(dir, m_library.getLibraryZimsFromDir(dir));
m_watcher.addPath(dir);
m_library.asyncUpdateFromDir(dir);
}
}
}
@ -284,13 +288,14 @@ bool KiwixApp::isCurrentArticleBookmarked()
void KiwixApp::setMonitorDir(const QString &dir) {
m_settingsManager.setMonitorDir(dir);
m_library.setMonitorDirZims(QStringList());
m_library.setMonitorDirZims(dir, QStringList());
for (auto path : m_watcher.directories()) {
m_watcher.removePath(path);
}
if (dir != "") {
m_watcher.addPath(dir);
m_library.asyncLoadMonitorDir(dir);
m_watcher.addPath(m_settingsManager.getDownloadDir());
m_library.asyncUpdateFromDir(dir);
}
}

View File

@ -115,9 +115,9 @@ void Library::save()
m_library.writeBookmarksToFile(kiwix::appendToDirectory(m_libraryDirectory.toStdString(), "library.bookmarks.xml"));
}
void Library::setMonitorDirZims(QStringList zimList)
void Library::setMonitorDirZims(QString monitorDir, QStringList zimList)
{
m_monitorDirZims = zimList;
m_knownZimsInDir[monitorDir] = zimList;
}
QStringList Library::getLibraryZimsFromDir(QString dir) const
@ -133,13 +133,12 @@ QStringList Library::getLibraryZimsFromDir(QString dir) const
return zimsInDir;
}
void Library::loadMonitorDir(QString monitorDir)
void Library::updateFromDir(QString monitorDir)
{
QMutex mutex;
QMutexLocker locker(&mutex);
QMutexLocker locker(&m_updateFromDirMutex);
const QDir dir(monitorDir);
QStringList newDirEntries = dir.entryList({"*.zim"});
QStringList oldDirEntries = m_monitorDirZims;
QStringList oldDirEntries = m_knownZimsInDir[monitorDir];
for (auto &str : newDirEntries) {
str = QDir::toNativeSeparators(monitorDir + "/" + str);
}
@ -160,18 +159,20 @@ void Library::loadMonitorDir(QString monitorDir)
needsRefresh |= manager.addBookFromPath(book.toStdString());
}
for (auto bookPath : removedZims) {
removeBookFromLibraryById(QString::fromStdString(m_library.getBookByPath(bookPath.toStdString()).getId()));
try {
removeBookFromLibraryById(QString::fromStdString(m_library.getBookByPath(bookPath.toStdString()).getId()));
} catch (...) {}
}
if (needsRefresh) {
setMonitorDirZims(newDir.values());
emit(booksChanged());
setMonitorDirZims(monitorDir, newDir.values());
}
}
void Library::asyncLoadMonitorDir(QString dir)
void Library::asyncUpdateFromDir(QString dir)
{
QtConcurrent::run( [=]() {
loadMonitorDir(dir);
updateFromDir(dir);
});
}

View File

@ -11,6 +11,7 @@
#include <QObject>
#include <QSharedPointer>
#include <QMap>
#include <QMutex>
#define TQS(v) (QString::fromStdString(v))
#define FORWARD_GETTER(METH) QString METH() const { return TQS(mp_book->METH()); }
@ -34,14 +35,14 @@ public:
QStringList listBookIds(const kiwix::Filter& filter, kiwix::supportedListSortBy sortBy, bool ascending) const;
const std::vector<kiwix::Bookmark> getBookmarks(bool onlyValidBookmarks = false) const { return m_library.getBookmarks(onlyValidBookmarks); }
QStringList getLibraryZimsFromDir(QString dir) const;
void setMonitorDirZims(QStringList zimList);
void setMonitorDirZims(QString monitorDir, QStringList zimList);
void addBookToLibrary(kiwix::Book& book);
void removeBookFromLibraryById(const QString& id);
void addBookmark(kiwix::Bookmark& bookmark);
void removeBookmark(const QString& zimId, const QString& url);
void save();
void loadMonitorDir(QString dir);
void asyncLoadMonitorDir(QString dir);
void updateFromDir(QString dir);
void asyncUpdateFromDir(QString dir);
kiwix::Library& getKiwixLibrary() { return m_library; }
public slots:
const kiwix::Book& getBookById(QString id) const;
@ -51,9 +52,10 @@ signals:
void bookmarksChanged();
private:
QMutex m_updateFromDirMutex;
kiwix::Library m_library;
QString m_libraryDirectory;
QStringList m_monitorDirZims;
QMap<QString, QStringList> m_knownZimsInDir;
friend class LibraryManipulator;
};

View File

@ -16,7 +16,7 @@ SettingsView* SettingsManager::getView()
{
if (m_view == nullptr) {
auto view = new SettingsView();
view->init(m_zoomFactor * 100, m_downloadDir, m_monitorDir);
view->init(m_zoomFactor * 100, m_downloadDir, m_monitorDir, m_moveToTrash);
connect(view, &QObject::destroyed, this, [=]() { m_view = nullptr; });
m_view = view;
}
@ -89,6 +89,13 @@ void SettingsManager::setMonitorDir(QString monitorDir)
emit(monitorDirChanged(monitorDir));
}
void SettingsManager::setMoveToTrash(bool moveToTrash)
{
m_moveToTrash = moveToTrash;
setSettings("moveToTrash", m_moveToTrash);
emit(moveToTrashChanged(m_moveToTrash));
}
void SettingsManager::initSettings()
{
m_kiwixServerPort = m_settings.value("localKiwixServer/port", 8080).toInt();
@ -96,4 +103,5 @@ void SettingsManager::initSettings()
m_downloadDir = m_settings.value("download/dir", QString::fromStdString(kiwix::getDataDirectory())).toString();
m_kiwixServerIpAddress = m_settings.value("localKiwixServer/ipAddress", QString("0.0.0.0")).toString();
m_monitorDir = m_settings.value("monitor/dir", QString("")).toString();
m_moveToTrash = m_settings.value("moveToTrash", true).toBool();
}

View File

@ -27,6 +27,7 @@ public:
qreal getZoomFactor() const { return m_zoomFactor; }
QString getDownloadDir() const { return m_downloadDir; }
QString getMonitorDir() const { return m_monitorDir; }
bool getMoveToTrash() const { return m_moveToTrash; }
public slots:
void setKiwixServerPort(int port);
@ -34,6 +35,7 @@ public slots:
void setZoomFactor(qreal zoomFactor);
void setDownloadDir(QString downloadDir);
void setMonitorDir(QString monitorDir);
void setMoveToTrash(bool moveToTrash);
private:
void initSettings();
@ -42,6 +44,7 @@ signals:
void zoomChanged(qreal zoomFactor);
void downloadDirChanged(QString downloadDir);
void monitorDirChanged(QString monitorDir);
void moveToTrashChanged(bool moveToTrash);
private:
QSettings m_settings;
@ -51,6 +54,7 @@ private:
qreal m_zoomFactor;
QString m_downloadDir;
QString m_monitorDir;
bool m_moveToTrash;
};
#endif // SETTINGSMANAGER_H

View File

@ -14,6 +14,7 @@ SettingsView::SettingsView(QWidget *parent)
QString styleSheet = QString(file.readAll());
ui->widget->setStyleSheet(styleSheet);
connect(ui->zoomPercentSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &SettingsView::setZoom);
connect(ui->moveToTrashToggle, &QCheckBox::clicked, this, &SettingsView::setMoveToTrash);
connect(ui->browseButton, &QPushButton::clicked, this, &SettingsView::browseDownloadDir);
connect(ui->resetButton, &QPushButton::clicked, this, &SettingsView::resetDownloadDir);
connect(ui->monitorBrowse, &QPushButton::clicked, this, &SettingsView::browseMonitorDir);
@ -21,6 +22,7 @@ SettingsView::SettingsView(QWidget *parent)
connect(KiwixApp::instance()->getSettingsManager(), &SettingsManager::downloadDirChanged, this, &SettingsView::onDownloadDirChanged);
connect(KiwixApp::instance()->getSettingsManager(), &SettingsManager::monitorDirChanged, this, &SettingsView::onMonitorDirChanged);
connect(KiwixApp::instance()->getSettingsManager(), &SettingsManager::zoomChanged, this, &SettingsView::onZoomChanged);
connect(KiwixApp::instance()->getSettingsManager(), &SettingsManager::moveToTrashChanged, this, &SettingsView::onMoveToTrashChanged);
ui->settingsLabel->setText(gt("settings"));
ui->zoomPercentLabel->setText(gt("zoom-level-setting"));
ui->downloadDirLabel->setText(gt("download-directory-setting"));
@ -31,9 +33,15 @@ SettingsView::SettingsView(QWidget *parent)
ui->monitorBrowse->setText(gt("browse"));
ui->monitorHelp->setText("<b>?</b>");
ui->monitorHelp->setToolTip(gt("monitor-directory-tooltip"));
ui->moveToTrashLabel->setText(gt("move-files-to-trash"));
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
ui->moveToTrashLabel->hide();
ui->moveToTrashToggle->hide();
#endif
}
void SettingsView::init(int zoomPercent, const QString &downloadDir, const QString &monitorDir)
void SettingsView::init(int zoomPercent, const QString &downloadDir, const QString &monitorDir, const bool moveToTrash)
{
ui->zoomPercentSpinBox->setValue(zoomPercent);
ui->downloadDirPath->setText(downloadDir);
@ -41,6 +49,7 @@ void SettingsView::init(int zoomPercent, const QString &downloadDir, const QStri
ui->monitorClear->hide();
}
ui->monitorDirPath->setText(monitorDir);
ui->moveToTrashToggle->setChecked(moveToTrash);
}
bool SettingsView::confirmDialog( QString messageText, QString messageTitle)
{
@ -131,6 +140,11 @@ void SettingsView::setZoom(int zoomPercent)
KiwixApp::instance()->getSettingsManager()->setZoomFactor(zoomFactor);
}
void SettingsView::setMoveToTrash(bool moveToTrash)
{
KiwixApp::instance()->getSettingsManager()->setMoveToTrash(moveToTrash);
}
void SettingsView::onDownloadDirChanged(const QString &dir)
{
ui->downloadDirPath->setText(dir);
@ -151,3 +165,8 @@ void SettingsView::onZoomChanged(qreal zoomFactor)
qreal zoomPercent = zoomFactor * 100;
ui->zoomPercentSpinBox->setValue(zoomPercent);
}
void SettingsView::onMoveToTrashChanged(bool moveToTrash)
{
ui->moveToTrashToggle->setChecked(moveToTrash);
}

View File

@ -11,16 +11,18 @@ class SettingsView : public QWidget
public:
SettingsView(QWidget *parent = nullptr);
~SettingsView(){};
void init(int zoomPercent, const QString &downloadDir, const QString &monitorDir);
void init(int zoomPercent, const QString &downloadDir, const QString &monitorDir, const bool moveToTrash);
public Q_SLOTS:
void resetDownloadDir();
void browseDownloadDir();
void browseMonitorDir();
void clearMonitorDir();
void setZoom(int zoomPercent);
void setMoveToTrash(bool moveToTrash);
void onDownloadDirChanged(const QString &dir);
void onMonitorDirChanged(const QString &dir);
void onZoomChanged(qreal zoomFactor);
void onMoveToTrashChanged(bool moveToTrash);
private:
bool confirmDialogDownloadDir(const QString& dir);
bool confirmDialog(QString messageText, QString messageTitle);

View File

@ -284,6 +284,50 @@
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="moveToTrashLabel">
<property name="text">
<string>Move deleted files to trash</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="moveToTrashToggle">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">