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

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.MediaTracker;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.math.BigDecimal;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;

import javax.print.attribute.standard.MediaSize;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollBar;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.MouseInputListener;

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




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

public class SGDrawingWindow extends JFrame
	implements ComponentListener, PropertyChangeListener,
		MouseInputListener, MouseWheelListener,
		ActionListener, AdjustmentListener, WindowListener,
		SGIUndoable, SGIPropertySettingListener, SGIConstants,
		SGIRootObjectConstants
{


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


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


	/**
	 * A layered pane.
	 */
	private final JLayeredPane mLayeredPane = new JLayeredPane();


	/**
	 * A panel to draw grid lines.<BR>
	 */
	private BackgroundPanel mBackgroundPanel;


	/**
	 * A panel to draw anchors.<BR>
	 */
	private ForegroundPanel mForegroundPanel;


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


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


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


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

	/**
	 * 倍率入力テキストフィールド用 Panel
	 */
	private JPanel mZoomComboBoxPanel = null;


	/**
	 * 
	 */
	private JButton mCreateNewWindowButton = null;
	private JButton mDrawGraphButton = null;
	private JButton mLoadPropertyButton = null;
	private JButton mSavePropertyButton = null;
	private JButton mExportFormatButton = null;
	private JToggleButton mInsertBreakButton = null;
	private JButton mBoundingBoxButton = null;
	private JToggleButton mInsertLabelButton = null;
	private JToggleButton mInsertTimingLineButton = null;
	private JToggleButton mInsertSignificantDifferenceSymbolButton = null;
	private JToggleButton mLockFigureButton = null;

	private JButton mUndoButton = null;
	private JButton mRedoButton = null;
	private JButton mCutButton = null;
	private JButton mCopyButton = null;
	private JButton mPasteButton = null;
	private JButton mPrintButton = null;
	private JButton mHelpButton = null;



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


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


	/**
	 * 
	 */
	private SGIImageExportManager mImageExportManager;



	/**
	 * Temporary size of the viewport.
	 */
	private final Dimension mTemporaryViewportSize = new Dimension();



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



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



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



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



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


	/**
	 * 
	 */
	private final SGTuple2f mPaperOrigin = new SGTuple2f();


	/**
	 * 
	 */
	private final SGTuple2f mPaperSize = new SGTuple2f();



	/**
	 * Bounds of the client area.
	 */
	private Rectangle2D mClientRect = null;



	/**
	 * 
	 */
	public static final int MINIMAL_LENGTH_ORDER = -2;



	/**
	 * Title of this window.
	 */
	public static final String TITLE = "Samurai Graph";



	/**
	 * The list of copied figures.
	 */
	private ArrayList mCopiedFiguresList = new ArrayList();


	/**
	 * The list of copied objects.
	 */

	private ArrayList mCopiedObjectsList = new ArrayList();


	/**
	 * The list of copied objects.
	 */
	private ArrayList mCopiedDataObjectsList = new ArrayList();


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


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


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


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



	/**
	 * Load image objects.
	 * @return a map object
	 */
	private Map loadImages()
	{
		String[] keys = {
			SAMURAI_IMG_FILENAME,
			NEW_WINDOW_ICON_FILENAME,
			DRAW_GRAPH_ICON_FILENAME,
			LOAD_PROPERTY_ICON_FILENAME,
			SAVE_PROPERTY_ICON_FILENAME,
			EXPORT_IMAGE_ICON_FILENAME,
			BOUNDING_BOX_ICON_FILENAME,
			INSERT_LABEL_ICON_FILENAME,
			INSERT_SIGDIFF_ICON_FILENAME,
			INSERT_BREAK_ICON_FILENAME,
			INSERT_TIMING_ICON_FILENAME,
			LOCK_ICON_FILENAME,
			UNLOCK_ICON_FILENAME
		};
		
		final int num = keys.length;

		ImageIcon[] icons = new ImageIcon[num];
		for( int ii=0; ii<num; ii++ )
		{
			icons[ii] = this.createIcon( keys[ii] );
		}

		MediaTracker mt = new MediaTracker(this);
		HashMap m = new HashMap();
		for( int ii=0; ii<num; ii++ )
		{
			m.put( keys[ii], icons[ii] );
			mt.addImage( icons[ii].getImage(), ii );
		}

		try
		{
			mt.waitForAll();
		}
		catch( InterruptedException e )
		{
			e.printStackTrace();
		}

		return m;
	}



	private static final String SAMURAI_IMG_FILENAME = "Samurai.gif";

	private static final String NEW_WINDOW_ICON_FILENAME = "NewGraph.png";
	private static final String DRAW_GRAPH_ICON_FILENAME = "DrawGraph.png";
	private static final String LOAD_PROPERTY_ICON_FILENAME = "LoadProperty.png";
	private static final String SAVE_PROPERTY_ICON_FILENAME = "SaveGraph.png";
	private static final String EXPORT_IMAGE_ICON_FILENAME = "ExportImage.png";
	private static final String BOUNDING_BOX_ICON_FILENAME = "BoundingBox.png";
	private static final String INSERT_LABEL_ICON_FILENAME = "InsertString.png";
	private static final String INSERT_SIGDIFF_ICON_FILENAME = "InsertSig.png";
	private static final String INSERT_BREAK_ICON_FILENAME = "InsertBreak.png";
	private static final String INSERT_TIMING_ICON_FILENAME = "InsertTiming.png";
	private static final String LOCK_ICON_FILENAME = "LockFigure.png";
	private static final String UNLOCK_ICON_FILENAME = "UnlockFigure.png";





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

		// load images		
		Map map = this.loadImages();


		// update the UI
		SwingUtilities.updateComponentTreeUI(this);


		// icon image
		final ImageIcon icon = (ImageIcon)map.get( SAMURAI_IMG_FILENAME );
		this.setIconImage( icon.getImage() );


		// create a pop-up menu
		this.createPopupMenu();


		// create a property dialog
		this.createPropertyDialog();


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


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


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


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


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


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


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


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


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


		// pack
		this.pack();


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


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

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

		//
		this.addMouseWheelListener(this);


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


		//
		// update items
		//

		this.updateItemsByFigureNumbers();
		this.updateGridItems();
		this.updatePaperItems();

		return true;

	}



	/**
	 * 
	 * @return
	 */
	public boolean updateItemsByFigureNumbers()
	{
		final boolean flag = ( this.getVisibleFigureListFromMap().size() !=0 );

		this.mExportFormatButton.setEnabled( flag );
		this.mSavePropertyButton.setEnabled( flag );
		this.setInsertToggleItemsEnabled( flag );
		this.mBoundingBoxButton.setEnabled( flag );

		{
			JMenuItem item = this.getMenuItem( MENUBAR_FILE, MENUBARCMD_EXPORT_AS_IMAGE );
			item.setEnabled( flag );
		}
		{
			JMenuItem item = this.getMenuItem( MENUBAR_FILE, MENUBARCMD_SAVE_PROPERTY );
			item.setEnabled( flag );
		}

		{
			JMenuItem item = this.getMenuItem( MENUBAR_FILE, MENUBARCMD_PRINT );
			item.setEnabled( flag );
		}

//		{
//			JMenuItem item = this.getMenuItem( MENUBAR_FILE, MENUCMD_PREVIEW );
//			item.setEnabled( flag );
//		}

		{
			final JMenu layout = this.getMenuFromMenuBar( MENUBAR_LAYOUT );
			final JMenu paper = this.getMenu( layout, MENUBAR_PAPER_SIZE );
			final JMenuItem item = this.getMenuItem( paper, MENUBARCMD_BOUNDING_BOX );
			item.setEnabled( flag );
		}
		{
			JMenuItem item = this.getMenuItem( MENUBAR_ARRANGE, MENUBARCMD_AUTO_ARRANGEMENT );
			item.setEnabled( flag );
		}

		return true;
	}



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



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

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


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

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

			this.mMinimumWindowSize.setSize( width, height );
		}


		// set the size of the components in window pane
		this.setComponentBounds();


		// set the client rectangle
		this.mClientRect = new Rectangle2D.Float();
//		this.updateClientRect();


		// set the paper rectangle
		final float initX = 0.0f/SGIConstants.CM_POINT_RATIO;
		final float initY = initX;
		this.setPaperOrigin( initX, initY );
//		this.setPaperSize( MediaSize.ISO.A4 );
		final float width = SGDefaultValues.PAPER_WIDTH;
		final float height = SGDefaultValues.PAPER_HEIGHT;
		this.setPaperSizeRoundingOut( width, height );

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


		return true;
	}



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



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

		Container com = this.mForegroundPanel;
		JScrollBar vBar = new JScrollBar( JScrollBar.VERTICAL, 0, 100, 0, 100 );
		JScrollBar hBar = new JScrollBar( JScrollBar.HORIZONTAL, 0, 100, 0, 100 );
		vBar.setVisible(false);
		hBar.setVisible(false);

//java.awt.GridBagConstraints gridBagConstraints;
//com.setLayout(new java.awt.GridBagLayout());
//
//gridBagConstraints = new java.awt.GridBagConstraints();
//gridBagConstraints.gridx = 0;
//gridBagConstraints.gridy = 1;
//gridBagConstraints.gridwidth = 1;
//gridBagConstraints.weightx = 1.0;
//gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
//gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTH;
//com.add(hBar, gridBagConstraints);
//
//gridBagConstraints = new java.awt.GridBagConstraints();
//gridBagConstraints.gridx = 1;
//gridBagConstraints.gridy = 0;
//gridBagConstraints.gridheight = 1;
//gridBagConstraints.weighty = 1.0;
//gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
//gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
//com.add(vBar, gridBagConstraints);
//
//
//JPanel jPanel1 = new JPanel();
//jPanel1.setBackground(new java.awt.Color(255, 255, 255));
//gridBagConstraints = new java.awt.GridBagConstraints();
//gridBagConstraints.gridx = 1;
//gridBagConstraints.gridy = 1;
//gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
//com.add(jPanel1, gridBagConstraints);


		com.setLayout( new BorderLayout() );
		com.add( vBar, BorderLayout.EAST );
		com.add( hBar, BorderLayout.SOUTH );

		{
			final int min = hBar.getMinimum();
			final int max = hBar.getMaximum();
			final int extent = hBar.getVisibleAmount();
			hBar.setValue( (max - extent - min)/2 );
		}
		{
			final int min = vBar.getMinimum();
			final int max = vBar.getMaximum();
			final int extent = vBar.getVisibleAmount();
			vBar.setValue( (max - extent - min)/2 );
		}

		this.mHScrollBar = hBar;
		this.mVScrollBar = vBar;

		return true;
	}



	/**
	 * name : name of resource file
	 */
	private ImageIcon createIcon( final String name )
	{
		URL url = this.getClass().getResource( RESOURCES_DIRNAME + name );
		ImageIcon icon = new ImageIcon(url);
		return icon;
	}



	/**
	 * 
	 * @return
	 */
	private boolean createToolBar( Map map )
	{
		this.mCreateNewWindowButton
			= this.createButtonInToolBar( map, NEW_WINDOW_ICON_FILENAME, TIP_CREATE_NEW_WINDOW );

		this.mDrawGraphButton
			= this.createButtonInToolBar( map, DRAW_GRAPH_ICON_FILENAME, TIP_DRAW_GRAPH );

		this.mLoadPropertyButton
			= this.createButtonInToolBar( map, LOAD_PROPERTY_ICON_FILENAME, TIP_LOAD_PROPERTY );

		this.mSavePropertyButton
			= this.createButtonInToolBar( map, SAVE_PROPERTY_ICON_FILENAME, TIP_SAVE_PROPERTY );

		this.mExportFormatButton
			= this.createButtonInToolBar( map, EXPORT_IMAGE_ICON_FILENAME, TIP_EXPORT_FORMAT );

		this.mBoundingBoxButton
			= this.createButtonInToolBar( map, BOUNDING_BOX_ICON_FILENAME, TIP_BOUNDING_BOX );

		this.mInsertLabelButton
			= this.createToggleButtonInToolBar( map, INSERT_LABEL_ICON_FILENAME, TIP_INSERT_LABEL );

		this.mInsertSignificantDifferenceSymbolButton
			= this.createToggleButtonInToolBar( map, INSERT_SIGDIFF_ICON_FILENAME, TIP_INSERT_SIG_DIFF_SYMBOL );

		this.mInsertBreakButton
			= this.createToggleButtonInToolBar( map, INSERT_BREAK_ICON_FILENAME, TIP_INSERT_AXIS_BREAK_SYMBOL );

		this.mInsertTimingLineButton
			= this.createToggleButtonInToolBar( map, INSERT_TIMING_ICON_FILENAME, TIP_INSERT_TIMING_LINE );

		this.mLockFigureButton
			= this.createToggleButtonInToolBar( map, UNLOCK_ICON_FILENAME, TIP_LOCK );


//		this.mUndoButton
//			= this.createButtonInToolBar( map, "Undo.png", TIP_UNDO );
//
//		this.mRedoButton
//			= this.createButtonInToolBar( map, "Redo.png", TIP_REDO );
//
//		this.mCutButton
//			= this.createButtonInToolBar( map, "Cut.png", TIP_CUT );
//
//		this.mCopyButton
//			= this.createButtonInToolBar( map, "Copy.png", TIP_COPY );
//
//		this.mPasteButton
//			= this.createButtonInToolBar( map, "Paste.png", TIP_PASTE );
//
//		this.mPrintButton
//			= this.createButtonInToolBar( map, "Print.png", TIP_PRINT );
//
//		this.mHelpButton
//			= this.createButtonInToolBar( map, "Help.png", TIP_HELP );


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

		this.mZoomComboBoxPanel = new JPanel();
		this.mZoomComboBoxPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 6));
		this.mZoomComboBoxPanel.add(mZoomComboBox);


		// ツールバーにコンポーネントを追加
		JToolBar bar = this.mToolBar;
		String laf = SGUtility.getLookAndFeelID();
		if( LAF_WINDOWS.equals(laf) )
//		if( SGUtility.identifyOS( OS_NAME_WINDOWS ) )
		{
			bar.setRollover(true);
		}


		bar.add(this.mCreateNewWindowButton);
		bar.add(this.mDrawGraphButton);
		bar.add(this.mLoadPropertyButton);
		bar.add(this.mSavePropertyButton);
		bar.add(this.mExportFormatButton);
		bar.add(this.mBoundingBoxButton);
		bar.addSeparator();
		bar.add(this.mInsertLabelButton);
		bar.add(this.mInsertSignificantDifferenceSymbolButton);
		bar.add(this.mInsertBreakButton);
		bar.add(this.mInsertTimingLineButton);
		bar.addSeparator();
		bar.add(this.mLockFigureButton);
		bar.addSeparator();
		bar.add(this.mZoomComboBoxPanel);


//		bar.add(this.mCreateNewWindowButton);
//		bar.add(this.mDrawGraphButton);
//		bar.add(this.mLoadPropertyButton);
//		bar.add(this.mSavePropertyButton);
//		bar.add(this.mExportFormatButton);
//		bar.add(this.mPrintButton);
//		bar.addSeparator();
//		bar.add(this.mUndoButton);
//		bar.add(this.mRedoButton);
//		bar.add(this.mCutButton);
//		bar.add(this.mCopyButton);
//		bar.add(this.mPasteButton);
//		bar.addSeparator();
//		bar.add(this.mInsertLabelButton);
//		bar.add(this.mInsertSignificantDifferenceSymbolButton);
//		bar.add(this.mInsertBreakButton);
//		bar.add(this.mInsertTimingLineButton);
//		bar.addSeparator();
//		bar.add(this.mBoundingBoxButton);
//		bar.add(this.mLockFigureButton);
//		bar.addSeparator();
//		bar.add(this.mHelpButton);
//		bar.addSeparator();
//		bar.add(this.mZoomComboBoxPanel);


		bar.setOrientation( JToolBar.HORIZONTAL );
		bar.setFloatable( false );
		bar.addPropertyChangeListener( this );

		this.setToolBar();


		//
		this.mInsertLabelButton.addActionListener(this);
		this.mInsertTimingLineButton.addActionListener(this);
		this.mInsertSignificantDifferenceSymbolButton.addActionListener(this);
		this.mSavePropertyButton.addActionListener(this);
		this.mExportFormatButton.addActionListener(this);
		this.mDrawGraphButton.addActionListener(this);
		this.mLoadPropertyButton.addActionListener(this);
		this.mInsertBreakButton.addActionListener(this);
		this.mLockFigureButton.addActionListener(this);
		this.mCreateNewWindowButton.addActionListener(this);
		this.mBoundingBoxButton.addActionListener(this);

		return true;
	}


	private JButton createButtonInToolBar( Map map, String name, String tip )
	{
		ImageIcon icon = (ImageIcon)map.get(name);
		icon.getImage();
		JButton b = new JButton( icon );
		b.setToolTipText( tip );
		return b;
	}


	private JToggleButton createToggleButtonInToolBar( Map map, String name, String tip )
	{
		ImageIcon icon = (ImageIcon)map.get(name);
		JToggleButton b = new JToggleButton( icon );
		b.setToolTipText( tip );
		return b;
	}



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

		this.getContentPane().remove( this.mToolBar );


		final int ori = this.mToolBar.getOrientation();
		if( ori == JToolBar.HORIZONTAL )
		{
			this.getContentPane().add( this.mToolBar, BorderLayout.NORTH );
		}
		else if( ori == JToolBar.VERTICAL )
		{
			this.getContentPane().add( this.mToolBar, BorderLayout.WEST );
		}

		return true;
	}



	/**
	 * 
	 */
	private int getToolBarHeight()
	{
		int height = 0;
		if( this.mToolBar.isVisible() )
		{
			height = this.mToolBar.getHeight();
		}
		return height;
	}


	/**
	 * 
	 * @return
	 */
	private int getToolBarWidth()
	{
		int width = 0;
		if( this.mToolBar.isVisible() )
		{
			width = this.mToolBar.getWidth();
		}
		return width;
	}


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

		ImageIcon iconLock;
		if( flag )
		{
			iconLock = this.createIcon( LOCK_ICON_FILENAME );
		}
		else
		{
			iconLock = this.createIcon( UNLOCK_ICON_FILENAME );
		}

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

		this.mLockFigureButton.setSelected( flag );
		this.mLockFigureButton.setIcon( iconLock );

		return true;
	}


	/**
	 * 
	 * @return
	 */
	protected boolean isInsertLabelButtonSelected()
	{
		return this.mInsertLabelButton.isSelected();
	}
	

	/**
	 * 
	 * @return
	 */
	protected boolean isInsertTimingLineButtonSelected()
	{
		return this.mInsertTimingLineButton.isSelected();
	}

	
	/**
	 * 
	 * @return
	 */
	protected boolean isInsertBreakButtonSelected()
	{
		return this.mInsertBreakButton.isSelected();
	}

	
	/**
	 * 
	 * @return
	 */
	protected boolean isInsertSignificantDifferenceSymbolButtonSelected()
	{
		return this.mInsertSignificantDifferenceSymbolButton.isSelected();
	}


	/**
	 * 
	 * @return
	 */
	private boolean createBackgroundPanel()
	{
		BackgroundPanel p = new BackgroundPanel( this );
		mLayeredPane.add(p);
		mLayeredPane.setLayer( p, LAYER_GRID_PANEL );

		this.mBackgroundPanel = p;

		return true;
	}



	/**
	 * 
	 */
	private boolean createZoomComboBox()
	{
		JComboBox box = new JComboBox();
		this.mZoomComboBox = box;
		
		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++ )
		{
			box.addItem( items[ii] );
		}

		box.setEditable( true );
		box.setToolTipText( TIP_ZOOM );
		box.setFont( new java.awt.Font("Dialog", 1, 12) );

		Dimension dim;
		String laf = SGUtility.getLookAndFeelID();
		if( !LAF_AQUA.equals(laf) & !LAF_WINDOWS.equals(laf) )
		{
			dim = new Dimension(120,25);
			box.setBackground( Color.WHITE );
			box.setBorder( BorderFactory.createLoweredBevelBorder() );
		}
		else
		{
			dim = new Dimension(120,22);
		}
		box.setPreferredSize(dim);
		this.setDefaultZoom();

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

		return true;
	}



	/**
	 * 
	 */
	private boolean createForegroundPanel()
	{
		ForegroundPanel p = new ForegroundPanel( this );

		mLayeredPane.add( p, BorderLayout.CENTER );
		mLayeredPane.setLayer( p, LAYER_ANCHOR_PANEL );

		this.mForegroundPanel = p;

		return true;
	}



	/**
	 * 
	 * @return
	 */
	private boolean createRulerPanel()
	{
		RulerPanel p = new RulerPanel( this );
		this.mLayeredPane.add(p);
		this.mLayeredPane.setLayer( p, LAYER_RULER_PANEL );

		this.mRulerPanel = p;

		return true;
	}



	protected boolean mRulerVisibleFlag = true;

	public int getRulerWidth()
	{
		int width = 0;
		if( this.mRulerVisibleFlag )
		{
			width = RulerPanel.RULER_WIDTH;
		}
		return width;
	}



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

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

		SGUtility.addItem( p, this, MENUCMD_PASTE );

		p.addSeparator();

		SGUtility.addItem( p, this, MENUCMD_PROPERTY );

		return true;
	}




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



	/**
	 * 
	 */
//	public void finalize()
//	{
//		System.out.println(this);
//	}



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


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



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


	/**
	 * 
	 * @return
	 */
	public boolean isGridVisible()
	{
		return this.mBackgroundPanel.isGridVisible();
	}


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


	/**
	 * 
	 * @return
	 */
	public float getGridInterval()
	{
		return this.mBackgroundPanel.getGridInterval();
	}


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



	/**
	 * 
	 */
	public void setGridLineWidth( final float width )
	{
		this.mBackgroundPanel.setGridLineWidth( width );
	}


	/**
	 * 
	 */
	public void setGridLineColor( final Color color )
	{
		this.mBackgroundPanel.setGridLineColor( color );
	}


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

		this.mBackgroundPanel.setPaperColor( color );

		return true;
	}



	/**
	 * 
	 * @param b
	 * @return
	 */
	public void setGridVisible( final boolean b )
	{
		this.mBackgroundPanel.setGridVisible(b);
	}


	/**
	 * 
	 */
	public void setGridInterval( final float interval )
	{
		this.mBackgroundPanel.setGridInterval( interval );
	}



	/**
	 * 
	 */
	public Color getPaperColor()
	{
		return this.mBackgroundPanel.getPaperColor();
	}


	static float getAnchorSize()
	{
		return ForegroundPanel.ANCHOR_SIZE;
	}


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

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

		// ツールバーの幅
		int tHeight = 0;
		if( this.mToolBar.getOrientation() == JToolBar.HORIZONTAL )
		{
			tHeight = this.getToolBarHeight();
		}


		final int width = iTop + menuBarWidth + tHeight;

		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;

		int tWidth = 0;
		if( this.mToolBar.getOrientation() == JToolBar.VERTICAL )
		{
			tWidth = this.getToolBarWidth();
		}

		return iLeft + tWidth;
	}



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



	/**
	 * 
	 * @return
	 */
	public float getMagnification()
	{
		return this.mMagnification;
	}



	/**
	 * 
	 * @return
	 */
	public float getMagnificationPercent()
	{
		return this.mMagnification*100.0f;
	}



	/**
	 * 
	 * @param creator
	 */
	public void setImageFileCreator( SGIImageExportManager creator )
	{
		this.mImageExportManager = creator;
	}



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


	/**
	 * 
	 */
	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.addFigure_( id, figure );

		return true;

	}



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

		this.addFigure_( id, figure );

		Point2D location = this.getLocationOnFigure(pos);
		figure.setGraphRectLocation(
			(float)location.getX(), (float)location.getY()
		);

		return true;
	}



	private boolean addFigure_( 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();
		final int rWidth = this.getRulerWidth();
		figure.setLocation( rWidth, rWidth );
		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 );


		//
		this.updateItemsByFigureNumbers();


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



	/**
	 * 
	 * @return
	 */
	public ArrayList getFigureListFromLayer()
	{
		ArrayList list = new ArrayList( Arrays.asList( this.getFigureArrayFromLayer() ) );
		return list;
	}


	/**
	 * 
	 * @return
	 */
	public ArrayList getFigureListFromMap()
	{
		ArrayList list = new ArrayList( Arrays.asList( this.getFigureArrayFromMap() ) );
		return list;
	}



	/**
	 * 
	 */
	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( this.drawBackFigure( fig ) == false )
			{
				return false;
			}
		}
		return true;
	}



	/**
	 * 
	 * @param figure
	 * @return
	 */
	public boolean drawBackFigure( final SGFigure figure )
	{
		return figure.drawbackFigure();
	}

	
	/**
	 * 
	 * @param figure
	 */
	public void moveToBack( SGFigure figure )
	{
		this.move( figure, false );
	}


	/**
	 * 
	 * @param figure
	 */
	public void moveToFront( SGFigure figure )
	{
		this.move( figure, true );
	}



	private void move( SGFigure figure, boolean toFront )
	{
		JLayeredPane p = this.mLayeredPane;
//		List before = Arrays.asList( p.getComponents() );

		if( toFront )
		{
			p.moveToFront( figure );
		}
		else
		{
			p.moveToBack( figure );
		}

//		List after = Arrays.asList( p.getComponents() );
//		this.setChanged( !before.equals(after) );
//		this.notifyToRoot();
	}


	

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



	/**
	 * 
	 * @param figure
	 * @return
	 */
	protected boolean hideFigure( SGFigure figure )
	{
		figure.setVisible( false );
		figure.setChanged( true );
		return true;
	}



	/**
	 * 
	 * @return
	 */
	public boolean clearFocusedObjects()
	{
		ArrayList list = this.getFocusedObjectsList();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGISelectable s = (SGISelectable)list.get(ii);
			s.setSelected(false);
		}
		return true;
	}


	/**
	 * 
	 * @return
	 */
	public ArrayList getFocusedObjectsList()
	{
		ArrayList list = new ArrayList();
		this.getFocusedObjectsList(list);
		return list;
	}



	/**
	 * 
	 * @param list
	 * @return
	 */
	public boolean getFocusedObjectsList( ArrayList list )
	{
		ArrayList fList = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<fList.size(); ii++ )
		{
			SGISelectable s = (SGISelectable)fList.get(ii);
			if( s.isSelected() )
			{
				list.add(s);
			}
		}
		return true;
	}


	/**
	 * 
	 * @return
	 */
	public ArrayList getCopiedFiguresList()
	{
		return new ArrayList( this.mCopiedFiguresList );
	}


	/**
	 * 
	 *
	 */
	public boolean hideSelectedObjects()
	{
		ArrayList list = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			if( figure.isSelected() )
			{
				this.hideFigure( figure );
			}
			else
			{
				if( figure.hideSelectedObjects() == false )
				{
					return false;
				}
			}
		}
		
		if( list.size()!=0 )
		{
			//
			this.setChanged(true);


			// clear the list
			this.clearFocusedObjects();
				

			//
			this.updateItemsByFigureNumbers();
		}
		
		return true;
	}



	/**
	 *
	 *
	 */
	protected void setSelectionSymbolsVisible( final boolean b )
	{
		ArrayList list = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.setSelectionSymbolsVisible(b);
		}
	}

	
	/**
	 * 
	 */
	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.setFocusedFigure( figure, false );

		return true;
	}



	/**
	 * Clear focused figures and focused objects in all figures.
	 */
	public boolean clearAllFocusedObjectsInFigures()
	{
		ArrayList list = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure fig = (SGFigure)list.get(ii);
			if( fig.clearFocusedObjects() == false )
			{
				return false;
			}
		}
		if( this.clearFocusedFigures() == false )
		{
			return false;
		}
		return true;
	}



	/**
	 * Clear focused figures.
	 * @return true:succeeded, false:failed
	 */
	public boolean clearFocusedFigures()
	{
		ArrayList list = this.getFocusedObjectsList();
		for( int ii=list.size()-1; ii>=0; ii-- )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			this.setFocusedFigure( figure, false );
		}
		return true;
	}



	/**
	 * Set the focused figures.
	 * @param figure figure
	 * @param focused flag to set
	 * @return true:succeeded, false:failed
	 */
	public boolean setFocusedFigure( final SGFigure figure, final boolean b )
	{
		figure.setSelected(b);
		figure.setSymbolsVisibleAroundAllObjects(b);
		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 )
	{
		final int rw = this.getRulerWidth();
		final float xx = x - this.getLeftWidth() - rw;
		final float yy = y - this.getTopWidth() - rw;
		return new Point2D.Float(xx,yy);
	}



	/**
	 * 
	 * @param pos
	 * @return
	 */
	public Point2D getLocationOnFigure( final Point pos )
	{
		return this.getLocationOnFigure( pos.x, pos.y );
	}





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

	/**
	 * 
	 */
	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 )
	{
		Rectangle2D cRect = this.getClientRect();
		Rectangle2D vpRect = this.getViewportBounds();

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

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

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

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

		// set the block increment to be equal to the extent
		bar.setBlockIncrement( extent );

		return true;
	}






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



	/**
	 * ビューポートのサイズを取得する
	 */
	public SGTuple2f getViewportSize()
	{
		final SGTuple2f size = this.getPaneSize();
		final int rw = this.getRulerWidth();
		size.x -= rw;
		size.y -= rw;
		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;
	}


	/**
	 * 
	 * @param x
	 * @param y
	 * @return
	 */
	public boolean setPaperOrigin( final float x, final float y )
	{
		final Rectangle2D cRect = this.getClientRect();
		final float mag = this.mMagnification;
		final float xx = ( x - (float)cRect.getX() )/mag;
		final float yy = ( y - (float)cRect.getY() )/mag;
		this.mPaperOrigin.setValues( xx, yy );
		return true;
	}



	/**
	 * 
	 * @param w
	 * @param h
	 * @return
	 */
	public boolean setPaperSize( final float w, final float h )
	{
		this.setPaperSizeRoundingOut( w, h );
//		this.mPaperSize.setValues( w/this.mMagnification, h/this.mMagnification );
		return true;
	}



	/**
	 * 
	 * @return
	 */
	public float getPaperX()
	{
		final Rectangle2D cRect = this.getClientRect();
		return (float)cRect.getX() + this.mMagnification*this.mPaperOrigin.x;
	}


	/**
	 * 
	 * @return
	 */
	public float getPaperY()
	{
		final Rectangle2D cRect = this.getClientRect();
		return (float)cRect.getY() + this.mMagnification*this.mPaperOrigin.y;
	}


	/**
	 * 
	 * @return
	 */
	public float getPaperWidth()
	{
		return this.mMagnification*this.mPaperSize.x;
	}


	/**
	 * 
	 * @return
	 */
	public float getPaperHeight()
	{
		return this.mMagnification*this.mPaperSize.y;
	}




	/**
	 * 
	 * @return
	 */
	public Rectangle2D getPaperRect()
	{
		Rectangle2D rect = new Rectangle2D.Float(
			this.getPaperX(), this.getPaperY(),
			this.getPaperWidth(), this.getPaperHeight() );
		return rect;
	}



	public static final float PAPER_MARGIN = 2.0f/SGIConstants.CM_POINT_RATIO;


	/**
	 * 
	 * @return
	 */
	public Rectangle2D getBoundingBox()
	{
		Rectangle2D rect = new Rectangle2D.Float();

		final float margin = this.mMagnification*PAPER_MARGIN;
		Rectangle2D pRect = this.getPaperRect();
		rect.setRect(
			pRect.getX(),
			pRect.getY(),
			pRect.getWidth() + margin,
			pRect.getHeight() + margin
		);

//		if( this.getVisibleFigureListFromMap().size()!=0 )
//		{
//			Rectangle2D fRect = this.getBoundingBoxOfFigures( this.getVisibleFigureListFromMap() );
//			if( fRect!=null )
//			{
//				rect = rect.createUnion(fRect);
//			}
//		}

		return rect;
	}



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

		this.mTemporaryViewportSize.setSize( width, 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 int rw = this.getRulerWidth();
		final float sizeX = width + iLeft + iRight + rw;
		final float sizeY = height + iTop + iBottom
			+ menuBarWidth + toolBarWidth + rw;
		this.setSize( (int)sizeX, (int)sizeY );


		return true;

	}



	/**
	 * 
	 * @return
	 */
	protected boolean setComponentBounds()
	{
		SGTuple2f paneSize = this.getPaneSize();
		final int width = (int)paneSize.x;
		final int height = (int)paneSize.y;
		final int rw = getRulerWidth();

//System.out.println(width+"  "+height);
		
		this.mLayeredPane.setSize( width, height );
		this.mRulerPanel.setBounds( 0, 0, width, height );
		this.mForegroundPanel.setBounds( rw, rw, width - rw, height - rw );
		this.mForegroundPanel.setPreferredSize( new Dimension( width - rw, height - rw ) );
		this.mForegroundPanel.validate();
		this.mBackgroundPanel.setBounds( rw, rw, width - rw, height - rw );

		return true;
	}



	/**
	 * ウインドウリサイズ時に行われる処理
	 */
	private boolean onResized()
	{

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


		// set the size of the components
		this.setComponentBounds();


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


		// ratio of the viewport size
		final float ratioX = size.x/this.mTemporaryViewportSize.width;
		final float ratioY = size.y/this.mTemporaryViewportSize.height;


		//
		this.updateClientRect();


		//
//		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.recordFigureRect();
			figure.setSize( vpSize );
			figure.setViewBounds();
		}


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

			// resize the paper
			Rectangle2D pRect = this.getPaperRect();
			final float pWidth = ratioX*(float)pRect.getWidth()/this.mMagnification;
			final float pHeight = ratioY*(float)pRect.getHeight()/this.mMagnification;
			this.setPaperSizeRoundingOut( pWidth, pHeight );

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

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


			this.setChanged(true);
			this.notifyToRoot();

		}



		//
		this.mTemporaryViewportSize.setSize( size.x, size.y );


		//
		this.zoomWithBoundingBox();


		return true;
	}



	/**
	 * 
	 * @param mag
	 * @return
	 */
	public boolean setZoom( final Number mag )
	{
		this.mZoomComboBox.setSelectedItem( mag );
		this.updateZoomItems();
		return true;
	}


	/**
	 * 
	 * @return
	 */
	private boolean setDefaultZoom()
	{
		return this.setZoom( new Integer( DEFAULT_ZOOM ) );
	}



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

		//
		// check
		//

		// cl：倍率＝（クライアント領域）／（ウインドウペイン）×100
		float cl = 0.0f;
		try
		{
			Object obj = this.mZoomComboBox.getSelectedItem();
			cl = Float.valueOf( obj.toString() ).floatValue();
		}
		catch( NumberFormatException ex )
		{
			this.setZoom( new Float( this.getMagnificationPercent() ) );
//System.out.println("数値を入力して下さい。");
			return false;
		}

		if( cl < 0.0 )
		{
			this.setZoom( new Float( this.getMagnificationPercent() ) );
//System.out.println("正の数値を入力して下さい。");
			return false;
		}
		if( cl < MIN_MAGNIFICATION_VALUE )
		{
			this.setZoom( new Integer( MIN_MAGNIFICATION_VALUE ) );
		}
		if( cl > MAX_MAGNIFICATION_VALUE )
		{
			this.setZoom( new Integer( MAX_MAGNIFICATION_VALUE ) );
		}


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

		return true;

	}



	/**
	 * 
	 */
	private boolean zoom( final float cl )
	{

		//
		this.mMagnification = cl;


		// zoom figures
		SGFigure[] array = this.getFigureArrayFromMap();
		for( int ii=0; ii<array.length; ii++ )
		{
			if( array[ii].zoom( this.mMagnification ) == false )
			{
				throw new Error();
			}
		}

		// zoom panels
		this.mRulerPanel.setMagnification( cl );
		this.mBackgroundPanel.setMagnification( cl );
		this.mForegroundPanel.setMagnification( cl );


		//
		this.updateClientRect();

		//
//		this.setScrollBarValue();


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

		Rectangle2D cRect = this.getClientRect();
		Rectangle2D pRect = this.getPaperRect();
		float width = (float)pRect.getWidth();
		float height = (float)pRect.getHeight();
		final float mag = this.mMagnification;

		if( mode==0 || mode==1 )
		{
			width = (float)( - cRect.getX() + bbRect.getX() + bbRect.getWidth() )/mag;
//			width = (float)( bbRect.getWidth() )/mag;
		}
		if( mode==0 || mode==2 )
		{
			height = (float)( - cRect.getY() + bbRect.getY() + bbRect.getHeight() )/mag;
//			height = (float)( bbRect.getHeight() )/mag;
		}

		this.setPaperSizeRoundingOut( width, height );

		this.updateClientRect();

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

			Rectangle2D rect = figure.getBoundingBox();
			if( rect==null )
			{
				return null;
			}
			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;

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

			//
			this.updateGraphRectOfAllFigures();


			this.getContentPane().repaint();

		}

	}



	/**
	 * 
	 * @param flag
	 * @return
	 */
	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="+value);


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

		final float cx = (float)cRect.getX();
		final float cy = (float)cRect.getY();
		final float cWidth = (float)cRect.getWidth();
		final float cHeight = (float)cRect.getHeight();
		final float vpWidth = (float)vpRect.getWidth();
		final float vpHeight = (float)vpRect.getHeight();

		if( flag )
		{
			final float diff = cWidth - vpWidth;
			final float x = - value*diff;
			this.setClientRect(
				x, cy, cWidth, cHeight
			);
		}
		else
		{
			final float diff = cHeight - vpHeight;
			final float y = - value*diff;
			this.setClientRect(
				cx, y, cWidth, cHeight
			);
		}

		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].getGraphRect();
			Point p = this.getLocationInPane(x,y);
			if( rect.contains(p) )
			{
				com = array[ii];
				break;
			}
		}

		return com;
	}













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


	/**
	 * バウンドプロパティの変更時に呼び出されます。
	 */
	public void propertyChange( PropertyChangeEvent e )
	{
		Object source = e.getSource();
		String pName = e.getPropertyName();
		Object oldValue = e.getOldValue();
		Object newValue = e.getNewValue();
	}



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

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

	/**
	 * コンポーネントの位置が変わると呼び出されます。 
	 */
	public void componentMoved(final ComponentEvent e)
	{
//System.out.println(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();
	}



	private int getTopShift()
	{
		return this.getTopWidth() + this.getRulerWidth();
	}


	private int getLeftShift()
	{
		return this.getLeftWidth() + this.getRulerWidth();
	}



	/**
	 * コンポーネント上でマウスボタンをクリック (押してから離す) したときに呼び出されます。
	 */
	public void mouseClicked(final MouseEvent e)
	{
		final int ls = this.getLeftShift();
		final int ts = this.getTopShift();
		e.translatePoint( -ls, -ts );
		if( this.clickFigures(e) )
		{
			this.updateDataItem();
			this.updateFocusedObjectItem();
			return;
		}
		e.translatePoint( ls, ts );

		this.onMouseClicked(e);
		this.updateDataItem();
		this.updateFocusedObjectItem();
	}


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

		// clear all focused figures and focused objects in all figures
		this.clearAllFocusedObjectsInFigures();


		// set the default cursor
		this.setDefaultCursor();


		// マウス左ボタンダブルクリックでプロパティダイアログを出す
		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;

	}


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

		//
		dg.addPropertySettingListener(this);

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

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

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

		// create temporary objects
		this.createTemporaryPropertyObject();

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

		dg.removeAllPropertySettingListeners();

		return true;
	}



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

		ArrayList list = this.getVisibleFigureListFromLayer();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			if( figure.onMouseClicked(e) )
			{
				return true;
			}

		}

		return false;
	}


	/**
	 * Update the list of focused objects when the mouse is pressed.
	 * @return
	 */
/*	protected boolean updateFocusedObjectsList(
		final SGISelectable el, final MouseEvent e )
	{
		final ArrayList fList = this.getFocusedObjectsList();

		// Neither CTRL key nor SHIFT key is pressed.
		final int mod = e.getModifiers();
		if( ( ( mod & MouseEvent.CTRL_MASK ) == 0 )
			& ( ( mod & MouseEvent.SHIFT_MASK ) == 0 ) )
		{
			// If the list already contains this object.
			if( fList.contains(el) )
			{
				// There is nothing to do.
			}
			else
			{
				this.clearFocusedObjects();
				el.setSelected(true);
			}

		}
		// otherwise
		else
		{
			// If the list already contains this object.
			el.setSelected( !el.isSelected() );
		}

		return true;
	}
*/


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

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


		AbstractButton selectedButton = null;
		ArrayList tList = this.getInsertToggleButtonList();
		for( int ii=0; ii<tList.size(); ii++ )
		{
			AbstractButton btn = (AbstractButton)tList.get(ii);
			if( btn.isSelected() )
			{
				selectedButton = btn;
				break;
			}
		}
		
		if( selectedButton!=null )
		{

			String msg = null;
			for( int ii=0; ii<list.size(); ii++ )
			{
				SGFigure figure = (SGFigure)list.get(ii);
				figure.onMouseReleased(e);

				// add symbols to the figure by the toggle buttons
				if( figure.onToggleSelected(e) )
				{
					// set the default cursor
					this.setDefaultCursor();

					// set insert items unselected
					this.setInsertToggleItemsUnselected();

					return true;
				}
			}

			
			if( this.mInsertLabelButton.isSelected() |
				this.mInsertBreakButton.isSelected() |
				this.mInsertSignificantDifferenceSymbolButton.isSelected() )
			{
				msg = "Click the figure.";
			}
			else if( this.mInsertTimingLineButton.isSelected() )
			{
				msg = "Click the axis line.";
			}
			else
			{
				msg = "Failed to add a symbol.";
			}

			SGUtility.showMessageDialog(
				this,
				msg,
				"Error", 
				JOptionPane.WARNING_MESSAGE );

		}
		else
		{

			// notify the mouse release to figures
			for( int ii=0; ii<list.size(); ii++ )
			{
				SGFigure figure = (SGFigure)list.get(ii);
				figure.onMouseReleased(e);
			}

			
			// 履歴に残す
			ArrayList fList = this.getFocusedObjectsList();
			for( int ii=0; ii<fList.size(); ii++ )
			{
				SGFigure figure = (SGFigure)fList.get(ii);
				if( figure.isFigureMoved() )
				{
					figure.setChanged(true);
				}
			}

			fList = this.getVisibleFigureListFromMap();
			for( int ii=0; ii<fList.size(); ii++ )
			{
				SGFigure figure = (SGFigure)fList.get(ii);
				SGIFigureElement[] array = figure.getIFigureElementArray();
				for( int jj=0; jj<array.length; jj++ )
				{
					array[jj].setChangedFocusedObjects();
				}
			}
			
			
			
			// update the client rectangle
			this.updateClientRect();
//			this.setScrollBarValue();


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

		return true;

	}



	/**
	 * 
	 */
	protected boolean pressFigures( final MouseEvent e )
	{
		SGFigure[] array = this.getFigureArrayFromLayer();
		for( int ii=0; ii<array.length; ii++ )
		{
			if( array[ii].isVisible() == false )
			{
				continue;
			}

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

		return false;
	}





	/**
	 * 
	 */
	protected void onMouseDraggedOnFigures( final MouseEvent e )
	{
		ArrayList list = this.getVisibleFigureListFromLayer();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			if( !figure.onMouseDragged(e) )
			{
				return;
			}
		}

		return;
	}



	/**
	 * Translate all selected objects.
	 * 
	 * @param dx
	 * @param dy
	 * @return
	 */
	public boolean translateFocusedObjects( final int dx, final int dy )
	{
		ArrayList list = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<list.size(); ii++ )
		{
			final SGFigure figure = (SGFigure)list.get(ii);
			if( figure.isSelected() )
			{
				figure.translate( dx, dy );
			}
			else
			{
				figure.translateSelectedObjects(dx,dy);
			}
		}

		
		return true;
	}



	/**
	 * 
	 * @param x	New X Coordinate
	 * @param y	New Y Coordinate
	 * @return
	 */
	protected boolean moveFocusedObjects( final int x, final int y )
	{
		final int dx = x - this.mTempMouseLocation.x;
		final int dy = y - this.mTempMouseLocation.y;

		this.translateFocusedObjects( dx, dy );

		// update the pressed point
		this.mTempMouseLocation.setLocation(
			this.mTempMouseLocation.x + dx,
			this.mTempMouseLocation.y + dy
		);

		return true;
	}



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

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

	
	private boolean mViewportPressedFlag = false;

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

		// Only when the mouse is pressed in the pane,
		// notify the mouse event to the figures
		if( this.getViewportBoundsInComponent().contains( e.getPoint() ) )
		{
			this.mViewportPressedFlag = true;
		}
		else
		{
			return;
		}


		//
		// for ruler panel
		//

		{
			final int ls = this.getLeftWidth();
			final int ts = this.getTopWidth();
			e.translatePoint( -ls, -ts );
		
			if( this.mRulerPanel.pressed(e) )
			{
				return;
			}
		
			e.translatePoint( ls, ts );
		}


		//
		// for figures
		//

		{
			final int ls = this.getLeftShift();
			final int ts = this.getTopShift();
			e.translatePoint( -ls, -ts );
		
			// record the pressed point
			this.mTempMouseLocation.setLocation( e.getPoint() );

			if( this.pressFigures(e) )
			{
				return;
			}
		
			e.translatePoint( ls, ts );
		}

		//
		this.onMousePressed(e);

	}



	/**
	 * 
	 */

	protected final Point mTempMouseLocation = new Point();



	/**
	 * 
	 */
	protected boolean onMousePressed( final MouseEvent e )
	{
		this.clearAllFocusedObjectsInFigures();
		return true;
	}



	/**
	 * コンポーネント上でマウスボタンを離すと呼び出されます。 
	 */
	public void mouseReleased(final MouseEvent e)
	{
		// Only when the mouse is pressed in the viewport,
		// notify the mouse event to the figures

		if( this.mViewportPressedFlag == false )
		{
			return;
		}		
		
		
		//
		// for ruler panel
		//

		if( this.mRulerPanel.isPressed() )
		{
			final int ls = this.getLeftWidth();
			final int ts = this.getTopWidth();
			e.translatePoint( -ls, -ts );
		
			this.mRulerPanel.released(e);
		
			e.translatePoint( ls, ts );
		}
		else
		{
			final int ls = this.getLeftShift();
			final int ts = this.getTopShift();
			e.translatePoint( -ls, -ts );
		
			this.onMouseReleasedToFigure(e);
		
			e.translatePoint( ls, ts );
		}

		
		this.getContentPane().repaint();


		// set the flag
		this.mViewportPressedFlag = false;

	}



	/**
	 * コンポーネント上でマウスのボタンを押してドラッグすると呼び出されます。 
	 */
	public void mouseDragged( final MouseEvent e )
	{
//System.out.println(e);

		// Only when the mouse is pressed in the viewport,
		// notify the mouse event to the figures
		if( this.mViewportPressedFlag == false )
		{
			return;
		}

		//
		// for ruler panel
		//

		if( this.mRulerPanel.isPressed() )
		{
			final int ls = this.getLeftWidth();
			final int ts = this.getTopWidth();
			e.translatePoint( -ls, -ts );
			this.mRulerPanel.dragged(e);
			e.translatePoint( ls, ts );
		}
		else
		{
			// notify to figures
			final int ls = this.getLeftShift();
			final int ts = this.getTopShift();
			e.translatePoint( -ls, -ts );
			this.onMouseDraggedOnFigures(e);
			e.translatePoint( ls, ts );
		}

		// call handler method of this window
		this.onMouseMovedOrDragged(e);
		this.getContentPane().repaint();
	}



	/**
	 * 
	 */
	protected void onMouseMovedOnFigures( final MouseEvent e )
	{
		ArrayList list = this.getVisibleFigureListFromLayer();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			if( figure.onMouseMoved(e) )
			{
				return;
			}
		}

		return;
	}



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

		final int ls = this.getLeftShift();
		final int ts = this.getTopShift();
		e.translatePoint( -ls, -ts );

		this.onMouseMovedOnFigures(e);

		e.translatePoint( ls, ts );

		this.onMouseMovedOrDragged(e);

	}



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


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

	}



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


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


		// ルーラ
		final double rulerWidth = this.getRulerWidth();
		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
		final int rw = this.getRulerWidth();
		xx -= rw;
		yy -= rw;


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


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

		return true;

	}


	/**
	 * 
	 */
	public static final String WINDOW_TITLE_PREFIX = "Samurai Graph - Window : ";


	/**
	 * 位置情報ラベルへの設定。
	 */
	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");

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

		final String title = WINDOW_TITLE_PREFIX + this.getID() + "  " + strPos;
		this.setTitle( title );

		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 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 void mouseWheelMoved(MouseWheelEvent e)
	{
//System.out.println(e);

		// scroll the vertical scroll bar
		JScrollBar bar = this.mVScrollBar;
		final int amount = e.getScrollAmount()*e.getWheelRotation();
		final int value = bar.getValue() + amount;
		bar.setValue( value );

	}



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



	/**
	 * 
	 */
	protected ArrayList getInsertToggleButtonList()
	{
		final ArrayList list = new ArrayList(
			Arrays.asList( this.getInsertToggleButtonArray() ) );
		return list;
	}


	/**
	 * 
	 * @return
	 */
	protected ArrayList getInsertMenuCommandList()
	{
		final ArrayList list = new ArrayList(
			Arrays.asList( this.getInsertMenuCommandArray() ) );
		return list;
	}


	/**
	 * 
	 * @return
	 */
	protected JToggleButton[] getInsertToggleButtonArray()
	{
		JToggleButton[] array = {
			this.mInsertLabelButton, this.mInsertSignificantDifferenceSymbolButton,
			this.mInsertBreakButton, this.mInsertTimingLineButton
		};

		return array;
	}


	/**
	 * 
	 * @return
	 */
	protected String[] getInsertMenuCommandArray()
	{
		String[] array = {
			MENUBARCMD_INSERT_LABEL, MENUBARCMD_INSERT_SIG_DIFF_SYMBOL,
			MENUBARCMD_INSERT_AXIS_BREAK_SYMBOL, MENUBARCMD_INSERT_TIMING_LINE
		};

		return array;
	}


	/**
	 * 
	 * @param command
	 * @return
	 */
	protected JToggleButton getInsertToggleButton( final String command )
	{
		ArrayList list = this.getInsertMenuCommandList();
		final int index = list.indexOf( command );
		JToggleButton[] array = this.getInsertToggleButtonArray();
		return array[index];
	}


	/**
	 * 
	 * @param btn
	 * @return
	 */
	protected String getInsertCommand( final JToggleButton btn )
	{
		ArrayList list = this.getInsertToggleButtonList();
		final int index = list.indexOf( btn );
		String[] array = this.getInsertMenuCommandArray();
		return array[index];
	}



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

		ArrayList itemList = this.getMenuItemList( MENUBAR_INSERT );
		for( int ii=0; ii<itemList.size(); ii++ )
		{
			SGToggleMenuItem item = (SGToggleMenuItem)itemList.get(ii);
			item.setSelected( false );
		}

		return true;
	}


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

		final ArrayList itemList = this.getMenuItemList( MENUBAR_INSERT );
		for( int ii=0; ii<itemList.size(); ii++ )
		{
			SGToggleMenuItem item = (SGToggleMenuItem)itemList.get(ii);
			item.setEnabled( flag );
		}

		return true;
	}



	/**
	 * 
	 * @return
	 */
	protected boolean isInsertToggleButtonSelected()
	{
		final ArrayList list = this.getInsertToggleButtonList();
		for( int ii=0; ii<list.size(); ii++ )
		{
			final AbstractButton btn = (AbstractButton)list.get(ii);
			if( btn.isSelected() )
			{
				return true;
			}
		}
		return false;
	}



	/**
	 * Paste the objects to the target figures.
	 * @param list - a list of the objects.
	 * @param dataList - a list of a data objects.
	 * @param nameList - a list of a data name.
	 */
	public void pasteToFigures(
		ArrayList list,
		ArrayList dataList,
		ArrayList nameList,
		ArrayList propertiesMapList )
	{
		ArrayList fList = this.getFocusedObjectsList();
		if( fList.size()==0 )
		{
			return;
		}

		// paste to the target object
		for( int ii=0; ii<fList.size(); ii++ )
		{
			SGFigure figure = (SGFigure)fList.get(ii);
			figure.paste( list );
			for( int jj=0; jj<nameList.size(); jj++ )
			{
				SGData data = (SGData)dataList.get(jj);
				String name = (String)nameList.get(jj);
				Map map = (Map)propertiesMapList.get(jj);
				SGData dataNew = (SGData)data.copy();
				figure.addData( dataNew, name, map );
			}
		}

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

	}


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



	/**
	 * 
	 *
	 */
	private void updateDataItem()
	{
		this.updateFocusedObjectItem();
	}



	/**
	 * 
	 * @return
	 */
	private void updateFocusedObjectItem()
	{
		boolean eff = false;
		ArrayList list = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			if( figure.isSelected() )
			{
				eff = true;
				break;
			}
			
			SGIFigureElement[] array = figure.getIFigureElementArray();
			for( int jj=0; jj<array.length; jj++ )
			{
				if( array[jj].getFocusedObjectsList().size()!=0 )
				{
					eff = true;
					break;
				}
			}
			
			if( eff )
			{
				break;
			}
		}
		

		// cut
		JMenuItem cut = this.getMenuItem( MENUBAR_EDIT, MENUBARCMD_CUT );
		if( cut!=null )
		{
			cut.setEnabled( eff );
		}


		// copy
		JMenuItem copy = this.getMenuItem( MENUBAR_EDIT, MENUBARCMD_COPY );
		if( copy!=null )
		{
			copy.setEnabled( eff );
		}


		// delete
		JMenuItem delete = this.getMenuItem( MENUBAR_EDIT, MENUBARCMD_DELETE );
		if( delete!=null )
		{
			delete.setEnabled( eff );
		}

		
		// duplicate
		JMenuItem duplicate = this.getMenuItem( MENUBAR_EDIT, MENUBARCMD_DUPLICATE );
		if( duplicate!=null )
		{
			duplicate.setEnabled( eff );
		}


		// move to front/back
		JMenu menu = this.getMenuFromMenuBar( MENUBAR_ARRANGE );
		if( menu!=null )
		{
			this.getMenuItem( MENUBAR_ARRANGE, MENUBARCMD_MOVE_TO_FRONT ).setEnabled( eff );
			this.getMenuItem( MENUBAR_ARRANGE, MENUBARCMD_MOVE_TO_BACK ).setEnabled( eff );
		}

	}
	
	
	
	/**
	 * 
	 * @param b
	 */
	public void setPasteMenuEnabled( final boolean b )
	{
		JMenuItem paste = this.getMenuItem( MENUBAR_EDIT, MENUBARCMD_PASTE );
		paste.setEnabled(b);
		
		Component[] array = this.mPopupMenu.getComponents();
		for( int ii=0; ii<array.length; ii++ )
		{
			if( array[ii] instanceof JMenuItem )
			{
				JMenuItem item = (JMenuItem)array[ii];
				if( item.getActionCommand().equals( MENUBARCMD_PASTE ) )
				{
					item.setEnabled(b);
				}
			}
		}
	}

	
	
	/**
	 * 
	 *
	 */
	private void updateGridItems()
	{
		final JMenu layout = this.getMenuFromMenuBar( MENUBAR_LAYOUT );

		final JMenu grid = this.getMenu( layout, MENUBAR_GRID );	
		if( grid==null )
		{
			throw new Error();
		}

		final JMenuItem plus = this.getMenuItem( grid, MENUBARCMD_PLUS_GRID );
		if( plus==null )
		{
			throw new Error();
		}
		final JMenuItem minus = this.getMenuItem( grid, MENUBARCMD_MINUS_GRID );
		if( minus==null )
		{
			throw new Error();
		}
		final JMenuItem visible = this.getMenuItem( grid, MENUBARCMD_GRID_VISIBLE );
		if( visible==null )
		{
			throw new Error();
		}
		JCheckBoxMenuItem chkVisible = (JCheckBoxMenuItem)visible;
		final boolean gridVisible = this.isGridVisible();
		chkVisible.setSelected( gridVisible );

		boolean plusFlag = false;
		boolean minusFlag = false;
		if( gridVisible )
		{
			final float interval = this.getGridInterval()*CM_POINT_RATIO;
			final float min = SGDrawingWindow.GRID_INTERVAL_MIN_VALUE;
			final float max = SGDrawingWindow.GRID_INTERVAL_MAX_VALUE;
			final float step = SGDrawingWindow.GRID_INTERVAL_STEP_SIZE;
			final int nCeilInterval = (int)Math.ceil(interval/step);
			final int nFloorInterval = (int)Math.floor(interval/step);
			final int nMin = (int)Math.rint(min/step);
			final int nMax = (int)Math.rint(max/step);
			if( nMin <= nFloorInterval )
			{
				minusFlag = true;
			}
			if( nCeilInterval <= nMax )
			{
				plusFlag = true;
			}
		}
		plus.setEnabled( plusFlag );
		minus.setEnabled( minusFlag );

		
	}



	/**
	 * 
	 */
	private boolean mPaperPortraitFlag = true;


	/**
	 * 
	 * @param b
	 */
	public void setPaperPortrait( final boolean b )
	{
		this.mPaperPortraitFlag = b;
	}


	/**
	 * 
	 * @return
	 */
	public boolean getPaperPortrait()
	{
		return this.mPaperPortraitFlag;
	}



	/**
	 * 
	 *
	 */
	private void updatePaperItems()
	{
		final JMenu layout = this.getMenuFromMenuBar( MENUBAR_LAYOUT );

		final JMenu paper = this.getMenu( layout, MENUBAR_PAPER_SIZE );
		if( paper==null )
		{
			throw new Error();
		}

		final JRadioButtonMenuItem portrait
			= (JRadioButtonMenuItem)this.getMenuItem( paper, MENUBARCMD_PAPER_PORTRAIT );
		if( portrait==null )
		{
			throw new Error();
		}

		if( this.mPaperPortraitFlag )
		{
			portrait.setSelected( true );
		}

	}



	/**
	 * 
	 *
	 */	
	private void updateZoomItems()
	{
		final int[] array = SGDrawingWindow.MAGNIFICATION_ARRAY;
		final int max = array[0];
		final int min = array[array.length-1];

		final JMenu layout = this.getMenuFromMenuBar( MENUBAR_LAYOUT );
		final int mag = (int)( this.getMagnificationPercent() );

		final JMenu zoom = this.getMenu( layout, MENUBAR_ZOOM );	
		if( zoom==null )
		{
			throw new Error();
		}

		final JMenuItem zoomIn = this.getMenuItem( zoom, MENUBARCMD_ZOOM_IN );
		if( zoomIn==null )
		{
			throw new Error();
		}

		final JMenuItem zoomOut = this.getMenuItem( zoom, MENUBARCMD_ZOOM_OUT );
		if( zoomOut==null )
		{
			throw new Error();
		}

		final JMenuItem zoomWayOut = this.getMenuItem( zoom, MENUBARCMD_ZOOM_WAY_OUT );
		if( zoomWayOut==null )
		{
			throw new Error();
		}

		final JMenuItem defaultZoom = this.getMenuItem( zoom, MENUBARCMD_DEFAULT_ZOOM );
		if( defaultZoom==null )
		{
			throw new Error();
		}

		boolean maxFlag = true;
		boolean minFlag = true;
		boolean defaultFlag = false;
		if( mag == max )
		{
			maxFlag = false;
		}
		else if( mag == min )
		{
			minFlag = false;
		}
		else if( mag == DEFAULT_ZOOM )
		{
			defaultFlag = true;
		}

		zoomIn.setEnabled( maxFlag );
		zoomOut.setEnabled( minFlag );
		zoomWayOut.setEnabled( minFlag );
		defaultZoom.setEnabled( !defaultFlag );

	}



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

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

		//
		// menu bar
		//

		if( command.equals(MENUBARCMD_EXIT) )
		{
			this.notifyToListener( NOTIFY_EXIT );
		}
		else if( command.equals(MENUBARCMD_CREATE_NEW_WINDOW) )
		{
			this.notifyToListener( NOTIFY_OPEN_WINDOW );
		}
		else if( command.equals(MENUBARCMD_CLOSE_WINDOW) )
		{
			this.closeWindow();
		}
		else if( command.equals(MENUBARCMD_DRAW_GRAPH) )
		{
			this.notifyToListener( NOTIFY_ADD_DATA );
		}
		else if( command.equals(MENUBARCMD_LOAD_PROPERTY) )
		{
			this.notifyToListener( NOTIFY_LOAD_PROPERTY );
		}
		else if( command.equals(MENUBARCMD_SAVE_PROPERTY) )
		{
			this.mPropertyFileCreationModeOfFigures = ALL_FIGURES;
			this.notifyToListener( NOTIFY_SAVE_PROPERTY );
		}
		else if( command.equals(MENUBARCMD_EXPORT_AS_IMAGE) )
		{
			this.notifyToListener( NOTIFY_EXPORT_IMAGE );
		}
		else if( command.equals(MENUBARCMD_PRINT) )
		{
			this.notifyToListener( NOTIFY_PRINT );
		}
		else if( command.equals( MENUBARCMD_PREVIEW ) )
		{
			this.previewImage();
		}
		else if( command.equals( MENUBARCMD_DELETE ) )
		{
			this.deleteFocusedObjects();
		}
		else if( command.equals( MENUBARCMD_CUT ) )
		{
			this.cutFocusedObjects();
		}
		else if( command.equals( MENUBARCMD_COPY ) )
		{
			this.copyFocusedObjects();
		}
		if( command.equals( MENUBARCMD_PASTE ) )
		{
			this.pasteCopiedObjects();
		}
		else if( command.equals( MENUBARCMD_DUPLICATE ) )
		{
			this.duplicateFocusedObjects();
		}
		else if( command.equals( MENUBARCMD_MOVE_TO_FRONT ) )
		{
			this.moveFocusedObjectsToFront();
		}
		else if( command.equals( MENUBARCMD_MOVE_TO_BACK ) )
		{
			this.moveFocusedObjectsToBack();
		}
		else if( command.equals( MENUBARCMD_UNDO ) )
		{
			this.onUndo();
		}
		else if( command.equals( MENUBARCMD_REDO ) )
		{
			this.onRedo();
		}
		else if( command.equals( MENUBARCMD_PAPER_A4_SIZE )
			|| command.equals( MENUBARCMD_PAPER_B5_SIZE )
			|| command.equals( MENUBARCMD_PAPER_USLETTER_SIZE ) )
		{

			MediaSize size = null;
			if( command.equals( MENUBARCMD_PAPER_A4_SIZE ) )
			{
				size = MediaSize.ISO.A4;
			}
			else if( command.equals( MENUBARCMD_PAPER_B5_SIZE ) )
			{
				size = MediaSize.ISO.B5;
			}
			else if( command.equals( MENUBARCMD_PAPER_USLETTER_SIZE ) )
			{
				size = MediaSize.NA.LETTER;
			}

			this.onPaperSizeChanged( size );
		}
		else if( command.equals( MENUBARCMD_PAPER_PORTRAIT )
			|| command.equals( MENUBARCMD_PAPER_LANDSCAPE ) )
		{
			this.mPaperPortraitFlag = ( command.equals(MENUBARCMD_PAPER_PORTRAIT) );
			this.updatePaperItems();
		}
		else if( command.equals( MENUBARCMD_BOUNDING_BOX ) )
		{
			this.setBoundigBox();
		}
		else if( command.equals( MENUBARCMD_PAPER_USER_CUSTOMIZE ) )
		{
			this.showPropertyDialog();
		}
		else if( command.equals( MENUBARCMD_AUTO_ARRANGEMENT ) )
		{
			this.onFiguresAligned();
		}
		else if( command.equals( MENUBARCMD_GRID_VISIBLE ) )
		{
			this.setGridVisible( !this.isGridVisible() );
			this.getContentPane().repaint();
			this.updateGridItems();

			this.setChanged(true);
			this.notifyToRoot();
		}
		else if( command.equals( MENUBARCMD_PLUS_GRID ) )
		{
			final float value = this.getGridInterval()*CM_POINT_RATIO;
			final float min = SGDrawingWindow.GRID_INTERVAL_MIN_VALUE;
			final float max = SGDrawingWindow.GRID_INTERVAL_MAX_VALUE;
			final float step = SGDrawingWindow.GRID_INTERVAL_STEP_SIZE;
			float valueNew = SGUtilityNumber.stepValue(
				true, value, min, max, step, 0.001f );
			final int indexNew = (int)Math.rint(valueNew/step);
			final int indexMax = (int)Math.rint(max/step);
			if( indexNew!=indexMax+1 )
			{
				if( valueNew > max )
				{
					valueNew = max;
				}
				this.setGridInterval( valueNew/SGIConstants.CM_POINT_RATIO );
				this.updateGridItems();

				this.setChanged(true);
				this.notifyToRoot();
			}
		}
		else if( command.equals( MENUBARCMD_MINUS_GRID ) )
		{
			final float value = this.getGridInterval()*CM_POINT_RATIO;
			final float min = SGDrawingWindow.GRID_INTERVAL_MIN_VALUE;
			final float max = SGDrawingWindow.GRID_INTERVAL_MAX_VALUE;
			final float step = SGDrawingWindow.GRID_INTERVAL_STEP_SIZE;
			float valueNew = SGUtilityNumber.stepValue(
				false, value, min, max, step, 0.001f );
			final int indexNew = (int)Math.rint(valueNew/step);
			final int indexMin = (int)Math.rint(min/step);
			if( indexNew!=indexMin-1 )
			{
				if( valueNew < min )
				{
					valueNew = min;
				}
				this.setGridInterval( valueNew/SGIConstants.CM_POINT_RATIO );
				this.updateGridItems();

				this.setChanged(true);
				this.notifyToRoot();
			}
		}
		else if( command.equals( MENUBARCMD_ZOOM_IN ) )
		{
			final int mag = (int)( this.getMagnificationPercent() );
			final int[] array = SGDrawingWindow.MAGNIFICATION_ARRAY;
			for( int ii=array.length-1; ii>=0; ii-- )
			{
				if( array[ii] > mag )
				{
					this.setZoom( new Integer( array[ii] ) );
					break;
				}
			}
		}
		else if( command.equals( MENUBARCMD_ZOOM_OUT ) )
		{
			final int mag = (int)( this.getMagnificationPercent() );
			final int[] array = SGDrawingWindow.MAGNIFICATION_ARRAY;
			for( int ii=0; ii<array.length; ii++ )
			{
				if( array[ii] < mag )
				{
					this.setZoom( new Integer( array[ii] ) );
					break;
				}
			}
		}
		else if( command.equals( MENUBARCMD_DEFAULT_ZOOM ) )
		{
			this.setDefaultZoom();
		}
		else if( command.equals( MENUBARCMD_ZOOM_WAY_OUT ) )
		{
			this.zoomWayOut();
		}
		else if( command.equals( MENUBARCMD_AUTO_ZOOM ) )
		{
			this.zoomWithBoundingBox();
		}
		else if( command.equals( MENUBARCMD_LOCK ) )
		{
			this.mLockFigureFlag = !this.mLockFigureFlag;
			this.updateLockItems();
		}
		else if( command.equals( MENUBARCMD_UPGRADE ) )
		{
			this.notifyToListener( NOTIFY_UPGRADE );
		}
		else if( command.equals( MENUBARCMD_CHANGE_LOG ) )
		{
			this.notifyToListener( NOTIFY_SHOW_CHANGE_LOG );
		}
		else if( command.equals( MENUBARCMD_PROXY ) )
		{
			this.notifyToListener( NOTIFY_SET_PROXY );
		}
		else if( command.equals( MENUBARCMD_ABOUT ) )
		{
			this.notifyToListener( NOTIFY_SHOW_ABOUT_DIALOG );
		}
		else if( command.equals( MENUBARCMD_LAF_METAL ) )
		{
			this.setLookAndFeel( LAF_CLASS_NAME_METAL );
		}
		else if( command.equals( MENUBARCMD_LAF_MOTIF ) )
		{
			this.setLookAndFeel( LAF_CLASS_NAME_MOTIF );
		}
		else if( command.equals( MENUBARCMD_LAF_WINDOWS ) )
		{
			this.setLookAndFeel( LAF_CLASS_NAME_WINDOWS );
		}
		else if( command.equals( MENUBARCMD_LAF_WINDOWSCLASSIC ) )
		{
			this.setLookAndFeel( LAF_CLASS_NAME_WINDOWSCLASSIC );
		}
		else if( command.equals( MENUBARCMD_LAF_AQUA ) )
		{
			this.setLookAndFeel( LAF_CLASS_NAME_AQUA );
		}


		// menus for insert
		ArrayList insertItemList = this.getMenuItemList( MENUBAR_INSERT );
		if( insertItemList.contains( source ) )
		{
			JToggleButton btn = this.getInsertToggleButton( command );
			JMenuItem item = (JMenuItem)source;
			item.setSelected( !item.isSelected() );

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

			// set the toggle button
			this.setInsertToggleItemsUnselected();
			btn.setSelected(b);
			item.setSelected(b);
		}




		//
		// Tool Bar
		//

		// zoom
		if( source.equals( this.mZoomComboBox ) )
		{
			this.onZoomed();
		}


		// create a new window
		if( source.equals( this.mCreateNewWindowButton ) )
		{
			this.notifyToListener( NOTIFY_OPEN_WINDOW );
		}


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

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


		// bounding box
		if( source.equals(this.mBoundingBoxButton) )
		{
			this.setBoundigBox();
		}


		// insert symbols
		final ArrayList bList = this.getInsertToggleButtonList();
		if( bList.contains(source) )
		{
			final JToggleButton btn = (JToggleButton)source;
			final String mCommand = this.getInsertCommand(btn);
			final JMenuItem item = this.getMenuItem( MENUBAR_INSERT, mCommand );
			final boolean b = btn.isSelected();
			if( b )
			{
				final Cursor cur = new Cursor( Cursor.CROSSHAIR_CURSOR );
				this.setCursor( cur );
			}
			else
			{
				this.setDefaultCursor();
			}
			
			// set the toggle button
			this.setInsertToggleItemsUnselected();
			btn.setSelected( b );
			item.setSelected( b );
		}


		// lock
		if( source.equals( this.mLockFigureButton ) )
		{
			this.mLockFigureFlag = this.mLockFigureButton.isSelected();
			this.updateLockItems();
		}


		//
		if( source.equals( this.mExportFormatButton ) )
		{
			this.notifyToListener( NOTIFY_EXPORT_IMAGE );
		}


		//
		if( source.equals( this.mSavePropertyButton ) )
		{
			this.mPropertyFileCreationModeOfFigures = ALL_FIGURES;
			this.notifyToListener( NOTIFY_SAVE_PROPERTY );
		}


		//
		// Pop-up menu
		//
		
		if( command.equals( MENUCMD_PROPERTY ) )
		{
			this.showPropertyDialog();
		}


		//
		this.getContentPane().repaint();

	}



	/**
	 * 
	 *
	 */
	void moveFocusedObjectsToFront()
	{
		ArrayList list = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.moveFocusedObjects( true );
		}
		this.notifyToRoot();
		this.updateDataItem();
	}


	/**
	 * 
	 *
	 */
	void moveFocusedObjectsToBack()
	{
		ArrayList list = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.moveFocusedObjects( false );
		}
		this.notifyToRoot();
		this.updateDataItem();
	}


	/**
	 * 
	 *
	 */
	void copyFocusedObjects()
	{
		// get copied objects from all figures
		this.copyAllObjectsInVisibleFigures();

		// notify the copy command
		this.notifyToListener( NOTIFY_COPY );

		// update the menu items
		this.updateFocusedObjectItem();
	}


	/**
	 * 
	 *
	 */
	void cutFocusedObjects()
	{
		// get copied objects from all figures
		this.cutAllObjectsInVisibleFigures();

		// notify the cut command
		this.notifyToListener( NOTIFY_CUT );

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

		// update the menu items
		this.updateFocusedObjectItem();
	}


	/**
	 * 
	 *
	 */
	void pasteCopiedObjects()
	{
		this.notifyToListener( NOTIFY_PASTE );

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


	/**
	 * 
	 *
	 */
	void duplicateFocusedObjects()
	{
		// duplicate child object of all figures
		ArrayList list = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			if( figure.duplicateFocusedObjects() == false )
			{
				return;
			}
		}

		// notify the duplication command
		this.notifyToListener( NOTIFY_DUPLICATE );

		// set unfocused the focused figures
		ArrayList fList = this.getFocusedObjectsList();
		for( int ii=0; ii<fList.size(); ii++ )
		{
			SGFigure figure = (SGFigure)fList.get(ii);
			this.setFocusedFigure( figure, false );
		}

		// set focused the duplicated figures
		ArrayList listNew = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<listNew.size(); ii++ )
		{
			SGFigure figure = (SGFigure)listNew.get(ii);
			if( list.contains(figure) == false )
			{
				this.setFocusedFigure( figure, true );
			}
		}

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


	/**
	 * 
	 *
	 */
	void deleteFocusedObjects()
	{
		// hide all focused objects
		this.hideSelectedObjects();

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

		// update the menu items
		this.updateDataItem();
	}




	/**
	 * 
	 *
	 */
	private void cutAllObjectsInVisibleFigures()
	{
		this.cutOrCopyAllObjectsInVisibleFigures(false);
	}


	/**
	 * 
	 *
	 */
	private void copyAllObjectsInVisibleFigures()
	{
		this.cutOrCopyAllObjectsInVisibleFigures(true);
	}


	/**
	 * 
	 * @param isCopy
	 */
	private void cutOrCopyAllObjectsInVisibleFigures( final boolean isCopy )
	{
		// get objects from all figures
		ArrayList fList = this.getVisibleFigureListFromMap();
		ArrayList objList = new ArrayList();
		ArrayList dataList = new ArrayList();
		ArrayList dataNameList = new ArrayList();
		ArrayList propertiesMapList = new ArrayList();
		if( isCopy )
		{
			for( int ii=0; ii<fList.size(); ii++ )
			{
				SGFigure figure = (SGFigure)fList.get(ii);
				objList.addAll( figure.createCopiedObjects() );
				figure.createCopiedDataObjects( dataList, dataNameList, propertiesMapList );
			}
		}
		else
		{
			for( int ii=0; ii<fList.size(); ii++ )
			{
				SGFigure figure = (SGFigure)fList.get(ii);
				objList.addAll( figure.cutFocusedObjects() );
				figure.cutFocusedDataObjects( dataList, dataNameList, propertiesMapList );
			}
		}


		// copy data
		ArrayList dList = new ArrayList();
		SGUtility.copyObjects( dataList, dList );


		// set to the attribute
		this.clearCopiedObjectsList();
		this.mCopiedObjectsList.addAll( objList );
		this.mCopiedDataObjectsList.addAll( dList );
		this.mCopiedDataNameList.addAll( dataNameList );
		this.mCopiedDataPropertiesMapList.addAll( propertiesMapList );
		this.mCopiedFiguresList.addAll( this.getFocusedObjectsList() );
	}



	/**
	 * Returns the list of copied objects.
	 * @return list of copied objects
	 */
	public ArrayList getCopiedObjectsList()
	{
		return new ArrayList( this.mCopiedObjectsList );
	}


	/**
	 * Returns the list of copied data objects.
	 * @return list of copied data objects
	 */
	public ArrayList getCopiedObjectsDataList()
	{
		return new ArrayList( this.mCopiedDataObjectsList );
	}


	/**
	 * 
	 * @return
	 */
	public ArrayList getCopiedDataNameList()
	{
		return new ArrayList( this.mCopiedDataNameList );
	}


	/**
	 * 
	 * @return
	 */
	public ArrayList getCopiedDataPropertiesMapList()
	{
		return new ArrayList( this.mCopiedDataPropertiesMapList );
	}


	/**
	 * Clear the list of copied objects.
	 *
	 */
	private void clearCopiedObjectsList()
	{
		this.mCopiedObjectsList.clear();
		this.mCopiedDataObjectsList.clear();
		this.mCopiedDataNameList.clear();
		this.mCopiedDataPropertiesMapList.clear();
		this.mCopiedFiguresList.clear();
	}



	/**
	 * 
	 */
	void notifyPasteToFocusedFigures()
	{
		this.mPasteTargetList.clear();
		this.mPasteTargetList.addAll( this.getFocusedObjectsList() );
		this.notifyToListener( NOTIFY_PASTE );
	}


	/**
	 * The target object to paste the copied objects.
	 */
	private ArrayList mPasteTargetList = new ArrayList();



	/**
	 * 
	 * @return
	 */
	private boolean zoomWithBoundingBox()
	{
		final JMenu layout = this.getMenuFromMenuBar( MENUBAR_LAYOUT );

		final JMenu zoom = this.getMenu( layout, MENUBAR_ZOOM );	
		if( zoom==null )
		{
			throw new Error();
		}

		final JCheckBoxMenuItem auto = (JCheckBoxMenuItem)this.getMenuItem( zoom, MENUBARCMD_AUTO_ZOOM );
		if( auto==null )
		{
			throw new Error();
		}

		if( auto.isSelected() )
		{
			this.zoomWayOut();
		}

		return true;
	}



	/**
	 * 
	 * @return
	 */
	private boolean zoomWayOut()
	{
		Rectangle2D bbRect = this.getBoundingBox();
		SGTuple2f vpSize = this.getViewportSize();
		final float ratioX = (float)( vpSize.x / ( bbRect.getWidth()/this.mMagnification ) );
		final float ratioY = (float)( vpSize.y / ( bbRect.getHeight()/this.mMagnification ) );
		final float smaller = ( ratioX < ratioY ? ratioX : ratioY );
		final int mag = (int)Math.floor(smaller*100.0f);
		this.setZoom( new Integer(mag) );
		return true;
	}


	/**
	 *
	 */	
	private void setLookAndFeel( String laf )
	{
		try
		{
			UIManager.setLookAndFeel(laf);
			SwingUtilities.updateComponentTreeUI(this);
		}
		catch(Exception ex)
		{
			System.out.println("Error L&F Setting");
		}
	}

	
	/**
	 * 
	 * @return
	 */
	private boolean updateLockItems()
	{
		final boolean flag = this.mLockFigureFlag;

		// set the toggle button
		this.setLockToggleButton( flag );

		// set the menu bar
		JCheckBoxMenuItem item
			= (JCheckBoxMenuItem)this.getMenuItem(
				MENUBAR_LAYOUT, MENUBARCMD_LOCK );		
		item.setSelected( flag );

		return true;
	}


	
	/**
	 * 
	 * @return
	 */
	private Rectangle2D getPaperRectInClientRect()
	{
		Rectangle2D rect = new Rectangle2D.Float(
			this.mPaperOrigin.x, this.mPaperOrigin.y,
			this.mPaperSize.x, this.mPaperSize.y
		);
		return rect;
	}
	
	
	private final Rectangle2D mTempPaperRect = new Rectangle2D.Float();


	/**
	 * 
	 * @return
	 */
	boolean recordPaperRect()
	{
		this.mTempPaperRect.setRect( this.getPaperRectInClientRect() );
		return true;
	}

	
	
	/**
	 * 
	 * @return
	 */
	public boolean isPaperBoundsChanged()
	{
		Rectangle temp = this.mTempPaperRect.getBounds();
		Rectangle present = this.getPaperRectInClientRect().getBounds();
		return !temp.equals(present);
	}


	/**
	 * 
	 * @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.recordFigureRect();
		}
		this.recordPaperRect();


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

		
		//
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			if( figure.isFigureMoved() )
			{
				figure.setChanged(true);
			}
		}
		if( this.isPaperBoundsChanged() )
		{
			this.setChanged(true);
		}

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


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

		//
		this.setChanged(true);
		this.notifyToRoot();

		//
		this.zoomWithBoundingBox();

		return true;
	}




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

		ArrayList list = this.getVisibleFigureListFromMap();
		if( list.size()!=0 )
		{
			// update the temporary rectangles
			for( int ii=0; ii<list.size(); ii++ )
			{
				SGFigure figure = (SGFigure)list.get(ii);
				figure.recordFigureRect();
			}
			this.recordPaperRect();

			// align figures
			Rectangle2D bbRect = this.getBoundingBoxOfFigures(list);
			for( int ii=0; ii<list.size(); ii++ )
			{
				SGFigure figure = (SGFigure)list.get(ii);
				float x = (float)( cRect.getX() + figure.getGraphRectX() - bbRect.getX() );
				float y = (float)( cRect.getY() + figure.getGraphRectY() - bbRect.getY() );
				figure.setGraphRectLocation(x,y);
				if( figure.isFigureMoved() )
				{
					figure.setChanged(true);
				}
			}

			//
			this.setFigureBoundingBox(0);

			//
			if( this.isPaperBoundsChanged() )
			{
				this.setChanged(true);
			}

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

		}
		else
		{
			SGUtility.showMessageDialog(
				this,
				"There is no figure.",
				"Failed to get the Bounding box.",
				JOptionPane.WARNING_MESSAGE );
		}

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

		// set size
		if( this.mPaperPortraitFlag )
		{
			this.setPaperSizeRoundingOutInCMUnit( widthCM, heightCM );
		}
		else
		{
			this.setPaperSizeRoundingOutInCMUnit( heightCM, widthCM );
		}

		return true;
	}



	/**
	 * 
	 * @param widthCM
	 * @param heightCM
	 * @return
	 */
	protected boolean setPaperSizeRoundingOutInCMUnit(
		final float widthCM, final float heightCM )
	{

		// 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/SGIConstants.CM_POINT_RATIO;
		final float height = dHeightCM/SGIConstants.CM_POINT_RATIO;

		// set the bounds of paper
		this.mPaperSize.setValues( width, height );

		return true;
	}



	/**
	 * 
	 * @param x
	 * @param y
	 * @param w
	 * @param h
	 * @return
	 */
	protected boolean setPaperSizeRoundingOut(
		final float widthPt, final float heightPt )
	{

		final float widthCM = widthPt*SGIConstants.CM_POINT_RATIO;
		final float heightCM = heightPt*SGIConstants.CM_POINT_RATIO;

		this.setPaperSizeRoundingOutInCMUnit( widthCM, heightCM );

		return true;
	}



	/**
	 * 
	 */
	public boolean initPropertiesHistory()
	{
		WindowProperties p = (WindowProperties)this.getProperties();
		this.addWindowPropertiesHistory(p);
		return true;
	}



	/**
	 * 
	 * @return
	 */
	private boolean addWindowPropertiesHistory( WindowProperties 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;
		return true;
	}




	/**
	 * 
	 */
	public boolean commit()
	{
		return this.commit( this.mDialog );
	}


	/**
	 * 
	 */
	public boolean commit( SGPropertyDialog dg )
	{
		SGWindowDialog wdg = (SGWindowDialog)dg;

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

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


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

		this.getContentPane().repaint();


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

		return true;
	}


	
	/**
	 * 
	 */
	private boolean mChangedFlag = false;


	
	/**
	 * 
	 */
	public boolean updateHistory()
	{
		ArrayList changedObjList = new ArrayList();
		if( this.mChangedFlag )
		{
			this.updateThisObjectHistory();
			changedObjList.add(this);
			this.setChanged(false);
		}

		ArrayList fList = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<fList.size(); ii++ )
		{
			SGFigure fig = (SGFigure)fList.get(ii);
			if( fig.isChanged() )
			{
				fig.updateHistory();
				changedObjList.add(fig);
			}
		}

		if( changedObjList.size()!=0 )
		{
//System.out.println(changedObjList);
			this.updateObjectHistory( changedObjList );
		}

		
		return true;
	}



	/**
	 * 
	 * @return
	 */
	public boolean updateThisObjectHistory()
	{
		this.mWindowStateCounter++;
		this.addWindowPropertiesHistory( (WindowProperties)this.getProperties() );
		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.getContentPane().repaint();

		return true;
	}




	/**
	 * 
	 */
	public boolean preview()
	{
		return this.preview( this.mDialog );
	}


	/**
	 * 
	 */
	public boolean preview( SGPropertyDialog dg )
	{
		SGWindowDialog wdg = (SGWindowDialog)dg;
		this.setPropertiesFromDialog(wdg);
		this.getContentPane().repaint();

		return true;
	}


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


		return true;
	}



	/**
	 * 
	 * @return
	 */
	private boolean setDialogProperty()
	{
		final SGWindowDialog dg = this.mDialog;
		
		// set title of dialog
		String title = SGWindowDialog.TITLE + " : " + this.getID();
		dg.setTitle(title);

		dg.setWindowWidth( this.mPaperSize.x*CM_POINT_RATIO );
		dg.setWindowHeight( this.mPaperSize.y*CM_POINT_RATIO );

		dg.setWindowGridVisible( this.isGridVisible() );
		dg.setWindowGridLinesInterval( this.getGridInterval()*CM_POINT_RATIO );
		dg.setWindowGridLinesWidth( this.getGridLineWidth() );

		dg.setWindowBackgroundColor( this.getPaperColor() );

		dg.setWindowGridLinesColor( this.getGridLineColor() );

		return true;

	}



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

		// 
		this.updateClientRect();

		//
//		this.setScrollBarValue();


		//
//		this.drawBackAllVisibleFigures();

		//
		this.zoomWithBoundingBox();

		//
		this.updateGridItems();


		return true;
	}



	/**
	 * 
	 * @return
	 */
	private boolean updateClientRect()
	{
		this.updateClientRectOld();
//		this.updateClientRectNew();
		return true;
	}



	/**
	 * 
	 * @return
	 */
	private boolean updateClientRectNew()
	{
System.out.println("-- updateClientRect --");

		Rectangle2D cRect = this.getClientRect();
		Rectangle2D pRect = this.getPaperRect();
		final float margin = PAPER_MARGIN;
		Rectangle2D bbRect = this.getBoundingBox();
		Rectangle2D vpRect = this.getViewportBounds();
		ArrayList fList = this.getVisibleFigureListFromMap();
//		Rectangle2D fRect
//			= this.getBoundingBoxOfFigures( fList );

		final float cx = (float)cRect.getX();
		final float cy = (float)cRect.getY();
		final float cw = (float)cRect.getWidth();
		final float ch = (float)cRect.getHeight();

		final float vx = (float)vpRect.getX();
		final float vy = (float)vpRect.getY();
		final float vw = (float)vpRect.getWidth();
		final float vh = (float)vpRect.getHeight();

		final float px = this.getPaperX();
		final float py = this.getPaperY();
		final float pw = this.getPaperWidth();
		final float ph = this.getPaperHeight();


//System.out.println("cRect:"+cRect);
//System.out.println("pRect:"+pRect);
//System.out.println("bbRect:"+bbRect);
//System.out.println("vpRect:"+vpRect);


//		final boolean movedLeft
//			= ( (int)cRect.getX()!=(int)bbRect.getX() );
//		final boolean movedTop
//			= ( (int)cRect.getY()!=(int)bbRect.getY() );
//		final boolean movedRight
//			= ( (int)(cRect.getX()+cRect.getWidth())!=(int)(bbRect.getX()+bbRect.getWidth()) );
//		final boolean movedBottom
//			= ( (int)(cRect.getY()+cRect.getHeight())!=(int)(bbRect.getY()+bbRect.getHeight() ) );
//
//System.out.println("left:"+movedLeft);
//System.out.println("right:"+movedRight);
//System.out.println("top:"+movedTop);
//System.out.println("bottom:"+movedBottom);


		Rectangle2D cRectNew = new Rectangle2D.Float();
		cRectNew.setRect( bbRect );
		{
			final boolean minXFlag = ( (int)vx <= (int)cRectNew.getX() );
			final boolean maxXFlag = ( (int)( cRectNew.getX() + cRectNew.getWidth() ) <= (int)( vx + vw ) );
			double xNew = cRectNew.getX();
			double wNew = cRectNew.getWidth();
			if( minXFlag & maxXFlag )
			{
				xNew = vx;
				wNew = vw;
			}
			else if( minXFlag )
			{
				xNew = vx;
				if( wNew < vw )
				{
					wNew = vw;
				}
			}
			else if( maxXFlag )
			{
				xNew = vx + vw - wNew;
				if( vx < xNew )
				{
					xNew = vx;
				}
				if( wNew < vw )
				{
					wNew = vw;
				}
			}
			cRectNew.setRect( xNew, cRectNew.getY(), wNew, cRectNew.getHeight() );
		}

		{
			final boolean minYFlag = ( vy < cRectNew.getMinY() );
			final boolean maxYFlag = ( cRectNew.getMinY() + cRectNew.getHeight() < vy + vh );
			double yNew = cRectNew.getY();
			double hNew = cRectNew.getHeight();
			if( minYFlag & maxYFlag )
			{
				yNew = vy;
				hNew = vh;
			}
			else if( minYFlag )
			{
				yNew = vy;
				if( hNew < vh )
				{
					hNew = vh;
				}
			}
			else if( maxYFlag )
			{
				yNew = vy + vh - hNew;
				if( vy < yNew )
				{
					yNew = vy;
				}
				if( hNew < vh )
				{
					hNew = vh;
				}
			}
			cRectNew.setRect( cRectNew.getX(), yNew, cRectNew.getWidth(), hNew );			
		}

this.mTempRect.setRect( cRectNew );


		// set paper origin
		float pXNew;
		float pYNew;
		if( fList.size()==0 )
		{
			pXNew = (float)cRectNew.getX() + 0*margin;
			pYNew = (float)cRectNew.getY() + 0*margin;
		}
		else
		{
			SGFigure left = null;
			SGFigure top = null;
			float minX = px;
			float minY = py;
			for( int ii=0; ii<fList.size(); ii++ )
			{
				SGFigure f = (SGFigure)fList.get(ii);
				Rectangle2D bb = f.getBoundingBox();
				final float x = (float)( bb.getX() );
				final float y = (float)( bb.getY() );
				if( x < minX )
				{
					minX = x;
					left = f;
				}
				if( y < minY )
				{
					minY = y;
					top = f;
				}
			}
			if( left!=null )
			{
				pXNew = px - minX;
			}
			else
			{
				pXNew = px;
			}
			if( top!=null )
			{
				pYNew = py - minY;
			}
			else
			{
				pYNew = py;
			}
		}

System.out.println(px+"  "+py);
System.out.println(pXNew+"  "+pYNew);

		// set client rectangle
		this.setClientRect( cRectNew );
		this.setPaperOrigin( pXNew, pYNew );
		this.updateGraphRectOfAllFigures();

		//
		this.setEnableScrollBars();

		//
		this.setScrollBarValue();


System.out.println();


		return true;

	}


private Rectangle2D mTempRect = new Rectangle2D.Double();



	/**
	 * ウインドウ内部のバウンディングボックスが変化したとき
	 * @return
	 */
	private boolean updateClientRectOld()
	{

		//
		// 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.fitRect( this.mClientRect, this.getBoundingBox(), true );

		if( SGUtility.isRectContains(
			this.getViewportBounds(), this.getBoundingBox(), true ) )
		{
			this.fitRect( this.mClientRect, this.getViewportBounds(), true );
		}

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

			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 )
			{
				diff = vpRect.getX() - cRect.getX();
			}
			else if( b1 && !b2 )
			{
				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();
				}
			}

			this.setClientRect(
				(float)( cRect.getX() + diff ),
				(float)cRect.getY(),
				(float)cRect.getWidth(),
				(float)cRect.getHeight()
			);
		}
				

		// vertical

		this.fitRect( this.mClientRect, this.getBoundingBox(), false );

		if( SGUtility.isRectContains(
			this.getViewportBounds(), this.getBoundingBox(), false ) )
		{
			this.fitRect( this.mClientRect, this.getViewportBounds(), false );
		}

		if( SGUtility.isRectContains(
			this.getClientRect(), this.getViewportBounds(), false ) == false )
		{
			Rectangle2D cRect = this.getClientRect();
			Rectangle2D vpRect = this.getViewportBounds();

			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 )
			{
				diff = vpRect.getY() - cRect.getY();
			}
			else if( b1 && !b2 )
			{
				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();
				}
			}

			this.setClientRect(
				(float)cRect.getX(),
				(float)( cRect.getY() + diff ),
				(float)cRect.getWidth(),
				(float)cRect.getHeight()
			);
		}


		//
		this.setScrollBarValue();


		//
		this.setEnableScrollBars();


		if( SGUtility.isRectContains(
			this.getViewportBounds(), this.getBoundingBox(), true ) )
		{
			this.fitRect( this.mClientRect, this.getViewportBounds(), true );
		}
		if( SGUtility.isRectContains(
			this.getViewportBounds(), this.getBoundingBox(), false ) )
		{
			this.fitRect( this.mClientRect, this.getViewportBounds(), false );
		}


		//
		this.setScrollBarValue();

		return true;
	}



	/**
	 * Fit rect1 to rect2.
	 * @param rect1
	 * @param rect2
	 * @param flag - true: x-direction, false: y-direction
	 */
	private void fitRect(
		Rectangle2D rect1, Rectangle2D rect2, final boolean flag )
	{
		if( flag )
		{
			rect1.setRect(
				rect2.getX(),
				rect1.getY(),
				rect2.getWidth(),
				rect1.getHeight()
			);
		}
		else
		{
			rect1.setRect(
				rect1.getX(),
				rect2.getY(),
				rect1.getWidth(),
				rect2.getHeight()
			);
		}
	}




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

		final boolean hFlag
			= SGUtilityNumber.contains(
				vpRect.x, vpRect.x + vpRect.width,
				bbRect.x, bbRect.x + bbRect.width );

		final boolean vFlag
			= SGUtilityNumber.contains(
				vpRect.y, vpRect.y + vpRect.height,
				bbRect.y, bbRect.y + bbRect.height );

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

//System.out.println(vpRect);
//System.out.println(bbRect);
//System.out.println(hFlag+"  "+vFlag);

		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.mPaperSize.setValues( 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 Boolean gridVisible = wp.getGridVisible();
		if( gridVisible==null )
		{
			return false;
		}
		this.setGridVisible( gridVisible.booleanValue() );

		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( new ArrayList( wp.visibleFigureList ) );

		return true;
	}



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

		final WindowProperties p = new WindowProperties();

		p.setPaperWidth( this.mPaperSize.x );
		p.setPaperHeight( this.mPaperSize.y );
		p.setBackGroundColor( this.getPaperColor() );
		p.setGridColor( this.getGridLineColor() );
		p.setGridVisible( this.isGridVisible() );
		p.setGridInterval( this.getGridInterval() );
		p.setGridLineWidth( this.getGridLineWidth() );
		p.figureMap = this.mFigureMap;
		p.visibleFigureList = new ArrayList( 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( SGWindowDialog dg )
	{

/*
		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 = dg.getProperties();
		if( p==null )
		{
			return null;
		}

//System.out.println(p);

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

		return p;

	}



	/**
	 * 
	 * @return
	 */
	public Rectangle2D getClientRect()
	{
		if( this.mClientRect==null )
		{
			return null;
		}
		else
		{
			return (Rectangle2D)this.mClientRect.clone();
		}
	}



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*SGIConstants.CM_POINT_RATIO+"cm, y="+y*SGIConstants.CM_POINT_RATIO+"cm");
	System.out.println("w="+w*SGIConstants.CM_POINT_RATIO+"cm, h="+h*SGIConstants.CM_POINT_RATIO+"cm");
	System.out.println();
}



public void dumpRect()
{
	Rectangle2D cRect = this.getClientRect();
	Rectangle2D vpRect = this.getViewportBounds();
	Rectangle2D bbRect = this.getBoundingBox();

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

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

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

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

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


	/**
	 * 
	 * @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 );
//System.out.println(this.mClientRect);
		return true;
	}


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



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



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



	/**
	 * 
	 * @return
	 */
	public Rectangle2D getViewportBoundsInComponent()
	{
		final int top = this.getTopWidth();
		final int left = this.getLeftWidth();
		final int rw = RulerPanel.RULER_WIDTH;
		final SGTuple2f dim = this.getViewportSize();
		final float w = dim.x + rw;
		final float h = dim.y + rw;
		Rectangle2D rect = new Rectangle2D.Float( left, top, w, h );
//System.out.println(rect);
		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;
	}



	/**
	 * Returns a two dimensional array of figure list.
	 */
	private ArrayList[][] getFigureListArray()
	{
		// get the visible figure list
		ArrayList figureList = this.getVisibleFigureListFromMap();
		if( figureList.size()==0 )
		{
			return null;
		}


		// 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.getGraphRect();
			if( rect.getWidth() < minWidth )
			{
				minWidth = (float)rect.getWidth();
			}
			if( rect.getHeight() < minHeight )
			{
				minHeight = (float)rect.getHeight();
			}
		}
		final float dx = minWidth;
		final float dy = minHeight;

		Rectangle2D bbRect = this.getBoundingBoxOfFigures(figureList);

		final int numX = (int)( (float)bbRect.getWidth()/dx ) + 1;
		final int numY = (int)( (float)bbRect.getHeight()/dy ) + 1;


		// get a two-dimensional array of figures
		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.getGraphRect();
			int nx = (int)( ( gRect.getCenterX() - bbRect.getX() )/dx );
			int ny = (int)( ( gRect.getCenterY() - bbRect.getY() )/dy );
			fListArray[nx][ny].add( figure );
		}


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


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

		return figureListArray;		
	}



	/**
	 * 
	 * @return
	 */
	private boolean alignFiguresLeftAndBottom( ArrayList[][] figureListArray )
	{
		final int sx = figureListArray.length;
		final int sy = figureListArray[0].length;

		//
		final float[][] topArray = new float[sx][sy];
		final float[][] bottomArray = new float[sx][sy];
		final float[][] leftArray = new float[sx][sy];
		final float[][] rightArray = new float[sx][sy];
		for( int ii=0; ii<sx; ii++ )
		{
			for( int jj=0; jj<sy; jj++ )
			{
				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.getGraphRect();
					final float width = (float)rect.getWidth();
					final float height = (float)rect.getHeight();
					SGTuple2f tb = new SGTuple2f();
					SGTuple2f lr = new SGTuple2f();
					figure.calcMargin( tb, lr );
					final float top = tb.x;
					final float bottom = tb.y;
					final float left = lr.x;
					final float right = lr.y;
					if( top + height > maxTop )
					{
						maxTop = top + height;
					}
					if( bottom > maxBottom )
					{
						maxBottom = bottom;
					}
					if( left > maxLeft )
					{
						maxLeft = left;
					}
					if( right + width > maxRight )
					{
						maxRight = right + width;
					}
				}

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



		// 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[] maxRightArray = new float[sx];
		for( int nx=0; nx<sx; nx++ )
		{
			float wMax = 0.0f;
			for( int ny=0; ny<sy; ny++ )
			{
				float width = rightArray[nx][ny];
				if( width > wMax )
				{
					wMax = width;
				}
			}
			maxRightArray[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;
		}


		// create arrays of the coordinate of the left-bottom corner
		final float diff
			= this.mMagnification*this.mBackgroundPanel.getGridInterval();
		Rectangle2D pRect = this.getPaperRect();
		final float px = (float)pRect.getX();
		final float py = (float)pRect.getY();
		float x = px;
		float y = py;
		final float[] originXArray = new float[sx];
		for( int nx=0; nx<sx; nx++ )
		{
			final float value = x + maxLeftArray[nx];
			final int index = (int)((value-px)/diff) +1;
			originXArray[nx] = px + index*diff;
			x = originXArray[nx] + maxRightArray[nx];
		}
		final float[] originYArray = new float[sy];
		for( int ny=0; ny<sy; ny++ )
		{
			final float value = y + heightArray[ny] - maxBottomArray[ny];
			final int index = (int)((value-py)/diff) +1;
			originYArray[ny] = py + index*diff;
			y = originYArray[ny] + maxBottomArray[ny];
		}


		// 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.setGraphRectLocationByLeftBottom(
						originXArray[nx], originYArray[ny] ) == false )
					{
						return false;
					}
				}
				if( !flag )
				{
					break;
				}
			}
			if( !flag )
			{
				break;
			}
		}

		return true;
	}



	private Float findCeilingValue( final float[] array, final float value )
	{
		float[] copy = (float[])array.clone();
		Arrays.sort(copy);
		
		for( int ii=0; ii<copy.length; ii++ )
		{
			if( value <= copy[ii] )
			{
				return new Float( copy[ii] );
			}
		}

		return null;
	}




	/**
	 * 
	 * @return
	 */
	public boolean alignFiguresByGraphArea()
	{
		// get the visible figure list
		ArrayList figureList = this.getVisibleFigureListFromMap();
		if( figureList.size()==0 )
		{
			return true;
		}

		Rectangle2D cRect = this.mClientRect;


		// 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.getGraphRect();
			if( rect.getWidth() < minWidth )
			{
				minWidth = (float)rect.getWidth();
			}
			if( rect.getHeight() < minHeight )
			{
				minHeight = (float)rect.getHeight();
			}
		}
		final float dx = minWidth;
		final float dy = minHeight;

		Rectangle2D bbRect = this.getBoundingBoxOfFigures(figureList);

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

final int numX = (int)( (float)bbRect.getWidth()/dx ) + 1;
final int numY = (int)( (float)bbRect.getHeight()/dy ) + 1;


		// get a two-dimensional array of figures
		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.getGraphRect();

//			int nx = (int)( ( gRect.getCenterX() - cRect.getX() )/dx );
//			int ny = (int)( ( gRect.getCenterY() - cRect.getY() )/dy );

int nx = (int)( ( gRect.getCenterX() - bbRect.getX() )/dx );
int ny = (int)( ( gRect.getCenterY() - bbRect.getY() )/dy );

			fListArray[nx][ny].add( figure );
		}


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


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



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

			}
		}



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


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



		// 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.setGraphRectLocationByLeftBottom(
						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];
		}
		Rectangle2D pRect = this.getPaperRect();
		final boolean bw = ( pRect.getWidth() < wTotal );
		final boolean bh = ( pRect.getHeight() < hTotal );


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

final int mode = 0;

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


		return true;

	}



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

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


		// get a two-dimensional array of the list of figures
		ArrayList[][] figureListArray = this.getFigureListArray();
		if( figureListArray==null )
		{
			return false;
		}
		if( figureListArray.length==0 )
		{
			return false;
		}


		// align figures
		if( this.alignFiguresLeftAndBottom( figureListArray ) == false )
		{
			return false;
		}


		// set bounding box
		if( this.setFigureBoundingBox(0) == 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);


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

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



	/**
	 * オブジェクトの履歴を更新する
	 * @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.updateUndoItems();

		return true;
	}



	/**
	 * 
	 * @return
	 */
	public boolean undo()
	{
		this.mWindowStateCounter--;

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

		return true;
	}


	/**
	 * 
	 * @return
	 */
	public boolean redo()
	{
		this.mWindowStateCounter++;

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

		return true;
	}



	boolean updateGraphRectOfAllFigures()
	{
		ArrayList list = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.updateGraphRect();
		}
		return true;
	}



	/**
	 * Update method called on undo and redo.
	 */
	private boolean updateOnUndo()
	{
		// clear all focused objects
		this.clearAllFocusedObjectsInFigures();

		// update the location and scroll values
		this.updateClientRect();
//		this.setScrollBarValue();

		// update the graph rectangle of figures
		this.updateGraphRectOfAllFigures();

		// update menu items
		this.updateUndoItems();
		this.updateItemsByFigureNumbers();
		this.updateDataItem();
		this.updateGridItems();

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


		// update
		this.updateOnUndo();
/*
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++;

		// update
		this.updateOnUndo();


		return true;
	}



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


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

	
	/**
	 * 
	 */
	private boolean updateUndoItems()
	{

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


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

		return true;
	}



	/**
	 * 
	 *
	 */
	public void notifyToRoot()
	{
//System.out.println("notifyToRoot");
		this.updateHistoryTree();
	}



	/**
	 * 
	 * @return
	 */
	private boolean updateHistoryTree()
	{
		return this.updateHistory();
	}




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

	/**
	 * 
	 */
	private boolean createMenuBar()
	{
		JMenuBar menuBar = this.getJMenuBar();

		final int ctrl = ActionEvent.CTRL_MASK;
		final int shift = ActionEvent.SHIFT_MASK;
		final int alt = ActionEvent.ALT_MASK;

		// File
		{
			final JMenu menuFile = new JMenu( MENUBAR_FILE );
			menuFile.setMnemonic( KeyEvent.VK_F );
			menuBar.add(menuFile);

			// open window
			this.createMenuItem(
				menuFile, MENUBARCMD_CREATE_NEW_WINDOW, this, KeyEvent.VK_N,
				KeyStroke.getKeyStroke(KeyEvent.VK_N, ctrl),
				true );

			// close window
			this.createMenuItem(
				menuFile, MENUBARCMD_CLOSE_WINDOW, this, KeyEvent.VK_W,
				KeyStroke.getKeyStroke(KeyEvent.VK_W, ctrl),
				true );

			menuFile.addSeparator();

			// draw graph
			this.createMenuItem(
				menuFile, MENUBARCMD_DRAW_GRAPH, this, KeyEvent.VK_D,
				KeyStroke.getKeyStroke(KeyEvent.VK_O, ctrl),
				true );

			menuFile.addSeparator();

			// load property
			this.createMenuItem(
				menuFile, MENUBARCMD_LOAD_PROPERTY, this, KeyEvent.VK_L,
				null, true );

			// save property
			this.createMenuItem(
				menuFile, MENUBARCMD_SAVE_PROPERTY, this, KeyEvent.VK_S,
				null, true );

			menuFile.addSeparator();

			// export as image
			this.createMenuItem(
				menuFile, MENUBARCMD_EXPORT_AS_IMAGE, this, KeyEvent.VK_E,
				KeyStroke.getKeyStroke(KeyEvent.VK_E, ctrl),
				false );

			// print
			this.createMenuItem(
				menuFile, MENUBARCMD_PRINT, this, KeyEvent.VK_P,
				KeyStroke.getKeyStroke(KeyEvent.VK_P, ctrl),
				false );

/*
			// preview
			this.createMenuItem(
				menuFile, MENUBARCMD_PREVIEW, this, KeyEvent.VK_V, null,
				false );
*/

			menuFile.addSeparator();

			// exit
			this.createMenuItem(
				menuFile, MENUBARCMD_EXIT, this, KeyEvent.VK_X,
				KeyStroke.getKeyStroke(KeyEvent.VK_Q, ctrl),
				true );

		}


		// Edit
		{
			final JMenu menuEdit = new JMenu(MENUBAR_EDIT);
			menuEdit.setMnemonic( KeyEvent.VK_E );
			menuBar.add(menuEdit);

			// undo
			this.createMenuItem(
				menuEdit, MENUBARCMD_UNDO, this, KeyEvent.VK_U,
				KeyStroke.getKeyStroke(KeyEvent.VK_Z, ctrl),
				false );

			// redo
			this.createMenuItem(
				menuEdit, MENUBARCMD_REDO, this, KeyEvent.VK_R,
				KeyStroke.getKeyStroke(KeyEvent.VK_Y, ctrl),
				false );

			menuEdit.addSeparator();

			// cut
			this.createMenuItem(
				menuEdit, MENUBARCMD_CUT, this, KeyEvent.VK_T,
				KeyStroke.getKeyStroke(KeyEvent.VK_X, ctrl),
				false );

			// copy
			this.createMenuItem(
				menuEdit, MENUBARCMD_COPY, this, KeyEvent.VK_C,
				KeyStroke.getKeyStroke(KeyEvent.VK_C, ctrl),
				false );

			// paste
			this.createMenuItem(
				menuEdit, MENUBARCMD_PASTE, this, KeyEvent.VK_P,
				KeyStroke.getKeyStroke(KeyEvent.VK_V, ctrl),
				false );

			menuEdit.addSeparator();

			// delete
			this.createMenuItem(
				menuEdit, MENUBARCMD_DELETE, this, KeyEvent.VK_D,
				KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0),
				false );

/*
			final JMenuItem selectAll = new JMenuItem( MENUBARCMD_SELECT_ALL );
			selectAll.setActionCommand(MENUBARCMD_SELECT_ALL);
			selectAll.addActionListener(this);
			selectAll.setAccelerator(
				KeyStroke.getKeyStroke(KeyEvent.VK_A, ctrl));
			selectAll.setMnemonic( KeyEvent.VK_A );
			menuEdit.add(selectAll);
			selectAll.setEnabled(false);
*/

			// duplicate
			this.createMenuItem(
				menuEdit, MENUBARCMD_DUPLICATE, this, KeyEvent.VK_I,
				KeyStroke.getKeyStroke(KeyEvent.VK_D, ctrl),
				false );

		}


		// Insert
		{
			final JMenu menuInsert = new JMenu( MENUBAR_INSERT );
			menuInsert.setMnemonic( KeyEvent.VK_I );
			menuBar.add(menuInsert);

			// label
			this.createToggleMenuItem(
				menuInsert, MENUBARCMD_INSERT_LABEL, this, KeyEvent.VK_L,
				null, false );

			// significant difference
			this.createToggleMenuItem(
				menuInsert, MENUBARCMD_INSERT_SIG_DIFF_SYMBOL, this, KeyEvent.VK_D,
				null, false );

			// axis break
			this.createToggleMenuItem(
				menuInsert, MENUBARCMD_INSERT_AXIS_BREAK_SYMBOL, this, KeyEvent.VK_B,
				null, false );

			// timing line
			this.createToggleMenuItem(
				menuInsert, MENUBARCMD_INSERT_TIMING_LINE, this, KeyEvent.VK_T,
				null, false );
		}


		// Layout
		{
			final JMenu menuLayout = new JMenu(MENUBAR_LAYOUT);
			menuLayout.setMnemonic( KeyEvent.VK_L );
			menuBar.add(menuLayout);

			// Paper Size
			{
				final JMenu menuPaperSize = new JMenu(MENUBAR_PAPER_SIZE);
				menuPaperSize.setMnemonic( KeyEvent.VK_P );
				menuLayout.add(menuPaperSize);

				// A4
				this.createMenuItem(
					menuPaperSize, MENUBARCMD_PAPER_A4_SIZE, this, KeyEvent.VK_4,
					null, true );

				// B5
				this.createMenuItem(
					menuPaperSize, MENUBARCMD_PAPER_B5_SIZE, this, KeyEvent.VK_5,
					null, true );

				// A4
				this.createMenuItem(
					menuPaperSize, MENUBARCMD_PAPER_USLETTER_SIZE, this, KeyEvent.VK_U,
					null, true );

				menuPaperSize.addSeparator();


				// portrait
				JRadioButtonMenuItem portrait
					= (JRadioButtonMenuItem)this.createRadioButtonMenuItem(
					menuPaperSize, MENUBARCMD_PAPER_PORTRAIT, this, KeyEvent.VK_P,
					null, true );

				// landscape
				JRadioButtonMenuItem landscape
					= (JRadioButtonMenuItem)this.createRadioButtonMenuItem(
					menuPaperSize, MENUBARCMD_PAPER_LANDSCAPE, this, KeyEvent.VK_L,
					null, true );

				// create a button-group
				ButtonGroup bGroup = new ButtonGroup();
				bGroup.add(portrait);
				bGroup.add(landscape);

				menuPaperSize.addSeparator();


				// bounding box
				this.createMenuItem(
					menuPaperSize, MENUBARCMD_BOUNDING_BOX, this, KeyEvent.VK_B,
					null, true );

				// user customize
				this.createMenuItem(
					menuPaperSize, MENUBARCMD_PAPER_USER_CUSTOMIZE, this, KeyEvent.VK_C,
					null, true );

			}

			menuLayout.addSeparator();


			// Grid
			{
				final JMenu menuGrid = new JMenu(MENUBAR_GRID);
				menuGrid.setMnemonic( KeyEvent.VK_G );
				menuLayout.add(menuGrid);

				// plus grid
				this.createMenuItem(
					menuGrid, MENUBARCMD_PLUS_GRID, this, KeyEvent.VK_P,
					KeyStroke.getKeyStroke(KeyEvent.VK_I, shift + alt),
					true );

				// minus grid
				this.createMenuItem(
					menuGrid, MENUBARCMD_MINUS_GRID, this, KeyEvent.VK_M,
					KeyStroke.getKeyStroke(KeyEvent.VK_D, shift + alt),
					true );


				// grid visible
				this.createCheckBoxMenuItem(
					menuGrid, MENUBARCMD_GRID_VISIBLE, this, KeyEvent.VK_V,
					KeyStroke.getKeyStroke(KeyEvent.VK_G, shift + alt),
					true );

/*
				// snap to grid
				this.createCheckBoxMenuItem(
					menuGrid, MENUBARCMD_SNAP_TO_GRID, this, KeyEvent.VK_S,
					KeyStroke.getKeyStroke(KeyEvent.VK_S, shift + alt),
					true );
*/
			}

			menuLayout.addSeparator();



			// Zoom
			{
				final JMenu menuZoom = new JMenu(MENUBAR_ZOOM);
				menuZoom.setMnemonic( KeyEvent.VK_Z );
				menuLayout.add(menuZoom);

				// zoom in
				this.createMenuItem(
					menuZoom, MENUBARCMD_ZOOM_IN, this, KeyEvent.VK_I,
					KeyStroke.getKeyStroke(KeyEvent.VK_Z, shift + alt),
					true );

				// zoom out
				JMenuItem zoomOut = this.createMenuItem(
					menuZoom, MENUBARCMD_ZOOM_OUT, this, KeyEvent.VK_O,
					KeyStroke.getKeyStroke(KeyEvent.VK_O, shift + alt),
					true );
				zoomOut.setDisplayedMnemonicIndex(5);


				// default zoom
				this.createMenuItem(
					menuZoom, MENUBARCMD_DEFAULT_ZOOM, this, KeyEvent.VK_D,
					null, true );

				// zoom way out
				this.createMenuItem(
					menuZoom, MENUBARCMD_ZOOM_WAY_OUT, this, KeyEvent.VK_W,
					null, true );

				// auto zoom
				this.createCheckBoxMenuItem(
					menuZoom, MENUBARCMD_AUTO_ZOOM, this, KeyEvent.VK_A,
					null, true );

			}

			menuLayout.addSeparator();


			// lock
			this.createCheckBoxMenuItem(
				menuLayout, MENUBARCMD_LOCK, this, KeyEvent.VK_O,
				null, true );

		}



		// Arrange
		{
			final JMenu menuArrange = new JMenu(MENUBAR_ARRANGE);
			menuArrange.setMnemonic( KeyEvent.VK_A );
			menuBar.add(menuArrange);


			// move to front
			this.createMenuItem(
				menuArrange, MENUBARCMD_MOVE_TO_FRONT, this, KeyEvent.VK_F,
				KeyStroke.getKeyStroke(KeyEvent.VK_F, ctrl),
				false );

			// move to back
			this.createMenuItem(
				menuArrange, MENUBARCMD_MOVE_TO_BACK, this, KeyEvent.VK_B,
				KeyStroke.getKeyStroke(KeyEvent.VK_B, ctrl),
				false );

			menuArrange.addSeparator();

			// align figures
			this.createMenuItem(
				menuArrange, MENUBARCMD_AUTO_ARRANGEMENT, this, KeyEvent.VK_R,
				null, true );

/*
			final JMenu menuAlignObjects = new JMenu(MENUBAR_ALIGN_OBJECTS);
			menuAlignObjects.addMenuListener(this);
			menuAlignObjects.setMnemonic( KeyEvent.VK_O );
			menuArrange.add( menuAlignObjects );
			{
				final JMenuItem left = new JMenuItem(MENUBARCMD_ALIGN_LEFT);
				left.setActionCommand(MENUBARCMD_ALIGN_LEFT);
				left.addActionListener(this);
				left.setMnemonic( KeyEvent.VK_L );
				menuAlignObjects.add(left);

				final JMenuItem center = new JMenuItem(MENUBARCMD_ALIGN_CENTER);
				center.setActionCommand(MENUBARCMD_ALIGN_CENTER);
				center.addActionListener(this);
				center.setMnemonic( KeyEvent.VK_C );
				menuAlignObjects.add(center);

				final JMenuItem right = new JMenuItem(MENUBARCMD_ALIGN_RIGHT);
				right.setActionCommand(MENUBARCMD_ALIGN_RIGHT);
				right.addActionListener(this);
				right.setMnemonic( KeyEvent.VK_R );
				menuAlignObjects.add(right);

				final JMenuItem top = new JMenuItem(MENUBARCMD_ALIGN_TOP);
				top.setActionCommand(MENUBARCMD_ALIGN_TOP);
				top.addActionListener(this);
				top.setMnemonic( KeyEvent.VK_T );
				menuAlignObjects.add(top);

				final JMenuItem middle = new JMenuItem(MENUBARCMD_ALIGN_MIDDLE);
				middle.setActionCommand(MENUBARCMD_ALIGN_MIDDLE);
				middle.addActionListener(this);
				middle.setMnemonic( KeyEvent.VK_M );
				menuAlignObjects.add(middle);

				final JMenuItem bottom = new JMenuItem(MENUBARCMD_ALIGN_BOTTOM);
				bottom.setActionCommand(MENUBARCMD_ALIGN_BOTTOM);
				bottom.addActionListener(this);
				bottom.setMnemonic( KeyEvent.VK_B );
				menuAlignObjects.add(bottom);

			}
*/

		}



		// Help
		{
			final JMenu menuHelp = new JMenu(MENUBAR_HELP);
			menuHelp.setMnemonic( KeyEvent.VK_H );
			menuBar.add(menuHelp);

/*
			// Look and Feel
			{
				final JMenu menuLaf = new JMenu(MENUBAR_LOOKANDFEEL);
				menuLaf.setMnemonic( KeyEvent.VK_L );
				menuHelp.add(menuLaf);

				// metal
				this.createMenuItem(
					menuLaf, MENUBARCMD_LAF_METAL, LAF_METAL, this, KeyEvent.VK_T,
					null, true );

				// motif
				this.createMenuItem(
					menuLaf, MENUBARCMD_LAF_MOTIF, LAF_MOTIF, this, KeyEvent.VK_M,
					null, true );

				// windows
				this.createMenuItem(
					menuLaf, MENUBARCMD_LAF_WINDOWS, LAF_WINDOWS, this, KeyEvent.VK_W,
					null, true );

				// windows classic
				this.createMenuItem(
					menuLaf, MENUBARCMD_LAF_WINDOWSCLASSIC, LAF_WINDOWSCLASSIC, this, KeyEvent.VK_C,
					null, true );

				// aqua
				this.createMenuItem(
					menuLaf, MENUBARCMD_LAF_AQUA, LAF_AQUA, this, KeyEvent.VK_A,
					null, true );
			}
*/

			// upgrade
			this.createMenuItem(
				menuHelp, MENUBARCMD_UPGRADE, this, KeyEvent.VK_U,
				null, true );

			menuHelp.addSeparator();

			// change log
			this.createMenuItem(
				menuHelp, MENUBARCMD_CHANGE_LOG, this, KeyEvent.VK_C,
				null, true );

			menuHelp.addSeparator();

			// proxy
			this.createMenuItem(
				menuHelp, MENUBARCMD_PROXY, this, KeyEvent.VK_P,
				null, true );

			menuHelp.addSeparator();

			// about
			this.createMenuItem(
				menuHelp, MENUBARCMD_ABOUT, this, KeyEvent.VK_A,
				null, true );

		}


		return true;

	}



	private JMenuItem createMenuItem(
		JMenu menu,
		String command,
		ActionListener l,
		int mnemonic,
		KeyStroke keyStroke,
		boolean enabled )
	{
		return this.createMenuItem(menu,command,command,l,mnemonic,keyStroke,enabled);
	}


	private JMenuItem createMenuItem(
		JMenu menu,
		String text,
		String command,
		ActionListener l,
		int mnemonic,
		KeyStroke keyStroke,
		boolean enabled )
	{
		final JMenuItem item = new JMenuItem(text);
		return this.createMenuItem_(menu,item,command,l,mnemonic,keyStroke,enabled);
	}


	private JMenuItem createRadioButtonMenuItem(
		JMenu menu,
		String command,
		ActionListener l,
		int mnemonic,
		KeyStroke keyStroke,
		boolean enabled )
	{
		final JMenuItem item = new JRadioButtonMenuItem(command);
		return this.createMenuItem_(menu,item,command,l,mnemonic,keyStroke,enabled);
	}

	private JMenuItem createCheckBoxMenuItem(
		JMenu menu,
		String command,
		ActionListener l,
		int mnemonic,
		KeyStroke keyStroke,
		boolean enabled )
	{
		final JMenuItem item = new JCheckBoxMenuItem(command);
		return this.createMenuItem_(menu,item,command,l,mnemonic,keyStroke,enabled);
	}


	private JMenuItem createToggleMenuItem(
		JMenu menu,
		String command,
		ActionListener l,
		int mnemonic,
		KeyStroke keyStroke,
		boolean enabled )
	{
		final JMenuItem item = new SGToggleMenuItem(command);
		return this.createMenuItem_(menu,item,command,l,mnemonic,keyStroke,enabled);
	}


	private JMenuItem createMenuItem_(
		JMenu menu,
		JMenuItem item,
		String command,
		ActionListener l,
		int mnemonic,
		KeyStroke keyStroke,
		boolean enabled )
	{
		item.setActionCommand(command);
		item.addActionListener(this);
		item.setMnemonic( mnemonic );
		if( keyStroke!=null )
		{
			item.setAccelerator( keyStroke );
		}
		item.setEnabled(enabled);
		menu.add(item);
		return item;
	}


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

		return null;
	}



	/**
	 * 
	 */
	public JMenu getMenu( final JMenu menu, final String menuName )
	{
		for( int ii=0; ii<menu.getItemCount(); ii++ )
		{
			JMenuItem item = menu.getItem(ii);

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

			if( item instanceof JMenu )
			{
				JMenu m = (JMenu)item;
				if( m.getText().equals(menuName) )
				{
					return m;
				}
			}
		}

		return null;
	}



	/**
	 * 
	 */
	public JMenuItem getMenuItem(
		final String menuName, final String itemName )
	{
		JMenu menu = this.getMenuFromMenuBar( menuName );
		if( menu==null )
		{
			return null;
		}

		return this.getMenuItem( menu, itemName );
	}



	/**
	 * 
	 */
	public JMenuItem getMenuItem(
		final JMenu menu, final String itemName )
	{
		for( int ii=0; ii<menu.getItemCount(); ii++ )
		{
			JMenuItem item = menu.getItem(ii);

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

			if( item.getText().equals(itemName) )
			{
				return item;
			}
		}

		return null;
	}



	/**
	 * 
	 * @param menuName
	 * @return
	 */
	public ArrayList getMenuItemList( final String menuName )
	{
		JMenu menu = this.getMenuFromMenuBar( menuName );
		if( menu==null )
		{
			return null;
		}

		ArrayList list = new ArrayList();
		Component[] comArray= menu.getMenuComponents();
		for( int ii=0; ii<comArray.length; ii++ )
		{
			if( ( comArray[ii] instanceof JMenuItem ) == false )
			{
				continue;
			}

			list.add( comArray[ii] );
		}

		return list;
	}



	private static final int PREVIEW = 0;
	private static final int EXPORT = 1;
	private static final int PRINT = 2;


	/**
	 * 
	 * @return
	 */
	public boolean previewImage()
	{
		return this.toImage( PREVIEW );
	}


	/**
	 * 
	 * @return
	 */
	public boolean exportAsImage()
	{
		return this.toImage( EXPORT );
	}


	/**
	 * 
	 * @return
	 */
	public boolean printImage()
	{
		return this.toImage( PRINT );
	}


	private boolean toImage( final int mode )
	{
		final int width = (int)this.mPaperSize.x;
		final int height = (int)this.mPaperSize.y;

		InfoForExport info = new InfoForExport();
		ExportPanel target = new ExportPanel();
		target.setOpaque(true);
		target.setBackground( this.getPaperColor() );
		target.setPreferredSize( new Dimension(width,height) );

		this.beforeExport( target, info );

		SGIImageExportManager man = this.mImageExportManager;

		boolean ret;
		switch( mode )
		{
			case EXPORT :
			{
				// export as image
				ret = man.export( target, this, width, height );
				break;
			}
			
			case PRINT :
			{
				// print as image

				// Create a panel object and add the target object to it,
				// and replaced the target object with it.
				JPanel panel = new JPanel();
				panel.setLayout(null);
				panel.setSize( width, height );
				panel.add(target);
				panel.setOpaque(true);
				panel.setBackground( target.getBackground() );
				
				ret = man.print( panel, this, width, height );
				break;
			}
			
			default :
			{
				ret = false;
			}
		}

		this.afterExport( target, info );

		return ret;
	}



	/**
	 * A class used for the image export.
	 */
	private static class InfoForExport
	{
		float mag;
		float hValue;
		float vValue;
		SGTuple2f[] locationArray;
		ArrayList visibleList;
	}




	/**
	 * 
	 * @param ePanel
	 * @param info
	 * @return
	 */
	private boolean beforeExport(
		final ExportPanel ePanel, final InfoForExport info )
	{
		float mag = this.mMagnification;
		float hValue = this.getHScrollValue();
		float vValue = this.getVScrollValue();
		ArrayList list = this.getVisibleFigureListFromLayer();

		// check whether the figures run off the edge of the paper
		boolean isInside = true;
		Rectangle pRect = this.getPaperRect().getBounds();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			Rectangle rect = figure.getBoundingBox().getBounds();
			if( pRect.contains(rect) == false )
			{
				isInside = false;
				break;
			}
		}
		if( !isInside )
		{
			SGUtility.showMessageDialog(
				this, "Some figures run off the edge of paper.",
				"Warning", JOptionPane.WARNING_MESSAGE );
		}


		// hide anchors temporarily
		this.setSelectionSymbolsVisible( false );
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.setSymbolsVisibleAroundAllObjects( false );
		}


		// record the location of figures
		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.mGraphRectX, figure.mGraphRectY
			);
		}

		// zoom
		this.zoom(1.0f);


		// set the location of figures
		Rectangle2D cRect = this.getClientRect();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.setGraphRectLocation(
				figure.getGraphRectX() - (float)cRect.getX(),
				figure.getGraphRectY() - (float)cRect.getY()
			);
		}


		//
		// set to the export panel
		//

		// set the location and the size of preview dialog
		final int width = (int)this.mPaperSize.x;
		final int height = (int)this.mPaperSize.y;

		// set the layered pane
		ePanel.setOpaque(false);
		ePanel.setLocation(0,0);
		ePanel.setSize( width, height );

		// add figures to the export panel
		for( int ii=list.size()-1; ii>=0; ii-- )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.setSize( new SGTuple2f( width, height ) );
			ePanel.add( figure );
			figure.setViewBounds( null );
		}

		// set invisible
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.setVisible(false);
		}


		// set information
		info.mag = mag;
		info.hValue = hValue;
		info.vValue = vValue;
		info.locationArray = locationArray;
		info.visibleList = list;

		return true;
	}


	/**
	 * 
	 * @param ePanel
	 * @param info
	 * @return
	 */
	private boolean afterExport(
		final ExportPanel ePanel, final InfoForExport info )
	{
		float mag = info.mag;
		float hValue = info.hValue;
		float vValue = info.vValue;
		SGTuple2f[] locationArray = info.locationArray;
		ArrayList list = info.visibleList;
			
		// zoom
		this.zoom(mag);

		// set scroll value
		this.setScrollValue( this.mHScrollBar, hValue );
		this.setScrollValue( this.mVScrollBar, vValue );

		// set the location
		SGTuple2f vpSize = this.getViewportSize();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.mGraphRectX = locationArray[ii].x;
			figure.mGraphRectY = locationArray[ii].y;
			figure.setSize( vpSize );
			figure.updateGraphRect();
			figure.setViewBounds();
		}

		// set visible
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.setVisible(true);
		}


		// rewrite hidden anchors
		this.setSelectionSymbolsVisible( true );
		ArrayList fList = this.getFocusedObjectsList();
		for( int ii=0; ii<fList.size(); ii++ )
		{
			SGFigure figure = (SGFigure)fList.get(ii);
			figure.setSymbolsVisibleAroundAllObjects( true );
		}

		return true;
	}



	/**
	 * A panel class used to export images.
	 *
	 */
	private static class ExportPanel extends JPanel
	{
		/**
		 * The list of printable objects.
		 */
		private ArrayList mPrintableList = new ArrayList();
		
		private ExportPanel()
		{
			super();
		}

		/**
		 * Add a figure.
		 * @param f - figure
		 */
		private void add( SGFigure f )
		{
			ArrayList list = this.mPrintableList;
			list.add(f);
			SGIFigureElement[] array
				= f.getIFigureElementArrayFromLayer();
			for( int ii=array.length-1; ii>=0; ii-- )
			{
				list.add( array[ii] );
			}
		}

		/**
		 * Paint this object.
		 * @param - graphic context
		 */
		public void paintComponent( Graphics g )
		{
			super.paintComponent(g);
			ArrayList list = this.mPrintableList;
			for( int ii=0; ii<list.size(); ii++ )
			{
				SGIPaintable p = (SGIPaintable)list.get(ii);
				p.paintGraphics(g,false);
			}
		}

	}



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





	/**
	 * 
	 * @param document
	 * @return
	 */
	public Element createElement( final Document document )
	{
		Element element = document.createElement( SGDrawingWindow.TAG_NAME_WINDOW );
		if( this.writeProperty( element ) == false )
		{
			return null;
		}
		return element;
	}
	
	
	/**
	 * 
	 * @param document
	 * @return
	 */
	public Element createElementForFocusedFiguresInBoundingBox( final Document document )
	{
		Element element = document.createElement( SGDrawingWindow.TAG_NAME_WINDOW );
		if( this.writePropertyForFocusedFiguresInBoundingBox( element ) == false )
		{
			return null;
		}
		return element;
	}


	

	/**
	 * Create a DOM Tree.
	 * @param document
	 * @return
	 */
	public boolean createDOMTree( Document document )
	{
		boolean flag;
		switch( this.mPropertyFileCreationModeOfFigures )
		{
			case ALL_FIGURES :
			{
				flag = this.createDOMTreeForAllFigures( document );
				break;
			}

			case FOCUSED_FIGURES_FOR_COPY :
			{
				flag = this.createDOMTreeForFocusedFiguresForDuplication( document );
				break;
			}

			case FOCUSED_FIGURES_IN_BOUNDING_BOX :
			{
				flag = this.createDOMTreeForFocusedFiguresInBoundingBox( document );
				break;
			}
			
			case FOCUSED_FIGURES_FOR_DUPLICATION :
			{
				flag = this.createDOMTreeForFocusedFiguresForDuplication( document );
				break;
			}
			
			default :
			{
				throw new Error();
			}
		}

		return flag;
	}
	
	
	/**
	 * Create a DOM Tree.
	 * @param document
	 * @param focused
	 * @return
	 */
	public boolean createDOMTree( Document document, int mode )
	{
		this.mPropertyFileCreationModeOfFigures = mode;
		return this.createDOMTree( document );
	}
	
	
	/**
	 * 
	 */
	private boolean createDOMTreeForAllFigures( Document document )
	{
		
		// get the root element
		Element property = document.getDocumentElement();
		
		// write properties of the window
		Element windowElement = this.createElement( document );
		if( windowElement==null )
		{
			return false;
		}
		property.appendChild( windowElement );
		
		// figures
		ArrayList list = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			Element el = figure.createElement( document );
			if( el == null )
			{
				return false;
			}
			windowElement.appendChild( el );
		}

		return true;
	}

	
	
	
	/**
	 * Creation mode of the property file of focused figures.
	 */
	private int mPropertyFileCreationModeOfFigures;


	public static final int ALL_FIGURES = 0;
	public static final int FOCUSED_FIGURES_FOR_COPY = 1;
	public static final int FOCUSED_FIGURES_IN_BOUNDING_BOX = 2;
	public static final int FOCUSED_FIGURES_FOR_DUPLICATION = 3;

	
	/**
	 * 
	 * @return
	 */
	boolean createPropertyFileFromFocusedFigures()
	{
		this.mPropertyFileCreationModeOfFigures
			= FOCUSED_FIGURES_IN_BOUNDING_BOX;
		this.notifyToListener( NOTIFY_SAVE_PROPERTY );
		return true;
	}
	
	

	/**
	 * 
	 */
	private boolean createDOMTreeForFocusedFiguresInBoundingBox( Document document )
	{

		// get the root element
		Element property = document.getDocumentElement();

		
		// write properties of the window
		Element windowElement = this.createElementForFocusedFiguresInBoundingBox( document );
		if( windowElement==null )
		{
			return false;
		}
		property.appendChild( windowElement );

		
		// figures
		ArrayList list = this.getFocusedObjectsList();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			Element el = figure.createElementForFocusedInBoundingBox( document );
			if( el == null )
			{
				return false;
			}
			windowElement.appendChild( el );
		}

		return true;
	}



	/**
	 * 
	 */
	private boolean createDOMTreeForFocusedFiguresForDuplication( Document document )
	{

		// get the root element
		Element property = document.getDocumentElement();

		
		// write properties of the window
		Element windowElement = this.createElement( document );
		if( windowElement==null )
		{
			return false;
		}
		property.appendChild( windowElement );

		
		// figures
		ArrayList list = this.getFocusedObjectsList();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			Element el = figure.createElementForFocusedForDuplication( document );
			if( el == null )
			{
				return false;
			}
			windowElement.appendChild( el );
		}

		return true;
	}



	/**
	 * 
	 * @param element
	 * @return
	 */
	public boolean writePropertyForFocusedFiguresInBoundingBox( final Element element )
	{
		// Size
		Rectangle2D rect = this.getBoundingBoxOfFigures( this.getFocusedObjectsList() );
		final float width = (float)rect.getWidth()*SGIConstants.CM_POINT_RATIO/this.mMagnification;
		final float height = (float)rect.getHeight()*SGIConstants.CM_POINT_RATIO/this.mMagnification;

		element.setAttribute(
			KEY_PAPER_WIDTH,
			Float.toString( width )	+ SGUtilityNumber.cm );
		element.setAttribute(
			KEY_PAPER_HEIGHT,
			Float.toString( height ) + SGUtilityNumber.cm );
		
		this.writeProperty_(element);

		return true;
	}


	/**
	 * 
	 * @param document
	 * @param parent
	 * @return
	 */
	public boolean writeProperty( final Element element )
	{
		// Size
		element.setAttribute(
			KEY_PAPER_WIDTH,
			Float.toString( this.mPaperSize.x*SGIConstants.CM_POINT_RATIO )
				+ SGUtilityNumber.cm );
		element.setAttribute(
			KEY_PAPER_HEIGHT,
			Float.toString( this.mPaperSize.y*SGIConstants.CM_POINT_RATIO )
			+ SGUtilityNumber.cm );

		this.writeProperty_(element);

		return true;
	}

	
	
	private boolean writeProperty_( final Element element )
	{
		// Grid
		element.setAttribute(
			KEY_GRID_VISIBLE,
			Boolean.toString( this.isGridVisible() ) );
		element.setAttribute(
			KEY_GRID_INTERVAL,
			Float.toString( this.getGridInterval()*CM_POINT_RATIO )
				+ SGUtilityNumber.cm );
		element.setAttribute(
			KEY_GRID_LINE_WIDTH,
			Float.toString( this.getGridLineWidth() )
				+ SGUtilityNumber.pt );

		// Color
		element.setAttribute(
			KEY_BACKGROUND_COLOR,
			SGUtilityText.getColorString( this.getPaperColor() ) );
		element.setAttribute(
			KEY_GRID_COLOR,
			SGUtilityText.getColorString( this.getGridLineColor() ) );

		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);
			SGIGraphElement gElement = figure.getGraphElement();

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

			plList.addAll(list);
			dList.add( gElement.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++ )
		{
			SGIPropertySettingListener l = (SGIPropertySettingListener)plList.get(ii);
			dg.addPropertySettingListener(l);
			l.createTemporaryPropertyObject();
		}

		dg.setDialogProperty();
		dg.setLocation( this.getLocation() );


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


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

		return true;
	}









//
// 内部クラス
//


	/**
	 * Base class of panel class in the window.
	 *
	 */
	private static abstract class InnerPanel extends JPanel
	{
		/**
		 * 
		 */
		protected float mMagnification = 1.0f;


		/**
		 * 
		 */
		protected SGDrawingWindow mWnd = null;


		/**
		 * 
		 * @param wnd
		 */		
		protected InnerPanel( SGDrawingWindow wnd )
		{
			super();
			this.mWnd = wnd;
		}


		/**
		 * @param f
		 */
		public void setMagnification( final float f )
		{
			this.mMagnification = f;
		}
		
	}



	/**
	 * Panel to draw anchors and rubber band.
	 */
	private static class ForegroundPanel extends InnerPanel
	{
		/**
		 * 
		 */
		public static final float ANCHOR_SIZE = 6.0f;

		/**
		 * 
		 */
		protected ForegroundPanel( SGDrawingWindow wnd )
		{
			super( wnd );
			this.setVisible(true);
			this.setOpaque(false);
		}


		/**
		 * 
		 */
		public void paintComponent( Graphics g )
		{
			super.paintComponent(g);

			final Graphics2D g2d = (Graphics2D)g.create();

			ArrayList list = this.mWnd.getFocusedObjectsList();
			for( int ii=0; ii<list.size(); ii++ )
			{

				final SGFigure figure = (SGFigure)list.get(ii);
				if( figure.isSelectionSymbolsVisible() == false )
				{
					continue;
				}

				// ドラッグ中の矩形
				Rectangle2D dRect = figure.getRubberBandRect();
				if( SGFigure.mRubberBandFlag & SGFigure.mRubberBandVisibleFlag )
				{
					this.drawRubberBand( g2d, dRect.getBounds() );
				}


				// アンカー
				{
					final Rectangle2D gRect = figure.getGraphRect();
					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 float size = ANCHOR_SIZE;
			final Shape anchor = new Ellipse2D.Float(
				x-0.5f*size, y-0.5f*size, size, size
			);

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

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



		/**
		 * 
		 */
		private void drawRubberBand( final Graphics2D g2d, final Rectangle 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.draw( rect );

//			final int x = rect.x;
//			final int y = rect.y;
//			final int w = rect.width;
//			final int h = rect.height;
//			final Line2D north = new Line2D.Float( x, y, x+w, y );
//			final Line2D south = new Line2D.Float( x, y+h, x+w, y+h );
//			final Line2D west = new Line2D.Float( x, y, x, y+h );
//			final Line2D east = new Line2D.Float( x+w, y, x+w, y+h );
//
//			g2d.draw( north );
//			g2d.draw( south );
//			g2d.draw( west );
//			g2d.draw( east );

		}

		
	}




	/**
	 * Panel to draw grid lines and paper.
	 */
	private static class BackgroundPanel extends InnerPanel
	{
		/**
		 * 
		 */
		private boolean mGridVisibleFlag = SGDefaultValues.GRID_VISIBLE;


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


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


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


		/**
		 * 
		 */
		private Color mPaperColor = SGDefaultValues.WINDOW_PAPER_COLOR;


		/**
		 * 
		 */
		protected BackgroundPanel( SGDrawingWindow wnd )
		{
			super( wnd );
			this.setVisible(true);
			this.setOpaque(true);
		}


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


			// get the rectangle of paper
			Rectangle2D pRect = this.mWnd.getPaperRect();
			final float px = (float)pRect.getX();
			final float py = (float)pRect.getY();
			final float pw = (float)pRect.getWidth();
			final float ph = (float)pRect.getHeight();

			Rectangle2D vpRect = this.mWnd.getViewportBounds();
			final float vx = (float)vpRect.getX();
			final float vy = (float)vpRect.getY();
			final float vw = (float)vpRect.getWidth();
			final float vh = (float)vpRect.getHeight();


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

			final Line2D line = new Line2D.Float();


			// draw the grid lines
			if( this.isGridVisible() )
			{

				// set the property of grid lines
				g2d.setStroke( new BasicStroke( this.getGridLineWidth() ) );
				g2d.setPaint( this.getGridLineColor() );


				// vertical lines
				final float[] xArray = this.getVerticalGridLocation();
				for( int ii=0; ii<xArray.length; ii++ )
				{
					final float x = xArray[ii];
					line.setLine( x, py, x, py + ph );
					g2d.draw( line );
				}


				// horizontal lines
				final float[] yArray = this.getHorizontalGridLocation();
				for( int ii=0; ii<yArray.length; ii++ )
				{
					final float y = yArray[ii];
					line.setLine( px, y, px + pw, y );
					g2d.draw( line );
				}

			}


			// draw the edge of paper
			g2d.setPaint( Color.BLACK );
			g2d.setStroke( new BasicStroke(1) );
			g2d.draw( pRect );



//			final float eWidth = 5.0f;
//
//			g2d.setStroke( new BasicStroke( eWidth ) );
//
//			final double x = pRect.getX() + pRect.getWidth() + eWidth/2.0;
//			line.setLine(
//				x, pRect.getY() + eWidth,
//				x, pRect.getY() + pRect.getHeight() + eWidth/2.0
//			);
//			g2d.draw( line );
//
//			final double y = pRect.getY() + pRect.getHeight() + eWidth/2.0;
//			line.setLine(
//				pRect.getX() + eWidth, y,
//				pRect.getX() + pRect.getWidth() + eWidth/2.0, y
//			);
//			g2d.draw( line );


//g2d.setPaint( Color.BLUE );
//g2d.setStroke( new BasicStroke( 8.0f ) );
//g2d.draw( this.mWnd.getClientRect() );
////g2d.draw( this.mWnd.mTempRect );
//
//g2d.setPaint( Color.RED );
//float[] dash = { 5.0f, 5.0f };
//g2d.setStroke( new BasicStroke( 5.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1.0f, dash, 0.0f ) );
//g2d.draw( this.mWnd.getBoundingBox() );

		}


		/**
		 * 
		 * @return
		 */
		public float[] getVerticalGridLocation()
		{
			final float space = this.mMagnification*this.getGridInterval();

			// get the rectangle of paper
			Rectangle2D pRect = this.mWnd.getPaperRect();
			final float px = (float)pRect.getX();
			final float pw = (float)pRect.getWidth();

			Rectangle2D vpRect = this.mWnd.getViewportBounds();
			final float vx = (float)vpRect.getX();
			final float vw = (float)vpRect.getWidth();

			ArrayList list = new ArrayList();
			int cnt = (int)( ( vx - px )/space ) + 1;
			while( true )
			{
				final float x = cnt*space + px;

				if( x > vx + vw )
				{
					break;
				}

				if( x > px + pw )
				{
					break;
				}

				list.add( new Float(x) );
				cnt++;
			}

			final float[] array = new float[list.size()];
			for( int ii=0; ii<array.length; ii++ )
			{
				array[ii] = ((Float)list.get(ii)).floatValue();
			}

			return array;
		}


		/**
		 * 
		 * @return
		 */
		public float[] getHorizontalGridLocation()
		{
			final float space = this.mMagnification*this.getGridInterval();

			// get the rectangle of paper
			Rectangle2D pRect = this.mWnd.getPaperRect();
			final float py = (float)pRect.getY();
			final float ph = (float)pRect.getHeight();

			Rectangle2D vpRect = this.mWnd.getViewportBounds();
			final float vy = (float)vpRect.getY();
			final float vh = (float)vpRect.getHeight();

			ArrayList list = new ArrayList();
			int cnt = (int)( ( vy - py )/space ) + 1;
			while( true )
			{
				final float y = cnt*space + py;

				if( y > vy + vh )
				{
					break;
				}

				if( y > py + ph )
				{
					break;
				}

				list.add( new Float(y) );
				cnt++;
			}

			final float[] array = new float[list.size()];
			for( int ii=0; ii<array.length; ii++ )
			{
				array[ii] = ((Float)list.get(ii)).floatValue();
			}

			return array;
		}



		/**
		 * @return
		 */
		public float getGridInterval()
		{
			return mGridInterval;
		}

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

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

		/**
		 * @return
		 */
		public boolean isGridVisible()
		{
			return mGridVisibleFlag;
		}

		/**
		 * @param f
		 */
		public void setGridInterval( final float f )
		{
			mGridInterval = f;
		}

		/**
		 * @param color
		 */
		public void setGridLineColor( final Color color )
		{
			mGridLineColor = color;
		}

		/**
		 * @param f
		 */
		public void setGridLineWidth( final float f )
		{
			mGridLineWidth = f;
		}

		/**
		 * @param b
		 */
		public void setGridVisible( final boolean b )
		{
			mGridVisibleFlag = b;
		}

		/**
		 * @return
		 */
		public Color getPaperColor()
		{
			return mPaperColor;
		}

		/**
		 * @param color
		 */
		public void setPaperColor(Color color)
		{
			mPaperColor = color;
		}

	}




	/**
	 * Panel to draw rulers.
	 */
	private static class RulerPanel extends InnerPanel
	{
		/**
		 * 
		 */
		private static final int RULER_WIDTH = 20;
		private static final int ANCHOR_SIZE = 12;
		private static final Color INNER_COLOR_1 = new Color(234,238,232);
		private static final Color INNER_COLOR_2 = new Color(124,155,64);

		private static final Color ANCHOR_INNER_COLOR = new Color(222,222,222);
		private static final float ANCHOR_EDGE_LINE_WIDTH = 4.0f;
		private static final Color ANCHOR_EDGE_LINE_COLOR = Color.WHITE;
		private static final Color LINE_COLOR = Color.BLACK;
		private static final float LINE_WIDTH = 2.0f;
		private static final BasicStroke LINE_STROKE
			= new BasicStroke(
				LINE_WIDTH,
				BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
				1.0f,
				new float[]{ 5*LINE_WIDTH, LINE_WIDTH, LINE_WIDTH, 2*LINE_WIDTH },
				0.0f
			);



		/**
		 * 
		 */
		private Font mRulerFont = null;
		private Point2D mHorizontalLocation = null;
		private Point2D mVerticalLocation = null;
		private boolean mDrawHorizontalLineFlag = false;
		private boolean mDrawVerticalLineFlag = false;



		/**
		 * 
		 */
		RulerPanel( SGDrawingWindow wnd )
		{
			super( wnd );
			
			this.setVisible(true);
			this.setOpaque(false);

			final int style = SGUtilityText.getFontStyle(
				SGDefaultValues.RULER_FONT_STYLE );

			this.mRulerFont = new Font(
				SGDefaultValues.RULER_FONT_NAME,
				style,
				(int)SGDefaultValues.RULER_FONT_SIZE
			);
		}


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

//			if( mRulerVisibleFlag )
			{
				this.drawRuler(g2d);
			}


			// lines
			if( this.mDrawHorizontalLineFlag )
			{
				this.drawHorizontalLine(g2d);
			}

			if( this.mDrawVerticalLineFlag )
			{
				this.drawVerticalLine(g2d);
			}


			//
			// anchor
			//


			// horizontal
			{
				Point2D pos = null;
				if( this.mDrawHorizontalLineFlag )
				{
					pos = this.mHorizontalLocation;
				}
				else
				{
					pos = this.getHorizontalAnchorLocationFromPaper();
				}
				this.drawHorizontalAnchor((int)pos.getX(),(Graphics2D)g2d.create());
			}

			// vertical
			{
				Point2D pos = null;
				if( this.mDrawVerticalLineFlag )
				{
					pos = this.mVerticalLocation;
				}
				else
				{
					pos = this.getVerticalAnchorLocationFromPaper();
				}
				this.drawVerticalAnchor((int)pos.getY(),(Graphics2D)g2d.create());
			}

		}



		private void drawHorizontalAnchor(
			final int x, final Graphics2D g2d )
		{
			
			final int nPoints = 7;
			final int[] xPos = new int[nPoints];
			final int[] yPos = new int[nPoints];

			final int y = (int)this.getHorizontalAnchorLocationFromPaper().getY() -1;

			xPos[0] = x + 3;
			yPos[0] = y - 10;
			
			xPos[1] = xPos[0];
			yPos[1] = y - 6;

			xPos[2] = x + 6;
			yPos[2] = yPos[1];

			xPos[3] = x;
			yPos[3] = y;
			
			xPos[4] = x - 6;
			yPos[4] = yPos[2];

			xPos[5] = x - 3;
			yPos[5] = yPos[4];
			
			xPos[6] = xPos[5];
			yPos[6] = yPos[0];


			this.drawAnchor( xPos, yPos, nPoints, g2d );
		}


		private void drawVerticalAnchor(
			final int y, final Graphics2D g2d )
		{
			final int size = ANCHOR_SIZE;
			final int nPoints = 7;
			final int[] xPos = new int[nPoints];
			final int[] yPos = new int[nPoints];

			final int x = (int)this.getVerticalAnchorLocationFromPaper().getX() -1;

			xPos[0] = x - 10;
			yPos[0] = y + 3;
			
			xPos[1] = x - 6;
			yPos[1] = yPos[0];

			xPos[2] = xPos[1];
			yPos[2] = y + 6;

			xPos[3] = x;
			yPos[3] = y;
			
			xPos[4] = xPos[2];
			yPos[4] = y - 6;

			xPos[5] = xPos[4];
			yPos[5] = y - 3;
			
			xPos[6] = xPos[0];
			yPos[6] = yPos[5];


			this.drawAnchor( xPos, yPos, nPoints, g2d );
		}



		private void drawAnchor(
			final int[] xPos, final int[] yPos, final int nPoints,
			final Graphics2D g2d )
		{
			final Shape sh
				= new Polygon( xPos, yPos, nPoints );

			final int x1 = xPos[6];
			final int y1 = yPos[6];
			final int x2 = ( xPos[2] + xPos[3] )/2;
			final int y2 = ( yPos[2] + yPos[3] )/2;

			GradientPaint gPaint = new GradientPaint(
				x1, y1, INNER_COLOR_1, x2, y2, INNER_COLOR_2 );
			g2d.setPaint( gPaint );
			g2d.fill(sh);

			g2d.setStroke( new BasicStroke(1) );
			g2d.setRenderingHint(
				RenderingHints.KEY_ANTIALIASING, 
				RenderingHints.VALUE_ANTIALIAS_ON
			);
			g2d.setPaint( Color.BLACK );
			g2d.draw(sh);
			
		}


		private void drawHorizontalLine( final Graphics2D g2d )
		{
			if( this.mHorizontalLocation==null )
			{
				return;
			}
			Point2D pos = this.mHorizontalLocation;
			final float x = (float)pos.getX();
			Line2D line = new Line2D.Float();
			line.setLine(
				pos.getX(),
				this.getHorizontalAnchorLocationFromPaper().getY(),
				pos.getX(),
				this.getHeight()
			);
			g2d.setPaint( LINE_COLOR );
			g2d.setStroke( LINE_STROKE );
			g2d.draw(line);
		}


		private void drawVerticalLine( final Graphics2D g2d )
		{
			if( this.mVerticalLocation==null )
			{
				return;
			}
			Point2D pos = this.mVerticalLocation;
			Line2D line = new Line2D.Float();
			line.setLine(
				this.getVerticalAnchorLocationFromPaper().getX(),
				pos.getY(),
				this.getWidth(),
				pos.getY()
			);
			g2d.setPaint( LINE_COLOR );
			g2d.setStroke( LINE_STROKE );
			g2d.draw(line);
		}


		/**
		 * 
		 * @return
		 */
		private boolean isPressed()
		{
			return this.mDrawHorizontalLineFlag | this.mDrawVerticalLineFlag;
		}


		/**
		 * 
		 * @param e
		 * @return
		 */
		private boolean pressed( MouseEvent e )
		{
			final int size = 10;

			{
				Point2D pos = this.getHorizontalAnchorLocationFromPaper();
				final int posX = (int)pos.getX();
				final int posY = (int)pos.getY();
				Rectangle rect = new Rectangle(
					posX - size/2, posY - size,
					size, size
				);

				if( rect.contains( e.getPoint() ) )
				{
					this.mDrawHorizontalLineFlag = true;
					this.mHorizontalLocation = pos;
					this.repaint();
					return true;
				}
			}

			{
				Point2D pos = this.getVerticalAnchorLocationFromPaper();
				final int posX = (int)pos.getX();
				final int posY = (int)pos.getY();
				Rectangle rect = new Rectangle(
					posX - size, posY - size/2,
					size, size
				);

				if( rect.contains( e.getPoint() ) )
				{
					this.mDrawVerticalLineFlag = true;
					this.mVerticalLocation = pos;
					this.repaint();
					return true;
				}
			}

			this.mDrawHorizontalLineFlag = false;
			this.mDrawVerticalLineFlag = false;
			this.mHorizontalLocation = null;
			this.mVerticalLocation = null;
			this.repaint();

			return false;
		}


		private boolean dragged( MouseEvent e )
		{
			this.mHorizontalLocation = e.getPoint();
			this.mVerticalLocation = e.getPoint();
			return true;
		}


		private boolean released( MouseEvent e )
		{
			final int x = e.getX();
			final int y = e.getY();

			Rectangle2D paper = this.mWnd.getPaperRect();
			final float startX = this.getPaperStartX();
			final float startY = this.getPaperStartY();
			
			final float ratio = SGIConstants.CM_POINT_RATIO;
			final float minWidth = SGDrawingWindow.PAPER_WIDTH_MIN_VALUE/ratio;
			final float minHeight = SGDrawingWindow.PAPER_HEIGHT_MIN_VALUE/ratio;
			final float maxWidth = SGDrawingWindow.PAPER_WIDTH_MAX_VALUE/ratio;
			final float maxHeight = SGDrawingWindow.PAPER_HEIGHT_MAX_VALUE/ratio;

			if( this.mDrawHorizontalLineFlag )
			{
				float w = ( x - startX )/this.mMagnification;
				if( w < minWidth )
				{
					w = minWidth;
				}
				if( w > maxWidth )
				{
					w = maxWidth;
				}
				this.mWnd.setPaperSize( w, this.mWnd.mPaperSize.y );
				this.mWnd.setChanged(true);
			}
			
			if( this.mDrawVerticalLineFlag )
			{
				float h = ( y - startY )/this.mMagnification;
				if( h < minHeight )
				{
					h = minHeight;
				}
				if( h > maxHeight )
				{
					h = maxHeight;
				}
				this.mWnd.setPaperSize( this.mWnd.mPaperSize.x, h );
				this.mWnd.setChanged(true);
			}

			if( this.mDrawHorizontalLineFlag | this.mDrawVerticalLineFlag )
			{
				this.mWnd.updateClientRect();
				this.mWnd.notifyToRoot();
				this.repaint();
			}

			this.mDrawHorizontalLineFlag = false;
			this.mDrawVerticalLineFlag = false;
			this.mHorizontalLocation = null;
			this.mVerticalLocation = null;

			return true;
		}


		private Point2D getHorizontalAnchorLocationFromPaper()
		{
			Rectangle2D rect = this.mWnd.getPaperRect();
			final float x = (float)rect.getX();
			final float y = (float)rect.getY();
			final float w = (float)rect.getWidth();
			final int rw = RulerPanel.RULER_WIDTH;
			Point2D pos = new Point2D.Float( x + rw + w, rw );
			return pos;
		}


		private Point2D getVerticalAnchorLocationFromPaper()
		{
			Rectangle2D rect = this.mWnd.getPaperRect();
			final float x = (float)rect.getX();
			final float y = (float)rect.getY();
			final float h = (float)rect.getHeight();
			final int rw = RulerPanel.RULER_WIDTH;
			Point2D pos = new Point2D.Float( rw, y + rw + h );
			return pos;
		}


		private float getPaperStartX()
		{
			Rectangle2D rect = this.mWnd.getPaperRect();
			final float x = (float)rect.getX();
			final int rw = RulerPanel.RULER_WIDTH;
			return x + rw;			
		}


		private float getPaperStartY()
		{
			Rectangle2D rect = this.mWnd.getPaperRect();
			final float y = (float)rect.getY();
			final int rw = RulerPanel.RULER_WIDTH;
			return y + rw;
		}


		private float getPaperEndX()
		{
			Rectangle2D rect = this.mWnd.getPaperRect();
			final float x = (float)rect.getX();
			final float w = (float)rect.getWidth();
			final int rw = RulerPanel.RULER_WIDTH;
			return x + rw + w;
		}


		private float getPaperEndY()
		{
			Rectangle2D rect = this.mWnd.getPaperRect();
			final float y = (float)rect.getY();
			final float h = (float)rect.getHeight();
			final int rw = RulerPanel.RULER_WIDTH;
			return y + rw + h;
		}



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

			//
			final int rw = RULER_WIDTH;
			final int width = this.getWidth();
			final int height = this.getHeight();

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

			xPoints[0] = 0;
			yPoints[0] = 0;
			
			xPoints[1] = width;
			yPoints[1] = 0;
			
			xPoints[2] = width;
			yPoints[2] = rw;
			
			xPoints[3] = rw;
			yPoints[3] = rw;
			
			xPoints[4] = rw;
			yPoints[4] = height;
			
			xPoints[5] = 0;
			yPoints[5] = height;

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


			//
			// paint
			//

			Color bgColor = this.getBackground();
			Color lineColor = Color.BLACK;

			g2d.setPaint( bgColor );
			g2d.fill( polygon );
			g2d.setPaint( lineColor );
			g2d.setStroke( new BasicStroke(1) );
			g2d.draw( polygon );


			// draw the lines of rulers
			this.drawNumbersAndLines( g2d );


			// corner
			final Rectangle2D rectCorner
				= new Rectangle2D.Float( 0.0f, 0.0f, rw, rw );
			g2d.setPaint( bgColor );
			g2d.fill( rectCorner );
			g2d.setPaint( lineColor );
			g2d.draw( rectCorner );


//			g2d.setStroke( new BasicStroke(2) );
//
//			Line2D left = new Line2D.Float( 0.0f, 0.0f, 0.0f, rw );
//			Line2D top = new Line2D.Float( 0.0f, 0.0f, rw, 0.0f );
//			g2d.setPaint( Color.WHITE );
//			g2d.draw( left );
//			g2d.draw( top );
//
//			Line2D right = new Line2D.Float( rw, 0.0f, rw, rw );
//			Line2D bottom = new Line2D.Float( 0.0f, rw, rw, rw );
//			g2d.setPaint( Color.BLACK );
//			g2d.draw( right );
//			g2d.draw( bottom );

			return true;

		}




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

			final int rw = RULER_WIDTH;
			final float mag = this.mMagnification;
			final int width = this.getWidth();
			final int height = this.getHeight();
			final Rectangle vpRect
				= new Rectangle( 0, 0, width - rw, height - rw );

			final Rectangle2D pRect = this.mWnd.getPaperRect();
			final Rectangle2D cRect = this.mWnd.getClientRect();

//			final float hStart = rw + (float)cRect.getX();
//			final float vStart = rw + (float)cRect.getY();

			final Line2D line = new Line2D.Float();

			g2d.setPaint( Color.BLACK );


			//
			// axis lines
			//

			g2d.setStroke( new BasicStroke(2) );

			// horizontal
			{
				final float x1 = rw;
				final float x2 = width;
				final float y = rw;
				line.setLine( x1, y, x2, y );
				g2d.draw(line);
			}

			// perpendicular
			{
				final float x = rw;
				final float y1 = rw;
				final float y2 = height;
				line.setLine( x, y1, x, y2 );
				g2d.draw(line);			
			}



			//
			// scale lines and numbers
			//

			Font font = this.mRulerFont;
			g2d.setStroke( new BasicStroke(1) );
			g2d.setFont( font );
			final float fSize = font.getSize();


			int offset;
			int subNum;
			if( mag < 0.50f )
			{
				offset = 4;
				subNum = 8;
			}
			else if( mag < 1.0f )
			{
				offset = 2;
				subNum = 4;
			}
			else
			{
				offset = 1;
				subNum = 4;
			}


			final float factor = mag/CM_POINT_RATIO;

			// horizontal
			{
				final ArrayList numberList = new ArrayList();
				final float px = (float)pRect.getX();
				final float pOffset = - px;
				final float pOffsetInRulerUnit = pOffset/factor;
				final float endLocation = (float)vpRect.getWidth() + pOffset;
				int diff = (int)pOffsetInRulerUnit;
				if( diff%offset!=0 )
				{
					diff = (diff/offset)*offset;
				}

				int cnt = diff;
				while( true )
				{
//System.out.print(cnt+" ");
					final float location = factor*cnt;
					if( location > endLocation )
					{
						break;
					}

					numberList.add( new Integer(cnt) );
					cnt+=offset;
				}
//System.out.println();


				// draw
				for( int ii=0; ii<numberList.size(); ii++ )
				{
					// main
					final int num = ((Integer)numberList.get(ii)).intValue();
					final float location = num*factor;
					final float pos = px + rw + location;
					line.setLine(
						pos, 0.20f*rw,
						pos, rw );
					g2d.draw(line);

					// number
					final int x = (int)( pos + 0.3f*fSize );
					final int y = (int)fSize + 1;
					g2d.drawString( Integer.toString( num ), x, y );

					// sub
					for( int jj=0; jj<subNum; jj++ )
					{
						final float pos_ = pos + 0.2f*(jj+1)*factor*offset;

						line.setLine(
							pos_, 0.75f*rw,
							pos_, rw );
						g2d.draw(line);
					}

				}

			}


			// perpendicular
			{
				final ArrayList numberList = new ArrayList();
				final float py = (float)pRect.getY();
				final float pOffset = - py;
				final float pOffsetInRulerUnit = pOffset/factor;
				final float endLocation = (float)vpRect.getHeight() + pOffset;
				int diff = (int)pOffsetInRulerUnit;
				if( diff%offset!=0 )
				{
					diff = (diff/offset)*offset;
				}

				int cnt = diff;
				while( true )
				{
//System.out.print(cnt+" ");
					final float location = factor*cnt;
					if( location > endLocation )
					{
						break;
					}

					numberList.add( new Integer(cnt) );
					cnt+=offset;
				}
//System.out.println();

				// draw
				for( int ii=0; ii<numberList.size(); ii++ )
				{

					// main
					final int num = ((Integer)numberList.get(ii)).intValue();
					final float location = num*factor;
					final float pos = py + rw + location;
					line.setLine(
						0.20f*rw, pos,
						rw, pos );
					g2d.draw(line);

					// number
					final int x = (int)( 0.20f*rw );
					int y = (int)( pos + fSize + 1 );
					char[] array = Integer.toString( num ).toCharArray();
					for( int jj=0; jj<array.length; jj++ )
					{
						Character c = new Character( array[jj] );
						g2d.drawString( c.toString(), x, y );
						y += (int)fSize;
					}

					// sub
					for( int jj=0; jj<subNum; jj++ )
					{
						final float pos_ = pos + 0.2f*(jj+1)*factor*offset;
						line.setLine(
							0.750f*rw, pos_,
							rw, pos_ );
						g2d.draw(line);
					}
				}

			}


			return true;
		}


	}




	/**
	 * Property of SGDrawingWindow.
	 */
	public static class WindowProperties extends SGProperties
	{
		TreeMap figureMap = new TreeMap();
		ArrayList visibleFigureList = new ArrayList();

		public static final String[] keys = {
			KEY_PAPER_WIDTH, KEY_PAPER_HEIGHT, KEY_BACKGROUND_COLOR,
			KEY_GRID_VISIBLE, KEY_GRID_COLOR, KEY_GRID_INTERVAL, KEY_GRID_LINE_WIDTH
		};


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


		/**
		 * 
		 */
		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 Boolean getGridVisible()
		{
			final String value = this.getProperty(KEY_GRID_VISIBLE);
			return SGUtilityText.getBoolean(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 setGridVisible( final boolean b )
		{
			this.setProperty( KEY_GRID_VISIBLE, new Boolean(b).toString() );
			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;
		}

	}



}
