• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdesdk API Reference
  • KDE Home
  • Contact Us
 

lokalize

  • sources
  • kde-4.14
  • kdesdk
  • lokalize
  • src
  • mergemode
mergecatalog.cpp
Go to the documentation of this file.
1 /* ****************************************************************************
2  This file is part of Lokalize
3 
4  Copyright (C) 2007-2011 by Nick Shaforostoff <shafff@ukr.net>
5 
6  This program is free software; you can redistribute it and/or
7  modify it under the terms of the GNU General Public License as
8  published by the Free Software Foundation; either version 2 of
9  the License or (at your option) version 3 or any later version
10  accepted by the membership of KDE e.V. (or its successor approved
11  by the membership of KDE e.V.), which shall act as a proxy
12  defined in Section 14 of version 3 of the license.
13 
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with this program. If not, see <http://www.gnu.org/licenses/>.
21 
22 **************************************************************************** */
23 
24 #include "mergecatalog.h"
25 #include "catalog_private.h"
26 #include "catalogstorage.h"
27 #include "cmd.h"
28 #include <kdebug.h>
29 #include <klocalizedstring.h>
30 #include <QMultiHash>
31 #include <QtAlgorithms>
32 
33 
34 
35 MergeCatalog::MergeCatalog(QObject* parent, Catalog* baseCatalog, bool saveChanges)
36  : Catalog(parent)
37  , m_baseCatalog(baseCatalog)
38  , m_modified(false)
39 {
40  setActivePhase(baseCatalog->activePhase(),baseCatalog->activePhaseRole());
41  if (saveChanges)
42  {
43  connect (baseCatalog,SIGNAL(signalEntryModified(DocPosition)),this,SLOT(copyFromBaseCatalogIfInDiffIndex(DocPosition)));
44  connect (baseCatalog,SIGNAL(signalFileSaved()),this,SLOT(save()));
45  }
46 }
47 
48 void MergeCatalog::copyFromBaseCatalog(const DocPosition& pos, int options)
49 {
50  bool a=m_mergeDiffIndex.contains(pos.entry);
51  if (options&EvenIfNotInDiffIndex || !a)
52  {
53  //sync changes
54  DocPosition ourPos=pos;
55  if ( (ourPos.entry=m_map.at(ourPos.entry)) == -1)
56  return;
57 
58  //note the explicit use of map...
59  if (m_storage->isApproved(ourPos)!=m_baseCatalog->isApproved(pos))
60  //kWarning()<<ourPos.entry<<"SHIT";
61  m_storage->setApproved(ourPos, m_baseCatalog->isApproved(pos));
62  DocPos p(pos);
63  if (!m_originalHashes.contains(p))
64  m_originalHashes[p]=qHash(m_storage->target(ourPos));
65  m_storage->setTarget(ourPos,m_baseCatalog->target(pos));
66  setModified(ourPos, true);
67 
68  if (options&EvenIfNotInDiffIndex && a)
69  m_mergeDiffIndex.removeAll(pos.entry);
70 
71  m_modified=true;
72  emit signalEntryModified(pos);
73  }
74 }
75 
76 QString MergeCatalog::msgstr(const DocPosition& pos) const
77 {
78  DocPosition us=pos;
79  us.entry=m_map.at(pos.entry);
80 
81  return (us.entry==-1)?QString():Catalog::msgstr(us);
82 }
83 
84 bool MergeCatalog::isApproved(uint index) const
85 {
86  return (m_map.at(index)==-1)?false:Catalog::isApproved(m_map.at(index));
87 }
88 
89 TargetState MergeCatalog::state(const DocPosition& pos) const
90 {
91  DocPosition us=pos;
92  us.entry=m_map.at(pos.entry);
93 
94  return (us.entry==-1)?New:Catalog::state(us);
95 }
96 
97 
98 bool MergeCatalog::isPlural(uint index) const
99 {
100  //sanity
101  if (m_map.at(index) == -1)
102  {
103  kWarning()<<"!!! index"<<index<<"m_map.at(index)"<<m_map.at(index)<<"numberOfEntries()"<<numberOfEntries();
104  return false;
105  }
106 
107  return Catalog::isPlural(m_map.at(index));
108 }
109 
110 bool MergeCatalog::isPresent(const short int& entry) const
111 {
112  return m_map.at(entry)!=-1;
113 }
114 
115 MatchItem MergeCatalog::calcMatchItem(const DocPosition& basePos,const DocPosition& mergePos)
116 {
117  CatalogStorage& baseStorage=*(m_baseCatalog->m_storage);
118  CatalogStorage& mergeStorage=*(m_storage);
119 
120  MatchItem item(mergePos.entry, basePos.entry, true);
121  //TODO make more robust, perhaps after XLIFF?
122  QStringList baseMatchData=baseStorage.matchData(basePos);
123  QStringList mergeMatchData=mergeStorage.matchData(mergePos);
124 
125  //compare ids
126  item.score+=40*((baseMatchData.isEmpty()&&mergeMatchData.isEmpty())?baseStorage.id(basePos)==mergeStorage.id(mergePos)
127  :baseMatchData==mergeMatchData);
128 
129  //TODO look also for changed/new <note>s
130 
131  //translation isn't changed
132  if (baseStorage.targetAllForms(basePos, true)==mergeStorage.targetAllForms(mergePos, true))
133  {
134  item.translationIsDifferent=baseStorage.isApproved(basePos)!=mergeStorage.isApproved(mergePos);
135  item.score+=29+1*item.translationIsDifferent;
136  }
137 #if 0
138  if (baseStorage.source(basePos)=="%1 (%2)")
139  {
140  qDebug()<<"BASE";
141  qDebug()<<m_baseCatalog->url();
142  qDebug()<<basePos.entry;
143  qDebug()<<baseStorage.source(basePos);
144  qDebug()<<baseMatchData.first();
145  qDebug()<<"MERGE";
146  qDebug()<<url();
147  qDebug()<<mergePos.entry;
148  qDebug()<<mergeStorage.source(mergePos);
149  qDebug()<<mergeStorage.matchData(mergePos).first();
150  qDebug()<<item.score;
151  qDebug()<<"";
152  }
153 #endif
154  return item;
155 }
156 
157 static QString strip(QString source)
158 {
159  source.remove('\n');
160  return source;
161 }
162 
163 int MergeCatalog::loadFromUrl(const KUrl& url)
164 {
165  int errorLine=Catalog::loadFromUrl(url);
166  if (KDE_ISUNLIKELY( errorLine!=0 ))
167  return errorLine;
168 
169  //now calc the entry mapping
170 
171  CatalogStorage& baseStorage=*(m_baseCatalog->m_storage);
172  CatalogStorage& mergeStorage=*(m_storage);
173 
174  DocPosition i(0);
175  int size=baseStorage.size();
176  int mergeSize=mergeStorage.size();
177  m_map.fill(-1,size);
178  QMultiMap<int,int> backMap; //will be used to maintain one-to-one relation
179 
180 
181  //precalc for fast lookup
182  QMultiHash<QString, int> mergeMap;
183  while (i.entry<mergeSize)
184  {
185  mergeMap.insert(strip(mergeStorage.source(i)),i.entry);
186  ++(i.entry);
187  }
188 
189  i.entry=0;
190  while (i.entry<size)
191  {
192  QString key=strip(baseStorage.source(i));
193  const QList<int>& entries=mergeMap.values(key);
194  QList<MatchItem> scores;
195  int k=entries.size();
196  if (k)
197  {
198  while(--k>=0)
199  scores<<calcMatchItem(i,DocPosition( entries.at(k) ));
200 
201  qSort(scores.begin(), scores.end(), qGreater<MatchItem>());
202 
203  m_map[i.entry]=scores.first().mergeEntry;
204  backMap.insert(scores.first().mergeEntry, i.entry);
205 
206  if (scores.first().translationIsDifferent)
207  m_mergeDiffIndex.append(i.entry);
208 
209  }
210  ++i.entry;
211  }
212 
213 
214  //maintain one-to-one relation
215  const QList<int>& mergePositions=backMap.uniqueKeys();
216  foreach(int mergePosition, mergePositions)
217  {
218  const QList<int>& basePositions=backMap.values(mergePosition);
219  if (basePositions.size()==1)
220  continue;
221 
222  //qDebug()<<"kv"<<mergePosition<<basePositions;
223  QList<MatchItem> scores;
224  foreach(int value, basePositions)
225  scores<<calcMatchItem(DocPosition(value), mergePosition);
226 
227  qSort(scores.begin(), scores.end(), qGreater<MatchItem>());
228  int i=scores.size();
229  while(--i>0)
230  {
231  //qDebug()<<"erasing"<<scores.at(i).baseEntry<<m_map[scores.at(i).baseEntry]<<",m_map["<<scores.at(i).baseEntry<<"]=-1";
232  m_map[scores.at(i).baseEntry]=-1;
233  }
234  }
235 
236  //fuzzy match unmatched entries?
237 /* QMultiHash<QString, int>::iterator it = mergeMap.begin();
238  while (it != mergeMap.end())
239  {
240  //kWarning()<<it.value()<<it.key();
241  ++it;
242  }*/
243  m_unmatchedCount=numberOfEntries()-mergePositions.count();
244  m_modified=false;
245  m_originalHashes.clear();
246 
247  return 0;
248 }
249 
250 bool MergeCatalog::isModified(DocPos pos) const
251 {
252  return Catalog::isModified(pos) && m_originalHashes.value(pos)!=qHash(target(pos.toDocPosition()));
253 }
254 
255 bool MergeCatalog::save()
256 {
257  bool ok = !m_modified || Catalog::save();
258  if (ok) m_modified=false;
259  m_originalHashes.clear();
260  return ok;
261 }
262 
263 void MergeCatalog::copyToBaseCatalog(DocPosition& pos)
264 {
265  bool changeContents=m_baseCatalog->msgstr(pos)!=msgstr(pos);
266 
267  m_baseCatalog->beginMacro(i18nc("@item Undo action item","Accept change in translation"));
268 
269  if ( m_baseCatalog->state(pos) != state(pos))
270  SetStateCmd::instantiateAndPush(m_baseCatalog,pos,state(pos));
271 
272  if (changeContents)
273  {
274  pos.offset=0;
275  if (!m_baseCatalog->msgstr(pos).isEmpty())
276  m_baseCatalog->push(new DelTextCmd(m_baseCatalog,pos,m_baseCatalog->msgstr(pos)));
277 
278  m_baseCatalog->push(new InsTextCmd(m_baseCatalog,pos,msgstr(pos)));
279  }
281  bool remove=true;
282  if (isPlural(pos.entry))
283  {
284  DocPosition p=pos;
285  p.form=qMin(m_baseCatalog->numberOfPluralForms(),numberOfPluralForms());//just sanity check
286  p.form=qMax((int)p.form,1);//just sanity check
287  while ((--(p.form))>=0 && remove)
288  remove=m_baseCatalog->msgstr(p)==msgstr(p);
289  }
290  if (remove)
291  removeFromDiffIndex(pos.entry);
292 
293  m_baseCatalog->endMacro();
294 }
295 
296 void MergeCatalog::copyToBaseCatalog(int options)
297 {
298  DocPosition pos;
299  pos.offset=0;
300  bool insHappened=false;
301  QLinkedList<int> changed=differentEntries();
302  foreach(int entry, changed)
303  {
304  pos.entry=entry;
305  if (options&EmptyOnly&&!m_baseCatalog->isEmpty(entry))
306  continue;
307  if (options&HigherOnly&&!m_baseCatalog->isEmpty(entry)&&m_baseCatalog->state(pos)>=state(pos))
308  continue;
309 
310  int formsCount=(m_baseCatalog->isPlural(entry))?m_baseCatalog->numberOfPluralForms():1;
311  pos.form=0;
312  while (pos.form<formsCount)
313  {
314  //m_baseCatalog->push(new DelTextCmd(m_baseCatalog,pos,m_baseCatalog->msgstr(pos.entry,0))); ?
315  //some forms may still contain translation...
316  if (!(options&EmptyOnly && !m_baseCatalog->isEmpty(pos)) /*&&
317  !(options&HigherOnly && !m_baseCatalog->isEmpty(pos) && m_baseCatalog->state(pos)>=state(pos))*/)
318  {
319  if (!insHappened)
320  {
321  //stop basecatalog from sending signalEntryModified to us
322  //when we are the ones who does the modification
323  disconnect (m_baseCatalog,SIGNAL(signalEntryModified(DocPosition)),this,SLOT(copyFromBaseCatalogIfInDiffIndex(DocPosition)));
324  insHappened=true;
325  m_baseCatalog->beginMacro(i18nc("@item Undo action item","Accept all new translations"));
326  }
327 
328  copyToBaseCatalog(pos);
332  }
333  ++(pos.form);
334  }
338  }
339 
340  if (insHappened)
341  {
342  m_baseCatalog->endMacro();
343  //reconnect to catch all modifications coming from outside
344  connect (m_baseCatalog,SIGNAL(signalEntryModified(DocPosition)),this,SLOT(copyFromBaseCatalogIfInDiffIndex(DocPosition)));
345  }
346 }
347 
348 #include "mergecatalog.moc"
MergeCatalog::state
TargetState state(const DocPosition &pos) const
Definition: mergecatalog.cpp:89
Catalog::url
const KUrl & url() const
Definition: catalog.h:189
CatalogStorage::source
virtual QString source(const DocPosition &pos) const =0
flat-model interface (ignores XLIFF grouping)
MergeCatalog::msgstr
QString msgstr(const DocPosition &) const
Definition: mergecatalog.cpp:76
QMap::contains
bool contains(const Key &key) const
QMap::values
QList< T > values() const
Catalog::loadFromUrl
int loadFromUrl(const KUrl &url, const KUrl &saidUrl=KUrl(), int *fileSize=0, bool fast=false)
Definition: catalog.cpp:508
Catalog::numberOfPluralForms
int numberOfPluralForms() const
Definition: catalog.h:150
QUndoStack::beginMacro
void beginMacro(const QString &text)
Catalog::m_storage
CatalogStorage * m_storage
Definition: catalog.h:243
CatalogStorage::setApproved
virtual void setApproved(const DocPosition &, bool approved)
Definition: catalogstorage.h:134
QVector::fill
QVector< T > & fill(const T &value, int size)
QList::at
const T & at(int i) const
catalogstorage.h
MergeCatalog::differentEntries
QLinkedList< int > differentEntries() const
Definition: mergecatalog.h:85
MergeCatalog::isPresent
bool isPresent(const short int &entry) const
whether 'merge source' has entry with such msgid
Definition: mergecatalog.cpp:110
MergeCatalog::HigherOnly
Definition: mergecatalog.h:101
Catalog::activePhaseRole
ProjectLocal::PersonRole activePhaseRole() const
Definition: catalog.h:120
Catalog::push
void push(QUndoCommand *cmd)
Definition: catalog.cpp:155
CatalogStorage::target
virtual QString target(const DocPosition &pos) const =0
MergeCatalog::EvenIfNotInDiffIndex
Definition: mergecatalog.h:105
cmd.h
Catalog::save
bool save()
Definition: catalog.cpp:609
QString::remove
QString & remove(int position, int n)
QMap::clear
void clear()
QObject::disconnect
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
CatalogStorage::setTarget
virtual void setTarget(const DocPosition &pos, const QString &arg)=0
New
Definition: state.h:32
Catalog::setActivePhase
void setActivePhase(const QString &phase, ProjectLocal::PersonRole role=ProjectLocal::Approver)
Definition: catalog.cpp:339
Catalog::isEmpty
bool isEmpty(uint index) const
Definition: catalog.cpp:432
Catalog::activePhase
QString activePhase() const
Definition: catalog.h:119
QList::size
int size() const
DelTextCmd
Definition: cmd.h:99
Catalog::isModified
bool isModified(DocPos entry) const
Definition: catalog.cpp:928
DocPosition::offset
uint offset
Definition: pos.h:51
DocPosition::entry
int entry
Definition: pos.h:48
Catalog::setModified
bool setModified(DocPos entry, bool modif)
Definition: catalog.cpp:915
DocPosition
This struct represents a position in a catalog.
Definition: pos.h:38
QLinkedList< int >
Catalog::target
QString target(const DocPosition &pos) const
Definition: catalog.h:96
QList::count
int count(const T &value) const
Catalog::signalFileSaved
Q_SCRIPTABLE void signalFileSaved()
SetStateCmd::instantiateAndPush
static void instantiateAndPush(Catalog *catalog, const DocPosition &pos, TargetState state)
Definition: cmd.cpp:186
Catalog::InsTextCmd
friend class InsTextCmd
Definition: catalog.h:248
catalog_private.h
QObject
QList::isEmpty
bool isEmpty() const
QString::isEmpty
bool isEmpty() const
strip
static QString strip(QString source)
Definition: mergecatalog.cpp:157
DocPosition::form
char form
Definition: pos.h:50
MatchItem
Definition: mergecatalog.h:32
MergeCatalog::removeFromDiffIndex
void removeFromDiffIndex(uint index)
Definition: mergecatalog.h:104
Catalog::isPlural
bool isPlural(uint index) const
Definition: catalog.cpp:405
QMultiMap::insert
QMap< Key, T >::iterator insert(const Key &key, const T &value)
QList::first
T & first()
QString
QList< int >
QMultiHash::insert
QHash< Key, T >::iterator insert(const Key &key, const T &value)
mergecatalog.h
CatalogStorage
Abstract interface for storage of translation file.
Definition: catalogstorage.h:45
QStringList
CatalogStorage::targetAllForms
virtual QStringList targetAllForms(const DocPosition &pos, bool stripNewLines=false) const =0
QList::end
iterator end()
MergeCatalog::copyFromBaseCatalog
void copyFromBaseCatalog(const DocPosition &, int options)
Definition: mergecatalog.cpp:48
MergeCatalog::save
bool save()
Definition: mergecatalog.cpp:255
MergeCatalog::MergeCatalog
MergeCatalog(QObject *parent, Catalog *baseCatalog, bool saveChanges=true)
Definition: mergecatalog.cpp:35
QVector::at
const T & at(int i) const
qHash
uint qHash(const DocPos &key)
Definition: pos.h:116
Catalog::signalEntryModified
void signalEntryModified(const DocPosition &)
QUndoStack::endMacro
void endMacro()
CatalogStorage::size
virtual int size() const =0
MergeCatalog::isModified
bool isModified(DocPos) const
Definition: mergecatalog.cpp:250
Catalog::isApproved
bool isApproved(uint index) const
Definition: catalog.cpp:410
Catalog::numberOfEntries
int numberOfEntries() const
Definition: catalog.cpp:171
DocPos
simpler version of DocPosition for use in QMap
Definition: pos.h:82
MergeCatalog::isPlural
bool isPlural(uint index) const
Definition: mergecatalog.cpp:98
Catalog
This class represents a catalog It uses CatalogStorage interface to work with catalogs in different f...
Definition: catalog.h:74
Catalog::state
TargetState state(const DocPosition &pos) const
Definition: catalog.cpp:421
QMultiMap
QLinkedList::removeAll
int removeAll(const T &value)
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
TargetState
TargetState
Definition: state.h:30
MergeCatalog::EmptyOnly
Definition: mergecatalog.h:101
Catalog::msgstr
virtual QString msgstr(const DocPosition &) const
Definition: catalog.cpp:195
MergeCatalog::isApproved
bool isApproved(uint index) const
Definition: mergecatalog.cpp:84
DocPos::toDocPosition
DocPosition toDocPosition()
Definition: pos.h:107
QList::begin
iterator begin()
MergeCatalog::copyFromBaseCatalogIfInDiffIndex
void copyFromBaseCatalogIfInDiffIndex(const DocPosition &pos)
Definition: mergecatalog.h:109
CatalogStorage::matchData
virtual QStringList matchData(const DocPosition &) const =0
user-invisible data for matching, e.g.
QLinkedList::contains
bool contains(const T &value) const
QMultiHash< QString, int >
QLinkedList::append
void append(const T &value)
CatalogStorage::id
virtual QString id(const DocPosition &) const =0
entry id unique for this file
QMap::value
const T value(const Key &key) const
QMap::uniqueKeys
QList< Key > uniqueKeys() const
MergeCatalog::loadFromUrl
int loadFromUrl(const KUrl &url)
Definition: mergecatalog.cpp:163
CatalogStorage::isApproved
virtual bool isApproved(const DocPosition &) const
Definition: catalogstorage.h:133
MergeCatalog::copyToBaseCatalog
void copyToBaseCatalog(DocPosition &pos)
Definition: mergecatalog.cpp:263
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:40:07 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

lokalize

Skip menu "lokalize"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdesdk API Reference

Skip menu "kdesdk API Reference"
  • kapptemplate
  • kcachegrind
  • kompare
  • lokalize
  • umbrello
  •   umbrello

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal