Quote:
Originally Posted by thiago.eec
2) Call other plugin's action (like running Epubcheck or ACE).
|
There is a custom action you can add that would do what you want. Go to Editor Chains > Manage Modules > Create > Copy/Paste the following:
Code:
#!/usr/bin/env python
# ~*~ coding: utf-8 ~*~
from __future__ import (unicode_literals, division, absolute_import,
print_function)
import re
# python 3 compatibility
from six import text_type as unicode
from PyQt5.Qt 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.editor_chains.actions.base import EditorAction
from calibre_plugins.editor_chains.common_utils import get_icon
try:
load_translations()
except NameError:
prints("EditorChains::actions/editor_actions.py - exception when loading translations")
EXCLUDED_GROUPS = [
'Editor Chains',
'Editor actions',
'Windows',
'Preview',
'Search'
]
ICON_SIZE = 32
def group_unique_names(gui, group):
menu_actions = [x for x in gui.__dict__.values() if isinstance(x, QAction)]
menu_unique_names = [re.sub(r'^action\-', r'', x.objectName()) for x in menu_actions]
if group == 'Plugins':
unique_names = [x for x in gui.keyboard.groups['Plugins']]
else:
unique_names = [x for x in gui.keyboard.groups[group] if x in menu_unique_names]
return unique_names
def get_qaction_from_unique_name(gui, unique_name):
shortcut = gui.keyboard.shortcuts[unique_name]
ac = shortcut['action']
return ac
def allowed_unique_names(gui):
unique_names = []
for group in gui.keyboard.groups.keys():
unique_names.extend(group_unique_names(gui, group))
unique_names += [x for x in gui.keyboard.groups['Plugins']]
return unique_names
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)
# opts_groupbox = QGroupBox()
# l.addWidget(opts_groupbox)
# opts_groupbox_layout = QVBoxLayout()
# opts_groupbox.setLayout(opts_groupbox_layout)
# cursor_chk = self.cursor_chk = QCheckBox(_('Disable wait cursor for this action.'))
# opts_groupbox_layout.addWidget(cursor_chk)
# cursor_chk.setChecked(False)
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)
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('&', '')
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 = unicode(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 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 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)
class EditorActions(EditorAction):
name = 'Editor Actions'
#_is_builtin = True
def run(self, chain, settings):
ac = get_qaction_from_unique_name(chain.gui, settings['unique_name'])
if ac:
if DEBUG:
prints('Editor Chains: Editor 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('Editor Chains: Editor Actions: Finishing run action')
def validate(self, settings):
gui = self.plugin_action.gui
if not settings:
return (_('Settings Error'), _('You must configure this action before running it'))
if settings['unique_name'] not in allowed_unique_names(gui):
return (_('Settings Error'), _('Action cannot be found: {}'.format(settings['unique_name'])))
return True
def config_widget(self):
return ConfigWidget
Notes:- If any of the plugins/actions you call require user interaction, you'll have to do it. There is no way to automate this.
- If you are familiar with Action Chains, this action is similar to an action called "Calibre Actions" in that plugin. I did not include this action in Editor Chains by default, nor I have plans to so. This is because in retrospect, including "Calibre Actions" in Actions Chains plugin is the main thing I regret, for several reasons.
Quote:
Originally Posted by thiago.eec
1) Add the 'Check book' action
|
The action provided above should enable you to call check books, but it will not allow for automatic repair, unless you click the hyperlink to do so.
A more sophisticated version with options and automatic repair without clicking should be possible, I guess. But I am not familiar with that part of calibre code. If you are interested, you can add it as a custom action, through modules as in the action provided above.
Hope that helps.
Edit: Similar to Action Chains, this plugin provides an API for other plugins to provide actions for Editor Chains. A plugin developer needs the following to add actions:
- Create a file called editor_chains.py in the root of the plugin folder.
- Include all the actions he want in the above file.
- Now in Editor Chains, the actions will appear under "Imported From Other Plugins" node.
The file editor_chains/actions/base.py provides instructions on how to write actions. You can also examine any of the actions in the editor_chain/actions for examples. The main method you need to implement is run(). If the you want the action to provide options for the user, also take a look at config_widget().