Coverage for src/robotide/ui/treenodehandlers.py: 52%

487 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-05-06 10:40 +0100

1# Copyright 2008-2015 Nokia Networks 

2# Copyright 2016- Robot Framework Foundation 

3# 

4# Licensed under the Apache License, Version 2.0 (the "License"); 

5# you may not use this file except in compliance with the License. 

6# You may obtain a copy of the License at 

7# 

8# http://www.apache.org/licenses/LICENSE-2.0 

9# 

10# Unless required by applicable law or agreed to in writing, software 

11# distributed under the License is distributed on an "AS IS" BASIS, 

12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

13# See the License for the specific language governing permissions and 

14# limitations under the License. 

15 

16import builtins 1ab

17import wx 1ab

18 

19from ..controller import ctrlcommands, filecontrollers, macrocontrollers, settingcontrollers 1ab

20from ..controller.ctrlcommands import SortTests, SortVariables 1ab

21from ..editor.editordialogs import (TestCaseNameDialog, UserKeywordNameDialog, ScalarVariableDialog, ListVariableDialog, 1ab

22 CopyUserKeywordDialog, DictionaryVariableDialog) 

23from ..publish import RideOpenVariableDialog, RideTestSelectedForRunningChanged, RideSettingsChanged, PUBLISHER 1ab

24from ..ui.progress import LoadProgressObserver 1ab

25from ..usages.UsageRunner import Usages, ResourceFileUsages 1ab

26from ..widgets import RIDEDialog, PopupMenuItems 1ab

27from .filedialogs import (AddSuiteDialog, AddDirectoryDialog, ChangeFormatDialog, NewResourceDialog, 1ab

28 RobotFilePathDialog) 

29from .progress import RenameProgressObserver 1ab

30from .resourcedialogs import ResourceRenameDialog, ResourceDeleteDialog 1ab

31from ..ui.resourcedialogs import FolderDeleteDialog 1ab

32 

33_ = wx.GetTranslation # To keep linter/code analyser happy 1ab

34builtins.__dict__['_'] = wx.GetTranslation 1ab

35 

36FILE_MANAGER = 'file manager' 1ab

37LABEL_ADD_SUITE = 'New Suite\tCtrl-Shift-F' 1ab

38LABEL_ADD_DIRECTORY = 'New Directory' 1ab

39LABEL_NEW_TEST_CASE = 'New Test Case\tCtrl-Shift-T' 1ab

40LABEL_NEW_USER_KEYWORD = 'New User Keyword\tCtrl-Shift-K' 1ab

41LABEL_SORT_VARIABLES = 'Sort Variables' 1ab

42LABEL_SORT_TESTS = 'Sort Tests' 1ab

43LABEL_SORT_KEYWORDS = 'Sort Keywords' 1ab

44LABEL_NEW_SCALAR = 'New Scalar\tCtrl-Shift-V' 1ab

45LABEL_NEW_LIST_VARIABLE = 'New List Variable\tCtrl-Shift-L' 1ab

46LABEL_NEW_DICT_VARIABLE = 'New Dictionary Variable' 1ab

47LABEL_CHANGE_FORMAT = 'Change Format' 1ab

48LABEL_COPY_MACRO = 'Copy\tCtrl-Shift-C' 1ab

49LABEL_RENAME = 'Rename\tF2' 1ab

50LABEL_ADD_RESOURCE = 'Add Resource' 1ab

51LABEL_NEW_RESOURCE = 'New Resource' 1ab

52LABEL_FIND_USAGES = 'Find Usages' 1ab

53LABEL_SELECT_ALL = 'Select All Tests' 1ab

54LABEL_DESELECT_ALL = 'Deselect All Tests' 1ab

55LABEL_SELECT_FAILED_TESTS = 'Select Only Failed Tests' 1ab

56LABEL_SELECT_PASSED_TESTS = 'Select Only Passed Tests' 1ab

57LABEL_DELETE = 'Delete\tCtrl-Shift-D' 1ab

58LABEL_DELETE_NO_KBSC = 'Delete' 1ab

59LABEL_EXCLUDE = 'Exclude' 1ab

60LABEL_INCLUDE = 'Include' 1ab

61LABEL_EXPAND_ALL = 'Expand all' 1ab

62LABEL_COLLAPSE_ALL = 'Collapse all' 1ab

63LABEL_REMOVE_READONLY = 'Remove Read Only' 1ab

64LABEL_OPEN_FOLDER = 'Open Containing Folder' 1ab

65LABEL_MOVE_UP = 'Move Up\tCtrl-Up' 1ab

66LABEL_MOVE_DOWN = 'Move Down\tCtrl-Down' 1ab

67 

68 

69def action_handler_class(controller): 1ab

70 return { 1afedc

71 filecontrollers.TestDataDirectoryController: TestDataDirectoryHandler, 

72 filecontrollers.ResourceFileController: ResourceFileHandler, 

73 filecontrollers.TestCaseFileController: TestCaseFileHandler, 

74 macrocontrollers.TestCaseController: TestCaseHandler, 

75 macrocontrollers.UserKeywordController: UserKeywordHandler, 

76 settingcontrollers.VariableController: VariableHandler, 

77 filecontrollers.ExcludedDirectoryController: ExcludedDirectoryHandler, 

78 filecontrollers.ExcludedFileController: ExcludedDirectoryHandler # Reuse the same class 

79 }[controller.__class__] 

80 

81 

82class _ActionHandler: 1ab

83 is_user_keyword = False 1ab

84 is_test_suite = False 1ab

85 is_variable = False 1ab

86 

87 _actions = [] 1ab

88 _actions_nt = [] 1ab

89 

90 def __init__(self, controller, tree, node, settings): 1ab

91 self.controller = controller 1afedc

92 self._tree = tree 1afedc

93 self._node = node 1afedc

94 self._settings = settings 1afedc

95 self._rendered = False 1afedc

96 self._popup_creator = tree._popup_creator 1afedc

97 

98 @property 1ab

99 def item(self): 1ab

100 return self.controller.data 1aghijklsmnopqrfetudc

101 

102 @property 1ab

103 def node(self): 1ab

104 return self._node 1ghijklmnopqr

105 

106 def show_popup(self): 1ab

107 """ DEBUG Next code selects item when right click, which is annoying when we want to expand or select tests 

108 but want to keep the Editor in the same file or position 

109 node = self._tree.controller.find_node_by_controller(self.controller) 

110 if node: 

111 wx.CallLater(500, self._tree.SelectItem, node) 

112 """ 

113 self._popup_creator.show(self._tree, PopupMenuItems(self, self._actions, self._actions_nt), self.controller) 

114 

115 @staticmethod 1ab

116 def begin_label_edit(): 1ab

117 return False 

118 

119 def double_clicked(self): 1ab

120 """ Just ignore it """ 

121 pass 

122 

123 def end_label_edit(self, event): 1ab

124 """ Just ignore it """ 

125 pass 

126 

127 def on_delete(self, event): 1ab

128 """ Just ignore it """ 

129 pass 

130 

131 def on_new_suite(self, event): 1ab

132 """ Just ignore it """ 

133 pass 

134 

135 def on_new_directory(self, event): 1ab

136 """ Just ignore it """ 

137 pass 

138 

139 def on_new_resource(self, event): 1ab

140 """ Just ignore it """ 

141 pass 

142 

143 def on_new_user_keyword(self, event): 1ab

144 """ Just ignore it """ 

145 pass 

146 

147 def on_new_test_case(self, event): 1ab

148 """ Just ignore it """ 

149 pass 

150 

151 def on_new_scalar(self, event): 1ab

152 """ Just ignore it """ 

153 pass 

154 

155 def on_new_list_variable(self, event): 1ab

156 """ Just ignore it """ 

157 pass 

158 

159 def on_new_dictionary_variable(self, event): 1ab

160 """ Just ignore it """ 

161 pass 

162 

163 def on_copy(self, event): 1ab

164 """ Just ignore it """ 

165 pass 

166 

167 def on_find_usages(self, event): 1ab

168 """ Just ignore it """ 

169 pass 

170 

171 def on_select_all_tests(self, event): 1ab

172 __ = event 

173 self._tree.SelectAllTests(self._node) 

174 

175 def on_deselect_all_tests(self, event): 1ab

176 __ = event 

177 self._tree.SelectAllTests(self._node, False) 

178 

179 def on_select_only_failed_tests(self, event): 1ab

180 __ = event 

181 self._tree.SelectFailedTests(self._node) 

182 

183 def on_select_only_passed_tests(self, event): 1ab

184 __ = event 

185 self._tree.SelectPassedTests(self._node) 

186 

187 def on_safe_delete(self, event): 1ab

188 """ Just ignore it """ 

189 pass 

190 

191 def on_exclude(self, event): 1ab

192 """ Just ignore it """ 

193 pass 

194 

195 def on_include(self, event): 1ab

196 """ Just ignore it """ 

197 pass 

198 

199 

200class _CanBeRenamed(object): 1ab

201 

202 def on_rename(self, event): 1ab

203 __ = event 

204 self._tree.label_editor.on_label_edit() 

205 

206 def begin_label_edit(self): 1ab

207 def label_edit(): 

208 # DEBUG: fixme yep.yep.yep.yep.yep 

209 node = self._tree.controller.find_node_by_controller(self.controller) 

210 if node: 

211 self._tree.EditLabel(node) 

212 # Must handle pending events before label edit 

213 # This is a fix for situations where there is a pending action 

214 # that will change this label (Text Editor all changing actions) 

215 wx.CallAfter(label_edit) 

216 return True 

217 

218 def end_label_edit(self, event): 1ab

219 if not event.IsEditCancelled(): 

220 if self._is_valid_rename(event.GetLabel()): 

221 self.rename(event.GetLabel()) 

222 else: 

223 event.Veto() 

224 

225 def _is_valid_rename(self, label): 1ab

226 validation = self.controller.validate_name(label) 

227 if validation.error_message: 

228 self._show_validation_error(validation.error_message) 

229 return False 

230 return True 

231 

232 @staticmethod 1ab

233 def _show_validation_error(err_msg): 1ab

234 message_box = RIDEDialog(title=_('Validation Error'), message=err_msg, style=wx.ICON_ERROR | wx.OK) 

235 message_box.ShowModal() 

236 

237 

238class DirectoryHandler(_ActionHandler): 1ab

239 is_draggable = False 1ab

240 is_test_suite = False 1ab

241 can_be_rendered = False 1ab

242 

243 def __init__(self, *args): 1ab

244 _ActionHandler.__init__(self, *args) 

245 self._actions = [_('New Resource')] 

246 self._actions_nt = [LABEL_NEW_RESOURCE] 

247 

248 def on_new_resource(self, event): 1ab

249 NewResourceDialog(self.controller, self._settings).execute() 

250 

251 

252class TestDataHandler(_ActionHandler): 1ab

253 def accepts_drag(self, dragged): 1ab

254 return isinstance(dragged, UserKeywordHandler) or isinstance(dragged, VariableHandler) 

255 is_draggable = False 1ab

256 is_test_suite = True 1ab

257 

258 @property 1ab

259 def tests(self): 1ab

260 return self.controller.tests 1vwxdc

261 

262 @property 1ab

263 def keywords(self): 1ab

264 return self.controller.keywords 1adc

265 

266 @property 1ab

267 def variables(self): 1ab

268 return self.controller.variables 1adc

269 

270 def has_been_modified_on_disk(self): 1ab

271 return self.item.has_been_modified_on_disk() 

272 

273 def do_drop(self, item): 1ab

274 self.controller.add_test_or_keyword(item) 

275 

276 @staticmethod 1ab

277 def rename(new_name): 1ab

278 _ = new_name 

279 return False 

280 

281 def on_sort_tests(self, event): 1ab

282 __ = event 

283 """Sorts the tests inside the treenode""" 

284 self.controller.execute(SortTests()) 

285 

286 def on_sort_keywords(self, event): 1ab

287 __ = event 

288 """Sorts the keywords inside the treenode""" 

289 self.controller.execute(ctrlcommands.SortKeywords()) 

290 

291 def on_sort_variables(self, event): 1ab

292 __ = event 

293 """Sorts the variables inside the treenode""" 

294 self.controller.execute(SortVariables()) 

295 

296 @property 1ab

297 def can_be_rendered(self): 1ab

298 if not self._has_children(): 1afedc

299 return False 

300 return not self._rendered 1afedc

301 

302 def _has_children(self): 1ab

303 return (self.item.keyword_table or self.item.testcase_table or 1afedc

304 self.item.variable_table) 

305 

306 def set_rendered(self): 1ab

307 self._rendered = True 1adc

308 

309 def on_change_format(self, event): 1ab

310 __ = event 

311 ChangeFormatDialog(self.controller).execute() 

312 

313 def on_new_user_keyword(self, event): 1ab

314 dlg = UserKeywordNameDialog(self.controller) 

315 if dlg.ShowModal() == wx.ID_OK: 

316 self.controller.execute(ctrlcommands.AddKeyword(dlg.get_name(), dlg.get_args())) 

317 dlg.Destroy() 

318 

319 def on_new_scalar(self, event): 1ab

320 self._new_var(ScalarVariableDialog) 

321 

322 def on_new_list_variable(self, event): 1ab

323 class FakePlugin(object): 

324 global_settings = self._settings 

325 self._new_var(ListVariableDialog, plugin=FakePlugin()) 

326 

327 def on_new_dictionary_variable(self, event): 1ab

328 class FakePlugin(object): 

329 global_settings = self._settings 

330 self._new_var(DictionaryVariableDialog, plugin=FakePlugin()) 

331 

332 def _new_var(self, dialog_class, plugin=None): 1ab

333 dlg = dialog_class(self._var_controller, plugin=plugin) 

334 if dlg.ShowModal() == wx.ID_OK: 

335 name, value = dlg.get_value() 

336 comment = dlg.get_comment() 

337 self.controller.execute(ctrlcommands.AddVariable(name, value, comment)) 

338 

339 @property 1ab

340 def _var_controller(self): 1ab

341 return self.controller.datafile_controller.variables 

342 

343 

344class TestDataDirectoryHandler(TestDataHandler): 1ab

345 

346 def __init__(self, *args): 1ab

347 TestDataHandler.__init__(self, *args) 

348 self._actions = [ 

349 _('New Suite\tCtrl-Shift-F'), 

350 _('New Directory'), 

351 _('New Resource'), 

352 '---', 

353 _('New User Keyword\tCtrl-Shift-K'), 

354 _('New Scalar\tCtrl-Shift-V'), 

355 _('New List Variable\tCtrl-Shift-L'), 

356 _('New Dictionary Variable'), 

357 '---', 

358 _('Change Format'), 

359 _('Open Containing Folder') 

360 ] 

361 self._actions_nt = [ 

362 LABEL_ADD_SUITE, 

363 LABEL_ADD_DIRECTORY, 

364 LABEL_NEW_RESOURCE, 

365 '---', 

366 LABEL_NEW_USER_KEYWORD, 

367 LABEL_NEW_SCALAR, 

368 LABEL_NEW_LIST_VARIABLE, 

369 LABEL_NEW_DICT_VARIABLE, 

370 '---', 

371 LABEL_CHANGE_FORMAT, 

372 LABEL_OPEN_FOLDER 

373 ] 

374 if self.controller.parent: 

375 self._actions.extend([_('Delete')]) 

376 self._actions_nt.extend([LABEL_DELETE_NO_KBSC]) 

377 

378 self._actions.extend([ 

379 '---', 

380 _('Select All Tests'), 

381 _('Deselect All Tests'), 

382 _('Select Only Failed Tests'), 

383 _('Select Only Passed Tests') 

384 ]) 

385 self._actions_nt.extend([ 

386 '---', 

387 LABEL_SELECT_ALL, 

388 LABEL_DESELECT_ALL, 

389 LABEL_SELECT_FAILED_TESTS, 

390 LABEL_SELECT_PASSED_TESTS 

391 ]) 

392 if self.controller.parent: 

393 self._actions.extend(['---', _('Exclude')]) 

394 self._actions_nt.extend(['---', LABEL_EXCLUDE]) 

395 self._actions.extend(['---', _('Expand all'), _('Collapse all')]) 

396 self._actions_nt.extend(['---', LABEL_EXPAND_ALL, LABEL_COLLAPSE_ALL]) 

397 

398 def on_expand_all(self, event): 1ab

399 __ = event 

400 self._tree.ExpandAllSubNodes(self._node) 

401 

402 def on_collapse_all(self, event): 1ab

403 __ = event 

404 self._tree.CollapseAllSubNodes(self._node) 

405 

406 def on_new_suite(self, event): 1ab

407 AddSuiteDialog(self.controller, self._settings).execute() 

408 

409 def on_new_directory(self, event): 1ab

410 AddDirectoryDialog(self.controller, self._settings).execute() 

411 

412 def on_new_resource(self, event): 1ab

413 NewResourceDialog(self.controller, self._settings).execute() 

414 

415 def on_delete(self, event): 1ab

416 FolderDeleteDialog(self.controller).execute() 

417 

418 def on_open_containing_folder(self, event): 1ab

419 __ = event 

420 try: 

421 file_manager = self._settings['General'][FILE_MANAGER] 

422 except KeyError: 

423 file_manager = None 

424 directory = self.controller.source 

425 # print(f"DEBUG: treenodecontrollers.py TestDataDirectoryHandler on_open_containing_folder" 

426 # f" directory={directory}") 

427 self.controller.execute(ctrlcommands.OpenContainingFolder(tool=file_manager, path=directory)) 

428 

429 def on_exclude(self, event): 1ab

430 try: 

431 self.controller.execute(ctrlcommands.Exclude()) 

432 # Next is to restart the file monitoring 

433 RideSettingsChanged(keys=('Excludes', 'excluded'), old=None, new=None).publish() 

434 except filecontrollers.DirtyRobotDataException: 

435 message_box = RIDEDialog(message=_('Directory contains unsaved data!\n' 

436 'You must save data before excluding.'), style=wx.ICON_WARNING | wx.OK) 

437 message_box.ShowModal() 

438 

439 

440class _FileHandlerThanCanBeRenamed(_CanBeRenamed): 1ab

441 

442 def begin_label_edit(self): 1ab

443 self._old_label = self._node.GetText() 

444 self._set_node_label(self.controller.basename) 

445 return _CanBeRenamed.begin_label_edit(self) 

446 

447 def end_label_edit(self, event): 1ab

448 if not event.IsEditCancelled(): 

449 result = self.controller.execute( 

450 self._rename_command(event.GetLabel())) 

451 if result: 

452 self._rename_ok_handler() 

453 self._old_label = self.controller.basename 

454 else: 

455 event.Veto() 

456 else: 

457 self._set_node_label(self._old_label) 

458 

459 def _rename_ok_handler(self): 1ab

460 """ Just ignore it """ 

461 pass 

462 

463 def _rename_command(self, label): 1ab

464 raise NotImplementedError(self.__class__) 

465 

466 def _set_node_label(self, label): 1ab

467 self._tree.SetItemText(self._node, label) 

468 

469 

470class ResourceFileHandler(_FileHandlerThanCanBeRenamed, TestDataHandler): 1ab

471 is_test_suite = False 1ab

472 

473 def __init__(self, *args): 1ab

474 TestDataHandler.__init__(self, *args) 1ad

475 self._actions = [ 1ad

476 _('New User Keyword\tCtrl-Shift-K'), 

477 _('New Scalar\tCtrl-Shift-V'), 

478 _('New List Variable\tCtrl-Shift-L'), 

479 _('New Dictionary Variable'), 

480 '---', 

481 _('Rename\tF2'), 

482 _('Change Format'), 

483 _('Sort Keywords'), 

484 _('Find Usages'), 

485 _('Delete\tCtrl-Shift-D'), 

486 '---', 

487 _('Sort Variables'), 

488 _('Sort Keywords'), 

489 '---', 

490 _('Exclude'), 

491 '---', 

492 _('Remove Read Only'), 

493 _('Open Containing Folder') 

494 ] 

495 self._actions_nt = [ 1ad

496 LABEL_NEW_USER_KEYWORD, 

497 LABEL_NEW_SCALAR, 

498 LABEL_NEW_LIST_VARIABLE, 

499 LABEL_NEW_DICT_VARIABLE, 

500 '---', 

501 LABEL_RENAME, 

502 LABEL_CHANGE_FORMAT, 

503 LABEL_SORT_KEYWORDS, 

504 LABEL_FIND_USAGES, 

505 LABEL_DELETE, 

506 '---', 

507 LABEL_SORT_VARIABLES, 

508 LABEL_SORT_KEYWORDS, 

509 '---', 

510 LABEL_EXCLUDE, 

511 '---', 

512 LABEL_REMOVE_READONLY, 

513 LABEL_OPEN_FOLDER 

514 ] 

515 

516 def on_exclude(self, event): 1ab

517 try: 

518 self.controller.execute(ctrlcommands.Exclude()) 

519 # Next is to restart the file monitoring 

520 RideSettingsChanged(keys=('Excludes', 'excluded'), old=None, new=None).publish() 

521 except filecontrollers.DirtyRobotDataException: 

522 message_box = RIDEDialog(message=_('File contains unsaved data!\n' 

523 'You must save data before excluding.'), style=wx.ICON_WARNING | wx.OK) 

524 message_box.ShowModal() 

525 

526 def on_remove_read_only(self, event): 1ab

527 __ = event 

528 

529 def return_true(): 

530 return True 

531 self.controller.is_modifiable = return_true 

532 self.controller.execute(ctrlcommands.RemoveReadOnly()) 

533 

534 def on_open_containing_folder(self, event): 1ab

535 __ = event 

536 try: 

537 file_manager = self._settings['General'][FILE_MANAGER] 

538 except KeyError: 

539 file_manager = None 

540 self.controller.execute(ctrlcommands.OpenContainingFolder(file_manager)) 

541 

542 def on_find_usages(self, event): 1ab

543 ResourceFileUsages(self.controller, self._tree.highlight).show() 

544 

545 def on_delete(self, event): 1ab

546 ResourceDeleteDialog(self.controller).execute() 

547 

548 def on_safe_delete(self, event): 1ab

549 return self.on_delete(event) 

550 

551 def _rename_command(self, label): 1ab

552 return ctrlcommands.RenameResourceFile( 

553 label, self._check_should_rename_static_imports) 

554 

555 def _check_should_rename_static_imports(self): 1ab

556 return ResourceRenameDialog(self.controller).execute() 

557 

558 

559class TestCaseFileHandler(_FileHandlerThanCanBeRenamed, TestDataHandler): 1ab

560 

561 def __init__(self, *args): 1ab

562 TestDataHandler.__init__(self, *args) 1ac

563 self._actions = [_('New Test Case\tCtrl-Shift-T'), 1ac

564 _('New User Keyword\tCtrl-Shift-K'), 

565 _('New Scalar\tCtrl-Shift-V'), 

566 _('New List Variable\tCtrl-Shift-L'), 

567 _('New Dictionary Variable'), 

568 '---', 

569 _('Rename\tF2'), 

570 _('Change Format'), 

571 _('Sort Keywords'), 

572 _('Delete\tCtrl-Shift-D'), 

573 '---', 

574 _('Sort Variables'), 

575 _('Sort Tests'), 

576 _('Sort Keywords'), 

577 '---', 

578 _('Select All Tests'), 

579 _('Deselect All Tests'), 

580 _('Select Only Failed Tests'), 

581 _('Select Only Passed Tests'), 

582 '---', 

583 _('Exclude'), 

584 '---', 

585 _('Remove Read Only'), 

586 _('Open Containing Folder') 

587 ] 

588 self._actions_nt = [ 1ac

589 LABEL_NEW_TEST_CASE, 

590 LABEL_NEW_USER_KEYWORD, 

591 LABEL_NEW_SCALAR, 

592 LABEL_NEW_LIST_VARIABLE, 

593 LABEL_NEW_DICT_VARIABLE, 

594 '---', 

595 LABEL_RENAME, 

596 LABEL_CHANGE_FORMAT, 

597 LABEL_SORT_KEYWORDS, 

598 LABEL_DELETE, 

599 '---', 

600 LABEL_SORT_VARIABLES, 

601 LABEL_SORT_TESTS, 

602 LABEL_SORT_KEYWORDS, 

603 '---', 

604 LABEL_SELECT_ALL, 

605 LABEL_DESELECT_ALL, 

606 LABEL_SELECT_FAILED_TESTS, 

607 LABEL_SELECT_PASSED_TESTS, 

608 '---', 

609 LABEL_EXCLUDE, 

610 '---', 

611 LABEL_REMOVE_READONLY, 

612 LABEL_OPEN_FOLDER 

613 ] 

614 

615 def accepts_drag(self, dragged): 1ab

616 _ = dragged 

617 return True 

618 

619 def on_exclude(self, event): 1ab

620 try: 

621 self.controller.execute(ctrlcommands.Exclude()) 

622 # Next is to restart the file monitoring 

623 RideSettingsChanged(keys=('Excludes', 'excluded'), old=None, new=None).publish() 

624 except filecontrollers.DirtyRobotDataException: 

625 message_box = RIDEDialog(message=_('File contains unsaved data!\n' 

626 'You must save data before excluding.'), style=wx.ICON_WARNING | wx.OK) 

627 message_box.ShowModal() 

628 

629 def on_remove_read_only(self, event): 1ab

630 __ = event 

631 

632 def return_true(): 

633 return True 

634 self.controller.is_modifiable = return_true 

635 self.controller.execute(ctrlcommands.RemoveReadOnly()) 

636 

637 def on_open_containing_folder(self, event): 1ab

638 __ = event 

639 try: 

640 file_manager = self._settings['General'][FILE_MANAGER] 

641 except KeyError: 

642 file_manager = None 

643 self.controller.execute(ctrlcommands.OpenContainingFolder(file_manager)) 

644 

645 def on_new_test_case(self, event): 1ab

646 dlg = TestCaseNameDialog(self.controller) 

647 if dlg.ShowModal() == wx.ID_OK: 

648 self.controller.execute(ctrlcommands.AddTestCase(dlg.get_name())) 

649 dlg.Destroy() 

650 

651 def on_delete(self, event): 1ab

652 message_box = RIDEDialog(title=_('Confirm'), message=_('Delete test case file'), 

653 style=wx.YES_NO | wx.ICON_QUESTION) 

654 ret = message_box.ShowModal() 

655 if ret == wx.YES: 

656 self.controller.execute(ctrlcommands.DeleteFile()) 

657 

658 def on_safe_delete(self, event): 1ab

659 return self.on_delete(event) 

660 

661 def _rename_command(self, label): 1ab

662 return ctrlcommands.RenameFile(label) 

663 

664 def _rename_ok_handler(self): 1ab

665 self._tree.SelectAllTests(self._node, False) 

666 

667 

668class _TestOrUserKeywordHandler(_CanBeRenamed, _ActionHandler): 1ab

669 is_draggable = True 1ab

670 

671 def __init__(self, *args): 1ab

672 _ActionHandler.__init__(self, *args) 1afedc

673 self._actions = [ 1afedc

674 _('Copy\tCtrl-Shift-C'), 

675 _('Move Up\tCtrl-Up'), 

676 _('Move Down\tCtrl-Down'), 

677 _('Rename\tF2'), 

678 '---', 

679 _('Delete') 

680 ] 

681 self._actions_nt = [ 1afedc

682 LABEL_COPY_MACRO, 

683 LABEL_MOVE_UP, 

684 LABEL_MOVE_DOWN, 

685 LABEL_RENAME, 

686 '---', 

687 LABEL_DELETE_NO_KBSC 

688 ] 

689 

690 

691 @staticmethod 1ab

692 def accepts_drag(dragged): 1ab

693 __ = dragged 

694 return False 

695 

696 def remove(self): 1ab

697 self.controller.delete() 

698 

699 def rename(self, new_name): 1ab

700 self.controller.execute(self._create_rename_command(new_name)) 

701 

702 def on_copy(self, event): 1ab

703 dlg = self._copy_name_dialog_class(self.controller, self.item) 

704 if dlg.ShowModal() == wx.ID_OK: 

705 self.controller.execute(ctrlcommands.CopyMacroAs(dlg.get_name())) 

706 dlg.Destroy() 

707 

708 def on_move_up(self, event): 1ab

709 __ = event 

710 if self.controller.move_up(): 

711 self._tree.move_up(self._node) 

712 

713 def on_move_down(self, event): 1ab

714 __ = event 

715 if self.controller.move_down(): 

716 self._tree.move_down(self._node) 

717 

718 def on_delete(self, event): 1ab

719 self.controller.execute(ctrlcommands.RemoveMacro(self.controller)) 

720 

721 

722class TestCaseHandler(_TestOrUserKeywordHandler): 1ab

723 def __init__(self, controller, tree, node, settings): 1ab

724 _TestOrUserKeywordHandler.__init__(self, controller, tree, node, settings) 1afc

725 PUBLISHER.subscribe(self.test_selection_changed, RideTestSelectedForRunningChanged) 1afc

726 

727 _datalist = property(lambda self: self.item.datalist) 1ab

728 _copy_name_dialog_class = TestCaseNameDialog 1ab

729 

730 def _add_copy_to_tree(self, parent_node, copied): 1ab

731 self._tree.add_test(parent_node, copied) 

732 

733 @staticmethod 1ab

734 def _create_rename_command(new_name): 1ab

735 return ctrlcommands.RenameTest(new_name) 

736 

737 def test_selection_changed(self, message): 1ab

738 if self.controller in message.tests: 738 ↛ 739line 738 didn't jump to line 739 because the condition on line 738 was never true1ghijklmnopqr

739 if not self.node.GetValue(): 

740 self._tree.CheckItem(self.node, checked=True) 

741 else: 

742 if self.node.GetValue(): 742 ↛ 743line 742 didn't jump to line 743 because the condition on line 742 was never true1ghijklmnopqr

743 self._tree.CheckItem(self.node, checked=False) 

744 

745 

746class UserKeywordHandler(_TestOrUserKeywordHandler): 1ab

747 is_user_keyword = True 1ab

748 _datalist = property(lambda self: self.item.datalist) 1ab

749 _copy_name_dialog_class = CopyUserKeywordDialog 1ab

750 

751 def __init__(self, *args): 1ab

752 _TestOrUserKeywordHandler.__init__(self, *args) 1aedc

753 self._actions = self._actions + [_('Find Usages')] 1aedc

754 self._actions_nt = self._actions_nt + [LABEL_FIND_USAGES] 1aedc

755 

756 def _add_copy_to_tree(self, parent_node, copied): 1ab

757 self._tree.add_keyword(parent_node, copied) 

758 

759 def _create_rename_command(self, new_name): 1ab

760 # print(f"DEBUG: treenodehandlers.py UserKeywodHandler _create_rename_command controller.name={self.controller.name}" 

761 # f", new_name={new_name} info={self.controller.info}") 

762 return ctrlcommands.RenameKeywordOccurrences(self.controller.name, new_name, 

763 RenameProgressObserver(self._tree.GetParent(), 

764 background=self._tree.background, 

765 foreground=self._tree.foreground), 

766 self.controller.info, language=self.controller.language) 

767 

768 def on_find_usages(self, event): 1ab

769 Usages(self.controller, self._tree.highlight).show() 

770 

771 

772class VariableHandler(_CanBeRenamed, _ActionHandler): 1ab

773 is_draggable = True 1ab

774 is_variable = True 1ab

775 

776 def __init__(self, *args): 1ab

777 _ActionHandler.__init__(self, *args) 

778 self._actions = [ 

779 _('Move Up\tCtrl-Up'), 

780 _('Move Down\tCtrl-Down'), 

781 _('Rename\tF2'), 

782 '---', 

783 _('Delete') 

784 ] 

785 self._actions_nt = [ 

786 LABEL_MOVE_UP, 

787 LABEL_MOVE_DOWN, 

788 LABEL_RENAME, 

789 '---', 

790 LABEL_DELETE_NO_KBSC 

791 ] 

792 

793 @staticmethod 1ab

794 def accepts_drag(dragged): 1ab

795 __ = dragged 

796 return False 

797 

798 def double_clicked(self): 1ab

799 RideOpenVariableDialog(controller=self.controller).publish() 

800 

801 def on_delete(self, event): 1ab

802 self.remove() 

803 

804 def remove(self): 1ab

805 self.controller.delete() 

806 

807 def rename(self, new_name): 1ab

808 self.controller.execute(ctrlcommands.UpdateVariableName(new_name)) 

809 

810 def on_move_up(self, event): 1ab

811 __ = event 

812 if self.controller.move_up(): 

813 self._tree.move_up(self._node) 

814 

815 def on_move_down(self, event): 1ab

816 __ = event 

817 if self.controller.move_down(): 

818 self._tree.move_down(self._node) 

819 

820 @property 1ab

821 def index(self): 1ab

822 return self.controller.index 

823 

824 

825class ResourceRootHandler(_ActionHandler): 1ab

826 can_be_rendered = is_draggable = is_user_keyword = is_test_suite = False 1ab

827 

828 def __init__(self, *args): 1ab

829 _ActionHandler.__init__(self, *args) 

830 self._actions = [_('Add Resource')] 

831 self._actions_nt = [LABEL_ADD_RESOURCE] 

832 

833 @staticmethod 1ab

834 def rename(new_name): 1ab

835 _ = new_name 

836 return False 

837 

838 @staticmethod 1ab

839 def accepts_drag(dragged): 1ab

840 __ = dragged 

841 return False 

842 

843 @property 1ab

844 def item(self): 1ab

845 return None 

846 

847 def on_add_resource(self, event): 1ab

848 __ = event 

849 path = RobotFilePathDialog( 

850 self._tree.GetParent(), self.controller, self._settings).execute() 

851 if path: 

852 self.controller.load_resource(path, LoadProgressObserver(self._tree.GetParent(), 

853 background=self._tree.background, 

854 foreground=self._tree.foreground)) 

855 

856 

857class ExcludedDirectoryHandler(TestDataDirectoryHandler): 1ab

858 is_draggable = False 1ab

859 is_test_suite = True 1ab

860 

861 def __init__(self, *args): 1ab

862 TestDataHandler.__init__(self, *args) 

863 self._actions = [_('Include')] 

864 self._actions_nt = [LABEL_INCLUDE] 

865 

866 def on_include(self, event): 1ab

867 self.controller.execute(ctrlcommands.Include()) 

868 # Next is to restart the file monitoring 

869 RideSettingsChanged(keys=('Excludes', 'included'), old=None, new=None).publish()