Coverage for src/robotide/editor/settingeditors.py: 25%
515 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
18from wx import Colour 1ab
20from multiprocessing import shared_memory 1ab
21from .editordialogs import editor_dialog, DocumentationDialog, MetadataDialog, \ 1ab
22 ScalarVariableDialog, ListVariableDialog, DictionaryVariableDialog, LibraryDialog, \
23 ResourceDialog, VariablesDialog
24from .formatters import ListToStringFormatter 1ab
25from .gridcolorizer import ColorizationSettings 1ab
26from ..lib.compat.parsing.language import get_english_label 1ab
27from .listeditor import ListEditor 1ab
28from .popupwindow import HtmlPopupWindow 1ab
29from .tags import TagsDisplay 1ab
30from .. import context 1ab
31from .. import utils 1ab
32from ..controller import ctrlcommands 1ab
33from ..publish import PUBLISHER 1ab
34from ..publish.messages import (RideImportSetting, RideOpenVariableDialog, RideExecuteSpecXmlImport, RideSaving, 1ab
35 RideVariableAdded, RideVariableUpdated, RideVariableRemoved)
36from ..utils.highlightmatcher import highlight_matcher 1ab
37from ..widgets import ButtonWithHandler, Label, HtmlWindow, PopupMenu, PopupMenuItems, HtmlDialog 1ab
39_ = wx.GetTranslation # To keep linter/code analyser happy 1ab
40builtins.__dict__['_'] = wx.GetTranslation 1ab
43class SettingEditor(wx.Panel): 1ab
44 popup_timer = None 1ab
46 def __init__(self, parent, controller, plugin, tree): 1ab
47 wx.Panel.__init__(self, parent)
48 from ..preferences import RideSettings
49 _settings = RideSettings()
50 self.general_settings = _settings['General']
51 self.color_background = self.general_settings.get('background', 'light grey')
52 self.color_foreground = self.general_settings.get('foreground', 'black')
53 self.color_secondary_background = self.general_settings.get('secondary background', 'light grey')
54 self.color_secondary_foreground = self.general_settings.get('secondary foreground', 'black')
55 self.color_background_help = self.general_settings.get('background help', (240, 242, 80))
56 self.color_foreground_text = self.general_settings.get('foreground text', (7, 0, 70))
57 self.font_face = self.general_settings.get('font face', '')
58 self.font_size = self.general_settings.get('font size', 11)
59 self.SetBackgroundColour(Colour(self.color_background))
60 # self.SetOwnBackgroundColour(Colour(self.color_background))
61 self.SetForegroundColour(Colour(self.color_foreground))
62 # self.SetOwnForegroundColour(Colour(self.color_foreground))
63 self._controller = controller
64 try:
65 set_lang = shared_memory.ShareableList(name="language")
66 self._language = [set_lang[0]]
67 # print(f"DEBUG: settings.py SettingEditor __init__ SHAREDMEM language={self._language}")
68 except AttributeError:
69 print("DEBUG: settings.py SettingEditor __init__ AttributeError")
70 try:
71 self._language = self._controller.language
72 # print(f"DEBUG: settings.py SettingEditor __init__ CONTROLLER language={self._language}")
73 except AttributeError:
74 self._language = ['en']
75 # print(f"DEBUG: settings.py SettingEditor __init__ set_lang={set_lang} language={self._language}")
76 self.plugin = plugin
77 self._datafile = controller.datafile
78 self._create_controls()
79 self._tree = tree
80 self._editing = False
81 self.font = self._tree.GetFont()
82 self.font.SetFaceName(self.font_face)
83 self.font.SetPointSize(self.font_size)
84 self._tree.SetFont(self.font)
85 self._tree.Refresh()
86 self.plugin.subscribe(self._ps_on_update_value, RideImportSetting)
88 def _create_controls(self): 1ab
89 sizer = wx.BoxSizer(wx.HORIZONTAL)
90 sizer.Add((5, 0))
91 width = max(len(self._controller.label), context.SETTING_LABEL_WIDTH)
92 label = Label(self, label=self._controller.label,
93 size=(width, context.SETTING_ROW_HEIGHT)) # Always show the English label as tooltip
94 label.SetToolTip(get_english_label(self._language, self._controller.label))
95 sizer.Add(label)
96 self._value_display = self._create_value_display()
97 self.update_value()
98 self._tooltip = self._get_tooltip()
99 sizer.Add(self._value_display, 1, wx.EXPAND)
100 self._add_edit(sizer)
101 sizer.Add(ButtonWithHandler(self, _('Clear'), mk_handler='Clear', handler=self.on_clear, fsize=self.font_size,
102 color_secondary_foreground=self.color_secondary_foreground,
103 color_secondary_background=self.color_secondary_background))
104 sizer.Layout()
105 self.SetSizer(sizer)
107 def _add_edit(self, sizer): 1ab
108 sizer.Add(
109 ButtonWithHandler(self, _('Edit'), mk_handler='Edit', handler=self.on_edit, fsize=self.font_size,
110 color_secondary_foreground=self.color_secondary_foreground,
111 color_secondary_background=self.color_secondary_background),
112 flag=wx.LEFT | wx.RIGHT, border=5)
114 def _create_value_display(self): 1ab
115 display = self._value_display_control()
116 display.Bind(wx.EVT_ENTER_WINDOW, self.on_enter_window)
117 display.Bind(wx.EVT_LEAVE_WINDOW, self.on_leave_window)
118 display.Bind(wx.EVT_WINDOW_DESTROY, self.on_window_destroy)
119 display.Bind(wx.EVT_MOTION, self.on_display_motion)
120 return display
122 def _value_display_control(self): 1ab
123 ctrl = SettingValueDisplay(self)
124 ctrl.Bind(wx.EVT_LEFT_UP, self.on_left_up)
125 ctrl.Bind(wx.EVT_KEY_DOWN, self.on_key)
126 return ctrl
128 def _get_tooltip(self): 1ab
129 return HtmlPopupWindow(self, (500, 350))
131 def on_key(self, event): 1ab
132 try:
133 self._tooltip.hide()
134 except AttributeError:
135 pass
136 event.Skip()
138 def on_display_motion(self, event): 1ab
139 try:
140 self._tooltip.hide()
141 except AttributeError:
142 pass
144 def refresh_values(self, controller): 1ab
145 self._controller = controller
146 self.update_value()
148 def refresh_datafile(self, item, event): 1ab
149 self._tree.refresh_datafile(item, event)
151 def on_edit(self, event=None): 1ab
152 self._hide_tooltip()
153 self._editing = True
154 dlg = self._create_editor_dialog()
155 if dlg.ShowModal() == wx.ID_OK:
156 value = dlg.get_value()
157 comment = dlg.get_comment()
158 if value != ['']:
159 self._set_value(value, comment)
160 self._update_and_notify()
161 else:
162 wx.CallAfter(self.on_clear, event)
163 dlg.Destroy()
164 self._editing = False
166 def _create_editor_dialog(self): 1ab
167 dlg_class = editor_dialog(self._controller, self._language)
168 return dlg_class(self._datafile, self._controller, self.plugin)
170 def _set_value(self, value_list, comment): 1ab
171 self._controller.execute(ctrlcommands.SetValues(value_list, comment))
173 def _hide_tooltip(self): 1ab
174 self._stop_popup_timer()
175 try:
176 self._tooltip.hide()
177 except AttributeError:
178 pass
180 def _stop_popup_timer(self): 1ab
181 if hasattr(self, 'popup_timer') and self.popup_timer is not None:
182 self.popup_timer.Stop()
184 def on_enter_window(self, event): 1ab
185 if self._mainframe_has_focus():
186 self.popup_timer = wx.CallLater(500, self.on_popup_timer, event)
188 def _mainframe_has_focus(self): 1ab
189 return wx.GetTopLevelParent(self.FindFocus()) == \
190 wx.GetTopLevelParent(self)
192 def on_window_destroy(self, event): 1ab
193 self._stop_popup_timer()
194 try:
195 self._tooltip.hide()
196 except AttributeError:
197 pass
198 event.Skip()
200 def on_leave_window(self, event): 1ab
201 self.on_window_destroy(event)
203 def on_popup_timer(self, event): 1ab
204 __ = event
205 _tooltipallowed = True
206 # DEBUG: This prevents tool tip for ex. Template edit field in wxPhoenix
207 try:
208 _tooltipallowed = self.Parent.tooltip_allowed(self._tooltip)
209 except AttributeError:
210 # print("DEBUG: There was an attempt to show a Tool Tip.\n")
211 pass
212 if _tooltipallowed:
213 details, title = self._get_details_for_tooltip()
214 if details:
215 self._tooltip.set_content(details, title)
216 self._tooltip.show_at(self._tooltip_position())
218 def _get_details_for_tooltip(self): 1ab
219 kw = self._controller.keyword_name
220 return self.plugin.get_keyword_details(kw), kw
222 @staticmethod 1ab
223 def _tooltip_position(): 1ab
224 ms = wx.GetMouseState()
225 # ensure that the popup gets focus immediately
226 return ms.x-3, ms.y-3
228 def on_left_up(self, event): 1ab
229 if event.ControlDown() or event.CmdDown():
230 self._navigate_to_user_keyword()
231 else:
232 if self._has_selected_area() and not self._editing:
233 wx.CallAfter(self.on_edit, event)
234 event.Skip()
236 def _has_selected_area(self): 1ab
237 selection = self._value_display.GetSelection()
238 if selection is None:
239 return False
240 return selection[0] == selection[1]
242 def _navigate_to_user_keyword(self): 1ab
243 uk = self.plugin.get_user_keyword(self._controller.keyword_name)
244 if uk:
245 self._tree.select_user_keyword_node(uk)
247 def _update_and_notify(self): 1ab
248 self.update_value()
250 def on_clear(self, event): 1ab
251 __ = event
252 self._controller.execute(ctrlcommands.ClearSetting())
253 self._update_and_notify()
255 def _ps_on_update_value(self, message): 1ab
256 _ = message
257 self.update_value()
259 def update_value(self): 1ab
260 if self._controller is None:
261 return
262 if self._controller.is_set:
263 self._value_display.set_value(self._controller, self.plugin)
264 else:
265 self._value_display.clear_field()
266 self.Refresh()
268 def get_selected_datafile_controller(self): 1ab
269 return self._controller.datafile_controller
271 def close(self): 1ab
272 self._controller = None
273 self.plugin.unsubscribe(self._ps_on_update_value, RideImportSetting)
275 def highlight(self, text): 1ab
276 return self._value_display.highlight(text)
278 def clear_highlight(self): 1ab
279 return self._value_display.clear_highlight()
281 def contains(self, text): 1ab
282 return self._value_display.contains(text)
285class SettingValueDisplay(wx.TextCtrl, HtmlPopupWindow): 1ab
286 _is_user_keyword = False 1ab
287 _keyword_name = None 1ab
288 _value = None 1ab
290 def __init__(self, parent): 1ab
291 wx.TextCtrl.__init__(
292 self, parent, size=(-1, context.SETTING_ROW_HEIGHT),
293 style=wx.TE_RICH | wx.TE_MULTILINE | wx.TE_NOHIDESEL)
294 """
295 self.SetBackgroundColour(Colour(200, 222, 40))
296 self.SetOwnBackgroundColour(Colour(200, 222, 40))
297 self.SetForegroundColour(Colour(7, 0, 70))
298 self.SetOwnForegroundColour(Colour(7, 0, 70))
299 """
300 self.color_secondary_background = parent.color_secondary_background
301 self.SetBackgroundColour(Colour(self.color_secondary_background))
302 self.SetEditable(False)
303 self._colour_provider = ColorizationSettings(
304 parent.plugin.global_settings['Grid'])
305 self._empty_values()
307 def _empty_values(self): 1ab
308 self._value = None
309 self._is_user_keyword = False
311 def set_value(self, controller, plugin): 1ab
312 self._value = controller.display_value
313 self._keyword_name = controller.keyword_name
314 try:
315 self._is_user_keyword = plugin.is_user_keyword(self._keyword_name)
316 except AttributeError:
317 self._is_user_keyword = False
318 self.SetValue(self._value)
319 self._colorize_data()
321 def _colorize_data(self, match=None): 1ab
322 self._colorize_background(match)
323 self._colorize_possible_user_keyword()
325 def _colorize_background(self, match=None): 1ab
326 self.SetBackgroundColour(self._get_background_colour(match))
328 def _get_background_colour(self, match=None): 1ab
329 if self._value is None:
330 return Colour(self.color_secondary_background)
331 if match is not None and self.contains(match):
332 return self._colour_provider.get_highlight_color()
333 return Colour(self.color_secondary_background) # 'white' # Colour(200, 222, 40)
335 def _colorize_possible_user_keyword(self): 1ab
336 if not self._is_user_keyword:
337 return
338 font = self.GetFont()
339 font.SetUnderlined(True)
340 user_kw_color = self._colour_provider.get_text_color('user keyword')
341 self.SetStyle(0, len(self._keyword_name),
342 wx.TextAttr(user_kw_color, self._get_background_colour(), font))
344 def clear_field(self): 1ab
345 self.Clear()
346 self._empty_values()
347 self._colorize_background()
349 def contains(self, text): 1ab
350 if self._value is None:
351 return False
352 return [item for item in self._value.split(' | ')
353 if highlight_matcher(text, item)] != []
355 def highlight(self, text): 1ab
356 self._colorize_data(match=text)
358 def clear_highlight(self): 1ab
359 self._colorize_data()
362class DocumentationEditor(SettingEditor): 1ab
364 def __init__(self, parent, controller, plugin, tree): 1ab
365 # print(f"DEBUG: DocumentationEditor parent={parent} controller={controller}")
366 SettingEditor.__init__(self, parent, controller, plugin, tree)
368 def _value_display_control(self): 1ab
369 ctrl = HtmlWindow(self, (-1, 100), color_background=self.color_secondary_background,
370 color_foreground=self.color_secondary_foreground)
371 ctrl.SetBackgroundColour(Colour(self.color_secondary_background))
372 ctrl.SetForegroundColour(Colour(self.color_secondary_foreground))
373 ctrl.Bind(wx.EVT_LEFT_DOWN, self.on_edit)
374 return ctrl
376 def update_value(self): 1ab
377 if self._controller:
378 self._value_display.set_content(self._controller.visible_value)
380 def on_key(self, event): 1ab
381 event.Skip()
383 def on_display_motion(self, event): 1ab
384 """ Just ignoring it """
385 pass
387 def _hide_tooltip(self): 1ab
388 """ Just ignoring it """
389 pass
391 def _create_editor_dialog(self): 1ab
392 # print(f"DEBUG: settingeditors.py DocumentationEditor _create_editor_dialog {self._language}")
393 return DocumentationDialog(self._datafile,
394 self._controller.editable_value)
396 def _set_value(self, value_list, comment): 1ab
397 if value_list:
398 self._controller.execute(ctrlcommands.UpdateDocumentation(value_list[0]))
400 def contains(self, text): 1ab
401 return False
403 def highlight(self, text): 1ab
404 """ Just ignoring it """
405 pass
407 def clear_highlight(self): 1ab
408 """ Just ignoring it """
409 pass
412class TagsEditor(SettingEditor): 1ab
414 def __init__(self, parent, controller, plugin, tree): 1ab
415 SettingEditor.__init__(self, parent, controller, plugin, tree)
416 self.plugin.subscribe(self._saving, RideSaving)
418 def _saving(self, message): 1ab
419 _ = message
420 self._tags_display.saving()
422 def _value_display_control(self): 1ab
423 self._tags_display = TagsDisplay(self, self._controller)
424 self._tags_display.Bind(wx.EVT_LEFT_UP, self.on_left_up)
425 self._tags_display.Bind(wx.EVT_KEY_DOWN, self.on_key)
426 return self._tags_display
428 def contains(self, text): 1ab
429 return False
431 def highlight(self, text): 1ab
432 """ Just ignoring it """
433 pass
435 def clear_highlight(self): 1ab
436 """ Just ignoring it """
437 pass
439 def close(self): 1ab
440 self._tags_display.close()
441 self.plugin.unsubscribe(self._saving, RideSaving)
442 SettingEditor.close(self)
445class _AbstractListEditor(ListEditor): 1ab
446 _titles = [] 1ab
448 def __init__(self, parent, tree, controller, label=None): 1ab
449 try:
450 # print(f"DEBUG: settingeditors.py _AbstractListEditor dir language={controller.parent.datafile._language}")
451 self._language = controller.parent.datafile._language
452 except AttributeError:
453 self._language = ['en']
454 ListEditor.__init__(self, parent, self._titles, controller)
455 self._datafile = controller.datafile
456 self._tree = tree
458 def get_selected_datafile_controller(self): 1ab
459 return self._controller.datafile_controller
461 def refresh_datafile(self, item, event): 1ab
462 self._tree.refresh_datafile(item, event)
464 def update_data(self): 1ab
465 ListEditor.update_data(self)
467 def update_value(self): 1ab
468 """ Just ignoring it """
469 pass
471 def close(self): 1ab
472 """ Just ignoring it """
473 pass
475 def highlight(self, text, expand=False): 1ab
476 """ Just ignoring it """
477 pass
480class VariablesListEditor(_AbstractListEditor): 1ab
481 _buttons_nt = ['Add Scalar', 'Add List', 'Add Dict'] 1ab
483 def __init__(self, parent, tree, controller): 1ab
484 self._titles = [_('Variable'), _('Value'), _('Comment')]
485 self._buttons = [_('Add Scalar'), _('Add List'), _('Add Dict')]
486 PUBLISHER.subscribe(
487 self._update_vars, RideVariableAdded)
488 PUBLISHER.subscribe(
489 self._update_vars, RideVariableUpdated)
490 PUBLISHER.subscribe(
491 self._update_vars, RideVariableRemoved)
492 PUBLISHER.subscribe(self._open_variable_dialog, RideOpenVariableDialog)
493 _AbstractListEditor.__init__(self, parent, tree, controller)
495 def _update_vars(self, message): 1ab
496 _ = message
497 ListEditor.update_data(self)
499 @staticmethod 1ab
500 def get_column_values(item): 1ab
501 return [item.name, item.value
502 if isinstance(item.value, str)
503 else ' | '.join(item.value),
504 ListToStringFormatter(item.comment).value]
506 def on_move_up(self, event): 1ab
507 _AbstractListEditor.on_move_up(self, event)
508 self._list.SetFocus()
510 def on_move_down(self, event): 1ab
511 _AbstractListEditor.on_move_down(self, event)
512 self._list.SetFocus()
514 def on_add_scalar(self, event): 1ab
515 __ = event
516 self._show_dialog(
517 ScalarVariableDialog(self._controller))
519 def on_add_list(self, event): 1ab
520 __ = event
521 self._show_dialog(
522 ListVariableDialog(self._controller, plugin=self.Parent.plugin))
524 def on_add_dict(self, event): 1ab
525 __ = event
526 self._show_dialog(
527 DictionaryVariableDialog(self._controller,
528 plugin=self.Parent.plugin))
530 def _show_dialog(self, dlg): 1ab
531 if dlg.ShowModal() == wx.ID_OK:
532 ctrl = self._controller.add_variable(*dlg.get_value())
533 ctrl.set_comment(dlg.get_comment())
534 self.update_data()
535 dlg.Destroy()
537 def on_edit(self, event): 1ab
538 var = self._controller[self._selection]
539 self._open_var_dialog(var)
541 def _open_variable_dialog(self, message): 1ab
542 # Prevent opening a dialog if self has been destroyed
543 if self:
544 self._open_var_dialog(message.controller)
546 def _open_var_dialog(self, var): 1ab
547 var_name = var.name.lower()
548 dlg = None
549 if var_name.startswith('${'):
550 dlg = ScalarVariableDialog(self._controller, item=var)
551 elif var_name.startswith('@{'):
552 dlg = ListVariableDialog(self._controller, item=var,
553 plugin=self.Parent.plugin)
554 elif var_name.startswith('&{'):
555 dlg = DictionaryVariableDialog(self._controller, item=var,
556 plugin=self.Parent.plugin)
557 if dlg: # DEBUG robot accepts % variable definition
558 if dlg.ShowModal() == wx.ID_OK:
559 name, value = dlg.get_value()
560 var.execute(ctrlcommands.UpdateVariable(name, value, dlg.get_comment()))
561 self.update_data()
562 dlg.Destroy()
564 def close(self): 1ab
565 PUBLISHER.unsubscribe_all(self)
568class ImportSettingListEditor(_AbstractListEditor): 1ab
569 _buttons_nt = ['Library', 'Resource', 'Variables', 'Import Failed Help'] 1ab
571 def __init__(self, parent, tree, controller, lang=None): 1ab
572 self._titles = [_('Import'), _('Name / Path'), _('Arguments'), _('Comment')]
573 self._buttons = [_('Library'), _('Resource'), _('Variables'), _('Import Failed Help')]
574 self._import_failed_shown = False
575 try:
576 self._language = controller.parent.datafile._language
577 except AttributeError:
578 self._language = ['en']
579 _AbstractListEditor.__init__(self, parent, tree, controller)
580 self.SetBackgroundColour(Colour(self.color_background))
581 # self.SetOwnBackgroundColour(Colour(self.color_background))
582 self.SetForegroundColour(Colour(self.color_foreground))
583 # self.SetOwnForegroundColour(Colour(self.color_foreground))
585 def _create_buttons(self): 1ab
586 sizer = wx.BoxSizer(wx.VERTICAL)
587 label = _('Add Import')
588 lsize = len(label) * self.font_size + 4
589 sizer.Add(Label(
590 self, label=label, size=wx.Size(lsize, 20),
591 style=wx.ALIGN_CENTER))
592 # Get max button size
593 fsize = max(8, self.font_size)
594 bsize = 0
595 for x in self._buttons:
596 bsize = max(bsize, len(x))
597 bsize = bsize * fsize
598 for label, label_nt in zip(self._buttons, self._buttons_nt):
599 sizer.Add(ButtonWithHandler(self, label, mk_handler=label_nt, width=bsize,
600 color_secondary_foreground=self.color_secondary_foreground,
601 color_secondary_background=self.color_secondary_background), 0, wx.ALL, 1)
602 return sizer
604 def on_left_click(self, event): 1ab
605 if not self.is_selected:
606 return
607 if wx.GetMouseState().ControlDown() or wx.GetMouseState().CmdDown():
608 self.navigate_to_tree()
610 def navigate_to_tree(self): 1ab
611 setting = self._get_setting()
612 if self.has_link_target(setting):
613 self._tree.select_node_by_data(setting.get_imported_controller())
615 def has_link_target(self, controller): 1ab
616 return controller.is_resource and controller.get_imported_controller()
618 def has_error(self, controller): 1ab
619 return controller.has_error()
621 def on_right_click(self, event): 1ab
622 menu, menu_nt = self._create_item_menu()
623 PopupMenu(self, PopupMenuItems(self, menu_names=menu, menu_names_nt=menu_nt))
625 def _create_item_menu(self): 1ab
626 menu = self._menu
627 menu_nt = self._menu_nt
628 item = self._controller[self._selection]
629 if item.has_error() and item.type == 'Library':
630 menu = menu[:] + [_('Import Library Spec XML')]
631 menu_nt = menu_nt[:] + ['Import Library Spec XML']
632 return menu, menu_nt
634 @staticmethod 1ab
635 def on_import_library_spec_xml(event): 1ab
636 __ = event
637 RideExecuteSpecXmlImport().publish()
639 def on_edit(self, event): 1ab
640 setting = self._get_setting()
641 self._show_import_editor_dialog(
642 editor_dialog(setting, self._language),
643 lambda v, c: setting.execute(ctrlcommands.SetValues(v, c)),
644 setting, on_empty=self._delete_selected,
645 title=_('Edit'))
647 def on_library(self, event): 1ab
648 __ = event
649 self._show_import_editor_dialog(
650 LibraryDialog,
651 lambda v, c: self._controller.execute(ctrlcommands.AddLibrary(v, c)),
652 title=_('Library'))
654 def on_resource(self, event): 1ab
655 __ = event
656 self._show_import_editor_dialog(
657 ResourceDialog,
658 lambda v, c: self._controller.execute(ctrlcommands.AddResource(v, c)),
659 title=_('Resource'))
661 def on_variables(self, event): 1ab
662 __ = event
663 self._show_import_editor_dialog(
664 VariablesDialog,
665 lambda v, c:
666 self._controller.execute(ctrlcommands.AddVariablesFileImport(v, c)),
667 title=_('Variables'))
669 def on_import_failed_help(self, event): 1ab
670 __ = event
671 if self._import_failed_shown:
672 return
673 dialog = HtmlDialog(_('Import failure handling'), _('''<br>Possible corrections and notes:<br>
674 <ul>
675 <li>Import failure is shown with red color.</li>
676 <li>See Tools / View RIDE Log for detailed information about the failure.</li>
677 <li>If the import contains a variable that RIDE has not initialized, consider adding the variable
678 to variable table with a default value.</li>
679 <li>For library import failure: Consider importing library spec XML (Tools / Import Library Spec XML or by
680 adding the XML file with the correct name to PYTHONPATH) to enable keyword completion
681 for example for Java libraries.
682 Library spec XML can be created using libdoc tool from Robot Framework.
683 For more information see
684 <a href="https://github.com/robotframework/RIDE/wiki/Keyword-Completion#wiki-using-library-specs">wiki</a>.
685 </li>
686 </ul>'''))
687 dialog.Bind(wx.EVT_CLOSE, self._import_failed_help_closed)
688 dialog.Show()
689 self._import_failed_shown = True
691 def _import_failed_help_closed(self, event): 1ab
692 self._import_failed_shown = False
693 event.Skip()
695 def _get_setting(self): 1ab
696 return self._controller[self._selection]
698 def _show_import_editor_dialog(self, dialog, creator_or_setter, item=None, on_empty=None, title=None): 1ab
699 dlg = dialog(self._controller, item=item, title=title)
700 if dlg.ShowModal() == wx.ID_OK:
701 value = dlg.get_value()
702 if not self._empty_name(value):
703 creator_or_setter(value, dlg.get_comment())
704 elif on_empty:
705 on_empty()
706 self.update_data()
707 dlg.Destroy()
709 @staticmethod 1ab
710 def _empty_name(value): 1ab
711 return not value[0]
713 @staticmethod 1ab
714 def get_column_values(item): 1ab
715 return [item.type, item.name, item.display_value,
716 ListToStringFormatter(item.comment).value]
719class MetadataListEditor(_AbstractListEditor): 1ab
721 _buttons_nt = ['Add Metadata'] 1ab
722 _sortable = False 1ab
724 def __init__(self, parent, tree, controller): 1ab
725 self._titles = [_('Metadata'), _('Value'), _('Comment')]
726 self._buttons = [_('Add Metadata')]
727 _AbstractListEditor.__init__(self, parent, tree, controller)
729 def on_edit(self, event): 1ab
730 meta = self._controller[self._selection]
731 dlg = MetadataDialog(self._controller.datafile, item=meta)
732 if dlg.ShowModal() == wx.ID_OK:
733 meta.set_value(*dlg.get_value())
734 meta.set_comment(dlg.get_comment())
735 self.update_data()
736 dlg.Destroy()
738 def on_add_metadata(self, event): 1ab
739 __ = event
740 dlg = MetadataDialog(self._controller.datafile)
741 if dlg.ShowModal() == wx.ID_OK:
742 ctrl = self._controller.add_metadata(*dlg.get_value())
743 ctrl.set_comment(dlg.get_comment())
744 self.update_data()
745 dlg.Destroy()
747 @staticmethod 1ab
748 def get_column_values(item): 1ab
749 return [item.name, utils.html_escape(item.value),
750 ListToStringFormatter(item.comment).value]