com.intellij.debugger.ui.DebuggerExpressionComboBox.java Source code

Java tutorial

Introduction

Here is the source code for com.intellij.debugger.ui.DebuggerExpressionComboBox.java

Source

/*
 * 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.debugger.ui;

import com.intellij.debugger.engine.evaluation.*;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.ui.EditorComboBoxEditor;
import com.intellij.ui.EditorComboBoxRenderer;
import com.intellij.ui.EditorTextField;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import javax.swing.plaf.basic.ComboPopup;
import java.awt.*;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * @author ven
 */
public class DebuggerExpressionComboBox extends DebuggerEditorImpl {
    public static final Key<String> KEY = Key.create("DebuggerComboBoxEditor.KEY");
    public static final int MAX_ROWS = 20;

    private MyEditorComboBoxEditor myEditor;
    private ComboBox myComboBox;

    private class MyEditorComboBoxEditor extends EditorComboBoxEditor {

        public MyEditorComboBoxEditor(Project project, FileType fileType) {
            super(project, fileType);
        }

        public Object getItem() {
            Document document = (Document) super.getItem();
            return createItem(document, getProject());
        }

        public void setItem(Object item) {
            TextWithImports twi = (TextWithImports) item;
            if (twi != null) {
                restoreFactory(twi);
            }
            final Document document = createDocument(twi);
            getEditorComponent().setNewDocumentAndFileType(getCurrentFactory().getFileType(), document);
            super.setItem(document);
            /* Causes PSI being modified from PSI events. See IDEADEV-22102
            final Editor editor = getEditor();
            if (editor != null) {
              DaemonCodeAnalyzer.getInstance(getProject()).updateVisibleHighlighters(editor);
            }
            */
        }

    }

    public DebuggerExpressionComboBox(Project project, @NonNls String recentsId) {
        this(project, null, recentsId, DefaultCodeFragmentFactory.getInstance());
    }

    public DebuggerExpressionComboBox(Project project, PsiElement context, @NonNls String recentsId,
            final CodeFragmentFactory factory) {
        super(project, context, recentsId, factory);
        setLayout(new BorderLayout(0, 0));

        myComboBox = new ComboBox(new MyComboboxModel(getRecents()), 100);
        myComboBox.setSwingPopup(false);

        // Have to turn this off because when used in DebuggerTreeInplaceEditor, the combobox popup is hidden on every change of selection
        // See comment to SynthComboBoxUI.FocusHandler.focusLost()
        myComboBox.setLightWeightPopupEnabled(false);

        myEditor = new MyEditorComboBoxEditor(getProject(), getCurrentFactory().getFileType());
        //noinspection GtkPreferredJComboBoxRenderer
        myComboBox.setRenderer(new EditorComboBoxRenderer(myEditor));

        myComboBox.setEditable(true);
        myComboBox.setEditor(myEditor);
        add(addChooseFactoryLabel(myComboBox, false));
    }

    public void selectPopupValue() {
        //selectAll();
        final Object currentPopupValue = getCurrentPopupValue();
        if (currentPopupValue != null) {
            myComboBox.getModel().setSelectedItem(currentPopupValue);
            myComboBox.getEditor().setItem(currentPopupValue);
        }

        myComboBox.setPopupVisible(false);
    }

    public boolean isPopupVisible() {
        return myComboBox.isVisible() && myComboBox.isPopupVisible();
    }

    public void setPopupVisible(final boolean b) {
        myComboBox.setPopupVisible(b);
    }

    @Nullable
    public Object getCurrentPopupValue() {
        if (!isPopupVisible())
            return null;

        final ComboPopup popup = myComboBox.getPopup();
        if (popup != null) {
            return popup.getList().getSelectedValue();
        }

        return null;
    }

    @Override
    protected void doSetText(TextWithImports item) {
        final String itemText = item.getText().replace('\n', ' ');
        restoreFactory(item);
        item.setText(itemText);
        if (!StringUtil.isEmpty(itemText)) {
            if (myComboBox.getItemCount() == 0 || !item.equals(myComboBox.getItemAt(0))) {
                myComboBox.insertItemAt(item, 0);
            }
        }
        if (myComboBox.getItemCount() > 0) {
            myComboBox.setSelectedIndex(0);
        }

        myComboBox.getEditor().setItem(item);
    }

    @Override
    protected void updateEditorUi() {
    }

    public TextWithImports getText() {
        return (TextWithImports) myComboBox.getEditor().getItem();
    }

    @Nullable
    private List<TextWithImports> getRecents() {
        final String recentsId = getRecentsId();
        if (recentsId != null) {
            final List<TextWithImports> result = new ArrayList<TextWithImports>();
            LinkedList<TextWithImports> recents = DebuggerRecents.getInstance(getProject())
                    .getRecents(getRecentsId());
            for (final TextWithImports evaluationText : recents) {
                if (evaluationText.getText().indexOf('\n') == -1) {
                    result.add(evaluationText);
                }
            }

            return result;
        }

        return null;
    }

    public Dimension getMinimumSize() {
        Dimension size = super.getMinimumSize();
        size.width = 100;
        return size;
    }

    public TextWithImports createText(String text, String importsString) {
        return new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, text, importsString,
                getCurrentFactory().getFileType());
    }

    @Override
    public void setEnabled(boolean enabled) {
        super.setEnabled(enabled);
        myComboBox.setEnabled(enabled);
        //if (enabled) {
        //  final ComboBoxEditor editor = myComboBox.getEditor();
        //  editor.setItem(editor.getItem());
        //}
    }

    public JComponent getPreferredFocusedComponent() {
        return (JComponent) myComboBox.getEditor().getEditorComponent();
    }

    public void selectAll() {
        myComboBox.getEditor().selectAll();
    }

    public Editor getEditor() {
        return myEditor.getEditor();
    }

    public JComponent getEditorComponent() {
        return myEditor.getEditorComponent();
    }

    public void addRecent(TextWithImports text) {
        if (text.getText().length() != 0) {
            Component editorComponent = myComboBox.getEditor().getEditorComponent();
            final boolean focusOwner = editorComponent.isFocusOwner();
            int offset = -1;
            if (editorComponent instanceof EditorTextField) {
                final EditorTextField textField = (EditorTextField) editorComponent;
                if (textField.getEditor() != null) {
                    offset = textField.getCaretModel().getOffset();
                }
            }
            super.addRecent(text);
            myComboBox.insertItemAt(text, 0);
            myComboBox.setSelectedIndex(0);
            editorComponent = myComboBox.getEditor().getEditorComponent();
            if (offset != -1 && editorComponent instanceof EditorTextField) {
                final EditorTextField textField = (EditorTextField) editorComponent;
                final Editor editor = textField.getEditor();
                if (editor != null) {
                    textField.getCaretModel().moveToOffset(offset);
                    editor.getSelectionModel().setSelection(offset, offset);
                }
            }

            if (focusOwner) {
                editorComponent.requestFocus();
            }
        }
    }

    private static class MyComboboxModel extends AbstractListModel implements MutableComboBoxModel {
        private List<TextWithImports> myItems = new ArrayList<TextWithImports>();
        private int mySelectedIndex = -1;

        private MyComboboxModel(@Nullable final List<TextWithImports> recents) {
            if (recents != null) {
                myItems = recents;
            }
        }

        @Override
        public void setSelectedItem(final Object anItem) {
            final int oldSelectedIndex = mySelectedIndex;
            mySelectedIndex = anItem instanceof TextWithImports ? myItems.indexOf(anItem) : -1;
            if (oldSelectedIndex != mySelectedIndex)
                fireContentsChanged(this, -1, -1);
        }

        @Override
        public Object getSelectedItem() {
            return mySelectedIndex == -1 || mySelectedIndex > myItems.size() - 1 ? null
                    : myItems.get(mySelectedIndex);
        }

        @Override
        public int getSize() {
            return myItems.size();
        }

        @Override
        public Object getElementAt(int index) {
            return myItems.get(index);
        }

        @Override
        public void addElement(final Object obj) {
            insertElementAt(obj, myItems.size() - 1);

            if (mySelectedIndex == -1 && myItems.size() == 1 && obj != null) {
                setSelectedItem(obj);
            }
        }

        @Override
        public void removeElement(Object obj) {
            removeElement(obj, true);
        }

        public void removeElement(final Object obj, final boolean checkSelection) {
            if (!(obj instanceof TextWithImports))
                throw new IllegalArgumentException();
            final int index = myItems.indexOf((TextWithImports) obj);
            if (index != -1) {
                myItems.remove(index);

                if (checkSelection) {
                    if (mySelectedIndex == index) {
                        if (myItems.size() == 0) {
                            setSelectedItem(null);
                        } else if (index > myItems.size() - 1) {
                            setSelectedItem(myItems.get(myItems.size() - 1));
                        }
                    }

                    fireIntervalRemoved(this, index, index);
                }
            }
        }

        @Override
        public void insertElementAt(final Object obj, final int index) {
            if (!(obj instanceof TextWithImports))
                throw new IllegalArgumentException();
            removeElement(obj, false); // remove duplicate entry if any

            myItems.add(index, (TextWithImports) obj);
            fireIntervalAdded(this, index, index);

            if (myItems.size() > MAX_ROWS) {
                for (int i = myItems.size() - 1; i > MAX_ROWS - 1; i--) {
                    myItems.remove(i);
                }

                // will not fire events here to not recreate the editor
                //fireIntervalRemoved(this, myItems.size() - 1, MAX_ROWS - 1);
            }
        }

        @Override
        public void removeElementAt(final int index) {
            if (index < 0 || index > myItems.size() - 1)
                throw new IndexOutOfBoundsException();
            removeElement(myItems.get(index));
        }
    }
}