Skip to content

Commit 2ba7b59

Browse files
committed
Optimize paste from clipboard
1 parent 0f7c8ce commit 2ba7b59

File tree

1 file changed

+63
-25
lines changed

1 file changed

+63
-25
lines changed

construct_editor/widgets/hex_editor.py

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from typing import Optional, Callable, List
1010
import math
1111
import typing as t
12+
import re
1213

1314
from construct_editor.helper import CallbackList
1415

@@ -918,17 +919,8 @@ def _paste(self, overwrite: bool = False, insert: bool = False) -> bool:
918919
clipboard = wx.TextDataObject()
919920
wx.TheClipboard.GetData(clipboard)
920921
wx.TheClipboard.Close()
921-
byts_str: str = clipboard.GetText()
922-
923-
# convert string to bytes
924-
try:
925-
byts_str = byts_str.replace(" ", "")
926-
byts = bytes.fromhex(byts_str)
927-
except Exception as e:
928-
wx.MessageBox(
929-
f"Can't convert data from clipboard to bytes.\n\n{str(e)}\n\nClipboard Data:\n{byts_str}",
930-
"Warning",
931-
)
922+
byts = self.string_to_byts(clipboard.GetText())
923+
if not byts:
932924
return False
933925

934926
# copy new data to the binary data
@@ -940,6 +932,35 @@ def _paste(self, overwrite: bool = False, insert: bool = False) -> bool:
940932
self.select_range(sel[0], sel[0] + len(byts) - 1)
941933
return True
942934

935+
def string_to_byts(self, byts_str: str):
936+
"""
937+
Normalize pasted string converting it to bytes (can be overridden).
938+
Return a "bytes" variable, or None in case or error.
939+
"""
940+
byts_str = (re.sub(r".*[\"'](.*)[\"'].*", r"\1", byts_str))
941+
try:
942+
byts = bytes.fromhex(byts_str)
943+
return byts
944+
except Exception:
945+
pass
946+
try:
947+
byts_str_conv = re.findall(r'[0-9A-Fa-fXx]+', byts_str)
948+
byts = bytes(map(lambda x: int(x, 16), byts_str_conv))
949+
return byts
950+
except Exception:
951+
pass
952+
try:
953+
byts = bytes(byts_str.encode('utf8', 'backslashreplace')
954+
.decode('unicode_escape'), encoding="raw_unicode_escape")
955+
return byts
956+
except Exception as e:
957+
wx.MessageBox(
958+
f"Can't convert data from clipboard to bytes.\n\n{str(e)}"
959+
f"\n\nProcessed clipboard data:\n{byts_str}",
960+
"Warning",
961+
)
962+
return None
963+
943964
def _undo(self):
944965
self._binary_data.command_processor.Undo()
945966

@@ -1025,53 +1046,70 @@ def _on_cell_right_click(self, event: Grid.GridEvent):
10251046
if select_cell:
10261047
self.SetGridCursor(event.GetRow(), event.GetCol())
10271048

1028-
menus = [
1049+
popup_menu = wx.Menu()
1050+
for menu in self.build_context_menu():
1051+
if menu is None:
1052+
popup_menu.AppendSeparator()
1053+
continue
1054+
if menu[3] != None: # checkbox boolean state
1055+
item: wx.MenuItem = popup_menu.AppendCheckItem(menu[0], menu[1])
1056+
item.Check(menu[3])
1057+
else:
1058+
item: wx.MenuItem = popup_menu.Append(menu[0], menu[1])
1059+
self.Bind(wx.EVT_MENU, menu[2], id=item.Id)
1060+
item.Enable(menu[4])
1061+
1062+
self.PopupMenu(popup_menu, event.GetPosition())
1063+
popup_menu.Destroy()
1064+
1065+
def build_context_menu(self):
1066+
"""Build the context menu. Can be overridden."""
1067+
return [
10291068
(
10301069
wx.ID_CUT,
10311070
"Cut\tCtrl+X",
10321071
lambda event: self._cut_selection(),
1072+
None,
10331073
not self.read_only,
10341074
),
1035-
(wx.ID_COPY, "Copy\tCtrl+C", lambda event: self._copy_selection(), True),
1075+
(
1076+
wx.ID_COPY,
1077+
"Copy\tCtrl+C",
1078+
lambda event: self._copy_selection(),
1079+
None,
1080+
True
1081+
),
10361082
(
10371083
wx.ID_PASTE,
10381084
"Paste (overwrite)\tCtrl+V",
10391085
lambda event: self._paste(overwrite=True),
1086+
None,
10401087
not self.read_only,
10411088
),
10421089
(
10431090
wx.ID_PASTE,
10441091
"Paste (insert)\tCtrl+Shift+V",
10451092
lambda event: self._paste(insert=True),
1093+
None,
10461094
not self.read_only,
10471095
),
10481096
None,
10491097
(
10501098
wx.ID_UNDO,
10511099
"Undo\tCtrl+Z",
10521100
lambda event: self._undo(),
1101+
None,
10531102
self._binary_data.command_processor.CanUndo(),
10541103
),
10551104
(
10561105
wx.ID_REDO,
10571106
"Redo\tCtrl+Y",
10581107
lambda event: self._redo(),
1108+
None,
10591109
self._binary_data.command_processor.CanRedo(),
10601110
),
10611111
]
10621112

1063-
popup_menu = wx.Menu()
1064-
for menu in menus:
1065-
if menu is None:
1066-
popup_menu.AppendSeparator()
1067-
continue
1068-
item: wx.MenuItem = popup_menu.Append(menu[0], menu[1])
1069-
self.Bind(wx.EVT_MENU, menu[2], id=item.Id)
1070-
item.Enable(menu[3])
1071-
1072-
self.PopupMenu(popup_menu, event.GetPosition())
1073-
popup_menu.Destroy()
1074-
10751113

10761114
# #####################################################################################################################
10771115
# ############################################## HexEditor ############################################################

0 commit comments

Comments
 (0)