Package games.stendhal.client.gui

Source Code of games.stendhal.client.gui.KTextEdit$TextPaneMouseListener

/* $Id: KTextEdit.java,v 1.72 2011/04/07 20:50:40 kiheru Exp $ */
/***************************************************************************
*                   (C) Copyright 2003-2010 - Stendhal                    *
***************************************************************************
***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************/
package games.stendhal.client.gui;

import games.stendhal.client.stendhal;
import games.stendhal.client.gui.chatlog.EventLine;
import games.stendhal.common.NotificationType;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.MouseEvent;
import java.io.FileWriter;
import java.util.Date;

import javax.swing.JComponent;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;

import org.apache.log4j.Logger;

/**
* Appendable text component to be used as the chat log.
*/
public class KTextEdit extends JComponent {
  /** Point size of the text */
  protected static final int TEXT_SIZE = 11;
  /** Color of the time stamp written before the lines */
  protected static final Color HEADER_COLOR = Color.gray;

  /** Location for saving chat log file. */
  private static final String GAME_LOG_FILE = stendhal.getGameFolder() + "gamechat.log";
 
  private static final long serialVersionUID = -698232821850852452L;
  private static final Logger logger = Logger.getLogger(KTextEdit.class);
 
  /** The actual text component for showing the chat log */
  protected JTextPane textPane;
  /** Scroll pane containing the text component */
  private JScrollPane scrollPane;
  /**
   * <code>true</code> if the chat log should automatically scroll to the
   * last line when more lines are added, <code>false</code> otherwise.
   */
  private boolean autoScrollEnabled;
 
 
  /** Listener for opening the popup menu when it's requested. */
  private final class TextPaneMouseListener extends MousePopupAdapter {
    @Override
    protected void showPopup(final MouseEvent e) {
      final JPopupMenu popup = new JPopupMenu("save");

      JMenuItem menuItem = new JMenuItem("Save");
      menuItem.addActionListener(new ActionListener() {
        public void actionPerformed(final ActionEvent e) {
          save();
        }
      });
      popup.add(menuItem);

      menuItem = new JMenuItem("Clear");
      menuItem.addActionListener(new ActionListener() {
        public void actionPerformed(final ActionEvent e) {
          clear();
        }
      });
      popup.add(menuItem);

      popup.show(e.getComponent(), e.getX(), e.getY());
    }
  }
 

  /**
   * Basic Constructor.
   */
  public KTextEdit() {
    buildGUI();
  }

  /**
   * This method builds the Gui.
   */
  protected void buildGUI() {
    textPane = new JTextPane();
    textPane.setEditable(false);
    textPane.setAutoscrolls(true);
   
    textPane.addMouseListener(new TextPaneMouseListener());
   
    initStylesForTextPane(textPane);
    setLayout(new BorderLayout());
   
    scrollPane = new JScrollPane(textPane);
    scrollPane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {
      public void adjustmentValueChanged(final AdjustmentEvent ev) {
        JScrollBar bar = (JScrollBar) ev.getAdjustable();
        // Try to avoid turning the new message indicator off
        // while the player keeps adjusting the scroll bar to
        // avoid missleading results
        if (!bar.getValueIsAdjusting() && (bar.getValue() + bar.getVisibleAmount() == bar.getMaximum())) {
            setUnreadLinesWarning(false);
            setAutoScrollEnabled(true);
        }
      }
    });
    add(scrollPane, BorderLayout.CENTER);
  }

  /**
   * Initializes the basic styles.
   * @param textPane
   *            the active text component
   */
  protected void initStylesForTextPane(final JTextPane textPane) {

    final Style def = StyleContext.getDefaultStyleContext().getStyle(
        StyleContext.DEFAULT_STYLE);

    final Style regular = textPane.addStyle("regular", def);
    StyleConstants.setFontFamily(def, "Dialog");
    StyleConstants.setFontSize(regular, TEXT_SIZE);

    Style s = textPane.addStyle("normal", regular);
    StyleConstants.setBold(s, true);
    StyleConstants.setForeground(s, HEADER_COLOR);

    s = textPane.addStyle("bold", regular);
    StyleConstants.setFontSize(regular, TEXT_SIZE + 1);
    StyleConstants.setItalic(s, true);
    StyleConstants.setBold(s, true);
    StyleConstants.setForeground(s, Color.blue);

    s = textPane.addStyle("header", regular);
    StyleConstants.setItalic(s, true);
    StyleConstants.setFontSize(s, TEXT_SIZE);
    StyleConstants.setForeground(s, HEADER_COLOR);

    s = textPane.addStyle("timestamp", regular);
    StyleConstants.setItalic(s, true);
    StyleConstants.setFontSize(s, TEXT_SIZE - 1);
    StyleConstants.setForeground(s, HEADER_COLOR);
  }

  /**
   * Get the style corresponding to a description and color.
   *
   * @param desiredColor
   *            the color with which the text must be colored
   * @param styleDescription
   *            which style to use (may not be normal)
   * @return the colored style
   */
  private Style getStyle(final Color desiredColor, final String styleDescription) {
    final Style s = textPane.getStyle(styleDescription);
    StyleConstants.setForeground(s, desiredColor);
    return s;
  }

  /**
   * Insert a header.
   *
   * @param header
   */
  protected void insertHeader(final String header) {
    final Document doc = textPane.getDocument();
    try {
      if (header.length() > 0) {
        doc.insertString(doc.getLength(), "<" + header + "> ",
            textPane.getStyle("header"));
      }
    } catch (final BadLocationException e) {
      logger.error("Couldn't insert initial text.", e);
    }
  }

  /**
   * Insert time stamp.
   *
   * @param header time stamp
   */
  protected void insertTimestamp(final String header) {
    final Document doc = textPane.getDocument();
    try {
      if (header.length() > 0) {
        doc.insertString(doc.getLength(), header,
            textPane.getStyle("timestamp"));
      }
    } catch (final BadLocationException e) {
      logger.error("Couldn't insert initial text.", e);
    }
  }

  /**
   * Add text using a style defined for a notification type.
   *
   * @param text
   * @param type
   */
  protected void insertText(final String text, final NotificationType type) {
    final Color color = type.getColor();
    final String styleDescription = type.getStyleDescription();
    final Document doc = textPane.getDocument();

    try {
      final FormatTextParser parser =  new FormatTextParser() {
        @Override
        public void normalText(final String txt) throws BadLocationException {
          doc.insertString(doc.getLength(), txt, getStyle(color,styleDescription));
        }

        @Override
        public void colorText(final String txt) throws BadLocationException {
          doc.insertString(doc.getLength(), txt, textPane.getStyle("bold"));
        }
      };
      parser.format(text);
    } catch (final Exception e) {
      // BadLocationException
      logger.error("Couldn't insert initial text.", e);
    }
  }

  /**
   * Start a new line.
   */
  protected void insertNewline() {
    final Document doc = textPane.getDocument();
    try {
      doc.insertString(doc.getLength(), "\r\n", getStyle(Color.black, "normal"));
    } catch (final BadLocationException e) {
      logger.error("Couldn't insert initial text.", e);
    }
  }

  /**
   * Scroll to the last line.
   */
  private void scrollToBottom() { 
    final JScrollBar vbar = scrollPane.getVerticalScrollBar();
    vbar.setValue(vbar.getMaximum());
  }

  /**
   * Add a new line with a specified header and content. The style will be
   * chosen according to the type of the message.
   *
   * @param header
   *            a string with the header
   * @param line
   *            a string representing the line to be printed
   * @param type
   *            The logical format type.
   */
  private synchronized void addLine(final String header, final String line,
      final NotificationType type) {
    // do the whole thing in the event dispatch thread to ensure the generated
    // events get handled in the correct order
    try {
      if (SwingUtilities.isEventDispatchThread()) {
        handleAddLine(header, line, type);
      } else {
        SwingUtilities.invokeAndWait(new Runnable() {
          public void run() {
            handleAddLine(header, line, type);
          }
        });
      }
    } catch (final Exception e) {
      logger.error(e, e);
    }
  }
 
  /**
   * Add a new line with a specified header and content. The style will be
   * chosen according to the type of the message. Keep the view at the last
   * line unless the user has scrolled higher.
   *
   * @param header
   *            a string with the header
   * @param line
   *            a string representing the line to be printed
   * @param type
   *            The logical format type.
   */
  private void handleAddLine(final String header, final String line, final NotificationType type) {
    final JScrollBar vbar = scrollPane.getVerticalScrollBar();
    final int currentLocation = vbar.getValue();
   
    setAutoScrollEnabled((vbar.getValue() + vbar.getVisibleAmount() == vbar.getMaximum()));
    insertNewline();

    final java.text.Format formatter = new java.text.SimpleDateFormat("[HH:mm] ");
    final String dateString = formatter.format(new Date());
    insertTimestamp(dateString);

    insertHeader(header);
    insertText(line, type);
   
    // wait a bit so that the scroll bar knows where it should scroll
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        if (isAutoScrollEnabled()) {
          scrollToBottom();
        } else {
          // the scroll bar insists changing its value, so jump back.
          // in a sane toolkit it would be possible to defer drawing
          // until this
          vbar.setValue(currentLocation);
          setUnreadLinesWarning(true);
        }
      }
    });
  }

  /**
   * Set the auto scroll flag.
   *
   * @param autoScrollEnabled <code>true</code> if the chat log view keeps
   *   at the last line, <code>false</code> otherwise
   */
  private void setAutoScrollEnabled(final boolean autoScrollEnabled) {
    this.autoScrollEnabled = autoScrollEnabled;
  }

  /**
   * Check if the view should keep following the last line.
   *
   * @return <code>true</code> if the view should be kept at bottom
   */
  private boolean isAutoScrollEnabled() {
    return autoScrollEnabled;
  }

  /**
   * Append an event line.
   *
   * @param line
   */
  public void addLine(final EventLine line) {
    this.addLine(line.getHeader(), line.getText(), line.getType());
  }
 
  /**
   * Clear the context.
   */
  public void clear() {
    textPane.setText("");
  }
 
  /**
   * Set a clear warning for the user that there are new, unread lines.
   * @param warn true if the warning indicator should be shown, false otherwise
   */
  private void setUnreadLinesWarning(final boolean warn) {
    if (warn) {
      textPane.setBackground(Color.pink);
    } else {
      textPane.setBackground(Color.white);
    }
  }
 
  /**
   * Save the contents into the log file and inform the user about it.
   */
  public void save() {
    FileWriter fo;
    try {
      fo = new FileWriter(GAME_LOG_FILE);
      try {
        textPane.write(fo);
      } finally {
        fo.close();
      }

      addLine("", "Chat log has been saved to " + GAME_LOG_FILE, NotificationType.CLIENT);
    } catch (final Exception ex) {
      logger.error(ex, ex);
    }
  }
}
TOP

Related Classes of games.stendhal.client.gui.KTextEdit$TextPaneMouseListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.