class PayloadView: """ PayloadView is a TextView viewer and editor. """ def __init__(self, payload=None, texteditor_factory=None, editable=True): self._idx = 0 self._texteditor_factory = texteditor_factory self._textareas = {} self._widgets = {} self._listener = None self.this = JTabbedPane() self.this.setUI(SneakTabbedPaneUI(self.this)) if payload: self.refresh(payload) self.editable = editable self.set_editable(editable) def _get_textarea(self, element): """ Recursive search for a textarea in the components of a given supercomponent :param element: current widget. :return: None """ try: if 'getDocument' in dir(element) and 'append' in dir( element) and JTextArea in element.__class__.__mro__: return element for e in element.getComponents(): ret = self._get_textarea(e) if ret: return ret except: return None def _create_texteditor(self, name=None, label=None): _textarea = None if name and name in self._widgets: return self._widgets[name] if not name: name = "TextArea#%s" % self._idx self._idx += 1 this = JPanel() # Add a label if label: this.setLayout(BorderLayout()) this.add(BorderLayout.PAGE_START, JLabel(label)) if self._texteditor_factory: _texteditor = self._texteditor_factory() _component = _texteditor.getComponent() this.add(BorderLayout.CENTER, _component) _textarea = self._get_textarea(_component) if not _textarea: _textarea = JTextArea() _textarea.setColumns(20) _textarea.setRows(5) _textarea.setLineWrap(True) _textarea.setWrapStyleWord(True) _textarea.setEditable(True) _textarea.setName(name) _textarea.setSelectionColor(Color(255, 153, 51)) _textarea.requestFocus() # Add textarea to a scrollable JPane _scrollpane = JScrollPane() _scrollpane.setViewportView(_textarea) this.add(BorderLayout.CENTER, _scrollpane) _textarea.setEditable(self.editable) self._textareas[name] = _textarea self._widgets[name] = this def on_change(evt): if not self._textareas[name].hasFocus(): return try: if name == "raw": SwingUtilities.invokeLater(lambda: self._refresh_queries( self._textareas['raw'].getText())) elif name.startswith('gql_query#'): id = int(name.split("#")[1]) content = json.loads(self._textareas['raw'].getText()) if id == 0 and not isinstance(content, list): content['query'] = self._textareas[name].getText() else: content[id]['query'] = self._textareas[name].getText() SwingUtilities.invokeLater(lambda: self._textareas['raw']. setText(json.dumps(content))) elif name.startswith('gql_variables#'): id = int(name.split("#")[1]) content = json.loads(self._textareas['raw'].getText()) if id == 0 and not isinstance(content, list): content['variables'] = json.loads( self._textareas[name].getText()) else: content[id]['variables'] = json.loads( self._textareas[name].getText()) SwingUtilities.invokeLater(lambda: self._textareas['raw']. setText(json.dumps(content))) except ValueError: pass # Avoid crashing for JSON not valid incompatibilities _textarea.getDocument().addDocumentListener( _PayloadListener(changed_update=on_change)) return this def set_editable(self, editable): """ Enable or Disable the editable textview :param editable: boolean parameter representing the editability :return: None """ self.editable = editable for t in self._textareas.values(): t.setEditable(editable) def _graphql_queries(self, payload): try: content = json.loads(payload) if not isinstance(content, list): content = [content] q = {} for i in range(0, len(content)): if any([ 'query' in content[i] and content[i]['query'].strip().startswith(qtype) for qtype in ['query', 'mutation', 'subscription', '{'] ]): q[i] = content[i] return q except ValueError: return None def _refresh_raw(self, payload): """ Refresh the textarea content with a new payload, if present :param payload: :return: None """ if payload: self.this.addTab("Raw", self._create_texteditor(name="raw", label='Raw')) self._textareas['raw'].setText(payload) if self._listener: self.add_listener(self._listener) inherits_popup_menu(self.this) def _get_tab_component_by_name(self, name): for i in range(0, self.this.getTabCount()): if self.this.getTitleAt(i) == name: return self.this.getComponentAt(i) return None def _get_tab_index_by_name(self, name): for i in range(0, self.this.getTabCount()): if self.this.getTitleAt(i) == name: return i return -1 def _refresh_queries(self, payload): """ Refresh the textarea content with a new payload, if present :param payload: :return: None """ graphql_tabs = [] for i in range(0, self.this.getTabCount()): if self.this.getTitleAt(i).startswith("GraphQL #"): graphql_tabs.append(self.this.getTitleAt(i)) if payload: # Check if the payload contains a GraphQL query object queries = self._graphql_queries(payload) if queries: # Generate and append GraphQL tab to the tabs for query_key in queries.keys(): qname = "gql_query#%s" % query_key vname = "gql_variables#%s" % query_key tname = "GraphQL #%s" % query_key queryeditor = self._create_texteditor(name=qname, label="Query:") self._textareas[qname].setText(queries[query_key]['query']) variableseditor = self._create_texteditor( name=vname, label="Variables:") this = self._get_tab_component_by_name(tname) if tname in graphql_tabs: graphql_tabs.remove(tname) if not this: this = JSplitPane(JSplitPane.VERTICAL_SPLIT, queryeditor, variableseditor) self.this.addTab(tname, this) this.setOneTouchExpandable(True) this.setDividerLocation(0.66) if 'variables' in queries[query_key]: this.getBottomComponent().setVisible(True) self._textareas[vname].setText( json.dumps(queries[query_key]['variables'], indent=4)) else: this.getBottomComponent().setVisible(False) self._textareas[vname].setText("{}") # Remove empty graphql tabs try: for tab in graphql_tabs: for i in range(0, self.this.getTabCount()): if self.this.getTitleAt(i) == tab: self.this.remove(i) except: # Do nothing if you cannot remove an entry pass inherits_popup_menu(self.this) def refresh(self, payload): """ Refresh the textarea content with a new payload, if present :param payload: :return: None """ self._refresh_queries(payload) self._refresh_raw(payload) inherits_popup_menu(self.this) def textarea(self): return self._textareas['raw'] def add_listener(self, listener): """ add a new listener to the textarea :param listener: this parameter should be a lambda or a method :return: None """ self._listener = listener if 'raw' in self._textareas: self._textareas['raw'].getDocument().addDocumentListener( _PayloadListener(listener))
class WSAShelp_09(java.lang.Runnable): #--------------------------------------------------------------------------- # Name: __init__() # Role: Class constructor #--------------------------------------------------------------------------- def __init__(self): #----------------------------------------------------------------------- # Painter instance used to highlight text # Note: See hilightTextPane() #----------------------------------------------------------------------- self.painter = DefaultHighlighter.DefaultHighlightPainter(Color.YELLOW) #----------------------------------------------------------------------- # Input field containing the text to be highlighted #----------------------------------------------------------------------- self.textField = JTextField('') #----------------------------------------------------------------------- # Dictionary, indexed by tab name, with info about tab contents #----------------------------------------------------------------------- self.tPanes = {} #----------------------------------------------------------------------- # Tabbed Pane for information to be displayed #----------------------------------------------------------------------- self.tabs = JTabbedPane(stateChanged=self.tabPicked) #--------------------------------------------------------------------------- # Name: TBD() # Role: Indicate work that needs To Be Done #--------------------------------------------------------------------------- def TBD(self, event): JOptionPane.showMessageDialog(self.frame, 'Not yet implemented', 'TBD', JOptionPane.PLAIN_MESSAGE) #--------------------------------------------------------------------------- # Name: about() # Role: Used to display information about the script / application # Note: One way to display the script docstring (i.e., __doc__) as it # appears is to use <html> text. # Note: The first character (i.e., [ 0 ]) is a newline, and is ignored #--------------------------------------------------------------------------- def about(self, event): message = __doc__[1:].replace(' ', ' ') message = message.replace('<', '<') message = message.replace('>', '>') message = message.replace('\n', '<br>') message = '<html>' + message message = JLabel(message, font=monoFont) JOptionPane.showMessageDialog(self.frame, message, 'About', JOptionPane.PLAIN_MESSAGE) #--------------------------------------------------------------------------- # Name: center() # Role: Position the frame in the center of the screen # Note: The frame isn't allowed to be wider than 1/2 the screen width, or # more than 1/2 the screen height. It is resized, if necessary. # Note: The value of 640 is used to keep the AdminTask.help() text from # wrapping #--------------------------------------------------------------------------- def center(self, frame): screenSize = Toolkit.getDefaultToolkit().getScreenSize() frameSize = frame.getSize() frameSize.width = min(frameSize.width, screenSize.width >> 1) frameSize.width = max(frameSize.width, 640) frameSize.height = min(frameSize.height, screenSize.height >> 1) if frameSize != frame.getSize(): frame.setSize(frameSize) frame.setLocation((screenSize.width - frameSize.width) >> 1, (screenSize.height - frameSize.height) >> 1) #--------------------------------------------------------------------------- # Name: Exit() # Role: ActionListener event handler called when user selects Show -> Exit #--------------------------------------------------------------------------- def Exit(self, event): sys.exit() #--------------------------------------------------------------------------- # Name: frameResized() # Role: Component Listener event handler for the componentResized event #--------------------------------------------------------------------------- def frameResized(self, ce): try: index = self.tabs.getSelectedIndex() name = self.tabs.getTitleAt(index) if len(self.tPanes[name]) > 1: table, rowHeight, w0, w1 = self.tPanes[name][1:] width = table.getParent().getExtentSize().getWidth() tcm = table.getColumnModel() # Table Column Model margin = tcm.getColumnMargin() # gap between columns if w0 + w1 + 2 * margin > width: table.setRowHeight(rowHeight * 3) c0 = int(round(width * .23)) c1 = int(width - c0 - margin) else: table.setRowHeight(rowHeight) c0 = w0 + margin c1 = int(width - c0 - margin) tcr = table.getCellRenderer(0, 0) tcr.setWidths(c0, c1) tcr.setHiText(self.textField.getText()) tcm.getColumn(0).setPreferredWidth(c0) tcm.getColumn(1).setPreferredWidth(c1) #------------------------------------------------------------------- # Redraw the table using the new column widths and row heights #------------------------------------------------------------------- table.repaint() except: print '\nError: %s\nvalue: %s' % sys.exc_info()[:2] #--------------------------------------------------------------------------- # Name: hilightText() # Role: Event handler called by Show -> Highlight Text #--------------------------------------------------------------------------- def hilightText(self, event): result = JOptionPane.showInputDialog( self.frame, # parentComponent 'What text do you want to highlight?' # message text ) if result != None: self.textField.setText(result) index = self.tabs.getSelectedIndex() name = self.tabs.getTitleAt(index) self.hilightTextPane(self.tPanes[name][0], result) if len(self.tPanes[name]) > 1: table = self.tPanes[name][1] table.getCellRenderer(0, 0).setHiText(result) table.repaint() #--------------------------------------------------------------------------- # Name: hilightTextPane() # Role: Find, and highlight every occurrance of text on specified JTextPane #--------------------------------------------------------------------------- def hilightTextPane(self, tPane, text): hiliter = tPane.getHighlighter() hiliter.removeAllHighlights() if text: doc = tPane.getDocument() info = doc.getText(0, doc.getLength()) start = 0 here = info.find(text, start) while here > -1: hiliter.addHighlight(here, here + len(text), self.painter) start = here + len(text) here = info.find(text, start) #--------------------------------------------------------------------------- # Name: MenuBar() # Role: Create the application menu bar #--------------------------------------------------------------------------- def MenuBar(self): #----------------------------------------------------------------------- # Start by creating our application menubar #----------------------------------------------------------------------- menu = JMenuBar() #----------------------------------------------------------------------- # "Show" entry #----------------------------------------------------------------------- show = JMenu('Show') show.add(JMenuItem('Highlight text', actionPerformed=self.hilightText)) show.add(JSeparator()) show.add(JMenuItem('Exit', actionPerformed=self.Exit)) menu.add(show) #----------------------------------------------------------------------- # "Help" entry #----------------------------------------------------------------------- help = JMenu('Help') help.add(JMenuItem('About', actionPerformed=self.about)) help.add(JMenuItem('Notice', actionPerformed=self.notice)) menu.add(help) return menu #--------------------------------------------------------------------------- # Name: notice() # Role: Used to display important information #--------------------------------------------------------------------------- def notice(self, event): JOptionPane.showMessageDialog( self.frame, Disclaimer, 'Notice', # Previously "Disclaimer" JOptionPane.WARNING_MESSAGE) #--------------------------------------------------------------------------- # Name: run() # Role: Instantiate the user class # Note: Invoked by the Swing Event Dispatch Thread #--------------------------------------------------------------------------- def run(self): self.frame = frame = JFrame('WSAShelp_09', layout=BorderLayout(), componentResized=self.frameResized, defaultCloseOperation=JFrame.EXIT_ON_CLOSE) #----------------------------------------------------------------------- # RegExp used to locate method names #----------------------------------------------------------------------- methRE = re.compile(r'^(\w+)(?:\s+.*)$', re.MULTILINE) #----------------------------------------------------------------------- # Add our menu bar to the frame #----------------------------------------------------------------------- frame.setJMenuBar(self.MenuBar()) #----------------------------------------------------------------------- # Create & Populate the JTabbedPane #----------------------------------------------------------------------- WASobjs = [ ('wsadmin', None), # Special case ('Help', Help), ('AdminApp', AdminApp), ('AdminConfig', AdminConfig), ('AdminControl', AdminControl), ('AdminTask', AdminTask) ] tabs = self.tabs for name, WASobj in WASobjs: #------------------------------------------------------------------- # Use a single ScrollPane for the AdminTask help #------------------------------------------------------------------- if name in ['wsadmin', 'AdminTask']: if WASobj: data = WASobj.help().expandtabs() else: data = Help.wsadmin().expandtabs() pane = JTextPane(text=data, editable=0, font=monoFont) #--------------------------------------------------------------- # Move the caret to ensure that the starting text is shown #--------------------------------------------------------------- pane.moveCaretPosition(0) tabs.addTab(name, JScrollPane(pane)) self.tPanes[name] = [pane] else: #--------------------------------------------------------------- # Use a RegExp to identify where the 1st method starts. #--------------------------------------------------------------- text = WASobj.help().expandtabs() mo = re.search(methRE, text) # Match Object desc = text[:mo.start(1)].strip() meth = text[mo.start(1):].strip() #--------------------------------------------------------------- # The description section is before the 1st method #--------------------------------------------------------------- topPane = JTextPane(text=desc, editable=0, font=monoFont) topPane.moveCaretPosition(0) top = JScrollPane(topPane) #--------------------------------------------------------------- # For the other scripting objects, use a vertically split pane # with the top containing the description section, and the # bottom (eventually) containing the method details. #--------------------------------------------------------------- splitPane = JSplitPane( JSplitPane.VERTICAL_SPLIT, top, JLabel('One moment please...'), resizeWeight=0.5, # divider position = 50% oneTouchExpandable=1) #--------------------------------------------------------------- # Start a separate thread to parse the method text and build a # a JTable to be put into the bottom part of this splitPane #--------------------------------------------------------------- self.tPanes[name] = [topPane] tableTask( meth, # Help text to be parsed / processed splitPane, # SplitPane to be updated self.tPanes[name], # tPanes entry to be updated WASobj # WAS scripting object ).execute() tabs.addTab(name, splitPane) #----------------------------------------------------------------------- # Add the tabbed pane to the frame & show the result #----------------------------------------------------------------------- frame.add(tabs, 'Center') frame.pack() self.center(frame) frame.setVisible(1) #--------------------------------------------------------------------------- # Name: tabPicked() # Role: ChangeListener event handler - called when a tab is selected #--------------------------------------------------------------------------- def tabPicked(self, event): pane = event.getSource() index = pane.getSelectedIndex() name = pane.getTitleAt(index) try: tPane = self.tPanes[name][0] tPane.select(0, 0) hiText = self.textField.getText() self.hilightTextPane(tPane, hiText) if len(self.tPanes[name]) > 1: table, rowHeight, w0, w1 = self.tPanes[name][1:] #--------------------------------------------------------------- # Viewport width & preferred width for column 0 #--------------------------------------------------------------- width = table.getParent().getExtentSize().getWidth() tcm = table.getColumnModel() # Table Column Model margin = tcm.getColumnMargin() # gap between columns if w0 + w1 + 2 * margin > width: table.setRowHeight(rowHeight * 3) c0 = int(round(width * .23)) c1 = int(width - c0 - margin) else: table.setRowHeight(rowHeight) c0 = w0 + margin c1 = int(width - c0 - margin) tcr = table.getCellRenderer(0, 0) tcr.setWidths(c0, c1) tcr.setHiText(hiText) tcm.getColumn(0).setPreferredWidth(c0) tcm.getColumn(1).setPreferredWidth(c1) except: Type, value = sys.exc_info()[:2] Type, value = str(Type), str(value) if not (Type.endswith('KeyError') and value == 'wsadmin'): print '\nError: %s\nvalue: %s' % (Type, value)