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 textwrap 17import time 18 19from java.awt import Component 20from java.awt.event import WindowAdapter 21from javax.swing import (BoxLayout, JLabel, JOptionPane, JPanel, 22 JPasswordField, JTextField, JList, JScrollPane) 23from javax.swing.JOptionPane import (DEFAULT_OPTION, OK_CANCEL_OPTION, 24 OK_OPTION, PLAIN_MESSAGE, 25 UNINITIALIZED_VALUE, YES_NO_OPTION) 26 27from robot.utils import html_escape 28 29 30MAX_CHARS_PER_LINE = 120 31 32 33class _SwingDialog(object): 34 35 def __init__(self, pane): 36 self._pane = pane 37 38 def _create_panel(self, message, widget): 39 panel = JPanel() 40 panel.setLayout(BoxLayout(panel, BoxLayout.Y_AXIS)) 41 label = self._create_label(message) 42 label.setAlignmentX(Component.LEFT_ALIGNMENT) 43 panel.add(label) 44 widget.setAlignmentX(Component.LEFT_ALIGNMENT) 45 panel.add(widget) 46 return panel 47 48 def _create_label(self, message): 49 # JLabel doesn't support multiline text, setting size, or wrapping. 50 # Need to handle all that ourselves. Feels like 2005... 51 wrapper = textwrap.TextWrapper(MAX_CHARS_PER_LINE, 52 drop_whitespace=False) 53 lines = [] 54 for line in html_escape(message, linkify=False).splitlines(): 55 if line: 56 lines.extend(wrapper.wrap(line)) 57 else: 58 lines.append('') 59 return JLabel('<html>%s</html>' % '<br>'.join(lines)) 60 61 def show(self): 62 self._show_dialog(self._pane) 63 return self._get_value(self._pane) 64 65 def _show_dialog(self, pane): 66 dialog = pane.createDialog(None, 'Robot Framework') 67 dialog.setModal(False) 68 dialog.setAlwaysOnTop(True) 69 dialog.addWindowFocusListener(pane.focus_listener) 70 dialog.show() 71 while dialog.isShowing(): 72 time.sleep(0.2) 73 dialog.dispose() 74 75 def _get_value(self, pane): 76 value = pane.getInputValue() 77 return value if value != UNINITIALIZED_VALUE else None 78 79 80class MessageDialog(_SwingDialog): 81 82 def __init__(self, message): 83 pane = WrappedOptionPane(message, PLAIN_MESSAGE, DEFAULT_OPTION) 84 _SwingDialog.__init__(self, pane) 85 86 87class InputDialog(_SwingDialog): 88 89 def __init__(self, message, default, hidden=False): 90 self._input_field = JPasswordField() if hidden else JTextField() 91 self._input_field.setText(default) 92 self._input_field.selectAll() 93 panel = self._create_panel(message, self._input_field) 94 pane = WrappedOptionPane(panel, PLAIN_MESSAGE, OK_CANCEL_OPTION) 95 pane.set_focus_listener(self._input_field) 96 _SwingDialog.__init__(self, pane) 97 98 def _get_value(self, pane): 99 if pane.getValue() != OK_OPTION: 100 return None 101 return self._input_field.getText() 102 103 104class SelectionDialog(_SwingDialog): 105 106 def __init__(self, message, options): 107 pane = WrappedOptionPane(message, PLAIN_MESSAGE, OK_CANCEL_OPTION) 108 pane.setWantsInput(True) 109 pane.setSelectionValues(options) 110 _SwingDialog.__init__(self, pane) 111 112 113class MultipleSelectionDialog(_SwingDialog): 114 115 def __init__(self, message, options): 116 self._selection_list = JList(options) 117 self._selection_list.setVisibleRowCount(8) 118 panel = self._create_panel(message, JScrollPane(self._selection_list)) 119 pane = WrappedOptionPane(panel, PLAIN_MESSAGE, OK_CANCEL_OPTION) 120 _SwingDialog.__init__(self, pane) 121 122 def _get_value(self, pane): 123 if pane.getValue() != OK_OPTION: 124 return None 125 return list(self._selection_list.getSelectedValuesList()) 126 127 128class PassFailDialog(_SwingDialog): 129 130 def __init__(self, message): 131 pane = WrappedOptionPane(message, PLAIN_MESSAGE, YES_NO_OPTION, 132 None, ['PASS', 'FAIL'], 'PASS') 133 _SwingDialog.__init__(self, pane) 134 135 def _get_value(self, pane): 136 value = pane.getValue() 137 return value == 'PASS' if value in ['PASS', 'FAIL'] else None 138 139 140class WrappedOptionPane(JOptionPane): 141 focus_listener = None 142 143 def getMaxCharactersPerLineCount(self): 144 return MAX_CHARS_PER_LINE 145 146 def set_focus_listener(self, component): 147 self.focus_listener = WindowFocusListener(component) 148 149 150class WindowFocusListener(WindowAdapter): 151 152 def __init__(self, component): 153 self.component = component 154 155 def windowGainedFocus(self, event): 156 self.component.requestFocusInWindow() 157