source: trunk/src/org/expeditee/io/KMSReader.java@ 1049

Last change on this file since 1049 was 1049, checked in by davidb, 8 years ago

New code, but commented out. If added in, allows for KMS saved frame to specify the 'dot-type'. This doesn't appear to be in the original file format, but gets added in Expeditee if this older format is edited through Browser.java.

File size: 16.9 KB
Line 
1/**
2 * KMSReader.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.io;
20
21import java.io.BufferedReader;
22import java.io.FileReader;
23import java.io.IOException;
24import java.lang.reflect.Constructor;
25import java.lang.reflect.InvocationTargetException;
26import java.lang.reflect.Method;
27import java.util.HashMap;
28import java.util.Iterator;
29import java.util.LinkedHashMap;
30
31import org.expeditee.gui.Frame;
32import org.expeditee.gui.MessageBay;
33import org.expeditee.items.Constraint;
34import org.expeditee.items.Dot;
35import org.expeditee.items.DotType;
36import org.expeditee.items.Item;
37import org.expeditee.items.Line;
38import org.expeditee.items.Text;
39import org.expeditee.stats.SessionStats;
40
41/**
42 * Reads in KMS format files and constructs the Frame and Item objects they
43 * contain.
44 *
45 * @author jdm18
46 *
47 */
48public class KMSReader extends DefaultFrameReader {
49
50 private BufferedReader _reader = null;
51
52 private static LinkedHashMap<String, Method> _ItemTags = null;
53
54 private static LinkedHashMap<String, Method> _FrameTags = null;
55
56 /**
57 * Does nothing, location must be set before use
58 */
59 public KMSReader() {
60 if (_ItemTags != null && _FrameTags != null)
61 return;
62
63 _ItemTags = new LinkedHashMap<String, Method>();
64 _FrameTags = new LinkedHashMap<String, Method>();
65
66 try {
67 _FrameTags.put("A", Frame.class.getMethod("setName", pString));
68 _FrameTags.put("V", Frame.class.getMethod("setVersion", pInt));
69 _FrameTags
70 .put("p", Frame.class.getMethod("setPermission", pPermission));
71 _FrameTags.put("U", Frame.class.getMethod("setOwner", pString));
72 _FrameTags.put("D", Frame.class
73 .getMethod("setDateCreated", pString));
74 _FrameTags.put("M", Frame.class.getMethod("setLastModifyUser",
75 pString));
76 _FrameTags.put("d", Frame.class.getMethod("setLastModifyDate",
77 pString));
78 _FrameTags
79 .put("F", Frame.class.getMethod("setFrozenDate", pString));
80
81 _FrameTags.put("O", Frame.class.getMethod("setForegroundColor",
82 pColor));
83 _FrameTags.put("B", Frame.class.getMethod("setBackgroundColor",
84 pColor));
85
86 _ItemTags.put("S", Item.class.getMethod("setID", pInt));
87 _ItemTags.put("s", Item.class.getMethod("setDateCreated", pString));
88 _ItemTags.put("d", Item.class.getMethod("setColor", pColor));
89 _ItemTags.put("G", Item.class.getMethod("setBackgroundColor",
90 pColor));
91 _ItemTags.put("P", Item.class.getMethod("setPosition", pPoint));
92 _ItemTags.put("F", Item.class.getMethod("setLink", pString));
93 _ItemTags.put("J", Item.class.getMethod("setFormula", pString));
94
95 _ItemTags.put("X", Item.class.getMethod("setActions", pList));
96 _ItemTags.put("x", Item.class.getMethod("setActionMark", pBool));
97 _ItemTags.put("U", Item.class.getMethod("setActionCursorEnter",
98 pList));
99 _ItemTags.put("V", Item.class.getMethod("setActionCursorLeave",
100 pList));
101 _ItemTags.put("W", Item.class.getMethod("setActionEnterFrame",
102 pList));
103 _ItemTags.put("Y", Item.class.getMethod("setActionLeaveFrame",
104 pList));
105 _ItemTags.put("D", Item.class.getMethod("setData", pList));
106 _ItemTags.put("u", Item.class.getMethod("setHighlight", pBool));
107 _ItemTags.put("e", Item.class.getMethod("setFillColor", pColor));
108 _ItemTags.put("E", Item.class.getMethod("setGradientColor", pColor));
109 _ItemTags.put("Q", Item.class.getMethod("setGradientAngle", pInt));
110
111 _ItemTags.put("i", Item.class.getMethod("setFillPattern", pString));
112 _ItemTags.put("o", Item.class.getMethod("setOwner", pString));
113 _ItemTags.put("n", Item.class.getMethod("setLinkMark", pBool));
114 _ItemTags
115 .put("q", Item.class.getMethod("setLinkFrameset", pString));
116 _ItemTags
117 .put("y", Item.class.getMethod("setLinkTemplate", pString));
118 _ItemTags.put("g", Item.class
119 .getMethod("setLinePattern", pIntArray));
120
121 _ItemTags.put("j", Item.class.getMethod("setArrow", pArrow));
122
123 // **** Mmmm. Not sure how DotType has crept into saved KMS frames.
124 // Is this the right thing to do (taken from DefaultFrameReader)
125 //_ItemTags.put("v", Item.class.getMethod("setDotType", new Class[]{DotType.class}));
126
127 _ItemTags.put("f", Text.class.getMethod("setFont", pFont));
128 _ItemTags.put("t", Text.class.getMethod("setSpacing", pFloat));
129 _ItemTags.put("T", Text.class.getMethod("appendText", pString));
130
131 _ItemTags.put("a", Text.class.getMethod("setWordSpacing", pInt));
132 _ItemTags.put("b", Text.class.getMethod("setLetterSpacing", pFloat));
133 _ItemTags.put("m", Text.class.getMethod("setInitialSpacing", pFloat));
134 _ItemTags.put("w", Text.class.getMethod("setWidth", pIntO));
135 _ItemTags.put("k", Text.class.getMethod("setJustification", pJustification));
136
137 _ItemTags.put("h", Item.class.getMethod("setThickness", pFloat));
138 _ItemTags.put("l", Item.class.getMethod("setLineIDs", pString));
139 _ItemTags.put("c", Item.class
140 .getMethod("setConstraintIDs", pString));
141
142 // Lines and constraints are created differently
143 _ItemTags.put("L", Line.class.getMethod("setStartItem", pItem));
144 // _ItemTags.put("g", null);
145
146 _ItemTags.put("C", Constraint.class.getMethod("getID",
147 (Class[]) null));
148 // _ItemTags.put("s2", null);
149 } catch (SecurityException e) {
150 // TODO Auto-generated catch block
151 e.printStackTrace();
152 } catch (NoSuchMethodException e) {
153 // TODO Auto-generated catch block
154 e.printStackTrace();
155 }
156 }
157
158 /**
159 * Determines whether a string begins with a KMS tag.
160 *
161 * @param s
162 * a line of text
163 * @return true if s begins with a KMS tag
164 */
165 private static boolean isValidLine(String s) {
166 return s.length() >= 3 && s.charAt(0) == '+' && s.charAt(2) == '+'
167 && Character.isLetter(s.charAt(1));
168 }
169
170 /**
171 * Reads a KMS file with the given name from disk.
172 *
173 * @param frameName
174 * the name of the Frame to read in from a file.
175 * @return A new Frame object that contains any Items described in the file.
176 * @throws IOException
177 * Any exceptions occured by the BufferedReader.
178 */
179 public Frame readFrame(BufferedReader reader) throws IOException {
180 _reader = reader;
181 Frame newFrame = null;
182 String next = "";
183 boolean header = true;
184 // clear hashmap and line list
185 _data.clear();
186 _linePoints.clear();
187 // First read the header
188 try {
189 while (_reader.ready()) {
190 next = _reader.readLine();
191 if (isValidLine(next)) {
192 if (header) {
193 // Create the frame when the first +S+ is reached
194 // And set the flag to indicate the end of the header
195 if (getTag(next).equals("S")) {
196 newFrame = readFrameClass();
197 header = false;
198 _data.clear();
199 processBodyLine(newFrame, next);
200 } else
201 processHeaderLine(next);
202 } else
203 processBodyLine(newFrame, next);
204 } else if (next.startsWith(SessionStats.ACTIVE_TIME_ATTRIBUTE)) {
205 try {
206 String value = next.substring(SessionStats.ACTIVE_TIME_ATTRIBUTE.length()).trim();
207 newFrame.setActiveTime(value);
208 } catch (Exception e) {
209 }
210
211 } else if (next.startsWith(SessionStats.DARK_TIME_ATTRIBUTE)) {
212 try {
213 String value = next.substring(SessionStats.DARK_TIME_ATTRIBUTE.length()).trim();
214 newFrame.setDarkTime(value);
215 } catch (Exception e) {
216 }
217
218 }
219 }
220 } catch (Exception e) {
221 System.out.println("Error reading bodyLine: " + next + " "
222 + e.getMessage());
223 e.printStackTrace();
224 }
225
226 // if the frame contains no items (Default.0 does this)
227 if (newFrame == null)
228 newFrame = readFrameClass();
229
230 _reader.close();
231 if (newFrame != null) {
232 //newFrame.refreshItemPermissions();
233 newFrame.setChanged(false);
234 }
235 return newFrame;
236 }
237
238 // stores the data of the Item to be created next
239 private LinkedHashMap<String, String> _data = new LinkedHashMap<String, String>(
240 20);
241
242 // creates an item from the last batch of data read from the file
243 private Item createItem() {
244 // creates an item based on the information in the hashmap
245 try {
246 return readItemClass();
247 } catch (IOException e) {
248 // TODO Auto-generated catch block
249 e.printStackTrace();
250 }
251
252 return null;
253 }
254
255 // Stores points used when constructing lines
256 private HashMap<Integer, Item> _linePoints = new HashMap<Integer, Item>();
257
258 /**
259 * Adds any lines stored in _lineStarts and _lineEnds to the given Frame.
260 *
261 * @param frame
262 * The Frame to add the newly created Line objects to.
263 */
264 private Line createLine() {
265 String s = _data.get("L");
266 _data.remove("L");
267
268 // get the line ID and type
269 java.awt.Point idtype = separateValues(s);
270
271 // get the end points
272 s = _data.get("s");
273 _data.remove("s");
274
275 java.awt.Point startend = separateValues(s);
276
277 int start = startend.x;
278 int end = startend.y;
279
280 if (_linePoints.get(start) != null && _linePoints.get(end) != null) {
281 Line line = new Line(_linePoints.get(start), _linePoints.get(end),
282 idtype.x);
283 return line;
284 }
285
286 // System.out.println(_linePoints.size());
287 // for (int i : _linePoints.keySet())
288 // System.out.println(i + " - "
289 // + _linePoints.get(i).getClass().getSimpleName());
290 //
291 // System.out.println("Error: Line " + idtype.x
292 // + " has missing end point(s) + (Looking for: " + start + " , "
293 // + end + ")");
294 return null;
295 }
296
297 /*
298 * Creates a constraint from the data containted in _data
299 */
300 private void createConstraint() {
301 java.awt.Point idtype = separateValues(_data.get("C"));
302 java.awt.Point startend = separateValues(_data.get("s"));
303
304 Item a = _linePoints.get(startend.x);
305 Item b = _linePoints.get(startend.y);
306
307 new Constraint(a, b, idtype.x, idtype.y);
308 }
309
310 /**
311 * Processes the body section of the KMS file, which contains all Items
312 *
313 * @param frame
314 * The Frame to add any created Items to.
315 * @param line
316 * The line of text read in from the file to process.
317 */
318 private void processBodyLine(Frame frame, String line) {
319 // separate the tag from the value
320 String tag = getTag(line);
321 line = getValue(line);
322
323 // if this is the start of a new item, a line, or a constraint
324 // then add the last item to the frame
325 if (tag.charAt(0) == 'S' || tag.charAt(0) == 'L'
326 || tag.charAt(0) == 'C') {
327 frame.addItem(createItem());
328
329 _data.clear();
330 _data.put(tag, line);
331 return;
332 }
333
334 // if this is the end of the file, then add the last item to the frame
335 if (tag.charAt(0) == 'Z') {
336 frame.addItem(createItem());
337 _data.clear();
338
339 return;
340 }
341
342 // check for duplicate tags (multiple lines of text)
343 String newtag = tag;
344 int i = 0;
345
346 // only executes if there are duplicate tags for this Item
347 while (_data.containsKey(newtag)) {
348 newtag = tag + i;
349 i++;
350 }
351
352 // All values are stored in a HashMap until the end of the Item is
353 // found.
354 _data.put(newtag, line);
355 }
356
357 private static String getTag(String line) {
358 assert (line.charAt(0) == '+');
359 assert (line.length() > 2);
360 return line.substring(1, 2);
361 }
362
363 private static String getValue(String line) {
364 assert (line.charAt(0) == '+');
365 if (line.length() > 4)
366 return line.substring(4);
367 else
368 return "";
369 }
370
371 /**
372 * Reads the header section of the file, which contains information about
373 * the Frame.
374 *
375 * @param frame
376 * The Frame to assign the read values to.
377 * @param line
378 * The line from the file to process.
379 * @return False if the end of the header has been reached, True otherwise.
380 */
381 private void processHeaderLine(String line) throws IOException {
382 // first separate the tag from the text
383 String tag = getTag(line);
384 String value = getValue(line);
385
386 if (tag.equals("Z"))
387 return;
388
389 if (_FrameTags.get(tag) == null) {
390 if (!tag.equals("t") && !tag.equals("v"))
391 MessageBay.errorMessage("Tag '" + tag + "' in '" + line
392 + "' is not supported.");
393 return;
394 }
395
396 _data.put(tag, value);
397 }
398
399 // returns two ints separated by a space from the given String
400 private java.awt.Point separateValues(String line) {
401 int x = Integer.parseInt(line.substring(0, line.indexOf(" ")));
402 int y = Integer.parseInt(line.substring(line.indexOf(" ") + 1));
403
404 return new java.awt.Point(x, y);
405 }
406
407 private Frame readFrameClass() throws IOException {
408 if (_data.size() == 0) {
409 MessageBay
410 .errorMessage("IO Error: File contains no valid KMS lines.");
411 return null;
412 }
413
414 Frame toMake = new Frame();
415 Iterator<String> it = _data.keySet().iterator();
416
417 while (it.hasNext()) {
418 String datatag = it.next();
419
420 Method toRun = _FrameTags.get(datatag);
421 Object[] vals = Conversion.Convert(toRun, _data.get(datatag));
422 try {
423 toRun.invoke(toMake, vals);
424 } catch (IllegalArgumentException e) {
425 // TODO Auto-generated catch block
426 e.printStackTrace();
427 } catch (IllegalAccessException e) {
428 // TODO Auto-generated catch block
429 e.printStackTrace();
430 } catch (InvocationTargetException e) {
431 // TODO Auto-generated catch block
432 e.printStackTrace();
433 }
434 }
435
436 return toMake;
437 }
438
439 @SuppressWarnings("unchecked")
440 private Item readItemClass() throws IOException {
441 Iterator<String> tags = _data.keySet().iterator();
442 Class toCreate = null;
443
444 // loop through all attributes read in for this item
445 while (tags.hasNext()) {
446 String next = tags.next();
447 Method m = _ItemTags.get(next);
448 if (m != null && _ItemTags.get(next + "2") == null) {
449 if (!m.getDeclaringClass().getSimpleName().equals("Item")) {
450 toCreate = m.getDeclaringClass();
451 break;
452 }
453 }
454 }
455
456 if (toCreate == null) {
457 if (_data.size() > 0)
458 toCreate = Dot.class;
459 else
460 return null;
461 }
462
463 Item toMake = null;
464
465 try {
466 if (toCreate == Line.class)
467 toMake = createLine();
468 else if (toCreate == Constraint.class) {
469 createConstraint();
470 return null;
471 } else if (toCreate == Item.class && _data.size() == 2) {
472 toCreate = Dot.class;
473 } else if (toCreate == Item.class) {
474 for (String s : _data.keySet())
475 System.out.println(s + " -> " + _data.get(s));
476 return null;
477 } else {
478 Object[] params = { -1 };
479 Constructor con = toCreate.getConstructor(int.class);
480 toMake = (Item) con.newInstance(params);
481 }
482 } catch (InstantiationException e) {
483 // TODO Auto-generated catch block
484 e.printStackTrace();
485 } catch (IllegalAccessException e) {
486 // TODO Auto-generated catch block
487 e.printStackTrace();
488 } catch (IllegalArgumentException e) {
489 // TODO Auto-generated catch block
490 e.printStackTrace();
491 } catch (InvocationTargetException e) {
492 // TODO Auto-generated catch block
493 e.printStackTrace();
494 } catch (SecurityException e) {
495 // TODO Auto-generated catch block
496 e.printStackTrace();
497 } catch (NoSuchMethodException e) {
498 // TODO Auto-generated catch block
499 e.printStackTrace();
500 }
501
502 if (toMake == null)
503 return null;
504
505 Iterator<String> it = _data.keySet().iterator();
506 String last = "";
507
508 int count = 0;
509
510 while (it.hasNext()) {
511 String tag = it.next();
512 if (_data.containsKey("" + tag.charAt(0) + count)) {
513 if (last.length() == 0)
514 last = _data.get(tag);
515 else
516 last += "\n" + _data.get(tag);
517
518 count++;
519 } else {
520 Method toRun = _ItemTags.get("" + tag.charAt(0));
521 if (toRun == null){
522 System.out.println("Error accessing tag method: "
523 + tag.charAt(0));
524
525 }
526 Object[] vals;
527 if (last.length() > 0)
528 vals = Conversion.Convert(toRun, last + "\n"
529 + _data.get(tag));
530 else
531 vals = Conversion.Convert(toRun, _data.get(tag));
532
533 try {
534 if (vals != null) {
535 toRun.invoke(toMake, vals);
536 }
537 } catch (IllegalArgumentException e) {
538 // TODO Auto-generated catch block
539 e.printStackTrace();
540 } catch (IllegalAccessException e) {
541 // TODO Auto-generated catch block
542 e.printStackTrace();
543 } catch (InvocationTargetException e) {
544 // TODO Auto-generated catch block
545 e.printStackTrace();
546 } catch (ClassCastException e) {
547 System.out.println(toRun.getName());
548 e.printStackTrace();
549 }
550
551 count = 0;
552 last = "";
553 }
554
555 }
556
557 if (!(toMake instanceof Line))
558 _linePoints.put(toMake.getID(), toMake);
559
560 return toMake;
561 }
562
563 public static int getVersion(String fullpath) {
564 try {
565 BufferedReader reader = new BufferedReader(new FileReader(fullpath));
566 String next = "";
567 // First read the header lines until we get the version number
568 while (reader.ready() && (next = reader.readLine()) != null) {
569 if (isValidLine(next)) {
570 char tag = getTag(next).charAt(0);
571 String value = getValue(next);
572 if (tag == 'V')
573 return Integer.parseInt(value);
574 else if (tag == 'Z')
575 return 0;
576 }
577 }
578 } catch (Exception e) {
579 }
580 return -1;
581 }
582}
Note: See TracBrowser for help on using the repository browser.