01-30-2022, 08:22 AM | #811 |
Custom User Title
Posts: 8,643
Karma: 61234567
Join Date: Oct 2018
Location: Canada
Device: Kobo Libra H2O, formerly Aura HD
|
Ah, so I should continue using the module for it?
|
01-30-2022, 08:52 AM | #812 |
Wizard
Posts: 1,092
Karma: 1948136
Join Date: Aug 2015
Device: Kindle
|
Just choose the template option, open the template editor and type the predefined location there. It should work the same.
|
Advert | |
|
01-30-2022, 04:55 PM | #813 |
Custom User Title
Posts: 8,643
Karma: 61234567
Join Date: Oct 2018
Location: Canada
Device: Kobo Libra H2O, formerly Aura HD
|
Thanks.
Question: Will the modules using Qt5 imports continue to work when Calibre goes Qt6? |
01-30-2022, 05:28 PM | #814 |
Wizard
Posts: 1,092
Karma: 1948136
Join Date: Aug 2015
Device: Kindle
|
Most of them will work fine with the old import statements (thanks to work by Kovid). But some needed more updates in order to work with the new version.
I updated the import statments for all of them in the Action Chains Scripts thread, but some of them (don't currently remember which ones), needed more changes to be PyQt6 compatible. It is safer to update your modules, by copying the new updated code. |
01-30-2022, 06:01 PM | #815 |
Custom User Title
Posts: 8,643
Karma: 61234567
Join Date: Oct 2018
Location: Canada
Device: Kobo Libra H2O, formerly Aura HD
|
Thanks. Should I update #25 (prompt for action) by copying the updated bits from #6 (prompt for confirmation)?
|
Advert | |
|
01-30-2022, 07:01 PM | #816 |
Wizard
Posts: 1,092
Karma: 1948136
Join Date: Aug 2015
Device: Kindle
|
I edited post #25 to update the import statement. Note that the old import (from PyQt5.Qt import ...) should still work with calibre 6.
|
01-30-2022, 10:28 PM | #817 |
Custom User Title
Posts: 8,643
Karma: 61234567
Join Date: Oct 2018
Location: Canada
Device: Kobo Libra H2O, formerly Aura HD
|
Hm, when using single-field edit to put a file-path into 'formats,' I get this error
Code:
calibre, version 5.35.0 ERROR: Unhandled exception: <b>NameError</b>:name 'cover_path' is not defined calibre 5.35* [64bit] embedded-python: True is64bit: True Windows-10-10.0.19041 Windows ('64bit', 'WindowsPE') ('Windows', '10', '10.0.19041') Python 3.8.5 Windows: ('10', '10.0.19041', '', 'Multiprocessor Free') Interface language: None Successfully initialized third party plugins: DeACSM (0, 0, 15) && DeDRM (7, 2, 1) && Action Chains (1, 16, 0) && Barnes & Noble (1, 2, 16) && Calibre Power Search Plugin (2, 1, 1) && Comments Cleaner (1, 6, 1) && Count Pages (1, 11, 2) && Embed Comic Metadata (1, 6, 1) && EpubCheck (0, 2, 4) && EpubMerge (2, 12, 0) && Extract ISBN (1, 5, 0) && FanFicFare (4, 9, 0) && Fantastic Fiction (1, 5, 1) && Favourites Menu (1, 1, 0) && Find Duplicates (1, 9, 2) && Generate Cover (2, 1, 0) && GetFileName (0, 1, 1) && Goodreads (1, 5, 3) && Import List (1, 8, 1) && Job Spy (1, 0, 190) && Kindle hi-res covers (0, 5, 0) && Kobo Books (1, 8, 3) && Kobo Utilities (2, 15, 1) && KoboTouchExtended (3, 5, 4) && Last Modified (0, 8, 1) && Manage Series (1, 3, 0) && Modify ePub (1, 7, 0) && Obok DeDRM (7, 2, 1) && Open With (1, 5, 13) && Overdrive Link (2, 50, 0) && Quality Check (1, 12, 0) && Reading List (1, 8, 0) && Search The Internet (1, 8, 1) && SmartEject (2, 4, 0) && Standard Ebooks (1, 0, 0) && Sum Column (0, 3, 1) && View Manager (1, 7, 0) && Walk Search History (1, 3, 2) && Overdrive Link* (2, 50, 0) Traceback (most recent call last): File "calibre_plugins.action_chains.action", line 455, in run_chain File "calibre_plugins.action_chains.chains", line 390, in run File "calibre_plugins.action_chains.chains", line 205, in _run_loop File "calibre_plugins.action_chains.chains", line 182, in _run_loop File "calibre_plugins.action_chains.actions.single_field", line 398, in run File "calibre_plugins.action_chains.actions.single_field", line 147, in template_to_field NameError: name 'cover_path' is not defined Code:
D:\Documents\Miscellany\paperbook.paperbook Code:
"D:\Documents\Miscellany\paperbook.paperbook" Code:
program: "D:\Documents\Miscellany\paperbook.paperbook" |
01-31-2022, 06:44 AM | #818 |
Wizard
Posts: 1,092
Karma: 1948136
Join Date: Aug 2015
Device: Kindle
|
Version 1.16.2
Fix: Single Field Edit: bug when using template option to add a format.
|
01-31-2022, 07:43 AM | #819 |
Custom User Title
Posts: 8,643
Karma: 61234567
Join Date: Oct 2018
Location: Canada
Device: Kobo Libra H2O, formerly Aura HD
|
That works! I had to remove the quotes though -- this path has no spaces but do I need to do anything differently if there is?
|
01-31-2022, 08:02 AM | #820 |
Grand Sorcerer
Posts: 11,742
Karma: 6997045
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
If you are using your first example and not the program: one then it is a SFM template. Text in SFM templates is used unchanged, assuming there aren't any {} in it. That is why you had to remove the quotes. Spaces don't matter.
|
02-01-2022, 08:00 PM | #821 |
Custom User Title
Posts: 8,643
Karma: 61234567
Join Date: Oct 2018
Location: Canada
Device: Kobo Libra H2O, formerly Aura HD
|
Possible oversight: Duplicating a blank 'separator' item creates a new chain called (copy).
Last edited by ownedbycats; 02-01-2022 at 09:25 PM. |
02-04-2022, 06:08 AM | #822 |
Custom User Title
Posts: 8,643
Karma: 61234567
Join Date: Oct 2018
Location: Canada
Device: Kobo Libra H2O, formerly Aura HD
|
Can a module be used to switch to specifically grid or list view?
Last edited by ownedbycats; 02-04-2022 at 10:59 AM. |
02-04-2022, 11:35 AM | #823 |
Wizard
Posts: 1,092
Karma: 1948136
Join Date: Aug 2015
Device: Kindle
|
I have an alternative — incomplete — implementation for Calibre Actions (You can call it calibre actions 2), that exposes more actions, including toggling the cover grid.
Code:
#!/usr/bin/env python # ~*~ coding: utf-8 ~*~ __license__ = 'GPL v3' __copyright__ = '2021, Ahmed Zaki <azaki00.dev@gmail.com>' __docformat__ = 'restructuredtext en' import re from qt.core import (QApplication, Qt, QWidget, QGridLayout, QHBoxLayout, QVBoxLayout, QDialog, QDialogButtonBox, QMenu, QPainter, QPoint, QPixmap, QSize, QIcon, QTreeWidgetItem, QTreeWidget, QAbstractItemView, QGroupBox, QCheckBox, QLabel, QAction) from calibre import prints from calibre.constants import DEBUG from calibre.gui2 import error_dialog from calibre_plugins.action_chains.actions.base import ChainAction from calibre_plugins.action_chains.common_utils import get_icon try: load_translations() except NameError: prints("ActionChains::actions/calibre_actions2.py - exception when loading translations") EXCLUDED_GROUPS = [ 'Action Chains' ] ICON_SIZE = 32 def get_qaction_from_unique_name(gui, unique_name): if unique_name.startswith('location_manager'): actions = gui.location_manager.all_actions[1:] for ac in actions: if 'location_manager:'+ac.calibre_name == unique_name: return ac else: shortcut = gui.keyboard.shortcuts[unique_name] ac = shortcut['action'] return ac def all_unique_names(gui): unique_names = [] for group in gui.keyboard.groups.keys(): unique_names.extend([x for x in gui.keyboard.groups[group]]) location_manager_actions = gui.location_manager.all_actions[1:] location_manager_unique_names = ['location_manager:'+action.calibre_name for action in location_manager_actions] unique_names += location_manager_unique_names return unique_names def validate(gui, settings, check_device_active=True): if not settings: return (_('Settings Error'), _('You must configure this action before running it')) unique_name = settings['unique_name'] if unique_name not in all_unique_names(gui): return (_('Settings Error'), _('Action cannot be found: {}'.format(unique_name))) ac = get_qaction_from_unique_name(gui, unique_name) if not ac: return (_('Settings Error'), _('Menu entry: ({}) cannot be found'.format(unique_name))) if unique_name.startswith('location_manager'): if check_device_active: if not gui.location_manager.has_device: return (_('Device Error'), _('This action ({}) is only available when device view is active'.format(unique_name))) return True class Item(QTreeWidgetItem): pass class ConfigWidget(QWidget): def __init__(self, plugin_action): QWidget.__init__(self) self.plugin_action = plugin_action self.gui = plugin_action.gui self.all_nodes = {} # used to keep track of selected item and allow only one selection self.checked_item = None self._init_controls() def _init_controls(self): self.blank_icon = QIcon(I('blank.png')) l = self.l = QVBoxLayout() self.setLayout(l) self.tv = QTreeWidget(self.gui) self.tv.setIconSize(QSize(ICON_SIZE, ICON_SIZE)) self.tv.header().hide() self.tv.setSelectionMode(QAbstractItemView.SingleSelection) l.addWidget(self.tv, 1) self.tv.itemChanged.connect(self._tree_item_changed) self._populate_actions_tree() def _get_scaled_icon(self, icon): if icon.isNull(): return self.blank_icon # We need the icon scaled to 16x16 src = icon.pixmap(ICON_SIZE, ICON_SIZE) if src.width() == ICON_SIZE and src.height() == ICON_SIZE: return icon # Need a new version of the icon pm = QPixmap(ICON_SIZE, ICON_SIZE) pm.fill(Qt.transparent) p = QPainter(pm) p.drawPixmap(QPoint(int((ICON_SIZE - src.width()) / 2), int((ICON_SIZE - src.height()) / 2)), src) p.end() return QIcon(pm) def set_checked_state(self, item, col, state): item.setCheckState(col, state) if state == Qt.Checked: self.checked_item = item else: self.checked_item = None def _populate_actions_tree(self): self.top_level_items_map = {} for group in sorted(self.gui.keyboard.groups.keys()): if group in EXCLUDED_GROUPS: continue # Create a node for our top level plugin name tl = Item() tl.setText(0, group) # Normal top-level checkable plugin iaction handling tl.setFlags(Qt.ItemIsEnabled) unique_names = self.gui.keyboard.groups[group] #unique_names = group_unique_names(self.gui, group) # Iterate through all the children of this node self._populate_action_children(unique_names, tl) self.tv.addTopLevelItem(tl) self.populate_location_manager() def populate_location_manager(self): # Create a node for our top level plugin name tl = Item() tl.setText(0, 'Location Manager') # Normal top-level checkable plugin iaction handling tl.setFlags(Qt.ItemIsEnabled) actions = self.gui.location_manager.all_actions[1:] unique_names = ['location_manager:'+action.calibre_name for action in actions] # Iterate through all the children of this node self._populate_action_children(unique_names, tl) self.tv.addTopLevelItem(tl) def _populate_action_children(self, unique_names, parent): for unique_name in unique_names: ac = get_qaction_from_unique_name(self.gui, unique_name) text = ac.text().replace('&', '') if not text: text = unique_name it = Item(parent) it.setText(0, text) it.setData(0, Qt.UserRole, unique_name) it.setFlags(Qt.ItemIsEnabled | Qt.ItemIsUserCheckable) it.setCheckState(0, Qt.Unchecked) it.setIcon(0, self._get_scaled_icon(ac.icon())) self.all_nodes[unique_name] = it def _tree_item_changed(self, item, column): # Checkstate has been changed is_checked = item.checkState(column) == Qt.Checked #text = str(item.text(column)).replace('&', '') unique_name = item.data(column, Qt.UserRole) if is_checked: # un-check previously checked item if any if self.checked_item: self.tv.blockSignals(True) self.checked_item.setCheckState(0, Qt.Unchecked) self.tv.blockSignals(False) self.checked_item = item else: self.checked_item = None def _repopulate_actions_tree(self): self.tv.clear() self._populate_actions_tree() def set_unique_name_checked(self, unique_name): it = self.all_nodes.get(unique_name) if it: self.set_checked_state(it, 0, Qt.Checked) self.tv.setCurrentItem(it) def load_settings(self, settings): if settings: #self.cursor_chk.setChecked(settings.get('disable_busy_cursor', False)) #self._repopulate_actions_tree() self.set_unique_name_checked(settings['unique_name']) def save_settings(self): settings = {} settings['unique_name'] = self.checked_item.data(0, Qt.UserRole) #settings['disable_busy_cursor'] = self.cursor_chk.isChecked() return settings def validate(self, settings): gui = self.plugin_action.gui return validate(gui, settings, check_device_active=False) class CalibreActions(ChainAction): name = 'Calibre Actions 2' #_is_builtin = True def run(self, gui, settings, chain): unique_name = settings['unique_name'] if unique_name.startswith('location_manager'): if not gui.location_manager.has_device: if DEBUG: prints('This action ({}) is only available when device view is active'.format(unique_name)) return ac = get_qaction_from_unique_name(chain.gui, unique_name) if ac: if DEBUG: prints('Action Chains: Calibre Actions: Found action: {}'.format(ac.text().replace('&', ''))) cursor = Qt.WaitCursor if settings.get('disable_busy_cursor'): cursor = Qt.ArrowCursor QApplication.setOverrideCursor(cursor) try: ac.trigger() finally: QApplication.restoreOverrideCursor() if DEBUG: prints('Action Chains: Calibre Actions: Finishing run action') def validate(self, settings): gui = self.plugin_action.gui return validate(gui, settings, check_device_active=True) def config_widget(self): return ConfigWidget Note, this is an abandoned incomplete implementation which lacks some features compared to the builtin Calibre Actions:
So, better to always use the builtin Calibre Actions and only use this implementation for extra actions. Note: you can find the toggle cover view grid action under the miscellaneous node. |
02-04-2022, 11:44 AM | #824 |
Custom User Title
Posts: 8,643
Karma: 61234567
Join Date: Oct 2018
Location: Canada
Device: Kobo Libra H2O, formerly Aura HD
|
Thanks. I used it and event manager to enable grid mode when starting Calibre. Well, unless I exit while it's in grid mode, then I get the list instead.
Last edited by ownedbycats; 02-04-2022 at 11:46 AM. |
02-10-2022, 08:24 AM | #825 |
Custom User Title
Posts: 8,643
Karma: 61234567
Join Date: Oct 2018
Location: Canada
Device: Kobo Libra H2O, formerly Aura HD
|
Small question: Is there a way to ensure that 'Edit ToC' Calibre action opens up in the foreground? For some reason, about half the time it immediately minimizes itself.
|
|
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
[Editor Plugin] Editor Chains | capink | Plugins | 86 | Today 05:54 PM |
Action Chains Resources | capink | Plugins | 54 | 01-29-2024 11:24 PM |
[GUI Plugin] Noosfere_util, a companion plugin to noosfere DB | lrpirlet | Plugins | 2 | 08-18-2022 03:15 PM |
[GUI Plugin] Save Virtual Libraries To Column (GUI) | chaley | Plugins | 14 | 04-04-2021 05:25 AM |