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.font.FontRenderContext;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;

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

import jp.riken.brain.ni.samuraigraph.base.SGAxis;
import jp.riken.brain.ni.samuraigraph.base.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.SGDrawingElementErrorBar;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementLine;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementRectangle;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementString;
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, ActionListener,
		SGIMovable, SGISelectable, SGILegendDialogObserver
{

	/**
	 *
	 */
	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 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 mTextField = 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.setBackgroundTransparent( 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");
	}


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


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

		// create legend
		ElementGroupSetInLegend legend = this.createGroupSet( data, name );
		this.createAllDrawingElements();
		this.updateSymbolsVisibleAroundFocusedObjects();


		// set properties on start-up
		if( this.mStartFlag )
		{
			this.onStartup(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, p );


		// create legend
		ElementGroupSetInLegend legend = this.createGroupSet( data, name );
		if( legend.setWholeProperties(p) == false )
		{
			throw new Error();
		}
		this.createAllDrawingElements();
		this.updateSymbolsVisibleAroundFocusedObjects();


		// set properties on start-up
		if( this.mStartFlag )
		{
			this.onStartup(data);
		}

		return true;
	}



	private ElementGroupSetInLegend createGroupSet( SGData data, String name )
	{
		//
		// レジェンドの要素を新規作成
		//

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


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


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


		return legend;		
	}



	/**
	 * called on the start-up
	 * @param data
	 */
	private void onStartup( SGData data )
	{
		// set the location of the legend
		// to the north-east point of the graph area
		final float x = this.getGraphRectX()
			+ this.getGraphRectWidth() - this.mMagnification*this.getLegendWidth();
		final float y = this.getGraphRectY();
		this.setLegendLocation( x, y );

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

		this.mStartFlag = false;
	}


	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 )
		{
			ElementGroupSetInLegendSXY legendSXY = (ElementGroupSetInLegendSXY)legend;
			
			dg = this.mSXYDataDialog;

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

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

		// set proeprties to the dialog
		dg.addPropertyDialogObserver(legend);
		dg.setDialogProperty();
		dg.setColorButtonBorder( true );

		// create temporary objects
		legend.prepare();

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

		dg.removeAllPropertyDialogObserver();


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


		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
		legend.setName( name );


		// axes
		if( ( data instanceof SGSXYData )
			|| ( data instanceof SGVXYData )
			|| ( data instanceof SGSXYMultipleData ) )
		{
			SGIAxisElement aElement = this.mAxisElement;

			// get axes list
			final SGAxis bAxis = aElement.getAxisInPlane( SGAxisElement.AXIS_HORIZONTAL_1 );
			final SGAxis tAxis = aElement.getAxisInPlane( SGAxisElement.AXIS_HORIZONTAL_2 );
			final SGAxis lAxis = aElement.getAxisInPlane( SGAxisElement.AXIS_PERPENDICULAR_1 );
			final SGAxis rAxis = aElement.getAxisInPlane( SGAxisElement.AXIS_PERPENDICULAR_2 );
			SGAxis axisX = null;
			SGAxis axisY = null;
			if( SGDefaultValues.SCALE_REFERENCE.equals( SGIAxisElement.LEFT_BOTTOM ) )
			{
				axisX = bAxis;
				axisY = lAxis;
			}
			else if( SGDefaultValues.SCALE_REFERENCE.equals( SGIAxisElement.LEFT_TOP ) )
			{
				axisX = tAxis;
				axisY = lAxis;
			}
			else if( SGDefaultValues.SCALE_REFERENCE.equals( SGIAxisElement.RIGHT_BOTTOM ) )
			{
				axisX = bAxis;
				axisY = rAxis;
			}
			else if( SGDefaultValues.SCALE_REFERENCE.equals( SGIAxisElement.RIGHT_TOP ) )
			{
				axisX = tAxis;
				axisY = rAxis;
			}
			else
			{
				return null;
			}

			legend.setXAxis(axisX);
			legend.setYAxis(axisY);
		}


		// 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 SGDrawingElementErrorBar )
				{
					legend.addDrawingElementGroup( SGElementGroup.ERROR_BAR_GROUP );
				}
				else 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 if( element instanceof SGDrawingElementString )
				{
					legend.addDrawingElementGroup( SGElementGroup.TICK_LABEL_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;
	}


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

		return null;
	}


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

		return null;
	}


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

		return null;
	}



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


	/**
	 * 
	 * @param value
	 */
	public void setXValue( final double value )
	{
		SGAxis axis = this.mXAxis;
			
		// current values gotten from the position of legend
		double currentValue = calcValue( this.getX(), axis, true );
		currentValue = getNumberInRangeOrder( currentValue, axis );


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

		float x;
		if( value==currentValue )
		{
			x = this.mLegendX;
		}
		else
		{
			final float x_ = calcLocation( value, axis, true );
			x = ( x_ - mGraphRectX )/this.mMagnification;
		}

		this.mLegendX = x;

		this.createAllDrawingElements();
	}


	/**
	 * 
	 * @param value
	 */
	public void setYValue( final double value )
	{
		SGAxis axis = this.mYAxis;
			
		// current values gotten from the position of legend
		double currentValue = calcValue( this.getY(), axis, false );
		currentValue = getNumberInRangeOrder( currentValue, axis );


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

		float y;
		if( value==currentValue )
		{
			y = this.mLegendY;
		}
		else
		{
			final float y_ = calcLocation( value, axis, false );
			y = ( y_ - mGraphRectY )/this.mMagnification;
		}

		this.mLegendY = y;

		this.createAllDrawingElements();
	}

	
	

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

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


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


	/**
	 * 
	 * @return
	 */
	public double getXValue()
	{
		SGAxis axis = this.mXAxis;
		double value = calcValue( this.getLegendX(), axis, true );
		if( value==Double.NaN )
		{
			return value;
		}

		value = getNumberInRangeOrder( value, axis );
		return value;
	}

	
	/**
	 * 
	 * @return
	 */
	public double getYValue()
	{
		SGAxis axis = this.mYAxis;
		double value = calcValue( this.getLegendY(), axis, false );
		if( value==Double.NaN )
		{
			return value;
		}

		value = getNumberInRangeOrder( value, axis );
		return value;
	}


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

		return true;
	}



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

		if( this.mTextField.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;
//
//	}


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



	/**
	 * 
	 */
	private boolean createDialog()
	{
		SGLegendDialog dg = new SGLegendDialog( this.mDialogOwner, true );
		this.mLegendDialog = dg;
		return true;
	}



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



	/**
	 * 
	 */
	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.setBackgroundTransparent( 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 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.isLegendVisible() )
		{

			// 背景の塗りつぶし
			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 )
	{
		if( g2d==null )
		{
			return;
		}

		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);
				Rectangle2D rect = el.getRect();
				if( rect==null )
				{
					continue;
				}
				Rectangle2D sRect = el.getStringBounds();
				if( sRect==null )
				{
					continue;
				}
				g2d.setPaint( Color.red );
				g2d.draw(rect);
				g2d.setPaint( Color.BLUE );
				g2d.draw(sRect);
			}
		}

	}



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


		// axes
		for( int ii=0; ii<groupSetListNew.size(); ii++ )
		{
			SGData data = (SGData)dataListNew.get(ii);
			ElementGroupSetInLegend legend
				= (ElementGroupSetInLegend)groupSetListNew.get(ii);
			legend.setXAxis( element.getXAxis(data) );
			legend.setYAxis( element.getYAxis(data) );
			legend.setZAxis( element.getZAxis(data) );
		}


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

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

			boolean diffFlag = false;

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


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


			// drawing element of data
			ArrayList sList = element.getDrawingElementList(data);
			final boolean diff_ = legend.synchronizeDrawingElements(sList);
			if( diff_ )
			{
				diffFlag = diff_;
			}

//			for( int jj=sList.size()-1; jj>=0; jj-- )
//			{
//				SGDrawingElement el = (SGDrawingElement)sList.get(jj);
//				ArrayList lList = legend.mDrawingElementGroupList;
//				SGElementGroup group = (SGElementGroup)lList.get(jj);
//				SGDrawingElement elOld = group.getDrawingElement();
//				SGProperties p = el.getProperties();
//				SGProperties pOld = elOld.getProperties();
//				if( p.equals(pOld) == false )
//				{
//					diffFlag = true;
//				}
//				group.setProperty(el);
//			}


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


			// set changed flag
			if( diffFlag )
			{
				legend.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( !isLegendVisible() )
		{
			return false;
		}

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

		Rectangle2D rect = this.getLegendRect();
		if( rect.contains(x,y) )
		{
			ArrayList gList = this.getVisibleTotallyLegendList();

			if( cnt==1 )
			{
				this.updateFocusedObjectsList( this, e );

				if( SwingUtilities.isLeftMouseButton(e) )
				{
					for( int ii=0; ii<gList.size(); ii++ )
					{
						ElementGroupSetInLegend legend
							= (ElementGroupSetInLegend)gList.get(ii);
						Rectangle2D sRect = legend.getStringBounds();
						if( sRect.contains(x,y) )
						{
							if( SwingUtilities.isLeftMouseButton(e) )
							{
								if( this.isSelected() )
								{
									this.showEditField(legend);
								}
							}
						}
					}
				}
				else if( SwingUtilities.isRightMouseButton(e) )
				{
					this.mPopupMenu.show( this, x, y );
				}
			}
			else if( cnt==2 )
			{

				for( int ii=0; ii<gList.size(); ii++ )
				{
					ElementGroupSetInLegend legend
						= (ElementGroupSetInLegend)gList.get(ii);

					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++ )
						{
							if( array[kk].isVisible() == false )
							{
								continue;
							}
	
							final boolean b = array[kk].contains(x,y);
							if(b)
							{
								if( SwingUtilities.isLeftMouseButton(e) )
								{
									if( cnt==2 )
									{
										legend.onMouseClicked(e);
										this.showDataDialog(legend);
										return true;
									}
								}
							}
						}
					}
				}


				if( SwingUtilities.isLeftMouseButton(e) )
				{
					this.setPropertiesOfSelectedObjects();
				}
			}

			return true;
		}


		return false;
	}



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



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



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


	/**
	 * 
	 * @return
	 */
	public SGPropertyDialog getPropertyDialog()
	{
		return this.mLegendDialog;
	}


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

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


		//
		this.createAllDrawingElements();


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

		notifyChange();

		this.notifyToRoot();

		return true;
	}



	/**
	 * 
	 */
	private boolean hideEditField()
	{
		this.mTextField.setText("");
		this.mTextField.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( !isLegendVisible() )
		{
			return false;
		}

		if( this.mTextField.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.mTextField.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.mTextField.getWidth() )
		{
			this.mTextField.setSize(
				(int)( stringRect.getWidth() + this.getMagnification()*this.getFontSize() ),
				this.mTextField.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 int getXAxisConfiguration()
	{
		return this.mAxisElement.getConfigurationInPlane( this.mXAxis );
	}


	/**
	 * 
	 */
	public int getYAxisConfiguration()
	{
		return this.mAxisElement.getConfigurationInPlane( this.mYAxis );
	}


	/**
	 * 
	 */
	public void setAxisConfiguration( final int configX, final int configY )
	{
		SGIAxisElement aElement = this.mAxisElement;
		SGAxis xAxis = aElement.getAxisInPlane( configX );
		SGAxis yAxis = aElement.getAxisInPlane( configY );
		this.mXAxis = xAxis;
		this.mYAxis = yAxis;
	}


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


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


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


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


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


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


	/**
	 * 
	 */
	public boolean setFontSize( final float size )
	{
		this.setFont( this.getFontName(), this.getFontStyle(), size );
		return true;
	}


	/**
	 * 
	 */
	public boolean setFontStyle( final int style )
	{
		this.setFont( this.getFontName(), style, this.getFontSize() );
		return true;
	}


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


	/**
	 * 
	 */
	public boolean setFontName( final String name )
	{
		this.setFont( name, this.getFontStyle(), this.getFontSize() );
		return true;
	}



	/**
	 * 
	 */
	public boolean setFont( final String name, final int style, final float size )
	{
		this.mFontName = name;
		this.mFontStyle = style;
		this.mFontSize = size;
		this.createAllDrawingElements();
		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()
	{
		final boolean visible = this.mLegendVisibleFlag;

		boolean visible2 = false;
		ArrayList list = this.mLegendList;
		for( int ii=0; ii<list.size(); ii++ )
		{
			ElementGroupSetInLegend groupSet = (ElementGroupSetInLegend)list.get(ii);
			final boolean b = groupSet.isVisibleTotally();
			if(b)
			{
				visible2 = true;
				break;
			}
		}

		final boolean b = visible & visible2;
		return b;
	}


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


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


	/**
	 * 
	 * @param groupSet
	 * @return
	 */
	private ElementGroupErrorBar getGroupErrorBar( final ElementGroupSetInLegend groupSet )
	{
		ArrayList groupList = groupSet.mDrawingElementGroupList;
		for( int ii=0; ii<groupList.size(); ii++ )
		{
			SGElementGroup group = (SGElementGroup)groupList.get(ii);
			if( group instanceof ElementGroupErrorBar )
			{
				return (ElementGroupErrorBar)group;
			}
		}

		return null;
	}


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

		if( source.equals( this.mTextField ) )
		{
			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.setPropertiesOfSelectedObjects();
		}

	}



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

		this.createAllDrawingElements();
		this.repaint();

		notifyChange();

		return true;
	}



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

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

		super.addPropertiesHistory(p);

		return true;
	}


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

		this.mTemporaryProperties = null;
		this.createAllDrawingElements();
		this.repaint();

		notifyChange();

		return true;
	}


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

		notifyChange();

		return true;
	}



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



	/**
	 * 
	 */
	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,data);
		}
		else if( data instanceof SGVXYData )
		{
			//
		}

		return ret;
	}

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

		final int ic = SGIConstants.PROPERTY_FILE_INCORRECT;
		SGIAxisElement aElement = this.mAxisElement;
		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);


		// configuration of X-axis
		str = el.getAttribute( KEY_X_AXIS_POSITION );
		if( str.length()==0 )
		{
			return ic;
		}
		final int configX = aElement.getConfigurationInCube(str);


		// configuration of Y-axis
		str = el.getAttribute( KEY_Y_AXIS_POSITION );
		if( str.length()==0 )
		{
			return ic;
		}
		final int configY = aElement.getConfigurationInCube(str);
		
		
		// set x- and y-axis
		groupSet.setXAxis( aElement.getAxisInCube( configX ) );
		groupSet.setYAxis( aElement.getAxisInCube( configY ) );


		// 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 = groupSet.getLineGroup();
		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 = groupSet.getSymbolGroup();
		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 = groupSet.getBarGroup();
		if( group.readProperty(bar) == false )
		{
			return ic;
		}



		if( data instanceof SGSXYData )
		{
			SGSXYData dataSXY = (SGSXYData)data;

			// error bar
			nList = el.getElementsByTagName( SGElementGroupErrorBar.TAG_NAME_ERROR_BAR );
			if( nList.getLength()==1 )
			{
				// if data has error bars
				if( dataSXY.isErrorValueHolding() )
				{
					if( groupSet.addDrawingElementGroup( SGElementGroup.ERROR_BAR_GROUP ) == false )
					{
						return ic;
					}

					ElementGroupErrorBar eGroup = (ElementGroupErrorBar)groupSet.getErrorBarGroup();

					Element errorBar = (Element)nList.item(0);
					if( eGroup.readProperty(errorBar)==false )
					{
						return ic;
					}

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

				}
			}
			else if( nList.getLength()==0 )
			{
				// if data has error bars
				if( dataSXY.isErrorValueHolding() )
				{
					if( groupSet.addDrawingElementGroup( SGElementGroup.ERROR_BAR_GROUP ) == false )
					{
						return ic;
					}

					ElementGroupErrorBar eGroup = (ElementGroupErrorBar)groupSet.getErrorBarGroup();

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


			// tick label
			nList = el.getElementsByTagName( SGElementGroupTickLabel.TAG_NAME_TICK_LABELS );
			if( nList.getLength()==1 )
			{
				// if data has tick labels
				if( dataSXY.isStringArrayHolding() )
				{
					if( groupSet.addDrawingElementGroup( SGElementGroup.TICK_LABEL_GROUP ) == false )
					{
						return ic;
					}

					ElementGroupTickLabels tGroup = (ElementGroupTickLabels)groupSet.getTickLabelGroup();

					Element tickLabel = (Element)nList.item(0);
					if( tGroup.readProperty(tickLabel) == false )
					{
						return ic;
					}

					if( tGroup.setPropertiesOfDrawingElements() == false )
					{
						return ic;
					}
				}
			}
			else if( nList.getLength()==0 )
			{
				// if data has tick labels
				if( dataSXY.isStringArrayHolding() )
				{
					if( groupSet.addDrawingElementGroup( SGElementGroup.TICK_LABEL_GROUP ) == false )
					{
						return ic;
					}

					ElementGroupTickLabels tGroup = (ElementGroupTickLabels)groupSet.getTickLabelGroup();

					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, SGIDataPropertyDialogObserver
	{


		/**
		 * 一つのデータに対する矩形
		 */
		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;
		}


		/**
		 * 
		 * @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);
				}
			}
			
			// error bar
			ElementGroupErrorBar groupErrorBar = getGroupErrorBar( this );
			if( groupErrorBar!=null )
			{
				if( groupErrorBar.isVisible() )
				{
					groupErrorBar.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;
//		}


		protected abstract boolean onMouseClicked( final MouseEvent e );


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


		abstract boolean synchronizeDrawingElements( ArrayList eList );

		
		/**
		 * 
		 * @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 SGProperties getProperties()
		{
			ElementGroupSetInLegendProperties ep = new ElementGroupSetInLegendProperties();
			if( this.getProperties(ep) == false )
			{
				return null;
			}

			return ep;
		}


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

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

			ElementGroupSetInLegendProperties ep = (ElementGroupSetInLegendProperties)p;

			SGIAxisElement aElement = SGLegendElement.this.mAxisElement;

			ep.xAxis = aElement.getConfigurationInCube( this.getXAxis() );
			ep.yAxis = aElement.getConfigurationInCube( this.getYAxis() );
			ep.zAxis = aElement.getConfigurationInCube( this.getZAxis() );

			return true;
		}



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

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

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

			ElementGroupSetInLegendProperties ep = (ElementGroupSetInLegendProperties)p;

			SGIAxisElement aElement = SGLegendElement.this.mAxisElement;

			this.setXAxis( aElement.getAxisInCube( ep.xAxis ) );
			this.setYAxis( aElement.getAxisInCube( ep.yAxis ) );
			this.setZAxis( aElement.getAxisInCube( ep.zAxis ) );

			return true;
		}



		/**
		 * アンドゥを行う
		 */
		public boolean undo()
		{
			if( super.undo() == false ) return false;

			createAllDrawingElements();
			notifyChange();

			return true;
		}


		/**
		 * リドゥを行う
		 */
		public boolean redo()
		{
			if( super.redo() == false ) return false;

			createAllDrawingElements();
			notifyChange();

			return true;
		}



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



		/**
		 * 
		 */
		class ElementGroupSetInLegendProperties extends ElementGroupSetPropertiesInFigureElement
		{
			int xAxis;
			int yAxis;
			int zAxis;

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

				ElementGroupSetInLegendProperties p
					= (ElementGroupSetInLegendProperties)obj;

				if( super.equals(obj) == false ) return false;
				if( p.xAxis!=this.xAxis ) return false;
				if( p.yAxis!=this.yAxis ) return false;
				if( p.zAxis!=this.zAxis ) return false;

				return true;
			}


		}

	}



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

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


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


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


		public int getSelectedTabIndex()
		{
			return this.mSelectedTabIndex;
		}

		private int mSelectedTabIndex = -1;




		// Line
		
		public boolean isLineVisible()
		{
			return this.getLineGroup().isVisible();
		}
		
		public float getLineWidth()
		{
			return this.getLineGroup().getLineWidth();
		}
		
		public int getLineType()
		{
			return this.getLineGroup().getLineType();
		}

		public Color getLineColor()
		{
			return this.getLineGroup().getColor(0);
		}


		public boolean setLineVisible( final boolean b )
		{
			this.getLineGroup().setVisible(b);
			return true;
		}

		public boolean setLineWidth( final float width )
		{
			return this.getLineGroup().setLineWidth( width );
		}

		public boolean setLineType( final int type )
		{
			return this.getLineGroup().setLineType( type );
		}
		
		public boolean setLineColor( final Color cl )
		{
			return this.getLineGroup().setColor( cl );
		}



		// Symbol

		public boolean isSymbolVisible()
		{
			return this.getSymbolGroup().isVisible();
		}

		public int getSymbolType()
		{
			return this.getSymbolGroup().getType();
		}

		public float getSymbolSize()
		{
			return this.getSymbolGroup().getSize();
		}

		public float getSymbolLineWidth()
		{
			return this.getSymbolGroup().getLineWidth();
		}

		public Color getSymbolInnerColor()
		{
			return this.getSymbolGroup().getColor(0);
		}

		public Color getSymbolLineColor()
		{
			return this.getSymbolGroup().getLineColor();
		}

		public boolean setSymbolVisible( final boolean b )
		{
			this.getSymbolGroup().setVisible(b);
			return true;
		}

		public boolean setSymbolType( final int type )
		{
			return this.getSymbolGroup().setType(type);
		}

		public boolean setSymbolSize( final float size )
		{
			return this.getSymbolGroup().setSize(size);
		}

		public boolean setSymbolLineWidth( final float width )
		{
			return this.getSymbolGroup().setLineWidth(width);
		}

		public boolean setSymbolInnerColor( final Color cl )
		{
			return this.getSymbolGroup().setColor(cl);
		}

		public boolean setSymbolLineColor( final Color cl )
		{
			return this.getSymbolGroup().setLineColor(cl);
		}



		// Bar

		public boolean isBarVisible()
		{
			return this.getBarGroup().isVisible();
		}

		public double getBarBaselineValue()
		{
			return this.getBarGroup().getBaselineValue();
		}

		public float getBarWidth()
		{
			return this.getBarGroup().getRectangleWidth();
		}

		public float getBarEdgeLineWidth()
		{
			return this.getBarGroup().getEdgeLineWidth();
		}

		public Color getBarInnerColor()
		{
			return this.getBarGroup().getColor(0);
		}

		public Color getBarEdgeLineColor()
		{
			return this.getBarGroup().getEdgeLineColor();
		}

		public boolean setBarVisible( final boolean b )
		{
			this.getBarGroup().setVisible(b);
			return true;
		}

		public boolean setBarBaselineValue( final double value )
		{
			return this.getBarGroup().setBaselineValue( value );
		}

		public boolean setBarWidth( final float width )
		{
			return this.getBarGroup().setRectangleWidth( width );
		}

		public boolean setBarEdgeLineWidth( final float width )
		{
			return this.getBarGroup().setEdgeLineWidth( width );
		}

		public boolean setBarInnerColor( final Color cl )
		{
			return this.getBarGroup().setColor(cl);
		}

		public boolean setBarEdgeLineColor( final Color cl )
		{
			return this.getBarGroup().setEdgeLineColor(cl);
		}



		// Error Bar
		public boolean isErrorBarHolding()
		{
			return (this.getErrorBarGroup()!=null);
		}

		public boolean isErrorBarVisible()
		{
			return this.getErrorBarGroup().isVisible();
		}

		public int getErrorBarHeadType()
		{
			return this.getErrorBarGroup().getHeadType();
		}

		public float getErrorBarHeadSize()
		{
			return this.getErrorBarGroup().getHeadSize();
		}

		public Color getErrorBarColor()
		{
			return this.getErrorBarGroup().getColor(0);
		}

		public float getErrorBarLineWidth()
		{
			return this.getErrorBarGroup().getLineWidth();
		}

		public int getErrorBarStyle()
		{
			return this.getErrorBarGroup().getErrorBarStyle();
		}

		public boolean setErrorBarVisible( final boolean b )
		{
			this.getErrorBarGroup().setVisible(b);
			return true;
		}

		public boolean setErrorBarHeadType( final int type )
		{
			this.getErrorBarGroup().setHeadType( type );
			return true;
		}

		public boolean setErrorBarHeadSize( final float size )
		{
			this.getErrorBarGroup().setHeadSize( size );
			return true;
		}

		public boolean setErrorBarColor( final Color cl )
		{
			return this.getErrorBarGroup().setColor(cl);
		}

		public boolean setErrorBarLineWidth( final float width )
		{
			this.getErrorBarGroup().setLineWidth( width );
			return true;
		}

		public boolean setErrorBarStyle( final int style )
		{
			this.getErrorBarGroup().setErrorBarStyle(style);
			return true;
		}



		// Tick Label

		public boolean isTickLabelHolding()
		{
			return (this.getTickLabelGroup()!=null);
		}

		public boolean isTickLabelVisible()
		{
			return this.getTickLabelGroup().isVisible();
		}

		public String getTickLabelFontName()
		{
			return this.getTickLabelGroup().getFontName();
		}

		public int getTickLabelFontStyle()
		{
			return this.getTickLabelGroup().getFontStyle();
		}

		public float getTickLabelFontSize()
		{
			return this.getTickLabelGroup().getFontSize();
		}

		public Color getTickLabelColor()
		{
			return this.getTickLabelGroup().getColor(0);
		}

		public boolean isTickLabelHorizontal()
		{
			return (this.getTickLabelGroup().getAngle()==SGElementGroupTickLabel.ANGLE_HORIZONTAL);
		}

		public boolean setTickLabelVisible( final boolean b )
		{
			this.getTickLabelGroup().setVisible(b);
			return true;
		}

		public boolean setTickLabelFontName( final String name )
		{
			return this.getTickLabelGroup().setFontName( name );
		}

		public boolean setTickLabelFontStyle( final int style )
		{
			return this.getTickLabelGroup().setFontStyle( style );
		}

		public boolean setTickLabelFontSize( final float size )
		{
			return this.getTickLabelGroup().setFontSize( size );
		}

		public boolean setTickLabelColor( final Color cl )
		{
			return this.getTickLabelGroup().setColor(cl);
		}


		public boolean setTickLabelHorizontal( final boolean b )
		{
			float angle;
			if(b)
			{
				angle = SGElementGroupTickLabel.ANGLE_HORIZONTAL;
			}
			else
			{
				angle = SGElementGroupTickLabel.ANGLE_INCLINED;
			}
			return this.getTickLabelGroup().setAngle( angle );			
		}



		/**
		 * 
		 * @param e
		 * @param groupSet
		 * @return
		 */
		protected boolean onMouseClicked( final MouseEvent e )
		{
			SGElementGroup group = this.getElementGroupAt( e.getX(), e.getY() );

			int index = -1;
			if( group instanceof ElementGroupLine )
			{
				index = 0;
			}
			else if( group instanceof ElementGroupSymbol )
			{
				index = 1;
			}
			else if( group instanceof ElementGroupBar )
			{
				index = 2;
			}
			else if( group instanceof ElementGroupErrorBar )
			{
				index = 3;
			}
			else if( group instanceof ElementGroupTickLabels )
			{
				index = 4;
			}
			this.mSelectedTabIndex = index;

			return true;
		}


		/**
		 * 
		 */
		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 if( type == SGElementGroup.ERROR_BAR_GROUP )
			{
				group = new ElementGroupErrorBar();
			}
			else if( type == SGElementGroup.TICK_LABEL_GROUP )
			{
				group = new ElementGroupTickLabels();
			}
			else
			{
				throw new Error();
			}

			this.addDrawingElementGroup( group );

			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 SGDrawingElementErrorBar )
			{
				group = new ElementGroupErrorBar();
			}
			else
			{
				throw new Error();
			}

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

			this.addDrawingElementGroup( group );


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


			return true;
		}


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


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

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

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

			this.mTemporaryProperties = null;

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

			notifyChange();

			return true;
		}


		// 設定前の状態に戻す
		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()
		{
			updateSymbolsVisibleAroundFocusedObjects();

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

			return true;
		}



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



		/**
		 * 
		 */
		public int getXAxisConfiguration()
		{
			return SGLegendElement.this.mAxisElement.getConfigurationInPlane( this.getXAxis() );
		}


		/**
		 * 
		 */
		public int getYAxisConfiguration()
		{
			return SGLegendElement.this.mAxisElement.getConfigurationInPlane( this.getYAxis() );
		}



		/**
		 * 
		 */
		public void setAxisConfiguration( final int configX, final int configY )
		{
			SGIAxisElement aElement = SGLegendElement.this.mAxisElement;
			SGAxis xAxis = aElement.getAxisInPlane( configX );
			SGAxis yAxis = aElement.getAxisInPlane( configY );
			this.setXAxis( xAxis );
			this.setYAxis( yAxis );
		}



		boolean synchronizeDrawingElements( ArrayList eList )
		{
			boolean diffFlag = false;
			for( int ii=0; ii<eList.size(); ii++ )
			{
				SGDrawingElement el = (SGDrawingElement)eList.get(ii);

				ArrayList groupList = null;
				if( el instanceof SGDrawingElementErrorBar )
				{
					groupList = this.getErrorBarGroups();
				}
				else if( el instanceof SGDrawingElementLine )
				{
					groupList = this.getLineGroups();
				}
				else if( el instanceof SGDrawingElementSymbol )
				{
					groupList = this.getSymbolGroups();
				}
				else if( el instanceof SGDrawingElementBar )
				{
					groupList = this.getBarGroups();
				}
				else if( el instanceof SGDrawingElementString )
				{
					groupList = this.getTickLabelGroups();
				}

				if( groupList==null )
				{
					continue;
				}
				
				for( int jj=0; jj<groupList.size(); jj++ )
				{
					SGElementGroup group = (SGElementGroup)groupList.get(jj);
					SGDrawingElement elOld = group.getDrawingElement();
					SGProperties p = el.getProperties();
					SGProperties pOld = elOld.getProperties();
					if( p.equals(pOld) == false )
					{
						diffFlag = true;
					}
					group.setProperty(el);
				}
			}

			return diffFlag;
		}


	}



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


	}



	/**
	 * Error bars.
	 *
	 */
	class ElementGroupErrorBar extends SGElementGroupErrorBar
		implements ILegendElement
	{

		/**
		 * Default constructor.
		 */
		ElementGroupErrorBar()
		{
			super();
			if( this.init() == false )
			{
				throw new Error();
			}
		}


		/**
		 * 
		 */
		private boolean init()
		{
			this.setVisible( SGDefaultValues.ERROR_BAR_VISIBLE );

			this.setLineWidth( SGDefaultValues.ERROR_BAR_LINE_WIDTH );
//			this.setLineType( SGDrawingElementLine.LINE_TYPE_SOLID );

			this.setHeadSize( SGDefaultValues.ERROR_BAR_SYMBOL_SIZE );
			Integer n = SGDrawingElementSymbol.getSymbolTypeFromName( SGDefaultValues.ERROR_BAR_SYMBOL_TYPE );
			if( n==null )
			{
				return false;
			}
			this.setHeadType( n.intValue() );
			this.setLineWidth( SGDefaultValues.ERROR_BAR_LINE_WIDTH );

			Integer style = SGDrawingElementErrorBar.getErrorBarStyleFromName( SGDefaultValues.ERROR_BAR_STYLE );
			if( style==null )
			{
				return false;
			}
			this.setErrorBarStyle( style.intValue() );

			this.setColor( SGDefaultValues.ERROR_BAR_COLOR );

			return true;
		}


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



		private static final float ERROR_BAR_HEIGHT = 20.0f;

		/**
		 * 
		 */
		public float getDataElementHeight()
		{
			final float barHeight = this.getMagnification()*ERROR_BAR_HEIGHT;
			final float headSize = this.getHeadSize();
			return barHeight + 2.0f*headSize;
		}


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


		/**
		 * 描画要素の作成
		 */
		public boolean createDrawingElementInLegend()
		{
			SGTuple2f start = new SGTuple2f();
			SGTuple2f end = new SGTuple2f();

			final float mag = this.getMagnification();
			Rectangle2D lRect = getRectOfGroupSet( this.mGroupSet );
			start.x = (float)( lRect.getX() + 0.50f*mag*MIN_WIDTH_DATA_ELEMENT );
			end.x = start.x;

			final float headSize = mag*this.getHeadSize();

			final float y = (float)lRect.getY() + 0.50f*headSize;
			final float h = (float)lRect.getHeight() - headSize;

			final int style = this.getErrorBarStyle();
			switch( style )
			{
				case ERROR_BAR_FULL :
				{
					start.y = y + h;
					end.y = y;
					break;
				}
				
				case ERROR_BAR_LOWER_ONLY :
				{
					start.y = y + h;
					end.y = y + 0.50f*h;
					break;
				}

				case ERROR_BAR_UPPER_ONLY :
				{
					start.y = y + 0.50f*h;
					end.y = y;
					break;
				}

				default :
				{
					throw new Error();				
				}
			}

			this.setLocation( new SGTuple2f[]{start}, new SGTuple2f[]{end} );

			return true;
		}

	}



	/**
	 * 
	 *
	 */
	class ElementGroupTickLabels extends SGElementGroupTickLabel implements ILegendElement
	{
		
		/**
		 * 
		 *
		 */
		ElementGroupTickLabels()
		{
			super();
			if( this.init() == false )
			{
				throw new Error();
			}
		}


		/**
		 * 
		 */
		private boolean init()
		{
			this.setVisible( SGDefaultValues.TICK_LABEL_VISIBLE );

			this.setFont(
				SGDefaultValues.TICK_LABEL_FONT_NAME,
				SGUtilityText.getFontStyle( SGDefaultValues.TICK_LABEL_FONT_STYLE ),
				SGDefaultValues.TICK_LABEL_FONT_SIZE
			);

			final Float angle = SGElementGroupTickLabel.getTickLabelAngleFromName( SGDefaultValues.TICK_LABEL_ANGLE );
			if( angle==null )
			{
				return false;
			}
			this.setAngle( angle.floatValue() );
			this.setColor( SGDefaultValues.TICK_LABEL_COLOR );

			return true;
		}


		/**
		 * 描画要素の作成
		 */
		public boolean createDrawingElementInLegend()
		{
			return true;
		}


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


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


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

	}



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



	}


}

