blob: 769296b0e7317d3c9565464263f5ad2732d4a833 [file] [log] [blame]
/*
* Copyright 2000-2013 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.ui;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.CaretModel;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.event.DocumentListener;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.TextComponentAccessor;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.MacUIUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
/**
* @author max
*/
// TODO[pegov]: should extend ComboBox not JComboBox!
public class EditorComboBox extends JComboBox implements DocumentListener {
public static TextComponentAccessor<EditorComboBox> COMPONENT_ACCESSOR = new TextComponentAccessor<EditorComboBox>() {
@Override
public String getText(EditorComboBox component) {
return component.getText();
}
@Override
public void setText(EditorComboBox component, @NotNull String text) {
component.setText(text);
}
};
private static final Logger LOG = Logger.getInstance("#com.intellij.ui.EditorTextField");
private Document myDocument;
private final Project myProject;
private EditorTextField myEditorField = null;
private final List<DocumentListener> myDocumentListeners = ContainerUtil.createLockFreeCopyOnWriteList();
private boolean myIsListenerInstalled = false;
private boolean myInheritSwingFont = true;
private final FileType myFileType;
private final boolean myIsViewer;
public EditorComboBox(String text) {
this(EditorFactory.getInstance().createDocument(text), null, FileTypes.PLAIN_TEXT);
}
public EditorComboBox(String text, Project project, FileType fileType) {
this(EditorFactory.getInstance().createDocument(text), project, fileType, false);
}
public EditorComboBox(Document document, Project project, FileType fileType) {
this(document, project, fileType, false);
}
public EditorComboBox(Document document, Project project, FileType fileType, boolean isViewer) {
myFileType = fileType;
myIsViewer = isViewer;
setDocument(document);
myProject = project;
enableEvents(AWTEvent.KEY_EVENT_MASK);
addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
final Editor editor = myEditorField != null ? myEditorField.getEditor() : null;
if (editor != null) {
editor.getSelectionModel().removeSelection();
}
}
});
setHistory(new String[]{""});
setEditable(true);
}
public void setFontInheritedFromLAF(boolean b) {
myInheritSwingFont = b;
setDocument(myDocument); // reinit editor.
}
public String getText() {
return myDocument.getText();
}
public void addDocumentListener(DocumentListener listener) {
myDocumentListeners.add(listener);
installDocumentListener();
}
public void removeDocumentListener(DocumentListener listener) {
myDocumentListeners.remove(listener);
uninstallDocumentListener(false);
}
@Override
public void beforeDocumentChange(DocumentEvent event) {
for (DocumentListener documentListener : myDocumentListeners) {
documentListener.beforeDocumentChange(event);
}
}
@Override
public void documentChanged(DocumentEvent event) {
for (DocumentListener documentListener : myDocumentListeners) {
documentListener.documentChanged(event);
}
}
@Override
public void paint(Graphics g) {
super.paint(g);
MacUIUtil.drawComboboxFocusRing(this, g);
}
public Project getProject() {
return myProject;
}
public Document getDocument() {
return myDocument;
}
public void setDocument(Document document) {
if (myDocument != null) {
uninstallDocumentListener(true);
}
myDocument = document;
installDocumentListener();
if (myEditorField == null) return;
myEditorField.setDocument(document);
}
private void installDocumentListener() {
if (myDocument != null && !myDocumentListeners.isEmpty() && !myIsListenerInstalled) {
myIsListenerInstalled = true;
myDocument.addDocumentListener(this);
}
}
private void uninstallDocumentListener(boolean force) {
if (myDocument != null && myIsListenerInstalled && (force || myDocumentListeners.isEmpty())) {
myIsListenerInstalled = false;
myDocument.removeDocumentListener(this);
}
}
public void setText(final String text) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
CommandProcessor.getInstance().executeCommand(getProject(), new Runnable() {
@Override
public void run() {
myDocument.replaceString(0, myDocument.getTextLength(), text);
if (myEditorField != null && myEditorField.getEditor() != null) {
myEditorField.getCaretModel().moveToOffset(myDocument.getTextLength());
}
}
}, null, myDocument);
}
});
}
public void removeSelection() {
if (myEditorField != null) {
final Editor editor = myEditorField.getEditor();
if (editor != null) {
editor.getSelectionModel().removeSelection();
}
}
else {
}
}
public CaretModel getCaretModel() {
return myEditorField.getCaretModel();
}
public void setHistory(final String[] history) {
setModel(new DefaultComboBoxModel(history));
}
public void prependItem(String item) {
ArrayList<Object> objects = new ArrayList<Object>();
objects.add(item);
int count = getItemCount();
for (int i = 0; i < count; i++) {
final Object itemAt = getItemAt(i);
if (!item.equals(itemAt)) {
objects.add(itemAt);
}
}
setModel(new DefaultComboBoxModel(ArrayUtil.toObjectArray(objects)));
}
public void appendItem(String item) {
ArrayList<Object> objects = new ArrayList<Object>();
int count = getItemCount();
for (int i = 0; i < count; i++) {
objects.add(getItemAt(i));
}
if (!objects.contains(item)) {
objects.add(item);
}
setModel(new DefaultComboBoxModel(ArrayUtil.toObjectArray(objects)));
}
private class MyEditor implements ComboBoxEditor {
@Override
public void addActionListener(ActionListener l) {
}
@Override
public Component getEditorComponent() {
return myEditorField;
}
@Override
public Object getItem() {
return myDocument.getText();
}
@Override
public void removeActionListener(ActionListener l) {
}
@Override
public void selectAll() {
if (myEditorField != null) {
final Editor editor = myEditorField.getEditor();
if (editor != null) {
editor.getSelectionModel().setSelection(0, myDocument.getTextLength());
}
}
}
@Override
public void setItem(Object anObject) {
if (anObject != null) {
EditorComboBox.this.setText((String)anObject);
} else {
EditorComboBox.this.setText("");
}
}
}
@Override
public void addNotify() {
releaseEditor();
setEditor();
super.addNotify();
if (UIUtil.isUnderDarcula() || UIUtil.isUnderIntelliJLaF()) {
final JScrollPane scrollPane = UIUtil.findComponentOfType(myEditorField, JScrollPane.class);
if (scrollPane != null) {
scrollPane.setBorder(new EmptyBorder(1,0,1,0));
}
}
myEditorField.getFocusTarget().addFocusListener(new FocusAdapter() {
@Override
public void focusGained(FocusEvent e) {
EditorComboBox.this.repaint();
}
@Override
public void focusLost(FocusEvent e) {
EditorComboBox.this.repaint();
}
});
}
private void setEditor() {
myEditorField = createEditorTextField(myDocument, myProject, myFileType, myIsViewer);
final ComboBoxEditor editor = new MyEditor();
setEditor(editor);
setRenderer(new EditorComboBoxRenderer(editor));
}
protected ComboboxEditorTextField createEditorTextField(Document document, Project project, FileType fileType, boolean isViewer) {
return new ComboboxEditorTextField(document, project, fileType, isViewer);
}
@Override
public void removeNotify() {
super.removeNotify();
if (myEditorField != null) {
releaseEditor();
myEditorField = null;
}
}
private void releaseEditor() {
if (myEditorField != null) {
final Editor editor = myEditorField.getEditor();
if (editor != null) {
myEditorField.releaseEditor(editor);
}
}
}
@Override
public void setFont(Font font) {
super.setFont(font);
if (myEditorField != null && myEditorField.getEditor() != null) {
setupEditorFont((EditorEx)myEditorField.getEditor());
}
}
private void setupEditorFont(final EditorEx editor) {
if (myInheritSwingFont) {
editor.getColorsScheme().setEditorFontName(getFont().getFontName());
editor.getColorsScheme().setEditorFontSize(getFont().getSize());
}
}
protected boolean shouldHaveBorder() {
return true;
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
if (myEditorField == null) {
return;
}
myEditorField.setEnabled(enabled);
}
@Override
public Dimension getPreferredSize() {
if (UIUtil.isUnderIntelliJLaF() || UIUtil.isUnderDarcula()) {
return super.getPreferredSize();
}
if (myEditorField != null) {
final Dimension preferredSize = new Dimension(myEditorField.getComponent().getPreferredSize());
final Insets insets = getInsets();
if (insets != null) {
preferredSize.width += insets.left;
preferredSize.width += insets.right;
preferredSize.height += insets.top;
preferredSize.height += insets.bottom;
}
return preferredSize;
}
//final int cbHeight = new JComboBox().getPreferredSize().height; // should be used actually
return new Dimension(100, UIUtil.fixComboBoxHeight(20));
}
@Override
protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
if (!((EditorEx)myEditorField.getEditor()).processKeyTyped(e)) {
return super.processKeyBinding(ks, e, condition, pressed);
}
return true;
}
public EditorEx getEditorEx() {
return myEditorField != null ? (EditorEx)myEditorField.getEditor() : null;
}
}