src/hbcore/utils/hbtextmeasurementutility.cpp
author hgs
Mon, 18 Oct 2010 18:23:13 +0300
changeset 34 ed14f46c0e55
permissions -rw-r--r--
201041
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
34
hgs
parents:
diff changeset
     1
/****************************************************************************
hgs
parents:
diff changeset
     2
**
hgs
parents:
diff changeset
     3
** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
hgs
parents:
diff changeset
     4
** All rights reserved.
hgs
parents:
diff changeset
     5
** Contact: Nokia Corporation (developer.feedback@nokia.com)
hgs
parents:
diff changeset
     6
**
hgs
parents:
diff changeset
     7
** This file is part of the HbCore module of the UI Extensions for Mobile.
hgs
parents:
diff changeset
     8
**
hgs
parents:
diff changeset
     9
** GNU Lesser General Public License Usage
hgs
parents:
diff changeset
    10
** This file may be used under the terms of the GNU Lesser General Public
hgs
parents:
diff changeset
    11
** License version 2.1 as published by the Free Software Foundation and
hgs
parents:
diff changeset
    12
** appearing in the file LICENSE.LGPL included in the packaging of this file.
hgs
parents:
diff changeset
    13
** Please review the following information to ensure the GNU Lesser General
hgs
parents:
diff changeset
    14
** Public License version 2.1 requirements will be met:
hgs
parents:
diff changeset
    15
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
hgs
parents:
diff changeset
    16
**
hgs
parents:
diff changeset
    17
** In addition, as a special exception, Nokia gives you certain additional
hgs
parents:
diff changeset
    18
** rights.  These rights are described in the Nokia Qt LGPL Exception
hgs
parents:
diff changeset
    19
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
hgs
parents:
diff changeset
    20
**
hgs
parents:
diff changeset
    21
** If you have questions regarding the use of this file, please contact
hgs
parents:
diff changeset
    22
** Nokia at developer.feedback@nokia.com.
hgs
parents:
diff changeset
    23
**
hgs
parents:
diff changeset
    24
****************************************************************************/
hgs
parents:
diff changeset
    25
hgs
parents:
diff changeset
    26
#include "hbtextmeasurementutility_r.h"
hgs
parents:
diff changeset
    27
#include "hbtextmeasurementutility_r_p.h"
hgs
parents:
diff changeset
    28
#include "hbwidgetbase.h"
hgs
parents:
diff changeset
    29
#include "hbfontspec.h"
hgs
parents:
diff changeset
    30
#include "hbinstance.h"
hgs
parents:
diff changeset
    31
#include "hbfeaturemanager_r.h"
hgs
parents:
diff changeset
    32
hgs
parents:
diff changeset
    33
#include <QGraphicsWidget>
hgs
parents:
diff changeset
    34
#include <QTextStream>
hgs
parents:
diff changeset
    35
#include <QFile>
hgs
parents:
diff changeset
    36
#include <QDir>
hgs
parents:
diff changeset
    37
#include <QDate>
hgs
parents:
diff changeset
    38
#include <QTimer>
hgs
parents:
diff changeset
    39
#include <QFont>
hgs
parents:
diff changeset
    40
hgs
parents:
diff changeset
    41
#include <QDebug> // for qWarning
hgs
parents:
diff changeset
    42
hgs
parents:
diff changeset
    43
#include <qmath.h>
hgs
parents:
diff changeset
    44
hgs
parents:
diff changeset
    45
#ifndef Q_OS_SYMBIAN
hgs
parents:
diff changeset
    46
#include <iostream>
hgs
parents:
diff changeset
    47
#endif
hgs
parents:
diff changeset
    48
hgs
parents:
diff changeset
    49
const QChar KCSVSeparator(',');
hgs
parents:
diff changeset
    50
const QString KUnknown("UNKNOWN");
hgs
parents:
diff changeset
    51
hgs
parents:
diff changeset
    52
class HbTextRecord
hgs
parents:
diff changeset
    53
{
hgs
parents:
diff changeset
    54
public:
hgs
parents:
diff changeset
    55
    HbTextRecord();
hgs
parents:
diff changeset
    56
    QString fontLogicalName() const;
hgs
parents:
diff changeset
    57
    HbFontSpec::Role fontRole(const QString logicalName) const;
hgs
parents:
diff changeset
    58
    bool operator<(const HbTextRecord &other)const;
hgs
parents:
diff changeset
    59
    static bool recordLessThan(HbTextRecord *rc1, HbTextRecord *rc2);
hgs
parents:
diff changeset
    60
    static bool recordFullCompare(HbTextRecord *rc1, HbTextRecord *rc2);
hgs
parents:
diff changeset
    61
public:
hgs
parents:
diff changeset
    62
    QString mRecordName;  // Record name
hgs
parents:
diff changeset
    63
    int mWidth;           // Text item width (in pixels)
hgs
parents:
diff changeset
    64
    HbFontSpec mFontSpec; // Font spec
hgs
parents:
diff changeset
    65
    int mRowCount;
hgs
parents:
diff changeset
    66
};
hgs
parents:
diff changeset
    67
hgs
parents:
diff changeset
    68
hgs
parents:
diff changeset
    69
HbTextRecord::HbTextRecord()
hgs
parents:
diff changeset
    70
{
hgs
parents:
diff changeset
    71
}
hgs
parents:
diff changeset
    72
hgs
parents:
diff changeset
    73
QString HbTextRecord::fontLogicalName() const
hgs
parents:
diff changeset
    74
{
hgs
parents:
diff changeset
    75
    QString logicalName(KUnknown);
hgs
parents:
diff changeset
    76
    switch(mFontSpec.role()){
hgs
parents:
diff changeset
    77
        case HbFontSpec::Primary:
hgs
parents:
diff changeset
    78
            logicalName = "qfn_primary";
hgs
parents:
diff changeset
    79
            break;
hgs
parents:
diff changeset
    80
        case HbFontSpec::Secondary:
hgs
parents:
diff changeset
    81
            logicalName = "qfn_secondary";
hgs
parents:
diff changeset
    82
            break;
hgs
parents:
diff changeset
    83
        case HbFontSpec::Title:
hgs
parents:
diff changeset
    84
            logicalName = "qfn_title";
hgs
parents:
diff changeset
    85
            break;
hgs
parents:
diff changeset
    86
        case HbFontSpec::PrimarySmall:
hgs
parents:
diff changeset
    87
            logicalName = "qfn_primary_small";
hgs
parents:
diff changeset
    88
            break;
hgs
parents:
diff changeset
    89
        case HbFontSpec::Digital:
hgs
parents:
diff changeset
    90
            logicalName = "qfn_digital";
hgs
parents:
diff changeset
    91
            break;
hgs
parents:
diff changeset
    92
        default:
hgs
parents:
diff changeset
    93
            break;
hgs
parents:
diff changeset
    94
    }
hgs
parents:
diff changeset
    95
    return logicalName;
hgs
parents:
diff changeset
    96
}
hgs
parents:
diff changeset
    97
hgs
parents:
diff changeset
    98
HbFontSpec::Role HbTextRecord::fontRole(const QString logicalName) const
hgs
parents:
diff changeset
    99
{
hgs
parents:
diff changeset
   100
    HbFontSpec::Role fontRole(HbFontSpec::Undefined);
hgs
parents:
diff changeset
   101
    if ( logicalName == "qfn_primary" ) {
hgs
parents:
diff changeset
   102
        fontRole = HbFontSpec::Primary;
hgs
parents:
diff changeset
   103
    } else if ( logicalName == "qfn_secondary" ) {
hgs
parents:
diff changeset
   104
        fontRole = HbFontSpec::Secondary;
hgs
parents:
diff changeset
   105
    } else if ( logicalName == "qfn_title" ) {
hgs
parents:
diff changeset
   106
        fontRole = HbFontSpec::Title;
hgs
parents:
diff changeset
   107
    } else if ( logicalName == "qfn_primary_small" ) {
hgs
parents:
diff changeset
   108
        fontRole = HbFontSpec::PrimarySmall;
hgs
parents:
diff changeset
   109
    } else if ( logicalName == "qfn_digital" ) {
hgs
parents:
diff changeset
   110
        fontRole = HbFontSpec::Digital;
hgs
parents:
diff changeset
   111
    }
hgs
parents:
diff changeset
   112
    return fontRole;
hgs
parents:
diff changeset
   113
}
hgs
parents:
diff changeset
   114
hgs
parents:
diff changeset
   115
bool HbTextRecord::operator<(const HbTextRecord& other)const
hgs
parents:
diff changeset
   116
{
hgs
parents:
diff changeset
   117
    return this->mRecordName < other.mRecordName;
hgs
parents:
diff changeset
   118
}
hgs
parents:
diff changeset
   119
hgs
parents:
diff changeset
   120
bool HbTextRecord::recordLessThan(HbTextRecord* rc1, HbTextRecord* rc2)
hgs
parents:
diff changeset
   121
{
hgs
parents:
diff changeset
   122
    return rc1->mRecordName < rc2->mRecordName;
hgs
parents:
diff changeset
   123
}
hgs
parents:
diff changeset
   124
hgs
parents:
diff changeset
   125
bool HbTextRecord::recordFullCompare(HbTextRecord* rc1, HbTextRecord* rc2)
hgs
parents:
diff changeset
   126
{
hgs
parents:
diff changeset
   127
    if (!rc1->mRecordName.compare(rc2->mRecordName)) {
hgs
parents:
diff changeset
   128
        if (rc1->mFontSpec == rc2->mFontSpec) {
hgs
parents:
diff changeset
   129
            if (rc1->mRowCount == rc2->mRowCount) {
hgs
parents:
diff changeset
   130
                if (rc1->mWidth == rc2->mWidth) {
hgs
parents:
diff changeset
   131
                    return true;
hgs
parents:
diff changeset
   132
                } else {
hgs
parents:
diff changeset
   133
                    qDebug() << "HbTextMeasurementUtility::recordFullCompare: Sizes don't match";
hgs
parents:
diff changeset
   134
                }
hgs
parents:
diff changeset
   135
            } else {
hgs
parents:
diff changeset
   136
                qDebug() << "HbTextMeasurementUtility::recordFullCompare: Row counts don't match";
hgs
parents:
diff changeset
   137
            }
hgs
parents:
diff changeset
   138
        } else {
hgs
parents:
diff changeset
   139
            qDebug() << "HbTextMeasurementUtility::recordFullCompare: Fonts don't match";
hgs
parents:
diff changeset
   140
        }
hgs
parents:
diff changeset
   141
    } else {
hgs
parents:
diff changeset
   142
        qDebug() << "HbTextMeasurementUtility::recordFullCompare: Names don't match";
hgs
parents:
diff changeset
   143
    }
hgs
parents:
diff changeset
   144
    qDebug() << "HbTextMeasurementUtility::recordFullCompare: -- record1:"
hgs
parents:
diff changeset
   145
        << rc1->mRecordName << rc1->mFontSpec.role() << rc1->mFontSpec.textHeight() << rc1->mRowCount << rc1->mWidth;
hgs
parents:
diff changeset
   146
    qDebug() << "HbTextMeasurementUtility::recordFullCompare: -- record2:"
hgs
parents:
diff changeset
   147
        << rc2->mRecordName << rc2->mFontSpec.role() << rc2->mFontSpec.textHeight() << rc2->mRowCount << rc2->mWidth;
hgs
parents:
diff changeset
   148
    return false;
hgs
parents:
diff changeset
   149
}
hgs
parents:
diff changeset
   150
hgs
parents:
diff changeset
   151
hgs
parents:
diff changeset
   152
hgs
parents:
diff changeset
   153
void HbTextMeasurementUtilityPrivate::readEntries(QTextStream &csvReader)
hgs
parents:
diff changeset
   154
{
hgs
parents:
diff changeset
   155
    // Read the file header.
hgs
parents:
diff changeset
   156
    QString line = csvReader.readLine();
hgs
parents:
diff changeset
   157
    
hgs
parents:
diff changeset
   158
    while ( !csvReader.atEnd() ) {
hgs
parents:
diff changeset
   159
hgs
parents:
diff changeset
   160
        line = csvReader.readLine();
hgs
parents:
diff changeset
   161
        QStringList list = line.split(KCSVSeparator);
hgs
parents:
diff changeset
   162
        if ( list.count() != 5 ) {
hgs
parents:
diff changeset
   163
            qDebug() << "HbTextMeasurementUtilityPrivate::readEntries: Invalid csv file row read";
hgs
parents:
diff changeset
   164
            continue;
hgs
parents:
diff changeset
   165
        }
hgs
parents:
diff changeset
   166
        HbTextRecord *record = new HbTextRecord();        
hgs
parents:
diff changeset
   167
        record->mRecordName = list.at(0);
hgs
parents:
diff changeset
   168
        record->mFontSpec.setRole(record->fontRole(list.at(1)));
hgs
parents:
diff changeset
   169
        record->mFontSpec.setTextHeight(list.at(2).toInt());
hgs
parents:
diff changeset
   170
        record->mWidth = list.at(3).toInt();
hgs
parents:
diff changeset
   171
        record->mRowCount = list.at(4).toInt();
hgs
parents:
diff changeset
   172
        records.append(record);
hgs
parents:
diff changeset
   173
    }
hgs
parents:
diff changeset
   174
}
hgs
parents:
diff changeset
   175
hgs
parents:
diff changeset
   176
hgs
parents:
diff changeset
   177
/*!
hgs
parents:
diff changeset
   178
    Write a report headers to csv file
hgs
parents:
diff changeset
   179
    \internal
hgs
parents:
diff changeset
   180
*/
hgs
parents:
diff changeset
   181
void HbTextMeasurementUtilityPrivate::writeHeaders(QTextStream &csvWriter)
hgs
parents:
diff changeset
   182
{
hgs
parents:
diff changeset
   183
    csvWriter << "Layout";
hgs
parents:
diff changeset
   184
    csvWriter << KCSVSeparator;
hgs
parents:
diff changeset
   185
    csvWriter << "Font";
hgs
parents:
diff changeset
   186
    csvWriter << KCSVSeparator;
hgs
parents:
diff changeset
   187
    csvWriter << "Row height";
hgs
parents:
diff changeset
   188
    csvWriter << KCSVSeparator;
hgs
parents:
diff changeset
   189
    csvWriter << "Row width";
hgs
parents:
diff changeset
   190
    csvWriter << KCSVSeparator;
hgs
parents:
diff changeset
   191
    csvWriter << "Max rows";
hgs
parents:
diff changeset
   192
    csvWriter << "\n";
hgs
parents:
diff changeset
   193
}
hgs
parents:
diff changeset
   194
hgs
parents:
diff changeset
   195
/*!
hgs
parents:
diff changeset
   196
    Write a text item record to csv file
hgs
parents:
diff changeset
   197
    \internal
hgs
parents:
diff changeset
   198
*/
hgs
parents:
diff changeset
   199
void HbTextMeasurementUtilityPrivate::writeEntry(
hgs
parents:
diff changeset
   200
    QTextStream &csvWriter,
hgs
parents:
diff changeset
   201
    const HbTextRecord *record)
hgs
parents:
diff changeset
   202
{
hgs
parents:
diff changeset
   203
    // "Layout"
hgs
parents:
diff changeset
   204
    csvWriter << record->mRecordName;
hgs
parents:
diff changeset
   205
    csvWriter << KCSVSeparator;
hgs
parents:
diff changeset
   206
    // "Font"
hgs
parents:
diff changeset
   207
    csvWriter << record->fontLogicalName();
hgs
parents:
diff changeset
   208
    csvWriter << KCSVSeparator;
hgs
parents:
diff changeset
   209
    // "Row height"
hgs
parents:
diff changeset
   210
    csvWriter << qRound(record->mFontSpec.textHeight()-0.5); // Floor.
hgs
parents:
diff changeset
   211
    csvWriter << KCSVSeparator;
hgs
parents:
diff changeset
   212
    // "Row width"
hgs
parents:
diff changeset
   213
    csvWriter << record->mWidth;
hgs
parents:
diff changeset
   214
    csvWriter << KCSVSeparator;
hgs
parents:
diff changeset
   215
    // "Max rows"
hgs
parents:
diff changeset
   216
    csvWriter << record->mRowCount;
hgs
parents:
diff changeset
   217
    csvWriter << '\n';
hgs
parents:
diff changeset
   218
}
hgs
parents:
diff changeset
   219
hgs
parents:
diff changeset
   220
/*!
hgs
parents:
diff changeset
   221
    Validate records by removing duplicate items.
hgs
parents:
diff changeset
   222
    \internal
hgs
parents:
diff changeset
   223
*/
hgs
parents:
diff changeset
   224
bool HbTextMeasurementUtilityPrivate::validateRecords(HbDeviceProfile &profile)
hgs
parents:
diff changeset
   225
{
hgs
parents:
diff changeset
   226
    if (records.isEmpty()) {
hgs
parents:
diff changeset
   227
        qDebug() << "HbTextMeasurementUtility::validateRecords: No result entries";
hgs
parents:
diff changeset
   228
        return false;
hgs
parents:
diff changeset
   229
    }
hgs
parents:
diff changeset
   230
    QList<HbTextRecord*> temp;
hgs
parents:
diff changeset
   231
    qSort(records.begin(), records.end(), &HbTextRecord::recordLessThan);
hgs
parents:
diff changeset
   232
    bool ret = true;
hgs
parents:
diff changeset
   233
hgs
parents:
diff changeset
   234
    foreach (HbTextRecord *record, records) {
hgs
parents:
diff changeset
   235
hgs
parents:
diff changeset
   236
        bool validRecord = true;
hgs
parents:
diff changeset
   237
hgs
parents:
diff changeset
   238
        for(int i=0; i<temp.count();i++) {
hgs
parents:
diff changeset
   239
            if (!temp[i]->mRecordName.compare(record->mRecordName)) {
hgs
parents:
diff changeset
   240
                // duplicate with same data.
hgs
parents:
diff changeset
   241
                if (HbTextRecord::recordFullCompare(temp[i], record)) {
hgs
parents:
diff changeset
   242
                    qDebug() << "HbTextMeasurementUtility::validateRecords: Duplicate removed";
hgs
parents:
diff changeset
   243
                    validRecord = false;
hgs
parents:
diff changeset
   244
                    break;
hgs
parents:
diff changeset
   245
                } else { // duplicates id with unequal data.
hgs
parents:
diff changeset
   246
                    qDebug() << "HbTextMeasurementUtility::validateRecords: Duplicate text id found";
hgs
parents:
diff changeset
   247
                    ret = false;
hgs
parents:
diff changeset
   248
                    continue;  // search still duplicates with same data.
hgs
parents:
diff changeset
   249
                }
hgs
parents:
diff changeset
   250
            }
hgs
parents:
diff changeset
   251
        }
hgs
parents:
diff changeset
   252
        if (validRecord) {
hgs
parents:
diff changeset
   253
            temp.append(record);
hgs
parents:
diff changeset
   254
        } else {
hgs
parents:
diff changeset
   255
            delete record;
hgs
parents:
diff changeset
   256
        }
hgs
parents:
diff changeset
   257
    }
hgs
parents:
diff changeset
   258
hgs
parents:
diff changeset
   259
    records = temp;
hgs
parents:
diff changeset
   260
    foreach (const HbTextRecord *record, records) {
hgs
parents:
diff changeset
   261
        if ( !record->fontLogicalName().compare(KUnknown) ) {
hgs
parents:
diff changeset
   262
            qDebug() << "HbTextMeasurementUtility::validateRecords: Result item" << record->mRecordName << "Fontspec is null";
hgs
parents:
diff changeset
   263
            ret = false;
hgs
parents:
diff changeset
   264
        }
hgs
parents:
diff changeset
   265
hgs
parents:
diff changeset
   266
        if ( record->mWidth > profile.logicalSize().width() ) {
hgs
parents:
diff changeset
   267
            qDebug() << "HbTextMeasurementUtility::validateRecords: Result item" << record->mRecordName << "width is too wide";
hgs
parents:
diff changeset
   268
            qDebug() << "HbTextMeasurementUtility::validateRecords: Profile width: " << profile.logicalSize().width();
hgs
parents:
diff changeset
   269
            qDebug() << "HbTextMeasurementUtility::validateRecords: Record width:" << record->mWidth;
hgs
parents:
diff changeset
   270
            ret = false;
hgs
parents:
diff changeset
   271
        }
hgs
parents:
diff changeset
   272
    }
hgs
parents:
diff changeset
   273
    return ret;
hgs
parents:
diff changeset
   274
}
hgs
parents:
diff changeset
   275
hgs
parents:
diff changeset
   276
/*!
hgs
parents:
diff changeset
   277
    \internal
hgs
parents:
diff changeset
   278
*/
hgs
parents:
diff changeset
   279
void HbTextMeasurementUtilityPrivate::doMeasureItems()
hgs
parents:
diff changeset
   280
{
hgs
parents:
diff changeset
   281
#ifndef HB_TEXT_MEASUREMENT_UTILITY
hgs
parents:
diff changeset
   282
    return;
hgs
parents:
diff changeset
   283
#else
hgs
parents:
diff changeset
   284
    // Process all pending events.
hgs
parents:
diff changeset
   285
    for (int i = 0; i < 3; ++i) {
hgs
parents:
diff changeset
   286
        QCoreApplication::sendPostedEvents();
hgs
parents:
diff changeset
   287
        QCoreApplication::processEvents();
hgs
parents:
diff changeset
   288
    }
hgs
parents:
diff changeset
   289
hgs
parents:
diff changeset
   290
    QList<HbMainWindow*> mainWindows;
hgs
parents:
diff changeset
   291
    if (mWindow) {
hgs
parents:
diff changeset
   292
        mainWindows.append(mWindow);
hgs
parents:
diff changeset
   293
    } else {
hgs
parents:
diff changeset
   294
        mainWindows = hbInstance->allMainWindows();
hgs
parents:
diff changeset
   295
    }
hgs
parents:
diff changeset
   296
    foreach (HbMainWindow* mainWindow, mainWindows ) {
hgs
parents:
diff changeset
   297
        QGraphicsScene* scene = mainWindow->scene(); //krazy:exclude=qclasses
hgs
parents:
diff changeset
   298
        QList<QGraphicsItem*> sceneItems = scene->items();
hgs
parents:
diff changeset
   299
        foreach (QGraphicsItem* sceneItem, sceneItems ) {
hgs
parents:
diff changeset
   300
            if ( sceneItem->isWidget() ) {
hgs
parents:
diff changeset
   301
                HbWidgetBase* widget = qobject_cast<HbWidgetBase*>(static_cast<QGraphicsWidget*>(sceneItem));
hgs
parents:
diff changeset
   302
                QVariant textId = widget
hgs
parents:
diff changeset
   303
                    ? widget->property( HbTextMeasurementUtilityNameSpace::textIdPropertyName )
hgs
parents:
diff changeset
   304
                    : QVariant();
hgs
parents:
diff changeset
   305
                if( widget && widget->isVisible() && ( textId != QVariant::Invalid ) 
hgs
parents:
diff changeset
   306
                    && ( !textId.toString().isEmpty() ) ) {
hgs
parents:
diff changeset
   307
                    HbTextRecord *record = new HbTextRecord();
hgs
parents:
diff changeset
   308
                    record->mRecordName = textId.toString();
hgs
parents:
diff changeset
   309
                    record->mWidth = qRound(widget->size().width() - 0.5); // Floor
hgs
parents:
diff changeset
   310
                    record->mFontSpec = widget->effectiveFontSpec();
hgs
parents:
diff changeset
   311
                    if ( record->mFontSpec != widget->fontSpec() ) {
hgs
parents:
diff changeset
   312
                        qDebug() << "HbTextMeasurementUtility::measureItems: fontSpec and effectiveFontSpec do not match for item"
hgs
parents:
diff changeset
   313
                                 << record->mRecordName;
hgs
parents:
diff changeset
   314
                        qDebug() << "- fontSpec, role:" << widget->fontSpec().role() << "textHeight:" << widget->fontSpec().textHeight();
hgs
parents:
diff changeset
   315
                        qDebug() << "- effectiveFontSpec, role:" << record->mFontSpec.role() << "textHeight:" << record->mFontSpec.textHeight();
hgs
parents:
diff changeset
   316
                    }
hgs
parents:
diff changeset
   317
                    record->mFontSpec.setTextHeight(qRound(record->mFontSpec.textHeight() - 0.5)); // Floor
hgs
parents:
diff changeset
   318
                    QVariant rowCount = widget->property( HbTextMeasurementUtilityNameSpace::textMaxLines );
hgs
parents:
diff changeset
   319
                    record->mRowCount = rowCount.toInt();
hgs
parents:
diff changeset
   320
                    if (record->mRowCount <= 0) {
hgs
parents:
diff changeset
   321
                        record->mRowCount = -1;
hgs
parents:
diff changeset
   322
                    }
hgs
parents:
diff changeset
   323
                    records.append(record);
hgs
parents:
diff changeset
   324
                }
hgs
parents:
diff changeset
   325
            }
hgs
parents:
diff changeset
   326
        }
hgs
parents:
diff changeset
   327
    }
hgs
parents:
diff changeset
   328
#endif
hgs
parents:
diff changeset
   329
}
hgs
parents:
diff changeset
   330
hgs
parents:
diff changeset
   331
QString HbTextMeasurementUtilityPrivate::reportFilePath(HbDeviceProfile &profile, const QString &domainName) const
hgs
parents:
diff changeset
   332
{
hgs
parents:
diff changeset
   333
#ifdef Q_OS_SYMBIAN
hgs
parents:
diff changeset
   334
    const QString KDriveF("F:\\");
hgs
parents:
diff changeset
   335
    const QString KDriveC("C:\\");
hgs
parents:
diff changeset
   336
    const QString KDirectory("data\\log\\qtestcase\\loc\\"); 
hgs
parents:
diff changeset
   337
hgs
parents:
diff changeset
   338
    QString filePath;
hgs
parents:
diff changeset
   339
    if (QFile::exists(KDriveF)) {
hgs
parents:
diff changeset
   340
        filePath = KDriveF + KDirectory;
hgs
parents:
diff changeset
   341
    } else {
hgs
parents:
diff changeset
   342
        filePath = KDriveC + KDirectory;
hgs
parents:
diff changeset
   343
    }
hgs
parents:
diff changeset
   344
#else
hgs
parents:
diff changeset
   345
    QString filePath(QDir::tempPath());
hgs
parents:
diff changeset
   346
    filePath.append(QDir::separator());
hgs
parents:
diff changeset
   347
    filePath.append("loc");
hgs
parents:
diff changeset
   348
    filePath.append(QDir::separator());
hgs
parents:
diff changeset
   349
    filePath.append(profile.name());
hgs
parents:
diff changeset
   350
    filePath.append(QDir::separator());
hgs
parents:
diff changeset
   351
#endif
hgs
parents:
diff changeset
   352
    filePath = QDir::toNativeSeparators(filePath);
hgs
parents:
diff changeset
   353
hgs
parents:
diff changeset
   354
    QDir dir(filePath);
hgs
parents:
diff changeset
   355
    if (!dir.exists()) {
hgs
parents:
diff changeset
   356
        dir.mkpath(filePath);
hgs
parents:
diff changeset
   357
    }
hgs
parents:
diff changeset
   358
hgs
parents:
diff changeset
   359
    // Make sure there are no illegal characters in "domainName"
hgs
parents:
diff changeset
   360
    QString tempName = domainName;
hgs
parents:
diff changeset
   361
    tempName.remove(QRegExp("[^a-zA-Z0-9]"));
hgs
parents:
diff changeset
   362
    if (tempName.isEmpty()) {
hgs
parents:
diff changeset
   363
        tempName = "unknown";
hgs
parents:
diff changeset
   364
    }
hgs
parents:
diff changeset
   365
hgs
parents:
diff changeset
   366
    filePath.append(tempName);
hgs
parents:
diff changeset
   367
    filePath.append('_');
hgs
parents:
diff changeset
   368
    filePath.append(profile.name());
hgs
parents:
diff changeset
   369
    filePath.append('_');
hgs
parents:
diff changeset
   370
    filePath.append(QString::number(QDate::currentDate().year()));
hgs
parents:
diff changeset
   371
    filePath.append("wk");
hgs
parents:
diff changeset
   372
    filePath.append(QString::number(QDate::currentDate().weekNumber()));
hgs
parents:
diff changeset
   373
    filePath.append(".csv");
hgs
parents:
diff changeset
   374
    return filePath;
hgs
parents:
diff changeset
   375
}
hgs
parents:
diff changeset
   376
hgs
parents:
diff changeset
   377
hgs
parents:
diff changeset
   378
/*!
hgs
parents:
diff changeset
   379
    @alpha
hgs
parents:
diff changeset
   380
    @hbcore
hgs
parents:
diff changeset
   381
    \class HbTextMeasurementUtility
hgs
parents:
diff changeset
   382
    \brief HbTextMeasurementUtility is used for measuring available space for localized texts.
hgs
parents:
diff changeset
   383
    
hgs
parents:
diff changeset
   384
    This class collects metrics from localized text items and writes a report to 
hgs
parents:
diff changeset
   385
    a CSV file. The report is intended to be used when lenghts of text strings are decided
hgs
parents:
diff changeset
   386
    and texts are localized to different language variants.
hgs
parents:
diff changeset
   387
hgs
parents:
diff changeset
   388
    The report contains the following data for each measured text item:
hgs
parents:
diff changeset
   389
    - Layout: The logical name for the measuser text item (typically the logical text id).
hgs
parents:
diff changeset
   390
    - Font: The logical fong (e.g. qfn_primary, qfn_secondary, etc.).
hgs
parents:
diff changeset
   391
    - Row height: Height of one text row in pixels. This measure corresponds to HbFontSpec::textHeight().
hgs
parents:
diff changeset
   392
    - Row width: Width of one text row in pixels.
hgs
parents:
diff changeset
   393
    - Max rows: Maximum row count for the measured text item.
hgs
parents:
diff changeset
   394
hgs
parents:
diff changeset
   395
    The text strings (set to text items) must have been allocated with hbTrId function.
hgs
parents:
diff changeset
   396
    It stores the logical text id's to text items and this uses that information when
hgs
parents:
diff changeset
   397
    collecting the metrics.
hgs
parents:
diff changeset
   398
    
hgs
parents:
diff changeset
   399
    Also the localization test mode (see: locTestMode) mush have been enabled
hgs
parents:
diff changeset
   400
    before any hbTrId calls. In practice it's best to enable it before launching the
hgs
parents:
diff changeset
   401
    application, or before creating the HbMainWindow, at latest.    
hgs
parents:
diff changeset
   402
*/
hgs
parents:
diff changeset
   403
hgs
parents:
diff changeset
   404
hgs
parents:
diff changeset
   405
/*!
hgs
parents:
diff changeset
   406
    \enum HbTextMeasurementUtility::LocTestMode
hgs
parents:
diff changeset
   407
    The LocTestMode enum identifies the possible localization test modes.
hgs
parents:
diff changeset
   408
*/
hgs
parents:
diff changeset
   409
/*!
hgs
parents:
diff changeset
   410
    \var HbTextMeasurementUtility::Disabled
hgs
parents:
diff changeset
   411
    Localization tests disabled.
hgs
parents:
diff changeset
   412
*/
hgs
parents:
diff changeset
   413
/*!
hgs
parents:
diff changeset
   414
    \var HbTextMeasurementUtility::Manual
hgs
parents:
diff changeset
   415
    Manual localization test mode. The client needs to call readReport, measureItems
hgs
parents:
diff changeset
   416
    and writeReport functions explicitly.
hgs
parents:
diff changeset
   417
*/
hgs
parents:
diff changeset
   418
/*!
hgs
parents:
diff changeset
   419
    \var HbTextMeasurementUtility::Automatic
hgs
parents:
diff changeset
   420
    Automatic localization test mode. The UI framework calls readReport, measureItems 
hgs
parents:
diff changeset
   421
    and writeReport automatically when needed.
hgs
parents:
diff changeset
   422
    
hgs
parents:
diff changeset
   423
    Notice that for performance reasons there's (at least) half a second timeout
hgs
parents:
diff changeset
   424
    between measureItems calls. You should wait a while before moving between views
hgs
parents:
diff changeset
   425
    in order to guarantee that the metrics will be harvested properly.
hgs
parents:
diff changeset
   426
*/
hgs
parents:
diff changeset
   427
hgs
parents:
diff changeset
   428
hgs
parents:
diff changeset
   429
/*!
hgs
parents:
diff changeset
   430
    Default constructor.
hgs
parents:
diff changeset
   431
*/
hgs
parents:
diff changeset
   432
HbTextMeasurementUtility::HbTextMeasurementUtility()
hgs
parents:
diff changeset
   433
{
hgs
parents:
diff changeset
   434
    d = new HbTextMeasurementUtilityPrivate;    
hgs
parents:
diff changeset
   435
#ifndef HB_TEXT_MEASUREMENT_UTILITY
hgs
parents:
diff changeset
   436
    d->mLocTestMode_cached = HbTextMeasurementUtility::Disabled;
hgs
parents:
diff changeset
   437
#else
hgs
parents:
diff changeset
   438
    d->mLocTestMode_cached = HbFeatureManager::instance()->featureStatus( HbFeatureManager::TextMeasurement );
hgs
parents:
diff changeset
   439
#endif
hgs
parents:
diff changeset
   440
}
hgs
parents:
diff changeset
   441
hgs
parents:
diff changeset
   442
/*!
hgs
parents:
diff changeset
   443
    Destructor.
hgs
parents:
diff changeset
   444
*/
hgs
parents:
diff changeset
   445
HbTextMeasurementUtility::~HbTextMeasurementUtility()
hgs
parents:
diff changeset
   446
{
hgs
parents:
diff changeset
   447
    qDeleteAll(d->records);
hgs
parents:
diff changeset
   448
    delete d;
hgs
parents:
diff changeset
   449
}
hgs
parents:
diff changeset
   450
hgs
parents:
diff changeset
   451
/*!
hgs
parents:
diff changeset
   452
    Returns singleton instance.
hgs
parents:
diff changeset
   453
*/
hgs
parents:
diff changeset
   454
HbTextMeasurementUtility *HbTextMeasurementUtility::instance()
hgs
parents:
diff changeset
   455
{
hgs
parents:
diff changeset
   456
    static HbTextMeasurementUtility theUtility;
hgs
parents:
diff changeset
   457
    return &theUtility;
hgs
parents:
diff changeset
   458
}
hgs
parents:
diff changeset
   459
hgs
parents:
diff changeset
   460
/*!
hgs
parents:
diff changeset
   461
    Sets the localization test mode to \a mode.
hgs
parents:
diff changeset
   462
*/
hgs
parents:
diff changeset
   463
void HbTextMeasurementUtility::setLocTestMode( int mode )
hgs
parents:
diff changeset
   464
{
hgs
parents:
diff changeset
   465
#ifndef HB_TEXT_MEASUREMENT_UTILITY
hgs
parents:
diff changeset
   466
    Q_UNUSED( mode );
hgs
parents:
diff changeset
   467
    return;
hgs
parents:
diff changeset
   468
#else
hgs
parents:
diff changeset
   469
    HbFeatureManager::instance()->setFeatureStatus( HbFeatureManager::TextMeasurement, mode );
hgs
parents:
diff changeset
   470
    d->mLocTestMode_cached = mode;
hgs
parents:
diff changeset
   471
#endif
hgs
parents:
diff changeset
   472
}
hgs
parents:
diff changeset
   473
hgs
parents:
diff changeset
   474
/*!
hgs
parents:
diff changeset
   475
    Returns the current localization test mode.
hgs
parents:
diff changeset
   476
*/
hgs
parents:
diff changeset
   477
int HbTextMeasurementUtility::locTestMode() const
hgs
parents:
diff changeset
   478
{
hgs
parents:
diff changeset
   479
    return d->mLocTestMode_cached;
hgs
parents:
diff changeset
   480
}
hgs
parents:
diff changeset
   481
hgs
parents:
diff changeset
   482
/*!
hgs
parents:
diff changeset
   483
    Measures all currently visible text items.
hgs
parents:
diff changeset
   484
    This method is asynchronous if time interval \a after (in milliseconds) is larger than zero,
hgs
parents:
diff changeset
   485
    and synchronous otherwise. This method will process any pending events in both cases, so 
hgs
parents:
diff changeset
   486
    the synchronous call should be sufficient in most of the cases.
hgs
parents:
diff changeset
   487
    
hgs
parents:
diff changeset
   488
    It's possible to give \a window parameter if the measurement is only made for text items
hgs
parents:
diff changeset
   489
    of specific HbMainWindow. The measurement is made for all text items in all HbMainWindows
hgs
parents:
diff changeset
   490
    if the parameter is omitted.
hgs
parents:
diff changeset
   491
*/
hgs
parents:
diff changeset
   492
void HbTextMeasurementUtility::measureItems(int after, HbMainWindow *window)
hgs
parents:
diff changeset
   493
{
hgs
parents:
diff changeset
   494
#ifndef HB_TEXT_MEASUREMENT_UTILITY
hgs
parents:
diff changeset
   495
    Q_UNUSED( after );
hgs
parents:
diff changeset
   496
    Q_UNUSED( window );
hgs
parents:
diff changeset
   497
    return;
hgs
parents:
diff changeset
   498
#else
hgs
parents:
diff changeset
   499
    // Store the window pointer, because it would not survive the singleShot timer call.
hgs
parents:
diff changeset
   500
    d->mWindow = window;
hgs
parents:
diff changeset
   501
hgs
parents:
diff changeset
   502
    if (after > 0) {
hgs
parents:
diff changeset
   503
        // Asynchronous
hgs
parents:
diff changeset
   504
        QTimer::singleShot(after, d, SLOT(doMeasureItems()));
hgs
parents:
diff changeset
   505
    } else {
hgs
parents:
diff changeset
   506
        // Synchronous
hgs
parents:
diff changeset
   507
        d->doMeasureItems();
hgs
parents:
diff changeset
   508
    }
hgs
parents:
diff changeset
   509
#endif
hgs
parents:
diff changeset
   510
}
hgs
parents:
diff changeset
   511
hgs
parents:
diff changeset
   512
/*!
hgs
parents:
diff changeset
   513
    Reads existing layout metric report file, see writeReport for the file locations.
hgs
parents:
diff changeset
   514
    
hgs
parents:
diff changeset
   515
    By using this method it is possible to update existing data instead of overwriting
hgs
parents:
diff changeset
   516
    data that is measurered earlier.
hgs
parents:
diff changeset
   517
hgs
parents:
diff changeset
   518
    This method should be called before first call of measureItems() and after reset().
hgs
parents:
diff changeset
   519
    If there are some metrics data in memory, the file is not read for optimization reasons.
hgs
parents:
diff changeset
   520
*/
hgs
parents:
diff changeset
   521
bool HbTextMeasurementUtility::readReport( HbDeviceProfile &profile, const QString &domainName )
hgs
parents:
diff changeset
   522
{
hgs
parents:
diff changeset
   523
#ifndef HB_TEXT_MEASUREMENT_UTILITY
hgs
parents:
diff changeset
   524
    Q_UNUSED( profile );
hgs
parents:
diff changeset
   525
    Q_UNUSED( domainName );
hgs
parents:
diff changeset
   526
    return false;
hgs
parents:
diff changeset
   527
#else
hgs
parents:
diff changeset
   528
    if (!d->records.isEmpty()) {
hgs
parents:
diff changeset
   529
        return false;
hgs
parents:
diff changeset
   530
    }
hgs
parents:
diff changeset
   531
    QString filePath = d->reportFilePath(profile, domainName);
hgs
parents:
diff changeset
   532
    QFile file;
hgs
parents:
diff changeset
   533
    file.setFileName(filePath);
hgs
parents:
diff changeset
   534
    if (!file.exists()) {
hgs
parents:
diff changeset
   535
        return false;
hgs
parents:
diff changeset
   536
    }
hgs
parents:
diff changeset
   537
    if (!file.open(QFile::ReadOnly | QFile::Text)) {
hgs
parents:
diff changeset
   538
#ifndef Q_OS_SYMBIAN
hgs
parents:
diff changeset
   539
        std::cerr << "Error: Cannot read file ";
hgs
parents:
diff changeset
   540
        std::cerr << qPrintable(filePath);
hgs
parents:
diff changeset
   541
        std::cerr << qPrintable(file.errorString()) << std::endl;
hgs
parents:
diff changeset
   542
#endif
hgs
parents:
diff changeset
   543
        return false;
hgs
parents:
diff changeset
   544
    }
hgs
parents:
diff changeset
   545
    QTextStream csvReader(&file);
hgs
parents:
diff changeset
   546
    d->readEntries(csvReader);
hgs
parents:
diff changeset
   547
    file.close();
hgs
parents:
diff changeset
   548
hgs
parents:
diff changeset
   549
    return true;
hgs
parents:
diff changeset
   550
#endif
hgs
parents:
diff changeset
   551
}
hgs
parents:
diff changeset
   552
hgs
parents:
diff changeset
   553
hgs
parents:
diff changeset
   554
/*!
hgs
parents:
diff changeset
   555
    Writes a layout metric report into a file. 
hgs
parents:
diff changeset
   556
    
hgs
parents:
diff changeset
   557
    The report contains metrics data for each text item at the time of last
hgs
parents:
diff changeset
   558
    call to the measureItems() method.
hgs
parents:
diff changeset
   559
        
hgs
parents:
diff changeset
   560
    Report is written to a csv (Comma Separated Values) file.
hgs
parents:
diff changeset
   561
    
hgs
parents:
diff changeset
   562
    On Symbian environment the report is written to memory directory
hgs
parents:
diff changeset
   563
    /data/log/qtestcase/loc/. Memory card is used if it exists (in F: drive).
hgs
parents:
diff changeset
   564
    Otherwise C: drive is used.
hgs
parents:
diff changeset
   565
    
hgs
parents:
diff changeset
   566
    On other environments the report is written to system temp path + "loc".
hgs
parents:
diff changeset
   567
    
hgs
parents:
diff changeset
   568
    A subdirectory will be created for each orientation and/or resolution, 
hgs
parents:
diff changeset
   569
    e.g. "NHD-3.2-inch_portrait".
hgs
parents:
diff changeset
   570
    
hgs
parents:
diff changeset
   571
    The CSV file name will be of format <domainName>_<device profile name>_<week number>.csv,
hgs
parents:
diff changeset
   572
    e.g. "myapp_NHD-3.2-inch_portrait_2010wk38.csv".
hgs
parents:
diff changeset
   573
*/
hgs
parents:
diff changeset
   574
bool HbTextMeasurementUtility::writeReport(HbDeviceProfile &profile, const QString &domainName)
hgs
parents:
diff changeset
   575
{
hgs
parents:
diff changeset
   576
#ifndef HB_TEXT_MEASUREMENT_UTILITY
hgs
parents:
diff changeset
   577
    Q_UNUSED( profile );
hgs
parents:
diff changeset
   578
    Q_UNUSED( domainName );
hgs
parents:
diff changeset
   579
    return false;
hgs
parents:
diff changeset
   580
#else
hgs
parents:
diff changeset
   581
    qDebug() << "HbTextMeasurementUtility::writeReport: Using profile" << profile.name();
hgs
parents:
diff changeset
   582
hgs
parents:
diff changeset
   583
    QString filePath = d->reportFilePath(profile, domainName);
hgs
parents:
diff changeset
   584
    QFile file(filePath);
hgs
parents:
diff changeset
   585
    if (!file.open(QFile::WriteOnly | QFile::Text)) {
hgs
parents:
diff changeset
   586
#ifndef Q_OS_SYMBIAN
hgs
parents:
diff changeset
   587
        std::cerr << "Error: Cannot write file ";
hgs
parents:
diff changeset
   588
        std::cerr << qPrintable(filePath);
hgs
parents:
diff changeset
   589
        std::cerr << qPrintable(file.errorString()) << std::endl;
hgs
parents:
diff changeset
   590
#endif
hgs
parents:
diff changeset
   591
        return false;
hgs
parents:
diff changeset
   592
    }
hgs
parents:
diff changeset
   593
    bool ret = writeReport(profile, &file);
hgs
parents:
diff changeset
   594
hgs
parents:
diff changeset
   595
    file.close();
hgs
parents:
diff changeset
   596
#ifndef Q_OS_SYMBIAN
hgs
parents:
diff changeset
   597
    if (file.error()) {
hgs
parents:
diff changeset
   598
        std::cerr << "Error: Cannot write file ";
hgs
parents:
diff changeset
   599
        std::cerr << qPrintable(filePath);
hgs
parents:
diff changeset
   600
        std::cerr << qPrintable(file.errorString()) << std::endl;
hgs
parents:
diff changeset
   601
    }
hgs
parents:
diff changeset
   602
#endif
hgs
parents:
diff changeset
   603
   return ret;
hgs
parents:
diff changeset
   604
#endif
hgs
parents:
diff changeset
   605
}
hgs
parents:
diff changeset
   606
hgs
parents:
diff changeset
   607
hgs
parents:
diff changeset
   608
/*!
hgs
parents:
diff changeset
   609
    Overloaded function provided for convenience. Here you can manually specify QIODevice where to write report.
hgs
parents:
diff changeset
   610
*/
hgs
parents:
diff changeset
   611
bool HbTextMeasurementUtility::writeReport(HbDeviceProfile &profile, QIODevice *device)
hgs
parents:
diff changeset
   612
{
hgs
parents:
diff changeset
   613
#ifndef HB_TEXT_MEASUREMENT_UTILITY
hgs
parents:
diff changeset
   614
    Q_UNUSED( device );
hgs
parents:
diff changeset
   615
    return false;
hgs
parents:
diff changeset
   616
#else
hgs
parents:
diff changeset
   617
hgs
parents:
diff changeset
   618
    if( device == 0 ) {
hgs
parents:
diff changeset
   619
        return false;
hgs
parents:
diff changeset
   620
    }
hgs
parents:
diff changeset
   621
hgs
parents:
diff changeset
   622
    bool succeed = d->validateRecords(profile);
hgs
parents:
diff changeset
   623
    if (succeed) {
hgs
parents:
diff changeset
   624
        qDebug() << "HbTextMeasurementUtility::writeReport: Measurements OK";
hgs
parents:
diff changeset
   625
    } else {
hgs
parents:
diff changeset
   626
        qDebug() << "HbTextMeasurementUtility::writeReport: Measurements NOT OK";
hgs
parents:
diff changeset
   627
    }
hgs
parents:
diff changeset
   628
hgs
parents:
diff changeset
   629
    QTextStream csvWriter(device);
hgs
parents:
diff changeset
   630
    d->writeHeaders(csvWriter);
hgs
parents:
diff changeset
   631
    foreach (const HbTextRecord *record, d->records) {
hgs
parents:
diff changeset
   632
        d->writeEntry(csvWriter, record);
hgs
parents:
diff changeset
   633
    }
hgs
parents:
diff changeset
   634
    return succeed;
hgs
parents:
diff changeset
   635
#endif
hgs
parents:
diff changeset
   636
}
hgs
parents:
diff changeset
   637
hgs
parents:
diff changeset
   638
/*!
hgs
parents:
diff changeset
   639
    Reset layout metrics data from memory.
hgs
parents:
diff changeset
   640
*/
hgs
parents:
diff changeset
   641
void HbTextMeasurementUtility::reset()
hgs
parents:
diff changeset
   642
{
hgs
parents:
diff changeset
   643
    d->records.clear();
hgs
parents:
diff changeset
   644
}
hgs
parents:
diff changeset
   645
hgs
parents:
diff changeset
   646
hgs
parents:
diff changeset
   647
hgs
parents:
diff changeset
   648