|
|
#811 |
|
Custom User Title
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 11,382
Karma: 79699999
Join Date: Oct 2018
Location: Canada
Device: Kobo Libra H2O, formerly Aura HD
|
Ah, so I should continue using the module for it?
|
|
|
|
|
|
#812 |
|
Wizard
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 1,216
Karma: 1995558
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 | |
|
|
|
|
#813 |
|
Custom User Title
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 11,382
Karma: 79699999
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? |
|
|
|
|
|
#814 |
|
Wizard
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 1,216
Karma: 1995558
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. |
|
|
|
|
|
#815 |
|
Custom User Title
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 11,382
Karma: 79699999
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 | |
|
|
|
|
#816 |
|
Wizard
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 1,216
Karma: 1995558
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.
|
|
|
|
|
|
#817 |
|
Custom User Title
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 11,382
Karma: 79699999
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" |
|
|
|
|
|
#818 |
|
Wizard
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 1,216
Karma: 1995558
Join Date: Aug 2015
Device: Kindle
|
Version 1.16.2
Fix: Single Field Edit: bug when using template option to add a format.
|
|
|
|
|
|
#819 |
|
Custom User Title
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 11,382
Karma: 79699999
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?
|
|
|
|
|
|
#820 |
|
Grand Sorcerer
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 12,528
Karma: 8065948
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.
|
|
|
|
|
|
#821 |
|
Custom User Title
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 11,382
Karma: 79699999
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 10:25 PM. |
|
|
|
|
|
#822 |
|
Custom User Title
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 11,382
Karma: 79699999
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 11:59 AM. |
|
|
|
|
|
#823 |
|
Wizard
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 1,216
Karma: 1995558
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. |
|
|
|
|
|
#824 |
|
Custom User Title
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 11,382
Karma: 79699999
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 12:46 PM. |
|
|
|
|
|
#825 |
|
Custom User Title
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 11,382
Karma: 79699999
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 |
| Action Chains Resources | capink | Plugins | 80 | 09-18-2025 05:45 AM |
| [Editor Plugin] Editor Chains | capink | Plugins | 106 | 06-17-2025 06:36 PM |
| [GUI Plugin] Noosfere_util, a companion plugin to noosfere DB | lrpirlet | Plugins | 2 | 08-18-2022 04:15 PM |
| [GUI Plugin] Save Virtual Libraries To Column (GUI) | chaley | Plugins | 14 | 04-04-2021 06:25 AM |