| /* |
| * 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"); |
| } |
| } |