def addCenterPane(self, atfAreaView, consoleView): splitPane = JSplitPane(JSplitPane.VERTICAL_SPLIT) splitPane.setTopComponent(atfAreaView) splitPane.setBottomComponent(consoleView) splitPane.setDividerSize(5) self.getContentPane().add(splitPane, BorderLayout.CENTER) # Make console's high remain smaller compared to edit area splitPane.setResizeWeight(0.9)
class AtfAreaView(JPanel): ''' Initializes the ATF (edit/model) view and sets its layout. ''' def __init__(self, controller): ''' Creates default empty text area in a panel for ATF edition. It has syntax highlighting based on the ATF parser (pyoracc). It also highlights line numbers where there are validations errors returned by the ORACC server. ''' # Give reference to controller to delegate action response self.controller = controller # Make text area occupy all available space and resize with parent # window self.setLayout(BorderLayout()) # Short hand for edit area and line numbers area self.edit_area = self.controller.edit_area self.line_numbers_area = self.controller.line_numbers_area # Create secondary text area for split view self.secondary_area = self.controller.secondary_area self.secondary_line_numbers = self.controller.secondary_line_numbers # Set undo/redo manager to edit area self.undo_manager = UndoManager() self.undo_manager.limit = 3000 self.edit_listener = AtfUndoableEditListener(self.undo_manager) self.edit_area.getDocument().addUndoableEditListener( self.edit_listener) # Sort out layout by synch-ing line numbers and text area and putting # only the text area in a scroll pane as indicated in the # TextLineNumber tutorial. self.edit_area.setPreferredSize(Dimension(1, 500)) self.container = JScrollPane(self.edit_area) self.container.setRowHeaderView(self.line_numbers_area) self.add(self.container, BorderLayout.CENTER) # Key listener that triggers syntax highlighting, etc. upon key release self.edit_area.addKeyListener(AtfAreaKeyListener(self.controller)) # Also needed in secondary area: self.secondary_area.addKeyListener(AtfAreaKeyListener(self.controller)) def toggle_split(self, split_orientation=None): ''' Clear ATF edit area and repaint chosen layout (splitscreen/scrollpane). ''' # Remove all existent components in parent JPanel self.removeAll() # Check what editor view to toggle self.setup_edit_area(split_orientation) # Revalitate is needed in order to repaint the components self.revalidate() self.repaint() def setup_edit_area(self, split_orientation=None): ''' Check if the ATF text area is being displayed in a split editor. If so, resets to normal JScrollPane. If not, splits the screen. ''' if isinstance(self.container, JSplitPane): # If Nammu is already displaying a split pane, reset to original # setup self.container = JScrollPane(self.edit_area) self.container.setRowHeaderView(self.line_numbers_area) self.container.setVisible(True) self.add(self.container, BorderLayout.CENTER) else: # If there is not a split pane, create both panels and setup view main_editor = JScrollPane(self.edit_area) main_editor.setRowHeaderView(self.line_numbers_area) secondary_editor = JScrollPane(self.secondary_area) secondary_editor.setRowHeaderView(self.secondary_line_numbers) self.container = JSplitPane(split_orientation, main_editor, secondary_editor) self.container.setDividerSize(5) self.container.setVisible(True) self.container.setDividerLocation(0.5) self.container.setResizeWeight(0.5) self.add(self.container, BorderLayout.CENTER)
class BurpExtender(IBurpExtender, ITab, IExtensionStateListener): # Define the global variables for the burp plugin EXTENSION_NAME = "UPnP BHunter" ipv4_selected = True services_dict = {} ip_service_dict = {} STOP_THREAD = False #Some SSDP m-search parameters are based upon "UPnP Device Architecture v2.0" SSDP_MULTICAST_IPv4 = ["239.255.255.250"] SSDP_MULTICAST_IPv6 = ["FF02::C", "FF05::C"] SSDP_MULTICAST_PORT = 1900 ST_ALL = "ssdp:all" ST_ROOTDEV = "upnp:rootdevice" PLACEHOLDER = "FUZZ_HERE" SSDP_TIMEOUT = 2 def registerExtenderCallbacks(self, callbacks): # Get a reference to callbacks object self.callbacks = callbacks # Get the useful extension helpers object self.helpers = callbacks.getHelpers() # Set the extension name self.callbacks.setExtensionName(self.EXTENSION_NAME) self.callbacks.registerExtensionStateListener(self) # Draw plugin user interface self.drawPluginUI() self.callbacks.addSuiteTab(self) # Plugin loading message print("[+] Burp plugin UPnP BHunter loaded successfully") return def drawPluginUI(self): # Create the plugin user interface self.pluginTab = JPanel() self.uiTitle = JLabel('UPnP BHunter Load, Aim and Fire Console') self.uiTitle.setFont(Font('Tahoma', Font.BOLD, 14)) self.uiTitle.setForeground(Color(250, 100, 0)) self.uiPanelA = JSplitPane(JSplitPane.VERTICAL_SPLIT) self.uiPanelA.setMaximumSize(Dimension(2500, 1000)) self.uiPanelA.setDividerSize(2) self.uiPanelB = JSplitPane(JSplitPane.VERTICAL_SPLIT) self.uiPanelB.setDividerSize(2) self.uiPanelA.setBottomComponent(self.uiPanelB) self.uiPanelA.setBorder(BorderFactory.createLineBorder(Color.gray)) # Create and configure labels and text fields self.labeltitle_step1 = JLabel("[1st STEP] Discover UPnP Locations") self.labeltitle_step1.setFont(Font('Tahoma', Font.BOLD, 14)) self.labeltitle_step2 = JLabel( "[2nd STEP] Select a UPnP Service and Action") self.labeltitle_step2.setFont(Font('Tahoma', Font.BOLD, 14)) self.labeltitle_step3 = JLabel("[3rd STEP] Time to Attack it") self.labeltitle_step3.setFont(Font('Tahoma', Font.BOLD, 14)) self.labelsubtitle_step1 = JLabel( "Specify the IP version address in scope and start UPnP discovery") self.labelsubtitle_step2 = JLabel( "Select which of the found UPnP services will be probed") self.labelsubtitle_step3 = JLabel( "Review and modify the request, then send it to one of the attack tools" ) self.label_step1 = JLabel("Target IP") self.label_step2 = JLabel("Found UPnp Services") self.labelstatus = JLabel(" Status") self.labelempty_step1 = JLabel(" ") self.labelempty_step2 = JLabel(" ") self.labelupnp = JLabel("UPnP list") self.labelip = JLabel("IP list") self.labelactions = JLabel("Actions") self.labelNoneServiceFound = JLabel(" ") self.labelNoneServiceFound.setFont(Font('Tahoma', Font.BOLD, 12)) self.labelNoneServiceFound.setForeground(Color.red) # Create combobox for IP version selection self.ip_versions = ["IPv4", "IPv6"] self.combo_ipversion = JComboBox(self.ip_versions) self.combo_ipversion.setSelectedIndex(0) self.combo_ipversion.setEnabled(True) # Create and configure progress bar self.progressbar = JProgressBar(0, 100) self.progressbar.setString("Ready") self.progressbar.setStringPainted(True) # Create and configure buttons self.startbutton = JButton("Start Discovery", actionPerformed=self.startHunting) self.clearbutton = JButton("Clear All", actionPerformed=self.clearAll) self.intruderbutton = JButton("Send to Intruder", actionPerformed=self.sendToIntruder) self.repeaterbutton = JButton("Send to Repeater", actionPerformed=self.sendToRepeater) #self.WANrepeaterbutton = JButton("to Repeater", actionPerformed=self.sendWANUPnPToRepeater) self.textarea_request = JTextArea(18, 90) self.intruderbutton.setEnabled(False) self.repeaterbutton.setEnabled(False) # Class neeeded to handle the target combobox in second step panel class TargetComboboxListener(ActionListener): def __init__(self, upnpcombo_targets, upnpcombo_services, ip_service_dict): self.upnpcombo_targets = upnpcombo_targets self.upnpcombo_services = upnpcombo_services self.ip_service_dict = ip_service_dict def actionPerformed(self, event): try: # Update the location url combobox depending on the IP combobox selected_target = self.upnpcombo_targets.getSelectedItem() if self.ip_service_dict and selected_target: self.upnpcombo_services.removeAllItems() for service_url in self.ip_service_dict[ selected_target]: self.upnpcombo_services.addItem(service_url) self.upnpcombo_services.setSelectedIndex(0) except BaseException as e: print("[!] Exception selecting service: \"%s\" ") % e # Class neeeded to handle the service combobox in second step panel class ServiceComboboxListener(ActionListener): def __init__(self, upnpcombo_services, upnpcombo_actions, services_dict): self.upnpcombo_services = upnpcombo_services self.upnpcombo_actions = upnpcombo_actions self.services = services_dict def actionPerformed(self, event): try: # Update the location url combobox depending on the IP combobox selected_service = self.upnpcombo_services.getSelectedItem( ) if self.services and selected_service: self.upnpcombo_actions.removeAllItems() actions = self.services[selected_service] for action in actions: self.upnpcombo_actions.addItem(action) self.upnpcombo_actions.setSelectedIndex(0) except BaseException as e: print("[!] Exception selecting service: \"%s\" ") % e # Class neeeded to handle the action combobox in second step panel class ActionComboboxListener(ActionListener): def __init__(self, upnpcombo_services, upnpcombo_actions, textarea_request, services_dict): self.upnpcombo_services = upnpcombo_services self.upnpcombo_actions = upnpcombo_actions self.textarea_request = textarea_request self.services = services_dict def actionPerformed(self, event): try: # Update the location url combobox depending on the IP combobox selected_action = self.upnpcombo_actions.getSelectedItem() selected_service = self.upnpcombo_services.getSelectedItem( ) if self.services and selected_action: self.textarea_request.setText( self.services[selected_service][selected_action]) except BaseException as e: print("[!] Exception selecting action: \"%s\" ") % e self.upnpactions = [" "] self.upnpcombo_actions = JComboBox(self.upnpactions) self.upnpcombo_actions.setSelectedIndex(0) self.upnpcombo_actions.setEnabled(False) # Create the combo box, select item at index 0 (first item in list) self.upnpservices = [" "] self.upnpcombo_services = JComboBox(self.upnpservices) self.upnpcombo_services.setSelectedIndex(0) self.upnpcombo_services.setEnabled(False) # Create the combo box, select item at index 0 (first item in list) self.upnptargets = [" "] self.upnpcombo_targets = JComboBox(self.upnptargets) self.upnpcombo_targets.setSelectedIndex(0) self.upnpcombo_targets.setEnabled(False) # Set the action listeners for all the comboboxes self.upnpcombo_targets.addActionListener( TargetComboboxListener(self.upnpcombo_targets, self.upnpcombo_services, self.ip_service_dict)) self.upnpcombo_services.addActionListener( ServiceComboboxListener(self.upnpcombo_services, self.upnpcombo_actions, self.services_dict)) self.upnpcombo_actions.addActionListener( ActionComboboxListener(self.upnpcombo_services, self.upnpcombo_actions, self.textarea_request, self.services_dict)) # Configuring first step panel self.panel_step1 = JPanel() self.panel_step1.setPreferredSize(Dimension(2250, 100)) self.panel_step1.setBorder(EmptyBorder(10, 10, 10, 10)) self.panel_step1.setLayout(BorderLayout(15, 15)) self.titlepanel_step1 = JPanel() self.titlepanel_step1.setLayout(BorderLayout()) self.titlepanel_step1.add(self.labeltitle_step1, BorderLayout.NORTH) self.titlepanel_step1.add(self.labelsubtitle_step1) self.targetpanel_step1 = JPanel() self.targetpanel_step1.add(self.label_step1) self.targetpanel_step1.add(self.combo_ipversion) self.targetpanel_step1.add(self.startbutton) self.targetpanel_step1.add(self.clearbutton) self.targetpanel_step1.add(self.labelstatus) self.targetpanel_step1.add(self.progressbar) self.emptypanel_step1 = JPanel() self.emptypanel_step1.setLayout(BorderLayout()) self.emptypanel_step1.add(self.labelempty_step1, BorderLayout.WEST) # Assembling first step panel components self.panel_step1.add(self.titlepanel_step1, BorderLayout.NORTH) self.panel_step1.add(self.targetpanel_step1, BorderLayout.WEST) self.panel_step1.add(self.emptypanel_step1, BorderLayout.SOUTH) self.uiPanelA.setTopComponent(self.panel_step1) # Configure second step panel self.panel_step2 = JPanel() self.panel_step2.setPreferredSize(Dimension(2250, 100)) self.panel_step2.setBorder(EmptyBorder(10, 10, 10, 10)) self.panel_step2.setLayout(BorderLayout(15, 15)) self.titlepanel_step2 = JPanel() self.titlepanel_step2.setLayout(BorderLayout()) self.titlepanel_step2.add(self.labeltitle_step2, BorderLayout.NORTH) self.titlepanel_step2.add(self.labelsubtitle_step2) self.selectpanel_step2 = JPanel() self.selectpanel_step2.add(self.labelip) self.selectpanel_step2.add(self.upnpcombo_targets) self.selectpanel_step2.add(self.labelupnp) self.selectpanel_step2.add(self.upnpcombo_services) self.selectpanel_step2.add(self.labelactions) self.selectpanel_step2.add(self.upnpcombo_actions) self.emptypanel_step2 = JPanel() self.emptypanel_step2.setLayout(BorderLayout()) self.emptypanel_step2.add(self.labelempty_step2, BorderLayout.WEST) self.emptypanel_step2.add(self.labelNoneServiceFound) # Assembling second step panel components self.panel_step2.add(self.titlepanel_step2, BorderLayout.NORTH) self.panel_step2.add(self.selectpanel_step2, BorderLayout.WEST) self.panel_step2.add(self.emptypanel_step2, BorderLayout.SOUTH) self.uiPanelB.setTopComponent(self.panel_step2) # Configuring third step panel self.panel_step3 = JPanel() self.panel_step3.setPreferredSize(Dimension(2250, 100)) self.panel_step3.setBorder(EmptyBorder(10, 10, 10, 10)) self.panel_step3.setLayout(BorderLayout(15, 15)) self.titlepanel_step3 = JPanel() self.titlepanel_step3.setLayout(BorderLayout()) self.titlepanel_step3.add(self.labeltitle_step3, BorderLayout.NORTH) self.titlepanel_step3.add(self.labelsubtitle_step3) self.underpanel_step3 = JPanel() self.underpanel_step3.setLayout(BorderLayout()) self.underpanel_step3.add((JScrollPane(self.textarea_request)), BorderLayout.NORTH) self.actionpanel_step3 = JPanel() self.actionpanel_step3.add(self.intruderbutton) self.actionpanel_step3.add(self.repeaterbutton) self.extrapanel_step3 = JPanel() self.extrapanel_step3.setLayout(BorderLayout()) self.extrapanel_step3.add(self.actionpanel_step3, BorderLayout.WEST) # Assembling thirdd step panel components self.panel_step3.add(self.titlepanel_step3, BorderLayout.NORTH) self.panel_step3.add(self.underpanel_step3, BorderLayout.WEST) self.panel_step3.add(self.extrapanel_step3, BorderLayout.SOUTH) self.uiPanelB.setBottomComponent(self.panel_step3) # Assembling the group of all panels layout = GroupLayout(self.pluginTab) self.pluginTab.setLayout(layout) layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING).addGroup( layout.createSequentialGroup().addGap(10, 10, 10).addGroup( layout.createParallelGroup( GroupLayout.Alignment.LEADING).addComponent( self.uiTitle).addGap(15, 15, 15).addComponent( self.uiPanelA)).addContainerGap( 26, Short.MAX_VALUE))) layout.setVerticalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING).addGroup( layout.createSequentialGroup().addGap(15, 15, 15).addComponent( self.uiTitle).addGap(15, 15, 15).addComponent( self.uiPanelA).addGap(20, 20, 20).addGap(20, 20, 20))) def extensionUnloaded(self): # Unload the plugin, and if running stop the background thread if self.upnpcombo_services.isEnabled(): if self.th.isAlive(): print("[+] Stopping thread %s") % self.th.getName() self.STOP_THREAD = True self.th.join() else: print("Thread %s already dead") % self.th.getName() print("[+] Burp plugin UPnP BHunter successfully unloaded") return def getTabCaption(self): return self.EXTENSION_NAME def getUiComponent(self): return self.pluginTab def clearAll(self, e=None): # Reset all data of the plugin self.services_dict.clear() self.progressbar.setString("Ready") self.progressbar.setValue(0) self.upnpcombo_targets.removeAllItems() self.upnpcombo_targets.setEnabled(False) self.upnpcombo_services.removeAllItems() self.upnpcombo_services.setEnabled(False) self.upnpcombo_actions.removeAllItems() self.upnpcombo_actions.setEnabled(False) self.intruderbutton.setEnabled(False) self.repeaterbutton.setEnabled(False) self.labelNoneServiceFound.setText(" ") self.textarea_request.setText(" ") print("[+] Clearing all data") return def startHunting(self, e=None): # Starting the UPnP hunt def startHunting_run(): # Initialize the internal parameters every time the start-discovery button is clicked self.services_dict.clear() found_loc = [] discovery_files = [] self.labelNoneServiceFound.setText(" ") self.intruderbutton.setEnabled(False) self.repeaterbutton.setEnabled(False) # Then determine if targerting IPv4 or IPv6 adresses if self.combo_ipversion.getSelectedItem() == "IPv4": self.ipv4_selected = True print("[+] Selected IPv4 address scope") else: self.ipv4_selected = False print("[+] Selected IPv6 address scope") # And here finally the hunt could start self.progressbar.setString("Running...") self.progressbar.setValue(20) found_loc = self.discoverUpnpLocations() self.progressbar.setValue(40) discovery_files = self.downloadXMLfiles(found_loc) self.progressbar.setValue(60) self.buildSOAPs(discovery_files) self.progressbar.setValue(80) self.progressbar.setString("Done") self.progressbar.setValue(100) self.updateComboboxList(self.services_dict) # Update the comboboxes list with the discovered UPnPs if (self.services_dict): self.upnpcombo_targets.setEnabled(True) self.upnpcombo_services.setEnabled(True) self.upnpcombo_actions.setEnabled(True) self.intruderbutton.setEnabled(True) self.repeaterbutton.setEnabled(True) if self.STOP_THREAD: return # Start a background thread to run the above nested function in order to prevent the blocking of plugin UI self.th = threading.Thread(target=startHunting_run) #self.th.daemon = True # This does not seem to be useful self.th.setName("th-BHunter") self.th.start() def ssdpReqBuilder(self, ssdp_timeout, st_type, ssdp_ip, ssdp_port): # Builder of the two ssdp msearch request types msearch_req = "M-SEARCH * HTTP/1.1\r\n" \ "HOST: {0}:{1}\r\n" \ "MAN: \"ssdp:discover\"\r\n" \ "MX: {2}\r\n" \ "ST: {3}\r\n" \ "\r\n" \ .format(ssdp_ip, ssdp_port, ssdp_timeout, st_type) return msearch_req def sendMsearch(self, ssdp_req, ssdp_ip, ssdp_port): # Send the ssdp request and retrieve response buf_resp = set() if self.ipv4_selected: print("[+] Creating IPv4 SSDP multicast request") sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) else: print("[+] Creating IPv6 SSDP multicast request") sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) sock.setblocking(0) # Sending ssdp requests while len(ssdp_req): # Blocking socket client until the request is completely sent try: sent = sock.sendto(ssdp_req.encode("ASCII"), (ssdp_ip, ssdp_port)) ssdp_req = ssdp_req[sent:] except socket.error, exc: if exc.errno != errno.EAGAIN: print("[E] Got error %s with socket when sending") % exc sock.close() raise exc print("[!] Blocking socket until ", len(ssdp_req), " is sent.") select.select([], [sock], []) continue # Retrieving ssdp responses num_resp = 0 while sock: # Blocking socket until there are ssdp responses to be read or timeout is reached readable, __, __ = select.select([sock], [], [], self.SSDP_TIMEOUT) if not readable: # Timeout reached without receiving any ssdp response if num_resp == 0: print( "[!] Got timeout without receiving any ssdp response.") break else: num_resp = num_resp + 1 # Almost an ssdp response was received if readable[0]: try: data = sock.recv(1024) if data: buf_resp.add(data.decode('ASCII')) except socket.error, exc: print("[E] Got error %s with socket when receiving" ) % exc sock.close() raise exc
class SplitPane5( java.lang.Runnable ) : #--------------------------------------------------------------------------- # Name: run() # Role: Instantiate the user class # Note: Invoked by the Swing Event Dispatch Thread #--------------------------------------------------------------------------- def run( self ) : frame = JFrame( 'SplitPane5', defaultCloseOperation = JFrame.EXIT_ON_CLOSE ) self.sp = JSplitPane( JSplitPane.VERTICAL_SPLIT, self.sizeOptions(), JButton( 'Bottom' ) ) # print '\nInitial size:', self.sp.getDividerSize() frame.add( self.sp ) frame.pack() frame.setVisible( 1 ) #--------------------------------------------------------------------------- # Name: sizeOptions() # Role: Create, and return a group of buttons used to resize the SplitPane # divider #--------------------------------------------------------------------------- def sizeOptions( self ) : pane = JPanel( GridLayout( 1, 0 ) ) pane.add( JButton( 'Small', actionPerformed = self.resize ) ) pane.add( JButton( 'Medium', actionPerformed = self.resize ) ) pane.add( JButton( 'Large', actionPerformed = self.resize ) ) return pane #--------------------------------------------------------------------------- # Name: resize() # Role: ActionListener actionPerformed event handler for divider resizing #--------------------------------------------------------------------------- def resize( self, event ) : sizes = { 'Small' : 0, 'Medium' : 10, 'Large' : 20 } name = event.getActionCommand() self.sp.setDividerSize( sizes[ name ] )
class AtfAreaView(JPanel): ''' Initializes the ATF (edit/model) view and sets its layout. ''' def __init__(self, controller): ''' Creates default empty text area in a panel for ATF edition. It has syntax highlighting based on the ATF parser (pyoracc). It also highlights line numbers where there are validations errors returned by the ORACC server. ''' # Give reference to controller to delegate action response self.controller = controller # Make text area occupy all available space and resize with parent # window self.setLayout(BorderLayout()) # Short hand for edit area and line numbers area self.edit_area = self.controller.edit_area self.line_numbers_area = self.controller.line_numbers_area # Create secondary text area for split view self.secondary_area = self.controller.secondary_area self.secondary_line_numbers = self.controller.secondary_line_numbers # Set undo/redo manager to edit area self.undo_manager = UndoManager() self.undo_manager.limit = 3000 self.edit_listener = AtfUndoableEditListener(self.undo_manager) self.edit_area.getDocument().addUndoableEditListener( self.edit_listener) # Sort out layout by synch-ing line numbers and text area and putting # only the text area in a scroll pane as indicated in the # TextLineNumber tutorial. self.edit_area.setPreferredSize(Dimension(1, 500)) self.container = JScrollPane(self.edit_area) self.container.setRowHeaderView(self.line_numbers_area) self.add(self.container, BorderLayout.CENTER) self.vert_scroll = self.container.getVerticalScrollBar() self.vert_scroll.addAdjustmentListener(atfAreaAdjustmentListener(self)) # Key listener that triggers syntax highlighting, etc. upon key release self.edit_area.addKeyListener(AtfAreaKeyListener(self)) # Also needed in secondary area: self.secondary_area.addKeyListener(AtfAreaKeyListener(self)) # Add a document listener to track changes to files docListener = atfAreaDocumentListener(self) self.edit_area.getDocument().addDocumentListener(docListener) # instance variable to store a record of the text contents prior to the # most recent change. Needed so that the different listeners can access # this to handle error line updating. self.oldtext = '' def toggle_split(self, split_orientation=None): ''' Clear ATF edit area and repaint chosen layout (splitscreen/scrollpane). ''' # Remove all existent components in parent JPanel self.removeAll() # Check what editor view to toggle self.setup_edit_area(split_orientation) # Revalitate is needed in order to repaint the components self.revalidate() self.repaint() def setup_edit_area(self, split_orientation=None): ''' Check if the ATF text area is being displayed in a split editor. If so, resets to normal JScrollPane. If not, splits the screen. ''' if isinstance(self.container, JSplitPane): # If Nammu is already displaying a split pane, reset to original # setup self.container = JScrollPane(self.edit_area) self.container.setRowHeaderView(self.line_numbers_area) self.container.setVisible(True) self.add(self.container, BorderLayout.CENTER) else: # If there is not a split pane, create both panels and setup view main_editor = JScrollPane(self.edit_area) main_editor.setRowHeaderView(self.line_numbers_area) secondary_editor = JScrollPane(self.secondary_area) secondary_editor.setRowHeaderView(self.secondary_line_numbers) self.container = JSplitPane(split_orientation, main_editor, secondary_editor) self.container.setDividerSize(5) self.container.setVisible(True) self.container.setDividerLocation(0.5) self.container.setResizeWeight(0.5) self.add(self.container, BorderLayout.CENTER) def get_viewport_carets(self): ''' Get the top left and bottom left caret position of the current viewport ''' extent = self.container.getViewport().getExtentSize() top_left_position = self.container.getViewport().getViewPosition() top_left_char = self.edit_area.viewToModel(top_left_position) bottom_left_position = Point(top_left_position.x, top_left_position.y + extent.height) bottom_left_char = self.edit_area.viewToModel(bottom_left_position) # Something has gone wrong. Assume that top_left should be at the start # of the file if top_left_char >= bottom_left_char: top_left_char = 0 # Get the text in the full edit area text = self.controller.edit_area.getText() # Pad the top of the viewport to capture up to the nearest header and # the bottom by 2 lines top_ch = self.controller.pad_top_viewport_caret(top_left_char, text) bottom_ch = self.controller.pad_bottom_viewport_caret(bottom_left_char, text) return top_ch, bottom_ch def refresh(self): ''' Restyle edit area using user selected appearance settings. ''' config = self.controller.controller.config # Create a new font with the new size font = set_font(config['edit_area_style']['fontsize']['user']) # Update the sytnax highlighter font params, so our changes are not # superceded self.controller.syntax_highlighter.font = font self.controller.syntax_highlighter.setup_attribs() attrs = self.controller.edit_area.getInputAttributes() StyleConstants.setFontSize(attrs, font.getSize()) # Get the Styledoc so we can update it doc = self.controller.edit_area.getStyledDocument() # Apply the new fontsize to the whole document doc.setCharacterAttributes(0, doc.getLength() + 1, attrs, False)
class AtfAreaView(JPanel): ''' Initializes the ATF (edit/model) view and sets its layout. ''' def __init__(self, controller): ''' Creates default empty text area in a panel for ATF edition. It has syntax highlighting based on the ATF parser (pyoracc). It also highlights line numbers where there are validations errors returned by the ORACC server. ''' # Give reference to controller to delegate action response self.controller = controller # Make text area occupy all available space and resize with parent # window self.setLayout(BorderLayout()) # Short hand for edit area and line numbers area self.edit_area = self.controller.edit_area self.line_numbers_area = self.controller.line_numbers_area # Create secondary text area for split view self.secondary_area = self.controller.secondary_area self.secondary_line_numbers = self.controller.secondary_line_numbers # Set undo/redo manager to edit area self.undo_manager = UndoManager() self.undo_manager.limit = 3000 self.edit_listener = AtfUndoableEditListener(self.undo_manager) self.edit_area.getDocument().addUndoableEditListener( self.edit_listener) # Sort out layout by synch-ing line numbers and text area and putting # only the text area in a scroll pane as indicated in the # TextLineNumber tutorial. self.edit_area.setPreferredSize(Dimension(1, 500)) self.container = JScrollPane(self.edit_area) self.container.setRowHeaderView(self.line_numbers_area) self.add(self.container, BorderLayout.CENTER) self.vert_scroll = self.container.getVerticalScrollBar() self.vert_scroll.addAdjustmentListener(atfAreaAdjustmentListener(self)) # Key listener that triggers syntax highlighting, etc. upon key release self.edit_area.addKeyListener(AtfAreaKeyListener(self)) # Also needed in secondary area: self.secondary_area.addKeyListener(AtfAreaKeyListener(self)) # Add a document listener to track changes to files docListener = atfAreaDocumentListener(self) self.edit_area.getDocument().addDocumentListener(docListener) # instance variable to store a record of the text contents prior to the # most recent change. Needed so that the different listeners can access # this to handle error line updating. self.oldtext = '' def toggle_split(self, split_orientation=None): ''' Clear ATF edit area and repaint chosen layout (splitscreen/scrollpane). ''' # Remove all existent components in parent JPanel self.removeAll() # Check what editor view to toggle self.setup_edit_area(split_orientation) # Revalitate is needed in order to repaint the components self.revalidate() self.repaint() def setup_edit_area(self, split_orientation=None): ''' Check if the ATF text area is being displayed in a split editor. If so, resets to normal JScrollPane. If not, splits the screen. ''' if isinstance(self.container, JSplitPane): # If Nammu is already displaying a split pane, reset to original # setup self.container = JScrollPane(self.edit_area) self.container.setRowHeaderView(self.line_numbers_area) self.container.setVisible(True) self.add(self.container, BorderLayout.CENTER) else: # If there is not a split pane, create both panels and setup view main_editor = JScrollPane(self.edit_area) main_editor.setRowHeaderView(self.line_numbers_area) secondary_editor = JScrollPane(self.secondary_area) secondary_editor.setRowHeaderView(self.secondary_line_numbers) self.container = JSplitPane(split_orientation, main_editor, secondary_editor) self.container.setDividerSize(5) self.container.setVisible(True) self.container.setDividerLocation(0.5) self.container.setResizeWeight(0.5) self.add(self.container, BorderLayout.CENTER) def get_viewport_carets(self): ''' Get the top left and bottom left caret position of the current viewport ''' extent = self.container.getViewport().getExtentSize() top_left_position = self.container.getViewport().getViewPosition() top_left_char = self.edit_area.viewToModel(top_left_position) bottom_left_position = Point(top_left_position.x, top_left_position.y + extent.height) bottom_left_char = self.edit_area.viewToModel(bottom_left_position) # Something has gone wrong. Assume that top_left should be at the start # of the file if top_left_char >= bottom_left_char: top_left_char = 0 # Get the text in the full edit area text = self.controller.edit_area.getText() # Pad the top of the viewport to capture up to the nearest header and # the bottom by 2 lines top_ch = self.controller.pad_top_viewport_caret(top_left_char, text) bottom_ch = self.controller.pad_bottom_viewport_caret( bottom_left_char, text) return top_ch, bottom_ch def refresh(self): ''' Restyle edit area using user selected appearance settings. ''' config = self.controller.controller.config # Create a new font with the new size font = set_font(config['edit_area_style']['fontsize']['user']) # Update the sytnax highlighter font params, so our changes are not # superceded self.controller.syntax_highlighter.font = font self.controller.syntax_highlighter.setup_attribs() attrs = self.controller.edit_area.getInputAttributes() StyleConstants.setFontSize(attrs, font.getSize()) # Get the Styledoc so we can update it doc = self.controller.edit_area.getStyledDocument() # Apply the new fontsize to the whole document doc.setCharacterAttributes(0, doc.getLength() + 1, attrs, False)