mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Add framework for allowing interface actions to accept drag and drop events. Apple driver: Fix bug preventing sending books to iBooks if no books have been previously added to iBooks. Fixes #1141078 ('NoneType' object is not iterable)
This commit is contained in:
commit
7e004def33
@ -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:
|
||||
|
@ -21,7 +21,6 @@ from calibre.utils.config import config_dir, dynamic, prefs
|
||||
from calibre.utils.date import now, parse_date
|
||||
from calibre.utils.zipfile import ZipFile
|
||||
|
||||
# DEBUG = False
|
||||
DEBUG = CALIBRE_DEBUG
|
||||
|
||||
def strftime(fmt='%Y/%m/%d %H:%M:%S', dt=None):
|
||||
@ -861,7 +860,6 @@ class ITUNES(DriverBase):
|
||||
Note that most of the initialization is necessarily performed in can_handle(), as
|
||||
we need to talk to iTunes to discover if there's a connected iPod
|
||||
'''
|
||||
|
||||
if self.iTunes is None:
|
||||
raise OpenFeedback(self.ITUNES_SANDBOX_LOCKOUT_MESSAGE)
|
||||
|
||||
@ -2156,27 +2154,28 @@ class ITUNES(DriverBase):
|
||||
if 'iPod' in self.sources:
|
||||
connected_device = self.sources['iPod']
|
||||
device = self.iTunes.sources[connected_device]
|
||||
dev_books = None
|
||||
for pl in device.playlists():
|
||||
if pl.special_kind() == appscript.k.Books:
|
||||
if DEBUG:
|
||||
logger().info(" Book playlist: '%s'" % (pl.name()))
|
||||
dev_books = pl.file_tracks()
|
||||
break
|
||||
else:
|
||||
logger().error(" book_playlist not found")
|
||||
|
||||
for book in dev_books:
|
||||
if book.kind() in self.Audiobooks:
|
||||
if DEBUG:
|
||||
logger().info(" ignoring '%s' of type '%s'" % (book.name(), book.kind()))
|
||||
if device.playlists() is not None:
|
||||
dev_books = None
|
||||
for pl in device.playlists():
|
||||
if pl.special_kind() == appscript.k.Books:
|
||||
if DEBUG:
|
||||
logger().info(" Book playlist: '%s'" % (pl.name()))
|
||||
dev_books = pl.file_tracks()
|
||||
break
|
||||
else:
|
||||
if DEBUG:
|
||||
logger().info(" %-40.40s %-30.30s %-40.40s [%s]" %
|
||||
(book.name(), book.artist(), book.composer(), book.kind()))
|
||||
device_books.append(book)
|
||||
if DEBUG:
|
||||
logger().info()
|
||||
logger().error(" book_playlist not found")
|
||||
|
||||
for book in dev_books:
|
||||
if book.kind() in self.Audiobooks:
|
||||
if DEBUG:
|
||||
logger().info(" ignoring '%s' of type '%s'" % (book.name(), book.kind()))
|
||||
else:
|
||||
if DEBUG:
|
||||
logger().info(" %-40.40s %-30.30s %-40.40s [%s]" %
|
||||
(book.name(), book.artist(), book.composer(), book.kind()))
|
||||
device_books.append(book)
|
||||
if DEBUG:
|
||||
logger().info()
|
||||
|
||||
elif iswindows:
|
||||
import pythoncom
|
||||
@ -2186,29 +2185,29 @@ class ITUNES(DriverBase):
|
||||
pythoncom.CoInitialize()
|
||||
connected_device = self.sources['iPod']
|
||||
device = self.iTunes.sources.ItemByName(connected_device)
|
||||
|
||||
dev_books = None
|
||||
for pl in device.Playlists:
|
||||
if pl.Kind == self.PlaylistKind.index('User') and \
|
||||
pl.SpecialKind == self.PlaylistSpecialKind.index('Books'):
|
||||
if DEBUG:
|
||||
logger().info(" Books playlist: '%s'" % (pl.Name))
|
||||
dev_books = pl.Tracks
|
||||
break
|
||||
else:
|
||||
if DEBUG:
|
||||
logger().info(" no Books playlist found")
|
||||
|
||||
for book in dev_books:
|
||||
if book.KindAsString in self.Audiobooks:
|
||||
if DEBUG:
|
||||
logger().info(" ignoring '%s' of type '%s'" % (book.Name, book.KindAsString))
|
||||
if device.Playlists is not None:
|
||||
dev_books = None
|
||||
for pl in device.Playlists:
|
||||
if pl.Kind == self.PlaylistKind.index('User') and \
|
||||
pl.SpecialKind == self.PlaylistSpecialKind.index('Books'):
|
||||
if DEBUG:
|
||||
logger().info(" Books playlist: '%s'" % (pl.Name))
|
||||
dev_books = pl.Tracks
|
||||
break
|
||||
else:
|
||||
if DEBUG:
|
||||
logger().info(" %-40.40s %-30.30s %-40.40s [%s]" % (book.Name, book.Artist, book.Composer, book.KindAsString))
|
||||
device_books.append(book)
|
||||
if DEBUG:
|
||||
logger().info()
|
||||
logger().info(" no Books playlist found")
|
||||
|
||||
for book in dev_books:
|
||||
if book.KindAsString in self.Audiobooks:
|
||||
if DEBUG:
|
||||
logger().info(" ignoring '%s' of type '%s'" % (book.Name, book.KindAsString))
|
||||
else:
|
||||
if DEBUG:
|
||||
logger().info(" %-40.40s %-30.30s %-40.40s [%s]" % (book.Name, book.Artist, book.Composer, book.KindAsString))
|
||||
device_books.append(book)
|
||||
if DEBUG:
|
||||
logger().info()
|
||||
|
||||
finally:
|
||||
pythoncom.CoUninitialize()
|
||||
|
@ -101,6 +101,11 @@ class InterfaceAction(QObject):
|
||||
#: on calibre as a whole
|
||||
action_type = 'global'
|
||||
|
||||
#: 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):
|
||||
QObject.__init__(self, parent)
|
||||
self.setObjectName(self.name)
|
||||
@ -108,6 +113,21 @@ class InterfaceAction(QObject):
|
||||
self.site_customization = site_customization
|
||||
self.interface_action_base_plugin = None
|
||||
|
||||
def accept_enter_event(self, event, mime_data):
|
||||
''' This method should return True iff this interface action is capable
|
||||
of handling the drag event. '''
|
||||
return False
|
||||
|
||||
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. '''
|
||||
return False
|
||||
|
||||
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 drag event. '''
|
||||
return False
|
||||
|
||||
def do_genesis(self):
|
||||
self.Dispatcher = partial(Dispatcher, parent=self)
|
||||
self.create_action()
|
||||
|
@ -8,8 +8,8 @@ __copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
|
||||
from PyQt4.Qt import (QObject, QToolBar, Qt, QSize, QToolButton, QVBoxLayout,
|
||||
QLabel, QWidget, QAction, QMenuBar, QMenu)
|
||||
from PyQt4.Qt import (Qt, QAction, QLabel, QMenu, QMenuBar, QObject,
|
||||
QToolBar, QToolButton, QSize, QVBoxLayout, QWidget)
|
||||
|
||||
from calibre.constants import isosx
|
||||
from calibre.gui2 import gprefs
|
||||
@ -116,20 +116,37 @@ class ToolBar(QToolBar): # {{{
|
||||
ch.setPopupMode(menu_mode)
|
||||
return ch
|
||||
|
||||
#support drag&drop from/to library from/to reader/card
|
||||
# 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)
|
||||
func = getattr(iac, func)
|
||||
if (( (w is not None and w.geometry().contains(pos)) or
|
||||
aa.menu().geometry().contains(pos)) and 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()
|
||||
return
|
||||
|
||||
if self.check_iactions_for_drag(event, md, 'accept_enter_event'):
|
||||
event.accept()
|
||||
else:
|
||||
event.ignore()
|
||||
|
||||
def dragMoveEvent(self, event):
|
||||
allowed = False
|
||||
md = event.mimeData()
|
||||
#Drop is only allowed in the location manager widget's different from the selected one
|
||||
# Drop is only allowed in the location manager widget's different from the selected one
|
||||
for ac in self.location_manager.available_actions:
|
||||
w = self.widgetForAction(ac)
|
||||
if w is not None:
|
||||
@ -141,12 +158,15 @@ class ToolBar(QToolBar): # {{{
|
||||
break
|
||||
if allowed:
|
||||
event.acceptProposedAction()
|
||||
return
|
||||
|
||||
if self.check_iactions_for_drag(event, md, 'accept_drag_move_event'):
|
||||
event.acceptProposedAction()
|
||||
else:
|
||||
event.ignore()
|
||||
|
||||
def dropEvent(self, event):
|
||||
data = event.mimeData()
|
||||
|
||||
mime = 'application/calibre+from_library'
|
||||
if data.hasFormat(mime):
|
||||
ids = list(map(int, str(data.data(mime)).split()))
|
||||
@ -160,6 +180,7 @@ class ToolBar(QToolBar): # {{{
|
||||
tgt = None
|
||||
self.gui.sync_to_device(tgt, False, send_ids=ids)
|
||||
event.accept()
|
||||
return
|
||||
|
||||
mime = 'application/calibre+from_device'
|
||||
if data.hasFormat(mime):
|
||||
@ -168,6 +189,13 @@ class ToolBar(QToolBar): # {{{
|
||||
self.gui.iactions['Add Books'].add_books_from_device(
|
||||
self.gui.current_view(), paths=paths)
|
||||
event.accept()
|
||||
return
|
||||
|
||||
# Give added_actions an opportunity to process the drag&drop event
|
||||
if self.check_iactions_for_drag(event, data, 'drop_event'):
|
||||
event.accept()
|
||||
else:
|
||||
event.ignore()
|
||||
|
||||
# }}}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user