mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
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
This commit is contained in:
parent
c06d44d598
commit
0012f5cc4b
201
imgsrc/character-set.svg
Normal file
201
imgsrc/character-set.svg
Normal file
@ -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>
|
After Width: | Height: | Size: 8.5 KiB |
BIN
resources/images/character-set.png
Normal file
BIN
resources/images/character-set.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.7 KiB |
@ -1068,6 +1068,9 @@ class Boss(QObject):
|
|||||||
if not editors:
|
if not editors:
|
||||||
self.gui.preview.clear()
|
self.gui.preview.clear()
|
||||||
|
|
||||||
|
def insert_character(self):
|
||||||
|
self.gui.insert_char.show()
|
||||||
|
|
||||||
# Shutdown {{{
|
# Shutdown {{{
|
||||||
def quit(self):
|
def quit(self):
|
||||||
if not self.confirm_quit():
|
if not self.confirm_quit():
|
||||||
|
@ -6,7 +6,7 @@ from __future__ import (unicode_literals, division, absolute_import,
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
|
__copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
|
||||||
import unicodedata, re
|
import unicodedata, re, weakref
|
||||||
from bisect import bisect
|
from bisect import bisect
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
@ -548,6 +548,7 @@ class CharDelegate(QStyledItemDelegate):
|
|||||||
class CharView(QListView):
|
class CharView(QListView):
|
||||||
|
|
||||||
show_name = pyqtSignal(object)
|
show_name = pyqtSignal(object)
|
||||||
|
char_selected = pyqtSignal(object)
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
self.last_mouse_idx = -1
|
self.last_mouse_idx = -1
|
||||||
@ -564,6 +565,16 @@ class CharView(QListView):
|
|||||||
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||||
self.customContextMenuRequested.connect(self.context_menu)
|
self.customContextMenuRequested.connect(self.context_menu)
|
||||||
self.showing_favorites = False
|
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):
|
def set_allow_drag_and_drop(self, enabled):
|
||||||
if not enabled:
|
if not enabled:
|
||||||
@ -640,6 +651,8 @@ class CharSelect(Dialog):
|
|||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
self.initialized = False
|
self.initialized = False
|
||||||
Dialog.__init__(self, _('Insert character'), 'charmap_dialog', parent)
|
Dialog.__init__(self, _('Insert character'), 'charmap_dialog', parent)
|
||||||
|
self.setWindowIcon(QIcon(I('character-set.png')))
|
||||||
|
self.focus_widget = None
|
||||||
|
|
||||||
def setup_ui(self):
|
def setup_ui(self):
|
||||||
self.l = l = QGridLayout(self)
|
self.l = l = QGridLayout(self)
|
||||||
@ -650,6 +663,7 @@ class CharSelect(Dialog):
|
|||||||
b.setCheckable(True)
|
b.setCheckable(True)
|
||||||
b.setChecked(False)
|
b.setChecked(False)
|
||||||
b.setVisible(False)
|
b.setVisible(False)
|
||||||
|
b.setDefault(True)
|
||||||
|
|
||||||
self.splitter = s = QSplitter(self)
|
self.splitter = s = QSplitter(self)
|
||||||
s.setChildrenCollapsible(False)
|
s.setChildrenCollapsible(False)
|
||||||
@ -660,6 +674,7 @@ class CharSelect(Dialog):
|
|||||||
self.rearrange_button.toggled[bool].connect(self.set_allow_drag_and_drop)
|
self.rearrange_button.toggled[bool].connect(self.set_allow_drag_and_drop)
|
||||||
self.category_view.category_selected.connect(self.show_chars)
|
self.category_view.category_selected.connect(self.show_chars)
|
||||||
self.char_view.show_name.connect(self.show_char_info)
|
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)
|
s.addWidget(self.category_view), s.addWidget(self.char_view)
|
||||||
|
|
||||||
self.char_info = la = QLabel('\xa0')
|
self.char_info = la = QLabel('\xa0')
|
||||||
@ -701,10 +716,29 @@ class CharSelect(Dialog):
|
|||||||
self.char_info.clear()
|
self.char_info.clear()
|
||||||
|
|
||||||
def show(self):
|
def show(self):
|
||||||
|
try:
|
||||||
|
self.focus_widget = weakref.ref(QApplication.focusWidget())
|
||||||
|
except TypeError:
|
||||||
|
self.focus_widget = None
|
||||||
self.initialize()
|
self.initialize()
|
||||||
Dialog.show(self)
|
Dialog.show(self)
|
||||||
self.raise_()
|
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__':
|
if __name__ == '__main__':
|
||||||
app = QApplication([])
|
app = QApplication([])
|
||||||
w = CharSelect()
|
w = CharSelect()
|
||||||
|
@ -29,6 +29,7 @@ from calibre.gui2.tweak_book.preview import Preview
|
|||||||
from calibre.gui2.tweak_book.search import SearchPanel
|
from calibre.gui2.tweak_book.search import SearchPanel
|
||||||
from calibre.gui2.tweak_book.check import Check
|
from calibre.gui2.tweak_book.check import Check
|
||||||
from calibre.gui2.tweak_book.toc import TOCViewer
|
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.widget import register_text_editor_actions
|
||||||
from calibre.gui2.tweak_book.editor.insert_resource import InsertImage
|
from calibre.gui2.tweak_book.editor.insert_resource import InsertImage
|
||||||
|
|
||||||
@ -217,6 +218,7 @@ class Main(MainWindow):
|
|||||||
self.check_book = Check(self)
|
self.check_book = Check(self)
|
||||||
self.toc_view = TOCViewer(self)
|
self.toc_view = TOCViewer(self)
|
||||||
self.image_browser = InsertImage(self, for_browsing=True)
|
self.image_browser = InsertImage(self, for_browsing=True)
|
||||||
|
self.insert_char = CharSelect(self)
|
||||||
|
|
||||||
self.create_actions()
|
self.create_actions()
|
||||||
self.create_toolbars()
|
self.create_toolbars()
|
||||||
@ -321,6 +323,8 @@ class Main(MainWindow):
|
|||||||
_('Beautify current file'))
|
_('Beautify current file'))
|
||||||
self.action_pretty_all = reg('format-justify-fill.png', _('&Beautify all files'), partial(self.boss.pretty_print, False), 'pretty-all', (),
|
self.action_pretty_all = reg('format-justify-fill.png', _('&Beautify all files'), partial(self.boss.pretty_print, False), 'pretty-all', (),
|
||||||
_('Beautify all files'))
|
_('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
|
# Polish actions
|
||||||
group = _('Polish Book')
|
group = _('Polish Book')
|
||||||
@ -423,6 +427,7 @@ class Main(MainWindow):
|
|||||||
e.addAction(self.action_editor_cut)
|
e.addAction(self.action_editor_cut)
|
||||||
e.addAction(self.action_editor_copy)
|
e.addAction(self.action_editor_copy)
|
||||||
e.addAction(self.action_editor_paste)
|
e.addAction(self.action_editor_paste)
|
||||||
|
e.addAction(self.action_insert_char)
|
||||||
e.addSeparator()
|
e.addSeparator()
|
||||||
e.addAction(self.action_preferences)
|
e.addAction(self.action_preferences)
|
||||||
|
|
||||||
@ -505,6 +510,7 @@ class Main(MainWindow):
|
|||||||
b.setToolTip(_('Donate to support calibre development'))
|
b.setToolTip(_('Donate to support calibre development'))
|
||||||
QTimer.singleShot(10, b.start_animation)
|
QTimer.singleShot(10, b.start_animation)
|
||||||
self.global_bar.addWidget(w)
|
self.global_bar.addWidget(w)
|
||||||
|
self.global_bar.addAction(self.action_insert_char)
|
||||||
a(self.action_help)
|
a(self.action_help)
|
||||||
|
|
||||||
a = create(_('Polish book tool bar'), 'polish').addAction
|
a = create(_('Polish book tool bar'), 'polish').addAction
|
||||||
|
Loading…
x
Reference in New Issue
Block a user