Permalink
Browse files

Edit book: Add a tool to insert arbitrary unicode characters, such as…

… special spaces or punctuation or characters from non-English languages into the text
  • Loading branch information...
1 parent c06d44d commit 0012f5cc4ba97eeee7a4c397ec091b0fff942d47 @kovidgoyal committed Jan 6, 2014
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 12.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 51448) -->
+
+<svg
+ xmlns:ns="http://ns.adobe.com/SaveForWeb/1.0/"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.0"
+ id="Livello_1"
+ width="128"
+ height="128"
+ viewBox="0 0 124.176 66.475"
+ overflow="visible"
+ enable-background="new 0 0 124.176 66.475"
+ xml:space="preserve"
+ sodipodi:version="0.32"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="character-set.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ sodipodi:modified="true"
+ inkscape:export-filename="/home/kovid/work/calibre/resources/images/character-set.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"><defs
+ id="defs29"><linearGradient
+ id="linearGradient3291"
+ inkscape:collect="always"><stop
+ id="stop3293"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" /><stop
+ id="stop3295"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" /></linearGradient><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3291"
+ id="radialGradient3336"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.197802,0,92.82166)"
+ cx="63.912209"
+ cy="115.70919"
+ fx="63.912209"
+ fy="115.7093"
+ r="63.912209" /><linearGradient
+ y2="0.00048828119"
+ x2="22.481001"
+ y1="65.662102"
+ x1="22.481001"
+ gradientUnits="userSpaceOnUse"
+ id="XMLID_4_"><stop
+ id="stop8"
+ style="stop-color:#2E3436"
+ offset="0" /><stop
+ id="stop10"
+ style="stop-color:#000000"
+ offset="1" /></linearGradient><linearGradient
+ y2="15.8804"
+ x2="64.6689"
+ y1="65.662102"
+ x1="64.6689"
+ gradientUnits="userSpaceOnUse"
+ id="XMLID_5_"
+ gradientTransform="matrix(1,0,0,1.0133482,0,1.6235306)"><stop
+ id="stop15"
+ style="stop-color:#2E3436"
+ offset="0" /><stop
+ id="stop17"
+ style="stop-color:#000000"
+ offset="1" /></linearGradient><linearGradient
+ y2="4.2846999"
+ x2="104.2773"
+ y1="66.474602"
+ x1="104.2773"
+ gradientUnits="userSpaceOnUse"
+ id="XMLID_6_"
+ gradientTransform="translate(0,1.687)"><stop
+ id="stop22"
+ style="stop-color:#2E3436"
+ offset="0" /><stop
+ id="stop24"
+ style="stop-color:#000000"
+ offset="1" /></linearGradient><linearGradient
+ inkscape:collect="always"
+ xlink:href="#XMLID_4_"
+ id="linearGradient2218"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,-1.0127815,0,68.971157)"
+ x1="38.609329"
+ y1="0.79894531"
+ x2="38.366798"
+ y2="50.62952" /><linearGradient
+ inkscape:collect="always"
+ xlink:href="#XMLID_6_"
+ id="linearGradient2253"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.9813158,0,2.9290339)"
+ x1="104.2773"
+ y1="66.474602"
+ x2="104.39857"
+ y2="15.9262" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3291"
+ id="radialGradient4261"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.197802,0,92.82166)"
+ cx="63.912209"
+ cy="115.70919"
+ fx="63.912209"
+ fy="115.7093"
+ r="63.912209" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3291"
+ id="radialGradient4265"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.197802,0,92.82166)"
+ cx="63.912209"
+ cy="115.70919"
+ fx="63.912209"
+ fy="115.7093"
+ r="63.912209" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3291"
+ id="radialGradient4268"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.197802,0,92.82166)"
+ cx="63.912209"
+ cy="115.70919"
+ fx="63.912209"
+ fy="115.7093"
+ r="63.912209" /></defs><sodipodi:namedview
+ inkscape:window-height="1058"
+ inkscape:window-width="1920"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="10.0"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ width="128px"
+ height="128px"
+ borderlayer="false"
+ inkscape:showpageshadow="false"
+ showgrid="true"
+ inkscape:zoom="3.8359375"
+ inkscape:cx="64"
+ inkscape:cy="64"
+ inkscape:window-x="0"
+ inkscape:window-y="22"
+ inkscape:current-layer="Livello_1"
+ inkscape:window-maximized="0"><inkscape:grid
+ id="GridFromPre046Settings"
+ type="xygrid"
+ originx="0px"
+ originy="0px"
+ spacingx="4px"
+ spacingy="4px"
+ color="#3f3fff"
+ empcolor="#3f3fff"
+ opacity="0.15"
+ empopacity="0.38"
+ empspacing="0" /></sodipodi:namedview><metadata
+ id="metadata3"><ns:sfw><ns:slices /><ns:sliceSourceBounds
+ x="1.912"
+ y="30.763"
+ height="66.475"
+ width="124.176"
+ bottomLeftOrigin="true" /></ns:sfw><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><path
+ style="fill:url(#linearGradient2218)"
+ d="M 16.401176,17.7155 L 0,68.162 L 9.6406172,68.162 L 14.036496,53.853984 L 30.316406,53.853984 L 34.9245,68.162 L 44.95923,68.162 L 28.315523,17.7155 L 16.401176,17.7155 z M 21.949078,25.053731 L 22.10066,25.053731 C 22.86066,27.971554 23.690555,31.413123 24.677555,34.479827 L 28.709637,46.914905 L 15.582633,46.914905 L 19.523766,34.479827 C 20.434765,31.48807 21.190078,27.971554 21.949078,25.053731 z "
+ id="path2200" /><path
+ style="fill:#000000;fill-opacity:1"
+ d="M 23.1875 28 C 17.786134 28 14.719782 31.645231 14.71875 36.15625 C 14.71875 40.496737 17.942815 44 23.1875 44 C 28.354875 44 31.624999 40.519503 31.625 36.09375 C 31.625 31.583884 28.651366 28 23.25 28 L 23.1875 28 z M 23.0625 32 L 23.15625 32 C 25.677144 32 27.15625 33.919307 27.15625 36 C 27.15625 38.23883 25.677144 40 23.15625 40 C 20.721219 40 19.15625 38.075555 19.15625 36.15625 C 19.15625 33.996488 20.540461 32 23.0625 32 z "
+ transform="matrix(0.970125,0,0,0.970125,0,-28.8505)"
+ id="path2228" /><path
+ style="fill:url(#XMLID_5_)"
+ id="path19"
+ d="M 52.479,68.162 L 52.479,49.375538 L 46.479,53.567759 L 46.479,46.980996 L 52.479,42.788774 L 52.479,17.7155 L 61.821,17.7155 L 61.821,36.57695 L 71.694,29.841225 L 71.694,36.501962 L 61.821,43.237688 L 61.821,60.452447 L 82.859,60.452447 L 82.859,68.160987 L 52.479,68.160987 L 52.479,68.162 z " /><path
+ style="fill:url(#linearGradient2253)"
+ d="M 123.72,65.914787 C 121.518,67.002085 116.658,68.162 110.505,68.162 C 94.252,68.162 84.379,58.3773 84.379,43.519198 C 84.379,27.428564 96.075,17.7155 111.72,17.7155 C 117.872,17.7155 122.278,18.948033 124.176,19.890096 L 122.125,26.992859 C 119.694,25.978179 116.354,25.108733 112.1,25.108733 C 101.696,25.108733 94.176,31.342051 94.176,43.083494 C 94.176,53.811238 100.783,60.69615 112.025,60.69615 C 115.822,60.69615 119.771,59.970957 122.202,58.883659 L 123.72,65.914787 z "
+ id="path2222" /><path
+ style="fill:#000000;fill-opacity:1"
+ d="M 105.08728,13.835 L 97.0125,2.1935 L 104.22438,2.1935 L 108.69271,8.6506979 L 108.8496,8.6506979 L 113.16104,2.1935 L 120.2955,2.1935 L 112.37761,13.835 L 105.08728,13.835 z "
+ id="path26" /><path
+ sodipodi:type="arc"
+ style="opacity:0.38139535;fill:url(#radialGradient4268);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
+ id="path1563"
+ sodipodi:cx="63.912209"
+ sodipodi:cy="115.70919"
+ sodipodi:rx="63.912209"
+ sodipodi:ry="12.641975"
+ d="M 127.82442 115.70919 A 63.912209 12.641975 0 1 1 0,115.70919 A 63.912209 12.641975 0 1 1 127.82442 115.70919 z"
+ transform="matrix(0.971458,0,0,0.3981189,-2.6300491e-5,44.226475)" /></svg>
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -1068,6 +1068,9 @@ def close_editor(self, name):
if not editors:
self.gui.preview.clear()
+ def insert_character(self):
+ self.gui.insert_char.show()
+
# Shutdown {{{
def quit(self):
if not self.confirm_quit():
@@ -6,7 +6,7 @@
__license__ = 'GPL v3'
__copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
-import unicodedata, re
+import unicodedata, re, weakref
from bisect import bisect
from functools import partial
@@ -548,6 +548,7 @@ def paint_non_printing(self, painter, option, charcode):
class CharView(QListView):
show_name = pyqtSignal(object)
+ char_selected = pyqtSignal(object)
def __init__(self, parent=None):
self.last_mouse_idx = -1
@@ -564,6 +565,16 @@ def __init__(self, parent=None):
self.setContextMenuPolicy(Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self.context_menu)
self.showing_favorites = False
+ pi = plugins['progress_indicator'][0]
+ if hasattr(pi, 'set_no_activate_on_click'):
+ pi.set_no_activate_on_click(self)
+ self.activated.connect(self.item_activated)
+ self.clicked.connect(self.item_activated)
+
+ def item_activated(self, index):
+ char_code, ok = self.model().data(index, Qt.UserRole).toInt()
+ if ok:
+ self.char_selected.emit(chr(char_code))
def set_allow_drag_and_drop(self, enabled):
if not enabled:
@@ -640,6 +651,8 @@ class CharSelect(Dialog):
def __init__(self, parent=None):
self.initialized = False
Dialog.__init__(self, _('Insert character'), 'charmap_dialog', parent)
+ self.setWindowIcon(QIcon(I('character-set.png')))
+ self.focus_widget = None
def setup_ui(self):
self.l = l = QGridLayout(self)
@@ -650,6 +663,7 @@ def setup_ui(self):
b.setCheckable(True)
b.setChecked(False)
b.setVisible(False)
+ b.setDefault(True)
self.splitter = s = QSplitter(self)
s.setChildrenCollapsible(False)
@@ -660,6 +674,7 @@ def setup_ui(self):
self.rearrange_button.toggled[bool].connect(self.set_allow_drag_and_drop)
self.category_view.category_selected.connect(self.show_chars)
self.char_view.show_name.connect(self.show_char_info)
+ self.char_view.char_selected.connect(self.char_selected)
s.addWidget(self.category_view), s.addWidget(self.char_view)
self.char_info = la = QLabel('\xa0')
@@ -701,10 +716,29 @@ def show_char_info(self, char_code):
self.char_info.clear()
def show(self):
+ try:
+ self.focus_widget = weakref.ref(QApplication.focusWidget())
+ except TypeError:
+ self.focus_widget = None
self.initialize()
Dialog.show(self)
self.raise_()
+ def char_selected(self, c):
+ if QApplication.keyboardModifiers() & Qt.CTRL:
+ self.hide()
+ if self.focus_widget is None or self.focus_widget() is None:
+ QApplication.clipboard().setText(c)
+ return
+ w = self.focus_widget()
+ if hasattr(w, 'textCursor'):
+ cr = w.textCursor()
+ cr.insertText(c)
+ w.setTextCursor(cr)
+ elif hasattr(w, 'insert'):
+ w.insert(c)
+
+
if __name__ == '__main__':
app = QApplication([])
w = CharSelect()
@@ -29,6 +29,7 @@
from calibre.gui2.tweak_book.search import SearchPanel
from calibre.gui2.tweak_book.check import Check
from calibre.gui2.tweak_book.toc import TOCViewer
+from calibre.gui2.tweak_book.char_select import CharSelect
from calibre.gui2.tweak_book.editor.widget import register_text_editor_actions
from calibre.gui2.tweak_book.editor.insert_resource import InsertImage
@@ -217,6 +218,7 @@ def __init__(self, opts, notify=None):
self.check_book = Check(self)
self.toc_view = TOCViewer(self)
self.image_browser = InsertImage(self, for_browsing=True)
+ self.insert_char = CharSelect(self)
self.create_actions()
self.create_toolbars()
@@ -321,6 +323,8 @@ def ereg(icon, text, target, sid, keys, description):
_('Beautify current file'))
self.action_pretty_all = reg('format-justify-fill.png', _('&Beautify all files'), partial(self.boss.pretty_print, False), 'pretty-all', (),
_('Beautify all files'))
+ self.action_insert_char = reg('character-set.png', _('&Insert special character'), self.boss.insert_character, 'insert-character', (),
+ _('Insert special character'))
# Polish actions
group = _('Polish Book')
@@ -423,6 +427,7 @@ def create_menubar(self):
e.addAction(self.action_editor_cut)
e.addAction(self.action_editor_copy)
e.addAction(self.action_editor_paste)
+ e.addAction(self.action_insert_char)
e.addSeparator()
e.addAction(self.action_preferences)
@@ -505,6 +510,7 @@ def create(text, name):
b.setToolTip(_('Donate to support calibre development'))
QTimer.singleShot(10, b.start_animation)
self.global_bar.addWidget(w)
+ self.global_bar.addAction(self.action_insert_char)
a(self.action_help)
a = create(_('Polish book tool bar'), 'polish').addAction

0 comments on commit 0012f5c

Please sign in to comment.