You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ActionManager.java 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. /*
  2. * Copyright (c) 2006-2007 Chris Smith, Shane Mc Cormack, Gregory Holmes
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. package uk.org.ownage.dmdirc.actions;
  23. import java.io.File;
  24. import java.io.IOException;
  25. import java.util.ArrayList;
  26. import java.util.HashMap;
  27. import java.util.List;
  28. import java.util.Map;
  29. import uk.org.ownage.dmdirc.Channel;
  30. import uk.org.ownage.dmdirc.Config;
  31. import uk.org.ownage.dmdirc.Server;
  32. import uk.org.ownage.dmdirc.logger.ErrorLevel;
  33. import uk.org.ownage.dmdirc.logger.Logger;
  34. import uk.org.ownage.dmdirc.parser.ChannelClientInfo;
  35. import uk.org.ownage.dmdirc.plugins.PluginManager;
  36. /**
  37. * Manages all actions for the client.
  38. * @author chris
  39. */
  40. public class ActionManager {
  41. /** A list of registered action types. */
  42. private static List<ActionType> actionTypes;
  43. /** A list of registered action components. */
  44. private static List<ActionComponent> actionComponents;
  45. /** A list of registered action comparisons. */
  46. private static List<ActionComparison> actionComparisons;
  47. /** A map linking types and a list of actions that're registered for them. */
  48. private static HashMap<ActionType, List<Action>> actions;
  49. /** A map linking groups and a list of actions that're in them. */
  50. private static HashMap<String, List<Action>> groups;
  51. /** Creates a new instance of ActionManager. */
  52. private ActionManager() {
  53. }
  54. /** Initialises the action manager. */
  55. public static void init() {
  56. actionTypes = new ArrayList<ActionType>();
  57. actionComparisons = new ArrayList<ActionComparison>();
  58. actionComponents = new ArrayList<ActionComponent>();
  59. registerActionTypes(CoreActionType.values());
  60. registerActionComparisons(CoreActionComparison.values());
  61. registerActionComponents(CoreActionComponent.values());
  62. }
  63. /**
  64. * Registers a set of actiontypes with the manager.
  65. * @param types An array of ActionTypes to be registered
  66. */
  67. public static void registerActionTypes(final ActionType[] types) {
  68. for (ActionType type : types) {
  69. actionTypes.add(type);
  70. }
  71. }
  72. /**
  73. * Registers a set of action components with the manager.
  74. * @param comps An array of ActionComponents to be registered
  75. */
  76. public static void registerActionComponents(final ActionComponent[] comps) {
  77. for (ActionComponent comp : comps) {
  78. actionComponents.add(comp);
  79. }
  80. }
  81. /**
  82. * Registers a set of action comparisons with the manager.
  83. * @param comps An array of ActionComparisons to be registered
  84. */
  85. public static void registerActionComparisons(final ActionComparison[] comps) {
  86. for (ActionComparison comp : comps) {
  87. actionComparisons.add(comp);
  88. }
  89. }
  90. /**
  91. * Returns a map of groups to action lists.
  92. * @return a map of groups to action lists
  93. */
  94. public static Map<String, List<Action>> getGroups() {
  95. return groups;
  96. }
  97. /**
  98. * Loads actions from the user's directory.
  99. */
  100. public static void loadActions() {
  101. actions = new HashMap<ActionType, List<Action>>();
  102. groups = new HashMap<String, List<Action>>();
  103. final File dir = new File(getDirectory());
  104. if (!dir.exists()) {
  105. try {
  106. dir.mkdirs();
  107. dir.createNewFile();
  108. } catch (IOException ex) {
  109. Logger.error(ErrorLevel.ERROR, "Unable to create actions dir", ex);
  110. }
  111. }
  112. if (dir == null || dir.listFiles() == null) {
  113. Logger.error(ErrorLevel.WARNING, "Unable to load user action files");
  114. } else {
  115. for (File file : dir.listFiles()) {
  116. if (file.isDirectory()) {
  117. groups.put(file.getName(), new ArrayList<Action>());
  118. loadActions(file);
  119. }
  120. }
  121. }
  122. }
  123. /**
  124. * Loads action files from a specified group directory.
  125. * @param dir The directory to scan.
  126. */
  127. private static void loadActions(final File dir) {
  128. for (File file : dir.listFiles()) {
  129. new Action(dir.getName(), file.getName());
  130. }
  131. }
  132. /**
  133. * Registers an action with the manager.
  134. * @param action The action to be registered
  135. */
  136. public static void registerAction(final Action action) {
  137. if (actions == null) {
  138. init();
  139. }
  140. for (ActionType trigger : action.getTriggers()) {
  141. if (!actions.containsKey(trigger)) {
  142. actions.put(trigger, new ArrayList<Action>());
  143. }
  144. actions.get(trigger).add(action);
  145. }
  146. if (!groups.containsKey(action.getGroup())) {
  147. groups.put(action.getGroup(), new ArrayList<Action>());
  148. }
  149. groups.get(action.getGroup()).add(action);
  150. }
  151. /**
  152. * Unregisters an action with the manager.
  153. * @param action The action to be unregistered
  154. */
  155. public static void unregisterAction(final Action action) {
  156. if (actions == null) {
  157. return;
  158. }
  159. for (Map.Entry<ActionType,List<Action>> map : actions.entrySet()) {
  160. if (map.getValue().contains(action)) {
  161. map.getValue().remove(action);
  162. }
  163. }
  164. for (Map.Entry<String,List<Action>> map : groups.entrySet()) {
  165. if (map.getValue().contains(action)) {
  166. map.getValue().remove(action);
  167. }
  168. }
  169. }
  170. /**
  171. * Deletes the specified action.
  172. * @param action The action to be deleted
  173. */
  174. public static void deleteAction(final Action action) {
  175. if (actions == null) {
  176. init();
  177. }
  178. unregisterAction(action);
  179. action.delete();
  180. }
  181. /**
  182. * Processes an event of the specified type.
  183. * @param type The type of the event to process
  184. * @param format The format of the message that's going to be displayed for
  185. * the event. Actions may change this format.
  186. * @param arguments The arguments for the event
  187. */
  188. public static void processEvent(final ActionType type,
  189. final StringBuffer format, final Object ... arguments) {
  190. if (actionTypes == null) {
  191. init();
  192. }
  193. if (type.getType().getArity() == arguments.length) {
  194. PluginManager.getPluginManager().processEvent(type, format, arguments);
  195. triggerActions(type, format, arguments);
  196. } else {
  197. Logger.error(ErrorLevel.ERROR, "Invalid number of arguments for action " + type);
  198. }
  199. }
  200. /**
  201. * Triggers actions that respond to the specified type.
  202. * @param type The type of the event to process
  203. * @param format The format of the message that's going to be displayed for
  204. * the event. Actions may change this format.*
  205. * @param arguments The arguments for the event
  206. */
  207. private static void triggerActions(final ActionType type,
  208. final StringBuffer format, final Object ... arguments) {
  209. if (actions.containsKey(type)) {
  210. for (Action action : actions.get(type)) {
  211. action.trigger(format, arguments);
  212. }
  213. }
  214. }
  215. /**
  216. * Returns the directory that should be used to store actions.
  217. * @return The directory that should be used to store actions
  218. */
  219. public static String getDirectory() {
  220. final String fs = System.getProperty("file.separator");
  221. return Config.getConfigDir() + "actions" + fs;
  222. }
  223. /**
  224. * Creates a new group with the specified name
  225. * @param group The group to be created
  226. */
  227. public static void makeGroup(final String group) {
  228. if (!groups.containsKey(group) && new File(getDirectory() + group).mkdir()) {
  229. groups.put(group, new ArrayList<Action>());
  230. }
  231. }
  232. /**
  233. * Removes the group with the specified name.
  234. * @param group The group to be removed
  235. */
  236. public static void removeGroup(final String group) {
  237. if (groups.containsKey(group)) {
  238. final File dir = new File(getDirectory() + group);
  239. for (File file : dir.listFiles()) {
  240. if (!file.delete()) {
  241. Logger.error(ErrorLevel.ERROR, "Unable to remove file: " + file.getAbsoluteFile());
  242. return;
  243. }
  244. }
  245. if (!dir.delete()) {
  246. Logger.error(ErrorLevel.ERROR, "Unable to remove dir: " + dir.getAbsoluteFile());
  247. return;
  248. }
  249. groups.remove(group);
  250. }
  251. }
  252. /**
  253. * Renames the specified group.
  254. * @param oldName The old name of the group
  255. * @param newName The new name of the group
  256. */
  257. public static void renameGroup(final String oldName, final String newName) {
  258. if (groups.containsKey(oldName)) {
  259. makeGroup(newName);
  260. for (Action action : groups.get(oldName)) {
  261. action.setGroup(newName);
  262. groups.get(newName).add(action);
  263. }
  264. groups.get(oldName).clear();
  265. removeGroup(oldName);
  266. }
  267. }
  268. /**
  269. * Returns the action comparison specified by the given string, or null if it
  270. * doesn't match a valid registered action comparison.
  271. * @param type The name of the action comparison to try and find
  272. * @return The actioncomparison with the specified name, or null on failure
  273. */
  274. public static ActionType getActionType(final String type) {
  275. if (actionTypes == null) {
  276. init();
  277. }
  278. for (ActionType target : actionTypes) {
  279. if (((Enum) target).name().equals(type)) {
  280. return target;
  281. }
  282. }
  283. return null;
  284. }
  285. /**
  286. * Returns a list of action types that are compatible with the one
  287. * specified.
  288. * @param type The type to be checked against
  289. * @return A list of compatible action types
  290. */
  291. public static List<ActionType> getCompatibleTypes(final ActionType type) {
  292. final List<ActionType> res = new ArrayList<ActionType>();
  293. for (ActionType target : actionTypes) {
  294. if (!target.equals(type) && target.getType().equals(type.getType())) {
  295. res.add(target);
  296. }
  297. }
  298. return res;
  299. }
  300. /**
  301. * Returns a list of action components that are compatible with the
  302. * specified class
  303. * @param target The class to be tested
  304. * @return A list of compatible action components
  305. */
  306. public static List<ActionComponent> getCompatibleComponents(final Class target) {
  307. final List<ActionComponent> res = new ArrayList<ActionComponent>();
  308. for (ActionComponent subject : actionComponents) {
  309. if (subject.appliesTo().equals(target)) {
  310. res.add(subject);
  311. }
  312. }
  313. return res;
  314. }
  315. /**
  316. * Returns a list of action comparisons that are compatible with the
  317. * specified class
  318. * @param target The class to be tested
  319. * @return A list of compatible action comparisons
  320. */
  321. public static List<ActionComparison> getCompatibleComparisons(final Class target) {
  322. final List<ActionComparison> res = new ArrayList<ActionComparison>();
  323. for (ActionComparison subject : actionComparisons) {
  324. if (subject.appliesTo().equals(target)) {
  325. res.add(subject);
  326. }
  327. }
  328. return res;
  329. }
  330. /**
  331. * Returns a list of all the action types registered by this manager.
  332. */
  333. public static List<ActionType> getTypes() {
  334. return actionTypes;
  335. }
  336. /**
  337. * Returns a list of all the action types registered by this manager.
  338. */
  339. public static List<ActionComparison> getComparisons() {
  340. return actionComparisons;
  341. }
  342. /**
  343. * Returns the action component specified by the given string, or null if it
  344. * doesn't match a valid registered action component.
  345. * @param type The name of the action component to try and find
  346. * @return The actioncomponent with the specified name, or null on failure
  347. */
  348. public static ActionComponent getActionComponent(final String type) {
  349. if (actionComponents == null) {
  350. init();
  351. }
  352. for (ActionComponent target : actionComponents) {
  353. if (((Enum) target).name().equals(type)) {
  354. return target;
  355. }
  356. }
  357. return null;
  358. }
  359. /**
  360. * Returns the action type specified by the given string, or null if it
  361. * doesn't match a valid registered action type.
  362. * @param type The name of the action type to try and find
  363. * @return The actiontype with the specified name, or null on failure
  364. */
  365. public static ActionComparison getActionComparison(final String type) {
  366. if (actionComparisons == null) {
  367. init();
  368. }
  369. for (ActionComparison target : actionComparisons) {
  370. if (((Enum) target).name().equals(type)) {
  371. return target;
  372. }
  373. }
  374. return null;
  375. }
  376. /**
  377. * Substitutes variables into the string based on the arguments.
  378. * @param target The string to be altered
  379. * @param arguments The arguments for the action
  380. */
  381. public static String substituteVars(final String target, final Object ... arguments) {
  382. String res = target;
  383. Server server = null;
  384. Channel channel = null;
  385. ChannelClientInfo source = null;
  386. if (arguments.length > 0 && arguments[0] instanceof Server) {
  387. server = (Server) arguments[0];
  388. } else if (arguments.length > 0 && arguments[0] instanceof Channel) {
  389. channel = (Channel) arguments[0];
  390. server = channel.getServer();
  391. }
  392. if (arguments.length > 1 && arguments[1] instanceof ChannelClientInfo) {
  393. source = (ChannelClientInfo) arguments[1];
  394. }
  395. if (server != null) {
  396. res = res.replaceAll("\\$nick", server.getParser().getMyself().getNickname());
  397. if (server.isAway()) {
  398. res = res.replaceAll("\\$awaymsg", server.getAwayMessage());
  399. }
  400. }
  401. if (channel != null) {
  402. res = res.replaceAll("\\$chan", channel.getChannelInfo().getName());
  403. }
  404. if (source != null) {
  405. res = res.replaceAll("\\$source", source.getNickname());
  406. }
  407. if (arguments.length > 2 && arguments[2] instanceof String) {
  408. res = res.replaceAll("\\$message", (String) arguments[2]);
  409. }
  410. for (String key : Config.getOptions("actions")) {
  411. res = res.replaceAll("\\$" + key, Config.getOption("actions", key));
  412. }
  413. if (arguments.length > 2 && arguments[2] instanceof String[]) {
  414. int i = 1;
  415. for (String arg : (String[]) arguments[2]) {
  416. res = res.replaceAll("\\$" + i, arg);
  417. i++;
  418. }
  419. }
  420. return res;
  421. }
  422. }