diff --git a/src/calibre/gui2/preferences/__init__.py b/src/calibre/gui2/preferences/__init__.py
index 92689d62f687..26bca987a5ff 100644
--- a/src/calibre/gui2/preferences/__init__.py
+++ b/src/calibre/gui2/preferences/__init__.py
@@ -114,6 +114,13 @@ def initial_tab_changed(self):
def do_on_child_tabs(self, method, *args):
r = False
for t in self.child_tabs:
+ lazy_init_called = getattr(t, 'lazy_init_called', True)
+ if method in ('commit', 'refresh_gui') and not lazy_init_called:
+ continue
+ if method == 'restore_defaults' and not lazy_init_called:
+ if hasattr(t, 'lazy_initialize'):
+ t.lazy_initialize()
+ t.lazy_init_called = True
r = r | bool(getattr(t, method)(*args))
return r
@@ -291,7 +298,7 @@ def __init__(self, parent=None):
self.settings = {}
self.child_tabs = []
for v in self.__dict__.values():
- if isinstance(v, ConfigTabWidget):
+ if isinstance(v, LazyConfigWidgetBase):
self.child_tabs.append(v)
def register(self, name, config_obj, gui_name=None, choices=None,
@@ -349,11 +356,30 @@ def get_plugin(category, name):
(category, name))
-class ConfigTabWidget(ConfigWidgetBase):
+class LazyConfigWidgetBase(ConfigWidgetBase):
+ '''
+ Use this for dialogs that are tabs, accessed either from the left or on the
+ top. It directly replaces ConfigWidgetBase, supporting the lazy operations.
+ '''
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self.lazy_init_called = False
def set_changed_signal(self, changed_signal):
self.changed_signal.connect(changed_signal)
+ def showEvent(self, event):
+ # called when the widget is actually displays. We can't do something like
+ # lazy_genesis because Qt does "things" before showEvent() is called. In
+ # particular, the register function doesn't work with combo boxes if
+ # genesis isn't called before everythign else. Why is a mystery.
+ if not self.lazy_init_called:
+ if hasattr(self, 'lazy_initialize'):
+ self.lazy_initialize()
+ self.lazy_init_called = True
+ super().showEvent(event)
+
class ConfigDialog(QDialog):
diff --git a/src/calibre/gui2/preferences/look_feel.py b/src/calibre/gui2/preferences/look_feel.py
index 496296127d91..264bebd0e0ec 100644
--- a/src/calibre/gui2/preferences/look_feel.py
+++ b/src/calibre/gui2/preferences/look_feel.py
@@ -44,7 +44,6 @@
from calibre import human_readable
from calibre.constants import ismacos, iswindows
-from calibre.db.categories import is_standard_category
from calibre.ebooks.metadata.book.render import DEFAULT_AUTHOR_LINK
from calibre.ebooks.metadata.sources.prefs import msprefs
from calibre.gui2 import (
@@ -59,13 +58,20 @@
qt_app,
question_dialog,
)
-from calibre.gui2.actions.show_quickview import get_quickview_action_plugin
+
from calibre.gui2.custom_column_widgets import get_field_list as em_get_field_list
from calibre.gui2.dialogs.quickview import get_qv_field_list
from calibre.gui2.library.alternate_views import CM_TO_INCH, auto_height
from calibre.gui2.preferences import ConfigWidgetBase, Setting, set_help_tips, test_widget
from calibre.gui2.preferences.coloring import EditRules
-from calibre.gui2.preferences.look_feel_tabs import DisplayedFields, move_field_down, move_field_up
+from calibre.gui2.preferences.look_feel_tabs import (
+ DisplayedFields,
+ export_layout,
+ import_layout,
+ move_field_down,
+ move_field_up,
+ reset_layout,
+)
from calibre.gui2.preferences.look_feel_ui import Ui_Form
from calibre.gui2.widgets import BusyCursor
from calibre.gui2.widgets2 import Dialog
@@ -481,12 +487,6 @@ def genesis(self, gui):
r('show_sb_all_actions_button', gprefs)
# r('show_sb_preference_button', gprefs)
r('row_numbers_in_book_list', gprefs)
- r('tag_browser_old_look', gprefs)
- r('tag_browser_hide_empty_categories', gprefs)
- r('tag_browser_always_autocollapse', gprefs)
- r('tag_browser_restore_tree_expansion', gprefs)
- r('tag_browser_show_tooltips', gprefs)
- r('tag_browser_allow_keyboard_focus', gprefs)
r('bd_show_cover', gprefs)
r('bd_overlay_cover_size', gprefs)
r('cover_corner_radius', gprefs)
@@ -497,13 +497,6 @@ def genesis(self, gui):
r('cover_grid_disk_cache_size', gprefs)
r('cover_grid_spacing', gprefs)
r('cover_grid_show_title', gprefs)
- r('tag_browser_show_counts', gprefs)
- r('tag_browser_item_padding', gprefs)
-
- r('qv_respects_vls', gprefs)
- r('qv_dclick_changes_column', gprefs)
- r('qv_retkey_changes_column', gprefs)
- r('qv_follows_column', gprefs)
r('emblem_size', gprefs)
r('emblem_position', gprefs, choices=[
@@ -536,10 +529,6 @@ def get_esc_lang(l):
choices.insert(1, ((get_language(lul), lul)))
r('language', prefs, choices=choices, restart_required=True, setting=LanguageSetting)
- r('show_avg_rating', config)
- r('show_links_in_tag_browser', gprefs)
- r('show_notes_in_tag_browser', gprefs)
- r('icons_on_right_in_tag_browser', gprefs)
r('disable_animations', config)
r('systray_icon', config, restart_required=True)
r('show_splash_screen', gprefs)
@@ -554,12 +543,6 @@ def get_esc_lang(l):
(_('Never'), 'never')]
r('toolbar_text', gprefs, choices=choices)
- choices = [(_('Disabled'), 'disable'), (_('By first letter'), 'first letter'),
- (_('Partitioned'), 'partition')]
- r('tags_browser_partition_method', gprefs, choices=choices)
- r('tags_browser_collapse_at', gprefs)
- r('tags_browser_collapse_fl_at', gprefs)
-
fm = db.field_metadata
choices = sorted(((fm[k]['name'], k) for k in fm.displayable_field_keys() if fm[k]['name']),
key=lambda x:sort_key(x[0]))
@@ -583,15 +566,6 @@ def get_esc_lang(l):
self.current_font = self.initial_font = None
self.change_font_button.clicked.connect(self.change_font)
- self.display_model = DisplayedFields(self.gui.current_db, self.field_display_order)
- self.display_model.dataChanged.connect(self.changed_signal)
- self.field_display_order.setModel(self.display_model)
- mu = partial(move_field_up, self.field_display_order, self.display_model)
- md = partial(move_field_down, self.field_display_order, self.display_model)
- self.df_up_button.clicked.connect(mu)
- self.df_down_button.clicked.connect(md)
- self.field_display_order.set_movement_functions(mu, md)
-
self.em_display_model = EMDisplayedFields(self.gui.current_db, self.em_display_order)
self.em_display_model.dataChanged.connect(self.changed_signal)
self.em_display_order.setModel(self.em_display_model)
@@ -600,41 +574,9 @@ def get_esc_lang(l):
self.em_display_order.set_movement_functions(mu, md)
self.em_up_button.clicked.connect(mu)
self.em_down_button.clicked.connect(md)
- self.em_export_layout_button.clicked.connect(partial(self.export_layout, model=self.em_display_model))
- self.em_import_layout_button.clicked.connect(partial(self.import_layout, model=self.em_display_model))
- self.em_reset_layout_button.clicked.connect(partial(self.reset_layout, model=self.em_display_model))
-
- self.qv_display_model = QVDisplayedFields(self.gui.current_db, self.qv_display_order)
- self.qv_display_model.dataChanged.connect(self.changed_signal)
- self.qv_display_order.setModel(self.qv_display_model)
- mu = partial(move_field_up, self.qv_display_order, self.qv_display_model)
- md = partial(move_field_down, self.qv_display_order, self.qv_display_model)
- self.qv_display_order.set_movement_functions(mu, md)
- self.qv_up_button.clicked.connect(mu)
- self.qv_down_button.clicked.connect(md)
-
- self.tb_display_model = TBDisplayedFields(self.gui.current_db, self.tb_display_order,
- category_icons=self.gui.tags_view.model().category_custom_icons)
- self.tb_display_model.dataChanged.connect(self.changed_signal)
- self.tb_display_order.setModel(self.tb_display_model)
- self.tb_reset_layout_button.clicked.connect(partial(self.reset_layout, model=self.tb_display_model))
- self.tb_export_layout_button.clicked.connect(partial(self.export_layout, model=self.tb_display_model))
- self.tb_import_layout_button.clicked.connect(partial(self.import_layout, model=self.tb_display_model))
- self.tb_up_button.clicked.connect(self.tb_up_button_clicked)
- self.tb_down_button.clicked.connect(self.tb_down_button_clicked)
- self.tb_display_order.set_movement_functions(self.tb_up_button_clicked, self.tb_down_button_clicked)
-
- self.tb_categories_to_part_model = TBPartitionedFields(self.gui.current_db,
- self.tb_cats_to_partition,
- category_icons=self.gui.tags_view.model().category_custom_icons)
- self.tb_categories_to_part_model.dataChanged.connect(self.changed_signal)
- self.tb_cats_to_partition.setModel(self.tb_categories_to_part_model)
- self.tb_partition_reset_button.clicked.connect(partial(self.reset_layout,
- model=self.tb_categories_to_part_model))
- self.tb_partition_export_layout_button.clicked.connect(partial(self.export_layout,
- model=self.tb_categories_to_part_model))
- self.tb_partition_import_layout_button.clicked.connect(partial(self.import_layout,
- model=self.tb_categories_to_part_model))
+ self.em_export_layout_button.clicked.connect(partial(export_layout, self, model=self.em_display_model))
+ self.em_import_layout_button.clicked.connect(partial(import_layout, self, model=self.em_display_model))
+ self.em_reset_layout_button.clicked.connect(partial(reset_layout, model=self.em_display_model))
self.bd_vertical_cats_model = BDVerticalCats(self.gui.current_db, self.tb_hierarchy_tab.tb_hierarchical_cats)
self.bd_vertical_cats_model.dataChanged.connect(self.changed_signal)
@@ -690,16 +632,8 @@ def get_esc_lang(l):
self.css_highlighter = get_highlighter('css')()
self.css_highlighter.apply_theme(get_theme(None))
self.css_highlighter.set_document(self.opt_book_details_css.document())
- self.lazy_tabs = {}
for i in range(self.tabWidget.count()):
self.sections_view.addItem(QListWidgetItem(self.tabWidget.tabIcon(i), self.tabWidget.tabText(i).replace('&', '')))
- # retrieve tabs and subtabs of look & feel to load their content later when clicking of them
- w = self.tabWidget.widget(i).widget()
- self.lazy_tabs[(i, None)] = w
- if isinstance(w, QTabWidget):
- w.currentChanged.connect(partial(self.lazy_tab_operations, i))
- for ii in range(w.count()):
- self.lazy_tabs[(i, ii)] = w.widget(ii)
self.sections_view.setCurrentRow(self.tabWidget.currentIndex())
self.sections_view.currentRowChanged.connect(self.tabWidget.setCurrentIndex)
self.sections_view.setMaximumWidth(self.sections_view.sizeHintForColumn(0) + 16)
@@ -728,59 +662,6 @@ def update_color_palette_state(self):
enabled = self.opt_ui_style.currentData() == 'calibre'
self.button_adjust_colors.setEnabled(enabled)
- def export_layout(self, model=None):
- filename = choose_save_file(self, 'em_import_export_field_list',
- _('Save column list to file'),
- filters=[(_('Column list'), ['json'])])
- if filename:
- try:
- with open(filename, 'w') as f:
- json.dump(model.fields, f, indent=1)
- except Exception as err:
- error_dialog(self, _('Export field layout'),
- _('
Could not write field list. Error:
%s')%err, show=True)
-
- def import_layout(self, model=None):
- filename = choose_files(self, 'em_import_export_field_list',
- _('Load column list from file'),
- filters=[(_('Column list'), ['json'])])
- if filename:
- try:
- with open(filename[0]) as f:
- fields = json.load(f)
- model.initialize(pref_data_override=fields)
- self.changed_signal.emit()
- except Exception as err:
- error_dialog(self, _('Import layout'),
- _('
Could not read field list. Error:
%s')%err, show=True)
-
- def reset_layout(self, model=None):
- model.initialize(use_defaults=True)
- self.changed_signal.emit()
-
- def tb_down_button_clicked(self):
- idx = self.tb_display_order.currentIndex()
- if idx.isValid():
- row = idx.row()
- model = self.tb_display_model
- fields = model.fields
- key = fields[row][0]
- if not is_standard_category(key):
- return
- if row < len(fields) and is_standard_category(fields[row+1][0]):
- move_field_down(self.tb_display_order, model)
-
- def tb_up_button_clicked(self):
- idx = self.tb_display_order.currentIndex()
- if idx.isValid():
- row = idx.row()
- model = self.tb_display_model
- fields = model.fields
- key = fields[row][0]
- if not is_standard_category(key):
- return
- move_field_up(self.tb_display_order, model)
-
def choose_icon_theme(self):
from calibre.gui2.icon_theme import ChooseTheme
d = ChooseTheme(self)
@@ -833,11 +714,7 @@ def initialize(self):
font.append(gprefs.get('font_stretch', QFont.Stretch.Unstretched))
self.current_font = self.initial_font = font
self.update_font_display()
- self.display_model.initialize()
self.em_display_model.initialize()
- self.qv_display_model.initialize()
- self.tb_display_model.initialize()
- self.tb_categories_to_part_model.initialize()
self.bd_vertical_cats_model.initialize()
db = self.gui.current_db
mi = []
@@ -857,10 +734,8 @@ def initialize(self):
self.opt_book_details_css.blockSignals(True)
self.opt_book_details_css.setPlainText(P('templates/book_details.css', data=True).decode('utf-8'))
self.opt_book_details_css.blockSignals(False)
- self.tb_focus_label.setVisible(self.opt_tag_browser_allow_keyboard_focus.isChecked())
self.update_color_palette_state()
self.opt_gui_layout.setCurrentIndex(0 if self.gui.layout_container.is_wide else 1)
- self.lazy_tab_operations(self.tabWidget.currentIndex(), None)
def open_cg_cache(self):
open_local_file(self.gui.grid_view.thumbnail_cache.location)
@@ -870,20 +745,9 @@ def update_cg_cache_size(self, size):
_('Current space used: %s') % human_readable(size))
def tab_changed(self, index):
- self.lazy_tab_operations(index, None)
if self.tabWidget.currentWidget() is self.cover_grid_tab:
self.show_current_cache_usage()
- def lazy_tab_operations(self, idx_section, idx_subtab):
- '''
- Check if the tab has lazy operations.
- Perfom the lazy operations only once, the first time the tab is selected.
- '''
- tab = self.lazy_tabs.get((idx_section, idx_subtab), None)
- if hasattr(tab, 'lazy_populate_content'):
- tab.lazy_populate_content()
- self.lazy_tabs.pop((idx_section, idx_subtab), None)
-
def show_current_cache_usage(self):
t = Thread(target=self.calc_cache_size)
t.daemon = True
@@ -912,9 +776,7 @@ def restore_defaults(self):
if ofont is not None:
self.changed_signal.emit()
self.update_font_display()
- self.display_model.restore_defaults()
self.em_display_model.restore_defaults()
- self.qv_display_model.restore_defaults()
self.bd_vertical_cats_model.restore_defaults()
gprefs.set('tb_search_order', gprefs.defaults['tb_search_order'])
self.edit_rules.clear()
@@ -986,11 +848,7 @@ def commit(self, *args):
is not None else QFont.Stretch.Unstretched)
QApplication.setFont(self.font_display.font())
rr = True
- self.display_model.commit()
self.em_display_model.commit()
- self.qv_display_model.commit()
- self.tb_display_model.commit()
- self.tb_categories_to_part_model.commit()
self.bd_vertical_cats_model.commit()
self.edit_rules.commit(self.gui.current_db.prefs)
self.icon_rules.commit(self.gui.current_db.prefs)
@@ -1027,9 +885,6 @@ def refresh_gui(self, gui):
gui.library_view.refresh_row_sizing()
gui.grid_view.refresh_settings()
gui.update_auto_scroll_timeout()
- qv = get_quickview_action_plugin()
- if qv:
- qv.refill_quickview()
gui.sb_all_gui_actions_button.setVisible(gprefs['show_sb_all_actions_button'])
# gui.sb_preferences_button.setVisible(gprefs['show_sb_preference_button'])
diff --git a/src/calibre/gui2/preferences/look_feel.ui b/src/calibre/gui2/preferences/look_feel.ui
index 3a88668f44d6..c55a609c8458 100644
--- a/src/calibre/gui2/preferences/look_feel.ui
+++ b/src/calibre/gui2/preferences/look_feel.ui
@@ -1307,487 +1307,15 @@ columns". Editing with mouse clicks and the Tab key will be disabled.</p
&Tag browser
-
+
Di&splay
-
- -
-
-
- User categories and Saved searches cannot be moved
-
-
- Select the categories to display in the Tag browser, and their &order
-
-
- tb_display_order
-
-
-
- -
-
-
-
- 0
- 200
-
-
-
- true
-
-
-
- -
-
-
- Move up. User categories and Saved searches cannot be moved. Keyboard shortcut: Ctrl-Up arrow
-
-
-
- :/images/arrow-up.png:/images/arrow-up.png
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 50
- 40
-
-
-
-
- -
-
-
- Move down. User categories and Saved searches cannot be moved. Keyboard shortcut: Ctrl-Down arrow
-
-
-
- :/images/arrow-down.png:/images/arrow-down.png
-
-
-
- -
-
-
-
-
-
- Click this button to reset the list to its default order.
-
-
- Reset list
-
-
-
- -
-
-
- <p>Click this button to set the list to one
-previously exported. This could be useful if you have several libraries with
-similar structure and you want to use the same column order for each one. Columns
-in the imported list that aren't in the current library are ignored. Columns in
-the library that are not in the imported list are put at the end and marked
-as displayable.</p>
-
-
- Import list
-
-
-
- -
-
-
- <p>Click this button to write the current display
-settings to a file. This could be useful if you have several libraries with similar
-structure and you want to use the same column order for each one.</p>
-
-
- Export list
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
- -
-
-
-
-
-
- Show the average rating per item indication in the Tag browser
-
-
- Show &average ratings
-
-
- true
-
-
-
- -
-
-
- Show an icon if the item has an attached link
-
-
- Show &links icons
-
-
- true
-
-
-
- -
-
-
- Show &tooltips
-
-
-
- -
-
-
- <p>Show counts for items in the Tag browser. Such as the number of books
-by each author, the number of authors, etc. If you turn it off, you can still
-see the counts by hovering your mouse over any item.</p>
-
-
- Show &counts
-
-
-
- -
-
-
- Show an icon if the item has an attached note
-
-
- Show ¬es icons
-
-
- true
-
-
-
- -
-
-
- Use &alternating row colors
-
-
-
- -
-
-
- <p>When checked, calibre will automatically hide any category
-(a column, custom or standard) that has no items to show. For example, some
-categories might not have values when using Virtual libraries. Checking this
-box will cause these empty categories to be hidden.</p>
-
-
- Hide empt&y categories (columns)
-
-
-
- -
-
-
- If checked the notes and links icons will be placed at the right, after
-the count and in columns. If unchecked, the icons will be placed immediately after the text,
-to the left of the count and not in columns.
-
-
- Place icons on the &right, in columns
-
-
- true
-
-
-
- -
-
-
- <p>When checked, Find in the Tag browser will show all items
-that match the search instead of the first one. If Hide empty categories is
-also checked then only categories containing a matched item will be shown.</p>
-
-
- Find &shows all items that match
-
-
-
- -
-
-
- <p>Ensure the last "used" item in the Tag browser is visible when opening a library.
-An item is "used" when it is expanded, collapsed, or clicked.</p>
-
-
- Expand tr&ee to show last used item
-
-
-
-
-
- -
-
-
-
-
-
- <p>When checked, the Tag browser can get keyboard focus, allowing
-use of the keyboard to navigate the tree using the arrow keys. The Enter key simulates
-a click on the selected item. The keyboard shortcut 'Tag browser /
-Give the Tag browser keyboard focus' changes the keyboard focus without
-using the mouse.</p>
-
-
- Allow the Tag browser to have keyboard &focus
-
-
-
- -
-
-
- margin-left: 1.5em
-
-
- <p style="text-indent: 2em; font-size:smaller">
-If you enable this option then you should set a keyboard shortcut to
-focus the Tag browser under
-<code>Preferences->Shortcuts->Tag browser->Give
-the Tag browser keyboard focus</code></p>
-
-
- true
-
-
-
-
-
- -
-
-
- QFormLayout::ExpandingFieldsGrow
-
-
-
-
-
- Spacing between &items:
-
-
- opt_tag_browser_item_padding
-
-
-
- -
-
-
- <p>The spacing between consecutive items in the Tag browser.
-In units of (ex) which is the approximate height of the letter 'x' in the
-currently used font.</p>
-
-
- ex
-
-
- 1
-
-
- -1.000000000000000
-
-
- 2.000000000000000
-
-
- 0.100000000000000
-
-
-
-
-
-
-
+
&Partitioning and collapsing
-
- -
-
-
-
-
-
- QFormLayout::ExpandingFieldsGrow
-
-
-
-
-
- &Category partitioning method:
-
-
- opt_tags_browser_partition_method
-
-
-
- -
-
-
- <p>Choose how Tag browser subcategories are displayed when
-there are more items than the limit. Select by first
-letter to see an A, B, C list. Choose partitioned to
-have a list of fixed-sized groups. Set to disabled
-if you never want subcategories</p>
-
-
-
- -
-
-
- Combine letters &when fewer items than:
-
-
- opt_tags_browser_collapse_fl_at
-
-
-
- -
-
-
- <p>If collapsing by first letter, combine adjacent letters together if
-there are fewer items under a letter than specified here. If the partition method is
-not set to first letter, this value is ignored. Set to zero to disable.</p>
-
-
- 10000
-
-
-
- -
-
-
- Co&llapse when more items than:
-
-
- opt_tags_browser_collapse_at
-
-
-
- -
-
-
- <p>If a Tag browser category has more than this number of items, it is divided
-up into subcategories. If the partition method is set to disable, this value is ignored.</p>
-
-
- 10000
-
-
-
-
-
- -
-
-
- <p>Check the box for categories that are to
-be partitioned using the criteria above. Uncheck the box if you don't want to
-partition a category even if the number of items is larger than
-the value shown above. This option can be used to
-avoid collapsing hierarchical categories that have only
-a few top-level elements.</p>
-
-
- Select categories to &partition:
-
-
- tb_cats_to_partition
-
-
-
- -
-
-
-
- 0
- 200
-
-
-
- true
-
-
-
- -
-
-
-
-
-
- Click this button to reset the list to its default order.
-
-
- Reset list
-
-
-
- -
-
-
- <p>Click this button to set the list to one
-previously exported. This could be useful if you have several libraries with
-similar structure and you want to use the same for each one.</p>
-
-
- Import list
-
-
-
- -
-
-
- <p>Click this button to write the current display
-settings to a file. This could be useful if you have several libraries with similar
-structure and you want to use the same for each one.</p>
-
-
- Export list
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
-
-
-
@@ -1800,7 +1328,7 @@ structure and you want to use the same for each one.</p>
-
+
:/images/cover_flow.png:/images/cover_flow.png
@@ -1808,13 +1336,8 @@ structure and you want to use the same for each one.</p>
Cover &browser
-
- -
-
-
-
-
+
:/images/quickview.png:/images/quickview.png
@@ -1822,108 +1345,6 @@ structure and you want to use the same for each one.</p>
&Quickview
-
- -
-
-
-
-
-
- <p>Check this box to make Quickview show books only in the
-current Virtual library. If unchecked, Quickview ignores Virtual libraries. If
-unchecked then only row changes are taken into account.</p>
-
-
- &Apply Virtual libraries
-
-
-
- -
-
-
- <p>Check this box to make Quickview change the column being examined
-when the column in the book list is changed using the cursor arrow keys</p>
-
-
- &Change Quickview item when book list column changes
-
-
-
- -
-
-
- <p>Pressing Enter in a cell changes both the book and the
-column being examined (the left-hand panel)</p>
-
-
- &Pressing Enter changes the examined column
-
-
-
- -
-
-
- <p>Double-clicking in a cell changes both the book and the
-column being examined (the left-hand panel)</p>
-
-
- &Double click changes examined column
-
-
-
-
-
- -
-
-
- Select columns to display
-
-
-
-
-
-
- Move up. Keyboard shortcut: Ctrl-Up arrow
-
-
-
- :/images/arrow-up.png:/images/arrow-up.png
-
-
-
- -
-
-
- Move down. Keyboard shortcut: Ctrl-Down arrow
-
-
-
- :/images/arrow-down.png:/images/arrow-down.png
-
-
-
- -
-
-
- true
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
-
@@ -1961,6 +1382,16 @@ column being examined (the left-hand panel)</p>
QWidget
calibre/gui2/preferences/look_feel.h
+
+ TbDisplayTab
+ ConfigWidget
+ calibre/gui2/preferences/look_feel_tabs.tb_display.h
+
+
+ TbPartitioningTab
+ ConfigWidget
+ calibre/gui2/preferences/look_feel_tabs.tb_partitioning.h
+
TbIconRulesTab
ConfigWidget
@@ -1976,6 +1407,11 @@ column being examined (the left-hand panel)</p>
ConfigWidget
calibre/gui2/preferences/look_feel_tabs.cover_view.h
+
+ QuickviewTab
+ ConfigWidget
+ calibre/gui2/preferences/look_feel_tabs.tb_quickview.h
+
@@ -1997,21 +1433,5 @@ column being examined (the left-hand panel)</p>
-
- opt_tag_browser_allow_keyboard_focus
- toggled(bool)
- tb_focus_label
- setVisible(bool)
-
-
- 275
- 528
-
-
- 358
- 555
-
-
-
diff --git a/src/calibre/gui2/preferences/look_feel_tabs/__init__.py b/src/calibre/gui2/preferences/look_feel_tabs/__init__.py
index 6cae188d2a4e..4ad4a9560ff2 100644
--- a/src/calibre/gui2/preferences/look_feel_tabs/__init__.py
+++ b/src/calibre/gui2/preferences/look_feel_tabs/__init__.py
@@ -5,9 +5,17 @@
__copyright__ = '2011, Kovid Goyal '
__docformat__ = 'restructuredtext en'
+import json
from qt.core import QAbstractListModel, QIcon, QItemSelectionModel, Qt
+from calibre.gui2 import (
+ choose_files,
+ choose_save_file,
+ config,
+ error_dialog,
+ gprefs,
+)
from calibre.gui2.book_details import get_field_list
@@ -100,6 +108,36 @@ def move(self, idx, delta):
self.changed = True
return idx
+def export_layout(in_widget, model=None):
+ filename = choose_save_file(in_widget, 'look_feel_prefs_import_export_field_list',
+ _('Save column list to file'),
+ filters=[(_('Column list'), ['json'])])
+ if filename:
+ try:
+ with open(filename, 'w') as f:
+ json.dump(model.fields, f, indent=1)
+ except Exception as err:
+ error_dialog(in_widget, _('Export field layout'),
+ _('Could not write field list. Error:
%s')%err, show=True)
+
+def import_layout(in_widget, model=None):
+ filename = choose_files(in_widget, 'look_feel_prefs_import_export_field_list',
+ _('Load column list from file'),
+ filters=[(_('Column list'), ['json'])])
+ if filename:
+ try:
+ with open(filename[0]) as f:
+ fields = json.load(f)
+ model.initialize(pref_data_override=fields)
+ in_widget.changed_signal.emit()
+ except Exception as err:
+ error_dialog(in_widget, _('Import layout'),
+ _('
Could not read field list. Error:
%s')%err, show=True)
+
+def reset_layout(in_widget, model=None):
+ model.initialize(use_defaults=True)
+ in_widget.changed_signal.emit()
+
def move_field_up(widget, model):
idx = widget.currentIndex()
diff --git a/src/calibre/gui2/preferences/look_feel_tabs/cover_view.py b/src/calibre/gui2/preferences/look_feel_tabs/cover_view.py
index 16e35bd0102c..606e849bf163 100644
--- a/src/calibre/gui2/preferences/look_feel_tabs/cover_view.py
+++ b/src/calibre/gui2/preferences/look_feel_tabs/cover_view.py
@@ -2,7 +2,7 @@
__license__ = 'GPL v3'
-__copyright__ = '2010, Kovid Goyal '
+__copyright__ = '2025, Kovid Goyal '
__docformat__ = 'restructuredtext en'
@@ -10,15 +10,15 @@
from calibre.gui2 import config, gprefs
from calibre.gui2.dialogs.template_dialog import TemplateDialog
-from calibre.gui2.preferences import ConfigTabWidget, ConfigWidgetBase, set_help_tips
+from calibre.gui2.preferences import LazyConfigWidgetBase, ConfigWidgetBase, set_help_tips
from calibre.gui2.preferences.look_feel_tabs.cover_view_ui import Ui_Form
-class CoverView(ConfigTabWidget, Ui_Form):
+class CoverView(LazyConfigWidgetBase, Ui_Form):
def genesis(self, gui):
self.gui = gui
- db = gui.library_view.model().db
+ db = self.gui.library_view.model().db
r = self.register
r('books_autoscroll_time', gprefs)
@@ -41,7 +41,7 @@ def genesis(self, gui):
self.fs_help_msg.setText(self.fs_help_msg.text()%(
QKeySequence(QKeySequence.StandardKey.FullScreen).toString(QKeySequence.SequenceFormat.NativeText)))
- def initialize(self):
+ def lazy_initialize(self):
ConfigWidgetBase.initialize(self)
set_help_tips(self.opt_cover_browser_narrow_view_position, _(
'This option controls the position of the cover browser when using the Narrow user '
@@ -51,11 +51,25 @@ def initialize(self):
'list. This option has no effect when using the Wide user interface layout.'))
def edit_cb_title_template(self):
- t = TemplateDialog(self, self.opt_cover_browser_title_template.text(), fm=self.gui.current_db.field_metadata)
+ rows = self.gui.library_view.selectionModel().selectedRows()
+ mi = None
+ db = self.gui.current_db.new_api
+ if rows:
+ ids = list(map(self.gui.library_view.model().id, rows))
+ mi = []
+ for bk in ids[0:min(10, len(ids))]:
+ mi.append(db.get_proxy_metadata(bk))
+ t = TemplateDialog(self, self.opt_cover_browser_title_template.text(), mi=mi, fm=db.field_metadata)
t.setWindowTitle(_('Edit template for caption'))
if t.exec():
self.opt_cover_browser_title_template.setText(t.rule[1])
+ def commit(self):
+ return ConfigWidgetBase.commit(self)
+
+ def restore_defaults(self):
+ ConfigWidgetBase.restore_defaults(self)
+
def refresh_gui(self, gui):
gui.cover_flow.setShowReflections(gprefs['cover_browser_reflections'])
gui.cover_flow.setPreserveAspectRatio(gprefs['cb_preserve_aspect_ratio'])
diff --git a/src/calibre/gui2/preferences/look_feel_tabs/tb_display.py b/src/calibre/gui2/preferences/look_feel_tabs/tb_display.py
new file mode 100644
index 000000000000..70345d89d2ad
--- /dev/null
+++ b/src/calibre/gui2/preferences/look_feel_tabs/tb_display.py
@@ -0,0 +1,118 @@
+#!/usr/bin/env python
+
+
+__license__ = 'GPL v3'
+__copyright__ = '2025, Kovid Goyal '
+__docformat__ = 'restructuredtext en'
+
+from functools import partial
+
+from calibre.db.categories import is_standard_category
+from calibre.gui2 import config, gprefs
+from calibre.gui2.preferences import ConfigWidgetBase, LazyConfigWidgetBase
+from calibre.gui2.preferences.look_feel_tabs import (
+ DisplayedFields,
+ import_layout,
+ export_layout,
+ move_field_down,
+ move_field_up,
+ reset_layout
+ )
+from calibre.gui2.preferences.look_feel_tabs.tb_display_ui import Ui_Form
+
+class TBDisplayedFields(DisplayedFields): # {{{
+ # The code in this class depends on the fact that the tag browser is
+ # initialized before this class is instantiated.
+
+ def __init__(self, db, parent=None, category_icons=None):
+ DisplayedFields.__init__(self, db, parent, category_icons=category_icons)
+ from calibre.gui2.ui import get_gui
+ self.gui = get_gui()
+
+ def initialize(self, use_defaults=False, pref_data_override=None):
+ tv = self.gui.tags_view
+ cat_ord = tv.model().get_ordered_categories(use_defaults=use_defaults,
+ pref_data_override=pref_data_override)
+ if use_defaults:
+ hc = []
+ self.changed = True
+ elif pref_data_override:
+ hc = [k for k,v in pref_data_override if not v]
+ self.changed = True
+ else:
+ hc = tv.hidden_categories
+
+ self.beginResetModel()
+ self.fields = [[x, x not in hc] for x in cat_ord]
+ self.endResetModel()
+
+ def commit(self):
+ if self.changed:
+ self.db.prefs.set('tag_browser_hidden_categories', [k for k,v in self.fields if not v])
+ self.db.prefs.set('tag_browser_category_order', [k for k,v in self.fields])
+# }}}
+
+
+class TbDisplayTab(LazyConfigWidgetBase, Ui_Form):
+
+ def genesis(self, gui):
+ self.gui = gui
+ r = self.register
+ r('tag_browser_old_look', gprefs)
+ r('tag_browser_hide_empty_categories', gprefs)
+ r('tag_browser_always_autocollapse', gprefs)
+ r('tag_browser_restore_tree_expansion', gprefs)
+ r('tag_browser_show_tooltips', gprefs)
+ r('tag_browser_allow_keyboard_focus', gprefs)
+ r('tag_browser_show_counts', gprefs)
+ r('tag_browser_item_padding', gprefs)
+ r('show_avg_rating', config)
+ r('show_links_in_tag_browser', gprefs)
+ r('show_notes_in_tag_browser', gprefs)
+ r('icons_on_right_in_tag_browser', gprefs)
+
+ self.tb_display_model = TBDisplayedFields(self.gui.current_db, self.tb_display_order,
+ category_icons=self.gui.tags_view.model().category_custom_icons)
+ self.tb_display_model.dataChanged.connect(self.changed_signal)
+ self.tb_display_order.setModel(self.tb_display_model)
+ self.tb_reset_layout_button.clicked.connect(partial(reset_layout, self, model=self.tb_display_model))
+ self.tb_export_layout_button.clicked.connect(partial(export_layout, self, model=self.tb_display_model))
+ self.tb_import_layout_button.clicked.connect(partial(import_layout, self, model=self.tb_display_model))
+ self.tb_up_button.clicked.connect(self.tb_up_button_clicked)
+ self.tb_down_button.clicked.connect(self.tb_down_button_clicked)
+ self.tb_display_order.set_movement_functions(self.tb_up_button_clicked, self.tb_down_button_clicked)
+
+ def lazy_initialize(self):
+ self.tb_display_model.initialize()
+ self.tb_focus_label.setVisible(self.opt_tag_browser_allow_keyboard_focus.isChecked())
+
+ def tb_down_button_clicked(self):
+ idx = self.tb_display_order.currentIndex()
+ if idx.isValid():
+ row = idx.row()
+ model = self.tb_display_model
+ fields = model.fields
+ key = fields[row][0]
+ if not is_standard_category(key):
+ return
+ if row < len(fields) and is_standard_category(fields[row+1][0]):
+ move_field_down(self.tb_display_order, model)
+
+ def tb_up_button_clicked(self):
+ idx = self.tb_display_order.currentIndex()
+ if idx.isValid():
+ row = idx.row()
+ model = self.tb_display_model
+ fields = model.fields
+ key = fields[row][0]
+ if not is_standard_category(key):
+ return
+ move_field_up(self.tb_display_order, model)
+
+ def restore_defaults(self):
+ ConfigWidgetBase.restore_defaults(self)
+ self.tb_display_model.restore_defaults()
+
+ def commit(self):
+ self.tb_display_model.commit()
+ return ConfigWidgetBase.commit(self)
diff --git a/src/calibre/gui2/preferences/look_feel_tabs/tb_display.ui b/src/calibre/gui2/preferences/look_feel_tabs/tb_display.ui
new file mode 100644
index 000000000000..893b1f93bb50
--- /dev/null
+++ b/src/calibre/gui2/preferences/look_feel_tabs/tb_display.ui
@@ -0,0 +1,360 @@
+
+
+ Form
+
+
+
+ 0
+ 0
+ 1096
+ 791
+
+
+
+ Form
+
+
+ -
+
+
+ User categories and Saved searches cannot be moved
+
+
+ Select the categories to display in the Tag browser, and their &order
+
+
+ tb_display_order
+
+
+
+ -
+
+
+
+ 0
+ 200
+
+
+
+ true
+
+
+
+ -
+
+
+ Move up. User categories and Saved searches cannot be moved. Keyboard shortcut: Ctrl-Up arrow
+
+
+
+ :/images/arrow-up.png:/images/arrow-up.png
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 50
+ 40
+
+
+
+
+ -
+
+
+ Move down. User categories and Saved searches cannot be moved. Keyboard shortcut: Ctrl-Down arrow
+
+
+
+ :/images/arrow-down.png:/images/arrow-down.png
+
+
+
+ -
+
+
-
+
+
+ Click this button to reset the list to its default order.
+
+
+ Reset list
+
+
+
+ -
+
+
+ <p>Click this button to set the list to one
+previously exported. This could be useful if you have several libraries with
+similar structure and you want to use the same column order for each one. Columns
+in the imported list that aren't in the current library are ignored. Columns in
+the library that are not in the imported list are put at the end and marked
+as displayable.</p>
+
+
+ Import list
+
+
+
+ -
+
+
+ <p>Click this button to write the current display
+settings to a file. This could be useful if you have several libraries with similar
+structure and you want to use the same column order for each one.</p>
+
+
+ Export list
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Show the average rating per item indication in the Tag browser
+
+
+ Show &average ratings
+
+
+ true
+
+
+
+ -
+
+
+ Show an icon if the item has an attached link
+
+
+ Show &links icons
+
+
+ true
+
+
+
+ -
+
+
+ Show &tooltips
+
+
+
+ -
+
+
+ <p>Show counts for items in the Tag browser. Such as the number of books
+by each author, the number of authors, etc. If you turn it off, you can still
+see the counts by hovering your mouse over any item.</p>
+
+
+ Show &counts
+
+
+
+ -
+
+
+ Show an icon if the item has an attached note
+
+
+ Show ¬es icons
+
+
+ true
+
+
+
+ -
+
+
+ Use &alternating row colors
+
+
+
+ -
+
+
+ <p>When checked, calibre will automatically hide any category
+(a column, custom or standard) that has no items to show. For example, some
+categories might not have values when using Virtual libraries. Checking this
+box will cause these empty categories to be hidden.</p>
+
+
+ Hide empt&y categories (columns)
+
+
+
+ -
+
+
+ If checked the notes and links icons will be placed at the right, after
+the count and in columns. If unchecked, the icons will be placed immediately after the text,
+to the left of the count and not in columns.
+
+
+ Place icons on the &right, in columns
+
+
+ true
+
+
+
+ -
+
+
+ <p>When checked, Find in the Tag browser will show all items
+that match the search instead of the first one. If Hide empty categories is
+also checked then only categories containing a matched item will be shown.</p>
+
+
+ Find &shows all items that match
+
+
+
+ -
+
+
+ <p>Ensure the last "used" item in the Tag browser is visible when opening a library.
+An item is "used" when it is expanded, collapsed, or clicked.</p>
+
+
+ Expand tr&ee to show last used item
+
+
+
+
+
+ -
+
+
-
+
+
+ <p>When checked, the Tag browser can get keyboard focus, allowing
+use of the keyboard to navigate the tree using the arrow keys. The Enter key simulates
+a click on the selected item. The keyboard shortcut 'Tag browser /
+Give the Tag browser keyboard focus' changes the keyboard focus without
+using the mouse.</p>
+
+
+ Allow the Tag browser to have keyboard &focus
+
+
+
+ -
+
+
+ margin-left: 1.5em
+
+
+ <p style="text-indent: 2em; font-size:smaller">
+If you enable this option then you should set a keyboard shortcut to
+focus the Tag browser under
+<code>Preferences->Shortcuts->Tag browser->Give
+the Tag browser keyboard focus</code></p>
+
+
+ true
+
+
+
+
+
+ -
+
+
+ QFormLayout::ExpandingFieldsGrow
+
+
-
+
+
+ Spacing between &items:
+
+
+ opt_tag_browser_item_padding
+
+
+
+ -
+
+
+ <p>The spacing between consecutive items in the Tag browser.
+In units of (ex) which is the approximate height of the letter 'x' in the
+currently used font.</p>
+
+
+ ex
+
+
+ 1
+
+
+ -1.000000000000000
+
+
+ 2.000000000000000
+
+
+ 0.100000000000000
+
+
+
+
+
+
+
+
+
+ ListViewWithMoveByKeyPress
+ QListView
+ calibre/gui2/preferences.h
+
+
+ ListWidgetWithMoveByKeyPress
+ QListWidget
+ calibre/gui2/preferences.h
+
+
+
+
+ opt_tag_browser_allow_keyboard_focus
+ toggled(bool)
+ tb_focus_label
+ setVisible(bool)
+
+
+ 275
+ 528
+
+
+ 358
+ 555
+
+
+
+
+
diff --git a/src/calibre/gui2/preferences/look_feel_tabs/tb_hierarchy.py b/src/calibre/gui2/preferences/look_feel_tabs/tb_hierarchy.py
index 2f91c0aa47a0..ff1b40d22fa8 100644
--- a/src/calibre/gui2/preferences/look_feel_tabs/tb_hierarchy.py
+++ b/src/calibre/gui2/preferences/look_feel_tabs/tb_hierarchy.py
@@ -11,7 +11,7 @@
from qt.core import QListWidgetItem, Qt
from calibre.gui2 import choose_files, choose_save_file, error_dialog, gprefs
-from calibre.gui2.preferences import ConfigTabWidget
+from calibre.gui2.preferences import LazyConfigWidgetBase
from calibre.gui2.preferences.look_feel_tabs import DisplayedFields
from calibre.gui2.preferences.look_feel_tabs.tb_hierarchy_ui import Ui_Form
@@ -54,18 +54,16 @@ def commit(self):
# }}}
-class TbHierarchyTab(ConfigTabWidget, Ui_Form):
+class TbHierarchyTab(LazyConfigWidgetBase, Ui_Form):
def genesis(self, gui):
self.gui = gui
- self.tab_opened = False
self.tb_search_order_up_button.clicked.connect(self.move_tb_search_up)
self.tb_search_order_down_button.clicked.connect(self.move_tb_search_down)
self.tb_search_order.set_movement_functions(self.move_tb_search_up, self.move_tb_search_down)
self.tb_search_order_reset_button.clicked.connect(self.reset_tb_search_order)
- def lazy_populate_content(self):
- self.tab_opened = True
+ def lazy_initialize(self):
self.fill_tb_search_order_box()
self.tb_hierarchical_cats_model = TBHierarchicalFields(self.gui.current_db, self.tb_hierarchical_cats,
@@ -170,7 +168,10 @@ def import_layout(self, model=None):
error_dialog(self, _('Import layout'),
_('Could not read field list. Error:
%s')%err, show=True)
+ def restore_defaults(self):
+ self.tb_hierarchical_cats_model.restore_defaults()
+ self.reset_tb_search_order()
+
def commit(self):
- if self.tab_opened:
- self.tb_search_order_commit()
- self.tb_hierarchical_cats_model.commit()
+ self.tb_search_order_commit()
+ self.tb_hierarchical_cats_model.commit()
diff --git a/src/calibre/gui2/preferences/look_feel_tabs/tb_icon_rules.py b/src/calibre/gui2/preferences/look_feel_tabs/tb_icon_rules.py
index 5b9f7bed8538..f8b836172c07 100644
--- a/src/calibre/gui2/preferences/look_feel_tabs/tb_icon_rules.py
+++ b/src/calibre/gui2/preferences/look_feel_tabs/tb_icon_rules.py
@@ -2,7 +2,7 @@
__license__ = 'GPL v3'
-__copyright__ = '2010, Kovid Goyal '
+__copyright__ = '2025, Kovid Goyal '
__docformat__ = 'restructuredtext en'
import copy
@@ -14,7 +14,7 @@
from calibre.constants import config_dir
from calibre.db.constants import TEMPLATE_ICON_INDICATOR
from calibre.gui2 import gprefs
-from calibre.gui2.preferences import ConfigTabWidget, ConfigWidgetBase
+from calibre.gui2.preferences import ConfigWidgetBase, LazyConfigWidgetBase
from calibre.gui2.preferences.look_feel_tabs.tb_icon_rules_ui import Ui_Form
DELETED_COLUMN = 0
@@ -98,7 +98,7 @@ def __init__(self, txt, for_child):
self.setIcon(QIcon.cached_icon(icon))
-class TbIconRulesTab(ConfigTabWidget, Ui_Form):
+class TbIconRulesTab(LazyConfigWidgetBase, Ui_Form):
def genesis(self, gui):
self.gui = gui
@@ -147,7 +147,7 @@ def genesis(self, gui):
except Exception:
pass
- def lazy_populate_content(self):
+ def lazy_initialize(self):
field_metadata = self.gui.current_db.field_metadata
category_icons = self.gui.tags_view.model().category_custom_icons
v = gprefs['tags_browser_value_icons']
@@ -256,7 +256,6 @@ def do_sort(self, section):
self.rules_table.sortByColumn(FOR_CHILDREN_COLUMN, Qt.SortOrder(self.for_children_order))
def commit(self):
- rr = ConfigWidgetBase.commit(self)
v = copy.deepcopy(gprefs['tags_browser_value_icons'])
for r in range(self.rules_table.rowCount()):
cat_item = self.rules_table.item(r, CATEGORY_COLUMN)
@@ -275,4 +274,4 @@ def commit(self):
if len(v[category]) == 0:
v.pop(category, None)
gprefs['tags_browser_value_icons'] = v
- return rr
+ return ConfigWidgetBase.commit(self)
diff --git a/src/calibre/gui2/preferences/look_feel_tabs/tb_partitioning.py b/src/calibre/gui2/preferences/look_feel_tabs/tb_partitioning.py
new file mode 100644
index 000000000000..73a3691b3b0d
--- /dev/null
+++ b/src/calibre/gui2/preferences/look_feel_tabs/tb_partitioning.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+
+
+__license__ = 'GPL v3'
+__copyright__ = '2025, Kovid Goyal '
+__docformat__ = 'restructuredtext en'
+
+
+from functools import partial
+
+from calibre.gui2 import gprefs
+from calibre.gui2.preferences import ConfigWidgetBase, LazyConfigWidgetBase
+from calibre.gui2.preferences.look_feel_tabs import DisplayedFields, export_layout, import_layout, reset_layout
+from calibre.gui2.preferences.look_feel_tabs.tb_partitioning_ui import Ui_Form
+
+
+class TBPartitionedFields(DisplayedFields): # {{{
+ # The code in this class depends on the fact that the tag browser is
+ # initialized before this class is instantiated.
+
+ def __init__(self, db, parent=None, category_icons=None):
+ DisplayedFields.__init__(self, db, parent, category_icons=category_icons)
+ from calibre.gui2.ui import get_gui
+ self.gui = get_gui()
+
+ def filter_user_categories(self, tv):
+ cats = tv.model().categories
+ answer = {}
+ filtered = set()
+ for key,name in cats.items():
+ if key.startswith('@'):
+ key = key.partition('.')[0]
+ name = key[1:]
+ if key not in filtered:
+ answer[key] = name
+ filtered.add(key)
+ return answer
+
+ def initialize(self, use_defaults=False, pref_data_override=None):
+ tv = self.gui.tags_view
+ cats = self.filter_user_categories(tv)
+ ans = []
+ if use_defaults:
+ ans = [[k, True] for k in cats.keys()]
+ self.changed = True
+ elif pref_data_override:
+ po = {k:v for k,v in pref_data_override}
+ ans = [[k, po.get(k, True)] for k in cats.keys()]
+ self.changed = True
+ else:
+ # Check if setting not migrated yet
+ cats_to_partition = frozenset(self.db.prefs.get('tag_browser_dont_collapse', gprefs.get('tag_browser_dont_collapse')) or ())
+ for key in cats:
+ ans.append([key, key not in cats_to_partition])
+ self.beginResetModel()
+ self.fields = ans
+ self.endResetModel()
+
+ def commit(self):
+ if self.changed:
+ # Migrate to a per-library setting
+ self.db.prefs.set('tag_browser_dont_collapse', [k for k,v in self.fields if not v])
+# }}}
+
+
+class TbPartitioningTab(LazyConfigWidgetBase, Ui_Form):
+
+ def genesis(self, gui):
+ self.gui = gui
+ r = self.register
+
+ choices = [(_('Disabled'), 'disable'), (_('By first letter'), 'first letter'),
+ (_('Partitioned'), 'partition')]
+ r('tags_browser_partition_method', gprefs, choices=choices)
+ r('tags_browser_collapse_at', gprefs)
+ r('tags_browser_collapse_fl_at', gprefs)
+
+ self.tb_categories_to_part_model = TBPartitionedFields(self.gui.current_db,
+ self.tb_cats_to_partition,
+ category_icons=self.gui.tags_view.model().category_custom_icons)
+ self.tb_categories_to_part_model.dataChanged.connect(self.changed_signal)
+ self.tb_cats_to_partition.setModel(self.tb_categories_to_part_model)
+ self.tb_partition_reset_button.clicked.connect(partial(reset_layout, self,
+ model=self.tb_categories_to_part_model))
+ self.tb_partition_export_layout_button.clicked.connect(partial(export_layout, self,
+ model=self.tb_categories_to_part_model))
+ self.tb_partition_import_layout_button.clicked.connect(partial(import_layout, self,
+ model=self.tb_categories_to_part_model))
+
+ def lazy_initialize(self):
+ self.tb_categories_to_part_model.initialize()
+
+ def commit(self):
+ self.tb_categories_to_part_model.commit()
+ return ConfigWidgetBase.commit(self)
+
+
+
diff --git a/src/calibre/gui2/preferences/look_feel_tabs/tb_partitioning.ui b/src/calibre/gui2/preferences/look_feel_tabs/tb_partitioning.ui
new file mode 100644
index 000000000000..e93be6e29c87
--- /dev/null
+++ b/src/calibre/gui2/preferences/look_feel_tabs/tb_partitioning.ui
@@ -0,0 +1,176 @@
+
+
+ Form
+
+
+
+ 0
+ 0
+ 1035
+ 547
+
+
+
+ Form
+
+
+ -
+
+
-
+
+
+ QFormLayout::ExpandingFieldsGrow
+
+
-
+
+
+ &Category partitioning method:
+
+
+ opt_tags_browser_partition_method
+
+
+
+ -
+
+
+ <p>Choose how Tag browser subcategories are displayed when
+there are more items than the limit. Select by first
+letter to see an A, B, C list. Choose partitioned to
+have a list of fixed-sized groups. Set to disabled
+if you never want subcategories</p>
+
+
+
+ -
+
+
+ Combine letters &when fewer items than:
+
+
+ opt_tags_browser_collapse_fl_at
+
+
+
+ -
+
+
+ <p>If collapsing by first letter, combine adjacent letters together if
+there are fewer items under a letter than specified here. If the partition method is
+not set to first letter, this value is ignored. Set to zero to disable.</p>
+
+
+ 10000
+
+
+
+ -
+
+
+ Co&llapse when more items than:
+
+
+ opt_tags_browser_collapse_at
+
+
+
+ -
+
+
+ <p>If a Tag browser category has more than this number of items, it is divided
+up into subcategories. If the partition method is set to disable, this value is ignored.</p>
+
+
+ 10000
+
+
+
+
+
+ -
+
+
+ <p>Check the box for categories that are to
+be partitioned using the criteria above. Uncheck the box if you don't want to
+partition a category even if the number of items is larger than
+the value shown above. This option can be used to
+avoid collapsing hierarchical categories that have only
+a few top-level elements.</p>
+
+
+ Select categories to &partition:
+
+
+ tb_cats_to_partition
+
+
+
+ -
+
+
+
+ 0
+ 200
+
+
+
+ true
+
+
+
+ -
+
+
-
+
+
+ Click this button to reset the list to its default order.
+
+
+ Reset list
+
+
+
+ -
+
+
+ <p>Click this button to set the list to one
+previously exported. This could be useful if you have several libraries with
+similar structure and you want to use the same for each one.</p>
+
+
+ Import list
+
+
+
+ -
+
+
+ <p>Click this button to write the current display
+settings to a file. This could be useful if you have several libraries with similar
+structure and you want to use the same for each one.</p>
+
+
+ Export list
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/calibre/gui2/preferences/look_feel_tabs/tb_quickview.py b/src/calibre/gui2/preferences/look_feel_tabs/tb_quickview.py
new file mode 100644
index 000000000000..17dc7f4f0358
--- /dev/null
+++ b/src/calibre/gui2/preferences/look_feel_tabs/tb_quickview.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+
+
+__license__ = 'GPL v3'
+__copyright__ = '2025, Kovid Goyal '
+__docformat__ = 'restructuredtext en'
+
+from functools import partial
+
+from calibre.gui2 import gprefs
+from calibre.gui2.actions.show_quickview import get_quickview_action_plugin
+from calibre.gui2.dialogs.quickview import get_qv_field_list
+from calibre.gui2.preferences import LazyConfigWidgetBase, ConfigWidgetBase
+from calibre.gui2.preferences.look_feel_tabs import DisplayedFields, move_field_down, move_field_up
+from calibre.gui2.preferences.look_feel_tabs.tb_quickview_ui import Ui_Form
+
+class QVDisplayedFields(DisplayedFields): # {{{
+
+ def __init__(self, db, parent=None):
+ DisplayedFields.__init__(self, db, parent)
+
+ def initialize(self, use_defaults=False):
+ self.beginResetModel()
+ self.fields = [[x[0], x[1]] for x in
+ get_qv_field_list(self.db.field_metadata, use_defaults=use_defaults)]
+ self.endResetModel()
+ self.changed = True
+
+ def commit(self):
+ if self.changed:
+ self.db.new_api.set_pref('qv_display_fields', self.fields)
+
+# }}}
+
+
+class QuickviewTab(LazyConfigWidgetBase, Ui_Form):
+
+ def genesis(self, gui):
+ self.gui = gui
+ r = self.register
+
+ r('qv_respects_vls', gprefs)
+ r('qv_dclick_changes_column', gprefs)
+ r('qv_retkey_changes_column', gprefs)
+ r('qv_follows_column', gprefs)
+
+ self.qv_display_model = QVDisplayedFields(self.gui.current_db, self.qv_display_order)
+ self.qv_display_model.dataChanged.connect(self.changed_signal)
+ self.qv_display_order.setModel(self.qv_display_model)
+
+ mu = partial(move_field_up, self.qv_display_order, self.qv_display_model)
+ md = partial(move_field_down, self.qv_display_order, self.qv_display_model)
+ self.qv_display_order.set_movement_functions(mu, md)
+ self.qv_up_button.clicked.connect(mu)
+ self.qv_down_button.clicked.connect(md)
+
+ def lazy_initialize(self):
+ self.qv_display_model.initialize()
+
+ def restore_defaults(self):
+ ConfigWidgetBase.restore_defaults(self)
+ self.qv_display_model.restore_defaults()
+
+ def refresh_gui(self, gui):
+ qv = get_quickview_action_plugin()
+ if qv:
+ qv.refill_quickview()
+
+ def commit(self, *args):
+ rr = ConfigWidgetBase.commit(self, *args)
+ self.qv_display_model.commit()
+ return rr
+
+
diff --git a/src/calibre/gui2/preferences/look_feel_tabs/tb_quickview.ui b/src/calibre/gui2/preferences/look_feel_tabs/tb_quickview.ui
new file mode 100644
index 000000000000..cf4a3174ec7d
--- /dev/null
+++ b/src/calibre/gui2/preferences/look_feel_tabs/tb_quickview.ui
@@ -0,0 +1,125 @@
+
+
+ Form
+
+
+
+ :/images/cover_flow.png:/images/cover_flow.png
+
+
+ -
+
+
-
+
+
+ <p>Check this box to make Quickview show books only in the
+current Virtual library. If unchecked, Quickview ignores Virtual libraries. If
+unchecked then only row changes are taken into account.</p>
+
+
+ &Apply Virtual libraries
+
+
+
+ -
+
+
+ <p>Check this box to make Quickview change the column being examined
+when the column in the book list is changed using the cursor arrow keys</p>
+
+
+ &Change Quickview item when book list column changes
+
+
+
+ -
+
+
+ <p>Pressing Enter in a cell changes both the book and the
+column being examined (the left-hand panel)</p>
+
+
+ &Pressing Enter changes the examined column
+
+
+
+ -
+
+
+ <p>Double-clicking in a cell changes both the book and the
+column being examined (the left-hand panel)</p>
+
+
+ &Double click changes examined column
+
+
+
+
+
+ -
+
+
+ Select columns to display
+
+
+
-
+
+
+ Move up. Keyboard shortcut: Ctrl-Up arrow
+
+
+
+ :/images/arrow-up.png:/images/arrow-up.png
+
+
+
+ -
+
+
+ Move down. Keyboard shortcut: Ctrl-Down arrow
+
+
+
+ :/images/arrow-down.png:/images/arrow-down.png
+
+
+
+ -
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+
+
+ ListViewWithMoveByKeyPress
+ QListView
+ calibre/gui2/preferences.h
+
+
+ ListWidgetWithMoveByKeyPress
+ QListWidget
+ calibre/gui2/preferences.h
+
+
+
+
\ No newline at end of file
diff --git a/src/calibre/gui2/preferences/main.py b/src/calibre/gui2/preferences/main.py
index caf6d121e7a0..91ee4407a8ef 100644
--- a/src/calibre/gui2/preferences/main.py
+++ b/src/calibre/gui2/preferences/main.py
@@ -418,6 +418,7 @@ def commit(self, *args):
return self.close_after_initial or (must_restart and rc) or do_restart
def restore_defaults(self, *args):
+ self.showing_widget.do_on_child_tabs('restore_defaults')
self.showing_widget.restore_defaults()
def on_shutdown(self):