diff --git a/src/nokde-stubs/prefs.cpp b/src/nokde-stubs/prefs.cpp
--- a/src/nokde-stubs/prefs.cpp
+++ b/src/nokde-stubs/prefs.cpp
@@ -58,6 +58,7 @@
, mPrefetchTM(false)
, mAutoaddTM(true)
, mScanToTMOnOpen(false)
+ , mDeleteFromTMOnMissing(false)
, mWordCompletionLength(3)
, mSuggCount(10)
diff --git a/src/nokde-stubs/prefs_lokalize.h b/src/nokde-stubs/prefs_lokalize.h
--- a/src/nokde-stubs/prefs_lokalize.h
+++ b/src/nokde-stubs/prefs_lokalize.h
@@ -160,6 +160,12 @@
}
protected:
+ static
+ bool deleteFromTMOnMissing()
+ {
+ return self()->mDeleteFromTMOnMissing;
+ }
+
Settings();
friend class SettingsHelper;
@@ -188,6 +194,7 @@
bool mPrefetchTM;
bool mAutoaddTM;
bool mScanToTMOnOpen;
+ bool mDeleteFromTMOnMissing;
int mWordCompletionLength;
int mSuggCount;
diff --git a/src/prefs/lokalize.kcfg b/src/prefs/lokalize.kcfg
--- a/src/prefs/lokalize.kcfg
+++ b/src/prefs/lokalize.kcfg
@@ -114,5 +114,8 @@
false
+
+ false
+
diff --git a/src/prefs/prefs_tm.ui b/src/prefs/prefs_tm.ui
--- a/src/prefs/prefs_tm.ui
+++ b/src/prefs/prefs_tm.ui
@@ -84,6 +84,13 @@
+ -
+
+
+ Delete missing files from translation memory on Rescan or when clicking a missing entry
+
+
+
diff --git a/src/project/project.h b/src/project/project.h
--- a/src/project/project.h
+++ b/src/project/project.h
@@ -111,6 +111,7 @@
}
bool queryCloseForAuxiliaryWindows();
+ bool isFileMissing(const QString& filePath) const;
void setDefaults();
// private slots:
diff --git a/src/project/project.cpp b/src/project/project.cpp
--- a/src/project/project.cpp
+++ b/src/project/project.cpp
@@ -307,6 +307,19 @@
m_tmManagerWindow->activateWindow();
}
+bool Project::isFileMissing(const QString& filePath) const
+{
+ if (!QFile::exists(filePath) && isLoaded()) {
+ //check if we are opening template
+ QString newPath = filePath;
+ newPath.replace(poDir(), potDir());
+ if (!QFile::exists(newPath) && !QFile::exists(newPath += 't')) {
+ return true;
+ }
+ }
+ return false;
+}
+
void Project::save()
{
m_localConfig->setFirstRun(false);
diff --git a/src/tm/jobs.h b/src/tm/jobs.h
--- a/src/tm/jobs.h
+++ b/src/tm/jobs.h
@@ -55,15 +55,16 @@
#define TMTABSELECT 100
#define UPDATE 80
#define REMOVE 70
+#define REMOVEFILE 69
#define INSERT 60
#define SELECT 50
#define BATCHSELECTFINISHED 49
#define IMPORT 30
#define EXPORT 25
+#define REMOVEMISSINGFILES 11
#define SCAN 10
#define SCANFINISHED 9
-
struct TMConfig {
QString markup;
QString accel;
@@ -89,7 +90,7 @@
explicit OpenDBJob(const QString& dbName, DbType type = TM::Local, bool reconnect = false, const ConnectionParams& connParams = ConnectionParams());
~OpenDBJob();
- int priority()const
+ int priority() const
{
return OPENDB;
}
@@ -128,7 +129,7 @@
explicit CloseDBJob(const QString& dbName);
~CloseDBJob();
- int priority()const
+ int priority() const
{
return CLOSEDB;
}
@@ -161,7 +162,7 @@
const QString& dbName);
~SelectJob();
- int priority()const
+ int priority() const
{
return SELECT;
}
@@ -197,14 +198,56 @@
SelectJob* initSelectJob(Catalog*, DocPosition pos, QString db = QString(), int opt = Enqueue);
+class RemoveMissingFilesJob: public QObject, public QRunnable
+{
+ Q_OBJECT
+public:
+ explicit RemoveMissingFilesJob(const QString& dbName);
+ ~RemoveMissingFilesJob();
+ int priority() const
+ {
+ return REMOVEMISSINGFILES;
+ }
+
+protected:
+ void run();
+
+ QString m_dbName;
+
+signals:
+ void done();
+};
+
+class RemoveFileJob: public QObject, public QRunnable
+{
+ Q_OBJECT
+public:
+ explicit RemoveFileJob(const QString& filePath, const QString& dbName, QObject *parent = nullptr);
+ ~RemoveFileJob();
+ int priority() const
+ {
+ return REMOVEFILE;
+ }
+
+protected:
+ void run();
+
+ QString m_filePath;
+ QString m_dbName;
+ QObject m_parent;
+
+signals:
+ void done();
+};
+
class RemoveJob: public QObject, public QRunnable
{
Q_OBJECT
public:
explicit RemoveJob(const TMEntry& entry);
~RemoveJob();
- int priority()const
+ int priority() const
{
return REMOVE;
}
@@ -241,7 +284,7 @@
~UpdateJob() {}
- int priority()const
+ int priority() const
{
return UPDATE;
}
@@ -266,7 +309,7 @@
explicit ScanJob(const QString& filePath, const QString& dbName);
~ScanJob();
- int priority()const
+ int priority() const
{
return SCAN;
}
@@ -319,7 +362,7 @@
{}
~BatchSelectFinishedJob() {};
- int priority()const
+ int priority() const
{
return BATCHSELECTFINISHED;
}
@@ -348,7 +391,7 @@
IndexWordsJob(QObject* parent = 0);
~IndexWordsJob();
- int priority()const
+ int priority() const
{
return 100;
}
@@ -374,7 +417,7 @@
const QString& dbName);
~ImportTmxJob();
- int priority()const
+ int priority() const
{
return IMPORT;
}
@@ -399,7 +442,7 @@
const QString& dbName);
~ExportTmxJob();
- int priority()const
+ int priority() const
{
return IMPORT;
}
@@ -424,7 +467,7 @@
explicit ExecQueryJob(const QString& queryString, const QString& dbName);
~ExecQueryJob();
- int priority()const
+ int priority() const
{
return TMTABSELECT;
}
diff --git a/src/tm/jobs.cpp b/src/tm/jobs.cpp
--- a/src/tm/jobs.cpp
+++ b/src/tm/jobs.cpp
@@ -111,8 +111,6 @@
}
-
-
static qlonglong getFileId(const QString& path,
QSqlDatabase& db)
{
@@ -355,6 +353,51 @@
return query1.exec(QStringLiteral("DELETE FROM main WHERE id=") + QString::number(mainId));
}
+
+static bool doRemoveFile(const QString& filePath, QSqlDatabase& db)
+{
+ qlonglong fileId = getFileId(filePath, db);
+ QSqlQuery query1(db);
+
+ if (Q_UNLIKELY(!query1.exec(U("SELECT id FROM files WHERE "
+ "id=") + QString::number(fileId))))
+ return false;
+
+ if (!query1.next())
+ return false;
+
+ query1.clear();
+
+ query1.exec(QStringLiteral("DELETE source_strings FROM source_strings, main WHERE source_strings.id = main.source AND main.file =") + QString::number(fileId));
+ query1.exec(QStringLiteral("DELETE target_strings FROM target_strings, main WHERE target_strings.id = main.target AND main.file =") + QString::number(fileId));
+ query1.exec(QStringLiteral("DELETE FROM main WHERE file = ") + QString::number(fileId));
+ return query1.exec(QStringLiteral("DELETE FROM files WHERE id=") + QString::number(fileId));
+}
+
+static int doRemoveMissingFiles(QSqlDatabase& db, const QString& dbName, QObject *job)
+{
+ int deletedFiles = 0;
+ QSqlQuery query1(db);
+
+ if (Q_UNLIKELY(!query1.exec(U("SELECT files.path FROM files"))))
+ return false;
+
+ if (!query1.next())
+ return false;
+
+ do {
+ QString filePath = query1.value(0).toString();
+ if (Project::instance()->isFileMissing(filePath)) {
+ qCWarning(LOKALIZE_LOG) << "Removing file " << filePath << " from translation memory";
+ RemoveFileJob* job_removefile = new RemoveFileJob(filePath, dbName, job);
+ TM::threadPool()->start(job_removefile, REMOVEFILE);
+ deletedFiles++;
+ }
+ } while (query1.next());
+
+ return deletedFiles;
+}
+
static QString escape(QString str)
{
return str.replace(QLatin1Char('\''), QStringLiteral("''"));
@@ -1541,6 +1584,60 @@
m_time = a.elapsed();
}
+RemoveMissingFilesJob::RemoveMissingFilesJob(const QString& dbName)
+ : QObject(), QRunnable()
+ , m_dbName(dbName)
+{
+ qCDebug(LOKALIZE_LOG) << "removingmissingfiles" << m_dbName;
+}
+
+
+RemoveMissingFilesJob::~RemoveMissingFilesJob()
+{
+ qCDebug(LOKALIZE_LOG) << "removingmissingfilesjob dtor" << m_dbName;
+}
+
+
+
+void RemoveMissingFilesJob::run()
+{
+// qCDebug(LOKALIZE_LOG)<
#include
#include
+#include
#include
#include
#include
#include
#include
#include
#include
-#include
-
#ifndef NOKDE
#include
#include
#include
+#include
+#include
#endif
#if defined(Q_OS_WIN) && defined(QStringLiteral)
@@ -528,6 +530,10 @@
void TMTab::updateTM()
{
scanRecursive(QStringList(Project::instance()->poDir()), Project::instance()->projectID());
+ if (Settings::deleteFromTMOnMissing()) {
+ RemoveMissingFilesJob* job = new RemoveMissingFilesJob(Project::instance()->projectID());
+ TM::threadPool()->start(job, REMOVEMISSINGFILES);
+ }
}
void TMTab::performQuery()
@@ -612,6 +618,17 @@
void TMTab::openFile()
{
QModelIndex item = ui_queryOptions->treeView->currentIndex();
+ if (Settings::deleteFromTMOnMissing()) {
+ //Check if the file exists and delete it if it doesn't
+ QString filePath = item.sibling(item.row(), TMDBModel::Filepath).data(Qt::UserRole).toString();
+ if (Project::instance()->isFileMissing(filePath)) {
+ //File doesn't exist
+ RemoveFileJob* job = new RemoveFileJob(filePath, ui_queryOptions->dbName->currentText());
+ TM::threadPool()->start(job, REMOVEFILE);
+ KMessageBox::information(this, i18nc("@info", "The file %1 doesn't exist, it has been removed from the Translation Memory.", filePath));
+ return performQuery();//We relaunch the query
+ }
+ }
emit fileOpenRequested(item.sibling(item.row(), TMDBModel::Filepath).data(Qt::UserRole).toString(),
item.sibling(item.row(), TMDBModel::Source).data().toString(),
item.sibling(item.row(), TMDBModel::Context).data().toString());
diff --git a/src/tm/tmview.h b/src/tm/tmview.h
--- a/src/tm/tmview.h
+++ b/src/tm/tmview.h
@@ -90,6 +90,7 @@
private:
bool event(QEvent *event);
+ void deleteFile(const TMEntry& e, const bool showPopUp);
private:
diff --git a/src/tm/tmview.cpp b/src/tm/tmview.cpp
--- a/src/tm/tmview.cpp
+++ b/src/tm/tmview.cpp
@@ -43,6 +43,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -571,26 +572,54 @@
}
}
+void TMView::deleteFile(const TMEntry& e, const bool showPopUp)
+{
+ QString filePath = e.file;
+ if (Project::instance()->isFileMissing(filePath)) {
+ //File doesn't exist
+ RemoveFileJob* job = new RemoveFileJob(e.file, e.dbName);
+ connect(job, SIGNAL(done()), this, SLOT(slotNewEntryDisplayed()));
+ TM::threadPool()->start(job, REMOVEFILE);
+ if (showPopUp) {
+ KMessageBox::information(this, i18nc("@info", "The file %1 doesn't exist, it has been removed from the Translation Memory.", e.file));
+ }
+ return;
+ }
+}
+
void TMView::contextMenu(const QPoint& pos)
{
int block = *m_entryPositions.lowerBound(m_browser->cursorForPosition(pos).anchor());
qCWarning(LOKALIZE_LOG) << block;
if (block >= m_entries.size())
return;
const TMEntry& e = m_entries.at(block);
- enum {Remove, Open};
+ enum {Remove, RemoveFile, Open};
QMenu popup;
popup.addAction(i18nc("@action:inmenu", "Remove this entry"))->setData(Remove);
if (e.file != m_catalog->url() && QFile::exists(e.file))
popup.addAction(i18nc("@action:inmenu", "Open file containing this entry"))->setData(Open);
+ else {
+ if (Settings::deleteFromTMOnMissing()) {
+ //Automatic deletion
+ deleteFile(e, true);
+ } else if (!QFile::exists(e.file)) {
+ //Still offer manual deletion if this is not the current file
+ popup.addAction(i18nc("@action:inmenu", "Remove this missing file from TM"))->setData(RemoveFile);
+ }
+ }
QAction* r = popup.exec(m_browser->mapToGlobal(pos));
if (!r)
return;
if (r->data().toInt() == Remove) {
removeEntry(e);
} else if (r->data().toInt() == Open) {
emit fileOpenRequested(e.file, e.source.string, e.ctxt);
+ } else if ((r->data().toInt() == RemoveFile) &&
+ KMessageBox::Yes == KMessageBox::questionYesNo(this, i18n("Do you really want to remove this missing file:
%1
from translation memory %2?", e.file, e.dbName),
+ i18nc("@title:window", "Translation Memory Missing File Removal"))) {
+ deleteFile(e, false);
}
}