1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * ident "%Z%%M% %I% %E% SMI" 24 * 25 * Copyright (c) 2000 by Sun Microsystems, Inc. 26 * All rights reserved. 27 */ 28 29 /* 30 * Copyright (C) 1996 Active Software, Inc. 31 * All rights reserved. 32 * 33 * @(#) Group.java 1.143 - last change made 07/25/97 34 */ 35 36 package sunsoft.jws.visual.rt.base; 37 38 import sunsoft.jws.visual.rt.awt.RootFrame; 39 import sunsoft.jws.visual.rt.shadow.*; 40 import sunsoft.jws.visual.rt.shadow.java.awt.*; 41 import sunsoft.jws.visual.rt.type.Converter; 42 import sunsoft.jws.visual.rt.type.AMConverter; 43 import sunsoft.jws.visual.rt.type.AMRef; 44 import sunsoft.jws.visual.rt.base.Global; 45 46 47 import java.awt.*; 48 import java.util.*; 49 import java.net.URL; 50 import java.applet.Applet; 51 52 /** 53 * The base class for every kind of group. 54 * <p> 55 * The attributes available for this 56 * class are listed below. In the type column, type names beginning 57 * with "sunsoft.jws.visual.rt" have been abbreviated to begin 58 * with "rt". 59 * 60 * <pre> 61 * name type default value 62 * --------------------------------------------------------------- 63 * visible java.lang.Boolean true 64 * < /pre> 65 * 66 * Check the super class for additional attributes. 67 * 68 * @version 1.143, 07/25/97 69 */ 70 public abstract class Group extends AttributeManager { 71 72 // Print the warning message only once. 73 private boolean warned = false; 74 75 /** 76 * This flag is used to detect when showGroup is called 77 * recursively during create. 78 * We don't want to execute the showGroup code twice 79 * because modal dialogs block during "show". 80 * This means that if 81 * show is called twice, the modal dialog will pop up 82 * again after it is hidden. 83 */ 84 private boolean doingShow = false; 85 86 /** 87 * This flag indicates whether or not the group is 88 * currently shown. 89 */ 90 private boolean isShowing = false; 91 92 /** 93 * This flag is set for forwarded attributes in a group. 94 */ 95 public static final int FORWARD = 0x100; 96 97 /** 98 * This flag is set for forwarded attributes that will 99 * be removed during initialization if the group's 100 * container does not define the attribute. 101 */ 102 public static final int FORWARD_REMOVE = 0x200; 103 104 /** 105 * This constant can be passed to the setCursor call. 106 * It indicates 107 * that the cursor should be restored to its previous value. 108 */ 109 public static final int RESTORE_CURSOR = 50000; 110 111 public static final int BACKSPACE_KEY = 8; 112 public static final int TAB_KEY = 9; 113 public static final int RETURN_KEY = 10; 114 public static final int ESCAPE_KEY = 27; 115 public static final int DELETE_KEY = 127; 116 117 // The root of the shadow tree. 118 private Root root; 119 120 /** 121 * Set to true when this group is initialized. 122 */ 123 private boolean isInitialized; 124 125 /** 126 * Set to true when this group has been started, but 127 * has not yet been stopped. 128 */ 129 private boolean isStarted = false; 130 131 /** 132 * Parent group for this group. 133 */ 134 private Group parentGroup = null; 135 136 private Vector children = new Vector(); 137 138 // Operations 139 private Vector operations = null; 140 141 /** 142 * Time Bomb 143 */ checkDate()144 private void checkDate() { 145 // August 1, 1996 : 838882801 146 // August 15, 1996 : 840092401 147 // October 15, 1996 : 845362801 148 149 Date date = new Date(840092401000L); 150 if (System.currentTimeMillis() >= 840092401000L) { 151 throw new Error(Global.getMsg( 152 "sunsoft.jws.visual.rt.base.Group.ExpiredVersion")); 153 } else if (!warned) { 154 warned = true; 155 System.out.println(Global.fmtMsg( 156 "sunsoft.jws.visual.rt.base.Group.ExpiredVersionDate", 157 date.toString())); 158 } 159 } 160 161 // NOTE: Any changes made to this comment should also 162 // be made in the lib/visual/gen/group.java file. 163 /** 164 * All the attributes used by this group must be defined in the 165 * constructor. setOnGroup is called at initialization for all 166 * the attributes. If the attribute has not been set prior to 167 * initialization, setOnGroup is called with the default value. 168 */ Group()169 public Group() { 170 // The "visible" attribute MUST have the DEFAULT 171 // flag set! We don't want "visible" 172 // being set during initialization. 173 attributes.add(/* NOI18N */"visible", 174 /* NOI18N */"java.lang.Boolean", Boolean.TRUE, DEFAULT); 175 } 176 177 /** 178 * Initialize the group. The shadow tree for the group 179 * is created during initialization. 180 */ initialize()181 public void initialize() { 182 boolean wasInitialized = isInitialized; 183 184 if (!isInitialized) { 185 if (!hasEnvironment()) { 186 throw new Error(Global.getMsg( 187 "sunsoft.jws.visual.rt.base.Group.GroupInitializationWarning")); 188 } 189 190 isInitialized = true; 191 192 /** 193 * AMREF: We could have started a recording of all 194 * new AMRef's 195 * here, but it's a performance hit that doesn't buy us 196 * anything, the user shouldn't be making AMRef's 197 * that point to 198 * an object by a certain name, changing the name 199 * of that object, and expecting it to work. 200 * The stopRecording call 201 * further down goes with this call. 202 */ 203 // AMRef.startRecording(); 204 205 root = initRoot(); 206 207 if (root == null && !(this instanceof NVGroup)) 208 throw new Error(Global.fmtMsg( 209 "sunsoft.jws.visual.rt.base.Group.RootIsNull", this.getClass().getName())); 210 211 /** AMREF: resolves all AMRef's loaded */ 212 // AMRef.stopRecording(root); 213 214 removeForwardedAttributes(); 215 216 initGroup(); 217 218 if (operations != null) { 219 Enumeration e = operations.elements(); 220 while (e.hasMoreElements()) { 221 Operations ops = 222 (Operations)e.nextElement(); 223 ops.setRoot(root); 224 } 225 } 226 } 227 228 // Initialize the visible sub-groups 229 Enumeration e = getChildList(); 230 while (e.hasMoreElements()) { 231 Group child = (Group)e.nextElement(); 232 if (wouldBeVisible(child)) 233 child.initialize(); 234 } 235 236 if (!wasInitialized) { 237 // Set attributes on the newly initialized group 238 e = attributes.elements(); 239 while (e.hasMoreElements()) { 240 Attribute a = (Attribute) e.nextElement(); 241 String name = a.getName(); 242 243 if (a.isModified() || 244 !a.flagged(DEFAULT | READONLY)) { 245 set(name, a.getValue()); 246 } 247 } 248 249 if (isLayoutMode()) { 250 WindowShadow s = getWindow(); 251 if (s != null) 252 s.setLayout(true); 253 } 254 } 255 } 256 257 /** 258 * Returns true if the group is currently initialized. 259 */ isInitialized()260 public boolean isInitialized() { 261 return isInitialized; 262 } 263 264 // NOTE: Any changes made to this comment should 265 // also be made in the 266 // lib/visual/gen/group.java file. 267 /** 268 * initRoot must be overridden in group subclasses to 269 * initialize the shadow tree. The return value must be the 270 * root of the newly initialized shadow tree. 271 */ initRoot()272 protected abstract Root initRoot(); 273 274 // NOTE: Any changes made to this comment should 275 // also be made in the 276 // lib/visual/gen/group.java file. 277 /** 278 * Called during initialization. It is called just after 279 * initRoot is called, but before the sub-groups 280 * are initialized and 281 * before the attributes are sent to the setOnGroup method. 282 * 283 * initGroup is only called once in the lifetime of the Group. 284 * This is because groups cannot be uninitialized. 285 * Anything that 286 * needs to be cleaned up should be created in 287 * createGroup instead 288 * of initGroup, and then can be cleaned up in destroyGroup. 289 * createGroup and destroyGroup may be called multiple 290 * times during 291 * the lifetime of a group. 292 */ initGroup()293 protected void initGroup() {}; 294 295 /** 296 * Returns a type name for this group to be used by visual java. 297 * May be overridden in sub-classes to give more useful names. 298 */ getUserTypeName()299 protected String getUserTypeName() { 300 return (Converter.shortClassName(getClass().getName()).toLowerCase()); 301 } 302 303 /** 304 * Returns the main container for this group. This can 305 * be either a WindowShadow or a PanelShadow. 306 */ getContainer()307 public ContainerShadow getContainer() { 308 if (root == null) 309 return null; 310 311 AttributeManager mgr = root.getMainChild(); 312 if (mgr == null) 313 return null; 314 else if (mgr instanceof ContainerShadow) 315 return (ContainerShadow)mgr; 316 else if (mgr instanceof Group) 317 return ((Group)mgr).getContainer(); 318 else 319 throw new Error(Global.fmtMsg( 320 "sunsoft.jws.visual.rt.base.Group.UnexpectedMainChildType", 321 mgr)); 322 } 323 324 /** 325 * Returns the main panel for this group. Returns 326 * null if the main container is not a panel. 327 */ getPanel()328 public PanelShadow getPanel() { 329 ContainerShadow c = getContainer(); 330 if (c instanceof PanelShadow) 331 return (PanelShadow)c; 332 else 333 return null; 334 } 335 336 /** 337 * Returns the main window for this group. Returns 338 * null if the main container is not a window. 339 */ getWindow()340 public WindowShadow getWindow() { 341 ContainerShadow c = getContainer(); 342 if (c instanceof WindowShadow) 343 return (WindowShadow)c; 344 else 345 return null; 346 } 347 348 /** 349 * Calls show or hide, depending on the value of cond. 350 */ show(boolean cond)351 public void show(boolean cond) { 352 if (cond) 353 show(); 354 else 355 hide(); 356 } 357 358 /** 359 * Shows the group by setting the visible attribute to true. 360 */ show()361 public void show() { 362 set(/* NOI18N */"visible", Boolean.TRUE); 363 } 364 365 /** 366 * Hides the group by setting the visible attribute to false. 367 */ hide()368 public void hide() { 369 set(/* NOI18N */"visible", Boolean.FALSE); 370 } 371 372 /** 373 * Returns true if the group is currently visible. 374 * 375 * If the application has not yet been fully initialized 376 * and created, 377 * then isVisible may return true for a group that is not yet 378 * visible on the screen. This means that by the time the 379 * initialization is complete, the group will be visible 380 * on the screen. 381 */ isVisible()382 public boolean isVisible() { 383 Group base = getBase(); 384 if (base == null) 385 return false; 386 else 387 return base.wouldBeVisible(this); 388 } 389 390 /** 391 * Returns true if the child group passed as a parameter 392 * will be visible 393 * when this group is made visible. If the group parameter 394 * is not a 395 * child of this group, then the return value will be false. 396 */ wouldBeVisible(Group group)397 public boolean wouldBeVisible(Group group) { 398 while (group != null && group != this) { 399 Boolean v = (Boolean)group.get(/* NOI18N */"visible"); 400 if (!v.booleanValue()) 401 return false; 402 403 AttributeManager mgr = (AttributeManager)group.getParent(); 404 while (!(mgr instanceof Root)) { 405 v = (Boolean)mgr.get(/* NOI18N */"visible"); 406 if (!v.booleanValue()) 407 return false; 408 mgr = (AttributeManager)mgr.getParent(); 409 } 410 411 if (mgr == null) 412 return false; 413 414 group = ((Root)mgr).getGroup(); 415 } 416 417 if (group == null) 418 return false; 419 420 return true; 421 } 422 423 /** 424 * Returns true if the group is currently showing. 425 */ isShowing()426 public boolean isShowing() { 427 return isShowing; 428 } 429 430 /** 431 * The only reason that this method exists if because 432 * the FrameEditor 433 * bypasses the visible attribute, and calls internalShowGroup 434 * directly. This means that the group becomes visible 435 * even though 436 * the visible attribute is set to false. In this situation, we 437 * still want the isVisible call for child groups to 438 * return true, 439 * hence the need for the isContainerVisible method. 440 */ isContainerVisible()441 private boolean isContainerVisible() { 442 if (inDesignerRoot()) { 443 ComponentShadow s = getContainer(); 444 if (s == null) 445 return false; 446 447 Component comp = (Component)s.getBody(); 448 if (comp == null) 449 return false; 450 451 return comp.isVisible(); 452 } else { 453 return false; 454 } 455 } 456 457 // NOTE: Any changes made to this comment should also 458 // be made in the 459 // lib/visual/gen/group.java file. 460 /** 461 * May be overridden by group subclasses that want 462 * to know when the group becomes visible. 463 * It is called just before 464 * the group becomes visible. 465 * The group will already be initialized 466 * and created at this point. 467 */ showGroup()468 protected void showGroup() { 469 } 470 471 /** 472 * Shows the group. Calling internalShowGroup does 473 * not affect the 474 * value of the visible attribute. 475 */ internalShowGroup()476 void internalShowGroup() { 477 Group base = null; 478 479 // Initialize ourselves if we haven't been initialized yet 480 if (!isInitialized) { 481 base = getBase(); 482 if (base != null) 483 base.setCursor(Frame.WAIT_CURSOR); 484 485 initialize(); 486 } 487 488 // Create ourselves if we haven't been created yet 489 if (!isCreated) { 490 doingShow = true; 491 create(); 492 doingShow = false; 493 } 494 495 if (!isShowing) { 496 isShowing = true; 497 498 if (root != null) 499 showGroup(); 500 501 // showGroup might call hide (trust me, it can happen) 502 if (!isShowing) 503 return; 504 } 505 506 // 507 // Invoke "show" on all the child groups that 508 // are not directly 509 // descended from the root. This solves two problems: 510 // 511 // 1) Panel groups are not immediate children of the root, 512 // therefore showRoot does not show the panel groups. 513 // 514 // 2) Some of the groups may not yet be created due 515 // to delayed 516 // instantiation. Calling internalShowGroup 517 // on these groups 518 // will cause them to be initialized and created, as well as 519 // shown. For example, say that this group was created while 520 // its visible attribute was set to false. This means that 521 // none of its child groups would be created because 522 // isVisible 523 // would return false for them. 524 // Now say that visibile is set 525 // to true for this group, causing internalShowGroup to be 526 // called. At this point, the child groups need to be 527 // initialized, created and shown, because now 528 // isVisible will 529 // return true for them. 530 // 531 // Note that this needs to be done before the call 532 // to showRoot. 533 // This is because panel groups must be created 534 // before the frames 535 // that contain them are shown in showRoot,or else the frame 536 // will come up the wrong size. 537 // 538 Enumeration e = children.elements(); 539 while (e.hasMoreElements()) { 540 Group child = (Group)e.nextElement(); 541 if (wouldBeVisible(child) && child.getParent() != root) 542 child.internalShowGroup(); 543 } 544 545 // Invoke "show" on all the children of the root 546 if (root != null) 547 root.showRoot(); 548 549 // Start the group if it isn't already started 550 if (hasStarted() && !isStarted) 551 start(); 552 553 // Revert the cursor 554 if (base != null) 555 base.setCursor(RESTORE_CURSOR); 556 } 557 558 // NOTE: Any changes made to this comment should 559 // also be made in the 560 // lib/visual/gen/group.java file. 561 /** 562 * May be overridden by group subclasses that want 563 * to know when the group becomes non-visible. 564 * It is called just 565 * before the group becomes non-visible. 566 */ hideGroup()567 protected void hideGroup() { 568 } 569 570 /** 571 * Hides the group. Calling hideGroup does not affect the 572 * value of the visible attribute. 573 * You should normally use "hide" 574 * instead of "hideGroup" so that the visible attribute is 575 * properly 576 * updated. 577 */ internalHideGroup()578 void internalHideGroup() { 579 if (!isInitialized) 580 return; 581 582 if (isShowing) { 583 isShowing = false; 584 if (root != null) 585 hideGroup(); 586 } 587 588 // Invoke "hide" on all the child groups 589 Enumeration e = children.elements(); 590 while (e.hasMoreElements()) { 591 Group group = (Group)e.nextElement(); 592 if (group.getParent() != root) 593 group.internalHideGroup(); 594 } 595 596 // Invoke "hide" on all the children of the root 597 if (root != null) 598 root.hideRoot(); 599 } 600 601 // 602 // Create and Destroy - Life span of the shadow bodies 603 // 604 605 /** 606 * Create the group. Creating the group causes 607 * all the AWT components 608 * to be created. Also, the createGroup method is called during 609 * group creation. 610 */ create()611 public void create() { 612 // Initialize ourselves if we haven't been initialized yet 613 if (!isInitialized) 614 initialize(); 615 616 if (!hasBase()) { 617 throw new Error(Global.getMsg( 618 "sunsoft.jws.visual.rt.base.Group.GroupCreationWarning")); 619 } 620 621 boolean wasCreated = isCreated; 622 boolean tmpShow = doingShow; 623 boolean shouldShow = false; 624 625 if (!wasCreated && !doingShow() && isVisible()) { 626 // Set the doingShow flag to true so that the windows 627 // under the 628 // root will not show while they are being created. 629 // We want to 630 // have them wait to be shown until internalShowGroup 631 // is called. 632 doingShow = true; 633 shouldShow = true; 634 } 635 636 super.create(); 637 638 if (root == null && !(this instanceof NVGroup)) 639 throw new Error(Global.getMsg( 640 "sunsoft.jws.visual.rt.base.Group.RootIsNull2")); 641 642 if (root != null) 643 root.create(); 644 645 if (!wasCreated) { 646 createGroup(); 647 648 // Show the group if it is visible 649 if (shouldShow) 650 internalShowGroup(); 651 } 652 653 doingShow = tmpShow; 654 } 655 656 // NOTE: Any changes made to this comment should 657 // also be made in the 658 // lib/visual/gen/group.java file. 659 /** 660 * Called during group creation. Groups can be 661 * created and destroyed multiple times during their lifetime. 662 * Anything that is created in createGroup should be cleaned up 663 * in destroyGroup. createGroup is called just after the group 664 * has been created. Anything that needs to be done before the 665 * group is created should be done in initGroup. 666 */ createGroup()667 protected void createGroup() {} 668 669 /** 670 * Destroy the group. This will destroy all AWT components, but 671 * does not destroy the shadow tree or the group tree. The group 672 * can be created again after a destroy by calling the "create" 673 * method. 674 */ destroy()675 public void destroy() { 676 if (!isInitialized) 677 return; 678 679 stop(); 680 681 if (isCreated) 682 destroyGroup(); 683 684 super.destroy(); 685 686 if (root != null) 687 root.destroy(); 688 } 689 690 // NOTE: Any changes made to this comment should also 691 // be made in the 692 // lib/visual/gen/group.java file. 693 /** 694 * Called during the destroy operation. Groups can 695 * be created and destroyed multiple times during their 696 * lifetime. 697 * Anything that has been created in createGroup should be 698 * cleaned up 699 * in destroyGroup. destroyGroup is called just before the 700 * group 701 * is destroyed. 702 */ destroyGroup()703 protected void destroyGroup() {} 704 705 // 706 // start/stop 707 // 708 709 /** 710 * This method should not be overridden by group subclasses. 711 * The "startGroup" method should be overridden instead. 712 */ start()713 public void start() { 714 if (!isInitialized) 715 return; 716 717 if (!isCreated) 718 create(); 719 720 if (!isStarted) { 721 isStarted = true; 722 startGroup(); 723 } 724 725 Enumeration e = children.elements(); 726 while (e.hasMoreElements()) { 727 Group child = (Group)e.nextElement(); 728 if (wouldBeVisible(child)) 729 child.start(); 730 } 731 } 732 733 // NOTE: Any changes made to this comment should also 734 // be made in the 735 // lib/visual/gen/group.java file. 736 /** 737 * May be overridden by group subclasses that want 738 * to be informed when the application is starting. 739 * This method is 740 * only called after the entire application has been 741 * initialized and created. 742 * 743 * For applets, startGroup is called whenever start 744 * is called on the applet. 745 */ startGroup()746 protected void startGroup() {} 747 748 /** 749 * Returns true if the group is currently started. 750 */ isStarted()751 public boolean isStarted() { 752 return isStarted; 753 } 754 755 /** 756 * This method should not be overridden by group subclasses. 757 * The "stopGroup" method should be overridden instead. 758 */ stop()759 public void stop() { 760 if (!isInitialized) 761 return; 762 763 if (isStarted) { 764 isStarted = false; 765 stopGroup(); 766 } 767 768 Enumeration e = children.elements(); 769 while (e.hasMoreElements()) 770 ((Group)e.nextElement()).stop(); 771 } 772 773 // NOTE: Any changes made to this comment should also 774 // be made in the 775 // lib/visual/gen/group.java file. 776 /** 777 * May be overridden by group subclasses that want 778 * to be informed when the application is stopping. This method 779 * will be called before a destroy is done. 780 * 781 * For applets, stopGroup is called whenever stop is called 782 * on the applet. 783 */ stopGroup()784 protected void stopGroup() {} 785 786 /** 787 * Returns true if the base group has been started. 788 */ hasStarted()789 protected boolean hasStarted() { 790 if (isBase()) { 791 return isStarted; 792 } else if (parentGroup != null) { 793 return parentGroup.hasStarted(); 794 } else { 795 return false; 796 } 797 } 798 799 // 800 // Group tree - An group can be either a node or a leaf. 801 // 802 add(Group child)803 void add(Group child) { 804 if (!children.contains(child)) { 805 child.setParentGroup(this); 806 children.addElement(child); 807 } 808 } 809 remove(Group child)810 void remove(Group child) { 811 if (children.contains(child)) { 812 child.setParentGroup(null); 813 children.removeElement(child); 814 } 815 } 816 addRootChildren(Root root)817 void addRootChildren(Root root) { 818 addChildren((AMContainer)root); 819 } 820 addChildren(AMContainer cntr)821 private void addChildren(AMContainer cntr) { 822 Enumeration e = cntr.getChildList(); 823 while (e.hasMoreElements()) { 824 AttributeManager child = (AttributeManager)e.nextElement(); 825 if (child instanceof Group) 826 add((Group)child); 827 if (child instanceof AMContainer) 828 addChildren((AMContainer)child); 829 } 830 } 831 removeRootChildren(Root root)832 void removeRootChildren(Root root) { 833 Enumeration e = children.elements(); 834 while (e.hasMoreElements()) { 835 Group child = (Group)e.nextElement(); 836 if (child.getRoot() == root) 837 remove(child); 838 } 839 } 840 841 /** 842 * Looks up a named child group of this group. Not recursive. 843 */ getChild(String name)844 public Group getChild(String name) { 845 for (Enumeration e = children.elements(); e.hasMoreElements(); ) 846 { 847 Group child = (Group)e.nextElement(); 848 if (name.equals(child.get(/* NOI18N */"name"))) 849 return (child); 850 } 851 return (null); 852 } 853 854 /** 855 * Returns an enumerated list of this group's children. The list 856 * is cloned because the caller might use it for removing child 857 * groups from this group. 858 */ getChildList()859 public Enumeration getChildList() { 860 return ((Vector)children.clone()).elements(); 861 } 862 setParentGroup(Group parent)863 private void setParentGroup(Group parent) { 864 parentGroup = parent; 865 } 866 867 /** 868 * Returns this group's parent. 869 */ getParentGroup()870 public Group getParentGroup() { 871 return parentGroup; 872 } 873 874 /** 875 * Returns this group (overrides the behavior of getGroup 876 * as defined in AttributeManager). 877 */ getGroup()878 public Group getGroup() { 879 return this; 880 } 881 882 /** 883 * Returns a hierarchy name based on the group tree. 884 */ getFullName()885 public String getFullName() { 886 String name = getName(); 887 if (name == null) 888 return null; 889 890 if (parentGroup != null) { 891 String parentName = parentGroup.getFullName(); 892 if (parentName != null) 893 name = parentName + /* NOI18N */"." + name; 894 } 895 896 return name; 897 } 898 899 /** 900 * Find a component from its full path name. 901 */ resolveFullName(String name)902 public AttributeManager resolveFullName(String name) { 903 AttributeManager mgr = null; 904 Group group = this; 905 Group newGroup; 906 907 while (group != null && !group.isBase()) 908 group = group.parentGroup; 909 if (group == null) 910 return null; 911 912 StringTokenizer st = new StringTokenizer(name, /* NOI18N */"."); 913 914 if (group.getName() != null) { 915 if (!st.hasMoreTokens()) 916 return null; 917 918 name = st.nextToken(); 919 if (!name.equals(group.getName())) 920 return null; 921 } 922 923 while (st.hasMoreTokens()) { 924 name = st.nextToken(); 925 newGroup = group.resolveGroup(name); 926 927 if (newGroup == null) { 928 if (group.root == null) 929 return null; 930 931 mgr = group.root.resolve(name); 932 break; 933 } else { 934 group = newGroup; 935 } 936 } 937 938 if (st.hasMoreTokens()) 939 return null; 940 941 return mgr; 942 } 943 944 /** 945 * Recursively looks for a named sub-group of this group. 946 */ resolveGroup(String name)947 public Group resolveGroup(String name) { 948 Group group; 949 String groupName; 950 951 Enumeration e = children.elements(); 952 while (e.hasMoreElements()) { 953 group = (Group)e.nextElement(); 954 groupName = group.getName(); 955 if (groupName != null && 956 groupName.equals(name)) { 957 return group; 958 } 959 } 960 961 return null; 962 } 963 964 // 965 // AWT parenting 966 // 967 setParentBody()968 void setParentBody() { 969 if (root != null) 970 root.addChildBody(getContainer()); 971 } 972 unsetParentBody()973 void unsetParentBody() { 974 if (root != null) 975 root.removeChildBody(getContainer()); 976 } 977 978 /** 979 * Add an operations class. 980 */ addOperations(Operations ops)981 public synchronized void addOperations(Operations ops) { 982 if (operations == null) 983 operations = new Vector(); 984 985 if (!operations.contains(ops)) { 986 ops.setGroup(this); 987 if (root != null) 988 ops.setRoot(root); 989 operations.addElement(ops); 990 } 991 } 992 993 /** 994 * Remove an operations class. 995 */ removeOperations(Operations ops)996 public synchronized void removeOperations(Operations ops) { 997 if (operations != null) 998 operations.removeElement(ops); 999 } 1000 1001 // 1002 // Events 1003 // 1004 1005 /** 1006 * Posts a message to this group's parent. This method should 1007 * be used when sending a message from within this group. 1008 */ postMessageToParent(Message msg)1009 public void postMessageToParent(Message msg) { 1010 if (parentGroup != null) 1011 parentGroup.postMessage(msg); 1012 } 1013 1014 /** 1015 * Posts a message to this group. This method should 1016 * be used when sending a message to this group. 1017 */ postMessage(Message msg)1018 public void postMessage(Message msg) { 1019 // Distribute the message to the operations classes 1020 if (operations != null) { 1021 Enumeration e = operations.elements(); 1022 while (e.hasMoreElements()) { 1023 Operations ops = (Operations)e.nextElement(); 1024 if (ops.handleMessage(msg)) 1025 return; 1026 } 1027 } 1028 1029 // Handle the message 1030 if (handleMessage(msg)) 1031 return; 1032 1033 // Don't pass AWT events up to the parent. If you want 1034 // an AWT event 1035 // to go to the parent group, call 1036 // "parent.postEvent()" directly. 1037 if (!msg.isAWT && parentGroup != null) 1038 parentGroup.postMessage(msg); 1039 } 1040 1041 // NOTE: Any changes made to this comment should also be 1042 // made in the 1043 // lib/visual/gen/group.java file. 1044 /** 1045 * May be overridden by subclasses that want to act 1046 * on messages that are sent to the group. 1047 * Typically, messages are 1048 * either AWT events that have been translated to 1049 * messages, or they 1050 * are messages that have been sent by other groups. 1051 * super.handleMessage should be called for any messages 1052 * that aren't handled. If super.handleMessage is not 1053 * called, then handleEvent 1054 * will not be called. 1055 * <p> 1056 * AWT events are not propagated regardless of the return 1057 * value from 1058 * handleEvent. If you want an AWT event to go to the parent 1059 * group, you need to call postMessageToParent() 1060 * with the event message. 1061 * <p> 1062 */ handleMessage(Message msg)1063 public boolean handleMessage(Message msg) { 1064 if (msg.isAWT) { 1065 Event evt = (Event)msg.arg; 1066 1067 handleEvent(msg, evt); 1068 1069 // Post AcceleratorKey messages for certain keys 1070 if (evt.id == Event.KEY_PRESS && evt.key != 0 && 1071 (evt.key < 32 || evt.key >= 127)) { 1072 postMessage(new Message(this, 1073 /* NOI18N */"AcceleratorKey", evt)); 1074 } 1075 1076 return true; 1077 } 1078 1079 return false; 1080 } 1081 1082 // NOTE: Any changes made to this comment should also be 1083 // made in the 1084 // lib/visual/gen/group.java file. 1085 /** 1086 * May be overridden by subclasses that want to get 1087 * notified when AWT events that are sent by the gui components. 1088 * The return value should be true for handled events, and 1089 * super.handleEvent should be called for unhandled events. 1090 * If super.handleEvent is not called, then the specific event 1091 * handling methods will not be called. 1092 * <p> 1093 * The message's target is set to the shadow that sent 1094 * the event. 1095 * The event's target is set to the AWT component that 1096 * sent the event. 1097 * <p> 1098 * The following more specific methods may also be overridden: 1099 * <pre> 1100 * public boolean mouseDown(Message msg, 1101 * Event evt, int x, int y); 1102 * public boolean mouseDrag(Message msg, Event evt, 1103 * int x, int y); 1104 * public boolean mouseUp(Message msg, Event evt, int x, int y); 1105 * public boolean mouseMove(Message msg, Event evt, 1106 * int x, int y); 1107 * public boolean mouseEnter(Message msg, Event evt, 1108 * int x, int y); 1109 * public boolean mouseExit(Message msg, Event evt, 1110 * int x, int y); 1111 * public boolean keyDown(Message msg, Event evt, int key); 1112 * public boolean keyUp(Message msg, Event evt, int key); 1113 * public boolean action(Message msg, Event evt, Object what); 1114 * public boolean gotFocus(Message msg, Event evt, Object what); 1115 * public boolean lostFocus(Message msg, 1116 * Event evt, Object what); 1117 * </pre> 1118 */ handleEvent(Message msg, Event evt)1119 public boolean handleEvent(Message msg, Event evt) { 1120 if (super.handleEvent(msg, evt)) 1121 return true; 1122 1123 // Intercept some of the WINDOW events. 1124 // Sub-groups that want to do 1125 // something different with these WINDOW events 1126 // should return true 1127 // after handling the event. 1128 1129 switch (evt.id) { 1130 case Event.WINDOW_DESTROY: 1131 windowDestroy(msg); 1132 return true; 1133 1134 case Event.WINDOW_ICONIFY: 1135 if (evt.target instanceof Window) { 1136 if (isBaseWindow((Window)evt.target)) { 1137 hide(); 1138 return true; 1139 } 1140 } 1141 return false; 1142 1143 case Event.WINDOW_DEICONIFY: 1144 if (evt.target instanceof Window) { 1145 if (isBaseWindow((Window)evt.target)) { 1146 show(); 1147 return true; 1148 } 1149 } 1150 return false; 1151 } 1152 1153 return false; 1154 } 1155 1156 /** 1157 * Exit the application with no error code. 1158 */ exit()1159 public void exit() { 1160 exit(0); 1161 } 1162 1163 /** 1164 * Exit the application. Calls exit on the parent 1165 * if there is a parent. 1166 * Only calls System.exit() if there is no applet. 1167 */ exit(int errCode)1168 public void exit(int errCode) { 1169 if (isBase()) { 1170 destroy(); 1171 if (applet == null) 1172 System.exit(errCode); 1173 } else if (parentGroup != null) { 1174 parentGroup.exit(errCode); 1175 } else { 1176 destroy(); 1177 } 1178 } 1179 1180 /** 1181 * Called when a WINDOW_DESTROY event is received by this group. 1182 * The default behavior for WINDOW_DESTROY events is to 1183 * set the visible 1184 * attribute to false for the target of the event. 1185 * If the target of 1186 * the event is the main window, then set this group's 1187 * visible attribute 1188 * to false. If this group is the base group, then exit the 1189 * application. 1190 */ windowDestroy(Message msg)1191 protected void windowDestroy(Message msg) { 1192 if (msg.target == getContainer()) { 1193 if (inDesignerRoot()) 1194 internalHideGroup(); 1195 else if (isBase()) 1196 exit(); 1197 else 1198 hide(); 1199 } else { 1200 if (msg.target instanceof AttributeManager) 1201 ((AttributeManager)msg.target).set(/* NOI18N */"visible", 1202 Boolean.FALSE); 1203 else if (msg.target instanceof Component) 1204 ((Component)msg.target).hide(); 1205 } 1206 } 1207 1208 /** 1209 * Attribute forwarding 1210 */ 1211 1212 private Vector forwardVector = new Vector(); 1213 1214 /** 1215 * Adds the attribute manager to the list of forwards. When 1216 * an attribute is set and is flagged FORWARD, the value for the 1217 * attribute will be forwarded to every matching attribute 1218 * manager 1219 * in the list of forwards. 1220 */ addAttributeForward(AttributeManager mgr)1221 protected void addAttributeForward(AttributeManager mgr) { 1222 if (forwardVector.contains(mgr)) 1223 return; 1224 1225 // Add this guy to the list of attribute forwards 1226 forwardVector.addElement(mgr); 1227 1228 // Override values in mgr with values from forwards 1229 Enumeration e = attributes.attributesWithFlags(FORWARD); 1230 1231 while (e.hasMoreElements()) { 1232 Attribute attr = (Attribute)e.nextElement(); 1233 String name = attr.getName(); 1234 String type = attr.getType(); 1235 1236 if (mgr.hasAttribute(name, type)) { 1237 Object value = mgr.get(name); 1238 1239 if (!attr.flagged(READONLY)) { 1240 if (!attr.isModified()) 1241 putInTable(name, value); 1242 else 1243 if (!mgr.getAttribute(name).flagged(READONLY)) 1244 mgr.set(name, attr.getValue()); 1245 } 1246 1247 attr.setDefaultValue(value); 1248 } 1249 } 1250 } 1251 1252 /** 1253 * Adds a set of attributes to this group that 1254 * are suitable for forwarding to a frame, dialog or panel. 1255 */ addForwardedAttributes()1256 protected void addForwardedAttributes() { 1257 if (genericAttrList == null) { 1258 genericAttrList = new AttributeList(); 1259 mergeForward(genericAttrList, new VJPanelShadow()); 1260 mergeForward(genericAttrList, new FrameShadow()); 1261 mergeForward(genericAttrList, new DialogShadow()); 1262 } 1263 1264 Enumeration e = genericAttrList.elements(); 1265 while (e.hasMoreElements()) { 1266 Attribute attr = (Attribute)e.nextElement(); 1267 if (!hasAttribute(attr.getName())) 1268 attributes.add((Attribute)attr.clone()); 1269 } 1270 1271 if (!hasAttribute(/* NOI18N */"text")) 1272 attributes.alias(/* NOI18N */"text", /* NOI18N */"title"); 1273 } 1274 mergeForward(AttributeList list, Shadow shadow)1275 private void mergeForward(AttributeList list, Shadow shadow) { 1276 AttributeList shadowList = 1277 (AttributeList)shadow.getAttributeList().clone(); 1278 Enumeration e = shadowList.elements(); 1279 1280 while (e.hasMoreElements()) { 1281 Attribute attr = (Attribute)e.nextElement(); 1282 if (!list.contains(attr.getName())) { 1283 // System.out.println(/* NOI18N */"add " + 1284 // attr.getName() + /* NOI18N */" " + attr.getType()); 1285 attr.addFlags(FORWARD | FORWARD_REMOVE); 1286 list.add(attr); 1287 } 1288 } 1289 } 1290 removeForwardedAttributes()1291 private void removeForwardedAttributes() { 1292 ContainerShadow cntr = getContainer(); 1293 if (cntr == null) 1294 return; 1295 1296 Enumeration e = attributes.attributesWithFlags(FORWARD_REMOVE); 1297 while (e.hasMoreElements()) { 1298 Attribute attr = (Attribute)e.nextElement(); 1299 if (!cntr.hasAttribute(attr.getName())) { 1300 attributes.remove(attr.getName()); 1301 } 1302 } 1303 } 1304 1305 /** 1306 * Return true if we are forwarding the attribute "attrName" 1307 * to "mgr", 1308 * otherwise return false. 1309 */ hasAttributeForward(AttributeManager mgr, String attrName)1310 boolean hasAttributeForward(AttributeManager mgr, String attrName) { 1311 return (forwardVector.contains(mgr) && 1312 attributes.get(attrName).flagged(FORWARD)); 1313 } 1314 1315 /** 1316 * These are helper routines for the group. 1317 * If you are fowarding 1318 * attributes to a component, dialog or frame, you should call 1319 * one of these methods in the constructor. 1320 */ 1321 1322 private static AttributeList genericAttrList = null; 1323 1324 /** 1325 * Compatibility method - do not use! 1326 */ addComponentAttributes()1327 protected void addComponentAttributes() { 1328 addForwardedAttributes(); 1329 } 1330 1331 /** 1332 * Compatibility method - do not use! 1333 */ addPanelAttributes()1334 protected void addPanelAttributes() { 1335 addForwardedAttributes(); 1336 } 1337 1338 /** 1339 * Compatibility method - do not use! 1340 */ addFrameAttributes()1341 protected void addFrameAttributes() { 1342 addForwardedAttributes(); 1343 } 1344 1345 /** 1346 * Compatibility method - do not use! 1347 */ addDialogAttributes()1348 protected void addDialogAttributes() { 1349 addForwardedAttributes(); 1350 } 1351 1352 // 1353 // Attributes - get and set 1354 // 1355 1356 /** 1357 * Get the value of a named attribute. 1358 */ get(String key)1359 public Object get(String key) { 1360 Attribute attr = attributes.get(key); 1361 1362 if (key.equals(/* NOI18N */"name")) { 1363 return super.get(key); 1364 } else if (key.equals(/* NOI18N */"visible")) { 1365 return super.get(key); 1366 } else if (!isInitialized) { 1367 return super.get(key); 1368 } else if (attr != null && attr.flagged(FORWARD)) { 1369 Enumeration e = forwardVector.elements(); 1370 AttributeManager mgr; 1371 1372 while (e.hasMoreElements()) { 1373 mgr = (AttributeManager)e.nextElement(); 1374 if (mgr.hasAttribute(key, attr.getType())) { 1375 return mgr.get(key); 1376 } 1377 } 1378 1379 return null; 1380 } else { 1381 return getOnGroup(key); 1382 } 1383 } 1384 1385 // NOTE: Any changes made to this comment should also 1386 // be made in the 1387 // lib/visual/gen/group.java file. 1388 /** 1389 * May be overridden by sub-groups that 1390 * store attribute values themselves, and do not depend on the 1391 * group superclass to store them. 1392 * This method should be overridden 1393 * instead of "get". Any attributes handled in setOnGroup where 1394 * super.setOnGroup is not called must also be handled 1395 * in getOnGroup. 1396 * <p> 1397 * The default implementation of getOnGroup retrieves the value 1398 * from the attribute table. 1399 * <p> 1400 * The reason that "getOnGroup" should be overridden instead 1401 * of "get" is that "getOnGroup" is guaranteed not to be called 1402 * until the group class is initialized. 1403 * This means that initRoot 1404 * will always be called before any calls to getOnGroup 1405 * are made. 1406 * <p> 1407 * Also, this method is only for attributes that are defined 1408 * in the 1409 * sub-groups. It is not called for forwarded attributes. 1410 * <p> 1411 */ getOnGroup(String key)1412 protected Object getOnGroup(String key) { 1413 return super.get(key); 1414 } 1415 1416 /** 1417 * Set the value of a named attribute. 1418 */ set(String key, Object value)1419 public void set(String key, Object value) { 1420 Attribute attr = attributes.get(key); 1421 1422 if (key.equals(/* NOI18N */"name")) { 1423 super.set(key, value); 1424 } else if (key.equals(/* NOI18N */"visible")) { 1425 super.set(key, value); 1426 if (((Boolean)value).booleanValue()) { 1427 if (isVisible()) 1428 internalShowGroup(); 1429 } else 1430 internalHideGroup(); 1431 } else if (!isInitialized) { 1432 super.set(key, value); 1433 } else if (attr != null && attr.flagged(FORWARD)) { 1434 super.set(key, value); 1435 1436 Enumeration e = forwardVector.elements(); 1437 AttributeManager mgr; 1438 boolean set = false; 1439 1440 while (e.hasMoreElements()) { 1441 mgr = (AttributeManager)e.nextElement(); 1442 if (mgr.hasAttribute(key, attr.getType())) { 1443 mgr.set(key, value); 1444 set = true; 1445 } 1446 } 1447 1448 if (set) { 1449 // update the the global register for unsaved changes 1450 if (inDesignerRoot()) 1451 DesignerAccess.setChangesMade(true); 1452 } 1453 } else { 1454 setOnGroup(key, value); 1455 } 1456 } 1457 1458 // NOTE: Any changes made to this comment should also 1459 // be made in the 1460 // lib/visual/gen/group.java file. 1461 /** 1462 * May be overridden by sub-groups that 1463 * want notification when attributes are changed. This method 1464 * should be overridden instead of "set". 1465 * Any attributes handled 1466 * in setOnGroup where super.setOnGroup is not called 1467 * must also be 1468 * handled in getOnGroup. 1469 * <p> 1470 * The default implementation of setOnGroup puts the value 1471 * in the attribute table. 1472 * <p> 1473 * The reason that "setOnGroup" should be overridden instead 1474 * of "set" is that "setOnGroup" is guaranteed not to be called 1475 * until the group class is initialized. 1476 * This means that initRoot 1477 * will always be called before any calls to setOnGroup 1478 * are made. 1479 * <p> 1480 * During initialization, "setOnGroup" will be called for all 1481 * the group's attributes even if they have not be changed from 1482 * the default value. But for attributes that have the DEFAULT 1483 * flag set, "setOnGroup" will only be called if the value 1484 * of the attribute has changed from the default. 1485 * <p> 1486 * Also, this method is only called when attributes defined 1487 * in the 1488 * sub-groups are updated. It is not called for forwarded 1489 * attributes. 1490 * <p> 1491 */ setOnGroup(String key, Object value)1492 protected void setOnGroup(String key, Object value) { 1493 super.set(key, value); 1494 } 1495 1496 /** 1497 * Base group information. 1498 */ 1499 1500 private Applet applet = null; 1501 private String cmdLineArgs[]; 1502 private Frame topLevel = null; 1503 private Registry registry = null; 1504 1505 private boolean hasEnvironment = false; 1506 hasEnvironment()1507 private boolean hasEnvironment() { 1508 if (hasEnvironment) 1509 return true; 1510 else if (parentGroup != null) 1511 return parentGroup.hasEnvironment(); 1512 else 1513 return false; 1514 } 1515 1516 /** 1517 * Returns true if this group is the base group. 1518 */ isBase()1519 public boolean isBase() { 1520 return hasEnvironment; 1521 } 1522 1523 /** 1524 * Returns true if the given window this group's base window. 1525 */ isBaseWindow(Window win)1526 protected boolean isBaseWindow(Window win) { 1527 WindowShadow shadow = 1528 (WindowShadow)DesignerAccess.getShadowTable().get(win); 1529 return (isBase() && (getWindow() == shadow)); 1530 } 1531 1532 /** 1533 * Returns true if this group is either the base group 1534 * or is a descendant 1535 * of the base group. 1536 */ hasBase()1537 public boolean hasBase() { 1538 if (hasEnvironment) 1539 return true; 1540 else if (parentGroup != null) 1541 return parentGroup.hasBase(); 1542 else 1543 return false; 1544 } 1545 1546 /** 1547 * Returns the base group. 1548 */ getBase()1549 public Group getBase() { 1550 if (hasEnvironment) 1551 return this; 1552 else if (parentGroup != null) 1553 return parentGroup.getBase(); 1554 else 1555 return null; 1556 } 1557 1558 /** 1559 * Returns true if we are doing a create operation in the 1560 * middle of a show operation. Create likes to call show if the 1561 * visible attribute is set to true, but create shouldn't call 1562 * show if show caused create to be called if the first place. 1563 */ doingShow()1564 boolean doingShow() { 1565 if (doingShow) 1566 return true; 1567 else if (parentGroup != null) 1568 return parentGroup.doingShow(); 1569 else 1570 return false; 1571 } 1572 1573 /** 1574 * Sets the environment information for the group. 1575 * This method should 1576 * be invoked only on the top-most group in the application. 1577 * Invoking 1578 * setEnvironmentInfo and setTopLevel on a group makes 1579 * it the base group. 1580 */ setEnvironmentInfo(Applet applet, String args[])1581 public void setEnvironmentInfo(Applet applet, String args[]) { 1582 // checkDate(); 1583 this.applet = applet; 1584 this.cmdLineArgs = args; 1585 hasEnvironment = true; 1586 } 1587 1588 /** 1589 * Sets the top level frame for the group. This method should 1590 * be invoked only on the top most group in the application. 1591 * Invoking setEnvironmentInfo and setTopLevel on a group 1592 * makes it 1593 * the base group. 1594 */ setTopLevel(Frame topLevel)1595 public void setTopLevel(Frame topLevel) { 1596 this.topLevel = topLevel; 1597 } 1598 1599 /** 1600 * Sets the cursor for all of the group's frames to the given 1601 * cursor value. Calls setCursor on all the child groups. 1602 */ setCursor(int cursor)1603 public void setCursor(int cursor) { 1604 if (root != null) 1605 root.setCursor(cursor); 1606 1607 Enumeration e = children.elements(); 1608 while (e.hasMoreElements()) { 1609 Group child = (Group)e.nextElement(); 1610 child.setCursor(cursor); 1611 } 1612 } 1613 1614 /** 1615 * Accessor method for the applet. Null is returned 1616 * when you're not 1617 * running as an applet. 1618 */ getApplet()1619 public Applet getApplet() { 1620 if (applet != null) 1621 return applet; 1622 else if (parentGroup != null) 1623 return parentGroup.getApplet(); 1624 else 1625 return null; 1626 } 1627 1628 /** 1629 * Accessor method for the command line arguments. 1630 * Null is returned 1631 * when you're not running from the command line. 1632 */ getCmdLineArgs()1633 public String[] getCmdLineArgs() { 1634 if (cmdLineArgs != null) 1635 return cmdLineArgs; 1636 else if (parentGroup != null) 1637 return parentGroup.getCmdLineArgs(); 1638 else 1639 return null; 1640 } 1641 1642 /** 1643 * Returns the first frame found while traversing up the 1644 * group tree. If no frame is found, then the top level 1645 * frame is returned. 1646 */ getFrame()1647 public Frame getFrame() { 1648 WindowShadow win = getWindow(); 1649 if (win != null && win.getBody() != null) 1650 { 1651 if (win instanceof DialogShadow) 1652 return (Frame)((Window) win.getBody()).getParent(); 1653 else 1654 return (Frame)win.getBody(); 1655 } else if (parentGroup != null) 1656 return parentGroup.getFrame(); 1657 else 1658 return getTopLevel(); 1659 } 1660 1661 /** 1662 * Accessor method for the top level frame. This will not 1663 * return null providing that the base group has been 1664 * initialized properly. 1665 */ getTopLevel()1666 public Frame getTopLevel() { 1667 if (topLevel != null) 1668 return topLevel; 1669 else if (parentGroup != null) 1670 return parentGroup.getTopLevel(); 1671 else 1672 return null; 1673 } 1674 1675 /** 1676 * Accessor method for the registry. The registry is 1677 * created when 1678 * the application starts. 1679 */ getRegistry()1680 public Registry getRegistry() { 1681 if (isBase()) { 1682 initRegistry(); 1683 return registry; 1684 } else if (parentGroup != null) 1685 return parentGroup.getRegistry(); 1686 else 1687 return null; 1688 } 1689 initRegistry()1690 private synchronized void initRegistry() { 1691 if (registry == null) 1692 registry = new Registry(); 1693 } 1694 layoutMode()1695 public void layoutMode() { 1696 super.layoutMode(); 1697 1698 WindowShadow s = getWindow(); 1699 if (s != null) 1700 s.setLayout(true); 1701 } 1702 previewMode()1703 public void previewMode() { 1704 super.previewMode(); 1705 1706 WindowShadow s = getWindow(); 1707 if (s != null) 1708 s.setPreview(true); 1709 } 1710 preValidate()1711 protected void preValidate() { 1712 PanelShadow panel = getPanel(); 1713 if (panel != null) 1714 panel.preValidate(); 1715 } 1716 } 1717