mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Show the number of currently selected books in the status bar at the bottom of the book list
This commit is contained in:
parent
70340d8b7c
commit
2c12c1aa3d
@ -27,7 +27,7 @@ def partial(*args, **kwargs):
|
||||
_keep_refs.append(ans)
|
||||
return ans
|
||||
|
||||
class LibraryViewMixin(object): # {{{
|
||||
class LibraryViewMixin(object): # {{{
|
||||
|
||||
def __init__(self, db):
|
||||
self.library_view.files_dropped.connect(self.iactions['Add Books'].files_dropped, type=Qt.QueuedConnection)
|
||||
@ -100,7 +100,7 @@ class LibraryViewMixin(object): # {{{
|
||||
|
||||
# }}}
|
||||
|
||||
class LibraryWidget(Splitter): # {{{
|
||||
class LibraryWidget(Splitter): # {{{
|
||||
|
||||
def __init__(self, parent):
|
||||
orientation = Qt.Vertical
|
||||
@ -119,7 +119,7 @@ class LibraryWidget(Splitter): # {{{
|
||||
self.addWidget(parent.library_view)
|
||||
# }}}
|
||||
|
||||
class Stack(QStackedWidget): # {{{
|
||||
class Stack(QStackedWidget): # {{{
|
||||
|
||||
def __init__(self, parent):
|
||||
QStackedWidget.__init__(self, parent)
|
||||
@ -147,7 +147,7 @@ class Stack(QStackedWidget): # {{{
|
||||
|
||||
# }}}
|
||||
|
||||
class UpdateLabel(QLabel): # {{{
|
||||
class UpdateLabel(QLabel): # {{{
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
QLabel.__init__(self, *args, **kwargs)
|
||||
@ -157,22 +157,22 @@ class UpdateLabel(QLabel): # {{{
|
||||
pass
|
||||
# }}}
|
||||
|
||||
class StatusBar(QStatusBar): # {{{
|
||||
class StatusBar(QStatusBar): # {{{
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QStatusBar.__init__(self, parent)
|
||||
self.default_message = __appname__ + ' ' + _('version') + ' ' + \
|
||||
self.get_version() + ' ' + _('created by Kovid Goyal')
|
||||
self.device_string = ''
|
||||
self.update_label = UpdateLabel('')
|
||||
self.total = self.current = self.selected = 0
|
||||
self.addPermanentWidget(self.update_label)
|
||||
self.update_label.setVisible(False)
|
||||
self._font = QFont()
|
||||
self._font.setBold(True)
|
||||
self.setFont(self._font)
|
||||
self.defmsg = QLabel(self.default_message)
|
||||
self.defmsg = QLabel('')
|
||||
self.defmsg.setFont(self._font)
|
||||
self.addWidget(self.defmsg)
|
||||
self.set_label()
|
||||
|
||||
def initialize(self, systray=None):
|
||||
self.systray = systray
|
||||
@ -180,18 +180,42 @@ class StatusBar(QStatusBar): # {{{
|
||||
|
||||
def device_connected(self, devname):
|
||||
self.device_string = _('Connected ') + devname
|
||||
self.defmsg.setText(self.default_message + ' ..::.. ' +
|
||||
self.device_string)
|
||||
self.set_label()
|
||||
|
||||
def update_state(self, total, current, selected):
|
||||
self.total, self.current, self.selected = total, current, selected
|
||||
self.set_label()
|
||||
|
||||
def set_label(self):
|
||||
try:
|
||||
self._set_label()
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _set_label(self):
|
||||
msg = '%s %s %s' % (__appname__, _('version'), get_version())
|
||||
if self.device_string:
|
||||
msg += ' ..::.. ' + self.device_string
|
||||
else:
|
||||
msg += _(' %(created)s %(name)s') % dict(created=_('created by'), name='Kovid Goyal')
|
||||
|
||||
if self.total != self.current:
|
||||
base = _('%(num)d of %(total)d books') % dict(num=self.current, total=self.total)
|
||||
else:
|
||||
base = _('%d books') % self.total
|
||||
if self.selected > 0:
|
||||
base = _('%(num)s, %(sel)d selected') % dict(num=base, sel=self.selected)
|
||||
|
||||
self.defmsg.setText('%s [%s]' % (msg, base))
|
||||
self.clearMessage()
|
||||
|
||||
def device_disconnected(self):
|
||||
self.device_string = ''
|
||||
self.set_label()
|
||||
self.defmsg.setText(self.default_message)
|
||||
self.clearMessage()
|
||||
|
||||
def get_version(self):
|
||||
return get_version()
|
||||
|
||||
def show_message(self, msg, timeout=0):
|
||||
self.showMessage(msg, timeout)
|
||||
if self.notifier is not None and not config['disable_tray_notification']:
|
||||
@ -207,11 +231,11 @@ class StatusBar(QStatusBar): # {{{
|
||||
|
||||
# }}}
|
||||
|
||||
class LayoutMixin(object): # {{{
|
||||
class LayoutMixin(object): # {{{
|
||||
|
||||
def __init__(self):
|
||||
|
||||
if config['gui_layout'] == 'narrow': # narrow {{{
|
||||
if config['gui_layout'] == 'narrow': # narrow {{{
|
||||
self.book_details = BookDetails(False, self)
|
||||
self.stack = Stack(self)
|
||||
self.bd_splitter = Splitter('book_details_splitter',
|
||||
@ -224,7 +248,7 @@ class LayoutMixin(object): # {{{
|
||||
self.centralwidget.layout().addWidget(self.bd_splitter)
|
||||
button_order = ('tb', 'bd', 'cb')
|
||||
# }}}
|
||||
else: # wide {{{
|
||||
else: # wide {{{
|
||||
self.bd_splitter = Splitter('book_details_splitter',
|
||||
_('Book Details'), I('book.png'), initial_side_size=200,
|
||||
orientation=Qt.Horizontal, parent=self, side_index=1,
|
||||
@ -312,9 +336,15 @@ class LayoutMixin(object): # {{{
|
||||
|
||||
def read_layout_settings(self):
|
||||
# View states are restored automatically when set_database is called
|
||||
|
||||
for x in ('cb', 'tb', 'bd'):
|
||||
getattr(self, x+'_splitter').restore_state()
|
||||
|
||||
def update_status_bar(self, *args):
|
||||
v = self.current_view()
|
||||
selected = len(v.selectionModel().selectedRows())
|
||||
total, current = v.model().counts()
|
||||
self.status_bar.update_state(total, current, selected)
|
||||
|
||||
# }}}
|
||||
|
||||
|
||||
|
@ -6,7 +6,7 @@ __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import functools, re, os, traceback, errno, time
|
||||
from collections import defaultdict
|
||||
from collections import defaultdict, namedtuple
|
||||
|
||||
from PyQt4.Qt import (QAbstractTableModel, Qt, pyqtSignal, QIcon, QImage,
|
||||
QModelIndex, QVariant, QDateTime, QColor, QPixmap)
|
||||
@ -29,6 +29,8 @@ from calibre.gui2.library import DEFAULT_SORT
|
||||
from calibre.utils.localization import calibre_langcode_to_name
|
||||
from calibre.library.coloring import color_row_key
|
||||
|
||||
Counts = namedtuple('Counts', 'total current')
|
||||
|
||||
def human_readable(size, precision=1):
|
||||
""" Convert a size in bytes into megabytes """
|
||||
return ('%.'+str(precision)+'f') % ((size/(1024.*1024.)),)
|
||||
@ -46,7 +48,7 @@ def default_image():
|
||||
_default_image = QImage(I('default_cover.png'))
|
||||
return _default_image
|
||||
|
||||
class ColumnColor(object):
|
||||
class ColumnColor(object): # {{{
|
||||
|
||||
def __init__(self, formatter, colors):
|
||||
self.mi = None
|
||||
@ -70,9 +72,9 @@ class ColumnColor(object):
|
||||
return color
|
||||
except:
|
||||
pass
|
||||
# }}}
|
||||
|
||||
|
||||
class ColumnIcon(object):
|
||||
class ColumnIcon(object): # {{{
|
||||
|
||||
def __init__(self, formatter):
|
||||
self.mi = None
|
||||
@ -108,6 +110,7 @@ class ColumnIcon(object):
|
||||
return icon_bitmap
|
||||
except:
|
||||
pass
|
||||
# }}}
|
||||
|
||||
class BooksModel(QAbstractTableModel): # {{{
|
||||
|
||||
@ -281,6 +284,13 @@ class BooksModel(QAbstractTableModel): # {{{
|
||||
self._clear_caches()
|
||||
self.count_changed_signal.emit(self.db.count())
|
||||
|
||||
def counts(self):
|
||||
if self.db.data.search_restriction_applied():
|
||||
total = self.db.data.get_search_restriction_book_count()
|
||||
else:
|
||||
total = self.db.count()
|
||||
return Counts(total, self.count())
|
||||
|
||||
def row_indices(self, index):
|
||||
''' Return list indices of all cells in index.row()'''
|
||||
return [self.index(index.row(), c) for c in range(self.columnCount(None))]
|
||||
@ -1195,6 +1205,12 @@ class DeviceBooksModel(BooksModel): # {{{
|
||||
self.editable = ['title', 'authors', 'collections']
|
||||
self.book_in_library = None
|
||||
|
||||
def counts(self):
|
||||
return Counts(len(self.db), len(self.map))
|
||||
|
||||
def count_changed(self, *args):
|
||||
self.count_changed_signal.emit(len(self.db))
|
||||
|
||||
def mark_for_deletion(self, job, rows, rows_are_ids=False):
|
||||
db_indices = rows if rows_are_ids else self.indices(rows)
|
||||
db_items = [self.db[i] for i in db_indices if -1 < i < len(self.db)]
|
||||
@ -1234,11 +1250,13 @@ class DeviceBooksModel(BooksModel): # {{{
|
||||
if not succeeded:
|
||||
indices = self.row_indices(self.index(row, 0))
|
||||
self.dataChanged.emit(indices[0], indices[-1])
|
||||
self.count_changed()
|
||||
|
||||
def paths_deleted(self, paths):
|
||||
self.map = list(range(0, len(self.db)))
|
||||
self.resort(False)
|
||||
self.research(True)
|
||||
self.count_changed()
|
||||
|
||||
def is_row_marked_for_deletion(self, row):
|
||||
try:
|
||||
@ -1301,6 +1319,7 @@ class DeviceBooksModel(BooksModel): # {{{
|
||||
self.last_search = text
|
||||
if self.last_search:
|
||||
self.searched.emit(True)
|
||||
self.count_changed()
|
||||
|
||||
def research(self, reset=True):
|
||||
self.search(self.last_search, reset)
|
||||
@ -1370,6 +1389,7 @@ class DeviceBooksModel(BooksModel): # {{{
|
||||
self.map = list(range(0, len(db)))
|
||||
self.research(reset=False)
|
||||
self.resort()
|
||||
self.count_changed()
|
||||
|
||||
def cover(self, row):
|
||||
item = self.db[self.map[row]]
|
||||
|
@ -325,6 +325,11 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
|
||||
if self.library_view.model().rowCount(None) < 3:
|
||||
self.library_view.resizeColumnsToContents()
|
||||
|
||||
for view in ('library', 'memory', 'card_a', 'card_b'):
|
||||
v = getattr(self, '%s_view' % view)
|
||||
v.selectionModel().selectionChanged.connect(self.update_status_bar)
|
||||
v.model().count_changed_signal.connect(self.update_status_bar)
|
||||
|
||||
self.library_view.model().count_changed()
|
||||
self.bars_manager.database_changed(self.library_view.model().db)
|
||||
self.library_view.model().database_changed.connect(self.bars_manager.database_changed,
|
||||
@ -661,6 +666,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
|
||||
# Reset the view in case something changed while it was invisible
|
||||
self.current_view().reset()
|
||||
self.set_number_of_books_shown()
|
||||
self.update_status_bar()
|
||||
|
||||
def job_exception(self, job, dialog_title=_('Conversion Error')):
|
||||
if not hasattr(self, '_modeless_dialogs'):
|
||||
|
Loading…
x
Reference in New Issue
Block a user