cleanup
[idea/community.git] / xml / dom-impl / src / com / intellij / util / xml / ui / DomUIFactoryImpl.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package com.intellij.util.xml.ui;
17
18 import com.intellij.codeHighlighting.BackgroundEditorHighlighter;
19 import com.intellij.codeHighlighting.HighlightingPass;
20 import com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass;
21 import com.intellij.codeInsight.daemon.impl.LocalInspectionsPass;
22 import com.intellij.openapi.editor.Document;
23 import com.intellij.openapi.editor.event.DocumentAdapter;
24 import com.intellij.openapi.editor.event.DocumentEvent;
25 import com.intellij.openapi.editor.impl.EditorComponentImpl;
26 import com.intellij.openapi.project.Project;
27 import com.intellij.openapi.util.TextRange;
28 import com.intellij.psi.PsiDocumentManager;
29 import com.intellij.psi.xml.XmlFile;
30 import com.intellij.ui.BooleanTableCellEditor;
31 import com.intellij.ui.UserActivityListener;
32 import com.intellij.ui.UserActivityWatcher;
33 import com.intellij.util.Function;
34 import com.intellij.util.ReflectionUtil;
35 import com.intellij.util.containers.ClassMap;
36 import com.intellij.util.xml.DomElement;
37 import com.intellij.util.xml.DomUtil;
38 import com.intellij.util.xml.highlighting.DomElementAnnotationsManagerImpl;
39 import com.intellij.util.xml.highlighting.DomElementsErrorPanel;
40 import org.jetbrains.annotations.NotNull;
41 import org.jetbrains.annotations.Nullable;
42
43 import javax.swing.*;
44 import javax.swing.border.EmptyBorder;
45 import javax.swing.table.TableCellEditor;
46 import java.awt.*;
47 import java.lang.reflect.Type;
48
49 /**
50  * @author peter
51  */
52 public class DomUIFactoryImpl extends DomUIFactory {
53   private final ClassMap<Function<DomWrapper<String>, BaseControl>> myCustomControlCreators = new ClassMap<Function<DomWrapper<String>, BaseControl>>();
54   private final ClassMap<Function<DomElement, TableCellEditor>> myCustomCellEditorCreators = new ClassMap<Function<DomElement, TableCellEditor>>();
55
56   public DomUIFactoryImpl() {
57     final Function<DomElement, TableCellEditor> booleanCreator = new Function<DomElement, TableCellEditor>() {
58       public TableCellEditor fun(final DomElement domElement) {
59         return new BooleanTableCellEditor();
60       }
61     };
62     registerCustomCellEditor(Boolean.class, booleanCreator);
63     registerCustomCellEditor(boolean.class, booleanCreator);
64     registerCustomCellEditor(String.class, new Function<DomElement, TableCellEditor>() {
65       public TableCellEditor fun(final DomElement domElement) {
66         return new DefaultCellEditor(removeBorder(new JTextField()));
67       }
68     });
69   }
70
71   protected TableCellEditor createCellEditor(DomElement element, Class type) {
72     if (Enum.class.isAssignableFrom(type)) {
73       return new ComboTableCellEditor((Class<? extends Enum>)type, false);
74     }
75
76     final Function<DomElement, TableCellEditor> function = myCustomCellEditorCreators.get(type);
77     assert function != null : "Type not supported: " + type;
78     return function.fun(element);
79   }
80
81   public final UserActivityWatcher createEditorAwareUserActivityWatcher() {
82     return new UserActivityWatcher() {
83       private final DocumentAdapter myListener = new DocumentAdapter() {
84         public void documentChanged(DocumentEvent e) {
85           fireUIChanged();
86         }
87       };
88
89       protected void processComponent(final Component component) {
90         super.processComponent(component);
91         if (component instanceof EditorComponentImpl) {
92           ((EditorComponentImpl)component).getEditor().getDocument().addDocumentListener(myListener);
93         }
94       }
95
96       protected void unprocessComponent(final Component component) {
97         super.unprocessComponent(component);
98         if (component instanceof EditorComponentImpl) {
99           ((EditorComponentImpl)component).getEditor().getDocument().removeDocumentListener(myListener);
100         }
101       }
102     };
103   }
104
105   public void setupErrorOutdatingUserActivityWatcher(final CommittablePanel panel, final DomElement... elements) {
106     final UserActivityWatcher userActivityWatcher = createEditorAwareUserActivityWatcher();
107     userActivityWatcher.addUserActivityListener(new UserActivityListener() {
108       private boolean isProcessingChange;
109
110       public void stateChanged() {
111         if (isProcessingChange) return;
112         isProcessingChange = true;
113         try {
114           for (final DomElement element : elements) {
115             DomElementAnnotationsManagerImpl.outdateProblemHolder(element);
116           }
117           CommittableUtil.updateHighlighting(panel);
118         }
119         finally {
120           isProcessingChange = false;
121         }
122       }
123     }, panel);
124     userActivityWatcher.register(panel.getComponent());
125   }
126
127   @Nullable
128   public BaseControl createCustomControl(final Type type, DomWrapper<String> wrapper, final boolean commitOnEveryChange) {
129     final Function<DomWrapper<String>, BaseControl> factory = myCustomControlCreators.get(ReflectionUtil.getRawType(type));
130     return factory == null ? null : factory.fun(wrapper);
131   }
132
133   public CaptionComponent addErrorPanel(CaptionComponent captionComponent, DomElement... elements) {
134     captionComponent.initErrorPanel(new DomElementsErrorPanel(elements));
135     return captionComponent;
136   }
137
138   public BackgroundEditorHighlighter createDomHighlighter(final Project project, final PerspectiveFileEditor editor, final DomElement element) {
139     return new BackgroundEditorHighlighter() {
140       @NotNull
141       public HighlightingPass[] createPassesForEditor() {
142         if (!element.isValid()) return HighlightingPass.EMPTY_ARRAY;
143         
144         final XmlFile psiFile = DomUtil.getFile(element);
145
146         final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project);
147         final Document document = psiDocumentManager.getDocument(psiFile);
148         if (document == null) return HighlightingPass.EMPTY_ARRAY;
149
150         editor.commit();
151
152         psiDocumentManager.commitAllDocuments();
153
154         GeneralHighlightingPass ghp = new GeneralHighlightingPass(project, psiFile, document, 0, document.getTextLength(), true, new TextRange(0, 0));
155         LocalInspectionsPass lip = new LocalInspectionsPass(psiFile, document, 0, document.getTextLength());
156         return new HighlightingPass[]{ghp, lip};
157       }
158
159       @NotNull
160       public HighlightingPass[] createPassesForVisibleArea() {
161         return createPassesForEditor();
162       }
163     };
164
165   }
166
167   public void updateHighlighting(final EditorTextFieldControl control) {
168     
169   }
170
171   public BaseControl createTextControl(DomWrapper<String> wrapper, final boolean commitOnEveryChange) {
172     return new TextControl(wrapper, commitOnEveryChange);
173   }
174
175   public void registerCustomControl(Class aClass, Function<DomWrapper<String>, BaseControl> creator) {
176     myCustomControlCreators.put(aClass, creator);
177   }
178
179   public void registerCustomCellEditor(final Class aClass, final Function<DomElement, TableCellEditor> creator) {
180     myCustomCellEditorCreators.put(aClass, creator);
181   }
182
183   private static <T extends JComponent> T removeBorder(final T component) {
184     component.setBorder(new EmptyBorder(0, 0, 0, 0));
185     return component;
186   }
187 }