
package jp.riken.brain.ni.samuraigraph.figure.java2d;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.font.FontRenderContext;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPopupMenu;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import jp.riken.brain.ni.samuraigraph.base.SGAxis;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementAxisBreak;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementAxis;
import jp.riken.brain.ni.samuraigraph.base.SGICopiable;
import jp.riken.brain.ni.samuraigraph.base.SGIDisposable;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElement;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementGraph;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementGrid;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementLegend;
import jp.riken.brain.ni.samuraigraph.base.SGIMovable;
import jp.riken.brain.ni.samuraigraph.base.SGINode;
import jp.riken.brain.ni.samuraigraph.base.SGISelectable;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementShape;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementSignificantDifference;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementString;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementTimingLine;
import jp.riken.brain.ni.samuraigraph.base.SGIUndoable;
import jp.riken.brain.ni.samuraigraph.base.SGProperties;
import jp.riken.brain.ni.samuraigraph.base.SGPropertyDialog;
import jp.riken.brain.ni.samuraigraph.base.SGTuple2f;
import jp.riken.brain.ni.samuraigraph.base.SGUndoManager;
import jp.riken.brain.ni.samuraigraph.base.SGUtility;
import jp.riken.brain.ni.samuraigraph.base.SGUtilityText;
import jp.riken.brain.ni.samuraigraph.figure.SGFigureElement;
import jp.riken.brain.ni.samuraigraph.figure.SGISignificantDifferenceConstants;
import jp.riken.brain.ni.samuraigraph.figure.SGIStringConstants;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementSignificantDifference.SigDiffProperties;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;




/**
 * A class managing significant difference symbols.
 */
public class SGFigureElementSignificantDifference extends SGFigureElement
	implements SGIFigureElementSignificantDifference,
		SGISignificantDifferenceConstants,
		SGIStringConstants, CaretListener, ActionListener
{

	/**
	 * 
	 */
	private SGIFigureElementAxis mAxisElement = null;
	
	
	/**
	 * 
	 */
	private JTextField mEditField = null;


	/**
	 * 
	 */
	private int mFocusedX = 0;


	/**
	 * 
	 */
	private int mFocusedY = 0;



	
	
	/**
	 * A symbol which the user is editing the text.
	 */
	private SigDiffSymbol mEditingSymbol = null;
	


	/**
	 * 
	 */
	private SGSignificantDifferenceDialog mDialog = null;



	/**
	 * 
	 *
	 */
	public SGFigureElementSignificantDifference()
	{
		super();
		this.initEditField();
	}


	/**
	 * 
	 */
	public void dispose()
	{
		super.dispose();
		this.mDialog.dispose();
		this.mDialog = null;
		this.mAxisElement = null;
		this.mEditField = null;
	}



	/**
	 * 
	 */
	private boolean createSignificanceDialog()
	{

		final SGSignificantDifferenceDialog dg
			= new SGSignificantDifferenceDialog( this.mDialogOwner, true );

		this.mDialog = dg;

		return true;
	}



	/**
	 * ズーム
	 */
	public boolean zoom( final float ratio )
	{
		// hide the text field
		if( this.terminateEditField() == false )
		{
			return false;
		}

		super.zoom(ratio);

		this.onZoomed(ratio);

		return true;

	}



	/**
	 * 
	 * @return
	 */
	public boolean setDialogOwner( final Frame frame )
	{
		super.setDialogOwner(frame);
		this.createSignificanceDialog();
		return true;
	}



	/**
	 * 
	 */
	public boolean addSignificantDifferenceSymbol(
			final SGAxis xAxis, final SGAxis yAxis, final int x, final int y )
	{
		SigDiffSymbol sd = new SigDiffSymbol();
		sd.zoom(this.mMagnification);

		// set axes
		sd.mXAxis = xAxis;
		sd.mYAxis = yAxis;
		
		// set the location
		sd.setLocation( x, y );

		// create drawing elements
		sd.createDrawingElement();

		// set axis values
		sd.setAxisValuesWithShape();
		
		//
		this.addToList(sd);

		//
		this.setChanged(true);

		// initialize history
		sd.initPropertiesHistory();

		this.notifyToRoot();
		

		return true;
	}


	/**
	 * 
	 */
	public boolean addSignificantDifferenceSymbol( final int x, final int y )
	{
		if( this.getGraphRect().contains( x, y ) == false )
		{
			return false;
		}

		SGAxis xAxis = this.mAxisElement.getAxis( DEFAULT_SIGDIFF_HORIZONTAL_AXIS );
		SGAxis yAxis = this.mAxisElement.getAxis( DEFAULT_SIGDIFF_PERPENDICULAR_AXIS );

		return this.addSignificantDifferenceSymbol( xAxis, yAxis, x, y );
	}



	/**
	 * 
	 * @param el
	 * @return
	 */
	private boolean hideSigDiffSymbol( final SigDiffSymbol el )
	{
		this.hideObject(el);
		this.clearFocusedObjects();
		return true;
	}


	/**
	 * 
	 */
	private boolean onZoomed( final float ratio )
	{
		List list = this.mChildList;
		for( int ii=0; ii<list.size(); ii++ )
		{
			final SigDiffSymbol sd = (SigDiffSymbol)list.get(ii);
			sd.zoom(ratio);
		}

		return true;
	}

	
	/**
	 * 
	 * @param element
	 */
	public void setAxisElement( final SGIFigureElementAxis element )
	{
		this.mAxisElement = element;
	}

	
	/**
	 * 同期を取る。
	 */
	public boolean synchronize( final SGIFigureElement element, final String msg )
	{

		boolean flag = true;
		if( element instanceof SGIFigureElementGraph )
		{
			
		}
		else if( element instanceof SGIFigureElementString )
		{
			
		}
		else if( element instanceof SGIFigureElementLegend )
		{
			
		}
		else if( element instanceof SGIFigureElementAxis )
		{
			flag = this.synchronizeToAxisElement( (SGIFigureElementAxis)element, msg );
		}
		else if( element instanceof SGIFigureElementAxisBreak )
		{
			
		}
		else if( element instanceof SGIFigureElementSignificantDifference )
		{
			
		}
		else if( element instanceof SGIFigureElementTimingLine )
		{
			
		}
		else if( element instanceof SGIFigureElementGrid )
		{

		}
		else if( element instanceof SGIFigureElementShape )
		{

		}
		else
		{
			flag = element.synchronizeArgument( this, msg );
		}

		return flag;
	}


	
	private boolean synchronizeToAxisElement( SGIFigureElementAxis element, String msg )
	{
		ArrayList list = this.getVisibleChildList();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SigDiffSymbol el = (SigDiffSymbol)list.get(ii);
			el.setShapeWithAxesValues();
		}
		return true;
	}



	/**
	 * Synchronize the element given by the argument.
	 * @param element An object to be synchronized.
	 */
	public boolean synchronizeArgument( final SGIFigureElement element, final String msg )
	{
	    // this shouldn't happen
	    throw new Error();
	}


	/**
	 * 
	 */
	public SGProperties getProperties()
	{
		SGProperties p = new SigDiffElementProperties();
		if( this.getProperties(p) == false )
		{
			return null;
		}
		return p;
	}


	/**
	 * 
	 */
	public String getTagName()
	{
		return TAG_NAME_SIGNIFICANT_DIFFERENCE;
	}


	
	/**
	 * 
	 */
	public boolean writeProperty(Element el)
	{
		return true;
	}

	

	/**
	 * 
	 */
	public boolean readProperty( final Element element )
	{
		NodeList nList = element.getElementsByTagName( SGISignificantDifferenceConstants.TAG_NAME_SIGDIFF_SYMBOL );
		for( int ii=0; ii<nList.getLength(); ii++ )
		{
			Node node = nList.item(ii);
			if( node instanceof Element )
			{
				Element el = (Element)node;
				SigDiffSymbol sd = new SigDiffSymbol();
				if( sd.readProperty(el) == false )
				{
					return false;
				}
				sd.initPropertiesHistory();
				this.addToList( sd );
			}
		}
		
		return true;
	}


	/**
	 * 
	 */
	public void actionPerformed(ActionEvent e)
	{
		final Object source = e.getSource();
		final String command = e.getActionCommand();

		if( source.equals( this.mEditField ) )
		{
			this.terminateEditField();
		}

	}



	/**
	 * 
	 */
	public boolean setGraphRect(
		final float x, final float y, final float width, final float height )
	{
		if( super.setGraphRect(x,y,width,height) == false )
		{
			return false;
		}

		if( this.terminateEditField() == false )
		{
			return false;
		}

		List list = this.mChildList;
		for( int ii=0; ii<list.size(); ii++ )
		{
			final SigDiffSymbol el = (SigDiffSymbol)list.get(ii);
			el.setShapeWithAxesValues();			
		}

		return true;
	}



	/**
	 * 
	 */
	public boolean getMarginAroundGraphRect(
		SGTuple2f topAndBottom, SGTuple2f leftAndRight )
	{

		if( super.getMarginAroundGraphRect( topAndBottom, leftAndRight ) == false )
		{
			return false;
		}

		ArrayList sList = this.getVisibleChildList();
		ArrayList rectList = new ArrayList();
		for( int ii=0; ii<sList.size(); ii++ )
		{
			SigDiffSymbol el = (SigDiffSymbol)sList.get(ii);
			Rectangle2D rect = el.getElementBounds();
			rectList.add( rect );
		}
		if( rectList.size()==0 )
		{
			return true;
		}


		// 得られた矩形を結合する
		Rectangle2D uniRect = SGUtility.createUnion(rectList);


		// 結合した矩形から幅を求める
		final float top = this.mGraphRectY - (float)uniRect.getY();
		final float bottom = -( this.mGraphRectY + this.mGraphRectHeight )
			 + (float)( uniRect.getY() + uniRect.getHeight() );
		final float left = this.mGraphRectX - (float)uniRect.getX();
		final float right = -( this.mGraphRectX + this.mGraphRectWidth )
			 + (float)( uniRect.getX() + uniRect.getWidth() );


		// 引数に設定
		topAndBottom.x += top;
		topAndBottom.y += bottom;
		leftAndRight.x += left;
		leftAndRight.y += right;

		return true;
	}



	/**
	 * 
	 */
	public void paintGraphics( Graphics g, boolean clip )
	{
		final Graphics2D g2d = (Graphics2D)g;

		// draw significant difference symbols
		ArrayList list = this.getVisibleChildList();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SigDiffSymbol el = (SigDiffSymbol)list.get(ii);
			if( el.isValid() == false )
			{
				continue;
			}
			el.paintElement(g2d);
		}

		// draw symbols around all objects
		if( this.mSymbolsVisibleFlagAroundAllObjects )
		{
			for( int ii=0; ii<list.size(); ii++ )
			{
				SigDiffSymbol el = (SigDiffSymbol)list.get(ii);
				if( el.isValid() == false )
				{
					continue;
				}
				ArrayList pList = el.getAnchorPointList();
				SGUtilityForFigureElementJava2D.drawAnchorAsChildObject( pList, g2d );
			}
		}

		// draw symbols around focused objects
		if( this.mSymbolsVisibleFlagAroundFocusedObjects )
		{
			ArrayList fList = this.getFocusedObjectsList();
			for( int ii=0; ii<fList.size(); ii++ )
			{
				SigDiffSymbol el = (SigDiffSymbol)fList.get(ii);
				if( el.isValid() == false )
				{
					continue;
				}
				ArrayList pList = el.getAnchorPointList();
				SGUtilityForFigureElementJava2D.drawAnchorAsFocusedObject( pList, g2d );
			}
		}

	}

	

	/**
	 * 
	 */
	public void caretUpdate( final CaretEvent e )
	{
		final String str = this.mEditField.getText();

		if( this.mEditingSymbol!=null )
		{
			final Font font = new Font(
				this.mEditingSymbol.getFontName(),
				this.mEditingSymbol.getFontStyle(),
				(int)(this.mEditingSymbol.getFontSize()*this.getMagnification()) );
			final Rectangle2D stringRect = font.getStringBounds(
				str, new FontRenderContext( null, false, false ) );
			
			final double width = stringRect.getWidth();
			if( width > this.mEditField.getWidth() )
			{
				this.mEditField.setSize(
					(int)( stringRect.getWidth() + this.getMagnification()*this.mEditingSymbol.getFontSize() ),
					this.mEditField.getHeight()
				);
			}
		}
	}



	/**
	 * 
	 * @param e
	 */
	public boolean onDrawingElement( final int x, final int y )
	{

		// significant difference symbols
		ArrayList list = this.getVisibleChildList();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SigDiffSymbol sd = (SigDiffSymbol)list.get(ii);
			if( sd.isValid() == false )
			{
				continue;
			}
			if( sd.contains(x,y) )
			{
				if( sd.isSelected() )
				{
					sd.mMouseLocation = sd.getMouseLocation(x,y);
					setMouseCursor( sd.getCursor( sd.mMouseLocation ) );
					return true;
				}
				setMouseCursor( Cursor.HAND_CURSOR );
				return true;
			}
		}

		return false;
	}




	/**
	 * 
	 */
	public boolean onMouseClicked( final MouseEvent e )
	{
		ArrayList list = this.getVisibleChildList();
		for( int ii=list.size()-1; ii>=0; ii-- )
		{
			SigDiffSymbol el = (SigDiffSymbol)list.get(ii);
			if( el.isValid() == false )
			{
				continue;
			}
			if( this.clickDrawingElements(el,e) )
			{
				return true;
			}
		}

		return false;
	}

	
	/**
	 * 
	 */
	private boolean clickDrawingElements(
		final SigDiffSymbol el, final MouseEvent e )
	{
		final int x = e.getX();
		final int y = e.getY();
		final int mod = e.getModifiers();
		final boolean ctrl  = (mod & InputEvent.CTRL_MASK)!=0;
		final boolean shift = (mod & InputEvent.SHIFT_MASK)!=0;
		final int cnt = e.getClickCount();

		// clicked on the line elements
		if( el.contains(x,y) )
		{
			// clicked on the string element
			if( el.getStringElement().contains(x,y) )
			{
				if( SwingUtilities.isLeftMouseButton(e) & cnt==1 )
				{
					if( el.isSelected() & !ctrl & !shift )
					{
						this.mEditingSymbol = el;
						this.showEditField( el );
					}
					else
					{
						this.updateFocusedObjectsList( el, e );
					}
				}
				else if( SwingUtilities.isRightMouseButton(e) & cnt==1 )
				{
					this.updateFocusedObjectsList(el,e);
					el.getPopupMenu().show( this.getComponent(), x, y );
				}
			}
			else
			// otherwise
			{
				this.updateFocusedObjectsList( el, e );
				if( SwingUtilities.isLeftMouseButton(e) & cnt==1 )
				{
					
				}
				else if( SwingUtilities.isLeftMouseButton(e) & cnt==2 )
				{
					this.setPropertiesOfSelectedObjects();
				}
				else if( SwingUtilities.isRightMouseButton(e) & cnt==1 )
				{
					el.getPopupMenu().show( this.getComponent(), x, y );
				}
			}

			return true;
		}

		return false;
	}

	
	
	/**
	 * 
	 */
	public void translateFocusedObjects( final int dx, final int dy )
	{
		if( this.terminateEditField() == false )
		{
			return;
		}

		super.translateFocusedObjects(dx,dy);
	}



	/**
	 * 
	 * @param e
	 */
	public boolean onMousePressed( final MouseEvent e )
	{
		
		if( this.terminateEditField() == false )
		{
			return false;
		}

		final int x = e.getX();
		final int y = e.getY();

		// significant difference symbols
		ArrayList list = this.getVisibleChildList();
		for( int ii=list.size()-1; ii>=0; ii-- )
		{
			SigDiffSymbol el = (SigDiffSymbol)list.get(ii);
			if( el.isValid() == false )
			{
				continue;
			}
			if( el.pressDrawingElements(e) )
			{
				this.mPressedPoint = e.getPoint();
				if( el.isSelected() )
				{
					this.mDraggableFlag = true;
				}
				return true;
			}
		}

		return false;
	}


	
	/**
	 * 
	 * @param e
	 */
	public boolean onMouseDragged( final MouseEvent e )
	{

		if( this.mDraggableFlag == false )
		{
			return false;
		}
		
		final int dx = e.getX() - this.mPressedPoint.x;
		final int dy = e.getY() - this.mPressedPoint.y;

		ArrayList list = this.getFocusedObjectsList();
		if( list.size()==1 )
		{
			SigDiffSymbol sd = (SigDiffSymbol)list.get(0);
			if( sd.isValid() == false )
			{
				return false;
			}
			if( sd.drag(e) == false )
			{
				return false;
			}

			sd.createDrawingElement();

			if( sd.setAxisValuesWithShape() == false )
			{
				return false;
			}
			if( sd.setShapeWithAxesValues() == false )
			{
				return false;
			}

			this.mPressedPoint = e.getPoint();

			return true;
			
		}
		for( int ii=0; ii<list.size(); ii++ )
		{
		    SigDiffSymbol sd = (SigDiffSymbol)list.get(ii);
		    
		    sd.translate(dx,dy);
		    
		    sd.createDrawingElement();
		    
		    if( sd.setAxisValuesWithShape() == false )
		    {
		        return false;
		    }
		    if( sd.setShapeWithAxesValues() == false )
		    {
		        return false;
		    }
		}
		
		this.mPressedPoint = e.getPoint();
		
		return true;
		
	}


	/**
	 * 
	 * @param e
	 */
	public boolean onMouseReleased( final MouseEvent e )
	{
/*
		ArrayList list = this.getFocusedObjectsList();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SigDiffSymbol sd = (SigDiffSymbol)list.get(ii);

			//
			SGProperties temp = sd.mTemporaryProperties;
			SGProperties p = sd.getProperties();
			if( p.equals(temp)==false )
			{
				sd.setChanged(true);
			}
			
			this.notifyToRoot();
		}
*/
		this.mDraggableFlag = false;

		return true;
	}

	
	/**
	 * 
	 * @return
	 */
	public boolean setTemporaryPropertiesOfFocusedObjects()
	{
		ArrayList list = this.getFocusedObjectsList();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SigDiffSymbol el = (SigDiffSymbol)list.get(ii);
			el.mTemporaryProperties = el.getProperties();
		}
		return true;
	}



	/**
	 * 
	 * @return
	 */
	public ArrayList getPropertyDialogObserverList()
	{
		return this.getFocusedObjectsList();
	}



	/**
	 * 
	 * @return
	 */
	public boolean setChangedFocusedObjects()
	{
		ArrayList list = this.getFocusedObjectsList();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SigDiffSymbol el = (SigDiffSymbol)list.get(ii);
			SGProperties temp = el.mTemporaryProperties;
			if( temp!=null )
			{
				SGProperties p = el.getProperties();
				if( p.equals(temp)==false )
				{
					el.setChanged(true);
				}
			}
		}
		return true;
	}

	
	/**
	 * 
	 * @return
	 */
	public boolean clearFocusedObjects()
	{
		if( super.clearFocusedObjects() == false )
		{
			return false;
		}
		
		if( this.terminateEditField() == false )
		{
			return false;
		}

		return true;
	}


	/**
	 * 
	 */
	public String toString()
	{
		return "SGSignificantDifferenceElement";
	}


	/**
	 * 
	 * @return
	 */
	public String getClassDescription()
	{
		return "Significant Difference Symbols";
	}


	/**
	 * 
	 */
	private boolean initEditField()
	{
		this.mEditField = new JTextField(10);
//		this.getComponent().setLayout(null);
//		this.getComponent().add(this.mEditField);
		this.mEditField.setVisible(false);
		this.mEditField.addActionListener(this);
		this.mEditField.addCaretListener(this);

		return true;
	}


	public void setComponent( JComponent com )
	{
		super.setComponent(com);
		com.add(this.mEditField);
	}



	/**
	 * 
	 */
	private boolean showEditField( final SigDiffSymbol el )
	{
		SGDrawingElementString2DExtended sElement
			= (SGDrawingElementString2DExtended)el.getStringElement();
		final JTextField tf = this.mEditField;

		final Rectangle2D rect = sElement.getElementBounds();
		final Rectangle2D sRect = sElement.getStringRect();

		final float fontSize = el.getMagnification()*el.getFontSize();

		final int x = (int)( rect.getX() - tf.getInsets().left );
		final int y = (int)( rect.getY() - fontSize/2.0f );
		final int w = (int)( sRect.getWidth() + fontSize );
		final int h = (int)( sRect.getHeight() + fontSize );

		tf.setLocation( x, y );
		tf.setSize( w, h );
		tf.setFont( new Font( el.getFontName(), el.getFontStyle(), (int)fontSize ) );
		tf.setForeground( el.getColor() );
		tf.setText( sElement.getString() );

		// show the text field
		tf.setVisible(true);
		tf.requestFocus();
		tf.setCaretPosition(0);

		return true;

	}


	/**
	 * 
	 */
	private boolean terminateEditField()
	{
		if( this.mEditField.isVisible() )
		{
			return this.commitEdit();
		}

		return true;
	}



	/**
	 * 
	 * @return
	 */
	private boolean hideEditField()
	{
		this.mEditField.setText("");
		this.mEditField.setVisible(false);
		return true;
	}



	/**
	 * 
	 * @return
	 */
	private boolean commitEdit()
	{
		if( this.mEditingSymbol==null )
		{
			return false;
		}

		String before = this.mEditingSymbol.getStringElement().getString();
		String after = this.mEditField.getText();
		if( SGUtilityText.isValidString(after) )
		{
			this.mEditingSymbol.setText( after );
			
			if( before.equals(after) == false )
			{
				this.mEditingSymbol.setChanged(true);
				this.notifyToRoot();
			}

			this.mEditingSymbol.createDrawingElement();
		}

		this.mEditingSymbol = null;
		this.hideEditField();
		this.repaint();
		
		return true;
	}



	/**
	 * 
	 */
	public boolean getProperties( final SGProperties p )
	{

		if( ( p instanceof SigDiffElementProperties ) == false )
		{
			return false;
		}

		SigDiffElementProperties gp = (SigDiffElementProperties)p;
		gp.visibleSigDiffSymbolList = this.getVisibleChildList();

		return true;

	}


	/**
	 * 
	 */
	public boolean setProperties( final SGProperties p )
	{
		if( ( p instanceof SigDiffElementProperties ) == false )
		{
			return false;
		}

		SigDiffElementProperties gp = (SigDiffElementProperties)p;

		boolean flag = this.setVisibleChildList( gp.visibleSigDiffSymbolList );
		if( !flag )
		{
			return false;
		}


		return true;

	}



	/**
	 * 
	 */
	public Element createElement( final Document document )
	{
		Element el = this.createThisElement( document );
		if( el==null )
		{
			return null;
		}

		ArrayList list = this.getVisibleChildList();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SigDiffSymbol sd = (SigDiffSymbol)list.get(ii);
			if( sd.isValid() == false )
			{
				continue;
			}

			Element elSigDiff = sd.createElement( document );
			if( elSigDiff==null )
			{
				return null;
			}
			el.appendChild( elSigDiff );
		}
		return el;
	}



//	/**
//	 * 
//	 * @return
//	 */
//	public boolean addPropertiesHistory( SGProperties p )
//	{
//
//		if( ( p instanceof SigDiffElementProperties ) == false )
//		{
//			return false;
//		}
//
//		boolean flag = super.addPropertiesHistory(p);		
//
//		return flag;
//	}



	/**
	 * 
	 */
	public boolean setMementoBackward()
	{
		boolean flag = super.setMementoBackward();
		if( !flag )
		{
			return false;
		}
		this.notifyChangeOnUndo();
		this.clearFocusedObjects();

		return true;
	}


	/**
	 * 
	 */
	public boolean setMementoForward()
	{
		boolean flag = super.setMementoForward();
		if( !flag )
		{
			return false;
		}
		this.notifyChangeOnUndo();
		this.clearFocusedObjects();

		return true;
	}



	/**
	 * Create copies of the focused objects.
	 * @return
	 */
	public boolean duplicateFocusedObjects()
	{
		final int ox = (int)( this.mMagnification*OFFSET_DUPLICATED_OBJECT_X );
		final int oy = (int)( this.mMagnification*OFFSET_DUPLICATED_OBJECT_Y );

		ArrayList cList = this.duplicateObjects();
		for( int ii=0; ii<cList.size(); ii++ )
		{
			// duplicate
			SigDiffSymbol el = (SigDiffSymbol)cList.get(ii);
			el.setShapeWithAxesValues();
			
			// translate the duplicate
			el.translate( ox, oy );

			// set selected
			el.setSelected(true);
			
			// add to the list
			this.addToList(el);

			el.initPropertiesHistory();
		}

		if( cList.size()!=0 )
		{
			this.setChanged(true);
		}
		
//		this.repaint();
		
		return true;
	}



	/**
	 * Paste the objects.
	 * @param list of the objects to be pasted
	 * @return true:succeeded, false:failed
	 */
	public boolean paste( ArrayList list )
	{
		final float mag = this.getMagnification();
		final int ox = (int)( mag*OFFSET_DUPLICATED_OBJECT_X );
		final int oy = (int)( mag*OFFSET_DUPLICATED_OBJECT_Y );

		int cnt = 0;
		for( int ii=0; ii<list.size(); ii++ )
		{
			Object obj = list.get(ii);
			if( obj instanceof SigDiffSymbol )
			{
				SigDiffSymbol sd = (SigDiffSymbol)obj;
				sd.setShapeWithAxesValues();

				// translate the instance to be pasted
				sd.translate( ox, oy );

				SGProperties p = sd.getProperties();
				
				SigDiffSymbol el = new SigDiffSymbol();
				el.setMagnification(mag);
				el.setProperties(p);

				el.mXAxis = this.mAxisElement.getAxisInCube( sd.mTempXAxis );
				el.mYAxis = this.mAxisElement.getAxisInCube( sd.mTempYAxis );

				// set the shape
				el.setShapeWithAxesValues();

				// add to the list
				this.addToList(el);

				// initialize history
				el.initPropertiesHistory();

				cnt++;
			}
		}
		
		if( cnt!=0 )
		{
			this.setChanged(true);
		}

//		this.repaint();

		return true;
	}



	/**
	 * 
	 */
	protected Set getAvailableChildSet()
	{
		Set set = new HashSet();
		List mList = this.getMementoList();
		for( int ii=0; ii<mList.size(); ii++ )
		{
			SigDiffElementProperties p = (SigDiffElementProperties)mList.get(ii);
			set.addAll( p.visibleSigDiffSymbolList );
		}

		return set;		
	}


	//
	private SigDiffSymbol getSigDiffSymbol( final int id )
	{
		SigDiffSymbol el = (SigDiffSymbol)this.getChildObject(id);
		if( el == null ) return null;
		if( el.isVisible() == false ) return null;
		return el;
	}


	public boolean setAxisXDirectly( final int id, final int value )
	{
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setXAxisLocation(value) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setAxisYDirectly( final int id, final int value )
	{
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setYAxisLocation(value) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setLocationHorizontalYDirectly( final int id, final double value )
	{
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		el.setHorizontalYValue( value );
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setLocationLeftXDirectly( final int id, final double value )
	{
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		el.setLeftXValue( value );
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setLocationLeftYDirectly( final int id, final double value )
	{
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		el.setLeftYValue( value );
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setLocationRightXDirectly( final int id, final double value )
	{
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		el.setRightXValue( value );
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setLocationRightYDirectly( final int id, final double value )
	{
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		el.setRightYValue( value );
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setLineVisibleDirectly( final int id, final boolean value )
	{
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		el.setLineVisible( value );
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setSpaceDirectly( final int id, final float value, final String unit )
	{
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setSpace( value, unit ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setLineWidthDirectly( final int id, final float value, final String unit )
	{
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setLineWidth( value, unit ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setTextDirectly( final int id , final String value )
	{
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setText( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setFontNameDirectly( final int id, final String value )
	{
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setFontName( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setFontStyleDirectly( final int id, final int value )
	{
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setFontStyle( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setFontSizeDirectly( final int id, final float value, final String unit )
	{
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setFontSize( value, unit ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setFontColorDirectly( final int id, final Color value )
	{
		SigDiffSymbol el = this.getSigDiffSymbol(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setColor( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}


	private boolean setDirectlyBefore( SigDiffSymbol el )
	{
		return el.prepare();
	}


	private boolean setDirectlyAfter( SigDiffSymbol el )
	{
		if( el.commit() == false )
		{
			return false;
		}
		this.notifyChange();
		this.notifyToRoot();
		this.repaint();
		return true;
	}



	/**
	 * 
	 */
	public static class SigDiffElementProperties extends SGProperties
	{
		ArrayList visibleSigDiffSymbolList = new ArrayList();


		/**
		 * 
		 *
		 */
		public SigDiffElementProperties()
		{
			super();
		}


		public void dispose()
		{
			this.visibleSigDiffSymbolList.clear();
			this.visibleSigDiffSymbolList = null;
		}

		/**
		 * 
		 */
		public boolean equals( final Object obj )
		{
			if( ( obj instanceof SigDiffElementProperties ) == false )
			{
				return false;
			}

			SigDiffElementProperties p = (SigDiffElementProperties)obj;

			if( p.visibleSigDiffSymbolList.equals(this.visibleSigDiffSymbolList) == false )
			{
				return false;
			}

			return true;
		}


		/**
		 * 
		 */
		public String toString()
		{
			String str = new String("[");
			str += this.visibleSigDiffSymbolList.toString();
			str += new String("]");

			return str;
		}
		
	}



	/**
	 * @author  okumura
	 */
	private class SigDiffSymbol extends SGDrawingElementSignificantDifference2D
		implements ActionListener,
			SGIUndoable, SGISelectable, SGIMovable, SGICopiable,
			SGISignificantDifferenceDialogObserver, SGINode, SGIDisposable,
			ChildObject
	{

		/**
		 * 
		 */
		private int mID;


		public int getID()
		{
			return this.mID;
		}

		public boolean setID( final int id )
		{
			this.mID = id;
			return true;
		}


		/**
		 * 
		 */
		private SigDiffSymbol mTempSymbol = null;

		
		/**
		 * Flag whether this object is focused.
		 */
		private boolean mSelectedFlag = false;


		/**
		 * Get the flag as a focused object.
		 * @return whether this object is focused.
		 */
		public boolean isSelected()
		{
			return this.mSelectedFlag;
		}


		/**
		 * Set the flag as a focused object.
		 * @param b focused
		 */
		public void setSelected( final boolean b )
		{
			this.mSelectedFlag = b;
		}


		/**
		 * 
		 */
		public String toString()
		{
			return "SigDiff:"+this.mID;
		}


		/**
		 * 
		 */
		public void finalize()
		{
//			System.out.println("finalize:"+this);
		}


		/**
		 * 
		 */
		public void dispose()
		{
			super.dispose();

			this.mPopupMenu = null;
			this.mPressedSymbolOrigin = null;

			this.mTemporaryProperties = null;

			if( this.mTempSymbol!=null )
			{
				this.mTempSymbol.dispose();
				this.mTempSymbol = null;
			}

			this.mUndoManager.dispose();
			this.mUndoManager = null;

			this.mXAxis = null;
			this.mYAxis = null;
		}

		
		/**
		 * 
		 */
		private SGAxis mXAxis = null;
		
		
		/**
		 * 
		 */
		private SGAxis mYAxis = null;

		
		/**
		 * 
		 */
		private double mXValue1;
		
		
		/**
		 * 
		 */
		private double mXValue2;

		
		/**
		 * 
		 */
		private double mHorizontalYValue;

		
		/**
		 * 
		 */
		private double mYValue1;

		
		/**
		 * 
		 */
		private double mYValue2;
		

		/**
		 * 
		 */
		private Point mPressedSymbolOrigin = null;
		
		
		/**
		 * 
		 */
		private SGProperties mTemporaryProperties = null;


		/**
		 * ポップアップメニュー
		 */
		private JPopupMenu mPopupMenu = new JPopupMenu();


		/**
		 * 
		 */
		private SigDiffSymbol()
		{
			super();
			this.init();
		}

		/**
		 * 
		 */
		public String getClassDescription()
		{
			return "";
		}


		/**
		 * 
		 * @return
		 */
		public String getInstanceDescription()
		{
			String xAxis = SGFigureElementSignificantDifference.this.mAxisElement.getLocationName( this.mXAxis );
			String yAxis = SGFigureElementSignificantDifference.this.mAxisElement.getLocationName( this.mYAxis );

			String str = "";
			str += this.mID + ": " + this.getText() + ", ";
			str += xAxis + ", " + yAxis + ", ";
			str += "LeftX=" + this.getLeftXValue() + ", ";
			str += "RightX=" + this.getRightXValue() + ", ";
			str += "HorizontalY=" + this.getHorizontalYValue() + ", ";

			return str;
		}


		/**
		 * 
		 */
		public int getXAxisLocation()
		{
			return SGFigureElementSignificantDifference.this.mAxisElement.getLocationInPlane( this.mXAxis );
		}


		/**
		 * 
		 */
		public int getYAxisLocation()
		{
			return SGFigureElementSignificantDifference.this.mAxisElement.getLocationInPlane( this.mYAxis );
		}


		/**
		 * 
		 */
		public boolean setXAxisLocation( final int config )
		{
			if( config!=SGIFigureElementAxis.AXIS_HORIZONTAL_1
				& config!=SGIFigureElementAxis.AXIS_HORIZONTAL_2 )
			{
				return false;
			}
			this.mXAxis = this.getAxis(config);
			return true;
		}

		/**
		 * 
		 */
		public boolean setYAxisLocation( final int config )
		{
			if( config!=SGIFigureElementAxis.AXIS_PERPENDICULAR_1
				& config!=SGIFigureElementAxis.AXIS_PERPENDICULAR_2 )
			{
				return false;
			}
			this.mYAxis = this.getAxis(config);
			return true;
		}

		private SGAxis getAxis( final int config )
		{
			return SGFigureElementSignificantDifference.this.mAxisElement.getAxisInPlane( config );
		}


		/**
		 * 
		 */
		public float getSpace( final String unit )
		{
			return (float)SGUtilityText.convertFromPoint( this.getSpace(), unit );
		}


		/**
		 * 
		 */
		public float getLineWidth( final String unit )
		{
			return (float)SGUtilityText.convertFromPoint( this.getLineWidth(), unit );
		}


		/**
		 * 
		 */
		public float getFontSize( final String unit )
		{
			return (float)SGUtilityText.convertFromPoint( this.getFontSize(), unit );
		}


		/**
		 * 
		 */
		public boolean setSpace( final float space, final String unit )
		{
			final double conv = SGUtilityText.convert( space, unit, SIGDIFF_SPACE_UNIT );
			if( conv < SIGDIFF_SPACE_MIN ) return false;
			if( conv > SIGDIFF_SPACE_MAX ) return false;

			return super.setSpace( space, unit );
		}


		/**
		 * 
		 */
		public boolean setLineWidth( final float lw, final String unit )
		{
			final double conv = SGUtilityText.convert( lw, unit, LINE_WIDTH_UNIT );
			if( conv < LINE_WIDTH_MIN_VALUE ) return false;
			if( conv > LINE_WIDTH_MAX_VALUE ) return false;

			return super.setLineWidth( lw, unit );
		}


		/**
		 * 
		 */
		public boolean setText( final String text )
		{
			if( text==null ) return false;
			if( text.length()==0 ) return false;
			return super.setText( text );
		}


		/**
		 * 
		 */
		public Object copy()
		{
			SigDiffSymbol el = new SigDiffSymbol();
			el.setMagnification( this.getMagnification() );
			el.setProperties( this.getProperties() );
			el.setLocation( this.getX(), this.getY() );
			el.mTempXAxis = SGFigureElementSignificantDifference.this.mAxisElement.getLocationInCube( this.mXAxis );
			el.mTempYAxis = SGFigureElementSignificantDifference.this.mAxisElement.getLocationInCube( this.mYAxis );
			return el;
		}
		
		private int mTempXAxis = -1;
		private int mTempYAxis = -1;


		/**
		 * 
		 */
		private SigDiffSymbol(
			final float x, final float y, final float w, final float hl, final float hr )
		{
			super(x,y,w,hl,hr);
			this.init();
		}


		/**
		 * 
		 */
		private boolean createPopupMenu()
		{
			JPopupMenu p = this.mPopupMenu;
			
			p.setBounds( 0, 0, 100, 100 );

			p.add( new JLabel( "  -- Significant Difference --" ) );
			p.addSeparator();

			SGUtility.addItem( p, this, MENUCMD_MOVE_TO_FRONT );
			SGUtility.addItem( p, this, MENUCMD_MOVE_TO_BACK );

			p.addSeparator();

			SGUtility.addItem( p, this, MENUCMD_CUT );
			SGUtility.addItem( p, this, MENUCMD_COPY );
			SGUtility.addItem( p, this, MENUCMD_PASTE );

			p.addSeparator();

			SGUtility.addItem( p, this, MENUCMD_DELETE );
			SGUtility.addItem( p, this, MENUCMD_DUPLICATE );

			p.addSeparator();

			SGUtility.addItem( p, this, MENUCMD_PROPERTY );

			return true;
		}


		/**
		 * 
		 */
		private boolean init()
		{
			this.setWidth( DEFAULT_SIGDIFF_SYMBOL_WIDTH, cm );
			this.setPerpendicularHeight1( DEFAULT_SIGDIFF_SYMBOL_LEFT_HEIGHT, cm );
			this.setPerpendicularHeight2( DEFAULT_SIGDIFF_SYMBOL_RIGHT_HEIGHT, cm );

			this.setFontSize( DEFAULT_SIGDIFF_SYMBOL_FONT_SIZE, FONT_SIZE_UNIT );
			this.setFontName( DEFAULT_SIGDIFF_SYMBOL_FONT_NAME );
			this.setFontStyle( DEFAULT_SIGDIFF_SYMBOL_FONT_STYLE );

			this.setLineWidth( DEFAULT_SIGDIFF_SYMBOL_LINE_WIDTH, LINE_WIDTH_UNIT );
			this.setColor( DEFAULT_SIGDIFF_SYMBOL_COLOR );
			this.setSpace( DEFAULT_SIGDIFF_SYMBOL_SPACE, SIGDIFF_SPACE_UNIT );

			this.createPopupMenu();

			return true;
		}


		/**
		 * 
		 */
		private JPopupMenu getPopupMenu()
		{
			return this.mPopupMenu;
		}



		/**
		 * 
		 */
		public boolean prepare()
		{
			this.mTemporaryProperties = this.getProperties();
			return true;
		}



		/**
		 * @return
		 */
		public String getTagName()
		{
			return TAG_NAME_SIGDIFF_SYMBOL;
		}

		
		/**
		 * 
		 * @param document
		 * @return
		 */
		public Element createElement( final Document document )
		{
			Element el = document.createElement( this.getTagName() );
			if( this.writeProperty(el) == false )
			{
				return null;
			}
			return el;
		}
		
		
		/**
		 * 
		 * @param el
		 * @return
		 */
		public boolean writeProperty( final Element el )
		{
			if( super.writeProperty(el) == false )
			{
				return false;
			}
			
			el.setAttribute( KEY_LEFT_X_VALUE, Double.toString( this.getLeftXValue() ) );
			el.setAttribute( KEY_LEFT_Y_VALUE, Double.toString( this.getLeftYValue() ) );
			el.setAttribute( KEY_RIGHT_X_VALUE, Double.toString( this.getRightXValue() ) );
			el.setAttribute( KEY_RIGHT_Y_VALUE, Double.toString( this.getRightYValue() ) );
			el.setAttribute( KEY_HORIZONTAL_Y_VALUE, Double.toString( this.getHorizontalYValue() ) );
			el.setAttribute( KEY_X_AXIS_POSITION, SGFigureElementSignificantDifference.this.mAxisElement.getLocationName( this.mXAxis ) );
			el.setAttribute( KEY_Y_AXIS_POSITION, SGFigureElementSignificantDifference.this.mAxisElement.getLocationName( this.mYAxis ) );
			
			return true;
		}

		

		/**
		 * 
		 */
		public boolean readProperty( final Element el )
		{
			if( super.readProperty(el) == false )
			{
				return false;
			}

			String str = null;
			Number num = null;
			Boolean b = null;


			// x axis
			str = el.getAttribute( KEY_X_AXIS_POSITION );
			if( str.length()!=0 )
			{
				SGAxis xAxis = SGFigureElementSignificantDifference.this.mAxisElement.getAxis(str);
				if( xAxis==null )
				{
					return false;
				}
				this.mXAxis = xAxis;
			}
			
			
			// y axis
			str = el.getAttribute( KEY_Y_AXIS_POSITION );
			if( str.length()!=0 )
			{
				SGAxis yAxis = SGFigureElementSignificantDifference.this.mAxisElement.getAxis(str);
				if( yAxis==null )
				{
					return false;
				}
				this.mYAxis = yAxis;
			}

			
			// left x value
			str = el.getAttribute( KEY_LEFT_X_VALUE );
			if( str.length()!=0 )
			{
				num = SGUtilityText.getDouble(str);
				if( num==null )
				{
					return false;
				}
				final double leftXValue = num.doubleValue();
				if( this.mXAxis.isValidValue( leftXValue ) == false )
				{
					return false;
				}
				this.setLeftXValue( leftXValue );
			}
		
		
			// left y value
			str = el.getAttribute( KEY_LEFT_Y_VALUE );
			if( str.length()!=0 )
			{
				num = SGUtilityText.getDouble(str);
				if( num==null )
				{
					return false;
				}
				final double leftYValue = num.doubleValue();
				if( this.mYAxis.isValidValue( leftYValue ) == false )
				{
					return false;
				}
				this.setLeftYValue( leftYValue );
			}


			// right x value
			str = el.getAttribute( KEY_RIGHT_X_VALUE );
			if( str.length()!=0 )
			{
				num = SGUtilityText.getDouble(str);
				if( num==null )
				{
					return false;
				}
				final double rightXValue = num.doubleValue();
				if( this.mXAxis.isValidValue( rightXValue ) == false )
				{
					return false;
				}
				this.setRightXValue( rightXValue );
			}

		
			// right y value
			str = el.getAttribute( KEY_RIGHT_Y_VALUE );
			if( str.length()!=0 )
			{
				num = SGUtilityText.getDouble(str);
				if( num==null )
				{
					return false;
				}
				final double rightYValue = num.doubleValue();
				if( this.mYAxis.isValidValue( rightYValue ) == false )
				{
					return false;
				}
				this.setRightYValue( rightYValue );
			}


			// horizontal y value
			str = el.getAttribute( KEY_HORIZONTAL_Y_VALUE );
			if( str.length()!=0 )
			{
				num = SGUtilityText.getDouble(str);
				if( num==null )
				{
					return false;
				}
				final double horizontalYValue = num.doubleValue();
				if( this.mYAxis.isValidValue( horizontalYValue ) == false )
				{
					return false;
				}
				this.setHorizontalYValue( horizontalYValue );
			}


			return true;
		}

		
		
		/**
		 * 
		 */
		public SGProperties getProperties()
		{
			SigDiffPropertiesWithAxes p = new SigDiffPropertiesWithAxes();
			if( this.getProperties(p) == false ) return null;
			return p;
		}


		/**
		 * 
		 */
		public boolean getProperties( SGProperties p )
		{
			if( ( p instanceof SigDiffPropertiesWithAxes ) == false ) return false;

			if( super.getProperties(p) == false ) return false;

			SigDiffPropertiesWithAxes sp = (SigDiffPropertiesWithAxes)p;
			sp.mLeftXValue = this.getLeftXValue();
			sp.mLeftYValue = this.getLeftYValue();
			sp.mRightXValue = this.getRightXValue();
			sp.mRightYValue = this.getRightYValue();
			sp.mHorizontalYValue = this.getHorizontalYValue();
			sp.mXAxis = this.mXAxis;
			sp.mYAxis = this.mYAxis;
			
			return true;
		}
		
		

		/**
		 * 
		 */
		public boolean setProperties( final SGProperties p )
		{
			if( ( p instanceof SigDiffPropertiesWithAxes ) == false ) return false;
			
			if( super.setProperties(p) == false ) return false;

			SigDiffPropertiesWithAxes sp = (SigDiffPropertiesWithAxes)p;
			this.setLeftXValue( sp.mLeftXValue );
			this.setLeftYValue( sp.mLeftYValue );
			this.setRightXValue( sp.mRightXValue );
			this.setRightYValue( sp.mRightYValue );
			this.setHorizontalYValue( sp.mHorizontalYValue );
			this.mXAxis = sp.mXAxis;
			this.mYAxis = sp.mYAxis;
			
			return true;
		}



		/**
		 * 
		 */
		public void actionPerformed( final ActionEvent e )
		{

			final String command = e.getActionCommand();
			final Object source = e.getSource();

			if( command.equals( MENUCMD_PROPERTY ) )
			{
				SGFigureElementSignificantDifference.this.setPropertiesOfSelectedObjects();
			}
			else if(
				command.equals( MENUCMD_COPY )
				| command.equals( MENUCMD_CUT )
				| command.equals( MENUCMD_PASTE )
				| command.equals( MENUCMD_DELETE )
				| command.equals( MENUCMD_DUPLICATE )
				| command.equals( MENUCMD_MOVE_TO_FRONT )
				| command.equals( MENUCMD_MOVE_TO_BACK )
			)
			{
				notifyToListener( command );
			}
		}



		/**
		 * 
		 */
		public boolean commit()
		{
			// ダイアログを出す前後でプロパティが変更されている場合のみ、
			// 履歴を更新する

			SGProperties pTemp = this.mTemporaryProperties;
			SGProperties pPresent = this.getProperties();
			if( pTemp.equals(pPresent) == false )
			{
				this.mUndoManager.setChanged(true);
			}

			this.setShapeWithAxesValues();
			repaint();
			notifyChange();

			return true;
		}


		/**
		 * 
		 */
		public boolean cancel()
		{
			if( this.setProperties( this.mTemporaryProperties ) == false )
			{
				return false;
			}
			this.mTemporaryProperties = null;

			this.setShapeWithAxesValues();
			repaint();
			notifyChange();

			return true;
		}


		/**
		 * 
		 */
		public boolean preview()
		{
			this.setShapeWithAxesValues();
			repaint();
			notifyChange();

			return true;
		}



		/**
		 * Returns a property dialog.
		 * @return property dialog
		 */
		public SGPropertyDialog getPropertyDialog()
		{
			return SGFigureElementSignificantDifference.this.mDialog;
		}



		/**
		 * Returns a list of child nodes.
		 * @return a list of chid nodes
		 */
		public ArrayList getChildNodes()
		{
			return new ArrayList();
		}



		/**
		 *
		 */
		public float getX()
		{
			final float sx = super.getX();
			return this.getMagnification() * sx + SGFigureElementSignificantDifference.this.mGraphRectX;
		}


		/**
		 *
		 */
		public float getY()
		{
			final float sy = super.getY();
			return this.getMagnification() * sy + SGFigureElementSignificantDifference.this.mGraphRectY;
		}


		/**
		 * 
		 * @param x
		 * @return
		 */
		public boolean setX( final float x )
		{
			final float nx = ( x - SGFigureElementSignificantDifference.this.mGraphRectX )/this.getMagnification();
			super.setX( nx );
			return true;
		}


		/**
		 * 
		 * @param y
		 * @return
		 */
		public boolean setY( final float y )
		{
			final float ny = ( y - SGFigureElementSignificantDifference.this.mGraphRectY )/this.getMagnification();
			super.setY( ny );
			return true;			
		}
		
		
		/**
		 * 
		 */
		public void translate( final float dx, final float dy )
		{
			this.setLocation( this.getX() + dx, this.getY() + dy );
			this.createDrawingElement();
			this.setAxisValuesWithShape();
			this.setShapeWithAxesValues();
		}

		
		/**
		 * 
		 * @return
		 */
		public double getLeftXValue()
		{
			if( !this.isFlippingHorizontal() )
			{
				return this.mXValue1;
			}

			return this.mXValue2;
		}

		
		/**
		 * 
		 * @return
		 */
		public double getLeftYValue()
		{
			if( !this.isFlippingHorizontal() )
			{
				return this.mYValue1;
			}
			return this.mYValue2;
		}

		
		/**
		 * 
		 * @return
		 */
		public double getRightXValue()
		{
			if( !this.isFlippingHorizontal() )
			{
				return this.mXValue2;
			}
			return this.mXValue1;
		}

		
		/**
		 * 
		 * @return
		 */
		public double getRightYValue()
		{
			if( !this.isFlippingHorizontal() )
			{
				return this.mYValue2;
			}
			return this.mYValue1;
		}


		/**
		 * 
		 * @return
		 */
		public double getHorizontalYValue()
		{
			return this.mHorizontalYValue;
		}
		
		
		/**
		 * 
		 * @param value
		 */
		public boolean setLeftXValue( final double value )
		{
			if( !this.isFlippingHorizontal() )
			{
				this.mXValue1 = value;
			}
			else
			{
				this.mXValue2 = value;
			}
			return true;
		}

		
		/**
		 * 
		 * @param value
		 */
		public boolean setLeftYValue( final double value )
		{
			if( !this.isFlippingHorizontal() )
			{
				this.mYValue1 = value;
			}
			else
			{
				this.mYValue2 = value;
			}
			return true;
		}


		/**
		 * 
		 * @param value
		 */
		public boolean setRightXValue( final double value )
		{
			if( !this.isFlippingHorizontal() )
			{
				this.mXValue2 = value;
			}
			else
			{
				this.mXValue1 = value;
			}
			return true;
		}

		
		/**
		 * 
		 * @param value
		 */
		public boolean setRightYValue( final double value )
		{
			if( !this.isFlippingHorizontal() )
			{
				this.mYValue2 = value;
			}
			else
			{
				this.mYValue1 = value;
			}
			return true;
		}


		/**
		 * 
		 * @param value
		 */
		public boolean setHorizontalYValue( final double value )
		{
			this.mHorizontalYValue = value;
			return true;
		}



		/**
		 * 
		 * @param horizontalYValue
		 * @param leftXValue
		 * @param leftYValue
		 * @param rightXValue
		 * @param rightYValue
		 * @return
		 */
		public boolean hasValidValues()
		{
			Number horizontalY = new Double( this.getHorizontalYValue() );
			Number leftX = new Double( this.getLeftXValue() );
			Number leftY = new Double( this.getLeftYValue() );
			Number rightX = new Double( this.getRightXValue() );
			Number rightY = new Double( this.getRightYValue() );

			if( this.mYAxis.isValidValue( horizontalY.doubleValue() ) == false )
			{
				return false;
			}

			if( this.mXAxis.isValidValue( leftX.doubleValue() ) == false )
			{
				return false;
			}

			if( this.mYAxis.isValidValue( leftY.doubleValue() ) == false )
			{
				return false;
			}

			if( this.mXAxis.isValidValue( rightX.doubleValue() ) == false )
			{
				return false;
			}

			if( this.mYAxis.isValidValue( rightY.doubleValue() ) == false )
			{
				return false;
			}

			return true;
		}



		/**
		 * 
		 * @param config
		 * @param value
		 * @return
		 */
		public boolean hasValidHorizontalYValue( final int config, final Number value )
		{
			final SGAxis axis = (config==-1) ? this.mYAxis : SGFigureElementSignificantDifference.this.mAxisElement.getAxisInPlane( config );
			final double v = (value!=null) ? value.doubleValue() : this.getHorizontalYValue();
			return axis.isValidValue(v);
		}


		/**
		 * 
		 * @param config
		 * @param value
		 * @return
		 */
		public boolean hasValidLeftXValue( final int config, final Number value )
		{
			final SGAxis axis = (config==-1) ? this.mXAxis : SGFigureElementSignificantDifference.this.mAxisElement.getAxisInPlane( config );
			final double v = (value!=null) ? value.doubleValue() : this.getLeftXValue();
			return axis.isValidValue(v);
		}


		/**
		 * 
		 * @param config
		 * @param value
		 * @return
		 */
		public boolean hasValidLeftYValue( final int config, final Number value )
		{
			final SGAxis axis = (config==-1) ? this.mYAxis : SGFigureElementSignificantDifference.this.mAxisElement.getAxisInPlane( config );
			final double v = (value!=null) ? value.doubleValue() : this.getLeftYValue();
			return axis.isValidValue(v);
		}


		/**
		 * 
		 * @param config
		 * @param value
		 * @return
		 */
		public boolean hasValidRightXValue( final int config, final Number value )
		{
			final SGAxis axis = (config==-1) ? this.mXAxis : SGFigureElementSignificantDifference.this.mAxisElement.getAxisInPlane( config );
			final double v = (value!=null) ? value.doubleValue() : this.getRightXValue();
			return axis.isValidValue(v);
		}


		/**
		 * 
		 * @param config
		 * @param value
		 * @return
		 */
		public boolean hasValidRightYValue( final int config, final Number value )
		{
			final SGAxis axis = (config==-1) ? this.mYAxis : SGFigureElementSignificantDifference.this.mAxisElement.getAxisInPlane( config );
			final double v = (value!=null) ? value.doubleValue() : this.getRightYValue();
			return axis.isValidValue(v);
		}

		
		/**
		 * 
		 */
		private boolean pressDrawingElements( final MouseEvent e )
		{

			final int x = e.getX();
			final int y = e.getY();

			if( this.contains(x,y) || this.getStringElement().contains(x,y) )
			{

				final float mag = this.getMagnification();

				// set the temporary object
				this.mTempSymbol = new SigDiffSymbol();
				this.mTempSymbol.setMagnification( mag );
				this.mTempSymbol.setLocation( this.getX(), this.getY() );
				this.mTempSymbol.setSize(
					this.getWidth(),
					this.getPerpendicularHeight1(),
					this.getPerpendicularHeight2()
				);

				this.mFlippingHorizontalFlag = this.isFlippingHorizontal();

				this.mMouseLocation = this.getMouseLocation(x,y);
				Cursor cur = null;
				if( this.mMouseLocation==BODY || this.mMouseLocation==ON_STRING )
				{
					cur = Cursor.getPredefinedCursor( Cursor.MOVE_CURSOR );
				}
				else
				{
					this.getCursor( this.mMouseLocation );
				}
				setMouseCursor( cur );

				return true;
			}

			return false;
		}



		/**
		 * 
		 */
		private boolean mFlippingHorizontalFlag;


		/**
		 * 
		 * @return
		 */
		private ArrayList getAnchorPointList()
		{
			ArrayList list = new ArrayList();
			if( this.isLineVisible() )
			{
				list.add( this.getLeftTerm() );
				list.add( this.getLeftMiddle() );
				list.add( this.getLeftJoint() );
				list.add( this.getHorizontalMiddle() );
				list.add( this.getRightJoint() );
				list.add( this.getRightMiddle() );
				list.add( this.getRightTerm() );
			}
			
			Rectangle2D rect = ((SGDrawingElementString2DExtended)this.getStringElement()).getElementBounds();
			final float x = (float)rect.getX();
			final float y = (float)rect.getY();
			final float w = (float)rect.getWidth();
			final float h = (float)rect.getHeight();
			Point2D pos0 = new Point2D.Float( x, y );
			Point2D pos1 = new Point2D.Float( x+w, y );
			Point2D pos2 = new Point2D.Float( x, y+h );
			Point2D pos3 = new Point2D.Float( x+w, y+h );
			list.add( pos0 );
			list.add( pos1 );
			list.add( pos2 );
			list.add( pos3 );

			return list;
		}



		/**
		 * Location of mouse pointer.
		 */
		private int mMouseLocation;



		/**
		 * 
		 * @param pos
		 * @param radius
		 * @param x
		 * @param y
		 * @return
		 */
		private boolean isInside( final Point2D pos, final int radius, final int x, final int y )
		{
			return( ( Math.abs( pos.getX() - x ) < radius )
				&& ( Math.abs( pos.getY() -  y ) < radius ) );
		}



		/**
		 * マウス位置を属性に設定
		 */
		private int getMouseLocation( final int x, final int y )
		{
			final int radius = (int)( 1.25f*ANCHOR_SIZE_FOR_FOCUSED_OBJECTS );

			final Point2D posHorizontalMiddle = this.getHorizontalMiddle();
			final Point2D posLeftMiddle = this.getLeftMiddle();
			final Point2D posRightMiddle = this.getRightMiddle();
			final Point2D posLeftJoint = this.getLeftJoint();
			final Point2D posRightJoint = this.getRightJoint();
			final Point2D posLeftTerm = this.getLeftTerm();
			final Point2D posRightTerm = this.getRightTerm();


			int location = -1;

			if( this.isLineVisible() )
			{
				// 水平線分中央
				if( this.isInside( posHorizontalMiddle, radius, x, y ) )
				{
					location = HORIZONTAL_MIDDLE;
				}
				// 左側接合部
				else if( this.isInside( posLeftJoint, radius, x, y ) )
				{
					location = LEFT_JOINT;
				}
				// 右側接合部
				else if( this.isInside( posRightJoint, radius, x, y ) )
				{
					location = RIGHT_JOINT;
				}
				// 垂直線分左側の端
				else if( this.isInside( posLeftTerm, radius, x, y ) )
				{
					location = LEFT_TERM;
				}
				// 垂直線分左側の中央
				else if( this.isInside( posLeftMiddle, radius, x, y ) )
				{
					location = LEFT_MIDDLE;
				}
				// 垂直線分右側の端
				else if( this.isInside( posRightTerm, radius, x, y ) )
				{
					location = RIGHT_TERM;
				}
				// 垂直線分右側の中央
				else if( this.isInside( posRightMiddle, radius, x, y ) )
				{
					location = RIGHT_MIDDLE;
				}
				else
				{
					location = BODY;
				}
			}

			if( this.getStringElement().contains(x,y) )
			{
				location = ON_STRING;
			}

			return location;
		}



		/**
		 * 
		 */
		private Cursor getCursor( final int location )
		{

			// マウスの位置に応じてカーソルを変更
			Cursor cur = null;
			switch( location )
			{
				case HORIZONTAL_MIDDLE:
				{
					if( !this.isFlippingVertical() )
					{
						cur = new Cursor( Cursor.N_RESIZE_CURSOR );
					}
					else
					{
						cur = new Cursor( Cursor.S_RESIZE_CURSOR );
					}
					break;
				}
				case LEFT_MIDDLE:
				{
					cur = new Cursor( Cursor.W_RESIZE_CURSOR );
					break;
				}
				case RIGHT_MIDDLE:
				{
					cur = new Cursor( Cursor.E_RESIZE_CURSOR );
					break;
				}
				case LEFT_TERM:
				{
					if( !this.isFlippingVerticalLeft() )
					{
						cur = new Cursor( Cursor.SW_RESIZE_CURSOR );
					}
					else
					{
						cur = new Cursor( Cursor.NW_RESIZE_CURSOR );
					}
					break;
				}
				case LEFT_JOINT:
				{
					if( !this.isFlippingVerticalLeft() )
					{
						cur = new Cursor( Cursor.NW_RESIZE_CURSOR );
					}
					else
					{
						cur = new Cursor( Cursor.SW_RESIZE_CURSOR );
					}
					break;
				}
				case RIGHT_TERM:
				{
					if( !this.isFlippingVerticalRight() )
					{
						cur = new Cursor( Cursor.SE_RESIZE_CURSOR );
					}
					else
					{
						cur = new Cursor( Cursor.NE_RESIZE_CURSOR );
					}
					break;
				}
				case RIGHT_JOINT:
				{
					if( !this.isFlippingVerticalRight() )
					{
						cur = new Cursor( Cursor.NE_RESIZE_CURSOR );
					}
					else
					{
						cur = new Cursor( Cursor.SE_RESIZE_CURSOR );
					}
					break;
				}
				case ON_STRING:
				{
					cur = new Cursor( Cursor.HAND_CURSOR );
					break;
				}
				default:
				{
					cur = new Cursor( Cursor.HAND_CURSOR );
				}
			}

//System.out.println(cur);

			return cur;

		}



		/**
		 * 
		 */
		private boolean drag( final MouseEvent e )
		{
//System.out.println("<< drag >>");

			if( SGFigureElementSignificantDifference.this.mPressedPoint == null )
			{
				return false;
			}

//System.out.println(e.getPoint());
//System.out.println();


			// translation
			if( this.mMouseLocation == BODY || this.mMouseLocation == ON_STRING )
			{
				final boolean flag = this.dragOtherPoint(e);
				return flag;
			}

			final float mag = this.getMagnification();

			SigDiffSymbol temp = this.mTempSymbol;
			final float xOld = temp.getX();
			final float yOld = temp.getY();
			final float wOld = mag*temp.getWidth();
			final float h1Old = mag*temp.getPerpendicularHeight1();
			final float h2Old = mag*temp.getPerpendicularHeight2();

//final float hlOld = mTempSymbol.getLeftHeight();
//final float hrOld = mTempSymbol.getRightHeight();


			final int diffX = e.getX() - SGFigureElementSignificantDifference.this.mPressedPoint.x;
			final int diffY = e.getY() - SGFigureElementSignificantDifference.this.mPressedPoint.y;

			final float sizeOldX = wOld;
			final float sizeOldY1 = h1Old;
			final float sizeOldY2 = h2Old;

			float sizeNewX = 0.0f;
			float sizeNewY1 = 0.0f;
			float sizeNewY2 = 0.0f;


			// 以下の処理で更新する量
			// そのまま新しい属性になる
			float x = xOld;
			float y = yOld;
			float w = wOld;
			float h1 = h1Old;
			float h2 = h2Old;

//final float r = SGConstants.CM_POINT_RATIO;
//System.out.println(diffX*r+"  "+diffY*r);

			//
			// ドラッグしている点に応じて場合分け
			//

			final int loc = this.mMouseLocation;
			final boolean flag = this.mFlippingHorizontalFlag;
			if( loc == HORIZONTAL_MIDDLE )
			{
//System.out.println("NORTH");
				sizeNewY1 = sizeOldY1 - diffY;
				sizeNewY2 = sizeOldY2 - diffY;

				y = yOld + sizeOldY1 - sizeNewY1;
				h1 = sizeNewY1;
				h2 = sizeNewY2;
			}
			else if(
				( loc==LEFT_MIDDLE && !flag )
				||
				( loc == RIGHT_MIDDLE && flag )
			)
			{
				sizeNewX = sizeOldX - diffX;
				x = xOld + sizeOldX - sizeNewX;
				w = sizeNewX;
			}
			else if(
				( loc==RIGHT_MIDDLE && !flag )
				||
				( loc==LEFT_MIDDLE && flag )
			)
			{
				sizeNewX = sizeOldX + diffX;
				w = sizeNewX;
			}
			else if(
				( loc==LEFT_JOINT && !flag )
				||
				( loc==RIGHT_JOINT && flag )
			)
			{
				sizeNewY1 = sizeOldY1 - diffY;
				sizeNewY2 = sizeOldY2 - diffY;
				sizeNewX = sizeOldX - diffX;

				x = xOld + sizeOldX - sizeNewX;
				y = yOld + sizeOldY1 - sizeNewY1;
				w = sizeNewX;
				h1 = sizeNewY1;
				h2 = sizeNewY2;
			}
			else if(
				( loc==RIGHT_JOINT && !flag )
				||
				( loc==LEFT_JOINT && flag )
			)
			{
				sizeNewX = sizeOldX + diffX;
				sizeNewY1 = sizeOldY1 - diffY;
				sizeNewY2 = sizeOldY2 - diffY;

				y = yOld + sizeOldY2 - sizeNewY2;
				w = sizeNewX;
				h1 = sizeNewY1;
				h2 = sizeNewY2;
			}
			else if( 
				( loc==LEFT_TERM && !flag )
				||
				( loc==RIGHT_TERM && flag )
			)
			{
				sizeNewX = sizeOldX - diffX;
				sizeNewY1 = sizeOldY1 + diffY;

				x = xOld + sizeOldX - sizeNewX;
				w = sizeNewX;
				h1 = sizeNewY1;
			}
			else if( 
				( loc==RIGHT_TERM && !flag )
				||
				( loc==LEFT_TERM && flag )
			)
			{
				sizeNewX = sizeOldX + diffX;
				sizeNewY2 = sizeOldY2 + diffY;

				w = sizeNewX;
				h2 = sizeNewY2;
			}

			// update the pressed point
			SGFigureElementSignificantDifference.this.mPressedPoint.setLocation(
				SGFigureElementSignificantDifference.this.mPressedPoint.getX() + diffX,
				SGFigureElementSignificantDifference.this.mPressedPoint.getY() + diffY
			);


			// set properties
			this.setLocation( x, y );
			this.setSize( w/mag, h1/mag, h2/mag );
			this.createDrawingElement();

			temp.setLocation( x, y );
			temp.setSize( w/mag, h1/mag, h2/mag );

			if( loc==LEFT_TERM | loc==LEFT_JOINT
				| loc==RIGHT_TERM | loc==RIGHT_JOINT )
			{
				final int location = this.getMouseLocation( e.getX(), e.getY() );
				setMouseCursor( this.getCursor( location ) );
			}

			return true;

		}



		/**
		 * 
		 */
		private boolean dragOtherPoint( final MouseEvent e )
		{
			// parallel displacement
			if ( SGFigureElementSignificantDifference.this.mPressedPoint != null )
			{
				// set the location to the symbol
				final int dx = e.getX() - SGFigureElementSignificantDifference.this.mPressedPoint.x;
				final int dy = e.getY() - SGFigureElementSignificantDifference.this.mPressedPoint.y;
				this.translate(dx,dy);

				SGFigureElementSignificantDifference.this.mPressedPoint = e.getPoint();
			}

			return true;
		}


		private boolean setShapeWithAxesValues()
		{
			final float x1 = calcLocation( this.mXValue1, this.mXAxis, true );
			final float x2 = calcLocation( this.mXValue2, this.mXAxis, true );
			final float y = calcLocation( this.mHorizontalYValue, this.mYAxis, false);
			final float y1 = calcLocation( this.mYValue1, this.mYAxis, false);
			final float y2 = calcLocation( this.mYValue2, this.mYAxis, false );

			if( Float.isNaN(x1) | Float.isNaN(x2) | Float.isNaN(y) | Float.isNaN(y1) | Float.isNaN(y2) )
			{
				this.setValid( false );
				return false;
			}
			this.setValid( true );

			this.setNodePointLocation(x1,y1,x2,y2,y);
			
			this.createDrawingElement();

			return true;
		}


		private boolean mValidFlag = true;

		public boolean isValid()
		{
			return this.mValidFlag;
		}

		public void setValid( final boolean b )
		{
			this.mValidFlag = b;
		}




		private boolean setAxisValuesWithShape()
		{
			final double xValue1 = calcValue( this.getX1(), this.mXAxis, true );
			final double yValue1 = calcValue( this.getY1(), this.mYAxis, false );
			final double xValue2 = calcValue( this.getX2(), this.mXAxis, true );
			final double yValue2 = calcValue( this.getY2(), this.mYAxis, false );
			final double hYValue = calcValue( this.getY(), this.mYAxis, false );

			this.mXValue1 = getNumberInRangeOrder( xValue1, this.mXAxis );
			this.mYValue1 = getNumberInRangeOrder( yValue1, this.mYAxis );
			this.mXValue2 = getNumberInRangeOrder( xValue2, this.mXAxis );
			this.mYValue2 = getNumberInRangeOrder( yValue2, this.mYAxis );
			this.mHorizontalYValue = getNumberInRangeOrder( hYValue, this.mYAxis );

//			this.mXValue1 = xValue1;
//			this.mYValue1 = yValue1;
//			this.mXValue2 = xValue2;
//			this.mYValue2 = yValue2;
//			this.mHorizontalYValue = hYValue;
			
			return true;
		}
		

		//
		private SGUndoManager mUndoManager = new SGUndoManager(this);


		/**
		 * 
		 * @return
		 */
		public SGProperties getMemento()
		{
			return this.getProperties();
		}


		/**
		 * 
		 * @param p
		 * @return
		 */
		public boolean setMemento( SGProperties p )
		{
			return this.setProperties(p);
		}


		/**
		 * 
		 * @return
		 */
		public boolean isUndoable()
		{
			return this.mUndoManager.isUndoable();
		}

	
		/**
		 * 
		 * @return
		 */
		public boolean isRedoable()
		{
			return this.mUndoManager.isRedoable();
		}


		/**
		 * 
		 */
		public boolean initPropertiesHistory()
		{
			return this.mUndoManager.initPropertiesHistory();
		}


		/**
		 * アンドゥを行う
		 */
		public boolean setMementoBackward()
		{
			if( this.mUndoManager.setMementoBackward() == false )
			{
				return false;
			}

			this.setShapeWithAxesValues();

			if( this.isValid() )
			{
				this.createDrawingElement();
			}

			return true;
		}


		/**
		 * リドゥを行う
		 */
		public boolean setMementoForward()
		{
			if( this.mUndoManager.setMementoForward() == false )
			{
				return false;
			}

			this.setShapeWithAxesValues();

			if( this.isValid() )
			{
				this.createDrawingElement();
			}

			return true;
		}



		/**
		 * アンドゥ操作を依頼する
		 */
		public boolean undo()
		{
			return this.setMementoBackward();
		}

	
	
		/**
		 * リドゥ操作を依頼する
		 */
		public boolean redo()
		{
			return this.setMementoForward();
		}


		/**
		 * 履歴の更新の実行。アンドゥ対象の操作が行われたときに、真っ先に呼ばれる。
		 */
		public boolean updateHistory()
		{
			return this.mUndoManager.updateHistory();
		}


		/**
		 * 
		 */
		public void initUndoBuffer()
		{
			this.mUndoManager.initUndoBuffer();
		}


		/**
		 * 
		 */
		public boolean isChanged()
		{
			return this.mUndoManager.isChanged();
		}

		public void setChanged( final boolean b )
		{
			this.mUndoManager.setChanged(b);
		}


		public boolean isChangedRoot()
		{
			return this.isChanged();
		}


		/**
		 * 
		 *
		 */
		public void notifyToRoot()
		{
			SGFigureElementSignificantDifference.this.notifyToRoot();
		}


	}



	/**
	 * @author  okumura
	 */
	public static class SigDiffPropertiesWithAxes extends SigDiffProperties
	{

		private double mLeftXValue;
		private double mRightXValue;
		private double mLeftYValue;
		private double mRightYValue;
		private double mHorizontalYValue;
		private SGAxis mXAxis;
		private SGAxis mYAxis;
		

		public SigDiffPropertiesWithAxes()
		{
			super();
		}


		/**
		 * 
		 */
		public boolean equals( final Object obj )
		{
			if( ( obj instanceof SigDiffPropertiesWithAxes ) == false ) return false;

			if( super.equals( obj ) == false ) return false;
			
			SigDiffPropertiesWithAxes p = (SigDiffPropertiesWithAxes)obj;

			if( p.mLeftXValue != this.mLeftXValue ) return false;
			if( p.mRightXValue != this.mRightXValue ) return false;
			if( p.mLeftYValue != this.mLeftYValue ) return false;
			if( p.mRightYValue != this.mRightYValue ) return false;
			if( p.mHorizontalYValue != this.mHorizontalYValue ) return false;
			if( p.mXAxis.equals( this.mXAxis ) == false ) return false;
			if( p.mYAxis.equals( this.mYAxis ) == false ) return false;

			return true;
		}


		public double getLeftXValue()
		{
			return this.mLeftXValue;
		}
		
		public double getLeftYValue()
		{
			return this.mLeftYValue;
		}
		
		public double getRightXValue()
		{
			return this.mRightXValue;
		}
		
		public double getRightYValue()
		{
			return this.mRightYValue;
		}
		
		public double getHorizontalYValue()
		{
			return this.mHorizontalYValue;
		}
		
		public SGAxis getXAxis()
		{
			return this.mXAxis;
		}
		
		public SGAxis getYAxis()
		{
			return this.mYAxis;
		}
		
		public void setLeftXValue( final double value )
		{
			this.mLeftXValue = value;
		}

		public void setLeftYValue( final double value )
		{
			this.mLeftYValue = value;
		}

		public void setRightXValue( final double value )
		{
			this.mRightXValue = value;
		}

		public void setRightYValue( final double value )
		{
			this.mRightYValue = value;
		}

		public void setHorizontalYValue( final double value )
		{
			this.mHorizontalYValue = value;
		}
		
		public void setXAxis( SGAxis axis )
		{
			if( axis==null )
			{
				throw new IllegalArgumentException("axis==null");
			}
			this.mXAxis = axis;
		}

		public void setYAxis( SGAxis axis )
		{
			if( axis==null )
			{
				throw new IllegalArgumentException("axis==null");
			}
			this.mYAxis = axis;
		}

	}





}
