Java tutorial
/* * Copyright (C) Heavy Lifting Software 2007, Robert Wloch 2012. * * This file is part of MouseFeed. * * MouseFeed is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * MouseFeed is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with MouseFeed. If not, see <http://www.gnu.org/licenses/>. */ package com.mousefeed.eclipse.preferences; import static com.mousefeed.eclipse.preferences.PreferenceConstants.P_CONFIGURE_KEYBOARD_SHORTCUT_ENABLED; import static com.mousefeed.eclipse.preferences.PreferenceConstants.P_CONFIGURE_KEYBOARD_SHORTCUT_THRESHOLD; import static com.mousefeed.eclipse.preferences.PreferenceConstants.P_DEFAULT_ON_WRONG_INVOCATION_MODE; import static com.mousefeed.eclipse.preferences.PreferenceConstants.P_INVOCATION_CONTROL_ENABLED; import static com.mousefeed.eclipse.preferences.PreferenceConstants.P_SHOW_USED_KEYBOARD_SHORTCUT; import static org.apache.commons.lang.Validate.notNull; import com.mousefeed.client.OnWrongInvocationMode; import com.mousefeed.eclipse.Activator; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.ui.IMemento; import org.eclipse.ui.WorkbenchException; import org.eclipse.ui.XMLMemento; /** * Provides access to the plugin preferences. * Singleton. * * @author Andriy Palamarchuk * @author Robert Wloch */ public class PreferenceAccessor { /** * Name of the file to store action-specific behavior when the actions * are invoked wrong way. */ static final String ACTIONS_WRONG_INVOCATION_MODE_FILE = "actionsWrongInvocationMode.xml"; /** * The singleton instance. */ private static final PreferenceAccessor INSTANCE = new PreferenceAccessor(); /** * The root document for the action-specific wrong invocation mode * preferences. */ private static final String TAG_ACTIONS_WRONG_INVOCATION_MODE = "actionsWrongInvocationMode"; /** * The action tag name. */ private static final String TAG_ACTION = "action"; /** * The action id tag name. */ private static final String TAG_ACTION_ID = "id"; /** * The action label tag name. */ private static final String TAG_ACTION_LABEL = "label"; /** * The on wrong invocation mode handling approach. */ private static final String TAG_ON_WRONG_INVOCATION_MODE = "onWrongInvocationMode"; /** * Actions on wrong invocation mode settings. Keys - action ids, values - * the settings. */ private final Map<String, ActionOnWrongInvocationMode> actionsOnWrongMode = new HashMap<String, ActionOnWrongInvocationMode>(); /** * Creates new preference accessor. * Because this class is a singleton, the constructor normally should not be * used. It is exposed for testing purposes only. */ PreferenceAccessor() { loadActionsOnWrongInvocationMode(); } /** * The singleton instance. * @return the singleton instance. Never <code>null</code>. */ public static PreferenceAccessor getInstance() { return INSTANCE; } /** * Whether invocation control is enabled preference. * The preference indicates whether to help to learn the desired way to * invoke actions * @return current preference value whether invocation control is enabled. */ public boolean isInvocationControlEnabled() { return getPreferenceStore().getBoolean(P_INVOCATION_CONTROL_ENABLED); } /** * @param invocationControlEnabled the new value for the setting returned by * {@link #isInvocationControlEnabled()}. * @see #isInvocationControlEnabled() */ public void storeInvocationControlEnabled(final boolean invocationControlEnabled) { getPreferenceStore().setValue(P_INVOCATION_CONTROL_ENABLED, invocationControlEnabled); } /** * Whether keyboard shortcut configuration is enabled preference. * The preference indicates whether to show the Keys preference page * for often used actions without a shortcut. * @return current preference value whether keyboard shortcut configuration * is enabled. */ public boolean isConfigureKeyboardShortcutEnabled() { return getPreferenceStore().getBoolean(P_CONFIGURE_KEYBOARD_SHORTCUT_ENABLED); } /** * @param configureKeyboardShortcutEnabled the new value for the setting returned by * {@link #isConfigureKeyboardShortcutEnabled()}. * @see #isConfigureKeyboardShortcutEnabled() */ public void storeConfigureKeyboardShortcutEnabled(final boolean configureKeyboardShortcutEnabled) { getPreferenceStore().setValue(P_CONFIGURE_KEYBOARD_SHORTCUT_ENABLED, configureKeyboardShortcutEnabled); } /** * The default preference of the threshold for the action invocation counter * above which keyboard shortcut configuration is enabled. * @return the global configure keyboard shortcut threshold preference. * @see PreferenceConstants#P_CONFIGURE_KEYBOARD_SHORTCUT_THRESHOLD */ public int getConfigureKeyboardShortcutThreshold() { return getPreferenceStore().getInt(P_CONFIGURE_KEYBOARD_SHORTCUT_THRESHOLD); } /** * @param configureKeyboardShortcutThreshold the new value for the setting returned by * {@link #getConfigureKeyboardShortcutThreshold()}. * @see #getConfigureKeyboardShortcutThreshold() */ public void storeConfigureKeyboardShortcutThreshold(final int configureKeyboardShortcutThreshold) { getPreferenceStore().setValue(P_CONFIGURE_KEYBOARD_SHORTCUT_THRESHOLD, configureKeyboardShortcutThreshold); } /** * Whether the used keyboard shortcut should be shown is enabled preference. * The preference indicates whether to show the used keyboard shortcut for * e.g. screencasts or coding dojos performed on a projector. * @return current preference value whether keyboard shortcut should be shown. */ public boolean isShowUsedKeyboardShortcutEnabled() { return getPreferenceStore().getBoolean(P_SHOW_USED_KEYBOARD_SHORTCUT); } /** * @param showUsedKeyboardShortcutEnabled the new value for the setting returned by * {@link #isShowUsedKeyboardShortcutEnabled()}. * @see #isShowUsedKeyboardShortcutEnabled() */ public void storeShowUsedKeyboardShortcutEnabled(final boolean showUsedKeyboardShortcutEnabled) { getPreferenceStore().setValue(P_SHOW_USED_KEYBOARD_SHORTCUT, showUsedKeyboardShortcutEnabled); } /** * The default preference what to do by default on wrong invocation mode. * @return the global invocation mode preference. Never <code>null</code>. * @see PreferenceConstants#P_DEFAULT_ON_WRONG_INVOCATION_MODE */ public OnWrongInvocationMode getOnWrongInvocationMode() { final String stored = getPreferenceStore().getString(P_DEFAULT_ON_WRONG_INVOCATION_MODE); return stored == null ? OnWrongInvocationMode.DEFAULT : OnWrongInvocationMode.valueOf(stored); } /** * The preference what to do on wrong invocation mode for the specified * action. * @param actionId the id of the action get preferences for. * Not <code>null</code>. * @return the invocation mode preference. * <code>null</code> if there is no action-specific setting. * In this case use the default preference value. */ public OnWrongInvocationMode getOnWrongInvocationMode(final String actionId) { notNull(actionId); final ActionOnWrongInvocationMode mode = actionsOnWrongMode.get(actionId); return mode == null ? null : mode.getOnWrongInvocationMode(); } /** * Saves action-specific on wrong invocation mode settings. * @param settings the new value. Not <code>null</code>. */ public void setOnWrongInvocationMode(final ActionOnWrongInvocationMode settings) { notNull(settings); actionsOnWrongMode.put(settings.getId(), settings); saveActionsOnWrongInvocationMode(); } /** * Returns action-specific wrong invocation mode handling for all actions. * @return the action-specific settings. Read-only. * The collection nor its elements should not be changed. * Note, the collection and the objects in it should be cloned for using * for any significant period of time. * Never <code>null</code>, can be empty if no action-specific settings were * defined. * All objects in the collection have unique ids. */ public Collection<ActionOnWrongInvocationMode> getActionsOnWrongInvocationMode() { return actionsOnWrongMode.values(); } /** * Replaces the action-specific settings. * @param settings the new settings. Not <code>null</code>. * Changes to the data passed to this method won't affect the values stored * in this class. * @see #getActionsOnWrongInvocationMode() */ public void setActionsOnWrongInvocationMode(final Collection<ActionOnWrongInvocationMode> settings) { this.actionsOnWrongMode.clear(); for (ActionOnWrongInvocationMode mode : settings) { final ActionOnWrongInvocationMode clone; try { clone = (ActionOnWrongInvocationMode) mode.clone(); } catch (final CloneNotSupportedException e) { throw new RuntimeException(); } this.actionsOnWrongMode.put(clone.getId(), clone); } saveActionsOnWrongInvocationMode(); } /** * Removes action-specific on wrong invocation mode setting. * After calling this method when the action with the specified id is * handled using the default settings. * @param actionId the action id. not <code>null</code>. */ public void removeOnWrongInvocaitonMode(final String actionId) { notNull(actionId); actionsOnWrongMode.remove(actionId); saveActionsOnWrongInvocationMode(); } /** * Stores the provided preference. * @param value the new value. Not <code>null</code>. */ public void storeOnWrongInvocationMode(final OnWrongInvocationMode value) { notNull(value); getPreferenceStore().setValue(P_DEFAULT_ON_WRONG_INVOCATION_MODE, value.name()); } /** * Loads preferences for the {@link #getOnWrongInvocationMode(String)}. */ private void loadActionsOnWrongInvocationMode() { final File file = getActionsWrongInvocationModeFile(); if (!file.exists() || file.length() == 0) { // the file not initialized yet return; } Reader reader = null; try { reader = new FileReader(file); final XMLMemento memento = XMLMemento.createReadRoot(reader); loadActionsOnWrongInvocationMode(memento); } catch (final FileNotFoundException ignore) { // the file does not exist yet } catch (final WorkbenchException e) { throw new RuntimeException(e); } finally { try { if (reader != null) { reader.close(); } } catch (final IOException e) { throw new RuntimeException(e); } } } /** * Loads action-specific invocation handling. * @param memento the memento to load the data from. * Assumed not <code>null</code>. * @see #loadActionsOnWrongInvocationMode() */ private void loadActionsOnWrongInvocationMode(final XMLMemento memento) { actionsOnWrongMode.clear(); final IMemento[] children = memento.getChildren(TAG_ACTION); for (IMemento child : children) { final ActionOnWrongInvocationMode mode = new ActionOnWrongInvocationMode(); mode.setLabel(child.getString(TAG_ACTION_LABEL)); mode.setId(child.getString(TAG_ACTION_ID)); mode.setOnWrongInvocationMode( OnWrongInvocationMode.valueOf(child.getString(TAG_ON_WRONG_INVOCATION_MODE))); actionsOnWrongMode.put(mode.getId(), mode); } } /** * Saves settings loaded by {@link #loadActionsOnWrongInvocationMode()}. */ private void saveActionsOnWrongInvocationMode() { final XMLMemento memento = createActionsOnWrongInvocationModeMemento(); Writer writer = null; try { writer = new FileWriter(getActionsWrongInvocationModeFile()); memento.save(writer); } catch (final IOException e) { throw new RuntimeException(e); } finally { try { if (writer != null) { writer.close(); } } catch (final IOException e) { throw new RuntimeException(e); } } } /** * Generates XML memento with the actions wrong invocation mode data. * @return the memento. Never <code>null</code>. */ private XMLMemento createActionsOnWrongInvocationModeMemento() { final XMLMemento memento = XMLMemento.createWriteRoot(TAG_ACTIONS_WRONG_INVOCATION_MODE); for (ActionOnWrongInvocationMode val : actionsOnWrongMode.values()) { final IMemento actionMemento = memento.createChild(TAG_ACTION); actionMemento.putString(TAG_ACTION_ID, val.getId()); actionMemento.putString(TAG_ACTION_LABEL, val.getLabel()); actionMemento.putString(TAG_ON_WRONG_INVOCATION_MODE, val.getOnWrongInvocationMode().name()); } return memento; } /** * The plugin preference store. * @return never <code>null</code>. */ private IPreferenceStore getPreferenceStore() { return Activator.getDefault().getPreferenceStore(); } /** * File storing action-specific preferences for action invocation mode. * @return the file for action-specific preferences when the actions are * invoked with a wrong invocation mode. */ File getActionsWrongInvocationModeFile() { if (Activator.getDefault() == null) { return new File("nonexisting"); } return Activator.getDefault().getStateLocation().append(ACTIONS_WRONG_INVOCATION_MODE_FILE).toFile(); } }