| /* |
| * Copyright 2000-2009 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.intellij.uiDesigner.radComponents; |
| |
| import com.intellij.openapi.project.Project; |
| import com.intellij.uiDesigner.UIFormXmlConstants; |
| import com.intellij.uiDesigner.XmlWriter; |
| import com.intellij.uiDesigner.core.GridConstraints; |
| import com.intellij.uiDesigner.designSurface.ComponentDragObject; |
| import com.intellij.uiDesigner.designSurface.ComponentDropLocation; |
| import com.intellij.uiDesigner.designSurface.FeedbackLayer; |
| import com.intellij.uiDesigner.designSurface.GuiEditor; |
| import com.intellij.uiDesigner.propertyInspector.Property; |
| import com.intellij.uiDesigner.propertyInspector.PropertyRenderer; |
| import com.intellij.uiDesigner.propertyInspector.PropertyEditor; |
| import com.intellij.uiDesigner.propertyInspector.InplaceContext; |
| import com.intellij.uiDesigner.propertyInspector.editors.ComboBoxPropertyEditor; |
| import com.intellij.uiDesigner.propertyInspector.renderers.LabelPropertyRenderer; |
| import com.intellij.uiDesigner.propertyInspector.properties.HGapProperty; |
| import com.intellij.uiDesigner.propertyInspector.properties.VGapProperty; |
| import com.intellij.uiDesigner.snapShooter.SnapshotContext; |
| import com.intellij.util.IncorrectOperationException; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.*; |
| import java.awt.*; |
| import java.util.ArrayList; |
| |
| /** |
| * @author yole |
| */ |
| public class RadBorderLayoutManager extends RadLayoutManager { |
| public String getName() { |
| return UIFormXmlConstants.LAYOUT_BORDER; |
| } |
| |
| public LayoutManager createLayout() { |
| return new BorderLayout(); |
| } |
| |
| public void writeLayout(final XmlWriter writer, final RadContainer radContainer) { |
| BorderLayout layout = (BorderLayout) radContainer.getLayout(); |
| writer.addAttribute(UIFormXmlConstants.ATTRIBUTE_HGAP, layout.getHgap()); |
| writer.addAttribute(UIFormXmlConstants.ATTRIBUTE_VGAP, layout.getVgap()); |
| } |
| |
| public void addComponentToContainer(final RadContainer container, final RadComponent component, final int index) { |
| if (component.getCustomLayoutConstraints() == null) { |
| if (container.getDelegee().getComponentCount() == 0) { |
| component.setCustomLayoutConstraints(BorderLayout.CENTER); |
| } |
| else { |
| throw new RuntimeException("can't add component without constraints to container with BorderLayout"); |
| } |
| } |
| container.getDelegee().add(component.getDelegee(), component.getCustomLayoutConstraints(), index); |
| } |
| |
| public void writeChildConstraints(final XmlWriter writer, final RadComponent child) { |
| writer.addAttribute(UIFormXmlConstants.ATTRIBUTE_BORDER_CONSTRAINT, (String) child.getCustomLayoutConstraints()); |
| } |
| |
| @NotNull @Override |
| public ComponentDropLocation getDropLocation(RadContainer container, final Point location) { |
| return new MyDropLocation(container, getQuadrantAt(container, location)); |
| } |
| |
| private static String getQuadrantAt(final RadContainer container, final Point location) { |
| if (location == null) { |
| return BorderLayout.CENTER; |
| } |
| |
| Dimension size = container.getDelegee().getSize(); |
| if (location.x < size.width / 3) { |
| return BorderLayout.WEST; |
| } |
| if (location.y < size.height / 3) { |
| return BorderLayout.NORTH; |
| } |
| if (location.x > size.width * 2 / 3) { |
| return BorderLayout.EAST; |
| } |
| if (location.y > size.height * 2 / 3) { |
| return BorderLayout.SOUTH; |
| } |
| |
| return BorderLayout.CENTER; |
| } |
| |
| |
| @Override public void changeContainerLayout(RadContainer container) throws IncorrectOperationException { |
| ArrayList<RadComponent> componentsInBorder = new ArrayList<RadComponent>(); |
| |
| boolean borderHorz = true; |
| if (container.getComponentCount() == 1) { |
| componentsInBorder.add(container.getComponent(0)); |
| } |
| else if (container.getLayoutManager().isIndexed()) { |
| for(RadComponent c: container.getComponents()) { |
| if (!(c instanceof RadHSpacer) && !(c instanceof RadVSpacer)) { |
| componentsInBorder.add(c); |
| } |
| } |
| } |
| else if (container.getLayoutManager().isGrid()) { |
| if (container.getGridRowCount() == 1) { |
| copyGridLine(container, componentsInBorder, true); |
| } |
| else if (container.getGridColumnCount() == 1) { |
| copyGridLine(container, componentsInBorder, false); |
| borderHorz = false; |
| } |
| } |
| |
| if ((container.getComponentCount() > 0 && componentsInBorder.size() == 0) || componentsInBorder.size() > 3) { |
| throw new IncorrectOperationException("Component layout is too complex to convert to BorderLayout"); |
| } |
| |
| for(int i=container.getComponentCount()-1; i >= 0; i--) { |
| container.removeComponent(container.getComponent(i)); |
| } |
| |
| super.changeContainerLayout(container); |
| |
| if (componentsInBorder.size() == 1) { |
| componentsInBorder.get(0).setCustomLayoutConstraints(BorderLayout.CENTER); |
| } |
| else if (componentsInBorder.size() > 1) { |
| componentsInBorder.get(0).setCustomLayoutConstraints(borderHorz ? BorderLayout.WEST : BorderLayout.NORTH); |
| componentsInBorder.get(1).setCustomLayoutConstraints(BorderLayout.CENTER); |
| if (componentsInBorder.size() > 2) { |
| componentsInBorder.get(2).setCustomLayoutConstraints(borderHorz ? BorderLayout.EAST : BorderLayout.SOUTH); |
| } |
| } |
| |
| for(RadComponent c: componentsInBorder) { |
| container.addComponent(c); |
| } |
| } |
| |
| private static void copyGridLine(final RadContainer container, final ArrayList<RadComponent> componentsInBorder, boolean isRow) { |
| int cell = 0; |
| while(cell < container.getGridCellCount(!isRow)) { |
| RadComponent c = container.getComponentAtGrid(isRow, 0, cell); |
| if (c == null) |
| cell++; |
| else { |
| if (!(c instanceof RadHSpacer) && !(c instanceof RadVSpacer)) { |
| componentsInBorder.add(c); |
| } |
| cell += c.getConstraints().getSpan(!isRow); |
| } |
| } |
| } |
| |
| @Override public Property[] getContainerProperties(final Project project) { |
| return new Property[] { |
| HGapProperty.getInstance(project), |
| VGapProperty.getInstance(project) |
| }; |
| } |
| |
| public Property[] getComponentProperties(final Project project, final RadComponent component) { |
| return new Property[] { |
| BorderSideProperty.INSTANCE |
| }; |
| } |
| |
| public boolean canMoveComponent(final RadComponent c, final int rowDelta, final int colDelta, final int rowSpanDelta, final int colSpanDelta) { |
| if (rowSpanDelta != 0 || colSpanDelta != 0) { |
| return false; |
| } |
| String side = (String) c.getCustomLayoutConstraints(); |
| String adjSide = getAdjacentSide(side, rowDelta, colDelta); |
| return adjSide != null && c.getParent().findComponentWithConstraints(adjSide) == null; |
| } |
| |
| public void moveComponent(final RadComponent c, final int rowDelta, final int colDelta, final int rowSpanDelta, final int colSpanDelta) { |
| String side = (String) c.getCustomLayoutConstraints(); |
| String adjSide = getAdjacentSide(side, rowDelta, colDelta); |
| if (adjSide != null) { |
| c.changeCustomLayoutConstraints(adjSide); |
| } |
| } |
| |
| @Nullable |
| private static String getAdjacentSide(final String side, final int rowDelta, final int colDelta) { |
| if (rowDelta == -1 && colDelta == 0) { |
| return getAdjacentSide(side, BorderLayout.NORTH, BorderLayout.SOUTH); |
| } |
| if (rowDelta == 1 && colDelta == 0) { |
| return getAdjacentSide(side, BorderLayout.SOUTH, BorderLayout.NORTH); |
| } |
| if (rowDelta == 0 && colDelta == -1) { |
| return getAdjacentSide(side, BorderLayout.WEST, BorderLayout.EAST); |
| } |
| if (rowDelta == 0 && colDelta == 1) { |
| return getAdjacentSide(side, BorderLayout.EAST, BorderLayout.WEST); |
| } |
| return null; |
| } |
| |
| @Nullable |
| private static String getAdjacentSide(final String side, final String toEdge, final String fromEdge) { |
| if (side.equals(toEdge)) { |
| return null; |
| } |
| if (side.equals(fromEdge)) { |
| return BorderLayout.CENTER; |
| } |
| return toEdge; |
| } |
| |
| @Override public void createSnapshotLayout(final SnapshotContext context, |
| final JComponent parent, |
| final RadContainer container, |
| final LayoutManager layout) { |
| BorderLayout borderLayout = (BorderLayout) layout; |
| container.setLayout(new BorderLayout(borderLayout.getHgap(), borderLayout.getVgap())); |
| } |
| |
| @Override public void addSnapshotComponent(final JComponent parent, |
| final JComponent child, |
| final RadContainer container, |
| final RadComponent component) { |
| BorderLayout borderLayout = (BorderLayout) parent.getLayout(); |
| final Object constraints = borderLayout.getConstraints(child); |
| if (constraints != null) { |
| // sometimes the container sets the layout manager to BorderLayout but |
| // overrides the layout() method so that the component constraints are not used |
| component.setCustomLayoutConstraints(constraints); |
| container.addComponent(component); |
| } |
| } |
| |
| private static class MyDropLocation implements ComponentDropLocation { |
| private final RadContainer myContainer; |
| private final String myQuadrant; |
| |
| public MyDropLocation(final RadContainer container, final String quadrant) { |
| myQuadrant = quadrant; |
| myContainer = container; |
| } |
| |
| public RadContainer getContainer() { |
| return myContainer; |
| } |
| |
| public boolean canDrop(ComponentDragObject dragObject) { |
| return dragObject.getComponentCount() == 1 && |
| ((BorderLayout) myContainer.getLayout()).getLayoutComponent(myQuadrant) == null; |
| } |
| |
| public void placeFeedback(FeedbackLayer feedbackLayer, ComponentDragObject dragObject) { |
| Dimension initialSize = dragObject.getInitialSize(myContainer); |
| feedbackLayer.putFeedback(myContainer.getDelegee(), getFeedbackRect(myQuadrant, initialSize), |
| myContainer.getDisplayName() + " (" + myQuadrant.toLowerCase() + ")"); |
| } |
| |
| private Rectangle getFeedbackRect(final String quadrant, final Dimension initialSize) { |
| Dimension size = myContainer.getDelegee().getSize(); |
| int initialWidth = (initialSize.width > 0 && initialSize.width < size.width) ? initialSize.width : size.width/3; |
| int initialHeight = (initialSize.height > 0 && initialSize.height < size.height) ? initialSize.height: size.height/3; |
| if (quadrant.equals(BorderLayout.WEST)) { |
| int deltaN = getHeightAtConstraint(BorderLayout.NORTH); |
| int deltaS = getHeightAtConstraint(BorderLayout.SOUTH); |
| return new Rectangle(0, deltaN, initialWidth, size.height - deltaN - deltaS); |
| } |
| if (quadrant.equals(BorderLayout.NORTH)) { |
| return new Rectangle(0, 0, size.width, initialHeight); |
| } |
| if (quadrant.equals(BorderLayout.EAST)) { |
| int deltaN = getHeightAtConstraint(BorderLayout.NORTH); |
| int deltaS = getHeightAtConstraint(BorderLayout.SOUTH); |
| return new Rectangle(size.width - initialWidth, deltaN, initialWidth, size.height - deltaN - deltaS); |
| } |
| if (quadrant.equals(BorderLayout.SOUTH)) { |
| return new Rectangle(0, size.height - initialHeight, size.width, initialHeight); |
| } |
| return new Rectangle(size.width/3, size.height/3, size.width/3, size.height/3); |
| } |
| |
| private int getHeightAtConstraint(final String constraint) { |
| BorderLayout layout = (BorderLayout) myContainer.getLayout(); |
| Component c = layout.getLayoutComponent(myContainer.getDelegee(), constraint); |
| if (c == null) { |
| return 0; |
| } |
| return c.getBounds().height; |
| } |
| |
| public void processDrop(GuiEditor editor, |
| RadComponent[] components, |
| GridConstraints[] constraintsToAdjust, |
| ComponentDragObject dragObject) { |
| components [0].setCustomLayoutConstraints(myQuadrant); |
| myContainer.addComponent(components [0]); |
| } |
| |
| @Nullable |
| public ComponentDropLocation getAdjacentLocation(Direction direction) { |
| String side = null; |
| switch (direction) { |
| case LEFT: |
| side = getAdjacentSide(myQuadrant, 0, -1); |
| break; |
| case UP: |
| side = getAdjacentSide(myQuadrant, -1, 0); |
| break; |
| case RIGHT: |
| side = getAdjacentSide(myQuadrant, 0, 1); |
| break; |
| case DOWN: |
| side = getAdjacentSide(myQuadrant, 1, 0); |
| break; |
| } |
| if (side != null) { |
| return new MyDropLocation(myContainer, side); |
| } |
| return null; |
| } |
| } |
| |
| private static class BorderSideProperty extends Property<RadComponent, String> { |
| private LabelPropertyRenderer<String> myRenderer = null; |
| private BorderSideEditor myEditor = null; |
| |
| public static BorderSideProperty INSTANCE = new BorderSideProperty(); |
| |
| public BorderSideProperty() { |
| super(null, "Border Side"); |
| } |
| |
| public String getValue(RadComponent component) { |
| return (String) component.getCustomLayoutConstraints(); |
| } |
| |
| protected void setValueImpl(RadComponent component, String value) throws Exception { |
| if (!value.equals(component.getCustomLayoutConstraints())) { |
| if (component.getParent().findComponentWithConstraints(value) != null) { |
| throw new Exception("There is already another component at location " + value); |
| } |
| component.changeCustomLayoutConstraints(value); |
| } |
| } |
| |
| @NotNull |
| public PropertyRenderer<String> getRenderer() { |
| if (myRenderer == null) { |
| myRenderer = new LabelPropertyRenderer<String>(); |
| } |
| return myRenderer; |
| } |
| |
| public PropertyEditor<String> getEditor() { |
| if (myEditor == null) { |
| myEditor = new BorderSideEditor(); |
| } |
| return myEditor; |
| } |
| } |
| |
| private static class BorderSideEditor extends ComboBoxPropertyEditor<String> { |
| public BorderSideEditor() { |
| String[] sides = new String[] { |
| BorderLayout.CENTER, BorderLayout.NORTH, BorderLayout.SOUTH, BorderLayout.WEST, BorderLayout.EAST, |
| BorderLayout.PAGE_START, BorderLayout.PAGE_END, BorderLayout.LINE_START, BorderLayout.LINE_END |
| }; |
| myCbx.setModel(new DefaultComboBoxModel(sides)); |
| } |
| |
| public JComponent getComponent(RadComponent component, String value, InplaceContext inplaceContext) { |
| myCbx.setSelectedItem(value); |
| return myCbx; |
| } |
| } |
| } |
| |