
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.Cursor;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
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.Iterator;
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.JDialog;
import javax.swing.JFrame;
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.event.MouseInputListener;

import org.freehep.util.export.ExportDialog;
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
{


	//
	// Text for the menu command of the menu bar
	//

	public static final String MENU_FILE = "File";
	public static final String MENUCMD_CREATE_NEW_WINDOW = "Create New Window";
	public static final String MENUCMD_CLOSE_WINDOW = "Close Window";
	public static final String MENUCMD_DRAW_GRAPH = "Draw Graph";
	public static final String MENUCMD_LOAD_PROPERTY = "Load Property";
	public static final String MENUCMD_SAVE_PROPERTY = "Save Property";
	public static final String MENUCMD_EXPORT_AS_IMAGE = "Export as Image";
	public static final String MENUCMD_PRINT = "Print";
	public static final String MENUCMD_PREVIEW = "Preview";
	public static final String MENUCMD_EXIT = "Exit";

	public static final String MENU_EDIT = "Edit";
	public static final String MENUCMD_UNDO = "Undo";
	public static final String MENUCMD_REDO = "Redo";
	public static final String MENUCMD_CUT = "Cut";
	public static final String MENUCMD_COPY = "Copy";
	public static final String MENUCMD_PASTE = "Paste";
	public static final String MENUCMD_DELETE = "Delete";
	public static final String MENUCMD_SELECT_ALL = "Select All";
	public static final String MENUCMD_DUPLICATE = "Duplicate";

	public static final String MENU_INSERT = "Insert";
	public static final String MENUCMD_INSERT_LABEL = "Label";
	public static final String MENUCMD_INSERT_SIG_DIFF_SYMBOL = "Significant Difference";
	public static final String MENUCMD_INSERT_AXIS_BREAK_SYMBOL = "Axis Break";
	public static final String MENUCMD_INSERT_TIMING_LINE = "Timing Line";

	public static final String MENU_LAYOUT = "Layout";
	public static final String MENU_PAPER_SIZE = "Paper Size";
	public static final String MENUCMD_PAPER_A4_SIZE = "A4";
	public static final String MENUCMD_PAPER_B5_SIZE = "B5";
	public static final String MENUCMD_PAPER_USLETTER_SIZE = "US Letter";
	public static final String MENUCMD_PAPER_PORTRAIT = "Portrait";
	public static final String MENUCMD_PAPER_LANDSCAPE = "Landscape";
	public static final String MENUCMD_BOUNDING_BOX = "Bounding Box";
	public static final String MENUCMD_PAPER_USER_CUSTOMIZE = "User Customize";

	public static final String MENU_GRID = "Grid";
	public static final String MENUCMD_PLUS_GRID = "Plus";
	public static final String MENUCMD_MINUS_GRID = "Minus";
	public static final String MENUCMD_GRID_VISIBLE = "Visible";
	public static final String MENUCMD_SNAP_TO_GRID = "Snap to Grid";

	public static final String MENU_ZOOM = "Zoom";
	public static final String MENUCMD_ZOOM_IN = "Zoom In";
	public static final String MENUCMD_ZOOM_OUT = "Zoom Out";
	public static final String MENUCMD_DEFAULT_ZOOM = "Default Zoom";
	public static final String MENUCMD_ZOOM_WAY_OUT = "Zoom Way Out";
	public static final String MENUCMD_AUTO_ZOOM = "Auto Zoom";

	public static final String MENUCMD_LOCK = "Lock";

	public static final String MENU_ARRANGE = "Arrange";
	public static final String MENUCMD_MOVE_SELECTED_DATA_TO_FRONT = "Move Data to Front";
	public static final String MENUCMD_MOVE_SELECTED_DATA_TO_BACK = "Move Data to Back";
	public static final String MENUCMD_AUTO_ARRANGEMENT = "Auto Arrangement";
	public static final String MENU_ALIGN_OBJECTS = "Align Objects";
	public static final String MENUCMD_ALIGN_LEFT = "Left";
	public static final String MENUCMD_ALIGN_CENTER = "Center";
	public static final String MENUCMD_ALIGN_RIGHT = "Right";
	public static final String MENUCMD_ALIGN_TOP = "Top";
	public static final String MENUCMD_ALIGN_MIDDLE = "Middle";
	public static final String MENUCMD_ALIGN_BOTTOM = "Bottom";

	public static final String MENU_HELP = "Help";
	public static final String MENUCMD_UPGRADE = "Upgrade";
	public static final String MENUCMD_CHANGE_LOG = "Change Log";
	public static final String MENUCMD_PROXY = "Proxy";
	public static final String MENUCMD_ABOUT = "About";



	//
	// Text for the tool-tips of the tool bar
	//

	public static final String TIP_CREATE_NEW_WINDOW = MENUCMD_CREATE_NEW_WINDOW;
	public static final String TIP_DRAW_GRAPH = MENUCMD_DRAW_GRAPH;
	public static final String TIP_LOAD_PROPERTY = MENUCMD_LOAD_PROPERTY;
	public static final String TIP_SAVE_PROPERTY = MENUCMD_SAVE_PROPERTY;
	public static final String TIP_EXPORT_FORMAT = MENUCMD_EXPORT_AS_IMAGE;
	public static final String TIP_BOUNDING_BOX = MENUCMD_BOUNDING_BOX;
	public static final String TIP_INSERT_LABEL = "Insert Label";
	public static final String TIP_INSERT_SIG_DIFF_SYMBOL = "Insert Significant Difference Symbol";
	public static final String TIP_INSERT_AXIS_BREAK_SYMBOL = "Insert Axis Break Symbol";
	public static final String TIP_INSERT_TIMING_LINE = "Insert Timing Line";
	public static final String TIP_LOCK = MENUCMD_LOCK;
	public static final String TIP_ZOOM = "Zoom";



	//
	// Text for the properties
	//

	public static final String TAG_NAME_WINDOW = "Window";
	public static final String KEY_PAPER_WIDTH = "PaperWidth";
	public static final String KEY_PAPER_HEIGHT = "PaperHeight";
	public static final String KEY_BACKGROUND_COLOR = "BackgroundColor";
	public static final String KEY_GRID_VISIBLE = "GridVisible";
	public static final String KEY_GRID_INTERVAL = "GridInterval";
	public static final String KEY_GRID_LINE_WIDTH = "GridLineWidth";
	public static final String KEY_GRID_COLOR = "GridLineColor";



	//
	// Constant Values
	//

	public static final float PAPER_WIDTH_MIN_VALUE = 0.0f;
	public static final float PAPER_WIDTH_MAX_VALUE = 99.0f;
	public static final float PAPER_HEIGHT_MIN_VALUE = 0.0f;
	public static final float PAPER_HEIGHT_MAX_VALUE = 99.0f;

	public static final float GRID_INTERVAL_MIN_VALUE = 0.50f;
	public static final float GRID_INTERVAL_MAX_VALUE = 10.0f;

	public static final float PAPER_STEP_SIZE = 1.0f;
	public static final float GRID_INTERVAL_STEP_SIZE = 0.50f;



	/**
	 * 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 final GridPanel mGridPanel = new GridPanel();


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


	/**
	 * A panel to draw rulers.<BR>
	 */
	private final RulerPanel mRulerPanel = new RulerPanel();


	/**
	 * 水平方向スクロールバー
	 */
	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;


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


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


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



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



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



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


	/**
	 * 
	 */
	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 JToolBar mToolBar = new JToolBar();



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


	/**
	 * 
	 */
	public static final float mAnchorSize = 6.0f;


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


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


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


	/**
	 * 
	 */
	private Color mRulerBackGroundColor;


	/**
	 * 
	 */
	private float mRulerFontSize;


	/**
	 * 
	 */
	private int mRulerFontStyle;


	/**
	 * 
	 */
	private String mRulerFontName;


	/**
	 * 
	 */
	private Font mRulerFont = null;



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


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


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


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



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



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


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


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



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


	/**
	 * 
	 */
	private SGAboutDialog mAboutDialog = null;


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


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



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





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

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


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


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


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


		// Create About dialog.
		this.createAboutDialog();


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


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


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


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


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


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


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


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


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


		// pack
		this.pack();


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


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


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

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

		//
		this.addMouseWheelListener(this);


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


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


		//
		// update items
		//

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

		return true;

	}



	/**
	 * 
	 * @return
	 */
	protected 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( MENU_FILE, MENUCMD_EXPORT_AS_IMAGE );
			item.setEnabled( flag );
		}
		{
			JMenuItem item = this.getMenuItem( MENU_FILE, MENUCMD_SAVE_PROPERTY );
			item.setEnabled( flag );
		}
		{
//			JMenuItem item = this.getMenuItem( MENU_FILE, MENUCMD_PRINT );
//			item.setEnabled( flag );
		}
		{
//			JMenuItem item = this.getMenuItem( MENU_FILE, MENUCMD_PREVIEW );
//			item.setEnabled( flag );
		}
		{
			final JMenu layout = this.getMenuFromMenuBar( MENU_LAYOUT );
			final JMenu paper = this.getMenu( layout, MENU_PAPER_SIZE );	
			final JMenuItem item = this.getMenuItem( paper, MENUCMD_BOUNDING_BOX );
			item.setEnabled( flag );
		}
		{
			JMenuItem item = this.getMenuItem( MENU_ARRANGE, MENUCMD_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.setSizeOfComponents();


		// set the client rectangle
		this.mClientRect = new Rectangle2D.Float();
		this.setClientOrigin( 0.0f, 0.0f );
		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()
	{

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

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

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

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


//		this.setScrollBarProperty();


		return true;
	}



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

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

//System.out.println(url);

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

		return icon;
	}
	
	

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

		String dir = RESOURCES_DIRNAME;

		final ImageIcon iconCreateNewWindow = this.createIcon( dir + "NewGraph.gif" );
		this.mCreateNewWindowButton = new JButton(iconCreateNewWindow);
		this.mCreateNewWindowButton.setToolTipText( TIP_CREATE_NEW_WINDOW );

		final ImageIcon iconDrawGraph = this.createIcon( dir + "DrawGraph.gif" );
		this.mDrawGraphButton = new JButton(iconDrawGraph);
		this.mDrawGraphButton.setToolTipText( TIP_DRAW_GRAPH );

		final ImageIcon iconLoadProperty = this.createIcon( dir + "LoadProperty.gif" );
		this.mLoadPropertyButton = new JButton(iconLoadProperty);
		this.mLoadPropertyButton.setToolTipText( TIP_LOAD_PROPERTY );

		final ImageIcon iconSaveProperty = this.createIcon( dir + "SaveGraph.gif");
		this.mSavePropertyButton = new JButton(iconSaveProperty);
		this.mSavePropertyButton.setToolTipText( TIP_SAVE_PROPERTY );

		final ImageIcon iconExportFormat = this.createIcon( dir + "ExportImage.gif" );
		this.mExportFormatButton = new JButton(iconExportFormat);
		this.mExportFormatButton.setToolTipText( TIP_EXPORT_FORMAT );

		final ImageIcon iconBoundingBox = this.createIcon( dir + "BoundingBox.gif" );
		this.mBoundingBoxButton = new JButton(iconBoundingBox);
		this.mBoundingBoxButton.setToolTipText( TIP_BOUNDING_BOX );

		final ImageIcon iconLabel = this.createIcon( dir + "InsertString.gif" );
		this.mInsertLabelButton = new JToggleButton(iconLabel);
		this.mInsertLabelButton.setToolTipText( TIP_INSERT_LABEL );

		final ImageIcon iconSigDiffSymbol = this.createIcon( dir + "InsertSig.gif" );
		this.mInsertSignificantDifferenceSymbolButton = new JToggleButton(iconSigDiffSymbol);
		this.mInsertSignificantDifferenceSymbolButton.setToolTipText( TIP_INSERT_SIG_DIFF_SYMBOL );

		final ImageIcon iconBreakSymbol = this.createIcon( dir + "InsertBreak.gif" );
		this.mInsertBreakButton = new JToggleButton(iconBreakSymbol);
		this.mInsertBreakButton.setToolTipText( TIP_INSERT_AXIS_BREAK_SYMBOL );

		final ImageIcon iconTimingLine = this.createIcon( dir + "InsertTiming.gif" );
		this.mInsertTimingLineButton = new JToggleButton(iconTimingLine);
		this.mInsertTimingLineButton.setToolTipText( TIP_INSERT_TIMING_LINE );

		final ImageIcon iconLock = this.createIcon( dir + "UnlockFigure.gif" );
		this.mLockFigureButton = new JToggleButton(iconLock);
		this.mLockFigureButton.setToolTipText( TIP_LOCK );

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

		// ツールバーにコンポーネントを追加
		this.mToolBar.add(this.mCreateNewWindowButton);
		this.mToolBar.add(this.mDrawGraphButton);
		this.mToolBar.add(this.mLoadPropertyButton);
		this.mToolBar.add(this.mSavePropertyButton);
		this.mToolBar.add(this.mExportFormatButton);
		this.mToolBar.add(this.mBoundingBoxButton);
		this.mToolBar.addSeparator();
		this.mToolBar.add(this.mInsertLabelButton);
		this.mToolBar.add(this.mInsertSignificantDifferenceSymbolButton);
		this.mToolBar.add(this.mInsertBreakButton);
		this.mToolBar.add(this.mInsertTimingLineButton);
		this.mToolBar.addSeparator();
		this.mToolBar.add(this.mLockFigureButton);
		this.mToolBar.addSeparator();
		this.mToolBar.add(this.mZoomComboBoxPanel);

                //		this.mZoomComboBox.setMaximumSize(
                //			new Dimension( 100, 100 ) );

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

		this.setToolBar();


		return true;
	}



	/**
	 * 
	 * @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(SGIConstants.RESOURCES_DIRNAME+"LockFigure.gif");
		}
		else
		{
			iconLock = this.createIcon(SGIConstants.RESOURCES_DIRNAME+"UnlockFigure.gif");
		}

		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 createGridPanel()
	{
//		mGridPanel = new GridPanel();
		mGridPanel.setVisible(true);
		mGridPanel.setOpaque(true);

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

		return true;
	}



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

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

		this.mZoomComboBox.setEditable( true );
		this.mZoomComboBox.setBackground( Color.WHITE );
		this.mZoomComboBox.setToolTipText( TIP_ZOOM );
		String osName = OS_NAME.toLowerCase();
		if( !osName.startsWith("mac os x") )
		{
			this.mZoomComboBox.setBorder(BorderFactory.createLoweredBevelBorder());
		}
		this.setDefaultZoom();

		return true;
	}



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

		return true;
	}



	/**
	 * 
	 * @return
	 */
	private boolean createRulerPanel()
	{
		this.mRulerPanel.setVisible(true);
		this.mRulerPanel.setOpaque(false);

		this.mRulerFontSize = SGDefaultValues.RULER_FONT_SIZE;
		this.mRulerFontName = SGDefaultValues.RULER_FONT_NAME;
		this.mRulerFontStyle = SGUtilityText.getFontStyle(
			SGDefaultValues.RULER_FONT_STYLE );
		this.mRulerBackGroundColor = this.getBackground();
		this.mRulerLineColor = Color.BLACK;

		this.mRulerFont = new Font(
			mRulerFontName,
			mRulerFontStyle,
			(int)(mRulerFontSize)
		);

		this.mLayeredPane.add(mRulerPanel);
		this.mLayeredPane.setLayer( mRulerPanel, LAYER_RULER_PANEL );

		return true;
	}



	protected boolean mRulerVisibleFlag = true;

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



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

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

		JMenuItem item = new JMenuItem( MENUCMD_PROPERTY );
		item.addActionListener(this);
		this.mPopupMenu.add(item);

		return true;
	}



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



	/**
	 * 
	 * @return
	 */
	private boolean createAboutDialog()
	{
		this.mAboutDialog = new SGAboutDialog(this,true);
		return true;
	}



	/**
	 * 
	 * @return
	 */
	public SGAboutDialog getAboutDialog()
	{
		return this.mAboutDialog;
	}



	/**
	 * 
	 */
	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 getGridVisible()
	{
		return this.mGridVisibleFlag;
	}


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


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



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


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


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

		this.mBackgroundColor = color;

		return true;
	}



	/**
	 * 
	 * @param b
	 * @return
	 */
	public boolean setGridVisible( final boolean b )
	{
		this.mGridVisibleFlag = b;
		return true;
	}


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



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



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

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



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

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

		// ツールバーの幅
		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;
	}



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


	/**
	 * 
	 */
	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
	 */
	protected void moveToBack( SGFigure figure )
	{
		this.mLayeredPane.moveToBack( figure );
	}


	/**
	 * 
	 * @param figure
	 */
	protected void moveToFront( SGFigure figure )
	{
		this.mLayeredPane.moveToFront( figure );
	}

	

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



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

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

		//
		this.mChangedFlag = true;		
		this.notifyToRoot();


		// clear the list
		this.clearFocusedObjects();
				

		//
		this.updateItemsByFigureNumbers();


		return true;
	}



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



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

		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.
	 */
	public boolean clearFocusedFigures()
	{
		ArrayList list = this.getFocusedObjectsList();
		for( int ii=list.size()-1; ii>=0; ii-- )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			this.removeFocusedFigure( figure );
		}
		return true;
	}



	/**
	 * 
	 * @param figure
	 * @return
	 */
	public boolean addFocusedFigure( final SGFigure figure )
	{
		figure.setSelected(true);
//		this.mFocusedFigureList.add( figure );
		figure.setSymbolsVisibleAroundAllObjects(true);
		return true;
	}



	/**
	 * 
	 * @param figure
	 * @return
	 */
	public boolean removeFocusedFigure( final SGFigure figure )
	{
		figure.setSelected(false);
//		this.mFocusedFigureList.remove( figure );
		figure.setSymbolsVisibleAroundAllObjects(false);
		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 )
	{
//System.out.println(flag);

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

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

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

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


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

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

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

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

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

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

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

		// 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.mClientRect;
		final float xx = ( x - (float)cRect.getX() )/this.mMagnification;
		final float yy = ( y - (float)cRect.getY() )/this.mMagnification;
		this.mPaperOrigin.setValues( xx, yy );
		return true;
	}



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



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


	/**
	 * 
	 * @return
	 */
	public float getPaperY()
	{
		final Rectangle2D cRect = this.mClientRect;
		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 float PAPER_MARGIN = 1.5f/SGIConstants.CM_POINT_RATIO;


	/**
	 * 
	 * @return
	 */
	public Rectangle2D getBoundingBox()
	{
		Rectangle2D rect = new Rectangle2D.Float();
		rect.setRect( this.getPaperRect() );
/*
		if( this.getVisibleFigureListFromMap().size()!=0 )
		{
			Rectangle2D fRect = this.getBoundingBoxOfFigures( this.getVisibleFigureListFromMap() );
			if( fRect!=null )
			{
				rect = rect.createUnion(fRect);
			}
		}
*/
		rect.setRect(
			rect.getX(),
			rect.getY(),
			rect.getWidth() + PAPER_MARGIN*this.mMagnification,
			rect.getHeight() + PAPER_MARGIN*this.mMagnification
		);

		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 setSizeOfComponents()
	{
		SGTuple2f paneSize = this.getPaneSize();
		this.mLayeredPane.setSize( (int)paneSize.x, (int)paneSize.y );
		this.mGridPanel.setBounds();
		this.mAnchorPanel.setBounds();
		this.mRulerPanel.setBounds();

		return true;
	}



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

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


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


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


	/**
	 * 
	 */
	public static final int DEFAULT_ZOOM = 100;



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

		//
		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();
		if( mode==0 || mode==1 )
		{
//			width = (float)( - cRect.getX() + bbRect.getX() + bbRect.getWidth() )/this.mMagnification;
			width = (float)( bbRect.getWidth() )/this.mMagnification;
		}
		if( mode==0 || mode==2 )
		{
//			height = (float)( - cRect.getY() + bbRect.getY() + bbRect.getHeight() )/this.mMagnification;
			height = (float)( bbRect.getHeight() )/this.mMagnification;
		}

		this.setPaperSizeRoundingOut( width, height );

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


		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;

//System.out.println(this.getScrollValue(bar));

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

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

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

					// set the graph area rect of the figure
					figure.setGraphRectToFigureElement();

					// set the rubber band
					figure.mRubberBandRect.setRect( figure.getGraphRect() );
				}
			}


			this.getContentPane().repaint();


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

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

		}


	}



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

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

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

		return true;
	}



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

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

			Rectangle2D rect = array[ii].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();

		if( source.equals( this.mToolBar ) )
		{

//System.out.println(this.getContentPane().getComponents().length);

			if( pName.equals("ancestor") )
			{
			

			}
			else if( pName.equals("orientation") )
			{
				final int oldNum = ((Number)oldValue).intValue();
				final int newNum = ((Number)newValue).intValue();

			}

		}


	}



	/**
	 * コンポーネントが可視になると呼び出されます。 
	 */
	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();
			return;
		}
		e.translatePoint( ls, ts );

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


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

		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;
			}
		}
		
		ArrayList list = this.getVisibleFigureListFromLayer();
		if( selectedButton!=null )
		{

			// When the mouse is released with toggle button is selected
			// without any visible figure, show a message dialog.
			if( list.size()==0 )
			{
				SGUtility.showMessageDialog(
					this,
					"There is no figure.",
					"Failed to add a symbol.", 
					JOptionPane.WARNING_MESSAGE );
				selectedButton.setSelected(false);
				this.setDefaultCursor();
			}
			
			
			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() )
			{
				msg = "Click the figure.";
			}
			else if( this.mInsertBreakButton.isSelected() )
			{
				msg = "Click the axis line.";
			}
			else if( this.mInsertSignificantDifferenceSymbolButton.isSelected() )
			{
				msg = "Click a horizontal axis line.";
			}
			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 boolean 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) )
			{
				this.getContentPane().repaint();
				return true;
			}
		}

		return false;
	}



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

		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;
		}		
		
		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 )
	{
		// Only when the mouse is pressed in the viewport,
		// notify the mouse event to the figures
		if( this.mViewportPressedFlag == false )
		{
			return;
		}

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

		return true;
	}



	/**
	 * コンポーネント上で、ボタンを押さずにマウスを移動すると呼び出されます。 
	 */
	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.mClientRect;
		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 = {
			MENUCMD_INSERT_LABEL, MENUCMD_INSERT_SIG_DIFF_SYMBOL,
			MENUCMD_INSERT_AXIS_BREAK_SYMBOL, MENUCMD_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( MENU_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( MENU_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;
	}



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


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



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



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


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


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


	
	/**
	 * 
	 */
	public static final String NOTIFY_SAVE_PROPERTY = "save property";


	/**
	 * 
	 * @return
	 */
	protected void notifySaveProperty()
	{
		this.notifyToListener( SGDrawingWindow.NOTIFY_SAVE_PROPERTY );
	}

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

		// dispose the window
		this.dispose();

		return true;
	}



	/**
	 * 
	 */
	public static final String NOTIFY_EXIT = "exit";


	/**
	 * 
	 * @return
	 */
	protected void notifyExit()
	{
		this.notifyToListener( SGDrawingWindow.NOTIFY_EXIT );
	}




	/**
	 * 
	 */
	public static final String NOTIFY_UPGRADE = "upgrade the latest version";


	/**
	 * 
	 */
	protected void notifyUpgrade()
	{
		this.notifyToListener( SGDrawingWindow.NOTIFY_UPGRADE );
	}



	/**
	 * 
	 */
	public static final String NOTIFY_SHOW_CHANGE_LOG = "show the change log";


	/**
	 * 
	 */
	protected void notifyChangeLog()
	{
		this.notifyToListener( SGDrawingWindow.NOTIFY_SHOW_CHANGE_LOG );
	}


	/**
	 * 
	 */
	public static final String NOTIFY_SET_PROXY = "set proxy";

	
	/**
	 * 
	 */
	protected void notifySetProxy()
	{
		this.notifyToListener( SGDrawingWindow.NOTIFY_SET_PROXY );
	}
	

	/**
	 * 
	 *
	 */
	protected void updateDataItem()
	{
		this.updateDeleteItem();
		this.updateMoveDataItems();
	}



	/**
	 * 
	 * @return
	 */
	private void updateDeleteItem()
	{
		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;
			}
		}
		
		JMenuItem item = this.getMenuItem( MENU_EDIT, MENUCMD_DELETE );
		if( item!=null )
		{
			item.setEnabled( eff );
		}

	}

	

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

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

		final JMenuItem plus = this.getMenuItem( grid, MENUCMD_PLUS_GRID );
		if( plus==null )
		{
			throw new Error();
		}
		final JMenuItem minus = this.getMenuItem( grid, MENUCMD_MINUS_GRID );
		if( minus==null )
		{
			throw new Error();
		}
		final JMenuItem visible = this.getMenuItem( grid, MENUCMD_GRID_VISIBLE );
		if( visible==null )
		{
			throw new Error();
		}
		JCheckBoxMenuItem chkVisible = (JCheckBoxMenuItem)visible;
		chkVisible.setSelected( this.mGridVisibleFlag );

		boolean plusFlag = false;
		boolean minusFlag = false;
		if( this.mGridVisibleFlag )
		{
			final float interval = this.mGridInterval*SGIConstants.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( MENU_LAYOUT );

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

		final JRadioButtonMenuItem portrait
			= (JRadioButtonMenuItem)this.getMenuItem( paper, MENUCMD_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( MENU_LAYOUT );
		final int mag = (int)( this.getMagnificationPercent() );

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

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

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

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

		final JMenuItem defaultZoom = this.getMenuItem( zoom, MENUCMD_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 );

	}



	/**
	 * 
	 * @return
	 */
	private void updateMoveDataItems()
	{
		// Data
		boolean flagFrontBack = false;
		ArrayList list = this.getVisibleFigureListFromMap();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			SGIGraphElement graph = figure.getGraphElement();

			final int visibleDataNum = graph.getVisibleDataNumber();
			if( visibleDataNum==0 )
			{
				continue;
			}

			final int selectedDataNum = graph.getSelectedDataNumber();

			if( selectedDataNum>0 && selectedDataNum<visibleDataNum )
			{
				flagFrontBack = true;
			}
				
		}

		JMenu menu = this.getMenuFromMenuBar( MENU_ARRANGE );
		if( menu!=null )
		{
			this.getMenuItem( MENU_ARRANGE, MENUCMD_MOVE_SELECTED_DATA_TO_FRONT ).setEnabled(flagFrontBack);
			this.getMenuItem( MENU_ARRANGE, MENUCMD_MOVE_SELECTED_DATA_TO_BACK ).setEnabled(flagFrontBack);
		}

	}



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

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


		//
		// menu bar
		//

		if( command.equals(MENUCMD_EXIT) )
		{
			this.notifyExit();
		}
		else if( command.equals(MENUCMD_CREATE_NEW_WINDOW) )
		{
			this.notifyOpen();
		}
		else if( command.equals(MENUCMD_CLOSE_WINDOW) )
		{
			this.closeWindow();
		}
		else if( command.equals(MENUCMD_DRAW_GRAPH) )
		{
			this.notifyAddData();
		}
		else if( command.equals(MENUCMD_LOAD_PROPERTY) )
		{
			this.notifyLoadProperty();
		}
		else if( command.equals(MENUCMD_SAVE_PROPERTY) )
		{
			this.mCreatePropertyFileOnFocusedFlag = false;
			this.notifySaveProperty();
		}
		else if( command.equals(MENUCMD_EXPORT_AS_IMAGE) )
		{
			this.export();
		}
		else if( command.equals(MENUCMD_PRINT) )
		{
/*
			PrintJob pj = getToolkit().getPrintJob(this, "print test", (Properties)null);
			if ( pj!=null )
			{
				Graphics g = pj.getGraphics();

final float ratio = SGConstants.CM_POINT_RATIO;
int x = (int)(5.0/ratio);
int y = (int)(5.0/ratio);
int w = (int)(10.0/ratio);
int h = (int)(15.0/ratio);
g.drawRect(x,y,w,h);
				g.dispose();
				pj.end();
			}
*/

		}
		else if( command.equals( MENUCMD_PREVIEW ) )
		{

			
		}
		else if( command.equals( MENUCMD_DELETE ) )
		{
			this.hideSelectedObjects();
/*
			ArrayList list = this.getVisibleFigureListFromMap();
			for( int ii=0; ii<list.size(); ii++ )
			{
				SGFigure figure = (SGFigure)list.get(ii);
				SGIGraphElement graph = figure.getGraphElement();
				graph.hideSelectedData();
			}
*/			this.notifyToRoot();
			this.updateDataItem();
		}
		else if( command.equals( MENUCMD_MOVE_SELECTED_DATA_TO_FRONT ) )
		{
			ArrayList list = this.getVisibleFigureListFromMap();
			for( int ii=0; ii<list.size(); ii++ )
			{
				SGFigure figure = (SGFigure)list.get(ii);
				SGIGraphElement graph = figure.getGraphElement();
				graph.moveSelectedDataToFront();
			}
			this.notifyToRoot();
			this.updateDataItem();
		}
		else if( command.equals( MENUCMD_MOVE_SELECTED_DATA_TO_BACK ) )
		{
			ArrayList list = this.getVisibleFigureListFromMap();
			for( int ii=0; ii<list.size(); ii++ )
			{
				SGFigure figure = (SGFigure)list.get(ii);
				SGIGraphElement graph = figure.getGraphElement();
				graph.moveSelectedDataToBack();
			}
			this.notifyToRoot();
			this.updateDataItem();
		}
		else if( command.equals( MENUCMD_UNDO ) )
		{
			this.onUndo();
		}
		else if( command.equals( MENUCMD_REDO ) )
		{
			this.onRedo();
		}
		else if( command.equals( MENUCMD_PAPER_A4_SIZE )
			|| command.equals( MENUCMD_PAPER_B5_SIZE )
			|| command.equals( MENUCMD_PAPER_USLETTER_SIZE ) )
		{

			MediaSize size = null;
			if( command.equals( MENUCMD_PAPER_A4_SIZE ) )
			{
				size = MediaSize.ISO.A4;
			}
			else if( command.equals( MENUCMD_PAPER_B5_SIZE ) )
			{
				size = MediaSize.ISO.B5;
			}
			else if( command.equals( MENUCMD_PAPER_USLETTER_SIZE ) )
			{
				size = MediaSize.NA.LETTER;
			}

			this.onPaperSizeChanged( size );
		}
		else if( command.equals( MENUCMD_PAPER_PORTRAIT )
			|| command.equals( MENUCMD_PAPER_LANDSCAPE ) )
		{
			this.mPaperPortraitFlag = ( command.equals(MENUCMD_PAPER_PORTRAIT) );
			this.updatePaperItems();
		}
		else if( command.equals( MENUCMD_BOUNDING_BOX ) )
		{
			this.setBoundigBox();
		}
		else if( command.equals( MENUCMD_PAPER_USER_CUSTOMIZE ) )
		{
			this.showPropertyDialog();
		}
		else if( command.equals( MENUCMD_AUTO_ARRANGEMENT ) )
		{
			this.onFiguresAligned();
		}
		else if( command.equals( MENUCMD_GRID_VISIBLE ) )
		{
			this.mGridVisibleFlag = !this.mGridVisibleFlag;
			this.getContentPane().repaint();
			this.updateGridItems();

			this.setChanged(true);
			this.notifyToRoot();
		}
		else if( command.equals( MENUCMD_PLUS_GRID ) )
		{
			final float value = this.mGridInterval*SGIConstants.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( MENUCMD_MINUS_GRID ) )
		{
			final float value = this.mGridInterval*SGIConstants.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( MENUCMD_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( MENUCMD_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( MENUCMD_DEFAULT_ZOOM ) )
		{
			this.setDefaultZoom();
		}
		else if( command.equals( MENUCMD_ZOOM_WAY_OUT ) )
		{
			final int[] array = SGDrawingWindow.MAGNIFICATION_ARRAY;
			final int mag = array[array.length-1];
			this.setZoom( new Integer( mag ) );
		}
		else if( command.equals( MENUCMD_AUTO_ZOOM ) )
		{
			this.zoomWithBoundingBox();
		}
		else if( command.equals( MENUCMD_LOCK ) )
		{
			this.mLockFigureFlag = !this.mLockFigureFlag;
			this.updateLockItems();
		}
		else if( command.equals( MENUCMD_UPGRADE ) )
		{
			this.notifyUpgrade();
		}
		else if( command.equals( MENUCMD_CHANGE_LOG ) )
		{
			this.notifyChangeLog();
		}
		else if( command.equals( MENUCMD_PROXY ) )
		{
			this.notifySetProxy();
		}
		else if( command.equals( MENUCMD_ABOUT ) )
		{
			this.onAbout();
		}


		// menus for insert
		ArrayList insertItemList = this.getMenuItemList( MENU_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.notifyOpen();
		}


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

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


		// 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( MENU_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.export();
		}


		//
		if( source.equals( this.mSavePropertyButton ) )
		{
			this.mCreatePropertyFileOnFocusedFlag = false;
			this.notifySaveProperty();
		}


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


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

	}



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

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

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

		if( auto.isSelected() )
		{
			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;
	}



	/**
	 * 
	 * @return
	 */
	private boolean onAbout()
	{
		JDialog dg = this.mAboutDialog;

		final int width = dg.getWidth();
		final int height = dg.getHeight();

		final int x = this.getX() + this.getWidth()/2 - width/2;
		final int y = this.getY() + this.getHeight()/2 - height/2;

		dg.setLocation(x,y);

		dg.setVisible(true);

		return true;
	}



	/**
	 * 
	 * @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(
				MENU_LAYOUT, MENUCMD_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
	 */
	protected boolean updatePaperRect()
	{
		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.updateFigureRect();
		}
		this.updatePaperRect();


		// aligns figures
		if( this.alignFiguresByGraphArea() == 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.mClientRect;

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

			// 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
		final float w = width*this.mMagnification;
		final float h = height*this.mMagnification;
		this.setPaperSize( w, h );

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

		// ダイアログからプロパティを取得して設定
		final boolean flag = this.setPropertiesFromDialog();
		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()
	{
		this.setPropertiesFromDialog();
		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*SGIConstants.CM_POINT_RATIO );
		dg.setWindowHeight( this.mPaperSize.y*SGIConstants.CM_POINT_RATIO );

		dg.setWindowGridVisible( this.getGridVisible() );
		dg.setWindowGridLinesInterval( this.mGridInterval*SGIConstants.CM_POINT_RATIO );
		dg.setWindowGridLinesWidth( this.mGridLineWidth );

		dg.setWindowBackgroundColor( this.mBackgroundColor );

		dg.setWindowGridLinesColor( this.mGridLineColor );

		return true;

	}



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

		// 
		this.updateClientRect();

		//
		this.setScrollBarValue();


		//
//		this.drawBackAllVisibleFigures();

		//
		this.zoomWithBoundingBox();

		//
		this.updateGridItems();


		return true;
	}



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

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

		// horizontal

		this.fitClientRectToBBRect(true);

		if( SGUtility.isRectContains(
			this.getViewportBounds(), this.getBoundingBox(), true ) )
		{
			this.fitClientRectToVPRect(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.setClientOrigin(
				(float)( cRect.getX() + diff ),
				(float)cRect.getY()
			);


		}
				



		// vertical

		this.fitClientRectToBBRect(false);

		if( SGUtility.isRectContains(
			this.getViewportBounds(), this.getBoundingBox(), false ) )
		{
			this.fitClientRectToVPRect(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.setClientOrigin(
				(float)cRect.getX(),
				(float)( cRect.getY() + diff )
			);


		}


		//
		this.setScrollBarValue();


		//
		this.setEnableScrollBars();


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


		return true;

	}



	/**
	 * 
	 * @return
	 */
	protected boolean updateClientRectNew()
	{

		// horizontal
		this.updateClientRect(true);


		// vertical
		this.updateClientRect(false);


		//
		this.setScrollBarValue();


		//
		this.setEnableScrollBars();


		return true;
	}



	/**
	 * 
	 * @param dirFlag
	 * @return
	 */
	protected boolean updateClientRect( final boolean dirFlag )
	{

		//
		// 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.
		//


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

/*
		// vp contains bb
		final boolean vp_bbFlag = SGUtility.isRectContains( vpRect, bbRect, dirFlag );
		if( vp_bbFlag )
		{
//			this.fitClientRectToVPRect( dirFlag );
			this.fitClientRectToBBRect( dirFlag );
		}
		else
		{
//System.out.println("dirFlag="+dirFlag);
//System.out.println("vpbbFlag="+vpbbFlag);

			final double bbStart = SGUtility.getRectStart( bbRect, dirFlag );
			final double bbEnd = SGUtility.getRectEnd( bbRect, dirFlag );
			final double vpStart = SGUtility.getRectStart( vpRect, dirFlag );
			final double vpEnd = SGUtility.getRectEnd( vpRect, dirFlag );
			final double cStart = SGUtility.getRectStart( cRect, dirFlag );
			final double cEnd = SGUtility.getRectEnd( cRect, dirFlag );

			final boolean vp_bbStart = SGUtility.isRectContains( vpRect, bbStart, dirFlag );
			final boolean vp_bbEnd = SGUtility.isRectContains( vpRect, bbEnd, dirFlag );

			final double bbWidth = SGUtility.getRectSize( bbRect, dirFlag );
			SGUtility.setRectSize( this.mClientRect, bbWidth, dirFlag );

			if( vp_bbStart && !vp_bbEnd )
			{
				SGUtility.setRectStart( this.mClientRect, vpStart, dirFlag );
			}
			else if( !vp_bbStart && vp_bbEnd )
			{
				SGUtility.setRectEnd( this.mClientRect, vpEnd, dirFlag );
			}

		}
*/

		this.fitClientRectToBBRect( dirFlag );


		return true;

	}




	private boolean fitClientRectToBBRect( final boolean flag )
	{
		Rectangle2D bbRect = this.getBoundingBox();
		if( bbRect==null )
		{
			return false;
		}

		Rectangle2D cRect = this.mClientRect;

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

		return true;
	}


	private boolean fitClientRectToVPRect( final boolean flag )
	{
		Rectangle2D vpRect = this.getViewportBounds();
		if( vpRect==null )
		{
			return false;
		}

		Rectangle2D cRect = this.mClientRect;

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

		return true;
	}





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

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

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

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

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

		return true;
	}



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

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

		WindowProperties wp = (WindowProperties)p;

		final Float w = wp.getPaperWidth();
		final Float h = wp.getPaperHeight();
		if( w==null || h==null )
		{
			return false;
		}
		this.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.mBackgroundColor );
		p.setGridColor( this.mGridLineColor );
		p.setGridVisible( this.mGridVisibleFlag );
		p.setGridInterval( this.mGridInterval );
		p.setGridLineWidth( this.mGridLineWidth );
		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()
	{

/*
		final WindowProperties p = new WindowProperties();

		final SGWindowDialog dg = (SGWindowDialog)this.mDialog;

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

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

//System.out.println(p);

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

		return p;

	}





	/**
	 * フォーカスされている全フィギュアに対してドラッグ矩形の設定を行う
	 * @return
	 */
	protected boolean setDraggingRectOfFocusedFigures()
	{
		ArrayList list = this.getFocusedObjectsList();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.setRubberBandRect();
		}
		return true;
	}



	/**
	 * 
	 * @return
	 */
	public Rectangle2D getClientRect()
	{
		return this.mClientRect;
	}




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



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



public void dumpClientRect()
{
	Rectangle2D rect = this.mClientRect;
	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_);
}



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



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



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



	/**
	 * 
	 * @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 SGTuple2f dim = this.getViewportSize();
		final float w = dim.x;
		final float h = dim.y;
		Rectangle2D rect = new Rectangle2D.Float( left, top, w, h );
		return rect;
	}



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

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


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


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




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

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


		return figureArray;
	}





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

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

	}




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

		this.updateGridItems();

		return true;
	}



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

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

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

		this.clearAllFocusedObjectsInFigures();
		this.updateUndoItems();
		this.updateItemsByFigureNumbers();
		this.updateDataItem();


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

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

		return true;

	}



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

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

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

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

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


		// increment
		this.mCurrentStateCounter++;

		this.clearAllFocusedObjectsInFigures();
		this.updateUndoItems();
		this.updateItemsByFigureNumbers();
		this.updateDataItem();


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


		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( MENU_EDIT, MENUCMD_UNDO );
			if( this.mCurrentStateCounter == 0 )
			{
				item.setEnabled(false);
			}
			else
			{
				item.setEnabled(true);
			}
		}


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

		return true;
	}



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



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




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

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


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

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

			final JMenuItem close = new JMenuItem( MENUCMD_CLOSE_WINDOW );
			close.setActionCommand(MENUCMD_CLOSE_WINDOW);
			close.addActionListener(this);
			close.setAccelerator(
				KeyStroke.getKeyStroke(KeyEvent.VK_W, ActionEvent.CTRL_MASK));
			close.setMnemonic( KeyEvent.VK_W );
			menuFile.add(close);

			menuFile.addSeparator();

			final JMenuItem drawGraph = new JMenuItem( MENUCMD_DRAW_GRAPH );
			drawGraph.setActionCommand(MENUCMD_DRAW_GRAPH);
			drawGraph.addActionListener(this);
			drawGraph.setAccelerator(
				KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK));
			drawGraph.setMnemonic( KeyEvent.VK_D );
			menuFile.add(drawGraph);

			menuFile.addSeparator();

			final JMenuItem loadProperty = new JMenuItem( MENUCMD_LOAD_PROPERTY );
			loadProperty.setActionCommand(MENUCMD_LOAD_PROPERTY);
			loadProperty.addActionListener(this);
			loadProperty.setMnemonic( KeyEvent.VK_L );
			menuFile.add(loadProperty);

			final JMenuItem saveProperty = new JMenuItem( MENUCMD_SAVE_PROPERTY );
			saveProperty.setActionCommand(MENUCMD_SAVE_PROPERTY);
			saveProperty.addActionListener(this);
			saveProperty.setMnemonic( KeyEvent.VK_S );
			menuFile.add(saveProperty);

			menuFile.addSeparator();

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

			menuFile.addSeparator();

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

			final JMenuItem preview = new JMenuItem( MENUCMD_PREVIEW );
			preview.setActionCommand(MENUCMD_PREVIEW);
			preview.addActionListener(this);
			preview.setMnemonic( KeyEvent.VK_V );
			menuFile.add(preview);

			menuFile.addSeparator();
*/

			final JMenuItem exit = new JMenuItem( MENUCMD_EXIT );
			exit.setActionCommand(MENUCMD_EXIT);
			exit.addActionListener(this);
			exit.setAccelerator(
				KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.CTRL_MASK));
			exit.setMnemonic( KeyEvent.VK_X );
			menuFile.add(exit);

		}


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

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

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

			menuEdit.addSeparator();

/*
			final JMenuItem cut = new JMenuItem( MENUCMD_CUT );
			cut.setActionCommand(MENUCMD_CUT);
			cut.addActionListener(this);
			cut.setAccelerator(
				KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.CTRL_MASK));
			cut.setMnemonic( KeyEvent.VK_T );
			menuEdit.add(cut);
			cut.setEnabled(false);

			final JMenuItem copy = new JMenuItem( MENUCMD_COPY );
			copy.setActionCommand(MENUCMD_COPY);
			copy.addActionListener(this);
			copy.setAccelerator(
				KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK));
			copy.setMnemonic( KeyEvent.VK_C );
			menuEdit.add(copy);
			copy.setEnabled(false);

			final JMenuItem paste = new JMenuItem( MENUCMD_PASTE );
			paste.setActionCommand(MENUCMD_PASTE);
			paste.addActionListener(this);
			paste.setAccelerator(
				KeyStroke.getKeyStroke(KeyEvent.VK_V, ActionEvent.CTRL_MASK));
			paste.setMnemonic( KeyEvent.VK_P );
			menuEdit.add(paste);
			paste.setEnabled(false);

			menuEdit.addSeparator();
*/

			final JMenuItem delete = new JMenuItem( MENUCMD_DELETE );
			delete.setActionCommand(MENUCMD_DELETE);
			delete.addActionListener(this);
			delete.setAccelerator(
				KeyStroke.getKeyStroke( KeyEvent.VK_DELETE, 0 ) );
			delete.setMnemonic( KeyEvent.VK_D );
			menuEdit.add(delete);
			delete.setEnabled(false);

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

			final JMenuItem duplicate = new JMenuItem( MENUCMD_DUPLICATE, KeyEvent.VK_I );
			duplicate.setActionCommand(MENUCMD_DUPLICATE);
			duplicate.addActionListener(this);
			duplicate.setAccelerator(
				KeyStroke.getKeyStroke(KeyEvent.VK_D, ActionEvent.CTRL_MASK));
			duplicate.setMnemonic( KeyEvent.VK_I );
			menuEdit.add(duplicate);
			duplicate.setEnabled(false);
*/

		}


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

			// label
			final JMenuItem label = new SGToggleMenuItem( MENUCMD_INSERT_LABEL );
			label.setActionCommand( MENUCMD_INSERT_LABEL );
			label.addActionListener(this);
			label.setMnemonic( KeyEvent.VK_L );
			menuInsert.add(label);

			// significant difference
			final JMenuItem sigdiff = new SGToggleMenuItem( MENUCMD_INSERT_SIG_DIFF_SYMBOL );
			sigdiff.setActionCommand( MENUCMD_INSERT_SIG_DIFF_SYMBOL );
			sigdiff.addActionListener(this);
			sigdiff.setMnemonic( KeyEvent.VK_D );
			menuInsert.add(sigdiff);

			// axis break
			final JMenuItem axisBreak = new SGToggleMenuItem( MENUCMD_INSERT_AXIS_BREAK_SYMBOL );
			axisBreak.setActionCommand( MENUCMD_INSERT_AXIS_BREAK_SYMBOL );
			axisBreak.addActionListener(this);
			axisBreak.setMnemonic( KeyEvent.VK_B );
			menuInsert.add(axisBreak);

			// timing line
			final JMenuItem timingLine = new SGToggleMenuItem( MENUCMD_INSERT_TIMING_LINE );
			timingLine.setActionCommand( MENUCMD_INSERT_TIMING_LINE );
			timingLine.addActionListener(this);
			timingLine.setMnemonic( KeyEvent.VK_T );
			menuInsert.add(timingLine);

		}


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

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

				final JMenuItem a4 = new JMenuItem(MENUCMD_PAPER_A4_SIZE);
				a4.setActionCommand(MENUCMD_PAPER_A4_SIZE);
				a4.addActionListener(this);
				a4.setMnemonic( KeyEvent.VK_4 );
				menuPaperSize.add(a4);

				final JMenuItem b5 = new JMenuItem(MENUCMD_PAPER_B5_SIZE);
				b5.setActionCommand(MENUCMD_PAPER_B5_SIZE);
				b5.addActionListener(this);
				b5.setMnemonic( KeyEvent.VK_5 );
				menuPaperSize.add(b5);

				final JMenuItem letter = new JMenuItem(MENUCMD_PAPER_USLETTER_SIZE);
				letter.setActionCommand(MENUCMD_PAPER_USLETTER_SIZE);
				letter.addActionListener(this);
				letter.setMnemonic( KeyEvent.VK_U );
				menuPaperSize.add(letter);

				menuPaperSize.addSeparator();

				final JRadioButtonMenuItem portrait= new JRadioButtonMenuItem(MENUCMD_PAPER_PORTRAIT);
				portrait.setActionCommand(MENUCMD_PAPER_PORTRAIT);
				portrait.addActionListener(this);
				portrait.setMnemonic( KeyEvent.VK_P );
				menuPaperSize.add( portrait );

				final JRadioButtonMenuItem landscape= new JRadioButtonMenuItem(MENUCMD_PAPER_LANDSCAPE);
				landscape.setActionCommand(MENUCMD_PAPER_LANDSCAPE);
				landscape.addActionListener(this);
				landscape.setMnemonic( KeyEvent.VK_L );
				menuPaperSize.add( landscape );

				ButtonGroup bGroup = new ButtonGroup();
				bGroup.add(portrait);
				bGroup.add(landscape);

				menuPaperSize.addSeparator();

				final JMenuItem bbFigure = new JMenuItem(MENUCMD_BOUNDING_BOX);
				bbFigure.setActionCommand( MENUCMD_BOUNDING_BOX );
				bbFigure.addActionListener(this);
				bbFigure.setMnemonic( KeyEvent.VK_B );
				menuPaperSize.add( bbFigure );

				final JMenuItem userCustomize = new JMenuItem(MENUCMD_PAPER_USER_CUSTOMIZE);
				userCustomize.setActionCommand( MENUCMD_PAPER_USER_CUSTOMIZE );
				userCustomize.addActionListener(this);
				userCustomize.setMnemonic( KeyEvent.VK_C );
				menuPaperSize.add( userCustomize );
			}

			menuLayout.addSeparator();


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

				final JMenuItem plusGrid = new JMenuItem(MENUCMD_PLUS_GRID);
				plusGrid.setActionCommand(MENUCMD_PLUS_GRID);
				plusGrid.addActionListener(this);
				plusGrid.setAccelerator(
					KeyStroke.getKeyStroke(KeyEvent.VK_I, ActionEvent.SHIFT_MASK + ActionEvent.ALT_MASK)
				);
				plusGrid.setMnemonic( KeyEvent.VK_P );
				menuGrid.add(plusGrid);

				final JMenuItem minusGrid = new JMenuItem(MENUCMD_MINUS_GRID);
				minusGrid.setActionCommand(MENUCMD_MINUS_GRID);
				minusGrid.addActionListener(this);
				minusGrid.setAccelerator(
					KeyStroke.getKeyStroke(KeyEvent.VK_D, ActionEvent.SHIFT_MASK + ActionEvent.ALT_MASK)
				);
				minusGrid.setMnemonic( KeyEvent.VK_M );
				menuGrid.add(minusGrid);

				final JCheckBoxMenuItem visibleGrid = new JCheckBoxMenuItem(MENUCMD_GRID_VISIBLE);
				visibleGrid.setActionCommand(MENUCMD_GRID_VISIBLE);
				visibleGrid.addActionListener(this);
				visibleGrid.setAccelerator(
					KeyStroke.getKeyStroke( KeyEvent.VK_G, ActionEvent.SHIFT_MASK + ActionEvent.ALT_MASK)
				);
				visibleGrid.setMnemonic( KeyEvent.VK_V );
				menuGrid.add(visibleGrid);
/*
				final JCheckBoxMenuItem snapToGrid = new JCheckBoxMenuItem(MENUCMD_SNAP_TO_GRID);
				snapToGrid.setActionCommand(MENUCMD_SNAP_TO_GRID);
				snapToGrid.addActionListener(this);
				snapToGrid.setAccelerator(
					KeyStroke.getKeyStroke( KeyEvent.VK_S, ActionEvent.SHIFT_MASK + ActionEvent.ALT_MASK )
				);
				snapToGrid.setMnemonic( KeyEvent.VK_S );
				menuGrid.add(snapToGrid);
*/			}

			menuLayout.addSeparator();



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

				final JMenuItem zoomIn = new JMenuItem(MENUCMD_ZOOM_IN);
				zoomIn.setActionCommand(MENUCMD_ZOOM_IN);
				zoomIn.addActionListener(this);
				zoomIn.setAccelerator(
					KeyStroke.getKeyStroke( KeyEvent.VK_Z, ActionEvent.ALT_MASK + ActionEvent.SHIFT_MASK )
				);
				zoomIn.setMnemonic( KeyEvent.VK_I );
				menuZoom.add(zoomIn);

				final JMenuItem zoomOut = new JMenuItem(MENUCMD_ZOOM_OUT);
				zoomOut.setActionCommand(MENUCMD_ZOOM_OUT);
				zoomOut.addActionListener(this);
				zoomOut.setAccelerator(
					KeyStroke.getKeyStroke( KeyEvent.VK_O, ActionEvent.ALT_MASK + ActionEvent.SHIFT_MASK )
				);
				zoomOut.setMnemonic( KeyEvent.VK_O );
				zoomOut.setDisplayedMnemonicIndex(5);
				menuZoom.add(zoomOut);

				final JMenuItem defaultZoom = new JMenuItem(MENUCMD_DEFAULT_ZOOM);
				defaultZoom.setActionCommand(MENUCMD_DEFAULT_ZOOM);
				defaultZoom.addActionListener(this);
				defaultZoom.setMnemonic( KeyEvent.VK_D );
				menuZoom.add(defaultZoom);

				final JMenuItem zoomWayOut = new JMenuItem(MENUCMD_ZOOM_WAY_OUT);
				zoomWayOut.setActionCommand(MENUCMD_ZOOM_WAY_OUT);
				zoomWayOut.addActionListener(this);
				zoomWayOut.setMnemonic( KeyEvent.VK_W );
				menuZoom.add(zoomWayOut);

				final JCheckBoxMenuItem autoZoom = new JCheckBoxMenuItem(MENUCMD_AUTO_ZOOM);
				autoZoom.setActionCommand(MENUCMD_AUTO_ZOOM);
				autoZoom.addActionListener(this);
				autoZoom.setMnemonic( KeyEvent.VK_A );
				menuZoom.add(autoZoom);

			}

			menuLayout.addSeparator();

			final JCheckBoxMenuItem lock = new JCheckBoxMenuItem(MENUCMD_LOCK);
			lock.setActionCommand( MENUCMD_LOCK );
			lock.addActionListener(this);
			lock.setMnemonic( KeyEvent.VK_O );
			menuLayout.add( lock );

		}



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

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

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

			menuArrange.addSeparator();

			final JMenuItem alignFigures = new JMenuItem(MENUCMD_AUTO_ARRANGEMENT);
			alignFigures.setActionCommand( MENUCMD_AUTO_ARRANGEMENT );
			alignFigures.addActionListener(this);
			alignFigures.setMnemonic( KeyEvent.VK_R );
			menuArrange.add( alignFigures );

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

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

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

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

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

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

			}
*/

		}



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

			// upgrade
			final JMenuItem upgrade = new JMenuItem(MENUCMD_UPGRADE);
			upgrade.setActionCommand( MENUCMD_UPGRADE );
			upgrade.addActionListener(this);
			upgrade.setMnemonic( KeyEvent.VK_U );
			menuHelp.add(upgrade);

			menuHelp.addSeparator();

			// change log
			final JMenuItem changeLog = new JMenuItem(MENUCMD_CHANGE_LOG);
			changeLog.setActionCommand( MENUCMD_CHANGE_LOG );
			changeLog.addActionListener(this);
			changeLog.setMnemonic( KeyEvent.VK_C );
			menuHelp.add( changeLog );

			menuHelp.addSeparator();

			// proxy
			final JMenuItem proxy = new JMenuItem(MENUCMD_PROXY);
			proxy.setActionCommand( MENUCMD_PROXY );
			proxy.addActionListener(this);
			proxy.setMnemonic( KeyEvent.VK_P );
			menuHelp.add( proxy );

			menuHelp.addSeparator();

			// about
			final JMenuItem about = new JMenuItem(MENUCMD_ABOUT);
			about.setActionCommand(MENUCMD_ABOUT);
			about.addActionListener(this);
			about.setMnemonic( KeyEvent.VK_A );
			menuHelp.add(about);
		}


		return true;

	}



	/**
	 * 
	 */
	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 ExportDialog mExportDialog = new ExportDialog();



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

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

		ArrayList list = this.getVisibleFigureListFromLayer();


		// hide anchors temporarily
		this.setSelectionSymbolsVisible( false );

		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.setSymbolsVisibleAroundAllObjects( false );
		}


		//
		Rectangle2D cRect = this.mClientRect;
		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 );
		}



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


		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 the location and the size of preview dialog
		Insets insets = this.mPreviewDialog.getInsets();
		final int width = (int)this.mPaperSize.x;
		final int height = (int)this.mPaperSize.y;
		this.mPreviewDialog.setSize(
			width + insets.left + insets.right,
			height + insets.top + insets.bottom	);
		this.mPreviewDialog.setLocation( this.getLocation() );
		Rectangle2D rectView = new Rectangle2D.Float( 0.0f, 0.0f, width, height );


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


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


		// show the preview dialog
		this.mPreviewDialog.setVisible(true);


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


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



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

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

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

		// アンカーを再描画
		this.setSelectionSymbolsVisible( true );

		ArrayList fList = this.getFocusedObjectsList();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGFigure figure = (SGFigure)list.get(ii);
			figure.setSymbolsVisibleAroundAllObjects( fList.contains(figure) );
		}
		
		return true;

	}





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

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

		this.mPreviewDialog.setVisible(false);

		return true;

	}












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





	/**
	 * 
	 * @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 createElementForFocusedFigures( final Document document )
	{
		Element element = document.createElement( SGDrawingWindow.TAG_NAME_WINDOW );
		if( this.writePropertyForFocusedFigures( element ) == false )
		{
			return null;
		}
		return element;
	}


	
	/**
	 * 
	 * @return
	 */
	public boolean createDOMTree( Document document )
	{
		boolean flag;
		if( this.mCreatePropertyFileOnFocusedFlag == false )
		{
			flag = this.createDOMTreeForAllFigures( document );
		}
		else
		{
			flag = this.createDOMTreeForFocusedFigures( document );
		}
		return flag;
	}
	
	
	
	/**
	 * 
	 */
	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;
	}

	
	
	
	/**
	 * 
	 */
	private boolean mCreatePropertyFileOnFocusedFlag = false;

	
	/**
	 * 
	 * @return
	 */
	boolean createPropertyFileFromFocusedFigures()
	{
		this.mCreatePropertyFileOnFocusedFlag = true;
		this.notifySaveProperty();
		return true;
	}
	
	

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

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

		
		// write properties of the window
		Element windowElement = this.createElementForFocusedFigures( 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.createElementForFocused( document );
			if( el == null )
			{
				return false;
			}
			windowElement.appendChild( el );
		}

		return true;
	}



	public boolean writePropertyForFocusedFigures( 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.mGridVisibleFlag ) );
		element.setAttribute(
			KEY_GRID_INTERVAL,
			Float.toString( this.mGridInterval*SGIConstants.CM_POINT_RATIO )
				+ SGUtilityNumber.cm );
		element.setAttribute(
			KEY_GRID_LINE_WIDTH,
			Float.toString( this.mGridLineWidth )
				+ SGUtilityNumber.pt );

		// Color
		element.setAttribute(
			KEY_BACKGROUND_COLOR,
			SGUtilityText.getColorString( this.getBackgroundColor() ) );
		element.setAttribute(
			KEY_GRID_COLOR,
			SGUtilityText.getColorString( this.mGridLineColor ) );

		return true;
	}
	
	
	



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


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

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

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

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

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

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

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

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


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


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

		return true;
	}









//
// 内部クラス
//


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


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

			return true;
		}


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

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

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

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


				// アンカー
				{
					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 Shape anchor = new Ellipse2D.Float(
				x-0.5f*mAnchorSize, y-0.5f*mAnchorSize, mAnchorSize, mAnchorSize
			);


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

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

		}



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

			g2d.setPaint(Color.BLACK);


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


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

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

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

		}

		
	}




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

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


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

			return true;
		}


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


			// get the rectangle of paper
			Rectangle2D pRect = getPaperRect();
			Rectangle2D vpRect = getViewportBounds();


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


			// draw the grid lines
			if( mGridVisibleFlag )
			{

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



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


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


				// vertical lines
				int cnt = (int)( ( vpRect.getX() - pRect.getX() )/space ) + 1;
				while( true )
				{
					final float x = cnt*space + (float)pRect.getX();

					if( x > vpRect.getX() + vpRect.getWidth() )
					{
						break;
					}

					if( x > pRect.getX() + pRect.getWidth() )
					{
						break;
					}

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

					cnt++;
				}


				// horizontal lines
				cnt = (int)( ( vpRect.getY() - pRect.getY() )/space ) + 1;
				while( true )
				{
					final float y = cnt*space + (float)pRect.getY();

					if( y > vpRect.getY() + vpRect.getHeight() )
					{
						break;
					}

					if( y > pRect.getY() + pRect.getHeight() )
					{
						break;
					}

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

					cnt++;
				}

			}


			// 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() + 10,
				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() + 10, y,
				pRect.getX() + pRect.getWidth() + eWidth/2.0, y
			);
			g2d.draw( line );
*/


/*
g2d.setStroke( new BasicStroke(5) );
g2d.setPaint( Color.RED );
g2d.draw( mClientRect );

g2d.setStroke( new BasicStroke(3) );
g2d.setPaint( Color.BLUE );
g2d.draw( getBoundingBox() );
*/

		}


	}




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

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


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

			return true;
		}


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

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



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

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

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

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


			g2d.setPaint( mRulerLineColor );
			g2d.setStroke
			(
				new BasicStroke
				(
					1.0f,
					BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER
				)
			);
			g2d.setPaint( mRulerBackGroundColor );
			g2d.fill( polygon );

			g2d.setPaint( Color.BLACK );
			g2d.draw( polygon );


			// draw the lines of rulers
			this.drawNumbersAndLines( g2d );


			// corner
			final Rectangle2D rectCorner
				= new Rectangle2D.Float(
					0.0f, 0.0f, RULER_WIDTH, RULER_WIDTH );
			g2d.setPaint( mRulerBackGroundColor );
			g2d.fill( rectCorner );

			g2d.setPaint( mRulerLineColor );
			g2d.draw( rectCorner );


			return true;

		}




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

			g2d.setPaint( mRulerLineColor );

			final Rectangle2D vpRect = getViewportBounds();
			final Rectangle2D cRect = getClientRect();

			final float xScroll = getHScrollValue();
			final float yScroll = getVScrollValue();

			final int rw = getRulerWidth();
			final float hStart = rw + (float)cRect.getX();
			final float vStart = rw + (float)cRect.getY();

			final Line2D line = new Line2D.Float();



			//
			// axis lines
			//

			g2d.setStroke
			(
				new BasicStroke
				(
					mRulerAxisLineWidth,
					BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER
				)
			);

			// horizontal
			{
				final float x1 = RULER_WIDTH;
				final float x2 = this.getWidth();
				final float y = RULER_WIDTH;
				line.setLine( x1, y, x2, y );
				g2d.draw(line);
			}

			// perpendicular
			{
				final float x = RULER_WIDTH;
				final float y1 = RULER_WIDTH;
				final float y2 = this.getHeight();
				line.setLine( x, y1, x, y2 );
				g2d.draw(line);			
			}



			//
			// scale lines and numbers
			//

			g2d.setStroke
			(
				new BasicStroke
				(
					mRulerScaleLineWidth,
					BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER
				)
			);

			g2d.setFont( mRulerFont );


			final float factor = mMagnification/SGIConstants.CM_POINT_RATIO;

			// horizontal
			{

				final ArrayList locationList = new ArrayList();
				float location = 0.0f;
				final int start = (int)( ( vpRect.getX() - cRect.getX() )*SGIConstants.CM_POINT_RATIO/mMagnification );
				int cnt = start;
				while( true )
				{
					location = factor*cnt;
					if( location > cRect.getWidth() )
					{
						break;
					}

					if( location > vpRect.getX() + vpRect.getWidth() - cRect.getX() )
					{
						break;
					}

					locationList.add( new Float(location) );
					cnt++;
				}

				// draw
				for( int ii=0; ii<locationList.size(); ii++ )
				{
					// main
					location = ((Float)locationList.get(ii)).floatValue();
					final float pos = hStart + location;
					line.setLine(
						pos, 0.20f*RULER_WIDTH,
						pos, RULER_WIDTH );
					g2d.draw(line);

					// number
					final Integer num = new Integer( start + ii );
					final int x = (int)( pos + 0.3f*mRulerFontSize );
					final int y = (int)mRulerFontSize + 1;
					g2d.drawString( num.toString(), x, y );

					// sub
					for( int jj=0; jj<4; jj++ )
					{
						final float pos_ = pos + mMagnification*0.2f*(jj+1)*(1.0f/SGIConstants.CM_POINT_RATIO);

						line.setLine(
							pos_, 0.75f*RULER_WIDTH,
							pos_, RULER_WIDTH );
						g2d.draw(line);
					}

				}

			}


			// perpendicular
			{
				final ArrayList locationList = new ArrayList();
				float location = 0.0f;
				final int start = (int)( ( vpRect.getY() - cRect.getY() )*SGIConstants.CM_POINT_RATIO/mMagnification );
				int cnt = start;
				while( true )
				{
					location = factor*cnt;
					if( location > cRect.getHeight() )
					{
						break;
					}

					if( location > vpRect.getY() + vpRect.getHeight() - cRect.getY() )
					{
						break;
					}

					locationList.add( new Float(location) );
					cnt++;
				}

				// draw
				for( int ii=0; ii<locationList.size(); ii++ )
				{

					// main
					location = ((Float)locationList.get(ii)).floatValue();
					final float pos = vStart + location;
					line.setLine(
						0.20f*RULER_WIDTH, pos,
						RULER_WIDTH, pos );
					g2d.draw(line);

					// number
					final Integer num = new Integer(ii+start);
					final int x = (int)( 0.20f*RULER_WIDTH );
					int y = (int)( pos + mRulerFontSize + 1 );
					char[] array = num.toString().toCharArray();
					for( int jj=0; jj<array.length; jj++ )
					{
						Character c = new Character(array[jj]);
						g2d.drawString( c.toString(), x, y );
						y += (int)mRulerFontSize;
					}

					// sub
					for( int jj=0; jj<4; jj++ )
					{
						final float pos_ = pos + mMagnification*0.2f*(jj+1)*(1.0f/SGIConstants.CM_POINT_RATIO);
						line.setLine(
							0.750f*RULER_WIDTH, pos_,
							RULER_WIDTH, pos_ );
						g2d.draw(line);
					}
				}

			}


			return true;
		}


	}




	/**
	 * Preview dialog on exporting to the files.
	 */
	class PreviewDialog extends JDialog
	{
		/**
		 * 
		 */
		protected JLayeredPane mLayeredPane;


		/**
		 * 
		 */
		protected PreviewDialog()
		{
			super();
			this.initComponents();
		}


		/**
		 * 
		 */
		protected PreviewDialog( final Frame owner, final String title )
		{
			super( owner, title );
			this.initComponents();
		}


		/**
		 * 
		 */
		private void initComponents()
		{
			this.mLayeredPane = new JLayeredPane();
			this.mLayeredPane.setOpaque(false);

			this.getContentPane().add( this.mLayeredPane );
			this.setVisible(false);
			this.setResizable(false);
		}

	}





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

	}



}

