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
.inspections
;
18 import com
.intellij
.openapi
.diagnostic
.Logger
;
19 import com
.intellij
.openapi
.module
.Module
;
20 import com
.intellij
.uiDesigner
.FormEditingUtil
;
21 import com
.intellij
.uiDesigner
.UIDesignerBundle
;
22 import com
.intellij
.uiDesigner
.actions
.GroupButtonsAction
;
23 import com
.intellij
.uiDesigner
.core
.GridConstraints
;
24 import com
.intellij
.uiDesigner
.designSurface
.GuiEditor
;
25 import com
.intellij
.uiDesigner
.lw
.IComponent
;
26 import com
.intellij
.uiDesigner
.lw
.IContainer
;
27 import com
.intellij
.uiDesigner
.lw
.IRootContainer
;
28 import com
.intellij
.uiDesigner
.quickFixes
.QuickFix
;
29 import com
.intellij
.uiDesigner
.radComponents
.RadButtonGroup
;
30 import com
.intellij
.uiDesigner
.radComponents
.RadComponent
;
31 import com
.intellij
.uiDesigner
.radComponents
.RadContainer
;
32 import com
.intellij
.uiDesigner
.radComponents
.RadRootContainer
;
33 import org
.jetbrains
.annotations
.NotNull
;
36 import java
.util
.ArrayList
;
37 import java
.util
.Collections
;
38 import java
.util
.Comparator
;
43 public class NoButtonGroupInspection
extends BaseFormInspection
{
44 private static final Logger LOG
= Logger
.getInstance("#com.intellij.uiDesigner.inspections.NoButtonGroupInspection");
46 public NoButtonGroupInspection() {
47 super("NoButtonGroup");
51 @Override public String
getDisplayName() {
52 return UIDesignerBundle
.message("inspection.no.button.group");
55 protected void checkComponentProperties(Module module
, IComponent component
, FormErrorCollector collector
) {
56 if (FormInspectionUtil
.isComponentClass(module
, component
, JRadioButton
.class)) {
57 final IRootContainer root
= FormEditingUtil
.getRoot(component
);
58 if (root
== null) return;
59 if (root
.getButtonGroupName(component
) == null) {
60 EditorQuickFixProvider quickFixProvider
= null;
61 IContainer parent
= component
.getParentContainer();
62 for(int i
=0; i
<parent
.getComponentCount(); i
++) {
63 IComponent child
= parent
.getComponent(i
);
64 if (child
!= component
&&
65 FormInspectionUtil
.isComponentClass(module
, child
, JRadioButton
.class)) {
66 final GridConstraints c1
= component
.getConstraints();
67 final GridConstraints c2
= child
.getConstraints();
68 if (areCellsAdjacent(parent
, c1
, c2
)) {
69 final String groupName
= root
.getButtonGroupName(child
);
70 if (groupName
== null) {
71 quickFixProvider
= new EditorQuickFixProvider() {
72 public QuickFix
createQuickFix(GuiEditor editor
, RadComponent component
) {
73 return new CreateGroupQuickFix(editor
, component
, c1
.getColumn() == c2
.getColumn());
79 quickFixProvider
= new EditorQuickFixProvider() {
80 public QuickFix
createQuickFix(GuiEditor editor
, RadComponent component
) {
81 return new AddToGroupQuickFix(editor
, component
, groupName
);
88 collector
.addError(getID(), component
, null, UIDesignerBundle
.message("inspection.no.button.group.error"), quickFixProvider
);
93 private static boolean areCellsAdjacent(final IContainer parent
, final GridConstraints c1
, final GridConstraints c2
) {
94 if (parent
instanceof RadContainer
) {
95 final RadContainer container
= (RadContainer
)parent
;
96 if (!container
.getLayoutManager().isGrid()) return false;
97 if (c1
.getRow() == c2
.getRow()) {
98 return FormEditingUtil
.prevCol(container
, c1
.getColumn()) == c2
.getColumn() ||
99 FormEditingUtil
.nextCol(container
, c1
.getColumn()) == c2
.getColumn();
101 if (c1
.getColumn() == c2
.getColumn()) {
102 return FormEditingUtil
.prevRow(container
, c1
.getRow()) == c2
.getRow() ||
103 FormEditingUtil
.nextRow(container
, c1
.getRow()) == c2
.getRow();
106 return (c1
.getRow() == c2
.getRow() && Math
.abs(c1
.getColumn() - c2
.getColumn()) == 1) ||
107 (c1
.getColumn() == c2
.getColumn() && Math
.abs(c1
.getRow() - c2
.getRow()) == 1);
110 private static class CreateGroupQuickFix
extends QuickFix
{
111 private final boolean myVerticalGroup
;
113 public CreateGroupQuickFix(final GuiEditor editor
, final RadComponent component
, boolean verticalGroup
) {
114 super(editor
, UIDesignerBundle
.message("inspection.no.button.group.quickfix.create"), component
);
115 myVerticalGroup
= verticalGroup
;
119 RadContainer parent
= myComponent
.getParent();
120 ArrayList
<RadComponent
> buttonsToGroup
= new ArrayList
<RadComponent
>();
121 for(RadComponent component
: parent
.getComponents()) {
122 if (FormInspectionUtil
.isComponentClass(myComponent
.getModule(), component
, JRadioButton
.class)) {
123 if (component
.getConstraints().getCell(!myVerticalGroup
) == myComponent
.getConstraints().getCell(!myVerticalGroup
))
124 buttonsToGroup
.add(component
);
127 Collections
.sort(buttonsToGroup
, new Comparator
<RadComponent
>() {
128 public int compare(final RadComponent o1
, final RadComponent o2
) {
129 if (myVerticalGroup
) {
130 return o1
.getConstraints().getRow() - o2
.getConstraints().getRow();
132 return o1
.getConstraints().getColumn() - o2
.getConstraints().getColumn();
136 // ensure that selected radio buttons are in adjacent cells, and exclude from grouping
137 // buttons separated by empty cells or other controls
138 int index
=buttonsToGroup
.indexOf(myComponent
);
139 LOG
.assertTrue(index
>= 0);
140 int expectCell
= myComponent
.getConstraints().getCell(myVerticalGroup
);
141 for(int i
=index
-1; i
>= 0; i
--) {
142 expectCell
= FormEditingUtil
.adjustForGap(parent
, expectCell
-1, myVerticalGroup
, -1);
143 if (buttonsToGroup
.get(i
).getConstraints().getCell(myVerticalGroup
) != expectCell
) {
144 removeRange(buttonsToGroup
, 0, i
);
148 expectCell
= myComponent
.getConstraints().getCell(myVerticalGroup
);
149 for(int i
=index
+1; i
<buttonsToGroup
.size(); i
++) {
150 expectCell
= FormEditingUtil
.adjustForGap(parent
, expectCell
+1, myVerticalGroup
, 1);
151 if (buttonsToGroup
.get(i
).getConstraints().getCell(myVerticalGroup
) != expectCell
) {
152 removeRange(buttonsToGroup
, i
, buttonsToGroup
.size()-1);
157 LOG
.assertTrue(buttonsToGroup
.size() > 1);
158 GroupButtonsAction
.groupButtons(myEditor
, buttonsToGroup
);
161 private static void removeRange(final ArrayList
<RadComponent
> buttonsToGroup
, final int minIndex
, final int maxIndex
) {
162 for(int index
=maxIndex
; index
>= minIndex
; index
--) {
163 buttonsToGroup
.remove(index
);
168 private static class AddToGroupQuickFix
extends QuickFix
{
169 private final String myGroupName
;
171 public AddToGroupQuickFix(final GuiEditor editor
, final RadComponent component
, final String groupName
) {
172 super(editor
, UIDesignerBundle
.message("inspection.no.button.group.quickfix.add", groupName
), component
);
173 myGroupName
= groupName
;
177 RadRootContainer root
= (RadRootContainer
) FormEditingUtil
.getRoot(myComponent
);
178 if (root
== null) return;
179 for(RadButtonGroup group
: root
.getButtonGroups()) {
180 if (group
.getName().equals(myGroupName
)) {
181 root
.setGroupForComponent(myComponent
, group
);
185 myEditor
.refreshAndSave(true);