PrEditor 0.1.0rc2__py2.py3-none-any.whl → 0.3.0__py2.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.
Potentially problematic release.
This version of PrEditor might be problematic. Click here for more details.
- {PrEditor-0.1.0rc2.dist-info → PrEditor-0.3.0.dist-info}/METADATA +8 -8
- {PrEditor-0.1.0rc2.dist-info → PrEditor-0.3.0.dist-info}/RECORD +26 -17
- {PrEditor-0.1.0rc2.dist-info → PrEditor-0.3.0.dist-info}/WHEEL +1 -1
- preditor/__init__.py +7 -2
- preditor/cli.py +1 -1
- preditor/gui/find_files.py +119 -0
- preditor/gui/fuzzy_search/__init__.py +0 -0
- preditor/gui/fuzzy_search/fuzzy_search.py +93 -0
- preditor/gui/group_tab_widget/__init__.py +14 -5
- preditor/gui/group_tab_widget/grouped_tab_models.py +108 -0
- preditor/gui/loggerwindow.py +152 -29
- preditor/gui/ui/find_files.ui +140 -0
- preditor/gui/ui/loggerwindow.ui +60 -3
- preditor/gui/workbox_mixin.py +34 -0
- preditor/gui/workbox_text_edit.py +3 -8
- preditor/gui/workboxwidget.py +2 -7
- preditor/resource/img/README.md +10 -0
- preditor/resource/img/format-letter-case.svg +1 -0
- preditor/resource/img/regex.svg +1 -0
- preditor/resource/img/restart.svg +1 -0
- preditor/stream/director.py +20 -3
- preditor/utils/text_search.py +342 -0
- preditor/version.py +2 -2
- {PrEditor-0.1.0rc2.dist-info → PrEditor-0.3.0.dist-info}/LICENSE +0 -0
- {PrEditor-0.1.0rc2.dist-info → PrEditor-0.3.0.dist-info}/entry_points.txt +0 -0
- {PrEditor-0.1.0rc2.dist-info → PrEditor-0.3.0.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: PrEditor
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: A python REPL and Editor and console based on Qt.
|
|
5
5
|
Home-page: https://github.com/blurstudio/PrEditor.git
|
|
6
6
|
Author: Blur Studio
|
|
@@ -20,13 +20,13 @@ Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7
|
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
22
|
Requires-Dist: Qt.py
|
|
23
|
-
Requires-Dist: configparser
|
|
24
|
-
Requires-Dist: future
|
|
25
|
-
Requires-Dist: python-redmine
|
|
26
|
-
Requires-Dist: signalslot
|
|
27
|
-
Requires-Dist: importlib-metadata
|
|
23
|
+
Requires-Dist: configparser >=4.0.2
|
|
24
|
+
Requires-Dist: future >=0.18.2
|
|
25
|
+
Requires-Dist: python-redmine >=2.1.1
|
|
26
|
+
Requires-Dist: signalslot >=0.1.2
|
|
27
|
+
Requires-Dist: importlib-metadata >=4.8.3 ; python_version >= "3.6"
|
|
28
28
|
Provides-Extra: cli
|
|
29
|
-
Requires-Dist: click
|
|
29
|
+
Requires-Dist: click >=7.1.2 ; extra == 'cli'
|
|
30
30
|
Requires-Dist: click-default-group ; extra == 'cli'
|
|
31
31
|
Provides-Extra: dev
|
|
32
32
|
Requires-Dist: black ; extra == 'dev'
|
|
@@ -38,7 +38,7 @@ Requires-Dist: pep8-naming ; extra == 'dev'
|
|
|
38
38
|
Requires-Dist: pytest ; extra == 'dev'
|
|
39
39
|
Requires-Dist: tox ; extra == 'dev'
|
|
40
40
|
Provides-Extra: shortcut
|
|
41
|
-
Requires-Dist: casement
|
|
41
|
+
Requires-Dist: casement >=0.1.0 ; (platform_system == "Windows") and extra == 'shortcut'
|
|
42
42
|
|
|
43
43
|
# PrEditor
|
|
44
44
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
preditor/__init__.py,sha256=
|
|
1
|
+
preditor/__init__.py,sha256=JlIK0Gp7g7DsKbyt1c5PMD9-3EyeE7q7wv1sJmhrlYc,10585
|
|
2
2
|
preditor/__main__.py,sha256=boRVSmxX6eF8EkzbePtCZbzdcaPseqVae4RPPLp3U1A,449
|
|
3
3
|
preditor/about_module.py,sha256=KIvCxZrMLhm5TR6lYskM4Y9VctJ0QtSQD5Nu8Ip1CGY,5267
|
|
4
|
-
preditor/cli.py,sha256=
|
|
4
|
+
preditor/cli.py,sha256=kyVr0V43KYSMLIEWXH54CA0ByFmPcpbFF-8cli6PVow,5300
|
|
5
5
|
preditor/contexts.py,sha256=xxRbOFORsvlG___EuSiKuT1aiKJvnkFojFZFZE0HPNk,5147
|
|
6
6
|
preditor/debug.py,sha256=xcOslCByK7nSebh5DR6m-uC6uV9tuJBZu-JAAPBl8aA,9515
|
|
7
7
|
preditor/enum.py,sha256=snG5V259dH9SI1kwBqZeZdhat36F1iAmIjYErosnDUg,23489
|
|
@@ -11,7 +11,7 @@ preditor/plugins.py,sha256=W3DfdDEE5DtEXOXioEyIe4tuIVV1V-RLcV8LoZJWpWU,1916
|
|
|
11
11
|
preditor/prefs.py,sha256=BPtSsdv2yuiRpIaqEml9fxlVYKHNfqQ77hp5YIQRDBg,2172
|
|
12
12
|
preditor/settings.py,sha256=DV9_DbJorEnhdIvW15E7h7PswlQUsy0UlA8bXUYN0og,2206
|
|
13
13
|
preditor/streamhandler_helper.py,sha256=kiU6T9WqJ3JKTTKCa7IUU8brwK7zO5UUpEzLhEfKe44,1788
|
|
14
|
-
preditor/version.py,sha256=
|
|
14
|
+
preditor/version.py,sha256=YNd1dEdZGzG2MvXfaTQdmMYCLOQm-rV09_xmC5Hxu5Y,142
|
|
15
15
|
preditor/weakref.py,sha256=b--KomFAHcMWr3DEAIN2j3XxRhjDWKw0WABXyn1nxDg,12177
|
|
16
16
|
preditor/cores/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
17
|
preditor/cores/core.py,sha256=ZXB4bts05DMQtc-dtkk81chIWNqYXImMuWCYuUHwLdA,2389
|
|
@@ -28,30 +28,35 @@ preditor/gui/dialog.py,sha256=Vw8Wflb2P3TngO8b-2suWP6JKHBVHdbGgYiRDKzYRlQ,7488
|
|
|
28
28
|
preditor/gui/drag_tab_bar.py,sha256=5J-BSKQzS6_WuYxxGqmnUJr6AriTAvwfVK7Q3p7knrM,7933
|
|
29
29
|
preditor/gui/editor_chooser.py,sha256=v82SPuxPgai3XiRWi9ypT0aRkbV6_IrbfBoAljM9pRY,1986
|
|
30
30
|
preditor/gui/errordialog.py,sha256=FZzSykNtqgTZ-CKEsLFXfcw_k8zwx7g_aMaHbpnq2xI,3110
|
|
31
|
+
preditor/gui/find_files.py,sha256=eG935f9Xbh7F1M8IK7PKko84a37shoaoplQitPMv_-c,4116
|
|
31
32
|
preditor/gui/level_buttons.py,sha256=yPFIWKc0bgKLrP2XHyBqNuvvTnXZqGdtN_p27jSb1Og,11925
|
|
32
33
|
preditor/gui/logger_window_handler.py,sha256=VTNhaoFUnConE3NHj9KaDZlVoifix8xCbCuN5Ozjz0M,1482
|
|
33
|
-
preditor/gui/loggerwindow.py,sha256=
|
|
34
|
+
preditor/gui/loggerwindow.py,sha256=_f7T6e04pFHF1MZQYE77JvAHUQnJ28TS7CPGizNS2yo,47589
|
|
34
35
|
preditor/gui/newtabwidget.py,sha256=5aCWn9xAl5h1oZACqVuEsOAbzKTS2RegrLI41gROC8A,1971
|
|
35
36
|
preditor/gui/redmine_login_dialog.py,sha256=cMPBuecSZD5yjycNkMwHa1AbdwgGoyHvX8anIvWjEFo,1893
|
|
36
37
|
preditor/gui/set_text_editor_path_dialog.py,sha256=6mbHAXEVQhaWyg0N67f54aZpd5fp6puGWzeM0tPepiU,2251
|
|
37
38
|
preditor/gui/window.py,sha256=bZAEKQDM6V4aew1nlSTPyq_tG-_IoSvyXHcZxrdFMaE,6924
|
|
38
|
-
preditor/gui/workbox_mixin.py,sha256=
|
|
39
|
-
preditor/gui/workbox_text_edit.py,sha256=
|
|
40
|
-
preditor/gui/workboxwidget.py,sha256=
|
|
41
|
-
preditor/gui/
|
|
39
|
+
preditor/gui/workbox_mixin.py,sha256=4tUiOWRFc0tEOAAo9BDD3idlkfO6t4VCuL4tklYNnTY,12543
|
|
40
|
+
preditor/gui/workbox_text_edit.py,sha256=fJY7eo1bpMyzLri5DfdVb2vad9znJjBvzLkY34T8gb4,3678
|
|
41
|
+
preditor/gui/workboxwidget.py,sha256=1uGSPZv3GxmOAIsA4oTaiPUHl003Yp6IA_rXanIToC4,8966
|
|
42
|
+
preditor/gui/fuzzy_search/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
43
|
+
preditor/gui/fuzzy_search/fuzzy_search.py,sha256=6npanW6aLmG_ezdHmpsKN7p2zwck_Qq6YUy9duCNN8Q,3595
|
|
44
|
+
preditor/gui/group_tab_widget/__init__.py,sha256=KpQKkX_FyFQLy2UtBQcLoMuj0eRA7E_2-KXrTwPqA9k,12530
|
|
42
45
|
preditor/gui/group_tab_widget/grouped_tab_menu.py,sha256=lopd3mjHJIE_5xLdlZL0ghuBzsYo36vO1OZE6L6tqbI,1288
|
|
46
|
+
preditor/gui/group_tab_widget/grouped_tab_models.py,sha256=zlmbcv3JAC5BzjKpm4CM7Hobibm1T_3GjaPoWIQbXiQ,3970
|
|
43
47
|
preditor/gui/group_tab_widget/grouped_tab_widget.py,sha256=EwzYVqhJaBaYS9tdd4FXUl-PxjplWtOi7f0t99De_bw,2803
|
|
44
48
|
preditor/gui/group_tab_widget/one_tab_widget.py,sha256=PdZAXjmV9oTHakh8aFYRlLnfwcoT459vQWVKgpZZx4Y,1971
|
|
45
49
|
preditor/gui/ui/editor_chooser.ui,sha256=cYSVHK0A4-zst6JyDkrBZK9qcAontbhV4Mmnw5ps72E,2736
|
|
46
50
|
preditor/gui/ui/errordialog.ui,sha256=H1wJJVU1t7kbnYkzGtGa8SBVpKjesJG_0imdBkJaEUY,2034
|
|
47
|
-
preditor/gui/ui/
|
|
51
|
+
preditor/gui/ui/find_files.ui,sha256=8mdD3Vg3ofRMChdKntxiDHO3JXHQSKjjY6OLY_1W5lc,3328
|
|
52
|
+
preditor/gui/ui/loggerwindow.ui,sha256=JVpvGWrnI4cQdX4DFwfsCMEnNh1iipc1Vxihcg8FJvU,30035
|
|
48
53
|
preditor/gui/ui/redmine_login_dialog.ui,sha256=PmGuJWvBcSDLya5UblFj5brwDH9VL2fJEveH-r5-nJ8,2911
|
|
49
54
|
preditor/gui/ui/set_text_editor_path_dialog.ui,sha256=QoSorDlyfUoNSrHQRP1Yrls5az4TyUsTQw_qYOe_Ljc,4004
|
|
50
55
|
preditor/resource/environment_variables.html,sha256=-uWicgOkour-sxtY-crrjMiLMyJzAzshwUXKqSm6TmI,3134
|
|
51
56
|
preditor/resource/error_mail.html,sha256=oCzynF3QSHi_Xg1wlmU5M5u1Q05mp7QV0ZtQ4e8KQDA,2400
|
|
52
57
|
preditor/resource/error_mail_inline.html,sha256=ceZ8HReyTirMOX-xNgVB9kMO8QhpbHI4-WObFeOG9KY,4014
|
|
53
58
|
preditor/resource/settings.ini,sha256=JhPumV7SzlRTZG3Fs1dxPokat3bthfZPw84lJ7E9zPQ,893
|
|
54
|
-
preditor/resource/img/README.md,sha256=
|
|
59
|
+
preditor/resource/img/README.md,sha256=gJo4tydTyeZgUlpoEjiNI7SHlKz5Y-e8aE8Yb7mPrHk,1025
|
|
55
60
|
preditor/resource/img/arrow_forward.png,sha256=41jN4EuemyaZtJ1vcynlAvCGRPJmq3NYq1HeWBGRbko,426
|
|
56
61
|
preditor/resource/img/check-bold.png,sha256=FLu28U1BTyUaljouxEGaoHXhG2z4OzvL57MfMSwAnSI,500
|
|
57
62
|
preditor/resource/img/chevron-down.png,sha256=4GNzTPW-q4LR_3tHj1ymlHsRymVma9J_N1eUvNboTJw,451
|
|
@@ -70,6 +75,7 @@ preditor/resource/img/file-remove.png,sha256=pnJVe9EBzvpMq8G7ikY_DXXDhM9e2m2pJtP
|
|
|
70
75
|
preditor/resource/img/format-align-left.png,sha256=y2ixRoDurohX5E5ddxr4tVib_bczRRT7DN9CBDhDmcw,331
|
|
71
76
|
preditor/resource/img/format-letter-case-lower.png,sha256=CkqlY2HABrGLyCEkDC8CPI4To873uNysB-f5PUK1gJA,978
|
|
72
77
|
preditor/resource/img/format-letter-case-upper.png,sha256=NECM28lYBHhnQ_GgKvgli2xbCbiVylNyfWY7VVNpSXw,977
|
|
78
|
+
preditor/resource/img/format-letter-case.svg,sha256=iny15GecoxoRdExnnPNNWQqpqoWicDSTBSV8kRIYF3M,964
|
|
73
79
|
preditor/resource/img/information.png,sha256=vb_-kGXq2T_zeAJlrt5FJGSK8WUFYstzQl8WuMSfs5I,778
|
|
74
80
|
preditor/resource/img/logging_critical.png,sha256=lj4U6l8iRcgmWZWxdaJALvWn_KQELiqY936ZkPlRWJU,151
|
|
75
81
|
preditor/resource/img/logging_custom.png,sha256=zmVRkBX2CVjqD8QdnRKxv7Jss1114bhBt6vpDVkxxdo,297
|
|
@@ -86,6 +92,8 @@ preditor/resource/img/preditor.ico,sha256=HjJbjJ3MYBmw5pFmkY2hEaomK-zPO7LJsOgGgA
|
|
|
86
92
|
preditor/resource/img/preditor.png,sha256=y-AdFUy_zDnkylDe8kX1BTfwZS_TIgmEBqrHhx_IhWE,32788
|
|
87
93
|
preditor/resource/img/preditor.psd,sha256=SZgadVDuDAzlUcg6ymlfAL7uw_JzLb1PsmkSAoSazv0,200136
|
|
88
94
|
preditor/resource/img/preditor.svg,sha256=MRsRxcZw3HSJ4ZRDA3XMLytJX34QPJVIAET4lG613KU,3804
|
|
95
|
+
preditor/resource/img/regex.svg,sha256=nIZ6QnNUycEYB9wacB8-DcxzDdcb1ris0ewi3DzGwlM,682
|
|
96
|
+
preditor/resource/img/restart.svg,sha256=v3CFD1bROBch5n8vSQAzQqQc-bzvL_YwkD0JAhn4fuc,403
|
|
89
97
|
preditor/resource/img/skip-forward-outline.png,sha256=5PAOknMYBZcuzskG8OO_QGAjLvA8g9M08MgjTvxfDrM,475
|
|
90
98
|
preditor/resource/img/skip-next-outline.png,sha256=FUTDclE-U4nF5JhjvX-31QTwfv5pKgaX4UziY6UUioU,478
|
|
91
99
|
preditor/resource/img/skip-next.png,sha256=q9V896VWgwatGShqSL7Ebv8sia3Q2XwBv5Y4KaZA60o,446
|
|
@@ -132,14 +140,15 @@ preditor/scintilla/lexers/mulexer.py,sha256=Y2FVp6ZJ9CgLIuIvItOzXMMRemuToID66dpB
|
|
|
132
140
|
preditor/scintilla/lexers/pythonlexer.py,sha256=WgL74RQGvGgsdAL-l2ioOMybqRw7M0GG-SxmzXsW4xw,1682
|
|
133
141
|
preditor/scintilla/ui/finddialog.ui,sha256=CEXouVKqVCDOfMBciK-89OmsGe2Kr6XdMbSPiffp0PA,4048
|
|
134
142
|
preditor/stream/__init__.py,sha256=SxILA3U3W8aNfVBd_oJ4-WXkA214cl1zGLSCelFx5QU,2682
|
|
135
|
-
preditor/stream/director.py,sha256=
|
|
143
|
+
preditor/stream/director.py,sha256=Gklbl6jwTmB0BtyR6MZxRytdlufaz5MoiW9Le9WFTmo,2733
|
|
136
144
|
preditor/stream/manager.py,sha256=NP4lf6hd5L_Ui-9Ws66gVEk6ZL8YqF7BxOzUsdrh3v0,2811
|
|
137
145
|
preditor/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
138
146
|
preditor/utils/cute.py,sha256=LfF8gXMAkkQAdo4mm6J9aVkDLwWZbE6prQ0moDbtCys,1045
|
|
139
147
|
preditor/utils/stylesheets.py,sha256=EVWZNq3WnaRiyUPoYMKQo_dLEwbRyKu26b03I1JDA-s,1622
|
|
140
|
-
|
|
141
|
-
PrEditor-0.
|
|
142
|
-
PrEditor-0.
|
|
143
|
-
PrEditor-0.
|
|
144
|
-
PrEditor-0.
|
|
145
|
-
PrEditor-0.
|
|
148
|
+
preditor/utils/text_search.py,sha256=21kuSDTpLIPUcriB81WP1kWfzuDBuP13ZtHUtypP5jE,14218
|
|
149
|
+
PrEditor-0.3.0.dist-info/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
|
|
150
|
+
PrEditor-0.3.0.dist-info/METADATA,sha256=wl3HFhDCOPwPoRizXgfCytrF8KIK8T9ov7lYFXm51FI,9277
|
|
151
|
+
PrEditor-0.3.0.dist-info/WHEEL,sha256=DZajD4pwLWue70CAfc7YaxT1wLUciNBvN_TTcvXpltE,110
|
|
152
|
+
PrEditor-0.3.0.dist-info/entry_points.txt,sha256=mpe0HFD_oIEBNPTJNyUEbmMV6Ivrp4EuYyZ34C5d_PU,519
|
|
153
|
+
PrEditor-0.3.0.dist-info/top_level.txt,sha256=iX1_mrUOky_BQr2oG0l_MbEUYF6idyjiWSzu9z3irIw,9
|
|
154
|
+
PrEditor-0.3.0.dist-info/RECORD,,
|
preditor/__init__.py
CHANGED
|
@@ -113,7 +113,7 @@ def configure(name, parent_callback=None, excepthook=True, logging=True, streams
|
|
|
113
113
|
preditor.debug.BlurExcepthook.install()
|
|
114
114
|
|
|
115
115
|
|
|
116
|
-
def launch(run_workbox=False, app_id=None, name=None):
|
|
116
|
+
def launch(run_workbox=False, app_id=None, name=None, standalone=False):
|
|
117
117
|
"""Launches the preditor gui creating the QApplication instance if not
|
|
118
118
|
already created.
|
|
119
119
|
|
|
@@ -125,6 +125,9 @@ def launch(run_workbox=False, app_id=None, name=None):
|
|
|
125
125
|
app_id (str, optional): Set the QApplication's applicationName to this
|
|
126
126
|
value. This is normally only used when launching a standalone
|
|
127
127
|
instance of the PrEditor gui.
|
|
128
|
+
standalone (bool, optional): Launch PrEditor in standalone mode. This
|
|
129
|
+
enables extra options that only make sense when it is running as
|
|
130
|
+
its own app, not inside of another app.
|
|
128
131
|
|
|
129
132
|
Returns:
|
|
130
133
|
preditor.gui.loggerwindow.LoggerWindow: The instance of the PrEditor
|
|
@@ -147,7 +150,9 @@ def launch(run_workbox=False, app_id=None, name=None):
|
|
|
147
150
|
|
|
148
151
|
# Check if we can actually run the PrEditor gui and setup Qt if required
|
|
149
152
|
app = App(name=app_id)
|
|
150
|
-
widget = LoggerWindow.instance(
|
|
153
|
+
widget = LoggerWindow.instance(
|
|
154
|
+
run_workbox=run_workbox, name=name, standalone=standalone
|
|
155
|
+
)
|
|
151
156
|
|
|
152
157
|
# Show the PrEditor instance and make sure it regains focus and visibility
|
|
153
158
|
widget.show()
|
preditor/cli.py
CHANGED
|
@@ -66,7 +66,7 @@ def launch(name, run_workbox):
|
|
|
66
66
|
parameter_source = click.get_current_context().get_parameter_source('name')
|
|
67
67
|
app_id = get_app_id(name, parameter_source == ParameterSource.DEFAULT)
|
|
68
68
|
|
|
69
|
-
preditor.launch(run_workbox=run_workbox, app_id=app_id, name=name)
|
|
69
|
+
preditor.launch(run_workbox=run_workbox, app_id=app_id, name=name, standalone=True)
|
|
70
70
|
|
|
71
71
|
|
|
72
72
|
# shortcut
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
from __future__ import absolute_import, print_function
|
|
2
|
+
|
|
3
|
+
from Qt.QtCore import Qt
|
|
4
|
+
from Qt.QtGui import QIcon
|
|
5
|
+
from Qt.QtWidgets import QApplication, QShortcut, QWidget
|
|
6
|
+
|
|
7
|
+
from .. import resourcePath
|
|
8
|
+
from ..utils.text_search import RegexTextSearch, SimpleTextSearch
|
|
9
|
+
from . import loadUi
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class FindFiles(QWidget):
|
|
13
|
+
def __init__(self, parent=None, managers=None, console=None):
|
|
14
|
+
super(FindFiles, self).__init__(parent=parent)
|
|
15
|
+
if managers is None:
|
|
16
|
+
managers = []
|
|
17
|
+
self.managers = managers
|
|
18
|
+
self.console = console
|
|
19
|
+
self.finder = None
|
|
20
|
+
self.match_files_count = 0
|
|
21
|
+
|
|
22
|
+
loadUi(__file__, self)
|
|
23
|
+
|
|
24
|
+
# Set the icons
|
|
25
|
+
self.uiCaseSensitiveBTN.setIcon(
|
|
26
|
+
QIcon(resourcePath("img/format-letter-case.svg"))
|
|
27
|
+
)
|
|
28
|
+
self.uiCloseBTN.setIcon(QIcon(resourcePath('img/close-thick.png')))
|
|
29
|
+
self.uiRegexBTN.setIcon(QIcon(resourcePath("img/regex.svg")))
|
|
30
|
+
|
|
31
|
+
# Create shortcuts
|
|
32
|
+
self.uiCloseSCT = QShortcut(
|
|
33
|
+
Qt.Key_Escape, self, context=Qt.WidgetWithChildrenShortcut
|
|
34
|
+
)
|
|
35
|
+
self.uiCloseSCT.activated.connect(self.hide)
|
|
36
|
+
|
|
37
|
+
self.uiCaseSensitiveSCT = QShortcut(
|
|
38
|
+
Qt.AltModifier | Qt.Key_C, self, context=Qt.WidgetWithChildrenShortcut
|
|
39
|
+
)
|
|
40
|
+
self.uiCaseSensitiveSCT.activated.connect(self.uiCaseSensitiveBTN.toggle)
|
|
41
|
+
|
|
42
|
+
self.uiRegexSCT = QShortcut(
|
|
43
|
+
Qt.AltModifier | Qt.Key_R, self, context=Qt.WidgetWithChildrenShortcut
|
|
44
|
+
)
|
|
45
|
+
self.uiRegexSCT.activated.connect(self.uiRegexBTN.toggle)
|
|
46
|
+
|
|
47
|
+
def activate(self):
|
|
48
|
+
"""Called to make this widget ready for the user to interact with."""
|
|
49
|
+
self.show()
|
|
50
|
+
self.uiFindTXT.setFocus()
|
|
51
|
+
|
|
52
|
+
def find(self):
|
|
53
|
+
find_text = self.uiFindTXT.text()
|
|
54
|
+
context = self.uiContextSPN.value()
|
|
55
|
+
# Create an instance of the TextSearch to use for this search
|
|
56
|
+
if self.uiRegexBTN.isChecked():
|
|
57
|
+
TextSearch = RegexTextSearch
|
|
58
|
+
else:
|
|
59
|
+
TextSearch = SimpleTextSearch
|
|
60
|
+
self.finder = TextSearch(
|
|
61
|
+
find_text, self.uiCaseSensitiveBTN.isChecked(), context=context
|
|
62
|
+
)
|
|
63
|
+
self.finder.callback_matching = self.insert_found_text
|
|
64
|
+
self.finder.callback_non_matching = self.insert_text
|
|
65
|
+
|
|
66
|
+
self.insert_text(self.finder.title())
|
|
67
|
+
|
|
68
|
+
self.match_files_count = 0
|
|
69
|
+
for manager in self.managers:
|
|
70
|
+
for (
|
|
71
|
+
editor,
|
|
72
|
+
group_name,
|
|
73
|
+
tab_name,
|
|
74
|
+
group_index,
|
|
75
|
+
tab_index,
|
|
76
|
+
) in manager.all_widgets():
|
|
77
|
+
path = "/".join((group_name, tab_name))
|
|
78
|
+
workbox_id = '{},{}'.format(group_index, tab_index)
|
|
79
|
+
self.find_in_editor(editor, path, workbox_id)
|
|
80
|
+
|
|
81
|
+
self.insert_text(
|
|
82
|
+
'\n{} matches in {} workboxes\n'.format(
|
|
83
|
+
self.finder.match_count, self.match_files_count
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
def find_in_editor(self, editor, path, workbox_id):
|
|
88
|
+
# Ensure the editor text is loaded and get its raw text
|
|
89
|
+
editor.__show__()
|
|
90
|
+
text = editor.__text__()
|
|
91
|
+
|
|
92
|
+
# Use the finder to check for matches
|
|
93
|
+
found = self.finder.search_text(text, path, workbox_id)
|
|
94
|
+
if found:
|
|
95
|
+
self.match_files_count += 1
|
|
96
|
+
|
|
97
|
+
def insert_found_text(self, text, workbox_id, line_num, tool_tip):
|
|
98
|
+
href = ', {}, {}'.format(workbox_id, line_num)
|
|
99
|
+
cursor = self.console.textCursor()
|
|
100
|
+
# Insert hyperlink
|
|
101
|
+
fmt = cursor.charFormat()
|
|
102
|
+
fmt.setAnchor(True)
|
|
103
|
+
fmt.setAnchorHref(href)
|
|
104
|
+
fmt.setFontUnderline(True)
|
|
105
|
+
fmt.setToolTip(tool_tip)
|
|
106
|
+
cursor.insertText(text, fmt)
|
|
107
|
+
# Show the updated text output
|
|
108
|
+
QApplication.instance().processEvents()
|
|
109
|
+
|
|
110
|
+
def insert_text(self, text):
|
|
111
|
+
cursor = self.console.textCursor()
|
|
112
|
+
fmt = cursor.charFormat()
|
|
113
|
+
fmt.setAnchor(False)
|
|
114
|
+
fmt.setAnchorHref('')
|
|
115
|
+
fmt.setFontUnderline(False)
|
|
116
|
+
fmt.setToolTip('')
|
|
117
|
+
cursor.insertText(text, fmt)
|
|
118
|
+
# Show the updated text output
|
|
119
|
+
QApplication.instance().processEvents()
|
|
File without changes
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
from __future__ import absolute_import
|
|
2
|
+
|
|
3
|
+
from functools import partial
|
|
4
|
+
|
|
5
|
+
from Qt.QtCore import QModelIndex, QPoint, Qt, Signal
|
|
6
|
+
from Qt.QtWidgets import QFrame, QLineEdit, QListView, QShortcut, QVBoxLayout
|
|
7
|
+
|
|
8
|
+
from ..group_tab_widget.grouped_tab_models import GroupTabFuzzyFilterProxyModel
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class FuzzySearch(QFrame):
|
|
12
|
+
canceled = Signal("QModelIndex")
|
|
13
|
+
"""Passes the original QModelIndex for the tab that was selected when the
|
|
14
|
+
widget was first shown. This lets you reset back to the orignal state."""
|
|
15
|
+
highlighted = Signal("QModelIndex")
|
|
16
|
+
"""Emitted when the user navitages to the given index, but hasn't selected."""
|
|
17
|
+
selected = Signal("QModelIndex")
|
|
18
|
+
"""Emitted when the user selects a item."""
|
|
19
|
+
|
|
20
|
+
def __init__(self, model, parent=None, **kwargs):
|
|
21
|
+
super(FuzzySearch, self).__init__(parent=parent, **kwargs)
|
|
22
|
+
self.y_offset = 100
|
|
23
|
+
self.setMinimumSize(400, 200)
|
|
24
|
+
self.uiCloseSCT = QShortcut(
|
|
25
|
+
Qt.Key_Escape, self, context=Qt.WidgetWithChildrenShortcut
|
|
26
|
+
)
|
|
27
|
+
self.uiCloseSCT.activated.connect(self._canceled)
|
|
28
|
+
|
|
29
|
+
self.uiUpSCT = QShortcut(Qt.Key_Up, self, context=Qt.WidgetWithChildrenShortcut)
|
|
30
|
+
self.uiUpSCT.activated.connect(partial(self.increment_selection, -1))
|
|
31
|
+
self.uiDownSCT = QShortcut(
|
|
32
|
+
Qt.Key_Down, self, context=Qt.WidgetWithChildrenShortcut
|
|
33
|
+
)
|
|
34
|
+
self.uiDownSCT.activated.connect(partial(self.increment_selection, 1))
|
|
35
|
+
|
|
36
|
+
lyt = QVBoxLayout(self)
|
|
37
|
+
self.uiLineEDIT = QLineEdit(parent=self)
|
|
38
|
+
self.uiLineEDIT.textChanged.connect(self.update_completer)
|
|
39
|
+
self.uiLineEDIT.returnPressed.connect(self.activated)
|
|
40
|
+
lyt.addWidget(self.uiLineEDIT)
|
|
41
|
+
self.uiResultsLIST = QListView(self)
|
|
42
|
+
self.uiResultsLIST.activated.connect(self.activated)
|
|
43
|
+
self.proxy_model = GroupTabFuzzyFilterProxyModel(self)
|
|
44
|
+
self.proxy_model.setSourceModel(model)
|
|
45
|
+
self.uiResultsLIST.setModel(self.proxy_model)
|
|
46
|
+
lyt.addWidget(self.uiResultsLIST)
|
|
47
|
+
|
|
48
|
+
self.original_model_index = model.original_model_index
|
|
49
|
+
|
|
50
|
+
def activated(self):
|
|
51
|
+
current = self.uiResultsLIST.currentIndex()
|
|
52
|
+
self.selected.emit(current)
|
|
53
|
+
self.hide()
|
|
54
|
+
|
|
55
|
+
def increment_selection(self, direction):
|
|
56
|
+
current = self.uiResultsLIST.currentIndex()
|
|
57
|
+
col = 0
|
|
58
|
+
row = 0
|
|
59
|
+
if current.isValid():
|
|
60
|
+
col = current.column()
|
|
61
|
+
row = current.row() + direction
|
|
62
|
+
new = self.uiResultsLIST.model().index(row, col)
|
|
63
|
+
self.uiResultsLIST.setCurrentIndex(new)
|
|
64
|
+
self.highlighted.emit(new)
|
|
65
|
+
|
|
66
|
+
def update_completer(self, wildcard):
|
|
67
|
+
if wildcard:
|
|
68
|
+
if not self.uiResultsLIST.currentIndex().isValid():
|
|
69
|
+
new = self.uiResultsLIST.model().index(0, 0)
|
|
70
|
+
self.uiResultsLIST.setCurrentIndex(new)
|
|
71
|
+
else:
|
|
72
|
+
self.uiResultsLIST.clearSelection()
|
|
73
|
+
self.uiResultsLIST.setCurrentIndex(QModelIndex())
|
|
74
|
+
self.proxy_model.setFuzzySearch(wildcard)
|
|
75
|
+
self.highlighted.emit(self.uiResultsLIST.currentIndex())
|
|
76
|
+
|
|
77
|
+
def _canceled(self):
|
|
78
|
+
# Restore the original tab as the user didn't choose the new tab
|
|
79
|
+
self.canceled.emit(self.original_model_index)
|
|
80
|
+
self.hide()
|
|
81
|
+
|
|
82
|
+
def reposition(self):
|
|
83
|
+
pgeo = self.parent().geometry()
|
|
84
|
+
geo = self.geometry()
|
|
85
|
+
center = QPoint(pgeo.width() // 2, 0)
|
|
86
|
+
geo.moveCenter(center)
|
|
87
|
+
geo.setY(self.y_offset)
|
|
88
|
+
self.setGeometry(geo)
|
|
89
|
+
|
|
90
|
+
def popup(self):
|
|
91
|
+
self.show()
|
|
92
|
+
self.reposition()
|
|
93
|
+
self.uiLineEDIT.setFocus(Qt.PopupFocusReason)
|
|
@@ -114,11 +114,20 @@ class GroupTabWidget(OneTabWidget):
|
|
|
114
114
|
return parent, editor
|
|
115
115
|
|
|
116
116
|
def all_widgets(self):
|
|
117
|
-
"""
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
117
|
+
"""A generator yielding information about every widget under every group.
|
|
118
|
+
|
|
119
|
+
Yields:
|
|
120
|
+
widget, group tab name, widget tab name, group tab index, widget tab index
|
|
121
|
+
"""
|
|
122
|
+
for group_index in range(self.count()):
|
|
123
|
+
group_name = self.tabText(group_index)
|
|
124
|
+
|
|
125
|
+
tab_widget = self.widget(group_index)
|
|
126
|
+
for tab_index in range(tab_widget.count()):
|
|
127
|
+
tab_name = tab_widget.tabText(tab_index)
|
|
128
|
+
yield tab_widget.widget(
|
|
129
|
+
tab_index
|
|
130
|
+
), group_name, tab_name, group_index, tab_index
|
|
122
131
|
|
|
123
132
|
def close_current_tab(self):
|
|
124
133
|
"""Convenient method to close the currently open editor tab prompting
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
from __future__ import absolute_import
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
from Qt.QtCore import QSortFilterProxyModel, Qt
|
|
6
|
+
from Qt.QtGui import QStandardItem, QStandardItemModel
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class GroupTabItemModel(QStandardItemModel):
|
|
10
|
+
GroupIndexRole = Qt.UserRole + 1
|
|
11
|
+
TabIndexRole = GroupIndexRole + 1
|
|
12
|
+
|
|
13
|
+
def __init__(self, manager, *args, **kwargs):
|
|
14
|
+
super(GroupTabItemModel, self).__init__(*args, **kwargs)
|
|
15
|
+
self.manager = manager
|
|
16
|
+
|
|
17
|
+
def workbox_indexes_from_model_index(self, index):
|
|
18
|
+
"""Returns the group_index and tab_index for the provided QModelIndex"""
|
|
19
|
+
return (
|
|
20
|
+
index.data(self.GroupIndexRole),
|
|
21
|
+
index.data(self.TabIndexRole),
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
def pathFromIndex(self, index):
|
|
25
|
+
parts = [""]
|
|
26
|
+
while index.isValid():
|
|
27
|
+
parts.append(self.data(index, Qt.DisplayRole))
|
|
28
|
+
index = index.parent()
|
|
29
|
+
if len(parts) == 1:
|
|
30
|
+
return ""
|
|
31
|
+
return "/".join([x for x in parts[::-1] if x])
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class GroupTabTreeItemModel(GroupTabItemModel):
|
|
35
|
+
def process(self):
|
|
36
|
+
root = self.invisibleRootItem()
|
|
37
|
+
current_group = self.manager.currentIndex()
|
|
38
|
+
current_tab = self.manager.currentWidget().currentIndex()
|
|
39
|
+
|
|
40
|
+
prev_group = -1
|
|
41
|
+
all_widgets = self.manager.all_widgets()
|
|
42
|
+
for _, group_name, tab_name, group_index, tab_index in all_widgets:
|
|
43
|
+
if prev_group != group_index:
|
|
44
|
+
group_item = QStandardItem(group_name)
|
|
45
|
+
group_item.setData(group_index, self.GroupIndexRole)
|
|
46
|
+
root.appendRow(group_item)
|
|
47
|
+
prev_group = group_index
|
|
48
|
+
|
|
49
|
+
tab_item = QStandardItem(tab_name)
|
|
50
|
+
tab_item.setData(group_index, self.GroupIndexRole)
|
|
51
|
+
tab_item.setData(tab_index, self.TabIndexRole)
|
|
52
|
+
group_item.appendRow(tab_item)
|
|
53
|
+
if group_index == current_group and tab_index == current_tab:
|
|
54
|
+
self.original_model_index = self.indexFromItem(tab_item)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class GroupTabListItemModel(GroupTabItemModel):
|
|
58
|
+
def flags(self, index):
|
|
59
|
+
return Qt.ItemIsEnabled | Qt.ItemIsSelectable
|
|
60
|
+
|
|
61
|
+
def process(self):
|
|
62
|
+
root = self.invisibleRootItem()
|
|
63
|
+
current_group = self.manager.currentIndex()
|
|
64
|
+
current_tab = self.manager.currentWidget().currentIndex()
|
|
65
|
+
|
|
66
|
+
all_widgets = self.manager.all_widgets()
|
|
67
|
+
for _, group_name, tab_name, group_index, tab_index in all_widgets:
|
|
68
|
+
tab_item = QStandardItem('/'.join((group_name, tab_name)))
|
|
69
|
+
tab_item.setData(group_index, self.GroupIndexRole)
|
|
70
|
+
tab_item.setData(tab_index, self.TabIndexRole)
|
|
71
|
+
root.appendRow(tab_item)
|
|
72
|
+
if group_index == current_group and tab_index == current_tab:
|
|
73
|
+
self.original_model_index = self.indexFromItem(tab_item)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class GroupTabFuzzyFilterProxyModel(QSortFilterProxyModel):
|
|
77
|
+
"""Implements a fuzzy search filter proxy model."""
|
|
78
|
+
|
|
79
|
+
def __init__(self, parent=None):
|
|
80
|
+
super(GroupTabFuzzyFilterProxyModel, self).__init__(parent=parent)
|
|
81
|
+
self._fuzzy_regex = None
|
|
82
|
+
|
|
83
|
+
def setFuzzySearch(self, search):
|
|
84
|
+
search = '.*'.join(search)
|
|
85
|
+
# search = '.*{}.*'.format(search)
|
|
86
|
+
self._fuzzy_regex = re.compile(search, re.I)
|
|
87
|
+
self.invalidateFilter()
|
|
88
|
+
|
|
89
|
+
def filterAcceptsRow(self, sourceRow, sourceParent):
|
|
90
|
+
if self.filterKeyColumn() == 0 and self._fuzzy_regex:
|
|
91
|
+
|
|
92
|
+
index = self.sourceModel().index(sourceRow, 0, sourceParent)
|
|
93
|
+
data = self.sourceModel().data(index)
|
|
94
|
+
ret = bool(self._fuzzy_regex.search(data))
|
|
95
|
+
return ret
|
|
96
|
+
|
|
97
|
+
return super(GroupTabFuzzyFilterProxyModel, self).filterAcceptsRow(
|
|
98
|
+
sourceRow, sourceParent
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
def pathFromIndex(self, index):
|
|
102
|
+
parts = [""]
|
|
103
|
+
while index.isValid():
|
|
104
|
+
parts.append(self.data(index, Qt.DisplayRole))
|
|
105
|
+
index = index.parent()
|
|
106
|
+
if len(parts) == 1:
|
|
107
|
+
return ""
|
|
108
|
+
return "/".join([x for x in parts[::-1] if x])
|