• 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
  • project
projectmodel.cpp
Go to the documentation of this file.
1 /* ****************************************************************************
2  This file is part of Lokalize
3 
4  Copyright (C) 2007-2013 by Nick Shaforostoff <shafff@ukr.net>
5  Copyright (C) 2009 by Viesturs Zarins <viesturs.zarins@mii.lu.lv>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License or (at your option) version 3 or any later version
11  accepted by the membership of KDE e.V. (or its successor approved
12  by the membership of KDE e.V.), which shall act as a proxy
13  defined in Section 14 of version 3 of the license.
14 
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with this program. If not, see <http://www.gnu.org/licenses/>.
22 
23 **************************************************************************** */
24 
25 #include "projectmodel.h"
26 #include "project.h"
27 
28 #include <threadweaver/ThreadWeaver.h>
29 #include <threadweaver/Thread.h>
30 
31 #include <kio/netaccess.h>
32 #include <klocale.h>
33 #include <kapplication.h>
34 #include <kstandarddirs.h>
35 
36 #include <QTime>
37 #include <QFile>
38 #include <QtAlgorithms>
39 #include <QTimer>
40 #include <QSqlDatabase>
41 #include <QSqlQuery>
42 #include <QSqlError>
43 
44 #undef KDE_NO_DEBUG_OUTPUT
45 static int nodeCounter=0;
46 
47 //TODO: figure out how to handle file and folder renames...
48 //TODO: fix behavior on folder removing, adding.
49 
50 
51 ProjectModel::ProjectModel(QObject *parent)
52  : QAbstractItemModel(parent)
53  , m_poModel(this)
54  , m_potModel(this)
55  , m_rootNode(ProjectNode(NULL, -1, -1, -1))
56  , m_dirIcon(KIcon(QLatin1String("inode-directory")))
57  , m_poIcon(KIcon(QLatin1String("flag-blue")))
58  , m_poComplIcon(KIcon(QLatin1String("flag-green")))
59  , m_potIcon(KIcon(QLatin1String("flag-black")))
60  , m_activeJob(NULL)
61  , m_activeNode(NULL)
62  , m_weaver(new ThreadWeaver::Weaver())
63  , m_completeScan(true)
64 {
65  m_weaver->setMaximumNumberOfThreads(1);
66 
67  m_poModel.dirLister()->setAutoErrorHandlingEnabled(false, NULL);
68  m_poModel.dirLister()->setNameFilter("*.po *.pot *.xlf");
69 
70  m_potModel.dirLister()->setAutoErrorHandlingEnabled(false, NULL);
71  m_potModel.dirLister()->setNameFilter("*.pot");
72 
73  connect(&m_poModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
74  this, SLOT(po_dataChanged(QModelIndex,QModelIndex)));
75 
76  connect(&m_poModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
77  this, SLOT(po_rowsInserted(QModelIndex,int,int)));
78 
79  connect(&m_poModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
80  this, SLOT(po_rowsRemoved(QModelIndex,int,int)));
81 
82  connect(&m_potModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
83  this, SLOT(pot_dataChanged(QModelIndex,QModelIndex)));
84 
85  connect(&m_potModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
86  this, SLOT(pot_rowsInserted(QModelIndex,int,int)));
87 
88  connect(&m_potModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
89  this, SLOT(pot_rowsRemoved(QModelIndex,int,int)));
90 
91  m_doneTimer = new QTimer();
92  m_doneTimer->setSingleShot(true);
93  connect(m_doneTimer, SIGNAL(timeout()), this, SLOT(updateTotalsChanged()));
94 
95  setUrl(KUrl(), KUrl());
96 }
97 
98 
99 ProjectModel::~ProjectModel()
100 {
101  m_dirsWaitingForMetadata.clear();
102 
103  if (m_activeJob != NULL)
104  m_activeJob->setStatus(-2);
105 
106  m_activeJob = NULL;
107 
108  for (int pos = 0; pos < m_rootNode.rows.count(); pos ++)
109  deleteSubtree(m_rootNode.rows.at(pos));
110 }
111 
112 void ProjectModel::setUrl(const KUrl &poUrl, const KUrl &potUrl)
113 {
114  //kDebug() << "ProjectModel::openUrl("<< poUrl.pathOrUrl() << +", " << potUrl.pathOrUrl() << ")";
115 
116  //cleanup old data
117 
118  m_dirsWaitingForMetadata.clear();
119 
120  if (m_activeJob != NULL)
121  m_activeJob->setStatus(-1);
122  m_activeJob = NULL;
123 
124  if (m_rootNode.rows.count())
125  {
126  beginRemoveRows(QModelIndex(), 0, m_rootNode.rows.count());
127 
128  for (int pos = 0; pos < m_rootNode.rows.count(); pos ++)
129  deleteSubtree(m_rootNode.rows.at(pos));
130  m_rootNode.rows.clear();
131  m_rootNode.poCount = 0;
132  m_rootNode.translated = -1;
133  m_rootNode.translated_reviewer = -1;
134  m_rootNode.translated_approver = -1;
135  m_rootNode.untranslated = -1;
136  m_rootNode.fuzzy = -1;
137  m_rootNode.fuzzy_reviewer = -1;
138  m_rootNode.fuzzy_approver = -1;
139 
140  endRemoveRows();
141  }
142 
143  //add trailing slashes to base URLs, needed for potToPo and poToPot
144  m_poUrl = poUrl;
145  m_potUrl = potUrl;
146  m_poUrl.adjustPath(KUrl::AddTrailingSlash);
147  m_potUrl.adjustPath(KUrl::AddTrailingSlash);
148 
149  emit loading();
150 
151  if (!poUrl.isEmpty())
152  m_poModel.dirLister()->openUrl(m_poUrl, KDirLister::Reload);
153  if (!potUrl.isEmpty())
154  m_potModel.dirLister()->openUrl(m_potUrl, KDirLister::Reload);
155 }
156 
157 
158 KUrl ProjectModel::beginEditing(const QModelIndex& index)
159 {
160  Q_ASSERT(index.isValid());
161 
162  QModelIndex poIndex = poIndexForOuter(index);
163  QModelIndex potIndex = potIndexForOuter(index);
164 
165  if (poIndex.isValid())
166  {
167  KFileItem item = m_poModel.itemForIndex(poIndex);
168  return item.url();
169  }
170  else if (potIndex.isValid())
171  {
172  //copy over the file
173  KUrl potFile = m_potModel.itemForIndex(potIndex).url();
174  KUrl poFile = potToPo(potFile);
175 
176  //EditorTab::fileOpen takes care of this
177  //be careful, copy only if file does not exist already.
178  // if (!KIO::NetAccess::exists(poFile, KIO::NetAccess::DestinationSide, NULL))
179  // KIO::NetAccess::file_copy(potFile, poFile);
180 
181  return poFile;
182  }
183  else
184  {
185  Q_ASSERT(false);
186  return KUrl();
187  }
188 }
189 
190 //Theese methds update the combined model from POT and PO model changes.
191 //Quite complex stuff here, better do not change anything.
192 
193 void ProjectModel::po_dataChanged(const QModelIndex& po_topLeft, const QModelIndex& po_bottomRight)
194 {
195  //nothing special here
196  //map from source and propagate
197  QModelIndex topLeft = indexForPoIndex(po_topLeft);
198  QModelIndex bottomRight = indexForPoIndex(po_bottomRight);
199 
200  emit dataChanged(topLeft, bottomRight);
201 
202  enqueueNodeForMetadataUpdate(nodeForIndex(topLeft.parent()));
203 }
204 
205 void ProjectModel::pot_dataChanged(const QModelIndex& pot_topLeft, const QModelIndex& pot_bottomRight)
206 {
207  //tricky here - some of the pot items may be represented by po items
208  //let's propagate that all subitems changed
209 
210 
211  QModelIndex pot_parent = pot_topLeft.parent();
212  QModelIndex parent = indexForPotIndex(pot_parent);
213 
214  ProjectNode* node = nodeForIndex(parent);
215  int count = node->rows.count();
216 
217  QModelIndex topLeft = index(0, pot_topLeft.column(), parent);
218  QModelIndex bottomRight = index(count-1, pot_bottomRight.column(), parent);
219 
220  emit dataChanged(topLeft, bottomRight);
221 
222  enqueueNodeForMetadataUpdate(nodeForIndex(topLeft.parent()));
223 }
224 
225 
226 void ProjectModel::po_rowsInserted(const QModelIndex& po_parent, int first, int last)
227 {
228  QModelIndex parent = indexForPoIndex(po_parent);
229  QModelIndex pot_parent = potIndexForOuter(parent);
230  ProjectNode* node = nodeForIndex(parent);
231 
232  //insert po rows
233  beginInsertRows(parent, first, last);
234 
235  for (int pos = first; pos <= last; pos ++)
236  {
237  ProjectNode * childNode = new ProjectNode(node, pos, pos, -1);
238  node->rows.insert(pos, childNode);
239  }
240 
241  node->poCount += last - first + 1;
242 
243  //update rowNumber
244  for (int pos = last + 1; pos < node->rows.count(); pos++)
245  node->rows[pos]->rowNumber = pos;
246 
247  endInsertRows();
248 
249  //remove unneeded pot rows, update PO rows
250  if (pot_parent.isValid() || !parent.isValid())
251  {
252  QVector<int> pot2PoMapping;
253  generatePOTMapping(pot2PoMapping, po_parent, pot_parent);
254 
255  for (int pos = node->poCount; pos < node->rows.count(); pos ++)
256  {
257  ProjectNode* potNode = node->rows.at(pos);
258  int potIndex = potNode->potRowNumber;
259  int poIndex = pot2PoMapping[potIndex];
260 
261  if (poIndex != -1)
262  {
263  //found pot node, that now has a PO index.
264  //remove the pot node and change the corresponding PO node
265  beginRemoveRows(parent, pos, pos);
266  node->rows.remove(pos);
267  deleteSubtree(potNode);
268  endRemoveRows();
269 
270  node->rows[poIndex]->potRowNumber = potIndex;
271  //This change does not need notification
272  //dataChanged(index(poIndex, 0, parent), index(poIndex, ProjectModelColumnCount, parent));
273 
274  pos--;
275  }
276  }
277  }
278 
279  enqueueNodeForMetadataUpdate(node);
280 }
281 
282 
283 void ProjectModel::pot_rowsInserted(const QModelIndex& pot_parent, int start, int end)
284 {
285  QModelIndex parent = indexForPotIndex(pot_parent);
286  QModelIndex po_parent = poIndexForOuter(parent);
287  ProjectNode* node = nodeForIndex(parent);
288 
289  int insertedCount = end + 1 - start;
290  QVector<int> newPotNodes;
291 
292  if (po_parent.isValid() || !parent.isValid())
293  {
294  //this node containts mixed items - add and merge the stuff
295 
296  QVector<int> pot2PoMapping;
297  generatePOTMapping(pot2PoMapping, po_parent, pot_parent);
298 
299  //reassign affected PO row POT indices
300  for (int pos = 0; pos < node->poCount;pos ++)
301  {
302  ProjectNode* n=node->rows[pos];
303  if (n->potRowNumber >= start)
304  n->potRowNumber += insertedCount;
305  }
306 
307  //assign new POT indices
308  for (int potIndex = start; potIndex <= end; potIndex ++)
309  {
310  int poIndex = pot2PoMapping[potIndex];
311  if (poIndex != -1)
312  {
313  //found pot node, that has a PO index.
314  //change the corresponding PO node
315  node->rows[poIndex]->potRowNumber = potIndex;
316  //This change does not need notification
317  //dataChanged(index(poIndex, 0, parent), index(poIndex, ProjectModelColumnCount, parent));
318  }
319  else
320  newPotNodes.append(potIndex);
321  }
322  }
323  else
324  {
325  for (int pos = start; pos < end; pos ++)
326  newPotNodes.append(pos);
327  }
328 
329  //insert standalone POT rows, preserving POT order
330 
331  int newNodesCount = newPotNodes.count();
332  if (newNodesCount)
333  {
334  int insertionPoint = node->poCount;
335  while ((insertionPoint < node->rows.count()) && (node->rows[insertionPoint]->potRowNumber < start))
336  insertionPoint++;
337 
338  beginInsertRows(parent, insertionPoint, insertionPoint + newNodesCount - 1);
339 
340  for (int pos = 0; pos < newNodesCount; pos ++)
341  {
342  int potIndex = newPotNodes.at(pos);
343  ProjectNode * childNode = new ProjectNode(node, insertionPoint, -1, potIndex);
344  node->rows.insert(insertionPoint, childNode);
345  insertionPoint++;
346  }
347 
348  //renumber remaining POT rows
349  for (int pos = insertionPoint; pos < node->rows.count(); pos ++)
350  {
351  node->rows[pos]->rowNumber = pos;
352  node->rows[pos]->potRowNumber += insertedCount;
353  }
354 
355  endInsertRows();
356  }
357 
358  enqueueNodeForMetadataUpdate(node);
359 }
360 
361 void ProjectModel::po_rowsRemoved(const QModelIndex& po_parent, int start, int end)
362 {
363  QModelIndex parent = indexForPoIndex(po_parent);
364  QModelIndex pot_parent = potIndexForOuter(parent);
365  ProjectNode* node = nodeForIndex(parent);
366  int removedCount = end + 1 - start;
367 
368  if ((!parent.isValid()) && (node->rows.count() == 0))
369  {
370  //events after removing entire contents
371  return;
372  }
373 
374  //remove PO rows
375  QList<int> potRowsToInsert;
376 
377  beginRemoveRows(parent, start, end);
378 
379  //renumber all rows after removed.
380  for (int pos = end + 1; pos < node->rows.count(); pos ++)
381  {
382  ProjectNode* childNode = node->rows.at(pos);
383  childNode->rowNumber -= removedCount;
384 
385  if (childNode->poRowNumber > end)
386  node->rows[pos]->poRowNumber -= removedCount;
387  }
388 
389  //remove
390  for (int pos = end; pos >= start; pos --)
391  {
392  int potIndex = node->rows.at(pos)->potRowNumber;
393  deleteSubtree(node->rows.at(pos));
394  node->rows.remove(pos);
395 
396  if (potIndex != -1)
397  potRowsToInsert.append(potIndex);
398  }
399 
400 
401  node->poCount -= removedCount;
402 
403  endRemoveRows(); //< fires removed event - the list has to be consistent now
404 
405  //add back rows that have POT files and fix row order
406  qSort(potRowsToInsert.begin(), potRowsToInsert.end());
407 
408  int insertionPoint = node->poCount;
409 
410  for (int pos = 0; pos < potRowsToInsert.count(); pos ++)
411  {
412  int potIndex = potRowsToInsert.at(pos);
413  while (insertionPoint < node->rows.count() && node->rows[insertionPoint]->potRowNumber < potIndex)
414  {
415  node->rows[insertionPoint]->rowNumber = insertionPoint;
416  insertionPoint ++;
417  }
418 
419  beginInsertRows(parent, insertionPoint, insertionPoint);
420 
421  ProjectNode * childNode = new ProjectNode(node, insertionPoint, -1, potIndex);
422  node->rows.insert(insertionPoint, childNode);
423  insertionPoint++;
424  endInsertRows();
425  }
426 
427  //renumber remaining rows
428  while (insertionPoint < node->rows.count())
429  {
430  node->rows[insertionPoint]->rowNumber = insertionPoint;
431  insertionPoint++;
432  }
433 
434  enqueueNodeForMetadataUpdate(node);
435 }
436 
437 
438 void ProjectModel::pot_rowsRemoved(const QModelIndex& pot_parent, int start, int end)
439 {
440  QModelIndex parent = indexForPotIndex(pot_parent);
441  QModelIndex po_parent = poIndexForOuter(parent);
442  ProjectNode * node = nodeForIndex(parent);
443  int removedCount = end + 1 - start;
444 
445  if ((!parent.isValid()) && (node->rows.count() == 0))
446  {
447  //events after removing entire contents
448  return;
449  }
450 
451  //First remove POT nodes
452 
453  int firstPOTToRemove = node->poCount;
454  int lastPOTToRemove = node->rows.count() - 1;
455 
456  while (firstPOTToRemove <= lastPOTToRemove && node->rows[firstPOTToRemove]->potRowNumber < start)
457  firstPOTToRemove ++;
458  while (lastPOTToRemove >= firstPOTToRemove && node->rows[lastPOTToRemove]->potRowNumber > end)
459  lastPOTToRemove --;
460 
461  if (firstPOTToRemove <= lastPOTToRemove)
462  {
463  beginRemoveRows(parent, firstPOTToRemove, lastPOTToRemove);
464 
465  for (int pos = lastPOTToRemove; pos >= firstPOTToRemove; pos --)
466  {
467  ProjectNode* childNode = node->rows.at(pos);
468  Q_ASSERT(childNode->potRowNumber >= start);
469  Q_ASSERT(childNode->potRowNumber <= end);
470  deleteSubtree(childNode);
471  node->rows.remove(pos);
472  }
473 
474  //renumber remaining rows
475  for (int pos = firstPOTToRemove; pos < node->rows.count(); pos ++)
476  {
477  node->rows[pos]->rowNumber = pos;
478  node->rows[pos]->potRowNumber -= removedCount;
479  }
480 
481  endRemoveRows();
482  }
483 
484  //now remove POT indices form PO rows
485 
486  if (po_parent.isValid() || !parent.isValid())
487  {
488  for (int poIndex = 0; poIndex < node->poCount; poIndex ++)
489  {
490  ProjectNode * childNode = node->rows[poIndex];
491  int potIndex = childNode->potRowNumber;
492 
493  if (potIndex >= start && potIndex <= end)
494  {
495  //found PO node, that has a POT index in range.
496  //change the corresponding PO node
497  node->rows[poIndex]->potRowNumber = -1;
498  //this change does not affect the model
499  //dataChanged(index(poIndex, 0, parent), index(poIndex, ProjectModelColumnCount, parent));
500  }
501  else if (childNode->potRowNumber > end)
502  {
503  //reassign POT indices
504  childNode->potRowNumber -= removedCount;
505  }
506  }
507  }
508 
509  enqueueNodeForMetadataUpdate(node);
510 }
511 
512 
513 int ProjectModel::columnCount(const QModelIndex& /*parent*/)const
514 {
515  return ProjectModelColumnCount;
516 }
517 
518 
519 QVariant ProjectModel::headerData(int section, Qt::Orientation, int role) const
520 {
521  if (role!=Qt::DisplayRole)
522  return QVariant();
523 
524  switch (section)
525  {
526  case FileName: return i18nc("@title:column File name","Name");
527  case Graph: return i18nc("@title:column Graphical representation of Translated/Fuzzy/Untranslated counts","Graph");
528  case TotalCount: return i18nc("@title:column Number of entries","Total");
529  case TranslatedCount: return i18nc("@title:column Number of entries","Translated");
530  case FuzzyCount: return i18nc("@title:column Number of entries","Not ready");
531  case UntranslatedCount: return i18nc("@title:column Number of entries","Untranslated");
532  case TranslationDate: return i18nc("@title:column","Last Translation");
533  case SourceDate: return i18nc("@title:column","Template Revision");
534  case LastTranslator: return i18nc("@title:column","Last Translator");
535  default: return QVariant();
536  }
537 }
538 
539 
540 Qt::ItemFlags ProjectModel::flags( const QModelIndex & index ) const
541 {
542  if (index.column() == FileName)
543  return Qt::ItemIsSelectable|Qt::ItemIsEnabled;
544  else
545  return Qt::ItemIsSelectable;
546 }
547 
548 
549 int ProjectModel::rowCount ( const QModelIndex & parent /*= QModelIndex()*/ ) const
550 {
551  return nodeForIndex(parent)->rows.size();
552 }
553 
554 
555 bool ProjectModel::hasChildren ( const QModelIndex & parent /*= QModelIndex()*/ ) const
556 {
557  if (!parent.isValid())
558  return true;
559 
560  QModelIndex poIndex = poIndexForOuter(parent);
561  QModelIndex potIndex = potIndexForOuter(parent);
562 
563  return ((poIndex.isValid() && m_poModel.hasChildren(poIndex)) ||
564  (potIndex.isValid() && m_potModel.hasChildren(potIndex)));
565 }
566 
567 bool ProjectModel::canFetchMore ( const QModelIndex & parent ) const
568 {
569  if (!parent.isValid())
570  return m_poModel.canFetchMore(QModelIndex()) || m_potModel.canFetchMore(QModelIndex());
571 
572  QModelIndex poIndex = poIndexForOuter(parent);
573  QModelIndex potIndex = potIndexForOuter(parent);
574 
575  return ((poIndex.isValid() && m_poModel.canFetchMore(poIndex)) ||
576  (potIndex.isValid() && m_potModel.canFetchMore(potIndex)));
577 }
578 
579 void ProjectModel::fetchMore ( const QModelIndex & parent )
580 {
581  if (!parent.isValid())
582  {
583  if (m_poModel.canFetchMore(QModelIndex()))
584  m_poModel.fetchMore(QModelIndex());
585 
586  if (m_potModel.canFetchMore(QModelIndex()))
587  m_potModel.fetchMore(QModelIndex());
588  }
589  else
590  {
591  QModelIndex poIndex = poIndexForOuter(parent);
592  QModelIndex potIndex = potIndexForOuter(parent);
593 
594  if (poIndex.isValid() && (m_poModel.canFetchMore(poIndex)))
595  m_poModel.fetchMore(poIndex);
596 
597  if (potIndex.isValid() && (m_potModel.canFetchMore(potIndex)))
598  m_potModel.fetchMore(potIndex);
599  }
600 }
601 
602 
603 
611 QVariant ProjectModel::data(const QModelIndex& index, int role) const
612 {
613  if (!index.isValid())
614  return QVariant();
615 
616  const ProjectModelColumns& column=(ProjectModelColumns)index.column();
617  ProjectNode* node = nodeForIndex(index);
618  QModelIndex internalIndex = poOrPotIndexForOuter(index);
619 
620  if (!internalIndex.isValid())
621  return QVariant();
622 
623  KFileItem item=itemForIndex(index);
624  bool isDir = item.isDir();
625 
626  int translated = node->translatedAsPerRole();
627  int fuzzy = node->fuzzyAsPerRole();
628  int untranslated = node->untranslated;
629  bool hasStats = translated != -1;
630 
631  switch(role)
632  {
633  case Qt::DisplayRole:
634  switch (column)
635  {
636  case FileName: return item.text();
637  case Graph: return hasStats?QRect(translated, untranslated, fuzzy, 0):QVariant();
638  case TotalCount: return hasStats?(translated + untranslated + fuzzy):QVariant();
639  case TranslatedCount:return hasStats?translated:QVariant();
640  case FuzzyCount: return hasStats?fuzzy:QVariant();
641  case UntranslatedCount:return hasStats?untranslated:QVariant();
642  case SourceDate: return node->sourceDate;
643  case TranslationDate:return node->translationDate;
644  case LastTranslator:return node->lastTranslator;
645  default: return QVariant();
646  }
647  case Qt::ToolTipRole:
648  switch (column)
649  {
650  case FileName: return item.text();
651  default: return QVariant();
652  }
653  case KDirModel::FileItemRole:
654  return QVariant::fromValue(item);
655  case Qt::DecorationRole:
656  switch (column)
657  {
658  case FileName:
659  if (isDir)
660  return m_dirIcon;
661  if (hasStats && fuzzy == 0 && untranslated == 0)
662  return m_poComplIcon;
663  else if (node->poRowNumber != -1)
664  return m_poIcon;
665  else if (node->potRowNumber != -1)
666  return m_potIcon;
667  default:
668  return QVariant();
669  }
670  case FuzzyUntrCountRole:
671  return item.isFile()?(fuzzy + untranslated):0;
672  case FuzzyCountRole:
673  return item.isFile()?fuzzy:0;
674  case UntransCountRole:
675  return item.isFile()?untranslated:0;
676  case TemplateOnlyRole:
677  return item.isFile()?(node->poRowNumber == -1):0;
678  case TransOnlyRole:
679  return item.isFile()?(node->potRowNumber == -1):0;
680  case TotalRole:
681  return hasStats?(fuzzy + untranslated + translated):0;
682  default:
683  return QVariant();
684  }
685 }
686 
687 
688 QModelIndex ProjectModel::index(int row, int column, const QModelIndex& parent) const
689 {
690  ProjectNode* parentNode = nodeForIndex(parent);
691  //kWarning()<<(sizeof(ProjectNode))<<nodeCounter;
692  if (row>=parentNode->rows.size())
693  {
694  kWarning()<<"SHIT HAPPENED WITH INDEXES"<<row<<parentNode->rows.size()<<itemForIndex(parent).url();
695  return QModelIndex();
696  }
697  return createIndex(row, column, parentNode->rows.at(row));
698 }
699 
700 
701 KFileItem ProjectModel::itemForIndex(const QModelIndex& index) const
702 {
703  if (!index.isValid())
704  {
705  //file item for root node.
706  return m_poModel.itemForIndex(index);
707  }
708  QModelIndex poIndex = poIndexForOuter(index);
709 
710  if (poIndex.isValid())
711  return m_poModel.itemForIndex(poIndex);
712  else
713  {
714  QModelIndex potIndex = potIndexForOuter(index);
715 
716  if (potIndex.isValid())
717  return m_potModel.itemForIndex(potIndex);
718  }
719 
720  kWarning()<<"returning empty KFileItem()"<<index.row()<<index.column();
721  kWarning()<<"returning empty KFileItem()"<<index.parent().isValid();
722  kWarning()<<"returning empty KFileItem()"<<index.parent().internalPointer();
723  kWarning()<<"returning empty KFileItem()"<<index.parent().data().toString();
724  kWarning()<<"returning empty KFileItem()"<<index.internalPointer();
725  kWarning()<<"returning empty KFileItem()"<<static_cast<ProjectNode*>(index.internalPointer())->untranslated<<static_cast<ProjectNode*>(index.internalPointer())->sourceDate;
726  return KFileItem();
727 }
728 
729 
730 ProjectModel::ProjectNode* ProjectModel::nodeForIndex(const QModelIndex& index) const
731 {
732  if (index.isValid())
733  {
734  ProjectNode * node = static_cast<ProjectNode *>(index.internalPointer());
735  Q_ASSERT(node != NULL);
736  return node;
737  }
738  else
739  {
740  ProjectNode * node = const_cast<ProjectNode *>(&m_rootNode);
741  Q_ASSERT(node != NULL);
742  return node;
743  }
744 }
745 
746 
747 QModelIndex ProjectModel::indexForNode(const ProjectNode* node)
748 {
749  if (node == &m_rootNode)
750  return QModelIndex();
751 
752  int row = node->rowNumber;
753  QModelIndex index = createIndex(row, 0, (void*)node);
754  return index;
755 }
756 
757 QModelIndex ProjectModel::indexForUrl(const KUrl& url)
758 {
759  if (m_poUrl.isParentOf(url))
760  {
761  QModelIndex poIndex = m_poModel.indexForUrl(url);
762  return indexForPoIndex(poIndex);
763  }
764  else if (m_potUrl.isParentOf(url))
765  {
766  QModelIndex potIndex = m_potModel.indexForUrl(url);
767  return indexForPotIndex(potIndex);
768  }
769 
770  return QModelIndex();
771 }
772 
773 QModelIndex ProjectModel::parent(const QModelIndex& childIndex) const
774 {
775  if (!childIndex.isValid())
776  return QModelIndex();
777 
778  ProjectNode* childNode = nodeForIndex(childIndex);
779  ProjectNode* parentNode = childNode->parent;
780 
781  if (!parentNode || (childNode == &m_rootNode) || (parentNode == &m_rootNode))
782  return QModelIndex();
783 
784  return createIndex(parentNode->rowNumber, 0, parentNode);
785 }
786 
787 
792 QModelIndex ProjectModel::indexForOuter(const QModelIndex& outerIndex, IndexType type) const
793 {
794  if (!outerIndex.isValid())
795  return QModelIndex();
796 
797  QModelIndex parent = outerIndex.parent();
798 
799  QModelIndex internalParent;
800  if (parent.isValid())
801  {
802  internalParent = indexForOuter(parent, type);
803  if (!internalParent.isValid())
804  return QModelIndex();
805  }
806 
807  ProjectNode* node = nodeForIndex(outerIndex);
808 
809  short rowNumber=(type==PoIndex?node->poRowNumber:node->potRowNumber);
810  if (rowNumber == -1)
811  return QModelIndex();
812  return (type==PoIndex?m_poModel:m_potModel).index(rowNumber, outerIndex.column(), internalParent);
813 }
814 
815 QModelIndex ProjectModel::poIndexForOuter(const QModelIndex& outerIndex) const
816 {
817  return indexForOuter(outerIndex, PoIndex);
818 }
819 
820 
821 QModelIndex ProjectModel::potIndexForOuter(const QModelIndex& outerIndex) const
822 {
823  return indexForOuter(outerIndex, PotIndex);
824 }
825 
826 
827 QModelIndex ProjectModel::poOrPotIndexForOuter(const QModelIndex& outerIndex) const
828 {
829  if (!outerIndex.isValid())
830  return QModelIndex();
831 
832  QModelIndex poIndex = poIndexForOuter(outerIndex);
833 
834  if (poIndex.isValid())
835  return poIndex;
836 
837  QModelIndex potIndex = potIndexForOuter(outerIndex);
838 
839  if (!potIndex.isValid())
840  kWarning()<<"error mapping index to PO or POT";
841 
842  return potIndex;
843 }
844 
845 QModelIndex ProjectModel::indexForPoIndex(const QModelIndex& poIndex) const
846 {
847  if (!poIndex.isValid())
848  return QModelIndex();
849 
850  QModelIndex outerParent = indexForPoIndex(poIndex.parent());
851  int row = poIndex.row(); //keep the same row, no changes
852 
853  return index(row, poIndex.column(), outerParent);
854 }
855 
856 QModelIndex ProjectModel::indexForPotIndex(const QModelIndex& potIndex) const
857 {
858  if (!potIndex.isValid())
859  return QModelIndex();
860 
861  QModelIndex outerParent = indexForPotIndex(potIndex.parent());
862  ProjectNode* node = nodeForIndex(outerParent);
863 
864  int potRow = potIndex.row();
865  int row = 0;
866 
867  while(row<node->rows.count() && node->rows.at(row)->potRowNumber!=potRow)
868  row++;
869 
870  if (row != node->rows.count())
871  return index(row, potIndex.column(), outerParent);
872 
873  kWarning()<<"error mapping index from POT to outer, searched for potRow:"<<potRow;
874  return QModelIndex();
875 }
876 
877 
883 void ProjectModel::generatePOTMapping(QVector<int> & result, const QModelIndex& poParent, const QModelIndex& potParent) const
884 {
885  result.clear();
886 
887  int poRows = m_poModel.rowCount(poParent);
888  int potRows = m_potModel.rowCount(potParent);
889 
890  if (potRows == 0)
891  return;
892 
893  QList<KUrl> poOccupiedUrls;
894 
895  for (int poPos = 0; poPos < poRows; poPos ++)
896  {
897  KFileItem file = m_poModel.itemForIndex(m_poModel.index(poPos, 0, poParent));
898  KUrl potUrl = poToPot(file.url());
899  poOccupiedUrls.append(potUrl);
900  }
901 
902  for (int potPos = 0; potPos < potRows; potPos ++)
903  {
904 
905  KUrl potUrl = m_potModel.itemForIndex(m_potModel.index(potPos, 0, potParent)).url();
906  int occupiedPos = -1;
907 
908  //TODO: this is slow
909  for (int poPos = 0; occupiedPos == -1 && poPos < poOccupiedUrls.count(); poPos ++)
910  {
911  KUrl& occupiedUrl = poOccupiedUrls[poPos];
912  if (potUrl.equals(occupiedUrl))
913  occupiedPos = poPos;
914  }
915 
916  result.append(occupiedPos);
917  }
918 }
919 
920 
921 KUrl ProjectModel::poToPot(const KUrl& poPath) const
922 {
923  if (!m_poUrl.isParentOf(poPath))
924  {
925  kWarning()<<"PO path not in project: " << poPath.url();
926  return KUrl();
927  }
928 
929  QString pathToAdd = KUrl::relativeUrl(m_poUrl, poPath);
930 
931  //change ".po" into ".pot"
932  if (pathToAdd.endsWith(".po")) //TODO: what about folders ??
933  pathToAdd+='t';
934 
935  KUrl potPath = m_potUrl;
936  potPath.addPath(pathToAdd);
937 
938  //kDebug() << "ProjectModel::poToPot("<< poPath.pathOrUrl() << +") = " << potPath.pathOrUrl();
939  return potPath;
940 }
941 
942 KUrl ProjectModel::potToPo(const KUrl& potPath) const
943 {
944  if (!m_potUrl.isParentOf(potPath))
945  {
946  kWarning()<<"POT path not in project: " << potPath.url();
947  return KUrl();
948  }
949 
950  QString pathToAdd = KUrl::relativeUrl(m_potUrl, potPath);
951 
952  //change ".pot" into ".po"
953  if (pathToAdd.endsWith(".pot")) //TODO: what about folders ??
954  pathToAdd = pathToAdd.left(pathToAdd.length() - 1);
955 
956  KUrl poPath = m_poUrl;
957  poPath.addPath(pathToAdd);
958 
959  //kDebug() << "ProjectModel::potToPo("<< potPath.pathOrUrl() << +") = " << poPath.pathOrUrl();
960  return poPath;
961 }
962 
963 
964 //Metadata stuff
965 //For updating translation stats
966 
967 void ProjectModel::enqueueNodeForMetadataUpdate(ProjectNode* node)
968 {
969  m_doneTimer->stop();
970 
971  if (m_dirsWaitingForMetadata.contains(node))
972  {
973  if ((m_activeJob != NULL) && (m_activeNode == node))
974  m_activeJob->setStatus(-1);
975 
976  return;
977  }
978 
979  m_dirsWaitingForMetadata.insert(node);
980 
981  if (m_activeJob == NULL)
982  startNewMetadataJob();
983 }
984 
985 
986 void ProjectModel::deleteSubtree(ProjectNode* node)
987 {
988  for (int row = 0; row < node->rows.count(); row ++)
989  deleteSubtree(node->rows.at(row));
990 
991  m_dirsWaitingForMetadata.remove(node);
992 
993  if ((m_activeJob != NULL) && (m_activeNode == node))
994  m_activeJob->setStatus(-1);
995 
996  delete node;
997 }
998 
999 
1000 void ProjectModel::startNewMetadataJob()
1001 {
1002  if (!m_completeScan) //hack for debugging
1003  return;
1004 
1005  m_activeJob = NULL;
1006  m_activeNode = NULL;
1007 
1008  if (m_dirsWaitingForMetadata.isEmpty())
1009  return;
1010 
1011  ProjectNode* node = *m_dirsWaitingForMetadata.begin();
1012 
1013  //prepare new work
1014  m_activeNode = node;
1015 
1016  QList<KFileItem> files;
1017 
1018  QModelIndex item = indexForNode(node);
1019 
1020  for (int row=0; row < node->rows.count(); row ++)
1021  files.append(itemForIndex(index(row, 0, item)));
1022 
1023  m_activeJob = new UpdateStatsJob(files, this);
1024  connect(
1025  m_activeJob,SIGNAL(done(ThreadWeaver::Job*)),
1026  this,SLOT(finishMetadataUpdate(ThreadWeaver::Job*)));
1027 
1028  m_weaver->enqueue(m_activeJob);
1029 }
1030 
1031 void ProjectModel::finishMetadataUpdate(ThreadWeaver::Job * _job)
1032 {
1033  UpdateStatsJob* job = static_cast<UpdateStatsJob *>(_job);
1034 
1035  if (job->m_status == -2)
1036  {
1037  delete job;
1038  return;
1039  }
1040 
1041  if ((m_dirsWaitingForMetadata.contains(m_activeNode)) && (job->m_status == 0))
1042  {
1043  m_dirsWaitingForMetadata.remove(m_activeNode);
1044  //store the results
1045 
1046  setMetadataForDir(m_activeNode, m_activeJob->m_info);
1047 
1048  QModelIndex item = indexForNode(m_activeNode);
1049 
1050  //scan dubdirs - initiate data loading into the model.
1051  for (int row=0; row < m_activeNode->rows.count(); row++)
1052  {
1053  QModelIndex child = index(row, 0, item);
1054 
1055  if (canFetchMore(child))
1056  fetchMore(child);
1057  //QCoreApplication::processEvents();
1058  }
1059  }
1060 
1061  delete m_activeJob;
1062 
1063  startNewMetadataJob();
1064 }
1065 
1066 
1067 void ProjectModel::slotFileSaved(const KUrl& url)
1068 {
1069  QModelIndex index = indexForUrl(url);
1070 
1071  if (!index.isValid())
1072  return;
1073 
1074  QList<KFileItem> files;
1075  files.append(itemForIndex(index));
1076 
1077  UpdateStatsJob* j = new UpdateStatsJob(files);
1078  connect(j,SIGNAL(done(ThreadWeaver::Job*)),
1079  this,SLOT(finishSingleMetadataUpdate(ThreadWeaver::Job*)));
1080 
1081  m_weaver->enqueue(j);
1082 }
1083 
1084 void ProjectModel::finishSingleMetadataUpdate(ThreadWeaver::Job* _job)
1085 {
1086  UpdateStatsJob* job = static_cast<UpdateStatsJob*>(_job);
1087 
1088  if (job->m_status != 0)
1089  {
1090  delete job;
1091  return;
1092  }
1093 
1094  const KFileMetaInfo& info=job->m_info.first();
1095  QModelIndex index = indexForUrl(info.url());
1096  if (!index.isValid())
1097  return;
1098 
1099  ProjectNode* node = nodeForIndex(index);
1100  node->setFileStats(job->m_info.first());
1101  updateDirStats(nodeForIndex(index.parent()));
1102 
1103  QModelIndex topLeft = index.sibling(index.row(), Graph);
1104  QModelIndex bottomRight = index.sibling(index.row(), ProjectModelColumnCount - 1);
1105  emit dataChanged(topLeft, bottomRight);
1106 
1107  delete job;
1108 }
1109 
1110 void ProjectModel::setMetadataForDir(ProjectNode* node, const QList<KFileMetaInfo>& data)
1111 {
1112  int dataCount = data.count();
1113  int rowsCount = node->rows.count();
1114  Q_ASSERT(dataCount == rowsCount);
1115 
1116  for (int row = 0; row < rowsCount; row ++)
1117  node->rows[row]->setFileStats(data.at(row));
1118 
1119  if (!dataCount)
1120  return;
1121 
1122  updateDirStats(node);
1123 
1124  QModelIndex item = indexForNode(node);
1125  QModelIndex topLeft = index(0, Graph, item);
1126  QModelIndex bottomRight = index(rowsCount - 1, ProjectModelColumnCount - 1, item);
1127  emit dataChanged(topLeft, bottomRight);
1128 }
1129 
1130 void ProjectModel::updateDirStats(ProjectNode* node)
1131 {
1132  node->calculateDirStats();
1133  if (node == &m_rootNode)
1134  {
1135  updateTotalsChanged();
1136  return;
1137  }
1138 
1139  updateDirStats(node->parent);
1140 
1141  if (node->parent->rows.count()==0 || node->parent->rows.count()>=node->rowNumber)
1142  return;
1143  QModelIndex index = indexForNode(node);
1144  kWarning()<<index.row()<<node->parent->rows.count();
1145  if (index.row()>=node->parent->rows.count())
1146  return;
1147  QModelIndex topLeft = index.sibling(index.row(), Graph);
1148  QModelIndex bottomRight = index.sibling(index.row(), ProjectModelColumnCount - 1);
1149  emit dataChanged(topLeft, bottomRight);
1150 }
1151 
1152 bool ProjectModel::updateDone(const QModelIndex& index, const KDirModel& model)
1153 {
1154  if (model.canFetchMore(index))
1155  return false;
1156 
1157  int row=model.rowCount(index);
1158  while (--row>=0)
1159  {
1160  if (!updateDone(model.index(row, 0, index), model))
1161  return false;
1162  }
1163  return true;
1164 }
1165 
1166 void ProjectModel::updateTotalsChanged()
1167 {
1168  bool done = m_dirsWaitingForMetadata.isEmpty();
1169  if (done)
1170  {
1171  done = updateDone(m_poModel.indexForUrl(m_poUrl), m_poModel) &&
1172  updateDone(m_potModel.indexForUrl(m_potUrl), m_potModel);
1173  if (m_rootNode.fuzzyAsPerRole() + m_rootNode.translatedAsPerRole() + m_rootNode.untranslated > 0 && !done)
1174  m_doneTimer->start(2000);
1175  }
1176  emit totalsChanged(m_rootNode.fuzzyAsPerRole(), m_rootNode.translatedAsPerRole(), m_rootNode.untranslated, done);
1177 }
1178 
1179 
1180 //ProjectNode class
1181 
1182 ProjectModel::ProjectNode::ProjectNode(ProjectNode* _parent, int _rowNum, int _poIndex, int _potIndex)
1183  : parent(_parent)
1184  , rowNumber(_rowNum)
1185  , poRowNumber(_poIndex)
1186  , potRowNumber(_potIndex)
1187  , poCount(0)
1188  , translated(-1)
1189  , translated_reviewer(-1)
1190  , translated_approver(-1)
1191  , untranslated(-10)
1192  , fuzzy(-1)
1193  , fuzzy_reviewer(-10)
1194  , fuzzy_approver(-10)
1195 {
1196  ++nodeCounter;
1197 }
1198 
1199 ProjectModel::ProjectNode::~ProjectNode()
1200 {
1201  --nodeCounter;
1202 }
1203 
1204 void ProjectModel::ProjectNode::calculateDirStats()
1205 {
1206  fuzzy = 0;
1207  fuzzy_reviewer = 0;
1208  fuzzy_approver = 0;
1209  translated = 0;
1210  translated_reviewer = 0;
1211  translated_approver = 0;
1212  untranslated = 0;
1213 
1214  for (int pos = 0; pos < rows.count(); pos++)
1215  {
1216  ProjectNode* child = rows.at(pos);
1217  if (child->translated != -1)
1218  {
1219  fuzzy += child->fuzzy;
1220  fuzzy_reviewer += child->fuzzy_reviewer;
1221  fuzzy_approver += child->fuzzy_approver;
1222  translated += child->translated;
1223  translated_reviewer += child->translated_reviewer;
1224  translated_approver += child->translated_approver;
1225  untranslated += child->untranslated;
1226  }
1227  }
1228 }
1229 
1230 
1231 void ProjectModel::ProjectNode::setFileStats(const KFileMetaInfo& info)
1232 {
1233  if (info.keys().count() == 0)
1234  return;
1235 
1236  translated = info.item("translation.translated").value().toInt();
1237  const QVariant translated_reviewer_variant = info.item("translation.translated_reviewer").value();
1238  translated_reviewer = translated_reviewer_variant.isValid() ? translated_reviewer_variant.toInt() : translated;
1239  const QVariant translated_approver_variant = info.item("translation.translated_approver").value();
1240  translated_approver = translated_approver_variant.isValid() ? translated_approver_variant.toInt() : translated;
1241  untranslated = info.item("translation.untranslated").value().toInt();
1242  fuzzy = info.item("translation.fuzzy").value().toInt();
1243  const QVariant fuzzy_reviewer_variant = info.item("translation.fuzzy_reviewer").value();
1244  fuzzy_reviewer = fuzzy_reviewer_variant.isValid() ? fuzzy_reviewer_variant.toInt() : fuzzy;
1245  const QVariant fuzzy_approver_variant = info.item("translation.fuzzy_approver").value();
1246  fuzzy_approver = fuzzy_approver_variant.isValid() ? fuzzy_approver_variant.toInt() : fuzzy;
1247  lastTranslator = info.item("translation.last_translator").value().toString();
1248  sourceDate = info.item("translation.source_date").value().toString();
1249  translationDate = info.item("translation.translation_date").value().toString();
1250  lastTranslator.squeeze();
1251  sourceDate.squeeze();
1252  translationDate.squeeze();
1253 }
1254 
1255 
1256 //BEGIN UpdateStatsJob
1257 //these are run in separate thread
1258 UpdateStatsJob::UpdateStatsJob(QList<KFileItem> files, QObject* owner)
1259  : ThreadWeaver::Job(owner)
1260  , m_files(files)
1261  , m_status(0)
1262 {
1263 }
1264 
1265 UpdateStatsJob::~UpdateStatsJob()
1266 {
1267 }
1268 
1269 static void initDataBase(QSqlDatabase& db)
1270 {
1271  QSqlQuery queryMain(db);
1272  queryMain.exec("PRAGMA encoding = \"UTF-8\"");
1273  queryMain.exec("CREATE TABLE IF NOT EXISTS metainfo ("
1274  "filepath INTEGER PRIMARY KEY ON CONFLICT REPLACE, "// AUTOINCREMENT,"
1275  //"filepath TEXT UNIQUE ON CONFLICT REPLACE, "
1276  "metainfo BLOB, "//XLIFF markup info, see catalog/catalogstring.h catalog/xliff/*
1277  "changedate INTEGER"
1278  ")");
1279 
1280  //queryMain.exec("CREATE INDEX IF NOT EXISTS filepath_index ON metainfo ("filepath)");
1281 }
1282 
1283 
1284 static KFileMetaInfo cachedMetaInfo(const KFileItem& file)
1285 {
1286  QString dbName="metainfocache";
1287  if (!QSqlDatabase::contains(dbName))
1288  {
1289  QSqlDatabase db=QSqlDatabase::addDatabase("QSQLITE",dbName);
1290  db.setDatabaseName(KStandardDirs::locateLocal("appdata", dbName+".sqlite"));
1291  if (KDE_ISUNLIKELY( !db.open() ))
1292  return KFileMetaInfo(file.url());
1293  initDataBase(db);
1294  }
1295  QSqlDatabase db=QSqlDatabase::database(dbName);
1296  if (!db.isOpen())
1297  return KFileMetaInfo(file.url());
1298 
1299  static const QString fields[]={
1300  "translation.translated",
1301  "translation.untranslated",
1302  "translation.fuzzy",
1303  "translation.last_translator",
1304  "translation.source_date",
1305  "translation.translation_date",
1306  "translation.translated_reviewer",
1307  "translation.translated_approver",
1308  "translation.fuzzy_reviewer",
1309  "translation.fuzzy_approver"
1310  };
1311  static const int nFields = sizeof(fields) / sizeof(fields[0]);
1312 
1313  QByteArray result;
1314 
1315  QSqlQuery queryCache(db);
1316  queryCache.prepare("SELECT * from metainfo where filepath=?");
1317  queryCache.bindValue(0, qHash(file.localPath()));
1318  queryCache.exec();
1319  if (queryCache.next() && file.time(KFileItem::ModificationTime).dateTime()==queryCache.value(2).toDateTime())
1320  {
1321  result=queryCache.value(1).toByteArray();
1322  QDataStream stream(&result,QIODevice::ReadOnly);
1323 
1324  //unfortunately direct KFileMetaInfo << operator doesn't work
1325  KFileMetaInfo info;
1326  QVector<QVariant> keys;
1327  stream>>keys;
1328  for(int i=0;i<keys.count();i++)
1329  info.item(fields[i]).setValue(keys.at(i));
1330  return info;
1331  }
1332 
1333  KFileMetaInfo info(file.url());
1334 
1335  QDataStream stream(&result,QIODevice::WriteOnly);
1336  //this is synced with ProjectModel::ProjectNode::setFileStats
1337  QVector<QVariant> keys(nFields);
1338  for(int i=0;i<nFields;i++)
1339  keys[i] = info.item(fields[i]).value();
1340  stream<<keys;
1341 
1342  QSqlQuery query(db);
1343 
1344  query.prepare("INSERT INTO metainfo (filepath, metainfo, changedate) "
1345  "VALUES (?, ?, ?)");
1346  query.bindValue(0, qHash(file.localPath()));
1347  query.bindValue(1, result);
1348  query.bindValue(2, file.time(KFileItem::ModificationTime).dateTime());
1349  if (KDE_ISUNLIKELY(!query.exec()))
1350  qWarning() <<"metainfo cache acquiring error: " <<query.lastError().text();
1351 
1352  return info;
1353 }
1354 
1355 void UpdateStatsJob::run()
1356 {
1357  static QString dbName="metainfocache";
1358  bool ok=QSqlDatabase::contains(dbName);
1359  if (ok)
1360  {
1361  QSqlDatabase db=QSqlDatabase::database(dbName);
1362  QSqlQuery queryBegin("BEGIN",db);
1363  }
1364  for (int pos=0; pos<m_files.count(); pos++)
1365  {
1366  if (m_status!=0)
1367  return;
1368 
1369  const KFileItem& file=m_files.at(pos);
1370  KFileMetaInfo info;
1371 
1372  if ((!file.isNull()) && (!file.isDir()))
1373  {
1374  //force population of metainfo, do not use the KFileItem default behavior
1375  if (file.metaInfo(false).keys().isEmpty())
1376  info=cachedMetaInfo(file);
1377  //info=KFileMetaInfo(file.url());
1378  else
1379  info=file.metaInfo(false);
1380  }
1381 
1382  m_info.append(info);
1383  }
1384  if (ok)
1385  {
1386  QSqlDatabase db=QSqlDatabase::database(dbName);
1387  {
1388  //braces are needed to avoid resource leak on close
1389  QSqlQuery queryEnd("END",db);
1390  }
1391  db.close();
1392  db.open();
1393  }
1394 }
1395 
1396 void UpdateStatsJob::setStatus(int status)
1397 {
1398  m_status=status;
1399 }
1400 //END UpdateStatsJob
1401 
1402 #include "projectmodel.moc"
ProjectModel::headerData
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
Definition: projectmodel.cpp:519
QObject::child
QObject * child(const char *objName, const char *inheritsClass, bool recursiveSearch) const
ProjectModel::beginEditing
KUrl beginEditing(const QModelIndex &index)
Definition: projectmodel.cpp:158
UpdateStatsJob::setStatus
void setStatus(int status)
Definition: projectmodel.cpp:1396
ProjectModel::totalsChanged
void totalsChanged(int fuzzy, int translated, int untranslated, bool done)
QModelIndex
QVariant::toByteArray
QByteArray toByteArray() const
project.h
ProjectModel::index
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const
Definition: projectmodel.cpp:688
ProjectModel::TotalRole
Definition: projectmodel.h:140
ProjectModel::TransOnlyRole
Definition: projectmodel.h:139
ProjectModel::FileName
Definition: projectmodel.h:122
ProjectModel::FuzzyUntrCountRole
Definition: projectmodel.h:135
QVector::append
void append(const T &value)
QByteArray
nodeCounter
static int nodeCounter
Definition: projectmodel.cpp:45
UpdateStatsJob::~UpdateStatsJob
~UpdateStatsJob()
Definition: projectmodel.cpp:1265
ProjectModel::hasChildren
bool hasChildren(const QModelIndex &parent=QModelIndex()) const
Definition: projectmodel.cpp:555
initDataBase
static void initDataBase(QSqlDatabase &db)
Definition: projectmodel.cpp:1269
QDataStream
QVariant::toDateTime
QDateTime toDateTime() const
QSqlQuery::exec
bool exec(const QString &query)
QList::at
const T & at(int i) const
QSqlDatabase::database
QSqlDatabase database(const QString &connectionName, bool open)
QVariant::value
T value() const
QSqlDatabase::addDatabase
QSqlDatabase addDatabase(const QString &type, const QString &connectionName)
ProjectModel::canFetchMore
bool canFetchMore(const QModelIndex &parent) const
Definition: projectmodel.cpp:567
QSet::insert
const_iterator insert(const T &value)
ProjectModel::flags
Qt::ItemFlags flags(const QModelIndex &index) const
Definition: projectmodel.cpp:540
ProjectModel::fetchMore
void fetchMore(const QModelIndex &parent)
Definition: projectmodel.cpp:579
QSqlDatabase
ProjectModel::TranslationDate
Definition: projectmodel.h:129
QVector::value
T value(int i) const
QSqlDatabase::contains
bool contains(const QString &connectionName)
QVector::clear
void clear()
QRect
QModelIndex::isValid
bool isValid() const
QSqlQuery::prepare
bool prepare(const QString &query)
QList::count
int count(const T &value) const
QList::append
void append(const T &value)
ProjectModel::columnCount
int columnCount(const QModelIndex &parent=QModelIndex()) const
Definition: projectmodel.cpp:513
QTimer
QVariant::toInt
int toInt(bool *ok) const
QAbstractItemModel::dataChanged
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
QAbstractItemModel::endInsertRows
void endInsertRows()
QSqlQuery::value
QVariant value(int index) const
QObject
QSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val, QFlags< QSql::ParamTypeFlag > paramType)
ProjectModel::ProjectModelColumns
ProjectModelColumns
Definition: projectmodel.h:120
UpdateStatsJob::m_files
QList< KFileItem > m_files
Definition: projectmodel.h:251
ProjectModel::setUrl
void setUrl(const KUrl &poUrl, const KUrl &potUrl)
Definition: projectmodel.cpp:112
QAbstractItemModel::beginRemoveRows
void beginRemoveRows(const QModelIndex &parent, int first, int last)
QSqlQuery
QModelIndex::row
int row() const
QSqlQuery::next
bool next()
ProjectModel::~ProjectModel
~ProjectModel()
Definition: projectmodel.cpp:99
QModelIndex::internalPointer
void * internalPointer() const
QString::endsWith
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const
ProjectModel::ProjectModelColumnCount
Definition: projectmodel.h:131
ProjectModel::UntransCountRole
Definition: projectmodel.h:137
ProjectModel::FuzzyCount
Definition: projectmodel.h:126
UpdateStatsJob::m_info
QList< KFileMetaInfo > m_info
Definition: projectmodel.h:252
ProjectModel::FuzzyCountRole
Definition: projectmodel.h:136
QList::first
T & first()
QSqlDatabase::open
bool open()
QString
QList< int >
QModelIndex::parent
QModelIndex parent() const
QAbstractItemModel::rowsRemoved
void rowsRemoved(const QModelIndex &parent, int start, int end)
ProjectModel::data
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
we use QRect to pass data through QVariant tunnel
Definition: projectmodel.cpp:611
ProjectModel::TemplateOnlyRole
Definition: projectmodel.h:138
QAbstractItemModel::createIndex
QModelIndex createIndex(int row, int column, void *ptr) const
QList::end
iterator end()
QSet::begin
iterator begin()
QSqlDatabase::isOpen
bool isOpen() const
QTimer::stop
void stop()
QVariant::fromValue
QVariant fromValue(const T &value)
ProjectModel::loading
void loading()
QSet::contains
bool contains(const T &value) const
QAbstractItemModel::beginInsertRows
void beginInsertRows(const QModelIndex &parent, int first, int last)
QVector::at
const T & at(int i) const
projectmodel.h
UpdateStatsJob::m_status
volatile int m_status
Definition: projectmodel.h:253
cachedMetaInfo
static KFileMetaInfo cachedMetaInfo(const KFileItem &file)
Definition: projectmodel.cpp:1284
qHash
uint qHash(const DocPos &key)
Definition: pos.h:116
QSet::remove
bool remove(const T &value)
QVector< int >
QModelIndex::data
QVariant data(int role) const
ProjectModel::LastTranslator
Definition: projectmodel.h:130
ProjectModel::ProjectModel
ProjectModel(QObject *parent)
Definition: projectmodel.cpp:51
QLatin1String
QModelIndex::sibling
QModelIndex sibling(int row, int column) const
UpdateStatsJob
Definition: projectmodel.h:241
QVector::count
int count(const T &value) const
QModelIndex::column
int column() const
QString::length
int length() const
QSqlQuery::lastError
QSqlError lastError() const
ProjectModel::indexForUrl
QModelIndex indexForUrl(const KUrl &url)
Definition: projectmodel.cpp:757
QSet::isEmpty
bool isEmpty() const
QAbstractItemModel
QString::left
QString left(int n) const
QTimer::start
void start(int msec)
QVariant::isValid
bool isValid() const
ProjectModel::TranslatedCount
Definition: projectmodel.h:125
UpdateStatsJob::UpdateStatsJob
UpdateStatsJob(QList< KFileItem > files, QObject *owner=0)
Definition: projectmodel.cpp:1258
QSqlError::text
QString text() const
QSqlDatabase::setDatabaseName
void setDatabaseName(const QString &name)
ProjectModel::SourceDate
Definition: projectmodel.h:128
ProjectModel::slotFileSaved
void slotFileSaved(const KUrl &)
Definition: projectmodel.cpp:1067
QAbstractItemModel::endRemoveRows
void endRemoveRows()
QSet::clear
void clear()
QAbstractItemModel::rowsInserted
void rowsInserted(const QModelIndex &parent, int start, int end)
ProjectModel::Graph
Definition: projectmodel.h:123
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject::parent
QObject * parent() const
QVariant::toString
QString toString() const
QList::begin
iterator begin()
UpdateStatsJob::run
void run()
Definition: projectmodel.cpp:1355
ProjectModel::rowCount
int rowCount(const QModelIndex &parent=QModelIndex()) const
Definition: projectmodel.cpp:549
ProjectModel::itemForIndex
KFileItem itemForIndex(const QModelIndex &index) const
Definition: projectmodel.cpp:701
QSqlDatabase::close
void close()
QTimer::setSingleShot
void setSingleShot(bool singleShot)
QVariant
ProjectModel::UntranslatedCount
Definition: projectmodel.h:127
ProjectModel::TotalCount
Definition: projectmodel.h:124
Qt::ItemFlags
typedef ItemFlags
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