mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
0.9.21+ - KG revisions for dnd support
This commit is contained in:
commit
627f895c47
@ -672,6 +672,7 @@ Some limitations of PDF input are:
|
||||
* Links and Tables of Contents are not supported
|
||||
* PDFs that use embedded non-unicode fonts to represent non-English characters will result in garbled output for those characters
|
||||
* Some PDFs are made up of photographs of the page with OCRed text behind them. In such cases |app| uses the OCRed text, which can be very different from what you see when you view the PDF file
|
||||
* PDFs that are used to display complex text, like right to left languages and math typesetting will not convert correctly
|
||||
|
||||
To re-iterate **PDF is a really, really bad** format to use as input. If you absolutely must use PDF, then be prepared for an
|
||||
output ranging anywhere from decent to unusable, depending on the input PDF.
|
||||
|
@ -30,11 +30,6 @@ class tvn24(BasicNewsRecipe):
|
||||
feeds = [(u'Najnowsze', u'http://www.tvn24.pl/najnowsze.xml'), ]
|
||||
#(u'Polska', u'www.tvn24.pl/polska.xml'), (u'\u015awiat', u'http://www.tvn24.pl/swiat.xml'), (u'Sport', u'http://www.tvn24.pl/sport.xml'), (u'Biznes', u'http://www.tvn24.pl/biznes.xml'), (u'Meteo', u'http://www.tvn24.pl/meteo.xml'), (u'Micha\u0142ki', u'http://www.tvn24.pl/michalki.xml'), (u'Kultura', u'http://www.tvn24.pl/kultura.xml')]
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for item in soup.findAll(style=True):
|
||||
del item['style']
|
||||
return soup
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for alink in soup.findAll('a'):
|
||||
if alink.string is not None:
|
||||
|
@ -101,9 +101,9 @@ class InterfaceAction(QObject):
|
||||
#: on calibre as a whole
|
||||
action_type = 'global'
|
||||
|
||||
#: If True, the action may inspect the event at accept_enter_event() and
|
||||
#: accept_drag_move_event(), returning True or False if it wants to handle the event.
|
||||
#: drop_event() will be called in the subclass from calibre.gui2.bars
|
||||
#: If True, then this InterfaceAction will have the opportunity to interact
|
||||
#: with drag and drop events. See the methods, :meth:`accept_enter_event`,
|
||||
#: :meth`:accept_drag_move_event`, :meth:`drop_event` for details.
|
||||
accepts_drops = False
|
||||
|
||||
def __init__(self, parent, site_customization):
|
||||
@ -113,14 +113,26 @@ class InterfaceAction(QObject):
|
||||
self.site_customization = site_customization
|
||||
self.interface_action_base_plugin = None
|
||||
|
||||
def accept_enter_event(self, mime_data):
|
||||
def accept_enter_event(self, event, mime_data):
|
||||
''' This method should return True iff this interface action is capable
|
||||
of handling the drag event. Do not call accept/ignore on the event,
|
||||
that will be taken care of by the calibre UI.'''
|
||||
return False
|
||||
|
||||
def accept_drag_move_event(self, mime_data):
|
||||
def accept_drag_move_event(self, event, mime_data):
|
||||
''' This method should return True iff this interface action is capable
|
||||
of handling the drag event. Do not call accept/ignore on the event,
|
||||
that will be taken care of by the calibre UI.'''
|
||||
return False
|
||||
|
||||
def drop_event(self, event):
|
||||
pass
|
||||
def drop_event(self, event, mime_data):
|
||||
''' This method should perform some useful action and return True
|
||||
iff this interface action is capable of handling the drop event. Do not
|
||||
call accept/ignore on the event, that will be taken care of by the
|
||||
calibre UI. You should not perform blocking/long operations in this
|
||||
function. Instead emit a signal or use QTimer.singleShot and return
|
||||
quickly. See the builtin actions for examples.'''
|
||||
return False
|
||||
|
||||
def do_genesis(self):
|
||||
self.Dispatcher = partial(Dispatcher, parent=self)
|
||||
@ -145,7 +157,6 @@ class InterfaceAction(QObject):
|
||||
else:
|
||||
action = QAction(text, self.gui)
|
||||
if attr == 'qaction':
|
||||
action.associated_interface_action = self
|
||||
mt = (action.text() if self.action_menu_clone_qaction is True else
|
||||
unicode(self.action_menu_clone_qaction))
|
||||
self.menuless_qaction = ma = QAction(action.icon(), mt, self.gui)
|
||||
|
@ -18,7 +18,8 @@ from calibre import sanitize_file_name_unicode
|
||||
class GenerateCatalogAction(InterfaceAction):
|
||||
|
||||
name = 'Generate Catalog'
|
||||
action_spec = (_('Create catalog'), 'catalog.png', 'Catalog builder', ())
|
||||
action_spec = (_('Create catalog'), 'catalog.png',
|
||||
_('Create a catalog of the books in your calibre library in different formats'), ())
|
||||
dont_add_to = frozenset(['context-menu-device'])
|
||||
|
||||
def genesis(self):
|
||||
|
@ -8,7 +8,7 @@ __docformat__ = 'restructuredtext en'
|
||||
import os
|
||||
from functools import partial
|
||||
|
||||
from PyQt4.Qt import QModelIndex
|
||||
from PyQt4.Qt import QModelIndex, QTimer
|
||||
|
||||
from calibre.gui2 import error_dialog, Dispatcher
|
||||
from calibre.gui2.tools import convert_single_ebook, convert_bulk_ebook
|
||||
@ -19,11 +19,36 @@ from calibre.customize.ui import plugin_for_input_format
|
||||
class ConvertAction(InterfaceAction):
|
||||
|
||||
name = 'Convert Books'
|
||||
action_spec = (_('Convert books'), 'convert.png', None, _('C'))
|
||||
action_spec = (_('Convert books'), 'convert.png', _('Convert books between different ebook formats'), _('C'))
|
||||
dont_add_to = frozenset(['context-menu-device'])
|
||||
action_type = 'current'
|
||||
action_add_menu = True
|
||||
|
||||
accepts_drops = True
|
||||
|
||||
def accept_enter_event(self, event, mime_data):
|
||||
if mime_data.hasFormat("application/calibre+from_library"):
|
||||
return True
|
||||
return False
|
||||
|
||||
def accept_drag_move_event(self, event, mime_data):
|
||||
if mime_data.hasFormat("application/calibre+from_library"):
|
||||
return True
|
||||
return False
|
||||
|
||||
def drop_event(self, event, mime_data):
|
||||
mime = 'application/calibre+from_library'
|
||||
if mime_data.hasFormat(mime):
|
||||
self.dropped_ids = tuple(map(int, str(mime_data.data(mime)).split()))
|
||||
QTimer.singleShot(1, self.do_drop)
|
||||
return True
|
||||
return False
|
||||
|
||||
def do_drop(self):
|
||||
book_ids = self.dropped_ids
|
||||
del self.dropped_ids
|
||||
self.do_convert(book_ids)
|
||||
|
||||
def genesis(self):
|
||||
m = self.convert_menu = self.qaction.menu()
|
||||
cm = partial(self.create_menu_action, self.convert_menu)
|
||||
@ -112,6 +137,9 @@ class ConvertAction(InterfaceAction):
|
||||
def convert_ebook(self, checked, bulk=None):
|
||||
book_ids = self.get_books_for_conversion()
|
||||
if book_ids is None: return
|
||||
self.do_convert(book_ids, bulk=bulk)
|
||||
|
||||
def do_convert(self, book_ids, bulk=None):
|
||||
previous = self.gui.library_view.currentIndex()
|
||||
rows = [x.row() for x in \
|
||||
self.gui.library_view.selectionModel().selectedRows()]
|
||||
|
@ -83,11 +83,37 @@ class MultiDeleter(QObject): # {{{
|
||||
class DeleteAction(InterfaceAction):
|
||||
|
||||
name = 'Remove Books'
|
||||
action_spec = (_('Remove books'), 'trash.png', None, 'Del')
|
||||
action_spec = (_('Remove books'), 'trash.png', _('Delete books'), 'Del')
|
||||
action_type = 'current'
|
||||
action_add_menu = True
|
||||
action_menu_clone_qaction = _('Remove selected books')
|
||||
|
||||
accepts_drops = True
|
||||
|
||||
def accept_enter_event(self, event, mime_data):
|
||||
if mime_data.hasFormat("application/calibre+from_library"):
|
||||
return True
|
||||
return False
|
||||
|
||||
def accept_drag_move_event(self, event, mime_data):
|
||||
if mime_data.hasFormat("application/calibre+from_library"):
|
||||
return True
|
||||
return False
|
||||
|
||||
def drop_event(self, event, mime_data):
|
||||
mime = 'application/calibre+from_library'
|
||||
if mime_data.hasFormat(mime):
|
||||
self.dropped_ids = tuple(map(int, str(mime_data.data(mime)).split()))
|
||||
QTimer.singleShot(1, self.do_drop)
|
||||
return True
|
||||
return False
|
||||
|
||||
def do_drop(self):
|
||||
book_ids = self.dropped_ids
|
||||
del self.dropped_ids
|
||||
if book_ids:
|
||||
self.do_library_delete(book_ids)
|
||||
|
||||
def genesis(self):
|
||||
self.qaction.triggered.connect(self.delete_books)
|
||||
self.delete_menu = self.qaction.menu()
|
||||
@ -296,6 +322,44 @@ class DeleteAction(InterfaceAction):
|
||||
current_row = rmap.get(next_id, None)
|
||||
self.library_ids_deleted(ids_deleted, current_row=current_row)
|
||||
|
||||
def do_library_delete(self, to_delete_ids):
|
||||
view = self.gui.current_view()
|
||||
# Ask the user if they want to delete the book from the library or device if it is in both.
|
||||
if self.gui.device_manager.is_device_connected:
|
||||
on_device = False
|
||||
on_device_ids = self._get_selected_ids()
|
||||
for id in on_device_ids:
|
||||
res = self.gui.book_on_device(id)
|
||||
if res[0] or res[1] or res[2]:
|
||||
on_device = True
|
||||
if on_device:
|
||||
break
|
||||
if on_device:
|
||||
loc = confirm_location('<p>' + _('Some of the selected books are on the attached device. '
|
||||
'<b>Where</b> do you want the selected files deleted from?'),
|
||||
self.gui)
|
||||
if not loc:
|
||||
return
|
||||
elif loc == 'dev':
|
||||
self.remove_matching_books_from_device()
|
||||
return
|
||||
elif loc == 'both':
|
||||
self.remove_matching_books_from_device()
|
||||
# The following will run if the selected books are not on a connected device.
|
||||
# The user has selected to delete from the library or the device and library.
|
||||
if not confirm('<p>'+_('The selected books will be '
|
||||
'<b>permanently deleted</b> and the files '
|
||||
'removed from your calibre library. Are you sure?')
|
||||
+'</p>', 'library_delete_books', self.gui):
|
||||
return
|
||||
next_id = view.next_id
|
||||
if len(to_delete_ids) < 5:
|
||||
view.model().delete_books_by_id(to_delete_ids)
|
||||
self.library_ids_deleted2(to_delete_ids, next_id=next_id)
|
||||
else:
|
||||
self.__md = MultiDeleter(self.gui, to_delete_ids,
|
||||
partial(self.library_ids_deleted2, next_id=next_id))
|
||||
|
||||
def delete_books(self, *args):
|
||||
'''
|
||||
Delete selected books from device or library.
|
||||
@ -307,41 +371,7 @@ class DeleteAction(InterfaceAction):
|
||||
# Library view is visible.
|
||||
if self.gui.stack.currentIndex() == 0:
|
||||
to_delete_ids = [view.model().id(r) for r in rows]
|
||||
# Ask the user if they want to delete the book from the library or device if it is in both.
|
||||
if self.gui.device_manager.is_device_connected:
|
||||
on_device = False
|
||||
on_device_ids = self._get_selected_ids()
|
||||
for id in on_device_ids:
|
||||
res = self.gui.book_on_device(id)
|
||||
if res[0] or res[1] or res[2]:
|
||||
on_device = True
|
||||
if on_device:
|
||||
break
|
||||
if on_device:
|
||||
loc = confirm_location('<p>' + _('Some of the selected books are on the attached device. '
|
||||
'<b>Where</b> do you want the selected files deleted from?'),
|
||||
self.gui)
|
||||
if not loc:
|
||||
return
|
||||
elif loc == 'dev':
|
||||
self.remove_matching_books_from_device()
|
||||
return
|
||||
elif loc == 'both':
|
||||
self.remove_matching_books_from_device()
|
||||
# The following will run if the selected books are not on a connected device.
|
||||
# The user has selected to delete from the library or the device and library.
|
||||
if not confirm('<p>'+_('The selected books will be '
|
||||
'<b>permanently deleted</b> and the files '
|
||||
'removed from your calibre library. Are you sure?')
|
||||
+'</p>', 'library_delete_books', self.gui):
|
||||
return
|
||||
next_id = view.next_id
|
||||
if len(rows) < 5:
|
||||
view.model().delete_books_by_id(to_delete_ids)
|
||||
self.library_ids_deleted2(to_delete_ids, next_id=next_id)
|
||||
else:
|
||||
self.__md = MultiDeleter(self.gui, to_delete_ids,
|
||||
partial(self.library_ids_deleted2, next_id=next_id))
|
||||
self.do_library_delete(to_delete_ids)
|
||||
# Device view is visible.
|
||||
else:
|
||||
if self.gui.stack.currentIndex() == 1:
|
||||
|
@ -177,7 +177,8 @@ class SendToDeviceAction(InterfaceAction):
|
||||
class ConnectShareAction(InterfaceAction):
|
||||
|
||||
name = 'Connect Share'
|
||||
action_spec = (_('Connect/share'), 'connect_share.png', None, None)
|
||||
action_spec = (_('Connect/share'), 'connect_share.png',
|
||||
_('Share books using a web server or email. Connect to special devices, etc.'), None)
|
||||
popup_type = QToolButton.InstantPopup
|
||||
|
||||
def genesis(self):
|
||||
|
@ -23,10 +23,38 @@ from calibre.db.errors import NoSuchFormat
|
||||
class EditMetadataAction(InterfaceAction):
|
||||
|
||||
name = 'Edit Metadata'
|
||||
action_spec = (_('Edit metadata'), 'edit_input.png', None, _('E'))
|
||||
action_spec = (_('Edit metadata'), 'edit_input.png', _('Change the title/author/cover etc. of books'), _('E'))
|
||||
action_type = 'current'
|
||||
action_add_menu = True
|
||||
|
||||
accepts_drops = True
|
||||
|
||||
def accept_enter_event(self, event, mime_data):
|
||||
if mime_data.hasFormat("application/calibre+from_library"):
|
||||
return True
|
||||
return False
|
||||
|
||||
def accept_drag_move_event(self, event, mime_data):
|
||||
if mime_data.hasFormat("application/calibre+from_library"):
|
||||
return True
|
||||
return False
|
||||
|
||||
def drop_event(self, event, mime_data):
|
||||
mime = 'application/calibre+from_library'
|
||||
if mime_data.hasFormat(mime):
|
||||
self.dropped_ids = tuple(map(int, str(mime_data.data(mime)).split()))
|
||||
QTimer.singleShot(1, self.do_drop)
|
||||
return True
|
||||
return False
|
||||
|
||||
def do_drop(self):
|
||||
book_ids = self.dropped_ids
|
||||
del self.dropped_ids
|
||||
if book_ids:
|
||||
db = self.gui.library_view.model().db
|
||||
rows = [db.row(i) for i in book_ids]
|
||||
self.edit_metadata_for(rows, book_ids)
|
||||
|
||||
def genesis(self):
|
||||
md = self.qaction.menu()
|
||||
cm = partial(self.create_menu_action, md)
|
||||
@ -186,18 +214,23 @@ class EditMetadataAction(InterfaceAction):
|
||||
Edit metadata of selected books in library.
|
||||
'''
|
||||
rows = self.gui.library_view.selectionModel().selectedRows()
|
||||
previous = self.gui.library_view.currentIndex()
|
||||
if not rows or len(rows) == 0:
|
||||
d = error_dialog(self.gui, _('Cannot edit metadata'),
|
||||
_('No books selected'))
|
||||
d.exec_()
|
||||
return
|
||||
|
||||
if bulk or (bulk is None and len(rows) > 1):
|
||||
return self.edit_bulk_metadata(checked)
|
||||
|
||||
row_list = [r.row() for r in rows]
|
||||
m = self.gui.library_view.model()
|
||||
ids = [m.id(r) for r in rows]
|
||||
self.edit_metadata_for(row_list, ids, bulk=bulk)
|
||||
|
||||
def edit_metadata_for(self, rows, book_ids, bulk=None):
|
||||
previous = self.gui.library_view.currentIndex()
|
||||
if bulk or (bulk is None and len(rows) > 1):
|
||||
return self.do_edit_bulk_metadata(rows, book_ids)
|
||||
|
||||
current_row = 0
|
||||
row_list = rows
|
||||
|
||||
if len(row_list) == 1:
|
||||
cr = row_list[0]
|
||||
@ -242,7 +275,6 @@ class EditMetadataAction(InterfaceAction):
|
||||
db = self.gui.library_view.model().db
|
||||
view.view_format(db.row(id_), fmt)
|
||||
|
||||
|
||||
def edit_bulk_metadata(self, checked):
|
||||
'''
|
||||
Edit metadata of selected books in library in bulk.
|
||||
@ -256,6 +288,9 @@ class EditMetadataAction(InterfaceAction):
|
||||
_('No books selected'))
|
||||
d.exec_()
|
||||
return
|
||||
self.do_edit_bulk_metadata(rows, ids)
|
||||
|
||||
def do_edit_bulk_metadata(self, rows, book_ids):
|
||||
# Prevent the TagView from updating due to signals from the database
|
||||
self.gui.tags_view.blockSignals(True)
|
||||
changed = False
|
||||
@ -278,7 +313,7 @@ class EditMetadataAction(InterfaceAction):
|
||||
self.gui.tags_view.recount()
|
||||
if self.gui.cover_flow:
|
||||
self.gui.cover_flow.dataChanged()
|
||||
self.gui.library_view.select_rows(ids)
|
||||
self.gui.library_view.select_rows(book_ids)
|
||||
|
||||
# Merge books {{{
|
||||
def merge_books(self, safe_merge=False, merge_only_formats=False):
|
||||
|
@ -16,7 +16,7 @@ from calibre.gui2.actions import InterfaceAction
|
||||
class FetchNewsAction(InterfaceAction):
|
||||
|
||||
name = 'Fetch News'
|
||||
action_spec = (_('Fetch news'), 'news.png', None, _('F'))
|
||||
action_spec = (_('Fetch news'), 'news.png', _('Download news in ebook form from various websites all over the world'), _('F'))
|
||||
|
||||
def location_selected(self, loc):
|
||||
enabled = loc == 'library'
|
||||
|
@ -11,8 +11,8 @@ from calibre.gui2.actions import InterfaceAction
|
||||
class OpenFolderAction(InterfaceAction):
|
||||
|
||||
name = 'Open Folder'
|
||||
action_spec = (_('Open containing folder'), 'document_open.png', None,
|
||||
_('O'))
|
||||
action_spec = (_('Open containing folder'), 'document_open.png',
|
||||
_('Open the folder containing the current book\'s files'), _('O'))
|
||||
dont_add_to = frozenset(['context-menu-device'])
|
||||
action_type = 'current'
|
||||
|
||||
|
@ -15,7 +15,7 @@ from calibre.gui2.dialogs.plugin_updater import (PluginUpdaterDialog,
|
||||
class PluginUpdaterAction(InterfaceAction):
|
||||
|
||||
name = 'Plugin Updater'
|
||||
action_spec = (_('Plugin Updater'), None, None, ())
|
||||
action_spec = (_('Plugin Updater'), None, _('Update any plugins you have installed in calibre'), ())
|
||||
action_type = 'current'
|
||||
|
||||
def genesis(self):
|
||||
|
@ -10,6 +10,7 @@ __docformat__ = 'restructuredtext en'
|
||||
import os, weakref, shutil, textwrap
|
||||
from collections import OrderedDict
|
||||
from functools import partial
|
||||
from future_builtins import map
|
||||
|
||||
from PyQt4.Qt import (QDialog, QGridLayout, QIcon, QCheckBox, QLabel, QFrame,
|
||||
QApplication, QDialogButtonBox, Qt, QSize, QSpacerItem,
|
||||
@ -364,9 +365,35 @@ class Report(QDialog): # {{{
|
||||
class PolishAction(InterfaceAction):
|
||||
|
||||
name = 'Polish Books'
|
||||
action_spec = (_('Polish books'), 'polish.png', None, _('P'))
|
||||
action_spec = (_('Polish books'), 'polish.png',
|
||||
_('Apply the shine of perfection to your books'), _('P'))
|
||||
dont_add_to = frozenset(['context-menu-device'])
|
||||
action_type = 'current'
|
||||
accepts_drops = True
|
||||
|
||||
def accept_enter_event(self, event, mime_data):
|
||||
if mime_data.hasFormat("application/calibre+from_library"):
|
||||
return True
|
||||
return False
|
||||
|
||||
def accept_drag_move_event(self, event, mime_data):
|
||||
if mime_data.hasFormat("application/calibre+from_library"):
|
||||
return True
|
||||
return False
|
||||
|
||||
def drop_event(self, event, mime_data):
|
||||
mime = 'application/calibre+from_library'
|
||||
if mime_data.hasFormat(mime):
|
||||
self.dropped_ids = tuple(map(int, str(mime_data.data(mime)).split()))
|
||||
QTimer.singleShot(1, self.do_drop)
|
||||
return True
|
||||
return False
|
||||
|
||||
def do_drop(self):
|
||||
book_id_map = self.get_supported_books(self.dropped_ids)
|
||||
del self.dropped_ids
|
||||
if book_id_map:
|
||||
self.do_polish(book_id_map)
|
||||
|
||||
def genesis(self):
|
||||
self.qaction.triggered.connect(self.polish_books)
|
||||
@ -377,7 +404,6 @@ class PolishAction(InterfaceAction):
|
||||
self.qaction.setEnabled(enabled)
|
||||
|
||||
def get_books_for_polishing(self):
|
||||
from calibre.ebooks.oeb.polish.main import SUPPORTED
|
||||
rows = [r.row() for r in
|
||||
self.gui.library_view.selectionModel().selectedRows()]
|
||||
if not rows or len(rows) == 0:
|
||||
@ -387,11 +413,16 @@ class PolishAction(InterfaceAction):
|
||||
return None
|
||||
db = self.gui.library_view.model().db
|
||||
ans = (db.id(r) for r in rows)
|
||||
return self.get_supported_books(ans)
|
||||
|
||||
def get_supported_books(self, book_ids):
|
||||
from calibre.ebooks.oeb.polish.main import SUPPORTED
|
||||
db = self.gui.library_view.model().db
|
||||
supported = set(SUPPORTED)
|
||||
for x in SUPPORTED:
|
||||
supported.add('ORIGINAL_'+x)
|
||||
ans = [(x, set( (db.formats(x, index_is_id=True) or '').split(',') )
|
||||
.intersection(supported)) for x in ans]
|
||||
.intersection(supported)) for x in book_ids]
|
||||
ans = [x for x in ans if x[1]]
|
||||
if not ans:
|
||||
error_dialog(self.gui, _('Cannot polish'),
|
||||
@ -409,6 +440,9 @@ class PolishAction(InterfaceAction):
|
||||
book_id_map = self.get_books_for_polishing()
|
||||
if not book_id_map:
|
||||
return
|
||||
self.do_polish(book_id_map)
|
||||
|
||||
def do_polish(self, book_id_map):
|
||||
d = Polish(self.gui.library_view.model().db, book_id_map, parent=self.gui)
|
||||
if d.exec_() == d.Accepted and d.jobs:
|
||||
show_reports = bool(d.show_reports.isChecked())
|
||||
|
@ -17,7 +17,7 @@ from calibre.constants import DEBUG, isosx
|
||||
class PreferencesAction(InterfaceAction):
|
||||
|
||||
name = 'Preferences'
|
||||
action_spec = (_('Preferences'), 'config.png', None, _('Ctrl+P'))
|
||||
action_spec = (_('Preferences'), 'config.png', _('Configure calibre'), _('Ctrl+P'))
|
||||
action_add_menu = True
|
||||
action_menu_clone_qaction = _('Change calibre behavior')
|
||||
|
||||
|
@ -11,7 +11,7 @@ from calibre.gui2.actions import InterfaceAction
|
||||
class RestartAction(InterfaceAction):
|
||||
|
||||
name = 'Restart'
|
||||
action_spec = (_('Restart'), None, None, _('Ctrl+R'))
|
||||
action_spec = (_('Restart'), None, _('Restart calibre'), _('Ctrl+R'))
|
||||
|
||||
def genesis(self):
|
||||
self.qaction.triggered.connect(self.restart)
|
||||
|
@ -17,7 +17,8 @@ from calibre.gui2.actions import InterfaceAction
|
||||
class SaveToDiskAction(InterfaceAction):
|
||||
|
||||
name = "Save To Disk"
|
||||
action_spec = (_('Save to disk'), 'save.png', None, _('S'))
|
||||
action_spec = (_('Save to disk'), 'save.png',
|
||||
_('Export ebook files from the calibre library'), _('S'))
|
||||
action_type = 'current'
|
||||
action_add_menu = True
|
||||
action_menu_clone_qaction = True
|
||||
|
@ -13,8 +13,8 @@ from calibre.gui2 import error_dialog
|
||||
class ShowBookDetailsAction(InterfaceAction):
|
||||
|
||||
name = 'Show Book Details'
|
||||
action_spec = (_('Show book details'), 'dialog_information.png', None,
|
||||
_('I'))
|
||||
action_spec = (_('Show book details'), 'dialog_information.png',
|
||||
_('Show the detailed metadata for the current book in a separate window'), _('I'))
|
||||
dont_add_to = frozenset(['context-menu-device'])
|
||||
action_type = 'current'
|
||||
|
||||
|
@ -14,7 +14,7 @@ from calibre.gui2.actions import InterfaceAction
|
||||
class SimilarBooksAction(InterfaceAction):
|
||||
|
||||
name = 'Similar Books'
|
||||
action_spec = (_('Similar books...'), None, None, None)
|
||||
action_spec = (_('Similar books...'), None, _('Show books similar to the current book'), None)
|
||||
popup_type = QToolButton.InstantPopup
|
||||
action_type = 'current'
|
||||
action_add_menu = True
|
||||
|
@ -17,7 +17,7 @@ from calibre.gui2.dialogs.confirm_delete import confirm
|
||||
class StoreAction(InterfaceAction):
|
||||
|
||||
name = 'Store'
|
||||
action_spec = (_('Get books'), 'store.png', None, _('G'))
|
||||
action_spec = (_('Get books'), 'store.png', _('Search dozens of online ebook retailers for the cheapest books'), _('G'))
|
||||
action_add_menu = True
|
||||
action_menu_clone_qaction = _('Search for ebooks')
|
||||
|
||||
|
@ -64,7 +64,7 @@ class TweakBook(QDialog):
|
||||
self.fmt_choice_box = QGroupBox(_('Choose the format to tweak:'), self)
|
||||
self._fl = fl = QHBoxLayout()
|
||||
self.fmt_choice_box.setLayout(self._fl)
|
||||
self.fmt_choice_buttons = [QRadioButton(x, self) for x in fmts]
|
||||
self.fmt_choice_buttons = [QRadioButton(y, self) for y in fmts]
|
||||
for x in self.fmt_choice_buttons:
|
||||
fl.addWidget(x, stretch=10 if x is self.fmt_choice_buttons[-1] else
|
||||
0)
|
||||
@ -291,6 +291,32 @@ class TweakEpubAction(InterfaceAction):
|
||||
dont_add_to = frozenset(['context-menu-device'])
|
||||
action_type = 'current'
|
||||
|
||||
accepts_drops = True
|
||||
|
||||
def accept_enter_event(self, event, mime_data):
|
||||
if mime_data.hasFormat("application/calibre+from_library"):
|
||||
return True
|
||||
return False
|
||||
|
||||
def accept_drag_move_event(self, event, mime_data):
|
||||
if mime_data.hasFormat("application/calibre+from_library"):
|
||||
return True
|
||||
return False
|
||||
|
||||
def drop_event(self, event, mime_data):
|
||||
mime = 'application/calibre+from_library'
|
||||
if mime_data.hasFormat(mime):
|
||||
self.dropped_ids = tuple(map(int, str(mime_data.data(mime)).split()))
|
||||
QTimer.singleShot(1, self.do_drop)
|
||||
return True
|
||||
return False
|
||||
|
||||
def do_drop(self):
|
||||
book_ids = self.dropped_ids
|
||||
del self.dropped_ids
|
||||
if book_ids:
|
||||
self.do_tweak(book_ids[0])
|
||||
|
||||
def genesis(self):
|
||||
self.qaction.triggered.connect(self.tweak_book)
|
||||
|
||||
@ -301,6 +327,9 @@ class TweakEpubAction(InterfaceAction):
|
||||
_('No book selected'), show=True)
|
||||
|
||||
book_id = self.gui.library_view.model().id(row)
|
||||
self.do_tweak(book_id)
|
||||
|
||||
def do_tweak(self, book_id):
|
||||
db = self.gui.library_view.model().db
|
||||
fmts = db.formats(book_id, index_is_id=True) or ''
|
||||
fmts = [x.lower().strip() for x in fmts.split(',')]
|
||||
|
@ -34,7 +34,7 @@ class HistoryAction(QAction):
|
||||
class ViewAction(InterfaceAction):
|
||||
|
||||
name = 'View'
|
||||
action_spec = (_('View'), 'view.png', None, _('V'))
|
||||
action_spec = (_('View'), 'view.png', _('Read books'), _('V'))
|
||||
action_type = 'current'
|
||||
action_add_menu = True
|
||||
action_menu_clone_qaction = True
|
||||
|
@ -117,21 +117,30 @@ class ToolBar(QToolBar): # {{{
|
||||
return ch
|
||||
|
||||
# support drag&drop from/to library, from/to reader/card, enabled plugins
|
||||
def check_iactions_for_drag(self, event, md, func):
|
||||
if self.added_actions:
|
||||
pos = event.pos()
|
||||
for iac in self.gui.iactions.itervalues():
|
||||
if iac.accepts_drops:
|
||||
aa = iac.qaction
|
||||
w = self.widgetForAction(aa)
|
||||
m = aa.menu()
|
||||
if (( (w is not None and w.geometry().contains(pos)) or
|
||||
(m is not None and m.isVisible() and m.geometry().contains(pos)) ) and
|
||||
getattr(iac, func)(event, md)):
|
||||
return True
|
||||
return False
|
||||
|
||||
def dragEnterEvent(self, event):
|
||||
md = event.mimeData()
|
||||
if md.hasFormat("application/calibre+from_library") or \
|
||||
md.hasFormat("application/calibre+from_device"):
|
||||
event.setDropAction(Qt.CopyAction)
|
||||
event.accept()
|
||||
elif self.added_actions:
|
||||
for aa in self.added_actions:
|
||||
if (getattr(aa.associated_interface_action, 'accepts_drops', False) and
|
||||
aa.menu().geometry().contains(event.pos())):
|
||||
if aa.associated_interface_action.accept_enter_event(md):
|
||||
event.accept()
|
||||
break
|
||||
else:
|
||||
event.ignore()
|
||||
return
|
||||
|
||||
if self.check_iactions_for_drag(event, md, 'accept_enter_event'):
|
||||
event.accept()
|
||||
else:
|
||||
event.ignore()
|
||||
|
||||
@ -152,15 +161,8 @@ class ToolBar(QToolBar): # {{{
|
||||
event.acceptProposedAction()
|
||||
return
|
||||
|
||||
if self.added_actions:
|
||||
for aa in self.added_actions:
|
||||
if (getattr(aa.associated_interface_action, 'accepts_drops', False) and
|
||||
aa.menu().geometry().contains(event.pos())):
|
||||
if aa.associated_interface_action.accept_drag_move_event(md):
|
||||
event.acceptProposedAction()
|
||||
break
|
||||
else:
|
||||
event.ignore()
|
||||
if self.check_iactions_for_drag(event, md, 'accept_drag_move_event'):
|
||||
event.acceptProposedAction()
|
||||
else:
|
||||
event.ignore()
|
||||
|
||||
@ -191,11 +193,8 @@ class ToolBar(QToolBar): # {{{
|
||||
return
|
||||
|
||||
# Give added_actions an opportunity to process the drag&drop event
|
||||
for aa in self.added_actions:
|
||||
if (getattr(aa.associated_interface_action, 'accepts_drops', False) and
|
||||
aa.menu().geometry().contains(event.pos())):
|
||||
aa.associated_interface_action.drop_event(event)
|
||||
event.accept()
|
||||
if self.check_iactions_for_drag(event, data, 'drop_event'):
|
||||
event.accept()
|
||||
else:
|
||||
event.ignore()
|
||||
|
||||
|
@ -28,9 +28,10 @@ class BaseModel(QAbstractListModel):
|
||||
|
||||
def name_to_action(self, name, gui):
|
||||
if name == 'Donate':
|
||||
return FakeAction('Donate', _('Donate'), 'donate.png',
|
||||
dont_add_to=frozenset(['context-menu',
|
||||
'context-menu-device']))
|
||||
return FakeAction(
|
||||
'Donate', _('Donate'), 'donate.png', tooltip=
|
||||
_('Donate to support the development of calibre'),
|
||||
dont_add_to=frozenset(['context-menu', 'context-menu-device']))
|
||||
if name == 'Location Manager':
|
||||
return FakeAction('Location Manager', _('Location Manager'), 'reader.png',
|
||||
_('Switch between library and device views'),
|
||||
@ -247,6 +248,18 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
self.remove_action_button.clicked.connect(self.remove_action)
|
||||
self.action_up_button.clicked.connect(partial(self.move, -1))
|
||||
self.action_down_button.clicked.connect(partial(self.move, 1))
|
||||
self.all_actions.setMouseTracking(True)
|
||||
self.current_actions.setMouseTracking(True)
|
||||
self.all_actions.entered.connect(self.all_entered)
|
||||
self.current_actions.entered.connect(self.current_entered)
|
||||
|
||||
def all_entered(self, index):
|
||||
tt = self.all_actions.model().data(index, Qt.ToolTipRole).toString()
|
||||
self.help_text.setText(tt)
|
||||
|
||||
def current_entered(self, index):
|
||||
tt = self.current_actions.model().data(index, Qt.ToolTipRole).toString()
|
||||
self.help_text.setText(tt)
|
||||
|
||||
def what_changed(self, idx):
|
||||
key = unicode(self.what.itemData(idx).toString())
|
||||
@ -264,7 +277,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
names = self.all_actions.model().names(x)
|
||||
if names:
|
||||
not_added = self.current_actions.model().add(names)
|
||||
ns = set([x.name for x in not_added])
|
||||
ns = set([y.name for y in not_added])
|
||||
added = set(names) - ns
|
||||
self.all_actions.model().remove(x, added)
|
||||
if not_added:
|
||||
@ -283,7 +296,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
names = self.current_actions.model().names(x)
|
||||
if names:
|
||||
not_removed = self.current_actions.model().remove(x)
|
||||
ns = set([x.name for x in not_removed])
|
||||
ns = set([y.name for y in not_removed])
|
||||
removed = set(names) - ns
|
||||
self.all_actions.model().add(removed)
|
||||
if not_removed:
|
||||
|
@ -234,6 +234,13 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="help_text">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="spacer_widget" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user