mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Speed up device detection on windows. Difference will be noticeable for all the EB600 clones in particular
This commit is contained in:
parent
0496407296
commit
f061a40650
@ -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()
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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 \
|
||||
|
@ -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:
|
||||
|
@ -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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user