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; } } }