
package jp.riken.brain.ni.samuraigraph.base;

import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import java.io.*;
import java.math.*;
import java.net.*;
import java.text.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.print.attribute.standard.*;

import org.freehep.util.export.ExportDialog;



/**
 * 描画用ウインドウ
 */

public class SGDrawingWindow extends JFrame
	implements ComponentListener, MouseListener, MouseMotionListener,
		ActionListener, AdjustmentListener, WindowListener, ChangeListener,
		SGIUndoable, SGIPropertySettingListener
{

	public static final String WINDOW_TITLE = "[Window]";
	public static final String KEY_PAPER_WIDTH = "Paper Width";
	public static final String KEY_PAPER_HEIGHT = "Paper Height";
	public static final String KEY_BACKGROUND_COLOR = "Background Color";
	public static final String KEY_GRID_VISIBLE = "Grid Visible";
	public static final String KEY_GRID_INTERVAL = "Grid Interval";
	public static final String KEY_GRID_LINE_WIDTH = "Grid Line Width";
	public static final String KEY_GRID_COLOR = "Grid Line Color";



	/**
	 * ID-number of this window.
	 */
	private int mID;


	/**
	 * Map of figures which belongs to this window.
	 */
	private TreeMap mFigureMap = new TreeMap();


	/**
	 * List of figures which are focused by mouse.
	 */
	protected ArrayList mFocusedFigureList = new ArrayList();


	/**
	 * マウス位置表示用ラベル
	 */
//	private JLabel mPosLabel = new JLabel();


	/**
	 * レイヤ構造を持ったペイン
	 */
	protected JLayeredPane mLayeredPane = new JLayeredPane();


	/**
	 * A panel to draw grid lines.<BR>
	 */
	protected GridPanel mGridPanel = new GridPanel();


	/**
	 * A panel to draw anchors.<BR>
	 */
	protected AnchorPanel mAnchorPanel = new AnchorPanel();


	/**
	 * A panel to draw rulers.<BR>
	 */
	private RulerPanel mRulerPanel = null;


	/**
	 * 水平方向スクロールバー
	 */
	private JScrollBar mHScrollBar = null;


	/**
	 * 垂直方向スクロールバー
	 */
	private JScrollBar mVScrollBar = null;


	/**
	 * 倍率入力テキストフィールド
	 */
	private JComboBox mMagnificationComboBox = null;


	/**
	 * 
	 */
	protected JButton mCreateNewGraphButton = null;


	/**
	 * 
	 */
	protected JButton mDrawGraphButton = null;


	/**
	 * 
	 */
	protected JButton mLoadPropertyButton = null;


	/**
	 * 
	 */
	protected JButton mSaveGraphButton = null;


	/**
	 * 
	 */
	protected JButton mExportImageButton = null;


	/**
	 * 
	 */
	protected JToggleButton mInsertBreakButton = null;


	/**
	 * 
	 */
	protected JButton mBoundingBoxButton = null;


	/**
	 * 
	 */
	protected JToggleButton mAddStringButton = null;


	/**
	 * 
	 */
	protected JToggleButton mAddTimingElementButton = null;


	/**
	 * 
	 */
	protected JToggleButton mAddSignificantSymbolButton = null;


	/**
	 * 
	 */
	protected JToggleButton mLockFigureButton = null;


	/**
	 * Popup menu.
	 */
	private JPopupMenu mPopupMenu = new JPopupMenu();


	/**
	 * Property dialog.
	 */
	private SGWindowDialog mDialog = null;


	/**
	 * Preview dialog.
	 */
	private PreviewDialog mPreviewDialog = null;



	/**
	 * Temporary width of the viewport.
	 */
	protected float mTemporaryViewportWidth = 0.0f;


	/**
	 * Temporary height of the viewport.
	 */
	protected float mTemporaryViewportHeight = 0.0f;


	/**
	 * 
	 */
	protected float mMagnification = 1.0f;



	/**
	 * 
	 */
	private Color mBackgroundColor = SGDefaultValues.WINDOW_BACKGROUND_COLOR;


	/**
	 * 
	 */
	private float mGridInterval = SGDefaultValues.GRID_INTERVAL;



	/**
	 * 
	 */
	private float mGridLineWidth = SGDefaultValues.GRID_LINE_WIDTH;


	/**
	 * 
	 */
	private Color mGridLineColor = SGDefaultValues.GRID_LINE_COLOR;



	/**
	 * 
	 */
	private JToolBar mToolBar = new JToolBar();



	/**
	 * 
	 */
	private boolean mLockFigureFlag = false;


	/**
	 * 
	 */
	protected float mAnchorSize = 6.0f;


	/**
	 * 
	 */
	private boolean mDrawAnchorFlag = true;


	/**
	 * 
	 */
	private float mRulerAxisLineWidth = 2.0f;


	/**
	 * 
	 */
	private float mRulerScaleLineWidth = 1.0f;


	/**
	 * 
	 */
	private Color mRulerLineColor = Color.BLACK;


	/**
	 * 
	 */
	private Color mRulerBackGroundColor;


	/**
	 * 
	 */
	private float mRulerFontSize = 10.0f;


	/**
	 * 
	 */
	public final static int LAYER_GRID_PANEL = 20;


	/**
	 * 
	 */
	public final static int LAYER_FIGURE = 30;


	/**
	 * 
	 */
	public final static int LAYER_ANCHOR_PANEL = 40;


	/**
	 * 
	 */
	public final static int LAYER_RULER_PANEL = 50;



	/**
	 * 
	 */
	public static final int RULER_WIDTH = 20;



	/**
	 * 
	 */
	public static final int MIN_MAGNIFICATION_VALUE = 10;


	/**
	 * 
	 */
	public static final int MAX_MAGNIFICATION_VALUE = 400;


	/**
	 * 
	 */
	public static final int[] MAGNIFICATION_ARRAY
		= {	400, 300, 200, 150, 100, 75, 66, 50, 33, 25 };



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



	/**
	 * この矩形内部の領域がファイル出力の対象となる
	 */
	protected Rectangle2D mPaperRect = new Rectangle2D.Float();



	/**
	 * Bounds of the client area.
	 */
	protected Rectangle2D mClientRect = new Rectangle2D.Float();




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



	/**
	 * 
	 * @return
	 */
	public String toString()
	{
		return new String("SGDrawingWindow:"+this.getID());
	}





	/**
	 * ウインドウの作成。<BR>
	 */
	private boolean create()
	{

		// icon image
		final ImageIcon icon = this.createIcon(SGConstants.RESOURCES_DIRNAME+"Samurai.gif");
		this.setIconImage( icon.getImage() );


		// ポップアップメニューを追加
		this.createPopupMenu();


		// ダイアログを追加
		this.createDialog();


		// メニューバーを追加
		this.setJMenuBar( this.createMenuBar() );


		// スクロールバーを追加
		this.createScrollBars();


		// レイヤペインを追加
		mLayeredPane = new JLayeredPane();
		this.getContentPane().add(
			mLayeredPane, BorderLayout.CENTER );


		// 倍率入力コンボボックスを作成
		this.createMagnificationBox();


		// ツールバーの作成
		this.createToolBar();


		// フィギュアロックボタンに設定
		this.mLockFigureButton.setSelected( this.mLockFigureFlag );


		// グリッド線描画用パネルを作成
		this.createGridPanel();


		// アンカー描画用パネルを作成
		this.createAnchorPanel();


		// ルーラ描画用パネルを作成
		this.createRulerPanel();


		// pack
		this.pack();


		//
//		this.mTemporaryWindowSize = this.getSize();



		//
		this.mAddStringButton.addActionListener(this);
		this.mAddTimingElementButton.addActionListener(this);
		this.mAddSignificantSymbolButton.addActionListener(this);
		this.mSaveGraphButton.addActionListener(this);
		this.mExportImageButton.addActionListener(this);
		this.mDrawGraphButton.addActionListener(this);
		this.mLoadPropertyButton.addActionListener(this);
		this.mInsertBreakButton.addActionListener(this);
		this.mLockFigureButton.addActionListener(this);
		this.mCreateNewGraphButton.addActionListener(this);
		this.mBoundingBoxButton.addActionListener(this);


		// コンポーネントリスナに追加
		this.addComponentListener(this);

		// マウスイベントリスナに追加
		this.addMouseListener(this);

		// マウスモーションリスナに追加
		this.addMouseMotionListener(this);


		// スクロールバーのイベントリスナに追加
		mVScrollBar.addAdjustmentListener(this);
		mHScrollBar.addAdjustmentListener(this);


		// 倍率入力コンボボックスのイベントリスナに追加
		mMagnificationComboBox.addActionListener(this);


		KeyboardFocusManager m = KeyboardFocusManager.getCurrentKeyboardFocusManager();
		m.addKeyEventPostProcessor(
			new KeyEventPostProcessor()
			{
				public boolean postProcessKeyEvent(KeyEvent e)
				{
					switch( e.getID() )
					{
						case KeyEvent.KEY_PRESSED:
						{
//System.out.println("p: " + e.getKeyChar());
							onKeyPressed(e);
							break;
						}
						case KeyEvent.KEY_RELEASED:
						{
//System.out.println("r: " + e.getKeyChar());
							onKeyReleased(e);
							break;
						}
						case KeyEvent.KEY_TYPED:
						{
//System.out.println("t: " + e.getKeyChar());
							onKeyTyped(e);
							break;
						}
						default :
						{
							
						}
					}

					return false;
				}
			}
		);


		// create a preview dialog
		this.createPreviewDialog();


		return true;

	}



	/**
	 * 
	 */
	private Dimension mMinimumWindowSize = new Dimension();



	/**
	 * 
	 * @return
	 */
	public boolean init()
	{

		// set default size
		{
			float width = SGDefaultValues.DEFAULT_VIEWPORT_WIDTH;
			float height = width/SGConstants.GOLDEN_RATIO;
			this.setViewportSize( width, height );
		}


		// set the minimum size
		{
			final int width = this.getInsets().left
				+ this.mMagnificationComboBox.getX()
				+ this.mMagnificationComboBox.getWidth();

			final int height = this.getInsets().top
				+ this.getJMenuBar().getHeight()
				+ this.getToolBarHeight()
				+ SGDrawingWindow.RULER_WIDTH;

			this.mMinimumWindowSize.setSize( width, height );

//System.out.println(this.mMinimumWindowSize);
		}


		// set the temporary size
//		this.mTemporaryWindowSize.setSize( this.getSize() );


		// set the paper rectangle
		this.setPaperOrigin( 0.0f, 0.0f );
		this.setPaperSize( MediaSize.ISO.A4 );


		// set the client rectangle
		this.setClientOrigin( 0.0f, 0.0f );

		this.updateClientRect();
		this.setScrollBarValue();


		// add properties history
		this.addPropertiesHistory();


		return true;
	}



	/**
	 * 
	 * @return
	 */
	private boolean createPreviewDialog()
	{
		String name = "Preview:" + this.getID();
		this.mPreviewDialog = new PreviewDialog(this,"Preview");
		this.mPreviewDialog.hide();

		return true;
	}



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

		mVScrollBar = new JScrollBar( JScrollBar.VERTICAL, 0, 100, 0, 100 );
		mHScrollBar = new JScrollBar( JScrollBar.HORIZONTAL, 0, 100, 0, 100 );
		mVScrollBar.setVisible(false);
		mHScrollBar.setVisible(false);

//mLayeredPane.add( mVScrollBar, BorderLayout.EAST );
//mLayeredPane.setLayer( mVScrollBar, LAYER_RULER_PANEL );

//mLayeredPane.add( mHScrollBar, BorderLayout.SOUTH );
//mLayeredPane.setLayer( mHScrollBar, LAYER_RULER_PANEL );

		this.getContentPane().add( mVScrollBar, BorderLayout.EAST );
		this.getContentPane().add( mHScrollBar, BorderLayout.SOUTH );
		{
			final int min = mHScrollBar.getMinimum();
			final int max = mHScrollBar.getMaximum();
			final int extent = mHScrollBar.getVisibleAmount();
			mHScrollBar.setValue( (max - extent - min)/2 );
//System.out.println("h: "+min+"  "+max+"  "+extent);
		}
		{
			final int min = mVScrollBar.getMinimum();
			final int max = mVScrollBar.getMaximum();
			final int extent = mVScrollBar.getVisibleAmount();
			mVScrollBar.setValue( (max - extent - min)/2 );
//System.out.println("v: "+min+"  "+max+"  "+extent);
		}
//System.out.println();


		this.setScrollBarProperty();


		return true;
	}



	/**
	 * name : name of resource file
	 */
	private ImageIcon createIcon( final String name )
	{
		if( name==null )
		{
			return null;
		}

		Class inClass = getClass();
		URL url = inClass.getResource(name);

//System.out.println(url);

		ImageIcon icon;
		if( url!=null )
		{
			icon = new ImageIcon(url);
		}
		else
		{
			icon = new ImageIcon(name);
		}

		return icon;
	}
	


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

/*
		// マウス位置表示用ラベルを設定
		mPosLabel = new JLabel("(00.0, 00.0)");
		mPosLabel.setVisible(true);
		mPosLabel.setOpaque(false);
		Dimension dimension = mPosLabel.getPreferredSize();
		mPosLabel.setPreferredSize(
			new Dimension( (int)dimension.getWidth(), (int)dimension.getHeight() ) );
*/

		// 倍率入力コンボボックスを設定
		final Dimension dimMag = mMagnificationComboBox.getPreferredSize();


		mMagnificationComboBox.setPreferredSize(
			new Dimension( (int)dimMag.getWidth()/2, (int)dimMag.getHeight() ) );


		// アイコンを作成してボタンに登録

		final ImageIcon iconNewGraph = this.createIcon(SGConstants.RESOURCES_DIRNAME+"NewGraph.gif");
		this.mCreateNewGraphButton = new JButton(iconNewGraph);
		this.mCreateNewGraphButton.setToolTipText("ウインドウの新規作成");

		final ImageIcon iconDrawGraph = this.createIcon(SGConstants.RESOURCES_DIRNAME+"DrawGraph.gif");
		this.mDrawGraphButton = new JButton(iconDrawGraph);
		this.mDrawGraphButton.setToolTipText("グラフの描画");

		final ImageIcon iconLoadProperty = this.createIcon(SGConstants.RESOURCES_DIRNAME+"LoadProperty.gif");
		this.mLoadPropertyButton = new JButton(iconLoadProperty);
		this.mLoadPropertyButton.setToolTipText("プロパティの読み込み");

		final ImageIcon iconSaveGraph = this.createIcon(SGConstants.RESOURCES_DIRNAME+"SaveGraph.gif");
		this.mSaveGraphButton = new JButton(iconSaveGraph);
		this.mSaveGraphButton.setToolTipText("プロパティの保存");

		final ImageIcon iconExportImage = this.createIcon(SGConstants.RESOURCES_DIRNAME+"ExportImage.gif");
		this.mExportImageButton = new JButton(iconExportImage);
		this.mExportImageButton.setToolTipText("画像ファイルへの保存");

		final ImageIcon iconBoundingBox = this.createIcon(SGConstants.RESOURCES_DIRNAME+"BoundingBox.gif");
		this.mBoundingBoxButton = new JButton(iconBoundingBox);
		this.mBoundingBoxButton.setToolTipText("バウンディングボックスの設定");

		final ImageIcon iconString = this.createIcon(SGConstants.RESOURCES_DIRNAME+"InsertString.gif");
		this.mAddStringButton = new JToggleButton(iconString);
		this.mAddStringButton.setToolTipText("ラベルの挿入");

		final ImageIcon iconSignificant = this.createIcon(SGConstants.RESOURCES_DIRNAME+"InsertSig.gif");
		this.mAddSignificantSymbolButton = new JToggleButton(iconSignificant);
		this.mAddSignificantSymbolButton.setToolTipText("有意差シンボルの挿入");

		final ImageIcon iconBreak = this.createIcon(SGConstants.RESOURCES_DIRNAME+"InsertBreak.gif");
		this.mInsertBreakButton = new JToggleButton(iconBreak);
		this.mInsertBreakButton.setToolTipText("軸のブレイクシンボルの挿入");

		final ImageIcon iconTiming = this.createIcon(SGConstants.RESOURCES_DIRNAME+"InsertTiming.gif");
		this.mAddTimingElementButton = new JToggleButton(iconTiming);
		this.mAddTimingElementButton.setToolTipText("タイミング線の挿入");

		final ImageIcon iconLock = this.createIcon(SGConstants.RESOURCES_DIRNAME+"UnlockFigure.gif");
		this.mLockFigureButton = new JToggleButton(iconLock);
		this.mLockFigureButton.setToolTipText("フィギュアをウインドウにロック");


		// ツールバーにコンポーネントを追加
		this.mToolBar.add(this.mCreateNewGraphButton);
		this.mToolBar.add(this.mDrawGraphButton);
		this.mToolBar.add(this.mLoadPropertyButton);
		this.mToolBar.add(this.mSaveGraphButton);
		this.mToolBar.add(this.mExportImageButton);
		this.mToolBar.add(this.mBoundingBoxButton);
		this.mToolBar.addSeparator();
		this.mToolBar.add(this.mAddStringButton);
		this.mToolBar.add(this.mAddSignificantSymbolButton);
		this.mToolBar.add(this.mInsertBreakButton);
		this.mToolBar.addSeparator();
		this.mToolBar.add(this.mAddTimingElementButton);
		this.mToolBar.addSeparator();
		this.mToolBar.add(this.mLockFigureButton);
		this.mToolBar.addSeparator();
		this.mToolBar.add(mMagnificationComboBox);
//		this.mToolBar.addSeparator();
//		this.mToolBar.add(mPosLabel);


		this.mMagnificationComboBox.setMaximumSize(
			new Dimension( 100, 100 ) );

		this.getContentPane().add( this.mToolBar, BorderLayout.NORTH );
		this.mToolBar.setFloatable( false );

		return true;
	}



	/**
	 * 
	 */
	private int getToolBarHeight()
	{
		return this.mToolBar.getHeight();
	}



	/**
	 * 
	 */
	private boolean  setLockToggleButton( final boolean flag )
	{

		ImageIcon iconLock;
		if( flag )
		{
			iconLock = this.createIcon(SGConstants.RESOURCES_DIRNAME+"LockFigure.gif");
		}
		else
		{
			iconLock = this.createIcon(SGConstants.RESOURCES_DIRNAME+"UnlockFigure.gif");
		}

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

		this.mLockFigureButton.setIcon( iconLock );

		return true;
	}




	/**
	 * 
	 * @return
	 */
	private boolean createGridPanel()
	{
		mGridPanel = new GridPanel();
		mGridPanel.setVisible(true);
		mGridPanel.setOpaque(true);

		mLayeredPane.add( mGridPanel );
		mLayeredPane.setLayer( mGridPanel, LAYER_GRID_PANEL );

		return true;
	}



	/**
	 * 
	 */
	private boolean createMagnificationBox()
	{
		this.mMagnificationComboBox = new JComboBox();
		
		final Object[] items = new Integer[MAGNIFICATION_ARRAY.length];
		for( int ii=0; ii<items.length; ii++ )
		{
			items[ii] = new Integer( MAGNIFICATION_ARRAY[ii] );
		}

		for( int ii=0; ii<MAGNIFICATION_ARRAY.length; ii++ )
		{
			this.mMagnificationComboBox.addItem( items[ii] );
		}

		this.mMagnificationComboBox.setSelectedItem( new Integer(100) );
		this.mMagnificationComboBox.setEditable( true );
		this.mMagnificationComboBox.setBackground( Color.WHITE );
		this.mMagnificationComboBox.setToolTipText("ズーム");

		return true;
	}



	/**
	 * 
	 */
	private boolean createAnchorPanel()
	{
		mAnchorPanel = new AnchorPanel();
		mAnchorPanel.setVisible(true);
		mAnchorPanel.setOpaque(false);
		mLayeredPane.add(mAnchorPanel);
		mLayeredPane.setLayer( mAnchorPanel, LAYER_ANCHOR_PANEL );

		return true;
	}



	/**
	 * 
	 * @return
	 */
	private boolean createRulerPanel()
	{
		mRulerPanel = new RulerPanel();
		mRulerPanel.setVisible(true);
		mRulerPanel.setOpaque(false);
		mRulerBackGroundColor = this.getBackground();
//mRulerBackGroundColor = Color.YELLOW;
		mRulerLineColor = Color.BLACK;
		mLayeredPane.add(mRulerPanel);
		mLayeredPane.setLayer( mRulerPanel, LAYER_RULER_PANEL );

		return true;
	}



	/**
	 * 
	 */
	private boolean createPopupMenu()
	{

/*
		mPopupMenu.setBounds( 0, 0, 100, 100 );


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

		return true;
	}



	/**
	 * 
	 */
	private boolean createDialog()
	{
		this.mDialog = new SGWindowDialog(this,true);
		return true;
	}










//
//	set/getメソッド
//


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



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



	/**
	 * 
	 */
	public float getGridLineWidth()
	{
		return this.mGridLineWidth;
	}


	/**
	 * 
	 */
	public Color getGridLineColor()
	{
		return this.mGridLineColor;
	}



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


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


	/**
	 * 
	 */
	public boolean setBackgroundColor( final Color color )
	{
		if( this.mGridPanel == null )
		{
			return false;
		}

		this.mBackgroundColor = color;

		return true;
	}



	/**
	 * 
	 */
	public boolean setGridInterval( final float interval )
	{
		this.mGridInterval = interval;
		return true;
	}



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



	/**
	 * 
	 * @return
	 */
	public int getCurrentFigureId()
	{
		int id;
		if( this.mFigureMap.size()==0 )
		{
			id = 1;
		}
		else
		{
			id = ((Integer)this.mFigureMap.lastKey()).intValue() + 1;
		}
		return id;
	}


	/**
	 * 
	 */
//	private JToolBar mBottomToolBar = new JToolBar();



	/**
	 * 
	 * @return
	 */
	public int getTopWidth()
	{
		final Insets insets = this.getInsets();
		final int iTop = insets.top;

		// メニューバーの幅
		final JMenuBar menuBar = this.getJMenuBar();
		final int menuBarWidth = menuBar.getHeight();

		// ツールバーの幅
		final int toolBarWidth = this.getToolBarHeight();

		final int width = iTop + menuBarWidth + toolBarWidth;

		return width;
	}



	/**
	 * 
	 * @return
	 */
	public int getBottomWidth()
	{
		final Insets insets = this.getInsets();
		final int iBottom = insets.bottom;
		
//		final int toolBarWidth = this.mBottomToolBar.getHeight();
//		final int width = iBottom + toolBarWidth;
//		return width;

		return iBottom;
	}



	/**
	 * 
	 * @return
	 */
	public int getLeftWidth()
	{
		final Insets insets = this.getInsets();
		final int iLeft = insets.left;
		return iLeft;
	}



	/**
	 * 
	 * @return
	 */
	public int getRightWidth()
	{
		final Insets insets = this.getInsets();
		final int iRight = insets.right;
		return iRight;
	}










//
//	フィギュア関係
//


	/**
	 * 
	 */
	public TreeMap getFigureMap()
	{
		return this.mFigureMap;
	}



	/**
	 * ウインドウにフィギュアを追加
	 * @param figure フィギュア
	 * @return true:成功、false:失敗
	 */
	public boolean addFigure( final int id, final SGFigure figure )
	{
//System.out.println("<< addFigure >>");

		this.addFigurePrev( id, figure );

		this.addFigureAfter( figure );

		return true;

	}



	/**
	 * ウインドウにフィギュアを追加
	 * @param figure フィギュア
	 * @return true:成功、false:失敗
	 */
	public boolean addFigure(
		final int id, final SGFigure figure, final int x, final int y )
	{

		this.addFigurePrev( id, figure );


		Point2D location = this.getLocationOnFigure(x,y);
		figure.setGraphAreaLocation(
			(float)location.getX(), (float)location.getY()
		);

		figure.drawbackFigure();


		this.addFigureAfter( figure );



		return true;
	}



	private boolean addFigureAfter( final SGFigure figure )
	{

		// initialize the rectangle for dragging
		figure.setDraggingRect();

		//
		this.updateHistory();

		repaint();

		return true;
	}



	private boolean addFigurePrev( final int id, final SGFigure figure )
	{
		// IDをセット
		figure.setID(id);


		// マップに追加
		this.mFigureMap.put( new Integer(id), figure );


		// レイヤペインに追加
		this.mLayeredPane.setLayer( figure, LAYER_FIGURE );
		this.mLayeredPane.add( figure );


		// set the location and the size
		SGTuple2f vpSize = this.getViewportSize();
		figure.setLocation( SGDrawingWindow.RULER_WIDTH, SGDrawingWindow.RULER_WIDTH );
		figure.setSize( (int)vpSize.x, (int)vpSize.y );
		SGIFigureElement[] array = figure.getIFigureElementArray();
		for( int ii=0; ii<array.length; ii++ )
		{
			array[ii].setISize( new SGTuple2f( vpSize.x, vpSize.y ) );
		}


		// フィギュアにビュー領域を設定
		figure.setViewBounds();


		// 倍率に合わせてズーム
		this.zoom( this.mMagnification );

		return true;
	}




	/**
	 * 
	 * @return
	 */
	public SGFigure[] getFigureArrayFromMap()
	{
		SGFigure[] array = new SGFigure[this.mFigureMap.size()];
		Iterator itr = this.mFigureMap.values().iterator();
		int cnt = 0;
		while( itr.hasNext() )
		{
			array[cnt] = (SGFigure)itr.next();
			cnt++;
		}
		return array;
	}



	/**
	 * 
	 */
	public SGFigure[] getFigureArrayFromLayer()
	{
		Component[] cArray = this.mLayeredPane.getComponentsInLayer( LAYER_FIGURE );
		SGFigure[] fArray = new SGFigure[cArray.length];
		for( int ii=0; ii<fArray.length; ii++ )
		{
			fArray[ii] = (SGFigure)cArray[ii];
		}
		return fArray;
	}



	/**
	 * 
	 * @return
	 */
	public ArrayList getVisibleFigureListFromMap()
	{
		SGFigure[] array = this.getFigureArrayFromMap();
		ArrayList list = new ArrayList();
		for( int ii=0; ii<array.length; ii++ )
		{
			if( array[ii].isVisible() )
			{
				list.add( array[ii] );
			}
		}
		return list;
	}



	/**
	 * 
	 * @return
	 */
	public ArrayList getVisibleFigureListFromLayer()
	{
		SGFigure[] array = this.getFigureArrayFromLayer();
		ArrayList list = new ArrayList();
		for( int ii=0; ii<array.length; ii++ )
		{
			if( array[ii].isVisible() )
			{
				list.add( array[ii] );
			}
		}
		return list;
	}




	/**
	 * 
	 * @return
	 */
	public boolean drawBackAllVisibleFigures()
	{
		ArrayList list = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure fig = (SGFigure)list.get(ii);
			if( fig.drawbackFigure() == false )
			{
				return false;
			}
		}
		return true;
	}




	/**
	 *
	 */
	public SGFigure getFigure( final int id )
	{
		return (SGFigure)mFigureMap.get( new Integer(id) );
	}



	/**
	 * 選択されたフィギュアを一時的に非表示にする。
	 * 本当に削除するのは、履歴で異なる方向に枝分かれした場合のみ。
	 */
	protected boolean hideSelectedFigures()
	{
//System.out.println("<< hideSelectedFigure >>");

		for( int ii=0; ii<this.mFocusedFigureList.size(); ii++ )
		{
			final SGFigure figure = (SGFigure)this.mFocusedFigureList.get(ii);
			figure.setVisible( false );
		}
		

		//
//		this.updateChildDifferenceHistoryList( this.mFocusedFigureList, false );

//System.out.println(this.mChildDifferenceFlagList);
//System.out.println(this.mChildDifferenceHistoryList);
//System.out.println();


		//
		this.updateHistory();


		// clear the list
		this.mFocusedFigureList.clear();
				
		this.repaint();


		return true;
	}



	/**
	 * 
	 */
	public boolean removeFigure( final ArrayList list )
	{

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

		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			if( this.removeFigure( figure ) == false )
			{
				return false;
			}
		}

		return true;
	}




	/**
	 * フィギュアの削除
	 */
	protected boolean removeFigure( final SGFigure figure )
	{

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

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


		// マップから削除
		this.mFigureMap.remove( new Integer( figure.getID() ) );
//System.out.println(figure.getID());

		// JLayeredPaneから削除
		this.mLayeredPane.remove( figure );

		return true;

	}



	/**
	 * 
	 */
	protected boolean setFigureVisible( final SGFigure figure, final boolean flag )
	{
		if( figure==null )
		{
			return false;
		}
		figure.setVisible(flag);
		this.mFocusedFigureList.clear();

		return true;
	}



	/**
	 * 
	 * @return
	 */
	protected boolean clearFocusedFigures()
	{
		for( int ii=0; ii<this.mFocusedFigureList.size(); ii++ )
		{
			SGFigure fig = (SGFigure)this.mFocusedFigureList.get(ii);
			fig.clearSelectedElements();
		}
		this.mFocusedFigureList.clear();

		return true;
	}




	/**
	 * 
	 * @param x	X-coordinate on the window.
	 * @param y	Y-coordinate on the window.
	 * @return
	 */
	public Point2D getLocationOnFigure( final int x, final int y )
	{
		float xx = x - this.getLeftWidth() - RULER_WIDTH;
		float yy = y - this.getTopWidth() - RULER_WIDTH;
		return new Point2D.Float(xx,yy);
	}







//
// スクロールバー関連
//

	/**
	 * 
	 */
	protected boolean setScrollValue(
		final JScrollBar bar, final double ratio )
	{

		final int min = bar.getMinimum();
		final int max = bar.getMaximum();
		final int extent = bar.getVisibleAmount();

		final int num = max - min - extent;		
		final double value = ratio*num;

		bar.setValue( (int)value );

		return true;
	}



	/**
	 * スクロールバーの値を取得
	 */
	protected float getScrollValue( final JScrollBar bar )
	{

		final int min = bar.getMinimum();
		final int max = bar.getMaximum();
		final int extent = bar.getVisibleAmount();

		if( max - min -extent == 0 )
		{
			return 0.0f;
		}

		final float ratio = (float)bar.getValue()/(float)(max-min-extent);

		return ratio;
	}



	/**
	 * 水平スクロールバーの値を取得
	 */
	protected float getHScrollValue()
	{
		return this.getScrollValue( this.mHScrollBar );
	}


	/**
	 * 垂直スクロールバーの値を取得
	 */
	protected float getVScrollValue()
	{
		return this.getScrollValue( this.mVScrollBar );
	}



	/**
	 * 
	 */
	private boolean setScrollBarProperty()
	{
//System.out.println("<<< setScrollBarProperty >>>");

		// スクロールバーから情報を取得
		final int vMax = this.mVScrollBar.getMaximum();
		final int vMin = this.mVScrollBar.getMinimum();
		final int hMax = this.mHScrollBar.getMaximum();
		final int hMin = this.mHScrollBar.getMinimum();
		final int vValueOld = this.mVScrollBar.getValue();
		final int hValueOld = this.mHScrollBar.getValue();
		final int vExtentOld = this.mVScrollBar.getVisibleAmount();
		final int hExtentOld = this.mHScrollBar.getVisibleAmount();


		// 現在のvalueの[min,max-extent]区間での比を求める
		final double vRatio = (double)( vValueOld - vMin )/(double)( vMax - vExtentOld - vMin );
		final double hRatio = (double)( hValueOld - hMin )/(double)( hMax - hExtentOld - hMin );


		// スクロールバーのノブの長さの設定
		final int vExtent = (int)( (double)(vMax-vMin)/this.mMagnification );
		final int hExtent = (int)( (double)(hMax-hMin)/this.mMagnification );


		this.mVScrollBar.setVisibleAmount(vExtent);
		this.mHScrollBar.setVisibleAmount(hExtent);


		//
		// valueの設定
		//

		final int vValue = (int)( vMin + vRatio*(vMax-vExtent-vMin) );
		final int hValue = (int)( hMin + hRatio*(hMax-hExtent-hMin) );
		this.mVScrollBar.setValue(vValue);
		this.mHScrollBar.setValue(hValue);


//System.out.println(vValue+"  "+hValue);
//System.out.println(vExtent+"  "+hExtent);

//System.out.println(this.mVScrollBar.getVisibleAmount());
//System.out.println(this.mHScrollBar.getVisibleAmount());
//System.out.println();


		return true;
	}



	/**
	 * 
	 * @return
	 */
	private boolean setScrollBarValue()
	{
//System.out.println("<< setScrollBarValue >>");

		if( this.mHScrollBar.isVisible() )
		{
			this.setScrollBarValue( true );
		}

		if( this.mVScrollBar.isVisible() )
		{
			this.setScrollBarValue( false );
		}

		return true;
	}



	private boolean setScrollBarValue( final boolean flag )
	{
//System.out.println(flag);

		Rectangle2D cRect = this.getClientRectZoomed();
		Rectangle2D vpRect = this.getViewportBoundsInClientRect();

		JScrollBar bar = null;
		float cLength = 0.0f;
		float vpMin = 0.0f;
		float vpLength = 0.0f;

		if( flag )
		{
			bar = this.mHScrollBar;
			cLength = (float)cRect.getWidth();
			vpMin = (float)vpRect.getX();
			vpLength = (float)vpRect.getWidth();
		}
		else
		{
			bar = this.mVScrollBar;
			cLength = (float)cRect.getHeight();
			vpMin = (float)vpRect.getY();
			vpLength = (float)vpRect.getHeight();
		}

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


//System.out.println("vp:"+(vpLength)*SGConstants.CM_POINT_RATIO/this.mMagnification+"cm");
//System.out.println("cl:"+(cLength)*SGConstants.CM_POINT_RATIO/this.mMagnification+"cm");

		final int min = bar.getMinimum();
		final int max = bar.getMaximum();
		final int extent = (int)( (vpLength/cLength)*( max - min ) );
		bar.setVisibleAmount( extent );

//System.out.println(min+"  "+max+"  "+extent);

		final float ratio = vpMin/( cLength - vpLength );
		final int value = min + (int)( ratio*( max - extent - min ) );
//System.out.println("+++");
		bar.setValue(value);
//System.out.println("---");

//System.out.println("@@@  "+"  "+ratio+"  "+value);

//System.out.println("@@@ "+ratio+"  "+bar.getValue()+"  "+value);

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

		return true;
	}






//
// ウインドウ内領域関係
//



	/**
	 * ビューポートのサイズを取得する
	 */
	public SGTuple2f getViewportSize()
	{
		final SGTuple2f size = this.getPaneSize();
		size.x -= SGDrawingWindow.RULER_WIDTH;
		size.y -= SGDrawingWindow.RULER_WIDTH;
		return size;
	}



	/**
	 * Returns the size of pane.
	 */
	public SGTuple2f getPaneSize()
	{

		// ボーダ領域の寸法を取得
		final Insets insets = this.getInsets();
		final int iTop = insets.top;
		final int iBottom = insets.bottom;
		final int iLeft = insets.left;
		final int iRight = insets.right;

		// メニューバーの幅
		final JMenuBar menuBar = this.getJMenuBar();
		final int menuBarWidth = menuBar.getHeight();

		// ツールバーの幅
		final int toolBarWidth = this.getToolBarHeight();


		// サイズを設定
		final float sizeX = this.getWidth() - ( iLeft + iRight );
		final float sizeY = this.getHeight() - (
			iTop + iBottom + menuBarWidth + toolBarWidth );

		final SGTuple2f size = new SGTuple2f( sizeX, sizeY );

		return size;
	}



	/**
	 * 
	 */
	public boolean setPaperRect( final Rectangle2D rect )
	{
		this.mPaperRect.setRect(rect);
		return true;
	}



	/**
	 * 紙の矩形を設定する
	 */
	public boolean setPaperRect(
		final float x, final float y,
		final float width, final float height )
	{
		this.mPaperRect.setRect(
			x,
			y,
			width,
			height
		);
		return true;
	}



	/**
	 * 
	 * @param x
	 * @param y
	 * @return
	 */
	public boolean setPaperOrigin( final float x, final float y )
	{
		this.setPaperRect(
			x,
			y,
			(float)this.mPaperRect.getWidth(),
			(float)this.mPaperRect.getHeight()
		);
		return true;
	}



	/**
	 * 
	 * @param w
	 * @param h
	 * @return
	 */
	public boolean setPaperSize( final float w, final float h )
	{
		this.setPaperRect(
			(float)this.mPaperRect.getX(),
			(float)this.mPaperRect.getY(),
			w,
			h
		);
		return true;
	}



	/**
	 * 
	 */
	public Rectangle2D getPaperRect()
	{
		Rectangle2D pRect = this.mPaperRect;
		Rectangle2D rect = new Rectangle2D.Float();
		rect.setRect(
			pRect.getX(),
			pRect.getY(),
			this.mMagnification*pRect.getWidth(),
			this.mMagnification*pRect.getHeight()
		);
		return rect;
	}



	public static float PAPER_MARGIN = 1.5f/SGConstants.CM_POINT_RATIO;


	/**
	 * 
	 * @return
	 */
	public Rectangle2D getBoundingBox()
	{
		Rectangle2D rect = new Rectangle2D.Float();
		Rectangle2D pRect = this.mPaperRect;
		rect.setRect(
			pRect.getX(),
			pRect.getY(),
			pRect.getWidth() + PAPER_MARGIN,
			pRect.getHeight() + PAPER_MARGIN
		);

		return rect;
	}



	/**
	 * 
	 * @return
	 */
	public Rectangle2D getBoundingBoxZoomed()
	{
		Rectangle2D rect = new Rectangle2D.Float();
		Rectangle2D pRect = this.getPaperRect();
		rect.setRect(
			pRect.getX(),
			pRect.getY(),
			pRect.getWidth() + this.mMagnification*PAPER_MARGIN,
			pRect.getHeight() + this.mMagnification*PAPER_MARGIN
		);

		return rect;
	}




	/**
	 * ピクセル単位でビューポートのサイズを指定
	 * 指定されたサイズを元にウインドウの全サイズを決定し、設定する
	 */
	public boolean setViewportSize(
		final float width, final float height )
	{

		this.mTemporaryViewportWidth = width;
		this.mTemporaryViewportHeight = height;


		// ボーダ領域の寸法を取得
		final Insets insets = this.getInsets();
		final int iTop = insets.top;
		final int iBottom = insets.bottom;
		final int iLeft = insets.left;
		final int iRight = insets.right;

//System.out.println("insets:"+insets);
//System.out.println();

		// メニューバーの幅
		final JMenuBar menuBar = this.getJMenuBar();
		final int menuBarWidth = menuBar.getHeight();

//System.out.println("menuBar:"+menuBar);
//System.out.println();


		// ツールバーの幅
		final int toolBarWidth = this.getToolBarHeight();

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


		// サイズを設定
		final float sizeX = width + (float)( iLeft + iRight + RULER_WIDTH );
		final float sizeY = height + (float)(
			iTop + iBottom + menuBarWidth + toolBarWidth + RULER_WIDTH );
		this.setSize( (int)sizeX, (int)sizeY );


		return true;

	}



	/**
	 * ウインドウリサイズ時に行われる処理
	 */
	private boolean onResized()
	{
//System.out.println("*** onResized ***");

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


		// set the size of the components
		SGTuple2f paneSize = this.getPaneSize();
		this.mLayeredPane.setSize( (int)paneSize.x, (int)paneSize.y );
		this.mGridPanel.setBounds();
		this.mAnchorPanel.setBounds();
		this.mRulerPanel.setBounds();


		// get and record the size of viewport
		final SGTuple2f size = this.getViewportSize();


		// リサイズ前後の変化量
		final float diffX = size.x - this.mTemporaryViewportWidth;;
		final float diffY = size.y - this.mTemporaryViewportHeight;
//System.out.println(diffX*SGConstants.CM_POINT_RATIO+"cm  "+diffY*SGConstants.CM_POINT_RATIO+"cm");


		// ratio of the viewport size
		final float ratioX = size.x/this.mTemporaryViewportWidth;
		final float ratioY = size.y/this.mTemporaryViewportHeight;

//System.out.println("ratio: "+ratioX+"  "+ratioY);

//System.out.println("11111");
//this.dumpRect();
//System.out.println();


		// リサイズに伴い、クライアント領域のサイズを変更する
		this.setClientSize(
			(float)( this.getClientRectZoomed().getWidth() + diffX )/this.mMagnification,
			(float)( this.getClientRectZoomed().getHeight() + diffY )/this.mMagnification
		);


//System.out.println("22222");
//this.dumpRect();
//System.out.println();


		//
		this.updateClientRect();

//System.out.println("33333");
//this.dumpRect();
//System.out.println();


		//
		this.setScrollBarValue();



		// resize the figures
		SGTuple2f vpSize = this.getViewportSize();
		ArrayList list = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.updateFigureRect();
			figure.setSize( vpSize );
			figure.setViewBounds();
		}



		// when the figures are locked
		if( this.mLockFigureFlag )
		{

			// resize the paper
			Rectangle2D pRect = this.getPaperRect();
//System.out.println(pRect);
			final float pWidth = ratioX*(float)pRect.getWidth();
			final float pHeight = ratioY*(float)pRect.getHeight();
			this.setPaperSize( pWidth, pHeight );
//System.out.println(this.getPaperRect());
//System.out.println();

			// resize the figures
			for( int ii=0; ii<list.size(); ii++ )
			{
				SGFigure figure = (SGFigure)list.get(ii);
				figure.updateFigureRect();
				figure.resize( ratioX, ratioY );
			}

			//
			this.updateClientRect();
			this.setScrollBarValue();


			// update the history
			ArrayList objList = new ArrayList();
			for( int ii=0; ii<list.size(); ii++ )
			{
				SGFigure figure = (SGFigure)list.get(ii);
				if( figure.isFigureMoved() )
				{
					final boolean flag = figure.updateHistory();
					if( !flag )
					{
						return false;
					}
					objList.add(figure);
				}
			}


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


			//
			objList.add(this);


			// updata the history
			boolean flag = this.updateObjectHistory( objList );
			if( !flag )
			{
				return false;
			}

			
		}



		//
		this.mTemporaryViewportWidth = size.x;
		this.mTemporaryViewportHeight = size.y;


		this.repaint();


		return true;
	}




	/**
	 * 
	 * @return
	 */
	private boolean onZoomed()
	{
//System.out.println("<< onZoomed() >>");

		//
		// check
		//

		// cl：倍率＝（クライアント領域）／（ウインドウペイン）×100
		float cl = 0.0f;
		try
		{
			Object obj = this.mMagnificationComboBox.getSelectedItem();
			cl = Float.valueOf( obj.toString() ).floatValue();
		}
		catch( NumberFormatException ex )
		{
			this.mMagnificationComboBox.setSelectedItem(
				new Integer( (int)(this.mMagnification*100.0f) ) );
System.out.println("数値を入力して下さい。");
			return false;
		}
		if( cl < 0.0 )
		{
			this.mMagnificationComboBox.setSelectedItem(
				new Integer( (int)(this.mMagnification*100.0f) ) );
System.out.println("正の数値を入力して下さい。");
			return false;
		}
		if( cl < MIN_MAGNIFICATION_VALUE )
		{
			this.mMagnificationComboBox.setSelectedItem(
				new Integer( MIN_MAGNIFICATION_VALUE ) );
		}
		if( cl > MAX_MAGNIFICATION_VALUE )
		{
			this.mMagnificationComboBox.setSelectedItem(
				new Integer( MAX_MAGNIFICATION_VALUE ) );
		}


		// zoom
		if( this.zoom( cl/100.0f ) == false )
		{
			return false;
		}

		return true;

	}



	/**
	 * 
	 */
	private boolean zoom( final float cl )
	{
////System.out.println("zoom");

		//
		this.mMagnification = cl;


		// zoom figures
		ArrayList list = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			boolean flag = figure.zoom( mMagnification );
			if( !flag )
			{
				return false;
			}
		}


		//
		this.updateClientRect();


		//
		this.setScrollBarValue();


		this.repaint();


		return true;
	}




	/**
	 * 
	 */
	public boolean setFigureBoundingBox( final int mode )
	{
//System.out.println("<< setFigureBoundingBox >>");
//System.out.println("mode="+mode);

		if( mode!=0 && mode!=1 && mode!=2 )
		{
			return false;
		}

		ArrayList rectList = new ArrayList();
		ArrayList fList = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<fList.size(); ii++ )
		{
			SGFigure figure = (SGFigure)fList.get(ii);
			rectList.add( figure.getBoundingBox() );
		}
		Rectangle2D bbRect = SGUtility.createUnion( rectList );
		if( bbRect==null )
		{
			return false;
		}
//System.out.println(bbRect);

		Rectangle2D cRect = this.getClientRectZoomed();
		Rectangle2D pRect = this.getPaperRect();
		float width = (float)pRect.getWidth()/this.mMagnification;
		float height = (float)pRect.getHeight()/this.mMagnification;
		if( mode==0 || mode==1 )
		{
			width = (float)( - cRect.getX() + bbRect.getX() + bbRect.getWidth() )/this.mMagnification;
		}
		if( mode==0 || mode==2 )
		{
			height = (float)( - cRect.getY() + bbRect.getY() + bbRect.getHeight() )/this.mMagnification;
		}

//System.out.println(width*this.mMagnification+"  "+height*this.mMagnification);
//System.out.println();

		this.setPaperSize( width, height );

		this.updateClientRect();
		this.setScrollBarValue();

//System.out.println();

		return true;
	}



	/**
	 * 引数で渡された全てのフィギュアを外包するような矩形を返す。
	 */
	public Rectangle2D getBoundingBoxOfFigures( final ArrayList figureList )
	{

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

		if( figureList.size() == 0 )
		{
			return new Rectangle2D.Float();
		}


		ArrayList list = new ArrayList();
		for( int ii=0; ii<figureList.size(); ii++ )
		{
			final SGFigure figure = (SGFigure)figureList.get(ii);
			if( figure==null )
			{
				continue;
			}

			Rectangle r = figure.getBounds();
			Rectangle2D rect = new Rectangle2D.Float(
				(float)r.getX(),
				(float)r.getY(),
				(float)r.getWidth(),
				(float)r.getHeight()
			);
			list.add( rect );
		}

		Rectangle2D rectAll = SGUtility.createUnion(list);


		return rectAll;

	}



	/**
	 * 調整値が変更されると呼び出されます。
	 */
	public void adjustmentValueChanged(
		final AdjustmentEvent e)
	{
//System.out.println("adjustmentValueChanged");


		Object source = e.getSource();

		if( source instanceof JScrollBar )
		{

			JScrollBar bar = (JScrollBar)source;

//System.out.println(bar.getValue());

			// クライアント領域の位置の設定
			if( bar.equals( this.mHScrollBar ) )
			{
				this.setClientRectByValueOfScrollBar( true );
			}
			else if( bar.equals( this.mVScrollBar ) )
			{
				this.setClientRectByValueOfScrollBar( false );
			}


			// グリッド用のパネルの再設定
			// 常にクライアント領域の原点と一致させる
			Rectangle2D cRect = this.getClientRect();
			this.setPaperOrigin(
				(float)cRect.getX(),
				(float)cRect.getY()
			);


			//
			{
				ArrayList list = this.getVisibleFigureListFromMap();
				for( int ii=0; ii<list.size(); ii++ )
				{
					SGFigure figure = (SGFigure)list.get(ii);

					// フィギュアのboundsを再設定
					figure.setGraphAreaRectToFigureElement();
				}
			}


			this.repaint();


//System.out.println(bar.getValue());
//System.out.println();

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

		}


	}



	private boolean setClientRectByValueOfScrollBar( final boolean flag )
	{

		JScrollBar bar = null;
		if( flag )
		{
			bar = this.mHScrollBar;
		}
		else
		{
			bar = this.mVScrollBar;
		}

		final float value = this.getScrollValue( bar );

//System.out.println(value);

		Rectangle2D cRect = this.getClientRectZoomed();
		Rectangle2D vpRect = this.getViewportBounds();

		if( flag )
		{
			final float diff = (float)( cRect.getWidth() - vpRect.getWidth() );
			final float x = - value*diff;
			this.setClientOrigin(
				x,
				(float)this.getClientRect().getY()
			);
		}
		else
		{
			final float diff = (float)( cRect.getHeight() - vpRect.getHeight() );
			final float y = - value*diff;
			this.setClientOrigin(
				(float)this.getClientRect().getX(),
				y
			);
		}

		return true;
	}



	/**
	 * 
	 */
	public Component getComponent( final int x, final int y )
	{
		Component com = this;

		SGFigure[] array = this.getFigureArrayFromLayer();
		for( int ii=0; ii<array.length; ii++ )
		{
			if( array[ii].isVisible() == false )
			{
				continue;
			}

			Rectangle2D rect = array[ii].getGraphAreaRect();
			Point p = this.getLocationInPane(x,y);
			if( rect.contains(p) )
			{
				com = array[ii];
				break;
			}
		}

		return com;
	}













//
// イベント関係
//


	/**
	 * コンポーネントが可視になると呼び出されます。 
	 */
	public void componentShown(final ComponentEvent e)
	{
	}

	/**
	 * コンポーネントが不可視になると呼び出されます。 
	 */
	public void componentHidden(final ComponentEvent e){}

	/**
	 * コンポーネントの位置が変わると呼び出されます。 
	 */
	public void componentMoved(final ComponentEvent e){}



	/**
	 * コンポーネントのサイズが変わると呼び出されます。 
	 */
	public void componentResized(final ComponentEvent e)
	{

//System.out.println("+++ componentResized +++");
//System.out.println(e.getSource());

		if( this.getWidth() < this.mMinimumWindowSize.width )
		{
			this.setSize( this.mMinimumWindowSize.width, this.getHeight() );
			return;
		}
		
		if( this.getHeight() < this.mMinimumWindowSize.height )
		{
			this.setSize( this.getWidth(), this.mMinimumWindowSize.height );
			return;
		}


//System.out.println();


		this.onResized();
	}



	/**
	 * コンポーネント上でマウスボタンをクリック (押してから離す) したときに呼び出されます。
	 */
	public void mouseClicked(final MouseEvent e)
	{
		this.onMouseClicked(e);
	}


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

		//
		this.mFocusedFigureList.clear();


		//
		this.repaint();



		// マウス左ボタンダブルクリックでプロパティダイアログを出す
		if( (SwingUtilities.isLeftMouseButton(e) )
			&& ( e.getClickCount() == 2 ) )
		{
			this.showPropertyDialog();
		}


		// マウス右ボタンクリックでポップアップメニューを出す
		if( (SwingUtilities.isRightMouseButton(e) )
			&& ( e.getClickCount() == 1 ) )
		{
//			mPopupMenu.show( this, e.getX(), e.getY());
		}


		return true;

	}


	/**
	 * 
	 */
	public boolean showPropertyDialog()
	{
		final SGPropertyDialog dg = this.mDialog;

		//
		dg.addPropertySettingListener(this);

		// set the location
		this.mDialog.setLocation( this.getLocation() );

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

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

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

		dg.show();

		dg.removeAllPropertySettingListeners();

		return true;
	}



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

		SGFigure[] array = this.getFigureArrayFromLayer();
		for( int ii=0; ii<array.length; ii++ )
		{
			if( array[ii].isVisible() == false )
			{
				continue;
			}

			if( array[ii].click(e) )
			{
				return true;
			}

		}

		this.onMouseClicked(e);

		return false;
	}




	/**
	 * 
	 */
	protected boolean onFigureReleased( final MouseEvent e )
	{
//System.out.println("<< onFigureReleased >> "+this.getID());

		SGFigure[] array = this.getFigureArrayFromLayer();
		for( int ii=0; ii<array.length; ii++ )
		{
			if( array[ii].isVisible() == false )
			{
				continue;
			}

			array[ii].release(e);
		}


		// 履歴に残す
/*		for( int ii=0; ii<this.mFocusedFigureList.size(); ii++ )
		{
			SGFigure figure = (SGFigure)this.mFocusedFigureList.get(ii);
			if( figure.isFigureMoved() )
			{
System.out.println(figure.isFigureMoved());

				// updata the history
				boolean flag = this.updateObjectHistory( this.mFocusedFigureList );
				if( !flag )
				{
					return false;
				}
				for( int jj=0; jj<this.mFocusedFigureList.size(); jj++ )
				{
					SGFigure fig = (SGFigure)this.mFocusedFigureList.get(jj);
					flag = fig.updateHistory();
					if( !flag )
					{
						return false;
					}
				}

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

				break;
			}
		}
*/


		ArrayList list = new ArrayList();
		for( int ii=0; ii<this.mFocusedFigureList.size(); ii++ )
		{
			SGFigure figure = (SGFigure)this.mFocusedFigureList.get(ii);
			if( figure.isFigureMoved() )
			{
//System.out.println(figure.isFigureMoved());

				final boolean flag = figure.updateHistory();
				if( !flag )
				{
					return false;
				}

				list.add( figure );
			}
		}

		// updata the history
		if( list.size()!=0 )
		{
			boolean flag = this.updateObjectHistory( list );
			if( !flag )
			{
				return false;
			}
		}

//System.out.println(list);

//System.out.println();


		return true;

	}



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

		SGFigure[] array = this.getFigureArrayFromLayer();
		for( int ii=0; ii<array.length; ii++ )
		{
			if( array[ii].isVisible() == false )
			{
				continue;
			}

			if( array[ii].press(e) )
			{
//System.out.println();
				return true;
			}
		}

		//
		this.onMousePressed(e);

//System.out.println();

		return false;
	}





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

		SGFigure[] array = this.getFigureArrayFromLayer();
		for( int ii=0; ii<array.length; ii++ )
		{
			if( array[ii].isVisible() == false )
			{
				continue;
			}

			if( array[ii].drag(e) )
			{
				return true;
			}
		}

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

		return false;
	}


	/**
	 * コンポーネントにマウスが入ると呼び出されます。 
	 */
	public void mouseEntered(final MouseEvent e){}

	/**
	 * コンポーネントからマウスが出ると呼び出されます。 
	 */
	public void mouseExited(final MouseEvent e){}


	/**
	 * コンポーネント上でマウスボタンを押すと呼び出されます。 
	 */
	public void mousePressed(final MouseEvent e)
	{
		this.onMousePressed(e);
	}


	/**
	 * 
	 */
	protected boolean onMousePressed( final MouseEvent e )
	{
//System.out.println("Window Pressed!");

		//
		this.mFocusedFigureList.clear();

		ArrayList list = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.clearSelectedElements();
		}


		//
		this.repaint();

		return true;
	}



	/**
	 * コンポーネント上でマウスボタンを離すと呼び出されます。 
	 */
	public void mouseReleased(final MouseEvent e)
	{
		this.onMouseReleased(e);
	}



	/**
	 * 
	 */
	protected boolean onMouseReleased( final MouseEvent e )
	{
		//
		this.mFocusedFigureList.clear();

		//
		this.repaint();

		this.setDefaultCursor();

		return true;
	}



	/**
	 * コンポーネント上でマウスのボタンを押してドラッグすると呼び出されます。 
	 */
	public void mouseDragged(final MouseEvent e)
	{
		final boolean flag = this.onMouseMovedOrDragged(e);
		if( !flag )
		{
			return;
		}
	}



	/**
	 * コンポーネント上で、ボタンを押さずにマウスを移動すると呼び出されます。 
	 */
	public void mouseMoved(final MouseEvent e)
	{

		final boolean flag = this.onMouseMovedOrDragged(e);
		if( !flag )
		{
			return;
		}

		// カーソルをデフォルトに戻す
		this.setCursor(Cursor.getDefaultCursor());

	}



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

		// マウスが取得する座標は、タイトルバー・メニューバー・ツールバー・インセット
		// を含む全領域における座標値である。

		Point p = this.getLocationInPane( e.getX(), e.getY() );
		final int x = p.x;
		final int y = p.y;


		if( x<0 || y<0 )
		{
			return true;
		}


		// 位置情報ラベルへの設定
		this.setPositionLabel( x, y );


		return true;

	}



	/**
	 * 
	 */
	private Point getLocationInPane( final int x, final int y )
	{
		
		int xx = x;
		int yy = y;


		// ボーダ領域の寸法を取得
		final Insets insets = this.getInsets();
		final int mTop = insets.top;
		final int mBottom = insets.bottom;
		final int mLeft = insets.left;
		final int mRight = insets.right;

		xx -= mLeft;
		yy -= mTop;


		// メニューバー
		final JMenuBar menuBar = this.getJMenuBar();
		final double menuHeight = menuBar.getHeight();
		yy -= menuHeight;


		// ツールバー
		final double toolHeight = this.getToolBarHeight();
		yy -= toolHeight;


		// ルーラ
		final double rulerWidth = RULER_WIDTH;
		xx -= rulerWidth;
		yy -= rulerWidth;

//System.out.println(xx+"  "+yy);

		return new Point(xx,yy);
	}



	/**
	 * ウインドウに所属するコンポーネントからの、位置情報ラベルへの設定
	 * @param com ウインドウに所属するコンポーネント
	 * @param x x座標値
	 * @param y y座標値
	 * @return true:成功、false:失敗
	 */
	protected boolean notifyPosition( final Component com, final int x, final int y )
	{
		// ボーダ領域の寸法を取得
		final Insets insets = this.getInsets();
		final int mTop = insets.top;
		final int mBottom = insets.bottom;
		final int mLeft = insets.left;
		final int mRight = insets.right;

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

		// 子コンポーネント上での座標値から、ペイン上での座標値に変換
		int xx = x + com.getX();
		int yy = y + com.getY();

		yy += mTop;


		// menu bar
		JMenuBar menuBar = this.getJMenuBar();
		yy -= menuBar.getHeight();


		// ruler
		xx -= SGDrawingWindow.RULER_WIDTH;
		yy -= SGDrawingWindow.RULER_WIDTH;


		if( xx<0 || yy<0 )
		{
			return true;
		}


		// 位置情報ラベルへの設定
		this.setPositionLabel( xx, yy );

		return true;

	}



	/**
	 * 位置情報ラベルへの設定。
	 */
	private boolean setPositionLabel( final int x, final int y )
	{

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

		final Rectangle2D cRect = this.getClientRect();
		final float cx = (float)cRect.getX();
		final float cy = (float)cRect.getY();

		final DecimalFormat df = new DecimalFormat("0.0");

		float xx = (-cx+x)*SGConstants.CM_POINT_RATIO/this.mMagnification;
		float yy = (-cy+y)*SGConstants.CM_POINT_RATIO/this.mMagnification;
		final String strPos = "(" + df.format(xx) + ", " + df.format(yy) + ")";


final String title = "(" + x + ", " + y + ")";

//		final String title = "Window:" + new Integer( this.getID() ).toString() + "  " + strPos;
		this.setTitle( title );


		return true;

	}



	/**
	 * 
	 */
	public void stateChanged( final ChangeEvent e )
	{

		final Object source = e.getSource();
		if( source instanceof JMenu )
		{
			final JMenu menu = (JMenu)source;
			this.menuChanged(e,menu);
		}

	}



	/**
	 * 
	 * @param e
	 * @param menu
	 * @return
	 */
	protected boolean menuChanged( final ChangeEvent e, final JMenu menu )
	{

		final String text = menu.getText();

		if( text.equals( MENU_EDIT ) )
		{
			boolean flag = false;
			ArrayList list = this.getVisibleFigureListFromMap();
			for( int ii=0; ii<list.size(); ii++ )
			{
				SGFigure figure = (SGFigure)list.get(ii);
				SGIGraphElement graph = figure.getGraphElement();
				if( graph.hasSelectedData() )
				{
					flag = true;
					break;
				}
			}

			this.getMenuItem( text, MENUCMD_MOVE_SELECTED_DATA_TO_FRONT ).setEnabled(flag);
			this.getMenuItem( text, MENUCMD_MOVE_SELECTED_DATA_TO_BACK ).setEnabled(flag);
			this.getMenuItem( text, MENUCMD_REMOVE_SELECTED_DATA ).setEnabled(flag);

		}


		return true;
	}




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



	/**
	 * 
	 */
	public void addActionListener( final ActionListener listener )
	{
		for( int ii=0; ii<mActionListenerList.size(); ii++ )
		{
			final ActionListener el = (ActionListener)mActionListenerList.get(ii);
			if( el.equals(listener) )
			{
				return;
			}
		}
		mActionListenerList.add(listener);
	}



	/**
	 * 
	 */
	public void removeActionListener( ActionListener listener )
	{
		for( int ii=mActionListenerList.size()-1; ii>=0; ii-- )
		{
			final ActionListener el = (ActionListener)mActionListenerList.get(ii);
			if( el.equals(listener) )
			{
				mActionListenerList.remove(listener);
			}
		}
	}



	/**
	 * 
	 */
	public void notifyToListener( final String command )
	{
		for( int ii=0; ii<mActionListenerList.size(); ii++ )
		{
			final ActionListener el = (ActionListener)mActionListenerList.get(ii);
			el.actionPerformed( this.getActionEvent( command ) );
		}
	}



	/**
	 * 
	 */
	private ActionEvent getActionEvent( final String command )
	{
		return new ActionEvent( this, 0, command );
	}



	/**
	 * 
	 */
	public void onKeyPressed( final KeyEvent e )
	{
		ArrayList list = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.onKeyPressed(e);
		}

	}



	/**
	 * 
	 */
	public void onKeyReleased( final KeyEvent e )
	{
		ArrayList list = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.onKeyReleased(e);
		}

	}



	/**
	 * 
	 */
	public void onKeyTyped( final KeyEvent e )
	{
//System.out.println(e.getKeyChar()+"  "+e.getModifiers());
//System.out.println(e.getSource());

		final char c = e.getKeyChar();
		final int m = e.getModifiers();

		// The Ctrl key is pressed.
		if( (m&KeyEvent.CTRL_MASK)!=0 )
		{
//System.out.println("Ctrl");

		}
		// The Shift key is pressed.
		else if( (m&KeyEvent.SHIFT_MASK)!=0 )
		{
//System.out.println("Shift");

		
		}
		else
		{
//System.out.println("Others");

		}
//System.out.println();


		// notify key event to the figures
		ArrayList list = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.onKeyTyped(e);
		}

	}




	/**
	 * 
	 */
	public void windowActivated(final WindowEvent e)
	{
/*
		Object obj = e.getSource();

		// フィギュアが属するウインドウ
		if( obj.equals( this ) )
		{
System.out.println("windowActivated");

			if( this.mDialog.isShowing() )
			{
//				this.mDialog.toFront();
			}
		}
*/
	}


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


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


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


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


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


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

		Object obj = e.getSource();


		// ウインドウのプロパティ設定用ダイアログ
		if( obj.equals(this.mDialog) )
		{
			this.cancel();
//this.onOK();
		}

	}



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



	/**
	 * 
	 */
	protected ArrayList getInsertToggleButtonList()
	{
		final ArrayList list = new ArrayList();
		list.add(this.mAddStringButton);
		list.add(this.mAddTimingElementButton);
		list.add(this.mAddSignificantSymbolButton);
		list.add(this.mInsertBreakButton);

		return list;
	}


	/**
	 * 
	 */
	protected boolean setInsertToggleButtonsSelected(
		final  boolean flag )
	{
		final ArrayList list = this.getInsertToggleButtonList();
		for( int ii=0; ii<list.size(); ii++ )
		{
			final AbstractButton btn = (AbstractButton)list.get(ii);
			btn.setSelected( flag );
		}

		return true;
	}




	/**
	 * 
	 */
	public static final String NOTIFY_OPEN_WINDOW = "open a new window";


	/**
	 *
	 */
	protected void notifyOpen()
	{
		this.notifyToListener( SGDrawingWindow.NOTIFY_OPEN_WINDOW );
	}



	/**
	 * 
	 */
	public static final String NOTIFY_ADD_DATA = "add new data";



	/**
	 * 
	 */
	protected void notifyAddData()
	{
		this.notifyToListener( SGDrawingWindow.NOTIFY_ADD_DATA );
	}


	
	/**
	 * 
	 */
	public static final String NOTIFY_LOAD_PROPERTY = "load property";


	/**
	 * 
	 * @return
	 */
	protected void notifyLoadProperty()
	{
		this.notifyToListener( SGDrawingWindow.NOTIFY_LOAD_PROPERTY );
	}


	/**
	 * Close the window
	 */
	public boolean closeWindow()
	{

		// notify to WindowListeners
		final WindowEvent eWin = new WindowEvent( this, WindowEvent.WINDOW_CLOSING );
		WindowListener[] listeners = this.getWindowListeners();
		for( int ii=0; ii<listeners.length; ii++ )
		{
			listeners[ii].windowClosing(eWin);
		}


		// dispose the window
		this.dispose();


		return true;

	}




	/**
	 * アクションが発生すると呼び出されます。
	 */
	public void actionPerformed(final ActionEvent e)
	{

		final String command = e.getActionCommand();
		final Object source = e.getSource();
//System.out.println(source);


		//
		// menu bar
		//

		if( command.equals(MENUCMD_EXIT) )
		{
			System.exit(0);
		}
		else if( command.equals(MENUCMD_OPEN_WINDOW) )
		{
			this.notifyOpen();
		}
		else if( command.equals(MENUCMD_CLOSE_WINDOW) )
		{
			this.closeWindow();
			return;
		}
		else if( command.equals(MENUCMD_LOAD_PROPERTY_FILE) )
		{
			this.notifyLoadProperty();
		}
		else if( command.equals(MENUCMD_SAVE_PROPERTY_FILE) )
		{
			this.createPropertyFile();
		}
		else if( command.equals(MENUCMD_EXPORT) )
		{
			try
			{
				this.export();
			}
			catch ( IOException ex )
			{
				System.out.println("ファイル出力に失敗しました。");
				ex.printStackTrace();
			}
		}
		else if( command.equals(MENUCMD_PRINT) )
		{
/*
			PrintJob pj = getToolkit().getPrintJob(this, "print test", (Properties)null);
			if ( pj!=null )
			{
				Graphics g = pj.getGraphics();

final float ratio = SGConstants.CM_POINT_RATIO;
int x = (int)(5.0/ratio);
int y = (int)(5.0/ratio);
int w = (int)(10.0/ratio);
int h = (int)(15.0/ratio);
g.drawRect(x,y,w,h);
				g.dispose();
				pj.end();
			}
*/		}
		else if( command.equals( MENUCMD_REMOVE_SELECTED_DATA ) )
		{
			ArrayList list = this.getVisibleFigureListFromMap();
			for( int ii=0; ii<list.size(); ii++ )
			{
				SGFigure figure = (SGFigure)list.get(ii);
				SGIGraphElement graph = figure.getGraphElement();
				graph.hideSelectedData();
			}
		}
		else if( command.equals( MENUCMD_MOVE_SELECTED_DATA_TO_FRONT ) )
		{
			ArrayList list = this.getVisibleFigureListFromMap();
			for( int ii=0; ii<list.size(); ii++ )
			{
				SGFigure figure = (SGFigure)list.get(ii);
				SGIGraphElement graph = figure.getGraphElement();
				graph.moveSelectedDataToFront();
			}
		}
		else if( command.equals( MENUCMD_MOVE_SELECTED_DATA_TO_BACK ) )
		{
			ArrayList list = this.getVisibleFigureListFromMap();
			for( int ii=0; ii<list.size(); ii++ )
			{
				SGFigure figure = (SGFigure)list.get(ii);
				SGIGraphElement graph = figure.getGraphElement();
				graph.moveSelectedDataToBack();
			}
		}
		else if( command.equals( MENUCMD_UNDO ) )
		{
			this.onUndo();
		}
		else if( command.equals( MENUCMD_REDO ) )
		{
			this.onRedo();
		}
		else if( command.equals( MENUCMD_A4_SIZE )
			|| command.equals( MENUCMD_B5_SIZE )
			|| command.equals( MENUCMD_LETTER_SIZE ) )
		{

			MediaSize size = null;
			if( command.equals( MENUCMD_A4_SIZE ) )
			{
				size = MediaSize.ISO.A4;
			}
			else if( command.equals( MENUCMD_B5_SIZE ) )
			{
				size = MediaSize.ISO.B5;
			}
			else if( command.equals( MENUCMD_LETTER_SIZE ) )
			{
				size = MediaSize.NA.LETTER;
			}

			this.onPaperSizeChanged( size );

		}
		else if( command.equals( MENUCMD_BOUNDING_BOX ) )
		{
			this.setBoundigBox();
		}
		else if( command.equals( MENUCMD_ALIGN_FIGURES ) )
		{
			this.onFiguresAligned();
		}


		//
		// Tool Bar
		//

		// ズーム
		if( source.equals( this.mMagnificationComboBox ) )
		{
			this.onZoomed();
		}


		// create a new window
		if( source.equals( this.mCreateNewGraphButton ) )
		{
			this.notifyOpen();
		}


		// add new data
		if( source.equals( this.mDrawGraphButton ) )
		{
			this.notifyAddData();
		}

		// load property file
		if( source.equals( this.mLoadPropertyButton ) )
		{
			this.notifyLoadProperty();
		}


		// バウンディングボックス設定ボタン
		if( source.equals(this.mBoundingBoxButton) )
		{
			this.setBoundigBox();
		}


		// 描画要素追加用トグルボタン
		final ArrayList bList = this.getInsertToggleButtonList();
		if( bList.contains(source) )
		{

			final AbstractButton clickedButton = (AbstractButton)source;

			if( clickedButton.isSelected() )
			{
				final Cursor cur = new Cursor( Cursor.CROSSHAIR_CURSOR );
				this.setCursor( cur );
			}
			else
			{
				this.setDefaultCursor();
			}



			for( int ii=0; ii<bList.size(); ii++ )
			{
				final AbstractButton aButton = (AbstractButton)bList.get(ii);
				if( clickedButton.equals( aButton ) )
				{
					continue;
				}
				
				aButton.setSelected( false );
			}
		}


		// フィギュアロック用トグルボタン
		if( source.equals( this.mLockFigureButton ) )
		{
			this.setLockToggleButton( this.mLockFigureButton.isSelected() );
			this.mLockFigureButton.repaint();
			this.mLockFigureFlag = this.mLockFigureButton.isSelected();

			//
			if( this.mLockFigureFlag )
			{
//				this.orderFiguresByBoundingBox();
			}
		}


		//
		if( source.equals( this.mExportImageButton ) )
		{
			try
			{
				this.export();
			}
			catch ( IOException ex )
			{
				System.out.println("ファイル出力に失敗しました。");
//				ex.printStackTrace();
			}
		}


		//
		if( source.equals( this.mSaveGraphButton ) )
		{
			boolean flag = this.createPropertyFile();
			if( !flag )
			{
				System.out.println("プロパティの保存に失敗しました。");
//				ex.printStackTrace();
			}
		}


		//
		this.repaint();

	}




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

		// record the location
		ArrayList list = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.updateFigureRect();
		}


		// aligns figures
		if( this.alignFiguresByGraphArea() == false )
		{
			return false;
		}


		// update the history
		ArrayList objList = new ArrayList();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			if( figure.isFigureMoved() )
			{
				final boolean flag = figure.updateHistory();
				if( !flag )
				{
					return false;
				}
				objList.add(figure);
			}
		}


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


		//
		objList.add(this);


		// updata the history
		boolean flag = this.updateObjectHistory( objList );
		if( !flag )
		{
			return false;
		}


		return true;
	}



	/**
	 * 
	 * @param size
	 * @return
	 */
	private boolean onPaperSizeChanged( final MediaSize size )
	{

		// record the previous size
		Rectangle pRect = this.getPaperRect().getBounds();


		// set the size of the paper
		this.setPaperSize(size);


		// compare the size
		Rectangle rect = this.getPaperRect().getBounds();
		if( pRect.equals(rect) )
		{
			return true;
		}


		//
		this.updateClientRect();
		this.setScrollBarValue();



		// record the location
		ArrayList list = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.updateFigureRect();
		}


		//
		this.drawBackAllVisibleFigures();



		// update the history
		ArrayList objList = new ArrayList();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			if( figure.isFigureMoved() )
			{
				final boolean flag = figure.updateHistory();
				if( !flag )
				{
					return false;
				}
				objList.add(figure);
			}
		}


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


		//
		objList.add(this);


		// updata the history
		boolean flag = this.updateObjectHistory( objList );
		if( !flag )
		{
			return false;
		}


//System.out.println(objList);

		return true;
	}




	/**
	 * 
	 * @return
	 */
	private boolean setBoundigBox()
	{
		Rectangle pRect = this.getPaperRect().getBounds();

		ArrayList list = this.getVisibleFigureListFromMap();
		if( list.size()!=0 )
		{

			// set the size
			this.setFigureBoundingBox(0);

			// compare the size
			Rectangle rect = this.getPaperRect().getBounds();
			if( pRect.equals(rect) )
			{
				return true;
			}


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

		}

		return true;
	}





	/**
	 * Set the size of window with given media size.
	 */
	public boolean setPaperSize( MediaSize size )
	{
		if( size==null )
		{
			return false;
		}

		// length in units of cm
		BigDecimal bdWidthCM = new BigDecimal( size.getX( MediaSize.MM ) );
		BigDecimal bdHeightCM = new BigDecimal( size.getY( MediaSize.MM ) );
		bdWidthCM = bdWidthCM.movePointLeft(1);
		bdHeightCM = bdHeightCM.movePointLeft(1);
		final float widthCM = bdWidthCM.floatValue();
		final float heightCM = bdHeightCM.floatValue();

		// round out the size
		final float dWidthCM = (float)SGUtilityNumber.roundOutNumber( widthCM, -2 );
		final float dHeightCM = (float)SGUtilityNumber.roundOutNumber( heightCM, -2 );

		// length in units of pixel
		final float width = dWidthCM/SGConstants.CM_POINT_RATIO;
		final float height = dHeightCM/SGConstants.CM_POINT_RATIO;

		// set the bounds of paper
		final Rectangle2D cRect = this.getClientRect();
		final float x = (float)cRect.getX();
		final float y = (float)cRect.getY();
		final float w = width*this.mMagnification;
		final float h = height*this.mMagnification;
		this.setPaperRect( x, y, width, height );

		return true;
	}



	/**
	 * 
	 */
	public boolean addPropertiesHistory()
	{

		// プロパティ履歴：初期状態をリストに追加
		WindowProperties p = (WindowProperties)this.getProperties();
		this.addWindowPropertiesHistory(p);

		return true;
	}



	/**
	 * 
	 * @return
	 */
	private boolean addWindowPropertiesHistory( WindowProperties p )
	{
//System.out.println("<< addWindowPropertyHistory >>");
//System.out.println(this.mWindowStateCounter);

//System.out.println(this.SGConstants.CM_POINT_RATIO);
//System.out.println(this.mMagnification);
//System.out.println(p.width+"  "+p.height);
//System.out.println(p.gridInterval);
//System.out.println(1.0f/SGConstants.CM_POINT_RATIO);

//System.out.println("added:"+p);

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

		this.mWindowPropertyHistoryList = list;

//System.out.println("history list:"+this.mWindowPropertyHistoryList);
//System.out.println();

		return true;
	}




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

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

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


		this.mTemporaryProperties = null;
		this.mDialog.removePropertySettingListener(this);

		this.repaint();

		return true;
	}



	/**
	 * 
	 */
	public boolean updateHistory()
	{

		// updata the history
		this.updateObjectHistory(this);


		//
		this.mWindowStateCounter++;


		//
		this.addWindowPropertiesHistory( (WindowProperties)this.getProperties() );


//System.out.println("<< updateHistory >>");
//System.out.println(this.mWindowStateCounter);
//System.out.println(this.mWindowPropertyHistoryList);
//System.out.println();

		return true;
	}



	/**
	 * Only returns true.
	 */
	public boolean updateParentHistory()
	{
		return true;
	}



	/**
	 * 
	 */
	public boolean cancel()
	{

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

		this.mTemporaryProperties = null;
		this.mDialog.removePropertySettingListener(this);

		//
		this.updateClientRect();

		//
		this.setScrollBarValue();


		this.repaint();

		return true;
	}



	/**
	 * 
	 */
	private WindowProperties readProperties(
		final BufferedReader br )
		throws IOException, ClassNotFoundException,
			InstantiationException, IllegalAccessException
	{
//System.out.println("readProperty");

		WindowProperties p = new WindowProperties();

		String line = null;

		// title
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		if( line.equals( SGDrawingWindow.WINDOW_TITLE ) == false )
		{
			return null;
		}


		final float unit = SGConstants.CM_POINT_RATIO;


		// width of the paper
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		Double dWidth = SGUtilityText.getDoublePropertyFromLine( line, SGDrawingWindow.KEY_PAPER_WIDTH );
		if( dWidth == null )
		{
			return null;
		}
		float paperWidth = dWidth.floatValue()/unit;
//System.out.println(paperWidth);


		// height of the paper
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		Double dHeight = SGUtilityText.getDoublePropertyFromLine( line, SGDrawingWindow.KEY_PAPER_HEIGHT );
		if( dHeight == null )
		{
			return null;
		}
		float paperHeight = dHeight.floatValue()/unit;
//System.out.println(paperHeight);


/*
		// grid visible
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		Boolean bGridVisible = SGUtilityText.getBooleanPropertyFromLine( line, SGDrawingWindow.PF_GRID_VISIBLE );
		if( bGridVisible == null )
		{
			return null;
		}
		boolean gridVisible = bGridVisible.booleanValue();
System.out.println(gridVisible);
*/

		// grid interval
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		Double dGridInterval = SGUtilityText.getDoublePropertyFromLine( line, SGDrawingWindow.KEY_GRID_INTERVAL );
		if( dGridInterval == null )
		{
			return null;
		}
		float gridInterval = dGridInterval.floatValue()/unit;
//System.out.println(gridInterval);


		// grid line width
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		Double dGridLineWidth = SGUtilityText.getDoublePropertyFromLine( line, SGDrawingWindow.KEY_GRID_LINE_WIDTH );
		if( dGridLineWidth == null )
		{
			return null;
		}
		float gridLineWidth = dGridLineWidth.floatValue();
//System.out.println(gridLineWidth);


		// background color
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		Color bgColor = SGUtilityText.getColorPropertyFromLine( line, SGDrawingWindow.KEY_BACKGROUND_COLOR );
		if( bgColor == null )
		{
			return null;
		}
//System.out.println(bgColor);


		// grid line color
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		Color gridColor = SGUtilityText.getColorPropertyFromLine( line, SGDrawingWindow.KEY_GRID_COLOR );
		if( gridColor == null )
		{
			return null;
		}
//System.out.println(gridColor);



		//
		// set the properties
		//

		p.setPaperWidth( paperWidth );
		p.setPaperHeight( paperHeight );
		p.setGridInterval( gridInterval );
		p.setGridLineWidth( gridLineWidth );
		p.setBackGroundColor( bgColor );
		p.setGridColor( gridColor );


		// not from property file
		{
//			p.gridVisible = this.mGridVisibleFlag;
			p.figureMap = this.mFigureMap;
			p.visibleFigureList = this.getVisibleFigureIDList();
		}


		return p;

	}



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

		return true;
	}




	/**
	 * 
	 */
	protected boolean setDefaultCursor()
	{
		Cursor cur = Cursor.getDefaultCursor();
		this.setCursor( cur );

		return true;
	}



	/**
	 * 
	 * @return
	 */
	private boolean setDialogProperty()
	{
//System.out.println("<< setDialogProperty >>");

		final SGWindowDialog dg = (SGWindowDialog)this.mDialog;

//System.out.println(this.mPaperRect);
//System.out.println((float)this.mPaperRect.getWidth()*SGConstants.CM_POINT_RATIO/this.mMagnification);
//System.out.println((float)this.mPaperRect.getHeight()*SGConstants.CM_POINT_RATIO/this.mMagnification);
//System.out.println();

		dg.setWindowWidth( (float)this.mPaperRect.getWidth()*SGConstants.CM_POINT_RATIO );
		dg.setWindowHeight( (float)this.mPaperRect.getHeight()*SGConstants.CM_POINT_RATIO );

		dg.setWindowGridLinesInterval( this.mGridInterval*SGConstants.CM_POINT_RATIO );
		dg.setWindowGridLinesWidth( this.mGridLineWidth );

		dg.setWindowBackgroundColor( this.mBackgroundColor );

		dg.setWindowGridLinesColor( this.mGridLineColor );

		return true;

	}



	/**
	 * 
	 */
	public boolean setPropertiesFromDialog()
	{
		WindowProperties p = this.getPropertiesFromDialog();
		if( this.setProperties(p) == false )
		{
			return false;
		}

		// 
		this.updateClientRect();

		//
		this.setScrollBarValue();


		//
		this.drawBackAllVisibleFigures();



		return true;
	}



	/**
	 * ウインドウ内部のバウンディングボックスが変化したとき
	 * @return
	 */
	private boolean updateClientRect()
	{
//System.out.println("<< updateClientRect >>");

//System.out.println("** before **");
//this.dumpRect();
//System.out.println();


		//
		// if the client rectangle does not contain the bounding box,
		// fit the client rectangle to the bounding box.
		//
		// if the viewport rectangle contains the bounding box,
		// fit the the client rect to the viewport rectangle.
		//

		// horizontal

		this.fitClientRectToBBRect(true);

		if( SGUtility.isRectContains(
			this.getViewportBoundsZoomed(), this.getBoundingBoxZoomed(), true ) )
		{
			this.fitClientRectToVPRect(true);
		}

		if( SGUtility.isRectContains(
			this.getClientRectZoomed(), this.getViewportBoundsZoomed(), true ) == false )
		{
			Rectangle2D cRect = this.getClientRectZoomed();
			Rectangle2D vpRect = this.getViewportBoundsZoomed();

			final boolean b1 = SGUtility.isRectContains( cRect, vpRect.getX(), true );
			final boolean b2 = SGUtility.isRectContains( cRect, vpRect.getX()+vpRect.getWidth(), true );

			double diff = 0.0;
			if( !b1 && b2 )
			{
//System.out.println("upper");
				diff = vpRect.getX() - cRect.getX();
			}
			else if( b1 && !b2 )
			{
//System.out.println("lower");
				diff = (vpRect.getX()+vpRect.getWidth())-(cRect.getX()+cRect.getWidth());
			}
			else if( !b1 && !b2 )
			{

				if( cRect.getX() < vpRect.getX() )
				{
					diff = (vpRect.getX()+vpRect.getWidth())-(cRect.getX()+cRect.getWidth());
				}
				else
				{
					diff = vpRect.getX() - cRect.getX();
				}

//System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
			}

			this.setClientOrigin(
				(float)( cRect.getX() + diff ),
				(float)cRect.getY()
			);


		}
				



		// vertical

		this.fitClientRectToBBRect(false);

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

		if( SGUtility.isRectContains(
			this.getViewportBoundsZoomed(), this.getBoundingBoxZoomed(), false ) )
		{
			this.fitClientRectToVPRect(false);
		}

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


		if( SGUtility.isRectContains(
			this.getClientRectZoomed(), this.getViewportBoundsZoomed(), false ) == false )
		{
			Rectangle2D cRect = this.getClientRectZoomed();
			Rectangle2D vpRect = this.getViewportBoundsZoomed();

			final boolean b1 = SGUtility.isRectContains( cRect, vpRect.getY(), false );
			final boolean b2 = SGUtility.isRectContains( cRect, vpRect.getY()+vpRect.getHeight(), false );

			double diff = 0.0;
			if( !b1 && b2 )
			{
//System.out.println("upper");
				diff = vpRect.getY() - cRect.getY();
			}
			else if( b1 && !b2 )
			{
//System.out.println("lower");
				diff = (vpRect.getY()+vpRect.getHeight())-(cRect.getY()+cRect.getHeight());
			}
			else if( !b1 && !b2 )
			{

				if( cRect.getY() < vpRect.getY() )
				{
					diff = (vpRect.getY()+vpRect.getHeight())-(cRect.getY()+cRect.getHeight());
				}
				else
				{
					diff = vpRect.getY() - cRect.getY();
				}

//System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
			}

			this.setClientOrigin(
				(float)cRect.getX(),
				(float)( cRect.getY() + diff )
			);


		}


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


		//
		this.setScrollBarValue();


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


		//
		this.setEnableScrollBars();


		if( SGUtility.isRectContains(
			this.getViewportBoundsZoomed(), this.getBoundingBoxZoomed(), true ) )
		{
			this.fitClientRectToVPRect(true);
		}
		if( SGUtility.isRectContains(
			this.getViewportBoundsZoomed(), this.getBoundingBoxZoomed(), false ) )
		{
			this.fitClientRectToVPRect(false);
		}


//System.out.println("** after **");
//this.dumpRect();
//System.out.println();


		repaint();

		return true;

	}




	private boolean fitClientRectToBBRect( final boolean flag )
	{
		Rectangle2D cRect = this.getClientRect();
		Rectangle2D bbRect = this.getBoundingBox();

		if( flag )
		{
			cRect.setRect(
				bbRect.getX(),
				cRect.getY(),
				bbRect.getWidth(),
				cRect.getHeight()
			);
		}
		else
		{
			cRect.setRect(
				cRect.getX(),
				bbRect.getY(),
				cRect.getWidth(),
				bbRect.getHeight()
			);
		}

		return true;
	}


	private boolean fitClientRectToVPRect( final boolean flag )
	{
		Rectangle2D cRect = this.getClientRect();
		Rectangle2D vpRect = this.getViewportBoundsInClientRect();

		if( flag )
		{
			cRect.setRect(
				vpRect.getX(),
				cRect.getY(),
				vpRect.getWidth(),
				cRect.getHeight()
			);
		}
		else
		{
			cRect.setRect(
				cRect.getX(),
				vpRect.getY(),
				cRect.getWidth(),
				vpRect.getHeight()
			);
		}

		return true;
	}





	/**
	 * スクロールバーの表示／非表示切り替え
	 * @return
	 */
	protected boolean setEnableScrollBars()
	{
		Rectangle2D vpRect = this.getViewportBoundsInClientRect();
		Rectangle2D bbRect = this.getBoundingBoxZoomed();

		final boolean hFlag
			= SGUtilityNumber.contains(
				vpRect.getX(), vpRect.getX()+vpRect.getWidth(),
				bbRect.getX(), bbRect.getX()+bbRect.getWidth() );

		final boolean vFlag
			= SGUtilityNumber.contains(
				vpRect.getY(), vpRect.getY()+vpRect.getHeight(),
				bbRect.getY(), bbRect.getY()+bbRect.getHeight() );

		this.mHScrollBar.setVisible(!hFlag);
		this.mVScrollBar.setVisible(!vFlag);

//System.out.println(hFlag+"  "+vFlag);
//this.dumpRect();

		return true;
	}



	/**
	 * 
	 */
	public boolean setProperties( SGProperties p )
	{
//System.out.println("setProperties");

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

		WindowProperties wp = (WindowProperties)p;

		final Float w = wp.getPaperWidth();
		final Float h = wp.getPaperHeight();
		if( w==null || h==null )
		{
			return false;
		}
		this.setPaperSize(
			w.floatValue(),
			h.floatValue()
		);

		final Color bgColor = wp.getBackgroundColor();
		if( bgColor==null )
		{
			return false;
		}
		this.setBackgroundColor(bgColor);

		final Color gridColor = wp.getGridColor();
		if( gridColor==null )
		{
			return false;
		}
		this.setGridLineColor(gridColor);

		final Float gridInterval = wp.getGridInterval();
		if( gridInterval==null )
		{
			return false;
		}
		this.setGridInterval(gridInterval.floatValue());

		final Float gridLineWidth = wp.getGridLineWidth();
		if( gridLineWidth==null )
		{
			return false;
		}
		this.setGridLineWidth(gridLineWidth.floatValue());

		this.mFigureMap = wp.figureMap;

		this.setFigureVisible( wp.visibleFigureList );

		return true;
	}



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

		final WindowProperties p = new WindowProperties();

		p.setPaperWidth( (float)this.mPaperRect.getWidth() );
		p.setPaperHeight( (float)this.mPaperRect.getHeight() );
		p.setBackGroundColor( this.mBackgroundColor );
		p.setGridColor( this.mGridLineColor );
		p.setGridInterval( this.mGridInterval );
		p.setGridLineWidth( this.mGridLineWidth );
		p.figureMap = this.mFigureMap;
		p.visibleFigureList = this.getVisibleFigureIDList();

		return p;

	}



	/**
	 * 
	 */	
	protected ArrayList getVisibleFigureIDList()
	{
		ArrayList idList = new ArrayList();
		ArrayList fList = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<fList.size(); ii++ )
		{
			SGFigure figure = (SGFigure)fList.get(ii);
			final int key = figure.getID();
			idList.add( new Integer(key) );
		}

		return idList;
	}



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

		SGFigure[] array = this.getFigureArrayFromMap();
		for( int ii=0; ii<array.length; ii++ )
		{
			final int id = array[ii].getID();
			if( list.contains( new Integer(id) ) )
			{
				array[ii].setVisible(true);
			}
			else
			{
				array[ii].setVisible(false);
			}
		}

		return true;
	}



	/**
	 * 
	 */
	private WindowProperties getPropertiesFromDialog()
	{

/*
		final WindowProperties p = new WindowProperties();

		final SGWindowDialog dg = (SGWindowDialog)this.mDialog;

		p.setPaperWidth( dg.getWindowWidth()/SGConstants.CM_POINT_RATIO );
		p.setPaperHeight( dg.getWindowHeight()/SGConstants.CM_POINT_RATIO );
		p.setBackGroundColor( dg.getWindowBackgroundColor() );
		p.setGridColor( dg.getWindowGridLinesColor() );
		p.setGridInterval( dg.getWindowGridLinesInterval()/SGConstants.CM_POINT_RATIO );
		p.setGridLineWidth( dg.getWindowGridLinesWidth() );
*/

		final WindowProperties p = this.mDialog.getProperties();
		if( p==null )
		{
			return null;
		}

//System.out.println(p);

		// not from dialog
		{
			p.figureMap = this.mFigureMap;
			p.visibleFigureList = this.getVisibleFigureIDList();
		}

		return p;

	}





	/**
	 * フォーカスされている全フィギュアに対してドラッグ矩形の設定を行う
	 * @return
	 */
	protected boolean setDraggingRectOfFocusedFigures()
	{
//System.out.println("<< setDraggingRectOfFocusedFigures >>");
		for( int ii=0; ii<this.mFocusedFigureList.size(); ii++ )
		{
			SGFigure figure = (SGFigure)this.mFocusedFigureList.get(ii);
//System.out.println("ID="+figure.getID());
//System.out.println("g:"+figure.getGraphAreaRect());
			figure.setDraggingRect();
//System.out.println("d:"+figure.getRectangleOnDragging());
		}
//System.out.println();

		return true;
	}



	/**
	 * 倍率100%でのクライアント領域の矩形を返す。<BR>
	 * @return クライアント領域の矩形
	 */
	public Rectangle2D getClientRect()
	{
		return this.mClientRect;
	}



	/**
	 * 
	 * @return
	 */
	public Rectangle2D getClientRectZoomed()
	{
		Rectangle2D cRect = this.getClientRect();
		Rectangle2D rect = new Rectangle2D.Float();
		rect.setRect(
			cRect.getX(),
			cRect.getY(),
			this.mMagnification*cRect.getWidth(),
			this.mMagnification*cRect.getHeight()		
		);
		return rect;
	}




	/**
	 * 
	 */
	public boolean setClientOrigin( final float x, final float y )
	{
		this.setClientRect(
			x,
			y,
			(float)this.getClientRect().getWidth(),
			(float)this.getClientRect().getHeight()
		);
		return true;
	}



	/**
	 * @param w
	 * @param h
	 * @return
	 */
	public boolean setClientSize( final float w, final float h )
	{
		this.setClientRect(
			(float)this.getClientRect().getX(),
			(float)this.getClientRect().getY(),
			w,
			h
		);
		return true;
	}



public void dumpClientRect()
{
	Rectangle2D rect = this.getClientRect();
	final double x = rect.getX();
	final double y = rect.getY();
	final double w = rect.getWidth();
	final double h = rect.getHeight();

	System.out.println("x="+x*SGConstants.CM_POINT_RATIO+"cm, y="+y*SGConstants.CM_POINT_RATIO+"cm");
	System.out.println("w="+w*SGConstants.CM_POINT_RATIO+"cm, h="+h*SGConstants.CM_POINT_RATIO+"cm");
	System.out.println();
}



public void dumpRect()
{
	Rectangle2D cRect = this.getClientRectZoomed();
	Rectangle2D vpRect = this.getViewportBoundsZoomed();
	Rectangle2D bbRect = this.getBoundingBoxZoomed();

	Rectangle2D cRect_ = new Rectangle2D.Float();
	Rectangle2D vpRect_ = new Rectangle2D.Float();
	Rectangle2D bbRect_ = new Rectangle2D.Float();

	cRect_.setRect(
		(float)cRect.getX()*SGConstants.CM_POINT_RATIO,
		(float)cRect.getY()*SGConstants.CM_POINT_RATIO,
		(float)cRect.getWidth()*SGConstants.CM_POINT_RATIO,
		(float)cRect.getHeight()*SGConstants.CM_POINT_RATIO	
	);

	vpRect_.setRect(
		(float)vpRect.getX()*SGConstants.CM_POINT_RATIO,
		(float)vpRect.getY()*SGConstants.CM_POINT_RATIO,
		(float)vpRect.getWidth()*SGConstants.CM_POINT_RATIO,
		(float)vpRect.getHeight()*SGConstants.CM_POINT_RATIO	
	);

	bbRect_.setRect(
		(float)bbRect.getX()*SGConstants.CM_POINT_RATIO,
		(float)bbRect.getY()*SGConstants.CM_POINT_RATIO,
		(float)bbRect.getWidth()*SGConstants.CM_POINT_RATIO,
		(float)bbRect.getHeight()*SGConstants.CM_POINT_RATIO	
	);

	System.out.println("client:"+cRect_);
	System.out.println("viewport:"+vpRect_);
	System.out.println("bounding box:"+bbRect_);
}



	/**
	 * 
	 */
	public boolean setClientRect( final Rectangle2D rect )
	{
		this.mClientRect.setRect( rect );
		return true;
	}



	/**
	 * 
	 * @param x
	 * @param y
	 * @param w
	 * @param h
	 * @return
	 */
	public boolean setClientRect(
		final float x, final float y, final float w, final float h )
	{
//this.dumpClientRect();
		this.mClientRect.setRect( x, y, w, h );
		return true;
	}



	/**
	 * ビューポートの境界の矩形を返す。
	 * クライアント領域に対する相対的な位置で与えられる。
	 */
	public Rectangle2D getViewportBoundsInClientRect()
	{
		final SGTuple2f dim = this.getViewportSize();
		final float w = dim.x;
		final float h = dim.y;
		final float x = - (float)this.getClientRect().getX();
		final float y = - (float)this.getClientRect().getY();
		Rectangle2D rect = new Rectangle2D.Float( x, y, w, h );
		return rect;
	}


	public Rectangle2D getViewportBoundsZoomedInClientRect()
	{
		final SGTuple2f dim = this.getViewportSize();
		final float w = dim.x*this.mMagnification;
		final float h = dim.y*this.mMagnification;
		final float x = - (float)this.getClientRect().getX();
		final float y = - (float)this.getClientRect().getY();
		Rectangle2D rect = new Rectangle2D.Float( x, y, w, h );
		return rect;
	}


	public Rectangle2D getViewportBounds()
	{
		final SGTuple2f dim = this.getViewportSize();
		final float w = dim.x;
		final float h = dim.y;
		Rectangle2D rect = new Rectangle2D.Float( 0.0f, 0.0f, w, h );
		return rect;
	}


	public Rectangle2D getViewportBoundsZoomed()
	{
		final SGTuple2f dim = this.getViewportSize();
		final float w = dim.x*this.mMagnification;
		final float h = dim.y*this.mMagnification;
		Rectangle2D rect = new Rectangle2D.Float( 0.0f, 0.0f, w, h );
		return rect;
	}


	/**
	 * ビューポートの境界の矩形を返す。
	 * mLayeredPane 内における位置で与えられる。
	 */
	public Rectangle2D getViewportBoundsInLayeredPane()
	{
		final SGTuple2f dim = this.getViewportSize();
		final float w = dim.x;
		final float h = dim.y;
		Rectangle2D rect = new Rectangle2D.Float(
			SGDrawingWindow.RULER_WIDTH,
			SGDrawingWindow.RULER_WIDTH,
			w,
			h
		);
		return rect;
	}




	/**
	 * 
	 * @return
	 */
	protected SGFigure[][] getOrderedFigureArray()
	{

		// get the visible figure list
		ArrayList list = this.getVisibleFigureListFromMap();


		// get the size of array
		final int n = list.size();
		if( n==0 )
		{
			return new SGFigure[0][0];
		}
		int size = 0;
		for( int ii=1; ii<=16; ii++ )
		{
			final int sqSmall = (ii-1)*(ii-1);
			final int sqLarge = ii*ii;
			if( (sqSmall<n) && (n<=sqLarge) )
			{
				size = ii;
				break;
			}
		}
		int sx = size;
		int div = n/sx;
		int sy = n%sx==0 ? div : div+1 ;


		// create a figure array
		final SGFigure[][] figureArray = new SGFigure[sy][sx];




		//
		// in the order of figure-ID
		//

		boolean flag = true;
		for( int ny=0; ny<sy; ny++ )
		{
			for( int nx=0; nx<sx; nx++ )
			{
				final int index = ny*sx + nx;
				if( index >= list.size() )
				{
					flag = false;
					break;
				}
				figureArray[ny][nx] = (SGFigure)list.get(index);
			}
			if( !flag )
			{
				break;
			}
		}


		return figureArray;
	}





	/**
	 * 
	 * @return
	 */
	public boolean alignFiguresByGraphArea()
	{
//System.out.println("<< order >>");

		// get the visible figure list
		ArrayList figureList = this.getVisibleFigureListFromMap();
		if( figureList.size()==0 )
		{
			return true;
		}
/*
		if( list.size()==1 )
		{
//			this.orderFiguresByBoundingBox();
			return true;
		}
*/

		Rectangle2D cRect = this.getClientRectZoomed();
		Rectangle2D pRect = this.getPaperRect();


		// width of division
		float minWidth = Float.MAX_VALUE;
		float minHeight = Float.MAX_VALUE;
		for( int ii=0; ii<figureList.size(); ii++ )
		{
			SGFigure figure = (SGFigure)figureList.get(ii);
			Rectangle2D rect = figure.getGraphAreaRect();
			if( rect.getWidth() < minWidth )
			{
				minWidth = (float)rect.getWidth();
			}
			if( rect.getHeight() < minHeight )
			{
				minHeight = (float)rect.getHeight();
			}
		}

		final float dx = minWidth;
		final float dy = minHeight;


//		final float dx = SGDefaultValues.DEFAULT_FIGURE_WIDTH*this.mMagnification;
//		final float dy = dx/SGConstants.GOLDEN_RATIO;


//final float dx = this.mMagnification*5.0f/SGConstants.CM_POINT_RATIO;
//final float dy = dx;


		final int numX = (int)( (float)cRect.getWidth()/dx ) + 1;
		final int numY = (int)( (float)cRect.getHeight()/dy ) + 1;
//System.out.println("numX="+numX);
//System.out.println("numY="+numY);
//System.out.println();

		ArrayList[][] fListArray = new ArrayList[numX][numY];
		for( int ii=0; ii<numX; ii++ )
		{
			for( int jj=0; jj<numY; jj++ )
			{
				fListArray[ii][jj] = new ArrayList();
			}
		}


		for( int ii=0; ii<figureList.size(); ii++ )
		{
			SGFigure figure = (SGFigure)figureList.get(ii);
			Rectangle2D gRect = figure.getGraphAreaRect();
			int nx = (int)( ( gRect.getCenterX() - cRect.getX() )/dx );
			int ny = (int)( ( gRect.getCenterY() - cRect.getY() )/dy );
//System.out.println("ii="+ii+",  nx="+nx+",  ny="+ny);			

			fListArray[nx][ny].add( figure );
		}
//System.out.println();


/*
for( int ii=0; ii<numX; ii++ )
{
	for( int jj=0; jj<numY; jj++ )
	{
		System.out.println(ii+"  "+jj+"  "+fListArray[ii][jj]);
	}
}
System.out.println();
*/


		ArrayList numListX = new ArrayList();
		for( int nx=0; nx<numX; nx++ )
		{
			boolean flag = false;
			for( int ny=0; ny<numY; ny++ )
			{
				if( fListArray[nx][ny].size()!=0 )
				{
					flag = true;
					break;
				}
			}

			if( flag )
			{
				numListX.add( new Integer(nx) );
			}
		}


		ArrayList numListY = new ArrayList();
		for( int ny=0; ny<numY; ny++ )
		{
			boolean flag = false;
			for( int nx=0; nx<numX; nx++ )
			{
				if( fListArray[nx][ny].size()!=0 )
				{
					flag = true;
					break;
				}
			}

			if( flag )
			{
				numListY.add( new Integer(ny) );
			}
		}

//System.out.println("numListX:"+numListX);
//System.out.println("numListY:"+numListY);
//System.out.println();

		final int sx = numListX.size();
		final int sy = numListY.size();

		ArrayList[][] figureListArray = new ArrayList[sx][sy];
		for( int ii=0; ii<sx; ii++ )
		{
			final int nx = ((Integer)numListX.get(ii)).intValue();
			for( int jj=0; jj<sy; jj++ )
			{
				final int ny = ((Integer)numListY.get(jj)).intValue();
				figureListArray[ii][jj] = fListArray[nx][ny];

//System.out.println(ii+"  "+jj+"  "+figureListArray[ii][jj]);
			}
		}
//System.out.println();




		//
		float[][] topArray = new float[sx][sy];
		float[][] bottomArray = new float[sx][sy];
		float[][] leftArray = new float[sx][sy];
		float[][] rightArray = new float[sx][sy];
		for( int ii=0; ii<sx; ii++ )
		{
			for( int jj=0; jj<sy; jj++ )
			{
				if( figureListArray[ii][jj] == null )
				{
					continue;
				}

				ArrayList list = figureListArray[ii][jj];
				float maxTop = 0.0f;
				float maxBottom = 0.0f;
				float maxLeft = 0.0f;
				float maxRight = 0.0f;
				for( int kk=0; kk<list.size(); kk++ )
				{
					SGFigure figure = (SGFigure)list.get(kk);
					Rectangle2D rect = figure.getGraphAreaRect();
					SGTuple2f tb = new SGTuple2f();
					SGTuple2f lr = new SGTuple2f();
					figure.calcMargin( tb, lr );
					if( tb.x + (float)rect.getHeight() > maxTop )
					{
						maxTop = tb.x + (float)rect.getHeight();
					}
					if( tb.y > maxBottom )
					{
						maxBottom = tb.y;
					}
					if( lr.x > maxLeft )
					{
						maxLeft = lr.x;
					}
					if( lr.y + (float)rect.getWidth() > maxRight )
					{
						maxRight = lr.y + (float)rect.getWidth();
					}
				}

				topArray[ii][jj] = maxTop;
				bottomArray[ii][jj] = maxBottom;
				leftArray[ii][jj] = maxLeft;
				rightArray[ii][jj] = maxRight;

//System.out.println(maxTop+"  "+maxBottom+"  "+maxLeft+"  "+maxRight);

			}
		}

//System.out.println();


		// get arrays of the width and the height
		final float[] widthArray = new float[sx];
		for( int nx=0; nx<sx; nx++ )
		{
			float wMax = 0.0f;
			for( int ny=0; ny<sy; ny++ )
			{
				float width = leftArray[nx][ny] + rightArray[nx][ny];
				if( width > wMax )
				{
					wMax = width;
				}
			}
			widthArray[nx] = wMax;
		}

		final float[] heightArray = new float[sy];
		for( int ny=0; ny<sy; ny++ )
		{
			float hMax = 0.0f;
			for( int nx=0; nx<sx; nx++ )
			{
				float height = topArray[nx][ny] + bottomArray[nx][ny];
				if( height > hMax )
				{
					hMax = height;
				}
			}
			heightArray[ny] = hMax;
		}


		// get arrays of the width and the height
		final float[] maxLeftArray = new float[sx];
		for( int nx=0; nx<sx; nx++ )
		{
			float wMax = 0.0f;
			for( int ny=0; ny<sy; ny++ )
			{
				float width = leftArray[nx][ny];
				if( width > wMax )
				{
					wMax = width;
				}
			}
			maxLeftArray[nx] = wMax;
		}

		final float[] maxBottomArray = new float[sy];
		for( int ny=0; ny<sy; ny++ )
		{
			float hMax = 0.0f;
			for( int nx=0; nx<sx; nx++ )
			{
				float height = bottomArray[nx][ny];
				if( height > hMax )
				{
					hMax = height;
				}
			}
			maxBottomArray[ny] = hMax;
		}

/*
for( int ii=0; ii<sx; ii++ )
{
	System.out.println(ii+"  "+widthArray[ii]);
}
System.out.println();

for( int ii=0; ii<sy; ii++ )
{
	System.out.println(ii+"  "+heightArray[ii]);
}
System.out.println();
*/

		// create arrays of the coordinate of the centers
		final float[] originXArray = new float[sx];
		float cx = (float)cRect.getX();
		for( int nx=0; nx<sx; nx++ )
		{
			originXArray[nx] = cx + maxLeftArray[nx];
			cx += widthArray[nx];
		}

		final float[] originYArray = new float[sy];
		float cy = (float)cRect.getY();
		for( int ny=0; ny<sy; ny++ )
		{
			originYArray[ny] = cy + heightArray[ny] - maxBottomArray[ny];
			cy += heightArray[ny];
		}

/*
for( int ii=0; ii<sx; ii++ )
{
	System.out.println(ii+"  "+originXArray[ii]);
}
System.out.println();

for( int ii=0; ii<sy; ii++ )
{
	System.out.println(ii+"  "+originYArray[ii]);
}
System.out.println();
*/


		// set the location of figures
		boolean flag = true;
		for( int ny=0; ny<sy; ny++ )
		{
			for( int nx=0; nx<sx; nx++ )
			{
				ArrayList list = figureListArray[nx][ny];
				for( int ii=0; ii<list.size(); ii++ )
				{
					SGFigure figure = (SGFigure)list.get(ii);
					if( figure==null )
					{
						flag = false;
						break;
					}

					if( figure.setGraphAreaLocationByLeftBottom(
						originXArray[nx], originYArray[ny] ) == false )
					{
						return false;
					}
				}
				if( !flag )
				{
					break;
				}
			}
			if( !flag )
			{
				break;
			}
		}


		// enlarge the size of paper
		int mode = -1;
		float wTotal = 0.0f;
		float hTotal = 0.0f;
		for( int ii=0; ii<widthArray.length; ii++ )
		{
			wTotal += widthArray[ii];
		}
		for( int ii=0; ii<heightArray.length; ii++ )
		{
			hTotal += heightArray[ii];
		}
		final boolean bw = ( pRect.getWidth() < wTotal );
		final boolean bh = ( pRect.getHeight() < hTotal );

//System.out.println("pRect:"+pRect);
//System.out.println("wTotal="+wTotal);
//System.out.println("hTotal="+hTotal);

		if( bw & bh )
		{
			mode = 0;
		}
		else if( bw )
		{
			mode = 1;
		}
		else if( bh )
		{
			mode = 2;
		}

//System.out.println("mode="+mode);
//System.out.println();

		if( mode!=-1 )
		{
			if( this.setFigureBoundingBox(mode) == false )
			{
				return false;
			}
		}


		return true;
	}




	public static final double OVERLAP_RATIO = 0.50;


	private boolean isOverlapping( SGFigure figure1, SGFigure figure2, final boolean flag )
	{

		Rectangle2D rect1 = figure1.getGraphAreaRect();
		Rectangle2D rect2 = figure2.getGraphAreaRect();

		final double value = SGUtility.getOverlapping( rect1, rect2, flag );

		boolean ret = false;
		if( flag )
		{
			final double ratio1 = value/rect1.getWidth();
			final double ratio2 = value/rect2.getWidth();
			if( ratio1>OVERLAP_RATIO || ratio2>OVERLAP_RATIO )
			{
				ret = true;
			}
		}
		else
		{
			final double ratio1 = value/rect1.getHeight();
			final double ratio2 = value/rect2.getHeight();
			if( ratio1>OVERLAP_RATIO || ratio2>OVERLAP_RATIO )
			{
				ret = true;
			}
		}

		return ret;
	}





	/**
	 * Returns the relative location of figure2 to figure1.
	 * @param figure1
	 * @param figure2
	 * @return		0:top 1:bottom 2:left 3:right
	 */
	private int getAlignment( SGFigure figure1, SGFigure figure2 )
	{
		Rectangle2D rect1 = figure1.getGraphAreaRect();
		Rectangle2D rect2 = figure2.getGraphAreaRect();

		final double vx = rect2.getCenterX() - rect1.getCenterX();
		final double vy = rect2.getCenterY() - rect1.getCenterY();

		final double angle = Math.atan2(vy,vx);
//System.out.println(angle/Math.PI);


		int num = -1;
		if( -0.75*Math.PI<=angle && angle<-0.25*Math.PI )
		{
			num = 0;
		}
		else if( 0.25*Math.PI<=angle && angle<0.75*Math.PI )
		{
			num = 1;
		}
		else if( ( -Math.PI<=angle && angle<-0.75*Math.PI )
			|| ( 0.75*Math.PI<=angle && angle<=Math.PI ) )
		{
			num = 2;
		}
		else if( -0.25*Math.PI<=angle && angle<0.25*Math.PI )
		{
			num = 3;
		}

		return num;
	}




	class Figure
	{
		SGFigure fig;
		Figure top;
		Figure bottom;
		Figure left;
		Figure right;
		Figure topLeft;
		Figure topRight;
		Figure bottomLeft;
		Figure bottomRight;
		ArrayList topList = new ArrayList();
		ArrayList bottomList = new ArrayList();
		ArrayList leftList = new ArrayList();
		ArrayList rightList = new ArrayList();

		public String toString()
		{
			if( fig==null )
			{
				return "null";
			}
			else
			{
				return fig.toString();
			}
		}
	}






	/**
	 * Order the figures.
	 * @return
	 */
	public boolean alignFiguresByBoundingBox()
	{
		boolean flag;


		final SGFigure[][] figureArray = this.getOrderedFigureArray();
		if( figureArray==null )
		{
			return false;
		}
		if( figureArray.length==0 )
		{
			return true;
		}
		final int sy = figureArray.length;
		final int sx = figureArray[0].length;


		// create an array of the bounding box of the figures
		Rectangle2D[][] rectArray = new Rectangle2D[sy][sx];
		flag = true;
		for( int ny=0; ny<sy; ny++ )
		{
			for( int nx=0; nx<sx; nx++ )
			{
				if( figureArray[ny][nx] == null )
				{
					flag = false;
					break;
				}
				rectArray[ny][nx] = figureArray[ny][nx].getBoundingBox();
			}
			if( !flag )
			{
				break;
			}
		}

/*
for( int ny=0; ny<sy; ny++ )
{
	for( int nx=0; nx<sx; nx++ )
	{
		System.out.println(ny+"  "+nx+"  "+array[ny][nx]);
	}
}
System.out.println();
*/

		// get arrays of the width and the height
		final float[] widthArray = new float[sx];
		for( int nx=0; nx<sx; nx++ )
		{
			float wMax = 0.0f;
			for( int ny=0; ny<sy; ny++ )
			{
				Rectangle2D rect = rectArray[ny][nx];
				if( rect==null )
				{
					break;
				}
				float width = (float)rectArray[ny][nx].getWidth();
				if( width > wMax )
				{
					wMax = width;
				}
			}
			widthArray[nx] = wMax;
		}

		final float[] heightArray = new float[sy];
		for( int ny=0; ny<sy; ny++ )
		{
			float hMax = 0.0f;
			for( int nx=0; nx<sx; nx++ )
			{
				Rectangle2D rect = rectArray[ny][nx];
				if( rect==null )
				{
					break;
				}
				float height = (float)rectArray[ny][nx].getHeight();
				if( height > hMax )
				{
					hMax = height;
				}
			}
			heightArray[ny] = hMax;
		}

/*
for( int ii=0; ii<sx; ii++ )
{
	System.out.println(ii+"  "+widthArray[ii]);
}
System.out.println();

for( int ii=0; ii<sy; ii++ )
{
	System.out.println(ii+"  "+heightArray[ii]);
}
System.out.println();
*/

		// create arrays of the coordinate of the centers

		Rectangle2D cRect = this.getClientRectZoomed();

		final float[] centerXArray = new float[sx];
		float cx = (float)cRect.getX();
		for( int nx=0; nx<sx; nx++ )
		{
			centerXArray[nx] = cx + widthArray[nx]/2.0f;
			cx += widthArray[nx];
		}

		final float[] centerYArray = new float[sy];
		float cy = (float)cRect.getY();
		for( int ny=0; ny<sy; ny++ )
		{
			centerYArray[ny] = cy + heightArray[ny]/2.0f;
			cy += heightArray[ny];
		}

/*
for( int ii=0; ii<sx; ii++ )
{
	System.out.println(ii+"  "+centerXArray[ii]);
}
System.out.println();

for( int ii=0; ii<sy; ii++ )
{
	System.out.println(ii+"  "+centerYArray[ii]);
}
System.out.println();
*/

		// set the location of figures

		flag = true;
		for( int ny=0; ny<sy; ny++ )
		{
			for( int nx=0; nx<sx; nx++ )
			{
				final int index = ny*sx + nx;
				SGFigure figure = figureArray[ny][nx];
				if( figure==null )
				{
					flag = false;
					break;
				}
				if( figure.setCenter(
					centerXArray[nx], centerYArray[ny] ) == false )
				{
					return false;
				}
			}
			if( !flag )
			{
				break;
			}
		}



		// enlarge the size of paper
		int mode = -1;
		float wTotal = 0.0f;
		float hTotal = 0.0f;
		for( int ii=0; ii<widthArray.length; ii++ )
		{
			wTotal += widthArray[ii];
		}
		for( int ii=0; ii<heightArray.length; ii++ )
		{
			hTotal += heightArray[ii];
		}
		Rectangle2D pRect = this.getPaperRect();
		final boolean bw = ( pRect.getWidth() < wTotal );
		final boolean bh = ( pRect.getHeight() < hTotal );

//System.out.println("pRect:"+pRect);
//System.out.println("wTotal="+wTotal);
//System.out.println("hTotal="+hTotal);

		if( bw & bh )
		{
			mode = 0;
		}
		else if( bw )
		{
			mode = 1;
		}
		else if( bh )
		{
			mode = 2;
		}

//System.out.println("mode="+mode);
//System.out.println();

		if( mode!=-1 )
		{
			if( this.setFigureBoundingBox(mode) == false )
			{
				return false;
			}
		}


		return true;
	}




	







//
//
// アンドゥ関係
//
//


	/**
	 * 現在、状態が履歴のどの位置にあるのかを示すカウンタ
	 * 自身と、属性のSGFigureの状態変更において変更される
	 */
	private int mCurrentStateCounter = 0;


	/**
	 * ウインドウの状態カウンタ
	 */
	private int mWindowStateCounter = 0;



	/**
	 * ウインドウのプロパティの履歴リスト
	 */
	private ArrayList mWindowPropertyHistoryList = new ArrayList();



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


	/**
	 * フィギュアリストの履歴リスト
	 */
	private ArrayList mFigureMapHistoryList = new ArrayList();



	/**
	 * オブジェクトの履歴を更新する
	 * @return
	 */
	public boolean updateObjectHistory( final SGIUndoable obj )
	{

		ArrayList objList = new ArrayList();
		objList.add(obj);
		boolean flag = this.updateObjectHistory(objList);
		if( !flag )
		{
			return false;
		}

		return true;

	}



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

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

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

		this.setUndoMenuItem();

		return true;
	}



	/**
	 * 
	 * @return
	 */
	public boolean undo()
	{
//System.out.println("undo "+this);

		this.mWindowStateCounter--;

		WindowProperties p = (WindowProperties)this.mWindowPropertyHistoryList.get(this.mWindowStateCounter);
		this.setProperties(p);

//System.out.println(p);

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

		repaint();

		return true;
	}



	/**
	 * 
	 * @return
	 */
	public boolean redo()
	{
//System.out.println("redo "+this);

		this.mWindowStateCounter++;

		WindowProperties p = (WindowProperties)this.mWindowPropertyHistoryList.get(this.mWindowStateCounter);
		this.setProperties(p);

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

		repaint();

		return true;

	}



	/**
	 * アンドゥ操作の実行
	 */
	public boolean onUndo()
	{

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

		// 記録されているundo操作対象オブジェクトの取得
		if( this.mCurrentStateCounter == 0 )
		{
//System.out.println("return false");
			return false;
		}
		ArrayList objList = (ArrayList)this.mUndoableObjectHistoryList.get(
			this.mCurrentStateCounter - 1 );
		for( int ii=0; ii<objList.size(); ii++ )
		{
			SGIUndoable obj = (SGIUndoable)objList.get(ii);
			// アンドゥ操作の実行の依頼
			boolean flag;
			if( obj.equals(this) )
			{
				flag = this.undo();
			}
			else
			{
				flag = obj.onUndo();
			}
		
			if( !flag )
			{
//System.out.println("return false");
				return false;
			}
		}


		// decrement
		this.mCurrentStateCounter--;

		this.mFocusedFigureList.clear();
		this.setUndoMenuItem();


		//
		this.updateClientRect();
		this.setScrollBarValue();

/*
System.out.println("-- history --");
System.out.println(this.mUndoableObjectHistoryList);
System.out.println(this.mWindowPropertyHistoryList);
System.out.println("cnt="+this.mCurrentStateCounter);
System.out.println();
*/

		return true;

	}



	/**
	 * 
	 */
	public boolean onRedo()
	{

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

		// 記録されているundo操作対象オブジェクトの取得
		if( this.mCurrentStateCounter == this.mUndoableObjectHistoryList.size() )
		{
//System.out.println("return false");
			return false;
		}

		ArrayList objList = (ArrayList)this.mUndoableObjectHistoryList.get( this.mCurrentStateCounter );
		for( int ii=0; ii<objList.size(); ii++ )
		{
			SGIUndoable obj = (SGIUndoable)objList.get(ii);
			// リドゥ操作の実行の依頼
			boolean flag;
			if( obj.equals(this) )
			{
				flag = this.redo();
			}
			else
			{
				flag = obj.onRedo();
			}

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


		// increment
		this.mCurrentStateCounter++;

		this.mFocusedFigureList.clear();
		this.setUndoMenuItem();


		//
		this.updateClientRect();
		this.setScrollBarValue();


		return true;

	}



	/**
	 * 
	 */
	private boolean setUndoMenuItem()
	{

		// undo
		{
			JMenuItem item = this.getMenuItem( MENU_EDIT, MENUCMD_UNDO );
			if( this.mCurrentStateCounter == 0 )
			{
				item.setEnabled(false);
			}
			else
			{
				item.setEnabled(true);
			}
		}


		// redo
		{
			JMenuItem item = this.getMenuItem( MENU_EDIT, MENUCMD_REDO );
			if( this.mCurrentStateCounter == this.mUndoableObjectHistoryList.size() )
			{
				item.setEnabled(false);
			}
			else
			{
				item.setEnabled(true);
			}
		}

		return true;
	}






//
// メニュー関係
//

	private final String MENU_FILE = "File";
	private final String MENUCMD_OPEN_WINDOW = "Open";
	private final String MENUCMD_CLOSE_WINDOW = "Close";
	private final String MENUCMD_LOAD_PROPERTY_FILE = "Load Property";
	private final String MENUCMD_SAVE_PROPERTY_FILE = "Save Property";
	private final String MENUCMD_EXPORT = "Export";
	private final String MENUCMD_PRINT = "Print";
	private final String MENUCMD_EXIT = "exit";


	private final String MENU_EDIT = "Edit";
	private final String MENUCMD_UNDO = "Undo";
	private final String MENUCMD_REDO = "Redo";
	private final String MENUCMD_MOVE_SELECTED_DATA_TO_FRONT
		= "Move Data to Front";
	private final String MENUCMD_MOVE_SELECTED_DATA_TO_BACK
		= "Move Data to Back";
	private final String MENUCMD_REMOVE_SELECTED_DATA
		= "Remove Data";

	private final String MENU_LAYOUT = "Layout";
	private final String MENUCMD_PAPER_SIZE = "Paper Size";
	private final String MENUCMD_A4_SIZE = "A4";
	private final String MENUCMD_B5_SIZE = "B5";
	private final String MENUCMD_LETTER_SIZE = "Letter";
	private final String MENUCMD_BOUNDING_BOX = "Bounding Box";
	private final String MENUCMD_ALIGN_FIGURES = "Align Figures";



	/**
	 * 
	 */
	private JMenuBar createMenuBar()
	{
		JMenuBar menuBar = new JMenuBar();


		// File
		{
			final JMenu menuFile = new JMenu(MENU_FILE);
			menuBar.add(menuFile);
			menuFile.addChangeListener(this);

			final JMenuItem open = new JMenuItem(MENUCMD_OPEN_WINDOW);
			open.setActionCommand(MENUCMD_OPEN_WINDOW);
			open.addActionListener(this);
			open.setAccelerator(
				KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK));
			menuFile.add(open);

			final JMenuItem close = new JMenuItem(MENUCMD_CLOSE_WINDOW);
			close.setActionCommand(MENUCMD_CLOSE_WINDOW);
			close.addActionListener(this);
			menuFile.add(close);

			menuFile.addSeparator();

			final JMenuItem loadProperty = new JMenuItem(MENUCMD_LOAD_PROPERTY_FILE);
			loadProperty.setActionCommand(MENUCMD_LOAD_PROPERTY_FILE);
			loadProperty.addActionListener(this);
			loadProperty.setAccelerator(
				KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK));
			menuFile.add(loadProperty);

			menuFile.addSeparator();

			final JMenuItem createProperty = new JMenuItem(MENUCMD_SAVE_PROPERTY_FILE);
			createProperty.setActionCommand(MENUCMD_SAVE_PROPERTY_FILE);
			createProperty.addActionListener(this);
			createProperty.setAccelerator(
				KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK));
			menuFile.add(createProperty);

			menuFile.addSeparator();

			final JMenuItem export = new JMenuItem(MENUCMD_EXPORT);
			export.setActionCommand(MENUCMD_EXPORT);
			export.addActionListener(this);
			export.setAccelerator(
				KeyStroke.getKeyStroke(KeyEvent.VK_E, ActionEvent.CTRL_MASK));
			menuFile.add(export);

			menuFile.addSeparator();

			final JMenuItem print = new JMenuItem(MENUCMD_PRINT);
			print.setActionCommand(MENUCMD_PRINT);
			print.addActionListener(this);
			print.setAccelerator(
				KeyStroke.getKeyStroke(KeyEvent.VK_P, ActionEvent.CTRL_MASK));
			menuFile.add(print);

			menuFile.addSeparator();

			final JMenuItem exit = new JMenuItem(MENUCMD_EXIT);
			exit.setActionCommand(MENUCMD_EXIT);
			exit.addActionListener(this);
			menuFile.add(exit);

		}


		// Edit
		{
			final JMenu menuEdit = new JMenu(MENU_EDIT);
			menuBar.add(menuEdit);
			menuEdit.addChangeListener(this);

			final JMenuItem undo = new JMenuItem(MENUCMD_UNDO);
			undo.setActionCommand(MENUCMD_UNDO);
			undo.addActionListener(this);
			undo.setAccelerator(
				KeyStroke.getKeyStroke(KeyEvent.VK_Z, ActionEvent.CTRL_MASK));
			menuEdit.add(undo);
			undo.setEnabled(false);

			final JMenuItem redo = new JMenuItem(MENUCMD_REDO);
			redo.setActionCommand(MENUCMD_REDO);
			redo.addActionListener(this);
			redo.setAccelerator(
				KeyStroke.getKeyStroke(KeyEvent.VK_Y, ActionEvent.CTRL_MASK));
			menuEdit.add(redo);
			redo.setEnabled(false);

			menuEdit.addSeparator();

			final JMenuItem moveDataToFront = new JMenuItem(MENUCMD_MOVE_SELECTED_DATA_TO_FRONT);
			moveDataToFront.setActionCommand(MENUCMD_MOVE_SELECTED_DATA_TO_FRONT);
			moveDataToFront.addActionListener(this);
			moveDataToFront.setAccelerator(
				KeyStroke.getKeyStroke(KeyEvent.VK_F, ActionEvent.CTRL_MASK));
			menuEdit.add(moveDataToFront);
			moveDataToFront.setEnabled(false);

			final JMenuItem moveDataToBack = new JMenuItem(MENUCMD_MOVE_SELECTED_DATA_TO_BACK);
			moveDataToBack.setActionCommand(MENUCMD_MOVE_SELECTED_DATA_TO_BACK);
			moveDataToBack.addActionListener(this);
			moveDataToBack.setAccelerator(
				KeyStroke.getKeyStroke(KeyEvent.VK_B, ActionEvent.CTRL_MASK));
			menuEdit.add(moveDataToBack);
			moveDataToBack.setEnabled(false);

			final JMenuItem removeData = new JMenuItem(MENUCMD_REMOVE_SELECTED_DATA);
			removeData.setActionCommand(MENUCMD_REMOVE_SELECTED_DATA);
			removeData.addActionListener(this);
			removeData.setAccelerator(
				KeyStroke.getKeyStroke(KeyEvent.VK_D, ActionEvent.CTRL_MASK));
			menuEdit.add(removeData);
			removeData.setEnabled(false);

		}



		// window
		{

			final JMenu menuWindow = new JMenu(MENU_LAYOUT);
			menuBar.add(menuWindow);
			menuWindow.addChangeListener(this);

			// window size
			final JMenu menuWindowSize = new JMenu(MENUCMD_PAPER_SIZE);
			menuWindow.add(menuWindowSize);

			final JMenuItem a4 = new JMenuItem(MENUCMD_A4_SIZE);
			a4.setActionCommand(MENUCMD_A4_SIZE);
			a4.addActionListener(this);
			menuWindowSize.add(a4);

			final JMenuItem b5 = new JMenuItem(MENUCMD_B5_SIZE);
			b5.setActionCommand(MENUCMD_B5_SIZE);
			b5.addActionListener(this);
			menuWindowSize.add(b5);

			final JMenuItem letter = new JMenuItem(MENUCMD_LETTER_SIZE);
			letter.setActionCommand(MENUCMD_LETTER_SIZE);
			letter.addActionListener(this);
			menuWindowSize.add(letter);

			final JMenuItem bbFigure = new JMenuItem(MENUCMD_BOUNDING_BOX);
			bbFigure.addActionListener(this);
			menuWindow.add( bbFigure );

			final JMenuItem alignFigures = new JMenuItem(MENUCMD_ALIGN_FIGURES);
			alignFigures.addActionListener(this);
			menuWindow.add( alignFigures );


		}


		return menuBar;

	}



	/**
	 * 
	 */
	private JMenu getMenu( final String menuName )
	{
		JMenuBar bar = this.getJMenuBar();
		for( int ii=0; ii<bar.getMenuCount(); ii++ )
		{
			JMenu menu = (JMenu)bar.getMenu(ii);
			if( menu.getActionCommand().equals(menuName) )
			{
				return menu;
			}
		}

		return null;
	}



	/**
	 * 
	 */
	private JMenuItem getMenuItem(
		final String menuName, final String itemName )
	{

		JMenu menu = this.getMenu( menuName );
		if( menu==null )
		{
			return null;
		}

//System.out.println("count="+menu.getItemCount());
		for( int ii=0; ii<menu.getItemCount(); ii++ )
		{
			JMenuItem item = menu.getItem(ii);
//System.out.println(ii+"  "+item);

			// skip separators
			if( item==null )
			{
				continue;
			}

			if( item.getText().equals(itemName) )
			{
				return item;
			}
		}
//System.out.println();

		return null;
	}



	/**
	 * 
	 */
	private static ExportDialog mExportDialog = new ExportDialog();



	/**
	 * export
	 * 暫定的にVectorGraphicsライブラリを使用する
	 */
	public boolean export() throws IOException
	{
//System.out.println("*** export ***");

		// record the properties		
		float mag = this.mMagnification;
		double hValue = this.getHScrollValue();
		double vValue = this.getVScrollValue();


		// hide anchors temporarily
		this.mDrawAnchorFlag = false;


		//
		ArrayList list = this.getVisibleFigureListFromLayer();
		Rectangle2D cRect = this.getClientRect();
		SGTuple2f[] locationArray = new SGTuple2f[list.size()];
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			locationArray[ii] = new SGTuple2f(
				figure.mGraphAreaX, figure.mGraphAreaY );
//System.out.println("before:"+locationArray[ii]);
		}



		// 倍率を100%にする
		this.zoom(1.0f);


		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.setGraphAreaLocation(
				figure.getGraphAreaX() - (float)cRect.getX(),
				figure.getGraphAreaY() - (float)cRect.getY()
			);
		}


/*
		// create a panel
		final JPanel previewPanel = new JPanel();
		previewPanel.setOpaque(true);
		previewPanel.setVisible(true);
		previewPanel.setBackground(
			new Color(
				this.mBackgroundColor.getRed(),
				this.mBackgroundColor.getGreen(),
				this.mBackgroundColor.getBlue(), 0
			)
		);
		lPane.add( previewPanel );
		lPane.setLayer( previewPanel, LAYER_GRID_PANEL );
*/

		// set the location and the size of preview dialog
		Insets insets = this.mPreviewDialog.getInsets();
		final int width = (int)this.mPaperRect.getWidth();
		final int height = (int)this.mPaperRect.getHeight();
		this.mPreviewDialog.setSize(
			width + insets.left + insets.right,
			height + insets.top + insets.bottom	);
		this.mPreviewDialog.setLocation( this.getLocation() );


		//
		JLayeredPane lPane = this.mPreviewDialog.mLayeredPane;
		lPane.setLocation(0,0);
		lPane.setSize( width, height );


		Rectangle2D rectView = new Rectangle2D.Float( 0.0f, 0.0f, width, height );


/*
		previewPanel.setLocation(0,0);
		previewPanel.setSize( (int)this.mPaperRect.getWidth(), (int)this.mPaperRect.getHeight() );

final float pw = previewPanel.getWidth()*SGConstants.CM_POINT_RATIO;
final float ph = previewPanel.getHeight()*SGConstants.CM_POINT_RATIO;
System.out.println(previewPanel.getLocation());
System.out.println(pw+"  "+ph);
System.out.println();
*/

		//
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.setLocation(0,0);
			figure.setSize( new SGTuple2f( width, height ) );
			figure.setGraphAreaRectToFigureElement();
			figure.setViewBounds( rectView );
			lPane.add( figure );
			lPane.setLayer( figure, LAYER_FIGURE );
		}


		// show the preview dialog
		this.mPreviewDialog.show();
		this.mPreviewDialog.repaint();


		// show the export dialog
		SGDrawingWindow.mExportDialog.showExportDialog
		(
			lPane,
			"Export view as ...",
			lPane,
			"export"
		);


		// terminate the preview window
		this.terminatePreviewDialog();



		// 再設定
		this.zoom(mag);

		this.setScrollValue( this.mHScrollBar, hValue );
		this.setScrollValue( this.mVScrollBar, vValue );

		SGTuple2f vpSize = this.getViewportSize();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.mGraphAreaX = locationArray[ii].x;
			figure.mGraphAreaY = locationArray[ii].y;
			figure.setSize( vpSize );
			figure.setGraphAreaRectToFigureElement();
			figure.setViewBounds();
		}

		// アンカーを再描画
		this.mDrawAnchorFlag = true;


		this.repaint();

		return true;

	}





	/**
	 * 
	 */
	private boolean terminatePreviewDialog()
	{

		Component[] comArray = this.mPreviewDialog.mLayeredPane.getComponentsInLayer( LAYER_FIGURE );
		for( int ii=0; ii<comArray.length; ii++ )
		{
			SGFigure figure = (SGFigure)comArray[ii];
			figure.setLocation( SGDrawingWindow.RULER_WIDTH, SGDrawingWindow.RULER_WIDTH );
			this.mLayeredPane.add(figure);
		}

		this.mPreviewDialog.hide();

		return true;

	}






	/**
	 * 
	 * ファイルチューザを開く
	 * 引数はディレクトリ名
	 * @return
	 */
	private File openFileChooser( String dir )
	{

		// create a file chooser object
		JFileChooser chooser = new JFileChooser(dir);

		// set the initially selected file
		File fileInit = new File( this.mPropertyFileName );
		chooser.setSelectedFile( fileInit );

		// show save dialog
		int ret = chooser.showSaveDialog(this);

		File file = null;
		switch( ret )
		{
			// selected
			case JFileChooser.APPROVE_OPTION :
			{
				file = chooser.getSelectedFile();
				this.mPropertyFileDirName = file.getPath();
				break;
			}

			// canceled
			case JFileChooser.CANCEL_OPTION :
			{
				break;
			}

			// error
			case JFileChooser.ERROR_OPTION :
			{
				throw new Error();
			}

			default :
			{
				
			}
		}

		return file;
	}








//
//	プロパティファイル関連
//


	/**
	 * 
	 */
	public final String PROPERTY_FILE_NAME = "property.txt";


	/**
	 * 
	 */
	private String mPropertyFileName = PROPERTY_FILE_NAME;


	/**
	 * 
	 */
	public final String PROPERTY_FILE_DIR_NAME = "./";


	/**
	 * 
	 */
	public String mPropertyFileDirName = PROPERTY_FILE_DIR_NAME;


	/**
	 * 
	 */
	public boolean createPropertyFile()
	{

		boolean flag = true;
		try
		{

			File file = this.openFileChooser(this.mPropertyFileDirName);
			if( file==null )
			{
				return true;
			}
//System.out.println(file);

			String fileName = file.getPath();
//System.out.println("fileName: "+fileName);


			FileOutputStream fos = new FileOutputStream(fileName);
			OutputStreamWriter osw = new OutputStreamWriter(fos);
			BufferedWriter bw = new BufferedWriter(osw);

			// window		
			flag = this.writeProperty(bw);
			if( !flag )
			{
				return false;
			}

			// figure
			ArrayList list = this.getVisibleFigureListFromMap();
			for( int ii=0; ii<list.size(); ii++ )
			{
				SGFigure figure = (SGFigure)list.get(ii);
				flag = figure.createPropertyFileAll(bw);
				if( !flag )
				{
					return false;
				}
			}

			// close
			bw.close();
			osw.close();
			fos.close();
		}
		catch( Exception ex )
		{
			ex.printStackTrace();
			return false;
		}

		return true;
	}



	/**
	 * 
	 */
	public boolean createPropertyFileForFocusedFigures()
	{

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

		boolean flag = true;
		try
		{

			File file = this.openFileChooser(this.mPropertyFileDirName);
			if( file==null )
			{
				return true;
			}
//System.out.println(file);

			String fileName = file.getPath();
//System.out.println("fileName: "+fileName);


			FileOutputStream fos = new FileOutputStream(fileName);
			OutputStreamWriter osw = new OutputStreamWriter(fos);
			BufferedWriter bw = new BufferedWriter(osw);

			// window
			flag = this.writePropertyForFocusedFigures(bw);
			if( !flag )
			{
				return false;
			}

			// figure
			for( int ii=0; ii<this.mFocusedFigureList.size(); ii++ )
			{
				SGFigure figure = (SGFigure)this.mFocusedFigureList.get(ii);
				flag = figure.createPropertyFileAllOnFocused(bw);
				if( !flag )
				{
					return false;
				}
			}

			// close
			bw.close();
			osw.close();
			fos.close();
		}
		catch( Exception ex )
		{
			return false;
		}

		return true;
	}



	/**
	 * 
	 */
	private boolean writePropertyForFocusedFigures( final Writer writer )
		throws IOException
	{

		// title
		writer.write(WINDOW_TITLE+"\n");


		//
		// Size
		//

		Rectangle2D rect = this.getBoundingBoxOfFigures( this.mFocusedFigureList );
		SGUtilityText.writePropertyLine( writer,
			KEY_PAPER_WIDTH, new Double( rect.getWidth()*SGConstants.CM_POINT_RATIO ) );
		SGUtilityText.writePropertyLine( writer,
			KEY_PAPER_HEIGHT, new Double( rect.getHeight()*SGConstants.CM_POINT_RATIO ) );


		//
		// Grid
		//

//		SGUtilityForPropertyFile.writePropertyLine( writer,
//			PF_GRID_VISIBLE, new Boolean( this.mGridVisibleFlag ) );
		SGUtilityText.writePropertyLine( writer,
			KEY_GRID_INTERVAL, new Float( this.mGridInterval*SGConstants.CM_POINT_RATIO ) );
		SGUtilityText.writePropertyLine( writer,
			KEY_GRID_LINE_WIDTH, new Float( this.mGridLineWidth*SGConstants.CM_POINT_RATIO ) );


		//
		// Color
		//

		SGUtilityText.writeColorPropertyLine( writer, KEY_BACKGROUND_COLOR, this.getBackgroundColor() );
		SGUtilityText.writeColorPropertyLine( writer,
			KEY_GRID_COLOR, this.mGridLineColor );


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


		return true;
	}



	/**
	 * 
	 */
	private boolean writePropertyOfWindowPaneForFocusedFigures( final Writer writer )
		throws IOException
	{

		return true;
	}


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

		// title
		writer.write(WINDOW_TITLE+"\n");


		SGUtilityText.writePropertyLine( writer,
			KEY_PAPER_WIDTH, new Float( this.mPaperRect.getWidth()*SGConstants.CM_POINT_RATIO ) );
		SGUtilityText.writePropertyLine( writer,
			KEY_PAPER_HEIGHT, new Float( this.mPaperRect.getHeight()*SGConstants.CM_POINT_RATIO ) );


		//
		// Grid
		//

		SGUtilityText.writePropertyLine( writer,
			KEY_GRID_INTERVAL, new Float( this.mGridInterval*SGConstants.CM_POINT_RATIO ) );
		SGUtilityText.writePropertyLine( writer,
			KEY_GRID_LINE_WIDTH, new Float( this.mGridLineWidth ) );


		//
		// Color
		//

		SGUtilityText.writeColorPropertyLine( writer, KEY_BACKGROUND_COLOR, this.getBackgroundColor() );
		SGUtilityText.writeColorPropertyLine( writer,
			KEY_GRID_COLOR, this.mGridLineColor );



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


		return true;

	}





//
// 共通プロパティ設定
//


	/**
	 * 
	 * @return
	 */
	protected boolean setPropertyOfSelectedObjects()
	{
//System.out.println("<< setPropertyOfSelectedObjects >>");

		ArrayList plList = new ArrayList();
		ArrayList dList = new ArrayList();

		ArrayList figList = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<figList.size(); ii++ )
		{
			SGFigure figure = (SGFigure)figList.get(ii);

			ArrayList list
				= figure.mGraphElement.getPropertySettingListerListOfDataElements();
			if( list.size()==0 )
			{
				continue;
			}

			plList.addAll(list);
			dList.add( figure.mGraphElement.getPropertyDialogForDataElements() );
		}
		if( plList.size()==0 )
		{
			return true;
		}

		for( int ii=0; ii<dList.size()-1; ii++ )
		{
			Object obj1 = dList.get(ii);
			for( int jj=ii; jj<dList.size(); jj++ )
			{
				Object obj2 = dList.get(jj);
				if( obj1.getClass().equals(obj2.getClass()) == false )
				{
					return false;
				}
			}
		}

		SGPropertyDialog dg = (SGPropertyDialog)dList.get(0);
		for( int ii=0; ii<plList.size(); ii++ )
		{
//System.out.println("ii="+ii);
			SGIPropertySettingListener l = (SGIPropertySettingListener)plList.get(ii);
			dg.addPropertySettingListener(l);
			l.createTemporaryPropertyObject();
		}
//System.out.println();

		dg.setDialogProperty();

		dg.setLocation( this.getLocation() );

		dg.show();

		return true;
	}









//
// 内部クラス
//


	/**
	 * Panel to draw anchors.
	 */
	class AnchorPanel extends JPanel
	{
		
		/**
		 * 
		 */
		protected AnchorPanel()
		{
			super();
		}


		/**
		 * コンポーネントとしての境界を指定する
		 */
		protected boolean setBounds()
		{
			// mLayeredPane の境界からルーラを除いた領域と一致させる
			final Rectangle rect = mLayeredPane.getBounds();
			final int rw = SGDrawingWindow.RULER_WIDTH;
			this.setBounds(
				rw,
				rw,
				rect.width - rw,
				rect.height - rw
			);

			return true;
		}


		/**
		 * 
		 */
		public void paintComponent( final Graphics g )
		{
			super.paintComponent(g);
			final Graphics2D g2d = (Graphics2D)g;


			if( mDrawAnchorFlag == false )
			{
				return;
			}



			final Rectangle2D cRect = getClientRectZoomed();

			for( int ii=0; ii<mFocusedFigureList.size(); ii++ )
			{

				final SGFigure figure = (SGFigure)mFocusedFigureList.get(ii);

//long sTime = System.currentTimeMillis();

				// ドラッグ中の矩形
				Rectangle2D dRect = figure.getRectangleOnDragging();
				if( SGFigure.mDrawRectangleOnDraggingFlag && SGFigure.mDraggingFlag )
				{
					this.drawRectangle( g2d, dRect );
				}

//long eTime = System.currentTimeMillis();
//System.out.println("diff="+(eTime-sTime));


				// アンカー
				{
					final Rectangle2D gRect = figure.getGraphAreaRect();
					final int x = (int)gRect.getX();
					final int y = (int)gRect.getY();
					final int w = (int)gRect.getWidth();
					final int h = (int)gRect.getHeight();
					drawAnchor( g2d, x, y );
					drawAnchor( g2d, x+w, y );
					drawAnchor( g2d, x, y+h );
					drawAnchor( g2d, x+w, y+h );
					drawAnchor( g2d, x+w/2, y );
					drawAnchor( g2d, x, y+h/2 );
					drawAnchor( g2d, x+w/2, y+h );
					drawAnchor( g2d, x+w, y+h/2 );
				}


			}


		}



		/**
		 * 
		 */
		private void drawAnchor( final Graphics2D g2d, final int x, final int y )
		{
			final Shape anchor = new Ellipse2D.Float(
				x-0.5f*mAnchorSize, y-0.5f*mAnchorSize, mAnchorSize, mAnchorSize
			);


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

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

		}



		/**
		 * 
		 */
		private void drawRectangle( final Graphics2D g2d, final Rectangle2D rect )
		{

			g2d.setPaint(Color.BLACK);


			final float width = 2.0f;
			final float dash[] = {2.0f*width,width};
			g2d.setStroke
			(
				new BasicStroke
				(
					width,
					BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
					10.0f, dash, 0.0f
				)
			);


//g2d.setStroke( new BasicStroke(1.0f) );

			final double x = rect.getX();
			final double y = rect.getY();
			final double w = rect.getWidth();
			final double h = rect.getHeight();
			final Line2D north = new Line2D.Double( x, y, x+w, y );
			final Line2D south = new Line2D.Double( x, y+h, x+w, y+h );
			final Line2D west = new Line2D.Double( x, y, x, y+h );
			final Line2D east = new Line2D.Double( x+w, y, x+w, y+h );

			g2d.draw( north );
			g2d.draw( south );
			g2d.draw( west );
			g2d.draw( east );

		}

		
	}




	/**
	 * Panel to draw grid lines.
	 */
	class GridPanel extends JPanel
	{

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


		/**
		 * コンポーネントとしての境界を指定する
		 */
		protected boolean setBounds()
		{
			// mLayeredPane の境界からルーラを除いた領域と一致させる
			final Rectangle rect = mLayeredPane.getBounds();
			final int rw = SGDrawingWindow.RULER_WIDTH;
			this.setBounds(
				rw,
				rw,
				rect.width - rw,
				rect.height - rw
			);

			return true;
		}


		/**
		 * 
		 */
		public void paintComponent( final Graphics g )
		{
			super.paintComponent(g);
			final Graphics2D g2d = (Graphics2D)g;


			// get the rectangle of paper
			Rectangle2D pRect = getPaperRect();
			if( pRect==null )
			{
				return;
			}


			// fill the paper rectangle
			g2d.setPaint( getBackgroundColor() );
			g2d.fill( pRect );


			// set the property of grid lines
			g2d.setStroke(
				new BasicStroke
				(
					mGridLineWidth,
					BasicStroke.CAP_BUTT,
					BasicStroke.JOIN_MITER
				)
			);
			g2d.setPaint( mGridLineColor );


			// grid interval
			final float space = mMagnification*mGridInterval;


			// create a line object
			final Line2D line = new Line2D.Float();


			// vertical lines
			int cnt = 0;
			while( true )
			{
				final float x = cnt*space + (float)pRect.getX();
				if( x > pRect.getX() + pRect.getWidth() )
				{
					break;
				}

				line.setLine(
					x,
					pRect.getY(),
					x,
					pRect.getY() + pRect.getHeight()
				);
				g2d.draw( line );

				cnt++;
			}


			// horizontal lines
			cnt = 0;
			while( true )
			{
				final float y = cnt*space + (float)pRect.getY();
				if( y > pRect.getY() + pRect.getHeight() )
				{
					break;
				}

				line.setLine(
					pRect.getX(),
					y,
					pRect.getX() + pRect.getWidth(),
					y
				);
				g2d.draw( line );

				cnt++;
			}

/*
g2d.setStroke( new BasicStroke(5) );

g2d.setPaint( Color.RED );
g2d.draw( getClientRectZoomed() );

g2d.setPaint( Color.BLUE );
g2d.draw( getBoundingBoxZoomed() );
*/

		}


	}




	/**
	 * Panel to draw rulers.
	 */
	class RulerPanel extends JPanel
	{

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


		/**
		 * コンポーネントとしての境界を指定する
		 */
		protected boolean setBounds()
		{
			// mLayeredPane の境界と一致させる
			final Rectangle rect = mLayeredPane.getBounds();
			this.setBounds(
				0,
				0,
				rect.width,
				rect.height
			);

			return true;
		}


		/**
		 * 
		 */
		public void paintComponent( final Graphics g )
		{
			super.paintComponent(g);
			final Graphics2D g2d = (Graphics2D)g;

			this.drawRuler(g2d);
		}



		/**
		 * 
		 */
		private boolean drawRuler( final Graphics2D g2d )
		{

			//
			final int nPoints = 6;
			final int[] xPoints = new int[nPoints];
			final int[] yPoints = new int[nPoints];

			xPoints[0] = 0;
			yPoints[0] = 0;
			
			xPoints[1] = this.getWidth();
			yPoints[1] = 0;
			
			xPoints[2] = this.getWidth();
			yPoints[2] = RULER_WIDTH;
			
			xPoints[3] = RULER_WIDTH;
			yPoints[3] = RULER_WIDTH;
			
			xPoints[4] = RULER_WIDTH;
			yPoints[4] = this.getHeight();
			
			xPoints[5] = 0;
			yPoints[5] = this.getHeight();

			final Polygon polygon
				= new Polygon( xPoints, yPoints, nPoints );


			g2d.setPaint( mRulerLineColor );
			g2d.setStroke
			(
				new BasicStroke
				(
					1.0f,
					BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER
				)
			);
			g2d.setPaint( mRulerBackGroundColor );
			g2d.fill( polygon );

			g2d.setPaint( Color.BLACK );
			g2d.draw( polygon );


			// draw the lines of rulers
			this.drawNumbersAndLines( g2d );


			// corner
			final Rectangle2D rectCorner
				= new Rectangle2D.Float(
					0.0f, 0.0f, RULER_WIDTH, RULER_WIDTH );
			g2d.setPaint( mRulerBackGroundColor );
			g2d.fill( rectCorner );

			g2d.setPaint( mRulerLineColor );
			g2d.draw( rectCorner );


			return true;

		}




		/**
		 * 
		 */
		private boolean drawNumbersAndLines( final Graphics2D g2d )
		{

			g2d.setPaint( mRulerLineColor );


			final SGTuple2f dim = getViewportSize();
			final float wPaneWidth = dim.x;
			final float wPaneHeight = dim.y;

			final Rectangle2D vpRect = getViewportBoundsInClientRect();
			final Rectangle2D cRect = getClientRectZoomed();

			final float xScroll = getHScrollValue();
			final float yScroll = getVScrollValue();

//			final float hShift = - xScroll*( mMagnification - 1.0f )*wPaneWidth;
//			final float vShift = - yScroll*( mMagnification - 1.0f )*wPaneHeight;

			final float hShift = (float)cRect.getX();
			final float vShift = (float)cRect.getY();

			final float hStart = RULER_WIDTH + hShift;
			final float vStart = RULER_WIDTH + vShift;



			//
			// axis lines
			//

			g2d.setStroke
			(
				new BasicStroke
				(
					mRulerAxisLineWidth,
					BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER
				)
			);

			// horizontal
			{
				final float x1 = RULER_WIDTH;
				final float x2 = (float)this.getWidth();
				final float y = RULER_WIDTH;
				final Line2D line = new Line2D.Float( x1, y, x2, y );
				g2d.draw(line);
			}

			// perpendicular
			{
				final float x = RULER_WIDTH;
				final float y1 = RULER_WIDTH;
				final float y2 = (float)this.getHeight();
				final Line2D line = new Line2D.Float( x, y1, x, y2 );
				g2d.draw(line);			
			}



			//
			// scale lines
			//

			g2d.setStroke
			(
				new BasicStroke
				(
					mRulerScaleLineWidth,
					BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER
				)
			);


//			final double largerWidth = ( cRect.getWidth() > wPaneWidth ? cRect.getWidth() : wPaneWidth );
//			final double largerHeight = ( cRect.getHeight() > wPaneHeight ? cRect.getHeight() : wPaneHeight );

final float largerWidth = (float)cRect.getWidth();
final float largerHeight = (float)cRect.getHeight();


			// horizontal
			{

				final ArrayList valueList = new ArrayList();
				float value = 0.0f;
				int cnt = 0;
				while( true )
				{
					value = mMagnification*(float)cnt/SGConstants.CM_POINT_RATIO;
					if( value > largerWidth )
					{
						break;
					}
					valueList.add( new Float(value) );
					cnt++;
				}

				// draw
				for( int ii=0; ii<valueList.size(); ii++ )
				{
					// main
					value = ((Float)valueList.get(ii)).floatValue();
					final float pos = hStart + value;
					final Line2D line = new Line2D.Float(
						pos, 0.20f*RULER_WIDTH,
						pos, RULER_WIDTH );
					g2d.draw(line);

					// number
					final Integer num = new Integer(ii);
					final int x = (int)( pos + 0.3f*mRulerFontSize );
					final int y = (int)mRulerFontSize;
					g2d.drawString( num.toString(), x, y );

					// sub
					for( int jj=0; jj<4; jj++ )
					{
						final float pos_ = pos + mMagnification*0.2f*(float)(jj+1)*(1.0f/SGConstants.CM_POINT_RATIO);

						final Line2D line_ = new Line2D.Float(
							pos_, 0.75f*RULER_WIDTH,
							pos_, RULER_WIDTH );
						g2d.draw(line_);
					}

				}

			}


			// perpendicular
			{
				final ArrayList valueList = new ArrayList();
				float value = 0.0f;
				int cnt = 0;
				while( true )
				{
					value = mMagnification*(float)cnt/SGConstants.CM_POINT_RATIO;
					if( value > largerHeight )
					{
						break;
					}
					valueList.add( new Float(value) );
					cnt++;
				}

				// draw
				for( int ii=0; ii<valueList.size(); ii++ )
				{

					// main
					value = ((Float)valueList.get(ii)).floatValue();
					final float pos = vStart + value;
					final Line2D line = new Line2D.Float(
						0.20f*RULER_WIDTH, pos,
						RULER_WIDTH, pos );
					g2d.draw(line);

					// number
					final Integer num = new Integer(ii);
					final int x = (int)( 0.20f*RULER_WIDTH );
					final int y = (int)( pos + mRulerFontSize );
					g2d.drawString( num.toString(), x, y );

					// sub
					for( int jj=0; jj<4; jj++ )
					{
						final float pos_ = pos + mMagnification*0.2f*(float)(jj+1)*(1.0f/SGConstants.CM_POINT_RATIO);

						final Line2D line_ = new Line2D.Float(
							0.750f*RULER_WIDTH, pos_,
							RULER_WIDTH, pos_ );
						g2d.draw(line_);
					}
				}

			}


//g2d.setPaint( Color.BLUE );
//g2d.setStroke( new BasicStroke(5) );
//g2d.draw( new Rectangle( 0, 0, this.getWidth(), this.getHeight() ) );

			return true;
		}


	}




	/**
	 * Preview dialog on exporting to the files.
	 */
	class PreviewDialog extends JDialog
	{


		/**
		 * 
		 */
		private JLayeredPane mLayeredPane = new JLayeredPane();


		/**
		 * 
		 */
		protected PreviewDialog()
		{
			super();
			this.initComponents();
		}


		/**
		 * 
		 */
		protected PreviewDialog( final Frame owner, final String title )
		{
			super( owner, title );
			this.initComponents();
		}


		/**
		 * 
		 */
		private void initComponents()
		{
			this.getContentPane().add( this.mLayeredPane );
			this.setVisible(true);
			this.setResizable(false);
		}


	}






	/**
	 * Property of SGDrawingWindow.
	 */
	public static class WindowProperties extends SGProperties
	{
//		float width;
//		float height;
//		Color bgColor;
//		Color gridColor;
//		float gridInterval;
//		float gridLineWidth;
//		boolean gridVisible = true;
		TreeMap figureMap = new TreeMap();
		ArrayList visibleFigureList = new ArrayList();


		public static final String[] keys = {
			KEY_PAPER_WIDTH, KEY_PAPER_HEIGHT, KEY_BACKGROUND_COLOR,
			KEY_GRID_COLOR, KEY_GRID_INTERVAL, KEY_GRID_LINE_WIDTH
		};


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


		/**
		 * 
		 */
		public String toString()
		{
			String str = new String("[");
			for( int ii=0; ii<keys.length; ii++ )
			{
				str += keys[ii] + "=" + this.getProperty( keys[ii] ) +",";
			}

			str += this.figureMap.toString();
			str += this.visibleFigureList.toString();
			str += new String("]");

			return str;
		}


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

			if( ( obj instanceof WindowProperties ) == false )
			{
				return false;
			}

			WindowProperties p = (WindowProperties)obj;

			for( int ii=0; ii<keys.length; ii++ )
			{
				if( this.getProperty(keys[ii]).equals(p.getProperty(keys[ii])) == false )
				{
					return false;
				}
			}

			if( p.figureMap.equals(this.figureMap) == false ) return false;
			if( p.visibleFigureList.equals(this.visibleFigureList) == false ) return false;

			return true;
		}


		public Float getPaperWidth()
		{
			final String value = this.getProperty(KEY_PAPER_WIDTH);
			return SGUtilityText.getFloat(value);
		}

		public Float getPaperHeight()
		{
			final String value = this.getProperty(KEY_PAPER_HEIGHT);
			return SGUtilityText.getFloat(value);
		}

		public Color getBackgroundColor()
		{
			final String value = this.getProperty(KEY_BACKGROUND_COLOR);
			return SGUtilityText.getColorFromString(value);
		}

		public Color getGridColor()
		{
			final String value = this.getProperty(KEY_GRID_COLOR);
			return SGUtilityText.getColorFromString(value);
		}

		public Float getGridInterval()
		{
			final String value = this.getProperty(KEY_GRID_INTERVAL);
			return SGUtilityText.getFloat(value);
		}

		public Float getGridLineWidth()
		{
			final String value = this.getProperty(KEY_GRID_LINE_WIDTH);
			return SGUtilityText.getFloat(value);
		}


		public boolean setPaperWidth( final float w )
		{
			if( w<0.0f )
			{
				return false;
			}
			this.setProperty( KEY_PAPER_WIDTH, new Float(w).toString() );
			return true;
		}

		public boolean setPaperHeight( final float h )
		{
			if( h<0.0f )
			{
				return false;
			}
			this.setProperty( KEY_PAPER_HEIGHT, new Float(h).toString() );
			return true;
		}

		public boolean setBackGroundColor( final Color cl )
		{
			if( cl==null )
			{
				return false;
			}
			String str = SGUtilityText.getColorString(cl);
			if( str==null )
			{
				return false;
			}
			this.setProperty( KEY_BACKGROUND_COLOR, str );
			return true;
		}

		public boolean setGridColor( final Color cl )
		{
			if( cl==null )
			{
				return false;
			}
			String str = SGUtilityText.getColorString(cl);
			if( str==null )
			{
				return false;
			}
			this.setProperty( KEY_GRID_COLOR, str );
			return true;
		}

		public boolean setGridInterval( final float num )
		{
			if( num<0.0f )
			{
				return false;
			}
			this.setProperty( KEY_GRID_INTERVAL, new Float(num).toString() );
			return true;
		}

		public boolean setGridLineWidth( final float num )
		{
			if( num<0.0f )
			{
				return false;
			}
			this.setProperty( KEY_GRID_LINE_WIDTH, new Float(num).toString() );
			return true;
		}

	}



}

