Sync to trunk.

This commit is contained in:
John Schember 2010-01-12 18:13:25 -05:00
commit 5ea2953092
15 changed files with 233 additions and 233 deletions

View File

@ -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 import re
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
class ChristianScienceMonitor(BasicNewsRecipe): class ChristianScienceMonitor(BasicNewsRecipe):
title = 'Christian Science Monitor' author = 'Kovid Goyal, Sujata Raman and Lorenzo Vigentini'
description = 'Providing context and clarity on national and international news, peoples and cultures' description = 'Providing context and clarity on national and international news, peoples and cultures'
max_articles_per_feed = 20
__author__ = 'Kovid Goyal and Sujata Raman' 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' language = 'en'
encoding = 'utf-8' encoding = 'utf-8'
no_stylesheets = True timefmt = '[%a, %d %b, %Y]'
use_embedded_content = False
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 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 = [ keep_only_tags = [
dict(name='div', attrs={'id':['story','main']}), dict(name='div', attrs={'id':'mainColumn'}),
] ]
remove_tags = [ remove_tags = [
dict(name='div', attrs={'id':['story-tools','videoPlayer','storyRelatedBottom','enlarge-photo','photo-paginate']}), 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='ul', attrs={'class':[ 'centerliststories']}) ,
dict(name='form', attrs={'id':[ 'commentform']}) , 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

View File

@ -48,7 +48,9 @@ class NYTimes(BasicNewsRecipe):
return 'NY Times' return 'NY Times'
def parse_index(self): def parse_index(self):
self.encoding = 'cp1252'
soup = self.index_to_soup('http://www.nytimes.com/pages/todayspaper/index.html') soup = self.index_to_soup('http://www.nytimes.com/pages/todayspaper/index.html')
self.encoding = None
def feed_title(div): def feed_title(div):
return ''.join(div.findAll(text=True, recursive=False)).strip() return ''.join(div.findAll(text=True, recursive=False)).strip()

View File

@ -9,6 +9,8 @@ from calibre.web.feeds.news import BasicNewsRecipe
class Slashdot(BasicNewsRecipe): class Slashdot(BasicNewsRecipe):
title = u'Slashdot.org' 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 oldest_article = 7
max_articles_per_feed = 100 max_articles_per_feed = 100
language = 'en' language = 'en'

View File

@ -5,7 +5,7 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
Device drivers. Device drivers.
''' '''
import sys, os, time, pprint import sys, time, pprint
from functools import partial from functools import partial
from StringIO import StringIO from StringIO import StringIO
@ -29,7 +29,7 @@ def strftime(epoch, zone=time.gmtime):
def debug(ioreg_to_tmp=False, buf=None): def debug(ioreg_to_tmp=False, buf=None):
from calibre.customize.ui import device_plugins 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.constants import iswindows, isosx, __version__
from calibre import prints from calibre import prints
oldo, olde = sys.stdout, sys.stderr oldo, olde = sys.stdout, sys.stderr
@ -37,19 +37,11 @@ def debug(ioreg_to_tmp=False, buf=None):
if buf is None: if buf is None:
buf = StringIO() buf = StringIO()
sys.stdout = sys.stderr = buf sys.stdout = sys.stderr = buf
if iswindows:
import pythoncom
pythoncom.CoInitialize()
try: try:
out = partial(prints, file=buf) out = partial(prints, file=buf)
out('Version:', __version__) out('Version:', __version__)
wmi = Wmi =None
if iswindows:
wmi = __import__('wmi', globals(), locals(), [], -1)
Wmi = wmi.WMI(find_classes=False)
s = DeviceScanner() s = DeviceScanner()
s.wmi = Wmi
s.scan() s.scan()
devices = (s.devices) devices = (s.devices)
if not iswindows: if not iswindows:
@ -60,21 +52,9 @@ def debug(ioreg_to_tmp=False, buf=None):
out('USB devices on system:') out('USB devices on system:')
out(pprint.pformat(devices)) out(pprint.pformat(devices))
if iswindows: if iswindows:
drives = [] drives = win_pnp_drives(debug=True)
out('Drives detected:') out('Drives detected:')
out('\t', '(ID, Partitions, Drive letter)') out(pprint.pformat(drives))
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)
ioreg = None ioreg = None
if isosx: if isosx:
@ -84,13 +64,10 @@ def debug(ioreg_to_tmp=False, buf=None):
ioreg = 'Output from mount:\n\n'+mount+'\n\n'+ioreg ioreg = 'Output from mount:\n\n'+mount+'\n\n'+ioreg
connected_devices = [] connected_devices = []
for dev in device_plugins(): for dev in device_plugins():
owmi = getattr(dev, 'wmi', None)
dev.wmi = Wmi
out('Looking for', dev.__class__.__name__) out('Looking for', dev.__class__.__name__)
connected, det = s.is_device_connected(dev, debug=True) connected, det = s.is_device_connected(dev, debug=True)
if connected: if connected:
connected_devices.append((dev, det)) connected_devices.append((dev, det))
dev.wmi = owmi
errors = {} errors = {}
success = False success = False
@ -102,8 +79,6 @@ def debug(ioreg_to_tmp=False, buf=None):
out(' ') out(' ')
for dev, det in connected_devices: for dev, det in connected_devices:
out('Trying to open', dev.name, '...', end=' ') out('Trying to open', dev.name, '...', end=' ')
owmi = getattr(dev, 'wmi', None)
dev.wmi = Wmi
try: try:
dev.reset(detected_device=det) dev.reset(detected_device=det)
dev.open() dev.open()
@ -113,8 +88,6 @@ def debug(ioreg_to_tmp=False, buf=None):
errors[dev] = traceback.format_exc() errors[dev] = traceback.format_exc()
out('failed') out('failed')
continue continue
finally:
dev.wmi = owmi
success = True success = True
if hasattr(dev, '_main_prefix'): if hasattr(dev, '_main_prefix'):
out('Main memory:', repr(dev._main_prefix)) out('Main memory:', repr(dev._main_prefix))
@ -142,7 +115,4 @@ def debug(ioreg_to_tmp=False, buf=None):
finally: finally:
sys.stdout = oldo sys.stdout = oldo
sys.stderr = olde sys.stderr = olde
if iswindows:
import pythoncom
pythoncom.CoUninitialize()

View File

@ -60,7 +60,7 @@ class DevicePlugin(Plugin):
import traceback import traceback
traceback.print_exc() 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(): def id_iterator():
if hasattr(self.VENDOR_ID, 'keys'): if hasattr(self.VENDOR_ID, 'keys'):
@ -85,7 +85,7 @@ class DevicePlugin(Plugin):
self.test_bcd_windows(device_id, bcd): self.test_bcd_windows(device_id, bcd):
if debug: if debug:
self.print_usb_device_info(device_id) 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 True
return False return False
@ -97,7 +97,7 @@ class DevicePlugin(Plugin):
return True return True
return False 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. Return True, device_info if a device handled by this plugin is currently connected.
@ -105,7 +105,7 @@ class DevicePlugin(Plugin):
''' '''
if iswindows: if iswindows:
return self.is_usb_connected_windows(devices_on_system, 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_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] vendors = self.VENDOR_ID if hasattr(self.VENDOR_ID, '__len__') else [self.VENDOR_ID]
@ -147,7 +147,7 @@ class DevicePlugin(Plugin):
""" """
raise NotImplementedError() 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 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 capable of handling it. If it is not it should return False. This method

View File

@ -9,7 +9,7 @@ For usage information run the script.
import StringIO, sys, time, os import StringIO, sys, time, os
from optparse import OptionParser from optparse import OptionParser
from calibre import __version__, iswindows, __appname__ from calibre import __version__, __appname__
from calibre.devices.errors import PathError from calibre.devices.errors import PathError
from calibre.utils.terminfo import TerminalController from calibre.utils.terminfo import TerminalController
from calibre.devices.errors import ArgumentError, DeviceError, DeviceLocked from calibre.devices.errors import ArgumentError, DeviceError, DeviceLocked
@ -198,14 +198,9 @@ def main():
args = args[1:] args = args[1:]
dev = None dev = None
scanner = DeviceScanner() scanner = DeviceScanner()
if iswindows:
import wmi, pythoncom
pythoncom.CoInitialize()
scanner.wmi = wmi.WMI(find_classes=False)
scanner.scan() scanner.scan()
connected_devices = [] connected_devices = []
for d in device_plugins(): for d in device_plugins():
d.wmi = scanner.wmi
ok, det = scanner.is_device_connected(d) ok, det = scanner.is_device_connected(d)
if ok: if ok:
dev = d dev = d

View File

@ -6,6 +6,7 @@ manner.
''' '''
import sys, os import sys, os
from threading import RLock
from calibre import iswindows, isosx, plugins, islinux from calibre import iswindows, isosx, plugins, islinux
@ -22,6 +23,54 @@ elif isosx:
except: except:
raise RuntimeError('Failed to load the usbobserver plugin: %s'%plugins['usbobserver'][1]) 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): class LinuxScanner(object):
SYSFS_PATH = os.environ.get('SYSFS_PATH', '/sys') SYSFS_PATH = os.environ.get('SYSFS_PATH', '/sys')
@ -85,26 +134,13 @@ class DeviceScanner(object):
raise RuntimeError('DeviceScanner requires the /sys filesystem to work.') raise RuntimeError('DeviceScanner requires the /sys filesystem to work.')
self.scanner = win_scanner if iswindows else osx_scanner if isosx else linux_scanner self.scanner = win_scanner if iswindows else osx_scanner if isosx else linux_scanner
self.devices = [] self.devices = []
self.wmi = None
self.pnp_ids = set([])
self.rescan_pnp_ids = True
def scan(self): def scan(self):
'''Fetch list of connected USB devices from operating system''' '''Fetch list of connected USB devices from operating system'''
self.devices = self.scanner() 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): 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): def main(args=sys.argv):

View File

@ -203,18 +203,6 @@ class Device(DeviceConfig, DevicePlugin):
return False 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): def windows_sort_drives(self, drives):
''' '''
Called to disambiguate main memory and storage card for devices that Called to disambiguate main memory and storage card for devices that
@ -223,8 +211,10 @@ class Device(DeviceConfig, DevicePlugin):
''' '''
return drives return drives
def can_handle_windows(self, device_id, pnp_id_iterator, debug=False): def can_handle_windows(self, device_id, debug=False):
for pnp_id in pnp_id_iterator(): 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'): if self.windows_match_device(pnp_id, 'WINDOWS_MAIN_MEM'):
return True return True
if debug: if debug:
@ -232,29 +222,20 @@ class Device(DeviceConfig, DevicePlugin):
return False return False
def open_windows(self): def open_windows(self):
from calibre.devices.scanner import win_pnp_drives
def matches_q(drive, attr): time.sleep(5)
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)
drives = {} drives = {}
c = self.wmi for drive, pnp_id in win_pnp_drives().items():
for drive in c.Win32_DiskDrive(): if self.windows_match_device(pnp_id, 'WINDOWS_CARD_A_MEM') and \
pnp_id = str(drive.PNPDeviceID) not drives.get('carda', False):
if self.windows_match_device(pnp_id, 'WINDOWS_CARD_A_MEM') and not drives.get('carda', None): drives['carda'] = drive
drives['carda'] = self.windows_get_drive_prefix(drive) elif self.windows_match_device(pnp_id, 'WINDOWS_CARD_B_MEM') and \
elif self.windows_match_device(pnp_id, 'WINDOWS_CARD_B_MEM') and not drives.get('cardb', None): not drives.get('cardb', False):
drives['cardb'] = self.windows_get_drive_prefix(drive) drives['cardb'] = drive
elif self.windows_match_device(pnp_id, 'WINDOWS_MAIN_MEM') and not drives.get('main', None): elif self.windows_match_device(pnp_id, 'WINDOWS_MAIN_MEM') and \
drives['main'] = self.windows_get_drive_prefix(drive) not drives.get('main', False):
drives['main'] = drive
if 'main' in drives.keys() and 'carda' in drives.keys() and \ if 'main' in drives.keys() and 'carda' in drives.keys() and \
'cardb' in drives.keys(): 'cardb' in drives.keys():

View File

@ -168,6 +168,7 @@ class Stylizer(object):
self.rules = rules self.rules = rules
self._styles = {} self._styles = {}
class_sel_pat = re.compile(r'\.[a-z]+', re.IGNORECASE) class_sel_pat = re.compile(r'\.[a-z]+', re.IGNORECASE)
capital_sel_pat = re.compile(r'h|[A-Z]+')
for _, _, cssdict, text, _ in rules: for _, _, cssdict, text, _ in rules:
try: try:
selector = CSSSelector(text) selector = CSSSelector(text)
@ -176,6 +177,15 @@ class Stylizer(object):
SelectorSyntaxError): SelectorSyntaxError):
continue continue
matches = selector(tree) 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): if not matches and class_sel_pat.match(text):
found = False found = False
for x in tree.xpath('//*[@class]'): for x in tree.xpath('//*[@class]'):

View File

@ -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, \ from calibre.customize.ui import available_input_formats, available_output_formats, \
device_plugins device_plugins
from calibre.devices.interface import DevicePlugin from calibre.devices.interface import DevicePlugin
from calibre.constants import iswindows
from calibre.gui2.dialogs.choose_format import ChooseFormatDialog from calibre.gui2.dialogs.choose_format import ChooseFormatDialog
from calibre.utils.ipc.job import BaseJob from calibre.utils.ipc.job import BaseJob
from calibre.devices.scanner import DeviceScanner from calibre.devices.scanner import DeviceScanner
@ -85,7 +84,6 @@ class DeviceManager(Thread):
self.job_manager = job_manager self.job_manager = job_manager
self.current_job = None self.current_job = None
self.scanner = DeviceScanner() self.scanner = DeviceScanner()
self.wmi = None
self.connected_device = None self.connected_device = None
self.ejected_devices = set([]) self.ejected_devices = set([])
@ -133,7 +131,6 @@ class DeviceManager(Thread):
self.connected_device = None self.connected_device = None
def detect_device(self): def detect_device(self):
self.scanner.rescan_pnp_ids = not self.is_device_connected
self.scanner.scan() self.scanner.scan()
if self.is_device_connected: if self.is_device_connected:
connected, detected_device = \ connected, detected_device = \
@ -170,30 +167,18 @@ class DeviceManager(Thread):
pass pass
def run(self): def run(self):
if iswindows: while self.keep_going:
import pythoncom self.detect_device()
pythoncom.CoInitialize() while True:
wmi = __import__('wmi', globals(), locals(), [], -1) job = self.next()
self.wmi = wmi.WMI(find_classes=False) if job is not None:
self.scanner.wmi = self.wmi self.current_job = job
for x in self.devices: self.device.set_progress_reporter(job.report_progress)
x.wmi = self.wmi self.current_job.run()
try: self.current_job = None
while self.keep_going: else:
self.detect_device() break
while True: time.sleep(self.sleep_time)
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={}): def create_job(self, func, done, description, args=[], kwargs={}):

View File

@ -7,7 +7,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>838</width> <width>884</width>
<height>730</height> <height>730</height>
</rect> </rect>
</property> </property>
@ -89,7 +89,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>562</width> <width>608</width>
<height>683</height> <height>683</height>
</rect> </rect>
</property> </property>

View File

@ -171,7 +171,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
if self._add_formats(paths): if self._add_formats(paths):
event.accept() event.accept()
def remove_format(self, x=None): def remove_format(self, *args):
rows = self.formats.selectionModel().selectedRows(0) rows = self.formats.selectionModel().selectedRows(0)
for row in rows: for row in rows:
self.formats.takeItem(row.row()) self.formats.takeItem(row.row())

View File

@ -23,9 +23,10 @@ KEY = Qt.UserRole + 3
class Customize(QFrame, Ui_Frame): class Customize(QFrame, Ui_Frame):
def __init__(self, dup_check, parent=None): def __init__(self, index, dup_check, parent=None):
QFrame.__init__(self, parent) QFrame.__init__(self, parent)
self.setupUi(self) self.setupUi(self)
self.data_model = index.model()
self.setFocusPolicy(Qt.StrongFocus) self.setFocusPolicy(Qt.StrongFocus)
self.setAutoFillBackground(True) self.setAutoFillBackground(True)
self.custom.toggled.connect(self.custom_toggled) self.custom.toggled.connect(self.custom_toggled)
@ -86,12 +87,21 @@ class Delegate(QStyledItemDelegate):
def __init__(self, parent=None): def __init__(self, parent=None):
QStyledItemDelegate.__init__(self, parent) QStyledItemDelegate.__init__(self, parent)
self.editing_indices = {} self.editing_indices = {}
self.closeEditor.connect(self.editing_done)
def to_doc(self, index): def to_doc(self, index):
doc = QTextDocument() doc = QTextDocument()
doc.setHtml(index.data().toString()) doc.setHtml(index.data().toString())
return doc 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): def sizeHint(self, option, index):
if index.row() in self.editing_indices: if index.row() in self.editing_indices:
return QSize(200, 200) return QSize(200, 200)
@ -111,7 +121,7 @@ class Delegate(QStyledItemDelegate):
painter.restore() painter.restore()
def createEditor(self, parent, option, index): 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.editing_indices[index.row()] = w
self.sizeHintChanged.emit(index) self.sizeHintChanged.emit(index)
return w return w
@ -135,8 +145,6 @@ class Delegate(QStyledItemDelegate):
setattr(editor, 'shortcut%d'%(x+1), seq) setattr(editor, 'shortcut%d'%(x+1), seq)
def setModelData(self, editor, model, index): def setModelData(self, editor, model, index):
self.editing_indices.pop(index.row())
self.sizeHintChanged.emit(index)
self.closeEditor.emit(editor, self.NoHint) self.closeEditor.emit(editor, self.NoHint)
custom = [] custom = []
if editor.custom.isChecked(): if editor.custom.isChecked():

View File

@ -141,8 +141,8 @@ class FormatList(QListWidget):
if event.key() == Qt.Key_Delete: if event.key() == Qt.Key_Delete:
self.emit(SIGNAL('delete_format()')) self.emit(SIGNAL('delete_format()'))
else: else:
QListWidget.keyPressEvent(self, event) return QListWidget.keyPressEvent(self, event)
class ImageView(QLabel): class ImageView(QLabel):

View File

@ -204,23 +204,22 @@ get_registry_property(HDEVINFO hDevInfo, DWORD index, DWORD property, BOOL *iter
return buffer; return buffer;
} }
static BOOL static BOOL
check_device_id(LPTSTR buffer, unsigned int vid, unsigned int pid) { check_device_id(LPTSTR buffer, unsigned int vid, unsigned int pid) {
WCHAR xVid[9], dVid[9], xPid[9], dPid[9]; WCHAR xVid[9], dVid[9], xPid[9], dPid[9];
unsigned int j; unsigned int j;
swprintf(xVid, L"vid_%4.4x", vid); _snwprintf_s(xVid, 9, _TRUNCATE, L"vid_%4.4x", vid);
swprintf(dVid, L"vid_%4.4d", vid); _snwprintf_s(dVid, 9, _TRUNCATE, L"vid_%4.4d", vid);
swprintf(xPid, L"pid_%4.4x", pid); _snwprintf_s(xPid, 9, _TRUNCATE, L"pid_%4.4x", pid);
swprintf(dPid, L"pid_%4.4d", pid); _snwprintf_s(dPid, 9, _TRUNCATE, L"pid_%4.4d", pid);
for (j = 0; j < wcslen(buffer); j++) buffer[j] = tolower(buffer[j]); for (j = 0; j < wcslen(buffer); j++) buffer[j] = tolower(buffer[j]);
return ( (wcsstr(buffer, xVid) != NULL || wcsstr(buffer, dVid) != NULL ) && return ( (wcsstr(buffer, xVid) != NULL || wcsstr(buffer, dVid) != NULL ) &&
(wcsstr(buffer, xPid) != NULL || wcsstr(buffer, dPid) != NULL ) (wcsstr(buffer, xPid) != NULL || wcsstr(buffer, dPid) != NULL )
); );
} }
static HDEVINFO static HDEVINFO
create_device_info_set(LPGUID guid, PCTSTR enumerator, HWND parent, DWORD flags) { create_device_info_set(LPGUID guid, PCTSTR enumerator, HWND parent, DWORD flags) {
HDEVINFO hDevInfo; HDEVINFO hDevInfo;
@ -286,7 +285,7 @@ get_all_removable_disks(struct tagDrives *g_drives)
if(GetVolumeNameForVolumeMountPoint(caDrive, volume, BUFSIZE)) if(GetVolumeNameForVolumeMountPoint(caDrive, volume, BUFSIZE))
{ {
g_drives[g_count].letter = caDrive[0]; 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 ++; g_count ++;
} }
@ -515,15 +514,17 @@ winutil_eject_drive(PyObject *self, PyObject *args) {
PSP_DEVICE_INTERFACE_DETAIL_DATA PSP_DEVICE_INTERFACE_DETAIL_DATA
get_device_grandparent(HDEVINFO hDevInfo, DWORD index, PWSTR buf, PWSTR volume_id, get_device_ancestors(HDEVINFO hDevInfo, DWORD index, PyObject *candidates, BOOL *iterate, BOOL ddebug) {
BOOL *iterate) {
SP_DEVICE_INTERFACE_DATA interfaceData; SP_DEVICE_INTERFACE_DATA interfaceData;
SP_DEVINFO_DATA devInfoData; SP_DEVINFO_DATA devInfoData;
BOOL status; BOOL status;
PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData; PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData;
DWORD interfaceDetailDataSize, DWORD interfaceDetailDataSize,
reqSize; reqSize;
DEVINST parent; DEVINST parent, pos;
wchar_t temp[BUFSIZE];
int i;
PyObject *devid;
interfaceData.cbSize = sizeof (SP_INTERFACE_DEVICE_DATA); interfaceData.cbSize = sizeof (SP_INTERFACE_DEVICE_DATA);
devInfoData.cbSize = sizeof (SP_DEVINFO_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; 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 ) { if ( interfaceDetailData == NULL ) {
PyErr_NoMemory(); PyErr_NoMemory();
return NULL; return NULL;
@ -563,38 +564,49 @@ get_device_grandparent(HDEVINFO hDevInfo, DWORD index, PWSTR buf, PWSTR volume_i
interfaceDetailDataSize, // Interface detail data size interfaceDetailDataSize, // Interface detail data size
&reqSize, // Buffer size required to get the detail data &reqSize, // Buffer size required to get the detail data
&devInfoData); // Interface device info &devInfoData); // Interface device info
if (ddebug) printf("Getting ancestors\n"); fflush(stdout);
if ( status == FALSE ) {PyErr_SetFromWindowsErr(0); PyMem_Free(interfaceDetailData); return NULL;} if ( status == FALSE ) {PyErr_SetFromWindowsErr(0); PyMem_Free(interfaceDetailData); return NULL;}
// Get the device instance of parent. This points to USBSTOR. pos = devInfoData.DevInst;
CM_Get_Parent(&parent, devInfoData.DevInst, 0);
// Get the device ID of the USBSTORAGE volume for(i = 0; i < 10; i++) {
CM_Get_Device_ID(parent, volume_id, BUFSIZE, 0); // Get the device instance of parent.
// Get the device instance of grand parent. This points to USB root. if (CM_Get_Parent(&parent, pos, 0) != CR_SUCCESS) break;
CM_Get_Parent(&parent, parent, 0); if (CM_Get_Device_ID(parent, temp, BUFSIZE, 0) == CR_SUCCESS) {
// Get the device ID of the USB root. if (ddebug) wprintf(L"device id: %s\n", temp); fflush(stdout);
CM_Get_Device_ID(parent, buf, BUFSIZE, 0); devid = PyUnicode_FromWideChar(temp, wcslen(temp));
if (devid) {
PyList_Append(candidates, devid);
Py_DECREF(devid);
}
}
pos = parent;
}
return interfaceDetailData; return interfaceDetailData;
} }
static PyObject * static PyObject *
winutil_get_mounted_volumes_for_usb_device(PyObject *self, PyObject *args) { winutil_get_removable_drives(PyObject *self, PyObject *args) {
unsigned int vid, pid, length, j; HDEVINFO hDevInfo;
HDEVINFO hDevInfo; BOOL iterate = TRUE, ddebug = FALSE;
BOOL iterate = TRUE;
PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData; PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData;
DWORD i; DWORD i;
WCHAR buf[BUFSIZE], volume[BUFSIZE], volume_id[BUFSIZE]; unsigned int j, length;
WCHAR volume[BUFSIZE];
struct tagDrives g_drives[MAX_DRIVES]; 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; return NULL;
} }
ddebug = PyObject_IsTrue(pdebug);
volumes = PyDict_New(); volumes = PyDict_New();
if (volumes == NULL) return NULL; if (volumes == NULL) return NULL;
for (j = 0; j < MAX_DRIVES; j++) g_drives[j].letter = 0; 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 // Enumerate through the set
for (i=0; iterate; i++) { 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) { if (interfaceDetailData == NULL) {
PyErr_Print(); continue; 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++) { length = wcslen(interfaceDetailData->DevicePath);
// Compare volume mount point with the one stored earlier. interfaceDetailData->DevicePath[length] = L'\\';
// If both match, return the corresponding drive letter. interfaceDetailData->DevicePath[length+1] = 0;
if(g_drives[j].letter != 0 && wcscmp(g_drives[j].volume, volume)==0)
{ if (ddebug) wprintf(L"Device path: %s\n", interfaceDetailData->DevicePath); fflush(stdout);
key = PyUnicode_FromWideChar(volume_id, wcslen(volume_id)); // On Vista+ DevicePath contains the information we need.
val = PyString_FromFormat("%c", (char)g_drives[j].letter); temp = PyUnicode_FromWideChar(interfaceDetailData->DevicePath, length);
if (key == NULL || val == NULL) { if (temp == NULL) return PyErr_NoMemory();
PyErr_NoMemory(); PyList_Append(candidates, temp);
PyMem_Free(interfaceDetailData); Py_DECREF(temp);
return NULL; if(GetVolumeNameForVolumeMountPointW(interfaceDetailData->DevicePath, volume, BUFSIZE)) {
} if (ddebug) wprintf(L"Volume: %s\n", volume); fflush(stdout);
PyDict_SetItem(volumes, key, val);
} 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 } //for
SetupDiDestroyDeviceInfoList(hDevInfo); SetupDiDestroyDeviceInfoList(hDevInfo);
return volumes; return volumes;
} }
static PyObject * static PyObject *
@ -876,21 +885,22 @@ static PyMethodDef WinutilMethods[] = {
"script being run. So to replace sys.argv, you should use " "script being run. So to replace sys.argv, you should use "
"sys.argv[1:] = argv()[1:]."}, "sys.argv[1:] = argv()[1:]."},
{"is_usb_device_connected", winutil_is_usb_device_connected, METH_VARARGS, {"is_usb_device_connected", winutil_is_usb_device_connected, METH_VARARGS,
"is_usb_device_connected(vid, pid) -> bool\n\n" "is_usb_device_connected(vid, pid) -> bool\n\n"
"Check if the USB device identified by VendorID: vid (integer) and" "Check if the USB device identified by VendorID: vid (integer) and"
" ProductID: pid (integer) is currently connected."}, " ProductID: pid (integer) is currently connected."},
{"get_usb_devices", winutil_get_usb_devices, METH_VARARGS, {"get_usb_devices", winutil_get_usb_devices, METH_VARARGS,
"get_usb_devices() -> list of strings\n\n" "get_usb_devices() -> list of strings\n\n"
"Return a list of the hardware IDs of all USB devices " "Return a list of the hardware IDs of all USB devices "
"connected to the system."}, "connected to the system."},
{"get_mounted_volumes_for_usb_device", winutil_get_mounted_volumes_for_usb_device, METH_VARARGS, {"get_removable_drives", winutil_get_removable_drives, METH_VARARGS,
"get_mounted_volumes_for_usb_device(vid, pid) -> dict\n\n" "get_removable_drives(debug=False) -> dict\n\n"
"Return a dictionary of volume_id:drive_letter for all" "Return mapping of all removable drives in the system. Maps drive letters "
"volumes mounted on the system that belong to the" "to a list of device id strings, atleast one of which will carry the information "
"usb device specified by vid (integer) and pid (integer)."}, "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", winutil_set_debug, METH_VARARGS,
"set_debug(bool)\n\nSet debugging mode." "set_debug(bool)\n\nSet debugging mode."