| /* |
| * 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; |
| } |
| } |