Sindbad~EG File Manager
/**
* Diagrammer.java
*
* Created on October 23, 2006, 9:58 PM
*
* Copyright (C) 2006 Christopher Mathenia
*
* 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.
*
* This program 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 General Public License for more details.
*/
/* 10.23.06 Beeson changed calls to value() to setLabelFromString */
/* 10.23.06 Beeson changed the way startData is called since now it's in scripts. */
package org.dynamicgeometry.diagrammer;
import java.util.*;
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import org.dynamicgeometry.scripts.*;
public class Diagrammer extends JApplet implements ActionListener, MenuListener
{
private static final int READY = 0; // state of applet is ready for user action
private static final int UNSELECT_OR_DRAG = 1; // mouse pressed on selected point, so either unselect or drag
private static final int SELECT_OR_DRAG = 2; // mouse pressed on unselected point, so either select or drag
private static final int UNSELECT = 3; // mouse pressed on selected non-draggable point (zero isInput)
private static final int SELECT = 4; // mouse pressed on non-selected, non-draggable point (zero isInput)
private static final int DRAG = 5; // mouse dragged, so set state to drag
private static final int DRAW_POINT_OR_SEGMENT = 6; // mouse pressed on canvas, so either draw point or segment
private static final int DRAW_SEGMENT = 7; // mouse dragged, so draw segment
// menu name and primitive menu items
private static final String MENU_TITLE = "Construct";
private String[] primitiveMenuItems =
{
"Line","Ray","Segment","Triangle","Quadrilateral","Circle","Arc","Extend","Intersect Two Lines",
"Intersect Line and Circle 1","Intersect Line and Circle 2","Intersect Two Circles (R)","Intersect Two Circles (L)"
};
// point and non-point labels
private static final String[] pointLabel = { "A","B","C","D","E","F","G","H","I","J","K","L","M" };
private static final String[] objectLabel = { "n","o","p","q","r","s","t","u","v","w","x","y","z" };
// keep track of which labels to use
private int pointCounter;
private int objectCounter;
private int pointRound = 0;
private int objectRound = 0;
// to set an object isInput
private static final int IS_INPUT = 0;
private static final int NOT_INPUT = 1;
// parameters passed in from webpage
private boolean testMode;
private String testerResult; // to display test result
private String whichConstruction;
private String[] startConstructions; // spec number 12. list of constructions can be passed in for menu
private int state; // holds the various states of applet
private boolean shiftDown; // holds state of shift key
private boolean disable; // if true, user cannot draw anything, only drag
private ArrayList<GeometricObject> theFigure; // holds all objects in order of creation
private ArrayList<GeometricObject> selected; // holds all selected objects in order of selection
private Stack<ArrayList<GeometricObject>> historyFigure; // holds theFigure at each state for undo menu
private Stack<Integer[]> historyLabel; // holds labels at each state for undo menu
private Stack<String> historyUndoText; // keep track of undo items for display in menu
private java.awt.Point curPoint; // to calc distance traveled while dragging
private GeometricObject targetObject; // keeps track of object if mouse pressed on it
private JMenu menu;
private JMenuItem undoMenuItem;
private JMenuItem testModeMenuItem;
/**
* Initializes drawing canvas, menu, and variables when applet is first loaded.
*/
public void init()
{
setContentPane(new DynamicCanvas());
targetObject = null;
curPoint = null;
shiftDown = false;
testMode = false;
testerResult = null;
whichConstruction = null;
startConstructions = null;
disable = false;
theFigure = new ArrayList<GeometricObject>();
selected = new ArrayList<GeometricObject>();
historyLabel = new Stack<Integer[]>();
historyFigure = new Stack<ArrayList<GeometricObject>>();
historyUndoText = new Stack<String>();
initMenu();
}
/**
* Initializes necessary variables after init() or after user browses
* back to webpage. Also, retrieves parameter information from webpage,
* sets the menu and requests focus in browser window.
*/
public void start()
{
state = READY;
// initialize label variables
pointCounter = 0;
objectCounter = 0;
pointRound = 0;
objectRound = 0;
historyUndoText.push("undo"); // initialize undo history
getParameters();
if (whichConstruction != null)
{
try
{
Scripts s = Scripts.getScriptObject(whichConstruction);
ArrayList<GeometricObject> figure = s.startData(getWidth(),getHeight());
setFigure(figure);
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
menu.setVisible(true);
this.setVisible(true);
repaint();
getContentPane().requestFocusInWindow();
}
/**
* Clears resources when user browses away from webpage.
*/
public void stop()
{
targetObject = null;
curPoint = null;
historyUndoText.clear();
historyLabel.clear();
historyFigure.clear();
theFigure.clear();
selected.clear();
System.gc();
}
/**
* Releases resources when user closes browser.
*/
public void destroy()
{
historyUndoText = null;
historyLabel = null;
historyFigure = null;
theFigure = null;
selected = null;
System.gc();
}
/**
* Iterates through figure reseting the location of all GeometricObjects
* that have isInput field != 0. Location is set according to the location of
* the object's arguments used to create it. If location is undefined, then
* sets object visible to false.
*
* @param figure ArrayList<GeometricObject> containing constructed GeometricObjects
*/
public void updateConstructions(ArrayList<GeometricObject> figure)
{
SymbolTable symTbl = new SymbolTable(figure.toArray(new GeometricObject[figure.size()]));
GeometricObject newObj = null;
GeometricObject[] results;
boolean visible = false;
for (GeometricObject obj : figure)
{
// find constructed point objects
if (obj.getIsInput() != IS_INPUT && obj instanceof Point && obj.getConstruction() != null)
{
try
{
results = symTbl.Execute1("", obj.getConstruction(), obj.getArgs().toArray(new GeometricObject[obj.getArgs().size()]));
newObj = results[0];
}
catch(Exception e) // objects moved in such a way that it no longer exists
{
newObj = null;
e.printStackTrace(); // added by Beeson 12.22.06
}
if (newObj != null) // continue testing for null here in case sym table stops throwing null and returns null
{
((Point)obj).setX(((Point)newObj).getX());
((Point)obj).setY(((Point)newObj).getY());
if (!obj.isVisible())
{
visible = true;
for (GeometricObject arg : obj.getArgs())
{
if (!arg.isVisible())
{
visible = false;
break;
}
}
if (visible)
{
obj.setVisible(true);
}
}
}
else // newObj null so make invisible if not already
{
if (obj.isVisible())
obj.setVisible(false);
}
}
if (obj.isVisible()) // check for arguments changed to visible false
{
for(GeometricObject arg : obj.getArgs())
{
if (!arg.isVisible())
{
obj.setVisible(false);
break;
}
}
}
else // check for all arguments visible true
{
visible = true;
for (GeometricObject arg : obj.getArgs())
{
if (!arg.isVisible())
{
visible = false;
break;
}
}
if (visible && obj.getIsInput() == IS_INPUT)
{ // args of non input object could be visible while obj is not
obj.setVisible(true);
}
}
}
}
/**
* Resets Diagrammer. If disable is true, then state set to DISABLED,
* otherwise state READY. If DISABLED, user can only drag and select
* objects. User cannot create objects and all menu items are disabled.
*
* @param disable boolean indicating whether Diagrammer should
* enter DISABLED state
*/
public void disableDiagrammer(boolean disable)
{
//stop();
this.disable = disable;
//start();
repaint();
}
/**
* setSelected calls setSelection which sets the corresponding
* object selection to true and adds object to selected array.
*
* @param i int index of object in theFigure to get selection set
* @param b boolean: true indicates selection true. false indicates selection false.
*/
public void setSelected(int i, boolean b)
{
if (i < theFigure.size())
{
setSelection(theFigure.get(i), b);
}
}
/**
* setColor applies the given Color to the object in theFigure
* that corresponds to the given index.
*
* @param i int index of object in theFigure to get color set
* @param c Color c to set object
*/
public void setColor(int i, Color c)
{
if (i < theFigure.size())
{
theFigure.get(i).setColor(c);
}
}
/**
* setLevel applies the given int level to the object in theFigure
* that corresponds to the given index.
*
* @param i int index of object in theFigure to get level set
* @param l int level to set object
*/
public void setLevel(int i, int l)
{
if (i < theFigure.size())
{
theFigure.get(i).setLevel(l);
}
}
/**
* setFigure sets the passed in ArrayList<GeometricObject> as theFigure.
* Resets selected according to new ArrayList. Add label to object if needed.
*
* @param newFigure ArrayList containing constructed GeometricObjects
*
*/
public void setFigure(ArrayList<GeometricObject> newFigure)
{
theFigure = newFigure;
selected.clear();
for (GeometricObject obj : theFigure)
{
if (obj.isSelected())
{
selected.add(obj);
}
if (obj.getLabel() == null)
{
if (obj instanceof Point)
{
obj.setLabelFromString(getPointLabel());
}
else
{
obj.setLabelFromString(getObjectLabel());
}
}
}
updateConstructions(theFigure);
repaint();
}
/**
* getFigure returns reference to theFigure
*
* @return ArrayList<GeometrictObject> theFigure
*/
public ArrayList<GeometricObject> getFigure()
{
return theFigure;
}
/**
* getSelected returns reference to selected
*
* @return ArrayList<GeometrictObject> selected
*/
public ArrayList<GeometricObject> getSelected()
{
return selected;
}
/**
* addObject adds object to theFigure
*
* @param obj GeometricObject to get added to theFigure
*/
public void addObject(GeometricObject obj)
{
theFigure.add(obj);
if (obj.isSelected())
{
selected.add(obj);
}
if (obj.getLabel() == null)
{
if (obj instanceof Point)
{
obj.setLabelFromString(getPointLabel());
}
else
{
obj.setLabelFromString(getObjectLabel());
}
}
}
/**
* removeObject removes object corresponding to given int index from theFigure
*
* @param i int index of object to get removed from theFigure
*/
public void removeObject(int i)
{
GeometricObject obj = theFigure.remove(i);
if (obj != null && obj.isSelected())
{
selected.remove(obj);
}
}
/**
* actionPerformed is called when the user selects a menu item. actionPerformed creates a new SymbolTable by
* passing an array of selected objects created from the selected ArrayList<GeometricObject>. Then SymbolTable
* calls Execute from this SymbolTable object. That is, actionPerformed identifies the action
* called and calls execute passing in the corresponding command and selected objects. Appends the object
* returned by SymbolTable.execute to theFigure.
*
* @param e ActionEvent representing an action
*/
public void actionPerformed(ActionEvent e)
{
GeometricObject[] args = null;
GeometricObject newObj = null;
GeometricObject[] results;
String action = e.getActionCommand();
int index = 0;
if (action.equals(historyUndoText.peek())) // Undo
{
undo();
}
else if (action.equals(testModeMenuItem.getText())) // Tester
{
try
{
Tester tester = new Tester(this);
String result = tester.check(whichConstruction);
if (result.equals("yes"))
{
//testerResult = "Pass";
tester.updateDatabase(whichConstruction);
javax.swing.JOptionPane.showMessageDialog(this, "The answer is correct.", "You did it!", javax.swing.JOptionPane.INFORMATION_MESSAGE);
} else {
//testerResult = "Fail";
javax.swing.JOptionPane.showMessageDialog(this, result, "Oops...", javax.swing.JOptionPane.ERROR_MESSAGE);
}
}
catch (Exception ex)
{
System.out.println("Tester check.");
ex.printStackTrace();
}
}
else
{
setHistory("Create " + action);
if (action.equals(primitiveMenuItems[index++])) // Line
{
args = new GeometricObject[2];
args[0] = selected.get(0);
args[1] = selected.get(1);
newObj = getConstructedObject("line", args, IS_INPUT);
}
else if (action.equals(primitiveMenuItems[index++])) // Ray
{
args = new GeometricObject[2];
args[0] = selected.get(0);
args[1] = selected.get(1);
newObj = getConstructedObject("ray", args, IS_INPUT);
}
else if (action.equals(primitiveMenuItems[index++])) // Segment
{
args = new GeometricObject[2];
args[0] = selected.get(0);
args[1] = selected.get(1);
newObj = getConstructedObject("segment", args, IS_INPUT);
}
else if (action.equals(primitiveMenuItems[index++])) // Triangle
{
newObj = new Triangle();
for (GeometricObject arg : selected)
{
newObj.addArg(arg);
}
newObj.setIsInput(IS_INPUT);
newObj.setLabelFromString(getObjectLabel());
newObj.setVisible(true);
}
else if (action.equals(primitiveMenuItems[index++])) // Quadrilateral
{
newObj = new Quadrilateral();
for (GeometricObject arg : selected)
{
newObj.addArg(arg);
}
newObj.setIsInput(IS_INPUT);
newObj.setLabelFromString(getObjectLabel());
newObj.setVisible(true);
}
else if (action.equals(primitiveMenuItems[index++])) // Circle
{
args = new GeometricObject[2];
args[0] = selected.get(0);
args[1] = selected.get(1);
newObj = getConstructedObject("circle", args, IS_INPUT);
}
else if (action.equals(primitiveMenuItems[index++])) // Arc
{
// arc( Point Point, Point A, Point B ) - arc from A to B clockwise on Circle C
args = new GeometricObject[4];
int i = 0;
for (GeometricObject selectedObj : selected)
{
if (selectedObj.getClass().getName().equals("org.dynamicgeometry.diagrammer.Circle"))
{
args[i++] = selectedObj.getArgs().get(0);
args[i++] = selectedObj.getArgs().get(1);
setSelection(selectedObj, false);
theFigure.remove(selectedObj);
break; // found circle, so break
}
}
for (GeometricObject selectedObj : selected)
{
// covers segment, ray
if (selectedObj instanceof Line)
{
args[i++] = selectedObj.getArgs().get(0); // start
args[i] = selectedObj.getArgs().get(1); // end
break; // found line, so break
}
}
newObj = getConstructedObject("arc", args, IS_INPUT);
}
else if (action.equals(primitiveMenuItems[index++])) // Extend
{
// extend(A,B,C,D) - constructs point E on ray AB (so B is between A and E) such that BE = CD
args = new GeometricObject[4];
int i = 0;
for (GeometricObject selectedObj : selected)
{
if (selectedObj.getClass().getName().equals("org.dynamicgeometry.diagrammer.Ray"))
{
args[i++] = selectedObj.getArgs().get(0); // start
args[i++] = selectedObj.getArgs().get(1); // end
}
}
if (i == 2) // not 2 Rays
{
for (GeometricObject selectedObj : selected)
{
if (selectedObj instanceof Line && !(selectedObj instanceof Ray))
{
args[i++] = selectedObj.getArgs().get(0); // start
args[i] = selectedObj.getArgs().get(1); // end
break; // found line, so break
}
}
}
newObj = getConstructedObject("extend", args, NOT_INPUT);
}
else if (action.equals(primitiveMenuItems[index++])) // Intersect Lines
{
newObj = getConstructedObject("intersectLines", parseIntersectLines(), NOT_INPUT);
}
else if (action.equals(primitiveMenuItems[index++])) // Intersect Line Circle1
{
newObj = getConstructedObject("intersectLineCircle1", parseIntersectLineCircle(), NOT_INPUT);
}
else if (action.equals(primitiveMenuItems[index++])) // Intersect Line Circle2
{
newObj = getConstructedObject("intersectLineCircle2", parseIntersectLineCircle(), NOT_INPUT);
}
else if (action.equals(primitiveMenuItems[index++])) // Intersect Circle1
{
newObj = getConstructedObject("intersectCircles1", parseIntersectCircles(), NOT_INPUT);
}
else if (action.equals(primitiveMenuItems[index++])) // Intersect Circle2
{
newObj = getConstructedObject("intersectCircles2", parseIntersectCircles(), NOT_INPUT);
}
else // non primitive construction
{
for (String script : Scripts.Euclid)
{
if (action.equals(script))
{
GeometricObject[] arg = new GeometricObject[selected.size()];
for (int i = 0; i < selected.size(); i++)
{
arg[i] = selected.get(i);
}
try
{
SymbolTable symTbl = new SymbolTable(theFigure.toArray(new GeometricObject[theFigure.size()]));
results = symTbl.Execute1(/*getPointLabel()*/"", action, arg); //selected.toArray(new GeometricObject[selected.size()]));
newObj = results[0];
if (!(newObj instanceof Point))
{
newObj.setLabelFromString(getObjectLabel());
checkFigure(newObj);
}
else
{
newObj.setLabelFromString(getPointLabel());
}
newObj.setIsInput(NOT_INPUT);
newObj.setVisible(true);
break; // found call, so break
}
catch(Exception ex)
{
System.out.println("this should never happen, b/c menu item wouldn't be enabled");
ex.printStackTrace();
}
break; // found so break
}
}
}
if (newObj != null)
{
theFigure.add(newObj);
// updateConstructions(theFigure);
}
} // end undo else
repaint();
}
/**
* Calls updateMenu() to set menu items appropriately when user selects menu
* @param e MenuEvent representing menu selection action
*/
public void menuSelected(MenuEvent e)
{
updateMenu();
}
/**
* Unused method from implemented abstract listener
* @param e MenuEvent representing canceled menu action
*/
public void menuCanceled(MenuEvent e)
{
}
/**
* Unused method from implemented abstract listener
* @param e MenuEvent representing Deselected menu action
*/
public void menuDeselected(MenuEvent e)
{
}
/*********** End Public Methods ***************/
/**
* getConstructedObject is a helper class for ActionPerformed.
* Instantiate SymbolTable based on selected objects and pass command and arguments
* to get a constructed object. If null is returned and object was suppose to be
* zero isInput object, then create object and give appropriate settings along with
* visible value of false (since its arguments are in a position that doesn't allow it
* to be created). If is not a zero isinput object and/or is returned, then set visible
* to true and continue on to give appropriate settings. Return the object.
*/
private GeometricObject getConstructedObject(String cmd, GeometricObject[] args, int input)
{
SymbolTable symTbl = new SymbolTable(theFigure.toArray(new GeometricObject[theFigure.size()]));
GeometricObject newObj = null;
GeometricObject[] results;
try
{
results = symTbl.Execute1("", cmd, args);
newObj = results[0];
}
catch(Exception ex)
{
System.out.println("this should never happen, b/c menu item would not be enabled");
ex.printStackTrace();
}
if (newObj != null) // continue testing for null in case symtable returns null instead of throwing
{
newObj.setVisible(true);
newObj.setIsInput(input);
if (newObj instanceof Point)
{
newObj.setLabelFromString(getPointLabel());
}
else
{
newObj.setLabelFromString(getObjectLabel());
}
}
return newObj;
}
/**
* Recursively checks if an object's arguments are in theFigure.
* If not, then sets appropriate settings and adds to theFigure.
*/
private void checkFigure(GeometricObject obj)
{
for (GeometricObject o : obj.getArgs())
{
if(!(o instanceof Point))
{
checkFigure(o);
}
if (!theFigure.contains(o))
{
o.setIsInput(NOT_INPUT);
o.setVisible(true);
if (o instanceof Point)
{
o.setLabelFromString(getPointLabel());
}
else
{
o.setLabelFromString(getObjectLabel());
}
theFigure.add(o);
}
}
}
/**
* setSelection sets a given object to the passed boolean value and updates
* selected array accordingly.
*
* If select is true
* 1. Object already selected: move object to top of selected list
* 2. Object not selected, then select object and add to selected list
*
* If select is false
* 1. Unselect object
* 2. Remove object from selected list
*/
private void setSelection(GeometricObject obj, boolean select)
{
if (select)
{
if (obj.isSelected()) // already selected, but move object to top of selected list
{
selected.remove(obj);
}
else // not already selected
{
obj.setSelected(select);
}
selected.add(obj);
}
else // unselect
{
obj.setSelected(select);
selected.remove(obj);
}
}
/**
* clearSelection sets each object's selection in selected array to false
* and removes all objects from selected array.
*/
private void clearSelection()
{
for (GeometricObject obj : selected)
{
obj.setSelected(false);
}
selected.clear();
}
/**
* setHistory adds the given ArrayList<GeometricObject> and undo text to
* the history stack and updates the history counters.
*/
private void setHistory(String text)
{
historyUndoText.push("undo " + text);
ArrayList<GeometricObject> ary = getCopyArray(theFigure);
historyFigure.push(ary);
Integer[] curState = new Integer[4];
curState[0] = new Integer(pointCounter);
curState[1] = new Integer(objectCounter);
curState[2] = new Integer(pointRound);
curState[3] = new Integer(objectRound);
historyLabel.push(curState);
for (GeometricObject obj : ary) // selection for undo is all false
{
obj.setSelected(false);
}
}
/**
* undo resets theFigure to the array at top of history stack, resets history pointers
* and removes undo text from top of history text stack. Lastly, clears all selected objects.
*/
private void undo()
{
historyUndoText.pop();
theFigure = historyFigure.pop();
Integer[] curState = historyLabel.pop();
pointCounter = curState[0].intValue();
objectCounter = curState[1].intValue();
pointRound = curState[2].intValue();
objectRound = curState[3].intValue();
clearSelection();
}
/**
* getCopyArray returns a duplicate ArrayList<GeometricObject> of given array.
* Creates a new ArrayList and calls helper methods to:
*
* For each object in array:
* 1. create new object in target at same index location.
* 2. copy settings of each of those objects
*
* Effectively, a deep clone is returned.
*
* This method set to public before demo to assist Tester work around
* a bug. Tester needs a true copy of theFigure with structure intact.
*/
public ArrayList<GeometricObject> getCopyArray(ArrayList<GeometricObject> source)
{
ArrayList<GeometricObject> target = new ArrayList<GeometricObject>();
copyArray(source, target);
copySettings(source, target);
return target;
}
/**
* copyArray creates a new object in target of same type for every object
* in source.
*
* The target array is returned.
*/
private ArrayList<GeometricObject> copyArray(ArrayList<GeometricObject> source, ArrayList<GeometricObject> target)
{
for (GeometricObject sourceObj : source)
{
if (sourceObj.getClass().getName().equals("org.dynamicgeometry.diagrammer.Point"))
{
target.add(new Point());
}
else if (sourceObj.getClass().getName().equals("org.dynamicgeometry.diagrammer.Segment"))
{
target.add(new Segment());
}
else if (sourceObj.getClass().getName().equals("org.dynamicgeometry.diagrammer.Ray"))
{
target.add(new Ray());
}
else if (sourceObj.getClass().getName().equals("org.dynamicgeometry.diagrammer.Line"))
{
target.add(new Line());
}
else if (sourceObj.getClass().getName().equals("org.dynamicgeometry.diagrammer.Triangle"))
{
target.add(new Triangle());
}
else if (sourceObj.getClass().getName().equals("org.dynamicgeometry.diagrammer.Quadrilateral"))
{
target.add(new Quadrilateral());
}
else if (sourceObj.getClass().getName().equals("org.dynamicgeometry.diagrammer.Arc"))
{
target.add(new Arc());
}
else if (sourceObj.getClass().getName().equals("org.dynamicgeometry.diagrammer.Circle"))
{
target.add(new Circle());
}
else
{
System.out.println("Illegal Object in theFigure");
}
}
return target;
}
/**
* copySettings applies the settings from each object in source array to
* target array.
*
* For each object in source:
* 1. set isVisible and isInput settings.
* 2. if object is Point, then apply coordinates; otherwise,
* set corresponding links to object arguments.
*
* The target array is returned.
*/
private ArrayList<GeometricObject> copySettings(ArrayList<GeometricObject> source, ArrayList<GeometricObject> target)
{
GeometricObject sourceObj = null;
GeometricObject targetObj = null;
for (int i = 0; i < source.size(); i++)
{
sourceObj = source.get(i);
targetObj = target.get(i);
// set variables - no selected b/c all objects in new are not selected
targetObj.setColor(sourceObj.getColor());
targetObj.setVisible(sourceObj.isVisible());
targetObj.setLineThickness(sourceObj.getLineThickness());
targetObj.setIsInput(sourceObj.getIsInput());
targetObj.setLevel(sourceObj.getLevel());
targetObj.setConstruction(sourceObj.getConstruction());
targetObj.setSelected(sourceObj.isSelected());
// set label
Label lbl = new Label();
lbl.setLabel(sourceObj.getLabel().toString());
lbl.setVisible(sourceObj.getLabel().getVisible());
targetObj.setLabel(lbl);
for (GeometricObject arg : sourceObj.getArgs()) // map links to arguments
{
try
{
targetObj.addArg(target.get(source.indexOf(arg)));
}
catch(Exception np)
{
// System.out.println("*** Copy Crasher *** " + arg);
// np.printStackTrace();
}
}
// if point, set location
if (sourceObj.getClass().getName().equals("org.dynamicgeometry.diagrammer.Point"))
{
((Point)targetObj).setX(((Point)sourceObj).getX());
((Point)targetObj).setY(((Point)sourceObj).getY());
}
}
return target;
}
/**
* getPointLabel returns next point label available.
*/
private String getPointLabel()
{
if (pointRound == 0 && pointCounter < pointLabel.length)
{
return pointLabel[pointCounter++];
}
else
{
if (pointCounter == pointLabel.length)
{
pointCounter = 0;
pointRound++;
}
return pointLabel[pointCounter++] + pointRound;
}
}
/**
* getObjectLabel returns next object label available.
*/
private String getObjectLabel()
{
if (objectRound == 0 && objectCounter < objectLabel.length)
{
return objectLabel[objectCounter++];
}
else
{
if (objectCounter == objectLabel.length)
{
objectCounter = 0;
objectRound++;
}
return objectLabel[objectCounter++] + objectRound;
}
}
/**
* getParameters retrieves parameters from webpage
*/
private void getParameters()
{
String param = getParameter("disable");
if (param != null)
{
this.disable = Boolean.parseBoolean(param);
param = null; // to be safe.
}
param = getParameter("testMode");
if (param != null)
{
this.testMode = Boolean.parseBoolean(param);
param = null; // to be safe.
}
param = getParameter("startConstruction");
if (param != null)
{
startConstructions = param.split(",");
}
this.whichConstruction = getParameter("whichConstruction");
//testing
// this.whichConstruction = "EquilateralTriangle";
// this.testMode = true;
}
/**
* returns array with appropriate arguments from selected for intersect lines
*/
private GeometricObject[] parseIntersectLines()
{
GeometricObject[] args = new GeometricObject[4];
int index = 0;
for (GeometricObject selectedObj : selected)
{
if (selectedObj instanceof Line) // covers segment, ray
{
args[index++] = selectedObj.getArgs().get(0); // start
args[index++] = selectedObj.getArgs().get(1); // end
}
}
return args;
}
/**
* returns array with appropriate arguments from selected for intersect line circle
*/
private GeometricObject[] parseIntersectLineCircle()
{
// intersectLineCircle1( Point A, Point B, Point C, Point D) -
// point of intersection of line AB with circle(C,D) that is nearer to the A end of line AB. if they meet
GeometricObject[] args = new GeometricObject[4];
int index = 0;
for (GeometricObject selectedObj : selected)
{
if (selectedObj instanceof Line) // covers segment, ray
{
args[index++] = selectedObj.getArgs().get(0); // start
args[index++] = selectedObj.getArgs().get(1); // end
break; // found line, so break
}
}
for (GeometricObject selectedObj : selected)
{
if (selectedObj.getClass().getName().equals("org.dynamicgeometry.diagrammer.Circle"))
{
args[index++] = selectedObj.getArgs().get(0); // center
args[index++] = selectedObj.getArgs().get(1); // circumference
break; // found circle, so break
}
}
return args;
}
/**
* returns array with appropriate arguments from selected for intersect circle
*/
private GeometricObject[] parseIntersectCircles()
{
GeometricObject[] args = new GeometricObject[2];
int index = 0;
for (GeometricObject selectedObj : selected)
{
if (selectedObj.getClass().getName().equals("org.dynamicgeometry.diagrammer.Circle"))
{
args[index++] = selectedObj;
}
}
return args;
}
/**
* initMenu instantiates a menu and adds menu items from primitiveMenuItems to menu.
* Also, initMenu adds undo menu item and adds menu to the menu bar of Diagrammer.
*/
private void initMenu()
{
menu = new JMenu(MENU_TITLE);
menu.addMenuListener(this);
JMenuItem menuItem = null;
undoMenuItem = new JMenuItem();
undoMenuItem.addActionListener(this);
menu.add(undoMenuItem); // undo
for (String item : primitiveMenuItems)
{
menuItem = new JMenuItem(item);
menuItem.addActionListener(this);
menu.add(menuItem);
}
testModeMenuItem = new JMenuItem("Check My Work"); // no null in action
testModeMenuItem.addActionListener(this);
JMenuBar menuBar = new JMenuBar();
menuBar.add(menu);
this.setJMenuBar(menuBar);
}
/**
* updateMenu sets menu items enabled according to what objects are currently selected in
* Diagrammer content pane.
*/
private void updateMenu()
{
for (int i = 0; i < menu.getItemCount(); i++)
{
menu.getItem(i).setEnabled(false);
}
if (!disable)
{
undoMenuItem.setText(historyUndoText.peek()); // set undo text top of stack
if (historyUndoText.size() > 1) // undo
{
undoMenuItem.setEnabled(true);
}
// count each type in selected to test what menuitems to enable
int points = 0;
int segments = 0;
int rays = 0;
int lines = 0;
int triangles = 0;
int arcs = 0;
int circles = 0;
for (GeometricObject obj : selected)
{
if (obj instanceof Point) points++;
else if (obj instanceof Segment) segments++;
else if (obj instanceof Ray) rays++;
else if (obj instanceof Line) lines++;
else if (obj instanceof Triangle) triangles++;
else if (obj instanceof Arc) arcs++;
else if (obj instanceof Circle) circles++;
}
try
{
// set menu items enabled according to what is currently selected
// SymbolTable symTbl = new SymbolTable(theFigure.toArray(new GeometricObject[theFigure.size()]));
SymbolTable symTbl = new SymbolTable(selected.toArray(new GeometricObject[selected.size()]));
if (selected.size() == 2 && points == 2)
{
menu.getItem(1).setEnabled(true); // Line
menu.getItem(2).setEnabled(true); // Ray
menu.getItem(3).setEnabled(true); // Segment
menu.getItem(6).setEnabled(true); // Circle
}
else if (selected.size() == 3 && points == 3)
{
menu.getItem(4).setEnabled(true); // Triangle
}
else if (selected.size() == 4 && points == 4)
{
menu.getItem(5).setEnabled(true); // Quadrilateral
}
else if (selected.size() <= 6 && (lines + rays + segments == 2) && (points == 4 || points == 3))
{
if (rays >= 1)
{
menu.getItem(8).setEnabled(true); // Extend (must have at least 1 Ray)
}
if (symTbl.Execute1("", "intersectLines", parseIntersectLines()) != null)
{
menu.getItem(9).setEnabled(true); // Insersect lines
}
}
else if (selected.size() <= 6 && (lines + rays + segments == 1) && circles == 1 && points <= 4 && points >= 2)
{
menu.getItem(7).setEnabled(true); // Arc
if (symTbl.Execute1("", "intersectLineCircle1", parseIntersectLineCircle()) != null)
{
menu.getItem(10).setEnabled(true); // intersectLineCircle1
}
if (symTbl.Execute1("", "intersectLineCircle2", parseIntersectLineCircle()) != null)
{
menu.getItem(11).setEnabled(true); // intersectLineCircle2
}
}
else if (selected.size() <= 6 && circles == 2 && points <= 4 && points >= 2)
{
if (symTbl.Execute1("", "intersectCircles1", parseIntersectCircles()) != null)
{
menu.getItem(12).setEnabled(true); // instersectCircle1
}
if (symTbl.Execute1("", "intersectCircles2", parseIntersectCircles()) != null)
{
menu.getItem(13).setEnabled(true); // intersectCircle2
}
}
// clear items in case testMode or whichConstruction updated
int max = primitiveMenuItems.length + 1; // undo
menu.remove(testModeMenuItem);
while (menu.getItemCount() > primitiveMenuItems.length + 1) // 2 = undo + testModeMenuItem
{
menu.remove(menu.getItemCount() - 1);
}
if (testMode)
{
testModeMenuItem.setEnabled(true);
menu.add(testModeMenuItem);
}
if (whichConstruction != null)
{
if (Scripts.earlier(whichConstruction, "NotInEuclid"))
{
GeometricObject[] arg = new GeometricObject[selected.size()];
for (int j = 0; j < selected.size(); j++)
{
arg[j] = selected.get(j);
}
JMenuItem menuItem = null;
for (String script : Scripts.Euclid)
{
if (Scripts.earlier(script,whichConstruction))
{
menuItem = new JMenuItem(script);
if (symTbl.Execute1("", script, arg) != null)
{
menuItem.setEnabled(true);
}
else
{
menuItem.setEnabled(false);
}
menuItem.addActionListener(this);
menu.add(menuItem);
}
}
if (Scripts.earlier(whichConstruction, "NotInEuclid"))
{
menuItem = new JMenuItem(whichConstruction);
if (symTbl.Execute1("", whichConstruction, arg) != null)
{
menuItem.setEnabled(true);
}
else
{
menuItem.setEnabled(false);
}
menuItem.addActionListener(this);
menu.add(menuItem);
}
}
}
else if (startConstructions != null)
{
GeometricObject[] arg = new GeometricObject[selected.size()];
for (int j = 0; j < selected.size(); j++)
{
arg[j] = selected.get(j);
}
JMenuItem menuItem = null;
for (String script : startConstructions)
{
menuItem = new JMenuItem(script);
if (symTbl.Execute1("", script, arg) != null)
{
menuItem.setEnabled(true);
}
else
{
menuItem.setEnabled(false);
}
menuItem.addActionListener(this);
menu.add(menuItem);
}
}
}
catch(Exception np)
{ // do nothing.. just testing for menu items enabled
}
} // end not disable
}
/**
* class DynamicCanvas provides the area (canvas) where objects are drawn.
*/
private class DynamicCanvas extends JPanel implements MouseListener, MouseMotionListener, KeyListener
{
/**
* Constructor for DynamicCanvas
*/
public DynamicCanvas()
{
addKeyListener(this);
addMouseListener(this);
addMouseMotionListener(this);
setBackground(Color.white);
}
/**
* If user presses mouse button while cursor is over canvas, then evaluates
* whether cursor was over an object or empty portion of canvas and applies
* selection and state of application accordingly.
*/
public void mousePressed(MouseEvent e)
{
java.awt.Point p = e.getPoint();
curPoint = p;
GeometricObject obj = null;
GeometricObject point = null;
GeometricObject geoObject = null;
// search last added point, if no point, then last added object.
for (ListIterator<GeometricObject> iter = theFigure.listIterator(theFigure.size()); iter.hasPrevious(); )
{
obj = iter.previous();
if (obj.isVisible() && obj.clickedOn(p.getX(), p.getY()))
{
if (obj instanceof Point)
{
if (obj.getIsInput() == IS_INPUT)
{
point = obj;
break; // found non-zero isinput Point, so break
}
else if (point == null)
{
point = obj; // found zero isinput Point, so keep looking
}
}
else if (geoObject == null)
{
geoObject = obj; // set to top segment and continue looking for point
}
}
}
if (point != null) // mouse down on point
{
targetObject = point;
if (point.isSelected())
{
if (point.getIsInput() != IS_INPUT)
{
state = UNSELECT;
}
else
{
state = UNSELECT_OR_DRAG;
}
}
else // point not selected
{
if (point.getIsInput() != IS_INPUT)
{
state = SELECT;
}
else
{
state = SELECT_OR_DRAG;
}
if (!shiftDown)
{
clearSelection();
}
setSelection(point, true);
}
}
else if (geoObject != null) // no point, but mouse down on top of object
{
targetObject = geoObject;
if (geoObject.isSelected())
{
state = UNSELECT_OR_DRAG;
}
else // segment not selected
{
state = SELECT_OR_DRAG;
if (!shiftDown)
{
clearSelection();
}
setSelection(geoObject, true);
// select geoObject parts
ArrayList<GeometricObject> args = geoObject.getArgs();
for (GeometricObject arg : args)
{
setSelection(arg, true);
}
}
}
else if (!disable) // draw point - mouse down on empty portion of canvas
{
state = DRAW_POINT_OR_SEGMENT;
setHistory("Create Point");
point = new Point(p.getX(), p.getY());
point.setVisible(true);
point.setIsInput(IS_INPUT);
point.setLabelFromString(getPointLabel());
targetObject = point;
theFigure.add(point);
if (!shiftDown) // set selection of new point
{
clearSelection();
}
else // shift down
{
setSelection(point, true);
}
}
this.repaint();
}
/**
* mouseDragged is called after mouse pressed and user drags mouse. Depending on
* state of application, either draws a segment or moves selected objects
* in accordance with mouse drag.
*/
public void mouseDragged(MouseEvent e)
{
java.awt.Point p = e.getPoint();
if (state == UNSELECT_OR_DRAG || state == SELECT_OR_DRAG)
{// state UNSELECT_OR_DRAG or SELECT_OR_DRAG first mouseDragged event only
// if (!disable) Beeson commented this out 12.22.06. Why was it here?
{
setHistory("Move");
}
state = DRAG;
}
if (state == DRAG) // state is DRAG, so drag!
{
// move all selected points relative to distance cursor traveled
double distanceX = p.getX() - curPoint.getX();
double distanceY = p.getY() - curPoint.getY();
for (GeometricObject selectedObj : selected)
{
if (selectedObj.getIsInput() == IS_INPUT && selectedObj.getClass().getName().equals("org.dynamicgeometry.diagrammer.Point"))
{
((Point)selectedObj).setX(((Point)selectedObj).getX() + distanceX);
((Point)selectedObj).setY(((Point)selectedObj).getY() + distanceY);
}
}
updateConstructions(theFigure); // updates constructed objects in theFigure
curPoint = p;
}
else if (state == DRAW_POINT_OR_SEGMENT) // start drawing segment
{
state = DRAW_SEGMENT;
Point endpoint = new Point(p.x, p.y); // end point for segment
endpoint.setVisible(true);
endpoint.setIsInput(IS_INPUT);
endpoint.setLabelFromString(getPointLabel());
theFigure.add(endpoint);
Segment segment = new Segment((Point)targetObject, endpoint);
segment.setVisible(true);
segment.setIsInput(IS_INPUT);
segment.setLabelFromString(getObjectLabel());
historyUndoText.pop(); // update undo menu text
historyUndoText.push("undo Create Segment and end Points");
theFigure.add(segment);
if (shiftDown)
{
setSelection(targetObject, true);
setSelection(endpoint, true);
setSelection(segment, true);
}
}
else if (state == DRAW_SEGMENT) // still drawing segment
{
GeometricObject obj = theFigure.get(theFigure.size() - 2); // get endpoint of segment
((Point)obj).setX(p.getX());
((Point)obj).setY(p.getY());
curPoint = p;
}
this.repaint();
}
/**
* mouseReleased is called after mouse pressed and user releases the button.
* A call is made to this method regardless of whether mouseDragged is called.
* Depending on the state of the application, either unselects an object,
* selects an object, unselects all objects except the object mouse pressed on.
*/
public void mouseReleased(MouseEvent e)
{
java.awt.Point p = e.getPoint();
if (state == UNSELECT_OR_DRAG || state == UNSELECT) // No drag, so UNSELECT
{
if (shiftDown) // UNSELECT and shift pressed, so unselect the clicked on object only
{
setSelection(targetObject, false);
if (targetObject.getIsInput() == IS_INPUT && targetObject.getClass().getName().equals("org.dynamicgeometry.diagrammer.Point"))
{
// if non-zero point, then also unselect any objects it is a part of
// don't want to check args of non-zero isinput
ArrayList<GeometricObject> unselectObjs = new ArrayList<GeometricObject>();
for (GeometricObject selectedObj : selected)
{
if (selectedObj.getIsInput() == IS_INPUT) // if selectedObj non-zero isinput, then don't want to unselect arguments
{
for (GeometricObject arg : selectedObj.getArgs()) // see if any arg constructing object is targetObject
{
if (arg == targetObject) // if an arg is targetObject, then add object to list to be unselected
{
unselectObjs.add(selectedObj);
}
}
}
}
for (GeometricObject obj : unselectObjs) // set selection for any unselectObj
{
setSelection(obj, false);
}
}
}
else // UNSELECT and shift not pressed, so unselect all except for clicked on object.
{
if (selected.size() == 1) // if single point, then unselect.
{
setSelection(targetObject, false);
}
else
{
clearSelection(); // seems easier to clear all, then reselect object
setSelection(targetObject, true);
if (targetObject.getIsInput() == IS_INPUT) // non-zero isinput objects get their arguments selected
{
for (GeometricObject arg : targetObject.getArgs()) // if re-selected target is not a point, then have to re-select its points
{
setSelection(arg, true);
}
}
}
}
}
// else if SELECT.. do nothing.. SELECT aready selected on mouse pressed
// else if DRAG do nothing.. no longer checking whether dragged on top of another
// else if SELECT_OR_DRAG do nothing.. no drag, so SELECT and already selected on mouse pressed
// else if DRAW_POINT_OR_SEGMENT do nothing.. no drag, so DRAW_POINT and point already drawn on mouse pressed
// else if DRAW_SEGMENT do nothing.. no longer checking whether dragged on top of another
state = READY;
targetObject = null;
curPoint = null;
this.repaint();
}
/**
* paintComponent is called after a call to repaint() via paint().
* Calls appropriate method to update the menu and calls draw method
* of each object in theFigure.
*/
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2D = (Graphics2D)g;
for (GeometricObject obj : theFigure)
{
obj.draw(g2D);
}
if (testerResult != null)
{
g.drawString("Result: " + testerResult, 5, 15);
testerResult = null;
}
this.requestFocusInWindow();
}
/**
* If shift key is pressed, then sets shiftsDown to true.
*/
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_SHIFT)
{
shiftDown = true;
}
}
/**
* If shift key is released, then sets shiftsDown to false.
*/
public void keyReleased(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_SHIFT)
{
shiftDown = false;
}
}
/**
* Unused method from implemented abstract listener
*/
public void mouseClicked(MouseEvent e)
{
}
/**
* Unused method from implemented abstract listener
*/
public void mouseEntered(MouseEvent e)
{
}
/**
* Unused method from implemented abstract listener
*/
public void mouseExited(MouseEvent e)
{
}
/**
* Unused method from implemented abstract listener
*/
public void mouseMoved(MouseEvent e)
{
}
/**
* Unused method from implemented abstract listener
*/
public void keyTyped(KeyEvent e)
{
}
} // end dynamicCanvas
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists