blob: 2855ab4dfc1f2b66ac02544a8528d3a37d42d07f [file] [log] [blame]
/*
* 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.debugger.settings;
import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.openapi.components.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.classFilter.ClassFilter;
import com.intellij.util.containers.hash.LinkedHashMap;
import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters;
import com.intellij.util.xmlb.XmlSerializer;
import com.intellij.util.xmlb.annotations.Transient;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
@State(
name = "DebuggerSettings",
storages = {
@Storage(
file = StoragePathMacros.APP_CONFIG + "/other.xml"
)}
)
public class DebuggerSettings implements Cloneable, PersistentStateComponent<Element> {
private static final Logger LOG = Logger.getInstance(DebuggerSettings.class);
public static final int SOCKET_TRANSPORT = 0;
public static final int SHMEM_TRANSPORT = 1;
@NonNls public static final String SUSPEND_ALL = "SuspendAll";
@NonNls public static final String SUSPEND_THREAD = "SuspendThread";
@NonNls public static final String SUSPEND_NONE = "SuspendNone";
@NonNls public static final String EVALUATE_FRAGMENT = "EvaluateFragment";
@NonNls public static final String EVALUATE_EXPRESSION = "EvaluateExpression";
@NonNls public static final String RUN_HOTSWAP_ALWAYS = "RunHotswapAlways";
@NonNls public static final String RUN_HOTSWAP_NEVER = "RunHotswapNever";
@NonNls public static final String RUN_HOTSWAP_ASK = "RunHotswapAsk";
@NonNls public static final String EVALUATE_FINALLY_ALWAYS = "EvaluateFinallyAlways";
@NonNls public static final String EVALUATE_FINALLY_NEVER = "EvaluateFinallyNever";
@NonNls public static final String EVALUATE_FINALLY_ASK = "EvaluateFinallyAsk";
public boolean TRACING_FILTERS_ENABLED;
public int DEBUGGER_TRANSPORT;
public boolean FORCE_CLASSIC_VM;
public boolean DISABLE_JIT;
public boolean HOTSWAP_IN_BACKGROUND = true;
public boolean SKIP_SYNTHETIC_METHODS;
public boolean SKIP_CONSTRUCTORS;
public boolean SKIP_GETTERS;
public boolean SKIP_CLASSLOADERS;
public String EVALUATION_DIALOG_TYPE;
public String RUN_HOTSWAP_AFTER_COMPILE;
public boolean COMPILE_BEFORE_HOTSWAP;
public boolean HOTSWAP_HANG_WARNING_ENABLED = false;
public volatile boolean WATCH_RETURN_VALUES = false;
public volatile boolean AUTO_VARIABLES_MODE = false;
public volatile boolean SHOW_LIBRARY_STACKFRAMES = true;
public String EVALUATE_FINALLY_ON_POP_FRAME = EVALUATE_FINALLY_ASK;
private ClassFilter[] mySteppingFilters = ClassFilter.EMPTY_ARRAY;
private Map<String, ContentState> myContentStates = new LinkedHashMap<String, ContentState>();
// transient - custom serialization
@Transient
public ClassFilter[] getSteppingFilters() {
final ClassFilter[] rv = new ClassFilter[mySteppingFilters.length];
for (int idx = 0; idx < rv.length; idx++) {
rv[idx] = mySteppingFilters[idx].clone();
}
return rv;
}
public static DebuggerSettings getInstance() {
return ServiceManager.getService(DebuggerSettings.class);
}
public void setSteppingFilters(ClassFilter[] steppingFilters) {
mySteppingFilters = steppingFilters != null ? steppingFilters : ClassFilter.EMPTY_ARRAY;
}
@Nullable
@Override
public Element getState() {
Element state = XmlSerializer.serialize(this, new SkipDefaultValuesSerializationFilters());
try {
DebuggerUtilsEx.writeFilters(state, "filter", mySteppingFilters);
}
catch (WriteExternalException e) {
LOG.error(e);
return null;
}
for (ContentState eachState : myContentStates.values()) {
final Element content = new Element("content");
if (eachState.write(content)) {
state.addContent(content);
}
}
return state;
}
@Override
public void loadState(Element state) {
XmlSerializer.deserializeInto(this, state);
try {
setSteppingFilters(DebuggerUtilsEx.readFilters(state.getChildren("filter")));
}
catch (InvalidDataException e) {
LOG.error(e);
}
myContentStates.clear();
for (Element content : state.getChildren("content")) {
ContentState contentState = new ContentState(content);
myContentStates.put(contentState.getType(), contentState);
}
}
public boolean equals(Object obj) {
if (!(obj instanceof DebuggerSettings)) return false;
DebuggerSettings secondSettings = (DebuggerSettings)obj;
return
TRACING_FILTERS_ENABLED == secondSettings.TRACING_FILTERS_ENABLED &&
DEBUGGER_TRANSPORT == secondSettings.DEBUGGER_TRANSPORT &&
StringUtil.equals(EVALUATE_FINALLY_ON_POP_FRAME, secondSettings.EVALUATE_FINALLY_ON_POP_FRAME) &&
FORCE_CLASSIC_VM == secondSettings.FORCE_CLASSIC_VM &&
DISABLE_JIT == secondSettings.DISABLE_JIT &&
HOTSWAP_IN_BACKGROUND == secondSettings.HOTSWAP_IN_BACKGROUND &&
SKIP_SYNTHETIC_METHODS == secondSettings.SKIP_SYNTHETIC_METHODS &&
SKIP_CLASSLOADERS == secondSettings.SKIP_CLASSLOADERS &&
SKIP_CONSTRUCTORS == secondSettings.SKIP_CONSTRUCTORS &&
SKIP_GETTERS == secondSettings.SKIP_GETTERS &&
COMPILE_BEFORE_HOTSWAP == secondSettings.COMPILE_BEFORE_HOTSWAP &&
HOTSWAP_HANG_WARNING_ENABLED == secondSettings.HOTSWAP_HANG_WARNING_ENABLED &&
(RUN_HOTSWAP_AFTER_COMPILE != null ? RUN_HOTSWAP_AFTER_COMPILE.equals(secondSettings.RUN_HOTSWAP_AFTER_COMPILE) : secondSettings.RUN_HOTSWAP_AFTER_COMPILE == null) &&
DebuggerUtilsEx.filterEquals(mySteppingFilters, secondSettings.mySteppingFilters);
}
@Override
public DebuggerSettings clone() {
try {
final DebuggerSettings cloned = (DebuggerSettings)super.clone();
cloned.myContentStates = new HashMap<String, ContentState>();
for (Map.Entry<String, ContentState> entry : myContentStates.entrySet()) {
cloned.myContentStates.put(entry.getKey(), entry.getValue().clone());
}
cloned.mySteppingFilters = new ClassFilter[mySteppingFilters.length];
for (int idx = 0; idx < mySteppingFilters.length; idx++) {
cloned.mySteppingFilters[idx] = mySteppingFilters[idx].clone();
}
return cloned;
}
catch (CloneNotSupportedException e) {
LOG.error(e);
}
return null;
}
public static class ContentState implements Cloneable {
private final String myType;
private boolean myMinimized;
private String mySelectedTab;
private double mySplitProportion;
private boolean myDetached;
private boolean myHorizontalToolbar;
private boolean myMaximized;
public ContentState(final String type) {
myType = type;
}
public ContentState(Element element) {
myType = element.getAttributeValue("type");
myMinimized = "true".equalsIgnoreCase(element.getAttributeValue("minimized"));
myMaximized = "true".equalsIgnoreCase(element.getAttributeValue("maximized"));
mySelectedTab = element.getAttributeValue("selected");
final String split = element.getAttributeValue("split");
if (split != null) {
mySplitProportion = Double.valueOf(split);
}
myDetached = "true".equalsIgnoreCase(element.getAttributeValue("detached"));
myHorizontalToolbar = !"false".equalsIgnoreCase(element.getAttributeValue("horizontal"));
}
public boolean write(final Element element) {
element.setAttribute("type", myType);
element.setAttribute("minimized", Boolean.valueOf(myMinimized).toString());
element.setAttribute("maximized", Boolean.valueOf(myMaximized).toString());
if (mySelectedTab != null) {
element.setAttribute("selected", mySelectedTab);
}
element.setAttribute("split", Double.toString(mySplitProportion));
element.setAttribute("detached", Boolean.valueOf(myDetached).toString());
element.setAttribute("horizontal", Boolean.valueOf(myHorizontalToolbar).toString());
return true;
}
public String getType() {
return myType;
}
public String getSelectedTab() {
return mySelectedTab;
}
public boolean isMinimized() {
return myMinimized;
}
public void setMinimized(final boolean minimized) {
myMinimized = minimized;
}
public void setMaximized(final boolean maximized) {
myMaximized = maximized;
}
public boolean isMaximized() {
return myMaximized;
}
public void setSelectedTab(final String selectedTab) {
mySelectedTab = selectedTab;
}
public void setSplitProportion(double splitProportion) {
mySplitProportion = splitProportion;
}
public double getSplitProportion(double defaultValue) {
return mySplitProportion <= 0 || mySplitProportion >= 1 ? defaultValue : mySplitProportion;
}
public void setDetached(final boolean detached) {
myDetached = detached;
}
public boolean isDetached() {
return myDetached;
}
public boolean isHorizontalToolbar() {
return myHorizontalToolbar;
}
public void setHorizontalToolbar(final boolean horizontalToolbar) {
myHorizontalToolbar = horizontalToolbar;
}
@Override
public ContentState clone() throws CloneNotSupportedException {
return (ContentState)super.clone();
}
}
}