/*
* Copyright (c) Ian F. Darwin, http://www.darwinsys.com/, 1996-2002.
* All rights reserved. Software written by Ian F. Darwin and others.
* $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Java, the Duke mascot, and all variants of Sun's Java "steaming coffee
* cup" logo are trademarks of Sun Microsystems. Sun's, and James Gosling's,
* pioneering role in inventing and promulgating (and standardizing) the Java
* language and environment is gratefully acknowledged.
*
* The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for
* inventing predecessor languages C and C++ is also gratefully acknowledged.
*/
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Point2D;
import java.io.IOException;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
* MVC Implementation
*
* @author Ian Darwin, http://www.darwinsys.com/
* @version $Id: MVCDemo.java,v 1.3 2004/03/21 00:44:36 ian Exp $
*/
public class MVCDemo {
/** "main program" method - construct and show */
public static void main(String[] av) {
// Create the data model
final Model model = new Model();
// create a JFrame to hold it all.
final JFrame f = new JFrame("MVC");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container cp = f.getContentPane();
JPanel tp = new JPanel();
cp.add(tp, BorderLayout.NORTH);
tp.add(new JLabel("New value:"));
final JTextField tf = new JTextField(10);
tp.add(tf);
tf.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
model.add(tf.getText());
tf.setText("");
}
});
JPanel p = new JPanel();
// The first View is a JTextArea subclassed to have
// an easy way of setting the data from a java.util.List
final TextView tv = new TextView();
model.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent evt) {
Object o = evt.getSource();
Model m = (Model) o;
tv.setListData(m.getData());
}
});
tv.setBackground(Color.RED);
tv.setSize(100, 100);
p.add(tv);
// The second View is the simplistic Grapher program from
// the Java Cookbook "Graphics" chapter (../graphics/Grapher.java)
final Grapher vv = new Grapher();
model.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent evt) {
Object o = evt.getSource();
Model m = (Model) o;
vv.setListData(m.getData());
}
});
vv.setBackground(Color.YELLOW);
vv.setSize(100, 100);
p.add(vv);
cp.add(p, BorderLayout.CENTER);
f.pack();
f.setLocation(100, 100);
f.setVisible(true);
}
}
class TextView extends JTextArea {
public TextView() {
super(20, 20);
}
public void setListData(ArrayList l) {
setText("");
for (int i = 0; i < l.size(); i++) {
append((String) l.get(i));
append("\n");
}
}
}
class Model {
private ArrayList list = new ArrayList();
public void add(String s) {
list.add(s);
fireChange();
}
public ArrayList getData() {
return list;
}
// Sun recommends using javax.swing.EventListenerList, but this is easier
ArrayList changeListeners = new ArrayList();
public void addChangeListener(ChangeListener cl) {
changeListeners.add(cl);
}
public void removeChangeListener(ChangeListener cl) {
changeListeners.remove(cl);
}
protected void fireChange() {
ChangeEvent evt = new ChangeEvent(this);
for (int i = 0; i < changeListeners.size(); i++) {
ChangeListener cl = (ChangeListener) changeListeners.get(i);
cl.stateChanged(evt);
}
}
}
class Grapher extends JPanel {
/** Multiplier for range to allow room for a border */
public final static double BORDERFACTOR = 1.1f;
/** The list of Point points. */
protected ArrayList data;
/** The minimum and maximum X values */
protected double minx = Integer.MAX_VALUE, maxx = Integer.MIN_VALUE;
/** The minimum and maximum Y values */
protected double miny = Integer.MAX_VALUE, maxy = Integer.MIN_VALUE;
/** The range of X and Y values */
protected double xrange, yrange;
public Grapher() {
data = new ArrayList();
figure();
}
/**
* Set the list data from a list of Strings, where the x coordinate is
* incremented automatically, and the y coordinate is made from the String
* in the list.
*/
public void setListDataFromYStrings(ArrayList newData) {
data.clear();
for (int i = 0; i < newData.size(); i++) {
Point2D p = new Point2D.Double();
p.setLocation(i, java.lang.Double.parseDouble((String) newData
.get(i)));
data.add(p);
}
figure();
}
/** Set the list from an existing List, as from GraphReader.read() */
public void setListData(ArrayList newData) {
data = newData;
figure();
}
/** Compute new data when list changes */
private void figure() {
// find min & max
for (int i = 0; i < data.size(); i++) {
Point2D d = (Point2D) data.get(i);
if (d.getX() < minx)
minx = d.getX();
if (d.getX() > maxx)
maxx = d.getX();
if (d.getY() < miny)
miny = d.getY();
if (d.getY() > maxy)
maxy = d.getY();
}
// Compute ranges
xrange = (maxx - minx) * BORDERFACTOR;
yrange = (maxy - miny) * BORDERFACTOR;
}
/**
* Called when the window needs painting. Computes X and Y range, scales.
*/
public void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension s = getSize();
if (data.size() < 2) {
g.drawString("Insufficient data: " + data.size(), 10, 40);
return;
}
// Compute scale factors
double xfact = s.width / xrange;
double yfact = s.height / yrange;
// Scale and plot the data
for (int i = 0; i < data.size(); i++) {
Point2D d = (Point2D) data.get(i);
double x = (d.getX() - minx) * xfact;
double y = (d.getY() - miny) * yfact;
// Draw a 5-pixel rectangle centered, so -2 both x and y.
// AWT numbers Y from 0 down, so invert:
g.drawRect(((int) x) - 2, s.height - 2 - (int) y, 5, 5);
}
}
public Dimension getPreferredSize() {
return new Dimension(150, 150);
}
public static void main(String[] args) throws IOException {
final JFrame f = new JFrame("Grapher");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Grapher grapher = new Grapher();
f.setContentPane(grapher);
f.setLocation(100, 100);
f.pack();
ArrayList data = new ArrayList();
data.add("a");
grapher.setListData(data);
f.setVisible(true);
}
}