com.intellij.uiDesigner.designSurface.MainProcessor.java Source code

Java tutorial

Introduction

Here is the source code for com.intellij.uiDesigner.designSurface.MainProcessor.java

Source

/*
 * Copyright 2000-2009 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.uiDesigner.designSurface;

import gnu.trove.TIntArrayList;

import java.awt.Component;
import java.awt.Cursor;
import java.awt.Point;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.ArrayList;

import javax.swing.JComponent;
import javax.swing.SwingUtilities;

import org.jetbrains.annotations.NotNull;
import com.intellij.ide.palette.impl.PaletteToolWindowManager;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.ActionPopupMenu;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.uiDesigner.FormEditingUtil;
import com.intellij.uiDesigner.palette.ComponentItem;
import com.intellij.uiDesigner.propertyInspector.InplaceContext;
import com.intellij.uiDesigner.radComponents.RadComponent;
import com.intellij.uiDesigner.radComponents.RadRootContainer;
import com.intellij.util.ui.UIUtil;

/**
 * @author Anton Katilin
 * @author Vladimir Kondratyev
 */
public final class MainProcessor extends EventProcessor {
    private static final Logger LOG = Logger.getInstance("#com.intellij.uiDesigner.MainProcessor");

    private static final int DRAGGER_SIZE = 10;

    private EventProcessor myCurrentProcessor;
    @NotNull
    private final InsertComponentProcessor myInsertComponentProcessor;
    @NotNull
    private final GuiEditor myEditor;
    private boolean myInsertFeedbackEnabled = true;
    private Point myLastMousePosition = new Point(0, 0);

    public MainProcessor(@NotNull final GuiEditor editor) {
        myEditor = editor;
        myInsertComponentProcessor = new InsertComponentProcessor(myEditor);
    }

    protected void processKeyEvent(final KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_SHIFT) {
            if (e.getID() == KeyEvent.KEY_PRESSED) {
                if ((myCurrentProcessor != null && myCurrentProcessor.isDragActive()) || (PaletteToolWindowManager
                        .getInstance(myEditor).getActiveItem(ComponentItem.class) != null
                        && myCurrentProcessor != myInsertComponentProcessor)) {
                    myEditor.setDesignTimeInsets(12);
                }
            } else {
                myEditor.setDesignTimeInsets(2);
            }
        }
        if (myCurrentProcessor != null) {
            myCurrentProcessor.processKeyEvent(e);
        } else if (e.getID() == KeyEvent.KEY_TYPED && Character.isLetterOrDigit(e.getKeyChar())
                && (e.getModifiers() & (InputEvent.ALT_MASK | InputEvent.CTRL_MASK | InputEvent.META_MASK)) == 0) {
            final ArrayList<RadComponent> selection = FormEditingUtil.getAllSelectedComponents(myEditor);
            if (selection.size() > 0) {
                final RadComponent component = selection.get(0);
                final InplaceEditingLayer inplaceLayer = myEditor.getInplaceEditingLayer();
                inplaceLayer.startInplaceEditing(component, component.getDefaultInplaceProperty(),
                        component.getDefaultInplaceEditorBounds(), new InplaceContext(false, e.getKeyChar()));
                e.consume();
            }
        }
    }

    public Point getLastMousePosition() {
        return myLastMousePosition;
    }

    protected void processMouseEvent(final MouseEvent e) {
        myLastMousePosition = e.getPoint();

        if (myCurrentProcessor != null && myCurrentProcessor.isDragActive()) {
            return;
        }

        // Here is a good place to handle right and wheel mouse clicking. All mouse
        // motion events should go further
        if (e.isPopupTrigger()) {
            RadComponent component = FormEditingUtil.getRadComponentAt(myEditor.getRootContainer(), e.getX(),
                    e.getY());
            if (component != null && !component.isSelected()) {
                FormEditingUtil.selectSingleComponent(myEditor, component);
            }

            final ActionManager actionManager = ActionManager.getInstance();
            final ActionPopupMenu popupMenu = actionManager.createActionPopupMenu(
                    ActionPlaces.GUI_DESIGNER_EDITOR_POPUP,
                    (ActionGroup) actionManager.getAction(IdeActions.GROUP_GUI_DESIGNER_EDITOR_POPUP));
            popupMenu.getComponent().show(e.getComponent(), e.getX(), e.getY());
            return;
        }

        final int id = e.getID();
        if ((MouseEvent.BUTTON2 == e.getButton() || MouseEvent.BUTTON3 == e.getButton())
                && (MouseEvent.MOUSE_PRESSED == id || MouseEvent.MOUSE_RELEASED == id
                        || MouseEvent.MOUSE_CLICKED == id)) {
            return;
        }

        // Handle all left mouse events and all motion events
        final RadComponent componentAt = FormEditingUtil.getRadComponentAt(myEditor.getRootContainer(), e.getX(),
                e.getY());
        if (componentAt != null) {
            final Point p1 = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), componentAt.getDelegee());
            final Component deepestComponentAt = SwingUtilities.getDeepestComponentAt(componentAt.getDelegee(),
                    p1.x, p1.y);
            final Point p2 = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), deepestComponentAt);

            EventProcessor processor = componentAt.getEventProcessor(e);
            if (processor != null) {
                myCurrentProcessor = processor;
            } else {
                final Component source = deepestComponentAt != null ? deepestComponentAt : componentAt.getDelegee();
                componentAt.processMouseEvent(new MouseEvent(source, id, e.getWhen(), e.getModifiers(), p2.x, p2.y,
                        e.getClickCount(), e.isPopupTrigger(), e.getButton()));
            }
        }

        Cursor cursor = Cursor.getDefaultCursor();
        if (id == MouseEvent.MOUSE_MOVED) {
            if (PaletteToolWindowManager.getInstance(myEditor).getActiveItem(ComponentItem.class) != null) {
                if (myInsertFeedbackEnabled) {
                    cursor = myInsertComponentProcessor.processMouseMoveEvent(e);
                }
            } else if (myCurrentProcessor != null) {
                myCurrentProcessor.processMouseEvent(e);
            } else {
                final RadComponent component = FormEditingUtil.getRadComponentAt(myEditor.getRootContainer(),
                        e.getX(), e.getY());
                if (component != null) {
                    final Point point = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(),
                            component.getDelegee());
                    final int resizeMask = Painter.getResizeMask(component, point.x, point.y);
                    if (resizeMask != 0) {
                        cursor = Cursor.getPredefinedCursor(Painter.getResizeCursor(resizeMask));
                    }
                    updateDragger(e);
                }
            }
        } else if (id == MouseEvent.MOUSE_PRESSED) {
            processMousePressed(e);
        } else if (id == MouseEvent.MOUSE_RELEASED) {
            // not every press sets processor so its not a redundant 'if'
            if (myCurrentProcessor != null) {
                myCurrentProcessor.processMouseEvent(e);
                myCurrentProcessor = null;
            }
        } else if (id == MouseEvent.MOUSE_CLICKED) {
            processMouseClicked(e);
        } else if (id == MouseEvent.MOUSE_EXITED) {
            myEditor.getActiveDecorationLayer().removeFeedback();
        }

        if (!e.isConsumed() && myCurrentProcessor != null) {
            myCurrentProcessor.processMouseEvent(e);
        }

        if (myCurrentProcessor != null && myCurrentProcessor.isDragActive()) {
            myEditor.getLayeredPane().setCursor(null);
        } else {
            if (myCurrentProcessor != null && myCurrentProcessor.getCursor() != null) {
                cursor = myCurrentProcessor.getCursor();
            }
            myEditor.getLayeredPane().setCursor(cursor);
        }
    }

    private void updateDragger(final MouseEvent e) {
        final RadComponent component = FormEditingUtil.getRadComponentAt(myEditor.getRootContainer(), e.getX(),
                e.getY());

        LOG.assertTrue(component != null);

        // Dragger
        final RadComponent oldDraggerHost = FormEditingUtil.getDraggerHost(myEditor);
        RadComponent newDraggerHost = null;
        for (RadComponent c = component; c != null && !(c instanceof RadRootContainer); c = c.getParent()) {
            if (c.isSelected()) {
                newDraggerHost = c;
                break;
            }
        }

        boolean keepOldHost = false;

        if (oldDraggerHost != null && oldDraggerHost.isSelected()) {
            final Point p = SwingUtilities.convertPoint(oldDraggerHost.getDelegee(), 0, 0, e.getComponent());
            final int deltaX = e.getX() - p.x;
            final int deltaY = e.getY() - p.y;
            if (deltaX > -DRAGGER_SIZE && deltaX < oldDraggerHost.getWidth() && deltaY > -DRAGGER_SIZE
                    && deltaY < oldDraggerHost.getHeight()) {
                keepOldHost = true;
                newDraggerHost = null;
            }
        }

        boolean shouldRepaint = false;

        if (oldDraggerHost != null && !keepOldHost && oldDraggerHost != newDraggerHost) {
            oldDraggerHost.setDragger(false);
            shouldRepaint = true;
        }

        if (newDraggerHost != null) {
            newDraggerHost.setDragger(true);
            shouldRepaint = true;
        }

        if (shouldRepaint) {
            myEditor.repaintLayeredPane();
        }
    }

    private void removeDragger() {
        final RadComponent oldDraggerHost = FormEditingUtil.getDraggerHost(myEditor);
        if (oldDraggerHost != null) {
            oldDraggerHost.setDragger(false);
            myEditor.repaintLayeredPane();
        }
    }

    private void processMousePressed(final MouseEvent e) {
        if (myCurrentProcessor != null) {
            if (myCurrentProcessor.needMousePressed()) {
                myCurrentProcessor.processMouseEvent(e);
                return;
            }
            // Sun sometimes skips mouse released events...
            myCurrentProcessor.cancelOperation();
            myCurrentProcessor = null;
        }

        RadComponent component = null;
        final RadComponent draggerHost = FormEditingUtil.getDraggerHost(myEditor);
        // Try to understand whether we pressed inside dragger area
        if (draggerHost != null) {
            final JComponent delegee = draggerHost.getDelegee();
            final Point p = SwingUtilities.convertPoint(delegee, 0, 0, e.getComponent());
            if (p.x - MainProcessor.DRAGGER_SIZE <= e.getX() && e.getX() <= p.x
                    && p.y - MainProcessor.DRAGGER_SIZE <= e.getY() && e.getY() <= p.y) {
                component = draggerHost;
            }
        }

        // If user clicked not inside dragger then we have find RadComponent at the click point
        if (component == null) {
            component = FormEditingUtil.getRadComponentAt(myEditor.getRootContainer(), e.getX(), e.getY());
        }

        if (component == null) {
            return;
        }

        final ComponentItem selectedItem = PaletteToolWindowManager.getInstance(myEditor)
                .getActiveItem(ComponentItem.class);
        if (selectedItem != null) {
            myInsertComponentProcessor.setSticky(UIUtil.isControlKeyDown(e));
            myCurrentProcessor = myInsertComponentProcessor;
            return;
        }

        if (!UIUtil.isControlKeyDown(e) && !e.isShiftDown()) {
            if (!component.isSelected() || FormEditingUtil.getSelectedComponents(myEditor).size() != 1) {
                FormEditingUtil.selectSingleComponent(myEditor, component);
            }
        }

        final Point point = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), component.getDelegee());
        final int resizeMask = Painter.getResizeMask(component, point.x, point.y);
        LOG.debug("MainProcessor.processMousePressed: resizeMask at (" + point.x + "," + point.y + ") is "
                + resizeMask);

        if (resizeMask != 0) {
            if (component.getParent() != null) {
                component = component.getParent().getActionTargetComponent(component);
            }
            myCurrentProcessor = new ResizeProcessor(myEditor, component, resizeMask);
        } else if (component instanceof RadRootContainer || e.isShiftDown()) {
            myCurrentProcessor = new GroupSelectionProcessor(myEditor, component);
        } else if (!e.isShiftDown()) {
            myCurrentProcessor = new DragSelectionProcessor(myEditor);
        }

        updateDragger(e);
    }

    private void processMouseClicked(final MouseEvent e) {
        if (e.getClickCount() != 2) { // inplace editing starts with double click
            return;
        }
        myEditor.getInplaceEditingLayer().startInplaceEditing(e.getX(), e.getY());
    }

    protected boolean cancelOperation() {
        if (myCurrentProcessor != null) {
            if (myCurrentProcessor.cancelOperation()) {
                myCurrentProcessor = null;
                myEditor.getLayeredPane().setCursor(Cursor.getDefaultCursor());
                myEditor.getActiveDecorationLayer().removeFeedback();
                return true;
            }
        } else if (PaletteToolWindowManager.getInstance(myEditor).getActiveItem(ComponentItem.class) != null) {
            cancelPaletteInsert();
            return true;
        }
        return false;
    }

    void cancelPaletteInsert() {
        PaletteToolWindowManager.getInstance(myEditor).clearActiveItem();
        myEditor.getLayeredPane().setCursor(Cursor.getDefaultCursor());
        myEditor.getActiveDecorationLayer().removeFeedback();
    }

    public void setInsertFeedbackEnabled(final boolean enabled) {
        myInsertFeedbackEnabled = enabled;
    }

    public void startPasteProcessor(final ArrayList<RadComponent> componentsToPaste, final TIntArrayList xs,
            final TIntArrayList ys) {
        removeDragger();
        myEditor.hideIntentionHint();
        myCurrentProcessor = new PasteProcessor(myEditor, componentsToPaste, xs, ys);
        myCurrentProcessor.processMouseEvent(new MouseEvent(myEditor, MouseEvent.MOUSE_MOVED, 0, 0,
                myLastMousePosition.x, myLastMousePosition.y, 1, false));
    }

    public void startInsertProcessor(@NotNull final ComponentItem componentToInsert,
            final ComponentDropLocation location) {
        removeDragger();
        myEditor.hideIntentionHint();
        myInsertComponentProcessor.setComponentToInsert(componentToInsert);
        myInsertComponentProcessor.setLastLocation(location);
        myCurrentProcessor = myInsertComponentProcessor;
    }

    public void stopCurrentProcessor() {
        myCurrentProcessor = null;
        myEditor.getLayeredPane().setCursor(null);
    }

    public boolean isProcessorActive() {
        return myCurrentProcessor != null;
    }
}