Добавил:
СПбГУТ * ИКСС * Программная инженерия Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Содержание ВКР / ВКР 2022 (с приложениями). Коваленко Л.А. Разработка конструктора нейронных сетей

.pdf
Скачиваний:
129
Добавлен:
11.06.2022
Размер:
13.19 Mб
Скачать

27

28def apply(self):

29self._from_ui_to_model()

30self._emit_ui_signals_for_updating()

31self.close()

32

33def show(self):

34self._last_settings = self.app_settings.get_settings()

35super().show()

36

37def cancel(self):

38self.app_settings.set_settings(self._last_settings, ignore_main_window_settings=True)

39self._from_model_to_ui()

40self.close()

41

42def _from_model_to_ui(self):

43# combo box

44self.ui.code_font_combo_box.setCurrentFont(self.app_settings.code_font)

45self.ui.text_font_combo_box.setCurrentFont(self.app_settings.text_font)

46self.ui.caption_font_combo_box.setCurrentFont(self.app_settings.caption_font)

47# spin box

48self.ui.code_font_spin_box.setValue(self.app_settings.code_font.pointSize())

49self.ui.text_font_spin_box.setValue(self.app_settings.text_font.pointSize())

50self.ui.caption_font_spin_box.setValue(self.app_settings.caption_font.pointSize())

51self._emit_ui_signals_for_updating()

52

53def _from_ui_to_model(self):

54self.app_settings.code_font = QtGui.QFont(self.ui.code_font_combo_box.currentFont().family(),

55

self.ui.code_font_spin_box.value())

56

self.app_settings.text_font = QtGui.QFont(self.ui.text_font_combo_box.currentFont().family(),

57

self.ui.text_font_spin_box.value())

58

self.app_settings.caption_font =

QtGui.QFont(self.ui.caption_font_combo_box.currentFont().family(),

59

self.ui.caption_font_spin_box.value())

60

self._emit_ui_signals_for_updating()

61

 

62def _emit_ui_signals_for_updating(self):

63self.code_block_font_changed_signal.emit(self.app_settings.code_font)

64self.text_block_font_changed_signal.emit(self.app_settings.text_font)

65self.caption_font_changed_signal.emit(self.app_settings.caption_font)

67def load_settings_from_config_file(self, config_file: str):

68self.app_settings.load_settings_from_config_file(filename=config_file)

69self._from_model_to_ui()

70self._last_settings = self.app_settings.get_settings()

71

72def save_settings_to_config_file(self, config_file: str):

73self.app_settings.save_settings_to_config_file(filename=config_file)

75@QtCore.Slot()

76def reload_settings(self):

77self.app_settings.load_settings_from_config_file(filename=self.app_settings.config_file)

78self._from_model_to_ui()

79

80@staticmethod

81def _gc_collect():

82gc.disable()

83n = gc.collect()

84gc.enable()

85QtWidgets.QMessageBox(QtWidgets.QMessageBox.Icon.Question,

86

'Очистка неиспользуемой памяти',

87

f'Удалено объектов: {n}',

88

QtWidgets.QMessageBox.Ok).exec()

121

ПРИЛОЖЕНИЕ В. Модуль «views/code_highlighter.py»

1import keyword

2import token

3import tokenize

4from copy import copy

5from io import StringIO

7from PySide6 import QtCore, QtGui

10class HighlightingRule:

11def __init__(self,

12

pattern: QtCore.QRegularExpression = None,

13

format: QtGui.QTextCharFormat = None):

14self.pattern = pattern

15self.format = format

18class CodeHighlighter(QtGui.QSyntaxHighlighter):

19elements_foreground = {

20'KEYWORD': '#008000', 'BUILTIN_NAME': '#008000', 'DECORATOR': '#AA22FF',

21'CLASS_AND_DEF': '#0000FF', 'PROPERTY': '#0055AA', 'SELF': '#0055AA',

22token.LPAR: '#212121', token.RPAR: '#212121', token.COMMA: '#212121',

23token.DOT: '#212121', token.COLON: '#212121', token.SEMI: '#212121',

24token.LSQB: '#212121', token.RSQB: '#212121', token.LBRACE: '#212121',

25token.RBRACE: '#212121', token.STRING: '#BA2121', token.NUMBER: '#008800',

26token.NAME: '#212121', token.OP: '#AA22FF', token.ERRORTOKEN: '#FF0000',

27token.COMMENT: '#6E7781', token.ENCODING: '#408080',

28}

29

30def __init__(self, parent=None):

31super().__init__(parent)

32highlighting_rule = HighlightingRule()

33self.highlighting_rules = []

34

35# formats

36self.formats = dict()

37for element, color in self.elements_foreground.items():

38

self.formats[element] = QtGui.QTextCharFormat()

39

self.formats[element].setForeground(QtGui.QColor(color))

40

 

41# keyword

42softkwlist = []

43try:

44

softkwlist = list(keyword.softkwlist)

45

except:

46

pass

47keyword_patterns = list(keyword.kwlist) + softkwlist

48highlighting_rule.format = copy(self.formats['KEYWORD'])

49for pattern in keyword_patterns:

50

highlighting_rule.pattern = QtCore.QRegularExpression(r'\b' + pattern + r'\b')

51

self.highlighting_rules.append(copy(highlighting_rule))

52

 

53# builtin

54highlighting_rule.format = copy(self.formats['BUILTIN_NAME'])

55for builtin in set(__builtins__.keys()) | {'self'}:

56

highlighting_rule.pattern = QtCore.QRegularExpression(r'\b' + builtin + r'\b')

57

self.highlighting_rules.append(copy(highlighting_rule))

58

 

59# decorator

60highlighting_rule.format = copy(self.formats['DECORATOR'])

61highlighting_rule.pattern = QtCore.QRegularExpression(r'@\w+?\b')

62self.highlighting_rules.append(copy(highlighting_rule))

63

64# class, def

65highlighting_rule.format = copy(self.formats['CLASS_AND_DEF'])

66highlighting_rule.pattern =

QtCore.QRegularExpression(r'(?<=class\s)(.*)(?=\()|(?<=def\s)(.*)(?=\()') 67 self.highlighting_rules.append(copy(highlighting_rule))

68

69# property/method

70highlighting_rule.format = copy(self.formats['PROPERTY'])

71highlighting_rule.pattern = QtCore.QRegularExpression(r'(?<=\.).+?\b')

72self.highlighting_rules.append(copy(highlighting_rule))

73

122

74def highlightBlock(self, text: str) -> None:

75start = 0

76if self.previousBlockState() == 1:

77

text = "'''" + text

78

start = 3

79

elif self.previousBlockState() == 2:

80

text = '"""' + text

81

start = 3

82

elif self.previousBlockState() == 3:

83

self.setFormat(0, len(text), self.formats[token.ERRORTOKEN])

84

self.setCurrentBlockState(3)

85

return

86

try:

87

for tok in tokenize.generate_tokens(StringIO(text).read):

88

tok_format = None

89

if tok.exact_type in self.formats:

90

tok_format = self.formats[tok.exact_type]

91

elif tok.type in self.formats:

92

tok_format = self.formats[tok.type]

93

if tok_format:

94

from_ = tok.start[1]

95

to_ = tok.end[1]

96

count_ = to_ - from_

97

self.setFormat(max(0, from_ - start), count_, tok_format)

98

if tok.type in (token.STRING, token.COMMENT):

99

text = text[:from_] + ' ' * count_ + text[to_:]

100except BaseException as e:

101e = e.args

102if isinstance(e, tuple) and len(e) >= 2 and isinstance(e[1], tuple) \

103

and len(e[1]) >= 2 and isinstance(e[1][1], int):

104

position_in_block = (e[1][0] - 1) * (len(text) - 1) + e[1][1]

105

print(e, repr(text), text[position_in_block])

106

if text[position_in_block:position_in_block + 3] == "'''" or \

107

text[position_in_block:position_in_block + 4] == "r'''" or \

108

text[position_in_block:position_in_block + 5] in ("rb'''", "rf'''"):

109

from_ = position_in_block

110

to_ = len(text) - position_in_block

111

count_ = to_ - from_

112

self.setFormat(max(0, from_ - start), count_, self.formats[token.STRING])

113

self.setCurrentBlockState(1)

114

text = text[:from_] + ' ' * count_ + text[to_:]

115

elif text[position_in_block:position_in_block + 3] == '"""' or \

116

text[position_in_block:position_in_block + 4] == 'r"""' or \

117

text[position_in_block:position_in_block + 5] in ('rb"""', 'rf"""'):

118

from_ = position_in_block

119

to_ = len(text) - position_in_block

120

count_ = to_ - from_

121

self.setFormat(max(0, from_ - start), count_, self.formats[token.STRING])

122

self.setCurrentBlockState(2)

123

text = text[:from_] + ' ' * count_ + text[to_:]

124else:

125self.setCurrentBlockState(0)

126if self.currentBlockState() == 3:

127return

128for rule in self.highlighting_rules:

129match_iterator = rule.pattern.globalMatch(text)

130while match_iterator.hasNext():

131

match = match_iterator.next()

132

from_ = match.capturedStart()

133

to_ = match.capturedEnd()

134

count_ = to_ - from_

135

self.setFormat(max(0, from_ - start), count_, rule.format)

136

text = text[:from_] + ' ' * count_ + text[to_:]

137

return

123

124

ПРИЛОЖЕНИЕ Г. Модуль «views/code_item.py»

1import re

2from typing import Union, Sequence

4from PySide6 import QtCore, QtWidgets, QtGui

6from views.autogen.code_item import Ui_CodeItem

7from views.code_highlighter import CodeHighlighter

10class CodeTextBox(QtWidgets.QTextEdit):

11font_changed = QtCore.Signal()

13spaces = ' ' * 4

14n_spaces = len(spaces)

16def __init__(self, code: str = ''):

17super().__init__()

18self.sizePolicy().setHorizontalStretch(1)

19self.setAcceptRichText(False)

20self.highlighter = CodeHighlighter(self.document())

21self.setLineWrapMode(QtWidgets.QTextEdit.LineWrapMode.NoWrap)

22self.setPlainText(code)

23self.setTabStopDistance(35)

24self.startswith_add_indent = \

25

re.compile(r'\b(async def|def|class|if|elif|else|try|except|finally|for|while|with)\b')

26

self.startswith_del_indent = \

27

re.compile(r'\b(break|continue|raise|return|pass)\b')

28

self.setFont(self.font())

29

 

30def setFont(self, font: Union[QtGui.QFont, str, Sequence[str]]) -> None:

31super().setFont(font)

32self.font_changed.emit()

33

34def keyPressEvent(self, e: QtGui.QKeyEvent) -> None:

35text_cursor = self.textCursor()

36has_selection = text_cursor.hasSelection()

37e_text = e.text()

38# Tab (Indent)

39if e.key() == QtGui.Qt.Key_Tab:

40

text_cursor.beginEditBlock()

41

 

42

if not has_selection:

43

text_cursor.insertText(self.spaces[text_cursor.positionInBlock() % self.n_spaces:])

44

text_cursor.endEditBlock()

45

return

46

 

47

start_block = self.document().findBlock(text_cursor.selectionStart())

48

end_block = self.document().findBlock(text_cursor.selectionEnd())

49

text_cursor.setPosition(start_block.position())

50

text_cursor.setPosition(end_block.position() + end_block.length() - 1,

QtGui.QTextCursor.KeepAnchor)

51

 

52

text = text_cursor.selectedText()

53

text_length = len(text)

54

start = text_cursor.selectionStart()

55

end = text_cursor.selectionEnd()

56

lines = []

57

for line in text.splitlines():

58

not_space_pos = next((i for i, x in enumerate(start_block.text()) if not x.isspace()), 0)

59

lines.append(self.spaces[not_space_pos % self.n_spaces:] + line)

60

text = '\n'.join(lines)

61

text_cursor.removeSelectedText()

62

text_cursor.insertText(text)

63

text_cursor.setPosition(start)

64

text_cursor.setPosition(end + len(text) - text_length, QtGui.QTextCursor.KeepAnchor)

65

text_cursor.endEditBlock()

66

self.setTextCursor(text_cursor)

67

return

68

# BackTab (Dedent)

69

if e.key() == QtGui.Qt.Key_Backtab:

70

text_cursor.beginEditBlock()

71

 

72

if not has_selection:

73

block = text_cursor.block()

74

block_position = block.position()

75

text_cursor.setPosition(block_position)

76

not_space_pos = next((i for i, x in enumerate(block.text()) if not x.isspace()),

block.length() - 1)

77

text_cursor.setPosition(block_position + not_space_pos, QtGui.QTextCursor.KeepAnchor)

78

text_cursor.removeSelectedText()

79

text_cursor.insertText(self.spaces * ((not_space_pos - 1) // self.n_spaces))

80

text_cursor.endEditBlock()

81

self.setTextCursor(text_cursor)

82

return

83

 

84

start_block = self.document().findBlock(text_cursor.selectionStart())

85

end_block = self.document().findBlock(text_cursor.selectionEnd())

86

text_cursor.setPosition(start_block.position())

87

text_cursor.setPosition(end_block.position() + end_block.length() - 1,

QtGui.QTextCursor.KeepAnchor)

88

text = text_cursor.selectedText()

89

text_length = len(text)

90

start = text_cursor.selectionStart()

91

end = text_cursor.selectionEnd()

92

lines = []

93

for line in text.splitlines():

94

not_space_pos = next((i for i, x in enumerate(line) if not x.isspace()), len(line))

95

lines.append(self.spaces * ((not_space_pos - 1) // self.n_spaces) + line[not_space_pos:])

96

text = '\n'.join(lines)

97

text_cursor.removeSelectedText()

98

text_cursor.insertText(text)

99

text_cursor.setPosition(start)

100text_cursor.setPosition(end + len(text) - text_length, QtGui.QTextCursor.KeepAnchor)

101text_cursor.endEditBlock()

102self.setTextCursor(text_cursor)

103return

104# Ctrl+C & Ctrl+X

105if e.key() in (QtGui.Qt.Key_C, QtGui.Qt.Key_X) and e.modifiers() & QtGui.Qt.ControlModifier \

106

and not has_selection:

107block = text_cursor.block()

108text_cursor.setPosition(block.position())

109text_cursor.setPosition(block.position() + block.length() -

110

(block.blockNumber() == self.document().blockCount() - 1),

111

QtGui.QTextCursor.KeepAnchor)

112self.setTextCursor(text_cursor)

113super().keyPressEvent(e)

114return

115# Ctrl+D

116if e.key() == QtGui.Qt.Key_D and e.modifiers() & QtGui.Qt.ControlModifier:

117text_cursor.beginEditBlock()

118if not has_selection:

119

block = text_cursor.block()

120

text_cursor.setPosition(block.position())

121

text_cursor.setPosition(block.position() + block.length() -

122

(block.blockNumber() == self.document().blockCount() - 1),

123

QtGui.QTextCursor.KeepAnchor)

124end = text_cursor.selectionEnd()

125text = text_cursor.selectedText()

126text_cursor.setPosition(end)

127text_cursor.insertText(text)

128start = end

129end = text_cursor.position()

130text_cursor.setPosition(start)

131text_cursor.setPosition(end, QtGui.QTextCursor.KeepAnchor)

132text_cursor.endEditBlock()

133self.setTextCursor(text_cursor)

134return

135# Backspace

136if e.key() == QtGui.Qt.Key_Backspace and not has_selection:

137block = text_cursor.block()

138position = text_cursor.position()

139text_cursor.setPosition(block.position())

140text_cursor.setPosition(position, QtGui.QTextCursor.KeepAnchor)

141text = text_cursor.selectedText()[::-1]

142if text and text[0] == self.spaces[0]:

143

text_cursor.beginEditBlock()

144

m1

= next((i for i, x in enumerate(text) if not x.isspace()), len(text))

145

m2

= len(text) % 4 or 4

146

text_cursor.setPosition(position)

147

for i in range(min(m1, m2)):

148

 

text_cursor.deletePreviousChar()

 

 

125

149

text_cursor.endEditBlock()

150

self.setTextCursor(text_cursor)

151

return

152# Ctrl+/

153elif e.key() == QtGui.Qt.Key_Slash and e.modifiers() & QtGui.Qt.ControlModifier:

154text_cursor.beginEditBlock()

155

 

156

if not has_selection:

157

block = text_cursor.block()

158

block_text = block.text()

159

not_space_idx = next((i for i, x in enumerate(block_text) if not x.isspace()), None)

160

if not_space_idx is not None and block_text[not_space_idx] == '#': # uncomment

161

text_cursor.setPosition(block.position() + not_space_idx)

162

text_cursor.deleteChar()

163

if not_space_idx + 1 < len(block_text) and block_text[not_space_idx + 1] == ' ':

164

text_cursor.deleteChar()

165

text_cursor.endEditBlock()

166

self.setTextCursor(text_cursor)

167

return

168

 

169

# comment

170

block_position = block.position()

171

text_cursor.setPosition(block_position)

172

not_space_pos = next((i for i, x in enumerate(block.text()) if not x.isspace()),

block.length() - 1)

173

text_cursor.setPosition(block_position + not_space_pos)

174

text_cursor.insertText('# ')

175

text_cursor.endEditBlock()

176

self.setTextCursor(text_cursor)

177

return

178

 

179start_block_position = self.document().findBlock(text_cursor.selectionStart()).position()

180end_block = self.document().findBlock(text_cursor.selectionEnd())

181text_cursor.setPosition(start_block_position)

182text_cursor.setPosition(end_block.position() + end_block.length() - 1, QtGui.QTextCursor.KeepAnchor)

183text = text_cursor.selectedText()

184lines = text.splitlines()

185new_lines = []

186for line in lines:

187

not_space_idx = next((i for i, x in enumerate(line) if not x.isspace()), None)

188

if not_space_idx is not None and line[not_space_idx] == '#': # uncomment

189

one_space = int(not_space_idx + 1 < len(line) and line[not_space_idx + 1] == ' ')

190

new_line = line[:not_space_idx] + line[not_space_idx + 1 + one_space:]

191

else: # comment

192

new_line = '# ' + line

193

new_lines.append(new_line)

194new_text = '\n'.join(new_lines)

195text_cursor.removeSelectedText()

196text_cursor.insertText(new_text)

197position = text_cursor.position()

198text_cursor.setPosition(start_block_position)

199text_cursor.setPosition(position, QtGui.QTextCursor.KeepAnchor)

200text_cursor.endEditBlock()

201self.setTextCursor(text_cursor)

202return

203# Enter

204if e.key() == QtGui.Qt.Key_Return:

205block = text_cursor.block()

206if text_cursor.positionInBlock() + 1 == block.length():

207

text_cursor.beginEditBlock()

208

line = block.text()

209

not_space_pos = next((i for i, x in enumerate(line) if not x.isspace()), len(line))

210

source_indent = ((not_space_pos + self.n_spaces - 1) // self.n_spaces)

211

add_indent = bool(self.startswith_add_indent.match(line[not_space_pos:]))

212

del_indent = bool(self.startswith_del_indent.match(line[not_space_pos:]))

213

text_cursor.insertText('\n' + self.spaces * (source_indent + add_indent - del_indent))

214

text_cursor.endEditBlock()

215

self.setTextCursor(text_cursor)

216

return

217

e = QtGui.QKeyEvent(e.type(),

218

e.key(),

219

e.modifiers(),

220

e_text)

221

super().keyPressEvent(e)

222

 

223

def insertPlainText(self, text: str) -> None: # Ctrl+V

 

126

224if not text:

225return

226if text.isspace():

227self.textCursor().insertText(text.replace('\t', self.spaces))

228return

229text_cursor = self.textCursor()

230line = text_cursor.block().text()

231not_space_pos = next((i for i, x in enumerate(line) if not x.isspace()), len(line))

232prefix_indent = ((not_space_pos + self.n_spaces - 1) // self.n_spaces)

233# remove prefix

234lines = text.replace('\t', self.spaces).splitlines()

235

236new_lines = []

237common_indent = None

238for i, line in enumerate(lines):

239line_indent = next((i for i, x in enumerate(line) if not x.isspace()), len(line))

240indent = (line_indent + self.n_spaces - 1) // self.n_spaces

241if common_indent is None:

242

common_indent = indent

243

else:

244

common_indent = min(common_indent, indent)

245

new_lines.append((indent, line[line_indent:]))

246

 

247r_lines = []

248for i, (indent, line) in enumerate(new_lines):

249new_indent = indent - common_indent + prefix_indent * (i != 0)

250r_lines.append(self.spaces * new_indent + line)

251# add prefix

252text = '\n'.join(line.rstrip(' ') if not line.isspace() else line

253

for i, line in enumerate(r_lines))

254

text_cursor.insertText(text)

255

 

256def insertFromMimeData(self, source: QtCore.QMimeData) -> None: # Ctrl+V

257self.insertPlainText(source.text())

258

259

260class OutputTextBox(QtWidgets.QTextEdit):

261font_changed = QtCore.Signal()

262hide_show_signal = QtCore.Signal(bool)

264def __init__(self, init_text: str = ''):

265super().__init__()

266self.sizePolicy().setHorizontalStretch(1)

267self.setAcceptRichText(False)

268self.setLineWrapMode(QtWidgets.QTextEdit.LineWrapMode.NoWrap)

269self.setPlainText(init_text)

270self.setTabStopDistance(35)

271self.setReadOnly(True)

272self.setFont(self.font())

274def setFont(self, font: Union[QtGui.QFont, str, Sequence[str]]) -> None:

275super().setFont(font)

276self.font_changed.emit()

278@QtCore.Slot(bool)

279def hide_show_slot(self, visible: bool = None):

280self.hide_show_signal.emit(visible)

281

282

283class CodeItem(QtWidgets.QWidget):

284execute_signal = QtCore.Signal(QtWidgets.QLabel, QtWidgets.QTextEdit, QtWidgets.QTextEdit)

285stop_signal = QtCore.Signal(QtWidgets.QLabel, QtWidgets.QTextEdit, QtWidgets.QTextEdit, bool)

286del_signal = QtCore.Signal()

287change_height_signal = QtCore.Signal(QtCore.QSize)

288changed_signal = QtCore.Signal()

289

 

290

def __init__(self, caption: str = '',

291

code: str = '', *,

292

hint: str = '',

293

output: str = '',

294

show_output: bool = ...):

295super().__init__()

296self.ui = Ui_CodeItem()

297self.ui.setupUi(self)

298self.min_widget_height = 110

299self.setMinimumHeight(self.min_widget_height)

127

301# add code editor

302self.code_editor = CodeTextBox()

303self.code_editor.textChanged.connect(self.change_size_slot)

304self.code_editor.font_changed.connect(self.change_size_slot)

305self.code_editor.textChanged.connect(self.changed_signal)

306self.ui.code_frame_vertical_layout.addWidget(self.code_editor)

308# add output text box

309self.output_text_box = OutputTextBox()

310self.output_text_box_min_height = 50

311self.output_text_box_max_height = 200

312self.output_text_box.setHtml(output)

313self.output_text_box.setMinimumHeight(self.output_text_box_min_height)

314self.output_text_box.setMaximumHeight(self.output_text_box_max_height)

315self.output_text_box.textChanged.connect(self.change_size_slot)

316self.output_text_box.font_changed.connect(self.change_size_slot)

317self.output_text_box.textChanged.connect(self.changed_signal)

318self.output_text_box.hide_show_signal.connect(self.hide_show_output_slot)

319self.ui.output_frame_vertical_layout.addWidget(self.output_text_box)

320 self.ui.output_frame_vertical_layout.setSizeConstraint(QtWidgets.QLayout.SizeConstraint.SetMaximumSize) 321

322# caption and indicator labels

323self.ui.code_caption.setText(caption)

324self.code_caption = self.ui.code_caption

325self.code_caption.textChanged.connect(self.changed_signal)

326self.ui.indicator_label.setText(hint)

327self.ui.indicator_label.setFont(QtGui.QFont('Consolas', 11))

328self.indicator_label = self.ui.indicator_label

329

330# signals and slots

331self.ui.start_button.clicked.connect(self.execute_slot)

332self.ui.stop_button.clicked.connect(self.stop_slot)

333self.ui.del_button.clicked.connect(self.del_slot)

334self.ui.del_button.clicked.connect(self.changed_signal)

335self.ui.hide_show_output_button.clicked.connect(self.hide_show_output_slot)

337# update widget

338self.code_editor.setPlainText(code)

339output = len(self.output_text_box.toPlainText())

340if show_output is not ...:

341self.hide_show_output_slot(show_output)

342elif output:

343self.hide_show_output_slot(True)

344else:

345self.hide_show_output_slot(False)

346

347@QtCore.Slot()

348def execute_slot(self):

349self.execute_signal.emit(self.indicator_label, self.code_editor, self.output_text_box)

351@QtCore.Slot()

352def stop_slot(self, force: bool = False, del_reason: bool = False):

353if force or QtWidgets.QMessageBox(QtWidgets.QMessageBox.Icon.Question,

354

'Вопрос',

355

'Подтвердить остановку блока кода?',

356

QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,

357

self).exec() == QtWidgets.QMessageBox.Yes:

358

self.stop_signal.emit(self.indicator_label, self.code_editor, self.output_text_box,

del_reason)

 

359

 

360@QtCore.Slot()

361def del_slot(self, force: bool = False):

362if force or QtWidgets.QMessageBox(QtWidgets.QMessageBox.Icon.Question,

363

'Вопрос',

364

'Подтвердить остановку и удаление блока кода?',

365

QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,

366

self).exec() == QtWidgets.QMessageBox.Yes:

367self.stop_slot(force=True, del_reason=True)

368self.del_signal.emit()

369

370@QtCore.Slot(bool)

371def hide_show_output_slot(self, visible: bool = None):

372if not visible or visible is None and not self.output_text_box.isHidden(): # not use isVisible!

373self.output_text_box.hide()

374self.ui.hide_show_output_button.setChecked(False)

375elif visible or visible is None and self.output_text_box.isHidden():

128

376self.output_text_box.show()

377self.ui.hide_show_output_button.setChecked(True)

378self.change_size_slot()

379self.output_text_box.setTextColor(QtGui.QColor().black())

381@QtCore.Slot()

382def change_size_slot(self):

383height_1 = max(self.min_widget_height,

384

self.code_editor.document().size().height()) + \

385

self.code_editor.horizontalScrollBar().height() * 3 // 2

386

height_2 = min(max(self.output_text_box_min_height,

387

self.output_text_box.document().size().height()),

388

self.output_text_box_max_height) + \

389

self.output_text_box.horizontalScrollBar().height() * 3 // 2

390self.code_editor.setFixedHeight(height_1)

391self.output_text_box.setFixedHeight(height_2)

392widget_height = self.code_editor.height() + \

393

self.code_caption.height() + \

394

self.ui.main_vertical_layout.contentsMargins().top() * 2 + \

395

self.ui.main_vertical_layout.contentsMargins().bottom() * 2 + \

396

int((not self.output_text_box.isHidden()) * self.output_text_box.height())

397self.setMinimumHeight(widget_height)

398self.change_height_signal.emit(QtCore.QSize(self.width(), widget_height))

400@QtCore.Slot(QtGui.QFont)

401def change_font(self, font: QtGui.QFont):

402self.code_editor.setFont(font)

403self.output_text_box.setFont(font)

ПРИЛОЖЕНИЕ Д. Модуль «views/text_item.py»

1 from typing import Union, Sequence

2

3 from PySide6 import QtWidgets, QtCore, QtGui

4

5 from views.autogen.text_item import Ui_TextItem

6

7

8class TextBox(QtWidgets.QTextEdit):

9font_changed = QtCore.Signal()

11def __init__(self, text: str = ''):

12super().__init__()

13self.setAcceptRichText(False)

14self.sizePolicy().setHorizontalStretch(1)

15self.setLineWrapMode(QtWidgets.QTextEdit.LineWrapMode.WidgetWidth)

16self.setHtml(text)

17self.setTabStopDistance(35)

18self.block_height = 0

19self.setFont(self.font())

20self.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.TextBrowserInteraction

21

| QtCore.Qt.TextInteractionFlag.TextEditorInteraction)

22

self._images = dict()

23

 

24@QtCore.Slot(QtGui.QFont)

25def setFont(self, font: Union[QtGui.QFont, str, Sequence[str]]) -> None:

26super().setFont(font)

27self.font_changed.emit()

28

29@QtCore.Slot(QtGui.QMouseEvent)

30def mousePressEvent(self, event: QtGui.QMouseEvent) -> None:

31if event.button() == QtGui.Qt.RightButton:

32

menu = self.createStandardContextMenu()

33

if menu is not None:

34

insert_plain_text_action = QtGui.QAction('Paste Plain Text')

35

insert_html_action = QtGui.QAction('Paste HTML')

36

insert_markdown_action = QtGui.QAction('Paste Markdown')

37

insert_plain_text_action.triggered.connect(self.insert_plain_text_slot)

38

insert_html_action.triggered.connect(self.insert_html_slot)

39

insert_markdown_action.triggered.connect(self.insert_markdown_slot)

40

menu.addSeparator()

41

menu.addAction(insert_html_action)

42

menu.addAction(insert_markdown_action)

43

menu.addAction(insert_plain_text_action)

44

menu.exec(event.globalPos())

 

129

45

else:

46

super().mouseReleaseEvent(event)

47

 

48@QtCore.Slot(str)

49def insertHtml(self, text: str) -> None:

50super(TextBox, self).insertHtml(text)

51self.edit_document_images()

52

53@QtCore.Slot(str)

54def setHtml(self, text: str) -> None:

55super(TextBox, self).setHtml(text)

56self.edit_document_images()

57

58@QtCore.Slot()

59def insert_plain_text_slot(self):

60try:

61

text = QtGui.QClipboard().text()

62

if text:

63

self.insertPlainText(text)

64

except:

65

__import__('traceback').print_exc()

66

 

67@QtCore.Slot()

68def insert_html_slot(self):

69try:

70

text = QtGui.QClipboard().text()

71

if text:

72

self.insertHtml(text)

73

except:

74

__import__('traceback').print_exc()

75

 

76@QtCore.Slot()

77def insert_markdown_slot(self):

78try:

79

markdown = QtGui.QClipboard().text()

80

if markdown:

81

text_edit = QtWidgets.QTextEdit()

82

text_edit.setMarkdown(markdown)

83

text_edit.setFont(self.font())

84

html = text_edit.toHtml()

85

if html:

86

self.insertHtml(html)

87

text_edit.deleteLater()

88

except:

89

__import__('traceback').print_exc()

90

 

91@QtCore.Slot(QtCore.QMimeData)

92def canInsertFromMimeData(self, source: QtCore.QMimeData) -> bool:

93return source.hasImage() or source.hasUrls() or super().canInsertFromMimeData(source)

95@QtCore.Slot(QtCore.QMimeData)

96def insertFromMimeData(self, source: QtCore.QMimeData) -> None:

97if source.hasImage():

98

self.drop_image(QtCore.QUrl(), source.imageData())

99elif source.hasUrls():

100for url in source.urls():

101

info = QtCore.QFileInfo(url.toLocalFile())

102

if info.suffix().lower() in QtGui.QImageReader.supportedImageFormats():

103

self.drop_image(url, QtGui.QImage(info.filePath()))

104

else:

105

self.drop_text_file(url)

106else:

107super().insertFromMimeData(source)

109@QtCore.Slot()

110def edit_document_images(self):

111global_it = self.document().begin()

112while global_it.isValid():

113it = global_it.begin()

114while it != global_it.end():

115

current_fragment: QtGui.QTextFragment = it.fragment()

116

if current_fragment.isValid():

117

if current_fragment.charFormat().isImageFormat():

118

image_format = current_fragment.charFormat().toImageFormat()

119

image_name = image_format.name()

120

image_data = self.document().resource(QtGui.QTextDocument.ImageResource,

image_name)

 

 

130