package jetbrains.mps.vcs.diff.ui.merge;
/*Generated by MPS */
import com.intellij.openapi.project.Project;
import jetbrains.mps.vcs.diff.merge.MergeSession;
import org.jetbrains.mps.openapi.model.SNodeId;
import jetbrains.mps.vcs.diff.merge.MergeSessionState;
import jetbrains.mps.vcs.diff.ui.common.ChangeEditorMessage;
import jetbrains.mps.vcs.diff.ui.common.DiffEditor;
import com.intellij.ui.JBSplitter;
import javax.swing.JPanel;
import java.awt.GridBagLayout;
import com.intellij.ide.util.PropertiesComponent;
import java.util.List;
import jetbrains.mps.vcs.diff.ui.common.ChangeGroupLayout;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import java.util.ArrayList;
import java.util.Map;
import jetbrains.mps.vcs.diff.ui.common.DiffChangeGroupLayout;
import jetbrains.mps.internal.collections.runtime.MapSequence;
import java.util.HashMap;
import jetbrains.mps.vcs.diff.ui.common.DiffEditorSeparator;
import jetbrains.mps.vcs.diff.ui.common.DiffEditorsGroup;
import com.intellij.openapi.diff.ex.DiffStatusBar;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import jetbrains.mps.vcs.diff.ui.common.NextPreviousTraverser;
import jetbrains.mps.vcs.diff.changes.ModelChange;
import jetbrains.mps.internal.collections.runtime.Sequence;
import org.jetbrains.mps.openapi.module.ModelAccess;
import jetbrains.mps.ide.project.ProjectHelper;
import com.intellij.openapi.actionSystem.ToggleAction;
import jetbrains.mps.ide.icons.IdeIcons;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.ActionGroup;
import javax.swing.JComponent;
import jetbrains.mps.internal.collections.runtime.IVisitor;
import jetbrains.mps.internal.collections.runtime.IMapping;
import org.jetbrains.mps.openapi.model.SModel;
import jetbrains.mps.internal.collections.runtime.IWhereFilter;
import jetbrains.mps.vcs.diff.ui.common.ChangeGroupMessages;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import org.jetbrains.mps.openapi.model.SNode;
public class MergeRootsPane {
private static final String PARAM_SHOW_INSPECTOR = MergeRootsPane.class.getName() + "ShowInspector";
private static final String PARAM_INSPECTOR_SPLITTER_POSITION = MergeRootsPane.class.getName() + "InspectorSplitterPosition";
private Project myProject;
private MergeSession myMergeSession;
private SNodeId myRootId;
private MergeSessionState myStateToRestore;
private boolean myDisposed = false;
private ChangeEditorMessage.ConflictChecker myConflictChecker;
private String[] myTitles;
private DiffEditor myResultEditor;
private DiffEditor myMineEditor;
private DiffEditor myRepositoryEditor;
private JBSplitter myPanel = new JBSplitter(true, 0.7f);
private JPanel myTopPanel = new JPanel(new GridBagLayout());
private JPanel myBottomPanel = new JPanel(new GridBagLayout());
private boolean isInspectorShown = PropertiesComponent.getInstance().getBoolean(PARAM_SHOW_INSPECTOR, true);
private List<ChangeGroupLayout> myChangeGroupLayouts = ListSequence.fromList(new ArrayList<ChangeGroupLayout>());
private Map<DiffChangeGroupLayout, Boolean> myDiffLayoutPart = MapSequence.fromMap(new HashMap<DiffChangeGroupLayout, Boolean>());
private List<DiffEditorSeparator> myEdtiorSeparators = ListSequence.fromList(new ArrayList<DiffEditorSeparator>());
private DiffEditorsGroup myDiffEditorsGroup = new DiffEditorsGroup();
private DiffStatusBar myStatusBar;
private DefaultActionGroup myActionGroup;
private NextPreviousTraverser myTraverser;
public MergeRootsPane(Project project, MergeSession mergeSession, SNodeId rootId, String rootName, String[] titles, DiffStatusBar statusBar) {
myProject = project;
myMergeSession = mergeSession;
myRootId = rootId;
myStateToRestore = myMergeSession.getCurrentState();
myTitles = titles;
myStatusBar = statusBar;
myConflictChecker = new ChangeEditorMessage.ConflictChecker() {
public boolean isChangeConflicted(ModelChange ch) {
return Sequence.fromIterable(myMergeSession.getConflictedWith(ch)).isNotEmpty();
}
};
myMineEditor = addEditor(0, myMergeSession.getMyModel());
myResultEditor = addEditor(1, myMergeSession.getResultModel());
myRepositoryEditor = addEditor(2, myMergeSession.getRepositoryModel());
linkEditors(true, false);
linkEditors(false, false);
linkEditors(true, true);
linkEditors(false, true);
final ModelAccess modelAccess = ProjectHelper.fromIdeaProject(myProject).getRepository().getModelAccess();
myMergeSession.setChangesInvalidateHandler(new MergeSession.ChangesInvalidateHandler() {
public void someChangesInvalidated() {
modelAccess.runWriteInEDT(new Runnable() {
public void run() {
rehighlight();
}
});
}
});
myPanel.setSplitterProportionKey(PARAM_INSPECTOR_SPLITTER_POSITION);
myPanel.setFirstComponent(myTopPanel);
if (isInspectorShown) {
myPanel.setSecondComponent(myBottomPanel);
}
myTraverser = new NextPreviousTraverser(myChangeGroupLayouts, myResultEditor.getMainEditor());
createActionGroup(rootName);
highlightAllChanges();
myTraverser.goToFirstChangeLater();
}
private void createActionGroup(String rootName) {
myActionGroup = new DefaultActionGroup();
myActionGroup.add(new ApplyNonConflictsForRoot(this));
myActionGroup.addSeparator();
myActionGroup.addAll(myTraverser.previousAction(), myTraverser.nextAction());
myTraverser.previousAction().registerCustomShortcutSet(NextPreviousTraverser.PREV_CHANGE_SHORTCUT, myPanel);
myTraverser.nextAction().registerCustomShortcutSet(NextPreviousTraverser.NEXT_CHANGE_SHORTCUT, myPanel);
myActionGroup.addSeparator();
myActionGroup.add(new ToggleAction("Show Inspector", "Show Inspector Windows", IdeIcons.INSPECTOR_ICON) {
public boolean isSelected(AnActionEvent e) {
return isInspectorShown;
}
public void setSelected(AnActionEvent e, boolean b) {
showInspector(b);
}
});
}
public ActionGroup getActions() {
return myActionGroup;
}
public void registerShortcuts(JComponent component) {
myTraverser.previousAction().registerCustomShortcutSet(NextPreviousTraverser.PREV_CHANGE_SHORTCUT, component);
myTraverser.nextAction().registerCustomShortcutSet(NextPreviousTraverser.NEXT_CHANGE_SHORTCUT, component);
}
public void unregisterShortcuts(JComponent component) {
myTraverser.previousAction().unregisterCustomShortcutSet(component);
myTraverser.nextAction().unregisterCustomShortcutSet(component);
}
public JPanel getPanel() {
return myPanel;
}
public SNodeId getRootId() {
return myRootId;
}
public void setRootId(SNodeId rootId) {
myRootId = rootId;
myStateToRestore = myMergeSession.getCurrentState();
myMineEditor.editRoot(getRootNodeId(myMergeSession.getMyModel()), myMergeSession.getMyModel());
myResultEditor.editRoot(getRootNodeId(myMergeSession.getResultModel()), myMergeSession.getResultModel());
myRepositoryEditor.editRoot(getRootNodeId(myMergeSession.getRepositoryModel()), myMergeSession.getRepositoryModel());
rehighlight();
myTraverser.goToFirstChangeLater();
}
public void setRoodId(SNodeId rootId, final MergeSession mergeSession) {
myMergeSession = mergeSession;
MapSequence.fromMap(myDiffLayoutPart).visitAll(new IVisitor<IMapping<DiffChangeGroupLayout, Boolean>>() {
public void visit(IMapping<DiffChangeGroupLayout, Boolean> it) {
it.key().setChangeSet((it.value() ? mergeSession.getMyChangeSet() : mergeSession.getRepositoryChangeSet()));
}
});
setRootId(rootId);
}
private void showInspector(boolean show) {
if (isInspectorShown == show) {
return;
}
isInspectorShown = show;
PropertiesComponent.getInstance().setValue(PARAM_SHOW_INSPECTOR, show + "");
myPanel.setSecondComponent((isInspectorShown ? myBottomPanel : null));
}
private ChangeGroupLayout createChangeGroupLayout(boolean mine, boolean inspector) {
DiffChangeGroupLayout layout = new DiffChangeGroupLayout(myConflictChecker, (mine ? myMergeSession.getMyChangeSet() : myMergeSession.getRepositoryChangeSet()), (mine ? myMineEditor : myResultEditor), (mine ? myResultEditor : myRepositoryEditor), inspector);
MapSequence.fromMap(myDiffLayoutPart).put(layout, mine);
return layout;
}
public void rehighlight() {
if (myDisposed) {
return;
}
myMineEditor.unhighlightAllChanges();
myResultEditor.unhighlightAllChanges();
myRepositoryEditor.unhighlightAllChanges();
if (myResultEditor.getEditedNode() == null) {
SModel resultModel = myMergeSession.getResultModel();
SNodeId nodeId = getRootNodeId(resultModel);
if (nodeId != null) {
myResultEditor.editRoot(nodeId, resultModel);
}
}
myResultEditor.getMainEditor().rebuildEditorContent();
highlightAllChanges();
}
private void highlightAllChanges() {
ListSequence.fromList(myChangeGroupLayouts).visitAll(new IVisitor<ChangeGroupLayout>() {
public void visit(ChangeGroupLayout b) {
b.invalidate();
}
});
List<ModelChange> changesForRoot = ListSequence.fromList(myMergeSession.getChangesForRoot(myRootId)).where(new IWhereFilter<ModelChange>() {
public boolean accept(ModelChange ch) {
return !(myMergeSession.isChangeResolved(ch));
}
}).toListSequence();
for (ModelChange change : ListSequence.fromList(changesForRoot)) {
higlightChange(myResultEditor, myMergeSession.getResultModel(), true, change);
if (myMergeSession.isMyChange(change)) {
higlightChange(myMineEditor, myMergeSession.getMyModel(), false, change);
} else {
higlightChange(myRepositoryEditor, myMergeSession.getRepositoryModel(), false, change);
}
}
ListSequence.fromList(myChangeGroupLayouts).visitAll(new IVisitor<ChangeGroupLayout>() {
public void visit(ChangeGroupLayout b) {
b.invalidate();
}
});
myMineEditor.repaintAndRebuildEditorMessages();
myResultEditor.repaintAndRebuildEditorMessages();
myRepositoryEditor.repaintAndRebuildEditorMessages();
int conflictingChanges = ListSequence.fromList(changesForRoot).where(new IWhereFilter<ModelChange>() {
public boolean accept(ModelChange ch) {
return Sequence.fromIterable(myMergeSession.getConflictedWith(ch)).isNotEmpty();
}
}).count();
myStatusBar.setText(MergeModelsPanel.generateUnresolvedChangesText(ListSequence.fromList(changesForRoot).count(), conflictingChanges));
}
private void higlightChange(DiffEditor diffEditor, SModel model, boolean isOldEditor, ModelChange change) {
diffEditor.highlightChange(model, change, isOldEditor, myConflictChecker);
}
private void linkEditors(boolean mine, boolean inspector) {
// create change group builder, trapecium strip and merge buttons painter
// 'mine' parameter means mine changeset, 'inspector' - highlight inspector editor component
ChangeGroupLayout layout = createChangeGroupLayout(mine, inspector);
ChangeGroupMessages.startMaintaining(layout);
ListSequence.fromList(myChangeGroupLayouts).addElement(layout);
DiffEditorSeparator separator = new DiffEditorSeparator(layout);
JPanel panel = (inspector ? myBottomPanel : myTopPanel);
GridBagConstraints gbc = new GridBagConstraints((mine ? 1 : 3), 0, 1, 1, 0, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 0, 5, 0), 0, 0);
panel.add(separator, gbc);
ListSequence.fromList(myEdtiorSeparators).addElement(separator);
MergeButtonsPainter.addTo(this, (mine ? myMineEditor : myRepositoryEditor), layout, inspector);
}
private SNodeId getRootNodeId(SModel model) {
SNode node = model.getNode(myRootId);
if (node != null && node.getParent() == null) {
return myRootId;
}
if (model == myMergeSession.getResultModel()) {
SNodeId replacement = myMergeSession.getReplacementId(myRootId);
if (replacement != null) {
return replacement;
}
}
return null;
}
private DiffEditor addEditor(int index, SModel model) {
SNodeId rootId = getRootNodeId(model);
SNode root = (rootId == null ? null : model.getNode(rootId));
final DiffEditor result = new DiffEditor(ProjectHelper.fromIdeaProject(myProject), root, myTitles[index], index == 0);
GridBagConstraints gbc = new GridBagConstraints(index * 2, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, (index == 0 ? 5 : 0), 5, (index == 2 ? 5 : 0)), 0, 0);
myTopPanel.add(result.getTopComponent(), gbc);
myBottomPanel.add(result.getInspector().getExternalComponent(), gbc);
myDiffEditorsGroup.add(result);
return result;
}
/*package*/ MergeSession getMergeSession() {
return myMergeSession;
}
public void restoreState() {
myMergeSession.restoreState(myStateToRestore);
}
public void dispose() {
synchronized (this) {
if (myDisposed) {
return;
}
if (myActionGroup != null) {
myActionGroup.removeAll();
}
myActionGroup = null;
if (myMineEditor != null) {
myMineEditor.dispose();
}
myMineEditor = null;
if (myResultEditor != null) {
myResultEditor.dispose();
}
myResultEditor = null;
if (myRepositoryEditor != null) {
myRepositoryEditor.dispose();
}
myRepositoryEditor = null;
ListSequence.fromList(myEdtiorSeparators).visitAll(new IVisitor<DiffEditorSeparator>() {
public void visit(DiffEditorSeparator s) {
s.dispose();
}
});
ListSequence.fromList(myEdtiorSeparators).clear();
myDisposed = true;
}
}
}