/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenFlexo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openflexo.swing.merge;
import java.awt.Adjustable;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.Observable;
import java.util.Observer;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import org.openflexo.diff.ComputeDiff;
import org.openflexo.diff.ComputeDiff.DiffReport;
import org.openflexo.diff.DelimitingMethod;
import org.openflexo.diff.DiffSource;
import org.openflexo.diff.merge.DetailedMerge;
import org.openflexo.diff.merge.MergeChange;
import org.openflexo.diff.merge.MergeChange.MergeChangeAction;
import org.openflexo.icon.UtilsIconLibrary;
import org.openflexo.jedit.JEditTextArea;
import org.openflexo.jedit.JEditTextAreaWithHighlights;
import org.openflexo.jedit.TokenMarker;
import org.openflexo.swing.VerticalLayout;
import org.openflexo.swing.diff.DiffPanel;
import org.openflexo.swing.merge.MergePanelElements.ComparePanel;
import org.openflexo.toolbox.TokenMarkerStyle;
public class DetailedMergeAnalysisPanel extends JDialog implements Observer {
MergePanelElements mergePanelElements;
DetailedMerge _detailedMerge;
private MergePanelElements.FilterChangeList changesList;
private ComparePanel comparePanel;
ReadOnlyTextArea mergedText;
ReadOnlyTextArea leftText;
ReadOnlyTextArea rightText;
ReadOnlyTextArea originalText;
private TokenMarkerStyle _style;
private static final int MAX_ROWS = 7;
private DiffReport _diffLeft = null;
private DiffReport _diffRight = null;
private DiffReport _diffLeftRight = null;
void updateHeader() {
String titleText = localizedForKey("detailed_analysis_for_conflict") + " [" + _detailedMerge.getDocumentType().getName() + "] "
+ " : [" + (_detailedMerge.isResolved() ? localizedForKey("resolved") : localizedForKey("unresolved")) + "]";
setTitle(titleText);
resolvedIcon.setIcon(_detailedMerge.isResolved() ? UtilsIconLibrary.ACCEPT_ICON : UtilsIconLibrary.REFUSE_ICON);
title.setText(titleText);
acceptButton.setEnabled(_detailedMerge.isResolved());
}
private JPanel header;
private JLabel resolvedIcon;
private JLabel title;
private JButton acceptButton;
private JButton cancelButton;
public DetailedMergeAnalysisPanel(DetailedMerge detailedMerge) {
super((Frame) null, true);
_detailedMerge = detailedMerge;
_detailedMerge.addObserver(this);
String original = detailedMerge.getChange().getOriginalText();
String left = detailedMerge.getChange().getTokenizedLeftText();
String right = detailedMerge.getChange().getTokenizedRightText();
_diffLeft = ComputeDiff.diff(left, original, detailedMerge.getDelimitingMethod());
;
_diffRight = ComputeDiff.diff(original, right, detailedMerge.getDelimitingMethod());
_diffLeftRight = ComputeDiff.diff(left, right, detailedMerge.getDelimitingMethod());
_style = detailedMerge.getDocumentType().getStyle();
JPanel content = new JPanel(new BorderLayout());
mergePanelElements = new MergePanelElements(detailedMerge, _style) {
@Override
public void selectChange(MergeChange change) {
super.selectChange(change);
DetailedMergeAnalysisPanel.this.selectChange(change);
}
@Override
public void update(Observable o, Object dataModification) {
super.update(o, dataModification);
if (o == getMerge() && dataModification instanceof MergeChange) {
updateHeader();
}
}
@Override
protected String localizedForKey(String key) {
return DetailedMergeAnalysisPanel.this.localizedForKey(key);
}
};
changesList = mergePanelElements.getChangesList();
changesList.setVisibleRowCount(5);
comparePanel = mergePanelElements.getComparePanel();
JScrollPane mergeTextArea = mergePanelElements.getMergePanel();
title = new JLabel(localizedForKey("detailed_analysis_for_conflict"), SwingConstants.LEFT);
title.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 5));
resolvedIcon = new JLabel(_detailedMerge.isResolved() ? UtilsIconLibrary.ACCEPT_ICON : UtilsIconLibrary.REFUSE_ICON);
JPanel titlePanel = new JPanel(new FlowLayout());
titlePanel.add(resolvedIcon);
titlePanel.add(title);
acceptButton = new JButton(localizedForKey("accept_merged_result"), UtilsIconLibrary.ACCEPT_ICON);
cancelButton = new JButton(localizedForKey("close"), UtilsIconLibrary.REFUSE_ICON);
cancelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dispose();
}
});
acceptButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
validateChanges();
}
});
JPanel buttonsPanel = new JPanel(new FlowLayout());
buttonsPanel.add(acceptButton);
buttonsPanel.add(cancelButton);
header = new JPanel(new BorderLayout());
header.add(titlePanel, BorderLayout.WEST);
header.add(buttonsPanel, BorderLayout.EAST);
content.add(header, BorderLayout.NORTH);
updateHeader();
JTabbedPane tabbedPane = new JTabbedPane();
JPanel mergePanel = new JPanel(new BorderLayout());
mergePanel.add(changesList, BorderLayout.EAST);
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, mergeTextArea, comparePanel);
splitPane.setDividerLocation(0.5);
splitPane.setResizeWeight(0.5);
Dimension dim = mergeTextArea.getPreferredSize();
dim.height = 280;
mergeTextArea.setPreferredSize(dim);
Dimension dim2 = comparePanel.getPreferredSize();
dim2.height = 300;
comparePanel.setPreferredSize(dim2);
splitPane.setDividerLocation(0.5);
mergePanel.add(splitPane, BorderLayout.CENTER);
tabbedPane.add(mergePanel, localizedForKey("detailed_merge"));
tabbedPane.add(new DiffPanel(_diffLeft, _style, BorderLayout.EAST), localizedForKey("left_original_diff"));
tabbedPane.add(new DiffPanel(_diffRight, _style, BorderLayout.EAST), localizedForKey("original_right_diff"));
tabbedPane.add(new DiffPanel(_diffLeftRight, _style, BorderLayout.EAST), localizedForKey("left_right_diff"));
content.add(tabbedPane, BorderLayout.CENTER);
/*controlPanel = mergePanelElements.getControlPanel();
add(controlPanel,BorderLayout.SOUTH);
JButton doneButton = new JButton();
doneButton.setText("Done");
doneButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
done();
}
});
controlPanel.add(doneButton);*/
int maxRows = 0;
int maxCols = 0;
DiffSource mergedSource = new DiffSource(_detailedMerge.getMergedSource().getText(), DelimitingMethod.LINES);
DiffSource leftSource = new DiffSource(_detailedMerge.getLeftSource().getText(), DelimitingMethod.LINES);
DiffSource rightSource = new DiffSource(_detailedMerge.getRightSource().getText(), DelimitingMethod.LINES);
DiffSource originalSource = new DiffSource(_detailedMerge.getOriginalSource().getText(), DelimitingMethod.LINES);
if (mergedSource.tokensCount() > maxRows) {
maxRows = mergedSource.tokensCount();
}
if (leftSource.tokensCount() > maxRows) {
maxRows = leftSource.tokensCount();
}
if (rightSource.tokensCount() > maxRows) {
maxRows = rightSource.tokensCount();
}
if (originalSource.tokensCount() > maxRows) {
maxRows = originalSource.tokensCount();
}
if (mergedSource.getMaxCols() > maxCols) {
maxCols = mergedSource.getMaxCols();
}
if (leftSource.getMaxCols() > maxCols) {
maxCols = leftSource.getMaxCols();
}
if (rightSource.getMaxCols() > maxCols) {
maxCols = rightSource.getMaxCols();
}
if (originalSource.getMaxCols() > maxCols) {
maxCols = originalSource.getMaxCols();
}
mergedText = new ReadOnlyTextArea(_detailedMerge.getMergedSource().getText(), _style);
mergedText.setColumns(maxCols);
mergedText.setRows(maxRows);
mergedText.validate();
leftText = new ReadOnlyTextArea(_detailedMerge.getLeftSource().getText(), _style);
leftText.setColumns(maxCols);
leftText.setRows(maxRows);
leftText.validate();
rightText = new ReadOnlyTextArea(_detailedMerge.getRightSource().getText(), _style);
rightText.setColumns(maxCols);
rightText.setRows(maxRows);
rightText.validate();
originalText = new ReadOnlyTextArea(_detailedMerge.getOriginalSource().getText(), _style);
originalText.setColumns(maxCols);
originalText.setRows(maxRows);
originalText.validate();
JPanel previewPanel = new JPanel(new VerticalLayout());
JPanel mergedTextPanel = new JPanel(new BorderLayout());
JLabel mergedTextLabel = new JLabel(localizedForKey("merged_result") + " ", SwingConstants.RIGHT);
mergedTextLabel.setVerticalAlignment(SwingConstants.TOP);
mergedTextLabel.setPreferredSize(new Dimension(120, 15));
mergedTextPanel.add(mergedTextLabel, BorderLayout.WEST);
mergedTextPanel.add(mergedText, BorderLayout.CENTER);
JPanel leftTextPanel = new JPanel(new BorderLayout());
JLabel leftTextLabel = new JLabel(localizedForKey("left_source") + " ", SwingConstants.RIGHT);
leftTextLabel.setVerticalAlignment(SwingConstants.TOP);
leftTextLabel.setPreferredSize(new Dimension(120, 15));
leftTextPanel.add(leftTextLabel, BorderLayout.WEST);
leftTextPanel.add(leftText, BorderLayout.CENTER);
JPanel rightTextPanel = new JPanel(new BorderLayout());
JLabel rightTextLabel = new JLabel(localizedForKey("right_source") + " ", SwingConstants.RIGHT);
rightTextLabel.setVerticalAlignment(SwingConstants.TOP);
rightTextLabel.setPreferredSize(new Dimension(120, 15));
rightTextPanel.add(rightTextLabel, BorderLayout.WEST);
rightTextPanel.add(rightText, BorderLayout.CENTER);
JPanel originalTextPanel = new JPanel(new BorderLayout());
JLabel originalTextLabel = new JLabel(localizedForKey("original_source") + " ", SwingConstants.RIGHT);
originalTextLabel.setVerticalAlignment(SwingConstants.TOP);
originalTextLabel.setPreferredSize(new Dimension(120, 15));
originalTextPanel.add(originalTextLabel, BorderLayout.WEST);
originalTextPanel.add(originalText, BorderLayout.CENTER);
previewPanel.add(mergedTextPanel);
previewPanel.add(leftTextPanel);
previewPanel.add(rightTextPanel);
previewPanel.add(originalTextPanel);
JPanel panel = new JPanel(new BorderLayout());
panel.add(previewPanel, BorderLayout.CENTER);
final JScrollBar horizontalScrollBar = new JScrollBar(Adjustable.HORIZONTAL);
int widthToScroll = mergedText.getPreferredSize().width;
horizontalScrollBar.setValues(-mergedText.getHorizontalOffset(), widthToScroll, 1, widthToScroll * 3);
horizontalScrollBar.setUnitIncrement(mergedText.getPainter().getFontMetrics().charWidth('W'));
horizontalScrollBar.setBlockIncrement(widthToScroll / 2);
horizontalScrollBar.addAdjustmentListener(new AdjustmentListener() {
@Override
public void adjustmentValueChanged(AdjustmentEvent e) {
mergedText.getHorizontalScrollBar().setValue(
e.getValue()
* (mergedText.getHorizontalScrollBar().getMaximum() - mergedText.getHorizontalScrollBar().getMinimum())
/ (horizontalScrollBar.getMaximum() - horizontalScrollBar.getMinimum()));
leftText.getHorizontalScrollBar().setValue(
e.getValue() * (leftText.getHorizontalScrollBar().getMaximum() - leftText.getHorizontalScrollBar().getMinimum())
/ (horizontalScrollBar.getMaximum() - horizontalScrollBar.getMinimum()));
rightText.getHorizontalScrollBar().setValue(
e.getValue() * (rightText.getHorizontalScrollBar().getMaximum() - rightText.getHorizontalScrollBar().getMinimum())
/ (horizontalScrollBar.getMaximum() - horizontalScrollBar.getMinimum()));
originalText.getHorizontalScrollBar().setValue(
e.getValue()
* (originalText.getHorizontalScrollBar().getMaximum() - originalText.getHorizontalScrollBar().getMinimum())
/ (horizontalScrollBar.getMaximum() - horizontalScrollBar.getMinimum()));
}
});
panel.add(horizontalScrollBar, BorderLayout.SOUTH);
if (maxRows > MAX_ROWS) {
mergedText.setPreferredSize(new Dimension(100, mergedText.getPainter().getFontMetrics().getHeight() * MAX_ROWS));
leftText.setPreferredSize(new Dimension(100, leftText.getPainter().getFontMetrics().getHeight() * MAX_ROWS));
rightText.setPreferredSize(new Dimension(100, rightText.getPainter().getFontMetrics().getHeight() * MAX_ROWS));
originalText.setPreferredSize(new Dimension(100, originalText.getPainter().getFontMetrics().getHeight() * MAX_ROWS));
final JScrollBar verticalScrollBar = new JScrollBar(Adjustable.VERTICAL);
int heightToScroll = mergedText.getPreferredSize().width;
verticalScrollBar.setValues(-mergedText.getHorizontalOffset(), heightToScroll, 1, heightToScroll * 3);
verticalScrollBar.setUnitIncrement(mergedText.getPainter().getFontMetrics().charWidth('W'));
verticalScrollBar.setBlockIncrement(heightToScroll / 2);
verticalScrollBar.addAdjustmentListener(new AdjustmentListener() {
@Override
public void adjustmentValueChanged(AdjustmentEvent e) {
mergedText.getVerticalScrollBar().setValue(
e.getValue()
* (mergedText.getVerticalScrollBar().getMaximum() - mergedText.getVerticalScrollBar().getMinimum())
/ (verticalScrollBar.getMaximum() - verticalScrollBar.getMinimum()));
leftText.getVerticalScrollBar().setValue(
e.getValue() * (leftText.getVerticalScrollBar().getMaximum() - leftText.getVerticalScrollBar().getMinimum())
/ (verticalScrollBar.getMaximum() - verticalScrollBar.getMinimum()));
rightText.getVerticalScrollBar().setValue(
e.getValue() * (rightText.getVerticalScrollBar().getMaximum() - rightText.getVerticalScrollBar().getMinimum())
/ (verticalScrollBar.getMaximum() - verticalScrollBar.getMinimum()));
originalText.getVerticalScrollBar().setValue(
e.getValue()
* (originalText.getVerticalScrollBar().getMaximum() - originalText.getVerticalScrollBar().getMinimum())
/ (verticalScrollBar.getMaximum() - verticalScrollBar.getMinimum()));
}
});
panel.add(verticalScrollBar, BorderLayout.EAST);
MouseWheelListener mouseWheelListener = new MouseWheelListener() {
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (verticalScrollBar.isVisible() && e.getScrollAmount() != 0) {
int direction = 0;
direction = e.getWheelRotation() < 0 ? -1 : 1;
if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
JEditTextArea.scrollByUnits(verticalScrollBar, direction, e.getScrollAmount());
} else if (e.getScrollType() == MouseWheelEvent.WHEEL_BLOCK_SCROLL) {
JEditTextArea.scrollByBlock(verticalScrollBar, direction);
}
}
}
};
panel.addMouseWheelListener(mouseWheelListener);
}
content.add(panel, BorderLayout.SOUTH);
content.validate();
getContentPane().add(content);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (_detailedMerge.getChanges().size() > 0) {
mergePanelElements.selectChange(_detailedMerge.getChanges().firstElement());
}
}
});
setPreferredSize(new Dimension(1000, 800));
validate();
pack();
setVisible(true);
}
protected void validateChanges() {
// System.out.println("Validate: "+_detailedMerge.getMergedSource().getText());
_detailedMerge.getChange().setCustomHandEdition(_detailedMerge.getMergedSource().getText());
_detailedMerge.getChange().setMergeChangeAction(MergeChangeAction.CustomEditing);
dispose();
}
@Override
public void dispose() {
_detailedMerge.deleteObserver(this);
super.dispose();
}
public void selectChange(MergeChange change) {
mergedText.getPainter().setSelectionColor(getColor(change));
leftText.getPainter().setSelectionColor(getColor(change));
rightText.getPainter().setSelectionColor(getColor(change));
originalText.getPainter().setSelectionColor(getColor(change));
if (change.getLast1() >= change.getFirst1()) {
originalText.selectArea(change.getMerge().getOriginalSource().tokenAt(change.getFirst1()).getTokenStartIndex(), change
.getMerge().getOriginalSource().tokenAt(change.getLast1()).getTokenEndIndex());
} else {
originalText.selectArea(0, 0);
}
if (change.getLast0() >= change.getFirst0()) {
if (change.getMerge().getLeftSource().tokenAt(change.getFirst0()) != null
&& change.getMerge().getLeftSource().tokenAt(change.getLast0()) != null) {
leftText.selectArea(change.getMerge().getLeftSource().tokenAt(change.getFirst0()).getTokenStartIndex(), change.getMerge()
.getLeftSource().tokenAt(change.getLast0()).getTokenEndIndex());
}
} else {
leftText.selectArea(0, 0);
}
if (change.getLast2() >= change.getFirst2()) {
if (change.getMerge().getRightSource().tokenAt(change.getFirst2()) != null
&& change.getMerge().getRightSource().tokenAt(change.getLast2()) != null) {
rightText.selectArea(change.getMerge().getRightSource().tokenAt(change.getFirst2()).getTokenStartIndex(), change.getMerge()
.getRightSource().tokenAt(change.getLast2()).getTokenEndIndex());
}
} else {
rightText.selectArea(0, 0);
}
if (change.getLastMergeIndex() >= change.getFirstMergeIndex()
&& change.getMerge().getMergedSource().tokenAt(change.getFirstMergeIndex()) != null
&& change.getMerge().getMergedSource().tokenAt(change.getLastMergeIndex()) != null) {
mergedText.selectArea(change.getMerge().getMergedSource().tokenAt(change.getFirstMergeIndex()).getTokenStartIndex(), change
.getMerge().getMergedSource().tokenAt(change.getLastMergeIndex()).getTokenEndIndex());
} else {
mergedText.selectArea(0, 0);
}
}
protected String localizedForKey(String key) {
return key;
}
protected class ReadOnlyTextArea extends JEditTextAreaWithHighlights {
public ReadOnlyTextArea(String text, TokenMarkerStyle style) {
super();
disableDefaultMouseWheelListener();
setTokenMarker(TokenMarker.makeTokenMarker(style));
setText(text);
setEditable(false);
setBackground(Color.RED);
remove(vertical);
remove(horizontal);
getPainter().setLineHighlightEnabled(false);
getPainter().setCaretColor(Color.WHITE);
}
public JScrollBar getHorizontalScrollBar() {
return horizontal;
}
public JScrollBar getVerticalScrollBar() {
return vertical;
}
// Disable select
@Override
public void select(int start, int end) {
}
public void selectArea(int start, int end) {
super.select(start, end);
}
}
private Color getColor(MergeChange change) {
if (change.getMergeChangeSource() == MergeChange.MergeChangeSource.Left) {
return MergeHighlight.MODIFICATION_SELECTED_COLOR;
} else if (change.getMergeChangeSource() == MergeChange.MergeChangeSource.Conflict) {
return MergeHighlight.REMOVAL_SELECTED_COLOR;
} else if (change.getMergeChangeSource() == MergeChange.MergeChangeSource.Right) {
return MergeHighlight.ADDITION_SELECTED_COLOR;
} else {
return Color.YELLOW;
}
}
@Override
public void update(Observable observable, Object dataModification) {
if (observable == _detailedMerge && dataModification instanceof MergeChange) {
mergedText.setText(_detailedMerge.getMergedSource().getText());
}
}
}