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
.module
.Module
;
19 import com
.intellij
.uiDesigner
.FormEditingUtil
;
20 import com
.intellij
.uiDesigner
.StringDescriptorManager
;
21 import com
.intellij
.uiDesigner
.SwingProperties
;
22 import com
.intellij
.uiDesigner
.UIDesignerBundle
;
23 import com
.intellij
.uiDesigner
.core
.SupportCode
;
24 import com
.intellij
.uiDesigner
.designSurface
.GuiEditor
;
25 import com
.intellij
.uiDesigner
.lw
.*;
26 import com
.intellij
.uiDesigner
.quickFixes
.QuickFix
;
27 import com
.intellij
.uiDesigner
.radComponents
.RadComponent
;
28 import org
.jetbrains
.annotations
.NotNull
;
29 import org
.jetbrains
.annotations
.Nullable
;
32 import java
.util
.ArrayList
;
33 import java
.util
.HashMap
;
34 import java
.util
.List
;
39 public class DuplicateMnemonicInspection
extends BaseFormInspection
{
40 private static final ThreadLocal
<HashMap
<IRootContainer
, MnemonicMap
>> myContainerMnemonicMap
= new ThreadLocal
<HashMap
<IRootContainer
, MnemonicMap
>>() {
42 protected HashMap
<IRootContainer
, MnemonicMap
> initialValue() {
43 return new HashMap
<IRootContainer
, MnemonicMap
>();
47 public DuplicateMnemonicInspection() {
48 super("DuplicateMnemonic");
53 public String
getDisplayName() {
54 return UIDesignerBundle
.message("inspection.duplicate.mnemonics");
57 @Override public void startCheckForm(IRootContainer radRootContainer
) {
58 myContainerMnemonicMap
.get().put(radRootContainer
, new MnemonicMap());
61 @Override public void doneCheckForm(IRootContainer rootContainer
) {
62 myContainerMnemonicMap
.get().remove(rootContainer
);
65 protected void checkComponentProperties(Module module
, IComponent component
, FormErrorCollector collector
) {
66 SupportCode
.TextWithMnemonic twm
= getTextWithMnemonic(module
, component
);
68 checkTextWithMnemonic(module
, component
, twm
, collector
);
73 public static SupportCode
.TextWithMnemonic
getTextWithMnemonic(final Module module
, final IComponent component
) {
74 if (module
.isDisposed()) return null;
75 IProperty prop
= FormInspectionUtil
.findProperty(component
, SwingProperties
.TEXT
);
77 Object propValue
= prop
.getPropertyValue(component
);
78 if (propValue
instanceof StringDescriptor
) {
79 StringDescriptor descriptor
= (StringDescriptor
)propValue
;
81 if (component
instanceof RadComponent
) {
82 value
= StringDescriptorManager
.getInstance(module
).resolve((RadComponent
) component
, descriptor
);
85 value
= StringDescriptorManager
.getInstance(module
).resolve(descriptor
, null);
87 SupportCode
.TextWithMnemonic twm
= SupportCode
.parseText(value
);
88 if (twm
.myMnemonicIndex
>= 0 &&
89 (FormInspectionUtil
.isComponentClass(module
, component
, JLabel
.class) || FormInspectionUtil
.isComponentClass(module
, component
, AbstractButton
.class))) {
97 private void checkTextWithMnemonic(final Module module
,
98 final IComponent component
,
99 final SupportCode
.TextWithMnemonic twm
,
100 final FormErrorCollector collector
) {
101 IRootContainer root
= FormEditingUtil
.getRoot(component
);
102 MnemonicMap map
= myContainerMnemonicMap
.get().get(root
);
103 MnemonicKey key
= buildMnemonicKey(twm
, component
);
104 if (map
.containsKey(key
)) {
105 IProperty prop
= FormInspectionUtil
.findProperty(component
, SwingProperties
.TEXT
);
106 IComponent oldComponent
= map
.get(key
);
107 collector
.addError(getID(), component
, prop
,
108 UIDesignerBundle
.message("inspection.duplicate.mnemonics.message",
109 FormInspectionUtil
.getText(module
, oldComponent
),
110 FormInspectionUtil
.getText(module
, component
)),
111 new EditorQuickFixProvider() {
112 public QuickFix
createQuickFix(GuiEditor editor
, RadComponent component
) {
113 return new AssignMnemonicFix(editor
, component
,
114 UIDesignerBundle
.message("inspection.duplicate.mnemonics.quickfix"));
119 map
.put(key
, component
);
123 private static MnemonicKey
buildMnemonicKey(final SupportCode
.TextWithMnemonic twm
, final IComponent component
) {
124 List
<Integer
> exclusiveContainerStack
= new ArrayList
<Integer
>();
125 IContainer parent
= component
.getParentContainer();
126 IComponent child
= component
;
127 while(parent
!= null) {
128 if (parent
.areChildrenExclusive()) {
129 exclusiveContainerStack
.add(0, parent
.indexOfComponent(child
));
132 parent
= parent
.getParentContainer();
134 return new MnemonicKey(twm
.getMnemonicChar(), exclusiveContainerStack
);
137 private static class MnemonicKey
{
138 private final char myMnemonicChar
;
139 private final List
<Integer
> myExclusiveContainerStack
;
141 public MnemonicKey(final char mnemonicChar
, final List
<Integer
> exclusiveContainerStack
) {
142 myMnemonicChar
= mnemonicChar
;
143 myExclusiveContainerStack
= exclusiveContainerStack
;
146 public boolean equals(final Object o
) {
147 if (this == o
) return true;
148 if (o
== null || getClass() != o
.getClass()) return false;
150 final MnemonicKey that
= (MnemonicKey
)o
;
152 if (myMnemonicChar
!= that
.myMnemonicChar
) return false;
153 if (!myExclusiveContainerStack
.equals(that
.myExclusiveContainerStack
)) return false;
158 public int hashCode() {
160 result
= (int)myMnemonicChar
;
161 result
= 31 * result
+ myExclusiveContainerStack
.hashCode();
166 private static class MnemonicMap
extends HashMap
<MnemonicKey
, IComponent
> {