File indexing completed on 2024-04-21 04:41:51
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 (C) 2012 Friedrich W. H. Kossebau <kossebau@kde.org> 0005 Copyright (C) 2017 Jarosław Staniek <staniek@kde.org> 0006 0007 This library is free software; you can redistribute it and/or 0008 modify it under the terms of the GNU Library General Public 0009 License as published by the Free Software Foundation; either 0010 version 2 of the License, or (at your option) any later version. 0011 0012 This library is distributed in the hope that it will be useful, 0013 but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 Library General Public License for more details. 0016 0017 You should have received a copy of the GNU Library General Public License 0018 along with this library; see the file COPYING.LIB. If not, write to 0019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0020 * Boston, MA 02110-1301, USA. 0021 */ 0022 0023 #include "KReportUnit.h" 0024 #include "kreport_debug.h" 0025 0026 #include <cmath> 0027 0028 #include <QTransform> 0029 #include <QCoreApplication> 0030 0031 class Q_DECL_HIDDEN KReportUnit::Private 0032 { 0033 public: 0034 KReportUnit::Type type; 0035 qreal pixelConversion; 0036 }; 0037 0038 // unit types 0039 // Note: ensure the same order as in KReportUnit::Unit 0040 static QList<KReportUnit::Type> s_unitTypes = { 0041 KReportUnit::Type::Millimeter, 0042 KReportUnit::Type::Centimeter, 0043 KReportUnit::Type::Decimeter, 0044 KReportUnit::Type::Inch, 0045 KReportUnit::Type::Pica, 0046 KReportUnit::Type::Cicero, 0047 KReportUnit::Type::Point, 0048 KReportUnit::Type::Pixel 0049 }; 0050 static int firstUnitIndex() 0051 { 0052 return static_cast<int>(KReportUnit::Type::Invalid) + 1; 0053 } 0054 0055 static int lastUnitIndex() 0056 { 0057 return static_cast<int>(KReportUnit::Type::Last); // without Invalid 0058 } 0059 0060 // unit symbols 0061 // Note: ensure the same order as in KReportUnit::Unit 0062 static const char* const s_unitSymbols[] = 0063 { 0064 nullptr, 0065 "mm", 0066 "cm", 0067 "dm", 0068 "in", 0069 "pi", 0070 "cc", 0071 "pt", 0072 "px" 0073 }; 0074 0075 KReportUnit::KReportUnit() : d(new Private) 0076 { 0077 d->type = Type::Invalid; 0078 d->pixelConversion = 1.0; 0079 } 0080 0081 KReportUnit::KReportUnit(Type type, qreal factor) : d(new Private) 0082 { 0083 d->type = type; 0084 d->pixelConversion = factor; 0085 } 0086 0087 KReportUnit::KReportUnit(const KReportUnit& other) : d(new Private) 0088 { 0089 d->type = other.type(); 0090 d->pixelConversion = other.factor(); 0091 } 0092 0093 KReportUnit::~KReportUnit() 0094 { 0095 delete d; 0096 } 0097 0098 bool KReportUnit::operator==(const KReportUnit& other) const 0099 { 0100 return d->type == other.d->type && 0101 (d->type != Type::Pixel || 0102 qFuzzyCompare(d->pixelConversion, other.d->pixelConversion)); 0103 } 0104 0105 bool KReportUnit::operator!=(const KReportUnit& other) const 0106 { 0107 return !operator==(other); 0108 } 0109 0110 0111 KReportUnit& KReportUnit::operator=(Type type) 0112 { 0113 d->type = type; 0114 d->pixelConversion = 1.0; 0115 return *this; 0116 } 0117 0118 KReportUnit & KReportUnit::operator=(const KReportUnit& other) 0119 { 0120 d->type = other.type(); 0121 d->pixelConversion = other.factor(); 0122 return *this; 0123 } 0124 0125 //static 0126 QList<KReportUnit::Type> KReportUnit::allTypes() 0127 { 0128 return s_unitTypes; 0129 } 0130 0131 //static 0132 QString KReportUnit::description(KReportUnit::Type type) 0133 { 0134 switch (type) { 0135 case KReportUnit::Type::Invalid: 0136 return tr("Invalid"); 0137 case KReportUnit::Type::Millimeter: 0138 return tr("Millimeters (mm)"); 0139 case KReportUnit::Type::Centimeter: 0140 return tr("Centimeters (cm)"); 0141 case KReportUnit::Type::Decimeter: 0142 return tr("Decimeters (dm)"); 0143 case KReportUnit::Type::Inch: 0144 return tr("Inches (in)"); 0145 case KReportUnit::Type::Pica: 0146 return tr("Pica (pi)"); 0147 case KReportUnit::Type::Cicero: 0148 return tr("Cicero (cc)"); 0149 case KReportUnit::Type::Point: 0150 return tr("Points (pt)"); 0151 case KReportUnit::Type::Pixel: 0152 return tr("Pixels (px)"); 0153 default: 0154 return tr("Unsupported unit"); 0155 } 0156 } 0157 0158 QString KReportUnit::description() const 0159 { 0160 return KReportUnit::description(type()); 0161 } 0162 0163 QStringList KReportUnit::descriptions(const QList<Type> &types) 0164 { 0165 QStringList result; 0166 for (Type t : types) { 0167 result.append(description(t)); 0168 } 0169 return result; 0170 } 0171 0172 qreal KReportUnit::toUserValue(qreal ptValue) const 0173 { 0174 switch (d->type) { 0175 case Type::Invalid: 0176 kreportWarning() << "Conversion for Invalid type not supported"; 0177 return -1.0; 0178 case Type::Millimeter: 0179 return toMillimeter(ptValue); 0180 case Type::Centimeter: 0181 return toCentimeter(ptValue); 0182 case Type::Decimeter: 0183 return toDecimeter(ptValue); 0184 case Type::Inch: 0185 return toInch(ptValue); 0186 case Type::Pica: 0187 return toPica(ptValue); 0188 case Type::Cicero: 0189 return toCicero(ptValue); 0190 case Type::Pixel: 0191 return ptValue * d->pixelConversion; 0192 case Type::Point: 0193 default: 0194 return toPoint(ptValue); 0195 } 0196 } 0197 0198 qreal KReportUnit::ptToUnit(qreal ptValue, const KReportUnit &unit) 0199 { 0200 switch (unit.d->type) { 0201 case Type::Invalid: 0202 return -1.0; 0203 case Type::Millimeter: 0204 return POINT_TO_MM(ptValue); 0205 case Type::Centimeter: 0206 return POINT_TO_CM(ptValue); 0207 case Type::Decimeter: 0208 return POINT_TO_DM(ptValue); 0209 case Type::Inch: 0210 return POINT_TO_INCH(ptValue); 0211 case Type::Pica: 0212 return POINT_TO_PI(ptValue); 0213 case Type::Cicero: 0214 return POINT_TO_CC(ptValue); 0215 case Type::Pixel: 0216 return ptValue * unit.d->pixelConversion; 0217 case Type::Point: 0218 default: 0219 return ptValue; 0220 } 0221 } 0222 0223 QString KReportUnit::toUserStringValue(qreal ptValue) const 0224 { 0225 return QLocale::system().toString(toUserValue(ptValue)); 0226 } 0227 0228 qreal KReportUnit::convertFromPoint(qreal ptValue) const 0229 { 0230 switch (d->type) { 0231 case Type::Millimeter: 0232 return POINT_TO_MM(ptValue); 0233 case Type::Centimeter: 0234 return POINT_TO_CM(ptValue); 0235 case Type::Decimeter: 0236 return POINT_TO_DM(ptValue); 0237 case Type::Inch: 0238 return POINT_TO_INCH(ptValue); 0239 case Type::Pica: 0240 return POINT_TO_PI(ptValue); 0241 case Type::Cicero: 0242 return POINT_TO_CC(ptValue); 0243 case Type::Pixel: 0244 return ptValue * d->pixelConversion; 0245 case Type::Point: 0246 default: 0247 return ptValue; 0248 } 0249 } 0250 0251 QPointF KReportUnit::convertFromPoint(const QPointF &ptValue) const 0252 { 0253 return QPointF(convertFromPoint(ptValue.x()), convertFromPoint(ptValue.y())); 0254 } 0255 0256 QSizeF KReportUnit::convertFromPoint(const QSizeF &ptValue) const 0257 { 0258 return QSizeF(convertFromPoint(ptValue.width()), convertFromPoint(ptValue.height())); 0259 } 0260 0261 qreal KReportUnit::convertToPoint(qreal value) const 0262 { 0263 switch (d->type) { 0264 case Type::Invalid: 0265 return -1.0; 0266 case Type::Millimeter: 0267 return MM_TO_POINT(value); 0268 case Type::Centimeter: 0269 return CM_TO_POINT(value); 0270 case Type::Decimeter: 0271 return DM_TO_POINT(value); 0272 case Type::Inch: 0273 return INCH_TO_POINT(value); 0274 case Type::Pica: 0275 return PI_TO_POINT(value); 0276 case Type::Cicero: 0277 return CC_TO_POINT(value); 0278 case Type::Pixel: 0279 return value / d->pixelConversion; 0280 case Type::Point: 0281 default: 0282 return value; 0283 } 0284 } 0285 0286 qreal KReportUnit::convertToPoint(const QString &value, bool *ok) const 0287 { 0288 return convertToPoint(QLocale::system().toDouble(value, ok)); 0289 } 0290 0291 QPointF KReportUnit::convertToPoint(const QPointF &value) const 0292 { 0293 return QPointF(KReportUnit::convertToPoint(value.x()), 0294 KReportUnit::convertToPoint(value.y())); 0295 } 0296 0297 QSizeF KReportUnit::convertToPoint(const QSizeF &value) const 0298 { 0299 return QSizeF(KReportUnit::convertToPoint(value.width()), 0300 KReportUnit::convertToPoint(value.height())); 0301 } 0302 0303 qreal KReportUnit::parseValue(const QString& _value, qreal defaultVal) 0304 { 0305 if (_value.isEmpty()) 0306 return defaultVal; 0307 0308 QString value(_value.simplified()); 0309 value.remove(QLatin1Char(' ')); 0310 0311 int firstLetter = -1; 0312 for (int i = 0; i < value.length(); ++i) { 0313 if (value.at(i).isLetter()) { 0314 if (value.at(i) == QLatin1Char('e')) 0315 continue; 0316 firstLetter = i; 0317 break; 0318 } 0319 } 0320 0321 bool ok; 0322 if (firstLetter == -1) { 0323 qreal result = QVariant(value).toReal(&ok); 0324 return ok ? result : defaultVal; 0325 } 0326 0327 const QByteArray symbol = value.mid(firstLetter).toLatin1(); 0328 value.truncate(firstLetter); 0329 const qreal val = value.toDouble(); 0330 0331 if (symbol == "pt" || symbol.isEmpty()) 0332 return val; 0333 0334 KReportUnit u(KReportUnit::symbolToType(QLatin1String(symbol))); 0335 if (u.isValid()) { 0336 return u.fromUserValue(val); 0337 } 0338 0339 if (symbol == "m") 0340 return DM_TO_POINT(val * 10.0); 0341 else if (symbol == "km") 0342 return DM_TO_POINT(val * 10000.0); 0343 kreportWarning() << "KReportUnit::parseValue: Unit" << symbol << "is not supported, please report."; 0344 0345 //! @todo add support for mi/ft ? 0346 return defaultVal; 0347 } 0348 0349 //static 0350 QString KReportUnit::symbol(KReportUnit::Type type) 0351 { 0352 return QLatin1String(s_unitSymbols[static_cast<int>(type)]); 0353 } 0354 0355 //static 0356 KReportUnit::Type KReportUnit::symbolToType(const QString &symbol) 0357 { 0358 Type result = Type::Invalid; 0359 0360 if (symbol == QLatin1String("inch") /*compat*/) { 0361 result = Type::Inch; 0362 } else { 0363 for (int i = firstUnitIndex(); i <= lastUnitIndex(); ++i) { 0364 if (symbol == QLatin1String(s_unitSymbols[i])) { 0365 result = static_cast<Type>(i); 0366 break; 0367 } 0368 } 0369 } 0370 return result; 0371 } 0372 0373 //static 0374 QStringList KReportUnit::symbols(const QList<Type> &types) 0375 { 0376 QStringList result; 0377 for (Type t : types) { 0378 result.append(symbol(t)); 0379 } 0380 return result; 0381 } 0382 0383 qreal KReportUnit::convertFromUnitToUnit(qreal value, const KReportUnit &fromUnit, const KReportUnit &toUnit, qreal factor) 0384 { 0385 qreal pt; 0386 switch (fromUnit.type()) { 0387 case Type::Invalid: 0388 pt = -1.0; 0389 break; 0390 case Type::Millimeter: 0391 pt = MM_TO_POINT(value); 0392 break; 0393 case Type::Centimeter: 0394 pt = CM_TO_POINT(value); 0395 break; 0396 case Type::Decimeter: 0397 pt = DM_TO_POINT(value); 0398 break; 0399 case Type::Inch: 0400 pt = INCH_TO_POINT(value); 0401 break; 0402 case Type::Pica: 0403 pt = PI_TO_POINT(value); 0404 break; 0405 case Type::Cicero: 0406 pt = CC_TO_POINT(value); 0407 break; 0408 case Type::Pixel: 0409 pt = value / factor; 0410 break; 0411 case Type::Point: 0412 default: 0413 pt = value; 0414 } 0415 0416 switch (toUnit.type()) { 0417 case Type::Millimeter: 0418 return POINT_TO_MM(pt); 0419 case Type::Centimeter: 0420 return POINT_TO_CM(pt); 0421 case Type::Decimeter: 0422 return POINT_TO_DM(pt); 0423 case Type::Inch: 0424 return POINT_TO_INCH(pt); 0425 case Type::Pica: 0426 return POINT_TO_PI(pt); 0427 case Type::Cicero: 0428 return POINT_TO_CC(pt); 0429 case Type::Pixel: 0430 return pt * factor; 0431 case Type::Invalid: 0432 default: 0433 return pt; 0434 } 0435 } 0436 0437 QPointF KReportUnit::convertFromUnitToUnit(const QPointF &value, 0438 const KReportUnit &fromUnit, 0439 const KReportUnit &toUnit) 0440 { 0441 return QPointF( 0442 KReportUnit::convertFromUnitToUnit(value.x(), fromUnit, toUnit), 0443 KReportUnit::convertFromUnitToUnit(value.y(), fromUnit, toUnit)); 0444 } 0445 0446 QSizeF KReportUnit::convertFromUnitToUnit(const QSizeF &value, 0447 const KReportUnit &fromUnit, 0448 const KReportUnit &toUnit) 0449 { 0450 return QSizeF( 0451 KReportUnit::convertFromUnitToUnit(value.width(), fromUnit, toUnit), 0452 KReportUnit::convertFromUnitToUnit(value.height(), fromUnit, toUnit)); 0453 } 0454 0455 QString KReportUnit::symbol() const 0456 { 0457 return QLatin1String(s_unitSymbols[static_cast<int>(d->type)]); 0458 } 0459 0460 qreal KReportUnit::parseAngle(const QString& _value, qreal defaultVal) 0461 { 0462 if (_value.isEmpty()) 0463 return defaultVal; 0464 0465 QString value(_value.simplified()); 0466 value.remove(QLatin1Char(' ')); 0467 0468 int firstLetter = -1; 0469 for (int i = 0; i < value.length(); ++i) { 0470 if (value.at(i).isLetter()) { 0471 if (value.at(i) == QLatin1Char('e')) 0472 continue; 0473 firstLetter = i; 0474 break; 0475 } 0476 } 0477 0478 if (firstLetter == -1) 0479 return value.toDouble(); 0480 0481 const QString type = value.mid(firstLetter); 0482 value.truncate(firstLetter); 0483 const qreal val = value.toDouble(); 0484 0485 if (type == QLatin1String("deg")) 0486 return val; 0487 else if (type == QLatin1String("rad")) 0488 return val * 180 / M_PI; 0489 else if (type == QLatin1String("grad")) 0490 return val * 0.9; 0491 0492 return defaultVal; 0493 } 0494 0495 #ifndef QT_NO_DEBUG_STREAM 0496 QDebug operator<<(QDebug debug, const KReportUnit &unit) 0497 { 0498 #ifndef NDEBUG 0499 if (unit.isValid()) { 0500 debug.nospace() << QString::fromLatin1("Unit(%1, %2)").arg(unit.symbol()).arg(unit.factor()); 0501 } else { 0502 debug.nospace() << QString::fromLatin1("Unit(Invalid)"); 0503 } 0504 #else 0505 Q_UNUSED(unit); 0506 #endif 0507 return debug.space(); 0508 } 0509 0510 void KReportUnit::setFactor(qreal factor) 0511 { 0512 d->pixelConversion = factor; 0513 } 0514 0515 qreal KReportUnit::factor() const 0516 { 0517 return d->pixelConversion; 0518 } 0519 0520 KReportUnit::Type KReportUnit::type() const 0521 { 0522 return d->type; 0523 } 0524 0525 bool KReportUnit::isValid() const 0526 { 0527 return d->type != KReportUnit::Type::Invalid; 0528 } 0529 0530 #endif