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
74904c40af
@ -45,8 +45,13 @@ namespaces = {
|
|||||||
'dcterms': 'http://purl.org/dc/terms/'
|
'dcterms': 'http://purl.org/dc/terms/'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xpath_cache = {}
|
||||||
|
|
||||||
def XPath(expr):
|
def XPath(expr):
|
||||||
return X(expr, namespaces=namespaces)
|
ans = xpath_cache.get(expr, None)
|
||||||
|
if ans is None:
|
||||||
|
xpath_cache[expr] = ans = X(expr, namespaces=namespaces)
|
||||||
|
return ans
|
||||||
|
|
||||||
def is_tag(x, q):
|
def is_tag(x, q):
|
||||||
tag = getattr(x, 'tag', x)
|
tag = getattr(x, 'tag', x)
|
||||||
|
@ -10,9 +10,9 @@ from functools import partial
|
|||||||
from future_builtins import map
|
from future_builtins import map
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from PyQt4.Qt import (QTableView, Qt, QAbstractItemView, QMenu, pyqtSignal,
|
from PyQt4.Qt import (QTableView, Qt, QAbstractItemView, QMenu, pyqtSignal, QFont,
|
||||||
QModelIndex, QIcon, QItemSelection, QMimeData, QDrag, QApplication,
|
QModelIndex, QIcon, QItemSelection, QMimeData, QDrag, QApplication, QStyle,
|
||||||
QPoint, QPixmap, QUrl, QImage, QPainter, QColor, QRect)
|
QPoint, QPixmap, QUrl, QImage, QPainter, QColor, QRect, QHeaderView, QStyleOptionHeader)
|
||||||
|
|
||||||
from calibre.gui2.library.delegates import (RatingDelegate, PubDateDelegate,
|
from calibre.gui2.library.delegates import (RatingDelegate, PubDateDelegate,
|
||||||
TextDelegate, DateDelegate, CompleteDelegate, CcTextDelegate,
|
TextDelegate, DateDelegate, CompleteDelegate, CcTextDelegate,
|
||||||
@ -25,7 +25,54 @@ from calibre.gui2.library import DEFAULT_SORT
|
|||||||
from calibre.constants import filesystem_encoding
|
from calibre.constants import filesystem_encoding
|
||||||
from calibre import force_unicode
|
from calibre import force_unicode
|
||||||
|
|
||||||
class PreserveViewState(object): # {{{
|
class HeaderView(QHeaderView): # {{{
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
QHeaderView.__init__(self, *args)
|
||||||
|
self.hover = -1
|
||||||
|
self.current_font = QFont(self.font())
|
||||||
|
self.current_font.setBold(True)
|
||||||
|
|
||||||
|
def event(self, e):
|
||||||
|
if e.type() in (e.HoverMove, e.HoverEnter):
|
||||||
|
self.hover = self.logicalIndexAt(e.pos())
|
||||||
|
elif e.type() in (e.Leave, e.HoverLeave):
|
||||||
|
self.hover = -1
|
||||||
|
return QHeaderView.event(self, e)
|
||||||
|
|
||||||
|
def paintSection(self, painter, rect, logical_index):
|
||||||
|
opt = QStyleOptionHeader()
|
||||||
|
self.initStyleOption(opt)
|
||||||
|
opt.rect = rect
|
||||||
|
opt.section = logical_index
|
||||||
|
opt.orientation = self.orientation()
|
||||||
|
opt.textAlignment = Qt.AlignHCenter | Qt.AlignVCenter
|
||||||
|
model = self.parent().model()
|
||||||
|
opt.text = model.headerData(logical_index, opt.orientation, Qt.DisplayRole).toString()
|
||||||
|
if self.isSortIndicatorShown() and self.sortIndicatorSection() == logical_index:
|
||||||
|
opt.sortIndicator = QStyleOptionHeader.SortDown if self.sortIndicatorOrder() == Qt.AscendingOrder else QStyleOptionHeader.SortUp
|
||||||
|
opt.text = opt.fontMetrics.elidedText(opt.text, Qt.ElideRight, rect.width() - 4)
|
||||||
|
if self.isEnabled():
|
||||||
|
opt.state |= QStyle.State_Enabled
|
||||||
|
if self.window().isActiveWindow():
|
||||||
|
opt.state |= QStyle.State_Active
|
||||||
|
if self.hover == logical_index:
|
||||||
|
opt.state |= QStyle.State_MouseOver
|
||||||
|
sm = self.selectionModel()
|
||||||
|
if opt.orientation == Qt.Vertical:
|
||||||
|
if sm.isRowSelected(logical_index, QModelIndex()):
|
||||||
|
opt.state |= QStyle.State_Sunken
|
||||||
|
|
||||||
|
painter.save()
|
||||||
|
if (
|
||||||
|
(opt.orientation == Qt.Horizontal and sm.currentIndex().column() == logical_index) or
|
||||||
|
(opt.orientation == Qt.Vertical and sm.currentIndex().row() == logical_index)):
|
||||||
|
painter.setFont(self.current_font)
|
||||||
|
self.style().drawControl(QStyle.CE_Header, opt, painter, self)
|
||||||
|
painter.restore()
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
class PreserveViewState(object): # {{{
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Save the set of selected books at enter time. If at exit time there are no
|
Save the set of selected books at enter time. If at exit time there are no
|
||||||
@ -72,13 +119,14 @@ class PreserveViewState(object): # {{{
|
|||||||
return {x:getattr(self, x) for x in ('selected_ids', 'current_id',
|
return {x:getattr(self, x) for x in ('selected_ids', 'current_id',
|
||||||
'vscroll', 'hscroll')}
|
'vscroll', 'hscroll')}
|
||||||
def fset(self, state):
|
def fset(self, state):
|
||||||
for k, v in state.iteritems(): setattr(self, k, v)
|
for k, v in state.iteritems():
|
||||||
|
setattr(self, k, v)
|
||||||
self.__exit__()
|
self.__exit__()
|
||||||
return property(fget=fget, fset=fset)
|
return property(fget=fget, fset=fset)
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class BooksView(QTableView): # {{{
|
class BooksView(QTableView): # {{{
|
||||||
|
|
||||||
files_dropped = pyqtSignal(object)
|
files_dropped = pyqtSignal(object)
|
||||||
add_column_signal = pyqtSignal()
|
add_column_signal = pyqtSignal()
|
||||||
@ -152,12 +200,16 @@ class BooksView(QTableView): # {{{
|
|||||||
# {{{ Column Header setup
|
# {{{ Column Header setup
|
||||||
self.can_add_columns = True
|
self.can_add_columns = True
|
||||||
self.was_restored = False
|
self.was_restored = False
|
||||||
self.column_header = self.horizontalHeader()
|
self.column_header = HeaderView(Qt.Horizontal, self)
|
||||||
|
self.setHorizontalHeader(self.column_header)
|
||||||
self.column_header.setMovable(True)
|
self.column_header.setMovable(True)
|
||||||
|
self.column_header.setClickable(True)
|
||||||
self.column_header.sectionMoved.connect(self.save_state)
|
self.column_header.sectionMoved.connect(self.save_state)
|
||||||
self.column_header.setContextMenuPolicy(Qt.CustomContextMenu)
|
self.column_header.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||||
self.column_header.customContextMenuRequested.connect(self.show_column_header_context_menu)
|
self.column_header.customContextMenuRequested.connect(self.show_column_header_context_menu)
|
||||||
self.column_header.sectionResized.connect(self.column_resized, Qt.QueuedConnection)
|
self.column_header.sectionResized.connect(self.column_resized, Qt.QueuedConnection)
|
||||||
|
self.row_header = HeaderView(Qt.Vertical, self)
|
||||||
|
self.setVerticalHeader(self.row_header)
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
self._model.database_changed.connect(self.database_changed)
|
self._model.database_changed.connect(self.database_changed)
|
||||||
@ -242,7 +294,7 @@ class BooksView(QTableView): # {{{
|
|||||||
ac.setCheckable(True)
|
ac.setCheckable(True)
|
||||||
ac.setChecked(True)
|
ac.setChecked(True)
|
||||||
if col not in ('ondevice', 'inlibrary') and \
|
if col not in ('ondevice', 'inlibrary') and \
|
||||||
(not self.model().is_custom_column(col) or \
|
(not self.model().is_custom_column(col) or
|
||||||
self.model().custom_columns[col]['datatype'] not in ('bool',
|
self.model().custom_columns[col]['datatype'] not in ('bool',
|
||||||
)):
|
)):
|
||||||
m = self.column_header_context_menu.addMenu(
|
m = self.column_header_context_menu.addMenu(
|
||||||
@ -284,7 +336,6 @@ class BooksView(QTableView): # {{{
|
|||||||
partial(self.column_header_context_handler,
|
partial(self.column_header_context_handler,
|
||||||
action='show', column=col))
|
action='show', column=col))
|
||||||
|
|
||||||
|
|
||||||
self.column_header_context_menu.addSeparator()
|
self.column_header_context_menu.addSeparator()
|
||||||
self.column_header_context_menu.addAction(
|
self.column_header_context_menu.addAction(
|
||||||
_('Shrink column if it is too wide to fit'),
|
_('Shrink column if it is too wide to fit'),
|
||||||
@ -373,7 +424,7 @@ class BooksView(QTableView): # {{{
|
|||||||
h = self.column_header
|
h = self.column_header
|
||||||
cm = self.column_map
|
cm = self.column_map
|
||||||
state = {}
|
state = {}
|
||||||
state['hidden_columns'] = [cm[i] for i in range(h.count())
|
state['hidden_columns'] = [cm[i] for i in range(h.count())
|
||||||
if h.isSectionHidden(i) and cm[i] != 'ondevice']
|
if h.isSectionHidden(i) and cm[i] != 'ondevice']
|
||||||
state['last_modified_injected'] = True
|
state['last_modified_injected'] = True
|
||||||
state['languages_injected'] = True
|
state['languages_injected'] = True
|
||||||
@ -521,7 +572,6 @@ class BooksView(QTableView): # {{{
|
|||||||
db.prefs[name] = ans
|
db.prefs[name] = ans
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
def restore_state(self):
|
def restore_state(self):
|
||||||
old_state = self.get_old_state()
|
old_state = self.get_old_state()
|
||||||
if old_state is None:
|
if old_state is None:
|
||||||
@ -844,7 +894,8 @@ class BooksView(QTableView): # {{{
|
|||||||
ids = frozenset(ids)
|
ids = frozenset(ids)
|
||||||
m = self.model()
|
m = self.model()
|
||||||
for row in xrange(m.rowCount(QModelIndex())):
|
for row in xrange(m.rowCount(QModelIndex())):
|
||||||
if len(row_map) >= len(ids): break
|
if len(row_map) >= len(ids):
|
||||||
|
break
|
||||||
c = m.id(row)
|
c = m.id(row)
|
||||||
if c in ids:
|
if c in ids:
|
||||||
row_map[c] = row
|
row_map[c] = row
|
||||||
@ -904,7 +955,8 @@ class BooksView(QTableView): # {{{
|
|||||||
pass
|
pass
|
||||||
return None
|
return None
|
||||||
def fset(self, val):
|
def fset(self, val):
|
||||||
if val is None: return
|
if val is None:
|
||||||
|
return
|
||||||
m = self.model()
|
m = self.model()
|
||||||
for row in xrange(m.rowCount(QModelIndex())):
|
for row in xrange(m.rowCount(QModelIndex())):
|
||||||
if m.id(row) == val:
|
if m.id(row) == val:
|
||||||
@ -926,7 +978,8 @@ class BooksView(QTableView): # {{{
|
|||||||
column = ci.column()
|
column = ci.column()
|
||||||
|
|
||||||
for i in xrange(ci.row()+1, self.row_count()):
|
for i in xrange(ci.row()+1, self.row_count()):
|
||||||
if i in selected_rows: continue
|
if i in selected_rows:
|
||||||
|
continue
|
||||||
try:
|
try:
|
||||||
return self.model().id(self.model().index(i, column))
|
return self.model().id(self.model().index(i, column))
|
||||||
except:
|
except:
|
||||||
@ -934,7 +987,8 @@ class BooksView(QTableView): # {{{
|
|||||||
|
|
||||||
# No unselected rows after the current row, look before
|
# No unselected rows after the current row, look before
|
||||||
for i in xrange(ci.row()-1, -1, -1):
|
for i in xrange(ci.row()-1, -1, -1):
|
||||||
if i in selected_rows: continue
|
if i in selected_rows:
|
||||||
|
continue
|
||||||
try:
|
try:
|
||||||
return self.model().id(self.model().index(i, column))
|
return self.model().id(self.model().index(i, column))
|
||||||
except:
|
except:
|
||||||
@ -982,7 +1036,7 @@ class BooksView(QTableView): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class DeviceBooksView(BooksView): # {{{
|
class DeviceBooksView(BooksView): # {{{
|
||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
BooksView.__init__(self, parent, DeviceBooksModel,
|
BooksView.__init__(self, parent, DeviceBooksModel,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user