class jiconsole(Console): """ Class jiconsole, it is the main class which handles user interaction """ PROMPT = sys.ps1 PROCESS = sys.ps2 BANNER = (InteractiveConsole.getDefaultBanner(), jEdit.getProperty("console-second-line")) def __init__(self, view): """ Constructor, initialized all the main variables and layout """ # Initializes variables self.view = view self.history = History(self) self.bs = 0 self.indenter = TabIndenter() self.exporterConsole = None self.executor = JythonExecutor.getExecutor() # Creates toolbar actions = [ ("Run.png", "jython.tooltip-run", self.runBuffer), \ ("RunToBuffer.png", "jython.tooltip-run-another", self.runBufferToWindow), \ ("RunAgain.png", "jython.tooltip-import", self.importBuffer), \ ("MultipleResults.png", "jython.tooltip-path", self.path), \ ("Open.png", "jython.tooltip-browse-path", self.browse), \ ("CopyToBuffer.png", "jython.tooltip-save-session", self.savesession), \ ("separator", None, None), \ ("Clear.png", "jython.tooltip-restart", self.restart), ("separator", None, None), ("Parse.png", "jython.tooltip-tabnanny", self.tabnanny), ("separator", None, None), ("Help.png", "jython.tooltip-about", self.about)] self.panel = JPanel(BorderLayout()) self.panel.add(BorderLayout.NORTH, ToolbarHandler(actions).createToolbar()) # Creates text pane and make keybindings # self.output = JTextPane(keyTyped = self.keyTyped, keyPressed = self.keyPressed, keyReleased = self.keyReleased) self.output = JTextPane(keyTyped=self.keyTyped, keyPressed=self.keyPressed) if jEdit.getBooleanProperty("options.jython.upDownFlag"): keyBindings = [ (KeyEvent.VK_ENTER, 0, "jython.enter", self.enter), (KeyEvent.VK_DELETE, 0, "jython.delete", self.delete), (KeyEvent.VK_HOME, 0, "jython.home", self.home), (KeyEvent.VK_UP, 0, "jython.up", self.history.historyUp), (KeyEvent.VK_DOWN, 0, "jython.down", self.history.historyDown), (KeyEvent.VK_UP, InputEvent.CTRL_MASK, DefaultEditorKit.upAction, self.output.keymap.getAction( KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0))), (KeyEvent.VK_DOWN, InputEvent.CTRL_MASK, DefaultEditorKit.downAction, self.output.keymap.getAction( KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0))) ] else: keyBindings = [ (KeyEvent.VK_ENTER, 0, "jython.enter", self.enter), (KeyEvent.VK_DELETE, 0, "jython.delete", self.delete), (KeyEvent.VK_HOME, 0, "jython.home", self.home), (KeyEvent.VK_UP, InputEvent.CTRL_MASK, "jython.historyup", \ self.history.historyUp), (KeyEvent.VK_DOWN, InputEvent.CTRL_MASK, "jython.historydown", \ self.history.historyDown) ] newmap = JTextComponent.addKeymap("jython", self.output.keymap) for (key, modifier, name, function) in keyBindings: newmap.addActionForKeyStroke(KeyStroke.getKeyStroke(key, modifier), ActionDelegator(name, function)) self.output.keymap = newmap self.doc = self.output.document self.panel.add(BorderLayout.CENTER, JScrollPane(self.output)) self.__propertiesChanged() self.__inittext() self.initialLocation = self.doc.createPosition(self.doc.length - 1) def browse(self, event): """ Opens the browse window """ self.view.dockableWindowManager.toggleDockableWindow( "jython-browser-dockable") def stop(self, event): """ Stops the current execution """ self.executor.interruptCurrent(self) def about(self, event): """ Opens the about dialog """ from jiabout import AboutDialog a = AboutDialog(self.view, jEdit.getProperty("jython.about.title")) centerDialog(a) a.setVisible(1) def savesession(self, event): """ Saves the current session """ from exportsession import export export(self.view, self.doc) def path(self, event): """ Opens the Path Handler """ from pathhandler import PyPathHandler v = PyPathHandler(self.view, sys) v.pack() centerDialog(v) v.visible = 1 def __buffer(self): """ Returns the current buffer ready for run/import, checking if it is a python buffer and whether has been saved """ from javax.swing import JOptionPane buf = self.view.editPane.buffer if buf.mode.name != "python": if buf.getProperty("jython.originator"): buf = buf.getProperty("jython.originator") if buf.mode.name == "python": if buf.dirty: if not jEdit.getBooleanProperty("options.jython.autosave"): if jEdit.getBooleanProperty("options.jython.saveask"): result = JOptionPane.showConfirmDialog( self.panel, "Do you want to save before running", "Confirm", JOptionPane.YES_NO_CANCEL_OPTION) if result == JOptionPane.CANCEL_OPTION: return None if result == JOptionPane.YES_OPTION: buf.save(self.view, None) else: buf.save(self.view, None) return buf return None def runBuffer(self, event): """ Runs the current buffer """ buffer = self.__buffer() if buffer: JythonExecutor.getExecutor().execBuffer(self.view, buffer, self) def runBufferToWindow(self, event): """ Runs the current buffer to and exports the result to another window """ from exportconsole import ConsoleToBuffer buffer = self.__buffer() if buffer: if jEdit.getBooleanProperty("options.jython.reuseOutputBuffer"): if not self.exporterConsole: self.exporterConsole = ConsoleToBuffer(self.view, buffer) self.exporterConsole.clear() else: self.exporterConsole = ConsoleToBuffer(self.view, buffer) JythonExecutor.getExecutor().execBuffer(self.view, buffer, self.exporterConsole) def tabnanny(self, event): import jitabnanny buffer = self.__buffer() jitabnanny.checkBuffer(buffer) def importBuffer(self, event): """ Imports the current buffer """ import os.path import imp b = self.__buffer() if b: modname, ext = os.path.splitext(os.path.basename(b.path)) if sys.modules.has_key(modname): mod = sys.modules[modname] else: mod = imp.new_module(modname) sys.modules[modname] = mod mod.__file__ = b.path setattr(sys.modules['__main__'], modname, mod) dir = os.path.dirname(b.path) dir = os.path.normpath(os.path.abspath(dir)) if dir not in sys.path: sys.path.insert(0, dir) JythonExecutor.getExecutor().importBuffer(self.view, b, self) def restart(self, event): """ Reinitializes the interpreter """ from javax.swing import JOptionPane result = JOptionPane.showConfirmDialog(self.panel, \ jEdit.getProperty("jython.console.clean-confirm"), "Confirm", JOptionPane.YES_NO_CANCEL_OPTION) if result == JOptionPane.YES_OPTION: JythonExecutor.getExecutor().interrupt() self.__inittext() def inLastLine(self, include=1): """ Determines whether the cursor is in the last line """ limits = self.__lastLine() caret = self.output.caretPosition if self.output.selectedText: caret = self.output.selectionStart if include: return (caret >= limits[0] and caret <= limits[1]) else: return (caret > limits[0] and caret <= limits[1]) def enter(self, event): """ Triggered when enter is pressed """ offsets = self.__lastLine() text = self.doc.getText(offsets[0], offsets[1] - offsets[0]) # Detects special keywords if text != "\n": if text[:-1] == "copyright": self.printResult( jEdit.getProperty("jython.interpreter.copyright") + sys.copyright) self.printPrompt() return if text[:-1] == "credits": import site self.printResult( jEdit.getProperty("jython.interpreter.credits") + "\n" + str(site.__builtin__.credits)) self.printPrompt() return if text[:-1] == "license": import site self.printResult( jEdit.getProperty("jython.interpreter.license")) self.printPrompt() return text = text[:-1] if self.indenter.isPushable(text): JythonExecutor.getExecutor().execute(self.view, text, self) self.history.append(text) else: self.printOnProcess() else: JythonExecutor.getExecutor().execute(self.view, text, self) def home(self, event): """ Triggered when HOME is pressed """ if self.inLastLine(): self.output.caretPosition = self.__lastLine()[0] else: lines = self.doc.rootElements[0].elementCount for i in xrange(0, lines - 1): offsets = (self.doc.rootElements[0].getElement(i).startOffset, \ self.doc.rootElements[0].getElement(i).endOffset) line = self.doc.getText(offsets[0], offsets[1] - offsets[0]) if self.output.caretPosition >= offsets[0] and \ self.output.caretPosition <= offsets[1]: if line.startswith(jiconsole.PROMPT) or line.startswith( jiconsole.PROCESS): self.output.caretPosition = offsets[0] + len( jiconsole.PROMPT) else: self.output.caretPosition = offsets[0] def replaceRow(self, text): """ Replaces the last line of the textarea with text """ offset = self.__lastLine() last = self.doc.getText(offset[0], offset[1] - offset[0]) if last != "\n": self.doc.remove(offset[0], offset[1] - offset[0] - 1) self.__addOutput(self.infoColor, text) def delete(self, event): """ Intercepts delete events only allowing it to work in the last line """ if self.inLastLine(): if self.output.selectedText: self.doc.remove( self.output.selectionStart, self.output.selectionEnd - self.output.selectionStart) elif self.output.caretPosition < self.doc.length: self.doc.remove(self.output.caretPosition, 1) def keyReleased(self, event): """ Experimental code completion, disabled for now """ if event.keyChar == '.': offsets = self.__lastLine() text = self.doc.getText(offsets[0], offsets[1] - offsets[0] - 1) #completions = jintrospect.getAutoCompleteList(text, globals()) completions = 0 if completions: CompletionPopup(self.view, completions, self.output, self) def keyTyped(self, event): if not self.inLastLine(): event.consume() if self.bs: event.consume() self.bs = 0 def keyPressed(self, event): if event.keyCode == KeyEvent.VK_BACK_SPACE: offsets = self.__lastLine() if not self.inLastLine(include=0): self.bs = 1 else: self.bs = 0 def printResult(self, msg): """ Prints the results of an operation """ self.__addOutput(self.output.foreground, "\n" + str(msg)) def printOnProcess(self): """ Prints the process symbol """ self.__addOutput(self.infoColor, "\n" + jiconsole.PROCESS) def printPrompt(self): """ Prints the prompt """ self.__addOutput(self.infoColor, "\n" + jiconsole.PROMPT) def printErrorMsg(self, msg, file, line): self.__addOutput(self.errorColor, "\n" + str(msg)) self.__addErrorButton((file, line)) def printError(self, e): import org self.__addOutput(self.errorColor, "\n%s" % str(e)[:-1]) if isinstance(e, org.python.core.PySyntaxError): self.__addErrorButton((e.value[1][0], e.value[1][1])) elif isinstance(e, org.python.core.PyException): import traceback self.__addErrorButton((traceback.extract_tb(e.traceback)[-1][0], traceback.extract_tb(e.traceback)[-1][1])) def _completeToken(self, token): """ Adds a token to be completed """ style = SimpleAttributeSet() style.addAttribute(StyleConstants.Foreground, self.infoColor) self.doc.insertString(self.output.caretPosition, token, style) def __addOutput(self, color, msg): """ Adds the output to the text area using a given color """ style = SimpleAttributeSet() if color: style.addAttribute(StyleConstants.Foreground, color) self.doc.insertString(self.doc.length, msg, style) self.output.caretPosition = self.doc.length def __propertiesChanged(self): """ Detects when the properties have changed """ self.output.background = jEdit.getColorProperty("jython.bgColor") self.output.foreground = jEdit.getColorProperty("jython.resultColor") self.infoColor = jEdit.getColorProperty("jython.textColor") self.errorColor = jEdit.getColorProperty("jython.errorColor") family = jEdit.getProperty("jython.font", "Monospaced") size = jEdit.getIntegerProperty("jython.fontsize", 14) style = jEdit.getIntegerProperty("jython.fontstyle", Font.PLAIN) self.output.setFont(Font(family, style, size)) def __inittext(self): """ Inserts the initial text with the jython banner """ self.doc.remove(0, self.doc.length) for line in "\n".join(jiconsole.BANNER): self.__addOutput(self.infoColor, line) self.printPrompt() self.output.requestFocus() def __lastLine(self): """ Returns the char offsets of the last line """ lines = self.doc.rootElements[0].elementCount offsets = (self.doc.rootElements[0].getElement(lines-1).startOffset, \ self.doc.rootElements[0].getElement(lines-1).endOffset) line = self.doc.getText(offsets[0], offsets[1] - offsets[0]) if len(line) >= 4 and (line[0:4] == jiconsole.PROMPT or line[0:4] == jiconsole.PROCESS): return (offsets[0] + len(jiconsole.PROMPT), offsets[1]) return offsets def __addErrorButton(self, parsed): from error import ErrorButton if parsed[0] != "<console>": self.__addOutput(self.errorColor, " ") self.output.insertComponent(ErrorButton(self.view, parsed))
class ChatClient(JFrame): ## Constructor method, receives the variables from the ChatApp class as parameters def __init__(self, name, greeting, tn): '''Constructor, initialises base class & assigns variables ''' # Call to the super method to take care of the base class(es) super(ChatClient, self).__init__() # Assign the relevent variable names self.username=name self.greeting=greeting self.tn = tn self.no_users=[] # Initiate the Threaded function for receiving messages t1=Thread(target=self.recvFunction) # Set to daemon t1.daemon=True t1.start() #Call the main UI uI=self.clientUI() ## Main GUI building function def clientUI(self): '''ClientUI and Widget creation ''' # Colours foreground_colour = Color(30,57,68) background_colour = Color(247,246,242) window_background = Color(145,190,210) # Borders self.border2=BorderFactory.createLineBorder(foreground_colour,1, True) # Fonts self.font= Font("Ubuntu Light", Font.BOLD, 20) self.label_font= Font("Ubuntu Light", Font.BOLD, 17) self.label_2_font= Font( "Ubuntu Light",Font.BOLD, 12) self.btn_font=Font("Ubuntu Light", Font.BOLD, 15) # Set the layout parameters self.client_layout=GroupLayout(self.getContentPane()) self.getContentPane().setLayout(self.client_layout) self.getContentPane().setBackground(window_background) self.client_layout.setAutoCreateGaps(True) self.client_layout.setAutoCreateContainerGaps(True) self.setPreferredSize(Dimension(400, 450)) # Create widgets and assemble the GUI # Main display area self.main_content=JTextPane() self.main_content.setBackground(background_colour) #self.main_content.setForeground(foreground_colour) self.main_content.setEditable(False) # Message entry area self.message=JTextArea( 2,2, border=self.border2, font=self.label_font, keyPressed=self.returnKeyPress) self.message.requestFocusInWindow() self.message.setBackground(background_colour) self.message.setForeground(foreground_colour) self.message.setLineWrap(True) self.message.setWrapStyleWord(True) self.message.setBorder(BorderFactory.createEmptyBorder(3,3,3,3)) self.message.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0), self.returnKeyPress) # BUttons quit_btn=JButton("Quit!", actionPerformed=ChatApp().closeEvent, border=self.border2, font=self.btn_font) go_btn=JButton("Send", actionPerformed=self.grabText, border=self.border2, font=self.btn_font) quit_btn.setBackground(background_colour) go_btn.setBackground(background_colour) quit_btn.setForeground(foreground_colour) go_btn.setForeground(foreground_colour) # Make scrollable self.scroll_content=JScrollPane(self.main_content) self.scroll_content.setPreferredSize(Dimension(150,275)) self.scroll_content.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER) self.scroll_content.setViewportView(self.main_content) self.scroll_content.setBackground(Color.WHITE) self.scroll_message=JScrollPane(self.message) self.scroll_message.setPreferredSize(Dimension(150,20)) self.scroll_message.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS) # Test user label, still not updating after first round of messages self.user_label=JLabel(" Users online : %s "%(str(len(self.no_users))),JLabel.RIGHT, font=self.label_2_font) # Assemble the components # Horizontal layout self.client_layout.setHorizontalGroup(self.client_layout.createParallelGroup() .addComponent(self.scroll_content) .addGroup(self.client_layout.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(self.scroll_message)) .addGroup(self.client_layout.createSequentialGroup() .addComponent(quit_btn) .addComponent(go_btn).addGap(20)) .addGroup(self.client_layout.createParallelGroup() .addComponent(self.user_label)) ) # Vertical layout self.client_layout.setVerticalGroup(self.client_layout.createSequentialGroup() .addGroup(self.client_layout.createParallelGroup() .addComponent(self.scroll_content)) .addComponent(self.scroll_message) .addGroup(self.client_layout.createParallelGroup() .addComponent(quit_btn) .addComponent(go_btn)) .addGroup(self.client_layout.createParallelGroup() .addComponent(self.user_label)) ) # Finalise the GUI self.client_layout.linkSize(SwingConstants.HORIZONTAL, [quit_btn,go_btn, self.user_label]) self.pack() self.message.requestFocusInWindow() self.setTitle(">>> Client %s <<<"%self.username) self.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) self.setLocationRelativeTo(None) self.setVisible(True) # Display the server greeting self.appendText('\n'+self.greeting+'\n') ## Function responsible for receiving and processing new messages def recvFunction(self): '''A function to control the receiving of data from the connection ''' # While the connection is available while self.tn: # Try to receive data using "<<<" as the delimiter try: message = self.tn.read_until('<<<') # If a message is received if message: garb, message=message.split('>>>') message, garb = message.split('<<<') message = ('\n'+message+'\n') # Call the append text function self.appendText(message) # Except if there is no data available except: #print('No message') pass ## Event driven function to retrieve and send data to the server def grabText(self, event): '''Function to repeatedly grab new messages entered into the text area and display them in the main text area. Resets the entry area ''' # Grab the text from the text area text=self.message.getText() # Don't allow an empty string through if text=='': return text=text.strip() # Call the append text function self.appendText('\nYou : '+text+'\n', self.username) # Reset the text to be empty and grab focus so that it is ready for new text input self.message.requestFocusInWindow() self.message.setText('') # Send the message to the server data=text.encode() self.tn.write(data+'\r\n') ## Function to handle appending of messages def appendText(self, message, user=None): '''This function takes care of appending any new messages to the content area ''' message_label=JTextArea(message,2,3, font=self.label_2_font) # If this is a message from the grab text function, create a new label, assign it's colours if user!=None: message_label.setBackground(Color(240,240,240)) message_label.setForeground(Color(129,129,129)) # Otherwise set the format for receive function (no user passed in) else: message_label.setBackground(Color(215,215,215)) message_label.setForeground(Color(40,153,153)) # Format and style options for the new message labels message_label.setEditable(False) message_label.setLineWrap(True) message_label.setWrapStyleWord(True) message_label.setBorder(BorderFactory.createLineBorder( Color(247,246,242),4)) # Sets the positioning of messages self.main_content.setCaretPosition(self.main_content.getDocument().getLength()) doc = self.main_content.getStyledDocument() attr=SimpleAttributeSet() self.main_content.insertComponent(message_label) # Essential for jtextarea to be able to stack message doc.insertString( self.main_content.getDocument().getLength(),'\n ', attr) # Not sure if needed self.main_content.repaint() ### This is a late edit so it isn't included in the documentation. Basically trying to dynamically update the number ### of users label at runtime. Works for incrementing the value but not decrementing it. print(message) # Only split the message if there are enough values to split (greeting messages differ in format to chat messages) try: user, text=message.split(' : ') except: return #print('Split values are %s %s'%(user, text)) user=str(user.strip()) #print(self.no_users) #print(user+' : '+text) # If the user already in the list, pass if user in self.no_users: if text == ('User %s amach sa teach !'%user): self.no_users.remove(user) print('User % removed'%user) else: #print('User %s not in list'%user) if str(user) == 'You': #print('User is equal to "You"') return self.no_users.append(user) print('User appended') self.number_users=len(self.no_users) #print('Length of user list is '+str(self.number_users)) self.user_label2=JLabel(" Users online : %s "%str(len(self.no_users)),JLabel.RIGHT, font=self.label_2_font) #print('Label created') #print('Attempt to replace label') self.client_layout.replace(self.user_label, self.user_label2) self.user_label = self.user_label2 self.user_label.repaint() self.user_label.revalidate() print('Label updated') ## Function to control return button press in message field def returnKeyPress(self,event): '''This function creates an object for return key press when inside the message entry area, creates an object of KeyAdapter and tests keycode for a match, responds with grab text callback ''' key_object=Key() key_value=key_object.keyPressed(event) if key_value == 10: self.grabText(event)