/* Copyright (C) 2013 VATSIM Community / contributors * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "blackmiscfreefunctions.h" #include "avallclasses.h" #include "pqallquantities.h" #include "mathallclasses.h" #include "geoallclasses.h" #include "networkallclasses.h" #include "settingsallclasses.h" #include "valuemap.h" #include "statusmessagelist.h" #include "voiceallclasses.h" /* * Metadata for PQs */ void BlackMisc::PhysicalQuantities::registerMetadata() { CMeasurementUnit::registerMetadata(); CAcceleration::registerMetadata(); CAngle::registerMetadata(); CFrequency::registerMetadata(); CLength::registerMetadata(); CMass::registerMetadata(); CPressure::registerMetadata(); CSpeed::registerMetadata(); CTemperature::registerMetadata(); CTime::registerMetadata(); } /* * Metadata for aviation */ void BlackMisc::Aviation::registerMetadata() { CComSystem::registerMetadata(); CNavSystem::registerMetadata(); CAdfSystem::registerMetadata(); CAltitude::registerMetadata(); CTransponder::registerMetadata(); CHeading::registerMetadata(); CTrack::registerMetadata(); CCallsign::registerMetadata(); CCallsignList::registerMetadata(); CAtcStation::registerMetadata(); CInformationMessage::registerMetadata(); CAtcStationList::registerMetadata(); CAircraft::registerMetadata(); CAircraftList::registerMetadata(); CAircraftSituation::registerMetadata(); CAircraftIcao::registerMetadata(); } /* * Metadata for Math */ void BlackMisc::Math::registerMetadata() { CMatrix3x3::registerMetadata(); CMatrix3x1::registerMetadata(); CMatrix1x3::registerMetadata(); CVector3D::registerMetadata(); } /* * Metadata for Geo */ void BlackMisc::Geo::registerMetadata() { CCoordinateEcef::registerMetadata(); CCoordinateNed::registerMetadata(); CCoordinateGeodetic::registerMetadata(); CLatitude::registerMetadata(); CLongitude::registerMetadata(); } /* * Metadata for Network */ void BlackMisc::Network::registerMetadata() { CUser::registerMetadata(); CUserList::registerMetadata(); CServer::registerMetadata(); CServerList::registerMetadata(); CTextMessage::registerMetadata(); CTextMessageList::registerMetadata(); } /* * Metadata for Settings */ void BlackMisc::Settings::registerMetadata() { CSettingsNetwork::registerMetadata(); } /* * Metadata for Voice */ void BlackMisc::Voice::registerMetadata() { CAudioDevice::registerMetadata(); CAudioDeviceList::registerMetadata(); CVoiceRoom::registerMetadata(); CVoiceRoomList::registerMetadata(); } /* * Metadata for Blackmisc */ void BlackMisc::registerMetadata() { // !! make sure the first id is correctly returned by // !! firstBlackMetaType CValueMap::registerMetadata(); CStatusMessage::registerMetadata(); CStatusMessageList::registerMetadata(); // sub namespaces PhysicalQuantities::registerMetadata(); Aviation::registerMetadata(); Math::registerMetadata(); Geo::registerMetadata(); Network::registerMetadata(); Settings::registerMetadata(); Voice::registerMetadata(); } /* * First of our ids */ int BlackMisc::firstBlackMetaType() { // must be the first registered above return qMetaTypeId(); } /* * Init resources */ void BlackMisc::initResources() { initBlackMiscResources(); } /* * Stupid extension bo be able to compare 2 QVariants */ bool BlackMisc::equalQVariants(const QVariant &v1, const QVariant &v2) { // prephase, shortcuts if (v1 == v2) return true; // compares on primitives or on address if (!v1.isValid() || !v2.isValid()) return false; if (v1.type() != v2.type()) return false; if (v1.userType() != v2.userType()) return false; // I have same types now const CValueObject *cs1 = CValueObject::fromQVariant(v1); const CValueObject *cs2 = CValueObject::fromQVariant(v2); if (cs1 && cs2) { uint h1 = cs1->getValueHash(); uint h2 = cs2->getValueHash(); return h1 == h2; } return false; } /* * Compare values */ int BlackMisc:: compareQVariants(const QVariant &v1, const QVariant &v2) { if (v1 == v2) return 0; // compares on primitives or on address if (!v1.isValid() || !v2.isValid()) qFatal("Invalid variants"); if (v1.type() != v2.type()) qFatal("Mismatching types"); if (v1.userType() != v2.userType()) qFatal("Mismatching user types"); switch (v1.type()) { case QMetaType::QString: { QString s1 = v1.value(); QString s2 = v2.value(); return s1.compare(s2); } case QMetaType::QDateTime: { QDateTime dt1 = v1.value(); QDateTime dt2 = v2.value(); if (dt1 == dt2) return 0; return dt1 < dt2 ? -1 : 1; } case QMetaType::QDate: { QDate d1 = v1.value(); QDate d2 = v2.value(); if (d1 == d2) return 0; return d1 < d2 ? -1 : 1; } case QMetaType::QTime: { QTime t1 = v1.value(); QTime t2 = v2.value(); if (t1 == t2) return 0; return t1 < t2 ? -1 : 1; } default: break; } // BlackObject if (v1.type() == QVariant::UserType) { const CValueObject *cs1 = CValueObject::fromQVariant(v1); const CValueObject *cs2 = CValueObject::fromQVariant(v2); if (cs1 && cs2) { return compare(*cs1, *cs2); } } // all kind of numeric values if (v1.canConvert()) { double d1 = v1.value(); double d2 = v2.value(); if (d1 == d2) return 0; return d1 < d2 ? -1 : 1; } qFatal("Unknown type for compare"); return -1; } /* * To string */ QString BlackMisc::qVariantToString(const QVariant &qv, bool i18n) { if (qv.type() != QVariant::UserType) return qv.toString(); const CValueObject *s = CValueObject::fromQVariant(qv); if (s) { return s->toQString(i18n); } else { return "unknown"; } } /* * Add hash values */ uint BlackMisc::calculateHash(const QList &values, const char *className) { // http://stackoverflow.com/questions/113511/hash-code-implementation/113600#113600 if (values.isEmpty()) return 0; uint hash = values.first(); for (int i = 1; i < values.size(); i++) { hash = 37 * hash + values.at(i); } // same values, but different class? if (className) { hash = 37 * hash + qHash(QString(className)); } return hash; } /* * Fix QVariant if it comes from DBus and contains QDBusArgument */ QVariant BlackMisc::fixQVariantFromDbusArgument(const QVariant &variant, int localUserType) { if (variant.canConvert()) { // complex, user type // it has to be made sure, that the cast works const QDBusArgument arg = variant.value(); QVariant fixedVariant; if (localUserType < static_cast(QVariant::UserType)) { // complex Qt type, e.g. QDateTime fixedVariant = BlackMisc::complexQtTypeFromDbusArgument(arg, localUserType); } else { // http://qt-project.org/doc/qt-5.0/qtcore/qmetatype.html#create void *obByMetaId = QMetaType::create(localUserType); // own types, send as QDBusArgument CValueObject *streamable = static_cast(obByMetaId); arg >> (*streamable); fixedVariant = streamable->toQVariant(); QMetaType::destroy(localUserType, obByMetaId); } return fixedVariant; } else { return variant; } } /* * Return QVariant based on QDBusArgument */ QVariant BlackMisc::complexQtTypeFromDbusArgument(const QDBusArgument &argument, int type) { // QDate = 14, QTime = 15, QDateTime = 16, QUrl = 17, switch (type) { case QMetaType::QDateTime: { QDateTime dt; argument >> dt; return QVariant::fromValue(dt); } case QMetaType::QDate: { QDate date; argument >> date; return QVariant::fromValue(date); } case QMetaType::QTime: { QTime time; argument >> time; return QVariant::fromValue(time); } default: qFatal("Type cannot be resolved"); } return QVariant(); // suppress compiler warning } #ifdef Q_CC_MSVC #include /* * Heap size of an object */ size_t BlackMisc::heapSizeOf(const QMetaType &metaType) { metaType.destroy(metaType.create()); // ignore one-off allocations of a class being instantiated for the first time _CrtMemState oldState, newState, diff; oldState.lTotalCount = newState.lTotalCount = diff.lTotalCount = 0; // avoid compiler warning diff.lSizes[_NORMAL_BLOCK] = 0; _CrtMemCheckpoint(&oldState); void *p = metaType.create(); _CrtMemCheckpoint(&newState); metaType.destroy(p); _CrtMemDifference(&diff, &oldState, &newState); return diff.lSizes[_NORMAL_BLOCK]; } /* * Heap size of an object */ size_t BlackMisc::heapSizeOf(const QMetaObject &metaObject) { delete metaObject.newInstance(); //ignore one-off allocations of a class being instantiated for the first time _CrtMemState oldState, newState, diff; oldState.lTotalCount = newState.lTotalCount = diff.lTotalCount = 0; // avoid compiler warning diff.lSizes[_NORMAL_BLOCK] = 0; _CrtMemCheckpoint(&oldState); QObject *obj = metaObject.newInstance(); _CrtMemCheckpoint(&newState); delete obj; _CrtMemDifference(&diff, &oldState, &newState); return diff.lSizes[_NORMAL_BLOCK]; } #else //!Q_CC_MSVC /* * Heap size of an object */ size_t BlackMisc::heapSizeOf(const QMetaType &) { qDebug() << "heapSizeOf not supported by your compiler toolchain"; return 0; } /* * Heap size of an object */ size_t BlackMisc::heapSizeOf(const QMetaObject &) { qDebug() << "heapSizeOf not supported by your compiler toolchain"; return 0; } #endif //!Q_CC_MSVC /* * Dump all user types */ void BlackMisc::displayAllUserMetatypesTypes() { for (int mt = QMetaType::User; mt < QMetaType::User + 1000; mt++) { if (!QMetaType::isRegistered(mt)) continue; QMetaType metaType(mt); qDebug() << "type:" << mt << "name:" << QMetaType::typeName(mt) << QMetaType::sizeOf(mt) << BlackMisc::heapSizeOf(metaType); } }