File indexing completed on 2025-01-12 12:39:36
0001 /************************************************************************ 0002 * * 0003 * This file is part of Kooka, a scanning/OCR application using * 0004 * Qt <http://www.qt.io> and KDE Frameworks <http://www.kde.org>. * 0005 * * 0006 * Copyright (C) 1999-2016 Klaas Freitag <freitag@suse.de> * 0007 * Jonathan Marten <jjm@keelhaul.me.uk> * 0008 * * 0009 * Kooka is free software; you can redistribute it and/or modify it * 0010 * under the terms of the GNU Library General Public License as * 0011 * published by the Free Software Foundation and appearing in the * 0012 * file COPYING included in the packaging of this file; either * 0013 * version 2 of the License, or (at your option) any later version. * 0014 * * 0015 * As a special exception, permission is given to link this program * 0016 * with any version of the KADMOS OCR/ICR engine (a product of * 0017 * reRecognition GmbH, Kreuzlingen), and distribute the resulting * 0018 * executable without including the source code for KADMOS in the * 0019 * source distribution. * 0020 * * 0021 * This program is distributed in the hope that it will be useful, * 0022 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0023 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0024 * GNU General Public License for more details. * 0025 * * 0026 * You should have received a copy of the GNU General Public * 0027 * License along with this program; see the file COPYING. If * 0028 * not, see <http://www.gnu.org/licenses/>. * 0029 * * 0030 ************************************************************************/ 0031 0032 #include "scandevices.h" 0033 0034 #include <klocalizedstring.h> 0035 0036 #include "scanglobal.h" 0037 #include "scansettings.h" 0038 #include "libkookascan_logging.h" 0039 0040 0041 ScanDevices *sInstance = nullptr; 0042 0043 ScanDevices *ScanDevices::self() 0044 { 0045 if (sInstance == nullptr) { 0046 sInstance = new ScanDevices(); 0047 } 0048 return (sInstance); 0049 } 0050 0051 ScanDevices::ScanDevices() 0052 { 0053 qCDebug(LIBKOOKASCAN_LOG); 0054 0055 if (!ScanGlobal::self()->init()) { 0056 return; // do sane_init() if necessary 0057 } 0058 0059 bool netaccess = ScanSettings::startupOnlyLocal(); 0060 qCDebug(LIBKOOKASCAN_LOG) << "Query for network scanners?" << netaccess; 0061 0062 SANE_Device const **dev_list = nullptr; 0063 SANE_Status status = sane_get_devices(&dev_list, (netaccess ? SANE_TRUE : SANE_FALSE)); 0064 if (status != SANE_STATUS_GOOD) 0065 { 0066 qCWarning(LIBKOOKASCAN_LOG) << "sane_get_devices() failed, status" << status; 0067 return; // no point carrying on 0068 } 0069 0070 const SANE_Device *dev; 0071 for (int devno = 0; (dev = dev_list[devno]) != nullptr; ++devno) { 0072 mScannerNames.append(dev->name); 0073 mScannerDevices.insert(dev->name, dev); 0074 qCDebug(LIBKOOKASCAN_LOG) << "SANE found scanner:" << dev->name << "=" << deviceDescription(dev->name); 0075 } 0076 0077 QStringList devs = ScanSettings::userDevices(); 0078 if (!devs.isEmpty()) 0079 { 0080 QStringList descs = ScanSettings::userDescriptions(); 0081 if (descs.count()<devs.count()) // ensure list correct length 0082 { 0083 for (int i = descs.count(); i<devs.count(); ++i) descs.append("Unknown"); 0084 ScanSettings::setUserDescriptions(descs); 0085 ScanSettings::self()->save(); 0086 } 0087 0088 QStringList types = ScanSettings::userTypes(); 0089 if (types.count()<devs.count()) // ensure list correct length 0090 { 0091 for (int i = types.count(); i<devs.count(); ++i) types.append("scanner"); 0092 ScanSettings::setUserTypes(types); 0093 ScanSettings::self()->save(); 0094 } 0095 0096 QStringList::const_iterator it2 = descs.constBegin(); 0097 QStringList::const_iterator it3 = types.constBegin(); 0098 for (QStringList::const_iterator it1 = devs.constBegin(); 0099 it1 != devs.constEnd(); ++it1, ++it2, ++it3) { 0100 // avoid duplication 0101 QByteArray name = (*it1).toLocal8Bit(); 0102 if (mScannerNames.contains(name)) { 0103 continue; 0104 } 0105 addUserSpecifiedDevice(name, (*it2), (*it3).toLocal8Bit(), true); 0106 qCDebug(LIBKOOKASCAN_LOG) << "Configured scanner:" << name << "=" << deviceDescription(name); 0107 } 0108 } 0109 } 0110 0111 ScanDevices::~ScanDevices() 0112 { 0113 } 0114 0115 void ScanDevices::addUserSpecifiedDevice(const QByteArray &backend, 0116 const QString &description, 0117 const QByteArray &type, 0118 bool dontSave) 0119 { 0120 if (backend.isEmpty()) { 0121 return; 0122 } 0123 0124 if (mScannerNames.contains(backend)) { 0125 qCDebug(LIBKOOKASCAN_LOG) << "device" << backend << "already exists, not adding"; 0126 return; 0127 } 0128 0129 QByteArray devtype = (!type.isEmpty() ? type : "scanner"); 0130 qCDebug(LIBKOOKASCAN_LOG) << "adding" << backend << "desc" << description 0131 << "type" << devtype << "dontSave" << dontSave; 0132 0133 if (!dontSave) // add new device to config 0134 { // get existing device lists 0135 QStringList devs = ScanSettings::userDevices(); 0136 QStringList descs = ScanSettings::userDescriptions(); 0137 QStringList types = ScanSettings::userTypes(); 0138 0139 int i = devs.indexOf(backend); 0140 if (i >= 0) { // see if already in list 0141 descs[i] = description; // if so just update 0142 types[i] = devtype; 0143 } else { 0144 devs.append(backend); // add new entry to lists 0145 descs.append(description); 0146 types.append(devtype); 0147 } 0148 0149 ScanSettings::setUserDevices(devs); 0150 ScanSettings::setUserDescriptions(descs); 0151 ScanSettings::setUserTypes(types); 0152 ScanSettings::self()->save(); 0153 } 0154 0155 SANE_Device *userdev = new SANE_Device; 0156 0157 // Need a permanent copy of the strings, because SANE_Device only holds 0158 // pointers to them. Unfortunately there is a memory leak here, the 0159 // 'userdev' object and its three QByteArray's are never deleted. 0160 // There is only a limited number of these objects in most applications, 0161 // so hopefully it won't matter too much. 0162 0163 userdev->name = (new QByteArray(backend))->constData(); 0164 userdev->model = (new QByteArray(description.toLocal8Bit()))->constData(); 0165 userdev->type = (new QByteArray(devtype))->constData(); 0166 userdev->vendor = ""; 0167 0168 mScannerNames.append(backend); 0169 mScannerDevices.insert(backend, userdev); 0170 } 0171 0172 const SANE_Device *ScanDevices::deviceInfo(const QByteArray &backend) const 0173 { 0174 if (!mScannerNames.contains(backend)) { 0175 return (nullptr); 0176 } 0177 return (mScannerDevices[backend]); 0178 } 0179 0180 QString ScanDevices::deviceDescription(const QByteArray &backend) const 0181 { 0182 if (!mScannerNames.contains(backend)) return (i18n("Unknown device '%1'", backend.constData())); 0183 0184 const SANE_Device *scanner = mScannerDevices[backend]; 0185 QString result = QString::fromLocal8Bit(scanner->vendor); 0186 if (!result.isEmpty()) result += ' '; 0187 result += QString::fromLocal8Bit(scanner->model); 0188 return (result); 0189 }