mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Add an option to expand the tag browser tree to show the item that was current when the library was closed. The implementation provides an API for plugins to get and set the expansion state.
See https://www.mobileread.com/forums/showthread.php?t=362240
This commit is contained in:
parent
16a5a9abff
commit
2ac8fcb927
@ -411,6 +411,7 @@ def create_defs():
|
|||||||
defs['tag_browser_old_look'] = False
|
defs['tag_browser_old_look'] = False
|
||||||
defs['tag_browser_hide_empty_categories'] = False
|
defs['tag_browser_hide_empty_categories'] = False
|
||||||
defs['tag_browser_always_autocollapse'] = False
|
defs['tag_browser_always_autocollapse'] = False
|
||||||
|
defs['tag_browser_restore_tree_expansion'] = False
|
||||||
defs['tag_browser_allow_keyboard_focus'] = False
|
defs['tag_browser_allow_keyboard_focus'] = False
|
||||||
defs['book_list_tooltips'] = True
|
defs['book_list_tooltips'] = True
|
||||||
defs['show_layout_buttons'] = False
|
defs['show_layout_buttons'] = False
|
||||||
|
@ -636,6 +636,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
|||||||
r('tag_browser_old_look', gprefs)
|
r('tag_browser_old_look', gprefs)
|
||||||
r('tag_browser_hide_empty_categories', gprefs)
|
r('tag_browser_hide_empty_categories', gprefs)
|
||||||
r('tag_browser_always_autocollapse', gprefs)
|
r('tag_browser_always_autocollapse', gprefs)
|
||||||
|
r('tag_browser_restore_tree_expansion', gprefs)
|
||||||
r('tag_browser_show_tooltips', gprefs)
|
r('tag_browser_show_tooltips', gprefs)
|
||||||
r('tag_browser_allow_keyboard_focus', gprefs)
|
r('tag_browser_allow_keyboard_focus', gprefs)
|
||||||
r('bd_show_cover', gprefs)
|
r('bd_show_cover', gprefs)
|
||||||
|
@ -1426,6 +1426,18 @@ also checked then only categories containing a matched item will be shown.</p
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QCheckBox" name="opt_tag_browser_restore_tree_expansion">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><p>When checked, when a library is opened the Tag browser
|
||||||
|
will expand the tree so that the last used item is visible. An item is "used" when
|
||||||
|
it is expanded, collapsed, or clicked.</p></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Expand tr&ee to show last used item</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="8" column="0" colspan="3">
|
<item row="8" column="0" colspan="3">
|
||||||
|
@ -947,8 +947,26 @@ class TagBrowserWidget(QFrame): # {{{
|
|||||||
self.tags_view.model().prefs['tag_browser_hide_empty_categories'] ^= True
|
self.tags_view.model().prefs['tag_browser_hide_empty_categories'] ^= True
|
||||||
self.tags_view.recount_with_position_based_index()
|
self.tags_view.recount_with_position_based_index()
|
||||||
|
|
||||||
def save_state(self):
|
def save_state(self, gprefs_local=None):
|
||||||
gprefs.set('tag browser search box visible', self.toggle_search_button.isChecked())
|
if gprefs_local is None:
|
||||||
|
gprefs_local = gprefs
|
||||||
|
gprefs_local.set('tag browser search box visible', self.toggle_search_button.isChecked())
|
||||||
|
|
||||||
|
def restore_expansion_state(self, state):
|
||||||
|
'''
|
||||||
|
Expands the tag browser tree so that the node specified in state is
|
||||||
|
visible. Use get_expansion_state() to get the state. The intent is that
|
||||||
|
a plugin could restore the state in the library_changed() method.
|
||||||
|
'''
|
||||||
|
if state is not None:
|
||||||
|
self.tags_view.restore_expansion(state)
|
||||||
|
|
||||||
|
def get_expansion_state(self):
|
||||||
|
'''
|
||||||
|
Returns the currently expanded node in the tag browser as a string
|
||||||
|
suitable for restoring using restore_expansion_state.
|
||||||
|
'''
|
||||||
|
return self.tags_view.current_expansion
|
||||||
|
|
||||||
def toggle_item(self):
|
def toggle_item(self):
|
||||||
self.tags_view.toggle_current_index()
|
self.tags_view.toggle_current_index()
|
||||||
|
@ -289,6 +289,7 @@ class TagsView(QTreeView): # {{{
|
|||||||
self.setDropIndicatorShown(True)
|
self.setDropIndicatorShown(True)
|
||||||
self.setAutoExpandDelay(500)
|
self.setAutoExpandDelay(500)
|
||||||
self.pane_is_visible = False
|
self.pane_is_visible = False
|
||||||
|
self.current_expansion = None
|
||||||
self.search_icon = QIcon.ic('search.png')
|
self.search_icon = QIcon.ic('search.png')
|
||||||
self.search_copy_icon = QIcon.ic("search_copy_saved.png")
|
self.search_copy_icon = QIcon.ic("search_copy_saved.png")
|
||||||
self.user_category_icon = QIcon.ic('tb_folder.png')
|
self.user_category_icon = QIcon.ic('tb_folder.png')
|
||||||
@ -426,6 +427,7 @@ class TagsView(QTreeView): # {{{
|
|||||||
self.refresh_signal_processed = True
|
self.refresh_signal_processed = True
|
||||||
db.add_listener(self.database_changed)
|
db.add_listener(self.database_changed)
|
||||||
self.expanded.connect(self.item_expanded)
|
self.expanded.connect(self.item_expanded)
|
||||||
|
self.collapsed.connect(self.item_collapsed)
|
||||||
self.collapsed.connect(self.collapse_node_and_children)
|
self.collapsed.connect(self.collapse_node_and_children)
|
||||||
db.data.add_marked_listener(self.marked_change_listener)
|
db.data.add_marked_listener(self.marked_change_listener)
|
||||||
|
|
||||||
@ -1434,6 +1436,7 @@ class TagsView(QTreeView): # {{{
|
|||||||
ci = self.currentIndex()
|
ci = self.currentIndex()
|
||||||
if not ci.isValid():
|
if not ci.isValid():
|
||||||
ci = self.indexAt(QPoint(10, 10))
|
ci = self.indexAt(QPoint(10, 10))
|
||||||
|
item_is_expanded = True if ci.isValid() and self.isExpanded(ci) else False
|
||||||
use_pos = self._model.use_position_based_index_on_next_recount
|
use_pos = self._model.use_position_based_index_on_next_recount
|
||||||
self._model.use_position_based_index_on_next_recount = False
|
self._model.use_position_based_index_on_next_recount = False
|
||||||
if use_pos:
|
if use_pos:
|
||||||
@ -1454,6 +1457,10 @@ class TagsView(QTreeView): # {{{
|
|||||||
index = self._model.index_for_named_path(path)
|
index = self._model.index_for_named_path(path)
|
||||||
if index.isValid():
|
if index.isValid():
|
||||||
self.show_item_at_index(index)
|
self.show_item_at_index(index)
|
||||||
|
if not item_is_expanded:
|
||||||
|
# show_item_at_index() will expand the target node.
|
||||||
|
# Collapse it if it wasn't expanded before the recount.
|
||||||
|
self.collapse(index)
|
||||||
self.blockSignals(False)
|
self.blockSignals(False)
|
||||||
|
|
||||||
def show_item_at_path(self, path, box=False,
|
def show_item_at_path(self, path, box=False,
|
||||||
@ -1490,5 +1497,26 @@ class TagsView(QTreeView): # {{{
|
|||||||
Called by the expanded signal
|
Called by the expanded signal
|
||||||
'''
|
'''
|
||||||
self.setCurrentIndex(idx)
|
self.setCurrentIndex(idx)
|
||||||
|
self.current_expansion = (self.isExpanded(idx), self._model.named_path_for_index(idx))
|
||||||
|
|
||||||
|
def item_collapsed(self, idx):
|
||||||
|
'''
|
||||||
|
Called by the collapsed signal
|
||||||
|
'''
|
||||||
|
self.current_expansion = (self.isExpanded(idx), self._model.named_path_for_index(idx))
|
||||||
|
|
||||||
|
def currentChanged(self, idx, prev_idx):
|
||||||
|
self.current_expansion = (self.isExpanded(idx), self._model.named_path_for_index(idx))
|
||||||
|
super().currentChanged(idx, prev_idx)
|
||||||
|
|
||||||
|
def restore_expansion(self, expansion):
|
||||||
|
self.current_expansion = None
|
||||||
|
if expansion is not None and len(expansion) == 2:
|
||||||
|
idx = self._model.index_for_named_path(expansion[1])
|
||||||
|
if idx.isValid():
|
||||||
|
self.show_item_at_index(idx)
|
||||||
|
if not expansion[0]:
|
||||||
|
self.collapse(idx)
|
||||||
|
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
@ -983,6 +983,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
|
|||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
self._save_tb_state(gprefs)
|
||||||
for action in self.iactions.values():
|
for action in self.iactions.values():
|
||||||
try:
|
try:
|
||||||
action.library_about_to_change(olddb, db)
|
action.library_about_to_change(olddb, db)
|
||||||
@ -1009,6 +1010,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
|
|||||||
if db.new_api.pref('virtual_lib_on_startup'):
|
if db.new_api.pref('virtual_lib_on_startup'):
|
||||||
self.apply_virtual_library(db.new_api.pref('virtual_lib_on_startup'))
|
self.apply_virtual_library(db.new_api.pref('virtual_lib_on_startup'))
|
||||||
self.rebuild_vl_tabs()
|
self.rebuild_vl_tabs()
|
||||||
|
self._restore_tb_expansion_state() # Do this before plugins library_changed()
|
||||||
for action in self.iactions.values():
|
for action in self.iactions.values():
|
||||||
try:
|
try:
|
||||||
action.library_changed(db)
|
action.library_changed(db)
|
||||||
@ -1167,16 +1169,29 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
|
|||||||
_('<b>Failed</b>')+': '+str(job.description),
|
_('<b>Failed</b>')+': '+str(job.description),
|
||||||
det_msg=job.details, retry_func=retry_func)
|
det_msg=job.details, retry_func=retry_func)
|
||||||
|
|
||||||
|
def _save_tb_state(self, gprefs):
|
||||||
|
self.tb_widget.save_state(gprefs)
|
||||||
|
if gprefs['tag_browser_restore_tree_expansion']:
|
||||||
|
tv_saved_expansions = gprefs.get('tags_view_saved_expansions', {})
|
||||||
|
tv_saved_expansions.update({self.current_db.library_id: self.tb_widget.get_expansion_state()})
|
||||||
|
gprefs['tags_view_saved_expansions'] = tv_saved_expansions
|
||||||
|
|
||||||
|
def _restore_tb_expansion_state(self):
|
||||||
|
if gprefs['tag_browser_restore_tree_expansion']:
|
||||||
|
tv_saved_expansions = gprefs.get('tags_view_saved_expansions', {})
|
||||||
|
self.tb_widget.restore_expansion_state(tv_saved_expansions.get(self.current_db.library_id))
|
||||||
|
|
||||||
def read_settings(self):
|
def read_settings(self):
|
||||||
self.restore_geometry(gprefs, 'calibre_main_window_geometry', get_legacy_saved_geometry=lambda: config['main_window_geometry'])
|
self.restore_geometry(gprefs, 'calibre_main_window_geometry', get_legacy_saved_geometry=lambda: config['main_window_geometry'])
|
||||||
self.read_layout_settings()
|
self.read_layout_settings()
|
||||||
|
self._restore_tb_expansion_state()
|
||||||
|
|
||||||
def write_settings(self):
|
def write_settings(self):
|
||||||
with gprefs: # Only write to gprefs once
|
with gprefs: # Only write to gprefs once
|
||||||
self.save_geometry(gprefs, 'calibre_main_window_geometry')
|
self.save_geometry(gprefs, 'calibre_main_window_geometry')
|
||||||
dynamic.set('sort_history', self.library_view.model().sort_history)
|
dynamic.set('sort_history', self.library_view.model().sort_history)
|
||||||
self.save_layout_state()
|
self.save_layout_state()
|
||||||
self.tb_widget.save_state()
|
self._save_tb_state(gprefs)
|
||||||
|
|
||||||
def restart(self):
|
def restart(self):
|
||||||
self.quit(restart=True)
|
self.quit(restart=True)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user