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 @@ -141,6 +141,12 @@ return self()->mScanToTMOnOpen; } + static + bool deleteFromTMOnMissing() + { + return self()->mDeleteFromTMOnMissing; + } + protected: Settings(); friend class SettingsHelper; @@ -170,6 +176,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,11 @@ false + + 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/tm/jobs.h b/src/tm/jobs.h --- a/src/tm/jobs.h +++ b/src/tm/jobs.h @@ -54,15 +54,18 @@ #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; @@ -87,7 +90,7 @@ explicit OpenDBJob(const QString& dbName, DbType type=TM::Local, bool reconnect=false, const ConnectionParams& connParams=ConnectionParams()); ~OpenDBJob(); - int priority()const{return OPENDB;} + int priority() const {return OPENDB;} struct DBStat { @@ -124,7 +127,7 @@ explicit CloseDBJob(const QString& dbName); ~CloseDBJob(); - int priority()const{return CLOSEDB;} + int priority() const {return CLOSEDB;} QString dbName(){return m_dbName;} signals: @@ -151,7 +154,7 @@ const QString& dbName); ~SelectJob(); - int priority()const{return SELECT;} + int priority() const {return SELECT;} signals: void done(SelectJob*); @@ -184,14 +187,50 @@ 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{return REMOVE;} + int priority() const {return REMOVE;} protected: void run(); @@ -225,7 +264,7 @@ ~UpdateJob(){} - int priority()const{return UPDATE;} + int priority() const {return UPDATE;} protected: void run (); @@ -247,7 +286,7 @@ explicit ScanJob(const QString& filePath, const QString& dbName); ~ScanJob(); - int priority()const{return SCAN;} + int priority() const {return SCAN;} protected: void run (); @@ -293,7 +332,7 @@ {} ~BatchSelectFinishedJob(){}; - int priority()const{return BATCHSELECTFINISHED;} + int priority() const {return BATCHSELECTFINISHED;} signals: void done(); @@ -316,7 +355,7 @@ IndexWordsJob(QObject* parent=0); ~IndexWordsJob(); - int priority()const{return 100;} + int priority() const {return 100;} protected: void run (); @@ -339,7 +378,7 @@ const QString& dbName); ~ImportTmxJob(); - int priority()const{return IMPORT;} + int priority() const {return IMPORT;} protected: void run (); @@ -361,7 +400,7 @@ const QString& dbName); ~ExportTmxJob(); - int priority()const{return IMPORT;} + int priority() const {return IMPORT;} protected: void run (); @@ -383,7 +422,7 @@ explicit ExecQueryJob(const QString& queryString, const QString& dbName); ~ExecQueryJob(); - int priority()const{return TMTABSELECT;} + int priority() const {return TMTABSELECT;} QSqlQuery* query; 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) { @@ -371,6 +369,60 @@ 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 (!QFile::exists(filePath)&&Project::instance()->isLoaded()) + { //check if we are opening template + QString newPath=filePath; + newPath.replace(Project::instance()->poDir(),Project::instance()->potDir()); + if (!QFile::exists(newPath) && !QFile::exists(newPath+='t')) + { + qCWarning(LOKALIZE_LOG)<<"Removing file "<start(job_removefile, REMOVEFILE); + deletedFiles++; + } + } + } + while (query1.next()); + + return deletedFiles; +} + static QString escape(QString str) { return str.replace(QLatin1Char('\''),QStringLiteral("''")); @@ -1633,6 +1685,61 @@ m_time=a.elapsed(); } +RemoveMissingFilesJob::RemoveMissingFilesJob(const QString& dbName) + : QObject(), QRunnable() + , m_dbName(dbName) +{ + qCDebug(LOKALIZE_LOG)<<"removingmissingfiles"< #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) @@ -546,6 +548,11 @@ 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() @@ -635,6 +642,24 @@ 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 (!QFile::exists(filePath)&&Project::instance()->isLoaded()) + { //check if we are opening template + QString newPath=filePath; + newPath.replace(Project::instance()->poDir(),Project::instance()->potDir()); + if (!QFile::exists(newPath) && !QFile::exists(newPath+='t')) + { + //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.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 @@ -589,11 +590,36 @@ 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 + QString filePath=e.file; + if (!QFile::exists(filePath)&&Project::instance()->isLoaded()) + {//check if we are opening template + QString newPath=filePath; + newPath.replace(Project::instance()->poDir(),Project::instance()->potDir()); + if (!QFile::exists(newPath) && !QFile::exists(newPath+='t')) + { + //File doesn't exist + RemoveFileJob* job=new RemoveFileJob(e.file,e.dbName); + connect(job,SIGNAL(done()),this,SLOT(slotNewEntryDisplayed())); + TM::threadPool()->start(job, REMOVEFILE); + KMessageBox::information(this, i18nc("@info","The file %1 doesn't exist, it has been removed from the Translation Memory.",e.file)); + return; + } + } + } + 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; @@ -606,7 +632,28 @@ TM::threadPool()->start(job, REMOVE); } 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"))) + { + QString filePath=e.file; + if (!QFile::exists(filePath)&&Project::instance()->isLoaded()) + {//check if we are opening template + QString newPath=filePath; + newPath.replace(Project::instance()->poDir(),Project::instance()->potDir()); + if (!QFile::exists(newPath) && !QFile::exists(newPath+='t')) + { + //File doesn't exist + RemoveFileJob* job=new RemoveFileJob(e.file,e.dbName); + connect(job,SIGNAL(done()),this,SLOT(slotNewEntryDisplayed())); + TM::threadPool()->start(job, REMOVEFILE); + return; + } + } + } } /**