mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge from main branch
This commit is contained in:
commit
54b3098eb2
32
recipes/dvhn.recipe
Normal file
32
recipes/dvhn.recipe
Normal file
@ -0,0 +1,32 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class AdvancedUserRecipe1302341394(BasicNewsRecipe):
|
||||
title = u'DvhN'
|
||||
oldest_article = 1
|
||||
max_articles_per_feed = 200
|
||||
|
||||
__author__ = 'Reijndert'
|
||||
no_stylesheets = True
|
||||
cover_url = 'http://www.dvhn.nl/template/Dagblad_v2.0/gfx/logo_DvhN.gif'
|
||||
language = 'nl'
|
||||
country = 'NL'
|
||||
version = 1
|
||||
publisher = u'Dagblad van het Noorden'
|
||||
category = u'Nieuws'
|
||||
description = u'Nieuws uit Noord Nederland'
|
||||
|
||||
|
||||
keep_only_tags = [dict(name='div', attrs={'id':'fullPicture'})
|
||||
,dict(name='div', attrs={'id':'articleText'})
|
||||
]
|
||||
|
||||
remove_tags = [
|
||||
dict(name=['object','link','iframe','base'])
|
||||
,dict(name='span',attrs={'class':'copyright'})
|
||||
]
|
||||
|
||||
feeds = [(u'Drenthe', u'http://www.dvhn.nl/nieuws/drenthe/index.jsp?service=rss'), (u'Groningen', u'http://www.dvhn.nl/nieuws/groningen/index.jsp?service=rss'), (u'Nederland', u'http://www.dvhn.nl/nieuws/nederland/index.jsp?service=rss'), (u'Wereld', u'http://www.dvhn.nl/nieuws/wereld/index.jsp?service=rss'), (u'Economie', u'http://www.dvhn.nl/nieuws/economie/index.jsp?service=rss'), (u'Sport', u'http://www.dvhn.nl/nieuws/sport/index.jsp?service=rss'), (u'Cultuur', u'http://www.dvhn.nl/nieuws/kunst/index.jsp?service=rss'), (u'24 Uur', u'http://www.dvhn.nl/nieuws/24uurdvhn/index.jsp?service=rss&selectiontype=last24hours')]
|
||||
|
||||
extra_css = '''
|
||||
body {font-family: verdana, arial, helvetica, geneva, sans-serif;}
|
||||
'''
|
@ -88,13 +88,6 @@ categories_collapsed_rating_template = r'{first.avg_rating:4.2f:ifempty(0)} - {l
|
||||
categories_collapsed_popularity_template = r'{first.count:d} - {last.count:d}'
|
||||
|
||||
|
||||
#: Set boolean custom columns to be tristate
|
||||
# Set whether boolean custom columns are two- or three-valued.
|
||||
# Two-values for true booleans
|
||||
# three-values for yes/no/unknown
|
||||
# Set to 'yes' for three-values, 'no' for two-values
|
||||
bool_custom_columns_are_tristate = 'yes'
|
||||
|
||||
#: Specify columns to sort the booklist by on startup
|
||||
# Provide a set of columns to be sorted on when calibre starts
|
||||
# The argument is None if saved sort history is to be used
|
||||
|
BIN
resources/images/connect_share_on.png
Normal file
BIN
resources/images/connect_share_on.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
@ -26,9 +26,9 @@ class EDGE(USBMS):
|
||||
PRODUCT_ID = [0x0c02]
|
||||
BCD = [0x0223]
|
||||
|
||||
VENDOR_NAME = 'ANDROID'
|
||||
WINDOWS_MAIN_MEM = '__FILE-STOR_GADG'
|
||||
WINDOWS_CARD_A_MEM = '__FILE-STOR_GADG'
|
||||
VENDOR_NAME = ['ANDROID', 'LINUX']
|
||||
WINDOWS_MAIN_MEM = ['__FILE-STOR_GADG', 'FILE-CD_GADGET']
|
||||
WINDOWS_CARD_A_MEM = ['__FILE-STOR_GADG', 'FILE-CD_GADGET']
|
||||
|
||||
MAIN_MEMORY_VOLUME_LABEL = 'Edge Main Memory'
|
||||
STORAGE_CARD_VOLUME_LABEL = 'Edge Storage Card'
|
||||
|
@ -279,7 +279,7 @@ class Worker(Thread): # Get details {{{
|
||||
|
||||
class Amazon(Source):
|
||||
|
||||
name = 'Amazon Store'
|
||||
name = 'Amazon Web'
|
||||
description = _('Downloads metadata from Amazon')
|
||||
|
||||
capabilities = frozenset(['identify', 'cover'])
|
||||
|
@ -13,7 +13,7 @@ from functools import partial
|
||||
|
||||
from calibre.ebooks import ConversionError, DRMError
|
||||
from calibre.ptempfile import PersistentTemporaryFile
|
||||
from calibre import isosx, iswindows, islinux, isfreebsd
|
||||
from calibre.constants import isosx, iswindows, islinux, isfreebsd
|
||||
from calibre import CurrentDir
|
||||
|
||||
PDFTOHTML = 'pdftohtml'
|
||||
@ -43,6 +43,8 @@ def pdftohtml(output_dir, pdf_path, no_images):
|
||||
# This is neccessary as pdftohtml doesn't always (linux) respect absolute paths
|
||||
pdf_path = os.path.abspath(pdf_path)
|
||||
cmd = [PDFTOHTML, '-enc', 'UTF-8', '-noframes', '-p', '-nomerge', '-nodrm', '-q', pdf_path, os.path.basename(index)]
|
||||
if isfreebsd:
|
||||
cmd.remove('-nodrm')
|
||||
if no_images:
|
||||
cmd.append('-i')
|
||||
|
||||
|
@ -13,7 +13,7 @@ from PyQt4.Qt import QVariant, QFileInfo, QObject, SIGNAL, QBuffer, Qt, \
|
||||
|
||||
ORG_NAME = 'KovidsBrain'
|
||||
APP_UID = 'libprs500'
|
||||
from calibre.constants import islinux, iswindows, isfreebsd, isfrozen
|
||||
from calibre.constants import islinux, iswindows, isfreebsd, isfrozen, isosx
|
||||
from calibre.utils.config import Config, ConfigProxy, dynamic, JSONConfig
|
||||
from calibre.utils.localization import set_qt_translator
|
||||
from calibre.ebooks.metadata.meta import get_metadata, metadata_from_formats
|
||||
@ -23,25 +23,45 @@ from calibre.utils.date import UNDEFINED_DATE
|
||||
# Setup gprefs {{{
|
||||
gprefs = JSONConfig('gui')
|
||||
|
||||
gprefs.defaults['action-layout-menubar'] = ()
|
||||
|
||||
gprefs.defaults['action-layout-menubar-device'] = ()
|
||||
|
||||
gprefs.defaults['action-layout-toolbar'] = (
|
||||
if isosx:
|
||||
gprefs.defaults['action-layout-menubar'] = (
|
||||
'Add Books', 'Edit Metadata', 'Convert Books',
|
||||
'Choose Library', 'Save To Disk', 'Preferences',
|
||||
'Help',
|
||||
)
|
||||
gprefs.defaults['action-layout-menubar-device'] = (
|
||||
'Add Books', 'Edit Metadata', 'Convert Books',
|
||||
'Location Manager', 'Send To Device',
|
||||
'Save To Disk', 'Preferences', 'Help',
|
||||
)
|
||||
gprefs.defaults['action-layout-toolbar'] = (
|
||||
'Add Books', 'Edit Metadata', None, 'Convert Books', 'View', None,
|
||||
'Choose Library', 'Donate', None, 'Fetch News', 'Save To Disk',
|
||||
'Connect Share', None, 'Remove Books',
|
||||
)
|
||||
gprefs.defaults['action-layout-toolbar-device'] = (
|
||||
'Add Books', 'Edit Metadata', None, 'Convert Books', 'View',
|
||||
'Send To Device', None, None, 'Location Manager', None, None,
|
||||
'Fetch News', 'Save To Disk', 'Connect Share', None,
|
||||
'Remove Books',
|
||||
)
|
||||
else:
|
||||
gprefs.defaults['action-layout-menubar'] = ()
|
||||
gprefs.defaults['action-layout-menubar-device'] = ()
|
||||
gprefs.defaults['action-layout-toolbar'] = (
|
||||
'Add Books', 'Edit Metadata', None, 'Convert Books', 'View', None,
|
||||
'Choose Library', 'Donate', None, 'Fetch News', 'Save To Disk',
|
||||
'Connect Share', None, 'Remove Books', None, 'Help', 'Preferences',
|
||||
)
|
||||
|
||||
gprefs.defaults['action-layout-toolbar-child'] = ()
|
||||
|
||||
gprefs.defaults['action-layout-toolbar-device'] = (
|
||||
gprefs.defaults['action-layout-toolbar-device'] = (
|
||||
'Add Books', 'Edit Metadata', None, 'Convert Books', 'View',
|
||||
'Send To Device', None, None, 'Location Manager', None, None,
|
||||
'Fetch News', 'Save To Disk', 'Connect Share', None,
|
||||
'Remove Books', None, 'Help', 'Preferences',
|
||||
)
|
||||
|
||||
gprefs.defaults['action-layout-toolbar-child'] = ()
|
||||
|
||||
gprefs.defaults['action-layout-context-menu'] = (
|
||||
'Edit Metadata', 'Send To Device', 'Save To Disk',
|
||||
'Connect Share', 'Copy To Library', None,
|
||||
@ -61,6 +81,7 @@ gprefs.defaults['toolbar_text'] = 'auto'
|
||||
gprefs.defaults['font'] = None
|
||||
gprefs.defaults['tags_browser_partition_method'] = 'first letter'
|
||||
gprefs.defaults['tags_browser_collapse_at'] = 100
|
||||
gprefs.defaults['edit_metadata_single_layout'] = 'default'
|
||||
|
||||
# }}}
|
||||
|
||||
|
@ -165,6 +165,10 @@ class ConnectShareAction(InterfaceAction):
|
||||
|
||||
def content_server_state_changed(self, running):
|
||||
self.share_conn_menu.server_state_changed(running)
|
||||
if running:
|
||||
self.qaction.setIcon(QIcon(I('connect_share_on.png')))
|
||||
else:
|
||||
self.qaction.setIcon(QIcon(I('connect_share.png')))
|
||||
|
||||
def toggle_content_server(self):
|
||||
if self.gui.content_server is None:
|
||||
|
@ -238,7 +238,7 @@ class Spacer(QWidget): # {{{
|
||||
self.l.addStretch(10)
|
||||
# }}}
|
||||
|
||||
class MenuAction(QAction):
|
||||
class MenuAction(QAction): # {{{
|
||||
|
||||
def __init__(self, clone, parent):
|
||||
QAction.__init__(self, clone.text(), parent)
|
||||
@ -247,7 +247,7 @@ class MenuAction(QAction):
|
||||
|
||||
def clone_changed(self):
|
||||
self.setText(self.clone.text())
|
||||
|
||||
# }}}
|
||||
|
||||
class MenuBar(QMenuBar): # {{{
|
||||
|
||||
@ -308,22 +308,47 @@ class MenuBar(QMenuBar): # {{{
|
||||
ac.setMenu(m)
|
||||
return ac
|
||||
|
||||
|
||||
|
||||
# }}}
|
||||
|
||||
class ToolBar(QToolBar): # {{{
|
||||
class BaseToolBar(QToolBar): # {{{
|
||||
|
||||
def __init__(self, donate, location_manager, child_bar, parent):
|
||||
def __init__(self, parent):
|
||||
QToolBar.__init__(self, parent)
|
||||
self.gui = parent
|
||||
self.child_bar = child_bar
|
||||
self.setContextMenuPolicy(Qt.PreventContextMenu)
|
||||
self.setMovable(False)
|
||||
self.setFloatable(False)
|
||||
self.setOrientation(Qt.Horizontal)
|
||||
self.setAllowedAreas(Qt.TopToolBarArea|Qt.BottomToolBarArea)
|
||||
self.setStyleSheet('QToolButton:checked { font-weight: bold }')
|
||||
self.preferred_width = self.sizeHint().width()
|
||||
|
||||
def resizeEvent(self, ev):
|
||||
QToolBar.resizeEvent(self, ev)
|
||||
style = self.get_text_style()
|
||||
self.setToolButtonStyle(style)
|
||||
|
||||
def get_text_style(self):
|
||||
style = Qt.ToolButtonTextUnderIcon
|
||||
s = gprefs['toolbar_icon_size']
|
||||
if s != 'off':
|
||||
p = gprefs['toolbar_text']
|
||||
if p == 'never':
|
||||
style = Qt.ToolButtonIconOnly
|
||||
elif p == 'auto' and self.preferred_width > self.width()+35:
|
||||
style = Qt.ToolButtonIconOnly
|
||||
return style
|
||||
|
||||
def contextMenuEvent(self, *args):
|
||||
pass
|
||||
|
||||
# }}}
|
||||
|
||||
class ToolBar(BaseToolBar): # {{{
|
||||
|
||||
def __init__(self, donate, location_manager, child_bar, parent):
|
||||
BaseToolBar.__init__(self, parent)
|
||||
self.gui = parent
|
||||
self.child_bar = child_bar
|
||||
self.donate_button = donate
|
||||
self.apply_settings()
|
||||
|
||||
@ -333,7 +358,6 @@ class ToolBar(QToolBar): # {{{
|
||||
donate.setCursor(Qt.PointingHandCursor)
|
||||
self.added_actions = []
|
||||
self.build_bar()
|
||||
self.preferred_width = self.sizeHint().width()
|
||||
self.setAcceptDrops(True)
|
||||
|
||||
def apply_settings(self):
|
||||
@ -348,9 +372,6 @@ class ToolBar(QToolBar): # {{{
|
||||
self.child_bar.setToolButtonStyle(style)
|
||||
self.donate_button.set_normal_icon_size(sz, sz)
|
||||
|
||||
def contextMenuEvent(self, *args):
|
||||
pass
|
||||
|
||||
def build_bar(self):
|
||||
self.showing_donate = False
|
||||
showing_device = self.location_manager.has_device
|
||||
@ -382,21 +403,20 @@ class ToolBar(QToolBar): # {{{
|
||||
bar.added_actions.append(ac)
|
||||
bar.setup_tool_button(bar, ac, QToolButton.MenuButtonPopup)
|
||||
elif what == 'Donate':
|
||||
self.d_widget = QWidget()
|
||||
self.d_widget.setLayout(QVBoxLayout())
|
||||
self.d_widget.layout().addWidget(self.donate_button)
|
||||
if isosx:
|
||||
bar.addAction(self.gui.donate_action)
|
||||
ch = self.setup_tool_button(bar, self.gui.donate_action)
|
||||
ch.setText(_('Donate'))
|
||||
else:
|
||||
self.d_widget = QWidget()
|
||||
self.d_widget.setLayout(QVBoxLayout())
|
||||
self.d_widget.layout().addWidget(self.donate_button)
|
||||
bar.addWidget(self.d_widget)
|
||||
self.showing_donate = True
|
||||
self.d_widget.setStyleSheet('QWidget, QToolButton {background-color: none; border: none; }')
|
||||
bar.addWidget(self.d_widget)
|
||||
self.showing_donate = True
|
||||
elif what in self.gui.iactions:
|
||||
action = self.gui.iactions[what]
|
||||
bar.addAction(action.qaction)
|
||||
self.added_actions.append(action.qaction)
|
||||
self.setup_tool_button(bar, action.qaction, action.popup_type)
|
||||
self.preferred_width = self.sizeHint().width()
|
||||
self.child_bar.preferred_width = self.child_bar.sizeHint().width()
|
||||
|
||||
def setup_tool_button(self, bar, ac, menu_mode=None):
|
||||
ch = bar.widgetForAction(ac)
|
||||
@ -408,21 +428,6 @@ class ToolBar(QToolBar): # {{{
|
||||
ch.setPopupMode(menu_mode)
|
||||
return ch
|
||||
|
||||
def resizeEvent(self, ev):
|
||||
QToolBar.resizeEvent(self, ev)
|
||||
style = Qt.ToolButtonTextUnderIcon
|
||||
s = gprefs['toolbar_icon_size']
|
||||
if s != 'off':
|
||||
p = gprefs['toolbar_text']
|
||||
if p == 'never':
|
||||
style = Qt.ToolButtonIconOnly
|
||||
|
||||
if p == 'auto' and self.preferred_width > self.width()+35 and \
|
||||
not gprefs['action-layout-toolbar-child']:
|
||||
style = Qt.ToolButtonIconOnly
|
||||
|
||||
self.setToolButtonStyle(style)
|
||||
|
||||
def database_changed(self, db):
|
||||
pass
|
||||
|
||||
@ -500,7 +505,7 @@ class MainWindowMixin(object): # {{{
|
||||
self.iactions['Fetch News'].init_scheduler(db)
|
||||
|
||||
self.search_bar = SearchBar(self)
|
||||
self.child_bar = QToolBar(self)
|
||||
self.child_bar = BaseToolBar(self)
|
||||
self.tool_bar = ToolBar(self.donate_button,
|
||||
self.location_manager, self.child_bar, self)
|
||||
self.addToolBar(Qt.TopToolBarArea, self.tool_bar)
|
||||
|
@ -658,7 +658,7 @@ editors = {'default': MetadataSingleDialog, 'alt1': MetadataSingleDialogAlt1}
|
||||
|
||||
def edit_metadata(db, row_list, current_row, parent=None, view_slot=None,
|
||||
set_current_callback=None):
|
||||
cls = db.prefs.get('edit_metadata_single_layout', '')
|
||||
cls = gprefs.get('edit_metadata_single_layout', '')
|
||||
if cls not in editors:
|
||||
cls = 'default'
|
||||
d = editors[cls](db, parent)
|
||||
|
@ -9,11 +9,13 @@ __docformat__ = 'restructuredtext en'
|
||||
|
||||
from threading import Thread, Event
|
||||
from operator import attrgetter
|
||||
from Queue import Queue, Empty
|
||||
|
||||
from PyQt4.Qt import (QStyledItemDelegate, QTextDocument, QRectF, QIcon, Qt,
|
||||
QStyle, QApplication, QDialog, QVBoxLayout, QLabel, QDialogButtonBox,
|
||||
QStackedWidget, QWidget, QTableView, QGridLayout, QFontInfo, QPalette,
|
||||
QTimer, pyqtSignal, QAbstractTableModel, QVariant, QSize)
|
||||
QTimer, pyqtSignal, QAbstractTableModel, QVariant, QSize, QListView,
|
||||
QPixmap, QAbstractListModel, QColor, QRect, QTextBrowser)
|
||||
from PyQt4.QtWebKit import QWebView
|
||||
|
||||
from calibre.customize.ui import metadata_plugins
|
||||
@ -24,6 +26,9 @@ from calibre.ebooks.metadata.book.base import Metadata
|
||||
from calibre.gui2 import error_dialog, NONE
|
||||
from calibre.utils.date import utcnow, fromordinal, format_date
|
||||
from calibre.library.comments import comments_to_html
|
||||
from calibre import force_unicode
|
||||
|
||||
DEBUG_DIALOG = False
|
||||
|
||||
class RichTextDelegate(QStyledItemDelegate): # {{{
|
||||
|
||||
@ -52,6 +57,65 @@ class RichTextDelegate(QStyledItemDelegate): # {{{
|
||||
painter.restore()
|
||||
# }}}
|
||||
|
||||
class CoverDelegate(QStyledItemDelegate): # {{{
|
||||
|
||||
needs_redraw = pyqtSignal()
|
||||
|
||||
def __init__(self, parent):
|
||||
QStyledItemDelegate.__init__(self, parent)
|
||||
|
||||
self.angle = 0
|
||||
self.timer = QTimer(self)
|
||||
self.timer.timeout.connect(self.frame_changed)
|
||||
self.color = parent.palette().color(QPalette.WindowText)
|
||||
self.spinner_width = 64
|
||||
|
||||
def frame_changed(self, *args):
|
||||
self.angle = (self.angle+30)%360
|
||||
self.needs_redraw.emit()
|
||||
|
||||
def start_animation(self):
|
||||
self.angle = 0
|
||||
self.timer.start(200)
|
||||
|
||||
def stop_animation(self):
|
||||
self.timer.stop()
|
||||
|
||||
def draw_spinner(self, painter, rect):
|
||||
width = rect.width()
|
||||
|
||||
outer_radius = (width-1)*0.5
|
||||
inner_radius = (width-1)*0.5*0.38
|
||||
|
||||
capsule_height = outer_radius - inner_radius
|
||||
capsule_width = int(capsule_height * (0.23 if width > 32 else 0.35))
|
||||
capsule_radius = capsule_width//2
|
||||
|
||||
painter.save()
|
||||
painter.setRenderHint(painter.Antialiasing)
|
||||
|
||||
for i in xrange(12):
|
||||
color = QColor(self.color)
|
||||
color.setAlphaF(1.0 - (i/12.0))
|
||||
painter.setPen(Qt.NoPen)
|
||||
painter.setBrush(color)
|
||||
painter.save()
|
||||
painter.translate(rect.center())
|
||||
painter.rotate(self.angle - i*30.0)
|
||||
painter.drawRoundedRect(-capsule_width*0.5,
|
||||
-(inner_radius+capsule_height), capsule_width,
|
||||
capsule_height, capsule_radius, capsule_radius)
|
||||
painter.restore()
|
||||
painter.restore()
|
||||
|
||||
def paint(self, painter, option, index):
|
||||
QStyledItemDelegate.paint(self, painter, option, index)
|
||||
if self.timer.isActive() and index.data(Qt.UserRole).toBool():
|
||||
rect = QRect(0, 0, self.spinner_width, self.spinner_width)
|
||||
rect.moveCenter(option.rect.center())
|
||||
self.draw_spinner(painter, rect)
|
||||
# }}}
|
||||
|
||||
class ResultsModel(QAbstractTableModel): # {{{
|
||||
|
||||
COLUMNS = (
|
||||
@ -268,7 +332,7 @@ class IdentifyWorker(Thread): # {{{
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
if True:
|
||||
if DEBUG_DIALOG:
|
||||
self.results = self.sample_results()
|
||||
else:
|
||||
self.results = identify(self.log, self.abort, title=self.title,
|
||||
@ -277,7 +341,7 @@ class IdentifyWorker(Thread): # {{{
|
||||
result.gui_rank = i
|
||||
except:
|
||||
import traceback
|
||||
self.error = traceback.format_exc()
|
||||
self.error = force_unicode(traceback.format_exc())
|
||||
# }}}
|
||||
|
||||
class IdentifyWidget(QWidget): # {{{
|
||||
@ -398,11 +462,307 @@ class IdentifyWidget(QWidget): # {{{
|
||||
self.abort.set()
|
||||
# }}}
|
||||
|
||||
class FullFetch(QDialog): # {{{
|
||||
class CoverWorker(Thread): # {{{
|
||||
|
||||
def __init__(self, log, abort, title, authors, identifiers):
|
||||
Thread.__init__(self)
|
||||
self.daemon = True
|
||||
|
||||
self.log, self.abort = log, abort
|
||||
self.title, self.authors, self.identifiers = (title, authors,
|
||||
identifiers)
|
||||
|
||||
self.rq = Queue()
|
||||
self.error = None
|
||||
|
||||
def fake_run(self):
|
||||
images = ['donate.png', 'config.png', 'column.png', 'eject.png', ]
|
||||
import time
|
||||
time.sleep(2)
|
||||
for pl, im in zip(metadata_plugins(['cover']), images):
|
||||
self.rq.put((pl, 1, 1, 'png', I(im, data=True)))
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
if DEBUG_DIALOG:
|
||||
self.fake_run()
|
||||
else:
|
||||
from calibre.ebooks.metadata.sources.covers import run_download
|
||||
run_download(self.log, self.rq, self.abort, title=self.title,
|
||||
authors=self.authors, identifiers=self.identifiers)
|
||||
except:
|
||||
import traceback
|
||||
self.error = force_unicode(traceback.format_exc())
|
||||
# }}}
|
||||
|
||||
class CoversModel(QAbstractListModel): # {{{
|
||||
|
||||
def __init__(self, current_cover, parent=None):
|
||||
QAbstractListModel.__init__(self, parent)
|
||||
|
||||
if current_cover is None:
|
||||
current_cover = QPixmap(I('default_cover.png'))
|
||||
|
||||
self.blank = QPixmap(I('blank.png')).scaled(150, 200)
|
||||
|
||||
self.covers = [self.get_item(_('Current cover'), current_cover)]
|
||||
self.plugin_map = {}
|
||||
for i, plugin in enumerate(metadata_plugins(['cover'])):
|
||||
self.covers.append((plugin.name+'\n'+_('Searching...'),
|
||||
QVariant(self.blank), None, True))
|
||||
self.plugin_map[plugin] = i+1
|
||||
|
||||
def get_item(self, src, pmap, waiting=False):
|
||||
sz = '%dx%d'%(pmap.width(), pmap.height())
|
||||
text = QVariant(src + '\n' + sz)
|
||||
scaled = pmap.scaled(150, 200, Qt.IgnoreAspectRatio,
|
||||
Qt.SmoothTransformation)
|
||||
return (text, QVariant(scaled), pmap, waiting)
|
||||
|
||||
def rowCount(self, parent=None):
|
||||
return len(self.covers)
|
||||
|
||||
def data(self, index, role):
|
||||
try:
|
||||
text, pmap, cover, waiting = self.covers[index.row()]
|
||||
except:
|
||||
return NONE
|
||||
if role == Qt.DecorationRole:
|
||||
return pmap
|
||||
if role == Qt.DisplayRole:
|
||||
return text
|
||||
if role == Qt.UserRole:
|
||||
return waiting
|
||||
return NONE
|
||||
|
||||
def plugin_for_index(self, index):
|
||||
row = index.row() if hasattr(index, 'row') else index
|
||||
for k, v in self.plugin_map.iteritems():
|
||||
if v == row:
|
||||
return k
|
||||
|
||||
def clear_failed(self):
|
||||
good = []
|
||||
pmap = {}
|
||||
for i, x in enumerate(self.covers):
|
||||
if not x[-1]:
|
||||
good.append(x)
|
||||
if i > 0:
|
||||
plugin = self.plugin_for_index(i)
|
||||
pmap[plugin] = len(good) - 1
|
||||
good = [x for x in self.covers if not x[-1]]
|
||||
self.covers = good
|
||||
self.plugin_map = pmap
|
||||
self.reset()
|
||||
|
||||
def index_for_plugin(self, plugin):
|
||||
idx = self.plugin_map.get(plugin, 0)
|
||||
return self.index(idx)
|
||||
|
||||
def update_result(self, plugin, width, height, data):
|
||||
try:
|
||||
idx = self.plugin_map[plugin]
|
||||
except:
|
||||
return
|
||||
pmap = QPixmap()
|
||||
pmap.loadFromData(data)
|
||||
if pmap.isNull():
|
||||
return
|
||||
self.covers[idx] = self.get_item(plugin.name, pmap, waiting=False)
|
||||
self.dataChanged.emit(self.index(idx), self.index(idx))
|
||||
|
||||
def cover_pixmap(self, index):
|
||||
row = index.row()
|
||||
if row > 0 and row < len(self.covers):
|
||||
pmap = self.covers[row][2]
|
||||
if pmap is not None and not pmap.isNull():
|
||||
return pmap
|
||||
|
||||
# }}}
|
||||
|
||||
class CoversView(QListView): # {{{
|
||||
|
||||
chosen = pyqtSignal()
|
||||
|
||||
def __init__(self, current_cover, parent=None):
|
||||
QListView.__init__(self, parent)
|
||||
self.m = CoversModel(current_cover, self)
|
||||
self.setModel(self.m)
|
||||
|
||||
self.setFlow(self.LeftToRight)
|
||||
self.setWrapping(True)
|
||||
self.setResizeMode(self.Adjust)
|
||||
self.setGridSize(QSize(190, 260))
|
||||
self.setIconSize(QSize(150, 200))
|
||||
self.setSelectionMode(self.SingleSelection)
|
||||
self.setViewMode(self.IconMode)
|
||||
|
||||
self.delegate = CoverDelegate(self)
|
||||
self.setItemDelegate(self.delegate)
|
||||
self.delegate.needs_redraw.connect(self.viewport().update,
|
||||
type=Qt.QueuedConnection)
|
||||
|
||||
self.doubleClicked.connect(self.chosen, type=Qt.QueuedConnection)
|
||||
|
||||
def select(self, num):
|
||||
current = self.model().index(num)
|
||||
sm = self.selectionModel()
|
||||
sm.select(current, sm.SelectCurrent)
|
||||
|
||||
def start(self):
|
||||
self.select(0)
|
||||
self.delegate.start_animation()
|
||||
|
||||
def clear_failed(self):
|
||||
plugin = self.m.plugin_for_index(self.currentIndex())
|
||||
self.m.clear_failed()
|
||||
self.select(self.m.index_for_plugin(plugin).row())
|
||||
|
||||
# }}}
|
||||
|
||||
class CoversWidget(QWidget): # {{{
|
||||
|
||||
chosen = pyqtSignal()
|
||||
finished = pyqtSignal()
|
||||
|
||||
def __init__(self, log, current_cover, parent=None):
|
||||
QWidget.__init__(self, parent)
|
||||
self.log = log
|
||||
self.abort = Event()
|
||||
|
||||
self.l = l = QGridLayout()
|
||||
self.setLayout(l)
|
||||
|
||||
self.msg = QLabel()
|
||||
self.msg.setWordWrap(True)
|
||||
l.addWidget(self.msg, 0, 0)
|
||||
|
||||
self.covers_view = CoversView(current_cover, self)
|
||||
self.covers_view.chosen.connect(self.chosen)
|
||||
l.addWidget(self.covers_view, 1, 0)
|
||||
self.continue_processing = True
|
||||
|
||||
def start(self, book, current_cover, title, authors):
|
||||
self.book, self.current_cover = book, current_cover
|
||||
self.title, self.authors = title, authors
|
||||
self.log('\n\nStarting cover download for:', book.title)
|
||||
self.msg.setText('<p>'+_('Downloading covers for <b>%s</b>, please wait...')%book.title)
|
||||
self.covers_view.start()
|
||||
|
||||
self.worker = CoverWorker(self.log, self.abort, self.title,
|
||||
self.authors, book.identifiers)
|
||||
self.worker.start()
|
||||
QTimer.singleShot(50, self.check)
|
||||
self.covers_view.setFocus(Qt.OtherFocusReason)
|
||||
|
||||
def check(self):
|
||||
if self.worker.is_alive() and not self.abort.is_set():
|
||||
QTimer.singleShot(50, self.check)
|
||||
try:
|
||||
self.process_result(self.worker.rq.get_nowait())
|
||||
except Empty:
|
||||
pass
|
||||
else:
|
||||
self.process_results()
|
||||
|
||||
def process_results(self):
|
||||
while self.continue_processing:
|
||||
try:
|
||||
self.process_result(self.worker.rq.get_nowait())
|
||||
except Empty:
|
||||
break
|
||||
|
||||
self.covers_view.clear_failed()
|
||||
|
||||
if self.worker.error is not None:
|
||||
error_dialog(self, _('Download failed'),
|
||||
_('Failed to download any covers, click'
|
||||
' "Show details" for details.'),
|
||||
det_msg=self.worker.error, show=True)
|
||||
|
||||
num = self.covers_view.model().rowCount()
|
||||
if num < 2:
|
||||
txt = _('Could not find any covers for <b>%s</b>')%self.book.title
|
||||
else:
|
||||
txt = _('Found <b>%d</b> covers of %s. Pick the one you like'
|
||||
' best.')%(num-1, self.title)
|
||||
self.msg.setText(txt)
|
||||
|
||||
self.finished.emit()
|
||||
|
||||
def process_result(self, result):
|
||||
if not self.continue_processing:
|
||||
return
|
||||
plugin, width, height, fmt, data = result
|
||||
self.covers_view.model().update_result(plugin, width, height, data)
|
||||
|
||||
def cleanup(self):
|
||||
self.covers_view.delegate.stop_animation()
|
||||
self.continue_processing = False
|
||||
|
||||
def cancel(self):
|
||||
self.continue_processing = False
|
||||
self.abort.set()
|
||||
|
||||
def cover_pixmap(self):
|
||||
idx = None
|
||||
for i in self.covers_view.selectionModel().selectedIndexes():
|
||||
if i.isValid():
|
||||
idx = i
|
||||
break
|
||||
if idx is None:
|
||||
idx = self.covers_view.currentIndex()
|
||||
return self.covers_view.model().cover_pixmap(idx)
|
||||
|
||||
# }}}
|
||||
|
||||
class LogViewer(QDialog): # {{{
|
||||
|
||||
def __init__(self, log, parent=None):
|
||||
QDialog.__init__(self, parent)
|
||||
self.log = log
|
||||
self.l = l = QVBoxLayout()
|
||||
self.setLayout(l)
|
||||
|
||||
self.tb = QTextBrowser(self)
|
||||
l.addWidget(self.tb)
|
||||
|
||||
self.bb = QDialogButtonBox(QDialogButtonBox.Close)
|
||||
l.addWidget(self.bb)
|
||||
self.bb.rejected.connect(self.reject)
|
||||
self.bb.accepted.connect(self.accept)
|
||||
|
||||
self.setWindowTitle(_('Download log'))
|
||||
self.setWindowIcon(QIcon(I('debug.png')))
|
||||
self.resize(QSize(800, 400))
|
||||
|
||||
self.keep_updating = True
|
||||
self.last_html = None
|
||||
self.finished.connect(self.stop)
|
||||
QTimer.singleShot(1000, self.update_log)
|
||||
|
||||
self.show()
|
||||
|
||||
def stop(self, *args):
|
||||
self.keep_updating = False
|
||||
|
||||
def update_log(self):
|
||||
if not self.keep_updating:
|
||||
return
|
||||
html = self.log.html
|
||||
if html != self.last_html:
|
||||
self.last_html = html
|
||||
self.tb.setHtml('<pre>%s</pre>'%html)
|
||||
QTimer.singleShot(1000, self.update_log)
|
||||
|
||||
# }}}
|
||||
|
||||
class FullFetch(QDialog): # {{{
|
||||
|
||||
def __init__(self, log, current_cover=None, parent=None):
|
||||
QDialog.__init__(self, parent)
|
||||
self.log, self.current_cover = log, current_cover
|
||||
self.book = self.cover_pixmap = None
|
||||
|
||||
self.setWindowTitle(_('Downloading metadata...'))
|
||||
self.setWindowIcon(QIcon(I('metadata.png')))
|
||||
@ -418,22 +778,39 @@ class FullFetch(QDialog): # {{{
|
||||
self.next_button = self.bb.addButton(_('Next'), self.bb.AcceptRole)
|
||||
self.next_button.setDefault(True)
|
||||
self.next_button.setEnabled(False)
|
||||
self.next_button.setIcon(QIcon(I('ok.png')))
|
||||
self.next_button.clicked.connect(self.next_clicked)
|
||||
self.ok_button = self.bb.button(self.bb.Ok)
|
||||
self.ok_button.setVisible(False)
|
||||
self.ok_button.clicked.connect(self.ok_clicked)
|
||||
self.log_button = self.bb.addButton(_('View log'), self.bb.ActionRole)
|
||||
self.log_button.clicked.connect(self.view_log)
|
||||
self.log_button.setIcon(QIcon(I('debug.png')))
|
||||
self.ok_button.setVisible(False)
|
||||
|
||||
self.identify_widget = IdentifyWidget(log, self)
|
||||
self.identify_widget.rejected.connect(self.reject)
|
||||
self.identify_widget.results_found.connect(self.identify_results_found)
|
||||
self.identify_widget.book_selected.connect(self.book_selected)
|
||||
self.stack.addWidget(self.identify_widget)
|
||||
self.resize(850, 500)
|
||||
|
||||
self.covers_widget = CoversWidget(self.log, self.current_cover, parent=self)
|
||||
self.covers_widget.chosen.connect(self.ok_clicked)
|
||||
self.stack.addWidget(self.covers_widget)
|
||||
|
||||
self.resize(850, 550)
|
||||
|
||||
self.finished.connect(self.cleanup)
|
||||
|
||||
def view_log(self):
|
||||
self._lv = LogViewer(self.log, self)
|
||||
|
||||
def book_selected(self, book):
|
||||
print (book)
|
||||
self.next_button.setVisible(False)
|
||||
self.ok_button.setVisible(True)
|
||||
self.book = book
|
||||
self.stack.setCurrentIndex(1)
|
||||
self.covers_widget.start(book, self.current_cover,
|
||||
self.title, self.authors)
|
||||
|
||||
def accept(self):
|
||||
# Prevent the usual dialog accept mechanisms from working
|
||||
@ -443,6 +820,9 @@ class FullFetch(QDialog): # {{{
|
||||
self.identify_widget.cancel()
|
||||
return QDialog.reject(self)
|
||||
|
||||
def cleanup(self):
|
||||
self.covers_widget.cleanup()
|
||||
|
||||
def identify_results_found(self):
|
||||
self.next_button.setEnabled(True)
|
||||
|
||||
@ -450,15 +830,25 @@ class FullFetch(QDialog): # {{{
|
||||
self.identify_widget.get_result()
|
||||
|
||||
def ok_clicked(self, *args):
|
||||
pass
|
||||
self.cover_pixmap = self.covers_widget.cover_pixmap()
|
||||
if DEBUG_DIALOG:
|
||||
if self.cover_pixmap is not None:
|
||||
self.w = QLabel()
|
||||
self.w.setPixmap(self.cover_pixmap)
|
||||
self.stack.addWidget(self.w)
|
||||
self.stack.setCurrentIndex(2)
|
||||
else:
|
||||
QDialog.accept(self)
|
||||
|
||||
def start(self, title=None, authors=None, identifiers={}):
|
||||
self.title, self.authors = title, authors
|
||||
self.identify_widget.start(title=title, authors=authors,
|
||||
identifiers=identifiers)
|
||||
self.exec_()
|
||||
# }}}
|
||||
|
||||
if __name__ == '__main__':
|
||||
DEBUG_DIALOG = True
|
||||
app = QApplication([])
|
||||
d = FullFetch(Log())
|
||||
d.start(title='great gatsby', authors=['Fitzgerald'])
|
||||
|
@ -11,7 +11,7 @@ from PyQt4.Qt import Qt, QVariant, QListWidgetItem
|
||||
|
||||
from calibre.gui2.preferences import ConfigWidgetBase, test_widget, Setting
|
||||
from calibre.gui2.preferences.behavior_ui import Ui_Form
|
||||
from calibre.gui2 import config, info_dialog, dynamic
|
||||
from calibre.gui2 import config, info_dialog, dynamic, gprefs
|
||||
from calibre.utils.config import prefs
|
||||
from calibre.customize.ui import available_output_formats, all_input_formats
|
||||
from calibre.utils.search_query_parser import saved_searches
|
||||
@ -19,6 +19,7 @@ from calibre.ebooks import BOOK_EXTENSIONS
|
||||
from calibre.ebooks.oeb.iterator import is_supported
|
||||
from calibre.constants import iswindows
|
||||
from calibre.utils.icu import sort_key
|
||||
from calibre.utils.config import test_eight_code
|
||||
|
||||
class OutputFormatSetting(Setting):
|
||||
|
||||
@ -62,6 +63,14 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
signal = getattr(self.opt_internally_viewed_formats, 'item'+signal)
|
||||
signal.connect(self.internally_viewed_formats_changed)
|
||||
|
||||
r('bools_are_tristate', db.prefs, restart_required=True)
|
||||
if test_eight_code:
|
||||
r = self.register
|
||||
choices = [(_('Default'), 'default'), (_('Compact Metadata'), 'alt1')]
|
||||
r('edit_metadata_single_layout', gprefs, choices=choices)
|
||||
else:
|
||||
self.opt_edit_metadata_single_layout.setVisible(False)
|
||||
self.edit_metadata_single_label.setVisible(False)
|
||||
|
||||
def initialize(self):
|
||||
ConfigWidgetBase.initialize(self)
|
||||
|
@ -14,44 +14,92 @@
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<item row="0" column="1">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>00</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="opt_overwrite_author_title_metadata">
|
||||
<property name="text">
|
||||
<string>&Overwrite author and title by default when fetching metadata</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<item row="0" column="2">
|
||||
<widget class="QCheckBox" name="opt_get_social_metadata">
|
||||
<property name="text">
|
||||
<string>Download &social metadata (tags/ratings/etc.) by default</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="opt_new_version_notification">
|
||||
<property name="text">
|
||||
<string>Show notification when &new version is available</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<item row="2" column="2">
|
||||
<widget class="QCheckBox" name="opt_bools_are_tristate">
|
||||
<property name="text">
|
||||
<string>Yes/No columns have three values (Requires restart)</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>If checked, Yes/No custom columns values can be Yes, No, or Unknown.
|
||||
If not checked, the values can be Yes or No.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="opt_upload_news_to_device">
|
||||
<property name="text">
|
||||
<string>Automatically send downloaded &news to ebook reader</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<item row="4" column="2">
|
||||
<widget class="QCheckBox" name="opt_delete_news_from_library_on_upload">
|
||||
<property name="text">
|
||||
<string>&Delete news from library when it is automatically sent to reader</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="1" column="0">
|
||||
<item row="6" column="0">
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_23">
|
||||
<property name="text">
|
||||
<string>Preferred &output format:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>opt_output_format</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="opt_output_format">
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToMinimumContentsLengthWithIcon</enum>
|
||||
</property>
|
||||
<property name="minimumContentsLength">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="6" column="2">
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Default network &timeout:</string>
|
||||
@ -61,7 +109,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="opt_network_timeout">
|
||||
<property name="toolTip">
|
||||
<string>Set the default timeout for network fetches (i.e. anytime we go out to the internet to get information)</string>
|
||||
@ -80,7 +128,21 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
</layout>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="priority_label">
|
||||
<property name="text">
|
||||
<string>Job &priority:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>opt_worker_process_priority</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="opt_worker_process_priority">
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToMinimumContentsLengthWithIcon</enum>
|
||||
@ -105,37 +167,11 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="priority_label">
|
||||
<property name="text">
|
||||
<string>Job &priority:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>opt_worker_process_priority</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_23">
|
||||
<property name="text">
|
||||
<string>Preferred &output format:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>opt_output_format</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="opt_output_format">
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToMinimumContentsLengthWithIcon</enum>
|
||||
</property>
|
||||
<property name="minimumContentsLength">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
</layout>
|
||||
</item>
|
||||
<item row="8" column="2">
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_170">
|
||||
<property name="text">
|
||||
<string>Restriction to apply when the current library is opened:</string>
|
||||
@ -145,7 +181,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item>
|
||||
<widget class="QComboBox" name="opt_gui_restriction">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
@ -166,14 +202,28 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="reset_confirmation_button">
|
||||
<property name="text">
|
||||
<string>Reset all disabled &confirmation dialogs</string>
|
||||
</property>
|
||||
</widget>
|
||||
<item row="9" column="0">
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="edit_metadata_single_label">
|
||||
<property name="text">
|
||||
<string>Edit metadata (single) layout:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>opt_edit_metadata_single_layout</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="opt_edit_metadata_single_layout">
|
||||
<property name="toolTip">
|
||||
<string>Choose a different layout for the Edit Metadata dialog. The compact metadata layout favors editing custom metadata over changing covers and formats.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<item row="20" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_5">
|
||||
<property name="title">
|
||||
<string>Preferred &input format order:</string>
|
||||
@ -235,7 +285,7 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<item row="20" column="2">
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>Use internal &viewer for:</string>
|
||||
@ -254,6 +304,13 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="30" column="0" colspan="3">
|
||||
<widget class="QPushButton" name="reset_confirmation_button">
|
||||
<property name="text">
|
||||
<string>Reset all disabled &confirmation dialogs</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
|
@ -13,7 +13,6 @@ from calibre.gui2.preferences import ConfigWidgetBase, test_widget
|
||||
from calibre.gui2.preferences.columns_ui import Ui_Form
|
||||
from calibre.gui2.preferences.create_custom_column import CreateCustomColumn
|
||||
from calibre.gui2 import error_dialog, question_dialog, ALL_COLUMNS
|
||||
from calibre.utils.config import test_eight_code
|
||||
|
||||
class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
|
||||
@ -34,14 +33,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
signal = getattr(self.opt_columns, 'item'+signal)
|
||||
signal.connect(self.columns_changed)
|
||||
|
||||
if test_eight_code:
|
||||
r = self.register
|
||||
choices = [(_('Default'), 'default'), (_('Compact Metadata'), 'alt1')]
|
||||
r('edit_metadata_single_layout', db.prefs, choices=choices)
|
||||
r('bools_are_tristate', db.prefs, restart_required=True)
|
||||
else:
|
||||
self.items_in_v_eight.setVisible(False)
|
||||
|
||||
def initialize(self):
|
||||
ConfigWidgetBase.initialize(self)
|
||||
self.init_columns()
|
||||
@ -178,10 +169,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
must_restart = True
|
||||
return must_restart
|
||||
|
||||
def refresh_gui(self, gui):
|
||||
gui.library_view.reset()
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from PyQt4.Qt import QApplication
|
||||
|
@ -197,67 +197,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="items_in_v_eight">
|
||||
<property name="title">
|
||||
<string>Related Options</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel">
|
||||
<property name="text">
|
||||
<string>Edit metadata layout:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>opt_edit_metadata_single_layout</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="opt_edit_metadata_single_layout">
|
||||
<property name="toolTip">
|
||||
<string>Choose a different layout for the Edit Metadata dialog. Alternate layouts make it easier to edit custom columns.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel">
|
||||
<property name="text">
|
||||
<string>Boolean columns are tristate:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>opt_bools_are_tristate</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="opt_bools_are_tristate">
|
||||
<property name="toolTip">
|
||||
<string>If checked, boolean columns values can be Yes, No, and Unknown.
|
||||
If not checked, the values can be Yes and No.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
|
@ -80,6 +80,12 @@ class BaseModel(QAbstractListModel):
|
||||
ans.append(n)
|
||||
return ans
|
||||
|
||||
def has_action(self, name):
|
||||
for a in self._data:
|
||||
if a.name == name:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class AllModel(BaseModel):
|
||||
|
||||
@ -291,16 +297,13 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
def commit(self):
|
||||
# Ensure preferences are showing in either the toolbar or
|
||||
# the menubar.
|
||||
pref_in_toolbar = lm_in_toolbar = False
|
||||
cm = self.models['toolbar']
|
||||
for x in cm[1]._data:
|
||||
if x.name == 'Preferences':
|
||||
pref_in_toolbar = True
|
||||
if x.name == 'Location Manager':
|
||||
lm_in_toolbar = True
|
||||
if not pref_in_toolbar:
|
||||
pref_in_toolbar = self.models['toolbar'][1].has_action('Preferences')
|
||||
pref_in_menubar = self.models['menubar'][1].has_action('Preferences')
|
||||
lm_in_toolbar = self.models['toolbar-device'][1].has_action('Location Manager')
|
||||
lm_in_menubar = self.models['menubar-device'][1].has_action('Location Manager')
|
||||
if not pref_in_toolbar and not pref_in_menubar:
|
||||
self.models['menubar'][1].add(['Preferences'])
|
||||
if not lm_in_toolbar:
|
||||
if not lm_in_toolbar and not lm_in_menubar:
|
||||
self.models['menubar-device'][1].add(['Location Manager'])
|
||||
|
||||
# Save data.
|
||||
|
@ -40,7 +40,6 @@ from calibre.ebooks import BOOK_EXTENSIONS, check_ebook_format
|
||||
from calibre.utils.magick.draw import save_cover_data_to
|
||||
from calibre.utils.recycle_bin import delete_file, delete_tree
|
||||
from calibre.utils.formatter_functions import load_user_template_functions
|
||||
from calibre.utils.config import test_eight_code
|
||||
|
||||
copyfile = os.link if hasattr(os, 'link') else shutil.copyfile
|
||||
|
||||
@ -213,11 +212,11 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
defs = self.prefs.defaults
|
||||
defs['gui_restriction'] = defs['cs_restriction'] = ''
|
||||
defs['categories_using_hierarchy'] = []
|
||||
defs['edit_metadata_single_layout'] = 'default'
|
||||
|
||||
# Migrate the bool tristate tweak
|
||||
defs['bools_are_tristate'] = \
|
||||
tweaks.get('bool_custom_columns_are_tristate', 'yes') == 'yes'
|
||||
if self.prefs.get('bools_are_tristate') is None or not test_eight_code:
|
||||
if self.prefs.get('bools_are_tristate') is None:
|
||||
self.prefs.set('bools_are_tristate', defs['bools_are_tristate'])
|
||||
|
||||
# Migrate saved search and user categories to db preference scheme
|
||||
|
@ -786,8 +786,7 @@ def write_tweaks(raw):
|
||||
tweaks = read_tweaks()
|
||||
test_eight_code = tweaks.get('test_eight_code', False)
|
||||
# test_eight_code notes
|
||||
# Change documentation of bool columns are tristate to indicate that it can be
|
||||
# overridden on a per library basis via Preferences->Custom columns
|
||||
# Change Amazon plugin name to just Amazon
|
||||
|
||||
def migrate():
|
||||
if hasattr(os, 'geteuid') and os.geteuid() == 0:
|
||||
|
Loading…
x
Reference in New Issue
Block a user