File indexing completed on 2025-03-09 03:58:42
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2009-08-01 0007 * Description : camera name helper class 0008 * 0009 * SPDX-FileCopyrightText: 2009-2012 by Andi Clemens <andi dot clemens at gmail dot com> 0010 * 0011 * SPDX-License-Identifier: GPL-2.0-or-later 0012 * 0013 * ============================================================ */ 0014 0015 #include "cameranamehelper.h" 0016 0017 // Qt includes 0018 0019 #include <QRegularExpression> 0020 0021 // KDE includes 0022 0023 #include <klocalizedstring.h> 0024 0025 namespace 0026 { 0027 static const KLocalizedString STR_AUTO_DETECTED(ki18nc("in camera model string", "auto-detected")); 0028 0029 /* 0030 * The constructors used here are written after many experiments. 0031 * REGEXP_MODES expression was failing to give exact match results if the pattern option 0032 * InvertedGreedinessOption was set later in extractCameraNameToken function with QRegularExpression::setPatternOption() 0033 * Maybe a bug in Qt. 0034 * */ 0035 static QRegularExpression REGEXP_CAMERA_NAME( 0036 QRegularExpression::anchoredPattern(QLatin1String("(.*)\\s*\\((.*)\\)\\s*")), 0037 QRegularExpression::InvertedGreedinessOption | QRegularExpression::CaseInsensitiveOption); 0038 0039 static QRegularExpression REGEXP_MODES( 0040 QRegularExpression::anchoredPattern(QLatin1String("(ptp|normal|mtp)(\\s+mode)?")), 0041 QRegularExpression::InvertedGreedinessOption | QRegularExpression::CaseInsensitiveOption); 0042 } 0043 0044 namespace Digikam 0045 { 0046 0047 QString CameraNameHelper::createCameraName(const QString& vendor, const QString& product, 0048 const QString& mode, bool autoDetected) 0049 { 0050 if (vendor.isEmpty()) 0051 { 0052 return QString(); 0053 } 0054 0055 QString tmp; 0056 QString _vendor = vendor.simplified(); 0057 QString _product = product.simplified(); 0058 QString _mode = mode.simplified().remove(QLatin1Char('(')).remove(QLatin1Char(')')); 0059 tmp = QString::fromUtf8("%1 %2").arg(_vendor).arg(_product); 0060 0061 if (!mode.isEmpty() && mode != STR_AUTO_DETECTED.toString()) 0062 { 0063 tmp.append(QLatin1String(" (")); 0064 tmp.append(_mode); 0065 tmp.append(autoDetected ? QString::fromUtf8(", %1)").arg(STR_AUTO_DETECTED.toString()) 0066 : QLatin1String(")")); 0067 } 0068 else if (autoDetected) 0069 { 0070 tmp.append(QString::fromUtf8(" (%1)").arg(STR_AUTO_DETECTED.toString())); 0071 } 0072 0073 return tmp.simplified(); 0074 } 0075 0076 QString CameraNameHelper::cameraName(const QString& name) 0077 { 0078 return parseAndFormatCameraName(name, false, false); 0079 } 0080 0081 QString CameraNameHelper::cameraNameAutoDetected(const QString& name) 0082 { 0083 return parseAndFormatCameraName(name, true, true); 0084 } 0085 0086 QString CameraNameHelper::parseAndFormatCameraName(const QString& cameraName, 0087 bool parseMode, bool autoDetected) 0088 { 0089 QString vendorAndProduct = extractCameraNameToken(cameraName, VendorAndProduct); 0090 0091 if (vendorAndProduct.isEmpty()) 0092 { 0093 return QString(); 0094 } 0095 0096 QString mode = parseMode ? extractCameraNameToken(cameraName, Mode) 0097 : QString(); 0098 0099 QString tmp = createCameraName(vendorAndProduct, QString(), mode, autoDetected); 0100 0101 return (tmp.isEmpty() ? cameraName.simplified() 0102 : tmp); 0103 } 0104 0105 QString CameraNameHelper::extractCameraNameToken(const QString& cameraName, Token tokenID) 0106 { 0107 static QRegularExpression REGEXP_AUTODETECTED(QString::fromUtf8("(%1|, %1)").arg(STR_AUTO_DETECTED.toString())); 0108 REGEXP_AUTODETECTED.setPatternOptions(QRegularExpression::InvertedGreedinessOption); 0109 0110 QRegularExpressionMatch expMatch = REGEXP_CAMERA_NAME.match(cameraName.simplified()); 0111 0112 if (expMatch.hasMatch()) 0113 { 0114 QString vendorProduct = expMatch.captured(1).simplified(); 0115 QString tmpMode = expMatch.captured(2).simplified(); 0116 QString clearedTmpMode = tmpMode; 0117 QString mode; 0118 clearedTmpMode.remove(REGEXP_AUTODETECTED); 0119 0120 if (!tmpMode.isEmpty() && clearedTmpMode.isEmpty()) 0121 { 0122 mode = tmpMode; 0123 } 0124 else 0125 { 0126 mode = REGEXP_MODES.match(clearedTmpMode).hasMatch() ? clearedTmpMode 0127 : QLatin1String(""); 0128 } 0129 0130 if (tokenID == VendorAndProduct) 0131 { 0132 return (mode.isEmpty() ? cameraName.simplified() 0133 : vendorProduct); 0134 } 0135 else 0136 { 0137 return mode; 0138 } 0139 } 0140 return ((tokenID == VendorAndProduct) ? cameraName.simplified() 0141 : QLatin1String("")); 0142 } 0143 0144 bool CameraNameHelper::sameDevices(const QString& deviceA, const QString& deviceB) 0145 { 0146 if (deviceA.isEmpty() || deviceB.isEmpty()) 0147 { 0148 return false; 0149 } 0150 0151 if (deviceA == deviceB) 0152 { 0153 return true; 0154 } 0155 0156 // We need to parse the names a little bit. First check if the vendor and name match 0157 0158 QString vendorAndProductA = extractCameraNameToken(deviceA, VendorAndProduct); 0159 QString vendorAndProductB = extractCameraNameToken(deviceB, VendorAndProduct); 0160 QString cameraNameA = createCameraName(vendorAndProductA); 0161 QString cameraNameB = createCameraName(vendorAndProductB); 0162 0163 // try to clean up the string, if not possible, return false 0164 0165 if (cameraNameA != cameraNameB) 0166 { 0167 return false; 0168 } 0169 0170 // is the extracted mode known and equal? 0171 0172 QString modeA = extractCameraNameToken(deviceA, Mode); 0173 QString modeB = extractCameraNameToken(deviceB, Mode); 0174 QRegularExpressionMatch match = REGEXP_MODES.match(modeA); 0175 bool isModeAValid = match.hasMatch(); 0176 modeA = isModeAValid ? match.captured(1).simplified().toLower() : QLatin1String(""); 0177 match = REGEXP_MODES.match(modeB); 0178 bool isModeBValid = match.hasMatch(); 0179 modeB = isModeBValid ? match.captured(1).simplified().toLower() : QLatin1String(""); 0180 0181 if ((isModeAValid != isModeBValid) || (modeA != modeB)) 0182 { 0183 return false; 0184 } 0185 0186 return true; 0187 } 0188 0189 } // namespace Digikam