📄 basicgraphui.java
字号:
* This can be used to do something interesting if the cell was already * selected, in which case this implementation selects the parent. * Override if you want different behaviour, such as start editing. */ protected void postProcessSelection( MouseEvent e, Object cell, boolean wasSelected) { if (wasSelected && graph.isCellSelected(cell)) { Object parent = cell; Object nextParent = null; while (((nextParent = graphModel.getParent(parent)) != null) && graphLayoutCache.isVisible(nextParent)) parent = nextParent; selectCellForEvent(parent, e); focus = graphLayoutCache.getMapping(parent, false); } } protected boolean isDescendant( CellView parentView, CellView childView) { if (parentView == null || childView == null) { return false; } Object parent = parentView.getCell(); Object child = childView.getCell(); Object ancestor = child; do { if (ancestor == parent) return true; } while ((ancestor = graphModel.getParent(ancestor)) != null); return false; } } // End of BasicGraphUI.MouseHandler public class RootHandle implements CellHandle, Serializable { //x and y offset from the mouse press event to the left/top corner of a view that is returned by a findViewForPoint(). //These are used only when the isSnapSelectedView mode is enabled. protected transient int _mouseToViewDelta_x = 0; protected transient int _mouseToViewDelta_y = 0; // Double Buffered protected transient Image offscreen; protected transient Graphics offgraphics; protected transient boolean firstDrag = true; /* Temporary views for the cells. */ protected transient CellView[] views; protected transient CellView[] contextViews; protected transient CellView[] portViews; /* Bounds of the cells. Non-null if too many cells. */ protected transient Rectangle cachedBounds; /* Child handles. Null if too many handles. */ protected transient CellHandle[] handles; /* The point where the mouse was pressed. */ protected transient Point start = null, last, snapStart, snapLast; /** * Indicates whether this handle is currently moving cells. Start * may be non-null and isMoving false while the minimum movement * has not been reached. */ protected boolean isMoving = false; /** * Indicates whether this handle has started drag and drop. * Note: isDragging => isMoving. */ protected boolean isDragging = false; /** The handle that consumed the last mousePressedEvent. Initially null. */ protected transient CellHandle activeHandle = null; /* The current selection context, responsible for cloning the cells. */ protected transient GraphContext context; /* True after the graph was repainted to block xor-ed painting of background. */ protected boolean isContextVisible = true; protected boolean blockPaint = false; /* Defines the Disconnection if DisconnectOnMove is True */ protected transient ConnectionSet disconnect = null; /** * Creates a root handle which contains handles for the given * cells. The root handle and all its childs point to the * specified JGraph instance. The root handle is responsible * for dragging the selection. */ public RootHandle(GraphContext ctx) { this.context = ctx; if (!ctx.isEmpty()) { // Temporary cells views = ctx.createTemporaryCellViews(); if (ctx.getDescendantCount() < MAXCELLS) contextViews = ctx.createTemporaryContextViews(); else cachedBounds = graph.toScreen(graph.getCellBounds(ctx.getCells())); // Sub-Handles Object[] cells = ctx.getCells(); if (cells.length < MAXHANDLES) { handles = new CellHandle[views.length]; for (int i = 0; i < views.length; i++) handles[i] = views[i].getHandle(ctx); // PortView Preview portViews = ctx.createTemporaryPortViews(); } } } /* Returns the context of this root handle. */ public GraphContext getContext() { return context; } /* Paint the handles. Use overlay to paint the current state. */ public void paint(Graphics g) { if (handles != null && handles.length < MAXHANDLES) for (int i = 0; i < handles.length; i++) if (handles[i] != null) handles[i].paint(g); blockPaint = true; } public void overlay(Graphics g) { if (isDragging && !DNDPREVIEW) // BUG IN 1.4 return; if (cachedBounds != null) { // Paint Cached Bounds g.setColor(Color.black); g.drawRect( cachedBounds.x, cachedBounds.y, cachedBounds.width - 2, cachedBounds.height - 2); } else { Graphics2D g2 = (Graphics2D) g; AffineTransform oldTransform = g2.getTransform(); g2.scale(graph.getScale(), graph.getScale()); if (views != null) { // Paint Temporary Views for (int i = 0; i < views.length; i++) paintCell(g, views[i], views[i].getBounds(), true); } if (contextViews != null && isContextVisible) { // Paint Temporary Context for (int i = 0; i < contextViews.length; i++) paintCell( g, contextViews[i], contextViews[i].getBounds(), true); } g2.setTransform(oldTransform); if (portViews != null && graph.isPortsVisible()) paintPorts(g, portViews); } } /** * Invoked when the mouse pointer has been moved on a component * (with no buttons down). */ public void mouseMoved(MouseEvent event) { if (!event.isConsumed() && handles != null) for (int i = handles.length - 1; i >= 0 && !event.isConsumed(); i--) if (handles[i] != null) handles[i].mouseMoved(event); } public void mousePressed(MouseEvent event) { if (!event.isConsumed() && graph.isMoveable()) { if (handles != null) { // Find Handle for (int i = handles.length - 1; i >= 0; i--) { if (handles[i] != null) { handles[i].mousePressed(event); if (event.isConsumed()) { activeHandle = handles[i]; return; } } } } if (views != null) { // Start Move if over cell Point screenPoint = event.getPoint(); Point pt = graph.fromScreen(new Point(screenPoint)); CellView view = findViewForPoint(pt); if (view != null) { if (snapSelectedView) { Rectangle bounds = view.getBounds(); start = graph.toScreen(new Point(bounds.x, bounds.y)); snapStart = graph.snap(new Point(start)); _mouseToViewDelta_x = screenPoint.x - start.x; _mouseToViewDelta_y = screenPoint.y - start.y; } else { //this is the original RootHandle's mode. snapStart = graph.snap(new Point(screenPoint)); _mouseToViewDelta_x = snapStart.x - screenPoint.x; _mouseToViewDelta_y = snapStart.y - screenPoint.y; start = new Point(snapStart); } last = new Point(start); snapLast = new Point(snapStart); isContextVisible = contextViews != null && contextViews.length < MAXCELLS && (!event.isControlDown() || !graph.isCloneable()); event.consume(); } } } } /** * Hook for subclassers to return a different view for a mouse click * at <code>pt</code>. For example, this can be used to return a leaf * cell instead of a group. */ protected CellView findViewForPoint(Point pt) { int snap = graph.getTolerance(); Rectangle r = new Rectangle(pt.x - snap, pt.y - snap, 2 * snap, 2 * snap); for (int i = 0; i < views.length; i++) if (views[i].intersects(graph.getGraphics(), r)) return views[i]; return null; } protected void startDragging(MouseEvent event) { isDragging = true; if (graph.isDragEnabled()) { int action = (event.isControlDown() && graph.isCloneable()) ? TransferHandler.COPY : TransferHandler.MOVE; TransferHandler th = graph.getTransferHandler(); try { th.exportAsDrag(graph, event, action); } catch (Exception ex) { // Ignore } } } // Double Buffers by David Larsson protected void initOffscreen() { try { Rectangle rect = graph.getBounds(); //RepaintManager repMan = RepaintManager.currentManager(getContext().getGraph()); //offscreen = repMan.getVolatileOffscreenBuffer(getContext().getGraph(), (int) rect.getWidth(), (int) rect.getHeight()); offscreen = new BufferedImage( rect.width, rect.height, BufferedImage.TYPE_INT_RGB); offgraphics = offscreen.getGraphics(); offgraphics.setClip( 0, 0, (int) rect.getWidth(), (int) rect.getHeight()); offgraphics.setColor(graph.getBackground()); offgraphics.fillRect( 0, 0, (int) rect.getWidth(), (int) rect.getHeight()); graph.getUI().paint(offgraphics, graph); } catch (Error e) { offscreen = null; offgraphics = null; } } /** Process mouse dragged event. */ public void mouseDragged(MouseEvent event) { boolean constrained = isConstrainedMoveEvent(event); Rectangle dirty = null; if (firstDrag && graph.isDoubleBuffered() && cachedBounds == null) { initOffscreen(); firstDrag = false; } if (event != null && !event.isConsumed()) { if (activeHandle != null) // Paint Active Handle activeHandle.mouseDragged(event); // Invoke Mouse Dragged else if (start != null) { // Move Cells Graphics g = (offgraphics != null) ? offgraphics : graph.getGraphics(); Point point = new Point(event.getPoint()); point.translate(-_mouseToViewDelta_x, -_mouseToViewDelta_y); Point snapCurrent = graph.snap(point); Point current = snapCurrent; int thresh = graph.getMinimumMove(); int dx = current.x - start.x; int dy = current.y - start.y; if (isMoving || Math.abs(dx) > thresh || Math.abs(dy) > thresh) { boolean overlayed = false; isMoving = true; if (disconnect == null && graph.isDisconnectOnMove()) disconnect = context.disconnect( graphLayoutCache.getAllDescendants(views)); // Constrained movement if (constrained && cachedBounds == null) { int totDx = current.x - start.x; int totDy = current.y - start.y; if (Math.abs(totDx) < Math.abs(totDy)) { dx = 0; dy = totDy; } else { dx = totDx; dy = 0; } } else { dx = current.x - last.x; dy = current.y - last.y; } double scale = graph.getScale(); dx = (int) (dx / scale); //we don't want to round. The best thing is to get just the integer part. //That way, the view won't "run away" from the mouse. It may lag behind //a mouse pointer occasionally, but will be catching up. dy = (int) (dy / scale); g.setColor(graph.getForeground()); // use 'darker' to force XOR to distinguish between existing background elements during drag // http://sourceforge.net/tracker/index.php?func=detail&aid=677743&group_id=43118&atid=435210 g.setXORMode(graph.getBackground().darker()); // Start Drag and Drop if (graph.isDragEnabled() && !isDragging) startDragging(event); if (dx != 0 || dy != 0) { if (!snapLast.equals(snapStart) && (offscreen != null || !blockPaint)) { overlay(g); overlayed = true; } isContextVisible = (!event.isControlDown() || !graph.isCloneable()) && contextViews != null && (contextViews.length < MAXCELLS); blockPaint = false; if (offscreen != null) { dirty = graph.toScreen( AbstractCellView.getBounds(views)); Rectangle t = graph.toScreen( AbstractCellView.getBounds( contextViews)); if (t != null) dirty.add(t); } if (constrained && cachedBounds == null) { //Reset Initial Positions CellView[] all = graphLayoutCache.getAllDescendants(views); for (int i = 0; i < all.length; i++) { CellView orig = graphLayoutCache.getMapping( all[i].getCell(), false); Map attr = orig.getAllAttributes(); all[i].setAttributes( GraphConstants.cloneMap(attr)); all[i].refresh(false); } } if (cachedBounds != null) cachedBounds.translate( (int) (dx * scale), (int) (dy * scale)); else { // Translate GraphLayoutCache.translateViews(views, dx, dy); if (views != null) graphLayoutCache.update(views); if (contextViews != null) graphLayoutCache.update(contextViews); } if (!snapCurrent.equals(snapStart)) { overlay(g); overlayed = true; } if (constrained) last = new Point(start); last.translate( (int) (dx * scale), (int) (dy * scale)); // It is better to translate <code>last<code> by a scaled dx/dy // instead of making it to be the <code>current<code> (as in prev version), // so that the view would be catching up with a mouse pointer snapLast = snapCurrent; if (overlayed && offscreen != null) { dirty.add( graph.toScreen( AbstractCellView.getBounds(views))); Rectangle t = graph.toScreen( AbstractCellView.getBounds( contextViews)); if (t != null) dirty.add(t); dirty.grow(2, 2); int sx1 = (GraphConstants.NEGATIVE_ALLOWED) ? dirty.x : Math.max(0, dirty.x); int sy1 = (GraphConstants.NEGATIVE_ALLOWED) ? dirty.y : Math.max(0, dirty.y); int sx2 = sx1 + dirty.width; int sy2 = sy1 + dirty.height; if (isDragging && !DNDPREVIEW) // JDK BUG! return; graph.getGraphics().drawImage( offscreen, sx1, sy1, sx2, sy2, sx1, sy1, sx2,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -