/******************************************************************************* * Copyright (c) 2013 Google, Inc and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Sergey Prigogin (Google) - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.internal.ui.refactoring.includes; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.eclipse.ui.IMemento; import org.eclipse.ui.WorkbenchException; import org.eclipse.ui.XMLMemento; import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.internal.corext.codemanipulation.IncludeInfo; /** * A set of header file substitution rules. */ public class HeaderSubstitutionMap { private static final String TAG_HEADER_SUBSTITUTION_MAPS = "maps"; //$NON-NLS-1$ private static final String TAG_HEADER_SUBSTITUTION_MAP = "map"; //$NON-NLS-1$ private static final String TAG_NAME = "name"; //$NON-NLS-1$ private static final String TAG_CPP_ONLY = "cpp_only"; //$NON-NLS-1$ private static final String TAG_UNCONDITIONAL_SUBSTITUTION_MAP = "unconditional_substitution_map"; //$NON-NLS-1$ private static final String TAG_OPTIONAL_SUBSTITUTION_MAP = "optional_substitution_map"; //$NON-NLS-1$ private String name; private boolean cppOnly; private final IncludeMap unconditionalSubstitutionMap; private final IncludeMap optionalSubstitutionMap; public HeaderSubstitutionMap(boolean cppOnly) { this.cppOnly = cppOnly; this.unconditionalSubstitutionMap = new IncludeMap(true); this.optionalSubstitutionMap = new IncludeMap(false); } public HeaderSubstitutionMap(String name, boolean cppOnly, IncludeMap unconditionalSubstitutionMap, IncludeMap optionalSubstitutionMap) { this.name = name; this.cppOnly = cppOnly; this.unconditionalSubstitutionMap = unconditionalSubstitutionMap; this.optionalSubstitutionMap = optionalSubstitutionMap; } /** * Indicates that the header file {@code to} should be used instead of {@code from}. * * @param from The header file to be replaced. * @param to The header file to be used instead. * @param unconditionalSubstitution {@code true} if the header substitution is mandatory. * Otherwise substitution only if the {@code to} header has to be included for other * reasons. */ protected void addMapping(IncludeInfo from, IncludeInfo to, boolean unconditionalSubstitution) { IncludeMap map = unconditionalSubstitution ? unconditionalSubstitutionMap : optionalSubstitutionMap; map.addMapping(from, to); } /** * Indicates that the header file {@code to} should be used instead of {@code from}. * @param from The header file to be replaced. The header is represented by an include name * optionally surrounded by double quotes or angle brackets. Angle brackets indicate * a system include. * @param to The header file to be used instead. The header is represented by an include name * optionally surrounded by double quotes or angle brackets. Angle brackets indicate * a system include. * @param unconditionalSubstitution {@code true} if the header substitution is mandatory. * Otherwise substitution only if the {@code to} header has to be included for other * reasons. */ public void addMapping(String from, String to, boolean unconditionalSubstitution) { IncludeMap map = unconditionalSubstitution ? unconditionalSubstitutionMap : optionalSubstitutionMap; map.addMapping(from, to); } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean isCppOnly() { return cppOnly; } public void setCppOnly(boolean cppOnly) { this.cppOnly = cppOnly; } public void saveToMemento(IMemento memento) { if (name != null) memento.putString(TAG_NAME, name); memento.putBoolean(TAG_CPP_ONLY, cppOnly); unconditionalSubstitutionMap.saveToMemento(memento.createChild(TAG_UNCONDITIONAL_SUBSTITUTION_MAP)); optionalSubstitutionMap.saveToMemento(memento.createChild(TAG_OPTIONAL_SUBSTITUTION_MAP)); } public static HeaderSubstitutionMap fromMemento(IMemento memento) { String name = memento.getString(TAG_NAME); Boolean b = memento.getBoolean(TAG_CPP_ONLY); boolean cppOnly = b != null && b.booleanValue(); IncludeMap unconditionalSubstitutionMap = IncludeMap.fromMemento(true, memento.getChild(TAG_UNCONDITIONAL_SUBSTITUTION_MAP)); IncludeMap optionalSubstitutionMap = IncludeMap.fromMemento(false, memento.getChild(TAG_OPTIONAL_SUBSTITUTION_MAP)); // Remove potential redundant substitutions from optionalSubstitutionMap. for (IncludeInfo header : unconditionalSubstitutionMap.getMap().keySet()) { optionalSubstitutionMap.removeMapping(header); } return new HeaderSubstitutionMap(name, cppOnly, unconditionalSubstitutionMap, optionalSubstitutionMap); } public static HeaderSubstitutionMap fromSerializedMemento(String str) { return fromSerializedMemento(new StringReader(str)); } public static HeaderSubstitutionMap fromSerializedMemento(Reader reader) { XMLMemento memento; try { memento = XMLMemento.createReadRoot(reader); } catch (WorkbenchException e) { return null; } return fromMemento(memento); } public static String serializeMaps(List<HeaderSubstitutionMap> maps) { XMLMemento memento = XMLMemento.createWriteRoot(TAG_HEADER_SUBSTITUTION_MAPS); for (HeaderSubstitutionMap element : maps) { element.saveToMemento(memento.createChild(TAG_HEADER_SUBSTITUTION_MAP)); } StringWriter writer = new StringWriter(); try { memento.save(writer); } catch (IOException e) { CUIPlugin.log(e); } return writer.toString(); } public static List<HeaderSubstitutionMap> deserializeMaps(String str) { StringReader reader = new StringReader(str); XMLMemento memento; try { memento = XMLMemento.createReadRoot(reader); } catch (WorkbenchException e) { return Collections.emptyList(); } List<HeaderSubstitutionMap> maps = new ArrayList<HeaderSubstitutionMap>(); for (IMemento element : memento.getChildren(TAG_HEADER_SUBSTITUTION_MAP)) { maps.add(fromMemento(element)); } return maps; } public IncludeMap getUnconditionalSubstitutionMap() { return unconditionalSubstitutionMap; } public IncludeMap getOptionalSubstitutionMap() { return optionalSubstitutionMap; } }