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

import java.util.*;
import java.io.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import java.awt.font.*;
import javax.swing.*;
import javax.swing.event.*;
import jp.riken.brain.ni.samuraigraph.base.*;
import jp.riken.brain.ni.samuraigraph.data.*;
import jp.riken.brain.ni.samuraigraph.figure.*;


/**
 * グラフの基本クラス
 */

public abstract class SGGraphElement extends SGFigureElement
	implements SGIGraphElement, Runnable, CaretListener
{

	/**
	 *
	 */
	protected SGIAxisElement mAxisElement = null;


	/**
	 * 
	 */
	protected ArrayList mGroupSetList = new ArrayList();


	/**
	 * 
	 */
	protected ArrayList mTimingElementGroupSetList = new ArrayList();


	/**
	 * 
	 */
	protected SGTimingLineDialog mTimingLineDialog = null;



	/**
	 * 
	 */
	protected static SGPropertyDialog mPropertyDialogForData = null;


	/**
	 * マウス選択されたSGElementGroupSetのリスト
	 */
	protected ArrayList mSelectedGroupSetList = new ArrayList();



	/**
	 * デフォルトでのタイミング線の線幅
	 */
	protected final float mTimingLineWidth = 2.0f;



	/**
	 * 
	 */
	protected JTextField mEditField = null;


	/**
	 * 
	 */
	protected int mFocusedX = 0;


	/**
	 * 
	 */
	protected int mFocusedY = 0;



	/**
	 * 
	 */
	public static final String REMOVE_SELECTED_GRAPH = "Remove selected datas";


	/**
	 * 
	 */
	public static final String REMOVE_SELECTED_ELEMENTS = "Remove selected elements";


	/**
	 * 
	 */
	public static final int MAX_NUMBER_EMPHASIS_SYMBOLS = 8;



	/**
	 * 
	 */
	public static final String REMOVE_SIGDIFF_SYMBOL = "Remove this Symbol";


	/**
	 * 
	 */
	protected Thread mThread = null;



	/**
	 * 
	 */
	protected SigDiffSymbol mTempSymbol = new SigDiffSymbol();



	/**
	 * 
	 */
	protected void startBlinking()
	{
		if( mThread == null )
		{
			mThread = new Thread(this);
			mThread.start();
		}
	}



	/**
	 * 
	 */
	public void run()
	{

		while(true)
		{

System.out.println("run");

			if( this.mSelectedGroupSetList.size() == 0 )
			{
System.out.println("break");

				this.mThread = null;

				break;
			}


			try
			{
				Thread.sleep(400);
				this.reverseVisible();
//				repaint();
			}
			catch( Exception ex )
			{
				ex.printStackTrace();
			}
			
		}

	}



	/**
	 * 
	 */
	private boolean reverseVisible()
	{
		for( int ii=0; ii<this.mSelectedGroupSetList.size(); ii++ )
		{
			SGElementGroupSet groupSet = (SGElementGroupSet)this.mSelectedGroupSetList.get(ii);
			groupSet.setVisible( !groupSet.isVisible() );
		}

		return true;
	}



	/**
	 * 
	 * @return
	 */
	public boolean clearSelectedElements()
	{
		super.clearSelectedElements();

		// clear selected drawing elements for data
		this.clearSelectedElementsGroupSet();
		
		// 
		if( this.mEditField.isVisible() )
		{
			this.terminateEditField();
		}
		this.clearFocusedSymbol();
//		repaint();

		return true;
	}




	/**
	 * コンストラクタ
	 */
	public SGGraphElement()
	{
		super();
		this.initEditField();
	}



	/**
	 * 
	 * @return
	 */
	public String toString()
	{
		return new String("SGGraphElement");
	}



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



	/**
	 * 
	 */
	private boolean createAllDialogs()
	{
		this.createDataDialog();
		this.createSignificanceDialog();
		this.createTimingLineDialog();
		return true;
	}


	/**
	 * プロパティダイアログの作成
	 */
	protected abstract boolean createDataDialog();


	/**
	 * 
	 */
	private SGSignificantDifferenceSymbolDialog mSigDiffDialog = null;


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

		final SGSignificantDifferenceSymbolDialog dg
			= new SGSignificantDifferenceSymbolDialog(
				mDialogOwner, true );

		this.mSigDiffDialog = dg;

		return true;
	}


	/**
	 * 
	 */
	private boolean createTimingLineDialog()
	{
		final SGTimingLineDialog dg = new SGTimingLineDialog( mDialogOwner, true );

		this.mTimingLineDialog = dg;

		return true;
	}


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

		return true;
	}



	/**
	 * 
	 */
	private boolean showEditField( final SigDiffSymbol el )
	{
//System.out.println("showEditField");

		SGDrawingElementString2DExtended sElement
			= (SGDrawingElementString2DExtended)el.getStringElement();

		final Rectangle2D rect = sElement.getElementBounds();
		final double fontSize = el.getFontSize();

//System.out.println(rect);
//System.out.println();

		this.mEditField.setVisible(true);
		this.mEditField.setLocation( (int)rect.getX(), (int)rect.getY() );
		this.mEditField.setSize(
			(int)(rect.getWidth()+0.20*fontSize),
			(int)(rect.getHeight())
		);
		this.mEditField.setFont(
			new Font( el.getFontFamilyName(), el.getFontStyle(),
				(int)(this.mMagnification*fontSize) )
		);
		this.mEditField.setForeground( el.getColor() );
		this.mEditField.setText( el.getStringElement().getString() );


		return true;

	}


	/**
	 * 
	 */
	private boolean terminateEditField()
	{
//System.out.println("-- terminateEditField --");

		if( this.mFocusedSymbol==null )
		{
			this.hideEditField();
			return true;
		}

		this.commitEdit();
		this.hideEditField();

		this.repaint();		

		return true;
	}



	private boolean clearFocusedSymbol()
	{
		this.mFocusedSymbol = null;
		this.mPressedSymbolOrigin = null;
		return true;
	}



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



	/**
	 * 
	 * @return
	 */
	private boolean commitEdit()
	{
		String before = this.mFocusedSymbol.mStringElement.getString();
		String after = this.mEditField.getText();
		this.mFocusedSymbol.setText( after );
		if( before.equals(after) == false )
		{
			this.mFocusedSymbol.updateHistory();
		}

		this.mFocusedSymbol.createDrawingElement();

		return true;
	}




	/**
	 * データの追加
	 * @param data 追加するデータ
	 * @return true:成功、false:失敗
	 */
	public abstract boolean addData( SGData data );




	/**
	 * 全描画要素の位置を決定
	 */
	protected abstract boolean setAllDrawingElementsLocation();



	/**
	 *
	 */
	public boolean setAxisElement( final SGIAxisElement element )
	{
		mAxisElement = element;
		return true;
	}


	/**
	 * 引数で渡されたSGDataオブジェクトに対応したElementGroupSetInGraphオブジェクトを取得する
	 */
	protected ElementGroupSetInGraph getGraphData( final SGData data )
	{
		for( int ii=0; ii<this.mDataList.size(); ii++ )
		{
			final SGData data_ = (SGData)this.mDataList.get(ii);
			if( data_.equals(data) )
			{
				final ElementGroupSetInGraph groupSet = (ElementGroupSetInGraph)this.mGroupSetList.get(ii);
				return groupSet;
			}
		}

		return null;
	}
	

	/**
	 * 引数で渡されたElementGroupSetInGraphオブジェクトに対応したSGDataオブジェクトを取得する
	 */
	protected SGData getData( final ElementGroupSetInGraph groupSet )
	{
		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			final ElementGroupSetInGraph groupSet_ = (ElementGroupSetInGraph)this.mGroupSetList.get(ii);
			if( groupSet_.equals(groupSet) )
			{
				final SGData data = (SGData)this.mDataList.get(ii);
				return data;
			}
		}

		return null;
	
	}




	/**
	 * 
	 */
	public String getDataName( final SGData data )
	{
		final ElementGroupSetInGraph groupSet = getGraphData(data);
		
		if( groupSet != null )
		{
			return groupSet.mName;
		}

		return null;
	}


	/**
	 * 
	 */
	public ArrayList getDrawingElementList( final SGData data )
	{
		final ElementGroupSetInGraph groupSet = getGraphData(data);
		
		if( groupSet != null )
		{
			return groupSet.getDrawingElementList();
		}

		return null;
	}



	/**
	 * 
	 */
	public ArrayList getVisibleFlagList( final SGData data )
	{

		if( data==null )
		{
			return null;
		}

		final ElementGroupSetInGraph groupSet = getGraphData(data);
		ArrayList list = groupSet.getVisibleFlagList();		

		return list;
	}




	/**
	 * 
	 */
	public boolean getTimingElementList(
		final ArrayList axisList, final ArrayList elementListList, final ArrayList valueList )
	{

//System.out.println("[SGIGraphElement]");
		for( int ii=0; ii<this.mTimingElementGroupSetList.size(); ii++ )
		{
//System.out.println("ii="+ii);

			final TimingElementGroupSetInGraph groupSet
				= (TimingElementGroupSetInGraph)mTimingElementGroupSetList.get(ii);

			final SGAxis axis = groupSet.mAxis;
			final ArrayList elementList = groupSet.getDrawingElementList();
			final SGDouble value = groupSet.mValue;

			axisList.add( axis );
			elementListList.add( elementList );
			valueList.add( value );

//SGDrawingElement el = (SGDrawingElement)elementList.get(0);

//System.out.println(" "+axis+"  "+value+"  "+el.getColor(0));

		}
//System.out.println();

		return true;
	}



	/**
	 * 
	 */
	public SGAxis getXAxis( final SGData data )
	{
		final ElementGroupSetInGraph groupSet = getGraphData(data);
		
		if( groupSet != null )
		{
			return groupSet.mXAxis;
		}

		return null;
	}


	/**
	 * 
	 */
	public SGAxis getYAxis( final SGData data )
	{
		final ElementGroupSetInGraph groupSet = getGraphData(data);
		
		if( groupSet != null )
		{
			return groupSet.mYAxis;
		}

		return null;
	}


	/**
	 * 
	 */
	public SGAxis getZAxis( final SGData data )
	{
		final ElementGroupSetInGraph groupSet = getGraphData(data);
		
		if( groupSet != null )
		{
			return groupSet.mZAxis;
		}

		return null;
	}



	/**
	 * 
	 */
	public JPopupMenu getPopupMenu( final SGData data )
	{
		return null;
	}


	/**
	 * 
	 */
	public JDialog getDialog( final SGData data )
	{
		return null;
	}



	/**
	 * ズーム
	 */
	public boolean zoom( final float ratio )
	{
//System.out.println("zoom");
//System.out.println("ratio="+ratio);

		super.zoom(ratio);

		this.onZoomed(ratio);

		this.setAllDrawingElementsLocation();

		return true;

	}



	/**
	 * 
	 */
	protected boolean onZoomed( final float ratio )
	{

		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			final ElementGroupSetInGraph groupSet
				= (ElementGroupSetInGraph)this.mGroupSetList.get(ii);
			groupSet.zoom(ratio);
		}


		// siginificant symbol
		for( int ii=0; ii<this.mSignificantDifferentSymbolsList.size(); ii++ )
		{
			final SigDiffSymbol sd = (SigDiffSymbol)this.mSignificantDifferentSymbolsList.get(ii);
			sd.zoom(ratio);
		}


		// timing lines
		for( int ii=0; ii<this.mTimingElementGroupSetList.size(); ii++ )
		{
			final TimingElementGroupSetInGraph groupSet
				= (TimingElementGroupSetInGraph)this.mTimingElementGroupSetList.get(ii);
			groupSet.zoom(ratio);
		}

		return true;
	}



	/**
	 * 
	 */
	public boolean removeData( final SGData data )
	{
		SGElementGroupSet groupSet = this.getElementGroupSet(data);
		this.mDataList.remove(data);
		this.mGroupSetList.remove(groupSet);

		return true;
	}


	/**
	 * 
	 */
	public boolean setDataVisible( final SGData data, final boolean flag )
	{
		SGElementGroupSet groupSet = this.getElementGroupSet(data);
		groupSet.setVisible(flag);
		return true;
	}



	/**
	 * 
	 */
	public boolean setISize( final SGTuple2f size )
	{
		super.setISize(size);

		this.drawBackAllSigDiffSymbols();

		return true;

	}



	/**
	 * 
	 */
	public boolean setGraphAreaRect(
		final float x, final float y, final float width, final float height )
	{

		super.setGraphAreaRect(x,y,width,height);

//long s = System.currentTimeMillis();

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

/*
		if( this.transformDrawingElementsLocation() == false )
		{
			return false;
		}
*/

//long t = System.currentTimeMillis();
//System.out.println(t-s);

		for( int ii=0; ii<this.mSignificantDifferentSymbolsList.size(); ii++ )
		{
			final SigDiffSymbol el
				= (SigDiffSymbol)this.mSignificantDifferentSymbolsList.get(ii);
			el.createDrawingElement();			
		}

		return true;
	}



	protected abstract boolean transformDrawingElementsLocation();



	/**
	 * 
	 */
	public boolean getMarginAroundGraphAreaRect(
		SGTuple2f topAndBottom, SGTuple2f leftAndRight )
	{
//System.out.println("<< SGGraphElement : getMarginAroundGraphAreaRect >>");

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

		ArrayList sList = this.getVisibleSigDiffSymbolList();
		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.mGraphAreaY - (float)uniRect.getY();
		final float bottom = -( this.mGraphAreaY + this.mGraphAreaHeight )
			 + (float)( uniRect.getY() + uniRect.getHeight() );
		final float left = this.mGraphAreaX - (float)uniRect.getX();
		final float right = -( this.mGraphAreaX + this.mGraphAreaWidth )
			 + (float)( uniRect.getX() + uniRect.getWidth() );


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

		return true;
	}



	/**
	 * 
	 */
	public boolean drawBackAllSigDiffSymbols()
	{
		for( int ii=0; ii<this.mSignificantDifferentSymbolsList.size(); ii++ )
		{
			final SigDiffSymbol el
				= (SigDiffSymbol)this.mSignificantDifferentSymbolsList.get(ii);
			if( this.drawBackSigDiffSymbol(el) == false )
			{
				return false;
			}
		}
		
		return true;
	}



	/**
	 * 
	 */
	public boolean chkBoundsVisible()
	{

/*
		if( this.mSignificantDifferentSymbolsList.size()==0 )
		{
			this.setComponentBoundsVisibleFlag(false);
			return true;
		}


		Rectangle fRect = this.getBounds();

		for( int ii=0; ii<this.mSignificantDifferentSymbolsList.size(); ii++ )
		{
			SigDiffSymbol el = (SigDiffSymbol)this.mSignificantDifferentSymbolsList.get(ii);
			Rectangle2D lRect = el.getElementBounds();
			boolean flag = !fRect.contains( lRect );
			if( flag )
			{
				this.setComponentBoundsVisibleFlag(true);
				return true;
			}
		}

		this.setComponentBoundsVisibleFlag(false);
*/

		return true;
	}



	/**
	 * 
	 */
	private boolean drawBackSigDiffSymbol( final SigDiffSymbol el )
	{

/*
//System.out.println("<< drawBackStringElement >>");


		final Rectangle fRect = this.getBounds();
		final Rectangle2D sRect = el.getElementBounds();

//System.out.println("fRect:"+fRect);
//System.out.println("sRect:"+sRect);

		if( !fRect.contains( sRect ) )
		{
//System.out.println("Not included!");

			// show the bounds of this component
			this.setComponentBoundsVisibleFlag(true);


			// 矩形の位置とサイズ
			final double x = sRect.getX();
			final double y = sRect.getY();
			final double w = sRect.getWidth();
			final double h = sRect.getHeight();

//System.out.println(x+"  "+y+"  "+w+"  "+h);

			double xx = this.mMagnification*el.getX();
			double yy = this.mMagnification*el.getY();
			if( x < 0.0 )
			{
//System.out.println("x<0.0");
				xx = this.mMagnification*el.getLineWidth();
			}
			else if( x + w > this.getWidth() )
			{
//System.out.println("x+w>this.getWidth()");
				xx = this.getWidth() - w
					- this.mMagnification*el.getLineWidth();
			}

			if( y < 0.0 )
			{
//System.out.println("y<0.0");
				yy = el.getStringBounds().getHeight() + this.mMagnification*el.getSpace();
			}
			else if( y + h > this.getHeight() )
			{
//System.out.println("y+h>this.getHeight()");
//System.out.println("y="+y);
//System.out.println("h="+h);
//System.out.println("y+h="+(y+h));
//System.out.println("getHeight()="+getHeight());

				yy = ( this.getHeight() - el.getLineBounds().getHeight() )
					- this.mMagnification*el.getLineWidth();
			}

			el.setLocation( (float)xx, (float)yy );

		}
		else
		{
			this.setComponentBoundsVisibleFlag(false);
		}

//System.out.println();

//		el.createDrawingElement();

		this.repaint();
*/

		return true;

	}




	/**
	 * 
	 */
	public void paintGraphics2D( final Graphics2D g2d )
	{

		super.paintGraphics2D(g2d);


		// draw significant difference symbols
		for( int ii=0; ii<this.mSignificantDifferentSymbolsList.size(); ii++ )
		{
			SigDiffSymbol sd
				= (SigDiffSymbol)this.mSignificantDifferentSymbolsList.get(ii);

			if( sd.isVisible() == false )
			{
				continue;
			}
		
			final float lineWidth = this.mMagnification*sd.getLineWidth();
			g2d.setStroke(
				new BasicStroke
				(
					lineWidth,
					BasicStroke.CAP_BUTT,
					BasicStroke.JOIN_MITER
				)
			);
		
			g2d.setPaint( sd.getColor() );

			Shape sh = sd.getConnectedShape();
			g2d.draw(sh);


			// string
			SGDrawingElementString2DExtended sElement
				= (SGDrawingElementString2DExtended)sd.getStringElement();
			sElement.drawString(g2d);

/*
g2d.setStroke( new BasicStroke(1) );
Rectangle2D rect = sd.getElementBounds();
g2d.draw(rect);
rect = sd.getStringBounds();
g2d.draw(rect);
*/

		}



		// draw anchors of significant difference symbols
		if( this.mFocusedSymbol!=null )
		{
			ArrayList list = new ArrayList();
			list.add(this.mFocusedSymbol);
			this.drawSignificantDifferenceSymbolAnchor(g2d,list);
		}
		


	}




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

		boolean flag = true;
		if( element instanceof SGILegendElement )
		{
			final SGILegendElement lElement = (SGILegendElement)element;
			flag = this.synchronizeToLegendElement( lElement );
		}
		else if( element instanceof SGIAxisElement )
		{
//System.out.println("SGIAxisElement");

			final SGIAxisElement aElement = (SGIAxisElement)element;
			flag = this.synchronizeToAxisElement( aElement );
		}
		else if( element instanceof SGIStringElement )
		{
			
		}
		else if( element instanceof SGIGraphElement )
		{
			
		}
		else
		{
			flag = this.synchronizeArgument( element );
		}


		return flag;

	}




	/**
	 * 
	 */
	protected boolean synchronizeToAxisElement( final SGIAxisElement aElement )
	{

//System.out.println("synchronizeToAxisElement");


		//
		// タイミング要素の情報を取得し同期を取る
		//

		{
			// 情報の取得
			final ArrayList axisList = new ArrayList();
			final ArrayList elementListList = new ArrayList();
			final ArrayList valueList = new ArrayList();
			aElement.getTimingElementList(
				axisList, elementListList, valueList );

//System.out.println("axisList:"+axisList);
//System.out.println("elementListList:"+elementListList);
//System.out.println("valueList:"+valueList);
//System.out.println();

/*
for( int ii=0; ii<this.mTimingElementGroupSetList.size(); ii++ )
{
	TimingElementGroupSetInGraph groupSet
		= (TimingElementGroupSetInGraph)this.mTimingElementGroupSetList.get(ii);
	SGDouble value = groupSet.mValue;
	System.out.println(ii+"  "+value);
}
System.out.println();
*/

			// Axisから取得したvalueListにvalueが含まれていないGroupSetはリストから削除
			for( int ii=this.mTimingElementGroupSetList.size()-1; ii>=0; ii-- )
			{
				final TimingElementGroupSetInGraph groupSet
					= (TimingElementGroupSetInGraph)this.mTimingElementGroupSetList.get(ii);
				final SGDouble value = groupSet.mValue;
				final boolean flag = valueList.contains(value);
				if( !flag )
				{
					this.mTimingElementGroupSetList.remove(ii);
				}
			}


			// 
			for( int ii=0; ii<valueList.size(); ii++ )
			{
//System.out.println("ii="+ii);

				final SGDouble value = (SGDouble)valueList.get(ii);
				final SGAxis axis = (SGAxis)axisList.get(ii);
				final ArrayList elementList = (ArrayList)elementListList.get(ii);

				boolean flag = false;
				for( int jj=0; jj<this.mTimingElementGroupSetList.size(); jj++ )
				{
//System.out.println(" jj="+jj);

					final TimingElementGroupSetInGraph groupSet
						= (TimingElementGroupSetInGraph)this.mTimingElementGroupSetList.get(jj);
					final SGDouble value_ = groupSet.mValue;
					if( value_.equals(value) )
					{

						// 描画要素の同期を取る
						final ArrayList groupList = groupSet.mDrawingElementGroupList;
						for( int kk=0; kk<groupList.size(); kk++ )
						{
//System.out.println("  kk="+kk);
							final SGElementGroup group = (SGElementGroup)groupList.get(kk);
							final SGDrawingElement el = (SGDrawingElement)elementList.get(kk);
							group.setProperty(el);
//System.out.println("   "+group.mMagnification);
						}

						flag = true;
						break;
					}
				}

				// valueが存在しない場合には作成
				if( !flag )
				{
//System.out.println("*** create ***");
					// タイミング要素群のセットを作成
					final TimingElementGroupSetInGraph groupSet
						= new TimingElementGroupSetInGraph();

					groupSet.mAxis = axis;
					groupSet.mValue = value;	// SGDoubleオブジェクトをキーとして用いる

					SGTuple2f[] pointsArray = new SGTuple2f[2];
					pointsArray[0] = new SGTuple2f();
					pointsArray[1] = new SGTuple2f();
					groupSet.mPointsArray = pointsArray;

//System.out.println(elementList);
					for( int jj=0; jj<elementList.size(); jj++ )
					{
						final SGDrawingElement el = (SGDrawingElement)elementList.get(jj);
						groupSet.addDrawingElementGroup(el);
					}

					this.mTimingElementGroupSetList.add( ii, groupSet );

					groupSet.setMagnification(this.mMagnification);

					groupSet.initPropertiesHistory();
					this.updateHistory();

//System.out.println();
				}

			}

		}

//System.out.println();



		//
		// 軸のスケールに合わせる
		//

		final ArrayList axisList = aElement.getAxisList();

		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			final ElementGroupSetInGraph groupSet = (ElementGroupSetInGraph)this.mGroupSetList.get(ii);
			final ArrayList groupList = groupSet.mDrawingElementGroupList;

			for( int jj=0; jj<groupList.size(); jj++ )
			{
				final SGElementGroup group = (SGElementGroup)groupList.get(jj);

				for( int kk=0; kk<axisList.size(); kk++ )
				{
					final SGAxis axis = (SGAxis)axisList.get(kk);
					final SGTuple2d range = axis.getRange();
					if(axis.equals(groupSet.mXAxis))
					{
						groupSet.mXAxis.setRange(range.x,range.y);
					}
					if(axis.equals(groupSet.mYAxis))
					{
						groupSet.mYAxis.setRange(range.x,range.y);
					}
					if(axis.equals(groupSet.mZAxis))
					{
						groupSet.mZAxis.setRange(range.x,range.y);
					}
				}	
			}
		}


		// 描画要素の作成
		this.setAllDrawingElementsLocation();

//		this.repaint();

		return true;

	}



	/**
	 * 
	 */
	protected boolean synchronizeToLegendElement( final SGILegendElement lElement )
	{

		// レジェンドからデータのリストを取得し、自分の持っているデータリストと
		// 描画要素リストをそれに合わせて並び替える
		final ArrayList dataList = lElement.getDataList();
		if( dataList.size() != this.mDataList.size() )
		{
			throw new Error("dataList.size() != this.mDataList.size()");
		}
		final ArrayList dataListNew = new ArrayList();
		final ArrayList groupSetListNew = new ArrayList();
		for( int ii=0; ii<dataList.size(); ii++ )
		{
			final SGData data = (SGData)dataList.get(ii);
			for( int jj=this.mDataList.size()-1; jj>=0; jj-- )
			{
				final SGData data_ = (SGData)this.mDataList.get(jj);
				if( data.equals(data_) )
				{
					final SGData dataRemoved = (SGData)this.mDataList.remove(jj);
					dataListNew.add(dataRemoved);
					final SGElementGroupSet groupSetRemoved = (SGElementGroupSet)this.mGroupSetList.remove(jj);
					groupSetListNew.add(groupSetRemoved);
					break;
				}
			}
		}
		this.mDataList = dataListNew;
		this.mGroupSetList = groupSetListNew;			


		return true;
	}



	/**
	 * 同期させる
	 */
	public boolean synchronizeArgument( final SGIFigureElement element )
	{
		if( true )
		{
			throw new Error("");
		}

		return false;
	}



	/**
	 * タイミング線の位置を決定
	 */

	protected boolean calcLocationOfTimingLine(
		final double value,
		final SGAxis axis,
		final SGTuple2f startPoint,
		final SGTuple2f endPoint )
	{

		// SGAxisElementから軸のリストを取得
		final ArrayList hAxisList = this.mAxisElement.getHorizontalAxisList();
		final ArrayList pAxisList = this.mAxisElement.getPerpendicularAxisList();


		Boolean hFlag = null;
		if( hAxisList.contains(axis) )
		{
			hFlag = new Boolean(true);
		}
		if( pAxisList.contains(axis) )
		{
			hFlag = new Boolean(false);
		}
		if( hFlag == null )
		{
			throw new Error("軸が一致しない");
		}

		if( hFlag.booleanValue() )
		{
			final float ratio = this.calcLocation( value, axis, true );
			startPoint.x = ratio;
			startPoint.y = (float)this.getHeight();
			endPoint.x = ratio;
			endPoint.y = 0.0f;
		}
		else
		{
			final float ratio = this.calcLocation( value, axis, false );
			startPoint.x = 0.0f;
			startPoint.y = ratio;
			endPoint.x = (float)this.getWidth();
			endPoint.y = ratio;
		}

		return true;
	}



	/**
	 * 
	 */
	protected boolean isInsideAxisRange(
		final SGTuple2d value,
		final SGAxis axisX,
		final SGAxis axisY )
	{
		return ( axisX.insideRange(value.x) && axisY.insideRange(value.y) );
	}




	/**
	 * 
	 */
	protected boolean calcLocationOfSXYData(
		final SGTuple2d[] valueArray,
		final SGAxis axisX,
		final SGAxis axisY,
		final SGTuple2f[] pointArray )
	{
//System.out.println("<< SGGraphElement::calcLocationOfSXYData >>");

		final int num = valueArray.length;

		final SGTuple2d rangeX = axisX.getRange();
		final SGTuple2d rangeY = axisY.getRange();
		final double minX = rangeX.x;
		final double maxX = rangeX.y;
		final double minY = rangeY.x;
		final double maxY = rangeY.y;
		final int typeX = axisX.getScaleType();
		final int typeY = axisY.getScaleType();


		// グラフ内での値に変換
		double minXInScale = 0.0;
		double maxXInScale = 0.0;
		double minYInScale = 0.0;
		double maxYInScale = 0.0;
		final double[] xInScale = new double[num];
		final double[] yInScale = new double[num];

		if( typeX == SGAxis.LINEAR_TYPE )
		{
			minXInScale = minX;
			maxXInScale = maxX;
			for( int ii=0; ii<num; ii++)
			{
				xInScale[ii] = valueArray[ii].x;
			}
		}
		else if( typeX == SGAxis.LOG_TYPE )
		{
			minXInScale = Math.log(minX);
			maxXInScale = Math.log(maxX);
			for( int ii=0; ii<num; ii++)
			{
				xInScale[ii] = Math.log(valueArray[ii].x);
			}
		}

		if( typeY == SGAxis.LINEAR_TYPE )
		{
			minYInScale = minY;
			maxYInScale = maxY;
			for( int ii=0; ii<num; ii++)
			{
				yInScale[ii] = valueArray[ii].y;
			}
		}
		else if( typeY == SGAxis.LOG_TYPE )
		{
			minYInScale = Math.log(minY);
			maxYInScale = Math.log(maxY);
			for( int ii=0; ii<num; ii++)
			{
				yInScale[ii] = Math.log(valueArray[ii].y);
			}
		}


		// グラフ領域内でのデータ点の比率を計算
		// グラフ全体での位置を計算
		for( int ii=0; ii<num; ii++ )
		{
			// ratio in the graph area rectangle
			final float xRatio
				= (float)( ( xInScale[ii] - minXInScale )/( maxXInScale - minXInScale ) );
			final float yRatio
				= (float)( 1.0 - ( yInScale[ii] - minYInScale )/( maxYInScale - minYInScale ) );

			// set the location of points
			final float posX = ( this.mGraphAreaX + xRatio*this.mGraphAreaWidth );
			final float posY = ( this.mGraphAreaY + yRatio*this.mGraphAreaHeight );
			pointArray[ii].setValues( (float)posX, (float)posY );
		}

//System.out.println("AAA");
		return true;
	}




	/**
	 * 
	 */
/*	protected boolean calcLocationOfVXYData(
		final SGTuple2d[] startArray,
		final SGTuple2d[] endArray,
		final SGAxis axisX,
		final SGAxis axisY,
		final ArrayList startLocationList,
		final ArrayList endLocationList )
	{

		if( startArray.length != endArray.length )
		{
			throw new IllegalArgumentException("startArray.length != endArray.length");
		}


		final SGTuple2d rangeX = axisX.getRange();
		final SGTuple2d rangeY = axisY.getRange();
		final double minX = rangeX.x;
		final double maxX = rangeX.y;
		final double minY = rangeY.x;
		final double maxY = rangeY.y;
		final int typeX = axisX.getScaleType();
		final int typeY = axisY.getScaleType();

		int num = startArray.length;


		// 点がスケール内に存在するかどうかのフラグ
		final boolean[] startInsideFlagArray = new boolean[num];
		final boolean[] endInsideFlagArray = new boolean[num];
		for( int ii=0; ii<num; ii++ )
		{
			startInsideFlagArray[ii] = this.isInsideAxisRange( startArray[ii], axisX, axisY );
			endInsideFlagArray[ii] = this.isInsideAxisRange( endArray[ii], axisX, axisY );
		}


		// 両方ともグラフ領域内に無い場合には除く
		final ArrayList startList = new ArrayList();
		final ArrayList endList = new ArrayList();
		for( int ii=0; ii<num; ii++ )
		{
			if( startInsideFlagArray[ii] || endInsideFlagArray[ii] )
			{
				startList.add( startArray[ii] );
				endList.add( endArray[ii] );
			}
		}


		//
		final SGTuple2d[] startArray2 = new SGTuple2d[startList.size()];
		final SGTuple2d[] endArray2 = new SGTuple2d[endList.size()];
		for( int ii=0; ii<startList.size(); ii++ )
		{
			startArray2[ii] = (SGTuple2d)startList.get(ii);
			endArray2[ii] = (SGTuple2d)endList.get(ii);
		}

		final int num2 = startArray2.length;


		// グラフ領域内でのデータ点の比率を計算
		final SGTuple2f[] startRatioArray = new SGTuple2f[num2];
		for( int ii=0; ii<num2; ii++ )
		{
//System.out.println(startArray[ii].x+"  "+startArray[ii].y);

			final double x = startArray2[ii].x;
			final double y = startArray2[ii].y;

			startRatioArray[ii] = new SGTuple2f();
			startRatioArray[ii].x = (float)( (x-minX)/(maxX-minX) );
			startRatioArray[ii].y = (float)( 1.0 - (y-minY)/(maxY-minY) );
		}
//System.out.println();

//System.out.println("end");
		final SGTuple2f[] endRatioArray = new SGTuple2f[num2];
		for( int ii=0; ii<num2; ii++ )
		{
//System.out.println(endArray[ii].x+"  "+endArray[ii].y);

			final double x = endArray2[ii].x;
			final double y = endArray2[ii].y;

			endRatioArray[ii] = new SGTuple2f();
			endRatioArray[ii].x = (float)( (x-minX)/(maxX-minX) );
			endRatioArray[ii].y = (float)( 1.0 - (y-minY)/(maxY-minY) );
		}
//System.out.println();


//System.out.println("start");
		// グラフ全体に対する比率を計算
		for( int ii=0; ii<num2; ii++ )
		{
			final float ratioX = ( mGraphAreaX + startRatioArray[ii].x*mGraphAreaWidth );
			final float ratioY = ( mGraphAreaY + startRatioArray[ii].y*mGraphAreaHeight );
			final SGTuple2f ratio = new SGTuple2f( ratioX, ratioY );
			startLocationList.add( ratio );
//System.out.println(ratioX+"  "+ratioY);
		}
//System.out.println();

//System.out.println("end");
		for( int ii=0; ii<num2; ii++ )
		{
			final float posX = ( mGraphAreaX + endRatioArray[ii].x*mGraphAreaWidth );
			final float posY = ( mGraphAreaY + endRatioArray[ii].y*mGraphAreaHeight );
			final SGTuple2f pos = new SGTuple2f( posX, posY );
			endLocationList.add( pos );
		}
//System.out.println();

		return true;
	}
*/


	/**
	 * 
	 */
	protected boolean calcLocationOfVXYData(
		final SGTuple2d[] startArray,
		final SGTuple2d[] endArray,
		final SGAxis axisX,
		final SGAxis axisY,
		final SGTuple2f[] startLocationArray,
		final SGTuple2f[] endLocationArray )
	{

		if( startArray==null || endArray==null || startLocationArray==null || endLocationArray==null )
		{
			throw new IllegalArgumentException("startArray==null || endArray==null || startLocationArray==null || endLocationArray==null");
		}

		if( startArray.length != endArray.length )
		{
			throw new IllegalArgumentException("startArray.length != endArray.length");
		}

		if( startLocationArray.length != endLocationArray.length )
		{
			throw new IllegalArgumentException("startLocationArray.length != endLocationArray.length");
		}


		final SGTuple2d rangeX = axisX.getRange();
		final SGTuple2d rangeY = axisY.getRange();
		final double minX = rangeX.x;
		final double maxX = rangeX.y;
		final double minY = rangeY.x;
		final double maxY = rangeY.y;
		final int typeX = axisX.getScaleType();
		final int typeY = axisY.getScaleType();

		int num = startArray.length;


		// グラフ領域内でのデータ点の比率を計算
		final SGTuple2f[] startRatioArray = new SGTuple2f[num];
		for( int ii=0; ii<num; ii++ )
		{
//System.out.println(startArray[ii].x+"  "+startArray[ii].y);

			final double x = startArray[ii].x;
			final double y = startArray[ii].y;

			startRatioArray[ii] = new SGTuple2f();
			startRatioArray[ii].x = (float)( (x-minX)/(maxX-minX) );
			startRatioArray[ii].y = (float)( 1.0 - (y-minY)/(maxY-minY) );
		}
//System.out.println();

//System.out.println("end");
		final SGTuple2f[] endRatioArray = new SGTuple2f[num];
		for( int ii=0; ii<num; ii++ )
		{
//System.out.println(endArray[ii].x+"  "+endArray[ii].y);

			final double x = endArray[ii].x;
			final double y = endArray[ii].y;

			endRatioArray[ii] = new SGTuple2f();
			endRatioArray[ii].x = (float)( (x-minX)/(maxX-minX) );
			endRatioArray[ii].y = (float)( 1.0 - (y-minY)/(maxY-minY) );
		}
//System.out.println();


//System.out.println("start");
		// グラフ全体に対する比率を計算
		for( int ii=0; ii<num; ii++ )
		{
			final float ratioX = ( mGraphAreaX + startRatioArray[ii].x*mGraphAreaWidth );
			final float ratioY = ( mGraphAreaY + startRatioArray[ii].y*mGraphAreaHeight );
			startLocationArray[ii].setValues( ratioX, ratioY );
		}
//System.out.println();

//System.out.println("end");
		for( int ii=0; ii<num; ii++ )
		{
			final float posX = ( mGraphAreaX + endRatioArray[ii].x*mGraphAreaWidth );
			final float posY = ( mGraphAreaY + endRatioArray[ii].y*mGraphAreaHeight );
			endLocationArray[ii].setValues( posX, posY );
		}
//System.out.println();


		return true;
	}



	/**
	 * 
	 */
	public boolean hasSelectedData()
	{
		return ( this.mSelectedGroupSetList.size()!=0 );
	}



	/**
	 * 
	 * @param e
	 * @param groupSet
	 * @return
	 */
	protected boolean clickElementGroupSet(
		final MouseEvent e,
		final ElementGroupSetInGraph groupSet )
	{
//System.out.println("<< SGGraphElement::clickElementGroupSet >>");
//System.out.println(this);

		// if the mouse is not on the drawing element, return false
		final boolean flag = groupSet.contains( e.getX(), e.getY() );

//System.out.println("*** "+flag);
//System.out.println();
		if( !flag )
		{
			return false;
		}


		// 右ボタンクリック１回でポップアップメニューを出す。
		// オブジェクトが選択されている場合には、
		// 共通の項目を記述したポップアップメニューを出す。
		if( ( SwingUtilities.isRightMouseButton(e) )
			&& ( e.getClickCount() == 1 ) )
		{
			groupSet.mPopupMenu.show( this, e.getX(), e.getY() );
			return true;
		}


		// left button
		if( SwingUtilities.isLeftMouseButton(e) )
		{

			// 左ボタンクリック２回でダイアログを出す。
			if( e.getClickCount() == 2 )
			{
				// show the property dialog
				groupSet.showPropertyDialog();

				// clear the selected group set
				this.clearSelectedElementsGroupSet();

				return true;
			}


			if( e.getClickCount() == 1 )
			{

				// CtrlキーもShiftキーも押さない状態での
				// 左ボタンクリック１回で、
				// オブジェクトの選択/解除を行う。
				if(
					( (e.getModifiers()&MouseEvent.CTRL_MASK) == 0)
					&& ( (e.getModifiers()&MouseEvent.SHIFT_MASK) == 0)
				)
				{

					if( this.mSelectedGroupSetList.contains(groupSet) )
					{
						// nothing to do
					}
					else
					{
						this.clearSelectedElementsGroupSet();
						this.addSelectedGroupSet(groupSet);
					}

				}
				else
				// CtrlキーまたはShiftキーを押した状態での左ボタンクリック１回で、
				// 複数のオブジェクトの選択/解除を行う。
				{

					if( this.mSelectedGroupSetList.contains(groupSet) )
					{
						this.removeSelectedGroupSet(groupSet);
					}
					else
					{
						// keep the present list
						ArrayList list = new ArrayList( this.mSelectedGroupSetList );

						// add a new group set
						list.add( groupSet );

						// clear
						this.clearSelectedElementsGroupSet();

						// update the list
						for( int ii=0; ii<list.size(); ii++ )
						{
							ElementGroupSetInGraph gs
								= (ElementGroupSetInGraph)list.get(ii);
							this.addSelectedGroupSet(gs);
						}
					}
					
				}

				return true;
				
			}

		}

		return false;
	}



	/**
	 * 
	 * @param e
	 * @param groupSet
	 * @return
	 */
	protected boolean pressElementGroupSet(
		final MouseEvent e,
		final ElementGroupSetInGraph groupSet )
	{

		final boolean flag = groupSet.contains( e.getX(), e.getY() );
		if( !flag )
		{
			return false;
		}

		return true;
	}



	/**
	 * 
	 * @param e
	 * @param groupSet
	 * @return
	 */
	protected boolean dragElementGroupSet(
		final MouseEvent e,
		final ElementGroupSetInGraph groupSet )
	{

		if( this.mSelectedGroupSetList.size()!=0 )
		{
			return true;
		}

		return false;
	}



	/**
	 * 
	 */
	protected boolean moveGroupSetToFront( final SGElementGroupSet groupSet )
	{
		SGData data = null;

		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			if( groupSet.equals(this.mGroupSetList.get(ii)) )
			{
				mGroupSetList.remove(ii);
				data = (SGData)mDataList.remove(ii);
				break;
			}
		}

		if( data == null )
		{
			return false;
		}

		mGroupSetList.add(mGroupSetList.size(),groupSet);
		mDataList.add(mDataList.size(),data);

		return true;
	}


	/**
	 * 
	 */
	protected boolean moveGroupSetToBack( final SGElementGroupSet groupSet )
	{
//System.out.println("<< moveGroupSetToBack >>");
//System.out.println(this.mGroupSetList);
//System.out.println(this.mDataList);

		SGData data = null;
		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			if( groupSet.equals(this.mGroupSetList.get(ii)) )
			{
				mGroupSetList.remove(ii);
				data = (SGData)mDataList.remove(ii);
				break;
			}
		}
//System.out.println("selected:"+data);
		if( data == null )
		{
			return false;
		}

		mGroupSetList.add(0,groupSet);
		mDataList.add(0,data);

//System.out.println(this.mGroupSetList);
//System.out.println(this.mDataList);

		return true;
	}


	/**
	 * 
	 */
	protected boolean removeGroupSet( final SGElementGroupSet groupSet )
	{
		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			if( groupSet.equals(this.mGroupSetList.get(ii)) )
			{
				mGroupSetList.remove(ii);
				mDataList.remove(ii);
				return true;
			}
		}

		return false;
	}



	/**
	 * 
	 */
	public boolean hideSelectedData()
	{

//System.out.println("<< hideSelectedData >>");
//System.out.println(this.mSelectedGroupSetList);

		if( this.mSelectedGroupSetList.size() == 0 )
		{
			return true;
		}

		for( int ii=0; ii<this.mSelectedGroupSetList.size(); ii++ )
		{
			final SGElementGroupSet groupSet
				= (SGElementGroupSet)this.mSelectedGroupSetList.get(ii);

			// set invisible
			groupSet.setVisible(false);

			// set unselected
			groupSet.setSelected(false);
		}
		this.mSelectedGroupSetList.clear();

//System.out.println(this.mSelectedGroupSetList);
//System.out.println();

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

		notifyChange();
//		repaint();

		return true;
	}


	/**
	 * 
	 */
	public boolean isDataVisible( SGData data )
	{
		SGElementGroupSet groupSet = this.getElementGroupSet(data);
		return groupSet.isVisible();
	}


	/**
	 * 
	 */
	public boolean removeSelectedData()
	{

//System.out.println("<< removeSelectedDatas >>");
//System.out.println(this.mSelectedGroupSetList);

		if( this.mSelectedGroupSetList.size() == 0 )
		{
			return true;
		}

//System.out.println("before:"+mDataList);

		for( int ii=0; ii<this.mSelectedGroupSetList.size(); ii++ )
		{
			final SGElementGroupSet groupSet
				= (SGElementGroupSet)this.mSelectedGroupSetList.get(ii);
			this.removeGroupSet( groupSet );
		}

//System.out.println("after:"+mDataList);
//System.out.println();

		notifyChange();
//		repaint();

		return true;
	}



	/**
	 * 
	 */
	public boolean moveSelectedDataToFront()
	{

		if( this.mSelectedGroupSetList.size() == 0 )
		{
			return true;
		}

		for( int ii=this.mSelectedGroupSetList.size()-1; ii>=0; ii-- )
		{
			final SGElementGroupSet groupSet = (SGElementGroupSet)this.mSelectedGroupSetList.get(ii);
			this.moveGroupSetToFront( groupSet );
		}
		this.mSelectedGroupSetList.clear();

		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			SGElementGroupSet gs = (SGElementGroupSet)this.mGroupSetList.get(ii);
			gs.setVisible(true);
		}

		notifyChange();
//		repaint();

		return true;
	}


	/**
	 * 
	 */
	public boolean moveSelectedDataToBack()
	{

		if( this.mSelectedGroupSetList.size() == 0 )
		{
			return true;
		}

		for( int ii=this.mSelectedGroupSetList.size()-1; ii>=0; ii-- )
		{
			final SGElementGroupSet groupSet = (SGElementGroupSet)this.mSelectedGroupSetList.get(ii);
			this.moveGroupSetToBack( groupSet );
		}
		this.mSelectedGroupSetList.clear();

		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			SGElementGroupSet gs = (SGElementGroupSet)this.mGroupSetList.get(ii);
			gs.setVisible(true);
		}

		notifyChange();
//		repaint();

		return true;
	}


	/**
	 * 
	 */
	protected SGElementGroupSet getElementGroupSet( SGData data )
	{

		for( int ii=0; ii<this.mDataList.size(); ii++ )
		{
			SGData data_ = (SGData)this.mDataList.get(ii);
			if( data_.equals(data) )
			{
				SGElementGroupSet groupSet = (SGElementGroupSet)this.mGroupSetList.get(ii);
				return groupSet;
			}
		}

		return null;

	}



	/**
	 * 
	 */
	protected SGData getData( SGElementGroupSet groupSet )
	{

		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			SGElementGroupSet groupSet_ = (SGElementGroupSet)this.mGroupSetList.get(ii);
			if( groupSet_.equals(groupSet) )
			{
				SGData data = (SGData)this.mDataList.get(ii);
				return data;
			}
		}

		return null;
	}



	/**
	 * 
	 */
	private boolean addSelectedGroupSet( final SGElementGroupSet groupSet )
	{
		this.mSelectedGroupSetList.add(groupSet);
		groupSet.setSelected( true );

		return true;		
	}


	/**
	 * 
	 */
	private boolean removeSelectedGroupSet( final SGElementGroupSet groupSet )
	{
		this.mSelectedGroupSetList.remove(groupSet);
		groupSet.setSelected( false );
		groupSet.setVisible(true);

		return true;		
	}



	/**
	 * 
	 */
	private boolean clearSelectedElementsGroupSet()
	{
		for( int ii=this.mSelectedGroupSetList.size()-1; ii>=0; ii-- )
		{
			final SGElementGroupSet groupSet
				= (SGElementGroupSet)mSelectedGroupSetList.get(ii);
			removeSelectedGroupSet(groupSet);
		}

		return true;
	}



	/**
	 * 
	 * @return
	 */
	public ArrayList getPropertySettingListerListOfDataElements()
	{
		return this.mSelectedGroupSetList;
	}



	/**
	 * 
	 * @return
	 */
	public SGPropertyDialog getPropertyDialogForDataElements()
	{
		return mPropertyDialogForData;
	}



	/**
	 * 
	 */
	public static final int mEmphasisSymbolSize = 6;



	/**
	 * 
	 * @return
	 */
	protected boolean drawEmphasisSymol(
		final Graphics2D g2d, final Point2D pos )
	{
		final int size = mEmphasisSymbolSize;
		final Rectangle2D rect = new Rectangle2D.Float(
			(float)pos.getX() - size/2,
			(float)pos.getY() - size/2,
			size, size );
		g2d.setStroke( new BasicStroke(1) );
		g2d.setPaint( Color.WHITE );
		g2d.fill(rect);
		g2d.setPaint( Color.BLACK );
		g2d.draw(rect);

		return true;
	}



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

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


		// click the data
		if( this.clickDrawingElements(e) )
		{
			return true;
		}


		// if no data are clicked, clear the list of clicked data.
		this.clearSelectedElementsGroupSet();

//System.out.println("cleared");
//System.out.println();


		// significant difference symbols
		for( int ii=this.mSignificantDifferentSymbolsList.size()-1; ii>=0; ii-- )
		{
			SigDiffSymbol el
				= (SigDiffSymbol)this.mSignificantDifferentSymbolsList.get(ii);

			if( el.isVisible() == false )
			{
				continue;
			}

//System.out.println("ii="+ii);
//System.out.println(el);
//System.out.println(el.mStringElement);

			// clicked on the line elements
			if( el.contains(x,y) )
			{
//System.out.println("clicked - body");
//System.out.println();

				if( (SwingUtilities.isLeftMouseButton(e) )
				&& ( e.getClickCount() == 1 ) )
				{
					return true;
				}
				else if( (SwingUtilities.isLeftMouseButton(e) )
				&& ( e.getClickCount() == 2 ) )
				{
					JDialog dialog = el.getDialog();
					dialog.show();
				}
				else if( (SwingUtilities.isRightMouseButton(e) )
				&& ( e.getClickCount() == 1 ) )
				{
					JPopupMenu menu = el.getPopupMenu();
					menu.show( this, e.getX(), e.getY() );
				}

				return true;
			}

			// clicked on the string element
			if( el.mStringElement.contains(x,y) )
			{
//System.out.println("clicked - string");
//System.out.println(el.getStringElement().getString());

				if( (SwingUtilities.isLeftMouseButton(e) )
				&& ( e.getClickCount() == 1 ) )
				{
					mFocusedSymbol = el;
					mFocusedX = (int)this.getX();
					mFocusedY = (int)this.getY();
					showEditField( el );
//					repaint();
				}
		
				return true;
			}

		}


		// timing lines
		for( int ii=this.mTimingElementGroupSetList.size()-1; ii>=0; ii-- )
		{

			final TimingElementGroupSetInGraph groupSet
				= (TimingElementGroupSetInGraph)this.mTimingElementGroupSetList.get(ii);

			if( groupSet.isVisible() == false )
			{
				continue;
			}

			if( groupSet.clickDrawingElements(e) )
			{
				return true;
			}

		}


/*
		if( this.mEditField.isVisible() )
		{
			this.terminateEditField();
		}
		else
		{
			this.terminateSelectedSymbol();
			repaint();
		}
*/

		return false;
	}



	/**
	 * 
	 * @param e
	 * @return
	 */
	public boolean clickDrawingElements( final MouseEvent e )
	{
//System.out.println("<< clickDrawingElements >>");

		for( int ii=this.mGroupSetList.size()-1; ii>=0; ii-- )
		{
//System.out.println("ii="+ii);
			final ElementGroupSetInGraph groupSet
				= (ElementGroupSetInGraph)mGroupSetList.get(ii);
			if( groupSet.isVisible() ==false )
			{
				continue;
			}

			if( this.clickElementGroupSet( e, groupSet ) )
			{
				return true;
			}
		}

		return false;
	}



	/**
	 * 
	 * @param e
	 * @return
	 */
	public boolean pressDrawingElements( final MouseEvent e )
	{
//System.out.println("<< clickDrawingElements >>");

		for( int ii=this.mGroupSetList.size()-1; ii>=0; ii-- )
		{
//System.out.println("ii="+ii);
			final ElementGroupSetInGraph groupSet
				= (ElementGroupSetInGraph)mGroupSetList.get(ii);

			if( this.pressElementGroupSet( e, groupSet ) )
			{
				return true;
			}
		}

		return false;
	}


	/**
	 * 
	 * @param e
	 * @return
	 */
	public boolean dragDrawingElements( final MouseEvent e )
	{
//System.out.println("<< clickDrawingElements >>");

		for( int ii=this.mGroupSetList.size()-1; ii>=0; ii-- )
		{
//System.out.println("ii="+ii);
			final ElementGroupSetInGraph groupSet
				= (ElementGroupSetInGraph)mGroupSetList.get(ii);

			if( this.dragElementGroupSet( e, groupSet ) )
			{
				return true;
			}
		}

		return false;
	}



	/**
	 * 
	 * @param e
	 */
	public boolean onMousePressed( final MouseEvent e )
	{
//System.out.println("<< onMousePressed >>");

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


		// press the data
		if( this.pressDrawingElements(e) )
		{
			return true;
		}


		// significant difference symbols
		for( int ii=this.mSignificantDifferentSymbolsList.size()-1; ii>=0; ii-- )
		{
			SigDiffSymbol el
				= (SigDiffSymbol)this.mSignificantDifferentSymbolsList.get(ii);

			if( el.isVisible() == false )
			{
				continue;
			}

			if( el.pressDrawingElements(e) )
			{
//System.out.println("@@@@@@@@@@@@@@@@@@ press @@@@@@@@@@@@@@@@@@");

				this.mFocusedSymbol = el;
				this.mPressedSymbolOrigin
					= new Point(
						(int)(e.getX()-el.getX()),
						(int)(e.getY()-el.getY())
					);

//				repaint();

				return true;
			}

		}


		if( this.mEditField.isVisible() )
		{
			this.terminateEditField();
		}
		this.clearFocusedSymbol();
//		repaint();


		return false;

	}	

	

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

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


		// drag the data
		if( this.dragDrawingElements(e) )
		{
			return true;
		}


		if( this.mFocusedSymbol!=null )
		{
			if( this.mFocusedSymbol.drag(e) == false )
			{
				return false;
			}

			this.drawBackSigDiffSymbol( this.mFocusedSymbol );
			this.mFocusedSymbol.createDrawingElement();

//			repaint();

		}


		return true;
	}


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

		if( this.mFocusedSymbol != null )
		{
			//
			if( this.mFocusedSymbol.isChanged() )
			{
				this.mFocusedSymbol.updateHistory();
			}

//			repaint();
		}


		return true;
	}


	/**
	 * 
	 */
	public boolean onKeyPressed( final KeyEvent e )
	{
		return true;
	}


	/**
	 * 
	 */
	public boolean onKeyReleased( final KeyEvent e )
	{
		return true;
	}


	/**
	 * 
	 */
	public boolean onKeyTyped( final KeyEvent e )
	{
		return true;
	}




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


		// significant difference symbols
		for( int ii=0; ii<this.mSignificantDifferentSymbolsList.size(); ii++ )
		{
			SigDiffSymbol sd
				= (SigDiffSymbol)this.mSignificantDifferentSymbolsList.get(ii);

			if( sd.isVisible() == false )
			{
				continue;
			}

			if( sd.onDrawingElement(x,y) )
			{
				if( sd.equals(this.mFocusedSymbol) )
				{
					sd.mMouseLocation = sd.getMouseLocation(x,y);
					this.mCursor = sd.getCursor( sd.mMouseLocation );
//					repaint();
					return true;
				}
				else
				{
					this.mCursor = new Cursor( Cursor.HAND_CURSOR );
//					repaint();
					return true;
				}
			}

		}



		// グラフの領域外であれば終了
		if( !this.isInsideGraphArea(x,y) )
		{
/*
			// グループのmEnteredFlagをfalseに設定する
			for( int ii=this.mGroupSetList.size()-1; ii>=0; ii-- )
			{
				final ElementGroupSetInGraph groupSet = (ElementGroupSetInGraph)mGroupSetList.get(ii);
				final ArrayList groupList = groupSet.mDrawingElementGroupList;
			
				for( int jj=groupList.size()-1; jj>=0; jj-- )
				{
					final SGElementGroup group = (SGElementGroup)groupList.get(jj);
//					group.mEnteredFlag = false;
				}
			}
*/
			return false;
		}


/*
		// 描画要素に対してマウスが上にあるかどうか問い合わせる
		for( int ii=this.mGroupSetList.size()-1; ii>=0; ii-- )
		{
			final ElementGroupSetInGraph groupSet = (ElementGroupSetInGraph)mGroupSetList.get(ii);
			if( groupSet.onDrawingElement(x,y) )
			{
				this.mCursor = new Cursor( Cursor.HAND_CURSOR );
				return true;
			}
		}
*/

//System.out.println("moved@"+System.currentTimeMillis());


//		repaint();

		return false;
	}



	/**
	 * 
	 */
	public boolean addSignificantDifferenceSymbol( final int x, final int y )
	{
//System.out.println("addSignificantDifferenceSymbol  "+x+" "+y);

		SigDiffSymbol sd = new SigDiffSymbol();
		sd.zoom(this.mMagnification);
		sd.setLocation( x, y );
		sd.createDrawingElement();

		this.mSignificantDifferentSymbolsList.add(sd);

		//
		this.updateHistory();

		// initialize history
		sd.initPropertiesHistory();

		return true;
	}



	/**
	 * 
	 */
	protected ArrayList mSignificantDifferentSymbolsList = new ArrayList();




	/**
	 * 描画メソッド
	 */
	protected boolean clipGraphArea( final Graphics2D g2d )
	{
		if( this.mViewBounds == null )
		{
			return false;				
		}
		final Rectangle2D rectGraph = this.getGraphAreaRect();
		final Rectangle2D rectCommon = new Rectangle2D.Float();
		Rectangle2D.intersect( rectGraph, this.mViewBounds, rectCommon );
		g2d.setClip( rectCommon );

		return true;
	}



	/**
	 * 
	 */
	protected boolean drawTimingElements( final Graphics2D g2d )
	{

		for( int ii=0; ii<this.mTimingElementGroupSetList.size(); ii++ )
		{
//System.out.println("ii="+ii);

			final TimingElementGroupSetInGraph groupSet
				= (TimingElementGroupSetInGraph)mTimingElementGroupSetList.get(ii);

			final ArrayList groupList = groupSet.mDrawingElementGroupList;
			for( int jj=0; jj<groupList.size(); jj++ )
			{
//System.out.println(" jj="+jj);
				final SGElementGroup group = (SGElementGroup)groupList.get(jj);
//System.out.println(" "+group);
				group.paintElement(g2d);
			}
		}
//System.out.println();


		return true;
	}




	/**
	 * 
	 */
	protected boolean moveTimingElementGroupSetToFront( final SGElementGroupSet groupSet )
	{

		for( int ii=0; ii<this.mTimingElementGroupSetList.size(); ii++ )
		{
			if( groupSet.equals(this.mTimingElementGroupSetList.get(ii)) )
			{
				mTimingElementGroupSetList.remove(ii);
				break;
			}
		}

		mTimingElementGroupSetList.add(mTimingElementGroupSetList.size(),groupSet);

		return true;
	}


	/**
	 * 
	 */
	protected boolean moveTimingElementGroupSetToBack( final SGElementGroupSet groupSet )
	{

		for( int ii=0; ii<this.mTimingElementGroupSetList.size(); ii++ )
		{
			if( groupSet.equals(this.mTimingElementGroupSetList.get(ii)) )
			{
				mTimingElementGroupSetList.remove(ii);
				break;
			}
		}

		mTimingElementGroupSetList.add(0,groupSet);

		return true;
	}



	/**
	 * 
	 */
	protected boolean removeTimingElementGroupSet( final SGElementGroupSet groupSet )
	{
		this.mTimingElementGroupSetList.remove(groupSet);
		this.updateHistory();

		return false;
	}


	/**
	 * 
	 */
	protected boolean drawRectangle(
		final double xMin, final double xMax, final double yMin, double yMax, final Graphics2D g2d )
	{

		if( g2d == null )
		{
			return false;
		}

		final Line2D lineUpper = new Line2D.Double( xMin, yMin, xMax, yMin );
		final Line2D lineLower = new Line2D.Double( xMin, yMax, xMax, yMax );
		final Line2D lineLeft = new Line2D.Double( xMin, yMin, xMin, yMax );
		final Line2D lineRight = new Line2D.Double( xMax, yMin, xMax, yMax );

		g2d.draw(lineUpper);
		g2d.draw(lineLower);
		g2d.draw(lineLeft);
		g2d.draw(lineRight);

		return true;
	}


	/**
	 * 
	 */
	public boolean changeXAxis( final SGData data )
	{

		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			final SGData data_ = (SGData)this.mDataList.get(ii);
			if( data_.equals(data) )
			{
				final ElementGroupSetInGraph groupSet
					= (ElementGroupSetInGraph)this.mGroupSetList.get(ii);
				this.changeXAxis( groupSet );
				return true;
			}

		}

		return false;
	}



	/**
	 * 
	 */
	public boolean changeYAxis( final SGData data )
	{

		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			final SGData data_ = (SGData)this.mDataList.get(ii);
			if( data_.equals(data) )
			{
				final ElementGroupSetInGraph groupSet
					= (ElementGroupSetInGraph)this.mGroupSetList.get(ii);
				this.changeYAxis( groupSet );
				return true;
			}

		}

		return false;
	}



	/**
	 * 
	 */
	public boolean changeZAxis( final SGData data )
	{
		return true;
	}



	/**
	 * 
	 */
	protected boolean changeXAxis( final ElementGroupSetInGraph groupSet )
	{
		SGAxis axisOfGroup = groupSet.mXAxis;

//System.out.println(axisOfGroup);

		final ArrayList list = mAxisElement.getXAxisList();

		SGAxis axisToChange = null;
		for( int ii=0; ii<list.size(); ii++ )
		{
			final SGAxis axis = (SGAxis)list.get(ii);
			if( axisOfGroup == axis )
			{
				axisToChange = (SGAxis)list.get((ii+1)%list.size());
				break;
			}
		}

		axisOfGroup = axisToChange;

//System.out.println(axisToChange);

		groupSet.mXAxis = axisToChange;

		return true;
	}



	/**
	 * 
	 */
	protected boolean changeYAxis( ElementGroupSetInGraph groupSet )
	{
		SGAxis axisOfGroup = groupSet.mYAxis;

//System.out.println(axisOfGroup);


		final ArrayList list = mAxisElement.getYAxisList();

		SGAxis axisToChange = null;
		for( int ii=0; ii<list.size(); ii++ )
		{
			final SGAxis axis = (SGAxis)list.get(ii);
			if( axisOfGroup == axis )
			{
				axisToChange = (SGAxis)list.get((ii+1)%list.size());
				break;
			}
		}

		axisOfGroup = axisToChange;

//System.out.println(axisToChange);

		groupSet.mYAxis = axisToChange;

		return true;
	}



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


		// ポップアップメニュー
		if( strCommand.equals(REMOVE_SELECTED_GRAPH) )
		{
			this.removeSelectedData();
		}

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

	}




	/**
	 * 
	 */
	public void caretUpdate( final CaretEvent e )
	{

		final String str = this.mEditField.getText();

System.out.println("@"+str+"@");

		if( this.mFocusedSymbol!=null )
		{
			final Font font = new Font(
				this.mFocusedSymbol.getFontFamilyName(),
				this.mFocusedSymbol.getFontStyle(),
				(int)(this.mFocusedSymbol.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.mFocusedSymbol.getFontSize() ),
					this.mEditField.getHeight()
				);
			}

//			this.repaint();
		}

	}



	/**
	 * 
	 */
	private boolean setSigDiffProperty( final BufferedReader br, final SigDiffSymbol el )
		throws IOException
	{

		SGSignificantDifferenceSymbol.SigDiffProperties p
			= (SGSignificantDifferenceSymbol.SigDiffProperties)this.readPropertiesOfSigDiffSymbol(br);
		if( p==null )
		{
			return false;
		}
		if( el.setProperties(p) == false )
		{
			return false;
		}

		return true;
	}



	/**
	 * 
	 */
	public boolean readProperty( final BufferedReader br ) throws IOException
	{

		String line = null;

		if( (line=SGUtilityText.readLine(br)) == null )
		{
			return false;
		}


		// dignificant difference symbols
		br.mark(256);
		while(true)
		{

			if( (line=SGUtilityText.readLine(br)) == null )
			{
				return false;
			}


			if( line.equals(PF_SIGDIFF_ELEMENT_TITLE) == false )
			{
				br.reset();
				break;
			}

			SGSignificantDifferenceSymbol.SigDiffProperties p
				= this.readPropertiesOfSigDiffSymbol(br);
			if( p==null )
			{
				return false;
			}

			SigDiffSymbol sd = new SigDiffSymbol();
			if( sd.setProperties(p) == false )
			{
				return false;
			}

			sd.createDrawingElement();
			this.mSignificantDifferentSymbolsList.add(sd);

			// initialize history
			sd.initPropertiesHistory();

			br.mark(256);
		}


		return true;
	}



	/**
	 * 
	 */
	public boolean writeProperty( final Writer writer ) throws IOException
	{
		writer.write( PF_GRAPH_TITLE + "\n" );

		for( int ii=0; ii<this.mSignificantDifferentSymbolsList.size(); ii++ )
		{
			SigDiffSymbol el = (SigDiffSymbol)this.mSignificantDifferentSymbolsList.get(ii);
			el.writeProperty(writer);
		}

		writer.write("\n");

		return true;
	}


	/**
	 * 
	 */
	public boolean writePropertyOfData( final Writer writer ) throws IOException
	{

		for( int ii=0; ii<this.mDataList.size(); ii++ )
		{
			writer.write( PF_DATA_TITLE + "\n" );

			final SGData data = (SGData)this.mDataList.get(ii);
			String className = null;

			if( data instanceof SGSXYData )
			{
				className = SGDataTypeConstants.SXY_DATA;
			}
			else if( data instanceof SGVXYData )
			{
				className = SGDataTypeConstants.VXY_DATA;
			}
			else if( data instanceof SGSXYMultipleData )
			{
				if( data instanceof SGSXYSamplingData )
				{
					className = SGDataTypeConstants.SXY_SAMPLING_DATA;
				}
				else
				{
					className = SGDataTypeConstants.SXY_MULTIPLE_DATA;
				}
			}
			else
			{
				return false;
			}

			SGUtilityText.writePropertyLine( writer, PF_CLASS_NAME, className );


			// データに対応したSGElementGroupSetオブジェクトを取得
			ElementGroupSetInGraph groupSet = this.getGraphData(data);
			groupSet.writePropertyOfData(writer);

		}


		writer.write("\n\n");

		return true;		

	}




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



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

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

		GraphProperties gp = (GraphProperties)p;
		gp.visibleElementGroupList = this.getVisibleElementGroupList();
		gp.visibleTimingElementList = this.getVisibleTimingElementList();
		gp.visibleSigDiffSymbolList = this.getVisibleSigDiffSymbolList();

		return true;

	}


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

		GraphProperties gp = (GraphProperties)p;

		boolean flag;
		flag = this.setVisibleElementGroupList( gp.visibleElementGroupList );
		if( !flag )
		{
			return false;
		}
		flag = this.setVisibleTimingElements( gp.visibleTimingElementList );
		if( !flag )
		{
			return false;
		}
		flag = this.setVisibleSigDiffSymbols( gp.visibleSigDiffSymbolList );
		if( !flag )
		{
			return false;
		}


		return true;

	}



	/**
	 * 
	 */
	protected ArrayList getVisibleElementGroupList()
	{
//System.out.println("<< getVisibleElementGroupList >>");

		ArrayList list = new ArrayList();

		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			SGElementGroupSet groupSet
				= (SGElementGroupSet)this.mGroupSetList.get(ii);
			if( groupSet.isVisible() )
			{
				list.add(groupSet);
			}
		}

//System.out.println(list);
//System.out.println();

		return list;
	}



	/**
	 * 
	 */
	protected ArrayList getVisibleTimingElementList()
	{
		ArrayList list = new ArrayList();

		for( int ii=0; ii<this.mTimingElementGroupSetList.size(); ii++ )
		{
			SGElementGroupSet groupSet
				= (SGElementGroupSet)this.mTimingElementGroupSetList.get(ii);
			if( groupSet.isVisible() )
			{
				list.add(groupSet);
			}
		}

		return list;
	}


	/**
	 * 
	 */
	protected ArrayList getVisibleSigDiffSymbolList()
	{
		ArrayList list = new ArrayList();

		for( int ii=0; ii<this.mSignificantDifferentSymbolsList.size(); ii++ )
		{
			SigDiffSymbol el
				= (SigDiffSymbol)this.mSignificantDifferentSymbolsList.get(ii);
			if( el.isVisible() )
			{
				list.add(el);
			}
		}

		return list;
	}



	/**
	 * 
	 */
	protected boolean setVisibleElementGroupList( final ArrayList list )
	{
		if( list == null )
		{
			return false;
		}

		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			SGElementGroupSet groupSet = (SGElementGroupSet)this.mGroupSetList.get(ii);
			groupSet.setVisible( list.contains(groupSet) );
		}

		return true;
	}



	/**
	 * 
	 */
	protected boolean setVisibleTimingElements( final ArrayList list )
	{
		if( list == null )
		{
			return false;
		}

		for( int ii=0; ii<this.mTimingElementGroupSetList.size(); ii++ )
		{
			SGElementGroupSet groupSet = (SGElementGroupSet)this.mTimingElementGroupSetList.get(ii);
			groupSet.setVisible( list.contains(groupSet) );
		}
		return true;
	}



	/**
	 * 
	 */
	protected boolean setVisibleSigDiffSymbols( final ArrayList list )
	{
		if( list == null )
		{
			return false;
		}

		for( int ii=0; ii<this.mSignificantDifferentSymbolsList.size(); ii++ )
		{
			SigDiffSymbol el = (SigDiffSymbol)this.mSignificantDifferentSymbolsList.get(ii);
			el.setVisible( list.contains(el) );
		}
		return true;
	}




	/**
	 * 親オブジェクトに対して自身の変更を伝える。
	 */
	private boolean updateParentHistoryFromElementGroupSet( SGIUndoable obj )
	{
		this.updateParentHistory();
		this.updateObjectHistory(obj);

		return true;
	}



	/**
	 * 
	 * @return
	 */
	public boolean addPropertiesHistory( SGProperties p )
	{

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

		boolean flag = super.addPropertiesHistory(p);		

		return flag;
	}



	/**
	 * 
	 */
	public boolean undo()
	{
		boolean flag = super.undo();
		if( !flag )
		{
			return false;
		}

		this.setAllDrawingElementsLocation();
		this.notifyChange();

		this.mFocusedSymbol = null;

//		repaint();

		return true;
	}


	/**
	 * 
	 */
	public boolean redo()
	{
		boolean flag = super.redo();
		if( !flag )
		{
			return false;
		}


		this.setAllDrawingElementsLocation();
		this.notifyChange();

		this.mFocusedSymbol = null;

//		repaint();

		return true;
	}



	/**
	 * 
	 */
	private SGSignificantDifferenceSymbol.SigDiffProperties readPropertiesOfSigDiffSymbol( final BufferedReader br )
		throws IOException
	{
	
		String line = null;		
	
		// x-coordinate
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		Double dX = SGUtilityText.getDoublePropertyFromLine( line, SGGraphElement.PF_SIGDIFF_X );
		if( dX==null )
		{
			return null;
		}
		float x = dX.floatValue()/SGConstants.CM_POINT_RATIO;
	
	
		// y-coordinate
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		Double dY = SGUtilityText.getDoublePropertyFromLine( line, SGGraphElement.PF_SIGDIFF_Y );
		if( dY==null )
		{
			return null;
		}
		float y = dY.floatValue()/SGConstants.CM_POINT_RATIO;


		// width
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		Double dWidth = SGUtilityText.getDoublePropertyFromLine( line, SGGraphElement.PF_SIGDIFF_WIDTH );
		if( dWidth==null )
		{
			return null;
		}
		float width = dWidth.floatValue()/SGConstants.CM_POINT_RATIO;
	
	
		// left-height
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		Double dLeftHeight = SGUtilityText.getDoublePropertyFromLine( line, SGGraphElement.PF_SIGDIFF_LEFT_HEIGHT );
		if( dLeftHeight==null )
		{
			return null;
		}
		float leftHeight = dLeftHeight.floatValue()/SGConstants.CM_POINT_RATIO;


		// right-height
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		Double dRightHeight = SGUtilityText.getDoublePropertyFromLine( line, SGGraphElement.PF_SIGDIFF_RIGHT_HEIGHT );
		if( dRightHeight==null )
		{
			return null;
		}
		float rightHeight = dRightHeight.floatValue()/SGConstants.CM_POINT_RATIO;


		// text
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		String text = SGUtilityText.getStringPropertyFromLine( line, SGGraphElement.PF_STRING_TEXT );
		if( text==null )
		{
			return null;
		}
	
	
		// font family name
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		String fontFamilyName = SGUtilityText.getPropertyFromLine(line,SGGraphElement.PF_FONT_FAMILY_NAME);
		if( fontFamilyName==null )
		{
			return null;
		}
	
	
		// font size
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		Double dFontSize = SGUtilityText.getDoublePropertyFromLine(line,SGGraphElement.PF_FONT_SIZE);
		if( dFontSize==null )
		{
			return null;
		}
		float fontSize = dFontSize.floatValue();
	
	
		// font style
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		Integer nStyle = SGUtilityText.getFontStyleFromLine(line,SGGraphElement.PF_FONT_STYLE);
		if( nStyle==null )
		{
			return null;
		}
		int fontStyle = nStyle.intValue();
	
	
		// set color
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		ArrayList colorList = SGUtilityText.getColorListFromLine(line,SGGraphElement.PF_STRING_COLOR_LIST);
		if( colorList==null )
		{
			return null;
		}
	
	
		// line width
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		Double dLineWidth = SGUtilityText.getDoublePropertyFromLine(line,SGGraphElement.PF_SIGDIFF_LINE_WIDTH);
		if( dLineWidth==null )
		{
			return null;
		}
		float lineWidth = dLineWidth.floatValue();
	
	
		SGSignificantDifferenceSymbol.SigDiffProperties p
			= new SGSignificantDifferenceSymbol.SigDiffProperties();
		p.x = x;
		p.y = y;
		p.width = width;
		p.height1 = leftHeight;
		p.height2 = rightHeight;
		p.text = text;
		p.fontFamilyName = fontFamilyName;
		p.fontSize = fontSize;
		p.fontStyle = fontStyle;
		p.colorList = colorList;
		p.lineWidth = lineWidth;
	
		return p;
	
	}



	/**
	 *
	 */
	protected abstract class ElementGroupSetInGraph
		extends SGElementGroupSetInFigureElement
		implements ActionListener, WindowListener,
			SGIUndoable, SGIPropertySettingListener
	{


		/**
		 * 
		 */
		protected SGAxis mXAxis = null;


		/**
		 * 
		 */
		protected SGAxis mYAxis = null;


		/**
		 * 
		 */
		protected SGAxis mZAxis = null;



		/**
		 * 
		 */
		protected SGProperties mTemporaryProperties = null;


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


		/**
		 * 
		 */
		protected ElementGroupSetInGraph()
		{
			super();
		}


		/**
		 * 
		 */
		protected boolean setXAxis( final SGAxis axis )
		{
			mXAxis = axis;
			return true;
		}


		/**
		 * 
		 */
		protected boolean setYAxis( final SGAxis axis )
		{
			mYAxis = axis;
			return true;
		}


		/**
		 * 
		 */
		protected boolean setZAxis( final SGAxis axis )
		{
			mZAxis = axis;
			return true;
		}



				
		/**
		 * 
		 */
		public SGAxis getXAxis()
		{
			return mXAxis;
		}


		/**
		 * 
		 */
		public SGAxis getYAxis()
		{
			return mYAxis;
		}

		
		/**
		 * 
		 */
		public SGAxis getZAxis()
		{
			return mZAxis;
		}



		/**
		 * 
		 */
		public ArrayList getVisibleFlagList()
		{

			final ArrayList list = new ArrayList();

			final ArrayList groupList = this.mDrawingElementGroupList;
			for( int jj=0; jj<groupList.size(); jj++ )
			{
				final SGElementGroup group = (SGElementGroup)groupList.get(jj);
				final boolean flag = group.isVisible();
				list.add( new Boolean(flag) );
			}

			return list;
		}


		/**
		 * 
		 * @param b
		 */
		public void setSelected( final boolean b )
		{
			super.setSelected(b);
			for( int ii=0; ii<this.mDrawingElementGroupList.size(); ii++ )
			{
				SGElementGroup group = (SGElementGroup)this.mDrawingElementGroupList.get(ii);
				group.setSelected(b);
			}
		}




		/**
		 * 
		 */
		public void windowActivated(final WindowEvent e)
		{
//System.out.println("windowActivated");
		}


		/**
		 * 
		 */
		public void windowDeactivated(final WindowEvent e)
		{
//System.out.println("windowDeactivated");
		}


		/**
		 * 
		 */
		public void windowIconified(final WindowEvent e)
		{
//System.out.println("windowIconified");
		}


		/**
		 * 
		 */
		public void windowDeiconified(final WindowEvent e)
		{
//System.out.println("windowDeiconified");
		}


		/**
		 * 
		 */
		public void windowOpened(final WindowEvent e)
		{
//System.out.println("windowOpened");
		}


		/**
		 * 
		 */
		public void windowClosed(final WindowEvent e)
		{
//System.out.println("windowClosed");
		}


		/**
		 * 
		 */
		public void windowClosing(final WindowEvent e)
		{
//System.out.println("windowClosing");

			Object obj = e.getSource();
//System.out.println(obj);
			if( obj.equals( mPropertyDialogForData ) )
			{
				this.cancel();
			}

		}



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

			final Object source = e.getSource();
			final String command = e.getActionCommand();
			if( command.equals("Dialog") )
			{
				setPropertyOfSelectedData();
			}

		}


		/**
		 * 
		 */
		protected abstract boolean createDrawingElements();


		/**
		 * 
		 */
		public boolean onDrawingElement( final int x, final int y )
		{
			for( int ii=0; ii<this.mDrawingElementGroupList.size(); ii++ )
			{
				SGElementGroup group = (SGElementGroup)this.mDrawingElementGroupList.get(ii);
				SGDrawingElement[] array = group.mDrawingElementArray;
				for( int jj=0; jj<array.length; jj++ )
				{
					if( array[jj].contains(x,y) )
					{
						return true;
					}
				}
			}
			return false;
		}



		/**
		 * 
		 */
		public boolean showPropertyDialog()
		{
			final SGPropertyDialog dg = mPropertyDialogForData;

			dg.addPropertySettingListener(this);
			dg.setLocation( mDialogOwner.getLocation() );

			return true;
		}



		/**
		 * 
		 */
		public boolean commit()
		{

			final boolean flag = this.setPropertiesFromDialog();
			if( !flag )
			{
				return false;
			}

			SGProperties pTemp = this.mTemporaryProperties;
			SGProperties pPresent = this.getWholeProperties();

			if( pTemp.equals(pPresent) == false )
			{
				// オブジェクト履歴を更新
				this.updateHistory();
			}

			this.mTemporaryProperties = null;
			mPropertyDialogForData.hide();

			//
			if( setAllDrawingElementsLocation() == false )
			{
				return false;
			}
			notifyChange();

			return true;
		}



		/**
		 * 
		 */
		public boolean cancel()
		{
			if( this.recover() == false )
			{
				throw new Error();
			}

			this.mTemporaryProperties = null;

			final SGPropertyDialog dg = mPropertyDialogForData;


			//
			if( setAllDrawingElementsLocation() == false )
			{
				return false;
			}
			notifyChange();

			return true;
		}


		/**
		 * 
		 */
		public boolean preview()
		{
			boolean flag = this.setPropertiesFromDialog();
			if( !flag )
			{
				return false;
			}

			//
			if( setAllDrawingElementsLocation() == false )
			{
				return false;
			}
			notifyChange();

			return true;
		}


		/**
		 * 
		 */
		public boolean setPropertiesFromDialog()
		{
			return true;
		}



		/**
		 * 
		 * @return
		 */
		protected boolean recover()
		{
			if( this.setWholeProperties( this.mTemporaryProperties ) == false )
			{
				return false;
			}

			return true;
		}



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

			return ep;
		}


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

			super.getProperties(p);

			ElementGroupSetInGraphProperties ep = (ElementGroupSetInGraphProperties)p;

			ep.xAxis = this.mXAxis;
			ep.yAxis = this.mYAxis;
			ep.zAxis = this.mZAxis;

			return true;
		}



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

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

			ElementGroupSetInGraphProperties ep = (ElementGroupSetInGraphProperties)p;

			this.mXAxis = ep.xAxis;			
			this.mYAxis = ep.yAxis;			
			this.mZAxis = ep.zAxis;			

			return true;
		}




		/**
		 * 
		 */
		public boolean readProperties( final BufferedReader br, final SGProperties prop )
			throws IOException
		{
			if( br==null || prop==null )
			{
				return false;
			}


			if( super.readProperties(br,prop) == false )
			{
				return false;
			}


			if( ( prop instanceof ElementGroupSetInGraphProperties ) == false )
			{
				return false;
			}
			
			ElementGroupSetInGraphProperties p = (ElementGroupSetInGraphProperties)prop;

			String line = null;

			// configuration of X-axis
			if( ( line = SGUtilityText.readLine(br) ) == null )
			{
				return false;
			}
//System.out.println(line);
			String strConfigX = SGUtilityText.getPropertyFromLine(line,SGIGraphElement.PF_LOCATION_X_AXIS);
			if( strConfigX==null )
			{
				return false;
			
			}
			int configX = mAxisElement.getConfigurationInCubeFromStringInPlane(strConfigX);


			// configuration of Y-axis
			if( ( line = SGUtilityText.readLine(br) ) == null )
			{
				return false;
			}
//System.out.println(line);
			String strConfigY = SGUtilityText.getPropertyFromLine(line,SGIGraphElement.PF_LOCATION_Y_AXIS);
			if( strConfigY==null )
			{
				return false;
			
			}
			int configY = mAxisElement.getConfigurationInCubeFromStringInPlane(strConfigY);


			// set x- and y-axis
			SGAxis xAxis = mAxisElement.getAxisInCube( configX );
			SGAxis yAxis = mAxisElement.getAxisInCube( configY );
			p.xAxis = xAxis;
			p.yAxis = yAxis;

//System.out.println(p);

			return true;
		}



		/**
		 * 
		 * @return
		 */
		public boolean setDrawingElementProperties( final ArrayList dElementList )
		{

			final ArrayList groupList = this.mDrawingElementGroupList;
			if( dElementList.size() != groupList.size() )
			{
				throw new IllegalArgumentException("dElementList.size() != groupList.size()");
			}

			// set the properties of drawing elements
			for( int ii=0; ii<groupList.size(); ii++ )
			{
				SGElementGroup group = (SGElementGroup)groupList.get(ii);
				SGDrawingElement dElement = (SGDrawingElement)dElementList.get(ii);
				group.setProperty( dElement );
			}

			return true;
		}



		/**
		 * 
		 * @return
		 */
		private ArrayList mElementGroupSetPropertyHistoryList = new ArrayList();


		/**
		 * 
		 * @return
		 */
		private int mElementGroupSetStateCounter = 0;


		/**
		 * 
		 */
		public boolean initPropertiesHistory()
		{
			this.addElementGroupSetPropertyHistory( (WholeProperties)this.getWholeProperties() );
			return true;
		}


		/**
		 * 
		 * @return
		 */
		private boolean addElementGroupSetPropertyHistory( WholeProperties p )
		{

//	  System.out.println("<< addFigurePropertyHistory >>");
//	  System.out.println(this.mFigureStateCounter);

			ArrayList list = new ArrayList();
			for( int ii=0; ii<this.mElementGroupSetStateCounter; ii++ )
			{
				list.add( this.mElementGroupSetPropertyHistoryList.get(ii) );
			}
			list.add(p);

			this.mElementGroupSetPropertyHistoryList = list;

//	  System.out.println(this.mFigurePropertyHistoryList);
//	  System.out.println("x="+p.x+"  y="+p.y);
//	  System.out.println("w="+p.width+"  h="+p.height);
//	  System.out.println();

			return true;
		}


		/**
		 * 現在、状態が履歴のどの位置にあるのかを示すカウンタ
		 */
		private int mCurrentStateCounter = 0;


		/**
		 * アンドゥ対象オブジェクトの履歴リスト
		 */
		protected ArrayList mUndoableObjectHistoryList = new ArrayList();


		/**
		 * アンドゥを行う
		 */
		public boolean undo()
		{
//System.out.println("undo : ElemntGroupSet");
//System.out.println();

			this.mElementGroupSetStateCounter--;

			WholeProperties p
				= (WholeProperties)this.mElementGroupSetPropertyHistoryList.get(
					this.mElementGroupSetStateCounter);
//System.out.println(p);
//System.out.println();

			this.setWholeProperties(p);

			setAllDrawingElementsLocation();
			notifyChange();
//			repaint();

			return true;
		}


		/**
		 * リドゥを行う
		 */
		public boolean redo()
		{
//System.out.println("redo : ElemntGroupSet");
//System.out.println();

			this.mElementGroupSetStateCounter++;

			WholeProperties p
				= (WholeProperties)this.mElementGroupSetPropertyHistoryList.get(
					this.mElementGroupSetStateCounter);
//System.out.println(p);
//System.out.println();

			this.setWholeProperties(p);

			setAllDrawingElementsLocation();
			notifyChange();
//			repaint();

			return true;
		}



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

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


		/**
		 * オブジェクトの履歴を更新する
		 * @return
		 */
		public boolean updateObjectHistory( final SGIUndoable obj )
		{
			ArrayList objList = new ArrayList();
			objList.add(obj);
			boolean flag = this.updateObjectHistory(objList);
			if( !flag )
			{
				return false;
			}

			return true;
		}



		/**
		 * オブジェクトの履歴を更新する
		 */
		public boolean updateObjectHistory( final ArrayList objList )
		{

			ArrayList list = new ArrayList();
			for( int ii=0; ii<this.mCurrentStateCounter; ii++ )
			{
				Object obj = this.mUndoableObjectHistoryList.get(ii);
				list.add(obj);
			}
			list.add( new ArrayList(objList) );

			this.mUndoableObjectHistoryList = list;
			this.mCurrentStateCounter++;

//System.out.println("<< updateObjectHistory >>");
//System.out.println(this.mUndoableObjectHistoryList);
//System.out.println(this.mCurrentStateCounter);
//System.out.println();

			return true;
		}



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

			// ウインドウのオブジェクト履歴を更新
			this.updateParentHistory();


			//
			this.updateThisObjectHistory();


//System.out.println(this.mElementGroupSetPropertyHistoryList);
//System.out.println();

			return true;
		}



		/**
		 * 
		 */
		public boolean updateThisObjectHistory()
		{

			// オブジェクト履歴を更新
			this.updateObjectHistory(this);


			// フィギュアのプロパティ履歴を更新
			this.mElementGroupSetStateCounter++;
			this.addElementGroupSetPropertyHistory( (WholeProperties)this.getWholeProperties() );

			return true;
		}


		/**
		 * 親オブジェクトに対して自身の変更を伝える。
		 */
		public boolean updateParentHistory()
		{
			return updateParentHistoryFromElementGroupSet(this);
		}






		/**
		 * 
		 */
		class ElementGroupSetInGraphProperties	extends ElementGroupSetPropertiesInFigureElement
		{
			SGAxis xAxis;
			SGAxis yAxis;
			SGAxis zAxis;

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

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

				ElementGroupSetInGraphProperties p = (ElementGroupSetInGraphProperties)obj;

				if( p.xAxis.equals(this.xAxis) == false ) return false;
				if( p.yAxis.equals(this.yAxis) == false ) return false;

				if( p.zAxis!=null || this.zAxis!=null )
				{
					if( p.zAxis.equals(this.zAxis) == false ) return false;
				}

				return true;
			}


			/**
			 * 
			 */
			public String toString()
			{
				String str = new String("[");
				str += super.toString();
				str += new String("xAxis="+xAxis+", ");
				str += new String("yAxis="+yAxis+", ");
				str += new String("zAxis="+zAxis+", ");
				str += new String("]");

				return str;
			}

		}


	}




	/**
	 * 
	 */
	abstract class ElementGroupSetForMultipleData extends ElementGroupSetInGraph
		implements ActionListener
	{

		/**
		 * 
		 */
		protected ArrayList mElementGroupSetList = new ArrayList();


		/**
		 * 
		 */
		protected ElementGroupSetForMultipleData()
		{
			super();
		}


		/**
		 * 
		 */
		public ArrayList getVisibleFlagList()
		{
			if( this.mElementGroupSetList.size()==0 )
			{
				return new ArrayList();
			}
			ElementGroupSetInGraph groupSet = (ElementGroupSetInGraph)this.mElementGroupSetList.get(0);
			ArrayList list = groupSet.getVisibleFlagList();
			return list;
		}


		/**
		 * 
		 * @param b
		 */
		public void setSelected( final boolean b )
		{
			super.setSelected(b);
			for( int ii=0; ii<this.mElementGroupSetList.size(); ii++ )
			{
				SGElementGroupSet groupSet = (SGElementGroupSet)this.mElementGroupSetList.get(ii);
				groupSet.setSelected(b);
			}
		}


		/**
		 * 
		 */
		public boolean contains( final int x, final int y )
		{
			for( int ii=0; ii<this.mElementGroupSetList.size(); ii++ )
			{
				SGElementGroupSet groupSet = (SGElementGroupSet)this.mElementGroupSetList.get(ii);
				if( groupSet.contains(x,y) )
				{
					return true;
				}
			}
			return false;
		}


		/**
		 * 
		 */
		public boolean setMagnification( final float mag )
		{
			super.setMagnification(mag);
			for( int ii=0; ii<this.mElementGroupSetList.size(); ii++ )
			{
				SGElementGroupSet groupSet
					= (SGElementGroupSet)this.mElementGroupSetList.get(ii);
				groupSet.setMagnification(mag);
			}

			return true;
		}


		/**
		 * 
		 */
		public boolean zoom( final float ratio )
		{
			super.zoom(ratio);

			for( int ii=0; ii<this.mElementGroupSetList.size(); ii++ )
			{
				SGElementGroupSet groupSet
					= (SGElementGroupSet)this.mElementGroupSetList.get(ii);
				groupSet.zoom(ratio);
			}

			return true;
		}

		/**
		 * 
		 */
		public boolean addDrawingElementGroup( final int type )
		{

			for( int ii=0; ii<this.mElementGroupSetList.size(); ii++ )
			{
				final ElementGroupSetInGraph groupSet = (ElementGroupSetInGraph)this.mElementGroupSetList.get(ii);
				groupSet.addDrawingElementGroup(type);
			}

			return true;
		}


		/**
		 * 
		 */
		public boolean addDrawingElementGroup( final SGDrawingElement element )
		{

			for( int ii=0; ii<this.mElementGroupSetList.size(); ii++ )
			{
				final ElementGroupSetInGraph groupSet = (ElementGroupSetInGraph)this.mElementGroupSetList.get(ii);
				groupSet.addDrawingElementGroup(element);
			}

			return true;
		}


		/**
		 * 
		 */
/*		protected boolean clickDrawingElements( final MouseEvent e )
		{

			for( int ii=this.mElementGroupSetList.size()-1; ii>=0; ii-- )
			{
				final ElementGroupSetInGraph groupSet = (ElementGroupSetInGraph)this.mElementGroupSetList.get(ii);
				boolean flag = groupSet.clickDrawingElements(e);
				if( flag )
				{
					return true;
				}
			}


			return false;
		}
*/

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

			for( int ii=this.mElementGroupSetList.size()-1; ii>=0; ii-- )
			{
				final ElementGroupSetInGraph groupSet = (ElementGroupSetInGraph)this.mElementGroupSetList.get(ii);
				boolean flag = groupSet.onDrawingElement(x,y);
				if( flag )
				{
					return true;
				}
			}

			return false;
		}


		/**
		 * 
		 */
		public void paintGraphics2D( final Graphics2D g2d )
		{
			for( int ii=this.mElementGroupSetList.size()-1; ii>=0; ii-- )
			{
				final ElementGroupSetInGraph groupSet = (ElementGroupSetInGraph)this.mElementGroupSetList.get(ii);
				groupSet.paintGraphics2D(g2d);
			}
		}



		/**
		 * 
		 */
		public ArrayList getDrawingElementList()
		{
			final ArrayList list = new ArrayList();

			if( this.mElementGroupSetList.size() == 0 )
			{
				return list;
			}

			// 最初のグループからだけ取得する
			final SGElementGroupSet groupSet = (SGElementGroupSet)this.mElementGroupSetList.get(0);
			for( int ii=0; ii<groupSet.mDrawingElementGroupList.size(); ii++ )
			{
				final SGElementGroup group = (SGElementGroup)groupSet.mDrawingElementGroupList.get(ii);
				final SGDrawingElement dElement = group.getDrawingElement();
				list.add( dElement );
			}

			return list;
		}



		/**
		 * 
		 * @return
		 */
		public boolean setDrawingElementProperties( final ArrayList dElementList )
		{

			final ArrayList groupSetList = this.mElementGroupSetList;

			// set the properties of drawing elements
			for( int ii=0; ii<groupSetList.size(); ii++ )
			{
				ElementGroupSetInGraph groupSet = (ElementGroupSetInGraph)groupSetList.get(ii);
				groupSet.setDrawingElementProperties( dElementList );
			}

/*
			final ArrayList groupList = this.mDrawingElementGroupList;
			if( dElementList.size() != groupList.size() )
			{
				throw new IllegalArgumentException("dElementList.size() != groupList.size()");
			}

			// set the properties of drawing elements
			for( int ii=0; ii<groupList.size(); ii++ )
			{
				SGElementGroup group = (SGElementGroup)groupList.get(ii);
				SGDrawingElement dElement = (SGDrawingElement)dElementList.get(ii);
				group.setProperty( dElement );
			}
*/

			return true;
		}


	}




	/**
	 * タイミング描画要素群のクラス
	 */
	class TimingElementGroupSetInGraph extends SGTimingElementGroupSet
		implements ActionListener, WindowListener, SGIUndoable
	{

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


		/**
		 * 
		 */
		private SGTuple2f[] mPointsArray = null;


		/**
		 * 
		 */
		protected TimingElementGroupSetInGraph()
		{
			super();
		}


		/**
		 * 
		 */
		public boolean addDrawingElementGroup( final int type )
		{


			SGElementGroup group = null;
			if( type == SGElementGroup.POLYLINE_GROUP )
			{
				group = new TimingElementGroupLine();
			}
			else
			{
				throw new Error("");
			}

			group.mGroupSet = this;


			// 描画要素の作成
			if( group.initDrawingElement( this.mPointsArray ) == false )
			{
				throw new Error();
			}


			// set the properties to drawing elements
			if( group.setPropertiesOfDrawingElements() == false )
			{
				return false;
			}


			// グループをデータのリストに追加
			this.mDrawingElementGroupList.add( group );


			return true;
		}


		/**
		 * 
		 */
		public boolean addDrawingElementGroup( final SGDrawingElement element )
		{
//System.out.println("<< addDrawingElementGroup >>");
//System.out.println("el:"+element);

			SGElementGroup group = null;
			if( element instanceof SGDrawingElementLine )
			{

//SGDrawingElementLine line = (SGDrawingElementLine)element;
//System.out.println(line.getLineWidth());
//System.out.println(line.getColorList());

				group = new TimingElementGroupLine();
			}
			else
			{
				throw new Error("");
			}

//System.out.println();

			group.mGroupSet = this;

			// グループをデータのリストに追加
			this.mDrawingElementGroupList.add( group );


			// 描画要素の作成
			if( group.initDrawingElement( this.mPointsArray ) == false )
			{
				throw new Error();
			}

			//
			if( group.setProperty( element ) == false )
			{
				return false;
			}


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



			return true;

		}



		/**
		 * Called when the location of data points have changed.
		 */
		public boolean setDrawingElementsLocation()
		{
//System.out.println("<< TimingElementGroupSetInGraph::setDrawingElementsLocation >>");

			final SGAxis axis = this.mAxis;
			final double value = this.mValue.mValue;

			for( int ii=0; ii<this.mDrawingElementGroupList.size(); ii++ )
			{
				final SGElementGroup group
					= (SGElementGroup)this.mDrawingElementGroupList.get(ii);

				if( group instanceof SGElementGroupLine )
				{
					final SGElementGroupLine groupLine = (SGElementGroupLine)group;
					if( calcLocationOfTimingLine(
							value,
							axis,
							this.mPointsArray[0],
							this.mPointsArray[1] ) == false )
					{
						return false;
					}

//System.out.println(this.mPointsArray[0]);
//System.out.println(this.mPointsArray[1]);

					if( groupLine.setLocation( this.mPointsArray ) == false )
					{
						return false;
					}
//System.out.println();
				}
				else
				{
					throw new Error();
				}

			}

			return true;
		}



		/**
		 * 
		 */
		public void paintGraphics2D( final Graphics2D g2d )
		{
			final ArrayList groupList = this.mDrawingElementGroupList;
			for( int ii=0; ii<groupList.size(); ii++ )
			{
				final SGElementGroup group = (SGElementGroup)groupList.get(ii);
				group.paintElement(g2d);
			}
		}


		/**
		 * 
		 */
		protected boolean clickDrawingElements( final MouseEvent e )
		{
			final int x = e.getX();
			final int y = e.getY();

//System.out.println(x+"  "+y);

			final ArrayList groupList = this.mDrawingElementGroupList;
			for( int jj=groupList.size()-1; jj>=0; jj-- )
			{
//System.out.println("jj="+jj);
				final SGElementGroup group = (SGElementGroup)groupList.get(jj);
				SGDrawingElement[] array = group.mDrawingElementArray;

				for( int kk=0; kk<array.length; kk++ )
				{
//System.out.println("kk="+kk);
//System.out.println(array[kk]);

					final boolean flag = array[kk].contains(x,y);
//System.out.println(flag);
					if( flag )
					{

						if( (SwingUtilities.isRightMouseButton(e) )
							&& ( e.getClickCount() == 1 ) )
						{
//							final JPopupMenu menu = group.getPopupMenu();
//							menu.show( this.mGraphElement, e.getX(), e.getY());
//							return true;
						}

						if( (SwingUtilities.isLeftMouseButton(e) )
						&& ( e.getClickCount() == 2 ) )
						{
							final JDialog dialog = this.getDialog();
							dialog.show();
							return true;
						}

					}
					
				}


			}


			return false;
		}



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

			final ArrayList groupList = this.mDrawingElementGroupList;
			for( int jj=groupList.size()-1; jj>=0; jj-- )
			{
				final SGElementGroup group = (SGElementGroup)groupList.get(jj);
				SGDrawingElement[] array = group.mDrawingElementArray;
				for( int kk=0; kk<array.length; kk++ )
				{
					final boolean flag = array[kk].contains(x,y);
					if( flag )
					{
						return true;
					}
				}
			}

			return false;
		}



		/**
		 * 
		 */
		public JDialog getDialog()
		{

			final SGTimingLineDialog dg = mTimingLineDialog;

			this.setDialogProperty();

			dg.setLocation( mDialogOwner.getLocation() );

			// ボタンに装飾
			dg.setColorButtonBorder(true);


			dg.setActionListener(this);
			dg.addWindowListener(this);


			//
			this.mTemporaryProperties = this.getWholeProperties();


			return dg;
		}



		/**
		 * 
		 */
		public void windowActivated(final WindowEvent e)
		{
//	System.out.println("windowActivated");
		}


		/**
		 * 
		 */
		public void windowDeactivated(final WindowEvent e)
		{
//	System.out.println("windowDeactivated");
		}


		/**
		 * 
		 */
		public void windowIconified(final WindowEvent e)
		{
//	System.out.println("windowIconified");
		}


		/**
		 * 
		 */
		public void windowDeiconified(final WindowEvent e)
		{
//	System.out.println("windowDeiconified");
		}


		/**
		 * 
		 */
		public void windowOpened(final WindowEvent e)
		{
//	System.out.println("windowOpened");
		}


		/**
		 * 
		 */
		public void windowClosed(final WindowEvent e)
		{
//	System.out.println("windowClosed");
		}


		/**
		 * 
		 */
		public void windowClosing(final WindowEvent e)
		{
//	System.out.println("windowClosing");

			Object obj = e.getSource();
//	System.out.println(obj);
			if( obj.equals( mTimingLineDialog ) )
			{
				this.onCanceled();
			}

		}


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

			final SGTimingLineDialog dg = mTimingLineDialog;


			if( command.equals("OK") || dg.getActiveComponentList().contains(source) )
			{
				if( this.onOK() == false ) return;
			}
			else if( command.equals("Cancel") )
			{
				if( this.onCanceled() == false ) return;
			}
			else if( command.equals("Preview") )
			{
				if( this.onPreviewed() == false ) return;
			}

		}


		/**
		 * 
		 */
		private boolean onOK()
		{

			boolean flag;

			// ダイアログからプロパティを取得して設定
			flag = this.setPropertyWithDialog();
			if( !flag )
			{
				return false;
			}


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

			SGProperties pTemp = this.mTemporaryProperties;
			SGProperties pPresent = this.getProperties();
			if( pTemp.equals(pPresent) == false )
			{
				// オブジェクト履歴を更新
				this.updateHistory();
			}

			this.mTemporaryProperties = null;
			mTimingLineDialog.hide();

			mTimingLineDialog.removeActionListener();
			mTimingLineDialog.removeWindowListener(this);

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

			notifyChange();

			return true;
		}



		/**
		 * 
		 */
		private boolean onCanceled()
		{
			boolean flag = this.recover();
			if( !flag ) return false;

			this.mTemporaryProperties = null;
			mTimingLineDialog.hide();

			mTimingLineDialog.removeActionListener();
			mTimingLineDialog.removeWindowListener(this);

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

			notifyChange();

			return true;
		}


		/**
		 * 
		 */
		private boolean onPreviewed()
		{
			boolean flag = this.setPropertyWithDialog();
			if( !flag ) return false;

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

			notifyChange();

			return true;
		}



		/**
		 * 
		 */
		public boolean recover()
		{

			if( this.setWholeProperties( this.mTemporaryProperties ) == false )
			{
				return false;
			}

			this.mTemporaryProperties = null;
			
			return true;
		}



		/**
		 * 
		 */
		private WholeProperties readProperties( final BufferedReader br )
		{

			WholeProperties wp = new WholeProperties();

			String line = null;

			try
			{

				TimingElementGroupSetProperties ep = new TimingElementGroupSetProperties();


				if( this.readProperties(br,ep) == false )
				{
					return null;
				}

				// configuration of axis
				if( ( line = SGUtilityText.readLine(br) ) == null )
				{
					return null;
				}
				Integer nConfiguration = SGUtilityText.getIntegerPropertyFromLine( line, SGIAxisElement.PF_AXIS_LOCATION );
				if( nConfiguration == null )
				{
					return null;
				}
				final int configuration = nConfiguration.intValue();
				ep.axis = mAxisElement.getAxisInCube(configuration);


				// value
				if( ( line = SGUtilityText.readLine(br) ) == null )
				{
					return null;
				}
				Double dValue = SGUtilityText.getDoublePropertyFromLine( line, SGIAxisElement.PF_TIMING_VALUE );
				if( dValue == null )
				{
					return null;
				}
				final double value = dValue.doubleValue();
				ep.value = value;


				// drawing elements
				ArrayList pList = new ArrayList();
				for( int ii=0; ii<this.mDrawingElementGroupList.size(); ii++ )
				{
					final SGElementGroup group = (SGElementGroup)this.mDrawingElementGroupList.get(ii);
					if( ( line = SGUtilityText.readLine(br) ) == null ) return null;
					SGProperties p = group.readProperties(br);
					if( p==null ) return null;
					pList.add(p);
				}

				wp.ep = ep;
				wp.ipList = pList;

			}
			catch( IOException ex )
			{
				ex.printStackTrace();
				return null;
			}


			return wp;

		}




		/**
		 * 
		 */
		private boolean readProperty( final BufferedReader br )
		{
			SGProperties p;

			if( ( p = this.readProperties(br) ) ==null ) return false;
//System.out.println(p);

			if( this.setWholeProperties(p) == false ) return false;

			return true;
		}



		/**
		 * 
		 */
		private boolean setDialogProperty()
		{

			for( int ii=0; ii<this.mDrawingElementGroupList.size(); ii++ )
			{
				final SGElementGroup group
					= (SGElementGroup)this.mDrawingElementGroupList.get(ii);
				group.setDialogProperty();
			}

			return true;
		}



		/**
		 * 
		 */
		private boolean setPropertyWithDialog()
		{

			for( int ii=0; ii<this.mDrawingElementGroupList.size(); ii++ )
			{
				final SGElementGroup group
					= (SGElementGroup)this.mDrawingElementGroupList.get(ii);
				group.setPropertyWithDialog();
			}

			return true;
		}



		/**
		 * 
		 * @return
		 */
		private ArrayList mElementGroupSetPropertyHistoryList = new ArrayList();


		/**
		 * 
		 * @return
		 */
		private int mElementGroupSetStateCounter = 0;


		/**
		 * 
		 */
		public boolean initPropertiesHistory()
		{
			this.addElementGroupSetPropertyHistory( (WholeProperties)this.getWholeProperties() );
			return true;
		}



		/**
		 * 
		 * @return
		 */
		private boolean addElementGroupSetPropertyHistory( SGProperties p )
		{

			ArrayList list = new ArrayList();
			for( int ii=0; ii<this.mElementGroupSetStateCounter; ii++ )
			{
				list.add( this.mElementGroupSetPropertyHistoryList.get(ii) );
			}
			list.add(p);

			this.mElementGroupSetPropertyHistoryList = list;

			return true;

		}



		/**
		 * 現在、状態が履歴のどの位置にあるのかを示すカウンタ
		 */
		private int mCurrentStateCounter = 0;


		/**
		 * アンドゥ対象オブジェクトの履歴リスト
		 */
		protected ArrayList mUndoableObjectHistoryList = new ArrayList();


		/**
		 * アンドゥを行う
		 */
		public boolean undo()
		{
//System.out.println("undo : ElemntGroupSet");
//System.out.println(this.mElementGroupSetPropertyHistoryList);

			this.mElementGroupSetStateCounter--;

			WholeProperties p
				= (WholeProperties)this.mElementGroupSetPropertyHistoryList.get(
					this.mElementGroupSetStateCounter);
//System.out.println(p);
//System.out.println();

			this.setWholeProperties(p);

			setAllDrawingElementsLocation();
			notifyChange();
//			repaint();

			return true;
		}


		/**
		 * リドゥを行う
		 */
		public boolean redo()
		{
//System.out.println("redo : ElemntGroupSet");
//System.out.println();

			this.mElementGroupSetStateCounter++;

			WholeProperties p
				= (WholeProperties)this.mElementGroupSetPropertyHistoryList.get(
					this.mElementGroupSetStateCounter);
//System.out.println(p);
//System.out.println();

			this.setWholeProperties(p);

			setAllDrawingElementsLocation();
			notifyChange();
//			repaint();

			return true;
		}



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

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


		/**
		 * オブジェクトの履歴を更新する
		 * @return
		 */
		public boolean updateObjectHistory( final SGIUndoable obj )
		{
			ArrayList objList = new ArrayList();
			objList.add(obj);
			boolean flag = this.updateObjectHistory(objList);
			if( !flag )
			{
				return false;
			}

			return true;
		}



		/**
		 * オブジェクトの履歴を更新する
		 */
		public boolean updateObjectHistory( final ArrayList objList )
		{

			ArrayList list = new ArrayList();
			for( int ii=0; ii<this.mCurrentStateCounter; ii++ )
			{
				Object obj = this.mUndoableObjectHistoryList.get(ii);
				list.add(obj);
			}
			list.add( new ArrayList(objList) );

			this.mUndoableObjectHistoryList = list;
			this.mCurrentStateCounter++;

//System.out.println("<< updateObjectHistory >>");
//System.out.println(this.mUndoableObjectHistoryList);
//System.out.println(this.mCurrentStateCounter);
//System.out.println();

			return true;
		}



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

			// ウインドウのオブジェクト履歴を更新
			this.updateParentHistory();


			//
			this.updateThisObjectHistory();

			return true;
		}



		/**
		 * 
		 */
		public boolean updateThisObjectHistory()
		{

			// オブジェクト履歴を更新
			this.updateObjectHistory(this);


			// フィギュアのプロパティ履歴を更新
			this.mElementGroupSetStateCounter++;
			this.addElementGroupSetPropertyHistory( this.getWholeProperties() );

			return true;
		}


		/**
		 * 親オブジェクトに対して自身の変更を伝える。
		 */
		public boolean updateParentHistory()
		{
			return updateParentHistoryFromElementGroupSet(this);
		}

	}



	/**
	 * 
	 */
	class TimingElementGroupLine extends SGElementGroupLine
	{

		/**
		 * 
		 */
		private static final String MOVE_TO_FRONT = "Move to Front";

		/**
		 * 
		 */
		private static final String MOVE_TO_BACK = "Move to Back";

		/**
		 * 
		 */
		private static final String REMOVE_TIMING_LINE = "Remove this Line";

		
		/**
		 * 
		 */
		protected TimingElementGroupLine()
		{
			super();
		}



		/**
		 * 
		 */
		protected String[] getPopupMenuCommandArray()
		{
			final String[] commandArray = {
				MOVE_TO_FRONT,
				MOVE_TO_BACK,
				REMOVE_TIMING_LINE,
//				SOLID_LINE,
//				BROKEN_LINE,
//				DOTTED_LINE
			};

			return commandArray;
		}



		/**
		 * 
		 */
		public boolean setDialogProperty()
		{

			final TimingElementGroupSetInGraph groupSet
				= (TimingElementGroupSetInGraph)this.mGroupSet;
			final SGTimingLineDialog dg = mTimingLineDialog;

			dg.setTiminValueString( groupSet.mValue.mValue );
			dg.setLineType( this.mLineType );
			dg.setLineWidth( this.mLineWidth );
			dg.setLineColorList( this.mColorList );

			return true;

		}


		/**
		 * 
		 */
		public boolean setPropertyWithDialog()
		{

			final TimingElementGroupSetInGraph groupSet
				= (TimingElementGroupSetInGraph)this.mGroupSet;
			final SGTimingLineDialog dg = mTimingLineDialog;


			// timing value
			double value = 0.0;
			try
			{
				value = Double.valueOf( dg.getTimingValueString() ).doubleValue();
			}
			catch( Exception ex )
			{
//				System.out.println("数値を入力して下さい。");
				SGUtility.showIllegalInputErrorMessageDialog( dg );
				dg.setTiminValueString( groupSet.mValue.mValue );
				return false;
			}
			groupSet.mValue.mValue = value;


			LineProperties p = dg.getLineProperties();
//System.out.println(p);
			if( p==null )
			{
				return false;
			}


			// not from the dialog
			p.setVisible(this.isVisible());


			// set properties
			if( this.setProperties(p) == false )
			{
				return false;
			}

			return true;
		}



		/**
		 * 
		 */
		class TimingLineProperties extends LineProperties
		{

			double value;


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

				TimingLineProperties p = (TimingLineProperties)obj;
				if( p.value != this.value ) return false;

				return true;
			}
			
		}

	}



	/**
	 * 
	 */
	protected Point mPressedSymbolOrigin = null;


	/**
	 * 
	 */
	protected SigDiffSymbol mFocusedSymbol = null;



	/**
	 * 
	 */
	public static final float mAnchorSize = 7.0f;



	/**
	 * 
	 */
	protected boolean drawSignificantDifferenceSymbolAnchor( final Graphics2D g2d, ArrayList symbolList )
	{

		if( g2d==null || symbolList==null )
		{
			return false;
		}


		for( int ii=0; ii<symbolList.size(); ii++ )
		{
			SigDiffSymbol el = (SigDiffSymbol)symbolList.get(ii);
			el.drawAllAnchors(g2d);
		}

		return true;
	}





	/**
	 * 親オブジェクトに対して自身の変更を伝える。
	 */
	private boolean updateParentHistoryFromStringElement( SigDiffSymbol el )
	{
		this.updateParentHistory();
		this.updateObjectHistory(el);

		return true;
	}



	/**
	 * 
	 */
	class SigDiffSymbol
		extends SGSignificantDifferenceSymbol2D
		implements ActionListener, WindowListener, SGIUndoable
	{

		/**
		 * 
		 */
		private boolean mVisible = true;



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


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


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


		/**
		 * 
		 */
		protected 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()
		{
			mPopupMenu.setBounds( 0, 0, 100, 100 );

			final String[] commandArray = {
				REMOVE_SIGDIFF_SYMBOL
			};

			for( int ii=0; ii<commandArray.length; ii++ )
			{
				final JMenuItem item = new JMenuItem(commandArray[ii]);
				item.addActionListener(this);
				mPopupMenu.add(item);
			}

			return true;
		}



		/**
		 * 
		 */
		private boolean init()
		{
			this.setWidth( SGDefaultValues.SIGDIFF_SYMBOL_WIDTH );
			this.setPerpendicularHeight1( SGDefaultValues.SIGDIFF_SYMBOL_LEFT_HEIGHT );
			this.setPerpendicularHeight2( SGDefaultValues.SIGDIFF_SYMBOL_RIGHT_HEIGHT );
//			this.setFontFamilyName( SGDefaultValues.SIGDIFF_SYMBOL_FONT_FAMILY_NAME );
//			this.setFontSize( SGDefaultValues.SIGDIFF_SYMBOL_FONT_SIZE );
			final int style = SGUtilityText.getFontStyle( SGDefaultValues.SIGDIFF_SYMBOL_FONT_STYLE );
			if( style==-1 )
			{
				return false;
			}
//			this.setFontStyle( style );
			this.setFont(
				SGDefaultValues.SIGDIFF_SYMBOL_FONT_FAMILY_NAME,
				style,
				SGDefaultValues.SIGDIFF_SYMBOL_FONT_SIZE
			);

			this.setLineWidth( SGDefaultValues.SIGDIFF_SYMBOL_LINE_WIDTH );
			this.setColor( SGDefaultValues.SIGDIFF_SYMBOL_COLOR );
			this.setSpace( SGDefaultValues.SIGDIFF_SYMBOL_SPACE );

			this.createPopupMenu();

			return true;
		}


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


		
		/**
		 * 
		 */
		private JDialog getDialog()
		{

			mSigDiffDialog.setActionListener(this);
			mSigDiffDialog.addWindowListener(this);

			mSigDiffDialog.setLocation( mDialogOwner.getLocation() );

			mSigDiffDialog.setColorButtonBorder(true);

			this.setDialogProperty();

			this.mTemporaryProperties = this.getProperties();

			mEditField.setVisible(false);
//			repaint();

			return mSigDiffDialog;
		}



		/**
		 * 
		 */
		public boolean writeProperty( final Writer writer ) throws IOException
		{

			writer.write( PF_SIGDIFF_ELEMENT_TITLE + "\n");

			SGUtilityText.writePropertyLine( writer, PF_SIGDIFF_X, new Float( this.mX*SGConstants.CM_POINT_RATIO ) );
			SGUtilityText.writePropertyLine( writer, PF_SIGDIFF_Y, new Float( this.mY*SGConstants.CM_POINT_RATIO) );
			SGUtilityText.writePropertyLine( writer, PF_SIGDIFF_WIDTH, new Float( this.mWidth*SGConstants.CM_POINT_RATIO) );
			SGUtilityText.writePropertyLine( writer, PF_SIGDIFF_LEFT_HEIGHT, new Float( this.mPerpendicularHeight1*SGConstants.CM_POINT_RATIO) );
			SGUtilityText.writePropertyLine( writer, PF_SIGDIFF_RIGHT_HEIGHT, new Float( this.mPerpendicularHeight2*SGConstants.CM_POINT_RATIO) );
			SGUtilityText.writeStringPropertyLine( writer, PF_STRING_TEXT, this.getText() );
			SGUtilityText.writePropertyLine( writer, PF_FONT_FAMILY_NAME, this.getFontFamilyName() );
			SGUtilityText.writePropertyLine( writer, PF_FONT_SIZE, new Float( this.getFontSize() ) );
			SGUtilityText.writePropertyLine( writer, PF_FONT_STYLE, SGUtilityText.getFontStyleName( this.getFontStyle() ) );
			SGUtilityText.writeColorListPropertyLine( writer, PF_STRING_COLOR_LIST, this.getColorList() );
			SGUtilityText.writePropertyLine( writer, PF_SIGDIFF_LINE_WIDTH, new Float( this.getLineWidth() ) );

			writer.write("\n");

			return true;
		}



		/**
		 * 
		 */
		private SigDiffProperties getPropertiesFromDialg()
		{

			SGSignificantDifferenceSymbolDialog dg = mSigDiffDialog;

			SigDiffProperties p = dg.getProperties();
			if( p==null )
			{
				return null;
			}


			// not from dialog
			p.x = this.mX;
			p.y = this.mY;
			p.width = this.mWidth;
			p.height1 = this.mPerpendicularHeight1;
			p.height2 = this.mPerpendicularHeight2;
			p.text = this.getText();


			return p;

		}




		/**
		 * 
		 */
		private boolean setDialogProperty()
		{

			final SGSignificantDifferenceSymbolDialog dg = mSigDiffDialog;


			// space
			dg.setSpace( this.mSpace*SGConstants.CM_POINT_RATIO );

			// font size
			dg.setFontSize( this.getFontSize() );


			// font family name
			dg.setFontFamilyName( this.getFontFamilyName() );			


			// font style
			dg.setFontStyle( this.getFontStyle() );
			

			// line width
			dg.setLineWidth( this.getLineWidth() );


			// color
			dg.setColorList( this.getColorList() );


			return true;
		}



		/**
		 * 
		 */
		public boolean setPropertyWithDialog()
		{
			SigDiffProperties p = this.getPropertiesFromDialg();
			if( p==null )
			{
				return false;
			}

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

			return true;
		}



		/**
		 * 
		 */
		public void windowActivated(final WindowEvent e)
		{
//	System.out.println("windowActivated");
		}


		/**
		 * 
		 */
		public void windowDeactivated(final WindowEvent e)
		{
//	System.out.println("windowDeactivated");
		}


		/**
		 * 
		 */
		public void windowIconified(final WindowEvent e)
		{
//	System.out.println("windowIconified");
		}


		/**
		 * 
		 */
		public void windowDeiconified(final WindowEvent e)
		{
//	System.out.println("windowDeiconified");
		}


		/**
		 * 
		 */
		public void windowOpened(final WindowEvent e)
		{
//	System.out.println("windowOpened");
		}


		/**
		 * 
		 */
		public void windowClosed(final WindowEvent e)
		{
//	System.out.println("windowClosed");
		}


		/**
		 * 
		 */
		public void windowClosing(final WindowEvent e)
		{
//	System.out.println("windowClosing");

			Object obj = e.getSource();
//	System.out.println(obj);
			if( obj.equals( mSigDiffDialog ) )
			{
				this.onCanceled();
			}

		}


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

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


			if( strCommand.equals(REMOVE_SIGDIFF_SYMBOL) )
			{
				this.setVisible(false);
				callParentUpdateHistory();
				mFocusedSymbol = null;
//				repaint();

				return;
			}


			//
			// for the properties of group
			//

			if( strCommand.equals("OK")
				|| mSigDiffDialog.getActiveComponentList().contains(source) )
			{
				if( this.onOK() == false ) return;
			}
			else if( strCommand.equals("Cancel") )
			{
				if( this.onCanceled() == false ) return;
			}
			else if( strCommand.equals("Preview") )
			{
				if( this.onPreviewed() == false ) return;
			}


		}


		/**
		 * 
		 */
		private boolean onOK()
		{

			boolean flag;

			// ダイアログからプロパティを取得して設定
			flag = this.setPropertyWithDialog();
			if( !flag )
			{
				return false;
			}


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

			SGProperties pTemp = this.mTemporaryProperties;
			SGProperties pPresent = this.getProperties();
//System.out.println("before:"+pTemp);
//System.out.println("after:"+pPresent);
			if( pTemp.equals(pPresent) == false )
			{
				// オブジェクト履歴を更新
				this.updateHistory();
			}
//System.out.println();

			this.createDrawingElement();
			notifyChange();
//			repaint();


			this.mTemporaryProperties = null;
			mSigDiffDialog.hide();
			mSigDiffDialog.removeActionListener();
			mSigDiffDialog.removeWindowListener(this);

			return true;

		}



		/**
		 * 
		 */
		private boolean onCanceled()
		{
			boolean flag = this.recover();
			if( !flag ) return false;

			this.createDrawingElement();
			notifyChange();
//			repaint();

			this.mTemporaryProperties = null;

			mSigDiffDialog.hide();
			mSigDiffDialog.removeActionListener();
			mSigDiffDialog.removeWindowListener(this);

			return true;
		}


		/**
		 * 
		 */
		private boolean onPreviewed()
		{
			boolean flag = this.setPropertyWithDialog();
			if( !flag ) return false;

			this.createDrawingElement();
			notifyChange();
//			repaint();

			return true;
		}


		/**
		 * 
		 * @return
		 */
		private boolean recover()
		{

			if( this.setProperties( this.mTemporaryProperties ) == false )
			{
				return false;
			}

			this.mTemporaryProperties = null;

			return true;
		}



		/**
		 *
		 */
		public float getX()
		{
			return this.mMagnification*this.mX + mGraphAreaX;
		}


		/**
		 *
		 */
		public float getY()
		{
			return this.mMagnification*this.mY + mGraphAreaY;
		}


		/**
		 * 
		 * @param x
		 * @return
		 */
		public boolean setX( final float x )
		{
			this.mX = ( x - mGraphAreaX )/this.mMagnification;
			return true;
		}


		/**
		 * 
		 * @param y
		 * @return
		 */
		public boolean setY( final float y )
		{
			this.mY = ( y - mGraphAreaY )/this.mMagnification;
			return true;			
		}


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

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

			if( this.contains(x,y) || this.mStringElement.contains(x,y) )
			{
				// マウスボタンを押下した点
				this.mPressedPoint = e.getPoint();

				// record history
				this.mTemporaryProperties = this.getProperties();

				// set the temporary object
				mTempSymbol.setMagnification( this.mMagnification );
				mTempSymbol.setLocation( this.getX(), this.getY() );
				mTempSymbol.setSize( this.getWidth(), this.getPerpendicularHeight1(), this.getPerpendicularHeight2() );
//				mTempSymbol.setWidth( this.getWidth() );
//				mTempSymbol.setLeftHeight( this.getLeftHeight() );
//				mTempSymbol.setRightHeight( this.getRightHeight() );

				this.mFlippingHorizontalFlag = this.isFlippingHorizontal();

/*
System.out.println("***");
System.out.println(this.mX+"  "+this.mY);
System.out.println(mTempSymbol.mX+"  "+mTempSymbol.mY);
System.out.println(this.getX()+"  "+this.getY());
System.out.println(mTempSymbol.getX()+"  "+mTempSymbol.getY());
System.out.println();
*/

				return true;
			}

			return false;
		}



		private boolean mFlippingHorizontalFlag;


		/**
		 * 
		 */
		protected boolean onDrawingElement( final int x, final int y )
		{

			if( this.mStringElement.contains(x,y) )
			{
				return true;
			}


			if( this.mHorizontalLine.contains(x,y) )
			{
				return true;
			}

			if( this.mPerpendicularLine1.contains(x,y) )
			{
				return true;
			}

			if( this.mPerpendicularLine2.contains(x,y) )
			{
				return true;
			}

			return false;
		}



		/**
		 * 
		 */
		protected boolean drawAllAnchors( final Graphics2D g2d )
		{
			this.drawAnchor( g2d, this.getLeftTerm() );
			this.drawAnchor( g2d, this.getLeftMiddle() );
			this.drawAnchor( g2d, this.getLeftJoint() );
			this.drawAnchor( g2d, this.getHorizontalMiddle() );
			this.drawAnchor( g2d, this.getRightJoint() );
			this.drawAnchor( g2d, this.getRightMiddle() );
			this.drawAnchor( g2d, this.getRightTerm() );

			return true;
		}



		/**
		 * 
		 */
		private void drawAnchor( final Graphics2D g2d, final Point2D pos )
		{
			final float x = (float)pos.getX();
			final float y = (float)pos.getY();

			final Shape anchor = new Ellipse2D.Float(
				x-0.5f*mAnchorSize, y-0.5f*mAnchorSize, mAnchorSize, mAnchorSize
			);

			g2d.setPaint(Color.BLACK);
			g2d.setStroke( new BasicStroke(3) );
			g2d.draw(anchor);

			g2d.setPaint(Color.WHITE);
			g2d.fill(anchor);
		}



		/**
		 * 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 ) );
		}



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

			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.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 if( this.mStringElement.contains(x,y) )
			{
				location = ON_STRING;
			}
			else
			{
				location = OTHER;
			}

			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;

		}



		/**
		 * 
		 */
		protected Point mPressedPoint = null;


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

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

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


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


			final float xOld = mTempSymbol.getX();
			final float yOld = mTempSymbol.getY();
			final float wOld = mTempSymbol.getWidth();
			final float h1Old = mTempSymbol.getPerpendicularHeight1();
			final float h2Old = mTempSymbol.getPerpendicularHeight2();

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


			final int diffX = e.getX() - mPressedPoint.x;
			final int diffY = e.getY() - 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);

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

			if( mMouseLocation == HORIZONTAL_MIDDLE )
			{
//System.out.println("NORTH");
				sizeNewY1 = sizeOldY1 - diffY;
				sizeNewY2 = sizeOldY2 - diffY;

				y = yOld + sizeOldY1 - sizeNewY1;
				h1 = sizeNewY1;
				h2 = sizeNewY2;
			}
			else if(
				( mMouseLocation==LEFT_MIDDLE && !this.mFlippingHorizontalFlag )
				||
				( mMouseLocation == RIGHT_MIDDLE && this.mFlippingHorizontalFlag )
			)
			{
				sizeNewX = sizeOldX - diffX;
				x = xOld + sizeOldX - sizeNewX;
				w = sizeNewX;
			}
			else if(
				( mMouseLocation==RIGHT_MIDDLE && !this.mFlippingHorizontalFlag )
				||
				( mMouseLocation==LEFT_MIDDLE && this.mFlippingHorizontalFlag )
			)
			{
				sizeNewX = sizeOldX + diffX;
				w = sizeNewX;
			}
			else if(
				( mMouseLocation==LEFT_JOINT && !this.mFlippingHorizontalFlag )
				||
				( mMouseLocation==RIGHT_JOINT && this.mFlippingHorizontalFlag )
			)
			{
				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(
				( mMouseLocation==RIGHT_JOINT && !this.mFlippingHorizontalFlag )
				||
				( mMouseLocation==LEFT_JOINT && this.mFlippingHorizontalFlag )
			)
			{
				sizeNewX = sizeOldX + diffX;
				sizeNewY1 = sizeOldY1 - diffY;
				sizeNewY2 = sizeOldY2 - diffY;

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

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

				w = sizeNewX;
				h2 = sizeNewY2;
			}

//System.out.println(diffX+"  "+diffY);


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


//System.out.println(x+"  "+y+"  "+w+"  "+hl+"  "+hr);


			// set properties
			this.setLocation( x, y );
			this.setSize(w,h1,h2);
//this.setWidth( w );
//this.setLeftHeight( hl );
//this.setRightHeight( hr );
			this.createDrawingElement();


			mTempSymbol.setLocation( x, y );
			mTempSymbol.setSize( w, h1, h2 );

//mTempSymbol.setWidth( w );
//mTempSymbol.setLeftHeight( hl );
//mTempSymbol.setRightHeight( hr );


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


//System.out.println("location="+location);
//System.out.println("*** "+mCursor.getType());

//			repaint();

//System.out.println(mMouseLocation);
//System.out.println(this.getMouseLocation(e.getX(),e.getY()));
//System.out.println();

//this.mMouseLocation = this.getMouseLocation( e.getX(), e.getY() );

			return true;

		}



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

//System.out.println("drag");

			// parallel displacement
			if ( this.mPressedPoint != null )
			{

				// set the location to the symbol
				final float x = (float)(e.getX()-mPressedSymbolOrigin.x);
				final float y = (float)(e.getY()-mPressedSymbolOrigin.y);
				this.setLocation(x,y);

				// シンボルがフィギュアの外に出ていたら戻す
//				drawBackSigDiffSymbol( this );
				this.createDrawingElement();
//				repaint();
			}

			return true;

		}






		/**
		 * 
		 * @return
		 */
		private ArrayList mStringElementPropertyHistoryList = new ArrayList();



		/**
		 * 
		 * @return
		 */
		private int mStringElementStateCounter = 0;



		/**
		 * 
		 */
		public boolean initPropertiesHistory()
		{
			this.addStringPropertyHistory( this.getProperties() );
			return true;
		}



		/**
		 * 
		 * @return
		 */
		private boolean addStringPropertyHistory( SGProperties p )
		{

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

//System.out.println("<< addFigurePropertyHistory >>");
//System.out.println(this.mFigureStateCounter);

			ArrayList list = new ArrayList();
			for( int ii=0; ii<this.mStringElementStateCounter; ii++ )
			{
				list.add( this.mStringElementPropertyHistoryList.get(ii) );
			}
			list.add(p);

			this.mStringElementPropertyHistoryList = list;

//System.out.println(this.mFigurePropertyHistoryList);
//System.out.println("x="+p.x+"  y="+p.y);
//System.out.println("w="+p.width+"  h="+p.height);
//System.out.println();

			return true;
		}



		/**
		 * 現在、状態が履歴のどの位置にあるのかを示すカウンタ
		 */
		private int mCurrentStateCounter = 0;


		/**
		 * アンドゥ対象オブジェクトの履歴リスト
		 */
		protected ArrayList mUndoableObjectHistoryList = new ArrayList();




		/**
		 * アンドゥを行う
		 */
		public boolean undo()
		{
//System.out.println("undo : SigDiffSymbol");
//System.out.println();

			this.mStringElementStateCounter--;

			SigDiffProperties p
				= (SigDiffProperties)this.mStringElementPropertyHistoryList.get(
					this.mStringElementStateCounter);
//System.out.println(p);
//System.out.println();

			this.setProperties(p);

			this.createDrawingElement();
//			repaint();

			return true;
		}


		/**
		 * リドゥを行う
		 */
		public boolean redo()
		{
//System.out.println("redo : SigDiffSymbol");
//System.out.println();

			this.mStringElementStateCounter++;

			SigDiffProperties p
				= (SigDiffProperties)this.mStringElementPropertyHistoryList.get(
					this.mStringElementStateCounter);
//System.out.println(p);
//System.out.println();

			this.setProperties(p);
			this.createDrawingElement();
//			repaint();

			return true;
		}



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

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


		/**
		 * オブジェクトの履歴を更新する
		 * @return
		 */
		public boolean updateObjectHistory( final SGIUndoable obj )
		{
			ArrayList objList = new ArrayList();
			objList.add(obj);
			boolean flag = this.updateObjectHistory(objList);
			if( !flag )
			{
				return false;
			}

			return true;
		}



		/**
		 * オブジェクトの履歴を更新する
		 */
		public boolean updateObjectHistory( final ArrayList objList )
		{

			ArrayList list = new ArrayList();
			for( int ii=0; ii<this.mCurrentStateCounter; ii++ )
			{
				Object obj = this.mUndoableObjectHistoryList.get(ii);
				list.add(obj);
			}
			list.add( new ArrayList(objList) );

			this.mUndoableObjectHistoryList = list;
			this.mCurrentStateCounter++;

//System.out.println("<< updateObjectHistory >>");
//System.out.println(this.mUndoableObjectHistoryList);
//System.out.println(this.mCurrentStateCounter);
//System.out.println();

			return true;
		}



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

			// 親オブジェクトのオブジェクト履歴を更新
			this.updateParentHistory();


			//
			this.updateThisObjectHistory();


			return true;
		}


		/**
		 * 
		 */
		public boolean updateThisObjectHistory()
		{
			// オブジェクト履歴を更新
			this.updateObjectHistory(this);


			// フィギュアのプロパティ履歴を更新
			this.mStringElementStateCounter++;
			this.addStringPropertyHistory( this.getProperties() );

			return true;
		}


		/**
		 * 親オブジェクトに対して自身の変更を伝える。
		 */
		public boolean updateParentHistory()
		{
			return updateParentHistoryFromStringElement(this);
		}



		/**
		 * 
		 */
		private boolean isChanged()
		{
			final boolean b = !(this.getProperties().equals(this.mTemporaryProperties));
			return b;
		}



	}










	/**
	 * 
	 */
	public static class GraphProperties extends SGProperties
	{

		ArrayList visibleElementGroupList = new ArrayList();
		ArrayList visibleTimingElementList = new ArrayList();
		ArrayList visibleSigDiffSymbolList = new ArrayList();


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


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

			GraphProperties p = (GraphProperties)obj;

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

			return true;
		}


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

			return str;
		}
		
	}



}

