com.intellij.xdebugger.impl.ui.DebuggerUIUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.intellij.xdebugger.impl.ui.DebuggerUIUtil.java

Source

/*
 * Copyright 2000-2015 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.xdebugger.impl.ui;

import com.intellij.codeInsight.hint.HintUtil;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.*;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.DimensionService;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.ui.AppUIUtil;
import com.intellij.ui.EditorTextField;
import com.intellij.ui.ScreenUtil;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.popup.list.ListPopupImpl;
import com.intellij.xdebugger.XDebuggerManager;
import com.intellij.xdebugger.breakpoints.XBreakpoint;
import com.intellij.xdebugger.breakpoints.XBreakpointAdapter;
import com.intellij.xdebugger.breakpoints.XBreakpointListener;
import com.intellij.xdebugger.breakpoints.XBreakpointManager;
import com.intellij.xdebugger.frame.XFullValueEvaluator;
import com.intellij.xdebugger.impl.breakpoints.XBreakpointBase;
import com.intellij.xdebugger.impl.breakpoints.ui.BreakpointsDialogFactory;
import com.intellij.xdebugger.impl.breakpoints.ui.XLightBreakpointPropertiesPanel;
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.util.concurrent.atomic.AtomicBoolean;

public class DebuggerUIUtil {
    @NonNls
    public static final String FULL_VALUE_POPUP_DIMENSION_KEY = "XDebugger.FullValuePopup";

    private DebuggerUIUtil() {
    }

    public static void enableEditorOnCheck(final JCheckBox checkbox, final JComponent textfield) {
        checkbox.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                boolean selected = checkbox.isSelected();
                textfield.setEnabled(selected);
            }
        });
        textfield.setEnabled(checkbox.isSelected());
    }

    public static void focusEditorOnCheck(final JCheckBox checkbox, final JComponent component) {
        final Runnable runnable = new Runnable() {
            @Override
            public void run() {
                component.requestFocus();
            }
        };
        checkbox.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (checkbox.isSelected()) {
                    SwingUtilities.invokeLater(runnable);
                }
            }
        });
    }

    public static void invokeLater(Runnable runnable) {
        ApplicationManager.getApplication().invokeLater(runnable);
    }

    public static RelativePoint calcPopupLocation(Editor editor, final int line) {
        Point p = editor.logicalPositionToXY(new LogicalPosition(line + 1, 0));

        final Rectangle visibleArea = editor.getScrollingModel().getVisibleArea();
        if (!visibleArea.contains(p)) {
            p = new Point((visibleArea.x + visibleArea.width) / 2, (visibleArea.y + visibleArea.height) / 2);
        }
        return new RelativePoint(editor.getContentComponent(), p);
    }

    public static void showValuePopup(@NotNull XFullValueEvaluator evaluator, @NotNull MouseEvent event,
            @NotNull Project project, @Nullable Editor editor) {
        EditorTextField textArea = new TextViewer("Evaluating...", project);
        textArea.setBackground(HintUtil.INFORMATION_COLOR);

        final FullValueEvaluationCallbackImpl callback = new FullValueEvaluationCallbackImpl(textArea);
        evaluator.startEvaluation(callback);

        Dimension size = DimensionService.getInstance().getSize(FULL_VALUE_POPUP_DIMENSION_KEY, project);
        if (size == null) {
            Dimension frameSize = WindowManager.getInstance().getFrame(project).getSize();
            size = new Dimension(frameSize.width / 2, frameSize.height / 2);
        }

        textArea.setPreferredSize(size);

        JBPopup popup = createValuePopup(project, textArea, callback);
        if (editor == null) {
            Rectangle bounds = new Rectangle(event.getLocationOnScreen(), size);
            ScreenUtil.fitToScreenVertical(bounds, 5, 5, true);
            if (size.width != bounds.width || size.height != bounds.height) {
                size = bounds.getSize();
                textArea.setPreferredSize(size);
            }
            popup.showInScreenCoordinates(event.getComponent(), bounds.getLocation());
        } else {
            popup.showInBestPositionFor(editor);
        }
    }

    public static JBPopup createValuePopup(Project project, JComponent component,
            @Nullable final FullValueEvaluationCallbackImpl callback) {
        ComponentPopupBuilder builder = JBPopupFactory.getInstance().createComponentPopupBuilder(component, null);
        builder.setResizable(true).setMovable(true)
                .setDimensionServiceKey(project, FULL_VALUE_POPUP_DIMENSION_KEY, false).setRequestFocus(false);
        if (callback != null) {
            builder.setCancelCallback(new Computable<Boolean>() {
                @Override
                public Boolean compute() {
                    callback.setObsolete();
                    return true;
                }
            });
        }
        return builder.createPopup();
    }

    public static void showXBreakpointEditorBalloon(final Project project, @Nullable final Point point,
            final JComponent component, final boolean showAllOptions, final XBreakpoint breakpoint) {
        final XBreakpointManager breakpointManager = XDebuggerManager.getInstance(project).getBreakpointManager();
        final XLightBreakpointPropertiesPanel<XBreakpointBase<?, ?, ?>> propertiesPanel = new XLightBreakpointPropertiesPanel<XBreakpointBase<?, ?, ?>>(
                project, breakpointManager, (XBreakpointBase) breakpoint, showAllOptions);

        final Ref<Balloon> balloonRef = Ref.create(null);
        final Ref<Boolean> isLoading = Ref.create(Boolean.FALSE);
        final Ref<Boolean> moreOptionsRequested = Ref.create(Boolean.FALSE);

        propertiesPanel.setDelegate(new XLightBreakpointPropertiesPanel.Delegate() {
            @Override
            public void showMoreOptions() {
                if (!isLoading.get()) {
                    propertiesPanel.saveProperties();
                }
                if (!balloonRef.isNull()) {
                    balloonRef.get().hide();
                }
                showXBreakpointEditorBalloon(project, point, component, true, breakpoint);
                moreOptionsRequested.set(true);
            }
        });

        isLoading.set(Boolean.TRUE);
        propertiesPanel.loadProperties();
        isLoading.set(Boolean.FALSE);

        if (moreOptionsRequested.get()) {
            return;
        }

        Runnable showMoreOptions = new Runnable() {
            @Override
            public void run() {
                propertiesPanel.saveProperties();
                propertiesPanel.dispose();
                BreakpointsDialogFactory.getInstance(project).showDialog(breakpoint);
            }
        };

        final JComponent mainPanel = propertiesPanel.getMainPanel();
        final Balloon balloon = showBreakpointEditor(project, mainPanel, point, component, showMoreOptions,
                breakpoint);
        balloonRef.set(balloon);

        final XBreakpointListener<XBreakpoint<?>> breakpointListener = new XBreakpointAdapter<XBreakpoint<?>>() {
            @Override
            public void breakpointRemoved(@NotNull XBreakpoint<?> removedBreakpoint) {
                if (removedBreakpoint.equals(breakpoint)) {
                    balloon.hide();
                }
            }
        };

        balloon.addListener(new JBPopupListener.Adapter() {
            @Override
            public void onClosed(LightweightWindowEvent event) {
                propertiesPanel.saveProperties();
                propertiesPanel.dispose();
                breakpointManager.removeBreakpointListener(breakpointListener);
            }
        });

        breakpointManager.addBreakpointListener(breakpointListener);
        ApplicationManager.getApplication().invokeLater(new Runnable() {
            @Override
            public void run() {
                IdeFocusManager.findInstance().requestFocus(mainPanel, true);
            }
        });
    }

    public static Balloon showBreakpointEditor(Project project, final JComponent mainPanel, final Point whereToShow,
            final JComponent component, @Nullable final Runnable showMoreOptions, Object breakpoint) {
        final BreakpointEditor editor = new BreakpointEditor();
        editor.setPropertiesPanel(mainPanel);
        editor.setShowMoreOptionsLink(true);

        final JPanel panel = editor.getMainPanel();
        final Balloon balloon = JBPopupFactory.getInstance().createDialogBalloonBuilder(panel, null)
                .setHideOnClickOutside(true).setCloseButtonEnabled(false).setAnimationCycle(0)
                .setBlockClicksThroughBalloon(true).createBalloon();

        editor.setDelegate(new BreakpointEditor.Delegate() {
            @Override
            public void done() {
                balloon.hide();
            }

            @Override
            public void more() {
                assert showMoreOptions != null;
                balloon.hide();
                showMoreOptions.run();
            }
        });

        if (whereToShow == null) {
            balloon.showInCenterOf(component);
        } else {
            //todo[kb] modify and move to BalloonImpl?
            final Window window = SwingUtilities.windowForComponent(component);
            final RelativePoint p = new RelativePoint(component, whereToShow);
            if (window != null) {
                final RelativePoint point = new RelativePoint(window, new Point(0, 0));
                if (p.getScreenPoint().getX() - point.getScreenPoint().getX() < 40) { // triangle + offsets is ~40px
                    p.getPoint().x += 40;
                }
            }
            balloon.show(p, Balloon.Position.below);
        }

        BreakpointsDialogFactory.getInstance(project).setBalloonToHide(balloon, breakpoint);

        return balloon;
    }

    private static class FullValueEvaluationCallbackImpl
            implements XFullValueEvaluator.XFullValueEvaluationCallback {
        private final AtomicBoolean myObsolete = new AtomicBoolean(false);
        private final EditorTextField myTextArea;

        public FullValueEvaluationCallbackImpl(final EditorTextField textArea) {
            myTextArea = textArea;
        }

        @Override
        public void evaluated(@NotNull final String fullValue) {
            evaluated(fullValue, null);
        }

        @Override
        public void evaluated(@NotNull final String fullValue, @Nullable final Font font) {
            AppUIUtil.invokeOnEdt(new Runnable() {
                @Override
                public void run() {
                    myTextArea.setText(fullValue);
                    if (font != null) {
                        myTextArea.setFont(font);
                    }
                }
            });
        }

        @Override
        public void errorOccurred(@NotNull final String errorMessage) {
            AppUIUtil.invokeOnEdt(new Runnable() {
                @Override
                public void run() {
                    myTextArea.setForeground(XDebuggerUIConstants.ERROR_MESSAGE_ATTRIBUTES.getFgColor());
                    myTextArea.setText(errorMessage);
                }
            });
        }

        private void setObsolete() {
            myObsolete.set(true);
        }

        @Override
        public boolean isObsolete() {
            return myObsolete.get();
        }
    }

    @Nullable
    public static String getNodeRawValue(@NotNull XValueNodeImpl valueNode) {
        if (valueNode.getValueContainer() instanceof XValueTextProvider) {
            return ((XValueTextProvider) valueNode.getValueContainer()).getValueText();
        } else {
            return valueNode.getRawValue();
        }
    }

    public static void registerExtraHandleShortcuts(final ListPopupImpl popup, String actionName) {
        AnAction action = ActionManager.getInstance().getAction(actionName);
        KeyStroke stroke = KeymapUtil.getKeyStroke(action.getShortcutSet());
        if (stroke != null) {
            popup.registerAction("handleSelection " + stroke, stroke, new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    popup.handleSelect(true);
                }
            });
        }
    }
}