Java tutorial
/******************************************************************************* * Copyright (C) 2011, Google Inc. * * 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 *******************************************************************************/ package com.google.eclipse.mechanic.core.keybinding; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.Map; import org.eclipse.core.runtime.IPath; import org.eclipse.jface.bindings.Binding; import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.collect.Iterables; import com.google.common.io.Closeables; /** * Class that formats the keybindings by sweat and tears. * * <p>The reason a JSON formatter is not used is so that the output, which is * meant to be read by a person, is carefully tinkered with to be readable. * * <p>The usage for this class is the following: 1. user creates a few * keybindings through the regular Eclipse UI; 2. user wants to create a task * based on these bindings; 3. user triggers this code (still TODO) which spits * out a file for him/her to bootstrap. This will be the canonical, documented * and simplest way to create a .kbd task file. * * @author zorzella@google.com */ class KeyBindingsManualFormatter { private final boolean debugDumpSystemBindings; private final Map<KbaChangeSetQualifier, KbaChangeSet> userBindingsMap; private final Map<KbaChangeSetQualifier, KbaChangeSet> systemBindingsMap; public KeyBindingsManualFormatter(final Map<KbaChangeSetQualifier, KbaChangeSet> userBindingsMap, final Map<KbaChangeSetQualifier, KbaChangeSet> systemBindingsMap) { this(System.getProperty("KEYBOARD_MECHANIC_DEBUG_DUMP_SYSTEM_BINDINGS", "false").equals("true"), userBindingsMap, systemBindingsMap); } public KeyBindingsManualFormatter(final boolean debugDumpSystemBindings, final Map<KbaChangeSetQualifier, KbaChangeSet> userBindingsMap, final Map<KbaChangeSetQualifier, KbaChangeSet> systemBindingsMap) { this.debugDumpSystemBindings = debugDumpSystemBindings; this.userBindingsMap = userBindingsMap; this.systemBindingsMap = systemBindingsMap; } enum BindingType { USER, SYSTEM,; static BindingType from(Binding binding) { return from(binding.getType()); } static BindingType from(int eclipseBindingType) { if (eclipseBindingType == Binding.SYSTEM) { return SYSTEM; } else if (eclipseBindingType == Binding.USER) { return USER; } else { throw new UnsupportedOperationException("Binding type: " + eclipseBindingType); } } } void dumpBindingsToFile(IPath outputLocation, String description) throws FileNotFoundException, IOException { if (debugDumpSystemBindings) { dumpBindingsToFile(BindingType.SYSTEM, systemBindingsMap, outputLocation.removeFileExtension().addFileExtension("sys"), description); } dumpBindingsToFile(BindingType.USER, userBindingsMap, outputLocation, description); } private void dumpBindingsToFile(BindingType bindingType, Map<KbaChangeSetQualifier, KbaChangeSet> kbaChangeSet, IPath outputLocation, String description) throws FileNotFoundException, IOException { String output = getBindingsPrintout(bindingType, kbaChangeSet, description); File file = outputLocation.toFile(); PrintStream stream = null; try { stream = new PrintStream(new FileOutputStream(file)); stream.print(output); } finally { Closeables.closeQuietly(stream); } } static String getBindingsPrintout(BindingType bindingType, Map<KbaChangeSetQualifier, KbaChangeSet> bindings, String description) { Preconditions.checkNotNull(description); StringBuilder output = new StringBuilder().append("{\n").append(i(1)) .append(quote(KeyBindingsParser.METADATA_JSON_KEY)).append(" : {\n").append(i(2)) .append(kvn(KeyBindingsParser.DESCRIPTION_JSON_KEY, description)).append(i(1)).append("},\n") .append(i(1)).append(quote(KeyBindingsParser.CHANGE_SETS_JSON_KEY)).append(" : [\n"); for (KbaChangeSetQualifier q : bindings.keySet()) { output.append(i(2)).append("{\n").append(i(2)) .append(kvcn(KeyBindingsParser.SCHEME_JSON_KEY, q.scheme)); if (q.platform != null) { output.append(i(2)).append(kvcn(KeyBindingsParser.PLATFORM_JSON_KEY, q.platform)); } output.append(i(2)).append(kvcn(KeyBindingsParser.CONTEXT_JSON_KEY, q.context)).append(i(2)) .append(kvcn(KeyBindingsParser.ACTION_JSON_KEY, q.action)).append(i(2)) .append(quote(KeyBindingsParser.BINDINGS_JSON_KEY)).append(" : [\n"); for (KbaBinding b : bindings.get(q).getBindingList()) { output.append(formatKbaBinding(b)); // TODO: GSON is not happy about trailing commas. Either make // GSON happy, or suppress trailing whitespaces } output.append(i(3)).append("]\n").append(i(2)).append("},\n"); } output.append(i(1)).append("]\n"); output.append("}"); return output.toString(); } private static CharSequence formatKbaBinding(KbaBinding b) { @SuppressWarnings("unused") // Remove needs to be worked on. boolean remove = false; StringBuilder toPrint = new StringBuilder().append(i(3)).append("{") .append(kvcs(KeyBindingsParser.KEYS_JSON_KEY, b.getKeySequence())).append(formatCommand(b)) .append("},\n"); return toPrint; } private static String formatCommand(KbaBinding b) { StringBuilder result = new StringBuilder().append(kv(KeyBindingsParser.COMMAND_JSON_KEY, b.getCid())); Map<String, String> parameterMap = b.getParameters(); if (parameterMap.size() > 0) { result.append(", ") .append(kd(KeyBindingsParser.COMMAND_PARAMETERS_JSON_KEY, formatParameters(parameterMap))); } return result.toString(); } private static String formatParameters(final Map<String, String> parameterMap) { StringBuilder sb = new StringBuilder(); sb.append("{"); Function<String, String> function = new Function<String, String>() { public String apply(String key) { return kv(urlEncoded(key), urlEncoded(parameterMap.get(key))); } }; Iterable<String> transformed = Iterables.transform(parameterMap.keySet(), function); sb.append(Joiner.on(", ").join(transformed)); sb.append("}"); return sb.toString(); } private static String urlEncoded(String key) { try { return URLEncoder.encode(key, "US-ASCII"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } // Beging quick-and-dirty methods to help us format the output private static String i(int indentNumber) { StringBuilder result = new StringBuilder(); for (int i = 0; i < indentNumber; i++) { result.append(" "); } return result.toString(); } private static String kd(String key, String data) { return quote(key) + " : " + data; } private static String kvn(String key, String value) { return quote(key) + " : " + quote(value) + "\n"; } private static String kv(String key, String value) { return quote(key) + " : " + quote(value); } private static String kvcs(String key, String value) { return quote(key) + " : " + quote(value) + ", "; } private static String kvcn(String key, String value) { return quote(key) + " : " + quote(value) + ",\n"; } private static String quote(String string) { StringBuilder sb = new StringBuilder("\""); for (char c : string.toCharArray()) { if (c == '\"' || c == '\\') { sb.append('\\'); } sb.append(c); } sb.append("\""); return sb.toString(); } }