source: trunk/src/org/expeditee/settings/Settings.java@ 1280

Last change on this file since 1280 was 1280, checked in by bln4, 5 years ago

Renamed MailMode action to ToggleBay
Renamed FrameCreator enums to more desirable names (David request)
Created test for altered functionality of FrameCreator as documented below.

FrameCreator now more cleanly obeys the specification of the enum parameter to its constructor. For example, override existing frameset ensures that the old frameset has been deleted (moved to trash).

File size: 10.1 KB
Line 
1/**
2 * Settings.java
3 * Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19package org.expeditee.settings;
20
21import java.lang.reflect.Field;
22import java.lang.reflect.Method;
23import java.util.HashMap;
24import java.util.Iterator;
25import java.util.LinkedList;
26import java.util.List;
27
28import org.expeditee.gui.AttributeValuePair;
29import org.expeditee.gui.Frame;
30import org.expeditee.gui.FrameCreator;
31import org.expeditee.gui.MessageBay;
32import org.expeditee.items.Text;
33import org.expeditee.items.widgets.Password;
34import org.expeditee.reflection.PackageLoader;
35import org.expeditee.setting.Setting;
36import org.expeditee.setting.VariableSetting;
37
38public abstract class Settings {
39
40 public static final String SETTINGS_PACKAGE_PARENT = "org.expeditee.";
41 public static final String SETTINGS_PACKAGE = SETTINGS_PACKAGE_PARENT + "settings.";
42
43 private static final class PageDescriptor {
44
45 private final HashMap<String, Setting> settings = new HashMap<String, Setting>();
46 private final List<String> orderedEntries = new LinkedList<String>();
47 private final List<VariableSetting> settingsList = new LinkedList<VariableSetting>();
48 private final Method onParsed;
49
50 private PageDescriptor(Class<?> clazz) {
51
52 // populate map of settings
53 for(Field f : clazz.getFields()) {
54 // Only allow classes that inherit from Setting
55 if(!Setting.class.isAssignableFrom(f.getType())) continue;
56
57 try {
58 Setting s = (Setting) f.get(null);
59 settings.put(f.getName().toLowerCase(), s);
60 if (s instanceof VariableSetting) settingsList.add((VariableSetting) s);
61 orderedEntries.add(f.getName());
62 } catch (Exception e) {
63 e.printStackTrace();
64 }
65 }
66
67 Method m = null;
68
69 try {
70 m = clazz.getMethod("onParsed", Text.class);
71 } catch(Exception e) {
72 // System.err.println(clazz.getName() + " has no onParsed(Text t) callback");
73 }
74
75 this.onParsed = m;
76 }
77 }
78
79 private static HashMap<String, PageDescriptor> _pages = new HashMap<String, PageDescriptor>();
80
81 private static boolean _init = false;
82
83 public static void Init()
84 {
85 if(_init) return;
86
87 _init = true;
88
89 try {
90 for(Class<?> clazz : PackageLoader.getClassesNew(SETTINGS_PACKAGE)) {
91 // Ignore this class since it's the controller
92 if(clazz.equals(Settings.class)) continue;
93
94 String settingsPageName = clazz.getPackage().getName().toLowerCase().substring(SETTINGS_PACKAGE_PARENT.length());
95 // System.out.println(settingsPage + " : " + clazz.getName());
96 _pages.put(settingsPageName, new PageDescriptor(clazz));
97 }
98
99 } catch (Exception e) {
100 e.printStackTrace();
101 }
102 }
103
104 /** Parses the settings tree, then resets any settings that were not set. */
105 public static void parseSettings(Text text)
106 {
107 List<VariableSetting> set = parseSettings(text, "");
108 List<VariableSetting> toDefault = new LinkedList<VariableSetting>();
109
110 for(PageDescriptor pd : _pages.values()) toDefault.addAll(pd.settingsList);
111
112 toDefault.removeAll(set);
113
114 for(VariableSetting s : toDefault) {
115 try {
116 s.reset();
117 } catch (Exception e) {
118 e.printStackTrace();
119 }
120 }
121 }
122
123 /**
124 * Sets all the simple settings.
125 *
126 * @param text
127 * @param prefix
128 *
129 * @return List of VariableSettings that were changed
130 */
131 private static List<VariableSetting> parseSettings(Text text, String prefix) {
132
133 List<VariableSetting> set = new LinkedList<VariableSetting>();
134
135 Frame child = text.getChild();
136
137 if(child == null) return set;
138
139 String settingsPage = prefix + text.getText().trim().toLowerCase().replaceAll("^@", "");
140 PageDescriptor pd = _pages.get(settingsPage);
141 if(pd == null) return set;
142
143 try {
144 // set the fields
145 List<Text> items = child.getBodyTextItems(false);
146 List<Text> annotations = new LinkedList<Text>(child.getAnnotationItems());
147 List<Frame> seen = new LinkedList<Frame>(); // to avoid getting stuck in a loop
148 seen.add(child);
149 // find all the frames for this settings page
150 while(!annotations.isEmpty()) {
151 Text annotation = annotations.remove(0);
152 Frame next = annotation.getChild();
153 if(next != null && !seen.contains(next)) {
154 items.addAll(next.getBodyTextItems(false));
155 annotations.addAll(next.getAnnotationItems());
156 seen.add(next);
157 }
158 }
159
160 // parse all the settings items on this page
161 for(Text t : items) {
162 AttributeValuePair avp = new AttributeValuePair(t.getText(), false);
163 try {
164 String settingName = avp.getAttributeOrValue().trim().toLowerCase();
165 // System.out.println(avp.getAttributeOrValue().trim().toLowerCase().replaceAll("^@", ""));
166 Setting s = pd.settings.get(settingName);//.replaceAll("^@", ""));
167 if(s == null) {
168 if(settingName.startsWith("//") || settingName.startsWith("@")) {
169 continue;
170 }
171 // System.out.println("Couldn't find setting \"" + settingName + "\"");
172 List<String> validPages = new LinkedList<String>();
173 // if the setting isn't found on the current page, check all child pages
174 for(String k : _pages.keySet()) {
175 if(k.startsWith(settingsPage) && k.length() > settingsPage.length()) {
176 // System.out.println(k + " is a child of " + settingsPage);
177 PageDescriptor cpd = _pages.get(k);
178 Setting tmp = cpd.settings.get(settingName);
179 if(tmp != null) {
180 // System.out.println("Found setting in subpage: " + k);
181 s = tmp;
182 validPages.add(k);
183 }
184 }
185 }
186
187 if(s == null) continue;
188
189 if(validPages.size() > 1) {
190 StringBuffer warnMessage = new StringBuffer("Found multiple matching settings in the following settings subpages: ");
191 String lastPage = "";
192 for(String page : validPages) {
193 warnMessage.append("\"" + page + "\",");
194 lastPage = page;
195 }
196 warnMessage.deleteCharAt(warnMessage.length() - 1);
197 warnMessage.append(" - choosing " + lastPage);
198 MessageBay.warningMessage(warnMessage.toString());
199 }
200 }
201
202 if(s.setSetting(t) && s instanceof VariableSetting) set.add((VariableSetting) s);
203
204 } catch (Exception e) {
205 e.printStackTrace();
206 }
207 }
208
209 // call the onParsed method if one exists
210 if(pd.onParsed != null) {
211 pd.onParsed.invoke(null, text);
212 }
213
214 } catch (Exception e) {
215 e.printStackTrace();
216 return set;
217 }
218
219 // if the page was a settings page, check if it has any subpages
220 for(Text t : child.getTextItems()) {
221 set.addAll(parseSettings(t, settingsPage + "."));
222 }
223 return set;
224 }
225
226 public static void generateSettingsTree(Text link) {
227 generateSettingsTree("settings", link);
228 }
229
230 private static void generateSettingsTree(String page, Text text) {
231 Frame parent = text.getParentOrCurrentFrame();
232 FrameCreator frames = new FrameCreator(parent.getFramesetName(), parent.getPath(), page, FrameCreator.ExistingFramesetOptions.AppendSegregatedFrames, false);
233 text.setLink(frames.getName());
234
235 // Add subpages of the current page by recursing
236 for (String k: _pages.keySet()) {
237 if (k.startsWith(page.toLowerCase()) && !k.equals(page)) {
238 String name = k.substring(page.length() + 1);
239 if (name.indexOf('.') != -1) {
240 continue;
241 }
242 System.out.println("@Settings: Generating " + name);
243 generateSettingsTree(k, frames.addText(name.substring(0, 1).toUpperCase() + name.substring(1), null, null, null, false));
244 }
245 }
246
247 // Start building current page
248 frames.setLastY(frames.getLastY() + 20);
249 // Add Settings of the current page
250 PageDescriptor pd = _pages.get(page);
251 if (pd == null) {
252 frames.save();
253 return;
254 }
255
256
257 Iterator<String> keys = pd.orderedEntries.stream().map(t -> t.toLowerCase()).iterator();
258 while(keys.hasNext()) {
259 String key = keys.next();
260 Setting setting = pd.settings.get(key);
261 if (setting == null) {
262 continue;
263 }
264
265 // Keep track of were we are placing items on Frames.
266 int x = 0, y = 0;
267
268 if (key.equals("pass")) {
269 // Special case for Password widgets
270 Text passwordWidgetText = frames.addText("iw: org.expeditee.items.widgets.Passwsord", null, null, null, false);
271 Password pw = new Password(passwordWidgetText, null);
272 pw.setPassword("");
273 frames.getCurrentFrame().removeItem(passwordWidgetText);
274 frames.getCurrentFrame().addAllItems(pw.getItems());
275 x = passwordWidgetText.getX() + passwordWidgetText.getBoundsWidth();
276 y = passwordWidgetText.getY();
277 } else {
278 // Determine the content for a setting label.
279 String name = key.substring(0, 1).toUpperCase() + key.substring(1);
280
281 // Construct and add text representation for setting.
282 // If a setting has no initialised value then it is not included.
283 Text settingRepresentation = setting.generateRepresentation(name, frames.getCurrentFrame().getFramesetName()).copy();
284 if (settingRepresentation.getBounds() == null) {
285 continue;
286 }
287 settingRepresentation.setID(frames.getCurrentFrame().getNextItemID());
288 frames.addItem(settingRepresentation, false);
289 x = settingRepresentation.getX() + settingRepresentation.getBoundsWidth();
290 y = settingRepresentation.getY();
291 }
292
293 x = Math.max(250, x + 20);
294 // Add tooltip for setting
295 Text tooltip = frames.getCurrentFrame().addText(x, y, "// " + setting.getTooltip(), null);
296 tooltip.rebuild(true);
297 if (tooltip.getY() + tooltip.getBoundsHeight() > frames.getLastY()) {
298 frames.setLastY(tooltip.getY() + tooltip.getBoundsHeight());
299 }
300 }
301
302 frames.save();
303 }
304}
Note: See TracBrowser for help on using the repository browser.