blob: fd431be7061ce0e6873c9aeb142e785693ef9090 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.util.xml.ui;
import com.intellij.codeHighlighting.BackgroundEditorHighlighter;
import com.intellij.codeHighlighting.HighlightingPass;
import com.intellij.codeInsight.daemon.impl.DefaultHighlightInfoProcessor;
import com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass;
import com.intellij.codeInsight.daemon.impl.HighlightInfoProcessor;
import com.intellij.codeInsight.daemon.impl.LocalInspectionsPass;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.impl.EditorComponentImpl;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ProperTextRange;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.xml.XmlFile;
import com.intellij.ui.BooleanTableCellEditor;
import com.intellij.ui.UserActivityListener;
import com.intellij.ui.UserActivityWatcher;
import com.intellij.util.Consumer;
import com.intellij.util.Function;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.containers.ClassMap;
import com.intellij.util.xml.DomElement;
import com.intellij.util.xml.DomUtil;
import com.intellij.util.xml.highlighting.DomElementAnnotationsManagerImpl;
import com.intellij.util.xml.highlighting.DomElementsErrorPanel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.table.TableCellEditor;
import java.awt.*;
import java.lang.reflect.Type;
/**
* @author peter
*/
public class DomUIFactoryImpl extends DomUIFactory {
private final ClassMap<Function<DomWrapper<String>, BaseControl>> myCustomControlCreators = new ClassMap<Function<DomWrapper<String>, BaseControl>>();
private final ClassMap<Function<DomElement, TableCellEditor>> myCustomCellEditorCreators = new ClassMap<Function<DomElement, TableCellEditor>>();
public DomUIFactoryImpl() {
final Function<DomElement, TableCellEditor> booleanCreator = new Function<DomElement, TableCellEditor>() {
@Override
public TableCellEditor fun(final DomElement domElement) {
return new BooleanTableCellEditor();
}
};
registerCustomCellEditor(Boolean.class, booleanCreator);
registerCustomCellEditor(boolean.class, booleanCreator);
registerCustomCellEditor(String.class, new Function<DomElement, TableCellEditor>() {
@Override
public TableCellEditor fun(final DomElement domElement) {
return new DefaultCellEditor(removeBorder(new JTextField()));
}
});
Consumer<DomUIFactory>[] extensions = Extensions.getExtensions(EXTENSION_POINT_NAME);
for (Consumer<DomUIFactory> extension : extensions) {
extension.consume(this);
}
}
@Override
protected TableCellEditor createCellEditor(DomElement element, Class type) {
if (Enum.class.isAssignableFrom(type)) {
return new ComboTableCellEditor((Class<? extends Enum>)type, false);
}
final Function<DomElement, TableCellEditor> function = myCustomCellEditorCreators.get(type);
assert function != null : "Type not supported: " + type;
return function.fun(element);
}
@Override
public final UserActivityWatcher createEditorAwareUserActivityWatcher() {
return new UserActivityWatcher() {
private final DocumentAdapter myListener = new DocumentAdapter() {
@Override
public void documentChanged(DocumentEvent e) {
fireUIChanged();
}
};
@Override
protected void processComponent(final Component component) {
super.processComponent(component);
if (component instanceof EditorComponentImpl) {
((EditorComponentImpl)component).getEditor().getDocument().addDocumentListener(myListener);
}
}
@Override
protected void unprocessComponent(final Component component) {
super.unprocessComponent(component);
if (component instanceof EditorComponentImpl) {
((EditorComponentImpl)component).getEditor().getDocument().removeDocumentListener(myListener);
}
}
};
}
@Override
public void setupErrorOutdatingUserActivityWatcher(final CommittablePanel panel, final DomElement... elements) {
final UserActivityWatcher userActivityWatcher = createEditorAwareUserActivityWatcher();
userActivityWatcher.addUserActivityListener(new UserActivityListener() {
private boolean isProcessingChange;
@Override
public void stateChanged() {
if (isProcessingChange) return;
isProcessingChange = true;
try {
for (final DomElement element : elements) {
DomElementAnnotationsManagerImpl.outdateProblemHolder(element);
}
CommittableUtil.updateHighlighting(panel);
}
finally {
isProcessingChange = false;
}
}
}, panel);
userActivityWatcher.register(panel.getComponent());
}
@Override
@Nullable
public BaseControl createCustomControl(final Type type, DomWrapper<String> wrapper, final boolean commitOnEveryChange) {
final Function<DomWrapper<String>, BaseControl> factory = myCustomControlCreators.get(ReflectionUtil.getRawType(type));
return factory == null ? null : factory.fun(wrapper);
}
@Override
public CaptionComponent addErrorPanel(CaptionComponent captionComponent, DomElement... elements) {
captionComponent.initErrorPanel(new DomElementsErrorPanel(elements));
return captionComponent;
}
@Override
public BackgroundEditorHighlighter createDomHighlighter(final Project project, final PerspectiveFileEditor editor, final DomElement element) {
return new BackgroundEditorHighlighter() {
@Override
@NotNull
public HighlightingPass[] createPassesForEditor() {
if (!element.isValid()) return HighlightingPass.EMPTY_ARRAY;
final XmlFile psiFile = DomUtil.getFile(element);
final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project);
final Document document = psiDocumentManager.getDocument(psiFile);
if (document == null) return HighlightingPass.EMPTY_ARRAY;
editor.commit();
psiDocumentManager.commitAllDocuments();
GeneralHighlightingPass ghp = new GeneralHighlightingPass(project, psiFile, document, 0, document.getTextLength(),
true, new ProperTextRange(0, document.getTextLength()), null, new DefaultHighlightInfoProcessor());
LocalInspectionsPass lip = new LocalInspectionsPass(psiFile, document, 0,
document.getTextLength(), LocalInspectionsPass.EMPTY_PRIORITY_RANGE, true,
HighlightInfoProcessor.getEmpty());
return new HighlightingPass[]{ghp, lip};
}
@Override
@NotNull
public HighlightingPass[] createPassesForVisibleArea() {
return createPassesForEditor();
}
};
}
@Override
public BaseControl createTextControl(DomWrapper<String> wrapper, final boolean commitOnEveryChange) {
return new TextControl(wrapper, commitOnEveryChange);
}
@Override
public void registerCustomControl(@NotNull Class aClass, Function<DomWrapper<String>, BaseControl> creator) {
myCustomControlCreators.put(aClass, creator);
}
@Override
public void registerCustomCellEditor(@NotNull final Class aClass, final Function<DomElement, TableCellEditor> creator) {
myCustomCellEditorCreators.put(aClass, creator);
}
private static <T extends JComponent> T removeBorder(final T component) {
component.setBorder(new EmptyBorder(0, 0, 0, 0));
return component;
}
}