mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge from trunk
This commit is contained in:
commit
4782888466
@ -5,7 +5,7 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import os, posixpath, urllib, sys
|
||||
import os, posixpath, urllib, sys, re
|
||||
|
||||
from lxml import etree
|
||||
|
||||
@ -160,8 +160,26 @@ class Container(object):
|
||||
mt = mimetype.lower()
|
||||
if mt.endswith('+xml'):
|
||||
parser = etree.XMLParser(no_network=True, huge_tree=not iswindows)
|
||||
return etree.fromstring(xml_to_unicode(raw,
|
||||
strip_encoding_pats=True, assume_utf8=True)[0], parser=parser)
|
||||
raw = xml_to_unicode(raw,
|
||||
strip_encoding_pats=True, assume_utf8=True,
|
||||
resolve_entities=True)[0].strip()
|
||||
idx = raw.find('<html')
|
||||
if idx == -1:
|
||||
idx = raw.find('<HTML')
|
||||
if idx > -1:
|
||||
pre = raw[:idx]
|
||||
raw = raw[idx:]
|
||||
if '<!DOCTYPE' in pre:
|
||||
user_entities = {}
|
||||
for match in re.finditer(r'<!ENTITY\s+(\S+)\s+([^>]+)', pre):
|
||||
val = match.group(2)
|
||||
if val.startswith('"') and val.endswith('"'):
|
||||
val = val[1:-1]
|
||||
user_entities[match.group(1)] = val
|
||||
if user_entities:
|
||||
pat = re.compile(r'&(%s);'%('|'.join(user_entities.keys())))
|
||||
raw = pat.sub(lambda m:user_entities[m.group(1)], raw)
|
||||
return etree.fromstring(raw, parser=parser)
|
||||
return raw
|
||||
|
||||
def write(self, path):
|
||||
|
@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en'
|
||||
|
||||
import functools, sys, os
|
||||
|
||||
from PyQt4.Qt import QMenu, Qt, pyqtSignal, QToolButton, QIcon, QStackedWidget, \
|
||||
from PyQt4.Qt import QMenu, Qt, pyqtSignal, QIcon, QStackedWidget, \
|
||||
QSize, QSizePolicy, QStatusBar, QUrl, QLabel, QFont
|
||||
|
||||
from calibre.utils.config import prefs
|
||||
@ -173,20 +173,6 @@ class ToolbarMixin(object): # {{{
|
||||
for x in (self.preferences_action, self.action_preferences):
|
||||
x.triggered.connect(self.do_config)
|
||||
|
||||
for x in ('news', 'edit', 'sync', 'convert', 'save', 'add', 'view',
|
||||
'del', 'preferences'):
|
||||
w = self.tool_bar.widgetForAction(getattr(self, 'action_'+x))
|
||||
w.setPopupMode(w.MenuButtonPopup)
|
||||
|
||||
self.tool_bar.setContextMenuPolicy(Qt.PreventContextMenu)
|
||||
|
||||
for ch in self.tool_bar.children():
|
||||
if isinstance(ch, QToolButton):
|
||||
ch.setCursor(Qt.PointingHandCursor)
|
||||
ch.setStatusTip(ch.toolTip())
|
||||
|
||||
self.tool_bar.contextMenuEvent = self.no_op
|
||||
|
||||
def show_help(self, *args):
|
||||
open_url(QUrl('http://calibre-ebook.com/user_manual'))
|
||||
|
||||
@ -435,8 +421,6 @@ class StatusBar(QStatusBar): # {{{
|
||||
class LayoutMixin(object): # {{{
|
||||
|
||||
def __init__(self):
|
||||
self.setupUi(self)
|
||||
self.setWindowTitle(__appname__)
|
||||
|
||||
if config['gui_layout'] == 'narrow': # narrow {{{
|
||||
self.book_details = BookDetails(False, self)
|
||||
|
460
src/calibre/gui2/layout.py
Normal file
460
src/calibre/gui2/layout.py
Normal file
@ -0,0 +1,460 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
from PyQt4.Qt import QIcon, Qt, QWidget, QAction, QToolBar, QSize, QVariant, \
|
||||
QAbstractListModel, QFont, QApplication, QPalette, pyqtSignal, QToolButton, \
|
||||
QModelIndex, QListView, QAbstractButton, QPainter, QPixmap, QColor, \
|
||||
QVBoxLayout, QSizePolicy, QLabel, QHBoxLayout, QComboBox
|
||||
|
||||
from calibre.constants import __appname__, filesystem_encoding
|
||||
from calibre.gui2.search_box import SearchBox2, SavedSearchBox
|
||||
from calibre.gui2.throbber import ThrobbingButton
|
||||
from calibre.gui2 import NONE
|
||||
from calibre import human_readable
|
||||
|
||||
class ToolBar(QToolBar): # {{{
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QToolBar.__init__(self, parent)
|
||||
self.setContextMenuPolicy(Qt.PreventContextMenu)
|
||||
self.setMovable(False)
|
||||
self.setFloatable(False)
|
||||
self.setOrientation(Qt.Horizontal)
|
||||
self.setAllowedAreas(Qt.TopToolBarArea|Qt.BottomToolBarArea)
|
||||
self.setIconSize(QSize(48, 48))
|
||||
self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
|
||||
|
||||
def add_actions(self, *args):
|
||||
self.left_space = QWidget(self)
|
||||
self.left_space.setSizePolicy(QSizePolicy.Expanding,
|
||||
QSizePolicy.Minimum)
|
||||
self.addWidget(self.left_space)
|
||||
for action in args:
|
||||
if action is None:
|
||||
self.addSeparator()
|
||||
else:
|
||||
self.addAction(action)
|
||||
self.right_space = QWidget(self)
|
||||
self.right_space.setSizePolicy(QSizePolicy.Expanding,
|
||||
QSizePolicy.Minimum)
|
||||
self.addWidget(self.right_space)
|
||||
|
||||
def contextMenuEvent(self, *args):
|
||||
pass
|
||||
|
||||
# }}}
|
||||
|
||||
# Location View {{{
|
||||
|
||||
class LocationModel(QAbstractListModel): # {{{
|
||||
|
||||
devicesChanged = pyqtSignal()
|
||||
|
||||
def __init__(self, parent):
|
||||
QAbstractListModel.__init__(self, parent)
|
||||
self.icons = [QVariant(QIcon(I('library.png'))),
|
||||
QVariant(QIcon(I('reader.svg'))),
|
||||
QVariant(QIcon(I('sd.svg'))),
|
||||
QVariant(QIcon(I('sd.svg')))]
|
||||
self.text = [_('Library\n%d books'),
|
||||
_('Reader\n%s'),
|
||||
_('Card A\n%s'),
|
||||
_('Card B\n%s')]
|
||||
self.free = [-1, -1, -1]
|
||||
self.count = 0
|
||||
self.highlight_row = 0
|
||||
self.library_tooltip = _('Click to see the books available on your computer')
|
||||
self.tooltips = [
|
||||
self.library_tooltip,
|
||||
_('Click to see the books in the main memory of your reader'),
|
||||
_('Click to see the books on storage card A in your reader'),
|
||||
_('Click to see the books on storage card B in your reader')
|
||||
]
|
||||
|
||||
def database_changed(self, db):
|
||||
lp = db.library_path
|
||||
if not isinstance(lp, unicode):
|
||||
lp = lp.decode(filesystem_encoding, 'replace')
|
||||
self.tooltips[0] = self.library_tooltip + '\n\n' + \
|
||||
_('Books located at') + ' ' + lp
|
||||
self.dataChanged.emit(self.index(0), self.index(0))
|
||||
|
||||
def rowCount(self, *args):
|
||||
return 1 + len([i for i in self.free if i >= 0])
|
||||
|
||||
def get_device_row(self, row):
|
||||
if row == 2 and self.free[1] == -1 and self.free[2] > -1:
|
||||
row = 3
|
||||
return row
|
||||
|
||||
def get_tooltip(self, row, drow):
|
||||
ans = self.tooltips[row]
|
||||
if row > 0:
|
||||
fs = self.free[drow-1]
|
||||
if fs > -1:
|
||||
ans += '\n\n%s '%(human_readable(fs)) + _('free')
|
||||
return ans
|
||||
|
||||
def data(self, index, role):
|
||||
row = index.row()
|
||||
drow = self.get_device_row(row)
|
||||
data = NONE
|
||||
if role == Qt.DisplayRole:
|
||||
text = self.text[drow]%(human_readable(self.free[drow-1])) if row > 0 \
|
||||
else self.text[drow]%self.count
|
||||
data = QVariant(text)
|
||||
elif role == Qt.DecorationRole:
|
||||
data = self.icons[drow]
|
||||
elif role in (Qt.ToolTipRole, Qt.StatusTipRole):
|
||||
ans = self.get_tooltip(row, drow)
|
||||
data = QVariant(ans)
|
||||
elif role == Qt.SizeHintRole:
|
||||
data = QVariant(QSize(155, 90))
|
||||
elif role == Qt.FontRole:
|
||||
font = QFont('monospace')
|
||||
font.setBold(row == self.highlight_row)
|
||||
data = QVariant(font)
|
||||
elif role == Qt.ForegroundRole and row == self.highlight_row:
|
||||
return QVariant(QApplication.palette().brush(
|
||||
QPalette.HighlightedText))
|
||||
elif role == Qt.BackgroundRole and row == self.highlight_row:
|
||||
return QVariant(QApplication.palette().brush(
|
||||
QPalette.Highlight))
|
||||
|
||||
return data
|
||||
|
||||
def device_connected(self, dev):
|
||||
self.icons[1] = QIcon(dev.icon)
|
||||
self.dataChanged.emit(self.index(1), self.index(1))
|
||||
|
||||
def headerData(self, section, orientation, role):
|
||||
return NONE
|
||||
|
||||
def update_devices(self, cp=(None, None), fs=[-1, -1, -1]):
|
||||
if cp is None:
|
||||
cp = (None, None)
|
||||
if isinstance(cp, (str, unicode)):
|
||||
cp = (cp, None)
|
||||
if len(fs) < 3:
|
||||
fs = list(fs) + [0]
|
||||
self.free[0] = fs[0]
|
||||
self.free[1] = fs[1]
|
||||
self.free[2] = fs[2]
|
||||
cpa, cpb = cp
|
||||
self.free[1] = fs[1] if fs[1] is not None and cpa is not None else -1
|
||||
self.free[2] = fs[2] if fs[2] is not None and cpb is not None else -1
|
||||
self.reset()
|
||||
self.devicesChanged.emit()
|
||||
|
||||
def location_changed(self, row):
|
||||
self.highlight_row = row
|
||||
self.dataChanged.emit(
|
||||
self.index(0), self.index(self.rowCount(QModelIndex())-1))
|
||||
|
||||
def location_for_row(self, row):
|
||||
if row == 0: return 'library'
|
||||
if row == 1: return 'main'
|
||||
if row == 3: return 'cardb'
|
||||
return 'carda' if self.free[1] > -1 else 'cardb'
|
||||
|
||||
# }}}
|
||||
|
||||
class LocationView(QListView):
|
||||
|
||||
unmount_device = pyqtSignal()
|
||||
location_selected = pyqtSignal(object)
|
||||
|
||||
def __init__(self, parent):
|
||||
QListView.__init__(self, parent)
|
||||
self.setModel(LocationModel(self))
|
||||
self.reset()
|
||||
self.currentChanged = self.current_changed
|
||||
|
||||
self.eject_button = EjectButton(self)
|
||||
self.eject_button.hide()
|
||||
|
||||
self.entered.connect(self.item_entered)
|
||||
self.viewportEntered.connect(self.viewport_entered)
|
||||
self.eject_button.clicked.connect(self.eject_clicked)
|
||||
self.model().devicesChanged.connect(self.eject_button.hide)
|
||||
self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding,
|
||||
QSizePolicy.Expanding))
|
||||
self.setMouseTracking(True)
|
||||
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
||||
self.setEditTriggers(self.NoEditTriggers)
|
||||
self.setTabKeyNavigation(True)
|
||||
self.setProperty("showDropIndicator", True)
|
||||
self.setSelectionMode(self.SingleSelection)
|
||||
self.setIconSize(QSize(40, 40))
|
||||
self.setMovement(self.Static)
|
||||
self.setFlow(self.LeftToRight)
|
||||
self.setGridSize(QSize(175, 90))
|
||||
self.setViewMode(self.ListMode)
|
||||
self.setWordWrap(True)
|
||||
self.setObjectName("location_view")
|
||||
self.setMaximumHeight(74)
|
||||
|
||||
def eject_clicked(self, *args):
|
||||
self.unmount_device.emit()
|
||||
|
||||
def count_changed(self, new_count):
|
||||
self.model().count = new_count
|
||||
self.model().reset()
|
||||
|
||||
def current_changed(self, current, previous):
|
||||
if current.isValid():
|
||||
i = current.row()
|
||||
location = self.model().location_for_row(i)
|
||||
self.location_selected.emit(location)
|
||||
self.model().location_changed(i)
|
||||
|
||||
def location_changed(self, row):
|
||||
if 0 <= row and row <= 3:
|
||||
self.model().location_changed(row)
|
||||
|
||||
def leaveEvent(self, event):
|
||||
self.unsetCursor()
|
||||
self.eject_button.hide()
|
||||
|
||||
def item_entered(self, location):
|
||||
self.setCursor(Qt.PointingHandCursor)
|
||||
self.eject_button.hide()
|
||||
|
||||
if location.row() == 1:
|
||||
rect = self.visualRect(location)
|
||||
|
||||
self.eject_button.resize(rect.height()/2, rect.height()/2)
|
||||
|
||||
x, y = rect.left(), rect.top()
|
||||
x = x + (rect.width() - self.eject_button.width() - 2)
|
||||
y += 6
|
||||
|
||||
self.eject_button.move(x, y)
|
||||
self.eject_button.show()
|
||||
|
||||
def viewport_entered(self):
|
||||
self.unsetCursor()
|
||||
self.eject_button.hide()
|
||||
|
||||
|
||||
class EjectButton(QAbstractButton):
|
||||
|
||||
def __init__(self, parent):
|
||||
QAbstractButton.__init__(self, parent)
|
||||
self.mouse_over = False
|
||||
|
||||
def enterEvent(self, event):
|
||||
self.mouse_over = True
|
||||
|
||||
def leaveEvent(self, event):
|
||||
self.mouse_over = False
|
||||
|
||||
def paintEvent(self, event):
|
||||
painter = QPainter(self)
|
||||
painter.setClipRect(event.rect())
|
||||
image = QPixmap(I('eject')).scaledToHeight(event.rect().height(),
|
||||
Qt.SmoothTransformation)
|
||||
|
||||
if not self.mouse_over:
|
||||
alpha_mask = QPixmap(image.width(), image.height())
|
||||
color = QColor(128, 128, 128)
|
||||
alpha_mask.fill(color)
|
||||
image.setAlphaChannel(alpha_mask)
|
||||
|
||||
painter.drawPixmap(0, 0, image)
|
||||
|
||||
|
||||
|
||||
|
||||
# }}}
|
||||
|
||||
class SearchBar(QWidget): # {{{
|
||||
|
||||
def __init__(self, parent):
|
||||
QWidget.__init__(self, parent)
|
||||
self._layout = l = QHBoxLayout()
|
||||
self.setLayout(self._layout)
|
||||
|
||||
self.restriction_label = QLabel(_("&Restrict to:"))
|
||||
l.addWidget(self.restriction_label)
|
||||
self.restriction_label.setSizePolicy(QSizePolicy.Minimum,
|
||||
QSizePolicy.Minimum)
|
||||
|
||||
x = QComboBox(self)
|
||||
x.setMaximumSize(QSize(150, 16777215))
|
||||
x.setObjectName("search_restriction")
|
||||
x.setToolTip(_("Books display will be restricted to those matching the selected saved search"))
|
||||
l.addWidget(x)
|
||||
parent.search_restriction = x
|
||||
|
||||
x = QLabel(self)
|
||||
x.setObjectName("search_count")
|
||||
l.addWidget(x)
|
||||
parent.search_count = x
|
||||
x.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
|
||||
|
||||
parent.advanced_search_button = x = QToolButton(self)
|
||||
x.setIcon(QIcon(I('search.svg')))
|
||||
l.addWidget(x)
|
||||
x.setToolTip(_("Advanced search"))
|
||||
|
||||
self.label = x = QLabel('&Search:')
|
||||
l.addWidget(self.label)
|
||||
x.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
|
||||
|
||||
x = parent.search = SearchBox2(self)
|
||||
x.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||
x.setObjectName("search")
|
||||
x.setToolTip(_("<p>Search the list of books by title, author, publisher, tags, comments, etc.<br><br>Words separated by spaces are ANDed"))
|
||||
l.addWidget(x)
|
||||
|
||||
x = parent.clear_button = QToolButton(self)
|
||||
x.setIcon(QIcon(I('clear_left.svg')))
|
||||
x.setObjectName("clear_button")
|
||||
l.addWidget(x)
|
||||
x.setToolTip(_("Reset Quick Search"))
|
||||
|
||||
x = parent.saved_search = SavedSearchBox(self)
|
||||
x.setMaximumSize(QSize(150, 16777215))
|
||||
x.setMinimumContentsLength(15)
|
||||
x.setObjectName("saved_search")
|
||||
l.addWidget(x)
|
||||
|
||||
x = parent.copy_search_button = QToolButton(self)
|
||||
x.setIcon(QIcon(I("search_copy_saved.svg")))
|
||||
x.setObjectName("copy_search_button")
|
||||
l.addWidget(x)
|
||||
x.setToolTip(_("Copy current search text (instead of search name)"))
|
||||
|
||||
x = parent.save_search_button = QToolButton(self)
|
||||
x.setIcon(QIcon(I("search_add_saved.svg")))
|
||||
x.setObjectName("save_search_button")
|
||||
l.addWidget(x)
|
||||
x.setToolTip(_("Save current search under the name shown in the box"))
|
||||
|
||||
x = parent.delete_search_button = QToolButton(self)
|
||||
x.setIcon(QIcon(I("search_delete_saved.svg")))
|
||||
x.setObjectName("delete_search_button")
|
||||
l.addWidget(x)
|
||||
x.setToolTip(_("Delete current saved search"))
|
||||
|
||||
self.label.setBuddy(parent.search)
|
||||
self.restriction_label.setBuddy(parent.search_restriction)
|
||||
|
||||
|
||||
# }}}
|
||||
|
||||
class LocationBar(ToolBar): # {{{
|
||||
|
||||
def __init__(self, actions, donate, location_view, parent=None):
|
||||
ToolBar.__init__(self, parent)
|
||||
|
||||
for ac in actions:
|
||||
self.addAction(ac)
|
||||
|
||||
self.addWidget(location_view)
|
||||
self.w = QWidget()
|
||||
self.w.setLayout(QVBoxLayout())
|
||||
self.w.layout().addWidget(donate)
|
||||
donate.setAutoRaise(True)
|
||||
donate.setCursor(Qt.PointingHandCursor)
|
||||
self.addWidget(self.w)
|
||||
self.setIconSize(QSize(50, 50))
|
||||
self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
|
||||
|
||||
def button_for_action(self, ac):
|
||||
b = QToolButton(self)
|
||||
b.setDefaultAction(ac)
|
||||
for x in ('ToolTip', 'StatusTip', 'WhatsThis'):
|
||||
getattr(b, 'set'+x)(b.text())
|
||||
|
||||
return b
|
||||
# }}}
|
||||
|
||||
class MainWindowMixin(object):
|
||||
|
||||
def __init__(self):
|
||||
self.setObjectName('MainWindow')
|
||||
self.setWindowIcon(QIcon(I('library.png')))
|
||||
self.setWindowTitle(__appname__)
|
||||
|
||||
self.setContextMenuPolicy(Qt.NoContextMenu)
|
||||
self.centralwidget = QWidget(self)
|
||||
self.setCentralWidget(self.centralwidget)
|
||||
self._central_widget_layout = QVBoxLayout()
|
||||
self.centralwidget.setLayout(self._central_widget_layout)
|
||||
self.resize(1012, 740)
|
||||
self.donate_button = ThrobbingButton(self.centralwidget)
|
||||
self.donate_button.set_normal_icon_size(64, 64)
|
||||
|
||||
# Actions {{{
|
||||
|
||||
def ac(name, text, icon, shortcut=None, tooltip=None):
|
||||
action = QAction(QIcon(I(icon)), text, self)
|
||||
text = tooltip if tooltip else text
|
||||
action.setToolTip(text)
|
||||
action.setStatusTip(text)
|
||||
action.setWhatsThis(text)
|
||||
action.setAutoRepeat(False)
|
||||
action.setObjectName('action_'+name)
|
||||
if shortcut:
|
||||
action.setShortcut(shortcut)
|
||||
setattr(self, 'action_'+name, action)
|
||||
|
||||
ac('add', _('Add books'), 'add_book.svg', _('A'))
|
||||
ac('del', _('Remove books'), 'trash.svg', _('Del'))
|
||||
ac('edit', _('Edit meta info'), 'edit_input.svg', _('E'))
|
||||
ac('merge', _('Merge book records'), 'merge_books.svg', _('M'))
|
||||
ac('sync', _('Send to device'), 'sync.svg')
|
||||
ac('save', _('Save to disk'), 'save.svg', _('S'))
|
||||
ac('news', _('Fetch news'), 'news.svg', _('F'))
|
||||
ac('convert', _('Convert books'), 'convert.svg', _('C'))
|
||||
ac('view', _('View'), 'view.svg', _('V'))
|
||||
ac('open_containing_folder', _('Open containing folder'),
|
||||
'document_open.svg')
|
||||
ac('show_book_details', _('Show book details'),
|
||||
'dialog_information.svg')
|
||||
ac('books_by_same_author', _('Books by same author'),
|
||||
'user_profile.svg')
|
||||
ac('books_in_this_series', _('Books in this series'),
|
||||
'books_in_series.svg')
|
||||
ac('books_by_this_publisher', _('Books by this publisher'),
|
||||
'publisher.png')
|
||||
ac('books_with_the_same_tags', _('Books with the same tags'),
|
||||
'tags.svg')
|
||||
ac('preferences', _('Preferences'), 'config.svg', _('Ctrl+P'))
|
||||
ac('help', _('Help'), 'help.svg', _('F1'), _("Browse the calibre User Manual"))
|
||||
|
||||
# }}}
|
||||
|
||||
self.tool_bar = ToolBar(self)
|
||||
self.addToolBar(Qt.BottomToolBarArea, self.tool_bar)
|
||||
self.tool_bar.add_actions(self.action_convert, self.action_view,
|
||||
None, self.action_edit, None,
|
||||
self.action_save, self.action_del,
|
||||
None,
|
||||
self.action_help, None, self.action_preferences)
|
||||
|
||||
self.location_view = LocationView(self.centralwidget)
|
||||
self.search_bar = SearchBar(self)
|
||||
self.location_bar = LocationBar([self.action_add, self.action_sync,
|
||||
self.action_news], self.donate_button, self.location_view, self)
|
||||
self.addToolBar(Qt.TopToolBarArea, self.location_bar)
|
||||
|
||||
l = self.centralwidget.layout()
|
||||
l.addWidget(self.search_bar)
|
||||
|
||||
for ch in list(self.tool_bar.children()) + list(self.location_bar.children()):
|
||||
if isinstance(ch, QToolButton):
|
||||
ch.setCursor(Qt.PointingHandCursor)
|
||||
ch.setAutoRaise(True)
|
||||
if ch is not self.donate_button:
|
||||
ch.setPopupMode(ch.MenuButtonPopup)
|
||||
|
||||
|
||||
|
@ -1,551 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<author>Kovid Goyal</author>
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1012</width>
|
||||
<height>822</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::NoContextMenu</enum>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>__appname__</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/library.png</normaloff>:/images/library.png</iconset>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="LocationView" name="location_view">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>75</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="mouseTracking">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAsNeeded</enum>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="tabKeyNavigation">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="showDropIndicator" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::NoSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="movement">
|
||||
<enum>QListView::Static</enum>
|
||||
</property>
|
||||
<property name="flow">
|
||||
<enum>QListView::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="gridSize">
|
||||
<size>
|
||||
<width>175</width>
|
||||
<height>90</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="viewMode">
|
||||
<enum>QListView::ListMode</enum>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ThrobbingButton" name="donate_button">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/donate.svg</normaloff>:/images/donate.svg</iconset>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="hl234">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="ComboBoxWithHelp" name="search_restriction">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Books display will be restricted to those matching the selected saved search</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="search_count">
|
||||
<property name="text">
|
||||
<string>set in ui.py</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="advanced_search_button">
|
||||
<property name="toolTip">
|
||||
<string>Advanced search</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/search.svg</normaloff>:/images/search.svg</iconset>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Alt+S</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>&Search:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>search</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="SearchBox2" name="search">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>700</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><p>Search the list of books by title, author, publisher, tags, comments, etc.<br><br>Words separated by spaces are ANDed</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string><p>Search the list of books by title, author, publisher, tags, comments, etc.<br><br>Words separated by spaces are ANDed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="clear_button">
|
||||
<property name="toolTip">
|
||||
<string>Reset Quick Search</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/clear_left.svg</normaloff>:/images/clear_left.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="SavedSearchBox" name="saved_search">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="minimumContentsLength">
|
||||
<number>15</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="copy_search_button">
|
||||
<property name="toolTip">
|
||||
<string>Copy current search text (instead of search name)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/search_copy_saved.svg</normaloff>:/images/search_copy_saved.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="save_search_button">
|
||||
<property name="toolTip">
|
||||
<string>Save current search under the name shown in the box</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/search_add_saved.svg</normaloff>:/images/search_add_saved.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="delete_search_button">
|
||||
<property name="toolTip">
|
||||
<string>Delete current saved search</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/search_delete_saved.svg</normaloff>:/images/search_delete_saved.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="tool_bar">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::PreventContextMenu</enum>
|
||||
</property>
|
||||
<property name="movable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>48</width>
|
||||
<height>48</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextUnderIcon</enum>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<addaction name="action_add"/>
|
||||
<addaction name="action_edit"/>
|
||||
<addaction name="action_convert"/>
|
||||
<addaction name="action_view"/>
|
||||
<addaction name="action_news"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_sync"/>
|
||||
<addaction name="action_save"/>
|
||||
<addaction name="action_del"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_help"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_preferences"/>
|
||||
</widget>
|
||||
<action name="action_add">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/add_book.svg</normaloff>:/images/add_book.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add books</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>A</string>
|
||||
</property>
|
||||
<property name="autoRepeat">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_del">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/trash.svg</normaloff>:/images/trash.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove books</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Remove books</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Del</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_edit">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/edit_input.svg</normaloff>:/images/edit_input.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Edit meta information</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>E</string>
|
||||
</property>
|
||||
<property name="autoRepeat">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_merge">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/merge_books.svg</normaloff>:/images/merge_books.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Merge book records</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>M</string>
|
||||
</property>
|
||||
<property name="autoRepeat">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_sync">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/sync.svg</normaloff>:/images/sync.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Send to device</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_save">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/save.svg</normaloff>:/images/save.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save to disk</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>S</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_news">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/news.svg</normaloff>:/images/news.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Fetch news</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_convert">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/convert.svg</normaloff>:/images/convert.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Convert E-books</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>C</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_view">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/view.svg</normaloff>:/images/view.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>View</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>V</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_open_containing_folder">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/document_open.svg</normaloff>:/images/document_open.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Open containing folder</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_show_book_details">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/dialog_information.svg</normaloff>:/images/dialog_information.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show book details</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_books_by_same_author">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/user_profile.svg</normaloff>:/images/user_profile.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Books by same author</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_books_in_this_series">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/books_in_series.svg</normaloff>:/images/books_in_series.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Books in this series</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_books_by_this_publisher">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/publisher.png</normaloff>:/images/publisher.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Books by this publisher</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_books_with_the_same_tags">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/tags.svg</normaloff>:/images/tags.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Books with the same tags</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_preferences">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/config.svg</normaloff>:/images/config.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Preferences</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Configure calibre</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+P</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_help">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../resources/images.qrc">
|
||||
<normaloff>:/images/help.svg</normaloff>:/images/help.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Help</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Browse the calibre User Manual</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F1</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LocationView</class>
|
||||
<extends>QListView</extends>
|
||||
<header>widgets.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>SearchBox2</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>calibre.gui2.search_box</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>SavedSearchBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>calibre.gui2.search_box</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ComboBoxWithHelp</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>calibre.gui2.widgets</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ThrobbingButton</class>
|
||||
<extends>QToolButton</extends>
|
||||
<header>calibre/gui2/throbber.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../../../resources/images.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
@ -31,7 +31,7 @@ from calibre.gui2.wizard import move_library
|
||||
from calibre.gui2.dialogs.scheduler import Scheduler
|
||||
from calibre.gui2.update import UpdateMixin
|
||||
from calibre.gui2.main_window import MainWindow
|
||||
from calibre.gui2.main_ui import Ui_MainWindow
|
||||
from calibre.gui2.layout import MainWindowMixin
|
||||
from calibre.gui2.device import DeviceMixin
|
||||
from calibre.gui2.jobs import JobManager, JobsDialog, JobsButton
|
||||
from calibre.gui2.dialogs.config import ConfigDialog
|
||||
@ -91,7 +91,7 @@ class SystemTrayIcon(QSystemTrayIcon): # {{{
|
||||
|
||||
# }}}
|
||||
|
||||
class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin, # {{{
|
||||
class Main(MainWindow, MainWindowMixin, DeviceMixin, ToolbarMixin, # {{{
|
||||
TagBrowserMixin, CoverFlowMixin, LibraryViewMixin, SearchBoxMixin,
|
||||
SavedSearchBoxMixin, SearchRestrictionMixin, LayoutMixin, UpdateMixin,
|
||||
AnnotationsAction, AddAction, DeleteAction,
|
||||
@ -120,7 +120,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin, # {{{
|
||||
self.another_instance_wants_to_talk)
|
||||
self.check_messages_timer.start(1000)
|
||||
|
||||
Ui_MainWindow.__init__(self)
|
||||
MainWindowMixin.__init__(self)
|
||||
|
||||
# Jobs Button {{{
|
||||
self.job_manager = JobManager()
|
||||
@ -281,7 +281,6 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin, # {{{
|
||||
|
||||
self.read_settings()
|
||||
self.finalize_layout()
|
||||
self.donate_button.set_normal_icon_size(64, 64)
|
||||
self.donate_button.start_animation()
|
||||
|
||||
def resizeEvent(self, ev):
|
||||
|
@ -5,26 +5,25 @@ Miscellaneous widgets used in the GUI
|
||||
'''
|
||||
import re, os, traceback
|
||||
|
||||
from PyQt4.Qt import QListView, QIcon, QFont, QLabel, QListWidget, \
|
||||
from PyQt4.Qt import QIcon, QFont, QLabel, QListWidget, \
|
||||
QListWidgetItem, QTextCharFormat, QApplication, \
|
||||
QSyntaxHighlighter, QCursor, QColor, QWidget, \
|
||||
QPixmap, QPalette, QSplitterHandle, QToolButton, \
|
||||
QPixmap, QSplitterHandle, QToolButton, \
|
||||
QAbstractListModel, QVariant, Qt, SIGNAL, pyqtSignal, \
|
||||
QRegExp, QSettings, QSize, QModelIndex, QSplitter, \
|
||||
QAbstractButton, QPainter, QLineEdit, QComboBox, \
|
||||
QRegExp, QSettings, QSize, QSplitter, \
|
||||
QPainter, QLineEdit, QComboBox, \
|
||||
QMenu, QStringListModel, QCompleter, QStringList, \
|
||||
QTimer, QRect
|
||||
|
||||
from calibre.gui2 import NONE, error_dialog, pixmap_to_data, gprefs
|
||||
|
||||
from calibre.gui2.filename_pattern_ui import Ui_Form
|
||||
from calibre import fit_image, human_readable
|
||||
from calibre import fit_image
|
||||
from calibre.utils.fonts import fontconfig
|
||||
from calibre.ebooks import BOOK_EXTENSIONS
|
||||
from calibre.ebooks.metadata.meta import metadata_from_filename
|
||||
from calibre.utils.config import prefs, XMLConfig
|
||||
from calibre.gui2.progress_indicator import ProgressIndicator as _ProgressIndicator
|
||||
from calibre.constants import filesystem_encoding
|
||||
|
||||
history = XMLConfig('history')
|
||||
|
||||
@ -259,198 +258,6 @@ class ImageView(QWidget):
|
||||
# }}}
|
||||
|
||||
|
||||
class LocationModel(QAbstractListModel):
|
||||
|
||||
def __init__(self, parent):
|
||||
QAbstractListModel.__init__(self, parent)
|
||||
self.icons = [QVariant(QIcon(I('library.png'))),
|
||||
QVariant(QIcon(I('reader.svg'))),
|
||||
QVariant(QIcon(I('sd.svg'))),
|
||||
QVariant(QIcon(I('sd.svg')))]
|
||||
self.text = [_('Library\n%d books'),
|
||||
_('Reader\n%s'),
|
||||
_('Card A\n%s'),
|
||||
_('Card B\n%s')]
|
||||
self.free = [-1, -1, -1]
|
||||
self.count = 0
|
||||
self.highlight_row = 0
|
||||
self.library_tooltip = _('Click to see the books available on your computer')
|
||||
self.tooltips = [
|
||||
self.library_tooltip,
|
||||
_('Click to see the books in the main memory of your reader'),
|
||||
_('Click to see the books on storage card A in your reader'),
|
||||
_('Click to see the books on storage card B in your reader')
|
||||
]
|
||||
|
||||
def database_changed(self, db):
|
||||
lp = db.library_path
|
||||
if not isinstance(lp, unicode):
|
||||
lp = lp.decode(filesystem_encoding, 'replace')
|
||||
self.tooltips[0] = self.library_tooltip + '\n\n' + \
|
||||
_('Books located at') + ' ' + lp
|
||||
self.dataChanged.emit(self.index(0), self.index(0))
|
||||
|
||||
def rowCount(self, *args):
|
||||
return 1 + len([i for i in self.free if i >= 0])
|
||||
|
||||
def get_device_row(self, row):
|
||||
if row == 2 and self.free[1] == -1 and self.free[2] > -1:
|
||||
row = 3
|
||||
return row
|
||||
|
||||
def get_tooltip(self, row, drow):
|
||||
ans = self.tooltips[row]
|
||||
if row > 0:
|
||||
fs = self.free[drow-1]
|
||||
if fs > -1:
|
||||
ans += '\n\n%s '%(human_readable(fs)) + _('free')
|
||||
return ans
|
||||
|
||||
def data(self, index, role):
|
||||
row = index.row()
|
||||
drow = self.get_device_row(row)
|
||||
data = NONE
|
||||
if role == Qt.DisplayRole:
|
||||
text = self.text[drow]%(human_readable(self.free[drow-1])) if row > 0 \
|
||||
else self.text[drow]%self.count
|
||||
data = QVariant(text)
|
||||
elif role == Qt.DecorationRole:
|
||||
data = self.icons[drow]
|
||||
elif role in (Qt.ToolTipRole, Qt.StatusTipRole):
|
||||
ans = self.get_tooltip(row, drow)
|
||||
data = QVariant(ans)
|
||||
elif role == Qt.SizeHintRole:
|
||||
data = QVariant(QSize(155, 90))
|
||||
elif role == Qt.FontRole:
|
||||
font = QFont('monospace')
|
||||
font.setBold(row == self.highlight_row)
|
||||
data = QVariant(font)
|
||||
elif role == Qt.ForegroundRole and row == self.highlight_row:
|
||||
return QVariant(QApplication.palette().brush(
|
||||
QPalette.HighlightedText))
|
||||
elif role == Qt.BackgroundRole and row == self.highlight_row:
|
||||
return QVariant(QApplication.palette().brush(
|
||||
QPalette.Highlight))
|
||||
|
||||
return data
|
||||
|
||||
def device_connected(self, dev):
|
||||
self.icons[1] = QIcon(dev.icon)
|
||||
self.dataChanged.emit(self.index(1), self.index(1))
|
||||
|
||||
def headerData(self, section, orientation, role):
|
||||
return NONE
|
||||
|
||||
def update_devices(self, cp=(None, None), fs=[-1, -1, -1]):
|
||||
if cp is None:
|
||||
cp = (None, None)
|
||||
if isinstance(cp, (str, unicode)):
|
||||
cp = (cp, None)
|
||||
if len(fs) < 3:
|
||||
fs = list(fs) + [0]
|
||||
self.free[0] = fs[0]
|
||||
self.free[1] = fs[1]
|
||||
self.free[2] = fs[2]
|
||||
cpa, cpb = cp
|
||||
self.free[1] = fs[1] if fs[1] is not None and cpa is not None else -1
|
||||
self.free[2] = fs[2] if fs[2] is not None and cpb is not None else -1
|
||||
self.reset()
|
||||
self.emit(SIGNAL('devicesChanged()'))
|
||||
|
||||
def location_changed(self, row):
|
||||
self.highlight_row = row
|
||||
self.emit(SIGNAL('dataChanged(QModelIndex,QModelIndex)'),
|
||||
self.index(0), self.index(self.rowCount(QModelIndex())-1))
|
||||
|
||||
def location_for_row(self, row):
|
||||
if row == 0: return 'library'
|
||||
if row == 1: return 'main'
|
||||
if row == 3: return 'cardb'
|
||||
return 'carda' if self.free[1] > -1 else 'cardb'
|
||||
|
||||
class LocationView(QListView):
|
||||
|
||||
def __init__(self, parent):
|
||||
QListView.__init__(self, parent)
|
||||
self.setModel(LocationModel(self))
|
||||
self.reset()
|
||||
self.currentChanged = self.current_changed
|
||||
|
||||
self.eject_button = EjectButton(self)
|
||||
self.eject_button.hide()
|
||||
|
||||
self.connect(self, SIGNAL('entered(QModelIndex)'), self.item_entered)
|
||||
self.connect(self, SIGNAL('viewportEntered()'), self.viewport_entered)
|
||||
self.connect(self.eject_button, SIGNAL('clicked()'), lambda: self.emit(SIGNAL('umount_device()')))
|
||||
self.connect(self.model(), SIGNAL('devicesChanged()'), self.eject_button.hide)
|
||||
|
||||
def count_changed(self, new_count):
|
||||
self.model().count = new_count
|
||||
self.model().reset()
|
||||
|
||||
def current_changed(self, current, previous):
|
||||
if current.isValid():
|
||||
i = current.row()
|
||||
location = self.model().location_for_row(i)
|
||||
self.emit(SIGNAL('location_selected(PyQt_PyObject)'), location)
|
||||
self.model().location_changed(i)
|
||||
|
||||
def location_changed(self, row):
|
||||
if 0 <= row and row <= 3:
|
||||
self.model().location_changed(row)
|
||||
|
||||
def leaveEvent(self, event):
|
||||
self.unsetCursor()
|
||||
self.eject_button.hide()
|
||||
|
||||
def item_entered(self, location):
|
||||
self.setCursor(Qt.PointingHandCursor)
|
||||
self.eject_button.hide()
|
||||
|
||||
if location.row() == 1:
|
||||
rect = self.visualRect(location)
|
||||
|
||||
self.eject_button.resize(rect.height()/2, rect.height()/2)
|
||||
|
||||
x, y = rect.left(), rect.top()
|
||||
x = x + (rect.width() - self.eject_button.width() - 2)
|
||||
y += 6
|
||||
|
||||
self.eject_button.move(x, y)
|
||||
self.eject_button.show()
|
||||
|
||||
def viewport_entered(self):
|
||||
self.unsetCursor()
|
||||
self.eject_button.hide()
|
||||
|
||||
|
||||
class EjectButton(QAbstractButton):
|
||||
|
||||
def __init__(self, parent):
|
||||
QAbstractButton.__init__(self, parent)
|
||||
self.mouse_over = False
|
||||
|
||||
def enterEvent(self, event):
|
||||
self.mouse_over = True
|
||||
|
||||
def leaveEvent(self, event):
|
||||
self.mouse_over = False
|
||||
|
||||
def paintEvent(self, event):
|
||||
painter = QPainter(self)
|
||||
painter.setClipRect(event.rect())
|
||||
image = QPixmap(I('eject')).scaledToHeight(event.rect().height(),
|
||||
Qt.SmoothTransformation)
|
||||
|
||||
if not self.mouse_over:
|
||||
alpha_mask = QPixmap(image.width(), image.height())
|
||||
color = QColor(128, 128, 128)
|
||||
alpha_mask.fill(color)
|
||||
image.setAlphaChannel(alpha_mask)
|
||||
|
||||
painter.drawPixmap(0, 0, image)
|
||||
|
||||
|
||||
|
||||
|
||||
class FontFamilyModel(QAbstractListModel):
|
||||
|
Loading…
x
Reference in New Issue
Block a user