package org.rubypeople.rdt.internal.ui.preferences; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.eclipse.core.runtime.IStatus; import org.rubypeople.rdt.internal.ui.RubyPlugin; import org.rubypeople.rdt.internal.ui.RubyUIException; import org.rubypeople.rdt.internal.ui.RubyUIStatus; import org.rubypeople.rdt.internal.ui.preferences.RubyEditorColoringConfigurationBlock.HighlightingColorListItem; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; public class SyntaxColoringStore { private static final int CURRENT_VERSION = 1; /** * Identifiers for the XML file. */ private final static String XML_NODE_ROOT = "colors"; //$NON-NLS-1$ private final static String XML_NODE_SETTING = "setting"; //$NON-NLS-1$ private final static String XML_ATTRIBUTE_VERSION = "version"; //$NON-NLS-1$ private final static String XML_ATTRIBUTE_ID = "id"; //$NON-NLS-1$ private final static String XML_ATTRIBUTE_VALUE = "value"; //$NON-NLS-1$ public static void write(List<HighlightingColorListItem> colors, File file) throws RubyUIException { final OutputStream writer; try { writer = new FileOutputStream(file); try { writeToStream(colors, writer); } finally { try { writer.close(); } catch (IOException e) { /* ignore */ } } } catch (IOException e) { throw createException(e, "Problems serializing the profiles to XML"); } } private static void writeToStream(List<HighlightingColorListItem> colors, OutputStream stream) throws RubyUIException { try { final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); final DocumentBuilder builder = factory.newDocumentBuilder(); final Document document = builder.newDocument(); final Element rootElement = document.createElement(XML_NODE_ROOT); rootElement.setAttribute(XML_ATTRIBUTE_VERSION, Integer.toString(CURRENT_VERSION)); document.appendChild(rootElement); for (HighlightingColorListItem item : colors) { addKeyValuePair(document, rootElement, item.getColorKey(), ""); addKeyValuePair(document, rootElement, item.getBackgroundKey(), ""); addKeyValuePair(document, rootElement, item.getBackgroundEnabledKey(), "false"); addKeyValuePair(document, rootElement, item.getBoldKey(), "false"); addKeyValuePair(document, rootElement, item.getItalicKey(), "false"); addKeyValuePair(document, rootElement, item.getStrikethroughKey(), "false"); addKeyValuePair(document, rootElement, item.getUnderlineKey(), "false"); } Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$ transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); //$NON-NLS-1$ transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$ transformer.transform(new DOMSource(document), new StreamResult(stream)); } catch (TransformerException e) { throw createException(e, "Problems serializing the profiles to XML"); } catch (ParserConfigurationException e) { throw createException(e, "Problems serializing the profiles to XML"); } } private static void addKeyValuePair(final Document document, final Element rootElement, String key, String defaultValue) { String value = RubyPlugin.getDefault().getPreferenceStore().getString(key); if (value == null || value.trim().length() == 0) { value = defaultValue; } final Element setting = document.createElement(XML_NODE_SETTING); setting.setAttribute(XML_ATTRIBUTE_ID, key); setting.setAttribute(XML_ATTRIBUTE_VALUE, value); rootElement.appendChild(setting); } /* * Creates a UI exception for logging purposes */ private static RubyUIException createException(Throwable t, String message) { return new RubyUIException(RubyUIStatus.createError(IStatus.ERROR, message, t)); } public static Map<String, String> readFromFile(File file) throws RubyUIException { try { final FileInputStream reader = new FileInputStream(file); try { return readFromStream(new InputSource(reader)); } finally { try { reader.close(); } catch (IOException e) { /* ignore */ } } } catch (IOException e) { throw createException(e, "Problems reading profiles from XML."); } } private static Map<String, String> readFromStream(InputSource inputSource) throws RubyUIException { final ProfileDefaultHandler handler = new ProfileDefaultHandler(); try { final SAXParserFactory factory = SAXParserFactory.newInstance(); final SAXParser parser = factory.newSAXParser(); parser.parse(inputSource, handler); } catch (SAXException e) { throw createException(e, "Problems reading profiles from XML."); } catch (IOException e) { throw createException(e, "Problems reading profiles from XML."); } catch (ParserConfigurationException e) { throw createException(e, "Problems reading profiles from XML."); } return handler.getProfiles(); } /** * A SAX event handler to parse the xml format for profiles. */ private final static class ProfileDefaultHandler extends DefaultHandler { private Map fSettings; public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (qName.equals(XML_NODE_SETTING)) { final String key= attributes.getValue(XML_ATTRIBUTE_ID); final String value= attributes.getValue(XML_ATTRIBUTE_VALUE); fSettings.put(key, value); } else if (qName.equals(XML_NODE_ROOT)) { fSettings= new HashMap(200); } } public void endElement(String uri, String localName, String qName) { } public Map getProfiles() { return fSettings; } } }