/******************************************************************************* * Copyright (c) 2007, 2016 Intel Corporation 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: * Intel Corporation - Initial API and implementation *******************************************************************************/ package org.eclipse.cdt.core.settings.model.util; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; import org.eclipse.cdt.core.settings.model.ICMacroEntry; import org.eclipse.cdt.core.settings.model.ICSettingEntry; public class SettingsSet { public static final int READ_ONLY = 1; public static final int WRITABLE = 1 << 1; private SettingLevel[] fLevels; public class SettingLevel { private int fFlagsToSet; private int fFlagsToClear; private boolean fIsReadOnly; private boolean fIsOverrideSupported; private LinkedHashMap<EntryNameKey, EntryInfo> fEntries; HashSet<String> fOverrideSet; private Object fContext; private SettingLevel() { fEntries = new LinkedHashMap<EntryNameKey, EntryInfo>(); } public boolean isReadOnly() { return fIsReadOnly; } public void setReadOnly(boolean readOnly) { fIsReadOnly = readOnly; } public boolean isOverrideSupported() { return fIsOverrideSupported; } public void setOverrideSupported(boolean supported) { fIsOverrideSupported = supported; } public void setFlagsToSet(int flags) { fFlagsToSet = flags; } public boolean containsOverrideInfo() { return fOverrideSet != null; } public void setFlagsToClear(int flags) { fFlagsToClear = flags; } public int getFlagsToSet() { return fFlagsToSet; } public int getFlagsToClear() { return fFlagsToClear; } public int getFlags(int baseFlags) { return (baseFlags | fFlagsToSet) & (~fFlagsToClear); } @SuppressWarnings("unchecked") public Set<String> getOverrideSet() { if (fOverrideSet != null) return (HashSet<String>)fOverrideSet.clone(); return new HashSet<String>(); } public void addEntries(ICLanguageSettingEntry entries[]) { if (entries != null) { for (int i = 0; i < entries.length; i++) { addEntry(entries[i]); } } } public void addEntries(List<ICLanguageSettingEntry> list) { for (ICLanguageSettingEntry se : list) addEntry(se); } public void addEntry(ICLanguageSettingEntry entry) { addEntry(entry, null); } public void addEntry(ICLanguageSettingEntry entry, Object customInfo) { entry = CDataUtil.createEntry(entry, fFlagsToSet, fFlagsToClear); EntryInfo info = new EntryInfo(entry, customInfo); fEntries.put(info.getContentsKey(), info); } public void addOverrideName(String name) { if (fOverrideSet == null) fOverrideSet = new HashSet<String>(); fOverrideSet.add(name); } public void addOverrideNameSet(Set<String> set) { if (set == null) return; if (fOverrideSet != null) { fOverrideSet.addAll(set); } else if (set.size() != 0) { fOverrideSet = new HashSet<String>(set); } } public void removeOverrideName(String name) { if (fOverrideSet == null) return; fOverrideSet.remove(name); if (fOverrideSet.size() == 0) fOverrideSet = null; } public void clear() { fEntries.clear(); fOverrideSet = null; } public Map<EntryNameKey, EntryInfo> clearAndGetMap() { Map<EntryNameKey, EntryInfo> map = fEntries; fEntries = new LinkedHashMap<EntryNameKey, EntryInfo>(); fOverrideSet = null; return map; } public EntryInfo[] getInfos() { return fEntries.values().toArray(new EntryInfo[fEntries.size()]); } public ICLanguageSettingEntry[] getEntries() { List<ICLanguageSettingEntry> list = getEntriesList(false); return list.toArray(new ICLanguageSettingEntry[list.size()]); } public ICLanguageSettingEntry[] getEntries(boolean includeOverridden) { List<ICLanguageSettingEntry> list = getEntriesList(includeOverridden); return list.toArray(new ICLanguageSettingEntry[list.size()]); } public List<ICLanguageSettingEntry> getEntriesList(boolean includeOverridden) { List<ICLanguageSettingEntry> list = new ArrayList<ICLanguageSettingEntry>(); EntryInfo infos[] = getInfos(); for (EntryInfo info : infos) { if (includeOverridden || !info.isOverridden()) list.add(info.getEntry()); } return list; } public Object getContext() { return fContext; } public void setContext(Object context) { fContext = context; } } public static class EntryInfo { private ICLanguageSettingEntry fEntry; private EntryNameKey fNameKey; private boolean fIsOverRidden; private Object fCustomInfo; private EntryInfo(ICLanguageSettingEntry entry, Object customInfo) { fEntry = entry; fCustomInfo = customInfo; } public EntryNameKey getContentsKey() { if (fNameKey == null) { fNameKey = new EntryNameKey(fEntry); } return fNameKey; } private void makeOverridden(boolean overridden) { fIsOverRidden = overridden; } public ICLanguageSettingEntry getEntry() { return fEntry; } public boolean isOverridden() { return fIsOverRidden; } public Object getCustomInfo() { return fCustomInfo; } } public SettingsSet(int num) { fLevels = new SettingLevel[num]; for (int i = 0; i < num; i++) { fLevels[i] = new SettingLevel(); } } public SettingLevel[] getLevels() { return fLevels.clone(); } public void adjustOverrideState() { Set<String> set = new HashSet<String>(); SettingLevel level; for (int i = 0; i < fLevels.length; i++) { level = fLevels[i]; if (level.isOverrideSupported() && level.fOverrideSet != null) set.addAll(level.fOverrideSet); adjustOverrideState(fLevels[i], set); } } private void adjustOverrideState(SettingLevel level, Set<String> overridenSet) { for (EntryInfo info : level.getInfos()) { if (overridenSet.add(info.getEntry().getName())) { info.makeOverridden(false); } else { info.makeOverridden(true); } } } public ICLanguageSettingEntry[] getEntries() { return getEntries(READ_ONLY | WRITABLE); } public ICLanguageSettingEntry[] getEntries(int types) { adjustOverrideState(); List<ICLanguageSettingEntry> entries = new ArrayList<ICLanguageSettingEntry>(); for (SettingLevel sl : fLevels) { if (isCompatible(sl, types)) getEntries(sl, entries); } return entries.toArray(new ICLanguageSettingEntry[entries.size()]); } private void getEntries(SettingLevel level, List<ICLanguageSettingEntry> list) { for (EntryInfo info : level.getInfos()) if (!info.isOverridden()) list.add(info.getEntry()); } private boolean isCompatible(SettingLevel level, int types) { if ((types & READ_ONLY) == 0 && level.isReadOnly()) return false; if ((types & WRITABLE) == 0 && !level.isReadOnly()) return false; return true; } private int getWritableLevelNum() { for (int i = 0; i <fLevels.length; i++) { if (!fLevels[i].isReadOnly()) return i; } return -1; } private int getOverrideLevelNum() { for (int i = 0; i <fLevels.length; i++) { if (fLevels[i].isOverrideSupported()) return i; } return -1; } @SuppressWarnings("unchecked") public void applyEntries(ICLanguageSettingEntry[] entries) { HashMap<EntryNameKey, Object[]> map = getEntryLevelMap(WRITABLE | READ_ONLY); Map<EntryNameKey, Object[]> mapCopy = (HashMap<EntryNameKey, Object[]>)map.clone(); Map<EntryNameKey, EntryInfo>[] clearedInfos = new Map [fLevels.length]; for (int i = 0; i < fLevels.length; i++) { if (!fLevels[i].isReadOnly()) clearedInfos[i] = fLevels[i].clearAndGetMap(); } Integer levelInteger; int levelNum; ICLanguageSettingEntry entry; int writableLevel = getWritableLevelNum(); SettingLevel level; for (int i = 0; i < entries.length; i++) { entry = entries[i]; EntryNameKey key = new EntryNameKey(entry); Object[] o = map.get(key); if (o != null && valueMatches(entry, o[1])) { mapCopy.remove(key); levelInteger = (Integer)o[0]; if (! entry.isBuiltIn()) // allow overwrite existing entry, levelInteger = null; // even with the same value } else { levelInteger = null; } levelNum = levelInteger != null ? levelInteger.intValue() : writableLevel; if (levelNum >= 0) { level = fLevels[levelNum]; if (!level.isReadOnly()) { Map<EntryNameKey, EntryInfo> clearedInfo = clearedInfos[levelNum]; Object customInfo = null; if (clearedInfo != null) { EntryInfo info = clearedInfo.get(key); if (info != null && entry.equalsByContents(info.getEntry())) customInfo = info.getCustomInfo(); } level.addEntry(entry, customInfo); } } } int overrideLevel = getOverrideLevelNum(); if (overrideLevel >= 0) { level = fLevels[overrideLevel]; if (level.isOverrideSupported() && !mapCopy.isEmpty()) { for (EntryNameKey enk : mapCopy.keySet()) { ICSettingEntry e = enk.getEntry(); if ((e.getFlags() & ICSettingEntry.BUILTIN) == 0) continue; String str = e.getName(); if (str != null) level.addOverrideName(str); } } } adjustOverrideState(); } public HashMap<EntryNameKey, Object[]> getEntryLevelMap(int types) { HashMap<EntryNameKey, Object[]> map = new HashMap<EntryNameKey, Object[]>(); for (int i = 0; i < fLevels.length; i++) { if (isCompatible(fLevels[i], types)) addLevelInfoToMap(fLevels[i], i, map); } return map; } private void addLevelInfoToMap(SettingLevel level, int l, Map<EntryNameKey, Object[]> map) { for (EntryInfo info : level.getInfos()) { EntryNameKey key = info.getContentsKey(); if (!map.containsKey(key)) map.put(key, new Object[]{Integer.valueOf(l), info.getEntry()}); } } private static boolean valueMatches(ICLanguageSettingEntry e, Object o) { if (!(e instanceof ICMacroEntry)) return true; // ignore values for other entries if (!(o instanceof ICMacroEntry)) return false; // cannot compare different entries String s1 = e.getValue(); String s2 = ((ICMacroEntry) o).getValue(); return s1 == null ? s2 == null : s1.equals(s2); } }