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

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

18from wx import Colour 1ab

19 

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

38 

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

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

41 

42 

43class SettingEditor(wx.Panel): 1ab

44 popup_timer = None 1ab

45 

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) 

87 

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) 

106 

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) 

113 

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 

121 

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 

127 

128 def _get_tooltip(self): 1ab

129 return HtmlPopupWindow(self, (500, 350)) 

130 

131 def on_key(self, event): 1ab

132 try: 

133 self._tooltip.hide() 

134 except AttributeError: 

135 pass 

136 event.Skip() 

137 

138 def on_display_motion(self, event): 1ab

139 try: 

140 self._tooltip.hide() 

141 except AttributeError: 

142 pass 

143 

144 def refresh_values(self, controller): 1ab

145 self._controller = controller 

146 self.update_value() 

147 

148 def refresh_datafile(self, item, event): 1ab

149 self._tree.refresh_datafile(item, event) 

150 

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 

165 

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) 

169 

170 def _set_value(self, value_list, comment): 1ab

171 self._controller.execute(ctrlcommands.SetValues(value_list, comment)) 

172 

173 def _hide_tooltip(self): 1ab

174 self._stop_popup_timer() 

175 try: 

176 self._tooltip.hide() 

177 except AttributeError: 

178 pass 

179 

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() 

183 

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) 

187 

188 def _mainframe_has_focus(self): 1ab

189 return wx.GetTopLevelParent(self.FindFocus()) == \ 

190 wx.GetTopLevelParent(self) 

191 

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() 

199 

200 def on_leave_window(self, event): 1ab

201 self.on_window_destroy(event) 

202 

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()) 

217 

218 def _get_details_for_tooltip(self): 1ab

219 kw = self._controller.keyword_name 

220 return self.plugin.get_keyword_details(kw), kw 

221 

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 

227 

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() 

235 

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] 

241 

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) 

246 

247 def _update_and_notify(self): 1ab

248 self.update_value() 

249 

250 def on_clear(self, event): 1ab

251 __ = event 

252 self._controller.execute(ctrlcommands.ClearSetting()) 

253 self._update_and_notify() 

254 

255 def _ps_on_update_value(self, message): 1ab

256 _ = message 

257 self.update_value() 

258 

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() 

267 

268 def get_selected_datafile_controller(self): 1ab

269 return self._controller.datafile_controller 

270 

271 def close(self): 1ab

272 self._controller = None 

273 self.plugin.unsubscribe(self._ps_on_update_value, RideImportSetting) 

274 

275 def highlight(self, text): 1ab

276 return self._value_display.highlight(text) 

277 

278 def clear_highlight(self): 1ab

279 return self._value_display.clear_highlight() 

280 

281 def contains(self, text): 1ab

282 return self._value_display.contains(text) 

283 

284 

285class SettingValueDisplay(wx.TextCtrl, HtmlPopupWindow): 1ab

286 _is_user_keyword = False 1ab

287 _keyword_name = None 1ab

288 _value = None 1ab

289 

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() 

306 

307 def _empty_values(self): 1ab

308 self._value = None 

309 self._is_user_keyword = False 

310 

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() 

320 

321 def _colorize_data(self, match=None): 1ab

322 self._colorize_background(match) 

323 self._colorize_possible_user_keyword() 

324 

325 def _colorize_background(self, match=None): 1ab

326 self.SetBackgroundColour(self._get_background_colour(match)) 

327 

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) 

334 

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)) 

343 

344 def clear_field(self): 1ab

345 self.Clear() 

346 self._empty_values() 

347 self._colorize_background() 

348 

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)] != [] 

354 

355 def highlight(self, text): 1ab

356 self._colorize_data(match=text) 

357 

358 def clear_highlight(self): 1ab

359 self._colorize_data() 

360 

361 

362class DocumentationEditor(SettingEditor): 1ab

363 

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) 

367 

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 

375 

376 def update_value(self): 1ab

377 if self._controller: 

378 self._value_display.set_content(self._controller.visible_value) 

379 

380 def on_key(self, event): 1ab

381 event.Skip() 

382 

383 def on_display_motion(self, event): 1ab

384 """ Just ignoring it """ 

385 pass 

386 

387 def _hide_tooltip(self): 1ab

388 """ Just ignoring it """ 

389 pass 

390 

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) 

395 

396 def _set_value(self, value_list, comment): 1ab

397 if value_list: 

398 self._controller.execute(ctrlcommands.UpdateDocumentation(value_list[0])) 

399 

400 def contains(self, text): 1ab

401 return False 

402 

403 def highlight(self, text): 1ab

404 """ Just ignoring it """ 

405 pass 

406 

407 def clear_highlight(self): 1ab

408 """ Just ignoring it """ 

409 pass 

410 

411 

412class TagsEditor(SettingEditor): 1ab

413 

414 def __init__(self, parent, controller, plugin, tree): 1ab

415 SettingEditor.__init__(self, parent, controller, plugin, tree) 

416 self.plugin.subscribe(self._saving, RideSaving) 

417 

418 def _saving(self, message): 1ab

419 _ = message 

420 self._tags_display.saving() 

421 

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 

427 

428 def contains(self, text): 1ab

429 return False 

430 

431 def highlight(self, text): 1ab

432 """ Just ignoring it """ 

433 pass 

434 

435 def clear_highlight(self): 1ab

436 """ Just ignoring it """ 

437 pass 

438 

439 def close(self): 1ab

440 self._tags_display.close() 

441 self.plugin.unsubscribe(self._saving, RideSaving) 

442 SettingEditor.close(self) 

443 

444 

445class _AbstractListEditor(ListEditor): 1ab

446 _titles = [] 1ab

447 

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 

457 

458 def get_selected_datafile_controller(self): 1ab

459 return self._controller.datafile_controller 

460 

461 def refresh_datafile(self, item, event): 1ab

462 self._tree.refresh_datafile(item, event) 

463 

464 def update_data(self): 1ab

465 ListEditor.update_data(self) 

466 

467 def update_value(self): 1ab

468 """ Just ignoring it """ 

469 pass 

470 

471 def close(self): 1ab

472 """ Just ignoring it """ 

473 pass 

474 

475 def highlight(self, text, expand=False): 1ab

476 """ Just ignoring it """ 

477 pass 

478 

479 

480class VariablesListEditor(_AbstractListEditor): 1ab

481 _buttons_nt = ['Add Scalar', 'Add List', 'Add Dict'] 1ab

482 

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) 

494 

495 def _update_vars(self, message): 1ab

496 _ = message 

497 ListEditor.update_data(self) 

498 

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] 

505 

506 def on_move_up(self, event): 1ab

507 _AbstractListEditor.on_move_up(self, event) 

508 self._list.SetFocus() 

509 

510 def on_move_down(self, event): 1ab

511 _AbstractListEditor.on_move_down(self, event) 

512 self._list.SetFocus() 

513 

514 def on_add_scalar(self, event): 1ab

515 __ = event 

516 self._show_dialog( 

517 ScalarVariableDialog(self._controller)) 

518 

519 def on_add_list(self, event): 1ab

520 __ = event 

521 self._show_dialog( 

522 ListVariableDialog(self._controller, plugin=self.Parent.plugin)) 

523 

524 def on_add_dict(self, event): 1ab

525 __ = event 

526 self._show_dialog( 

527 DictionaryVariableDialog(self._controller, 

528 plugin=self.Parent.plugin)) 

529 

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() 

536 

537 def on_edit(self, event): 1ab

538 var = self._controller[self._selection] 

539 self._open_var_dialog(var) 

540 

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) 

545 

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() 

563 

564 def close(self): 1ab

565 PUBLISHER.unsubscribe_all(self) 

566 

567 

568class ImportSettingListEditor(_AbstractListEditor): 1ab

569 _buttons_nt = ['Library', 'Resource', 'Variables', 'Import Failed Help'] 1ab

570 

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)) 

584 

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 

603 

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() 

609 

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()) 

614 

615 def has_link_target(self, controller): 1ab

616 return controller.is_resource and controller.get_imported_controller() 

617 

618 def has_error(self, controller): 1ab

619 return controller.has_error() 

620 

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)) 

624 

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 

633 

634 @staticmethod 1ab

635 def on_import_library_spec_xml(event): 1ab

636 __ = event 

637 RideExecuteSpecXmlImport().publish() 

638 

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')) 

646 

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')) 

653 

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')) 

660 

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')) 

668 

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 

690 

691 def _import_failed_help_closed(self, event): 1ab

692 self._import_failed_shown = False 

693 event.Skip() 

694 

695 def _get_setting(self): 1ab

696 return self._controller[self._selection] 

697 

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() 

708 

709 @staticmethod 1ab

710 def _empty_name(value): 1ab

711 return not value[0] 

712 

713 @staticmethod 1ab

714 def get_column_values(item): 1ab

715 return [item.type, item.name, item.display_value, 

716 ListToStringFormatter(item.comment).value] 

717 

718 

719class MetadataListEditor(_AbstractListEditor): 1ab

720 

721 _buttons_nt = ['Add Metadata'] 1ab

722 _sortable = False 1ab

723 

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) 

728 

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() 

737 

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() 

746 

747 @staticmethod 1ab

748 def get_column_values(item): 1ab

749 return [item.name, utils.html_escape(item.value), 

750 ListToStringFormatter(item.comment).value]