Index: src/org/openstreetmap/josm/data/Preferences.java
===================================================================
--- src/org/openstreetmap/josm/data/Preferences.java	(revision 11730)
+++ src/org/openstreetmap/josm/data/Preferences.java	(working copy)
@@ -70,6 +70,7 @@
 import org.openstreetmap.josm.gui.preferences.SourceEditor.ExtendedSourceEntry;
 import org.openstreetmap.josm.gui.preferences.validator.ValidatorTagCheckerRulesPreference;
 import org.openstreetmap.josm.gui.preferences.validator.ValidatorTagCheckerRulesPreference.RulePrefHelper;
+import org.openstreetmap.josm.io.CachedFile;
 import org.openstreetmap.josm.io.OfflineAccessException;
 import org.openstreetmap.josm.io.OnlineResource;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
@@ -592,15 +593,15 @@
      * Called after every put. In case of a problem, do nothing but output the error in log.
      * @throws IOException if any I/O error occurs
      */
-    public synchronized void save() throws IOException {
-        save(getPreferenceFile(), settingsMap.entrySet().stream().filter(NO_DEFAULT_SETTINGS_ENTRY), false);
+    public void save() throws IOException {
+        save(getPreferenceFile(), settingsMap.entrySet().stream().filter(NO_DEFAULT_SETTINGS_ENTRY), false, false);
     }
 
-    public synchronized void saveDefaults() throws IOException {
-        save(getDefaultsCacheFile(), defaultsMap.entrySet().stream(), true);
+    public void saveDefaults() throws IOException {
+        save(getDefaultsCacheFile(), defaultsMap.entrySet().stream(), true, false);
     }
 
-    protected void save(File prefFile, Stream<Entry<String, Setting<?>>> settings, boolean defaults) throws IOException {
+    public synchronized void save(File prefFile, Stream<Entry<String, Setting<?>>> settings, boolean defaults, boolean addTime) throws IOException {
         if (!defaults) {
             /* currently unused, but may help to fix configuration issues in future */
             putInteger("josm.version", Version.getInstance().getVersion());
@@ -616,7 +617,7 @@
         }
 
         try (PreferencesWriter writer = new PreferencesWriter(
-                new PrintWriter(new File(prefFile + "_tmp"), StandardCharsets.UTF_8.name()), false, defaults)) {
+                new PrintWriter(new File(prefFile + "_tmp"), StandardCharsets.UTF_8.name()), false, defaults, addTime)) {
             writer.write(settings);
         }
 
@@ -655,7 +656,7 @@
     protected void load() throws IOException, SAXException, XMLStreamException {
         File pref = getPreferenceFile();
         PreferencesReader.validateXML(pref);
-        PreferencesReader reader = new PreferencesReader(pref, false);
+        PreferencesReader reader = new PreferencesReader(pref, false, false);
         reader.parse();
         settingsMap.clear();
         settingsMap.putAll(reader.getSettings());
@@ -675,9 +676,8 @@
     protected void loadDefaults() throws IOException, XMLStreamException, SAXException {
         File def = getDefaultsCacheFile();
         PreferencesReader.validateXML(def);
-        PreferencesReader reader = new PreferencesReader(def, true);
+        PreferencesReader reader = new PreferencesReader(def, true, true);
         reader.parse();
-        defaultsMap.clear();
         long minTime = System.currentTimeMillis() / 1000 - MAX_AGE_DEFAULT_PREFERENCES;
         for (Entry<String, Setting<?>> e : reader.getSettings().entrySet()) {
             if (e.getValue().getTime() >= minTime) {
@@ -686,6 +686,15 @@
         }
     }
 
+    protected void loadAvailable() throws XMLStreamException, IOException {
+        try (CachedFile cf = new CachedFile("resource://data/preferences-available.xml");
+                Reader rd = cf.getContentReader()) {
+            PreferencesReader reader = new PreferencesReader(rd, true, false);
+            reader.parse();
+            defaultsMap.putAll(reader.getSettings());
+        }
+    }
+
     /**
      * Loads preferences from XML reader.
      * @param in XML reader
@@ -693,7 +702,7 @@
      * @throws IOException if any I/O error occurs
      */
     public void fromXML(Reader in) throws XMLStreamException, IOException {
-        PreferencesReader reader = new PreferencesReader(in, false);
+        PreferencesReader reader = new PreferencesReader(in, false, false);
         reader.parse();
         settingsMap.clear();
         settingsMap.putAll(reader.getSettings());
@@ -782,6 +791,13 @@
                 Main.warn(tr("Failed to initialize preferences. Failed to reset preference file to default: {0}", getPreferenceFile()));
             }
         }
+        try {
+            loadAvailable();
+        } catch (XMLStreamException | IOException e) {
+            Main.error(e);
+            Main.warn(tr("Failed to load available preferences."));
+            defaultsMap.clear();
+        }
         File def = getDefaultsCacheFile();
         if (def.exists()) {
             try {
@@ -1473,7 +1489,7 @@
      * @return XML
      */
     public String toXML(boolean nopass) {
-        return toXML(settingsMap.entrySet(), nopass, false);
+        return toXML(settingsMap.entrySet(), nopass, false, false);
     }
 
     /**
@@ -1484,10 +1500,10 @@
      * regular preferences
      * @return XML
      */
-    public String toXML(Collection<Entry<String, Setting<?>>> settings, boolean nopass, boolean defaults) {
+    public String toXML(Collection<Entry<String, Setting<?>>> settings, boolean nopass, boolean defaults, boolean addTime) {
         try (
             StringWriter sw = new StringWriter();
-            PreferencesWriter prefWriter = new PreferencesWriter(new PrintWriter(sw), nopass, defaults)
+            PreferencesWriter prefWriter = new PreferencesWriter(new PrintWriter(sw), nopass, defaults, addTime)
         ) {
             prefWriter.write(settings);
             sw.flush();
Index: src/org/openstreetmap/josm/data/preferences/PreferencesReader.java
===================================================================
--- src/org/openstreetmap/josm/data/preferences/PreferencesReader.java	(revision 11730)
+++ src/org/openstreetmap/josm/data/preferences/PreferencesReader.java	(working copy)
@@ -46,6 +46,7 @@
     private final File file;
 
     private final boolean defaults;
+    private final boolean expectTime;
 
     /**
      * Constructs a new {@code PreferencesReader}.
@@ -53,10 +54,11 @@
      * @param defaults true when reading from the cache file for default preferences,
      * false for the regular preferences config file
      */
-    public PreferencesReader(File file, boolean defaults) {
+    public PreferencesReader(File file, boolean defaults, boolean expectTime) {
         this.defaults = defaults;
         this.reader = null;
         this.file = file;
+        this.expectTime = expectTime;
     }
 
     /**
@@ -65,10 +67,11 @@
      * @param defaults true when reading from the cache file for default preferences,
      * false for the regular preferences config file
      */
-    public PreferencesReader(Reader reader, boolean defaults) {
+    public PreferencesReader(Reader reader, boolean defaults, boolean expectTime) {
         this.defaults = defaults;
         this.reader = reader;
         this.file = null;
+        this.expectTime = expectTime;
     }
 
     /**
@@ -176,7 +179,7 @@
                         setting = new StringSetting(Optional.ofNullable(parser.getAttributeValue(null, "value"))
                                 .orElseThrow(() -> new XMLStreamException(tr("value expected"), parser.getLocation())));
                     }
-                    if (defaults) {
+                    if (expectTime) {
                         setting.setTime(Math.round(Double.parseDouble(parser.getAttributeValue(null, "time"))));
                     }
                     settings.put(parser.getAttributeValue(null, "key"), setting);
@@ -210,7 +213,7 @@
     private void parseToplevelList() throws XMLStreamException {
         String key = parser.getAttributeValue(null, "key");
         Long time = null;
-        if (defaults) {
+        if (expectTime) {
             time = Math.round(Double.parseDouble(parser.getAttributeValue(null, "time")));
         }
         String name = parser.getLocalName();
@@ -231,8 +234,10 @@
                     setting = new ListSetting(null);
                     break;
             }
-            setting.setTime(time);
-            settings.put(key, setting);
+            if (expectTime) {
+                setting.setTime(time);
+                settings.put(key, setting);
+            }
             jumpToEnd();
         } else {
             while (true) {
@@ -286,7 +291,7 @@
                         break;
                 }
             }
-            if (defaults) {
+            if (expectTime) {
                 setting.setTime(time);
             }
             settings.put(key, setting);
Index: src/org/openstreetmap/josm/data/preferences/PreferencesWriter.java
===================================================================
--- src/org/openstreetmap/josm/data/preferences/PreferencesWriter.java	(revision 11730)
+++ src/org/openstreetmap/josm/data/preferences/PreferencesWriter.java	(working copy)
@@ -19,6 +19,7 @@
 public class PreferencesWriter extends XmlWriter implements SettingVisitor {
     private final boolean noPassword;
     private final boolean defaults;
+    private final boolean addTime;
     private String key;
 
     /**
@@ -27,10 +28,11 @@
      * @param noPassword if password must be excluded
      * @param defaults true, if default values are converted to XML, false for regular preferences
      */
-    public PreferencesWriter(PrintWriter out, boolean noPassword, boolean defaults) {
+    public PreferencesWriter(PrintWriter out, boolean noPassword, boolean defaults, boolean addTime) {
         super(out);
         this.noPassword = noPassword;
         this.defaults = defaults;
+        this.addTime = addTime;
     }
 
     /**
@@ -67,7 +69,7 @@
     }
 
     private void addTime(Setting<?> setting) {
-        if (defaults) {
+        if (addTime) {
             out.write("' time='" + Optional.ofNullable(setting.getTime()).orElseThrow(IllegalStateException::new));
         }
     }
Index: src/org/openstreetmap/josm/gui/dialogs/changeset/query/TimeRestrictionPanel.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/changeset/query/TimeRestrictionPanel.java	(revision 11730)
+++ src/org/openstreetmap/josm/gui/dialogs/changeset/query/TimeRestrictionPanel.java	(working copy)
@@ -293,7 +293,7 @@
      * Remember settings in preferences.
      */
     public void rememberSettings() {
-        String prefRoot = "changeset-query.advanced.time-restrictions";
+        final String prefRoot = "changeset-query.advanced.time-restrictions";
         if (rbClosedAfter.isSelected()) {
             Main.pref.put(prefRoot + ".query-type", "closed-after");
         } else if (rbClosedAfterAndCreatedBefore.isSelected()) {
@@ -311,7 +311,7 @@
      * Restore settings from preferences.
      */
     public void restoreFromSettings() {
-        String prefRoot = "changeset-query.advanced.open-restrictions";
+        final String prefRoot = "changeset-query.advanced.open-restrictions";
         String v = Main.pref.get(prefRoot + ".query-type", "closed-after");
         rbClosedAfter.setSelected("closed-after".equals(v));
         rbClosedAfterAndCreatedBefore.setSelected("closed-after-created-before".equals(v));
Index: scripts/BuildProjectionDefinitions.java
===================================================================
--- scripts/BuildProjectionDefinitions.java	(revision 11730)
+++ scripts/BuildProjectionDefinitions.java	(working copy)
@@ -45,7 +45,7 @@
 
     /**
      * Program entry point
-     * @param args command line arguments (not used)
+     * @param args command line arguments: 1st argument - base directory
      * @throws IOException if any I/O error occurs
      */
     public static void main(String[] args) throws IOException {
Index: scripts/PreferencesCollector.java
===================================================================
--- scripts/PreferencesCollector.java	(revision 0)
+++ scripts/PreferencesCollector.java	(working copy)
@@ -0,0 +1,329 @@
+// License: GPL. For details, see LICENSE file.
+import java.awt.Color;
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Preferences;
+import org.openstreetmap.josm.data.preferences.BooleanProperty;
+import org.openstreetmap.josm.data.preferences.CollectionProperty;
+import org.openstreetmap.josm.data.preferences.ColorProperty;
+import org.openstreetmap.josm.data.preferences.DoubleProperty;
+import org.openstreetmap.josm.data.preferences.EnumProperty;
+import org.openstreetmap.josm.data.preferences.IntegerProperty;
+import org.openstreetmap.josm.data.preferences.ListListSetting;
+import org.openstreetmap.josm.data.preferences.ListSetting;
+import org.openstreetmap.josm.data.preferences.LongProperty;
+import org.openstreetmap.josm.data.preferences.MapListSetting;
+import org.openstreetmap.josm.data.preferences.Setting;
+import org.openstreetmap.josm.data.preferences.StringProperty;
+import org.openstreetmap.josm.data.preferences.StringSetting;
+import org.openstreetmap.josm.data.preferences.StrokeProperty;
+import org.openstreetmap.josm.tools.I18n;
+
+import spoon.Launcher;
+import spoon.processing.AbstractProcessor;
+import spoon.reflect.code.BinaryOperatorKind;
+import spoon.reflect.code.CtAbstractInvocation;
+import spoon.reflect.code.CtBinaryOperator;
+import spoon.reflect.code.CtConstructorCall;
+import spoon.reflect.code.CtExpression;
+import spoon.reflect.code.CtFieldRead;
+import spoon.reflect.code.CtInvocation;
+import spoon.reflect.code.CtLiteral;
+import spoon.reflect.code.CtUnaryOperator;
+import spoon.reflect.code.CtVariableRead;
+import spoon.reflect.code.UnaryOperatorKind;
+import spoon.reflect.declaration.CtClass;
+import spoon.reflect.declaration.CtElement;
+import spoon.reflect.declaration.CtField;
+import spoon.reflect.declaration.CtVariable;
+import spoon.reflect.declaration.ModifierKind;
+import spoon.reflect.eval.PartialEvaluator;
+import spoon.reflect.reference.CtExecutableReference;
+import spoon.reflect.reference.CtFieldReference;
+import spoon.reflect.reference.CtVariableReference;
+import spoon.reflect.visitor.filter.AbstractFilter;
+import spoon.support.SpoonClassNotFoundException;
+
+public class PreferencesCollector extends AbstractProcessor<CtAbstractInvocation> {
+
+    public SortedMap<String, Setting<?>> settingsMap = new TreeMap<>();
+    public int numNull = 0;
+
+    public static void main(String[] args) {
+        String baseDir = args[0];
+        Launcher spoon = new Launcher();
+        spoon.addInputResource(baseDir + "/src/org/openstreetmap/josm");
+        spoon.buildModel();
+        PreferencesCollector coll = new PreferencesCollector();
+        for (CtAbstractInvocation inv : spoon.getFactory().Package().getRootPackage().getElements(new AbstractFilter<CtAbstractInvocation>() {
+            @Override
+            public boolean matches(CtAbstractInvocation element) {
+                return element instanceof CtInvocation || element instanceof CtConstructorCall;
+            }
+        })) {
+            coll.process(inv);
+        }
+        try {
+            System.err.println("number of unique recognized keys:              " + coll.settingsMap.keySet().size());
+            System.err.println("number of unrecognized keys (with duplicates): " + coll.numNull);
+            Main.pref.save(new File(baseDir + "/data/preferences-available.xml"), coll.settingsMap.entrySet().stream(), true, false);
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    @Override
+    public void process(CtAbstractInvocation element) {
+        Map<Executable, Setting<?>> prefExecutables = new HashMap<>();
+        try {
+            // don't include Preferences.getInteger(String key, String specName, int def) as it
+            // is usually called with non-constant parameter specName
+            prefExecutables.put(Preferences.class.getMethod("get", String.class), new StringSetting(null));
+            prefExecutables.put(Preferences.class.getMethod("get", String.class, String.class), new StringSetting(null));
+            prefExecutables.put(Preferences.class.getMethod("getCollection", String.class), new ListSetting(null));
+            prefExecutables.put(Preferences.class.getMethod("getCollection", String.class, Collection.class), new ListSetting(null));
+            prefExecutables.put(Preferences.class.getMethod("getArray", String.class), new ListListSetting(null));
+            prefExecutables.put(Preferences.class.getMethod("getArray", String.class, Collection.class), new ListListSetting(null));
+            prefExecutables.put(Preferences.class.getMethod("getBoolean", String.class), new StringSetting(null));
+            prefExecutables.put(Preferences.class.getMethod("getBoolean", String.class, boolean.class), new StringSetting(null));
+            prefExecutables.put(Preferences.class.getMethod("getInteger", String.class, int.class), new StringSetting(null));
+            prefExecutables.put(Preferences.class.getMethod("getDouble", String.class, double.class), new StringSetting(null));
+            prefExecutables.put(Preferences.class.getMethod("getListOfStructs", String.class, Collection.class), new MapListSetting(null));
+            prefExecutables.put(Preferences.class.getMethod("getListOfStructs", String.class, Class.class), new MapListSetting(null));
+            prefExecutables.put(Preferences.class.getMethod("getListOfStructs", String.class, Collection.class, Class.class), new MapListSetting(null));
+            prefExecutables.put(Preferences.class.getMethod("getLong", String.class, long.class), new StringSetting(null));
+            prefExecutables.put(StringProperty.class.getConstructor(String.class, String.class), new StringSetting(null));
+            prefExecutables.put(IntegerProperty.class.getConstructor(String.class, int.class), new StringSetting(null));
+            prefExecutables.put(LongProperty.class.getConstructor(String.class, long.class), new StringSetting(null));
+            prefExecutables.put(BooleanProperty.class.getConstructor(String.class, boolean.class), new StringSetting(null));
+            prefExecutables.put(DoubleProperty.class.getConstructor(String.class, double.class), new StringSetting(null));
+            prefExecutables.put(CollectionProperty.class.getConstructor(String.class, Collection.class), new ListSetting(null));
+            prefExecutables.put(StrokeProperty.class.getConstructor(String.class, String.class), new StringSetting(null));
+            prefExecutables.put(EnumProperty.class.getConstructor(String.class, Class.class, Enum.class), new StringSetting(null));
+            prefExecutables.put(ColorProperty.class.getConstructor(String.class, String.class), new StringSetting(null));
+            prefExecutables.put(ColorProperty.class.getConstructor(String.class, Color.class), new StringSetting(null));
+        } catch (NoSuchMethodException | SecurityException ex) {
+            throw new RuntimeException(ex);
+        }
+        CtExecutableReference exec = element.getExecutable();
+        Executable realExec = null;
+        if (element instanceof CtInvocation) {
+            realExec = exec.getActualMethod();
+        } else if (element instanceof CtConstructorCall) {
+            try {
+                realExec = exec.getActualConstructor();
+            } catch (SpoonClassNotFoundException cnf) {
+                // it seems to have trouble with certain nested inner / anonymous classes
+            }
+        } else throw new AssertionError();
+
+        Setting setting = prefExecutables.get(realExec);
+        if (setting != null) {
+            List<CtExpression<?>> args = element.getArguments();
+            CtExpression key = args.get(0);
+            StaticCodeEvaluator eval = new StaticCodeEvaluator();
+            eval.evaluate(key);
+            String strKey = eval.getResult();
+            if (strKey != null) {
+                // fix ColorProperty
+                Class klass = realExec.getDeclaringClass();
+                if (klass.equals(ColorProperty.class)) {
+                    strKey = ColorProperty.getColorKey(strKey);
+                }
+
+                // add default value, if possilbe
+                if (setting instanceof StringSetting && args.size() >= 2) {
+                    CtExpression defaultValue = args.get(args.size() - 1);
+                    StaticCodeEvaluator eval2 = new StaticCodeEvaluator();
+                    eval2.evaluate(defaultValue);
+                    String strDefault = eval2.getResult();
+                    if (strDefault != null) {
+                        setting = new StringSetting(strDefault);
+                    } else {
+                        System.err.println("=== default value extraction failed!");
+                        System.err.println("file: "+element.getPosition().getLine()+":"+element.getPosition().getColumn() +element.getPosition().getFile());
+                        System.err.println("v: "+defaultValue.getClass()+ " "+ defaultValue);
+                        System.err.println(eval.getErrorLog());
+                    }
+                }
+                settingsMap.put(strKey, setting);
+            } else {
+                System.err.println("=== key extraction failed!");
+                System.err.println("file: "+element.getPosition().getLine()+":"+element.getPosition().getColumn() +element.getPosition().getFile());
+                System.err.println("exec: "+element.getExecutable());
+                System.err.println("args: "+element.getArguments());
+                System.err.println(eval.getErrorLog());
+                numNull++;
+            }
+        }
+    }
+
+    public static Class determineClass(CtElement element) {
+        CtClass klass = element.getParent(CtClass.class);
+        if (klass == null)
+            return null;
+        return klass.getActualClass();
+    }
+
+    public static class StaticCodeEvaluator implements PartialEvaluator {
+
+        private String result;
+        private StringBuilder sb = new StringBuilder();
+
+        private final Method marktr;
+
+        public StaticCodeEvaluator() {
+            try {
+                marktr = I18n.class.getMethod("marktr", String.class);
+            } catch (NoSuchMethodException | SecurityException ex) {
+                throw new RuntimeException();
+            }
+        }
+
+        @Override
+        public <R extends CtElement> R evaluate(R element) {
+            Object oResult = evalWrk(element, 0);
+            if (oResult != null) {
+                this.result = oResult.toString();
+            }
+            return null;
+        }
+
+        protected Object evalWrk(CtElement element, int lvl) {
+            lvl++;
+            if (lvl > 10) {
+                log("maximum recursion level exceeded!");
+                return null;
+            }
+            if (element instanceof CtLiteral) {
+                return eval((CtLiteral) element, lvl);
+            } else if (element instanceof CtFieldRead) {
+                return eval((CtFieldRead) element, lvl);
+            } else if (element instanceof CtVariableRead) {
+                return eval((CtVariableRead) element, lvl);
+            } else if (element instanceof CtUnaryOperator) {
+                return eval((CtUnaryOperator) element, lvl);
+            } else if (element instanceof CtBinaryOperator) {
+                return eval((CtBinaryOperator) element, lvl);
+            } else if (element instanceof CtInvocation) {
+                return eval((CtInvocation) element, lvl);
+            } else {
+                log("cannot handle "+element.getClass()+ " "+element);
+                return null;
+            }
+        }
+
+        public String getResult() {
+            return result;
+        }
+
+        public String getErrorLog() {
+            return sb.toString();
+        }
+
+        protected Object eval(CtLiteral literal, int lvl) {
+            return literal.getValue();
+        }
+
+        protected Object eval(CtFieldRead frr, int lvl) {
+            CtFieldReference fr = frr.getVariable();
+            String d = "";
+            if (fr.isFinal()) {
+                d += "final ";
+            }
+            if (fr.isStatic()) {
+                d += "static ";
+            }
+            log(" getKey qualified name - "+fr.getQualifiedName());
+            CtField fld = fr.getDeclaration();
+            if (fr.isFinal() && fr.isStatic() && fld != null) {
+                CtExpression def = fld.getDefaultExpression();
+                if (def == null) throw new AssertionError();
+                log("  getKey default expression: "+def.getClass());
+                return this.evalWrk(def, lvl);
+            }
+            log(" getKey result: "+d+" "+fld);
+            return null;
+        }
+
+        protected Object eval(CtVariableRead vr, int lvl) {
+            CtVariableReference vref = vr.getVariable();
+            CtVariable var = vref.getDeclaration();
+            if (!var.getModifiers().contains(ModifierKind.FINAL)) {
+                log("non-final variable: "+var.getSimpleName());
+                return null;
+            }
+            CtExpression def = var.getDefaultExpression();
+            if (def == null) {
+                log("no initializer for variable: "+var.getSimpleName());
+                return null;
+            }
+            return evalWrk(def, lvl);
+        }
+
+        protected Object eval(CtUnaryOperator uo, int lvl) {
+            if (uo.getKind() != UnaryOperatorKind.NEG) {
+                log("cannot handle unary operator: "+uo.getKind());
+                return null;
+            }
+            Object arg = evalWrk(uo.getOperand(), lvl);
+            if (arg == null) return null;
+            if (arg instanceof Integer) {
+                return - ((Integer) arg);
+            } else if (arg instanceof Long) {
+                return - ((Long) arg);
+            } else if (arg instanceof Float) {
+                return - ((Float) arg);
+            } else if (arg instanceof Double) {
+                return - ((Double) arg);
+            } else {
+                log("cannot handle type "+arg.getClass()+" of value "+arg);
+                return null;
+            }
+        }
+
+        protected Object eval(CtBinaryOperator bo, int lvl) {
+            if (bo.getKind() != BinaryOperatorKind.PLUS) {
+                log("cannot handle binary operator: "+bo.getKind());
+                return null;
+            }
+            Object left = evalWrk(bo.getLeftHandOperand(), lvl);
+            if (left != null && left instanceof String) {
+                Object right = evalWrk(bo.getRightHandOperand(), lvl);
+                if (right != null && right instanceof String) {
+                    return ((String) left) + ((String) right);
+                }
+            }
+            return null;
+        }
+
+        protected Object eval(CtInvocation inv, int lvl) {
+            if (inv.toString().equals("(getClass().getName())")) {
+                return determineClass(inv).getCanonicalName();
+            }
+            CtExecutableReference eref = inv.getExecutable();
+            Method m = eref.getActualMethod();
+            if (marktr.equals(m)) {
+                List<CtExpression<?>> args = inv.getArguments();
+                CtExpression arg = args.get(0);
+                return this.evalWrk(arg, lvl);
+            }
+            log("cannot handle CtInvocation: "+inv);
+            return null;
+        }
+
+        protected void log(String msg) {
+            sb.append(msg + "\n");
+        }
+    }
+}

Property changes on: scripts/PreferencesCollector.java
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
