001: /**
002: * LibreSource
003: * Copyright (C) 2004-2008 Artenum SARL / INRIA
004: * http://www.libresource.org - contact@artenum.com
005: *
006: * This file is part of the LibreSource software,
007: * which can be used and distributed under license conditions.
008: * The license conditions are provided in the LICENSE.TXT file
009: * at the root path of the packaging that enclose this file.
010: * More information can be found at
011: * - http://dev.libresource.org/home/license
012: *
013: * Initial authors :
014: *
015: * Guillaume Bort / INRIA
016: * Francois Charoy / Universite Nancy 2
017: * Julien Forest / Artenum
018: * Claude Godart / Universite Henry Poincare
019: * Florent Jouille / INRIA
020: * Sebastien Jourdain / INRIA / Artenum
021: * Yves Lerumeur / Artenum
022: * Pascal Molli / Universite Henry Poincare
023: * Gerald Oster / INRIA
024: * Mariarosa Penzi / Artenum
025: * Gerard Sookahet / Artenum
026: * Raphael Tani / INRIA
027: *
028: * Contributors :
029: *
030: * Stephane Bagnier / Artenum
031: * Amadou Dia / Artenum-IUP Blois
032: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
033: */package org.libresource.so6.plugin.compare;
034:
035: import org.eclipse.compare.CompareConfiguration;
036: import org.eclipse.compare.CompareEditorInput;
037: import org.eclipse.compare.CompareUI;
038: import org.eclipse.compare.IStreamContentAccessor;
039: import org.eclipse.compare.ITypedElement;
040: import org.eclipse.compare.ResourceNode;
041: import org.eclipse.compare.structuremergeviewer.DiffContainer;
042: import org.eclipse.compare.structuremergeviewer.DiffNode;
043: import org.eclipse.compare.structuremergeviewer.Differencer;
044: import org.eclipse.compare.structuremergeviewer.IStructureComparator;
045:
046: import org.eclipse.core.resources.IFile;
047: import org.eclipse.core.resources.IFolder;
048: import org.eclipse.core.resources.IResource;
049: import org.eclipse.core.runtime.CoreException;
050: import org.eclipse.core.runtime.IAdaptable;
051: import org.eclipse.core.runtime.IProgressMonitor;
052: import org.eclipse.core.runtime.IStatus;
053: import org.eclipse.core.runtime.Status;
054:
055: import org.eclipse.jface.dialogs.ProgressMonitorDialog;
056: import org.eclipse.jface.operation.IRunnableWithProgress;
057: import org.eclipse.jface.viewers.ColumnWeightData;
058: import org.eclipse.jface.viewers.IOpenListener;
059: import org.eclipse.jface.viewers.IStructuredContentProvider;
060: import org.eclipse.jface.viewers.ITableLabelProvider;
061: import org.eclipse.jface.viewers.LabelProvider;
062: import org.eclipse.jface.viewers.OpenEvent;
063: import org.eclipse.jface.viewers.StructuredSelection;
064: import org.eclipse.jface.viewers.TableLayout;
065: import org.eclipse.jface.viewers.TableViewer;
066: import org.eclipse.jface.viewers.Viewer;
067:
068: import org.eclipse.swt.SWT;
069: import org.eclipse.swt.graphics.Image;
070: import org.eclipse.swt.layout.GridData;
071: import org.eclipse.swt.widgets.Composite;
072: import org.eclipse.swt.widgets.Control;
073: import org.eclipse.swt.widgets.Shell;
074: import org.eclipse.swt.widgets.Table;
075: import org.eclipse.swt.widgets.TableColumn;
076:
077: import org.eclipse.team.internal.ui.Utils;
078: import org.eclipse.team.ui.ISaveableWorkbenchPart;
079:
080: import org.eclipse.ui.IPropertyListener;
081: import org.eclipse.ui.IWorkbenchPartSite;
082:
083: import org.libresource.so6.core.command.Command;
084: import org.libresource.so6.core.engine.DBType;
085: import org.libresource.so6.core.engine.OpVector;
086: import org.libresource.so6.core.engine.util.FileUtils;
087: import org.libresource.so6.plugin.Plugin;
088: import org.libresource.so6.plugin.core.So6Util;
089:
090: /**
091: * @author Guillaume Bort
092: */
093: import java.io.ByteArrayInputStream;
094: import java.io.File;
095: import java.io.FileInputStream;
096: import java.io.InputStream;
097:
098: import java.lang.reflect.InvocationTargetException;
099:
100: import java.text.SimpleDateFormat;
101:
102: import java.util.Iterator;
103: import java.util.ListIterator;
104: import java.util.Stack;
105: import java.util.Vector;
106:
107: /**
108: * DOCUMENT ME!
109: *
110: * @author $author$
111: * @version $Revision: 1.3 $
112: */
113: public class So6HistoryCompareInput extends CompareEditorInput
114: implements ISaveableWorkbenchPart {
115: private IResource resource;
116: private ITypedElement left;
117: private ITypedElement right;
118: private Shell shell;
119: private TableViewer viewer;
120: private Vector patchs;
121:
122: /**
123: * Creates a new So6HistoryCompareInput object.
124: *
125: * @param resource DOCUMENT ME!
126: *
127: * @throws Exception DOCUMENT ME!
128: */
129: public So6HistoryCompareInput(IResource resource) throws Exception {
130: super (new CompareConfiguration());
131: this .resource = resource;
132: setTitle("Compare " + resource.getName() + " with "
133: + resource.getName() + " (history)");
134: initLabels();
135: }
136:
137: /**
138: * DOCUMENT ME!
139: *
140: * @param listener DOCUMENT ME!
141: */
142: public void addPropertyListener(IPropertyListener listener) {
143: // noop
144: }
145:
146: /**
147: * DOCUMENT ME!
148: *
149: * @param parent DOCUMENT ME!
150: *
151: * @return DOCUMENT ME!
152: */
153: public Control createContents(Composite parent) {
154: Control c = super .createContents(parent);
155: c.setLayoutData(new GridData(GridData.FILL_BOTH));
156:
157: return c;
158: }
159:
160: /**
161: * DOCUMENT ME!
162: *
163: * @param parent DOCUMENT ME!
164: *
165: * @return DOCUMENT ME!
166: */
167: public Viewer createDiffViewer(Composite parent) {
168: Table table = new Table(parent, SWT.H_SCROLL | SWT.V_SCROLL
169: | SWT.MULTI | SWT.FULL_SELECTION);
170: table.setHeaderVisible(true);
171: table.setLinesVisible(true);
172:
173: GridData data = new GridData(GridData.FILL_BOTH);
174: table.setLayoutData(data);
175:
176: TableLayout layout = new TableLayout();
177: table.setLayout(layout);
178:
179: viewer = new TableViewer(table);
180:
181: // ticket
182: TableColumn col = new TableColumn(table, SWT.NONE);
183: col.setResizable(true);
184: col.setText("Ticket");
185: layout.addColumnData(new ColumnWeightData(5, true));
186:
187: // creation date
188: col = new TableColumn(table, SWT.NONE);
189: col.setResizable(true);
190: col.setText("Date");
191: layout.addColumnData(new ColumnWeightData(10, true));
192:
193: // author
194: col = new TableColumn(table, SWT.NONE);
195: col.setResizable(true);
196: col.setText("Workspace name");
197: layout.addColumnData(new ColumnWeightData(10, true));
198:
199: // comment
200: col = new TableColumn(table, SWT.NONE);
201: col.setResizable(true);
202: col.setText("Comment");
203: layout.addColumnData(new ColumnWeightData(50, true));
204:
205: viewer.setLabelProvider(new PatchTableLabelProvider());
206:
207: table.setData(CompareUI.COMPARE_VIEWER_TITLE, "History of "
208: + resource.getName());
209: viewer.setContentProvider(new VersionCompareContentProvider());
210:
211: viewer.addOpenListener(new IOpenListener() {
212: public void open(OpenEvent event) {
213: long ticket = ((Patch) ((VersionCompareDiffNode) ((StructuredSelection) event
214: .getSelection()).getFirstElement())
215: .getAdapter(Patch.class)).getToTicket();
216: getCompareConfiguration().setRightLabel(
217: "history of " + resource.getName() + " ("
218: + ticket + ")");
219: }
220: });
221:
222: return viewer;
223: }
224:
225: /**
226: * DOCUMENT ME!
227: *
228: * @param parent DOCUMENT ME!
229: */
230: public void createPartControl(Composite parent) {
231: createContents(parent);
232: }
233:
234: /**
235: * DOCUMENT ME!
236: */
237: public void dispose() {
238: }
239:
240: /**
241: * DOCUMENT ME!
242: *
243: * @param monitor DOCUMENT ME!
244: */
245: public void doSave(IProgressMonitor monitor) {
246: try {
247: saveChanges(monitor);
248: } catch (CoreException e) {
249: Utils.handle(e);
250: }
251: }
252:
253: /**
254: * DOCUMENT ME!
255: */
256: public void doSaveAs() {
257: // noop
258: }
259:
260: /**
261: * DOCUMENT ME!
262: *
263: * @return DOCUMENT ME!
264: */
265: public IWorkbenchPartSite getSite() {
266: return null;
267: }
268:
269: /**
270: * DOCUMENT ME!
271: *
272: * @return DOCUMENT ME!
273: */
274: public String getTitleToolTip() {
275: return null;
276: }
277:
278: /**
279: * DOCUMENT ME!
280: *
281: * @return DOCUMENT ME!
282: */
283: public Viewer getViewer() {
284: return viewer;
285: }
286:
287: /**
288: * DOCUMENT ME!
289: *
290: * @return DOCUMENT ME!
291: */
292: public boolean isDirty() {
293: return isSaveNeeded();
294: }
295:
296: /**
297: * DOCUMENT ME!
298: *
299: * @return DOCUMENT ME!
300: */
301: public boolean isSaveAsAllowed() {
302: return true;
303: }
304:
305: /**
306: * DOCUMENT ME!
307: *
308: * @return DOCUMENT ME!
309: */
310: public boolean isSaveOnCloseNeeded() {
311: return true;
312: }
313:
314: /**
315: * DOCUMENT ME!
316: *
317: * @param monitor DOCUMENT ME!
318: *
319: * @return DOCUMENT ME!
320: *
321: * @throws InvocationTargetException DOCUMENT ME!
322: * @throws InterruptedException DOCUMENT ME!
323: */
324: public Object prepareInput(IProgressMonitor monitor)
325: throws InvocationTargetException, InterruptedException {
326: DiffNode diffRoot = new DiffNode(Differencer.NO_CHANGE);
327: ITypedElement left = new TypedBufferedContent((IFile) resource);
328: patchs = So6Util.getPatchs(resource, monitor);
329:
330: if (monitor.isCanceled()) {
331: return null;
332: }
333:
334: for (Iterator i = patchs.iterator(); i.hasNext();) {
335: Patch patch = (Patch) i.next();
336: ITypedElement right = new So6HistoryResourceNode(patch);
337: diffRoot.add(new VersionCompareDiffNode(left, right));
338: }
339:
340: return diffRoot;
341: }
342:
343: /**
344: * DOCUMENT ME!
345: *
346: * @param listener DOCUMENT ME!
347: */
348: public void removePropertyListener(IPropertyListener listener) {
349: // noop
350: }
351:
352: private void initLabels() {
353: CompareConfiguration cc = getCompareConfiguration();
354: cc.setLeftLabel(resource.getName());
355: cc.setRightLabel(resource.getName());
356: cc.setLeftEditable(true);
357: cc.setRightEditable(false);
358: }
359:
360: class FolderResourceNode extends ResourceNode {
361: private Vector children;
362:
363: public FolderResourceNode(IResource resource) {
364: super (resource);
365: }
366:
367: public boolean equals(Object other) {
368: return other.hashCode() == hashCode();
369: }
370:
371: public Object[] getChildren() {
372: try {
373: if (children == null) {
374: Object[] o = super .getChildren();
375: children = new Vector();
376:
377: for (int i = 0; i < o.length; i++) {
378: if (!So6Util.isIgnored(((ResourceNode) o[i])
379: .getResource())) {
380: children
381: .add(new FolderResourceNode(
382: ((ResourceNode) o[i])
383: .getResource()));
384: }
385: }
386: }
387: } catch (Exception e) {
388: e.printStackTrace();
389: }
390:
391: if ((children == null) || (children.size() == 0)) {
392: return null;
393: }
394:
395: return children.toArray();
396: }
397:
398: public int hashCode() {
399: String path = "/"
400: + getResource().getProjectRelativePath().toString();
401:
402: return path.hashCode();
403: }
404: }
405:
406: class PatchTableLabelProvider extends LabelProvider implements
407: ITableLabelProvider {
408: public Image getColumnImage(Object element, int columnIndex) {
409: return null;
410: }
411:
412: public String getColumnText(Object element, int columnIndex) {
413: Patch patch = adaptToPatch(element);
414:
415: switch (columnIndex) {
416: case 0:
417: return patch.getToTicket() + "";
418:
419: case 1:
420: return new SimpleDateFormat("dd-MM-yy hh:mm")
421: .format(patch.getDate());
422:
423: case 2:
424: return patch.getFrom();
425:
426: case 3:
427: return patch.getComment();
428: }
429:
430: return "prout";
431: }
432:
433: protected Patch adaptToPatch(Object element) {
434: Patch patch = null;
435:
436: if (element instanceof Patch) {
437: patch = (Patch) element;
438: } else if (element instanceof IAdaptable) {
439: patch = (Patch) ((IAdaptable) element)
440: .getAdapter(Patch.class);
441: }
442:
443: return patch;
444: }
445: }
446:
447: class So6HistoryResourceNode implements IStructureComparator,
448: IStreamContentAccessor, ITypedElement {
449: protected Patch patch;
450: private So6HistoryResourceNode[] children;
451:
452: public So6HistoryResourceNode(Patch patch) {
453: this .patch = patch;
454: }
455:
456: public boolean equals(Object other) {
457: return other.hashCode() == hashCode();
458: }
459:
460: public Object[] getChildren() {
461: return new Object[0];
462: }
463:
464: public InputStream getContents() throws CoreException {
465: try {
466: Stack patchStack = new Stack();
467: Patch currentPatch = getPatch();
468:
469: while (currentPatch != null) {
470: patchStack.push(currentPatch);
471: currentPatch = currentPatch.getPrevious();
472: }
473:
474: File tmpDir = FileUtils.createTmpDir();
475: DBType dbType = new DBType("tutu", "");
476:
477: while (!patchStack.empty()) {
478: currentPatch = (Patch) patchStack.pop();
479:
480: OpVector cmds = currentPatch.getCmds();
481:
482: for (ListIterator i = cmds.getCommands(); i
483: .hasNext();) {
484: Command command = (Command) i.next();
485: command.setPath("A");
486: command.execute(tmpDir.getPath(), dbType);
487: }
488: }
489:
490: return new FileInputStream(new File(tmpDir, "A"));
491: } catch (Exception e) {
492: e.printStackTrace();
493: throw new CoreException(new Status(IStatus.ERROR,
494: Plugin.ID, IStatus.OK, e.getMessage(), e));
495: }
496: }
497:
498: public Image getImage() {
499: return CompareUI.getImage(getType());
500: }
501:
502: public String getName() {
503: return resource.getName();
504: }
505:
506: public Patch getPatch() {
507: return patch;
508: }
509:
510: public String getType() {
511: if (resource == null) {
512: return UNKNOWN_TYPE;
513: }
514:
515: if (resource instanceof IFolder) {
516: return FOLDER_TYPE;
517: }
518:
519: String name = resource.getName();
520: name = name.substring(name.lastIndexOf('.') + 1);
521:
522: return (name.length() == 0) ? UNKNOWN_TYPE : name;
523: }
524:
525: public int hashCode() {
526: return ("/" + resource.getProjectRelativePath().toString())
527: .hashCode();
528: }
529: }
530:
531: class TypedBufferedContent extends ResourceNode {
532: public TypedBufferedContent(IFile resource) {
533: super (resource);
534: }
535:
536: public void fireChange() {
537: fireContentChanged();
538: }
539:
540: public ITypedElement replace(ITypedElement child,
541: ITypedElement other) {
542: return null;
543: }
544:
545: public void setContent(byte[] contents) {
546: if (contents == null) {
547: contents = new byte[0];
548: }
549:
550: final InputStream is = new ByteArrayInputStream(contents);
551: IRunnableWithProgress runnable = new IRunnableWithProgress() {
552: public void run(IProgressMonitor monitor)
553: throws InvocationTargetException,
554: InterruptedException {
555: try {
556: IFile file = (IFile) resource;
557:
558: if (is != null) {
559: if (!file.exists()) {
560: file.create(is, false, monitor);
561: } else {
562: file.setContents(is, false, true,
563: monitor);
564: }
565: } else {
566: file.delete(false, true, monitor);
567: }
568: } catch (CoreException e) {
569: throw new InvocationTargetException(e);
570: }
571: }
572: };
573:
574: try {
575: new ProgressMonitorDialog(shell).run(false, false,
576: runnable);
577: } catch (InvocationTargetException e) {
578: e.printStackTrace();
579: } catch (InterruptedException e) {
580: // Ignore
581: }
582:
583: fireContentChanged();
584: }
585:
586: protected InputStream createStream() throws CoreException {
587: return ((IFile) getResource()).getContents();
588: }
589: }
590:
591: class VersionCompareContentProvider implements
592: IStructuredContentProvider {
593: public void dispose() {
594: }
595:
596: public Object[] getElements(Object inputElement) {
597: if (inputElement instanceof DiffContainer) {
598: return ((DiffContainer) inputElement).getChildren();
599: }
600:
601: return null;
602: }
603:
604: public void inputChanged(Viewer viewer, Object oldInput,
605: Object newInput) {
606: }
607: }
608:
609: class VersionCompareDiffNode extends DiffNode implements IAdaptable {
610: public VersionCompareDiffNode(ITypedElement left,
611: ITypedElement right) {
612: super (left, right);
613: }
614:
615: public void fireContentChanges() {
616: fireChange();
617: }
618:
619: public Object getAdapter(Class adapter) {
620: if (adapter == Patch.class) {
621: return ((So6HistoryResourceNode) getRight()).getPatch();
622: }
623:
624: return null;
625: }
626:
627: public String getName() {
628: return getRight().getName();
629: }
630: }
631: }
|