kexi

kexidatetimeformatter.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2006 Jaroslaw Staniek <js@iidea.pl>
00003 
00004    This program is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this program; see the file COPYING.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "kexidatetimeformatter.h"
00021 
00022 #include <kdebug.h>
00023 #include <klocale.h>
00024 #include <kglobal.h>
00025 #include <kdatepicker.h>
00026 #include <kdatetbl.h>
00027 #include <klineedit.h>
00028 #include <kpopupmenu.h>
00029 #include <kdatewidget.h>
00030 
00031 KexiDateFormatter::KexiDateFormatter()
00032 {
00033     // use "short date" format system settings
00035     QString df( KGlobal::locale()->dateFormatShort() );
00036     if (df.length()>2)
00037         m_separator = df.mid(2,1);
00038     else
00039         m_separator = "-";
00040     const int separatorLen = m_separator.length();
00041     QString yearMask("9999");
00042     QString yearDateFormat("yyyy"), 
00043         monthDateFormat("MM"), 
00044         dayDateFormat("dd"); //for setting up m_dateFormat
00045     bool ok = df.length()>=8;
00046     int yearpos, monthpos, daypos; //result of df.find()
00047     if (ok) {//look at % variables
00050         yearpos = df.find("%y", 0, false); //&y or %y
00051         m_longYear = !(yearpos>=0 && df.mid(yearpos+1, 1)=="y"); 
00052         if (!m_longYear) {
00053             yearMask = "99";
00054             yearDateFormat = "yy";
00055         }
00056         monthpos = df.find("%m", 0, true); //%m or %n
00057         m_monthWithLeadingZero = true;
00058         if (monthpos<0) {
00059             monthpos = df.find("%n", 0, false);
00060             m_monthWithLeadingZero = false;
00061             monthDateFormat = "M";
00062         }
00063         daypos = df.find("%d", 0, true);//%d or %e
00064         m_dayWithLeadingZero = true;
00065         if (daypos<0) {
00066             daypos = df.find("%e", 0, false);
00067             m_dayWithLeadingZero = false;
00068             dayDateFormat = "d";
00069         }
00070         ok = (yearpos>=0 && monthpos>=0 && daypos>=0);
00071     }
00072     m_order = QDateEdit::YMD; //default
00073     if (ok) {
00074         if (yearpos<monthpos && monthpos<daypos) {
00075             //will be set in "default: YMD"
00076         }
00077         else if (yearpos<daypos && daypos<monthpos) {
00078             m_order = QDateEdit::YDM;
00081             m_inputMask = QString("%1%299%399").arg(yearMask).arg(m_separator).arg(m_separator);
00082             m_qtFormat = yearDateFormat+m_separator+dayDateFormat+m_separator+monthDateFormat;
00083             m_yearpos = 0;
00084             m_daypos = yearMask.length()+separatorLen;
00085             m_monthpos = m_daypos+2+separatorLen;
00086         }
00087         else if (daypos<monthpos && monthpos<yearpos) {
00088             m_order = QDateEdit::DMY;
00089             m_inputMask = QString("99%199%2%3").arg(m_separator).arg(m_separator).arg(yearMask);
00090             m_qtFormat = dayDateFormat+m_separator+monthDateFormat+m_separator+yearDateFormat;
00091             m_daypos = 0;
00092             m_monthpos = 2+separatorLen;
00093             m_yearpos = m_monthpos+2+separatorLen;
00094         }
00095         else if (monthpos<daypos && daypos<yearpos) {
00096             m_order = QDateEdit::MDY;
00097             m_inputMask = QString("99%199%2%3").arg(m_separator).arg(m_separator).arg(yearMask);
00098             m_qtFormat = monthDateFormat+m_separator+dayDateFormat+m_separator+yearDateFormat;
00099             m_monthpos = 0;
00100             m_daypos = 2+separatorLen;
00101             m_yearpos = m_daypos+2+separatorLen;
00102         }
00103         else
00104             ok = false;
00105     }
00106     if (!ok || m_order == QDateEdit::YMD) {//default: YMD
00107         m_inputMask = QString("%1%299%399").arg(yearMask).arg(m_separator).arg(m_separator);
00108         m_qtFormat = yearDateFormat+m_separator+monthDateFormat+m_separator+dayDateFormat;
00109         m_yearpos = 0;
00110         m_monthpos = yearMask.length()+separatorLen;
00111         m_daypos = m_monthpos+2+separatorLen;
00112     }
00113     m_inputMask += ";_";
00114 }
00115 
00116 KexiDateFormatter::~KexiDateFormatter()
00117 {
00118 }
00119 
00120 QDate KexiDateFormatter::stringToDate( const QString& str ) const
00121 {
00122     bool ok = true;
00123     int year = str.mid(m_yearpos, m_longYear ? 4 : 2).toInt(&ok);
00124     if (!ok)
00125         return QDate();
00126     if (year < 30) {//2000..2029
00127         year = 2000 + year;
00128     }
00129     else if (year < 100) {//1930..1999
00130         year = 1900 + year;
00131     }
00132 
00133     int month = str.mid(m_monthpos, 2).toInt(&ok);
00134     if (!ok)
00135         return QDate();
00136 
00137     int day = str.mid(m_daypos, 2).toInt(&ok);
00138     if (!ok)
00139         return QDate();
00140 
00141     QDate date(year, month, day);
00142     if (!date.isValid())
00143         return QDate();
00144     return date;
00145 }
00146 
00147 QVariant KexiDateFormatter::stringToVariant( const QString& str ) const
00148 {
00149     if (isEmpty(str))
00150         return QVariant();
00151     const QDate date( stringToDate( str ) );
00152     if (date.isValid())
00153         return date;
00154     return QVariant();
00155 }
00156 
00157 bool KexiDateFormatter::isEmpty( const QString& str ) const
00158 {
00159     QString s(str);
00160     return s.replace(m_separator,"").stripWhiteSpace().isEmpty();
00161 }
00162 
00163 QString KexiDateFormatter::dateToString( const QDate& date ) const
00164 {
00165     return date.toString(m_qtFormat);
00166 }
00167 
00168 //------------------------------------------------
00169 
00170 KexiTimeFormatter::KexiTimeFormatter()
00171 : m_hmsRegExp( new QRegExp("(\\d*):(\\d*):(\\d*).*( am| pm){,1}", false) )
00172  , m_hmRegExp( new QRegExp("(\\d*):(\\d*).*( am| pm){,1}", false) )
00173 {
00174     QString tf( KGlobal::locale()->timeFormat() );
00175     //m_hourpos, m_minpos, m_secpos; are result of tf.find()
00176     QString hourVariable, minVariable, secVariable;
00177 
00178     //detect position of HOUR section: find %H or %k or %I or %l
00179     m_24h = true;
00180     m_hoursWithLeadingZero = true;
00181     m_hourpos = tf.find("%H", 0, true);
00182     if (m_hourpos>=0) {
00183         m_24h = true;
00184         m_hoursWithLeadingZero = true;
00185     }
00186     else {
00187         m_hourpos = tf.find("%k", 0, true);
00188         if (m_hourpos>=0) {
00189             m_24h = true;
00190             m_hoursWithLeadingZero = false;
00191         }
00192         else {
00193             m_hourpos = tf.find("%I", 0, true);
00194             if (m_hourpos>=0) {
00195                 m_24h = false;
00196                 m_hoursWithLeadingZero = true;
00197             }
00198             else {
00199                 m_hourpos = tf.find("%l", 0, true);
00200                 if (m_hourpos>=0) {
00201                     m_24h = false;
00202                     m_hoursWithLeadingZero = false;
00203                 }
00204             }
00205         }
00206     }
00207     m_minpos = tf.find("%M", 0, true);
00208     m_secpos = tf.find("%S", 0, true); //can be -1
00209     m_ampmpos = tf.find("%p", 0, true); //can be -1
00210 
00211     if (m_hourpos<0 || m_minpos<0) {
00212         //set default: hr and min are needed, sec are optional
00213         tf = "%H:%M:%S";
00214         m_24h = true;
00215         m_hoursWithLeadingZero = false;
00216         m_hourpos = 0;
00217         m_minpos = 3;
00218         m_secpos = m_minpos + 3;
00219         m_ampmpos = -1;
00220     }
00221     hourVariable = tf.mid(m_hourpos, 2);
00222 
00223     m_inputMask = tf;
00224 //  m_inputMask.replace( hourVariable, "00" );
00225 //  m_inputMask.replace( "%M", "00" );
00226 //  m_inputMask.replace( "%S", "00" ); //optional
00227     m_inputMask.replace( hourVariable, "99" );
00228     m_inputMask.replace( "%M", "99" );
00229     m_inputMask.replace( "%S", "00" ); //optional
00230     m_inputMask.replace( "%p", "AA" ); //am or pm
00231     m_inputMask += ";_";
00232 
00233     m_outputFormat = tf;
00234 }
00235 
00236 KexiTimeFormatter::~KexiTimeFormatter()
00237 {
00238     delete m_hmsRegExp;
00239     delete m_hmRegExp;
00240 }
00241 
00242 QTime KexiTimeFormatter::stringToTime( const QString& str ) const
00243 {
00244     int hour, min, sec;
00245     bool pm = false;
00246 
00247     bool tryWithoutSeconds = true;
00248     if (m_secpos>=0) {
00249         if (-1 != m_hmsRegExp->search(str)) {
00250             hour = m_hmsRegExp->cap(1).toInt();
00251             min = m_hmsRegExp->cap(2).toInt();
00252             sec = m_hmsRegExp->cap(3).toInt();
00253             if (m_ampmpos >= 0 && m_hmsRegExp->numCaptures()>3)
00254                 pm = m_hmsRegExp->cap(4).stripWhiteSpace().lower()=="pm";
00255             tryWithoutSeconds = false;
00256         }
00257     }
00258     if (tryWithoutSeconds) {
00259         if (-1 == m_hmRegExp->search(str))
00260             return QTime(99,0,0);
00261         hour = m_hmRegExp->cap(1).toInt();
00262         min = m_hmRegExp->cap(2).toInt();
00263         sec = 0;
00264         if (m_ampmpos >= 0 && m_hmRegExp->numCaptures()>2)
00265             pm = m_hmsRegExp->cap(4).lower()=="pm";
00266     }
00267 
00268     if (pm && hour < 12)
00269         hour += 12; //PM
00270     return QTime(hour, min, sec);
00271 }
00272 
00273 QVariant KexiTimeFormatter::stringToVariant( const QString& str )
00274 {
00275     if (isEmpty( str ))
00276         return QVariant();
00277     const QTime time( stringToTime( str ) );
00278     if (time.isValid())
00279         return time;
00280     return QVariant();
00281 }
00282 
00283 bool KexiTimeFormatter::isEmpty( const QString& str ) const
00284 {
00285     QString s(str);
00286     return s.replace(':',"").stripWhiteSpace().isEmpty();
00287 }
00288 
00289 QString KexiTimeFormatter::timeToString( const QTime& time ) const
00290 {
00291     if (!time.isValid())
00292         return QString::null;
00293 
00294     QString s(m_outputFormat);
00295     if (m_24h) {
00296         if (m_hoursWithLeadingZero)
00297             s.replace( "%H", QString::fromLatin1(time.hour()<10 ? "0" : "") + QString::number(time.hour()) );
00298         else
00299             s.replace( "%k", QString::number(time.hour()) );
00300     }
00301     else {
00302         int time12 = (time.hour()>12) ? (time.hour()-12) : time.hour();
00303         if (m_hoursWithLeadingZero)
00304             s.replace( "%I", QString::fromLatin1(time12<10 ? "0" : "") + QString::number(time12) );
00305         else
00306             s.replace( "%l", QString::number(time12) );
00307     }
00308     s.replace( "%M", QString::fromLatin1(time.minute()<10 ? "0" : "") + QString::number(time.minute()) );
00309     if (m_secpos>=0)
00310         s.replace( "%S", QString::fromLatin1(time.second()<10 ? "0" : "") + QString::number(time.second()) );
00311     if (m_ampmpos>=0)
00312         s.replace( "%p", KGlobal::locale()->translate( time.hour()>=12 ? "pm" : "am") );
00313     return s;
00314 }
00315 
00316 //------------------------------------------------
00317 
00318 QString dateTimeInputMask(const KexiDateFormatter& dateFormatter, const KexiTimeFormatter& timeFormatter)
00319 {
00320     QString mask(dateFormatter.inputMask());
00321     mask.truncate(dateFormatter.inputMask().length()-2);
00322     return mask + " " + timeFormatter.inputMask();
00323 }
00324 
00325 QDateTime stringToDateTime(
00326     const KexiDateFormatter& dateFormatter, const KexiTimeFormatter& timeFormatter, const QString& str)
00327 {
00328     QString s( str.stripWhiteSpace() );
00329     const int timepos = s.find(" ");
00330     const bool emptyTime = timepos >= 0 && timeFormatter.isEmpty(s.mid(timepos+1)); //.replace(':',"").stripWhiteSpace().isEmpty();
00331     if (emptyTime)
00332         s = s.left(timepos);
00333     if (timepos>0 && !emptyTime) {
00334         return QDateTime(
00335             dateFormatter.stringToDate( s.left(timepos) ),
00336             timeFormatter.stringToTime( s.mid(timepos+1) )
00337         );
00338     }
00339     else {
00340         return QDateTime(
00341             dateFormatter.stringToDate( s ),
00342             QTime(0,0,0)
00343         );
00344     }
00345 }
00346 
00347 bool dateTimeIsEmpty( const KexiDateFormatter& dateFormatter, const KexiTimeFormatter& timeFormatter, 
00348     const QString& str )
00349 {
00350     int timepos = str.find(" ");
00351     const bool emptyTime = timepos >= 0 && timeFormatter.isEmpty(str.mid(timepos+1)); //s.mid(timepos+1).replace(':',"").stripWhiteSpace().isEmpty();
00352     return (timepos >= 0 && dateFormatter.isEmpty(str.left(timepos)) //s.left(timepos).replace(m_dateFormatter.separator(), "").stripWhiteSpace().isEmpty()
00353         && emptyTime);
00354 }
00355 
00356 bool dateTimeIsValid( const KexiDateFormatter& dateFormatter, 
00357     const KexiTimeFormatter& timeFormatter, const QString& str )
00358 {
00359     int timepos = str.find(" ");
00360     const bool emptyTime = timepos >= 0 && timeFormatter.isEmpty(str.mid(timepos+1)); //s.mid(timepos+1).replace(':',"").stripWhiteSpace().isEmpty();
00361     if (timepos >= 0 && dateFormatter.isEmpty(str.left(timepos)) // s.left(timepos).replace(m_dateFormatter.separator(), "").stripWhiteSpace().isEmpty()
00362         && emptyTime)
00363         //empty date/time is valid
00364         return true;
00365     return timepos>=0 && dateFormatter.stringToDate( str.left(timepos) ).isValid()
00366         && (emptyTime /*date without time is also valid*/ || timeFormatter.stringToTime( str.mid(timepos+1) ).isValid());
00367 }
KDE Home | KDE Accessibility Home | Description of Access Keys