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.localhistory.ui.view;
042:
043: import java.awt.BorderLayout;
044: import java.awt.Component;
045: import java.awt.event.ActionEvent;
046: import java.awt.event.ActionListener;
047: import java.beans.PropertyChangeEvent;
048: import java.beans.PropertyChangeListener;
049: import java.io.*;
050: import java.util.logging.Level;
051: import javax.swing.*;
052:
053: import org.netbeans.api.diff.*;
054: import org.netbeans.modules.localhistory.LocalHistory;
055: import org.netbeans.modules.localhistory.store.StoreEntry;
056: import org.netbeans.modules.localhistory.utils.FileUtils;
057: import org.netbeans.modules.versioning.util.NoContentPanel;
058: import org.netbeans.modules.versioning.util.Utils;
059: import org.netbeans.modules.versioning.util.VersioningEvent;
060: import org.netbeans.modules.versioning.util.VersioningListener;
061: import org.openide.filesystems.FileObject;
062: import org.openide.filesystems.FileUtil;
063: import org.openide.explorer.ExplorerManager;
064: import org.openide.loaders.DataObject;
065: import org.openide.loaders.DataObjectNotFoundException;
066: import org.openide.nodes.Node;
067: import org.openide.util.NbBundle;
068: import org.openide.util.RequestProcessor;
069: import org.openide.util.Lookup;
070: import org.openide.util.lookup.Lookups;
071:
072: /**
073: *
074: * @author Tomas Stupka
075: */
076: public class LocalHistoryDiffView implements PropertyChangeListener,
077: ActionListener, VersioningListener {
078:
079: private final LocalHistoryTopComponent master;
080: private DiffPanel panel;
081: private Component diffComponent;
082: private DiffController diffView;
083: private DiffPrepareTask prepareTask = null;
084:
085: /** Creates a new instance of LocalHistoryView */
086: public LocalHistoryDiffView(LocalHistoryTopComponent master) {
087: this .master = master;
088: panel = new DiffPanel();
089: panel.nextButton.addActionListener(this );
090: panel.prevButton.addActionListener(this );
091: LocalHistory.getInstance().addVersioningListener(this );
092: showNoContent(NbBundle.getMessage(LocalHistoryDiffView.class,
093: "MSG_DiffPanel_NoVersion"));
094: }
095:
096: public void propertyChange(PropertyChangeEvent evt) {
097: if (ExplorerManager.PROP_SELECTED_NODES.equals(evt
098: .getPropertyName())) {
099: disableNavigationButtons();
100: selectionChanged(evt);
101: } else if (DiffController.PROP_DIFFERENCES.equals(evt
102: .getPropertyName())) {
103: refreshNavigationButtons();
104: }
105: }
106:
107: public void versioningEvent(VersioningEvent event) {
108: if (event.getId() != LocalHistory.EVENT_FILE_CREATED) {
109: return;
110: }
111: File file = (File) event.getParams()[0];
112: if (file == null || prepareTask == null
113: || !file.equals(prepareTask.entry.getFile())) {
114: return;
115: }
116: scheduleTask(prepareTask);
117: }
118:
119: JPanel getPanel() {
120: return panel;
121: }
122:
123: private void selectionChanged(PropertyChangeEvent evt) {
124: Node[] newSelection = ((Node[]) evt.getNewValue());
125: if (newSelection == null || newSelection.length == 0) {
126: showNoContent(NbBundle.getMessage(
127: LocalHistoryDiffView.class,
128: "MSG_DiffPanel_NoVersion"));
129: return;
130: }
131:
132: StoreEntry se = newSelection[0].getLookup().lookup(
133: StoreEntry.class);
134:
135: if (se == null) {
136: showNoContent(NbBundle.getMessage(
137: LocalHistoryDiffView.class,
138: "MSG_DiffPanel_IllegalSelection"));
139: return;
140: }
141: refreshDiffPanel(se);
142: }
143:
144: private void refreshDiffPanel(StoreEntry se) {
145: prepareTask = new DiffPrepareTask(se);
146: scheduleTask(prepareTask);
147: }
148:
149: private static void scheduleTask(Runnable runnable) {
150: RequestProcessor.Task task = RequestProcessor.getDefault()
151: .create(runnable);
152: task.schedule(0);
153: }
154:
155: private class DiffPrepareTask implements Runnable {
156:
157: private final StoreEntry entry;
158:
159: public DiffPrepareTask(final StoreEntry se) {
160: entry = se;
161: }
162:
163: public void run() {
164: // XXX how to get the mimetype
165:
166: SwingUtilities.invokeLater(new Runnable() {
167: public void run() {
168: try {
169:
170: File file = entry.getFile();
171:
172: File tempFolder = Utils.getTempFolder();
173: File tmpHistoryFile = new File(tempFolder, file
174: .getName());
175: tmpHistoryFile.deleteOnExit();
176: FileUtils.copy(entry.getStoreFileInputStream(),
177: tmpHistoryFile);
178: Utils.associateEncoding(file, tmpHistoryFile);
179:
180: StreamSource ss1 = new LHStreamSource(
181: tmpHistoryFile,
182: entry.getFile().getName()
183: + " "
184: + StoreEntryNode
185: .getFormatedDate(entry),
186: entry.getMIMEType());
187:
188: String title;
189: StreamSource ss2;
190: if (file.exists()) {
191: title = NbBundle.getMessage(
192: LocalHistoryDiffView.class,
193: "LBL_Diff_CurrentFile");
194: ss2 = new LHStreamSource(file, title, entry
195: .getMIMEType());
196: } else {
197: title = NbBundle.getMessage(
198: LocalHistoryDiffView.class,
199: "LBL_Diff_FileDeleted");
200: ss2 = StreamSource.createSource(
201: "currentfile", title, entry
202: .getMIMEType(),
203: new StringReader(""));
204: }
205:
206: diffView = DiffController.create(ss1, ss2);
207: diffView
208: .addPropertyChangeListener(LocalHistoryDiffView.this );
209:
210: JComponent c = diffView.getJComponent();
211: setDiffComponent(c);
212: master.setDiffView(c);
213: if (diffView.getDifferenceCount() > 0) {
214: setCurrentDifference(0);
215: } else {
216: refreshNavigationButtons();
217: }
218: panel.revalidate();
219: panel.repaint();
220:
221: } catch (IOException ioe) {
222: LocalHistory.LOG.log(Level.SEVERE, null, ioe);
223: }
224: }
225: });
226: }
227: }
228:
229: private void showNoContent(String s) {
230: setDiffComponent(new NoContentPanel(s));
231: }
232:
233: private void setDiffComponent(Component component) {
234: //int dl = panel.splitPane.getDividerLocation();
235: if (diffComponent != null) {
236: panel.diffPanel.remove(diffComponent);
237: }
238: panel.diffPanel.add(component, BorderLayout.CENTER);
239: diffComponent = component;
240: panel.diffPanel.revalidate();
241: panel.diffPanel.repaint();
242: //panel.splitPane.setDividerLocation(dl);
243: }
244:
245: public void actionPerformed(ActionEvent evt) {
246: if (evt.getSource() == panel.nextButton) {
247: onNextButton();
248: } else if (evt.getSource() == panel.prevButton) {
249: onPrevButton();
250: }
251: }
252:
253: private void onNextButton() {
254: if (diffView == null) {
255: return;
256: }
257: int nextDiffernce = diffView.getDifferenceIndex() + 1;
258: if (nextDiffernce < diffView.getDifferenceCount()) {
259: setCurrentDifference(nextDiffernce);
260: }
261: }
262:
263: private void onPrevButton() {
264: if (diffView == null) {
265: return;
266: }
267: int prevDiffernce = diffView.getDifferenceIndex() - 1;
268: if (prevDiffernce > -1) {
269: setCurrentDifference(prevDiffernce);
270: }
271: }
272:
273: private void setCurrentDifference(int idx) {
274: diffView.setLocation(DiffController.DiffPane.Modified,
275: DiffController.LocationType.DifferenceIndex, idx);
276: refreshNavigationButtons();
277: }
278:
279: private void disableNavigationButtons() {
280: panel.prevButton.setEnabled(false);
281: panel.nextButton.setEnabled(false);
282: }
283:
284: private void refreshNavigationButtons() {
285: int currentDifference = diffView.getDifferenceIndex();
286: panel.prevButton.setEnabled(currentDifference > 0);
287: panel.nextButton.setEnabled(currentDifference < diffView
288: .getDifferenceCount() - 1);
289: }
290:
291: private class LHStreamSource extends StreamSource {
292:
293: private final File file;
294: private final String title;
295: private final String mimeType;
296:
297: public LHStreamSource(File file, String title, String mimeType) {
298: this .file = file;
299: this .title = title;
300: this .mimeType = mimeType;
301: }
302:
303: public boolean isEditable() {
304: FileObject fo = FileUtil.toFileObject(file);
305: return isPrimary(fo);
306: }
307:
308: private boolean isPrimary(FileObject fo) {
309: if (fo != null) {
310: try {
311: DataObject dao = DataObject.find(fo);
312: return fo.equals(dao.getPrimaryFile());
313: } catch (DataObjectNotFoundException e) {
314: // no dataobject, never mind
315: }
316: }
317: return true;
318: }
319:
320: public Lookup getLookup() {
321: FileObject fo = FileUtil.toFileObject(file);
322: if (fo != null && isPrimary(fo)) {
323: return Lookups.fixed(fo);
324: } else {
325: return Lookups.fixed();
326: }
327: }
328:
329: public String getName() {
330: return title;
331: }
332:
333: public String getTitle() {
334: return title;
335: }
336:
337: public String getMIMEType() {
338: return mimeType;
339: }
340:
341: public Reader createReader() throws IOException {
342: return new FileReader(file);
343: }
344:
345: public Writer createWriter(Difference[] conflicts)
346: throws IOException {
347: return null;
348: }
349: }
350:
351: }
|