001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.diff.builtin.visualizer.editable;
042:
043: import org.openide.util.NbBundle;
044:
045: import javax.swing.plaf.basic.BasicSplitPaneDivider;
046: import javax.swing.plaf.basic.BasicSplitPaneUI;
047: import javax.swing.border.Border;
048: import javax.swing.*;
049: import javax.accessibility.Accessible;
050: import javax.accessibility.AccessibleContext;
051: import java.awt.*;
052: import java.awt.event.MouseEvent;
053: import java.awt.event.MouseMotionListener;
054: import java.awt.event.MouseListener;
055: import java.awt.geom.CubicCurve2D;
056: import java.awt.geom.GeneralPath;
057: import java.util.*;
058: import java.util.List;
059:
060: /**
061: * Split pane divider with Diff decorations.
062: *
063: * @author Maros Sandor
064: */
065: class DiffSplitPaneDivider extends BasicSplitPaneDivider implements
066: MouseMotionListener, MouseListener, Accessible {
067:
068: private final Image insertAllImage = org.openide.util.Utilities
069: .loadImage("org/netbeans/modules/diff/builtin/visualizer/editable/move_all.png"); // NOI18N
070: private final Image insertAllActiveImage = org.openide.util.Utilities
071: .loadImage("org/netbeans/modules/diff/builtin/visualizer/editable/move_all_active.png"); // NOI18N
072: private final int actionIconsHeight;
073: private final int actionIconsWidth;
074: private final Point POINT_ZERO = new Point(0, 0);
075:
076: private final EditableDiffView master;
077:
078: private Point lastMousePosition = POINT_ZERO;
079: private HotSpot lastHotSpot = null;
080: private java.util.List<HotSpot> hotspots = new ArrayList<HotSpot>(0);
081:
082: private DiffSplitDivider mydivider;
083:
084: DiffSplitPaneDivider(BasicSplitPaneUI splitPaneUI,
085: EditableDiffView master) {
086: super (splitPaneUI);
087: this .master = master;
088:
089: actionIconsHeight = insertAllImage.getHeight(this );
090: actionIconsWidth = insertAllImage.getWidth(this );
091:
092: setBorder(null);
093: setLayout(new BorderLayout());
094: mydivider = new DiffSplitDivider();
095: add(mydivider);
096:
097: addMouseListener(this );
098: addMouseMotionListener(this );
099: }
100:
101: public void mouseClicked(MouseEvent e) {
102: if (!e.isPopupTrigger()) {
103: HotSpot spot = getHotspotAt(e.getPoint());
104: if (spot != null) {
105: performAction(); // there is only one hotspot
106: }
107: }
108: }
109:
110: public void mouseExited(MouseEvent e) {
111: lastMousePosition = POINT_ZERO;
112: if (lastHotSpot != null) {
113: mydivider.repaint(lastHotSpot.getRect());
114: }
115: lastHotSpot = null;
116: }
117:
118: public void mouseEntered(MouseEvent e) {
119: // not interested
120: }
121:
122: public void mousePressed(MouseEvent e) {
123: // not interested
124: }
125:
126: public void mouseReleased(MouseEvent e) {
127: // not interested
128: }
129:
130: public void mouseDragged(MouseEvent e) {
131: // not interested
132: }
133:
134: public void mouseMoved(MouseEvent e) {
135: Point p = e.getPoint();
136: lastMousePosition = p;
137: HotSpot spot = getHotspotAt(p);
138: if (lastHotSpot != spot) {
139: mydivider.repaint(lastHotSpot == null ? spot.getRect()
140: : lastHotSpot.getRect());
141: }
142: lastHotSpot = spot;
143: setCursor(spot != null ? Cursor
144: .getPredefinedCursor(Cursor.HAND_CURSOR) : Cursor
145: .getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
146: }
147:
148: private void performAction() {
149: master.rollback(null);
150: }
151:
152: public void setBorder(Border border) {
153: super .setBorder(BorderFactory.createEmptyBorder());
154: }
155:
156: DiffSplitDivider getDivider() {
157: return mydivider;
158: }
159:
160: private HotSpot getHotspotAt(Point p) {
161: for (HotSpot hotspot : hotspots) {
162: if (hotspot.getRect().contains(p)) {
163: return hotspot;
164: }
165: }
166: return null;
167: }
168:
169: private class DiffSplitDivider extends JPanel {
170:
171: private Map renderingHints;
172:
173: public DiffSplitDivider() {
174: setBackground(UIManager.getColor("SplitPane.background")); // NOI18N
175: setOpaque(true);
176: renderingHints = (Map) (Toolkit.getDefaultToolkit()
177: .getDesktopProperty("awt.font.desktophints")); // NOI18N
178: }
179:
180: public String getToolTipText(MouseEvent event) {
181: Point p = event.getPoint();
182: HotSpot spot = getHotspotAt(p);
183: if (spot == null)
184: return null;
185: return NbBundle.getMessage(DiffSplitDivider.class,
186: "TT_DiffPanel_MoveAll"); // NOI18N
187: }
188:
189: protected void paintComponent(Graphics gr) {
190: Graphics2D g = (Graphics2D) gr.create();
191: Rectangle clip = g.getClipBounds();
192: Stroke cs = g.getStroke();
193:
194: g.setColor(getBackground());
195: g.fillRect(clip.x, clip.y, clip.width, clip.height);
196:
197: if (master.getEditorPane1() == null) {
198: g.dispose();
199: return;
200: }
201:
202: Rectangle rightView = master.getEditorPane2()
203: .getScrollPane().getViewport().getViewRect();
204: Rectangle leftView = master.getEditorPane1()
205: .getScrollPane().getViewport().getViewRect();
206:
207: int editorsOffset = master.getEditorPane2().getLocation().y
208: + master.getEditorPane2().getInsets().top;
209:
210: int rightOffset = -rightView.y + editorsOffset;
211: int leftOffset = -leftView.y + editorsOffset;
212:
213: if (renderingHints != null) {
214: g.addRenderingHints(renderingHints);
215: }
216: String diffInfo = (master.getCurrentDifference() + 1) + "/"
217: + master.getDifferenceCount(); // NOI18N
218: int width = g.getFontMetrics().stringWidth(diffInfo);
219: g.setColor(Color.BLACK);
220: g.drawString(diffInfo, (getWidth() - width) / 2, g
221: .getFontMetrics().getHeight());
222:
223: if (clip.y < editorsOffset) {
224: g.setClip(clip.x, editorsOffset, clip.width,
225: clip.height);
226: }
227:
228: int rightY = getWidth() - 1;
229:
230: g.setColor(Color.LIGHT_GRAY);
231: g.drawLine(0, clip.y, 0, clip.height);
232: g.drawLine(rightY, clip.y, rightY, clip.height);
233:
234: int curDif = master.getCurrentDifference();
235:
236: g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
237: RenderingHints.VALUE_ANTIALIAS_ON);
238: DiffViewManager.DecoratedDifference[] decoratedDiffs = master
239: .getManager().getDecorations();
240: int idx = 0;
241: boolean everythingEditable = true;
242: for (DiffViewManager.DecoratedDifference dd : decoratedDiffs) {
243: everythingEditable &= dd.canRollback();
244: g.setColor(master.getColor(dd.getDiff()));
245: g.setStroke(curDif == idx++ ? master.getBoldStroke()
246: : cs);
247: if (dd.getBottomLeft() == -1) {
248: paintMatcher(g, master.getColor(dd.getDiff()), 0,
249: rightY, dd.getTopLeft() + leftOffset, dd
250: .getTopRight()
251: + rightOffset, dd.getBottomRight()
252: + rightOffset, dd.getTopLeft()
253: + leftOffset);
254: } else if (dd.getBottomRight() == -1) {
255: paintMatcher(g, master.getColor(dd.getDiff()), 0,
256: rightY, dd.getTopLeft() + leftOffset, dd
257: .getTopRight()
258: + rightOffset, dd.getTopRight()
259: + rightOffset, dd.getBottomLeft()
260: + leftOffset);
261: } else {
262: paintMatcher(g, master.getColor(dd.getDiff()), 0,
263: rightY, dd.getTopLeft() + leftOffset, dd
264: .getTopRight()
265: + rightOffset, dd.getBottomRight()
266: + rightOffset, dd.getBottomLeft()
267: + leftOffset);
268: }
269: }
270:
271: if (master.isActionsEnabled() && everythingEditable) {
272: List<HotSpot> newActionIcons = new ArrayList<HotSpot>();
273: Rectangle hotSpot = new Rectangle(
274: (getWidth() - actionIconsWidth) / 2,
275: editorsOffset, actionIconsWidth,
276: actionIconsHeight);
277: if (hotSpot.contains(lastMousePosition)) {
278: g.drawImage(insertAllActiveImage, hotSpot.x,
279: hotSpot.y, this );
280: } else {
281: g.drawImage(insertAllImage, hotSpot.x, hotSpot.y,
282: this );
283: }
284: newActionIcons.add(new HotSpot(hotSpot, null));
285: hotspots = newActionIcons;
286: }
287: g.dispose();
288: }
289:
290: private void paintMatcher(Graphics2D g, Color fillClr,
291: int leftX, int rightX, int upL, int upR, int doR,
292: int doL) {
293: CubicCurve2D upper = new CubicCurve2D.Float(leftX, upL,
294: (rightX - leftX) * .3f, upL,
295: (rightX - leftX) * .7f, upR, rightX, upR);
296: CubicCurve2D bottom = new CubicCurve2D.Float(rightX, doR,
297: (rightX - leftX) * .7f, doR,
298: (rightX - leftX) * .3f, doL, leftX, doL);
299: GeneralPath path = new GeneralPath();
300: path.append(upper, false);
301: path.append(bottom, true);
302: path.closePath();
303: g.setColor(fillClr);
304: g.fill(path);
305: g.setColor(master.getColorLines());
306: g.draw(upper);
307: g.draw(bottom);
308: }
309: }
310: }
|