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-2006 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:
0042: package org.netbeans.modules.form;
0043:
0044: import java.awt.*;
0045: import java.awt.event.*;
0046: import java.util.*;
0047: import java.util.List;
0048: import java.util.prefs.PreferenceChangeEvent;
0049: import java.util.prefs.PreferenceChangeListener;
0050: import javax.swing.*;
0051: import javax.swing.border.*;
0052: import java.beans.*;
0053:
0054: import org.jdesktop.layout.Baseline;
0055: import org.jdesktop.layout.LayoutStyle;
0056:
0057: import org.netbeans.core.spi.multiview.*;
0058: import org.netbeans.modules.form.menu.MenuEditLayer;
0059: import org.netbeans.modules.form.palette.PaletteItem;
0060: import org.openide.DialogDisplayer;
0061: import org.openide.NotifyDescriptor;
0062: import org.openide.actions.FileSystemAction;
0063: import org.openide.util.actions.SystemAction;
0064: import org.openide.windows.TopComponent;
0065: import org.openide.nodes.Node;
0066: import org.openide.util.*;
0067: import org.openide.util.lookup.*;
0068: import org.openide.awt.UndoRedo;
0069: import org.openide.explorer.ExplorerUtils;
0070: import org.openide.ErrorManager;
0071: import org.openide.explorer.ExplorerManager;
0072:
0073: import org.netbeans.modules.form.assistant.*;
0074: import org.netbeans.modules.form.wizard.ConnectionWizard;
0075: import org.netbeans.modules.form.layoutsupport.LayoutSupportManager;
0076: import org.netbeans.modules.form.layoutdesign.*;
0077: import org.netbeans.modules.form.layoutdesign.LayoutConstants.PaddingType;
0078: import org.netbeans.modules.form.layoutdesign.support.SwingLayoutBuilder;
0079: import org.netbeans.modules.form.palette.PaletteUtils;
0080: import org.netbeans.modules.form.project.ClassSource;
0081: import org.netbeans.modules.form.project.ClassPathUtils;
0082: import org.openide.filesystems.FileObject;
0083:
0084: /**
0085: * This is a TopComponent subclass holding the form designer. It consist of two
0086: * layers - HandleLayer (responsible for interaction with user) and
0087: * ComponentLayer (presenting the components, not accessible to the user).
0088: *
0089: * FormDesigner
0090: * +- AssistantView
0091: * +- JScrollPane
0092: * +- JLayeredPane
0093: * +- HandleLayer
0094: * +- ComponentLayer
0095: *
0096: * @author Tran Duc Trung, Tomas Pavek, Josef Kozak
0097: */
0098:
0099: public class FormDesigner extends TopComponent implements
0100: MultiViewElement {
0101: static final String PROP_DESIGNER_SIZE = "designerSize"; // NOI18N
0102:
0103: // UI components composition
0104: private JLayeredPane layeredPane;
0105: private ComponentLayer componentLayer;
0106: private HandleLayer handleLayer;
0107: private NonVisualTray nonVisualTray;
0108: private FormToolBar formToolBar;
0109:
0110: // in-place editing
0111: private InPlaceEditLayer textEditLayer;
0112: private FormProperty editedProperty;
0113: private InPlaceEditLayer.FinishListener finnishListener;
0114:
0115: private MenuEditLayer menuEditLayer;
0116:
0117: // metadata
0118: private FormModel formModel;
0119: private FormModelListener formModelListener;
0120: private RADVisualComponent topDesignComponent;
0121:
0122: private FormEditor formEditor;
0123:
0124: // layout visualization and interaction
0125: private List<RADComponent> selectedComponents = new ArrayList<RADComponent>();
0126: private List<RADComponent> selectedLayoutComponents = new ArrayList<RADComponent>();
0127: private VisualReplicator replicator;
0128: private LayoutDesigner layoutDesigner;
0129: private List<Action> designerActions;
0130: private List<Action> resizabilityActions;
0131:
0132: private JToggleButton[] resizabilityButtons;
0133:
0134: private int designerMode;
0135: public static final int MODE_SELECT = 0;
0136: public static final int MODE_CONNECT = 1;
0137: public static final int MODE_ADD = 2;
0138:
0139: private boolean initialized = false;
0140:
0141: private RADComponent connectionSource;
0142: private RADComponent connectionTarget;
0143:
0144: MultiViewElementCallback multiViewObserver;
0145:
0146: private ExplorerManager explorerManager;
0147: private FormProxyLookup lookup;
0148:
0149: private AssistantView assistantView;
0150: private PreferenceChangeListener settingsListener;
0151:
0152: /** The icons for FormDesigner */
0153: private static String iconURL = "org/netbeans/modules/form/resources/formDesigner.gif"; // NOI18N
0154:
0155: private boolean hasPropertyChangeListener = false;
0156:
0157: // ----------
0158: // constructors and setup
0159:
0160: FormDesigner(FormEditor formEditor) {
0161: setIcon(Utilities.loadImage(iconURL));
0162: setLayout(new BorderLayout());
0163:
0164: FormLoaderSettings settings = FormLoaderSettings.getInstance();
0165: Color backgroundColor = settings
0166: .getFormDesignerBackgroundColor();
0167: Color borderColor = settings.getFormDesignerBorderColor();
0168:
0169: JPanel loadingPanel = new JPanel();
0170: loadingPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 12,
0171: 12 + (settings.getAssistantShown() ? 40 : 0)));
0172: loadingPanel.setBackground(backgroundColor);
0173: JLabel loadingLbl = new JLabel(FormUtils
0174: .getBundleString("LBL_FormLoading")); // NOI18N
0175: loadingLbl.setOpaque(true);
0176: loadingLbl.setPreferredSize(new Dimension(410, 310));
0177: loadingLbl.setHorizontalAlignment(SwingConstants.CENTER);
0178: loadingPanel.add(loadingLbl);
0179: loadingLbl.setBorder(new CompoundBorder(new LineBorder(
0180: borderColor, 5),
0181: new EmptyBorder(new Insets(6, 6, 6, 6))));
0182: add(loadingPanel, BorderLayout.CENTER);
0183:
0184: this .formEditor = formEditor;
0185:
0186: if (formEditor != null) { // Issue 67879
0187: explorerManager = new ExplorerManager();
0188:
0189: // add FormDataObject to lookup so it can be obtained from multiview TopComponent
0190: ActionMap map = ComponentInspector.getInstance()
0191: .setupActionMap(getActionMap());
0192: final FormDataObject formDataObject = formEditor
0193: .getFormDataObject();
0194: lookup = new FormProxyLookup(new Lookup[] {
0195: ExplorerUtils.createLookup(explorerManager, map),
0196: Lookups.fixed(new Object[] { formDataObject }),
0197: PaletteUtils.getPaletteLookup(formDataObject
0198: .getPrimaryFile()),
0199: formDataObject.getNodeDelegate().getLookup() });
0200: associateLookup(lookup);
0201:
0202: formToolBar = new FormToolBar(this );
0203: }
0204: }
0205:
0206: void initialize() {
0207: initialized = true;
0208: removeAll();
0209:
0210: formModel = formEditor.getFormModel();
0211:
0212: componentLayer = new ComponentLayer(formModel);
0213: handleLayer = new HandleLayer(this );
0214: nonVisualTray = FormEditor.isNonVisualTrayEnabled() ? new NonVisualTray(
0215: formModel)
0216: : null;
0217:
0218: JPanel designPanel = new JPanel(new BorderLayout());
0219: designPanel.add(componentLayer, BorderLayout.CENTER);
0220: if (nonVisualTray != null) {
0221: designPanel.add(nonVisualTray, BorderLayout.SOUTH);
0222: }
0223:
0224: layeredPane = new JLayeredPane() {
0225: // hack: before each paint make sure the dragged components have
0226: // bounds set out of visible area (as they physically stay in their
0227: // container and the layout manager may lay them back if some
0228: // validation occurs)
0229: @Override
0230: protected void paintChildren(Graphics g) {
0231: handleLayer.maskDraggingComponents();
0232: super .paintChildren(g);
0233: }
0234: };
0235: layeredPane.setLayout(new OverlayLayout(layeredPane));
0236: layeredPane.add(designPanel, new Integer(1000));
0237: layeredPane.add(handleLayer, new Integer(1001));
0238:
0239: updateAssistant();
0240: settingsListener = new PreferenceChangeListener() {
0241: public void preferenceChange(PreferenceChangeEvent evt) {
0242: if (FormLoaderSettings.PROP_ASSISTANT_SHOWN.equals(evt
0243: .getKey())) {
0244: updateAssistant();
0245: }
0246: }
0247:
0248: };
0249: FormLoaderSettings.getPreferences()
0250: .addPreferenceChangeListener(settingsListener);
0251:
0252: JScrollPane scrollPane = new JScrollPane(layeredPane);
0253: scrollPane.setBorder(null); // disable border, winsys will handle borders itself
0254: scrollPane.setViewportBorder(null); // disable also GTK L&F viewport border
0255: scrollPane.getVerticalScrollBar().setUnitIncrement(5); // Issue 50054
0256: scrollPane.getHorizontalScrollBar().setUnitIncrement(5);
0257: add(scrollPane, BorderLayout.CENTER);
0258:
0259: explorerManager.setRootContext(formEditor.getFormRootNode());
0260:
0261: if (!hasPropertyChangeListener) {
0262: addPropertyChangeListener("activatedNodes",
0263: new PropertyChangeListener() { // NOI18N
0264: public void propertyChange(
0265: PropertyChangeEvent evt) {
0266: try {
0267: Lookup[] lookups = lookup
0268: .getSubLookups();
0269: Node[] oldNodes = (Node[]) evt
0270: .getOldValue();
0271: Node[] nodes = (Node[]) evt
0272: .getNewValue();
0273: Lookup lastLookup = lookups[lookups.length - 1];
0274: Node delegate = formEditor
0275: .getFormDataObject()
0276: .getNodeDelegate();
0277: if (!(lastLookup instanceof NoNodeLookup)
0278: && (oldNodes.length >= 1)
0279: && (!oldNodes[0]
0280: .equals(delegate))) {
0281: switchLookup();
0282: } else if ((lastLookup instanceof NoNodeLookup)
0283: && (nodes.length == 0)) {
0284: switchLookup();
0285: }
0286: List<Node> list = new ArrayList<Node>(
0287: nodes.length);
0288: for (int i = 0; i < nodes.length; i++) {
0289: if ((nodes[i] != null)
0290: && (nodes[i] != delegate)) {
0291: list.add(nodes[i]);
0292: }
0293: }
0294: explorerManager
0295: .setSelectedNodes(list
0296: .toArray(new Node[list
0297: .size()]));
0298: } catch (PropertyVetoException ex) {
0299: ex.printStackTrace();
0300: }
0301: }
0302: });
0303: hasPropertyChangeListener = true;
0304: }
0305:
0306: if (formModelListener == null)
0307: formModelListener = new FormListener();
0308: formModel.addFormModelListener(formModelListener);
0309:
0310: replicator = new VisualReplicator(true, FormUtils
0311: .getViewConverters(), FormEditor
0312: .getBindingSupport(formModel));
0313:
0314: resetTopDesignComponent(false);
0315: handleLayer.setViewOnly(formModel.isReadOnly());
0316:
0317: // Beans without layout model doesn't require layout designer
0318: if (formModel.getLayoutModel() != null) {
0319: layoutDesigner = new LayoutDesigner(formModel
0320: .getLayoutModel(), new LayoutMapper());
0321: }
0322:
0323: updateWholeDesigner();
0324:
0325: // not very nice hack - it's better FormEditorSupport has its
0326: // listener registered after FormDesigner
0327: formEditor.reinstallListener();
0328:
0329: if (formEditor.getFormDesigner() == null) {
0330: // 70940: Make sure some form designer is registered
0331: formEditor.setFormDesigner(this );
0332: }
0333:
0334: //force the menu edit layer to be created
0335: getMenuEditLayer();
0336:
0337: // vlv: print
0338: designPanel.putClientProperty(java.awt.print.Printable.class,
0339: ""); // NOI18N
0340: }
0341:
0342: void reset(FormEditor formEditor) {
0343: if (initialized) {
0344: clearSelection();
0345: }
0346: initialized = false;
0347:
0348: removeAll();
0349:
0350: componentLayer = null;
0351: handleLayer = null;
0352: nonVisualTray = null;
0353: layeredPane = null;
0354: if (textEditLayer != null) {
0355: if (textEditLayer.isVisible()) {
0356: textEditLayer.finishEditing(false);
0357: }
0358: textEditLayer.removeFinishListener(getFinnishListener());
0359: textEditLayer = null;
0360: }
0361:
0362: if (menuEditLayer != null) {
0363: menuEditLayer = null;
0364: }
0365:
0366: if (formModel != null) {
0367: if (formModelListener != null) {
0368: formModel.removeFormModelListener(formModelListener);
0369: }
0370: if (settingsListener != null) {
0371: FormLoaderSettings.getPreferences()
0372: .removePreferenceChangeListener(
0373: settingsListener);
0374: }
0375: topDesignComponent = null;
0376: formModel = null;
0377: }
0378:
0379: replicator = null;
0380: layoutDesigner = null;
0381:
0382: connectionSource = null;
0383: connectionTarget = null;
0384: this .formEditor = formEditor;
0385: }
0386:
0387: private void switchLookup() {
0388: Lookup[] lookups = lookup.getSubLookups();
0389: Lookup nodeLookup = formEditor.getFormDataObject()
0390: .getNodeDelegate().getLookup();
0391: int index = lookups.length - 1;
0392: if (lookups[index] instanceof NoNodeLookup) {
0393: lookups[index] = nodeLookup;
0394: } else {
0395: // should not affect selected nodes, but should provide cookies etc.
0396: lookups[index] = new NoNodeLookup(nodeLookup);
0397: }
0398: lookup.setSubLookups(lookups);
0399: }
0400:
0401: private void updateAssistant() {
0402: if (FormLoaderSettings.getInstance().getAssistantShown()) {
0403: AssistantModel assistant = FormEditor
0404: .getAssistantModel(formModel);
0405: assistantView = new AssistantView(assistant);
0406: assistant.setContext("select"); // NOI18N
0407: add(assistantView, BorderLayout.NORTH);
0408: } else {
0409: if (assistantView != null) {
0410: remove(assistantView);
0411: assistantView = null;
0412: }
0413: }
0414: revalidate();
0415: }
0416:
0417: // ------
0418: // important getters
0419:
0420: public FormModel getFormModel() {
0421: return formModel;
0422: }
0423:
0424: public HandleLayer getHandleLayer() {
0425: return handleLayer;
0426: }
0427:
0428: ComponentLayer getComponentLayer() {
0429: return componentLayer;
0430: }
0431:
0432: NonVisualTray getNonVisualTray() {
0433: return nonVisualTray;
0434: }
0435:
0436: FormToolBar getFormToolBar() {
0437: return formToolBar;
0438: }
0439:
0440: public LayoutDesigner getLayoutDesigner() {
0441: return layoutDesigner;
0442: }
0443:
0444: public FormEditor getFormEditor() {
0445: return formEditor;
0446: }
0447:
0448: @Override
0449: public javax.swing.Action[] getActions() {
0450: Action[] actions = super .getActions();
0451: SystemAction fsAction = SystemAction
0452: .get(FileSystemAction.class);
0453: if (!Arrays.asList(actions).contains(fsAction)) {
0454: Action[] newActions = new Action[actions.length + 1];
0455: System.arraycopy(actions, 0, newActions, 0, actions.length);
0456: newActions[actions.length] = fsAction;
0457: actions = newActions;
0458: }
0459: return actions;
0460: }
0461:
0462: // ------------
0463: // designer content
0464:
0465: public Object getComponent(RADComponent metacomp) {
0466: return replicator.getClonedComponent(metacomp.getId());
0467: }
0468:
0469: public Object getComponent(String componentId) {
0470: return replicator.getClonedComponent(componentId);
0471: }
0472:
0473: public RADComponent getMetaComponent(Object comp) {
0474: String id = replicator.getClonedComponentId(comp);
0475: return id != null ? formModel.getMetaComponent(id) : null;
0476: }
0477:
0478: // public RADComponent getMetaComponent(String componentId) {
0479: // return formModel.getMetaComponent(componentId);
0480: // }
0481:
0482: public RADVisualComponent getTopDesignComponent() {
0483: return topDesignComponent;
0484: }
0485:
0486: boolean isTopRADComponent() {
0487: RADComponent topMetaComp = formModel.getTopRADComponent();
0488: return topMetaComp != null && topMetaComp == topDesignComponent;
0489: }
0490:
0491: public void setTopDesignComponent(RADVisualComponent component,
0492: boolean update) {
0493:
0494: highlightTopDesignComponentName(false);
0495: // TODO need to remove bindings of the current cloned view (or clone bound components as well)
0496: topDesignComponent = component;
0497: highlightTopDesignComponentName(!isTopRADComponent());
0498:
0499: FormDataObject formDO = formEditor.getFormDataObject();
0500: if (formDO != null) {
0501: formDO.getFormEditorSupport().updateMVTCDisplayName();
0502: }
0503: if (update) {
0504: setSelectedComponent(topDesignComponent);
0505: updateWholeDesigner();
0506: }
0507: }
0508:
0509: private void highlightTopDesignComponentName(boolean bl) {
0510: if (topDesignComponent != null) {
0511: RADComponentNode node = topDesignComponent
0512: .getNodeReference();
0513: if (node != null) {
0514: node.highlightDisplayName(bl);
0515: }
0516: }
0517: }
0518:
0519: public void resetTopDesignComponent(boolean update) {
0520: RADComponent top = formModel.getTopRADComponent();
0521: setTopDesignComponent(
0522: top instanceof RADVisualComponent ? (RADVisualComponent) top
0523: : null, update);
0524: }
0525:
0526: /** Tests whether top designed container is some parent of given component
0527: * (whether the component is in the tree under top designed container).
0528: *
0529: * @param metacomp component.
0530: * @return <code>true</code> if the component is in designer,
0531: * returns <code>false</code> otherwise.
0532: */
0533: public boolean isInDesigner(RADVisualComponent metacomp) {
0534: Object comp = replicator.getClonedComponent(metacomp);
0535: return comp instanceof Component ? componentLayer
0536: .isAncestorOf((Component) comp) : false;
0537: }
0538:
0539: void updateWholeDesigner() {
0540: if (formModelListener != null)
0541: formModelListener.formChanged(null);
0542: }
0543:
0544: private void updateComponentLayer(final boolean fireChange) {
0545: if (formModel == null) { // the form can be closed just after opened, before this gets called (#70439)
0546: return;
0547: }
0548: if (getLayoutDesigner() == null) {
0549: return;
0550: }
0551:
0552: // Ensure that the components are laid out
0553: componentLayer.revalidate(); // Add componentLayer among components to validate
0554: RepaintManager.currentManager(componentLayer)
0555: .validateInvalidComponents();
0556:
0557: LayoutModel layoutModel = formModel.getLayoutModel();
0558: if (getLayoutDesigner().updateCurrentState() && fireChange) {
0559: formModel.fireFormChanged(true); // hack: to regenerate code once again
0560: }
0561:
0562: layoutModel.endUndoableEdit();
0563: updateResizabilityActions();
0564: componentLayer.repaint();
0565: }
0566:
0567: // updates layout of a container in designer to match current model - used
0568: // by HandleLayer when canceling component dragging
0569: void updateContainerLayout(RADVisualContainer metacont) {
0570: replicator.updateContainerLayout(metacont);
0571: componentLayer.revalidate();
0572: componentLayer.repaint();
0573: }
0574:
0575: public static Container createFormView(final RADComponent metacomp,
0576: final FormLAF.PreviewInfo previewInfo) throws Exception {
0577: Container result = null;
0578: FormModel formModel = metacomp.getFormModel();
0579: FileObject formFile = FormEditor.getFormDataObject(formModel)
0580: .getFormFile();
0581: final ClassLoader classLoader = ClassPathUtils
0582: .getProjectClassLoader(formFile);
0583: Locale defaultLocale = switchToDesignLocale(formModel);
0584: try {
0585: FormLAF.setUsePreviewDefaults(classLoader, previewInfo);
0586: result = (Container) FormLAF.executeWithLookAndFeel(
0587: formModel, new Mutex.ExceptionAction() {
0588: public Object run() throws Exception {
0589: VisualReplicator r = new VisualReplicator(
0590: false, FormUtils
0591: .getViewConverters(), null);
0592: r.setTopMetaComponent(metacomp);
0593: Object container = r.createClone();
0594: if (container instanceof RootPaneContainer) {
0595: JRootPane rootPane = ((RootPaneContainer) container)
0596: .getRootPane();
0597: JLayeredPane newPane = new JLayeredPane() {
0598: @Override
0599: public void paint(Graphics g) {
0600: try {
0601: FormLAF
0602: .setUsePreviewDefaults(
0603: classLoader,
0604: previewInfo);
0605: super .paint(g);
0606: } finally {
0607: FormLAF
0608: .setUsePreviewDefaults(
0609: null, null);
0610: }
0611: }
0612: };
0613: // Copy components from the original layered pane into our one
0614: JLayeredPane oldPane = rootPane
0615: .getLayeredPane();
0616: Component[] comps = oldPane
0617: .getComponents();
0618: for (int i = 0; i < comps.length; i++) {
0619: newPane
0620: .add(
0621: comps[i],
0622: Integer
0623: .valueOf(oldPane
0624: .getLayer(comps[i])));
0625: }
0626: // Use our layered pane that knows about LAF switching
0627: rootPane.setLayeredPane(newPane);
0628: // Make the glass pane visible to force repaint of the whole layered pane
0629: rootPane.getGlassPane()
0630: .setVisible(true);
0631: // Mark it as design preview
0632: rootPane.putClientProperty(
0633: "designPreview", Boolean.TRUE); // NOI18N
0634: } // else AWT Frame - we don't care that the L&F of the Swing
0635: // components may not look good - it is a strange use case
0636: return container;
0637: }
0638: }
0639:
0640: );
0641: } finally {
0642: FormLAF.setUsePreviewDefaults(null, null);
0643: if (defaultLocale != null)
0644: Locale.setDefault(defaultLocale);
0645: }
0646: return result;
0647: }
0648:
0649: private static Locale switchToDesignLocale(FormModel formModel) {
0650: Locale defaultLocale = null;
0651: String locale = FormEditor.getResourceSupport(formModel)
0652: .getDesignLocale();
0653: if (locale != null && !locale.equals("")) { // NOI18N
0654: defaultLocale = Locale.getDefault();
0655:
0656: String[] parts = locale.split("_"); // NOI18N
0657: int i = 0;
0658: if ("".equals(parts[i])) // NOI18N
0659: i++;
0660: String language = i < parts.length ? parts[i++] : null;
0661: String country = i < parts.length ? parts[i++] : ""; // NOI18N
0662: String variant = i < parts.length ? parts[i] : ""; // NOI18N
0663: if (language != null)
0664: Locale
0665: .setDefault(new Locale(language, country,
0666: variant));
0667: }
0668: return defaultLocale;
0669: }
0670:
0671: Component getTopDesignComponentView() {
0672: return topDesignComponent != null ? (Component) replicator
0673: .getClonedComponent(topDesignComponent) : null;
0674: }
0675:
0676: // NOTE: does not create a new Point instance
0677: Point pointFromComponentToHandleLayer(Point p, Component sourceComp) {
0678: Component commonParent = layeredPane;
0679: Component comp = sourceComp;
0680: while (comp != commonParent) {
0681: p.x += comp.getX();
0682: p.y += comp.getY();
0683: comp = comp.getParent();
0684: }
0685: comp = handleLayer;
0686: while (comp != commonParent) {
0687: p.x -= comp.getX();
0688: p.y -= comp.getY();
0689: comp = comp.getParent();
0690: }
0691: return p;
0692: }
0693:
0694: // NOTE: does not create a new Point instance
0695: Point pointFromHandleToComponentLayer(Point p, Component targetComp) {
0696: Component commonParent = layeredPane;
0697: Component comp = handleLayer;
0698: while (comp != commonParent) {
0699: p.x += comp.getX();
0700: p.y += comp.getY();
0701: comp = comp.getParent();
0702: }
0703: comp = targetComp;
0704: while (comp != commonParent) {
0705: p.x -= comp.getX();
0706: p.y -= comp.getY();
0707: comp = comp.getParent();
0708: }
0709: return p;
0710: }
0711:
0712: boolean isCoordinatesRoot(Component comp) {
0713: return (layeredPane == comp);
0714: }
0715:
0716: private Rectangle componentBoundsToTop(Component component) {
0717: if (component == null)
0718: return null;
0719:
0720: Component top = getTopDesignComponentView();
0721:
0722: int dx = 0;
0723: int dy = 0;
0724:
0725: if (component != top) {
0726: Component comp = component.getParent();
0727: while (comp != top) {
0728: if (comp == null) {
0729: break;//return null;
0730: }
0731: dx += comp.getX();
0732: dy += comp.getY();
0733: comp = comp.getParent();
0734: }
0735: } else {
0736: dx = -top.getX();
0737: dy = -top.getY();
0738: }
0739:
0740: Rectangle bounds = component.getBounds();
0741: bounds.x += dx;
0742: bounds.y += dy;
0743:
0744: return bounds;
0745: }
0746:
0747: // -------
0748: // designer mode
0749:
0750: void setDesignerMode(int mode) {
0751: formToolBar.updateDesignerMode(mode);
0752:
0753: if (mode == designerMode || !initialized) {
0754: return;
0755: }
0756:
0757: if (mode == MODE_ADD) {
0758: PaletteItem pitem = PaletteUtils.getSelectedItem();
0759: if ((pitem != null)
0760: && PaletteItem.TYPE_CHOOSE_BEAN.equals(pitem
0761: .getExplicitComponentType())
0762: && ComponentInspector.getInstance()
0763: .getFocusedForm() == formEditor) {
0764: NotifyDescriptor.InputLine desc = new NotifyDescriptor.InputLine(
0765: FormUtils.getBundleString("MSG_Choose_Bean"), // NOI18N
0766: FormUtils.getBundleString("TITLE_Choose_Bean")); // NOI18N
0767: DialogDisplayer.getDefault().notify(desc);
0768: if (NotifyDescriptor.OK_OPTION.equals(desc.getValue())) {
0769: pitem.setClassFromCurrentProject(desc
0770: .getInputText(), formEditor
0771: .getFormDataObject().getPrimaryFile());
0772: } else {
0773: toggleSelectionMode();
0774: return;
0775: }
0776: }
0777: }
0778:
0779: designerMode = mode;
0780:
0781: resetConnection();
0782: if (mode == MODE_CONNECT)
0783: clearSelection();
0784:
0785: handleLayer.endDragging(null);
0786: AssistantModel aModel = FormEditor.getAssistantModel(formModel);
0787: switch (mode) {
0788: case MODE_CONNECT:
0789: aModel.setContext("connectSource");
0790: break; // NOI18N
0791: case MODE_SELECT:
0792: aModel.setContext("select");
0793: break; // NOI18N
0794: }
0795: }
0796:
0797: public int getDesignerMode() {
0798: return designerMode;
0799: }
0800:
0801: public void toggleSelectionMode() {
0802: setDesignerMode(MODE_SELECT);
0803: PaletteUtils.clearPaletteSelection();
0804: }
0805:
0806: void toggleConnectionMode() {
0807: setDesignerMode(MODE_CONNECT);
0808: PaletteUtils.clearPaletteSelection();
0809: }
0810:
0811: void toggleAddMode() {
0812: setDesignerMode(MODE_ADD);
0813: PaletteUtils.clearPaletteSelection();
0814: }
0815:
0816: // -------
0817: // designer size
0818:
0819: Dimension getDesignerSize() {
0820: return componentLayer.getDesignerSize();
0821: }
0822:
0823: void setDesignerSize(Dimension size, Dimension oldSize) {
0824: if (topDesignComponent instanceof RADVisualFormContainer) {
0825: ((RADVisualFormContainer) topDesignComponent)
0826: .setDesignerSize(size);
0827: } else if (topDesignComponent != null) {
0828: if (topDesignComponent == formModel.getTopRADComponent()) {
0829: oldSize = (Dimension) topDesignComponent
0830: .getAuxValue(PROP_DESIGNER_SIZE);
0831: topDesignComponent
0832: .setAuxValue(PROP_DESIGNER_SIZE, size);
0833: }
0834: if (oldSize == null)
0835: oldSize = getDesignerSize();
0836:
0837: getFormModel().fireSyntheticPropertyChanged(
0838: topDesignComponent,
0839: FormDesigner.PROP_DESIGNER_SIZE, oldSize, size);
0840: }
0841: }
0842:
0843: public void resetDesignerSize() {
0844: setDesignerSize(null, null);
0845: }
0846:
0847: void storeDesignerSize(Dimension size) { // without firing model change
0848: if (topDesignComponent instanceof RADVisualFormContainer)
0849: ((RADVisualFormContainer) topDesignComponent)
0850: .setDesignerSizeImpl(size);
0851: else if (topDesignComponent == formModel.getTopRADComponent()) // root not a visual container
0852: topDesignComponent.setAuxValue(PROP_DESIGNER_SIZE, size);
0853: }
0854:
0855: private void setupDesignerSize() {
0856: Dimension size = null;
0857: RADVisualFormContainer formCont = topDesignComponent instanceof RADVisualFormContainer ? (RADVisualFormContainer) topDesignComponent
0858: : null;
0859: if (formCont == null
0860: || formCont.hasExplicitSize()
0861: || !RADVisualContainer
0862: .isFreeDesignContainer(topDesignComponent)) { // try to obtain stored designer size
0863: if (formCont != null)
0864: size = formCont.getDesignerSize();
0865: if (size == null)
0866: size = (Dimension) topDesignComponent
0867: .getAuxValue(PROP_DESIGNER_SIZE);
0868: if (size == null
0869: && (!formModel.isFreeDesignDefaultLayout() || topDesignComponent == formModel
0870: .getTopRADComponent())) { // use default size if no stored size is available and
0871: // old layout form or top design comp is root in the form (but not a container)
0872: size = new Dimension(400, 300);
0873: }
0874: }
0875:
0876: Dimension setSize = componentLayer.setDesignerSize(size); // null computes preferred size
0877: storeDesignerSize(setSize);
0878: }
0879:
0880: private void checkDesignerSize() {
0881: if ((formModel.isFreeDesignDefaultLayout() || RADVisualContainer
0882: .isFreeDesignContainer(topDesignComponent))
0883: && topDesignComponent instanceof RADVisualComponent
0884: && (!(topDesignComponent instanceof RADVisualFormContainer) || !((RADVisualFormContainer) topDesignComponent)
0885: .hasExplicitSize())) { // new layout container defining designer size
0886: // designer size not defined explicitly - check minimum size
0887: Component topComp = getTopDesignComponentView();
0888: Component topCont = null;
0889: if (topDesignComponent instanceof RADVisualContainer) {
0890: topCont = ((RADVisualContainer) topDesignComponent)
0891: .getContainerDelegate(topComp);
0892: }
0893: if (topCont == null) {
0894: topCont = topComp;
0895: }
0896: // can't rely on minimum size of the container wrap - e.g. menu bar
0897: // returns wrong min height
0898: int wDiff = topComp.getWidth() - topCont.getWidth();
0899: int hDiff = topComp.getHeight() - topCont.getHeight();
0900:
0901: Dimension designerSize = new Dimension(getDesignerSize());
0902: designerSize.width -= wDiff;
0903: designerSize.height -= hDiff;
0904: Dimension minSize = topCont.getMinimumSize();
0905: boolean corrected = false;
0906: if (designerSize.width < minSize.width) {
0907: designerSize.width = minSize.width;
0908: corrected = true;
0909: }
0910: if (designerSize.height < minSize.height) {
0911: designerSize.height = minSize.height;
0912: corrected = true;
0913: }
0914:
0915: if (corrected) {
0916: designerSize.width += wDiff;
0917: designerSize.height += hDiff;
0918:
0919: // hack: we need the size correction in the undo/redo
0920: if (formModel.isCompoundEditInProgress()) {
0921: FormModelEvent ev = new FormModelEvent(formModel,
0922: FormModelEvent.SYNTHETIC_PROPERTY_CHANGED);
0923: ev.setComponentAndContainer(topDesignComponent,
0924: null);
0925: ev.setProperty(PROP_DESIGNER_SIZE,
0926: getDesignerSize(), designerSize);
0927: formModel.addUndoableEdit(ev.getUndoableEdit());
0928: }
0929:
0930: componentLayer.setDesignerSize(designerSize);
0931: storeDesignerSize(designerSize);
0932: }
0933: }
0934: }
0935:
0936: // ---------
0937: // components selection
0938:
0939: public java.util.List<RADComponent> getSelectedComponents() {
0940: return selectedComponents;
0941: }
0942:
0943: Node[] getSelectedComponentNodes() {
0944: List<Node> selectedNodes = new ArrayList<Node>(
0945: selectedComponents.size());
0946: for (RADComponent c : selectedComponents) {
0947: if (c.getNodeReference() != null) { // issue 126192 workaround
0948: selectedNodes.add(c.getNodeReference());
0949: }
0950: }
0951: return selectedNodes.toArray(new Node[selectedNodes.size()]);
0952: }
0953:
0954: java.util.List<RADComponent> getSelectedLayoutComponents() {
0955: return selectedLayoutComponents;
0956: }
0957:
0958: boolean isComponentSelected(RADComponent metacomp) {
0959: return selectedComponents.contains(metacomp);
0960: }
0961:
0962: public void setSelectedComponent(RADComponent metacomp) {
0963: clearSelectionImpl();
0964: addComponentToSelectionImpl(metacomp);
0965: repaintSelection();
0966: updateComponentInspector();
0967: }
0968:
0969: public void setSelectedComponents(RADComponent[] metacomps) {
0970: clearSelectionImpl();
0971:
0972: for (int i = 0; i < metacomps.length; i++)
0973: addComponentToSelectionImpl(metacomps[i]);
0974:
0975: repaintSelection();
0976: updateComponentInspector();
0977: }
0978:
0979: void setSelectedNode(FormNode node) {
0980: if (node instanceof RADComponentNode)
0981: setSelectedComponent(((RADComponentNode) node)
0982: .getRADComponent());
0983: else {
0984: clearSelectionImpl();
0985: repaintSelection();
0986:
0987: ComponentInspector ci = ComponentInspector.getInstance();
0988: if (ci.getFocusedForm() != formEditor)
0989: return;
0990:
0991: Node[] selectedNodes = new Node[] { node };
0992: try {
0993: ci.setSelectedNodes(selectedNodes, formEditor);
0994: // sets also the activated nodes (both for ComponentInspector
0995: // and FormDesigner)
0996: } catch (java.beans.PropertyVetoException ex) {
0997: ex.printStackTrace();
0998: }
0999: }
1000: }
1001:
1002: public void addComponentToSelection(RADComponent metacomp) {
1003: addComponentToSelectionImpl(metacomp);
1004: repaintSelection();
1005: updateComponentInspector();
1006: }
1007:
1008: void addComponentsToSelection(RADComponent[] metacomps) {
1009: for (int i = 0; i < metacomps.length; i++)
1010: addComponentToSelectionImpl(metacomps[i]);
1011:
1012: repaintSelection();
1013: updateComponentInspector();
1014: }
1015:
1016: void removeComponentFromSelection(RADComponent metacomp) {
1017: removeComponentFromSelectionImpl(metacomp);
1018: repaintSelection();
1019: updateComponentInspector();
1020: }
1021:
1022: public void clearSelection() {
1023: clearSelectionImpl();
1024: repaintSelection();
1025: updateComponentInspector();
1026: }
1027:
1028: void addComponentToSelectionImpl(RADComponent metacomp) {
1029: if (metacomp != null) {
1030: selectedComponents.add(metacomp);
1031: RADVisualComponent layoutComponent = componentToLayoutComponent(metacomp);
1032: if (layoutComponent != null) {
1033: selectedLayoutComponents.add(layoutComponent);
1034: ensureComponentIsShown((RADVisualComponent) metacomp);
1035: selectionChanged();
1036: }
1037: }
1038: }
1039:
1040: RADVisualComponent componentToLayoutComponent(RADComponent metacomp) {
1041: if (metacomp instanceof RADVisualComponent) {
1042: RADVisualComponent visualComp = (RADVisualComponent) metacomp;
1043: if (!visualComp.isMenuComponent()) {
1044: RADVisualContainer metacont = visualComp
1045: .getParentContainer();
1046: if ((metacont != null)
1047: && JScrollPane.class.isAssignableFrom(metacont
1048: .getBeanInstance().getClass())
1049: && isInDesigner(metacont)) { // substitute with scroll pane...
1050: return metacont;
1051: }
1052: // otherwise just check if it is visible in the designer
1053: return isInDesigner(visualComp) ? visualComp : null;
1054: }
1055: }
1056: return null;
1057: }
1058:
1059: void removeComponentFromSelectionImpl(RADComponent metacomp) {
1060: selectedComponents.remove(metacomp);
1061: selectedLayoutComponents.remove(metacomp);
1062: selectionChanged();
1063: }
1064:
1065: void clearSelectionImpl() {
1066: selectedComponents.clear();
1067: selectedLayoutComponents.clear();
1068: selectionChanged();
1069: }
1070:
1071: void selectionChanged() {
1072: updateDesignerActions();
1073: updateResizabilityActions();
1074: updateAssistantContext();
1075: }
1076:
1077: void repaintSelection() {
1078: handleLayer.repaint();
1079: }
1080:
1081: private void updateDesignerActions() {
1082: Collection selectedIds = selectedLayoutComponentIds();
1083: boolean enabled = false;
1084: if (selectedIds.size() >= 2) {
1085: RADComponent parent = commonParent(selectedIds);
1086: if (parent != null) {
1087: LayoutModel layoutModel = formModel.getLayoutModel();
1088: LayoutComponent parentLC = layoutModel
1089: .getLayoutComponent(parent.getId());
1090: if ((parentLC != null)
1091: && (parentLC.isLayoutContainer())) {
1092: enabled = true;
1093: }
1094: }
1095: }
1096: Iterator iter = getDesignerActions(true).iterator();
1097: while (iter.hasNext()) {
1098: Action action = (Action) iter.next();
1099: action.setEnabled(enabled);
1100: }
1101: }
1102:
1103: void setResizabilityButtons(JToggleButton[] buttons) {
1104: this .resizabilityButtons = buttons;
1105: }
1106:
1107: public JToggleButton[] getResizabilityButtons() {
1108: return resizabilityButtons;
1109: }
1110:
1111: public void updateResizabilityActions() {
1112: Collection componentIds = componentIds();
1113: LayoutModel layoutModel = getFormModel().getLayoutModel();
1114: LayoutDesigner layoutDesigner = getLayoutDesigner();
1115: Iterator iter = componentIds.iterator();
1116: boolean resizable[] = new boolean[2];
1117: boolean nonResizable[] = new boolean[2];
1118: while (iter.hasNext()) {
1119: String id = (String) iter.next();
1120: LayoutComponent comp = layoutModel.getLayoutComponent(id);
1121: for (int i = 0; i < 2; i++) {
1122: if (layoutDesigner.isComponentResizing(comp,
1123: (i == 0) ? LayoutConstants.HORIZONTAL
1124: : LayoutConstants.VERTICAL)) {
1125: resizable[i] = true;
1126: } else {
1127: nonResizable[i] = true;
1128: }
1129: }
1130: }
1131: for (int i = 0; i < 2; i++) {
1132: boolean match;
1133: boolean miss;
1134: match = resizable[i];
1135: miss = nonResizable[i];
1136: getResizabilityButtons()[i].setSelected(!miss && match);
1137: ((ResizabilityAction) getResizabilityActions().toArray()[i])
1138: .setEnabled(match || miss);
1139: // getResizabilityButtons()[i].setPaintDisabledIcon(match && miss);
1140: }
1141: }
1142:
1143: private void updateAssistantContext() {
1144: String context = null;
1145: String additionalCtx = null;
1146: List<RADComponent> selComps = getSelectedComponents();
1147: int selCount = selComps.size();
1148: if (selCount > 0) {
1149: RADComponent metacomp = selComps.get(0);
1150: if (layoutDesigner != null
1151: && layoutDesigner.isUnplacedComponent(metacomp
1152: .getId())) {
1153: if (selCount > 1) {
1154: List<String> ids = new ArrayList<String>(selCount);
1155: for (RADComponent c : selComps) {
1156: ids.add(c.getId());
1157: }
1158: if (layoutDesigner.getDraggableComponents(ids)
1159: .size() == selCount) {
1160: // all selected components are "unplaced" in the same container
1161: context = "unplacedComponents1"; // NOI18N
1162: additionalCtx = "unplacedComponents2"; // NOI18N
1163: }
1164: } else {
1165: context = "unplacedComponent1"; // NOI18N
1166: additionalCtx = "unplacedComponent2"; // NOI18N
1167: }
1168: }
1169: if (selCount == 1 && context == null) {
1170: Object bean = metacomp.getBeanInstance();
1171: if (bean instanceof JTabbedPane) {
1172: JTabbedPane pane = (JTabbedPane) bean;
1173: int count = pane.getTabCount();
1174: switch (count) {
1175: case 0:
1176: context = "tabbedPaneEmpty";
1177: break; // NOI18N
1178: case 1:
1179: context = "tabbedPaneOne";
1180: break; // NOI18N
1181: default:
1182: context = "tabbedPane";
1183: break; // NOI18N
1184: }
1185: } else if (bean instanceof JRadioButton) {
1186: Node.Property property = metacomp
1187: .getPropertyByName("buttonGroup"); // NOI18N
1188: try {
1189: if ((property != null)
1190: && (property.getValue() == null)) {
1191: context = "buttonGroup"; // NOI18N
1192: }
1193: } catch (Exception ex) {
1194: ex.printStackTrace();
1195: }
1196: } else if ((bean instanceof JPanel)
1197: && (getTopDesignComponent() != metacomp)
1198: && (Math.random() < 0.2)) {
1199: context = "designThisContainer"; // NOI18N
1200: } else if ((bean instanceof JComboBox)
1201: && (Math.random() < 0.4)) {
1202: context = "comboBoxModel"; // NOI18N
1203: } else if ((bean instanceof JList)
1204: && (Math.random() < 0.4)) {
1205: context = "listModel"; // NOI18N
1206: } else if ((bean instanceof JTable)
1207: && (Math.random() < 0.4)) {
1208: context = "tableModel"; // NOI18N
1209: } else if (bean instanceof JScrollPane) {
1210: JScrollPane scrollPane = (JScrollPane) bean;
1211: if ((scrollPane.getViewport() != null)
1212: && (scrollPane.getViewport().getView() == null)) {
1213: context = "scrollPaneEmpty"; // NOI18N
1214: } else if (Math.random() < 0.5) {
1215: context = "scrollPane"; // NOI18N
1216: }
1217: }
1218: }
1219: }
1220: if (context == null) {
1221: context = "select"; // NOI18N
1222: }
1223: FormEditor.getAssistantModel(formModel).setContext(context,
1224: additionalCtx);
1225: }
1226:
1227: /** Finds out what component follows after currently selected component
1228: * when TAB (forward true) or Shift+TAB (forward false) is pressed.
1229: * @return the next or previous component for selection
1230: */
1231: RADComponent getNextVisualComponent(boolean forward) {
1232: RADComponent currentComp = null;
1233: int n = selectedComponents.size();
1234: if (n > 0) {
1235: if (n > 1)
1236: return null;
1237: RADComponent sel = selectedComponents.get(0);
1238: if (sel instanceof RADVisualComponent) {
1239: currentComp = sel;
1240: } else {
1241: return null;
1242: }
1243: }
1244:
1245: return getNextVisualComponent(currentComp, forward);
1246: }
1247:
1248: /** @return the next or prevoius component to component comp
1249: */
1250: RADComponent getNextVisualComponent(RADComponent comp,
1251: boolean forward) {
1252: if (comp == null)
1253: return topDesignComponent;
1254: if (getComponent(comp) == null)
1255: return null;
1256:
1257: RADVisualContainer cont;
1258: RADComponent[] subComps;
1259:
1260: if (forward) {
1261: // try the first sub-component
1262: subComps = getVisualSubComponents(comp);
1263: if (subComps.length > 0) {
1264: return subComps[0];
1265: }
1266:
1267: // try the next component (or the next of the parent then)
1268: if (comp == topDesignComponent)
1269: return topDesignComponent;
1270: cont = (RADVisualContainer) comp.getParentComponent();
1271: if (cont == null) {
1272: return null;
1273: }
1274: int i = cont.getIndexOf(comp);
1275: while (i >= 0) {
1276: subComps = cont.getSubComponents();
1277: if (i + 1 < subComps.length)
1278: return subComps[i + 1];
1279:
1280: if (cont == topDesignComponent)
1281: break;
1282: comp = cont; // one level up
1283: cont = (RADVisualContainer) comp.getParentComponent();
1284: if (cont == null)
1285: return null; // should not happen
1286: i = cont.getIndexOf(comp);
1287: }
1288:
1289: return topDesignComponent;
1290: } else { // backward
1291: // take the previuos component
1292: if (comp != topDesignComponent) {
1293: cont = (RADVisualContainer) comp.getParentComponent();
1294: if (cont == null) {
1295: return null;
1296: }
1297: int i = cont.getIndexOf(comp);
1298: if (i >= 0) { // should be always true
1299: if (i == 0)
1300: return cont; // the opposite to the 1st forward step
1301:
1302: subComps = cont.getSubComponents();
1303: comp = subComps[i - 1];
1304: } else
1305: comp = topDesignComponent;
1306: }
1307:
1308: // find the last subcomponent of it
1309: do {
1310: subComps = getVisualSubComponents(comp);
1311: if (subComps.length > 0) {
1312: comp = subComps[subComps.length - 1];
1313: continue;
1314: } else {
1315: break;
1316: }
1317: } while (true);
1318: return comp;
1319: }
1320: }
1321:
1322: private RADComponent[] getVisualSubComponents(RADComponent metacomp) {
1323: return metacomp instanceof RADVisualContainer ? ((RADVisualContainer) metacomp)
1324: .getSubComponents()
1325: : new RADComponent[0];
1326: // TBD components set as properties
1327: }
1328:
1329: /**
1330: * Aligns selected components in the specified direction.
1331: *
1332: * @param closed determines if closed group should be created.
1333: * @param dimension dimension to align in.
1334: * @param alignment requested alignment.
1335: */
1336: void align(boolean closed, int dimension, int alignment) {
1337: // Check that the action is enabled
1338: Action action = null;
1339: Iterator iter = getDesignerActions(true).iterator();
1340: while (iter.hasNext()) {
1341: Action candidate = (Action) iter.next();
1342: if (candidate instanceof AlignAction) {
1343: AlignAction alignCandidate = (AlignAction) candidate;
1344: if ((alignCandidate.getAlignment() == alignment)
1345: && (alignCandidate.getDimension() == dimension)) {
1346: action = alignCandidate;
1347: break;
1348: }
1349: }
1350: }
1351: if ((action == null) || (!action.isEnabled())) {
1352: return;
1353: }
1354: Collection selectedIds = selectedLayoutComponentIds();
1355: RADComponent parent = commonParent(selectedIds);
1356: LayoutModel layoutModel = formModel.getLayoutModel();
1357: Object layoutUndoMark = layoutModel.getChangeMark();
1358: javax.swing.undo.UndoableEdit ue = layoutModel
1359: .getUndoableEdit();
1360: boolean autoUndo = true;
1361: try {
1362: getLayoutDesigner().align(selectedIds, closed, dimension,
1363: alignment);
1364: autoUndo = false;
1365: } finally {
1366: formModel.fireContainerLayoutChanged(
1367: (RADVisualContainer) parent, null, null, null);
1368: if (!layoutUndoMark.equals(layoutModel.getChangeMark())) {
1369: formModel.addUndoableEdit(ue);
1370: }
1371: if (autoUndo) {
1372: formModel.forceUndoOfCompoundEdit();
1373: }
1374: }
1375: }
1376:
1377: /**
1378: * Returns designer actions (they will be displayed in toolbar).
1379: *
1380: * @param forToolbar determines whether the method should return
1381: * all designer actions or just the subset for the form toolbar.
1382: * @return <code>Collection</code> of <code>Action</code> objects.
1383: */
1384: public Collection<Action> getDesignerActions(boolean forToolbar) {
1385: if (designerActions == null) {
1386: designerActions = new LinkedList<Action>();
1387: // Grouping actions
1388: designerActions.add(new AlignAction(
1389: LayoutConstants.HORIZONTAL,
1390: LayoutConstants.LEADING, true));
1391: designerActions.add(new AlignAction(
1392: LayoutConstants.HORIZONTAL,
1393: LayoutConstants.TRAILING, true));
1394: designerActions.add(new AlignAction(
1395: LayoutConstants.HORIZONTAL, LayoutConstants.CENTER,
1396: true));
1397: designerActions.add(new AlignAction(
1398: LayoutConstants.VERTICAL, LayoutConstants.LEADING,
1399: true));
1400: designerActions.add(new AlignAction(
1401: LayoutConstants.VERTICAL, LayoutConstants.TRAILING,
1402: true));
1403: designerActions.add(new AlignAction(
1404: LayoutConstants.VERTICAL, LayoutConstants.CENTER,
1405: true));
1406: // Align actions
1407: designerActions.add(new AlignAction(
1408: LayoutConstants.HORIZONTAL,
1409: LayoutConstants.LEADING, false));
1410: designerActions.add(new AlignAction(
1411: LayoutConstants.HORIZONTAL,
1412: LayoutConstants.TRAILING, false));
1413: designerActions.add(new AlignAction(
1414: LayoutConstants.VERTICAL, LayoutConstants.LEADING,
1415: false));
1416: designerActions.add(new AlignAction(
1417: LayoutConstants.VERTICAL, LayoutConstants.TRAILING,
1418: false));
1419: }
1420: return forToolbar ? designerActions.subList(0, 6)
1421: : designerActions;
1422: }
1423:
1424: public Collection<Action> getResizabilityActions() {
1425: if (resizabilityActions == null) {
1426: resizabilityActions = new LinkedList<Action>();
1427: resizabilityActions.add(new ResizabilityAction(
1428: LayoutConstants.HORIZONTAL));
1429: resizabilityActions.add(new ResizabilityAction(
1430: LayoutConstants.VERTICAL));
1431: }
1432: return resizabilityActions;
1433: }
1434:
1435: /**
1436: * Returns collection of ids of the selected layout components.
1437: *
1438: * @return <code>Collection</code> of <code>String</code> objects.
1439: */
1440: Collection<String> selectedLayoutComponentIds() {
1441: Iterator metacomps = getSelectedLayoutComponents().iterator();
1442: Collection<String> selectedIds = new LinkedList<String>();
1443: while (metacomps.hasNext()) {
1444: RADComponent metacomp = (RADComponent) metacomps.next();
1445: selectedIds.add(metacomp.getId());
1446: }
1447: return selectedIds;
1448: }
1449:
1450: /**
1451: * Checks whether the given components are in the same containter.
1452: *
1453: * @param compIds <code>Collection</code> of component IDs.
1454: * @return common container parent or <code>null</code>
1455: * if the components are not from the same container.
1456: */
1457: private RADComponent commonParent(Collection compIds) {
1458: RADComponent parent = null;
1459: Iterator iter = compIds.iterator();
1460: FormModel formModel = getFormModel();
1461: while (iter.hasNext()) {
1462: String compId = (String) iter.next();
1463: RADComponent metacomp = formModel.getMetaComponent(compId);
1464: RADComponent metacont = metacomp.getParentComponent();
1465: if (parent == null) {
1466: parent = metacont;
1467: }
1468: if ((metacont == null) || (parent != metacont)) {
1469: return null;
1470: }
1471: }
1472: return parent;
1473: }
1474:
1475: // ---------
1476: // visibility update
1477:
1478: // synchronizes ComponentInspector with selection in FormDesigner
1479: // [there is a hardcoded relationship between these two views]
1480: void updateComponentInspector() {
1481: ComponentInspector ci = ComponentInspector.getInstance();
1482: if (ci.getFocusedForm() != formEditor)
1483: return;
1484:
1485: Node[] selectedNodes = getSelectedComponentNodes();
1486: try {
1487: setActivatedNodes(selectedNodes); // Issue 62356
1488: ci.setSelectedNodes(selectedNodes, formEditor);
1489: // sets also the activated nodes (both for ComponentInspector
1490: // and FormDesigner)
1491: } catch (java.beans.PropertyVetoException ex) {
1492: ex.printStackTrace();
1493: }
1494: }
1495:
1496: void updateVisualSettings() {
1497: componentLayer.updateVisualSettings();
1498: if (nonVisualTray != null) {
1499: nonVisualTray.updateVisualSettings();
1500: }
1501: layeredPane.revalidate();
1502: layeredPane.repaint(); // repaints both HanleLayer and ComponentLayer
1503: }
1504:
1505: private void ensureComponentIsShown(RADVisualComponent metacomp) {
1506: Component comp = (Component) getComponent(metacomp);
1507: if (comp == null)
1508: return; // component is not in the visualized tree
1509:
1510: // if (comp == null) { // visual component doesn't exist yet
1511: // if (metacont != null)
1512: // metacont.getLayoutSupport().selectComponent(
1513: // metacont.getIndexOf(metacomp));
1514: // return;
1515: // }
1516:
1517: if (comp.isShowing())
1518: return; // component is showing
1519: if (!isInDesigner(metacomp))
1520: return; // component is not in designer
1521:
1522: Component topComp = (Component) getComponent(topDesignComponent);
1523: if (topComp == null || !topComp.isShowing())
1524: return; // designer is not showing
1525:
1526: RADVisualContainer metacont = metacomp.getParentContainer();
1527: RADVisualComponent child = metacomp;
1528:
1529: while (metacont != null) {
1530: Container cont = (Container) getComponent(metacont);
1531:
1532: LayoutSupportManager laysup = metacont.getLayoutSupport();
1533: if (laysup != null) {
1534: Container contDelegate = metacont
1535: .getContainerDelegate(cont);
1536: laysup.selectComponent(child.getComponentIndex());
1537: laysup.arrangeContainer(cont, contDelegate);
1538: }
1539:
1540: if (metacont == topDesignComponent || cont.isShowing())
1541: break;
1542:
1543: child = metacont;
1544: metacont = metacont.getParentContainer();
1545: }
1546: }
1547:
1548: // --------------
1549: // bean connection
1550:
1551: void connectBean(RADComponent metacomp, boolean showDialog) {
1552: if (connectionSource == null) {
1553: connectionSource = metacomp;
1554: FormEditor.getAssistantModel(formModel).setContext(
1555: "connectTarget"); // NOI18N
1556: handleLayer.repaint();
1557: } else {
1558: if (metacomp == connectionSource) {
1559: if (connectionTarget != null) {
1560: resetConnection();
1561: toggleSelectionMode();
1562: }
1563: return;
1564: }
1565: connectionTarget = metacomp;
1566: handleLayer.repaint();
1567: if (showDialog) {
1568: if (connectionTarget != null) {
1569: FormEditor.getAssistantModel(formModel).setContext(
1570: "connectWizard"); // NOI18N
1571: createConnection(connectionSource, connectionTarget);
1572: }
1573: // resetConnection();
1574: toggleSelectionMode();
1575: }
1576: }
1577: }
1578:
1579: public RADComponent getConnectionSource() {
1580: return connectionSource;
1581: }
1582:
1583: public RADComponent getConnectionTarget() {
1584: return connectionTarget;
1585: }
1586:
1587: public void resetConnection() {
1588: if (connectionSource != null || connectionTarget != null) {
1589: connectionSource = null;
1590: connectionTarget = null;
1591: handleLayer.repaint();
1592: }
1593: }
1594:
1595: private void createConnection(RADComponent source,
1596: RADComponent target) {
1597: ConnectionWizard cw = new ConnectionWizard(formModel, source,
1598: target);
1599:
1600: if (cw.show()) {
1601: final Event event = cw.getSelectedEvent();
1602: final String eventName = cw.getEventName();
1603: String bodyText = cw.getGeneratedCode();
1604:
1605: formModel.getFormEvents().attachEvent(event, eventName,
1606: bodyText);
1607:
1608: // hack: after all updates, switch to editor
1609: SwingUtilities.invokeLater(new Runnable() {
1610: public void run() {
1611: formModel.getFormEvents().attachEvent(event,
1612: eventName, null);
1613: }
1614: });
1615: }
1616: }
1617:
1618: // -----------------
1619: // in-place editing
1620:
1621: public void startInPlaceEditing(RADComponent metacomp) {
1622:
1623: if (formModel.isReadOnly())
1624: return;
1625: if (textEditLayer != null && textEditLayer.isVisible())
1626: return;
1627: if (!isEditableInPlace(metacomp)) // check for sure
1628: return;
1629:
1630: Component comp = (Component) getComponent(metacomp);
1631: if (comp == null) { // component is not visible
1632: notifyCannotEditInPlace();
1633: return;
1634: }
1635:
1636: FormProperty property = null;
1637: if (JTabbedPane.class.isAssignableFrom(metacomp.getBeanClass())) {
1638: JTabbedPane tabbedPane = (JTabbedPane) comp;
1639: int index = tabbedPane.getSelectedIndex();
1640: RADVisualContainer metacont = (RADVisualContainer) metacomp;
1641: RADVisualComponent tabComp = metacont
1642: .getSubComponent(index);
1643: Node.Property[] props = tabComp.getConstraintsProperties();
1644: for (int i = 0; i < props.length; i++) {
1645: if (props[i].getName()
1646: .equals("TabConstraints.tabTitle")) { // NOI18N
1647: if (props[i] instanceof FormProperty) {
1648: property = (FormProperty) props[i];
1649: } else {
1650: return;
1651: }
1652: }
1653: }
1654: if (property == null)
1655: return;
1656: } else {
1657: property = metacomp.getBeanProperty("text"); // NOI18N
1658: if (property == null)
1659: return; // should not happen
1660: }
1661:
1662: String editText = null;
1663: try {
1664: Object text = property.getRealValue();
1665: if (!(text instanceof String))
1666: text = ""; // or return?
1667: editText = (String) text;
1668: } catch (Exception ex) { // should not happen
1669: ex.printStackTrace();
1670: return;
1671: }
1672:
1673: editedProperty = property;
1674:
1675: getInPlaceEditLayer();
1676: try {
1677: textEditLayer.setEditedComponent(comp, editText);
1678: } catch (IllegalArgumentException ex) {
1679: notifyCannotEditInPlace();
1680: return;
1681: }
1682:
1683: textEditLayer.setVisible(true);
1684: handleLayer.setVisible(false);
1685: textEditLayer.requestFocus();
1686: }
1687:
1688: private InPlaceEditLayer.FinishListener getFinnishListener() {
1689: if (finnishListener == null) {
1690: finnishListener = new InPlaceEditLayer.FinishListener() {
1691: public void editingFinished(boolean textChanged) {
1692: finishInPlaceEditing(textEditLayer.isTextChanged());
1693: }
1694: };
1695: }
1696: return finnishListener;
1697: }
1698:
1699: private void finishInPlaceEditing(boolean applyChanges) {
1700: if (applyChanges) {
1701: try {
1702: Object value = editedProperty.getValue();
1703: if (value instanceof String) {
1704: editedProperty.setValue(textEditLayer
1705: .getEditedText());
1706: } else {
1707: PropertyEditor prEd = editedProperty
1708: .findDefaultEditor();
1709: editedProperty
1710: .setValue(new FormProperty.ValueWithEditor(
1711: textEditLayer.getEditedText(), prEd));
1712: }
1713: } catch (Exception ex) { // should not happen
1714: ex.printStackTrace();
1715: }
1716: }
1717: if (handleLayer != null) {
1718: textEditLayer.setVisible(false);
1719: handleLayer.setVisible(true);
1720: handleLayer.requestFocus();
1721: }
1722: editedProperty = null;
1723: }
1724:
1725: public boolean isEditableInPlace(RADComponent metacomp) {
1726: if (metacomp == null) {
1727: return false;
1728: }
1729: Object comp = getComponent(metacomp);
1730: if (!(comp instanceof Component)) {
1731: return false;
1732: }
1733:
1734: // don't allow in-place editing if there's some AWT parent (it may
1735: // cause problems with fake peers on some platforms)
1736: RADComponent parent = metacomp.getParentComponent();
1737: while (parent != null) {
1738: if (!JComponent.class.isAssignableFrom(parent
1739: .getBeanClass())
1740: && !RootPaneContainer.class.isAssignableFrom(parent
1741: .getBeanClass()))
1742: return false;
1743: parent = parent.getParentComponent();
1744: }
1745:
1746: Class beanClass = metacomp.getBeanClass();
1747: return InPlaceEditLayer.supportsEditingFor(beanClass, false)
1748: && (!JTabbedPane.class.isAssignableFrom(beanClass) || ((JTabbedPane) comp)
1749: .getTabCount() != 0);
1750: }
1751:
1752: private void notifyCannotEditInPlace() {
1753: DialogDisplayer.getDefault().notify(
1754: new NotifyDescriptor.Message(FormUtils
1755: .getBundleString("MSG_ComponentNotShown"), // NOI18N
1756: NotifyDescriptor.WARNING_MESSAGE));
1757: }
1758:
1759: // -----------------
1760: // menu editing
1761:
1762: public void openMenu(RADComponent metacomp) {
1763: MenuEditLayer menuEditLayer = getMenuEditLayer();
1764: Component comp = (Component) getComponent(metacomp);
1765: menuEditLayer.setVisible(true);
1766: menuEditLayer.openAndShowMenu(metacomp, comp);
1767: }
1768:
1769: // --------
1770: // methods of TopComponent
1771:
1772: // only MultiViewDescriptor is stored, not MultiViewElement
1773: @Override
1774: public int getPersistenceType() {
1775: return TopComponent.PERSISTENCE_NEVER;
1776: }
1777:
1778: @Override
1779: public HelpCtx getHelpCtx() {
1780: return new HelpCtx("gui.formeditor"); // NOI18N
1781: }
1782:
1783: @Override
1784: public void componentActivated() {
1785: if (formModel == null)
1786: return;
1787:
1788: formEditor.setFormDesigner(this );
1789: ComponentInspector ci = ComponentInspector.getInstance();
1790: if (ci.getFocusedForm() != formEditor) {
1791: ci.focusForm(formEditor);
1792: if (getDesignerMode() == MODE_CONNECT)
1793: clearSelection();
1794: else
1795: updateComponentInspector();
1796: }
1797:
1798: ci.attachActions();
1799: if (textEditLayer == null || !textEditLayer.isVisible())
1800: handleLayer.requestFocus();
1801: }
1802:
1803: @Override
1804: public void componentDeactivated() {
1805: if (formModel == null)
1806: return;
1807:
1808: if (textEditLayer != null && textEditLayer.isVisible())
1809: textEditLayer.finishEditing(false);
1810:
1811: ComponentInspector.getInstance().detachActions();
1812: resetConnection();
1813: }
1814:
1815: @Override
1816: public UndoRedo getUndoRedo() {
1817: UndoRedo ur = formModel != null ? formModel
1818: .getUndoRedoManager() : null;
1819: return ur != null ? ur : super .getUndoRedo();
1820: }
1821:
1822: @Override
1823: protected String preferredID() {
1824: return formEditor.getFormDataObject().getName();
1825: }
1826:
1827: // ------
1828: // multiview stuff
1829:
1830: public JComponent getToolbarRepresentation() {
1831: return getFormToolBar();
1832: }
1833:
1834: public JComponent getVisualRepresentation() {
1835: return this ;
1836: }
1837:
1838: public void setMultiViewCallback(MultiViewElementCallback callback) {
1839: multiViewObserver = callback;
1840:
1841: // add FormDesigner as a client property so it can be obtained
1842: // from multiview TopComponent (it is not sufficient to put
1843: // it into lookup - only content of the lookup of the active
1844: // element is accessible)
1845: callback.getTopComponent().putClientProperty("formDesigner",
1846: this ); // NOI18N
1847:
1848: // needed for deserialization...
1849: if (formEditor != null) {
1850: // this is used (or misused?) to obtain the deserialized multiview
1851: // topcomponent and set it to FormEditorSupport
1852: FormDataObject formDO = formEditor.getFormDataObject();
1853: formDO.getFormEditorSupport().setTopComponent(
1854: callback.getTopComponent());
1855: }
1856: }
1857:
1858: @Override
1859: public void requestVisible() {
1860: if (multiViewObserver != null)
1861: multiViewObserver.requestVisible();
1862: else
1863: super .requestVisible();
1864: }
1865:
1866: @Override
1867: public void requestActive() {
1868: if (multiViewObserver != null)
1869: multiViewObserver.requestActive();
1870: else
1871: super .requestActive();
1872: }
1873:
1874: @Override
1875: public void componentClosed() {
1876: super .componentClosed();
1877: if (formModel != null) {
1878: if (formModelListener != null) {
1879: formModel.removeFormModelListener(formModelListener);
1880: }
1881: if (settingsListener != null) {
1882: FormLoaderSettings.getPreferences()
1883: .removePreferenceChangeListener(
1884: settingsListener);
1885: }
1886: topDesignComponent = null;
1887: formModel = null;
1888: }
1889: }
1890:
1891: @Override
1892: public void componentShowing() {
1893: super .componentShowing();
1894: if (!formEditor.isFormLoaded()) {
1895: formEditor.loadFormDesigner();
1896: if (!formEditor.isFormLoaded()) { // there was a loading error
1897: removeAll();
1898: return;
1899: }
1900: // hack: after IDE start, if some form is opened but not active in
1901: // winsys, we need to select it in ComponentInspector
1902: EventQueue.invokeLater(new Runnable() {
1903: public void run() {
1904: if (formEditor != null
1905: && formEditor.isFormLoaded()
1906: && ComponentInspector.exists()
1907: && ComponentInspector.getInstance()
1908: .getFocusedForm() == null) {
1909: ComponentInspector.getInstance().focusForm(
1910: formEditor);
1911: }
1912: }
1913: });
1914: }
1915: if (!initialized) {
1916: initialize();
1917: }
1918: FormEditorSupport.checkFormGroupVisibility();
1919: }
1920:
1921: @Override
1922: public void componentHidden() {
1923: super .componentHidden();
1924: FormEditorSupport.checkFormGroupVisibility();
1925: }
1926:
1927: @Override
1928: public void componentOpened() {
1929: super .componentOpened();
1930: if ((formEditor == null) && (multiViewObserver != null)) { // Issue 67879
1931: multiViewObserver.getTopComponent().close();
1932: EventQueue.invokeLater(new Runnable() {
1933: public void run() {
1934: FormEditorSupport.checkFormGroupVisibility();
1935: }
1936: });
1937: }
1938: }
1939:
1940: public CloseOperationState canCloseElement() {
1941: // if this is not the last cloned designer, closing is OK
1942: if (!FormEditorSupport.isLastView(multiViewObserver
1943: .getTopComponent()))
1944: return CloseOperationState.STATE_OK;
1945:
1946: // return a placeholder state - to be sure our CloseHandler is called
1947: return MultiViewFactory.createUnsafeCloseState(
1948: "ID_FORM_CLOSING", // dummy ID // NOI18N
1949: MultiViewFactory.NOOP_CLOSE_ACTION,
1950: MultiViewFactory.NOOP_CLOSE_ACTION);
1951: }
1952:
1953: public InPlaceEditLayer getInPlaceEditLayer() {
1954: if (textEditLayer == null) {
1955: textEditLayer = new InPlaceEditLayer();
1956: textEditLayer.setVisible(false);
1957: textEditLayer.addFinishListener(getFinnishListener());
1958: layeredPane.add(textEditLayer, new Integer(2001));
1959: }
1960: return textEditLayer;
1961: }
1962:
1963: MenuEditLayer getMenuEditLayer() {
1964: if (menuEditLayer == null) {
1965: menuEditLayer = new MenuEditLayer(this );
1966: menuEditLayer.setVisible(false);
1967: layeredPane.add(menuEditLayer, new Integer(2000));
1968: }
1969: return menuEditLayer;
1970: }
1971:
1972: // -----------
1973: // innerclasses
1974:
1975: private class LayoutMapper implements VisualMapper {
1976:
1977: // -------
1978:
1979: // public String getTopComponentId() {
1980: // return getTopDesignComponent().getId();
1981: // }
1982:
1983: public Rectangle getComponentBounds(String componentId) {
1984: Component visual = getVisualComponent(componentId, true,
1985: false);
1986: Rectangle rect = null;
1987: if (visual != null) {
1988: rect = componentBoundsToTop(visual);
1989: }
1990:
1991: if (getLayoutDesigner().logTestCode()) {
1992: getLayoutDesigner().testCode.add(" compBounds.put(\""
1993: + componentId + "\", new Rectangle("
1994: + //NOI18N
1995: rect.x + ", " + rect.y + ", " + rect.width
1996: + ", " + rect.height + "));"); //NOI18N
1997: }
1998:
1999: return rect;
2000: }
2001:
2002: public Rectangle getContainerInterior(String componentId) {
2003: Component visual = getVisualComponent(componentId, true,
2004: false);
2005: if (visual == null)
2006: return null;
2007:
2008: RADVisualContainer metacont = (RADVisualContainer) getMetaComponent(componentId);
2009: Container cont = metacont.getContainerDelegate(visual);
2010:
2011: Rectangle rect = componentBoundsToTop(cont);
2012: Insets insets = cont.getInsets();
2013: rect.x += insets.left;
2014: rect.y += insets.top;
2015: rect.width -= insets.left + insets.right;
2016: rect.height -= insets.top + insets.bottom;
2017:
2018: if (getLayoutDesigner().logTestCode()) {
2019: getLayoutDesigner().testCode
2020: .add(" contInterior.put(\""
2021: + componentId
2022: + "\", new Rectangle("
2023: + //NOI18N
2024: rect.x + ", " + rect.y + ", "
2025: + rect.width + ", " + rect.height
2026: + "));"); //NOI18N
2027: }
2028:
2029: return rect;
2030: }
2031:
2032: public Dimension getComponentMinimumSize(String componentId) {
2033: Component visual = getVisualComponent(componentId, false,
2034: false);
2035: Dimension dim = null;
2036: if (visual != null) {
2037: dim = visual.getMinimumSize();
2038: }
2039: if (getLayoutDesigner().logTestCode()) {
2040: getLayoutDesigner().testCode.add(" compMinSize.put(\""
2041: + componentId
2042: + "\", new Dimension("
2043: + //NOI18N
2044: new Double(dim.getWidth()).intValue() + ", "
2045: + new Double(dim.getHeight()).intValue()
2046: + "));"); //NOI18N
2047: }
2048: return dim;
2049: }
2050:
2051: public Dimension getComponentPreferredSize(String componentId) {
2052: Component visual = getVisualComponent(componentId, false,
2053: false);
2054: Dimension dim = null;
2055: if (visual != null) {
2056: dim = visual.getPreferredSize();
2057: }
2058: if (getLayoutDesigner().logTestCode()) {
2059: getLayoutDesigner().testCode
2060: .add(" compPrefSize.put(\""
2061: + componentId
2062: + "\", new Dimension("
2063: + //NOI18N
2064: new Double(dim.getWidth()).intValue()
2065: + ", "
2066: + new Double(dim.getHeight())
2067: .intValue() + "));"); //NOI18N
2068: }
2069: return dim;
2070: }
2071:
2072: public boolean hasExplicitPreferredSize(String componentId) {
2073: JComponent visual = (JComponent) getVisualComponent(
2074: componentId, false, true);
2075: boolean hasExplPrefSize = false;
2076: if (visual != null) {
2077: hasExplPrefSize = visual.isPreferredSizeSet();
2078: }
2079: if (getLayoutDesigner().logTestCode()) {
2080: getLayoutDesigner().testCode
2081: .add(" hasExplicitPrefSize.put(\""
2082: + componentId + "\", new Boolean("
2083: + hasExplPrefSize + "));"); //NOI18N
2084: }
2085: return hasExplPrefSize;
2086: }
2087:
2088: public int getBaselinePosition(String componentId, int width,
2089: int height) {
2090: int baseLinePos = -1;
2091: JComponent comp = (JComponent) getVisualComponent(
2092: componentId, true, true);
2093: // [hack - vertically resizable components cannot be baseline aligned]
2094: // [this should be either solved or filtered in LayoutDragger according to vertical resizability of the component]
2095: if (comp != null
2096: && (comp instanceof JScrollPane
2097: || comp.getClass().equals(JPanel.class) || comp instanceof JTabbedPane)) {
2098: // || comp instanceof JTextArea
2099: // || comp instanceof JTree || comp instanceof JTable || comp instanceof JList
2100: baseLinePos = 0;
2101: }
2102:
2103: if (baseLinePos == -1) {
2104: if (comp != null) {
2105: baseLinePos = Baseline.getBaseline(comp, width,
2106: height);
2107: } else {
2108: baseLinePos = 0;
2109: }
2110: }
2111:
2112: if (getLayoutDesigner().logTestCode()) {
2113: String id = componentId + "-" + width + "-" + height; //NOI18N
2114: getLayoutDesigner().testCode
2115: .add(" baselinePosition.put(\"" + id
2116: + "\", new Integer(" + baseLinePos
2117: + "));"); //NOI18N
2118: }
2119:
2120: return baseLinePos;
2121: }
2122:
2123: public int getPreferredPadding(String comp1Id, String comp2Id,
2124: int dimension, int comp2Alignment,
2125: PaddingType paddingType) {
2126: String id = null;
2127: if (getLayoutDesigner().logTestCode()) {
2128: id = comp1Id + "-"
2129: + comp2Id
2130: + "-"
2131: + dimension
2132: + "-"
2133: + comp2Alignment
2134: + "-" // NOI18N
2135: + (paddingType != null ? paddingType.ordinal()
2136: : 0);
2137: }
2138:
2139: JComponent comp1 = (JComponent) getVisualComponent(comp1Id,
2140: true, true);
2141: JComponent comp2 = (JComponent) getVisualComponent(comp2Id,
2142: true, true);
2143: if (comp1 == null || comp2 == null) { // not JComponents...
2144: if (getLayoutDesigner().logTestCode()) {
2145: getLayoutDesigner().testCode
2146: .add(" prefPadding.put(\"" + id + //NOI18N
2147: "\", new Integer(10)); // comp1Id-comp2Id-dimension-comp2Alignment-paddingType"); //NOI18N
2148: }
2149: return 10; // default distance between components (for non-JComponents)
2150: }
2151:
2152: assert dimension == HORIZONTAL || dimension == VERTICAL;
2153: assert comp2Alignment == LEADING
2154: || comp2Alignment == TRAILING;
2155:
2156: int type = paddingType == PaddingType.INDENT ? LayoutStyle.INDENT
2157: : (paddingType == PaddingType.RELATED ? LayoutStyle.RELATED
2158: : LayoutStyle.UNRELATED);
2159: int position = 0;
2160: if (dimension == HORIZONTAL) {
2161: if (paddingType == PaddingType.INDENT) {
2162: position = comp2Alignment == LEADING ? SwingConstants.WEST
2163: : SwingConstants.EAST;
2164: } else {
2165: position = comp2Alignment == LEADING ? SwingConstants.EAST
2166: : SwingConstants.WEST;
2167: }
2168: } else {
2169: position = comp2Alignment == LEADING ? SwingConstants.SOUTH
2170: : SwingConstants.NORTH;
2171: }
2172:
2173: int prefPadding = paddingType != PaddingType.SEPARATE ? FormLAF
2174: .getDesignerLayoutStyle().getPreferredGap(comp1,
2175: comp2, type, position, null)
2176: : SwingLayoutBuilder.PADDING_SEPARATE_VALUE; // not in LayoutStyle
2177:
2178: if (getLayoutDesigner().logTestCode()) {
2179: getLayoutDesigner().testCode
2180: .add(" prefPadding.put(\"" + id
2181: + "\", new Integer(" + prefPadding + //NOI18N
2182: ")); // comp1Id-comp2Id-dimension-comp2Alignment-paddingType"); //NOI18N
2183: }
2184:
2185: return prefPadding;
2186: }
2187:
2188: public int getPreferredPaddingInParent(String parentId,
2189: String compId, int dimension, int compAlignment) {
2190: String id = null;
2191: if (getLayoutDesigner().logTestCode()) {
2192: id = parentId + "-" + compId + "-" + dimension + "-"
2193: + compAlignment; //NOI18N
2194: }
2195:
2196: JComponent comp = null;
2197: Container parent = (Container) getVisualComponent(parentId,
2198: true, false);
2199: if (parent != null) {
2200: RADVisualContainer metacont = (RADVisualContainer) getMetaComponent(parentId);
2201: parent = metacont.getContainerDelegate(parent);
2202: comp = (JComponent) getVisualComponent(compId, true,
2203: true);
2204: }
2205: if (comp == null) {
2206: if (getLayoutDesigner().logTestCode()) {
2207: getLayoutDesigner().testCode
2208: .add(" prefPaddingInParent.put(\"" + id + //NOI18N
2209: "\", new Integer(10)); // parentId-compId-dimension-compAlignment"); //NOI18N
2210: }
2211: return 10; // default distance from parent border (for non-JComponents)
2212: }
2213:
2214: assert dimension == HORIZONTAL || dimension == VERTICAL;
2215: assert compAlignment == LEADING
2216: || compAlignment == TRAILING;
2217:
2218: int alignment;
2219:
2220: if (dimension == HORIZONTAL) {
2221: if (compAlignment == LEADING) {
2222: alignment = SwingConstants.WEST;
2223: } else {
2224: alignment = SwingConstants.EAST;
2225: }
2226: } else {
2227: if (compAlignment == LEADING) {
2228: alignment = SwingConstants.NORTH;
2229: } else {
2230: alignment = SwingConstants.SOUTH;
2231: }
2232: }
2233: int prefPadding = FormLAF.getDesignerLayoutStyle()
2234: .getContainerGap(comp, alignment, parent);
2235:
2236: if (getLayoutDesigner().logTestCode()) {
2237: getLayoutDesigner().testCode
2238: .add(" prefPaddingInParent.put(\"" + id
2239: + "\", new Integer("
2240: + //NOI18N
2241: prefPadding
2242: + ")); // parentId-compId-dimension-compAlignment"); //NOI18N
2243: }
2244:
2245: return prefPadding;
2246: }
2247:
2248: public boolean[] getComponentResizability(String compId,
2249: boolean[] resizability) {
2250: resizability[0] = resizability[1] = true;
2251: // [real resizability spec TBD]
2252: return resizability;
2253: }
2254:
2255: public void rebuildLayout(String contId) {
2256: replicator
2257: .updateContainerLayout((RADVisualContainer) getMetaComponent(contId));
2258: replicator.getLayoutBuilder(contId).doLayout();
2259: }
2260:
2261: public void setComponentVisibility(String componentId,
2262: boolean visible) {
2263: Object comp = getComponent(componentId);
2264: if (comp instanceof Component) {
2265: ((Component) comp).setVisible(visible);
2266: }
2267: }
2268:
2269: // -------
2270:
2271: private RADComponent getMetaComponent(String compId) {
2272: RADComponent metacomp = formModel.getMetaComponent(compId);
2273: if (metacomp == null) {
2274: RADComponent precreated = formModel
2275: .getComponentCreator()
2276: .getPrecreatedMetaComponent();
2277: if (precreated != null
2278: && precreated.getId().equals(compId)) {
2279: metacomp = precreated;
2280: }
2281: }
2282: return metacomp;
2283: }
2284:
2285: private Component getVisualComponent(String compId,
2286: boolean needVisible, boolean needJComponent) {
2287: Object comp = getComponent(compId);
2288: if (comp == null) {
2289: RADVisualComponent precreated = formModel
2290: .getComponentCreator()
2291: .getPrecreatedMetaComponent();
2292: if (precreated != null
2293: && precreated.getId().equals(compId)) {
2294: comp = precreated.getBeanInstance();
2295: }
2296: if (comp == null && !needVisible) {
2297: RADComponent metacomp = getMetaComponent(compId);
2298: if (metacomp != null) {
2299: comp = metacomp.getBeanInstance();
2300: }
2301: }
2302: }
2303: Class<?> type = needJComponent ? JComponent.class
2304: : Component.class;
2305: return comp != null
2306: && type.isAssignableFrom(comp.getClass()) ? (Component) comp
2307: : null;
2308: }
2309:
2310: }
2311:
2312: // --------
2313:
2314: private Collection<String> componentIds() {
2315: List<String> componentIds = new LinkedList<String>();
2316: List selectedComps = getSelectedLayoutComponents();
2317: LayoutModel layoutModel = getFormModel().getLayoutModel();
2318: Iterator iter = selectedComps.iterator();
2319: while (iter.hasNext()) {
2320: RADVisualComponent visualComp = (RADVisualComponent) iter
2321: .next();
2322: if ((visualComp.getParentContainer() != null)
2323: && (visualComp.getParentLayoutSupport() == null)
2324: && layoutModel.getLayoutComponent(visualComp
2325: .getId()) != null)
2326: componentIds.add(visualComp.getId());
2327: }
2328: return componentIds;
2329: }
2330:
2331: // Listener on FormModel - ensures updating of designer view.
2332: private class FormListener implements FormModelListener, Runnable {
2333:
2334: private FormModelEvent[] events;
2335:
2336: public void formChanged(final FormModelEvent[] events) {
2337: if (!EventQueue.isDispatchThread()) {
2338: EventQueue.invokeLater(new Runnable() {
2339: public void run() {
2340: processEvents(events);
2341: }
2342: });
2343: } else {
2344: processEvents(events);
2345: }
2346: }
2347:
2348: private void processEvents(FormModelEvent[] events) {
2349: boolean lafBlock;
2350: if (events == null) {
2351: lafBlock = true;
2352: } else {
2353: lafBlock = false;
2354: boolean modifying = false;
2355: for (int i = 0; i < events.length; i++) {
2356: FormModelEvent ev = events[i];
2357: if (ev.isModifying())
2358: modifying = true;
2359: if ((ev.getChangeType() == FormModelEvent.COMPONENT_ADDED)
2360: || (ev.getChangeType() == FormModelEvent.COMPONENT_PROPERTY_CHANGED)
2361: || (ev.getChangeType() == FormModelEvent.BINDING_PROPERTY_CHANGED)) {
2362: lafBlock = true;
2363: break;
2364: }
2365: }
2366: if (!modifying)
2367: return;
2368:
2369: assert EventQueue.isDispatchThread();
2370: }
2371:
2372: this .events = events;
2373:
2374: if (lafBlock) { // Look&Feel UI defaults remapping needed
2375: Locale defaultLocale = switchToDesignLocale(getFormModel());
2376: try {
2377: FormLAF.executeWithLookAndFeel(formModel, this );
2378: } finally {
2379: if (defaultLocale != null)
2380: Locale.setDefault(defaultLocale);
2381: }
2382: } else
2383: run();
2384: }
2385:
2386: public void run() {
2387: if (events == null) {
2388: Object originalVisualComp = (topDesignComponent == null) ? null
2389: : replicator
2390: .getClonedComponent(topDesignComponent);
2391: Dimension originalSize = originalVisualComp instanceof Component ? ((Component) originalVisualComp)
2392: .getSize()
2393: : null;
2394:
2395: replicator.setTopMetaComponent(topDesignComponent);
2396: Component formClone = (Component) replicator
2397: .createClone();
2398: if (formClone != null) {
2399: formClone.setVisible(true);
2400: componentLayer.setTopDesignComponent(formClone);
2401: if (originalSize != null) {
2402: componentLayer.setDesignerSize(originalSize);
2403: checkDesignerSize();
2404: } else
2405: setupDesignerSize();
2406: if (getLayoutDesigner() != null)
2407: getLayoutDesigner()
2408: .externalSizeChangeHappened();
2409: // Must be invoked later. ComponentLayer doesn't have a peer (yet)
2410: // when the form is opened and validate does nothing on components
2411: // without peer.
2412: EventQueue.invokeLater(new Runnable() {
2413: public void run() {
2414: updateComponentLayer(false);
2415: }
2416: });
2417: }
2418: return;
2419: }
2420:
2421: FormModelEvent[] events = this .events;
2422: this .events = null;
2423:
2424: int prevType = 0;
2425: ComponentContainer prevContainer = null;
2426: boolean updateDone = false;
2427: boolean deriveDesignerSize = false;
2428:
2429: for (int i = 0; i < events.length; i++) {
2430: FormModelEvent ev = events[i];
2431: int type = ev.getChangeType();
2432: ComponentContainer metacont = ev.getContainer();
2433:
2434: if (type == FormModelEvent.CONTAINER_LAYOUT_EXCHANGED
2435: || type == FormModelEvent.CONTAINER_LAYOUT_CHANGED
2436: || type == FormModelEvent.COMPONENT_LAYOUT_CHANGED) {
2437: if ((prevType != FormModelEvent.CONTAINER_LAYOUT_EXCHANGED
2438: && prevType != FormModelEvent.CONTAINER_LAYOUT_CHANGED && prevType != FormModelEvent.COMPONENT_LAYOUT_CHANGED)
2439: || prevContainer != metacont) {
2440: replicator
2441: .updateContainerLayout((RADVisualContainer) metacont);
2442: updateDone = true;
2443: }
2444: } else if (type == FormModelEvent.COMPONENT_ADDED) {
2445: if ((metacont instanceof RADVisualContainer || metacont instanceof RADMenuComponent)
2446: && (prevType != FormModelEvent.COMPONENT_ADDED || prevContainer != metacont)) {
2447: replicator.updateAddedComponents(metacont);
2448: // Note: replicator calls BindingDesignSupport to establish
2449: // bindings for the the cloned instance (e.g. in remove undo)
2450: updateDone = true;
2451: }
2452: } else if (type == FormModelEvent.COMPONENT_REMOVED) {
2453: RADComponent removed = ev.getComponent();
2454:
2455: // if the top designed component (or some of its parents)
2456: // was removed then whole designer view must be recreated
2457: if (removed instanceof RADVisualComponent
2458: && (removed == topDesignComponent || removed
2459: .isParentComponent(topDesignComponent))) {
2460: resetTopDesignComponent(false);
2461: updateWholeDesigner();
2462: return;
2463: } else {
2464: replicator.removeComponent(ev.getComponent(),
2465: ev.getContainer());
2466: updateDone = true;
2467: }
2468: // Note: BindingDesignSupport takes care of removing bindings
2469: } else if (type == FormModelEvent.COMPONENTS_REORDERED) {
2470: if (prevType != FormModelEvent.COMPONENTS_REORDERED
2471: || prevContainer != metacont) {
2472: replicator.reorderComponents(metacont);
2473: updateDone = true;
2474: }
2475: } else if (type == FormModelEvent.COMPONENT_PROPERTY_CHANGED) {
2476: RADProperty eventProperty = ev
2477: .getComponentProperty();
2478: RADComponent eventComponent = ev.getComponent();
2479:
2480: replicator.updateComponentProperty(eventProperty);
2481: updateConnectedProperties(eventProperty,
2482: eventComponent);
2483:
2484: updateDone = true;
2485: } else if (type == FormModelEvent.BINDING_PROPERTY_CHANGED) {
2486: if (ev.getSubPropertyName() == null) {
2487: replicator.updateBinding(ev.getNewBinding());
2488: }
2489: // Note: BindingDesignSupport takes care of removing the old binding
2490: updateDone = true;
2491: } else if (type == FormModelEvent.SYNTHETIC_PROPERTY_CHANGED
2492: && PROP_DESIGNER_SIZE.equals(ev
2493: .getPropertyName())) {
2494: Dimension size = (Dimension) ev
2495: .getNewPropertyValue();
2496: if (size != null) {
2497: componentLayer.setDesignerSize(size);
2498: deriveDesignerSize = false;
2499: updateDone = true;
2500: } else { // null size to compute designer size based on content (from resetDesignerSize)
2501: deriveDesignerSize = true;
2502: updateDone = true;
2503: }
2504: }
2505:
2506: prevType = type;
2507: prevContainer = metacont;
2508: }
2509:
2510: if (updateDone) {
2511: if (deriveDesignerSize) { // compute from preferred size
2512: setupDesignerSize();
2513: } else { // check if not smaller than minimum size
2514: checkDesignerSize();
2515: }
2516: LayoutDesigner layoutDesigner = getLayoutDesigner();
2517: if ((layoutDesigner != null)
2518: && formModel.isCompoundEditInProgress()) {
2519: getLayoutDesigner().externalSizeChangeHappened();
2520: }
2521: updateComponentLayer(true);
2522: }
2523: }
2524:
2525: private void updateConnectedProperties(
2526: RADProperty eventProperty, RADComponent eventComponent) {
2527: for (RADComponent component : formModel.getAllComponents()) {
2528: RADProperty[] properties = component
2529: .getKnownBeanProperties();
2530: for (int i = 0; i < properties.length; i++) {
2531: try {
2532: if (properties[i].isChanged()) {
2533: Object value = properties[i].getValue();
2534: if (value instanceof RADConnectionPropertyEditor.RADConnectionDesignValue) {
2535: RADConnectionPropertyEditor.RADConnectionDesignValue propertyValue = (RADConnectionPropertyEditor.RADConnectionDesignValue) value;
2536:
2537: if (propertyValue.getRADComponent() != null
2538: && propertyValue.getProperty() != null
2539: && eventComponent
2540: .getName()
2541: .equals(
2542: propertyValue
2543: .getRADComponent()
2544: .getName())
2545: && eventProperty
2546: .getName()
2547: .equals(
2548: propertyValue
2549: .getProperty()
2550: .getName())) {
2551:
2552: replicator
2553: .updateComponentProperty(properties[i]);
2554: }
2555: }
2556: }
2557: } catch (Exception e) {
2558: ErrorManager.getDefault().notify(e);
2559: }
2560: }
2561: }
2562:
2563: }
2564: }
2565:
2566: /** Lookup that excludes nodes. */
2567: private static class NoNodeLookup extends Lookup {
2568: private final Lookup delegate;
2569:
2570: public NoNodeLookup(Lookup delegate) {
2571: this .delegate = delegate;
2572: }
2573:
2574: public <T> T lookup(Class<T> clazz) {
2575: return (clazz == Node.class) ? null : delegate
2576: .lookup(clazz);
2577: }
2578:
2579: public <T> Result<T> lookup(Template<T> template) {
2580: if (template.getType() == Node.class) {
2581: return Lookup.EMPTY.lookup(new Lookup.Template<T>(
2582: template.getType()));
2583: } else {
2584: return delegate.lookup(template);
2585: }
2586: }
2587: }
2588:
2589: /**
2590: * Action that aligns selected components in the specified direction.
2591: */
2592: private class AlignAction extends AbstractAction {
2593: // PENDING change to icons provided by Dusan
2594: private static final String ICON_BASE = "org/netbeans/modules/form/resources/align_"; // NOI18N
2595: /** Dimension to align in. */
2596: private int dimension;
2597: /** Requested alignment. */
2598: private int alignment;
2599: /** Group/Align action. */
2600: private boolean closed;
2601:
2602: /**
2603: * Creates action that aligns selected components in the specified direction.
2604: *
2605: * @param dimension dimension to align in.
2606: * @param alignment requested alignment.
2607: */
2608: AlignAction(int dimension, int alignment, boolean closed) {
2609: this .dimension = dimension;
2610: this .alignment = alignment;
2611: this .closed = closed;
2612: boolean horizontal = (dimension == LayoutConstants.HORIZONTAL);
2613: boolean leading = (alignment == LayoutConstants.LEADING);
2614: String code;
2615: if (alignment == LayoutConstants.CENTER) {
2616: code = (horizontal ? "ch" : "cv"); // NOI18N
2617: } else {
2618: code = (horizontal ? (leading ? "l" : "r")
2619: : (leading ? "u" : "d")); // NOI18N
2620: }
2621: String iconResource = ICON_BASE + code + ".png"; // NOI18N
2622: putValue(Action.SMALL_ICON, new ImageIcon(Utilities
2623: .loadImage(iconResource)));
2624: putValue(Action.SHORT_DESCRIPTION, FormUtils
2625: .getBundleString("CTL_AlignAction_" + code)); // NOI18N
2626: setEnabled(false);
2627: }
2628:
2629: /**
2630: * Performs the alignment of selected components.
2631: *
2632: * @param e event that invoked the action.
2633: */
2634: public void actionPerformed(ActionEvent e) {
2635: align(closed, dimension, alignment);
2636: }
2637:
2638: public int getDimension() {
2639: return dimension;
2640: }
2641:
2642: public int getAlignment() {
2643: return alignment;
2644: }
2645:
2646: }
2647:
2648: /**
2649: * Action that aligns selected components in the specified direction.
2650: */
2651: private class ResizabilityAction extends AbstractAction {
2652: // PENDING change to icons provided by Dusan
2653: private static final String ICON_BASE = "org/netbeans/modules/form/resources/resize_"; // NOI18N
2654: /** Dimension of resizability. */
2655: private int dimension;
2656:
2657: /**
2658: * Creates action that changes the resizability of the component.
2659: *
2660: * @param dimension dimension of the resizability
2661: */
2662: ResizabilityAction(int dimension) {
2663: this .dimension = dimension;
2664: String code = (dimension == LayoutConstants.HORIZONTAL) ? "h"
2665: : "v"; // NOI18N
2666: String iconResource = ICON_BASE + code + ".png"; // NOI18N
2667: putValue(Action.SMALL_ICON, new ImageIcon(Utilities
2668: .loadImage(iconResource)));
2669: putValue(Action.SHORT_DESCRIPTION, FormUtils
2670: .getBundleString("CTL_ResizeButton_" + code)); // NOI18N
2671: setEnabled(false);
2672: }
2673:
2674: /**
2675: * Performs the resizability change of selected components.
2676: *
2677: * @param e event that invoked the action.
2678: */
2679: public void actionPerformed(ActionEvent e) {
2680: FormModel formModel = getFormModel();
2681: LayoutModel layoutModel = formModel.getLayoutModel();
2682: Object layoutUndoMark = layoutModel.getChangeMark();
2683: javax.swing.undo.UndoableEdit ue = layoutModel
2684: .getUndoableEdit();
2685: boolean autoUndo = true;
2686: LayoutDesigner layoutDesigner = getLayoutDesigner();
2687: Collection componentIds = componentIds();
2688: Set<RADVisualContainer> containers = new HashSet<RADVisualContainer>();
2689: try {
2690: Iterator iter = componentIds.iterator();
2691: while (iter.hasNext()) {
2692: String compId = (String) iter.next();
2693: LayoutComponent layoutComp = layoutModel
2694: .getLayoutComponent(compId);
2695: boolean resizing = (getResizabilityButtons()[dimension])
2696: .isSelected();
2697: if (layoutDesigner.isComponentResizing(layoutComp,
2698: dimension) != resizing) {
2699: layoutDesigner.setComponentResizing(layoutComp,
2700: dimension, resizing);
2701: RADVisualComponent comp = (RADVisualComponent) formModel
2702: .getMetaComponent(compId);
2703: containers.add(comp.getParentContainer());
2704: }
2705: }
2706: autoUndo = false;
2707: } finally {
2708: Iterator<RADVisualContainer> iter = containers
2709: .iterator();
2710: while (iter.hasNext()) {
2711: formModel.fireContainerLayoutChanged(iter.next(),
2712: null, null, null);
2713: }
2714: if (!layoutUndoMark.equals(layoutModel.getChangeMark())) {
2715: formModel.addUndoableEdit(ue);
2716: }
2717: if (autoUndo) {
2718: formModel.forceUndoOfCompoundEdit();
2719: }
2720: }
2721: }
2722: }
2723:
2724: static class FormProxyLookup extends ProxyLookup {
2725:
2726: FormProxyLookup(Lookup[] lookups) {
2727: super (lookups);
2728: }
2729:
2730: Lookup[] getSubLookups() {
2731: return getLookups();
2732: }
2733:
2734: void setSubLookups(Lookup[] lookups) {
2735: setLookups(lookups);
2736: }
2737:
2738: }
2739:
2740: }
|