diff --git a/src/alttransview.cpp b/src/alttransview.cpp index db5b84d..61c900f 100644 --- a/src/alttransview.cpp +++ b/src/alttransview.cpp @@ -1,314 +1,310 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2014 by Nick Shaforostoff 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 "alttransview.h" #include "lokalize_debug.h" #include "diff.h" #include "catalog.h" #include "cmd.h" #include "project.h" #include "xlifftextedit.h" #include "tmview.h" //TextBrowser #include "mergecatalog.h" #include "prefs_lokalize.h" #include #include #include #include #include #include #include #include #include #include AltTransView::AltTransView(QWidget* parent, Catalog* catalog, const QVector& actions) : QDockWidget(i18nc("@title:window", "Alternate Translations"), parent) , m_browser(new TM::TextBrowser(this)) , m_catalog(catalog) , m_normTitle(i18nc("@title:window", "Alternate Translations")) , m_hasInfoTitle(m_normTitle + QStringLiteral(" [*]")) , m_hasInfo(false) , m_everShown(false) , m_actions(actions) { setObjectName(QStringLiteral("msgIdDiff")); setWidget(m_browser); hide(); m_browser->setReadOnly(true); m_browser->viewport()->setBackgroundRole(QPalette::Background); QTimer::singleShot(0, this, &AltTransView::initLater); } void AltTransView::initLater() { setAcceptDrops(true); -#ifndef NOKDE KConfig config; KConfigGroup group(&config, "AltTransView"); m_everShown = group.readEntry("EverShown", false); -#endif QSignalMapper* signalMapper = new QSignalMapper(this); int i = m_actions.size(); while (--i >= 0) { connect(m_actions.at(i), &QAction::triggered, signalMapper, QOverload<>::of(&QSignalMapper::map)); signalMapper->setMapping(m_actions.at(i), i); } connect(signalMapper, QOverload::of(&QSignalMapper::mapped), this, &AltTransView::slotUseSuggestion); connect(m_browser, &TM::TextBrowser::textInsertRequested, this, &AltTransView::textInsertRequested); //connect(m_browser, &TM::TextBrowser::customContextMenuRequested, this, &AltTransView::contextMenu); } AltTransView::~AltTransView() { } void AltTransView::dragEnterEvent(QDragEnterEvent* event) { if (event->mimeData()->hasUrls() && Catalog::extIsSupported(event->mimeData()->urls().first().path())) event->acceptProposedAction(); } void AltTransView::dropEvent(QDropEvent *event) { event->acceptProposedAction(); attachAltTransFile(event->mimeData()->urls().first().toLocalFile()); //update m_prevEntry.entry = -1; QTimer::singleShot(0, this, &AltTransView::process); } void AltTransView::attachAltTransFile(const QString& path) { MergeCatalog* altCat = new MergeCatalog(m_catalog, m_catalog, /*saveChanges*/false); altCat->loadFromUrl(path); m_catalog->attachAltTransCatalog(altCat); } void AltTransView::addAlternateTranslation(int entry, const QString& trans) { AltTrans altTrans; altTrans.target = trans; m_catalog->attachAltTrans(entry, altTrans); m_prevEntry = DocPos(); QTimer::singleShot(0, this, &AltTransView::process); } void AltTransView::fileLoaded() { m_prevEntry.entry = -1; QString absPath = m_catalog->url(); QString relPath = QDir(Project::instance()->projectDir()).relativeFilePath(absPath); QFileInfo info(Project::instance()->altTransDir() % '/' % relPath); if (info.canonicalFilePath() != absPath && info.exists()) attachAltTransFile(info.canonicalFilePath()); else qCWarning(LOKALIZE_LOG) << "alt trans file doesn't exist:" << Project::instance()->altTransDir() % '/' % relPath; } void AltTransView::slotNewEntryDisplayed(const DocPosition& pos) { m_entry = DocPos(pos); QTimer::singleShot(0, this, &AltTransView::process); } void AltTransView::process() { if (m_entry == m_prevEntry) return; if (m_catalog->numberOfEntries() <= m_entry.entry) return;//because of Qt::QueuedConnection m_prevEntry = m_entry; m_browser->clear(); m_entryPositions.clear(); const QVector& entries = m_catalog->altTrans(m_entry.toDocPosition()); m_entries = entries; if (entries.isEmpty()) { if (m_hasInfo) { m_hasInfo = false; setWindowTitle(m_normTitle); } return; } if (!m_hasInfo) { m_hasInfo = true; setWindowTitle(m_hasInfoTitle); } if (!isVisible() && !Settings::altTransViewEverShownWithData()) { if (KMessageBox::questionYesNo(this, i18n("There is useful data available in Alternate Translations view.\n\n" "For Gettext PO files it displays difference between current source text " "and the source text corresponding to the fuzzy translation found by msgmerge when updating PO based on POT template.\n\n" "Do you want to show the view with the data?"), m_normTitle) == KMessageBox::Yes) show(); Settings::setAltTransViewEverShownWithData(true); } CatalogString source = m_catalog->sourceWithTags(m_entry.toDocPosition()); QTextBlockFormat blockFormatBase; QTextBlockFormat blockFormatAlternate; blockFormatAlternate.setBackground(QPalette().alternateBase()); QTextCharFormat noncloseMatchCharFormat; QTextCharFormat closeMatchCharFormat; closeMatchCharFormat.setFontWeight(QFont::Bold); int i = 0; int limit = entries.size(); forever { const AltTrans& entry = entries.at(i); QTextCursor cur = m_browser->textCursor(); QString html; html.reserve(1024); if (!entry.source.isEmpty()) { html += QStringLiteral("

"); QString result = userVisibleWordDiff(entry.source.string, source.string, Project::instance()->accel(), Project::instance()->markup()).toHtmlEscaped(); //result.replace("&","&"); //result.replace("<","<"); //result.replace(">",">"); result.replace(QStringLiteral("{KBABELADD}"), QStringLiteral("")); result.replace(QStringLiteral("{/KBABELADD}"), QStringLiteral("")); result.replace(QStringLiteral("{KBABELDEL}"), QStringLiteral("")); result.replace(QStringLiteral("{/KBABELDEL}"), QStringLiteral("")); result.replace(QStringLiteral("\\n"), QStringLiteral("\\n

")); html += result; html += QStringLiteral("
"); cur.insertHtml(html); html.clear(); } if (!entry.target.isEmpty()) { if (Q_LIKELY(i < m_actions.size())) { m_actions.at(i)->setStatusTip(entry.target.string); html += QString(QStringLiteral("[%1] ")).arg(m_actions.at(i)->shortcut().toString(QKeySequence::NativeText)); } else html += QStringLiteral("[ - ] "); cur.insertText(html); html.clear(); insertContent(cur, entry.target); } m_entryPositions.insert(cur.anchor(), i); html += i ? QStringLiteral("

") : QStringLiteral("

"); cur.insertHtml(html); if (Q_UNLIKELY(++i >= limit)) break; cur.insertBlock(i % 2 ? blockFormatAlternate : blockFormatBase); } -#ifndef NOKDE if (!m_everShown) { m_everShown = true; show(); KConfig config; KConfigGroup group(&config, "AltTransView"); group.writeEntry("EverShown", true); } -#endif } bool AltTransView::event(QEvent *event) { if (event->type() == QEvent::ToolTip) { QHelpEvent *helpEvent = static_cast(event); if (m_entryPositions.isEmpty()) { QString tooltip = i18nc("@info:tooltip", "

Sometimes, if source text is changed, its translation becomes deprecated and is either marked as needing review (i.e. looses approval status), " "or (only in case of XLIFF file) moved to the alternate translations section accompanying the unit.

" "

This toolview also shows the difference between current source string and the previous source string, so that you can easily see which changes should be applied to existing translation to make it reflect current source.

" "

Double-clicking any word in this toolview inserts it into translation.

" "

Drop translation file onto this toolview to use it as a source for additional alternate translations.

" ); QToolTip::showText(helpEvent->globalPos(), tooltip); return true; } int block1 = m_browser->cursorForPosition(m_browser->viewport()->mapFromGlobal(helpEvent->globalPos())).blockNumber(); int block = *m_entryPositions.lowerBound(m_browser->cursorForPosition(m_browser->viewport()->mapFromGlobal(helpEvent->globalPos())).anchor()); if (block1 != block) qCWarning(LOKALIZE_LOG) << "block numbers don't match"; if (block >= m_entries.size()) return false; QString origin = m_entries.at(block).origin; if (origin.isEmpty()) return false; QString tooltip = i18nc("@info:tooltip", "Origin: %1", origin); QToolTip::showText(helpEvent->globalPos(), tooltip); return true; } return QWidget::event(event); } void AltTransView::slotUseSuggestion(int i) { if (Q_UNLIKELY(i >= m_entries.size())) return; TM::TMEntry tmEntry; tmEntry.target = m_entries.at(i).target; CatalogString source = m_catalog->sourceWithTags(m_entry.toDocPosition()); tmEntry.diff = userVisibleWordDiff(m_entries.at(i).source.string, source.string, Project::instance()->accel(), Project::instance()->markup()); CatalogString target = TM::targetAdapted(tmEntry, source); qCWarning(LOKALIZE_LOG) << "0" << target.string; if (Q_UNLIKELY(target.isEmpty())) return; m_catalog->beginMacro(i18nc("@item Undo action", "Use alternate translation")); QString old = m_catalog->targetWithTags(m_entry.toDocPosition()).string; if (!old.isEmpty()) { //FIXME test! removeTargetSubstring(m_catalog, m_entry.toDocPosition(), 0, old.size()); //m_catalog->push(new DelTextCmd(m_catalog,m_pos,m_catalog->msgstr(m_pos))); } qCWarning(LOKALIZE_LOG) << "1" << target.string; //m_catalog->push(new InsTextCmd(m_catalog,m_pos,target)/*,true*/); insertCatalogString(m_catalog, m_entry.toDocPosition(), target, 0); m_catalog->endMacro(); emit refreshRequested(); } diff --git a/src/binunitsview.cpp b/src/binunitsview.cpp index 25a2ac6..036d661 100644 --- a/src/binunitsview.cpp +++ b/src/binunitsview.cpp @@ -1,221 +1,213 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2009-2014 by Nick Shaforostoff 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 "binunitsview.h" #include "phaseswindow.h" //MyTreeView #include "catalog.h" #include "cmd.h" #include "project.h" #include #include #include #include -#ifndef NOKDE #include #include -#endif //BEGIN BinUnitsModel BinUnitsModel::BinUnitsModel(Catalog* catalog, QObject* parent) : QAbstractListModel(parent) , m_catalog(catalog) { connect(catalog, QOverload<>::of(&Catalog::signalFileLoaded), this, &BinUnitsModel::fileLoaded); connect(catalog, &Catalog::signalEntryModified, this, &BinUnitsModel::entryModified); -#ifndef NOKDE connect(KDirWatch::self(), &KDirWatch::dirty, this, &BinUnitsModel::updateFile); -#endif } void BinUnitsModel::fileLoaded() { beginResetModel(); m_imageCache.clear(); endResetModel(); } void BinUnitsModel::entryModified(const DocPosition& pos) { if (pos.entry < m_catalog->numberOfEntries()) return; QModelIndex item = index(pos.entry - m_catalog->numberOfEntries(), TargetFilePath); emit dataChanged(item, item); } void BinUnitsModel::updateFile(QString path) { QString relPath = QDir(Project::instance()->projectDir()).relativeFilePath(path); DocPosition pos(m_catalog->numberOfEntries()); int limit = m_catalog->numberOfEntries() + m_catalog->binUnitsCount(); while (pos.entry < limit) { if (m_catalog->target(pos) == relPath || m_catalog->source(pos) == relPath) { int row = pos.entry - m_catalog->numberOfEntries(); m_imageCache.remove(relPath); emit dataChanged(index(row, SourceFilePath), index(row, TargetFilePath)); return; } pos.entry++; } } void BinUnitsModel::setTargetFilePath(int row, const QString& path) { DocPosition pos(row + m_catalog->numberOfEntries()); QString old = m_catalog->target(pos); if (!old.isEmpty()) { m_catalog->push(new DelTextCmd(m_catalog, pos, old)); m_imageCache.remove(old); } m_catalog->push(new InsTextCmd(m_catalog, pos, QDir(Project::instance()->projectDir()).relativeFilePath(path))); QModelIndex item = index(row, TargetFilePath); emit dataChanged(item, item); } int BinUnitsModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; return m_catalog->binUnitsCount(); } QVariant BinUnitsModel::data(const QModelIndex& index, int role) const { if (role == Qt::DecorationRole) { DocPosition pos(index.row() + m_catalog->numberOfEntries()); if (index.column() < Approved) { QString path = index.column() == SourceFilePath ? m_catalog->source(pos) : m_catalog->target(pos); if (!m_imageCache.contains(path)) { QString absPath = Project::instance()->absolutePath(path); -#ifndef NOKDE KDirWatch::self()->addFile(absPath); //TODO remember watched files to react only on them in dirty() signal handler -#endif m_imageCache.insert(path, QImage(absPath).scaled(128, 128, Qt::KeepAspectRatio)); } return m_imageCache.value(path); } } else if (role == Qt::TextAlignmentRole) return int(Qt::AlignLeft | Qt::AlignTop); if (role != Qt::DisplayRole) return QVariant(); static const char* noyes[] = {I18N_NOOP("no"), I18N_NOOP("yes")}; DocPosition pos(index.row() + m_catalog->numberOfEntries()); switch (index.column()) { case SourceFilePath: return m_catalog->source(pos); case TargetFilePath: return m_catalog->target(pos); case Approved: return noyes[m_catalog->isApproved(pos)]; } return QVariant(); } QVariant BinUnitsModel::headerData(int section, Qt::Orientation, int role) const { if (role != Qt::DisplayRole) return QVariant(); switch (section) { case SourceFilePath: return i18nc("@title:column", "Source"); case TargetFilePath: return i18nc("@title:column", "Target"); case Approved: return i18nc("@title:column", "Approved"); } return QVariant(); } //END BinUnitsModel BinUnitsView::BinUnitsView(Catalog* catalog, QWidget* parent) : QDockWidget(i18nc("@title toolview name", "Binary Units"), parent) , m_catalog(catalog) , m_model(new BinUnitsModel(catalog, this)) , m_view(new MyTreeView(this)) { setObjectName(QStringLiteral("binUnits")); hide(); setWidget(m_view); m_view->setModel(m_model); m_view->setRootIsDecorated(false); m_view->setAlternatingRowColors(true); m_view->viewport()->setBackgroundRole(QPalette::Background); connect(m_view, &MyTreeView::doubleClicked, this, &BinUnitsView::mouseDoubleClicked); connect(catalog, QOverload<>::of(&Catalog::signalFileLoaded), this, &BinUnitsView::fileLoaded); } void BinUnitsView::fileLoaded() { setVisible(m_catalog->binUnitsCount()); } void BinUnitsView::selectUnit(const QString& id) { QModelIndex item = m_model->index(m_catalog->unitById(id) - m_catalog->numberOfEntries()); m_view->setCurrentIndex(item); m_view->scrollTo(item); show(); } void BinUnitsView::contextMenuEvent(QContextMenuEvent *event) { QModelIndex item = m_view->currentIndex(); if (!item.isValid()) return; QMenu menu; QAction* setTarget = menu.addAction(i18nc("@action:inmenu", "Set the file")); QAction* useSource = menu.addAction(i18nc("@action:inmenu", "Use source file")); // menu.addSeparator(); // QAction* openSource=menu.addAction(i18nc("@action:inmenu","Open source file in external program")); // QAction* openTarget=menu.addAction(i18nc("@action:inmenu","Open target file in external program")); QAction* result = menu.exec(event->globalPos()); if (!result) return; QString sourceFilePath = item.sibling(item.row(), BinUnitsModel::SourceFilePath).data().toString(); if (result == useSource) m_model->setTargetFilePath(item.row(), sourceFilePath); else if (result == setTarget) { QString targetFilePath = QFileDialog::getOpenFileName(this, QString(), Project::instance()->projectDir()); if (!targetFilePath.isEmpty()) m_model->setTargetFilePath(item.row(), targetFilePath); } event->accept(); } void BinUnitsView::mouseDoubleClicked(const QModelIndex& item) { -#ifndef NOKDE //FIXME child processes don't notify us about changes ;( if (item.column() < BinUnitsModel::Approved) new KRun(QUrl::fromLocalFile(Project::instance()->absolutePath(item.data().toString())), this); -#endif } diff --git a/src/catalog/catalog.cpp b/src/catalog/catalog.cpp index 1e83956..76ec582 100644 --- a/src/catalog/catalog.cpp +++ b/src/catalog/catalog.cpp @@ -1,1069 +1,1053 @@ /* **************************************************************************** This file is part of Lokalize This file contains parts of KBabel code Copyright (C) 1999-2000 by Matthias Kiefer 2001-2005 by Stanislav Visnovsky 2006 by Nicolas Goutte 2007-2014 by Nick Shaforostoff 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) any later version. 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. **************************************************************************** */ #include "catalog.h" #include "catalog_private.h" #include "project.h" -#ifndef NOKDE #include "projectmodel.h" //to notify about modification -#endif #include "catalogstorage.h" #include "gettextstorage.h" #include "gettextimport.h" #include "gettextexport.h" #include "xliffstorage.h" #include "tsstorage.h" #include "mergecatalog.h" #include "version.h" #include "prefs_lokalize.h" #include "jobs.h" #include "dbfilesmodel.h" #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN #define U QLatin1String #else #define U QStringLiteral #endif //QString Catalog::supportedMimeFilters("text/x-gettext-translation application/x-xliff application/x-linguist"); //" text/x-gettext-translation-template") QString Catalog::supportedFileTypes(bool includeTemplates) { QString sep = QStringLiteral(";;"); QString all = i18n("All supported files (*.po *.pot *.xlf *.xliff *.ts)") + sep; return all + (includeTemplates ? i18n("Gettext (*.po *.pot)") : i18n("Gettext (*.po)")) + sep + i18n("XLIFF (*.xlf *.xliff)") + sep + i18n("Linguist (*.ts)"); } static const QString extensions[] = {U(".po"), U(".pot"), U(".xlf"), U(".xliff"), U(".ts")}; static const char* const xliff_states[] = { I18N_NOOP("New"), I18N_NOOP("Needs translation"), I18N_NOOP("Needs full localization"), I18N_NOOP("Needs adaptation"), I18N_NOOP("Translated"), I18N_NOOP("Needs translation review"), I18N_NOOP("Needs full localization review"), I18N_NOOP("Needs adaptation review"), I18N_NOOP("Final"), I18N_NOOP("Signed-off") }; const char* const* Catalog::states() { return xliff_states; } QStringList Catalog::supportedExtensions() { QStringList result; int i = sizeof(extensions) / sizeof(QString); while (--i >= 0) result.append(extensions[i]); return result; } bool Catalog::extIsSupported(const QString& path) { QStringList ext = supportedExtensions(); int i = ext.size(); while (--i >= 0 && !path.endsWith(ext.at(i))) ; return i != -1; } Catalog::Catalog(QObject *parent) : QUndoStack(parent) , d(this) , m_storage(0) { -#ifndef NOKDE //cause refresh events for files modified from lokalize itself aint delivered automatically connect(this, QOverload::of(&Catalog::signalFileSaved), Project::instance()->model(), QOverload::of(&ProjectModel::slotFileSaved), Qt::QueuedConnection); QTimer* t = &(d._autoSaveTimer); t->setInterval(2 * 60 * 1000); t->setSingleShot(false); connect(t, &QTimer::timeout, this, &Catalog::doAutoSave); connect(this, QOverload<>::of(&Catalog::signalFileSaved), t, QOverload<>::of(&QTimer::start)); connect(this, QOverload<>::of(&Catalog::signalFileLoaded), t, QOverload<>::of(&QTimer::start)); connect(this, &Catalog::indexChanged, this, &Catalog::setAutoSaveDirty); -#endif connect(Project::local(), &Project::configChanged, this, &Catalog::projectConfigChanged); } Catalog::~Catalog() { clear(); //delete m_storage; //deleted in clear(); } void Catalog::clear() { setIndex(cleanIndex());//to keep TM in sync QUndoStack::clear(); d._errorIndex.clear(); d._nonApprovedIndex.clear(); d._emptyIndex.clear(); delete m_storage; m_storage = 0; d._filePath.clear(); d._lastModifiedPos = DocPosition(); d._modifiedEntries.clear(); while (!d._altTransCatalogs.isEmpty()) d._altTransCatalogs.takeFirst()->deleteLater(); d._altTranslations.clear(); /* d.msgidDiffList.clear(); d.msgstr2MsgidDiffList.clear(); d.diffCache.clear(); */ } void Catalog::push(QUndoCommand* cmd) { generatePhaseForCatalogIfNeeded(this); QUndoStack::push(cmd); } //BEGIN STORAGE TRANSLATION int Catalog::capabilities() const { if (Q_UNLIKELY(!m_storage)) return 0; return m_storage->capabilities(); } int Catalog::numberOfEntries() const { if (Q_UNLIKELY(!m_storage)) return 0; return m_storage->size(); } static DocPosition alterForSinglePlural(const Catalog* th, DocPosition pos) { //if source lang is english (implied) and target lang has only 1 plural form (e.g. Chinese) if (Q_UNLIKELY(th->numberOfPluralForms() == 1 && th->isPlural(pos))) pos.form = 1; return pos; } QString Catalog::msgid(const DocPosition& pos) const { if (Q_UNLIKELY(!m_storage)) return QString(); return m_storage->source(alterForSinglePlural(this, pos)); } QString Catalog::msgidWithPlurals(const DocPosition& pos) const { if (Q_UNLIKELY(!m_storage)) return QString(); return m_storage->sourceWithPlurals(pos); } QString Catalog::msgstr(const DocPosition& pos) const { if (Q_UNLIKELY(!m_storage)) return QString(); return m_storage->target(pos); } QString Catalog::msgstrWithPlurals(const DocPosition& pos) const { if (Q_UNLIKELY(!m_storage)) return QString(); return m_storage->targetWithPlurals(pos); } CatalogString Catalog::sourceWithTags(const DocPosition& pos) const { if (Q_UNLIKELY(!m_storage)) return CatalogString(); return m_storage->sourceWithTags(alterForSinglePlural(this, pos)); } CatalogString Catalog::targetWithTags(const DocPosition& pos) const { if (Q_UNLIKELY(!m_storage)) return CatalogString(); return m_storage->targetWithTags(pos); } CatalogString Catalog::catalogString(const DocPosition& pos) const { if (Q_UNLIKELY(!m_storage)) return CatalogString(); return m_storage->catalogString(pos.part == DocPosition::Source ? alterForSinglePlural(this, pos) : pos); } QVector Catalog::notes(const DocPosition& pos) const { if (Q_UNLIKELY(!m_storage)) return QVector(); return m_storage->notes(pos); } QVector Catalog::developerNotes(const DocPosition& pos) const { if (Q_UNLIKELY(!m_storage)) return QVector(); return m_storage->developerNotes(pos); } Note Catalog::setNote(const DocPosition& pos, const Note& note) { if (Q_UNLIKELY(!m_storage)) return Note(); return m_storage->setNote(pos, note); } QStringList Catalog::noteAuthors() const { if (Q_UNLIKELY(!m_storage)) return QStringList(); return m_storage->noteAuthors(); } void Catalog::attachAltTransCatalog(Catalog* altCat) { d._altTransCatalogs.append(altCat); if (numberOfEntries() != altCat->numberOfEntries()) qCWarning(LOKALIZE_LOG) << altCat->url() << "has different number of entries"; } void Catalog::attachAltTrans(int entry, const AltTrans& trans) { d._altTranslations.insert(entry, trans); } QVector Catalog::altTrans(const DocPosition& pos) const { QVector result; if (m_storage) result = m_storage->altTrans(pos); foreach (Catalog* altCat, d._altTransCatalogs) { if (pos.entry >= altCat->numberOfEntries()) { qCDebug(LOKALIZE_LOG) << "ignoring" << altCat->url() << "this time because" << pos.entry << "<" << altCat->numberOfEntries(); continue; } if (altCat->source(pos) != source(pos)) { qCDebug(LOKALIZE_LOG) << "ignoring" << altCat->url() << "this time because s don't match"; continue; } QString target = altCat->msgstr(pos); if (!target.isEmpty() && altCat->isApproved(pos)) { result << AltTrans(); result.last().target = target; result.last().type = AltTrans::Reference; result.last().origin = altCat->url(); } } if (d._altTranslations.contains(pos.entry)) result << d._altTranslations.value(pos.entry); return result; } QStringList Catalog::sourceFiles(const DocPosition& pos) const { if (Q_UNLIKELY(!m_storage)) return QStringList(); return m_storage->sourceFiles(pos); } QString Catalog::id(const DocPosition& pos) const { if (Q_UNLIKELY(!m_storage)) return QString(); return m_storage->id(pos); } QStringList Catalog::context(const DocPosition& pos) const { if (Q_UNLIKELY(!m_storage)) return QStringList(); return m_storage->context(pos); } QString Catalog::setPhase(const DocPosition& pos, const QString& phase) { if (Q_UNLIKELY(!m_storage)) return QString(); return m_storage->setPhase(pos, phase); } void Catalog::setActivePhase(const QString& phase, ProjectLocal::PersonRole role) { //qCDebug(LOKALIZE_LOG)<<"setting active phase"<size(); while (pos.entry < limit) { if (!isApproved(pos)) d._nonApprovedIndex << pos.entry; if (m_storage->isEmpty(pos)) d._emptyIndex << pos.entry; ++(pos.entry); } emit signalNumberOfFuzziesChanged(); emit signalNumberOfEmptyChanged(); } QString Catalog::phase(const DocPosition& pos) const { if (Q_UNLIKELY(!m_storage)) return QString(); return m_storage->phase(pos); } Phase Catalog::phase(const QString& name) const { return m_storage->phase(name); } QList Catalog::allPhases() const { return m_storage->allPhases(); } QVector Catalog::phaseNotes(const QString& phase) const { return m_storage->phaseNotes(phase); } QVector Catalog::setPhaseNotes(const QString& phase, QVector notes) { return m_storage->setPhaseNotes(phase, notes); } QMap Catalog::allTools() const { return m_storage->allTools(); } bool Catalog::isPlural(uint index) const { return m_storage && m_storage->isPlural(DocPosition(index)); } bool Catalog::isApproved(uint index) const { if (Q_UNLIKELY(!m_storage)) return false; bool extendedStates = m_storage->capabilities()&ExtendedStates; return (extendedStates &&::isApproved(state(DocPosition(index)), activePhaseRole())) || (!extendedStates && m_storage->isApproved(DocPosition(index))); } TargetState Catalog::state(const DocPosition& pos) const { if (Q_UNLIKELY(!m_storage)) return NeedsTranslation; if (m_storage->capabilities()&ExtendedStates) return m_storage->state(pos); else return closestState(m_storage->isApproved(pos), activePhaseRole()); } bool Catalog::isEmpty(uint index) const { return m_storage && m_storage->isEmpty(DocPosition(index)); } bool Catalog::isEmpty(const DocPosition& pos) const { return m_storage && m_storage->isEmpty(pos); } bool Catalog::isEquivTrans(const DocPosition& pos) const { return m_storage && m_storage->isEquivTrans(pos); } int Catalog::binUnitsCount() const { return m_storage ? m_storage->binUnitsCount() : 0; } int Catalog::unitById(const QString& id) const { return m_storage ? m_storage->unitById(id) : 0; } QString Catalog::mimetype() { if (Q_UNLIKELY(!m_storage)) return QString(); return m_storage->mimetype(); } QString Catalog::fileType() { if (Q_UNLIKELY(!m_storage)) return QString(); return m_storage->fileType(); } CatalogType Catalog::type() { if (Q_UNLIKELY(!m_storage)) return Gettext; return m_storage->type(); } QString Catalog::sourceLangCode() const { if (Q_UNLIKELY(!m_storage)) return QString(); return m_storage->sourceLangCode(); } QString Catalog::targetLangCode() const { if (Q_UNLIKELY(!m_storage)) return QString(); return m_storage->targetLangCode(); } void Catalog::setTargetLangCode(const QString& targetLangCode) { if (Q_UNLIKELY(!m_storage)) return; bool notify = m_storage->targetLangCode() != targetLangCode; m_storage->setTargetLangCode(targetLangCode); if (notify) emit signalFileLoaded(); } //END STORAGE TRANSLATION //BEGIN OPEN/SAVE #define DOESNTEXIST -1 #define ISNTREADABLE -2 #define UNKNOWNFORMAT -3 KAutoSaveFile* Catalog::checkAutoSave(const QString& url) { -#ifndef NOKDE KAutoSaveFile* autoSave = 0; QList staleFiles = KAutoSaveFile::staleFiles(QUrl::fromLocalFile(url)); foreach (KAutoSaveFile *stale, staleFiles) { if (stale->open(QIODevice::ReadOnly) && !autoSave) { autoSave = stale; autoSave->setParent(this); } else stale->deleteLater(); } if (autoSave) qCInfo(LOKALIZE_LOG) << "autoSave" << autoSave->fileName(); return autoSave; -#else - return 0; -#endif } int Catalog::loadFromUrl(const QString& filePath, const QString& saidUrl, int* fileSize, bool fast) { QFileInfo info(filePath); if (Q_UNLIKELY(!info.exists() || info.isDir())) return DOESNTEXIST; if (Q_UNLIKELY(!info.isReadable())) return ISNTREADABLE; bool readOnly = !info.isWritable(); QTime a; a.start(); QFile file(filePath); if (!file.open(QIODevice::ReadOnly)) return ISNTREADABLE;//TODO CatalogStorage* storage = 0; if (filePath.endsWith(QLatin1String(".po")) || filePath.endsWith(QLatin1String(".pot"))) storage = new GettextCatalog::GettextStorage; else if (filePath.endsWith(QLatin1String(".xlf")) || filePath.endsWith(QLatin1String(".xliff"))) storage = new XliffStorage; else if (filePath.endsWith(QLatin1String(".ts"))) storage = new TsStorage; else { //try harder QTextStream in(&file); int i = 0; bool gettext = false; while (!in.atEnd() && ++i < 64 && !gettext) gettext = in.readLine().contains(QLatin1String("msgid")); if (gettext) storage = new GettextCatalog::GettextStorage; else return UNKNOWNFORMAT; } int line = storage->load(&file); file.close(); if (Q_UNLIKELY(line != 0 || (!storage->size() && (line == -1)))) { delete storage; return line; } if (a.elapsed() > 100) qCDebug(LOKALIZE_LOG) << filePath << "opened in" << a.elapsed(); //ok... clear(); //commit transaction m_storage = storage; updateApprovedEmptyIndexCache(); d._numberOfPluralForms = storage->numberOfPluralForms(); d._autoSaveDirty = true; d._readOnly = readOnly; d._filePath = saidUrl.isEmpty() ? filePath : saidUrl; //set some sane role, a real phase with a nmae will be created later with the first edit command setActivePhase(QString(), Project::local()->role()); -#ifndef NOKDE if (!fast) { KAutoSaveFile* autoSave = checkAutoSave(d._filePath); d._autoSaveRecovered = autoSave; if (autoSave) { d._autoSave->deleteLater(); d._autoSave = autoSave; //restore 'modified' status for entries MergeCatalog* mergeCatalog = new MergeCatalog(this, this); int errorLine = mergeCatalog->loadFromUrl(autoSave->fileName()); if (Q_LIKELY(errorLine == 0)) mergeCatalog->copyToBaseCatalog(); mergeCatalog->deleteLater(); d._autoSave->close(); } else d._autoSave->setManagedFile(QUrl::fromLocalFile(d._filePath)); } -#endif if (fileSize) *fileSize = file.size(); emit signalFileLoaded(); emit signalFileLoaded(d._filePath); return 0; } bool Catalog::save() { return saveToUrl(d._filePath); } //this function is not called if QUndoStack::isClean() ! bool Catalog::saveToUrl(QString localFilePath) { if (Q_UNLIKELY(!m_storage)) return true; bool nameChanged = localFilePath.length(); if (Q_LIKELY(!nameChanged)) localFilePath = d._filePath; QString localPath = QFileInfo(localFilePath).absolutePath(); if (!QFileInfo::exists(localPath)) if (!QDir::root().mkpath(localPath)) return false; QFile file(localFilePath); if (Q_UNLIKELY(!file.open(QIODevice::WriteOnly))) //i18n("Wasn't able to open file %1",filename.ascii()); return false; bool belongsToProject = localFilePath.contains(Project::instance()->poDir()); if (Q_UNLIKELY(!m_storage->save(&file, belongsToProject))) return false; file.close(); -#ifndef NOKDE d._autoSave->remove(); d._autoSaveRecovered = false; -#endif setClean(); //undo/redo if (nameChanged) { d._filePath = localFilePath; -#ifndef NOKDE d._autoSave->setManagedFile(QUrl::fromLocalFile(localFilePath)); -#endif } //Settings::self()->setCurrentGroup("Bookmarks"); //Settings::self()->addItemIntList(d._filePath.url(),d._bookmarkIndex); emit signalFileSaved(); emit signalFileSaved(localFilePath); return true; /* else if (status==NO_PERMISSIONS) { if (KMessageBox::warningContinueCancel(this, i18n("You do not have permission to write to file:\n%1\n" "Do you want to save to another file or cancel?", _currentURL.prettyUrl()), i18n("Error"),KStandardGuiItem::save())==KMessageBox::Continue) return fileSaveAs(); } */ } void Catalog::doAutoSave() { -#ifndef NOKDE if (isClean() || !(d._autoSaveDirty)) return; if (Q_UNLIKELY(!m_storage)) return; if (!d._autoSave->open(QIODevice::WriteOnly)) { emit signalFileAutoSaveFailed(d._autoSave->fileName()); return; } qCInfo(LOKALIZE_LOG) << "doAutoSave" << d._autoSave->fileName(); m_storage->save(d._autoSave); d._autoSave->close(); d._autoSaveDirty = false; -#endif } void Catalog::projectConfigChanged() { setActivePhase(activePhase(), Project::local()->role()); } QByteArray Catalog::contents() { QBuffer buf; buf.open(QIODevice::WriteOnly); m_storage->save(&buf); buf.close(); return buf.data(); } //END OPEN/SAVE /** * helper method to keep db in a good shape :) * called on * 1) entry switch * 2) automatic editing code like replace or undo/redo operation **/ static void updateDB( const QString& filePath, const QString& ctxt, const CatalogString& english, const CatalogString& newTarget, int form, bool approved, const QString& dbName //const DocPosition&,//for back tracking ) { TM::UpdateJob* j = new TM::UpdateJob(filePath, ctxt, english, newTarget, form, approved, dbName); TM::threadPool()->start(j); } //BEGIN UNDO/REDO const DocPosition& Catalog::undo() { QUndoStack::undo(); return d._lastModifiedPos; } const DocPosition& Catalog::redo() { QUndoStack::redo(); return d._lastModifiedPos; } void Catalog::flushUpdateDBBuffer() { if (!Settings::autoaddTM()) return; DocPosition pos = d._lastModifiedPos; if (pos.entry == -1 || pos.entry >= numberOfEntries()) { //nothing to flush //qCWarning(LOKALIZE_LOG)<<"nothing to flush or new file opened"; return; } QString dbName; if (Project::instance()->targetLangCode() == targetLangCode()) { dbName = Project::instance()->projectID(); } else { dbName = sourceLangCode() % '-' % targetLangCode(); qCInfo(LOKALIZE_LOG) << "updating" << dbName << "because target language of project db does not match" << Project::instance()->targetLangCode() << targetLangCode(); if (!TM::DBFilesModel::instance()->m_configurations.contains(dbName)) { TM::OpenDBJob* openDBJob = new TM::OpenDBJob(dbName, TM::Local, true); connect(openDBJob, &TM::OpenDBJob::done, TM::DBFilesModel::instance(), &TM::DBFilesModel::updateProjectTmIndex); openDBJob->m_setParams = true; openDBJob->m_tmConfig.markup = Project::instance()->markup(); openDBJob->m_tmConfig.accel = Project::instance()->accel(); openDBJob->m_tmConfig.sourceLangCode = sourceLangCode(); openDBJob->m_tmConfig.targetLangCode = targetLangCode(); TM::DBFilesModel::instance()->openDB(openDBJob); } } int form = -1; if (isPlural(pos.entry)) form = pos.form; updateDB(url(), context(pos.entry).first(), sourceWithTags(pos), targetWithTags(pos), form, isApproved(pos.entry), dbName); d._lastModifiedPos = DocPosition(); } void Catalog::setLastModifiedPos(const DocPosition& pos) { if (pos.entry >= numberOfEntries()) //bin-units return; bool entryChanged = DocPos(d._lastModifiedPos) != DocPos(pos); if (entryChanged) flushUpdateDBBuffer(); d._lastModifiedPos = pos; } bool CatalogPrivate::addToEmptyIndexIfAppropriate(CatalogStorage* storage, const DocPosition& pos, bool alreadyEmpty) { if ((!pos.offset) && (storage->target(pos).isEmpty()) && (!alreadyEmpty)) { insertInList(_emptyIndex, pos.entry); return true; } return false; } void Catalog::targetDelete(const DocPosition& pos, int count) { if (Q_UNLIKELY(!m_storage)) return; bool alreadyEmpty = m_storage->isEmpty(pos); m_storage->targetDelete(pos, count); if (d.addToEmptyIndexIfAppropriate(m_storage, pos, alreadyEmpty)) emit signalNumberOfEmptyChanged(); emit signalEntryModified(pos); } bool CatalogPrivate::removeFromUntransIndexIfAppropriate(CatalogStorage* storage, const DocPosition& pos) { if ((!pos.offset) && (storage->isEmpty(pos))) { _emptyIndex.removeAll(pos.entry); return true; } return false; } void Catalog::targetInsert(const DocPosition& pos, const QString& arg) { if (Q_UNLIKELY(!m_storage)) return; if (d.removeFromUntransIndexIfAppropriate(m_storage, pos)) emit signalNumberOfEmptyChanged(); m_storage->targetInsert(pos, arg); emit signalEntryModified(pos); } void Catalog::targetInsertTag(const DocPosition& pos, const InlineTag& tag) { if (Q_UNLIKELY(!m_storage)) return; if (d.removeFromUntransIndexIfAppropriate(m_storage, pos)) emit signalNumberOfEmptyChanged(); m_storage->targetInsertTag(pos, tag); emit signalEntryModified(pos); } InlineTag Catalog::targetDeleteTag(const DocPosition& pos) { if (Q_UNLIKELY(!m_storage)) return InlineTag(); bool alreadyEmpty = m_storage->isEmpty(pos); InlineTag tag = m_storage->targetDeleteTag(pos); if (d.addToEmptyIndexIfAppropriate(m_storage, pos, alreadyEmpty)) emit signalNumberOfEmptyChanged(); emit signalEntryModified(pos); return tag; } void Catalog::setTarget(DocPosition pos, const CatalogString& s) { //TODO for case of markup present m_storage->setTarget(pos, s.string); } TargetState Catalog::setState(const DocPosition& pos, TargetState state) { bool extendedStates = m_storage && m_storage->capabilities()&ExtendedStates; bool approved =::isApproved(state, activePhaseRole()); if (Q_UNLIKELY(!m_storage || (extendedStates && m_storage->state(pos) == state) || (!extendedStates && m_storage->isApproved(pos) == approved))) return this->state(pos); TargetState prevState; if (extendedStates) { prevState = m_storage->setState(pos, state); d._statesIndex[prevState].removeAll(pos.entry); insertInList(d._statesIndex[state], pos.entry); } else { prevState = closestState(!approved, activePhaseRole()); m_storage->setApproved(pos, approved); } if (!approved) insertInList(d._nonApprovedIndex, pos.entry); else d._nonApprovedIndex.removeAll(pos.entry); emit signalNumberOfFuzziesChanged(); emit signalEntryModified(pos); return prevState; } Phase Catalog::updatePhase(const Phase& phase) { return m_storage->updatePhase(phase); } void Catalog::setEquivTrans(const DocPosition& pos, bool equivTrans) { if (m_storage) m_storage->setEquivTrans(pos, equivTrans); } bool Catalog::setModified(DocPos entry, bool modified) { if (modified) { if (d._modifiedEntries.contains(entry)) return false; d._modifiedEntries.insert(entry); } else d._modifiedEntries.remove(entry); return true; } bool Catalog::isModified(DocPos entry) const { return d._modifiedEntries.contains(entry); } bool Catalog::isModified(int entry) const { if (!isPlural(entry)) return isModified(DocPos(entry, 0)); int f = numberOfPluralForms(); while (--f >= 0) if (isModified(DocPos(entry, f))) return true; return false; } //END UNDO/REDO int findNextInList(const QLinkedList& list, int index) { int nextIndex = -1; foreach (int key, list) { if (Q_UNLIKELY(key > index)) { nextIndex = key; break; } } return nextIndex; } int findPrevInList(const QLinkedList& list, int index) { int prevIndex = -1; foreach (int key, list) { if (Q_UNLIKELY(key >= index)) break; prevIndex = key; } return prevIndex; } void insertInList(QLinkedList& list, int index) { QLinkedList::Iterator it = list.begin(); while (it != list.end() && index > *it) ++it; list.insert(it, index); } void Catalog::setBookmark(uint idx, bool set) { if (set) insertInList(d._bookmarkIndex, idx); else d._bookmarkIndex.removeAll(idx); } bool isApproved(TargetState state, ProjectLocal::PersonRole role) { static const TargetState marginStates[] = {Translated, Final, SignedOff}; return state >= marginStates[role]; } bool isApproved(TargetState state) { static const TargetState marginStates[] = {Translated, Final, SignedOff}; return state == marginStates[0] || state == marginStates[1] || state == marginStates[2]; } TargetState closestState(bool approved, ProjectLocal::PersonRole role) { Q_ASSERT(role != ProjectLocal::Undefined); static const TargetState approvementStates[][3] = { {NeedsTranslation, NeedsReviewTranslation, NeedsReviewTranslation}, {Translated, Final, SignedOff} }; return approvementStates[approved][role]; } bool Catalog::isObsolete(int entry) const { if (Q_UNLIKELY(!m_storage)) return false; return m_storage->isObsolete(entry); } QString Catalog::originalOdfFilePath() { if (Q_UNLIKELY(!m_storage)) return QString(); return m_storage->originalOdfFilePath(); } void Catalog::setOriginalOdfFilePath(const QString& odfFilePath) { if (Q_UNLIKELY(!m_storage)) return; m_storage->setOriginalOdfFilePath(odfFilePath); } diff --git a/src/catalog/catalog_private.h b/src/catalog/catalog_private.h index c413d37..9ac218a 100644 --- a/src/catalog/catalog_private.h +++ b/src/catalog/catalog_private.h @@ -1,131 +1,125 @@ /* **************************************************************************** This file is part of Lokalize This file is based on the one from KBabel Copyright (C) 1999-2000 by Matthias Kiefer 2001-2004 by Stanislav Visnovsky 2007 by Nick Shaforostoff 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) any later version. 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. **************************************************************************** */ #ifndef CATALOGPRIVATE_H #define CATALOGPRIVATE_H #include "projectlocal.h" #include "state.h" #include "pos.h" #include "alttrans.h" -#ifndef NOKDE #include -#endif #include #include #include #include #include #include #include class QTextCodec; class CatalogStorage; class Catalog; class CatalogPrivate { public: /** url of the po-file, that belongs to this catalog */ QString _filePath; QString _packageName; QString _packageDir; /** identification string for used import filter*/ QString _importID; QTextCodec *fileCodec; int _numberOfPluralForms; QTimer _autoSaveTimer; -#ifndef NOKDE KAutoSaveFile* _autoSave; -#endif bool _autoSaveDirty; bool _autoSaveRecovered; bool _readOnly; //for wrapping short _maxLineLength; QLinkedList _nonApprovedIndex; QLinkedList _emptyIndex; QLinkedList _errorIndex; QLinkedList _bookmarkIndex; QVector< QLinkedList > _statesIndex; QLinkedList _altTransCatalogs; QMap _altTranslations; //for undo/redo //keeps pos of the entry that was last modified DocPosition _lastModifiedPos; QSet _modifiedEntries;//just for the nice gui QString _phase; ProjectLocal::PersonRole _phaseRole; explicit CatalogPrivate(QObject* parent) : fileCodec(0) , _numberOfPluralForms(-1) -#ifndef NOKDE , _autoSave(new KAutoSaveFile(parent)) -#endif , _autoSaveDirty(true) , _autoSaveRecovered(false) , _readOnly(false) , _maxLineLength(80) , _phaseRole(ProjectLocal::Undefined) { Q_UNUSED(parent) _statesIndex.resize(StateCount); } bool addToEmptyIndexIfAppropriate(CatalogStorage*, const DocPosition& pos, bool alreadyEmpty); bool removeFromUntransIndexIfAppropriate(CatalogStorage*, const DocPosition& pos); }; #endif //CatalogPrivate_H diff --git a/src/catalog/catalogstring.cpp b/src/catalog/catalogstring.cpp index 4c81f27..8513d6d 100644 --- a/src/catalog/catalogstring.cpp +++ b/src/catalog/catalogstring.cpp @@ -1,325 +1,325 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2008-2014 by Nick Shaforostoff 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 "catalogstring.h" #include "lokalize_debug.h" #include const char* InlineTag::getElementName(InlineElement type) { static const char* inlineElementNames[(int)InlineElementCount] = { "_unknown", "bpt", "ept", "ph", "it", //"_NEVERSHOULDBECHOSEN", "mrk", "g", "sub", "_NEVERSHOULDBECHOSEN", "x", "bx", "ex" }; return inlineElementNames[(int)type]; } InlineTag InlineTag::getPlaceholder() const { InlineTag tagRange = *this; tagRange.start = -1; tagRange.end = -1; return tagRange; } InlineTag::InlineElement InlineTag::getElementType(const QByteArray& tag) { int i = InlineTag::InlineElementCount; while (--i > 0) if (getElementName(InlineElement(i)) == tag) break; return InlineElement(i); } QString InlineTag::displayName() const { static const char* inlineElementNames[(int)InlineElementCount] = { "_unknown", I18N_NOOP2("XLIFF inline tag name", "Start of paired tag"), I18N_NOOP2("XLIFF inline tag name", "End of paired tag"), I18N_NOOP2("XLIFF inline tag name", "Stand-alone tag"), I18N_NOOP2("XLIFF inline tag name", "Isolated tag"), //"_NEVERSHOULDBECHOSEN", I18N_NOOP2("XLIFF inline tag name", "Marker"), I18N_NOOP2("XLIFF inline tag name", "Generic group placeholder"), I18N_NOOP2("XLIFF inline tag name", "Sub-flow"), "_NEVERSHOULDBECHOSEN", I18N_NOOP2("XLIFF inline tag name", "Generic placeholder"), I18N_NOOP2("XLIFF inline tag name", "Start of paired placeholder"), I18N_NOOP2("XLIFF inline tag name", "End of paired placeholder") }; QString result = i18nc("XLIFF inline tag name", inlineElementNames[type]); if (type == mrk) { static const char* mrkTypes[] = { "abbrev", "abbreviated-form", "abbreviation", "acronym", "appellation", "collocation", "common-name", "datetime", "equation", "expanded-form", "formula", "head-term", "initialism", "international-scientific-term", "internationalism", "logical-expression", "materials-management-unit", "name", "near-synonym", "part-number", "phrase", "phraseological-unit", "protected", "romanized-form", "seg", "set-phrase", "short-form", "sku", "standard-text", "symbol", "synonym", "synonymous-phrase", "term", "transcribed-form", "transliterated-form", "truncated-term", "variant" }; static const char* mrkTypeNames[] = { I18N_NOOP2("XLIFF mark type", "abbreviation"), I18N_NOOP2("XLIFF mark type", "abbreviated form: a term resulting from the omission of any part of the full term while designating the same concept"), I18N_NOOP2("XLIFF mark type", "abbreviation: an abbreviated form of a simple term resulting from the omission of some of its letters (e.g. 'adj.' for 'adjective')"), I18N_NOOP2("XLIFF mark type", "acronym: an abbreviated form of a term made up of letters from the full form of a multiword term strung together into a sequence pronounced only syllabically (e.g. 'radar' for 'radio detecting and ranging')"), I18N_NOOP2("XLIFF mark type", "appellation: a proper-name term, such as the name of an agency or other proper entity"), I18N_NOOP2("XLIFF mark type", "collocation: a recurrent word combination characterized by cohesion in that the components of the collocation must co-occur within an utterance or series of utterances, even though they do not necessarily have to maintain immediate proximity to one another"), I18N_NOOP2("XLIFF mark type", "common name: a synonym for an international scientific term that is used in general discourse in a given language"), I18N_NOOP2("XLIFF mark type", "date and/or time"), I18N_NOOP2("XLIFF mark type", "equation: an expression used to represent a concept based on a statement that two mathematical expressions are, for instance, equal as identified by the equal sign (=), or assigned to one another by a similar sign"), I18N_NOOP2("XLIFF mark type", "expanded form: The complete representation of a term for which there is an abbreviated form"), I18N_NOOP2("XLIFF mark type", "formula: figures, symbols or the like used to express a concept briefly, such as a mathematical or chemical formula"), I18N_NOOP2("XLIFF mark type", "head term: the concept designation that has been chosen to head a terminological record"), I18N_NOOP2("XLIFF mark type", "initialism: an abbreviated form of a term consisting of some of the initial letters of the words making up a multiword term or the term elements making up a compound term when these letters are pronounced individually (e.g. 'BSE' for 'bovine spongiform encephalopathy')"), I18N_NOOP2("XLIFF mark type", "international scientific term: a term that is part of an international scientific nomenclature as adopted by an appropriate scientific body"), I18N_NOOP2("XLIFF mark type", "internationalism: a term that has the same or nearly identical orthographic or phonemic form in many languages"), I18N_NOOP2("XLIFF mark type", "logical expression: an expression used to represent a concept based on mathematical or logical relations, such as statements of inequality, set relationships, Boolean operations, and the like"), I18N_NOOP2("XLIFF mark type", "materials management unit: a unit to track object"), I18N_NOOP2("XLIFF mark type", "name"), I18N_NOOP2("XLIFF mark type", "near synonym: a term that represents the same or a very similar concept as another term in the same language, but for which interchangeability is limited to some contexts and inapplicable in others"), I18N_NOOP2("XLIFF mark type", "part number: a unique alphanumeric designation assigned to an object in a manufacturing system"), I18N_NOOP2("XLIFF mark type", "phrase"), I18N_NOOP2("XLIFF mark type", "phraseological: a group of two or more words that form a unit, the meaning of which frequently cannot be deduced based on the combined sense of the words making up the phrase"), I18N_NOOP2("XLIFF mark type", "protected: the marked text should not be translated"), I18N_NOOP2("XLIFF mark type", "romanized form: a form of a term resulting from an operation whereby non-Latin writing systems are converted to the Latin alphabet"), I18N_NOOP2("XLIFF mark type", "segment: the marked text represents a segment"), I18N_NOOP2("XLIFF mark type", "set phrase: a fixed, lexicalized phrase"), I18N_NOOP2("XLIFF mark type", "short form: a variant of a multiword term that includes fewer words than the full form of the term (e.g. 'Group of Twenty-four' for 'Intergovernmental Group of Twenty-four on International Monetary Affairs')"), I18N_NOOP2("XLIFF mark type", "stock keeping unit: an inventory item identified by a unique alphanumeric designation assigned to an object in an inventory control system"), I18N_NOOP2("XLIFF mark type", "standard text: a fixed chunk of recurring text"), I18N_NOOP2("XLIFF mark type", "symbol: a designation of a concept by letters, numerals, pictograms or any combination thereof"), I18N_NOOP2("XLIFF mark type", "synonym: a term that represents the same or a very similar concept as the main entry term in a term entry"), I18N_NOOP2("XLIFF mark type", "synonymous phrase: phraseological unit in a language that expresses the same semantic content as another phrase in that same language"), I18N_NOOP2("XLIFF mark type", "term"), I18N_NOOP2("XLIFF mark type", "transcribed form: a form of a term resulting from an operation whereby the characters of one writing system are represented by characters from another writing system, taking into account the pronunciation of the characters converted"), I18N_NOOP2("XLIFF mark type", "transliterated form: a form of a term resulting from an operation whereby the characters of an alphabetic writing system are represented by characters from another alphabetic writing system"), I18N_NOOP2("XLIFF mark type", "truncated term: an abbreviated form of a term resulting from the omission of one or more term elements or syllables (e.g. 'flu' for 'influenza')"), I18N_NOOP2("XLIFF mark type", "variant: one of the alternate forms of a term") }; int i = sizeof(mrkTypes) / sizeof(char*); while (--i >= 0 && mrkTypes[i] != id) ; if (i != -1) { result = i18nc("XLIFF mark type", mrkTypeNames[i]); if (!result.isEmpty()) result[0] = result.at(0).toUpper(); } } if (!ctype.isEmpty()) - result += " (" + ctype + ")"; + result += " (" + ctype + ')'; return result; } QMap CatalogString::tagIdToIndex() const { QMap result; int index = 0; int count = tags.size(); for (int i = 0; i < count; ++i) { if (!result.contains(tags.at(i).id)) result.insert(tags.at(i).id, index++); } return result; } QByteArray CatalogString::tagsAsByteArray()const { QByteArray result; if (tags.size()) { QDataStream stream(&result, QIODevice::WriteOnly); stream << tags; } return result; } CatalogString::CatalogString(QString str, QByteArray tagsByteArray) : string(str) { if (tagsByteArray.size()) { QDataStream stream(tagsByteArray); stream >> tags; } } static void adjustTags(QList& tags, int position, int value) { int i = tags.size(); while (--i >= 0) { InlineTag& t = tags[i]; if (t.start > position) t.start += value; if (t.end >= position) //cases when strict > is needed? t.end += value; } } void CatalogString::remove(int position, int len) { string.remove(position, len); adjustTags(tags, position, -len); } void CatalogString::insert(int position, const QString& str) { string.insert(position, str); adjustTags(tags, position, str.size()); } QDataStream &operator<<(QDataStream &out, const InlineTag &t) { return out << int(t.type) << t.start << t.end << t.id; } QDataStream &operator>>(QDataStream &in, InlineTag &t) { int type; in >> type >> t.start >> t.end >> t.id; t.type = InlineTag::InlineElement(type); return in; } QDataStream &operator<<(QDataStream &out, const CatalogString &myObj) { return out << myObj.string << myObj.tags; } QDataStream &operator>>(QDataStream &in, CatalogString &myObj) { return in >> myObj.string >> myObj.tags; } void adaptCatalogString(CatalogString& target, const CatalogString& ref) { //qCWarning(LOKALIZE_LOG) << "HERE" << target.string; QHash id2tagIndex; QMultiMap tagType2tagIndex; int i = ref.tags.size(); while (--i >= 0) { const InlineTag& t = ref.tags.at(i); id2tagIndex.insert(t.id, i); tagType2tagIndex.insert(t.type, i); qCWarning(LOKALIZE_LOG) << "inserting" << t.id << t.type << i; } QList oldTags = target.tags; target.tags.clear(); //we actually walking from beginning to end: qSort(oldTags.begin(), oldTags.end(), qGreater()); i = oldTags.size(); while (--i >= 0) { const InlineTag& targetTag = oldTags.at(i); if (id2tagIndex.contains(targetTag.id)) { qCWarning(LOKALIZE_LOG) << "matched" << targetTag.id << i; target.tags.append(targetTag); tagType2tagIndex.remove(targetTag.type, id2tagIndex.take(targetTag.id)); oldTags.removeAt(i); } } //qCWarning(LOKALIZE_LOG) << "HERE 0" << target.string; //now all the tags left have to ID (exact) matches i = oldTags.size(); while (--i >= 0) { InlineTag targetTag = oldTags.at(i); if (tagType2tagIndex.contains(targetTag.type)) { //try to match by position //we're _taking_ first so the next one becomes new 'first' for the next time. QList possibleRefMatches; foreach (int i, tagType2tagIndex.values(targetTag.type)) possibleRefMatches << ref.tags.at(i); qSort(possibleRefMatches); qCWarning(LOKALIZE_LOG) << "setting id:" << targetTag.id << possibleRefMatches.first().id; targetTag.id = possibleRefMatches.first().id; target.tags.append(targetTag); qCWarning(LOKALIZE_LOG) << "id??:" << targetTag.id << target.tags.first().id; tagType2tagIndex.remove(targetTag.type, id2tagIndex.take(targetTag.id)); oldTags.removeAt(i); } } //qCWarning(LOKALIZE_LOG) << "HERE 1" << target.string; //now walk through unmatched tags and properly remove them. foreach (const InlineTag& tag, oldTags) { if (tag.isPaired()) target.remove(tag.end, 1); target.remove(tag.start, 1); } //qCWarning(LOKALIZE_LOG) << "HERE 2" << target.string; } diff --git a/src/catalog/gettext/gettextstorage.cpp b/src/catalog/gettext/gettextstorage.cpp index 36d06a0..0ee7931 100644 --- a/src/catalog/gettext/gettextstorage.cpp +++ b/src/catalog/gettext/gettextstorage.cpp @@ -1,466 +1,466 @@ /* Copyright 2008-2014 Nick Shaforostoff 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 "gettextstorage.h" #include "lokalize_debug.h" #include "gettextheader.h" #include "catalogitem_private.h" #include "gettextimport.h" #include "gettextexport.h" #include "project.h" #include "version.h" #include "prefs_lokalize.h" #include "diff.h" #include #include #include #include #include #include QMutex regExMutex; // static QString GNUPluralForms(const QString& lang); using namespace GettextCatalog; GettextStorage::GettextStorage() : CatalogStorage() , m_codec(0) , m_maxLineLength(80) , m_trailingNewLines(0) , m_generatedFromDocbook(false) { } GettextStorage::~GettextStorage() { } //BEGIN OPEN/SAVE int GettextStorage::load(QIODevice* device/*, bool readonly*/) { //GettextImportPlugin importer=GettextImportPlugin(readonly?(new ExtraDataSaver()):(new ExtraDataListSaver())); GettextImportPlugin importer; ConversionStatus status = OK; int errorLine; { QMutexLocker locker(®ExMutex); status = importer.open(device, this, &errorLine); } //for langs with more than 2 forms //we create any form-entries additionally needed uint i = 0; uint lim = size(); while (i < lim) { CatalogItem& item = m_entries[i]; if (item.isPlural() && item.msgstrPlural().count() < m_numberOfPluralForms ) { QVector msgstr(item.msgstrPlural()); while (msgstr.count() < m_numberOfPluralForms) msgstr.append(QString()); item.setMsgstr(msgstr); } ++i; } //qCompress(m_storage->m_catalogExtraData.join("\n\n").toUtf8(),9); return status == OK ? 0 : (errorLine + 1); } bool GettextStorage::save(QIODevice* device, bool belongsToProject) { QString header = m_header.msgstr(); QString comment = m_header.comment(); QString catalogProjectId;//=m_url.fileName(); //catalogProjectId=catalogProjectId.left(catalogProjectId.lastIndexOf('.')); { QMutexLocker locker(®ExMutex); updateHeader(header, comment, m_targetLangCode, m_numberOfPluralForms, catalogProjectId, m_generatedFromDocbook, belongsToProject, /*forSaving*/true, m_codec); } m_header.setMsgstr(header); m_header.setComment(comment); //GettextExportPlugin exporter(m_maxLineLength>70?m_maxLineLength:-1, m_trailingNewLines);// this is kinda hackish... GettextExportPlugin exporter(Project::instance()->wordWrap(), m_trailingNewLines); ConversionStatus status = OK; status = exporter.save(device/*x-gettext-translation*/, this, m_codec); return status == OK; } //END OPEN/SAVE //BEGIN STORAGE TRANSLATION int GettextStorage::size() const { return m_entries.size(); } static const QChar altSep(156); static InlineTag makeInlineTag(int i) { static const QString altSepText(QStringLiteral(" | ")); static const QString ctype = i18n("separator for different-length string alternatives"); return InlineTag(i, i, InlineTag::x, QString::number(i), QString(), altSepText, ctype); } static CatalogString makeCatalogString(const QString& string) { CatalogString result; result.string = string; int i = 0; while ((i = result.string.indexOf(altSep, i)) != -1) { result.string[i] = TAGRANGE_IMAGE_SYMBOL; result.tags.append(makeInlineTag(i)); ++i; } return result; } //flat-model interface (ignores XLIFF grouping) CatalogString GettextStorage::sourceWithTags(DocPosition pos) const { return makeCatalogString(source(pos)); } CatalogString GettextStorage::targetWithTags(DocPosition pos) const { return makeCatalogString(target(pos)); } QString GettextStorage::source(const DocPosition& pos) const { return m_entries.at(pos.entry).msgid(pos.form); } QString GettextStorage::target(const DocPosition& pos) const { return m_entries.at(pos.entry).msgstr(pos.form); } QString GettextStorage::sourceWithPlurals(const DocPosition& pos) const { if (m_entries.at(pos.entry).isPlural()) { const QVector plurals = m_entries.at(pos.entry).msgidPlural(); QString pluralString = QString(); for (int i = 0; i < plurals.size(); i++) { pluralString += plurals.at(i); if (i != plurals.size() - 1) { - pluralString += "|"; + pluralString += '|'; } } return pluralString; } else { return m_entries.at(pos.entry).msgid(pos.form); } } QString GettextStorage::targetWithPlurals(const DocPosition& pos) const { if (m_entries.at(pos.entry).isPlural()) { const QVector plurals = m_entries.at(pos.entry).msgstrPlural(); QString pluralString = QString(); for (int i = 0; i < plurals.size(); i++) { pluralString += plurals.at(i); if (i != plurals.size() - 1) { - pluralString += "|"; + pluralString += '|'; } } return pluralString; } else { return m_entries.at(pos.entry).msgstr(pos.form); } } void GettextStorage::targetDelete(const DocPosition& pos, int count) { m_entries[pos.entry].d._msgstrPlural[pos.form].remove(pos.offset, count); } void GettextStorage::targetInsert(const DocPosition& pos, const QString& arg) { m_entries[pos.entry].d._msgstrPlural[pos.form].insert(pos.offset, arg); } void GettextStorage::setTarget(const DocPosition& pos, const QString& arg) { m_entries[pos.entry].d._msgstrPlural[pos.form] = arg; } void GettextStorage::targetInsertTag(const DocPosition& pos, const InlineTag& tag) { Q_UNUSED(tag); targetInsert(pos, altSep); } InlineTag GettextStorage::targetDeleteTag(const DocPosition& pos) { targetDelete(pos, 1); return makeInlineTag(pos.offset); } QStringList GettextStorage::sourceAllForms(const DocPosition& pos, bool stripNewLines) const { return m_entries.at(pos.entry).allPluralForms(CatalogItem::Source, stripNewLines); } QStringList GettextStorage::targetAllForms(const DocPosition& pos, bool stripNewLines) const { return m_entries.at(pos.entry).allPluralForms(CatalogItem::Target, stripNewLines); } QVector GettextStorage::altTrans(const DocPosition& pos) const { static const QRegExp alt_trans_mark_re(QStringLiteral("^#\\|")); QStringList prev = m_entries.at(pos.entry).comment().split('\n').filter(alt_trans_mark_re); QString oldSingular; QString oldPlural; QString* cur = &oldSingular; QStringList::iterator it = prev.begin(); static const QString msgid_plural_alt = QStringLiteral("#| msgid_plural \""); while (it != prev.end()) { if (it->startsWith(msgid_plural_alt)) cur = &oldPlural; int start = it->indexOf('\"') + 1; int end = it->lastIndexOf('\"'); if (start && end != -1) { if (!cur->isEmpty()) (*cur) += '\n'; if (!(cur->isEmpty() && (end - start) == 0)) //for multiline msgs (*cur) += it->midRef(start, end - start); } ++it; } if (pos.form == 0) cur = &oldSingular; cur->replace(QStringLiteral("\\\""), QStringLiteral("\"")); QVector result; if (!cur->isEmpty()) result << AltTrans(CatalogString(*cur), i18n("Previous source value, saved by Gettext during transition to a newer POT template")); return result; } Note GettextStorage::setNote(DocPosition pos, const Note& note) { //qCWarning(LOKALIZE_LOG)<<"s"< l = notes(pos); if (l.size()) oldNote = l.first(); QStringList comment = m_entries.at(pos.entry).comment().split('\n'); //remove previous comment; QStringList::iterator it = comment.begin(); while (it != comment.end()) { if (it->startsWith(QLatin1String("# "))) it = comment.erase(it); else ++it; } if (note.content.size()) comment.prepend(QStringLiteral("# ") + note.content.split('\n').join(QStringLiteral("\n# "))); m_entries[pos.entry].setComment(comment.join(QStringLiteral("\n"))); //qCWarning(LOKALIZE_LOG)<<"e"< GettextStorage::notes(const DocPosition& docPosition, const QRegExp& re, int preLen) const { QVector result; QString content; QStringList note = m_entries.at(docPosition.entry).comment().split('\n').filter(re); foreach (const QString &s, note) { if (s.size() >= preLen) { content += s.midRef(preLen); content += QLatin1Char('\n'); } } if (!content.isEmpty()) { content.chop(1); result << Note(content); } return result; //i18nc("@info PO comment parsing. contains filename","Place:"); //i18nc("@info PO comment parsing","GUI place:"); } QVector GettextStorage::notes(const DocPosition& docPosition) const { static const QRegExp nre(QStringLiteral("^# ")); return notes(docPosition, nre, 2); } QVector GettextStorage::developerNotes(const DocPosition& docPosition) const { static const QRegExp dnre(QStringLiteral("^#\\. (?!i18n: file:)")); return notes(docPosition, dnre, 3); } QStringList GettextStorage::sourceFiles(const DocPosition& pos) const { QStringList result; QStringList commentLines = m_entries.at(pos.entry).comment().split('\n'); static const QRegExp i18n_file_re(QStringLiteral("^#. i18n: file: ")); foreach (const QString &uiLine, commentLines.filter(i18n_file_re)) { foreach (const QStringRef &fileRef, uiLine.midRef(15).split(' ')) { result << fileRef.toString(); } } bool hasUi = !result.isEmpty(); static const QRegExp cpp_re(QStringLiteral("^#: ")); foreach (const QString &cppLine, commentLines.filter(cpp_re)) { if (hasUi && cppLine.startsWith(QLatin1String("#: rc.cpp"))) continue; foreach (const QStringRef &fileRef, cppLine.midRef(3).split(' ')) { result << fileRef.toString(); } } return result; } QStringList GettextStorage::context(const DocPosition& pos) const { return matchData(pos); } QStringList GettextStorage::matchData(const DocPosition& pos) const { QString ctxt = m_entries.at(pos.entry).msgctxt(); //KDE-specific //Splits @info:whatsthis and actual note /* if (ctxt.startsWith('@') && ctxt.contains(' ')) { QStringList result(ctxt.section(' ',0,0,QString::SectionSkipEmpty)); result<poDir()); updateHeader(values, comment, m_targetLangCode, m_numberOfPluralForms, catalogProjectId, m_generatedFromDocbook, belongsToProject, /*forSaving*/true, m_codec); m_header = newHeader; m_header.setComment(comment); m_header.setMsgstr(values); // setClean(false); //emit signalHeaderChanged(); return true; } qCWarning(LOKALIZE_LOG) << "header Not valid"; return false; } diff --git a/src/catalog/gettextheader.cpp b/src/catalog/gettextheader.cpp index e08b225..a33b881 100644 --- a/src/catalog/gettextheader.cpp +++ b/src/catalog/gettextheader.cpp @@ -1,680 +1,672 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2008-2014 by Nick Shaforostoff 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 "gettextheader.h" #include "lokalize_debug.h" #include "project.h" #include "version.h" #include "prefs_lokalize.h" #include "prefs.h" #include #include #include #include #include #include #include #include #include #include /** * this data was obtained by running GNUPluralForms() * on all languages KDE knows of **/ struct langPInfo { const char *lang; const char *plural; }; static const langPInfo langsWithPInfo[] = { { "ar", "nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;" }, { "be@latin", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" }, { "be", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" }, { "br", "nplurals=1; plural=0;" }, { "bs", "nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;" }, { "csb", "nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)" }, { "cs", "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;" }, { "da", "nplurals=2; plural=(n != 1);" }, { "de", "nplurals=2; plural=(n != 1);" }, { "el", "nplurals=2; plural=(n != 1);" }, { "en", "nplurals=2; plural=(n != 1);" }, { "en_GB", "nplurals=2; plural=(n != 1);" }, { "en_US", "nplurals=2; plural=(n != 1);" }, { "eo", "nplurals=2; plural=(n != 1);" }, { "es", "nplurals=2; plural=(n != 1);" }, { "et", "nplurals=2; plural=(n != 1);" }, { "fa", "nplurals=1; plural=0;" }, { "fi", "nplurals=2; plural=(n != 1);" }, { "fo", "nplurals=2; plural=(n != 1);" }, { "fr", "nplurals=2; plural=(n > 1);" }, { "ga", "nplurals=5; plural=n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n < 11 ? 3 : 4" }, { "gd", "nplurals=4; plural=(n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : (n > 2 && n < 20) ? 2 : 3;" }, { "gu", "nplurals=2; plural=(n!=1);" }, { "he", "nplurals=2; plural=(n != 1);" }, { "hi", "nplurals=2; plural=(n!=1);" }, { "hne", "nplurals=2; plural=(n!=1);" }, { "hr", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" }, { "hsb", "nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3;" }, { "hu", "nplurals=2; plural=(n != 1);" }, { "hy", "nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;" }, { "id", "nplurals=1; plural=0;" }, { "it", "nplurals=2; plural=(n != 1);" }, { "ja", "nplurals=1; plural=0;" }, { "ka", "nplurals=1; plural=0;" }, { "kk", "nplurals=1; plural=0;" }, { "km", "nplurals=1; plural=0;" }, { "ko", "nplurals=1; plural=0;" }, { "lt", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);" }, { "lv", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);" }, { "mai", "nplurals=2; plural=(n!=1);" }, { "mk", "nplurals=3; plural=n%10==1 ? 0 : n%10==2 ? 1 : 2;" }, { "mr", "nplurals=2; plural=(n!=1);" }, { "ms", "nplurals=2; plural=1;" }, { "nb", "nplurals=2; plural=(n != 1);" }, { "nl", "nplurals=2; plural=(n != 1);" }, { "nn", "nplurals=2; plural=(n != 1);" }, { "oc", "nplurals=2; plural=(n > 1);" }, { "or", "nplurals=2; plural=(n!=1);" }, { "pl", "nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" }, { "pt", "nplurals=2; plural=(n != 1);" }, { "pt_BR", "nplurals=2; plural=(n > 1);" }, { "ro", "nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2;" }, { "ru", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" }, { "sk", "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;" }, { "sl", "nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n%100==4 ? 3 : 0);" }, { "sr", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" }, { "sr@latin", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" }, { "sv", "nplurals=2; plural=(n != 1);" }, { "te", "nplurals=5; plural=n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4;" }, { "th", "nplurals=1; plural=0;" }, { "tr", "nplurals=2; plural=(n > 1);" }, { "ug", "nplurals=1; plural=0;" }, { "uk", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" }, { "uz", "nplurals=1; plural=0;" }, { "uz@cyrillic", "nplurals=1; plural=0;" }, { "vi", "nplurals=1; plural=0;" }, { "zh_CN", "nplurals=1; plural=0;" }, { "zh_HK", "nplurals=1; plural=0;" }, { "zh_TW", "nplurals=1; plural=0;" } }; static const size_t langsWithPInfoCount = sizeof(langsWithPInfo) / sizeof(langsWithPInfo[0]); int numberOfPluralFormsFromHeader(const QString& header) { QRegExp rxplural(QStringLiteral("Plural-Forms:\\s*nplurals=(.);")); if (rxplural.indexIn(header) == -1) return 0; bool ok; int result = rxplural.cap(1).toShort(&ok); return ok ? result : 0; } int numberOfPluralFormsForLangCode(const QString& langCode) { QString expr = GNUPluralForms(langCode); QRegExp rxplural(QStringLiteral("nplurals=(.);")); if (rxplural.indexIn(expr) == -1) return 0; bool ok; int result = rxplural.cap(1).toShort(&ok); return ok ? result : 0; } QString GNUPluralForms(const QString& lang) { QByteArray l(lang.toUtf8()); int i = langsWithPInfoCount; while (--i >= 0 && l != langsWithPInfo[i].lang) ; if (Q_LIKELY(i >= 0)) return QString::fromLatin1(langsWithPInfo[i].plural); i = langsWithPInfoCount; while (--i >= 0 && !l.startsWith(langsWithPInfo[i].lang)) ; if (Q_LIKELY(i >= 0)) return QString::fromLatin1(langsWithPInfo[i].plural); //BEGIN alternative // NOTE does this work under M$ OS? qCDebug(LOKALIZE_LOG) << "gonna call msginit"; QString def = QStringLiteral("nplurals=2; plural=n != 1;"); QStringList arguments; arguments << QLatin1String("-l") << lang << QLatin1String("-i") << QLatin1String("-") << QLatin1String("-o") << QLatin1String("-") << QLatin1String("--no-translator") << QLatin1String("--no-wrap"); QProcess msginit; msginit.start(QLatin1String("msginit"), arguments); msginit.waitForStarted(5000); if (Q_UNLIKELY(msginit.state() != QProcess::Running)) { //qCWarning(LOKALIZE_LOG)<<"msginit error"; return def; } msginit.write( "# SOME DESCRIPTIVE TITLE.\n" "# Copyright (C) YEAR Free Software Foundation, Inc.\n" "# FIRST AUTHOR , YEAR.\n" "#\n" "#, fuzzy\n" "msgid \"\"\n" "msgstr \"\"\n" "\"Project-Id-Version: PACKAGE VERSION\\n\"\n" "\"POT-Creation-Date: 2002-06-25 03:23+0200\\n\"\n" "\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n" "\"Last-Translator: FULL NAME \\n\"\n" "\"Language-Team: LANGUAGE \\n\"\n" "\"Language: LL\\n\"\n" "\"MIME-Version: 1.0\\n\"\n" "\"Content-Type: text/plain; charset=UTF-8\\n\"\n" "\"Content-Transfer-Encoding: ENCODING\\n\"\n" // "\"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\\n\"\n" ); msginit.closeWriteChannel(); if (Q_UNLIKELY(!msginit.waitForFinished(5000))) { qCWarning(LOKALIZE_LOG) << "msginit error"; return def; } QByteArray result = msginit.readAll(); int pos = result.indexOf("Plural-Forms: "); if (Q_UNLIKELY(pos == -1)) { //qCWarning(LOKALIZE_LOG)<<"msginit error"<'); temp = QStringLiteral("Last-Translator: ") % authorNameEmail % BACKSLASH_N; QRegExp lt(QStringLiteral("^ *Last-Translator:.*")); for (it = headerList.begin(), found = false; it != headerList.end() && !found; ++it) { if (it->contains(lt)) { if (forSaving) *it = temp; found = true; } } if (Q_UNLIKELY(!found)) headerList.append(temp); QLocale cLocale(QLocale::C); QString dateTimeString = cLocale.toString(QDateTime::currentDateTime(), QStringLiteral("yyyy-MM-dd hh:mm")); const int offset_seconds = QDateTime::currentDateTime().offsetFromUtc(); const int offset_hours = abs(offset_seconds) / 3600; const int offset_minutes = abs(offset_seconds % 3600) / 60; QString zoneOffsetString = (offset_seconds >= 0 ? '+' : '-') % (offset_hours < 10 ? QStringLiteral("0") : QStringLiteral("")) % QString::number(offset_hours) % (offset_minutes < 10 ? QStringLiteral("0") : QStringLiteral("")) % QString::number(offset_minutes); temp = QStringLiteral("PO-Revision-Date: ") % dateTimeString % zoneOffsetString % BACKSLASH_N; QRegExp poRevDate(QStringLiteral("^ *PO-Revision-Date:.*")); for (it = headerList.begin(), found = false; it != headerList.end() && !found; ++it) { found = it->contains(poRevDate); if (found && forSaving) *it = temp; } if (Q_UNLIKELY(!found)) headerList.append(temp); temp = QStringLiteral("Project-Id-Version: ") % CatalogProjectId % BACKSLASH_N; //temp.replace( "@PACKAGE@", packageName()); QRegExp projectIdVer(QStringLiteral("^ *Project-Id-Version:.*")); for (it = headerList.begin(), found = false; it != headerList.end() && !found; ++it) { found = it->contains(projectIdVer); if (found && it->contains(QLatin1String("PACKAGE VERSION"))) *it = temp; } if (Q_UNLIKELY(!found)) headerList.append(temp); langCode = Project::instance()->isLoaded() ? Project::instance()->langCode() : Settings::defaultLangCode(); QString language; //initialized with preexisting value or later QString mailingList; //initialized with preexisting value or later static QMap langEnums; if (!langEnums.size()) for (int l = QLocale::Abkhazian; l <= QLocale::Akoose; ++l) langEnums[QLocale::languageToString((QLocale::Language)l)] = (QLocale::Language)l; static QRegExp langTeamRegExp(QStringLiteral("^ *Language-Team:.*")); for (it = headerList.begin(), found = false; it != headerList.end() && !found; ++it) { found = it->contains(langTeamRegExp); if (found) { //really parse header QRegExp re(QStringLiteral("^ *Language-Team: *(.*) *<([^>]*)>")); if (re.indexIn(*it) != -1) { if (langEnums.contains(re.cap(1).trimmed())) { language = re.cap(1).trimmed(); mailingList = re.cap(2).trimmed(); QList locales = QLocale::matchingLocales(langEnums.value(language), QLocale::AnyScript, QLocale::AnyCountry); if (locales.size()) langCode = locales.first().name().left(2); } } ait = it; } } if (language.isEmpty()) { language = QLocale::languageToString(QLocale(langCode).language()); if (language.isEmpty()) language = langCode; } if (mailingList.isEmpty() || belongsToProject) { if (Project::instance()->isLoaded()) mailingList = Project::instance()->mailingList(); else //if (mailingList.isEmpty()) mailingList = Settings::defaultMailingList(); } temp = QStringLiteral("Language-Team: ") % language % QStringLiteral(" <") % mailingList % QStringLiteral(">\\n"); if (Q_LIKELY(found)) (*ait) = temp; else headerList.append(temp); static QRegExp langCodeRegExp(QStringLiteral("^ *Language: *([^ \\\\]*)")); temp = QStringLiteral("Language: ") % langCode % BACKSLASH_N; for (it = headerList.begin(), found = false; it != headerList.end() && !found; ++it) { found = (langCodeRegExp.indexIn(*it) != -1); if (found && langCodeRegExp.cap(1).isEmpty()) *it = temp; //if (found) qCWarning(LOKALIZE_LOG)<<"got explicit lang code:"<contains(ctRe); if (found) *it = temp; } if (Q_UNLIKELY(!found)) headerList.append(temp); temp = QStringLiteral("Content-Transfer-Encoding: 8bit\\n"); QRegExp cteRe(QStringLiteral("^ *Content-Transfer-Encoding:.*")); for (it = headerList.begin(), found = false; it != headerList.end() && !found; ++it) found = it->contains(cteRe); if (!found) headerList.append(temp); // ensure MIME-Version header temp = QStringLiteral("MIME-Version: 1.0\\n"); QRegExp mvRe(QStringLiteral("^ *MIME-Version:")); for (it = headerList.begin(), found = false; it != headerList.end() && !found; ++it) { found = it->contains(mvRe); if (found) *it = temp; } if (Q_UNLIKELY(!found)) headerList.append(temp); //qCDebug(LOKALIZE_LOG)<<"testing for GNUPluralForms"; // update plural form header QRegExp pfRe(QStringLiteral("^ *Plural-Forms:")); for (it = headerList.begin(), found = false; it != headerList.end() && !found; ++it) found = it->contains(pfRe); if (found) { --it; //qCDebug(LOKALIZE_LOG)<<"GNUPluralForms found"; int num = numberOfPluralFormsFromHeader(header); if (!num) { if (generatedFromDocbook) num = 1; else { qCDebug(LOKALIZE_LOG) << "No plural form info in header, using project-defined one" << langCode; QString t = GNUPluralForms(langCode); //qCWarning(LOKALIZE_LOG)<<"generated: " << t; if (!t.isEmpty()) { static QRegExp pf(QStringLiteral("^ *Plural-Forms:\\s*nplurals.*\\\\n")); pf.setMinimal(true); temp = QStringLiteral("Plural-Forms: %1\\n").arg(t); it->replace(pf, temp); num = numberOfPluralFormsFromHeader(temp); } else { qCWarning(LOKALIZE_LOG) << "no... smth went wrong :(\ncheck your gettext install"; num = 2; } } } numberOfPluralForms = num; } else if (!generatedFromDocbook) { //qCDebug(LOKALIZE_LOG)<<"generating GNUPluralForms"<contains(xgRe); if (found) *it = temp; } if (Q_UNLIKELY(!found)) headerList.append(temp); //m_header.setMsgstr( headerList.join( "\n" ) ); header = headerList.join(QStringLiteral("\n")); //END header itself //BEGIN comment = description, copyrights // U+00A9 is the Copyright sign QRegExp fsfc(QStringLiteral("^# *Copyright (\\(C\\)|\\x00a9).*Free Software Foundation, Inc")); for (it = commentList.begin(), found = false; it != commentList.end() && !found; ++it) { found = it->contains(fsfc) ; if (found) it->replace(QStringLiteral("YEAR"), cLocale.toString(QDate::currentDate(), QStringLiteral("yyyy"))); } /* if( saveOptions.FSFCopyright == ProjectSettingsBase::Update ) { //update years QString cy = cLocale.toString(QDate::currentDate(), "yyyy"); if( !it->contains( QRegExp(cy)) ) // is the year already included? { int index = it->lastIndexOf( QRegExp("[\\d]+[\\d\\-, ]*") ); if( index == -1 ) { KMessageBox::information(0,i18n("Free Software Foundation Copyright does not contain any year. " "It will not be updated.")); } else { it->insert(index+1, QString(", ")+cy); } } }*/ #if 0 if ((!usePrefs || saveOptions.updateDescription) && (!saveOptions.descriptionString.isEmpty())) { temp = "# " + saveOptions.descriptionString; temp.replace("@PACKAGE@", packageName()); temp.replace("@LANGUAGE@", identityOptions.languageName); temp = temp.trimmed(); // The description strings has often buggy variants already in the file, these must be removed QString regexpstr = "^#\\s+" + QRegExp::escape(saveOptions.descriptionString.trimmed()) + "\\s*$"; regexpstr.replace("@PACKAGE@", ".*"); regexpstr.replace("@LANGUAGE@", ".*"); //qCDebug(LOKALIZE_LOG) << "REGEXPSTR: " << regexpstr; QRegExp regexp(regexpstr); // The buggy variants exist in English too (of a time before KBabel got a translation for the corresponding language) QRegExp regexpUntranslated("^#\\s+translation of .* to .*\\s*$"); qCDebug(LOKALIZE_LOG) << "Temp is '" << temp << "'"; found = false; bool foundTemplate = false; it = commentList.begin(); while (it != commentList.end()) { qCDebug(LOKALIZE_LOG) << "testing '" << (*it) << "'"; bool deleteItem = false; if ((*it) == temp) { qCDebug(LOKALIZE_LOG) << "Match "; if (found) deleteItem = true; else found = true; } else if (regexp.indexIn(*it) >= 0) { // We have a similar (translated) string (from another project or another language (perhaps typos)). Remove it. deleteItem = true; } else if (regexpUntranslated.indexIn(*it) >= 0) { // We have a similar (untranslated) string (from another project or another language (perhaps typos)). Remove it. deleteItem = true; } else if ((*it) == "# SOME DESCRIPTIVE TITLE.") { // We have the standard title placeholder, remove it deleteItem = true; } if (deleteItem) it = commentList.erase(it); else ++it; } if (!found) commentList.prepend(temp); } #endif // qCDebug(LOKALIZE_LOG) << "HEADER COMMENT: " << commentList; /* if ( (!usePrefs || saveOptions.updateTranslatorCopyright) && ( ! identityOptions->readEntry("authorName","").isEmpty() ) && ( ! identityOptions->readEntry("Email","").isEmpty() ) ) // An email address can be used as ersatz of a name {*/ // return; QStringList foundAuthors; temp = QStringLiteral("# ") % authorNameEmail % QStringLiteral(", ") % cLocale.toString(QDate::currentDate(), QStringLiteral("yyyy")) % '.'; // ### TODO: it would be nice if the entry could start with "COPYRIGHT" and have the "(C)" symbol (both not mandatory) QRegExp regexpAuthorYear(QStringLiteral("^#.*(<.+@.+>)?,\\s*([\\d]+[\\d\\-, ]*|YEAR)")); QRegExp regexpYearAlone(QStringLiteral("^# , \\d{4}.?\\s*$")); if (commentList.isEmpty()) { commentList.append(temp); commentList.append(QString()); } else { it = commentList.begin(); while (it != commentList.end()) { bool deleteItem = false; if (it->indexOf(QLatin1String("copyright"), 0, Qt::CaseInsensitive) != -1) { // We have a line with a copyright. It should not be moved. } else if (it->contains(QRegExp(QStringLiteral("#, *fuzzy")))) deleteItem = true; else if (it->contains(regexpYearAlone)) { // We have found a year number that is preceded by a comma. // That is typical of KBabel 1.10 (and earlier?) when there is neither an author name nor an email // Remove the entry deleteItem = true; } else if (it->contains(QLatin1String("# FIRST AUTHOR , YEAR."))) deleteItem = true; else if (it->contains(QLatin1String("# SOME DESCRIPTIVE TITLE"))) deleteItem = true; else if (it->contains(regexpAuthorYear)) { // email address followed by year if (!foundAuthors.contains((*it))) { // The author line is new (and not a duplicate), so add it to the author line list foundAuthors.append((*it)); } // Delete also non-duplicated entry, as now all what is needed will be processed in foundAuthors deleteItem = true; } if (deleteItem) it = commentList.erase(it); else ++it; } if (!foundAuthors.isEmpty()) { found = false; bool foundAuthor = false; const QString cy = cLocale.toString(QDate::currentDate(), QStringLiteral("yyyy")); ait = foundAuthors.end(); for (it = foundAuthors.begin() ; it != foundAuthors.end(); ++it) { if (it->contains(Settings::authorName()) || it->contains(Settings::authorEmail())) { foundAuthor = true; if (it->contains(cy)) found = true; else ait = it; } } if (!found) { if (!foundAuthor) foundAuthors.append(temp); else if (ait != foundAuthors.end()) { //update years const int index = (*ait).lastIndexOf(QRegExp(QStringLiteral("[\\d]+[\\d\\-, ]*"))); if (index == -1) (*ait) += QStringLiteral(", ") % cy; else ait->insert(index + 1, QStringLiteral(", ") % cy); } else qCDebug(LOKALIZE_LOG) << "INTERNAL ERROR: author found but iterator dangling!"; } } else foundAuthors.append(temp); foreach (QString author, foundAuthors) { // ensure dot at the end of copyright if (!author.endsWith(QLatin1Char('.'))) author += QLatin1Char('.'); commentList.append(author); } } //m_header.setComment( commentList.join( "\n" ) ); comment = commentList.join(QStringLiteral("\n")); //END comment = description, copyrights } QString fullUserName();// defined in helpers.cpp bool askAuthorInfoIfEmpty() { if (QThread::currentThread() == qApp->thread()) { if (Settings::authorName().isEmpty()) { bool ok; QString contact = QInputDialog::getText( SettingsController::instance()->mainWindowPtr(), i18nc("@window:title", "Author name missing"), i18n("Your name:"), QLineEdit::Normal, fullUserName(), &ok); -#ifndef NOKDE Settings::self()->authorNameItem()->setValue(ok ? contact : fullUserName()); Settings::self()->save(); -#else - Settings::self()->setAuthorName(ok ? contact : fullUserName()); -#endif } if (Settings::authorEmail().isEmpty()) { bool ok; QString email = QInputDialog::getText( SettingsController::instance()->mainWindowPtr(), i18nc("@window:title", "Author email missing"), i18n("Your email:"), QLineEdit::Normal, QString(), &ok); if (ok) { -#ifndef NOKDE Settings::self()->authorEmailItem()->setValue(email); Settings::self()->save(); -#else - Settings::self()->setAuthorEmail(email); -#endif } } } return !Settings::authorName().isEmpty() && !Settings::authorEmail().isEmpty(); } diff --git a/src/catalog/pos.cpp b/src/catalog/pos.cpp index 46360e9..5a9cfb9 100644 --- a/src/catalog/pos.cpp +++ b/src/catalog/pos.cpp @@ -1,154 +1,152 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007 by Nick Shaforostoff 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) any later version. 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. **************************************************************************** */ #include "pos.h" #include "catalog.h" bool switchPrev(Catalog*& catalog, DocPosition& pos, int parts) { bool switchEntry = false; bool switchCommentIndex = false; if (pos.part == DocPosition::Comment) switchCommentIndex = true; else if (pos.part == DocPosition::Target) { if (parts & DocPosition::Source) pos.part = DocPosition::Source; switchEntry = !(parts & DocPosition::Source); } else if (pos.part == DocPosition::Source) switchEntry = true; bool skipCommentThisTime = false; if (switchCommentIndex) { if (pos.form) pos.form--; switchEntry = pos.form; //pos.form is zero again skipCommentThisTime = pos.form; } if (!switchEntry) return true; if (Q_UNLIKELY(pos.form > 0 && catalog->isPlural(pos.entry))) pos.form--; else if (Q_UNLIKELY(pos.entry == 0)) return false; else { pos.entry--; pos.form = catalog->isPlural(pos.entry) * (catalog->numberOfPluralForms() - 1); } pos.offset = 0; if (parts & DocPosition::Comment && !skipCommentThisTime && pos.form == 0 && catalog->notes(pos).size()) { pos.part = DocPosition::Comment; pos.form = catalog->notes(pos).size() - 1; } else pos.part = DocPosition::Target; return true; } bool switchNext(Catalog*& catalog, DocPosition& pos, int parts) { bool switchEntry = false; bool switchCommentIndex = false; if (pos.part == DocPosition::Source) pos.part = DocPosition::Target; else if (pos.part == DocPosition::Target) { if (parts & DocPosition::Comment && pos.form == 0 && catalog->notes(pos).size()) pos.part = DocPosition::Comment; else switchEntry = true; } else if (pos.part == DocPosition::Comment) switchCommentIndex = true; if (switchCommentIndex) { pos.form++; if (catalog->notes(pos).size() == pos.form) { pos.form = 0; switchEntry = true; } } if (!switchEntry) return true; if (Q_UNLIKELY(pos.entry != -1 && pos.form + 1 < catalog->numberOfPluralForms() && catalog->isPlural(pos.entry))) pos.form++; else if (Q_UNLIKELY(pos.entry == catalog->numberOfEntries() - 1)) return false; else { pos.entry++; pos.form = 0; } pos.offset = 0; pos.part = (parts & DocPosition::Source) ? DocPosition::Source : DocPosition::Target; return true; } -#ifndef NOKDE #include const QDBusArgument &operator>>(const QDBusArgument &argument, DocPosition& pos) { int entry; int form; uint offset; argument.beginStructure(); argument >> entry >> form >> offset; argument.endStructure(); pos.entry = entry; pos.form = form; pos.offset = offset; return argument; } QDBusArgument &operator<<(QDBusArgument &argument, const DocPosition &pos) { int entry = pos.entry; int form = pos.form; uint offset = pos.offset; argument.beginStructure(); argument << entry << form << offset; argument.endStructure(); return argument; } -#endif diff --git a/src/cataloglistview/cataloglistview.cpp b/src/cataloglistview/cataloglistview.cpp index 32b642f..ea9409a 100644 --- a/src/cataloglistview/cataloglistview.cpp +++ b/src/cataloglistview/cataloglistview.cpp @@ -1,317 +1,315 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2009 by Nick Shaforostoff 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 "cataloglistview.h" #include "lokalize_debug.h" #include "catalogmodel.h" #include "catalog.h" #include "project.h" #include "prefs.h" #include "headerviewmenu.h" #include #include #include #include #include #include #include #include #include #include #include -#include -#ifndef NOKDE -#include -#endif +#include +#include class CatalogTreeView: public QTreeView { public: CatalogTreeView(QWidget * parent) : QTreeView(parent) {} ~CatalogTreeView() {} protected: void keyReleaseEvent(QKeyEvent *e) { if (e->key() == Qt::Key_Return && currentIndex().isValid()) { emit clicked(currentIndex()); e->accept(); } else { QTreeView::keyReleaseEvent(e); } } }; CatalogView::CatalogView(QWidget* parent, Catalog* catalog) : QDockWidget(i18nc("@title:window aka Message Tree", "Translation Units"), parent) , m_browser(new CatalogTreeView(this)) , m_lineEdit(new QLineEdit(this)) , m_model(new CatalogTreeModel(this, catalog)) , m_proxyModel(new CatalogTreeFilterModel(this)) { setObjectName(QStringLiteral("catalogTreeView")); QWidget* w = new QWidget(this); QVBoxLayout* layout = new QVBoxLayout(w); layout->setContentsMargins(0, 0, 0, 0); QHBoxLayout* l = new QHBoxLayout; l->setContentsMargins(0, 0, 0, 0); l->setSpacing(0); layout->addLayout(l); m_lineEdit->setClearButtonEnabled(true); m_lineEdit->setPlaceholderText(i18n("Quick search...")); - m_lineEdit->setToolTip(i18nc("@info:tooltip", "Activated by Ctrl+L.") + " " + i18nc("@info:tooltip", "Accepts regular expressions")); + m_lineEdit->setToolTip(i18nc("@info:tooltip", "Activated by Ctrl+L.") + ' ' + i18nc("@info:tooltip", "Accepts regular expressions")); connect(m_lineEdit, &QLineEdit::textChanged, this, &CatalogView::setFilterRegExp, Qt::QueuedConnection); // QShortcut* ctrlEsc=new QShortcut(QKeySequence(Qt::META+Qt::Key_Escape),this,SLOT(reset()),0,Qt::WidgetWithChildrenShortcut); QShortcut* esc = new QShortcut(QKeySequence(Qt::Key_Escape), this, 0, 0, Qt::WidgetWithChildrenShortcut); connect(esc, &QShortcut::activated, this, &CatalogView::escaped); QToolButton* btn = new QToolButton(w); btn->setPopupMode(QToolButton::InstantPopup); btn->setText(i18n("options")); //btn->setArrowType(Qt::DownArrow); btn->setMenu(new QMenu(this)); m_filterOptionsMenu = btn->menu(); connect(m_filterOptionsMenu, &QMenu::aboutToShow, this, &CatalogView::fillFilterOptionsMenu); connect(m_filterOptionsMenu, &QMenu::triggered, this, &CatalogView::filterOptionToggled); l->addWidget(m_lineEdit); l->addWidget(btn); layout->addWidget(m_browser); setTabOrder(m_lineEdit, btn); setTabOrder(btn, m_browser); setFocusProxy(m_lineEdit); setWidget(w); connect(m_browser, &CatalogTreeView::clicked, this, &CatalogView::slotItemActivated); m_browser->setRootIsDecorated(false); m_browser->setAllColumnsShowFocus(true); m_browser->setAlternatingRowColors(true); m_browser->viewport()->setBackgroundRole(QPalette::Background); #ifdef Q_OS_DARWIN QPalette p; p.setColor(QPalette::AlternateBase, p.color(QPalette::Background).darker(110)); p.setColor(QPalette::Highlight, p.color(QPalette::Background).darker(150)); m_browser->setPalette(p); #endif m_proxyModel->setSourceModel(m_model); m_browser->setModel(m_proxyModel); m_browser->setColumnWidth(0, m_browser->columnWidth(0) / 3); m_browser->setSortingEnabled(true); m_browser->sortByColumn(0, Qt::AscendingOrder); m_browser->setWordWrap(false); m_browser->setUniformRowHeights(true); m_browser->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); new HeaderViewMenuHandler(m_browser->header()); m_browser->header()->restoreState(readUiState("CatalogTreeViewState")); } CatalogView::~CatalogView() { writeUiState("CatalogTreeViewState", m_browser->header()->saveState()); } void CatalogView::setFocus() { QDockWidget::setFocus(); m_lineEdit->selectAll(); } void CatalogView::slotNewEntryDisplayed(const DocPosition& pos) { QModelIndex item = m_proxyModel->mapFromSource(m_model->index(pos.entry, 0)); m_browser->setCurrentIndex(item); m_browser->scrollTo(item/*,QAbstractItemView::PositionAtCenter*/); } void CatalogView::setFilterRegExp() { QString expr = m_lineEdit->text(); if (m_proxyModel->filterRegExp().pattern() != expr) m_proxyModel->setFilterRegExp(m_proxyModel->filerOptions()&CatalogTreeFilterModel::IgnoreAccel ? expr.remove(Project::instance()->accel()) : expr); } void CatalogView::slotItemActivated(const QModelIndex& idx) { emit gotoEntry(DocPosition(m_proxyModel->mapToSource(idx).row()), 0); } void CatalogView::filterOptionToggled(QAction* action) { if (action->data().isNull()) return; int opt = action->data().toInt(); if (opt > 0) m_proxyModel->setFilerOptions(m_proxyModel->filerOptions()^opt); else { if (opt != -1) opt = -opt - 2; m_proxyModel->setFilterKeyColumn(opt); } m_filterOptionsMenu->clear(); } void CatalogView::fillFilterOptionsMenu() { m_filterOptionsMenu->clear(); if (m_proxyModel->individualRejectFilterEnabled()) m_filterOptionsMenu->addAction(i18n("Reset individual filter"), this, SLOT(setEntriesFilteredOut())); bool extStates = m_model->catalog()->capabilities()&ExtendedStates; const char* const basicTitles[] = { I18N_NOOP("Case insensitive"), I18N_NOOP("Ignore accelerator marks"), I18N_NOOP("Ready"), I18N_NOOP("Non-ready"), I18N_NOOP("Non-empty"), I18N_NOOP("Empty"), I18N_NOOP("Changed since file open"), I18N_NOOP("Unchanged since file open"), I18N_NOOP("Same in sync file"), I18N_NOOP("Different in sync file"), I18N_NOOP("Not in sync file"), I18N_NOOP("Plural"), I18N_NOOP("Non-plural"), }; const char* const* extTitles = Catalog::states(); const char* const* alltitles[2] = {basicTitles, extTitles}; QMenu* basicMenu = m_filterOptionsMenu->addMenu(i18nc("@title:inmenu", "Basic")); QMenu* extMenu = extStates ? m_filterOptionsMenu->addMenu(i18nc("@title:inmenu", "States")) : 0; QMenu* allmenus[2] = {basicMenu, extMenu}; QMenu* columnsMenu = m_filterOptionsMenu->addMenu(i18nc("@title:inmenu", "Searchable column")); QAction* txt; txt = m_filterOptionsMenu->addAction(i18nc("@title:inmenu", "Resort and refilter on content change"), m_proxyModel, &CatalogTreeFilterModel::setDynamicSortFilter); txt->setCheckable(true); txt->setChecked(m_proxyModel->dynamicSortFilter()); for (int i = 0; (1 << i) < CatalogTreeFilterModel::MaxOption; ++i) { bool ext = (1 << i) >= CatalogTreeFilterModel::New; if (!extStates && ext) break; txt = allmenus[ext]->addAction(i18n(alltitles[ext][i - ext * FIRSTSTATEPOSITION])); txt->setData(1 << i); txt->setCheckable(true); txt->setChecked(m_proxyModel->filerOptions() & (1 << i)); if ((1 << i) == CatalogTreeFilterModel::IgnoreAccel) basicMenu->addSeparator(); } if (!extStates) m_filterOptionsMenu->addSeparator(); for (int i = -1; i < CatalogTreeModel::DisplayedColumnCount; ++i) { qCWarning(LOKALIZE_LOG) << i; txt = columnsMenu->addAction((i == -1) ? i18nc("@item:inmenu all columns", "All") : m_model->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString()); txt->setData(-i - 2); txt->setCheckable(true); txt->setChecked(m_proxyModel->filterKeyColumn() == i); } } void CatalogView::reset() { m_proxyModel->setFilterKeyColumn(-1); m_proxyModel->setFilerOptions(CatalogTreeFilterModel::AllStates); m_lineEdit->clear(); //emit gotoEntry(DocPosition(m_proxyModel->mapToSource(m_browser->currentIndex()).row()),0); slotItemActivated(m_browser->currentIndex()); } void CatalogView::setMergeCatalogPointer(MergeCatalog* pointer) { m_proxyModel->setMergeCatalogPointer(pointer); } int CatalogView::siblingEntryNumber(int step) { QModelIndex item = m_browser->currentIndex(); int lastRow = m_proxyModel->rowCount() - 1; if (!item.isValid()) { if (lastRow == -1) return -1; item = m_proxyModel->index((step == 1) ? 0 : lastRow, 0); m_browser->setCurrentIndex(item); } else { if (item.row() == ((step == -1) ? 0 : lastRow)) return -1; item = item.sibling(item.row() + step, 0); } return m_proxyModel->mapToSource(item).row(); } int CatalogView::nextEntryNumber() { return siblingEntryNumber(1); } int CatalogView::prevEntryNumber() { return siblingEntryNumber(-1); } static int edgeEntry(CatalogTreeFilterModel* m_proxyModel, int row) { if (!m_proxyModel->rowCount()) return -1; return m_proxyModel->mapToSource(m_proxyModel->index(row, 0)).row(); } int CatalogView::firstEntryNumber() { return edgeEntry(m_proxyModel, 0); } int CatalogView::lastEntryNumber() { return edgeEntry(m_proxyModel, m_proxyModel->rowCount() - 1); } void CatalogView::setEntryFilteredOut(int entry, bool filteredOut) { m_proxyModel->setEntryFilteredOut(entry, filteredOut); } void CatalogView::setEntriesFilteredOut(bool filteredOut) { show(); m_proxyModel->setEntriesFilteredOut(filteredOut); } diff --git a/src/cataloglistview/catalogmodel.cpp b/src/cataloglistview/catalogmodel.cpp index fbcb03e..f5ecea8 100644 --- a/src/cataloglistview/catalogmodel.cpp +++ b/src/cataloglistview/catalogmodel.cpp @@ -1,308 +1,297 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2014 by Nick Shaforostoff 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 "catalogmodel.h" #include "lokalize_debug.h" #include "catalog.h" #include "project.h" -#ifndef NOKDE #include -#endif #include #include #include #include #define DYNAMICFILTER_LIMIT 256 QVector CatalogTreeModel::m_fonts; CatalogTreeModel::CatalogTreeModel(QObject* parent, Catalog* catalog) : QAbstractItemModel(parent) , m_catalog(catalog) , m_ignoreAccel(true) { if (m_fonts.isEmpty()) { QVector fonts(4, QApplication::font()); fonts[1].setItalic(true); //fuzzy fonts[2].setBold(true); //modified fonts[3].setItalic(true); //fuzzy fonts[3].setBold(true); //modified m_fonts.reserve(4); for (int i = 0; i < 4; i++) m_fonts << fonts.at(i); } connect(catalog, &Catalog::signalEntryModified, this, &CatalogTreeModel::reflectChanges); connect(catalog, QOverload<>::of(&Catalog::signalFileLoaded), this, &CatalogTreeModel::fileLoaded); } QModelIndex CatalogTreeModel::index(int row, int column, const QModelIndex& /*parent*/) const { return createIndex(row, column); } QModelIndex CatalogTreeModel::parent(const QModelIndex& /*index*/) const { return QModelIndex(); } int CatalogTreeModel::columnCount(const QModelIndex& parent) const { Q_UNUSED(parent); return DisplayedColumnCount; } void CatalogTreeModel::fileLoaded() { beginResetModel(); endResetModel(); } void CatalogTreeModel::reflectChanges(DocPosition pos) { emit dataChanged(index(pos.entry, 0), index(pos.entry, DisplayedColumnCount - 1)); #if 0 I disabled dynamicSortFilter function //lazy sorting/filtering if (rowCount() < DYNAMICFILTER_LIMIT || m_prevChanged != pos) { qCWarning(LOKALIZE_LOG) << "first dataChanged emitment" << pos.entry; emit dataChanged(index(pos.entry, 0), index(pos.entry, DisplayedColumnCount - 1)); if (!(rowCount() < DYNAMICFILTER_LIMIT)) { qCWarning(LOKALIZE_LOG) << "second dataChanged emitment" << m_prevChanged.entry; emit dataChanged(index(m_prevChanged.entry, 0), index(m_prevChanged.entry, DisplayedColumnCount - 1)); } } m_prevChanged = pos; #endif } int CatalogTreeModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; return m_catalog->numberOfEntries(); } QVariant CatalogTreeModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const { if (role != Qt::DisplayRole) return QVariant(); switch (section) { case Key: return i18nc("@title:column", "Entry"); case Source: return i18nc("@title:column Original text", "Source"); case Target: return i18nc("@title:column Text in target language", "Target"); case Notes: return i18nc("@title:column", "Notes"); case Context: return i18nc("@title:column", "Context"); case TranslationStatus: return i18nc("@title:column", "Translation Status"); } return QVariant(); } QVariant CatalogTreeModel::data(const QModelIndex& index, int role) const { if (m_catalog->numberOfEntries() <= index.row()) return QVariant(); if (role == Qt::SizeHintRole) { //no need to cache because of uniform row heights return QFontMetrics(QApplication::font()).size(Qt::TextSingleLine, QString::fromLatin1(" ")); } else if (role == Qt::FontRole/* && index.column()==Target*/) { bool fuzzy = !m_catalog->isApproved(index.row()); bool modified = m_catalog->isModified(index.row()); return m_fonts.at(fuzzy * 1 | modified * 2); } else if (role == Qt::ForegroundRole) { -#ifndef NOKDE if (m_catalog->isBookmarked(index.row())) { static KColorScheme colorScheme(QPalette::Normal); return colorScheme.foreground(KColorScheme::LinkText); } if (m_catalog->isObsolete(index.row())) { static KColorScheme colorScheme(QPalette::Normal); return colorScheme.foreground(KColorScheme::InactiveText); } -#else - if (m_catalog->isBookmarked(index.row())) { - return QApplication::palette().link(); - } - if (m_catalog->isObsolete(index.row())) { - return QApplication::palette().brightText(); - } -#endif } else if (role == Qt::UserRole) { switch (index.column()) { case TranslationStatus: return m_catalog->isApproved(index.row()); case IsEmpty: return m_catalog->isEmpty(index.row()); case State: return int(m_catalog->state(index.row())); case IsModified: return m_catalog->isModified(index.row()); case IsPlural: return m_catalog->isPlural(index.row()); default: role = Qt::DisplayRole; } } else if (role == StringFilterRole) { //exclude UI strings if (index.column() >= TranslationStatus) return QVariant(); else if (index.column() == Source || index.column() == Target) { QString str = index.column() == Source ? m_catalog->msgidWithPlurals(index.row()) : m_catalog->msgstrWithPlurals(index.row()); return m_ignoreAccel ? str.remove(Project::instance()->accel()) : str; } role = Qt::DisplayRole; } if (role != Qt::DisplayRole) return QVariant(); switch (index.column()) { case Key: return index.row() + 1; case Source: return m_catalog->msgidWithPlurals(index.row()); case Target: return m_catalog->msgstrWithPlurals(index.row()); case Notes: { QString result; foreach (const Note ¬e, m_catalog->notes(index.row())) result += note.content; return result; } case Context: return m_catalog->context(index.row()); case TranslationStatus: static QString statuses[] = {i18nc("@info:status 'non-fuzzy' in gettext terminology", "Ready"), i18nc("@info:status 'fuzzy' in gettext terminology", "Needs review"), i18nc("@info:status", "Untranslated") }; if (m_catalog->isEmpty(index.row())) return statuses[2]; return statuses[!m_catalog->isApproved(index.row())]; } return QVariant(); } CatalogTreeFilterModel::CatalogTreeFilterModel(QObject* parent) : QSortFilterProxyModel(parent) , m_filerOptions(AllStates) , m_individualRejectFilterEnable(false) , m_mergeCatalog(NULL) { setFilterKeyColumn(-1); setFilterCaseSensitivity(Qt::CaseInsensitive); setFilterRole(CatalogTreeModel::StringFilterRole); setDynamicSortFilter(false); } void CatalogTreeFilterModel::setSourceModel(QAbstractItemModel* sourceModel) { QSortFilterProxyModel::setSourceModel(sourceModel); connect(sourceModel, &QAbstractItemModel::modelReset, this, QOverload<>::of(&CatalogTreeFilterModel::setEntriesFilteredOut)); setEntriesFilteredOut(false); } void CatalogTreeFilterModel::setEntriesFilteredOut() { return setEntriesFilteredOut(false); } void CatalogTreeFilterModel::setEntriesFilteredOut(bool filteredOut) { m_individualRejectFilter.fill(filteredOut, sourceModel()->rowCount()); m_individualRejectFilterEnable = filteredOut; invalidateFilter(); } void CatalogTreeFilterModel::setEntryFilteredOut(int entry, bool filteredOut) { // if (entry>=m_individualRejectFilter.size()) // sourceModelReset(); m_individualRejectFilter[entry] = filteredOut; m_individualRejectFilterEnable = true; invalidateFilter(); } void CatalogTreeFilterModel::setFilerOptions(int o) { m_filerOptions = o; setFilterCaseSensitivity(o & CaseInsensitive ? Qt::CaseInsensitive : Qt::CaseSensitive); static_cast(sourceModel())->setIgnoreAccel(o & IgnoreAccel); invalidateFilter(); } bool CatalogTreeFilterModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const { int filerOptions = m_filerOptions; bool accepts = true; if (bool(filerOptions & Ready) != bool(filerOptions & NotReady)) { bool ready = sourceModel()->index(source_row, CatalogTreeModel::TranslationStatus, source_parent).data(Qt::UserRole).toBool(); accepts = (ready == bool(filerOptions & Ready) || ready != bool(filerOptions & NotReady)); } if (accepts && bool(filerOptions & NonEmpty) != bool(filerOptions & Empty)) { bool untr = sourceModel()->index(source_row, CatalogTreeModel::IsEmpty, source_parent).data(Qt::UserRole).toBool(); accepts = (untr == bool(filerOptions & Empty) || untr != bool(filerOptions & NonEmpty)); } if (accepts && bool(filerOptions & Modified) != bool(filerOptions & NonModified)) { bool modified = sourceModel()->index(source_row, CatalogTreeModel::IsModified, source_parent).data(Qt::UserRole).toBool(); accepts = (modified == bool(filerOptions & Modified) || modified != bool(filerOptions & NonModified)); } if (accepts && bool(filerOptions & Plural) != bool(filerOptions & NonPlural)) { bool modified = sourceModel()->index(source_row, CatalogTreeModel::IsPlural, source_parent).data(Qt::UserRole).toBool(); accepts = (modified == bool(filerOptions & Plural) || modified != bool(filerOptions & NonPlural)); } // These are the possible sync options of a row: // * SameInSync: The sync file contains a row with the same msgid and the same msgstr. // * DifferentInSync: The sync file contains a row with the same msgid and different msgstr. // * NotInSync: The sync file does not contain any row with the same msgid. // // The code below takes care of filtering rows when any of those options is not checked. // const int mask = (SameInSync | DifferentInSync | NotInSync); if (accepts && m_mergeCatalog && (filerOptions & mask) && (filerOptions & mask) != mask) { bool isPresent = m_mergeCatalog->isPresent(source_row); bool isDifferent = m_mergeCatalog->isDifferent(source_row); accepts = ! ((isPresent && !isDifferent && !bool(filerOptions & SameInSync)) || (isPresent && isDifferent && !bool(filerOptions & DifferentInSync)) || (!isPresent && !bool(filerOptions & NotInSync)) ); } if (accepts && (filerOptions & STATES) != STATES) { int state = sourceModel()->index(source_row, CatalogTreeModel::State, source_parent).data(Qt::UserRole).toInt(); accepts = (filerOptions & (1 << (state + FIRSTSTATEPOSITION))); } accepts = accepts && !(m_individualRejectFilterEnable && source_row < m_individualRejectFilter.size() && m_individualRejectFilter.at(source_row)); return accepts && QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); } void CatalogTreeFilterModel::setMergeCatalogPointer(MergeCatalog* pointer) { m_mergeCatalog = pointer; } diff --git a/src/common/fastsizehintitemdelegate.cpp b/src/common/fastsizehintitemdelegate.cpp index 9b02903..5f9b6bc 100644 --- a/src/common/fastsizehintitemdelegate.cpp +++ b/src/common/fastsizehintitemdelegate.cpp @@ -1,146 +1,134 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2012 by Nick Shaforostoff 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 "fastsizehintitemdelegate.h" #include #include #include #include FastSizeHintItemDelegate::FastSizeHintItemDelegate(QObject *parent, const QVector& slc, const QVector& rtc) : QItemDelegate(parent) , singleLineColumns(slc) , richTextColumns(rtc) -#ifndef NOKDE , activeScheme(QPalette::Active, KColorScheme::View) -#endif {} void FastSizeHintItemDelegate::reset() { cache.clear(); } QSize FastSizeHintItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { int lineCount = 1; int nPos = 20; int column = qMax(index.column(), 0); if (!singleLineColumns.at(column)) { QString text = index.data().toString(); nPos = text.indexOf('\n'); if (nPos == -1) nPos = text.size(); else lineCount += text.count('\n'); } static QFontMetrics metrics(option.font); return QSize(metrics.averageCharWidth() * nPos, metrics.height() * lineCount); } void FastSizeHintItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { painter->save(); painter->setClipping(true); painter->setClipRect(option.rect); QBrush bgBrush; -#ifndef NOKDE const KColorScheme& scheme = activeScheme; if (option.state & QStyle::State_MouseOver) bgBrush = scheme.background(KColorScheme::LinkBackground); else if (index.row() % 2) bgBrush = scheme.background(KColorScheme::AlternateBackground); else bgBrush = scheme.background(KColorScheme::NormalBackground); -#else - static QPalette p; - if (option.state & QStyle::State_MouseOver) - bgBrush = p.highlight(); - else if (index.row() % 2) - bgBrush = p.alternateBase(); - else - bgBrush = p.base(); -#endif painter->fillRect(option.rect, bgBrush); painter->setClipRect(option.rect.adjusted(0, 0, -2, 0)); //painter->setFont(option.font); RowColumnUnion rc; rc.index.row = index.row(); rc.index.column = index.column(); //TMDBModel* m=static_cast(index.model()); if (!cache.contains(rc.v)) { QString text = index.data(FastSizeHintItemDelegate::HtmlDisplayRole).toString(); cache.insert(rc.v, new QStaticText(text)); QTextOption textOption = cache.object(rc.v)->textOption(); textOption.setWrapMode(QTextOption::NoWrap); cache.object(rc.v)->setTextOption(textOption); cache.object(rc.v)->setTextFormat(richTextColumns.at(index.column()) ? Qt::RichText : Qt::PlainText); } int rectWidth = option.rect.width(); QStaticText* staticText = cache.object(rc.v); //staticText->setTextWidth(rectWidth-4); QPoint textStartPoint = option.rect.topLeft(); textStartPoint.rx() += 2; painter->drawStaticText(textStartPoint, *staticText); if (staticText->size().width() <= rectWidth - 4) { painter->restore(); return; } painter->setPen(bgBrush.color()); QPoint p1 = option.rect.topRight(); QPoint p2 = option.rect.bottomRight(); int limit = qMin(8, rectWidth - 2); int i = limit; while (--i > 0) { painter->setOpacity(float(i) / limit); painter->drawLine(p1, p2); p1.rx()--; p2.rx()--; } painter->restore(); } QString convertToHtml(QString str, bool italics) { /* if (str.isEmpty()) return str; */ str = Qt::convertFromPlainText(str); //FIXME use another routine (this has bugs) if (italics) str = "

" % QString::fromRawData(str.unicode() + 3, str.length() - 3 - 4) % "

"; return str; } diff --git a/src/common/fastsizehintitemdelegate.h b/src/common/fastsizehintitemdelegate.h index c4b2f80..afe363e 100644 --- a/src/common/fastsizehintitemdelegate.h +++ b/src/common/fastsizehintitemdelegate.h @@ -1,81 +1,77 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2012 by Nick Shaforostoff 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 FASTSIZEHINTITEMDELEGATE_H #define FASTSIZEHINTITEMDELEGATE_H #include #include #include -#ifndef NOKDE #include -#endif QString convertToHtml(QString string, bool italics = false); /** * remember to connect appropriate signals to reset slot * for delegate to have actual cache * * @author Nick Shaforostoff */ class FastSizeHintItemDelegate: public QItemDelegate { Q_OBJECT public: enum Roles { HtmlDisplayRole = Qt::UserRole + 5 }; FastSizeHintItemDelegate(QObject *parent, const QVector& slc, const QVector& rtc); ~FastSizeHintItemDelegate() {} void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; public slots: void reset(); private: QVector singleLineColumns; QVector richTextColumns; struct RowColumn { short row: 16; short column: 16; }; union RowColumnUnion { RowColumn index; int v; }; mutable QCache cache; -#ifndef NOKDE KColorScheme activeScheme; -#endif }; #endif // FASTSIZEHINTITEMDELEGATE_H diff --git a/src/common/languagelistmodel.cpp b/src/common/languagelistmodel.cpp index e8480f6..8fd12f7 100644 --- a/src/common/languagelistmodel.cpp +++ b/src/common/languagelistmodel.cpp @@ -1,188 +1,167 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2009-2014 by Nick Shaforostoff 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 "languagelistmodel.h" -#ifndef NOKDE -//#include #include #include -#endif #include #include #include #include #include #include #include LanguageListModel* LanguageListModel::_instance = 0; LanguageListModel* LanguageListModel::_emptyLangInstance = 0; void LanguageListModel::cleanupLanguageListModel() { delete LanguageListModel::_instance; LanguageListModel::_instance = 0; delete LanguageListModel::_emptyLangInstance; LanguageListModel::_emptyLangInstance = 0; } LanguageListModel* LanguageListModel::instance() { if (_instance == 0) { _instance = new LanguageListModel(); qAddPostRoutine(LanguageListModel::cleanupLanguageListModel); } return _instance; } LanguageListModel* LanguageListModel::emptyLangInstance() { if (_emptyLangInstance == 0) _emptyLangInstance = new LanguageListModel(WithEmptyLang); return _emptyLangInstance; } LanguageListModel::LanguageListModel(ModelType type, QObject* parent) : QStringListModel(parent) , m_sortModel(new QSortFilterProxyModel(this)) -#ifndef NOKDE , m_systemLangList(new KConfig(QLatin1String("locale/kf5_all_languages"), KConfig::NoGlobals, QStandardPaths::GenericDataLocation)) -#endif { -#ifndef NOKDE setStringList(m_systemLangList->groupList()); -#else - QStringList ll; - QList allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry); - foreach (const QLocale& l, allLocales) - ll.append(l.name()); - ll = ll.toSet().toList(); - setStringList(ll); -#endif if (type == WithEmptyLang) insertRows(rowCount(), 1); #if 0 //KDE5PORT KIconLoader::global()->addExtraDesktopThemes(); #endif //qCWarning(LOKALIZE_LOG)<hasContext(KIconLoader::International); //qCDebug(LOKALIZE_LOG)<queryIconsByContext(KIconLoader::NoGroup,KIconLoader::International); m_sortModel->setSourceModel(this); m_sortModel->sort(0); } QVariant LanguageListModel::data(const QModelIndex& index, int role) const { if (role == Qt::DecorationRole) { -#if 0 //#ifndef NOKDE +#if 0 //# static QMap iconCache; QString langCode = stringList().at(index.row()); if (!iconCache.contains(langCode)) { QString code = QLocale(langCode).name(); QString path; if (code.contains('_')) code = QString::fromRawData(code.unicode() + 3, 2).toLower(); if (code != "C") { static const QString flagPath("l10n/%1/flag.png"); path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("locale/") + flagPath.arg(code)); } iconCache[langCode] = QIcon(path); } return iconCache.value(langCode); #endif } else if (role == Qt::DisplayRole) { const QString& code = stringList().at(index.row()); if (code.isEmpty()) return code; //qCDebug(LOKALIZE_LOG)<<"languageCodeToName"< displayNames(stringList().size()); if (displayNames.at(index.row()).length()) return displayNames.at(index.row()); -#ifndef NOKDE return QVariant::fromValue( displayNames[index.row()] = KConfigGroup(m_systemLangList, code).readEntry("Name") % QStringLiteral(" (") % code % ')'); -#else - QLocale l(code); -// if (l.language()==QLocale::C && code!="C") - return QVariant::fromValue( - displayNames[index.row()] = QLocale::languageToString(l.language()) % QStringLiteral(" (") % code % ')'); -#endif } return QStringListModel::data(index, role); } QFlags< Qt::ItemFlag > LanguageListModel::flags(const QModelIndex& index) const { return QStringListModel::flags(index); } int LanguageListModel::sortModelRowForLangCode(const QString& langCode) { return m_sortModel->mapFromSource(index(stringList().indexOf(langCode))).row(); } QString LanguageListModel::langCodeForSortModelRow(int row) { return stringList().at(m_sortModel->mapToSource(m_sortModel->index(row, 0)).row()); } #include "prefs.h" #include "project.h" #include #include #include #include #include #include QString getTargetLangCode(const QString& title, bool askUser) { if (!askUser) { if (Project::instance()->targetLangCode().length()) return Project::instance()->targetLangCode(); return QLocale::system().name(); } QDialog dlg(SettingsController::instance()->mainWindowPtr()); dlg.setWindowTitle(title); QHBoxLayout* l = new QHBoxLayout(&dlg); l->addWidget(new QLabel(i18n("Target language:"), &dlg)); QComboBox* lc = new QComboBox(&dlg); l->addWidget(lc); lc->setModel(LanguageListModel::instance()->sortModel()); lc->setCurrentIndex(LanguageListModel::instance()->sortModelRowForLangCode(Project::instance()->targetLangCode())); QDialogButtonBox* btn = new QDialogButtonBox(QDialogButtonBox::Ok, &dlg); l->addWidget(btn); QObject::connect(btn, &QDialogButtonBox::accepted, &dlg, &QDialog::accept); QObject::connect(btn, &QDialogButtonBox::rejected, &dlg, &QDialog::reject); dlg.show(); dlg.activateWindow(); //if we're called from another app if (!dlg.exec()) return Project::instance()->targetLangCode(); return LanguageListModel::instance()->langCodeForSortModelRow(lc->currentIndex()); } diff --git a/src/common/languagelistmodel.h b/src/common/languagelistmodel.h index e2c27a7..50e9a17 100644 --- a/src/common/languagelistmodel.h +++ b/src/common/languagelistmodel.h @@ -1,71 +1,65 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2009 by Nick Shaforostoff 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 LANGUAGELISTMODEL_H #define LANGUAGELISTMODEL_H #include class QSortFilterProxyModel; class KConfig; class LanguageListModel: public QStringListModel { enum ModelType { Default, WithEmptyLang }; public: static LanguageListModel* instance(); static LanguageListModel* emptyLangInstance(); private: static LanguageListModel * _instance; static LanguageListModel * _emptyLangInstance; static void cleanupLanguageListModel(); LanguageListModel(ModelType type = Default, QObject* parent = 0); QSortFilterProxyModel* m_sortModel; KConfig* m_systemLangList; public: QVariant data(const QModelIndex& index, int role) const; QFlags< Qt::ItemFlag > flags(const QModelIndex& index) const; QSortFilterProxyModel* sortModel() const { return m_sortModel; }; int sortModelRowForLangCode(const QString&); QString langCodeForSortModelRow(int); }; -QString getTargetLangCode(const QString& title, bool askUser = -#ifndef NOKDE - false -#else - true -#endif - ); +QString getTargetLangCode(const QString& title, bool askUser = false); #endif // LANGUAGELISTMODEL_H diff --git a/src/editortab.cpp b/src/editortab.cpp index 6680346..4d8d7dc 100644 --- a/src/editortab.cpp +++ b/src/editortab.cpp @@ -1,1811 +1,1767 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2014 by Nick Shaforostoff 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 "editortab.h" #include "xlifftextedit.h" #include "lokalize_debug.h" #include "actionproxy.h" #include "editorview.h" #include "catalog.h" #include "pos.h" #include "cmd.h" #include "completionstorage.h" -#ifndef NOKDE #define WEBQUERY_ENABLE -#endif //views #include "msgctxtview.h" #include "alttransview.h" #include "mergeview.h" #include "cataloglistview.h" #include "glossaryview.h" #ifdef WEBQUERY_ENABLE #include "webqueryview.h" #endif #include "tmview.h" #include "binunitsview.h" #include "phaseswindow.h" #include "projectlocal.h" #include "project.h" #include "prefs.h" #include "prefs_lokalize.h" #include "languagelistmodel.h" -#ifndef NOKDE #include #include #include #include #include #include -#endif - #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include EditorTab::EditorTab(QWidget* parent, bool valid) : LokalizeSubwindowBase2(parent) , m_project(Project::instance()) , m_catalog(new Catalog(this)) , m_view(new EditorView(this, m_catalog/*,new keyEventHandler(this,m_catalog)*/)) , m_pologyProcessInProgress(false) -#ifndef NOKDE , m_sonnetDialog(0) , m_spellcheckStartUndoIndex(0) , m_spellcheckStop(false) -#endif , m_currentIsApproved(true) , m_currentIsUntr(true) , m_fullPathShown(false) -#ifndef NOKDE , m_doReplaceCalled(false) , m_find(0) , m_replace(0) -#endif , m_syncView(0) , m_syncViewSecondary(0) -#ifndef NOKDE , m_valid(valid) , m_dbusId(-1) -#endif { //QTime chrono;chrono.start(); setAcceptDrops(true); setCentralWidget(m_view); setupStatusBar(); //--NOT called from initLater() ! setupActions(); - -#ifndef NOKDE dbusObjectPath(); -#endif connect(m_view, &EditorView::signalChanged, this, &EditorTab::msgStrChanged); msgStrChanged(); connect(SettingsController::instance(), &SettingsController::generalSettingsChanged, m_view, &EditorView::settingsChanged); connect(m_view->tabBar(), &QTabBar::currentChanged, this, &EditorTab::switchForm); connect(m_view, QOverload::of(&EditorView::gotoEntryRequested), this, QOverload::of(&EditorTab::gotoEntry)); connect(m_view, &EditorView::tmLookupRequested, this, &EditorTab::lookupSelectionInTranslationMemory); connect(this, &EditorTab::fileOpened, this, &EditorTab::indexWordsForCompletion, Qt::QueuedConnection); connect(m_catalog, &Catalog::signalFileAutoSaveFailed, this, &EditorTab::fileAutoSaveFailedWarning); //defer some work to make window appear earlier (~200 msec on my Core Duo) //QTimer::singleShot(0,this,SLOT(initLater())); //qCWarning(LOKALIZE_LOG)<isEmpty()) { emit fileAboutToBeClosed(); emit fileClosed(); emit fileClosed(currentFile()); } -#ifndef NOKDE ids.removeAll(m_dbusId); -#endif } void EditorTab::setupStatusBar() { statusBarItems.insert(ID_STATUS_CURRENT, i18nc("@info:status message entry", "Current: %1", 0)); statusBarItems.insert(ID_STATUS_TOTAL, i18nc("@info:status message entries", "Total: %1", 0)); statusBarItems.insert(ID_STATUS_FUZZY, i18nc("@info:status message entries\n'fuzzy' in gettext terminology", "Not ready: %1", 0)); statusBarItems.insert(ID_STATUS_UNTRANS, i18nc("@info:status message entries", "Untranslated: %1", 0)); statusBarItems.insert(ID_STATUS_ISFUZZY, QString()); connect(m_catalog, &Catalog::signalNumberOfFuzziesChanged, this, &EditorTab::numberOfFuzziesChanged); connect(m_catalog, &Catalog::signalNumberOfEmptyChanged, this, &EditorTab::numberOfUntranslatedChanged); } -#ifndef NOKDE void LokalizeSubwindowBase::reflectNonApprovedCount(int count, int total) { QString text = i18nc("@info:status message entries\n'fuzzy' in gettext terminology", "Not ready: %1", count); if (count && total) text += i18nc("percentages in statusbar", " (%1%)", int(100.0 * count / total)); statusBarItems.insert(ID_STATUS_FUZZY, text); } void LokalizeSubwindowBase::reflectUntranslatedCount(int count, int total) { QString text = i18nc("@info:status message entries", "Untranslated: %1", count); if (count && total) text += i18nc("percentages in statusbar", " (%1%)", int(100.0 * count / total)); statusBarItems.insert(ID_STATUS_UNTRANS, text); } -#endif void EditorTab::numberOfFuzziesChanged() { reflectNonApprovedCount(m_catalog->numberOfNonApproved(), m_catalog->numberOfEntries()); } void EditorTab::numberOfUntranslatedChanged() { reflectUntranslatedCount(m_catalog->numberOfUntranslated(), m_catalog->numberOfEntries()); } void EditorTab::setupActions() { //all operations that can be done after initial setup //(via QTimer::singleShot) go to initLater() setXMLFile(QStringLiteral("editorui.rc")); setUpdatedXMLFile(); QAction *action; KActionCollection* ac = actionCollection(); KActionCategory* actionCategory; KActionCategory* file = new KActionCategory(i18nc("@title actions category", "File"), ac); KActionCategory* nav = new KActionCategory(i18nc("@title actions category", "Navigation"), ac); KActionCategory* edit = new KActionCategory(i18nc("@title actions category", "Editing"), ac); KActionCategory* sync1 = new KActionCategory(i18n("Synchronization 1"), ac); KActionCategory* sync2 = new KActionCategory(i18n("Synchronization 2"), ac); KActionCategory* tm = new KActionCategory(i18n("Translation Memory"), ac); KActionCategory* glossary = new KActionCategory(i18nc("@title actions category", "Glossary"), ac); //KActionCategory* tools=new KActionCategory(i18nc("@title actions category","Tools"), ac); #ifndef Q_OS_DARWIN QLocale::Language systemLang = QLocale::system().language(); #endif //BEGIN dockwidgets int i = 0; QVector altactions(ALTTRANS_SHORTCUTS); Qt::Key altlist[ALTTRANS_SHORTCUTS] = { Qt::Key_1, Qt::Key_2, Qt::Key_3, Qt::Key_4, Qt::Key_5, Qt::Key_6, Qt::Key_7, Qt::Key_8, Qt::Key_9 }; QAction* altaction; for (i = 0; i < ALTTRANS_SHORTCUTS; ++i) { altaction = tm->addAction(QStringLiteral("alttrans_insert_%1").arg(i)); ac->setDefaultShortcut(altaction, QKeySequence(Qt::ALT + altlist[i])); altaction->setText(i18nc("@action:inmenu", "Insert alternate translation #%1", QString::number(i))); altactions[i] = altaction; } m_altTransView = new AltTransView(this, m_catalog, altactions); addDockWidget(Qt::BottomDockWidgetArea, m_altTransView); ac->addAction(QStringLiteral("showmsgiddiff_action"), m_altTransView->toggleViewAction()); connect(this, QOverload::of(&EditorTab::signalNewEntryDisplayed), m_altTransView, QOverload::of(&AltTransView::slotNewEntryDisplayed)); connect(m_altTransView, &AltTransView::textInsertRequested, m_view, &EditorView::insertTerm); connect(m_altTransView, &AltTransView::refreshRequested, m_view, QOverload<>::of(&EditorView::gotoEntry), Qt::QueuedConnection); connect(m_catalog, QOverload<>::of(&Catalog::signalFileLoaded), m_altTransView, &AltTransView::fileLoaded); m_syncView = new MergeView(this, m_catalog, true); addDockWidget(Qt::BottomDockWidgetArea, m_syncView); sync1->addAction(QStringLiteral("showmergeview_action"), m_syncView->toggleViewAction()); connect(this, QOverload::of(&EditorTab::signalNewEntryDisplayed), m_syncView, QOverload::of(&MergeView::slotNewEntryDisplayed)); connect(m_catalog, QOverload<>::of(&Catalog::signalFileLoaded), m_syncView, &MergeView::cleanup); connect(m_syncView, &MergeView::gotoEntry, this, QOverload::of(&EditorTab::gotoEntry)); m_syncViewSecondary = new MergeView(this, m_catalog, false); addDockWidget(Qt::BottomDockWidgetArea, m_syncViewSecondary); sync2->addAction(QStringLiteral("showmergeviewsecondary_action"), m_syncViewSecondary->toggleViewAction()); connect(this, QOverload::of(&EditorTab::signalNewEntryDisplayed), m_syncViewSecondary, QOverload::of(&MergeView::slotNewEntryDisplayed)); connect(m_catalog, QOverload<>::of(&Catalog::signalFileLoaded), m_syncViewSecondary, &MergeView::cleanup); connect(m_catalog, QOverload::of(&Catalog::signalFileLoaded), m_syncViewSecondary, QOverload::of(&MergeView::mergeOpen), Qt::QueuedConnection); connect(m_syncViewSecondary, &MergeView::gotoEntry, this, QOverload::of(&EditorTab::gotoEntry)); m_transUnitsView = new CatalogView(this, m_catalog); addDockWidget(Qt::LeftDockWidgetArea, m_transUnitsView); ac->addAction(QStringLiteral("showcatalogtreeview_action"), m_transUnitsView->toggleViewAction()); connect(this, QOverload::of(&EditorTab::signalNewEntryDisplayed), m_transUnitsView, QOverload::of(&CatalogView::slotNewEntryDisplayed)); connect(m_transUnitsView, &CatalogView::gotoEntry, this, QOverload::of(&EditorTab::gotoEntry)); connect(m_transUnitsView, &CatalogView::escaped, this, &EditorTab::setProperFocus); connect(m_syncView, &MergeView::mergeCatalogPointerChanged, m_transUnitsView, &CatalogView::setMergeCatalogPointer); m_notesView = new MsgCtxtView(this, m_catalog); addDockWidget(Qt::LeftDockWidgetArea, m_notesView); ac->addAction(QStringLiteral("showmsgctxt_action"), m_notesView->toggleViewAction()); connect(m_catalog, QOverload<>::of(&Catalog::signalFileLoaded), m_notesView, &MsgCtxtView::cleanup); connect(m_notesView, &MsgCtxtView::srcFileOpenRequested, this, &EditorTab::dispatchSrcFileOpenRequest); connect(m_view, &EditorView::signalChanged, m_notesView, &MsgCtxtView::removeErrorNotes); connect(m_notesView, &MsgCtxtView::escaped, this, &EditorTab::setProperFocus); action = edit->addAction(QStringLiteral("edit_addnote"), m_notesView, SLOT(addNoteUI())); //action->setShortcut(Qt::CTRL+glist[i]); action->setText(i18nc("@action:inmenu", "Add a note")); QVector tmactions_insert(TM_SHORTCUTS); QVector tmactions_remove(TM_SHORTCUTS); Qt::Key tmlist[TM_SHORTCUTS] = { Qt::Key_1, Qt::Key_2, Qt::Key_3, Qt::Key_4, Qt::Key_5, Qt::Key_6, Qt::Key_7, Qt::Key_8, Qt::Key_9, Qt::Key_0 }; QAction* tmaction; for (i = 0; i < TM_SHORTCUTS; ++i) { // action->setVisible(false); tmaction = tm->addAction(QStringLiteral("tmquery_insert_%1").arg(i)); ac->setDefaultShortcut(tmaction, QKeySequence(Qt::CTRL + tmlist[i])); tmaction->setText(i18nc("@action:inmenu", "Insert TM suggestion #%1", i + 1)); tmactions_insert[i] = tmaction; tmaction = tm->addAction(QStringLiteral("tmquery_remove_%1").arg(i)); ac->setDefaultShortcut(tmaction, QKeySequence(Qt::CTRL + Qt::ALT + tmlist[i])); tmaction->setText(i18nc("@action:inmenu", "Remove TM suggestion #%1", i + 1)); tmactions_remove[i] = tmaction; } #ifndef Q_OS_DARWIN if (systemLang == QLocale::Czech) { ac->setDefaultShortcuts(tmactions_insert[0], QList() << QKeySequence(Qt::CTRL + tmlist[0]) << QKeySequence(Qt::CTRL + Qt::Key_Plus)); ac->setDefaultShortcuts(tmactions_remove[0], QList() << QKeySequence(Qt::CTRL + Qt::ALT + tmlist[0]) << QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_Plus)); } #endif TM::TMView* _tmView = new TM::TMView(this, m_catalog, tmactions_insert, tmactions_remove); addDockWidget(Qt::BottomDockWidgetArea, _tmView); tm->addAction(QStringLiteral("showtmqueryview_action"), _tmView->toggleViewAction()); connect(_tmView, &TM::TMView::refreshRequested, m_view, QOverload<>::of(&EditorView::gotoEntry), Qt::QueuedConnection); connect(_tmView, &TM::TMView::refreshRequested, this, &EditorTab::msgStrChanged, Qt::QueuedConnection); connect(_tmView, &TM::TMView::textInsertRequested, m_view, &EditorView::insertTerm); connect(_tmView, &TM::TMView::fileOpenRequested, this, &EditorTab::fileOpenRequested); connect(this, &EditorTab::fileAboutToBeClosed, m_catalog, &Catalog::flushUpdateDBBuffer); connect(this, &EditorTab::signalNewEntryDisplayed, m_catalog, &Catalog::flushUpdateDBBuffer); connect(this, &EditorTab::signalNewEntryDisplayed, _tmView, QOverload::of(&TM::TMView::slotNewEntryDisplayed)); //do this after flushUpdateDBBuffer QVector gactions(GLOSSARY_SHORTCUTS); Qt::Key glist[GLOSSARY_SHORTCUTS] = { Qt::Key_E, Qt::Key_H, // Qt::Key_G, // Qt::Key_I, // Qt::Key_J, // Qt::Key_K, Qt::Key_K, Qt::Key_P, Qt::Key_N, // Qt::Key_Q, // Qt::Key_R, // Qt::Key_U, // Qt::Key_V, // Qt::Key_W, // Qt::Key_X, Qt::Key_Y, // Qt::Key_Z, Qt::Key_BraceLeft, Qt::Key_BraceRight, Qt::Key_Semicolon, Qt::Key_Apostrophe }; QAction* gaction; // int i=0; for (i = 0; i < GLOSSARY_SHORTCUTS; ++i) { // action->setVisible(false); gaction = glossary->addAction(QStringLiteral("glossary_insert_%1").arg(i)); ac->setDefaultShortcut(gaction, QKeySequence(Qt::CTRL + glist[i])); gaction->setText(i18nc("@action:inmenu", "Insert term translation #%1", QString::number(i))); gactions[i] = gaction; } GlossaryNS::GlossaryView* _glossaryView = new GlossaryNS::GlossaryView(this, m_catalog, gactions); addDockWidget(Qt::BottomDockWidgetArea, _glossaryView); glossary->addAction(QStringLiteral("showglossaryview_action"), _glossaryView->toggleViewAction()); connect(this, &EditorTab::signalNewEntryDisplayed, _glossaryView, QOverload::of(&GlossaryNS::GlossaryView::slotNewEntryDisplayed)); connect(_glossaryView, &GlossaryNS::GlossaryView::termInsertRequested, m_view, &EditorView::insertTerm); gaction = glossary->addAction(QStringLiteral("glossary_define"), this, SLOT(defineNewTerm())); gaction->setText(i18nc("@action:inmenu", "Define new term")); _glossaryView->addAction(gaction); _glossaryView->setContextMenuPolicy(Qt::ActionsContextMenu); BinUnitsView* binUnitsView = new BinUnitsView(m_catalog, this); addDockWidget(Qt::BottomDockWidgetArea, binUnitsView); edit->addAction(QStringLiteral("showbinunitsview_action"), binUnitsView->toggleViewAction()); connect(m_view, &EditorView::binaryUnitSelectRequested, binUnitsView, &BinUnitsView::selectUnit); //#ifdef WEBQUERY_ENABLE #if 0 QVector wqactions(WEBQUERY_SHORTCUTS); Qt::Key wqlist[WEBQUERY_SHORTCUTS] = { Qt::Key_1, Qt::Key_2, Qt::Key_3, Qt::Key_4, Qt::Key_5, Qt::Key_6, Qt::Key_7, Qt::Key_8, Qt::Key_9, Qt::Key_0, }; QAction* wqaction; for (i = 0; i < WEBQUERY_SHORTCUTS; ++i) { // action->setVisible(false); wqaction = ac->addAction(QString("webquery_insert_%1").arg(i)); wqaction->setShortcut(Qt::CTRL + Qt::ALT + wqlist[i]); //wqaction->setShortcut(Qt::META+wqlist[i]); wqaction->setText(i18nc("@action:inmenu", "Insert WebQuery result #%1", i)); wqactions[i] = wqaction; } WebQueryView* _webQueryView = new WebQueryView(this, m_catalog, wqactions); addDockWidget(Qt::BottomDockWidgetArea, _webQueryView); ac->addAction(QStringLiteral("showwebqueryview_action"), _webQueryView->toggleViewAction()); connect(this, &EditorTab::signalNewEntryDisplayed, _webQueryView, SLOT(slotNewEntryDisplayed(DocPosition))); connect(_webQueryView, SIGNAL(textInsertRequested(QString)), m_view, SLOT(insertTerm(QString))); #endif //END dockwidgets actionCategory = file; // File action = file->addAction(KStandardAction::Save, this, SLOT(saveFile())); // action->setEnabled(false); // connect (m_catalog,SIGNAL(cleanChanged(bool)),action,SLOT(setDisabled(bool))); connect(m_catalog, &Catalog::cleanChanged, this, &EditorTab::setModificationSign); file->addAction(KStandardAction::SaveAs, this, SLOT(saveFileAs())); //action = KStandardAction::quit(qApp, SLOT(quit()), ac); //action->setText(i18nc("@action:inmenu","Close all Lokalize windows")); //KStandardAction::quit(kapp, SLOT(quit()), ac); //KStandardAction::quit(this, SLOT(deleteLater()), ac); #define ADD_ACTION_SHORTCUT_ICON(_name,_text,_shortcut,_icon)\ action = actionCategory->addAction(QStringLiteral(_name));\ action->setText(_text);\ action->setIcon(QIcon::fromTheme(QStringLiteral(_icon)));\ ac->setDefaultShortcut(action, QKeySequence( _shortcut )); #define ADD_ACTION_SHORTCUT(_name,_text,_shortcut)\ action = actionCategory->addAction(QStringLiteral(_name));\ action->setText(_text);\ ac->setDefaultShortcut(action, QKeySequence( _shortcut )); action = actionCategory->addAction(QStringLiteral("file_phases")); action->setText(i18nc("@action:inmenu", "Phases...")); connect(action, &QAction::triggered, this, &EditorTab::openPhasesWindow); ADD_ACTION_SHORTCUT("file_wordcount", i18nc("@action:inmenu", "Word count"), Qt::CTRL + Qt::ALT + Qt::Key_C) connect(action, &QAction::triggered, this, &EditorTab::displayWordCount); ADD_ACTION_SHORTCUT("file_cleartarget", i18nc("@action:inmenu", "Clear all translated entries"), Qt::CTRL + Qt::ALT + Qt::Key_D) connect(action, &QAction::triggered, this, &EditorTab::clearTranslatedEntries); ADD_ACTION_SHORTCUT("file_pology", i18nc("@action:inmenu", "Launch the Pology command on this file"), Qt::CTRL + Qt::ALT + Qt::Key_P) action->setEnabled(Settings::self()->pologyEnabled()); connect(action, &QAction::triggered, this, &EditorTab::launchPology); ADD_ACTION_SHORTCUT("file_xliff2odf", i18nc("@action:inmenu", "Merge translation into OpenDocument"), Qt::CTRL + Qt::Key_Backslash) connect(action, &QAction::triggered, this, &EditorTab::mergeIntoOpenDocument); connect(this, &EditorTab::xliffFileOpened, action, &QAction::setVisible); action->setVisible(false); //Edit actionCategory = edit; action = edit->addAction(KStandardAction::Undo, this, SLOT(undo())); connect((const TranslationUnitTextEdit*)m_view->viewPort(), &TranslationUnitTextEdit::undoRequested, this, &EditorTab::undo); connect(m_catalog, &Catalog::canUndoChanged, action, &QAction::setEnabled); action->setEnabled(false); action = edit->addAction(KStandardAction::Redo, this, SLOT(redo())); connect((const TranslationUnitTextEdit*)m_view->viewPort(), &TranslationUnitTextEdit::redoRequested, this, &EditorTab::redo); connect(m_catalog, &Catalog::canRedoChanged, action, &QAction::setEnabled); action->setEnabled(false); action = nav->addAction(KStandardAction::Find, this, SLOT(find())); action = nav->addAction(KStandardAction::FindNext, this, SLOT(findNext())); action = nav->addAction(KStandardAction::FindPrev, this, SLOT(findPrev())); action->setText(i18nc("@action:inmenu", "Change searching direction")); action = edit->addAction(KStandardAction::Replace, this, SLOT(replace())); connect(m_view, &EditorView::findRequested, this, &EditorTab::find); connect(m_view, &EditorView::findNextRequested, this, QOverload<>::of(&EditorTab::findNext)); connect(m_view, &EditorView::replaceRequested, this, &EditorTab::replace); action = actionCategory->addAction(QStringLiteral("edit_approve"), new KToolBarPopupAction(QIcon::fromTheme(QStringLiteral("approved")), i18nc("@option:check whether message is marked as translated/reviewed/approved (depending on your role)", "Approved"), this)); ac->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_U)); action->setCheckable(true); connect(action, &QAction::triggered, m_view, &EditorView::toggleApprovement); connect(m_view, &EditorView::signalApprovedEntryDisplayed, this, &EditorTab::signalApprovedEntryDisplayed); connect(this, &EditorTab::signalApprovedEntryDisplayed, action, &QAction::setChecked); connect(this, &EditorTab::signalApprovedEntryDisplayed, this, &EditorTab::msgStrChanged, Qt::QueuedConnection); m_approveAction = action; -#ifdef NOKDE - QMenu* am = new QMenu(i18nc("@option:check whether message is marked as translated/reviewed/approved (depending on your role)", "State"), this); - action = am->menuAction(); - ac->addAction(QStringLiteral("edit_state"), action); -#endif m_stateAction = action; connect(Project::local(), &ProjectLocal::configChanged, this, &EditorTab::setApproveActionTitle); connect(m_catalog, &Catalog::activePhaseChanged, this, &EditorTab::setApproveActionTitle); connect(m_stateAction->menu(), &QMenu::aboutToShow, this, &EditorTab::showStatesMenu); connect(m_stateAction->menu(), &QMenu::triggered, this, &EditorTab::setState); action = actionCategory->addAction(QStringLiteral("edit_approve_go_fuzzyUntr")); action->setText(i18nc("@action:inmenu", "Approve and go to next")); connect(action, &QAction::triggered, this, &EditorTab::toggleApprovementGotoNextFuzzyUntr); m_approveAndGoAction = action; setApproveActionTitle(); action = actionCategory->addAction(QStringLiteral("edit_nonequiv"), m_view, SLOT(setEquivTrans(bool))); action->setText(i18nc("@action:inmenu", "Equivalent translation")); action->setCheckable(true); connect(this, &EditorTab::signalEquivTranslatedEntryDisplayed, action, &QAction::setChecked); #ifndef Q_OS_DARWIN int copyShortcut = Qt::CTRL + Qt::Key_Space; if (Q_UNLIKELY(systemLang == QLocale::Korean || systemLang == QLocale::Japanese || systemLang == QLocale::Chinese )) copyShortcut = Qt::ALT + Qt::Key_Space; #else int copyShortcut = Qt::META + Qt::Key_Space; #endif ADD_ACTION_SHORTCUT_ICON("edit_msgid2msgstr", i18nc("@action:inmenu", "Copy source to target"), copyShortcut, "msgid2msgstr") connect(action, &QAction::triggered, (const TranslationUnitTextEdit*)m_view->viewPort(), &TranslationUnitTextEdit::source2target); ADD_ACTION_SHORTCUT("edit_unwrap-target", i18nc("@action:inmenu", "Unwrap target"), Qt::CTRL + Qt::Key_I) connect(action, &QAction::triggered, m_view, QOverload<>::of(&EditorView::unwrap)); action = edit->addAction(QStringLiteral("edit_clear-target"), m_view->viewPort(), SLOT(removeTargetSubstring())); ac->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_D)); action->setText(i18nc("@action:inmenu", "Clear")); action = edit->addAction(QStringLiteral("edit_tagmenu"), m_view->viewPort(), SLOT(tagMenu())); ac->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_T)); action->setText(i18nc("@action:inmenu", "Insert Tag")); action = edit->addAction(QStringLiteral("edit_tagimmediate"), m_view->viewPort(), SLOT(tagImmediate())); ac->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_M)); action->setText(i18nc("@action:inmenu", "Insert Next Tag")); -#ifndef NOKDE action = edit->addAction(QStringLiteral("edit_completion"), m_view, SIGNAL(doExplicitCompletion())); ac->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_Space)); action->setText(i18nc("@action:inmenu", "Completion")); action = edit->addAction(QStringLiteral("edit_spellreplace"), m_view->viewPort(), SLOT(spellReplace())); ac->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_Equal)); action->setText(i18nc("@action:inmenu", "Replace with best spellcheck suggestion")); -#endif // action = ac->addAction("glossary_define",m_view,SLOT(defineNewTerm())); // action->setText(i18nc("@action:inmenu","Define new term")); // Go actionCategory = nav; action = nav->addAction(KStandardAction::Next, this, SLOT(gotoNext())); action->setText(i18nc("@action:inmenu entry", "&Next")); connect(this, &EditorTab::signalLastDisplayed, action, &QAction::setDisabled); connect((const TranslationUnitTextEdit*)m_view->viewPort(), &TranslationUnitTextEdit::gotoNextRequested, this, &EditorTab::gotoNext); action = nav->addAction(KStandardAction::Prior, this, SLOT(gotoPrev())); action->setText(i18nc("@action:inmenu entry", "&Previous")); connect(this, &EditorTab::signalFirstDisplayed, action, &QAction::setDisabled); connect((const TranslationUnitTextEdit*)m_view->viewPort(), &TranslationUnitTextEdit::gotoPrevRequested, this, &EditorTab::gotoPrev); action = nav->addAction(KStandardAction::FirstPage, this, SLOT(gotoFirst())); connect((const TranslationUnitTextEdit*)m_view->viewPort(), &TranslationUnitTextEdit::gotoFirstRequested, this, &EditorTab::gotoFirst); action->setText(i18nc("@action:inmenu", "&First Entry")); action->setShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_Home)); connect(this, &EditorTab::signalFirstDisplayed, action, &QAction::setDisabled); action = nav->addAction(KStandardAction::LastPage, this, SLOT(gotoLast())); connect((const TranslationUnitTextEdit*)m_view->viewPort(), &TranslationUnitTextEdit::gotoLastRequested, this, &EditorTab::gotoLast); action->setText(i18nc("@action:inmenu", "&Last Entry")); action->setShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_End)); connect(this, &EditorTab::signalLastDisplayed, action, &QAction::setDisabled); action = nav->addAction(KStandardAction::GotoPage, this, SLOT(gotoEntry())); ac->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_G)); action->setText(i18nc("@action:inmenu", "Entry by number")); ADD_ACTION_SHORTCUT_ICON("go_prev_fuzzy", i18nc("@action:inmenu\n'not ready' means 'fuzzy' in gettext terminology", "Previous non-empty but not ready"), Qt::CTRL + Qt::Key_PageUp, "prevfuzzy") connect(action, &QAction::triggered, this, &EditorTab::gotoPrevFuzzy); connect((const TranslationUnitTextEdit*)m_view->viewPort(), &TranslationUnitTextEdit::gotoPrevFuzzyRequested, this, &EditorTab::gotoPrevFuzzy); connect(this, &EditorTab::signalPriorFuzzyAvailable, action, &QAction::setEnabled); ADD_ACTION_SHORTCUT_ICON("go_next_fuzzy", i18nc("@action:inmenu\n'not ready' means 'fuzzy' in gettext terminology", "Next non-empty but not ready"), Qt::CTRL + Qt::Key_PageDown, "nextfuzzy") connect(action, &QAction::triggered, this, &EditorTab::gotoNextFuzzy); connect((const TranslationUnitTextEdit*)m_view->viewPort(), &TranslationUnitTextEdit::gotoNextFuzzyRequested, this, &EditorTab::gotoNextFuzzy); connect(this, &EditorTab::signalNextFuzzyAvailable, action, &QAction::setEnabled); ADD_ACTION_SHORTCUT_ICON("go_prev_untrans", i18nc("@action:inmenu", "Previous untranslated"), Qt::ALT + Qt::Key_PageUp, "prevuntranslated") connect(action, &QAction::triggered, this, &EditorTab::gotoPrevUntranslated); connect((const TranslationUnitTextEdit*)m_view->viewPort(), &TranslationUnitTextEdit::gotoPrevUntranslatedRequested, this, &EditorTab::gotoPrevUntranslated); connect(this, &EditorTab::signalPriorUntranslatedAvailable, action, &QAction::setEnabled); ADD_ACTION_SHORTCUT_ICON("go_next_untrans", i18nc("@action:inmenu", "Next untranslated"), Qt::ALT + Qt::Key_PageDown, "nextuntranslated") connect(action, &QAction::triggered, this, &EditorTab::gotoNextUntranslated); connect((const TranslationUnitTextEdit*)m_view->viewPort(), &TranslationUnitTextEdit::gotoNextUntranslatedRequested, this, &EditorTab::gotoNextUntranslated); connect(this, &EditorTab::signalNextUntranslatedAvailable, action, &QAction::setEnabled); ADD_ACTION_SHORTCUT_ICON("go_prev_fuzzyUntr", i18nc("@action:inmenu\n'not ready' means 'fuzzy' in gettext terminology", "Previous not ready"), Qt::CTRL + Qt::SHIFT/*ALT*/ + Qt::Key_PageUp, "prevfuzzyuntrans") connect(action, &QAction::triggered, this, &EditorTab::gotoPrevFuzzyUntr); connect((const TranslationUnitTextEdit*)m_view->viewPort(), &TranslationUnitTextEdit::gotoPrevFuzzyUntrRequested, this, &EditorTab::gotoPrevFuzzyUntr); connect(this, &EditorTab::signalPriorFuzzyOrUntrAvailable, action, &QAction::setEnabled); ADD_ACTION_SHORTCUT_ICON("go_next_fuzzyUntr", i18nc("@action:inmenu\n'not ready' means 'fuzzy' in gettext terminology", "Next not ready"), Qt::CTRL + Qt::SHIFT + Qt::Key_PageDown, "nextfuzzyuntrans") connect(action, &QAction::triggered, this, QOverload<>::of(&EditorTab::gotoNextFuzzyUntr)); connect((const TranslationUnitTextEdit*)m_view->viewPort(), &TranslationUnitTextEdit::gotoNextFuzzyUntrRequested, this, QOverload<>::of(&EditorTab::gotoNextFuzzyUntr)); connect(this, &EditorTab::signalNextFuzzyOrUntrAvailable, action, &QAction::setEnabled); action = nav->addAction(QStringLiteral("go_focus_earch_line"), m_transUnitsView, SLOT(setFocus())); ac->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_L)); action->setText(i18nc("@action:inmenu", "Focus the search line of Translation Units view")); //Bookmarks action = nav->addAction(KStandardAction::AddBookmark, m_view, SLOT(toggleBookmark(bool))); //action = ac->addAction("bookmark_do"); action->setText(i18nc("@option:check", "Bookmark message")); action->setCheckable(true); //connect(action, SIGNAL(triggered(bool)),m_view,SLOT(toggleBookmark(bool))); connect(this, &EditorTab::signalBookmarkDisplayed, action, &QAction::setChecked); action = nav->addAction(QStringLiteral("bookmark_prior"), this, SLOT(gotoPrevBookmark())); action->setText(i18nc("@action:inmenu", "Previous bookmark")); connect(this, &EditorTab::signalPriorBookmarkAvailable, action, &QAction::setEnabled); action = nav->addAction(QStringLiteral("bookmark_next"), this, SLOT(gotoNextBookmark())); action->setText(i18nc("@action:inmenu", "Next bookmark")); connect(this, &EditorTab::signalNextBookmarkAvailable, action, &QAction::setEnabled); //Tools edit->addAction(KStandardAction::Spelling, this, SLOT(spellcheck())); actionCategory = tm; // xgettext: no-c-format ADD_ACTION_SHORTCUT("tools_tm_batch", i18nc("@action:inmenu", "Fill in all exact suggestions"), Qt::CTRL + Qt::ALT + Qt::Key_B) connect(action, &QAction::triggered, _tmView, &TM::TMView::slotBatchTranslate); // xgettext: no-c-format ADD_ACTION_SHORTCUT("tools_tm_batch_fuzzy", i18nc("@action:inmenu", "Fill in all exact suggestions and mark as fuzzy"), Qt::CTRL + Qt::ALT + Qt::Key_N) connect(action, &QAction::triggered, _tmView, &TM::TMView::slotBatchTranslateFuzzy); //MergeMode action = sync1->addAction(QStringLiteral("merge_open"), m_syncView, SLOT(mergeOpen())); action->setText(i18nc("@action:inmenu", "Open file for sync/merge")); action->setStatusTip(i18nc("@info:status", "Open catalog to be merged into the current one / replicate base file changes to")); action->setToolTip(action->statusTip()); action->setWhatsThis(action->statusTip()); m_syncView->addAction(action); action = sync1->addAction(QStringLiteral("merge_prev"), m_syncView, SLOT(gotoPrevChanged())); action->setText(i18nc("@action:inmenu", "Previous different")); action->setStatusTip(i18nc("@info:status", "Previous entry which is translated differently in the file being merged, including empty translations in merge source")); action->setToolTip(action->statusTip()); action->setWhatsThis(action->statusTip()); ac->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::Key_Up)); connect(m_syncView, &MergeView::signalPriorChangedAvailable, action, &QAction::setEnabled); m_syncView->addAction(action); action = sync1->addAction(QStringLiteral("merge_next"), m_syncView, SLOT(gotoNextChanged())); action->setText(i18nc("@action:inmenu", "Next different")); action->setStatusTip(i18nc("@info:status", "Next entry which is translated differently in the file being merged, including empty translations in merge source")); action->setToolTip(action->statusTip()); action->setWhatsThis(action->statusTip()); ac->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::Key_Down)); connect(m_syncView, &MergeView::signalNextChangedAvailable, action, &QAction::setEnabled); m_syncView->addAction(action); action = sync1->addAction(QStringLiteral("merge_nextapproved"), m_syncView, SLOT(gotoNextChangedApproved())); action->setText(i18nc("@action:inmenu", "Next different approved")); ac->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::META + Qt::Key_Down)); connect(m_syncView, &MergeView::signalNextChangedAvailable, action, &QAction::setEnabled); m_syncView->addAction(action); action = sync1->addAction(QStringLiteral("merge_accept"), m_syncView, SLOT(mergeAccept())); action->setText(i18nc("@action:inmenu", "Copy from merging source")); action->setEnabled(false); ac->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::Key_Return)); connect(m_syncView, &MergeView::signalEntryWithMergeDisplayed, action, &QAction::setEnabled); m_syncView->addAction(action); action = sync1->addAction(QStringLiteral("merge_acceptnew"), m_syncView, SLOT(mergeAcceptAllForEmpty())); action->setText(i18nc("@action:inmenu", "Copy all new translations")); action->setStatusTip(i18nc("@info:status", "This changes only empty and non-ready entries in base file")); action->setToolTip(action->statusTip()); action->setWhatsThis(action->statusTip()); ac->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_A)); connect(m_syncView, &MergeView::mergeCatalogAvailable, action, &QAction::setEnabled); m_syncView->addAction(action); //action->setShortcut(Qt::ALT+Qt::Key_E); action = sync1->addAction(QStringLiteral("merge_back"), m_syncView, SLOT(mergeBack())); action->setText(i18nc("@action:inmenu", "Copy to merging source")); connect(m_syncView, &MergeView::mergeCatalogAvailable, action, &QAction::setEnabled); ac->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_Return)); m_syncView->addAction(action); //Secondary merge action = sync2->addAction(QStringLiteral("mergesecondary_open"), m_syncViewSecondary, SLOT(mergeOpen())); action->setText(i18nc("@action:inmenu", "Open file for secondary sync")); action->setStatusTip(i18nc("@info:status", "Open catalog to be merged into the current one / replicate base file changes to")); action->setToolTip(action->statusTip()); action->setWhatsThis(action->statusTip()); m_syncViewSecondary->addAction(action); action = sync2->addAction(QStringLiteral("mergesecondary_prev"), m_syncViewSecondary, SLOT(gotoPrevChanged())); action->setText(i18nc("@action:inmenu", "Previous different")); action->setStatusTip(i18nc("@info:status", "Previous entry which is translated differently in the file being merged, including empty translations in merge source")); action->setToolTip(action->statusTip()); action->setWhatsThis(action->statusTip()); connect(m_syncView, &MergeView::signalPriorChangedAvailable, action, &QAction::setEnabled); m_syncViewSecondary->addAction(action); action = sync2->addAction(QStringLiteral("mergesecondary_next"), m_syncViewSecondary, SLOT(gotoNextChanged())); action->setText(i18nc("@action:inmenu", "Next different")); action->setStatusTip(i18nc("@info:status", "Next entry which is translated differently in the file being merged, including empty translations in merge source")); action->setToolTip(action->statusTip()); action->setWhatsThis(action->statusTip()); connect(m_syncView, &MergeView::signalNextChangedAvailable, action, &QAction::setEnabled); m_syncViewSecondary->addAction(action); action = sync2->addAction(QStringLiteral("mergesecondary_accept"), m_syncViewSecondary, SLOT(mergeAccept())); action->setText(i18nc("@action:inmenu", "Copy from merging source")); connect(m_syncView, &MergeView::signalEntryWithMergeDisplayed, action, &QAction::setEnabled); m_syncViewSecondary->addAction(action); action = sync2->addAction(QStringLiteral("mergesecondary_acceptnew"), m_syncViewSecondary, SLOT(mergeAcceptAllForEmpty())); action->setText(i18nc("@action:inmenu", "Copy all new translations")); action->setStatusTip(i18nc("@info:status", "This changes only empty entries")); action->setToolTip(action->statusTip()); action->setWhatsThis(action->statusTip()); m_syncViewSecondary->addAction(action); action = sync2->addAction(QStringLiteral("mergesecondary_back"), m_syncViewSecondary, SLOT(mergeBack())); action->setText(i18nc("@action:inmenu", "Copy to merging source")); m_syncViewSecondary->addAction(action); } void EditorTab::setProperFocus() { m_view->setProperFocus(); } void EditorTab::hideDocks() { if (m_transUnitsView->isFloating()) m_transUnitsView->hide(); } void EditorTab::showDocks() { return; if (m_transUnitsView->isFloating()) m_transUnitsView->show(); } void EditorTab::setProperCaption(QString title, bool modified) { if (m_catalog->autoSaveRecovered()) title += ' ' + i18nc("editor tab name", "(recovered)"); setWindowTitle(title + QStringLiteral(" [*]")); setWindowModified(modified); } void EditorTab::setFullPathShown(bool fullPathShown) { m_fullPathShown = fullPathShown; updateCaptionPath(); setModificationSign(); } void EditorTab::setModificationSign() { bool clean = m_catalog->isClean() && !m_syncView->isModified() && !m_syncViewSecondary->isModified(); setProperCaption(_captionPath, !clean); } void EditorTab::updateCaptionPath() { QString url = m_catalog->url(); if (!m_project->isLoaded()) { _captionPath = url; return; } if (!m_fullPathShown) { _captionPath = QFileInfo(url).fileName(); return; } _captionPath = QDir(QFileInfo(m_project->path()).absolutePath()).relativeFilePath(url); if (_captionPath.contains(QLatin1String("../.."))) _captionPath = url; else if (_captionPath.startsWith(QLatin1String("./"))) _captionPath = _captionPath.mid(2); } bool EditorTab::fileOpen(QString filePath, QString suggestedDirPath, bool silent) { if (!m_catalog->isClean()) { switch (KMessageBox::warningYesNoCancel(SettingsController::instance()->mainWindowPtr(), i18nc("@info", "The document contains unsaved changes.\n" "Do you want to save your changes or discard them?"), i18nc("@title:window", "Warning"), KStandardGuiItem::save(), KStandardGuiItem::discard()) ) { case KMessageBox::Yes: if (!saveFile()) return false; break; case KMessageBox::Cancel: return false; default:; } } if (suggestedDirPath.isEmpty()) suggestedDirPath = m_catalog->url(); QString saidPath; if (filePath.isEmpty()) { //Prevent crashes //Project::instance()->model()->weaver()->suspend(); //KDE5PORT use mutex if the crash is still there with kfilemetadata library filePath = QFileDialog::getOpenFileName(SettingsController::instance()->mainWindowPtr(), i18nc("@title:window", "Select translation file"), suggestedDirPath, Catalog::supportedFileTypes(true));//" text/x-gettext-translation-template"); //Project::instance()->model()->weaver()->resume(); //TODO application/x-xliff, windows: just extensions //originalPath=url.path(); never used } else 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')) { saidPath = filePath; filePath = newPath; } } if (filePath.isEmpty()) return false; QApplication::setOverrideCursor(Qt::WaitCursor); QString prevFilePath = currentFilePath(); bool wasOpen = !m_catalog->isEmpty(); if (wasOpen) emit fileAboutToBeClosed(); int errorLine = m_catalog->loadFromUrl(filePath, saidPath); if (wasOpen && errorLine == 0) { emit fileClosed(); emit fileClosed(prevFilePath); } QApplication::restoreOverrideCursor(); if (errorLine == 0) { statusBarItems.insert(ID_STATUS_TOTAL, i18nc("@info:status message entries", "Total: %1", m_catalog->numberOfEntries())); numberOfUntranslatedChanged(); numberOfFuzziesChanged(); m_currentPos.entry = -1; //so the signals are emitted DocPosition pos(0); //we delay gotoEntry(pos) until project is loaded; //Project if (!m_project->isLoaded()) { QFileInfo fileInfo(filePath); -#ifndef NOKDE //search for it int i = 4; QDir dir = fileInfo.dir(); QStringList proj(QStringLiteral("*.lokalize")); dir.setNameFilters(proj); while (--i && !dir.isRoot() && !m_project->isLoaded()) { if (dir.entryList().isEmpty()) { if (!dir.cdUp()) break; } else m_project->load(dir.absoluteFilePath(dir.entryList().first())); } -#endif //enforce autosync m_syncViewSecondary->mergeOpen(filePath); if (!m_project->isLoaded()) { if (m_project->desirablePath().isEmpty()) m_project->setDesirablePath(fileInfo.absolutePath() + QStringLiteral("/index.lokalize")); if (m_catalog->targetLangCode().isEmpty() /*&& m_project->targetLangCode().length()*/) m_catalog->setTargetLangCode(getTargetLangCode(fileInfo.fileName())); //_project->setLangCode(m_catalog->targetLangCode()); } } if (m_catalog->targetLangCode().isEmpty() /*&& m_project->targetLangCode().length()*/) m_catalog->setTargetLangCode(Project::instance()->targetLangCode()); gotoEntry(pos); updateCaptionPath(); setModificationSign(); //OK!!! emit xliffFileOpened(m_catalog->type() == Xliff); emit fileOpened(); return true; } if (!silent) { -#ifndef NOKDE if (errorLine > 0) KMessageBox::error(this, i18nc("@info", "Error opening the file %1, line: %2", filePath, errorLine)); else KMessageBox::error(this, i18nc("@info", "Error opening the file %1", filePath)); -#else - KMessageBox::error(this, i18nc("@info", "Error opening the file")); -#endif } return false; } bool EditorTab::saveFileAs(const QString& defaultPath) { QString filePath = QFileDialog::getSaveFileName(this, i18nc("@title:window", "Save File As"), QFileInfo(defaultPath.isEmpty() ? m_catalog->url() : defaultPath).absoluteFilePath(), m_catalog->fileType()); if (filePath.isEmpty()) return false; if (!Catalog::extIsSupported(filePath) && m_catalog->url().contains('.')) filePath += m_catalog->url().midRef(m_catalog->url().lastIndexOf('.')); return saveFile(filePath); } bool EditorTab::saveFile(const QString& filePath) { bool clean = m_catalog->isClean() && !m_syncView->isModified() && !m_syncViewSecondary->isModified() && filePath == m_catalog->url(); if (clean) return true; if (m_catalog->isClean() && filePath.isEmpty()) { emit m_catalog->signalFileSaved(); return true; } if (m_catalog->saveToUrl(filePath)) { updateCaptionPath(); setModificationSign(); emit fileSaved(filePath); return true; } const QString errorFilePath = filePath.isEmpty() ? m_catalog->url() : filePath; -#ifndef NOKDE if (KMessageBox::Continue == KMessageBox::warningContinueCancel(this, i18nc("@info", "Error saving the file %1\n" "Do you want to save to another file or cancel?", errorFilePath), i18nc("@title", "Error"), KStandardGuiItem::save()) ) -#else - if (QMessageBox::Yes == QMessageBox::warning(this, QString(), - i18nc("@info", "Error saving the file %1\n" - "Do you want to save to another file or cancel?").arg(errorFilePath), - QMessageBox::Yes | QMessageBox::No) - ) -#endif return saveFileAs(errorFilePath); return false; } void EditorTab::fileAutoSaveFailedWarning(const QString& fileName) { KMessageBox::information(this, i18nc("@info", "Could not perform file autosaving.\n" "The target file was %1.", fileName)); } EditorState EditorTab::state() { EditorState state; state.dockWidgets = saveState(); state.filePath = m_catalog->url(); state.mergeFilePath = m_syncView->filePath(); state.entry = m_currentPos.entry; //state.offset=_currentPos.offset; return state; } bool EditorTab::queryClose() { bool clean = m_catalog->isClean() && !m_syncView->isModified() && !m_syncViewSecondary->isModified(); if (clean) return true; //TODO caption switch (KMessageBox::warningYesNoCancel(this, i18nc("@info", "The document contains unsaved changes.\n" "Do you want to save your changes or discard them?"), i18nc("@title:window", "Warning"), KStandardGuiItem::save(), KStandardGuiItem::discard())) { case KMessageBox::Yes: return saveFile(); case KMessageBox::No: return true; default: return false; } } void EditorTab::undo() { gotoEntry(m_catalog->undo(), 0); msgStrChanged(); } void EditorTab::redo() { gotoEntry(m_catalog->redo(), 0); msgStrChanged(); } void EditorTab::gotoEntry() { bool ok = false; DocPosition pos = m_currentPos; pos.entry = QInputDialog::getInt(this, i18nc("@title", "Jump to Entry"), i18nc("@label:spinbox", "Enter entry number:"), pos.entry, 1, m_catalog->numberOfEntries(), 1, &ok); if (ok) { --(pos.entry); gotoEntry(pos); } } void EditorTab::gotoEntry(DocPosition pos) { return gotoEntry(pos, 0); } void EditorTab::gotoEntry(DocPosition pos, int selection) { //specially for dbus users if (pos.entry >= m_catalog->numberOfEntries() || pos.entry < 0) return; if (!m_catalog->isPlural(pos)) pos.form = 0; m_currentPos.part = pos.part; //for searching; //UndefPart => called on fuzzy toggle bool newEntry = m_currentPos.entry != pos.entry || m_currentPos.form != pos.form; if (newEntry || pos.part == DocPosition::Comment) { m_notesView->gotoEntry(pos, pos.part == DocPosition::Comment ? selection : 0); if (pos.part == DocPosition::Comment) { pos.form = 0; pos.offset = 0; selection = 0; } } m_view->gotoEntry(pos, selection); if (pos.part == DocPosition::UndefPart) m_currentPos.part = DocPosition::Target; //QTime time; time.start(); if (newEntry) { m_currentPos = pos; if (true) { emit signalNewEntryDisplayed(pos); emit entryDisplayed(); emit signalFirstDisplayed(pos.entry == m_transUnitsView->firstEntryNumber()); emit signalLastDisplayed(pos.entry == m_transUnitsView->lastEntryNumber()); emit signalPriorFuzzyAvailable(pos.entry > m_catalog->firstFuzzyIndex()); emit signalNextFuzzyAvailable(pos.entry < m_catalog->lastFuzzyIndex()); emit signalPriorUntranslatedAvailable(pos.entry > m_catalog->firstUntranslatedIndex()); emit signalNextUntranslatedAvailable(pos.entry < m_catalog->lastUntranslatedIndex()); emit signalPriorFuzzyOrUntrAvailable(pos.entry > m_catalog->firstFuzzyIndex() || pos.entry > m_catalog->firstUntranslatedIndex() ); emit signalNextFuzzyOrUntrAvailable(pos.entry < m_catalog->lastFuzzyIndex() || pos.entry < m_catalog->lastUntranslatedIndex()); emit signalPriorBookmarkAvailable(pos.entry > m_catalog->firstBookmarkIndex()); emit signalNextBookmarkAvailable(pos.entry < m_catalog->lastBookmarkIndex()); emit signalBookmarkDisplayed(m_catalog->isBookmarked(pos.entry)); emit signalEquivTranslatedEntryDisplayed(m_catalog->isEquivTrans(pos)); emit signalApprovedEntryDisplayed(m_catalog->isApproved(pos)); } } statusBarItems.insert(ID_STATUS_CURRENT, i18nc("@info:status", "Current: %1", m_currentPos.entry + 1)); //qCDebug(LOKALIZE_LOG)<<"ELA "<msgstr(m_currentPos).isEmpty(); bool isApproved = m_catalog->isApproved(m_currentPos); if (isUntr == m_currentIsUntr && isApproved == m_currentIsApproved) return; QString msg; if (isUntr) msg = i18nc("@info:status", "Untranslated"); else if (isApproved)msg = i18nc("@info:status 'non-fuzzy' in gettext terminology", "Ready"); else msg = i18nc("@info:status 'fuzzy' in gettext terminology", "Needs review"); /* else statusBar()->changeItem("",ID_STATUS_ISFUZZY);*/ statusBarItems.insert(ID_STATUS_ISFUZZY, msg); m_currentIsUntr = isUntr; m_currentIsApproved = isApproved; } void EditorTab::switchForm(int newForm) { if (m_currentPos.form == newForm) return; DocPosition pos = m_currentPos; pos.form = newForm; gotoEntry(pos); } void EditorTab::gotoNextUnfiltered() { DocPosition pos = m_currentPos; if (switchNext(m_catalog, pos)) gotoEntry(pos); } void EditorTab::gotoPrevUnfiltered() { DocPosition pos = m_currentPos; if (switchPrev(m_catalog, pos)) gotoEntry(pos); } void EditorTab::gotoFirstUnfiltered() { gotoEntry(DocPosition(0)); } void EditorTab::gotoLastUnfiltered() { gotoEntry(DocPosition(m_catalog->numberOfEntries() - 1)); } void EditorTab::gotoFirst() { DocPosition pos = DocPosition(m_transUnitsView->firstEntryNumber()); if (pos.entry != -1) gotoEntry(pos); } void EditorTab::gotoLast() { DocPosition pos = DocPosition(m_transUnitsView->lastEntryNumber()); if (pos.entry != -1) gotoEntry(pos); } void EditorTab::gotoNext() { DocPosition pos = m_currentPos; if (m_catalog->isPlural(pos) && pos.form + 1 < m_catalog->numberOfPluralForms()) pos.form++; else pos = DocPosition(m_transUnitsView->nextEntryNumber()); if (pos.entry != -1) gotoEntry(pos); } void EditorTab::gotoPrev() { DocPosition pos = m_currentPos; if (m_catalog->isPlural(pos) && pos.form > 0) pos.form--; else pos = DocPosition(m_transUnitsView->prevEntryNumber()); if (pos.entry != -1) gotoEntry(pos); } void EditorTab::gotoPrevFuzzy() { DocPosition pos; if ((pos.entry = m_catalog->prevFuzzyIndex(m_currentPos.entry)) == -1) return; gotoEntry(pos); } void EditorTab::gotoNextFuzzy() { DocPosition pos; if ((pos.entry = m_catalog->nextFuzzyIndex(m_currentPos.entry)) == -1) return; gotoEntry(pos); } void EditorTab::gotoPrevUntranslated() { DocPosition pos; if ((pos.entry = m_catalog->prevUntranslatedIndex(m_currentPos.entry)) == -1) return; gotoEntry(pos); } void EditorTab::gotoNextUntranslated() { DocPosition pos; if ((pos.entry = m_catalog->nextUntranslatedIndex(m_currentPos.entry)) == -1) return; gotoEntry(pos); } void EditorTab::gotoPrevFuzzyUntr() { DocPosition pos; short fu = m_catalog->prevFuzzyIndex(m_currentPos.entry); short un = m_catalog->prevUntranslatedIndex(m_currentPos.entry); pos.entry = fu > un ? fu : un; if (pos.entry == -1) return; gotoEntry(pos); } bool EditorTab::gotoNextFuzzyUntr() { return gotoNextFuzzyUntr(DocPosition()); } bool EditorTab::gotoNextFuzzyUntr(const DocPosition& p) { int index = (p.entry == -1) ? m_currentPos.entry : p.entry; DocPosition pos; short fu = m_catalog->nextFuzzyIndex(index); short un = m_catalog->nextUntranslatedIndex(index); if ((fu == -1) && (un == -1)) return false; if (fu == -1) fu = un; else if (un == -1) un = fu; pos.entry = fu < un ? fu : un; gotoEntry(pos); return true; } void EditorTab::toggleApprovementGotoNextFuzzyUntr() { if (!m_catalog->isApproved(m_currentPos.entry)) m_view->toggleApprovement(); if (!gotoNextFuzzyUntr()) gotoNextFuzzyUntr(DocPosition(-2));//so that we don't skip the first } void EditorTab::setApproveActionTitle() { const char* const titles[] = { I18N_NOOP2("@option:check trans-unit state", "Translated"), I18N_NOOP2("@option:check trans-unit state", "Signed-off"), I18N_NOOP2("@option:check trans-unit state", "Approved") }; const char* const helpText[] = { I18N_NOOP2("@info:tooltip", "Translation is done (although still may need a review)"), I18N_NOOP2("@info:tooltip", "Translation has received positive review"), I18N_NOOP2("@info:tooltip", "Entry is fully localized (i.e. final)") }; int role = m_catalog->activePhaseRole(); if (role == ProjectLocal::Undefined) role = Project::local()->role(); m_approveAction->setText(i18nc("@option:check trans-unit state", titles[role])); m_approveAction->setToolTip(i18nc("@info:tooltip", helpText[role])); m_approveAndGoAction->setVisible(role == ProjectLocal::Approver); -#ifdef NOKDE - m_stateAction->setVisible(m_catalog->capabilities()&ExtendedStates); -#endif } void EditorTab::showStatesMenu() { m_stateAction->menu()->clear(); if (!(m_catalog->capabilities()&ExtendedStates)) { QAction* a = m_stateAction->menu()->addAction(i18nc("@info:status 'fuzzy' in gettext terminology", "Needs review")); a->setData(QVariant(-1)); a->setCheckable(true); a->setChecked(!m_catalog->isApproved(m_currentPos)); a = m_stateAction->menu()->addAction(i18nc("@info:status 'non-fuzzy' in gettext terminology", "Ready")); a->setData(QVariant(-2)); a->setCheckable(true); a->setChecked(m_catalog->isApproved(m_currentPos)); return; } TargetState state = m_catalog->state(m_currentPos); const char* const* states = Catalog::states(); for (int i = 0; i < StateCount; ++i) { QAction* a = m_stateAction->menu()->addAction(i18n(states[i])); a->setData(QVariant(i)); a->setCheckable(true); a->setChecked(state == i); if (i == New || i == Translated || i == Final) m_stateAction->menu()->addSeparator(); } } void EditorTab::setState(QAction* a) { if (!(m_catalog->capabilities()&ExtendedStates)) m_view->toggleApprovement(); else m_view->setState(TargetState(a->data().toInt())); m_stateAction->menu()->clear(); } void EditorTab::openPhasesWindow() { PhasesWindow w(m_catalog, this); w.exec(); } void EditorTab::gotoPrevBookmark() { DocPosition pos; if ((pos.entry = m_catalog->prevBookmarkIndex(m_currentPos.entry)) == -1) return; gotoEntry(pos); } void EditorTab::gotoNextBookmark() { DocPosition pos; if ((pos.entry = m_catalog->nextBookmarkIndex(m_currentPos.entry)) == -1) return; gotoEntry(pos); } //wrapper for cmdline handling... void EditorTab::mergeOpen(QString mergeFilePath) { m_syncView->mergeOpen(mergeFilePath); } //HACK to prevent redundant repaintings when widget isn't visible void EditorTab::paintEvent(QPaintEvent* event) { if (QMdiSubWindow* sw = qobject_cast(parent())) { if (sw->mdiArea()->currentSubWindow() != sw) return; } LokalizeSubwindowBase2::paintEvent(event); } void EditorTab::indexWordsForCompletion() { CompletionStorage::instance()->scanCatalog(m_catalog); } void EditorTab::launchPology() { if (!m_pologyProcessInProgress) { QString command = Settings::self()->pologyCommandFile().replace(QStringLiteral("%f"), QStringLiteral("\"") + currentFilePath() + QStringLiteral("\"")); m_pologyProcess = new KProcess; m_pologyProcess->setOutputChannelMode(KProcess::SeparateChannels); qCWarning(LOKALIZE_LOG) << "Launching pology command: " << command; connect(m_pologyProcess, QOverload::of(&KProcess::finished), this, &EditorTab::pologyHasFinished); m_pologyProcess->setShellCommand(command); m_pologyProcessInProgress = true; m_pologyProcess->start(); } else { KMessageBox::error(this, i18n("A Pology check is already in progress."), i18n("Pology error")); } } void EditorTab::pologyHasFinished(int exitCode, QProcess::ExitStatus exitStatus) { const QString pologyError = m_pologyProcess->readAllStandardError(); if (exitStatus == QProcess::CrashExit) { KMessageBox::error(this, i18n("The Pology check has crashed unexpectedly:\n%1", pologyError), i18n("Pology error")); } else if (exitCode == 0) { KMessageBox::information(this, i18n("The Pology check has succeeded."), i18n("Pology success")); } else { KMessageBox::error(this, i18n("The Pology check has returned an error:\n%1", pologyError), i18n("Pology error")); } m_pologyProcess->deleteLater(); m_pologyProcessInProgress = false; } void EditorTab::clearTranslatedEntries() { switch (KMessageBox::warningYesNoCancel(this, i18nc("@info", "This will delete all the translations from the file.\n" "Do you really want to clear all translated entries?"), i18nc("@title:window", "Warning"), KStandardGuiItem::yes(), KStandardGuiItem::no())) { case KMessageBox::Yes: { DocPosition pos(0); do { removeTargetSubstring(m_catalog, pos); } while (switchNext(m_catalog, pos)); msgStrChanged(); gotoEntry(m_currentPos); } default:; } } void EditorTab::displayWordCount() { //TODO in trans and fuzzy separately int sourceCount = 0; int targetCount = 0; QRegExp rxClean(Project::instance()->markup() % '|' % Project::instance()->accel()); //cleaning regexp; NOTE isEmpty()? QRegExp rxSplit(QStringLiteral("\\W|\\d"));//splitting regexp DocPosition pos(0); do { QString msg = m_catalog->source(pos); msg.remove(rxClean); QStringList words = msg.split(rxSplit, QString::SkipEmptyParts); sourceCount += words.size(); msg = m_catalog->target(pos); msg.remove(rxClean); words = msg.split(rxSplit, QString::SkipEmptyParts); targetCount += words.size(); } while (switchNext(m_catalog, pos)); KMessageBox::information(this, i18nc("@info words count", "Source text words: %1
Target text words: %2", sourceCount, targetCount), i18nc("@title", "Word Count")); } bool EditorTab::findEntryBySourceContext(const QString& source, const QString& ctxt) { DocPosition pos(0); do { if (m_catalog->source(pos) == source && m_catalog->context(pos.entry) == QStringList(ctxt)) { gotoEntry(pos); return true; } } while (switchNext(m_catalog, pos)); return false; } //see also termlabel.h void EditorTab::defineNewTerm() { //TODO just a word under cursor? QString en(m_view->selectionInSource().toLower()); if (en.isEmpty()) en = m_catalog->msgid(m_currentPos).toLower(); QString target(m_view->selectionInTarget().toLower()); if (target.isEmpty()) target = m_catalog->msgstr(m_currentPos).toLower(); m_project->defineNewTerm(en, target); } void EditorTab::reloadFile() { QString mergeFilePath = m_syncView->filePath(); DocPosition p = m_currentPos; if (!fileOpen(currentFilePath())) return; gotoEntry(p); if (!mergeFilePath.isEmpty()) mergeOpen(mergeFilePath); } static void openLxrSearch(const QString& srcFileRelPath) { QDesktopServices::openUrl(QUrl(QStringLiteral("https://lxr.kde.org/search?_filestring=") + QString::fromLatin1(QUrl::toPercentEncoding(srcFileRelPath)))); } void EditorTab::dispatchSrcFileOpenRequest(const QString& srcFileRelPath, int line) { // Try project scripts first. m_srcFileOpenRequestAccepted = false; emit srcFileOpenRequested(srcFileRelPath, line); if (m_srcFileOpenRequestAccepted) return; // If project scripts do not handle opening the source file, check if the // path exists relative to the current translation file path. QDir relativePath(currentFilePath()); relativePath.cdUp(); QString srcAbsolutePath(relativePath.absoluteFilePath(srcFileRelPath)); if (QFile::exists(srcAbsolutePath)) { QDesktopServices::openUrl(QUrl::fromLocalFile(srcAbsolutePath)); return; } QString dir = Project::instance()->local()->sourceDir(); if (dir.isEmpty()) { switch (KMessageBox::questionYesNoCancel(SettingsController::instance()->mainWindowPtr(), i18nc("@info", "Would you like to search for the source file locally or via lxr.kde.org?"), i18nc("@title:window", "Source file lookup"), KGuiItem(i18n("Locally")), KGuiItem("lxr.kde.org") )) { case KMessageBox::Yes: break; case KMessageBox::No: openLxrSearch(srcFileRelPath); case KMessageBox::Cancel: default: return; } } //hard fallback if (dir.isEmpty()) { dir = QFileDialog::getExistingDirectory(this, i18n("Select project's base folder for source file lookup"), QDir::homePath()); if (dir.length()) Project::instance()->local()->setSourceDir(dir); } if (dir.length()) { auto doOpen = [srcFileRelPath]() { auto sourceFilePaths = Project::instance()->sourceFilePaths(); bool found = false; QByteArray fn = srcFileRelPath.midRef(srcFileRelPath.lastIndexOf('/') + 1).toUtf8(); auto it = sourceFilePaths.constFind(fn); while (it != sourceFilePaths.constEnd() && it.key() == fn) { const QString absFilePath = QString::fromUtf8(it.value() + '/' + fn); if (!absFilePath.endsWith(srcFileRelPath) || !QFileInfo::exists(absFilePath)) { //for the case when link contained also folders it++; continue; } found = true; QDesktopServices::openUrl(QUrl::fromLocalFile(absFilePath)); it++; } if (!found) { switch (KMessageBox::warningYesNoCancel(SettingsController::instance()->mainWindowPtr(), i18nc("@info", "Could not find source file in the folder specified.\n" "Do you want to change source files folder?"), i18nc("@title:window", "Source file lookup"), KStandardGuiItem::yes(), KStandardGuiItem::no(), KGuiItem(i18n("lxr.kde.org")))) { case KMessageBox::Cancel: Project::instance()->local()->setSourceDir(QString()); Project::instance()->resetSourceFilePaths(); openLxrSearch(srcFileRelPath); case KMessageBox::No: return; default: ; //fall through to dir selection } QString dir = QFileDialog::getExistingDirectory(0, i18n("Select project's base folder for source file lookup"), Project::instance()->local()->sourceDir()); if (dir.length()) { Project::instance()->local()->setSourceDir(dir); Project::instance()->resetSourceFilePaths(); } } }; if (!Project::instance()->sourceFilePaths().isEmpty()) doOpen(); else connect(Project::instance(), &Project::sourceFilePathsAreReady, doOpen); return; } // Otherwise, let the user know how to create a project script to handle // opening source file paths that are not relative to translation files. KMessageBox::information(this, i18nc("@info", "Cannot open the target source file: The target source file is not " "relative to the current translation file, and there are currently no " "scripts loaded to handle opening source files in custom paths. Refer " "to the Lokalize handbook for script examples and how to plug them " "into your project.")); } void EditorTab::mergeIntoOpenDocument() { if (!m_catalog || m_catalog->type() != Xliff) return; QString xliff2odf = QStringLiteral("xliff2odf"); if (QProcess::execute(xliff2odf, QStringList(QLatin1String("--version"))) == -2) { KMessageBox::error(SettingsController::instance()->mainWindowPtr(), i18n("Install translate-toolkit package and retry.")); return; } QString xliffFolder = QFileInfo(m_catalog->url()).absolutePath(); QString originalOdfFilePath = m_catalog->originalOdfFilePath(); if (originalOdfFilePath.isEmpty() || !QFile::exists(originalOdfFilePath)) { originalOdfFilePath = QFileDialog::getOpenFileName( SettingsController::instance()->mainWindowPtr(), i18n("Select original OpenDocument on which current XLIFF file is based"), xliffFolder, i18n("OpenDocument files (*.odt *.ods)")/*"text/x-lokalize-project"*/); if (originalOdfFilePath.length()) m_catalog->setOriginalOdfFilePath(originalOdfFilePath); } if (originalOdfFilePath.isEmpty()) return; saveFile(); //TODO check if odt did update (merge with new template is needed) QFileInfo originalOdfFileInfo(originalOdfFilePath); QString targetLangCode = m_catalog->targetLangCode(); QStringList args(m_catalog->url()); args.append(xliffFolder % '/' % originalOdfFileInfo.baseName() % '-' % targetLangCode % '.' % originalOdfFileInfo.suffix()); args.append(QStringLiteral("-t")); args.append(originalOdfFilePath); qCDebug(LOKALIZE_LOG) << args; QProcess::execute(xliff2odf, args); if (!QFile::exists(args.at(1))) return; //if (originalOdfFileInfo.suffix().toLower()==QLatin1String(".odt")) { QString lowriter = QStringLiteral("soffice"); if (QProcess::execute(lowriter, QStringList("--version")) == -2) { //TODO //KMessageBox::error(SettingsController::instance()->mainWindowPtr(), i18n("Install translate-toolkit package and retry")); return; } QProcess::startDetached(lowriter, QStringList(args.at(1))); QString reloaderScript = QStandardPaths::locate(QStandardPaths::DataLocation, QStringLiteral("scripts/odf/xliff2odf-standalone.py")); if (reloaderScript.length()) { QString python = QStringLiteral("python"); QStringList unoArgs(QStringLiteral("-c")); unoArgs.append(QStringLiteral("import uno")); if (QProcess::execute(python, unoArgs) != 0) { python = QStringLiteral("python3"); QStringList unoArgs(QStringLiteral("-c")); unoArgs.append(QStringLiteral("import uno")); if (QProcess::execute(python, unoArgs) != 0) { KMessageBox::information(SettingsController::instance()->mainWindowPtr(), i18n("Install python-uno package for additional functionality.")); return; } } QStringList reloaderArgs(reloaderScript); reloaderArgs.append(args.at(1)); reloaderArgs.append(currentEntryId()); QProcess::execute(python, reloaderArgs); } } } //BEGIN DBus interface -#ifndef NOKDE #include "editoradaptor.h" QList EditorTab::ids; QString EditorTab::dbusObjectPath() { const QString EDITOR_PATH = QStringLiteral("/ThisIsWhatYouWant/Editor/"); if (m_dbusId == -1) { m_adaptor = new EditorAdaptor(this); int i = 0; while (i < ids.size() && i == ids.at(i)) ++i; ids.insert(i, i); m_dbusId = i; QDBusConnection::sessionBus().registerObject(EDITOR_PATH + QString::number(m_dbusId), this); } return EDITOR_PATH + QString::number(m_dbusId); } -#endif QString EditorTab::currentFilePath() { return m_catalog->url(); } QByteArray EditorTab::currentFileContents() { return m_catalog->contents(); } QString EditorTab::currentEntryId() { return m_catalog->id(m_currentPos); } QString EditorTab::selectionInTarget() { return m_view->selectionInTarget(); } QString EditorTab::selectionInSource() { return m_view->selectionInSource(); } void EditorTab::lookupSelectionInTranslationMemory() { emit tmLookupRequested(selectionInSource(), selectionInTarget()); } void EditorTab::setEntryFilteredOut(int entry, bool filteredOut) { m_transUnitsView->setEntryFilteredOut(entry, filteredOut); } void EditorTab::setEntriesFilteredOut(bool filteredOut) { m_transUnitsView->setEntriesFilteredOut(filteredOut); } int EditorTab::entryCount() { return m_catalog->numberOfEntries(); } QString EditorTab::entrySource(int entry, int form) { return m_catalog->sourceWithTags(DocPosition(entry, form)).string; } QString EditorTab::entryTarget(int entry, int form) { return m_catalog->targetWithTags(DocPosition(entry, form)).string; } int EditorTab::entryPluralFormCount(int entry) { return m_catalog->isPlural(entry) ? m_catalog->numberOfPluralForms() : 1; } bool EditorTab::entryReady(int entry) { return m_catalog->isApproved(entry); } QString EditorTab::sourceLangCode() { return m_catalog->sourceLangCode(); } QString EditorTab::targetLangCode() { return m_catalog->targetLangCode(); } void EditorTab::addEntryNote(int entry, const QString& note) { m_notesView->addNote(entry, note); } void EditorTab::addTemporaryEntryNote(int entry, const QString& note) { m_notesView->addTemporaryEntryNote(entry, note); } void EditorTab::addAlternateTranslation(int entry, const QString& translation) { m_altTransView->addAlternateTranslation(entry, translation); } void EditorTab::addTemporaryAlternateTranslation(int entry, const QString& translation) { m_altTransView->addAlternateTranslation(entry, translation); } void EditorTab::attachAlternateTranslationFile(const QString& path) { m_altTransView->attachAltTransFile(path); } void EditorTab::setEntryTarget(int entry, int form, const QString& content) { DocPosition pos(entry, form); m_catalog->beginMacro(i18nc("@item Undo action item", "Set unit text")); removeTargetSubstring(m_catalog, pos); insertCatalogString(m_catalog, pos, CatalogString(content)); m_catalog->endMacro(); if (m_currentPos == pos) m_view->gotoEntry(); } //END DBus interface diff --git a/src/editortab.h b/src/editortab.h index e6bb210..41a4e29 100644 --- a/src/editortab.h +++ b/src/editortab.h @@ -1,424 +1,406 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2014 by Nick Shaforostoff 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 EDITORTAB_H #define EDITORTAB_H #ifdef HAVE_CONFIG_H #include #endif #include "pos.h" #include "lokalizesubwindowbase.h" #include #include -#ifndef NOKDE namespace Sonnet { class Dialog; } namespace Sonnet { class BackgroundChecker; } #include class KFind; class KReplace; class KActionCategory; -#endif class Project; class Catalog; class EditorView; class MergeView; class CatalogView; class MsgCtxtView; class AltTransView; namespace GlossaryNS { class GlossaryView; } struct EditorState { public: EditorState(): entry(0) {} EditorState(const EditorState& s): dockWidgets(s.dockWidgets), filePath(s.filePath), entry(0) {} ~EditorState() {} QByteArray dockWidgets; QString filePath; QString mergeFilePath; int entry; //int offset; }; /** * @short Editor tab * * This class can be called a dispatcher for one message catalog. * * It is accessible via Lokalize.currentEditor() from kross scripts and via * '/ThisIsWhatYouWant/Editor/# : org.kde.Lokalize.Editor' from qdbusviewer * * @author Nick Shaforostoff */ class EditorTab: public LokalizeSubwindowBase2 { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.Lokalize.Editor") //qdbuscpp2xml -m -s editortab.h -o org.kde.lokalize.Editor.xml #define qdbuscpp2xml public: EditorTab(QWidget* parent, bool valid = true); ~EditorTab(); //interface for LokalizeMainWindow void hideDocks(); void showDocks(); QString currentFilePath(); void setFullPathShown(bool); void setProperCaption(QString, bool); //reimpl to remove ' - Lokalize' public slots: void setProperFocus(); public: bool queryClose(); EditorState state(); -#ifndef NOKDE KXMLGUIClient* guiClient() { return (KXMLGUIClient*)this; } QString dbusObjectPath(); int dbusId() { return m_dbusId; } QObject* adaptor() { return m_adaptor; } -#endif //wrapper for cmdline handling void mergeOpen(QString mergeFilePath); bool fileOpen(QString filePath = QString(), QString suggestedDirPath = QString(), bool silent = false); public slots: //for undo/redo, views void gotoEntry(DocPosition pos); void gotoEntry(DocPosition pos, int selection); #ifdef qdbuscpp2xml Q_SCRIPTABLE void gotoEntry(int entry) { gotoEntry(DocPosition(entry)); } Q_SCRIPTABLE void gotoEntryForm(int entry, int form) { gotoEntry(DocPosition(entry, form)); } Q_SCRIPTABLE void gotoEntryFormOffset(int entry, int form, int offset) { gotoEntry(DocPosition(entry, form, offset)); } Q_SCRIPTABLE void gotoEntryFormOffsetSelection(int entry, int form, int offset, int selection) { gotoEntry(DocPosition(entry, form, offset), selection); } Q_SCRIPTABLE QString currentEntryId(); Q_SCRIPTABLE int currentEntry() { return m_currentPos.entry; } Q_SCRIPTABLE int currentForm() { return m_currentPos.form; } Q_SCRIPTABLE QString selectionInTarget(); Q_SCRIPTABLE QString selectionInSource(); Q_SCRIPTABLE void setEntryFilteredOut(int entry, bool filteredOut); Q_SCRIPTABLE void setEntriesFilteredOut(bool filteredOut); Q_SCRIPTABLE int entryCount(); Q_SCRIPTABLE QString entrySource(int entry, int form); Q_SCRIPTABLE QString entryTarget(int entry, int form); Q_SCRIPTABLE void setEntryTarget(int entry, int form, const QString& content); Q_SCRIPTABLE int entryPluralFormCount(int entry); Q_SCRIPTABLE bool entryReady(int entry); Q_SCRIPTABLE void addEntryNote(int entry, const QString& note); Q_SCRIPTABLE void addTemporaryEntryNote(int entry, const QString& note); Q_SCRIPTABLE void addAlternateTranslation(int entry, const QString& translation); Q_SCRIPTABLE void addTemporaryAlternateTranslation(int entry, const QString& translation); Q_SCRIPTABLE QString currentFile() { return currentFilePath(); } Q_SCRIPTABLE QByteArray currentFileContents(); Q_SCRIPTABLE QString sourceLangCode(); Q_SCRIPTABLE QString targetLangCode(); Q_SCRIPTABLE void attachAlternateTranslationFile(const QString& path); Q_SCRIPTABLE void openSyncSource(QString path) { mergeOpen(path); } Q_SCRIPTABLE void reloadFile(); #endif Q_SCRIPTABLE bool saveFile(const QString& filePath = QString()); Q_SCRIPTABLE bool saveFileAs(const QString& defaultPath = QString()); Q_SCRIPTABLE void close() { return parent()->deleteLater(); } Q_SCRIPTABLE void gotoNextUnfiltered(); Q_SCRIPTABLE void gotoPrevUnfiltered(); Q_SCRIPTABLE void gotoFirstUnfiltered(); Q_SCRIPTABLE void gotoLastUnfiltered(); Q_SCRIPTABLE void gotoNext(); Q_SCRIPTABLE void gotoPrev(); Q_SCRIPTABLE void gotoFirst(); Q_SCRIPTABLE void gotoLast(); Q_SCRIPTABLE void mergeIntoOpenDocument(); Q_SCRIPTABLE bool findEntryBySourceContext(const QString& source, const QString& ctxt); -#ifndef NOKDE Q_SCRIPTABLE bool isValid() { return m_valid; } Q_SCRIPTABLE void setSrcFileOpenRequestAccepted(bool a) { m_srcFileOpenRequestAccepted = a; } -#endif private slots: -#ifndef NOKDE void highlightFound(const QString &, int, int); //for find/replace void highlightFound_(const QString &, int, int); //for find/replace -#endif void lookupSelectionInTranslationMemory(); //statusbar indication void numberOfFuzziesChanged(); void numberOfUntranslatedChanged(); //fuzzy, untr [statusbar] indication void msgStrChanged(); //modif [caption] indication void setModificationSign(); void updateCaptionPath(); //gui void switchForm(int); void undo(); void redo(); -#ifndef NOKDE void findNext(); void findPrev(); void find(); void replace(); void replaceNext();//internal void doReplace(const QString&, int, int, int); //internal void cleanupReplace();//internal -#endif // void selectAll(); // void deselectAll(); // void clear(); // void search2msgstr(); // void plural2msgstr(); void gotoEntry(); void gotoPrevFuzzyUntr(); bool gotoNextFuzzyUntr(const DocPosition& pos); bool gotoNextFuzzyUntr(); void gotoNextFuzzy(); void gotoPrevFuzzy(); void gotoNextUntranslated(); void gotoPrevUntranslated(); void toggleApprovementGotoNextFuzzyUntr(); void setApproveActionTitle(); -#ifndef NOKDE void spellcheck(); void spellcheckNext(); void spellcheckShow(const QString&, int); void spellcheckReplace(QString, int, const QString&); void spellcheckStop(); void spellcheckCancel(); -#endif void gotoNextBookmark(); void gotoPrevBookmark(); void displayWordCount(); void clearTranslatedEntries(); void launchPology(); void openPhasesWindow(); void defineNewTerm(); void initLater(); void showStatesMenu(); void setState(QAction*); void dispatchSrcFileOpenRequest(const QString& srcPath, int line); void indexWordsForCompletion(); void fileAutoSaveFailedWarning(const QString&); void pologyHasFinished(int exitCode, QProcess::ExitStatus exitStatus); protected: void paintEvent(QPaintEvent* event); private: void setupAccel(); void setupActions(); void setupStatusBar(); void findNext(const DocPosition& startingPos); void replaceNext(const DocPosition&); private: Project* m_project; Catalog* m_catalog; EditorView* m_view; QAction* m_approveAndGoAction; QAction* m_approveAction; - QAction* m_stateAction; //is = m_approveAction ifndef NOKDE + QAction* m_stateAction; KProcess* m_pologyProcess; bool m_pologyProcessInProgress; DocPosition m_currentPos; DocPosition _searchingPos; //for find/replace DocPosition _replacingPos; DocPosition _spellcheckPos; DocPosition _spellcheckStartPos; -#ifndef NOKDE Sonnet::BackgroundChecker* m_sonnetChecker; Sonnet::Dialog* m_sonnetDialog; int m_spellcheckStartUndoIndex; bool m_spellcheckStop: 1; -#endif bool m_currentIsApproved: 1; //for statusbar animation bool m_currentIsUntr: 1; //for statusbar animation bool m_fullPathShown: 1; -#ifndef NOKDE bool m_doReplaceCalled: 1; //used to prevent non-clean catalog status KFind* m_find; KReplace* m_replace; -#endif //BEGIN views MergeView* m_syncView; MergeView* m_syncViewSecondary; CatalogView* m_transUnitsView; MsgCtxtView* m_notesView; AltTransView* m_altTransView; //END views QString _captionPath; bool m_srcFileOpenRequestAccepted; //BEGIN dbus -#ifndef NOKDE bool m_valid; QObject* m_adaptor; int m_dbusId; static QList ids; -#endif //END dbus signals: void tmLookupRequested(DocPosition::Part, const QString&); void tmLookupRequested(const QString& source, const QString& target); Q_SCRIPTABLE void srcFileOpenRequested(const QString& srcPath, int line); void fileOpenRequested(const QString& filePath, const QString& str, const QString& ctxt, const bool setAsActive); //emitted when mainwindow is closed or another file is opened void fileClosed(); Q_SCRIPTABLE void fileClosed(const QString& path); Q_SCRIPTABLE void fileSaved(const QString& path); Q_SCRIPTABLE void fileAboutToBeClosed();//old catalog is still accessible Q_SCRIPTABLE void fileOpened(); Q_SCRIPTABLE void entryDisplayed(); void signalNewEntryDisplayed(const DocPosition&); void signalEntryWithMergeDisplayed(bool, const DocPosition&); void signalFirstDisplayed(bool); void signalLastDisplayed(bool); void signalEquivTranslatedEntryDisplayed(bool); void signalApprovedEntryDisplayed(bool); void signalFuzzyEntryDisplayed(bool); void signalPriorFuzzyAvailable(bool); void signalNextFuzzyAvailable(bool); void signalPriorUntranslatedAvailable(bool); void signalNextUntranslatedAvailable(bool); void signalPriorFuzzyOrUntrAvailable(bool); void signalNextFuzzyOrUntrAvailable(bool); // merge mode signals gone to the view //NOTE move these to catalog tree view? void signalPriorBookmarkAvailable(bool); void signalNextBookmarkAvailable(bool); void signalBookmarkDisplayed(bool); Q_SCRIPTABLE void xliffFileOpened(bool); }; #endif diff --git a/src/editorview.cpp b/src/editorview.cpp index b7af613..80ddcdf 100644 --- a/src/editorview.cpp +++ b/src/editorview.cpp @@ -1,362 +1,354 @@ /* **************************************************************************** This file is part of Lokalize (some bits of KBabel code were reused) Copyright (C) 2007-2014 by Nick Shaforostoff Copyright (C) 1999-2000 by Matthias Kiefer 2001-2004 by Stanislav Visnovsky 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) any later version. 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. **************************************************************************** */ #include "editorview.h" #include "lokalize_debug.h" #include "xlifftextedit.h" #include "project.h" #include "catalog.h" #include "cmd.h" #include "prefs_lokalize.h" #include "prefs.h" #include #include #include #include #include #include #include #include #include -#ifndef NOKDE #include #include #include -#endif //parent is set on qsplitter insertion -#ifndef NOKDE LedsWidget::LedsWidget(QWidget* parent): QWidget(parent) { KColorScheme colorScheme(QPalette::Normal); QHBoxLayout* layout = new QHBoxLayout(this); layout->addStretch(); layout->addWidget(new QLabel(i18nc("@label whether entry is fuzzy", "Not ready:"), this)); layout->addWidget(ledFuzzy = new KLed(colorScheme.foreground(KColorScheme::NeutralText).color()/*Qt::green*/, KLed::Off, KLed::Sunken, KLed::Rectangular)); layout->addWidget(new QLabel(i18nc("@label whether entry is untranslated", "Untranslated:"), this)); layout->addWidget(ledUntr = new KLed(colorScheme.foreground(KColorScheme::NegativeText).color()/*Qt::red*/, KLed::Off, KLed::Sunken, KLed::Rectangular)); layout->addSpacing(1); layout->addWidget(lblColumn = new QLabel(this)); layout->addStretch(); setMaximumHeight(minimumSizeHint().height()); } void LedsWidget::contextMenuEvent(QContextMenuEvent* event) { QMenu menu; menu.addAction(i18nc("@action", "Hide")); if (!menu.exec(event->globalPos())) return; //NOTE the config doesn't seem to work Settings::setLeds(false); SettingsController::instance()->dirty = true; hide(); } void LedsWidget::cursorPositionChanged(int column) { lblColumn->setText(i18nc("@info:label cursor position", "Column: %1", column)); } -#endif EditorView::EditorView(QWidget *parent, Catalog* catalog/*,keyEventHandler* kh*/) : QSplitter(Qt::Vertical, parent) , m_catalog(catalog) , m_sourceTextEdit(new TranslationUnitTextEdit(catalog, DocPosition::Source, this)) , m_targetTextEdit(new TranslationUnitTextEdit(catalog, DocPosition::Target, this)) , m_pluralTabBar(new QTabBar(this)) -#ifndef NOKDE , m_leds(0) -#endif , m_modifiedAfterFind(false) { m_pluralTabBar->hide(); m_sourceTextEdit->setWhatsThis(i18n("

Original String

\n" "

This part of the window shows the original message\n" "of the currently displayed entry.

")); m_sourceTextEdit->viewport()->setBackgroundRole(QPalette::Background); m_sourceTextEdit->setVisualizeSeparators(Settings::self()->visualizeSeparators()); m_targetTextEdit->setVisualizeSeparators(Settings::self()->visualizeSeparators()); connect(m_targetTextEdit, &TranslationUnitTextEdit::contentsModified, this, &EditorView::resetFindForCurrent); connect(m_targetTextEdit, &TranslationUnitTextEdit::toggleApprovementRequested, this, &EditorView::toggleApprovement); connect(this, &EditorView::signalApprovedEntryDisplayed, m_targetTextEdit, &TranslationUnitTextEdit::reflectApprovementState); connect(m_sourceTextEdit, &TranslationUnitTextEdit::tagInsertRequested, m_targetTextEdit, &TranslationUnitTextEdit::insertTag); connect(m_sourceTextEdit, &TranslationUnitTextEdit::binaryUnitSelectRequested, this, &EditorView::binaryUnitSelectRequested); connect(m_targetTextEdit, &TranslationUnitTextEdit::binaryUnitSelectRequested, this, &EditorView::binaryUnitSelectRequested); connect(m_sourceTextEdit, &TranslationUnitTextEdit::gotoEntryRequested, this, &EditorView::gotoEntryRequested); connect(m_targetTextEdit, &TranslationUnitTextEdit::gotoEntryRequested, this, &EditorView::gotoEntryRequested); connect(m_sourceTextEdit, &TranslationUnitTextEdit::tmLookupRequested, this, &EditorView::tmLookupRequested); connect(m_targetTextEdit, &TranslationUnitTextEdit::tmLookupRequested, this, &EditorView::tmLookupRequested); connect(m_sourceTextEdit, &TranslationUnitTextEdit::findRequested, this, &EditorView::findRequested); connect(m_targetTextEdit, &TranslationUnitTextEdit::findRequested, this, &EditorView::findRequested); connect(m_sourceTextEdit, &TranslationUnitTextEdit::findNextRequested, this, &EditorView::findNextRequested); connect(m_targetTextEdit, &TranslationUnitTextEdit::findNextRequested, this, &EditorView::findNextRequested); connect(m_sourceTextEdit, &TranslationUnitTextEdit::replaceRequested, this, &EditorView::replaceRequested); connect(m_targetTextEdit, &TranslationUnitTextEdit::replaceRequested, this, &EditorView::replaceRequested); connect(this, &EditorView::doExplicitCompletion, m_targetTextEdit, &TranslationUnitTextEdit::doExplicitCompletion); addWidget(m_pluralTabBar); addWidget(m_sourceTextEdit); addWidget(m_targetTextEdit); QWidget::setTabOrder(m_targetTextEdit, m_sourceTextEdit); QWidget::setTabOrder(m_sourceTextEdit, m_targetTextEdit); setFocusProxy(m_targetTextEdit); // QTimer::singleShot(3000,this,SLOT(setupWhatsThis())); settingsChanged(); } EditorView::~EditorView() { } void EditorView::resetFindForCurrent(const DocPosition& pos) { m_modifiedAfterFind = true; emit signalChanged(pos.entry); } void EditorView::settingsChanged() { //Settings::self()->config()->setGroup("Editor"); m_sourceTextEdit->document()->setDefaultFont(Settings::msgFont()); m_targetTextEdit->document()->setDefaultFont(Settings::msgFont()); m_sourceTextEdit->setVisualizeSeparators(Settings::self()->visualizeSeparators()); m_targetTextEdit->setVisualizeSeparators(Settings::self()->visualizeSeparators()); -#ifndef NOKDE if (m_leds) m_leds->setVisible(Settings::leds()); else if (Settings::leds()) { m_leds = new LedsWidget(this); insertWidget(2, m_leds); connect(m_targetTextEdit, &TranslationUnitTextEdit::cursorPositionChanged, m_leds, &LedsWidget::cursorPositionChanged); connect(m_targetTextEdit, &TranslationUnitTextEdit::nonApprovedEntryDisplayed, m_leds->ledFuzzy, &KLed::on); connect(m_targetTextEdit, &TranslationUnitTextEdit::approvedEntryDisplayed, m_leds->ledFuzzy, &KLed::off); connect(m_targetTextEdit, &TranslationUnitTextEdit::untranslatedEntryDisplayed, m_leds->ledUntr, &KLed::on); connect(m_targetTextEdit, &TranslationUnitTextEdit::translatedEntryDisplayed, m_leds->ledUntr, &KLed::off); m_targetTextEdit->showPos(m_targetTextEdit->currentPos()); } -#endif } void EditorView::gotoEntry() { return gotoEntry(DocPosition(), 0); } //main function in this file :) void EditorView::gotoEntry(DocPosition pos, int selection) { setUpdatesEnabled(false); bool refresh = (pos.entry == -1); if (refresh) pos = m_targetTextEdit->currentPos(); //qCWarning(LOKALIZE_LOG)<<"refresh"<isPlural(pos.entry))) { if (Q_UNLIKELY(m_catalog->numberOfPluralForms() != m_pluralTabBar->count())) { int i = m_pluralTabBar->count(); if (m_catalog->numberOfPluralForms() > m_pluralTabBar->count()) while (i < m_catalog->numberOfPluralForms()) m_pluralTabBar->addTab(i18nc("@title:tab", "Plural Form %1", ++i)); else while (i > m_catalog->numberOfPluralForms()) m_pluralTabBar->removeTab(i--); } m_pluralTabBar->show(); m_pluralTabBar->blockSignals(true); m_pluralTabBar->setCurrentIndex(pos.form); m_pluralTabBar->blockSignals(false); } else m_pluralTabBar->hide(); //bool keepCursor=DocPos(pos)==DocPos(_msgidEdit->currentPos()); bool keepCursor = false; CatalogString sourceWithTags = m_sourceTextEdit->showPos(pos, CatalogString(), keepCursor); //qCWarning(LOKALIZE_LOG)<<"calling showPos"; QString targetString = m_targetTextEdit->showPos(pos, sourceWithTags, keepCursor).string; //qCWarning(LOKALIZE_LOG)<<"ss"<<_msgstrEdit->textCursor().anchor()<<_msgstrEdit->textCursor().position(); m_sourceTextEdit->cursorToStart(); m_targetTextEdit->cursorToStart(); bool untrans = targetString.isEmpty(); //qCWarning(LOKALIZE_LOG)<<"ss1"<<_msgstrEdit->textCursor().anchor()<<_msgstrEdit->textCursor().position(); if (pos.offset || selection) { TranslationUnitTextEdit* msgEdit = (pos.part == DocPosition::Source ? m_sourceTextEdit : m_targetTextEdit); QTextCursor t = msgEdit->textCursor(); t.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, pos.offset); //NOTE this was kinda bug due to on-the-fly msgid wordwrap if (selection) t.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, selection); msgEdit->setTextCursor(t); } else if (!untrans) { QTextCursor t = m_targetTextEdit->textCursor(); //what if msg starts with a tag? if (Q_UNLIKELY(targetString.startsWith('<'))) { int offset = targetString.indexOf(QRegExp(QStringLiteral(">[^<]"))); if (offset != -1) t.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, offset + 1); } else if (Q_UNLIKELY(targetString.startsWith(TAGRANGE_IMAGE_SYMBOL))) { int offset = targetString.indexOf(QRegExp(QStringLiteral("[^") % QChar(TAGRANGE_IMAGE_SYMBOL) % ']')); if (offset != -1) t.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, offset + 1); } m_targetTextEdit->setTextCursor(t); } //qCWarning(LOKALIZE_LOG)<<"set-->"<<_msgstrEdit->textCursor().anchor()<<_msgstrEdit->textCursor().position(); //qCWarning(LOKALIZE_LOG)<<"anchor"<setFocus(); setUpdatesEnabled(true); } //BEGIN edit actions that are easier to do in this class void EditorView::unwrap() { unwrap(0); } void EditorView::unwrap(TranslationUnitTextEdit* editor) { if (!editor) editor = m_targetTextEdit; QTextCursor t = editor->document()->find(QRegExp("[^(\\\\n)]$")); if (t.isNull()) return; if (editor == m_targetTextEdit) m_catalog->beginMacro(i18nc("@item Undo action item", "Unwrap")); t.movePosition(QTextCursor::EndOfLine); if (!t.atEnd()) t.deleteChar(); QRegExp rx("[^(\\\\n)>]$"); //remove '\n's skipping "\\\\n" while (!(t = editor->document()->find(rx, t)).isNull()) { t.movePosition(QTextCursor::EndOfLine); if (!t.atEnd()) t.deleteChar(); } if (editor == m_targetTextEdit) m_catalog->endMacro(); } void EditorView::insertTerm(const QString& term) { m_targetTextEdit->insertPlainText(term); m_targetTextEdit->setFocus(); } QString EditorView::selectionInTarget() const { //TODO remove IMAGES return m_targetTextEdit->textCursor().selectedText(); } QString EditorView::selectionInSource() const { //TODO remove IMAGES return m_sourceTextEdit->textCursor().selectedText(); } void EditorView::setProperFocus() { m_targetTextEdit->setFocus(); } //END edit actions that are easier to do in this class QObject* EditorView::viewPort() { return m_targetTextEdit; } void EditorView::toggleBookmark(bool checked) { if (Q_UNLIKELY(m_targetTextEdit->currentPos().entry == -1)) return; m_catalog->setBookmark(m_targetTextEdit->currentPos().entry, checked); } void EditorView::toggleApprovement() { //qCWarning(LOKALIZE_LOG)<<"called"; if (Q_UNLIKELY(m_targetTextEdit->currentPos().entry == -1)) return; bool newState = !m_catalog->isApproved(m_targetTextEdit->currentPos().entry); SetStateCmd::push(m_catalog, m_targetTextEdit->currentPos(), newState); emit signalApprovedEntryDisplayed(newState); } void EditorView::setState(TargetState state) { if (Q_UNLIKELY(m_targetTextEdit->currentPos().entry == -1 || m_catalog->state(m_targetTextEdit->currentPos()) == state)) return; SetStateCmd::instantiateAndPush(m_catalog, m_targetTextEdit->currentPos(), state); emit signalApprovedEntryDisplayed(m_catalog->isApproved(m_targetTextEdit->currentPos())); } void EditorView::setEquivTrans(bool equivTrans) { m_catalog->push(new SetEquivTransCmd(m_catalog, m_targetTextEdit->currentPos(), equivTrans)); } diff --git a/src/editorview.h b/src/editorview.h index 404bf0e..37dea3d 100644 --- a/src/editorview.h +++ b/src/editorview.h @@ -1,142 +1,140 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2009 by Nick Shaforostoff 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 EDITORVIEW_H #define EDITORVIEW_H #include "pos.h" #include "state.h" #include "catalogstring.h" #include class Catalog; class LedsWidget; class TranslationUnitTextEdit; class QTabBar; class QContextMenuEvent; class QDragEnterEvent; /** * This is the main view class for Lokalize Editor. * Most of the non-menu, non-toolbar, non-statusbar, * and non-dockview editing GUI code should go here. * * There are several ways (for views) to modify current msg: * -modify KTextEdit and changes will be applied to catalog automatically (plus you need to care of fuzzy indication etc) * -modify catalog directly, then call EditorWindow::gotoEntry slot * I used both :) * * @short Main editor view: source and target textedits * @author Nick Shaforostoff */ class EditorView: public QSplitter { Q_OBJECT public: EditorView(QWidget *, Catalog*); virtual ~EditorView(); QTabBar* tabBar() { return m_pluralTabBar; //to connect tabbar signals to controller (EditorWindow) slots } QString selectionInTarget() const;//for non-batch replace QString selectionInSource() const; QObject* viewPort(); void setProperFocus(); public slots: void gotoEntry(DocPosition pos, int selection/*, bool updateHistory=true*/); void gotoEntry(); void toggleApprovement(); void setState(TargetState); void setEquivTrans(bool); void settingsChanged(); void insertTerm(const QString&); //workaround for qt ctrl+z bug //Edit menu void unwrap(); void unwrap(TranslationUnitTextEdit* editor); /* void dragEnterEvent(QDragEnterEvent* event); void dropEvent(QDropEvent*); */ private: Catalog* m_catalog; TranslationUnitTextEdit * m_sourceTextEdit; TranslationUnitTextEdit * m_targetTextEdit ; QTabBar* m_pluralTabBar; LedsWidget* m_leds; public: bool m_modifiedAfterFind;//for F3-search reset signals: void signalEquivTranslatedEntryDisplayed(bool); void signalApprovedEntryDisplayed(bool); void signalChangeStatusbar(const QString&); void signalChanged(uint index); //esp for mergemode... void binaryUnitSelectRequested(const QString& id); void gotoEntryRequested(const DocPosition&); void tmLookupRequested(DocPosition::Part, const QString&); //void tmLookupRequested(const QString& source, const QString& target); void findRequested(); void findNextRequested(); void replaceRequested(); void doExplicitCompletion(); private slots: void resetFindForCurrent(const DocPosition& pos); void toggleBookmark(bool); }; -#ifndef NOKDE class KLed; class QLabel; class LedsWidget: public QWidget { Q_OBJECT public: LedsWidget(QWidget* parent); private: void contextMenuEvent(QContextMenuEvent* event); public slots: void cursorPositionChanged(int column); public: KLed* ledFuzzy; KLed* ledUntr; QLabel* lblColumn; }; -#endif #endif diff --git a/src/filesearch/filesearchtab.cpp b/src/filesearch/filesearchtab.cpp index b010844..89081f8 100644 --- a/src/filesearch/filesearchtab.cpp +++ b/src/filesearch/filesearchtab.cpp @@ -1,929 +1,921 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2014 by Nick Shaforostoff 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 "filesearchtab.h" #include "lokalize_debug.h" #include "ui_filesearchoptions.h" #include "ui_massreplaceoptions.h" #include "project.h" #include "prefs.h" #include "tmscanapi.h" //TODO separate some decls into new header #include "state.h" #include "qaview.h" #include "catalog.h" #include "fastsizehintitemdelegate.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#ifndef NOKDE #include #include #include -#endif static QStringList doScanRecursive(const QDir& dir); class FileListModel: public QStringListModel { public: FileListModel(QObject* parent): QStringListModel(parent) {} QVariant data(const QModelIndex& item, int role = Qt::DisplayRole) const; Qt::ItemFlags flags(const QModelIndex&) const { return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } }; QVariant FileListModel::data(const QModelIndex& item, int role) const { if (role == Qt::DisplayRole) return shorterFilePath(stringList().at(item.row())); if (role == Qt::UserRole) return stringList().at(item.row()); return QVariant(); } SearchFileListView::SearchFileListView(QWidget* parent) : QDockWidget(i18nc("@title:window", "File List"), parent) , m_browser(new QTreeView(this)) , m_background(new QLabel(i18n("Drop translation files here..."), this)) , m_model(new FileListModel(this)) { setWidget(m_background); m_background->setMinimumWidth(QFontMetrics(font()).averageCharWidth() * 30); m_background->setAlignment(Qt::AlignCenter); m_browser->hide(); m_browser->setModel(m_model); m_browser->setRootIsDecorated(false); m_browser->setHeaderHidden(true); m_browser->setUniformRowHeights(true); m_browser->setAlternatingRowColors(true); m_browser->setContextMenuPolicy(Qt::ActionsContextMenu); QAction* action = new QAction(i18nc("@action:inmenu", "Clear"), m_browser); connect(action, &QAction::triggered, this, &SearchFileListView::clear); m_browser->addAction(action); connect(m_browser, &QTreeView::activated, this, &SearchFileListView::requestFileOpen); } void SearchFileListView::requestFileOpen(const QModelIndex& item) { emit fileOpenRequested(item.data(Qt::UserRole).toString(), true); } void SearchFileListView::addFiles(const QStringList& files) { if (files.isEmpty()) return; m_background->hide(); setWidget(m_browser); m_browser->show(); //ensure unquiness, sorting the list along the way QMap map; foreach (const QString& filepath, m_model->stringList()) map[filepath] = true; foreach (const QString& filepath, files) map[filepath] = true; m_model->setStringList(map.keys()); } void SearchFileListView::addFilesFast(const QStringList& files) { if (files.size()) m_model->setStringList(m_model->stringList() + files); } void SearchFileListView::clear() { m_model->setStringList(QStringList()); } QStringList SearchFileListView::files() const { return m_model->stringList(); } void SearchFileListView::scrollTo(const QString& file) { if (file.isEmpty()) { m_browser->scrollToTop(); return; } int idx = m_model->stringList().indexOf(file); if (idx != -1) m_browser->scrollTo(m_model->index(idx, 0), QAbstractItemView::PositionAtCenter); } bool SearchParams::isEmpty() const { return sourcePattern.pattern().isEmpty() && targetPattern.pattern().isEmpty(); } SearchJob::SearchJob(const QStringList& f, const SearchParams& sp, const QVector& r, int sn, QObject*) : QRunnable() , files(f) , searchParams(sp) , rules(r) , searchNumber(sn) , m_size(0) { setAutoDelete(false); } void SearchJob::run() { QTime a; a.start(); bool removeAmpFromSource = searchParams.sourcePattern.patternSyntax() == QRegExp::FixedString && !searchParams.sourcePattern.pattern().contains(QLatin1Char('&')); bool removeAmpFromTarget = searchParams.targetPattern.patternSyntax() == QRegExp::FixedString && !searchParams.targetPattern.pattern().contains(QLatin1Char('&')); foreach (const QString& filePath, files) { Catalog catalog(0); if (Q_UNLIKELY(catalog.loadFromUrl(filePath, QString(), &m_size, true) != 0)) continue; //QVector catalogResults; int numberOfEntries = catalog.numberOfEntries(); DocPosition pos(0); for (; pos.entry < numberOfEntries; pos.entry++) { //if (!searchParams.states[catalog.state(pos)]) // return false; int lim = catalog.isPlural(pos.entry) ? catalog.numberOfPluralForms() : 1; for (pos.form = 0; pos.form < lim; pos.form++) { int sp = 0; int tp = 0; if (!searchParams.sourcePattern.isEmpty()) sp = searchParams.sourcePattern.indexIn(removeAmpFromSource ? catalog.source(pos).remove(QLatin1Char('&')) : catalog.source(pos)); if (!searchParams.targetPattern.isEmpty()) tp = searchParams.targetPattern.indexIn(removeAmpFromTarget ? catalog.target(pos).remove(QLatin1Char('&')) : catalog.target(pos)); //int np=searchParams.notesPattern.indexIn(catalog.notes(pos)); if ((sp != -1) != searchParams.invertSource && (tp != -1) != searchParams.invertTarget) { //TODO handle multiple results in same column //FileSearchResult r; SearchResult r; r.filepath = filePath; r.docPos = pos; if (!searchParams.sourcePattern.isEmpty() && !searchParams.invertSource) r.sourcePositions << StartLen(searchParams.sourcePattern.pos(), searchParams.sourcePattern.matchedLength()); if (!searchParams.targetPattern.isEmpty() && !searchParams.invertTarget) r.targetPositions << StartLen(searchParams.targetPattern.pos(), searchParams.targetPattern.matchedLength()); r.source = catalog.source(pos); r.target = catalog.target(pos); r.state = catalog.state(pos); r.isApproved = catalog.isApproved(pos); //r.activePhase=catalog.activePhase(); if (rules.size()) { QVector positions(2); int matchedQaRule = findMatchingRule(rules, r.source, r.target, positions); if (matchedQaRule == -1) continue; if (positions.at(0).len) r.sourcePositions << positions.at(0); if (positions.at(1).len) r.targetPositions << positions.at(1); } r.sourcePositions.squeeze(); r.targetPositions.squeeze(); //catalogResults< map; for (int i = 0; i < searchResults.count(); ++i) map.insertMulti(searchResults.at(i).filepath, i); foreach (const QString& filepath, map.keys()) { Catalog catalog(QThread::currentThread()); if (catalog.loadFromUrl(filepath, QString()) != 0) continue; foreach (int index, map.values(filepath)) { SearchResult& sr = searchResults[index]; DocPosition docPos = sr.docPos.toDocPosition(); if (catalog.target(docPos) != sr.target) { qCWarning(LOKALIZE_LOG) << "skipping replace because" << catalog.target(docPos) << "!=" << sr.target; continue; } CatalogString s = catalog.targetWithTags(docPos); int pos = replaceWhat.indexIn(s.string); while (pos != -1) { if (!s.string.midRef(pos, replaceWhat.matchedLength()).contains(TAGRANGE_IMAGE_SYMBOL)) { docPos.offset = pos; catalog.targetDelete(docPos, replaceWhat.matchedLength()); catalog.targetInsert(docPos, replaceWith); s.string.replace(pos, replaceWhat.matchedLength(), replaceWith); pos += replaceWith.length(); } else { pos += replaceWhat.matchedLength(); qCWarning(LOKALIZE_LOG) << "skipping replace because matched text contains markup" << s.string; } if (pos > s.string.length() || replaceWhat.pattern().startsWith('^')) break; pos = replaceWhat.indexIn(s.string, pos); } } catalog.save(); } } //BEGIN FileSearchModel FileSearchModel::FileSearchModel(QObject* parent) : QAbstractListModel(parent) { } QVariant FileSearchModel::headerData(int section, Qt::Orientation, int role) const { if (role != Qt::DisplayRole) return QVariant(); switch (section) { case FileSearchModel::Source: return i18nc("@title:column Original text", "Source"); case FileSearchModel::Target: return i18nc("@title:column Text in target language", "Target"); //case FileSearchModel::Context: return i18nc("@title:column","Context"); case FileSearchModel::Filepath: return i18nc("@title:column", "File"); case FileSearchModel::TranslationStatus: return i18nc("@title:column", "Translation Status"); } return QVariant(); } void FileSearchModel::appendSearchResults(const SearchResults& results) { beginInsertRows(QModelIndex(), m_searchResults.size(), m_searchResults.size() + results.size() - 1); m_searchResults += results; endInsertRows(); } void FileSearchModel::clear() { beginResetModel(); m_searchResults.clear();; endResetModel(); } QVariant FileSearchModel::data(const QModelIndex& item, int role) const { bool doHtml = (role == FastSizeHintItemDelegate::HtmlDisplayRole); if (doHtml) role = Qt::DisplayRole; if (role == Qt::DisplayRole) { QString result; const SearchResult& sr = m_searchResults.at(item.row()); if (item.column() == Source) result = sr.source; if (item.column() == Target) result = sr.target; if (item.column() == Filepath) result = shorterFilePath(sr.filepath); if (doHtml && item.column() <= FileSearchModel::Target) { if (result.isEmpty()) return result; const QString startBld = QStringLiteral("_ST_"); const QString endBld = QStringLiteral("_END_"); const QString startBldTag = QStringLiteral(""); const QString endBldTag = QStringLiteral(""); if (item.column() == FileSearchModel::Target && !m_replaceWhat.isEmpty()) { result.replace(m_replaceWhat, m_replaceWith); QString escaped = convertToHtml(result, !sr.isApproved); escaped.replace(startBld, startBldTag); escaped.replace(endBld, endBldTag); return escaped; } const QVector& occurrences = item.column() == FileSearchModel::Source ? sr.sourcePositions : sr.targetPositions; int occ = occurrences.count(); while (--occ >= 0) { const StartLen& sl = occurrences.at(occ); result.insert(sl.start + sl.len, endBld); result.insert(sl.start, startBld); } /* !isApproved(sr.state, Project::instance()->local()->role())*/ QString escaped = convertToHtml(result, item.column() == FileSearchModel::Target && !sr.isApproved); escaped.replace(startBld, startBldTag); escaped.replace(endBld, endBldTag); return escaped; } return result; } if (role == Qt::UserRole) { const SearchResult& sr = m_searchResults.at(item.row()); if (item.column() == Filepath) return sr.filepath; } return QVariant(); } void FileSearchModel::setReplacePreview(const QRegExp& s, const QString& r) { m_replaceWhat = s; m_replaceWith = QLatin1String("_ST_") % r % QLatin1String("_END_"); emit dataChanged(index(0, Target), index(rowCount() - 1, Target)); } //END FileSearchModel //BEGIN FileSearchTab FileSearchTab::FileSearchTab(QWidget *parent) : LokalizeSubwindowBase2(parent) // , m_proxyModel(new TMResultsSortFilterProxyModel(this)) , m_model(new FileSearchModel(this)) , m_lastSearchNumber(0) , m_dbusId(-1) { setWindowTitle(i18nc("@title:window", "Search and replace in files")); setAcceptDrops(true); QWidget* w = new QWidget(this); ui_fileSearchOptions = new Ui_FileSearchOptions; ui_fileSearchOptions->setupUi(w); setCentralWidget(w); QShortcut* sh = new QShortcut(Qt::CTRL + Qt::Key_L, this); connect(sh, &QShortcut::activated, ui_fileSearchOptions->querySource, QOverload<>::of(&QLineEdit::setFocus)); setFocusProxy(ui_fileSearchOptions->querySource); sh = new QShortcut(Qt::Key_Escape, this, SLOT(stopSearch()), 0, Qt::WidgetWithChildrenShortcut); QTreeView* view = ui_fileSearchOptions->treeView; QVector singleLineColumns(FileSearchModel::ColumnCount, false); singleLineColumns[FileSearchModel::Filepath] = true; singleLineColumns[FileSearchModel::TranslationStatus] = true; //singleLineColumns[TMDBModel::Context]=true; QVector richTextColumns(FileSearchModel::ColumnCount, false); richTextColumns[FileSearchModel::Source] = true; richTextColumns[FileSearchModel::Target] = true; view->setItemDelegate(new FastSizeHintItemDelegate(this, singleLineColumns, richTextColumns)); connect(m_model, &FileSearchModel::modelReset, (FastSizeHintItemDelegate*)view->itemDelegate(), &FastSizeHintItemDelegate::reset); connect(m_model, &FileSearchModel::dataChanged, (FastSizeHintItemDelegate*)view->itemDelegate(), &FastSizeHintItemDelegate::reset); //connect(m_model,SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),view->itemDelegate(),SLOT(reset())); //connect(m_proxyModel,SIGNAL(layoutChanged()),view->itemDelegate(),SLOT(reset())); //connect(m_proxyModel,SIGNAL(layoutChanged()),this,SLOT(displayTotalResultCount())); view->setContextMenuPolicy(Qt::ActionsContextMenu); QAction* a = new QAction(i18n("Copy source to clipboard"), view); a->setShortcut(Qt::CTRL + Qt::Key_S); a->setShortcutContext(Qt::WidgetWithChildrenShortcut); connect(a, &QAction::triggered, this, &FileSearchTab::copySourceToClipboard); view->addAction(a); a = new QAction(i18n("Copy target to clipboard"), view); a->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return)); a->setShortcutContext(Qt::WidgetWithChildrenShortcut); connect(a, &QAction::triggered, this, &FileSearchTab::copyTargetToClipboard); view->addAction(a); a = new QAction(i18n("Open file"), view); a->setShortcut(QKeySequence(Qt::Key_Return)); a->setShortcutContext(Qt::WidgetWithChildrenShortcut); connect(a, &QAction::triggered, this, &FileSearchTab::openFile); connect(view, &QTreeView::activated, this, &FileSearchTab::openFile); view->addAction(a); connect(ui_fileSearchOptions->querySource, &QLineEdit::returnPressed, this, &FileSearchTab::performSearch); connect(ui_fileSearchOptions->queryTarget, &QLineEdit::returnPressed, this, &FileSearchTab::performSearch); connect(ui_fileSearchOptions->doFind, &QPushButton::clicked, this, &FileSearchTab::performSearch); // m_proxyModel->setDynamicSortFilter(true); // m_proxyModel->setSourceModel(m_model); view->setModel(m_model); // view->setModel(m_proxyModel); // view->sortByColumn(FileSearchModel::Filepath,Qt::AscendingOrder); // view->setSortingEnabled(true); // view->setItemDelegate(new FastSizeHintItemDelegate(this)); // connect(m_model,SIGNAL(resultsFetched()),view->itemDelegate(),SLOT(reset())); // connect(m_model,SIGNAL(modelReset()),view->itemDelegate(),SLOT(reset())); // connect(m_proxyModel,SIGNAL(layoutChanged()),view->itemDelegate(),SLOT(reset())); // connect(m_proxyModel,SIGNAL(layoutChanged()),this,SLOT(displayTotalResultCount())); //BEGIN resizeColumnToContents static const int maxInitialWidths[] = {QApplication::desktop()->availableGeometry().width() / 3, QApplication::desktop()->availableGeometry().width() / 3}; int column = sizeof(maxInitialWidths) / sizeof(int); while (--column >= 0) view->setColumnWidth(column, maxInitialWidths[column]); //END resizeColumnToContents int i = 6; while (--i > ID_STATUS_PROGRESS) statusBarItems.insert(i, QString()); -#ifndef NOKDE setXMLFile(QStringLiteral("filesearchtabui.rc"), true); dbusObjectPath(); -#endif KActionCollection* ac = actionCollection(); KActionCategory* srf = new KActionCategory(i18nc("@title actions category", "Search and replace in files"), ac); m_searchFileListView = new SearchFileListView(this); //m_searchFileListView->hide(); addDockWidget(Qt::RightDockWidgetArea, m_searchFileListView); srf->addAction(QStringLiteral("showfilelist_action"), m_searchFileListView->toggleViewAction()); connect(m_searchFileListView, &SearchFileListView::fileOpenRequested, this, QOverload::of(&FileSearchTab::fileOpenRequested)); m_massReplaceView = new MassReplaceView(this); addDockWidget(Qt::RightDockWidgetArea, m_massReplaceView); srf->addAction(QStringLiteral("showmassreplace_action"), m_massReplaceView->toggleViewAction()); connect(m_massReplaceView, &MassReplaceView::previewRequested, m_model, &FileSearchModel::setReplacePreview); connect(m_massReplaceView, &MassReplaceView::replaceRequested, this, &FileSearchTab::massReplace); //m_massReplaceView->hide(); m_qaView = new QaView(this); m_qaView->hide(); addDockWidget(Qt::RightDockWidgetArea, m_qaView); srf->addAction(QStringLiteral("showqa_action"), m_qaView->toggleViewAction()); connect(m_qaView, &QaView::rulesChanged, this, &FileSearchTab::performSearch); connect(m_qaView->toggleViewAction(), &QAction::toggled, this, &FileSearchTab::performSearch, Qt::QueuedConnection); view->header()->restoreState(readUiState("FileSearchResultsHeaderState")); } FileSearchTab::~FileSearchTab() { stopSearch(); writeUiState("FileSearchResultsHeaderState", ui_fileSearchOptions->treeView->header()->saveState()); -#ifndef NOKDE ids.removeAll(m_dbusId); -#endif } void FileSearchTab::performSearch() { if (m_searchFileListView->files().isEmpty()) { addFilesToSearch(doScanRecursive(QDir(Project::instance()->poDir()))); if (m_searchFileListView->files().isEmpty()) return; } m_model->clear(); statusBarItems.insert(1, QString()); m_searchFileListView->scrollTo(); m_lastSearchNumber++; SearchParams sp; sp.sourcePattern.setPattern(ui_fileSearchOptions->querySource->text()); sp.targetPattern.setPattern(ui_fileSearchOptions->queryTarget->text()); sp.invertSource = ui_fileSearchOptions->invertSource->isChecked(); sp.invertTarget = ui_fileSearchOptions->invertTarget->isChecked(); QVector rules = m_qaView->isVisible() ? m_qaView->rules() : QVector(); if (sp.isEmpty() && rules.isEmpty()) return; if (!ui_fileSearchOptions->regEx->isChecked()) { sp.sourcePattern.setPatternSyntax(QRegExp::FixedString); sp.targetPattern.setPatternSyntax(QRegExp::FixedString); } /* else { sp.sourcePattern.setMinimal(true); sp.targetPattern.setMinimal(true); } */ stopSearch(); m_massReplaceView->deactivatePreview(); QStringList files = m_searchFileListView->files(); for (int i = 0; i < files.size(); i += 100) { QStringList batch; int lim = qMin(files.size(), i + 100); for (int j = i; j < lim; j++) batch.append(files.at(j)); SearchJob* job = new SearchJob(batch, sp, rules, m_lastSearchNumber); QObject::connect(job, &SearchJob::done, this, &FileSearchTab::searchJobDone); QThreadPool::globalInstance()->start(job); m_runningJobs.append(job); } } void FileSearchTab::stopSearch() { #if QT_VERSION >= 0x050500 int i = m_runningJobs.size(); while (--i >= 0) QThreadPool::globalInstance()->cancel(m_runningJobs.at(i)); #endif m_runningJobs.clear(); } void FileSearchTab::massReplace(const QRegExp &what, const QString& with) { #define BATCH_SIZE 20 SearchResults searchResults = m_model->searchResults(); for (int i = 0; i < searchResults.count(); i += BATCH_SIZE) { int last = qMin(i + BATCH_SIZE, searchResults.count() - 1); QString filepath = searchResults.at(last).filepath; while (last + 1 < searchResults.count() && filepath == searchResults.at(last + 1).filepath) ++last; MassReplaceJob* job = new MassReplaceJob(searchResults.mid(i, last + 1 - i), i, what, with); QObject::connect(job, &MassReplaceJob::done, this, &FileSearchTab::replaceJobDone); QThreadPool::globalInstance()->start(job); m_runningJobs.append(job); } } static void copy(QTreeView* view, int column) { QApplication::clipboard()->setText(view->currentIndex().sibling(view->currentIndex().row(), column).data().toString()); } void FileSearchTab::copySourceToClipboard() { copy(ui_fileSearchOptions->treeView, FileSearchModel::Source); } void FileSearchTab::copyTargetToClipboard() { copy(ui_fileSearchOptions->treeView, FileSearchModel::Target); } void FileSearchTab::openFile() { QModelIndex item = ui_fileSearchOptions->treeView->currentIndex(); SearchResult sr = m_model->searchResult(item); DocPosition docPos = sr.docPos.toDocPosition(); int selection = 0; if (sr.targetPositions.size()) { docPos.offset = sr.targetPositions.first().start; selection = sr.targetPositions.first().len; } qCDebug(LOKALIZE_LOG) << "fileOpenRequest" << docPos.offset << selection; emit fileOpenRequested(sr.filepath, docPos, selection, true); } void FileSearchTab::fileSearchNext() { QModelIndex item = ui_fileSearchOptions->treeView->currentIndex(); int row = item.row(); int rowCount = m_model->rowCount(); if (++row >= rowCount) //ok if row was -1 (no solection) return; ui_fileSearchOptions->treeView->setCurrentIndex(item.sibling(row, item.column())); openFile(); } QStringList scanRecursive(const QList& urls) { QStringList result; int i = urls.size(); while (--i >= 0) { if (urls.at(i).isEmpty() || urls.at(i).path().isEmpty()) //NOTE is this a Qt bug? continue; QString path = urls.at(i).toLocalFile(); if (Catalog::extIsSupported(path)) result.append(path); else result += doScanRecursive(QDir(path)); } return result; } //returns gross number of jobs started static QStringList doScanRecursive(const QDir& dir) { QStringList result; QStringList subDirs(dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Readable)); int i = subDirs.size(); while (--i >= 0) result += doScanRecursive(QDir(dir.filePath(subDirs.at(i)))); QStringList filters = Catalog::supportedExtensions(); i = filters.size(); while (--i >= 0) filters[i].prepend('*'); QStringList files(dir.entryList(filters, QDir::Files | QDir::NoDotAndDotDot | QDir::Readable)); i = files.size(); while (--i >= 0) result.append(dir.filePath(files.at(i))); return result; } void FileSearchTab::dragEnterEvent(QDragEnterEvent* event) { if (dragIsAcceptable(event->mimeData()->urls())) event->acceptProposedAction(); } void FileSearchTab::dropEvent(QDropEvent *event) { event->acceptProposedAction(); addFilesToSearch(scanRecursive(event->mimeData()->urls())); } void FileSearchTab::addFilesToSearch(const QStringList& files) { m_searchFileListView->addFiles(files); performSearch(); } void FileSearchTab::setSourceQuery(const QString& query) { ui_fileSearchOptions->querySource->setText(query); } void FileSearchTab::setTargetQuery(const QString& query) { ui_fileSearchOptions->queryTarget->setText(query); } void FileSearchTab::searchJobDone(SearchJob* j) { j->deleteLater(); if (j->searchNumber != m_lastSearchNumber) return; /* SearchResults searchResults; FileSearchResults::const_iterator i = j->results.constBegin(); while (i != j->results.constEnd()) { foreach(const FileSearchResult& fsr, i.value()) { SearchResult sr(fsr); sr.filepath=i.key(); searchResults<appendSearchResults(searchResults); */ if (j->results.size()) { m_model->appendSearchResults(j->results); m_searchFileListView->scrollTo(j->results.last().filepath); } statusBarItems.insert(1, i18nc("@info:status message entries", "Total: %1", m_model->rowCount())); //ui_fileSearchOptions->treeView->setFocus(); } void FileSearchTab::replaceJobDone(MassReplaceJob* j) { j->deleteLater(); ui_fileSearchOptions->treeView->scrollTo(m_model->index(j->globalPos + j->searchResults.count(), 0)); } //END FileSearchTab //BEGIN MASS REPLACE MassReplaceView::MassReplaceView(QWidget* parent) : QDockWidget(i18nc("@title:window", "Mass replace"), parent) , ui(new Ui_MassReplaceOptions) { QWidget* base = new QWidget(this); setWidget(base); ui->setupUi(base); connect(ui->doPreview, &QPushButton::toggled, this, &MassReplaceView::requestPreview); connect(ui->doReplace, &QPushButton::clicked, this, &MassReplaceView::requestReplace); /* QLabel* rl=new QLabel(i18n("Replace:"), base); QLineEdit* searchEdit=new QLineEdit(base); QHBoxLayout* searchL=new QHBoxLayout(); searchL->addWidget(rl); searchL->addWidget(searchEdit); QLabel* wl=new QLabel(i18n("With:"), base); wl->setAlignment(Qt::AlignRight); wl->setMinimumSize(rl->minimumSizeHint()); QLineEdit* replacementEdit=new QLineEdit(base); QHBoxLayout* replacementL=new QHBoxLayout(); replacementL->addWidget(wl); replacementL->addWidget(replacementEdit); FlowLayout* fl=new FlowLayout(); fl->addItem(searchL); fl->addItem(replacementL); base->setLayout(fl); */ } MassReplaceView::~MassReplaceView() { delete ui; } static QRegExp regExpFromUi(const QString& s, Ui_MassReplaceOptions* ui) { return QRegExp(s, ui->matchCase->isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive, ui->useRegExps->isChecked() ? QRegExp::FixedString : QRegExp::RegExp); } void MassReplaceView::requestPreviewUpdate() { QString s = ui->searchText->text(); QString r = ui->replaceText->text(); if (s.length()) ui->doReplace->setEnabled(true); emit previewRequested(regExpFromUi(s, ui), r); } void MassReplaceView::requestPreview(bool enable) { if (enable) { connect(ui->searchText, &QLineEdit::textEdited, this, &MassReplaceView::requestPreviewUpdate); connect(ui->replaceText, &QLineEdit::textEdited, this, &MassReplaceView::requestPreviewUpdate); connect(ui->useRegExps, &QCheckBox::toggled, this, &MassReplaceView::requestPreviewUpdate); connect(ui->matchCase, &QCheckBox::toggled, this, &MassReplaceView::requestPreviewUpdate); requestPreviewUpdate(); } else { disconnect(ui->searchText, &QLineEdit::textEdited, this, &MassReplaceView::requestPreviewUpdate); disconnect(ui->replaceText, &QLineEdit::textEdited, this, &MassReplaceView::requestPreviewUpdate); disconnect(ui->useRegExps, &QCheckBox::toggled, this, &MassReplaceView::requestPreviewUpdate); disconnect(ui->matchCase, &QCheckBox::toggled, this, &MassReplaceView::requestPreviewUpdate); emit previewRequested(QRegExp(), QString()); } } void MassReplaceView::requestReplace() { QString s = ui->searchText->text(); QString r = ui->replaceText->text(); if (s.isEmpty()) return; emit replaceRequested(regExpFromUi(s, ui), r); } void MassReplaceView::deactivatePreview() { ui->doPreview->setChecked(false); ui->doReplace->setEnabled(false); } -#ifndef NOKDE #include "filesearchadaptor.h" #include QList FileSearchTab::ids; //BEGIN DBus interface QString FileSearchTab::dbusObjectPath() { QString FILESEARCH_PATH = QStringLiteral("/ThisIsWhatYouWant/FileSearch/"); if (m_dbusId == -1) { new FileSearchAdaptor(this); int i = 0; while (i < ids.size() && i == ids.at(i)) ++i; ids.insert(i, i); m_dbusId = i; QDBusConnection::sessionBus().registerObject(FILESEARCH_PATH + QString::number(m_dbusId), this); } return FILESEARCH_PATH + QString::number(m_dbusId); } bool FileSearchTab::findGuiTextPackage(QString text, QString package) { setSourceQuery(text); performSearch(); return true; } //END DBus interface -#endif diff --git a/src/filesearch/filesearchtab.h b/src/filesearch/filesearchtab.h index 864eda9..df27711 100644 --- a/src/filesearch/filesearchtab.h +++ b/src/filesearch/filesearchtab.h @@ -1,337 +1,333 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2012 by Nick Shaforostoff 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 FILESEARCHTAB_H #define FILESEARCHTAB_H #include "lokalizesubwindowbase.h" #include "pos.h" #include "rule.h" #include #include #include #include class MassReplaceJob; class SearchJob; class QRunnable; class QLabel; class QaView; class QStringListModel; class QComboBox; class QTreeView; class QSortFilterProxyModel; class KXMLGUIClient; class FileSearchModel; class SearchFileListView; class MassReplaceView; class Ui_FileSearchOptions; /** * Global file search/repalce tab */ class FileSearchTab: public LokalizeSubwindowBase2 { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.Lokalize.FileSearch") //qdbuscpp2xml -m -s filesearch/filesearchtab.h -o filesearch/org.kde.lokalize.FileSearch.xml public: FileSearchTab(QWidget *parent); ~FileSearchTab(); void hideDocks() {}; void showDocks() {}; -#ifndef NOKDE KXMLGUIClient* guiClient() { return (KXMLGUIClient*)this; } QString dbusObjectPath(); int dbusId() { return m_dbusId; } -#endif public slots: void copySourceToClipboard(); void copyTargetToClipboard(); void openFile(); Q_SCRIPTABLE void performSearch(); Q_SCRIPTABLE void addFilesToSearch(const QStringList&); Q_SCRIPTABLE void setSourceQuery(const QString&); Q_SCRIPTABLE void setTargetQuery(const QString&); -#ifndef NOKDE Q_SCRIPTABLE bool findGuiText(QString text) { return findGuiTextPackage(text, QString()); } Q_SCRIPTABLE bool findGuiTextPackage(QString text, QString package); -#endif void fileSearchNext(); void stopSearch(); void massReplace(const QRegExp &what, const QString& with); private slots: void searchJobDone(SearchJob*); void replaceJobDone(MassReplaceJob*); signals: void fileOpenRequested(const QString& filePath, DocPosition docPos, int selection, const bool setAsActive); void fileOpenRequested(const QString& filePath, const bool setAsActive); private: void dragEnterEvent(QDragEnterEvent* event); void dropEvent(QDropEvent*); private: Ui_FileSearchOptions* ui_fileSearchOptions; FileSearchModel* m_model; //TMResultsSortFilterProxyModel *m_proxyModel; SearchFileListView* m_searchFileListView; MassReplaceView* m_massReplaceView; QaView* m_qaView; QVector m_runningJobs; //to avoid results from previous search showing up in the new one int m_lastSearchNumber; int m_dbusId; static QList ids; }; struct FileSearchResult { DocPos docPos; QString source; QString target; bool isApproved; TargetState state; //Phase activePhase; QVector sourcePositions; QVector targetPositions; //int matchedQaRule; //short notePos; //char noteindex; }; typedef QMap > FileSearchResults; struct SearchResult: public FileSearchResult { QString filepath; SearchResult(const FileSearchResult& fsr): FileSearchResult(fsr) {} SearchResult() {} }; typedef QVector SearchResults; class FileSearchModel: public QAbstractListModel { Q_OBJECT public: enum FileSearchModelColumns { Source = 0, Target, //Context, Filepath, TranslationStatus, //Notes, ColumnCount }; enum Roles { FullPathRole = Qt::UserRole, TransStateRole = Qt::UserRole + 1, HtmlDisplayRole = Qt::UserRole + 2 }; FileSearchModel(QObject* parent); ~FileSearchModel() {} QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; QVariant data(const QModelIndex& item, int role = Qt::DisplayRole) const; int columnCount(const QModelIndex& parent = QModelIndex()) const { Q_UNUSED(parent) return ColumnCount; } int rowCount(const QModelIndex& parent = QModelIndex()) const { Q_UNUSED(parent) return m_searchResults.size(); } SearchResults searchResults()const { return m_searchResults; } SearchResult searchResult(const QModelIndex& item) const { return m_searchResults.at(item.row()); } void appendSearchResults(const SearchResults&); void clear(); public slots: void setReplacePreview(const QRegExp&, const QString&); private: SearchResults m_searchResults; QRegExp m_replaceWhat; QString m_replaceWith; }; class SearchFileListView: public QDockWidget { Q_OBJECT public: SearchFileListView(QWidget*); ~SearchFileListView() {} void addFiles(const QStringList& files); void addFilesFast(const QStringList& files); QStringList files()const; void scrollTo(const QString& file = QString()); public slots: void clear(); void requestFileOpen(const QModelIndex&); signals: void fileOpenRequested(const QString& filePath, const bool setAsActive); private: QTreeView* m_browser; QLabel* m_background; QStringListModel* m_model; }; class Ui_MassReplaceOptions; class MassReplaceView: public QDockWidget { Q_OBJECT public: MassReplaceView(QWidget*); ~MassReplaceView(); void deactivatePreview(); signals: void previewRequested(const QRegExp&, const QString&); void replaceRequested(const QRegExp&, const QString&); private slots: void requestPreview(bool enable); void requestPreviewUpdate(); void requestReplace(); private: Ui_MassReplaceOptions* ui; }; struct SearchParams { QRegExp sourcePattern; QRegExp targetPattern; QRegExp notesPattern; bool invertSource; bool invertTarget; bool states[StateCount]; bool isEmpty() const; SearchParams(): invertSource(false), invertTarget(false) { memset(states, 0, sizeof(states)); } }; #include class SearchJob: public QObject, public QRunnable { Q_OBJECT public: explicit SearchJob(const QStringList& f, const SearchParams& sp, const QVector& r, int sn, QObject* parent = 0); ~SearchJob() {} signals: void done(SearchJob*); protected: void run(); public: QStringList files; SearchParams searchParams; QVector rules; int searchNumber; SearchResults results; //plain int m_size; }; /// @short replace in files class MassReplaceJob: public QObject, public QRunnable { Q_OBJECT public: explicit MassReplaceJob(const SearchResults& srs, int pos, const QRegExp& s, const QString& r, //int sn, QObject* parent = 0); ~MassReplaceJob() {} signals: void done(MassReplaceJob*); protected: void run(); public: SearchResults searchResults; int globalPos; QRegExp replaceWhat; QString replaceWith; }; #endif diff --git a/src/glossary/glossarywindow.cpp b/src/glossary/glossarywindow.cpp index 7bd321f..92b5887 100644 --- a/src/glossary/glossarywindow.cpp +++ b/src/glossary/glossarywindow.cpp @@ -1,574 +1,566 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2014 by Nick Shaforostoff 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 "glossarywindow.h" #include "lokalize_debug.h" #include "glossary.h" #include "project.h" #include "languagelistmodel.h" #include "ui_termedit.h" #include #include -#ifndef NOKDE #include -#endif #include #include #include #include #include #include #include #include #include #include using namespace GlossaryNS; //BEGIN GlossaryTreeView GlossaryTreeView::GlossaryTreeView(QWidget *parent) : QTreeView(parent) { setSortingEnabled(true); sortByColumn(GlossaryModel::English, Qt::AscendingOrder); setItemsExpandable(false); setAllColumnsShowFocus(true); /* setSelectionMode(QAbstractItemView::ExtendedSelection); setSelectionBehavior(QAbstractItemView::SelectRows);*/ } static QByteArray modelIndexToId(const QModelIndex& item) { return item.sibling(item.row(), 0).data(Qt::DisplayRole).toByteArray(); } void GlossaryTreeView::currentChanged(const QModelIndex& current, const QModelIndex&/* previous*/) { if (current.isValid()) { //QModelIndex item=static_cast(model())->mapToSource(current); //emit currentChanged(item.row()); emit currentChanged(modelIndexToId(current)); scrollTo(current); } } void GlossaryTreeView::selectRow(int i) { QSortFilterProxyModel* proxyModel = static_cast(model()); GlossaryModel* sourceModel = static_cast(proxyModel->sourceModel()); //sourceModel->forceReset(); setCurrentIndex(proxyModel->mapFromSource(sourceModel->index(i, 0))); } //END GlossaryTreeView //BEGIN SubjectFieldModel //typedef QStringListModel SubjectFieldModel; #if 0 class SubjectFieldModel: public QAbstractItemModel { public: //Q_OBJECT SubjectFieldModel(QObject* parent); ~SubjectFieldModel() {} QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const; QModelIndex parent(const QModelIndex&) const; int rowCount(const QModelIndex& parent = QModelIndex()) const; int columnCount(const QModelIndex& parent = QModelIndex()) const; QVariant data(const QModelIndex&, int role = Qt::DisplayRole) const; bool setData(const QModelIndex&, const QVariant&, int role = Qt::EditRole); bool setItemData(const QModelIndex& index, const QMap& roles); bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex()); Qt::ItemFlags flags(const QModelIndex&) const; /*private: Catalog* m_catalog;*/ }; inline SubjectFieldModel::SubjectFieldModel(QObject* parent) : QAbstractItemModel(parent) // , m_catalog(catalog) { } QModelIndex SubjectFieldModel::index(int row, int column, const QModelIndex& /*parent*/) const { return createIndex(row, column); } Qt::ItemFlags SubjectFieldModel::flags(const QModelIndex&) const { return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled; } QModelIndex SubjectFieldModel::parent(const QModelIndex& /*index*/) const { return QModelIndex(); } int SubjectFieldModel::columnCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; return 1; } /* inline Qt::ItemFlags SubjectFieldModel::flags ( const QModelIndex & index ) const { if (index.column()==FuzzyFlag) return Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled; return QAbstractItemModel::flags(index); }*/ int SubjectFieldModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; return Project::instance()->glossary()->subjectFields.size(); } QVariant SubjectFieldModel::data(const QModelIndex& index, int role) const { if (role == Qt::DisplayRole || role == Qt::EditRole) return Project::instance()->glossary()->subjectFields.at(index.row()); return QVariant(); } bool SubjectFieldModel::insertRows(int row, int count, const QModelIndex& parent) { beginInsertRows(parent, row, row + count - 1); QStringList& subjectFields = Project::instance()->glossary()->subjectFields; while (--count >= 0) subjectFields.insert(row + count, QString()); endInsertRows(); return true; } bool SubjectFieldModel::setData(const QModelIndex& index, const QVariant& value, int role) { qCDebug(LOKALIZE_LOG) << role; QStringList& subjectFields = Project::instance()->glossary()->subjectFields; subjectFields[index.row()] = value.toString(); return true; } bool SubjectFieldModel::setItemData(const QModelIndex& index, const QMap& roles) { if (roles.contains(Qt::EditRole)) { QStringList& subjectFields = Project::instance()->glossary()->subjectFields; subjectFields[index.row()] = roles.value(Qt::EditRole).toString(); } return true; } #endif //END SubjectFieldModel //BEGIN GlossaryWindow GlossaryWindow::GlossaryWindow(QWidget *parent) : KMainWindow(parent) , m_browser(new GlossaryTreeView(this)) , m_proxyModel(new GlossarySortFilterProxyModel(this)) , m_reactOnSignals(true) { //setAttribute(Qt::WA_DeleteOnClose, true); setAttribute(Qt::WA_DeleteOnClose, false); QSplitter* splitter = new QSplitter(Qt::Horizontal, this); setCentralWidget(splitter); m_proxyModel->setFilterKeyColumn(-1); m_proxyModel->setDynamicSortFilter(true);; GlossaryModel* model = new GlossaryModel(this); m_proxyModel->setSourceModel(model); m_browser->setModel(m_proxyModel); m_browser->setUniformRowHeights(true); m_browser->setAutoScroll(true); m_browser->setColumnHidden(GlossaryModel::ID, true); m_browser->setColumnWidth(GlossaryModel::English, m_browser->columnWidth(GlossaryModel::English) * 2); //man this is HACK y m_browser->setColumnWidth(GlossaryModel::Target, m_browser->columnWidth(GlossaryModel::Target) * 2); m_browser->setAlternatingRowColors(true); //left QWidget* w = new QWidget(splitter); QVBoxLayout* layout = new QVBoxLayout(w); m_filterEdit = new QLineEdit(w); m_filterEdit->setClearButtonEnabled(true); m_filterEdit->setPlaceholderText(i18n("Quick search...")); m_filterEdit->setFocus(); - m_filterEdit->setToolTip(i18nc("@info:tooltip", "Activated by Ctrl+L.") + " " + i18nc("@info:tooltip", "Accepts regular expressions")); + m_filterEdit->setToolTip(i18nc("@info:tooltip", "Activated by Ctrl+L.") + ' ' + i18nc("@info:tooltip", "Accepts regular expressions")); new QShortcut(Qt::CTRL + Qt::Key_L, this, SLOT(setFocus()), 0, Qt::WidgetWithChildrenShortcut); connect(m_filterEdit, &QLineEdit::textChanged, m_proxyModel, &GlossaryNS::GlossarySortFilterProxyModel::setFilterRegExp); layout->addWidget(m_filterEdit); layout->addWidget(m_browser); { QPushButton* addBtn = new QPushButton(w); connect(addBtn, &QPushButton::clicked, this, QOverload<>::of(&GlossaryWindow::newTermEntry)); QPushButton* rmBtn = new QPushButton(w); connect(rmBtn, &QPushButton::clicked, this, QOverload<>::of(&GlossaryWindow::rmTermEntry)); -#ifndef NOKDE KGuiItem::assign(addBtn, KStandardGuiItem::add()); KGuiItem::assign(rmBtn, KStandardGuiItem::remove()); -#else - addBtn->setText(QApplication::translate("KStandardGuiItem", "Add")); - rmBtn->setText(QApplication::translate("KStandardGuiItem", "Remove")); -#endif + QPushButton* restoreBtn = new QPushButton(i18nc("@action:button reloads glossary from disk", "Restore from disk"), w); restoreBtn->setToolTip(i18nc("@info:tooltip", "Reload glossary from disk, discarding any changes")); connect(restoreBtn, &QPushButton::clicked, this, &GlossaryWindow::restore); QWidget* btns = new QWidget(w); QHBoxLayout* btnsLayout = new QHBoxLayout(btns); btnsLayout->addWidget(addBtn); btnsLayout->addWidget(rmBtn); btnsLayout->addWidget(restoreBtn); layout->addWidget(btns); //QWidget::setTabOrder(m_browser,addBtn); QWidget::setTabOrder(addBtn, rmBtn); QWidget::setTabOrder(rmBtn, restoreBtn); QWidget::setTabOrder(restoreBtn, m_filterEdit); } QWidget::setTabOrder(m_filterEdit, m_browser); splitter->addWidget(w); //right m_editor = new QWidget(splitter); m_editor->hide(); Ui_TermEdit ui_termEdit; ui_termEdit.setupUi(m_editor); splitter->addWidget(m_editor); Project* project = Project::instance(); m_sourceTermsModel = new TermsListModel(project->glossary(), project->sourceLangCode(), this); m_targetTermsModel = new TermsListModel(project->glossary(), project->targetLangCode(), this); ui_termEdit.sourceTermsView->setModel(m_sourceTermsModel); ui_termEdit.targetTermsView->setModel(m_targetTermsModel); connect(ui_termEdit.addEngTerm, &QToolButton::clicked, ui_termEdit.sourceTermsView, &TermListView::addTerm); connect(ui_termEdit.remEngTerm, &QToolButton::clicked, ui_termEdit.sourceTermsView, &TermListView::rmTerms); connect(ui_termEdit.addTargetTerm, &QToolButton::clicked, ui_termEdit.targetTermsView, &TermListView::addTerm); connect(ui_termEdit.remTargetTerm, &QToolButton::clicked, ui_termEdit.targetTermsView, &TermListView::rmTerms); m_sourceTermsView = ui_termEdit.sourceTermsView; m_targetTermsView = ui_termEdit.targetTermsView; m_subjectField = ui_termEdit.subjectField; m_definition = ui_termEdit.definition; m_definitionLang = ui_termEdit.definitionLang; //connect (m_english,SIGNAL(textChanged()), this,SLOT(applyEntryChange())); //connect (m_target,SIGNAL(textChanged()), this,SLOT(applyEntryChange())); //connect (m_definition,SIGNAL(editingFinished()),this,SLOT(applyEntryChange())); //connect (m_definition,SIGNAL(textChanged()),this,SLOT(applyEntryChange())); //connect (m_subjectField,SIGNAL(editTextChanged(QString)),this,SLOT(applyEntryChange())); connect(m_subjectField->lineEdit(), &QLineEdit::editingFinished, this, &GlossaryWindow::applyEntryChange); //m_subjectField->addItems(Project::instance()->glossary()->subjectFields()); //m_subjectField->setModel(new SubjectFieldModel(this)); QStringList subjectFields = Project::instance()->glossary()->subjectFields(); qSort(subjectFields); QStringListModel* subjectFieldsModel = new QStringListModel(this); subjectFieldsModel->setStringList(subjectFields); m_subjectField->setModel(subjectFieldsModel); connect(m_browser, QOverload::of(&GlossaryTreeView::currentChanged), this, &GlossaryWindow::currentChanged); connect(m_browser, QOverload::of(&GlossaryTreeView::currentChanged), this, &GlossaryWindow::showEntryInEditor); connect(m_definitionLang, QOverload::of(&KComboBox::activated), this, &GlossaryWindow::showDefinitionForLang); m_definitionLang->setModel(LanguageListModel::emptyLangInstance()->sortModel()); m_definitionLang->setCurrentIndex(LanguageListModel::emptyLangInstance()->sortModelRowForLangCode(m_defLang));//empty lang //TODO //connect(m_targetTermsModel,SIGNAL(dataChanged(QModelIndex,QModelIndex)),m_browser,SLOT(setFocus())); -#ifndef NOKDE setAutoSaveSettings(QLatin1String("GlossaryWindow"), true); -#endif //Glossary* glossary=Project::instance()->glossary(); /*setCaption(i18nc("@title:window","Glossary"), !glossary->changedIds.isEmpty()||!glossary->addedIds.isEmpty()||!glossary->removedIds.isEmpty()); */ } GlossaryWindow::~GlossaryWindow() { } void GlossaryWindow::setFocus() { m_filterEdit->setFocus(); m_filterEdit->selectAll(); } void GlossaryWindow::showEntryInEditor(const QByteArray& id) { if (m_editor->isVisible()) applyEntryChange(); else m_editor->show(); m_id = id; m_reactOnSignals = false; Project* project = Project::instance(); Glossary* glossary = project->glossary(); m_subjectField->setCurrentItem(glossary->subjectField(id),/*insert*/true); QStringList langsToTry = QStringList(m_defLang) << QStringLiteral("en") << QStringLiteral("en_US") << project->targetLangCode(); foreach (const QString& lang, langsToTry) { QString d = glossary->definition(m_id, lang); if (!d.isEmpty()) { if (m_defLang != lang) m_definitionLang->setCurrentIndex(LanguageListModel::emptyLangInstance()->sortModelRowForLangCode(lang)); m_defLang = lang; break; } } m_definition->setPlainText(glossary->definition(m_id, m_defLang)); m_sourceTermsModel->setEntry(id); m_targetTermsModel->setEntry(id); //m_sourceTermsModel->setStringList(glossary->terms(id,project->sourceLangCode())); //m_targetTermsModel->setStringList(glossary->terms(id,project->targetLangCode())); m_reactOnSignals = true; } void GlossaryWindow::currentChanged(int i) { Q_UNUSED(i); m_reactOnSignals = false; m_editor->show(); m_reactOnSignals = true; } void GlossaryWindow::showDefinitionForLang(int langModelIndex) { applyEntryChange(); m_defLang = LanguageListModel::emptyLangInstance()->langCodeForSortModelRow(langModelIndex); m_definition->setPlainText(Project::instance()->glossary()->definition(m_id, m_defLang)); } void GlossaryWindow::applyEntryChange() { if (!m_reactOnSignals || !m_browser->currentIndex().isValid()) return; QByteArray id = m_id; //modelIndexToId(m_browser->currentIndex()); Project* project = Project::instance(); Glossary* glossary = project->glossary(); if (m_subjectField->currentText() != glossary->subjectField(id)) glossary->setSubjectField(id, QString(), m_subjectField->currentText()); if (m_definition->toPlainText() != glossary->definition(id, m_defLang)) glossary->setDefinition(id, m_defLang, m_definition->toPlainText()); //HACK to force finishing of the listview editing QWidget* prevFocusWidget = QApplication::focusWidget(); m_browser->setFocus(); if (prevFocusWidget) prevFocusWidget->setFocus(); // QSortFilterProxyModel* proxyModel=static_cast(model()); //GlossaryModel* sourceModel=static_cast(m_proxyModel->sourceModel()); const QModelIndex& idx = m_proxyModel->mapToSource(m_browser->currentIndex()); if (!idx.isValid()) return; //TODO display filename, optionally stripped like for filetab names setCaption(i18nc("@title:window", "Glossary"), !glossary->isClean()); } void GlossaryWindow::selectEntry(const QByteArray& id) { //let it fetch the rows QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers | QEventLoop::WaitForMoreEvents, 100); QModelIndexList items = m_proxyModel->match(m_proxyModel->index(0, 0), Qt::DisplayRole, QVariant(id), 1, 0); if (items.count()) { m_browser->setCurrentIndex(items.first()); m_browser->scrollTo(items.first(), QAbstractItemView::PositionAtCenter); //qCDebug(LOKALIZE_LOG)<setCurrentIndex(QModelIndex()); showEntryInEditor(id); //qCDebug(LOKALIZE_LOG)<(m_proxyModel->sourceModel()); QByteArray id = sourceModel->appendRow(_english, _target); selectEntry(id); } void GlossaryWindow::rmTermEntry() { rmTermEntry(-1); } void GlossaryWindow::rmTermEntry(int i) { setCaption(i18nc("@title:window", "Glossary"), true); //QSortFilterProxyModel* proxyModel=static_cast(model()); GlossaryModel* sourceModel = static_cast(m_proxyModel->sourceModel()); if (i == -1) { //NOTE actually we should remove selected items, not current one const QModelIndex& current = m_browser->currentIndex(); if (!current.isValid()) return; i = m_proxyModel->mapToSource(current).row(); } sourceModel->removeRow(i); } void GlossaryWindow::restore() { setCaption(i18nc("@title:window", "Glossary"), false); Glossary* glossary = Project::instance()->glossary(); glossary->load(glossary->path()); m_reactOnSignals = false; showEntryInEditor(m_id); m_reactOnSignals = true; } bool GlossaryWindow::save() { //TODO add error message return Project::instance()->glossary()->save(); } bool GlossaryWindow::queryClose() { Glossary* glossary = Project::instance()->glossary(); applyEntryChange(); if (glossary->isClean()) return true; switch (KMessageBox::warningYesNoCancel(this, i18nc("@info", "The glossary contains unsaved changes.\n\ Do you want to save your changes or discard them?"), i18nc("@title:window", "Warning"), KStandardGuiItem::save(), KStandardGuiItem::discard())) { case KMessageBox::Yes: return save(); case KMessageBox::No: restore(); return true; default: return false; } } //END GlossaryWindow void TermsListModel::setEntry(const QByteArray& id) { m_id = id; QStringList terms = m_glossary->terms(m_id, m_lang); terms.append(QString()); //allow adding new terms setStringList(terms); } bool TermsListModel::setData(const QModelIndex& index, const QVariant& value, int role) { Q_UNUSED(role); m_glossary->setTerm(m_id, m_lang, index.row(), value.toString()); setEntry(m_id); //allow adding new terms return true; } bool TermsListModel::removeRows(int row, int count, const QModelIndex& parent) { Q_UNUSED(count) if (row == rowCount() - 1) return false;// cannot delete non-existing item m_glossary->rmTerm(m_id, m_lang, row); return QStringListModel::removeRows(row, 1, parent); } void TermListView::addTerm() { setCurrentIndex(model()->index(model()->rowCount() - 1, 0)); edit(currentIndex()); } void TermListView::rmTerms() { foreach (const QModelIndex& row, selectionModel()->selectedRows()) model()->removeRow(row.row()); } diff --git a/src/lokalize.pro b/src/lokalize.pro index b0b4efa..c2f4d68 100644 --- a/src/lokalize.pro +++ b/src/lokalize.pro @@ -1,185 +1,173 @@ #------------------------------------------------- # # Project created by QtCreator 2012-06-06T01:26:21 # #------------------------------------------------- QT += core widgets xml sql TARGET = lokalize mac: TARGET = Lokalize win32: TARGET = Lokalize TEMPLATE = app SOURCES += main.cpp\ ## lokalizemainwindow.cpp actionproxy.cpp\ editortab.cpp\ # editortab_findreplace.cpp editorview.cpp\ xlifftextedit.cpp\ syntaxhighlighter.cpp\ completionstorage.cpp\ phaseswindow.cpp\ noteeditor.cpp\ msgctxtview.cpp\ binunitsview.cpp\ cataloglistview/cataloglistview.cpp\ cataloglistview/catalogmodel.cpp\ common/headerviewmenu.cpp\ common/domroutines.cpp\ common/fastsizehintitemdelegate.cpp\ common/flowlayout.cpp\ common/termlabel.cpp\ common/languagelistmodel.cpp\ common/stemming.cpp\ common/htmlhelpers.cpp\ glossary/glossaryview.cpp\ glossary/glossary.cpp\ glossary/glossarywindow.cpp\ mergemode/mergecatalog.cpp\ mergemode/mergeview.cpp\ alttransview.cpp\ common/diff.cpp\ project/project.cpp\ # project/projectmodel.cpp # project/projectwidget.cpp # project/projecttab.cpp # project/poextractor.cpp ## prefs/prefs.cpp # webquery/webqueryview.cpp # webquery/webquerycontroller.cpp # webquery/myactioncollectionview.cpp # tools/widgettextcaptureconfig.cpp filesearch/filesearchtab.cpp\ tm/tmview.cpp\ tm/tmscanapi.cpp\ tm/jobs.cpp\ tm/dbfilesmodel.cpp\ tm/tmmanager.cpp\ tm/tmtab.cpp\ tm/qaview.cpp\ tm/qamodel.cpp\ catalog/phase.cpp\ catalog/cmd.cpp\ catalog/pos.cpp\ catalog/catalog.cpp\ catalog/catalogstring.cpp\ catalog/gettextheader.cpp\ catalog/gettext/gettextstorage.cpp\ catalog/gettext/catalogitem.cpp\ catalog/gettext/importplugin.cpp\ catalog/gettext/gettextimport.cpp\ catalog/gettext/gettextexport.cpp\ catalog/xliff/xliffstorage.cpp\ - catalog/ts/tsstorage.cpp\ - nokde-stubs/prefs.cpp\ - nokde-stubs/lokalizesubwindowbase.cpp\ - nokde-stubs/welcometab.cpp + catalog/ts/tsstorage.cpp mac: CONFIG += objective_c mac: OBJECTIVE_SOURCES += common/machelpers.mm win32: SOURCES += common/winhelpers.cpp unix:!mac: SOURCES += common/unixhelpers.cpp HEADERS += editortab.h\ editorview.h\ xlifftextedit.h\ syntaxhighlighter.h\ ## completionstorage.h\ phaseswindow.h\ noteeditor.h\ msgctxtview.h\ binunitsview.h\ cataloglistview/cataloglistview.h\ cataloglistview/catalogmodel.h\ common/headerviewmenu.h\ common/fastsizehintitemdelegate.h\ common/flowlayout.h\ common/termlabel.h\ common/languagelistmodel.h\ common/stemming.h\ glossary/glossaryview.h\ glossary/glossary.h\ glossary/glossarywindow.h\ mergemode/mergecatalog.h\ mergemode/mergeview.h\ alttransview.h\ project/project.h\ # project/projectmodel.h # project/projectwidget.h # project/projecttab.h # project/poextractor.h ## prefs/prefs.h # webquery/webqueryview.h # webquery/webquerycontroller.h # webquery/myactioncollectionview.h # tools/widgettextcaptureconfig.h filesearch/filesearchtab.h\ tm/tmview.h\ ## tm/tmscanapi.h\ tm/jobs.h\ tm/dbfilesmodel.h\ tm/tmmanager.h\ tm/tmtab.h\ tm/qaview.h\ tm/qamodel.h\ catalog/phase.h\ catalog/cmd.h\ catalog/pos.h\ catalog/catalog.h\ - catalog/catalogstring.h\ - nokde-stubs/prefs.h\ - nokde-stubs/prefs_lokalize.h\ - nokde-stubs/projectbase.h\ - nokde-stubs/projectlocal.h\ - nokde-stubs/kaboutdata.h\ - nokde-stubs/welcometab.h + catalog/catalogstring.h FORMS += glossary/termedit.ui\ tm/queryoptions.ui\ tm/managedatabases.ui\ tm/dbparams.ui\ filesearch/filesearchoptions.ui\ - filesearch/massreplaceoptions.ui\ - nokde-stubs/welcomewidget.ui + filesearch/massreplaceoptions.ui -INCLUDEPATH += catalog catalog/gettext catalog/xliff catalog/ts cataloglistview mergemode glossary tm filesearch project common nokde-stubs filesearch - -DEFINES += NOKDE +INCLUDEPATH += catalog catalog/gettext catalog/xliff catalog/ts cataloglistview mergemode glossary tm filesearch project common filesearch #unix: LIBS += -lhunspell CONFIG += exceptions_off c++11 stl_off mac: QMAKE_LFLAGS += -dead_strip mac: ICON = ../icons/osx/Lokalize.icns mac: QMAKE_INFO_PLIST = ../icons/osx/Info.plist mac: QMAKE_POST_LINK += cp -n ../icons/osx/LokalizePo*.icns ../icons/osx/LokalizeXliff.icns Lokalize.app/Contents/Resources/ #remove this block to get a simpler build sonnet_static { DEFINES += SONNET_STATIC SONNETCORE_EXPORT="" SONNETUI_EXPORT="" INCLUDEPATH += ../../sonnet/src/core INCLUDEPATH += ../../sonnet/src/ui win32:LIBS += -L../../sonnet/src/core/release -lsonnet-core win32:LIBS += -L../../sonnet/src/ui/release -lsonnet-ui win32:LIBS += -L../../sonnet/src/plugins/hunspell/release -lsonnet-hunspell mac:LIBS += -L../../sonnet/src/core -lsonnet-core mac:LIBS += -L../../sonnet/src/ui -lsonnet-ui mac:LIBS += -L../../sonnet/src/plugins/hunspell -lsonnet-hunspell mac:LIBS += -L../../sonnet/src/plugins/nsspellchecker -lsonnet-nsspellchecker DEFINES += HAVE_HUNSPELL #win32: DEFINES += HUNSPELL_STATIC INCLUDEPATH += ../../hunspell/src/hunspell INCLUDEPATH += ../../hunspell/src mac:LIBS += -L../../hunspell/src/hunspell/.libs/ -lhunspell-1.2 win32:LIBS += -L../../hunspell/src/win_api/x64/Release_dll -llibhunspell win32:system("copy ..\\..\\hunspell\\src\\win_api\\x64\\Release_dll\\libhunspell.dll release") } diff --git a/src/lokalizesubwindowbase.h b/src/lokalizesubwindowbase.h index 78c059f..8a55e14 100644 --- a/src/lokalizesubwindowbase.h +++ b/src/lokalizesubwindowbase.h @@ -1,267 +1,115 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2014 by Nick Shaforostoff 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 LOKALIZESUBWINDOWBASE_H #define LOKALIZESUBWINDOWBASE_H #include #include #include #include #include #include "actionproxy.h" -#ifndef NOKDE #include #include /** * Interface for LokalizeMainWindow */ class LokalizeSubwindowBase: public KMainWindow { Q_OBJECT public: LokalizeSubwindowBase(QWidget* parent): KMainWindow(parent) {} virtual ~LokalizeSubwindowBase() { emit aboutToBeClosed(); } virtual KXMLGUIClient* guiClient() = 0; virtual void reloadUpdatedXML() = 0; virtual void setUpdatedXMLFile() = 0; //interface for LokalizeMainWindow virtual void hideDocks() = 0; virtual void showDocks() = 0; //bool queryClose(); virtual QString currentFilePath() { return QString(); } protected: void reflectNonApprovedCount(int count, int total); void reflectUntranslatedCount(int count, int total); signals: void aboutToBeClosed(); public: //QHash supportedActions; StatusBarProxy statusBarItems; protected: QDateTime lastXMLUpdate; }; /** * C++ casting workaround */ class LokalizeSubwindowBase2: public LokalizeSubwindowBase, public KXMLGUIClient { public: LokalizeSubwindowBase2(QWidget* parent): LokalizeSubwindowBase(parent), KXMLGUIClient() {} virtual ~LokalizeSubwindowBase2() {} KXMLGUIClient* guiClient() { return (KXMLGUIClient*)this; } void setUpdatedXMLFile() { QString localXml = guiClient()->localXMLFile(); if (QFile::exists(localXml)) { lastXMLUpdate = QFileInfo(localXml).lastModified(); } } void reloadUpdatedXML() { QString localXml = guiClient()->localXMLFile(); if (QFile::exists(localXml)) { QDateTime newXMLUpdate = QFileInfo(localXml).lastModified(); if (newXMLUpdate > lastXMLUpdate) { lastXMLUpdate = newXMLUpdate; guiClient()->reloadXML(); } } } }; -#else -#include -#include -#include -#include -#include -#include -#include "kmainwindow.h" -namespace KStandardAction -{ -/** - * The standard menubar and toolbar actions. - */ -enum StandardAction { - ActionNone, - - // File Menu - New, Open, OpenRecent, Save, SaveAs, Revert, Close, - Print, PrintPreview, Mail, Quit, - - // Edit Menu - Undo, Redo, Cut, Copy, Paste, SelectAll, Deselect, Find, FindNext, FindPrev, - Replace, - - // View Menu - ActualSize, FitToPage, FitToWidth, FitToHeight, ZoomIn, ZoomOut, - Zoom, Redisplay, - - // Go Menu - Up, Back, Forward, Home /*Home page*/, Prior, Next, Goto, GotoPage, GotoLine, - FirstPage, LastPage, DocumentBack, DocumentForward, - - // Bookmarks Menu - AddBookmark, EditBookmarks, - - // Tools Menu - Spelling, - - // Settings Menu - ShowMenubar, ShowToolbar, ShowStatusbar, - SaveOptions, KeyBindings, - Preferences, ConfigureToolbars, - - // Help Menu - Help, HelpContents, WhatsThis, ReportBug, AboutApp, AboutKDE, - TipofDay, - - // Other standard actions - ConfigureNotifications, - FullScreen, - Clear, - PasteText, - SwitchApplicationLanguage -}; -}; -class KActionCategory; -class KActionCollection -{ -public: - KActionCollection(QMainWindow* w); - ~KActionCollection() - { - qDeleteAll(categories); - } - static void setDefaultShortcut(QAction* a, const QKeySequence& s) - { - a->setShortcut(s); - } - static void setDefaultShortcuts(QAction* a, const QList& l) - { - a->setShortcuts(l); - } - - QAction* addAction(const QString& name, QAction* a); - - QMainWindow* m_mainWindow; - QMenu* file; - QMenu* edit; - QMenu* view; - QMenu* go; - QMenu* sync; - QMenu* tools; - QMenu* tm; - QMenu* glossary; - - QVector categories; -}; -class KActionCategory -{ -public: - KActionCategory(const QString&, KActionCollection* c_): c(c_) - { - c->categories.append(this); - } - QAction* addAction(const char* name, QAction* a) - { - return c->addAction(name, a); - } - QAction* addAction(const QString& name, QAction* a) - { - return c->addAction(name, a); - } - QAction* addAction(const QLatin1String& name, QAction* a) - { - return c->addAction(name, a); - } - QAction* addAction(const QString& name) - { - return c->addAction(name, new QAction(name, c->m_mainWindow)); - } - QAction* addAction(const QString& name, QObject* rcv, const char* slot) - { - QAction* a = new QAction(name, rcv); - QObject::connect(a, &QAction::triggered, rcv, slot); - return c->addAction(name, a); - } - QAction* addAction(KStandardAction::StandardAction, QObject* rcv, const char* slot); - - static void setDefaultShortcut(QAction* a, const QKeySequence& s) - { - a->setShortcut(s); - } - - KActionCollection* c; -}; -#define KToolBarPopupAction QAction -class LokalizeSubwindowBase2: public KMainWindow -{ -public: - LokalizeSubwindowBase2(QWidget* parent): KMainWindow(parent), c(new KActionCollection(this)) - { - } - virtual ~LokalizeSubwindowBase2() - { - delete c; - } - - void setXMLFile(const char*, bool f = false) {} - void setXMLFile(const QString&, bool f = false) {} - KActionCollection* actionCollection() const - { - return c; - } - - StatusBarProxy statusBarItems; -protected: - void reflectNonApprovedCount(int count, int total) {} - void reflectUntranslatedCount(int count, int total) {} - KActionCollection* c; -}; -#endif #endif diff --git a/src/main.cpp b/src/main.cpp index 84099e5..e5a3edb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,255 +1,163 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2014 by Nick Shaforostoff 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 "lokalize_debug.h" #include "project.h" #include "prefs.h" #include "prefs_lokalize.h" -#ifndef NOKDE #include "version.h" #include "projecttab.h" #include "projectmodel.h" #include "lokalizemainwindow.h" #include "stemming.h" -#else -#define LOKALIZE_VERSION QStringLiteral("2.0") -#include "welcometab.h" -#endif #include "jobs.h" #include "catalogstring.h" #include "pos.h" #include #include #include #include #include #include #include #include -#ifndef NOKDE #include -#endif #include #include #include "editortab.h" -#ifdef NOKDE -#ifdef Q_OS_WIN -#include -#define FILEPATHMESSAGE 10 -char sentPath[256]; -COPYDATASTRUCT MyCDS; - -PCOPYDATASTRUCT pMyCDS; -LONG_PTR WINAPI windowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - if (message == WM_COPYDATA) { - pMyCDS = (PCOPYDATASTRUCT)lParam; - if (pMyCDS->dwData == FILEPATHMESSAGE) { - EditorTab* t = Project::instance()->fileOpen(QString::fromUtf8((char*)pMyCDS->lpData)); - if (t) t->activateWindow(); - } - return 0; - } - return DefWindowProc(hWnd, message, wParam, lParam); -} -#endif -#endif - int main(int argc, char **argv) { TM::threadPool()->setMaxThreadCount(1); TM::threadPool()->setExpiryTimeout(-1); QThreadPool::globalInstance()->setMaxThreadCount(1); QApplication app(argc, argv); KLocalizedString::setApplicationDomain("lokalize"); QCommandLineParser parser; KAboutData about(QStringLiteral("lokalize"), i18nc("@title", "Lokalize"), LOKALIZE_VERSION, i18n("Computer-aided translation system.\nDo not translate what had already been translated."), KAboutLicense::GPL, i18nc("@info:credit", "(c) 2007-2015 Nick Shaforostoff\n(c) 1999-2006 The KBabel developers") /*, KLocalizedString(), 0, "shafff@ukr.net"*/); about.addAuthor(i18n("Nick Shaforostoff"), QString(), QStringLiteral("shaforostoff@gmail.com")); about.addCredit(i18n("Google Inc."), i18n("sponsored development as part of Google Summer Of Code program"), QString(), QStringLiteral("http://google.com")); about.addCredit(i18n("NLNet Foundation"), i18n("sponsored XLIFF-related work"), QString(), QStringLiteral("https://nlnet.nl/")); about.addCredit(i18n("Translate-toolkit"), i18n("provided excellent cross-format converting scripts"), QString(), QStringLiteral("http://translate.sourceforge.net")); about.addCredit(i18n("Viesturs Zarins"), i18n("project tree merging translation+templates"), QStringLiteral("viesturs.zarins@mii.lu.lv"), QString()); about.addCredit(i18n("Stephan Johach"), i18n("bug fixing patches"), QStringLiteral("hunsum@gmx.de")); about.addCredit(i18n("Chusslove Illich"), i18n("bug fixing patches"), QStringLiteral("caslav.ilic@gmx.net")); about.addCredit(i18n("Jure Repinc"), i18n("testing and bug fixing"), QStringLiteral("jlp@holodeck1.com")); about.addCredit(i18n("Stefan Asserhall"), i18n("patches"), QStringLiteral("stefan.asserhall@comhem.se")); about.addCredit(i18n("Papp Laszlo"), i18n("bug fixing patches"), QStringLiteral("djszapi@archlinux.us")); about.addCredit(i18n("Albert Astals Cid"), i18n("XLIFF improvements"), QStringLiteral("aacid@kde.org")); about.addCredit(i18n("Simon Depiets"), i18n("bug fixing and improvements"), QStringLiteral("sdepiets@gmail.com")); -#ifndef NOKDE KAboutData::setApplicationData(about); about.setupCommandLine(&parser); //parser.addOption(QCommandLineOption(QStringList() << QLatin1String("source"), i18n( "Source for the merge mode" ), QLatin1String("URL"))); parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("noprojectscan"), i18n("Do not scan files of the project."))); parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("project"), i18n("Load specified project."), QStringLiteral("filename"))); parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("+[URL]"), i18n("Document to open"))); parser.process(app); about.processCommandLine(&parser); -#else - QCoreApplication::setApplicationName(QStringLiteral("Lokalize")); - QCoreApplication::setApplicationVersion(LOKALIZE_VERSION); - QCoreApplication::setOrganizationName(QStringLiteral("KDE")); - QCoreApplication::setOrganizationDomain(QStringLiteral("kde.org")); - parser.process(app); -#endif - //qCDebug(LOKALIZE_LOG) is important as it avoids compile 'optimization'. qCDebug(LOKALIZE_LOG) << qRegisterMetaType(); qCDebug(LOKALIZE_LOG) << qRegisterMetaType(); qCDebug(LOKALIZE_LOG) << qRegisterMetaType(); qCDebug(LOKALIZE_LOG) << qRegisterMetaType(); qRegisterMetaTypeStreamOperators("InlineTag"); qRegisterMetaTypeStreamOperators("CatalogString"); -#ifndef NOKDE qAddPostRoutine(&cleanupSpellers); const KDBusService dbusService(KDBusService::Multiple); // see if we are starting with session management if (app.isSessionRestored()) kRestoreMainWindows(); else { // no session.. just start up normally QString projectFilePath = parser.value(QStringLiteral("project")); QVector urls; Q_FOREACH (const QString& filePath, parser.positionalArguments()) if (filePath.endsWith(QLatin1String(".lokalize"))) projectFilePath = filePath; else if (QFileInfo::exists(filePath)) urls.append(filePath); if (projectFilePath.length()) { // load needs an absolute path // FIXME: I do not know how to handle urls here // bug 245546 regarding symlinks QFileInfo projectFileInfo(projectFilePath); projectFilePath = projectFileInfo.canonicalFilePath(); if (projectFilePath.isEmpty()) projectFilePath = projectFileInfo.absoluteFilePath(); Project::instance()->load(projectFilePath); } LokalizeMainWindow* lmw = new LokalizeMainWindow; SettingsController::instance()->setMainWindowPtr(lmw); lmw->show(); if (urls.size()) new DelayedFileOpener(urls, lmw); //Project::instance()->model()->setCompleteScan(parser.isSet("noprojectscan"));// TODO: negate check (and ensure nobody passes the no-op --noprojectscan argument) } -#else -#ifdef Q_OS_WIN - TCHAR gClassName[100]; - wsprintf(gClassName, TEXT("LokalizeResponder")); - - HWND responder = FindWindow(gClassName, L"LokalizeResponder"); - if (responder) { - for (int j = 0; j < parser.positionalArguments().count(); j++) { - if (!QFileInfo::exists(parser.positionalArguments().at(j))) continue; - strncpy(sentPath, parser.positionalArguments().at(j).toUtf8().constData(), 255); - MyCDS.dwData = FILEPATHMESSAGE; - MyCDS.cbData = sizeof(sentPath); // size of data - MyCDS.lpData = &sentPath; // data structure - SendMessage(responder, WM_COPYDATA, 0, (LPARAM)(LPVOID) &MyCDS); - } - return 0; - } - - WNDCLASS windowClass; - windowClass.style = CS_GLOBALCLASS | CS_DBLCLKS; - windowClass.lpfnWndProc = windowProc; - windowClass.cbClsExtra = 0; - windowClass.cbWndExtra = 0; - windowClass.hInstance = (HINSTANCE) GetModuleHandle(NULL); - windowClass.hIcon = 0; - windowClass.hCursor = 0; - windowClass.hbrBackground = 0; - windowClass.lpszMenuName = 0; - windowClass.lpszClassName = gClassName; - RegisterClass(&windowClass); - responder = CreateWindow(gClassName, L"LokalizeResponder", 0, 0, 0, 10, 10, 0, (HMENU)0, (HINSTANCE)GetModuleHandle(NULL), 0); -#endif - - SettingsController::instance()->ensureProjectIsLoaded(); - for (int j = 0; j < parser.positionalArguments().count(); j++) - if (QFileInfo::exists(parser.positionalArguments().at(j))) Project::instance()->fileOpen(parser.positionalArguments().at(j)); - if (!parser.positionalArguments().count()) { - WelcomeTab* welcome = new WelcomeTab(0); - welcome->move(QApplication::desktop()->screen()->rect().center() - welcome->rect().center()); - welcome->show(); - } - app.installEventFilter(Project::instance()); -#endif int code = app.exec(); -#ifdef NOKDE -#ifdef Q_OS_WIN - DestroyWindow(responder); -#endif -#endif QThreadPool::globalInstance()->clear(); TM::cancelAllJobs(); TM::threadPool()->clear(); TM::threadPool()->waitForDone(1000); -#ifndef NOKDE Project::instance()->model()->threadPool()->clear(); if (SettingsController::instance()->dirty) //for config changes done w/o config dialog Settings::self()->save(); if (Project::instance()->isLoaded()) Project::instance()->save(); qCDebug(LOKALIZE_LOG) << "Finishing Project jobs..."; qCDebug(LOKALIZE_LOG) << "Finishing TM jobs..."; int secs = 5; while (--secs >= 0) { Project::instance()->model()->threadPool()->waitForDone(1000); TM::threadPool()->waitForDone(1000); QThreadPool::globalInstance()->waitForDone(1000); //qCDebug(LOKALIZE_LOG)<<"QCoreApplication::processEvents()..."; QCoreApplication::processEvents(); QCoreApplication::sendPostedEvents(0, 0); } -#else - Settings::self()->save(); -#endif return code; } diff --git a/src/mergemode/mergeview.cpp b/src/mergemode/mergeview.cpp index d205e99..81be5df 100644 --- a/src/mergemode/mergeview.cpp +++ b/src/mergemode/mergeview.cpp @@ -1,376 +1,371 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2014 by Nick Shaforostoff 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 "mergeview.h" #include "cmd.h" #include "mergecatalog.h" #include "project.h" #include "diff.h" #include #include #include - -#ifndef NOKDE #include -#endif #include #include #include #include #include #include MergeView::MergeView(QWidget* parent, Catalog* catalog, bool primary) : QDockWidget(primary ? i18nc("@title:window that displays difference between current file and 'merge source'", "Primary Sync") : i18nc("@title:window that displays difference between current file and 'merge source'", "Secondary Sync"), parent) , m_browser(new QTextEdit(this)) , m_baseCatalog(catalog) , m_mergeCatalog(0) , m_normTitle(primary ? i18nc("@title:window that displays difference between current file and 'merge source'", "Primary Sync") : i18nc("@title:window that displays difference between current file and 'merge source'", "Secondary Sync")) , m_hasInfoTitle(m_normTitle + " [*]") , m_hasInfo(false) , m_primary(primary) { setObjectName(primary ? QStringLiteral("mergeView-primary") : QStringLiteral("mergeView-secondary")); setWidget(m_browser); setToolTip(i18nc("@info:tooltip", "Drop file to be merged into / synced with the current one here, then see context menu options")); hide(); setAcceptDrops(true); m_browser->setReadOnly(true); m_browser->setContextMenuPolicy(Qt::NoContextMenu); m_browser->viewport()->setBackgroundRole(QPalette::Background); setContextMenuPolicy(Qt::ActionsContextMenu); } MergeView::~MergeView() { delete m_mergeCatalog; emit mergeCatalogPointerChanged(NULL); emit mergeCatalogAvailable(false); } QString MergeView::filePath() { if (m_mergeCatalog) return m_mergeCatalog->url(); return QString(); } void MergeView::dragEnterEvent(QDragEnterEvent* event) { if (event->mimeData()->hasUrls() && Catalog::extIsSupported(event->mimeData()->urls().first().path())) event->acceptProposedAction(); } void MergeView::dropEvent(QDropEvent *event) { mergeOpen(event->mimeData()->urls().first().toLocalFile()); event->acceptProposedAction(); } void MergeView::slotUpdate(const DocPosition& pos) { if (pos.entry == m_pos.entry) slotNewEntryDisplayed(pos); } void MergeView::slotNewEntryDisplayed(const DocPosition& pos) { m_pos = pos; if (!m_mergeCatalog) return; emit signalPriorChangedAvailable((pos.entry > m_mergeCatalog->firstChangedIndex()) || (pluralFormsAvailableBackward() != -1)); emit signalNextChangedAvailable((pos.entry < m_mergeCatalog->lastChangedIndex()) || (pluralFormsAvailableForward() != -1)); if (!m_mergeCatalog->isPresent(pos.entry)) { //i.e. no corresponding entry, whether changed or not if (m_hasInfo) { m_hasInfo = false; setWindowTitle(m_normTitle); m_browser->clear(); // m_browser->viewport()->setBackgroundRole(QPalette::Base); } emit signalEntryWithMergeDisplayed(false); /// no editing at all! //////////// return; } if (!m_hasInfo) { m_hasInfo = true; setWindowTitle(m_hasInfoTitle); } emit signalEntryWithMergeDisplayed(m_mergeCatalog->isDifferent(pos.entry)); QString result = userVisibleWordDiff(m_baseCatalog->msgstr(pos), m_mergeCatalog->msgstr(pos), Project::instance()->accel(), Project::instance()->markup(), Html); #if 0 int i = -1; bool inTag = false; while (++i < result.size()) { //dynamic if (!inTag) { if (result.at(i) == '<') inTag = true; else if (result.at(i) == ' ') result.replace(i, 1, "&sp;"); } else if (result.at(i) == '>') inTag = false; } #endif if (!m_mergeCatalog->isApproved(pos.entry)) { result.prepend(""); result.append(""); } if (m_mergeCatalog->isModified(pos)) { result.prepend(""); result.append(""); } result.replace(' ', QChar::Nbsp); m_browser->setHtml(result); //qCDebug(LOKALIZE_LOG)<<"ELA "<clear(); } void MergeView::mergeOpen(QString mergeFilePath) { if (Q_UNLIKELY(!m_baseCatalog->numberOfEntries())) return; if (mergeFilePath == m_baseCatalog->url()) { //(we are likely to be _mergeViewSecondary) //special handling: open corresponding file in the branch //for AutoSync QString path = QFileInfo(mergeFilePath).canonicalFilePath(); //bug 245546 regarding symlinks QString oldPath = path; path.replace(Project::instance()->poDir(), Project::instance()->branchDir()); if (oldPath == path) { //if file doesn't exist both are empty cleanup(); return; } mergeFilePath = path; } if (mergeFilePath.isEmpty()) { //Project::instance()->model()->weaver()->suspend(); //KDE5PORT use mutex if needed mergeFilePath = QFileDialog::getOpenFileName(this, i18nc("@title:window", "Select translation file"), QString(), Catalog::supportedFileTypes(false)); //Project::instance()->model()->weaver()->resume(); } if (mergeFilePath.isEmpty()) return; delete m_mergeCatalog; m_mergeCatalog = new MergeCatalog(this, m_baseCatalog); emit mergeCatalogPointerChanged(m_mergeCatalog); emit mergeCatalogAvailable(m_mergeCatalog); int errorLine = m_mergeCatalog->loadFromUrl(mergeFilePath); if (Q_LIKELY(errorLine == 0)) { if (m_pos.entry > 0) emit signalPriorChangedAvailable(m_pos.entry > m_mergeCatalog->firstChangedIndex()); emit signalNextChangedAvailable(m_pos.entry < m_mergeCatalog->lastChangedIndex()); //a bit hacky :) connect(m_mergeCatalog, &MergeCatalog::signalEntryModified, this, &MergeView::slotUpdate); if (m_pos.entry != -1) slotNewEntryDisplayed(m_pos); show(); } else { //KMessageBox::error(this, KIO::NetAccess::lastErrorString() ); cleanup(); -#ifndef NOKDE if (errorLine > 0) KMessageBox::error(this, i18nc("@info", "Error opening the file %1 for synchronization, error line: %2", mergeFilePath, errorLine)); else { /* disable this as requested by bug 272587 KNotification* notification=new KNotification("MergeFilesOpenError", this); notification->setText( i18nc("@info %1 is full filename","Error opening the file %1 for synchronization",url.pathOrUrl()) ); notification->sendEvent(); */ } -#endif //i18nc("@info %1 is w/o path","No branch counterpart for %1",url.fileName()), } } bool MergeView::isModified() { return m_mergeCatalog && m_mergeCatalog->isModified(); //not isClean because mergecatalog doesn't keep history } int MergeView::pluralFormsAvailableForward() { if (Q_LIKELY(m_pos.entry == -1 || !m_mergeCatalog->isPlural(m_pos.entry))) return -1; int formLimit = qMin(m_baseCatalog->numberOfPluralForms(), m_mergeCatalog->numberOfPluralForms()); //just sanity check DocPosition pos = m_pos; while (++(pos.form) < formLimit) { if (m_baseCatalog->msgstr(pos) != m_mergeCatalog->msgstr(pos)) return pos.form; } return -1; } int MergeView::pluralFormsAvailableBackward() { if (Q_LIKELY(m_pos.entry == -1 || !m_mergeCatalog->isPlural(m_pos.entry))) return -1; DocPosition pos = m_pos; while (--(pos.form) >= 0) { if (m_baseCatalog->msgstr(pos) != m_mergeCatalog->msgstr(pos)) return pos.form; } return -1; } void MergeView::gotoPrevChanged() { if (Q_UNLIKELY(!m_mergeCatalog)) return; DocPosition pos; //first, check if there any plural forms waiting to be synced int form = pluralFormsAvailableBackward(); if (Q_UNLIKELY(form != -1)) { pos = m_pos; pos.form = form; } else if (Q_UNLIKELY((pos.entry = m_mergeCatalog->prevChangedIndex(m_pos.entry)) == -1)) return; if (Q_UNLIKELY(m_mergeCatalog->isPlural(pos.entry) && form == -1)) pos.form = qMin(m_baseCatalog->numberOfPluralForms(), m_mergeCatalog->numberOfPluralForms()) - 1; emit gotoEntry(pos, 0); } void MergeView::gotoNextChangedApproved() { gotoNextChanged(true); } void MergeView::gotoNextChanged(bool approvedOnly) { if (Q_UNLIKELY(!m_mergeCatalog)) return; DocPosition pos = m_pos; //first, check if there any plural forms waiting to be synced int form = pluralFormsAvailableForward(); if (Q_UNLIKELY(form != -1)) { pos = m_pos; pos.form = form; } else if (Q_UNLIKELY((pos.entry = m_mergeCatalog->nextChangedIndex(m_pos.entry)) == -1)) return; while (approvedOnly && !m_mergeCatalog->isApproved(pos.entry)) { if (Q_UNLIKELY((pos.entry = m_mergeCatalog->nextChangedIndex(pos.entry)) == -1)) return; } emit gotoEntry(pos, 0); } void MergeView::mergeBack() { if (m_pos.entry == -1 || !m_mergeCatalog || m_baseCatalog->msgstr(m_pos).isEmpty()) return; m_mergeCatalog->copyFromBaseCatalog(m_pos); } void MergeView::mergeAccept() { if (m_pos.entry == -1 || !m_mergeCatalog //||m_baseCatalog->msgstr(m_pos)==m_mergeCatalog->msgstr(m_pos) || m_mergeCatalog->msgstr(m_pos).isEmpty()) return; m_mergeCatalog->copyToBaseCatalog(m_pos); emit gotoEntry(m_pos, 0); } void MergeView::mergeAcceptAllForEmpty() { if (Q_UNLIKELY(!m_mergeCatalog)) return; bool update = m_mergeCatalog->differentEntries().contains(m_pos.entry); m_mergeCatalog->copyToBaseCatalog(/*MergeCatalog::EmptyOnly*/MergeCatalog::HigherOnly); if (update != m_mergeCatalog->differentEntries().contains(m_pos.entry)) emit gotoEntry(m_pos, 0); } bool MergeView::event(QEvent *event) { if (event->type() == QEvent::ToolTip && m_mergeCatalog) { QHelpEvent *helpEvent = static_cast(event); QString text = QStringLiteral("") % QDir::toNativeSeparators(filePath()) % QStringLiteral("\n") % i18nc("@info:tooltip", "Different entries: %1\nUnmatched entries: %2", m_mergeCatalog->differentEntries().count(), m_mergeCatalog->unmatchedCount()); text.replace('\n', QStringLiteral("
")); QToolTip::showText(helpEvent->globalPos(), text); return true; } return QWidget::event(event); } diff --git a/src/nokde-stubs/kaboutdata.h b/src/nokde-stubs/kaboutdata.h deleted file mode 100644 index 3fe6303..0000000 --- a/src/nokde-stubs/kaboutdata.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef KABOUTDATA_H -#define KABOUTDATA_H - -#include -#include -#include - -namespace KAboutLicense -{ -enum L {GPL}; -}; -struct Credit { - QString name, what, mail, site; -}; -class KAboutData: public QObject -{ - Q_OBJECT -public: - KAboutData(const QString&, const QString& n, const QString& v, const QString& d, KAboutLicense::L, const QString& c); - void addAuthor(const QString& name, const QString&, const QString& mail); - void addCredit(const QString& who, const QString& forwhat, const QString& mail, const QString& site = QString()); - - static KAboutData* instance; -public slots: - void doAbout(); -private: - QString name, version, description, copyright; - QVector credits; -}; - -#endif diff --git a/src/nokde-stubs/kcombobox.h b/src/nokde-stubs/kcombobox.h deleted file mode 100644 index f15e6b9..0000000 --- a/src/nokde-stubs/kcombobox.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef KCOMBOBOX_H -#define KCOMBOBOX_H - -#include -#include - -class KComboBox: public QComboBox -{ -public: - KComboBox(QWidget* p): QComboBox(p) {} - void setCurrentItem(const QString& s, bool insert = false) - { - setCurrentText(s); - if (insert) - if (QStringListModel* lm = qobject_cast(model())) { - QStringList l = lm->stringList(); - if (!l.contains(s)) l.append(s); - lm->setStringList(l); - } - } -}; - -#endif - diff --git a/src/nokde-stubs/klocalizedstring.h b/src/nokde-stubs/klocalizedstring.h deleted file mode 100644 index 8bf5d1a..0000000 --- a/src/nokde-stubs/klocalizedstring.h +++ /dev/null @@ -1,93 +0,0 @@ -/* **************************************************************************** - This file is part of Lokalize - - Copyright (C) 2007-2014 by Nick Shaforostoff - - 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 KLOCALIZEDSTRING_H -#define KLOCALIZEDSTRING_H - -#include - -static inline QString i18nc(const char* y, const char* x) -{ - return QObject::tr(x, y); -} -static inline QString i18nc(const char* y, const char* x, int n) -{ - return QObject::tr(x, y, n); -} -static inline QString i18nc(const char* y, const char* x, const QString& s) -{ - return QObject::tr(x, y).arg(s); -} -static inline QString i18nc(const char* y, const char* x, const QString& s1, const QString& s2) -{ - return QObject::tr(x, y).arg(s1).arg(s2); -} -static inline QString i18nc(const char* y, const char* x, int n, int m) -{ - return QObject::tr(x, y).arg(n).arg(m); -} -static inline QString i18n(const char* x, int n, int m) -{ - return QObject::tr(x).arg(n).arg(m); -} -static inline QString i18n(const char* x, const QString& s1, const QString& s2) -{ - return QObject::tr(x).arg(s1).arg(s2); -} -static inline QString i18n(const char* x) -{ - return QObject::tr(x); -} - -namespace KLocalizedString -{ -void setApplicationDomain(const char*); -}; - -#if 0 -QString i18nc(const char* y, const char* x); -QString i18nc(const char* y, const char* x, int n); -QString i18nc(const char* y, const char* x, const QString& s); -QString i18nc(const char* y, const char* x, const QString& s1, const QString& s2); -QString i18nc(const char* y, const char* x, int n, int m) -{ - return QObject::tr(x, y).arg(n).arg(m); -} -QString i18n(const char* x, int n, int m) -{ - return QObject::tr(x).arg(n).arg(m); -} -QString i18n(const char* x, const QString& s1, const QString& s2) -{ - return QObject::tr(x).arg(s1).arg(s2); -} -QString i18n(const char* x) -{ - return QObject::tr(x); -} -#endif - -#define I18N_NOOP2(y, x) x -#define I18N_NOOP(x) x - -#endif diff --git a/src/nokde-stubs/kmainwindow.h b/src/nokde-stubs/kmainwindow.h deleted file mode 100644 index fc8cfcc..0000000 --- a/src/nokde-stubs/kmainwindow.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef KMAINWINDOW_H -#define KMAINWINDOW_H - -#include "lokalize_debug.h" - -#include -#include -#include - -class KMainWindow: public QMainWindow -{ -public: - KMainWindow(QWidget*): QMainWindow(0) - { - setAttribute(Qt::WA_DeleteOnClose, true); - } - void setCaption(const QString& s, bool m = false) - { - Q_UNUSED(m) setWindowTitle(s); - } - - virtual bool queryClose() - { - return true; - } - -protected: - void closeEvent(QCloseEvent *event) - { - event->setAccepted(queryClose()); - } -}; - -#endif - diff --git a/src/nokde-stubs/kmessagebox.h b/src/nokde-stubs/kmessagebox.h deleted file mode 100644 index 2b6130d..0000000 --- a/src/nokde-stubs/kmessagebox.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef KMESSAGEBOX_H -#define KMESSAGEBOX_H - -#include - -namespace KStandardGuiItem -{ -static inline int save() -{ - return 0; -} -static inline int discard() -{ - return 0; -} -static inline int yes() -{ - return 0; -} -static inline int no() -{ - return 0; -} -}; - -#define KGuiItem(x) 0 - -class KMessageBox: public QMessageBox -{ -public: - enum {Continue = QMessageBox::Ignore}; - static QMessageBox::StandardButton warningYesNoCancel(QWidget *parent, const QString &text, - const QString &caption, - int y = 0, - int n = 0, - int c = 0, - const QString &dontAskAgainName = QString()) - { - Q_UNUSED(y) Q_UNUSED(n) Q_UNUSED(c) Q_UNUSED(dontAskAgainName) - return warning(parent, caption, text, Yes | No | Cancel, Yes); - } - static QMessageBox::StandardButton questionYesNoCancel(QWidget *parent, const QString &text, - const QString &caption, - int y = 0, - int n = 0, - int c = 0, - const QString &dontAskAgainName = QString()) - { - Q_UNUSED(y) Q_UNUSED(n) Q_UNUSED(c) Q_UNUSED(dontAskAgainName) - return question(parent, caption, text, Yes | No | Cancel, Yes); - } - - static QMessageBox::StandardButton questionYesNo(QWidget *parent, const QString &text, - const QString &caption, - int y = 0, - int n = 0, - const QString &dontAskAgainName = QString()) - { - Q_UNUSED(y) Q_UNUSED(n) Q_UNUSED(dontAskAgainName) - return question(parent, caption, text, Yes | No | Cancel, Yes); - } - static void information(QWidget *parent, - const QString &text, - const QString &caption = QString(), - const QString &dontShowAgainName = QString()) - { - Q_UNUSED(dontShowAgainName) - QMessageBox::information(parent, caption, text); - } - - static QMessageBox::StandardButton error(QWidget *parent, const QString &text) - { - return critical(parent, QString(), text); - } -}; - -#endif - diff --git a/src/nokde-stubs/kpassivepopup.h b/src/nokde-stubs/kpassivepopup.h deleted file mode 100644 index daa5cc5..0000000 --- a/src/nokde-stubs/kpassivepopup.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef KPASSIVEPOPUP_H -#define KPASSIVEPOPUP_H - - -namespace KPassivePopup -{ -enum {Balloon}; -void message(int, const QString &caption, const QString &text, - QWidget *parent) -{} - -}; - -#endif - diff --git a/src/nokde-stubs/ktextedit.h b/src/nokde-stubs/ktextedit.h deleted file mode 100644 index e426e4e..0000000 --- a/src/nokde-stubs/ktextedit.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef KTEXTEDIT_H -#define KTEXTEDIT_H - -#include - -class KTextEdit: public QTextEdit -{ -public: - KTextEdit(QWidget* p): QTextEdit(p) {} - void setHighlighter(void*) {} - -}; - -#endif - diff --git a/src/nokde-stubs/lokalizesubwindowbase.cpp b/src/nokde-stubs/lokalizesubwindowbase.cpp deleted file mode 100644 index c0e4514..0000000 --- a/src/nokde-stubs/lokalizesubwindowbase.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* **************************************************************************** - This file is part of Lokalize - - Copyright (C) 2014 by Nick Shaforostoff - - 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 "lokalizesubwindowbase.h" -#include "project.h" -#include "kaboutdata.h" -#include "klocalizedstring.h" -#include -#include -#include - -KActionCollection::KActionCollection(QMainWindow* w) - : m_mainWindow(w) - , file(m_mainWindow->menuBar()->addMenu(QApplication::translate("QMenuBar", "File"))) - , edit(m_mainWindow->menuBar()->addMenu(QApplication::translate("QMenuBar", "Edit"))) - , view(m_mainWindow->menuBar()->addMenu(QApplication::translate("QMenuBar", "View"))) - , go(m_mainWindow->menuBar()->addMenu(QApplication::translate("QMenuBar", "Go"))) - , sync(m_mainWindow->menuBar()->addMenu(QApplication::translate("QMenuBar", "Sync"))) - , tools(m_mainWindow->menuBar()->addMenu(QApplication::translate("QMenuBar", "Tools"))) - , tm(new QMenu(QApplication::translate("QMenuBar", "Translation Memory"))) - , glossary(new QMenu(QApplication::translate("QMenuBar", "Glossary"))) -{ - QAction* a = file->addAction(QApplication::translate("QMenuBar", "Open..."), Project::instance(), SLOT(fileOpen())); - a->setShortcut(QKeySequence::Open); - - a = file->addAction(QApplication::translate("QMenuBar", "Close"), m_mainWindow, SLOT(close())); - a->setShortcut(QKeySequence::Close); - - QMenu* help = m_mainWindow->menuBar()->addMenu(QApplication::translate("QMenuBar", "Help")); - a = help->addAction(QApplication::translate("QMenuBar", "About Lokalize"), KAboutData::instance, SLOT(doAbout())); - a->setMenuRole(QAction::AboutRole); - a = help->addAction(QApplication::translate("QMenuBar", "About Qt"), qApp, SLOT(aboutQt())); - a->setMenuRole(QAction::AboutQtRole); - - a = tools->addAction(i18nc("@action:inmenu", "Search and replace in files"), Project::instance(), &Project::showFileSearch); - a->setShortcut(QKeySequence::Find); - - a = tools->addAction(i18nc("@action:inmenu", "Find next in files"), Project::instance(), &Project::fileSearchNext); - a->setShortcut(QKeySequence::FindNext); - - tools->addSeparator(); - - a = tools->addAction(i18nc("@action:inmenu", "Translation memory"), Project::instance(), &Project::showTM); - a->setShortcut(Qt::Key_F7); -} - -QAction* KActionCollection::addAction(const QString& name, QAction* a) -{ - if (name.startsWith("file_")) file->addAction(a); - if (name.startsWith("edit_")) edit->addAction(a); - if (name.startsWith("merge_")) sync->addAction(a); - if (name.startsWith("go_")) go->addAction(a); - if (name.startsWith("tmquery_")) tm->addAction(a); - if (name.startsWith("glossary_insert")) glossary->addAction(a); - if (name.startsWith("show")) view->addAction(a); - if (name.startsWith("tools")) tools->addAction(a); - - if (name == "mergesecondary_back") { - if (!tm->isEmpty()) edit->addMenu(tm); - if (!glossary->isEmpty()) edit->addMenu(glossary); - } - return a; -} - - -QAction* KActionCategory::addAction(KStandardAction::StandardAction t, QObject* rcv, const char* slot) -{ - QString name = QStringLiteral("std"); - QMenu* m = 0; - QKeySequence::StandardKey k = QKeySequence::UnknownKey; - switch (t) { - case KStandardAction::Save: name = QApplication::translate("QMenuBar", "Save"); m = c->file; k = QKeySequence::Save; break; - case KStandardAction::SaveAs: name = QApplication::translate("QMenuBar", "Save As..."); m = c->file; k - QKeySequence::SaveAs; break; - case KStandardAction::Next: m = c->go; k = QKeySequence::MoveToNextPage; break; - case KStandardAction::Prior: m = c->go; k = QKeySequence::MoveToPreviousPage; break; - default:; - } - if (m) { - QAction* a = m->addAction(name, rcv, slot); - if ((int)k) a->setShortcut(k); - if (t == KStandardAction::SaveAs) - c->file->addSeparator(); - return a; - } - - QAction* a = new QAction(name, rcv); - QObject::connect(a, SIGNAL(triggered(bool)), rcv, slot); - return a; -} diff --git a/src/nokde-stubs/prefs.cpp b/src/nokde-stubs/prefs.cpp deleted file mode 100644 index 8efa5f8..0000000 --- a/src/nokde-stubs/prefs.cpp +++ /dev/null @@ -1,365 +0,0 @@ -#include "prefs.h" -#include "prefs_lokalize.h" -#include "projectbase.h" -#include "projectlocal.h" -#include "project.h" -#include "tmtab.h" -#include "filesearchtab.h" - -#include "kaboutdata.h" - -#include -#include -#include -#include -#include -#include -#include - -SettingsController* SettingsController::_instance = 0; -void SettingsController::cleanupSettingsController() -{ - delete SettingsController::_instance; - SettingsController::_instance = 0; -} - -SettingsController* SettingsController::instance() -{ - if (_instance == 0) { - _instance = new SettingsController; - ///qAddPostRoutine(SettingsController::cleanupSettingsController); - } - - return _instance; -} - -bool SettingsController::ensureProjectIsLoaded() -{ - Project::instance()->populateGlossary(); - return true; -} - -QString fullUserName();// defined in helpers.cpp - -Settings::Settings() - : mAddColor(0x99, 0xCC, 0xFF) - , mDelColor(0xFF, 0x99, 0x99) - , mMsgFont() - , mHighlightSpaces(true) - , mLeds(false) - - // Editor - , mAutoApprove(true) - , mAutoSpellcheck(true) - , mMouseWheelGo(false) - , mAltTransViewEverShownWithData(false) - - // TM - , mPrefetchTM(false) - , mAutoaddTM(true) - , mScanToTMOnOpen(false) - , mDeleteFromTMOnMissing(false) - - , mWordCompletionLength(3) - , mTabSwitch(0) - , mSuggCount(10) - , mSuggScore(0) -{ - QSettings s; - mAuthorName = s.value(QStringLiteral("Author/Name"), QString()).toString(); - if (mAuthorName.isEmpty()) { - mAuthorName = fullUserName(); - if (mAuthorName.length()) mAuthorName[0] = mAuthorName.at(0).toUpper(); - } - mAuthorEmail = s.value(QStringLiteral("Author/Email"), QString()).toString(); - - mDefaultLangCode = s.value(QStringLiteral("Editor/TargetLangCode"), QLocale::system().name()).toString(); - - mAltTransViewEverShownWithData = s.value(QStringLiteral("Editor/AltTransViewEverShownWithData"), false).toBool(); -} - -void Settings::save() -{ - QSettings s; - s.setValue(QStringLiteral("Author/Name"), mAuthorName); - s.setValue(QStringLiteral("Author/Email"), mAuthorEmail); - - s.setValue(QStringLiteral("Editor/TargetLangCode"), mDefaultLangCode); - - s.setValue(QStringLiteral("Editor/AltTransViewEverShownWithData"), mAltTransViewEverShownWithData); -} - -Settings *Settings::self() -{ - static Settings* s = new Settings; - return s; -} - - - -void writeUiState(const char* elementName, const QByteArray& state) -{ - QSettings s; - s.setValue(QStringLiteral("UI/") + QLatin1String(elementName), state.toBase64()); -} -QByteArray readUiState(const char* elementName) -{ - QSettings s; - return QByteArray::fromBase64(s.value(QStringLiteral("UI/") + QLatin1String(elementName), QByteArray()).toByteArray()); -} - - - - - -#include "editortab.h" - -ProjectBase::ProjectBase() - : m_tmTab(0) - , mProjectID(QStringLiteral("default")) - , mKind() - , mTargetLangCode(Settings::defaultLangCode()) - , mSourceLangCode("en_US") - , mPoBaseDir(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)) - , mPotBaseDir() - , mBranchDir() - , mAltDir() - , mGlossaryTbx(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/terms.tbx") - , mMainQA(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/main.lqa") - - // RegExps - , mAccel("&") - , mMarkup("(<[^>]+>)+|(&[A-Za-z_:][A-Za-z0-9_\\.:-]*;)+") - , mWordWrap(80) -{ - QSettings s; - mSourceLangCode = s.value(QStringLiteral("Project/SourceLangCode"), mSourceLangCode).toString(); - mTargetLangCode = s.value(QStringLiteral("Project/TargetLangCode"), mTargetLangCode).toString(); -} - -void ProjectBase::save() -{ - QSettings s; - s.setValue(QStringLiteral("Project/SourceLangCode"), mSourceLangCode); - s.setValue(QStringLiteral("Project/TargetLangCode"), mTargetLangCode); -} - -ProjectLocal::ProjectLocal() - : mRole(Translator) - , mFirstRun(true) -{ - QSettings s; - mRole = s.value("Project/AuthorRole", mRole).toInt(); - mSourceDir = s.value("Project/SourceDir", mSourceDir).toString(); -} - -void ProjectLocal::save() -{ - QSettings s; - s.setValue(QStringLiteral("Project/AuthorRole"), mRole); - s.setValue(QStringLiteral("Project/SourceDir"), mSourceDir); -} - -EditorTab* ProjectBase::fileOpen(QString filePath, int entry, bool setAsActive, const QString& mergeFile, bool silent) -{ - if (filePath.length()) { - FileToEditor::const_iterator it = m_fileToEditor.constFind(filePath); - if (it != m_fileToEditor.constEnd()) { - qCWarning(LOKALIZE_LOG) << "already opened:" << filePath; - if (EditorTab* e = it.value()) { - e->activateWindow(); - return e; - } - } - } - - QByteArray state = m_lastEditorState; - EditorTab* w = new EditorTab(0); - - QString suggestedDirPath; - if (EditorTab* e = qobject_cast(QApplication::activeWindow())) { - QString fp = e->currentFilePath(); - if (fp.length()) suggestedDirPath = QFileInfo(fp).absolutePath(); - } - - if (!w->fileOpen(filePath, suggestedDirPath, silent)) { - w->deleteLater(); - return 0; - } - if (filePath.length()) { - FileToEditor::const_iterator it = m_fileToEditor.constFind(filePath); - if (it != m_fileToEditor.constEnd()) { - qCWarning(LOKALIZE_LOG) << "already opened:" << filePath; - if (EditorTab* e = it.value()) { - e->activateWindow(); - w->deleteLater(); - return e; - } - } - } - - w->show(); - - if (!state.isEmpty()) - w->restoreState(QByteArray::fromBase64(state)); - - if (entry/* || offset*/) - w->gotoEntry(DocPosition(entry/*, DocPosition::Target, 0, offset*/)); - - if (!mergeFile.isEmpty()) - w->mergeOpen(mergeFile); - -// m_openRecentFileAction->addUrl(QUrl::fromLocalFile(filePath));//(w->currentUrl()); - connect(w, SIGNAL(destroyed(QObject*)), this, SLOT(editorClosed(QObject*))); - connect(w, SIGNAL(fileOpenRequested(QString, QString, QString, bool)), this, SLOT(fileOpen(QString, QString, QString, bool))); - connect(w, SIGNAL(tmLookupRequested(QString, QString)), this, SLOT(lookupInTranslationMemory(QString, QString))); - - filePath = w->currentFilePath(); - QStringRef fnSlashed = filePath.midRef(filePath.lastIndexOf('/')); - FileToEditor::const_iterator i = m_fileToEditor.constBegin(); - while (i != m_fileToEditor.constEnd()) { - if (i.key().endsWith(fnSlashed)) { - i.value()->setFullPathShown(true); - w->setFullPathShown(true); - } - ++i; - } - m_fileToEditor.insert(filePath, w); - - //emit editorAdded(); - return w; -} - -EditorTab* ProjectBase::fileOpen(const QString& filePath, const QString& source, const QString& ctxt, const bool setAsActive) -{ - EditorTab* w = fileOpen(filePath, 0, setAsActive); - if (!w) - return 0;//TODO message - w->findEntryBySourceContext(source, ctxt); - return w; -} - -EditorTab* ProjectBase::fileOpen(const QString& filePath, DocPosition docPos, int selection, const bool setAsActive) -{ - EditorTab* w = fileOpen(filePath, 0, setAsActive); - if (!w) - return 0;//TODO message - w->gotoEntry(docPos, selection); - return w; -} - -void ProjectBase::editorClosed(QObject* obj) -{ - m_fileToEditor.remove(m_fileToEditor.key(static_cast(obj))); -} - -bool ProjectBase::eventFilter(QObject *obj, QEvent *event) -{ - if (event->type() == QEvent::FileOpen) { - QFileOpenEvent *e = static_cast(event); - fileOpen(e->file()); - return true; - } - return QObject::eventFilter(obj, event); -} - -void ProjectBase::lookupInTranslationMemory(const QString& source, const QString& target) -{ - TM::TMTab* w = showTM(); - w->lookup(source, target); -} - -TM::TMTab* ProjectBase::showTM() -{ - if (!m_tmTab) { - m_tmTab = new TM::TMTab(0); - connect(m_tmTab, SIGNAL(fileOpenRequested(QString, QString, QString, bool)), this, SLOT(fileOpen(QString, QString, QString, bool))); - } - m_tmTab->show(); - m_tmTab->activateWindow(); - return m_tmTab; -} - -void ProjectBase::showFileSearch() -{ - if (!m_fileSearchTab) { - m_fileSearchTab = new FileSearchTab(0); - connect(m_fileSearchTab, SIGNAL(fileOpenRequested(QString, DocPosition, int, bool)), this, SLOT(fileOpen(QString, DocPosition, int, bool))); - connect(m_fileSearchTab, SIGNAL(fileOpenRequested(QString, bool)), this, SLOT(fileOpen(QString, bool))); - } - - if (EditorTab* e = qobject_cast(QApplication::activeWindow())) { - QString fp = e->currentFilePath(); - if (fp.length()) { - m_fileSearchTab->addFilesToSearch(QStringList(fp)); - m_fileSearchTab->setSourceQuery(e->selectionInSource()); - m_fileSearchTab->setTargetQuery(e->selectionInTarget()); - } - } - - m_fileSearchTab->show(); - m_fileSearchTab->activateWindow(); -} - -void ProjectBase::fileSearchNext() -{ - if (!m_fileSearchTab) - showFileSearch(); - else - m_fileSearchTab->fileSearchNext(); -} - - - -KAboutData* KAboutData::instance = 0; - -KAboutData::KAboutData(const QString&, const QString& n, const QString& v, const QString& d, KAboutLicense::L, const QString& c) - : name(n) - , version(v) - , description(d) - , copyright(c) -{ - KAboutData::instance = this; -} - -void KAboutData::addAuthor(const QString& name, const QString&, const QString& mail) -{ -// Credit c; -// c.name=name; -// c.mail=mail; -// credits.append(c); -} - -void KAboutData::addCredit(const QString& name, const QString& forwhat, const QString& mail, const QString& site) -{ - Credit c; - c.name = name; - c.mail = mail; - c.what = forwhat; - c.site = site; - credits.append(c); -} - - -void KAboutData::doAbout() -{ - QString cs; - foreach (const Credit& c, credits) { - cs += c.name % ": " % c.what % "
"; - } - QMessageBox::about(0, name, "

" % name % ' ' % version % "

" % description % "

" % copyright.replace('\n', "
") % "


Credits:
" % cs % "
"); -} - -namespace KLocalizedString -{ -void setApplicationDomain(const char*) {} -}; - - - - - - - - - diff --git a/src/nokde-stubs/prefs.h b/src/nokde-stubs/prefs.h deleted file mode 100644 index 525deae..0000000 --- a/src/nokde-stubs/prefs.h +++ /dev/null @@ -1,81 +0,0 @@ -/* **************************************************************************** - This file is part of Lokalize - - Copyright (C) 2007-2014 by Nick Shaforostoff - - 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 PREFS_H -#define PREFS_H - -#include - -/** - * Singleton that manages cfgs for Lokalize and projects - */ -class SettingsController: public QObject -{ - Q_OBJECT - -public: - SettingsController(): dirty(false), m_mainWindowPtr(0) {} - ~SettingsController() {} - - bool dirty; - - void setMainWindowPtr(QWidget* w) - { - m_mainWindowPtr = w; - } - QWidget* mainWindowPtr() - { - return m_mainWindowPtr; - } - -public slots: - void showSettingsDialog() {} - - bool ensureProjectIsLoaded(); - QString projectOpen(QString path = QString(), bool doOpen = true) - { - return QString(); - } - bool projectCreate() - { - return true; - } - void projectConfigure() {} - -signals: - void generalSettingsChanged(); - -private: - QWidget* m_mainWindowPtr; - -private: - static SettingsController* _instance; - static void cleanupSettingsController(); -public: - static SettingsController* instance(); -}; - -void writeUiState(const char* elementName, const QByteArray&); -QByteArray readUiState(const char* elementName); - -#endif diff --git a/src/nokde-stubs/prefs_lokalize.h b/src/nokde-stubs/prefs_lokalize.h deleted file mode 100644 index 83edf10..0000000 --- a/src/nokde-stubs/prefs_lokalize.h +++ /dev/null @@ -1,218 +0,0 @@ -// This file is generated by kconfig_compiler_kf5 from lokalize.kcfg. -#ifndef SETTINGS_H -#define SETTINGS_H - -#include - -#include -#include -#include -class Settings: public QObject -{ - Q_OBJECT -public: - - static Settings *self(); - ~Settings() {} - - void save(); - -public slots: - static void setAuthorName(const QString& v) - { - self()->mAuthorName = v; - } - static void setAuthorEmail(const QString& v) - { - self()->mAuthorEmail = v; - } - static void setDefaultLangCode(const QString& v) - { - self()->mDefaultLangCode = v; - } - -public: - static QString authorName() - { - return self()->mAuthorName; - } - static QString authorLocalizedName() - { - return self()->mAuthorLocalizedName; - } - static QString authorEmail() - { - return self()->mAuthorEmail; - } - - static - QString defaultLangCode() - { - return self()->mDefaultLangCode; - } - - static - QString defaultMailingList() - { - return self()->mDefaultMailingList; - } - - static - QColor addColor() - { - return self()->mAddColor; - } - - static - QColor delColor() - { - return self()->mDelColor; - } - - static - bool highlightSpaces() - { - return self()->mHighlightSpaces; - } - - static - QFont msgFont() - { - return self()->mMsgFont; - } - - static - void setLeds(bool v) - { - self()->mLeds = v; - } - - static - bool leds() - { - return self()->mLeds; - } - - static - bool autoApprove() - { - return self()->mAutoApprove; - } - - static - void setAutoSpellcheck(bool v) - { - self()->mAutoSpellcheck = v; - } - - static - bool autoSpellcheck() - { - return self()->mAutoSpellcheck; - } - - static - bool mouseWheelGo() - { - return self()->mMouseWheelGo; - } - - static - bool altTransViewEverShownWithData() - { - return self()->mAltTransViewEverShownWithData; - } - - static - void setAltTransViewEverShownWithData(bool v) - { - self()->mAltTransViewEverShownWithData = v; - } - - static - int wordCompletionLength() - { - return self()->mWordCompletionLength; - } - - static - int tabSwitch() - { - return self()->mTabSwitch; - } - - static - bool prefetchTM() - { - return self()->mPrefetchTM; - } - - static - int suggCount() - { - return self()->mSuggCount; - } - - static - int suggScore() - { - return self()->mSuggScore; - } - - static - bool autoaddTM() - { - return self()->mAutoaddTM; - } - - static - bool scanToTMOnOpen() - { - return self()->mScanToTMOnOpen; - } - -protected: - static - bool deleteFromTMOnMissing() - { - return self()->mDeleteFromTMOnMissing; - } - - Settings(); - friend class SettingsHelper; - - - // Identity - QString mAuthorName; - QString mAuthorLocalizedName; - QString mAuthorEmail; - QString mDefaultLangCode; - QString mDefaultMailingList; - - // Appearance - QColor mAddColor; - QColor mDelColor; - QFont mMsgFont; - bool mHighlightSpaces; - bool mLeds; - - // Editor - bool mAutoApprove; - bool mAutoSpellcheck; - bool mMouseWheelGo; - bool mAltTransViewEverShownWithData; - - // TM - bool mPrefetchTM; - bool mAutoaddTM; - bool mScanToTMOnOpen; - bool mDeleteFromTMOnMissing; - - int mWordCompletionLength; - int mTabSwitch; - int mSuggCount; - int mSuggScore; -}; - -#endif - diff --git a/src/nokde-stubs/projectbase.h b/src/nokde-stubs/projectbase.h deleted file mode 100644 index fdcfb69..0000000 --- a/src/nokde-stubs/projectbase.h +++ /dev/null @@ -1,280 +0,0 @@ -// This file is generated by kconfig_compiler_kf5 from projectbase.kcfg. -#ifndef PROJECTBASE_H -#define PROJECTBASE_H - -#include "lokalize_debug.h" - -#include -#include -#include -#include - -#include "pos.h" - -class FileSearchTab; -class EditorTab; -namespace TM -{ -class TMTab; -}; - -class ProjectBase: public QObject -{ - Q_OBJECT -public: - - ProjectBase(); - ~ProjectBase() - { - save(); - } - - bool eventFilter(QObject *obj, QEvent *event); - -public slots: - EditorTab* fileOpen(QString url = QString(), int entry = 0, bool setAsActive = true, const QString& mergeFile = QString(), bool silent = false); - EditorTab* fileOpen(const QString& filePath, const QString& source, const QString& ctxt, const bool setAsActive); - EditorTab* fileOpen(const QString& filePath, DocPosition docPos, int selection, const bool setAsActive); - - void lookupInTranslationMemory(const QString& source, const QString& target); - TM::TMTab* showTM(); - void showFileSearch(); - void fileSearchNext(); - - void editorClosed(QObject* obj); -private: - //using QPointer switches it.value() to 0 before we get to destroyed() handler - //typedef QMap > FileToEditor; - typedef QMap FileToEditor; - FileToEditor m_fileToEditor; - QByteArray m_lastEditorState; - QPointer m_tmTab; - QPointer m_fileSearchTab; - - -public: - void setProjectID(const QString & v) - { - mProjectID = v; - } - - QString projectID() const - { - return mProjectID; - } - - void setKind(const QString & v) - { - mKind = v; - } - - QString kind() const - { - return mKind; - } - - void setLangCode(const QString &) - { - //this is called from setDefaults() - //mTargetLangCode = v; - } - - QString langCode() const - { - return mTargetLangCode; - } -public slots: - void setTargetLangCode(const QString & v) - { - mTargetLangCode = v; - } - void setSourceLangCode(const QString & v) - { - mSourceLangCode = v; - } -public: - QString targetLangCode() const - { - return mTargetLangCode; - } - QString sourceLangCode() const - { - return mSourceLangCode; - } - - void setMailingList(const QString & v) - { - mMailingList = v; - } - - QString mailingList() const - { - return mMailingList; - } - - void setPoBaseDir(const QString & v) - { - mPoBaseDir = v; - } - - QString poBaseDir() const - { - return mPoBaseDir; - } - - /** - Set PotBaseDir - */ - void setPotBaseDir(const QString & v) - { - mPotBaseDir = v; - } - - /** - Get PotBaseDir - */ - QString potBaseDir() const - { - return mPotBaseDir; - } - - /** - Set BranchDir - */ - void setBranchDir(const QString & v) - { - mBranchDir = v; - } - - /** - Get BranchDir - */ - QString branchDir() const - { - return mBranchDir; - } - - /** - Set AltDir - */ - void setAltDir(const QString & v) - { - mAltDir = v; - } - - /** - Get AltDir - */ - QString altDir() const - { - return mAltDir; - } - - /** - Set GlossaryTbx - */ - void setGlossaryTbx(const QString & v) - { - mGlossaryTbx = v; - } - - /** - Get GlossaryTbx - */ - QString glossaryTbx() const - { - return mGlossaryTbx; - } - - /** - Set MainQA - */ - void setMainQA(const QString & v) - { - mMainQA = v; - } - - /** - Get MainQA - */ - QString mainQA() const - { - return mMainQA; - } - - /** - Set Accel - */ - void setAccel(const QString & v) - { - mAccel = v; - } - - /** - Get Accel - */ - QString accel() const - { - return mAccel; - } - - /** - Set Markup - */ - void setMarkup(const QString & v) - { - mMarkup = v; - } - - /** - Get Markup - */ - QString markup() const - { - return mMarkup; - } - - /** - Set WordWrap - */ - void setWordWrap(int v) - { - mWordWrap = v; - } - - /** - Get WordWrap - */ - int wordWrap() const - { - return mWordWrap; - } - - void save(); - void setDefaults() {} -protected: - - // General - QString mProjectID; - QString mKind; - QString mLangCode; - QString mTargetLangCode; - QString mSourceLangCode; - QString mMailingList; - QString mPoBaseDir; - QString mPotBaseDir; - QString mBranchDir; - QString mAltDir; - QString mGlossaryTbx; - QString mMainQA; - - // RegExps - QString mAccel; - QString mMarkup; - int mWordWrap; - -private: -}; - -#endif - diff --git a/src/nokde-stubs/projectlocal.h b/src/nokde-stubs/projectlocal.h deleted file mode 100644 index dd66a00..0000000 --- a/src/nokde-stubs/projectlocal.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef PROJECTLOCAL_H -#define PROJECTLOCAL_H - -#include - -class ProjectLocal: public QObject -{ - Q_OBJECT - -public: - enum PersonRole { Translator, Reviewer, Approver, Undefined }; - - ProjectLocal(); - ~ProjectLocal() - { - save(); - } - -public slots: - void setRole(int v) - { - mRole = (PersonRole)v; - } -public: - void setRole(PersonRole v) - { - mRole = v; - } - PersonRole role() const - { - return static_cast(mRole); - } - - void setFirstRun(bool v) - { - mFirstRun = v; - } - bool firstRun() const - { - return mFirstRun; - } - - void setSourceDir(const QString& s) - { - mSourceDir = s; - } - QString sourceDir() const - { - return mSourceDir; - } - - void save(); - void setDefaults() {} -protected: - - // Personal - int mRole; - bool mFirstRun; - QString mSourceDir; - -private: -}; - -#endif - diff --git a/src/nokde-stubs/welcometab.cpp b/src/nokde-stubs/welcometab.cpp deleted file mode 100644 index 4ca7e5a..0000000 --- a/src/nokde-stubs/welcometab.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* **************************************************************************** - This file is part of Lokalize - - Copyright (C) 2014 by Nick Shaforostoff - - 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 "welcometab.h" -#include "prefs_lokalize.h" -#include "languagelistmodel.h" -#include "tmscanapi.h" -#include "project.h" -#include "catalog.h" -#include - -#include -#include -#include - -WelcomeTab::WelcomeTab(QWidget *parent) - : LokalizeSubwindowBase2(parent) -{ -#ifndef Q_OS_DARWIN - menuBar()->hide(); -#endif - setWindowTitle("Lokalize"/*i18nc("@title:window","Lokalize")*/);//setCaption(i18nc("@title:window","Project"),false); - setAcceptDrops(true); - setCentralWidget(new QWidget(this)); - - setupUi(centralWidget()); - - QStringList i; - i << i18n("Translator") << i18n("Reviewer") << i18n("Approver"); - roleCombo->addItems(i); - roleCombo->setCurrentIndex(Project::instance()->local()->role()); - connect(roleCombo, SIGNAL(currentIndexChanged(int)), Project::instance()->local(), SLOT(setRole(int))); - - sourceLangCombo->setModel(LanguageListModel::instance()->sortModel()); - targetLangCombo->setModel(LanguageListModel::instance()->sortModel()); - sourceLangCombo->setCurrentIndex(LanguageListModel::instance()->sortModelRowForLangCode(Project::instance()->sourceLangCode())); - targetLangCombo->setCurrentIndex(LanguageListModel::instance()->sortModelRowForLangCode(Project::instance()->targetLangCode())); - LangCodeSaver* s = new LangCodeSaver(this); - LangCodeSaver* t = new LangCodeSaver(this); - connect(sourceLangCombo, SIGNAL(currentIndexChanged(int)), s, SLOT(setLangCode(int))); - connect(targetLangCombo, SIGNAL(currentIndexChanged(int)), t, SLOT(setLangCode(int))); - connect(s, SIGNAL(langCodeSelected(QString)), Project::instance(), SLOT(setSourceLangCode(QString))); - connect(t, SIGNAL(langCodeSelected(QString)), Project::instance(), SLOT(setTargetLangCode(QString))); - connect(t, SIGNAL(langCodeSelected(QString)), Settings::self(), SLOT(setDefaultLangCode(QString))); - - authorNameEdit->setText(Settings::self()->authorName()); - connect(authorNameEdit, SIGNAL(textChanged(QString)), Settings::self(), SLOT(setAuthorName(QString))); - - glossaryPathEdit->setText(Project::instance()->glossaryPath()); -} - -WelcomeTab::~WelcomeTab() -{ -} - -void LangCodeSaver::setLangCode(int index) -{ - emit langCodeSelected(LanguageListModel::instance()->langCodeForSortModelRow(index)); -} - -void WelcomeTab::dragEnterEvent(QDragEnterEvent* event) -{ - if (dragIsAcceptable(event->mimeData()->urls())) - event->acceptProposedAction(); -} - -void WelcomeTab::dropEvent(QDropEvent* event) -{ - foreach (const QUrl& url, event->mimeData()->urls()) { - const QString& filePath = url.toLocalFile(); - if (Catalog::extIsSupported(filePath) - && Project::instance()->fileOpen(filePath)) { - event->acceptProposedAction(); - } - } -} - diff --git a/src/nokde-stubs/welcometab.h b/src/nokde-stubs/welcometab.h deleted file mode 100644 index e6c65da..0000000 --- a/src/nokde-stubs/welcometab.h +++ /dev/null @@ -1,57 +0,0 @@ -/* **************************************************************************** - This file is part of Lokalize - - Copyright (C) 2014 by Nick Shaforostoff - - 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 WELCOMETAB_H -#define WELCOMETAB_H - -#include "lokalizesubwindowbase.h" -#include "ui_welcomewidget.h" - -class WelcomeTab: public LokalizeSubwindowBase2, public Ui_WelcomeWidget -{ - Q_OBJECT - -public: - WelcomeTab(QWidget* parent); - ~WelcomeTab(); - -protected: - virtual void dragEnterEvent(QDragEnterEvent*); - virtual void dropEvent(QDropEvent*); - -}; - -//helps translate 'Russian (ru_UA)' -> 'ru_UA' -class LangCodeSaver: public QObject -{ - Q_OBJECT -public: - LangCodeSaver(QWidget* p): QObject(p) {} -public slots: - void setLangCode(int index); -signals: - void langCodeSelected(const QString&); -}; - - -#endif diff --git a/src/nokde-stubs/welcomewidget.ui b/src/nokde-stubs/welcomewidget.ui deleted file mode 100644 index 770ba3b..0000000 --- a/src/nokde-stubs/welcomewidget.ui +++ /dev/null @@ -1,81 +0,0 @@ - - - WelcomeWidget - - - - 0 - 0 - 389 - 276 - - - - - QFormLayout::AllNonFixedFieldsGrow - - - - - <html><head/><body><p align="center">Welcome to Lokalize!</p><p>Drop a translation file here to start editing it.</p><p>You can help translating KDE into your mother language by going to <a href="http://l10n.kde.org/"><span style=" text-decoration: underline; color:#0000ff;">KDE localization site</span></a> and contacting appropriate language team.</p><p><br/></p><p><br/></p></body></html> - - - true - - - - - - - Your name: - - - - - - - - - - Your role (XLIFF only): - - - - - - - - - - Default source language: - - - - - - - Default target language: - - - - - - - - - - - - - Glossary file: - - - - - - - - - - - diff --git a/src/phaseswindow.cpp b/src/phaseswindow.cpp index b01e775..a02992d 100644 --- a/src/phaseswindow.cpp +++ b/src/phaseswindow.cpp @@ -1,366 +1,360 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2009-2014 by Nick Shaforostoff 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 "phaseswindow.h" #include "catalog.h" #include "cmd.h" #include "noteeditor.h" #include "project.h" #include #include - -#ifndef NOKDE #include -#endif #include #include #include #include #include #include #include #include #include #include #include #include //BEGIN PhasesModel class PhasesModel: public QAbstractListModel { public: enum PhasesModelColumns { Date = 0, Process, Company, Contact, ToolName, ColumnCount }; PhasesModel(Catalog* catalog, QObject* parent); ~PhasesModel() {} QModelIndex addPhase(const Phase& phase); QModelIndex activePhaseIndex()const { return index(m_activePhase); } QList addedPhases()const; int rowCount(const QModelIndex& parent = QModelIndex()) const; int columnCount(const QModelIndex& parent = QModelIndex()) const { Q_UNUSED(parent); return ColumnCount; } QVariant data(const QModelIndex&, int role = Qt::DisplayRole) const; QVariant headerData(int section, Qt::Orientation, int role = Qt::DisplayRole) const; private: Catalog* m_catalog; QList m_phases; QMap m_tools; int m_activePhase; }; PhasesModel::PhasesModel(Catalog* catalog, QObject* parent) : QAbstractListModel(parent) , m_catalog(catalog) , m_phases(catalog->allPhases()) , m_tools(catalog->allTools()) { m_activePhase = m_phases.size(); while (--m_activePhase >= 0 && m_phases.at(m_activePhase).name != catalog->activePhase()) ; } QModelIndex PhasesModel::addPhase(const Phase& phase) { m_activePhase = m_phases.size(); beginInsertRows(QModelIndex(), m_activePhase, m_activePhase); m_phases.append(phase); endInsertRows(); return index(m_activePhase); } QList PhasesModel::addedPhases()const { QList result; for (int i = m_catalog->allPhases().size(); i < m_phases.size(); ++i) result.append(m_phases.at(i)); return result; } int PhasesModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; return m_phases.size(); } QVariant PhasesModel::data(const QModelIndex& index, int role) const { if (role == Qt::FontRole && index.row() == m_activePhase) { QFont font = QApplication::font(); font.setBold(true); return font; } if (role == Qt::UserRole) return m_phases.at(index.row()).name; if (role != Qt::DisplayRole) return QVariant(); const Phase& phase = m_phases.at(index.row()); switch (index.column()) { case Date: return phase.date.toString(); case Process: return phase.process; case Company: return phase.company; case Contact: return QString(phase.contact % (phase.email.isEmpty() ? QString() : QStringLiteral(" <%1> ").arg(phase.email)) % (phase.phone.isEmpty() ? QString() : QStringLiteral(", %1").arg(phase.phone))); case ToolName: return m_tools.value(phase.tool).name; } return QVariant(); } QVariant PhasesModel::headerData(int section, Qt::Orientation, int role) const { if (role != Qt::DisplayRole) return QVariant(); switch (section) { case Date: return i18nc("@title:column", "Date"); case Process: return i18nc("@title:column", "Process"); case Company: return i18nc("@title:column", "Company"); case Contact: return i18nc("@title:column", "Person"); case ToolName: return i18nc("@title:column", "Tool"); } return QVariant(); } //END PhasesModel //BEGIN PhaseEditDialog class PhaseEditDialog: public QDialog { public: PhaseEditDialog(QWidget *parent); ~PhaseEditDialog() {} Phase phase()const; ProjectLocal::PersonRole role()const; private: KComboBox* m_process; }; PhaseEditDialog::PhaseEditDialog(QWidget *parent) : QDialog(parent) , m_process(new KComboBox(this)) { QStringList processes; processes << i18n("Translation") << i18n("Review") << i18n("Approval"); m_process->setModel(new QStringListModel(processes, this)); QFormLayout* l = new QFormLayout(this); l->addRow(i18nc("noun", "Process (this will also change your role):"), m_process); QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); connect(buttonBox, &QDialogButtonBox::accepted, this, &PhaseEditDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &PhaseEditDialog::reject); l->addRow(buttonBox); } Phase PhaseEditDialog::phase() const { Phase phase; phase.process = processes()[m_process->currentIndex()]; return phase; } ProjectLocal::PersonRole PhaseEditDialog::role() const { return (ProjectLocal::PersonRole)m_process->currentIndex(); } PhasesWindow::PhasesWindow(Catalog* catalog, QWidget *parent) : QDialog(parent) , m_catalog(catalog) , m_model(new PhasesModel(catalog, this)) , m_view(new MyTreeView(this)) , m_browser(new QTextBrowser(this)) , m_editor(0) { connect(this, &PhasesWindow::accepted, this, &PhasesWindow::handleResult); //setAttribute(Qt::WA_DeleteOnClose, true); QVBoxLayout* l = new QVBoxLayout(this); QHBoxLayout* btns = new QHBoxLayout; l->addLayout(btns); QPushButton* add = new QPushButton(this); -#ifndef NOKDE KGuiItem::assign(add, KStandardGuiItem::add()); -#else - add->setText(tr("Add")); -#endif + connect(add, &QPushButton::clicked, this, &PhasesWindow::addPhase); btns->addWidget(add); btns->addStretch(5); QSplitter* splitter = new QSplitter(this); l->addWidget(splitter); m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); connect(m_buttonBox, &QDialogButtonBox::accepted, this, &PhasesWindow::accept); connect(m_buttonBox, &QDialogButtonBox::rejected, this, &PhasesWindow::reject); l->addWidget(m_buttonBox); m_view->setRootIsDecorated(false); m_view->setModel(m_model); splitter->addWidget(m_view); int column = m_model->columnCount(); while (--column >= 0) m_view->resizeColumnToContents(column); if (m_model->rowCount()) m_view->setCurrentIndex(m_model->activePhaseIndex()); connect(m_view, &MyTreeView::currentIndexChanged, this, &PhasesWindow::displayPhaseNotes); m_noteView = new QWidget(this); m_noteView->hide(); splitter->addWidget(m_noteView); m_stackedLayout = new QStackedLayout(m_noteView); m_stackedLayout->addWidget(m_browser); m_browser->viewport()->setBackgroundRole(QPalette::Background); m_browser->setOpenLinks(false); connect(m_browser, &QTextBrowser::anchorClicked, this, &PhasesWindow::anchorClicked); splitter->setStretchFactor(0, 15); splitter->setStretchFactor(1, 5); resize(QSize(700, 400)); } void PhasesWindow::handleResult() { m_catalog->beginMacro(i18nc("@item Undo action item", "Edit phases")); Phase last; foreach (const Phase& phase, m_model->addedPhases()) static_cast(m_catalog)->push(new UpdatePhaseCmd(m_catalog, last = phase)); Project::instance()->local()->setRole(roleForProcess(last.process)); m_catalog->setActivePhase(last.name, roleForProcess(last.process)); QMapIterator > i(m_phaseNotes); while (i.hasNext()) { i.next(); m_catalog->setPhaseNotes(i.key(), i.value()); } m_catalog->endMacro(); } void PhasesWindow::addPhase() { PhaseEditDialog d(this); if (!d.exec()) return; Phase phase = d.phase(); initPhaseForCatalog(m_catalog, phase, ForceAdd); m_view->setCurrentIndex(m_model->addPhase(phase)); m_phaseNotes.insert(phase.name, QVector()); m_buttonBox->button(QDialogButtonBox::Ok)->setFocus(); } static QString phaseNameFromView(QTreeView* view) { return view->currentIndex().data(Qt::UserRole).toString(); } void PhasesWindow::anchorClicked(QUrl link) { QString path = link.path().mid(1); // minus '/' if (link.scheme() == QLatin1String("note")) { if (!m_editor) { m_editor = new NoteEditor(this); m_stackedLayout->addWidget(m_editor); connect(m_editor, &NoteEditor::accepted, this, &PhasesWindow::noteEditAccepted); connect(m_editor, &NoteEditor::rejected, this, &PhasesWindow::noteEditRejected); } m_editor->setNoteAuthors(m_catalog->noteAuthors()); if (path.endsWith(QLatin1String("add"))) m_editor->setNote(Note(), -1); else { int pos = path.toInt(); QString phaseName = phaseNameFromView(m_view); QVector notes = m_phaseNotes.contains(phaseName) ? m_phaseNotes.value(phaseName) : m_catalog->phaseNotes(phaseName); m_editor->setNote(notes.at(pos), pos); } m_stackedLayout->setCurrentIndex(1); } } void PhasesWindow::noteEditAccepted() { QString phaseName = phaseNameFromView(m_view); if (!m_phaseNotes.contains(phaseName)) m_phaseNotes.insert(phaseName, m_catalog->phaseNotes(phaseName)); //QVector notes=m_phaseNotes.value(phaseName); if (m_editor->noteIndex() == -1) m_phaseNotes[phaseName].append(m_editor->note()); else m_phaseNotes[phaseName][m_editor->noteIndex()] = m_editor->note(); m_stackedLayout->setCurrentIndex(0); displayPhaseNotes(m_view->currentIndex()); } void PhasesWindow::noteEditRejected() { m_stackedLayout->setCurrentIndex(0); } void PhasesWindow::displayPhaseNotes(const QModelIndex& current) { m_browser->clear(); QString phaseName = current.data(Qt::UserRole).toString(); QVector notes = m_phaseNotes.contains(phaseName) ? m_phaseNotes.value(phaseName) : m_catalog->phaseNotes(phaseName); displayNotes(m_browser, notes); m_noteView->show(); m_stackedLayout->setCurrentIndex(0); } diff --git a/src/project/project.cpp b/src/project/project.cpp index 364d0b5..6967fb8 100644 --- a/src/project/project.cpp +++ b/src/project/project.cpp @@ -1,519 +1,498 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2014 by Nick Shaforostoff 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 -#ifndef NOKDE #include "projectmodel.h" #include "webquerycontroller.h" #include #include #include #include #include #include #include #include using namespace Kross; -#endif 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("i18n-nb@lister.ping.uio.no"); if (lang.startsWith(QLatin1String("nl"))) return QLatin1String("kde-i18n-nl@kde.org"); if (lang.startsWith(QLatin1String("nn"))) return QLatin1String("i18n-nn@lister.ping.uio.no"); 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("i18n-sme@lister.ping.uio.no"); 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) { QTime 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 -#ifndef NOKDE setSharedConfig(KSharedConfig::openConfig(newProjectPath, KConfig::NoGlobals)); if (!QFileInfo::exists(newProjectPath)) Project::instance()->setDefaults(); ProjectBase::load(); -#else -#endif m_path = newProjectPath; m_desirablePath.clear(); //cache: m_projectDir = QFileInfo(m_path).absolutePath(); -#ifndef NOKDE m_localConfig->setSharedConfig(KSharedConfig::openConfig(projectID() + QStringLiteral(".local"), KConfig::NoGlobals, QStandardPaths::DataLocation)); m_localConfig->load(); -#endif 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(); 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() { -#ifndef NOKDE 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); -#endif } 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(0, 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() { -#ifndef NOKDE if (Q_UNLIKELY(!m_model)) m_model = new ProjectModel(this); return m_model; -#else - return 0; -#endif } 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(); private: QString m_folderName; }; SourceFilesSearchJob::SourceFilesSearchJob(const QString& folderName, QObject* parent) : KJob(parent) , m_folderName(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() { QMultiMap sourceFilePaths; fillFilePathsRecursive(startingDir, sourceFilePaths); Project::instance()->m_sourceFilePaths = sourceFilePaths; 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)); } -#endif const QMultiMap& Project::sourceFilePaths() { if (m_sourceFilePaths.isEmpty()) { QDir dir(local()->sourceDir()); if (dir.exists()) { -#ifndef NOKDE 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(); -#else - QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - fillFilePathsRecursive(dir, m_sourceFilePaths); - QApplication::restoreOverrideCursor(); -#endif } } 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/syntaxhighlighter.cpp b/src/syntaxhighlighter.cpp index a0b3d4a..cc832b0 100644 --- a/src/syntaxhighlighter.cpp +++ b/src/syntaxhighlighter.cpp @@ -1,303 +1,278 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2009 by Nick Shaforostoff 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 "syntaxhighlighter.h" #include "lokalize_debug.h" #include "project.h" #include "prefs_lokalize.h" #include "prefs.h" -#ifndef NOKDE #include -#endif #include #include #include #define STATE_NORMAL 0 #define STATE_TAG 1 #define NUM_OF_RULES 5 SyntaxHighlighter::SyntaxHighlighter(QTextEdit *parent) -#ifndef NOKDE : Sonnet::Highlighter(parent) , tagBrush(KColorScheme::View, KColorScheme::VisitedText) -#elif defined(SONNET_STATIC) - : Sonnet::Highlighter(parent) -#else - : QSyntaxHighlighter(parent->document()) -#endif , m_approved(true) // , fromDocbook(docbook) { highlightingRules.reserve(NUM_OF_RULES); HighlightingRule rule; //rule.format.setFontItalic(true); // tagFormat.setForeground(tagBrush.brush(QApplication::palette())); -#if !defined(NOKDE) || defined(SONNET_STATIC) setAutomatic(false); -#endif -#ifndef NOKDE tagFormat.setForeground(tagBrush.brush(QApplication::palette())); -#else - tagFormat.setForeground(QApplication::palette().linkVisited()); -#endif + //QTextCharFormat format; //tagFormat.setForeground(Qt::darkBlue); // if (!docbook) //support multiline tags // { // rule.format = tagFormat; // rule.pattern = QRegExp("<.+>"); // rule.pattern.setMinimal(true); // highlightingRules.append(rule); // } //entity rule.format.setForeground(Qt::darkMagenta); rule.pattern = QRegExp(QStringLiteral("(&[A-Za-z_:][A-Za-z0-9_\\.:-]*;)")); highlightingRules.append(rule); QString accel = Project::instance()->accel(); if (!accel.isEmpty()) { rule.format.setForeground(Qt::darkMagenta); rule.pattern = QRegExp(accel); highlightingRules.append(rule); } //\n \t \" rule.format.setForeground(Qt::darkGreen); rule.pattern = QRegExp(QStringLiteral("(\\\\[abfnrtv'\?\\\\])|(\\\\\\d+)|(\\\\x[\\dabcdef]+)")); highlightingRules.append(rule); //spaces settingsChanged(); connect(SettingsController::instance(), &SettingsController::generalSettingsChanged, this, &SyntaxHighlighter::settingsChanged); } void SyntaxHighlighter::settingsChanged() { QRegExp re(" +$|^ +|.?" % QChar(0x0000AD) % ".?"); //soft hyphen if (Settings::highlightSpaces() && highlightingRules.last().pattern != re) { HighlightingRule rule; rule.format.clearForeground(); -#ifndef NOKDE KColorScheme colorScheme(QPalette::Normal); //nbsp //rule.format.setBackground(colorScheme.background(KColorScheme::NegativeBackground)); rule.format.setBackground(colorScheme.foreground(KColorScheme::InactiveText)); -#else - rule.format.setBackground(QApplication::palette().alternateBase()); -#endif rule.format.setFontLetterSpacing(200); rule.pattern = QRegExp(QChar(0x00a0U), Qt::CaseSensitive, QRegExp::FixedString); highlightingRules.append(rule); //usual spaces at the end rule.format.setFontLetterSpacing(100); -#ifndef NOKDE rule.format.setBackground(colorScheme.background(KColorScheme::ActiveBackground)); -#else - rule.format.setBackground(QApplication::palette().midlight()); -#endif rule.pattern = re; highlightingRules.append(rule); rehighlight(); } else if (!Settings::highlightSpaces() && highlightingRules.last().pattern == re) { highlightingRules.resize(highlightingRules.size() - 2); rehighlight(); } } /* void SyntaxHighlighter::setFuzzyState(bool fuzzy) { return; int i=NUM_OF_RULES; while(--i>=0) highlightingRules[i].format.setFontItalic(fuzzy); tagFormat.setFontItalic(fuzzy); }*/ void SyntaxHighlighter::highlightBlock(const QString &text) { int currentBlockState = STATE_NORMAL; QTextCharFormat f; f.setFontItalic(!m_approved); setFormat(0, text.length(), f); tagFormat.setFontItalic(!m_approved); //if (fromDocbook) { int startIndex = STATE_NORMAL; if (previousBlockState() != STATE_TAG) startIndex = text.indexOf('<'); while (startIndex >= 0) { int endIndex = text.indexOf('>', startIndex); int commentLength; if (endIndex == -1) { currentBlockState = STATE_TAG; commentLength = text.length() - startIndex; } else { commentLength = endIndex - startIndex + 1/*+ commentEndExpression.matchedLength()*/; } setFormat(startIndex, commentLength, tagFormat); startIndex = text.indexOf('<', startIndex + commentLength); } } foreach (const HighlightingRule &rule, highlightingRules) { QRegExp expression(rule.pattern); int index = expression.indexIn(text); while (index >= 0) { int length = expression.matchedLength(); QTextCharFormat f = rule.format; f.setFontItalic(!m_approved); setFormat(index, length, f); index = expression.indexIn(text, index + length); } } -#if !defined(NOKDE) || defined(SONNET_STATIC) if (spellCheckerFound()) Sonnet::Highlighter::highlightBlock(text); // Resets current block state -#endif setCurrentBlockState(currentBlockState); } #if 0 void SyntaxHighlighter::setFormatRetainingUnderlines(int start, int count, QTextCharFormat f) { QVector underLines(count); for (int i = 0; i < count; ++i) underLines[i] = format(start + i).fontUnderline(); setFormat(start, count, f); f.setFontUnderline(true); int prevStart = -1; bool isPrevUnderLined = false; for (int i = 0; i < count; ++i) { if (!underLines.at(i) && prevStart != -1) setFormat(start + isPrevUnderLined, i - prevStart, f); else if (underLines.at(i) && !isPrevUnderLined) prevStart = i; isPrevUnderLined = underLines.at(i); } } #endif void SyntaxHighlighter::setMisspelled(int start, int count) { -#if !defined(NOKDE) || defined(SONNET_STATIC) const Project& project = *Project::instance(); const QString text = currentBlock().text(); QString word = text.mid(start, count); if (m_sourceString.contains(word) && project.targetLangCode().leftRef(2) != project.sourceLangCode().leftRef(2)) return; const QString accel = project.accel(); if (!isWordMisspelled(word.remove(accel))) return; count = word.length(); //safety bool smthPreceeding = (start > 0) && (accel.endsWith(text.at(start - 1)) || text.at(start - 1) == QChar(0x0000AD) //soft hyphen ); //HACK. Needs Sonnet API redesign (KDE 5) if (smthPreceeding) { qCWarning(LOKALIZE_LOG) << "ampersand is in the way. word len:" << count; int realStart = text.lastIndexOf(QRegExp("\\b"), start - 2); if (realStart == -1) realStart = 0; QString t = text.mid(realStart, count + start - realStart); t.remove(accel); t.remove(QChar(0x0000AD)); if (!isWordMisspelled(t)) return; } bool smthAfter = (start + count + 1 < text.size()) && (accel.startsWith(text.at(start + count)) || text.at(start + count) == QChar(0x0000AD) //soft hyphen ); if (smthAfter) { qCWarning(LOKALIZE_LOG) << "smthAfter. ampersand is in the way. word len:" << count; int realEnd = text.indexOf(QRegExp(QStringLiteral("\\b")), start + count + 2); if (realEnd == -1) realEnd = text.size(); QString t = text.mid(start, realEnd - start); t.remove(accel); t.remove(QChar(0x0000AD)); if (!isWordMisspelled(t)) return; } if (count && format(start) == tagFormat) return; for (int i = 0; i < count; ++i) { QTextCharFormat f(format(start + i)); f.setFontUnderline(true); f.setUnderlineStyle(QTextCharFormat::SpellCheckUnderline); f.setUnderlineColor(Qt::red); setFormat(start + i, 1, f); } -#endif } void SyntaxHighlighter::unsetMisspelled(int start, int count) { for (int i = 0; i < count; ++i) { QTextCharFormat f(format(start + i)); f.setFontUnderline(false); setFormat(start + i, 1, f); } } diff --git a/src/syntaxhighlighter.h b/src/syntaxhighlighter.h index 1abede4..cbf4167 100644 --- a/src/syntaxhighlighter.h +++ b/src/syntaxhighlighter.h @@ -1,89 +1,79 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2009 by Nick Shaforostoff 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 HIGHLIGHTER_H #define HIGHLIGHTER_H #include -#ifndef NOKDE #include #include -#elif defined(SONNET_STATIC) -#include "highlighter.h" -#endif #include #include class QTextDocument; class QTextEdit; -#if !defined(NOKDE) || defined(SONNET_STATIC) class SyntaxHighlighter : public Sonnet::Highlighter -#else -class SyntaxHighlighter : public QSyntaxHighlighter -#endif { Q_OBJECT public: explicit SyntaxHighlighter(QTextEdit *parent); ~SyntaxHighlighter() {}; void setApprovementState(bool a) { m_approved = a; }; void setSourceString(const QString& s) { m_sourceString = s; } protected: void highlightBlock(const QString &text); void setMisspelled(int start, int count); void unsetMisspelled(int start, int count); private slots: void settingsChanged(); // void setFormatRetainingUnderlines(int start, int count, QTextCharFormat format); private: struct HighlightingRule { QRegExp pattern; QTextCharFormat format; }; QVector highlightingRules; // bool fromDocbook; QTextCharFormat tagFormat; -#ifndef NOKDE KStatefulBrush tagBrush; -#endif bool m_approved; QString m_sourceString; }; #endif diff --git a/src/tm/tmscanapi.cpp b/src/tm/tmscanapi.cpp index eab610f..40a503a 100644 --- a/src/tm/tmscanapi.cpp +++ b/src/tm/tmscanapi.cpp @@ -1,201 +1,181 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2014 by Nick Shaforostoff 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 "tmscanapi.h" #include "lokalize_debug.h" #include "jobs.h" #include "catalog.h" #include "prefs_lokalize.h" #include "gettextheader.h" #include "dbfilesmodel.h" #include "project.h" #include -#ifndef NOKDE #include #include #include -#else -class KJob; -#endif namespace TM { static QVector doScanRecursive(const QDir& dir, const QString& dbName, KJob* metaJob); } using namespace TM; -#ifndef NOKDE RecursiveScanJob::RecursiveScanJob(const QString& dbName, QObject* parent) : KJob(parent) , m_dbName(dbName) { setCapabilities(KJob::Killable); } bool RecursiveScanJob::doKill() { #if QT_VERSION >= 0x050500 foreach (ScanJob* job, m_jobs) TM::threadPool()->cancel(job); #endif return true; } void RecursiveScanJob::setJobs(const QVector& jobs) { m_jobs = jobs; setTotalAmount(KJob::Files, jobs.size()); if (!jobs.size()) kill(KJob::EmitResult); } void RecursiveScanJob::scanJobFinished(ScanJobFeedingBack* j) { j->deleteLater(); ScanJob* job = static_cast(j); setProcessedAmount(KJob::Files, processedAmount(KJob::Files) + 1); emitPercent(processedAmount(KJob::Files), totalAmount(KJob::Files)); setProcessedAmount(KJob::Bytes, processedAmount(KJob::Bytes) + job->m_size); if (m_time.elapsed()) emitSpeed(1000 * processedAmount(KJob::Bytes) / m_time.elapsed()); if (processedAmount(KJob::Files) == totalAmount(KJob::Files)) { emitResult(); qCDebug(LOKALIZE_LOG) << "finished in" << m_time.elapsed() << "msecs"; } } void RecursiveScanJob::start() { m_time.start(); emit description(this, i18n("Adding files to Lokalize translation memory"), qMakePair(i18n("TM"), m_dbName)); } -#endif int TM::scanRecursive(const QStringList& filePaths, const QString& dbName) { -#ifndef NOKDE RecursiveScanJob* metaJob = new RecursiveScanJob(dbName); KIO::getJobTracker()->registerJob(metaJob); metaJob->start(); -#else - KJob* metaJob = 0; -#endif if (!askAuthorInfoIfEmpty()) return 0; QVector result; int i = filePaths.size(); while (--i >= 0) { const QString& filePath = filePaths.at(i); if (filePath.isEmpty()) continue; if (Catalog::extIsSupported(filePath)) { -#ifndef NOKDE ScanJobFeedingBack* job = new ScanJobFeedingBack(filePath, dbName); QObject::connect(job, &ScanJobFeedingBack::done, metaJob, &RecursiveScanJob::scanJobFinished); -#else - ScanJob* job = new ScanJob(filePath, dbName); -#endif TM::threadPool()->start(job, SCAN); result.append(job); } else result += doScanRecursive(QDir(filePath), dbName, metaJob); } -#ifndef NOKDE metaJob->setJobs(result); -#endif DBFilesModel::instance()->openDB(dbName); //update stats after it finishes return result.size(); } //returns gross number of jobs started static QVector TM::doScanRecursive(const QDir& dir, const QString& dbName, KJob* metaJob) { QVector result; QStringList subDirs(dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Readable)); int i = subDirs.size(); while (--i >= 0) result += TM::doScanRecursive(QDir(dir.filePath(subDirs.at(i))), dbName, metaJob); QStringList filters = Catalog::supportedExtensions(); i = filters.size(); while (--i >= 0) filters[i].prepend('*'); QStringList files(dir.entryList(filters, QDir::Files | QDir::NoDotAndDotDot | QDir::Readable)); i = files.size(); while (--i >= 0) { -#ifndef NOKDE ScanJobFeedingBack* job = new ScanJobFeedingBack(dir.filePath(files.at(i)), dbName); QObject::connect(job, &ScanJobFeedingBack::done, (RecursiveScanJob*)metaJob, &RecursiveScanJob::scanJobFinished); -#else - ScanJob* job = new ScanJob(dir.filePath(files.at(i)), dbName); -#endif TM::threadPool()->start(job, SCAN); result.append(job); } return result; } bool dragIsAcceptable(const QList& urls) { int i = urls.size(); while (--i >= 0) { bool ok = Catalog::extIsSupported(urls.at(i).path()); if (!ok) { QFileInfo info(urls.at(i).toLocalFile()); ok = info.exists() && info.isDir(); } if (ok) return true; } return false; } QString shorterFilePath(const QString path) { if (!Project::instance()->isLoaded()) return path; QString pDir = Project::instance()->projectDir(); if (path.startsWith(pDir))//TODO cache projectDir? return QDir(pDir).relativeFilePath(path); return path; } diff --git a/src/tm/tmscanapi.h b/src/tm/tmscanapi.h index 2259f12..ab1e62c 100644 --- a/src/tm/tmscanapi.h +++ b/src/tm/tmscanapi.h @@ -1,73 +1,69 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2009 by Nick Shaforostoff 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 SCANAPI_H #define SCANAPI_H #include #include #include #include -#ifndef NOKDE #include -#endif bool dragIsAcceptable(const QList& urls); QString shorterFilePath(const QString path); namespace TM { class ScanJob; class ScanJobFeedingBack; void purgeMissingFilesFromTM(const QStringList& urls, const QString& dbName); ///wrapper. returns gross number of jobs started int scanRecursive(const QStringList& urls, const QString& dbName); -#ifndef NOKDE class RecursiveScanJob: public KJob { Q_OBJECT public: RecursiveScanJob(const QString& dbName, QObject* parent = 0); void setJobs(const QVector& jobs); void start(); public slots: void scanJobFinished(ScanJobFeedingBack*); protected: bool doKill(); private: QString m_dbName; QTime m_time; QVector m_jobs; }; -#endif } #endif diff --git a/src/tm/tmtab.cpp b/src/tm/tmtab.cpp index baa838f..ed7fd98 100644 --- a/src/tm/tmtab.cpp +++ b/src/tm/tmtab.cpp @@ -1,806 +1,794 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2014 by Nick Shaforostoff 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 "tmtab.h" #include "lokalize_debug.h" #include "ui_queryoptions.h" #include "project.h" #include "dbfilesmodel.h" #include "tmscanapi.h" #include "qaview.h" #include "prefs_lokalize.h" #include "jobs.h" #include "fastsizehintitemdelegate.h" #include #include #include #include #include #include #include #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) #undef QStringLiteral #define QStringLiteral QLatin1String #endif using namespace TM; //static int BIG_COUNTER=0; //TODO do things for case when user explicitly wants to find & accel mark //BEGIN TMDBModel TMDBModel::TMDBModel(QObject* parent) : QSqlQueryModel(parent) , m_queryType(WordOrder) , m_totalResultCount(0) { setHeaderData(TMDBModel::Source, Qt::Horizontal, i18nc("@title:column Original text", "Source")); setHeaderData(TMDBModel::Target, Qt::Horizontal, i18nc("@title:column Text in target language", "Target")); setHeaderData(TMDBModel::Context, Qt::Horizontal, i18nc("@title:column", "Context")); setHeaderData(TMDBModel::Filepath, Qt::Horizontal, i18nc("@title:column", "File")); setHeaderData(TMDBModel::TransationStatus, Qt::Horizontal, i18nc("@title:column", "Translation Status")); } void TMDBModel::setDB(const QString& str) { m_dbName = str; QString sourceLangCode = DBFilesModel::instance()->m_configurations.value(str).sourceLangCode; QString targetLangCode = DBFilesModel::instance()->m_configurations.value(str).targetLangCode; if (sourceLangCode.length()) setHeaderData(TMDBModel::Source, Qt::Horizontal, QString(i18nc("@title:column Original text", "Source") % QStringLiteral(": ") % sourceLangCode)); if (targetLangCode.length()) setHeaderData(TMDBModel::Target, Qt::Horizontal, QString(i18nc("@title:column Text in target language", "Target") % QStringLiteral(": ") % targetLangCode)); } void TMDBModel::setQueryType(int type) { m_queryType = (QueryType)type; } void TMDBModel::setFilter(const QString& source, const QString& target, bool invertSource, bool invertTarget, const QString& filemask ) { QString escapedSource(source); escapedSource.replace('\'', QStringLiteral("''")); QString escapedTarget(target); escapedTarget.replace('\'', QStringLiteral("''")); QString invertSourceStr; if (invertSource) invertSourceStr = QStringLiteral("NOT "); QString invertTargetStr; if (invertTarget) invertTargetStr = QStringLiteral("NOT "); QString escapedFilemask(filemask); escapedFilemask.replace('\'', QStringLiteral("''")); QString sourceQuery; QString targetQuery; QString fileQuery; if (m_queryType == SubStr) { escapedSource.replace('%', QStringLiteral("\b%")); escapedSource.replace('_', QStringLiteral("\b_")); escapedTarget.replace('%', QStringLiteral("\b%")); escapedTarget.replace('_', QStringLiteral("\b_")); if (!escapedSource.isEmpty()) sourceQuery = QStringLiteral("AND source_strings.source ") % invertSourceStr % QStringLiteral("LIKE '%") % escapedSource % QStringLiteral("%' ESCAPE '\b' "); if (!escapedTarget.isEmpty()) targetQuery = QStringLiteral("AND target_strings.target ") % invertTargetStr % QStringLiteral("LIKE '%") % escapedTarget % QStringLiteral("%' ESCAPE '\b' "); } else if (m_queryType == WordOrder) { /*escapedSource.replace('%',"\b%");escapedSource.replace('_',"\b_"); escapedTarget.replace('%',"\b%");escapedTarget.replace('_',"\b_");*/ QRegExp wre(QStringLiteral("\\W")); QStringList sourceList = escapedSource.split(wre, QString::SkipEmptyParts); QStringList targetList = escapedTarget.split(wre, QString::SkipEmptyParts); if (!sourceList.isEmpty()) sourceQuery = QStringLiteral("AND source_strings.source ") % invertSourceStr % QStringLiteral("LIKE '%") % sourceList.join(QStringLiteral("%' AND source_strings.source ") % invertSourceStr % QStringLiteral("LIKE '%")) % QStringLiteral("%' "); if (!targetList.isEmpty()) targetQuery = QStringLiteral("AND target_strings.target ") % invertTargetStr % QStringLiteral("LIKE '%") % targetList.join(QStringLiteral("%' AND target_strings.target ") % invertTargetStr % QStringLiteral("LIKE '%")) % QStringLiteral("%' "); } else { if (!escapedSource.isEmpty()) sourceQuery = QStringLiteral("AND source_strings.source ") % invertSourceStr % QStringLiteral("GLOB '") % escapedSource % QStringLiteral("' "); if (!escapedTarget.isEmpty()) targetQuery = QStringLiteral("AND target_strings.target ") % invertTargetStr % QStringLiteral("GLOB '") % escapedTarget % QStringLiteral("' "); } if (!filemask.isEmpty()) fileQuery = QStringLiteral("AND files.path GLOB '") % escapedFilemask % QStringLiteral("' "); QString fromPart = QStringLiteral("FROM main JOIN source_strings ON (source_strings.id=main.source) " "JOIN target_strings ON (target_strings.id=main.target), files " "WHERE files.id=main.file ") % sourceQuery % targetQuery % fileQuery; ExecQueryJob* job = new ExecQueryJob(QStringLiteral( "SELECT source_strings.source, target_strings.target, " "main.ctxt, files.path, " "source_strings.source_accel, target_strings.target_accel, main.bits ") + fromPart, m_dbName, &m_dbOperationMutex); connect(job, &ExecQueryJob::done, this, &TMDBModel::slotQueryExecuted); threadPool()->start(job); job = new ExecQueryJob(QStringLiteral("SELECT count(*) ") + fromPart, m_dbName, &m_dbOperationMutex); connect(job, &ExecQueryJob::done, this, &TMDBModel::slotQueryExecuted); threadPool()->start(job); m_totalResultCount = 0; } void TMDBModel::slotQueryExecuted(ExecQueryJob* job) { job->deleteLater(); m_dbOperationMutex.lock(); if (job->query->lastQuery().startsWith(QLatin1String("SELECT count(*) "))) { m_totalResultCount = job->query->next() ? job->query->value(0).toInt() : -1; m_dbOperationMutex.unlock(); emit finalResultCountFetched(m_totalResultCount); return; } query().finish(); query().clear(); setQuery(*(job->query)); m_dbOperationMutex.unlock(); emit resultsFetched(); } bool TMDBModel::rowIsApproved(int row) const { bool ok; qlonglong bits = record(row).value(TMDBModel::_Bits).toLongLong(&ok); return !(ok && bits & 4); } int TMDBModel::translationStatus(const QModelIndex& item) const { //QMutexLocker locker(&m_dbOperationMutex); if (QSqlQueryModel::data(item.sibling(item.row(), Target), Qt::DisplayRole).toString().isEmpty()) return 2; return int(!rowIsApproved(item.row())); } #define TM_DELIMITER '\v' QVariant TMDBModel::data(const QModelIndex& item, int role) const { //QMutexLocker locker(&m_dbOperationMutex); bool doHtml = (role == FastSizeHintItemDelegate::HtmlDisplayRole); if (doHtml) role = Qt::DisplayRole; else if (role == Qt::FontRole && item.column() == TMDBModel::Target) { //TODO Qt::ForegroundRole -- brush for orphaned entries QFont font = QApplication::font(); font.setItalic(!rowIsApproved(item.row())); return font; } else if (role == FullPathRole && item.column() == TMDBModel::Filepath) return QSqlQueryModel::data(item, Qt::DisplayRole); else if (role == TransStateRole) return translationStatus(item); QVariant result = QSqlQueryModel::data(item, role); /* if (role==Qt::SizeHintRole && !result.isValid()) BIG_COUNTER++;*/ if (role != Qt::DisplayRole) return result; if (item.column() == TMDBModel::Context) { //context QString r = result.toString(); int pos = r.indexOf(TM_DELIMITER); if (pos != -1) result = r.remove(pos, r.size()); } else if (item.column() < TMDBModel::Context && !record(item.row()).isNull(TMDBModel::_SourceAccel + item.column())) { //source, target const QVariant& posVar = record(item.row()).value(TMDBModel::_SourceAccel + item.column()); int pos = -1; bool ok = false; if (posVar.isValid()) pos = posVar.toInt(&ok); if (ok && pos != -1) { QString r = result.toString(); r.insert(pos, Project::instance()->accel()); result = r; } } else if (item.column() == TMDBModel::Filepath) { return shorterFilePath(result.toString()); } else if (item.column() == TMDBModel::TransationStatus) { static QString statuses[] = {i18nc("@info:status 'non-fuzzy' in gettext terminology", "Ready"), i18nc("@info:status 'fuzzy' in gettext terminology", "Needs review"), i18nc("@info:status", "Untranslated") }; return statuses[translationStatus(item)]; } if (doHtml && item.column() < TMDBModel::Context) return convertToHtml(result.toString(), item.column() == TMDBModel::Target && !rowIsApproved(item.row())); else return result; } //END TMDBModel //BEGIN TMResultsSortFilterProxyModel class TMResultsSortFilterProxyModel: public QSortFilterProxyModel { public: TMResultsSortFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent) {} void setRules(const QVector& rules); void fetchMore(const QModelIndex& parent); QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; protected: bool lessThan(const QModelIndex& left, const QModelIndex& right) const; bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const; private: QVector m_rules; mutable QMap m_matchingRulesForSourceRow; //mutable QMap > m_highlightDataForSourceRow; }; bool TMResultsSortFilterProxyModel::lessThan(const QModelIndex& left, const QModelIndex& right) const { if (left.column() == TMDBModel::TransationStatus) { int l = left.data(TMDBModel::TransStateRole).toInt(); int r = right.data(TMDBModel::TransStateRole).toInt(); return l < r; } return QSortFilterProxyModel::lessThan(left, right); } void TMResultsSortFilterProxyModel::fetchMore(const QModelIndex& parent) { int oldSourceRowCount = sourceModel()->rowCount(); int oldRowCount = rowCount(); QSortFilterProxyModel::fetchMore(parent); if (m_rules.isEmpty()) return; while (oldRowCount == rowCount()) { QSortFilterProxyModel::fetchMore(parent); if (sourceModel()->rowCount() == oldSourceRowCount) break; oldSourceRowCount = sourceModel()->rowCount(); } qCDebug(LOKALIZE_LOG) << "row count" << sourceModel()->rowCount() << " filtered:" << rowCount(); emit layoutChanged(); } void TMResultsSortFilterProxyModel::setRules(const QVector& rules) { m_rules = rules; m_matchingRulesForSourceRow.clear(); invalidateFilter(); } QVariant TMResultsSortFilterProxyModel::data(const QModelIndex& index, int role) const { QVariant result = QSortFilterProxyModel::data(index, role); if (m_rules.isEmpty() || role != FastSizeHintItemDelegate::HtmlDisplayRole) return result; if (index.column() != TMDBModel::Source && index.column() != TMDBModel::Target) return result; int source_row = mapToSource(index).row(); QString string = result.toString(); QVector regExps; if (index.column() == TMDBModel::Source) regExps = m_rules[m_matchingRulesForSourceRow[source_row]].sources; else regExps = m_rules[m_matchingRulesForSourceRow[source_row]].falseFriends; foreach (const QRegExp& re, regExps) { int pos = re.indexIn(string); if (pos != -1) return string.replace(pos, re.matchedLength(), QStringLiteral("") % re.cap(0) % QStringLiteral("")); } //StartLen sl=m_highlightDataForSourceRow.value(source_row).at(index.column()); return result; } bool TMResultsSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const { if (m_rules.isEmpty()) return true; QString source = sourceModel()->index(source_row, TMDBModel::Source, source_parent).data().toString(); QString target = sourceModel()->index(source_row, TMDBModel::Target, source_parent).data().toString(); static QVector dummy_positions; int i = findMatchingRule(m_rules, source, target, dummy_positions); bool accept = (i != -1); if (accept) m_matchingRulesForSourceRow[source_row] = i; return accept; } //END TMResultsSortFilterProxyModel class QueryStylesModel: public QStringListModel { public: explicit QueryStylesModel(QObject* parent = 0); QVariant data(const QModelIndex& item, int role) const; }; QueryStylesModel::QueryStylesModel(QObject* parent): QStringListModel(parent) { setStringList(QStringList(i18n("Substring")) << i18n("Google-like") << i18n("Wildcard")); } QVariant QueryStylesModel::data(const QModelIndex& item, int role) const { if (role == Qt::ToolTipRole) { static QString tooltips[] = {i18n("Case insensitive"), i18n("Space is AND operator. Case insensitive."), i18n("Shell globs (* and ?). Case sensitive.") }; return tooltips[item.row()]; } return QStringListModel::data(item, role); } //BEGIN TMWindow TMTab::TMTab(QWidget *parent) : LokalizeSubwindowBase2(parent) , m_proxyModel(new TMResultsSortFilterProxyModel(this)) , m_partToAlsoTryLater(DocPosition::UndefPart) , m_dbusId(-1) { //setCaption(i18nc("@title:window","Translation Memory"),false); setWindowTitle(i18nc("@title:window", "Translation Memory")); setAcceptDrops(true); ui_queryOptions = new Ui_QueryOptions; QWidget* w = new QWidget(this); ui_queryOptions->setupUi(w); setCentralWidget(w); ui_queryOptions->queryLayout->setStretchFactor(ui_queryOptions->mainQueryLayout, 42); connect(ui_queryOptions->querySource, &QLineEdit::returnPressed, this, &TMTab::performQuery); connect(ui_queryOptions->queryTarget, &QLineEdit::returnPressed, this, &TMTab::performQuery); connect(ui_queryOptions->filemask, &QLineEdit::returnPressed, this, &TMTab::performQuery); connect(ui_queryOptions->doFind, &QPushButton::clicked, this, &TMTab::performQuery); connect(ui_queryOptions->doUpdateTM, &QPushButton::clicked, this, &TMTab::updateTM); QShortcut* sh = new QShortcut(Qt::CTRL + Qt::Key_L, this); connect(sh, &QShortcut::activated, ui_queryOptions->querySource, QOverload<>::of(&QLineEdit::setFocus)); setFocusProxy(ui_queryOptions->querySource); QTreeView* view = ui_queryOptions->treeView; view->setContextMenuPolicy(Qt::ActionsContextMenu); QAction* a = new QAction(i18n("Copy source to clipboard"), view); a->setShortcut(Qt::CTRL + Qt::Key_S); a->setShortcutContext(Qt::WidgetWithChildrenShortcut); connect(a, &QAction::triggered, this, &TMTab::copySource); view->addAction(a); a = new QAction(i18n("Copy target to clipboard"), view); a->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return)); a->setShortcutContext(Qt::WidgetWithChildrenShortcut); connect(a, &QAction::triggered, this, &TMTab::copyTarget); view->addAction(a); a = new QAction(i18n("Open file"), view); a->setShortcut(QKeySequence(Qt::Key_Return)); a->setShortcutContext(Qt::WidgetWithChildrenShortcut); connect(a, &QAction::triggered, this, &TMTab::openFile); connect(view, &QTreeView::activated, this, &TMTab::openFile); view->addAction(a); //view->addAction(KStandardAction::copy(this),this,SLOT(),this); //QKeySequence::Copy? //QShortcut* shortcut = new QShortcut(Qt::CTRL + Qt::Key_P,view,0,0,Qt::WidgetWithChildrenShortcut); //connect(shortcut,SIGNAL(activated()), this, SLOT(copyText())); m_model = new TMDBModel(this); m_model->setDB(Project::instance()->projectID()); m_proxyModel->setDynamicSortFilter(true); m_proxyModel->setSourceModel(m_model); view->setModel(m_proxyModel); view->sortByColumn(TMDBModel::Filepath, Qt::AscendingOrder); view->setSortingEnabled(true); view->setColumnHidden(TMDBModel::_SourceAccel, true); view->setColumnHidden(TMDBModel::_TargetAccel, true); view->setColumnHidden(TMDBModel::_Bits, true); QVector singleLineColumns(TMDBModel::ColumnCount, false); singleLineColumns[TMDBModel::Filepath] = true; singleLineColumns[TMDBModel::TransationStatus] = true; singleLineColumns[TMDBModel::Context] = true; QVector richTextColumns(TMDBModel::ColumnCount, false); richTextColumns[TMDBModel::Source] = true; richTextColumns[TMDBModel::Target] = true; view->setItemDelegate(new FastSizeHintItemDelegate(this, singleLineColumns, richTextColumns)); connect(m_model, &TMDBModel::resultsFetched, (FastSizeHintItemDelegate*)view->itemDelegate(), &FastSizeHintItemDelegate::reset); connect(m_model, &TMDBModel::modelReset, (FastSizeHintItemDelegate*)view->itemDelegate(), &FastSizeHintItemDelegate::reset); //connect(m_model,SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),view->itemDelegate(),SLOT(reset())); connect(m_proxyModel, &TMResultsSortFilterProxyModel::layoutChanged, (FastSizeHintItemDelegate*)view->itemDelegate(), &FastSizeHintItemDelegate::reset); connect(m_proxyModel, &TMResultsSortFilterProxyModel::layoutChanged, this, &TMTab::displayTotalResultCount); connect(m_model, &TMDBModel::resultsFetched, this, &TMTab::handleResults); connect(m_model, &TMDBModel::finalResultCountFetched, this, &TMTab::displayTotalResultCount); ui_queryOptions->queryStyle->setModel(new QueryStylesModel(this)); connect(ui_queryOptions->queryStyle, QOverload::of(&KComboBox::currentIndexChanged), m_model, &TMDBModel::setQueryType); ui_queryOptions->dbName->setModel(DBFilesModel::instance()); ui_queryOptions->dbName->setRootModelIndex(DBFilesModel::instance()->rootIndex()); int pos = ui_queryOptions->dbName->findData(Project::instance()->projectID(), DBFilesModel::NameRole); if (pos >= 0) ui_queryOptions->dbName->setCurrentIndex(pos); connect(ui_queryOptions->dbName, QOverload::of(&QComboBox::currentIndexChanged), m_model, &TMDBModel::setDB); //connect(ui_queryOptions->dbName, SIGNAL(activated(QString)), this, SLOT(performQuery())); //BEGIN resizeColumnToContents static const int maxInitialWidths[4] = {QApplication::desktop()->availableGeometry().width() / 3, QApplication::desktop()->availableGeometry().width() / 3, 50, 200}; int column = sizeof(maxInitialWidths) / sizeof(int); while (--column >= 0) view->setColumnWidth(column, maxInitialWidths[column]); //END resizeColumnToContents int i = 6; while (--i > ID_STATUS_PROGRESS) statusBarItems.insert(i, QString()); setXMLFile(QStringLiteral("translationmemoryrui.rc"), true); setUpdatedXMLFile(); dbusObjectPath(); QAction *action; KActionCollection* ac = actionCollection(); KActionCategory* tm = new KActionCategory(i18nc("@title actions category", "Translation Memory"), ac); action = tm->addAction(QStringLiteral("tools_tm_manage"), Project::instance(), SLOT(showTMManager())); action->setText(i18nc("@action:inmenu", "Manage translation memories")); m_qaView = new QaView(this); m_qaView->hide(); addDockWidget(Qt::RightDockWidgetArea, m_qaView); tm->addAction(QStringLiteral("showqa_action"), m_qaView->toggleViewAction()); connect(m_qaView, &QaView::rulesChanged, this, QOverload<>::of(&TMTab::setQAMode)); connect(m_qaView->toggleViewAction(), &QAction::toggled, this, QOverload::of(&TMTab::setQAMode)); -#ifndef NOKDE KConfig config; KConfigGroup cg(&config, "MainWindow"); view->header()->restoreState(QByteArray::fromBase64(cg.readEntry("TMSearchResultsHeaderState", QByteArray()))); -#endif } TMTab::~TMTab() { -#ifndef NOKDE KConfig config; KConfigGroup cg(&config, "MainWindow"); cg.writeEntry("TMSearchResultsHeaderState", ui_queryOptions->treeView->header()->saveState().toBase64()); ids.removeAll(m_dbusId); -#endif delete ui_queryOptions; } 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() { if (ui_queryOptions->dbName->currentText().isEmpty()) { int pos = ui_queryOptions->dbName->findData(Project::instance()->projectID(), DBFilesModel::NameRole); if (pos >= 0) ui_queryOptions->dbName->setCurrentIndex(pos); //m_model->setDB(Project::instance()->projectID()); } m_model->m_dbOperationMutex.lock(); m_model->setFilter(ui_queryOptions->querySource->text(), ui_queryOptions->queryTarget->text(), ui_queryOptions->invertSource->isChecked(), ui_queryOptions->invertTarget->isChecked(), ui_queryOptions->filemask->text() ); m_model->m_dbOperationMutex.unlock(); QApplication::setOverrideCursor(Qt::BusyCursor); } void TMTab::handleResults() { QApplication::restoreOverrideCursor(); QString filemask = ui_queryOptions->filemask->text(); //ui_queryOptions->regexSource->text(),ui_queryOptions->regexTarget->text() m_model->m_dbOperationMutex.lock(); int rowCount = m_model->rowCount(); m_model->m_dbOperationMutex.unlock(); if (rowCount == 0) { qCDebug(LOKALIZE_LOG) << "m_model->rowCount()==0"; //try harder if (m_partToAlsoTryLater != DocPosition::UndefPart) { if (m_partToAlsoTryLater == DocPosition::Comment) { QString text = ui_queryOptions->queryTarget->text(); if (text.isEmpty()) text = ui_queryOptions->querySource->text(); if (text.isEmpty()) m_partToAlsoTryLater = DocPosition::UndefPart; else findGuiText(text); return; } QLineEdit* const source_target_query[] = {ui_queryOptions->queryTarget, ui_queryOptions->querySource}; source_target_query[m_partToAlsoTryLater == DocPosition::Source]->setText(source_target_query[m_partToAlsoTryLater != DocPosition::Source]->text()); source_target_query[m_partToAlsoTryLater != DocPosition::Source]->clear(); m_partToAlsoTryLater = ui_queryOptions->filemask->text().isEmpty() ? DocPosition::UndefPart : DocPosition::Comment; //leave a note that we should also try w/o package if the current one doesn't succeed return performQuery(); } if (!filemask.isEmpty() && !filemask.contains('*')) { ui_queryOptions->filemask->setText('*' % filemask % '*'); return performQuery(); } } qCDebug(LOKALIZE_LOG) << "=DocPosition::UndefPart"; m_partToAlsoTryLater = DocPosition::UndefPart; ui_queryOptions->treeView->setFocus(); } void TMTab::displayTotalResultCount() { m_model->m_dbOperationMutex.lock(); int total = m_model->totalResultCount(); int filtered = m_proxyModel->rowCount(); if (filtered == m_model->rowCount()) statusBarItems.insert(1, i18nc("@info:status message entries", "Total: %1", total)); else statusBarItems.insert(1, i18nc("@info:status message entries", "Total: %1 (%2)", filtered, total)); m_model->m_dbOperationMutex.unlock(); } static void copy(Ui_QueryOptions* ui_queryOptions, int column) { QApplication::clipboard()->setText(ui_queryOptions->treeView->currentIndex().sibling(ui_queryOptions->treeView->currentIndex().row(), column).data().toString()); } void TMTab::copySource() { copy(ui_queryOptions, TMDBModel::Source); } void TMTab::copyTarget() { copy(ui_queryOptions, TMDBModel::Target); } 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 does not 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(), true); } void TMTab::setQAMode() { return setQAMode(true); } void TMTab::setQAMode(bool enable) { static_cast(ui_queryOptions->treeView->itemDelegate())->reset(); if (!enable) { m_proxyModel->setRules(QVector()); return; } m_proxyModel->setRules(m_qaView->rules()); /*QDomElement docElem = m_categories.at(0).toElement(); QDomNode n = docElem.firstChildElement(); while(!n.isNull()) { QDomElement e = n.toElement(); qCDebug(LOKALIZE_LOG) << e.tagName(); n = n.nextSiblingElement(); }*/ performQuery(); } //END TMWindow #if 0 bool QueryResultDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& /*option*/, const QModelIndex& index) { qCWarning(LOKALIZE_LOG) << "QEvent" << event; if (event->type() == QEvent::Shortcut) { qCWarning(LOKALIZE_LOG) << "QEvent::Shortcut" << index.data().canConvert(QVariant::String); if (static_cast(event)->key().matches(QKeySequence::Copy) && index.data().canConvert(QVariant::String)) { QApplication::clipboard()->setText(index.data().toString()); qCWarning(LOKALIZE_LOG) << "index.data().toString()"; } } else if (event->type() == QEvent::MouseButtonRelease) { QMouseEvent* mEvent = static_cast(event); if (mEvent->button() == Qt::MidButton) { } } else if (event->type() == QEvent::KeyPress) { QKeyEvent* kEvent = static_cast(event); if (kEvent->key() == Qt::Key_Return) { if (kEvent->modifiers() == Qt::NoModifier) { } } } else return false; event->accept(); return true; } #endif void TMTab::dragEnterEvent(QDragEnterEvent* event) { if (dragIsAcceptable(event->mimeData()->urls())) event->acceptProposedAction(); } void TMTab::dropEvent(QDropEvent *event) { QStringList files; foreach (const QUrl& url, event->mimeData()->urls()) files.append(url.toLocalFile()); if (scanRecursive(files, Project::instance()->projectID())) event->acceptProposedAction(); } -#ifndef NOKDE #include "translationmemoryadaptor.h" -#endif //BEGIN DBus interface QList TMTab::ids; QString TMTab::dbusObjectPath() { -#ifndef NOKDE const QString TM_PATH = QStringLiteral("/ThisIsWhatYouWant/TranslationMemory/"); if (m_dbusId == -1) { new TranslationMemoryAdaptor(this); int i = 0; while (i < ids.size() && i == ids.at(i)) ++i; ids.insert(i, i); m_dbusId = i; QDBusConnection::sessionBus().registerObject(TM_PATH + QString::number(m_dbusId), this); } return TM_PATH + QString::number(m_dbusId); -#else - return QString(); -#endif } void TMTab::lookup(QString source, QString target) { source.remove(Project::instance()->accel()); target.remove(Project::instance()->accel()); ui_queryOptions->querySource->setText(source); ui_queryOptions->queryTarget->setText(target); ui_queryOptions->invertSource->setChecked(false); ui_queryOptions->invertTarget->setChecked(false); ui_queryOptions->queryStyle->setCurrentIndex(TMDBModel::SubStr); performQuery(); } // void TMTab::lookup(DocPosition::Part part, QString text) // { // lookup(part==DocPosition::Source?text:QString(),part==DocPosition::Target?text:QString()); // } bool TMTab::findGuiTextPackage(QString text, QString package) { qCWarning(LOKALIZE_LOG) << package << text; QLineEdit* const source_target_query[] = {ui_queryOptions->queryTarget, ui_queryOptions->querySource}; static const DocPosition::Part source_target[] = {DocPosition::Target, DocPosition::Source}; QTextCodec* latin1 = QTextCodec::codecForMib(4); DocPosition::Part tryNowPart = source_target[latin1->canEncode(text)]; m_partToAlsoTryLater = source_target[tryNowPart == DocPosition::Target]; text.remove(Project::instance()->accel()); ui_queryOptions->querySource->clear(); ui_queryOptions->queryTarget->clear(); source_target_query[tryNowPart == DocPosition::Source]->setText(text); ui_queryOptions->invertSource->setChecked(false); ui_queryOptions->invertTarget->setChecked(false); if (!package.isEmpty()) package = '*' % package % '*'; ui_queryOptions->filemask->setText(package); ui_queryOptions->queryStyle->setCurrentIndex(TMDBModel::Glob); performQuery(); return true; } //END DBus interface diff --git a/src/xlifftextedit.cpp b/src/xlifftextedit.cpp index 5aa7f6b..0001593 100644 --- a/src/xlifftextedit.cpp +++ b/src/xlifftextedit.cpp @@ -1,1318 +1,1298 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2014 by Nick Shaforostoff 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 "xlifftextedit.h" #include "lokalize_debug.h" #include "catalog.h" #include "cmd.h" #include "syntaxhighlighter.h" #include "prefs_lokalize.h" #include "prefs.h" #include "project.h" #include "completionstorage.h" #include -#ifndef NOKDE #include -#endif #include #include #include #include #include #include #include #include #include #include #include #include #include inline static QImage generateImage(const QString& str, const QFont& font) { // im_count++; // QTime a;a.start(); QStyleOptionButton opt; opt.fontMetrics = QFontMetrics(font); opt.text = ' ' + str + ' '; opt.rect = opt.fontMetrics.boundingRect(opt.text).adjusted(0, 0, 5, 5); opt.rect.moveTo(0, 0); QImage result(opt.rect.size(), QImage::Format_ARGB32); result.fill(0);//0xAARRGGBB QPainter painter(&result); QApplication::style()->drawControl(QStyle::CE_PushButton, &opt, &painter); // im_time+=a.elapsed(); // qCWarning(LOKALIZE_LOG)<width() + 2 * frameWidth(); return QSize(w, h); } bool MyCompletionBox::eventFilter(QObject* object, QEvent* event) { if (event->type() == QEvent::KeyPress) { QKeyEvent* e = static_cast(event); if (e->key() == Qt::Key_PageDown || e->key() == Qt::Key_PageUp) { hide(); return false; } } return KCompletionBox::eventFilter(object, event); } -#endif TranslationUnitTextEdit::~TranslationUnitTextEdit() { disconnect(document(), &QTextDocument::contentsChange, this, &TranslationUnitTextEdit::contentsChanged); } TranslationUnitTextEdit::TranslationUnitTextEdit(Catalog* catalog, DocPosition::Part part, QWidget* parent) : KTextEdit(parent) , m_currentUnicodeNumber(0) , m_langUsesSpaces(true) , m_catalog(catalog) , m_part(part) , m_highlighter(new SyntaxHighlighter(this)) , m_enabled(Settings::autoSpellcheck()) , m_completionBox(0) , m_cursorSelectionStart(0) , m_cursorSelectionEnd(0) { setReadOnly(part == DocPosition::Source); setUndoRedoEnabled(false); setAcceptRichText(false); -#if !defined(NOKDE) || defined(SONNET_STATIC) m_highlighter->setActive(m_enabled); setHighlighter(m_highlighter); -#endif if (part == DocPosition::Target) { connect(document(), &QTextDocument::contentsChange, this, &TranslationUnitTextEdit::contentsChanged); connect(this, &TranslationUnitTextEdit::cursorPositionChanged, this, &TranslationUnitTextEdit::emitCursorPositionChanged); } connect(catalog, QOverload<>::of(&Catalog::signalFileLoaded), this, &TranslationUnitTextEdit::fileLoaded); //connect (Project::instance(), &Project::configChanged, this, &TranslationUnitTextEdit::projectConfigChanged); } void TranslationUnitTextEdit::setSpellCheckingEnabled(bool enable) { Settings::setAutoSpellcheck(enable); m_enabled = enable; -#if !defined(NOKDE) || defined(SONNET_STATIC) m_highlighter->setActive(enable); -#endif SettingsController::instance()->dirty = true; } void TranslationUnitTextEdit::setVisualizeSeparators(bool enable) { if (enable) { QTextOption textoption = document()->defaultTextOption(); textoption.setFlags(textoption.flags() | QTextOption::ShowLineAndParagraphSeparators | QTextOption::ShowTabsAndSpaces); document()->setDefaultTextOption(textoption); } else { QTextOption textoption = document()->defaultTextOption(); textoption.setFlags(textoption.flags() & (~QTextOption::ShowLineAndParagraphSeparators) & (~QTextOption::ShowTabsAndSpaces)); document()->setDefaultTextOption(textoption); } } void TranslationUnitTextEdit::fileLoaded() { QString langCode = m_part == DocPosition::Source ? m_catalog->sourceLangCode() : m_catalog->targetLangCode(); QLocale langLocale(langCode); -#if !defined(NOKDE) || defined(SONNET_STATIC) // First try to use a locale name derived from the language code m_highlighter->setCurrentLanguage(langLocale.name()); // If that fails, try to use the language code directly if (m_highlighter->currentLanguage() != langLocale.name() || m_highlighter->currentLanguage().isEmpty()) { m_highlighter->setCurrentLanguage(langCode); if (m_highlighter->currentLanguage() != langCode && langCode.length() > 2) m_highlighter->setCurrentLanguage(langCode.left(2)); } -#endif //"i use an english locale while translating kde pot files from english to hebrew" Bug #181989 Qt::LayoutDirection targetLanguageDirection = Qt::LeftToRight; static QLocale::Language rtlLanguages[] = {QLocale::Arabic, QLocale::Hebrew, QLocale::Urdu, QLocale::Persian, QLocale::Pashto}; int i = sizeof(rtlLanguages) / sizeof(QLocale::Arabic); while (--i >= 0 && langLocale.language() != rtlLanguages[i]) ; if (i != -1) targetLanguageDirection = Qt::RightToLeft; setLayoutDirection(targetLanguageDirection); if (m_part == DocPosition::Source) return; //"Some language do not need space between words. For example Chinese." static QLocale::Language noSpaceLanguages[] = {QLocale::Chinese}; i = sizeof(noSpaceLanguages) / sizeof(QLocale::Chinese); while (--i >= 0 && langLocale.language() != noSpaceLanguages[i]) ; m_langUsesSpaces = (i == -1); } void TranslationUnitTextEdit::reflectApprovementState() { if (m_part == DocPosition::Source || m_currentPos.entry == -1) return; bool approved = m_catalog->isApproved(m_currentPos.entry); disconnect(document(), &QTextDocument::contentsChange, this, &TranslationUnitTextEdit::contentsChanged); m_highlighter->setApprovementState(approved); m_highlighter->rehighlight(); connect(document(), &QTextDocument::contentsChange, this, &TranslationUnitTextEdit::contentsChanged); viewport()->setBackgroundRole(approved ? QPalette::Base : QPalette::AlternateBase); if (approved) emit approvedEntryDisplayed(); else emit nonApprovedEntryDisplayed(); bool untr = m_catalog->isEmpty(m_currentPos); if (untr) emit untranslatedEntryDisplayed(); else emit translatedEntryDisplayed(); } void TranslationUnitTextEdit::reflectUntranslatedState() { if (m_part == DocPosition::Source || m_currentPos.entry == -1) return; bool untr = m_catalog->isEmpty(m_currentPos); if (untr) emit untranslatedEntryDisplayed(); else emit translatedEntryDisplayed(); } /** * makes MsgEdit reflect current entry **/ CatalogString TranslationUnitTextEdit::showPos(DocPosition docPosition, const CatalogString& refStr, bool keepCursor) { docPosition.part = m_part; m_currentPos = docPosition; CatalogString catalogString = m_catalog->catalogString(m_currentPos); QString target = catalogString.string; _oldMsgstr = target; //_oldMsgstrAscii=document()->toPlainText(); <-- MOVED THIS TO THE END //BEGIN pos QTextCursor cursor = textCursor(); int pos = cursor.position(); int anchor = cursor.anchor(); //qCWarning(LOKALIZE_LOG)<<"called"<<"pos"<sourceWithTags(docPosition) : refStr); connect(document(), &QTextDocument::contentsChange, this, &TranslationUnitTextEdit::contentsChanged); _oldMsgstrAscii = document()->toPlainText(); //BEGIN pos QTextCursor t = textCursor(); t.movePosition(QTextCursor::Start); if (pos || anchor) { //qCWarning(LOKALIZE_LOG)<<"setting"<blockSignals(true); clear(); QTextCursor c = textCursor(); insertContent(c, catStr, refStr); document()->blockSignals(false); if (m_part == DocPosition::Target) m_highlighter->setSourceString(refStr.string); else //reflectApprovementState() does this for Target m_highlighter->rehighlight(); //explicitly because the signals were disabled } #if 0 struct SearchFunctor { virtual int operator()(const QString& str, int startingPos); }; int SearchFunctor::operator()(const QString& str, int startingPos) { return str.indexOf(TAGRANGE_IMAGE_SYMBOL, startingPos); } struct AlternativeSearchFunctor: public SearchFunctor { int operator()(const QString& str, int startingPos); }; int AlternativeSearchFunctor::operator()(const QString& str, int startingPos) { int tagPos = str.indexOf(TAGRANGE_IMAGE_SYMBOL, startingPos); int diffStartPos = str.indexOf("{KBABEL", startingPos); int diffEndPos = str.indexOf("{/KBABEL", startingPos); int diffPos = qMin(diffStartPos, diffEndPos); if (diffPos == -1) diffPos = qMax(diffStartPos, diffEndPos); int result = qMin(tagPos, diffPos); if (result == -1) result = qMax(tagPos, diffPos); return result; } #endif void insertContent(QTextCursor& cursor, const CatalogString& catStr, const CatalogString& refStr, bool insertText) { //settings for TMView QTextCharFormat chF = cursor.charFormat(); QFont font = cursor.document()->defaultFont(); //font.setWeight(chF.fontWeight()); QMap posToTag; int i = catStr.tags.size(); while (--i >= 0) { //qCDebug(LOKALIZE_LOG)<<"\t"< sourceTagIdToIndex = refStr.tagIdToIndex(); int refTagIndexOffset = sourceTagIdToIndex.size(); i = 0; int prev = 0; while ((i = catStr.string.indexOf(TAGRANGE_IMAGE_SYMBOL, i)) != -1) { #if 0 SearchFunctor nextStopSymbol = AlternativeSearchFunctor(); char state = '0'; while ((i = nextStopSymbol(catStr.string, i)) != -1) { //handle diff display for TMView if (catStr.string.at(i) != TAGRANGE_IMAGE_SYMBOL) { if (catStr.string.at(i + 1) == '/') state = '0'; else if (catStr.string.at(i + 8) == 'D') state = '-'; else state = '+'; continue; } #endif if (insertText) cursor.insertText(catStr.string.mid(prev, i - prev)); else { cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, i - prev); cursor.deleteChar();//delete TAGRANGE_IMAGE_SYMBOL to insert it properly } if (!posToTag.contains(i)) { prev = ++i; continue; } int tagIndex = posToTag.value(i); InlineTag tag = catStr.tags.at(tagIndex); QString name = tag.id; QString text; if (tag.type == InlineTag::mrk) text = QStringLiteral("*"); else if (!tag.equivText.isEmpty()) text = tag.equivText; //TODO add number? when? -- right now this is done for gettext qt's 156 mark else text = QString::number(sourceTagIdToIndex.contains(tag.id) ? sourceTagIdToIndex.value(tag.id) : (tagIndex + refTagIndexOffset)); if (tag.start != tag.end) { //qCWarning(LOKALIZE_LOG)<<"b"<resource(QTextDocument::ImageResource, QUrl(name)).isNull()) cursor.document()->addResource(QTextDocument::ImageResource, QUrl(name), generateImage(text, font)); cursor.insertImage(name);//NOTE what if twice the same name? cursor.setCharFormat(chF); prev = ++i; } cursor.insertText(catStr.string.mid(prev)); } void TranslationUnitTextEdit::contentsChanged(int offset, int charsRemoved, int charsAdded) { Q_ASSERT(m_catalog->targetLangCode().length()); Q_ASSERT(Project::instance()->targetLangCode().length()); //qCWarning(LOKALIZE_LOG)<<"contentsChanged. offset"<toPlainText(); if (editTextAscii == _oldMsgstrAscii) { //qCWarning(LOKALIZE_LOG)<<"stopping"<targetWithTags(pos).string; const QStringRef addedText = editText.midRef(offset, charsAdded); //BEGIN XLIFF markup handling //protect from tag removal //TODO use midRef when Qt 4.8 is in distros bool markupRemoved = charsRemoved && target.midRef(offset, charsRemoved).contains(TAGRANGE_IMAGE_SYMBOL); bool markupAdded = charsAdded && addedText.contains(TAGRANGE_IMAGE_SYMBOL); if (markupRemoved || markupAdded) { bool modified = false; CatalogString targetWithTags = m_catalog->targetWithTags(m_currentPos); //special case when the user presses Del w/o selection if (!charsAdded && charsRemoved == 1) { int i = targetWithTags.tags.size(); while (--i >= 0) { if (targetWithTags.tags.at(i).start == offset || targetWithTags.tags.at(i).end == offset) { modified = true; pos.offset = targetWithTags.tags.at(i).start; m_catalog->push(new DelTagCmd(m_catalog, pos)); } } } else if (!markupAdded) { //check if all { plus } tags were selected modified = removeTargetSubstring(offset, charsRemoved, /*refresh*/false); if (modified && charsAdded) m_catalog->push(new InsTextCmd(m_catalog, pos, addedText.toString())); } //qCWarning(LOKALIZE_LOG)<<"calling showPos"; showPos(m_currentPos, CatalogString(),/*keepCursor*/true); if (!modified) { //qCWarning(LOKALIZE_LOG)<<"stop"; return; } } //END XLIFF markup handling else { if (charsRemoved) m_catalog->push(new DelTextCmd(m_catalog, pos, _oldMsgstr.mid(offset, charsRemoved))); _oldMsgstr = editText; //newStr becomes OldStr _oldMsgstrAscii = editTextAscii; //qCWarning(LOKALIZE_LOG)<<"char"<push(new InsTextCmd(m_catalog, pos, addedText.toString())); } /* TODO if (_leds) { if (m_catalog->msgstr(pos).isEmpty()) _leds->ledUntr->on(); else _leds->ledUntr->off(); } */ requestToggleApprovement(); reflectUntranslatedState(); // for mergecatalog (remove entry from index) // and for statusbar emit contentsModified(m_currentPos); -#ifndef NOKDE if (charsAdded == 1) { int sp = target.lastIndexOf(CompletionStorage::instance()->rxSplit, offset - 1); int len = (offset - sp); int wordCompletionLength = Settings::self()->wordCompletionLength(); if (wordCompletionLength >= 3 && len >= wordCompletionLength) doCompletion(offset + 1); else if (m_completionBox) m_completionBox->hide(); } else if (m_completionBox) m_completionBox->hide(); -#endif //qCWarning(LOKALIZE_LOG)<<"finish"; } bool TranslationUnitTextEdit::removeTargetSubstring(int delStart, int delLen, bool refresh) { if (Q_UNLIKELY(m_currentPos.entry == -1)) return false; if (!::removeTargetSubstring(m_catalog, m_currentPos, delStart, delLen)) return false; requestToggleApprovement(); if (refresh) { //qCWarning(LOKALIZE_LOG)<<"calling showPos"; showPos(m_currentPos, CatalogString(),/*keepCursor*/true/*false*/); } emit contentsModified(m_currentPos.entry); return true; } void TranslationUnitTextEdit::insertCatalogString(CatalogString catStr, int start, bool refresh) { QString REMOVEME = QStringLiteral("REMOVEME"); CatalogString sourceForReferencing = m_catalog->sourceWithTags(m_currentPos); const CatalogString target = m_catalog->targetWithTags(m_currentPos); QHash id2tagIndex; int i = sourceForReferencing.tags.size(); while (--i >= 0) id2tagIndex.insert(sourceForReferencing.tags.at(i).id, i); //remove markup that is already in target, to avoid duplicates if the string being inserted contains it as well foreach (const InlineTag& tag, target.tags) { if (id2tagIndex.contains(tag.id)) sourceForReferencing.tags[id2tagIndex.value(tag.id)].id = REMOVEME; } //iterating from the end is essential i = sourceForReferencing.tags.size(); while (--i >= 0) if (sourceForReferencing.tags.at(i).id == REMOVEME) sourceForReferencing.tags.removeAt(i); adaptCatalogString(catStr, sourceForReferencing); ::insertCatalogString(m_catalog, m_currentPos, catStr, start); if (refresh) { //qCWarning(LOKALIZE_LOG)<<"calling showPos"; showPos(m_currentPos, CatalogString(),/*keepCursor*/true/*false*/); QTextCursor cursor = textCursor(); cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, catStr.string.size()); setTextCursor(cursor); } } const QString LOKALIZE_XLIFF_MIMETYPE = QStringLiteral("application/x-lokalize-xliff+xml"); QMimeData* TranslationUnitTextEdit::createMimeDataFromSelection() const { QMimeData *mimeData = new QMimeData; CatalogString catalogString = m_catalog->catalogString(m_currentPos); QTextCursor cursor = textCursor(); int start = qMin(cursor.anchor(), cursor.position()); int end = qMax(cursor.anchor(), cursor.position()); QMap tagPlaces; if (fillTagPlaces(tagPlaces, catalogString, start, end - start)) { //transform CatalogString //TODO substring method catalogString.string = catalogString.string.mid(start, end - start); QList::iterator it = catalogString.tags.begin(); while (it != catalogString.tags.end()) { if (!tagPlaces.contains(it->start)) it = catalogString.tags.erase(it); else { it->start -= start; it->end -= start; ++it; } } QByteArray a; QDataStream out(&a, QIODevice::WriteOnly); QVariant v; qVariantSetValue(v, catalogString); out << v; mimeData->setData(LOKALIZE_XLIFF_MIMETYPE, a); } QString text = catalogString.string; text.remove(TAGRANGE_IMAGE_SYMBOL); mimeData->setText(text); return mimeData; } void TranslationUnitTextEdit::dragEnterEvent(QDragEnterEvent * event) { QObject* dragSource = event->source(); if (dragSource->objectName().compare("qt_scrollarea_viewport") == 0) dragSource = dragSource->parent(); //This is a deplacement within the Target area if (m_part == DocPosition::Target && this == dragSource) { QTextCursor cursor = textCursor(); int start = qMin(cursor.anchor(), cursor.position()); int end = qMax(cursor.anchor(), cursor.position()); m_cursorSelectionEnd = end; m_cursorSelectionStart = start; } QTextEdit::dragEnterEvent(event); } void TranslationUnitTextEdit::dropEvent(QDropEvent * event) { //Ensure the cursor moves to the correct location if (m_part == DocPosition::Target) { setTextCursor(cursorForPosition(event->pos())); //This is a copy modifier, disable the selection flags if (event->keyboardModifiers() & Qt::ControlModifier) { m_cursorSelectionEnd = 0; m_cursorSelectionStart = 0; } } QTextEdit::dropEvent(event); } void TranslationUnitTextEdit::insertFromMimeData(const QMimeData * source) { if (m_part == DocPosition::Source) return; if (source->hasFormat(LOKALIZE_XLIFF_MIMETYPE)) { //qCWarning(LOKALIZE_LOG)<<"has"; QVariant v; QByteArray data = source->data(LOKALIZE_XLIFF_MIMETYPE); QDataStream in(&data, QIODevice::ReadOnly); in >> v; //qCWarning(LOKALIZE_LOG)<<"ins"<(v).string<(v).ranges.size(); int start = 0; m_catalog->beginMacro(i18nc("@item Undo action item", "Insert text with markup")); QTextCursor cursor = textCursor(); if (cursor.hasSelection()) { start = qMin(cursor.anchor(), cursor.position()); int end = qMax(cursor.anchor(), cursor.position()); removeTargetSubstring(start, end - start); cursor.setPosition(start); setTextCursor(cursor); } else //sets right cursor position implicitly -- needed for mouse paste { QMimeData mimeData; mimeData.setText(QString()); if (m_cursorSelectionEnd != m_cursorSelectionStart) { int oldCursorPosition = textCursor().position(); removeTargetSubstring(m_cursorSelectionStart, m_cursorSelectionEnd - m_cursorSelectionStart); if (oldCursorPosition >= m_cursorSelectionEnd) { cursor.setPosition(oldCursorPosition - (m_cursorSelectionEnd - m_cursorSelectionStart)); setTextCursor(cursor); } } KTextEdit::insertFromMimeData(&mimeData); start = textCursor().position(); } insertCatalogString(v.value(), start); m_catalog->endMacro(); } else { QString text = source->text(); text.remove(TAGRANGE_IMAGE_SYMBOL); insertPlainText(text); } } static bool isMasked(const QString & str, uint col) { if (col == 0 || str.isEmpty()) return false; uint counter = 0; int pos = col; while (pos >= 0 && str.at(pos) == '\\') { counter++; pos--; } return !(bool)(counter % 2); } void TranslationUnitTextEdit::keyPressEvent(QKeyEvent * keyEvent) { QString spclChars = QStringLiteral("abfnrtv'?\\"); if (keyEvent->matches(QKeySequence::MoveToPreviousPage)) emit gotoPrevRequested(); else if (keyEvent->matches(QKeySequence::MoveToNextPage)) emit gotoNextRequested(); else if (keyEvent->matches(QKeySequence::Undo)) emit undoRequested(); else if (keyEvent->matches(QKeySequence::Redo)) emit redoRequested(); else if (keyEvent->matches(QKeySequence::Find)) emit findRequested(); else if (keyEvent->matches(QKeySequence::FindNext)) emit findNextRequested(); else if (keyEvent->matches(QKeySequence::Replace)) emit replaceRequested(); else if (keyEvent->modifiers() == (Qt::AltModifier | Qt::ControlModifier)) { if (keyEvent->key() == Qt::Key_Home) emit gotoFirstRequested(); else if (keyEvent->key() == Qt::Key_End) emit gotoLastRequested(); } else if (keyEvent->matches(QKeySequence::MoveToNextLine) || keyEvent->matches(QKeySequence::MoveToPreviousLine)) { //static QTime lastUpDownPress; //if (lastUpDownPress.msecsTo(QTime::currentTime())<500) { keyEvent->setAccepted(true); bool up = keyEvent->key() == Qt::Key_Up; QTextCursor c = textCursor(); if (!c.movePosition(up ? QTextCursor::Up : QTextCursor::Down)) { QTextCursor::MoveOperation op; if (up && !c.atStart()) op = QTextCursor::Start; else if (!up && !c.atEnd()) op = QTextCursor::End; else if (up) { emit gotoPrevRequested(); op = QTextCursor::End; } else { emit gotoNextRequested(); op = QTextCursor::Start; } c.movePosition(op); } setTextCursor(c); } //lastUpDownPress=QTime::currentTime(); } else if (m_part == DocPosition::Source) return KTextEdit::keyPressEvent(keyEvent); //BEGIN GENERAL // ALT+123 feature TODO this is general so should be on another level else if ((keyEvent->modifiers()&Qt::AltModifier) && !keyEvent->text().isEmpty() && keyEvent->text().at(0).isDigit()) { QString text = keyEvent->text(); while (!text.isEmpty() && text.at(0).isDigit()) { m_currentUnicodeNumber = 10 * m_currentUnicodeNumber + (text.at(0).digitValue()); text.remove(0, 1); } KTextEdit::keyPressEvent(keyEvent); } //END GENERAL else if (!keyEvent->modifiers() && (keyEvent->key() == Qt::Key_Backspace || keyEvent->key() == Qt::Key_Delete)) { //only for cases when: //-BkSpace was hit and cursor was atStart //-Del was hit and cursor was atEnd if (Q_UNLIKELY(!m_catalog->isApproved(m_currentPos.entry) && !textCursor().hasSelection()) && ((textCursor().atStart() && keyEvent->key() == Qt::Key_Backspace) || (textCursor().atEnd() && keyEvent->key() == Qt::Key_Delete))) requestToggleApprovement(); else KTextEdit::keyPressEvent(keyEvent); } else if (keyEvent->key() == Qt::Key_Space && (keyEvent->modifiers()&Qt::AltModifier)) insertPlainText(QChar(0x00a0U)); else if (keyEvent->key() == Qt::Key_Minus && (keyEvent->modifiers()&Qt::AltModifier)) insertPlainText(QChar(0x0000AD)); //BEGIN clever editing else if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) { -#ifndef NOKDE if (m_completionBox && m_completionBox->isVisible()) { if (m_completionBox->currentItem()) completionActivated(m_completionBox->currentItem()->text()); else qCWarning(LOKALIZE_LOG) << "avoided a crash. a case for bug 238835!"; m_completionBox->hide(); return; } -#endif if (m_catalog->type() != Gettext) return KTextEdit::keyPressEvent(keyEvent); QString str = toPlainText(); QTextCursor t = textCursor(); int pos = t.position(); QString ins; if (keyEvent->modifiers()&Qt::ShiftModifier) { if (pos > 0 && !str.isEmpty() && str.at(pos - 1) == QLatin1Char('\\') && !isMasked(str, pos - 1)) { ins = 'n'; } else { ins = QStringLiteral("\\n"); } } else if (!(keyEvent->modifiers()&Qt::ControlModifier)) { if (m_langUsesSpaces && pos > 0 && !str.isEmpty() && !str.at(pos - 1).isSpace()) { if (str.at(pos - 1) == QLatin1Char('\\') && !isMasked(str, pos - 1)) ins = QLatin1Char('\\'); // if there is no new line at the end if (pos < 2 || str.midRef(pos - 2, 2) != QLatin1String("\\n")) ins += QLatin1Char(' '); } else if (str.isEmpty()) { ins = QStringLiteral("\\n"); } } if (!str.isEmpty()) { ins += '\n'; insertPlainText(ins); } else KTextEdit::keyPressEvent(keyEvent); } else if (m_catalog->type() != Gettext) KTextEdit::keyPressEvent(keyEvent); else if ((keyEvent->modifiers()&Qt::ControlModifier) ? (keyEvent->key() == Qt::Key_D) : (keyEvent->key() == Qt::Key_Delete) && textCursor().atEnd()) { qCWarning(LOKALIZE_LOG) << "workaround for Qt/X11 bug"; QTextCursor t = textCursor(); if (!t.hasSelection()) { int pos = t.position(); QString str = toPlainText(); //workaround for Qt/X11 bug: if Del on NumPad is pressed, then pos is beyond end if (pos == str.size()) --pos; if (!str.isEmpty() && str.at(pos) == '\\' && !isMasked(str, pos) && pos < str.length() - 1 && spclChars.contains(str.at(pos + 1))) { t.deleteChar(); } } t.deleteChar(); setTextCursor(t); } else if ((!keyEvent->modifiers() && keyEvent->key() == Qt::Key_Backspace) || ((keyEvent->modifiers() & Qt::ControlModifier) && keyEvent->key() == Qt::Key_H)) { QTextCursor t = textCursor(); if (!t.hasSelection()) { int pos = t.position(); QString str = toPlainText(); if (!str.isEmpty() && pos > 0 && spclChars.contains(str.at(pos - 1))) { if (pos > 1 && str.at(pos - 2) == QLatin1Char('\\') && !isMasked(str, pos - 2)) { t.deletePreviousChar(); t.deletePreviousChar(); setTextCursor(t); //qCWarning(LOKALIZE_LOG)<<"set-->"<key() == Qt::Key_Tab) insertPlainText(QStringLiteral("\\t")); else KTextEdit::keyPressEvent(keyEvent); //END clever editing } void TranslationUnitTextEdit::keyReleaseEvent(QKeyEvent * e) { if ((e->key() == Qt::Key_Alt) && m_currentUnicodeNumber >= 32) { insertPlainText(QChar(m_currentUnicodeNumber)); m_currentUnicodeNumber = 0; } else KTextEdit::keyReleaseEvent(e); } QString TranslationUnitTextEdit::toPlainText() { QTextCursor cursor = textCursor(); cursor.select(QTextCursor::Document); QString text = cursor.selectedText(); text.replace(QChar(8233), '\n'); /* int ii=text.size(); while(--ii>=0) qCWarning(LOKALIZE_LOG)<push(new InsTagCmd(m_catalog, currentPos(), tag)); showPos(currentPos(), CatalogString(),/*keepCursor*/true); cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, tag.end + 1 + tag.isPaired()); setFocus(); } int TranslationUnitTextEdit::strForMicePosIfUnderTag(QPoint mice, CatalogString & str, bool tryHarder) { if (m_currentPos.entry == -1) return -1; QTextCursor cursor = cursorForPosition(mice); int pos = cursor.position(); str = m_catalog->catalogString(m_currentPos); if (pos == -1 || pos >= str.string.size()) return -1; //qCWarning(LOKALIZE_LOG)<<"here1"<0) // { // cursor.movePosition(QTextCursor::Left); // mice.setX(mice.x()+cursorRect(cursor).width()/2); // pos=cursorForPosition(mice).position(); // } if (str.string.at(pos) != TAGRANGE_IMAGE_SYMBOL) { bool cont = tryHarder && --pos >= 0 && str.string.at(pos) == TAGRANGE_IMAGE_SYMBOL; if (!cont) return -1; } int result = str.tags.size(); while (--result >= 0 && str.tags.at(result).start != pos && str.tags.at(result).end != pos) ; return result; } void TranslationUnitTextEdit::mouseReleaseEvent(QMouseEvent * event) { if (event->button() == Qt::LeftButton) { CatalogString str; int pos = strForMicePosIfUnderTag(event->pos(), str); if (pos != -1 && m_part == DocPosition::Source) { emit tagInsertRequested(str.tags.at(pos)); event->accept(); return; } } KTextEdit::mouseReleaseEvent(event); } void TranslationUnitTextEdit::contextMenuEvent(QContextMenuEvent * event) { CatalogString str; int pos = strForMicePosIfUnderTag(event->pos(), str); if (pos != -1) { QString xid = str.tags.at(pos).xid; if (!xid.isEmpty()) { QMenu menu; int entry = m_catalog->unitById(xid); /* QAction* findUnit=menu.addAction(entry>=m_catalog->numberOfEntries()? i18nc("@action:inmenu","Show the binary unit"): i18nc("@action:inmenu","Go to the referenced entry")); */ QAction* result = menu.exec(event->globalPos()); if (result) { if (entry >= m_catalog->numberOfEntries()) emit binaryUnitSelectRequested(xid); else emit gotoEntryRequested(DocPosition(entry)); event->accept(); } return; } } if (textCursor().hasSelection()) { QMenu menu; menu.addAction(i18nc("@action:inmenu", "Lookup selected text in translation memory")); if (menu.exec(event->globalPos())) emit tmLookupRequested(m_part, textCursor().selectedText()); return; } if (m_part != DocPosition::Target) return; KTextEdit::contextMenuEvent(event); #if 0 QTextCursor wordSelectCursor = cursorForPosition(event->pos()); wordSelectCursor.select(QTextCursor::WordUnderCursor); if (m_highlighter->isWordMisspelled(wordSelectCursor.selectedText())) { QMenu menu; QMenu suggestions; foreach (const QString& s, m_highlighter->suggestionsForWord(wordSelectCursor.selectedText())) suggestions.addAction(s); if (!suggestions.isEmpty()) { QAction* answer = suggestions.exec(event->globalPos()); if (answer) { m_catalog->beginMacro(i18nc("@item Undo action item", "Replace text")); wordSelectCursor.insertText(answer->text()); m_catalog->endMacro(); } } } #endif // QMenu menu; // QAction* spellchecking=menu.addAction(); // event->accept(); } void TranslationUnitTextEdit::wheelEvent(QWheelEvent * event) { //Override default KTextEdit behavior which ignores Ctrl+wheelEvent when the field is not ReadOnly (i/o zooming) if (m_part == DocPosition::Target && !Settings::mouseWheelGo() && (event->modifiers() == Qt::ControlModifier)) { float delta = event->angleDelta().y() / 120.f; zoomInF(delta); return; } if (m_part == DocPosition::Source || !Settings::mouseWheelGo()) return KTextEdit::wheelEvent(event); switch (event->modifiers()) { case Qt::ControlModifier: if (event->delta() > 0) emit gotoPrevFuzzyRequested(); else emit gotoNextFuzzyRequested(); break; case Qt::AltModifier: if (event->delta() > 0) emit gotoPrevUntranslatedRequested(); else emit gotoNextUntranslatedRequested(); break; case Qt::ControlModifier + Qt::ShiftModifier: if (event->delta() > 0) emit gotoPrevFuzzyUntrRequested(); else emit gotoNextFuzzyUntrRequested(); break; case Qt::ShiftModifier: return KTextEdit::wheelEvent(event); default: if (event->delta() > 0) emit gotoPrevRequested(); else emit gotoNextRequested(); } } void TranslationUnitTextEdit::spellReplace() { -#ifndef NOKDE QTextCursor wordSelectCursor = textCursor(); wordSelectCursor.select(QTextCursor::WordUnderCursor); if (!m_highlighter->isWordMisspelled(wordSelectCursor.selectedText())) return; const QStringList& suggestions = m_highlighter->suggestionsForWord(wordSelectCursor.selectedText()); if (suggestions.isEmpty()) return; m_catalog->beginMacro(i18nc("@item Undo action item", "Replace text")); wordSelectCursor.insertText(suggestions.first()); m_catalog->endMacro(); -#endif } bool TranslationUnitTextEdit::event(QEvent * event) { #ifdef Q_OS_MAC if (event->type() == QEvent::InputMethod) { QInputMethodEvent* e = static_cast(event); insertPlainText(e->commitString()); e->accept(); return true; } #endif if (event->type() == QEvent::ToolTip) { QHelpEvent *helpEvent = static_cast(event); CatalogString str; int pos = strForMicePosIfUnderTag(helpEvent->pos(), str, true); if (pos != -1) { QString tooltip = str.tags.at(pos).displayName(); QToolTip::showText(helpEvent->globalPos(), tooltip); return true; } -#if !defined(NOKDE) || defined(SONNET_STATIC) QString tip; QString langCode = m_highlighter->currentLanguage(); bool nospell = langCode.isEmpty(); if (nospell) langCode = m_part == DocPosition::Source ? m_catalog->sourceLangCode() : m_catalog->targetLangCode(); QLocale l(langCode); if (l.language() != QLocale::C) tip = l.nativeLanguageName() + QLatin1String(" ("); tip += langCode; if (l.language() != QLocale::C) tip += ')'; if (nospell) tip += QLatin1String(" - ") % i18n("no spellcheck available"); QToolTip::showText(helpEvent->globalPos(), tip); -#endif } return KTextEdit::event(event); } void TranslationUnitTextEdit::tagMenu() { doTag(false); } void TranslationUnitTextEdit::tagImmediate() { doTag(true); } void TranslationUnitTextEdit::doTag(bool immediate) { QMenu menu; QAction* txt = 0; CatalogString sourceWithTags = m_catalog->sourceWithTags(m_currentPos); int count = sourceWithTags.tags.size(); if (count) { QMap tagIdToIndex = m_catalog->targetWithTags(m_currentPos).tagIdToIndex(); bool hasActive = false; for (int i = 0; i < count; ++i) { //txt=menu.addAction(sourceWithTags.ranges.at(i)); txt = menu.addAction(QString::number(i)/*+" "+sourceWithTags.ranges.at(i).id*/); txt->setData(QVariant(i)); if (!hasActive && !tagIdToIndex.contains(sourceWithTags.tags.at(i).id)) { if (immediate) { insertTag(sourceWithTags.tags.at(txt->data().toInt())); return; } hasActive = true; menu.setActiveAction(txt); } } if (immediate) return; txt = menu.exec(mapToGlobal(cursorRect().bottomRight())); if (!txt) return; insertTag(sourceWithTags.tags.at(txt->data().toInt())); } else { if (Q_UNLIKELY(Project::instance()->markup().isEmpty())) return; //QRegExp tag("(<[^>]*>)+|\\&\\w+\\;"); QRegExp tag(Project::instance()->markup()); tag.setMinimal(true); QString en = m_catalog->sourceWithTags(m_currentPos).string; QString target(toPlainText()); en.remove('\n'); target.remove('\n'); int pos = 0; //tag.indexIn(en); int posInMsgStr = 0; while ((pos = tag.indexIn(en, pos)) != -1) { /* QString str(tag.cap(0)); str.replace("&","&&");*/ txt = menu.addAction(tag.cap(0)); pos += tag.matchedLength(); if (posInMsgStr != -1 && (posInMsgStr = target.indexOf(tag.cap(0), posInMsgStr)) == -1) { if (immediate) { insertPlainText(txt->text()); return; } menu.setActiveAction(txt); } else if (posInMsgStr != -1) posInMsgStr += tag.matchedLength(); } if (!txt || immediate) return; //txt=menu.exec(_msgidEdit->mapToGlobal(QPoint(0,0))); txt = menu.exec(mapToGlobal(cursorRect().bottomRight())); if (txt) insertPlainText(txt->text()); } } void TranslationUnitTextEdit::source2target() { CatalogString sourceWithTags = m_catalog->sourceWithTags(m_currentPos); QString text = sourceWithTags.string; QString out; QString ctxt = m_catalog->context(m_currentPos.entry).first(); QRegExp delimiter(QStringLiteral("\\s*,\\s*")); //TODO ask for the fillment if the first time. //BEGIN KDE specific part if (ctxt.startsWith(QLatin1String("NAME OF TRANSLATORS")) || text.startsWith(QLatin1String("_: NAME OF TRANSLATORS\\n"))) { if (!document()->toPlainText().split(delimiter).contains(Settings::authorLocalizedName())) { if (!document()->isEmpty()) out = QLatin1String(", "); out += Settings::authorLocalizedName(); } } else if (ctxt.startsWith(QLatin1String("EMAIL OF TRANSLATORS")) || text.startsWith(QLatin1String("_: EMAIL OF TRANSLATORS\\n"))) { if (!document()->toPlainText().split(delimiter).contains(Settings::authorEmail())) { if (!document()->isEmpty()) out = QLatin1String(", "); out += Settings::authorEmail(); } } else if (/*_catalog->isGeneratedFromDocbook() &&*/ text.startsWith(QLatin1String("ROLES_OF_TRANSLATORS"))) { if (!document()->isEmpty()) out = '\n'; out += QLatin1String("\n" "\n" "
") % Settings::authorEmail() % QLatin1String("
\n" "
"); } else if (text.startsWith(QLatin1String("CREDIT_FOR_TRANSLATORS"))) { if (!document()->isEmpty()) out = '\n'; out += QLatin1String("") % Settings::authorLocalizedName() % '\n' % QLatin1String("") % Settings::authorEmail() % QLatin1String(""); } //END KDE specific part else { m_catalog->beginMacro(i18nc("@item Undo action item", "Copy source to target")); removeTargetSubstring(0, -1,/*refresh*/false); insertCatalogString(sourceWithTags, 0,/*refresh*/false); m_catalog->endMacro(); showPos(m_currentPos, sourceWithTags,/*keepCursor*/false); requestToggleApprovement(); } if (!out.isEmpty()) { QTextCursor t = textCursor(); t.movePosition(QTextCursor::End); t.insertText(out); setTextCursor(t); } } void TranslationUnitTextEdit::requestToggleApprovement() { if (m_catalog->isApproved(m_currentPos.entry) || !Settings::autoApprove()) return; bool skip = m_catalog->isPlural(m_currentPos); if (skip) { skip = false; DocPos pos(m_currentPos); for (pos.form = 0; pos.form < m_catalog->numberOfPluralForms(); ++(pos.form)) skip = skip || !m_catalog->isModified(pos); } if (!skip) emit toggleApprovementRequested(); } void TranslationUnitTextEdit::cursorToStart() { QTextCursor t = textCursor(); t.movePosition(QTextCursor::Start); setTextCursor(t); } void TranslationUnitTextEdit::doCompletion(int pos) { -#ifndef NOKDE QTime a; a.start(); QString target = m_catalog->targetWithTags(m_currentPos).string; int sp = target.lastIndexOf(CompletionStorage::instance()->rxSplit, pos - 1); int len = (pos - sp) - 1; QStringList s = CompletionStorage::instance()->makeCompletion(QString::fromRawData(target.unicode() + sp + 1, len)); if (!m_completionBox) { //BEGIN creation m_completionBox = new MyCompletionBox(this); connect(m_completionBox, &MyCompletionBox::activated, this, &TranslationUnitTextEdit::completionActivated); m_completionBox->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); //END creation } m_completionBox->setItems(s); if (s.size() && !s.first().isEmpty()) { m_completionBox->setCurrentRow(0); //qApp->removeEventFilter( m_completionBox ); if (!m_completionBox->isVisible()) //NOTE remove the check if kdelibs gets adapted m_completionBox->show(); m_completionBox->resize(m_completionBox->sizeHint()); QPoint p = cursorRect().bottomRight(); if (p.x() < 10) //workaround Qt bug p.rx() += textCursor().verticalMovementX() + QFontMetrics(currentFont()).width('W'); m_completionBox->move(viewport()->mapToGlobal(p)); } else m_completionBox->hide(); -#endif } void TranslationUnitTextEdit::doExplicitCompletion() { doCompletion(textCursor().anchor()); } void TranslationUnitTextEdit::completionActivated(const QString & semiWord) { QTextCursor cursor = textCursor(); cursor.insertText(semiWord); setTextCursor(cursor); }