Warning, file /office/calligra/libs/odf/KoUnit.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* This file is part of the KDE project
0002    Copyright (C) 2001 David Faure <faure@kde.org>
0003    Copyright (C) 2004, Nicolas GOUTTE <goutte@kde.org>
0004    Copyright 2012 Friedrich W. H. Kossebau <kossebau@kde.org>
0005 
0006    This library is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU Library General Public
0008    License as published by the Free Software Foundation; either
0009    version 2 of the License, or (at your option) any later version.
0010 
0011    This library is distributed in the hope that it will be useful,
0012    but WITHOUT ANY WARRANTY; without even the implied warranty of
0013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014    Library General Public License for more details.
0015 
0016    You should have received a copy of the GNU Library General Public License
0017    along with this library; see the file COPYING.LIB.  If not, write to
0018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020 */
0021 
0022 #include "KoUnit.h"
0023 
0024 #include <cmath>
0025 
0026 #include <QTransform>
0027 
0028 #include <klocalizedstring.h>
0029 #include <OdfDebug.h>
0030 #include <QtGlobal>
0031 
0032 
0033 // ensure the same order as in KoUnit::Unit
0034 static const char* const unitNameList[KoUnit::TypeCount] =
0035 {
0036     "mm",
0037     "pt",
0038     "in",
0039     "cm",
0040     "dm",
0041     "pi",
0042     "cc",
0043     "px"
0044 };
0045 
0046 QString KoUnit::unitDescription(KoUnit::Type type)
0047 {
0048     switch (type) {
0049     case KoUnit::Millimeter:
0050         return i18n("Millimeters (mm)");
0051     case KoUnit::Centimeter:
0052         return i18n("Centimeters (cm)");
0053     case KoUnit::Decimeter:
0054         return i18n("Decimeters (dm)");
0055     case KoUnit::Inch:
0056         return i18n("Inches (in)");
0057     case KoUnit::Pica:
0058         return i18n("Pica (pi)");
0059     case KoUnit::Cicero:
0060         return i18n("Cicero (cc)");
0061     case KoUnit::Point:
0062         return i18n("Points (pt)");
0063     case KoUnit::Pixel:
0064         return i18n("Pixels (px)");
0065     default:
0066         return i18n("Unsupported unit");
0067     }
0068 }
0069 
0070 // grouped by units which are similar
0071 static const KoUnit::Type typesInUi[KoUnit::TypeCount] =
0072 {
0073     KoUnit::Millimeter,
0074     KoUnit::Centimeter,
0075     KoUnit::Decimeter,
0076     KoUnit::Inch,
0077     KoUnit::Pica,
0078     KoUnit::Cicero,
0079     KoUnit::Point,
0080     KoUnit::Pixel,
0081 };
0082 
0083 QStringList KoUnit::listOfUnitNameForUi(ListOptions listOptions)
0084 {
0085     QStringList lst;
0086     for (int i = 0; i < KoUnit::TypeCount; ++i) {
0087         const Type type = typesInUi[i];
0088         if ((type != Pixel) || ((listOptions & HideMask) == ListAll))
0089             lst.append(unitDescription(type));
0090     }
0091     return lst;
0092 }
0093 
0094 KoUnit KoUnit::fromListForUi(int index, ListOptions listOptions, qreal factor)
0095 {
0096     KoUnit::Type type = KoUnit::Point;
0097 
0098     if ((0 <= index) && (index < KoUnit::TypeCount)) {
0099         // iterate through all enums and skip the Pixel enum if needed
0100         for (int i = 0; i < KoUnit::TypeCount; ++i) {
0101             if ((listOptions&HidePixel) && (typesInUi[i] == Pixel)) {
0102                 ++index;
0103                 continue;
0104             }
0105             if (i == index) {
0106                 type = typesInUi[i];
0107                 break;
0108             }
0109         }
0110     }
0111 
0112     return KoUnit(type, factor);
0113 }
0114 
0115 int KoUnit::indexInListForUi(ListOptions listOptions) const
0116 {
0117     if ((listOptions&HidePixel) && (m_type == Pixel)) {
0118         return -1;
0119     }
0120 
0121     int result = -1;
0122 
0123     int skipped = 0;
0124     for (int i = 0; i < KoUnit::TypeCount; ++i) {
0125         if ((listOptions&HidePixel) && (typesInUi[i] == Pixel)) {
0126             ++skipped;
0127             continue;
0128         }
0129         if (typesInUi[i] == m_type) {
0130             result = i - skipped;
0131             break;
0132         }
0133     }
0134 
0135     return result;
0136 }
0137 
0138 qreal KoUnit::toUserValue(qreal ptValue) const
0139 {
0140     switch (m_type) {
0141     case Millimeter:
0142         return toMillimeter(ptValue);
0143     case Centimeter:
0144         return toCentimeter(ptValue);
0145     case Decimeter:
0146         return toDecimeter(ptValue);
0147     case Inch:
0148         return toInch(ptValue);
0149     case Pica:
0150         return toPica(ptValue);
0151     case Cicero:
0152         return toCicero(ptValue);
0153     case Pixel:
0154         return ptValue * m_pixelConversion;
0155     case Point:
0156     default:
0157         return toPoint(ptValue);
0158     }
0159 }
0160 
0161 qreal KoUnit::ptToUnit(const qreal ptValue, const KoUnit &unit)
0162 {
0163     switch (unit.m_type) {
0164     case Millimeter:
0165         return POINT_TO_MM(ptValue);
0166     case Centimeter:
0167         return POINT_TO_CM(ptValue);
0168     case Decimeter:
0169         return POINT_TO_DM(ptValue);
0170     case Inch:
0171         return POINT_TO_INCH(ptValue);
0172     case Pica:
0173         return POINT_TO_PI(ptValue);
0174     case Cicero:
0175         return POINT_TO_CC(ptValue);
0176     case Pixel:
0177         return ptValue * unit.m_pixelConversion;
0178     case Point:
0179     default:
0180         return ptValue;
0181     }
0182 }
0183 
0184 QString KoUnit::toUserStringValue(qreal ptValue) const
0185 {
0186     return QLocale().toString(toUserValue(ptValue));
0187 }
0188 
0189 qreal KoUnit::fromUserValue(qreal value) const
0190 {
0191     switch (m_type) {
0192     case Millimeter:
0193         return MM_TO_POINT(value);
0194     case Centimeter:
0195         return CM_TO_POINT(value);
0196     case Decimeter:
0197         return DM_TO_POINT(value);
0198     case Inch:
0199         return INCH_TO_POINT(value);
0200     case Pica:
0201         return PI_TO_POINT(value);
0202     case Cicero:
0203         return CC_TO_POINT(value);
0204     case Pixel:
0205         return value / m_pixelConversion;
0206     case Point:
0207     default:
0208         return value;
0209     }
0210 }
0211 
0212 qreal KoUnit::fromUserValue(const QString &value, bool *ok) const
0213 {
0214     return fromUserValue(QLocale().toDouble(value, ok));
0215 }
0216 
0217 qreal KoUnit::parseValue(const QString& _value, qreal defaultVal)
0218 {
0219     if (_value.isEmpty())
0220         return defaultVal;
0221 
0222     QString value(_value.simplified());
0223     value.remove(QLatin1Char(' '));
0224 
0225     int firstLetter = -1;
0226     for (int i = 0; i < value.length(); ++i) {
0227         if (value.at(i).isLetter()) {
0228             if (value.at(i) == QLatin1Char('e'))
0229                 continue;
0230             firstLetter = i;
0231             break;
0232         }
0233     }
0234 
0235     if (firstLetter == -1)
0236         return value.toDouble();
0237 
0238     const QString symbol = value.mid(firstLetter);
0239     value.truncate(firstLetter);
0240     const qreal val = value.toDouble();
0241 
0242     if (symbol == QLatin1String("pt"))
0243         return val;
0244 
0245     bool ok;
0246     KoUnit u = KoUnit::fromSymbol(symbol, &ok);
0247     if (ok)
0248         return u.fromUserValue(val);
0249 
0250     if (symbol == QLatin1String("m"))
0251         return DM_TO_POINT(val * 10.0);
0252     else if (symbol == QLatin1String("km"))
0253         return DM_TO_POINT(val * 10000.0);
0254     warnOdf << "KoUnit::parseValue: Unit " << symbol << " is not supported, please report.";
0255 
0256     // TODO : add support for mi/ft ?
0257     return defaultVal;
0258 }
0259 
0260 KoUnit KoUnit::fromSymbol(const QString &symbol, bool *ok)
0261 {
0262     Type result = Point;
0263 
0264     if (symbol == QLatin1String("inch") /*compat*/) {
0265         result = Inch;
0266         if (ok)
0267             *ok = true;
0268     } else {
0269         if (ok)
0270             *ok = false;
0271 
0272         for (int i = 0; i < TypeCount; ++i) {
0273             if (symbol == QLatin1String(unitNameList[i])) {
0274                 result = static_cast<Type>(i);
0275                 if (ok)
0276                     *ok = true;
0277             }
0278         }
0279     }
0280 
0281     return KoUnit(result);
0282 }
0283 
0284 qreal KoUnit::convertFromUnitToUnit(const qreal value, const KoUnit &fromUnit, const KoUnit &toUnit, qreal factor)
0285 {
0286     qreal pt;
0287     switch (fromUnit.type()) {
0288     case Millimeter:
0289         pt = MM_TO_POINT(value);
0290         break;
0291     case Centimeter:
0292         pt = CM_TO_POINT(value);
0293         break;
0294     case Decimeter:
0295         pt = DM_TO_POINT(value);
0296         break;
0297     case Inch:
0298         pt = INCH_TO_POINT(value);
0299         break;
0300     case Pica:
0301         pt = PI_TO_POINT(value);
0302         break;
0303     case Cicero:
0304         pt = CC_TO_POINT(value);
0305         break;
0306     case Pixel:
0307         pt = value / factor;
0308         break;
0309     case Point:
0310     default:
0311         pt = value;
0312     }
0313 
0314     switch (toUnit.type()) {
0315     case Millimeter:
0316         return POINT_TO_MM(pt);
0317     case Centimeter:
0318         return POINT_TO_CM(pt);
0319     case Decimeter:
0320         return POINT_TO_DM(pt);
0321     case Inch:
0322         return POINT_TO_INCH(pt);
0323     case Pica:
0324         return POINT_TO_PI(pt);
0325     case Cicero:
0326         return POINT_TO_CC(pt);
0327     case Pixel:
0328         return pt * factor;
0329     case Point:
0330     default:
0331         return pt;
0332     }
0333 
0334 }
0335 
0336 QString KoUnit::symbol() const
0337 {
0338     return QLatin1String(unitNameList[m_type]);
0339 }
0340 
0341 qreal KoUnit::parseAngle(const QString& _value, qreal defaultVal)
0342 {
0343     if (_value.isEmpty())
0344         return defaultVal;
0345 
0346     QString value(_value.simplified());
0347     value.remove(QLatin1Char(' '));
0348 
0349     int firstLetter = -1;
0350     for (int i = 0; i < value.length(); ++i) {
0351         if (value.at(i).isLetter()) {
0352             if (value.at(i) == QLatin1Char('e'))
0353                 continue;
0354             firstLetter = i;
0355             break;
0356         }
0357     }
0358 
0359     if (firstLetter == -1)
0360         return value.toDouble();
0361 
0362     const QString type = value.mid(firstLetter);
0363     value.truncate(firstLetter);
0364     const qreal val = value.toDouble();
0365 
0366     if (type == QLatin1String("deg"))
0367         return val;
0368     else if (type == QLatin1String("rad"))
0369         return val * 180 / M_PI;
0370     else if (type == QLatin1String("grad"))
0371         return val * 0.9;
0372 
0373     return defaultVal;
0374 }
0375 
0376 qreal KoUnit::approxTransformScale(const QTransform &t)
0377 {
0378     return std::sqrt(qAbs(t.determinant()));
0379 }
0380 
0381 void KoUnit::adjustByPixelTransform(const QTransform &t)
0382 {
0383     m_pixelConversion *= approxTransformScale(t);
0384 }
0385 
0386 #ifndef QT_NO_DEBUG_STREAM
0387 QDebug operator<<(QDebug debug, const KoUnit &unit)
0388 {
0389 #ifndef NDEBUG
0390     debug.nospace() << unit.symbol();
0391 #else
0392     Q_UNUSED(unit);
0393 #endif
0394     return debug.space();
0395 
0396 }
0397 #endif