• 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
xlifftextedit.cpp
Go to the documentation of this file.
1 /* ****************************************************************************
2  This file is part of Lokalize
3 
4  Copyright (C) 2007-2012 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 #undef KDE_NO_DEBUG_OUTPUT
25 
26 #include "xlifftextedit.h"
27 #include "catalog.h"
28 #include "cmd.h"
29 #include "syntaxhighlighter.h"
30 #include "prefs_lokalize.h"
31 #include "prefs.h"
32 #include "project.h"
33 #include "completionstorage.h"
34 
35 #include <kcompletionbox.h>
36 
37 #include <QStringBuilder>
38 #include <QPixmap>
39 #include <QPushButton>
40 #include <QPainter>
41 #include <QStyle>
42 #include <QApplication>
43 #include <QStyleOptionButton>
44 #include <QMimeData>
45 #include <QMetaType>
46 
47 #include <QMenu>
48 #include <QMouseEvent>
49 #include <QToolTip>
50 
51 // static int im_count=0;
52 // static int im_time=0;
53 
54 #undef KDE_NO_DEBUG_OUTPUT
55 #include <QScrollBar>
56 
57 
58 inline static QImage generateImage(const QString& str, const QFont& font)
59 {
60  // im_count++;
61  // QTime a;a.start();
62 
63  QStyleOptionButton opt;
64  opt.fontMetrics=QFontMetrics(font);
65  opt.text=' '+str+' ';
66  opt.rect=opt.fontMetrics.boundingRect(opt.text).adjusted(0,0,5,5);
67  opt.rect.moveTo(0,0);
68 
69  QImage result(opt.rect.size(),QImage::Format_ARGB32);
70  result.fill(0);//0xAARRGGBB
71  QPainter painter(&result);
72  QApplication::style()->drawControl(QStyle::CE_PushButton,&opt,&painter);
73 
74  // im_time+=a.elapsed();
75  // kWarning()<<im_count<<im_time;
76  return result;
77 }
78 
79 class MyCompletionBox: public KCompletionBox
80 {
81 public:
82  MyCompletionBox(QWidget* p):KCompletionBox(p){}
83  QSize sizeHint() const;
84 
85  bool eventFilter(QObject* , QEvent* ); //reimplemented to deliver more keypresses to XliffTextEdit
86 };
87 
88 QSize MyCompletionBox::sizeHint() const
89 {
90  int h = count()?(sizeHintForRow(0)):0;
91  h=qMin(count()*h,10*h) + 2*frameWidth();
92  int w = sizeHintForColumn(0) + verticalScrollBar()->width() + 2*frameWidth();
93  return QSize(w, h);
94 }
95 
96 bool MyCompletionBox::eventFilter(QObject* object, QEvent* event)
97 {
98  if (event->type()==QEvent::KeyPress)
99  {
100  QKeyEvent* e = static_cast<QKeyEvent*>(event);
101  if (e->key()==Qt::Key_PageDown || e->key()==Qt::Key_PageUp)
102  {
103  hide();
104  return false;
105  }
106  }
107  return KCompletionBox::eventFilter(object, event);
108 }
109 
110 
111 #if 1
112 class XliffTextEditSpellInterface: public KTextEditSpellInterface
113 {
114 public:
115  XliffTextEditSpellInterface(SyntaxHighlighter* highlighter);
116  ~XliffTextEditSpellInterface(){};
117 
118  bool isSpellCheckingEnabled() const {return m_enabled;}
119  void setSpellCheckingEnabled(bool enable);
120  bool shouldBlockBeSpellChecked(const QString &block) const{Q_UNUSED(block); return true;}
121 private:
122  bool m_enabled;
123  SyntaxHighlighter* m_highlighter;
124 };
125 
126 XliffTextEditSpellInterface::XliffTextEditSpellInterface(SyntaxHighlighter* highlighter)
127  : KTextEditSpellInterface()
128  , m_enabled(Settings::autoSpellcheck())
129  , m_highlighter(highlighter)
130 {
131  m_highlighter->setActive(m_enabled);
132 }
133 
134 void XliffTextEditSpellInterface::setSpellCheckingEnabled(bool enable)
135 {
136  Settings::setAutoSpellcheck(enable);
137  m_enabled=enable;
138  m_highlighter->setActive(enable);
139  SettingsController::instance()->dirty=true;
140 }
141 #endif
142 
143 TranslationUnitTextEdit::TranslationUnitTextEdit(Catalog* catalog, DocPosition::Part part, QWidget* parent)
144  : KTextEdit(parent)
145  , m_currentUnicodeNumber(0)
146  , m_langUsesSpaces(true)
147  , m_catalog(catalog)
148  , m_part(part)
149  , m_highlighter(new SyntaxHighlighter(this))
150  , m_completionBox(0)
151 {
152  setReadOnly(part==DocPosition::Source);
153  setUndoRedoEnabled(false);
154  setAcceptRichText(false);
155 
156  if (part==DocPosition::Target)
157  {
158  connect (document(), SIGNAL(contentsChange(int,int,int)), this, SLOT(contentsChanged(int,int,int)));
159  connect (this,SIGNAL(cursorPositionChanged()), this, SLOT(emitCursorPositionChanged()));
160  }
161  connect (catalog,SIGNAL(signalFileLoaded()), this, SLOT(fileLoaded()));
162  //connect (Project::instance(),SIGNAL(configChanged()), this, SLOT(projectConfigChanged()));
163 
164  setSpellInterface(new XliffTextEditSpellInterface(m_highlighter));
165  setHighlighter(m_highlighter);
166 }
167 
168 void TranslationUnitTextEdit::fileLoaded()
169 {
170  QString langCode=m_part==DocPosition::Source? m_catalog->sourceLangCode():m_catalog->targetLangCode();
171 
172  QLocale langLocale(langCode);
173  // First try to use a locale name derived from the language code
174  m_highlighter->setCurrentLanguage(langLocale.name());
175  // If that fails, try to use the language code directly
176  if (m_highlighter->currentLanguage().isEmpty()) {
177  m_highlighter->setCurrentLanguage(langCode);
178  }
179 
180  //"i use an english locale while translating kde pot files from english to hebrew" Bug #181989
181  Qt::LayoutDirection targetLanguageDirection=Qt::LeftToRight;
182  static QLocale::Language rtlLanguages[]={QLocale::Arabic, QLocale::Hebrew, QLocale::Urdu, QLocale::Persian, QLocale::Pashto};
183  int i=sizeof(rtlLanguages)/sizeof(QLocale::Arabic);
184  while (--i>=0 && langLocale.language()!=rtlLanguages[i])
185  ;
186  if (i!=-1)
187  targetLanguageDirection=Qt::RightToLeft;
188  setLayoutDirection(targetLanguageDirection);
189 
190  if (m_part==DocPosition::Source)
191  return;
192 
193  //"Some language do not need space between words. For example Chinese."
194  static QLocale::Language noSpaceLanguages[]={QLocale::Chinese};
195  i=sizeof(noSpaceLanguages)/sizeof(QLocale::Chinese);
196  while (--i>=0 && langLocale.language()!=noSpaceLanguages[i])
197  ;
198  m_langUsesSpaces=(i==-1);
199 }
200 
201 void TranslationUnitTextEdit::reflectApprovementState()
202 {
203  if (m_part==DocPosition::Source || m_currentPos.entry==-1)
204  return;
205 
206  bool approved=m_catalog->isApproved(m_currentPos.entry);
207 
208  m_highlighter->setApprovementState(approved);
209  disconnect (document(), SIGNAL(contentsChange(int,int,int)), this, SLOT(contentsChanged(int,int,int)));
210  m_highlighter->rehighlight();
211  connect (document(), SIGNAL(contentsChange(int,int,int)), this, SLOT(contentsChanged(int,int,int)));
212  viewport()->setBackgroundRole(approved?QPalette::Base:QPalette::AlternateBase);
213 
214 
215  if (approved) emit approvedEntryDisplayed();
216  else emit nonApprovedEntryDisplayed();
217 
218  bool untr=m_catalog->isEmpty(m_currentPos);
219  if (untr) emit untranslatedEntryDisplayed();
220  else emit translatedEntryDisplayed();
221 }
222 
223 void TranslationUnitTextEdit::reflectUntranslatedState()
224 {
225  if (m_part==DocPosition::Source || m_currentPos.entry==-1)
226  return;
227 
228  bool untr=m_catalog->isEmpty(m_currentPos);
229  if (untr) emit untranslatedEntryDisplayed();
230  else emit translatedEntryDisplayed();
231 }
232 
233 
237 CatalogString TranslationUnitTextEdit::showPos(DocPosition docPosition, const CatalogString& refStr, bool keepCursor)
238 {
239  docPosition.part=m_part;
240  m_currentPos=docPosition;
241 
242  CatalogString catalogString=m_catalog->catalogString(m_currentPos);
243  QString target=catalogString.string;
244  _oldMsgstr=target;
245  //_oldMsgstrAscii=document()->toPlainText(); <-- MOVED THIS TO THE END
246 
247  //BEGIN pos
248  QTextCursor cursor=textCursor();
249  int pos=cursor.position();
250  int anchor=cursor.anchor();
251  //kWarning()<<"called"<<"pos"<<pos<<anchor<<"keepCursor"<<keepCursor;
252  if (!keepCursor && toPlainText()!=target)
253  {
254  //kWarning()<<"resetting pos";
255  pos=0;
256  anchor=0;
257  }
258  //END pos
259 
260  disconnect (document(), SIGNAL(contentsChange(int,int,int)), this, SLOT(contentsChanged(int,int,int)));
261  if (docPosition.part==DocPosition::Source)
262  setContent(catalogString);
263  else
264  setContent(catalogString,refStr.string.isEmpty()?m_catalog->sourceWithTags(docPosition):refStr);
265  connect (document(), SIGNAL(contentsChange(int,int,int)), this, SLOT(contentsChanged(int,int,int)));
266 
267  _oldMsgstrAscii=document()->toPlainText();
268 
269  //BEGIN pos
270  QTextCursor t=textCursor();
271  t.movePosition(QTextCursor::Start);
272  if (pos || anchor)
273  {
274  //kWarning()<<"setting"<<anchor<<pos;
275  // I don't know why the following (more correct) code does not work
276  t.setPosition(anchor,QTextCursor::MoveAnchor);
277  int length=pos-anchor;
278  if (length)
279  t.movePosition(length<0?QTextCursor::PreviousCharacter:QTextCursor::NextCharacter,QTextCursor::KeepAnchor,qAbs(length));
280  }
281  setTextCursor(t);
282  //kWarning()<<"set?"<<textCursor().anchor()<<textCursor().position();
283  //END pos
284 
285  reflectApprovementState();
286  reflectUntranslatedState();
287  return catalogString; //for the sake of not calling XliffStorage/doContent twice
288 }
289 
290 void TranslationUnitTextEdit::setContent(const CatalogString& catStr, const CatalogString& refStr)
291 {
292  //kWarning()<<"";
293  //kWarning()<<"START";
294  //kWarning()<<str<<ranges.size();
295  //prevent undo tracking system from recording this 'action'
296  document()->blockSignals(true);
297  clear();
298 
299  QTextCursor c=textCursor();
300  insertContent(c,catStr,refStr);
301 
302  document()->blockSignals(false);
303 
304  if (m_part==DocPosition::Target)
305  m_highlighter->setSourceString(refStr.string);
306  else
307  //reflectApprovementState() does this for Target
308  m_highlighter->rehighlight(); //explicitly because we disabled signals
309 }
310 
311 #if 0
312 struct SearchFunctor
313 {
314  virtual int operator()(const QString& str, int startingPos);
315 };
316 
317 int SearchFunctor::operator()(const QString& str, int startingPos)
318 {
319  return str.indexOf(TAGRANGE_IMAGE_SYMBOL, startingPos);
320 }
321 
322 struct AlternativeSearchFunctor: public SearchFunctor
323 {
324  int operator()(const QString& str, int startingPos);
325 };
326 
327 int AlternativeSearchFunctor::operator()(const QString& str, int startingPos)
328 {
329  int tagPos=str.indexOf(TAGRANGE_IMAGE_SYMBOL, startingPos);
330  int diffStartPos=str.indexOf("{KBABEL", startingPos);
331  int diffEndPos=str.indexOf("{/KBABEL", startingPos);
332 
333  int diffPos=qMin(diffStartPos,diffEndPos);
334  if (diffPos==-1)
335  diffPos=qMax(diffStartPos,diffEndPos);
336 
337  int result=qMin(tagPos,diffPos);
338  if (result==-1)
339  result=qMax(tagPos,diffPos);
340  return result;
341 }
342 #endif
343 
344 void insertContent(QTextCursor& cursor, const CatalogString& catStr, const CatalogString& refStr, bool insertText)
345 {
346  //settings for TMView
347  QTextCharFormat chF=cursor.charFormat();
348  QFont font=cursor.document()->defaultFont();
349  //font.setWeight(chF.fontWeight());
350 
351  QMap<int,int> posToTag;
352  int i=catStr.tags.size();
353  //kDebug()<<"size:"<<i;
354  while(--i>=0)
355  {
356  //kDebug()<<"\t"<<catStr.tags.at(i).getElementName()<<catStr.tags.at(i).id<<catStr.tags.at(i).start<<catStr.tags.at(i).end;
357  posToTag.insert(catStr.tags.at(i).start,i);
358  posToTag.insert(catStr.tags.at(i).end,i);
359  }
360 
361  QMap<QString,int> sourceTagIdToIndex=refStr.tagIdToIndex();
362  int refTagIndexOffset=sourceTagIdToIndex.size();
363 
364  i=0;
365  int prev=0;
366  while ((i = catStr.string.indexOf(TAGRANGE_IMAGE_SYMBOL, i)) != -1)
367  {
368 #if 0
369  SearchFunctor nextStopSymbol=AlternativeSearchFunctor();
370  char state='0';
371  while ((i = nextStopSymbol(catStr.string, i)) != -1)
372  {
373  //handle diff display for TMView
374  if (catStr.string.at(i)!=TAGRANGE_IMAGE_SYMBOL)
375  {
376  if (catStr.string.at(i+1)=='/')
377  state='0';
378  else if (catStr.string.at(i+8)=='D')
379  state='-';
380  else
381  state='+';
382  continue;
383  }
384 #endif
385  if (insertText)
386  cursor.insertText(catStr.string.mid(prev,i-prev));
387  else
388  {
389  cursor.movePosition(QTextCursor::NextCharacter,QTextCursor::MoveAnchor,i-prev);
390  cursor.deleteChar();//delete TAGRANGE_IMAGE_SYMBOL to insert it properly
391  }
392 
393  if (!posToTag.contains(i))
394  {
395  prev=++i;
396  continue;
397  }
398  int tagIndex=posToTag.value(i);
399  InlineTag tag=catStr.tags.at(tagIndex);
400  QString name=tag.id;
401  QString text;
402  if (tag.type==InlineTag::mrk)
403  text="*";
404  else if (!tag.equivText.isEmpty())
405  text=tag.equivText; //TODO add number? when? -- right now this is done for gettext qt's 156 mark
406  else
407  text=QString::number(sourceTagIdToIndex.contains(tag.id)?sourceTagIdToIndex.value(tag.id):(tagIndex+refTagIndexOffset));
408  if (tag.start!=tag.end)
409  {
410  //kWarning()<<"b"<<i;
411  if (tag.start==i)
412  {
413  //kWarning()<<"\t\tstart:"<<tag.getElementName()<<tag.id<<tag.start;
414  text.append(" {");
415  name.append("-start");
416  }
417  else
418  {
419  //kWarning()<<"\t\tend:"<<tag.getElementName()<<tag.id<<tag.end;
420  text.prepend("} ");
421  name.append("-end");
422  }
423  }
424  if (cursor.document()->resource(QTextDocument::ImageResource, QUrl(name)).isNull())
425  cursor.document()->addResource(QTextDocument::ImageResource, QUrl(name), generateImage(text,font));
426  cursor.insertImage(name);//NOTE what if twice the same name?
427  cursor.setCharFormat(chF);
428 
429  prev=++i;
430  }
431  cursor.insertText(catStr.string.mid(prev));
432 }
433 
434 
435 
436 void TranslationUnitTextEdit::contentsChanged(int offset, int charsRemoved, int charsAdded)
437 {
438  //kWarning()<<"contentsChanged. offset"<<offset<<"charsRemoved"<<charsRemoved<<"charsAdded"<<charsAdded<<"_oldMsgstr"<<_oldMsgstr;
439  //HACK to workaround #218246
440  const QString& editTextAscii=document()->toPlainText();
441  if (editTextAscii==_oldMsgstrAscii)
442  {
443  //kWarning()<<"stopping"<<editTextAscii<<_oldMsgstrAscii;
444  return;
445  }
446 
447 
448 
449  const QString& editText=toPlainText();
450  if (KDE_ISUNLIKELY( m_currentPos.entry==-1 || editText==_oldMsgstr ))
451  {
452  //kWarning()<<"stopping"<<m_currentPos.entry<<editText<<_oldMsgstr;
453  return;
454  }
455 
456  //ktextedit spellcheck handling:
457  if (charsRemoved==0 && editText.isEmpty() && _oldMsgstr.length())
458  charsRemoved=_oldMsgstr.length();
459  if (charsAdded && editText.isEmpty())
460  charsAdded=0;
461  if (charsRemoved && _oldMsgstr.isEmpty())
462  charsRemoved=0;
463 
464  DocPosition pos=m_currentPos;
465  pos.offset=offset;
466  //kWarning()<<"offset"<<offset<<"charsRemoved"<<charsRemoved<<"_oldMsgstr"<<_oldMsgstr;
467 
468  QString target=m_catalog->targetWithTags(pos).string;
469  const QString& addedText=editText.mid(offset,charsAdded);
470 
471 //BEGIN XLIFF markup handling
472  //protect from tag removal
473  //TODO use midRef when Qt 4.8 is in distros
474  bool markupRemoved=charsRemoved && QString::fromRawData(target.unicode()+offset,charsRemoved).contains(TAGRANGE_IMAGE_SYMBOL);
475  bool markupAdded=charsAdded && addedText.contains(TAGRANGE_IMAGE_SYMBOL);
476  if (markupRemoved || markupAdded)
477  {
478  bool modified=false;
479  CatalogString targetWithTags=m_catalog->targetWithTags(m_currentPos);
480  //special case when the user presses Del w/o selection
481  if (!charsAdded && charsRemoved==1)
482  {
483  int i=targetWithTags.tags.size();
484  while(--i>=0)
485  {
486  if (targetWithTags.tags.at(i).start==offset || targetWithTags.tags.at(i).end==offset)
487  {
488  modified=true;
489  pos.offset=targetWithTags.tags.at(i).start;
490  m_catalog->push(new DelTagCmd(m_catalog,pos));
491  }
492  }
493  }
494  else if (!markupAdded) //check if all { plus } tags were selected
495  {
496  modified=removeTargetSubstring(offset, charsRemoved, /*refresh*/false);
497  if (modified&&charsAdded)
498  m_catalog->push(new InsTextCmd(m_catalog,pos,addedText));
499  }
500 
501  //kWarning()<<"calling showPos";
502  showPos(m_currentPos,CatalogString(),/*keepCursor*/true);
503  if (!modified)
504  {
505  //kWarning()<<"stop";
506  return;
507  }
508  }
509 //END XLIFF markup handling
510  else
511  {
512  if (charsRemoved)
513  m_catalog->push(new DelTextCmd(m_catalog,pos,_oldMsgstr.mid(offset,charsRemoved)));
514 
515  _oldMsgstr=editText;//newStr becomes OldStr
516  _oldMsgstrAscii=editTextAscii;
517  //kWarning()<<"char"<<editText[offset].unicode();
518  if (charsAdded)
519  m_catalog->push(new InsTextCmd(m_catalog,pos,addedText));
520 
521  }
522 
523 /* TODO
524  if (_leds)
525  {
526  if (m_catalog->msgstr(pos).isEmpty()) _leds->ledUntr->on();
527  else _leds->ledUntr->off();
528  }
529 */
530  requestToggleApprovement();
531  reflectUntranslatedState();
532 
533  // for mergecatalog (remove entry from index)
534  // and for statusbar
535  emit contentsModified(m_currentPos);
536 
537  if (charsAdded==1)
538  {
539  int sp=target.lastIndexOf(CompletionStorage::instance()->rxSplit,offset-1);
540  int len=(offset-sp);
541  int wordCompletionLength=Settings::self()->wordCompletionLength();
542  if (wordCompletionLength>=3 && len>=wordCompletionLength)
543  doCompletion(offset+1);
544  else if (m_completionBox)
545  m_completionBox->hide();
546  }
547  else if (m_completionBox)
548  m_completionBox->hide();
549 
550  //kWarning()<<"finish";
551 }
552 
553 
554 bool TranslationUnitTextEdit::removeTargetSubstring(int delStart, int delLen, bool refresh)
555 {
556  if (KDE_ISUNLIKELY( m_currentPos.entry==-1 ))
557  return false;
558 
559  if (!::removeTargetSubstring(m_catalog, m_currentPos, delStart, delLen))
560  return false;
561 
562  requestToggleApprovement();
563 
564  if (refresh)
565  {
566  //kWarning()<<"calling showPos";
567  showPos(m_currentPos,CatalogString(),/*keepCursor*/true/*false*/);
568  }
569  emit contentsModified(m_currentPos.entry);
570  return true;
571 }
572 
573 void TranslationUnitTextEdit::insertCatalogString(CatalogString catStr, int start, bool refresh)
574 {
575  CatalogString source=m_catalog->sourceWithTags(m_currentPos);
576  CatalogString target=m_catalog->targetWithTags(m_currentPos);
577 
578 
579  QHash<QString,int> id2tagIndex;
580  int i=source.tags.size();
581  while(--i>=0)
582  id2tagIndex.insert(source.tags.at(i).id,i);
583 
584  foreach(const InlineTag& tag, target.tags)
585  {
586  if (id2tagIndex.contains(tag.id))
587  source.tags[id2tagIndex.value(target.tags.at(i).id)].id="REMOVEME";
588  }
589 
590  //iterating from the end is essential
591  i=source.tags.size();
592  while(--i>=0)
593  if (source.tags.at(i).id=="REMOVEME")
594  source.tags.removeAt(i);
595 
596 
597  adaptCatalogString(catStr,source);
598 
599  ::insertCatalogString(m_catalog,m_currentPos,catStr,start);
600 
601  if (refresh)
602  {
603  //kWarning()<<"calling showPos";
604  showPos(m_currentPos,CatalogString(),/*keepCursor*/true/*false*/);
605  QTextCursor cursor=textCursor();
606  cursor.movePosition(QTextCursor::NextCharacter,QTextCursor::MoveAnchor,catStr.string.size());
607  setTextCursor(cursor);
608  }
609 }
610 
611 
612 
613 QMimeData* TranslationUnitTextEdit::createMimeDataFromSelection() const
614 {
615  QMimeData *mimeData = new QMimeData;
616 
617  CatalogString catalogString=m_catalog->catalogString(m_currentPos);
618 
619  QTextCursor cursor=textCursor();
620  int start=qMin(cursor.anchor(),cursor.position());
621  int end=qMax(cursor.anchor(),cursor.position());
622 
623  QMap<int,int> tagPlaces;
624  if (fillTagPlaces(tagPlaces,catalogString,start,end-start))
625  {
626  //transform CatalogString
627  //TODO substring method
628  catalogString.string=catalogString.string.mid(start,end-start);
629 
630  QList<InlineTag>::iterator it=catalogString.tags.begin();
631  while (it != catalogString.tags.end())
632  {
633  if (!tagPlaces.contains(it->start))
634  it=catalogString.tags.erase(it);
635  else
636  {
637  it->start-=start;
638  it->end-=start;
639  ++it;
640  }
641  }
642 
643  QByteArray a;
644  QDataStream out(&a,QIODevice::WriteOnly);
645  QVariant v;
646  qVariantSetValue<CatalogString>(v,catalogString);
647  out<<v;
648  mimeData->setData("application/x-lokalize-xliff+xml",a);
649  }
650 
651  QString text=catalogString.string;
652  text.remove(TAGRANGE_IMAGE_SYMBOL);
653  mimeData->setText(text);
654  return mimeData;
655 }
656 
657 void TranslationUnitTextEdit::insertFromMimeData(const QMimeData* source)
658 {
659  if (m_part==DocPosition::Source)
660  return;
661 
662  if (source->hasFormat("application/x-lokalize-xliff+xml"))
663  {
664  //kWarning()<<"has";
665  QVariant v;
666  QByteArray data=source->data("application/x-lokalize-xliff+xml");
667  QDataStream in(&data,QIODevice::ReadOnly);
668  in>>v;
669  //qWarning()<<"ins"<<qVariantValue<CatalogString>(v).string<<qVariantValue<CatalogString>(v).ranges.size();
670 
671  int start=0;
672  m_catalog->beginMacro(i18nc("@item Undo action item","Insert text with markup"));
673  QTextCursor cursor=textCursor();
674  if (cursor.hasSelection())
675  {
676  start=qMin(cursor.anchor(),cursor.position());
677  int end=qMax(cursor.anchor(),cursor.position());
678  removeTargetSubstring(start,end-start);
679  cursor.setPosition(start);
680  setTextCursor(cursor);
681  }
682  else
683  //sets right cursor position implicitly -- needed for mouse paste
684  {
685  QMimeData mimeData;
686  mimeData.setText("");
687  KTextEdit::insertFromMimeData(&mimeData);
688  start=textCursor().position();
689  }
690 
691  insertCatalogString(qVariantValue<CatalogString>(v), start);
692  m_catalog->endMacro();
693  }
694  else
695  {
696  QString text=source->text();
697  text.remove(TAGRANGE_IMAGE_SYMBOL);
698  insertPlainText(text);
699  }
700 }
701 
702 
703 
704 
705 
706 
707 
708 
709 
710 
711 
712 
713 
714 
715 
716 
717 
718 
719 static bool isMasked(const QString& str, uint col)
720 {
721  if(col == 0 || str.isEmpty())
722  return false;
723 
724  uint counter=0;
725  int pos=col;
726 
727  while(pos >= 0 && str.at(pos) == '\\')
728  {
729  counter++;
730  pos--;
731  }
732 
733  return !(bool)(counter%2);
734 }
735 
736 static QString spclChars("abfnrtv'?\\");
737 
738 void TranslationUnitTextEdit::keyPressEvent(QKeyEvent *keyEvent)
739 {
740  if(keyEvent->matches(QKeySequence::MoveToPreviousPage))
741  emit gotoPrevRequested();
742  else if(keyEvent->matches(QKeySequence::MoveToNextPage))
743  emit gotoNextRequested();
744  else if(keyEvent->matches(QKeySequence::Undo))
745  emit undoRequested();
746  else if(keyEvent->matches(QKeySequence::Redo))
747  emit redoRequested();
748  else if(keyEvent->matches(QKeySequence::Find))
749  emit findRequested();
750  else if(keyEvent->matches(QKeySequence::FindNext))
751  emit findNextRequested();
752  else if(keyEvent->matches(QKeySequence::Replace))
753  emit replaceRequested();
754  else if (keyEvent->modifiers() == (Qt::AltModifier|Qt::ControlModifier))
755  {
756  if(keyEvent->key()==Qt::Key_Home)
757  emit gotoFirstRequested();
758  else if(keyEvent->key()==Qt::Key_End)
759  emit gotoLastRequested();
760  }
761  else if (m_part==DocPosition::Source)
762  return KTextEdit::keyPressEvent(keyEvent);
763 
764  //BEGIN GENERAL
765  // ALT+123 feature TODO this is general so should be on another level
766  else if( (keyEvent->modifiers()&Qt::AltModifier)
767  &&!keyEvent->text().isEmpty()
768  &&keyEvent->text().at(0).isDigit() )
769  {
770  QString text=keyEvent->text();
771  while (!text.isEmpty()&& text.at(0).isDigit() )
772  {
773  m_currentUnicodeNumber = 10*m_currentUnicodeNumber+(text.at(0).digitValue());
774  text.remove(0,1);
775  }
776  KTextEdit::keyPressEvent(keyEvent);
777  }
778  //END GENERAL
779 
780  else if (!keyEvent->modifiers()&&(keyEvent->key()==Qt::Key_Backspace||keyEvent->key()==Qt::Key_Delete))
781  {
782  //only for cases when:
783  //-BkSpace was hit and cursor was atStart
784  //-Del was hit and cursor was atEnd
785  if (KDE_ISUNLIKELY( !m_catalog->isApproved(m_currentPos.entry) && !textCursor().hasSelection() )
786  && ((textCursor().atStart()&&keyEvent->key()==Qt::Key_Backspace)
787  ||(textCursor().atEnd()&&keyEvent->key()==Qt::Key_Delete) ))
788  requestToggleApprovement();
789  else
790  KTextEdit::keyPressEvent(keyEvent);
791  }
792  else if( keyEvent->key() == Qt::Key_Space && (keyEvent->modifiers()&Qt::AltModifier) )
793  insertPlainText(QChar(0x00a0U));
794  else if( keyEvent->key() == Qt::Key_Minus && (keyEvent->modifiers()&Qt::AltModifier) )
795  insertPlainText(QChar(0x0000AD));
796  else if (m_catalog->mimetype()!="text/x-gettext-translation")
797  KTextEdit::keyPressEvent(keyEvent);
798  //clever editing
799  else if(keyEvent->key()==Qt::Key_Return||keyEvent->key()==Qt::Key_Enter)
800  {
801  if (m_completionBox&&m_completionBox->isVisible())
802  {
803  if (m_completionBox->currentItem())
804  completionActivated(m_completionBox->currentItem()->text());
805  else
806  kWarning()<<"avoided a crash. a case for bug 238835!";
807  m_completionBox->hide();
808  return;
809  }
810  QString str=toPlainText();
811  QTextCursor t=textCursor();
812  int pos=t.position();
813  QString ins;
814  if( keyEvent->modifiers()&Qt::ShiftModifier )
815  {
816  if(pos>0
817  &&!str.isEmpty()
818  &&str.at(pos-1)=='\\'
819  &&!isMasked(str,pos-1))
820  {
821  ins='n';
822  }
823  else
824  {
825  ins="\\n";
826  }
827  }
828  else if(!(keyEvent->modifiers()&Qt::ControlModifier))
829  {
830  if(m_langUsesSpaces
831  &&pos>0
832  &&!str.isEmpty()
833  &&!str.at(pos-1).isSpace())
834  {
835  if(str.at(pos-1)=='\\'
836  &&!isMasked(str,pos-1))
837  ins='\\';
838  // if there is no new line at the end
839  if(pos<2||str.midRef(pos-2,2)!="\\n")
840  ins+=' ';
841  }
842  else if(str.isEmpty())
843  {
844  ins="\\n";
845  }
846  }
847  if (!str.isEmpty())
848  {
849  ins+='\n';
850  insertPlainText(ins);
851  }
852  else
853  KTextEdit::keyPressEvent(keyEvent);
854  }
855  else if( (keyEvent->modifiers()&Qt::ControlModifier)?
856  (keyEvent->key()==Qt::Key_D) :
857  (keyEvent->key()==Qt::Key_Delete)
858  && textCursor().atEnd())
859  {
860  kWarning()<<"workaround for Qt/X11 bug";
861  QTextCursor t=textCursor();
862  if(!t.hasSelection())
863  {
864  int pos=t.position();
865  QString str=toPlainText();
866  //workaround for Qt/X11 bug: if Del on NumPad is pressed, then pos is beyond end
867  if (pos==str.size()) --pos;
868  if(!str.isEmpty()
869  &&str.at(pos) == '\\'
870  &&!isMasked(str,pos)
871  &&pos<str.length()-1
872  &&spclChars.contains(str.at(pos+1)))
873  {
874  t.deleteChar();
875  }
876  }
877 
878  t.deleteChar();
879  setTextCursor(t);
880  }
881  else if( (!keyEvent->modifiers()&&keyEvent->key()==Qt::Key_Backspace)
882  || ( ( keyEvent->modifiers() & Qt::ControlModifier ) && keyEvent->key() == Qt::Key_H ) )
883  {
884  QTextCursor t=textCursor();
885  if(!t.hasSelection())
886  {
887  int pos=t.position();
888  QString str=toPlainText();
889  if(!str.isEmpty() && pos>0 && spclChars.contains(str.at(pos-1)))
890  {
891  if(pos>1 && str.at(pos-2)=='\\' && !isMasked(str,pos-2))
892  {
893  t.deletePreviousChar();
894  t.deletePreviousChar();
895  setTextCursor(t);
896  //kWarning()<<"set-->"<<textCursor().anchor()<<textCursor().position();
897  }
898  }
899 
900  }
901  KTextEdit::keyPressEvent(keyEvent);
902  }
903  else if(keyEvent->key() == Qt::Key_Tab)
904  insertPlainText("\\t");
905  else
906  KTextEdit::keyPressEvent(keyEvent);
907 }
908 
909 void TranslationUnitTextEdit::keyReleaseEvent(QKeyEvent* e)
910 {
911  if ( (e->key()==Qt::Key_Alt) && m_currentUnicodeNumber >= 32 )
912  {
913  insertPlainText(QChar( m_currentUnicodeNumber ));
914  m_currentUnicodeNumber=0;
915  }
916  else
917  KTextEdit::keyReleaseEvent(e);
918 }
919 
920 QString TranslationUnitTextEdit::toPlainText()
921 {
922  QTextCursor cursor = textCursor();
923  cursor.select(QTextCursor::Document);
924  QString text=cursor.selectedText();
925  text.replace(QChar(8233),'\n');
926 /*
927  int ii=text.size();
928  while(--ii>=0)
929  kWarning()<<text.at(ii).unicode();
930 */
931  return text;
932 }
933 
934 
935 
936 void TranslationUnitTextEdit::emitCursorPositionChanged()
937 {
938  emit cursorPositionChanged(textCursor().columnNumber());
939 }
940 
941 void TranslationUnitTextEdit::insertTag(InlineTag tag)
942 {
943  QTextCursor cursor=textCursor();
944  tag.start=qMin(cursor.anchor(),cursor.position());
945  tag.end=qMax(cursor.anchor(),cursor.position())+tag.isPaired();
946  kWarning()<<(m_part==DocPosition::Source)<<tag.start<<tag.end;
947  m_catalog->push(new InsTagCmd(m_catalog,currentPos(),tag));
948  showPos(currentPos(),CatalogString(),/*keepCursor*/true);
949  cursor.movePosition(QTextCursor::NextCharacter,QTextCursor::MoveAnchor,tag.end+1+tag.isPaired());
950  setFocus();
951 }
952 
953 int TranslationUnitTextEdit::strForMicePosIfUnderTag(QPoint mice, CatalogString& str, bool tryHarder)
954 {
955  QTextCursor cursor=cursorForPosition(mice);
956  int pos=cursor.position();
957  str=m_catalog->catalogString(m_currentPos);
958  if (pos==-1 || pos>=str.string.size()) return -1;
959  //kWarning()<<"here1"<<str.string.at(pos)<<str.string.at(pos-1)<<str.string.at(pos+1);
960 
961 
962 // if (pos>0)
963 // {
964 // cursor.movePosition(QTextCursor::Left);
965 // mice.setX(mice.x()+cursorRect(cursor).width()/2);
966 // pos=cursorForPosition(mice).position();
967 // }
968 
969  if (str.string.at(pos)!=TAGRANGE_IMAGE_SYMBOL)
970  {
971  bool cont=tryHarder && --pos>=0 && str.string.at(pos)==TAGRANGE_IMAGE_SYMBOL;
972  if (!cont)
973  return -1;
974  }
975 
976  int result=str.tags.size();
977  while(--result>=0 && str.tags.at(result).start!=pos && str.tags.at(result).end!=pos)
978  ;
979  return result;
980 }
981 
982 void TranslationUnitTextEdit::mouseReleaseEvent(QMouseEvent* event)
983 {
984  if (event->button()==Qt::LeftButton)
985  {
986  CatalogString str;
987  int pos=strForMicePosIfUnderTag(event->pos(),str);
988  if (pos!=-1 && m_part==DocPosition::Source)
989  {
990  emit tagInsertRequested(str.tags.at(pos));
991  event->accept();
992  return;
993  }
994  }
995  KTextEdit::mouseReleaseEvent(event);
996 }
997 
998 
999 void TranslationUnitTextEdit::contextMenuEvent(QContextMenuEvent *event)
1000 {
1001  CatalogString str;
1002  int pos=strForMicePosIfUnderTag(event->pos(),str);
1003  if (pos!=-1)
1004  {
1005  QString xid=str.tags.at(pos).xid;
1006 
1007  if (!xid.isEmpty())
1008  {
1009  QMenu menu;
1010  int entry=m_catalog->unitById(xid);
1011  /* QAction* findUnit=menu.addAction(entry>=m_catalog->numberOfEntries()?
1012  i18nc("@action:inmenu","Show the binary unit"):
1013  i18nc("@action:inmenu","Go to the referenced entry")); */
1014 
1015  QAction* result=menu.exec(event->globalPos());
1016  if (result)
1017  {
1018  kWarning()<<entry<<xid;
1019  if (entry>=m_catalog->numberOfEntries())
1020  emit binaryUnitSelectRequested(xid);
1021  else
1022  emit gotoEntryRequested(DocPosition(entry));
1023  event->accept();
1024  }
1025  return;
1026  }
1027  }
1028  if (textCursor().hasSelection())
1029  {
1030  QMenu menu;
1031  // QAction* lookup=menu.addAction(i18nc("@action:inmenu","Lookup selected text in translation memory"));
1032  if (menu.exec(event->globalPos()))
1033  emit tmLookupRequested(m_part,textCursor().selectedText());
1034  return;
1035  }
1036 
1037  if (m_part!=DocPosition::Target)
1038  return;
1039 
1040  KTextEdit::contextMenuEvent(event);
1041 
1042 #if 0
1043  QTextCursor wordSelectCursor=cursorForPosition(event->pos());
1044  wordSelectCursor.select(QTextCursor::WordUnderCursor);
1045  if (m_highlighter->isWordMisspelled(wordSelectCursor.selectedText()))
1046  {
1047  QMenu menu;
1048  QMenu suggestions;
1049  foreach(const QString& s, m_highlighter->suggestionsForWord(wordSelectCursor.selectedText()))
1050  suggestions.addAction(s);
1051  if (!suggestions.isEmpty())
1052  {
1053  QAction* answer=suggestions.exec(event->globalPos());
1054  if (answer)
1055  {
1056  m_catalog->beginMacro(i18nc("@item Undo action item","Replace text"));
1057  wordSelectCursor.insertText(answer->text());
1058  m_catalog->endMacro();
1059  }
1060  }
1061  }
1062 #endif
1063 
1064 // QMenu menu;
1065 // QAction* spellchecking=menu.addAction();
1066 // event->accept();
1067 }
1068 
1069 void TranslationUnitTextEdit::wheelEvent(QWheelEvent *event)
1070 {
1071  if (m_part==DocPosition::Source || !Settings::mouseWheelGo())
1072  return KTextEdit::wheelEvent(event);
1073 
1074  switch (event->modifiers())
1075  {
1076  case Qt::ControlModifier:
1077  if (event->delta() > 0)
1078  emit gotoPrevFuzzyRequested();
1079  else
1080  emit gotoNextFuzzyRequested();
1081  break;
1082  case Qt::AltModifier:
1083  if (event->delta() > 0)
1084  emit gotoPrevUntranslatedRequested();
1085  else
1086  emit gotoNextUntranslatedRequested();
1087  break;
1088  case Qt::ControlModifier + Qt::ShiftModifier:
1089  if (event->delta() > 0)
1090  emit gotoPrevFuzzyUntrRequested();
1091  else
1092  emit gotoNextFuzzyUntrRequested();
1093  break;
1094  case Qt::ShiftModifier:
1095  return KTextEdit::wheelEvent(event);
1096  default:
1097  if (event->delta() > 0)
1098  emit gotoPrevRequested();
1099  else
1100  emit gotoNextRequested();
1101  }
1102 }
1103 
1104 void TranslationUnitTextEdit::spellReplace()
1105 {
1106  QTextCursor wordSelectCursor=textCursor();
1107  wordSelectCursor.select(QTextCursor::WordUnderCursor);
1108  if (!m_highlighter->isWordMisspelled(wordSelectCursor.selectedText()))
1109  return;
1110 
1111  const QStringList& suggestions=m_highlighter->suggestionsForWord(wordSelectCursor.selectedText());
1112  if (suggestions.isEmpty())
1113  return;
1114 
1115  m_catalog->beginMacro(i18nc("@item Undo action item","Replace text"));
1116  wordSelectCursor.insertText(suggestions.first());
1117  m_catalog->endMacro();
1118 }
1119 
1120 bool TranslationUnitTextEdit::event(QEvent *event)
1121 {
1122  if (event->type()==QEvent::ToolTip)
1123  {
1124  QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
1125  CatalogString str;
1126  int pos=strForMicePosIfUnderTag(helpEvent->pos(),str,true);
1127  if (pos!=-1)
1128  {
1129  QString tooltip=str.tags.at(pos).displayName();
1130  QToolTip::showText(helpEvent->globalPos(),tooltip);
1131  return true;
1132  }
1133 
1134  QString langCode=m_highlighter->currentLanguage();
1135  bool nospell=langCode.isEmpty();
1136  if (nospell)
1137  langCode=m_part==DocPosition::Source?m_catalog->sourceLangCode():m_catalog->targetLangCode();
1138  QString tip=KGlobal::locale()->languageCodeToName(langCode)%" ("%langCode%")";
1139  if (nospell)
1140  tip+=" - "%i18n("no spellcheck available");
1141  QToolTip::showText(helpEvent->globalPos(), tip);
1142  }
1143  return KTextEdit::event(event);
1144 }
1145 
1146 
1147 
1148 void TranslationUnitTextEdit::tagMenu() {doTag(false);}
1149 void TranslationUnitTextEdit::tagImmediate(){doTag(true);}
1150 
1151 void TranslationUnitTextEdit::doTag(bool immediate)
1152 {
1153  QMenu menu;
1154  QAction* txt=0;
1155 
1156  CatalogString sourceWithTags=m_catalog->sourceWithTags(m_currentPos);
1157  int count=sourceWithTags.tags.size();
1158  if (count)
1159  {
1160  QMap<QString,int> tagIdToIndex=m_catalog->targetWithTags(m_currentPos).tagIdToIndex();
1161  bool hasActive=false;
1162  for (int i=0;i<count;++i)
1163  {
1164  //txt=menu.addAction(sourceWithTags.ranges.at(i));
1165  txt=menu.addAction(QString::number(i)/*+" "+sourceWithTags.ranges.at(i).id*/);
1166  txt->setData(QVariant(i));
1167  if (!hasActive && !tagIdToIndex.contains(sourceWithTags.tags.at(i).id))
1168  {
1169  if (immediate)
1170  {
1171  insertTag(sourceWithTags.tags.at(txt->data().toInt()));
1172  return;
1173  }
1174  hasActive=true;
1175  menu.setActiveAction(txt);
1176  }
1177  }
1178  if (immediate) return;
1179  txt=menu.exec(mapToGlobal(cursorRect().bottomRight()));
1180  if (!txt) return;
1181  insertTag(sourceWithTags.tags.at(txt->data().toInt()));
1182  }
1183  else
1184  {
1185  if (KDE_ISUNLIKELY( Project::instance()->markup().isEmpty() ))
1186  return;
1187 
1188  //QRegExp tag("(<[^>]*>)+|\\&\\w+\\;");
1189  QRegExp tag(Project::instance()->markup());
1190  tag.setMinimal(true);
1191  QString en=m_catalog->sourceWithTags(m_currentPos).string;
1192  QString target(toPlainText());
1193  en.remove('\n');
1194  target.remove('\n');
1195  int pos=0;
1196  //tag.indexIn(en);
1197  int posInMsgStr=0;
1198  while ((pos=tag.indexIn(en,pos))!=-1)
1199  {
1200  /* QString str(tag.cap(0));
1201  str.replace("&","&&");*/
1202  txt=menu.addAction(tag.cap(0));
1203  pos+=tag.matchedLength();
1204 
1205  if (posInMsgStr!=-1 && (posInMsgStr=target.indexOf(tag.cap(0),posInMsgStr))==-1)
1206  {
1207  if (immediate)
1208  {
1209  insertPlainText(txt->text());
1210  return;
1211  }
1212  menu.setActiveAction(txt);
1213  } else if (posInMsgStr!=-1)
1214  posInMsgStr+=tag.matchedLength();
1215  }
1216  if (!txt || immediate)
1217  return;
1218 
1219  //txt=menu.exec(_msgidEdit->mapToGlobal(QPoint(0,0)));
1220  txt=menu.exec(mapToGlobal(cursorRect().bottomRight()));
1221  if (txt)
1222  insertPlainText(txt->text());
1223  }
1224 }
1225 
1226 
1227 void TranslationUnitTextEdit::source2target()
1228 {
1229  CatalogString sourceWithTags=m_catalog->sourceWithTags(m_currentPos);
1230  QString text=sourceWithTags.string;
1231  QString out;
1232  QString ctxt=m_catalog->context(m_currentPos.entry).first();
1233  QRegExp delimiter("\\s*,\\s*");
1234 
1235  //TODO ask for the fillment if the first time.
1236  //BEGIN KDE specific part
1237  if( ctxt.startsWith( "NAME OF TRANSLATORS" ) || text.startsWith( "_: NAME OF TRANSLATORS\\n" ))
1238  {
1239  if (!document()->toPlainText().split(delimiter).contains(Settings::authorLocalizedName())) {
1240  if (!document()->isEmpty())
1241  out=", ";
1242  out+=Settings::authorLocalizedName();
1243  }
1244  }
1245  else if( ctxt.startsWith( "EMAIL OF TRANSLATORS" ) || text.startsWith( "_: EMAIL OF TRANSLATORS\\n" )) {
1246  if (!document()->toPlainText().split(delimiter).contains(Settings::authorEmail())) {
1247  if (!document()->isEmpty())
1248  out=", ";
1249  out+=Settings::authorEmail();
1250  }
1251  }
1252  else if( /*_catalog->isGeneratedFromDocbook() &&*/ text.startsWith( "ROLES_OF_TRANSLATORS" ) )
1253  {
1254  if (!document()->isEmpty())
1255  out='\n';
1256  out+="<othercredit role=\\\"translator\\\">\n"
1257  "<firstname></firstname><surname></surname>\n"
1258  "<affiliation><address><email>"+Settings::authorEmail()+"</email></address>\n"
1259  "</affiliation><contrib></contrib></othercredit>";
1260  }
1261  else if( text.startsWith( "CREDIT_FOR_TRANSLATORS" ) )
1262  {
1263  if (!document()->isEmpty())
1264  out='\n';
1265  out+="<para>"+Settings::authorLocalizedName()+'\n'+
1266  "<email>"+Settings::authorEmail()+"</email></para>";
1267  }
1268  //END KDE specific part
1269 
1270  else {
1271  m_catalog->beginMacro(i18nc("@item Undo action item","Copy source to target"));
1272  removeTargetSubstring(0,-1,/*refresh*/false);
1273  insertCatalogString(sourceWithTags,0,/*refresh*/false);
1274  m_catalog->endMacro();
1275 
1276  showPos(m_currentPos,sourceWithTags,/*keepCursor*/false);
1277 
1278  requestToggleApprovement();
1279  }
1280  if (!out.isEmpty()) {
1281  QTextCursor t=textCursor();
1282  t.movePosition(QTextCursor::End);
1283  t.insertText(out);
1284  setTextCursor(t);
1285  }
1286 }
1287 
1288 void TranslationUnitTextEdit::requestToggleApprovement()
1289 {
1290  if (m_catalog->isApproved(m_currentPos.entry)||!Settings::autoApprove())
1291  return;
1292 
1293  bool skip=m_catalog->isPlural(m_currentPos);
1294  if (skip)
1295  {
1296  skip=false;
1297  DocPos pos(m_currentPos);
1298  for (pos.form=0;pos.form<m_catalog->numberOfPluralForms();++(pos.form))
1299  skip=skip||!m_catalog->isModified(pos);
1300  }
1301  if (!skip)
1302  emit toggleApprovementRequested();
1303 }
1304 
1305 
1306 void TranslationUnitTextEdit::cursorToStart()
1307 {
1308  QTextCursor t=textCursor();
1309  t.movePosition(QTextCursor::Start);
1310  setTextCursor(t);
1311 }
1312 
1313 
1314 void TranslationUnitTextEdit::doCompletion(int pos)
1315 {
1316  QTime a;a.start();
1317  QString target=m_catalog->targetWithTags(m_currentPos).string;
1318  int sp=target.lastIndexOf(CompletionStorage::instance()->rxSplit,pos-1);
1319  int len=(pos-sp)-1;
1320 
1321  QStringList s=CompletionStorage::instance()->makeCompletion(QString::fromRawData(target.unicode()+sp+1,len));
1322 
1323  if (!m_completionBox)
1324  {
1325 //BEGIN creation
1326  m_completionBox=new MyCompletionBox(this);
1327  connect(m_completionBox,SIGNAL(activated(QString)),this,SLOT(completionActivated(QString)));
1328  m_completionBox->setSizePolicy(QSizePolicy::Maximum,QSizePolicy::Preferred);
1329 //END creation
1330  }
1331  m_completionBox->setItems(s);
1332  if (s.size() && !s.first().isEmpty())
1333  {
1334  m_completionBox->setCurrentRow(0);
1335  //qApp->removeEventFilter( m_completionBox );
1336  if (!m_completionBox->isVisible()) //NOTE remove the ckeck if kdelibs gets adapted
1337  m_completionBox->show();
1338  m_completionBox->resize(m_completionBox->sizeHint());
1339  m_completionBox->move(viewport()->mapToGlobal(cursorRect().bottomRight()));
1340  }
1341  else
1342  m_completionBox->hide();
1343  kDebug()<<"hits generated in"<<a.elapsed()<<"msecs";
1344 }
1345 
1346 void TranslationUnitTextEdit::doExplicitCompletion()
1347 {
1348  doCompletion(textCursor().anchor());
1349 }
1350 
1351 void TranslationUnitTextEdit::completionActivated(const QString& semiWord)
1352 {
1353  QTextCursor cursor=textCursor();
1354  cursor.insertText(semiWord);
1355  setTextCursor(cursor);
1356 }
1357 
1358 #include "xlifftextedit.moc"
Catalog::context
QStringList context(const DocPosition &pos) const
Definition: catalog.cpp:322
QTextCursor::position
int position() const
QAction::text
text
SyntaxHighlighter::setApprovementState
void setApprovementState(bool a)
Definition: syntaxhighlighter.h:45
TranslationUnitTextEdit::contextMenuEvent
void contextMenuEvent(QContextMenuEvent *event)
Definition: xlifftextedit.cpp:999
CompletionStorage::makeCompletion
QStringList makeCompletion(const QString &) const
Definition: completionstorage.cpp:80
DelTagCmd
TagRange is filled from document.
Definition: cmd.h:149
DocPosition::part
Part part
Definition: pos.h:49
QString::indexOf
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
QEvent
project.h
QWidget
QKeyEvent::modifiers
Qt::KeyboardModifiers modifiers() const
TranslationUnitTextEdit::reflectApprovementState
void reflectApprovementState()
Definition: xlifftextedit.cpp:201
Catalog::targetWithTags
CatalogString targetWithTags(const DocPosition &pos) const
Definition: catalog.cpp:211
QString::append
QString & append(QChar ch)
QEvent::type
Type type() const
TranslationUnitTextEdit::spellReplace
void spellReplace()
Definition: xlifftextedit.cpp:1104
QHash::insert
iterator insert(const Key &key, const T &value)
QMimeData::data
QByteArray data(const QString &mimeType) const
QTextCursor
QMap::contains
bool contains(const Key &key) const
InlineTag::isPaired
static bool isPaired(InlineElement type)
Definition: catalogstring.h:105
TranslationUnitTextEdit::removeTargetSubstring
bool removeTargetSubstring(int start=0, int end=-1, bool refresh=true)
Definition: xlifftextedit.cpp:554
InsTextCmd
how undo system works: undo() and redo() functions call appropriate private method of Catalog to chan...
Definition: cmd.h:85
TranslationUnitTextEdit::wheelEvent
void wheelEvent(QWheelEvent *event)
Definition: xlifftextedit.cpp:1069
Catalog::targetLangCode
QString targetLangCode() const
Definition: catalog.cpp:474
TranslationUnitTextEdit::toggleApprovementRequested
void toggleApprovementRequested()
QTextCursor::charFormat
QTextCharFormat charFormat() const
Catalog::numberOfPluralForms
int numberOfPluralForms() const
Definition: catalog.h:150
QTextCursor::deletePreviousChar
void deletePreviousChar()
QByteArray
DocPosition::Target
Definition: pos.h:44
TAGRANGE_IMAGE_SYMBOL
#define TAGRANGE_IMAGE_SYMBOL
Definition: catalogstring.h:33
DocPosition::Part
Part
Definition: pos.h:40
QUndoStack::beginMacro
void beginMacro(const QString &text)
QTextDocument::resource
QVariant resource(int type, const QUrl &name) const
QMimeData::hasFormat
virtual bool hasFormat(const QString &mimeType) const
QDataStream
QChar
Settings::authorLocalizedName
static QString authorLocalizedName()
Get authorLocalizedName.
Definition: prefs_lokalize.h:43
QString::prepend
QString & prepend(QChar ch)
QAction::data
QVariant data() const
InlineTag::equivText
QString equivText
Definition: catalogstring.h:73
QFont
TranslationUnitTextEdit::gotoNextFuzzyUntrRequested
void gotoNextFuzzyUntrRequested()
QMenu::setActiveAction
void setActiveAction(QAction *act)
QChar::isDigit
bool isDigit() const
QList::at
const T & at(int i) const
QMap< int, int >
TranslationUnitTextEdit::keyPressEvent
void keyPressEvent(QKeyEvent *keyEvent)
Definition: xlifftextedit.cpp:738
Project::instance
static Project * instance()
Definition: project.cpp:67
completionstorage.h
QString::size
int size() const
TranslationUnitTextEdit::gotoLastRequested
void gotoLastRequested()
QMenu::addAction
void addAction(QAction *action)
QTextCursor::selectedText
QString selectedText() const
QList::removeAt
void removeAt(int i)
QWheelEvent
CompletionStorage::instance
static CompletionStorage * instance()
Definition: completionstorage.cpp:37
TranslationUnitTextEdit::mouseReleaseEvent
void mouseReleaseEvent(QMouseEvent *event)
Definition: xlifftextedit.cpp:982
TranslationUnitTextEdit::currentPos
DocPosition currentPos() const
Definition: xlifftextedit.h:47
TranslationUnitTextEdit::approvedEntryDisplayed
void approvedEntryDisplayed()
QHelpEvent::pos
const QPoint & pos() const
QChar::digitValue
int digitValue() const
Settings::mouseWheelGo
static bool mouseWheelGo()
Get MouseWheelGo.
Definition: prefs_lokalize.h:259
Catalog::push
void push(QUndoCommand *cmd)
Definition: catalog.cpp:155
QList::erase
iterator erase(iterator pos)
Settings::authorEmail
static QString authorEmail()
Get authorEmail.
Definition: prefs_lokalize.h:61
TranslationUnitTextEdit::doExplicitCompletion
void doExplicitCompletion()
Definition: xlifftextedit.cpp:1346
TranslationUnitTextEdit::TranslationUnitTextEdit
TranslationUnitTextEdit(Catalog *catalog, DocPosition::Part part, QWidget *parent=0)
Definition: xlifftextedit.cpp:143
isMasked
static bool isMasked(const QString &str, uint col)
Definition: xlifftextedit.cpp:719
QPoint
prefs.h
QFontMetrics
CatalogString::string
QString string
Definition: catalogstring.h:130
cmd.h
QMouseEvent
TranslationUnitTextEdit::cursorPositionChanged
void cursorPositionChanged(int column)
insertContent
void insertContent(QTextCursor &cursor, const CatalogString &catStr, const CatalogString &refStr, bool insertText)
Definition: xlifftextedit.cpp:344
QString::remove
QString & remove(int position, int n)
TranslationUnitTextEdit::undoRequested
void undoRequested()
TranslationUnitTextEdit::source2target
void source2target()
Definition: xlifftextedit.cpp:1227
Catalog::catalogString
CatalogString catalogString(const DocPosition &pos) const
Definition: catalog.cpp:219
Settings::wordCompletionLength
static int wordCompletionLength()
Get WordCompletionLength.
Definition: prefs_lokalize.h:277
QContextMenuEvent::globalPos
const QPoint & globalPos() const
QToolTip::showText
void showText(const QPoint &pos, const QString &text, QWidget *w)
QTime
QTextCursor::anchor
int anchor() const
QMimeData
Catalog::isEmpty
bool isEmpty(uint index) const
Definition: catalog.cpp:432
TranslationUnitTextEdit::redoRequested
void redoRequested()
QStyleOptionButton
QTextCursor::movePosition
bool movePosition(MoveOperation operation, MoveMode mode, int n)
fillTagPlaces
bool fillTagPlaces(QMap< int, int > &tagPlaces, const CatalogString &catalogString, int start, int len)
CatalogString cmds helper function.
Definition: cmd.cpp:328
QList::size
int size() const
QString::lastIndexOf
int lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
QTextCursor::select
void select(SelectionType selection)
DelTextCmd
Definition: cmd.h:99
TranslationUnitTextEdit::gotoNextFuzzyRequested
void gotoNextFuzzyRequested()
Catalog::isModified
bool isModified(DocPos entry) const
Definition: catalog.cpp:928
TranslationUnitTextEdit::replaceRequested
void replaceRequested()
QMenu::isEmpty
bool isEmpty() const
DocPosition::offset
uint offset
Definition: pos.h:51
DocPosition::entry
int entry
Definition: pos.h:48
Settings::self
static Settings * self()
Definition: prefs_lokalize.cpp:19
DocPosition
This struct represents a position in a catalog.
Definition: pos.h:38
TranslationUnitTextEdit::findRequested
void findRequested()
QRegExp
TranslationUnitTextEdit::event
bool event(QEvent *event)
Definition: xlifftextedit.cpp:1120
QTextCursor::hasSelection
bool hasSelection() const
QString::fromRawData
QString fromRawData(const QChar *unicode, int size)
QTime::elapsed
int elapsed() const
QString::number
QString number(int n, int base)
QChar::isSpace
bool isSpace() const
QMimeData::text
QString text() const
QVariant::toInt
int toInt(bool *ok) const
QVariant::isNull
bool isNull() const
TranslationUnitTextEdit::keyReleaseEvent
void keyReleaseEvent(QKeyEvent *e)
Definition: xlifftextedit.cpp:909
QImage::fill
void fill(uint pixelValue)
CatalogString::tagIdToIndex
QMap< QString, int > tagIdToIndex() const
Definition: catalogstring.cpp:187
QHash
TranslationUnitTextEdit::gotoPrevFuzzyRequested
void gotoPrevFuzzyRequested()
QContextMenuEvent
QTextDocument::addResource
void addResource(int type, const QUrl &name, const QVariant &resource)
QObject
QHelpEvent::globalPos
const QPoint & globalPos() const
InlineTag::type
InlineElement type
Definition: catalogstring.h:70
catalog.h
QMouseEvent::button
Qt::MouseButton button() const
QTextCursor::insertText
void insertText(const QString &text)
QList::isEmpty
bool isEmpty() const
QPainter
generateImage
static QImage generateImage(const QString &str, const QFont &font)
Definition: xlifftextedit.cpp:58
TranslationUnitTextEdit::contentsModified
void contentsModified(const DocPosition &)
QString::isEmpty
bool isEmpty() const
InlineTag::start
int start
Definition: catalogstring.h:68
QTextCursor::document
QTextDocument * document() const
TranslationUnitTextEdit::untranslatedEntryDisplayed
void untranslatedEntryDisplayed()
QString::startsWith
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
QKeyEvent::text
QString text() const
TranslationUnitTextEdit::cursorToStart
void cursorToStart()
Definition: xlifftextedit.cpp:1306
InlineTag::id
QString id
Definition: catalogstring.h:71
QMimeData::setText
void setText(const QString &text)
Catalog::isPlural
bool isPlural(uint index) const
Definition: catalog.cpp:405
TranslationUnitTextEdit::gotoPrevFuzzyUntrRequested
void gotoPrevFuzzyUntrRequested()
TranslationUnitTextEdit::translatedEntryDisplayed
void translatedEntryDisplayed()
QList::first
T & first()
TranslationUnitTextEdit::tagInsertRequested
void tagInsertRequested(const InlineTag &tag)
SettingsController::dirty
bool dirty
Definition: prefs.h:44
QString
QList
TranslationUnitTextEdit::tmLookupRequested
void tmLookupRequested(DocPosition::Part, const QString &)
TranslationUnitTextEdit::emitCursorPositionChanged
void emitCursorPositionChanged()
Definition: xlifftextedit.cpp:936
Settings::autoApprove
static bool autoApprove()
Get AutoApprove.
Definition: prefs_lokalize.h:214
InsTagCmd
Do insert tag.
Definition: cmd.h:131
QMenu::exec
QAction * exec()
adaptCatalogString
void adaptCatalogString(CatalogString &target, const CatalogString &ref)
prepares
Definition: catalogstring.cpp:271
TranslationUnitTextEdit::gotoNextRequested
void gotoNextRequested()
QKeyEvent::matches
bool matches(QKeySequence::StandardKey key) const
Settings
Definition: prefs_lokalize.h:13
QStringList
TranslationUnitTextEdit::gotoPrevRequested
void gotoPrevRequested()
QInputEvent::modifiers
Qt::KeyboardModifiers modifiers() const
QLocale
QAction::setData
void setData(const QVariant &userData)
QTextCharFormat
QList::end
iterator end()
QHash::value
const T value(const Key &key) const
QTextDocument::defaultFont
defaultFont
QKeyEvent::key
int key() const
QMenu
QString::contains
bool contains(QChar ch, Qt::CaseSensitivity cs) const
QSize
QUrl
TranslationUnitTextEdit::findNextRequested
void findNextRequested()
SettingsController::instance
static SettingsController * instance()
Definition: prefs.cpp:70
QString::midRef
QStringRef midRef(int position, int n) const
TranslationUnitTextEdit::gotoEntryRequested
void gotoEntryRequested(const DocPosition &)
QImage
TranslationUnitTextEdit::insertCatalogString
void insertCatalogString(CatalogString catStr, int start=0, bool refresh=true)
Definition: xlifftextedit.cpp:573
QWheelEvent::delta
int delta() const
TranslationUnitTextEdit::showPos
CatalogString showPos(DocPosition pos, const CatalogString &refStr=CatalogString(), bool keepCursor=true)
makes MsgEdit reflect current entry
Definition: xlifftextedit.cpp:237
QString::replace
QString & replace(int position, int n, QChar after)
QString::unicode
const QChar * unicode() const
QKeyEvent
CatalogString
data structure used to pass info about inline elements a XLIFF tag is represented by a TAGRANGE_IMAGE...
Definition: catalogstring.h:128
xlifftextedit.h
QContextMenuEvent::pos
const QPoint & pos() const
syntaxhighlighter.h
QString::mid
QString mid(int position, int n) const
prefs_lokalize.h
QApplication::style
QStyle * style()
QUndoStack::endMacro
void endMacro()
Catalog::sourceWithTags
CatalogString sourceWithTags(const DocPosition &pos) const
Definition: catalog.cpp:203
CatalogString::tags
QList< InlineTag > tags
Definition: catalogstring.h:131
DocPosition::Source
Definition: pos.h:43
QStyle::drawControl
virtual void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const =0
QString::at
const QChar at(int position) const
QAction
Catalog::isApproved
bool isApproved(uint index) const
Definition: catalog.cpp:410
Catalog::numberOfEntries
int numberOfEntries() const
Definition: catalog.cpp:171
Settings::setAutoSpellcheck
static void setAutoSpellcheck(bool v)
Set AutoSpellcheck.
Definition: prefs_lokalize.h:231
DocPos
simpler version of DocPosition for use in QMap
Definition: pos.h:82
TranslationUnitTextEdit::tagMenu
void tagMenu()
Definition: xlifftextedit.cpp:1148
QString::length
int length() const
TranslationUnitTextEdit::gotoPrevUntranslatedRequested
void gotoPrevUntranslatedRequested()
InlineTag::mrk
Definition: catalogstring.h:57
TranslationUnitTextEdit::insertTag
void insertTag(InlineTag tag)
Definition: xlifftextedit.cpp:941
QTextCursor::deleteChar
void deleteChar()
QTime::start
void start()
Catalog
This class represents a catalog It uses CatalogStorage interface to work with catalogs in different f...
Definition: catalog.h:74
QTextCursor::setCharFormat
void setCharFormat(const QTextCharFormat &format)
TranslationUnitTextEdit::binaryUnitSelectRequested
void binaryUnitSelectRequested(const QString &)
QMap::insert
iterator insert(const Key &key, const T &value)
QHash::contains
bool contains(const Key &key) const
Catalog::sourceLangCode
QString sourceLangCode() const
Definition: catalog.cpp:466
TranslationUnitTextEdit::gotoFirstRequested
void gotoFirstRequested()
Catalog::mimetype
QString mimetype()
Definition: catalog.cpp:458
SyntaxHighlighter
Definition: syntaxhighlighter.h:37
QTextCursor::insertImage
void insertImage(const QTextImageFormat &format, QTextFrameFormat::Position alignment)
QMimeData::setData
void setData(const QString &mimeType, const QByteArray &data)
QMouseEvent::pos
const QPoint & pos() const
spclChars
static QString spclChars("abfnrtv'?\\")
TranslationUnitTextEdit::reflectUntranslatedState
void reflectUntranslatedState()
Definition: xlifftextedit.cpp:223
TranslationUnitTextEdit::gotoNextUntranslatedRequested
void gotoNextUntranslatedRequested()
TranslationUnitTextEdit::tagImmediate
void tagImmediate()
Definition: xlifftextedit.cpp:1149
InlineTag::end
int end
Definition: catalogstring.h:69
QHelpEvent
TranslationUnitTextEdit::createMimeDataFromSelection
QMimeData * createMimeDataFromSelection() const
Definition: xlifftextedit.cpp:613
QList::begin
iterator begin()
SyntaxHighlighter::setSourceString
void setSourceString(const QString &s)
Definition: syntaxhighlighter.h:46
QMap::size
int size() const
InlineTag
data structure used to pass info about inline elements a XLIFF tag is represented by a TAGRANGE_IMAGE...
Definition: catalogstring.h:44
TranslationUnitTextEdit::nonApprovedEntryDisplayed
void nonApprovedEntryDisplayed()
TranslationUnitTextEdit::insertFromMimeData
void insertFromMimeData(const QMimeData *source)
Definition: xlifftextedit.cpp:657
KTextEdit
Catalog::unitById
int unitById(const QString &id) const
Definition: catalog.cpp:453
QMap::value
const T value(const Key &key) const
QVariant
TranslationUnitTextEdit::toPlainText
QString toPlainText()
Definition: xlifftextedit.cpp:920
QTextCursor::setPosition
void setPosition(int pos, MoveMode m)
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