mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Sync to trunk.
This commit is contained in:
commit
5ea2953092
@ -1,19 +1,38 @@
|
||||
#!/usr/bin/env python
|
||||
__license__ = 'GPL v3'
|
||||
__author__ = 'Kovid Goyal and Sujata Raman, Lorenzo Vigentini'
|
||||
__copyright__ = '2009, Kovid Goyal and Sujata Raman'
|
||||
__version__ = 'v1.02'
|
||||
__date__ = '10, January 2010'
|
||||
__description__ = 'Providing context and clarity on national and international news, peoples and cultures'
|
||||
|
||||
'''csmonitor.com'''
|
||||
|
||||
|
||||
import re
|
||||
from calibre import strftime
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class ChristianScienceMonitor(BasicNewsRecipe):
|
||||
|
||||
title = 'Christian Science Monitor'
|
||||
description = 'Providing context and clarity on national and international news, peoples and cultures'
|
||||
max_articles_per_feed = 20
|
||||
__author__ = 'Kovid Goyal and Sujata Raman'
|
||||
author = 'Kovid Goyal, Sujata Raman and Lorenzo Vigentini'
|
||||
description = 'Providing context and clarity on national and international news, peoples and cultures'
|
||||
|
||||
cover_url = 'http://www.csmonitor.com/extension/csm_base/design/csm_design/images/csmlogo_179x46.gif'
|
||||
title = 'Christian Science Monitor'
|
||||
publisher = 'The Christian Science Monitor'
|
||||
category = 'News, politics, culture, economy, general interest'
|
||||
|
||||
language = 'en'
|
||||
encoding = 'utf-8'
|
||||
no_stylesheets = True
|
||||
use_embedded_content = False
|
||||
timefmt = '[%a, %d %b, %Y]'
|
||||
|
||||
oldest_article = 16
|
||||
max_articles_per_feed = 20
|
||||
use_embedded_content = False
|
||||
recursion = 10
|
||||
|
||||
remove_javascript = True
|
||||
no_stylesheets = True
|
||||
|
||||
|
||||
preprocess_regexps = [ (re.compile(i[0], re.IGNORECASE | re.DOTALL), i[1]) for i in
|
||||
@ -55,33 +74,15 @@ class ChristianScienceMonitor(BasicNewsRecipe):
|
||||
]
|
||||
|
||||
keep_only_tags = [
|
||||
dict(name='div', attrs={'id':['story','main']}),
|
||||
dict(name='div', attrs={'id':'mainColumn'}),
|
||||
]
|
||||
|
||||
remove_tags = [
|
||||
dict(name='div', attrs={'id':['story-tools','videoPlayer','storyRelatedBottom','enlarge-photo','photo-paginate']}),
|
||||
dict(name='div', attrs={'class':[ 'spacer3','divvy spacer7','comment','storyIncludeBottom']}),
|
||||
dict(name='div', attrs={'class':['storyToolbar cfx','podStoryRel','spacer3','divvy spacer7','comment','storyIncludeBottom']}),
|
||||
dict(name='ul', attrs={'class':[ 'centerliststories']}) ,
|
||||
dict(name='form', attrs={'id':[ 'commentform']}) ,
|
||||
]
|
||||
|
||||
remove_tags_after = [ dict(name='div', attrs={'class':[ 'ad csmAd']})]
|
||||
|
||||
def find_articles(self, section):
|
||||
ans = []
|
||||
for x in section.findAll('head4'):
|
||||
title = ' '.join(x.findAll(text=True)).strip()
|
||||
a = x.find('a')
|
||||
if not a: continue
|
||||
href = a['href']
|
||||
ans.append({'title':title, 'url':href, 'description':'', 'date': strftime('%a, %d %b')})
|
||||
|
||||
#for x in ans:
|
||||
# x['url'] += '/output/print'
|
||||
return ans
|
||||
|
||||
def postprocess_html(self, soup, first_fetch):
|
||||
html = soup.find('html')
|
||||
if html is None:
|
||||
return soup
|
||||
html.extract()
|
||||
return html
|
||||
|
@ -48,7 +48,9 @@ class NYTimes(BasicNewsRecipe):
|
||||
return 'NY Times'
|
||||
|
||||
def parse_index(self):
|
||||
self.encoding = 'cp1252'
|
||||
soup = self.index_to_soup('http://www.nytimes.com/pages/todayspaper/index.html')
|
||||
self.encoding = None
|
||||
|
||||
def feed_title(div):
|
||||
return ''.join(div.findAll(text=True, recursive=False)).strip()
|
||||
|
@ -9,6 +9,8 @@ from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class Slashdot(BasicNewsRecipe):
|
||||
title = u'Slashdot.org'
|
||||
description = '''Tech news. WARNING: This recipe downloads a lot
|
||||
of content and can result in your IP being banned from slashdot.org'''
|
||||
oldest_article = 7
|
||||
max_articles_per_feed = 100
|
||||
language = 'en'
|
||||
|
@ -5,7 +5,7 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
Device drivers.
|
||||
'''
|
||||
|
||||
import sys, os, time, pprint
|
||||
import sys, time, pprint
|
||||
from functools import partial
|
||||
from StringIO import StringIO
|
||||
|
||||
@ -29,7 +29,7 @@ def strftime(epoch, zone=time.gmtime):
|
||||
|
||||
def debug(ioreg_to_tmp=False, buf=None):
|
||||
from calibre.customize.ui import device_plugins
|
||||
from calibre.devices.scanner import DeviceScanner
|
||||
from calibre.devices.scanner import DeviceScanner, win_pnp_drives
|
||||
from calibre.constants import iswindows, isosx, __version__
|
||||
from calibre import prints
|
||||
oldo, olde = sys.stdout, sys.stderr
|
||||
@ -37,19 +37,11 @@ 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__)
|
||||
wmi = Wmi =None
|
||||
if iswindows:
|
||||
wmi = __import__('wmi', globals(), locals(), [], -1)
|
||||
Wmi = wmi.WMI(find_classes=False)
|
||||
s = DeviceScanner()
|
||||
s.wmi = Wmi
|
||||
s.scan()
|
||||
devices = (s.devices)
|
||||
if not iswindows:
|
||||
@ -60,21 +52,9 @@ def debug(ioreg_to_tmp=False, buf=None):
|
||||
out('USB devices on system:')
|
||||
out(pprint.pformat(devices))
|
||||
if iswindows:
|
||||
drives = []
|
||||
drives = win_pnp_drives(debug=True)
|
||||
out('Drives detected:')
|
||||
out('\t', '(ID, Partitions, Drive letter)')
|
||||
for drive in Wmi.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)
|
||||
out(pprint.pformat(drives))
|
||||
|
||||
ioreg = None
|
||||
if isosx:
|
||||
@ -84,13 +64,10 @@ def debug(ioreg_to_tmp=False, buf=None):
|
||||
ioreg = 'Output from mount:\n\n'+mount+'\n\n'+ioreg
|
||||
connected_devices = []
|
||||
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
|
||||
@ -102,8 +79,6 @@ def debug(ioreg_to_tmp=False, buf=None):
|
||||
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()
|
||||
@ -113,8 +88,6 @@ 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))
|
||||
@ -142,7 +115,4 @@ def debug(ioreg_to_tmp=False, buf=None):
|
||||
finally:
|
||||
sys.stdout = oldo
|
||||
sys.stderr = olde
|
||||
if iswindows:
|
||||
import pythoncom
|
||||
pythoncom.CoUninitialize()
|
||||
|
||||
|
@ -60,7 +60,7 @@ class DevicePlugin(Plugin):
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def is_usb_connected_windows(self, devices_on_system, pnp_id_iterator, debug=False):
|
||||
def is_usb_connected_windows(self, devices_on_system, debug=False):
|
||||
|
||||
def id_iterator():
|
||||
if hasattr(self.VENDOR_ID, 'keys'):
|
||||
@ -85,7 +85,7 @@ class DevicePlugin(Plugin):
|
||||
self.test_bcd_windows(device_id, bcd):
|
||||
if debug:
|
||||
self.print_usb_device_info(device_id)
|
||||
if self.can_handle_windows(device_id, pnp_id_iterator, debug=debug):
|
||||
if self.can_handle_windows(device_id, debug=debug):
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -97,7 +97,7 @@ class DevicePlugin(Plugin):
|
||||
return True
|
||||
return False
|
||||
|
||||
def is_usb_connected(self, devices_on_system, pnp_id_iterator, debug=False):
|
||||
def is_usb_connected(self, devices_on_system, debug=False):
|
||||
'''
|
||||
Return True, device_info if a device handled by this plugin is currently connected.
|
||||
|
||||
@ -105,7 +105,7 @@ class DevicePlugin(Plugin):
|
||||
'''
|
||||
if iswindows:
|
||||
return self.is_usb_connected_windows(devices_on_system,
|
||||
pnp_id_iterator, debug=debug), None
|
||||
debug=debug), None
|
||||
|
||||
vendors_on_system = set([x[0] for x in devices_on_system])
|
||||
vendors = self.VENDOR_ID if hasattr(self.VENDOR_ID, '__len__') else [self.VENDOR_ID]
|
||||
@ -147,7 +147,7 @@ class DevicePlugin(Plugin):
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def can_handle_windows(self, device_id, pnp_id_iterator, debug=False):
|
||||
def can_handle_windows(self, device_id, 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
|
||||
|
@ -9,7 +9,7 @@ For usage information run the script.
|
||||
import StringIO, sys, time, os
|
||||
from optparse import OptionParser
|
||||
|
||||
from calibre import __version__, iswindows, __appname__
|
||||
from calibre import __version__, __appname__
|
||||
from calibre.devices.errors import PathError
|
||||
from calibre.utils.terminfo import TerminalController
|
||||
from calibre.devices.errors import ArgumentError, DeviceError, DeviceLocked
|
||||
@ -198,14 +198,9 @@ def main():
|
||||
args = args[1:]
|
||||
dev = None
|
||||
scanner = DeviceScanner()
|
||||
if iswindows:
|
||||
import wmi, pythoncom
|
||||
pythoncom.CoInitialize()
|
||||
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
|
||||
|
@ -6,6 +6,7 @@ manner.
|
||||
'''
|
||||
|
||||
import sys, os
|
||||
from threading import RLock
|
||||
|
||||
from calibre import iswindows, isosx, plugins, islinux
|
||||
|
||||
@ -22,6 +23,54 @@ elif isosx:
|
||||
except:
|
||||
raise RuntimeError('Failed to load the usbobserver plugin: %s'%plugins['usbobserver'][1])
|
||||
|
||||
class WinPNPScanner(object):
|
||||
|
||||
def __init__(self):
|
||||
self.scanner = None
|
||||
if iswindows:
|
||||
self.scanner = plugins['winutil'][0].get_removable_drives
|
||||
self.lock = RLock()
|
||||
|
||||
def drive_is_ok(self, letter, debug=False):
|
||||
import win32api, win32file
|
||||
with self.lock:
|
||||
oldError = win32api.SetErrorMode(1) #SEM_FAILCRITICALERRORS = 1
|
||||
try:
|
||||
ans = True
|
||||
try:
|
||||
win32file.GetDiskFreeSpaceEx(letter+':\\')
|
||||
except:
|
||||
ans = False
|
||||
return ans
|
||||
finally:
|
||||
win32api.SetErrorMode(oldError)
|
||||
|
||||
def __call__(self, debug=False):
|
||||
if self.scanner is None:
|
||||
return {}
|
||||
try:
|
||||
drives = self.scanner(debug)
|
||||
except:
|
||||
drives = {}
|
||||
if debug:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
remove = set([])
|
||||
for letter in drives:
|
||||
if not self.drive_is_ok(letter, debug=debug):
|
||||
remove.add(letter)
|
||||
for letter in remove:
|
||||
drives.pop(letter)
|
||||
ans = {}
|
||||
for key, val in drives.items():
|
||||
val = [x.upper() for x in val]
|
||||
val = [x for x in val if 'USBSTOR' in x]
|
||||
if val:
|
||||
ans[key+':\\'] = val[-1]
|
||||
return ans
|
||||
|
||||
win_pnp_drives = WinPNPScanner()
|
||||
|
||||
class LinuxScanner(object):
|
||||
|
||||
SYSFS_PATH = os.environ.get('SYSFS_PATH', '/sys')
|
||||
@ -85,26 +134,13 @@ 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, self.pnp_id_iterator, debug=debug)
|
||||
return device.is_usb_connected(self.devices, debug=debug)
|
||||
|
||||
|
||||
def main(args=sys.argv):
|
||||
|
@ -203,18 +203,6 @@ class Device(DeviceConfig, DevicePlugin):
|
||||
|
||||
return False
|
||||
|
||||
def windows_get_drive_prefix(self, drive):
|
||||
prefix = None
|
||||
|
||||
try:
|
||||
partition = drive.associators("Win32_DiskDriveToDiskPartition")[0]
|
||||
logical_disk = partition.associators('Win32_LogicalDiskToPartition')[0]
|
||||
prefix = logical_disk.DeviceID + os.sep
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
return prefix
|
||||
|
||||
def windows_sort_drives(self, drives):
|
||||
'''
|
||||
Called to disambiguate main memory and storage card for devices that
|
||||
@ -223,8 +211,10 @@ 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():
|
||||
def can_handle_windows(self, device_id, debug=False):
|
||||
from calibre.devices.scanner import win_pnp_drives
|
||||
drives = win_pnp_drives()
|
||||
for pnp_id in drives.values():
|
||||
if self.windows_match_device(pnp_id, 'WINDOWS_MAIN_MEM'):
|
||||
return True
|
||||
if debug:
|
||||
@ -232,29 +222,20 @@ class Device(DeviceConfig, DevicePlugin):
|
||||
return False
|
||||
|
||||
def open_windows(self):
|
||||
from calibre.devices.scanner import win_pnp_drives
|
||||
|
||||
def matches_q(drive, attr):
|
||||
q = getattr(self, attr)
|
||||
if q is None: return False
|
||||
if isinstance(q, basestring):
|
||||
q = [q]
|
||||
pnp = str(drive.PNPDeviceID)
|
||||
for x in q:
|
||||
if x in pnp:
|
||||
return True
|
||||
return False
|
||||
|
||||
time.sleep(8)
|
||||
time.sleep(5)
|
||||
drives = {}
|
||||
c = self.wmi
|
||||
for drive in c.Win32_DiskDrive():
|
||||
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(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(pnp_id, 'WINDOWS_MAIN_MEM') and not drives.get('main', None):
|
||||
drives['main'] = self.windows_get_drive_prefix(drive)
|
||||
for drive, pnp_id in win_pnp_drives().items():
|
||||
if self.windows_match_device(pnp_id, 'WINDOWS_CARD_A_MEM') and \
|
||||
not drives.get('carda', False):
|
||||
drives['carda'] = drive
|
||||
elif self.windows_match_device(pnp_id, 'WINDOWS_CARD_B_MEM') and \
|
||||
not drives.get('cardb', False):
|
||||
drives['cardb'] = drive
|
||||
elif self.windows_match_device(pnp_id, 'WINDOWS_MAIN_MEM') and \
|
||||
not drives.get('main', False):
|
||||
drives['main'] = drive
|
||||
|
||||
if 'main' in drives.keys() and 'carda' in drives.keys() and \
|
||||
'cardb' in drives.keys():
|
||||
|
@ -168,6 +168,7 @@ class Stylizer(object):
|
||||
self.rules = rules
|
||||
self._styles = {}
|
||||
class_sel_pat = re.compile(r'\.[a-z]+', re.IGNORECASE)
|
||||
capital_sel_pat = re.compile(r'h|[A-Z]+')
|
||||
for _, _, cssdict, text, _ in rules:
|
||||
try:
|
||||
selector = CSSSelector(text)
|
||||
@ -176,6 +177,15 @@ class Stylizer(object):
|
||||
SelectorSyntaxError):
|
||||
continue
|
||||
matches = selector(tree)
|
||||
|
||||
if not matches:
|
||||
ntext = capital_sel_pat.sub(lambda m: m.group().lower(), text)
|
||||
if ntext != text:
|
||||
self.logger.warn('Transformed CSS selector', text, 'to',
|
||||
ntext)
|
||||
selector = CSSSelector(ntext)
|
||||
matches = selector(tree)
|
||||
|
||||
if not matches and class_sel_pat.match(text):
|
||||
found = False
|
||||
for x in tree.xpath('//*[@class]'):
|
||||
|
@ -13,7 +13,6 @@ from PyQt4.Qt import QMenu, QAction, QActionGroup, QIcon, SIGNAL, QPixmap, \
|
||||
from calibre.customize.ui import available_input_formats, available_output_formats, \
|
||||
device_plugins
|
||||
from calibre.devices.interface import DevicePlugin
|
||||
from calibre.constants import iswindows
|
||||
from calibre.gui2.dialogs.choose_format import ChooseFormatDialog
|
||||
from calibre.utils.ipc.job import BaseJob
|
||||
from calibre.devices.scanner import DeviceScanner
|
||||
@ -85,7 +84,6 @@ 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([])
|
||||
|
||||
@ -133,7 +131,6 @@ class DeviceManager(Thread):
|
||||
self.connected_device = None
|
||||
|
||||
def detect_device(self):
|
||||
self.scanner.rescan_pnp_ids = not self.is_device_connected
|
||||
self.scanner.scan()
|
||||
if self.is_device_connected:
|
||||
connected, detected_device = \
|
||||
@ -170,30 +167,18 @@ class DeviceManager(Thread):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
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.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()
|
||||
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)
|
||||
|
||||
|
||||
def create_job(self, func, done, description, args=[], kwargs={}):
|
||||
|
@ -7,7 +7,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>838</width>
|
||||
<width>884</width>
|
||||
<height>730</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -89,7 +89,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>562</width>
|
||||
<width>608</width>
|
||||
<height>683</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -171,7 +171,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
if self._add_formats(paths):
|
||||
event.accept()
|
||||
|
||||
def remove_format(self, x=None):
|
||||
def remove_format(self, *args):
|
||||
rows = self.formats.selectionModel().selectedRows(0)
|
||||
for row in rows:
|
||||
self.formats.takeItem(row.row())
|
||||
|
@ -23,9 +23,10 @@ KEY = Qt.UserRole + 3
|
||||
|
||||
class Customize(QFrame, Ui_Frame):
|
||||
|
||||
def __init__(self, dup_check, parent=None):
|
||||
def __init__(self, index, dup_check, parent=None):
|
||||
QFrame.__init__(self, parent)
|
||||
self.setupUi(self)
|
||||
self.data_model = index.model()
|
||||
self.setFocusPolicy(Qt.StrongFocus)
|
||||
self.setAutoFillBackground(True)
|
||||
self.custom.toggled.connect(self.custom_toggled)
|
||||
@ -86,12 +87,21 @@ class Delegate(QStyledItemDelegate):
|
||||
def __init__(self, parent=None):
|
||||
QStyledItemDelegate.__init__(self, parent)
|
||||
self.editing_indices = {}
|
||||
self.closeEditor.connect(self.editing_done)
|
||||
|
||||
def to_doc(self, index):
|
||||
doc = QTextDocument()
|
||||
doc.setHtml(index.data().toString())
|
||||
return doc
|
||||
|
||||
def editing_done(self, editor, hint):
|
||||
remove = None
|
||||
for row, w in self.editing_indices.items():
|
||||
remove = (row, w.data_model.index(row))
|
||||
if remove is not None:
|
||||
self.editing_indices.pop(remove[0])
|
||||
self.sizeHintChanged.emit(remove[1])
|
||||
|
||||
def sizeHint(self, option, index):
|
||||
if index.row() in self.editing_indices:
|
||||
return QSize(200, 200)
|
||||
@ -111,7 +121,7 @@ class Delegate(QStyledItemDelegate):
|
||||
painter.restore()
|
||||
|
||||
def createEditor(self, parent, option, index):
|
||||
w = Customize(index.model().duplicate_check, parent=parent)
|
||||
w = Customize(index, index.model().duplicate_check, parent=parent)
|
||||
self.editing_indices[index.row()] = w
|
||||
self.sizeHintChanged.emit(index)
|
||||
return w
|
||||
@ -135,8 +145,6 @@ class Delegate(QStyledItemDelegate):
|
||||
setattr(editor, 'shortcut%d'%(x+1), seq)
|
||||
|
||||
def setModelData(self, editor, model, index):
|
||||
self.editing_indices.pop(index.row())
|
||||
self.sizeHintChanged.emit(index)
|
||||
self.closeEditor.emit(editor, self.NoHint)
|
||||
custom = []
|
||||
if editor.custom.isChecked():
|
||||
|
@ -141,8 +141,8 @@ class FormatList(QListWidget):
|
||||
if event.key() == Qt.Key_Delete:
|
||||
self.emit(SIGNAL('delete_format()'))
|
||||
else:
|
||||
QListWidget.keyPressEvent(self, event)
|
||||
|
||||
return QListWidget.keyPressEvent(self, event)
|
||||
|
||||
|
||||
class ImageView(QLabel):
|
||||
|
||||
|
@ -204,23 +204,22 @@ get_registry_property(HDEVINFO hDevInfo, DWORD index, DWORD property, BOOL *iter
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
check_device_id(LPTSTR buffer, unsigned int vid, unsigned int pid) {
|
||||
WCHAR xVid[9], dVid[9], xPid[9], dPid[9];
|
||||
unsigned int j;
|
||||
swprintf(xVid, L"vid_%4.4x", vid);
|
||||
swprintf(dVid, L"vid_%4.4d", vid);
|
||||
swprintf(xPid, L"pid_%4.4x", pid);
|
||||
swprintf(dPid, L"pid_%4.4d", pid);
|
||||
|
||||
for (j = 0; j < wcslen(buffer); j++) buffer[j] = tolower(buffer[j]);
|
||||
|
||||
return ( (wcsstr(buffer, xVid) != NULL || wcsstr(buffer, dVid) != NULL ) &&
|
||||
(wcsstr(buffer, xPid) != NULL || wcsstr(buffer, dPid) != NULL )
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
static BOOL
|
||||
check_device_id(LPTSTR buffer, unsigned int vid, unsigned int pid) {
|
||||
WCHAR xVid[9], dVid[9], xPid[9], dPid[9];
|
||||
unsigned int j;
|
||||
_snwprintf_s(xVid, 9, _TRUNCATE, L"vid_%4.4x", vid);
|
||||
_snwprintf_s(dVid, 9, _TRUNCATE, L"vid_%4.4d", vid);
|
||||
_snwprintf_s(xPid, 9, _TRUNCATE, L"pid_%4.4x", pid);
|
||||
_snwprintf_s(dPid, 9, _TRUNCATE, L"pid_%4.4d", pid);
|
||||
|
||||
for (j = 0; j < wcslen(buffer); j++) buffer[j] = tolower(buffer[j]);
|
||||
|
||||
return ( (wcsstr(buffer, xVid) != NULL || wcsstr(buffer, dVid) != NULL ) &&
|
||||
(wcsstr(buffer, xPid) != NULL || wcsstr(buffer, dPid) != NULL )
|
||||
);
|
||||
}
|
||||
|
||||
static HDEVINFO
|
||||
create_device_info_set(LPGUID guid, PCTSTR enumerator, HWND parent, DWORD flags) {
|
||||
HDEVINFO hDevInfo;
|
||||
@ -286,7 +285,7 @@ get_all_removable_disks(struct tagDrives *g_drives)
|
||||
if(GetVolumeNameForVolumeMountPoint(caDrive, volume, BUFSIZE))
|
||||
{
|
||||
g_drives[g_count].letter = caDrive[0];
|
||||
wcscpy(g_drives[g_count].volume, volume);
|
||||
wcscpy_s(g_drives[g_count].volume, BUFSIZE, volume);
|
||||
g_count ++;
|
||||
}
|
||||
|
||||
@ -515,15 +514,17 @@ winutil_eject_drive(PyObject *self, PyObject *args) {
|
||||
|
||||
|
||||
PSP_DEVICE_INTERFACE_DETAIL_DATA
|
||||
get_device_grandparent(HDEVINFO hDevInfo, DWORD index, PWSTR buf, PWSTR volume_id,
|
||||
BOOL *iterate) {
|
||||
get_device_ancestors(HDEVINFO hDevInfo, DWORD index, PyObject *candidates, BOOL *iterate, BOOL ddebug) {
|
||||
SP_DEVICE_INTERFACE_DATA interfaceData;
|
||||
SP_DEVINFO_DATA devInfoData;
|
||||
BOOL status;
|
||||
PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData;
|
||||
DWORD interfaceDetailDataSize,
|
||||
reqSize;
|
||||
DEVINST parent;
|
||||
DEVINST parent, pos;
|
||||
wchar_t temp[BUFSIZE];
|
||||
int i;
|
||||
PyObject *devid;
|
||||
|
||||
interfaceData.cbSize = sizeof (SP_INTERFACE_DEVICE_DATA);
|
||||
devInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
|
||||
@ -549,7 +550,7 @@ get_device_grandparent(HDEVINFO hDevInfo, DWORD index, PWSTR buf, PWSTR volume_i
|
||||
);
|
||||
|
||||
interfaceDetailDataSize = reqSize;
|
||||
interfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)PyMem_Malloc(interfaceDetailDataSize+10);
|
||||
interfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)PyMem_Malloc(interfaceDetailDataSize+50);
|
||||
if ( interfaceDetailData == NULL ) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
@ -563,38 +564,49 @@ get_device_grandparent(HDEVINFO hDevInfo, DWORD index, PWSTR buf, PWSTR volume_i
|
||||
interfaceDetailDataSize, // Interface detail data size
|
||||
&reqSize, // Buffer size required to get the detail data
|
||||
&devInfoData); // Interface device info
|
||||
if (ddebug) printf("Getting ancestors\n"); fflush(stdout);
|
||||
|
||||
if ( status == FALSE ) {PyErr_SetFromWindowsErr(0); PyMem_Free(interfaceDetailData); return NULL;}
|
||||
|
||||
// Get the device instance of parent. This points to USBSTOR.
|
||||
CM_Get_Parent(&parent, devInfoData.DevInst, 0);
|
||||
// Get the device ID of the USBSTORAGE volume
|
||||
CM_Get_Device_ID(parent, volume_id, BUFSIZE, 0);
|
||||
// Get the device instance of grand parent. This points to USB root.
|
||||
CM_Get_Parent(&parent, parent, 0);
|
||||
// Get the device ID of the USB root.
|
||||
CM_Get_Device_ID(parent, buf, BUFSIZE, 0);
|
||||
pos = devInfoData.DevInst;
|
||||
|
||||
for(i = 0; i < 10; i++) {
|
||||
// Get the device instance of parent.
|
||||
if (CM_Get_Parent(&parent, pos, 0) != CR_SUCCESS) break;
|
||||
if (CM_Get_Device_ID(parent, temp, BUFSIZE, 0) == CR_SUCCESS) {
|
||||
if (ddebug) wprintf(L"device id: %s\n", temp); fflush(stdout);
|
||||
devid = PyUnicode_FromWideChar(temp, wcslen(temp));
|
||||
if (devid) {
|
||||
PyList_Append(candidates, devid);
|
||||
Py_DECREF(devid);
|
||||
}
|
||||
}
|
||||
pos = parent;
|
||||
}
|
||||
|
||||
return interfaceDetailData;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
winutil_get_mounted_volumes_for_usb_device(PyObject *self, PyObject *args) {
|
||||
unsigned int vid, pid, length, j;
|
||||
HDEVINFO hDevInfo;
|
||||
BOOL iterate = TRUE;
|
||||
winutil_get_removable_drives(PyObject *self, PyObject *args) {
|
||||
HDEVINFO hDevInfo;
|
||||
BOOL iterate = TRUE, ddebug = FALSE;
|
||||
PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData;
|
||||
DWORD i;
|
||||
WCHAR buf[BUFSIZE], volume[BUFSIZE], volume_id[BUFSIZE];
|
||||
unsigned int j, length;
|
||||
WCHAR volume[BUFSIZE];
|
||||
struct tagDrives g_drives[MAX_DRIVES];
|
||||
PyObject *volumes, *key, *val;
|
||||
PyObject *volumes, *key, *candidates, *pdebug = Py_False, *temp;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ii", &vid, &pid)) {
|
||||
if (!PyArg_ParseTuple(args, "|O", &pdebug)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ddebug = PyObject_IsTrue(pdebug);
|
||||
|
||||
volumes = PyDict_New();
|
||||
if (volumes == NULL) return NULL;
|
||||
|
||||
|
||||
for (j = 0; j < MAX_DRIVES; j++) g_drives[j].letter = 0;
|
||||
|
||||
@ -609,47 +621,44 @@ winutil_get_mounted_volumes_for_usb_device(PyObject *self, PyObject *args) {
|
||||
|
||||
// Enumerate through the set
|
||||
for (i=0; iterate; i++) {
|
||||
interfaceDetailData = get_device_grandparent(hDevInfo, i, buf, volume_id, &iterate);
|
||||
candidates = PyList_New(0);
|
||||
if (candidates == NULL) return PyErr_NoMemory();
|
||||
|
||||
interfaceDetailData = get_device_ancestors(hDevInfo, i, candidates, &iterate, ddebug);
|
||||
if (interfaceDetailData == NULL) {
|
||||
PyErr_Print(); continue;
|
||||
}
|
||||
debug("Device num: %d Device Id: %ws\n\n", i, buf);
|
||||
if (check_device_id(buf, vid, pid)) {
|
||||
debug("Device matches\n\n");
|
||||
length = wcslen(interfaceDetailData->DevicePath);
|
||||
interfaceDetailData->DevicePath[length] = '\\';
|
||||
interfaceDetailData->DevicePath[length+1] = 0;
|
||||
if(GetVolumeNameForVolumeMountPoint(interfaceDetailData->DevicePath, volume, BUFSIZE)) {
|
||||
|
||||
for(j = 0; j < MAX_DRIVES; j++) {
|
||||
// Compare volume mount point with the one stored earlier.
|
||||
// If both match, return the corresponding drive letter.
|
||||
if(g_drives[j].letter != 0 && wcscmp(g_drives[j].volume, volume)==0)
|
||||
{
|
||||
key = PyUnicode_FromWideChar(volume_id, wcslen(volume_id));
|
||||
val = PyString_FromFormat("%c", (char)g_drives[j].letter);
|
||||
if (key == NULL || val == NULL) {
|
||||
PyErr_NoMemory();
|
||||
PyMem_Free(interfaceDetailData);
|
||||
return NULL;
|
||||
}
|
||||
PyDict_SetItem(volumes, key, val);
|
||||
}
|
||||
length = wcslen(interfaceDetailData->DevicePath);
|
||||
interfaceDetailData->DevicePath[length] = L'\\';
|
||||
interfaceDetailData->DevicePath[length+1] = 0;
|
||||
|
||||
if (ddebug) wprintf(L"Device path: %s\n", interfaceDetailData->DevicePath); fflush(stdout);
|
||||
// On Vista+ DevicePath contains the information we need.
|
||||
temp = PyUnicode_FromWideChar(interfaceDetailData->DevicePath, length);
|
||||
if (temp == NULL) return PyErr_NoMemory();
|
||||
PyList_Append(candidates, temp);
|
||||
Py_DECREF(temp);
|
||||
if(GetVolumeNameForVolumeMountPointW(interfaceDetailData->DevicePath, volume, BUFSIZE)) {
|
||||
if (ddebug) wprintf(L"Volume: %s\n", volume); fflush(stdout);
|
||||
|
||||
for(j = 0; j < MAX_DRIVES; j++) {
|
||||
if(g_drives[j].letter != 0 && wcscmp(g_drives[j].volume, volume)==0) {
|
||||
if (ddebug) printf("Found drive: %c\n", (char)g_drives[j].letter); fflush(stdout);
|
||||
key = PyBytes_FromFormat("%c", (char)g_drives[j].letter);
|
||||
if (key == NULL) return PyErr_NoMemory();
|
||||
PyDict_SetItem(volumes, key, candidates);
|
||||
Py_DECREF(candidates);
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
debug("Failed to get volume name for volume mount point:\n");
|
||||
if (DEBUG) debug("%ws\n\n", format_last_error());
|
||||
}
|
||||
|
||||
PyMem_Free(interfaceDetailData);
|
||||
}
|
||||
|
||||
PyMem_Free(interfaceDetailData);
|
||||
} //for
|
||||
|
||||
SetupDiDestroyDeviceInfoList(hDevInfo);
|
||||
return volumes;
|
||||
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
@ -876,21 +885,22 @@ static PyMethodDef WinutilMethods[] = {
|
||||
"script being run. So to replace sys.argv, you should use "
|
||||
"sys.argv[1:] = argv()[1:]."},
|
||||
|
||||
{"is_usb_device_connected", winutil_is_usb_device_connected, METH_VARARGS,
|
||||
"is_usb_device_connected(vid, pid) -> bool\n\n"
|
||||
"Check if the USB device identified by VendorID: vid (integer) and"
|
||||
" ProductID: pid (integer) is currently connected."},
|
||||
{"is_usb_device_connected", winutil_is_usb_device_connected, METH_VARARGS,
|
||||
"is_usb_device_connected(vid, pid) -> bool\n\n"
|
||||
"Check if the USB device identified by VendorID: vid (integer) and"
|
||||
" ProductID: pid (integer) is currently connected."},
|
||||
|
||||
{"get_usb_devices", winutil_get_usb_devices, METH_VARARGS,
|
||||
"get_usb_devices() -> list of strings\n\n"
|
||||
"Return a list of the hardware IDs of all USB devices "
|
||||
"connected to the system."},
|
||||
|
||||
{"get_mounted_volumes_for_usb_device", winutil_get_mounted_volumes_for_usb_device, METH_VARARGS,
|
||||
"get_mounted_volumes_for_usb_device(vid, pid) -> dict\n\n"
|
||||
"Return a dictionary of volume_id:drive_letter for all"
|
||||
"volumes mounted on the system that belong to the"
|
||||
"usb device specified by vid (integer) and pid (integer)."},
|
||||
{"get_removable_drives", winutil_get_removable_drives, METH_VARARGS,
|
||||
"get_removable_drives(debug=False) -> dict\n\n"
|
||||
"Return mapping of all removable drives in the system. Maps drive letters "
|
||||
"to a list of device id strings, atleast one of which will carry the information "
|
||||
"needed for device matching. On Vista+ it is always the last string in the list. "
|
||||
"Note that you should upper case all strings."},
|
||||
|
||||
{"set_debug", winutil_set_debug, METH_VARARGS,
|
||||
"set_debug(bool)\n\nSet debugging mode."
|
||||
|
Loading…
x
Reference in New Issue
Block a user