~smartboyhw/ubuntu/raring/calligra/2.6.0-0ubuntu1

« back to all changes in this revision

Viewing changes to words/part/dockers/KWStatistics.cpp

  • Committer: Package Import Robot
  • Author(s): Philip Muškovac
  • Date: 2012-10-23 21:09:16 UTC
  • mfrom: (1.1.13)
  • Revision ID: package-import@ubuntu.com-20121023210916-m82w6zxnxhaxz7va
Tags: 1:2.5.90-0ubuntu1
* New upstream alpha release (LP: #1070436)
  - Add libkactivities-dev and libopenimageio-dev to build-depends
  - Add kubuntu_build_calligraactive.diff to build calligraactive by default
  - Add package for calligraauthor and move files that are shared between
    calligrawords and calligraauthor to calligrawords-common
* Document the patches
* Remove numbers from patches so they follow the same naming scheme as
  the rest of our patches.
* calligra-data breaks replaces krita-data (<< 1:2.5.3) (LP: #1071686)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* This file is part of the KDE project
2
 
 * Copyright (C) 2005, 2007 Thomas Zander <zander@kde.org>
3
 
 * Copyright (C) 2012 Shreya Pandit <shreya@shreyapandit.com>
4
 
 * This library is free software; you can redistribute it and/or
5
 
 * modify it under the terms of the GNU Library General Public
6
 
 * License as published by the Free Software Foundation; either
7
 
 * version 2 of the License, or (at your option) any later version.
8
 
 *
9
 
 * This library is distributed in the hope that it will be useful,
10
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 
 * Library General Public License for more details.
13
 
 *
14
 
 * You should have received a copy of the GNU Library General Public License
15
 
 * along with this library; see the file COPYING.LIB.  If not, write to
16
 
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17
 
 * Boston, MA 02110-1301, USA.
18
 
 */
19
 
 
20
 
#include "KWStatistics.h"
21
 
 
22
 
#include "Words.h"
23
 
#include "KWDocument.h"
24
 
#include "frames/KWFrame.h"
25
 
#include "frames/KWFrameSet.h"
26
 
#include "frames/KWTextFrameSet.h"
27
 
#include <ui_KWStatisticsDocker.h>
28
 
#include "dockers/StatisticsPreferencesPopup.h"
29
 
#include <KoCanvasResourceManager.h>
30
 
#include <KoSelection.h>
31
 
#include <KoShape.h>
32
 
 
33
 
#include <QTextLayout>
34
 
#include <QTextDocument>
35
 
#include <QTextBlock>
36
 
#include <QTimer>
37
 
 
38
 
KWStatistics::KWStatistics(KoCanvasResourceManager *provider, KWDocument *document, KoSelection *selection, QWidget *parent)
39
 
        : QWidget(parent),
40
 
        m_resourceManager(provider),
41
 
        m_selection(selection),
42
 
        m_document(document),
43
 
        m_textDocument(0),
44
 
        m_timer(0),
45
 
        m_charsWithSpace(0),
46
 
        m_charsWithoutSpace(0),
47
 
        m_words(0),
48
 
        m_sentences(0),
49
 
        m_lines(0),
50
 
        m_syllables(0),
51
 
        m_paragraphs(0)
52
 
 
53
 
{
54
 
    m_showInDocker = true;
55
 
    m_timer = new QTimer(this);
56
 
    m_timer->start(2500);
57
 
    widgetDocker.setupUi(this);
58
 
    m_menu = new StatisticsPreferencesPopup(widgetDocker.preferences);
59
 
    widgetDocker.preferences->setMenu(m_menu);
60
 
    widgetDocker.preferences->setPopupMode(QToolButton::InstantPopup);
61
 
 
62
 
    connect(m_timer, SIGNAL(timeout()), this, SLOT(updateData()));
63
 
    connect(widgetDocker.preferences, SIGNAL(clicked()), widgetDocker.preferences, SLOT(showMenu()));
64
 
    connect(m_menu, SIGNAL(wordsDisplayChange(int)), this, SLOT(wordsDisplayChanged(int)));
65
 
    connect(m_menu, SIGNAL(sentencesDisplayChange(int)), this, SLOT(sentencesDisplayChanged(int)));
66
 
    connect(m_menu, SIGNAL(linesDisplayChange(int)), this, SLOT(linesDisplayChanged(int)));
67
 
    connect(m_menu, SIGNAL(syllablesDisplayChange(int)), this, SLOT(syllablesDisplayChanged(int)));
68
 
    connect(m_menu, SIGNAL(charspaceDisplayChange(int)), this, SLOT(charspaceDisplayChanged(int)));
69
 
    connect(m_menu, SIGNAL(charnospaceDisplayChange(int)), this, SLOT(charnospaceDisplayChanged(int)));
70
 
    connect(m_menu, SIGNAL(eastDisplayChange(int)), this, SLOT(eastDisplayChanged(int)));
71
 
    connect(m_menu, SIGNAL(fleschDisplayChange(int)), this, SLOT(fleschDisplayChanged(int)));
72
 
 
73
 
    KConfigGroup cfgGroup = KGlobal::config()->group("Statistics");
74
 
    bool visible = cfgGroup.readEntry("WordsVisible", true);
75
 
    widgetDocker.Words->setVisible(visible);
76
 
    widgetDocker.count_words->setVisible(visible);
77
 
 
78
 
    visible = cfgGroup.readEntry("SentencesVisible", true);
79
 
    widgetDocker.Sentences->setVisible(visible);
80
 
    widgetDocker.count_sentences->setVisible(visible);
81
 
 
82
 
    visible = cfgGroup.readEntry("SyllablesVisible", true);
83
 
    widgetDocker.Syllables->setVisible(visible);
84
 
    widgetDocker.count_syllables->setVisible(visible);
85
 
 
86
 
    visible = cfgGroup.readEntry("LinesVisible", true);
87
 
    widgetDocker.Lines->setVisible(visible);
88
 
    widgetDocker.count_lines->setVisible(visible);
89
 
 
90
 
    visible = cfgGroup.readEntry("EastAsianCharactersVisible", true);
91
 
    widgetDocker.Cjkchars->setVisible(visible);
92
 
    widgetDocker.count_cjkchars->setVisible(visible);
93
 
 
94
 
    visible = cfgGroup.readEntry("FleschVisible", true);
95
 
    widgetDocker.Flesch->setVisible(visible);
96
 
    widgetDocker.count_flesch->setVisible(visible);
97
 
 
98
 
    visible = cfgGroup.readEntry("CharspacesVisible", true);
99
 
    widgetDocker.spaces->setVisible(visible);
100
 
    widgetDocker.count_spaces->setVisible(visible);
101
 
 
102
 
    visible = cfgGroup.readEntry("CharnospacesVisible", true);
103
 
    widgetDocker.nospaces->setVisible(visible);
104
 
    widgetDocker.count_nospaces->setVisible(visible);
105
 
}
106
 
 
107
 
KWStatistics::~KWStatistics()
108
 
{
109
 
    m_timer->stop();
110
 
}
111
 
void KWStatistics::updateData()
112
 
{
113
 
    if (!isVisible()) {
114
 
        return;
115
 
    }
116
 
    m_charsWithSpace = 0;
117
 
    m_charsWithoutSpace = 0;
118
 
    m_words = 0;
119
 
    m_sentences = 0;
120
 
    m_lines = 0;
121
 
    m_syllables = 0;
122
 
    m_paragraphs = 0;
123
 
    m_cjkChars = 0;
124
 
 
125
 
    // parts of words for better counting of syllables:
126
 
    // (only use reg exp if necessary -> speed up)
127
 
 
128
 
    QStringList subs_syl;
129
 
    subs_syl << "cial" << "tia" << "cius" << "cious" << "giu" << "ion" << "iou";
130
 
    QStringList subs_syl_regexp;
131
 
    subs_syl_regexp << "sia$" << "ely$";
132
 
 
133
 
    QStringList add_syl;
134
 
    add_syl << "ia" << "riet" << "dien" << "iu" << "io" << "ii";
135
 
    QStringList add_syl_regexp;
136
 
    add_syl_regexp << "[aeiouym]bl$" << "[aeiou]{3}" << "^mc" << "ism$"
137
 
    << "[^l]lien" << "^coa[dglx]." << "[^gq]ua[^auieo]" << "dnt$";
138
 
 
139
 
    foreach (KWFrameSet *fs, m_document->frameSets()) {
140
 
        KWTextFrameSet *tfs = dynamic_cast<KWTextFrameSet*>(fs);
141
 
        if (tfs == 0) continue;
142
 
 
143
 
        QTextDocument *doc = tfs->document();
144
 
        QTextBlock block = doc->begin();
145
 
        while (block.isValid()) {
146
 
            m_paragraphs += 1;
147
 
            m_charsWithSpace += block.text().length();
148
 
            m_charsWithoutSpace += block.text().length() - block.text().count(QRegExp("\\s"));
149
 
            if (block.layout())
150
 
                m_lines += block.layout()->lineCount();
151
 
            m_cjkChars += countCJKChars(block.text());
152
 
 
153
 
            QString s = block.text();
154
 
 
155
 
            // Syllable and Word count
156
 
            // Algorithm mostly taken from Greg Fast's Lingua::EN::Syllable module for Perl.
157
 
            // This guesses correct for 70-90% of English words, but the overall value
158
 
            // is quite good, as some words get a number that's too high and others get
159
 
            // one that's too low.
160
 
            // IMPORTANT: please test any changes against demos/statistics.kwd
161
 
            QRegExp re("\\s+");
162
 
            const QStringList wordlist = s.split(re, QString::SkipEmptyParts);
163
 
            m_words += wordlist.count();
164
 
            re.setCaseSensitivity(Qt::CaseInsensitive);
165
 
            for (QStringList::ConstIterator it1 = wordlist.begin(); it1 != wordlist.end(); ++it1) {
166
 
                QString word1 = *it1;
167
 
                QString word = *it1;
168
 
                re.setPattern("[!?.,:_\"-]");    // clean word from punctuation
169
 
                word.remove(re);
170
 
                if (word.length() <= 3) {  // extension to the original algorithm
171
 
                    m_syllables++;
172
 
                    continue;
173
 
                }
174
 
                re.setPattern("e$");
175
 
                word.remove(re);
176
 
                re.setPattern("[^aeiouy]+");
177
 
                QStringList syls = word.split(re, QString::SkipEmptyParts);
178
 
                int word_syllables = 0;
179
 
                for (QStringList::Iterator it = subs_syl.begin(); it != subs_syl.end(); ++it) {
180
 
                    if (word.indexOf(*it, 0, Qt::CaseInsensitive) != -1)
181
 
                        word_syllables--;
182
 
                }
183
 
                for (QStringList::Iterator it = subs_syl_regexp.begin(); it != subs_syl_regexp.end(); ++it) {
184
 
                    re.setPattern(*it);
185
 
                    if (word.indexOf(re) != -1)
186
 
                        word_syllables--;
187
 
                }
188
 
                for (QStringList::Iterator it = add_syl.begin(); it != add_syl.end(); ++it) {
189
 
                    if (word.indexOf(*it, 0, Qt::CaseInsensitive) != -1)
190
 
                        word_syllables++;
191
 
                }
192
 
                for (QStringList::Iterator it = add_syl_regexp.begin(); it != add_syl_regexp.end(); ++it) {
193
 
                    re.setPattern(*it);
194
 
                    if (word.indexOf(re) != -1)
195
 
                        word_syllables++;
196
 
                }
197
 
                word_syllables += syls.count();
198
 
                if (word_syllables == 0)
199
 
                    word_syllables = 1;
200
 
                m_syllables += word_syllables;
201
 
            }
202
 
            re.setCaseSensitivity(Qt::CaseSensitive);
203
 
 
204
 
            block = block.next();
205
 
 
206
 
            // Sentence count
207
 
            // Clean up for better result, destroys the original text but we only want to count
208
 
            s = s.trimmed();
209
 
            if (s.isEmpty())
210
 
                continue;
211
 
            QChar lastchar = s.at(s.length() - 1);
212
 
            if (! s.isEmpty() && lastchar != QChar('.') && lastchar != QChar('?') && lastchar != QChar('!')) {  // e.g. for headlines
213
 
                s = s + '.';
214
 
            }
215
 
            re.setPattern("[.?!]+");         // count "..." as only one "."
216
 
            s.replace(re, ".");
217
 
            re.setPattern("\\d\\.\\d");      // don't count floating point numbers as sentences
218
 
            s.replace(re, "0,0");
219
 
            re.setPattern("[A-Z]\\.+");      // don't count "U.S.A." as three sentences
220
 
            s.replace(re, "*");
221
 
                for (int i = 0 ; i < s.length(); ++i) {
222
 
                    QChar ch = s[i];
223
 
                    if (ch == QChar('.') || ch == QChar('?') || ch == QChar('!'))
224
 
                        ++m_sentences;
225
 
            }
226
 
        }
227
 
    }
228
 
    updateDataUi();
229
 
}
230
 
 
231
 
void KWStatistics::updateDataUi()
232
 
{
233
 
    // calculate Flesch reading ease score:
234
 
    float flesch_score = 0;
235
 
    if (m_words > 0 && m_sentences > 0)
236
 
        flesch_score = 206.835 - (1.015 * (m_words / m_sentences)) - (84.6 * m_syllables / m_words);
237
 
    QString flesch = KGlobal::locale()->formatNumber(flesch_score);
238
 
    QString newText[8];
239
 
    newText[0] = KGlobal::locale()->formatNumber(m_words, 0);
240
 
    widgetDocker.count_words->setText(newText[0]);
241
 
 
242
 
    newText[1] = KGlobal::locale()->formatNumber(m_sentences, 0);
243
 
    widgetDocker.count_sentences->setText(newText[1]);
244
 
 
245
 
    newText[2] = KGlobal::locale()->formatNumber(m_syllables, 0);
246
 
    widgetDocker.count_syllables->setText(newText[2]);
247
 
 
248
 
    newText[3] = KGlobal::locale()->formatNumber(m_lines, 0);
249
 
    widgetDocker.count_lines->setText(newText[3]);
250
 
 
251
 
    newText[4] = KGlobal::locale()->formatNumber(m_charsWithSpace, 0);
252
 
    widgetDocker.count_spaces->setText(newText[4]);
253
 
 
254
 
    newText[5] = KGlobal::locale()->formatNumber(m_charsWithoutSpace, 0);
255
 
    widgetDocker.count_nospaces->setText(newText[5]);
256
 
 
257
 
    newText[6] = KGlobal::locale()->formatNumber(m_cjkChars, 0);
258
 
    widgetDocker.count_cjkchars->setText(newText[6]);
259
 
 
260
 
     newText[7] = flesch;
261
 
     widgetDocker.count_flesch->setText(newText[7]);
262
 
}
263
 
 
264
 
 
265
 
void KWStatistics::selectionChanged()
266
 
{
267
 
    if (m_selection->count() != 1)
268
 
        return;
269
 
 
270
 
    KoShape *shape = m_selection->firstSelectedShape();
271
 
    if (!shape) return;
272
 
    KWFrame *frame = dynamic_cast<KWFrame*>(shape->applicationData());
273
 
    if (!frame) return; // you can have embedded shapes selected, in that case it surely is no text frameset.
274
 
    KWTextFrameSet *fs = dynamic_cast<KWTextFrameSet*>(frame->frameSet());
275
 
    if (fs) {
276
 
        if (m_textDocument)
277
 
            disconnect(m_textDocument, SIGNAL(contentsChanged()), m_timer, SLOT(start()));
278
 
        m_textDocument = fs->document();
279
 
 
280
 
    }
281
 
}
282
 
 
283
 
int KWStatistics::countCJKChars(const QString &text)
284
 
{
285
 
    int count = 0;
286
 
 
287
 
    QString::const_iterator it;
288
 
    for (it = text.constBegin(); it != text.constEnd(); ++it) {
289
 
        QChar qChar = *it;
290
 
        /*
291
 
         * CJK punctuations: 0x3000 - 0x303F (but I believe we shouldn't include this in the statistics)
292
 
         * Hiragana: 0x3040 - 0x309F
293
 
         * Katakana: 0x30A0 - 0x30FF
294
 
         * CJK Unified Ideographs: 4E00 - 9FFF (Chinese Traditional & Simplified, Kanji and Hanja
295
 
         * Hangul: 0xAC00 - 0xD7AF
296
 
         */
297
 
        if ((qChar >= 0x3040 && qChar <= 0x309F)
298
 
                || (qChar >= 0x30A0 && qChar <= 0x30FF)
299
 
                || (qChar >= 0x4E00 && qChar <= 0x9FFF)
300
 
                || (qChar >= 0xAC00 && qChar <= 0xD7AF)) {
301
 
            count++;
302
 
        }
303
 
    }
304
 
 
305
 
    return count;
306
 
}
307
 
 
308
 
void KWStatistics::wordsDisplayChanged(int state)
309
 
{   KConfigGroup cfgGroup = KGlobal::config()->group("Statistics");
310
 
    switch (state) {
311
 
    case Qt::Checked:
312
 
        widgetDocker.Words->show();
313
 
        widgetDocker.count_words->show();
314
 
        cfgGroup.writeEntry("WordsVisible",true);
315
 
        cfgGroup.sync();
316
 
        break;
317
 
    case Qt::Unchecked:
318
 
        widgetDocker.Words->hide();
319
 
        widgetDocker.count_words->hide();
320
 
        cfgGroup.writeEntry("WordsVisible",false);
321
 
        cfgGroup.sync();
322
 
        break;
323
 
    default:
324
 
        break;
325
 
    }
326
 
}
327
 
 
328
 
void KWStatistics::sentencesDisplayChanged(int state)
329
 
{
330
 
    KConfigGroup cfgGroup = KGlobal::config()->group("Statistics");
331
 
    switch (state) {
332
 
    case Qt::Checked:
333
 
        widgetDocker.Sentences->show();
334
 
        widgetDocker.count_sentences->show();
335
 
        cfgGroup.writeEntry("SentencesVisible",true);
336
 
        cfgGroup.sync();
337
 
        break;
338
 
    case Qt::Unchecked:
339
 
        widgetDocker.Sentences->hide();
340
 
        widgetDocker.count_sentences->hide();
341
 
        cfgGroup.writeEntry("SentencesVisible",false);
342
 
        cfgGroup.sync();
343
 
        break;
344
 
    default:
345
 
        break;
346
 
    }
347
 
}
348
 
 
349
 
void KWStatistics::linesDisplayChanged(int state)
350
 
{
351
 
    KConfigGroup cfgGroup = KGlobal::config()->group("Statistics");
352
 
    switch (state) {
353
 
    case Qt::Checked:
354
 
        widgetDocker.Lines->show();
355
 
        widgetDocker.count_lines->show();
356
 
        cfgGroup.writeEntry("LinesVisible",true);
357
 
        cfgGroup.sync();
358
 
        break;
359
 
    case Qt::Unchecked:
360
 
        widgetDocker.Lines->hide();
361
 
        widgetDocker.count_lines->hide();
362
 
        cfgGroup.writeEntry("LinesVisible",false);
363
 
        cfgGroup.sync();
364
 
        break;
365
 
    default:
366
 
        break;
367
 
    }
368
 
}
369
 
void KWStatistics::syllablesDisplayChanged(int state)
370
 
{
371
 
    KConfigGroup cfgGroup = KGlobal::config()->group("Statistics");
372
 
    switch (state) {
373
 
    case Qt::Checked:
374
 
        widgetDocker.Syllables->show();
375
 
        widgetDocker.count_syllables->show();
376
 
        cfgGroup.writeEntry("SyllablesVisible",true);
377
 
        cfgGroup.sync();
378
 
        break;
379
 
    case Qt::Unchecked:
380
 
        widgetDocker.Syllables->hide();
381
 
        widgetDocker.count_syllables->hide();
382
 
        cfgGroup.writeEntry("SyllablesVisible",false);
383
 
        cfgGroup.sync();
384
 
        break;
385
 
    default:
386
 
        break;
387
 
    }
388
 
}
389
 
void KWStatistics::charspaceDisplayChanged(int state)
390
 
{
391
 
    KConfigGroup cfgGroup = KGlobal::config()->group("Statistics");
392
 
    switch (state) {
393
 
    case Qt::Checked:
394
 
        widgetDocker.spaces->show();
395
 
        widgetDocker.count_spaces->show();
396
 
        cfgGroup.writeEntry("CharspacesVisible",true);
397
 
        cfgGroup.sync();
398
 
        break;
399
 
    case Qt::Unchecked:
400
 
        widgetDocker.spaces->hide();
401
 
        widgetDocker.count_spaces->hide();
402
 
        cfgGroup.writeEntry("CharspacesVisible",false);
403
 
        cfgGroup.sync();
404
 
        break;
405
 
    default:
406
 
        break;
407
 
    }
408
 
}
409
 
 
410
 
void KWStatistics::charnospaceDisplayChanged(int state)
411
 
{
412
 
    KConfigGroup cfgGroup = KGlobal::config()->group("Statistics");
413
 
    switch (state) {
414
 
    case Qt::Checked:
415
 
        widgetDocker.nospaces->show();
416
 
        widgetDocker.count_nospaces->show();
417
 
        cfgGroup.writeEntry("CharnospacesVisible",true);
418
 
        cfgGroup.sync();
419
 
        break;
420
 
    case Qt::Unchecked:
421
 
        widgetDocker.nospaces->hide();
422
 
        widgetDocker.count_nospaces->hide();
423
 
        cfgGroup.writeEntry("CharnospacesVisible",false);
424
 
        cfgGroup.sync();
425
 
        break;
426
 
    default:
427
 
        break;
428
 
    }
429
 
}
430
 
void KWStatistics::eastDisplayChanged(int state)
431
 
{
432
 
    KConfigGroup cfgGroup = KGlobal::config()->group("Statistics");
433
 
    switch (state) {
434
 
    case Qt::Checked:
435
 
        widgetDocker.Cjkchars->show();
436
 
        widgetDocker.count_cjkchars->show();
437
 
        cfgGroup.writeEntry("EastAsianCharactersVisible",true);
438
 
        cfgGroup.sync();
439
 
        break;
440
 
    case Qt::Unchecked:
441
 
        widgetDocker.Cjkchars->hide();
442
 
        widgetDocker.count_cjkchars->hide();
443
 
        cfgGroup.writeEntry("EastAsianCharactersVisible",false);
444
 
        cfgGroup.sync();
445
 
        break;
446
 
    default:
447
 
        break;
448
 
    }
449
 
}
450
 
void KWStatistics::fleschDisplayChanged(int state)
451
 
{
452
 
    KConfigGroup cfgGroup = KGlobal::config()->group("Statistics");
453
 
    switch (state) {
454
 
    case Qt::Checked:
455
 
        widgetDocker.Flesch->show();
456
 
        widgetDocker.count_flesch->show();
457
 
        cfgGroup.writeEntry("FleschVisible",true);
458
 
        cfgGroup.sync();
459
 
        break;
460
 
    case Qt::Unchecked:
461
 
        widgetDocker.Flesch->hide();
462
 
        widgetDocker.count_flesch->hide();
463
 
        cfgGroup.writeEntry("FleschVisible",false);
464
 
        cfgGroup.sync();
465
 
        break;
466
 
    default:
467
 
        break;
468
 
    }
469
 
}
470
 
 
471