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