• Skip to content
  • Skip to link menu
KDE 4.7 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KDECore

ktimezone.cpp
Go to the documentation of this file.
00001 /*
00002    This file is part of the KDE libraries
00003    Copyright (c) 2005-2008,2011 David Jarvie <djarvie@kde.org>
00004    Copyright (c) 2005 S.R.Haque <srhaque@iee.org>.
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019    Boston, MA 02110-1301, USA.
00020 */
00021 
00022 #include "ktimezone.h"
00023 
00024 #include <config.h>
00025 #include <config-date.h> // SIZEOF_TIME_T
00026 
00027 #ifdef HAVE_SYS_TIME_H
00028 #include <sys/time.h>
00029 #endif
00030 #ifdef HAVE_TIME_H
00031 #include <time.h>
00032 #endif
00033 #include <climits>
00034 #include <cstdlib>
00035 
00036 #include <QtCore/QSet>
00037 #include <QtCore/QSharedData>
00038 #include <QtCore/QCoreApplication>
00039 
00040 #include <kdebug.h>
00041 #include <kglobal.h>
00042 
00043 int gmtoff(time_t t);   // defined in ksystemtimezone.cpp
00044 
00045 
00046 /******************************************************************************/
00047 
00048 class KTimeZonesPrivate
00049 {
00050 public:
00051     KTimeZonesPrivate() {}
00052 
00053     KTimeZones::ZoneMap zones;
00054 };
00055 
00056 
00057 KTimeZones::KTimeZones()
00058   : d(new KTimeZonesPrivate)
00059 {
00060 }
00061 
00062 KTimeZones::~KTimeZones()
00063 {
00064     delete d;
00065 }
00066 
00067 const KTimeZones::ZoneMap KTimeZones::zones() const
00068 {
00069     return d->zones;
00070 }
00071 
00072 bool KTimeZones::add(const KTimeZone &zone)
00073 {
00074     if (!zone.isValid())
00075         return false;
00076     if (d->zones.find(zone.name()) != d->zones.end())
00077         return false;    // name already exists
00078     d->zones.insert(zone.name(), zone);
00079     return true;
00080 }
00081 
00082 KTimeZone KTimeZones::remove(const KTimeZone &zone)
00083 {
00084     if (zone.isValid())
00085     {
00086         for (ZoneMap::Iterator it = d->zones.begin(), end = d->zones.end();  it != end;  ++it)
00087         {
00088             if (it.value() == zone)
00089             {
00090                 d->zones.erase(it);
00091                 return zone;
00092             }
00093         }
00094     }
00095     return KTimeZone();
00096 }
00097 
00098 KTimeZone KTimeZones::remove(const QString &name)
00099 {
00100     if (!name.isEmpty())
00101     {
00102         ZoneMap::Iterator it = d->zones.find(name);
00103         if (it != d->zones.end())
00104         {
00105             KTimeZone zone = it.value();
00106             d->zones.erase(it);
00107             return zone;
00108         }
00109     }
00110     return KTimeZone();
00111 }
00112 
00113 void KTimeZones::clear()
00114 {
00115   d->zones.clear();
00116 }
00117 
00118 KTimeZone KTimeZones::zone(const QString &name) const
00119 {
00120     if (!name.isEmpty())
00121     {
00122         ZoneMap::ConstIterator it = d->zones.constFind(name);
00123         if (it != d->zones.constEnd())
00124             return it.value();
00125         if (name == KTimeZone::utc().name())
00126             return KTimeZone::utc();
00127     }
00128     return KTimeZone();    // error
00129 }
00130 
00131 
00132 /******************************************************************************/
00133 
00134 class KTimeZonePhasePrivate : public QSharedData
00135 {
00136     public:
00137         QByteArray       abbreviations;  // time zone abbreviations (zero-delimited)
00138         QString          comment;        // optional comment
00139         int              utcOffset;      // seconds to add to UTC
00140         bool             dst;            // true if daylight savings time
00141 
00142         explicit KTimeZonePhasePrivate(int offset = 0, bool ds = false)
00143         : QSharedData(),
00144           utcOffset(offset),
00145           dst(ds)
00146         {}
00147         KTimeZonePhasePrivate(const KTimeZonePhasePrivate& rhs)
00148         : QSharedData(rhs),
00149           abbreviations(rhs.abbreviations),
00150           comment(rhs.comment),
00151           utcOffset(rhs.utcOffset),
00152           dst(rhs.dst)
00153         {}
00154         bool operator==(const KTimeZonePhasePrivate &rhs) const
00155         {
00156             return abbreviations == rhs.abbreviations
00157                &&  comment       == rhs.comment
00158                &&  utcOffset     == rhs.utcOffset
00159                &&  dst           == rhs.dst;
00160         }
00161 };
00162 
00163 
00164 KTimeZone::Phase::Phase()
00165   : d(new KTimeZonePhasePrivate)
00166 {
00167 }
00168 
00169 KTimeZone::Phase::Phase(int utcOffset, const QByteArray &abbrevs,
00170                         bool dst, const QString &cmt)
00171   : d(new KTimeZonePhasePrivate(utcOffset, dst))
00172 {
00173     d->abbreviations = abbrevs;
00174     d->comment       = cmt;
00175 }
00176 
00177 KTimeZone::Phase::Phase(int utcOffset, const QList<QByteArray> &abbrevs,
00178                         bool dst, const QString &cmt)
00179   : d(new KTimeZonePhasePrivate(utcOffset, dst))
00180 {
00181     for (int i = 0, end = abbrevs.count();  i < end;  ++i)
00182     {
00183         if (i > 0)
00184             d->abbreviations += '\0';
00185         d->abbreviations += abbrevs[i];
00186     }
00187     d->comment = cmt;
00188 }
00189 
00190 KTimeZone::Phase::Phase(const KTimeZone::Phase &rhs)
00191   : d(rhs.d)
00192 {
00193 }
00194 
00195 KTimeZone::Phase::~Phase()
00196 {
00197 }
00198 
00199 KTimeZone::Phase &KTimeZone::Phase::operator=(const KTimeZone::Phase &rhs)
00200 {
00201     d = rhs.d;
00202     return *this;
00203 }
00204 
00205 bool KTimeZone::Phase::operator==(const KTimeZone::Phase &rhs) const
00206 {
00207     return d == rhs.d  ||  *d == *rhs.d;
00208 }
00209 
00210 int KTimeZone::Phase::utcOffset() const
00211 {
00212     return d->utcOffset;
00213 }
00214 
00215 QList<QByteArray> KTimeZone::Phase::abbreviations() const
00216 {
00217     return d->abbreviations.split('\0');
00218 }
00219 
00220 bool KTimeZone::Phase::isDst() const
00221 {
00222     return d->dst;
00223 }
00224 
00225 QString KTimeZone::Phase::comment() const
00226 {
00227     return d->comment;
00228 }
00229 
00230 
00231 /******************************************************************************/
00232 
00233 class KTimeZoneTransitionPrivate
00234 {
00235 public:
00236     QDateTime time;
00237     KTimeZone::Phase phase;
00238 };
00239 
00240 
00241 KTimeZone::Transition::Transition()
00242     : d(new KTimeZoneTransitionPrivate)
00243 {
00244 }
00245 
00246 KTimeZone::Transition::Transition(const QDateTime &t, const KTimeZone::Phase &p)
00247     : d(new KTimeZoneTransitionPrivate)
00248 {
00249     d->time  = t;
00250     d->phase = p;
00251 }
00252 
00253 KTimeZone::Transition::Transition(const KTimeZone::Transition &t)
00254     : d(new KTimeZoneTransitionPrivate)
00255 {
00256     d->time  = t.d->time;
00257     d->phase = t.d->phase;
00258 }
00259 
00260 KTimeZone::Transition::~Transition()
00261 {
00262     delete d;
00263 }
00264 
00265 KTimeZone::Transition &KTimeZone::Transition::operator=(const KTimeZone::Transition &t)
00266 {
00267     d->time  = t.d->time;
00268     d->phase = t.d->phase;
00269     return *this;
00270 }
00271 
00272 bool KTimeZone::Transition::operator<(const KTimeZone::Transition &rhs) const
00273 {
00274     return d->time < rhs.d->time;
00275 }
00276 
00277 QDateTime        KTimeZone::Transition::time() const   { return d->time; }
00278 KTimeZone::Phase KTimeZone::Transition::phase() const  { return d->phase; }
00279 
00280 
00281 /******************************************************************************/
00282 
00283 class KTimeZoneDataPrivate
00284 {
00285     public:
00286         QList<KTimeZone::Phase>       phases;
00287         QList<KTimeZone::Transition>  transitions;
00288         QList<KTimeZone::LeapSeconds> leapChanges;
00289         QList<int>                    utcOffsets;
00290         QList<QByteArray>             abbreviations;
00291         int preUtcOffset;    // UTC offset to use before the first phase
00292 
00293         KTimeZoneDataPrivate() : preUtcOffset(0) {}
00294         // Find the last transition before a specified UTC or local date/time.
00295         int transitionIndex(const QDateTime &dt) const;
00296         bool transitionIndexes(const QDateTime &start, const QDateTime &end, int &ixstart, int &ixend) const;
00297         bool isSecondOccurrence(const QDateTime &utcLocalTime, int transitionIndex) const;
00298 };
00299 
00300 
00301 /******************************************************************************/
00302 
00303 class KTimeZonePrivate : public QSharedData
00304 {
00305 public:
00306     KTimeZonePrivate() : source(0), data(0), refCount(1), cachedTransitionIndex(-1) {}
00307     KTimeZonePrivate(KTimeZoneSource *src, const QString& nam,
00308                      const QString &country, float lat, float lon, const QString &cmnt);
00309     KTimeZonePrivate(const KTimeZonePrivate &);
00310     ~KTimeZonePrivate()  { delete data; }
00311     KTimeZonePrivate &operator=(const KTimeZonePrivate &);
00312     static KTimeZoneSource *utcSource();
00313     static void cleanup();
00314 
00315     KTimeZoneSource *source;
00316     QString name;
00317     QString countryCode;
00318     QString comment;
00319     float   latitude;
00320     float   longitude;
00321     mutable KTimeZoneData *data;
00322     int     refCount; // holds the number of KTimeZoneBackend instances using the KTimeZonePrivate instance as a d-pointer.
00323     int       cachedTransitionIndex;
00324     QDateTime cachedTransitionStartZoneTime;
00325     QDateTime cachedTransitionEndZoneTime;
00326     bool      cachedTransitionTimesValid;
00327 
00328 private:
00329     static KTimeZoneSource *mUtcSource;
00330 };
00331 
00332 KTimeZoneSource *KTimeZonePrivate::mUtcSource = 0;
00333 
00334 
00335 KTimeZonePrivate::KTimeZonePrivate(KTimeZoneSource *src, const QString& nam,
00336                  const QString &country, float lat, float lon, const QString &cmnt)
00337   : source(src),
00338     name(nam),
00339     countryCode(country.toUpper()),
00340     comment(cmnt),
00341     latitude(lat),
00342     longitude(lon),
00343     data(0),
00344     refCount(1),
00345     cachedTransitionIndex(-1)
00346 {
00347     // Detect duff values.
00348     if (latitude > 90 || latitude < -90)
00349         latitude = KTimeZone::UNKNOWN;
00350     if (longitude > 180 || longitude < -180)
00351         longitude = KTimeZone::UNKNOWN;
00352 }
00353 
00354 KTimeZonePrivate::KTimeZonePrivate(const KTimeZonePrivate &rhs)
00355   : QSharedData(rhs),
00356     source(rhs.source),
00357     name(rhs.name),
00358     countryCode(rhs.countryCode),
00359     comment(rhs.comment),
00360     latitude(rhs.latitude),
00361     longitude(rhs.longitude),
00362     refCount(1),
00363     cachedTransitionIndex(rhs.cachedTransitionIndex),
00364     cachedTransitionStartZoneTime(rhs.cachedTransitionStartZoneTime),
00365     cachedTransitionEndZoneTime(rhs.cachedTransitionEndZoneTime),
00366     cachedTransitionTimesValid(rhs.cachedTransitionTimesValid)
00367 {
00368     if (rhs.data)
00369         data = rhs.data->clone();
00370     else
00371         data = 0;
00372 }
00373 
00374 KTimeZonePrivate &KTimeZonePrivate::operator=(const KTimeZonePrivate &rhs)
00375 {
00376     // Changing the contents of a KTimeZonePrivate instance by means of operator=() doesn't affect how
00377     // many references to it are held.
00378     source      = rhs.source;
00379     name        = rhs.name;
00380     countryCode = rhs.countryCode;
00381     comment     = rhs.comment;
00382     latitude    = rhs.latitude;
00383     longitude   = rhs.longitude;
00384     cachedTransitionIndex         = rhs.cachedTransitionIndex;
00385     cachedTransitionStartZoneTime = rhs.cachedTransitionStartZoneTime;
00386     cachedTransitionEndZoneTime   = rhs.cachedTransitionEndZoneTime;
00387     cachedTransitionTimesValid    = rhs.cachedTransitionTimesValid;
00388     delete data;
00389     if (rhs.data)
00390         data = rhs.data->clone();
00391     else
00392         data = 0;
00393     // refCount is unchanged
00394     return *this;
00395 }
00396 
00397 KTimeZoneSource *KTimeZonePrivate::utcSource()
00398 {
00399     if (!mUtcSource)
00400     {
00401         mUtcSource = new KTimeZoneSource;
00402         qAddPostRoutine(KTimeZonePrivate::cleanup);
00403     }
00404     return mUtcSource;
00405 }
00406 
00407 void KTimeZonePrivate::cleanup()
00408 {
00409     delete mUtcSource;
00410 }
00411 
00412 
00413 /******************************************************************************/
00414 
00415 K_GLOBAL_STATIC(KTimeZonePrivate, s_emptyTimeZonePrivate)
00416 
00417 KTimeZoneBackend::KTimeZoneBackend()
00418   : d(&*s_emptyTimeZonePrivate)
00419 {
00420     ++d->refCount;
00421 }
00422 
00423 KTimeZoneBackend::KTimeZoneBackend(const QString &name)
00424   : d(new KTimeZonePrivate(KTimeZonePrivate::utcSource(), name, QString(), KTimeZone::UNKNOWN, KTimeZone::UNKNOWN, QString()))
00425 {}
00426 
00427 KTimeZoneBackend::KTimeZoneBackend(KTimeZoneSource *source, const QString &name,
00428         const QString &countryCode, float latitude, float longitude, const QString &comment)
00429   : d(new KTimeZonePrivate(source, name, countryCode, latitude, longitude, comment))
00430 {}
00431 
00432 KTimeZoneBackend::KTimeZoneBackend(const KTimeZoneBackend &other)
00433   : d(other.d)
00434 {
00435     ++d->refCount;
00436 }
00437 
00438 KTimeZoneBackend::~KTimeZoneBackend()
00439 {
00440     if (d && --d->refCount == 0)
00441         delete d;
00442     d = 0;
00443 }
00444 
00445 KTimeZoneBackend &KTimeZoneBackend::operator=(const KTimeZoneBackend &other)
00446 {
00447     if (d != other.d)
00448     {
00449         if (--d->refCount == 0)
00450             delete d;
00451         d = other.d;
00452         ++d->refCount;
00453     }
00454     return *this;
00455 }
00456 
00457 QByteArray KTimeZoneBackend::type() const
00458 {
00459     return "KTimeZone";
00460 }
00461 
00462 KTimeZoneBackend *KTimeZoneBackend::clone() const
00463 {
00464     return new KTimeZoneBackend(*this);
00465 }
00466 
00467 int KTimeZoneBackend::offsetAtZoneTime(const KTimeZone* caller, const QDateTime &zoneDateTime, int *secondOffset) const
00468 {
00469     if (!zoneDateTime.isValid()  ||  zoneDateTime.timeSpec() != Qt::LocalTime)    // check for invalid time
00470     {
00471         if (secondOffset)
00472             *secondOffset = 0;
00473         return 0;
00474     }
00475     QList<KTimeZone::Transition> transitions = caller->transitions();
00476     int index = d->cachedTransitionIndex;
00477     if (index >= 0 && index < transitions.count())
00478     {
00479         // There is a cached transition - check whether zoneDateTime uses it.
00480         // Caching is used because this method has been found to consume
00481         // significant CPU in real life applications.
00482         if (!d->cachedTransitionTimesValid)
00483         {
00484             int offset = transitions[index].phase().utcOffset();
00485         int preoffset = (index > 0) ? transitions[index - 1].phase().utcOffset() : d->data ? d->data->previousUtcOffset() : 0;
00486             d->cachedTransitionStartZoneTime = transitions[index].time().addSecs(qMax(offset, preoffset));
00487             if (index + 1 < transitions.count())
00488         {
00489                 int postoffset = transitions[index + 1].phase().utcOffset();
00490                 d->cachedTransitionEndZoneTime = transitions[index + 1].time().addSecs(qMin(offset, postoffset));
00491         }
00492             d->cachedTransitionTimesValid = true;
00493         }
00494         QDateTime dtutc = zoneDateTime;
00495         dtutc.setTimeSpec(Qt::UTC);
00496         if (dtutc >= d->cachedTransitionStartZoneTime
00497         &&  (index + 1 >= transitions.count() || dtutc < d->cachedTransitionEndZoneTime))
00498         {
00499             // The time falls within the cached transition limits, so return its UTC offset
00500             int offset = transitions[index].phase().utcOffset();
00501             if (secondOffset)
00502                 *secondOffset = offset;
00503 #ifdef COMPILING_TESTS
00504             qDebug("-> Using cache");   // test output requires qDebug instead of kDebug
00505 #endif
00506             return offset;
00507         }
00508     }
00509 
00510     // The time doesn't fall within the cached transition, or there isn't a cached transition
00511 #ifdef COMPILING_TESTS
00512     qDebug("-> No cache");   // test output requires qDebug instead of kDebug
00513 #endif
00514     bool validTime;
00515     int secondIndex = -1;
00516     index = caller->transitionIndex(zoneDateTime, (secondOffset ? &secondIndex : 0), &validTime);
00517     const KTimeZone::Transition* tr = (index >= 0) ? &transitions[index] : 0;
00518     int offset = tr ? tr->phase().utcOffset()
00519                     : validTime ? (d->data ? d->data->previousUtcOffset() : 0)
00520                                 : KTimeZone::InvalidOffset;
00521     if (secondOffset)
00522         *secondOffset = (secondIndex >= 0) ? transitions[secondIndex].phase().utcOffset() : offset;
00523 
00524     // Cache transition data for subsequent date/time values which occur after the same transition.
00525     d->cachedTransitionIndex = index;
00526     d->cachedTransitionTimesValid = false;
00527     return offset;
00528 }
00529 
00530 int KTimeZoneBackend::offsetAtUtc(const KTimeZone* caller, const QDateTime &utcDateTime) const
00531 {
00532     if (!utcDateTime.isValid()  ||  utcDateTime.timeSpec() != Qt::UTC)    // check for invalid time
00533         return 0;
00534     QList<KTimeZone::Transition> transitions = caller->transitions();
00535     int index = d->cachedTransitionIndex;
00536     if (index >= 0 && index < transitions.count())
00537     {
00538         // There is a cached transition - check whether utcDateTime uses it.
00539         int offset = transitions[index].phase().utcOffset();
00540         if (utcDateTime >= transitions[index].time()
00541         &&  (index + 1 >= transitions.count()
00542              || utcDateTime < transitions[index + 1].time()))
00543         {
00544             // The time falls within the cached transition, so return its UTC offset
00545 #ifdef COMPILING_TESTS
00546             qDebug("Using cache");   // test output requires qDebug instead of kDebug
00547 #endif
00548             return offset;
00549         }
00550     }
00551 
00552     // The time doesn't fall within the cached transition, or there isn't a cached transition
00553 #ifdef COMPILING_TESTS
00554     qDebug("No cache");   // test output requires qDebug instead of kDebug
00555 #endif
00556     index = caller->transitionIndex(utcDateTime);
00557     d->cachedTransitionIndex = index;   // cache transition data
00558     d->cachedTransitionTimesValid = false;
00559     const KTimeZone::Transition* tr = (index >= 0) ? &transitions[index] : 0;
00560     return tr ? tr->phase().utcOffset() : (d->data ? d->data->previousUtcOffset() : 0);
00561 }
00562 
00563 int KTimeZoneBackend::offset(const KTimeZone* caller, time_t t) const
00564 {
00565     return offsetAtUtc(caller, KTimeZone::fromTime_t(t));
00566 }
00567 
00568 bool KTimeZoneBackend::isDstAtUtc(const KTimeZone* caller, const QDateTime &utcDateTime) const
00569 {
00570     if (!utcDateTime.isValid()  ||  utcDateTime.timeSpec() != Qt::UTC)    // check for invalid time
00571         return false;
00572     const KTimeZone::Transition *tr = caller->transition(utcDateTime);
00573     if (!tr)
00574         return false;
00575     return tr->phase().isDst();
00576 }
00577 
00578 bool KTimeZoneBackend::isDst(const KTimeZone* caller, time_t t) const
00579 {
00580     return isDstAtUtc(caller, KTimeZone::fromTime_t(t));
00581 }
00582 
00583 bool KTimeZoneBackend::hasTransitions(const KTimeZone* caller) const
00584 {
00585     Q_UNUSED(caller);
00586     return false;
00587 }
00588 
00589 
00590 /******************************************************************************/
00591 
00592 #if SIZEOF_TIME_T == 8
00593 const time_t KTimeZone::InvalidTime_t = 0x800000000000000LL;
00594 #else
00595 const time_t KTimeZone::InvalidTime_t = 0x80000000;
00596 #endif
00597 const int    KTimeZone::InvalidOffset = 0x80000000;
00598 const float  KTimeZone::UNKNOWN = 1000.0;
00599 
00600 
00601 KTimeZone::KTimeZone()
00602   : d(new KTimeZoneBackend())
00603 {}
00604 
00605 KTimeZone::KTimeZone(const QString &name)
00606   : d(new KTimeZoneBackend(name))
00607 {}
00608 
00609 KTimeZone::KTimeZone(const KTimeZone &tz)
00610   : d(tz.d->clone())
00611 {}
00612 
00613 KTimeZone::~KTimeZone()
00614 {
00615     delete d;
00616 }
00617 
00618 KTimeZone::KTimeZone(KTimeZoneBackend *impl)
00619   : d(impl)
00620 {
00621     // 'impl' should be a newly constructed object, with refCount = 1
00622     Q_ASSERT(d->d->refCount == 1 || d->d == &*s_emptyTimeZonePrivate);
00623 }
00624 
00625 KTimeZone &KTimeZone::operator=(const KTimeZone &tz)
00626 {
00627     if (d != tz.d)
00628     {
00629         delete d;
00630         d = tz.d->clone();
00631     }
00632     return *this;
00633 }
00634 
00635 bool KTimeZone::operator==(const KTimeZone &rhs) const
00636 {
00637     return d->d == rhs.d->d;
00638 }
00639 
00640 QByteArray KTimeZone::type() const
00641 {
00642     return d->type();
00643 }
00644 
00645 bool KTimeZone::isValid() const
00646 {
00647     return !d->d->name.isEmpty();
00648 }
00649 
00650 QString KTimeZone::countryCode() const
00651 {
00652     return d->d->countryCode;
00653 }
00654 
00655 float KTimeZone::latitude() const
00656 {
00657     return d->d->latitude;
00658 }
00659 
00660 float KTimeZone::longitude() const
00661 {
00662     return d->d->longitude;
00663 }
00664 
00665 QString KTimeZone::comment() const
00666 {
00667     return d->d->comment;
00668 }
00669 
00670 QString KTimeZone::name() const
00671 {
00672     return d->d->name;
00673 }
00674 
00675 QList<QByteArray> KTimeZone::abbreviations() const
00676 {
00677     if (!data(true))
00678         return QList<QByteArray>();
00679     return d->d->data->abbreviations();
00680 }
00681 
00682 QByteArray KTimeZone::abbreviation(const QDateTime &utcDateTime) const
00683 {
00684     if (utcDateTime.timeSpec() != Qt::UTC  ||  !data(true))
00685         return QByteArray();
00686     return d->d->data->abbreviation(utcDateTime);
00687 }
00688 
00689 QList<int> KTimeZone::utcOffsets() const
00690 {
00691     if (!data(true))
00692         return QList<int>();
00693     return d->d->data->utcOffsets();
00694 }
00695 
00696 QList<KTimeZone::Phase> KTimeZone::phases() const
00697 {
00698     if (!data(true))
00699         return QList<KTimeZone::Phase>();
00700     return d->d->data->phases();
00701 }
00702 
00703 bool KTimeZone::hasTransitions() const
00704 {
00705     return d->hasTransitions(this);
00706 }
00707 
00708 QList<KTimeZone::Transition> KTimeZone::transitions(const QDateTime &start, const QDateTime &end) const
00709 {
00710     if (!data(true))
00711         return QList<KTimeZone::Transition>();
00712     return d->d->data->transitions(start, end);
00713 }
00714 
00715 const KTimeZone::Transition *KTimeZone::transition(const QDateTime &dt, const Transition **secondTransition,
00716                                                    bool *validTime) const
00717 {
00718     if (!data(true))
00719         return 0;
00720     return d->d->data->transition(dt, secondTransition, validTime);
00721 }
00722 
00723 int KTimeZone::transitionIndex(const QDateTime &dt, int *secondIndex, bool *validTime) const
00724 {
00725     if (!data(true))
00726         return -1;
00727     return d->d->data->transitionIndex(dt, secondIndex, validTime);
00728 }
00729 
00730 QList<QDateTime> KTimeZone::transitionTimes(const Phase &phase, const QDateTime &start, const QDateTime &end) const
00731 {
00732     if (!data(true))
00733         return QList<QDateTime>();
00734     return d->d->data->transitionTimes(phase, start, end);
00735 }
00736 
00737 QList<KTimeZone::LeapSeconds> KTimeZone::leapSecondChanges() const
00738 {
00739     if (!data(true))
00740         return QList<KTimeZone::LeapSeconds>();
00741     return d->d->data->leapSecondChanges();
00742 }
00743 
00744 KTimeZoneSource *KTimeZone::source() const
00745 {
00746     return d->d->source;
00747 }
00748 
00749 const KTimeZoneData *KTimeZone::data(bool create) const
00750 {
00751     if (!isValid())
00752         return 0;
00753     if (create && !d->d->data && d->d->source->useZoneParse())
00754         d->d->data = d->d->source->parse(*this);
00755     return d->d->data;
00756 }
00757 
00758 void KTimeZone::setData(KTimeZoneData *data, KTimeZoneSource *source)
00759 {
00760     if (!isValid())
00761         return;
00762     delete d->d->data;
00763     d->d->data = data;
00764     if (source)
00765         d->d->source = source;
00766 }
00767 
00768 bool KTimeZone::updateBase(const KTimeZone &other)
00769 {
00770     if (d->d->name.isEmpty() || d->d->name != other.d->d->name)
00771         return false;
00772     d->d->countryCode = other.d->d->countryCode;
00773     d->d->comment     = other.d->d->comment;
00774     d->d->latitude    = other.d->d->latitude;
00775     d->d->longitude   = other.d->d->longitude;
00776     return true;
00777 }
00778 
00779 bool KTimeZone::parse() const
00780 {
00781     if (!isValid())
00782         return false;
00783     if (d->d->source->useZoneParse())
00784     {
00785         delete d->d->data;
00786         d->d->data = d->d->source->parse(*this);
00787     }
00788     return d->d->data;
00789 }
00790 
00791 QDateTime KTimeZone::toUtc(const QDateTime &zoneDateTime) const
00792 {
00793     if (!zoneDateTime.isValid()  ||  zoneDateTime.timeSpec() != Qt::LocalTime)
00794         return QDateTime();
00795     int secs = offsetAtZoneTime(zoneDateTime);
00796     if (secs == InvalidOffset)
00797         return QDateTime();
00798     QDateTime dt = zoneDateTime;
00799     dt.setTimeSpec(Qt::UTC);
00800     return dt.addSecs(-secs);
00801 }
00802 
00803 QDateTime KTimeZone::toZoneTime(const QDateTime &utcDateTime, bool *secondOccurrence) const
00804 {
00805     if (secondOccurrence)
00806         *secondOccurrence = false;
00807     if (!utcDateTime.isValid()  ||  utcDateTime.timeSpec() != Qt::UTC)    // check for invalid time
00808         return QDateTime();
00809 
00810     // Convert UTC to local time
00811     if (hasTransitions())
00812     {
00813         if (!data(true))
00814         {
00815             // No data - default to UTC
00816             QDateTime dt = utcDateTime;
00817             dt.setTimeSpec(Qt::LocalTime);
00818             return dt;
00819         }
00820 
00821         int index = d->d->data->transitionIndex(utcDateTime);
00822         int secs = (index >= 0) ? d->d->data->transitions()[index].phase().utcOffset() : d->d->data->previousUtcOffset();
00823         QDateTime dt = utcDateTime.addSecs(secs);
00824         if (secondOccurrence)
00825         {
00826             // Check whether the local time occurs twice around a daylight savings time
00827             // shift, and if so, whether it's the first or second occurrence.
00828             *secondOccurrence = d->d->data->d->isSecondOccurrence(dt, index);
00829         }
00830         dt.setTimeSpec(Qt::LocalTime);
00831         return dt;
00832     }
00833     else
00834     {
00835         int secs = offsetAtUtc(utcDateTime);
00836         QDateTime dt = utcDateTime.addSecs(secs);
00837         dt.setTimeSpec(Qt::LocalTime);
00838         if (secondOccurrence)
00839         {
00840             // Check whether the local time occurs twice around a daylight savings time
00841             // shift, and if so, whether it's the first or second occurrence.
00842             *secondOccurrence = (secs != offsetAtZoneTime(dt));
00843         }
00844         return dt;
00845     }
00846 }
00847 
00848 QDateTime KTimeZone::convert(const KTimeZone &newZone, const QDateTime &zoneDateTime) const
00849 {
00850     if (newZone == *this)
00851     {
00852         if (zoneDateTime.timeSpec() != Qt::LocalTime)
00853             return QDateTime();
00854         return zoneDateTime;
00855     }
00856     return newZone.toZoneTime(toUtc(zoneDateTime));
00857 }
00858 
00859 int KTimeZone::offsetAtZoneTime(const QDateTime &zoneDateTime, int *secondOffset) const
00860 {
00861     return d->offsetAtZoneTime(this, zoneDateTime, secondOffset);
00862 }
00863 
00864 int KTimeZone::offsetAtUtc(const QDateTime &utcDateTime) const
00865 {
00866     return d->offsetAtUtc(this, utcDateTime);
00867 }
00868 
00869 int KTimeZone::offset(time_t t) const
00870 {
00871     return d->offset(this, t);
00872 }
00873 
00874 int KTimeZone::currentOffset(Qt::TimeSpec basis) const
00875 {
00876     // Get current offset of this time zone to UTC
00877     time_t now = time(0);
00878     int secs = offset(now);
00879 
00880     switch (basis)
00881     {
00882         case Qt::LocalTime:
00883             // Return the current offset of this time zone to the local system time
00884             return secs - gmtoff(now);
00885         case Qt::UTC:
00886             // Return the current offset of this time zone to UTC
00887             return secs;
00888 
00889         default:
00890             break;
00891     }
00892     return 0;
00893 }
00894 
00895 bool KTimeZone::isDstAtUtc(const QDateTime &utcDateTime) const
00896 {
00897     return d->isDstAtUtc(this, utcDateTime);
00898 }
00899 
00900 bool KTimeZone::isDst(time_t t) const
00901 {
00902     return d->isDst(this, t);
00903 }
00904 
00905 KTimeZone KTimeZone::utc()
00906 {
00907     static KTimeZone utcZone(QLatin1String("UTC"));
00908     return utcZone;
00909 }
00910 
00911 QDateTime KTimeZone::fromTime_t(time_t t)
00912 {
00913     static const int secondsADay = 86400;
00914     static const QDate epochDate(1970,1,1);
00915     static const QTime epochTime(0,0,0);
00916     int days = t / secondsADay;
00917     int secs;
00918     if (t >= 0)
00919         secs = t % secondsADay;
00920     else
00921     {
00922         secs = secondsADay - (-t % secondsADay);
00923         --days;
00924     }
00925     return QDateTime(epochDate.addDays(days), epochTime.addSecs(secs), Qt::UTC);
00926 }
00927 
00928 time_t KTimeZone::toTime_t(const QDateTime &utcDateTime)
00929 {
00930     static const QDate epochDate(1970,1,1);
00931     static const QTime epochTime(0,0,0);
00932     if (utcDateTime.timeSpec() != Qt::UTC)
00933         return InvalidTime_t;
00934     qint64 days = epochDate.daysTo(utcDateTime.date());
00935     qint64 secs = epochTime.secsTo(utcDateTime.time());
00936     qint64 t64 = days * 86400 + secs;
00937     time_t t = static_cast<time_t>(t64);
00938     if (static_cast<qint64>(t) != t64)
00939         return InvalidTime_t;
00940     return t;
00941 }
00942 
00943 
00944 /******************************************************************************/
00945 
00946 class KTimeZoneSourcePrivate
00947 {
00948 public:
00949     bool mUseZoneParse;
00950 };
00951 
00952 
00953 KTimeZoneSource::KTimeZoneSource()
00954   : d(new KTimeZoneSourcePrivate)
00955 {
00956     d->mUseZoneParse = true;
00957 }
00958 
00959 KTimeZoneSource::KTimeZoneSource(bool useZoneParse)
00960   : d(new KTimeZoneSourcePrivate)
00961 {
00962     d->mUseZoneParse = useZoneParse;
00963 }
00964 
00965 KTimeZoneSource::~KTimeZoneSource()
00966 {
00967     delete d;
00968 }
00969 
00970 KTimeZoneData *KTimeZoneSource::parse(const KTimeZone &) const
00971 {
00972     Q_ASSERT(d->mUseZoneParse);  // method should never be called if it isn't usable
00973     return new KTimeZoneData;
00974 }
00975 
00976 bool KTimeZoneSource::useZoneParse() const
00977 {
00978     return d->mUseZoneParse;
00979 }
00980 
00981 
00982 /******************************************************************************/
00983 
00984 class KTimeZoneLeapSecondsPrivate
00985 {
00986     public:
00987         QDateTime  dt;         // UTC time when this change occurred
00988         QString    comment;    // optional comment
00989         int        seconds;    // number of leap seconds
00990 };
00991 
00992 
00993 KTimeZone::LeapSeconds::LeapSeconds()
00994   : d(new KTimeZoneLeapSecondsPrivate)
00995 {
00996 }
00997 
00998 KTimeZone::LeapSeconds::LeapSeconds(const QDateTime &utc, int leap, const QString &cmt)
00999   : d(new KTimeZoneLeapSecondsPrivate)
01000 {
01001     if (utc.timeSpec() == Qt::UTC)   // invalid if start time is not UTC
01002     {
01003         d->dt      = utc;
01004         d->comment = cmt;
01005         d->seconds = leap;
01006     }
01007 }
01008 
01009 KTimeZone::LeapSeconds::LeapSeconds(const KTimeZone::LeapSeconds &c)
01010   : d(new KTimeZoneLeapSecondsPrivate)
01011 {
01012     d->dt      = c.d->dt;
01013     d->comment = c.d->comment;
01014     d->seconds = c.d->seconds;
01015 }
01016 
01017 KTimeZone::LeapSeconds::~LeapSeconds()
01018 {
01019     delete d;
01020 }
01021 
01022 KTimeZone::LeapSeconds &KTimeZone::LeapSeconds::operator=(const KTimeZone::LeapSeconds &c)
01023 {
01024     d->dt      = c.d->dt;
01025     d->comment = c.d->comment;
01026     d->seconds = c.d->seconds;
01027     return *this;
01028 }
01029 
01030 bool KTimeZone::LeapSeconds::operator<(const KTimeZone::LeapSeconds& c) const
01031 {
01032     return d->dt < c.d->dt;
01033 }
01034 
01035 QDateTime KTimeZone::LeapSeconds::dateTime() const
01036 {
01037     return d->dt;
01038 }
01039 
01040 bool KTimeZone::LeapSeconds::isValid() const
01041 {
01042     return d->dt.isValid();
01043 }
01044 
01045 int KTimeZone::LeapSeconds::leapSeconds() const
01046 {
01047     return d->seconds;
01048 }
01049 
01050 QString KTimeZone::LeapSeconds::comment() const
01051 {
01052     return d->comment;
01053 }
01054 
01055 
01056 /******************************************************************************/
01057 
01058 
01059 int KTimeZoneDataPrivate::transitionIndex(const QDateTime &dt) const
01060 {
01061     // Do a binary search to find the last transition before this date/time
01062     int start = -1;
01063     int end = transitions.count();
01064     if (dt.timeSpec() == Qt::UTC)
01065     {
01066         while (end - start > 1)
01067         {
01068             int i = (start + end) / 2;
01069             if (dt < transitions[i].time())
01070                 end = i;
01071             else
01072                 start = i;
01073         }
01074     }
01075     else
01076     {
01077         QDateTime dtutc = dt;
01078         dtutc.setTimeSpec(Qt::UTC);
01079         while (end - start > 1)
01080         {
01081             int i = (start + end) / 2;
01082             if (dtutc.addSecs(-transitions[i].phase().utcOffset()) < transitions[i].time())
01083                 end = i;
01084             else
01085                 start = i;
01086         }
01087     }
01088     return end ? start : -1;
01089 }
01090 
01091 // Find the indexes to the transitions at or after start, and before or at end.
01092 // start and end must be UTC.
01093 // Reply = false if none.
01094 bool KTimeZoneDataPrivate::transitionIndexes(const QDateTime &start, const QDateTime &end, int &ixstart, int &ixend) const
01095 {
01096     ixstart = 0;
01097     if (start.isValid() && start.timeSpec() == Qt::UTC)
01098     {
01099         ixstart = transitionIndex(start);
01100         if (ixstart < 0)
01101             ixstart = 0;
01102         else if (transitions[ixstart].time() < start)
01103         {
01104             if (++ixstart >= transitions.count())
01105                 return false;   // there are no transitions at/after 'start'
01106         }
01107     }
01108     ixend = -1;
01109     if (end.isValid() && end.timeSpec() == Qt::UTC)
01110     {
01111         ixend = transitionIndex(end);
01112         if (ixend < 0)
01113             return false;   // there are no transitions at/before 'end'
01114     }
01115     return true;
01116 }
01117 
01118 /* Check if it's a local time which occurs both before and after the specified
01119  * transition (for which it has to span a daylight saving to standard time change).
01120  * @param utcLocalTime local time set to Qt::UTC
01121  */
01122 bool KTimeZoneDataPrivate::isSecondOccurrence(const QDateTime &utcLocalTime, int transitionIndex) const
01123 {
01124     if (transitionIndex < 0)
01125         return false;
01126     int offset = transitions[transitionIndex].phase().utcOffset();
01127     int prevoffset = (transitionIndex > 0) ? transitions[transitionIndex-1].phase().utcOffset() : preUtcOffset;
01128     int phaseDiff = prevoffset - offset;
01129     if (phaseDiff <= 0)
01130         return false;
01131     // Find how long after the start of the latest phase 'dt' is
01132     int afterStart = transitions[transitionIndex].time().secsTo(utcLocalTime) - offset;
01133     return (afterStart < phaseDiff);
01134 }
01135 
01136 
01137 
01138 KTimeZoneData::KTimeZoneData()
01139   : d(new KTimeZoneDataPrivate)
01140 { }
01141 
01142 KTimeZoneData::KTimeZoneData(const KTimeZoneData &c)
01143   : d(new KTimeZoneDataPrivate)
01144 {
01145     d->phases        = c.d->phases;
01146     d->transitions   = c.d->transitions;
01147     d->leapChanges   = c.d->leapChanges;
01148     d->utcOffsets    = c.d->utcOffsets;
01149     d->abbreviations = c.d->abbreviations;
01150     d->preUtcOffset  = c.d->preUtcOffset;
01151 }
01152 
01153 KTimeZoneData::~KTimeZoneData()
01154 {
01155     delete d;
01156 }
01157 
01158 KTimeZoneData &KTimeZoneData::operator=(const KTimeZoneData &c)
01159 {
01160     d->phases        = c.d->phases;
01161     d->transitions   = c.d->transitions;
01162     d->leapChanges   = c.d->leapChanges;
01163     d->utcOffsets    = c.d->utcOffsets;
01164     d->abbreviations = c.d->abbreviations;
01165     d->preUtcOffset  = c.d->preUtcOffset;
01166     return *this;
01167 }
01168 
01169 KTimeZoneData *KTimeZoneData::clone() const
01170 {
01171     return new KTimeZoneData(*this);
01172 }
01173 
01174 QList<QByteArray> KTimeZoneData::abbreviations() const
01175 {
01176     if (d->abbreviations.isEmpty())
01177     {
01178         for (int i = 0, end = d->phases.count();  i < end;  ++i)
01179         {
01180             const QList<QByteArray> abbrevs = d->phases[i].abbreviations();
01181             for (int j = 0, jend = abbrevs.count();  j < jend;  ++j)
01182                 if (!d->abbreviations.contains(abbrevs[j]))
01183                     d->abbreviations.append(abbrevs[j]);
01184         }
01185         if (d->abbreviations.isEmpty())
01186             d->abbreviations += "UTC";
01187     }
01188     return d->abbreviations;
01189 }
01190 
01191 QByteArray KTimeZoneData::abbreviation(const QDateTime &utcDateTime) const
01192 {
01193     if (d->phases.isEmpty())
01194         return "UTC";
01195     const KTimeZone::Transition *tr = transition(utcDateTime);
01196     if (!tr)
01197         return QByteArray();
01198     const QList<QByteArray> abbrevs = tr->phase().abbreviations();
01199     if (abbrevs.isEmpty())
01200         return QByteArray();
01201     return abbrevs[0];
01202 }
01203 
01204 QList<int> KTimeZoneData::utcOffsets() const
01205 {
01206     if (d->utcOffsets.isEmpty())
01207     {
01208         for (int i = 0, end = d->phases.count();  i < end;  ++i)
01209         {
01210             int offset = d->phases[i].utcOffset();
01211             if (!d->utcOffsets.contains(offset))
01212                 d->utcOffsets.append(offset);
01213         }
01214         if (d->utcOffsets.isEmpty())
01215             d->utcOffsets += 0;
01216         else
01217             qSort(d->utcOffsets);
01218     }
01219     return d->utcOffsets;
01220 }
01221 
01222 QList<KTimeZone::Phase> KTimeZoneData::phases() const
01223 {
01224     return d->phases;
01225 }
01226 
01227 void KTimeZoneData::setPhases(const QList<KTimeZone::Phase> &phases, int previousUtcOffset)
01228 {
01229     d->phases = phases;
01230     d->preUtcOffset = previousUtcOffset;
01231 }
01232 
01233 bool KTimeZoneData::hasTransitions() const
01234 {
01235     return false;
01236 }
01237 
01238 QList<KTimeZone::Transition> KTimeZoneData::transitions(const QDateTime &start, const QDateTime &end) const
01239 {
01240     int ixstart, ixend;
01241     if (!d->transitionIndexes(start, end, ixstart, ixend))
01242         return QList<KTimeZone::Transition>();   // there are no transitions within the time period
01243     if (ixend >= 0)
01244         return d->transitions.mid(ixstart, ixend - ixstart + 1);
01245     if (ixstart > 0)
01246         return d->transitions.mid(ixstart);
01247     return d->transitions;
01248 }
01249 
01250 void KTimeZoneData::setTransitions(const QList<KTimeZone::Transition> &transitions)
01251 {
01252     d->transitions = transitions;
01253 }
01254 
01255 int KTimeZoneData::previousUtcOffset() const
01256 {
01257     return d->preUtcOffset;
01258 }
01259 
01260 const KTimeZone::Transition *KTimeZoneData::transition(const QDateTime &dt, const KTimeZone::Transition **secondTransition,
01261                                                        bool *validTime) const
01262 {
01263     int secondIndex;
01264     int index = transitionIndex(dt, (secondTransition ? &secondIndex : 0), validTime);
01265     if (secondTransition)
01266         *secondTransition = (secondIndex >= 0) ? &d->transitions[secondIndex] : 0;
01267     return (index >= 0) ? &d->transitions[index] : 0;
01268 }
01269 
01270 int KTimeZoneData::transitionIndex(const QDateTime &dt, int *secondIndex, bool *validTime) const
01271 {
01272     if (validTime)
01273         *validTime = true;
01274 
01275     // Find the last transition before this date/time
01276     int index = d->transitionIndex(dt);
01277     if (dt.timeSpec() == Qt::UTC)
01278     {
01279         if (secondIndex)
01280             *secondIndex = index;
01281         return index;
01282     }
01283     else
01284     {
01285         /* Check whether the specified local time actually occurs.
01286          * Find the start of the next phase, and check if it falls in the gap
01287          * between the two phases.
01288          */
01289         QDateTime dtutc = dt;
01290         dtutc.setTimeSpec(Qt::UTC);
01291         int count = d->transitions.count();
01292         int next = (index >= 0) ? index + 1 : 0;
01293         if (next < count)
01294         {
01295             KTimeZone::Phase nextPhase = d->transitions[next].phase();
01296             int offset = (index >= 0) ? d->transitions[index].phase().utcOffset() : d->preUtcOffset;
01297             int phaseDiff = nextPhase.utcOffset() - offset;
01298             if (phaseDiff > 0)
01299             {
01300                 // Get UTC equivalent as if 'dt' was in the next phase
01301                 if (dtutc.secsTo(d->transitions[next].time()) + nextPhase.utcOffset() < phaseDiff)
01302                 {
01303                     // The time falls in the gap between the two phases,
01304                     // so return an invalid value.
01305                     if (validTime)
01306                         *validTime = false;
01307                     if (secondIndex)
01308                         *secondIndex = -1;
01309                     return -1;
01310                 }
01311             }
01312         }
01313 
01314         if (index < 0)
01315         {
01316             // The specified time is before the first phase
01317             if (secondIndex)
01318                 *secondIndex = -1;
01319             return -1;
01320         }
01321 
01322         /* Check if it's a local time which occurs both before and after the 'latest'
01323          * phase start time (for which it has to span a daylight saving to standard
01324          * time change).
01325          */
01326         bool duplicate = true;
01327         if (d->isSecondOccurrence(dtutc, index))
01328         {
01329             // 'dt' occurs twice
01330             if (secondIndex)
01331             {
01332                 *secondIndex = index;
01333                 duplicate = false;
01334             }
01335             // Get the transition containing the first occurrence of 'dt'
01336             if (index <= 0)
01337                 return -1;   // first occurrence of 'dt' is just before the first transition
01338             --index;
01339         }
01340 
01341         if (secondIndex  &&  duplicate)
01342             *secondIndex = index;
01343         return index;
01344     }
01345 }
01346 
01347 QList<QDateTime> KTimeZoneData::transitionTimes(const KTimeZone::Phase &phase, const QDateTime &start, const QDateTime &end) const
01348 {
01349     QList<QDateTime> times;
01350     int ixstart, ixend;
01351     if (d->transitionIndexes(start, end, ixstart, ixend))
01352     {
01353         if (ixend < 0)
01354             ixend = d->transitions.count() - 1;
01355         while (ixstart <= ixend)
01356         {
01357             if (d->transitions[ixstart].phase() == phase)
01358                 times += d->transitions[ixstart].time();
01359         }
01360     }
01361     return times;
01362 }
01363 
01364 QList<KTimeZone::LeapSeconds> KTimeZoneData::leapSecondChanges() const
01365 {
01366     return d->leapChanges;
01367 }
01368 
01369 void KTimeZoneData::setLeapSecondChanges(const QList<KTimeZone::LeapSeconds> &adjusts)
01370 {
01371     d->leapChanges = adjusts;
01372 }
01373 
01374 KTimeZone::LeapSeconds KTimeZoneData::leapSecondChange(const QDateTime &utc) const
01375 {
01376     if (utc.timeSpec() != Qt::UTC)
01377         kError() << "KTimeZoneData::leapSecondChange(): non-UTC time specified" << endl;
01378     else
01379     {
01380         for (int i = d->leapChanges.count();  --i >= 0;  )
01381         {
01382             if (d->leapChanges[i].dateTime() < utc)
01383                 return d->leapChanges[i];
01384         }
01385     }
01386     return KTimeZone::LeapSeconds();
01387 }

KDECore

Skip menu "KDECore"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal