/*
* #!
* Ontopia Vizigator
* #-
* Copyright (C) 2001 - 2013 The Ontopia Project
* #-
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* !#
*/
package net.ontopia.topicmaps.viz;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import net.ontopia.utils.StreamUtils;
/**
* Parses menu configuration files.
*/
public class MenuFileParser {
private String source;
Map enabled;
int lineIndex;
boolean succeeded;
/**
* Create new from a given file.
*/
public MenuFileParser(String fileString) {
try {
source = readFile(fileString);
VizDebugUtils.debug(source);
} catch (IOException e) {
source = null;
WarningBox warningBox =
new WarningBox(Messages.getString("Viz.FileNotFoundColon") +
fileString);
warningBox.setVisible(true);
}
}
public void warn(String warning) {
String args[] = new String[1];
args[0] = String.valueOf(lineIndex);
WarningBox warningBox =
new WarningBox(Messages.getString("Viz.ErrorInLine", args) + warning);
warningBox.setVisible(true);
}
public ParsedMenuFile parse() {
if (source == null)
return null;
enabled = new HashMap();
lineIndex = 1;
try {
while (parseLine())
lineIndex++;
return new ParsedMenuFile(enabled);
} catch (MenuFileParseError e) {
warn(e.getMessage());
return new ParsedMenuFile(null);
}
}
/**
* @return true iff there are more lines to parse *after* the current line.
*/
private boolean parseLine() throws MenuFileParseError {
int index = source.indexOf('\n');
if (index == -1) {
if (source.length() > 0)
parseLine(source);
return false;
}
parseLine(source.substring(0, index));
if (source.length() == index + 1)
return false;
source = source.substring(index + 1);
return true;
}
private void parseLine(String startLine) throws MenuFileParseError {
String line = startLine;
VizDebugUtils.debug("Parsing line: " + line);
// Remove the comment part (if present).
int hashIndex = line.indexOf('#');
if (hashIndex != -1)
line = line.substring(0, hashIndex);
// Remove any leading and trailing whitespace.
line = line.trim();
VizDebugUtils.debug("trimmed line: " + line);
// This was a blank line or one with only a comment.
// No further processing needed.
if (line.length() == 0)
return;
String args[] = new String[1];
args[0] = startLine;
int eqIndex = line.indexOf('=');
if (eqIndex == -1)
throw new MenuFileParseError(
Messages.getString("Viz.MissingEqualsMessage", startLine));
if (eqIndex == 0)
throw new MenuFileParseError(
Messages.getString("Viz.MissingNameMessage", startLine));
if (eqIndex == line.length() - 1)
throw new MenuFileParseError(
Messages.getString("Viz.MissingOnOffMessage", startLine));
String name = line.substring(0, eqIndex);
VizDebugUtils.debug("name: " + name);
validateName(name);
String value = line.substring(eqIndex + 1);
VizDebugUtils.debug("value: " + value);
validateValue(value);
enabled.put(name, value.equals("on") ? Boolean.TRUE : Boolean.FALSE);
}
private void validateName (String name) throws MenuFileParseError {
// The name must be on the form: Alpha ("." | Alpha)*
if (!loweralpha(name.charAt(0)))
throw new MenuFileParseError(Messages
.getString("Viz.NameCannotStartPeriod"));
if (!loweralpha(name.charAt(name.length() - 1)))
throw new MenuFileParseError(Messages
.getString("Viz.NameCannotEndPeriod"));
int index = 0;
while (index < name.length()) {
char currentChar = name.charAt(index);
if (!(loweralpha(currentChar) || currentChar == '.'))
throw new MenuFileParseError(Messages
.getString("Viz.NameOnlyAZ"));
index++;
}
}
private boolean loweralpha(char c) {
return 'a' <= c && c <= 'z';
}
private void validateValue (String value) throws MenuFileParseError {
// Value must be either "on" or "off".
if (!(value.equals("on") || value.equals("off")))
throw new MenuFileParseError("The value \"" + value +
"\" is not on the form \"on\" or \"off\"");
}
private String readFile(String urlFileString) throws IOException {
URL url = new URL(urlFileString);
VizDebugUtils.debug("url: " + url.toString());
InputStream stream = url.openStream();
Reader reader = new InputStreamReader(stream, "iso-8859-1");
StringWriter writer = new StringWriter();
StreamUtils.transfer(reader, writer);
stream.close();
return writer.toString();
}
/**
* Generates a box with a warning message and an Ok button.
*/
private class WarningBox extends JFrame {
public WarningBox(String warning) {
// Create the warning panel to hold all the other components.
JPanel warningPanel = new JPanel();
// Lay out the components vertically.
warningPanel.setLayout(new BoxLayout(warningPanel, BoxLayout.Y_AXIS));
warningPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory
.createEtchedBorder(), Messages.getString("Viz.Warning")));
// Create the warning message.
JTextArea warningTextArea = new JTextArea(warning);
warningTextArea.setLineWrap(true);
warningTextArea.setWrapStyleWord(true);
warningTextArea.setEditable(false);
warningTextArea.setFont(warningTextArea.getFont().deriveFont(13f));
warningTextArea.setBackground(warningPanel.getBackground());
warningPanel.add(warningTextArea);
// Will listen for and act upon changes to the OK button.
ActionListener okListener = new ActionListener() {
public void actionPerformed(ActionEvent action) {
setVisible(false);
}
};
// Create an Ok button.
JButton okButton = new JButton(
Messages.getString("Viz.OK"));
okButton.addActionListener(okListener);
warningPanel.add(okButton);
getContentPane().add(warningPanel);
setSize(400, 150);
}
}
/**
* Indicates a parse or syntax error in MenuFileParser.
*/
public class MenuFileParseError extends Exception {
String message;
public MenuFileParseError(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
}