/* * 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 com.intellij.ide.palette.impl.PaletteToolWindowManager; import com.intellij.openapi.actionSystem.*; 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; import gnu.trove.TIntArrayList; import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.util.ArrayList; /** * @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; } }