File indexing completed on 2024-04-14 03:51:26

0001 /*
0002     This file is part of the KContacts framework.
0003     SPDX-FileCopyrightText: 2001 Cornelius Schumacher <schumacher@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "phonenumber.h"
0009 #include "parametermap_p.h"
0010 
0011 #include <KLocalizedString>
0012 #include <krandom.h>
0013 
0014 #include <QDataStream>
0015 #include <QSharedData>
0016 
0017 using namespace KContacts;
0018 
0019 static QString cleanupNumber(const QString &input)
0020 {
0021     return input.simplified();
0022 }
0023 
0024 class Q_DECL_HIDDEN PhoneNumber::Private : public QSharedData
0025 {
0026 public:
0027     Private(Type type)
0028         : mId(KRandom::randomString(8))
0029         , mType(type)
0030     {
0031     }
0032 
0033     Private(const Private &other)
0034         : QSharedData(other)
0035     {
0036         mId = other.mId;
0037         mType = other.mType;
0038         mNumber = other.mNumber;
0039     }
0040 
0041     QString mId;
0042     QString mNumber;
0043     Type mType;
0044     ParameterMap mParamMap;
0045 };
0046 
0047 PhoneNumber::PhoneNumber()
0048     : d(new Private(Home))
0049 {
0050 }
0051 
0052 PhoneNumber::PhoneNumber(const QString &number, Type type)
0053     : d(new Private(type))
0054 {
0055     d->mNumber = cleanupNumber(number);
0056 }
0057 
0058 PhoneNumber::PhoneNumber(const PhoneNumber &other)
0059     : d(other.d)
0060 {
0061 }
0062 
0063 PhoneNumber::~PhoneNumber()
0064 {
0065 }
0066 
0067 bool PhoneNumber::operator==(const PhoneNumber &other) const
0068 {
0069     if (d->mId != other.d->mId) {
0070         return false;
0071     }
0072 
0073     if (d->mNumber != other.d->mNumber) {
0074         return false;
0075     }
0076 
0077     if (d->mType != other.d->mType) {
0078         return false;
0079     }
0080 
0081     if (d->mParamMap != other.d->mParamMap) {
0082         return false;
0083     }
0084 
0085     return true;
0086 }
0087 
0088 bool PhoneNumber::operator!=(const PhoneNumber &other) const
0089 {
0090     return !(other == *this);
0091 }
0092 
0093 PhoneNumber &PhoneNumber::operator=(const PhoneNumber &other)
0094 {
0095     if (this != &other) {
0096         d = other.d;
0097     }
0098 
0099     return *this;
0100 }
0101 
0102 bool PhoneNumber::isEmpty() const
0103 {
0104     return d->mNumber.isEmpty();
0105 }
0106 
0107 void PhoneNumber::setId(const QString &id)
0108 {
0109     d->mId = id;
0110 }
0111 
0112 QString PhoneNumber::id() const
0113 {
0114     return d->mId;
0115 }
0116 
0117 void PhoneNumber::setNumber(const QString &number)
0118 {
0119     d->mNumber = cleanupNumber(number);
0120 }
0121 
0122 QString PhoneNumber::number() const
0123 {
0124     return d->mNumber;
0125 }
0126 
0127 QString PhoneNumber::normalizedNumber() const
0128 {
0129     QString result;
0130     result.reserve(d->mNumber.size());
0131     for (const auto &c : d->mNumber) {
0132         if (c.isDigit() || (c == QLatin1Char('+') && result.isEmpty())) {
0133             result.push_back(c);
0134         }
0135     }
0136     return result;
0137 }
0138 
0139 void PhoneNumber::setType(Type type)
0140 {
0141     d->mType = type;
0142 }
0143 
0144 PhoneNumber::Type PhoneNumber::type() const
0145 {
0146     return d->mType;
0147 }
0148 
0149 QString PhoneNumber::typeLabel() const
0150 {
0151     return typeLabel(type());
0152 }
0153 
0154 PhoneNumber::TypeList PhoneNumber::typeList()
0155 {
0156     static TypeList list;
0157 
0158     if (list.isEmpty()) {
0159         list << Home << Work << Msg << Pref << Voice << Fax << Cell << Video //
0160              << Bbs << Modem << Car << Isdn << Pcs << Pager << Undefined;
0161     }
0162 
0163     return list;
0164 }
0165 
0166 QString PhoneNumber::typeFlagLabel(TypeFlag type)
0167 {
0168     switch (type) {
0169     case Undefined:
0170         return i18nc("Undefined phone type", "Telephone number");
0171     case Home:
0172         return i18nc("Home phone", "Home");
0173     case Work:
0174         return i18nc("Work phone", "Work");
0175     case Msg:
0176         return i18n("Messenger");
0177     case Pref:
0178         return i18nc("Preferred phone", "Preferred");
0179     case Voice:
0180         return i18n("Voice");
0181     case Fax:
0182         return i18n("Fax");
0183     case Cell:
0184         return i18nc("Mobile Phone", "Mobile");
0185     case Video:
0186         return i18nc("Video phone", "Video");
0187     case Bbs:
0188         return i18n("Mailbox");
0189     case Modem:
0190         return i18n("Modem");
0191     case Car:
0192         return i18nc("Car Phone", "Car");
0193     case Isdn:
0194         return i18n("ISDN");
0195     case Pcs:
0196         return i18n("PCS");
0197     case Pager:
0198         return i18n("Pager");
0199     default:
0200         return i18nc("another type of phone", "Other");
0201     }
0202 }
0203 
0204 QString PhoneNumber::typeLabel(Type type)
0205 {
0206     QString label;
0207     bool first = true;
0208 
0209     // special cases
0210     // Pref stand alone -> Preferred Number
0211     // Home+Fax or Work+Fax -> combine as initial string
0212     if (type == Pref) {
0213         return i18n("Preferred Number");
0214     }
0215 
0216     if (type & Fax) {
0217         if (type & Home) {
0218             label = i18n("Home Fax");
0219             first = false;
0220             type &= ~Fax;
0221             type &= ~Home;
0222         } else if (type & Work) {
0223             label = i18n("Work Fax");
0224             first = false;
0225             type &= ~Fax;
0226             type &= ~Work;
0227         }
0228     }
0229 
0230     const TypeList list = typeList();
0231     for (const auto f : list) {
0232         // these are actually flags
0233         const TypeFlag flag = static_cast<TypeFlag>(static_cast<int>(f));
0234         if (type & flag) {
0235             if (!first) {
0236                 label.append(QLatin1Char('/'));
0237             }
0238 
0239             label.append(typeFlagLabel(flag));
0240 
0241             if (first) {
0242                 first = false;
0243             }
0244         }
0245     }
0246 
0247     return label;
0248 }
0249 
0250 bool PhoneNumber::isPreferred() const
0251 {
0252     return type() & Pref;
0253 }
0254 
0255 bool PhoneNumber::supportsSms() const
0256 {
0257     return type() & Cell;
0258 }
0259 
0260 QString PhoneNumber::toString() const
0261 {
0262     QString str = QLatin1String("PhoneNumber {\n");
0263     str += QStringLiteral("    Id: %1\n").arg(d->mId);
0264     str += QStringLiteral("    Type: %1\n").arg(typeLabel(d->mType));
0265     str = d->mParamMap.toString();
0266     str += QStringLiteral("    Number: %1\n").arg(d->mNumber);
0267     str += QLatin1String("}\n");
0268 
0269     return str;
0270 }
0271 
0272 void PhoneNumber::setParams(const ParameterMap &params)
0273 {
0274     d->mParamMap = params;
0275 }
0276 
0277 ParameterMap PhoneNumber::params() const
0278 {
0279     return d->mParamMap;
0280 }
0281 
0282 QDataStream &KContacts::operator<<(QDataStream &s, const PhoneNumber &phone)
0283 {
0284     return s << phone.d->mId << static_cast<uint>(phone.d->mType) << phone.d->mNumber << phone.d->mParamMap;
0285 }
0286 
0287 QDataStream &KContacts::operator>>(QDataStream &s, PhoneNumber &phone)
0288 {
0289     uint type;
0290     s >> phone.d->mId >> type >> phone.d->mNumber >> phone.d->mParamMap;
0291     phone.d->mType = PhoneNumber::Type(type);
0292 
0293     return s;
0294 }
0295 
0296 #include "moc_phonenumber.cpp"