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