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 }