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("