001: /*
002: * ToolBarProperties.java
003: *
004: * Copyright (C) 2002, 2003, 2004, 2005, 2006 Takis Diakoumis
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License
008: * as published by the Free Software Foundation; either version 2
009: * of the License, or any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
019: *
020: */
021:
022: package org.underworldlabs.swing.toolbar;
023:
024: import java.io.CharArrayWriter;
025: import java.io.File;
026: import java.io.FileInputStream;
027: import java.io.FileOutputStream;
028: import java.io.IOException;
029: import java.io.InputStream;
030: import java.io.OutputStream;
031:
032: import java.util.Vector;
033:
034: import javax.swing.SwingUtilities;
035: import javax.xml.parsers.SAXParser;
036: import javax.xml.parsers.SAXParserFactory;
037: import javax.xml.transform.Transformer;
038: import javax.xml.transform.TransformerFactory;
039: import javax.xml.transform.sax.SAXSource;
040: import javax.xml.transform.stream.StreamResult;
041:
042: import org.xml.sax.Attributes;
043: import org.xml.sax.ContentHandler;
044: import org.xml.sax.DTDHandler;
045: import org.xml.sax.EntityResolver;
046: import org.xml.sax.ErrorHandler;
047: import org.xml.sax.InputSource;
048: import org.xml.sax.SAXException;
049: import org.xml.sax.SAXParseException;
050: import org.xml.sax.XMLReader;
051: import org.xml.sax.helpers.AttributesImpl;
052: import org.xml.sax.helpers.DefaultHandler;
053:
054: import org.underworldlabs.swing.GUIUtils;
055:
056: /* ----------------------------------------------------------
057: * CVS NOTE: Changes to the CVS repository prior to the
058: * release of version 3.0.0beta1 has meant a
059: * resetting of CVS revision numbers.
060: * ----------------------------------------------------------
061: */
062:
063: /**
064: *
065: * @author Takis Diakoumis
066: * @version $Revision: 1.6 $
067: * @date $Date: 2006/06/28 08:34:57 $
068: */
069: public class ToolBarProperties {
070:
071: /** The user defined tools */
072: private static Vector tools;
073:
074: /** The default tools */
075: private static Vector defaultTools;
076:
077: /** the tools XML conf file path */
078: private static String toolsConfPath;
079:
080: /** the default tools XML conf resource file path */
081: private static String defaultToolsConfPath;
082:
083: // -----------------------------------
084: // --- XML elements and attributes ---
085: // -----------------------------------
086: private static final String EQ_TOOLBARS = "system-toolbars";
087: private static final String TOOLBAR = "toolbar";
088: private static final String ROW = "row";
089: private static final String POSITION = "position";
090: private static final String LOC_X = "loc-x";
091: private static final String RESIZE_OFFSET_X = "resize-offset-x";
092: private static final String MINIMUM_WIDTH = "minimum-width";
093: private static final String PREFERRED_WIDTH = "preferred-width";
094: private static final String CURRENT_WIDTH = "current-width";
095: private static final String BUTTONS = "buttons";
096: private static final String CONSTRAINTS = "constraints";
097: private static final String BUTTON = "button";
098: private static final String NAME = "name";
099: private static final String ACTION_ID = "action-id";
100: private static final String ID = "id";
101: private static final String VISIBLE = "visible";
102: private static final String ORDER = "order";
103: // -----------------------------------
104:
105: private static final String EMPTY = "";
106:
107: /** Whether the tools have been loaded and config files passed. */
108: private static boolean toolsLoaded;
109:
110: public static void init(String _toolsConfPath,
111: String _defaultToolsConfPath) {
112: toolsConfPath = _toolsConfPath;
113: defaultToolsConfPath = _defaultToolsConfPath;
114:
115: // TODO: do we allow null conf files with defaults only???
116:
117: if (toolsConfPath != null) {
118: loadTools();
119: }
120: toolsLoaded = true;
121: }
122:
123: private static void checkInit() {
124: if (toolsConfPath == null) {
125: throw new RuntimeException(
126: "Tool configuration XML file is NULL or failed to load. "
127: + "Ensure the init() method is run prior to retrieving "
128: + "any tool conf information");
129: }
130: }
131:
132: private static void checkDefaultInit() {
133: if (defaultToolsConfPath == null) {
134: throw new RuntimeException(
135: "Default Tool configuration XML file resource is NULL "
136: + "Ensure the init(...) method is called prior to retrieving "
137: + "any tool conf information");
138: }
139: }
140:
141: public static Vector getToolbarButtonsVector() {
142: checkInit();
143: if (tools == null || tools.size() == 0) {
144: loadTools();
145: }
146:
147: return tools;
148: }
149:
150: public static ToolBarWrapper[] getToolbarButtonsArray() {
151: checkInit();
152: if (tools == null || tools.size() == 0) {
153: loadTools();
154: }
155:
156: return (ToolBarWrapper[]) tools
157: .toArray(new ToolBarWrapper[] {});
158: }
159:
160: public static Vector getDefaultToolbarButtonsVector() {
161: checkDefaultInit();
162: if (defaultTools == null || defaultTools.size() == 0) {
163: loadDefaults(false);
164: }
165:
166: return defaultTools;
167: }
168:
169: public static ToolBarWrapper[] getDefaultToolbarButtonsArray() {
170: checkDefaultInit();
171: if (defaultTools == null || defaultTools.size() == 0) {
172: loadDefaults(false);
173: }
174:
175: return (ToolBarWrapper[]) defaultTools
176: .toArray(new ToolBarWrapper[] {});
177: }
178:
179: public static void setToolBarConstraints(String name,
180: ToolBarConstraints tbc) {
181: ToolBarWrapper toolBar = getToolBar(name);
182: toolBar.setConstraints(tbc);
183: }
184:
185: public static void removeToolBar(String name) {
186: tools.remove(getToolBar(name));
187: }
188:
189: public static void resetToolBar(String name, ToolBarWrapper toolBar) {
190: tools.remove(getToolBar(name));
191: tools.add(toolBar);
192: }
193:
194: public static void setToolBarVisible(String name, boolean visible) {
195: ToolBarWrapper toolBar = getToolBar(name);
196: toolBar.setVisible(visible);
197: }
198:
199: public static boolean isToolBarVisible(String name) {
200: ToolBarWrapper toolBar = getToolBar(name);
201: return toolBar.isVisible();
202: }
203:
204: public static ToolBarWrapper getDefaultToolBar(String name) {
205: checkDefaultInit();
206: if (defaultTools == null || defaultTools.isEmpty()) {
207: loadDefaults(false);
208: }
209:
210: ToolBarWrapper toolBar = null;
211: for (int i = 0, k = defaultTools.size(); i < k; i++) {
212: toolBar = (ToolBarWrapper) defaultTools.elementAt(i);
213:
214: if (name.compareTo(toolBar.getName()) == 0) {
215: break;
216: }
217:
218: }
219:
220: return toolBar;
221: }
222:
223: public static int getNextToolbarRow() {
224: int row;
225: int currentMaxRow = -1;
226: ToolBarWrapper[] toolBars = getToolbarButtonsArray();
227:
228: for (int i = 0; i < toolBars.length; i++) {
229: row = toolBars[i].getConstraints().getRow();
230:
231: if (row > currentMaxRow) {
232: currentMaxRow = row;
233: }
234:
235: }
236:
237: return currentMaxRow + 1;
238: }
239:
240: public static ToolBarWrapper getToolBar(String name) {
241: if (tools == null || tools.size() == 0) {
242: loadTools();
243: }
244:
245: ToolBarWrapper toolBar = null;
246: for (int i = 0, k = tools.size(); i < k; i++) {
247: toolBar = (ToolBarWrapper) tools.elementAt(i);
248: if (name.compareTo(toolBar.getName()) == 0) {
249: break;
250: }
251: }
252:
253: return toolBar;
254: }
255:
256: public static int saveTools() {
257: OutputStream os = null;
258: try {
259: TransformerFactory transFactory = TransformerFactory
260: .newInstance();
261: Transformer transformer = transFactory.newTransformer();
262: ToolsParser cp = new ToolsParser();
263:
264: File file = new File(toolsConfPath);
265:
266: os = new FileOutputStream(file);
267: SAXSource source = new SAXSource(cp,
268: new ToolbarButtonsSource());
269: StreamResult r = new StreamResult(os);
270: transformer.transform(source, r);
271: return 1;
272: } catch (Exception e) {
273: e.printStackTrace();
274: return 0;
275: } finally {
276: if (os != null) {
277: try {
278: os.close();
279: } catch (IOException e) {
280: }
281: }
282: }
283: }
284:
285: public static void reloadTools(boolean loadDefaults) {
286: if (loadDefaults) {
287: defaultTools = null;
288: loadDefaults(false);
289: } else {
290: loadTools();
291: }
292: }
293:
294: private static synchronized void loadDefaults(boolean setDefaults) {
295:
296: if (defaultTools != null && defaultTools.size() > 0) {
297: return;
298: }
299:
300: InputStream input = null;
301: ClassLoader cl = ToolBarProperties.class.getClassLoader();
302:
303: if (cl != null) {
304: input = cl.getResourceAsStream(defaultToolsConfPath);
305: } else {
306: input = ClassLoader
307: .getSystemResourceAsStream(defaultToolsConfPath);
308: }
309:
310: try {
311: SAXParserFactory factory = SAXParserFactory.newInstance();
312: factory.setNamespaceAware(true);
313:
314: SAXParser parser = factory.newSAXParser();
315: XMLToolHandler handler = new XMLToolHandler();
316: parser.parse(input, handler);
317: defaultTools = handler.getToolsVector();
318:
319: if (setDefaults) {
320: int size = defaultTools.size();
321: tools = new Vector(size);
322: ToolBarWrapper toolBar = null;
323: for (int i = 0; i < size; i++) {
324: toolBar = (ToolBarWrapper) defaultTools
325: .elementAt(i);
326: tools.add(toolBar.clone());
327: }
328:
329: }
330: } catch (Exception e) {
331: e.printStackTrace();
332: GUIUtils.displayErrorMessage(null,
333: "Error opening default tools definitions.");
334: } finally {
335: if (input != null) {
336: try {
337: input.close();
338: } catch (IOException e) {
339: }
340: }
341: }
342:
343: }
344:
345: // checks for new tools added from the defaults
346: private static void compareTools() {
347:
348: boolean hasButton = false;
349: boolean rebuild = false;
350:
351: ToolBarWrapper[] defaultsArray = getDefaultToolbarButtonsArray();
352: ToolBarWrapper[] toolsArray = getToolbarButtonsArray();
353:
354: ToolBarWrapper currentToolBar = null;
355:
356: for (int i = 0; i < defaultsArray.length; i++) {
357: String name = defaultsArray[i].getName();
358:
359: ToolBarButton[] buttons = defaultsArray[i]
360: .getButtonsArray();
361: if (buttons == null) {
362: continue;
363: }
364:
365: for (int j = 0; j < toolsArray.length; j++) {
366:
367: if (toolsArray[j].getName().compareTo(name) == 0) {
368: currentToolBar = toolsArray[j];
369: break;
370: }
371:
372: }
373:
374: ToolBarButton[] _buttons = currentToolBar.getButtonsArray();
375: if (_buttons == null) {
376: continue;
377: }
378:
379: for (int k = 0; k < buttons.length; k++) {
380: int id = buttons[k].getId();
381:
382: for (int m = 0; m < _buttons.length; m++) {
383: if (_buttons[m].getId() == id) {
384: hasButton = true;
385: break;
386: }
387: hasButton = false;
388: }
389:
390: if (!hasButton) {
391: rebuild = true;
392: ToolBarButton newButton = (ToolBarButton) buttons[k]
393: .clone();
394: newButton.setVisible(false);
395: newButton.setOrder(1000);
396: currentToolBar.addButton(newButton);
397: }
398:
399: }
400:
401: }
402:
403: // regenerate the saved file if required
404: if (rebuild) {
405: tools = new Vector(toolsArray.length);
406: for (int i = 0; i < toolsArray.length; i++) {
407: tools.add(toolsArray[i]);
408: }
409: saveTools();
410: }
411:
412: }
413:
414: private static synchronized void loadTools() {
415: String fullPath = null;
416: File file = new File(toolsConfPath);
417:
418: if (file.exists()) {
419: InputStream in = null;
420: try {
421: SAXParserFactory factory = SAXParserFactory
422: .newInstance();
423: factory.setNamespaceAware(true);
424:
425: SAXParser parser = factory.newSAXParser();
426: XMLToolHandler handler = new XMLToolHandler();
427:
428: in = new FileInputStream(file);
429: parser.parse(in, handler);
430: tools = handler.getToolsVector();
431:
432: SwingUtilities.invokeLater(new Runnable() {
433: public void run() {
434: compareTools();
435: }
436: });
437:
438: } catch (Exception e) {
439: e.printStackTrace();
440: GUIUtils
441: .displayErrorMessage(null,
442: "Error opening tools definitions.\nResorting to system defaults.");
443: loadDefaults(true);
444: } finally {
445: if (in != null) {
446: try {
447: in.close();
448: } catch (IOException e) {
449: }
450: }
451: }
452:
453: } else {
454: GUIUtils
455: .displayErrorMessage(
456: null,
457: "Tool buttons definition XML file not found.\n"
458: + "Ensure the file toolbars.xml is in the conf "
459: + "directory of this distribution.");
460: }
461: }
462:
463: static class XMLToolHandler extends DefaultHandler {
464:
465: private ToolBarWrapper toolBar;
466: private ToolBarButton tb;
467: private ToolBarConstraints tbc;
468: private CharArrayWriter contents = new CharArrayWriter();
469: private Vector toolBars = new Vector();
470:
471: public XMLToolHandler() {
472: }
473:
474: public void startElement(String nameSpaceURI, String localName,
475: String qName, Attributes attrs) {
476: contents.reset();
477: if (localName.equals(TOOLBAR)) {
478: toolBar = new ToolBarWrapper(attrs.getValue(NAME),
479: Boolean.valueOf(attrs.getValue(VISIBLE))
480: .booleanValue());
481: } else if (localName.equals(CONSTRAINTS)) {
482: tbc = new ToolBarConstraints();
483: } else if (localName.equals(BUTTON)) {
484: tb = new ToolBarButton(Integer.parseInt(attrs
485: .getValue(ID)), attrs.getValue(ACTION_ID));
486: }
487: }
488:
489: public void endElement(String nameSpaceURI, String localName,
490: String qName) {
491:
492: if (localName.equals(ROW))
493: tbc.setRow(Integer.parseInt(contents.toString()));
494:
495: else if (localName.equals(POSITION))
496: tbc.setPosition(Integer.parseInt(contents.toString()));
497:
498: else if (localName.equals(LOC_X))
499: tbc.setLocX(Integer.parseInt(contents.toString()));
500:
501: else if (localName.equals(RESIZE_OFFSET_X))
502: tbc.setResizeOffsetX(Integer.parseInt(contents
503: .toString()));
504:
505: else if (localName.equals(MINIMUM_WIDTH))
506: tbc.setMinimumWidth(Integer.parseInt(contents
507: .toString()));
508:
509: else if (localName.equals(PREFERRED_WIDTH))
510: tbc.setPreferredWidth(Integer.parseInt(contents
511: .toString()));
512:
513: else if (localName.equals(CURRENT_WIDTH))
514: tbc.setCurrentWidth(Integer.parseInt(contents
515: .toString()));
516:
517: else if (localName.equals(VISIBLE))
518: tb.setVisible(Boolean.valueOf(contents.toString())
519: .booleanValue());
520:
521: else if (localName.equals(ORDER)) {
522: tb.setOrder(Integer.parseInt(contents.toString()));
523: toolBar.addButton(tb);
524: tb = null;
525: }
526:
527: else if (localName.equals(TOOLBAR)) {
528: toolBar.setConstraints(tbc);
529: toolBars.add(toolBar);
530: tbc = null;
531: }
532:
533: }
534:
535: public Vector getToolsVector() {
536: return toolBars;
537: }
538:
539: public void characters(char[] data, int start, int length) {
540: contents.write(data, start, length);
541: }
542:
543: public void ignorableWhitespace(char[] data, int start,
544: int length) {
545: characters(data, start, length);
546: }
547:
548: public void error(SAXParseException spe) throws SAXException {
549: throw new SAXException(spe.getMessage());
550: }
551: } // XMLHandler
552:
553: static class ToolsParser implements XMLReader {
554: private String nsu = EMPTY;
555: private AttributesImpl atts = new AttributesImpl();
556:
557: private String attType1 = "CDATA";
558: private ContentHandler handler;
559:
560: private static char[] newLine = { '\n' };
561: private static String indent_1 = "\n ";
562: private static String indent_2 = "\n ";
563: private static String indent_3 = "\n ";
564: private static String indent_4 = "\n ";
565:
566: public ToolsParser() {
567: }
568:
569: public void parse(InputSource input) throws SAXException,
570: IOException {
571: if (!(input instanceof ToolbarButtonsSource))
572: throw new SAXException(
573: "Parser can only accept a ToolbarButtonsSource");
574:
575: parse((ToolbarButtonsSource) input);
576: }
577:
578: public void parse(ToolbarButtonsSource input)
579: throws IOException, SAXException {
580: try {
581: if (handler == null) {
582: throw new SAXException("No content handler");
583: }
584:
585: ToolBarWrapper[] tb = input.getTools();
586:
587: handler.startDocument();
588: handler.startElement(nsu, EQ_TOOLBARS, EQ_TOOLBARS,
589: atts);
590: handler.ignorableWhitespace(newLine, 0, 1);
591:
592: boolean isSeparator = false;
593: ToolBarConstraints tbc = null;
594: ToolBarButton button = null;
595: Vector buttons = null;
596: String marker = null;
597:
598: for (int i = 0; i < tb.length; i++) {
599: handler.ignorableWhitespace(indent_1.toCharArray(),
600: 0, indent_1.length());
601:
602: atts.addAttribute(EMPTY, NAME, NAME, attType1,
603: tb[i].getName());
604: atts.addAttribute(EMPTY, VISIBLE, VISIBLE,
605: attType1, Boolean.toString(tb[i]
606: .isVisible()));
607:
608: handler.startElement(nsu, TOOLBAR, TOOLBAR, atts);
609: atts.removeAttribute(atts.getIndex(NAME));
610: atts.removeAttribute(atts.getIndex(VISIBLE));
611:
612: handler.ignorableWhitespace(newLine, 0, 1);
613:
614: handler.ignorableWhitespace(indent_2.toCharArray(),
615: 0, indent_2.length());
616: handler.startElement(nsu, CONSTRAINTS, CONSTRAINTS,
617: atts);
618: handler.ignorableWhitespace(newLine, 0, 1);
619:
620: tbc = tb[i].getConstraints();
621: writeXML(ROW, Integer.toString(tbc.getRow()),
622: indent_3);
623: writeXML(POSITION, Integer.toString(tbc
624: .getPosition()), indent_3);
625: writeXML(LOC_X, Integer.toString(tbc.getLocX()),
626: indent_3);
627: writeXML(RESIZE_OFFSET_X, Integer.toString(tbc
628: .getResizeOffsetX()), indent_3);
629: writeXML(MINIMUM_WIDTH, Integer.toString(tbc
630: .getMinimumWidth()), indent_3);
631: writeXML(PREFERRED_WIDTH, Integer.toString(tbc
632: .getPreferredWidth()), indent_3);
633: writeXML(CURRENT_WIDTH, Integer.toString(tbc
634: .getCurrentWidth()), indent_3);
635:
636: handler.ignorableWhitespace(newLine, 0, 1);
637: handler.ignorableWhitespace(indent_2.toCharArray(),
638: 0, indent_2.length());
639: handler.endElement(nsu, CONSTRAINTS, CONSTRAINTS);
640: handler.ignorableWhitespace(newLine, 0, 1);
641: tbc = null;
642:
643: if (tb[i].hasButtons()) {
644: buttons = tb[i].getButtonsVector();
645:
646: handler.ignorableWhitespace(indent_2
647: .toCharArray(), 0, indent_2.length());
648: handler.startElement(nsu, BUTTONS, BUTTONS,
649: atts);
650: handler.ignorableWhitespace(newLine, 0, 1);
651:
652: for (int j = 0, k = buttons.size(); j < k; j++) {
653: button = (ToolBarButton) buttons
654: .elementAt(j);
655: handler.ignorableWhitespace(indent_3
656: .toCharArray(), 0, indent_3
657: .length());
658: atts.addAttribute(EMPTY, ID, ID, attType1,
659: Integer.toString(button.getId()));
660:
661: isSeparator = button.isSeparator();
662:
663: if (!isSeparator)
664: atts.addAttribute(EMPTY, ACTION_ID,
665: ACTION_ID, attType1, button
666: .getActionId());
667:
668: handler.startElement(nsu, BUTTON, BUTTON,
669: atts);
670: atts.removeAttribute(atts.getIndex(ID));
671:
672: if (!isSeparator)
673: atts.removeAttribute(atts
674: .getIndex(ACTION_ID));
675:
676: writeXML(VISIBLE, Boolean.toString(button
677: .isVisible()), indent_4);
678: writeXML(ORDER, Integer.toString(button
679: .getOrder()), indent_4);
680:
681: handler.ignorableWhitespace(indent_3
682: .toCharArray(), 0, indent_3
683: .length());
684: handler.endElement(nsu, BUTTON, BUTTON);
685: handler.ignorableWhitespace(newLine, 0, 1);
686: }
687:
688: handler.ignorableWhitespace(indent_2
689: .toCharArray(), 0, indent_2.length());
690: handler.endElement(nsu, BUTTONS, BUTTONS);
691: handler.ignorableWhitespace(newLine, 0, 1);
692:
693: }
694:
695: handler.ignorableWhitespace(indent_1.toCharArray(),
696: 0, indent_1.length());
697: handler.endElement(nsu, TOOLBAR, TOOLBAR);
698: handler.ignorableWhitespace(newLine, 0, 1);
699:
700: }
701:
702: handler.ignorableWhitespace(newLine, 0, 1);
703: handler.endElement(nsu, EQ_TOOLBARS, EQ_TOOLBARS);
704: handler.endDocument();
705:
706: } catch (Exception e) {
707: e.printStackTrace();
708: }
709:
710: }
711:
712: private void writeXML(String name, String line, String space)
713: throws SAXException {
714: int textLength = line.length();
715:
716: handler.ignorableWhitespace(space.toCharArray(), 0, space
717: .length());
718:
719: handler.startElement(nsu, name, name, atts);
720:
721: handler.characters(line.toCharArray(), 0, textLength);
722:
723: handler.endElement(nsu, name, name);
724: }
725:
726: public void setContentHandler(ContentHandler handler) {
727: this .handler = handler;
728: }
729:
730: public ContentHandler getContentHandler() {
731: return this .handler;
732: }
733:
734: public void setErrorHandler(ErrorHandler handler) {
735: }
736:
737: public ErrorHandler getErrorHandler() {
738: return null;
739: }
740:
741: public void parse(String systemId) throws IOException,
742: SAXException {
743: }
744:
745: public DTDHandler getDTDHandler() {
746: return null;
747: }
748:
749: public EntityResolver getEntityResolver() {
750: return null;
751: }
752:
753: public void setEntityResolver(EntityResolver resolver) {
754: }
755:
756: public void setDTDHandler(DTDHandler handler) {
757: }
758:
759: public Object getProperty(String name) {
760: return null;
761: }
762:
763: public void setProperty(String name, java.lang.Object value) {
764: }
765:
766: public void setFeature(String name, boolean value) {
767: }
768:
769: public boolean getFeature(String name) {
770: return false;
771: }
772: } // class DriverParser
773:
774: static class ToolbarButtonsSource extends InputSource {
775:
776: public ToolBarWrapper[] getTools() {
777: int size = tools.size();
778: ToolBarWrapper[] toolBars = new ToolBarWrapper[size];
779: for (int i = 0; i < size; i++) {
780: toolBars[i] = (ToolBarWrapper) tools.elementAt(i);
781: }
782: return toolBars;
783: }
784:
785: } // class ToolbarButtonsSource
786:
787: }
|