001 /* 002 Copyright (C) 2003 Laurent Martelli <laurent@aopsys.com> 003 004 This program is free software; you can redistribute it and/or modify 005 it under the terms of the GNU Lesser General Public License as 006 published by the Free Software Foundation; either version 2 of the 007 License, or (at your option) any later version. 008 009 This program is distributed in the hope that it will be useful, 010 but WITHOUT ANY WARRANTY; without even the implied warranty of 011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 GNU Lesser General Public License for more details. 013 014 You should have received a copy of the GNU Lesser General Public 015 License along with this program; if not, write to the Free Software 016 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 017 */ 018 019 package org.objectweb.jac.ide.diagrams; 020 021 import CH.ifa.draw.contrib.AutoscrollHelper; 022 import CH.ifa.draw.framework.ConnectionFigure; 023 import CH.ifa.draw.framework.Connector; 024 import CH.ifa.draw.framework.Drawing; 025 import CH.ifa.draw.framework.DrawingChangeEvent; 026 import CH.ifa.draw.framework.DrawingEditor; 027 import CH.ifa.draw.framework.DrawingView; 028 import CH.ifa.draw.framework.Figure; 029 import CH.ifa.draw.framework.FigureEnumeration; 030 import CH.ifa.draw.framework.FigureSelection; 031 import CH.ifa.draw.framework.FigureSelectionListener; 032 import CH.ifa.draw.framework.Handle; 033 import CH.ifa.draw.framework.Painter; 034 import CH.ifa.draw.framework.PointConstrainer; 035 import CH.ifa.draw.framework.Tool; 036 import CH.ifa.draw.standard.FigureEnumerator; 037 import CH.ifa.draw.standard.SimpleUpdateStrategy; 038 import CH.ifa.draw.standard.StandardFigureSelection; 039 import CH.ifa.draw.util.Geom; 040 import java.awt.Color; 041 import java.awt.Dimension; 042 import java.awt.Graphics; 043 import java.awt.Insets; 044 import java.awt.Point; 045 import java.awt.PrintGraphics; 046 import java.awt.Rectangle; 047 import java.awt.dnd.Autoscroll; 048 import java.awt.event.KeyEvent; 049 import java.awt.event.KeyListener; 050 import java.awt.event.MouseEvent; 051 import java.awt.event.MouseListener; 052 import java.awt.event.MouseMotionListener; 053 import java.util.Enumeration; 054 import java.util.Vector; 055 import javax.swing.JPanel; 056 import javax.swing.Scrollable; 057 058 /** 059 * Same as CH.ifa.draw.standard.StandardDrawingView, but with specific 060 * handling of "remove". 061 */ 062 public class IDEDrawingView extends JPanel 063 implements DrawingView, KeyListener, Autoscroll, Scrollable { 064 065 /** 066 * The DrawingEditor of the view. 067 * @see #tool 068 * @see #setStatus 069 */ 070 transient private DrawingEditor fEditor; 071 072 /** the registered listeners for selection changes */ 073 private transient Vector fSelectionListeners; 074 075 /** The shown drawing. */ 076 private Drawing fDrawing; 077 078 /** the accumulated damaged area */ 079 private transient Rectangle fDamage = null; 080 081 /** 082 * The list of currently selected figures. 083 */ 084 transient private Vector fSelection; 085 086 /** 087 * The shown selection handles. 088 */ 089 transient private Vector fSelectionHandles; 090 091 /** 092 * The preferred size of the view 093 */ 094 private Dimension fViewSize; 095 096 /** 097 * The position of the last mouse click 098 * inside the view. 099 */ 100 private Point fLastClick; 101 102 /** 103 * A vector of optional backgrounds. The vector maintains 104 * a list a view painters that are drawn before the contents, 105 * that is in the background. 106 */ 107 private Vector fBackgrounds = null; 108 109 /** 110 * A vector of optional foregrounds. The vector maintains 111 * a list a view painters that are drawn after the contents, 112 * that is in the foreground. 113 */ 114 private Vector fForegrounds = null; 115 116 /** 117 * The update strategy used to repair the view. 118 */ 119 private Painter fUpdateStrategy; 120 121 /** 122 * The grid used to constrain points for snap to 123 * grid functionality. 124 */ 125 private PointConstrainer fConstrainer; 126 127 /** 128 * Scrolling increment 129 */ 130 public static final int MINIMUM_WIDTH = 400; 131 public static final int MINIMUM_HEIGHT = 300; 132 public static final int SCROLL_INCR = 100; 133 public static final int SCROLL_OFFSET = 10; 134 135 public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { 136 return SCROLL_OFFSET; 137 } 138 public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { 139 return SCROLL_INCR; 140 } 141 142 public boolean getScrollableTracksViewportWidth() { 143 return false; 144 } 145 public boolean getScrollableTracksViewportHeight() { 146 return false; 147 } 148 public Dimension getPreferredScrollableViewportSize() { 149 return getPreferredSize(); 150 } 151 152 /* 153 * Serialization support. In JavaDraw only the Drawing is serialized. 154 * However, for beans support StandardDrawingView supports 155 * serialization 156 */ 157 private static final long serialVersionUID = -3878153366174603336L; 158 159 /** 160 * Constructs the view. 161 */ 162 public IDEDrawingView(DrawingEditor editor) { 163 this(editor, MINIMUM_WIDTH, MINIMUM_HEIGHT); 164 } 165 166 public IDEDrawingView(DrawingEditor editor, int width, int height) { 167 setAutoscrolls(true); 168 counter++; 169 fEditor = editor; 170 fViewSize = new Dimension(width,height); 171 fSelectionListeners = new Vector(); 172 addFigureSelectionListener(editor()); 173 fLastClick = new Point(0, 0); 174 fConstrainer = null; 175 fSelection = new Vector(); 176 // JFC/Swing uses double buffering automatically as default 177 setDisplayUpdate(new SimpleUpdateStrategy()); 178 // TODO: Test FastBufferedUpdateStrategy with JFC/Swing double buffering 179 //setDisplayUpdate(new FastBufferedUpdateStrategy()); 180 setBackground(Color.lightGray); 181 182 addMouseListener(ml); 183 addMouseMotionListener(mml); 184 addKeyListener(this); 185 } 186 187 MouseListener ml = new MouseListener() { 188 // listener methods we are not interested in 189 public void mouseClicked(MouseEvent e) {} 190 public void mouseEntered(MouseEvent e) {} 191 public void mouseExited(MouseEvent e) {} 192 /** 193 * Handles mouse down events. The event is delegated to the 194 * currently active tool. 195 * @return whether the event was handled. 196 */ 197 public void mousePressed(MouseEvent e) { 198 if (tool()!=null) { 199 requestFocus(); // JDK1.1 200 Point p = constrainPoint(new Point(e.getX(), e.getY())); 201 fLastClick = new Point(e.getX(), e.getY()); 202 tool().mouseDown(e, p.x, p.y); 203 checkDamage(); 204 } 205 } 206 /** 207 * Handles mouse up events. The event is delegated to the 208 * currently active tool. 209 * @return whether the event was handled. 210 */ 211 public void mouseReleased(MouseEvent e) { 212 if (tool()!=null) { 213 Point p = constrainPoint(new Point(e.getX(), e.getY())); 214 tool().mouseUp(e, p.x, p.y); 215 checkDamage(); 216 } 217 } 218 }; 219 220 MouseMotionListener mml = new MouseMotionListener() { 221 /** 222 * Handles mouse drag events. The event is delegated to the 223 * currently active tool. 224 * @return whether the event was handled. 225 */ 226 public void mouseDragged(MouseEvent e) { 227 if (tool()!=null) { 228 Point p = constrainPoint(new Point(e.getX(), e.getY())); 229 tool().mouseDrag(e, p.x, p.y); 230 checkDamage(); 231 } 232 } 233 234 /** 235 * Handles mouse move events. The event is delegated to the 236 * currently active tool. 237 * @return whether the event was handled. 238 */ 239 public void mouseMoved(MouseEvent e) { 240 if (tool()!=null) { 241 tool().mouseMove(e, e.getX(), e.getY()); 242 } 243 } 244 }; 245 246 /** 247 * Sets the view's editor. 248 */ 249 public void setEditor(DrawingEditor editor) { 250 fEditor = editor; 251 } 252 253 /** 254 * Gets the current tool. 255 */ 256 public Tool tool() { 257 return editor().tool(); 258 } 259 260 /** 261 * Gets the drawing. 262 */ 263 public Drawing drawing() { 264 return fDrawing; 265 } 266 267 /** 268 * Sets and installs another drawing in the view. 269 */ 270 public void setDrawing(Drawing d) { 271 if (fDrawing != null) { 272 clearSelection(); 273 fDrawing.removeDrawingChangeListener(this); 274 } 275 fDrawing = d; 276 if (fDrawing != null) { 277 fDrawing.addDrawingChangeListener(this); 278 } 279 checkMinimumSize(); 280 repaint(); 281 } 282 283 /** 284 * Gets the editor. 285 */ 286 public DrawingEditor editor() { 287 return fEditor; 288 } 289 290 /** 291 * Adds a figure to the drawing. 292 * @return the added figure. 293 */ 294 public Figure add(Figure figure) { 295 return drawing().add(figure); 296 } 297 298 /** 299 * Removes a figure from the drawing. 300 * @return the removed figure 301 */ 302 public Figure remove(Figure figure) { 303 return drawing().remove(figure); 304 } 305 306 /** 307 * Adds a vector of figures to the drawing. 308 */ 309 public void addAll(Vector figures) { 310 FigureEnumeration k = new FigureEnumerator(figures); 311 while (k.hasMoreElements()) { 312 add(k.nextFigure()); 313 } 314 } 315 316 /** 317 * Check existance of figure in the drawing 318 */ 319 public boolean figureExists(Figure inf, FigureEnumeration e) { 320 while(e.hasMoreElements()) { 321 Figure figure = e.nextFigure(); 322 323 if(figure.includes(inf)) { 324 return true; 325 } 326 } 327 328 return false; 329 } 330 331 /** 332 * Inserts a vector of figures and translates them by the 333 * given offset. This function is used to insert figures from clipboards (cut/copy) 334 * 335 * @return enumeration which has been added to the drawing. The figures in the enumeration 336 * can have changed during adding them (e.g. they could have been decorated). 337 */ 338 public FigureEnumeration insertFigures(FigureEnumeration fe, int dx, int dy, boolean bCheck) { 339 if (fe == null) { 340 return FigureEnumerator.getEmptyEnumeration(); 341 } 342 343 Vector addedFigures = new Vector(); 344 Vector vCF = new Vector(10); 345 346 while (fe.hasMoreElements()) { 347 Figure figure = fe.nextFigure(); 348 if (figure instanceof ConnectionFigure) { 349 vCF.addElement(figure); 350 } 351 else if (figure != null) { 352 figure.moveBy(dx, dy); 353 figure = add(figure); 354 addToSelection(figure); 355 // figure might has changed during adding so add it afterwards 356 addedFigures.addElement(figure); 357 } 358 } 359 360 FigureEnumeration ecf = new FigureEnumerator(vCF); 361 362 while (ecf.hasMoreElements()) { 363 ConnectionFigure cf = (ConnectionFigure) ecf.nextFigure(); 364 Figure sf = cf.startFigure(); 365 Figure ef = cf.endFigure(); 366 367 if (figureExists(sf, drawing().figures()) && 368 figureExists(ef, drawing().figures()) && 369 (!bCheck || cf.canConnect(sf, ef))) { 370 371 if (bCheck) { 372 Point sp = sf.center(); 373 Point ep = ef.center(); 374 Connector fStartConnector = cf.startFigure().connectorAt(ep.x, ep.y); 375 Connector fEndConnector = cf.endFigure().connectorAt(sp.x, sp.y); 376 377 if (fEndConnector != null && fStartConnector != null) { 378 cf.connectStart(fStartConnector); 379 cf.connectEnd(fEndConnector); 380 cf.updateConnection(); 381 } 382 } 383 384 Figure nf = add(cf); 385 addToSelection(nf); 386 // figure might has changed during adding so add it afterwards 387 addedFigures.addElement(nf); 388 } 389 } 390 391 return new FigureEnumerator(addedFigures); 392 } 393 394 /** 395 * Returns a vector of connectionfigures attached to this figure 396 */ 397 public Vector getConnectionFigures(Figure inFigure) { 398 // If no figure or figure is non connectable, just return null 399 if (inFigure == null || !inFigure.canConnect()) { 400 return null; 401 } 402 403 // if (inFigure instanceof ConnectionFigure) 404 // return null; 405 406 Vector result = new Vector(5); 407 FigureEnumeration figures = drawing().figures(); 408 409 // Find all connection figures 410 while (figures.hasMoreElements()) { 411 Figure f= figures.nextFigure(); 412 413 if ((f instanceof ConnectionFigure) && !(isFigureSelected(f))) { 414 ConnectionFigure cf = (ConnectionFigure) f; 415 416 if (cf.startFigure().includes(inFigure) || 417 cf.endFigure().includes(inFigure)) { 418 result.addElement(f); 419 } 420 } 421 } 422 423 return result; 424 } 425 426 /** 427 * Gets the minimum dimension of the drawing. 428 */ 429 public Dimension getMinimumSize() { 430 return fViewSize; 431 } 432 433 /** 434 * Gets the preferred dimension of the drawing.. 435 */ 436 public Dimension getPreferredSize() { 437 return getMinimumSize(); 438 } 439 440 /** 441 * Sets the current display update strategy. 442 * @see Painter 443 */ 444 public void setDisplayUpdate(Painter updateStrategy) { 445 fUpdateStrategy = updateStrategy; 446 } 447 448 /** 449 * Sets the current display update strategy. 450 * @see Painter 451 */ 452 public Painter getDisplayUpdate() { 453 return fUpdateStrategy; 454 } 455 456 /** 457 * Gets the currently selected figures. 458 * @return a vector with the selected figures. The vector 459 * is a copy of the current selection. 460 */ 461 public Vector selection() { 462 // protect the vector with the current selection 463 return (Vector)fSelection.clone(); 464 } 465 466 /** 467 * Gets an enumeration over the currently selected figures. 468 */ 469 public FigureEnumeration selectionElements() { 470 return new FigureEnumerator(selectionZOrdered()); 471 } 472 473 /** 474 * Gets the currently selected figures in Z order. 475 * @see #selection 476 * @return a vector with the selected figures. The vector 477 * is a copy of the current selection. 478 */ 479 public Vector selectionZOrdered() { 480 Vector result = new Vector(selectionCount()); 481 FigureEnumeration figures = drawing().figures(); 482 483 while (figures.hasMoreElements()) { 484 Figure f= figures.nextFigure(); 485 if (isFigureSelected(f)) { 486 result.addElement(f); 487 } 488 } 489 return result; 490 } 491 492 /** 493 * Gets the number of selected figures. 494 */ 495 public int selectionCount() { 496 return fSelection.size(); 497 } 498 499 /** 500 * Test whether a given figure is selected. 501 */ 502 public boolean isFigureSelected(Figure checkFigure) { 503 return fSelection.contains(checkFigure); 504 } 505 506 /** 507 * Adds a figure to the current selection. The figure is only selected if 508 * it is also contained in the Drawing associated with this DrawingView. 509 */ 510 public void addToSelection(Figure figure) { 511 if (!isFigureSelected(figure) && drawing().includes(figure)) { 512 fSelection.addElement(figure); 513 fSelectionHandles = null; 514 figure.invalidate(); 515 fireSelectionChanged(); 516 } 517 } 518 519 /** 520 * Adds a vector of figures to the current selection. 521 */ 522 public void addToSelectionAll(Vector figures) { 523 addToSelectionAll(new FigureEnumerator(figures)); 524 } 525 526 /** 527 * Adds a FigureEnumeration to the current selection. 528 */ 529 public void addToSelectionAll(FigureEnumeration fe) { 530 while (fe.hasMoreElements()) { 531 addToSelection(fe.nextFigure()); 532 } 533 } 534 535 /** 536 * Removes a figure from the selection. 537 */ 538 public void removeFromSelection(Figure figure) { 539 if (isFigureSelected(figure)) { 540 fSelection.removeElement(figure); 541 fSelectionHandles = null; 542 figure.invalidate(); 543 fireSelectionChanged(); 544 } 545 } 546 547 /** 548 * If a figure isn't selected it is added to the selection. 549 * Otherwise it is removed from the selection. 550 */ 551 public void toggleSelection(Figure figure) { 552 if (isFigureSelected(figure)) { 553 removeFromSelection(figure); 554 } 555 else { 556 addToSelection(figure); 557 } 558 fireSelectionChanged(); 559 } 560 561 /** 562 * Clears the current selection. 563 */ 564 public void clearSelection() { 565 // there is nothing selected 566 if (fSelectionHandles == null) { 567 // avoid unnecessary selection changed event when nothing has to be cleared 568 return; 569 } 570 571 FigureEnumeration fe = selectionElements(); 572 while (fe.hasMoreElements()) { 573 fe.nextFigure().invalidate(); 574 } 575 fSelection = new Vector(); 576 fSelectionHandles = null; 577 fireSelectionChanged(); 578 } 579 580 /** 581 * Gets an enumeration of the currently active handles. 582 */ 583 private Enumeration selectionHandles() { 584 if (fSelectionHandles == null) { 585 fSelectionHandles = new Vector(); 586 FigureEnumeration k = selectionElements(); 587 while (k.hasMoreElements()) { 588 Figure figure = k.nextFigure(); 589 Enumeration kk = figure.handles().elements(); 590 while (kk.hasMoreElements()) { 591 fSelectionHandles.addElement(kk.nextElement()); 592 } 593 } 594 } 595 return fSelectionHandles.elements(); 596 } 597 598 /** 599 * Gets the current selection as a FigureSelection. A FigureSelection 600 * can be cut, copied, pasted. 601 */ 602 public FigureSelection getFigureSelection() { 603 return new StandardFigureSelection(new FigureEnumerator(selectionZOrdered()), selectionCount()); 604 } 605 606 /** 607 * Finds a handle at the given coordinates. 608 * @return the hit handle, null if no handle is found. 609 */ 610 public Handle findHandle(int x, int y) { 611 Handle handle; 612 613 Enumeration k = selectionHandles(); 614 while (k.hasMoreElements()) { 615 handle = (Handle) k.nextElement(); 616 if (handle.containsPoint(x, y)) { 617 return handle; 618 } 619 } 620 return null; 621 } 622 623 /** 624 * Informs that the current selection changed. 625 * By default this event is forwarded to the 626 * drawing editor. 627 */ 628 protected void fireSelectionChanged() { 629 if (fSelectionListeners != null) { 630 for (int i = 0; i < fSelectionListeners.size(); i++) { 631 FigureSelectionListener l = (FigureSelectionListener)fSelectionListeners.elementAt(i); 632 l.figureSelectionChanged(this); 633 } 634 } 635 } 636 637 /** 638 * Gets the position of the last click inside the view. 639 */ 640 public Point lastClick() { 641 return fLastClick; 642 } 643 644 /** 645 * Sets the grid spacing that is used to constrain points. 646 */ 647 public void setConstrainer(PointConstrainer c) { 648 fConstrainer = c; 649 } 650 651 /** 652 * Gets the current constrainer. 653 */ 654 public PointConstrainer getConstrainer() { 655 return fConstrainer; 656 } 657 658 /** 659 * Constrains a point to the current grid. 660 */ 661 protected Point constrainPoint(Point p) { 662 // constrin to view size 663 Dimension size = getSize(); 664 //p.x = Math.min(size.width, Math.max(1, p.x)); 665 //p.y = Math.min(size.height, Math.max(1, p.y)); 666 p.x = Geom.range(1, size.width, p.x); 667 p.y = Geom.range(1, size.height, p.y); 668 669 if (fConstrainer != null ) { 670 return fConstrainer.constrainPoint(p); 671 } 672 return p; 673 } 674 675 676 /** 677 * Handles key down events. Cursor keys are handled 678 * by the view the other key events are delegated to the 679 * currently active tool. 680 * @return whether the event was handled. 681 */ 682 public void keyPressed(KeyEvent e) { 683 int code = e.getKeyCode(); 684 if ((code == KeyEvent.VK_BACK_SPACE) || (code == KeyEvent.VK_DELETE)) { 685 // Do nothing, let DiagramView do that stuff. 686 } else if (code == KeyEvent.VK_DOWN || code == KeyEvent.VK_UP || 687 code == KeyEvent.VK_RIGHT || code == KeyEvent.VK_LEFT) { 688 handleCursorKey(code); 689 } else { 690 tool().keyDown(e, code); 691 } 692 checkDamage(); 693 } 694 695 /** 696 * Handles cursor keys by moving all the selected figures 697 * one grid point in the cursor direction. 698 */ 699 protected void handleCursorKey(int key) { 700 int dx = 0, dy = 0; 701 int stepX = 1, stepY = 1; 702 // should consider Null Object. 703 if (fConstrainer != null) { 704 stepX = fConstrainer.getStepX(); 705 stepY = fConstrainer.getStepY(); 706 } 707 708 switch (key) { 709 case KeyEvent.VK_DOWN: 710 dy = stepY; 711 break; 712 case KeyEvent.VK_UP: 713 dy = -stepY; 714 break; 715 case KeyEvent.VK_RIGHT: 716 dx = stepX; 717 break; 718 case KeyEvent.VK_LEFT: 719 dx = -stepX; 720 break; 721 } 722 moveSelection(dx, dy); 723 } 724 725 private void moveSelection(int dx, int dy) { 726 FigureEnumeration figures = selectionElements(); 727 while (figures.hasMoreElements()) { 728 figures.nextFigure().moveBy(dx, dy); 729 } 730 checkDamage(); 731 } 732 733 /** 734 * Refreshes the drawing if there is some accumulated damage 735 */ 736 public synchronized void checkDamage() { 737 } 738 739 public void repairDamage() { 740 if (fDamage != null) { 741 repaint(fDamage.x, fDamage.y, fDamage.width, fDamage.height); 742 fDamage = null; 743 } 744 } 745 746 public void drawingInvalidated(DrawingChangeEvent e) { 747 Rectangle r = e.getInvalidatedRectangle(); 748 if (fDamage == null) { 749 fDamage = r; 750 } else { 751 fDamage.add(r); 752 } 753 } 754 755 public void drawingRequestUpdate(DrawingChangeEvent e) { 756 repairDamage(); 757 } 758 759 /** 760 * Paints the drawing view. The actual drawing is delegated to 761 * the current update strategy. 762 * @see Painter 763 */ 764 protected void paintComponent(Graphics g) { 765 getDisplayUpdate().draw(g, this); 766 } 767 768 /** 769 * Draws the contents of the drawing view. 770 * The view has three layers: background, drawing, handles. 771 * The layers are drawn in back to front order. 772 */ 773 public void drawAll(Graphics g) { 774 boolean isPrinting = g instanceof PrintGraphics; 775 drawBackground(g); 776 if (fBackgrounds != null && !isPrinting) { 777 drawPainters(g, fBackgrounds); 778 } 779 drawDrawing(g); 780 if (fForegrounds != null && !isPrinting) { 781 drawPainters(g, fForegrounds); 782 } 783 if (!isPrinting) { 784 drawHandles(g); 785 } 786 } 787 788 /** 789 * Draws the given figures. 790 * The view has three layers: background, drawing, handles. 791 * The layers are drawn in back to front order. 792 * No background is drawn. 793 */ 794 public void draw(Graphics g, FigureEnumeration fe) { 795 boolean isPrinting = g instanceof PrintGraphics; 796 //drawBackground(g); 797 if (fBackgrounds != null && !isPrinting) { 798 drawPainters(g, fBackgrounds); 799 } 800 fDrawing.draw(g, fe); 801 if (fForegrounds != null && !isPrinting) { 802 drawPainters(g, fForegrounds); 803 } 804 if (!isPrinting) { 805 drawHandles(g); 806 } 807 } 808 809 /** 810 * Draws the currently active handles. 811 */ 812 public void drawHandles(Graphics g) { 813 Enumeration k = selectionHandles(); 814 while (k.hasMoreElements()) { 815 ((Handle) k.nextElement()).draw(g); 816 } 817 } 818 819 /** 820 * Draws the drawing. 821 */ 822 public void drawDrawing(Graphics g) { 823 fDrawing.draw(g); 824 } 825 826 /** 827 * Draws the background. If a background pattern is set it 828 * is used to fill the background. Otherwise the background 829 * is filled in the background color. 830 */ 831 public void drawBackground(Graphics g) { 832 g.setColor(getBackground()); 833 g.fillRect(0, 0, getBounds().width, getBounds().height); 834 } 835 836 private void drawPainters(Graphics g, Vector v) { 837 for (int i = 0; i < v.size(); i++) { 838 ((Painter)v.elementAt(i)).draw(g, this); 839 } 840 } 841 842 /** 843 * Adds a background. 844 */ 845 public void addBackground(Painter painter) { 846 if (fBackgrounds == null) { 847 fBackgrounds = new Vector(3); 848 } 849 fBackgrounds.addElement(painter); 850 repaint(); 851 } 852 853 /** 854 * Removes a background. 855 */ 856 public void removeBackground(Painter painter) { 857 if (fBackgrounds != null) { 858 fBackgrounds.removeElement(painter); 859 } 860 repaint(); 861 } 862 863 /** 864 * Removes a foreground. 865 */ 866 public void removeForeground(Painter painter) { 867 if (fForegrounds != null) { 868 fForegrounds.removeElement(painter); 869 } 870 repaint(); 871 } 872 873 /** 874 * Adds a foreground. 875 */ 876 public void addForeground(Painter painter) { 877 if (fForegrounds == null) { 878 fForegrounds = new Vector(3); 879 } 880 fForegrounds.addElement(painter); 881 repaint(); 882 } 883 884 /** 885 * Freezes the view by acquiring the drawing lock. 886 * @see Drawing#lock 887 */ 888 public void freezeView() { 889 drawing().lock(); 890 } 891 892 /** 893 * Unfreezes the view by releasing the drawing lock. 894 * @see Drawing#unlock 895 */ 896 public void unfreezeView() { 897 drawing().unlock(); 898 } 899 900 private void checkMinimumSize() { 901 FigureEnumeration k = drawing().figures(); 902 Dimension d = new Dimension(0, 0); 903 while (k.hasMoreElements()) { 904 Rectangle r = k.nextFigure().displayBox(); 905 d.width = Math.max(d.width, r.x+r.width); 906 d.height = Math.max(d.height, r.y+r.height); 907 } 908 if (fViewSize.height < d.height || fViewSize.width < d.width) { 909 fViewSize.height = d.height + SCROLL_OFFSET; 910 fViewSize.width = d.width + SCROLL_OFFSET; 911 setSize(fViewSize); 912 } 913 } 914 915 public boolean isFocusTraversable() { 916 return true; 917 } 918 919 public boolean isInteractive() { 920 return true; 921 } 922 923 public void keyTyped(KeyEvent e) {} 924 public void keyReleased(KeyEvent e) {} 925 926 /** 927 * Add a listener for selection changes. 928 * @param fsl jhotdraw.framework.FigureSelectionListener 929 */ 930 public void addFigureSelectionListener(FigureSelectionListener fsl) { 931 fSelectionListeners.add(fsl); 932 } 933 934 /** 935 * Remove a listener for selection changes. 936 * @param fsl jhotdraw.framework.FigureSelectionListener 937 */ 938 public void removeFigureSelectionListener(FigureSelectionListener fsl) { 939 fSelectionListeners.remove(fsl); 940 } 941 942 public int getDefaultDNDActions() { 943 return java.awt.dnd.DnDConstants.ACTION_COPY_OR_MOVE; 944 } 945 946 947 /***** Autoscroll support *****/ 948 private ASH ash = new ASH(10); 949 950 public void autoscroll(java.awt.Point p) { 951 ash.autoscroll(p); 952 } 953 public Insets getAutoscrollInsets() { 954 return ash.getAutoscrollInsets(); 955 } 956 class ASH extends AutoscrollHelper { 957 public ASH(int margin) { 958 super(margin); 959 } 960 public Dimension getSize() { 961 return IDEDrawingView.this.getSize(); 962 } 963 public Rectangle getVisibleRect() { 964 return IDEDrawingView.this.getVisibleRect(); 965 } 966 public void scrollRectToVisible(Rectangle aRect) { 967 IDEDrawingView.this.scrollRectToVisible(aRect); 968 } 969 } 970 971 public String toString() { 972 return "DrawingView Nr: " + myCounter; 973 } 974 975 static int counter; 976 int myCounter = counter; 977 }