File indexing completed on 2024-05-12 16:35:02

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
0003  * Copyright (C) 2008,2010 Thorsten Zachmann <zachmann@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 "DateVariable.h"
0023 #include "FixedDateFormat.h"
0024 
0025 #include <KoProperties.h>
0026 #include <KoXmlReader.h>
0027 #include <KoXmlWriter.h>
0028 #include <KoXmlNS.h>
0029 #include <KoShapeLoadingContext.h>
0030 #include <KoShapeSavingContext.h>
0031 #include <KoOdfLoadingContext.h>
0032 #include <KoOdfStylesReader.h>
0033 #include <KoOdfWorkaround.h>
0034 
0035 DateVariable::DateVariable(DateType type)
0036         : KoVariable()
0037         , m_type(type)
0038         , m_displayType(Date)
0039         , m_valueType(DateTime)
0040         , m_daysOffset(0)
0041         , m_monthsOffset(0)
0042         , m_yearsOffset(0)
0043         , m_secsOffset(0)
0044 {
0045     m_datetime = QDateTime::currentDateTime();
0046 }
0047 
0048 DateVariable::~DateVariable()
0049 {
0050 }
0051 
0052 void DateVariable::saveOdf(KoShapeSavingContext & context)
0053 {
0054     // TODO support data-style-name
0055     KoXmlWriter *writer = &context.xmlWriter();
0056     if (m_displayType == Time) {
0057         writer->startElement("text:time", false);
0058     } else {
0059         writer->startElement("text:date", false);
0060     }
0061 
0062     if (!m_definition.isEmpty()) {
0063         QString styleName = KoOdfNumberStyles::saveOdfDateStyle(context.mainStyles(), m_definition, false);
0064         writer->addAttribute("style:data-style-name", styleName);
0065     }
0066 
0067     if (m_type == Fixed) {
0068         writer->addAttribute("text:fixed", "true");
0069         // only write as much information as we read: just date/time or datetime
0070         if (m_displayType == Time) {
0071             const QString timeValue = (m_valueType == DateTime) ?
0072                 m_datetime.toString(Qt::ISODate) :
0073                 m_datetime.time().toString(Qt::ISODate);
0074             writer->addAttribute("text:time-value", timeValue);
0075         } else {
0076             const QString dateValue = (m_valueType == DateTime) ?
0077                 m_datetime.toString(Qt::ISODate) :
0078                 m_datetime.date().toString(Qt::ISODate);
0079             writer->addAttribute("text:date-value", dateValue);
0080         }
0081     } else {
0082         writer->addAttribute("text:fixed", "false");
0083     }
0084     writer->addTextNode(value());
0085     writer->endElement();
0086 }
0087 
0088 bool DateVariable::loadOdf(const KoXmlElement & element, KoShapeLoadingContext & context)
0089 {
0090     const QString localName(element.localName());
0091     QString dateFormat;
0092     QString dataStyle = element.attributeNS(KoXmlNS::style, "data-style-name");
0093     if (!dataStyle.isEmpty()) {
0094         if (context.odfLoadingContext().stylesReader().dataFormats().contains(dataStyle)) {
0095             KoOdfNumberStyles::NumericStyleFormat dataFormat = context.odfLoadingContext().stylesReader().dataFormats().value(dataStyle).first;
0096             dateFormat = dataFormat.prefix + dataFormat.formatStr + dataFormat.suffix;
0097         }
0098     }
0099 
0100     //dateProperties.setProperty("fixed", QVariant(element.attributeNS(KoXmlNS::text, "fixed") == "true"));
0101     if (element.attributeNS(KoXmlNS::text, "fixed", "false") == "true") {
0102         m_type = Fixed;
0103     } else {
0104         m_type = AutoUpdate;
0105     }
0106 
0107     if (localName == "time") {
0108         m_displayType = Time;
0109     } else {
0110         m_displayType = Date;
0111     }
0112 
0113     //dateProperties.setProperty("time", element.attributeNS(KoXmlNS::text, localName + "-value"));
0114     QString value(element.attributeNS(KoXmlNS::text, localName + "-value", ""));
0115     if (!value.isEmpty()) {
0116 #ifndef NWORKAROUND_ODF_BUGS
0117         KoOdfWorkaround::fixBadDateForTextTime(value);
0118 #endif
0119         // hopefully this simple detection works in all cases
0120         const bool isDateTime = (value.indexOf(QLatin1Char('T')) != -1);
0121 
0122         if (isDateTime) {
0123             m_datetime = QDateTime::fromString(value, Qt::ISODate);
0124             m_valueType = DateTime;
0125         } else {
0126             if (m_displayType == Time) {
0127                 const QTime time = QTime::fromString(value, Qt::ISODate);
0128                 m_datetime = QDateTime(QDate::currentDate(), time);
0129             } else {
0130                 const QDate date = QDate::fromString(value, Qt::ISODate);
0131                 m_datetime = QDateTime(date);
0132             }
0133             m_valueType = DateOrTime;
0134         }
0135     } else {
0136         // if value is not set current time is assumed  ODF 19.881 text:time-value
0137         m_type = AutoUpdate;
0138     }
0139 
0140     //dateProperties.setProperty("definition", dateFormat);
0141     m_definition = dateFormat;
0142 
0143     //dateProperties.setProperty("adjust", element.attributeNS(KoXmlNS::text, localName + "-adjust"));
0144     const QString adjust(element.attributeNS(KoXmlNS::text, localName + "-adjust", ""));
0145     adjustTime(adjust);
0146     update();
0147     return true;
0148 }
0149 
0150 void DateVariable::readProperties(const KoProperties *props)
0151 {
0152     m_definition = props->stringProperty("definition");
0153     if (!props->stringProperty("time").isEmpty())
0154         m_datetime = QDateTime::fromString(props->stringProperty("time"), Qt::ISODate);
0155     if (props->intProperty("id") == Fixed)
0156         m_type = Fixed;
0157     else
0158         m_type = AutoUpdate;
0159     QString displayTypeProp = props->stringProperty("displayType", "date");
0160     if (displayTypeProp == "time") {
0161         m_displayType = Time;
0162     }
0163     else {
0164         m_displayType = Date;
0165     }
0166     m_valueType = DateTime;
0167     adjustTime(props->stringProperty("adjust"));
0168     update();
0169 }
0170 
0171 QWidget *DateVariable::createOptionsWidget()
0172 {
0173     switch (m_type) {
0174     case Fixed:
0175         return new FixedDateFormat(this);
0176     default:;
0177     }
0178     return 0;
0179 }
0180 
0181 void DateVariable::setDefinition(const QString &definition)
0182 {
0183     m_definition = definition;
0184     update();
0185 }
0186 
0187 void DateVariable::setSecsOffset(int offset)
0188 {
0189     m_secsOffset = offset;
0190     update();
0191 }
0192 
0193 void DateVariable::setDaysOffset(int offset)
0194 {
0195     m_daysOffset = offset;
0196     update();
0197 }
0198 
0199 void DateVariable::setMonthsOffset(int offset)
0200 {
0201     m_monthsOffset = offset;
0202     update();
0203 }
0204 
0205 void DateVariable::setYearsOffset(int offset)
0206 {
0207     m_yearsOffset = offset;
0208     update();
0209 }
0210 
0211 void DateVariable::update()
0212 {
0213     QDateTime target;
0214     switch (m_type) {
0215     case Fixed:
0216         target = m_datetime;
0217         break;
0218     case AutoUpdate:
0219         target = QDateTime::currentDateTime();
0220         break;
0221     }
0222     target = target.addSecs(m_secsOffset);
0223     target = target.addDays(m_daysOffset);
0224     target = target.addMonths(m_monthsOffset);
0225     target = target.addYears(m_yearsOffset);
0226     switch (m_displayType) {
0227     case Time:
0228         if (m_definition.isEmpty()) {
0229             setValue(target.time().toString(Qt::LocalDate));
0230         }
0231         else {
0232             setValue(target.time().toString(m_definition));
0233         }
0234         break;
0235     case Date:
0236         if (m_definition.isEmpty()) {
0237             setValue(target.date().toString(Qt::LocalDate));
0238         }
0239         else {
0240             setValue(target.toString(m_definition));
0241         }
0242         break;
0243     }
0244 }
0245 
0246 void DateVariable::adjustTime(const QString & value)
0247 {
0248     if (!value.isEmpty()) {
0249         m_daysOffset = 0;
0250         m_monthsOffset = 0;
0251         m_yearsOffset = 0;
0252         m_secsOffset = 0;
0253         int multiplier = 1;
0254         if (value.contains("-")) {
0255             multiplier = -1;
0256         }
0257         QString timePart;
0258         QString datePart;
0259         QStringList parts = value.mid(value.indexOf('P') + 1).split('T');
0260         datePart = parts[0];
0261         if (parts.size() > 1) {
0262             timePart = parts[1];
0263         }
0264         QRegExp rx("([0-9]+)([DHMSY])");
0265         int value;
0266         bool valueOk;
0267         if (!timePart.isEmpty()) {
0268             int pos = 0;
0269             while ((pos = rx.indexIn(timePart, pos)) != -1) {
0270                 value = rx.cap(1).toInt(&valueOk);
0271                 if (valueOk) {
0272                     if (rx.cap(2) == "H") {
0273                         m_secsOffset += multiplier * 3600 * value;
0274                     } else if (rx.cap(2) == "M") {
0275                         m_secsOffset += multiplier * 60 * value;
0276                     } else if (rx.cap(2) == "S") {
0277                         m_secsOffset += multiplier * value;
0278                     }
0279                 }
0280                 pos += rx.matchedLength();
0281             }
0282         }
0283         if (!datePart.isEmpty()) {
0284             int pos = 0;
0285             while ((pos = rx.indexIn(datePart, pos)) != -1) {
0286                 value = rx.cap(1).toInt(&valueOk);
0287                 if (valueOk) {
0288                     if (rx.cap(2) == "Y") {
0289                         m_yearsOffset += multiplier * value;
0290                     } else if (rx.cap(2) == "M") {
0291                         m_monthsOffset += multiplier * value;
0292                     } else if (rx.cap(2) == "D") {
0293                         m_daysOffset += multiplier * value;
0294                     }
0295                 }
0296                 pos += rx.matchedLength();
0297             }
0298         }
0299     }
0300 }