Ejemplo n.º 1
0
public class DistributedTextEditor extends JFrame {

  private static final long serialVersionUID = -1412971829037207445L;

  private static DistributedTextEditor editor;

  private JTextArea area1 = new JTextArea(20, 120);
  private JTextArea area2 = new JTextArea(20, 120);
  private JTextField ipaddress = new JTextField("localhost");
  private JTextField portNumber = new JTextField("4242");

  private EventReplayer er;
  private Thread ert;

  private JFileChooser dialog = new JFileChooser(System.getProperty("user.dir"));

  private String currentFile = "Untitled";
  private boolean changed = false;
  private boolean connected = false;
  private boolean active = false;
  private boolean locked = false;
  private boolean listen = false;
  private DocumentEventCapturer dec;
  private ServerSocket serverSocket;
  private Socket clientSocket;
  private LamportClock lc;
  private int serverport;

  public DistributedTextEditor() {
    area1.setFont(new Font("Monospaced", Font.PLAIN, 12));

    area2.setFont(new Font("Monospaced", Font.PLAIN, 12));
    ((AbstractDocument) area1.getDocument()).setDocumentFilter(dec);
    area2.setEditable(false);

    Container content = getContentPane();
    content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));

    JScrollPane scroll1 =
        new JScrollPane(
            area1, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    content.add(scroll1, BorderLayout.CENTER);

    JScrollPane scroll2 =
        new JScrollPane(
            area2, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    content.add(scroll2, BorderLayout.CENTER);

    content.add(ipaddress, BorderLayout.CENTER);
    content.add(portNumber, BorderLayout.CENTER);

    JMenuBar JMB = new JMenuBar();
    setJMenuBar(JMB);
    JMenu file = new JMenu("File");
    JMenu edit = new JMenu("Edit");
    JMB.add(file);
    JMB.add(edit);

    file.add(Listen);
    file.add(Connect);
    file.add(Disconnect);
    file.addSeparator();
    file.add(Save);
    file.add(SaveAs);
    file.add(Quit);

    edit.add(Copy);
    edit.add(Paste);
    edit.getItem(0).setText("Copy");
    edit.getItem(1).setText("Paste");

    Save.setEnabled(false);
    SaveAs.setEnabled(false);
    Disconnect.setEnabled(false);

    setDefaultCloseOperation(EXIT_ON_CLOSE);
    pack();
    area1.addKeyListener(k1);
    area1.addMouseListener(m1);
    setTitle("Disconnected");
    setVisible(true);
    area1.insert("Welcome to Hjortehandlerne's distributed text editor. \n", 0);

    this.addWindowListener(w1);
  }

  private WindowListener w1 =
      new WindowListener() {
        /** Kill all active threads */
        @Override
        public void windowClosing(WindowEvent e) {
          disconnect();
        }

        @Override
        public void windowActivated(WindowEvent e) {}

        @Override
        public void windowClosed(WindowEvent e) {}

        @Override
        public void windowDeactivated(WindowEvent e) {}

        @Override
        public void windowDeiconified(WindowEvent e) {}

        @Override
        public void windowIconified(WindowEvent e) {}

        @Override
        public void windowOpened(WindowEvent e) {}
      };

  private KeyListener k1 =
      new KeyAdapter() {
        public void keyPressed(KeyEvent e) {
          changed = true;
          Save.setEnabled(true);
          SaveAs.setEnabled(true);
        }

        /**
         * The keyReleased event ensures that the caret-position is updated for both peers, when the
         * user moves the caret with the arrow-keys.
         */
        public void keyReleased(KeyEvent e) {
          int left = e.VK_LEFT;
          int right = e.VK_RIGHT;
          int up = e.VK_UP;
          int down = e.VK_DOWN;
          int home = e.VK_HOME;
          int end = e.VK_END;
          int A = e.VK_A;
          int kc = e.getKeyCode();

          if (kc == left
              || kc == right
              || kc == up
              || kc == down
              || kc == home
              || kc == end
              || (kc == A && e.isControlDown())) {
            if (dec == null) return;
            lc.increment();
            TextEvent cu = new CaretUpdate(area1.getCaretPosition(), lc.getTimeStamp());
            dec.sendObjectToAllPeers(cu);
            er.getEventHistoryLock().lock();
            er.getEventHistory().add(cu);
            er.getEventHistoryLock().unlock();
          }
        }
      };

  /**
   * This mouselistener ensures that both peers have an updated caret-position for this user, when
   * he moves his caret by a mouseclick.
   */
  private MouseListener m1 =
      new MouseAdapter() {
        public void mouseReleased(MouseEvent e) {
          if (e.getButton() == e.BUTTON1 && connected) {
            if (dec == null) return;
            lc.increment();
            TextEvent cu = new CaretUpdate(area1.getCaretPosition(), lc.getTimeStamp());
            dec.sendObjectToAllPeers(cu);
            er.getEventHistoryLock().lock();
            er.getEventHistory().add(cu);
            er.getEventHistoryLock().unlock();
          }
        }
      };

  /**
   * This action is called when the Listen-button is fired. It creates a serversocket, and awaits a
   * connection. When the first connection is made, a ConnectionData object is sent to the other
   * peer, and this editor creates new data for the incomming peer. After the first connection is
   * made, waitForConnection is called, which waits for more connections.
   */
  Action Listen =
      new AbstractAction("Listen") {
        public void actionPerformed(ActionEvent e) {
          saveOld();
          final InetAddress local;
          active = true;
          try {
            local = InetAddress.getLocalHost();
            Runnable server =
                new Runnable() {
                  public void run() {
                    serverport = Integer.parseInt(portNumber.getText());
                    int myID = getNewId();
                    registerOnPort();
                    editor.setTitleToListen();
                    clientSocket = waitForConnectionFromClient();
                    lc = new LamportClock(myID);
                    area1.setText("");
                    resetArea2();
                    if (clientSocket != null) {
                      listen = true;
                      connected = true;
                      dec = new DocumentEventCapturer(lc, editor);
                      setDocumentFilter(dec);
                      er = new EventReplayer(editor, dec, lc);
                      er.updateCaretPos(myID, 0);
                      ert = new Thread(er);
                      ert.start();

                      try {
                        ObjectOutputStream output =
                            new ObjectOutputStream(clientSocket.getOutputStream());
                        ObjectInputStream input =
                            new ObjectInputStream(clientSocket.getInputStream());
                        JoinNetworkRequest request = (JoinNetworkRequest) input.readObject();
                        int id = getNewId();
                        Peer peer =
                            new Peer(
                                editor,
                                er,
                                id,
                                clientSocket,
                                output,
                                input,
                                lc,
                                clientSocket.getInetAddress().getHostAddress(),
                                request.getPort());
                        ConnectionData cd =
                            new ConnectionData(
                                er.getEventHistory(),
                                er.getAcknowledgements(),
                                er.getCarets(),
                                id,
                                area1.getText(),
                                lc.getTimeStamp(),
                                lc.getID(),
                                dec.getPeers(),
                                serverSocket.getLocalPort());
                        dec.addPeer(peer);
                        er.addCaretPos(id, 0);
                        Thread t = new Thread(peer);
                        t.start();
                        peer.writeObjectToStream(cd);
                      } catch (IOException | ClassNotFoundException e) {
                        e.printStackTrace();
                      }
                    }
                    waitForConnection();
                  }
                };
            Thread serverThread = new Thread(server);
            serverThread.start();
          } catch (UnknownHostException e1) {
            e1.printStackTrace();
          }

          changed = false;
          Disconnect.setEnabled(true);
          Listen.setEnabled(false);
          Connect.setEnabled(false);
          Save.setEnabled(false);
          SaveAs.setEnabled(false);
        }
      };

  /**
   * waitForConnection waits for incomming connections. There are two cases. If we receive a
   * JoinNetworkRequest it means that a new peer tries to get into the network. We lock the entire
   * system, and sends a ConnectionData object to the new peer, from which he can connect to every
   * other peer. We add this new peer to our data.
   *
   * <p>If we receive a NewPeerDataRequest, it means that a new peer has received ConnectionData
   * from another peer in the network, and he is now trying to connect to everyone, including me. We
   * then update our data with the new peer.
   */
  private void waitForConnection() {
    while (active) {
      Socket client = waitForConnectionFromClient();
      if (client != null) {
        try {
          ObjectOutputStream output = new ObjectOutputStream(client.getOutputStream());
          ObjectInputStream input = new ObjectInputStream(client.getInputStream());
          Object o = input.readObject();

          if (o instanceof JoinNetworkRequest) {
            JoinNetworkRequest request = (JoinNetworkRequest) o;
            dec.sendObjectToAllPeers(new LockRequest(lc.getTimeStamp()));
            waitForAllToLock();
            setLocked(true);
            Thread.sleep(500);
            int id = getNewId();
            Peer p =
                new Peer(
                    editor,
                    er,
                    id,
                    client,
                    output,
                    input,
                    lc,
                    client.getInetAddress().getHostAddress(),
                    request.getPort());
            ConnectionData cd =
                new ConnectionData(
                    er.getEventHistory(),
                    er.getAcknowledgements(),
                    er.getCarets(),
                    id,
                    area1.getText(),
                    lc.getTimeStamp(),
                    lc.getID(),
                    dec.getPeers(),
                    serverSocket.getLocalPort());
            p.writeObjectToStream(cd);
            dec.addPeer(p);
            Thread t = new Thread(p);
            t.start();
            er.addCaretPos(id, 0);
          } else if (o instanceof NewPeerDataRequest) {
            NewPeerDataRequest request = (NewPeerDataRequest) o;
            Peer newPeer =
                new Peer(
                    editor,
                    er,
                    request.getId(),
                    client,
                    output,
                    input,
                    lc,
                    client.getInetAddress().getHostAddress(),
                    request.getPort());
            dec.addPeer(newPeer);
            er.addCaretPos(request.getId(), request.getCaretPos());
            newPeer.writeObjectToStream(new NewPeerDataAcknowledgement(lc.getTimeStamp()));
            Thread t = new Thread(newPeer);
            t.start();
          }
        } catch (IOException | ClassNotFoundException | InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
  }

  private void waitForAllToLock() {
    for (Peer p : dec.getPeers()) {
      while (!p.isLocked() && p.isConnected()) {
        try {
          Thread.sleep(100);
        } catch (InterruptedException e) {
        }
      }
      p.setLocked(false);
    }
  }

  /**
   * Will register this server on the port number portNumber. Will not start waiting for
   * connections. For this you should call waitForConnectionFromClient().
   */
  private void registerOnPort() {
    try {
      serverSocket = new ServerSocket(Integer.parseInt(portNumber.getText()));
    } catch (IOException e) {
      serverSocket = null;
      System.err.println("Cannot open server socket on port number" + portNumber.getText());
      System.err.println(e);
      System.exit(-1);
    }
  }

  /** Closes the serversocket */
  public void deregisterOnPort() {
    if (serverSocket != null) {
      try {
        serverSocket.close();
        serverSocket = null;
      } catch (IOException e) {
        System.err.println(e);
      }
    }
  }

  /**
   * Waits for the next client to connect on port number portNumber or takes the next one in line in
   * case a client is already trying to connect. Returns the socket of the connection, null if there
   * were any failures.
   */
  private Socket waitForConnectionFromClient() {
    Socket res = null;
    try {
      res = serverSocket.accept();
    } catch (IOException e) {
    }
    return res;
  }

  /**
   * This action is called when the Connect-button is fired. It creates a ClientSocket with the
   * known peer, and opens a serversocket to listen for new peers. We send a JoinNetworkRequest to
   * the known peer, and receive ConnectionData from him. We then connect to all other peers in the
   * network, and update our data from the received ConnectionData. At last we call
   * waitForConnection() to wait for new connections from new peers, and finally we tell everyone to
   * unlock the system
   */
  Action Connect =
      new AbstractAction("Connect") {
        public void actionPerformed(ActionEvent e) {
          saveOld();
          area1.setText("");
          resetArea2();
          try {
            clientSocket = new Socket(ipaddress.getText(), Integer.parseInt(portNumber.getText()));
            Random r = new Random();
            serverport = 10000 + r.nextInt(8999); // random port :D

            serverSocket = new ServerSocket(serverport);
            active = true;
            editor.setTitleToListen();

            connected = true;

            ObjectOutputStream output = new ObjectOutputStream(clientSocket.getOutputStream());
            ObjectInputStream input = new ObjectInputStream(clientSocket.getInputStream());
            output.writeObject(new JoinNetworkRequest(serverport));

            ConnectionData data = getConnectionData(clientSocket, input);

            lc = new LamportClock(data.getId());
            lc.setMaxTime(data.getTs());
            dec = new DocumentEventCapturer(lc, editor);
            er = new EventReplayer(editor, dec, lc);
            ert = new Thread(er);
            ert.start();

            Peer peer =
                new Peer(
                    editor,
                    er,
                    data.getHostId(),
                    clientSocket,
                    output,
                    input,
                    lc,
                    clientSocket.getInetAddress().getHostAddress(),
                    data.getPort());
            dec.addPeer(peer);
            Thread thread = new Thread(peer);
            thread.start();

            er.setAcknowledgements(data.getAcknowledgements());
            er.setEventHistory(data.getEventHistory());
            er.setCarets(data.getCarets());

            er.addCaretPos(lc.getID(), 0);

            for (PeerWrapper p : data.getPeers()) {
              Socket socket;
              try {
                socket = connectToPeer(p.getIP(), p.getPort());
                ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
                ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
                outputStream.writeObject(
                    new NewPeerDataRequest(lc.getID(), serverSocket.getLocalPort(), 0));
                Peer newPeer =
                    new Peer(
                        editor,
                        er,
                        p.getId(),
                        socket,
                        outputStream,
                        inputStream,
                        lc,
                        p.getIP(),
                        p.getPort());
                dec.addPeer(newPeer);
                Thread t = new Thread(newPeer);
                t.start();
              } catch (IOException ex) {
                continue;
              }
            }

            Thread t1 =
                new Thread(
                    new Runnable() {

                      @Override
                      public void run() {
                        waitForConnection();
                      }
                    });
            t1.start();
            area1.setText(data.getTextField());
            area1.setCaretPosition(0);
            setDocumentFilter(dec);

            dec.sendObjectToAllPeers(new UnlockRequest(lc.getTimeStamp()));

            changed = false;
            Connect.setEnabled(false);
            Disconnect.setEnabled(true);
            Listen.setEnabled(false);
            Save.setEnabled(false);
            SaveAs.setEnabled(false);
          } catch (NumberFormatException | IOException e1) {
            setTitle("Unable to connect");
          }
        }

        private Socket connectToPeer(String ip, int port) {
          try {
            Socket peer = new Socket(ip, port);
            return peer;
          } catch (IOException e) {
            e.printStackTrace();
          }
          return null;
        }

        private ConnectionData getConnectionData(Socket clientSocket, ObjectInputStream input) {
          ConnectionData res;
          try {
            Object o = input.readObject();
            res = (ConnectionData) o;
            return res;
          } catch (IOException | ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
          return null;
        }
      };

  /** This action is called when the Disconnect-button is fired. */
  Action Disconnect =
      new AbstractAction("Disconnect") {
        public void actionPerformed(ActionEvent e) {
          disconnect();
        }
      };

  /**
   * The disconnect method will stop the eventreplayer, and send null to the other peers, to stop
   * their reading from their streams. The GUI-menu is updated appropriately.
   */
  public void disconnect() {
    setTitle("Disconnected");
    active = false;
    if (connected == true) {
      er.stopStreamToQueue();
      ert.interrupt();
      setDocumentFilter(null);
      connected = false;
      setLocked(false);
    }
    deregisterOnPort();
    Disconnect.setEnabled(false);
    Connect.setEnabled(true);
    Listen.setEnabled(true);
    Save.setEnabled(true);
    SaveAs.setEnabled(true);
  }

  Action Save =
      new AbstractAction("Save") {
        public void actionPerformed(ActionEvent e) {
          if (!currentFile.equals("Untitled")) saveFile(currentFile);
          else saveFileAs();
        }
      };

  Action SaveAs =
      new AbstractAction("Save as...") {
        public void actionPerformed(ActionEvent e) {
          saveFileAs();
        }
      };

  Action Quit =
      new AbstractAction("Quit") {
        public void actionPerformed(ActionEvent e) {
          saveOld();
          System.exit(0);
        }
      };

  ActionMap m = area1.getActionMap();
  Action Copy = m.get(DefaultEditorKit.copyAction);
  Action Paste = m.get(DefaultEditorKit.pasteAction);

  private void saveFileAs() {
    if (dialog.showSaveDialog(null) == JFileChooser.APPROVE_OPTION)
      saveFile(dialog.getSelectedFile().getAbsolutePath());
  }

  private void saveOld() {
    if (changed) {
      if (JOptionPane.showConfirmDialog(
              this,
              "Would you like to save " + currentFile + " ?",
              "Save",
              JOptionPane.YES_NO_OPTION)
          == JOptionPane.YES_OPTION) saveFile(currentFile);
    }
  }

  private void saveFile(String fileName) {
    try {
      FileWriter w = new FileWriter(fileName);
      area1.write(w);
      w.close();
      currentFile = fileName;
      changed = false;
      Save.setEnabled(false);
    } catch (IOException e) {
    }
  }

  public boolean getActive() {
    return active;
  }

  public DocumentFilter getDocumentFilter() {
    return dec;
  }

  public JTextArea getTextArea() {
    return area1;
  }

  public DocumentEventCapturer getDocumentEventCapturer() {
    return dec;
  }

  public void setDocumentFilter(DocumentFilter filter) {
    ((AbstractDocument) area1.getDocument()).setDocumentFilter(filter);
  }

  public void setErrorMessage(String s) {
    area2.setText("Error: " + s);
  }

  public void setTitleToListen() {
    try {
      String serverString = serverSocket.getInetAddress().getLocalHost().toString();
      String serverIP = serverString.split("/")[1];
      editor.setTitle("Listening on: " + serverIP + ":" + serverport);
    } catch (UnknownHostException e) {
      e.printStackTrace();
    }
  }

  public void resetArea2() {
    area2.setText("");
  }

  public static void main(String[] arg) {
    editor = new DistributedTextEditor();
  }

  public void setLocked(boolean b) {
    locked = b;
    area1.setEnabled(!b);
  }

  public boolean getListen() {
    return listen;
  }

  public void setTextInArea2(String res) {
    area2.setText(res);
  }

  public EventReplayer getEventReplayer() {
    return er;
  }

  public int getNewId() {
    Random r = new Random();
    return r.nextInt(1000000);
  }
}
/**
 * A text editor created for my own use. Credit to
 * http://forum.codecall.net/topic/49721-simple-text-editor/
 *
 * @author Corey Hickson
 * @version 0.1
 */
public class CoreyTextEditor extends JFrame {

  // Variables to help initialize the text editor
  private JTextArea area = new JTextArea(20, 120);
  private JFileChooser dialog = new JFileChooser(System.getProperty("user.dir"));
  private String currentFile = "Untitled";
  private boolean changed = false;

  /** Constructor to create the frame and its components */
  public CoreyTextEditor() {
    // Create a scroll pane
    area.setFont(new Font("Monospaced", Font.PLAIN, 12));
    JScrollPane scroll =
        new JScrollPane(
            area, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    add(scroll, BorderLayout.CENTER);

    // Adds the system default look and feel

    try {
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    } catch (ClassNotFoundException
        | InstantiationException
        | UnsupportedLookAndFeelException
        | IllegalAccessException e) {
      e.printStackTrace();
    }

    // Create a menu bar
    JMenuBar JMB = new JMenuBar();
    setJMenuBar(JMB);
    JMenu file = new JMenu("File");
    JMenu edit = new JMenu("Edit");
    JMB.add(file);
    JMB.add(edit);

    // Finishing our menu bar
    file.add(New);
    file.add(Open);
    file.add(Save);
    file.add(SaveAs);
    file.addSeparator();
    file.add(Quit);

    edit.add(Cut);
    edit.add(Copy);
    edit.add(Paste);

    edit.getItem(0).setText("Cut");
    edit.getItem(0).setIcon(new ImageIcon("cut.gif"));
    edit.getItem(1).setText("Copy");
    edit.getItem(1).setIcon(new ImageIcon("copy.gif"));
    edit.getItem(2).setText("Paste");
    edit.getItem(2).setIcon(new ImageIcon("paste.gif"));

    // Time to make a toolbar!
    JToolBar tool = new JToolBar();
    add(tool, BorderLayout.NORTH);
    tool.add(New);
    tool.add(Open);
    tool.add(Save);
    tool.addSeparator();

    JButton cut = tool.add(Cut);
    JButton cop = tool.add(Copy);
    JButton pas = tool.add(Paste);

    cut.setText(null);
    cut.setIcon(new ImageIcon("cut.gif"));
    cop.setText(null);
    cop.setIcon(new ImageIcon("copy.gif"));
    pas.setText(null);
    pas.setIcon(new ImageIcon("paste.gif"));

    Save.setEnabled(false);
    SaveAs.setEnabled(false);

    setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    pack();

    /*
     KeyListener to change Save and SaveAs
    */
    KeyListener k1 =
        new KeyAdapter() {
          public void keyPressed(KeyEvent e) {
            changed = true;
            Save.setEnabled(true);
            SaveAs.setEnabled(true);
          }
        };
    area.addKeyListener(k1);
    setTitle(currentFile + " - CoreyTextEditor");
    setVisible(true);
  }

  Action New =
      new AbstractAction("New", new ImageIcon("new.gif")) {
        public void actionPerformed(ActionEvent e) {
          saveOld();
          area.setText("");
          currentFile = "Untitled";
          setTitle(currentFile + " - CoreyTextEditor");
          changed = false;
          Save.setEnabled(false);
          SaveAs.setEnabled(false);
        }
      };

  Action Open =
      new AbstractAction("Open", new ImageIcon("open.gif")) {
        public void actionPerformed(ActionEvent e) {
          saveOld();
          if (dialog.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
            readInFile(dialog.getSelectedFile().getAbsolutePath());
          }
          SaveAs.setEnabled(true);
        }
      };

  Action Save =
      new AbstractAction("Save", new ImageIcon("save.gif")) {
        public void actionPerformed(ActionEvent e) {
          if (!currentFile.equals("Untitled")) {
            saveFile(currentFile);
          } else {
            saveFileAs();
          }
        }
      };

  Action SaveAs =
      new AbstractAction("Save as...") {
        public void actionPerformed(ActionEvent e) {
          saveFileAs();
        }
      };

  Action Quit =
      new AbstractAction("Quit") {
        public void actionPerformed(ActionEvent e) {
          saveOld();
          System.exit(0);
        }
      };

  ActionMap m = area.getActionMap();
  Action Cut = m.get(DefaultEditorKit.cutAction);
  Action Copy = m.get(DefaultEditorKit.copyAction);
  Action Paste = m.get(DefaultEditorKit.pasteAction);

  private void saveFileAs() {
    if (dialog.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) {
      saveFile(dialog.getSelectedFile().getAbsolutePath());
    }
  }

  private void saveOld() {
    if (changed) {
      if (JOptionPane.showConfirmDialog(
              this,
              "Would you like to save " + currentFile + " ?",
              "Save",
              JOptionPane.YES_NO_OPTION)
          == JOptionPane.YES_OPTION) {
        saveFile(currentFile);
      }
    }
  }

  private void readInFile(String fileName) {
    try {
      FileReader r = new FileReader(fileName);
      area.read(r, null);
      r.close();
      currentFile = fileName;
      setTitle(currentFile + " - CoreyTextEditor");
      changed = false;
    } catch (IOException e) {
      Toolkit.getDefaultToolkit().beep();
      JOptionPane.showMessageDialog(this, "Editor can't find the file called " + fileName);
    }
  }

  private void saveFile(String fileName) {
    try {
      FileWriter w = new FileWriter(fileName);
      area.write(w);
      w.close();
      currentFile = fileName;
      setTitle(currentFile + " - CoreyTextEditor");
      changed = false;
      Save.setEnabled(false);
    } catch (IOException e) {
      // No handling done here
    }
  }

  public static void main(String[] args) {
    new CoreyTextEditor();
  }
}