3d47784530c26dde1486343d93f6e65c5a3a2dab
[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.psi.PsiDocumentManager;
28 import com.intellij.psi.xml.XmlFile;
29 import com.intellij.ui.BooleanTableCellEditor;
30 import com.intellij.ui.UserActivityListener;
31 import com.intellij.ui.UserActivityWatcher;
32 import com.intellij.util.Function;
33 import com.intellij.util.ReflectionUtil;
34 import com.intellij.util.SmartList;
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 import java.util.List;
49
50 /**
51  * @author peter
52  */
53 public class DomUIFactoryImpl extends DomUIFactory {
54   private final ClassMap<Function<DomWrapper<String>, BaseControl>> myCustomControlCreators = new ClassMap<Function<DomWrapper<String>, BaseControl>>();
55   private final ClassMap<Function<DomElement, TableCellEditor>> myCustomCellEditorCreators = new ClassMap<Function<DomElement, TableCellEditor>>();
56
57   public DomUIFactoryImpl() {
58     final Function<DomElement, TableCellEditor> booleanCreator = new Function<DomElement, TableCellEditor>() {
59       public TableCellEditor fun(final DomElement domElement) {
60         return new BooleanTableCellEditor();
61       }
62     };
63     registerCustomCellEditor(Boolean.class, booleanCreator);
64     registerCustomCellEditor(boolean.class, booleanCreator);
65     registerCustomCellEditor(String.class, new Function<DomElement, TableCellEditor>() {
66       public TableCellEditor fun(final DomElement domElement) {
67         return new DefaultCellEditor(removeBorder(new JTextField()));
68       }
69     });
70   }
71
72   protected TableCellEditor createCellEditor(DomElement element, Class type) {
73     if (Enum.class.isAssignableFrom(type)) {
74       return new ComboTableCellEditor((Class<? extends Enum>)type, false);
75     }
76
77     final Function<DomElement, TableCellEditor> function = myCustomCellEditorCreators.get(type);
78     assert function != null : "Type not supported: " + type;
79     return function.fun(element);
80   }
81
82   public final UserActivityWatcher createEditorAwareUserActivityWatcher() {
83     return new UserActivityWatcher() {
84       private final DocumentAdapter myListener = new DocumentAdapter() {
85         public void documentChanged(DocumentEvent e) {
86           fireUIChanged();
87         }
88       };
89
90       protected void processComponent(final Component component) {
91         super.processComponent(component);
92         if (component instanceof EditorComponentImpl) {
93           ((EditorComponentImpl)component).getEditor().getDocument().addDocumentListener(myListener);
94         }
95       }
96
97       protected void unprocessComponent(final Component component) {
98         super.unprocessComponent(component);
99         if (component instanceof EditorComponentImpl) {
100           ((EditorComponentImpl)component).getEditor().getDocument().removeDocumentListener(myListener);
101         }
102       }
103     };
104   }
105
106   public void setupErrorOutdatingUserActivityWatcher(final CommittablePanel panel, final DomElement... elements) {
107     final UserActivityWatcher userActivityWatcher = createEditorAwareUserActivityWatcher();
108     userActivityWatcher.addUserActivityListener(new UserActivityListener() {
109       private boolean isProcessingChange;
110
111       public void stateChanged() {
112         if (isProcessingChange) return;
113         isProcessingChange = true;
114         try {
115           for (final DomElement element : elements) {
116             DomElementAnnotationsManagerImpl.outdateProblemHolder(element);
117           }
118           CommittableUtil.updateHighlighting(panel);
119         }
120         finally {
121           isProcessingChange = false;
122         }
123       }
124     }, panel);
125     userActivityWatcher.register(panel.getComponent());
126   }
127
128   @Nullable
129   public BaseControl createCustomControl(final Type type, DomWrapper<String> wrapper, final boolean commitOnEveryChange) {
130     final Function<DomWrapper<String>, BaseControl> factory = myCustomControlCreators.get(ReflectionUtil.getRawType(type));
131     return factory == null ? null : factory.fun(wrapper);
132   }
133
134   public CaptionComponent addErrorPanel(CaptionComponent captionComponent, DomElement... elements) {
135     captionComponent.initErrorPanel(new DomElementsErrorPanel(elements));
136     return captionComponent;
137   }
138
139   public BackgroundEditorHighlighter createDomHighlighter(final Project project, final PerspectiveFileEditor editor, final DomElement element) {
140     return new BackgroundEditorHighlighter() {
141       @NotNull
142       public HighlightingPass[] createPassesForEditor() {
143         if (!element.isValid()) return HighlightingPass.EMPTY_ARRAY;
144         
145         final XmlFile psiFile = DomUtil.getFile(element);
146
147         final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project);
148         final Document document = psiDocumentManager.getDocument(psiFile);
149         if (document == null) return HighlightingPass.EMPTY_ARRAY;
150
151         editor.commit();
152
153         psiDocumentManager.commitAllDocuments();
154
155         final List<HighlightingPass> result = new SmartList<HighlightingPass>();
156         result.add(new GeneralHighlightingPass(project, psiFile, document, 0, document.getTextLength(), true));
157         result.add(new LocalInspectionsPass(psiFile, document, 0, document.getTextLength()));
158         return result.toArray(new HighlightingPass[result.size()]);
159       }
160
161       @NotNull
162       public HighlightingPass[] createPassesForVisibleArea() {
163         return createPassesForEditor();
164       }
165     };
166
167   }
168
169   public void updateHighlighting(final EditorTextFieldControl control) {
170     
171   }
172
173   public BaseControl createTextControl(DomWrapper<String> wrapper, final boolean commitOnEveryChange) {
174     return new TextControl(wrapper, commitOnEveryChange);
175   }
176
177   public void registerCustomControl(Class aClass, Function<DomWrapper<String>, BaseControl> creator) {
178     myCustomControlCreators.put(aClass, creator);
179   }
180
181   public void registerCustomCellEditor(final Class aClass, final Function<DomElement, TableCellEditor> creator) {
182     myCustomCellEditorCreators.put(aClass, creator);
183   }
184
185   private static <T extends JComponent> T removeBorder(final T component) {
186     component.setBorder(new EmptyBorder(0, 0, 0, 0));
187     return component;
188   }
189 }