
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;



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

		final Rectangle2D rect = el.getStringElement().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.clearFocusedSymbol();

		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 createAllDrawingElements();



	/**
	 *
	 */
	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 int x, final int y, final int w, final int h, final float ratio )
	{
//System.out.println("zoom");
//System.out.println("ratio="+ratio);

		super.zoom(x,y,w,h,ratio);

		this.onZoomed(x,y,w,h,ratio);

		this.createAllDrawingElements();

		return true;

	}



	/**
	 * 
	 */
	protected boolean onZoomed( final int x, final int y, final int w, final int h, final float ratio )
	{

		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			final ElementGroupSetInGraph groupSet
				= (ElementGroupSetInGraph)this.mGroupSetList.get(ii);
			groupSet.zoom(w,h,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(w,h,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 removeAllElements()
	{
		super.removeAllElements();

		this.mGroupSetList.clear();
		this.mTimingElementGroupSetList.clear();

		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);

		this.createAllDrawingElements();

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



		return true;
	}



	/**
	 * 
	 */
	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
			sd.getStringElement().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 float ratioX = aElement.getGraphAreaX();
		final float ratioY = aElement.getGraphAreaY();
		final float ratioW = aElement.getGraphAreaWidth();
		final float ratioH = aElement.getGraphAreaHeight();

		this.setGraphAreaRect( ratioX, ratioY, ratioW, ratioH );

//System.out.println(ratioX+"  "+ratioY+"  "+ratioW+"  "+ratioH);
//System.out.println();

		this.drawBackAllSigDiffSymbols();



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

		{
			// 情報の取得
			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オブジェクトをキーとして用いる

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

					groupSet.setMagnification(this.mMagnification);
					this.mTimingElementGroupSetList.add( ii, groupSet );

					groupSet.addPropertiesHistory();
					this.updateHistory();

				}

			}

		}

//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.createAllDrawingElements();

		this.repaint();

		return true;

	}



	/**
	 * タイミング描画要素の作成
	 */
	protected boolean createTimingElements( final SGTimingElementGroupSet groupSet )
	{

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

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

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

			if( group instanceof SGElementGroupLine )
			{
				final SGElementGroupLine groupLine = (SGElementGroupLine)group;
				final ArrayList ratioList = this.calcLocationOfTimingLine( axis, value );
				groupLine.createDrawingElement( ratioList );
			}
			else
			{
				throw new Error();
			}

		}



		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;
	}



	/**
	 * タイミング線の描画要素を作成
	 */

	private ArrayList calcLocationOfTimingLine(
		final SGAxis axis, final double value )
	{

		// オブジェクトを作成
		final SGDrawingElementLine line
			= new SGDrawingElementLine2D(
				new SGTuple2f(), new SGTuple2f(), mTimingLineWidth );


		//
		// 位置を決定
		//

		// 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("軸が一致しない");
		}


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


		final ArrayList posList = new ArrayList();
		posList.add(start);
		posList.add(end);


		return posList;

	}



	/**
	 * 
	 */
	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 ArrayList posList )
	{

//System.out.println("<< calcRatioOfSXYData >>");

		final float gx = this.mGraphAreaX;
		final float gy = this.mGraphAreaY;
		final float gw = this.mGraphAreaWidth;
		final float gh = this.mGraphAreaHeight;
//		final float mag = this.mMagnification;

//System.out.println(gx*SGConstants.CM_POINT_RATIO);
//System.out.println(gy*SGConstants.CM_POINT_RATIO);
//System.out.println(gw*SGConstants.CM_POINT_RATIO);
//System.out.println(gh*SGConstants.CM_POINT_RATIO);
//System.out.println();


		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();

		final int vNum = valueArray.length;



		// グラフ内での値に変換
		double minXInScale = 0.0;
		double maxXInScale = 0.0;
		double minYInScale = 0.0;
		double maxYInScale = 0.0;
		final int num = valueArray.length;
		final SGTuple2d[] valueArrayInScale = new SGTuple2d[num];
		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);
//System.out.println(ii+"  "+valueArray2[ii].y+"  "+yInScale[ii]);
			}
		}


		// グラフ領域内でのデータ点の比率を計算
		// グラフ全体での位置を計算
		final SGTuple2f[] ratioArray = new SGTuple2f[num];
		for( int ii=0; ii<num; ii++ )
		{

			if( typeX == SGAxis.LOG_TYPE )
			{
				if( Double.isInfinite( xInScale[ii] ) )
				{
					continue;
				}

				if( Double.isNaN( xInScale[ii] ) )
				{
					continue;
				}
			}

			if( typeY == SGAxis.LOG_TYPE )
			{
				if( Double.isInfinite( yInScale[ii] ) )
				{
					continue;
				}

				if( Double.isNaN( yInScale[ii] ) )
				{
					continue;
				}
			}


			final float x
				= (float)( ( xInScale[ii] - minXInScale )/( maxXInScale - minXInScale ) );
			final float y
				= (float)( 1.0 - ( yInScale[ii] - minYInScale )/( maxYInScale - minYInScale ) );

			final float posX = ( gx + x*gw );
			final float posY = ( gy + y*gh );

			SGTuple2f pos = new SGTuple2f( (float)posX, (float)posY );
			posList.add( pos );
		}


		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 Error();
		}


		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;
	}



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


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

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


		// 左ボタンクリック２回でダイアログを出す。
		if( (SwingUtilities.isLeftMouseButton(e) )
		&& ( e.getClickCount() == 2 ) )
		{
//System.out.println("LEFT * 2");

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

			// 最初の１クリックで選択されているので、
			// それをクリアする
			this.clearSelectedElementsGroupSet();

			// show the property dialog
			groupSet.showPropertyDialog();

			return true;
		}


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


		// CtrlキーまたはShiftキーを押した状態での左ボタンクリック１回で、
		// 複数のオブジェクトの選択/解除を行う。
		if(
			( SwingUtilities.isLeftMouseButton(e) )
			&& ( e.getClickCount() == 1 )
			&& (
				( (e.getModifiers()&MouseEvent.CTRL_MASK) != 0)
				|| ( (e.getModifiers()&MouseEvent.SHIFT_MASK) != 0)
			)
		)
		{
//System.out.println("CTRL");
			if( this.mSelectedGroupSetList.contains(groupSet) )
			{
				this.removeSelectedGroupSet(groupSet);
//System.out.println("remove"+"  "+this.mSelectedGroupList.size());
			}
			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);
				}
//System.out.println("add"+"  "+this.mSelectedGroupList.size());
			}

			repaint();
//System.out.println();
	
			return true;
		}


		// CtrlキーもShiftキーも押さない状態での
		// 左ボタンクリック１回で、
		// オブジェクトの選択/解除を行う。
		if(
			( SwingUtilities.isLeftMouseButton(e) )
			&& ( e.getClickCount() == 1 )
			&& (
				( (e.getModifiers()&MouseEvent.CTRL_MASK) == 0)
				&& ( (e.getModifiers()&MouseEvent.SHIFT_MASK) == 0)
			)
		)
		{
//System.out.println("LEFT * 1");
	
			if( this.mSelectedGroupSetList.contains(groupSet) )
			{
				this.removeSelectedGroupSet(groupSet);
//System.out.println("remove"+"  "+this.mSelectedGroupList.size());
			}
			else
			{
				this.clearSelectedElementsGroupSet();
				this.addSelectedGroupSet(groupSet);
//System.out.println("add"+"  "+this.mSelectedGroupList.size());
			}

			repaint();
	
//System.out.println();
			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);
			groupSet.setVisible(false);
		}
		this.mSelectedGroupSetList.clear();


		this.updateHistory();

		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.mSelectedFlag = true;

		return true;		
	}


	/**
	 * 
	 */
	private boolean removeSelectedGroupSet( final SGElementGroupSet groupSet )
	{
		this.mSelectedGroupSetList.remove(groupSet);
		groupSet.mSelectedFlag = 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 this.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) )
		{
//			this.createAllDrawingElements();
//			this.startBlinking();
			return true;
		}


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

//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(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);
			final ArrayList groupList = groupSet.mDrawingElementGroupList;

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

		return false;
	}




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

		// 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 )
	{

		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.setMouseLocation(x,y);
					this.mCursor = sd.getCursor();
					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);

		// 前処理
//		this.terminateEditField();


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

		this.mSignificantDifferentSymbolsList.add(sd);


		//
		this.updateHistory();


		// initialize history
		sd.addPropertiesHistory();

		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
	{

		SigDiffProperties p = (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;
			}

			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.addPropertiesHistory();

			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.createAllDrawingElements();
		this.notifyChange();

		repaint();

		return true;
	}


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


		this.createAllDrawingElements();
		this.notifyChange();

		repaint();

		return true;
	}



	/**
	 * 
	 */
	private 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();
	
	
		SigDiffProperties p = new SigDiffProperties();
		p.x = x;
		p.y = y;
		p.width = width;
		p.leftHeight = leftHeight;
		p.rightHeight = 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;
		}



		/**
		 * 
		 */
		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);
				ArrayList list = group.mDrawingElementList;
				for( int jj=0; jj<list.size(); jj++ )
				{
					SGDrawingElement el = (SGDrawingElement)list.get(jj);
					if( el.contains(x,y) )
					{
//						group.mEnteredFlag = true;
						return true;
					}
				}

//				group.mEnteredFlag = false;
			}

			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();

			//
			createAllDrawingElements();
			notifyChange();
			repaint();

			return true;
		}



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

			this.mTemporaryProperties = null;

			final SGPropertyDialog dg = mPropertyDialogForData;


			//
			createAllDrawingElements();
			notifyChange();
			repaint();

			return true;
		}


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

			createAllDrawingElements();
			notifyChange();
			repaint();

			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
		 */
		private ArrayList mElementGroupSetPropertyHistoryList = new ArrayList();


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


		/**
		 * 
		 */
		public boolean addPropertiesHistory()
		{
			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);

			createAllDrawingElements();
			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);

			createAllDrawingElements();
			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.updateObjectHistory(this);


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

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

			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;
		}


		/**
		 * 
		 */
		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 int w, final int h, final float ratio )
		{
			super.zoom(w,h,ratio);

			for( int ii=0; ii<this.mElementGroupSetList.size(); ii++ )
			{
				SGElementGroupSet groupSet
					= (SGElementGroupSet)this.mElementGroupSetList.get(ii);
				groupSet.zoom(w,h,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;
		}


	}




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

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



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


		/**
		 * 
		 */
		protected SGElementGroup createDrawingElementGroup( final int type )
		{


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

			group.mGroupSet = this;

			return group;
		}


		/**
		 * 
		 */
		public SGElementGroup createDrawingElementGroup( final SGDrawingElement element )
		{

			SGElementGroup group = null;
			if( element instanceof SGDrawingElementLine )
			{
				group = new TimingElementGroupLine();
			}
			else
			{
				throw new Error("");
			}


			group.setProperty( element );

			group.mGroupSet = this;


			return group;

		}


		/**
		 * 
		 */
		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 ArrayList groupList = this.mDrawingElementGroupList;
			for( int jj=groupList.size()-1; jj>=0; jj-- )
			{
				final SGElementGroup group = (SGElementGroup)groupList.get(jj);
				final ArrayList elementList = group.mDrawingElementList;
				for( int kk=0; kk<elementList.size(); kk++ )
				{
					final SGDrawingElement element = (SGDrawingElement)elementList.get(kk);
					final boolean flag = element.contains(e.getX(),e.getY());

					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);
				final ArrayList elementList = group.mDrawingElementList;
				for( int kk=0; kk<elementList.size(); kk++ )
				{
					final SGDrawingElement element = (SGDrawingElement)elementList.get(kk);
					final boolean flag = element.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);

			createAllDrawingElements();
			notifyChange();
			repaint();

			return true;
		}



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

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

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

			createAllDrawingElements();
			notifyChange();
			repaint();

			return true;
		}


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

			createAllDrawingElements();
			notifyChange();
			repaint();

			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 addPropertiesHistory()
		{
			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);

			createAllDrawingElements();
			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);

			createAllDrawingElements();
			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.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();
		}


		/**
		 * 
		 */
		public void actionPerformed(final ActionEvent e)
		{
			super.actionPerformed(e);

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


			if( command.equals(MOVE_TO_FRONT) )
			{
				moveTimingElementGroupSetToFront( this.mGroupSet );
			}
			else if( command.equals(MOVE_TO_BACK) )
			{
				moveTimingElementGroupSetToBack( this.mGroupSet );
			}
			else if( command.equals(REMOVE_TIMING_LINE) )
			{
//				removeTimingElementGroupSet( this.mGroupSet );

this.mGroupSet.setVisible(false);
callParentUpdateHistory();
			}


/*
			//
			// for the properties of line
			//

			ArrayList comList = this.getActiveDialogComponents();

			if( command.equals("OK") || comList.contains(source) )
			{
				this.setPropertyWithDialog();
				this.mDialog.hide();
			}
			else if( command.equals("Cancel") )
			{
				recover();
				this.mDialog.hide();
			}
			else if( command.equals("Preview") )
			{
				this.setPropertyWithDialog();
			}
*/

			createAllDrawingElements();
			notifyChange();
			repaint();
		}



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



	/**
	 * 
	 */
	protected 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 SGSignificantDifferenceSymbol
		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 final String REMOVE_SYMBOL = "Remove this Symbol";


		/**
		 * 
		 */
		private boolean createPopupMenu()
		{
			mPopupMenu.setBounds( 0, 0, 100, 100 );

			final String[] commandArray = {
				REMOVE_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.setLeftHeight( SGDefaultValues.SIGDIFF_SYMBOL_LEFT_HEIGHT );
			this.setRightHeight( 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.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.mLeftHeight*SGConstants.CM_POINT_RATIO) );
			SGUtilityText.writePropertyLine( writer, PF_SIGDIFF_RIGHT_HEIGHT, new Float( this.mRightHeight*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.leftHeight = this.mLeftHeight;
			p.rightHeight = this.mRightHeight;
			p.text = this.getText();

/*
			p.space = dg.getSpace()/SGConstants.CM_POINT_RATIO;
			p.fontSize = dg.getFontSize();
			p.fontFamilyName = dg.getFontFamilyName();
			p.fontStyle = dg.getFontStyle();
			p.lineWidth = dg.getLineWidth();
			p.colorList = dg.getTextColorList();
*/

			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 setProperties( final SGProperties p )
		{

			if( p==null ) return false;

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

			SigDiffProperties sp = (SigDiffProperties)p;

			this.mX = sp.x;
			this.mY = sp.y;
			this.setSize( sp.width, sp.leftHeight, sp.rightHeight );
			this.setText( sp.text );

			this.setSpace( sp.space );
			this.setFontFamilyName( sp.fontFamilyName );
			this.setFontSize( sp.fontSize );
			this.setFontStyle( sp.fontStyle );
			this.setLineWidth( sp.lineWidth );
			this.setColorList( sp.colorList );

			return true;

		}


		/**
		 * 
		 */
		public SGProperties getProperties()
		{

			SigDiffProperties p = new SigDiffProperties();
			p.x = this.mX;
			p.y = this.mY;
			p.width = this.mWidth;
			p.leftHeight = this.mLeftHeight;
			p.rightHeight = this.mRightHeight;
			p.text = this.getText();

			p.space = this.getSpace();
			p.fontFamilyName = this.getFontFamilyName();
			p.fontSize = this.getFontSize();
			p.fontStyle = this.getFontStyle();
			p.colorList = this.mColorList;
			p.lineWidth = this.getLineWidth();
			
			return p;
		}


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


		/**
		 * 引数は任意の倍率における、フィギュア内における位置
		 */
		public boolean setLocation( float x, float y )
		{
//System.out.println("x="+mX*SGConstants.CM_POINT_RATIO+"cm  y="+mY*SGConstants.CM_POINT_RATIO+"cm");
			this.setX(x);
			this.setY(y);
			return true;
		}


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



		/**
		 * 倍率100%のときの、フィギュア内での位置を返す
		 */
		public Point2D getLocation()
		{
			Point2D pos = new Point2D.Float(
				this.getX(), this.getY()
			);
			return pos;
		}


		/**
		 * 
		 */
		public boolean isVisible()
		{
			return this.mVisible;
		}


		/**
		 * 
		 */
		public boolean setVisible( final boolean flag )
		{
			this.mVisible = flag;
			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) )
			{

				// record history

				this.mTemporaryProperties = this.getProperties();

				// マウスボタンを押下した点
				this.mPressedPoint = e.getPoint();

mTempSymbol.setMagnification( this.mMagnification );
mTempSymbol.setLocation( this.getX(), this.getY() );
mTempSymbol.setSize( this.getWidth(), this.getLeftHeight(), this.getRightHeight() );


/*
				this.mXDragging = this.getX();
				this.mYDragging = this.getY();
				this.mWidthDragging = this.mWidth;
				this.mLeftHeightDragging = this.mLeftHeight;
				this.mRightHeightDragging = this.mRightHeight;
*/
				return true;
			}

			return false;
		}



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

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


			if( this.mLineTop.contains(x,y) )
			{
//System.out.println("top");
				return true;
			}

			if( this.mLineLeft.contains(x,y) )
			{
//System.out.println("left");
				return true;
			}

			if( this.mLineRight.contains(x,y) )
			{
//System.out.println("right");
				return true;
			}

			return false;
		}



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

			final float xLeft = this.getX();
			final float xRight = this.getX() + this.getWidth();
			final float xMiddle = ( xLeft + xRight )/2.0f;

			final float yTop = this.getY();
			final float yBottomLeft = this.getY() + this.getLeftHeight();
			final float yMiddleLeft = ( yTop + yBottomLeft )/2.0f;
			final float yBottomRight = this.getY() + this.getRightHeight();
			final float yMiddleRight = ( yTop + yBottomRight )/2.0f;

			this.drawAnchor(g2d,xMiddle,yTop);
			this.drawAnchor(g2d,xLeft,yTop);
			this.drawAnchor(g2d,xLeft,yMiddleLeft);
			this.drawAnchor(g2d,xLeft,yBottomLeft);
			this.drawAnchor(g2d,xRight,yTop);
			this.drawAnchor(g2d,xRight,yMiddleRight);
			this.drawAnchor(g2d,xRight,yBottomRight);

			return true;
		}



		/**
		 * 
		 */
		private void drawAnchor( final Graphics2D g2d, final float x, final float y )
		{
			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;


		/**
		 * 
		 */
		protected final int OTHER = 0;


		/**
		 * 
		 */
		protected final int NORTH = 1;


		/**
		 * 
		 */
		protected final int SOUTH = 2;


		/**
		 * 
		 */
		protected final int WEST = 3;


		/**
		 * 
		 */
		protected final int EAST = 4;


		/**
		 * 
		 */
		protected final int NORTH_WEST = 5;


		/**
		 * 
		 */
		protected final int NORTH_EAST = 6;


		/**
		 * 
		 */
		protected final int SOUTH_WEST = 7;


		/**
		 * 
		 */
		protected final int SOUTH_EAST = 8;


		/**
		 * 
		 */
		protected final int ON_STRING = 9;



		/**
		 * マウス位置を属性に設定
		 */
		private boolean setMouseLocation( final int x, final int y )
		{

			final double radius = 1.25*mAnchorSize;

			final float sx = this.getX();
			final float sy = this.getY();
			final float sw = this.getWidth();
			final float slh = this.getLeftHeight();
			final float srh = this.getRightHeight();


			// 左上
			if( ( Math.abs(x-sx) < radius ) && ( Math.abs(y-sy) < radius ) )
			{
				mMouseLocation = NORTH_WEST;
			}
			// 右下
			else if( ( Math.abs( x-(sx+sw) ) < radius )
				&& ( ( Math.abs( y-(sy+srh) ) < radius ) ) )
			{
				mMouseLocation = SOUTH_EAST;
			}
			// 右上
			else if( ( Math.abs(x-(sx+sw)) < radius )
				&& ( Math.abs(y-sy) < radius ) )
			{
				mMouseLocation = NORTH_EAST;
			}
			// 左下
			else if( ( Math.abs(x-sx) < radius )
				&& ( ( Math.abs(y-(sy+slh)) < radius ) ) )
			{
				mMouseLocation = SOUTH_WEST;
			}
			// 左端中央
			else if( ( Math.abs(x-sx) < radius )
				&& ( Math.abs(y-(sy+slh/2)) < radius ) )
			{
				mMouseLocation = WEST;
			}
			// 右端中央
			else if( ( Math.abs(x-(sx+sw)) < radius )
				&& ( Math.abs(y-(sy+srh/2)) < radius ) )
			{
				mMouseLocation = EAST;
			}
			// 上端中央
			else if( ( Math.abs(y-sy) < radius )
				&& ( Math.abs(x-(sx+sw/2)) < radius ) )
			{
				mMouseLocation = NORTH;
			}
			else if( this.mStringElement.contains(x,y) )
			{
//System.out.println(this.mStringElement.getElementBounds()+"  "+x+"  "+y);
				mMouseLocation = ON_STRING;
				return true;
			}
			else
			{
				mMouseLocation = OTHER;
			}

			return true;

		}



		/**
		 * 
		 */
		private Cursor getCursor()
		{

			// マウスの位置に応じてカーソルを変更
			Cursor cur = null;
			switch( mMouseLocation )
			{
				case WEST:
				{
					cur = new Cursor( Cursor.W_RESIZE_CURSOR );
					break;
				}
				case EAST:
				{
					cur = new Cursor( Cursor.E_RESIZE_CURSOR );
					break;
				}
				case NORTH:
				{
					cur = new Cursor( Cursor.N_RESIZE_CURSOR );
					break;
				}
				case SOUTH:
				{
					cur = new Cursor( Cursor.S_RESIZE_CURSOR );
					break;
				}
				case NORTH_WEST:
				{
					cur = new Cursor( Cursor.NW_RESIZE_CURSOR );
					break;
				}
				case SOUTH_EAST:
				{
					cur = new Cursor( Cursor.SE_RESIZE_CURSOR );
					break;
				}
				case NORTH_EAST:
				{
					cur = new Cursor( Cursor.NE_RESIZE_CURSOR );
					break;
				}
				case SOUTH_WEST:
				{
					cur = new Cursor( Cursor.SW_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;



		/**
		 * 
		 */
//		private float mXDragging = 0.0f;


		/**
		 * 
		 */
//		private float mYDragging = 0.0f;


		/**
		 * 
		 */
//		private float mWidthDragging = 0.0f;


		/**
		 * 
		 */
//		private float mLeftHeightDragging = 0.0f;


		/**
		 * 
		 */
//		private float mRightHeightDragging = 0.0f;



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

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

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


			if( getBounds().contains( e.getPoint() ) == false )
			{
				return false;
			}


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


			// グラフ描画領域の変更前の状態
/*			final float xOld = this.mXDragging;
			final float yOld = this.mYDragging;
			final float wOld = this.mWidthDragging;
			final float hlOld = this.mLeftHeightDragging;
			final float hrOld = this.mRightHeightDragging;
*/

			final float xOld = mTempSymbol.getX();
			final float yOld = mTempSymbol.getY();
			final float wOld = mTempSymbol.getWidth();
			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 sizeOldYLeft = hlOld;
			final float sizeOldYRight = hrOld;

			float sizeNewX = 0.0f;
			float sizeNewYLeft = 0.0f;
			float sizeNewYRight = 0.0f;


			// 以下の処理で更新する量
			// そのまま新しい属性になる
			float x = xOld;
			float y = yOld;
			float w = wOld;
			float hl = hlOld;
			float hr = hrOld;

final float r = SGConstants.CM_POINT_RATIO;
//System.out.println(xOld*r+"  "+yOld*r+"  "+wOld*this.mMagnification*r+"  "+hlOld*this.mMagnification*r+"  "+hrOld*this.mMagnification*r);
System.out.println(diffX*r+"  "+diffY*r);

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

			if( mMouseLocation == NORTH )
			{
//System.out.println("NORTH");

//				if( SGFigure.mDrawRectangleOnDraggingFlag )
				{
					mPressedPoint.setLocation(
						mPressedPoint.getX(),
						mPressedPoint.getY() + diffY
					);
				}

				sizeNewYLeft = sizeOldYLeft - diffY;
				sizeNewYRight = sizeOldYRight - diffY;

				y = yOld + sizeOldYLeft - sizeNewYLeft;
				hl = sizeNewYLeft;
				hr = sizeNewYRight;

			}
			else if( mMouseLocation == WEST )
			{

//System.out.println("WEST");
			
//				if( SGFigure.mDrawRectangleOnDraggingFlag )
				{
					mPressedPoint.setLocation(
						mPressedPoint.getX() + diffX,
						mPressedPoint.getY() + diffY
					);
				}

				sizeNewX = sizeOldX - diffX;

				x = xOld + sizeOldX - sizeNewX;
				w = sizeNewX;
			}
			else if( mMouseLocation == EAST )
			{
//System.out.println("EAST");

				mPressedPoint.setLocation(
					mPressedPoint.getX() + diffX,
					mPressedPoint.getY()
				);

				sizeNewX = sizeOldX + diffX;

				w = sizeNewX;

			}
			else if( mMouseLocation == NORTH_WEST )
			{

//				if( SGFigure.mDrawRectangleOnDraggingFlag )
				{
					mPressedPoint.setLocation(
						mPressedPoint.getX() + diffX,
						mPressedPoint.getY() + diffY
					);
				}

		
				// Shiftキーが押されていたら縦横比は変えない
				if( (e.getModifiers()&MouseEvent.SHIFT_MASK) != 0 )
				{
					sizeNewYLeft = sizeNewX*( sizeOldYLeft/sizeOldX );
					sizeNewYRight = sizeNewX*( sizeOldYRight/sizeOldX );
				}
				else
				{
					sizeNewYLeft = sizeOldYLeft - diffY;
					sizeNewYRight = sizeOldYRight - diffY;
				}

				sizeNewX = sizeOldX - diffX;

				x = xOld + sizeOldX - sizeNewX;
				y = yOld + sizeOldYLeft - sizeNewYLeft;
				w = sizeNewX;
				hl = sizeNewYLeft;
				hr = sizeNewYRight;

			}
			else if(
				( mMouseLocation == NORTH_EAST )
				&& ( (e.getModifiers()&MouseEvent.SHIFT_MASK) == 0 )
			)
			{

//				if( SGFigure.mDrawRectangleOnDraggingFlag )
				{
					mPressedPoint.setLocation(
						mPressedPoint.getX() + diffX,
						mPressedPoint.getY() + diffY
					);
				}
/*				else
				{
					mPressedPoint.setLocation(
						mPressedPoint.getX() + diffX,
						mPressedPoint.getY()
					);
				}
*/

				// Shiftキーが押されていないので縦横比は可変
				sizeNewX = sizeOldX + diffX;
				sizeNewYLeft = sizeOldYLeft - diffY;
				sizeNewYRight = sizeOldYRight - diffY;

				y = yOld + sizeOldYRight - sizeNewYRight;
				w = sizeNewX;
				hl = sizeNewYLeft;
				hr = sizeNewYRight;

			}
/*			else if(
				( mMouseLocation == NORTH_EAST )
				&& ( (e.getModifiers()&MouseEvent.SHIFT_MASK) != 0 )
			)
			{

				if( SGFigure.mDrawRectangleOnDraggingFlag )
				{
					mPressedPoint.setLocation(
						mPressedPoint.getX(),
						mPressedPoint.getY() + diffY
					);
				}


				// Shiftキーが押されているので縦横比は不変
				sizeNewYLeft = sizeOldYLeft - diffY/this.mMagnification;
				sizeNewYRight = sizeOldYRight - diffY/this.mMagnification;
				sizeNewX = sizeNewYRight*( sizeOldX/sizeOldYRight );

				y = yOld + sizeOldYRight - sizeNewYRight;
				w = sizeNewX;
				hl = sizeNewYLeft;
				hr = sizeNewYRight;

			}
*/			else if(
				( mMouseLocation == SOUTH_WEST )
				&& ( (e.getModifiers()&MouseEvent.SHIFT_MASK) == 0 )
			)
			{

//				if( SGFigure.mDrawRectangleOnDraggingFlag )
				{
					mPressedPoint.setLocation(
						mPressedPoint.getX() + diffX,
						mPressedPoint.getY() + diffY
					);
				}
/*				else
				{
					mPressedPoint.setLocation(
						mPressedPoint.getX(),
						mPressedPoint.getY() + diffY
					);
				}
*/

				// Shiftキーが押されていないので縦横比は可変
				sizeNewX = sizeOldX - diffX;
				sizeNewYLeft = sizeOldYLeft + diffY;

				x = xOld + sizeOldX - sizeNewX;
				w = sizeNewX;
				hl = sizeNewYLeft;

			}
/*			else if(
				( mMouseLocation == SOUTH_WEST )
				&& ( (e.getModifiers()&MouseEvent.SHIFT_MASK) != 0 )
			)
			{

				if( SGFigure.mDrawRectangleOnDraggingFlag )
				{
					mPressedPoint.setLocation(
						mPressedPoint.getX() + diffX,
						mPressedPoint.getY() + diffY
					);
				}


				// Shiftキーが押されているので縦横比は不変
				sizeNewX = sizeOldX - diffX/this.mMagnification;
				sizeNewYLeft = sizeNewX*( sizeOldYLeft/sizeOldX );

				x = xOld + sizeOldX - sizeNewX;
				w = sizeNewX;
				hl = sizeNewYLeft;

			}
*/			else if(
				( mMouseLocation == SOUTH_EAST )
				&& ( (e.getModifiers()&MouseEvent.SHIFT_MASK) == 0 )
			)
			{

				mPressedPoint.setLocation(
					mPressedPoint.getX() + diffX,
					mPressedPoint.getY() + diffY
				);

				// Shiftキーが押されていないので縦横比は可変
				sizeNewX = sizeOldX + diffX;
				sizeNewYRight = sizeOldYRight + diffY;

				w = sizeNewX;
				hr = sizeNewYRight;

			}
/*			else if(
				( mMouseLocation == SOUTH_EAST )
				&& ( (e.getModifiers()&MouseEvent.SHIFT_MASK) != 0 )
			)
			{

				mPressedPoint.setLocation(
					mPressedPoint.getX() + diffX,
					mPressedPoint.getY()
				);

				// Shiftキーが押されているので縦横比は不変
				sizeNewX = sizeOldX + diffX/this.mMagnification;
				sizeNewYLeft = sizeNewX*( sizeOldYLeft/sizeOldX );

				w = sizeNewX;
				hl = sizeNewYLeft;

			}
*/


			// 幅が狭くなりすぎたらreturn
			if( w < mMinWidth )
			{
System.out.println("w < mMinWidth");
				return true;
			}
			if( hl < mMinHeight )
			{
System.out.println("hl < mMinHeight");
				return true;
			}
			if( hr < mMinHeight )
			{
System.out.println("hr < mMinHeight");
				return true;
			}


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


			// 更新
/*
			this.mXDragging = x;
			this.mYDragging = y;
			this.mWidthDragging = w;
			this.mLeftHeightDragging = hl;
			this.mRightHeightDragging = hr;
*/

			mTempSymbol.setLocation( x, y );
			mTempSymbol.setSize( w, hl, hr );


			// repaint
			repaint();


			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 addPropertiesHistory()
		{
			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()
		{
//System.out.println("<< SigDiffSymbol : updateHistory >>");

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


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


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

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

			return true;
		}



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



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



	}





	/**
	 * 
	 */
	public static class SigDiffProperties extends SGProperties
	{
		
		float x;
		float y;
		float width;
		float leftHeight;
		float rightHeight;
		float space;
		float lineWidth;
		String text;
		String fontFamilyName;
		float fontSize;
		int fontStyle;
		ArrayList colorList = new ArrayList();


		public SigDiffProperties()
		{
			super();
		}


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

			SigDiffProperties p = (SigDiffProperties)obj;

			if( p.x != this.x ) return false;
			if( p.y != this.y ) return false;
			if( p.width != this.width ) return false;
			if( p.leftHeight != this.leftHeight ) return false;
			if( p.rightHeight != this.rightHeight ) return false;
			if( p.space != this.space ) return false;
			if( p.lineWidth != this.lineWidth ) return false;
			if( p.text.equals(this.text) == false ) return false;
			if( p.fontFamilyName.equals(this.fontFamilyName) == false ) return false;
			if( p.fontSize != this.fontSize ) return false;
			if( p.fontStyle != this.fontStyle ) return false;
			if( p.colorList.equals(this.colorList) == false ) return false;

			return true;
		}

	}






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



}

