merge main branch

This commit is contained in:
Fabian Graßl 2010-10-07 15:08:02 +02:00
commit 498c34bca0
7 changed files with 262 additions and 113 deletions

View File

@ -17,7 +17,7 @@ from calibre.ebooks.metadata import authors_to_string, MetaInformation
from calibre.ebooks.metadata.book.base import Metadata
from calibre.ebooks.metadata.epub import set_metadata
from calibre.library.server.utils import strftime
from calibre.utils.config import config_dir
from calibre.utils.config import config_dir, prefs
from calibre.utils.date import isoformat, now, parse_date
from calibre.utils.localization import get_lang
from calibre.utils.logging import Log
@ -68,6 +68,8 @@ class ITUNES(DriverBase):
Delete:
delete_books()
remove_books_from_metadata()
use_plugboard_ext()
set_plugboard()
sync_booklists()
card_prefix()
free_space()
@ -76,6 +78,8 @@ class ITUNES(DriverBase):
set_progress_reporter()
upload_books()
add_books_to_metadata()
use_plugboard_ext()
set_plugboard()
set_progress_reporter()
sync_booklists()
card_prefix()
@ -106,6 +110,9 @@ class ITUNES(DriverBase):
PRODUCT_ID = [0x1292,0x1293,0x1294,0x1297,0x1299,0x129a]
BCD = [0x01]
# Plugboard ID
DEVICE_PLUGBOARD_NAME = 'APPLE'
# iTunes enumerations
Audiobooks = [
'Audible file',
@ -164,6 +171,7 @@ class ITUNES(DriverBase):
# Properties
cached_books = {}
cache_dir = os.path.join(config_dir, 'caches', 'itunes')
calibre_library_path = prefs['library_path']
archive_path = os.path.join(cache_dir, "thumbs.zip")
description_prefix = "added by calibre"
ejected = False
@ -173,6 +181,8 @@ class ITUNES(DriverBase):
log = Log()
manual_sync_mode = False
path_template = 'iTunes/%s - %s.%s'
plugboards = None
plugboard_func = None
problem_titles = []
problem_msg = None
report_progress = None
@ -814,6 +824,15 @@ class ITUNES(DriverBase):
'''
self.report_progress = report_progress
def set_plugboards(self, plugboards, pb_func):
# This method is called with the plugboard that matches the format
# declared in use_plugboard_ext and a device name of ITUNES
if DEBUG:
self.log.info("ITUNES.set_plugboard()")
#self.log.info(' using plugboard %s' % plugboards)
self.plugboards = plugboards
self.plugboard_func = pb_func
def sync_booklists(self, booklists, end_session=True):
'''
Update metadata on device.
@ -977,7 +996,6 @@ class ITUNES(DriverBase):
self._dump_cached_books(header="after upload_books()",indent=2)
return (new_booklist, [], [])
# Private methods
def _add_device_book(self,fpath, metadata):
'''
@ -1256,7 +1274,10 @@ class ITUNES(DriverBase):
self.problem_titles.append("'%s' by %s" % (metadata.title, metadata.author[0]))
self.log.error(" error converting '%s' to thumb for '%s'" % (metadata.cover,metadata.title))
finally:
zfw.close()
try:
zfw.close()
except:
pass
else:
if DEBUG:
self.log.info(" no cover defined in metadata for '%s'" % metadata.title)
@ -1273,10 +1294,10 @@ class ITUNES(DriverBase):
this_book.db_id = None
this_book.device_collections = []
this_book.format = format
this_book.library_id = lb_added
this_book.library_id = lb_added # ??? GR
this_book.path = path
this_book.thumbnail = thumb
this_book.iTunes_id = lb_added
this_book.iTunes_id = lb_added # ??? GR
this_book.uuid = metadata.uuid
if isosx:
@ -1322,8 +1343,8 @@ class ITUNES(DriverBase):
plist = None
if plist:
if DEBUG:
self.log.info(" _delete_iTunesMetadata_plist():")
self.log.info(" deleting '%s'\n from '%s'" % (pl_name,fpath))
self.log.info(" _delete_iTunesMetadata_plist():")
self.log.info(" deleting '%s'\n from '%s'" % (pl_name,fpath))
zf.delete(pl_name)
zf.close()
@ -2213,6 +2234,7 @@ class ITUNES(DriverBase):
(self.iTunes.name(), self.iTunes.version(), self.initial_status,
self.version[0],self.version[1],self.version[2]))
self.log.info(" iTunes_media: %s" % self.iTunes_media)
self.log.info(" calibre_library_path: %s" % self.calibre_library_path)
if iswindows:
'''
@ -2266,6 +2288,7 @@ class ITUNES(DriverBase):
(self.iTunes.Windows[0].name, self.iTunes.Version, self.initial_status,
self.version[0],self.version[1],self.version[2]))
self.log.info(" iTunes_media: %s" % self.iTunes_media)
self.log.info(" calibre_library_path: %s" % self.calibre_library_path)
def _purge_orphans(self,library_books, cached_books):
'''
@ -2368,7 +2391,8 @@ class ITUNES(DriverBase):
'''
iTunes does not delete books from storage when removing from database
We only want to delete stored copies if the file is stored in iTunes
We don't want to delete files stored outside of iTunes
We don't want to delete files stored outside of iTunes.
Also confirm that storage_path does not point into calibre's storage.
'''
if DEBUG:
self.log.info(" ITUNES._remove_from_iTunes():")
@ -2376,7 +2400,8 @@ class ITUNES(DriverBase):
if isosx:
try:
storage_path = os.path.split(cached_book['lib_book'].location().path)
if cached_book['lib_book'].location().path.startswith(self.iTunes_media):
if cached_book['lib_book'].location().path.startswith(self.iTunes_media) and \
not storage_path[0].startswith(self.calibre_library_path):
title_storage_path = storage_path[0]
if DEBUG:
self.log.info(" removing title_storage_path: %s" % title_storage_path)
@ -2427,7 +2452,8 @@ class ITUNES(DriverBase):
path = book.Location
if book:
if self.iTunes_media and path.startswith(self.iTunes_media):
if self.iTunes_media and path.startswith(self.iTunes_media) and \
not path.startswith(self.calibre_library_path):
storage_path = os.path.split(path)
if DEBUG:
self.log.info(" removing '%s' at %s" %
@ -2454,11 +2480,17 @@ class ITUNES(DriverBase):
if DEBUG:
self.log.info(" unable to remove '%s' from iTunes" % cached_book['title'])
def title_sorter(self, title):
return re.sub('^\s*A\s+|^\s*The\s+|^\s*An\s+', '', title).rstrip()
def _update_epub_metadata(self, fpath, metadata):
'''
'''
self.log.info(" ITUNES._update_epub_metadata()")
# Fetch plugboard updates
metadata_x = self._xform_metadata_via_plugboard(metadata, 'epub')
# Refresh epub metadata
with open(fpath,'r+b') as zfo:
# Touch the OPF timestamp
@ -2490,9 +2522,14 @@ class ITUNES(DriverBase):
self.log.info(" add timestamp: %s" % metadata.timestamp)
# Force the language declaration for iBooks 1.1
metadata.language = get_lang().replace('_', '-')
#metadata.language = get_lang().replace('_', '-')
# Updates from metadata plugboard (ignoring publisher)
metadata.language = metadata_x.language
if DEBUG:
self.log.info(" rewriting language: <dc:language>%s</dc:language>" % metadata.language)
if metadata.language != metadata_x.language:
self.log.info(" rewriting language: <dc:language>%s</dc:language>" % metadata.language)
zf_opf.close()
@ -2570,75 +2607,97 @@ class ITUNES(DriverBase):
if DEBUG:
self.log.info(" ITUNES._update_iTunes_metadata()")
strip_tags = re.compile(r'<[^<]*?/?>')
STRIP_TAGS = re.compile(r'<[^<]*?/?>')
# Update metadata from plugboard
# If self.plugboard is None (no transforms), original metadata is returned intact
metadata_x = self._xform_metadata_via_plugboard(metadata, this_book.format)
if isosx:
if lb_added:
lb_added.album.set(metadata.title)
lb_added.artist.set(authors_to_string(metadata.authors))
lb_added.composer.set(metadata.uuid)
lb_added.name.set(metadata_x.title)
lb_added.album.set(metadata_x.title)
lb_added.artist.set(authors_to_string(metadata_x.authors))
lb_added.composer.set(metadata_x.uuid)
lb_added.description.set("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S')))
lb_added.enabled.set(True)
lb_added.sort_artist.set(metadata.author_sort.title())
lb_added.sort_name.set(this_book.title_sorter)
if this_book.format == 'pdf':
lb_added.name.set(metadata.title)
lb_added.sort_artist.set(metadata_x.author_sort.title())
lb_added.sort_name.set(metadata.title_sort)
if db_added:
db_added.album.set(metadata.title)
db_added.artist.set(authors_to_string(metadata.authors))
db_added.composer.set(metadata.uuid)
db_added.name.set(metadata_x.title)
db_added.album.set(metadata_x.title)
db_added.artist.set(authors_to_string(metadata_x.authors))
db_added.composer.set(metadata_x.uuid)
db_added.description.set("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S')))
db_added.enabled.set(True)
db_added.sort_artist.set(metadata.author_sort.title())
db_added.sort_name.set(this_book.title_sorter)
if this_book.format == 'pdf':
db_added.name.set(metadata.title)
db_added.sort_artist.set(metadata_x.author_sort.title())
db_added.sort_name.set(metadata.title_sort)
if metadata.comments:
if metadata_x.comments:
if lb_added:
lb_added.comment.set(strip_tags.sub('',metadata.comments))
lb_added.comment.set(STRIP_TAGS.sub('',metadata_x.comments))
if db_added:
db_added.comment.set(strip_tags.sub('',metadata.comments))
db_added.comment.set(STRIP_TAGS.sub('',metadata_x.comments))
if metadata.rating:
if metadata_x.rating:
if lb_added:
lb_added.rating.set(metadata.rating*10)
lb_added.rating.set(metadata_x.rating*10)
# iBooks currently doesn't allow setting rating ... ?
try:
if db_added:
db_added.rating.set(metadata.rating*10)
db_added.rating.set(metadata_x.rating*10)
except:
pass
# Set genre from series if available, else first alpha tag
# Otherwise iTunes grabs the first dc:subject from the opf metadata
if metadata.series and self.settings().read_metadata:
# self.settings().read_metadata is used as a surrogate for "Use Series name as Genre"
if metadata_x.series and self.settings().read_metadata:
if DEBUG:
self.log.info(" ITUNES._update_iTunes_metadata()")
self.log.info(" using Series name as Genre")
# Format the index as a sort key
index = metadata.series_index
index = metadata_x.series_index
integer = int(index)
fraction = index-integer
series_index = '%04d%s' % (integer, str('%0.4f' % fraction).lstrip('0'))
if lb_added:
lb_added.sort_name.set("%s %s" % (metadata.series, series_index))
lb_added.genre.set(metadata.series)
lb_added.episode_ID.set(metadata.series)
lb_added.episode_number.set(metadata.series_index)
lb_added.sort_name.set("%s %s" % (self.title_sorter(metadata_x.series), series_index))
lb_added.episode_ID.set(metadata_x.series)
lb_added.episode_number.set(metadata_x.series_index)
# If no plugboard transform applied to tags, change the Genre/Category to Series
if metadata.tags == metadata_x.tags:
lb_added.genre.set(self.title_sorter(metadata_x.series))
else:
for tag in metadata_x.tags:
if self._is_alpha(tag[0]):
lb_added.genre.set(tag)
break
if db_added:
db_added.sort_name.set("%s %s" % (metadata.series, series_index))
db_added.genre.set(metadata.series)
db_added.episode_ID.set(metadata.series)
db_added.episode_number.set(metadata.series_index)
db_added.sort_name.set("%s %s" % (self.title_sorter(metadata_x.series), series_index))
db_added.episode_ID.set(metadata_x.series)
db_added.episode_number.set(metadata_x.series_index)
elif metadata.tags:
# If no plugboard transform applied to tags, change the Genre/Category to Series
if metadata.tags == metadata_x.tags:
db_added.genre.set(self.title_sorter(metadata_x.series))
else:
for tag in metadata_x.tags:
if self._is_alpha(tag[0]):
db_added.genre.set(tag)
break
elif metadata_x.tags is not None:
if DEBUG:
self.log.info(" %susing Tag as Genre" %
"no Series name available, " if self.settings().read_metadata else '')
for tag in metadata.tags:
for tag in metadata_x.tags:
if self._is_alpha(tag[0]):
if lb_added:
lb_added.genre.set(tag)
@ -2648,40 +2707,38 @@ class ITUNES(DriverBase):
elif iswindows:
if lb_added:
lb_added.Album = metadata.title
lb_added.Artist = authors_to_string(metadata.authors)
lb_added.Composer = metadata.uuid
lb_added.Name = metadata_x.title
lb_added.Album = metadata_x.title
lb_added.Artist = authors_to_string(metadata_x.authors)
lb_added.Composer = metadata_x.uuid
lb_added.Description = ("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S')))
lb_added.Enabled = True
lb_added.SortArtist = (metadata.author_sort.title())
lb_added.SortName = (this_book.title_sorter)
if this_book.format == 'pdf':
lb_added.Name = metadata.title
lb_added.SortArtist = metadata_x.author_sort.title()
lb_added.SortName = metadata.title_sort
if db_added:
db_added.Album = metadata.title
db_added.Artist = authors_to_string(metadata.authors)
db_added.Composer = metadata.uuid
db_added.Name = metadata_x.title
db_added.Album = metadata_x.title
db_added.Artist = authors_to_string(metadata_x.authors)
db_added.Composer = metadata_x.uuid
db_added.Description = ("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S')))
db_added.Enabled = True
db_added.SortArtist = (metadata.author_sort.title())
db_added.SortName = (this_book.title_sorter)
if this_book.format == 'pdf':
db_added.Name = metadata.title
db_added.SortArtist = metadata_x.author_sort.title()
db_added.SortName = metadata.title_sort
if metadata.comments:
if metadata_x.comments:
if lb_added:
lb_added.Comment = (strip_tags.sub('',metadata.comments))
lb_added.Comment = (STRIP_TAGS.sub('',metadata_x.comments))
if db_added:
db_added.Comment = (strip_tags.sub('',metadata.comments))
db_added.Comment = (STRIP_TAGS.sub('',metadata_x.comments))
if metadata.rating:
if metadata_x.rating:
if lb_added:
lb_added.AlbumRating = (metadata.rating*10)
lb_added.AlbumRating = (metadata_x.rating*10)
# iBooks currently doesn't allow setting rating ... ?
try:
if db_added:
db_added.AlbumRating = (metadata.rating*10)
db_added.AlbumRating = (metadata_x.rating*10)
except:
if DEBUG:
self.log.warning(" iTunes automation interface reported an error"
@ -2691,36 +2748,54 @@ class ITUNES(DriverBase):
# Otherwise iBooks uses first <dc:subject> from opf
# iTunes balks on setting EpisodeNumber, but it sticks (9.1.1.12)
if metadata.series and self.settings().read_metadata:
if metadata_x.series and self.settings().read_metadata:
if DEBUG:
self.log.info(" using Series name as Genre")
# Format the index as a sort key
index = metadata.series_index
index = metadata_x.series_index
integer = int(index)
fraction = index-integer
series_index = '%04d%s' % (integer, str('%0.4f' % fraction).lstrip('0'))
if lb_added:
lb_added.SortName = "%s %s" % (metadata.series, series_index)
lb_added.Genre = metadata.series
lb_added.EpisodeID = metadata.series
lb_added.SortName = "%s %s" % (self.title_sorter(metadata_x.series), series_index)
lb_added.EpisodeID = metadata_x.series
try:
lb_added.EpisodeNumber = metadata.series_index
lb_added.EpisodeNumber = metadata_x.series_index
except:
pass
# If no plugboard transform applied to tags, change the Genre/Category to Series
if metadata.tags == metadata_x.tags:
lb_added.Genre = self.title_sorter(metadata_x.series)
else:
for tag in metadata_x.tags:
if self._is_alpha(tag[0]):
lb_added.Genre = tag
break
if db_added:
db_added.SortName = "%s %s" % (metadata.series, series_index)
db_added.Genre = metadata.series
db_added.EpisodeID = metadata.series
db_added.SortName = "%s %s" % (self.title_sorter(metadata_x.series), series_index)
db_added.EpisodeID = metadata_x.series
try:
db_added.EpisodeNumber = metadata.series_index
db_added.EpisodeNumber = metadata_x.series_index
except:
if DEBUG:
self.log.warning(" iTunes automation interface reported an error"
" setting EpisodeNumber on iDevice")
elif metadata.tags:
# If no plugboard transform applied to tags, change the Genre/Category to Series
if metadata.tags == metadata_x.tags:
db_added.Genre = self.title_sorter(metadata_x.series)
else:
for tag in metadata_x.tags:
if self._is_alpha(tag[0]):
db_added.Genre = tag
break
elif metadata_x.tags is not None:
if DEBUG:
self.log.info(" using Tag as Genre")
for tag in metadata.tags:
for tag in metadata_x.tags:
if self._is_alpha(tag[0]):
if lb_added:
lb_added.Genre = tag
@ -2728,6 +2803,36 @@ class ITUNES(DriverBase):
db_added.Genre = tag
break
def _xform_metadata_via_plugboard(self, book, format):
''' Transform book metadata from plugboard templates '''
if DEBUG:
self.log.info(" ITUNES._update_metadata_from_plugboard()")
if self.plugboard_func:
pb = self.plugboard_func(self.DEVICE_PLUGBOARD_NAME, format, self.plugboards)
newmi = book.deepcopy_metadata()
newmi.template_to_attribute(book, pb)
if DEBUG:
self.log.info(" transforming %s using %s:" % (format, pb))
self.log.info(" title: %s %s" % (book.title, ">>> %s" %
newmi.title if book.title != newmi.title else ''))
self.log.info(" title_sort: %s %s" % (book.title_sort, ">>> %s" %
newmi.title_sort if book.title_sort != newmi.title_sort else ''))
self.log.info(" authors: %s %s" % (book.authors, ">>> %s" %
newmi.authors if book.authors != newmi.authors else ''))
self.log.info(" author_sort: %s %s" % (book.author_sort, ">>> %s" %
newmi.author_sort if book.author_sort != newmi.author_sort else ''))
self.log.info(" language: %s %s" % (book.language, ">>> %s" %
newmi.language if book.language != newmi.language else ''))
self.log.info(" publisher: %s %s" % (book.publisher, ">>> %s" %
newmi.publisher if book.publisher != newmi.publisher else ''))
self.log.info(" tags: %s %s" % (book.tags, ">>> %s" %
newmi.tags if book.tags != newmi.tags else ''))
else:
newmi = book
return newmi
class ITUNES_ASYNC(ITUNES):
'''
This subclass allows the user to interact directly with iTunes via a menu option
@ -2738,6 +2843,9 @@ class ITUNES_ASYNC(ITUNES):
icon = I('devices/itunes.png')
description = _('Communicate with iTunes.')
# Plugboard ID
DEVICE_PLUGBOARD_NAME = 'APPLE'
connected = False
def __init__(self,path):
@ -3012,15 +3120,9 @@ class BookList(list):
class Book(Metadata):
'''
A simple class describing a book in the iTunes Books Library.
- See ebooks.metadata.__init__ for all fields
See ebooks.metadata.book.base
'''
def __init__(self,title,author):
Metadata.__init__(self, title, authors=[author])
@dynamic_property
def title_sorter(self):
doc = '''String to sort the title. If absent, title is returned'''
def fget(self):
return re.sub('^\s*A\s+|^\s*The\s+|^\s*An\s+', '', self.title).rstrip()
return property(doc=doc, fget=fget)

View File

@ -411,6 +411,22 @@ class DevicePlugin(Plugin):
'''
raise NotImplementedError()
def set_plugboards(self, plugboards, pb_func):
'''
provide the driver the current set of plugboards and a function to
select a specific plugboard. This method is called immediately before
add_books and sync_booklists.
pb_func is a callable with the following signature:
def pb_func(device_name, format, plugboards)
You give it the current device name (either the class name or
DEVICE_PLUGBOARD_NAME), the format you are interested in (a 'real'
format or 'device_db'), and the plugboards (you were given those by
set_plugboards, the same place you got this method).
Return value: None or a single plugboard instance.
'''
pass
class BookList(list):
'''

View File

@ -83,7 +83,7 @@ class ISBNDBMetadata(Metadata):
summ = tostring(book.find('summary'))
if summ:
self.comments = 'SUMMARY:\n'+summ.string
self.comments = 'SUMMARY:\n'+summ
def build_isbn(base_url, opts):

View File

@ -21,6 +21,7 @@ class Worker(Thread):
def __init__(self, ids, db, loc, progress, done):
Thread.__init__(self)
self.ids = ids
self.processed = set([])
self.db = db
self.loc = loc
self.error = None
@ -71,6 +72,7 @@ class Worker(Thread):
co = self.db.conversion_options(x, 'PIPE')
if co is not None:
newdb.set_conversion_options(x, 'PIPE', co)
self.processed.add(x)
class CopyToLibraryAction(InterfaceAction):
@ -107,9 +109,13 @@ class CopyToLibraryAction(InterfaceAction):
for name, loc in locations:
self.menu.addAction(name, partial(self.copy_to_library,
loc))
self.menu.addAction(name + ' ' + _('(delete after copy)'),
partial(self.copy_to_library, loc, delete_after=True))
self.menu.addSeparator()
self.qaction.setVisible(bool(locations))
def copy_to_library(self, loc):
def copy_to_library(self, loc, delete_after=False):
rows = self.gui.library_view.selectionModel().selectedRows()
if not rows or len(rows) == 0:
return error_dialog(self.gui, _('Cannot copy'),
@ -140,7 +146,16 @@ class CopyToLibraryAction(InterfaceAction):
else:
self.gui.status_bar.show_message(_('Copied %d books to %s') %
(len(ids), loc), 2000)
if delete_after and self.worker.processed:
v = self.gui.library_view
ci = v.currentIndex()
row = None
if ci.isValid():
row = ci.row()
v.model().delete_books_by_id(self.worker.processed)
self.gui.iactions['Remove Books'].library_ids_deleted(
self.worker.processed, row)

View File

@ -149,6 +149,18 @@ class DeleteAction(InterfaceAction):
self.gui.library_view.model().current_changed(self.gui.library_view.currentIndex(),
self.gui.library_view.currentIndex())
def library_ids_deleted(self, ids_deleted, current_row=None):
view = self.gui.library_view
for v in (self.gui.memory_view, self.gui.card_a_view, self.gui.card_b_view):
if v is None:
continue
v.model().clear_ondevice(ids_deleted)
if current_row is not None:
ci = view.model().index(current_row, 0)
if ci.isValid():
view.set_current_row(current_row)
def delete_books(self, *args):
'''
Delete selected books from device or library.
@ -168,14 +180,7 @@ class DeleteAction(InterfaceAction):
if ci.isValid():
row = ci.row()
ids_deleted = view.model().delete_books(rows)
for v in (self.gui.memory_view, self.gui.card_a_view, self.gui.card_b_view):
if v is None:
continue
v.model().clear_ondevice(ids_deleted)
if row is not None:
ci = view.model().index(row, 0)
if ci.isValid():
view.set_current_row(row)
self.library_ids_deleted(ids_deleted, row)
else:
if not confirm('<p>'+_('The selected books will be '
'<b>permanently deleted</b> '

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>707</width>
<height>340</height>
<width>931</width>
<height>389</height>
</rect>
</property>
<property name="windowTitle">
@ -23,7 +23,7 @@ Use this dialog to define a 'plugboard' for a format (or all formats) and a devi
Often templates will contain simple references to composite columns, but this is not necessary. You can use any template in a source box that you can use elsewhere in calibre.
One possible use for a plugboard is to alter the title to contain series informaton. Another would be to change the author sort, something that mobi users might do to force it to use the ';' that the kindle requires. A third would be to specify the language.</string>
One possible use for a plugboard is to alter the title to contain series information. Another would be to change the author sort, something that mobi users might do to force it to use the ';' that the kindle requires. A third would be to specify the language.</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
@ -41,8 +41,7 @@ One possible use for a plugboard is to alter the title to contain series informa
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="device_label">
</widget>
<widget class="QLabel" name="device_label"/>
</item>
<item row="3" column="0" colspan="2">
<widget class="Line" name="line">

View File

@ -166,6 +166,8 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
def __init__(self, pathtoebook=None, debug_javascript=False):
MainWindow.__init__(self, None)
self.setupUi(self)
self.show_toc_on_open = False
self.current_book_has_toc = False
self.base_window_title = unicode(self.windowTitle())
self.iterator = None
self.current_page = None
@ -214,11 +216,12 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.action_metadata.setCheckable(True)
self.action_metadata.setShortcut(Qt.CTRL+Qt.Key_I)
self.action_table_of_contents.setCheckable(True)
self.toc.setMinimumWidth(80)
self.action_reference_mode.setCheckable(True)
self.connect(self.action_reference_mode, SIGNAL('triggered(bool)'),
lambda x: self.view.reference_mode(x))
self.connect(self.action_metadata, SIGNAL('triggered(bool)'), lambda x:self.metadata.setVisible(x))
self.connect(self.action_table_of_contents, SIGNAL('triggered(bool)'), lambda x:self.toc.setVisible(x))
self.connect(self.action_table_of_contents, SIGNAL('toggled(bool)'), lambda x:self.toc.setVisible(x))
self.connect(self.action_copy, SIGNAL('triggered(bool)'), self.copy)
self.connect(self.action_font_size_larger, SIGNAL('triggered(bool)'),
self.font_size_larger)
@ -259,7 +262,6 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
f = functools.partial(self.load_ebook, pathtoebook)
QTimer.singleShot(50, f)
self.view.setMinimumSize(100, 100)
self.splitter.setSizes([1, 300])
self.toc.setCursor(Qt.PointingHandCursor)
self.tool_bar.setContextMenuPolicy(Qt.PreventContextMenu)
self.tool_bar2.setContextMenuPolicy(Qt.PreventContextMenu)
@ -285,6 +287,12 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
def save_state(self):
state = str(self.saveState(self.STATE_VERSION))
dynamic['viewer_toolbar_state'] = state
dynamic.set('viewer_window_geometry', self.saveGeometry())
if self.current_book_has_toc:
dynamic.set('viewer_toc_isvisible', bool(self.toc.isVisible()))
if self.toc.isVisible():
dynamic.set('viewer_splitter_state',
bytearray(self.splitter.saveState()))
def restore_state(self):
state = dynamic.get('viewer_toolbar_state', None)
@ -609,10 +617,15 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
title = self.iterator.opf.title
if not title:
title = os.path.splitext(os.path.basename(pathtoebook))[0]
self.action_table_of_contents.setDisabled(not self.iterator.toc)
if self.iterator.toc:
self.toc_model = TOC(self.iterator.toc)
self.toc.setModel(self.toc_model)
if self.show_toc_on_open:
self.action_table_of_contents.setChecked(True)
else:
self.action_table_of_contents.setChecked(False)
self.action_table_of_contents.setDisabled(not self.iterator.toc)
self.current_book_has_toc = bool(self.iterator.toc)
self.current_title = title
self.setWindowTitle(self.base_window_title+' - '+title)
self.pos.setMaximum(sum(self.iterator.pages))
@ -656,22 +669,21 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
return self
def __exit__(self, *args):
self.write_settings()
if self.iterator is not None:
self.save_current_position()
self.iterator.__exit__(*args)
def write_settings(self):
dynamic.set('viewer_window_geometry', self.saveGeometry())
def read_settings(self):
c = config().parse()
wg = dynamic['viewer_window_geometry']
if wg is not None and c.remember_window_size:
self.restoreGeometry(wg)
self.splitter.setSizes([1, 300])
if c.remember_window_size:
wg = dynamic.get('viewer_window_geometry', None)
if wg is not None:
self.restoreGeometry(wg)
ss = dynamic.get('viewer_splitter_state', None)
if ss is not None:
self.splitter.restoreState(ss)
self.show_toc_on_open = dynamic.get('viewer_toc_isvisible', False)
def config(defaults=None):
desc = _('Options to control the ebook viewer')