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

Last change on this file since 641 was 641, checked in by jts21, 11 years ago

Generated settings frames now use capitalised setting names, and settings are generated/displayed in the order they were declared in code.
Settings with no value no longer have a ':' after their name (good for some things, however maybe we should be showing somehow that some settings can have a value set after a colon, and others use a frame linked from the setting item, and others just use the properties of the setting item?).
Password setting(s) now use the password widget.
Fixed some problems with settings that try to work without having a value set (SpellChecker, ColorWheels, HomeFrame).

File size: 9.0 KB
Line 
1package org.expeditee.settings;
2
3import java.lang.reflect.Field;
4import java.lang.reflect.Method;
5import java.lang.reflect.Modifier;
6import java.util.HashMap;
7import java.util.LinkedList;
8import java.util.List;
9
10import org.expeditee.gui.AttributeValuePair;
11import org.expeditee.gui.DisplayIO;
12import org.expeditee.gui.Frame;
13import org.expeditee.gui.FrameIO;
14import org.expeditee.gui.FrameUtils;
15import org.expeditee.items.Text;
16import org.expeditee.items.widgets.Password;
17import org.expeditee.reflection.PackageLoader;
18
19public abstract class Settings {
20
21 public static final String SETTINGS_PACKAGE_PARENT = "org.expeditee.";
22 public static final String SETTINGS_PACKAGE = SETTINGS_PACKAGE_PARENT + "settings.";
23
24 private static final class PageDescriptor {
25
26 private static final class FieldSet {
27
28 private final Field field;
29 private final Method method;
30
31 private FieldSet(Field field, Method method) {
32 this.field = field;
33 this.method = method;
34 }
35 }
36
37 private final HashMap<String, FieldSet> settings = new HashMap<String, FieldSet>();
38 private final List<Field> hasDefault = new LinkedList<Field>();
39 private final List<String> orderedEntries = new LinkedList<String>();
40 private final Method onParsed;
41
42 private PageDescriptor(Class<?> clazz) {
43
44 // populate map of settings with methods
45 for(Method m : clazz.getMethods()) {
46 // method name must start with "set", and method must take 1 Text item as parameter
47 if(m.getName().toLowerCase().startsWith("set") && m.getParameterTypes().length == 1 && m.getParameterTypes()[0] == Text.class) {
48 // System.out.println(m.getName().toLowerCase());
49 settings.put(m.getName().substring(3).toLowerCase(), new FieldSet(null, m));
50 if(!orderedEntries.contains(m.getName().substring(3))) {
51 orderedEntries.add(m.getName().substring(3));
52 }
53 }
54 }
55 // populate map of settings with fields
56 for(Field f : clazz.getFields()) {
57 Class<?> type = f.getType();
58 // only allow valid types
59 if(type != String.class &&
60 type != Boolean.class && type != boolean.class &&
61 type != Integer.class && type != int.class &&
62 type != Double.class && type != double.class &&
63 type != Float.class && type != float.class) {
64 continue;
65 }
66 FieldSet fs = settings.get(f.getName().toLowerCase());
67 if(fs == null) {
68 settings.put(f.getName().toLowerCase(), new FieldSet(f, null));
69 } else {
70 settings.put(f.getName().toLowerCase(), new FieldSet(f, fs.method));
71 }
72 if(!orderedEntries.contains(f.getName())) {
73 orderedEntries.add(f.getName());
74 }
75 }
76 // check which fields have default values
77 for(Field f : clazz.getFields()) {
78 if(!Modifier.isFinal(f.getModifiers())) {
79 if(this.settings.get("default" + f.getName().toLowerCase()) != null) {
80 this.hasDefault.add(f);
81 }
82 }
83 }
84 Method m = null;
85 try {
86 m = clazz.getMethod("onParsed", Text.class);
87 } catch(Exception e) {
88 // System.err.println(clazz.getName() + " has no onParsed(Text t) callback");
89 }
90 this.onParsed = m;
91 }
92 }
93 private static HashMap<String, PageDescriptor> _pages = new HashMap<String, PageDescriptor>();
94
95 public static void Init() {
96 try {
97 for(Class<?> clazz : PackageLoader.getClassesNew(SETTINGS_PACKAGE)) {
98 // Ignore this class since it's the controller
99 if(clazz.equals(Settings.class)) {
100 continue;
101 }
102 String settingsPage = clazz.getPackage().getName().toLowerCase().substring(SETTINGS_PACKAGE_PARENT.length());
103 // System.out.println(settingsPage + " : " + clazz.getName());
104 _pages.put(settingsPage, new PageDescriptor(clazz));
105 }
106
107 } catch (Exception e) {
108 e.printStackTrace();
109 }
110 FrameUtils.ParseProfile(FrameIO.LoadProfile(UserSettings.ProfileName));
111 }
112
113 public static void parseSettings(Text text) {
114 parseSettings(text, "");
115 }
116
117 /**
118 * Sets all the simple settings.
119 *
120 * @param text
121 * @param prefix
122 */
123 private static void parseSettings(Text text, String prefix) {
124
125 Frame child = text.getChild();
126 if(child == null) {
127 return;
128 }
129 String settingsPage = prefix + text.getText().trim().toLowerCase().replaceAll("^@", "");
130 PageDescriptor pd = _pages.get(settingsPage);
131 if(pd == null) {
132 return;
133 }
134 try {
135 if (text.getChild() == null) {
136 return;
137 }
138 List<Field> toDefault = new LinkedList<Field>(pd.hasDefault);
139 // set the fields
140 for (Text t : text.getChild().getBodyTextItems(true)) {
141 AttributeValuePair avp = new AttributeValuePair(t.getText(), false);
142 try {
143 // System.out.println(avp.getAttributeOrValue().trim().toLowerCase().replaceAll("^@", ""));
144 PageDescriptor.FieldSet fs = pd.settings.get(avp.getAttributeOrValue().trim().toLowerCase().replaceAll("^@", ""));
145 if(fs == null) {
146 continue;
147 }
148 Field f = fs.field;
149 Method m = fs.method;
150 if(m != null) {
151 m.invoke(null, t);
152 // System.out.println("Set " + avp.getAttributeOrValue() + " by method");
153 // we're setting this field, so remove it from the list of fields to default
154 toDefault.remove(f);
155 } else {
156 if (f != null) {
157 // if the value is empty, set it to the default
158 if(avp.getValue() == null || avp.getValue().trim().length() == 0) {
159 continue;
160 }
161 Class<?> type = f.getType();
162 if(type == String.class) {
163 f.set(null, avp.getValue());
164 } else if(type == Boolean.class || type == boolean.class) {
165 f.set(null, avp.getBooleanValue());
166 } else if(type == Integer.class || type == int.class) {
167 f.set(null, avp.getIntegerValue());
168 } else if(type == Double.class || type == double.class) {
169 f.set(null, avp.getDoubleValue());
170 } else if(type == Float.class || type == float.class) {
171 f.set(null, avp.getDoubleValue().floatValue());
172 } else {
173 System.err.println("Failed to set " + f.getName() + " of " + type);
174 continue;
175 }
176 // we're setting this field, so remove it from the list of fields to default
177 toDefault.remove(f);
178 // System.out.println("Set " + f.getName() + " to " + f.get(null));
179 }
180 }
181 } catch (Exception e) {
182 e.printStackTrace();
183 }
184 }
185 // set any unset fields to their default
186 for(Field f : toDefault) {
187 try {
188 f.set(null, pd.settings.get("default" + f.getName().toLowerCase()).field.get(null));
189 // System.out.println("Set " + f.getName() + " to default value " + f.get(null));
190 } catch (Exception e) {
191 e.printStackTrace();
192 }
193 }
194 // call the onParsed method if one exists
195 if(pd.onParsed != null) {
196 pd.onParsed.invoke(null, text);
197 }
198 } catch (Exception e) {
199 e.printStackTrace();
200 return;
201 }
202 // if the page was a settings page, check if it has any subpages
203 for(Text t : child.getTextItems()) {
204 parseSettings(t, settingsPage + ".");
205 }
206 }
207
208 public static Text generateSettingsTree() {
209 return generateSettingsTree("settings", DisplayIO.getCurrentFrame().createNewText("Settings"));
210 }
211
212 private static Text generateSettingsTree(String page, Text text) {
213 Frame frame = FrameIO.CreateNewFrame(text);
214 text.setLink(frame.getName());
215
216 int x = 50, y = 100;
217 int dY = UserSettings.ItemTemplate.getPolygon().getBounds().height + 1;
218 int maxY = UserSettings.InitialHeight - 150;
219
220 // add subpages of the current page
221 for(String k : _pages.keySet()) {
222 if(k.startsWith(page.toLowerCase()) && !k.equals(page)) {
223 String name = k.substring(page.length() + 1);
224 if(name.indexOf('.') != -1) {
225 continue;
226 }
227 System.out.println("Generating " + name);
228 generateSettingsTree(k, frame.addText(x, y, name.substring(0, 1).toUpperCase() + name.substring(1), null));
229 y += dY;
230 if(y >= maxY) {
231 x += 300;
232 y = 100;
233 }
234 }
235 }
236
237 x += 200;
238 y = 100;
239
240 // add settings of the current page
241 PageDescriptor pd = _pages.get(page);
242 if(pd != null) {
243 for(String str : pd.orderedEntries) {
244 String key = str.toLowerCase();
245 if(key.startsWith("default")) {
246 continue;
247 }
248 PageDescriptor.FieldSet fs = pd.settings.get(key);
249 String name = null;
250 Object value = "";
251 name = str.substring(0, 1).toUpperCase() + str.substring(1);
252 if(fs.method == null && fs.field != null) {
253 try {
254 if(pd.hasDefault.contains(fs.field)) {
255 value = ": " + pd.settings.get("default" + key).field.get(null);
256 } else {
257 value = ": " + fs.field.get(null);
258 }
259 } catch (Exception e) {
260 e.printStackTrace();
261 }
262 } else if(fs.method == null) {
263 continue;
264 }
265 if(key.equals("pass")) {
266 Password pw = new Password(frame.createNewText("@iw: org.expeditee.items.widgets.Password"), null);
267 pw.setPassword((String) value);
268 pw.setPosition(x, y);
269 frame.addAllItems(pw.getItems());
270 y += pw.getHeight();
271 } else {
272 frame.addText(x, y, name + value, null);
273 }
274 y += dY;
275 if(y >= maxY) {
276 x += 300;
277 y = 100;
278 }
279 }
280 }
281
282 FrameIO.SaveFrame(frame);
283 return text;
284 }
285}
Note: See TracBrowser for help on using the repository browser.