blob: 0bb7d72f894e1eaab0682b5ee76d90811427b784 [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.designSurface;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.radComponents.RadComponent;
import com.intellij.uiDesigner.radComponents.RadContainer;
import com.intellij.uiDesigner.shared.XYLayoutManager;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.Rectangle;
import java.awt.LayoutManager;
/**
* @author yole
*/
public class GridDropLocation implements ComponentDropLocation {
private static final Logger LOG = Logger.getInstance("#com.intellij.uiDesigner.designSurface.GridDropLocation");
protected final RadContainer myContainer;
protected int myRow;
protected int myColumn;
public GridDropLocation(@NotNull final RadContainer container, final int row, final int column) {
myContainer = container;
myRow = row;
myColumn = column;
}
public int getRow() {
return myRow;
}
public int getColumn() {
return myColumn;
}
public RadContainer getContainer() {
return myContainer;
}
public boolean canDrop(final ComponentDragObject dragObject) {
// If target point doesn't belong to any cell and column then do not allow drop.
if (myRow == -1 || myColumn == -1) {
LOG.debug("RadContainer.canDrop=false because no cell at mouse position");
return false;
}
int colSpan = 1; // allow drop any (NxM) component to cell (1x1)
int rowSpan = 1;
for(int i=0; i<dragObject.getComponentCount(); i++) {
int relativeCol = dragObject.getRelativeCol(i);
int relativeRow = dragObject.getRelativeRow(i);
LOG.debug("checking component: relativeRow" + relativeRow + ", relativeCol" + relativeCol + ", colSpan=" + colSpan + ", rowSpan=" + rowSpan);
if (myRow + relativeRow < 0 ||
myColumn + relativeCol < 0 ||
myRow + relativeRow + rowSpan > myContainer.getGridRowCount() ||
myColumn + relativeCol + colSpan > myContainer.getGridColumnCount()) {
LOG.debug("RadContainer.canDrop=false because range is outside grid: row=" + (myRow +relativeRow) +
", col=" + (myColumn +relativeCol) + ", colSpan=" + colSpan + ", rowSpan=" + rowSpan);
return false;
}
final RadComponent componentInRect = findOverlappingComponent(myRow + relativeRow, myColumn + relativeCol, rowSpan, colSpan);
if (componentInRect != null) {
LOG.debug("GridDropLocation.canDrop=false because found component " + componentInRect.getId() +
" in rect (row=" + (myRow +relativeRow) + ", col=" + (myColumn +relativeCol) +
", rowSpan=" + rowSpan + ", colSpan=" + colSpan + ")");
return false;
}
}
LOG.debug("canDrop=true");
return true;
}
protected RadComponent findOverlappingComponent(final int startRow, final int startCol, final int rowSpan, final int colSpan) {
return myContainer.findComponentInRect(startRow, startCol, rowSpan, colSpan);
}
public void placeFeedback(FeedbackLayer feedbackLayer, ComponentDragObject dragObject) {
Rectangle feedbackRect = null;
if (getContainer().getLayoutManager().isGrid()) {
feedbackRect = getGridFeedbackRect(dragObject, false, false, true);
}
if (feedbackRect != null) {
final JComponent component = getContainer().getDelegee();
StringBuilder feedbackBuilder = new StringBuilder(getContainer().getDisplayName());
feedbackBuilder.append(" (").append(myRow + getContainer().getGridLayoutManager().getCellIndexBase());
feedbackBuilder.append(", ").append(myColumn + getContainer().getGridLayoutManager().getCellIndexBase());
feedbackBuilder.append(")");
feedbackLayer.putFeedback(component, feedbackRect, feedbackBuilder.toString());
}
else {
feedbackLayer.removeFeedback();
}
}
@Nullable
protected Rectangle getGridFeedbackCellRect(ComponentDragObject dragObject,
boolean ignoreWidth,
boolean ignoreHeight,
boolean overlapping) {
if (dragObject.getComponentCount() == 0) {
return null;
}
Rectangle rc = calculateGridFeedbackCellRect(dragObject, ignoreWidth, ignoreHeight, true);
if (rc == null) {
return calculateGridFeedbackCellRect(dragObject, ignoreWidth, ignoreHeight, false);
}
if (overlapping && findOverlappingComponent(rc.y, rc.x, rc.height + 1, rc.width + 1) != null) {
return calculateGridFeedbackCellRect(dragObject, ignoreWidth, ignoreHeight, false);
}
return rc;
}
@Nullable
private Rectangle calculateGridFeedbackCellRect(ComponentDragObject dragObject,
boolean ignoreWidth,
boolean ignoreHeight,
boolean spans) {
Rectangle rc = getDragObjectDimensions(dragObject, spans);
int w = ignoreWidth ? 1 : rc.width;
int h = ignoreHeight ? 1 : rc.height;
if (rc.x < 0 || rc.y < 0 || rc.y + h > getContainer().getGridRowCount() || rc.x + w > getContainer().getGridColumnCount()) {
return null;
}
return new Rectangle(rc.x, rc.y, w - 1, h - 1);
}
protected Rectangle getDragObjectDimensions(ComponentDragObject dragObject, boolean spans) {
int firstRow = getRow();
int lastRow = getRow();
int firstCol = getColumn();
int lastCol = getColumn();
for (int i = 0; i < dragObject.getComponentCount(); i++) {
int relRow = dragObject.getRelativeRow(i);
int relCol = dragObject.getRelativeCol(i);
firstRow = Math.min(firstRow, getRow() + relRow);
firstCol = Math.min(firstCol, getColumn() + relCol);
lastRow = Math.max(lastRow, getRow() + relRow + (spans ? dragObject.getRowSpan(i) : 1) - 1);
lastCol = Math.max(lastCol, getColumn() + relCol + (spans ? dragObject.getColSpan(i) : 1) - 1);
}
return new Rectangle(firstCol, firstRow, lastCol - firstCol + 1, lastRow - firstRow + 1);
}
@Nullable
protected Rectangle getGridFeedbackRect(ComponentDragObject dragObject, boolean ignoreWidth, boolean ignoreHeight, boolean overlapping) {
Rectangle cellRect = getGridFeedbackCellRect(dragObject, ignoreWidth, ignoreHeight, overlapping);
if (cellRect == null) return null;
int h = ignoreHeight ? 0 : cellRect.height;
int w = ignoreWidth ? 0 : cellRect.width;
return getContainer().getGridLayoutManager().getGridCellRangeRect(getContainer(), cellRect.y, cellRect.x,
cellRect.y+h, cellRect.x+w);
}
public void processDrop(final GuiEditor editor,
final RadComponent[] components,
final GridConstraints[] constraintsToAdjust,
final ComponentDragObject dragObject) {
dropIntoGrid(myContainer, components, myRow, myColumn, dragObject);
}
@Nullable
public ComponentDropLocation getAdjacentLocation(Direction direction) {
switch(direction) {
case LEFT: return new GridInsertLocation(myContainer, myRow, myColumn, GridInsertMode.ColumnBefore);
case UP: return new GridInsertLocation(myContainer, myRow, myColumn, GridInsertMode.RowBefore);
case RIGHT: return new GridInsertLocation(myContainer, myRow, myColumn, GridInsertMode.ColumnAfter);
case DOWN: return new GridInsertLocation(myContainer, myRow, myColumn, GridInsertMode.RowAfter);
}
return null;
}
@NonNls @Override public String toString() {
return "GridDropLocation(row=" + myRow + ",col=" + myColumn + ")";
}
protected static void dropIntoGrid(final RadContainer container, final RadComponent[] components, int row, int column, final ComponentDragObject dragObject) {
assert components.length > 0;
for(int i=0; i<components.length; i++) {
RadComponent c = components [i];
if (c instanceof RadContainer) {
final LayoutManager layout = ((RadContainer)c).getLayout();
if (layout instanceof XYLayoutManager) {
((XYLayoutManager)layout).setPreferredSize(c.getSize());
}
}
int relativeCol = dragObject.getRelativeCol(i);
int relativeRow = dragObject.getRelativeRow(i);
LOG.debug("dropIntoGrid: relativeRow=" + relativeRow + ", relativeCol=" + relativeCol);
int colSpan = dragObject.getColSpan(i);
int rowSpan = dragObject.getRowSpan(i);
assert row + relativeRow >= 0;
assert column + relativeCol >= 0;
if (rowSpan > 1 || colSpan > 1) {
if ((row + relativeRow + rowSpan > container.getGridRowCount() && rowSpan > 1) ||
(column + relativeCol + colSpan > container.getGridColumnCount() && colSpan > 1) ||
container.findComponentInRect(row + relativeRow, column + relativeCol, rowSpan, colSpan) != null) {
rowSpan = 1;
colSpan = 1;
}
}
if (!container.getGridLayoutManager().isGridDefinedByComponents()) {
assert relativeRow + rowSpan <= container.getGridRowCount();
assert relativeCol + colSpan <= container.getGridColumnCount();
}
RadComponent old = container.findComponentInRect(row + relativeRow, column + relativeCol, rowSpan, colSpan);
if (old != null) {
LOG.error("Drop rectangle not empty: (" + (row + relativeRow) + ", " + (column + relativeCol) + ", " + rowSpan + ", " + colSpan +
"), component ID=" + old.getId());
}
final GridConstraints constraints = c.getConstraints();
constraints.setRow(row + relativeRow);
constraints.setColumn(column + relativeCol);
constraints.setRowSpan(rowSpan);
constraints.setColSpan(colSpan);
LOG.info("GridDropLocation.dropIntoGrid() constraints=" + constraints);
container.addComponent(c);
// Fill DropInfo
c.revalidate();
}
container.revalidate();
LOG.info("GridDropLocation.dropIntoGrid() done");
}
}