mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 18:54:09 -04:00
0.7.42
This commit is contained in:
commit
984aed4cd2
@ -4,7 +4,7 @@
|
||||
# for important features/bug fixes.
|
||||
# Also, each release can have new and improved recipes.
|
||||
|
||||
- version: 0.7.41
|
||||
- version: 0.7.42
|
||||
date: 2011-01-21
|
||||
|
||||
new features:
|
||||
|
@ -2,7 +2,7 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
__appname__ = 'calibre'
|
||||
__version__ = '0.7.41'
|
||||
__version__ = '0.7.42'
|
||||
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
||||
|
||||
import re
|
||||
|
@ -1541,7 +1541,10 @@ class MobiWriter(object):
|
||||
exth.write(data)
|
||||
nrecs += 1
|
||||
if term == 'rights' :
|
||||
try:
|
||||
rights = unicode(oeb.metadata.rights[0]).encode('utf-8')
|
||||
except:
|
||||
rights = 'Unknown'
|
||||
exth.write(pack('>II', EXTH_CODES['rights'], len(rights) + 8))
|
||||
exth.write(rights)
|
||||
|
||||
|
@ -12,7 +12,8 @@ from lxml.html import soupparser
|
||||
|
||||
from PyQt4.Qt import QApplication, QFontInfo, QSize, QWidget, QPlainTextEdit, \
|
||||
QToolBar, QVBoxLayout, QAction, QIcon, Qt, QTabWidget, QUrl, \
|
||||
QSyntaxHighlighter, QColor, QChar, QColorDialog, QMenu, QInputDialog
|
||||
QSyntaxHighlighter, QColor, QChar, QColorDialog, QMenu, QInputDialog, \
|
||||
QHBoxLayout
|
||||
from PyQt4.QtWebKit import QWebView, QWebPage
|
||||
|
||||
from calibre.ebooks.chardet import xml_to_unicode
|
||||
@ -488,7 +489,7 @@ class Highlighter(QSyntaxHighlighter):
|
||||
|
||||
class Editor(QWidget): # {{{
|
||||
|
||||
def __init__(self, parent=None):
|
||||
def __init__(self, parent=None, one_line_toolbar=False):
|
||||
QWidget.__init__(self, parent)
|
||||
self.toolbar1 = QToolBar(self)
|
||||
self.toolbar2 = QToolBar(self)
|
||||
@ -508,9 +509,14 @@ class Editor(QWidget): # {{{
|
||||
self.wyswyg.layout = l = QVBoxLayout(self.wyswyg)
|
||||
self.setLayout(self._layout)
|
||||
l.setContentsMargins(0, 0, 0, 0)
|
||||
l.addWidget(self.toolbar1)
|
||||
l.addWidget(self.toolbar2)
|
||||
l.addWidget(self.toolbar3)
|
||||
if one_line_toolbar:
|
||||
tb = QHBoxLayout()
|
||||
l.addLayout(tb)
|
||||
else:
|
||||
tb = l
|
||||
tb.addWidget(self.toolbar1)
|
||||
tb.addWidget(self.toolbar2)
|
||||
tb.addWidget(self.toolbar3)
|
||||
l.addWidget(self.editor)
|
||||
self._layout.addWidget(self.tabs)
|
||||
self.tabs.addTab(self.wyswyg, _('Normal view'))
|
||||
|
@ -77,9 +77,9 @@ class TitleEdit(EnLineEdit):
|
||||
def commit(self, db, id_):
|
||||
title = self.current_val
|
||||
if self.COMMIT:
|
||||
getattr(db, 'set_', self.TITLE_ATTR)(id_, title, notify=False)
|
||||
getattr(db, 'set_'+ self.TITLE_ATTR)(id_, title, notify=False)
|
||||
else:
|
||||
getattr(db, 'set_', self.TITLE_ATTR)(id_, title, notify=False,
|
||||
getattr(db, 'set_'+ self.TITLE_ATTR)(id_, title, notify=False,
|
||||
commit=False)
|
||||
return True
|
||||
|
||||
|
@ -11,7 +11,7 @@ from functools import partial
|
||||
from PyQt4.Qt import Qt, QVBoxLayout, QHBoxLayout, QWidget, QPushButton, \
|
||||
QGridLayout, pyqtSignal, QDialogButtonBox, QScrollArea, QFont, \
|
||||
QTabWidget, QIcon, QToolButton, QSplitter, QGroupBox, QSpacerItem, \
|
||||
QSizePolicy
|
||||
QSizePolicy, QPalette, QFrame, QSize
|
||||
|
||||
from calibre.ebooks.metadata import authors_to_string, string_to_authors
|
||||
from calibre.gui2 import ResizableDialog, error_dialog, gprefs
|
||||
@ -22,9 +22,11 @@ from calibre.gui2.metadata.basic_widgets import TitleEdit, AuthorsEdit, \
|
||||
from calibre.gui2.custom_column_widgets import populate_metadata_page
|
||||
from calibre.utils.config import tweaks
|
||||
|
||||
class MetadataSingleDialog(ResizableDialog):
|
||||
class MetadataSingleDialogBase(ResizableDialog):
|
||||
|
||||
view_format = pyqtSignal(object)
|
||||
cc_two_column = tweaks['metadata_single_use_2_cols_for_custom_fields']
|
||||
one_line_comments_toolbar = False
|
||||
|
||||
def __init__(self, db, parent=None):
|
||||
self.db = db
|
||||
@ -65,9 +67,7 @@ class MetadataSingleDialog(ResizableDialog):
|
||||
|
||||
self.create_basic_metadata_widgets()
|
||||
|
||||
if len(self.db.custom_column_label_map) == 0:
|
||||
self.central_widget.tabBar().setVisible(False)
|
||||
else:
|
||||
if len(self.db.custom_column_label_map):
|
||||
self.create_custom_metadata_widgets()
|
||||
|
||||
|
||||
@ -101,7 +101,7 @@ class MetadataSingleDialog(ResizableDialog):
|
||||
'Using this button to create author sort will change author sort from'
|
||||
' red to green.'))
|
||||
self.author_sort = AuthorSortEdit(self, self.authors,
|
||||
self.deduce_author_sort_button, db)
|
||||
self.deduce_author_sort_button, self.db)
|
||||
self.basic_metadata_widgets.extend([self.authors, self.author_sort])
|
||||
|
||||
self.swap_title_author_button = QToolButton(self)
|
||||
@ -127,7 +127,7 @@ class MetadataSingleDialog(ResizableDialog):
|
||||
self.cover = Cover(self)
|
||||
self.basic_metadata_widgets.append(self.cover)
|
||||
|
||||
self.comments = CommentsEdit(self)
|
||||
self.comments = CommentsEdit(self, self.one_line_comments_toolbar)
|
||||
self.basic_metadata_widgets.append(self.comments)
|
||||
|
||||
self.rating = RatingEdit(self)
|
||||
@ -166,19 +166,213 @@ class MetadataSingleDialog(ResizableDialog):
|
||||
w.setLayout(layout)
|
||||
self.custom_metadata_widgets, self.__cc_spacers = \
|
||||
populate_metadata_page(layout, self.db, None, parent=w, bulk=False,
|
||||
two_column=tweaks['metadata_single_use_2_cols_for_custom_fields'])
|
||||
two_column=self.cc_two_column)
|
||||
self.__custom_col_layouts = [layout]
|
||||
ans = self.custom_metadata_widgets
|
||||
for i in range(len(ans)-1):
|
||||
if len(ans[i+1].widgets) == 2:
|
||||
w.setTabOrder(ans[i].widgets[-1], ans[i+1].widgets[1])
|
||||
else:
|
||||
w.setTabOrder(ans[i].widgets[-1], ans[i+1].widgets[0])
|
||||
for c in range(2, len(ans[i].widgets), 2):
|
||||
w.setTabOrder(ans[i].widgets[c-1], ans[i].widgets[c+1])
|
||||
# }}}
|
||||
|
||||
def do_layout(self): # {{{
|
||||
def set_custom_metadata_tab_order(self, before=None, after=None): # {{{
|
||||
sto = QWidget.setTabOrder
|
||||
if getattr(self, 'custom_metadata_widgets', []):
|
||||
ans = self.custom_metadata_widgets
|
||||
for i in range(len(ans)-1):
|
||||
if before is not None and i == 0:
|
||||
pass# Do something
|
||||
if len(ans[i+1].widgets) == 2:
|
||||
sto(ans[i].widgets[-1], ans[i+1].widgets[1])
|
||||
else:
|
||||
sto(ans[i].widgets[-1], ans[i+1].widgets[0])
|
||||
for c in range(2, len(ans[i].widgets), 2):
|
||||
sto(ans[i].widgets[c-1], ans[i].widgets[c+1])
|
||||
if after is not None:
|
||||
pass # Do something
|
||||
# }}}
|
||||
|
||||
def do_layout(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def __call__(self, id_):
|
||||
self.book_id = id_
|
||||
for widget in self.basic_metadata_widgets:
|
||||
widget.initialize(self.db, id_)
|
||||
for widget in self.custom_metadata_widgets:
|
||||
widget.initialize(id_)
|
||||
# Commented out as it doesn't play nice with Next, Prev buttons
|
||||
#self.fetch_metadata_button.setFocus(Qt.OtherFocusReason)
|
||||
|
||||
|
||||
# Miscellaneous interaction methods {{{
|
||||
def update_window_title(self, *args):
|
||||
title = self.title.current_val
|
||||
if len(title) > 50:
|
||||
title = title[:50] + u'\u2026'
|
||||
self.setWindowTitle(_('Edit Metadata') + ' - ' +
|
||||
title)
|
||||
|
||||
def swap_title_author(self, *args):
|
||||
title = self.title.current_val
|
||||
self.title.current_val = authors_to_string(self.authors.current_val)
|
||||
self.authors.current_val = string_to_authors(title)
|
||||
self.title_sort.auto_generate()
|
||||
self.author_sort.auto_generate()
|
||||
|
||||
def remove_unused_series(self, *args):
|
||||
self.db.remove_unused_series()
|
||||
idx = self.series.current_val
|
||||
self.series.clear()
|
||||
self.series.initialize(self.db, self.book_id)
|
||||
if idx:
|
||||
for i in range(self.series.count()):
|
||||
if unicode(self.series.itemText(i)) == idx:
|
||||
self.series.setCurrentIndex(i)
|
||||
break
|
||||
|
||||
def tags_editor(self, *args):
|
||||
self.tags.edit(self.db, self.book_id)
|
||||
|
||||
def metadata_from_format(self, *args):
|
||||
mi, ext = self.formats_manager.get_selected_format_metadata(self.db,
|
||||
self.book_id)
|
||||
if mi is not None:
|
||||
self.update_from_mi(mi)
|
||||
|
||||
def cover_from_format(self, *args):
|
||||
mi, ext = self.formats_manager.get_selected_format_metadata(self.db,
|
||||
self.book_id)
|
||||
if mi is None:
|
||||
return
|
||||
cdata = None
|
||||
if mi.cover and os.access(mi.cover, os.R_OK):
|
||||
cdata = open(mi.cover).read()
|
||||
elif mi.cover_data[1] is not None:
|
||||
cdata = mi.cover_data[1]
|
||||
if cdata is None:
|
||||
error_dialog(self, _('Could not read cover'),
|
||||
_('Could not read cover from %s format')%ext).exec_()
|
||||
return
|
||||
orig = self.cover.current_val
|
||||
self.cover.current_val = cdata
|
||||
if self.cover.current_val is None:
|
||||
self.cover.current_val = orig
|
||||
return error_dialog(self, _('Could not read cover'),
|
||||
_('The cover in the %s format is invalid')%ext,
|
||||
show=True)
|
||||
return
|
||||
|
||||
def update_from_mi(self, mi):
|
||||
if not mi.is_null('title'):
|
||||
self.title.current_val = mi.title
|
||||
if not mi.is_null('authors'):
|
||||
self.authors.current_val = mi.authors
|
||||
if not mi.is_null('author_sort'):
|
||||
self.author_sort.current_val = mi.author_sort
|
||||
if not mi.is_null('rating'):
|
||||
try:
|
||||
self.rating.current_val = mi.rating
|
||||
except:
|
||||
pass
|
||||
if not mi.is_null('publisher'):
|
||||
self.publisher.current_val = mi.publisher
|
||||
if not mi.is_null('tags'):
|
||||
self.tags.current_val = mi.tags
|
||||
if not mi.is_null('isbn'):
|
||||
self.isbn.current_val = mi.isbn
|
||||
if not mi.is_null('pubdate'):
|
||||
self.pubdate.current_val = mi.pubdate
|
||||
if not mi.is_null('series') and mi.series.strip():
|
||||
self.series.current_val = mi.series
|
||||
if mi.series_index is not None:
|
||||
self.series_index.current_val = float(mi.series_index)
|
||||
if mi.comments and mi.comments.strip():
|
||||
self.comments.current_val = mi.comments
|
||||
|
||||
def fetch_metadata(self, *args):
|
||||
pass # TODO: fetch metadata
|
||||
# }}}
|
||||
|
||||
def apply_changes(self):
|
||||
self.changed.add(self.book_id)
|
||||
for widget in self.basic_metadata_widgets:
|
||||
try:
|
||||
if not widget.commit(self.db, self.book_id):
|
||||
return False
|
||||
except IOError, err:
|
||||
if err.errno == 13: # Permission denied
|
||||
import traceback
|
||||
fname = err.filename if err.filename else 'file'
|
||||
error_dialog(self, _('Permission denied'),
|
||||
_('Could not open %s. Is it being used by another'
|
||||
' program?')%fname, det_msg=traceback.format_exc(),
|
||||
show=True)
|
||||
return False
|
||||
raise
|
||||
for widget in getattr(self, 'custom_metadata_widgets', []):
|
||||
widget.commit(self.book_id)
|
||||
|
||||
self.db.commit()
|
||||
return True
|
||||
|
||||
def accept(self):
|
||||
self.save_state()
|
||||
if not self.apply_changes():
|
||||
return
|
||||
ResizableDialog.accept(self)
|
||||
|
||||
def reject(self):
|
||||
self.save_state()
|
||||
ResizableDialog.reject(self)
|
||||
|
||||
def save_state(self):
|
||||
gprefs['metasingle_window_geometry3'] = bytearray(self.saveGeometry())
|
||||
|
||||
# Dialog use methods {{{
|
||||
def start(self, row_list, current_row, view_slot=None):
|
||||
self.row_list = row_list
|
||||
self.current_row = current_row
|
||||
if view_slot is not None:
|
||||
self.view_format.connect(view_slot)
|
||||
self.do_one()
|
||||
ret = self.exec_()
|
||||
self.break_cycles()
|
||||
return ret
|
||||
|
||||
def do_one(self, delta=0):
|
||||
self.current_row += delta
|
||||
prev = next_ = None
|
||||
if self.current_row > 0:
|
||||
prev = self.db.title(self.row_list[self.current_row-1])
|
||||
if self.current_row < len(self.row_list) - 1:
|
||||
next_ = self.db.title(self.row_list[self.current_row+1])
|
||||
|
||||
if next_ is not None:
|
||||
tip = _('Save changes and edit the metadata of %s')%next_
|
||||
self.next_button.setToolTip(tip)
|
||||
self.next_button.setVisible(next_ is not None)
|
||||
if prev is not None:
|
||||
tip = _('Save changes and edit the metadata of %s')%prev
|
||||
self.prev_button.setToolTip(tip)
|
||||
self.prev_button.setVisible(prev is not None)
|
||||
self(self.db.id(self.row_list[self.current_row]))
|
||||
|
||||
def break_cycles(self):
|
||||
# Break any reference cycles that could prevent python
|
||||
# from garbage collecting this dialog
|
||||
def disconnect(signal):
|
||||
try:
|
||||
signal.disconnect()
|
||||
except:
|
||||
pass # Fails if view format was never connected
|
||||
disconnect(self.view_format)
|
||||
for b in ('next_button', 'prev_button'):
|
||||
x = getattr(self, b, None)
|
||||
if x is not None:
|
||||
disconnect(x.clicked)
|
||||
# }}}
|
||||
|
||||
class MetadataSingleDialog(MetadataSingleDialogBase): # {{{
|
||||
|
||||
def do_layout(self):
|
||||
if len(self.db.custom_column_label_map) == 0:
|
||||
self.central_widget.tabBar().setVisible(False)
|
||||
self.central_widget.clear()
|
||||
self.tabs = []
|
||||
self.labels = []
|
||||
@ -283,181 +477,143 @@ class MetadataSingleDialog(ResizableDialog):
|
||||
l.addWidget(self.comments)
|
||||
self.splitter.addWidget(gb)
|
||||
|
||||
self.set_custom_metadata_tab_order()
|
||||
|
||||
# }}}
|
||||
|
||||
def __call__(self, id_):
|
||||
self.book_id = id_
|
||||
for widget in self.basic_metadata_widgets:
|
||||
widget.initialize(self.db, id_)
|
||||
for widget in self.custom_metadata_widgets:
|
||||
widget.initialize(id_)
|
||||
# Commented out as it doesn't play nice with Next, Prev buttons
|
||||
#self.fetch_metadata_button.setFocus(Qt.OtherFocusReason)
|
||||
class MetadataSingleDialogAlt(MetadataSingleDialogBase): # {{{
|
||||
|
||||
cc_two_column = False
|
||||
one_line_comments_toolbar = True
|
||||
|
||||
def update_window_title(self, *args):
|
||||
title = self.title.current_val
|
||||
if len(title) > 50:
|
||||
title = title[:50] + u'\u2026'
|
||||
self.setWindowTitle(_('Edit Metadata') + ' - ' +
|
||||
title)
|
||||
def do_layout(self):
|
||||
self.central_widget.clear()
|
||||
self.tabs = []
|
||||
self.labels = []
|
||||
sto = QWidget.setTabOrder
|
||||
|
||||
def swap_title_author(self, *args):
|
||||
title = self.title.current_val
|
||||
self.title.current_val = authors_to_string(self.authors.current_val)
|
||||
self.authors.current_val = string_to_authors(title)
|
||||
self.title_sort.auto_generate()
|
||||
self.author_sort.auto_generate()
|
||||
self.tabs.append(QWidget(self))
|
||||
self.central_widget.addTab(self.tabs[0], _("&Metadata"))
|
||||
self.tabs[0].l = QGridLayout()
|
||||
self.tabs[0].setLayout(self.tabs[0].l)
|
||||
|
||||
def remove_unused_series(self, *args):
|
||||
self.db.remove_unused_series()
|
||||
idx = self.series.current_val
|
||||
self.series.clear()
|
||||
self.series.initialize(self.db, self.book_id)
|
||||
if idx:
|
||||
for i in range(self.series.count()):
|
||||
if unicode(self.series.itemText(i)) == idx:
|
||||
self.series.setCurrentIndex(i)
|
||||
break
|
||||
self.tabs.append(QWidget(self))
|
||||
self.central_widget.addTab(self.tabs[1], _("&Cover and formats"))
|
||||
self.tabs[1].l = QGridLayout()
|
||||
self.tabs[1].setLayout(self.tabs[1].l)
|
||||
|
||||
def tags_editor(self, *args):
|
||||
self.tags.edit(self.db, self.book_id)
|
||||
# Tab 0
|
||||
tab0 = self.tabs[0]
|
||||
|
||||
def metadata_from_format(self, *args):
|
||||
mi, ext = self.formats_manager.get_selected_format_metadata(self.db,
|
||||
self.book_id)
|
||||
if mi is not None:
|
||||
self.update_from_mi(mi)
|
||||
tl = QGridLayout()
|
||||
gb = QGroupBox(_('&Basic metadata'), self.tabs[0])
|
||||
self.tabs[0].l.addWidget(gb, 0, 0, 1, 1)
|
||||
gb.setLayout(tl)
|
||||
|
||||
def cover_from_format(self, *args):
|
||||
mi, ext = self.formats_manager.get_selected_format_metadata(self.db,
|
||||
self.book_id)
|
||||
if mi is None:
|
||||
return
|
||||
cdata = None
|
||||
if mi.cover and os.access(mi.cover, os.R_OK):
|
||||
cdata = open(mi.cover).read()
|
||||
elif mi.cover_data[1] is not None:
|
||||
cdata = mi.cover_data[1]
|
||||
if cdata is None:
|
||||
error_dialog(self, _('Could not read cover'),
|
||||
_('Could not read cover from %s format')%ext).exec_()
|
||||
return
|
||||
orig = self.cover.current_val
|
||||
self.cover.current_val = cdata
|
||||
if self.cover.current_val is None:
|
||||
self.cover.current_val = orig
|
||||
return error_dialog(self, _('Could not read cover'),
|
||||
_('The cover in the %s format is invalid')%ext,
|
||||
show=True)
|
||||
return
|
||||
sto(self.button_box, self.title)
|
||||
|
||||
def update_from_mi(self, mi):
|
||||
if not mi.is_null('title'):
|
||||
self.title.current_val = mi.title
|
||||
if not mi.is_null('authors'):
|
||||
self.authors.current_val = mi.authors
|
||||
if not mi.is_null('author_sort'):
|
||||
self.author_sort.current_val = mi.author_sort
|
||||
if not mi.is_null('rating'):
|
||||
try:
|
||||
self.rating.current_val = mi.rating
|
||||
except:
|
||||
pass
|
||||
if not mi.is_null('publisher'):
|
||||
self.publisher.current_val = mi.publisher
|
||||
if not mi.is_null('tags'):
|
||||
self.tags.current_val = mi.tags
|
||||
if not mi.is_null('isbn'):
|
||||
self.isbn.current_val = mi.isbn
|
||||
if not mi.is_null('pubdate'):
|
||||
self.pubdate.current_val = mi.pubdate
|
||||
if not mi.is_null('series') and mi.series.strip():
|
||||
self.series.current_val = mi.series
|
||||
if mi.series_index is not None:
|
||||
self.series_index.current_val = float(mi.series_index)
|
||||
if mi.comments and mi.comments.strip():
|
||||
self.comments.current_val = mi.comments
|
||||
def create_row(row, widget, tab_to, button=None, icon=None, span=1):
|
||||
ql = BuddyLabel(widget)
|
||||
tl.addWidget(ql, row, 1, 1, 1)
|
||||
tl.addWidget(widget, row, 2, 1, 1)
|
||||
if button is not None:
|
||||
tl.addWidget(button, row, 3, span, 1)
|
||||
if icon is not None:
|
||||
button.setIcon(QIcon(I(icon)))
|
||||
if tab_to is not None:
|
||||
if button is not None:
|
||||
sto(widget, button)
|
||||
sto(button, tab_to)
|
||||
else:
|
||||
sto(widget, tab_to)
|
||||
|
||||
def fetch_metadata(self, *args):
|
||||
pass # TODO: fetch metadata
|
||||
tl.addWidget(self.swap_title_author_button, 0, 0, 2, 1)
|
||||
|
||||
def apply_changes(self):
|
||||
self.changed.add(self.book_id)
|
||||
for widget in self.basic_metadata_widgets:
|
||||
try:
|
||||
if not widget.commit(self.db, self.book_id):
|
||||
return False
|
||||
except IOError, err:
|
||||
if err.errno == 13: # Permission denied
|
||||
import traceback
|
||||
fname = err.filename if err.filename else 'file'
|
||||
error_dialog(self, _('Permission denied'),
|
||||
_('Could not open %s. Is it being used by another'
|
||||
' program?')%fname, det_msg=traceback.format_exc(),
|
||||
show=True)
|
||||
return False
|
||||
raise
|
||||
for widget in getattr(self, 'custom_metadata_widgets', []):
|
||||
widget.commit(self.book_id)
|
||||
create_row(0, self.title, self.title_sort,
|
||||
button=self.deduce_title_sort_button, span=2,
|
||||
icon='auto_author_sort.png')
|
||||
create_row(1, self.title_sort, self.authors)
|
||||
create_row(2, self.authors, self.author_sort,
|
||||
button=self.deduce_author_sort_button,
|
||||
span=2, icon='auto_author_sort.png')
|
||||
create_row(3, self.author_sort, self.series)
|
||||
create_row(4, self.series, self.series_index,
|
||||
button=self.remove_unused_series_button, icon='trash.png')
|
||||
create_row(5, self.series_index, self.tags)
|
||||
create_row(6, self.tags, self.rating, button=self.tags_editor_button)
|
||||
create_row(7, self.rating, self.pubdate)
|
||||
create_row(8, self.pubdate, self.publisher,
|
||||
button=self.pubdate.clear_button, icon='trash.png')
|
||||
create_row(9, self.publisher, self.timestamp)
|
||||
create_row(10, self.timestamp, self.isbn,
|
||||
button=self.timestamp.clear_button, icon='trash.png')
|
||||
create_row(11, self.isbn, self.comments)
|
||||
tl.addItem(QSpacerItem(1, 1, QSizePolicy.Fixed, QSizePolicy.Expanding),
|
||||
12, 1, 1 ,1)
|
||||
|
||||
self.db.commit()
|
||||
return True
|
||||
w = getattr(self, 'custom_metadata_widgets_parent', None)
|
||||
if w is not None:
|
||||
gb = QGroupBox(_('C&ustom metadata'), tab0)
|
||||
gbl = QVBoxLayout()
|
||||
gb.setLayout(gbl)
|
||||
sr = QScrollArea(tab0)
|
||||
sr.setWidgetResizable(True)
|
||||
sr.setBackgroundRole(QPalette.Base)
|
||||
sr.setFrameStyle(QFrame.NoFrame)
|
||||
sr.setWidget(w)
|
||||
gbl.addWidget(sr)
|
||||
self.tabs[0].l.addWidget(gb, 0, 1, 1, 1)
|
||||
sto(self.isbn, gb)
|
||||
|
||||
def accept(self):
|
||||
self.save_state()
|
||||
if not self.apply_changes():
|
||||
return
|
||||
ResizableDialog.accept(self)
|
||||
w = QGroupBox(_('&Comments'), tab0)
|
||||
sp = QSizePolicy()
|
||||
sp.setVerticalStretch(10)
|
||||
sp.setHorizontalPolicy(QSizePolicy.Expanding)
|
||||
sp.setVerticalPolicy(QSizePolicy.Expanding)
|
||||
w.setSizePolicy(sp)
|
||||
l = QHBoxLayout()
|
||||
w.setLayout(l)
|
||||
l.addWidget(self.comments)
|
||||
tab0.l.addWidget(w, 1, 0, 1, 2)
|
||||
|
||||
def reject(self):
|
||||
self.save_state()
|
||||
ResizableDialog.reject(self)
|
||||
# Tab 1
|
||||
tab1 = self.tabs[1]
|
||||
|
||||
def save_state(self):
|
||||
gprefs['metasingle_window_geometry3'] = bytearray(self.saveGeometry())
|
||||
wsp = QWidget(tab1)
|
||||
wgl = QVBoxLayout()
|
||||
wsp.setLayout(wgl)
|
||||
|
||||
def start(self, row_list, current_row, view_slot=None):
|
||||
self.row_list = row_list
|
||||
self.current_row = current_row
|
||||
if view_slot is not None:
|
||||
self.view_format.connect(view_slot)
|
||||
self.do_one()
|
||||
ret = self.exec_()
|
||||
self.break_cycles()
|
||||
return ret
|
||||
# right-hand side of splitter
|
||||
gb = QGroupBox(_('Change cover'), tab1)
|
||||
l = QGridLayout()
|
||||
gb.setLayout(l)
|
||||
sto(self.swap_title_author_button, self.cover.buttons[0])
|
||||
for i, b in enumerate(self.cover.buttons[:3]):
|
||||
l.addWidget(b, 0, i, 1, 1)
|
||||
sto(b, self.cover.buttons[i+1])
|
||||
hl = QHBoxLayout()
|
||||
for b in self.cover.buttons[3:]:
|
||||
hl.addWidget(b)
|
||||
sto(self.cover.buttons[-2], self.cover.buttons[-1])
|
||||
l.addLayout(hl, 1, 0, 1, 3)
|
||||
wgl.addWidget(gb)
|
||||
wgl.addItem(QSpacerItem(10, 10, QSizePolicy.Expanding,
|
||||
QSizePolicy.Expanding))
|
||||
wgl.addWidget(self.fetch_metadata_button)
|
||||
wgl.addItem(QSpacerItem(10, 10, QSizePolicy.Expanding,
|
||||
QSizePolicy.Expanding))
|
||||
wgl.addWidget(self.formats_manager)
|
||||
|
||||
def do_one(self, delta=0):
|
||||
self.current_row += delta
|
||||
prev = next_ = None
|
||||
if self.current_row > 0:
|
||||
prev = self.db.title(self.row_list[self.current_row-1])
|
||||
if self.current_row < len(self.row_list) - 1:
|
||||
next_ = self.db.title(self.row_list[self.current_row+1])
|
||||
self.splitter = QSplitter(Qt.Horizontal, tab1)
|
||||
tab1.l.addWidget(self.splitter)
|
||||
self.splitter.addWidget(self.cover)
|
||||
self.splitter.addWidget(wsp)
|
||||
|
||||
if next_ is not None:
|
||||
tip = _('Save changes and edit the metadata of %s')%next_
|
||||
self.next_button.setToolTip(tip)
|
||||
self.next_button.setVisible(next_ is not None)
|
||||
if prev is not None:
|
||||
tip = _('Save changes and edit the metadata of %s')%prev
|
||||
self.prev_button.setToolTip(tip)
|
||||
self.prev_button.setVisible(prev is not None)
|
||||
self(self.db.id(self.row_list[self.current_row]))
|
||||
self.formats_manager.formats.setMaximumWidth(10000)
|
||||
self.formats_manager.formats.setIconSize(QSize(64, 64))
|
||||
|
||||
# }}}
|
||||
|
||||
def break_cycles(self):
|
||||
# Break any reference cycles that could prevent python
|
||||
# from garbage collecting this dialog
|
||||
def disconnect(signal):
|
||||
try:
|
||||
signal.disconnect()
|
||||
except:
|
||||
pass # Fails if view format was never connected
|
||||
disconnect(self.view_format)
|
||||
for b in ('next_button', 'prev_button'):
|
||||
x = getattr(self, b, None)
|
||||
if x is not None:
|
||||
disconnect(x.clicked)
|
||||
|
||||
def edit_metadata(db, row_list, current_row, parent=None, view_slot=None):
|
||||
d = MetadataSingleDialog(db, parent)
|
||||
@ -467,8 +623,8 @@ def edit_metadata(db, row_list, current_row, parent=None, view_slot=None):
|
||||
if __name__ == '__main__':
|
||||
from PyQt4.Qt import QApplication
|
||||
app = QApplication([])
|
||||
from calibre.library import db
|
||||
db = db()
|
||||
from calibre.library import db as db_
|
||||
db = db_()
|
||||
row_list = list(range(len(db.data)))
|
||||
edit_metadata(db, row_list, 0)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user