Example #1
0
class ClientGUI(object):

  def __init__(self, windowTitle="Client GUI"):
    # create new instance of TK
    self.base_gui = pygui.Tk()

    # store the windowTitle in an object attribute
    self.base_window_title = windowTitle

    # Connection Details
    self.connection_host = ''
    self.connection_name = ''
    self.connection_port = 0

    # Client Object
    self.client = None

    # [Connection GUI Initialization] ::start
    self.connection_gui_bootstrapped = False
    self.connection_config_frame = pygui.Frame(self.base_gui)
    self.host_to_use_field = pygui.Entry(self.connection_config_frame)
    self.port_to_use_field = pygui.Entry(self.connection_config_frame)
    self.name_field = pygui.Entry(self.connection_config_frame)
    self.connect_server_btn = pygui.Button(self.connection_config_frame, text="Connect", command=self.connect_to_server)
    # [Connection GUI Initialization] ::end

    # [Main GUI Initialization] ::start
    self.main_gui_bootstrapped = False
    self.chat_room_frame = pygui.Frame(self.base_gui)
    self.activity_log_area = ScrolledText(self.chat_room_frame, height=10, width=50)
    self.message_field = pygui.Entry(self.chat_room_frame)
    self.submit_msg_btn = pygui.Button(self.chat_room_frame, text="Send", command=self.send_msg)

    self.exit_chat_btn = pygui.Button(self.chat_room_frame,
                                      text="Leave Chat Room",
                                      command=lambda: self.switch_context('connection'))
    # [Connection GUI Initialization] ::end

  def bootstrap(self):
    if self.client is None:
      print "Client Object must be specified. Call the set_client() method and set the ClientGUI Object."
      sys.exit(1)

    self.connection_gui()

    # set window title
    self.base_gui.wm_title(self.base_window_title)

    # handle close button
    self.base_gui.protocol("WM_DELETE_WINDOW", self.destroy_gui)

    # Start the GUI
    self.base_gui.mainloop()

  def connection_gui(self):
    # [Config Section] :start
    # assemble the UI and the frame if the attribute does not exist
    if self.connection_gui_bootstrapped is False:
      # Add field for host/hostname to use
      pygui.Label(self.connection_config_frame, text="Host").grid(row=0, column=0)
      self.host_to_use_field.grid(row=0, column=1)

      # Add field for port to use
      pygui.Label(self.connection_config_frame, text="Port").grid(row=1, column=0)
      self.port_to_use_field.grid(row=1, column=1)

      # Add field for chat username/alias
      pygui.Label(self.connection_config_frame, text="Name").grid(row=2, column=0)
      self.name_field.grid(row=2, column=1)

      self.connect_server_btn.grid(row=3, column=1)

      self.connection_gui_bootstrapped = True

    self.connection_config_frame.pack(side=pygui.TOP, padx=10, pady=10)
    # [Config Section] :end

  def main_gui(self):
    # [Chat Room] ::start
    # assemble the UI and the frame if the attribute does not exist
    if self.main_gui_bootstrapped is False:
      self.activity_log_area.grid(row=0)
      self.activity_log_area.edit_modified(0)
      self.activity_log_area.config(highlightbackground="black")
      self.activity_log_area.bind('<<Modified>>', self.scroll_to_end)

      self.message_field.grid(row=1, column=0)
      self.message_field.config(width=30)
      self.message_field.bind("<Return>", self.send_msg)

      self.submit_msg_btn.grid(row=1, column=1)

      self.exit_chat_btn.grid(row=2)

      self.main_gui_bootstrapped = True

    # empty the chat logs
    self.activity_log_area.delete("1.0", pygui.END)

    # show the frame for chat room
    self.chat_room_frame.pack(side=pygui.TOP, padx=10, pady=10)
    # [Chat Room] ::end

  def destroy_gui(self):
    # disconnect from the server
    self.client.disconnect()

    # destroy the window
    self.base_gui.destroy()

  def switch_context(self, context):
    if context == 'main':
      # hide the connection frame/GUI from the window
      if hasattr(self, 'connection_config_frame'):
        self.connection_config_frame.pack_forget()

      self.main_gui()

      title = "%s connected on %s:%s - %s" % (strip_uid(self.connection_name),
                                              self.connection_host,
                                              str(self.connection_port),
                                              self.base_window_title)

      # change the window title to show the connection details
      self.base_gui.wm_title(title)

    else:
      # disconnect from the server
      self.client.disconnect()

      # hide the chat room frame/GUI from the window
      if hasattr(self, 'chat_room_frame'):
        self.chat_room_frame.pack_forget()

      self.connection_gui()

      # set window title
      self.base_gui.wm_title(self.base_window_title)

  def scroll_to_end(self, *_):
    # scroll to the end of text area
    self.activity_log_area.see(pygui.END)
    self.activity_log_area.edit_modified(0)

  def connect_to_server(self):
    hostval = self.host_to_use_field.get()
    portval = self.port_to_use_field.get()
    nameval = self.name_field.get()

    if hostval != '' and portval != '' and nameval != '':
      self.connection_host = str(hostval)
      self.connection_name = str(nameval)

      # check if the host supplied is a valid ip address
      if not is_ipv4(self.connection_host):
        msgBox.showinfo("Client GUI", "Invalid IP Address")
        return

      # check if the input for port number is a valid integer
      try:
        self.connection_port = int(portval)
      except ValueError:
        msgBox.showinfo("Client GUI", "Invalid Port Number")
        return

      # initiate client-server connection
      if self.client.connect(self.connection_host, self.connection_port, self.connection_name) is True:
        # swap UI components/widgets
        self.switch_context('main')

        # log any broadcast message and disconnect on lost connection
        self.client.start_communications(self.log, lambda: self.switch_context('connection'))
      else:
        msgBox.showinfo("Client GUI", "Cant connect to server. Please try again later.")

    else:
      msgBox.showinfo("Client GUI", "Please enter the host, and port to connect to as well as your chat name")

  def set_client(self, client):
    self.client = client

  def send_msg(self, *_):
    message = self.message_field.get()

    # only send messages which are not empty
    if message:
      # show the message on your side
      self.log('[' + strip_uid(self.connection_name) + '] ' + message)

      # send the message to the other side
      self.client.send_msg(str(message))

      # delete the message
      self.message_field.delete(0, pygui.END)

  def log(self, message):
    self.activity_log_area.insert(pygui.END, message + "\n")
Example #2
0
class ServerGUI(object):
    server_on = False

    def __init__(self, window_title="Server GUI"):
        self.base_gui = pygui.Tk()

        self.window_title = window_title
        self.server_port = 0
        self.server = None

        # [GUI Initialization] ::start
        self.server_config_frame = pygui.Frame(self.base_gui)
        self.port_to_use_field = pygui.Entry(self.server_config_frame)
        self.server_controls_frame = pygui.Frame(self.base_gui)
        self.create_server_btn = pygui.Button(self.server_controls_frame,
                                              text="Start Server",
                                              command=self.invoke_server)
        self.stop_server_btn = pygui.Button(self.server_controls_frame,
                                            text="Stop Server",
                                            command=self.stop_server)
        self.quit_btn = pygui.Button(self.server_controls_frame,
                                     text="Quit",
                                     command=self.destroy_gui)
        # [GUI Initialization] ::end

        self.server_logs_frame = pygui.Frame(self.base_gui)
        self.activity_log_area = ScrolledText(self.server_logs_frame,
                                              height=10,
                                              width=50)

    def bootstrap(self):
        if self.server is None:
            print "Server Object must be specified. Call the set_server() method and set the ServerGUI Object."
            sys.exit(1)

        # set window title
        self.base_gui.wm_title(self.window_title)

        # [Config Section] :start
        self.server_config_frame.pack(side=pygui.TOP, pady=10)

        # Add field for port to use
        pygui.Label(self.server_config_frame,
                    text="Server port to use").grid(row=0, column=0)

        self.port_to_use_field.grid(row=0, column=1)
        self.port_to_use_field.bind("<Return>", self.invoke_server)
        # [Config Section] :end

        # [Controls Section] ::start
        self.server_controls_frame.pack(side=pygui.RIGHT, fill=pygui.Y)

        # Add Start server button
        self.create_server_btn.grid(row=0, column=1)

        # Stop Server
        self.stop_server_btn.grid(row=1, column=1)

        # Quit Button
        self.quit_btn.grid(row=2, column=1)
        # [Controls Section] ::end

        # [Logs Section] ::start
        self.server_logs_frame.pack(side=pygui.LEFT, padx=10, pady=10)

        # Create a text area for showing logs.
        pygui.Label(self.server_logs_frame, text="Logs").grid(row=0)

        self.activity_log_area.edit_modified(0)
        self.activity_log_area.grid(row=1)
        self.activity_log_area.config(highlightbackground="black")
        self.activity_log_area.bind('<<Modified>>', self.scroll_to_end)
        # [Logs Section] ::end

        # handle close button
        self.base_gui.protocol("WM_DELETE_WINDOW", self.destroy_gui)

        # Start the GUI
        self.base_gui.mainloop()

    def set_server(self, server):
        self.server = server

    def scroll_to_end(self, *_):
        # scroll to the end of text area
        self.activity_log_area.see(pygui.END)
        self.activity_log_area.edit_modified(0)

    def destroy_gui(self):
        self.stop_server()
        self.base_gui.destroy()

    def stop_server(self, *_):
        if self.server_on is True:
            self.server.stop(self.log)

            # set the SERVER_ON flag to false to enable create a new server instance
            self.server_on = False
        else:
            self.log("Server already stopped.")

    def invoke_server(self, *_):
        portval = self.port_to_use_field.get()

        if portval != '':
            # check if the input for port number is a valid integer
            try:
                self.server_port = int(portval)
            except ValueError:
                msgBox.showinfo("Client GUI", "Invalid Port Number")
                return

            # start the server if not yet started
            if self.server_on is False:
                # log the message
                self.server.set_port(self.server_port)

                if not self.server.invoke(self.log):
                    msgBox.showinfo(
                        "Client GUI",
                        "Cannot bind to port: %s. Please select another port to bind on."
                        % str(self.server_port))

                    return

                # Prevent starting another instance of server
                self.server_on = True
            else:
                self.log("Server already started on port: " +
                         str(self.server_port))
        else:
            self.log(
                "Please provide port number for the server to bind on. Thanks!"
            )

    def log(self, message):
        self.activity_log_area.insert(pygui.END, message + "\n")