File indexing completed on 2024-04-21 15:30:06

0001 /* This file is part of the KDE project
0002    Copyright (C) 2003-2019 Jarosław Staniek <staniek@kde.org>
0003 
0004    Portions of kstandarddirs.cpp:
0005    Copyright (C) 1999 Sirtaj Singh Kang <taj@kde.org>
0006    Copyright (C) 1999,2007 Stephan Kulow <coolo@kde.org>
0007    Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
0008    Copyright (C) 2009 David Faure <faure@kde.org>
0009 
0010    This program is free software; you can redistribute it and/or
0011    modify it under the terms of the GNU Library General Public
0012    License as published by the Free Software Foundation; either
0013    version 2 of the License, or (at your option) any later version.
0014 
0015    This program is distributed in the hope that it will be useful,
0016    but WITHOUT ANY WARRANTY; without even the implied warranty of
0017    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0018    Library General Public License for more details.
0019 
0020    You should have received a copy of the GNU Library General Public License
0021    along with this program; see the file COPYING.  If not, write to
0022    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0023  * Boston, MA 02110-1301, USA.
0024 */
0025 
0026 #ifndef KDB_TOOLS_UTILS_H
0027 #define KDB_TOOLS_UTILS_H
0028 
0029 #include "kdb_export.h"
0030 #include "config-kdb.h"
0031 
0032 #include <QObject>
0033 #include <QDateTime>
0034 #include <QMetaMethod>
0035 #include <QDebug>
0036 
0037 namespace KDbUtils
0038 {
0039 
0040 //! @return true if @a o has parent @a par (checks recursively)
0041 KDB_EXPORT bool hasParent(QObject* par, QObject* o);
0042 
0043 //! @return parent object of @a o that is of type @a type or @c nullptr if no such parent
0044 template<class type>
0045 inline type findParent(QObject* o, const char* className = nullptr)
0046 {
0047     if (!o)
0048         return nullptr;
0049     while ((o = o->parent())) {
0050         if (::qobject_cast< type >(o) && (!className || o->inherits(className)))
0051             return ::qobject_cast< type >(o);
0052     }
0053     return nullptr;
0054 }
0055 
0056 /**
0057  * Returns the time as a string using Qt::ISODateWithMs format
0058  *
0059  * If milliseconds is zero then they are not appended.
0060  * Works also for Qt < 5.8 which does not offer QTime::toString(Qt::ISODateWithMs).
0061  *
0062  * @since 3.2
0063  */
0064 KDB_EXPORT QString toISODateStringWithMs(const QTime &time);
0065 
0066 /**
0067  * Returns the date/time as a string using Qt::ISODateWithMs format
0068  *
0069  * If milliseconds in time is zero then they are not appended.
0070  * Works also for Qt < 5.8 which does not offer QDateTime::toString(Qt::ISODateWithMs).
0071  *
0072  * @since 3.2
0073  */
0074 KDB_EXPORT QString toISODateStringWithMs(const QDateTime &dateTime);
0075 
0076 /**
0077  * Returns the time represented by the string using the Qt::ISODateWithMs format
0078  *
0079  * Milliseconds are optional.
0080  * Works also for Qt < 5.8 which does not offer QTime::fromString(QString, Qt::ISODateWithMs).
0081  *
0082  * @note Equal to QTime::fromString(string, Qt::ISODate) since the Qt::ISODate mode already
0083  * supports milliseconds in case of fromString().
0084  *
0085  * @since 3.2
0086  */
0087 KDB_EXPORT QTime timeFromISODateStringWithMs(const QString &string);
0088 
0089 /**
0090  * Returns the date/time represented by the string using the Qt::ISODateWithMs format
0091  *
0092  * Milliseconds of time are optional.
0093  * Works also for Qt < 5.8 which does not offer QDateTime::fromString(QString, Qt::ISODateWithMs).
0094  *
0095  * @note Equal to QDateTime::fromString(string, Qt::ISODate) since the Qt::ISODate mode already
0096  * supports milliseconds in case of fromString().
0097  *
0098  * @since 3.2
0099  */
0100 KDB_EXPORT QDateTime dateTimeFromISODateStringWithMs(const QString &string);
0101 
0102 //! QDateTime - a hack needed because QVariant(QTime) has broken isNull()
0103 KDB_EXPORT QDateTime stringToHackedQTime(const QString& s);
0104 
0105 /*! Serializes @a map to the array pointed by @a array.
0106  KDbUtils::deserializeMap() can be used to deserialize this array back to map.
0107  Does nothing if @a array is @c nullptr. */
0108 KDB_EXPORT void serializeMap(const QMap<QString, QString>& map, QByteArray *array);
0109 
0110 /*! Serializes @a map to the string pointed by @a string.
0111  KDbUtils::deserializeMap() can be used to deserialize this array back to map.
0112  Does nothing if @a string is @c nullptr. */
0113 KDB_EXPORT void serializeMap(const QMap<QString, QString>& map, QString *string);
0114 
0115 /*! @return a map deserialized from a byte array @a array.
0116  @a array need to contain data previously serialized using KexiUtils::serializeMap(). */
0117 KDB_EXPORT QMap<QString, QString> deserializeMap(const QByteArray& array);
0118 
0119 /*! @return a map deserialized from @a string.
0120  @a string need to contain data previously serialized using KexiUtils::serializeMap(). */
0121 KDB_EXPORT QMap<QString, QString> deserializeMap(const QString& string);
0122 
0123 /**
0124  * Returns a valid filename converted from given string
0125  *
0126  * Following steps are performed:
0127  * - replace \\, /, :, *, ?, ", <, >, |, \n \\t characters with a space,
0128  * - simplify whitespace by removing redundant space characters using QString::simplified().
0129  * - prepend '_' character if the first character is '.', so the file will not be considered hidden
0130  *   (since 3.2.0).
0131  *
0132  * @note Do not pass full paths here but only filename strings.
0133  */
0134 KDB_EXPORT QString stringToFileName(const QString& string);
0135 
0136 /*! Performs a simple @a string encryption using rot47-like algorithm.
0137  Each character's unicode value is increased by 47 + i (where i is index of the character).
0138  The resulting string still contains readable characters but some of them can be non-ASCII.
0139  Does nothing if @a string is @c nullptr.
0140  @note Do not use this for data that can be accessed by attackers! */
0141 KDB_EXPORT void simpleCrypt(QString *string);
0142 
0143 /*! Performs a simple @a string decryption using rot47-like algorithm,
0144  using opposite operations to KexiUtils::simpleCrypt().
0145  @return true on success and false on failure. Failue means that one or more characters have unicode
0146  numbers smaller than value of 47 + i. On failure @a string is not altered.
0147  Does nothing and returns @c false if @a string is @c nullptr.
0148 */
0149 KDB_EXPORT bool simpleDecrypt(QString *string);
0150 
0151 //! @internal
0152 KDB_EXPORT QString pointerToStringInternal(void* pointer, int size);
0153 //! @internal
0154 KDB_EXPORT void* stringToPointerInternal(const QString& string, int size);
0155 
0156 //! @return a pointer @a pointer safely serialized to string
0157 template<class type>
0158 QString pointerToString(type *pointer)
0159 {
0160     return pointerToStringInternal(pointer, sizeof(type*));
0161 }
0162 
0163 //! @return a pointer of type @a type safely deserialized from @a string
0164 template<class type>
0165 type* stringToPointer(const QString& string)
0166 {
0167     return static_cast<type*>(stringToPointerInternal(string, sizeof(type*)));
0168 }
0169 
0170 //! @return value converted to text, squeezed to reasonable length, useful for debugging
0171 //! If the value is not a byte array or string, or if it's not longer than 1024 characters,
0172 //! @a value is returned.
0173 //! @since 3.1
0174 KDB_EXPORT QVariant squeezedValue(const QVariant &value);
0175 
0176 //! @short Autodeleting hash
0177 template <class Key, class T>
0178 class AutodeletedHash : public QHash<Key, T>
0179 {
0180 public:
0181     //! Creates autodeleting hash as a copy of @a other.
0182     //! Auto-deletion is not enabled as it would cause double deletion for items.
0183     //! If you enable auto-deletion on here, make sure you disable it in the @a other hash.
0184     AutodeletedHash(const AutodeletedHash& other) : QHash<Key, T>(other), m_autoDelete(false) {}
0185 
0186     //! Creates empty autodeleting hash.
0187     //! Auto-deletion is enabled by default.
0188     AutodeletedHash(bool autoDelete = true) : QHash<Key, T>(), m_autoDelete(autoDelete) {}
0189 
0190     ~AutodeletedHash() {
0191         if (m_autoDelete) {
0192             qDeleteAll(*this);
0193         }
0194     }
0195     void setAutoDelete(bool set) {
0196         m_autoDelete = set;
0197     }
0198     bool autoDelete() const {
0199         return m_autoDelete;
0200     }
0201     void clear() {
0202         if (m_autoDelete) {
0203             qDeleteAll(*this);
0204         }
0205         QHash<Key, T>::clear();
0206     }
0207     typename QHash<Key, T>::iterator erase(typename QHash<Key, T>::iterator pos) {
0208         typename QHash<Key, T>::iterator it = QHash<Key, T>::erase(pos);
0209         if (m_autoDelete) {
0210             delete it.value();
0211             it.value() = 0;
0212             return it;
0213         }
0214     }
0215     typename QHash<Key, T>::iterator insert(const Key &key, const T &value) {
0216         if (m_autoDelete) {
0217             T &oldValue = QHash<Key, T>::operator[](key);
0218             if (oldValue && oldValue != value) { // only delete if differs
0219                 delete oldValue;
0220             }
0221         }
0222         return QHash<Key, T>::insert(key, value);
0223     }
0224     int remove(const Key &key) {
0225         if (m_autoDelete) {
0226             const QList<T> values(QHash<Key, T>::values(key));
0227             const int result = QHash<Key, T>::remove(key);
0228             for (T item : values) {
0229                 delete item;
0230             }
0231             return result;
0232         } else {
0233             return QHash<Key, T>::remove(key);
0234         }
0235     }
0236     // note: no need to override insertMulti(), unite(), take(), they do not replace items
0237 
0238 private:
0239     bool m_autoDelete;
0240 };
0241 
0242 //! @short Autodeleting list
0243 template <typename T>
0244 class AutodeletedList : public QList<T>
0245 {
0246 public:
0247     //! Creates autodeleting list as a copy of @a other.
0248     //! Auto-deletion is not enabled as it would cause double deletion for items.
0249     //! If you enable auto-deletion on here, make sure you disable it in the @a other list.
0250     AutodeletedList(const AutodeletedList& other)
0251             : QList<T>(other), m_autoDelete(false) {}
0252 
0253     //! Creates empty autodeleting list.
0254     //! Auto-deletion is enabled by default.
0255     AutodeletedList(bool autoDelete = true) : QList<T>(), m_autoDelete(autoDelete) {}
0256 
0257     ~AutodeletedList() {
0258         if (m_autoDelete) qDeleteAll(*this);
0259     }
0260     void setAutoDelete(bool set) {
0261         m_autoDelete = set;
0262     }
0263     bool autoDelete() const {
0264         return m_autoDelete;
0265     }
0266     void removeAt(int i) {
0267         T item = QList<T>::takeAt(i); if (m_autoDelete) delete item;
0268     }
0269     void removeFirst() {
0270         T item = QList<T>::takeFirst(); if (m_autoDelete) delete item;
0271     }
0272     void removeLast() {
0273         T item = QList<T>::takeLast(); if (m_autoDelete) delete item;
0274     }
0275     void replace(int i, const T& value) {
0276         T item = QList<T>::takeAt(i); insert(i, value); if (m_autoDelete) delete item;
0277     }
0278     void insert(int i, const T& value) {
0279         QList<T>::insert(i, value);
0280     }
0281     typename QList<T>::iterator erase(typename QList<T>::iterator pos) {
0282         T item = *pos;
0283         typename QList<T>::iterator res = QList<T>::erase(pos);
0284         if (m_autoDelete)
0285             delete item;
0286         return res;
0287     }
0288     typename QList<T>::iterator erase(
0289         typename QList<T>::iterator afirst,
0290         typename QList<T>::iterator alast) {
0291         if (!m_autoDelete)
0292             return QList<T>::erase(afirst, alast);
0293         while (afirst != alast) {
0294             T item = *afirst;
0295             afirst = QList<T>::erase(afirst);
0296             delete item;
0297         }
0298         return alast;
0299     }
0300     void pop_back() {
0301         removeLast();
0302     }
0303     void pop_front() {
0304         removeFirst();
0305     }
0306     int removeAll(const T& value) {
0307         if (!m_autoDelete)
0308             return QList<T>::removeAll(value);
0309         typename QList<T>::iterator it(QList<T>::begin());
0310         int removedCount = 0;
0311         while (it != QList<T>::end()) {
0312             if (*it == value) {
0313                 T item = *it;
0314                 it = QList<T>::erase(it);
0315                 delete item;
0316                 removedCount++;
0317             } else
0318                 ++it;
0319         }
0320         return removedCount;
0321     }
0322     void clear() {
0323         if (!m_autoDelete)
0324             return QList<T>::clear();
0325         while (!QList<T>::isEmpty()) {
0326             T item = QList<T>::takeFirst();
0327             delete item;
0328         }
0329     }
0330 
0331 private:
0332     bool m_autoDelete;
0333 };
0334 
0335 //! @short Case insensitive hash container supporting QString or QByteArray keys.
0336 //! Keys are turned to lowercase before inserting.
0337 template <typename Key, typename T>
0338 class CaseInsensitiveHash : public QHash<Key, T>
0339 {
0340 public:
0341     CaseInsensitiveHash() : QHash<Key, T>() {}
0342     typename QHash<Key, T>::iterator find(const Key& key) const {
0343         return QHash<Key, T>::find(key.toLower());
0344     }
0345     typename QHash<Key, T>::const_iterator constFind(const Key& key) const {
0346         return QHash<Key, T>::constFind(key.toLower());
0347     }
0348     bool contains(const Key& key) const {
0349         return QHash<Key, T>::contains(key.toLower());
0350     }
0351     int count(const Key& key) const {
0352         return QHash<Key, T>::count(key.toLower());
0353     }
0354     typename QHash<Key, T>::iterator insert(const Key& key, const T& value) {
0355         return QHash<Key, T>::insert(key.toLower(), value);
0356     }
0357     typename QHash<Key, T>::iterator insertMulti(const Key& key, const T& value) {
0358         return QHash<Key, T>::insertMulti(key.toLower(), value);
0359     }
0360     const Key key(const T& value, const Key& defaultKey) const {
0361         return QHash<Key, T>::key(value, defaultKey.toLower());
0362     }
0363     int remove(const Key& key) {
0364         return QHash<Key, T>::remove(key.toLower());
0365     }
0366     const T take(const Key& key) {
0367         return QHash<Key, T>::take(key.toLower());
0368     }
0369     const T value(const Key& key) const {
0370         return QHash<Key, T>::value(key.toLower());
0371     }
0372     const T value(const Key& key, const T& defaultValue) const {
0373         return QHash<Key, T>::value(key.toLower(), defaultValue);
0374     }
0375     QList<T> values(const Key& key) const {
0376         return QHash<Key, T>::values(key.toLower());
0377     }
0378     T& operator[](const Key& key) {
0379         return QHash<Key, T>::operator[](key.toLower());
0380     }
0381     const T operator[](const Key& key) const {
0382         return QHash<Key, T>::operator[](key.toLower());
0383     }
0384 };
0385 
0386 //! A set created from static (0-terminated) array of raw null-terminated strings.
0387 class KDB_EXPORT StaticSetOfStrings
0388 {
0389 public:
0390     StaticSetOfStrings();
0391     explicit StaticSetOfStrings(const char* const array[]);
0392     ~StaticSetOfStrings();
0393     void setStrings(const char* const array[]);
0394     bool isEmpty() const;
0395 
0396     //! @return true if @a string can be found within set, comparison is case sensitive
0397     bool contains(const QByteArray& string) const;
0398 private:
0399     class Private;
0400     Private * const d;
0401     Q_DISABLE_COPY(StaticSetOfStrings)
0402 };
0403 
0404 /*! @return debugging string for object @a object of type @a T */
0405 template <typename T>
0406 QString debugString(const T& object)
0407 {
0408     QString result;
0409     QDebug dbg(&result);
0410     dbg << object;
0411     return result;
0412 }
0413 
0414 //! Used by findExe().
0415 enum class FindExeOption {
0416     //! No options
0417     None = 0,
0418     //! If set, the path returned may not have the executable bit set.
0419     IgnoreExecBit = 1
0420 };
0421 Q_DECLARE_FLAGS(FindExeOptions, FindExeOption)
0422 
0423 /**
0424  * Finds the executable in the system path.
0425  *
0426  * A valid executable must be a file and have its executable bit set.
0427  *
0428  * @param appname The name of the executable file for which to search.
0429  *                if this contains a path separator, it will be resolved
0430  *                according to the current working directory
0431  *                (shell-like behavior).
0432  * @param path    The path which will be searched. If this is
0433  *                null (default), the @c $PATH environment variable will
0434  *                be searched.
0435  * @param options Options, see FindExeOption.
0436  *
0437  * @return The path of the executable. If it was not found, returns QString().
0438  */
0439 QString findExe(const QString& appname,
0440                 const QString& path = QString(),
0441                 FindExeOptions options = FindExeOption::None);
0442 
0443 //! A single property
0444 //! @note This property is general-purpose and not related to Qt Properties.
0445 //! @see KDbUtils::PropertySet
0446 class KDB_EXPORT Property {
0447 public:
0448     //! Constructs a null property
0449     Property();
0450 
0451     Property(const QVariant &aValue, const QString &aCaption);
0452 
0453     Property(const Property &other);
0454 
0455     ~Property();
0456 
0457     bool operator==(const Property &other) const;
0458 
0459     bool operator!=(const Property &other) const { return !operator==(other); }
0460 
0461     bool isNull() const;
0462 
0463     QVariant value() const;
0464 
0465     void setValue(const QVariant &value);
0466 
0467     QString caption() const;
0468 
0469     void setCaption(const QString &caption);
0470 
0471 private:
0472     class Private;
0473     Private * const d;
0474 };
0475 
0476 //! A set of properties.
0477 //! @note These properties are general-purpose and not related to Qt Properties.
0478 //! @see KDbUtils::Property
0479 class KDB_EXPORT PropertySet
0480 {
0481 public:
0482     PropertySet();
0483 
0484     PropertySet(const PropertySet &other);
0485 
0486     ~PropertySet();
0487 
0488     //! Assigns @a other to this property set and returns a reference to this property set.
0489     PropertySet& operator=(const PropertySet &other);
0490 
0491     //! @return true if this property set has exactly the same properties as @a other
0492     //! @since 3.1
0493     bool operator==(const PropertySet &other) const;
0494 
0495     //! @return true if this property differs in at least one property from @a other
0496     //! @since 3.1
0497     bool operator!=(const PropertySet &other) const { return !operator==(other); }
0498 
0499     //! Inserts property with a given @a name, @a value and @a caption.
0500     //! If @a caption is empty, caption from existing property is reused.
0501     //! @a name must be a valid identifier (see KDb::isIdentifier()).
0502     void insert(const QByteArray &name, const QVariant &value, const QString &caption = QString());
0503 
0504     //! Sets caption for property @a name to @a caption.
0505     //! If such property does not exist, does nothing.
0506     //! @since 3.1
0507     void setCaption(const QByteArray &name, const QString &caption);
0508 
0509     //! Sets value for property @a name to @a value.
0510     //! If such property does not exist, does nothing.
0511     //! @since 3.1
0512     void setValue(const QByteArray &name, const QVariant &value);
0513 
0514     //! Removes property with a given @a name.
0515     void remove(const QByteArray &name);
0516 
0517     //! @return property with a given @a name.
0518     //! If not found, a null Property is returned (Property::isNull).
0519     Property property(const QByteArray &name) const;
0520 
0521     //! @return a list of property names.
0522     QList<QByteArray> names() const;
0523 
0524 private:
0525     class Private;
0526     Private * const d;
0527 };
0528 
0529 } // KDbUtils
0530 
0531 #endif //KDB_TOOLS_UTILS_H