Robot Framework Integrated Development Environment (RIDE)
treenodehandlers.py
Go to the documentation of this file.
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 
16 import wx
17 
18 from ..controller import ctrlcommands, filecontrollers, macrocontrollers, settingcontrollers
19 from ..controller.ctrlcommands import SortTests, SortVariables
20 # import (RenameKeywordOccurrences, RemoveMacro, AddKeyword, AddTestCase, RenameTest,
21 # CopyMacroAs, AddVariable, UpdateVariableName, RenameFile, RenameResourceFile,
22 # DeleteFile, SortKeywords, Include, Exclude, OpenContainingFolder, RemoveReadOnly)
23 
24 # import (TestDataDirectoryController, ResourceFileController, TestCaseFileController,
25 # ExcludedDirectoryController, DirtyRobotDataException)
26 # import TestCaseController, UserKeywordController
27 # import VariableController
28 from ..editor.editordialogs import (TestCaseNameDialog, UserKeywordNameDialog, ScalarVariableDialog, ListVariableDialog,
29  CopyUserKeywordDialog, DictionaryVariableDialog)
30 from ..publish import RideOpenVariableDialog, RideTestSelectedForRunningChanged, PUBLISHER
31 from ..ui.progress import LoadProgressObserver
32 from ..ui.resourcedialogs import FolderDeleteDialog
33 from ..usages.UsageRunner import Usages, ResourceFileUsages
34 from ..utils import overrides
35 from ..widgets import PopupMenuItems
36 from .filedialogs import (AddSuiteDialog, AddDirectoryDialog, ChangeFormatDialog, NewResourceDialog,
37  RobotFilePathDialog)
38 from .progress import RenameProgressObserver
39 from .resourcedialogs import ResourceRenameDialog, ResourceDeleteDialog
40 from ..ui.resourcedialogs import FolderDeleteDialog
41 
42 
43 def action_handler_class(controller):
44  return {
45  filecontrollers.TestDataDirectoryController: TestDataDirectoryHandler,
46  filecontrollers.ResourceFileController: ResourceFileHandler,
47  filecontrollers.TestCaseFileController: TestCaseFileHandler,
48  macrocontrollers.TestCaseController: TestCaseHandler,
49  macrocontrollers.UserKeywordController: UserKeywordHandler,
50  settingcontrollers.VariableController: VariableHandler,
51  filecontrollers.ExcludedDirectoryController: ExcludedDirectoryHandler
52  }[controller.__class__]
53 
54 
56  is_user_keyword = False
57  is_test_suite = False
58  is_variable = False
59 
60 
63  _label_add_suite = 'New Suite\tCtrl-Shift-F'
64 
67  _label_add_directory = 'New Directory'
68 
71  _label_new_test_case = 'New Test Case\tCtrl-Shift-T'
72 
75  _label_new_user_keyword = 'New User Keyword\tCtrl-Shift-K'
76 
79  _label_sort_variables = 'Sort Variables'
80 
83  _label_sort_tests = 'Sort Tests'
84 
87  _label_sort_keywords = 'Sort Keywords'
88 
91  _label_new_scalar = 'New Scalar\tCtrl-Shift-V'
92 
95  _label_new_list_variable = 'New List Variable\tCtrl-Shift-L'
96 
99  _label_new_dict_variable = 'New Dictionary Variable'
100 
103  _label_change_format = 'Change Format'
104 
107  _label_copy_macro = 'Copy\tCtrl-Shift-C'
108 
111  _label_rename = 'Rename\tF2'
112 
115  _label_add_resource = 'Add Resource'
116 
119  _label_new_resource = 'New Resource'
120 
123  _label_find_usages = 'Find Usages'
124 
127  _label_select_all = 'Select All Tests'
128 
131  _label_deselect_all = 'Deselect All Tests'
132 
135  _label_select_failed_tests = 'Select Only Failed Tests'
136 
139  _label_select_passed_tests = 'Select Only Passed Tests'
140 
143  _label_delete = 'Delete\tCtrl-Shift-D'
144 
147  _label_delete_no_kbsc = 'Delete'
148 
151  _label_exclude = 'Exclude'
152 
155  _label_include = 'Include'
156 
159  _label_expand_all = 'Expand all'
160 
163  _label_collapse_all = 'Collapse all'
164 
167  _label_remove_readonly = 'Remove Read Only'
168 
171  _label_open_folder = 'Open Containing Folder'
172 
173  def __init__(self, controller, tree, node, settings):
174  self.controllercontroller = controller
175  self._tree_tree = tree
176  self._node_node = node
177  self._settings_settings = settings
178  self._rendered_rendered = False
179  self._popup_creator_popup_creator = tree._popup_creator
180 
181  @property
182  item = property
183 
184  def item(self):
185  return self.controllercontroller.data
186 
187  @property
188  node = property
189 
190  def node(self):
191  return self._node_node
192 
193  def show_popup(self):
194  self._popup_creator_popup_creator.show(self._tree_tree, PopupMenuItems(self, self._actions),
195  self.controllercontroller)
196 
197  def begin_label_edit(self):
198  return False
199 
200  def double_clicked(self):
201  pass
202 
203  def end_label_edit(self, event):
204  pass
205 
206  def OnDelete(self, event):
207  pass
208 
209  def OnNewSuite(self, event):
210  pass
211 
212  def OnNewDirectory(self, event):
213  pass
214 
215  def OnNewResource(self, event):
216  pass
217 
218  def OnNewUserKeyword(self, event):
219  pass
220 
221  def OnNewTestCase(self, event):
222  pass
223 
224  def OnNewScalar(self, event):
225  pass
226 
227  def OnNewListVariable(self, event):
228  pass
229 
230  def OnNewDictionaryVariable(self, event):
231  pass
232 
233  def OnCopy(self, event):
234  pass
235 
236  def OnFindUsages(self, event):
237  pass
238 
239  def OnSelectAllTests(self, event):
240  self._tree.SelectAllTests(self._node)
241 
242  def OnDeselectAllTests(self, event):
243  self._tree_tree.SelectAllTests(self._node_node, False)
244 
245  def OnSelectOnlyFailedTests(self, event):
246  self._tree_tree.SelectFailedTests(self._node_node)
247 
248  def OnSelectOnlyPassedTests(self, event):
249  self._tree_tree.SelectPassedTests(self._node_node)
250 
251  def OnSafeDelete(self, event):
252  pass
253 
254  def OnExclude(self, event):
255  pass
256 
257  def OnInclude(self, event):
258  pass
259 
260 
261 class _CanBeRenamed():
262 
263  def OnRename(self, event):
264  self._tree.label_editor.OnLabelEdit()
265 
266  def begin_label_edit(self):
267  def label_edit():
268  # FIXME: yep.yep.yep.yep.yep
269  node = self._tree._controller.find_node_by_controller(
270  self.controller)
271  if node:
272  self._tree.EditLabel(node)
273  # Must handle pending events before label edit
274  # This is a fix for situations where there is a pending action
275  # that will change this label (Text Editor all changing actions)
276  wx.CallAfter(label_edit)
277  return True
278 
279  def end_label_edit(self, event):
280  if not event.IsEditCancelled():
281  if self._is_valid_rename_is_valid_rename(event.GetLabel()):
282  self.rename(event.GetLabel())
283  else:
284  event.Veto()
285 
286  def _is_valid_rename(self, label):
287  validation = self.controller.validate_name(label)
288  if validation.error_message:
289  self._show_validation_error_show_validation_error(validation.error_message)
290  return False
291  return True
292 
293  def _show_validation_error(self, err_msg):
294  wx.MessageBox(err_msg, 'Validation Error', style=wx.ICON_ERROR)
295 
296 
298  is_draggable = False
299  is_test_suite = False
300  can_be_rendered = False
301 
304  _actions = [_ActionHandler._label_new_resource]
305 
306  def OnNewResource(self, event):
307  NewResourceDialog(self.controllercontroller, self._settings_settings).execute()
308 
309 
311  accepts_drag = lambda self, dragged: (isinstance(dragged, UserKeywordHandler) or
312  isinstance(dragged, VariableHandler))
313 
314  is_draggable = False
315  is_test_suite = True
316 
317  @property
318  tests = property
319 
320  def tests(self):
321  return self.controllercontroller.tests
322 
323  @property
324  keywords = property
325 
326  def keywords(self):
327  return self.controllercontroller.keywords
328 
329  @property
330  variables = property
331 
332  def variables(self):
333  return self.controllercontroller.variables
334 
336  return self.itemitemitem.has_been_modified_on_disk()
337 
338  def do_drop(self, item):
339  self.controllercontroller.add_test_or_keyword(item)
340 
341  def rename(self, new_name):
342  return False
343 
344 
345  def OnSortTests(self, event):
346  self.controllercontroller.execute(SortTests())
347 
348 
349  def OnSortKeywords(self, event):
350  self.controllercontroller.execute(ctrlcommands.SortKeywords())
351 
352 
353  def OnSortVariables(self, event):
354  self.controllercontroller.execute(SortVariables())
355 
356  @property
357  can_be_rendered = property
358 
359  def can_be_rendered(self):
360  if not self._has_children_has_children():
361  return False
362  return not self._rendered_rendered_rendered
363 
364  def _has_children(self):
365  return (self.itemitemitem.keyword_table or self.itemitemitem.testcase_table or
366  self.itemitemitem.variable_table)
367 
368  def set_rendered(self):
369  self._rendered_rendered_rendered = True
370 
371  def OnChangeFormat(self, event):
372  ChangeFormatDialog(self.controllercontroller).execute()
373 
374  def OnNewUserKeyword(self, event):
375  dlg = UserKeywordNameDialog(self.controllercontroller)
376  if dlg.ShowModal() == wx.ID_OK:
377  self.controllercontroller.execute(ctrlcommands.AddKeyword(dlg.get_name(), dlg.get_args()))
378  dlg.Destroy()
379 
380  def OnNewScalar(self, event):
381  self._new_var_new_var(ScalarVariableDialog)
382 
383  def OnNewListVariable(self, event):
384  class FakePlugin():
385  global_settings = self._settings_settings
386  self._new_var_new_var(ListVariableDialog, plugin=FakePlugin())
387 
388  def OnNewDictionaryVariable(self, event):
389  class FakePlugin():
390  global_settings = self._settings_settings
391  self._new_var_new_var(DictionaryVariableDialog, plugin=FakePlugin())
392 
393  def _new_var(self, dialog_class, plugin=None):
394  dlg = dialog_class(self._var_controller_var_controller_var_controller, plugin=plugin)
395  if dlg.ShowModal() == wx.ID_OK:
396  name, value = dlg.get_value()
397  comment = dlg.get_comment()
398  self.controllercontroller.execute(ctrlcommands.AddVariable(name, value, comment))
399 
400  @property
401  _var_controller = property
402 
403  def _var_controller(self):
404  return self.controllercontroller.datafile_controller.variables
405 
406 
408 
409  def __init__(self, *args):
410  TestDataHandler.__init__(self, *args)
411  self._actions_actions = [
412  _ActionHandler._label_add_suite,
413  _ActionHandler._label_add_directory,
414  _ActionHandler._label_new_resource,
415  '---',
416  _ActionHandler._label_new_user_keyword,
417  _ActionHandler._label_new_scalar,
418  _ActionHandler._label_new_list_variable,
419  _ActionHandler._label_new_dict_variable,
420  '---',
421  _ActionHandler._label_change_format
422  ]
423  if self.controllercontroller.parent:
424  self._actions_actions.extend([_ActionHandler._label_delete_no_kbsc])
425 
426  self._actions_actions.extend([
427  '---',
428  _ActionHandler._label_select_all,
429  _ActionHandler._label_deselect_all,
430  _ActionHandler._label_select_failed_tests,
431  _ActionHandler._label_select_passed_tests
432  ])
433  if self.controllercontroller.parent:
434  self._actions_actions.extend(['---',
435  _ActionHandler._label_exclude])
436  self._actions_actions.extend(['---',
437  _ActionHandler._label_expand_all,
438  _ActionHandler._label_collapse_all])
439 
440  def OnExpandAll(self, event):
441  self._tree_tree.ExpandAllSubNodes(self._node_node)
442 
443  def OnCollapseAll(self, event):
444  self._tree_tree.CollapseAllSubNodes(self._node_node)
445 
446  def OnNewSuite(self, event):
447  AddSuiteDialog(self.controllercontroller, self._settings_settings).execute()
448 
449  def OnNewDirectory(self, event):
450  AddDirectoryDialog(self.controllercontroller, self._settings_settings).execute()
451 
452  def OnNewResource(self, event):
453  NewResourceDialog(self.controllercontroller, self._settings_settings).execute()
454 
455  def OnDelete(self, event):
456  FolderDeleteDialog(self.controllercontroller).execute()
457 
458  def OnExclude(self, event):
459  try:
460  self.controllercontroller.execute(ctrlcommands.Exclude())
461  except filecontrollers.DirtyRobotDataException:
462  wx.MessageBox('Directory contains unsaved data!\n'
463  'You must save data before excluding.')
464 
465 
467 
468  @overrides(_CanBeRenamed)
469  def begin_label_edit(self):
470  self._old_label_old_label = self._node.GetText()
471  self._set_node_label_set_node_label(self.controller.basename)
472  return _CanBeRenamed.begin_label_edit(self)
473 
474  @overrides(_CanBeRenamed)
475  def end_label_edit(self, event):
476  if not event.IsEditCancelled():
477  result = self.controller.execute(
478  self._rename_command_rename_command(event.GetLabel()))
479  if result:
480  self._rename_ok_handler_rename_ok_handler()
481  self._old_label_old_label = self.controller.basename
482  else:
483  event.Veto()
484  else:
485  self._set_node_label_set_node_label(self._old_label_old_label)
486 
488  pass
489 
490  def _rename_command(self, label):
491  raise NotImplementedError(self.__class__)
492 
493  def _set_node_label(self, label):
494  self._tree.SetItemText(self._node, label)
495 
496 
498  is_test_suite = False
499 
502  _actions = [_ActionHandler._label_new_user_keyword,
503  _ActionHandler._label_new_scalar,
504  _ActionHandler._label_new_list_variable,
505  _ActionHandler._label_new_dict_variable,
506  '---',
507  _ActionHandler._label_rename,
508  _ActionHandler._label_change_format,
509  _ActionHandler._label_sort_keywords,
510  _ActionHandler._label_find_usages,
511  _ActionHandler._label_delete,
512  '---',
513  _ActionHandler._label_sort_variables,
514  _ActionHandler._label_sort_keywords,
515  '---',
516  _ActionHandler._label_remove_readonly,
517  _ActionHandler._label_open_folder
518  ]
519 
520  def OnRemoveReadOnly(self, event):
521 
522  def returnTrue():
523  return True
524  self.controllercontroller.is_modifiable = returnTrue
525  self.controllercontroller.execute(ctrlcommands.RemoveReadOnly())
526 
527  def OnOpenContainingFolder(self, event):
528  self.controllercontroller.execute(ctrlcommands.OpenContainingFolder())
529 
530  def OnFindUsages(self, event):
531  ResourceFileUsages(self.controllercontroller, self._tree_tree.highlight).show()
532 
533  def OnDelete(self, event):
534  ResourceDeleteDialog(self.controllercontroller).execute()
535 
536  def OnSafeDelete(self, event):
537  return self.OnDeleteOnDeleteOnDelete(event)
538 
539  @overrides(_FileHandlerThanCanBeRenamed)
540  def _rename_command(self, label):
541  return ctrlcommands.RenameResourceFile(
542  label, self._check_should_rename_static_imports_check_should_rename_static_imports)
543 
545  return ResourceRenameDialog(self.controllercontroller).execute()
546 
547 
549  accepts_drag = lambda *args: True
550 
553  _actions = [_ActionHandler._label_new_test_case,
554  _ActionHandler._label_new_user_keyword,
555  _ActionHandler._label_new_scalar,
556  _ActionHandler._label_new_list_variable,
557  _ActionHandler._label_new_dict_variable,
558  '---',
559  _ActionHandler._label_rename,
560  _ActionHandler._label_change_format,
561  _ActionHandler._label_sort_keywords,
562  _ActionHandler._label_delete,
563  '---',
564  _ActionHandler._label_sort_variables,
565  _ActionHandler._label_sort_tests,
566  _ActionHandler._label_sort_keywords,
567  '---',
568  _ActionHandler._label_select_all,
569  _ActionHandler._label_deselect_all,
570  _ActionHandler._label_select_failed_tests,
571  _ActionHandler._label_select_passed_tests,
572  '---',
573  _ActionHandler._label_remove_readonly,
574  _ActionHandler._label_open_folder
575  ]
576 
577  def OnRemoveReadOnly(self, event):
578 
579  def returnTrue():
580  return True
581  self.controllercontroller.is_modifiable = returnTrue
582  self.controllercontroller.execute(ctrlcommands.RemoveReadOnly())
583 
584  def OnOpenContainingFolder(self, event):
585 
586  self.controllercontroller.execute(ctrlcommands.OpenContainingFolder())
587 
588  def OnNewTestCase(self, event):
589  dlg = TestCaseNameDialog(self.controllercontroller)
590  if dlg.ShowModal() == wx.ID_OK:
591  self.controllercontroller.execute(ctrlcommands.AddTestCase(dlg.get_name()))
592  dlg.Destroy()
593 
594  def OnDelete(self, event):
595  if wx.MessageBox('Delete test case file', caption='Confirm',
596  style=wx.YES_NO | wx.ICON_QUESTION) == wx.YES:
597  self.controllercontroller.execute(ctrlcommands.DeleteFile())
598 
599  def OnSafeDelete(self, event):
600  return self.OnDeleteOnDeleteOnDelete(event)
601 
602  @overrides(_FileHandlerThanCanBeRenamed)
603  def _rename_command(self, label):
604  return ctrlcommands.RenameFile(label)
605 
606  @overrides(_FileHandlerThanCanBeRenamed)
608  self._tree_tree.SelectAllTests(self._node_node,False)
609 
610 
612  accepts_drag = lambda *args: False
613  is_draggable = True
614 
617  _actions = [
618  _ActionHandler._label_copy_macro,
619  'Move Up\tCtrl-Up',
620  'Move Down\tCtrl-Down',
621  _ActionHandler._label_rename,
622  '---',
623  'Delete'
624  ]
625 
626  def remove(self):
627  self.controllercontroller.delete()
628 
629  def rename(self, new_name):
630  self.controllercontroller.execute(self._create_rename_command(new_name))
631 
632  def OnCopy(self, event):
633  dlg = self._copy_name_dialog_class(self.controllercontroller, self.itemitemitem)
634  if dlg.ShowModal() == wx.ID_OK:
635  self.controllercontroller.execute(ctrlcommands.CopyMacroAs(dlg.get_name()))
636  dlg.Destroy()
637 
638  def OnMoveUp(self, event):
639  if self.controllercontroller.move_up():
640  self._tree_tree.move_up(self._node_node)
641 
642  def OnMoveDown(self, event):
643  if self.controllercontroller.move_down():
644  self._tree_tree.move_down(self._node_node)
645 
646  def OnDelete(self, event):
647  self.controllercontroller.execute(ctrlcommands.RemoveMacro(self.controllercontroller))
648 
649 
651  def __init__(self, controller, tree, node, settings):
652  _TestOrUserKeywordHandler.__init__(self, controller, tree, node, settings)
653  PUBLISHER.subscribe(self.test_selection_changedtest_selection_changed, RideTestSelectedForRunningChanged)
654 
655 
658  _datalist = property(lambda self: self.itemitemitem.datalist)
659 
662  _copy_name_dialog_class = TestCaseNameDialog
663 
664  def _add_copy_to_tree(self, parent_node, copied):
665  self._tree_tree.add_test(parent_node, copied)
666 
667  def _create_rename_command(self, new_name):
668  return ctrlcommands.RenameTest(new_name)
669 
670  def test_selection_changed(self, message):
671  if self.controllercontroller in message.tests:
672  if not self.nodenodenode.GetValue():
673  self._tree_tree.CheckItem(self.nodenodenode, checked=True)
674  else:
675  if self.nodenodenode.GetValue():
676  self._tree_tree.CheckItem(self.nodenodenode, checked=False)
677 
678 
680  is_user_keyword = True
681 
684  _datalist = property(lambda self: self.itemitemitem.datalist)
685 
688  _copy_name_dialog_class = CopyUserKeywordDialog
689 
692  _actions = _TestOrUserKeywordHandler._actions + [
693  _ActionHandler._label_find_usages]
694 
695  def _add_copy_to_tree(self, parent_node, copied):
696  self._tree_tree.add_keyword(parent_node, copied)
697 
698  def _create_rename_command(self, new_name):
699  return ctrlcommands.RenameKeywordOccurrences(
700  self.controllercontroller.name, new_name,
701  RenameProgressObserver(self._tree_tree.GetParent()),
702  self.controllercontroller.info)
703 
704  def OnFindUsages(self, event):
705  Usages(self.controllercontroller, self._tree_tree.highlight).show()
706 
707 
709  accepts_drag = lambda *args: False
710  is_draggable = True
711  is_variable = True
712  OnMoveUp = OnMoveDown = lambda *args: None
713 
716  _actions = [
717  'Move Up\tCtrl-Up',
718  'Move Down\tCtrl-Down',
719  _ActionHandler._label_rename,
720  '---',
721  'Delete'
722  ]
723 
724  @overrides(_ActionHandler)
725  def double_clicked(self):
726  RideOpenVariableDialog(controller=self.controllercontroller).publish()
727 
728  def OnDelete(self, event):
729  self.removeremove()
730 
731  def remove(self):
732  self.controllercontroller.delete()
733 
734  def rename(self, new_name):
735  self.controllercontroller.execute(ctrlcommands.UpdateVariableName(new_name))
736 
737  def OnMoveUp(self, event):
738  if self.controllercontroller.move_up():
739  self._tree_tree.move_up(self._node_node)
740 
741  def OnMoveDown(self, event):
742  if self.controllercontroller.move_down():
743  self._tree_tree.move_down(self._node_node)
744 
745  @property
746  index = property
747 
748  def index(self):
749  return self.controllercontroller.index
750 
751 
753  can_be_rendered = is_draggable = is_user_keyword = is_test_suite = False
754  rename = lambda self, new_name: False
755  accepts_drag = lambda self, dragged: False
756 
759  _actions = [_ActionHandler._label_add_resource]
760 
761  @property
762  item = property
763 
764  def item(self):
765  return None
766 
767  def OnAddResource(self, event):
768  path = RobotFilePathDialog(
769  self._tree_tree.GetParent(), self.controllercontroller, self._settings_settings).execute()
770  if path:
771  self.controllercontroller.load_resource(path, LoadProgressObserver(self._tree_tree.GetParent()))
772 
773 
775  is_draggable = False
776  is_test_suite = True
777 
778  def __init__(self, *args):
779  TestDataHandler.__init__(self, *args)
780  self._actions_actions_actions = [_ActionHandler._label_include]
781 
782  def OnInclude(self, event):
783  self.controllercontroller.execute(ctrlcommands.Include())
Sent when variable dialog is requested to be open.
Definition: messages.py:187
def _add_copy_to_tree(self, parent_node, copied)
def __init__(self, controller, tree, node, settings)
def OnSortTests(self, event)
Sorts the tests inside the treenode.
def OnSortKeywords(self, event)
Sorts the keywords inside the treenode.
def _new_var(self, dialog_class, plugin=None)
def OnSortVariables(self, event)
Sorts the variables inside the treenode.
def _add_copy_to_tree(self, parent_node, copied)
def __init__(self, controller, tree, node, settings)
def action_handler_class(controller)