Source for javax.swing.text.View

   1: /* View.java -- 
   2:    Copyright (C) 2002, 2004, 2005  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.swing.text;
  40: 
  41: import java.awt.Container;
  42: import java.awt.Graphics;
  43: import java.awt.Rectangle;
  44: import java.awt.Shape;
  45: 
  46: import javax.swing.JComponent;
  47: import javax.swing.SwingConstants;
  48: import javax.swing.event.DocumentEvent;
  49: 
  50: public abstract class View implements SwingConstants
  51: {
  52:   public static final int BadBreakWeight = 0;
  53:   public static final int ExcellentBreakWeight = 2000;
  54:   public static final int ForcedBreakWeight = 3000;
  55:   public static final int GoodBreakWeight = 1000;
  56: 
  57:   public static final int X_AXIS = 0;
  58:   public static final int Y_AXIS = 1;
  59:     
  60:   private float width, height;
  61:   private Element elt;
  62:   private View parent;
  63: 
  64:   /**
  65:    * The child views.
  66:    */
  67:   View[] children;
  68: 
  69:   /**
  70:    * Creates a new <code>View</code> instance.
  71:    *
  72:    * @param elem an <code>Element</code> value
  73:    */
  74:   public View(Element elem)
  75:   {
  76:     elt = elem;
  77:     children = new View[0];
  78:   }
  79: 
  80:   public abstract void paint(Graphics g, Shape s);
  81: 
  82:   public void setParent(View parent)
  83:   {
  84:     this.parent = parent;
  85:   }
  86:     
  87:   public View getParent()
  88:   {
  89:     return parent;
  90:   }
  91:     
  92:   public Container getContainer()
  93:   {
  94:     View parent = getParent();
  95:     return parent != null ? parent.getContainer() : null;
  96:   }
  97:   
  98:   public Document getDocument()
  99:   {
 100:     return getElement().getDocument();
 101:   }
 102:     
 103:   public Element getElement()
 104:   {
 105:     return elt;
 106:   }
 107: 
 108:   public abstract float getPreferredSpan(int axis);
 109: 
 110:   public int getResizeWeight(int axis)
 111:   {
 112:     return 0;
 113:   }
 114: 
 115:   public float getMaximumSpan(int axis)
 116:   {
 117:     if (getResizeWeight(axis) <= 0)
 118:       return getPreferredSpan(axis);
 119: 
 120:     return Integer.MAX_VALUE;
 121:   }
 122: 
 123:   public float getMinimumSpan(int axis)
 124:   {
 125:     if (getResizeWeight(axis) <= 0)
 126:       return getPreferredSpan(axis);
 127: 
 128:     return Integer.MAX_VALUE;
 129:   }
 130:   
 131:   public void setSize(float width, float height)
 132:   {
 133:     // The default implementation does nothing.
 134:   }
 135:   
 136:   public float getAlignment(int axis)
 137:   {
 138:     return 0.5f;
 139:   }
 140: 
 141:   public AttributeSet getAttributes()
 142:   {
 143:     return getElement().getAttributes();
 144:   }
 145:   
 146:   public boolean isVisible()
 147:   {
 148:     return true;
 149:   }
 150: 
 151:   public int getViewCount()
 152:   {
 153:     return 0;
 154:   }
 155:   
 156:   public View getView(int index)
 157:   {
 158:     return null;
 159:   }
 160: 
 161:   public ViewFactory getViewFactory()
 162:   {
 163:     View parent = getParent();
 164:     return parent != null ? parent.getViewFactory() : null;
 165:   }
 166: 
 167:   public void replace(int offset, int length, View[] views)
 168:   {
 169:     // Default implementation does nothing.
 170:   }
 171: 
 172:   public void insert(int offset, View view)
 173:   {
 174:     View[] array = { view };
 175:     replace(offset, 1, array);
 176:   }
 177: 
 178:   public void append(View view)
 179:   {
 180:     View[] array = { view };
 181:     replace(getViewCount(), 1, array);
 182:   }
 183: 
 184:   public void removeAll()
 185:   {
 186:     replace(0, getViewCount(), null); 
 187:   }
 188: 
 189:   public void remove(int index)
 190:   {
 191:     replace(index, 1, null); 
 192:   }
 193: 
 194:   public View createFragment(int p0, int p1)
 195:   {
 196:     // The default implementation doesn't support fragmentation.
 197:     return this;
 198:   }
 199: 
 200:   public int getStartOffset()
 201:   {
 202:     return getElement().getStartOffset();
 203:   }
 204: 
 205:   public int getEndOffset()
 206:   {
 207:     return getElement().getEndOffset();
 208:   }
 209: 
 210:   public Shape getChildAllocation(int index, Shape a)
 211:   {
 212:     return null;
 213:   }
 214:   
 215:   /**
 216:    * @since 1.4
 217:    */
 218:   public int getViewIndex(float x, float y, Shape allocation)
 219:   {
 220:     return -1;
 221:   }
 222:   
 223:   /**
 224:    * @since 1.4
 225:    */
 226:   public String getToolTipText(float x, float y, Shape allocation)
 227:   {
 228:     int index = getViewIndex(x, y, allocation);
 229: 
 230:     if (index < -1)
 231:       return null;
 232: 
 233:     Shape childAllocation = getChildAllocation(index, allocation);
 234: 
 235:     if (childAllocation.getBounds().contains(x, y))
 236:       return getView(index).getToolTipText(x, y, childAllocation);
 237: 
 238:     return null;
 239:   }
 240: 
 241:   /**
 242:    * @since 1.3
 243:    */
 244:   public Graphics getGraphics()
 245:   {
 246:     return getContainer().getGraphics();
 247:   }
 248: 
 249:   public void preferenceChanged(View child, boolean width, boolean height)
 250:   {
 251:     if (parent != null)
 252:       parent.preferenceChanged(this, width, height);
 253:     else
 254:       ((JComponent) getContainer()).revalidate();
 255:   }
 256: 
 257:   public int getBreakWeight(int axis, float pos, float len)
 258:   {
 259:     return BadBreakWeight;
 260:   }
 261: 
 262:   public View breakView(int axis, int offset, float pos, float len)
 263:   {
 264:     return this;
 265:   }
 266: 
 267:   /**
 268:    * @since 1.3
 269:    */
 270:   public int getViewIndex(int pos, Position.Bias b)
 271:   {
 272:     return -1;
 273:   }
 274: 
 275:   /**
 276:    * Receive notification about an insert update to the text model.
 277:    *
 278:    * The default implementation of this method does the following:
 279:    * <ul>
 280:    * <li>Call {@link #updateChildren} if the element that this view is
 281:    * responsible for has changed. This makes sure that the children can
 282:    * correctly represent the model.<li>
 283:    * <li>Call {@link #forwardUpdate}. This forwards the DocumentEvent to
 284:    * the child views.<li>
 285:    * <li>Call {@link #updateLayout}. Gives the view a chance to either
 286:    * repair its layout, reschedule layout or do nothing at all.</li>
 287:    * </ul>
 288:    *
 289:    * @param ev the DocumentEvent that describes the change
 290:    * @param shape the shape of the view
 291:    * @param vf the ViewFactory for creating child views
 292:    */
 293:   public void insertUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
 294:   {
 295:     Element el = getElement();
 296:     DocumentEvent.ElementChange ec = ev.getChange(el);
 297:     if (ec != null)
 298:       updateChildren(ec, ev, vf);
 299:     forwardUpdate(ec, ev, shape, vf);
 300:     updateLayout(ec, ev, shape);
 301:   }
 302: 
 303:   /**
 304:    * Receive notification about a remove update to the text model.
 305:    *
 306:    * The default implementation of this method does the following:
 307:    * <ul>
 308:    * <li>Call {@link #updateChildren} if the element that this view is
 309:    * responsible for has changed. This makes sure that the children can
 310:    * correctly represent the model.<li>
 311:    * <li>Call {@link #forwardUpdate}. This forwards the DocumentEvent to
 312:    * the child views.<li>
 313:    * <li>Call {@link #updateLayout}. Gives the view a chance to either
 314:    * repair its layout, reschedule layout or do nothing at all.</li>
 315:    * </ul>
 316:    *
 317:    * @param ev the DocumentEvent that describes the change
 318:    * @param shape the shape of the view
 319:    * @param vf the ViewFactory for creating child views
 320:    */
 321:   public void removeUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
 322:   {
 323:     Element el = getElement();
 324:     DocumentEvent.ElementChange ec = ev.getChange(el);
 325:     if (ec != null)
 326:         updateChildren(ec, ev, vf);
 327:     forwardUpdate(ec, ev, shape, vf);
 328:     updateLayout(ec, ev, shape);
 329:   }
 330: 
 331:   /**
 332:    * Receive notification about a change update to the text model.
 333:    *
 334:    * The default implementation of this method does the following:
 335:    * <ul>
 336:    * <li>Call {@link #updateChildren} if the element that this view is
 337:    * responsible for has changed. This makes sure that the children can
 338:    * correctly represent the model.<li>
 339:    * <li>Call {@link #forwardUpdate}. This forwards the DocumentEvent to
 340:    * the child views.<li>
 341:    * <li>Call {@link #updateLayout}. Gives the view a chance to either
 342:    * repair its layout, reschedule layout or do nothing at all.</li>
 343:    * </ul>
 344:    *
 345:    * @param ev the DocumentEvent that describes the change
 346:    * @param shape the shape of the view
 347:    * @param vf the ViewFactory for creating child views
 348:    */
 349:   public void changedUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
 350:   {
 351:     Element el = getElement();
 352:     DocumentEvent.ElementChange ec = ev.getChange(el);
 353:     if (ec != null)
 354:         updateChildren(ec, ev, vf);
 355:     forwardUpdate(ec, ev, shape, vf);
 356:     updateLayout(ec, ev, shape);
 357:   }
 358: 
 359:   /**
 360:    * Updates the list of children that is returned by {@link #getView}
 361:    * and {@link #getViewCount}.
 362:    *
 363:    * Element that are specified as beeing added in the ElementChange record are
 364:    * assigned a view for using the ViewFactory. Views of Elements that
 365:    * are specified as beeing removed are removed from the list.
 366:    *
 367:    * @param ec the ElementChange record that describes the change of the
 368:    *           element
 369:    * @param ev the DocumentEvent describing the change of the document model
 370:    * @param vf the ViewFactory to use for creating new views
 371:    *
 372:    * @return whether or not the child views represent the child elements of
 373:    *         the element that this view is responsible for. Some views may
 374:    *         create views that are responsible only for parts of the element
 375:    *         that they are responsible for and should then return false.
 376:    *
 377:    * @since 1.3
 378:    */
 379:   protected boolean updateChildren(DocumentEvent.ElementChange ec,
 380:                                    DocumentEvent ev,
 381:                                    ViewFactory vf)
 382:   {
 383:     Element[] added = ec.getChildrenAdded();
 384:     Element[] removed = ec.getChildrenRemoved();
 385:     View[] newChildren = new View[children.length + added.length
 386:                                   - removed.length];
 387:     int index = ec.getIndex();
 388:     System.arraycopy(children, 0, newChildren, 0, index);
 389:     System.arraycopy(children, index, added, 0, added.length);
 390:     int index2 = index + removed.length;
 391:     int len2 = children.length - index2;
 392:     System.arraycopy(children, index2, newChildren, index + added.length,
 393:                      len2);
 394:     children = newChildren;
 395: 
 396:     return true;
 397:   }
 398: 
 399:   /**
 400:    * Forwards the DocumentEvent to child views that need to get notified
 401:    * of the change to the model. This calles {@link #forwardUpdateToView}
 402:    * for each View that must be forwarded to.
 403:    *
 404:    * @param ec the ElementChange describing the element changes (may be
 405:    *           <code>null</code> if there were no changes)
 406:    * @param ev the DocumentEvent describing the changes to the model
 407:    * @param shape the current allocation of the view
 408:    * @param vf the ViewFactory used to create new Views
 409:    *
 410:    * @since 1.3
 411:    */
 412:   protected void forwardUpdate(DocumentEvent.ElementChange ec,
 413:                                DocumentEvent ev, Shape shape, ViewFactory vf)
 414:   {
 415:     for (int i = 0; i < children.length; i++)
 416:       {
 417:         View child = children[i];
 418:         forwardUpdateToView(child, ev, shape, vf);
 419:       }
 420:   }
 421: 
 422:   /**
 423:    * Forwards an update event to the given child view. This calls
 424:    * {@link #insertUpdate}, {@link #removeUpdate} or {@link #changedUpdate},
 425:    * depending on the type of document event.
 426:    *
 427:    * @param view the View to forward the event to
 428:    * @param ev the DocumentEvent to forward
 429:    * @param shape the current allocation of the View
 430:    * @param vf the ViewFactory used to create new Views
 431:    *
 432:    * @since 1.3
 433:    */
 434:   protected void forwardUpdateToView(View view, DocumentEvent ev, Shape shape,
 435:                                      ViewFactory vf)
 436:   {
 437:     DocumentEvent.EventType type = ev.getType();
 438:     if (type == DocumentEvent.EventType.INSERT)
 439:       view.insertUpdate(ev, shape, vf);
 440:     else if (type == DocumentEvent.EventType.REMOVE)
 441:       view.removeUpdate(ev, shape, vf);
 442:     else if (type == DocumentEvent.EventType.CHANGE)
 443:       view.changedUpdate(ev, shape, vf);
 444:   }
 445: 
 446:   /**
 447:    * Updates the layout.
 448:    *
 449:    * @param ec the ElementChange that describes the changes to the element
 450:    * @param ev the DocumentEvent that describes the changes to the model
 451:    * @param shape the current allocation for this view
 452:    *
 453:    * @since 1.3
 454:    */
 455:   protected void updateLayout(DocumentEvent.ElementChange ec,
 456:                               DocumentEvent ev, Shape shape)
 457:   {
 458:     Rectangle b = shape.getBounds();
 459:     if (ec != null)
 460:       preferenceChanged(this, true, true);
 461:   }
 462: }