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
« 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.
16import builtins 1ab
17import wx 1ab
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
33_ = wx.GetTranslation # To keep linter/code analyser happy 1ab
34builtins.__dict__['_'] = wx.GetTranslation 1ab
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
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__]
82class _ActionHandler: 1ab
83 is_user_keyword = False 1ab
84 is_test_suite = False 1ab
85 is_variable = False 1ab
87 _actions = [] 1ab
88 _actions_nt = [] 1ab
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
98 @property 1ab
99 def item(self): 1ab
100 return self.controller.data 1aghijklsmnopqrfetudc
102 @property 1ab
103 def node(self): 1ab
104 return self._node 1ghijklmnopqr
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)
115 @staticmethod 1ab
116 def begin_label_edit(): 1ab
117 return False
119 def double_clicked(self): 1ab
120 """ Just ignore it """
121 pass
123 def end_label_edit(self, event): 1ab
124 """ Just ignore it """
125 pass
127 def on_delete(self, event): 1ab
128 """ Just ignore it """
129 pass
131 def on_new_suite(self, event): 1ab
132 """ Just ignore it """
133 pass
135 def on_new_directory(self, event): 1ab
136 """ Just ignore it """
137 pass
139 def on_new_resource(self, event): 1ab
140 """ Just ignore it """
141 pass
143 def on_new_user_keyword(self, event): 1ab
144 """ Just ignore it """
145 pass
147 def on_new_test_case(self, event): 1ab
148 """ Just ignore it """
149 pass
151 def on_new_scalar(self, event): 1ab
152 """ Just ignore it """
153 pass
155 def on_new_list_variable(self, event): 1ab
156 """ Just ignore it """
157 pass
159 def on_new_dictionary_variable(self, event): 1ab
160 """ Just ignore it """
161 pass
163 def on_copy(self, event): 1ab
164 """ Just ignore it """
165 pass
167 def on_find_usages(self, event): 1ab
168 """ Just ignore it """
169 pass
171 def on_select_all_tests(self, event): 1ab
172 __ = event
173 self._tree.SelectAllTests(self._node)
175 def on_deselect_all_tests(self, event): 1ab
176 __ = event
177 self._tree.SelectAllTests(self._node, False)
179 def on_select_only_failed_tests(self, event): 1ab
180 __ = event
181 self._tree.SelectFailedTests(self._node)
183 def on_select_only_passed_tests(self, event): 1ab
184 __ = event
185 self._tree.SelectPassedTests(self._node)
187 def on_safe_delete(self, event): 1ab
188 """ Just ignore it """
189 pass
191 def on_exclude(self, event): 1ab
192 """ Just ignore it """
193 pass
195 def on_include(self, event): 1ab
196 """ Just ignore it """
197 pass
200class _CanBeRenamed(object): 1ab
202 def on_rename(self, event): 1ab
203 __ = event
204 self._tree.label_editor.on_label_edit()
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
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()
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
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()
238class DirectoryHandler(_ActionHandler): 1ab
239 is_draggable = False 1ab
240 is_test_suite = False 1ab
241 can_be_rendered = False 1ab
243 def __init__(self, *args): 1ab
244 _ActionHandler.__init__(self, *args)
245 self._actions = [_('New Resource')]
246 self._actions_nt = [LABEL_NEW_RESOURCE]
248 def on_new_resource(self, event): 1ab
249 NewResourceDialog(self.controller, self._settings).execute()
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
258 @property 1ab
259 def tests(self): 1ab
260 return self.controller.tests 1vwxdc
262 @property 1ab
263 def keywords(self): 1ab
264 return self.controller.keywords 1adc
266 @property 1ab
267 def variables(self): 1ab
268 return self.controller.variables 1adc
270 def has_been_modified_on_disk(self): 1ab
271 return self.item.has_been_modified_on_disk()
273 def do_drop(self, item): 1ab
274 self.controller.add_test_or_keyword(item)
276 @staticmethod 1ab
277 def rename(new_name): 1ab
278 _ = new_name
279 return False
281 def on_sort_tests(self, event): 1ab
282 __ = event
283 """Sorts the tests inside the treenode"""
284 self.controller.execute(SortTests())
286 def on_sort_keywords(self, event): 1ab
287 __ = event
288 """Sorts the keywords inside the treenode"""
289 self.controller.execute(ctrlcommands.SortKeywords())
291 def on_sort_variables(self, event): 1ab
292 __ = event
293 """Sorts the variables inside the treenode"""
294 self.controller.execute(SortVariables())
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
302 def _has_children(self): 1ab
303 return (self.item.keyword_table or self.item.testcase_table or 1afedc
304 self.item.variable_table)
306 def set_rendered(self): 1ab
307 self._rendered = True 1adc
309 def on_change_format(self, event): 1ab
310 __ = event
311 ChangeFormatDialog(self.controller).execute()
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()
319 def on_new_scalar(self, event): 1ab
320 self._new_var(ScalarVariableDialog)
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())
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())
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))
339 @property 1ab
340 def _var_controller(self): 1ab
341 return self.controller.datafile_controller.variables
344class TestDataDirectoryHandler(TestDataHandler): 1ab
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])
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])
398 def on_expand_all(self, event): 1ab
399 __ = event
400 self._tree.ExpandAllSubNodes(self._node)
402 def on_collapse_all(self, event): 1ab
403 __ = event
404 self._tree.CollapseAllSubNodes(self._node)
406 def on_new_suite(self, event): 1ab
407 AddSuiteDialog(self.controller, self._settings).execute()
409 def on_new_directory(self, event): 1ab
410 AddDirectoryDialog(self.controller, self._settings).execute()
412 def on_new_resource(self, event): 1ab
413 NewResourceDialog(self.controller, self._settings).execute()
415 def on_delete(self, event): 1ab
416 FolderDeleteDialog(self.controller).execute()
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))
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()
440class _FileHandlerThanCanBeRenamed(_CanBeRenamed): 1ab
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)
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)
459 def _rename_ok_handler(self): 1ab
460 """ Just ignore it """
461 pass
463 def _rename_command(self, label): 1ab
464 raise NotImplementedError(self.__class__)
466 def _set_node_label(self, label): 1ab
467 self._tree.SetItemText(self._node, label)
470class ResourceFileHandler(_FileHandlerThanCanBeRenamed, TestDataHandler): 1ab
471 is_test_suite = False 1ab
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 ]
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()
526 def on_remove_read_only(self, event): 1ab
527 __ = event
529 def return_true():
530 return True
531 self.controller.is_modifiable = return_true
532 self.controller.execute(ctrlcommands.RemoveReadOnly())
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))
542 def on_find_usages(self, event): 1ab
543 ResourceFileUsages(self.controller, self._tree.highlight).show()
545 def on_delete(self, event): 1ab
546 ResourceDeleteDialog(self.controller).execute()
548 def on_safe_delete(self, event): 1ab
549 return self.on_delete(event)
551 def _rename_command(self, label): 1ab
552 return ctrlcommands.RenameResourceFile(
553 label, self._check_should_rename_static_imports)
555 def _check_should_rename_static_imports(self): 1ab
556 return ResourceRenameDialog(self.controller).execute()
559class TestCaseFileHandler(_FileHandlerThanCanBeRenamed, TestDataHandler): 1ab
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 ]
615 def accepts_drag(self, dragged): 1ab
616 _ = dragged
617 return True
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()
629 def on_remove_read_only(self, event): 1ab
630 __ = event
632 def return_true():
633 return True
634 self.controller.is_modifiable = return_true
635 self.controller.execute(ctrlcommands.RemoveReadOnly())
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))
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()
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())
658 def on_safe_delete(self, event): 1ab
659 return self.on_delete(event)
661 def _rename_command(self, label): 1ab
662 return ctrlcommands.RenameFile(label)
664 def _rename_ok_handler(self): 1ab
665 self._tree.SelectAllTests(self._node, False)
668class _TestOrUserKeywordHandler(_CanBeRenamed, _ActionHandler): 1ab
669 is_draggable = True 1ab
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 ]
691 @staticmethod 1ab
692 def accepts_drag(dragged): 1ab
693 __ = dragged
694 return False
696 def remove(self): 1ab
697 self.controller.delete()
699 def rename(self, new_name): 1ab
700 self.controller.execute(self._create_rename_command(new_name))
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()
708 def on_move_up(self, event): 1ab
709 __ = event
710 if self.controller.move_up():
711 self._tree.move_up(self._node)
713 def on_move_down(self, event): 1ab
714 __ = event
715 if self.controller.move_down():
716 self._tree.move_down(self._node)
718 def on_delete(self, event): 1ab
719 self.controller.execute(ctrlcommands.RemoveMacro(self.controller))
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
727 _datalist = property(lambda self: self.item.datalist) 1ab
728 _copy_name_dialog_class = TestCaseNameDialog 1ab
730 def _add_copy_to_tree(self, parent_node, copied): 1ab
731 self._tree.add_test(parent_node, copied)
733 @staticmethod 1ab
734 def _create_rename_command(new_name): 1ab
735 return ctrlcommands.RenameTest(new_name)
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)
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
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
756 def _add_copy_to_tree(self, parent_node, copied): 1ab
757 self._tree.add_keyword(parent_node, copied)
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)
768 def on_find_usages(self, event): 1ab
769 Usages(self.controller, self._tree.highlight).show()
772class VariableHandler(_CanBeRenamed, _ActionHandler): 1ab
773 is_draggable = True 1ab
774 is_variable = True 1ab
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 ]
793 @staticmethod 1ab
794 def accepts_drag(dragged): 1ab
795 __ = dragged
796 return False
798 def double_clicked(self): 1ab
799 RideOpenVariableDialog(controller=self.controller).publish()
801 def on_delete(self, event): 1ab
802 self.remove()
804 def remove(self): 1ab
805 self.controller.delete()
807 def rename(self, new_name): 1ab
808 self.controller.execute(ctrlcommands.UpdateVariableName(new_name))
810 def on_move_up(self, event): 1ab
811 __ = event
812 if self.controller.move_up():
813 self._tree.move_up(self._node)
815 def on_move_down(self, event): 1ab
816 __ = event
817 if self.controller.move_down():
818 self._tree.move_down(self._node)
820 @property 1ab
821 def index(self): 1ab
822 return self.controller.index
825class ResourceRootHandler(_ActionHandler): 1ab
826 can_be_rendered = is_draggable = is_user_keyword = is_test_suite = False 1ab
828 def __init__(self, *args): 1ab
829 _ActionHandler.__init__(self, *args)
830 self._actions = [_('Add Resource')]
831 self._actions_nt = [LABEL_ADD_RESOURCE]
833 @staticmethod 1ab
834 def rename(new_name): 1ab
835 _ = new_name
836 return False
838 @staticmethod 1ab
839 def accepts_drag(dragged): 1ab
840 __ = dragged
841 return False
843 @property 1ab
844 def item(self): 1ab
845 return None
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))
857class ExcludedDirectoryHandler(TestDataDirectoryHandler): 1ab
858 is_draggable = False 1ab
859 is_test_suite = True 1ab
861 def __init__(self, *args): 1ab
862 TestDataHandler.__init__(self, *args)
863 self._actions = [_('Include')]
864 self._actions_nt = [LABEL_INCLUDE]
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()