Start to move column display logic into the view classes, where it belongs

This commit is contained in:
Kovid Goyal 2010-05-17 16:04:30 -06:00
parent ce023e2c56
commit d393b430bd
2 changed files with 77 additions and 96 deletions

View File

@ -19,7 +19,7 @@ from PyQt4.QtCore import QAbstractTableModel, QVariant, Qt, pyqtSignal, \
from calibre import strftime from calibre import strftime
from calibre.ebooks.metadata import fmt_sidx, authors_to_string, string_to_authors from calibre.ebooks.metadata import fmt_sidx, authors_to_string, string_to_authors
from calibre.ebooks.metadata.meta import set_metadata as _set_metadata from calibre.ebooks.metadata.meta import set_metadata as _set_metadata
from calibre.gui2 import NONE, TableView, config, error_dialog, UNDEFINED_QDATE from calibre.gui2 import NONE, config, error_dialog, UNDEFINED_QDATE
from calibre.gui2.dialogs.comments_dialog import CommentsDialog from calibre.gui2.dialogs.comments_dialog import CommentsDialog
from calibre.gui2.widgets import EnLineEdit, TagsLineEdit from calibre.gui2.widgets import EnLineEdit, TagsLineEdit
from calibre.library.caches import _match, CONTAINS_MATCH, EQUALS_MATCH, REGEXP_MATCH from calibre.library.caches import _match, CONTAINS_MATCH, EQUALS_MATCH, REGEXP_MATCH
@ -30,6 +30,15 @@ from calibre.utils.pyparsing import ParseException
from calibre.utils.search_query_parser import SearchQueryParser from calibre.utils.search_query_parser import SearchQueryParser
# Delegates {{{ # Delegates {{{
class DummyDelegate(QStyledItemDelegate):
def sizeHint(self, option, index):
return QSize(0, 0)
def paint(self, painter, option, index):
pass
class RatingDelegate(QStyledItemDelegate): class RatingDelegate(QStyledItemDelegate):
COLOR = QColor("blue") COLOR = QColor("blue")
SIZE = 16 SIZE = 16
@ -313,6 +322,7 @@ class BooksModel(QAbstractTableModel): # {{{
orig_headers = { orig_headers = {
'title' : _("Title"), 'title' : _("Title"),
'ondevice' : _("On Device"),
'authors' : _("Author(s)"), 'authors' : _("Author(s)"),
'size' : _("Size (MB)"), 'size' : _("Size (MB)"),
'timestamp' : _("Date"), 'timestamp' : _("Date"),
@ -321,7 +331,6 @@ class BooksModel(QAbstractTableModel): # {{{
'publisher' : _("Publisher"), 'publisher' : _("Publisher"),
'tags' : _("Tags"), 'tags' : _("Tags"),
'series' : _("Series"), 'series' : _("Series"),
'ondevice' : _("On Device"),
} }
def __init__(self, parent=None, buffer=40): def __init__(self, parent=None, buffer=40):
@ -342,6 +351,7 @@ class BooksModel(QAbstractTableModel): # {{{
self.bool_no_icon = QIcon(I('list_remove.svg')) self.bool_no_icon = QIcon(I('list_remove.svg'))
self.bool_blank_icon = QIcon(I('blank.svg')) self.bool_blank_icon = QIcon(I('blank.svg'))
self.device_connected = False self.device_connected = False
self.read_config()
def is_custom_column(self, cc_label): def is_custom_column(self, cc_label):
return cc_label in self.custom_columns return cc_label in self.custom_columns
@ -352,29 +362,10 @@ class BooksModel(QAbstractTableModel): # {{{
def read_config(self): def read_config(self):
self.use_roman_numbers = config['use_roman_numerals_for_series_number'] self.use_roman_numbers = config['use_roman_numerals_for_series_number']
cmap = config['column_map'][:] # force a copy
self.headers = {}
self.column_map = []
for col in cmap: # take out any columns no longer in the db
if col == 'ondevice':
if self.device_connected:
self.column_map.append(col)
elif col in self.orig_headers or col in self.custom_columns:
self.column_map.append(col)
for col in self.column_map:
if col in self.orig_headers:
self.headers[col] = self.orig_headers[col]
elif col in self.custom_columns:
self.headers[col] = self.custom_columns[col]['name']
self.build_data_convertors()
self.reset()
self.emit(SIGNAL('columns_sorted()'))
def set_device_connected(self, is_connected): def set_device_connected(self, is_connected):
self.device_connected = is_connected self.device_connected = is_connected
self.read_config()
self.db.refresh_ondevice() self.db.refresh_ondevice()
self.database_changed.emit(self.db)
def set_book_on_device_func(self, func): def set_book_on_device_func(self, func):
self.book_on_device = func self.book_on_device = func
@ -382,7 +373,24 @@ class BooksModel(QAbstractTableModel): # {{{
def set_database(self, db): def set_database(self, db):
self.db = db self.db = db
self.custom_columns = self.db.custom_column_label_map self.custom_columns = self.db.custom_column_label_map
self.read_config() self.column_map = list(self.orig_headers.keys()) + \
list(self.custom_columns)
def col_idx(name):
if name == 'ondevice':
return -1
if name not in self.db.FIELD_MAP:
return 100000
return self.db.FIELD_MAP[name]
self.column_map.sort(cmp=lambda x,y: cmp(col_idx(x), col_idx(y)))
for col in self.column_map:
if col in self.orig_headers:
self.headers[col] = self.orig_headers[col]
elif col in self.custom_columns:
self.headers[col] = self.custom_columns[col]['name']
self.build_data_convertors()
self.reset()
self.database_changed.emit(db) self.database_changed.emit(db)
def refresh_ids(self, ids, current_row=-1): def refresh_ids(self, ids, current_row=-1):
@ -982,7 +990,7 @@ class BooksModel(QAbstractTableModel): # {{{
# }}} # }}}
class BooksView(TableView): class BooksView(QTableView): # {{{
TIME_FMT = '%d %b %Y' TIME_FMT = '%d %b %Y'
wrapper = textwrap.TextWrapper(width=20) wrapper = textwrap.TextWrapper(width=20)
@ -997,7 +1005,7 @@ class BooksView(TableView):
return ('%.'+str(precision)+'f') % ((size/(1024.*1024.)),) return ('%.'+str(precision)+'f') % ((size/(1024.*1024.)),)
def __init__(self, parent, modelcls=BooksModel): def __init__(self, parent, modelcls=BooksModel):
TableView.__init__(self, parent) QTableView.__init__(self, parent)
self.rating_delegate = RatingDelegate(self) self.rating_delegate = RatingDelegate(self)
self.timestamp_delegate = DateDelegate(self) self.timestamp_delegate = DateDelegate(self)
self.pubdate_delegate = PubDateDelegate(self) self.pubdate_delegate = PubDateDelegate(self)
@ -1005,6 +1013,7 @@ class BooksView(TableView):
self.authors_delegate = TextDelegate(self) self.authors_delegate = TextDelegate(self)
self.series_delegate = TextDelegate(self) self.series_delegate = TextDelegate(self)
self.publisher_delegate = TextDelegate(self) self.publisher_delegate = TextDelegate(self)
self.text_delegate = TextDelegate(self)
self.cc_text_delegate = CcTextDelegate(self) self.cc_text_delegate = CcTextDelegate(self)
self.cc_bool_delegate = CcBoolDelegate(self) self.cc_bool_delegate = CcBoolDelegate(self)
self.cc_comments_delegate = CcCommentsDelegate(self) self.cc_comments_delegate = CcCommentsDelegate(self)
@ -1013,13 +1022,9 @@ class BooksView(TableView):
self.setModel(self._model) self.setModel(self._model)
self.setSelectionBehavior(QAbstractItemView.SelectRows) self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.setSortingEnabled(True) self.setSortingEnabled(True)
for i in range(10): self.selectionModel().currentRowChanged.connect(self._model.current_changed)
self.setItemDelegateForColumn(i, TextDelegate(self)) self.column_header = self.horizontalHeader()
self.columns_sorted() self._model.database_changed.connect(self.database_changed)
QObject.connect(self.selectionModel(), SIGNAL('currentRowChanged(QModelIndex, QModelIndex)'),
self._model.current_changed)
self.connect(self._model, SIGNAL('columns_sorted()'),
self.columns_sorted, Qt.QueuedConnection)
hv = self.verticalHeader() hv = self.verticalHeader()
hv.setClickable(True) hv.setClickable(True)
hv.setCursor(Qt.PointingHandCursor) hv.setCursor(Qt.PointingHandCursor)
@ -1040,56 +1045,49 @@ class BooksView(TableView):
sm.select(idx, sm.Select|sm.Rows) sm.select(idx, sm.Select|sm.Rows)
self.selected_ids = [] self.selected_ids = []
def columns_sorted(self): def set_ondevice_column_visibility(self):
m = self._model
self.column_header.setSectionHidden(m.column_map.index('ondevice'),
not m.device_connected)
def set_device_connected(self, is_connected):
self._model.set_device_connected(is_connected)
self.set_ondevice_column_visibility()
def database_changed(self, db):
for i in range(self.model().columnCount(None)): for i in range(self.model().columnCount(None)):
if self.itemDelegateForColumn(i) in (self.rating_delegate, if self.itemDelegateForColumn(i) in (self.rating_delegate,
self.timestamp_delegate, self.pubdate_delegate): self.timestamp_delegate, self.pubdate_delegate):
self.setItemDelegateForColumn(i, self.itemDelegate()) self.setItemDelegateForColumn(i, self.itemDelegate())
cm = self._model.column_map cm = self._model.column_map
self.set_ondevice_column_visibility()
if 'rating' in cm:
self.setItemDelegateForColumn(cm.index('rating'), self.rating_delegate)
if 'timestamp' in cm:
self.setItemDelegateForColumn(cm.index('timestamp'), self.timestamp_delegate)
if 'pubdate' in cm:
self.setItemDelegateForColumn(cm.index('pubdate'), self.pubdate_delegate)
if 'tags' in cm:
self.setItemDelegateForColumn(cm.index('tags'), self.tags_delegate)
if 'authors' in cm:
self.setItemDelegateForColumn(cm.index('authors'), self.authors_delegate)
if 'publisher' in cm:
self.setItemDelegateForColumn(cm.index('publisher'), self.publisher_delegate)
if 'series' in cm:
self.setItemDelegateForColumn(cm.index('series'), self.series_delegate)
for colhead in cm: for colhead in cm:
if not self._model.is_custom_column(colhead): if self._model.is_custom_column(colhead):
continue cc = self._model.custom_columns[colhead]
cc = self._model.custom_columns[colhead] if cc['datatype'] == 'datetime':
if cc['datatype'] == 'datetime': delegate = CcDateDelegate(self)
delegate = CcDateDelegate(self) delegate.set_format(cc['display'].get('date_format',''))
delegate.set_format(cc['display'].get('date_format','')) self.setItemDelegateForColumn(cm.index(colhead), delegate)
self.setItemDelegateForColumn(cm.index(colhead), delegate) elif cc['datatype'] == 'comments':
elif cc['datatype'] == 'comments': self.setItemDelegateForColumn(cm.index(colhead), self.cc_comments_delegate)
self.setItemDelegateForColumn(cm.index(colhead), self.cc_comments_delegate) elif cc['datatype'] == 'text':
elif cc['datatype'] == 'text': if cc['is_multiple']:
if cc['is_multiple']: self.setItemDelegateForColumn(cm.index(colhead), self.tags_delegate)
self.setItemDelegateForColumn(cm.index(colhead), self.tags_delegate) else:
else: self.setItemDelegateForColumn(cm.index(colhead), self.cc_text_delegate)
elif cc['datatype'] in ('int', 'float'):
self.setItemDelegateForColumn(cm.index(colhead), self.cc_text_delegate) self.setItemDelegateForColumn(cm.index(colhead), self.cc_text_delegate)
elif cc['datatype'] in ('int', 'float'): elif cc['datatype'] == 'bool':
self.setItemDelegateForColumn(cm.index(colhead), self.cc_text_delegate) self.setItemDelegateForColumn(cm.index(colhead), self.cc_bool_delegate)
elif cc['datatype'] == 'bool': elif cc['datatype'] == 'rating':
self.setItemDelegateForColumn(cm.index(colhead), self.cc_bool_delegate) self.setItemDelegateForColumn(cm.index(colhead), self.rating_delegate)
elif cc['datatype'] == 'rating': else:
self.setItemDelegateForColumn(cm.index(colhead), self.rating_delegate) dattr = colhead+'_delegate'
if not self.restore_column_widths(): delegate = colhead if hasattr(self, dattr) else 'text'
self.resizeColumnsToContents() self.setItemDelegateForColumn(cm.index(colhead), getattr(self,
delegate+'_delegate'))
sort_col = self._model.sorted_on[0]
if sort_col in cm:
idx = cm.index(sort_col)
self.horizontalHeader().setSortIndicator(idx, self._model.sorted_on[1])
def set_context_menu(self, edit_metadata, send_to_device, convert, view, def set_context_menu(self, edit_metadata, send_to_device, convert, view,
save, open_folder, book_details, delete, similar_menu=None): save, open_folder, book_details, delete, similar_menu=None):
@ -1131,7 +1129,7 @@ class BooksView(TableView):
idx = self._model.column_map.index(colname) idx = self._model.column_map.index(colname)
except ValueError: except ValueError:
idx = 0 idx = 0
TableView.sortByColumn(self, idx, order) QTableView.sortByColumn(self, idx, order)
@classmethod @classmethod
def paths_from_event(cls, event): def paths_from_event(cls, event):
@ -1195,6 +1193,8 @@ class BooksView(TableView):
def row_count(self): def row_count(self):
return self._model.count() return self._model.count()
# }}}
class DeviceBooksView(BooksView): class DeviceBooksView(BooksView):
def __init__(self, parent): def __init__(self, parent):
@ -1218,7 +1218,7 @@ class DeviceBooksView(BooksView):
QObject.connect(self._model, SIGNAL('booklist_dirtied()'), slot) QObject.connect(self._model, SIGNAL('booklist_dirtied()'), slot)
def sortByColumn(self, col, order): def sortByColumn(self, col, order):
TableView.sortByColumn(self, col, order) QTableView.sortByColumn(self, col, order)
def dropEvent(self, *args): def dropEvent(self, *args):
error_dialog(self, _('Not allowed'), error_dialog(self, _('Not allowed'),

View File

@ -535,8 +535,6 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.library_view.model().set_book_on_device_func(self.book_on_device) self.library_view.model().set_book_on_device_func(self.book_on_device)
prefs['library_path'] = self.library_path prefs['library_path'] = self.library_path
self.library_view.restore_sort_at_startup(dynamic.get('sort_history', [('timestamp', Qt.DescendingOrder)])) self.library_view.restore_sort_at_startup(dynamic.get('sort_history', [('timestamp', Qt.DescendingOrder)]))
if not self.library_view.restore_column_widths():
self.library_view.resizeColumnsToContents()
self.search.setFocus(Qt.OtherFocusReason) self.search.setFocus(Qt.OtherFocusReason)
self.cover_cache = CoverCache(self.library_path) self.cover_cache = CoverCache(self.library_path)
self.cover_cache.start() self.cover_cache.start()
@ -943,7 +941,8 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
def save_device_view_settings(self): def save_device_view_settings(self):
model = self.location_view.model() model = self.location_view.model()
self.memory_view.write_settings() return
#self.memory_view.write_settings()
for x in range(model.rowCount()): for x in range(model.rowCount()):
if x > 1: if x > 1:
if model.location_for_row(x) == 'carda': if model.location_for_row(x) == 'carda':
@ -1030,10 +1029,6 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.card_b_view.set_editable(self.device_manager.device.CAN_SET_METADATA) self.card_b_view.set_editable(self.device_manager.device.CAN_SET_METADATA)
for view in (self.memory_view, self.card_a_view, self.card_b_view): for view in (self.memory_view, self.card_a_view, self.card_b_view):
view.sortByColumn(3, Qt.DescendingOrder) view.sortByColumn(3, Qt.DescendingOrder)
view.read_settings()
if not view.restore_column_widths():
view.resizeColumnsToContents()
view.resize_on_select = not view.isVisible()
if view.model().rowCount(None) > 1: if view.model().rowCount(None) > 1:
view.resizeRowToContents(0) view.resizeRowToContents(0)
height = view.rowHeight(0) height = view.rowHeight(0)
@ -1048,8 +1043,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.book_on_device(None, reset=True) self.book_on_device(None, reset=True)
if reset_only: if reset_only:
return return
self.library_view.write_settings() self.library_view.set_device_connected(device_connected)
self.library_view.model().set_device_connected(device_connected)
############################################################################ ############################################################################
######################### Fetch annotations ################################ ######################### Fetch annotations ################################
@ -2262,8 +2256,6 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
return return
d = ConfigDialog(self, self.library_view.model(), d = ConfigDialog(self, self.library_view.model(),
server=self.content_server) server=self.content_server)
# Save current column widths in case columns are turned on or off
self.library_view.write_settings()
d.exec_() d.exec_()
self.content_server = d.server self.content_server = d.server
@ -2328,14 +2320,6 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
''' '''
page = 0 if location == 'library' else 1 if location == 'main' else 2 if location == 'carda' else 3 page = 0 if location == 'library' else 1 if location == 'main' else 2 if location == 'carda' else 3
self.stack.setCurrentIndex(page) self.stack.setCurrentIndex(page)
view = self.memory_view if page == 1 else \
self.card_a_view if page == 2 else \
self.card_b_view if page == 3 else None
if view:
if view.resize_on_select:
if not view.restore_column_widths():
view.resizeColumnsToContents()
view.resize_on_select = False
self.status_bar.reset_info() self.status_bar.reset_info()
self.sidebar.location_changed(location) self.sidebar.location_changed(location)
if location == 'library': if location == 'library':
@ -2442,9 +2426,6 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
config.set('main_window_geometry', self.saveGeometry()) config.set('main_window_geometry', self.saveGeometry())
dynamic.set('sort_history', self.library_view.model().sort_history) dynamic.set('sort_history', self.library_view.model().sort_history)
self.sidebar.save_state() self.sidebar.save_state()
self.library_view.write_settings()
if self.device_connected:
self.save_device_view_settings()
def restart(self): def restart(self):
self.quit(restart=True) self.quit(restart=True)