public class RADComponentNode extends FormNode implements RADComponentCookie, FormPropertyCookie { private static final MessageFormat nodeNameFormat = new MessageFormat(FormUtils.getBundleString("FMT_ComponentNodeName")); // NOI18N private static final MessageFormat nodeNoNameFormat = new MessageFormat(FormUtils.getBundleString("FMT_UnnamedComponentNodeName")); // NOI18N private RADComponent component; private boolean highlightDisplayName; private Map<Integer, Image> img = new HashMap<Integer, Image>(); public RADComponentNode(RADComponent component) { this( component instanceof ComponentContainer ? new RADChildren((ComponentContainer) component) : Children.LEAF, component); } public RADComponentNode(Children children, RADComponent component) { super(children, component.getFormModel()); this.component = component; component.setNodeReference(this); // getCookieSet().add(this); if (component instanceof ComponentContainer) getCookieSet().add(new ComponentsIndex()); updateName(); } void updateName() { String compClassName = Utilities.getShortClassName(component.getBeanClass()); if (component == component.getFormModel().getTopRADComponent()) setDisplayName(nodeNoNameFormat.format(new Object[] {compClassName})); else setDisplayName(nodeNameFormat.format(new Object[] {getName(), compClassName})); } public void fireComponentPropertiesChange() { firePropertyChange(null, null, null); } public void fireComponentPropertySetsChange() { firePropertySetsChange(null, null); } private static boolean iconsInitialized; @Override public Image getIcon(final int iconType) { Image icon = img.get(iconType); if (icon != null) return icon; // try to get a special icon icon = BeanSupport.getBeanIcon(component.getBeanClass(), iconType); if (icon == null) { final String className = component.getBeanClass().getName(); final String classDetails = (String) component.getAuxValue(RADComponent.AUX_VALUE_CLASS_DETAILS); if (!iconsInitialized) { // getIconForClass invokes getNodes(true) which cannot be called in Mutex EventQueue.invokeLater( new Runnable() { @Override public void run() { Image icon = PaletteUtils.getIconForClass(className, classDetails, iconType, true); iconsInitialized = true; if (icon != null) { img.put(iconType, icon); fireIconChange(); } } }); } else { icon = PaletteUtils.getIconForClass(className, classDetails, iconType, false); } if (icon == null) { // get icon from BeanInfo java.beans.BeanInfo bi = component.getBeanInfo(); if (bi != null) { icon = bi.getIcon(iconType); } if (icon == null) { // use default icon icon = super.getIcon(iconType); } } } img.put(iconType, icon); return icon; } @Override public Image getOpenedIcon(int iconType) { return getIcon(iconType); } @Override public HelpCtx getHelpCtx() { return new HelpCtx("gui.components.editing"); // NOI18N } @Override public Node.PropertySet[] getPropertySets() { final Node.PropertySet[][] props = new Node.PropertySet[1][]; Runnable runnable = new Runnable() { @Override public void run() { FormLAF.executeWithLAFLocks( new Runnable() { @Override public void run() { props[0] = component.getProperties(); } }); } }; if (EventQueue.isDispatchThread()) { runnable.run(); } else { try { // We have made some attempts to keep initialization // of properties outside AWT thread, but it always // deadlocked with AWT thread for various reasons. EventQueue.invokeAndWait(runnable); } catch (InterruptedException iex) { FormUtils.LOGGER.log(Level.INFO, iex.getMessage(), iex); } catch (InvocationTargetException itex) { FormUtils.LOGGER.log(Level.INFO, itex.getMessage(), itex); } } return props[0]; } /* List new types that can be created in this node. * @return new types */ @Override public NewType[] getNewTypes() { return component.getNewTypes(); } @Override public Action getPreferredAction() { FormEditor formEditor = FormEditor.getFormEditor(component.getFormModel()); if (formEditor == null) { return null; } for (Action action : formEditor.getDefaultComponentActions()) { if (action.isEnabled()) { return action; } } return null; } @Override public Action[] getActions(boolean context) { if (actions == null) { List<Action> actions = new ArrayList<Action>(20); RADComponent topComp = component.getFormModel().getTopRADComponent(); if (component.isReadOnly()) { if (component == topComp) { actions.add(SystemAction.get(TestAction.class)); actions.add(null); } Event[] events = component.getKnownEvents(); for (int i = 0; i < events.length; i++) { if (events[i].hasEventHandlers()) { actions.add(SystemAction.get(EventsAction.class)); actions.add(null); break; } } actions.add(SystemAction.get(CopyAction.class)); } else { if (InPlaceEditLayer.supportsEditingFor(component.getBeanClass(), false)) { actions.add(SystemAction.get(InPlaceEditAction.class)); } if (javax.swing.JTable.class.isAssignableFrom(component.getBeanClass())) { actions.add(SystemAction.get(CustomizeTableAction.class)); } if (component != topComp) { actions.add(SystemAction.get(ChangeVariableNameAction.class)); } else { actions.add(SystemAction.get(TestAction.class)); } if (FormEditor.getBindingSupport(component.getFormModel()) != null) { // zxb:删除掉绑定菜单项。 // actions.add(SystemAction.get(BindAction.class)); } actions.add(SystemAction.get(EventsAction.class)); actions.add(null); java.util.List actionProps = component.getActionProperties(); Iterator iter = actionProps.iterator(); while (iter.hasNext()) { final RADProperty prop = (RADProperty) iter.next(); Action action = PropertyAction.createIfEditable(prop); if (action != null) { actions.add(action); } } addSeparator(actions); if (component instanceof ComponentContainer) { addContainerActions(actions); addLayoutActions(actions); } else { addLayoutActions(actions); addContainerActions(actions); } if (component != topComp) { actions.add(SystemAction.get(MoveUpAction.class)); actions.add(SystemAction.get(MoveDownAction.class)); } if (component instanceof ComponentContainer) { actions.add(SystemAction.get(ReorderAction.class)); } addSeparator(actions); if (component != topComp) { actions.add(SystemAction.get(CutAction.class)); } actions.add(SystemAction.get(CopyAction.class)); if (component instanceof ComponentContainer) { actions.add(SystemAction.get(PasteAction.class)); } if (component != topComp) { actions.add(SystemAction.get(DuplicateAction.class)); actions.add(SystemAction.get(DeleteAction.class)); } actions.add(null); // zxb:删除掉自定义代码菜单项。 // actions.add(SystemAction.get(CustomCodeAction.class)); } actions.add(null); javax.swing.Action[] superActions = super.getActions(context); for (int i = 0; i < superActions.length; i++) actions.add(superActions[i]); this.actions = new Action[actions.size()]; actions.toArray(this.actions); } return actions; } private void addLayoutActions(List<Action> actions) { if (component.getParentComponent() instanceof RADVisualContainer) { actions.add(SystemAction.get(AlignAction.class)); actions.add(SystemAction.get(SetAnchoringAction.class)); actions.add(SystemAction.get(SetResizabilityAction.class)); actions.add(SystemAction.get(ChooseSameSizeAction.class)); actions.add(SystemAction.get(DefaultSizeAction.class)); actions.add(SystemAction.get(EncloseAction.class)); actions.add(SystemAction.get(CustomizeEmptySpaceAction.class)); actions.add(null); } } private void addContainerActions(List<Action> actions) { if (component instanceof RADVisualContainer) { if (!((RADVisualContainer) component).hasDedicatedLayoutSupport()) { actions.add(SystemAction.get(SelectLayoutAction.class)); actions.add(SystemAction.get(CustomizeLayoutAction.class)); } if (MenuEditLayer.isMenuBarContainer(component)) { actions.add(SystemAction.get(InsertMenuAction.class)); } else if (MenuEditLayer.isMenuRelatedContainer(component)) { actions.add(SystemAction.get(AddSubItemAction.class)); } else { // only use the AddAction for non-menu containers actions.add(SystemAction.get(AddAction.class)); } } if (getNewTypes().length != 0) { actions.add(null); actions.add(SystemAction.get(NewAction.class)); } if (EditContainerAction.isEditableComponent(component)) { actions.add(SystemAction.get(EditContainerAction.class)); } if (DesignParentAction.isParentEditableComponent(component)) { actions.add(SystemAction.get(DesignParentAction.class)); } if (component.getParentComponent() == null) { if (component instanceof RADVisualComponent) { actions.add(SystemAction.get(DefaultSizeAction.class)); } if (component instanceof RADVisualContainer && !((RADVisualContainer) component).hasDedicatedLayoutSupport()) { actions.add(SystemAction.get(CustomizeEmptySpaceAction.class)); } } addSeparator(actions); } private static void addSeparator(List<Action> actions) { int n = actions.size(); if (n > 0 && actions.get(n - 1) != null) { actions.add(null); } } @Override public String getName() { return component.getName(); } /** * Set the system name. Fires a property change event. Also may change the display name according * to {@link #displayFormat}. * * @param s the new name */ @Override public void setName(String s) { component.rename(s); } /** * Can this node be renamed? * * @return <code>false</code> */ @Override public boolean canRename() { return !component.isReadOnly() && component != component.getFormModel().getTopRADComponent(); } /** * Can this node be destroyed? * * @return <CODE>false</CODE> */ @Override public boolean canDestroy() { return !component.isReadOnly() && component != component.getFormModel().getTopRADComponent(); } /** * Remove the node from its parent and deletes it. The default implementation obtains write access * to the {@link Children#MUTEX children's lock}, and removes the node from its parent(if any). * Also fires a property change. * * <p>This may be overridden by subclasses to do any additional cleanup. * * @exception java.io.IOException if something fails */ @Override public void destroy() throws java.io.IOException { if (component.getNodeReference() == this) { if (MetaComponentCreator.isTransparentLayoutComponent(component.getParentComponent())) { component = component.getParentComponent(); } if (EventQueue.isDispatchThread()) { component.getFormModel().removeComponent(component, true); } else { EventQueue.invokeLater( new Runnable() { @Override public void run() { component.getFormModel().removeComponent(component, true); } }); } } // otherwise the component was likely already removed with a parent component super.destroy(); } /** * Test whether there is a customizer for this node. If true, the customizer can be obtained via * {@link #getCustomizer}. * * @return <CODE>true</CODE> if there is a customizer */ @Override public boolean hasCustomizer() { return !component.isReadOnly() && ((component.getBeanInfo().getBeanDescriptor().getCustomizerClass() != null)); } /** * Creates the customizer component for the node. * * @return the component, or null if there is no customizer */ @Override protected Component createCustomizer() { Class customizerClass = component.getBeanInfo().getBeanDescriptor().getCustomizerClass(); if (customizerClass == null) { if (javax.swing.JTable.class.isAssignableFrom(component.getBeanClass())) { customizerClass = TableCustomizer.class; } else { return null; } } Object customizerObject; try { customizerObject = customizerClass.newInstance(); } catch (InstantiationException e) { ErrorManager.getDefault().notify(ErrorManager.WARNING, e); return null; } catch (IllegalAccessException e) { ErrorManager.getDefault().notify(ErrorManager.WARNING, e); return null; } if (!(customizerObject instanceof Component) || !(customizerObject instanceof Customizer)) return null; if (customizerObject instanceof NodeCustomizer) ((NodeCustomizer) customizerObject).attach(component.getNodeReference()); // Issue 203352 - default values of properties must be initialized // before the customizer is shown/used component.ensureDefaultPropertyValuesInitialization(); Customizer customizer = (Customizer) customizerObject; customizer.setObject(component.getBeanInstance()); if (customizerObject instanceof FormAwareEditor) { // Hack - returns some property Node.Property prop = component.getProperties()[0].getProperties()[0]; ((FormAwareEditor) customizerObject) .setContext(component.getFormModel(), (FormProperty) prop); } customizer.addPropertyChangeListener( new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { FormProperty[] properties; if (evt.getPropertyName() != null) { FormProperty changedProperty = component.getBeanProperty(evt.getPropertyName()); if (changedProperty != null) properties = new FormProperty[] {changedProperty}; else return; // non-existing property? } else { properties = component.getAllBeanProperties(); evt = null; } updatePropertiesFromCustomizer(properties, evt); } }); // [undo/redo for customizer probably does not work...] return (Component) customizerObject; } private void updatePropertiesFromCustomizer( final FormProperty[] properties, final PropertyChangeEvent evt) { // we run this as privileged to avoid security problems - because // the property change is fired from untrusted bean customizer code AccessController.doPrivileged( new PrivilegedAction<Object>() { @Override public Object run() { Object oldValue = evt != null ? evt.getOldValue() : null; Object newValue = evt != null ? evt.getNewValue() : null; for (int i = 0; i < properties.length; i++) { FormProperty prop = properties[i]; try { prop.reinstateProperty(); // if (prop.isChanged()) // [what if changed to default // value?] prop.propertyValueChanged(oldValue, newValue); } catch (Exception ex) { // unlikely to happen ex.printStackTrace(); } } return null; } }); } // ----------------------------------------------------------------------------------------- // Clipboard operations /** * Test whether this node can be copied. The default implementation returns <code>true</code>. * * @return <code>true</code> if it can */ @Override public boolean canCopy() { return true; } /** * Test whether this node can be cut. The default implementation assumes it can if this node is * writeable. * * @return <code>true</code> if it can */ @Override public boolean canCut() { return !component.isReadOnly() && component != component.getFormModel().getTopRADComponent(); } /** * Copy this node to the clipboard. * * @return The transferable for RACComponentNode * @throws java.io.IOException if it could not copy */ @Override public Transferable clipboardCopy() throws java.io.IOException { return new CopySupport.RADTransferable(CopySupport.getComponentCopyFlavor(), component); } /** * Cut this node to the clipboard. * * @return {@link Transferable} with one flavor, {@link RAD_COMPONENT_COPY_FLAVOR } * @throws java.io.IOException if it could not cut */ @Override public Transferable clipboardCut() throws java.io.IOException { return new CopySupport.RADTransferable(CopySupport.getComponentCutFlavor(), component); } /** * Accumulate the paste types that this node can handle for a given transferable. * * @param t a transferable containing clipboard data * @param s a list of {@link PasteType}s that will have added to it all types valid for this node */ @Override protected void createPasteTypes(Transferable t, java.util.List<PasteType> s) { CopySupport.createPasteTypes(t, s, component.getFormModel(), component); } // ----------------------------------------------------------------------------- // RADComponentCookie implementation @Override public RADComponent getRADComponent() { return component; } // ----------------------------------- // FormPropertyCookie implementation @Override public FormProperty getProperty(String name) { return component.getPropertyByName(name, FormProperty.class, true); // Node.Property prop = component.getPropertyByName(name, true); // return (FormProperty) (prop instanceof FormProperty ? prop : null); } // ----------------------------------------------------------------------------- // Innerclasses public static class RADChildren extends FormNodeChildren { private ComponentContainer container; private Object keyLayout; public RADChildren(ComponentContainer container) { super(); this.container = container; updateKeys(); } // FormNodeChildren implementation @Override protected void updateKeys() { RADComponent[] subComps = container.getSubBeans(); List<Object> keys = new ArrayList<Object>(subComps.length + 2); if (container instanceof RADVisualContainer) { RADVisualContainer visualCont = (RADVisualContainer) container; RADComponent menuComp = visualCont.getContainerMenu(); if (menuComp != null) keys.add(menuComp); if (visualCont.shouldHaveLayoutNode()) { keyLayout = visualCont .getLayoutSupport() .getLayoutDelegate(); // new Object(); // [need not be recreated every time] keys.add(keyLayout); } for (int i = 0; i < subComps.length; i++) if (subComps[i] != menuComp) keys.add(subComps[i]); } else { for (int i = 0; i < subComps.length; i++) keys.add(subComps[i]); } setKeys(keys); } @Override protected Node[] createNodes(Object key) { Node node; if (key == keyLayout) node = new LayoutNode((RADVisualContainer) container); else { node = new RADComponentNode((RADComponent) key); node.getChildren().getNodes(); // enforce subnodes creation } return new Node[] {node}; } } private final class ComponentsIndex extends org.openide.nodes.Index.Support { @Override public Node[] getNodes() { RADComponent[] comps; if (component instanceof RADVisualContainer) comps = ((RADVisualContainer) component).getSubComponents(); else if (component instanceof ComponentContainer) comps = ((ComponentContainer) component).getSubBeans(); else comps = null; Node[] nodes = new Node[comps != null ? comps.length : 0]; for (int i = 0; i < nodes.length; i++) nodes[i] = comps[i].getNodeReference(); return nodes; } @Override public int getNodesCount() { return getNodes().length; } @Override public void reorder(int[] perm) { if (component instanceof ComponentContainer) { ComponentContainer cont = (ComponentContainer) component; cont.reorderSubComponents(perm); component.getFormModel().fireComponentsReordered(cont, perm); } } } private static final class ChangeVariableNameAction extends RenameAction { @Override public String getName() { return NbBundle.getMessage( ChangeVariableNameAction.class, "ChangeVariableNameAction"); // NOI18N } } @Override public String getHtmlDisplayName() { if (highlightDisplayName) { return "<html><b>" + getDisplayName() + "</b></html>"; // NOI18N } else { return "<html>" + getDisplayName() + "</html>"; // NOI18N } } void highlightDisplayName(boolean highlight) { if (highlight != highlightDisplayName) { highlightDisplayName = highlight; fireDisplayNameChange(null, getDisplayName()); } } private static final class CustomizeTableAction extends CustomizeAction { @Override public String getName() { return FormUtils.getBundleString("NAME_CustomizeTableAction"); // NOI18N } @Override protected boolean enable(Node[] activatedNodes) { return true; } } }
@Override public String getName() { return FormUtils.getBundleString("NAME_CustomizeTableAction"); // NOI18N }