File indexing completed on 2024-05-05 05:48:32

0001 /*
0002     CT Unit of Time Interval Implementation
0003     --------------------------------------------------------------------
0004     SPDX-FileCopyrightText: 1999 Gary Meyer <gary@meyer.net>
0005     --------------------------------------------------------------------
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #include "ctunit.h"
0010 
0011 #include <KLocalizedString>
0012 
0013 CTUnit::CTUnit(int _min, int _max, const QString &tokStr)
0014 {
0015     mMin = _min;
0016     mMax = _max;
0017     initialize(tokStr);
0018 }
0019 
0020 CTUnit::CTUnit(const CTUnit &source)
0021 {
0022     mMin = source.mMin;
0023     mMax = source.mMax;
0024 
0025     mInitialEnabled.clear();
0026     mEnabled.clear();
0027     mInitialEnabled.reserve(mMax + 1);
0028     for (int i = 0; i <= mMax; i++) {
0029         mInitialEnabled.append(false);
0030         mEnabled.append(source.mEnabled.at(i));
0031     }
0032 
0033     mInitialTokStr = QLatin1String("");
0034     mDirty = true;
0035 }
0036 
0037 CTUnit::~CTUnit()
0038 {
0039 }
0040 
0041 CTUnit &CTUnit::operator=(const CTUnit &unit)
0042 {
0043     if (this == &unit) {
0044         return *this;
0045     }
0046 
0047     mMin = unit.mMin;
0048     mMax = unit.mMax;
0049 
0050     mEnabled.clear();
0051     for (int i = 0; i <= mMax; i++) {
0052         mEnabled.append(unit.mEnabled[i]);
0053     }
0054     mDirty = true;
0055 
0056     return *this;
0057 }
0058 
0059 void CTUnit::initialize(const QString &tokStr)
0060 {
0061     mEnabled.clear();
0062     for (int i = 0; i <= mMax; i++) {
0063         mEnabled.append(false);
0064         mInitialEnabled.append(false);
0065     }
0066 
0067     for (int i = mMin; i <= mMax; i++) {
0068         mInitialEnabled[i] = mEnabled[i];
0069     }
0070 
0071     parse(tokStr);
0072     mInitialTokStr = tokStr;
0073     mDirty = false;
0074 }
0075 
0076 void CTUnit::parse(const QString &tokenString)
0077 {
0078     QString tokStr = tokenString;
0079 
0080     // subelement is that which is between commas
0081     QString subelement;
0082     int commapos, slashpos, dashpos;
0083     int beginat, endat, step;
0084 
0085     // loop through each subelement
0086     tokStr += QLatin1Char(',');
0087     while ((commapos = tokStr.indexOf(QLatin1Char(','))) > 0) {
0088         subelement = tokStr.mid(0, commapos);
0089 
0090         // find "/" to determine step
0091         slashpos = subelement.indexOf(QLatin1Char('/'));
0092         if (slashpos == -1) {
0093             step = 1;
0094             slashpos = subelement.length();
0095         } else {
0096             step = fieldToValue(subelement.mid(slashpos + 1, subelement.length() - slashpos - 1));
0097             if (step < 1) {
0098                 step = 1;
0099             }
0100         }
0101 
0102         // find "=" to determine range
0103         dashpos = subelement.indexOf(QLatin1Char('-'));
0104         if (dashpos == -1) {
0105             // deal with "*"
0106             if (subelement.mid(0, slashpos) == QLatin1Char('*')) {
0107                 beginat = mMin;
0108                 endat = mMax;
0109             } else {
0110                 beginat = fieldToValue(subelement.mid(0, slashpos));
0111                 endat = beginat;
0112             }
0113         } else {
0114             beginat = fieldToValue(subelement.mid(0, dashpos));
0115             endat = fieldToValue(subelement.mid(dashpos + 1, slashpos - dashpos - 1));
0116         }
0117 
0118         // ignore out of range
0119         if (beginat < 0) {
0120             beginat = 0;
0121         }
0122         if (endat > mMax) {
0123             endat = mMax;
0124         }
0125 
0126         // setup enabled
0127         for (int i = beginat; i <= endat; i += step) {
0128             mInitialEnabled[i] = mEnabled[i] = true;
0129         }
0130 
0131         tokStr = tokStr.mid(commapos + 1, tokStr.length() - commapos - 1);
0132     }
0133 }
0134 
0135 QString CTUnit::exportUnit() const
0136 {
0137     if (!mDirty) {
0138         return mInitialTokStr;
0139     }
0140 
0141     if (isAllEnabled()) {
0142         return QStringLiteral("*");
0143     }
0144 
0145     int total = enabledCount();
0146     int count = 0;
0147     QString tokenizeUnit;
0148 
0149     for (int num = mMin; num <= mMax; num++) {
0150         if (mEnabled[num]) {
0151             tokenizeUnit += QString::number(num);
0152             count++;
0153 
0154             if (count < total) {
0155                 tokenizeUnit += QLatin1Char(',');
0156             }
0157         }
0158     }
0159 
0160     return tokenizeUnit;
0161 }
0162 
0163 QString CTUnit::genericDescribe(const QList<QString> &label) const
0164 {
0165     int total(enabledCount());
0166     int count(0);
0167     QString tmpStr;
0168     for (int i = mMin; i <= mMax; i++) {
0169         if (mEnabled[i]) {
0170             tmpStr += label.at(i);
0171             count++;
0172             switch (total - count) {
0173             case 0:
0174                 break;
0175             case 1:
0176                 if (total > 2) {
0177                     tmpStr += i18n(",");
0178                 }
0179                 tmpStr += i18n(" and ");
0180                 break;
0181             default:
0182                 tmpStr += i18n(", ");
0183                 break;
0184             }
0185         }
0186     }
0187     return tmpStr;
0188 }
0189 
0190 int CTUnit::minimum() const
0191 {
0192     return mMin;
0193 }
0194 
0195 int CTUnit::maximum() const
0196 {
0197     return mMax;
0198 }
0199 
0200 bool CTUnit::isEnabled(int pos) const
0201 {
0202     return mEnabled.at(pos);
0203 }
0204 
0205 bool CTUnit::isAllEnabled() const
0206 {
0207     for (int i = mMin; i <= mMax; i++) {
0208         if (!mEnabled.at(i)) {
0209             return false;
0210         }
0211     }
0212 
0213     return true;
0214 }
0215 
0216 void CTUnit::setEnabled(int pos, bool value)
0217 {
0218     mEnabled[pos] = value;
0219     mDirty = true;
0220     return;
0221 }
0222 
0223 bool CTUnit::isDirty() const
0224 {
0225     return mDirty;
0226 }
0227 
0228 int CTUnit::enabledCount() const
0229 {
0230     int total(0);
0231     for (int i = mMin; i <= mMax; i++) {
0232         total += (mEnabled[i] == true);
0233     }
0234     return total;
0235 }
0236 
0237 void CTUnit::apply()
0238 {
0239     mInitialTokStr = exportUnit();
0240     for (int i = mMin; i <= mMax; i++) {
0241         mInitialEnabled[i] = mEnabled.at(i);
0242     }
0243     mDirty = false;
0244 }
0245 
0246 void CTUnit::cancel()
0247 {
0248     for (int i = mMin; i <= mMax; i++) {
0249         mEnabled[i] = mInitialEnabled.at(i);
0250     }
0251     mDirty = false;
0252 }
0253 
0254 int CTUnit::fieldToValue(const QString &entry) const
0255 {
0256     QString lower = entry.toLower();
0257 
0258     // check for days
0259     QList<QString> days;
0260     days << QStringLiteral("sun") << QStringLiteral("mon") << QStringLiteral("tue") << QStringLiteral("wed") << QStringLiteral("thu") << QStringLiteral("fri")
0261          << QStringLiteral("sat");
0262 
0263     int day = days.indexOf(lower);
0264     if (day != -1) {
0265         return day;
0266     }
0267 
0268     // check for months
0269     QList<QString> months;
0270     months << QLatin1String("") << QStringLiteral("jan") << QStringLiteral("feb") << QStringLiteral("mar") << QStringLiteral("apr") << QStringLiteral("may")
0271            << QStringLiteral("jun") << QStringLiteral("jul") << QStringLiteral("aug") << QStringLiteral("sep") << QStringLiteral("oct") << QStringLiteral("nov")
0272            << QStringLiteral("dec");
0273 
0274     int month = months.indexOf(lower);
0275     if (month != -1) {
0276         return month;
0277     }
0278 
0279     // If the string does not match a day ora month, then it's a simple number (minute, hour or day of month)
0280     return entry.toInt();
0281 }
0282 
0283 /**
0284  * Find a period in enabled values
0285  * If no period has been found, return 0
0286  */
0287 int CTUnit::findPeriod(const QList<int> &periods) const
0288 {
0289     for (int period : periods) {
0290         bool validPeriod = true;
0291 
0292         for (int i = minimum(); i <= maximum(); i++) {
0293             bool periodTesting;
0294             if ((double)i / (double)period == i / period) {
0295                 periodTesting = true;
0296             } else {
0297                 periodTesting = false;
0298             }
0299 
0300             if (isEnabled(i) != periodTesting) {
0301                 validPeriod = false;
0302                 break;
0303             }
0304         }
0305 
0306         if (validPeriod) {
0307             return period;
0308         }
0309     }
0310 
0311     return 0;
0312 }