From 91350fc1284bb3207a62be4552cdf5e0bdde8408 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Sun, 1 May 2011 16:21:13 +0100 Subject: [PATCH 01/16] Add another Samsung card ID (SGH-T849_CARD) to WINDOWS_CARD_A_MEM. --- src/calibre/devices/android/driver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/devices/android/driver.py b/src/calibre/devices/android/driver.py index 359dae89fe..f500560f97 100644 --- a/src/calibre/devices/android/driver.py +++ b/src/calibre/devices/android/driver.py @@ -112,7 +112,7 @@ class ANDROID(USBMS): 'MB860', 'MULTI-CARD', 'MID7015A', 'INCREDIBLE', 'A7EB'] WINDOWS_CARD_A_MEM = ['ANDROID_PHONE', 'GT-I9000_CARD', 'SGH-I897', 'FILE-STOR_GADGET', 'SGH-T959', 'SAMSUNG_ANDROID', 'GT-P1000_CARD', - 'A70S', 'A101IT', '7', 'INCREDIBLE', 'A7EB'] + 'A70S', 'A101IT', '7', 'INCREDIBLE', 'A7EB', 'SGH-T849_CARD'] OSX_MAIN_MEM = 'Android Device Main Memory' From bab502e6543b2997158b23a72d6f41e119e15136 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 1 May 2011 09:58:55 -0600 Subject: [PATCH 02/16] Fix Brand Eins --- recipes/brand_eins.recipe | 13 ++++++++----- src/calibre/manual/faq.rst | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/recipes/brand_eins.recipe b/recipes/brand_eins.recipe index 15e1d3ccca..e6fe57b334 100644 --- a/recipes/brand_eins.recipe +++ b/recipes/brand_eins.recipe @@ -3,7 +3,8 @@ __license__ = 'GPL v3' __copyright__ = '2010, Constantin Hofstetter , Steffen Siebert ' -__version__ = '0.98' # 2011-04-10 +__version__ = '0.98' + ''' http://brandeins.de - Wirtschaftsmagazin ''' import re import string @@ -13,8 +14,8 @@ from calibre.web.feeds.recipes import BasicNewsRecipe class BrandEins(BasicNewsRecipe): title = u'brand eins' - __author__ = 'Constantin Hofstetter; Steffen Siebert' - description = u'Wirtschaftsmagazin: Gets the last full issue on default. Set a integer value for the username-field to get older issues: 1 -> the newest (but not complete) issue, 2 -> the last complete issue (default), 3 -> the issue before 2 etc.' + __author__ = 'Constantin Hofstetter' + description = u'Wirtschaftsmagazin' publisher ='brandeins.de' category = 'politics, business, wirtschaft, Germany' use_embedded_content = False @@ -105,10 +106,11 @@ class BrandEins(BasicNewsRecipe): keys = issue_map.keys() keys.sort() keys.reverse() - selected_issue = issue_map[keys[issue-1]] + selected_issue_key = keys[issue - 1] + selected_issue = issue_map[selected_issue_key] url = selected_issue.get('href', False) # Get the title for the magazin - build it out of the title of the cover - take the issue and year; - self.title = "brand eins "+ re.search(r"(?P\d\d\/\d\d\d\d)", selected_issue.find('img').get('title', False)).group('date') + self.title = "brand eins " + selected_issue_key[4:] + "/" + selected_issue_key[0:4] url = 'http://brandeins.de/'+url # url = "http://www.brandeins.de/archiv/magazin/tierisch.html" @@ -161,3 +163,4 @@ class BrandEins(BasicNewsRecipe): current_articles.append({'title': title, 'url': url, 'description': description, 'date':''}) titles_and_articles.append([chapter_title, current_articles]) return titles_and_articles + diff --git a/src/calibre/manual/faq.rst b/src/calibre/manual/faq.rst index 816ce7c496..08ebb6506b 100644 --- a/src/calibre/manual/faq.rst +++ b/src/calibre/manual/faq.rst @@ -468,7 +468,7 @@ If it still wont launch, start a command prompt (press the windows key and R; th Post any output you see in a help message on the `Forum `_. -|app| freeze when I click on anything? +|app| freezes when I click on anything? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There are three possible things I know of, that can cause this: From 186a47da8ce95287db54d0706ff556a4363d0860 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 1 May 2011 10:33:10 -0600 Subject: [PATCH 03/16] Fix #774743 (Calibre Crash on read [open by (v) from edit-screen]) --- src/calibre/gui2/actions/view.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/gui2/actions/view.py b/src/calibre/gui2/actions/view.py index c93e69f0fc..6cf5c5d5af 100644 --- a/src/calibre/gui2/actions/view.py +++ b/src/calibre/gui2/actions/view.py @@ -60,7 +60,7 @@ class ViewAction(InterfaceAction): def build_menus(self, db): self.view_menu.clear() - self.view_menu.addAction(self.qaction) + self.view_menu.addAction(self.view_action) self.view_menu.addAction(self.view_specific_action) self.view_menu.addSeparator() self.view_menu.addAction(self.action_pick_random) From 9a32f09a71ba49f727f1c298bf79915bd18f6e98 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 1 May 2011 10:46:42 -0600 Subject: [PATCH 04/16] MOBI Input: Handle MOBI files with empty tags correctly. Fixes #774785 (Private bug) --- src/calibre/ebooks/mobi/reader.py | 5 +++++ src/calibre/ebooks/oeb/base.py | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/calibre/ebooks/mobi/reader.py b/src/calibre/ebooks/mobi/reader.py index d9c6853795..3d858864a8 100644 --- a/src/calibre/ebooks/mobi/reader.py +++ b/src/calibre/ebooks/mobi/reader.py @@ -253,6 +253,8 @@ class MobiReader(object): .italic { font-style: italic } + .underline { text-decoration: underline } + .mbp_pagebreak { page-break-after: always; margin: 0; display: block } @@ -601,6 +603,9 @@ class MobiReader(object): elif tag.tag == 'i': tag.tag = 'span' tag.attrib['class'] = 'italic' + elif tag.tag == 'u': + tag.tag = 'span' + tag.attrib['class'] = 'underline' elif tag.tag == 'b': tag.tag = 'span' tag.attrib['class'] = 'bold' diff --git a/src/calibre/ebooks/oeb/base.py b/src/calibre/ebooks/oeb/base.py index 1f71e32548..db83fca496 100644 --- a/src/calibre/ebooks/oeb/base.py +++ b/src/calibre/ebooks/oeb/base.py @@ -1049,8 +1049,8 @@ class Manifest(object): # Remove hyperlinks with no content as they cause rendering # artifacts in browser based renderers - # Also remove empty and tags - for a in xpath(data, '//h:a[@href]|//h:i|//h:b'): + # Also remove empty , and tags + for a in xpath(data, '//h:a[@href]|//h:i|//h:b|//h:u'): if a.get('id', None) is None and a.get('name', None) is None \ and len(a) == 0 and not a.text: remove_elem(a) From 7bfa82b98308f18e7d53a590417d0dd378893416 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 1 May 2011 13:50:24 -0600 Subject: [PATCH 05/16] Fix #775048 (spelling mistake on website) --- src/calibre/manual/faq.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/manual/faq.rst b/src/calibre/manual/faq.rst index 08ebb6506b..2e2a8e5ae6 100644 --- a/src/calibre/manual/faq.rst +++ b/src/calibre/manual/faq.rst @@ -557,7 +557,7 @@ You have two choices: How is |app| licensed? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -|app| is licensed under the GNU General Public License v3 (an open source license). This means that you are free to redistribute |app| as long as you make the source code available. So if you want to put |app| on a CD with your product, you must also put the |app| source code on the CD. The source code is available for download `from googlecode `_. You are free to use the results of conversions from |app| however you want. You cannot use code, libraries from |app| in your software without maing your software open source. For details, see `The GNU GPL v3 `_. +|app| is licensed under the GNU General Public License v3 (an open source license). This means that you are free to redistribute |app| as long as you make the source code available. So if you want to put |app| on a CD with your product, you must also put the |app| source code on the CD. The source code is available for download `from googlecode `_. You are free to use the results of conversions from |app| however you want. You cannot use code, libraries from |app| in your software without making your software open source. For details, see `The GNU GPL v3 `_. How do I run calibre from my USB stick? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 255fe03b289000c46f83eb4a2c93362e8179be53 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 2 May 2011 12:25:45 +0100 Subject: [PATCH 06/16] First attempt at a user_defined device --- src/calibre/customize/builtins.py | 2 + src/calibre/devices/__init__.py | 52 ++++++++++ src/calibre/devices/user_defined/__init__.py | 0 src/calibre/devices/user_defined/driver.py | 86 +++++++++++++++++ .../gui2/preferences/device_user_defined.py | 94 +++++++++++++++++++ src/calibre/gui2/preferences/misc.py | 6 ++ src/calibre/gui2/preferences/misc.ui | 9 +- 7 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 src/calibre/devices/user_defined/__init__.py create mode 100644 src/calibre/devices/user_defined/driver.py create mode 100644 src/calibre/gui2/preferences/device_user_defined.py diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index 36bcbdbfe2..776b04d5f6 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -595,6 +595,7 @@ from calibre.devices.jetbook.driver import JETBOOK, MIBUK, JETBOOK_MINI from calibre.devices.kindle.driver import KINDLE, KINDLE2, KINDLE_DX from calibre.devices.nook.driver import NOOK, NOOK_COLOR from calibre.devices.prs505.driver import PRS505 +from calibre.devices.user_defined.driver import USER_DEFINED from calibre.devices.android.driver import ANDROID, S60 from calibre.devices.nokia.driver import N770, N810, E71X, E52 from calibre.devices.eslick.driver import ESLICK, EBK52 @@ -742,6 +743,7 @@ plugins += [ EEEREADER, NEXTBOOK, ITUNES, + USER_DEFINED, ] plugins += [x for x in list(locals().values()) if isinstance(x, type) and \ x.__name__.endswith('MetadataReader')] diff --git a/src/calibre/devices/__init__.py b/src/calibre/devices/__init__.py index 63b0b89a17..d151ae1844 100644 --- a/src/calibre/devices/__init__.py +++ b/src/calibre/devices/__init__.py @@ -156,3 +156,55 @@ def debug(ioreg_to_tmp=False, buf=None): sys.stdout = oldo sys.stderr = olde +def device_info(ioreg_to_tmp=False, buf=None): + from calibre.devices.scanner import DeviceScanner, win_pnp_drives + from calibre.constants import iswindows + from calibre import prints + import re + + res = {} + if not iswindows: + return None + try: + s = DeviceScanner() + s.scan() + devices = (s.devices) + device_details = {} + device_set = set() + for dev in devices: + vid = re.search('vid_([0-9a-f]*)&', dev) + if vid: + vid = vid.group(1) + pid = re.search('pid_([0-9a-f]*)&', dev) + if pid: + pid = pid.group(1) + rev = re.search('rev_([0-9a-f]*)$', dev) + if rev: + rev = rev.group(1) + d = vid+pid+rev + prints(d) + device_set.add(d) + device_details[d] = (vid, pid, rev) + res['device_set'] = device_set + res['device_details'] = device_details + drives = win_pnp_drives(debug=False) + drive_details = {} + print drives + drive_set = set() + for drive,details in drives.iteritems(): + order = 'ORD_' + str(drive.order) + ven = re.search('VEN_([^&]*)&', details) + if ven: + ven = ven.group(1) + prod = re.search('PROD_([^&]*)&', details) + if prod: + prod = prod.group(1) + d = (order, ven, prod) + print d + drive_details[drive] = d + drive_set.add(drive) + res['drive_details'] = drive_details + res['drive_set'] = drive_set + finally: + pass + return res \ No newline at end of file diff --git a/src/calibre/devices/user_defined/__init__.py b/src/calibre/devices/user_defined/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/calibre/devices/user_defined/driver.py b/src/calibre/devices/user_defined/driver.py new file mode 100644 index 0000000000..682ed1712e --- /dev/null +++ b/src/calibre/devices/user_defined/driver.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- + +__license__ = 'GPL v3' +__copyright__ = '2009, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + +from calibre.devices.usbms.driver import USBMS +from calibre.ebooks import BOOK_EXTENSIONS + +class USER_DEFINED(USBMS): + + name = 'User Defined USB driver' + gui_name = 'User Defined phone' + author = 'Kovid Goyal' + supported_platforms = ['windows', 'osx', 'linux'] + + # Ordered list of supported formats + FORMATS = BOOK_EXTENSIONS + + VENDOR_ID = 0xFFFF + PRODUCT_ID = 0xFFFF + BCD = None + + EBOOK_DIR_MAIN = '' + EBOOK_DIR_CARD_A = '' + + VENDOR_NAME = [] + WINDOWS_MAIN_MEM = '' + WINDOWS_CARD_A_MEM = '' + + OSX_MAIN_MEM = 'Device Main Memory' + + MAIN_MEMORY_VOLUME_LABEL = 'Device Main Memory' + + SUPPORTS_SUB_DIRS = True + + EXTRA_CUSTOMIZATION_MESSAGE = [ + _('USB Vendor ID (in hex)'), + _('USB Product ID (in hex)'), + _('USB Revision ID (in hex)'), + _('Windows main memory vendor string'), + _('Windows main memory ID string'), + _('Windows card A vendor string'), + _('Windows card A ID string'), + _('Main memory folder'), + _('Card A folder'), + ] + EXTRA_CUSTOMIZATION_DEFAULT = [ + '0x0000', + '0x0000', + '0x0000', + '', + '', + '', + '', + '', + '', + ] + OPT_USB_VENDOR_ID = 0 + OPT_USB_PRODUCT_ID = 1 + OPT_USB_REVISION_ID = 2 + OPT_USB_WINDOWS_MM_VEN_ID = 3 + OPT_USB_WINDOWS_MM_ID = 4 + OPT_USB_WINDOWS_CA_VEN_ID = 5 + OPT_USB_WINDOWS_CA_ID = 6 + OPT_MAIN_MEM_FOLDER = 7 + OPT_CARD_A_FOLDER = 8 + + def __init__(self, *args): + USBMS.__init__(self, args) + try: + e = self.settings().extra_customization + self.VENDOR_ID = int(e[self.OPT_USB_VENDOR_ID], 16) + self.PRODUCT_ID = int(e[self.OPT_USB_PRODUCT_ID], 16) + self.BCD = [int(e[self.OPT_USB_REVISION_ID], 16)] + print '%x, %x, %s' %(self.VENDOR_ID, self.PRODUCT_ID, str(self.BCD)) + if e[self.OPT_USB_WINDOWS_MM_VEN_ID]: + self.VENDOR_NAME.append(e[self.OPT_USB_WINDOWS_MM_VEN_ID]) + if e[self.OPT_USB_WINDOWS_CA_VEN_ID]: + self.VENDOR_NAME.append(e[self.OPT_USB_WINDOWS_CA_VEN_ID]) + self.WINDOWS_MAIN_MEM = e[self.OPT_USB_WINDOWS_MM_ID] + self.WINDOWS_CARD_A_MEM = e[self.OPT_USB_WINDOWS_CA_ID] + self.EBOOK_DIR_MAIN = e[self.OPT_MAIN_MEM_FOLDER] + self.EBOOK_DIR_CARD_A = e[self.OPT_CARD_A_FOLDER] + except: + pass \ No newline at end of file diff --git a/src/calibre/gui2/preferences/device_user_defined.py b/src/calibre/gui2/preferences/device_user_defined.py new file mode 100644 index 0000000000..0b820bd742 --- /dev/null +++ b/src/calibre/gui2/preferences/device_user_defined.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai +from __future__ import with_statement + +__license__ = 'GPL v3' +__copyright__ = '2009, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + + +from PyQt4.Qt import QDialog, QVBoxLayout, QPlainTextEdit, QTimer, \ + QDialogButtonBox, QPushButton, QApplication, QIcon, QMessageBox + +def step_dialog(parent, title, msg, det_msg=''): + d = QMessageBox(parent) + d.setWindowTitle(title) + d.setText(msg) + d.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) + return d.exec_() & QMessageBox.Cancel + + +class UserDefinedDevice(QDialog): + + def __init__(self, parent=None): + QDialog.__init__(self, parent) + self._layout = QVBoxLayout(self) + self.setLayout(self._layout) + self.log = QPlainTextEdit(self) + self._layout.addWidget(self.log) + self.log.setPlainText(_('Getting debug information')+'...') + self.copy = QPushButton(_('Copy to &clipboard')) + self.copy.setDefault(True) + self.setWindowTitle(_('Debug device detection')) + self.setWindowIcon(QIcon(I('debug.png'))) + self.copy.clicked.connect(self.copy_to_clipboard) + self.ok = QPushButton('&OK') + self.ok.setAutoDefault(False) + self.ok.clicked.connect(self.accept) + self.bbox = QDialogButtonBox(self) + self.bbox.addButton(self.copy, QDialogButtonBox.ActionRole) + self.bbox.addButton(self.ok, QDialogButtonBox.AcceptRole) + self._layout.addWidget(self.bbox) + self.resize(750, 500) + self.bbox.setEnabled(False) + QTimer.singleShot(1000, self.device_info) + + def device_info(self): + try: + from calibre.devices import device_info + r = step_dialog(self.parent(), _('Device Detection'), + _('Ensure your device is disconnected, then press OK')) + if r: + return + before = device_info() + r = step_dialog(self.parent(), _('Device Detection'), + _('Ensure your device is connected, then press OK')) + if r: + return + after = device_info() + new_drives = after['drive_set'] - before['drive_set'] + new_devices = after['device_set'] - before['device_set'] + res = '' + if len(new_drives) and len(new_devices) == 1: + for d in new_devices: + res = _('USB Vendor ID (in hex)') + ': 0x' + \ + after['device_details'][d][0] + '\n' + res += _('USB Product ID (in hex)') + ': 0x' + \ + after['device_details'][d][1] + '\n' + res += _('USB Revision ID (in hex)') + ': 0x' + \ + after['device_details'][d][2] + '\n' + # sort the drives by the order number + for i,d in enumerate(sorted(new_drives, + key=lambda x: after['drive_details'][x][0])): + if i == 0: + res += _('Windows main memory ID string') + ': ' + \ + after['drive_details'][d][1] + '\n' + res += _('Windows main memory ID string') + ': ' + \ + after['drive_details'][d][2] + '\n' + else: + res += _('Windows card A vendor string') + ': ' + \ + after['drive_details'][d][1] + '\n' + res += _('Windows card A ID string') + ': ' + \ + after['drive_details'][d][2] + '\n' + + self.log.setPlainText(res) + finally: + self.bbox.setEnabled(True) + + def copy_to_clipboard(self): + QApplication.clipboard().setText(self.log.toPlainText()) + +if __name__ == '__main__': + app = QApplication([]) + d = UserDefinedDevice() + d.exec_() diff --git a/src/calibre/gui2/preferences/misc.py b/src/calibre/gui2/preferences/misc.py index ead5da4ce4..80bfdffcd8 100644 --- a/src/calibre/gui2/preferences/misc.py +++ b/src/calibre/gui2/preferences/misc.py @@ -30,6 +30,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): r('enforce_cpu_limit', config, restart_required=True) self.device_detection_button.clicked.connect(self.debug_device_detection) self.button_open_config_dir.clicked.connect(self.open_config_dir) + self.user_defined_device_button.clicked.connect(self.user_defined_device) self.button_osx_symlinks.clicked.connect(self.create_symlinks) self.button_osx_symlinks.setVisible(isosx) @@ -38,6 +39,11 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): d = DebugDevice(self) d.exec_() + def user_defined_device(self, *args): + from calibre.gui2.preferences.device_user_defined import UserDefinedDevice + d = UserDefinedDevice(self) + d.exec_() + def open_config_dir(self, *args): from calibre.utils.config import config_dir open_local_file(config_dir) diff --git a/src/calibre/gui2/preferences/misc.ui b/src/calibre/gui2/preferences/misc.ui index 8b0189b0a1..cce14f5ade 100644 --- a/src/calibre/gui2/preferences/misc.ui +++ b/src/calibre/gui2/preferences/misc.ui @@ -58,7 +58,14 @@ - + + + + Setup the &user defined device + + + + Qt::Vertical From f74bed638111653a7d302c17da8938e34d962f16 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 2 May 2011 13:29:08 +0100 Subject: [PATCH 07/16] ... --- src/calibre/devices/__init__.py | 4 ---- src/calibre/devices/user_defined/driver.py | 17 +++++++++-------- .../gui2/preferences/device_user_defined.py | 7 ++++++- src/calibre/gui2/preferences/misc.py | 3 ++- src/calibre/gui2/preferences/misc.ui | 2 +- 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/calibre/devices/__init__.py b/src/calibre/devices/__init__.py index d151ae1844..02c42a1d6e 100644 --- a/src/calibre/devices/__init__.py +++ b/src/calibre/devices/__init__.py @@ -159,7 +159,6 @@ def debug(ioreg_to_tmp=False, buf=None): def device_info(ioreg_to_tmp=False, buf=None): from calibre.devices.scanner import DeviceScanner, win_pnp_drives from calibre.constants import iswindows - from calibre import prints import re res = {} @@ -182,14 +181,12 @@ def device_info(ioreg_to_tmp=False, buf=None): if rev: rev = rev.group(1) d = vid+pid+rev - prints(d) device_set.add(d) device_details[d] = (vid, pid, rev) res['device_set'] = device_set res['device_details'] = device_details drives = win_pnp_drives(debug=False) drive_details = {} - print drives drive_set = set() for drive,details in drives.iteritems(): order = 'ORD_' + str(drive.order) @@ -200,7 +197,6 @@ def device_info(ioreg_to_tmp=False, buf=None): if prod: prod = prod.group(1) d = (order, ven, prod) - print d drive_details[drive] = d drive_set.add(drive) res['drive_details'] = drive_details diff --git a/src/calibre/devices/user_defined/driver.py b/src/calibre/devices/user_defined/driver.py index 682ed1712e..03ed7dee94 100644 --- a/src/calibre/devices/user_defined/driver.py +++ b/src/calibre/devices/user_defined/driver.py @@ -10,7 +10,7 @@ from calibre.ebooks import BOOK_EXTENSIONS class USER_DEFINED(USBMS): name = 'User Defined USB driver' - gui_name = 'User Defined phone' + gui_name = 'User Defined USB Device' author = 'Kovid Goyal' supported_platforms = ['windows', 'osx', 'linux'] @@ -66,21 +66,22 @@ class USER_DEFINED(USBMS): OPT_MAIN_MEM_FOLDER = 7 OPT_CARD_A_FOLDER = 8 - def __init__(self, *args): - USBMS.__init__(self, args) + def initialize(self): try: e = self.settings().extra_customization self.VENDOR_ID = int(e[self.OPT_USB_VENDOR_ID], 16) self.PRODUCT_ID = int(e[self.OPT_USB_PRODUCT_ID], 16) self.BCD = [int(e[self.OPT_USB_REVISION_ID], 16)] - print '%x, %x, %s' %(self.VENDOR_ID, self.PRODUCT_ID, str(self.BCD)) if e[self.OPT_USB_WINDOWS_MM_VEN_ID]: self.VENDOR_NAME.append(e[self.OPT_USB_WINDOWS_MM_VEN_ID]) - if e[self.OPT_USB_WINDOWS_CA_VEN_ID]: + if e[self.OPT_USB_WINDOWS_CA_VEN_ID] and \ + e[self.OPT_USB_WINDOWS_CA_VEN_ID] not in self.VENDOR_NAME: self.VENDOR_NAME.append(e[self.OPT_USB_WINDOWS_CA_VEN_ID]) - self.WINDOWS_MAIN_MEM = e[self.OPT_USB_WINDOWS_MM_ID] - self.WINDOWS_CARD_A_MEM = e[self.OPT_USB_WINDOWS_CA_ID] + self.WINDOWS_MAIN_MEM = e[self.OPT_USB_WINDOWS_MM_ID] + '&' + self.WINDOWS_CARD_A_MEM = e[self.OPT_USB_WINDOWS_CA_ID] + '&' self.EBOOK_DIR_MAIN = e[self.OPT_MAIN_MEM_FOLDER] self.EBOOK_DIR_CARD_A = e[self.OPT_CARD_A_FOLDER] except: - pass \ No newline at end of file + import traceback + traceback.print_exc() + USBMS.initialize(self) \ No newline at end of file diff --git a/src/calibre/gui2/preferences/device_user_defined.py b/src/calibre/gui2/preferences/device_user_defined.py index 0b820bd742..914e2b5666 100644 --- a/src/calibre/gui2/preferences/device_user_defined.py +++ b/src/calibre/gui2/preferences/device_user_defined.py @@ -81,7 +81,12 @@ class UserDefinedDevice(QDialog): res += _('Windows card A ID string') + ': ' + \ after['drive_details'][d][2] + '\n' - self.log.setPlainText(res) + trailer = _('Enter the above values into the USER_DEVICE by ' + 'customizing the device plugin. Be sure to also ' + 'enter the folders where you want the books to ' + 'be put. You must restart calibre for your changes ' + 'to take effect.\n') + self.log.setPlainText(res + '\n\n' + trailer) finally: self.bbox.setEnabled(True) diff --git a/src/calibre/gui2/preferences/misc.py b/src/calibre/gui2/preferences/misc.py index 80bfdffcd8..179e8a995d 100644 --- a/src/calibre/gui2/preferences/misc.py +++ b/src/calibre/gui2/preferences/misc.py @@ -9,7 +9,7 @@ __docformat__ = 'restructuredtext en' from calibre.gui2.preferences import ConfigWidgetBase, test_widget, Setting from calibre.gui2.preferences.misc_ui import Ui_Form from calibre.gui2 import error_dialog, config, open_local_file, info_dialog -from calibre.constants import isosx +from calibre.constants import isosx, iswindows class WorkersSetting(Setting): @@ -33,6 +33,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): self.user_defined_device_button.clicked.connect(self.user_defined_device) self.button_osx_symlinks.clicked.connect(self.create_symlinks) self.button_osx_symlinks.setVisible(isosx) + self.user_defined_device_button.setVisible(iswindows) def debug_device_detection(self, *args): from calibre.gui2.preferences.device_debug import DebugDevice diff --git a/src/calibre/gui2/preferences/misc.ui b/src/calibre/gui2/preferences/misc.ui index cce14f5ade..df530bbe9a 100644 --- a/src/calibre/gui2/preferences/misc.ui +++ b/src/calibre/gui2/preferences/misc.ui @@ -61,7 +61,7 @@ - Setup the &user defined device + Get information to setup the &user defined device (Windows only) From 0962ebb3ba0016b223d603a819e0b59b5bfe6984 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 2 May 2011 14:58:26 +0100 Subject: [PATCH 08/16] Make user_defined_device information work on linux --- src/calibre/devices/__init__.py | 81 ++++++++++--------- .../gui2/preferences/device_user_defined.py | 36 +++++---- src/calibre/gui2/preferences/misc.py | 3 +- src/calibre/gui2/preferences/misc.ui | 2 +- 4 files changed, 66 insertions(+), 56 deletions(-) diff --git a/src/calibre/devices/__init__.py b/src/calibre/devices/__init__.py index 02c42a1d6e..e47cd82b50 100644 --- a/src/calibre/devices/__init__.py +++ b/src/calibre/devices/__init__.py @@ -162,45 +162,54 @@ def device_info(ioreg_to_tmp=False, buf=None): import re res = {} - if not iswindows: - return None + device_details = {} + device_set = set() + drive_details = {} + drive_set = set() + res['device_set'] = device_set + res['device_details'] = device_details + res['drive_details'] = drive_details + res['drive_set'] = drive_set + try: s = DeviceScanner() s.scan() devices = (s.devices) - device_details = {} - device_set = set() - for dev in devices: - vid = re.search('vid_([0-9a-f]*)&', dev) - if vid: - vid = vid.group(1) - pid = re.search('pid_([0-9a-f]*)&', dev) - if pid: - pid = pid.group(1) - rev = re.search('rev_([0-9a-f]*)$', dev) - if rev: - rev = rev.group(1) - d = vid+pid+rev - device_set.add(d) - device_details[d] = (vid, pid, rev) - res['device_set'] = device_set - res['device_details'] = device_details - drives = win_pnp_drives(debug=False) - drive_details = {} - drive_set = set() - for drive,details in drives.iteritems(): - order = 'ORD_' + str(drive.order) - ven = re.search('VEN_([^&]*)&', details) - if ven: - ven = ven.group(1) - prod = re.search('PROD_([^&]*)&', details) - if prod: - prod = prod.group(1) - d = (order, ven, prod) - drive_details[drive] = d - drive_set.add(drive) - res['drive_details'] = drive_details - res['drive_set'] = drive_set + if not iswindows: + devices = [list(x) for x in devices] + for dev in devices: + for i in range(3): + dev[i] = hex(dev[i]) + d = dev[0] + dev[1] + dev[2] + device_set.add(d) + device_details[d] = dev[0:3] + else: + for dev in devices: + vid = re.search('vid_([0-9a-f]*)&', dev) + if vid: + vid = vid.group(1) + pid = re.search('pid_([0-9a-f]*)&', dev) + if pid: + pid = pid.group(1) + rev = re.search('rev_([0-9a-f]*)$', dev) + if rev: + rev = rev.group(1) + d = vid+pid+rev + device_set.add(d) + device_details[d] = (vid, pid, rev) + + drives = win_pnp_drives(debug=False) + for drive,details in drives.iteritems(): + order = 'ORD_' + str(drive.order) + ven = re.search('VEN_([^&]*)&', details) + if ven: + ven = ven.group(1) + prod = re.search('PROD_([^&]*)&', details) + if prod: + prod = prod.group(1) + d = (order, ven, prod) + drive_details[drive] = d + drive_set.add(drive) finally: pass - return res \ No newline at end of file + return res diff --git a/src/calibre/gui2/preferences/device_user_defined.py b/src/calibre/gui2/preferences/device_user_defined.py index 914e2b5666..c2a27d3937 100644 --- a/src/calibre/gui2/preferences/device_user_defined.py +++ b/src/calibre/gui2/preferences/device_user_defined.py @@ -10,6 +10,8 @@ __docformat__ = 'restructuredtext en' from PyQt4.Qt import QDialog, QVBoxLayout, QPlainTextEdit, QTimer, \ QDialogButtonBox, QPushButton, QApplication, QIcon, QMessageBox +from calibre.constants import iswindows + def step_dialog(parent, title, msg, det_msg=''): d = QMessageBox(parent) d.setWindowTitle(title) @@ -26,10 +28,10 @@ class UserDefinedDevice(QDialog): self.setLayout(self._layout) self.log = QPlainTextEdit(self) self._layout.addWidget(self.log) - self.log.setPlainText(_('Getting debug information')+'...') + self.log.setPlainText(_('Getting device information')+'...') self.copy = QPushButton(_('Copy to &clipboard')) self.copy.setDefault(True) - self.setWindowTitle(_('Debug device detection')) + self.setWindowTitle(_('User-defined device information')) self.setWindowIcon(QIcon(I('debug.png'))) self.copy.clicked.connect(self.copy_to_clipboard) self.ok = QPushButton('&OK') @@ -59,7 +61,7 @@ class UserDefinedDevice(QDialog): new_drives = after['drive_set'] - before['drive_set'] new_devices = after['device_set'] - before['device_set'] res = '' - if len(new_drives) and len(new_devices) == 1: + if (not iswindows or len(new_drives)) and len(new_devices) == 1: for d in new_devices: res = _('USB Vendor ID (in hex)') + ': 0x' + \ after['device_details'][d][0] + '\n' @@ -67,20 +69,20 @@ class UserDefinedDevice(QDialog): after['device_details'][d][1] + '\n' res += _('USB Revision ID (in hex)') + ': 0x' + \ after['device_details'][d][2] + '\n' - # sort the drives by the order number - for i,d in enumerate(sorted(new_drives, - key=lambda x: after['drive_details'][x][0])): - if i == 0: - res += _('Windows main memory ID string') + ': ' + \ - after['drive_details'][d][1] + '\n' - res += _('Windows main memory ID string') + ': ' + \ - after['drive_details'][d][2] + '\n' - else: - res += _('Windows card A vendor string') + ': ' + \ - after['drive_details'][d][1] + '\n' - res += _('Windows card A ID string') + ': ' + \ - after['drive_details'][d][2] + '\n' - + if iswindows: + # sort the drives by the order number + for i,d in enumerate(sorted(new_drives, + key=lambda x: after['drive_details'][x][0])): + if i == 0: + res += _('Windows main memory ID string') + ': ' + \ + after['drive_details'][d][1] + '\n' + res += _('Windows main memory ID string') + ': ' + \ + after['drive_details'][d][2] + '\n' + else: + res += _('Windows card A vendor string') + ': ' + \ + after['drive_details'][d][1] + '\n' + res += _('Windows card A ID string') + ': ' + \ + after['drive_details'][d][2] + '\n' trailer = _('Enter the above values into the USER_DEVICE by ' 'customizing the device plugin. Be sure to also ' 'enter the folders where you want the books to ' diff --git a/src/calibre/gui2/preferences/misc.py b/src/calibre/gui2/preferences/misc.py index 179e8a995d..80bfdffcd8 100644 --- a/src/calibre/gui2/preferences/misc.py +++ b/src/calibre/gui2/preferences/misc.py @@ -9,7 +9,7 @@ __docformat__ = 'restructuredtext en' from calibre.gui2.preferences import ConfigWidgetBase, test_widget, Setting from calibre.gui2.preferences.misc_ui import Ui_Form from calibre.gui2 import error_dialog, config, open_local_file, info_dialog -from calibre.constants import isosx, iswindows +from calibre.constants import isosx class WorkersSetting(Setting): @@ -33,7 +33,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): self.user_defined_device_button.clicked.connect(self.user_defined_device) self.button_osx_symlinks.clicked.connect(self.create_symlinks) self.button_osx_symlinks.setVisible(isosx) - self.user_defined_device_button.setVisible(iswindows) def debug_device_detection(self, *args): from calibre.gui2.preferences.device_debug import DebugDevice diff --git a/src/calibre/gui2/preferences/misc.ui b/src/calibre/gui2/preferences/misc.ui index df530bbe9a..843f0f01b7 100644 --- a/src/calibre/gui2/preferences/misc.ui +++ b/src/calibre/gui2/preferences/misc.ui @@ -61,7 +61,7 @@ - Get information to setup the &user defined device (Windows only) + Get information to setup the &user defined device From ffdfb6ebe552f26a8b9e3fceb6494edab328dfb6 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 2 May 2011 15:21:51 +0100 Subject: [PATCH 09/16] ... --- src/calibre/gui2/preferences/device_user_defined.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/calibre/gui2/preferences/device_user_defined.py b/src/calibre/gui2/preferences/device_user_defined.py index c2a27d3937..198ae0d7a9 100644 --- a/src/calibre/gui2/preferences/device_user_defined.py +++ b/src/calibre/gui2/preferences/device_user_defined.py @@ -51,11 +51,13 @@ class UserDefinedDevice(QDialog): r = step_dialog(self.parent(), _('Device Detection'), _('Ensure your device is disconnected, then press OK')) if r: + self.close() return before = device_info() r = step_dialog(self.parent(), _('Device Detection'), _('Ensure your device is connected, then press OK')) if r: + self.close() return after = device_info() new_drives = after['drive_set'] - before['drive_set'] @@ -83,7 +85,8 @@ class UserDefinedDevice(QDialog): after['drive_details'][d][1] + '\n' res += _('Windows card A ID string') + ': ' + \ after['drive_details'][d][2] + '\n' - trailer = _('Enter the above values into the USER_DEVICE by ' + trailer = _('Copy these values to the clipboard, paste them into an ' + 'editor, then enter them into the USER_DEVICE by ' 'customizing the device plugin. Be sure to also ' 'enter the folders where you want the books to ' 'be put. You must restart calibre for your changes ' From 106396f76806aa2647b85268c9ab18e7688301ed Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 2 May 2011 15:36:25 +0100 Subject: [PATCH 10/16] ... --- src/calibre/devices/user_defined/driver.py | 40 +++++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/calibre/devices/user_defined/driver.py b/src/calibre/devices/user_defined/driver.py index 03ed7dee94..3211bd19ef 100644 --- a/src/calibre/devices/user_defined/driver.py +++ b/src/calibre/devices/user_defined/driver.py @@ -35,15 +35,37 @@ class USER_DEFINED(USBMS): SUPPORTS_SUB_DIRS = True EXTRA_CUSTOMIZATION_MESSAGE = [ - _('USB Vendor ID (in hex)'), - _('USB Product ID (in hex)'), - _('USB Revision ID (in hex)'), - _('Windows main memory vendor string'), - _('Windows main memory ID string'), - _('Windows card A vendor string'), - _('Windows card A ID string'), - _('Main memory folder'), - _('Card A folder'), + _('USB Vendor ID (in hex)') + ':::' + + _('Get this ID using Preferences -> Misc -> Get information to ' + 'set up the user-defined device'), + _('USB Product ID (in hex)')+ ':::' + + _('Get this ID using Preferences -> Misc -> Get information to ' + 'set up the user-defined device'), + _('USB Revision ID (in hex)')+ ':::' + + _('Get this ID using Preferences -> Misc -> Get information to ' + 'set up the user-defined device'), + _('Windows main memory vendor string') + ':::' + + _('This field is used only on windows. ' + 'Get this ID using Preferences -> Misc -> Get information to ' + 'set up the user-defined device'), + _('Windows main memory ID string') + ':::' + + _('This field is used only on windows. ' + 'Get this ID using Preferences -> Misc -> Get information to ' + 'set up the user-defined device'), + _('Windows card A vendor string') + ':::' + + _('This field is used only on windows. ' + 'Get this ID using Preferences -> Misc -> Get information to ' + 'set up the user-defined device'), + _('Windows card A ID string') + ':::' + + _('This field is used only on windows. ' + 'Get this ID using Preferences -> Misc -> Get information to ' + 'set up the user-defined device'), + _('Main memory folder') + ':::' + + _('Enter the folder where the books are to be stored. This folder ' + 'is prepended to any send_to_device template'), + _('Card A folder') + ':::' + + _('Enter the folder where the books are to be stored. This folder ' + 'is prepended to any send_to_device template'), ] EXTRA_CUSTOMIZATION_DEFAULT = [ '0x0000', From c64d180d1d470823486b871a07617c0886fbdc3e Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 2 May 2011 18:07:13 +0100 Subject: [PATCH 11/16] Switch device plugin preferences to double-column if more than 6 preferences --- src/calibre/devices/usbms/deviceconfig.py | 3 ++ src/calibre/devices/user_defined/driver.py | 52 ++++++++++--------- .../gui2/device_drivers/configwidget.py | 19 +++++-- .../gui2/device_drivers/configwidget.ui | 2 +- 4 files changed, 46 insertions(+), 30 deletions(-) diff --git a/src/calibre/devices/usbms/deviceconfig.py b/src/calibre/devices/usbms/deviceconfig.py index 3c79652463..3f669f1e24 100644 --- a/src/calibre/devices/usbms/deviceconfig.py +++ b/src/calibre/devices/usbms/deviceconfig.py @@ -94,6 +94,9 @@ class DeviceConfig(object): if isinstance(cls.EXTRA_CUSTOMIZATION_MESSAGE, list): ec = [] for i in range(0, len(cls.EXTRA_CUSTOMIZATION_MESSAGE)): + if config_widget.opt_extra_customization[i] is None: + ec.append(None) + continue if hasattr(config_widget.opt_extra_customization[i], 'isChecked'): ec.append(config_widget.opt_extra_customization[i].isChecked()) else: diff --git a/src/calibre/devices/user_defined/driver.py b/src/calibre/devices/user_defined/driver.py index 3211bd19ef..f57f61fe7c 100644 --- a/src/calibre/devices/user_defined/driver.py +++ b/src/calibre/devices/user_defined/driver.py @@ -15,7 +15,7 @@ class USER_DEFINED(USBMS): supported_platforms = ['windows', 'osx', 'linux'] # Ordered list of supported formats - FORMATS = BOOK_EXTENSIONS + FORMATS = ['epub', 'mobi', 'pdf'] VENDOR_ID = 0xFFFF PRODUCT_ID = 0xFFFF @@ -35,42 +35,44 @@ class USER_DEFINED(USBMS): SUPPORTS_SUB_DIRS = True EXTRA_CUSTOMIZATION_MESSAGE = [ - _('USB Vendor ID (in hex)') + ':::' + + _('USB Vendor ID (in hex)') + ':::

' + _('Get this ID using Preferences -> Misc -> Get information to ' - 'set up the user-defined device'), - _('USB Product ID (in hex)')+ ':::' + + 'set up the user-defined device') + '

', + _('USB Product ID (in hex)')+ ':::

' + _('Get this ID using Preferences -> Misc -> Get information to ' - 'set up the user-defined device'), - _('USB Revision ID (in hex)')+ ':::' + + 'set up the user-defined device') + '

', + _('USB Revision ID (in hex)')+ ':::

' + _('Get this ID using Preferences -> Misc -> Get information to ' - 'set up the user-defined device'), - _('Windows main memory vendor string') + ':::' + + 'set up the user-defined device') + '

', + '', + _('Windows main memory vendor string') + ':::

' + _('This field is used only on windows. ' 'Get this ID using Preferences -> Misc -> Get information to ' - 'set up the user-defined device'), - _('Windows main memory ID string') + ':::' + + 'set up the user-defined device') + '

', + _('Windows main memory ID string') + ':::

' + _('This field is used only on windows. ' 'Get this ID using Preferences -> Misc -> Get information to ' - 'set up the user-defined device'), - _('Windows card A vendor string') + ':::' + + 'set up the user-defined device') + '

', + _('Windows card A vendor string') + ':::

' + _('This field is used only on windows. ' 'Get this ID using Preferences -> Misc -> Get information to ' - 'set up the user-defined device'), - _('Windows card A ID string') + ':::' + + 'set up the user-defined device') + '

', + _('Windows card A ID string') + ':::

' + _('This field is used only on windows. ' 'Get this ID using Preferences -> Misc -> Get information to ' - 'set up the user-defined device'), - _('Main memory folder') + ':::' + + 'set up the user-defined device') + '

', + _('Main memory folder') + ':::

' + _('Enter the folder where the books are to be stored. This folder ' - 'is prepended to any send_to_device template'), - _('Card A folder') + ':::' + + 'is prepended to any send_to_device template') + '

', + _('Card A folder') + ':::

' + _('Enter the folder where the books are to be stored. This folder ' - 'is prepended to any send_to_device template'), + 'is prepended to any send_to_device template') + '

', ] EXTRA_CUSTOMIZATION_DEFAULT = [ '0x0000', '0x0000', '0x0000', + None, '', '', '', @@ -81,12 +83,12 @@ class USER_DEFINED(USBMS): OPT_USB_VENDOR_ID = 0 OPT_USB_PRODUCT_ID = 1 OPT_USB_REVISION_ID = 2 - OPT_USB_WINDOWS_MM_VEN_ID = 3 - OPT_USB_WINDOWS_MM_ID = 4 - OPT_USB_WINDOWS_CA_VEN_ID = 5 - OPT_USB_WINDOWS_CA_ID = 6 - OPT_MAIN_MEM_FOLDER = 7 - OPT_CARD_A_FOLDER = 8 + OPT_USB_WINDOWS_MM_VEN_ID = 4 + OPT_USB_WINDOWS_MM_ID = 5 + OPT_USB_WINDOWS_CA_VEN_ID = 6 + OPT_USB_WINDOWS_CA_ID = 7 + OPT_MAIN_MEM_FOLDER = 8 + OPT_CARD_A_FOLDER = 9 def initialize(self): try: diff --git a/src/calibre/gui2/device_drivers/configwidget.py b/src/calibre/gui2/device_drivers/configwidget.py index fc7e16e639..e55a0c6dda 100644 --- a/src/calibre/gui2/device_drivers/configwidget.py +++ b/src/calibre/gui2/device_drivers/configwidget.py @@ -62,8 +62,18 @@ class ConfigWidget(QWidget, Ui_ConfigWidget): if isinstance(extra_customization_message, list): self.opt_extra_customization = [] + if len(extra_customization_message) > 6: + row_func = lambda x, y: ((x/2) * 2) + y + col_func = lambda x: x%2 + else: + row_func = lambda x, y: x*2 + y + col_func = lambda x: 0 + for i, m in enumerate(extra_customization_message): label_text, tt = parse_msg(m) + if not label_text: + self.opt_extra_customization.append(None) + continue if isinstance(settings.extra_customization[i], bool): self.opt_extra_customization.append(QCheckBox(label_text)) self.opt_extra_customization[-1].setToolTip(tt) @@ -75,8 +85,9 @@ class ConfigWidget(QWidget, Ui_ConfigWidget): l.setBuddy(self.opt_extra_customization[i]) l.setWordWrap(True) self.opt_extra_customization[i].setText(settings.extra_customization[i]) - self.extra_layout.addWidget(l) - self.extra_layout.addWidget(self.opt_extra_customization[i]) + self.extra_layout.addWidget(l, row_func(i, 0), col_func(i)) + self.extra_layout.addWidget(self.opt_extra_customization[i], + row_func(i, 1), col_func(i)) else: self.opt_extra_customization = QLineEdit() label_text, tt = parse_msg(extra_customization_message) @@ -86,8 +97,8 @@ class ConfigWidget(QWidget, Ui_ConfigWidget): l.setWordWrap(True) if settings.extra_customization: self.opt_extra_customization.setText(settings.extra_customization) - self.extra_layout.addWidget(l) - self.extra_layout.addWidget(self.opt_extra_customization) + self.extra_layout.addWidget(l, 0, 0) + self.extra_layout.addWidget(self.opt_extra_customization, 1, 0) self.opt_save_template.setText(settings.save_template) diff --git a/src/calibre/gui2/device_drivers/configwidget.ui b/src/calibre/gui2/device_drivers/configwidget.ui index 619d7052e8..92324fd1a7 100644 --- a/src/calibre/gui2/device_drivers/configwidget.ui +++ b/src/calibre/gui2/device_drivers/configwidget.ui @@ -101,7 +101,7 @@
- + From 5d3455b184a6563fd3a43d93fea6de87f638d649 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 2 May 2011 11:52:07 -0600 Subject: [PATCH 12/16] Print out plugin load failure traceback only in DEBUG mode --- src/calibre/customize/ui.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/calibre/customize/ui.py b/src/calibre/customize/ui.py index 151235cef9..3a2d638aab 100644 --- a/src/calibre/customize/ui.py +++ b/src/calibre/customize/ui.py @@ -19,6 +19,7 @@ from calibre.utils.config import (make_config_dir, Config, ConfigProxy, plugin_dir, OptionParser) from calibre.ebooks.epub.fix import ePubFixer from calibre.ebooks.metadata.sources.base import Source +from calibre.constants import DEBUG builtin_names = frozenset([p.name for p in builtin_plugins]) @@ -487,8 +488,9 @@ def initialize_plugins(): plugin = initialize_plugin(plugin, None if isinstance(zfp, type) else zfp) _initialized_plugins.append(plugin) except: - print 'Failed to initialize plugin...' - traceback.print_exc() + print 'Failed to initialize plugin:', repr(zfp) + if DEBUG: + traceback.print_exc() _initialized_plugins.sort(cmp=lambda x,y:cmp(x.priority, y.priority), reverse=True) reread_filetype_plugins() reread_metadata_plugins() From 58c6733d3f9af650c5b7d7dc004e551d21d0d79e Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 2 May 2011 20:27:41 +0100 Subject: [PATCH 13/16] Add some documentation for the new User Defined device. --- src/calibre/manual/faq.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/calibre/manual/faq.rst b/src/calibre/manual/faq.rst index 2e2a8e5ae6..0e964516c4 100644 --- a/src/calibre/manual/faq.rst +++ b/src/calibre/manual/faq.rst @@ -100,7 +100,9 @@ Device Integration What devices does |app| support? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -At the moment |app| has full support for the SONY PRS line, Barnes & Noble Nook line, Cybook Gen 3/Opus, Amazon Kindle line, Entourage Edge, Longshine ShineBook, Ectaco Jetbook, BeBook/BeBook Mini, Irex Illiad/DR1000, Foxit eSlick, PocketBook line, Italica, eClicto, Iriver Story, Airis dBook, Hanvon N515, Binatone Readme, Teclast K3 and clones, SpringDesign Alex, Kobo Reader, various Android phones and the iPhone/iPad. In addition, using the :guilabel:`Connect to folder` function you can use it with any ebook reader that exports itself as a USB disk. +At the moment |app| has full support for the SONY PRS line, Barnes & Noble Nook line, Cybook Gen 3/Opus, Amazon Kindle line, Entourage Edge, Longshine ShineBook, Ectaco Jetbook, BeBook/BeBook Mini, Irex Illiad/DR1000, Foxit eSlick, PocketBook line, Italica, eClicto, Iriver Story, Airis dBook, Hanvon N515, Binatone Readme, Teclast K3 and clones, SpringDesign Alex, Kobo Reader, various Android phones and the iPhone/iPad. In addition, using the :guilabel:`Connect to folder` function you can use it with any ebook reader that exports itself as a USB disk. + +There is also a special ``User Defined`` device plugin that can be used to connect to arbitrary devices that present their memory as disk drives. See the device plugin ``Preferences -> Plugins -> Device Plugins -> User Defined`` and ``Preferences -> Miscelleaneous -> Get information to setup the user defined device`` for more information. How can I help get my device supported in |app|? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -133,6 +135,11 @@ Follow these steps to find the problem: * In calibre, go to Preferences->Plugins->Device Interface plugin and make sure the plugin for your device is enabled, the plugin icon next to it should be green when it is enabled. * If all the above steps fail, go to Preferences->Miscellaneous and click debug device detection with your device attached and post the output as a ticket on `the calibre bug tracker `_. +My device is non-standard or unusual. What can I do to connect to it? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In addition to the ``Connect to Folder`` function found under the Connect/Share menu (see :guilabel:`Connect to folder`), |app| provides a ``User Defined`` device plugin that can be used to connect to any USB device that presents its memory as disk drives. See the device plugin ``Preferences -> Plugins -> Device Plugins -> User Defined`` and ``Preferences -> Miscelleaneous -> Get information to setup the user defined device`` for more information. + How does |app| manage collections on my SONY reader? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From fb87d6b9ad88ef54fe2bbf008a27430b6b954387 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 2 May 2011 13:46:19 -0600 Subject: [PATCH 14/16] Fix #775825 (titlecase error on the word (part) macht) --- src/calibre/utils/titlecase.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/utils/titlecase.py b/src/calibre/utils/titlecase.py index bf2f9a78d4..1f153dd5fe 100755 --- a/src/calibre/utils/titlecase.py +++ b/src/calibre/utils/titlecase.py @@ -68,7 +68,7 @@ def titlecase(text): continue match = MAC_MC.match(word) - if match and not match.group(2).startswith('hin'): + if match and not match.group(2)[:3] in ('hin', 'ht'): line.append("%s%s" % (capitalize(match.group(1)), capitalize(match.group(2)))) continue From 375529f7cba71779bc74b264ba645bcf0daa9b80 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 2 May 2011 16:41:53 -0600 Subject: [PATCH 15/16] Fix #775952 (Calibre not seeing dell streak 5 due to new USB identifier) --- src/calibre/devices/android/driver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/devices/android/driver.py b/src/calibre/devices/android/driver.py index f500560f97..ca84271778 100644 --- a/src/calibre/devices/android/driver.py +++ b/src/calibre/devices/android/driver.py @@ -62,7 +62,7 @@ class ANDROID(USBMS): 0x502 : { 0x3203 : [0x0100]}, # Dell - 0x413c : { 0xb007 : [0x0100, 0x0224]}, + 0x413c : { 0xb007 : [0x0100, 0x0224, 0x0226]}, # LG 0x1004 : { 0x61cc : [0x100], 0x61ce : [0x100], 0x618e : [0x226] }, From 5bf153338b11da59b4f24cdd1e68611513ac7daf Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 2 May 2011 18:28:38 -0600 Subject: [PATCH 16/16] BibTeX catalog: Convert all HTML comments to plain text. Fixes #775051 (catalog BIB) --- src/calibre/devices/user_defined/driver.py | 3 +-- src/calibre/library/catalog.py | 17 ++++++++++------- src/calibre/utils/bibtex.py | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/calibre/devices/user_defined/driver.py b/src/calibre/devices/user_defined/driver.py index f57f61fe7c..c496422255 100644 --- a/src/calibre/devices/user_defined/driver.py +++ b/src/calibre/devices/user_defined/driver.py @@ -5,7 +5,6 @@ __copyright__ = '2009, Kovid Goyal ' __docformat__ = 'restructuredtext en' from calibre.devices.usbms.driver import USBMS -from calibre.ebooks import BOOK_EXTENSIONS class USER_DEFINED(USBMS): @@ -108,4 +107,4 @@ class USER_DEFINED(USBMS): except: import traceback traceback.print_exc() - USBMS.initialize(self) \ No newline at end of file + USBMS.initialize(self) diff --git a/src/calibre/library/catalog.py b/src/calibre/library/catalog.py index 717e8e2c6b..aeecc3cfca 100644 --- a/src/calibre/library/catalog.py +++ b/src/calibre/library/catalog.py @@ -8,6 +8,7 @@ from collections import namedtuple from copy import deepcopy from xml.sax.saxutils import escape from lxml import etree +from types import StringType, UnicodeType from calibre import prints, prepare_string_for_xml, strftime from calibre.constants import preferred_encoding, DEBUG @@ -15,13 +16,16 @@ from calibre.customize import CatalogPlugin from calibre.customize.conversion import OptionRecommendation, DummyReporter from calibre.ebooks.BeautifulSoup import BeautifulSoup, BeautifulStoneSoup, Tag, NavigableString from calibre.ebooks.chardet import substitute_entites +from calibre.library.save_to_disk import preprocess_template from calibre.ptempfile import PersistentTemporaryDirectory +from calibre.utils.bibtex import BibTeX from calibre.utils.config import config_dir from calibre.utils.date import format_date, isoformat, is_date_undefined, now as nowf +from calibre.utils.html2text import html2text from calibre.utils.icu import capitalize from calibre.utils.logging import default_log as log -from calibre.utils.zipfile import ZipFile, ZipInfo from calibre.utils.magick.draw import thumbnail +from calibre.utils.zipfile import ZipFile, ZipInfo FIELDS = ['all', 'title', 'author_sort', 'authors', 'comments', 'cover', 'formats','id', 'isbn', 'ondevice', 'pubdate', 'publisher', @@ -303,12 +307,6 @@ class BIBTEX(CatalogPlugin): # {{{ def run(self, path_to_output, opts, db, notification=DummyReporter()): - from types import StringType, UnicodeType - - from calibre.library.save_to_disk import preprocess_template - #Bibtex functions - from calibre.utils.bibtex import BibTeX - def create_bibtex_entry(entry, fields, mode, template_citation, bibtexdict, citation_bibtex=True, calibre_files=True): @@ -365,6 +363,11 @@ class BIBTEX(CatalogPlugin): # {{{ #\n removal item = item.replace(u'\r\n',u' ') item = item.replace(u'\n',u' ') + #html to text + try: + item = html2text(item) + except: + log.warn("Failed to convert comments to text") bibtex_entry.append(u'note = "%s"' % bibtexdict.utf8ToBibtex(item)) elif field == 'isbn' : diff --git a/src/calibre/utils/bibtex.py b/src/calibre/utils/bibtex.py index d19a6b05fe..518ec96611 100644 --- a/src/calibre/utils/bibtex.py +++ b/src/calibre/utils/bibtex.py @@ -2905,4 +2905,4 @@ class BibTeX: def bibtex_author_format(self, item): #Format authors for Bibtex compliance (get a list as input) - return self.utf8ToBibtex(u' and'.join([author for author in item])) + return self.utf8ToBibtex(u' and '.join([author for author in item]))