Commit | Line | Data |
---|---|---|
9e834013 NR |
1 | package be.nikiroo.utils.resources; |
2 | ||
3 | import java.util.ArrayList; | |
4 | import java.util.List; | |
8517b60c NR |
5 | import java.util.Map; |
6 | import java.util.Set; | |
7 | import java.util.TreeMap; | |
9e834013 NR |
8 | |
9 | import be.nikiroo.utils.resources.Meta.Format; | |
10 | ||
11 | /** | |
12 | * A graphical item that reflect a configuration option from the given | |
13 | * {@link Bundle}. | |
14 | * | |
15 | * @author niki | |
16 | * | |
17 | * @param <E> | |
18 | * the type of {@link Bundle} to edit | |
19 | */ | |
20 | public class MetaInfo<E extends Enum<E>> { | |
21 | private final Bundle<E> bundle; | |
22 | private final E id; | |
23 | ||
24 | private Meta meta; | |
25 | ||
26 | private String value; | |
8517b60c NR |
27 | private List<Runnable> reloadedListeners = new ArrayList<Runnable>(); |
28 | private List<Runnable> saveListeners = new ArrayList<Runnable>(); | |
9e834013 NR |
29 | |
30 | private String name; | |
31 | private String description; | |
32 | ||
33 | public MetaInfo(Class<E> type, Bundle<E> bundle, E id) { | |
34 | this.bundle = bundle; | |
35 | this.id = id; | |
36 | ||
37 | try { | |
38 | this.meta = type.getDeclaredField(id.name()).getAnnotation( | |
39 | Meta.class); | |
40 | } catch (NoSuchFieldException e) { | |
41 | } catch (SecurityException e) { | |
42 | } | |
43 | ||
44 | // We consider that if a description bundle is used, everything is in it | |
45 | ||
46 | String description = null; | |
47 | if (bundle.getDescriptionBundle() != null) { | |
48 | description = bundle.getDescriptionBundle().getString(id); | |
49 | if (description != null && description.trim().isEmpty()) { | |
50 | description = null; | |
51 | } | |
52 | } | |
53 | ||
54 | if (description == null) { | |
55 | description = meta.description(); | |
56 | if (meta.info() != null && !meta.info().isEmpty()) { | |
8517b60c | 57 | description += " (" + meta.info() + ")"; |
9e834013 NR |
58 | } |
59 | } | |
60 | ||
61 | String name = id.toString(); | |
62 | if (name.length() > 1) { | |
63 | name = name.substring(0, 1) + name.substring(1).toLowerCase(); | |
64 | name = name.replace("_", " "); | |
65 | } | |
66 | ||
67 | this.name = name; | |
68 | this.description = description; | |
69 | ||
70 | reload(); | |
71 | } | |
72 | ||
73 | /** | |
74 | * THe name of this item, deduced from its ID. | |
75 | * <p> | |
76 | * In other words, it is the ID but presented in a displayable form. | |
77 | * | |
78 | * @return the name | |
79 | */ | |
80 | public String getName() { | |
81 | return name; | |
82 | } | |
83 | ||
84 | /** | |
85 | * The description of this item (information to present to the user). | |
86 | * | |
87 | * @return the description | |
88 | */ | |
89 | public String getDescription() { | |
90 | return description; | |
91 | } | |
92 | ||
93 | public Format getFormat() { | |
94 | return meta.format(); | |
95 | } | |
96 | ||
97 | /** | |
98 | * The value stored by this item, as a {@link String}. | |
99 | * | |
100 | * @return the value | |
101 | */ | |
102 | public String getString() { | |
103 | return value; | |
104 | } | |
105 | ||
106 | public String getDefaultString() { | |
107 | return meta.def(); | |
108 | } | |
109 | ||
110 | public Boolean getBoolean() { | |
111 | return BundleHelper.parseBoolean(getString()); | |
112 | } | |
113 | ||
114 | public Boolean getDefaultBoolean() { | |
115 | return BundleHelper.parseBoolean(getDefaultString()); | |
116 | } | |
117 | ||
118 | public Character getCharacter() { | |
119 | return BundleHelper.parseCharacter(getString()); | |
120 | } | |
121 | ||
122 | public Character getDefaultCharacter() { | |
123 | return BundleHelper.parseCharacter(getDefaultString()); | |
124 | } | |
125 | ||
126 | public Integer getInteger() { | |
127 | return BundleHelper.parseInteger(getString()); | |
128 | } | |
129 | ||
130 | public Integer getDefaultInteger() { | |
131 | return BundleHelper.parseInteger(getDefaultString()); | |
132 | } | |
133 | ||
134 | public Integer getColor() { | |
135 | return BundleHelper.parseColor(getString()); | |
136 | } | |
137 | ||
138 | public Integer getDefaultColor() { | |
139 | return BundleHelper.parseColor(getDefaultString()); | |
140 | } | |
141 | ||
142 | public List<String> getList() { | |
143 | return BundleHelper.parseList(getString()); | |
144 | } | |
145 | ||
146 | public List<String> getDefaultList() { | |
147 | return BundleHelper.parseList(getDefaultString()); | |
148 | } | |
149 | ||
150 | /** | |
151 | * The value stored by this item, as a {@link String}. | |
152 | * | |
153 | * @param value | |
154 | * the new value | |
155 | */ | |
156 | public void setString(String value) { | |
157 | this.value = value; | |
158 | } | |
159 | ||
160 | public void setBoolean(boolean value) { | |
161 | setString(BundleHelper.fromBoolean(value)); | |
162 | } | |
163 | ||
164 | public void setCharacter(char value) { | |
165 | setString(BundleHelper.fromCharacter(value)); | |
166 | } | |
167 | ||
168 | public void setInteger(int value) { | |
169 | setString(BundleHelper.fromInteger(value)); | |
170 | } | |
171 | ||
172 | public void setColor(int value) { | |
173 | setString(BundleHelper.fromColor(value)); | |
174 | } | |
175 | ||
176 | public void setList(List<String> value) { | |
177 | setString(BundleHelper.fromList(value)); | |
178 | } | |
179 | ||
180 | /** | |
181 | * Reload the value from the {@link Bundle}. | |
182 | */ | |
183 | public void reload() { | |
184 | value = bundle.getString(id); | |
8517b60c | 185 | for (Runnable listener : reloadedListeners) { |
9e834013 NR |
186 | try { |
187 | listener.run(); | |
188 | } catch (Exception e) { | |
189 | // TODO: error management? | |
190 | e.printStackTrace(); | |
191 | } | |
192 | } | |
193 | } | |
194 | ||
8517b60c NR |
195 | // listeners will be called AFTER reload |
196 | public void addReloadedListener(Runnable listener) { | |
197 | reloadedListeners.add(listener); | |
9e834013 NR |
198 | } |
199 | ||
200 | /** | |
201 | * Save the current value to the {@link Bundle}. | |
202 | */ | |
203 | public void save() { | |
8517b60c NR |
204 | for (Runnable listener : saveListeners) { |
205 | try { | |
206 | listener.run(); | |
207 | } catch (Exception e) { | |
208 | // TODO: error management? | |
209 | e.printStackTrace(); | |
210 | } | |
211 | } | |
9e834013 NR |
212 | bundle.setString(id, value); |
213 | } | |
214 | ||
8517b60c NR |
215 | // listeners will be called BEFORE save |
216 | public void addSaveListener(Runnable listener) { | |
217 | saveListeners.add(listener); | |
218 | } | |
219 | ||
9e834013 NR |
220 | /** |
221 | * Create a list of {@link MetaInfo}, one for each of the item in the given | |
222 | * {@link Bundle}. | |
223 | * | |
224 | * @param <E> | |
225 | * the type of {@link Bundle} to edit | |
226 | * @param type | |
227 | * a class instance of the item type to work on | |
228 | * @param bundle | |
229 | * the {@link Bundle} to sort through | |
230 | * | |
231 | * @return the list | |
232 | */ | |
233 | static public <E extends Enum<E>> List<MetaInfo<E>> getItems(Class<E> type, | |
234 | Bundle<E> bundle) { | |
235 | List<MetaInfo<E>> list = new ArrayList<MetaInfo<E>>(); | |
236 | for (E id : type.getEnumConstants()) { | |
237 | list.add(new MetaInfo<E>(type, bundle, id)); | |
238 | } | |
239 | ||
240 | return list; | |
241 | } | |
242 | ||
8517b60c NR |
243 | // TODO: multiple levels? |
244 | static public <E extends Enum<E>> Map<MetaInfo<E>, List<MetaInfo<E>>> getGroupedItems( | |
245 | Class<E> type, Bundle<E> bundle) { | |
246 | Map<MetaInfo<E>, List<MetaInfo<E>>> map = new TreeMap<MetaInfo<E>, List<MetaInfo<E>>>(); | |
247 | Map<MetaInfo<E>, List<MetaInfo<E>>> map1 = new TreeMap<MetaInfo<E>, List<MetaInfo<E>>>(); | |
248 | ||
249 | List<MetaInfo<E>> ungrouped = new ArrayList<MetaInfo<E>>(); | |
250 | for (MetaInfo<E> info : getItems(type, bundle)) { | |
251 | if (info.meta.group()) { | |
252 | List<MetaInfo<E>> list = new ArrayList<MetaInfo<E>>(); | |
253 | map.put(info, list); | |
254 | map1.put(info, list); | |
255 | } else { | |
256 | ungrouped.add(info); | |
257 | } | |
258 | } | |
259 | ||
260 | for (int i = 0; i < ungrouped.size(); i++) { | |
261 | MetaInfo<E> info = ungrouped.get(i); | |
262 | MetaInfo<E> group = findParent(info, map.keySet()); | |
263 | if (group != null) { | |
264 | map.get(group).add(info); | |
265 | ungrouped.remove(i--); | |
266 | } | |
267 | } | |
268 | ||
269 | if (ungrouped.size() > 0) { | |
270 | map.put(null, ungrouped); | |
271 | } | |
272 | ||
273 | return map; | |
274 | } | |
275 | ||
276 | static private <E extends Enum<E>> MetaInfo<E> findParent(MetaInfo<E> info, | |
277 | Set<MetaInfo<E>> candidates) { | |
278 | MetaInfo<E> group = null; | |
279 | for (MetaInfo<E> pcandidate : candidates) { | |
280 | if (info.id.toString().startsWith(pcandidate.id.toString())) { | |
281 | if (group == null | |
282 | || group.id.toString().length() < pcandidate.id | |
283 | .toString().length()) { | |
284 | group = pcandidate; | |
285 | } | |
286 | } | |
287 | } | |
288 | ||
289 | return group; | |
290 | } | |
9e834013 | 291 | } |