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

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.font.FontRenderContext;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.TreeMap;

import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;

import jp.riken.brain.ni.samuraigraph.base.SGAxis;
import jp.riken.brain.ni.samuraigraph.base.SGData;
import jp.riken.brain.ni.samuraigraph.base.SGDefaultValues;
import jp.riken.brain.ni.samuraigraph.base.SGDrawingElement;
import jp.riken.brain.ni.samuraigraph.base.SGIAxisBreakElement;
import jp.riken.brain.ni.samuraigraph.base.SGIAxisElement;
import jp.riken.brain.ni.samuraigraph.base.SGIConstants;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElement;
import jp.riken.brain.ni.samuraigraph.base.SGIGraphElement;
import jp.riken.brain.ni.samuraigraph.base.SGIGridElement;
import jp.riken.brain.ni.samuraigraph.base.SGILegendElement;
import jp.riken.brain.ni.samuraigraph.base.SGIMovable;
import jp.riken.brain.ni.samuraigraph.base.SGISelectable;
import jp.riken.brain.ni.samuraigraph.base.SGISignificantDifferenceElement;
import jp.riken.brain.ni.samuraigraph.base.SGIStringElement;
import jp.riken.brain.ni.samuraigraph.base.SGITimingLineElement;
import jp.riken.brain.ni.samuraigraph.base.SGIUndoable;
import jp.riken.brain.ni.samuraigraph.base.SGProperties;
import jp.riken.brain.ni.samuraigraph.base.SGPropertyDialog;
import jp.riken.brain.ni.samuraigraph.base.SGTuple2f;
import jp.riken.brain.ni.samuraigraph.base.SGUtility;
import jp.riken.brain.ni.samuraigraph.base.SGUtilityNumber;
import jp.riken.brain.ni.samuraigraph.base.SGUtilityText;
import jp.riken.brain.ni.samuraigraph.data.SGSXYData;
import jp.riken.brain.ni.samuraigraph.data.SGSXYMultipleData;
import jp.riken.brain.ni.samuraigraph.data.SGVXYData;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementArrow;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementBar;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementLine;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementRectangle;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementSymbol;
import jp.riken.brain.ni.samuraigraph.figure.SGFigureElement;
import jp.riken.brain.ni.samuraigraph.figure.SGIStringConstants;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;



/**
 * レジェンドクラス
 */

public class SGLegendElement extends SGFigureElement
	implements SGILegendElement, SGIStringConstants,
		CaretListener, WindowListener, ActionListener,
		SGIMovable, SGISelectable
{

	/**
	 *
	 */
	private SGIGraphElement mGraphElement = null;

	
	/**
	 * 
	 */
	private SGIAxisElement mAxisElement = null;
	

	/**
	 * 
	 */
	private ArrayList mLegendList = new ArrayList();


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

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

	

	/**
	 * 倍率100%の状態での、レジェンドのＸ座標値
	 * グラフ描画領域の原点からの相対的位置
	 */
	private float mLegendX = 0.0f;
	
	
	/**
	 * 倍率100%の状態での、レジェンドのＹ座標値
	 * グラフ描画領域の原点からの相対的位置
	 */
	private float mLegendY = 0.0f;


	/**
	 * 倍率100%の状態での、レジェンドの横幅
	 */
	private float mLegendWidth = 0.0f;


	/**
	 * 倍率100%の状態での、レジェンドの縦幅
	 */
	private float mLegendHeight = 0.0f;


	/**
	 * 
	 */
	private float mFontSize;


	/**
	 * 
	 */
	private int mFontStyle;


	/**
	 * 
	 */
	private String mFontName;


	/**
	 * 
	 */
	private Color mStringColor;


	/**
	 * 
	 */
	private static final float MIN_WIDTH_DATA_ELEMENT
		= 2.5f/SGIConstants.CM_POINT_RATIO;


	/**
	 * 
	 */
	private float mFrameLineWidth;


	/**
	 * 
	 */
	private Color mFrameLineColor;


	/**
	 * 
	 */
	private Color mBackgroundColor;



	/**
	 *
	 */
	private boolean mLegendVisibleFlag = true;


	/**
	 * 
	 */
	private boolean mEnteredFlag = false;


	/**
	 * 
	 */
	private boolean mFrameVisibleFlag = true;


	/**
	 * 
	 */
	private boolean mLegendTransparentFlag = true;


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


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


	/**
	 * A dialog to set properties of legend.
	 */
	private SGLegendDialog mLegendDialog;


	/**
	 * A dialog to set properties of data.
	 */
	private SGPropertyDialogSXYData mSXYDataDialog;
	private SGPropertyDialogVXYData mVXYDataDialog;


	/**
	 * 
	 */
	private JTextField mEditField = new JTextField();


	/**
	 * 
	 */
	public static final String MENUCMD_HIDE = "Hide";


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

		if( this.init() == false )
		{
			throw new Error();
		}
	}



	/**
	 * 
	 */
	private boolean init()
	{
		this.setLegendVisible( SGDefaultValues.LEGEND_VISIBLE );
		this.setFontName( SGDefaultValues.LEGEND_FONT_NAME );
		this.setFontSize( SGDefaultValues.LEGEND_FONT_SIZE );
		final int style = SGUtilityText.getFontStyle( SGDefaultValues.LEGEND_FONT_STYLE );
		if( style==-1 )
		{
			return false;
		}
		this.setFontStyle( style );
		this.setStringColor( SGDefaultValues.LEGEND_STRING_COLOR );
		this.setFrameVisible( SGDefaultValues.LEGEND_FRAME_VISIBLE );
		this.setFrameLineWidth( SGDefaultValues.LEGEND_FRAME_WIDTH );
		this.setFrameLineColor( SGDefaultValues.LEGEND_FRAME_COLOR );
		this.setBackgroundColor( SGDefaultValues.LEGEND_BACKGROUND_COLOR );
		this.setLegendTransparent( SGDefaultValues.LEGEND_TRANSPARENT );

		//
		this.createPopupMenu();

		return true;
	}



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

		p.add( new JLabel( "  -- Legend --" ) );
		p.addSeparator();

		SGUtility.addItem( p, this, MENUCMD_HIDE );

		p.addSeparator();

		SGUtility.addItem( p, this, MENUCMD_PROPERTY );

		return true;
	}



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


	/**
	 *
	 */
	public boolean addData( final SGData data, final String name )
	{

		if( mGraphElement==null || data==null )
		{
			throw new Error("mGraphElement==null || data==null");
		}

		super.addData( data, name );


		//
		// レジェンドの要素を新規作成
		//

		ElementGroupSetInLegend legend = this.createLegendElement( data, name );
		if( legend == null )
		{
			return false;
		}


		// 倍率
		legend.setMagnification( this.mMagnification );


		// LegendDataをリストに追加
		this.mLegendList.add( legend );


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


		// on the start-up, set the location of the legend
		// to the north-east point of the graph area
		if( this.mStartFlag )
		{
			final float x = this.getGraphRectX()
				+ this.getGraphRectWidth() - this.mMagnification*this.getLegendWidth();
			final float y = this.getGraphRectY();
			this.setLegendLocation( x, y );
			this.mStartFlag = false;
		}

		
		// set axes
		{
			SGAxis xAxis = mAxisElement.getAxis( SGDefaultValues.LEGEND_HORIZONTAL_AXIS );
			SGAxis yAxis = mAxisElement.getAxis( SGDefaultValues.LEGEND_PERPENDICULAR_AXIS );
			this.mXAxis = xAxis;
			this.mYAxis = yAxis;
		}


		// create a property dialog for data
		this.createDataDialog( data );

		return true;
	}



	/**
	 *
	 */
	public boolean addData(
		final SGData data, final String name, final SGProperties p )
	{

		if( mGraphElement==null || data==null )
		{
			throw new Error("mGraphElement==null || data==null");
		}

		super.addData( data, name );


		//
		// レジェンドの要素を新規作成
		//

		ElementGroupSetInLegend legend = this.createLegendElement( data, name );
		if( legend == null )
		{
			return false;
		}


		// 倍率
		legend.setMagnification( this.mMagnification );


		// LegendDataをリストに追加
		this.mLegendList.add( legend );


		if( legend.setWholeProperties(p) == false )
		{
			throw new Error();
		}


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


		// on the start-up, set the location of the legend
		// to the north-east point of the graph area
		if( this.mStartFlag )
		{
			final float x = this.getGraphRectX()
				+ this.getGraphRectWidth() - this.mMagnification*this.getLegendWidth();
			final float y = this.getGraphRectY();
			this.setLegendLocation( x, y );
			this.mStartFlag = false;
		}

		
		// set axes
		{
			SGAxis xAxis = mAxisElement.getAxis( SGDefaultValues.LEGEND_HORIZONTAL_AXIS );
			SGAxis yAxis = mAxisElement.getAxis( SGDefaultValues.LEGEND_PERPENDICULAR_AXIS );
			this.mXAxis = xAxis;
			this.mYAxis = yAxis;
		}


		// create a property dialog for data
		this.createDataDialog( data );


		return true;
	}



	private void createDataDialog( SGData data )
	{
		if( data instanceof SGSXYData | data instanceof SGSXYMultipleData )
		{
			if( this.mSXYDataDialog == null )
			{
				this.mSXYDataDialog = new SGPropertyDialogSXYData( this.mDialogOwner, true );
			}
		}
		else if( data instanceof SGVXYData )
		{
			if( this.mVXYDataDialog == null )
			{
//				this.mVXYDataDialog = new SGPropertyDialogVXYData( this.mDialogOwner, true );
			}
		}
	}


	private SGPropertyDialog showDataDialog( ElementGroupSetInLegend legend )
	{
		SGPropertyDialog dg = null;
		if( legend instanceof ElementGroupSetInLegendSXY )
		{
			dg = this.mSXYDataDialog;


			// 色設定ボタン
			dg.setColorButtonBorder(true);


			// set the location
			dg.setLocation( this.mDialogOwner.getLocation() );

		}
//		else if( legend instanceof ElementGroupSetInLegendVXY )
//		{
//			dg = this.mVXYDataDialog;
//		}


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


		//
		dg.addPropertySettingListener(legend);


		// ダイアログに設定
		dg.setDialogProperty();

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

		// create temporary objects
		legend.createTemporaryPropertyObject();

		// show the dialog
		dg.setVisible(true);

		dg.removeAllPropertySettingListeners();


		return dg;
	}

	

	// used only on the start-up
	private boolean mStartFlag = true;
	


	/**
	 * 
	 */
	private ElementGroupSetInLegend createLegendElement( final SGData data, final String name )
	{

		ElementGroupSetInLegend legend = null;
		if( ( data instanceof SGSXYData )
			|| ( data instanceof SGSXYMultipleData ) )
		{
			legend = new ElementGroupSetInLegendSXY();
		}
//		else if( data instanceof SGVXYData )
//		{
//			legend = new ElementGroupSetInLegendVXY();
//		}
		else
		{
			return null;
		}


		// name of data
//		String name = mGraphElement.getDataName(data);
		legend.setName( name );


		// drawing elements
		ArrayList elementList = mGraphElement.getDrawingElementList(data);
		if( ( data instanceof SGSXYData )
			|| ( data instanceof SGSXYMultipleData ) )
		{
			for( int ii=0; ii<elementList.size(); ii++ )
			{
				SGDrawingElement element = (SGDrawingElement)elementList.get(ii);

				if( element instanceof SGDrawingElementLine )
				{
					legend.addDrawingElementGroup( SGElementGroup.POLYLINE_GROUP );
				}
				else if( element instanceof SGDrawingElementRectangle )
				{
					legend.addDrawingElementGroup( SGElementGroup.RECTANGLE_GROUP );
				}
				else if( element instanceof SGDrawingElementSymbol )
				{
					legend.addDrawingElementGroup( SGElementGroup.SYMBOL_GROUP );
				}
				else
				{
					throw new Error();
				}
			}
		}
		else if( data instanceof SGVXYData )
		{
			for( int ii=0; ii<elementList.size(); ii++ )
			{
				SGDrawingElement element = (SGDrawingElement)elementList.get(ii);

				if( element instanceof SGDrawingElementArrow )
				{
					legend.addDrawingElementGroup( SGElementGroup.ARROW_GROUP );
				}
				else
				{
					throw new Error();
				}
			}
		}
		else
		{
			throw new Error("This data-type is not defined.");
		}


		// visible flag
		ArrayList visibleFlagList = this.mGraphElement.getVisibleFlagList(data);
		ArrayList groupList = legend.mDrawingElementGroupList;
		if( visibleFlagList.size()!=groupList.size() )
		{
			throw new Error();
		}
		for( int ii=0; ii<groupList.size(); ii++ )
		{
			SGElementGroup group = (SGElementGroup)groupList.get(ii);
			boolean b = ((Boolean)visibleFlagList.get(ii)).booleanValue();
			group.setVisible(b);
		}


		// visible in legend
		boolean visibleInLegend = this.mGraphElement.getVisibleInLegendFlag( data );
		legend.setVisibleInLegend( visibleInLegend );


		legend.initPropertiesHistory();

		return legend;

	}



	/**
	 * 
	 */
	public ArrayList getDrawingElementList( final SGData data )
	{
		return getLegendData(data).getDrawingElementList();
	}



	/**
	 * 
	 */
	public boolean getFocusedObjectsList( ArrayList list )
	{
		if( this.isSelected() )
		{
			list.add( this );
		}
		return true;
	}


	/**
	 * 
	 *
	 */
	public boolean hideSelectedObject( SGISelectable s )
	{
		return true;
	}


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

		return null;
	}


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


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

		return null;
	}



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

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

		ArrayList list = new ArrayList();

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

		return list;
	}


	/**
	 * 
	 */
	private boolean mSelectedFlag = false;
	
	/**
	 * 
	 */
	public void setSelected( final boolean b )
	{
		this.mSelectedFlag = b;
	}
	

	/**
	 * 
	 */
	public boolean isSelected()
	{
		return this.mSelectedFlag;
	}

	
	/**
	 * フィギュア内でのＸ座標を返す
	 */
	public float getLegendX()
	{
		return this.mGraphRectX + this.mLegendX*this.mMagnification;
	}



	/**
	 * フィギュア内でのＹ座標を返す
	 */
	public float getLegendY()
	{
		return this.mGraphRectY + this.mLegendY*this.mMagnification;
	}


	/**
	 * 
	 */
	public float getLegendWidth()
	{
		return this.mLegendWidth;
	}


	/**
	 * 
	 */
	public float getLegendHeight()
	{
		return this.mLegendHeight;
	}



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



	/**
	 * 引数は任意の倍率における、フィギュア内における位置
	 */
	public boolean setLegendLocation( float x, float y )
	{
		this.mLegendX = ( x - this.mGraphRectX )/this.mMagnification;
		this.mLegendY = ( y - this.mGraphRectY )/this.mMagnification;
		return true;
	}

	
	
	/**
	 * 
	 */
	public void translate( final int dx, final int dy )
	{
		this.setLegendLocation(
			this.getLegendX() + dx, this.getLegendY() + dy );
		this.createAllDrawingElements();
	}


	/**
	 * 
	 * @return
	 */
	private double getXValue()
	{
		SGAxis axis = this.mXAxis;
		double value = calcValue( this.getLegendX(), axis, true );
		value = getNumberInRangeOrder( value, axis );
		return value;
	}

	
	/**
	 * 
	 * @return
	 */
	private double getYValue()
	{
		SGAxis axis = this.mYAxis;
		double value = calcValue( this.getLegendY(), axis, false );
		value = getNumberInRangeOrder( value, axis );
		return value;
	}


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

		return true;
	}



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

		if( this.mEditField.isVisible() )
		{
			this.terminateEditField();
		}
		this.clearFocusedGroup();

		return true;
	}




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



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

		// 色設定ボタン
		this.mLegendDialog.setColorButtonBorder(true);


		// set the location
		this.mLegendDialog.setLocation( this.mDialogOwner.getLocation() );


		// ダイアログに設定
		this.setDialogProperty();


		// テンポラリオブジェクトを作成
		this.mTemporaryProperties = this.getProperties();


		return this.mLegendDialog;

	}



	/**
	 * 
	 */
	private boolean createDialog()
	{

		SGLegendDialog dg = new SGLegendDialog( this.mDialogOwner, true );

		dg.setActionListener(this);


		//
		// add an WindowListener
		//
		
		dg.addWindowListener( this );


		this.mLegendDialog = dg;

		return true;
	}



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

		SGLegendDialog dg = this.mLegendDialog;
		
		
		// location
		double xValue = calcValue( this.getLegendX(), this.mXAxis, true );
		double yValue = calcValue( this.getLegendY(), this.mYAxis, false );
		xValue = getNumberInRangeOrder( xValue, this.mXAxis );
		yValue = getNumberInRangeOrder( yValue, this.mYAxis );
		dg.setXValue( new Double( xValue ) );
		dg.setYValue( new Double( yValue ) );

		
		//
		dg.setLegendVisible( this.mLegendVisibleFlag );

		//
		dg.setFrameVisible( this.mFrameVisibleFlag );
		dg.setFrameLineWidth( this.mFrameLineWidth );
		dg.setFrameLineColor( this.mFrameLineColor );


		//
		dg.setFontName( this.mFontName );
		dg.setFontSize( this.mFontSize );
		dg.setFontStyle( this.mFontStyle );
		dg.setTextColor( this.mStringColor );


		//
		dg.setBackgroundColor( this.mBackgroundColor );
		dg.setLegendTransparent( this.mLegendTransparentFlag );

		
		//
		this.setDialogPropertyOfAxis();
		
		return true;

	}


	
	/**
	 * 
	 */
	private boolean setDialogPropertyOfAxis()
	{
		SGLegendDialog dg = this.mLegendDialog;

		final int configX = mAxisElement.getConfigurationInPlane( this.mXAxis );
		final int configY = mAxisElement.getConfigurationInPlane( this.mYAxis );
		boolean flag = dg.setAxisRadioButton( configX, configY );
		if( !flag )
		{
			return false;
		}
		return true;
	}


	
	/**
	 * 
	 */
	private LegendCommonProperties getCommonPropertiesFromDialog()
	{

		SGLegendDialog dg = this.mLegendDialog;

		LegendCommonProperties p = dg.getCommonProperties();
		if( p==null )
		{
			return null;
		}
		
		return p;
	}

	

	/**
	 * 
	 */
	protected SGProperties getCommonProperties()
	{
		LegendCommonProperties p = new LegendCommonProperties();

		p.x = this.mLegendX;
		p.y = this.mLegendY;

		p.visible = this.isLegendVisible();
		p.frameLineVisible = this.isFrameLineVisible();
		p.frameLineWidth = this.getFrameLineWidth();
		p.frameLineColor = this.getFrameLineColor();
		p.backgroundColor = this.getBackgroundColor();
		p.transparent = this.isLegendTransparent();
		p.fontName = this.getFontName();
		p.fontSize = this.getFontSize();
		p.fontStyle = this.getFontStyle();
		p.stringColor = this.getStringColor();

		p.xAxis = this.mXAxis;
		p.yAxis = this.mYAxis;
		
		return p;
	}


	/**
	 * 
	 */
	public SGProperties getDataProperties( SGData data )
	{
		final ElementGroupSetInLegend groupSet
			= this.getElementGroupSet(data);
		if( groupSet != null )
		{
			return groupSet.getWholeProperties();
		}
		return null;
	}

	/**
	 * 
	 */
	protected TreeMap getDataPropertiesMap()
	{
		TreeMap map = new TreeMap();
		for( int ii=0; ii<this.mLegendList.size(); ii++ )
		{
			ElementGroupSetInLegend groupSet
				= (ElementGroupSetInLegend)this.mLegendList.get(ii);
			SGProperties p = groupSet.getProperties();
			SGData data = this.getData( groupSet );
			map.put( new Integer(data.hashCode()), p );
		}
		return map;
	}
	


	/**
	 * 
	 */
	public SGProperties getProperties()
	{
		LegendCommonProperties wp = new LegendCommonProperties();
		wp = (LegendCommonProperties)this.getCommonProperties();
		return wp;
	}



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

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

		LegendCommonProperties wp = (LegendCommonProperties)p;

		if( this.setCommonProperties( wp ) == false )
		{
			return false;
		}

		return true;
	}



	/**
	 * 
	 * @param hashCode
	 * @return
	 */
	protected SGData getData( final int hashCode )
	{
		for( int ii=0; ii<this.mDataList.size(); ii++ )
		{
			SGData data = (SGData)this.mDataList.get(ii);
			if( data.hashCode() == hashCode )
			{
				return data;
			}
		}
		return null;
	}



	/**
	 * 
	 */
	private boolean setCommonProperties( final LegendCommonProperties p )
	{

		this.mLegendX = p.x;
		this.mLegendY = p.y;

		this.setLegendVisible( p.visible );
		this.setFrameVisible( p.frameLineVisible );
		this.setFrameLineWidth( p.frameLineWidth );
		this.setFrameLineColor( p.frameLineColor );
		this.setBackgroundColor( p.backgroundColor );
		this.setLegendTransparent( p.transparent );
		this.setFontName( p.fontName );
		this.setFontSize( p.fontSize );
		this.setFontStyle( p.fontStyle );
		this.setStringColor( p.stringColor );

		this.mXAxis = p.xAxis;
		this.mYAxis = p.yAxis;
		
		return true;
	}



	/**
	 * 
	 */
	private boolean setPropertyWithDialog()
	{
		LegendCommonProperties p = this.getCommonPropertiesFromDialog();
		if( p==null )
		{
			return false;
		}

		
		
		SGLegendDialog dg = this.mLegendDialog;

		
		//
		// axes
		//

		final String xAxisLocation = dg.getXAxisLocation();
		final SGAxis xAxis = mAxisElement.getAxis( xAxisLocation );
		final String yAxisLocation = dg.getYAxisLocation();
		final SGAxis yAxis = mAxisElement.getAxis( yAxisLocation );
		p.xAxis = xAxis;
		p.yAxis = yAxis;

		
		
		//
		// location
		//

		// values from dialog
		Number xValueFromDialog_ = dg.getXValue();
		if( xValueFromDialog_==null )
		{
			SGUtility.showIllegalInputErrorMessageDialog( dg );
			return false;
		}
		Number yValueFromDialog_ = dg.getYValue();
		if( yValueFromDialog_==null )
		{
			SGUtility.showIllegalInputErrorMessageDialog( dg );
			return false;
		}
		final double xValueFromDialog = xValueFromDialog_.doubleValue();
		final double yValueFromDialog = yValueFromDialog_.doubleValue();
		
		
		// current values gotten from the position of legend
		double xValueCurrent = calcValue( this.getLegendX(), xAxis, true );
		double yValueCurrent = calcValue( this.getLegendY(), yAxis, false );
		xValueCurrent = getNumberInRangeOrder( xValueCurrent, xAxis );
		yValueCurrent = getNumberInRangeOrder( yValueCurrent, yAxis );


		// if values from the dialog is diffrent from the current values,
		// set the values from the dialog

		float x;
		if( xValueFromDialog==xValueCurrent )
		{
			x = this.mLegendX;
		}
		else
		{
			final float x_ = calcLocation( xValueFromDialog, xAxis, true );
			x = ( x_ - mGraphRectX )/this.mMagnification;
		}

		
		float y;
		if( yValueFromDialog==yValueCurrent )
		{
			y = this.mLegendY;
		}
		else
		{
			final float y_ = calcLocation( yValueFromDialog, yAxis, false );
			y = ( y_ - mGraphRectY )/this.mMagnification;
		}

		
		p.x = x;
		p.y = y;

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

		
		return true;
	}



	private static final float MARGIN_HORIZONTAL = 6.0f;
	private static final float MARGIN_VERTICAL = 4.0f;
	private final static float marginTop = MARGIN_VERTICAL;
	private final static float marginBottom = MARGIN_VERTICAL;
	private final static float marginLeft = MARGIN_HORIZONTAL;
	private final static float marginRight = MARGIN_HORIZONTAL;
	private final static float spaceDataAndString = MARGIN_HORIZONTAL;
	private final static float spaceLegend = MARGIN_VERTICAL;


	/**
	 * create all drawing elements
	 */
	private boolean createAllDrawingElements()
	{

		final float mag = this.mMagnification;

		// get visible legend array
		final ArrayList visibleGroupSetList = this.getVisibleTotallyLegendList();
		final int num = visibleGroupSetList.size();
		final ElementGroupSetInLegend[] legendArray = new ElementGroupSetInLegend[num];
		for( int ii=0; ii<num; ii++ )
		{
			legendArray[ii] = (ElementGroupSetInLegend)visibleGroupSetList.get(ii);
		}

		// create string elements
		for( int ii=0; ii<num; ii++ )
		{
			legendArray[ii].createStringElement();
		}

		// get the bounding box of string elements
		final Rectangle2D[] stringBoundsArray = new Rectangle2D[num];
		for( int ii=0; ii<num; ii++ )
		{
			stringBoundsArray[ii] = legendArray[ii].getStringBounds();
		}

		// get height of string elements
		final float[] stringHeightArray = new float[num];
		for( int ii=0; ii<num; ii++ )
		{
			stringHeightArray[ii] = (float)stringBoundsArray[ii].getHeight();
		}

		// max width of string elements
		float stringWidthMax = 0.0f;
		for( int ii=0; ii<num; ii++ )
		{
			float width = (float)stringBoundsArray[ii].getWidth();
			if( width > stringWidthMax )
			{
				stringWidthMax = width;
			}
		}

		// max width of drawing elements
		float dataWidthMax = MIN_WIDTH_DATA_ELEMENT;
		for( int ii=0; ii<num; ii++ )
		{
			final float width = legendArray[ii].getMaxDataElementWidth()/mag;
			if( width > dataWidthMax )
			{
				dataWidthMax = width;
			}
		}


		// legend width in the default zoom
		final float legendWidth
			= dataWidthMax + stringWidthMax/mag + spaceDataAndString;


		// height array of drawing elements
		final double[] dataHeightArray = new double[num];
		for( int ii=0; ii<num; ii++ )
		{
			dataHeightArray[ii] = legendArray[ii].getMaxDataElementHeight();
		}


		// total height array
		float[] legendHeightArray = new float[num];
		for( int ii=0; ii<num; ii++ )
		{
			legendHeightArray[ii]
				= (float)Math.max( dataHeightArray[ii], stringHeightArray[ii] );
		}


		// rectangle array of legend
		Rectangle2D[] legendRectArray = new Rectangle2D[num];
		float rectY = this.getLegendY() + mag*marginTop;
		final float lx = this.getLegendX() + mag*marginLeft;
		final float lw = mag*legendWidth;
		for( int ii=0; ii<num; ii++ )
		{
			final float ly = rectY;
			final float lh = legendHeightArray[ii];
			legendRectArray[ii] = new Rectangle2D.Float(lx,ly,lw,lh);
			rectY += lh + mag*spaceLegend;
		}


		// set rectangle
		for( int ii=0; ii<num; ii++ )
		{
			legendArray[ii].setRect( legendRectArray[ii] );
		}


		// legend height in the default zoom
		float legendHeight = 0.0f;
		for( int ii=0; ii<num; ii++ )
		{
			legendHeight += legendHeightArray[ii]/mag;
		}
		legendHeight += (num-1)*spaceLegend;


		// create drawing elements of each object
		for( int ii=0; ii<num; ii++ )
		{
			legendArray[ii].createDrawingElement();
		}


		// set location of string elements
		final float sx
			= this.getLegendX() + mag*( marginLeft + dataWidthMax + spaceDataAndString );
		for( int ii=0; ii<num; ii++ )
		{
			final float sy = (float)legendRectArray[ii].getY()
				+ 0.50f*(float)legendRectArray[ii].getHeight()
				- 0.50f*stringHeightArray[ii];
			legendArray[ii].getStringElement().setLocation( sx, sy );
		}


		// set to attributes
		this.mLegendWidth = marginLeft + legendWidth + marginRight;
		this.mLegendHeight = marginTop + legendHeight + marginBottom;


		return true;
	}




	/**
	 * 
	 */
	public boolean setGraphRect(
		final float x, final float y, final float width, final float height )
	{
		super.setGraphRect(x,y,width,height);

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

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

		return true;
	}




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

		if( this.mLegendVisibleFlag || this.mEnteredFlag )
		{

			// 背景の塗りつぶし
			if( this.mLegendTransparentFlag == false )
			{
				Rectangle2D rect = this.getLegendRect();
				g2d.setPaint( this.getBackgroundColor() );
				g2d.fill(rect);
			}


			// グラフの描画
			ArrayList list = this.getVisibleTotallyLegendList();
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupSetInLegend groupSet
					= (ElementGroupSetInLegend)list.get(ii);
				groupSet.paintGraphics2D( g2d );
			}


			// フレームを描画する
			if( this.mFrameVisibleFlag & list.size()!=0 )
			{
				this.drawLegendFrameLines(g2d);
			}

			// draw symbols around all objects
			if( this.mSymbolsVisibleFlagAroundAllObjects & list.size()!=0 )
			{
				ArrayList pList = this.getAnchorPointList();
				SGUtilityForFigureElement.drawAnchorAsChildObject( pList, g2d );
			}

			
			// draw symbols around focused objects
			if( this.mSymbolsVisibleFlagAroundFocusedObjects & this.isSelected() )
			{
				ArrayList pList = this.getAnchorPointList();
				SGUtilityForFigureElement.drawAnchorAsFocusedObject( pList, g2d );
			}

		}

	}


	/**
	 *
	 *
	 */
	private void updateSymbolsVisibleAroundFocusedObjects()
	{
		ArrayList list = this.getVisibleTotallyLegendList();
		this.setSymbolsVisibleAroundFocusedObjects( list.size()!=0 );
	}



	private ArrayList getAnchorPointList()
	{
		ArrayList list = new ArrayList();
		
		Rectangle2D rect = this.getLegendRect();
		final float x = (float)rect.getX();
		final float y = (float)rect.getY();
		final float w = (float)rect.getWidth();
		final float h = (float)rect.getHeight();
			
		Point2D nw = new Point2D.Float(x,y);
		Point2D sw = new Point2D.Float(x,y+h);
		Point2D ne = new Point2D.Float(x+w,y);
		Point2D se = new Point2D.Float(x+w,y+h);

		list.add( nw );
		list.add( sw );
		list.add( ne );
		list.add( se );
		
		return list;
	}



	/**
	 * 
	 * @param g2d
	 */
	private void drawLegendFrameLines( final Graphics2D g2d )
	{

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

		g2d.setPaint( this.mFrameLineColor );

		g2d.setStroke(
			new BasicStroke
			(
				this.mMagnification*this.mFrameLineWidth,
				BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER
			)
		);

		g2d.draw( this.getLegendRect() );


		if( false )
		{
			ArrayList gList = this.getVisibleTotallyLegendList();
			for( int ii=0; ii<gList.size(); ii++ )
			{
				ElementGroupSetInLegend el = (ElementGroupSetInLegend)gList.get(ii);
				g2d.setPaint( Color.red );
				g2d.draw(el.getRect());

				g2d.setPaint( Color.BLUE );
				g2d.draw(el.getStringBounds());
			}
		}

	}



	/**
	 * 
	 */
	public boolean contains( final int x, final int y )
	{
		Rectangle2D rect = new Rectangle2D.Float(
			this.getLegendX(),
			this.getLegendY(),
			mLegendWidth,
			mLegendHeight );
		return rect.contains(x,y);
	}



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

		for( int ii=this.mDataList.size()-1; ii>=0; ii-- )
		{
			SGData data_ = (SGData)mDataList.get(ii);
			if( data_.equals(data) )
			{
				this.mDataList.remove(ii);
				this.mLegendList.remove(ii);
			}
		}

		return true;
	}


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

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

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

		return true;
	}


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

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

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

		return true;
	}


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

		return false;
	}



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

		boolean flag = true;
		if( element instanceof SGIAxisElement )
		{

		}
		else if( element instanceof SGIGraphElement )
		{
//System.out.println("SGIGraphElement");

			SGIGraphElement gElement = (SGIGraphElement)element;
			flag = this.synchronizeToGraphElement( gElement );

		}
		else if( element instanceof SGIStringElement )
		{
			
		}
		else if( element instanceof SGILegendElement )
		{
			
		}
		else if( element instanceof SGIAxisBreakElement )
		{
			
		}
		else if( element instanceof SGISignificantDifferenceElement )
		{
			
		}
		else if( element instanceof SGITimingLineElement )
		{
			
		}
		else if( element instanceof SGIGridElement )
		{

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


		return flag;
	}



	/**
	 * 
	 */
	private boolean synchronizeToGraphElement( final SGIGraphElement element )
	{

		// グラフからデータのリストを取得し、自分の持っているデータリストと
		// 描画要素リストをそれに合わせて並び替える

		ArrayList dataList = element.getDataList();
		if( dataList.size() != this.mDataList.size() )
		{
			throw new Error("dataList.size() != this.mDataList.size()");
		}
		ArrayList dataListNew = new ArrayList();
		ArrayList groupSetListNew = new ArrayList();
		for( int ii=0; ii<dataList.size(); ii++ )
		{
			SGData data = (SGData)dataList.get(ii);
			for( int jj=this.mDataList.size()-1; jj>=0; jj-- )
			{
				SGData data_ = (SGData)this.mDataList.get(jj);
				if( data.equals(data_) )
				{
					SGData dataRemoved = (SGData)this.mDataList.remove(jj);
					dataListNew.add(dataRemoved);
					SGElementGroupSet groupSetRemoved
						= (SGElementGroupSet)this.mLegendList.remove(jj);
					groupSetListNew.add(groupSetRemoved);
					break;
				}
			}
		}
		this.mDataList = dataListNew;
		this.mLegendList = groupSetListNew;
			


		// 描画要素のプロパティの同期を取る
		for( int ii=this.mDataList.size()-1; ii>=0; ii-- )
		{
			SGData data = (SGData)mDataList.get(ii);

			ElementGroupSetInLegend groupSet
				= (ElementGroupSetInLegend)this.mLegendList.get(ii);

			boolean diffFlag = false;

			// name of data
			String nameNew = element.getDataName(data);
			String nameOld = groupSet.getName();
			if( nameNew.equals( nameOld ) == false )
			{
				groupSet.setChanged(true);
			}
			groupSet.setName( nameNew );


			// visible
			boolean visibleFlag = element.isDataVisible(data);
			if( visibleFlag != groupSet.isVisible() )
			{
				this.setChanged(true);
			}
			groupSet.setVisible( visibleFlag );


			// drawing element of data
			ArrayList sList = element.getDrawingElementList(data);

			ArrayList elList = new ArrayList();
			for( int jj=sList.size()-1; jj>=0; jj-- )
			{
				SGDrawingElement el = (SGDrawingElement)sList.get(jj);
				ArrayList lList = groupSet.mDrawingElementGroupList;
				SGElementGroup group = (SGElementGroup)lList.remove(jj);
				SGDrawingElement elOld = group.getDrawingElement();
				SGProperties p = el.getProperties();
				SGProperties pOld = elOld.getProperties();
				if( p.equals(pOld) == false )
				{
					diffFlag = true;
				}
				elList.add(el);
			}
			for( int jj=elList.size()-1; jj>=0; jj-- )
			{
				SGDrawingElement el = (SGDrawingElement)elList.get(jj);
				groupSet.addDrawingElementGroup(el);
			}


			// visible in legend
			boolean visibleInLegend = element.getVisibleInLegendFlag( data );
			if( visibleInLegend != groupSet.isVisibleInLegend() )
			{
				diffFlag = true;
			}
			groupSet.setVisibleInLegend( visibleInLegend );


			// add to the group-set list
			mLegendList.set( ii, groupSet );


			if( diffFlag )
			{
				groupSet.setChanged(true);
			}

		}


		this.createAllDrawingElements();			
		this.updateSymbolsVisibleAroundFocusedObjects();


		return true;
	}




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



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

		this.createAllDrawingElements();

		return true;

	}



	/**
	 * ズーム
	 */
	public boolean zoom( final float ratio )
	{
		if( super.zoom(ratio) == false )
		{
			return false;
		}

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

		ArrayList list = this.getVisibleTotallyLegendList();
		for( int ii=0; ii<list.size(); ii++ )
		{
			ElementGroupSetInLegend lData
				= (ElementGroupSetInLegend)list.get(ii);
			lData.zoom(ratio);
		}


		// 描画要素を作成
		this.createAllDrawingElements();

		return true;
	}





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

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


		Rectangle2D graphRect = this.getGraphRect();
		Rectangle2D lRect = this.getLegendRect();
		if( lRect.getWidth() < Double.MIN_VALUE || lRect.getHeight() < Double.MIN_VALUE )
		{
			return true;
		}


		ArrayList list = new ArrayList();
		list.add( graphRect );
		if( this.isLegendVisible() )
		{
			list.add( lRect );
		}

		Rectangle2D uniRect = SGUtility.createUnion(list);

//System.out.println(graphRect);
//System.out.println(lRect);
//System.out.println(uniRect);		

		final float top = (float)( graphRect.getY() - uniRect.getY() );
		final float bottom = (float)( ( uniRect.getY() + uniRect.getHeight() )
			- ( graphRect.getY() + graphRect.getHeight() ) );
		final float left = (float)( graphRect.getX() - uniRect.getX() );
		final float right = (float)( ( uniRect.getX() + uniRect.getWidth() )
			- ( graphRect.getX() + graphRect.getWidth() ) );

		topAndBottom.x += top;
		topAndBottom.y += bottom;
		leftAndRight.x += left;
		leftAndRight.y += right;

//System.out.println(topAndBottom+"  "+leftAndRight);

//System.out.println();

		return true;
	}




	/**
	 * 
	 */
	public boolean onMouseClicked( final MouseEvent e )
	{

		// if the legend is invisible, return false
		if( !mLegendVisibleFlag )
		{
			return false;
		}

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

		ArrayList gList = this.getVisibleTotallyLegendList();
		for( int ii=0; ii<gList.size(); ii++ )
		{

			ElementGroupSetInLegend legend
				= (ElementGroupSetInLegend)gList.get(ii);

			Rectangle2D rect = legend.getRect();
			if( rect == null )
			{
				continue;
			}

			if( rect.contains(x,y) )
			{
				Rectangle2D sRect = legend.getStringBounds();
				if( SwingUtilities.isRightMouseButton(e) & cnt==1 )
				{
					this.updateFocusedObjectsList( this, e );
					this.mPopupMenu.show( this, x, y );
					return true;
				}


				if( sRect.contains(x,y) )
				{
					if( SwingUtilities.isLeftMouseButton(e) & cnt==1 )
					{
						if( this.isSelected() )
						{
							this.showEditField(legend);
						}
						else
						{
							this.updateFocusedObjectsList( this, e );
						}
					}
				}
				else
				{
					this.updateFocusedObjectsList( this, e );

//					ArrayList list = legend.mDrawingElementGroupList;
//					for( int jj=list.size()-1; jj>=0; jj-- )
//					{
//						SGElementGroup group = (SGElementGroup)list.get(jj);
//						if( group.isVisible() == false )
//						{
//							continue;
//						}
//
//						SGDrawingElement[] array = group.mDrawingElementArray;
//						for( int kk=0; kk<array.length; kk++ )
//						{
//							final boolean flag = array[kk].contains(x,y);
//							if( flag )
//							{
//								if( SwingUtilities.isRightMouseButton(e) & cnt==1 )
//								{
//
//								}
//								else if( SwingUtilities.isLeftMouseButton(e) & cnt==2 )
//								{
//									this.showDataDialog(legend);
//								}
//
//								return true;
//							}
//
//						}
//
//					}


					if( SwingUtilities.isLeftMouseButton(e) & cnt==2 )
					{
						this.getDialog().setVisible(true);
					}

				}

				return true;
			}
			
		}

		return false;	
	}



	/**
	 * 
	 */
	private ElementGroupSetInLegend mFocusedGroup = null;



	/**
	 * 
	 */
	public String getFontName()
	{
		return this.mFontName;
	}



	/**
	 * 
	 */
	public int getFontStyle()
	{
		return this.mFontStyle;
	}


	/**
	 * 
	 */
	public float getFontSize()
	{
		return this.mFontSize;
	}


	/**
	 * 
	 */
	public float getFrameLineWidth()
	{
		return this.mFrameLineWidth;
	}


	/**
	 * 
	 */
	public Color getFrameLineColor()
	{
		return this.mFrameLineColor;
	}


	/**
	 * 
	 */
	public Color getBackgroundColor()
	{
		return this.mBackgroundColor;
	}


	/**
	 * 
	 */
	public Color getStringColor()
	{
		return this.mStringColor;
	}


	/**
	 * 
	 */
	private boolean showEditField( ElementGroupSetInLegend legend )
	{
		this.mFocusedGroup = legend;
		JTextField tf = this.mEditField;

		final Rectangle2D rect = legend.getStringBounds();
		final float fontSize = this.getMagnification()*this.getFontSize();

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

		Font font = new Font( this.getFontName(), this.getFontStyle(), (int)(fontSize) );
		tf.setFont( font );
		tf.setForeground( this.mStringColor );
		tf.setText( legend.getName() );

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

		return true;
	}


	/**
	 * 
	 */
	private Point mLegendLocation = null;


	/**
	 * 
	 */
	private boolean isMoved()
	{
		final boolean bx = ( (int)this.mLegendX == (int)this.mLegendLocation.getX() );
		final boolean by = ( (int)this.mLegendY == (int)this.mLegendLocation.getY() );
		final boolean b = !( bx && by );
		return b;
	}



	/**
	 * 
	 */
	private boolean terminateEditField()
	{
		this.commitEdit();
		this.hideEditField();
		this.clearFocusedGroup();

		return true;
	}



	/**
	 * 
	 * @return
	 */
	private boolean commitEdit()
	{
		String str = this.mEditField.getText();

		// 文字列の長さが0の場合には設定しない
		if( str.length() == 0 )
		{
			return false;
		}

		// 文字列が空白だけの場合にも設定しない
		for( int ii=0; ii<str.length(); ii++ )
		{
			final char c = str.charAt(ii);
			if( c!=' ' && c!='　' )
			{
				break;
			}

			return false;
		}


		String before = this.mFocusedGroup.getName();
		String after = str;
		this.mFocusedGroup.setName( after );

		// draw back
//		this.drawBackLegend();

		//
		this.createAllDrawingElements();


		// update the history
		if( before.equals(after) == false )
		{
			if( this.mFocusedGroup.updateHistory() == false )
			{
				return false;
			}
			this.mFocusedGroup.setChanged( true );
		}

		notifyChange();


		this.notifyToRoot();


		return true;
	}



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



	/**
	 * 
	 * @return
	 */
	private boolean clearFocusedGroup()
	{
		this.mFocusedGroup = null;
		return true;
	}



	/**
	 * 
	 */
	private Point mPressedPoint = null;

	
	/**
	 * 
	 * @param e
	 */
	public boolean onMousePressed( final MouseEvent e )
	{
		if( !mLegendVisibleFlag )
		{
			return false;
		}

		if( this.mEditField.isVisible() )
		{
			this.terminateEditField();
		}

		Rectangle2D lRect = this.getLegendRect();
		if( lRect.contains( e.getX(), e.getY() ) )
		{
			this.mLegendLocation = new Point(
					(int)this.mLegendX,
					(int)this.mLegendY
				);
			this.mPressedPoint = e.getPoint();
			setMouseCursor( Cursor.MOVE_CURSOR );
			return true;
		}

		this.clearFocusedGroup();

		return false;
	}



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

		
		// レジェンドの位置設定
		if( this.isSelected() )
		{
			final int dx = e.getX() - this.mPressedPoint.x;
			final int dy = e.getY() - this.mPressedPoint.y;
			this.translate(dx,dy);
			this.mPressedPoint = e.getPoint();

			if( this.createAllDrawingElements() == false )
			{
				return false;
			}
		}
		
		return true;

	}



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

		//
		if( this.mLegendLocation!=null )
		{
			if( this.isMoved() )
			{
				this.mChangedFlag = true;
			}
		}


		Rectangle2D rect = this.getLegendRect();
		if( rect.contains( e.getPoint() ) )
		{
			setMouseCursor( Cursor.HAND_CURSOR );
		}
		else
		{
			setMouseCursor( Cursor.DEFAULT_CURSOR );
		}


		//
//		this.notifyToRoot();


		return true;
	}


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



	/**
	 * 
	 * @return
	 */
	public boolean setChangedFocusedObjects()
	{
		SGProperties temp = this.mTemporaryProperties;
		SGProperties p = this.getProperties();
		if( p.equals(temp)==false )
		{
			this.setChanged(true);
		}

		return true;
	}

	
	
	/**
	 * 
	 */
	public Rectangle2D getLegendRect()
	{
		final float mag = this.mMagnification;
		Rectangle2D rect = new Rectangle2D.Float(
			this.getLegendX(),
			this.getLegendY(),
			mag*this.mLegendWidth,
			mag*this.mLegendHeight
		);

		return rect;
	}



	/**
	 * 
	 */
	public boolean isResizable( final double w, final double h )
	{

		Rectangle2D rect = this.getLegendRect();

//System.out.println("  "+w+"  "+rect.getWidth());

		if( w<rect.getWidth() || h<rect.getHeight() )
		{
			return false;
		}
		else
		{
			return true;
		}

	}



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

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

		final Font font = new Font(
			this.getFontName(),
			this.getFontStyle(),
			(int)(this.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.getFontSize() ),
				this.mEditField.getHeight()
			);
		}
	
//		this.repaint();
	}



	/**
	 * 
	 * @param e
	 */
	public boolean onDrawingElement( final int x, final int y )
	{
		if( this.isLegendVisible() )
		{
			if( this.getLegendRect().contains(x,y) )
			{
				this.setMouseCursor( Cursor.HAND_CURSOR );
				return true;
			}
		}
		
		return false;
	}



	/**
	 * 
	 */
	public boolean setAxisElement( final SGIAxisElement element )
	{
		this.mAxisElement = element;
		return true;
	}
	
	
	
	/**
	 *
	 */
	public boolean setGraphElement( final SGIGraphElement element )
	{
		mGraphElement = element;
		return true;
	}



	/**
	 * 
	 */
	public boolean setLegendVisible( final boolean flag )
	{
		this.mLegendVisibleFlag = flag;
		return true;
	}


	/**
	 * 
	 * @param flag
	 * @return
	 */
	public boolean setLegendTransparent( final boolean flag )
	{
		this.mLegendTransparentFlag = flag;
		return true;
	}


	/**
	 * 
	 */
	public boolean setFrameVisible( final boolean flag )
	{
		this.mFrameVisibleFlag = flag;
		return true;
	}


	/**
	 * 
	 */
	public boolean setFrameLineWidth( final float width )
	{
		this.mFrameLineWidth = width;
		return true;
	}


	/**
	 * 
	 */
	public boolean setFrameLineColor( final Color cl )
	{
		this.mFrameLineColor = cl;
		return true;
	}


	/**
	 * 
	 */
	public boolean setBackgroundColor( final Color cl )
	{
		this.mBackgroundColor = cl;
		return true;
	}


	/**
	 * 
	 */
	public boolean setFontSize( final float size )
	{
		this.mFontSize = size;
		return true;
	}


	/**
	 * 
	 */
	public boolean setFontStyle( final int style )
	{
		this.mFontStyle = style;
		return true;
	}


	/**
	 * 
	 */
	public boolean setStringColor( final Color color )
	{
		this.mStringColor = color;
		return true;
	}


	/**
	 * 
	 */
	public boolean setFontName( final String name )
	{
		this.mFontName = name;
		return true;
	}


	/**
	 * 
	 */
//	public boolean setWidthOfDataElement( final float width )
//	{
//		this.mWidthOfDataElement = width;
//		return true;
//	}


	/**
	 * 
	 */
	private SGData getData( final ElementGroupSetInLegend groupSet )
	{
		ArrayList list = this.mLegendList;
		for( int ii=0; ii<list.size(); ii++ )
		{
			ElementGroupSetInLegend groupSet_
				= (ElementGroupSetInLegend)list.get(ii);
			if( groupSet_.equals(groupSet) )
			{
				SGData data = (SGData)this.mDataList.get(ii);			
				return data;
			}
		}

		return null;
	}



	/**
	 * 
	 */
	public boolean isLegendVisible()
	{
		return this.mLegendVisibleFlag;
	}


	/**
	 * 
	 */
	public boolean isFrameLineVisible()
	{
		return this.mFrameVisibleFlag;
	}


	/*:
	 * 
	 */
	public boolean isLegendTransparent()
	{
		return this.mLegendTransparentFlag;
	}



	/**
	 * 
	 */
	public Rectangle2D getRectOfGroup( final SGElementGroup group )
	{
		for( int ii=0; ii<this.mLegendList.size(); ii++ )
		{
			ElementGroupSetInLegend leg
				= (ElementGroupSetInLegend)this.mLegendList.get(ii);
			ArrayList groupList = leg.mDrawingElementGroupList;
			for( int jj=0; jj<groupList.size(); jj++ )
			{
				SGElementGroup group_ = (SGElementGroup)groupList.get(jj);
				if( group_.equals(group) )
				{
					return leg.mDataRect;
				}
			}

		}

		return null;
	}


	/**
	 * 
	 */
	public Rectangle2D getRectOfGroupSet( final SGElementGroupSet groupSet )
	{
		for( int ii=0; ii<this.mLegendList.size(); ii++ )
		{
			ElementGroupSetInLegend leg
				= (ElementGroupSetInLegend)this.mLegendList.get(ii);
			if( groupSet.equals(leg) )
			{
				return leg.mDataRect;
			}
		}

		return null;
	}



	/**
	 * 
	 */
	private ElementGroupLine getGroupLine( final ElementGroupSetInLegend groupSet )
	{

		ArrayList groupList = groupSet.mDrawingElementGroupList;
		for( int ii=0; ii<groupList.size(); ii++ )
		{
			SGElementGroup group = (SGElementGroup)groupList.get(ii);
			if( group instanceof ElementGroupLine )
			{
				return (ElementGroupLine)group;
			}
		}

		return null;
	}


	/**
	 * 
	 */
	private ElementGroupBar getGroupBar( final ElementGroupSetInLegend groupSet )
	{

		ArrayList groupList = groupSet.mDrawingElementGroupList;
		for( int ii=0; ii<groupList.size(); ii++ )
		{
			SGElementGroup group = (SGElementGroup)groupList.get(ii);
			if( group instanceof ElementGroupBar )
			{
				return (ElementGroupBar)group;
			}
		}

		return null;
	}


	/**
	 * 
	 */
	private ElementGroupSymbol getGroupSymbol( final ElementGroupSetInLegend groupSet )
	{

		ArrayList groupList = groupSet.mDrawingElementGroupList;
		for( int ii=0; ii<groupList.size(); ii++ )
		{
			SGElementGroup group = (SGElementGroup)groupList.get(ii);
			if( group instanceof ElementGroupSymbol )
			{
				return (ElementGroupSymbol)group;
			}
		}

		return null;
	}


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

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


		//
		// Pop-up menu
		//

		if( command.equals( MENUCMD_HIDE ) )
		{
			this.setLegendVisible( false );
			this.repaint();
			this.setChanged(true);
			this.notifyToRoot();
			return;
		}
		else if( command.equals( MENUCMD_PROPERTY ) )
		{
			this.getDialog().setVisible(true);
		}


		if( command.equals("OK")
		|| this.mLegendDialog.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()
	{

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

		
		// ダイアログを出す前後でプロパティが変更されている場合のみ、
		// 履歴を更新する
		SGProperties pTemp = this.mTemporaryProperties;
		SGProperties pPresent = this.getProperties();
		if( pTemp.equals(pPresent) == false )
		{
			this.mChangedFlag = true;
		}
		this.mTemporaryProperties = null;
		this.mLegendDialog.setVisible(false);

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

		
		// notify the change to the root
		this.notifyToRoot();


		return true;
	}




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

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

		super.addPropertiesHistory(p);

		return true;
	}


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

		this.mTemporaryProperties = null;
		this.mLegendDialog.setVisible(false);

		this.createAllDrawingElements();
		notifyChange();

		return true;
	}


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

		this.createAllDrawingElements();
		notifyChange();

		return true;
	}



	/**
	 * 
	 */
	public void windowActivated(final WindowEvent e)
	{
	}


	/**
	 * 
	 */
	public void windowDeactivated(final WindowEvent e)
	{
	}


	/**
	 * 
	 */
	public void windowIconified(final WindowEvent e)
	{
	}


	/**
	 * 
	 */
	public void windowDeiconified(final WindowEvent e)
	{
	}


	/**
	 * 
	 */
	public void windowOpened(final WindowEvent e)
	{
	}


	/**
	 * 
	 */
	public void windowClosed(final WindowEvent e)
	{
	}


	/**
	 * 
	 */
	public void windowClosing(final WindowEvent e)
	{
		Object obj = e.getSource();
		if( obj.equals( this.mLegendDialog ) )
		{
			this.onCanceled();
		}
	}



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


	
	/**
	 * 
	 */
	public boolean isChanged()
	{
		if( super.isChanged() )
		{
			return true;
		}
		ArrayList list = this.getVisibleLegendList();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGIUndoable el = (SGIUndoable)list.get(ii);
			if( el.isChanged() )
			{
				return true;
			}
		}
		return false;
	}


	/**
	 * 
	 */
	public boolean updateHistory()
	{
		ArrayList list = this.getVisibleLegendList();
		return this.updateHistory_(list);
	}



	/**
	 * Returns a list of visible group sets.
	 * @return a list of group sets
	 */
	protected ArrayList getVisibleLegendList()
	{
		ArrayList list = new ArrayList();
		ArrayList gList = this.mLegendList;
		for( int ii=0; ii<gList.size(); ii++ )
		{
			ElementGroupSetInLegend groupSet
				= (ElementGroupSetInLegend)gList.get(ii);
			if( groupSet.isVisible() )
			{
				list.add(groupSet);
			}
		}

		return list;
	}



	/**
	 * Returns a list of "totally" visible group sets.
	 * @return a list of group sets
	 */
	protected ArrayList getVisibleTotallyLegendList()
	{
		ArrayList list = new ArrayList();
		ArrayList gList = this.mLegendList;
		for( int ii=0; ii<gList.size(); ii++ )
		{
			ElementGroupSetInLegend groupSet
				= (ElementGroupSetInLegend)gList.get(ii);
			if( groupSet.isVisibleTotally() )
			{
				list.add(groupSet);
			}
		}

		return list;
	}



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

		return true;
	}


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

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

		return null;

	}



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

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

		return null;
	}



	/**
	 * 
	 */
	public boolean createDataObject( final Element el, final SGData data )
	{
		if( super.createDataObject( el, data ) == false )
		{
			return false;
		}


		// construct a SGElementGroupSet object
		ElementGroupSetInLegend groupSet = this.getGroupSetNewInstance(data);
		if( groupSet==null )
		{
			return false;
		}


		//
		this.mLegendList.add( groupSet );

		//
		int ret = this.setProperty( el, groupSet );
		if( ret==SGIConstants.PROPERTY_FILE_INCORRECT )
		{
			return false;
		}

		
		// create drawing elements
		this.createAllDrawingElements();

		
		// set false the flag
		this.mStartFlag = false;


		// create property dialogs for data
		this.createDataDialog(data);		


		return true;
	}


	
	/**
	 * 
	 */
	protected ElementGroupSetInLegend getGroupSetNewInstance( final SGData data )
	{
		ElementGroupSetInLegend groupSet = null;

		if( data instanceof SGSXYData || data instanceof SGSXYMultipleData )
		{
			groupSet = new ElementGroupSetInLegendSXY();
		}
//		else if( data instanceof SGVXYData )
//		{
//			groupSet = new ElementGroupSetInLegendVXY();
//		}

		return groupSet;
	}

	
	/**
	 * 
	 */
	private int setProperty(
		final Element el, final ElementGroupSetInLegend groupSet )
	{
		SGData data = this.getData(groupSet);
		int ret = SGIConstants.PROPERTY_FILE_INCORRECT;
		if( ( data instanceof SGSXYData ) || ( data instanceof SGSXYMultipleData ) )
		{
			ElementGroupSetInLegendSXY gs = (ElementGroupSetInLegendSXY)groupSet;
			ret = this.setPropertyOfElementGroupSetInLegendSXY(el,gs);
		}
		else if( data instanceof SGVXYData )
		{
			//
		}

		return ret;
	}

	
	
	/**
	 * 
	 */
	private int setPropertyOfElementGroupSetInLegendSXY(
		final Element el,
		final ElementGroupSetInLegendSXY groupSet )
	{

		final int ic = SGIConstants.PROPERTY_FILE_INCORRECT;
		String str = null;


		// name of data
		str = el.getAttribute( KEY_DATA_NAME );
		if( str.length()==0 )
		{
			return ic;
		}
		final String name = str;
		
		groupSet.setName(name);



		// visible in legend
		str = el.getAttribute( KEY_VISIBLE_IN_LEGEND );
		if( str.length()==0 )
		{
			return ic;
		}
		Boolean b = SGUtilityText.getBoolean(str);
		if( b==null )
		{
			return ic;
		}
		groupSet.setVisibleInLegend( b.booleanValue() );


		//
		// create drawing element groups
		//
		
		SGElementGroup group = null;
		NodeList nList = null;

		// line
		nList = el.getElementsByTagName( SGElementGroupLine.TAG_NAME_LINE );
		if( nList.getLength()!=1 )
		{
			return ic;
		}
		if( groupSet.addDrawingElementGroup( SGElementGroup.POLYLINE_GROUP ) == false )
		{
			return ic;
		}
		Element line = (Element)nList.item(0);
		group = (SGElementGroup)(groupSet.getLineGroups().get(0));
		if( group.readProperty(line) == false )
		{
			return ic;
		}
		
		
		// symbol
		nList = el.getElementsByTagName( SGElementGroupSymbol.TAG_NAME_SYMBOL );
		if( nList.getLength()!=1 )
		{
			return ic;
		}
		if( groupSet.addDrawingElementGroup( SGElementGroup.SYMBOL_GROUP ) == false )
		{
			return ic;
		}
		Element symbol = (Element)nList.item(0);
		group = (SGElementGroup)(groupSet.getSymbolGroups().get(0));
		if( group.readProperty(symbol) == false )
		{
			return ic;
		}

		
		// bar
		nList = el.getElementsByTagName( SGElementGroupBar.TAG_NAME_BAR );
		if( nList.getLength()!=1 )
		{
			return ic;
		}
		if( groupSet.addDrawingElementGroup( SGElementGroup.RECTANGLE_GROUP ) == false )
		{
			return ic;
		}
		Element bar = (Element)nList.item(0);
		group = (SGElementGroup)(groupSet.getBarGroups().get(0));
		if( group.readProperty(bar) == false )
		{
			return ic;
		}

/*
		// error bar
		nList = el.getElementsByTagName( SGElementGroupErrorBar.TAG_NAME_ERROR_BAR );
		if( nList.getLength()==1 )
		{
			Element errorBar = (Element)nList.item(0);

			// 読み込まれたデータがエラーバー情報を持っているとは限らない！
			// 持っている場合には以下の処理を行う
			if( data.isErrorValueHolding() )
			{
				ElementGroupErrorBar eGroup
					= this.createErrorBar( groupSet, data );

				if( eGroup.readProperty(errorBar)==false )
				{
					return ic;
				}

				if( eGroup.setPropertiesOfDrawingElements() == false )
				{
					return ic;
				}

				eGroup.setLocation(
					eGroup.mStartArray,
					eGroup.mEndArray );

			}
			else
			{
				ElementGroupErrorBar eGroup = new ElementGroupErrorBar();
				if( eGroup.readProperty(errorBar) == false )
				{
					return ic;
				}
			}
		
		}
		else if( nList.getLength()==0 )
		{
			// 読み込まれたデータがエラーバー情報を持っていないとは限らない！
			// 持っている場合には以下の処理を行う
			if( data.isErrorValueHolding() )
			{
				ElementGroupErrorBar eGroup = this.createErrorBar( groupSet, data );
				if( eGroup==null )
				{
					return ic;
				}
				if( eGroup.setPropertiesOfDrawingElements() == false )
				{
					return ic;
				}
			}
		}
		else
		{
			return ic;
		}
		
		
		// tick label
		nList = el.getElementsByTagName( SGElementGroupTickLabel.TAG_NAME_STRING );
		if( nList.getLength()==1 )
		{
			Element tickLabel = (Element)nList.item(0);

			// 読み込まれたデータがデータ文字列情報を持っているとは限らない！
			if( data.isStringArrayHolding() )
			{
				ElementGroupTickLabelStringElement tGroup
					= this.createTickLabels( groupSet, data );
				if( tGroup.readProperty(tickLabel) == false )
				{
					return ic;
				}

				if( tGroup.setPropertiesOfDrawingElements() == false )
				{
					return ic;
				}

				tGroup.setLocation( tGroup.mPointsArray );
			}
			else
			{
				ElementGroupTickLabelStringElement tGroup
					= new ElementGroupTickLabelStringElement();
				if( tGroup.readProperty(tickLabel) == false )
				{
					return ic;
				}
			}
			
		}
		else if( nList.getLength()==0 )
		{
			if( data.isStringArrayHolding() )
			{
				ElementGroupTickLabelStringElement tGroup
					= this.createTickLabels( groupSet, data );
				if( tGroup==null )
				{
					return ic;
				}
				if( tGroup.setPropertiesOfDrawingElements() == false )
				{
					return ic;
				}
			}
		}
		else
		{
			return ic;
		}
*/		
		
		
		//
		groupSet.initPropertiesHistory();

		
		return SGIConstants.SUCCESSFUL_COMPLETION;
	}


	


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

	
	/**
	 * 
	 */
	public boolean writeProperty( final Element el )
	{
		final String cm = SGUtilityNumber.cm;
		final String pt = SGUtilityNumber.pt;

		el.setAttribute( KEY_LEGEND_VISIBLE, Boolean.toString( this.mLegendVisibleFlag ) );

		el.setAttribute( KEY_X_AXIS_POSITION, mAxisElement.getAxisLocation( this.mXAxis ) );
		el.setAttribute( KEY_Y_AXIS_POSITION, mAxisElement.getAxisLocation( this.mYAxis ) );

		el.setAttribute( KEY_X_VALUE, Double.toString( this.getXValue() ) );
		el.setAttribute( KEY_Y_VALUE, Double.toString( this.getYValue() ) );

		
//		el.setAttribute( KEY_LEGEND_X, Float.toString( this.mLegendX*SGIConstants.CM_POINT_RATIO ) + cm );
//		el.setAttribute( KEY_LEGEND_Y, Float.toString( this.mLegendY*SGIConstants.CM_POINT_RATIO ) + cm );
		
		
		el.setAttribute( KEY_FRAME_VISIBLE, Boolean.toString( this.mFrameVisibleFlag ) );
		el.setAttribute( KEY_FRAME_LINE_WIDTH, Float.toString( this.mFrameLineWidth ) + pt );
		el.setAttribute( KEY_FRAME_LINE_COLOR, SGUtilityText.getColorString( this.mFrameLineColor ) );
		el.setAttribute( KEY_BACKGROUND_COLOR, SGUtilityText.getColorString( this.mBackgroundColor ) );
		el.setAttribute( KEY_BACKGROUND_TRANSPARENT, Boolean.toString( this.mLegendTransparentFlag ) );

		el.setAttribute( KEY_FONT_NAME, this.mFontName );
		el.setAttribute( KEY_FONT_SIZE, Float.toString( this.mFontSize ) + pt );
		el.setAttribute( KEY_FONT_STYLE, SGUtilityText.getFontStyleName( this.mFontStyle ) );
		el.setAttribute( KEY_STRING_COLORS, SGUtilityText.getColorString( this.mStringColor ) );

		return true;
	}
	
	
	/**
	 * 
	 */
	public Element createElement( final Document document )
	{
		return this.createThisElement( document );
	}

	
	
	/**
	 * 
	 */
	public boolean readProperty( final Element element )
	{
		String str;

		LegendCommonProperties wp = this.readProperty_( element );
		if( wp==null ) return false;
		
		if( this.setProperties(wp) == false ) return false;

		return true;
	}


	
	/**
	 * 
	 * @param el
	 * @return
	 */
	private LegendCommonProperties readProperty_( final Element el )
	{
		
		final String cm = SGUtilityNumber.cm;
		final String pt = SGUtilityNumber.pt;
		final float ratio = SGIConstants.CM_POINT_RATIO;

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

		
		// set legend visible
		str = el.getAttribute( SGLegendElement.KEY_LEGEND_VISIBLE );
		if( str.length()==0 )
		{
			return null;
		}
		b = SGUtilityText.getBoolean(str);
		if( b==null )
		{
			return null;
		}
		final boolean legendVisible = b.booleanValue();

		
		// set axes
		str = el.getAttribute( KEY_X_AXIS_POSITION );
		if( str.length()==0 )
		{
			return null;
		}
		SGAxis xAxis = mAxisElement.getAxis(str);
		
		str = el.getAttribute( KEY_Y_AXIS_POSITION );
		if( str.length()==0 )
		{
			return null;
		}
		SGAxis yAxis = mAxisElement.getAxis(str);


		str = el.getAttribute( KEY_X_VALUE );
		if( str.length()==0 )
		{
			return null;
		}
		num = SGUtilityText.getDouble(str);
		if( num==null )
		{
			return null;
		}
		final double xValue = num.doubleValue();
		final float posX = calcLocation( xValue, xAxis, true );
		final float x = ( posX - mGraphRectX )/this.mMagnification;

		
		str = el.getAttribute( KEY_Y_VALUE );
		if( str.length()==0 )
		{
			return null;
		}
		num = SGUtilityText.getDouble(str);
		if( num==null )
		{
			return null;
		}
		final double yValue = num.doubleValue();
		final float posY = calcLocation( yValue, yAxis, false );
		final float y = ( posY - mGraphRectY )/this.mMagnification;

		
/*
		// set the location of SGLegendElement
		str = element.getAttribute( KEY_LEGEND_X );
		if( str.length()==0 )
		{
			return null;
		}
		num = SGUtilityText.getFloat(str,cm);
		if( num==null )
		{
			return null;
		}
		final float x = num.floatValue()/ratio;

		str = element.getAttribute( KEY_LEGEND_Y );
		if( str.length()==0 )
		{
			return null;
		}
		num = SGUtilityText.getFloat(str,cm);
		if( num==null )
		{
			return null;
		}
		final float y = num.floatValue()/ratio;
*/

		// set frame visible
		str = el.getAttribute( SGLegendElement.KEY_LEGEND_VISIBLE );
		if( str.length()==0 )
		{
			return null;
		}
		b = SGUtilityText.getBoolean(str);
		if( b == null )
		{
			return null;
		}
		final boolean frameVisible = b.booleanValue();


		// set frame line width
		str = el.getAttribute( SGLegendElement.KEY_FRAME_LINE_WIDTH );
		if( str.length()==0 )
		{
			return null;
		}
		num = SGUtilityText.getFloat(str,pt);
		final float frameLineWidth = num.floatValue();


		// set frame line color
		str = el.getAttribute( SGLegendElement.KEY_FRAME_LINE_COLOR );
		if( str.length()==0 )
		{
			return null;
		}
		cl = SGUtilityText.getColorFromString(str);
		if( cl == null )
		{
			return null;
		}
		final Color frameLineColor = cl;


		// background color
		str = el.getAttribute( SGLegendElement.KEY_BACKGROUND_COLOR );
		if( str.length()==0 )
		{
			return null;
		}
		cl = SGUtilityText.getColorFromString(str);
		if( cl == null )
		{
			return null;
		}
		final Color bgColor = cl;

		
		// transparent
		str = el.getAttribute( SGLegendElement.KEY_BACKGROUND_TRANSPARENT );
		if( str.length()==0 )
		{
			return null;
		}
		b = SGUtilityText.getBoolean(str);
		if( b==null )
		{
			return null;
		}
		final boolean transparent = b.booleanValue();


		// set font name
		str = el.getAttribute( KEY_FONT_NAME );
		if( str.length()==0 )
		{
			return null;
		}
		final String fontName = str;


		// set font size
		str = el.getAttribute( KEY_FONT_SIZE );
		if( str.length()==0 )
		{
			return null;
		}
		num = SGUtilityText.getFloat(str,pt);
		if( num==null )
		{
			return null;
		}
		float fontSize = num.floatValue();


		// set font style
		str = el.getAttribute( KEY_FONT_STYLE );
		if( str.length()==0 )
		{
			return null;
		}
		final int fontStyle = SGUtilityText.getFontStyle(str);
		if( fontStyle==-1 )
		{
			return null;
		}


		// set the string color
		str = el.getAttribute( KEY_STRING_COLORS );
		if( str.length()==0 )
		{
			return null;
		}
		cl = SGUtilityText.getColorFromString(str);
		if( cl==null )
		{
			return null;
		}
		final Color strColor = cl;


		LegendCommonProperties cp = new LegendCommonProperties();
		cp.visible = legendVisible;
		cp.x = x;
		cp.y = y;
		cp.frameLineVisible = frameVisible;
		cp.frameLineWidth = frameLineWidth;
		cp.frameLineColor = frameLineColor;
		cp.backgroundColor = bgColor;
		cp.transparent = transparent;
		cp.fontName = fontName;
		cp.fontSize = fontSize;
		cp.fontStyle = fontStyle;
		cp.stringColor = strColor;
		cp.xAxis = xAxis;
		cp.yAxis = yAxis;

		return cp;
	}
	
	
	
	
	/**
	 * 
	 */
	interface ILegendElement
	{
		/**
		 * 
		 * @return
		 */
		public float getDataElementWidth();

		/**
		 * 
		 * @return
		 */
		public float getDataElementHeight();

		/**
		 * 
		 * @return
		 */
		public boolean createDrawingElementInLegend();

		/**
		 * 
		 * @return
		 */
		public int getNumberOfPoints();

	}



	/**
	 * 一つのデータに対応したレジェンド
	 */
	abstract class ElementGroupSetInLegend
		extends SGElementGroupSetInFigureElement
		implements ActionListener, SGIUndoable, SGIPropertySettingListenerData
	{

		/**
		 * 一つのデータに対する矩形
		 */
		protected Rectangle2D mDataRect = null;


		/**
		 * 実際に描画するデータ名の文字列描画要素
		 */		
		protected SGDrawingElementString2DExtended mDrawingString = null;


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


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



		/**
		 * Returns whether this group set is visible by two flags.
		 * @return visibility of this group set
		 */
		private boolean isVisibleTotally()
		{
			return ( this.isVisible() & this.isVisibleInLegend() );
		}




		/**
		 * データ名の文字列描画要素を作成
		 */
		private boolean createStringElement()
		{
			String name = this.mName;// + " ";
			SGDrawingElementString2DExtended el = new SGDrawingElementString2DExtended(
				name, mFontName, mFontStyle, mFontSize );
			el.setColor( mStringColor );
			el.setMagnification( mMagnification );
			mDrawingString = el;
			return true;
		}


		/**
		 * 
		 * @return
		 */
		private boolean paintString( final Graphics2D g2d )
		{
			if( this.mDrawingString!=null )
			{
				this.mDrawingString.drawString(g2d);
			}
			return true;
		}


		/**
		 * 
		 * @return
		 */
		private SGDrawingElementString2D getStringElement()
		{
			return this.mDrawingString;
		}


		/**
		 * 
		 * @return
		 */
		private Rectangle2D getStringBounds()
		{
			if( this.mDrawingString==null )
			{
				return null;
			}
			Rectangle2D rect = this.getStringElement().getElementBounds();
			return rect;
		}


		/**
		 * 
		 * @return
		 */
		private Rectangle2D getRect()
		{
			return this.mDataRect;
		}


		/**
		 * 
		 * @param rect
		 */
		private void setRect( Rectangle2D rect )
		{
			this.mDataRect = rect;
		}


		/**
		 * 
		 */
		public float getMaxDataElementWidth()
		{
			float max = 0.0f;
			final ArrayList list = this.mDrawingElementGroupList;
			for( int ii=0; ii<list.size(); ii++ )
			{
				ILegendElement el = (ILegendElement)list.get(ii);
				final float width = el.getDataElementWidth();
				if( width > max )
				{
					max = width;
				}
			}

			return max;
		}


		/**
		 * 
		 */
		public double getMaxDataElementHeight()
		{
			double max = 0.0;
			ArrayList list = this.mDrawingElementGroupList;
			for( int ii=0; ii<list.size(); ii++ )
			{
				SGElementGroup group = (SGElementGroup)list.get(ii);
				if( !group.isVisible() )
				{
					continue;
				}
				ILegendElement el = (ILegendElement)list.get(ii);
				double height = el.getDataElementHeight();
				if( height > max )
				{
					max = height;
				}
			}

			return max;
		}


		/**
		 * 
		 */
		public boolean onDrawingElement( final int x, final int y )
		{
			return this.mDataRect.contains(x,y);
		}


		/**
		 * 
		 * @return
		 */
		private boolean createDrawingElement()
		{
			final ArrayList list = this.mDrawingElementGroupList;
			for( int ii=0; ii<list.size(); ii++ )
			{
				ILegendElement el = (ILegendElement)list.get(ii);
				el.createDrawingElementInLegend();
			}

			return true;
		}


		/**
		 * 
		 */
		public void paintGraphics2D( final Graphics2D g2d )
		{
			
			// draw the name of data
			g2d.setPaint( mStringColor );
			this.paintString(g2d);

			// bar
			ElementGroupBar groupBar = getGroupBar( this );
			if( groupBar!=null )
			{
				if( groupBar.isVisible() )
				{
					groupBar.paintElement(g2d);
				}
			}
	
			// line
			ElementGroupLine groupLine = getGroupLine( this );
			if( groupLine!=null )
			{
				if( groupLine.isVisible() )
				{
					groupLine.paintElement(g2d);
				}
			}
	
			// symbol
			ElementGroupSymbol groupSymbol = getGroupSymbol( this );
			if( groupSymbol!=null )
			{
				if( groupSymbol.isVisible() )
				{
					groupSymbol.paintElement(g2d);
				}
			}

		}


		/**
		 * 
		 */
		protected boolean clickDrawingElements( final MouseEvent e )
		{
			return false;
		}


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

			SGElementGroup group = null;
			if( type == SGElementGroup.POLYLINE_GROUP )
			{
				group = new ElementGroupLine();
			}
			else if( type == SGElementGroup.RECTANGLE_GROUP )
			{
				group = new ElementGroupBar();
			}
			else if( type == SGElementGroup.SYMBOL_GROUP )
			{
				group = new ElementGroupSymbol();
			}
			else if( type == SGElementGroup.ARROW_GROUP )
			{
				group = new ElementGroupArrow();
			}
			else
			{
				throw new Error("");
			}

			this.addDrawingElementGroup( group );


			// 描画要素の作成
//			createAllDrawingElements();


			return true;
		}


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

			SGElementGroup group = null;
			if( element instanceof SGDrawingElementLine )
			{
				group = new ElementGroupLine();
			}
			else if( element instanceof SGDrawingElementBar )
			{
				group = new ElementGroupBar();
			}
			else if( element instanceof SGDrawingElementSymbol )
			{
				group = new ElementGroupSymbol();
			}
			else if( element instanceof SGDrawingElementArrow )
			{
				group = new ElementGroupArrow();
			}
			else
			{
				throw new Error("");
			}

			group.setProperty( element );
			group.setMagnification(this.mMagnification);

			this.addDrawingElementGroup( group );


			// 描画要素の作成
			createAllDrawingElements();


			return true;
		}



		/**
		 * 
		 */
		private boolean addDrawingElementGroup( final SGElementGroup group )
		{

			group.mGroupSet = this;


			ILegendElement lElement = (ILegendElement)group;


			// 描画要素の作成
			group.initDrawingElement( lElement.getNumberOfPoints() );


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


			// 倍率
			group.setMagnification( mMagnification );


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


			return true;
		}


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


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


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

			createAllDrawingElements();
			notifyChange();
		}



		/**
		 * 
		 */
		public boolean setProperties( final SGProperties p )
		{
			ElementGroupSetProperties pp = (ElementGroupSetProperties)p;
			pp.visible = this.isVisible();

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

			return true;
		}



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


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


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


		/**
		 * 
		 * @return
		 */
		private boolean addElementGroupSetPropertyHistory( WholeProperties p )
		{
			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()
		{
			this.mElementGroupSetStateCounter--;

			WholeProperties p
				= (WholeProperties)this.mElementGroupSetPropertyHistoryList.get(
					this.mElementGroupSetStateCounter);

			this.setWholeProperties(p);

			createAllDrawingElements();
//			notifyChange();

			return true;
		}


		/**
		 * リドゥを行う
		 */
		public boolean redo()
		{
			this.mElementGroupSetStateCounter++;

			WholeProperties p
				= (WholeProperties)this.mElementGroupSetPropertyHistoryList.get(
					this.mElementGroupSetStateCounter);

			this.setWholeProperties(p);

			createAllDrawingElements();
//			notifyChange();

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

			return true;
		}



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

			return true;
		}



		/**
		 * 
		 */
		public boolean updateThisObjectHistory()
		{
			this.mElementGroupSetStateCounter++;
			WholeProperties p = (WholeProperties)this.getWholeProperties();
			this.addElementGroupSetPropertyHistory(p);
			return true;
		}


		/**
		 * 
		 *
		 */
		public void notifyToRoot()
		{
			notifyToRootFromFigureElement();
		}


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

		protected boolean mChangedFlag = false;

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

	}



	/**
	 * 
	 */
	class ElementGroupSetInLegendSXY extends ElementGroupSetInLegend
		implements SGIPropertySettingListenerSXYData
	{

		/**
		 * 
		 */
		protected SGPropertyDialogSXYData mDialog = null;


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


		public boolean getLegendVisibleFlag()
		{
			return this.isVisibleInLegend();
		}


		// テンポラリオブジェクトを作成させる
		public boolean createTemporaryPropertyObject()
		{
			this.mTemporaryProperties = this.getWholeProperties();
			return true;
		}


		// ダイアログに設定された値を元に設定し、終了
		public boolean commit()
		{
			return this.commit( mSXYDataDialog );
		}


		// 設定前の状態に戻す
		public boolean cancel()
		{
			if( this.setWholeProperties( this.mTemporaryProperties ) == false )
			{
				return false;
			}

			this.mTemporaryProperties = null;

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

			return true;
		}


		// ダイアログに設定された値を元に設定する
		public boolean preview()
		{
			return this.preview( mSXYDataDialog );
		}


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

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

			if( pTemp.equals(pPresent) == false )
			{
				this.mChangedFlag = true;
			}

			this.mTemporaryProperties = null;
			mSXYDataDialog.setVisible(false);

			//
			if( createAllDrawingElements() == false )
			{
				return false;
			}

			notifyChange();

			return true;

		}

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

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

			return true;
		}




		/**
		 * 
		 */
		public boolean setPropertiesFromDialog( SGPropertyDialog dialog )
		{

			final SGPropertyDialogSXYData dg
				= (SGPropertyDialogSXYData)dialog;


			// 全部がチェックアウトされたら警告
			if( !dg.getLineVisible()
			&& !dg.getBarVisible()
			&& !dg.getSymbolVisible() )
			{
				JOptionPane.showMessageDialog(
					dg, MSG_NOT_HIDE_ALL_ELEMENTS );
				return false;
			}


			//
			if( this.setPropertyWithDialog_( dg ) == false )
			{
				return false;
			}

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

			return true;
		}


		/**
		 * 
		 */
		private boolean setPropertyWithDialog_( SGPropertyDialogSXYData dg )
		{

			// set the related axes
			SGIAxisElement aElement = mAxisElement;
			final SGAxis bAxis = aElement.getAxisInPlane( SGIAxisElement.AXIS_HORIZONTAL_1 );
			final SGAxis tAxis = aElement.getAxisInPlane( SGIAxisElement.AXIS_HORIZONTAL_2 );
			final SGAxis lAxis = aElement.getAxisInPlane( SGIAxisElement.AXIS_PERPENDICULAR_1 );
			final SGAxis rAxis = aElement.getAxisInPlane( SGIAxisElement.AXIS_PERPENDICULAR_2 );

//			if( dg.isLeftBottomSelected() )
//			{
//				this.mXAxis = bAxis;
//				this.mYAxis = lAxis;
//			}
//			else if( dg.isLeftTopSelected() )
//			{
//				this.mXAxis = tAxis;
//				this.mYAxis = lAxis;
//			}
//			else if( dg.isRightBottomSelected() )
//			{
//				this.mXAxis = bAxis;
//				this.mYAxis = rAxis;
//			}
//			else if( dg.isRightTopSelected() )
//			{
//				this.mXAxis = tAxis;
//				this.mYAxis = rAxis;
//			}


			// visibility in legend
			Boolean b = dg.getLegendVisible();
			if( b!=null )
			{
				this.setVisibleInLegend( b.booleanValue() );
			}
			updateSymbolsVisibleAroundFocusedObjects();


			//
			ArrayList lineList = this.getLineGroups();
			for( int ii=0; ii<lineList.size(); ii++ )
			{
				SGElementGroupLine group = (SGElementGroupLine)lineList.get(ii);
				if( dg.isTabEnabled( dg.getLinePanel() ) )
				{
					if( dg.setLineProperties(group) == false )
					{
						return false;
					}
				}
			}

			ArrayList symbolList = this.getSymbolGroups();
			for( int ii=0; ii<symbolList.size(); ii++ )
			{
				SGElementGroupSymbol group = (SGElementGroupSymbol)symbolList.get(ii);
				if( dg.isTabEnabled( dg.getSymbolPanel() ) )
				{
					if( dg.setSymbolProperties(group) == false )
					{
						return false;
					}
				}
			}

			ArrayList barList = this.getBarGroups();
			for( int ii=0; ii<barList.size(); ii++ )
			{
				SGElementGroupBar group = (SGElementGroupBar)barList.get(ii);
				if( dg.isTabEnabled( dg.getBarPanel() ) )
				{
					if( dg.setBarProperties(group) == false )
					{
						return false;
					}
				}
			}

//			if( this.mErrorBarGroup!=null )
//			{
//				if( dg.isTabEnabled( dg.getErrorBarPanel() ) )
//				{
//					if( dg.setErrorBarProperties( this.mErrorBarGroup ) == false )
//					{
//						return false;
//					}
//				}
//			}
//
//			if( this.mTickLabels!=null )
//			{
//				if( dg.isTabEnabled( dg.getTickLabelPanel() ) )
//				{
//					if( dg.setTickLabelProperties( this.mTickLabels ) == false )
//					{
//						return false;
//					}
//				}
//			}

			return true;
		}



		/**
		 * 
		 */
		public ArrayList getLineGroups()
		{
			ArrayList list = new ArrayList();
			for( int ii=0; ii<this.mDrawingElementGroupList.size(); ii++ )
			{
				Object obj = this.mDrawingElementGroupList.get(ii);
				if( obj instanceof SGElementGroupLine )
				{
					list.add(obj);
				}
			}
			return list;
		}


		/**
		 * 
		 */
		public ArrayList getSymbolGroups()
		{
			ArrayList list = new ArrayList();
			for( int ii=0; ii<this.mDrawingElementGroupList.size(); ii++ )
			{
				Object obj = this.mDrawingElementGroupList.get(ii);
				if( obj instanceof SGElementGroupSymbol )
				{
					list.add(obj);
				}
			}
			return list;
		}


		/**
		 * 
		 */
		public ArrayList getBarGroups()
		{
			ArrayList list = new ArrayList();
			for( int ii=0; ii<this.mDrawingElementGroupList.size(); ii++ )
			{
				Object obj = this.mDrawingElementGroupList.get(ii);
				if( obj instanceof SGElementGroupBar )
				{
					list.add(obj);
				}
			}
			return list;
		}


		public int getXAxisConfiguration()
		{
			return -1;
		}

		public int getYAxisConfiguration()
		{
			return -1;
		}


		public ArrayList getErrorBarGroups()
		{
			return new ArrayList();
		}


		public ArrayList getTickLabelGroups()
		{
			return new ArrayList();
		}


		public boolean setLineProperties( SGProperties p )
		{
			return true;
		}

		public boolean setSymbolProperties( SGProperties p )
		{
			return true;
		}

		public boolean setBarProperties( SGProperties p )
		{
			return true;
		}

		public boolean setErrorBarProperties( SGProperties p )
		{
			return true;
		}

		public boolean setTickLabelProperties( SGProperties p )
		{
			return true;
		}


	}



	/**
	 * 
	 */
//	class ElementGroupSetInLegendVXY extends ElementGroupSetInLegend
//	{
//
//		/**
//		 * 
//		 */
//		protected SGPropertyDialogVXYData mDialog = null;
//
//
//		/**
//		 * 
//		 */
//		protected ElementGroupSetInLegendVXY()
//		{
//			super();
//		}
//		
//	}



	/**
	 * 
	 */
	class ElementGroupLine extends SGElementGroupLine
		implements ILegendElement
	{

		/**
		 *
		 */
		protected ElementGroupLine()
		{
			super();
			if( this.init() == false )
			{
				throw new Error();
			}
		}


		/**
		 * 
		 */
		private boolean init()
		{
			this.setVisible( SGDefaultValues.LINE_VISIBLE );
			this.setLineWidth( SGDefaultValues.LINE_WIDTH );
			final Integer n = SGDrawingElementLine.getLineTypeFromName( SGDefaultValues.LINE_TYPE );
			if( n==null )
			{
				return false;
			}
			this.setLineType( n.intValue() );
			this.setColor( SGDefaultValues.LINE_COLOR );

			return true;
		}


		/**
		 * 
		 */
		public float getDataElementWidth()
		{
			return this.mMagnification*MIN_WIDTH_DATA_ELEMENT;
		}


		/**
		 * 
		 */
		public float getDataElementHeight()
		{
			return 1.5f*mMagnification*mLineWidth;
		}


		/**
		 * 
		 * @return
		 */
		public int getNumberOfPoints()
		{
			return 2;
		}

	
		/**
		 * 描画要素の作成
		 */
		public boolean createDrawingElementInLegend()
		{

			Rectangle2D lRect = getRectOfGroupSet(this.mGroupSet);

			SGTuple2f start = new SGTuple2f();
			start.x = (float)lRect.getX() + 0.0f*this.getDataElementWidth();
			start.y = (float)lRect.getY() + 0.50f*(float)lRect.getHeight();
			SGTuple2f end = new SGTuple2f();
			end.x = start.x + 1.0f*this.mMagnification*MIN_WIDTH_DATA_ELEMENT;
			end.y = start.y;


			SGTuple2f[] array = new SGTuple2f[2];
			array[0] = start;
			array[1] = end;


			this.setLocation( array );

			return true;
		}


	}



	/**
	 * 
	 */
	class ElementGroupBar extends SGElementGroupBar
		implements ILegendElement
	{

		/**
		 *
		 */
		protected ElementGroupBar()
		{
			super();
			if( this.init() == false )
			{
				throw new Error();
			}
		}


		/**
		 * 
		 */
		private boolean init()
		{
			this.setVisible( SGDefaultValues.BAR_VISIBLE );
			this.setBaselineValue( SGDefaultValues.BAR_BASELINE_VALUE );
			this.setRectangleWidth( SGDefaultValues.BAR_WIDTH );
			this.setColor( SGDefaultValues.BAR_COLOR );
			this.setEdgeLineWidth( SGDefaultValues.BAR_LINE_WIDTH );
			this.setEdgeLineColor( SGDefaultValues.BAR_LINE_COLOR );

			return true;
		}


		/**
		 * 
		 */
		public float getDataElementWidth()
		{
			return this.mMagnification*MIN_WIDTH_DATA_ELEMENT;
		}


		/**
		 * 
		 */
		public float getDataElementHeight()
		{
			return 1.5f*mRectangleWidth*this.mMagnification;
		}


		/**
		 * 
		 * @return
		 */
		public int getNumberOfPoints()
		{
			return 1;
		}


		/**
		 * 
		 */
		public boolean createDrawingElementInLegend()
		{

			Rectangle2D lRect = getRectOfGroupSet(this.mGroupSet);

			final float barWidth = this.mMagnification*mRectangleWidth;

			SGTuple2f start = new SGTuple2f();
			start.x = (float)lRect.getX() + 0.20f*this.getDataElementWidth();
			start.y = (float)lRect.getY() + 0.50f*(float)lRect.getHeight() - 0.50f*barWidth;

			SGTuple2f[] array = new SGTuple2f[1];
			array[0] = start;
			this.setLocation(array);			

			return true;
		}



		/**
		 * 
		 */
		public boolean setLocation(
			final SGTuple2f[] pointArray )
		{

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

			if( pointArray.length != this.mDrawingElementArray.length )
			{
				throw new IllegalArgumentException();
			}

			// 棒グラフの描画要素を作成
			for( int ii=0; ii<this.mDrawingElementArray.length; ii++ )
			{
				SGDrawingElementBar2D bar
					= (SGDrawingElementBar2D)this.mDrawingElementArray[ii];
				SGTuple2f point = pointArray[ii];
				bar.setBounds(
					point.x, point.y,
					0.60f*this.getDataElementWidth(),
					this.mMagnification*this.mRectangleWidth
				);
			}
//			if( this.setPropertiesOfDrawingElements() == false )
//			{
//				return false;
//			}

			return true;
		}


	}



	/**
	 * 
	 */
	class ElementGroupSymbol extends SGElementGroupSymbol
		implements ILegendElement
	{

		/**
		 *
		 */
		protected ElementGroupSymbol()
		{
			super();
			if( this.init() == false )
			{
				throw new Error();
			}
		}


		/**
		 * 
		 */
		private boolean init()
		{
			this.setVisible( SGDefaultValues.SYMBOL_VISIBLE );
			Integer n = SGDrawingElementSymbol.getSymbolTypeFromName( SGDefaultValues.SYMBOL_TYPE );
			if( n==null )
			{
				return false;
			}
			this.setType( n.intValue() );
			this.setSize( SGDefaultValues.SYMBOL_SIZE );
			this.setColor( SGDefaultValues.SYMBOL_BODY_COLOR );
			this.setLineWidth( SGDefaultValues.SYMBOL_LINE_WIDTH );
			this.setLineColor( SGDefaultValues.SYMBOL_LINE_COLOR );

			return true;
		}


		/**
		 * 
		 */
		public float getDataElementWidth()
		{
			final float w = this.mMagnification*MIN_WIDTH_DATA_ELEMENT;
			final float s = getDataElementSize();
			if( w<s )
			{
				return s;
			}
			else
			{
				return w;
			}
		}


		/**
		 * 
		 */
		public float getDataElementHeight()
		{
			return 1.5f*getDataElementSize();
		}


		/**
		 * 
		 */
		private float getDataElementSize()
		{
			if( this.mDrawingElementArray!=null )
			{
				if( this.mDrawingElementArray.length == 0 )
				{
					return 0.0f;
				}

				SGDrawingElementSymbol2D symbol
					= (SGDrawingElementSymbol2D)this.mDrawingElementArray[0];
				Rectangle2D rect = symbol.getElementBounds().getBounds2D();
				return (float)rect.getHeight();
			}
			else
			{
				return 0.0f;
			}
		}


		/**
		 * 
		 * @return
		 */
		public int getNumberOfPoints()
		{
			return 1;
		}


		/**
		 * 
		 */
		public boolean createDrawingElementInLegend()
		{

			Rectangle2D lRect = getRectOfGroupSet(this.mGroupSet);

			SGTuple2f position = new SGTuple2f();
			position.x = (float)lRect.getX() + 0.50f*this.mMagnification*MIN_WIDTH_DATA_ELEMENT;
			position.y = (float)lRect.getY() + 0.50f*(float)lRect.getHeight();

			SGTuple2f[] array = new SGTuple2f[1];
			array[0] = position;
			this.setLocation(array);

			return true;

		}


	}




	/**
	 * 
	 */
	class ElementGroupArrow extends SGElementGroupArrow
		implements ILegendElement
	{

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


		/**
		 * 
		 */
		public float getDataElementWidth()
		{
			return this.mMagnification*MIN_WIDTH_DATA_ELEMENT;
		}


		/**
		 * 
		 */
		public float getDataElementHeight()
		{
			return 0.0f;
		}


		/**
		 * 
		 * @return
		 */
		public int getNumberOfPoints()
		{
			return 1;
		}


		/**
		 * 
		 */
		public boolean createDrawingElementInLegend()
		{
			Rectangle2D lRect = getRectOfGroupSet(this.mGroupSet);

			SGTuple2f start = new SGTuple2f();
			start.x = (float)lRect.getX() + 0.10f*this.mMagnification*MIN_WIDTH_DATA_ELEMENT;
			start.y = (float)lRect.getY() + 0.50f*(float)lRect.getHeight();
			SGTuple2f end = new SGTuple2f();
			end.x = start.x + 0.80f*this.mMagnification*MIN_WIDTH_DATA_ELEMENT;
			end.y = start.y;


			SGTuple2f[] startArray = new SGTuple2f[1];
			startArray[0] = start;
			SGTuple2f[] endArray = new SGTuple2f[1];
			endArray[0] = end;
			if( this.setLocation( startArray, endArray ) == false )
			{
				return false;
			}

			return true;
		}



		/**
		 * 
		 */
		Rectangle2D getDataElementBounds()
		{
			Rectangle2D rect = new Rectangle2D.Double();
//
//
//
			return rect;
		}



	}





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

		float x;
		float y;
		boolean visible;
		boolean frameLineVisible;
		float frameLineWidth;
		Color frameLineColor;
		String fontName;
		float fontSize;
		int fontStyle;
		Color stringColor;
		Color backgroundColor;
		boolean transparent;
		SGAxis xAxis;
		SGAxis yAxis;


		/**
		 * 
		 */
		public boolean equals( final Object obj )
		{

			if( ( obj instanceof LegendCommonProperties ) == false ) return false;

			LegendCommonProperties p = (LegendCommonProperties)obj;

			if( p.x != this.x ) return false;
			if( p.y != this.y ) return false;
			if( p.visible != this.visible ) return false;
			if( p.frameLineVisible != this.frameLineVisible ) return false;
			if( p.frameLineWidth != this.frameLineWidth ) return false;
			if( p.frameLineColor.equals(this.frameLineColor) == false ) return false;
			if( p.fontName.equals(this.fontName) == false ) return false;
			if( p.fontSize != this.fontSize ) return false;
			if( p.fontStyle != this.fontStyle ) return false;
			if( p.stringColor.equals(this.stringColor) == false ) return false;
			if( p.backgroundColor.equals( this.backgroundColor ) == false ) return false;
			if( p.transparent != this.transparent ) return false;

			return true;
		}


		/**
		 * 
		 */
		public String toString()
		{
			String str = new String("[");
			str += new String("x="+x+", ");
			str += new String("y="+y+", ");
			str += new String("visible="+visible+", ");
			str += new String("frameLineVisible="+frameLineVisible+", ");
			str += new String("frameLineWidth="+frameLineWidth+", ");
			str += new String("frameLineColor="+frameLineColor+", ");
			str += new String("fontName="+fontName+", ");
			str += new String("fontSize="+fontSize+", ");
			str += new String("fontStyle="+fontStyle+", ");
			str += new String("stringColor="+stringColor+", ");
			str += new String("innerColor="+backgroundColor+", ");
			str += new String("transparent="+transparent+", ");
			str += new String("]");

			return str;
		}



	}


}

