• 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
  • filesearch
filesearchtab.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 #include "filesearchtab.h"
25 #include "ui_filesearchoptions.h"
26 #include "ui_massreplaceoptions.h"
27 #include "project.h"
28 
29 #include "tmscanapi.h" //TODO separate some decls into new header
30 #include "state.h"
31 #include "qaview.h"
32 
33 #include "catalog.h"
34 #include "fastsizehintitemdelegate.h"
35 //#include "flowlayout.h"
36 
37 #include <QApplication>
38 #include <QDesktopWidget>
39 #include <QTreeView>
40 #include <QClipboard>
41 #include <QShortcut>
42 #include <QDragEnterEvent>
43 #include <QSortFilterProxyModel>
44 #include <QStyledItemDelegate>
45 #include <QStringBuilder>
46 #include <QPainter>
47 #include <QTextDocument>
48 #include <QHeaderView>
49 #include <QStringListModel>
50 #include <QBoxLayout>
51 
52 #include <KColorScheme>
53 #include <kactioncategory.h>
54 #include <kaction.h>
55 #include <klocale.h>
56 #include <kstandarddirs.h>
57 #include <kxmlguifactory.h>
58 #include <threadweaver/Job.h>
59 #include <threadweaver/JobCollection.h>
60 #include <threadweaver/ThreadWeaver.h>
61 #include <threadweaver/Thread.h>
62 
63 
64 static QStringList doScanRecursive(const QDir& dir);
65 
66 
67 
68 class FileListModel: public QStringListModel
69 {
70 public:
71  FileListModel(QObject* parent): QStringListModel(parent){}
72  QVariant data(const QModelIndex& item, int role=Qt::DisplayRole) const;
73 };
74 
75 QVariant FileListModel::data(const QModelIndex& item, int role) const
76 {
77  if (role==Qt::DisplayRole)
78  return shorterFilePath(stringList().at(item.row()));
79  return QVariant();
80 }
81 
82 SearchFileListView::SearchFileListView(QWidget* parent)
83  : QDockWidget( i18nc("@title:window","File List"), parent)
84  , m_browser(new QTreeView(this))
85  , m_background(new QLabel(i18n("Drop translation files here..."), this))
86  , m_model(new FileListModel(this))
87 {
88  setWidget(m_background);
89  m_background->setMinimumWidth(QApplication::desktop()->width()/4);
90  m_background->setAlignment(Qt::AlignCenter);
91  m_browser->hide();
92  m_browser->setModel(m_model);
93  m_browser->setRootIsDecorated(false);
94  m_browser->setHeaderHidden(true);
95  m_browser->setUniformRowHeights(true);
96  m_browser->setAlternatingRowColors(true);
97 
98 
99  m_browser->setContextMenuPolicy(Qt::ActionsContextMenu);
100 
101  QAction* action=new QAction(i18nc("@action:inmenu", "Clear"), m_browser);
102  connect(action, SIGNAL(triggered()), this, SLOT(clear()));
103  m_browser->addAction(action);
104 }
105 
106 void SearchFileListView::addFiles(const QStringList& files)
107 {
108  if (files.isEmpty())
109  return;
110 
111  m_background->hide();
112  setWidget(m_browser);
113  m_browser->show();
114 
115  //ensure unquiness, sorting the list along the way
116  QMap<QString, bool> map;
117  foreach(const QString& filepath, m_model->stringList())
118  map[filepath]=true;
119  foreach(const QString& filepath, files)
120  map[filepath]=true;
121 
122  m_model->setStringList(map.keys());
123 }
124 
125 void SearchFileListView::addFilesFast(const QStringList& files)
126 {
127  if (files.size())
128  m_model->setStringList(m_model->stringList()+files);
129 }
130 
131 void SearchFileListView::clear()
132 {
133  m_model->setStringList(QStringList());
134 }
135 
136 
137 QStringList SearchFileListView::files() const
138 {
139  return m_model->stringList();
140 }
141 
142 void SearchFileListView::scrollTo(const QString& file)
143 {
144  if (file.isEmpty())
145  {
146  m_browser->scrollToTop();
147  return;
148  }
149  int idx=m_model->stringList().indexOf(file);
150  if (idx!=-1)
151  m_browser->scrollTo(m_model->index(idx, 0), QAbstractItemView::PositionAtCenter);
152 }
153 
154 
155 struct SearchParams
156 {
157  QRegExp sourcePattern;
158  QRegExp targetPattern;
159  QRegExp notesPattern;
160 
161  bool states[StateCount];
162 
163  bool isEmpty() const;
164 };
165 
166 bool SearchParams::isEmpty() const
167 {
168  return sourcePattern.pattern().isEmpty()
169  && targetPattern.pattern().isEmpty();
170 }
171 
172 
173 
175 class SearchJob: public ThreadWeaver::Job
176 {
177 public:
178  explicit SearchJob(const QStringList& f,
179  const SearchParams& sp,
180  const QVector<Rule>& r,
181  int sn,
182  QObject* parent=0);
183  ~SearchJob(){}
184 
185 protected:
186  void run ();
187 public:
188  QStringList files;
189  SearchParams searchParams;
190  QVector<Rule> rules;
191  int searchNumber;
192 
193  //QMap<QString, QVector<FileSearchResult> > results; //filepath -> results
194  SearchResults results; //plain
195 
196  int m_size;
197 };
198 
199 SearchJob::SearchJob(const QStringList& f, const SearchParams& sp, const QVector<Rule>& r, int sn, QObject* parent)
200  : ThreadWeaver::Job(parent)
201  , files(f)
202  , searchParams(sp)
203  , rules(r)
204  , searchNumber(sn)
205 {
206 }
207 
208 void SearchJob::run()
209 {
210  QTime a;a.start();
211  foreach(const QString& path, files)
212  {
213  Catalog catalog(thread());
214  if (KDE_ISUNLIKELY(catalog.loadFromUrl(KUrl::fromPath(path), KUrl(), &m_size)!=0))
215  continue;
216 
217  //QVector<FileSearchResult> catalogResults;
218  int numberOfEntries=catalog.numberOfEntries();
219  DocPosition pos(0);
220  for (;pos.entry<numberOfEntries;pos.entry++)
221  {
222  //if (!searchParams.states[catalog.state(pos)])
223  // return false;
224  int lim=catalog.isPlural(pos.entry)?catalog.numberOfPluralForms():1;
225  for (pos.form=0;pos.form<lim;pos.form++)
226  {
227  int sp=0;
228  int tp=0;
229  if (!searchParams.sourcePattern.isEmpty())
230  sp=searchParams.sourcePattern.indexIn(catalog.source(pos));
231  if (!searchParams.targetPattern.isEmpty())
232  tp=searchParams.targetPattern.indexIn(catalog.target(pos));
233  //int np=searchParams.notesPattern.indexIn(catalog.notes(pos));
234 
235  if (sp!=-1 && tp!=-1)
236  {
237  //TODO handle multiple results in same column
238  //FileSearchResult r;
239  SearchResult r;
240  r.filepath=path;
241  r.docPos=pos;
242  if (!searchParams.sourcePattern.isEmpty())
243  r.sourcePositions<<StartLen(searchParams.sourcePattern.pos(), searchParams.sourcePattern.matchedLength());
244  if (!searchParams.targetPattern.isEmpty())
245  r.targetPositions<<StartLen(searchParams.targetPattern.pos(), searchParams.targetPattern.matchedLength());
246  r.source=catalog.source(pos);
247  r.target=catalog.target(pos);
248  r.state=catalog.state(pos);
249  r.isApproved=catalog.isApproved(pos);
250  //r.activePhase=catalog.activePhase();
251  if (rules.size())
252  {
253  QVector<StartLen> positions(2);
254  int matchedQaRule=findMatchingRule(rules, r.source, r.target, positions);
255  if (matchedQaRule==-1)
256  continue;
257  if (positions.at(0).len)
258  r.sourcePositions<<positions.at(0);
259  if (positions.at(1).len)
260  r.targetPositions<<positions.at(1);
261  }
262 
263  r.sourcePositions.squeeze();
264  r.targetPositions.squeeze();
265  //catalogResults<<r;
266  results<<r;
267  }
268  }
269  }
270  //if (catalogResults.size())
271  // results[path]=catalogResults;
272  }
273  qDebug()<<"done in"<<a.elapsed();
274 }
275 
277 class MassReplaceJob: public ThreadWeaver::Job
278 {
279 public:
280  explicit MassReplaceJob(const SearchResults& srs,
281  int pos,
282  const QRegExp& s,
283  const QString& r,
284  //int sn,
285  QObject* parent=0);
286  ~MassReplaceJob(){}
287 
288 protected:
289  void run ();
290 public:
291  SearchResults searchResults;
292  int globalPos;
293  QRegExp replaceWhat;
294  QString replaceWith;
295 };
296 
297 MassReplaceJob::MassReplaceJob(const SearchResults& srs, int pos, const QRegExp& s, const QString& r, QObject* parent)
298  : ThreadWeaver::Job(parent)
299  , searchResults(srs)
300  , globalPos(pos)
301  , replaceWhat(s)
302  , replaceWith(r)
303 {
304 }
305 
306 void MassReplaceJob::run()
307 {
308  QMultiHash<QString, int> map;
309  for (int i=0;i<searchResults.count();++i)
310  map.insertMulti(searchResults.at(i).filepath, i);
311 
312  foreach(const QString& filepath, map.keys())
313  {
314  Catalog catalog(thread());
315  if (catalog.loadFromUrl(KUrl::fromPath(filepath), KUrl())!=0)
316  continue;
317 
318  foreach(int index, map.values(filepath))
319  {
320  SearchResult& sr=searchResults[index];
321  if (catalog.target(sr.docPos.toDocPosition())!=sr.target)
322  continue;
323 
324  CatalogString s=catalog.targetWithTags(sr.docPos.toDocPosition());
325  s.string.replace(replaceWhat, replaceWith);
326  catalog.setTarget(sr.docPos.toDocPosition(), s);
327  }
328 
329  catalog.save();
330  }
331 }
332 
333 
334 //BEGIN FileSearchModel
335 FileSearchModel::FileSearchModel(QObject* parent)
336  : QAbstractListModel(parent)
337 {
338 }
339 
340 QVariant FileSearchModel::headerData(int section, Qt::Orientation orientation, int role) const
341 {
342  if (role!=Qt::DisplayRole)
343  return QVariant();
344  switch (section)
345  {
346  case FileSearchModel::Source: return i18nc("@title:column Original text","Source");
347  case FileSearchModel::Target: return i18nc("@title:column Text in target language","Target");
348  //case FileSearchModel::Context: return i18nc("@title:column","Context");
349  case FileSearchModel::Filepath: return i18nc("@title:column","File");
350  case FileSearchModel::TranslationStatus: return i18nc("@title:column","Translation Status");
351  }
352  return QVariant();
353 }
354 
355 void FileSearchModel::appendSearchResults(const SearchResults& results)
356 {
357  beginInsertRows(QModelIndex(), m_searchResults.size(), m_searchResults.size()+results.size()-1);
358  m_searchResults+=results;
359  endInsertRows();
360 }
361 
362 void FileSearchModel::clear()
363 {
364  beginResetModel();
365  m_searchResults.clear();;
366  endResetModel();
367 }
368 
369 QVariant FileSearchModel::data(const QModelIndex& item, int role) const
370 {
371  bool doHtml=(role==FastSizeHintItemDelegate::HtmlDisplayRole);
372  if (doHtml)
373  role=Qt::DisplayRole;
374 
375  if (role==Qt::DisplayRole)
376  {
377  QString result;
378  const SearchResult& sr=m_searchResults.at(item.row());
379  if (item.column()==Source)
380  result=sr.source;
381  if (item.column()==Target)
382  result=sr.target;
383  if (item.column()==Filepath)
384  result=shorterFilePath(sr.filepath);
385 
386  if (doHtml && item.column()<=FileSearchModel::Target)
387  {
388  if (result.isEmpty())
389  return result;
390 
391  static QString startBld="_ST_";
392  static QString endBld="_END_";
393  static QString startBldTag="<b >";
394  static QString endBldTag="</b >";
395 
396  if (item.column()==FileSearchModel::Target && !m_replaceWhat.isEmpty())
397  {
398  result.replace(m_replaceWhat, m_replaceWith);
399  QString escaped=convertToHtml(result, !sr.isApproved);
400  escaped.replace(startBld, startBldTag);
401  escaped.replace(endBld, endBldTag);
402  return escaped;
403  }
404 
405  const QVector<StartLen>& occurences=item.column()==FileSearchModel::Source?sr.sourcePositions:sr.targetPositions;
406  int occ=occurences.count();
407  while (--occ>=0)
408  {
409  const StartLen& sl=occurences.at(occ);
410  result.insert(sl.start+sl.len, endBld);
411  result.insert(sl.start, startBld);
412  }
413  /* !isApproved(sr.state/*, Project::instance()->local()->role())*/
414  QString escaped=convertToHtml(result, item.column()==FileSearchModel::Target && !sr.isApproved);
415 
416  escaped.replace(startBld, startBldTag);
417  escaped.replace(endBld, endBldTag);
418  return escaped;
419  }
420  return result;
421 
422  }
423 
424  if (role==Qt::UserRole)
425  {
426  const SearchResult& sr=m_searchResults.at(item.row());
427  if (item.column()==Filepath)
428  return sr.filepath;
429  }
430 
431  return QVariant();
432 }
433 
434 void FileSearchModel::setReplacePreview(const QRegExp& s, const QString& r)
435 {
436  m_replaceWhat=s;
437  m_replaceWith="_ST_" % r % "_END_";
438 
439  emit dataChanged(index(0, Target), index(rowCount()-1, Target));
440 }
441 
442 
443 //END FileSearchModel
444 
445 //BEGIN FileSearchTab
446 FileSearchTab::FileSearchTab(QWidget *parent)
447  : LokalizeSubwindowBase2(parent)
448 // , m_proxyModel(new TMResultsSortFilterProxyModel(this))
449  , m_model(new FileSearchModel(this))
450  , m_lastSearchNumber(0)
451  , m_dbusId(-1)
452 {
453  setWindowTitle(i18nc("@title:window","Search and replace in files"));
454  setAcceptDrops(true);
455 
456  QWidget* w=new QWidget(this);
457  ui_fileSearchOptions=new Ui_FileSearchOptions;
458  ui_fileSearchOptions->setupUi(w);
459  setCentralWidget(w);
460 
461 
462  QShortcut* sh=new QShortcut(Qt::CTRL+Qt::Key_L, this);
463  connect(sh,SIGNAL(activated()),ui_fileSearchOptions->querySource,SLOT(setFocus()));
464  setFocusProxy(ui_fileSearchOptions->querySource);
465 
466  sh=new QShortcut(Qt::Key_Escape,this,SLOT(stopSearch()),0,Qt::WidgetWithChildrenShortcut);
467 
468  QTreeView* view=ui_fileSearchOptions->treeView;
469 
470  QVector<bool> singleLineColumns(FileSearchModel::ColumnCount, false);
471  singleLineColumns[FileSearchModel::Filepath]=true;
472  singleLineColumns[FileSearchModel::TranslationStatus]=true;
473  //singleLineColumns[TMDBModel::Context]=true;
474 
475  QVector<bool> richTextColumns(FileSearchModel::ColumnCount, false);
476  richTextColumns[FileSearchModel::Source]=true;
477  richTextColumns[FileSearchModel::Target]=true;
478  view->setItemDelegate(new FastSizeHintItemDelegate(this,singleLineColumns,richTextColumns));
479  connect(m_model,SIGNAL(modelReset()),view->itemDelegate(),SLOT(reset()));
480  connect(m_model,SIGNAL(dataChanged(QModelIndex,QModelIndex)),view->itemDelegate(),SLOT(reset()));
481  //connect(m_model,SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),view->itemDelegate(),SLOT(reset()));
482  //connect(m_proxyModel,SIGNAL(layoutChanged()),view->itemDelegate(),SLOT(reset()));
483  //connect(m_proxyModel,SIGNAL(layoutChanged()),this,SLOT(displayTotalResultCount()));
484 
485  view->setContextMenuPolicy(Qt::ActionsContextMenu);
486 
487  QAction* a=new QAction(i18n("Copy source to clipboard"),view);
488  a->setShortcut(Qt::CTRL + Qt::Key_S);
489  a->setShortcutContext(Qt::WidgetWithChildrenShortcut);
490  connect(a,SIGNAL(activated()), this, SLOT(copySource()));
491  view->addAction(a);
492 
493  a=new QAction(i18n("Copy target to clipboard"),view);
494  a->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return));
495  a->setShortcutContext(Qt::WidgetWithChildrenShortcut);
496  connect(a,SIGNAL(activated()), this, SLOT(copyTarget()));
497  view->addAction(a);
498 
499  a=new QAction(i18n("Open file"),view);
500  a->setShortcut(QKeySequence(Qt::Key_Return));
501  a->setShortcutContext(Qt::WidgetWithChildrenShortcut);
502  connect(a,SIGNAL(activated()), this, SLOT(openFile()));
503  connect(view,SIGNAL(activated(QModelIndex)), this, SLOT(openFile()));
504  view->addAction(a);
505 
506  connect(ui_fileSearchOptions->querySource,SIGNAL(returnPressed()),this,SLOT(performSearch()));
507  connect(ui_fileSearchOptions->queryTarget,SIGNAL(returnPressed()),this,SLOT(performSearch()));
508  connect(ui_fileSearchOptions->doFind,SIGNAL(clicked()), this,SLOT(performSearch()));
509 
510 // m_proxyModel->setDynamicSortFilter(true);
511 // m_proxyModel->setSourceModel(m_model);
512  view->setModel(m_model);
513 // view->setModel(m_proxyModel);
514 // view->sortByColumn(FileSearchModel::Filepath,Qt::AscendingOrder);
515 // view->setSortingEnabled(true);
516 // view->setItemDelegate(new FastSizeHintItemDelegate(this));
517 // connect(m_model,SIGNAL(resultsFetched()),view->itemDelegate(),SLOT(reset()));
518 // connect(m_model,SIGNAL(modelReset()),view->itemDelegate(),SLOT(reset()));
519 // connect(m_proxyModel,SIGNAL(layoutChanged()),view->itemDelegate(),SLOT(reset()));
520 // connect(m_proxyModel,SIGNAL(layoutChanged()),this,SLOT(displayTotalResultCount()));
521 
522 
523 //BEGIN resizeColumnToContents
524  static const int maxInitialWidths[]={QApplication::desktop()->availableGeometry().width()/3,QApplication::desktop()->availableGeometry().width()/3};
525  int column=sizeof(maxInitialWidths)/sizeof(int);
526  while (--column>=0)
527  view->setColumnWidth(column, maxInitialWidths[column]);
528 //END resizeColumnToContents
529 
530  int i=6;
531  while (--i>ID_STATUS_PROGRESS)
532  statusBarItems.insert(i,QString());
533 
534  setXMLFile("filesearchtabui.rc",true);
535  dbusObjectPath();
536 
537 
538  //KAction *action;
539  KActionCollection* ac=actionCollection();
540  KActionCategory* srf=new KActionCategory(i18nc("@title actions category","Search and replace in files"), ac);
541 
542  m_searchFileListView = new SearchFileListView(this);
543  //m_searchFileListView->hide();
544  addDockWidget(Qt::RightDockWidgetArea, m_searchFileListView);
545  srf->addAction( QLatin1String("showfilelist_action"), m_searchFileListView->toggleViewAction() );
546 
547  m_massReplaceView = new MassReplaceView(this);
548  addDockWidget(Qt::RightDockWidgetArea, m_massReplaceView);
549  srf->addAction( QLatin1String("showmassreplace_action"), m_massReplaceView->toggleViewAction() );
550  connect(m_massReplaceView, SIGNAL(previewRequested(QRegExp,QString)), m_model, SLOT(setReplacePreview(QRegExp ,QString)));
551  connect(m_massReplaceView, SIGNAL(replaceRequested(QRegExp,QString)), this, SLOT(massReplace(QRegExp,QString)));
552  //m_massReplaceView->hide();
553 
554  m_qaView = new QaView(this);
555  m_qaView->hide();
556  addDockWidget(Qt::RightDockWidgetArea, m_qaView);
557  srf->addAction( QLatin1String("showqa_action"), m_qaView->toggleViewAction() );
558 
559  connect(m_qaView, SIGNAL(rulesChanged()), this, SLOT(performSearch()));
560  connect(m_qaView->toggleViewAction(), SIGNAL(toggled(bool)), this, SLOT(performSearch()), Qt::QueuedConnection);
561 
562  KConfig config;
563  KConfigGroup cg(&config,"MainWindow");
564  view->header()->restoreState(QByteArray::fromBase64( cg.readEntry("FileSearchResultsHeaderState", QByteArray()) ));
565 }
566 
567 FileSearchTab::~FileSearchTab()
568 {
569  stopSearch();
570 
571  KConfig config;
572  KConfigGroup cg(&config,"MainWindow");
573  cg.writeEntry("FileSearchResultsHeaderState",ui_fileSearchOptions->treeView->header()->saveState().toBase64());
574 
575  ids.removeAll(m_dbusId);
576 }
577 
578 void FileSearchTab::performSearch()
579 {
580  if (m_searchFileListView->files().isEmpty())
581  {
582  addFilesToSearch(doScanRecursive(QDir(Project::instance()->poDir())));
583  if (m_searchFileListView->files().isEmpty())
584  return;
585  }
586 
587  m_model->clear();
588  statusBarItems.insert(1,QString());
589  m_searchFileListView->scrollTo();
590 
591  m_lastSearchNumber++;
592 
593  SearchParams sp;
594  sp.sourcePattern.setPattern(ui_fileSearchOptions->querySource->text());
595  sp.targetPattern.setPattern(ui_fileSearchOptions->queryTarget->text());
596 
597  QVector<Rule> rules=m_qaView->isVisible()?m_qaView->rules():QVector<Rule>();
598 
599  if (sp.isEmpty() && rules.isEmpty())
600  return;
601 
602  if (!ui_fileSearchOptions->regEx->isChecked())
603  {
604  sp.sourcePattern.setPatternSyntax(QRegExp::FixedString);
605  sp.targetPattern.setPatternSyntax(QRegExp::FixedString);
606  }
607 /*
608  else
609  {
610  sp.sourcePattern.setMinimal(true);
611  sp.targetPattern.setMinimal(true);
612  }
613 */
614  stopSearch();
615 
616  m_massReplaceView->deactivatePreview();
617 
618  QStringList files=m_searchFileListView->files();
619  for(int i=0; i<files.size();i+=100)
620  {
621  QStringList batch;
622  int lim=qMin(files.size(), i+100);
623  for(int j=i; j<lim;j++)
624  batch.append(files.at(j));
625 
626  SearchJob* job=new SearchJob(batch, sp, rules, m_lastSearchNumber);
627  QObject::connect(job,SIGNAL(done(ThreadWeaver::Job*)),job,SLOT(deleteLater()));
628  QObject::connect(job,SIGNAL(done(ThreadWeaver::Job*)),this,SLOT(searchJobDone(ThreadWeaver::Job*)));
629  ThreadWeaver::Weaver::instance()->enqueue(job);
630  m_runningJobs.append(job);
631  }
632 }
633 
634 void FileSearchTab::stopSearch()
635 {
636  QVector<ThreadWeaver::Job*>::const_iterator it;
637  for (it = m_runningJobs.constBegin(); it != m_runningJobs.constEnd(); ++it)
638  ThreadWeaver::Weaver::instance()->dequeue(*it);
639  m_runningJobs.clear();
640 }
641 
642 
643 void FileSearchTab::massReplace(const QRegExp &what, const QString& with)
644 {
645 #define BATCH_SIZE 20
646 
647  SearchResults searchResults=m_model->searchResults();
648 
649  for (int i=0;i<searchResults.count();i+=BATCH_SIZE)
650  {
651  int last=qMin(i+BATCH_SIZE, searchResults.count()-1);
652  QString filepath=searchResults.at(last).filepath;
653  while (last+1<searchResults.count() && filepath==searchResults.at(last+1).filepath)
654  ++last;
655 
656  MassReplaceJob* job=new MassReplaceJob(searchResults.mid(i, last+1-i), i, what, with);
657  QObject::connect(job,SIGNAL(done(ThreadWeaver::Job*)),job,SLOT(deleteLater()));
658  QObject::connect(job,SIGNAL(done(ThreadWeaver::Job*)),this,SLOT(replaceJobDone(ThreadWeaver::Job*)));
659  ThreadWeaver::Weaver::instance()->enqueue(job);
660  m_runningJobs.append(job);
661  }
662 }
663 
664 
665 static void copy(QTreeView* view, int column)
666 {
667  QApplication::clipboard()->setText( view->currentIndex().sibling(view->currentIndex().row(),column).data().toString());
668 }
669 
670 void FileSearchTab::copySource()
671 {
672  copy(ui_fileSearchOptions->treeView, FileSearchModel::Source);
673 }
674 
675 void FileSearchTab::copyTarget()
676 {
677  copy(ui_fileSearchOptions->treeView, FileSearchModel::Target);
678 }
679 
680 void FileSearchTab::openFile()
681 {
682  QModelIndex item=ui_fileSearchOptions->treeView->currentIndex();
683  SearchResult sr=m_model->searchResult(item);
684  DocPosition docPos=sr.docPos.toDocPosition();
685  int selection=0;
686  if (sr.targetPositions.size())
687  {
688  docPos.offset=sr.targetPositions.first().start;
689  selection =sr.targetPositions.first().len;
690  }
691  kDebug()<<"fileOpenRequest"<<docPos.offset<<selection;
692  emit fileOpenRequested(sr.filepath, docPos, selection);
693 }
694 
695 void FileSearchTab::fileSearchNext()
696 {
697  QModelIndex item=ui_fileSearchOptions->treeView->currentIndex();
698  int row=item.row();
699  int rowCount=m_model->rowCount();
700 
701  if (++row>=rowCount) //ok if row was -1 (no solection)
702  return;
703 
704  ui_fileSearchOptions->treeView->setCurrentIndex(item.sibling(row, item.column()));
705  openFile();
706 }
707 
708 
709 QStringList scanRecursive(const QList<QUrl>& urls)
710 {
711  QStringList result;
712 
713  int i=urls.size();
714  while(--i>=0)
715  {
716  if (urls.at(i).isEmpty() || urls.at(i).path().isEmpty() ) //NOTE is this a Qt bug?
717  continue;
718  QString path=urls.at(i).toLocalFile();
719  if (Catalog::extIsSupported(path))
720  result.append(path);
721  else
722  result+=doScanRecursive(QDir(path));
723  }
724 
725  return result;
726 }
727 
728 //returns gross number of jobs started
729 static QStringList doScanRecursive(const QDir& dir)
730 {
731  QStringList result;
732  QStringList subDirs(dir.entryList(QDir::Dirs|QDir::NoDotAndDotDot|QDir::Readable));
733  int i=subDirs.size();
734  while(--i>=0)
735  result+=doScanRecursive(QDir(dir.filePath(subDirs.at(i))));
736 
737  QStringList filters=Catalog::supportedExtensions();
738  i=filters.size();
739  while(--i>=0)
740  filters[i].prepend('*');
741  QStringList files(dir.entryList(filters,QDir::Files|QDir::NoDotAndDotDot|QDir::Readable));
742  i=files.size();
743 
744  while(--i>=0)
745  result.append(dir.filePath(files.at(i)));
746 
747  return result;
748 }
749 
750 
751 void FileSearchTab::dragEnterEvent(QDragEnterEvent* event)
752 {
753  if(dragIsAcceptable(event->mimeData()->urls()))
754  event->acceptProposedAction();
755 }
756 
757 void FileSearchTab::dropEvent(QDropEvent *event)
758 {
759  event->acceptProposedAction();
760  addFilesToSearch(scanRecursive(event->mimeData()->urls()));
761 }
762 
763 void FileSearchTab::addFilesToSearch(const QStringList& files)
764 {
765  m_searchFileListView->addFiles(files);
766  performSearch();
767 }
768 
769 void FileSearchTab::searchJobDone(ThreadWeaver::Job* job)
770 {
771  SearchJob* j=static_cast<SearchJob*>(job);
772  if (j->searchNumber!=m_lastSearchNumber)
773  return;
774 
775 /*
776  SearchResults searchResults;
777 
778  FileSearchResults::const_iterator i = j->results.constBegin();
779  while (i != j->results.constEnd())
780  {
781  foreach(const FileSearchResult& fsr, i.value())
782  {
783  SearchResult sr(fsr);
784  sr.filepath=i.key();
785  searchResults<<sr;
786  }
787  ++i;
788  }
789 
790  m_model->appendSearchResults(searchResults);
791 */
792  if (j->results.size())
793  {
794  m_model->appendSearchResults(j->results);
795  m_searchFileListView->scrollTo(j->results.last().filepath);
796  }
797 
798  statusBarItems.insert(1,i18nc("@info:status message entries","Total: %1", m_model->rowCount()));
799  //ui_fileSearchOptions->treeView->setFocus();
800 }
801 
802 void FileSearchTab::replaceJobDone(ThreadWeaver::Job* job)
803 {
804  MassReplaceJob* j=static_cast<MassReplaceJob*>(job);
805  ui_fileSearchOptions->treeView->scrollTo(m_model->index(j->globalPos+j->searchResults.count(), 0));
806 
807 }
808 
809 
810 //END FileSearchTab
811 
812 //BEGIN MASS REPLACE
813 
814 MassReplaceView::MassReplaceView(QWidget* parent)
815  : QDockWidget(i18nc("@title:window","Mass replace"), parent)
816  , ui(new Ui_MassReplaceOptions)
817 {
818  QWidget* base=new QWidget(this);
819  setWidget(base);
820  ui->setupUi(base);
821 
822  connect(ui->doPreview, SIGNAL(toggled(bool)), this, SLOT(requestPreview(bool)));
823  connect(ui->doReplace, SIGNAL(clicked(bool)), this, SLOT(requestReplace()));
824 /*
825  QLabel* rl=new QLabel(i18n("Replace:"), base);
826  KLineEdit* searchEdit=new KLineEdit(base);
827  QHBoxLayout* searchL=new QHBoxLayout();
828  searchL->addWidget(rl);
829  searchL->addWidget(searchEdit);
830 
831  QLabel* wl=new QLabel(i18n("With:"), base);
832  wl->setAlignment(Qt::AlignRight);
833  wl->setMinimumSize(rl->minimumSizeHint());
834  KLineEdit* replacementEdit=new KLineEdit(base);
835  QHBoxLayout* replacementL=new QHBoxLayout();
836  replacementL->addWidget(wl);
837  replacementL->addWidget(replacementEdit);
838 
839  FlowLayout* fl=new FlowLayout();
840  fl->addItem(searchL);
841  fl->addItem(replacementL);
842  base->setLayout(fl);
843  */
844 }
845 
846 MassReplaceView::~MassReplaceView()
847 {
848  delete ui;
849 }
850 
851 void MassReplaceView::requestPreview(bool enable)
852 {
853  QString s, r;
854  if (enable)
855  {
856  s=ui->searchText->text();
857  r=ui->replaceText->text();
858 
859  if (s.length())
860  ui->doReplace->setEnabled(true);
861  }
862 
863  emit previewRequested(QRegExp(s), r);
864 }
865 
866 void MassReplaceView::requestReplace()
867 {
868  QString s=ui->searchText->text();
869  QString r=ui->replaceText->text();
870 
871  if (s.isEmpty())
872  return;
873 
874  emit replaceRequested(QRegExp(s), r);
875 }
876 
877 void MassReplaceView::deactivatePreview()
878 {
879  ui->doPreview->setChecked(false);
880  ui->doReplace->setEnabled(false);
881 }
882 
883 
884 #include "filesearchadaptor.h"
885 #include <qdbusconnection.h>
886 
887 QList<int> FileSearchTab::ids;
888 
889 //BEGIN DBus interface
890 
891 QString FileSearchTab::dbusObjectPath()
892 {
893  if ( m_dbusId==-1 )
894  {
895  new FileSearchAdaptor(this);
896 
897  int i=0;
898  while(i<ids.size()&&i==ids.at(i))
899  ++i;
900  ids.insert(i,i);
901  m_dbusId=i;
902  QDBusConnection::sessionBus().registerObject("/ThisIsWhatYouWant/FileSearch/" + QString::number(m_dbusId), this);
903  }
904 
905  return "/ThisIsWhatYouWant/FileSearch/" + QString::number(m_dbusId);
906 }
907 
908 
909 //END DBus interface
910 
911 #include "filesearchtab.moc"
FileSearchModel::Filepath
Definition: filesearchtab.h:157
QaView::rules
QVector< Rule > rules() const
Definition: qaview.cpp:81
QModelIndex
FileSearchModel::clear
void clear()
Definition: filesearchtab.cpp:362
FileSearchResult::isApproved
bool isApproved
Definition: filesearchtab.h:123
project.h
QWidget
FileSearchTab::massReplace
void massReplace(const QRegExp &what, const QString &with)
Definition: filesearchtab.cpp:643
FileSearchResult::targetPositions
QVector< StartLen > targetPositions
Definition: filesearchtab.h:128
QAction::setShortcutContext
void setShortcutContext(Qt::ShortcutContext context)
dragIsAcceptable
bool dragIsAcceptable(const QList< QUrl > &urls)
Definition: tmscanapi.cpp:151
FileSearchModel::searchResult
SearchResult searchResult(const QModelIndex &item) const
Definition: filesearchtab.h:179
QAbstractItemView::setAlternatingRowColors
void setAlternatingRowColors(bool enable)
StartLen::len
short len
Definition: rule.h:49
QDropEvent::mimeData
const QMimeData * mimeData() const
BATCH_SIZE
#define BATCH_SIZE
QRegExp::isEmpty
bool isEmpty() const
StatusBarProxy::insert
void insert(int, const QString &)
Definition: actionproxy.cpp:97
Catalog::supportedExtensions
static QStringList supportedExtensions()
Definition: catalog.cpp:84
QVector::append
void append(const T &value)
filesearchtab.h
QByteArray
QDockWidget
QWidget::addAction
void addAction(QAction *action)
FileSearchModel::Target
Definition: filesearchtab.h:155
StartLen::start
short start
Definition: rule.h:48
QHeaderView::restoreState
bool restoreState(const QByteArray &state)
SearchFileListView::files
QStringList files() const
Definition: filesearchtab.cpp:137
copy
static void copy(QTreeView *view, int column)
Definition: filesearchtab.cpp:665
FileSearchTab::copyTarget
void copyTarget()
Definition: filesearchtab.cpp:675
QWidget::setMinimumWidth
void setMinimumWidth(int minw)
QVector::constEnd
const_iterator constEnd() const
FileSearchModel::searchResults
SearchResults searchResults() const
Definition: filesearchtab.h:178
QList::at
const T & at(int i) const
FileSearchModel::data
QVariant data(const QModelIndex &item, int role=Qt::DisplayRole) const
Definition: filesearchtab.cpp:369
QMap
FileSearchTab::FileSearchTab
FileSearchTab(QWidget *parent)
Definition: filesearchtab.cpp:446
Project::instance
static Project * instance()
Definition: project.cpp:67
QDBusConnection::registerObject
bool registerObject(const QString &path, QObject *object, QFlags< QDBusConnection::RegisterOption > options)
QWidget::isVisible
bool isVisible() const
QDir::filePath
QString filePath(const QString &fileName) const
QLabel::setAlignment
void setAlignment(QFlags< Qt::AlignmentFlag >)
QTreeView::setUniformRowHeights
void setUniformRowHeights(bool uniform)
QDBusConnection::sessionBus
QDBusConnection sessionBus()
FileSearchResult::target
QString target
Definition: filesearchtab.h:121
QVector::first
T & first()
MassReplaceView
Definition: filesearchtab.h:218
CatalogString::string
QString string
Definition: catalogstring.h:130
fastsizehintitemdelegate.h
QTime
FileSearchTab::dbusObjectPath
QString dbusObjectPath()
Definition: filesearchtab.cpp:891
FileSearchModel::ColumnCount
Definition: filesearchtab.h:160
FileSearchModel::setReplacePreview
void setReplacePreview(const QRegExp &, const QString &)
Definition: filesearchtab.cpp:434
QList::size
int size() const
SearchFileListView::SearchFileListView
SearchFileListView(QWidget *)
Definition: filesearchtab.cpp:82
DocPosition::offset
uint offset
Definition: pos.h:51
QWidget::width
int width() const
QAbstractItemModel::beginResetModel
void beginResetModel()
Catalog::extIsSupported
static bool extIsSupported(const QString &path)
Definition: catalog.cpp:93
DocPosition
This struct represents a position in a catalog.
Definition: pos.h:38
QMap::keys
QList< Key > keys() const
QRegExp
QVector::clear
void clear()
FileSearchResult::sourcePositions
QVector< StartLen > sourcePositions
Definition: filesearchtab.h:127
FileSearchModel::FileSearchModel
FileSearchModel(QObject *parent)
Definition: filesearchtab.cpp:335
QStringListModel::stringList
QStringList stringList() const
QTime::elapsed
int elapsed() const
FileSearchTab::stopSearch
void stopSearch()
Definition: filesearchtab.cpp:634
QTreeView::setColumnWidth
void setColumnWidth(int column, int width)
QString::number
QString number(int n, int base)
QList::append
void append(const T &value)
SearchFileListView
Definition: filesearchtab.h:192
QString::insert
QString & insert(int position, QChar ch)
QStringListModel::data
virtual QVariant data(const QModelIndex &index, int role) const
QAbstractItemModel::dataChanged
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
SearchFileListView::addFilesFast
void addFilesFast(const QStringList &files)
Definition: filesearchtab.cpp:125
QApplication::clipboard
QClipboard * clipboard()
QAbstractItemModel::endInsertRows
void endInsertRows()
MassReplaceView::replaceRequested
void replaceRequested(const QRegExp &, const QString &)
QObject
StateCount
Definition: state.h:42
catalog.h
QAbstractListModel::index
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const
QAbstractListModel
QDropEvent
QList::isEmpty
bool isEmpty() const
FileSearchModel::rowCount
int rowCount(const QModelIndex &parent=QModelIndex()) const
Definition: filesearchtab.h:176
QString::isEmpty
bool isEmpty() const
QList::removeAll
int removeAll(const T &value)
QAbstractItemView::setItemDelegate
void setItemDelegate(QAbstractItemDelegate *delegate)
QModelIndex::row
int row() const
FileSearchTab::fileSearchNext
void fileSearchNext()
Definition: filesearchtab.cpp:695
FileSearchTab::copySource
void copySource()
Definition: filesearchtab.cpp:670
FileSearchModel::TranslationStatus
Definition: filesearchtab.h:158
QAbstractItemView::itemDelegate
QAbstractItemDelegate * itemDelegate() const
FileSearchTab::addFilesToSearch
Q_SCRIPTABLE void addFilesToSearch(const QStringList &)
Definition: filesearchtab.cpp:763
QtConcurrent::run
QFuture< T > run(Function function,...)
FileSearchResult::docPos
DocPos docPos
Definition: filesearchtab.h:118
QVector::mid
QVector< T > mid(int pos, int length) const
states
static const char *const states[]
Definition: xliffstorage.cpp:955
QShortcut
QString
QList
QWidget::hide
void hide()
QtConcurrent::map
QFuture< void > map(Sequence &sequence, MapFunction function)
FastSizeHintItemDelegate
remember to connect appropriate signals to reset slot for delegate to have actual cache ...
Definition: fastsizehintitemdelegate.h:42
QStringListModel
FileSearchResult::source
QString source
Definition: filesearchtab.h:120
QStringList
QVector::squeeze
void squeeze()
SearchFileListView::scrollTo
void scrollTo(const QString &file=QString())
Definition: filesearchtab.cpp:142
SearchResult
Definition: filesearchtab.h:137
QWidget::setContextMenuPolicy
void setContextMenuPolicy(Qt::ContextMenuPolicy policy)
QAction::setShortcut
void setShortcut(const QKeySequence &shortcut)
QTreeView::scrollTo
virtual void scrollTo(const QModelIndex &index, ScrollHint hint)
QAbstractItemModel::beginInsertRows
void beginInsertRows(const QModelIndex &parent, int first, int last)
FileSearchTab::performSearch
Q_SCRIPTABLE void performSearch()
Definition: filesearchtab.cpp:578
QDockWidget::setWidget
void setWidget(QWidget *widget)
QDir
findMatchingRule
int findMatchingRule(const QVector< Rule > &rules, const QString &source, const QString &target, QVector< StartLen > &positions)
Definition: qaview.cpp:100
QString::replace
QString & replace(int position, int n, QChar after)
CatalogString
data structure used to pass info about inline elements a XLIFF tag is represented by a TAGRANGE_IMAGE...
Definition: catalogstring.h:128
QVector::at
const T & at(int i) const
FileSearchModel
Definition: filesearchtab.h:147
QVector::constBegin
const_iterator constBegin() const
QRect::width
int width() const
QDockWidget::toggleViewAction
QAction * toggleViewAction() const
scanRecursive
QStringList scanRecursive(const QList< QUrl > &urls)
Definition: filesearchtab.cpp:709
state.h
QVector< Rule >
FileSearchTab::~FileSearchTab
~FileSearchTab()
Definition: filesearchtab.cpp:567
QDragEnterEvent
LokalizeSubwindowBase::statusBarItems
StatusBarProxy statusBarItems
Definition: lokalizesubwindowbase.h:63
StartLen
Definition: rule.h:46
SearchFileListView::addFiles
void addFiles(const QStringList &files)
Definition: filesearchtab.cpp:106
QLatin1String
QTreeView
QKeySequence
QApplication::desktop
QDesktopWidget * desktop()
QMimeData::urls
QList< QUrl > urls() const
QByteArray::fromBase64
QByteArray fromBase64(const QByteArray &base64)
QTreeView::setHeaderHidden
void setHeaderHidden(bool hide)
QList::insert
void insert(int i, const T &value)
convertToHtml
QString convertToHtml(QString str, bool italics)
Definition: fastsizehintitemdelegate.cpp:119
QVector::isEmpty
bool isEmpty() const
QModelIndex::sibling
QModelIndex sibling(int row, int column) const
QDir::entryList
QStringList entryList(QFlags< QDir::Filter > filters, QFlags< QDir::SortFlag > sort) const
QAbstractItemView::scrollToTop
void scrollToTop()
tmscanapi.h
QTreeView::setModel
virtual void setModel(QAbstractItemModel *model)
qaview.h
QAction
QaView
Definition: qaview.h:36
QWidget::QWidget
QWidget(QWidget *parent, QFlags< Qt::WindowType > f)
SearchFileListView::clear
void clear()
Definition: filesearchtab.cpp:131
QVector::count
int count(const T &value) const
FileSearchModel::Source
Definition: filesearchtab.h:154
QModelIndex::column
int column() const
QString::length
int length() const
ID_STATUS_PROGRESS
#define ID_STATUS_PROGRESS
Definition: actionproxy.h:92
MassReplaceView::previewRequested
void previewRequested(const QRegExp &, const QString &)
MassReplaceView::~MassReplaceView
~MassReplaceView()
Definition: filesearchtab.cpp:846
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
MassReplaceView::deactivatePreview
void deactivatePreview()
Definition: filesearchtab.cpp:877
QDesktopWidget::availableGeometry
const QRect availableGeometry(int screen) const
QStringList::indexOf
int indexOf(const QRegExp &rx, int from) const
QClipboard::setText
void setText(const QString &text, Mode mode)
QTreeView::header
QHeaderView * header() const
shorterFilePath
QString shorterFilePath(const QString path)
Definition: tmscanapi.cpp:169
QWidget::show
void show()
FileSearchTab::fileOpenRequested
void fileOpenRequested(const KUrl &url, DocPosition docPos, int selection)
QAbstractItemView::currentIndex
QModelIndex currentIndex() const
QTreeView::setRootIsDecorated
void setRootIsDecorated(bool show)
FastSizeHintItemDelegate::HtmlDisplayRole
Definition: fastsizehintitemdelegate.h:49
QAbstractItemModel::endResetModel
void endResetModel()
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QLabel
QVector::size
int size() const
LokalizeSubwindowBase2
C++ casting workaround.
Definition: lokalizesubwindowbase.h:70
FileSearchResult::state
TargetState state
Definition: filesearchtab.h:124
FileSearchModel::headerData
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
Definition: filesearchtab.cpp:340
FileSearchModel::appendSearchResults
void appendSearchResults(const SearchResults &)
Definition: filesearchtab.cpp:355
QStringListModel::setStringList
void setStringList(const QStringList &strings)
DocPos::toDocPosition
DocPosition toDocPosition()
Definition: pos.h:107
MassReplaceView::MassReplaceView
MassReplaceView(QWidget *)
Definition: filesearchtab.cpp:814
QMultiHash< QString, int >
SearchResult::filepath
QString filepath
Definition: filesearchtab.h:139
doScanRecursive
static QStringList doScanRecursive(const QDir &dir)
Definition: filesearchtab.cpp:729
FileSearchTab::openFile
void openFile()
Definition: filesearchtab.cpp:680
QVariant
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