Speed up device detection on windows. Difference will be noticeable for all the EB600 clones in particular

This commit is contained in:
Kovid Goyal 2010-01-02 19:42:45 -07:00
parent 0496407296
commit f061a40650
7 changed files with 222 additions and 241 deletions

View File

@ -37,6 +37,10 @@ def debug(ioreg_to_tmp=False, buf=None):
if buf is None:
buf = StringIO()
sys.stdout = sys.stderr = buf
if iswindows:
import pythoncom
pythoncom.CoInitialize()
try:
out = partial(prints, file=buf)
out('Version:', __version__)
@ -50,29 +54,25 @@ def debug(ioreg_to_tmp=False, buf=None):
d[i] = hex(d[i])
out('USB devices on system:')
out(pprint.pformat(devices))
wmi = Wmi =None
if iswindows:
if iswindows:
import pythoncom
pythoncom.CoInitialize()
wmi = __import__('wmi', globals(), locals(), [], -1)
Wmi = wmi.WMI(find_classes=False)
drives = []
out('Drives detected:')
out('\t', '(ID, Partitions, Drive letter)')
for drive in Wmi.Win32_DiskDrive():
if drive.Partitions == 0:
continue
try:
wmi = __import__('wmi', globals(), locals(), [], -1)
drives = []
out('Drives detected:')
out('\t', '(ID, Partitions, Drive letter)')
for drive in wmi.WMI(find_classes=False).Win32_DiskDrive():
if drive.Partitions == 0:
continue
try:
partition = drive.associators("Win32_DiskDriveToDiskPartition")[0]
logical_disk = partition.associators('Win32_LogicalDiskToPartition')[0]
prefix = logical_disk.DeviceID+os.sep
drives.append((str(drive.PNPDeviceID), drive.Index, prefix))
except IndexError:
drives.append((str(drive.PNPDeviceID), 'No mount points found'))
for drive in drives:
out('\t', drive)
finally:
pythoncom.CoUninitialize()
partition = drive.associators("Win32_DiskDriveToDiskPartition")[0]
logical_disk = partition.associators('Win32_LogicalDiskToPartition')[0]
prefix = logical_disk.DeviceID+os.sep
drives.append((str(drive.PNPDeviceID), drive.Index, prefix))
except IndexError:
drives.append((str(drive.PNPDeviceID), 'No mount points found'))
for drive in drives:
out('\t', drive)
ioreg = None
if isosx:
@ -81,17 +81,26 @@ def debug(ioreg_to_tmp=False, buf=None):
ioreg = Device.run_ioreg()
ioreg = 'Output from mount:\n\n'+mount+'\n\n'+ioreg
connected_devices = []
s.wmi = Wmi
for dev in device_plugins():
owmi = getattr(dev, 'wmi', None)
dev.wmi = Wmi
out('Looking for', dev.__class__.__name__)
connected, det = s.is_device_connected(dev, debug=True)
if connected:
connected_devices.append((dev, det))
dev.wmi = owmi
errors = {}
success = False
out('Devices possibly connected:', end=' ')
for dev, det in connected_devices:
out('Device possibly connected:', dev.__class__.name)
out('Trying to open device...', end=' ')
out(dev.name, end=', ')
out(' ')
for dev, det in connected_devices:
out('Trying to open', dev.name, '...', end=' ')
owmi = getattr(dev, 'wmi', None)
dev.wmi = Wmi
try:
dev.reset(detected_device=det)
dev.open()
@ -101,6 +110,8 @@ def debug(ioreg_to_tmp=False, buf=None):
errors[dev] = traceback.format_exc()
out('failed')
continue
finally:
dev.wmi = owmi
success = True
if hasattr(dev, '_main_prefix'):
out('Main memory:', repr(dev._main_prefix))
@ -128,4 +139,7 @@ def debug(ioreg_to_tmp=False, buf=None):
finally:
sys.stdout = oldo
sys.stderr = olde
if iswindows:
import pythoncom
pythoncom.CoUninitialize()

View File

@ -43,8 +43,7 @@ class DevicePlugin(Plugin):
#: Icon for this device
icon = I('reader.svg')
@classmethod
def test_bcd_windows(cls, device_id, bcd):
def test_bcd_windows(self, device_id, bcd):
if bcd is None or len(bcd) == 0:
return True
for c in bcd:
@ -54,30 +53,28 @@ class DevicePlugin(Plugin):
return True
return False
@classmethod
def print_usb_device_info(cls, info):
def print_usb_device_info(self, info):
try:
print '\t', repr(info)
except:
import traceback
traceback.print_exc()
@classmethod
def is_usb_connected_windows(cls, devices_on_system, debug=False):
def is_usb_connected_windows(self, devices_on_system, pnp_id_iterator, debug=False):
def id_iterator():
if hasattr(cls.VENDOR_ID, 'keys'):
for vid in cls.VENDOR_ID:
vend = cls.VENDOR_ID[vid]
if hasattr(self.VENDOR_ID, 'keys'):
for vid in self.VENDOR_ID:
vend = self.VENDOR_ID[vid]
for pid in vend:
bcd = vend[pid]
yield vid, pid, bcd
else:
vendors = cls.VENDOR_ID if hasattr(cls.VENDOR_ID, '__len__') else [cls.VENDOR_ID]
products = cls.PRODUCT_ID if hasattr(cls.PRODUCT_ID, '__len__') else [cls.PRODUCT_ID]
vendors = self.VENDOR_ID if hasattr(self.VENDOR_ID, '__len__') else [self.VENDOR_ID]
products = self.PRODUCT_ID if hasattr(self.PRODUCT_ID, '__len__') else [self.PRODUCT_ID]
for vid in vendors:
for pid in products:
yield vid, pid, cls.BCD
yield vid, pid, self.BCD
for vendor_id, product_id, bcd in id_iterator():
vid, pid = 'vid_%4.4x'%vendor_id, 'pid_%4.4x'%product_id
@ -85,15 +82,14 @@ class DevicePlugin(Plugin):
for device_id in devices_on_system:
if (vid in device_id or vidd in device_id) and \
(pid in device_id or pidd in device_id) and \
cls.test_bcd_windows(device_id, bcd):
self.test_bcd_windows(device_id, bcd):
if debug:
cls.print_usb_device_info(device_id)
if cls.can_handle(device_id):
self.print_usb_device_info(device_id)
if self.can_handle_windows(device_id, pnp_id_iterator, debug=debug):
return True
return False
@classmethod
def test_bcd(cls, bcdDevice, bcd):
def test_bcd(self, bcdDevice, bcd):
if bcd is None or len(bcd) == 0:
return True
for c in bcd:
@ -101,24 +97,24 @@ class DevicePlugin(Plugin):
return True
return False
@classmethod
def is_usb_connected(cls, devices_on_system, debug=False):
def is_usb_connected(self, devices_on_system, pnp_id_iterator, debug=False):
'''
Return True, device_info if a device handled by this plugin is currently connected.
:param devices_on_system: List of devices currently connected
'''
if iswindows:
return cls.is_usb_connected_windows(devices_on_system, debug=debug), None
return self.is_usb_connected_windows(devices_on_system,
pnp_id_iterator, debug=debug), None
vendors_on_system = set([x[0] for x in devices_on_system])
vendors = cls.VENDOR_ID if hasattr(cls.VENDOR_ID, '__len__') else [cls.VENDOR_ID]
if hasattr(cls.VENDOR_ID, 'keys'):
vendors = self.VENDOR_ID if hasattr(self.VENDOR_ID, '__len__') else [self.VENDOR_ID]
if hasattr(self.VENDOR_ID, 'keys'):
products = []
for ven in cls.VENDOR_ID:
products.extend(cls.VENDOR_ID[ven].keys())
for ven in self.VENDOR_ID:
products.extend(self.VENDOR_ID[ven].keys())
else:
products = cls.PRODUCT_ID if hasattr(cls.PRODUCT_ID, '__len__') else [cls.PRODUCT_ID]
products = self.PRODUCT_ID if hasattr(self.PRODUCT_ID, '__len__') else [self.PRODUCT_ID]
for vid in vendors:
if vid in vendors_on_system:
@ -126,14 +122,14 @@ class DevicePlugin(Plugin):
cvid, pid, bcd = dev[:3]
if cvid == vid:
if pid in products:
if hasattr(cls.VENDOR_ID, 'keys'):
cbcd = cls.VENDOR_ID[vid][pid]
if hasattr(self.VENDOR_ID, 'keys'):
cbcd = self.VENDOR_ID[vid][pid]
else:
cbcd = cls.BCD
if cls.test_bcd(bcd, cbcd):
cbcd = self.BCD
if self.test_bcd(bcd, cbcd):
if debug:
cls.print_usb_device_info(dev)
if cls.can_handle(dev, debug=debug):
self.print_usb_device_info(dev)
if self.can_handle(dev, debug=debug):
return True, dev
return False, None
@ -151,25 +147,30 @@ class DevicePlugin(Plugin):
"""
raise NotImplementedError()
@classmethod
def get_fdi(cls):
'''Return the FDI description of this device for HAL on linux.'''
return ''
@classmethod
def can_handle(cls, device_info, debug=False):
def can_handle_windows(self, device_id, pnp_id_iterator, debug=False):
'''
Optional method to perform further checks on a device to see if this driver
is capable of handling it. If it is not it should return False. This method
is only called after the vendor, product ids and the bcd have matched, so
it can do some relatively time intensive checks. The default implementation
returns True.
returns True. This method is called only on windows. See also
:method:`can_handle`.
:param device_info: On windows a device ID string. On Unix a tuple of
``(vendor_id, product_id, bcd)``.
'''
return True
def can_handle(self, device_info, debug=False):
'''
Unix version of :method:`can_handle_windows`
:param device_info: Is a tupe of (vid, pid, bcd, manufacturer, product,
serial number)
'''
return True
def open(self):
'''
Perform any device specific initialization. Called after the device is

View File

@ -197,15 +197,15 @@ def main():
command = args[0]
args = args[1:]
dev = None
_wmi = None
scanner = DeviceScanner()
if iswindows:
import wmi, pythoncom
pythoncom.CoInitialize()
_wmi = wmi.WMI()
scanner = DeviceScanner(_wmi)
scanner.wmi = wmi.WMI(find_classes=False)
scanner.scan()
connected_devices = []
for d in device_plugins():
d.wmi = scanner.wmi
ok, det = scanner.is_device_connected(d)
if ok:
dev = d

View File

@ -85,13 +85,26 @@ class DeviceScanner(object):
raise RuntimeError('DeviceScanner requires the /sys filesystem to work.')
self.scanner = win_scanner if iswindows else osx_scanner if isosx else linux_scanner
self.devices = []
self.wmi = None
self.pnp_ids = set([])
self.rescan_pnp_ids = True
def scan(self):
'''Fetch list of connected USB devices from operating system'''
self.devices = self.scanner()
if self.rescan_pnp_ids:
self.pnp_ids = set([])
def pnp_id_iterator(self):
if self.wmi is not None and not self.pnp_ids:
for drive in self.wmi.Win32_DiskDrive():
if drive.Partitions > 0:
self.pnp_ids.add(str(drive.PNPDeviceID))
for x in self.pnp_ids:
yield x
def is_device_connected(self, device, debug=False):
return device.is_usb_connected(self.devices, debug=debug)
return device.is_usb_connected(self.devices, self.pnp_id_iterator, debug=debug)
def main(args=sys.argv):

View File

@ -22,7 +22,7 @@ from itertools import repeat
from calibre.devices.interface import DevicePlugin
from calibre.devices.errors import DeviceError, FreeSpaceError
from calibre.devices.usbms.deviceconfig import DeviceConfig
from calibre.constants import iswindows, islinux, isosx, __appname__, plugins
from calibre.constants import iswindows, islinux, isosx, plugins
from calibre.utils.filenames import ascii_filename as sanitize, shorten_components_to
if isosx:
@ -83,53 +83,6 @@ class Device(DeviceConfig, DevicePlugin):
EBOOK_DIR_CARD_B = ''
DELETE_EXTS = []
FDI_TEMPLATE = \
'''
<device>
<match key="info.category" string="volume">
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.vendor_id" int="%(vendor_id)s">
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.product_id" int="%(product_id)s">
%(BCD_start)s
<match key="@info.parent:storage.lun" int="%(lun0)d">
<merge key="volume.label" type="string">%(main_memory)s</merge>
<merge key="%(app)s.mainvolume" type="string">%(deviceclass)s</merge>
</match>
%(BCD_end)s
</match>
</match>
</match>
</device>
<device>
<match key="info.category" string="volume">
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.vendor_id" int="%(vendor_id)s">
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.product_id" int="%(product_id)s">
%(BCD_start)s
<match key="@info.parent:storage.lun" int="%(lun1)d">
<merge key="volume.label" type="string">%(storage_card)s</merge>
<merge key="%(app)s.cardvolume" type="string">%(deviceclass)s</merge>
</match>
%(BCD_end)s
</match>
</match>
</match>
</device>
<device>
<match key="info.category" string="volume">
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.vendor_id" int="%(vendor_id)s">
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.product_id" int="%(product_id)s">
%(BCD_start)s
<match key="@info.parent:storage.lun" int="%(lun2)d">
<merge key="volume.label" type="string">%(storage_card)s</merge>
<merge key="%(app)s.cardvolume" type="string">%(deviceclass)s</merge>
</match>
%(BCD_end)s
</match>
</match>
</match>
</device>
'''
FDI_LUNS = {'lun0':0, 'lun1':1, 'lun2':2}
FDI_BCD_TEMPLATE = '<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.device_revision_bcd" int="%(bcd)s">'
def reset(self, key='-1', log_packets=False, report_progress=None,
detected_device=None):
@ -138,6 +91,7 @@ class Device(DeviceConfig, DevicePlugin):
self.detected_device = USBDevice(detected_device)
except: # On windows detected_device is None
self.detected_device = None
self.set_progress_reporter(report_progress)
@classmethod
def get_gui_name(cls):
@ -146,37 +100,11 @@ class Device(DeviceConfig, DevicePlugin):
x = cls.__name__
return x
@classmethod
def get_fdi(cls):
fdi = ''
for vid in cls.VENDOR_ID:
for pid in cls.PRODUCT_ID:
fdi_base_values = dict(
app=__appname__,
deviceclass=cls.__name__,
vendor_id=hex(vid),
product_id=hex(pid),
main_memory=cls.MAIN_MEMORY_VOLUME_LABEL,
storage_card=cls.STORAGE_CARD_VOLUME_LABEL,
)
fdi_base_values.update(cls.FDI_LUNS)
if cls.BCD is None:
fdi_base_values['BCD_start'] = ''
fdi_base_values['BCD_end'] = ''
fdi += cls.FDI_TEMPLATE % fdi_base_values
else:
for bcd in cls.BCD:
fdi_bcd_values = fdi_base_values
fdi_bcd_values['BCD_start'] = cls.FDI_BCD_TEMPLATE % dict(bcd=hex(bcd))
fdi_bcd_values['BCD_end'] = '</match>'
fdi += cls.FDI_TEMPLATE % fdi_bcd_values
return fdi
def set_progress_reporter(self, report_progress):
self.report_progress = report_progress
self.report_progress = report_progress
if self.report_progress is None:
self.report_progress = lambda x, y: x
def card_prefix(self, end_session=True):
return (self._card_a_prefix, self._card_b_prefix)
@ -239,9 +167,7 @@ class Device(DeviceConfig, DevicePlugin):
def windows_filter_pnp_id(self, pnp_id):
return False
def windows_match_device(self, drive, attr):
pnp_id = (str(drive.PNPDeviceID) if not isinstance(drive, basestring)
else str(drive)).upper()
def windows_match_device(self, pnp_id, attr):
device_id = getattr(self, attr)
def test_vendor():
@ -292,6 +218,12 @@ class Device(DeviceConfig, DevicePlugin):
'''
return drives
def can_handle_windows(self, device_id, pnp_id_iterator, debug=False):
for pnp_id in pnp_id_iterator():
if self.windows_match_device(pnp_id, 'WINDOWS_MAIN_MEM'):
return True
return False
def open_windows(self):
def matches_q(drive, attr):
@ -307,14 +239,14 @@ class Device(DeviceConfig, DevicePlugin):
time.sleep(8)
drives = {}
wmi = __import__('wmi', globals(), locals(), [], -1)
c = wmi.WMI(find_classes=False)
c = self.wmi
for drive in c.Win32_DiskDrive():
if self.windows_match_device(drive, 'WINDOWS_CARD_A_MEM') and not drives.get('carda', None):
pnp_id = str(drive.PNPDeviceID)
if self.windows_match_device(pnp_id, 'WINDOWS_CARD_A_MEM') and not drives.get('carda', None):
drives['carda'] = self.windows_get_drive_prefix(drive)
elif self.windows_match_device(drive, 'WINDOWS_CARD_B_MEM') and not drives.get('cardb', None):
elif self.windows_match_device(pnp_id, 'WINDOWS_CARD_B_MEM') and not drives.get('cardb', None):
drives['cardb'] = self.windows_get_drive_prefix(drive)
elif self.windows_match_device(drive, 'WINDOWS_MAIN_MEM') and not drives.get('main', None):
elif self.windows_match_device(pnp_id, 'WINDOWS_MAIN_MEM') and not drives.get('main', None):
drives['main'] = self.windows_get_drive_prefix(drive)
if 'main' in drives.keys() and 'carda' in drives.keys() and \

View File

@ -72,15 +72,12 @@ class DeviceManager(Thread):
def __init__(self, connected_slot, job_manager, sleep_time=2):
'''
@param sleep_time: Time to sleep between device probes in secs
@type sleep_time: integer
:sleep_time: Time to sleep between device probes in secs
'''
Thread.__init__(self)
self.setDaemon(True)
# [Device driver, Showing in GUI, Ejected]
self.devices = [[d, False, False] for d in device_plugins()]
self.device = None
self.device_class = None
self.devices = list(device_plugins())
self.sleep_time = sleep_time
self.connected_slot = connected_slot
self.jobs = Queue.Queue(0)
@ -88,75 +85,83 @@ class DeviceManager(Thread):
self.job_manager = job_manager
self.current_job = None
self.scanner = DeviceScanner()
self.wmi = None
self.connected_device = None
self.ejected_devices = set([])
def report_progress(self, *args):
pass
@property
def is_device_connected(self):
return self.connected_device is not None
@property
def device(self):
return self.connected_device
def do_connect(self, connected_devices):
if iswindows:
import pythoncom
pythoncom.CoInitialize()
try:
for dev, detected_device in connected_devices:
dev.reset(detected_device=detected_device)
try:
dev.open()
except:
print 'Unable to open device', dev
traceback.print_exc()
continue
self.device = dev
self.device_class = dev.__class__
self.connected_slot(True)
return True
finally:
if iswindows:
pythoncom.CoUninitialize()
for dev, detected_device in connected_devices:
dev.reset(detected_device=detected_device,
report_progress=self.report_progress)
try:
dev.open()
except:
print 'Unable to open device', dev
traceback.print_exc()
continue
self.connected_device = dev
self.connected_slot(True)
return True
return False
def connected_device_removed(self):
while True:
try:
job = self.jobs.get_nowait()
job.abort(Exception(_('Device no longer connected.')))
except Queue.Empty:
break
try:
self.connected_device.post_yank_cleanup()
except:
pass
if self.connected_device in self.ejected_devices:
self.ejected_devices.remove(self.connected_device)
else:
self.connected_slot(False)
self.connected_device = None
def detect_device(self):
self.scanner.rescan_pnp_ids = not self.is_device_connected
self.scanner.scan()
connected_devices = []
for device in self.devices:
connected, detected_device = self.scanner.is_device_connected(device[0])
if connected and not device[1] and not device[2]:
# If connected and not showing in GUI and not ejected
connected_devices.append((device[0], detected_device))
device[1] = True
elif not connected and device[1]:
# Disconnected but showing in GUI
while True:
try:
job = self.jobs.get_nowait()
job.abort(Exception(_('Device no longer connected.')))
except Queue.Empty:
break
try:
self.device.post_yank_cleanup()
except:
pass
device[2] = False
self.device = None
self.connected_slot(False)
device[1] ^= True
if connected_devices:
if not self.do_connect(connected_devices):
print 'Connect to device failed, retying in 5 seconds...'
time.sleep(5)
if not self.do_connect(connected_devices):
print 'Device connect failed again, giving up'
if self.is_device_connected:
connected, detected_device = \
self.scanner.is_device_connected(self.connected_device)
if not connected:
self.connected_device_removed()
else:
possibly_connected_devices = []
for device in self.devices:
if device in self.ejected_devices:
continue
possibly_connected, detected_device = \
self.scanner.is_device_connected(device)
if possibly_connected:
possibly_connected_devices.append((device, detected_device))
if possibly_connected_devices:
if not self.do_connect(possibly_connected_devices):
print 'Connect to device failed, retying in 5 seconds...'
time.sleep(5)
if not self.do_connect(possibly_connected_devices):
print 'Device connect failed again, giving up'
def umount_device(self):
if self.device is not None:
self.device.eject()
dev = None
for x in self.devices:
if x[0] is self.device:
dev = x
break
if dev is not None:
dev[2] = True
if self.is_device_connected:
self.connected_device.eject()
self.ejected_devices.add(self.connected_device)
self.connected_slot(False)
def next(self):
if not self.jobs.empty():
try:
@ -165,18 +170,31 @@ class DeviceManager(Thread):
pass
def run(self):
while self.keep_going:
self.detect_device()
while True:
job = self.next()
if job is not None:
self.current_job = job
self.device.set_progress_reporter(job.report_progress)
self.current_job.run()
self.current_job = None
else:
break
time.sleep(self.sleep_time)
if iswindows:
import pythoncom
pythoncom.CoInitialize()
wmi = __import__('wmi', globals(), locals(), [], -1)
self.wmi = wmi.WMI(find_classes=False)
self.scanner.wmi = self.wmi
for x in self.devices:
x[0].wmi = self.wmi
try:
while self.keep_going:
self.detect_device()
while True:
job = self.next()
if job is not None:
self.current_job = job
self.device.set_progress_reporter(job.report_progress)
self.current_job.run()
self.current_job = None
else:
break
time.sleep(self.sleep_time)
finally:
if iswindows:
pythoncom.CoUninitialize()
def create_job(self, func, done, description, args=[], kwargs={}):
job = DeviceJob(func, done, self.job_manager,
@ -495,7 +513,7 @@ class DeviceGUI(object):
fmt = None
if specific:
d = ChooseFormatDialog(self, _('Choose format to send to device'),
self.device_manager.device_class.settings().format_map)
self.device_manager.device.settings().format_map)
d.exec_()
fmt = d.format().lower()
dest, sub_dest = dest.split(':')
@ -637,7 +655,7 @@ class DeviceGUI(object):
p = QPixmap()
p.loadFromData(data)
if not p.isNull():
ht = self.device_manager.device_class.THUMBNAIL_HEIGHT \
ht = self.device_manager.device.THUMBNAIL_HEIGHT \
if self.device_manager else DevicePlugin.THUMBNAIL_HEIGHT
p = p.scaledToHeight(ht, Qt.SmoothTransformation)
return (p.width(), p.height(), pixmap_to_data(p))
@ -675,10 +693,11 @@ class DeviceGUI(object):
def sync_news(self, send_ids=None, do_auto_convert=True):
if self.device_connected:
settings = self.device_manager.device.settings()
ids = list(dynamic.get('news_to_be_synced', set([]))) if send_ids is None else send_ids
ids = [id for id in ids if self.library_view.model().db.has_id(id)]
files, _auto_ids = self.library_view.model().get_preferred_formats_from_ids(
ids, self.device_manager.device_class.settings().format_map,
ids, settings.format_map,
exclude_auto=do_auto_convert)
auto = []
if do_auto_convert and _auto_ids:
@ -687,12 +706,12 @@ class DeviceGUI(object):
formats = [] if dbfmts is None else \
[f.lower() for f in dbfmts.split(',')]
if set(formats).intersection(available_input_formats()) \
and set(self.device_manager.device_class.settings().format_map).intersection(available_output_formats()):
and set(settings.format_map).intersection(available_output_formats()):
auto.append(id)
if auto:
format = None
for fmt in self.device_manager.device_class.settings().format_map:
if fmt in list(set(self.device_manager.device_class.settings().format_map).intersection(set(available_output_formats()))):
for fmt in settings.format_map:
if fmt in list(set(settings.format_map).intersection(set(available_output_formats()))):
format = fmt
break
if format is not None:
@ -738,8 +757,10 @@ class DeviceGUI(object):
if not self.device_manager or not ids or len(ids) == 0:
return
settings = self.device_manager.device.settings()
_files, _auto_ids = self.library_view.model().get_preferred_formats_from_ids(ids,
self.device_manager.device_class.settings().format_map,
settings.format_map,
paths=True, set_metadata=True,
specific_format=specific_format,
exclude_auto=do_auto_convert)
@ -790,21 +811,21 @@ class DeviceGUI(object):
formats = self.library_view.model().db.formats(id, index_is_id=True)
formats = formats.split(',') if formats is not None else []
formats = [f.lower().strip() for f in formats]
if list(set(formats).intersection(available_input_formats())) != [] and list(set(self.device_manager.device_class.settings().format_map).intersection(available_output_formats())) != []:
if list(set(formats).intersection(available_input_formats())) != [] and list(set(settings.format_map).intersection(available_output_formats())) != []:
auto.append(id)
else:
bad.append(self.library_view.model().db.title(id, index_is_id=True))
else:
if specific_format in list(set(self.device_manager.device_class.settings().format_map).intersection(set(available_output_formats()))):
if specific_format in list(set(settings.format_map).intersection(set(available_output_formats()))):
auto.append(id)
else:
bad.append(self.library_view.model().db.title(id, index_is_id=True))
if auto != []:
format = specific_format if specific_format in list(set(self.device_manager.device_class.settings().format_map).intersection(set(available_output_formats()))) else None
format = specific_format if specific_format in list(set(settings.format_map).intersection(set(available_output_formats()))) else None
if not format:
for fmt in self.device_manager.device_class.settings().format_map:
if fmt in list(set(self.device_manager.device_class.settings().format_map).intersection(set(available_output_formats()))):
for fmt in settings.format_map:
if fmt in list(set(settings.format_map).intersection(set(available_output_formats()))):
format = fmt
break
if not format:

View File

@ -840,11 +840,11 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
return
mainlist, cardalist, cardblist = job.result
self.memory_view.set_database(mainlist)
self.memory_view.set_editable(self.device_manager.device_class.CAN_SET_METADATA)
self.memory_view.set_editable(self.device_manager.device.CAN_SET_METADATA)
self.card_a_view.set_database(cardalist)
self.card_a_view.set_editable(self.device_manager.device_class.CAN_SET_METADATA)
self.card_a_view.set_editable(self.device_manager.device.CAN_SET_METADATA)
self.card_b_view.set_database(cardblist)
self.card_b_view.set_editable(self.device_manager.device_class.CAN_SET_METADATA)
self.card_b_view.set_editable(self.device_manager.device.CAN_SET_METADATA)
for view in (self.memory_view, self.card_a_view, self.card_b_view):
view.sortByColumn(3, Qt.DescendingOrder)
view.read_settings()