source: trunk/tools/linguist/linguist/messagemodel.h@ 769

Last change on this file since 769 was 769, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.3 sources from branches/vendor/nokia/qt.

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