plover 5.0.0.dev2__py3-none-any.whl → 5.0.0.dev3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- plover/__init__.py +8 -7
- plover/__main__.py +1 -1
- plover/command/set_config.py +7 -4
- plover/config.py +177 -74
- plover/dictionary/base.py +21 -9
- plover/dictionary/helpers.py +6 -4
- plover/dictionary/json_dict.py +10 -12
- plover/dictionary/loading_manager.py +8 -10
- plover/dictionary/rtfcre_dict.py +46 -43
- plover/dictionary/rtfcre_parse.py +116 -100
- plover/engine.py +112 -96
- plover/exception.py +4 -1
- plover/formatting.py +198 -140
- plover/gui_none/add_translation.py +17 -16
- plover/gui_none/engine.py +1 -3
- plover/gui_none/main.py +2 -2
- plover/gui_qt/about_dialog.py +17 -17
- plover/gui_qt/add_translation_dialog.py +8 -9
- plover/gui_qt/add_translation_widget.py +66 -63
- plover/gui_qt/config_window.py +274 -154
- plover/gui_qt/console_widget.py +9 -13
- plover/gui_qt/dictionaries_widget.py +140 -119
- plover/gui_qt/dictionary_editor.py +60 -61
- plover/gui_qt/engine.py +3 -3
- plover/gui_qt/info_browser.py +50 -4
- plover/gui_qt/log_qt.py +3 -2
- plover/gui_qt/lookup_dialog.py +9 -9
- plover/gui_qt/machine_options.py +38 -37
- plover/gui_qt/main.py +19 -19
- plover/gui_qt/main_window.py +88 -71
- plover/gui_qt/paper_tape.py +69 -52
- plover/gui_qt/paper_tape_ui.py +0 -3
- plover/gui_qt/plugins_manager.py +47 -43
- plover/gui_qt/resources_rc.py +28 -28
- plover/gui_qt/run_dialog.py +7 -6
- plover/gui_qt/steno_validator.py +2 -3
- plover/gui_qt/suggestions_dialog.py +34 -38
- plover/gui_qt/suggestions_widget.py +22 -16
- plover/gui_qt/tool.py +1 -3
- plover/gui_qt/trayicon.py +19 -19
- plover/gui_qt/utils.py +19 -9
- plover/i18n.py +9 -8
- plover/key_combo.py +130 -130
- plover/log.py +26 -26
- plover/machine/base.py +40 -35
- plover/machine/geminipr.py +7 -7
- plover/machine/keyboard.py +16 -14
- plover/machine/keyboard_capture/__init__.py +0 -1
- plover/machine/keymap.py +24 -20
- plover/machine/passport.py +6 -5
- plover/machine/procat.py +12 -16
- plover/machine/stentura.py +45 -29
- plover/machine/txbolt.py +5 -3
- plover/macro/repeat.py +0 -1
- plover/macro/retro.py +9 -9
- plover/macro/undo.py +4 -3
- plover/meta/attach.py +12 -10
- plover/meta/case.py +2 -1
- plover/meta/conditional.py +3 -3
- plover/meta/currency.py +4 -4
- plover/meta/mode.py +15 -15
- plover/meta/punctuation.py +1 -0
- plover/misc.py +21 -17
- plover/orthography.py +12 -10
- plover/oslayer/__init__.py +7 -5
- plover/oslayer/config.py +16 -15
- plover/oslayer/controller.py +13 -13
- plover/oslayer/linux/i18n.py +2 -1
- plover/oslayer/linux/keyboardcontrol.py +2 -2
- plover/oslayer/linux/keyboardcontrol_uinput.py +48 -3
- plover/oslayer/linux/keyboardcontrol_x11.py +860 -851
- plover/oslayer/linux/log.py +1 -1
- plover/oslayer/linux/log_dbus.py +97 -65
- plover/oslayer/linux/serial.py +2 -2
- plover/oslayer/linux/wmctrl_x11.py +11 -15
- plover/oslayer/osx/keyboardcontrol.py +194 -99
- plover/oslayer/osx/keyboardlayout.py +138 -119
- plover/oslayer/osx/log.py +14 -8
- plover/oslayer/osx/serial.py +1 -1
- plover/oslayer/osx/wmctrl.py +6 -1
- plover/oslayer/windows/keyboardcontrol.py +195 -89
- plover/oslayer/windows/keyboardlayout.py +367 -334
- plover/oslayer/windows/log.py +5 -3
- plover/oslayer/windows/serial.py +4 -5
- plover/oslayer/windows/wmctrl.py +1 -1
- plover/output/__init__.py +1 -2
- plover/output/keyboard.py +15 -15
- plover/plugins_manager/__main__.py +42 -39
- plover/plugins_manager/global_registry.py +2 -5
- plover/plugins_manager/local_registry.py +11 -13
- plover/plugins_manager/package_index.py +12 -18
- plover/plugins_manager/pip_wrapper.py +5 -5
- plover/plugins_manager/plugin_metadata.py +17 -9
- plover/plugins_manager/registry.py +39 -28
- plover/plugins_manager/requests.py +2 -4
- plover/plugins_manager/utils.py +9 -7
- plover/registry.py +28 -26
- plover/resource.py +13 -10
- plover/scripts/dist_main.py +7 -7
- plover/scripts/main.py +57 -34
- plover/scripts/send_command.py +13 -7
- plover/steno.py +16 -9
- plover/steno_dictionary.py +47 -21
- plover/suggestions.py +11 -11
- plover/system/__init__.py +39 -23
- plover/system/english_stenotype.py +231 -229
- plover/translation.py +67 -51
- {plover-5.0.0.dev2.dist-info → plover-5.0.0.dev3.dist-info}/METADATA +1 -1
- plover-5.0.0.dev3.dist-info/RECORD +216 -0
- plover_build_utils/check_requirements.py +5 -6
- plover_build_utils/download.py +10 -8
- plover_build_utils/get_pip.py +10 -5
- plover_build_utils/install_wheels.py +33 -31
- plover_build_utils/pyqt.py +24 -22
- plover_build_utils/setup.py +64 -54
- plover_build_utils/source_less.py +6 -6
- plover_build_utils/testing/blackbox.py +31 -31
- plover_build_utils/testing/dict.py +3 -3
- plover_build_utils/testing/output.py +5 -6
- plover_build_utils/testing/parametrize.py +5 -3
- plover_build_utils/testing/steno_dictionary.py +145 -124
- plover_build_utils/tree.py +21 -19
- plover_build_utils/trim.py +5 -5
- plover_build_utils/zipdir.py +3 -3
- plover-5.0.0.dev2.dist-info/RECORD +0 -216
- {plover-5.0.0.dev2.dist-info → plover-5.0.0.dev3.dist-info}/WHEEL +0 -0
- {plover-5.0.0.dev2.dist-info → plover-5.0.0.dev3.dist-info}/entry_points.txt +0 -0
- {plover-5.0.0.dev2.dist-info → plover-5.0.0.dev3.dist-info}/licenses/LICENSE.txt +0 -0
- {plover-5.0.0.dev2.dist-info → plover-5.0.0.dev3.dist-info}/top_level.txt +0 -0
- {plover-5.0.0.dev2.dist-info → plover-5.0.0.dev3.dist-info}/zip-safe +0 -0
plover/gui_qt/plugins_manager.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
from threading import Thread
|
|
3
2
|
import atexit
|
|
4
3
|
import html
|
|
@@ -6,7 +5,13 @@ import os
|
|
|
6
5
|
import sys
|
|
7
6
|
|
|
8
7
|
from PySide6.QtCore import Qt, Signal, Slot
|
|
9
|
-
from PySide6.QtWidgets import
|
|
8
|
+
from PySide6.QtWidgets import (
|
|
9
|
+
QDialog,
|
|
10
|
+
QMessageBox,
|
|
11
|
+
QTableWidgetItem,
|
|
12
|
+
QInputDialog,
|
|
13
|
+
QWidget,
|
|
14
|
+
)
|
|
10
15
|
|
|
11
16
|
from plover.gui_qt.tool import Tool
|
|
12
17
|
from plover.gui_qt.info_browser import InfoBrowser
|
|
@@ -18,10 +23,9 @@ from plover.plugins_manager.__main__ import pip
|
|
|
18
23
|
|
|
19
24
|
|
|
20
25
|
class PluginsManager(Tool, Ui_PluginsManager):
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
ICON = ':/resources/plugins_manager.svg'
|
|
26
|
+
TITLE = "Plugins Manager"
|
|
27
|
+
ROLE = "plugins_manager"
|
|
28
|
+
ICON = ":/resources/plugins_manager.svg"
|
|
25
29
|
|
|
26
30
|
# We use a class instance so the state is persistent
|
|
27
31
|
# accross different executions of the dialog when
|
|
@@ -46,7 +50,7 @@ class PluginsManager(Tool, Ui_PluginsManager):
|
|
|
46
50
|
|
|
47
51
|
def _need_restart(self):
|
|
48
52
|
for state in self._packages:
|
|
49
|
-
if state.status in (
|
|
53
|
+
if state.status in ("removed", "updated"):
|
|
50
54
|
return True
|
|
51
55
|
return False
|
|
52
56
|
|
|
@@ -62,7 +66,7 @@ class PluginsManager(Tool, Ui_PluginsManager):
|
|
|
62
66
|
self.table.setSortingEnabled(False)
|
|
63
67
|
self.table.setRowCount(len(self._packages))
|
|
64
68
|
for row, state in enumerate(self._packages):
|
|
65
|
-
for column, attr in enumerate(
|
|
69
|
+
for column, attr in enumerate("status name version summary".split()):
|
|
66
70
|
item = QTableWidgetItem(getattr(state, attr, "N/A"))
|
|
67
71
|
item.setFlags(item.flags() & ~Qt.ItemFlag.ItemIsEditable)
|
|
68
72
|
self.table.setItem(row, column, item)
|
|
@@ -80,12 +84,12 @@ class PluginsManager(Tool, Ui_PluginsManager):
|
|
|
80
84
|
if item.column() != 0:
|
|
81
85
|
continue
|
|
82
86
|
state = self._get_state(item.row())
|
|
83
|
-
if state.status in (
|
|
87
|
+
if state.status in ("installed", "updated"):
|
|
84
88
|
can_uninstall.append(state.name)
|
|
85
|
-
elif state.status in (
|
|
89
|
+
elif state.status in ("outdated",):
|
|
86
90
|
can_uninstall.append(state.name)
|
|
87
91
|
can_install.append(state.name)
|
|
88
|
-
elif state.status !=
|
|
92
|
+
elif state.status != "unsupported" and state.latest:
|
|
89
93
|
can_install.append(state.name)
|
|
90
94
|
return can_install, can_uninstall
|
|
91
95
|
|
|
@@ -108,7 +112,7 @@ class PluginsManager(Tool, Ui_PluginsManager):
|
|
|
108
112
|
metadata = self._get_state(current_item.row()).metadata
|
|
109
113
|
if metadata is None:
|
|
110
114
|
return
|
|
111
|
-
prologue =
|
|
115
|
+
prologue = "<h1>%s (%s)</h1>" % (
|
|
112
116
|
html.escape(metadata.name),
|
|
113
117
|
html.escape(metadata.version),
|
|
114
118
|
)
|
|
@@ -122,7 +126,7 @@ class PluginsManager(Tool, Ui_PluginsManager):
|
|
|
122
126
|
metadata.home_page,
|
|
123
127
|
html.escape(metadata.home_page),
|
|
124
128
|
)
|
|
125
|
-
prologue +=
|
|
129
|
+
prologue += "<hr>"
|
|
126
130
|
if metadata.description:
|
|
127
131
|
description = metadata.description
|
|
128
132
|
description_content_type = metadata.description_content_type
|
|
@@ -138,7 +142,7 @@ class PluginsManager(Tool, Ui_PluginsManager):
|
|
|
138
142
|
self._engine.restart()
|
|
139
143
|
else:
|
|
140
144
|
atexit._run_exitfuncs()
|
|
141
|
-
args = [sys.executable,
|
|
145
|
+
args = [sys.executable, "-m", __spec__.name]
|
|
142
146
|
os.execv(args[0], args)
|
|
143
147
|
|
|
144
148
|
def _update_packages(self):
|
|
@@ -146,7 +150,7 @@ class PluginsManager(Tool, Ui_PluginsManager):
|
|
|
146
150
|
self._packages_updated.emit()
|
|
147
151
|
|
|
148
152
|
def _clear_info(self):
|
|
149
|
-
self.info.setHtml(
|
|
153
|
+
self.info.setHtml("")
|
|
150
154
|
|
|
151
155
|
@Slot()
|
|
152
156
|
def refresh(self):
|
|
@@ -159,43 +163,42 @@ class PluginsManager(Tool, Ui_PluginsManager):
|
|
|
159
163
|
@Slot()
|
|
160
164
|
def install_from_git(self):
|
|
161
165
|
url, ok = QInputDialog.getText(
|
|
162
|
-
self,
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
)
|
|
166
|
+
self,
|
|
167
|
+
"Install from Git repo",
|
|
168
|
+
"<b>WARNING: Installing plugins is a security risk.<br>"
|
|
169
|
+
"A plugin from a Git repo can contain malicious code.<br>"
|
|
170
|
+
"Only install it if you got it from a trusted source.</b><br><br>"
|
|
171
|
+
"Enter repository link for plugin<br>"
|
|
172
|
+
"(will look similar to "
|
|
173
|
+
"https://github.com/user/repository.git): <br>",
|
|
174
|
+
)
|
|
170
175
|
if not ok or not url:
|
|
171
176
|
return
|
|
172
177
|
|
|
173
|
-
code = self._run(
|
|
174
|
-
['install'] +
|
|
175
|
-
['git+' + url]
|
|
176
|
-
)
|
|
178
|
+
code = self._run(["install"] + ["git+" + url])
|
|
177
179
|
if code == QDialog.DialogCode.Accepted:
|
|
178
180
|
self._update_table()
|
|
179
181
|
self.restart_button.setEnabled(True)
|
|
180
|
-
|
|
182
|
+
|
|
181
183
|
@Slot()
|
|
182
184
|
def install_selected_package(self):
|
|
183
185
|
packages = self._get_selection()[0]
|
|
184
|
-
if
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
186
|
+
if (
|
|
187
|
+
QMessageBox.warning(
|
|
188
|
+
self,
|
|
189
|
+
"Install " + ", ".join(packages),
|
|
190
|
+
"Installing plugins is a <b>security risk</b>. "
|
|
191
|
+
"A plugin can contain virus/malware. "
|
|
192
|
+
"Only install it if you got it from a trusted source."
|
|
193
|
+
" Are you sure you want to proceed?",
|
|
194
|
+
buttons=QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
|
195
|
+
defaultButton=QMessageBox.StandardButton.No,
|
|
196
|
+
)
|
|
197
|
+
!= QMessageBox.StandardButton.Yes
|
|
198
|
+
):
|
|
194
199
|
return
|
|
195
200
|
code = self._run(
|
|
196
|
-
[
|
|
197
|
-
[self._packages[name].latest.requirement
|
|
198
|
-
for name in packages]
|
|
201
|
+
["install"] + [self._packages[name].latest.requirement for name in packages]
|
|
199
202
|
)
|
|
200
203
|
if code == QDialog.DialogCode.Accepted:
|
|
201
204
|
for name in packages:
|
|
@@ -207,7 +210,7 @@ class PluginsManager(Tool, Ui_PluginsManager):
|
|
|
207
210
|
@Slot()
|
|
208
211
|
def uninstall_selected_package(self):
|
|
209
212
|
packages = self._get_selection()[1]
|
|
210
|
-
code = self._run([
|
|
213
|
+
code = self._run(["uninstall", "-y"] + packages)
|
|
211
214
|
if code == QDialog.DialogCode.Accepted:
|
|
212
215
|
for name in packages:
|
|
213
216
|
state = self._packages[name]
|
|
@@ -216,8 +219,9 @@ class PluginsManager(Tool, Ui_PluginsManager):
|
|
|
216
219
|
self.restart_button.setEnabled(True)
|
|
217
220
|
|
|
218
221
|
|
|
219
|
-
if __name__ ==
|
|
222
|
+
if __name__ == "__main__":
|
|
220
223
|
from PySide6.QtWidgets import QApplication
|
|
224
|
+
|
|
221
225
|
app = QApplication([])
|
|
222
226
|
dlg = PluginsManager(None)
|
|
223
227
|
dlg.show()
|
plover/gui_qt/resources_rc.py
CHANGED
|
@@ -2853,61 +2853,61 @@ qt_resource_struct = b"\
|
|
|
2853
2853
|
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x1c\x00\x00\x00\x02\
|
|
2854
2854
|
\x00\x00\x00\x00\x00\x00\x00\x00\
|
|
2855
2855
|
\x00\x00\x01\x84\x00\x00\x00\x00\x00\x01\x00\x00:\x0b\
|
|
2856
|
-
\x00\x00\x01\
|
|
2856
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0b\
|
|
2857
2857
|
\x00\x00\x00\xcc\x00\x00\x00\x00\x00\x01\x00\x00\x0d\xac\
|
|
2858
|
-
\x00\x00\x01\
|
|
2858
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0b\
|
|
2859
2859
|
\x00\x00\x03H\x00\x00\x00\x00\x00\x01\x00\x00\x9aw\
|
|
2860
|
-
\x00\x00\x01\
|
|
2860
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0c\
|
|
2861
2861
|
\x00\x00\x01\x1c\x00\x00\x00\x00\x00\x01\x00\x00\x1a\xf6\
|
|
2862
|
-
\x00\x00\x01\
|
|
2862
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0b\
|
|
2863
2863
|
\x00\x00\x00X\x00\x00\x00\x00\x00\x01\x00\x00\x04*\
|
|
2864
|
-
\x00\x00\x01\
|
|
2864
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0c\
|
|
2865
2865
|
\x00\x00\x00.\x00\x00\x00\x00\x00\x01\x00\x00\x01\x06\
|
|
2866
|
-
\x00\x00\x01\
|
|
2866
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0c\
|
|
2867
2867
|
\x00\x00\x03.\x00\x00\x00\x00\x00\x01\x00\x00\x98\xcc\
|
|
2868
|
-
\x00\x00\x01\
|
|
2868
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0c\
|
|
2869
2869
|
\x00\x00\x00\x18\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
|
|
2870
|
-
\x00\x00\x01\
|
|
2870
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0b\
|
|
2871
2871
|
\x00\x00\x03\x00\x00\x00\x00\x00\x00\x01\x00\x00\x93:\
|
|
2872
|
-
\x00\x00\x01\
|
|
2872
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0b\
|
|
2873
2873
|
\x00\x00\x01p\x00\x00\x00\x00\x00\x01\x00\x0072\
|
|
2874
|
-
\x00\x00\x01\
|
|
2874
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0b\
|
|
2875
2875
|
\x00\x00\x01\xee\x00\x00\x00\x00\x00\x01\x00\x00E\x9b\
|
|
2876
|
-
\x00\x00\x01\
|
|
2876
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0b\
|
|
2877
2877
|
\x00\x00\x00\xa0\x00\x00\x00\x00\x00\x01\x00\x00\x0bW\
|
|
2878
|
-
\x00\x00\x01\
|
|
2878
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0c\
|
|
2879
2879
|
\x00\x00\x01H\x00\x00\x00\x00\x00\x01\x00\x00%i\
|
|
2880
|
-
\x00\x00\x01\
|
|
2880
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0b\
|
|
2881
2881
|
\x00\x00\x03p\x00\x00\x00\x00\x00\x01\x00\x00\x9b\xd6\
|
|
2882
|
-
\x00\x00\x01\
|
|
2882
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0c\
|
|
2883
2883
|
\x00\x00\x00\x8a\x00\x00\x00\x00\x00\x01\x00\x00\x06\xc2\
|
|
2884
|
-
\x00\x00\x01\
|
|
2884
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0c\
|
|
2885
2885
|
\x00\x00\x01\x04\x00\x00\x00\x00\x00\x01\x00\x00\x16:\
|
|
2886
|
-
\x00\x00\x01\
|
|
2886
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0c\
|
|
2887
2887
|
\x00\x00\x03\x9c\x00\x00\x00\x00\x00\x01\x00\x00\x9f\xae\
|
|
2888
|
-
\x00\x00\x01\
|
|
2888
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0c\
|
|
2889
2889
|
\x00\x00\x01\xa4\x00\x00\x00\x00\x00\x01\x00\x00?\xd7\
|
|
2890
|
-
\x00\x00\x01\
|
|
2890
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0b\
|
|
2891
2891
|
\x00\x00\x02F\x00\x00\x00\x00\x00\x01\x00\x00si\
|
|
2892
|
-
\x00\x00\x01\
|
|
2892
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0b\
|
|
2893
2893
|
\x00\x00\x01\xbe\x00\x00\x00\x00\x00\x01\x00\x00C\x93\
|
|
2894
|
-
\x00\x00\x01\
|
|
2894
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0b\
|
|
2895
2895
|
\x00\x00\x00\xb2\x00\x00\x00\x00\x00\x01\x00\x00\x0c]\
|
|
2896
|
-
\x00\x00\x01\
|
|
2896
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0b\
|
|
2897
2897
|
\x00\x00\x02z\x00\x00\x00\x00\x00\x01\x00\x00{\x0c\
|
|
2898
|
-
\x00\x00\x01\
|
|
2898
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0b\
|
|
2899
2899
|
\x00\x00\x02\xcc\x00\x00\x00\x00\x00\x01\x00\x00\x8c^\
|
|
2900
|
-
\x00\x00\x01\
|
|
2900
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0b\
|
|
2901
2901
|
\x00\x00\x02\x1c\x00\x00\x00\x00\x00\x01\x00\x00p\xec\
|
|
2902
|
-
\x00\x00\x01\
|
|
2902
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0c\
|
|
2903
2903
|
\x00\x00\x00\xe6\x00\x00\x00\x00\x00\x01\x00\x00\x10\xac\
|
|
2904
|
-
\x00\x00\x01\
|
|
2904
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0c\
|
|
2905
2905
|
\x00\x00\x02\x02\x00\x00\x00\x00\x00\x01\x00\x00F\xd9\
|
|
2906
|
-
\x00\x00\x01\
|
|
2906
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0b\
|
|
2907
2907
|
\x00\x00\x00D\x00\x00\x00\x00\x00\x01\x00\x00\x02Y\
|
|
2908
|
-
\x00\x00\x01\
|
|
2908
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0b\
|
|
2909
2909
|
\x00\x00\x02\x9a\x00\x00\x00\x00\x00\x01\x00\x00\x7f#\
|
|
2910
|
-
\x00\x00\x01\
|
|
2910
|
+
\x00\x00\x01\x98\x07\x8f\x01\x0b\
|
|
2911
2911
|
"
|
|
2912
2912
|
|
|
2913
2913
|
def qInitResources():
|
plover/gui_qt/run_dialog.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
from PySide6.QtWidgets import QDialogButtonBox, QDialog
|
|
3
2
|
|
|
4
3
|
from plover.gui_qt.console_widget import ConsoleWidget
|
|
@@ -6,7 +5,6 @@ from plover.gui_qt.run_dialog_ui import Ui_RunDialog
|
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
class RunDialog(QDialog, Ui_RunDialog):
|
|
9
|
-
|
|
10
8
|
def __init__(self, run_args, popen=None):
|
|
11
9
|
super().__init__()
|
|
12
10
|
self.setupUi(self)
|
|
@@ -24,16 +22,19 @@ class RunDialog(QDialog, Ui_RunDialog):
|
|
|
24
22
|
|
|
25
23
|
def reject(self):
|
|
26
24
|
if self._successful is not None:
|
|
27
|
-
super().done(
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
super().done(
|
|
26
|
+
getattr(
|
|
27
|
+
QDialog.DialogCode, "Accepted" if self._successful else "Rejected"
|
|
28
|
+
)
|
|
29
|
+
)
|
|
30
30
|
return
|
|
31
31
|
self._console.terminate()
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
if __name__ ==
|
|
34
|
+
if __name__ == "__main__":
|
|
35
35
|
import sys
|
|
36
36
|
from PySide6.QtWidgets import QApplication
|
|
37
|
+
|
|
37
38
|
app = QApplication([])
|
|
38
39
|
dlg = RunDialog(sys.argv[1:])
|
|
39
40
|
dlg.show()
|
plover/gui_qt/steno_validator.py
CHANGED
|
@@ -4,12 +4,11 @@ from plover.steno import normalize_steno
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class StenoValidator(QValidator):
|
|
7
|
-
|
|
8
7
|
def validate(self, text, pos):
|
|
9
|
-
if not text.strip(
|
|
8
|
+
if not text.strip("-/"):
|
|
10
9
|
state = QValidator.State.Intermediate
|
|
11
10
|
else:
|
|
12
|
-
prefix = text.rstrip(
|
|
11
|
+
prefix = text.rstrip("-/")
|
|
13
12
|
if text == prefix:
|
|
14
13
|
state = QValidator.State.Acceptable
|
|
15
14
|
steno = text
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
import re
|
|
3
2
|
|
|
4
3
|
from PySide6.QtCore import Qt, Slot
|
|
@@ -16,22 +15,22 @@ from plover import _
|
|
|
16
15
|
from plover.suggestions import Suggestion
|
|
17
16
|
from plover.formatting import RetroFormatter
|
|
18
17
|
|
|
18
|
+
from plover.gui_qt import utils
|
|
19
19
|
from plover.gui_qt.suggestions_dialog_ui import Ui_SuggestionsDialog
|
|
20
20
|
from plover.gui_qt.utils import ToolBar
|
|
21
21
|
from plover.gui_qt.tool import Tool
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
class SuggestionsDialog(Tool, Ui_SuggestionsDialog):
|
|
25
|
-
|
|
26
25
|
# i18n: Widget: “SuggestionsDialog”, tooltip.
|
|
27
|
-
__doc__ = _(
|
|
26
|
+
__doc__ = _("Suggest possible strokes for the last written words.")
|
|
28
27
|
|
|
29
|
-
TITLE = _(
|
|
30
|
-
ICON =
|
|
31
|
-
ROLE =
|
|
32
|
-
SHORTCUT =
|
|
28
|
+
TITLE = _("Suggestions")
|
|
29
|
+
ICON = ":/resources/lightbulb.svg"
|
|
30
|
+
ROLE = "suggestions"
|
|
31
|
+
SHORTCUT = "Ctrl+J"
|
|
33
32
|
|
|
34
|
-
WORD_RX = re.compile(r
|
|
33
|
+
WORD_RX = re.compile(r"(?:\w+|[^\w\s]+)\s*")
|
|
35
34
|
|
|
36
35
|
STYLE_TRANSLATION, STYLE_STROKES = range(2)
|
|
37
36
|
|
|
@@ -46,20 +45,25 @@ class SuggestionsDialog(Tool, Ui_SuggestionsDialog):
|
|
|
46
45
|
self.setupUi(self)
|
|
47
46
|
self._last_suggestions = None
|
|
48
47
|
# Toolbar.
|
|
49
|
-
|
|
50
|
-
self.action_ToggleOnTop,
|
|
48
|
+
actions = [
|
|
51
49
|
self.action_SelectFont,
|
|
52
50
|
self.action_Clear,
|
|
53
|
-
|
|
51
|
+
]
|
|
52
|
+
if not utils.is_wayland():
|
|
53
|
+
# Wayland does not support window on top.
|
|
54
|
+
actions.insert(0, self.action_ToggleOnTop)
|
|
55
|
+
|
|
56
|
+
self.layout().addWidget(ToolBar(*actions))
|
|
57
|
+
|
|
54
58
|
self.action_Clear.setEnabled(False)
|
|
55
59
|
# Font popup menu.
|
|
56
60
|
self._font_menu = QMenu()
|
|
57
61
|
# i18n: Widget: “SuggestionsDialog”, “font” menu.
|
|
58
|
-
self._font_menu_text = QAction(_(
|
|
62
|
+
self._font_menu_text = QAction(_("&Text"), self._font_menu)
|
|
59
63
|
# i18n: Widget: “SuggestionsDialog”, “font” menu.
|
|
60
|
-
self._font_menu_strokes = QAction(_(
|
|
64
|
+
self._font_menu_strokes = QAction(_("&Strokes"), self._font_menu)
|
|
61
65
|
self._font_menu.addActions([self._font_menu_text, self._font_menu_strokes])
|
|
62
|
-
engine.signal_connect(
|
|
66
|
+
engine.signal_connect("translated", self.on_translation)
|
|
63
67
|
self.suggestions.setFocus()
|
|
64
68
|
self.restore_state()
|
|
65
69
|
self.finished.connect(self.save_state)
|
|
@@ -72,8 +76,8 @@ class SuggestionsDialog(Tool, Ui_SuggestionsDialog):
|
|
|
72
76
|
|
|
73
77
|
def _restore_state(self, settings):
|
|
74
78
|
for name in (
|
|
75
|
-
|
|
76
|
-
|
|
79
|
+
"text_font",
|
|
80
|
+
"strokes_font",
|
|
77
81
|
):
|
|
78
82
|
font_string = settings.value(name)
|
|
79
83
|
if font_string is None:
|
|
@@ -82,21 +86,21 @@ class SuggestionsDialog(Tool, Ui_SuggestionsDialog):
|
|
|
82
86
|
if not font.fromString(font_string):
|
|
83
87
|
continue
|
|
84
88
|
self._set_font(name, font)
|
|
85
|
-
ontop = settings.value(
|
|
89
|
+
ontop = settings.value("ontop", None, bool)
|
|
86
90
|
if ontop is not None:
|
|
87
91
|
self.action_ToggleOnTop.setChecked(ontop)
|
|
88
92
|
self.toggle_ontop(ontop)
|
|
89
93
|
|
|
90
94
|
def _save_state(self, settings):
|
|
91
95
|
for name in (
|
|
92
|
-
|
|
93
|
-
|
|
96
|
+
"text_font",
|
|
97
|
+
"strokes_font",
|
|
94
98
|
):
|
|
95
99
|
font = self._get_font(name)
|
|
96
100
|
font_string = font.toString()
|
|
97
101
|
settings.setValue(name, font_string)
|
|
98
102
|
ontop = bool(self.windowFlags() & Qt.WindowType.WindowStaysOnTopHint)
|
|
99
|
-
settings.setValue(
|
|
103
|
+
settings.setValue("ontop", ontop)
|
|
100
104
|
|
|
101
105
|
def _show_suggestions(self, suggestion_list):
|
|
102
106
|
self.suggestions.append(suggestion_list)
|
|
@@ -104,19 +108,18 @@ class SuggestionsDialog(Tool, Ui_SuggestionsDialog):
|
|
|
104
108
|
|
|
105
109
|
@staticmethod
|
|
106
110
|
def tails(ls):
|
|
107
|
-
|
|
111
|
+
"""Return all tail combinations (a la Haskell)
|
|
108
112
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
113
|
+
tails :: [x] -> [[x]]
|
|
114
|
+
>>> tails('abcd')
|
|
115
|
+
['abcd', 'bcd', 'cd', d']
|
|
112
116
|
|
|
113
|
-
|
|
117
|
+
"""
|
|
114
118
|
|
|
115
119
|
for i in range(len(ls)):
|
|
116
120
|
yield ls[i:]
|
|
117
121
|
|
|
118
122
|
def on_translation(self, old, new):
|
|
119
|
-
|
|
120
123
|
# Check for new output.
|
|
121
124
|
for a in reversed(new):
|
|
122
125
|
if a.text and not a.text.isspace():
|
|
@@ -132,7 +135,7 @@ class SuggestionsDialog(Tool, Ui_SuggestionsDialog):
|
|
|
132
135
|
|
|
133
136
|
suggestion_list = []
|
|
134
137
|
for phrase in self.tails(split_words):
|
|
135
|
-
phrase =
|
|
138
|
+
phrase = "".join(phrase)
|
|
136
139
|
suggestion_list.extend(self._engine.get_suggestions(phrase))
|
|
137
140
|
|
|
138
141
|
if not suggestion_list and split_words:
|
|
@@ -148,24 +151,17 @@ class SuggestionsDialog(Tool, Ui_SuggestionsDialog):
|
|
|
148
151
|
if action is None:
|
|
149
152
|
return
|
|
150
153
|
if action == self._font_menu_text:
|
|
151
|
-
name =
|
|
152
|
-
font_options = ()
|
|
154
|
+
name = "text_font"
|
|
153
155
|
elif action == self._font_menu_strokes:
|
|
154
|
-
name =
|
|
155
|
-
font_options = (QFontDialog.FontDialogOption.MonospacedFonts,)
|
|
156
|
+
name = "strokes_font"
|
|
156
157
|
font = self._get_font(name)
|
|
157
|
-
ok, font = QFontDialog.getFont(font, self,
|
|
158
|
+
ok, font = QFontDialog.getFont(font, self, "")
|
|
158
159
|
if ok:
|
|
159
160
|
self._set_font(name, font)
|
|
160
161
|
|
|
161
162
|
@Slot(bool)
|
|
162
163
|
def toggle_ontop(self, ontop):
|
|
163
|
-
|
|
164
|
-
if ontop:
|
|
165
|
-
flags |= Qt.WindowType.WindowStaysOnTopHint
|
|
166
|
-
else:
|
|
167
|
-
flags &= ~Qt.WindowType.WindowStaysOnTopHint
|
|
168
|
-
self.setWindowFlags(flags)
|
|
164
|
+
self.setWindowFlag(Qt.WindowStaysOnTopHint, ontop)
|
|
169
165
|
self.show()
|
|
170
166
|
|
|
171
167
|
@Slot()
|
|
@@ -24,12 +24,11 @@ from .utils import ActionCopyViewSelectionToClipboard
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
# i18n: Widget: “SuggestionsWidget”.
|
|
27
|
-
NO_SUGGESTIONS_STRING = _(
|
|
27
|
+
NO_SUGGESTIONS_STRING = _("no suggestions")
|
|
28
28
|
MAX_SUGGESTIONS_COUNT = 10
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
class SuggestionsDelegate(QStyledItemDelegate):
|
|
32
|
-
|
|
33
32
|
def __init__(self, parent=None):
|
|
34
33
|
super().__init__(parent=parent)
|
|
35
34
|
self._doc = QTextDocument()
|
|
@@ -61,13 +60,13 @@ class SuggestionsDelegate(QStyledItemDelegate):
|
|
|
61
60
|
|
|
62
61
|
def _format_suggestion(self, index):
|
|
63
62
|
suggestion = index.data(Qt.ItemDataRole.DisplayRole)
|
|
64
|
-
translation = escape_translation(suggestion.text) +
|
|
63
|
+
translation = escape_translation(suggestion.text) + ":"
|
|
65
64
|
if not suggestion.steno_list:
|
|
66
|
-
translation +=
|
|
65
|
+
translation += " " + NO_SUGGESTIONS_STRING
|
|
67
66
|
return translation, None
|
|
68
|
-
strokes =
|
|
67
|
+
strokes = ""
|
|
69
68
|
for strokes_list in suggestion.steno_list[:MAX_SUGGESTIONS_COUNT]:
|
|
70
|
-
strokes +=
|
|
69
|
+
strokes += "\n " + "/".join(strokes_list)
|
|
71
70
|
return translation, strokes
|
|
72
71
|
|
|
73
72
|
def _suggestion_size_hint(self, index):
|
|
@@ -106,7 +105,6 @@ class SuggestionsDelegate(QStyledItemDelegate):
|
|
|
106
105
|
|
|
107
106
|
|
|
108
107
|
class SuggestionsModel(QAbstractListModel):
|
|
109
|
-
|
|
110
108
|
def __init__(self):
|
|
111
109
|
super().__init__()
|
|
112
110
|
self._suggestion_list = []
|
|
@@ -123,11 +121,13 @@ class SuggestionsModel(QAbstractListModel):
|
|
|
123
121
|
if role == Qt.ItemDataRole.AccessibleTextRole:
|
|
124
122
|
translation = escape_translation(suggestion.text)
|
|
125
123
|
if suggestion.steno_list:
|
|
126
|
-
steno =
|
|
127
|
-
|
|
124
|
+
steno = ", ".join(
|
|
125
|
+
"/".join(strokes_list)
|
|
126
|
+
for strokes_list in suggestion.steno_list[:MAX_SUGGESTIONS_COUNT]
|
|
127
|
+
)
|
|
128
128
|
else:
|
|
129
129
|
steno = NO_SUGGESTIONS_STRING
|
|
130
|
-
return translation +
|
|
130
|
+
return translation + ": " + steno
|
|
131
131
|
return None
|
|
132
132
|
|
|
133
133
|
def clear(self):
|
|
@@ -142,19 +142,25 @@ class SuggestionsModel(QAbstractListModel):
|
|
|
142
142
|
self.endInsertRows()
|
|
143
143
|
|
|
144
144
|
def mimeTypes(self):
|
|
145
|
-
return [
|
|
145
|
+
return ["text/plain"]
|
|
146
146
|
|
|
147
147
|
def mimeData(self, indexes):
|
|
148
148
|
data = QMimeData()
|
|
149
|
-
data.setText(
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
149
|
+
data.setText(
|
|
150
|
+
"\n".join(
|
|
151
|
+
filter(
|
|
152
|
+
None,
|
|
153
|
+
(
|
|
154
|
+
self.data(index, Qt.ItemDataRole.AccessibleTextRole)
|
|
155
|
+
for index in indexes
|
|
156
|
+
),
|
|
157
|
+
)
|
|
158
|
+
)
|
|
159
|
+
)
|
|
153
160
|
return data
|
|
154
161
|
|
|
155
162
|
|
|
156
163
|
class SuggestionsWidget(QListView):
|
|
157
|
-
|
|
158
164
|
def __init__(self, parent=None):
|
|
159
165
|
super().__init__(parent=parent)
|
|
160
166
|
self.setResizeMode(self.ResizeMode.Adjust)
|
plover/gui_qt/tool.py
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
|
|
2
1
|
from PySide6.QtWidgets import QDialog
|
|
3
2
|
|
|
4
3
|
from plover.gui_qt.utils import WindowStateMixin
|
|
5
4
|
|
|
6
5
|
|
|
7
6
|
class Tool(QDialog, WindowStateMixin):
|
|
8
|
-
|
|
9
7
|
# Used for dialog window title, menu entry text.
|
|
10
8
|
TITLE = None
|
|
11
9
|
# Optional path to icon image.
|
|
@@ -20,7 +18,7 @@ class Tool(QDialog, WindowStateMixin):
|
|
|
20
18
|
self._engine = engine
|
|
21
19
|
|
|
22
20
|
def _update_title(self):
|
|
23
|
-
self.setWindowTitle(
|
|
21
|
+
self.setWindowTitle("Plover: " + self.TITLE)
|
|
24
22
|
|
|
25
23
|
def setupUi(self, widget):
|
|
26
24
|
super().setupUi(widget)
|