package org.emdev.ui.actions; import org.sufficientlysecure.viewer.R; import android.content.DialogInterface; import android.content.DialogInterface.OnMultiChoiceClickListener; import android.util.SparseBooleanArray; import android.view.KeyEvent; import android.view.View; import android.view.inputmethod.EditorInfo; import android.widget.AdapterView; import android.widget.TextView; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import org.emdev.common.log.LogContext; import org.emdev.common.log.LogManager; import org.emdev.utils.LengthUtils; import org.emdev.utils.collections.SparseArrayEx; public class ActionEx implements Runnable, View.OnClickListener, View.OnLongClickListener, AdapterView.OnItemClickListener, DialogInterface.OnClickListener, OnMultiChoiceClickListener, TextView.OnEditorActionListener { private static final LogContext LCTX = LogManager.root().lctx("Actions"); private static final String SHORT_DESCRIPTION = "ShortDescription"; private static SparseArrayEx<String> s_names; private static Map<String, Integer> s_ids; public final int id; public final String name; private final ActionControllerMethod m_method; private final Map<String, Object> m_values = new LinkedHashMap<String, Object>(); private final Map<String, IActionParameter> m_actionParameters = new LinkedHashMap<String, IActionParameter>(); private boolean enabled = true; /** * Constructor * * @param controller * action controller * @param category * action category * @param id * action id */ ActionEx(final IActionController<?> controller, final int id) { this.id = id; this.name = getActionName(id); this.m_method = new ActionControllerMethod(controller, this); } /** * Returns the action's description. * * @return the actions description * @see #setDescription */ public String getDescription() { return getParameter(SHORT_DESCRIPTION); } /** * Sets the action's description. * * @param description * the string used to set the action's description * @see #getDescription * @beaninfo bound: true preferred: true attribute: visualUpdate true * description: The action's name. */ public void setDescription(final String description) { putValue(SHORT_DESCRIPTION, description); } public boolean isEnabled() { return enabled; } public void setEnabled(final boolean enabled) { this.enabled = enabled; } /** * @return ActionControllerMethod */ public ActionControllerMethod getMethod() { return m_method; } /** * Returns component managed by action controller created this action. * * @param <ManagedComponent> * managed component type * @return component managed by action controller created this action */ @SuppressWarnings("unchecked") public <ManagedComponent> ManagedComponent getManagedComponent() { return (ManagedComponent) getValue(IActionController.MANAGED_COMPONENT_PROPERTY); } /** * Gets the <code>Object</code> associated with the specified key. * * @param key * a string containing the specified <code>key</code> * @return the binding <code>Object</code> stored with this key; if * there are no keys, it will return <code>null</code> * @see javax.swing.AbstractAction#getValue(java.lang.String) */ @Deprecated public Object getValue(final String key) { return m_values.get(key); } public ActionEx putValue(final String key, final Object value) { m_values.put(key, value); return this; } /** * Gets the <code>Object</code> associated with the specified key. * * @param <T> * parameter type * @param key * a string containing the specified <code>key</code> * @return the binding <code>Object</code> stored with this key; if * there are no keys, it will return defaultValue parameter */ @SuppressWarnings("unchecked") public <T> T getParameter(final String key) { return (T) m_values.get(key); } /** * Gets the <code>Object</code> associated with the specified key. * * @param <T> * parameter type * @param key * a string containing the specified <code>key</code> * @param defaultValue * default value * @return the binding <code>Object</code> stored with this key; if * there are no keys, it will return defaultValue parameter */ @SuppressWarnings("unchecked") public <T> T getParameter(final String key, final T defaultValue) { final Object value = getParameter(key); return (T) (value != null ? value : defaultValue); } /** * Adds a parameter to the action * * @param parameter * action parameter to set */ public ActionEx addParameter(final IActionParameter parameter) { m_actionParameters.put(parameter.getName(), parameter); return this; } @Override public void run() { try { if (!enabled) { LCTX.d("Action " + name + ": disabled"); return; } setParameters(); LCTX.d("Execute action: " + name + ": " + m_values); m_method.invoke(this); } catch (final InvocationTargetException ex) { LCTX.e("Action " + name + " failed on execution: ", ex.getCause()); } catch (final Throwable th) { LCTX.e("Action " + name + " failed on execution: ", th); } finally { } } @Override public void onClick(final View view) { this.putValue(IActionController.VIEW_PROPERTY, view); run(); } @Override public boolean onLongClick(final View view) { this.putValue(IActionController.VIEW_PROPERTY, view); run(); return true; } @Override public void onClick(final DialogInterface dialog, final int which) { this.putValue(IActionController.DIALOG_PROPERTY, dialog); this.putValue(IActionController.DIALOG_ITEM_PROPERTY, which); this.run(); } public boolean isDialogItemSelected(final int which) { final SparseBooleanArray map = this.getParameter(IActionController.DIALOG_SELECTED_ITEMS_PROPERTY); return map != null ? map.get(which) : false; } @Override public void onClick(final DialogInterface dialog, final int which, final boolean isChecked) { SparseBooleanArray map = this.getParameter(IActionController.DIALOG_SELECTED_ITEMS_PROPERTY); if (map == null) { map = new SparseBooleanArray(); this.putValue(IActionController.DIALOG_SELECTED_ITEMS_PROPERTY, map); } map.put(which, isChecked); } @Override public boolean onEditorAction(final TextView textView, final int actionId, final KeyEvent keyEvent) { if ((actionId == EditorInfo.IME_NULL || actionId == EditorInfo.IME_ACTION_DONE)) { if ((keyEvent == null || keyEvent.getAction() == KeyEvent.ACTION_UP)) { this.putValue(IActionController.VIEW_PROPERTY, textView); run(); } return true; } return false; } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { this.putValue(IActionController.VIEW_PROPERTY, parent); this.putValue(IActionController.ADAPTER_SELECTED_ITEM_PROPERTY, parent.getAdapter().getItem(position)); run(); } /** * Sets parameter values to the action */ private void setParameters() { for (final Entry<String, IActionParameter> entry : m_actionParameters.entrySet()) { putValue(entry.getKey(), entry.getValue().getValue()); } } public static String getActionName(final int id) { if (s_names == null) { fillMapping(); } return LengthUtils.safeString(s_names.get(id), "0x" + Integer.toHexString(id)); } public static Integer getActionId(final String name) { if (s_ids == null) { fillMapping(); } return s_ids.get(name); } private static void fillMapping() { s_names = new SparseArrayEx<String>(); s_ids = new HashMap<String, Integer>(); for (final Field f : R.id.class.getFields()) { final int modifiers = f.getModifiers(); if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { if (f.getType() == int.class) { try { final int value = f.getInt(null); s_names.put(value, f.getName()); s_ids.put(f.getName(), value); } catch (final Throwable th) { } } } } } }