File indexing completed on 2025-01-19 03:59:41
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2003-02-03 0007 * Description : Cameras list container 0008 * 0009 * SPDX-FileCopyrightText: 2003-2005 by Renchi Raju <renchi dot raju at gmail dot com> 0010 * SPDX-FileCopyrightText: 2006-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0011 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 #include "cameralist.h" 0017 0018 // Qt includes 0019 0020 #include <QDateTime> 0021 #include <QDomDocument> 0022 #include <QDomElement> 0023 #include <QFile> 0024 #include <QString> 0025 #include <QTextStream> 0026 #include <QApplication> 0027 #include <QMessageBox> 0028 0029 #if QT_VERSION < QT_VERSION_CHECK(6,0,0) 0030 # include <QTextCodec> 0031 #endif 0032 0033 // KDE includes 0034 0035 #include <klocalizedstring.h> 0036 0037 // Local includes 0038 0039 #include "cameratype.h" 0040 #include "gpcamera.h" 0041 #include "digikam_debug.h" 0042 0043 namespace Digikam 0044 { 0045 0046 CameraList* CameraList::m_defaultList = nullptr; 0047 0048 CameraList* CameraList::defaultList() 0049 { 0050 return m_defaultList; 0051 } 0052 0053 class Q_DECL_HIDDEN CameraList::Private 0054 { 0055 public: 0056 0057 explicit Private() 0058 : modified(false) 0059 { 0060 } 0061 0062 bool modified; 0063 0064 QList<CameraType*> clist; 0065 QString file; 0066 }; 0067 0068 CameraList::CameraList(QObject* const parent, const QString& file) 0069 : QObject(parent), 0070 d (new Private) 0071 { 0072 d->file = file; 0073 qCDebug(DIGIKAM_GENERAL_LOG) << "Camera XML data: " << d->file; 0074 0075 if (!m_defaultList) 0076 { 0077 m_defaultList = this; 0078 } 0079 } 0080 0081 CameraList::~CameraList() 0082 { 0083 save(); 0084 clear(); 0085 delete d; 0086 0087 if (m_defaultList == this) 0088 { 0089 m_defaultList = nullptr; 0090 } 0091 } 0092 0093 bool CameraList::load() 0094 { 0095 d->modified = false; 0096 0097 QFile cfile(d->file); 0098 0099 if (!cfile.open(QIODevice::ReadOnly)) 0100 { 0101 return false; 0102 } 0103 0104 QDomDocument doc(QLatin1String("cameralist")); 0105 0106 if (!doc.setContent(&cfile)) 0107 { 0108 cfile.close(); 0109 0110 return false; 0111 } 0112 0113 QDomElement docElem = doc.documentElement(); 0114 0115 if (docElem.tagName() != QLatin1String("cameralist")) 0116 { 0117 cfile.close(); 0118 0119 return false; 0120 } 0121 0122 for (QDomNode n = docElem.firstChild() ; !n.isNull() ; n = n.nextSibling()) 0123 { 0124 QDomElement e = n.toElement(); 0125 0126 if (e.isNull()) 0127 { 0128 continue; 0129 } 0130 0131 if (e.tagName() != QLatin1String("item")) 0132 { 0133 continue; 0134 } 0135 0136 QString title = e.attribute(QLatin1String("title")); 0137 QString model = e.attribute(QLatin1String("model")); 0138 QString port = e.attribute(QLatin1String("port")); 0139 QString path = e.attribute(QLatin1String("path")); 0140 int sn = e.attribute(QLatin1String("startingnumber")).toInt(); 0141 CameraType* const ctype = new CameraType(title, model, port, path, sn); 0142 insertPrivate(ctype); 0143 } 0144 0145 cfile.close(); 0146 0147 return true; 0148 } 0149 0150 bool CameraList::save() 0151 { 0152 // If not modified don't save the file 0153 0154 if (!d->modified) 0155 { 0156 return true; 0157 } 0158 0159 QDomDocument doc(QLatin1String("cameralist")); 0160 doc.setContent(QLatin1String("<!DOCTYPE XMLCameraList><cameralist version=\"1.2\" client=\"digikam\"/>")); 0161 0162 QDomElement docElem = doc.documentElement(); 0163 0164 Q_FOREACH (CameraType* const ctype, d->clist) 0165 { 0166 QDomElement elem = doc.createElement(QLatin1String("item")); 0167 elem.setAttribute(QLatin1String("title"), ctype->title()); 0168 elem.setAttribute(QLatin1String("model"), ctype->model()); 0169 elem.setAttribute(QLatin1String("port"), ctype->port()); 0170 elem.setAttribute(QLatin1String("path"), ctype->path()); 0171 elem.setAttribute(QLatin1String("startingnumber"), QString::number(ctype->startingNumber())); 0172 docElem.appendChild(elem); 0173 } 0174 0175 QFile cfile(d->file); 0176 0177 if (!cfile.open(QIODevice::WriteOnly)) 0178 { 0179 qCDebug(DIGIKAM_GENERAL_LOG) << "Cannot open Camera XML file to save data (" << d->file << ")"; 0180 return false; 0181 } 0182 0183 QTextStream stream(&cfile); 0184 0185 #if QT_VERSION < QT_VERSION_CHECK(6,0,0) 0186 0187 // In Qt5 only. Qt6 uses UTF-8 by default. 0188 0189 stream.setCodec(QTextCodec::codecForName("UTF-8")); 0190 0191 #endif 0192 0193 stream.setAutoDetectUnicode(true); 0194 stream << doc.toString(); 0195 cfile.close(); 0196 0197 d->modified = false; 0198 0199 return true; 0200 } 0201 0202 void CameraList::insert(CameraType* const ctype) 0203 { 0204 if (!ctype) 0205 { 0206 return; 0207 } 0208 0209 d->modified = true; 0210 insertPrivate(ctype); 0211 } 0212 0213 void CameraList::remove(CameraType* const ctype) 0214 { 0215 if (!ctype) 0216 { 0217 return; 0218 } 0219 0220 d->modified = true; 0221 removePrivate(ctype); 0222 } 0223 0224 void CameraList::insertPrivate(CameraType* const ctype) 0225 { 0226 if (!ctype) 0227 { 0228 return; 0229 } 0230 0231 d->clist.append(ctype); 0232 0233 Q_EMIT signalCameraAdded(ctype); 0234 } 0235 0236 void CameraList::removePrivate(CameraType* const ctype) 0237 { 0238 if (!ctype) 0239 { 0240 return; 0241 } 0242 0243 Q_EMIT signalCameraRemoved(ctype->action()); 0244 0245 int i = d->clist.indexOf(ctype); 0246 0247 if (i != -1) 0248 { 0249 delete d->clist.takeAt(i); 0250 } 0251 } 0252 0253 void CameraList::clear() 0254 { 0255 while (!d->clist.isEmpty()) 0256 { 0257 d->modified = true; 0258 removePrivate(d->clist.first()); 0259 } 0260 } 0261 0262 QList<CameraType*>* CameraList::cameraList() const 0263 { 0264 return &d->clist; 0265 } 0266 0267 CameraType* CameraList::find(const QString& title) const 0268 { 0269 Q_FOREACH (CameraType* const ctype, d->clist) 0270 { 0271 if (ctype->title() == title) 0272 { // cppcheck-suppress useStlAlgorithm 0273 return ctype; 0274 } 0275 } 0276 0277 return nullptr; 0278 } 0279 0280 CameraType* CameraList::autoDetect(bool& retry) 0281 { 0282 retry = false; 0283 0284 QString model, port; 0285 0286 if (GPCamera::autoDetect(model, port) != 0) 0287 { 0288 retry = (QMessageBox::warning(qApp->activeWindow(), qApp->applicationName(), 0289 i18n("Failed to auto-detect camera; " 0290 "please make sure it is connected " 0291 "properly and is turned on. " 0292 "Would you like to try again?"), 0293 QMessageBox::Yes | QMessageBox::No) 0294 == QMessageBox::Yes); 0295 0296 return nullptr; 0297 } 0298 0299 // Check if the camera is already in the list 0300 0301 Q_FOREACH (CameraType* const ctype, d->clist) 0302 { 0303 // We can get away with checking only the model, as the auto-detection 0304 // works only for usb cameras. so the port is always usb: 0305 0306 if (ctype->model() == model) 0307 { // cppcheck-suppress useStlAlgorithm 0308 return ctype; 0309 } 0310 } 0311 0312 // Looks like a new camera 0313 0314 // NOTE: libgphoto2 now (2.1.4+) expects port names to be 0315 // something like "usb:001,012". but on linux these port numbers 0316 // will change every time camera is reconnected. gphoto port funcs 0317 // also allow regexp match, so the safe bet is to just pass in 0318 // "usb:" and cross your fingers that user doesn't have multiple cameras 0319 // connected at the same time (whack them if they do). 0320 0321 if (port.startsWith(QLatin1String("usb:"))) 0322 { 0323 port = QLatin1String("usb:"); 0324 } 0325 0326 CameraType* const ctype = new CameraType(model, model, port, QLatin1String("/"), 1); 0327 insert(ctype); 0328 0329 return ctype; 0330 } 0331 0332 bool CameraList::findConnectedCamera(int vendorId, int productId, QString& model, QString& port) 0333 { 0334 return GPCamera::findConnectedUsbCamera(vendorId, productId, model, port); 0335 } 0336 0337 bool CameraList::changeCameraStartIndex(const QString& cameraTitle, int startIndex) 0338 { 0339 CameraType* const cam = find(cameraTitle); 0340 0341 if (cam) 0342 { 0343 cam->setStartingNumber(startIndex); 0344 d->modified = true; 0345 save(); 0346 0347 return true; 0348 } 0349 0350 return false; 0351 } 0352 0353 } // namespace Digikam 0354 0355 #include "moc_cameralist.cpp"