1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Linguist of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#ifndef MESSAGEMODEL_H
30#define MESSAGEMODEL_H
31
32#include "translator.h"
33
34#include <QtCore/QAbstractItemModel>
35#include <QtCore/QList>
36#include <QtCore/QHash>
37#include <QtCore/QLocale>
38#include <QtGui/QColor>
39#include <QtGui/QBitmap>
40
41QT_BEGIN_NAMESPACE
42
43class DataModel;
44class MultiDataModel;
45
46class MessageItem
47{
48public:
49 MessageItem(const TranslatorMessage &message);
50
51 bool danger() const { return m_danger; }
52 void setDanger(bool danger) { m_danger = danger; }
53
54 void setTranslation(const QString &translation)
55 { m_message.setTranslation(translation); }
56
57 QString id() const { return m_message.id(); }
58 QString context() const { return m_message.context(); }
59 QString text() const { return m_message.sourceText(); }
60 QString pluralText() const { return m_message.extra(ba: QLatin1String("po-msgid_plural")); }
61 QString comment() const { return m_message.comment(); }
62 QString fileName() const { return m_message.fileName(); }
63 QString extraComment() const { return m_message.extraComment(); }
64 QString translatorComment() const { return m_message.translatorComment(); }
65 void setTranslatorComment(const QString &cmt) { m_message.setTranslatorComment(cmt); }
66 int lineNumber() const { return m_message.lineNumber(); }
67 QString translation() const { return m_message.translation(); }
68 QStringList translations() const { return m_message.translations(); }
69 void setTranslations(const QStringList &translations)
70 { m_message.setTranslations(translations); }
71
72 TranslatorMessage::Type type() const { return m_message.type(); }
73 void setType(TranslatorMessage::Type type) { m_message.setType(type); }
74
75 bool isFinished() const { return type() == TranslatorMessage::Finished; }
76 bool isObsolete() const
77 { return type() == TranslatorMessage::Obsolete || type() == TranslatorMessage::Vanished; }
78 const TranslatorMessage &message() const { return m_message; }
79
80 bool compare(const QString &findText, bool matchSubstring,
81 Qt::CaseSensitivity cs) const;
82
83private:
84 TranslatorMessage m_message;
85 bool m_danger;
86};
87
88
89class ContextItem
90{
91public:
92 ContextItem(const QString &context);
93
94 int finishedDangerCount() const { return m_finishedDangerCount; }
95 int unfinishedDangerCount() const { return m_unfinishedDangerCount; }
96
97 int finishedCount() const { return m_finishedCount; }
98 int unfinishedCount() const { return m_nonobsoleteCount - m_finishedCount; }
99 int nonobsoleteCount() const { return m_nonobsoleteCount; }
100
101 QString context() const { return m_context; }
102 QString comment() const { return m_comment; }
103 QString fullContext() const { return m_comment.trimmed(); }
104
105 // For item status in context list
106 bool isObsolete() const { return !nonobsoleteCount(); }
107 bool isFinished() const { return unfinishedCount() == 0; }
108
109 MessageItem *messageItem(int i) const;
110 int messageCount() const { return msgItemList.count(); }
111
112 MessageItem *findMessage(const QString &sourcetext, const QString &comment) const;
113
114private:
115 friend class DataModel;
116 friend class MultiDataModel;
117 void appendMessage(const MessageItem &msg) { msgItemList.append(t: msg); }
118 void appendToComment(const QString &x);
119 void incrementFinishedCount() { ++m_finishedCount; }
120 void decrementFinishedCount() { --m_finishedCount; }
121 void incrementFinishedDangerCount() { ++m_finishedDangerCount; }
122 void decrementFinishedDangerCount() { --m_finishedDangerCount; }
123 void incrementUnfinishedDangerCount() { ++m_unfinishedDangerCount; }
124 void decrementUnfinishedDangerCount() { --m_unfinishedDangerCount; }
125 void incrementNonobsoleteCount() { ++m_nonobsoleteCount; }
126
127 QString m_comment;
128 QString m_context;
129 int m_finishedCount;
130 int m_finishedDangerCount;
131 int m_unfinishedDangerCount;
132 int m_nonobsoleteCount;
133 QList<MessageItem> msgItemList;
134};
135
136
137class DataIndex
138{
139public:
140 DataIndex() : m_context(-1), m_message(-1) {}
141 DataIndex(int context, int message) : m_context(context), m_message(message) {}
142 int context() const { return m_context; }
143 int message() const { return m_message; }
144 bool isValid() const { return m_context >= 0; }
145protected:
146 int m_context;
147 int m_message;
148};
149
150
151class DataModelIterator : public DataIndex
152{
153public:
154 DataModelIterator(DataModel *model, int contextNo = 0, int messageNo = 0);
155 MessageItem *current() const;
156 bool isValid() const;
157 void operator++();
158private:
159 DataModelIterator() {}
160 DataModel *m_model; // not owned
161};
162
163
164class DataModel : public QObject
165{
166 Q_OBJECT
167public:
168 DataModel(QObject *parent = 0);
169
170 enum FindLocation { NoLocation = 0, SourceText = 0x1, Translations = 0x2, Comments = 0x4 };
171
172 // Specializations
173 int contextCount() const { return m_contextList.count(); }
174 ContextItem *findContext(const QString &context) const;
175 MessageItem *findMessage(const QString &context, const QString &sourcetext,
176 const QString &comment) const;
177
178 ContextItem *contextItem(int index) const;
179 MessageItem *messageItem(const DataIndex &index) const;
180
181 int messageCount() const { return m_numMessages; }
182 bool isEmpty() const { return m_numMessages == 0; }
183 bool isModified() const { return m_modified; }
184 void setModified(bool dirty);
185 bool isWritable() const { return m_writable; }
186 void setWritable(bool writable) { m_writable = writable; }
187
188 bool isWellMergeable(const DataModel *other) const;
189 bool load(const QString &fileName, bool *langGuessed, QWidget *parent);
190 bool save(QWidget *parent) { return save(fileName: m_srcFileName, parent); }
191 bool saveAs(const QString &newFileName, QWidget *parent);
192 bool release(const QString &fileName, bool verbose,
193 bool ignoreUnfinished, TranslatorSaveMode mode, QWidget *parent);
194 QString srcFileName(bool pretty = false) const
195 { return pretty ? prettifyPlainFileName(fn: m_srcFileName) : m_srcFileName; }
196
197 static QString prettifyPlainFileName(const QString &fn);
198 static QString prettifyFileName(const QString &fn);
199
200 bool setLanguageAndCountry(QLocale::Language lang, QLocale::Country country);
201 QLocale::Language language() const { return m_language; }
202 QLocale::Country country() const { return m_country; }
203 void setSourceLanguageAndCountry(QLocale::Language lang, QLocale::Country country);
204 QLocale::Language sourceLanguage() const { return m_sourceLanguage; }
205 QLocale::Country sourceCountry() const { return m_sourceCountry; }
206
207 const QString &localizedLanguage() const { return m_localizedLanguage; }
208 const QStringList &numerusForms() const { return m_numerusForms; }
209 const QList<bool> &countRefNeeds() const { return m_countRefNeeds; }
210
211 QStringList normalizedTranslations(const MessageItem &m) const;
212 void doCharCounting(const QString& text, int& trW, int& trC, int& trCS);
213 void updateStatistics();
214
215 int getSrcWords() const { return m_srcWords; }
216 int getSrcChars() const { return m_srcChars; }
217 int getSrcCharsSpc() const { return m_srcCharsSpc; }
218
219signals:
220 void statsChanged(int words, int characters, int cs, int words2, int characters2, int cs2);
221 void progressChanged(int finishedCount, int oldFinishedCount);
222 void languageChanged();
223 void modifiedChanged();
224
225private:
226 friend class DataModelIterator;
227 QList<ContextItem> m_contextList;
228
229 bool save(const QString &fileName, QWidget *parent);
230 void updateLocale();
231
232 bool m_writable;
233 bool m_modified;
234
235 int m_numMessages;
236
237 // For statistics
238 int m_srcWords;
239 int m_srcChars;
240 int m_srcCharsSpc;
241
242 QString m_srcFileName;
243 QLocale::Language m_language;
244 QLocale::Language m_sourceLanguage;
245 QLocale::Country m_country;
246 QLocale::Country m_sourceCountry;
247 bool m_relativeLocations;
248 Translator::ExtraData m_extra;
249
250 QString m_localizedLanguage;
251 QStringList m_numerusForms;
252 QList<bool> m_countRefNeeds;
253};
254
255
256struct MultiMessageItem
257{
258public:
259 MultiMessageItem(const MessageItem *m);
260 QString id() const { return m_id; }
261 QString text() const { return m_text; }
262 QString pluralText() const { return m_pluralText; }
263 QString comment() const { return m_comment; }
264 bool isEmpty() const { return !m_nonnullCount; }
265 // The next two include also read-only
266 bool isObsolete() const { return m_nonnullCount && !m_nonobsoleteCount; }
267 int countNonobsolete() const { return m_nonobsoleteCount; }
268 // The next three include only read-write
269 int countEditable() const { return m_editableCount; }
270 bool isUnfinished() const { return m_unfinishedCount != 0; }
271 int countUnfinished() const { return m_unfinishedCount; }
272
273private:
274 friend class MultiDataModel;
275 void incrementNonnullCount() { ++m_nonnullCount; }
276 void decrementNonnullCount() { --m_nonnullCount; }
277 void incrementNonobsoleteCount() { ++m_nonobsoleteCount; }
278 void decrementNonobsoleteCount() { --m_nonobsoleteCount; }
279 void incrementEditableCount() { ++m_editableCount; }
280 void decrementEditableCount() { --m_editableCount; }
281 void incrementUnfinishedCount() { ++m_unfinishedCount; }
282 void decrementUnfinishedCount() { --m_unfinishedCount; }
283
284 QString m_id;
285 QString m_text;
286 QString m_pluralText;
287 QString m_comment;
288 int m_nonnullCount; // all
289 int m_nonobsoleteCount; // all
290 int m_editableCount; // read-write
291 int m_unfinishedCount; // read-write
292};
293
294struct MultiContextItem
295{
296public:
297 MultiContextItem(int oldCount, ContextItem *ctx, bool writable);
298
299 ContextItem *contextItem(int model) const { return m_contextList[model]; }
300
301 MultiMessageItem *multiMessageItem(int msgIdx) const
302 { return const_cast<MultiMessageItem *>(&m_multiMessageList[msgIdx]); }
303 MessageItem *messageItem(int model, int msgIdx) const { return m_messageLists[model][msgIdx]; }
304 int firstNonobsoleteMessageIndex(int msgIdx) const;
305 int findMessage(const QString &sourcetext, const QString &comment) const;
306 int findMessageById(const QString &id) const;
307
308 QString context() const { return m_context; }
309 QString comment() const { return m_comment; }
310 int messageCount() const { return m_messageLists.isEmpty() ? 0 : m_messageLists[0].count(); }
311 // For item count in context list
312 int getNumFinished() const { return m_finishedCount; }
313 int getNumEditable() const { return m_editableCount; }
314 // For background in context list
315 bool isObsolete() const { return messageCount() && !m_nonobsoleteCount; }
316
317private:
318 friend class MultiDataModel;
319 void appendEmptyModel();
320 void assignLastModel(ContextItem *ctx, bool writable);
321 void removeModel(int pos);
322 void moveModel(int oldPos, int newPos); // newPos is *before* removing at oldPos
323 void putMessageItem(int pos, MessageItem *m);
324 void appendMessageItems(const QList<MessageItem *> &m);
325 void removeMultiMessageItem(int pos);
326 void incrementFinishedCount() { ++m_finishedCount; }
327 void decrementFinishedCount() { --m_finishedCount; }
328 void incrementEditableCount() { ++m_editableCount; }
329 void decrementEditableCount() { --m_editableCount; }
330 void incrementNonobsoleteCount() { ++m_nonobsoleteCount; }
331 void decrementNonobsoleteCount() { --m_nonobsoleteCount; }
332
333 QString m_context;
334 QString m_comment;
335 QList<MultiMessageItem> m_multiMessageList;
336 QList<ContextItem *> m_contextList;
337 // The next two could be in the MultiMessageItems, but are here for efficiency
338 QList<QList<MessageItem *> > m_messageLists;
339 QList<QList<MessageItem *> *> m_writableMessageLists;
340 int m_finishedCount; // read-write
341 int m_editableCount; // read-write
342 int m_nonobsoleteCount; // all (note: this counts messages, not multi-messages)
343};
344
345
346class MultiDataIndex
347{
348public:
349 MultiDataIndex() : m_model(-1), m_context(-1), m_message(-1) {}
350 MultiDataIndex(int model, int context, int message)
351 : m_model(model), m_context(context), m_message(message) {}
352 void setModel(int model) { m_model = model; }
353 int model() const { return m_model; }
354 int context() const { return m_context; }
355 int message() const { return m_message; }
356 bool isValid() const { return m_context >= 0; }
357 bool operator==(const MultiDataIndex &other) const
358 { return m_model == other.m_model && m_context == other.m_context && m_message == other.m_message; }
359 bool operator!=(const MultiDataIndex &other) const { return !(*this == other); }
360protected:
361 int m_model;
362 int m_context;
363 int m_message;
364};
365
366
367class MultiDataModelIterator : public MultiDataIndex
368{
369public:
370 MultiDataModelIterator(MultiDataModel *model, int modelNo, int contextNo = 0, int messageNo = 0);
371 MessageItem *current() const;
372 bool isValid() const;
373 void operator++();
374private:
375 MultiDataModelIterator() {}
376 MultiDataModel *m_dataModel; // not owned
377};
378
379
380class MessageModel;
381
382class MultiDataModel : public QObject
383{
384 Q_OBJECT
385
386public:
387 MultiDataModel(QObject *parent = 0);
388 ~MultiDataModel();
389
390 bool isWellMergeable(const DataModel *dm) const;
391 void append(DataModel *dm, bool readWrite);
392 bool save(int model, QWidget *parent) { return m_dataModels[model]->save(parent); }
393 bool saveAs(int model, const QString &newFileName, QWidget *parent)
394 { return m_dataModels[model]->saveAs(newFileName, parent); }
395 bool release(int model, const QString &fileName, bool verbose, bool ignoreUnfinished, TranslatorSaveMode mode, QWidget *parent)
396 { return m_dataModels[model]->release(fileName, verbose, ignoreUnfinished, mode, parent); }
397 void close(int model);
398 void closeAll();
399 int isFileLoaded(const QString &name) const;
400 void moveModel(int oldPos, int newPos); // newPos is *before* removing at oldPos; note that this does not emit update signals
401
402 // Entire multi-model
403 int modelCount() const { return m_dataModels.count(); }
404 int contextCount() const { return m_multiContextList.count(); }
405 int messageCount() const { return m_numMessages; }
406 // Next two needed for progress indicator in main window
407 int getNumFinished() const { return m_numFinished; }
408 int getNumEditable() const { return m_numEditable; }
409 bool isModified() const;
410 QStringList srcFileNames(bool pretty = false) const;
411 QString condensedSrcFileNames(bool pretty = false) const;
412
413 // Per submodel
414 QString srcFileName(int model, bool pretty = false) const { return m_dataModels[model]->srcFileName(pretty); }
415 bool isModelWritable(int model) const { return m_dataModels[model]->isWritable(); }
416 bool isModified(int model) const { return m_dataModels[model]->isModified(); }
417 void setModified(int model, bool dirty) { m_dataModels[model]->setModified(dirty); }
418 QLocale::Language language(int model) const { return m_dataModels[model]->language(); }
419 QLocale::Language sourceLanguage(int model) const { return m_dataModels[model]->sourceLanguage(); }
420
421 // Per message
422 void setTranslation(const MultiDataIndex &index, const QString &translation);
423 void setFinished(const MultiDataIndex &index, bool finished);
424 void setDanger(const MultiDataIndex &index, bool danger);
425
426 // Retrieve items
427 DataModel *model(int i) { return m_dataModels[i]; }
428 MultiContextItem *multiContextItem(int ctxIdx) const
429 { return const_cast<MultiContextItem *>(&m_multiContextList[ctxIdx]); }
430 MultiMessageItem *multiMessageItem(const MultiDataIndex &index) const
431 { return multiContextItem(ctxIdx: index.context())->multiMessageItem(msgIdx: index.message()); }
432 MessageItem *messageItem(const MultiDataIndex &index, int model) const;
433 MessageItem *messageItem(const MultiDataIndex &index) const { return messageItem(index, model: index.model()); }
434 int findContextIndex(const QString &context) const;
435 MultiContextItem *findContext(const QString &context) const;
436
437 static QString condenseFileNames(const QStringList &names);
438 static QStringList prettifyFileNames(const QStringList &names);
439
440 QBrush brushForModel(int model) const;
441
442signals:
443 void modelAppended();
444 void modelDeleted(int model);
445 void allModelsDeleted();
446 void languageChanged(int model);
447 void statsChanged(int words, int characters, int cs, int words2, int characters2, int cs2);
448 void modifiedChanged(bool);
449 void multiContextDataChanged(const MultiDataIndex &index);
450 void contextDataChanged(const MultiDataIndex &index);
451 void messageDataChanged(const MultiDataIndex &index);
452 void translationChanged(const MultiDataIndex &index); // Only the primary one
453
454private slots:
455 void onModifiedChanged();
456 void onLanguageChanged();
457
458private:
459 friend class MultiDataModelIterator;
460 friend class MessageModel;
461
462 ContextItem *contextItem(const MultiDataIndex &index) const
463 { return multiContextItem(ctxIdx: index.context())->contextItem(model: index.model()); }
464
465 void updateCountsOnAdd(int model, bool writable);
466 void updateCountsOnRemove(int model, bool writable);
467 void incrementFinishedCount() { ++m_numFinished; }
468 void decrementFinishedCount() { --m_numFinished; }
469 void incrementEditableCount() { ++m_numEditable; }
470 void decrementEditableCount() { --m_numEditable; }
471
472 int m_numFinished;
473 int m_numEditable;
474 int m_numMessages;
475
476 bool m_modified;
477
478 QList<MultiContextItem> m_multiContextList;
479 QList<DataModel *> m_dataModels;
480
481 MessageModel *m_msgModel;
482
483 QColor m_colors[7];
484 QBitmap m_bitmap;
485};
486
487class MessageModel : public QAbstractItemModel
488{
489 Q_OBJECT
490
491public:
492 enum { SortRole = Qt::UserRole };
493
494 MessageModel(QObject *parent, MultiDataModel *data);
495
496 // QAbstractItemModel
497 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
498 QModelIndex parent(const QModelIndex& index) const;
499 int rowCount(const QModelIndex &parent = QModelIndex()) const;
500 int columnCount(const QModelIndex &parent = QModelIndex()) const;
501 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
502
503 // Convenience
504 MultiDataIndex dataIndex(const QModelIndex &index, int model) const;
505 MultiDataIndex dataIndex(const QModelIndex &index) const
506 { return dataIndex(index, model: index.column() - 1 < m_data->modelCount() ? index.column() - 1 : -1); }
507 QModelIndex modelIndex(const MultiDataIndex &index);
508
509private slots:
510 void multiContextItemChanged(const MultiDataIndex &index);
511 void contextItemChanged(const MultiDataIndex &index);
512 void messageItemChanged(const MultiDataIndex &index);
513
514private:
515 friend class MultiDataModel;
516
517 MultiDataModel *m_data; // not owned
518};
519
520QT_END_NAMESPACE
521
522#endif // MESSAGEMODEL_H
523

source code of qttools/src/linguist/linguist/messagemodel.h