diff --git a/src/project/project.cpp b/src/project/project.cpp index b6aeb3a..17ea563 100644 --- a/src/project/project.cpp +++ b/src/project/project.cpp @@ -1,500 +1,503 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2014 by Nick Shaforostoff 2018-2019 by Simon Depiets This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . **************************************************************************** */ #include "project.h" #include "lokalize_debug.h" #include "projectlocal.h" #include "prefs.h" #include "jobs.h" #include "glossary.h" #include "tmmanager.h" #include "glossarywindow.h" #include "editortab.h" #include "dbfilesmodel.h" #include "qamodel.h" #include #include #include #include #include #include #include #include #include #include "projectmodel.h" #include "webquerycontroller.h" #include #include #include #include #include #include #include #include using namespace Kross; QString getMailingList() { QString lang = QLocale::system().name(); if (lang.startsWith(QLatin1String("ca"))) return QLatin1String("kde-i18n-ca@kde.org"); if (lang.startsWith(QLatin1String("de"))) return QLatin1String("kde-i18n-de@kde.org"); if (lang.startsWith(QLatin1String("hu"))) return QLatin1String("kde-l10n-hu@kde.org"); if (lang.startsWith(QLatin1String("tr"))) return QLatin1String("kde-l10n-tr@kde.org"); if (lang.startsWith(QLatin1String("it"))) return QLatin1String("kde-i18n-it@kde.org"); if (lang.startsWith(QLatin1String("lt"))) return QLatin1String("kde-i18n-lt@kde.org"); if (lang.startsWith(QLatin1String("nb"))) return QLatin1String("l10n-no@lister.huftis.org"); if (lang.startsWith(QLatin1String("nl"))) return QLatin1String("kde-i18n-nl@kde.org"); if (lang.startsWith(QLatin1String("nn"))) return QLatin1String("l10n-no@lister.huftis.org"); if (lang.startsWith(QLatin1String("pt_BR"))) return QLatin1String("kde-i18n-pt_BR@kde.org"); if (lang.startsWith(QLatin1String("ru"))) return QLatin1String("kde-russian@lists.kde.ru"); if (lang.startsWith(QLatin1String("se"))) return QLatin1String("l10n-no@lister.huftis.org"); if (lang.startsWith(QLatin1String("sl"))) return QLatin1String("lugos-slo@lugos.si"); return QLatin1String("kde-i18n-doc@kde.org"); } Project* Project::_instance = 0; void Project::cleanupProject() { delete Project::_instance; Project::_instance = 0; } Project* Project::instance() { if (_instance == 0) { _instance = new Project(); qAddPostRoutine(Project::cleanupProject); } return _instance; } Project::Project() : ProjectBase() , m_localConfig(new ProjectLocal()) , m_model(0) , m_glossary(new GlossaryNS::Glossary(this)) , m_glossaryWindow(0) , m_tmManagerWindow(0) { setDefaults(); /* qRegisterMetaType("DocPosition"); qDBusRegisterMetaType(); */ //QTimer::singleShot(66,this,SLOT(initLater())); } /* void Project::initLater() { if (isLoaded()) return; KConfig cfg; KConfigGroup gr(&cfg,"State"); QString file=gr.readEntry("Project"); if (!file.isEmpty()) load(file); } */ Project::~Project() { delete m_localConfig; //Project::save() } void Project::load(const QString &newProjectPath, const QString& forcedTargetLangCode, const QString& forcedProjectId) { // QElapsedTimer a; a.start(); TM::threadPool()->clear(); qCDebug(LOKALIZE_LOG) << "loading" << newProjectPath << "finishing tm jobs..."; if (!m_path.isEmpty()) { TM::CloseDBJob* closeDBJob = new TM::CloseDBJob(projectID()); closeDBJob->setAutoDelete(true); TM::threadPool()->start(closeDBJob, CLOSEDB); } TM::threadPool()->waitForDone(500);//more safety setSharedConfig(KSharedConfig::openConfig(newProjectPath, KConfig::NoGlobals)); if (!QFileInfo::exists(newProjectPath)) Project::instance()->setDefaults(); ProjectBase::load(); m_path = newProjectPath; m_desirablePath.clear(); //cache: m_projectDir = QFileInfo(m_path).absolutePath(); m_localConfig->setSharedConfig(KSharedConfig::openConfig(projectID() + QStringLiteral(".local"), KConfig::NoGlobals, QStandardPaths::DataLocation)); m_localConfig->load(); if (forcedTargetLangCode.length()) setLangCode(forcedTargetLangCode); else if (langCode().isEmpty()) setLangCode(QLocale::system().name()); if (forcedProjectId.length()) setProjectID(forcedProjectId); //KConfig config; //delete m_localConfig; m_localConfig=new KConfigGroup(&config,"Project-"+path()); populateDirModel(); //put 'em into thread? //QTimer::singleShot(0,this,SLOT(populateGlossary())); populateGlossary();//we cant postpone it because project load can be called from define new term function m_sourceFilePaths.clear(); + m_sourceFilePathsReady = false; if (newProjectPath.isEmpty()) return; if (!isTmSupported()) qCWarning(LOKALIZE_LOG) << "no sqlite module available"; //NOTE do we need to explicitly call it when project id changes? TM::DBFilesModel::instance()->openDB(projectID(), TM::Undefined, true); if (QaModel::isInstantiated()) { QaModel::instance()->saveRules(); QaModel::instance()->loadRules(qaPath()); } //qCDebug(LOKALIZE_LOG)<<"until emitting signal"<setAutoDelete(true); TM::threadPool()->start(closeDBJob, CLOSEDB); populateDirModel(); populateGlossary(); TM::threadPool()->waitForDone(500);//more safety TM::DBFilesModel::instance()->openDB(projectID(), TM::Undefined, true); } QString Project::absolutePath(const QString& possiblyRelPath) const { if (QFileInfo(possiblyRelPath).isRelative()) return QDir::cleanPath(m_projectDir + QLatin1Char('/') + possiblyRelPath); return possiblyRelPath; } void Project::populateDirModel() { if (Q_UNLIKELY(m_path.isEmpty() || !QFileInfo::exists(poDir()))) return; QUrl potUrl; if (QFileInfo::exists(potDir())) potUrl = QUrl::fromLocalFile(potDir()); model()->setUrl(QUrl::fromLocalFile(poDir()), potUrl); } void Project::populateGlossary() { m_glossary->load(glossaryPath()); } GlossaryNS::GlossaryWindow* Project::showGlossary() { return defineNewTerm(); } GlossaryNS::GlossaryWindow* Project::defineNewTerm(QString en, QString target) { if (!SettingsController::instance()->ensureProjectIsLoaded()) return 0; if (!m_glossaryWindow) m_glossaryWindow = new GlossaryNS::GlossaryWindow(SettingsController::instance()->mainWindowPtr()); m_glossaryWindow->show(); m_glossaryWindow->activateWindow(); if (!en.isEmpty() || !target.isEmpty()) m_glossaryWindow->newTermEntry(en, target); return m_glossaryWindow; } bool Project::queryCloseForAuxiliaryWindows() { if (m_glossaryWindow && m_glossaryWindow->isVisible()) return m_glossaryWindow->queryClose(); return true; } bool Project::isTmSupported() const { QStringList drivers = QSqlDatabase::drivers(); return drivers.contains(QLatin1String("QSQLITE")); } void Project::showTMManager() { if (!m_tmManagerWindow) { if (!isTmSupported()) { KMessageBox::information(nullptr, i18n("TM facility requires SQLite Qt module."), i18n("No SQLite module available")); return; } m_tmManagerWindow = new TM::TMManagerWin(SettingsController::instance()->mainWindowPtr()); } m_tmManagerWindow->show(); 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); ProjectBase::setTargetLangCode(langCode()); ProjectBase::save(); m_localConfig->save(); } ProjectModel* Project::model() { if (Q_UNLIKELY(!m_model)) m_model = new ProjectModel(this); return m_model; } void Project::setDefaults() { ProjectBase::setDefaults(); setLangCode(QLocale::system().name()); } void Project::init(const QString& path, const QString& kind, const QString& id, const QString& sourceLang, const QString& targetLang) { setDefaults(); bool stop = false; while (true) { setKind(kind); setSourceLangCode(sourceLang); setLangCode(targetLang); setProjectID(id); if (stop) break; else { load(path); stop = true; } } save(); } static void fillFilePathsRecursive(const QDir& dir, QMultiMap& sourceFilePaths) { QStringList subDirs(dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Readable)); int i = subDirs.size(); while (--i >= 0) fillFilePathsRecursive(QDir(dir.filePath(subDirs.at(i))), sourceFilePaths); static QStringList filters = QStringList(QStringLiteral("*.cpp")) << QStringLiteral("*.c") << QStringLiteral("*.cc") << QStringLiteral("*.mm") << QStringLiteral("*.ui") << QStringLiteral("*rc"); QStringList files(dir.entryList(filters, QDir::Files | QDir::NoDotAndDotDot | QDir::Readable)); i = files.size(); QByteArray absDirPath = dir.absolutePath().toUtf8(); absDirPath.squeeze(); while (--i >= 0) { //qCDebug(LOKALIZE_LOG)<sourceFilePathsAreReady(); } protected: bool doKill() override; private: QString m_folderName; }; SourceFilesSearchJob::SourceFilesSearchJob(const QString& folderName, QObject* parent) : KJob(parent) , m_folderName(folderName) { + qCWarning(LOKALIZE_LOG) << "Starting SourceFilesSearchJob on " << folderName; setCapabilities(KJob::Killable); } bool SourceFilesSearchJob::doKill() { //TODO return true; } class FillSourceFilePathsJob: public QRunnable { public: explicit FillSourceFilePathsJob(const QDir& dir, SourceFilesSearchJob* j): startingDir(dir), kj(j) {} protected: void run() override { QMultiMap sourceFilePaths; fillFilePathsRecursive(startingDir, sourceFilePaths); Project::instance()->m_sourceFilePaths = sourceFilePaths; + Project::instance()->m_sourceFilePathsReady = true; QTimer::singleShot(0, kj, &SourceFilesSearchJob::finish); } public: QDir startingDir; SourceFilesSearchJob* kj; }; void SourceFilesSearchJob::start() { QThreadPool::globalInstance()->start(new FillSourceFilePathsJob(QDir(m_folderName), this)); emit description(this, i18n("Scanning folders with source files"), qMakePair(i18n("Editor"), m_folderName)); } const QMultiMap& Project::sourceFilePaths() { - if (m_sourceFilePaths.isEmpty()) { + if (!m_sourceFilePathsReady && m_sourceFilePaths.isEmpty()) { QDir dir(local()->sourceDir()); if (dir.exists()) { SourceFilesSearchJob* metaJob = new SourceFilesSearchJob(local()->sourceDir()); KIO::getJobTracker()->registerJob(metaJob); metaJob->start(); //KNotification* notification=new KNotification("SourceFileScan", 0); //notification->setText( i18nc("@info","Please wait while %1 is being scanned for source files.", local()->sourceDir()) ); //notification->sendEvent(); } } return m_sourceFilePaths; } #include #include #include "languagelistmodel.h" void Project::projectOdfCreate() { QString odf2xliff = QStringLiteral("odf2xliff"); if (QProcess::execute(odf2xliff, QStringList(QLatin1String("--version"))) == -2) { KMessageBox::error(SettingsController::instance()->mainWindowPtr(), i18n("Install translate-toolkit package and retry")); return; } QString odfPath = QFileDialog::getOpenFileName(SettingsController::instance()->mainWindowPtr(), QString(), QDir::homePath()/*_catalog->url().directory()*/, i18n("OpenDocument files (*.odt *.ods)")/*"text/x-lokalize-project"*/); if (odfPath.isEmpty()) return; QString targetLangCode = getTargetLangCode(QString(), true); QFileInfo fi(odfPath); QString trFolderName = i18nc("project folder name. %2 is targetLangCode", "%1 %2 Translation", fi.baseName(), targetLangCode); fi.absoluteDir().mkdir(trFolderName); QStringList args(odfPath); args.append(fi.absoluteDir().absoluteFilePath(trFolderName) + '/' + fi.baseName() + QLatin1String(".xlf")); qCDebug(LOKALIZE_LOG) << args; QProcess::execute(odf2xliff, args); if (!QFile::exists(args.at(1))) return; emit closed(); Project::instance()->load(fi.absoluteDir().absoluteFilePath(trFolderName) + QLatin1String("/index.lokalize"), targetLangCode, fi.baseName() + '-' + targetLangCode); emit fileOpenRequested(args.at(1), true); } diff --git a/src/project/project.h b/src/project/project.h index 14b3e23..ee882b0 100644 --- a/src/project/project.h +++ b/src/project/project.h @@ -1,217 +1,219 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2009 by Nick Shaforostoff 2018-2019 by Simon Depiets This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . **************************************************************************** */ #ifndef PROJECT_H #define PROJECT_H #include #include #include "projectbase.h" #define WEBQUERY_ENABLE class ProjectModel; class ProjectLocal; namespace GlossaryNS { class Glossary; } namespace GlossaryNS { class GlossaryWindow; } namespace TM { class TMManagerWin; } /** * Singleton object that represents project. * It is shared between EditorWindow 'mainwindows' that use the same project file. * Keeps project's KDirModel, Glossary and kross::actions * * GUI for config handling is implemented in prefs.cpp * * @short Singleton object that represents project */ ///////// * Also provides list of web-query scripts class Project: public ProjectBase { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.Lokalize.Project") //qdbuscpp2xml -m -s project.h -o org.kde.lokalize.Project.xml public: explicit Project(); virtual ~Project(); bool isLoaded()const { return !m_path.isEmpty(); } ProjectModel* model(); //void setPath(const QString& p){m_path=p;} QString path()const { return m_path; } QString projectDir()const { return m_projectDir; } QString poDir()const { return absolutePath(poBaseDir()); } QString potDir()const { return absolutePath(potBaseDir()); } QString branchDir()const { return absolutePath(ProjectBase::branchDir()); } QString glossaryPath()const { return absolutePath(glossaryTbx()); } QString qaPath()const { return absolutePath(mainQA()); } GlossaryNS::Glossary* glossary()const { return m_glossary; } QString altTransDir()const { return absolutePath(altDir()); } bool queryCloseForAuxiliaryWindows(); bool isFileMissing(const QString& filePath) const; void setDefaults() override; // private slots: // void initLater(); public slots: Q_SCRIPTABLE void load(const QString& newProjectPath, const QString& defaultTargetLangCode = QString(), const QString& defaultProjectId = QString()); Q_SCRIPTABLE void reinit(); Q_SCRIPTABLE void save(); Q_SCRIPTABLE QString translationsRoot()const { return poDir(); } Q_SCRIPTABLE QString templatesRoot()const { return potDir(); } Q_SCRIPTABLE QString targetLangCode()const { return ProjectBase::langCode(); } Q_SCRIPTABLE QString sourceLangCode()const { return ProjectBase::sourceLangCode(); } Q_SCRIPTABLE void init(const QString& path, const QString& kind, const QString& id, const QString& sourceLang, const QString& targetLang); Q_SCRIPTABLE QString kind()const { return ProjectBase::kind(); } Q_SCRIPTABLE QString absolutePath(const QString&) const; Q_SCRIPTABLE void setDesirablePath(const QString& path) { m_desirablePath = path; } Q_SCRIPTABLE QString desirablePath() const { return m_desirablePath; } Q_SCRIPTABLE bool isTmSupported() const; signals: Q_SCRIPTABLE void loaded(); void fileOpenRequested(const QString&, const bool setAsActive); void closed(); public slots: void populateDirModel(); void populateGlossary(); void showTMManager(); GlossaryNS::GlossaryWindow* showGlossary(); GlossaryNS::GlossaryWindow* defineNewTerm(QString en = QString(), QString target = QString()); void projectOdfCreate(); private: static Project* _instance; static void cleanupProject(); public: static Project* instance(); static ProjectLocal* local() { return instance()->m_localConfig; } const QMultiMap& sourceFilePaths(); void resetSourceFilePaths() { m_sourceFilePaths.clear(); + m_sourceFilePathsReady = false; } friend class FillSourceFilePathsJob; signals: void sourceFilePathsAreReady(); private: QString m_path; QString m_desirablePath; ProjectLocal* m_localConfig; ProjectModel* m_model; GlossaryNS::Glossary* m_glossary; GlossaryNS::GlossaryWindow* m_glossaryWindow; TM::TMManagerWin* m_tmManagerWindow; QMultiMap m_sourceFilePaths; + bool m_sourceFilePathsReady; //cache QString m_projectDir; }; #endif