1  /*
     2   Copyright aswing.org, see the LICENCE.txt.
     3  */
     4  import org.aswing.Component;
     5  import org.aswing.Container;
     6  import org.aswing.UIManager;
     7  import org.aswing.geom.Dimension;
     8  import org.aswing.geom.Point;
     9  import org.aswing.geom.Rectangle;
    10  import org.aswing.LayoutManager;
    11  import org.aswing.Viewportable;
    12  import org.aswing.ViewportLayout;
    13  import org.aswing.plaf.ViewportUI;
    14  
    15  
    16  /**
    17   *
    18   * @author iiley
    19   */
    20  class org.aswing.JViewport extends Container implements Viewportable {
    21  				
    22  	/**
    23  	 * When the viewport's state changed.
    24  	 * View position changed, view changed, all related to scroll things changed.
    25  	 *<br>
    26  	 * onStateChanged Event{source:JViewport}
    27  	 */	
    28  	public static var ON_STATE_CHANGED:String = "onStateChanged";//Component.ON_STATE_CHANGED; 	
    29   	
    30  	private var verticalUnitIncrement:Number;
    31  	private var verticalBlockIncrement:Number;
    32  	private var horizontalUnitIncrement:Number;
    33  	private var horizontalBlockIncrement:Number;
    34  	
    35  	private var view:Component;
    36  	
    37  	/**
    38  	 * <br>
    39  	 * JViewport(view:Component)<br>
    40  	 * JViewport()<br>
    41  	 */
    42  	public function JViewport(view:Component){
    43  		super();
    44  		setName("JViewport");
    45  		if(view != undefined) setView(view);
    46  		setLayout(new ViewportLayout());
    47  		updateUI();
    48  	}
    49  
    50      
    51      
    52      public function updateUI():Void{
    53      	setUI(ViewportUI(UIManager.getUI(this)));
    54      }
    55      
    56      
    57      public function setUI(newUI:ViewportUI):Void{
    58      	super.setUI(newUI);
    59      }
    60  	
    61  	
    62  	
    63  	
    64  	public function getUIClassID():String{
    65  		return "ViewportUI";
    66  	}	
    67  
    68  	/**
    69  	 * @throws Error if the layout is not a ViewportLayout
    70  	 */
    71  	public function setLayout(layout:LayoutManager):Void{
    72  		if(layout instanceof ViewportLayout){
    73  			super.setLayout(layout);
    74  		}else{
    75  			trace(this + " Only on set ViewportLayout to JViewport");
    76  			throw new Error(this + " Only on set ViewportLayout to JViewport");
    77  		}
    78  	}
    79  	
    80  	
    81  	/**
    82  	 * Sets the view component.<br>
    83  	 * 
    84  	 * <p>The view is the visible content of the JViewPort.
    85  	 * 
    86  	 * <p>JViewport use to manage the scroll view of a component.
    87  	 * the component will be set size to its preferred size, then scroll in the viewport.<br>
    88  	 * 
    89  	 * <p>If the component's isTracksViewportWidth method is defined and return true,
    90  	 * when the viewport's show size is larger than the component's,
    91  	 * the component will be widen to the show size, otherwise, not widen.
    92  	 * Same as isTracksViewportHeight method.
    93  	 */
    94  	public function setView(view:Component):Void{
    95  		if(this.view != view){
    96  			this.view = view;
    97  			removeAll();
    98  			
    99  			if(view != null){
   100  				super.insert(-1, view);
   101  			}
   102  			fireStateChanged();
   103  		}
   104  	}
   105  	
   106  	public function getView():Component{
   107  		return view;
   108  	}
   109  		
   110  	/**
   111  	 * Sets the unit value for the Vertical scrolling.
   112  	 */
   113      public function setVerticalUnitIncrement(increment:Number):Void{
   114      	if(verticalUnitIncrement != increment){
   115      		verticalUnitIncrement = increment;
   116  			fireStateChanged();
   117      	}
   118      }
   119      
   120      /**
   121       * Sets the block value for the Vertical scrolling.
   122       */
   123      public function setVerticalBlockIncrement(increment:Number):Void{
   124      	if(verticalBlockIncrement != increment){
   125      		verticalBlockIncrement = increment;
   126  			fireStateChanged();
   127      	}
   128      }
   129      
   130  	/**
   131  	 * Sets the unit value for the Horizontal scrolling.
   132  	 */
   133      public function setHorizontalUnitIncrement(increment:Number):Void{
   134      	if(horizontalUnitIncrement != increment){
   135      		horizontalUnitIncrement = increment;
   136  			fireStateChanged();
   137      	}
   138      }
   139      
   140      /**
   141       * Sets the block value for the Horizontal scrolling.
   142       */
   143      public function setHorizontalBlockIncrement(increment:Number):Void{
   144      	if(horizontalBlockIncrement != increment){
   145      		horizontalBlockIncrement = increment;
   146  			fireStateChanged();
   147      	}
   148      }		
   149  			
   150  	
   151  	/**
   152  	 * In fact just call setView(com) in this method
   153  	 * @see #setView()
   154  	 */
   155  	public function append(com:Component, constraints:Object):Void{
   156  		setView(com);
   157  	}
   158  	
   159  	/**
   160  	 * In fact just call setView(com) in this method
   161  	 * @see #setView()
   162  	 */	
   163  	public function insert(i:Number, com:Component, constraints:Object):Void{
   164  		setView(com);
   165  	}	
   166  	
   167  	//--------------------implementatcion of Viewportable---------------
   168  
   169  	/**
   170  	 * Returns the unit value for the Vertical scrolling.
   171  	 */
   172      public function getVerticalUnitIncrement():Number{
   173      	if(verticalUnitIncrement != undefined){
   174      		return verticalUnitIncrement;
   175      	}else{
   176      		return 1;
   177      	}
   178      }
   179      
   180      /**
   181       * Return the block value for the Vertical scrolling.
   182       */
   183      public function getVerticalBlockIncrement():Number{
   184      	if(verticalBlockIncrement != undefined){
   185      		return verticalBlockIncrement;
   186      	}else{
   187      		return getExtentSize().height-1;
   188      	}
   189      }
   190      
   191  	/**
   192  	 * Returns the unit value for the Horizontal scrolling.
   193  	 */
   194      public function getHorizontalUnitIncrement():Number{
   195      	if(horizontalUnitIncrement != undefined){
   196      		return horizontalUnitIncrement;
   197      	}else{
   198      		return 1;
   199      	}
   200      }
   201      
   202      /**
   203       * Return the block value for the Horizontal scrolling.
   204       */
   205      public function getHorizontalBlockIncrement():Number{
   206      	if(horizontalBlockIncrement != undefined){
   207      		return horizontalBlockIncrement;
   208      	}else{
   209      		return getExtentSize().width - 1;
   210      	}
   211      }
   212      
   213      public function setViewportTestSize(s:Dimension):Void{
   214      	setSize(s);
   215      }
   216  
   217  	public function getExtentSize() : Dimension {
   218  		return getInsets().inroundsSize(getSize());
   219  	}
   220  	
   221  	/**
   222       * Usually the view's preffered size.
   223       * @return the view's size, (0, 0) if view is null.
   224  	 */
   225  	public function getViewSize() : Dimension {
   226  		if(view == null){
   227  			return new Dimension();
   228  		}else{
   229  			return view.getPreferredSize();
   230  		}
   231  	}
   232  	
   233  	/**
   234  	 * Returns the view's position, if there is not any view, return null.
   235  	 * @return the view's position, null if view is null.
   236  	 */
   237  	public function getViewPosition() : Point {
   238  		if(view != null){
   239  			var p:Point = view.getLocation();
   240  			var ir:Rectangle = getInsets().getInsideBounds(getSize().getBounds());
   241  			p.x = ir.x - p.x;
   242  			p.y = ir.y - p.y;
   243  			return p;
   244  		}else{
   245  			return null;
   246  		}
   247  	}
   248  
   249  	public function setViewPosition(p : Point) : Void {
   250  		restrictionViewPos(p);
   251  		if(!p.equals(getViewPosition())){
   252  			var ir:Rectangle = getInsets().getInsideBounds(getSize().getBounds());
   253  			view.setLocation(ir.x-p.x, ir.y-p.y);
   254  			view.revalidate();
   255  			fireStateChanged();
   256  		}
   257  	}
   258  
   259  	public function scrollRectToVisible(contentRect : Rectangle) : Void {
   260  		setViewPosition(new Point(contentRect.x, contentRect.y));
   261  	}
   262  	
   263  	/**
   264  	 * Scrolls to view bottom left content. 
   265  	 * This will make the scrollbars of <code>JScrollPane</code> scrolled automatically, 
   266  	 * if it is located in a <code>JScrollPane</code>.
   267  	 */
   268  	public function scrollToBottomLeft():Void{
   269  		setViewPosition(new Point(0, Number.MAX_VALUE));
   270  	}
   271  	/**
   272  	 * Scrolls to view bottom right content. 
   273  	 * This will make the scrollbars of <code>JScrollPane</code> scrolled automatically, 
   274  	 * if it is located in a <code>JScrollPane</code>.
   275  	 */	
   276  	public function scrollToBottomRight():Void{
   277  		setViewPosition(new Point(Number.MAX_VALUE, Number.MAX_VALUE));
   278  	}
   279  	/**
   280  	 * Scrolls to view top left content. 
   281  	 * This will make the scrollbars of <code>JScrollPane</code> scrolled automatically, 
   282  	 * if it is located in a <code>JScrollPane</code>.
   283  	 */	
   284  	public function scrollToTopLeft():Void{
   285  		setViewPosition(new Point(0, 0));
   286  	}
   287  	/**
   288  	 * Scrolls to view to right content. 
   289  	 * This will make the scrollbars of <code>JScrollPane</code> scrolled automatically, 
   290  	 * if it is located in a <code>JScrollPane</code>.
   291  	 */	
   292  	public function scrollToTopRight():Void{
   293  		setViewPosition(new Point(Number.MAX_VALUE, 0));
   294  	}
   295  	
   296  	private function restrictionViewPos(p:Point):Point{
   297  		var maxPos:Point = getViewMaxPos();
   298  		p.x = Math.max(0, Math.min(maxPos.x, p.x));
   299  		p.y = Math.max(0, Math.min(maxPos.y, p.y));
   300  		return p;
   301  	}
   302  	
   303  	private function getViewMaxPos():Point{
   304  		var showSize:Dimension = getExtentSize();
   305  		var viewSize:Dimension = getViewSize();
   306  		var p:Point = new Point(viewSize.width-showSize.width, viewSize.height-showSize.height);
   307  		if(p.x < 0) p.x = 0;
   308  		if(p.y < 0) p.y = 0;
   309  		return p;
   310  	}
   311  	
   312      /**
   313       * Converts a size in screen pixel coordinates to view ligic coordinates.
   314       * Subclasses of viewport that support "logical coordinates" will override this method. 
   315       * 
   316       * @param size  a <code>Dimension</code> object using screen pixel coordinates
   317       * @return a <code>Dimension</code> object converted to view logic coordinates
   318       */
   319  	public function toViewCoordinatesSize(size : Dimension) : Dimension {
   320  		return new Dimension(size.width, size.height);
   321  	}
   322  	
   323      /**
   324       * Converts a point in screen pixel coordinates to view coordinates.
   325       * Subclasses of viewport that support "logical coordinates" will override this method. 
   326       *
   327       * @param p  a <code>Point</code> object using screen pixel coordinates
   328       * @return a <code>Point</code> object converted to view coordinates
   329       */
   330  	public function toViewCoordinatesLocation(p : Point) : Point {
   331  		return new Point(p.x, p.y);
   332  	}
   333  	
   334      /**
   335       * Converts a size in view logic coordinates to screen pixel coordinates.
   336       * Subclasses of viewport that support "logical coordinates" will override this method. 
   337       * 
   338       * @param size  a <code>Dimension</code> object using view logic coordinates
   339       * @return a <code>Dimension</code> object converted to screen pixel coordinates
   340       */
   341      public function toScreenCoordinatesSize(size:Dimension):Dimension{
   342      	return new Dimension(size.width, size.height);
   343      }
   344  
   345      /**
   346       * Converts a point in view logic coordinates to screen pixel coordinates.
   347       * Subclasses of viewport that support "logical coordinates" will override this method. 
   348       * 
   349       * @param p  a <code>Point</code> object using view logic coordinates
   350       * @return a <code>Point</code> object converted to screen pixel coordinates
   351       */
   352      public function toScreenCoordinatesLocation(p:Point):Point{
   353      	return new Point(p.x, p.y);
   354      }
   355      	
   356  	public function addChangeListener(func:Function, obj:Object):Object{
   357  		return addEventListener(Component.ON_STATE_CHANGED, func, obj);
   358  	}
   359  	
   360  	public function getViewportPane() : Component {
   361  		return this;
   362  	}
   363  
   364  }
   365