blob: 12fb2f52c12a2ef2c5901ede03555600e930ed03 [file] [log] [blame]
/*
* 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;
}
}
}