diff --git a/src/calibre/devices/prs505/driver.py b/src/calibre/devices/prs505/driver.py index 4c14565c2d..094c12cf0c 100644 --- a/src/calibre/devices/prs505/driver.py +++ b/src/calibre/devices/prs505/driver.py @@ -35,7 +35,7 @@ class PRS505(USBMS): VENDOR_NAME = 'SONY' WINDOWS_MAIN_MEM = re.compile( - r'(PRS-(505|300|500))|' + r'(PRS-(505|500))|' r'(PRS-((700[#/])|((6|9|3)(0|5)0&)))' ) WINDOWS_CARD_A_MEM = re.compile( diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 1b61404589..e58dce5559 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -50,6 +50,7 @@ gprefs.defaults['action-layout-context-menu-device'] = ( gprefs.defaults['show_splash_screen'] = True gprefs.defaults['toolbar_icon_size'] = 'medium' gprefs.defaults['toolbar_text'] = 'auto' +gprefs.defaults['show_child_bar'] = False # }}} diff --git a/src/calibre/gui2/actions/__init__.py b/src/calibre/gui2/actions/__init__.py index 57ad900fba..b2d1656367 100644 --- a/src/calibre/gui2/actions/__init__.py +++ b/src/calibre/gui2/actions/__init__.py @@ -71,6 +71,12 @@ class InterfaceAction(QObject): all_locations = frozenset(['toolbar', 'toolbar-device', 'context-menu', 'context-menu-device']) + #: Type of action + #: 'current' means acts on the current view + #: 'global' means an action that does not act on the current view, but rather + #: on calibre as a whole + action_type = 'global' + def __init__(self, parent, site_customization): QObject.__init__(self, parent) self.setObjectName(self.name) diff --git a/src/calibre/gui2/actions/add.py b/src/calibre/gui2/actions/add.py index f0ff794fab..add7bf1d5b 100644 --- a/src/calibre/gui2/actions/add.py +++ b/src/calibre/gui2/actions/add.py @@ -25,6 +25,7 @@ class AddAction(InterfaceAction): action_spec = (_('Add books'), 'add_book.png', _('Add books to the calibre library/device from files on your computer') , _('A')) + action_type = 'current' def genesis(self): self._add_filesystem_book = self.Dispatcher(self.__add_filesystem_book) diff --git a/src/calibre/gui2/actions/add_to_library.py b/src/calibre/gui2/actions/add_to_library.py index 6fc0d5fb1f..05aea8f1dd 100644 --- a/src/calibre/gui2/actions/add_to_library.py +++ b/src/calibre/gui2/actions/add_to_library.py @@ -13,6 +13,7 @@ class AddToLibraryAction(InterfaceAction): action_spec = (_('Add books to library'), 'add_book.png', _('Add books to your calibre library from the connected device'), None) dont_add_to = frozenset(['toolbar', 'context-menu']) + action_type = 'current' def genesis(self): self.qaction.triggered.connect(self.add_books_to_library) diff --git a/src/calibre/gui2/actions/annotate.py b/src/calibre/gui2/actions/annotate.py index 5356d63e98..dfafcd1a39 100644 --- a/src/calibre/gui2/actions/annotate.py +++ b/src/calibre/gui2/actions/annotate.py @@ -18,6 +18,7 @@ class FetchAnnotationsAction(InterfaceAction): name = 'Fetch Annotations' action_spec = (_('Fetch annotations (experimental)'), None, None, None) + action_type = 'current' def genesis(self): pass diff --git a/src/calibre/gui2/actions/convert.py b/src/calibre/gui2/actions/convert.py index ee0f06ab71..29acfc52b1 100644 --- a/src/calibre/gui2/actions/convert.py +++ b/src/calibre/gui2/actions/convert.py @@ -21,6 +21,7 @@ class ConvertAction(InterfaceAction): name = 'Convert Books' action_spec = (_('Convert books'), 'convert.png', None, _('C')) dont_add_to = frozenset(['toolbar-device', 'context-menu-device']) + action_type = 'current' def genesis(self): cm = QMenu() diff --git a/src/calibre/gui2/actions/copy_to_library.py b/src/calibre/gui2/actions/copy_to_library.py index 7127c91e8c..6b7654f644 100644 --- a/src/calibre/gui2/actions/copy_to_library.py +++ b/src/calibre/gui2/actions/copy_to_library.py @@ -80,6 +80,7 @@ class CopyToLibraryAction(InterfaceAction): _('Copy selected books to the specified library'), None) popup_type = QToolButton.InstantPopup dont_add_to = frozenset(['toolbar-device', 'context-menu-device']) + action_type = 'current' def genesis(self): self.menu = QMenu(self.gui) diff --git a/src/calibre/gui2/actions/delete.py b/src/calibre/gui2/actions/delete.py index 0343c6df84..406860e4ec 100644 --- a/src/calibre/gui2/actions/delete.py +++ b/src/calibre/gui2/actions/delete.py @@ -16,6 +16,7 @@ class DeleteAction(InterfaceAction): name = 'Remove Books' action_spec = (_('Remove books'), 'trash.png', None, _('Del')) + action_type = 'current' def genesis(self): self.qaction.triggered.connect(self.delete_books) diff --git a/src/calibre/gui2/actions/edit_collections.py b/src/calibre/gui2/actions/edit_collections.py index e45d36fc62..7f5dd76538 100644 --- a/src/calibre/gui2/actions/edit_collections.py +++ b/src/calibre/gui2/actions/edit_collections.py @@ -13,6 +13,7 @@ class EditCollectionsAction(InterfaceAction): action_spec = (_('Manage collections'), None, _('Manage the collections on this device'), None) dont_add_to = frozenset(['toolbar', 'context-menu']) + action_type = 'current' def genesis(self): self.qaction.triggered.connect(self.edit_collections) diff --git a/src/calibre/gui2/actions/edit_metadata.py b/src/calibre/gui2/actions/edit_metadata.py index 878ba77a43..ac04652efa 100644 --- a/src/calibre/gui2/actions/edit_metadata.py +++ b/src/calibre/gui2/actions/edit_metadata.py @@ -22,6 +22,7 @@ class EditMetadataAction(InterfaceAction): name = 'Edit Metadata' action_spec = (_('Edit metadata'), 'edit_input.png', None, _('E')) + action_type = 'current' def genesis(self): self.create_action(spec=(_('Merge book records'), 'merge_books.png', diff --git a/src/calibre/gui2/actions/open.py b/src/calibre/gui2/actions/open.py index 106bfa24f6..141ff01a66 100644 --- a/src/calibre/gui2/actions/open.py +++ b/src/calibre/gui2/actions/open.py @@ -14,6 +14,7 @@ class OpenFolderAction(InterfaceAction): action_spec = (_('Open containing folder'), 'document_open.png', None, _('O')) dont_add_to = frozenset(['toolbar-device', 'context-menu-device']) + action_type = 'current' def genesis(self): self.qaction.triggered.connect(self.gui.iactions['View'].view_folder) diff --git a/src/calibre/gui2/actions/save_to_disk.py b/src/calibre/gui2/actions/save_to_disk.py index bfcc02e130..e9664b9980 100644 --- a/src/calibre/gui2/actions/save_to_disk.py +++ b/src/calibre/gui2/actions/save_to_disk.py @@ -38,6 +38,7 @@ class SaveToDiskAction(InterfaceAction): name = "Save To Disk" action_spec = (_('Save to disk'), 'save.png', None, _('S')) + action_type = 'current' def genesis(self): self.qaction.triggered.connect(self.save_to_disk) diff --git a/src/calibre/gui2/actions/show_book_details.py b/src/calibre/gui2/actions/show_book_details.py index d17d0998f1..18b0a694bf 100644 --- a/src/calibre/gui2/actions/show_book_details.py +++ b/src/calibre/gui2/actions/show_book_details.py @@ -16,6 +16,7 @@ class ShowBookDetailsAction(InterfaceAction): action_spec = (_('Show book details'), 'dialog_information.png', None, _('I')) dont_add_to = frozenset(['toolbar-device', 'context-menu-device']) + action_type = 'current' def genesis(self): self.qaction.triggered.connect(self.show_book_info) diff --git a/src/calibre/gui2/actions/similar_books.py b/src/calibre/gui2/actions/similar_books.py index 1a14869a9c..644cd3160a 100644 --- a/src/calibre/gui2/actions/similar_books.py +++ b/src/calibre/gui2/actions/similar_books.py @@ -16,6 +16,7 @@ class SimilarBooksAction(InterfaceAction): name = 'Similar Books' action_spec = (_('Similar books...'), None, None, None) popup_type = QToolButton.InstantPopup + action_type = 'current' def genesis(self): m = QMenu(self.gui) diff --git a/src/calibre/gui2/actions/view.py b/src/calibre/gui2/actions/view.py index 2f6be24e5b..0fbf86c567 100644 --- a/src/calibre/gui2/actions/view.py +++ b/src/calibre/gui2/actions/view.py @@ -22,6 +22,7 @@ class ViewAction(InterfaceAction): name = 'View' action_spec = (_('View'), 'view.png', None, _('V')) + action_type = 'current' def genesis(self): self.persistent_files = [] diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index 45c78ce6da..f839e1d519 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -627,12 +627,11 @@ class DeviceMixin(object): # {{{ def connect_to_folder(self): dir = choose_dir(self, 'Select Device Folder', _('Select folder to open as device')) - kls = FOLDER_DEVICE - self.device_manager.mount_device(kls=kls, kind='folder', path=dir) + if dir is not None: + self.device_manager.mount_device(kls=FOLDER_DEVICE, kind='folder', path=dir) def connect_to_itunes(self): - kls = ITUNES_ASYNC - self.device_manager.mount_device(kls=kls, kind='itunes', path=None) + self.device_manager.mount_device(kls=ITUNES_ASYNC, kind='itunes', path=None) # disconnect from both folder and itunes devices def disconnect_mounted_device(self): diff --git a/src/calibre/gui2/layout.py b/src/calibre/gui2/layout.py index 58d5267c8e..ec7e023dc1 100644 --- a/src/calibre/gui2/layout.py +++ b/src/calibre/gui2/layout.py @@ -61,7 +61,7 @@ class LocationManager(QObject): # {{{ ac('library', _('Library'), 'lt.png', _('Show books in calibre library')) - ac('main', _('Reader'), 'reader.png', + ac('main', _('Device'), 'reader.png', _('Show books in the main memory of the device')) ac('carda', _('Card A'), 'sd.png', _('Show books in storage card A')) @@ -197,11 +197,21 @@ class SearchBar(QWidget): # {{{ # }}} +class Spacer(QWidget): + + def __init__(self, parent): + QWidget.__init__(self, parent) + self.l = QHBoxLayout() + self.setLayout(self.l) + self.l.addStretch(10) + + class ToolBar(QToolBar): # {{{ - def __init__(self, donate, location_manager, parent): + def __init__(self, donate, location_manager, child_bar, parent): QToolBar.__init__(self, parent) self.gui = parent + self.child_bar = child_bar self.setContextMenuPolicy(Qt.PreventContextMenu) self.setMovable(False) self.setFloatable(False) @@ -223,16 +233,19 @@ class ToolBar(QToolBar): # {{{ sz = gprefs['toolbar_icon_size'] sz = {'small':24, 'medium':48, 'large':64}[sz] self.setIconSize(QSize(sz, sz)) + self.child_bar.setIconSize(QSize(sz, sz)) style = Qt.ToolButtonTextUnderIcon if gprefs['toolbar_text'] == 'never': style = Qt.ToolButtonIconOnly self.setToolButtonStyle(style) + self.child_bar.setToolButtonStyle(style) self.donate_button.set_normal_icon_size(sz, sz) def contextMenuEvent(self, *args): pass def build_bar(self): + self.child_bar.setVisible(gprefs['show_child_bar']) self.showing_donate = False showing_device = self.location_manager.has_device actions = '-device' if showing_device else '' @@ -244,10 +257,16 @@ class ToolBar(QToolBar): # {{{ m.setVisible(False) self.clear() + self.child_bar.clear() self.added_actions = [] + self.spacers = [Spacer(self.child_bar), Spacer(self.child_bar), + Spacer(self), Spacer(self)] + self.child_bar.addWidget(self.spacers[0]) + if gprefs['show_child_bar']: + self.addWidget(self.spacers[2]) for what in actions: - if what is None: + if what is None and not gprefs['show_child_bar']: self.addSeparator() elif what == 'Location Manager': for ac in self.location_manager.available_actions: @@ -262,12 +281,21 @@ class ToolBar(QToolBar): # {{{ self.showing_donate = True elif what in self.gui.iactions: action = self.gui.iactions[what] - self.addAction(action.qaction) + bar = self + if action.action_type == 'current' and gprefs['show_child_bar']: + bar = self.child_bar + bar.addAction(action.qaction) self.added_actions.append(action.qaction) self.setup_tool_button(action.qaction, action.popup_type) + self.child_bar.addWidget(self.spacers[1]) + if gprefs['show_child_bar']: + self.addWidget(self.spacers[3]) + def setup_tool_button(self, ac, menu_mode=None): ch = self.widgetForAction(ac) + if ch is None: + ch = self.child_bar.widgetForAction(ac) ch.setCursor(Qt.PointingHandCursor) ch.setAutoRaise(True) if ac.menu() is not None and menu_mode is not None: @@ -280,7 +308,8 @@ class ToolBar(QToolBar): # {{{ if p == 'never': style = Qt.ToolButtonIconOnly - if p == 'auto' and self.preferred_width > self.width()+35: + if p == 'auto' and self.preferred_width > self.width()+35 and \ + not gprefs['show_child_bar']: style = Qt.ToolButtonIconOnly self.setToolButtonStyle(style) @@ -309,9 +338,11 @@ class MainWindowMixin(object): # {{{ self.iactions['Fetch News'].init_scheduler(db) self.search_bar = SearchBar(self) + self.child_bar = QToolBar(self) self.tool_bar = ToolBar(self.donate_button, - self.location_manager, self) + self.location_manager, self.child_bar, self) self.addToolBar(Qt.TopToolBarArea, self.tool_bar) + self.addToolBar(Qt.BottomToolBarArea, self.child_bar) l = self.centralwidget.layout() l.addWidget(self.search_bar) diff --git a/src/calibre/gui2/preferences/look_feel.py b/src/calibre/gui2/preferences/look_feel.py index f30b2fddbb..10c2fcfe95 100644 --- a/src/calibre/gui2/preferences/look_feel.py +++ b/src/calibre/gui2/preferences/look_feel.py @@ -46,6 +46,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): r('use_roman_numerals_for_series_number', config) r('separate_cover_flow', config, restart_required=True) r('search_as_you_type', config) + r('show_child_bar', gprefs) choices = [(_('Small'), 'small'), (_('Medium'), 'medium'), (_('Large'), 'large')] diff --git a/src/calibre/gui2/preferences/look_feel.ui b/src/calibre/gui2/preferences/look_feel.ui index 7c6c736b24..1de55d51ef 100644 --- a/src/calibre/gui2/preferences/look_feel.ui +++ b/src/calibre/gui2/preferences/look_feel.ui @@ -173,6 +173,13 @@ + + + + &Split the toolbar into two toolbars + + + diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index 8a2979f122..f787a44eee 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -605,7 +605,11 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): def has_cover(self, index, index_is_id=False): id = index if index_is_id else self.id(index) - path = os.path.join(self.library_path, self.path(id, index_is_id=True), 'cover.jpg') + try: + path = os.path.join(self.abspath(id, index_is_id=True), 'cover.jpg') + except: + # Can happen if path has not yet been set + return False return os.access(path, os.R_OK) def remove_cover(self, id, notify=True): @@ -616,6 +620,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): except (IOError, OSError): time.sleep(0.2) os.remove(path) + self.data.set(id, self.FIELD_MAP['cover'], False, row_is_id=True) if notify: self.notify('cover', [id]) @@ -636,6 +641,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): except (IOError, OSError): time.sleep(0.2) save_cover_data_to(data, path) + self.data.set(id, self.FIELD_MAP['cover'], True, row_is_id=True) if notify: self.notify('cover', [id]) @@ -1103,8 +1109,11 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): label=user_mi[key]['label']) self.notify('metadata', [id]) - # Given a book, return the list of author sort strings for the book's authors def authors_sort_strings(self, id, index_is_id=False): + ''' + Given a book, return the list of author sort strings + for the book's authors + ''' id = id if index_is_id else self.id(id) aut_strings = self.conn.get(''' SELECT sort @@ -1773,10 +1782,10 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): series_index = 1.0 if mi.series_index is None else mi.series_index aus = mi.author_sort if mi.author_sort else self.author_sort_from_authors(mi.authors) title = mi.title - if isinstance(aus, str): + if isbytestring(aus): aus = aus.decode(preferred_encoding, 'replace') - if isinstance(title, str): - title = title.decode(preferred_encoding) + if isbytestring(title): + title = title.decode(preferred_encoding, 'replace') obj = self.conn.execute('INSERT INTO books(title, series_index, author_sort) VALUES (?, ?, ?)', (title, series_index, aus)) id = obj.lastrowid diff --git a/src/calibre/utils/magick/__init__.py b/src/calibre/utils/magick/__init__.py index 073a030361..2707430c67 100644 --- a/src/calibre/utils/magick/__init__.py +++ b/src/calibre/utils/magick/__init__.py @@ -194,7 +194,7 @@ class Image(_magick.Image): # {{{ # }}} -def create_canvas(width, height, bgcolor='white'): +def create_canvas(width, height, bgcolor='#ffffff'): canvas = Image() canvas.create_canvas(int(width), int(height), str(bgcolor)) return canvas diff --git a/src/calibre/utils/magick/draw.py b/src/calibre/utils/magick/draw.py index 301bf9912a..ed9e3d3d83 100644 --- a/src/calibre/utils/magick/draw.py +++ b/src/calibre/utils/magick/draw.py @@ -11,7 +11,7 @@ from calibre.utils.magick import Image, DrawingWand, create_canvas from calibre.constants import __appname__, __version__ from calibre import fit_image -def save_cover_data_to(data, path, bgcolor='white', resize_to=None, +def save_cover_data_to(data, path, bgcolor='#ffffff', resize_to=None, return_data=False): ''' Saves image in data to path, in the format specified by the path @@ -28,7 +28,7 @@ def save_cover_data_to(data, path, bgcolor='white', resize_to=None, return canvas.export(os.path.splitext(path)[1][1:]) canvas.save(path) -def thumbnail(data, width=120, height=120, bgcolor='white', fmt='jpg'): +def thumbnail(data, width=120, height=120, bgcolor='#ffffff', fmt='jpg'): img = Image() img.load(data) owidth, oheight = img.size @@ -61,7 +61,7 @@ def identify(path): return identify_data(data) def add_borders_to_image(path_to_image, left=0, top=0, right=0, bottom=0, - border_color='white'): + border_color='#ffffff'): img = Image() img.open(path_to_image) lwidth, lheight = img.size @@ -80,7 +80,7 @@ def create_text_wand(font_size, font_path=None): ans.text_alias = True return ans -def create_text_arc(text, font_size, font=None, bgcolor='white'): +def create_text_arc(text, font_size, font=None, bgcolor='#ffffff'): if isinstance(text, unicode): text = text.encode('utf-8') @@ -148,7 +148,7 @@ class TextLine(object): def create_cover_page(top_lines, logo_path, width=590, height=750, - bgcolor='white', output_format='jpg'): + bgcolor='#ffffff', output_format='jpg'): ''' Create the standard calibre cover page and return it as a byte string in the specified output_format. diff --git a/src/calibre/web/feeds/news.py b/src/calibre/web/feeds/news.py index 9ba9583c73..a140dfbf05 100644 --- a/src/calibre/web/feeds/news.py +++ b/src/calibre/web/feeds/news.py @@ -290,10 +290,12 @@ class BasicNewsRecipe(Recipe): #: the cover for the periodical. Overriding this in your recipe instructs #: calibre to render the downloaded cover into a frame whose width and height #: are expressed as a percentage of the downloaded cover. - #: cover_margins = (10,15,'white') pads the cover with a white margin + #: cover_margins = (10, 15, '#ffffff') pads the cover with a white margin #: 10px on the left and right, 15px on the top and bottom. - #: Colors name defined at http://www.imagemagick.org/script/color.php - cover_margins = (0,0,'white') + #: Color names defined at http://www.imagemagick.org/script/color.php + #: Note that for some reason, white does not always work on windows. Use + #: #ffffff instead + cover_margins = (0, 0, '#ffffff') #: Set to a non empty string to disable this recipe #: The string will be used as the disabled message