0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041: package org.netbeans.modules.form.menu;
0042:
0043: import java.awt.BorderLayout;
0044: import java.awt.Color;
0045: import java.awt.Component;
0046: import java.awt.Font;
0047: import java.awt.Graphics;
0048: import java.awt.Graphics2D;
0049: import java.awt.Insets;
0050: import java.awt.Point;
0051: import java.awt.RenderingHints;
0052: import java.awt.dnd.DropTarget;
0053: import java.awt.dnd.DropTargetDragEvent;
0054: import java.awt.dnd.DropTargetDropEvent;
0055: import java.awt.dnd.DropTargetEvent;
0056: import java.awt.dnd.DropTargetListener;
0057: import java.awt.event.ComponentAdapter;
0058: import java.awt.event.ComponentEvent;
0059: import java.awt.event.KeyAdapter;
0060: import java.awt.event.KeyEvent;
0061: import java.awt.event.MouseEvent;
0062: import java.beans.PropertyChangeEvent;
0063: import java.beans.PropertyChangeListener;
0064: import java.util.ArrayList;
0065: import java.util.Collections;
0066: import java.util.HashMap;
0067: import java.util.List;
0068: import java.util.Map;
0069: import java.util.TooManyListenersException;
0070: import javax.swing.Action;
0071: import javax.swing.BorderFactory;
0072: import javax.swing.Icon;
0073: import javax.swing.JCheckBoxMenuItem;
0074: import javax.swing.JComponent;
0075: import javax.swing.JLayeredPane;
0076: import javax.swing.JMenu;
0077: import javax.swing.JMenuBar;
0078: import javax.swing.JMenuItem;
0079: import javax.swing.JPanel;
0080: import javax.swing.JPopupMenu;
0081: import javax.swing.JRadioButtonMenuItem;
0082: import javax.swing.JSeparator;
0083: import javax.swing.SwingUtilities;
0084: import javax.swing.UIManager;
0085: import javax.swing.border.Border;
0086: import javax.swing.border.CompoundBorder;
0087: import javax.swing.event.MouseInputAdapter;
0088: import javax.swing.plaf.PopupMenuUI;
0089: import org.netbeans.modules.form.*;
0090: import org.netbeans.modules.form.actions.PropertyAction;
0091: import org.netbeans.modules.form.assistant.AssistantMessages;
0092: import org.netbeans.modules.form.editors.IconEditor.NbImageIcon;
0093: import org.netbeans.modules.form.palette.PaletteItem;
0094: import org.netbeans.modules.form.palette.PaletteUtils;
0095: import org.openide.filesystems.FileObject;
0096: import org.openide.nodes.Node;
0097: import org.openide.nodes.NodeOp;
0098: import org.openide.util.NbBundle;
0099:
0100: /**
0101: *
0102: * @author joshua.marinacci@sun.com
0103: */
0104: public class MenuEditLayer extends JPanel {
0105: /* === constants for the look of the designer === */
0106: public static final Border DRAG_MENU_BORDER = BorderFactory
0107: .createLineBorder(Color.BLACK, 1);
0108: public static final Border DRAG_SEPARATOR_BORDER = BorderFactory
0109: .createLineBorder(Color.RED, 1);
0110: public static final Color SELECTED_MENU_BACKGROUND = new Color(
0111: 0xA5A6A9);
0112: public static final Color EMPTY_ICON_COLOR = new Color(0xDDDDDD);
0113: public static final int EMPTY_ICON_BORDER_WIDTH = 2;
0114:
0115: /* === private constants === */
0116: private static final boolean USE_NEW_ITEM_COLOR_SWITCHING = false;
0117:
0118: /* === public and package level fields. these should probably become getters and setters ===*/
0119: public VisualDesignerPopupFactory hackedPopupFactory = null;
0120: public FormDesigner formDesigner;
0121: JLayeredPane layers;
0122: JComponent glassLayer;
0123: DropTargetLayer dropTargetLayer;
0124: boolean showMenubarWarning = false;
0125:
0126: /* === private fields === */
0127: private Map<JMenu, PopupMenuUI> menuPopupUIMap;
0128:
0129: public enum SelectedPortion {
0130: Icon, Text, Accelerator, All, None
0131: };
0132:
0133: private SelectedPortion selectedPortion = SelectedPortion.None;
0134:
0135: private KeyboardMenuNavigator keyboardMenuNavigator;
0136: private Map<RADVisualContainer, FormModelListener> formModelListeners;
0137: private DragOperation dragop;
0138: private FormModelListener menuBarFormListener;
0139: private PropertyChangeListener selectionListener;
0140: private boolean isAlive = true;
0141: private static final boolean USE_JSEPARATOR_FIX = true;
0142:
0143: /** Creates a new instance of MenuEditLayer */
0144: public MenuEditLayer(final FormDesigner formDesigner) {
0145: this .formDesigner = formDesigner;
0146: menuPopupUIMap = new HashMap<JMenu, PopupMenuUI>();
0147: formModelListeners = new HashMap<RADVisualContainer, FormModelListener>();
0148:
0149: layers = new JLayeredPane();
0150: this .setLayout(new BorderLayout());
0151: this .add(layers, BorderLayout.CENTER);
0152:
0153: dragop = new DragOperation(this );
0154:
0155: glassLayer = new JComponent() {
0156: @Override
0157: public void paintComponent(Graphics g) {
0158: }
0159: };
0160:
0161: layers.add(glassLayer, new Integer(500)); // put the glass layer over the drag layer
0162: glassLayer.setSize(400, 400); //josh: do i need this line? probably can delete it.
0163:
0164: dropTargetLayer = new DropTargetLayer(this );
0165: layers.add(dropTargetLayer, new Integer(
0166: JLayeredPane.DRAG_LAYER - 5)); // put the drop target layer just above the drag layer
0167:
0168: // make the extra layers resize to the main component
0169: this .addComponentListener(new ComponentAdapter() {
0170: @Override
0171: public void componentResized(ComponentEvent e) {
0172: glassLayer.setSize(MenuEditLayer.this .getSize());
0173: dropTargetLayer.setSize(MenuEditLayer.this .getSize());
0174: }
0175: });
0176:
0177: MouseInputAdapter mia = new GlassLayerMouseListener();
0178: glassLayer.addMouseListener(mia);
0179: glassLayer.addMouseMotionListener(mia);
0180: configureSelectionListener();
0181: }
0182:
0183: DragOperation getDragOperation() {
0184: return dragop;
0185: }
0186:
0187: public static boolean isMenuRelatedRADComponent(RADComponent comp) {
0188: if (comp == null)
0189: return false;
0190: return isMenuRelatedComponentClass(comp.getBeanClass());
0191: }
0192:
0193: public static boolean isNonMenuJSeparator(RADComponent comp) {
0194: if (comp == null)
0195: return false;
0196: if (JSeparator.class.isAssignableFrom(comp.getBeanClass())) {
0197: RADComponent parent = comp.getParentComponent();
0198: if (parent != null
0199: && JMenu.class.isAssignableFrom(parent
0200: .getBeanClass())) {
0201: return false;
0202: }
0203: return true;
0204: }
0205: return false;
0206: }
0207:
0208: public static boolean isMenuBarContainer(RADComponent comp) {
0209: if (comp == null)
0210: return false;
0211: Class clas = comp.getBeanClass();
0212: if (clas == null)
0213: return false;
0214: if (JMenuBar.class.isAssignableFrom(clas))
0215: return true;
0216: return false;
0217: }
0218:
0219: public static boolean isMenuRelatedContainer(RADComponent comp) {
0220: if (comp == null)
0221: return false;
0222: Class clas = comp.getBeanClass();
0223: if (clas == null)
0224: return false;
0225: if (JMenu.class.isAssignableFrom(clas))
0226: return true;
0227: if (JPopupMenu.class.isAssignableFrom(clas))
0228: return true;
0229: return false;
0230: }
0231:
0232: public static boolean isMenuRelatedComponentClass(Class clas) {
0233: if (clas == null)
0234: return false;
0235: if (JMenuItem.class.isAssignableFrom(clas))
0236: return true;
0237: if (JMenu.class.isAssignableFrom(clas))
0238: return true;
0239: if (JSeparator.class.isAssignableFrom(clas))
0240: return true;
0241: if (JMenuBar.class.isAssignableFrom(clas))
0242: return true;
0243: return false;
0244: }
0245:
0246: public boolean isPossibleNewMenuComponent(PaletteItem item) {
0247: if (item == null)
0248: return false;
0249: if (item.getComponentClass() == null)
0250: return false;
0251: if (JMenuItem.class.isAssignableFrom(item.getComponentClass())) {
0252: return true;
0253: }
0254: return false;
0255: }
0256:
0257: public void startNewMenuComponentPickAndPlop(PaletteItem item,
0258: Point pt) {
0259: this .setVisible(true);
0260: this .requestFocus();
0261: dragop = new DragOperation(this );
0262: dragop.start(item, pt);
0263: }
0264:
0265: public void startNewMenuComponentDragAndDrop(PaletteItem item) {
0266: this .setVisible(true);
0267: this .requestFocus();
0268: configureGlassLayer();
0269: configureFormListeners();
0270: }
0271:
0272: @Override
0273: protected void paintComponent(Graphics g) {
0274: super .paintComponent(g);
0275: Graphics2D g2 = (Graphics2D) g.create();
0276: g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
0277: RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
0278: g2.setColor(Color.BLACK);
0279: /* Using the assistant now instead of text ontop of the glasspane.
0280: * josh: I need to delete all of the previous code related to the showMenubarWarning boolean
0281: if(showMenubarWarning) {
0282: g2.drawString("You cannot add a menu component to a form without a menubar.", 5, getHeight()-30);
0283: }*/
0284: g2.dispose();
0285: }
0286:
0287: // the public method for non-menu parts of the form editor to
0288: // start menu editing
0289: public void openAndShowMenu(RADComponent metacomp, Component comp) {
0290: //p("making sure the menu is open: " + metacomp + " " + metacomp.getName());
0291: if (hackedPopupFactory == null) {
0292: this .hackedPopupFactory = new VisualDesignerPopupFactory(
0293: this );
0294: }
0295: openMenu(metacomp, comp);
0296: glassLayer.requestFocusInWindow();
0297: }
0298:
0299: void openMenu(RADComponent metacomp, Component comp) {
0300: getPopupFactory();
0301: configureGlassLayer();
0302: registerKeyListeners();
0303: configureFormListeners();
0304: configureSelectionListener();
0305: //reset the layers
0306: JMenu menu = (JMenu) comp;
0307: configureMenu(null, menu);
0308: showMenuPopup(menu);
0309: if (metacomp instanceof RADVisualContainer) {
0310: keyboardMenuNavigator
0311: .setCurrentMenuRAD((RADVisualContainer) metacomp);
0312: }
0313: }
0314:
0315: public void hideMenuLayer() {
0316: // tear down each menu and menu item
0317: unconfigureFormListeners();
0318: unconfigureSelectionListener();
0319: for (JMenu m : menuPopupUIMap.keySet()) {
0320: unconfigureMenu(m);
0321: }
0322: menuPopupUIMap.clear();
0323: if (hackedPopupFactory != null) {
0324: hackedPopupFactory.containerMap.clear();
0325: hackedPopupFactory = null;
0326: }
0327: if (dragop.isStarted()) {
0328: dragop.fastEnd();
0329: }
0330: // close all popup frames
0331: this .setVisible(false);
0332: if (keyboardMenuNavigator != null) {
0333: glassLayer.removeKeyListener(keyboardMenuNavigator);
0334: keyboardMenuNavigator.unconfigure();
0335: keyboardMenuNavigator = null;
0336: }
0337: backgroundMap.clear();
0338: //hackedPopupFactory.containerMap.clear();
0339: if (formDesigner.getHandleLayer() != null) {
0340: formDesigner.getHandleLayer().requestFocusInWindow();
0341: }
0342: }
0343:
0344: //josh: all this key listener stuff should go into a separate class
0345: private synchronized void registerKeyListeners() {
0346: if (keyboardMenuNavigator == null) {
0347: keyboardMenuNavigator = new KeyboardMenuNavigator(this );
0348: glassLayer.addKeyListener(keyboardMenuNavigator);
0349: glassLayer.addKeyListener(new KeyAdapter() {
0350: @Override
0351: public void keyPressed(KeyEvent e) {
0352: if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
0353: dragop.fastEnd();
0354: }
0355: }
0356: });
0357: }
0358: }
0359:
0360: private VisualDesignerPopupFactory getPopupFactory() {
0361: if (hackedPopupFactory == null) {
0362: hackedPopupFactory = new VisualDesignerPopupFactory(this );
0363: }
0364: return hackedPopupFactory;
0365: }
0366:
0367: private void configureGlassLayer() {
0368: try {
0369: glassLayer.setDropTarget(new DropTarget());
0370: glassLayer.getDropTarget().addDropTargetListener(
0371: new GlassLayerDropTargetListener());
0372: } catch (TooManyListenersException ex) {
0373: ex.printStackTrace();
0374: }
0375: }
0376:
0377: PropertyChangeListener paletteListener = null;
0378:
0379: private void configureFormListeners() {
0380:
0381: if (menuBarFormListener == null) {
0382: menuBarFormListener = new FormModelListener() {
0383: public void formChanged(FormModelEvent[] events) {
0384: if (events != null) {
0385: for (FormModelEvent evt : events) {
0386: // if this is a menubar delete event
0387: if (evt.getChangeType() == FormModelEvent.COMPONENT_REMOVED) {
0388: if (evt.getComponent() != null
0389: && JMenuBar.class
0390: .isAssignableFrom(evt
0391: .getComponent()
0392: .getBeanClass())) {
0393: hideMenuLayer();
0394: }
0395: }
0396: if (evt.getChangeType() == FormModelEvent.FORM_TO_BE_CLOSED) {
0397: hideMenuLayer();
0398: isAlive = false;
0399: }
0400: if (evt.getChangeType() == FormModelEvent.COMPONENT_ADDED) {
0401: if (evt.getCreatedDeleted()) {
0402: if (USE_NEW_ITEM_COLOR_SWITCHING) {
0403: configureNewComponent(evt
0404: .getComponent());
0405: }
0406: }
0407: }
0408:
0409: }
0410: }
0411: }
0412: };
0413: formDesigner.getFormModel().addFormModelListener(
0414: menuBarFormListener);
0415: }
0416: if (paletteListener == null) {
0417: paletteListener = new PropertyChangeListener() {
0418: public void propertyChange(PropertyChangeEvent evt) {
0419: if (PaletteUtils.getSelectedItem() == null
0420: || !isMenuRelatedComponentClass(PaletteUtils
0421: .getSelectedItem()
0422: .getComponentClass())) {
0423: if (dragop != null && dragop.isStarted()) {
0424: dragop.fastEnd();
0425: }
0426: }
0427: }
0428: };
0429: paletteContext = formDesigner.getFormEditor()
0430: .getFormDataObject().getFormFile();
0431: PaletteUtils.addPaletteListener(paletteListener,
0432: paletteContext);
0433: }
0434: }
0435:
0436: FileObject paletteContext = null;
0437:
0438: private void unconfigureFormListeners() {
0439: if (menuBarFormListener != null) {
0440: if (formDesigner != null
0441: && formDesigner.getFormModel() != null) {
0442: formDesigner.getFormModel().removeFormModelListener(
0443: menuBarFormListener);
0444: }
0445: }
0446: if (paletteListener != null) {
0447: PaletteUtils.removePaletteListener(paletteListener,
0448: paletteContext);
0449: paletteContext = null;
0450: paletteListener = null;
0451: }
0452: menuBarFormListener = null;
0453: }
0454:
0455: private void configureSelectionListener() {
0456: if (selectionListener == null) {
0457: selectionListener = new PropertyChangeListener() {
0458: public void propertyChange(PropertyChangeEvent evt) {
0459: if (!isAlive)
0460: return;
0461: Node[] newNodes = (Node[]) evt.getNewValue();
0462: List<RADComponent> selectedNodes = new ArrayList<RADComponent>();
0463:
0464: for (Node n : newNodes) {
0465: if (n instanceof RADComponentNode) {
0466: RADComponentNode radn = (RADComponentNode) n;
0467: selectedNodes.add(radn.getRADComponent());
0468: }
0469: }
0470:
0471: setSelectedRADComponents(selectedNodes);
0472:
0473: }
0474:
0475: };
0476: formDesigner.addPropertyChangeListener("activatedNodes",
0477: selectionListener);
0478: }
0479: }
0480:
0481: private void unconfigureSelectionListener() {
0482: if (selectionListener != null) {
0483: formDesigner
0484: .removePropertyChangeListener(selectionListener);
0485: selectionListener = null;
0486: }
0487: }
0488:
0489: void showMenuPopup(final JMenu menu) {
0490: getPopupFactory();
0491: // if already created then just make it visible
0492: if (hackedPopupFactory.containerMap.containsKey(menu)) {
0493: JPanel view = hackedPopupFactory.containerMap.get(menu);
0494: view.setVisible(true);
0495: } else {
0496: if (!isConfigured(menu)) {
0497: configureMenu(null, menu);
0498: }
0499: final JPopupMenu popup = menu.getPopupMenu();
0500:
0501: if (!(popup.getUI() instanceof VisualDesignerPopupMenuUI)) {
0502: popup.setUI(new VisualDesignerPopupMenuUI(this , popup
0503: .getUI()));
0504: }
0505: if (menu.isShowing()) {
0506: //force popup view creation
0507: hackedPopupFactory.getPopup(menu, null, 0, 0);
0508:
0509: // do later so that the component will definitely be on screen by then
0510: SwingUtilities.invokeLater(new Runnable() {
0511: public void run() {
0512: try {
0513: popup.show(menu, 0, menu.getHeight());
0514: } catch (Exception ex) {
0515: ex.printStackTrace();
0516: //ignore anyexceptions caused by showing the popups
0517: }
0518:
0519: }
0520: });
0521: }
0522: }
0523: this .validate();
0524: }
0525:
0526: public boolean isMenuLayerComponent(RADComponent metacomp) {
0527: if (metacomp == null) {
0528: return false;
0529: }
0530: if (metacomp.getBeanClass().equals(JMenuItem.class)) {
0531: return true;
0532: }
0533: if (metacomp.getBeanClass().equals(JMenu.class)) {
0534: return true;
0535: }
0536: return false;
0537: }
0538:
0539: void configureMenu(final JComponent parent, final JMenu menu) {
0540: // make sure it will draw it's border so we can have rollovers and selection
0541: menu.setBorderPainted(true);
0542: //install the wrapper icon if not a toplevel JMenu
0543: if (!isTopLevelMenu(menu)) {
0544: if (!(menu.getIcon() instanceof WrapperIcon)) {
0545: menu.setIcon(new WrapperIcon(menu.getIcon()));
0546: }
0547: }
0548:
0549: // configure the maps and popups
0550: JPopupMenu popup = menu.getPopupMenu();
0551: menuPopupUIMap.put(menu, popup.getUI());
0552: popup.setUI(new VisualDesignerPopupMenuUI(this , popup.getUI()));
0553:
0554: // get all of the components in this menu
0555: Component[] subComps = menu.getMenuComponents();
0556: // if this isn't the first time this menu has been opened then the sub components
0557: // will have been moved to the popupPanel already, so we will find them there instead.
0558: JPanel popupPanel = getPopupFactory().containerMap.get(menu);
0559: if (popupPanel != null) {
0560: subComps = popupPanel.getComponents();
0561: }
0562:
0563: RADVisualContainer menuRAD = (RADVisualContainer) formDesigner
0564: .getMetaComponent(menu);
0565: registerForm(menuRAD, menu);
0566:
0567: // recurse for sub-menus
0568: for (Component c : subComps) {
0569: if (c instanceof JMenu) {
0570: configureMenu(menu, (JMenu) c);
0571: RADComponent rad = formDesigner.getMetaComponent(c);
0572: registerForm((RADVisualContainer) rad, (JMenu) c);
0573: } else {
0574: configureMenuItem(menu, (JComponent) c);
0575: }
0576: }
0577: }
0578:
0579: private void unconfigureMenu(final JMenu menu) {
0580: // restore the UI
0581: menu.getPopupMenu().setUI(menuPopupUIMap.get(menu));
0582:
0583: // restore all children
0584: JPanel popup = hackedPopupFactory.containerMap.get(menu);
0585: if (popup != null) {
0586: for (Component c : popup.getComponents()) {
0587: if (c instanceof JMenu) {
0588: unconfigureMenu((JMenu) c);
0589: } else {
0590: unconfigureMenuItem((JComponent) c);
0591: }
0592: }
0593:
0594: //hide the popup(s) if it's still visible
0595: if (menu.getPopupMenu() != null) {
0596: menu.getPopupMenu().setVisible(false);
0597: }
0598: popup.setVisible(false);
0599: //layers.remove(popup);
0600: }
0601: VisualDesignerJPanelPopup pop = hackedPopupFactory
0602: .getPopup(menu);
0603: if (pop != null) {
0604: pop.hide();
0605: }
0606: if (popup != null) {
0607: popup.setVisible(false);
0608: }
0609: menu.setPopupMenuVisible(false);
0610: hackedPopupFactory.containerMap.remove(menu);
0611: }
0612:
0613: private boolean isConfigured(JComponent c) {
0614: return menuPopupUIMap.containsKey(c);
0615: }
0616:
0617: void configureMenuItem(final JMenu parent, final JComponent c) {
0618: if (c instanceof JMenuItem) {
0619: JMenuItem item = (JMenuItem) c;
0620: if (!(item.getIcon() instanceof WrapperIcon)) {
0621: item.setIcon(new WrapperIcon(item.getIcon()));
0622: }
0623: installAcceleratorPreview(item);
0624: item.setBorderPainted(true);
0625: }
0626: }
0627:
0628: static final int ACCEL_PREVIEW_WIDTH = 80;
0629: private static final Border accel_border = new Border() {
0630:
0631: public void paintBorder(Component c, Graphics g, int x, int y,
0632: int width, int height) {
0633: g.setColor(Color.WHITE);
0634: int offset = 5;
0635: if (DropTargetLayer.isAqua()) {
0636: offset = 2;
0637: }
0638: int ioffset = 0;
0639: if (DropTargetLayer.isVista()) {
0640: ioffset = -2;
0641: }
0642: g
0643: .fillRect(width - ACCEL_PREVIEW_WIDTH + offset, 1,
0644: ACCEL_PREVIEW_WIDTH - 0 + ioffset, height
0645: + ioffset);
0646: g.setColor(EMPTY_ICON_COLOR);
0647: g
0648: .drawRect(width - ACCEL_PREVIEW_WIDTH + offset, 1,
0649: ACCEL_PREVIEW_WIDTH - 1 + ioffset, height
0650: + ioffset);
0651: g.drawRect(width - ACCEL_PREVIEW_WIDTH + offset + 1, 2,
0652: ACCEL_PREVIEW_WIDTH - 3 + ioffset, height - 2
0653: + ioffset);
0654: g.setColor(Color.LIGHT_GRAY);
0655: g.setFont(new Font("SansSerif", Font.PLAIN, 10)); // NOI18N
0656: String shortcut = NbBundle.getMessage(MenuEditLayer.class,
0657: "MENU_Shortcut"); // NOI18N
0658: g.drawString(shortcut, width - ACCEL_PREVIEW_WIDTH + 15,
0659: height - 3 + ioffset);
0660: }
0661:
0662: public Insets getBorderInsets(Component c) {
0663: return new Insets(0, 0, 0, ACCEL_PREVIEW_WIDTH);
0664: }
0665:
0666: public boolean isBorderOpaque() {
0667: return true;
0668: }
0669:
0670: };
0671:
0672: //installs a special border to represent the accelerator preview
0673: //if the menu item already has an accelerator, then it will
0674: //remove the preview if necessary.
0675: private static void installAcceleratorPreview(JMenuItem item) {
0676: if (item instanceof JMenu)
0677: return;
0678: //detect accelerator key
0679: boolean already_has_accel = false;
0680: if (item.getAccelerator() != null)
0681: already_has_accel = true;
0682: if (item.getAction() != null
0683: && item.getAction().getValue(Action.ACCELERATOR_KEY) != null)
0684: already_has_accel = true;
0685:
0686: boolean already_has_accel_border = false;
0687: if (item.getBorder() == accel_border) {
0688: already_has_accel_border = true;
0689: //uninstall if needed
0690: if (already_has_accel) {
0691: item.setBorder(null);
0692: return;
0693: }
0694: }
0695:
0696: if (item.getBorder() instanceof CompoundBorder) {
0697: CompoundBorder comp = (CompoundBorder) item.getBorder();
0698: if (comp.getInsideBorder() == accel_border) {
0699: already_has_accel_border = true;
0700: //uninstall if needed
0701: if (already_has_accel) {
0702: item.setBorder(comp.getOutsideBorder());
0703: return;
0704: }
0705: }
0706: }
0707:
0708: if (already_has_accel_border)
0709: return;
0710: if (already_has_accel)
0711: return;
0712:
0713: if (item.getBorder() == null) {
0714: item.setBorder(accel_border);
0715: return;
0716: }
0717:
0718: item.setBorder(BorderFactory.createCompoundBorder(item
0719: .getBorder(), accel_border));
0720: }
0721:
0722: void unconfigureMenuItem(JComponent c) {
0723: }
0724:
0725: //override JComponent.isOpaque to always return false
0726: @Override
0727: public boolean isOpaque() {
0728: return false;
0729: }
0730:
0731: // returns true if parent really is an ancestor of target
0732: boolean isAncestor(JComponent target, JComponent parent) {
0733: if (!(parent instanceof JMenu)) {
0734: return false;
0735: }
0736: RADComponent targetRad = formDesigner.getMetaComponent(target);
0737: RADComponent parentRad = targetRad.getParentComponent();
0738: if (parentRad == null)
0739: return false;
0740: Object possibleParent = formDesigner.getComponent(parentRad);
0741: RADComponent realParentRad = formDesigner
0742: .getMetaComponent(parent);
0743: if (parentRad == realParentRad) {
0744: return true;
0745: }
0746: if (parent == possibleParent) {
0747: return true;
0748: } else {
0749: // recursively check up the chain to see if this is a further ancestor
0750: if (possibleParent instanceof JMenu) {
0751: return isAncestor((JMenu) possibleParent, parent);
0752: }
0753: }
0754: return false;
0755: }
0756:
0757: boolean hasSelectedDescendants(JMenu menu) {
0758: RADComponent comp = formDesigner.getMetaComponent(menu);
0759: if (comp instanceof RADVisualContainer) {
0760: return hasSelectedDescendants((RADVisualContainer) comp);
0761: }
0762: return false;
0763: }
0764:
0765: boolean hasSelectedDescendants(RADVisualContainer comp) {
0766: if (this .selectedComponents.contains(comp)) {
0767: return true;
0768: }
0769: for (RADComponent c : comp.getSubBeans()) {
0770: if (this .selectedComponents.contains(c))
0771: return true;
0772: if (c instanceof RADVisualContainer) {
0773: boolean sel = hasSelectedDescendants((RADVisualContainer) c);
0774: if (sel)
0775: return true;
0776: }
0777: }
0778: return false;
0779: }
0780:
0781: JComponent getMenuParent(JComponent menu) {
0782: RADComponent targetRad = formDesigner.getMetaComponent(menu);
0783: RADComponent parentRad = targetRad.getParentComponent();
0784: if (parentRad != null) {
0785: Object possibleParent = formDesigner
0786: .getComponent(parentRad);
0787: if (possibleParent instanceof JComponent) {
0788: return (JComponent) possibleParent;
0789: }
0790: }
0791: return null;
0792: }
0793:
0794: List<RADComponent> getSelectedRADComponents() {
0795: return Collections.unmodifiableList(selectedComponents);
0796: }
0797:
0798: RADComponent getSingleSelectedComponent() {
0799: if (selectedComponents.isEmpty()) {
0800: return null;
0801: }
0802: if (selectedComponents.size() > 1) {
0803: setSelectedRADComponent(selectedComponents.get(0));
0804: }
0805: return selectedComponents.get(0);
0806: }
0807:
0808: private List<RADComponent> selectedComponents = new ArrayList<RADComponent>();
0809:
0810: boolean isComponentSelected() {
0811: return !selectedComponents.isEmpty();
0812: }
0813:
0814: void setSelectedRADComponent(RADComponent comp) {
0815: List<RADComponent> comps = new ArrayList<RADComponent>();
0816: comps.add(comp);
0817: setSelectedRADComponents(comps);
0818: formDesigner.setSelectedComponent(comp);
0819: }
0820:
0821: void addSelectedRADComponent(RADComponent comp) {
0822: List<RADComponent> comps = new ArrayList<RADComponent>();
0823: comps.addAll(selectedComponents);
0824: comps.add(comp);
0825: setSelectedRADComponents(comps);
0826: formDesigner.addComponentToSelection(comp);
0827: }
0828:
0829: void setSelectedRADComponents(List<RADComponent> comps) {
0830: try {
0831: //clear old bgs first
0832: for (RADComponent rad : selectedComponents) {
0833: if (isMenuRelatedRADComponent(rad)
0834: && !isMenuBarContainer(rad)
0835: && !isNonMenuJSeparator(rad)) { // don't mess w/ the menubar's background
0836: JComponent c = (JComponent) formDesigner
0837: .getComponent(rad);
0838: if (c != null) { // could be null if comp was just deleted
0839: c.setBackground(getNormalBackground(rad, c));
0840: }
0841: }
0842: }
0843:
0844: selectedComponents.clear();
0845: selectedComponents.addAll(comps);
0846:
0847: //check for non-menu comps
0848: for (RADComponent c : selectedComponents) {
0849: if (!isMenuRelatedRADComponent(c)
0850: || isNonMenuJSeparator(c)) {
0851: setVisible(false);
0852: return;
0853: }
0854: }
0855:
0856: registerKeyListeners();
0857:
0858: for (RADComponent rad : selectedComponents) {
0859: JComponent c = (JComponent) formDesigner
0860: .getComponent(rad);
0861: if (c != null) {
0862: if (!isMenuBarContainer(rad)) { // don't mess w/ the menubar's background
0863: c.setBackground(getSelectedBackground(c));
0864: }
0865: makeSureShowingOnScreen(rad, c);
0866: if (c instanceof JMenu) {
0867: showMenuPopup((JMenu) c);
0868: }
0869: }
0870: }
0871:
0872: repaint();
0873:
0874: } catch (Exception ex) {
0875: ex.printStackTrace();
0876: }
0877: }
0878:
0879: private String getComponentDefaultsPrefix(JComponent c) {
0880: if (c instanceof JMenuBar) {
0881: return "MenuBar"; // NOI18N
0882: }
0883: if (c instanceof JMenu) {
0884: return "Menu"; // NOI18N
0885: }
0886: if (c instanceof JCheckBoxMenuItem) {
0887: return "CheckBoxMenuItem"; // NOI18N
0888: }
0889: if (c instanceof JRadioButtonMenuItem) {
0890: return "RadioButtonMenuItem"; // NOI18N
0891: }
0892: return "MenuItem"; // NOI18N
0893: }
0894:
0895: private Color getNormalBackground(RADComponent metacomp,
0896: JComponent c) {
0897: RADProperty prop = metacomp.getBeanProperty("background"); // NOI18N
0898: Color color = null;
0899: if (prop != null) {
0900: try {
0901: Object value = prop.getTargetValue();
0902: if (value instanceof Color) {
0903: color = (Color) value;
0904: }
0905: } catch (Exception ex) {
0906: }
0907: }
0908: if (color == null) {
0909: // fallback - for example subclass of menu component
0910: // that hides background property
0911: color = backgroundMap.get(c);
0912: }
0913: return color;
0914: }
0915:
0916: private Map<JComponent, Color> backgroundMap = new HashMap<JComponent, Color>();
0917:
0918: private Color getSelectedBackground(JComponent c) {
0919: //don't put into the map twice
0920: if (!backgroundMap.containsKey(c)) {
0921: backgroundMap.put(c, c.getBackground());
0922: }
0923: return SELECTED_MENU_BACKGROUND;
0924: }
0925:
0926: private Color getNormalForeground(JComponent c) {
0927: String prefix = getComponentDefaultsPrefix(c);
0928: Color color = UIManager.getDefaults().getColor(
0929: prefix + ".foreground"); // NOI18N
0930: if (color == null) {
0931: color = Color.BLACK;
0932: }
0933: return color;
0934: }
0935:
0936: private void makeSureShowingOnScreen(RADComponent rad,
0937: JComponent comp) {
0938: if (!this .isVisible()) {
0939: this .setVisible(true);
0940: registerKeyListeners();
0941: if (rad instanceof RADVisualContainer) {
0942: keyboardMenuNavigator
0943: .setCurrentMenuRAD((RADVisualContainer) rad);
0944: } else {
0945: keyboardMenuNavigator
0946: .setCurrentMenuRAD((RADVisualContainer) rad
0947: .getParentComponent());
0948: }
0949: }
0950:
0951: List<RADComponent> path = new ArrayList<RADComponent>();
0952: RADComponent temp = rad.getParentComponent();
0953: while (true) {
0954: if (temp == null)
0955: break;
0956: path.add(temp);
0957: temp = temp.getParentComponent();
0958: if (!isMenuRelatedRADComponent(temp)) {
0959: break;
0960: }
0961: }
0962:
0963: // go backwards, top to bottom
0964: for (int i = path.size() - 1; i >= 0; i--) {
0965: RADComponent r = path.get(i);
0966: JComponent c = (JComponent) formDesigner.getComponent(r);
0967: if (c instanceof JMenu) {
0968: showMenuPopup((JMenu) c);
0969: }
0970: }
0971:
0972: }
0973:
0974: private void showContextMenu(Point popupPos) {
0975: ComponentInspector inspector = ComponentInspector.getInstance();
0976: Node[] selectedNodes = inspector.getSelectedNodes();
0977: JPopupMenu popup = NodeOp.findContextMenu(selectedNodes);
0978: if (!this .isVisible()) {
0979: this .setVisible(true);
0980: }
0981: if (popup != null) {
0982: popup.show(this , popupPos.x, popupPos.y);
0983: }
0984: }
0985:
0986: // returns true if this is a menu container that should be highlighted if the component
0987: // tcomp is dragged over it.
0988: public boolean canHighlightContainer(
0989: RADVisualContainer targetContainer, RADVisualComponent tcomp) {
0990: Class beanclass = tcomp.getBeanClass();
0991: if (targetContainer != null
0992: && targetContainer.isMenuComponent()
0993: && targetContainer.canAddComponent(beanclass)) {
0994: return true;
0995: }
0996: return false;
0997: }
0998:
0999: // is this rollover code still being used?
1000: // this turns on and off the rollover highlight as well as auto-opening the menu
1001: // if it is a menu
1002: private JComponent prevRollover = null;
1003:
1004: public void rolloverContainer(RADVisualContainer targetContainer) {
1005: if (targetContainer == null && prevRollover != null) {
1006: clearRollover();
1007: }
1008: if (targetContainer != null) {
1009: JComponent rollover = (JComponent) formDesigner
1010: .getComponent(targetContainer);
1011: if (rollover != prevRollover) {
1012: clearRollover();
1013: }
1014: prevRollover = rollover;
1015: prevRollover.setBorder(new Border() {
1016:
1017: public void paintBorder(Component c, Graphics g, int x,
1018: int y, int width, int height) {
1019: Graphics2D g2 = (Graphics2D) g;
1020: g2
1021: .setStroke(DropTargetLayer.DROP_TARGET_LINE_STROKE);
1022: g2.setColor(DropTargetLayer.DROP_TARGET_COLOR);
1023: g2.drawRect(x, y, width, height);
1024: }
1025:
1026: public Insets getBorderInsets(Component c) {
1027: return new Insets(2, 2, 2, 2);
1028: }
1029:
1030: public boolean isBorderOpaque() {
1031: return false;
1032: }
1033: //BorderFactory.createLineBorder(Color.ORANGE,2)
1034: });
1035: prevRollover.repaint();
1036: if (rollover instanceof JMenu) {
1037: formDesigner.openMenu(targetContainer);
1038: //openMenu(targetContainer,rollover);
1039: }
1040: }
1041: }
1042:
1043: public void clearRollover() {
1044: if (prevRollover == null)
1045: return;
1046: prevRollover.setBorder(BorderFactory.createEmptyBorder());
1047: prevRollover.repaint();
1048: prevRollover = null;
1049: }
1050:
1051: void addRadComponentToBefore(RADVisualComponent payloadRad,
1052: JComponent target) {
1053: addRadComponentTo(payloadRad, target, +0);
1054: }
1055:
1056: void addRadComponentToAfter(RADVisualComponent payloadRad,
1057: JComponent target) {
1058: addRadComponentTo(payloadRad, target, +1);
1059: }
1060:
1061: private void addRadComponentTo(RADVisualComponent payloadRad,
1062: JComponent target, int offset) {
1063: try {
1064: JComponent targetParent = getMenuParent(target);
1065: if (target.getParent() instanceof JMenuBar) {
1066: targetParent = (JComponent) target.getParent();
1067: }
1068: RADVisualComponent targetRad = (RADVisualComponent) formDesigner
1069: .getMetaComponent(target);
1070: RADVisualContainer targetParentRad = (RADVisualContainer) formDesigner
1071: .getMetaComponent(targetParent);
1072:
1073: assert targetParentRad != null;
1074:
1075: int index2 = targetParentRad.getIndexOf(targetRad) + offset;
1076: formDesigner.getFormModel().fireComponentAdded(payloadRad,
1077: false);
1078: formDesigner.getFormModel().addVisualComponent(payloadRad,
1079: targetParentRad, new Integer(index2), true);
1080: } catch (Exception ex) {
1081: ex.printStackTrace();
1082: }
1083:
1084: }
1085:
1086: boolean addRadComponentToEnd(JComponent targetComponent,
1087: MetaComponentCreator creator) {
1088: RADVisualContainer targetContainer = (RADVisualContainer) formDesigner
1089: .getMetaComponent(targetComponent);
1090: Object constraints = null;
1091: boolean added = creator.addPrecreatedComponent(targetContainer,
1092: constraints);
1093: return added;
1094: }
1095:
1096: void moveRadComponentInto(JComponent payload, JComponent targetMenu) {
1097: try {
1098:
1099: //check if dragging onto self
1100: if (payload == targetMenu) {
1101: return;
1102: }
1103:
1104: //check if dragging to a descendant node
1105: if (isAncestor(targetMenu, payload)) {
1106: return;
1107: }
1108:
1109: JComponent payloadParent = getMenuParent(payload);
1110: if (payloadParent == null) {
1111: payloadParent = (JComponent) payload.getParent();
1112: }
1113: RADVisualComponent payloadRad = (RADVisualComponent) formDesigner
1114: .getMetaComponent(payload);
1115: RADVisualContainer payloadParentRad = (RADVisualContainer) formDesigner
1116: .getMetaComponent(payloadParent);
1117:
1118: // remove the component from it's old location
1119: // if no payload rad then that probably means this is a new component from the palette
1120: if (payloadRad != null && payloadParentRad != null) {
1121: int index = payloadParentRad.getIndexOf(payloadRad);
1122: payloadParentRad.remove(payloadRad);
1123: formDesigner.getFormModel().fireComponentRemoved(
1124: payloadRad, payloadParentRad, index, false);
1125: }
1126:
1127: RADVisualContainer targetMenuRad = (RADVisualContainer) formDesigner
1128: .getMetaComponent(targetMenu);
1129: //add inside the target menu
1130: //add to end of the toplevel menu
1131: targetMenuRad.add(payloadRad, -1);
1132: targetMenuRad.getLayoutSupport().addComponents(
1133: new RADVisualComponent[] { payloadRad }, null, -1);
1134: formDesigner.getFormModel().fireComponentAdded(payloadRad,
1135: false);
1136: return;
1137: } catch (Exception ex) {
1138: ex.printStackTrace();
1139: }
1140: }
1141:
1142: void moveRadComponentToBefore(JComponent payload, JComponent target) {
1143: moveRadComponentTo(payload, target, 0);
1144: }
1145:
1146: void moveRadComponentToAfter(JComponent payload, JComponent target) {
1147: moveRadComponentTo(payload, target, 1);
1148: }
1149:
1150: private void moveRadComponentTo(JComponent payload,
1151: JComponent target, int offset) {
1152: try {
1153: if (payload == target) {
1154: return;
1155: }
1156: //check if dragging to a descendant node
1157: if (isAncestor(target, payload)) {
1158: return;
1159: }
1160: JComponent payloadParent = getMenuParent(payload);
1161: /*
1162: if(payloadParent == null) {
1163: payloadParent = (JComponent) payload.getParent();
1164: }*/
1165:
1166: JComponent targetParent = getMenuParent(target);
1167:
1168: if (targetParent == null) {
1169: targetParent = (JComponent) target.getParent();
1170: }
1171: RADVisualComponent payloadRad = (RADVisualComponent) formDesigner
1172: .getMetaComponent(payload);
1173: RADVisualComponent targetRad = (RADVisualComponent) formDesigner
1174: .getMetaComponent(target);
1175: RADVisualContainer payloadParentRad = (RADVisualContainer) formDesigner
1176: .getMetaComponent(payloadParent);
1177: RADVisualContainer targetParentRad = (RADVisualContainer) formDesigner
1178: .getMetaComponent(targetParent);
1179:
1180: //if a toplevel menu dragged next to another toplevel menu
1181: if (payload instanceof JMenu
1182: && payload.getParent() instanceof JMenuBar
1183: && target instanceof JMenu
1184: && target.getParent() instanceof JMenuBar) {
1185: //remove from old spot
1186: targetParent = (JComponent) target.getParent();
1187: payloadParent = (JComponent) payload.getParent();
1188: payloadParentRad = (RADVisualContainer) formDesigner
1189: .getMetaComponent(payloadParent);
1190: targetParentRad = (RADVisualContainer) formDesigner
1191: .getMetaComponent(targetParent);
1192: }
1193:
1194: //skip if no payload rad, which probably means this is a new component from the palette
1195: if (payloadRad != null && payloadParentRad != null) {
1196: int index = payloadParentRad.getIndexOf(payloadRad);
1197: payloadParentRad.remove(payloadRad);
1198: formDesigner.getFormModel().fireComponentRemoved(
1199: payloadRad, payloadParentRad, index, false);
1200: }
1201:
1202: //if dragged component into a toplevel menu
1203: if (targetParent == null && target instanceof JMenu
1204: && target.getParent() instanceof JMenuBar) {
1205: targetParentRad = (RADVisualContainer) targetRad;
1206: //add to end of the toplevel menu
1207: targetParentRad.add(payloadRad, -1);
1208: targetParentRad.getLayoutSupport().addComponents(
1209: new RADVisualComponent[] { payloadRad }, null,
1210: -1);
1211: formDesigner.getFormModel().fireComponentAdded(
1212: payloadRad, false);
1213: return;
1214: }
1215:
1216: // insert if target exists, else the item was removed by dragging out of the menu
1217: if (targetParentRad != null) {
1218: int index2 = targetParentRad.getIndexOf(targetRad)
1219: + offset;
1220: targetParentRad.add(payloadRad, index2);
1221: targetParentRad.getLayoutSupport().addComponents(
1222: new RADVisualComponent[] { payloadRad }, null,
1223: index2);
1224: formDesigner.getFormModel().fireComponentAdded(
1225: payloadRad, false);
1226: }
1227: } catch (Exception ex) {
1228: ex.printStackTrace();
1229: }
1230: }
1231:
1232: public static boolean addComponentToEndOfMenu(
1233: RADComponent targetContainer, PaletteItem paletteItem) {
1234: FormModel model = targetContainer.getFormModel();
1235: MetaComponentCreator creator = model.getComponentCreator();
1236: creator.precreateVisualComponent(paletteItem
1237: .getComponentClassSource());
1238: boolean added = creator.addPrecreatedComponent(targetContainer,
1239: null);
1240: return added;
1241: }
1242:
1243: // change the look of the component to reflect the newly added state.
1244: // this mainly means making the foreground color light gray.
1245: void configureNewComponent(RADComponent item) {
1246: if (item != null) {
1247: JComponent c = (JComponent) formDesigner.getComponent(item);
1248: if (c != null) {
1249: c.setForeground(Color.LIGHT_GRAY);
1250: }
1251: }
1252: }
1253:
1254: // change the look of the component to reflect the fully edited state
1255: private void configureEditedComponent(JComponent c) {
1256: if (c == null)
1257: return;
1258: if (USE_NEW_ITEM_COLOR_SWITCHING) {
1259: if (c.getForeground() == Color.LIGHT_GRAY) {
1260: c.setForeground(getNormalForeground(c));
1261: }
1262: }
1263: }
1264:
1265: void configureEditedComponent(RADComponent c) {
1266: if (c != null) {
1267: configureEditedComponent((JComponent) formDesigner
1268: .getComponent(c));
1269: }
1270: }
1271:
1272: //listens to see if this particular menu has been changed
1273: private void registerForm(final RADVisualContainer metacomp,
1274: final JMenu menu) {
1275: // don't double register
1276: if (!formModelListeners.containsKey(metacomp)) {
1277: FormModelListener fml = new FormModelListener() {
1278: public void formChanged(FormModelEvent[] events) {
1279: if (events != null) {
1280: for (FormModelEvent evt : events) {
1281: if (evt.getChangeType() == FormModelEvent.FORM_TO_BE_CLOSED) {
1282: formModelListeners.remove(metacomp);
1283: metacomp.getFormModel()
1284: .addFormModelListener(this );
1285: continue;
1286: }
1287:
1288: if (evt.getChangeType() == FormModelEvent.COMPONENT_PROPERTY_CHANGED) {
1289: if ("action".equals(evt
1290: .getPropertyName())) { // NOI18N
1291: configureEditedComponent(evt
1292: .getComponent());
1293: }
1294: }
1295: if (evt.getChangeType() == FormModelEvent.COMPONENT_PROPERTY_CHANGED
1296: || evt.getChangeType() == FormModelEvent.BINDING_PROPERTY_CHANGED) {
1297: if (evt.getContainer() == metacomp
1298: || evt.getComponent() == metacomp) {
1299: rebuildOnScreenMenu(metacomp);
1300: }
1301: updateIcon(evt.getComponent());
1302: }
1303:
1304: if (evt.getChangeType() == FormModelEvent.COMPONENT_ADDED) {
1305: updateIcon(evt.getComponent());
1306: //reinstall the accelerator preview when moving items around
1307: if (evt.getComponent() != null) {
1308: Component co = (Component) formDesigner
1309: .getComponent(evt
1310: .getComponent());
1311: if (co instanceof JMenuItem) {
1312: installAcceleratorPreview((JMenuItem) co);
1313: }
1314: }
1315: }
1316:
1317: // if this menu was deleted then make sure it's popup is hidden and removed
1318: if (evt.getChangeType() == FormModelEvent.COMPONENT_REMOVED) {
1319: if (evt.getComponent() == metacomp) {
1320: unconfigureMenu(menu);
1321: continue;
1322: }
1323: }
1324: // if something added to the menu we monitor
1325: if (evt.getChangeType() == FormModelEvent.COMPONENT_ADDED
1326: || evt.getChangeType() == FormModelEvent.COMPONENTS_REORDERED
1327: || evt.getChangeType() == FormModelEvent.COMPONENT_REMOVED) {
1328: if (evt.getContainer() == metacomp) {
1329: // then rebuild the menu
1330: rebuildOnScreenMenu(metacomp);
1331: return;
1332: }
1333: if (evt.getContainer() == getFormMenuBar()) {
1334: JComponent comp = (JComponent) formDesigner
1335: .getComponent(getFormMenuBar());
1336: if (comp != null) { // MenuBar not shown in the designer, see issue 124873
1337: RADVisualContainer rad = (RADVisualContainer) getFormMenuBar();
1338: comp.removeAll();
1339: for (RADVisualComponent c : rad
1340: .getSubComponents()) {
1341: if (c != null) {
1342: comp
1343: .add((JComponent) formDesigner
1344: .getComponent(c));
1345: }
1346: }
1347: }
1348: }
1349: }
1350: }
1351: }
1352: }
1353: };
1354: formModelListeners.put(metacomp, fml);
1355: metacomp.getFormModel().addFormModelListener(fml);
1356: }
1357: }
1358:
1359: private void rebuildOnScreenMenu(RADVisualContainer menuRAD) {
1360: if (menuRAD == null)
1361: return;
1362: if (hackedPopupFactory == null)
1363: return;
1364: JMenu menu = (JMenu) formDesigner.getComponent(menuRAD);
1365: if (hackedPopupFactory.containerMap.containsKey(menu)) {
1366: JPanel popupContainer = hackedPopupFactory.containerMap
1367: .get(menu);
1368: if (popupContainer == null)
1369: return;
1370: for (Component c : popupContainer.getComponents()) {
1371: if (c instanceof JMenu) {
1372: unconfigureMenu((JMenu) c);
1373: } else {
1374: unconfigureMenuItem((JComponent) c);
1375: }
1376: }
1377: popupContainer.removeAll();
1378: // rebuild it
1379: for (RADVisualComponent child : menuRAD.getSubComponents()) {
1380: if (child != null) {
1381: JComponent jchild = (JComponent) formDesigner
1382: .getComponent(child);
1383: if (!isConfigured(jchild)) {
1384: if (jchild instanceof JMenu) {
1385: configureMenu(menu, (JMenu) jchild);
1386: } else {
1387: configureMenuItem(menu, jchild);
1388: }
1389: }
1390: popupContainer.add(jchild);
1391: }
1392: }
1393:
1394: // repack it
1395: popupContainer.setSize(popupContainer.getLayout()
1396: .preferredLayoutSize(popupContainer));
1397: validate();
1398: popupContainer.repaint();
1399: }
1400: }
1401:
1402: private void updateIcon(RADComponent rad) {
1403: try {
1404: Component comp = (Component) formDesigner.getComponent(rad);
1405: if (comp instanceof JMenuItem) {
1406: JMenuItem item = (JMenuItem) comp;
1407: RADProperty icon_prop = rad.getBeanProperty("icon");
1408: Object value = icon_prop.getValue();
1409: // extract the new value
1410: Icon icon = null;
1411: if (value instanceof Icon) {
1412: icon = (Icon) value;
1413: }
1414: if (value instanceof NbImageIcon) {
1415: icon = ((NbImageIcon) value).getIcon();
1416: }
1417: if (value instanceof ResourceValue) {
1418: ResourceValue rv = (ResourceValue) value;
1419: Object designValue = rv.getDesignValue();
1420: if (designValue instanceof Icon) {
1421: icon = (Icon) designValue;
1422: }
1423: if (designValue instanceof NbImageIcon) {
1424: icon = ((NbImageIcon) designValue).getIcon();
1425: }
1426: }
1427: // do the actual update
1428: if (!(item.getIcon() instanceof WrapperIcon)
1429: && !isTopLevelMenu(item)) {
1430: item.setIcon(new WrapperIcon(item.getIcon()));
1431: }
1432:
1433: if (item.getIcon() instanceof WrapperIcon) {
1434: ((WrapperIcon) item.getIcon()).setIcon(icon);
1435: } else { // we should never get here
1436: item.setIcon(icon);
1437: }
1438: }
1439: } catch (Throwable thr) {
1440: thr.printStackTrace();
1441: }
1442:
1443: }
1444:
1445: //returns true if this array contains a menu component
1446: public static boolean containsMenuTypeComponent(
1447: RADVisualComponent[] comps) {
1448: if (comps == null)
1449: return false;
1450: if (comps.length < 1)
1451: return false;
1452: for (RADVisualComponent c : comps) {
1453: if (JMenuItem.class.isAssignableFrom(c.getBeanClass()))
1454: return true;
1455: if (JMenuBar.class.isAssignableFrom(c.getBeanClass()))
1456: return true;
1457: if (JMenu.class.isAssignableFrom(c.getBeanClass()))
1458: return true;
1459: }
1460: return false;
1461: }
1462:
1463: public static boolean containsMenuBar(RADVisualComponent[] comps) {
1464: if (comps == null)
1465: return false;
1466: if (comps.length < 1)
1467: return false;
1468: for (RADVisualComponent c : comps) {
1469: if (JMenuBar.class.isAssignableFrom(c.getBeanClass()))
1470: return true;
1471: }
1472: return false;
1473: }
1474:
1475: // returns true if this container is a menubar or menu, else false
1476: public static boolean isValidMenuContainer(RADVisualContainer cont) {
1477: if (cont == null)
1478: return false;
1479: if (JMenuBar.class.isAssignableFrom(cont.getBeanClass()))
1480: return true;
1481: if (JMenu.class.isAssignableFrom(cont.getBeanClass()))
1482: return true;
1483: return false;
1484: }
1485:
1486: public static boolean isTopLevelMenu(JComponent comp) {
1487: if (comp == null)
1488: return false;
1489: if (comp instanceof JMenu) {
1490: if (comp.getParent() instanceof JMenuBar)
1491: return true;
1492: }
1493: return false;
1494: }
1495:
1496: public boolean doesFormContainMenuBar() {
1497: for (RADComponent comp : formDesigner.getFormModel()
1498: .getAllComponents()) {
1499: if (JMenuBar.class.isAssignableFrom(comp.getBeanClass())) {
1500: return true;
1501: }
1502: }
1503: return false;
1504: }
1505:
1506: public RADComponent getFormMenuBar() {
1507: for (RADComponent comp : formDesigner.getFormModel()
1508: .getAllComponents()) {
1509: if (JMenuBar.class.isAssignableFrom(comp.getBeanClass())) {
1510: return comp;
1511: }
1512: }
1513: return null;
1514: }
1515:
1516: private class GlassLayerMouseListener extends MouseInputAdapter {
1517: Point pressPoint = null;
1518: JComponent pressComp = null;
1519: private boolean isEditing = false;
1520:
1521: @Override
1522: public void mousePressed(MouseEvent e) {
1523: //if this is a valid menu drop
1524: if (dragop.isStarted()
1525: && dragop.getTargetComponent() != null
1526: && isMenuRelatedComponentClass(dragop
1527: .getTargetComponent().getClass())) {
1528: if (e.isShiftDown()) {
1529: dragop.end(e.getPoint(), false);
1530: PaletteItem item = PaletteUtils.getSelectedItem();
1531: dragop.start(item, e.getPoint());
1532: } else {
1533: dragop.end(e.getPoint(), true);
1534: }
1535: return;
1536: }
1537: if (shouldRedispatchToHandle()) {
1538: dragop.fastEnd();
1539: formDesigner.getHandleLayer().dispatchEvent(e);
1540: return;
1541: }
1542: // drag drag ops
1543: if (dragop.isStarted()) {
1544: dragop.end(e.getPoint());
1545: return;
1546: }
1547:
1548: // open top level menus when clicking them
1549: RADComponent rad = formDesigner.getHandleLayer()
1550: .getMetaComponentAt(e.getPoint(),
1551: HandleLayer.COMP_DEEPEST);
1552: if (rad != null) {
1553: JComponent c = (JComponent) formDesigner
1554: .getComponent(rad);
1555: if (c != null && isTopLevelMenu(c)) {
1556: if (e.getClickCount() > 1) {
1557: isEditing = true;
1558: configureEditedComponent(c);
1559: formDesigner.startInPlaceEditing(rad);
1560: } else {
1561: openMenu(rad, c);
1562: glassLayer.requestFocusInWindow();
1563: if (DropTargetLayer.isMultiselectPressed(e)) {
1564: addSelectedRADComponent(rad);
1565: } else {
1566: setSelectedRADComponent(rad);
1567: }
1568: if (e.isPopupTrigger()) {
1569: showContextMenu(e.getPoint());
1570: return;
1571: }
1572: if (!dragop.isStarted()) {
1573: pressPoint = e.getPoint();
1574: pressComp = c;
1575: return;
1576: }
1577: }
1578: return;
1579: }
1580: if (c instanceof JMenuBar) {
1581: setSelectedRADComponent(rad);
1582: if (e.isPopupTrigger()) {
1583: showContextMenu(e.getPoint());
1584: return;
1585: }
1586: return;
1587: }
1588: }
1589:
1590: JComponent c = dragop.getDeepestComponentInPopups(e
1591: .getPoint());
1592:
1593: if (c == null && !isMenuRelatedRADComponent(rad)) {
1594: PaletteUtils.clearPaletteSelection();
1595: hideMenuLayer();
1596: formDesigner.getHandleLayer().mousePressed(e);
1597: return;
1598: }
1599:
1600: // start editing
1601: if (e.getClickCount() > 1) {
1602: if (c instanceof JMenuItem) {
1603: JMenuItem item = (JMenuItem) c;
1604: Point pt = SwingUtilities.convertPoint(glassLayer,
1605: e.getPoint(), item);
1606: SelectedPortion portion = DropTargetLayer
1607: .calculateSelectedPortion(item, pt);
1608: RADComponent radcomp = formDesigner
1609: .getMetaComponent(item);
1610: configureEditedComponent(c);
1611: if (portion == SelectedPortion.Icon) {
1612: showIconEditor(radcomp);
1613: } else if (portion == SelectedPortion.Accelerator) {
1614: showAcceleratorEditor(radcomp);
1615: } else {
1616: isEditing = true;
1617: formDesigner.startInPlaceEditing(radcomp);
1618: }
1619: }
1620: }
1621:
1622: // show context menu
1623: if (e.isPopupTrigger()) {
1624: showContextMenu(e.getPoint());
1625: return;
1626: }
1627:
1628: //prep for drag motion for menuitem to menuitem drags
1629: if (!dragop.isStarted() && c instanceof JMenuItem) {
1630: pressPoint = e.getPoint();
1631: pressComp = c;
1632: return;
1633: }
1634: }
1635:
1636: @Override
1637: public void mouseReleased(MouseEvent e) {
1638: if (e.isPopupTrigger()) {
1639: showContextMenu(e.getPoint());
1640: return;
1641: }
1642:
1643: if (dragop.isStarted() && !e.isShiftDown()) {
1644: dragop.end(e.getPoint());
1645: } else {
1646: if (!isEditing) {
1647: JComponent c = dragop.getDeepestComponentInPopups(e
1648: .getPoint());
1649: if (c != null) {
1650: if (c instanceof JMenuItem) {
1651: Point localPt = SwingUtilities
1652: .convertPoint(glassLayer, e
1653: .getPoint(), c);
1654: selectedPortion = DropTargetLayer
1655: .calculateSelectedPortion(
1656: (JMenuItem) c, localPt);
1657: dropTargetLayer.repaint();
1658: } else {
1659: selectedPortion = SelectedPortion.None;
1660: }
1661: glassLayer.requestFocusInWindow();
1662: RADComponent rad = formDesigner
1663: .getMetaComponent(c);
1664: //add to selection if shift is down, instead of replacing
1665: if (DropTargetLayer.isMultiselectPressed(e)) {
1666: addSelectedRADComponent(rad);
1667: } else {
1668: setSelectedRADComponent(rad);
1669: }
1670: }
1671: }
1672: isEditing = false;
1673: }
1674: }
1675:
1676: private void showIconEditor(RADComponent comp) {
1677: try {
1678: RADProperty prop = comp.getBeanProperty("icon"); // NOI18N
1679: new PropertyAction(prop).actionPerformed(null);
1680: } catch (Throwable th) {
1681: th.printStackTrace();
1682: }
1683: }
1684:
1685: private void showAcceleratorEditor(RADComponent comp) {
1686: try {
1687: RADProperty prop = comp.getBeanProperty("accelerator"); // NOI18N
1688: new PropertyAction(prop).actionPerformed(null);
1689: } catch (Throwable th) {
1690: th.printStackTrace();
1691: }
1692: }
1693:
1694: @Override
1695: public void mouseEntered(MouseEvent e) {
1696: if (showMenubarWarning) {
1697: showMenubarWarning = false;
1698: repaint();
1699: }
1700: if (dragop.isStarted()) {
1701: if (PaletteUtils.getSelectedItem() == null
1702: && dragop.isPickAndPlop()) {
1703: dragop.fastEnd();
1704: } else {
1705: dragop.setTargetVisible(true);
1706: }
1707: }
1708: if (!dragop.isStarted()
1709: || PaletteUtils.getSelectedItem() != dragop
1710: .getCurrentItem()) {
1711: PaletteItem item = PaletteUtils.getSelectedItem();
1712:
1713: // if not menu related at all, then jump back to handle layer
1714: if (item != null
1715: && !isMenuRelatedComponentClass(item
1716: .getComponentClass())) {
1717: hideMenuLayer();
1718: return;
1719: }
1720:
1721: if (formDesigner.getDesignerMode() == FormDesigner.MODE_ADD
1722: && item != null) {
1723: if (JMenuBar.class.isAssignableFrom(item
1724: .getComponentClass())) {
1725: hideMenuLayer();
1726: return;
1727: }
1728: dragop.start(item, e.getPoint());
1729: }
1730:
1731: /*
1732: if(formDesigner.getDesignerMode() == FormDesigner.MODE_SELECT && showMenubarWarning) {
1733: //glassLayer.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
1734: showMenubarWarning = false;
1735: repaint();
1736: }*/
1737: }
1738: }
1739:
1740: @Override
1741: public void mouseExited(MouseEvent e) {
1742: if (dragop.isStarted()) {
1743: dragop.setTargetVisible(false);
1744: }
1745: }
1746:
1747: @Override
1748: public void mouseDragged(MouseEvent e) {
1749: if (!dragop.isStarted() && pressPoint != null
1750: && pressComp instanceof JMenuItem
1751: && e.getPoint().distance(pressPoint) > 10) {
1752: dragop.start((JMenuItem) pressComp, e.getPoint());
1753: pressPoint = null;
1754: pressComp = null;
1755: }
1756: if (dragop.isStarted()) {
1757: dragop.move(e.getPoint());
1758: }
1759: return;
1760: }
1761:
1762: @Override
1763: public void mouseMoved(MouseEvent e) {
1764: if (shouldRedispatchToHandle()) {
1765: formDesigner.getHandleLayer().dispatchEvent(e);
1766: //hideMenuLayer();
1767: //return;
1768: }
1769: if (dragop.isStarted()) {
1770: if (!doesFormContainMenuBar()) {
1771: FormEditor.getAssistantModel(
1772: formDesigner.getFormModel()).setContext(
1773: "missingMenubar"); // NOI18N
1774: }
1775: dragop.move(e.getPoint());
1776: }
1777:
1778: }
1779:
1780: private boolean shouldRedispatchToHandle() {
1781: if (!USE_JSEPARATOR_FIX)
1782: return false;
1783: if (dragop.isStarted() && dragop.isPickAndPlop()) {
1784: if (dragop.getDragComponent() instanceof JSeparator /*&&
1785: dropTargetLayer.getDropTargetComponent() == null*/) {
1786: return true;
1787: }
1788: }
1789: return false;
1790: }
1791:
1792: }
1793:
1794: private boolean shouldRedispatchDnDToHandle(DropTargetDragEvent dtde) {
1795: RADComponent rad = formDesigner.getHandleLayer()
1796: .getMetaComponentAt(dtde.getLocation(),
1797: HandleLayer.COMP_DEEPEST);
1798: if (rad != null
1799: && isMenuRelatedComponentClass(rad.getBeanClass())) {
1800: return false;
1801: }
1802: if (!USE_JSEPARATOR_FIX)
1803: return false;
1804: PaletteItem item = PaletteUtils.getSelectedItem();
1805: if (item != null
1806: && JSeparator.class.isAssignableFrom(item
1807: .getComponentClass())) {
1808: return true;
1809: }
1810: return false;
1811: }
1812:
1813: private class GlassLayerDropTargetListener implements
1814: DropTargetListener {
1815: public void dragEnter(DropTargetDragEvent dtde) {
1816: if (shouldRedispatchDnDToHandle(dtde)) {
1817: dragProxying = true;
1818: formDesigner.getHandleLayer()
1819: .getNewComponentDropListener().dragEnter(dtde);
1820: return;
1821: }
1822: if (!dragop.isStarted()) {
1823: start(dtde);
1824: }
1825: }
1826:
1827: private void start(DropTargetDragEvent dtde) {
1828: PaletteItem item = PaletteUtils.getSelectedItem();
1829:
1830: if (item != null
1831: && !isMenuRelatedComponentClass(item
1832: .getComponentClass())) {
1833: hideMenuLayer();
1834: return;
1835: }
1836:
1837: if (formDesigner.getDesignerMode() == FormDesigner.MODE_ADD
1838: && item != null) {
1839: if (JMenuBar.class.isAssignableFrom(item
1840: .getComponentClass())) {
1841: hideMenuLayer();
1842: return;
1843: }
1844: dragop.start(item, dtde.getLocation());
1845: }
1846: }
1847:
1848: public void dragOver(DropTargetDragEvent dtde) {
1849: // look at the rad component under the cursor first
1850: if (dragProxying && shouldRedispatchDnDToHandle(dtde)) {
1851: formDesigner.getHandleLayer()
1852: .getNewComponentDropListener().dragOver(dtde);
1853: return;
1854: }
1855: dragProxying = false;
1856: if (dragop.isStarted()) {
1857: dragop.move(dtde.getLocation());
1858: } else {
1859: start(dtde);
1860: }
1861: }
1862:
1863: public void dropActionChanged(DropTargetDragEvent dtde) {
1864: }
1865:
1866: public void dragExit(DropTargetEvent dte) {
1867: //if(shouldRedispatchDnDToHandle()) {
1868: if (dragProxying) {
1869: formDesigner.getHandleLayer()
1870: .getNewComponentDropListener().dragExit(dte);
1871: }
1872: dragProxying = false;
1873: }
1874:
1875: public void drop(DropTargetDropEvent dtde) {
1876: //if(shouldRedispatchDnDToHandle()) {
1877: if (dragProxying) {
1878: formDesigner.getHandleLayer()
1879: .getNewComponentDropListener().drop(dtde);
1880: dragProxying = false;
1881: return;
1882: }
1883: if (dragop.isStarted()) {
1884: dragop.end(dtde.getLocation());
1885: dragProxying = false;
1886: return;
1887: }
1888: }
1889:
1890: }
1891:
1892: public SelectedPortion getCurrentSelectedPortion() {
1893: return selectedPortion;
1894: }
1895:
1896: private boolean dragProxying = false;
1897:
1898: public boolean isDragProxying() {
1899: return dragProxying;
1900: }
1901:
1902: static class WrapperIcon implements Icon {
1903: private Icon wrapee;
1904:
1905: public WrapperIcon() {
1906: this (null);
1907: }
1908:
1909: public WrapperIcon(Icon icon) {
1910: wrapee = icon;
1911: }
1912:
1913: public void setIcon(Icon icon) {
1914: this .wrapee = icon;
1915: }
1916:
1917: public void paintIcon(Component arg0, Graphics g, int x, int y) {
1918: if (wrapee != null) {
1919: wrapee.paintIcon(arg0, g, x, y);
1920: } else {
1921: Graphics g2 = g.create();
1922: g2.setColor(Color.WHITE);
1923: g2.fillRect(x, y, getIconWidth() - 1,
1924: getIconHeight() - 1);
1925: g2.setColor(MenuEditLayer.EMPTY_ICON_COLOR);
1926: g2.drawRect(x, y, getIconWidth() - 1,
1927: getIconHeight() - 1);
1928: g2.drawRect(x + 1, y + 1, getIconWidth() - 3,
1929: getIconHeight() - 3);
1930: g2.dispose();
1931: }
1932: }
1933:
1934: public int getIconWidth() {
1935: if (wrapee != null) {
1936: return wrapee.getIconWidth();
1937: }
1938: return 16;
1939: }
1940:
1941: public int getIconHeight() {
1942: if (wrapee != null) {
1943: return wrapee.getIconHeight();
1944: }
1945: return 16;
1946: }
1947:
1948: }
1949:
1950: }
|