📄 mosaiclayout.java
字号:
///////////////////////////////////////////////////////////////
//
// MosaicLayout.java 1.0 97/02/05 Robert Buff buff@cs.nyu.edu
// 1.1 97/06/19 Robert Buff buff@cs.nyu.edu
// 1.2 97/07/10 Robert Buff buff@cs.nyu.edu
// 1.3 97/07/30 Robert Buff buff@cs.nyu.edu
// 1.4 98/01/30 Robert Buff buff@cs.nyu.edu
// 1.5A 06/05/98 Antranig Basman amb26@eng.cam.ac.uk
// !!!!!! represents fixes performed for 1.5A by AMB.
//
// Copyright (c) 1997, 98 Robert Buff. All Rights Reserved.
//
// You may use, copy, modify, and distribute this software
// for NON-COMMERCIAL purposes and without fee provided that
// this copyright notice appears in all copies. If you would
// like to use this software for COMMERCIAL purposes, contact
// the author and we will work something out.
//
// It would also be nice to give credit to the author in the
// Help/About dialog window of any application that uses this
// software.
//
///////////////////////////////////////////////////////////////
//
// This class defines a layout manager that a) organizes its
// components in a hierarchical manner, and b) allows the user
// to resize its components by clicking on and dragging of sashes.
//
// The layout manager mirrors the subdivision of the panel space
// in a tree whose leaf nodes point to the components, and whose
// interior nodes correspond to rectangular grids. The columns
// and rows of each interior grid can be resized by the user by
// dragging the sashes that are inserted between adjacent columns
// and rows.
//
// In addition, the layout manager follows a dynamic resizing
// policy that is activated when the underlying panel changes
// its size. Weights can be assigned to each component; these
// weights, together with the minimum and preferred size of
// the components, determine how the actual size of each
// component changes.
//
// Supporting classes:
//
// MosaicConstraints: its relation to MosaicLayout is similar
// to the relation of GridBagConstraints to GridBagLayout.
// For each component, weights and gravity parameters can
// be specified.
//
// MosaicCoordStack: contains the position that is assigned to
// a component. Basically, a sequence of (column/row)
// pairs whose length corresponds to the level of the
// component in the hierarchy. Describes the path to
// the component in the tree.
//
// MosaicPanel: a subclass of Panel that notifies the layout
// manager of mouse events and paint requests, for it is
// the layout manager's responsibility to draw the sashes
// and handle resize requests delivered by mouse events.
// If the parent of the layout manager is NOT a MosaicPanel,
// the layout manager is still functioning, but does not
// draw sashes any more. The possibility of manually
// rearranging the components is then no longer given.
// The layout manager checks for the type of its parent
// and acts accordingly.
//
// The sashes are painted directly on the parent MosaicPanel,
// without additional components. The look of the sashes comes
// close to the look of sashes in Windows environments. I didn't
// bother to make them look nice on black-and-white monitors.
//
// Resizing is done online - while dragging - by default, but this
// can be switched off if repainting the components is expensive
// (see m_liveDrag).
//
// No component is ever made smaller than its minimum size,
// even if the underlying panel gets smaller. However, components
// can be manually made larger than their preferred size even if
// their assigned weight is zero.
//
// It is possible to create named constraints and load them into
// a dictionary that the layout manager maintains. Later on,
// these constraints can be assigned to any number of components
// by specifying their name in the add( name, comp ) version of
// the add function of the underlying container panel.
//
// In general, the features of the layout manager can be discovered
// best by studying the commented public member functions of the
// class MosaicLayout, listed in the top section of the class
// definition. Other features and strategies are only sparsely
// commented.
//
// The following is an example of how to use MosaicLayout. Note
// that the position of components can be indicated by submitting
// MosaicCoordStack objects directly to the layout manager, or
// by calling the layout manager's setPos() function which
// essentially creates a MosaicCoordStack object for the next
// component that is registered with the add( name, comp )
// function of the underlying panel (you must use the version
// that supplies a name in this case, as the other version
// delays transfering the data to the layout manager, thus
// disrupting the order).
//
// The example without using MosaicCoordStack directly (order
// is crucial):
//
// MosaicPanel m_panel = new MosaicPanel();
// MosaicLayout m_layout = new MosaicLayout();
//
// setLayout( new BorderLayout() );
// add( "Center", m_panel );
// m_panel.setLayout( m_layout );
//
// Button button1 = new Button( "Monday" );
// Button button2 = new Button( "Tuesday" );
// Button button3 = new Button( "Wednesday" );
// Button button4 = new Button( "Thursday" );
// Button button5 = new Button( "Friday" );
// Button button6 = new Button( "Saturday" );
// Button button7 = new Button( "Sunday" );
//
// m_layout.setPos( 0, 0, 0, 0 );
// m_panel.add( "", button1 );
//
// m_layout.setPos( 0, 0, 1, 0, 0, 0 );
// m_panel.add( "", button2 );
//
// m_layout.setPos( 0, 0, 1, 0, 1, 0 );
// m_panel.add( "", button3 );
//
// m_layout.setPos( 0, 0, 1, 0, 0, 1 );
// m_panel.add( "", button4 );
//
// m_layout.setPos( 0, 0, 1, 0, 1, 1 );
// m_panel.add( "", button5 );
//
// m_layout.setPos( 0, 1, 0, 0 );
// m_panel.add( "", button6 );
//
// m_layout.setPos( 0, 1, 1, 0 );
// m_panel.add( "", button7 );
//
// m_layout.setConstraints( button3, new MosaicConstraints(
// MosaicConstraints.CENTER, MosaicConstraints.HORIZONTAL ) );
//
// m_layout.setConstraints( button5, new MosaicConstraints(
// MosaicConstraints.CENTER, MosaicConstraints.HORIZONTAL ) );
//
// The example when MosaicCoordStack is used (the order
// does not matter any more; only the middle section of
// the code is repeated):
//
// m_panel.add( button1 );
// m_panel.add( button2 );
// m_panel.add( button3 );
// m_panel.add( button4 );
// m_panel.add( button5 );
// m_panel.add( button6 );
// m_panel.add( button7 );
//
// MosaicCoordStack c;
//
// c.setPos( 0, 0, 0, 0 );
// m_layout.setCoordStack( button1, c );
// c.setPos( 0, 0, 1, 0, 0, 0 );
// m_layout.setCoordStack( button2, c );
// c.setPos( 0, 0, 1, 0, 1, 0 );
// m_layout.setCoordStack( button3, c );
// c.setPos( 0, 0, 1, 0, 0, 1 );
// m_layout.setCoordStack( button4, c );
// c.setPos( 0, 0, 1, 0, 1, 1 );
// m_layout.setCoordStack( button5, c );
// c.setPos( 0, 1, 0, 0 );
// m_layout.setCoordStack( button6, c );
// c.setPos( 0, 1, 1, 0 );
// m_layout.setCoordStack( button7, c );
//
// No guarantee is made that this code actually does what
// has been described above. This is a first version that
// surely contains bugs.
//
///////////////////////////////////////////////////////////////
//
// History:
//
//
// 1.1 Default cursor is activated in empty tiles.
// layout() is now called recursively for all components.
//
// 1.2 checkPanel() is now called in minimumLayoutSize() and
// preferredLayoutSize. These functions are called before
// layoutContainer() by parent layout managers.
//
// 1.3 After dragging the sashes, the event MOUSE_UP triggers
// a final recursion in the component tree, to determine the
// correct cursor shape. Note, however, that (at least in
// my version of VJ++) the default shape becomes only
// active again after the mouse is moved. Don't know why.
//
// 1.4 Minor bugfix: now calling validate() instead of
// layout() in 1.1.
//
///////////////////////////////////////////////////////////////
package nom.rb.common;
import java.awt.*;
import java.util.*;
import nom.rb.common.MosaicConstraints;
import nom.rb.common.MosaicCoordStack;
import nom.rb.common.MosaicPanel;
///////////////////////////////////////////////////////////////
//
// M o s a i c L a y o u t
//
///////////////////////////////////////////////////////////////
public class MosaicLayout extends Object implements LayoutManager
{
// The layout manager maintains a repository of reusable
// constraint objects, that can be assigned to components
// many times. They are identified by their unique name
// and stored in the following hashtable.
protected Hashtable m_name2Constraints = null;
// Each component is represented by a leaf node in the tree
// that mirrors the hierarchy. The leaf node that corresponds
// to a particular component can be found in this hashtable.
protected Hashtable m_comp2Node = null;
// Whenever a MosaicCoordStack object is passed to the layout
// manager, it is copied and the column counter at its lowest
// level is advanced to the next column to the right. When a
// new component is registered, this generated MosaicCoordStack
// object is taken as its default position.
protected MosaicCoordStack m_lastCoordStack = null;
protected MosaicCoordStack m_nextCoordStack = null;
// This is the root node of the hierarchy tree.
protected MosaicNode m_root = null;
// If the parent of the layout manager is a MosaicPanel,
// then sashes are displayed between components that can
// be grabbed by the user in order to resize the components.
// In addition to that, the layout manager tries to detect
// the frame that contains the panel, because cursor types
// can only be changed for frames.
// If the parent of the layout manager is not a MosaicPanel,
// m_panel is set to null.
protected MosaicPanel m_panel = null;
protected Frame m_frame = null;
// Dragging does always refer to a particular interior
// node in the hierarchy. Which one? This one:
protected MosaicInteriorNode m_activeNode = null;
// The cursor changes its shape on sashes (if the frame of
// the parent could be found) according to the following
// values. On Windows systems, a different shape is chosen
// for column and row sashes and for intersections. On all
// other systems, the cursor is uniformly changed to
// MOVE_CURSOR.
protected int colSashCursor = Frame.DEFAULT_CURSOR;
protected int rowSashCursor = Frame.DEFAULT_CURSOR;
protected int crossSashCursor = Frame.DEFAULT_CURSOR;
// The size of sashes can be set for top level sashes and
// sashes on all other levels of the hierarchy separately.
protected int m_topLevelSashSize = 7;
protected int m_medLevelSashSize = 7;
// The following variable controls whether the repositioning
// that results from dragging operations is done while the
// dragging is going on, thus giving online feedback,
// or if it should be delayed until the mouse button is
// released (better for components that take a long time to
// draw). Note that if the latter is chosen, there is no
// hint like outlined sashes.
protected boolean m_liveDrag = true;
// Remember if the tree has been constructed (m_initialized)
// and the components have been reshaped (m_finalized).
protected boolean m_initialized = false;
protected boolean m_finalized = false;
//
// M o s a i c L a y o u t
//
// The constructor. MosaicConstraints object are registered
// under the name "Default" and "Centered." The latter one
// centers its component at its minimum size.
public MosaicLayout()
{
m_name2Constraints = new Hashtable();
m_comp2Node = new Hashtable();
setConstraints( "Default", new MosaicConstraints() );
setConstraints( "Centered",
new MosaicConstraints( MosaicConstraints.CENTER,
MosaicConstraints.NONE ) );
}
//
// a d d L a y o u t C o m p o n e n t
//
// One of the required callbacks of a layout manager.
// The component comp is added with the constraints that have
// previously been registered under the specified name. Its
// position in the hierarchy is initialized as being to
// the right of the last position that has been registered
// or generated. If the component has already been
// added (meaning it is found in the m_comp2Node hashtable),
// only the constraints are changed; its position remains
// unchanged.
public void addLayoutComponent( String name, Component comp )
{
if( m_comp2Node.containsKey( comp ) ) {
lookupNode( comp ).m_constraints = newConstraints( name );
}
else {
m_comp2Node.put( comp, new MosaicLeafNode( this, comp,
newConstraints( name ), newCoordStack() ) );
}
m_initialized = m_finalized = false;
}
//
// l a y o u t C o n t a i n e r
//
// One of the required callbacks of a layout manager.
// The hierarchy tree is generated from all the components
// that belong to the container parent. This contains all
// the components that have been registered with the
// addLayoutComponent() function, but also others. For
// those others that cannot be found in the hashtable
// m_comp2Node, leaf nodes are generated on the fly.
// (Their constraints and positions - coord stacks - are
// generated on the fly as well.) Note that one can
// very well register the constraints or position of
// a component that has not been added with
// addLayoutComponent(); as a general rule, leaf nodes
// are created whenever necessary.
public void layoutContainer( Container parent )
{
checkPanel( parent );
initializeGeometry( parent );
if( m_root != null ) {
Insets insets = parent.getInsets();
Dimension size = parent.getSize();
m_root.finalizeGeometry( insets.left, insets.top,
size.width - insets.left - insets.right,
size.height - insets.top - insets.bottom, true );
}
m_finalized = true;
}
//
// m i n i m u m L a y o u t S i z e
//
// One of the required callbacks of a layout manager.
// Returns the overall minimum size derived from the
// minimum sizes of all components. The tree is
// generated first if it doesn't exist yet.
public Dimension minimumLayoutSize( Container parent )
{
checkPanel( parent );
initializeGeometry( parent );
if( m_root == null )
return new Dimension( 0, 0 );
return m_root.m_minSize;
}
//
// p r e f e r r e d L a y o u t S i z e
//
// One of the required callbacks of a layout manager.
// Returns the overall preferred size derived from the
// preferred sizes of all components. The tree is
// generated first if it doesn't exist yet.
public Dimension preferredLayoutSize( Container parent )
{
checkPanel( parent );
initializeGeometry( parent );
if( m_root == null )
return new Dimension( 0, 0 );
// !!!!!! *BIG* bug fix here - line used to read m_root.m_size. AMB 05/98
return m_root.m_prefSize;
}
//
// r e m o v e L a y o u t C o m p o n e n t
//
// One of the required callbacks of a layout manager.
// The component comp is removed from the hashtable
// m_comp2Node, and is thus no longer part of the
// construction. The hierachy tree is marked as
// invalid; it is rebuilt when layoutContainer() is
// called later on.
public void removeLayoutComponent( Component comp )
{
if( m_comp2Node.containsKey( comp ) ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -