/*******************************************************************************
* Copyright (c) 2008-2011 Chair for Applied Software Engineering,
* Technische Universitaet Muenchen.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
******************************************************************************/
package org.eclipse.emf.emfstore.client.ui.dialogs.merge.ui.widgets;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.Conflict;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.ConflictOption;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.options.MergeTextOption;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.ui.DecisionBox;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.ui.components.DetailsComponent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.ui.forms.widgets.TableWrapLayout;
import diff.match.patch.diff_match_patch;
import diff.match.patch.diff_match_patch.Diff;
import diff.match.patch.diff_match_patch.Operation;
/**
* Is used to display longer conflicting text and to merge them.
*
* @author wesendon
*/
public class MergeTextWidget implements Observer {
private final DecisionBox decisionBox;
private ArrayList<ConflictOption> options;
private TabFolder tabFolder;
private final DetailsComponent detailsComponent;
/**
* Default constructor.
*
* @param decisionBox container
* @param detailsComponent details component
*/
public MergeTextWidget(DecisionBox decisionBox, DetailsComponent detailsComponent) {
this.decisionBox = decisionBox;
this.detailsComponent = detailsComponent;
options = new ArrayList<ConflictOption>();
decisionBox.getConflict().addObserver(this);
}
/**
* Add involved ConflictOptions.
*
* @param option option
*/
public void addOption(ConflictOption option) {
options.add(option);
}
/**
* Called by container in order to build gui.
*
* @param parent container
*/
public void createContent(Composite parent) {
tabFolder = new TabFolder(parent, SWT.NONE);
tabFolder.setBackground(parent.getBackground());
tabFolder.setLayout(new TableWrapLayout());
for (ConflictOption option : options) {
createTab(tabFolder, option);
}
}
private void createTab(TabFolder tabFolder, ConflictOption option) {
TabItem tab = new TabItem(tabFolder, SWT.NONE);
tab.setText(getTitle(option));
StyledText text = new StyledText(tabFolder, SWT.MULTI | SWT.WRAP);
setText(option, text);
text.setBackground(tabFolder.getBackground());
text.setEditable(isEditable(option));
text.setWordWrap(true);
// text.setTopMargin(5);
// text.setLeftMargin(5);
// text.setRightMargin(5);
tab.setControl(text);
}
private void setText(ConflictOption option, final StyledText styledText) {
if (option instanceof MergeTextOption) {
handleMergeTextOption(option, styledText);
} else {
styledText.setText(option.getFullOptionLabel());
}
}
private void handleMergeTextOption(ConflictOption option, final StyledText styledText) {
final MergeTextOption mergeOption = (MergeTextOption) option;
diff_match_patch dmp = new diff_match_patch();
dmp.Diff_EditCost = 10;
LinkedList<Diff> diffMain = dmp.diff_main(mergeOption.getMyText(), mergeOption.getTheirString());
dmp.diff_cleanupEfficiency(diffMain);
String description = "";
List<StyleRange> styleRanges = new ArrayList<StyleRange>();
for (Diff diff : diffMain) {
String text = diff.text;
if (!diff.operation.equals(Operation.EQUAL)) {
StyleRange styleRange = new StyleRange();
styleRange.start = description.length();
styleRange.length = text.length();
if (diff.operation.equals(Operation.DELETE)) {
styleRange.foreground = Display.getDefault().getSystemColor(SWT.COLOR_RED);
} else if (diff.operation.equals(Operation.INSERT)) {
styleRange.foreground = Display.getDefault().getSystemColor(SWT.COLOR_DARK_GREEN);
}
styleRanges.add(styleRange);
}
description += text;
}
styledText.setText(description);
styledText.setStyleRanges(styleRanges.toArray(new StyleRange[styleRanges.size()]));
styledText.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
String newText = styledText.getText();
String oldText = mergeOption.getMergedText();
if (newText != null && !newText.equals(oldText)) {
mergeOption.setMergedText(newText);
decisionBox.setSolution(mergeOption);
}
}
});
}
private boolean isEditable(ConflictOption option) {
return option instanceof MergeTextOption;
}
private String getTitle(ConflictOption option) {
switch (option.getType()) {
case MyOperation:
return "My Version";
case TheirOperation:
return "Version from Repository";
case Custom:
case MergeText:
return option.getOptionLabel();
default:
return "";
}
}
/**
* {@inheritDoc}
*
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
public void update(Observable o, Object arg) {
Conflict conflict = decisionBox.getConflict();
if (conflict != null && conflict == o) {
ConflictOption solution = conflict.getSolution();
if (solution instanceof MergeTextOption) {
for (int i = 0; i < options.size(); i++) {
if (options.get(i) == solution) {
detailsComponent.setExpanded(true);
tabFolder.setSelection(i);
}
}
}
}
}
}