/* * Copyright 2003-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jetbrains.mps.ide.editorTabs.tabfactory.tabs; import com.intellij.openapi.editor.Document; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; import jetbrains.mps.ide.editorTabs.TabColorProvider; import jetbrains.mps.ide.editorTabs.tabfactory.NodeChangeCallback; import jetbrains.mps.ide.editorTabs.tabfactory.TabsComponent; import jetbrains.mps.ide.project.ProjectHelper; import jetbrains.mps.ide.relations.RelationComparator; import jetbrains.mps.ide.undo.MPSUndoUtil; import jetbrains.mps.plugins.relations.RelationDescriptor; import jetbrains.mps.util.containers.MultiMap; import org.jetbrains.mps.openapi.model.SNode; import org.jetbrains.mps.openapi.model.SNodeReference; import javax.swing.JComponent; import javax.swing.JPanel; import java.awt.BorderLayout; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; /** * This class expects subclasses to supply single component to serve UI functions. Subclasses shall use {@link #setContent(JComponent)} * and {@link #removeContent(JComponent)}, not <code>getComponent().add()</code> or <code>getComponent().remove()</code> as this class * manages layout constraints of the only child itself. Method {@link #getComponent()} is for external consumers or child unrelated activities. */ public abstract class BaseTabsComponent implements TabsComponent { private final NodeChangeCallback myCallback; private final CreateModeCallback myCreateModeCallback; protected final SNodeReference myBaseNode; protected final Collection<RelationDescriptor> myPossibleTabs; protected final JComponent myEditor; protected final boolean myShowGrayed; private final TabColorProvider myColorProvider; private final Project myProject; private List<Document> myEditedDocuments = new ArrayList<Document>(); private SNodeReference myLastNode = null; private JComponent myComponent; private volatile boolean myDisposed = false; protected BaseTabsComponent(SNodeReference baseNode, Set<RelationDescriptor> possibleTabs, JComponent editor, NodeChangeCallback callback, boolean showGrayed, CreateModeCallback createModeCallback, Project project) { myBaseNode = baseNode; final ArrayList<RelationDescriptor> tabs = new ArrayList<RelationDescriptor>(possibleTabs); Collections.sort(tabs, new RelationComparator()); myPossibleTabs = Collections.unmodifiableList(tabs); myEditor = editor; myCallback = callback; myShowGrayed = showGrayed; TabColorProvider[] extensions = Extensions.getExtensions(TabColorProvider.EP_NAME, project); myColorProvider = extensions.length > 0 ? extensions[0] : null; myProject = project; myCreateModeCallback = createModeCallback; myComponent = new JPanel(new BorderLayout()); } @Override public void dispose() { myDisposed = true; } protected boolean isDisposed() { return myDisposed; } @Override public final JComponent getComponent() { return myComponent; } protected void setContent(JComponent component) { myComponent.add(component, BorderLayout.CENTER); } protected void removeContent(JComponent component) { myComponent.remove(component); } @Override public List<Document> getAllEditedDocuments() { return myEditedDocuments; } @Override public void editNode(SNodeReference node) { myLastNode = node; myCallback.changeNode(node); } protected final SNodeReference getEditedNode() { return myLastNode; } protected void enterCreateMode(RelationDescriptor tab) { myLastNode = null; myCallback.changeNode(null); // this is workaround for update tab header icon if (myCreateModeCallback != null) { myCreateModeCallback.create(tab); } } protected TabEditorLayout updateDocumentsAndNodes() { List<Document> editedDocumentsNew = new ArrayList<Document>(); TabEditorLayout result = new TabEditorLayout(); SNode baseNode = myBaseNode.resolve(getProject().getRepository()); if (baseNode == null) return result; //see MPS-23013; if the node was just deleted and the command is not yet finished, the ref can still be resolved (unregistered nodes?) if (baseNode.getModel() == null) return result; for (RelationDescriptor d : myPossibleTabs) { MultiMap<SNodeReference, SNodeReference> topToUses = new MultiMap<SNodeReference, SNodeReference>(); for (SNode n : d.getNodes(baseNode)) { if (n == null || n.getModel() == null/* n.model == null is hack for MPS-21506*/) { continue; } topToUses.putValue(n.getContainingRoot().getReference(), n.getReference()); } if (topToUses.isEmpty()) continue; for (SNodeReference top : topToUses.keySet()) { editedDocumentsNew.add(MPSUndoUtil.getDoc(getProject().getRepository(), top)); result.add(d, top, topToUses.get(top)); } } myEditedDocuments = editedDocumentsNew; return result; } public TabColorProvider getColorProvider() { return myColorProvider; } protected final jetbrains.mps.project.Project getProject() { return ProjectHelper.toMPSProject(myProject); } }