package jetbrains.mps.vcs.diff.ui; /*Generated by MPS */ import jetbrains.mps.project.MPSProject; import jetbrains.mps.vcs.diff.ModelChangeSet; import org.jetbrains.mps.openapi.model.SNodeId; import jetbrains.mps.vcs.diff.ui.common.DiffEditor; import java.util.List; import jetbrains.mps.vcs.diff.ui.common.ChangeGroupLayout; import jetbrains.mps.internal.collections.runtime.ListSequence; import java.util.ArrayList; import jetbrains.mps.vcs.diff.ui.common.DiffEditorSeparator; import jetbrains.mps.vcs.diff.ui.common.DiffEditorsGroup; import com.intellij.ui.JBSplitter; import javax.swing.JPanel; import java.awt.GridBagLayout; import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.diff.ex.DiffStatusBar; import com.intellij.openapi.actionSystem.DefaultActionGroup; import jetbrains.mps.vcs.diff.ui.common.NextPreviousTraverser; import com.intellij.openapi.actionSystem.ToggleAction; import jetbrains.mps.ide.icons.IdeIcons; import com.intellij.openapi.actionSystem.AnActionEvent; import jetbrains.mps.vcs.diff.changes.ModelChange; import com.intellij.openapi.actionSystem.ActionGroup; import javax.swing.JComponent; import org.jetbrains.annotations.Nullable; import jetbrains.mps.vcs.diff.ui.common.Bounds; import com.intellij.openapi.application.ApplicationManager; import jetbrains.mps.internal.collections.runtime.IVisitor; import jetbrains.mps.vcs.diff.ui.common.DiffChangeGroupLayout; import jetbrains.mps.vcs.diff.ui.common.ChangeGroupMessages; import java.awt.GridBagConstraints; import java.awt.Insets; import jetbrains.mps.smodel.SModelOperations; import org.jetbrains.mps.openapi.model.SModel; import jetbrains.mps.internal.collections.runtime.Sequence; import jetbrains.mps.util.NameUtil; import jetbrains.mps.vcs.diff.ChangeSetBuilder; public class RootDifferencePane implements IHighlighter { private static final String PARAM_SHOW_INSPECTOR = RootDifferencePane.class.getName() + "ShowInspector"; private static final String PARAM_INSPECTOR_SPLITTER_POSITION = RootDifferencePane.class.getName() + "InspectorSplitterPosition"; private final MPSProject myProject; private ModelChangeSet myChangeSet; private SNodeId myRootId; private DiffEditor myOldEditor; private DiffEditor myNewEditor; private List<ChangeGroupLayout> myChangeGroupLayouts = ListSequence.fromList(new ArrayList<ChangeGroupLayout>()); private List<DiffEditorSeparator> myEditorSeparators = ListSequence.fromList(new ArrayList<DiffEditorSeparator>()); private DiffEditorsGroup myDiffEditorsGroup = new DiffEditorsGroup(); 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 DiffStatusBar myStatusBar; private DefaultActionGroup myActionGroup; private NextPreviousTraverser myTraverser; public RootDifferencePane(MPSProject project, ModelChangeSet changeSet, SNodeId rootId, String rootName, String[] titles, boolean isEditable, DiffStatusBar statusBar) { myChangeSet = changeSet; myRootId = rootId; myProject = project; myStatusBar = statusBar; myOldEditor = addEditor(0, myChangeSet.getOldModel(), titles[0]); myNewEditor = addEditor(1, myChangeSet.getNewModel(), titles[1]); linkEditors(true); linkEditors(false); myPanel.setSplitterProportionKey(PARAM_INSPECTOR_SPLITTER_POSITION); myPanel.setFirstComponent(myTopPanel); if (isInspectorShown) { myPanel.setSecondComponent(myBottomPanel); } myTraverser = new NextPreviousTraverser(myChangeGroupLayouts, myNewEditor.getMainEditor()); createActionGroup(isEditable, rootName); } private void createActionGroup(boolean isEditable, String rootName) { myActionGroup = new DefaultActionGroup(); 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); } }); myActionGroup.addSeparator(); if (isEditable) { myActionGroup.add(new RevertRootsAction(rootName) { @Override protected Iterable<ModelChange> getChanges() { return myChangeSet.getChangesForRoot(myRootId); } @Override protected void after() { rehighlight(); } }); } } 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 void navigateInitial(@Nullable final Bounds firstChange) { highlightAllChanges(); if (firstChange != null) { ApplicationManager.getApplication().invokeLater(new Runnable() { public void run() { myTraverser.goToBounds(firstChange); } }); } else { myTraverser.goToFirstChangeLater(); } } public SNodeId getRootId() { return myRootId; } public void setRootId(SNodeId rootId) { myRootId = rootId; myOldEditor.editRoot(myRootId, myChangeSet.getOldModel()); myNewEditor.editRoot(myRootId, myChangeSet.getNewModel()); rehighlight(); myTraverser.goToFirstChangeLater(); } public void setRootId(SNodeId rootId, ModelChangeSet changeSet) { myChangeSet = changeSet; ListSequence.fromList(myChangeGroupLayouts).visitAll(new IVisitor<ChangeGroupLayout>() { public void visit(ChangeGroupLayout it) { ((DiffChangeGroupLayout) it).setChangeSet(myChangeSet); } }); 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 void linkEditors(boolean inspector) { // create change group builder, trapecium strip and merge buttons painter // 'mine' parameter means mine changeset, 'inspector' - highlight inspector editor component ChangeGroupLayout layout = new DiffChangeGroupLayout(null, myChangeSet, myOldEditor, myNewEditor, inspector); ChangeGroupMessages.startMaintaining(layout); ListSequence.fromList(myChangeGroupLayouts).addElement(layout); DiffEditorSeparator separator = new DiffEditorSeparator(layout); GridBagConstraints gbc = new GridBagConstraints(1, 0, 1, 1, 0, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 0, 5, 0), 0, 0); ((inspector ? myBottomPanel : myTopPanel)).add(separator, gbc); ListSequence.fromList(myEditorSeparators).addElement(separator); if (!(SModelOperations.isReadOnly(myChangeSet.getNewModel()))) { DiffButtonsPainter.addTo(this, myOldEditor, layout, inspector); DiffButtonsPainter.addTo(this, myNewEditor, layout, inspector); } } private DiffEditor addEditor(int index, SModel model, String title) { final DiffEditor result = new DiffEditor(myProject, model.getNode(myRootId), title, 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; } private void highlightAllChanges() { ListSequence.fromList(myChangeGroupLayouts).visitAll(new IVisitor<ChangeGroupLayout>() { public void visit(ChangeGroupLayout b) { b.invalidate(); } }); for (ModelChange change : Sequence.fromIterable(myChangeSet.getChangesForRoot(myRootId))) { higlightChange(myOldEditor, myChangeSet.getOldModel(), true, change); higlightChange(myNewEditor, myChangeSet.getNewModel(), false, change); } ListSequence.fromList(myChangeGroupLayouts).visitAll(new IVisitor<ChangeGroupLayout>() { public void visit(ChangeGroupLayout b) { b.invalidate(); } }); myOldEditor.repaintAndRebuildEditorMessages(); myNewEditor.repaintAndRebuildEditorMessages(); int count = Sequence.fromIterable(myChangeSet.getChangesForRoot(myRootId)).count(); myStatusBar.setText((count == 0 ? "no differences" : NameUtil.formatNumericalString(count, "difference"))); } private void higlightChange(DiffEditor diffEditor, SModel model, boolean isOldEditor, ModelChange change) { diffEditor.highlightChange(model, change, isOldEditor, null); } @Override public void rehighlight() { ChangeSetBuilder.rebuildChangeSet(myChangeSet); myNewEditor.unhighlightAllChanges(); myOldEditor.unhighlightAllChanges(); if (myNewEditor.getEditedNode() == null) { myNewEditor.editRoot(myRootId, myChangeSet.getNewModel()); } myNewEditor.getMainEditor().rebuildEditorContent(); myOldEditor.getMainEditor().rebuildEditorContent(); highlightAllChanges(); } /*package*/ void rollbackChanges(Iterable<ModelChange> changes) { ModelChange.rollbackChanges(changes); rehighlight(); } public void dispose() { myActionGroup.removeAll(); myActionGroup = null; myOldEditor.dispose(); myOldEditor = null; myNewEditor.dispose(); myNewEditor = null; ListSequence.fromList(myEditorSeparators).visitAll(new IVisitor<DiffEditorSeparator>() { public void visit(DiffEditorSeparator s) { s.dispose(); } }); ListSequence.fromList(myEditorSeparators).clear(); myEditorSeparators = null; } }