Coverage Report

Created: 2026-01-25 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/kdesdk-thumbnailers/po_thumbnailer/pocreator.cpp
Line
Count
Source
1
/*
2
    SPDX-FileCopyrightText: 2011-2012 Ni Hui <shuizhuyuanluo@126.com>
3
4
    SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
5
*/
6
7
#include "pocreator.h"
8
9
#include <gettext-po.h>
10
#include <QColor>
11
#include <QImage>
12
#include <QPainter>
13
14
#include <KPluginFactory>
15
16
0
K_PLUGIN_CLASS_WITH_JSON(PoCreator, "pothumbnail.json")
Unexecuted instantiation: pothumbnail_factory::tr(char const*, char const*, int)
Unexecuted instantiation: pothumbnail_factory::~pothumbnail_factory()
17
0
18
0
static bool readerror = false;
19
0
20
0
static void xerror( int severity,
21
0
                    po_message_t /*message*/,
22
0
                    const char */*filename*/, size_t /*lineno*/, size_t /*column*/,
23
0
                    int /*multiline_p*/, const char */*message_text*/ )
24
3.33M
{
25
3.33M
    if ( severity == PO_SEVERITY_ERROR || severity == PO_SEVERITY_FATAL_ERROR )
26
3.30M
        readerror = true;
27
3.33M
}
28
29
static void xerror2( int severity,
30
                     po_message_t /*message1*/,
31
                     const char */*filename1*/, size_t /*lineno1*/, size_t /*column1*/,
32
                     int /*multiline_p1*/, const char */*message_text1*/,
33
                     po_message_t /*message2*/,
34
                     const char */*filename2*/, size_t /*lineno2*/, size_t /*column2*/,
35
                     int /*multiline_p2*/, const char */*message_text2*/ )
36
46.6k
{
37
46.6k
    if ( severity == PO_SEVERITY_ERROR || severity == PO_SEVERITY_FATAL_ERROR )
38
46.6k
        readerror = true;
39
46.6k
}
40
41
static bool get_po_info( const char* filepath, int& translate, int& untranslate, int& fuzzy, int& obsolete )
42
8.54k
{
43
8.54k
    po_file_t pofile;
44
8.54k
    const struct po_xerror_handler handler = { xerror, xerror2 };
45
46
8.54k
    pofile = po_file_read( filepath, &handler );
47
8.54k
    if ( pofile == NULL ) {
48
0
         return false;
49
0
    }
50
8.54k
    if ( readerror ) {
51
8.54k
        po_file_free( pofile );
52
8.54k
        return false;
53
8.54k
    }
54
55
0
    po_message_iterator_t it;
56
0
    it = po_message_iterator( pofile, NULL );
57
0
    po_message_t msg;
58
0
    const char* msgstr;
59
0
    while ( ( msg = po_next_message( it ) ) != NULL ) {
60
0
        if ( po_message_is_obsolete( msg ) )
61
0
            ++obsolete;
62
0
        else if ( po_message_is_fuzzy( msg ) )
63
0
            ++fuzzy;
64
0
        else {
65
0
            msgstr = po_message_msgstr( msg );
66
0
            if ( msgstr[0] == '\0' )
67
0
                ++untranslate;
68
0
            else
69
0
                ++translate;
70
0
        }
71
0
    }
72
0
    po_message_iterator_free( it );
73
74
    /// do not count domain header as translated message
75
0
    const char* header = po_file_domain_header( pofile, NULL );
76
0
    if ( header != NULL )
77
0
        --translate;
78
79
0
    po_file_free( pofile );
80
81
0
    return true;
82
8.54k
}
83
84
PoCreator::PoCreator(QObject *parent, const QVariantList &args)
85
8.54k
    : KIO::ThumbnailCreator(parent, args)
86
8.54k
{
87
8.54k
}
88
89
PoCreator::~PoCreator()
90
8.54k
{
91
8.54k
}
92
93
KIO::ThumbnailResult PoCreator::create( const KIO::ThumbnailRequest &request )
94
8.54k
{
95
8.54k
    int translate = 0;
96
8.54k
    int untranslate = 0;
97
8.54k
    int fuzzy = 0;
98
8.54k
    int obsolete = 0;
99
100
8.54k
    if ( !get_po_info( request.url().toLocalFile().toLocal8Bit().constData(), translate, untranslate, fuzzy, obsolete ) )
101
8.54k
        return KIO::ThumbnailResult::fail();
102
103
0
    int total = translate + untranslate + fuzzy + obsolete;
104
105
0
    if (total == 0) {
106
        // Treat a .po file with no strings as an invalid file
107
0
        return KIO::ThumbnailResult::fail();
108
0
    }
109
110
0
    int d = ( request.targetSize().width() < request.targetSize().height() ) ? request.targetSize().width() - 2 : request.targetSize().height() - 2;
111
112
0
    QImage pix( d + 2, d + 2, QImage::Format_ARGB32_Premultiplied );
113
0
    pix.fill( Qt::transparent ); /// transparent background
114
115
0
    int circle = 16 * 360;
116
0
    int untranslateAngle = untranslate * circle / total;
117
0
    int fuzzyAngle = fuzzy * circle / total;
118
0
    int obsoleteAngle = obsolete * circle / total;
119
0
    int translateAngle = circle - untranslateAngle - fuzzyAngle - obsoleteAngle;
120
121
0
    QPainter p( &pix );
122
0
    p.setRenderHint( QPainter::Antialiasing );
123
124
0
    if ( fuzzyAngle > 0 ) {
125
0
        p.setBrush( Qt::blue );
126
0
        if ( fuzzy == total )
127
0
            p.drawEllipse( 1, 1, d, d );
128
0
        else
129
0
            p.drawPie( 1, 1, d, d, 0, -fuzzyAngle );
130
0
    }
131
0
    if ( untranslateAngle > 0 ) {
132
0
        p.setBrush( Qt::red );
133
0
        if ( untranslate == total )
134
0
            p.drawEllipse( 1, 1, d, d );
135
0
        else
136
0
            p.drawPie( 1, 1, d, d, -fuzzyAngle, -untranslateAngle );
137
0
    }
138
0
    if ( obsoleteAngle > 0 ) {
139
0
        p.setBrush( Qt::yellow );
140
0
        if ( obsolete == total )
141
0
            p.drawEllipse( 1, 1, d, d );
142
0
        else
143
0
            p.drawPie( 1, 1, d, d, -fuzzyAngle-untranslateAngle, -obsoleteAngle );
144
0
    }
145
0
    if ( translateAngle > 0 ) {
146
0
        p.setBrush( Qt::darkGreen );
147
0
        if ( translate == total )
148
0
            p.drawEllipse( 1, 1, d, d );
149
0
        else
150
0
            p.drawPie( 1, 1, d, d, -fuzzyAngle-untranslateAngle-obsoleteAngle, -translateAngle );
151
0
    }
152
153
0
    return KIO::ThumbnailResult::pass(pix);
154
0
}
155
156
#include "pocreator.moc"