/* ===========================================================
* TradeManager : a application to trade strategies for the Java(tm) platform
* ===========================================================
*
* (C) Copyright 2011-2011, by Simon Allen and Contributors.
*
* Project Info: org.trade
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Oracle, Inc.
* in the United States and other countries.]
*
* (C) Copyright 2011-2011, by Simon Allen and Contributors.
*
* Original Author: Simon Allen;
* Contributor(s): -;
*
* Changes
* -------
*
*/
package org.trade.ui.base;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.print.PrinterException;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.Writer;
import java.net.URLConnection;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JDialog;
import javax.swing.JEditorPane;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Document;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledEditorKit;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The StreamEditorPane responsible for actaully displaying text
*
* @version $Id: StreamEditorPane.java,v 1.10 2002/01/11 20:06:02 simon Exp $
* @author Simon Allen
*/
public class StreamEditorPane extends JEditorPane implements MouseListener, ActionListener {
private static final long serialVersionUID = -8068406289677664715L;
private final static Logger _log = LoggerFactory.getLogger(StreamEditorPane.class);
protected UndoableEditListener undoHandler = new UndoHandler();
protected UndoManager undo = new UndoManager();
private UndoAction undoAction = new UndoAction();
private RedoAction redoAction = new RedoAction();
private JPopupMenu popup = null;
private String m_currFileName = null;
private int m_startPosition = 0;
private String m_currDir = null;
JFileChooser m_fileChooser = new JFileChooser();
public StreamEditorPane() {
this("text/plain");
}
/**
* Constructor for StreamEditorPane.
*
* @param type
* String
* @throws IOException
*/
public StreamEditorPane(String type) {
super();
if (type == null) {
// Unknown type - use plain text
type = "text/plain";
}
DefaultStyledDocument doc = new DefaultStyledDocument(new StyleContext());
StyledEditorKit styled = new StyledEditorKit();
setContentType(type);
setEditorKitForContentType(type, styled);
setDocument(doc);
this.setMinimumSize(new Dimension(300, 200));
this.addMouseListener(this);
}
/**
* Method append.
*
* @param text
* String
*/
public void append(String text) {
append(text, null);
}
/**
* Method append.
*
* @param text
* String
* @param attrSet
* AttributeSet
*/
public void append(String text, AttributeSet attrSet) {
try {
this.getDocument().insertString(this.getDocument().getLength(), text, attrSet);
} catch (BadLocationException ex) {
_log.error("Error appending text:", ex);
}
}
/**
* Method setInputStream.
*
* @param is
* InputStream
* @throws IOException
* @throws BadLocationException
*/
public void setInputStream(InputStream is) throws IOException, BadLocationException {
String type = guessContentType(is);
if (type == null) {
// Unknown type - use plain text
type = "text/plain";
}
// Set the new content type
setContentType(type);
// Now create the appropriate document and install it
// Document doc = getEditorKit().createDefaultDocument();
DefaultStyledDocument doc = new DefaultStyledDocument(new StyleContext());
StyledEditorKit styled = new StyledEditorKit();
setEditorKitForContentType(type, styled);
setDocument(doc);
// Finally, read the date from the stream
getEditorKit().read(is, doc, 0);
}
/**
* Method setDocument.
*
* @param doc
* Document
*/
public void setDocument(Document doc) {
if (null != getDocument()) {
getDocument().removeUndoableEditListener(undoHandler);
}
super.setDocument(doc);
getDocument().addUndoableEditListener(undoHandler);
}
/**
* Method getText.
*
* @return String
*/
public String getText() {
String text = null;
try {
text = super.getDocument().getText(0, super.getDocument().getLength());
} catch (BadLocationException ex) {
_log.error("Error appending getting text:", ex);
}
return text;
}
/**
* Save current file, asking user for new destination name. Report to
* statuBar.
*
*
* @return false means user cancelled the SaveAs
*/
public boolean saveAs() {
boolean retSaveAs = false;
// Make the dialog visible as a modal (default) dialog box.
ExampleFileFilter filter = new ExampleFileFilter(new String[] { "*" }, "All Files");
m_fileChooser.addChoosableFileFilter(filter);
if (null != getDirName()) {
m_fileChooser.setSelectedFile(new File(getDirName() + "//" + getFileName()));
} else {
m_fileChooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
}
int returnVal = m_fileChooser.showSaveDialog(this.getRootPane());
// Upon return, getFile() will be null if user cancelled the dialog.
if (returnVal == JFileChooser.APPROVE_OPTION) {
// Non-null file property after return implies user
// selected a filename to save to.
// Set the current file name to the user's selection,
// then do a regular saveFile
if (m_fileChooser.getSelectedFile().exists()) {
int result = JOptionPane.showConfirmDialog(this.getRootPane(),
"File Exists. Do you want to over write ? ", "Warning", JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.WARNING_MESSAGE);
if (result == JOptionPane.YES_OPTION) {
setFileName(m_fileChooser.getSelectedFile().getPath());
setCurrentDirectory(m_fileChooser.getCurrentDirectory().toString());
retSaveAs = saveFileWriter(getFileName());
} else if (result == JOptionPane.NO_OPTION) {
retSaveAs = true;
} else if (result == JOptionPane.CANCEL_OPTION) {
// cancel
retSaveAs = false;
} else {
// cancel
retSaveAs = false;
}
} else {
setFileName(m_fileChooser.getSelectedFile().getPath());
setCurrentDirectory(m_fileChooser.getCurrentDirectory().toString());
retSaveAs = saveFileWriter(getFileName());
}
} else {
retSaveAs = false;
}
return retSaveAs;
}
/**
* Save current file, asking user for new destination name. Report to
* statuBar.
*
*
* @return false means user cancelled the SaveAs
*/
public boolean openFile() {
boolean retOpenFile = false;
// Make the dialog visible as a modal (default) dialog box.
ExampleFileFilter filter = new ExampleFileFilter(new String[] { "*" }, "All Files");
m_fileChooser.addChoosableFileFilter(filter);
if (null != getDirName()) {
m_fileChooser.setSelectedFile(new File(getDirName() + "//" + getFileName()));
} else {
m_fileChooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
}
int returnVal = m_fileChooser.showOpenDialog(this.getRootPane());
// Upon return, getFile() will be null if user cancelled the dialog.
if (returnVal == JFileChooser.APPROVE_OPTION) {
// Non-null file property after return implies user
// selected a filename to save to.
// Set the current file name to the user's selection,
// then do a regular saveFile
if (m_fileChooser.getSelectedFile().exists()) {
setFileName(m_fileChooser.getSelectedFile().getPath());
setCurrentDirectory(m_fileChooser.getCurrentDirectory().toString());
retOpenFile = openFileReader(getFileName());
}
} else {
retOpenFile = false;
}
return retOpenFile;
}
/**
* Method getDirName.
*
* @return String
*/
private String getDirName() {
return m_currDir;
}
/**
* Method setCurrentDirectory.
*
* @param dir
* String
*/
private void setCurrentDirectory(String dir) {
m_currDir = dir;
}
/**
* Method getFileName.
*
* @return String
*/
public String getFileName() {
return m_currFileName;
}
/**
* Method setFileName.
*
* @param currFileName
* String
*/
public void setFileName(String currFileName) {
m_currFileName = currFileName;
}
/**
* Method openFileReader.
*
* @param fileName
* String
* @return boolean
*/
public boolean openFileReader(String fileName) {
boolean result = false;
try {
Reader read = new FileReader(fileName);
this.read(read, fileName);
read.close();
result = true;
} catch (Throwable t) {
JOptionPane.showMessageDialog(this, "Could not save file " + fileName, "Warning",
JOptionPane.WARNING_MESSAGE);
result = false;
}
return result;
}
/**
* Method saveFileWriter.
*
* @param fileName
* String
* @return boolean
*/
public boolean saveFileWriter(String fileName) {
boolean result = false;
try {
Writer w = new FileWriter(fileName);
this.write(w);
w.close();
result = true;
} catch (Throwable t) {
JOptionPane.showMessageDialog(this, "Could not save file " + fileName, "Warning",
JOptionPane.WARNING_MESSAGE);
result = false;
}
return result;
}
/**
* Method setText.
*
* @param text
* String
*/
public void setText(String text) {
super.setText(text);
undo.discardAllEdits();
}
/**
* Method isDirty.
*
* @return boolean
*/
public boolean isDirty() {
return undo.canUndoOrRedo();
}
/**
* Method find.
*
* @param findText
* String
* @param startPosition
* int
*/
public void find(String findText, int startPosition) {
String findTextUpper = findText.toUpperCase();
try {
String text = getDocument().getText(0, getDocument().getLength());
int currstartPosition = text.toUpperCase().indexOf(findTextUpper, startPosition);
if (currstartPosition != -1) {
this.setSelectionStart(currstartPosition);
this.setSelectionEnd(currstartPosition + findTextUpper.length());
this.setSelectionColor(Color.red);
m_startPosition = currstartPosition + findTextUpper.length() + 1;
} else {
m_startPosition = 0;
}
} catch (BadLocationException e) {
e.printStackTrace();
}
}
// Guess the content type
/**
* Method guessContentType.
*
* @param is
* InputStream
* @return String
* @throws IOException
*/
protected String guessContentType(InputStream is) throws IOException {
String type = URLConnection.guessContentTypeFromStream(is);
if (type == null) {
is.mark(10);
int c1 = is.read();
int c2 = is.read();
int c3 = is.read();
int c4 = is.read();
int c5 = is.read();
is.reset();
if ((c1 == '{') && (c2 == '\\') && (c3 == 'r') && (c4 == 't') && (c5 == 'f')) {
type = "text/rtf";
}
// Add more heuristics here
}
return type;
}
/**
* mousePressed() -
*
*
*
*
*
* @param evt
* MouseEvent
* @exception *
* @see
*/
public void mousePressed(MouseEvent evt) {
if (evt.isPopupTrigger()) {
createPopup(evt.getPoint());
}
}
/**
* mouseReleased() -
*
*
*
*
*
* @param evt
* MouseEvent
* @exception *
* @see
*/
public void mouseReleased(MouseEvent evt) {
if (evt.isPopupTrigger()) {
createPopup(evt.getPoint());
}
}
/**
* mouseClicked() -
*
*
*
*
*
* @param evt
* MouseEvent
* @exception *
* @see
*/
public void mouseClicked(MouseEvent evt) {
if (evt.isPopupTrigger()) {
if (this.isEnabled()) {
createPopup(evt.getPoint());
}
}
}
/**
* mouseEntered() -
*
*
*
*
*
* @param evt
* MouseEvent
* @exception *
* @see
*/
public void mouseEntered(MouseEvent evt) {
}
/**
* mouseExited() -
*
*
*
*
*
* @param evt
* MouseEvent
* @exception *
* @see
*/
public void mouseExited(MouseEvent evt) {
}
/**
* createPopup() -
*
*
*
*
*
* @param point
* Point
* @exception *
* @see
*/
protected void createPopup(Point point) {
popup = new JPopupMenu();
JMenuItem undo = new JMenuItem("Undo");
undo.setMnemonic('Z');
JMenuItem mi = popup.add(undo);
mi.addActionListener(this);
JMenuItem redo = new JMenuItem("Redo");
// redo.setMnemonic('Z');
mi = popup.add(redo);
mi.addActionListener(this);
popup.addSeparator();
JMenuItem copy = new JMenuItem("Copy");
copy.setMnemonic('C');
mi = popup.add(copy);
mi.addActionListener(this);
JMenuItem cut = new JMenuItem("Cut");
cut.setMnemonic('X');
mi = popup.add(cut);
mi.addActionListener(this);
JMenuItem paste = new JMenuItem("Paste");
paste.setMnemonic('V');
mi = popup.add(paste);
mi.addActionListener(this);
popup.addSeparator();
JMenuItem open = new JMenuItem("Open");
open.setMnemonic('O');
mi = popup.add(open);
mi.addActionListener(this);
JMenuItem save = new JMenuItem("Save");
save.setMnemonic('S');
mi = popup.add(save);
mi.addActionListener(this);
popup.addSeparator();
JMenuItem print = new JMenuItem("Print");
print.setMnemonic('P');
mi = popup.add(print);
mi.addActionListener(this);
popup.addSeparator();
JMenuItem find = new JMenuItem("Find");
find.setMnemonic('F');
mi = popup.add(find);
mi.addActionListener(this);
JMenuItem replace = new JMenuItem("Replace");
replace.setMnemonic('R');
mi = popup.add(replace);
mi.addActionListener(this);
// Try to make the popup lightweight
point = getSuitableLocation(point, popup.getPreferredSize(), this);
popup.show(this, point.x, point.y);
}
/**
* actionPerformed() -
*
*
*
*
*
* @param evt
* ActionEvent
* @exception *
* @see
*/
public void actionPerformed(ActionEvent evt) {
JMenuItem mi = (JMenuItem) evt.getSource();
if (mi.getActionCommand().equals("Undo")) {
undo.undo();
} else if (mi.getActionCommand().equals("Redo")) {
undo.redo();
} else if (mi.getActionCommand().equals("Copy")) {
this.copy();
} else if (mi.getActionCommand().equals("Cut")) {
this.cut();
} else if (mi.getActionCommand().equals("Paste")) {
this.paste();
} else if (mi.getActionCommand().equals("Save")) {
this.saveAs();
} else if (mi.getActionCommand().equals("Open")) {
this.openFile();
} else if (mi.getActionCommand().equals("Print")) {
try {
print();
} catch (PrinterException e) {
// Do nothing ....
}
} else if (mi.getActionCommand().equals("Find")) {
find();
} else if (mi.getActionCommand().equals("Replace")) {
replace();
}
this.repaint();
}
/**
* getSuitableLocation() -
*
*
*
*
*
* @param point
* Point
* @param d
* Dimension
* @param c
* Component
* @return Point * @exception * @see
*/
protected Point getSuitableLocation(Point point, Dimension d, Component c) {
// First locate the parent JFrame or JDialog
Component topLevel = getComponentContainer(c);
if (topLevel != null) {
int newX; // New proposed x co-ordinate
int newY; // New proposed y co-ordinate
// We have a top-level parent
Rectangle parentBounds = topLevel.getBounds(); // Parent bounds,
// screen-relative
// Get proposed location, relative to the screen
SwingUtilities.convertPointToScreen(point, c);
if ((point.x + d.width) > (parentBounds.x + parentBounds.width)) {
// Popup overhangs to the right
newX = (parentBounds.x + parentBounds.width) - d.width;
} else {
newX = point.x;
}
if ((point.y + d.height) > (parentBounds.y + parentBounds.height)) {
// Popup ends below frame
newY = (parentBounds.y + parentBounds.height) - d.height;
} else {
newY = point.y;
}
// Change location only if necessary AND if
// we can make the popup fit inside the frame
if ((newX >= 0) && (newY >= 0)) {
point.x = newX;
point.y = newY;
}
// Convert back to relative co-ordinates
SwingUtilities.convertPointFromScreen(point, c);
}
return point;
}
private void replace() {
String textToReplace = this.getSelectedText().toUpperCase();
if (null == textToReplace)
return;
String replaceText = (String) JOptionPane.showInputDialog(this.getRootPane(), "Replace",
"Replace selected text with", JOptionPane.INFORMATION_MESSAGE, null, null, null);
try {
String text = getDocument().getText(0, getDocument().getLength());
int startPosition = text.toUpperCase().indexOf(textToReplace, m_startPosition);
while (startPosition != -1) {
this.setSelectionStart(startPosition);
this.setSelectionEnd(startPosition + textToReplace.length());
this.setSelectionColor(Color.red);
int option = JOptionPane.showConfirmDialog(this.getRootPane(), "Do you want to replace ?", "Replace ?",
JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE);
if (option == JOptionPane.YES_OPTION) {
this.replaceSelection(replaceText);
m_startPosition = startPosition + replaceText.length() + 1;
} else {
m_startPosition = startPosition + textToReplace.length() + 1;
}
text = getDocument().getText(0, getDocument().getLength());
startPosition = text.toUpperCase().indexOf(textToReplace, m_startPosition);
}
m_startPosition = 0;
} catch (BadLocationException ex) {
_log.error("Error replacing text:", ex);
}
}
private void find() {
String findText = null;
Object findObj = JOptionPane.showInputDialog(this.getRootPane(), "Find ", "Find",
JOptionPane.INFORMATION_MESSAGE, null, null, this.getSelectedText());
if (findObj instanceof String) {
findText = ((String) findObj).toUpperCase();
try {
String text = getDocument().getText(0, getDocument().getLength());
int startPosition = text.toUpperCase().indexOf(findText, m_startPosition);
if (startPosition != -1) {
this.setSelectionStart(startPosition);
this.setSelectionEnd(startPosition + findText.length());
this.setSelectionColor(Color.red);
m_startPosition = startPosition + findText.length() + 1;
} else {
m_startPosition = 0;
}
} catch (BadLocationException ex) {
_log.error("Error finding text:", ex);
}
}
}
/**
* getComponentContainer() -
*
*
*
*
*
* @param c
* Component
* @return Component * @exception * @see
*/
private Component getComponentContainer(Component c) {
Component topLevel = c;
while ((topLevel != null) && !(topLevel instanceof JFrame) && !(topLevel instanceof JDialog)) {
topLevel = topLevel.getParent();
}
return topLevel;
}
/**
*
* @version $Id: StreamEditorPane.java,v 1.10 2002/01/11 20:06:02 simon Exp
* $
* @author Simon Allen
*/
class UndoHandler implements UndoableEditListener {
/**
* Messaged when the Document has created an edit, the edit is added to
* <code>undo</code>, an instance of UndoManager.
*
* @param e
* UndoableEditEvent
* @see javax.swing.event.UndoableEditListener#undoableEditHappened(UndoableEditEvent)
*/
public void undoableEditHappened(UndoableEditEvent e) {
undo.addEdit(e.getEdit());
undoAction.update();
redoAction.update();
}
}
/**
*
* @version $Id: StreamEditorPane.java,v 1.10 2002/01/11 20:06:02 simon Exp
* $
* @author Simon Allen
*/
class UndoAction extends AbstractAction {
/**
*
*/
private static final long serialVersionUID = -1274054242153556791L;
public UndoAction() {
super("Undo");
this.setEnabled(false);
}
/**
* Method actionPerformed.
*
* @param e
* ActionEvent
* @see java.awt.event.ActionListener#actionPerformed(ActionEvent)
*/
public void actionPerformed(ActionEvent e) {
try {
undo.undo();
} catch (CannotUndoException ex) {
_log.error("Error undoing text:", ex);
}
update();
redoAction.update();
}
protected void update() {
if (undo.canUndo()) {
this.setEnabled(true);
putValue(Action.NAME, undo.getUndoPresentationName());
} else {
this.setEnabled(false);
putValue(Action.NAME, "Undo");
}
}
}
/**
*
* @version $Id: StreamEditorPane.java,v 1.10 2002/01/11 20:06:02 simon Exp
* $
* @author Simon Allen
*/
class RedoAction extends AbstractAction {
/**
*
*/
private static final long serialVersionUID = 519980226158345645L;
public RedoAction() {
super("Redo");
this.setEnabled(false);
}
/**
* Method actionPerformed.
*
* @param e
* ActionEvent
* @see java.awt.event.ActionListener#actionPerformed(ActionEvent)
*/
public void actionPerformed(ActionEvent e) {
try {
undo.redo();
} catch (CannotRedoException ex) {
_log.error("Error redoing text:", ex);
}
update();
undoAction.update();
}
protected void update() {
if (undo.canRedo()) {
this.setEnabled(true);
putValue(Action.NAME, undo.getRedoPresentationName());
} else {
this.setEnabled(false);
putValue(Action.NAME, "Redo");
}
}
}
}