/*
* Copyright 2000-2014 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 com.intellij.profile;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.components.MainConfigurationStateSplitter;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.packageDependencies.DependencyValidationManager;
import com.intellij.psi.search.scope.packageSet.NamedScopesHolder;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.xmlb.XmlSerializer;
import com.intellij.util.xmlb.annotations.OptionTag;
import gnu.trove.THashMap;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* User: anna
* Date: 30-Nov-2005
*/
public abstract class DefaultProjectProfileManager extends ProjectProfileManager implements PersistentStateComponent<Element> {
protected static final Logger LOG = Logger.getInstance("#com.intellij.profile.DefaultProjectProfileManager");
@NonNls public static final String SCOPES = "scopes";
@NonNls protected static final String SCOPE = "scope";
@NonNls public static final String PROFILE = "profile";
@NonNls protected static final String NAME = "name";
private static final String VERSION = "1.0";
@NotNull
protected final Project myProject;
protected String myProjectProfile;
/** This field is used for serialization. Do not rename it or make access weaker */
public boolean USE_PROJECT_PROFILE = true;
private final ApplicationProfileManager myApplicationProfileManager;
private final Map<String, Profile> myProfiles = new THashMap<String, Profile>();
protected final DependencyValidationManager myHolder;
private final List<ProfileChangeAdapter> myProfilesListener = ContainerUtil.createLockFreeCopyOnWriteList();
@NonNls private static final String PROJECT_DEFAULT_PROFILE_NAME = "Project Default";
public DefaultProjectProfileManager(@NotNull final Project project,
@NotNull ApplicationProfileManager applicationProfileManager,
@NotNull DependencyValidationManager holder) {
myProject = project;
myHolder = holder;
myApplicationProfileManager = applicationProfileManager;
}
@NotNull
public Project getProject() {
return myProject;
}
@Override
public synchronized Profile getProfile(@NotNull String name, boolean returnRootProfileIfNamedIsAbsent) {
return myProfiles.containsKey(name) ? myProfiles.get(name) : myApplicationProfileManager.getProfile(name, returnRootProfileIfNamedIsAbsent);
}
@Override
public synchronized void updateProfile(@NotNull Profile profile) {
myProfiles.put(profile.getName(), profile);
for (ProfileChangeAdapter profileChangeAdapter : myProfilesListener) {
profileChangeAdapter.profileChanged(profile);
}
}
@Nullable
@Override
public synchronized Element getState() {
Element state = new Element("settings");
String[] sortedProfiles = myProfiles.keySet().toArray(new String[myProfiles.size()]);
Arrays.sort(sortedProfiles);
for (String profile : sortedProfiles) {
final Profile projectProfile = myProfiles.get(profile);
if (projectProfile != null) {
Element profileElement = new Element(PROFILE);
try {
projectProfile.writeExternal(profileElement);
}
catch (WriteExternalException e) {
LOG.error(e);
}
boolean hasSmthToSave = sortedProfiles.length > 1 || isDefaultProfileUsed();
if (!hasSmthToSave) {
for (Element child : profileElement.getChildren()) {
if (!child.getName().equals("option")) {
hasSmthToSave = true;
break;
}
}
}
if (!hasSmthToSave) {
continue;
}
state.addContent(profileElement);
}
}
if (!state.getChildren().isEmpty() || isDefaultProfileUsed()) {
XmlSerializer.serializeInto(this, state);
state.addContent(new Element("version").setAttribute("value", VERSION));
}
return state;
}
@Override
public synchronized void loadState(Element state) {
myProfiles.clear();
XmlSerializer.deserializeInto(this, state);
for (Element o : state.getChildren(PROFILE)) {
Profile profile = myApplicationProfileManager.createProfile();
profile.setProfileManager(this);
try {
profile.readExternal(o);
}
catch (InvalidDataException e) {
LOG.error(e);
}
profile.setProjectLevel(true);
myProfiles.put(profile.getName(), profile);
}
if (state.getChild("version") == null || !Comparing.strEqual(state.getChild("version").getAttributeValue("value"), VERSION)) {
boolean toConvert = true;
for (Element o : state.getChildren("option")) {
if (Comparing.strEqual(o.getAttributeValue("name"), "USE_PROJECT_LEVEL_SETTINGS")) {
toConvert = Boolean.parseBoolean(o.getAttributeValue("value"));
break;
}
}
if (toConvert) {
convert(state);
}
}
}
protected void convert(Element element) {
}
private boolean isDefaultProfileUsed() {
return myProjectProfile != null && !Comparing.strEqual(myProjectProfile, PROJECT_DEFAULT_PROFILE_NAME);
}
@NotNull
@Override
public NamedScopesHolder getScopesManager() {
return myHolder;
}
@NotNull
@Override
public synchronized Collection<Profile> getProfiles() {
getProjectProfileImpl();
return myProfiles.values();
}
@NotNull
@Override
public synchronized String[] getAvailableProfileNames() {
return ArrayUtil.toStringArray(myProfiles.keySet());
}
@Override
public synchronized void deleteProfile(@NotNull String name) {
myProfiles.remove(name);
}
@Override
@OptionTag("PROJECT_PROFILE")
public synchronized String getProjectProfile() {
return myProjectProfile;
}
@Override
public synchronized void setProjectProfile(@Nullable String newProfile) {
if (Comparing.strEqual(newProfile, myProjectProfile)) {
return;
}
String oldProfile = myProjectProfile;
myProjectProfile = newProfile;
USE_PROJECT_PROFILE = newProfile != null;
if (oldProfile != null) {
for (ProfileChangeAdapter adapter : myProfilesListener) {
adapter.profileActivated(getProfile(oldProfile), newProfile != null ? getProfile(newProfile) : null);
}
}
}
@NotNull
public synchronized Profile getProjectProfileImpl(){
if (!USE_PROJECT_PROFILE) {
return myApplicationProfileManager.getRootProfile();
}
if (myProjectProfile == null || myProfiles.isEmpty()){
setProjectProfile(PROJECT_DEFAULT_PROFILE_NAME);
final Profile projectProfile = myApplicationProfileManager.createProfile();
projectProfile.copyFrom(myApplicationProfileManager.getRootProfile());
projectProfile.setProjectLevel(true);
projectProfile.setName(PROJECT_DEFAULT_PROFILE_NAME);
myProfiles.put(PROJECT_DEFAULT_PROFILE_NAME, projectProfile);
}
else if (!myProfiles.containsKey(myProjectProfile)){
setProjectProfile(myProfiles.keySet().iterator().next());
}
final Profile profile = myProfiles.get(myProjectProfile);
profile.setProfileManager(this);
return profile;
}
public void addProfileChangeListener(@NotNull final ProfileChangeAdapter profilesListener, @NotNull Disposable parent) {
myProfilesListener.add(profilesListener);
Disposer.register(parent, new Disposable() {
@Override
public void dispose() {
myProfilesListener.remove(profilesListener);
}
});
}
public void removeProfileChangeListener(@NotNull ProfileChangeAdapter profilesListener) {
myProfilesListener.remove(profilesListener);
}
public static class ProfileStateSplitter extends MainConfigurationStateSplitter {
@NotNull
@Override
protected String getSubStateFileName(@NotNull Element element) {
for (Element option : element.getChildren("option")) {
if (option.getAttributeValue("name").equals("myName")) {
return option.getAttributeValue("value");
}
}
throw new IllegalStateException();
}
@NotNull
@Override
protected String getComponentStateFileName() {
return "profiles_settings";
}
@NotNull
@Override
protected String getSubStateTagName() {
return PROFILE;
}
}
protected void fireProfilesInitialized() {
for (ProfileChangeAdapter profileChangeAdapter : myProfilesListener) {
profileChangeAdapter.profilesInitialized();
}
}
protected void fireProfilesShutdown() {
for (ProfileChangeAdapter profileChangeAdapter : myProfilesListener) {
profileChangeAdapter.profilesShutdown();
}
}
}