PageRenderTime 25ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/src/com/atlassian/uwc/ui/listeners/SaveListener.java

https://bitbucket.org/dodok1/uwc
Java | 304 lines | 186 code | 39 blank | 79 comment | 18 complexity | 4820f9a7426fe6e6fff3b9fba2f4b670 MD5 | raw file
  1. package com.atlassian.uwc.ui.listeners;
  2. import java.awt.event.ActionEvent;
  3. import java.awt.event.ActionListener;
  4. import java.awt.event.FocusEvent;
  5. import java.awt.event.FocusListener;
  6. import java.util.Observable;
  7. import java.util.Observer;
  8. import java.util.Vector;
  9. import java.util.regex.Matcher;
  10. import java.util.regex.Pattern;
  11. import javax.swing.JComboBox;
  12. import javax.swing.JComponent;
  13. import javax.swing.JList;
  14. import javax.swing.JPasswordField;
  15. import javax.swing.JTextField;
  16. import org.apache.log4j.Logger;
  17. import com.atlassian.uwc.ui.FeedbackWindow;
  18. import com.atlassian.uwc.ui.UWCGuiModel;
  19. import com.atlassian.uwc.ui.UWCUserSettings;
  20. import com.atlassian.uwc.ui.UWCUserSettings.Setting;
  21. /**
  22. * saves settings on event triggers
  23. */
  24. public class SaveListener implements ActionListener, FocusListener, FeedbackHandler, Observer {
  25. private static final String PATH_DELIMITER = "::";
  26. public static final String DEFAULT_COMMAND = "calling save listener action";
  27. Logger log = Logger.getLogger(this.getClass());
  28. private static final String COMMAND_BASE = "Saving:";
  29. /**
  30. * type of ui element
  31. */
  32. public enum Component {
  33. UNKNOWN,
  34. COMBOBOX,
  35. TEXTFIELD,
  36. PASSWORD,
  37. PAGES,
  38. }
  39. private JComponent component = null;
  40. private Component type = Component.UNKNOWN;
  41. private UWCUserSettings.Setting setting;
  42. private UWCGuiModel model;
  43. private FeedbackWindow feedbackWindow;
  44. /**
  45. * instantiates the object,
  46. * and notes the component type as COMBOBOX
  47. * @param component
  48. * @param model
  49. * @param setting
  50. * @param feedbackWindow
  51. */
  52. public SaveListener(JComboBox component, UWCGuiModel model, Setting setting, FeedbackWindow feedbackWindow) {
  53. this.component = component;
  54. this.setting = setting;
  55. this.model = model;
  56. this.feedbackWindow = feedbackWindow;
  57. this.type = Component.COMBOBOX;
  58. }
  59. /**
  60. * instantiates the object,
  61. * and notes the component type as TEXTFIELD
  62. * @param component
  63. * @param model
  64. * @param setting
  65. * @param feedbackWindow
  66. */
  67. public SaveListener(JTextField component, UWCGuiModel model, Setting setting, FeedbackWindow feedbackWindow) {
  68. this.component = component;
  69. this.setting = setting;
  70. this.model = model;
  71. this.feedbackWindow = feedbackWindow;
  72. this.type = Component.TEXTFIELD;
  73. }
  74. /**
  75. * instantiates the object,
  76. * and notes the component type as PASSWORD
  77. * @param component
  78. * @param model
  79. * @param setting
  80. * @param feedbackWindow
  81. */
  82. public SaveListener(JPasswordField component, UWCGuiModel model, Setting setting, FeedbackWindow feedbackWindow) {
  83. this.component = component;
  84. this.setting = setting;
  85. this.model = model;
  86. this.feedbackWindow = feedbackWindow;
  87. this.type = Component.PASSWORD;
  88. }
  89. public SaveListener(JList component, UWCGuiModel model, Setting setting, FeedbackWindow feedbackWindow) {
  90. this.component = component;
  91. this.setting = setting;
  92. this.model = model;
  93. this.feedbackWindow = feedbackWindow;
  94. this.type = Component.PAGES;
  95. }
  96. /**
  97. * does one of two things:
  98. * (2) identifies that the event has all the necessary info for saving, and saves the setting
  99. * (1) retriggers the event with additional necessary info saved in the command
  100. * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
  101. */
  102. public void actionPerformed(ActionEvent event) {
  103. String command = event.getActionCommand();
  104. if (command.startsWith(COMMAND_BASE)) { //re-sent event with useful info
  105. saveComponent(this.setting, command);
  106. }
  107. else { //original event
  108. String newCommand = COMMAND_BASE;
  109. switch(type) {
  110. case COMBOBOX:
  111. newCommand += ((JComboBox)component).getSelectedItem();
  112. break;
  113. case TEXTFIELD:
  114. newCommand += ((JTextField)component).getText();
  115. break;
  116. case PASSWORD:
  117. newCommand += getPasswordData((JPasswordField)component);
  118. break;
  119. case PAGES:
  120. newCommand += getPagesString(this.model.getPageNames());
  121. break;
  122. default:
  123. log.error("Component Type Unknown! Could not save.");
  124. return;
  125. }
  126. ActionEvent newEvent = new ActionEvent(
  127. event.getSource(),
  128. event.getID(),
  129. newCommand, //this is the part that's different
  130. event.getModifiers());
  131. this.actionPerformed(newEvent);
  132. }
  133. }
  134. /**
  135. * @param component
  136. * @return the password saved in the given component as a String
  137. */
  138. public static String getPasswordData(JPasswordField component) {
  139. char[] passCh = component.getPassword();
  140. return String.copyValueOf(passCh);
  141. }
  142. private String getPagesString(Vector<String> pages) {
  143. String pagesString = "";
  144. for (int i = 0; i < pages.size(); i++) {
  145. String page = (String) pages.get(i);
  146. if (i > 0) pagesString += PATH_DELIMITER;
  147. pagesString += page;
  148. }
  149. return pagesString;
  150. }
  151. /**
  152. * saves the setting by parsing the given command
  153. * @param setting
  154. * @param command should be COMMAND_BASE + the value of the setting
  155. */
  156. private void saveComponent(Setting setting, String command) {
  157. String value = command.replaceFirst(COMMAND_BASE, ""); //get rid of header
  158. if (!valid(setting, value)) {
  159. revert();
  160. String instructions = getSettingSpecificInstructions(setting);
  161. String message = "Value '" + value + "'" +
  162. " for Setting '" + setting.toString() + "'" +
  163. " is invalid. " +
  164. instructions;
  165. this.feedbackWindow.launch();
  166. this.feedbackWindow.updateFeedback(message);
  167. log.error(message);
  168. }
  169. if (this.model == null) {
  170. log.error("Could not save. Model is null.");
  171. return;
  172. }
  173. //log it but hide passwords
  174. String printVal = value;
  175. if (setting == Setting.PASSWORD)
  176. printVal = "*******";
  177. log.debug("Saving Setting '" +setting + "' = '" + printVal +"'");
  178. //save it
  179. this.model.saveSetting(setting, value);
  180. }
  181. static String validAttachment = "\\d+[BKMG]";
  182. static Pattern validAttachmentPattern = Pattern.compile(validAttachment, Pattern.CASE_INSENSITIVE);
  183. /**
  184. * validates the value for the given setting
  185. * @param setting
  186. * @param value
  187. * @return true if value is allowed
  188. */
  189. public static boolean valid(Setting setting, String value) {
  190. switch (setting) {
  191. case ATTACHMENT_SIZE:
  192. if (UWCUserSettings.DEFAULT_ATTACHMENT_SIZE.equals(value)) return true;
  193. Matcher validAttachmentFinder = validAttachmentPattern.matcher(value);
  194. return validAttachmentFinder.matches();
  195. case URL:
  196. return (UWCUserSettings.isValid(setting, value));
  197. default:
  198. return true;
  199. }
  200. }
  201. /**
  202. * getter
  203. * @return current setting
  204. */
  205. public Setting getSetting() {
  206. return this.setting;
  207. }
  208. /**
  209. * retrieves use instructions appropriate for the given setting
  210. * @param setting
  211. * @return use instructions
  212. */
  213. public static String getSettingSpecificInstructions(Setting setting) {
  214. switch (setting) {
  215. case ATTACHMENT_SIZE:
  216. return "Value must be in this format: number[BKMG]. For example: 15M";
  217. case URL:
  218. return "Value must be in this format: [https?://]something.com[:port][/contextpath]\n";
  219. }
  220. return "";
  221. }
  222. /**
  223. * reverts any changes to the component to the previous value
  224. */
  225. private void revert() {
  226. switch (this.type) {
  227. case TEXTFIELD:
  228. JTextField textfield = (JTextField) component;
  229. textfield.setText(this.model.getSetting(this.setting));
  230. }
  231. }
  232. /**
  233. * Identifies the current setting as "unsaved".
  234. * Note: Saving occurs after the focus is lost. (See this.focusLost.)
  235. * So we keep note of which setting the user is currently focused on
  236. * so that if we start an operation (conversion, export, etc), we know which
  237. * setting still needs to be saved before we actually do the op.
  238. * @see java.awt.event.FocusListener#focusGained(java.awt.event.FocusEvent)
  239. */
  240. public void focusGained(FocusEvent arg0) {
  241. this.model.setUnsaved(this.setting);
  242. }
  243. /**
  244. * Saves this component when the focus is lost.
  245. * @see java.awt.event.FocusListener#focusLost(java.awt.event.FocusEvent)
  246. */
  247. public void focusLost(FocusEvent event) {
  248. //save when the focus is lost
  249. if (event.getID() == FocusEvent.FOCUS_LOST) {
  250. actionPerformed(new ActionEvent(
  251. event.getSource(), event.getID(), DEFAULT_COMMAND));
  252. }
  253. }
  254. public void update(Observable obs, Object obj) {
  255. //save when pages are added (when PageHandler.updateUI notifies observers)
  256. if (obs instanceof AddPagesListener ||
  257. obs instanceof SelectFileDropTargetListener ||
  258. obs instanceof RemovePagesListener) {
  259. actionPerformed(new ActionEvent(obs, 1, DEFAULT_COMMAND));
  260. }
  261. else {
  262. log.error("We haven't implemented use of this observer with the SaveListener: " + obs.getClass().toString());
  263. }
  264. }
  265. }