1  /*
     2   Copyright aswing.org, see the LICENCE.txt.
     3  */
     4  
     5  import org.aswing.plaf.*;
     6  import org.aswing.geom.*;
     7  import org.aswing.*;
     8  import org.aswing.utils.*;
     9   
    10  /**
    11   *
    12   * @author iiley
    13   */
    14  class org.aswing.JScrollPane extends Container{
    15  	
    16  
    17  	/**
    18  	 * When one of the scrollpane's scrollbar Adjustment Value Changed.
    19  	 *<br>
    20  	 * onAdjustmentValueChanged Event{source:JScrollBar, pane:JScrollPane}
    21  	 * @see JScrollBar#ON_ADJUSTMENT_VALUE_CHANGED
    22  	 */	
    23  	public static var ON_ADJUSTMENT_VALUE_CHANGED:String = "onAdjustmentValueChanged";//JScrollBar.ON_ADJUSTMENT_VALUE_CHANGED; 		
    24  	
    25  	/**
    26  	 * When the current viewport was replaced to another.
    27  	 *<br>
    28  	 * onViewportChanged Event{source:JScrollPane, oldViewport:Viewportable, newViewport:Viewportable}
    29  	 */	
    30  	public static var ON_VIEWPORT_CHANGED:String = "onViewportChanged"; 		
    31  	
    32      /**
    33       * scrollbar are displayed only when needed.
    34       */
    35      public static var SCROLLBAR_AS_NEEDED:Number = 0;
    36      /**
    37       * scrollbar are never displayed.
    38       */
    39      public static var SCROLLBAR_NEVER:Number = 1;
    40      /**
    41       * scrollbar are always displayed.
    42       */
    43      public static var SCROLLBAR_ALWAYS:Number = 2;
    44  	
    45  	private var viewport:Viewportable;
    46  	private var vScrollBar:JScrollBar;
    47  	private var hScrollBar:JScrollBar;
    48  	private var vsbPolicy:Number;
    49  	private var hsbPolicy:Number;
    50  	private var scrollbarListener:Object;
    51  	private var view:Component;
    52  	
    53  	/**
    54  	 * JScrollPane(view:Component, vsbPolicy:Number, hsbPolicy:Number)<br>
    55  	 * JScrollPane(view:Component, vsbPolicy:Number)<br>
    56  	 * JScrollPane(view:Component)<br>
    57  	 * JScrollPane(viewport:Viewportable, vsbPolicy:Number, hsbPolicy:Number)<br>
    58  	 * JScrollPane(viewport:Viewportable, vsbPolicy:Number)<br>
    59  	 * JScrollPane(viewport:Viewportable)<br>
    60  	 * JScrollPane()
    61  	 * <p>
    62  	 * Create a JScrollPane, you can specified a Component to be view,
    63  	 * then here will create a JViewport to manager the view's scroll,
    64  	 * or a Viewportable to be the view, it mananger the scroll itself.
    65  	 * If view is not instanceof either, no view will be viewed.
    66  	 * 
    67  	 * @param viewOrViewport the scroll content component or a Viewportable
    68  	 * @param vsbPolicy SCROLLBAR_AS_NEEDED or SCROLLBAR_NEVER or SCROLLBAR_ALWAYS, default SCROLLBAR_AS_NEEDED
    69  	 * @param hsbPolicy SCROLLBAR_AS_NEEDED or SCROLLBAR_NEVER or SCROLLBAR_ALWAYS, default SCROLLBAR_AS_NEEDED
    70  	 * @see #SCROLLBAR_AS_NEEDED
    71  	 * @see #SCROLLBAR_NEVER
    72  	 * @see #SCROLLBAR_ALWAYS
    73  	 * @see #setViewportView()
    74  	 * @see #setViewport()
    75  	 * @see org.aswing.Viewportable
    76  	 * @see org.aswing.JViewport
    77  	 * @see org.aswing.JList
    78  	 * @see org.aswing.JTextArea
    79  	 */
    80  	public function JScrollPane(viewOrViewport:Object, vsbPolicy:Number, hsbPolicy:Number){
    81  		super();
    82  		setName("JScrollPane");
    83  		if(vsbPolicy == undefined) vsbPolicy = SCROLLBAR_AS_NEEDED;
    84  		if(hsbPolicy == undefined) hsbPolicy = SCROLLBAR_AS_NEEDED;
    85  		this.vsbPolicy = vsbPolicy;
    86  		this.hsbPolicy = hsbPolicy;
    87  		
    88  		scrollbarListener = new Object();
    89  		scrollbarListener[JScrollBar.ON_ADJUSTMENT_VALUE_CHANGED] = Delegate.create(this, __onBarScroll);
    90  		
    91  		setVerticalScrollBar(new JScrollBar(JScrollBar.VERTICAL));
    92  		setHorizontalScrollBar(new JScrollBar(JScrollBar.HORIZONTAL));
    93  		setView(viewOrViewport);
    94  		setLayout(new ScrollPaneLayout());
    95  		updateUI();
    96  	}
    97  	
    98      public function updateUI():Void{
    99      	setUI(ScrollPaneUI(UIManager.getUI(this)));
   100      }
   101      
   102      public function setUI(newUI:ScrollPaneUI):Void{
   103      	super.setUI(newUI);
   104      }
   105  	
   106  	public function getUIClassID():String{
   107  		return "ScrollPaneUI";
   108  	}	
   109  	
   110  	/**
   111  	 * @throws Error when the layout is not ScrollPaneLayout instance.
   112  	 */
   113  	public function setLayout(layout:LayoutManager):Void{
   114  		if(layout instanceof ScrollPaneLayout){
   115  			super.setLayout(layout);
   116  		}else{
   117  			trace("Only on set ScrollPaneLayout to JScrollPane");
   118  			throw new Error("Only on set ScrollPaneLayout to JScrollPane");
   119  		}
   120  	}
   121  	
   122  	/**
   123  	 * @return true always here.
   124  	 */
   125  	public function isValidateRoot():Boolean{
   126  		return true;
   127  	}
   128  	
   129  	/**
   130  	 * Sets the view to viewed and scrolled by this scrollpane.
   131  	 * if this view is not a Viewportable implementation,
   132  	 * then here will create a JViewport to manager the view's scroll,
   133  	 * else the Viewportable will be the viewport.
   134  	 * <br>
   135  	 * If view is not instanceof either, no view will be set.
   136  	 * <br>If you want to make a component viewed by your way, you have two way:
   137  	 * <p>
   138  	 * <ul>
   139  	 * <li>1.Make your component a <code>Viewportable</code> implementation.
   140  	 * <li>2.Make a your new <code>Viewportable</code> likes <code>JViewport</code>, recommend
   141  	 * you extends the <code>JViewport</code>, then make your component to be the viewport's view like
   142  	 * <code>JViewport</code> does.
   143  	 * </ul>
   144  	 * <p>
   145  	 * setView(view:Component)<br>
   146  	 * setView(view:Viewportable)<br>
   147  	 * @see Viewportable
   148  	 * 
   149  	 * @param viewOrViewport a component or a Viewportable object.
   150  	 */
   151  	public function setView(viewOrViewport:Object):Void{
   152  		if(viewOrViewport instanceof Viewportable){
   153  			setViewport(Viewportable(viewOrViewport));
   154  		}else if(viewOrViewport instanceof Component){
   155  			setViewportView(Component(viewOrViewport));
   156  		}else{
   157  			//do nothing
   158  		}
   159  	}
   160  	
   161      /**
   162       * Creates a JViewport and then sets its view.  Applications
   163       * that don't provide the view directly to the <code>JScrollPane</code>
   164       * constructor
   165       * should use this method to specify the scrollable child that's going
   166       * to be displayed in the scrollpane. For example:
   167       * <pre>
   168       * JScrollPane scrollpane = new JScrollPane();
   169       * scrollpane.setViewportView(myBigComponentToScroll);
   170       * </pre>
   171       * Applications should not add children directly to the scrollpane.
   172       *
   173       * @param view the component to add to the viewport
   174       * @see #setViewport()
   175       * @see JViewport#setView()
   176       */
   177  	public function setViewportView(view:Component):Void{
   178  		setViewport(new JViewport(view));
   179  	}
   180  	
   181  	/**
   182  	 * Returns the view currently in the scrollpane.
   183  	 */
   184  	public function getViewportView():Component{
   185  		return view;
   186  	}
   187  	
   188      /**
   189       * Removes the old viewport (if there is one); and syncs the scrollbars and
   190       * headers with the new viewport.
   191       * <p>
   192       * Most applications will find it more convenient to use 
   193       * <code>setView</code>
   194       * to add a viewport or a view to the scrollpane.
   195       * 
   196       * @param viewport the new viewport to be used; if viewport is
   197       *		<code>null</code>, the old viewport is still removed
   198       *		and the new viewport is set to <code>null</code>
   199       * @see #getViewport()
   200       * @see #setViewportView()
   201       * @see JList
   202       * @see JTextArea
   203       * 
   204       */
   205  	private function setViewport(vp:Viewportable):Void{
   206  		if(viewport != vp){
   207  			var event:Event = createEventObj(ON_VIEWPORT_CHANGED);
   208  			event.oldViewport = viewport;
   209  			event.newViewport = vp;
   210  			if(viewport != null){
   211  				remove(viewport.getViewportPane());
   212  			}
   213  			viewport = vp;
   214  			if(viewport != null){
   215  				super.insert(-1, viewport.getViewportPane());
   216  			}
   217  			revalidate();
   218  			dispatchEvent(ON_VIEWPORT_CHANGED, event);
   219  		}
   220  	}
   221  	
   222  	public function getViewport():Viewportable{
   223  		return viewport;
   224  	}
   225  	
   226  	/**
   227  	 * Returns the visible extent rectangle related the current scroll properties.
   228  	 * @return the visible extent rectangle
   229  	 */
   230  	public function getVisibleRect():Rectangle{
   231  		return new Rectangle(getHorizontalScrollBar().getValue(),
   232  							 getVerticalScrollBar().getValue(),
   233  							 getHorizontalScrollBar().getVisibleAmount(),
   234  							 getVerticalScrollBar().getVisibleAmount());
   235  	}
   236  	
   237  	/**
   238  	 * Shortcut to and ON_ADJUSTMENT_VALUE_CHANGED listener.
   239  	 * <p>
   240  	 * addAdjustmentListener(func:Function)<br>
   241  	 * addAdjustmentListener(func:Function, obj:Object)<br>
   242  	 * @param func the function which want to handler the event.
   243  	 * @param obj context in which to run the function of param func.
   244  	 * @see #ON_ADJUSTMENT_VALUE_CHANGED
   245  	 */
   246  	public function addAdjustmentListener(func:Function, obj:Object):Object{
   247  		return addEventListener(ON_ADJUSTMENT_VALUE_CHANGED, func, obj);
   248  	}
   249  	
   250  	/**
   251  	 * Event handler for scroll bars
   252  	 */
   253  	private function __onBarScroll(event:Event):Void{
   254  		event.pane = this;
   255  		dispatchEvent(ON_ADJUSTMENT_VALUE_CHANGED, event);
   256  	}
   257  		
   258  	/**
   259  	 * Adds the scrollbar that controls the viewport's horizontal view position to the scrollpane. 
   260  	 */
   261  	public function setHorizontalScrollBar(horizontalScrollBar:JScrollBar):Void{
   262  		if(hScrollBar != horizontalScrollBar){
   263  			hScrollBar.removeEventListener(scrollbarListener);
   264  			remove(hScrollBar);
   265  			hScrollBar = horizontalScrollBar;
   266  			hScrollBar.setName("HorizontalScrollBar");
   267  			super.insert(-1, hScrollBar);
   268  			hScrollBar.addEventListener(scrollbarListener);
   269  			revalidate();
   270  		}
   271  	}
   272  	
   273  	public function getHorizontalScrollBar():JScrollBar{
   274  		return hScrollBar;
   275  	}
   276  	
   277  	public function setHorizontalScrollBarPolicy(policy:Number):Void{
   278  		hsbPolicy = (policy == undefined ? SCROLLBAR_AS_NEEDED : policy);
   279  	} 
   280   
   281  	public function getHorizontalScrollBarPolicy():Number{
   282  		return hsbPolicy;
   283  	} 
   284  	
   285   	/**
   286  	 * Adds the scrollbar that controls the viewport's vertical view position to the scrollpane. 
   287  	 */
   288  	public function setVerticalScrollBar(verticalScrollBar:JScrollBar):Void{
   289  		if(vScrollBar != verticalScrollBar){
   290  			vScrollBar.removeEventListener(scrollbarListener);
   291  			remove(vScrollBar);
   292  			vScrollBar = verticalScrollBar;
   293  			vScrollBar.setName("verticalScrollBar");
   294  			super.insert(-1, vScrollBar);
   295  			vScrollBar.addEventListener(scrollbarListener);
   296  			revalidate();
   297  		}
   298  	}
   299  	
   300  	public function getVerticalScrollBar():JScrollBar{
   301  		return vScrollBar;
   302  	}
   303  	
   304  	public function setVerticalScrollBarPolicy(policy:Number):Void{
   305  		vsbPolicy = (policy == undefined ? SCROLLBAR_AS_NEEDED : policy);
   306  	} 
   307  
   308  	public function getVerticalScrollBarPolicy():Number{
   309  		return vsbPolicy;
   310  	}
   311  	
   312  	/**
   313  	 * @throws Error when append child to JScrollPane
   314  	 */
   315  	public function append(com:Component, constraints:Object):Void{
   316  		trace("Can not add comp to JScrollPane");
   317  		throw new Error("Can not add comp to JScrollPane");
   318  	}
   319  	
   320  	/**
   321  	 * @throws Error when append child to JScrollPane
   322  	 */	
   323  	public function insert(i:Number, com:Component, constraints:Object):Void{
   324  		trace("Can not add comp to JScrollPane");
   325  		throw new Error("Can not add comp to JScrollPane");	
   326  	}	
   327  }
   328