/*
* Copyright 2003-2011 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.projectPane.favorites;
import com.intellij.openapi.components.ProjectComponent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.DefaultJDOMExternalizer;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizable;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.util.ArrayUtil;
import org.jetbrains.mps.openapi.module.SModuleReference;
import org.jetbrains.mps.openapi.model.SModelReference;
import org.jetbrains.mps.openapi.model.SNodeReference;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.mps.openapi.persistence.PersistenceFacade;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class MPSFavoritesManager implements ProjectComponent, JDOMExternalizable {
private static final String ELEMENT_FAVORITES_LIST = "favorites_list";
private static final String FAVORITES_ROOT = "favorite_root";
private static final String ATTRIBUTE_NAME = "name";
private static final String MODULE_REFERENCE = "module_ref";
private static final String SNODE_REFERENCE = "node_ref";
private final Map<String, List<Object>> myName2FavoritesRoots = new LinkedHashMap<String, List<Object>>();
private final Project myProject;
private List<MPSFavoritesListener> myListeners = new ArrayList<MPSFavoritesListener>();
// Do not delete this attribute!!
// It was added here to save at least some information into XML element inside writeExternal() method.
// Without this HACK new IDEA platform will remove misc.xml file (nothing to save there)
// and later fail with the exception: misc.xml file not found.
public boolean keepMe = true;
public interface MPSFavoritesListener {
void rootsChanged(String listName);
void listAdded(String listName);
void listRemoved(String listName);
}
public MPSFavoritesManager(Project project) {
myProject = project;
}
private static void writeRoots(Element element, List<Object> roots) {
for (Object root : roots) {
final Element favoriteRoot = new Element(FAVORITES_ROOT);
if (root instanceof SModelReference) {
favoriteRoot.setAttribute("model_ref", root.toString());
} else if (root instanceof SModuleReference) {
favoriteRoot.setAttribute(MODULE_REFERENCE, root.toString());
} else if (root instanceof SNodeReference) {
SNodeReference nodePointer = (SNodeReference) root;
favoriteRoot.setAttribute(SNODE_REFERENCE, jetbrains.mps.smodel.SNodePointer.serialize(nodePointer));
}
element.addContent(favoriteRoot);
}
}
private static List<Object> readRoots(final Element list, Project project) {
List<Object> result = new ArrayList<Object>();
for (Object favorite : list.getChildren(FAVORITES_ROOT)) {
Element favoriteElement = (Element) favorite;
final String moduleRef = favoriteElement.getAttributeValue(MODULE_REFERENCE);
if (moduleRef != null) {
result.add(PersistenceFacade.getInstance().createModuleReference(moduleRef));
continue;
}
String snodeRef = favoriteElement.getAttributeValue(SNODE_REFERENCE);
if (snodeRef != null) {
result.add(jetbrains.mps.smodel.SNodePointer.deserialize(snodeRef));
} else {
//todo obsolete, remove after 3.0
final String modelRef = favoriteElement.getAttributeValue("model_ref");
if (modelRef != null) {
final String nodeId = favoriteElement.getAttributeValue("node_pointer");
if (nodeId == null) {
SModelReference modelReference = PersistenceFacade.getInstance().createModelReference(modelRef);
result.add(modelReference);
} else {
SNodeReference nodePointer = new jetbrains.mps.smodel.SNodePointer(modelRef, nodeId);
result.add(nodePointer);
}
}
}
}
return result;
}
private void onListAdded(String name) {
//copy operation is necessary cause we can add/remove listeners in listeners
for (MPSFavoritesListener listener : new ArrayList<MPSFavoritesListener>(myListeners)) {
listener.listAdded(name);
}
}
private void onListChanged(String name) {
//copy operation is necessary cause we can add/remove listeners in listeners
for (MPSFavoritesListener listener : new ArrayList<MPSFavoritesListener>(myListeners)) {
listener.rootsChanged(name);
}
}
private void onListRemoved(String name) {
//copy operation is necessary cause we can add/remove listeners in listeners
for (MPSFavoritesListener listener : new ArrayList<MPSFavoritesListener>(myListeners)) {
listener.listRemoved(name);
}
}
@Override
public void projectOpened() {
}
@Override
public void projectClosed() {
}
@Override
@NotNull
public String getComponentName() {
return "MPSFavoritesManager";
}
@Override
public void initComponent() {
}
@Override
public void disposeComponent() {
}
@Override
public void readExternal(Element element) throws InvalidDataException {
myName2FavoritesRoots.clear();
for (Object list : element.getChildren(ELEMENT_FAVORITES_LIST)) {
final String name = ((Element) list).getAttributeValue(ATTRIBUTE_NAME);
List<Object> roots = readRoots((Element) list, myProject);
myName2FavoritesRoots.put(name, roots);
}
DefaultJDOMExternalizer.readExternal(this, element);
}
@Override
public void writeExternal(Element element) throws WriteExternalException {
for (final String name : myName2FavoritesRoots.keySet()) {
Element list = new Element(ELEMENT_FAVORITES_LIST);
list.setAttribute(ATTRIBUTE_NAME, name);
writeRoots(list, myName2FavoritesRoots.get(name));
element.addContent(list);
}
DefaultJDOMExternalizer.writeExternal(this, element);
}
public String[] getFavoriteNames() {
Set<String> favariteNames = new LinkedHashSet<String>();
favariteNames.addAll(myName2FavoritesRoots.keySet());
return ArrayUtil.toStringArray(favariteNames);
}
public void addNewFavoritesList(String name) {
myName2FavoritesRoots.put(name, new ArrayList<Object>());
onListAdded(name);
}
public void removeFavoritesList(String name) {
myName2FavoritesRoots.remove(name);
onListRemoved(name);
}
public void addRoots(String name, List<Object> roots) {
if (!myName2FavoritesRoots.containsKey(name)) return;
myName2FavoritesRoots.get(name).addAll(roots);
onListChanged(name);
}
public void removeRoots(String name, List<Object> roots) {
if (!myName2FavoritesRoots.containsKey(name)) return;
myName2FavoritesRoots.get(name).removeAll(roots);
onListChanged(name);
}
public void addListener(MPSFavoritesListener listener) {
myListeners.add(listener);
}
public void removeListener(MPSFavoritesListener listener) {
myListeners.remove(listener);
}
public List<Object> getRoots(String name) {
return myName2FavoritesRoots.get(name);
}
}