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:
042: package org.netbeans.modules.diff.builtin.visualizer.editable;
043:
044: import org.netbeans.api.diff.Difference;
045: import org.netbeans.spi.editor.highlighting.HighlightsContainer;
046: import org.netbeans.spi.editor.highlighting.HighlightsSequence;
047: import org.netbeans.spi.editor.highlighting.HighlightsChangeListener;
048: import org.netbeans.spi.editor.highlighting.HighlightsChangeEvent;
049:
050: import javax.swing.*;
051: import javax.swing.text.AttributeSet;
052: import javax.swing.text.DefaultEditorKit;
053: import javax.swing.text.EditorKit;
054: import javax.accessibility.AccessibleContext;
055: import java.awt.*;
056: import java.util.*;
057: import java.util.List;
058:
059: /**
060: * Represents left and/or right side of the main split pane.
061: *
062: * @author Maros Sandor
063: */
064: class DiffContentPanel extends JPanel implements HighlightsContainer {
065:
066: private final EditableDiffView master;
067: private final boolean isFirst;
068:
069: private final DecoratedEditorPane editorPane;
070: private JScrollPane scrollPane;
071: private final LineNumbersActionsBar linesActions;
072: private final JScrollPane actionsScrollPane;
073:
074: private Difference[] currentDiff;
075:
076: public DiffContentPanel(EditableDiffView master, boolean isFirst) {
077: this .master = master;
078: this .isFirst = isFirst;
079:
080: setLayout(new BorderLayout());
081:
082: editorPane = new DecoratedEditorPane(this );
083: editorPane.setEditable(false);
084: scrollPane = new JScrollPane(editorPane);
085: add(scrollPane);
086:
087: linesActions = new LineNumbersActionsBar(this , master
088: .isActionsEnabled());
089: actionsScrollPane = new JScrollPane(linesActions);
090: actionsScrollPane
091: .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
092: actionsScrollPane
093: .setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
094: actionsScrollPane.setBorder(null);
095: add(actionsScrollPane, isFirst ? BorderLayout.LINE_END
096: : BorderLayout.LINE_START);
097:
098: editorPane.putClientProperty(
099: DiffHighlightsLayerFactory.HIGHLITING_LAYER_ID, this );
100: if (!isFirst) {
101: editorPane.putClientProperty("errorStripeOnly",
102: Boolean.TRUE);
103: editorPane.putClientProperty("code-folding-enable", false);
104: }
105: }
106:
107: void initActions() {
108: //TODO: copied from CloneableEditor - this has no effect
109: ActionMap paneMap = editorPane.getActionMap();
110: ActionMap am = getActionMap();
111: am.setParent(paneMap);
112: paneMap.put(DefaultEditorKit.cutAction,
113: getAction(DefaultEditorKit.cutAction));
114: paneMap.put(DefaultEditorKit.copyAction,
115: getAction(DefaultEditorKit.copyAction));
116: paneMap.put("delete",
117: getAction(DefaultEditorKit.deleteNextCharAction)); // NOI18N
118: paneMap.put(DefaultEditorKit.pasteAction,
119: getAction(DefaultEditorKit.pasteAction));
120: }
121:
122: private Action getAction(String key) {
123: if (key == null) {
124: return null;
125: }
126:
127: // Try to find the action from kit.
128: EditorKit kit = editorPane.getEditorKit();
129:
130: if (kit == null) { // kit is cleared in closeDocument()
131:
132: return null;
133: }
134:
135: Action[] actions = kit.getActions();
136:
137: for (int i = 0; i < actions.length; i++) {
138: if (key.equals(actions[i].getValue(Action.NAME))) {
139: return actions[i];
140: }
141: }
142:
143: return null;
144: }
145:
146: LineNumbersActionsBar getLinesActions() {
147: return linesActions;
148: }
149:
150: public JScrollPane getActionsScrollPane() {
151: return actionsScrollPane;
152: }
153:
154: public JScrollPane getScrollPane() {
155: return scrollPane;
156: }
157:
158: public Difference[] getCurrentDiff() {
159: return currentDiff;
160: }
161:
162: public boolean isFirst() {
163: return isFirst;
164: }
165:
166: public void setCurrentDiff(Difference[] currentDiff) {
167: this .currentDiff = currentDiff;
168: editorPane.setDifferences(currentDiff);
169: linesActions.onDiffSetChanged();
170: fireHilitingChanged();
171: // revalidate();
172: }
173:
174: public Dimension getPreferredSize() {
175: Dimension d = super .getPreferredSize();
176: Container parent = getParent();
177: if (parent instanceof JViewport) {
178: if (parent.getWidth() > d.width) {
179: d = new Dimension(parent.getWidth(), d.height);
180: }
181: }
182: return d;
183: }
184:
185: public DecoratedEditorPane getEditorPane() {
186: return editorPane;
187: }
188:
189: public AccessibleContext getAccessibleContext() {
190: return editorPane.getAccessibleContext();
191: }
192:
193: public EditableDiffView getMaster() {
194: return master;
195: }
196:
197: // === Highliting ========================================================================
198:
199: HighlightsContainer getHighlightsContainer() {
200: return this ;
201: }
202:
203: public HighlightsSequence getHighlights(int start, int end) {
204: return new DiffHighlightsSequence(start, end);
205: }
206:
207: private final List<HighlightsChangeListener> listeners = new ArrayList<HighlightsChangeListener>(
208: 1);
209:
210: public void addHighlightsChangeListener(
211: HighlightsChangeListener listener) {
212: synchronized (listeners) {
213: listeners.add(listener);
214: }
215: }
216:
217: public void removeHighlightsChangeListener(
218: HighlightsChangeListener listener) {
219: synchronized (listeners) {
220: listeners.remove(listener);
221: }
222: }
223:
224: void fireHilitingChanged() {
225: synchronized (listeners) {
226: for (HighlightsChangeListener listener : listeners) {
227: listener.highlightChanged(new HighlightsChangeEvent(
228: this , 0, Integer.MAX_VALUE));
229: }
230: }
231: }
232:
233: void onUISettingsChanged() {
234: editorPane.repaint();
235: linesActions.onUISettingsChanged();
236: actionsScrollPane.revalidate();
237: actionsScrollPane.repaint();
238: revalidate();
239: repaint();
240: }
241:
242: public void setCustomEditor(JComponent c) {
243: remove(scrollPane);
244: // The present editorPane will already be wrapped with the new custom editor
245: // including the new scrollpane that needs to be re-assigned
246: Component viewPort = editorPane.getParent();
247: if (viewPort instanceof JViewport) {
248: viewPort = viewPort.getParent();
249: if (viewPort instanceof JScrollPane) {
250: scrollPane = (JScrollPane) viewPort;
251: add(c);
252: }
253: }
254: }
255:
256: /**
257: * Iterates over all found differences.
258: */
259: private class DiffHighlightsSequence implements HighlightsSequence {
260:
261: private final int endOffset;
262: private final int startOffset;
263:
264: private int currentHiliteIndex = -1;
265: private DiffViewManager.HighLight[] hilites;
266:
267: public DiffHighlightsSequence(int start, int end) {
268: this .startOffset = start;
269: this .endOffset = end;
270: lookupHilites();
271: }
272:
273: private void lookupHilites() {
274: List<DiffViewManager.HighLight> list = new ArrayList<DiffViewManager.HighLight>();
275: DiffViewManager.HighLight[] allHilites = isFirst ? master
276: .getManager().getFirstHighlights() : master
277: .getManager().getSecondHighlights();
278: for (DiffViewManager.HighLight hilite : allHilites) {
279: if (hilite.getEndOffset() < startOffset)
280: continue;
281: if (hilite.getStartOffset() > endOffset)
282: break;
283: list.add(hilite);
284: }
285: hilites = list.toArray(new DiffViewManager.HighLight[list
286: .size()]);
287: }
288:
289: public boolean moveNext() {
290: if (currentHiliteIndex >= hilites.length - 1)
291: return false;
292: currentHiliteIndex++;
293: return true;
294: }
295:
296: public int getStartOffset() {
297: return hilites[currentHiliteIndex].getStartOffset();
298: }
299:
300: public int getEndOffset() {
301: return hilites[currentHiliteIndex].getEndOffset();
302: }
303:
304: public AttributeSet getAttributes() {
305: return hilites[currentHiliteIndex].getAttrs();
306: }
307: }
308: }
|