2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.uiDesigner
;
18 import com
.intellij
.uiDesigner
.core
.GridConstraints
;
19 import com
.intellij
.uiDesigner
.radComponents
.RadAbstractGridLayoutManager
;
20 import com
.intellij
.uiDesigner
.radComponents
.RadComponent
;
21 import com
.intellij
.uiDesigner
.radComponents
.RadContainer
;
22 import org
.jetbrains
.annotations
.NotNull
;
27 * @author Anton Katilin
28 * @author Vladimir Kondratyev
30 public final class GridChangeUtil
{
31 private GridChangeUtil() {
34 public static void splitColumn(final RadContainer grid
, final int columnIndex
) {
35 splitCell(grid
, columnIndex
, false);
38 public static void splitRow(final RadContainer grid
, final int rowIndex
) {
39 splitCell(grid
, rowIndex
, true);
42 public static boolean isColumnEmpty(final RadContainer grid
, final int columnIndex
) {
43 return canDeleteCell(grid
, columnIndex
, false) == CellStatus
.Empty
;
46 public static boolean isRowEmpty(final RadContainer grid
, final int rowIndex
) {
47 return canDeleteCell(grid
, rowIndex
, true) == CellStatus
.Empty
;
51 * @param cellIndex column or row index, depending on isRow parameter; must be in the range 0..grid.get{Row|Column}Count()-1
52 * @param isRow if true, row inserted, otherwise column
53 * @param isBefore if true, row/column will be inserted before row/column with given index, otherwise after
55 public static void insertRowOrColumn(final RadContainer grid
, final int cellIndex
, final boolean isRow
, final boolean isBefore
) {
56 check(grid
, isRow
, cellIndex
);
58 final RadAbstractGridLayoutManager oldLayout
= grid
.getGridLayoutManager();
60 int beforeIndex
= cellIndex
;
62 // beforeIndex can actually be equal to get{Row|Column}Count an case we add row after the last row/column
66 final LayoutManager newLayout
= oldLayout
.copyLayout(grid
.getLayout(), isRow ?
1 : 0, isRow ?
0 : 1);
68 for (int i
=grid
.getComponentCount() - 1; i
>= 0; i
--){
69 final GridConstraints constraints
= grid
.getComponent(i
).getConstraints();
70 final GridConstraints oldConstraints
= (GridConstraints
) constraints
.clone();
71 adjustConstraintsOnInsert(constraints
, isRow
, beforeIndex
, 1);
72 grid
.getComponent(i
).fireConstraintsChanged(oldConstraints
);
75 grid
.setLayout(newLayout
);
78 public static void adjustConstraintsOnInsert(final GridConstraints constraints
, final boolean isRow
, final int beforeIndex
,
80 if (constraints
.getCell(isRow
) >= beforeIndex
) {
81 addToCell(constraints
, isRow
, count
);
83 else if (isCellInsideComponent(constraints
, isRow
, beforeIndex
)) {
84 // component belongs to the cell being resized - increment component's span
85 addToSpan(constraints
, isRow
, count
);
90 * @param cellIndex column or row index, depending on isRow parameter; must be in the range 0..grid.get{Row|Column}Count()-1
91 * @param isRow if true, row is splitted, otherwise column
93 public static void splitCell(final RadContainer grid
, final int cellIndex
, final boolean isRow
) {
94 check(grid
, isRow
, cellIndex
);
96 int insertedCells
= grid
.getGridLayoutManager().insertGridCells(grid
, cellIndex
, isRow
, false, false);
98 for (int i
=grid
.getComponentCount() - 1; i
>= 0; i
--){
99 final RadComponent component
= grid
.getComponent(i
);
100 final GridConstraints constraints
= component
.getConstraints();
102 if (constraints
.getCell(isRow
) + constraints
.getSpan(isRow
) - 1 == cellIndex
) {
103 // component belongs to the cell being resized - increment component's span
104 GridConstraints oldConstraints
= (GridConstraints
)constraints
.clone();
105 constraints
.setSpan(isRow
, constraints
.getSpan(isRow
) + insertedCells
);
106 component
.fireConstraintsChanged(oldConstraints
);
111 public enum CellStatus
{
112 Empty
, Redundant
, CanShift
, Required
116 * @param cellIndex column or row index, depending on isRow parameter; must be in the range 0..grid.get{Row|Column}Count()-1
117 * @param isRow if true, row is deleted, otherwise column
118 * @return whether the specified column can be deleted
120 public static CellStatus
canDeleteCell(@NotNull final RadContainer grid
, final int cellIndex
, final boolean isRow
) {
121 check(grid
, isRow
, cellIndex
);
123 // Do not allow to delete the single row/column
124 if(isRow
&& grid
.getGridRowCount() <= grid
.getGridLayoutManager().getMinCellCount()) {
125 return CellStatus
.Required
;
127 else if(!isRow
&& grid
.getGridColumnCount() <= grid
.getGridLayoutManager().getMinCellCount()) {
128 return CellStatus
.Required
;
131 boolean haveComponents
= false;
132 boolean haveOrigins
= false;
133 boolean haveSingleSpan
= false;
134 for (int i
= 0; i
< grid
.getComponentCount(); i
++) {
135 final GridConstraints constraints
= grid
.getComponent(i
).getConstraints();
136 final int cell
= constraints
.getCell(isRow
);
137 final int span
= constraints
.getSpan(isRow
);
139 if (cellIndex
>= cell
&& cellIndex
< cell
+span
) {
140 haveComponents
= true;
141 if (cellIndex
== cell
) {
144 haveSingleSpan
= true;
150 return CellStatus
.Required
;
152 return CellStatus
.CanShift
;
154 return CellStatus
.Redundant
;
155 return CellStatus
.Empty
;
158 public static boolean canDeleteCells(final RadContainer grid
, final int[] cells
, final boolean row
) {
159 // for multiple cells, we can't determine if deleting all cells will have a correct result
160 for(int cell
: cells
) {
161 CellStatus status
= canDeleteCell(grid
, cell
, row
);
162 if (status
!= CellStatus
.Empty
) {
163 if (cells
.length
== 1 && status
== CellStatus
.Redundant
) {
173 * @param cellIndex column or row index, depending on isRow parameter; must be in the range 0..grid.get{Row|Column}Count()-1
174 * @param isRow if true, row is deleted, otherwise column
176 public static void deleteCell(final RadContainer grid
, final int cellIndex
, final boolean isRow
) {
177 check(grid
, isRow
, cellIndex
);
178 if (canDeleteCell(grid
, cellIndex
, isRow
) == CellStatus
.Required
) {
179 throw new IllegalArgumentException("cell cannot be deleted");
182 final RadAbstractGridLayoutManager oldLayout
= grid
.getGridLayoutManager();
184 final LayoutManager newLayout
= oldLayout
.copyLayout(grid
.getLayout(), isRow ?
-1 : 0, isRow ?
0 : -1);
186 for (int i
=grid
.getComponentCount() - 1; i
>= 0; i
--){
187 final GridConstraints constraints
= grid
.getComponent(i
).getConstraints();
188 final GridConstraints oldConstraints
= (GridConstraints
) constraints
.clone();
190 if (constraints
.getCell(isRow
) > cellIndex
) {
191 // component starts after the cell being deleted - move it
192 addToCell(constraints
, isRow
, -1);
194 else if (isCellInsideComponent(constraints
, isRow
, cellIndex
)) {
195 // component belongs to the cell being deleted - decrement component's span
196 addToSpan(constraints
, isRow
, -1);
198 grid
.getComponent(i
).fireConstraintsChanged(oldConstraints
);
201 grid
.setLayout(newLayout
);
205 private static boolean isCellInsideComponent(final GridConstraints constraints
, final boolean isRow
, final int cellIndex
) {
206 final int cell
= constraints
.getCell(isRow
);
207 final int span
= constraints
.getSpan(isRow
);
208 return cell
<= cellIndex
&& cellIndex
<= cell
+ span
- 1;
212 * check whether passed container is grid and cellIndex is in proper range
214 private static void check(@NotNull RadContainer grid
, final boolean isRow
, final int cellIndex
){
215 if (!grid
.getLayoutManager().isGrid()){
216 throw new IllegalArgumentException("container must be grid");
219 final int cellCount
= isRow ? grid
.getGridRowCount() : grid
.getGridColumnCount();
220 if (cellIndex
== 0 && cellCount
== 0) return;
221 if (cellIndex
< 0 || cellIndex
>= cellCount
) {
222 throw new IllegalArgumentException("invalid index: " + cellIndex
);
226 private static void addToCell(final GridConstraints constraints
, final boolean isRow
, final int delta
){
228 constraints
.setRow(constraints
.getRow() + delta
);
231 constraints
.setColumn(constraints
.getColumn() + delta
);
235 private static void addToSpan(final GridConstraints constraints
, final boolean isRow
, final int delta
){
237 constraints
.setRowSpan(constraints
.getRowSpan() + delta
);
240 constraints
.setColSpan(constraints
.getColSpan() + delta
);
244 public static void moveCells(final RadContainer container
, final boolean isRow
, final int[] cellsToMove
, int targetCell
) {
245 for(int i
=0; i
<cellsToMove
.length
; i
++) {
246 final int sourceCell
= cellsToMove
[i
];
247 moveCell(container
, isRow
, sourceCell
, targetCell
);
248 if (sourceCell
< targetCell
) {
249 for(int j
=i
+1; j
<cellsToMove
.length
; j
++) {
259 public static void moveCell(final RadContainer container
, final boolean isRow
, final int sourceCell
, int targetCell
) {
260 if (targetCell
== sourceCell
|| targetCell
== sourceCell
+1) return;
261 // if column moved to left - components inbetween move to right, and vice versa
262 int delta
= (sourceCell
> targetCell
) ?
1 : -1;
263 int startCell
= Math
.min(sourceCell
, targetCell
);
264 int endCell
= Math
.max(sourceCell
, targetCell
);
265 if (sourceCell
< targetCell
) targetCell
--;
266 for(RadComponent c
: container
.getComponents()) {
267 GridConstraints constraints
= c
.getConstraints();
268 GridConstraints oldConstraints
= (GridConstraints
) constraints
.clone();
269 final int aCell
= constraints
.getCell(isRow
);
270 if (aCell
== sourceCell
) {
271 constraints
.setCell(isRow
, targetCell
);
273 else if (aCell
>= startCell
&& aCell
< endCell
) {
274 constraints
.setCell(isRow
, aCell
+ delta
);
276 c
.fireConstraintsChanged(oldConstraints
);