/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package org.apache.batik.apps.svgbrowser;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.Writer;
import java.net.Authenticator;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.StringTokenizer;
import java.util.Vector;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.UIManager;
import javax.swing.plaf.FontUIResource;
import org.apache.batik.swing.JSVGCanvas;
import org.apache.batik.swing.gvt.GVTTreeRendererAdapter;
import org.apache.batik.swing.gvt.GVTTreeRendererEvent;
import org.apache.batik.swing.svg.GVTTreeBuilderAdapter;
import org.apache.batik.swing.svg.GVTTreeBuilderEvent;
import org.apache.batik.swing.svg.SVGDocumentLoaderAdapter;
import org.apache.batik.swing.svg.SVGDocumentLoaderEvent;
import org.apache.batik.util.ApplicationSecurityEnforcer;
import org.apache.batik.util.ParsedURL;
import org.apache.batik.util.SVGConstants;
import org.apache.batik.util.XMLResourceDescriptor;
import org.apache.batik.util.gui.resource.ResourceManager;
/**
* This class contains the main method of an SVG viewer.
*
* @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
* @version $Id: Main.java,v 1.47 2003/04/11 13:54:38 vhardy Exp $
*/
public class Main implements Application {
/**
* Extension used in addition to the scriptType value
* to read from the PreferenceManager whether or not the
* scriptType can be loaded.
*/
public static final String UNKNOWN_SCRIPT_TYPE_LOAD_KEY_EXTENSION
= ".load";
/**
* User home property
*/
public static final String PROPERTY_USER_HOME = "user.home";
/**
* System property for specifying an additional policy file.
*/
public static final String PROPERTY_JAVA_SECURITY_POLICY
= "java.security.policy";
/**
* Batik configuration sub-directory
*/
public static final String BATIK_CONFIGURATION_SUBDIRECTORY = ".batik";
/**
* Name of the Squiggle configuration file
*/
public static final String SQUIGGLE_CONFIGURATION_FILE = "preferences.xml";
/**
* Name of the Squiggle policy file
*/
public static final String SQUIGGLE_POLICY_FILE = "__svgbrowser.policy";
/**
* Entry for granting network access to scripts
*/
public static final String POLICY_GRANT_SCRIPT_NETWORK_ACCESS
= "grant {\n permission java.net.SocketPermission \"*\", \"listen, connect, resolve, accept\";\n};\n\n";
/**
* Entry for granting file system access to scripts
*/
public static final String POLICY_GRANT_SCRIPT_FILE_ACCESS
= "grant {\n permission java.io.FilePermission \"<<ALL FILES>>\", \"read\";\n};\n\n";
/**
* Entry for the list of recently visited URI
*/
public static final String PREFERENCE_KEY_VISITED_URI_LIST
= "preference.key.visited.uri.list";
/**
* Entry for the maximum number of last visited URIs
*/
public static final String PREFERENCE_KEY_VISITED_URI_LIST_LENGTH
= "preference.key.visited.uri.list.length";
/**
* List of separators between URI values in the preference
* file
*/
public static final String URI_SEPARATOR = " ";
/**
* Default font-family value.
*/
public static final String DEFAULT_DEFAULT_FONT_FAMILY
= "Arial, Helvetica, sans-serif";
/**
* SVG initialization file, used to trigger loading of most of
* the Batik classes
*/
public static final String SVG_INITIALIZATION = "resources/init.svg";
/**
* Stores the initialization file URI
*/
protected String svgInitializationURI;
/**
* Creates a viewer frame and shows it..
* @param args The command-line arguments.
*/
public static void main(String[] args) {
new Main(args);
}
/**
* The gui resources file name
*/
public final static String RESOURCES =
"org.apache.batik.apps.svgbrowser.resources.Main";
/**
* URL for Squiggle's security policy file
*/
public static final String SQUIGGLE_SECURITY_POLICY
= "org/apache/batik/apps/svgbrowser/resources/svgbrowser.policy";
/**
* The resource bundle
*/
protected static ResourceBundle bundle;
/**
* The resource manager
*/
protected static ResourceManager resources;
static {
bundle = ResourceBundle.getBundle(RESOURCES, Locale.getDefault());
resources = new ResourceManager(bundle);
}
/**
* The frame's icon.
*/
protected static ImageIcon frameIcon = new ImageIcon
(Main.class.getResource(resources.getString("Frame.icon")));
/**
* The preference manager.
*/
protected XMLPreferenceManager preferenceManager;
/**
* Maximum number of recently visited URIs
*/
public static final int MAX_VISITED_URIS = 10;
/**
* The array of last visited URIs
*/
protected Vector lastVisited = new Vector();
/**
* The actual allowed maximum number of last visited URIs
*/
protected int maxVisitedURIs = MAX_VISITED_URIS;
/**
* The arguments.
*/
protected String[] arguments;
/**
* Controls whether the application can override the
* system security policy property. This is done when there
* was no initial security policy specified when the application
* stated, in which case Batik will use that property.
*/
protected boolean overrideSecurityPolicy = false;
/**
* Script security enforcement is delegated to the
* security utility
*/
protected ApplicationSecurityEnforcer securityEnforcer;
/**
* The option handlers.
*/
protected Map handlers = new HashMap();
{
handlers.put("-font-size", new FontSizeHandler());
}
/**
* The viewer frames.
*/
protected List viewerFrames = new LinkedList();
/**
* The preference dialog.
*/
protected PreferenceDialog preferenceDialog;
/**
* Creates a new application.
* @param args The command-line arguments.
*/
public Main(String[] args) {
arguments = args;
//
// Preferences
//
Map defaults = new HashMap(11);
defaults.put(PreferenceDialog.PREFERENCE_KEY_LANGUAGES,
Locale.getDefault().getLanguage());
defaults.put(PreferenceDialog.PREFERENCE_KEY_SHOW_RENDERING,
Boolean.FALSE);
defaults.put(PreferenceDialog.PREFERENCE_KEY_AUTO_ADJUST_WINDOW,
Boolean.TRUE);
defaults.put(PreferenceDialog.PREFERENCE_KEY_SELECTION_XOR_MODE,
Boolean.FALSE);
defaults.put(PreferenceDialog.PREFERENCE_KEY_ENABLE_DOUBLE_BUFFERING,
Boolean.TRUE);
defaults.put(PreferenceDialog.PREFERENCE_KEY_SHOW_DEBUG_TRACE,
Boolean.FALSE);
defaults.put(PreferenceDialog.PREFERENCE_KEY_PROXY_HOST,
"");
defaults.put(PreferenceDialog.PREFERENCE_KEY_PROXY_PORT,
"");
defaults.put(PreferenceDialog.PREFERENCE_KEY_CSS_MEDIA,
"screen");
defaults.put(PreferenceDialog.PREFERENCE_KEY_DEFAULT_FONT_FAMILY,
DEFAULT_DEFAULT_FONT_FAMILY);
defaults.put(PreferenceDialog.PREFERENCE_KEY_IS_XML_PARSER_VALIDATING,
Boolean.FALSE);
defaults.put(PreferenceDialog.PREFERENCE_KEY_ENFORCE_SECURE_SCRIPTING,
Boolean.TRUE);
defaults.put(PreferenceDialog.PREFERENCE_KEY_GRANT_SCRIPT_FILE_ACCESS,
Boolean.FALSE);
defaults.put(PreferenceDialog.PREFERENCE_KEY_GRANT_SCRIPT_NETWORK_ACCESS,
Boolean.FALSE);
defaults.put(PreferenceDialog.PREFERENCE_KEY_LOAD_JAVA,
Boolean.TRUE);
defaults.put(PreferenceDialog.PREFERENCE_KEY_LOAD_ECMASCRIPT,
Boolean.TRUE);
defaults.put(PreferenceDialog.PREFERENCE_KEY_ALLOWED_SCRIPT_ORIGIN,
new Integer(ResourceOrigin.DOCUMENT));
defaults.put(PreferenceDialog.PREFERENCE_KEY_ALLOWED_EXTERNAL_RESOURCE_ORIGIN,
new Integer(ResourceOrigin.ANY));
defaults.put(PREFERENCE_KEY_VISITED_URI_LIST,
"");
defaults.put(PREFERENCE_KEY_VISITED_URI_LIST_LENGTH,
new Integer(MAX_VISITED_URIS));
securityEnforcer
= new ApplicationSecurityEnforcer(this.getClass(),
SQUIGGLE_SECURITY_POLICY);
try {
preferenceManager = new XMLPreferenceManager(SQUIGGLE_CONFIGURATION_FILE,
defaults);
String dir = System.getProperty(PROPERTY_USER_HOME);
File f = new File(dir, BATIK_CONFIGURATION_SUBDIRECTORY);
f.mkdir();
preferenceManager.setPreferenceDirectory(f.getCanonicalPath());
preferenceManager.load();
setPreferences();
initializeLastVisited();
Authenticator.setDefault(new JAuthenticator());
} catch (Exception e) {
e.printStackTrace();
}
//
// Initialization
//
final AboutDialog initDialog = new AboutDialog();
final JProgressBar pb = new JProgressBar(0, 3);
initDialog.getContentPane().add("South", pb);
// Work around pack() bug on some platforms
Dimension ss = initDialog.getToolkit().getScreenSize();
Dimension ds = initDialog.getPreferredSize();
initDialog.setLocation((ss.width - ds.width) / 2,
(ss.height - ds.height) / 2);
initDialog.setSize(ds);
initDialog.setVisible(true);
final JSVGViewerFrame v = new JSVGViewerFrame(this);
JSVGCanvas c = v.getJSVGCanvas();
c.addSVGDocumentLoaderListener(new SVGDocumentLoaderAdapter() {
public void documentLoadingStarted(SVGDocumentLoaderEvent e) {
pb.setValue(1);
}
public void documentLoadingCompleted(SVGDocumentLoaderEvent e) {
pb.setValue(2);
}
});
c.addGVTTreeBuilderListener(new GVTTreeBuilderAdapter() {
public void gvtBuildCompleted(GVTTreeBuilderEvent e) {
pb.setValue(3);
}
});
c.addGVTTreeRendererListener(new GVTTreeRendererAdapter() {
public void gvtRenderingCompleted(GVTTreeRendererEvent e) {
initDialog.dispose();
v.dispose();
System.gc();
run();
}
});
c.setSize(100, 100);
svgInitializationURI = Main.class.getResource(SVG_INITIALIZATION).toString();
c.loadSVGDocument(svgInitializationURI);
}
/**
* Installs a custom policy file in the '.batik' directory. This is initialized
* with the content of the policy file coming with the distribution
*/
public void installCustomPolicyFile() throws IOException {
String securityPolicyProperty
= System.getProperty(PROPERTY_JAVA_SECURITY_POLICY);
if (overrideSecurityPolicy
||
securityPolicyProperty == null
||
"".equals(securityPolicyProperty)) {
// Access default policy file
ParsedURL policyURL = new ParsedURL(securityEnforcer.getPolicyURL());
// Override the user policy
String dir = System.getProperty(PROPERTY_USER_HOME);
File batikConfigDir = new File(dir, BATIK_CONFIGURATION_SUBDIRECTORY);
File policyFile = new File(batikConfigDir, SQUIGGLE_POLICY_FILE);
// Copy original policy file into local policy file
Reader r = new BufferedReader(new InputStreamReader(policyURL.openStream()));
Writer w = new FileWriter(policyFile);
char[] buf = new char[1024];
int n = 0;
while ( (n=r.read(buf, 0, buf.length)) != -1 ) {
w.write(buf, 0, n);
}
r.close();
// Now, append additional grants depending on the security
// settings
boolean grantScriptNetworkAccess
= preferenceManager.getBoolean
(PreferenceDialog.PREFERENCE_KEY_GRANT_SCRIPT_NETWORK_ACCESS);
boolean grantScriptFileAccess
= preferenceManager.getBoolean
(PreferenceDialog.PREFERENCE_KEY_GRANT_SCRIPT_FILE_ACCESS);
if (grantScriptNetworkAccess) {
w.write(POLICY_GRANT_SCRIPT_NETWORK_ACCESS);
}
if (grantScriptFileAccess) {
w.write(POLICY_GRANT_SCRIPT_FILE_ACCESS);
}
w.close();
// We now use the JAVA_SECURITY_POLICY property, so
// we allow override on subsequent calls.
overrideSecurityPolicy = true;
System.setProperty(PROPERTY_JAVA_SECURITY_POLICY,
policyFile.toURL().toString());
}
}
/**
* Runs the application.
*/
public void run() {
try {
int i = 0;
for (; i < arguments.length; i++) {
OptionHandler oh = (OptionHandler)handlers.get(arguments[i]);
if (oh == null) {
break;
}
i = oh.handleOption(i);
}
JSVGViewerFrame frame = createAndShowJSVGViewerFrame();
while (i < arguments.length) {
if (arguments[i].length() == 0) {
i++;
continue;
}
File file = new File(arguments[i]);
String uri = null;
try{
if (file.canRead()) {
uri = file.toURL().toString();
}
}catch(SecurityException se){
// Cannot access files.
}
if(uri == null){
uri = arguments[i];
ParsedURL purl = null;
purl = new ParsedURL(arguments[i]);
if (!purl.complete())
// This is not a valid uri
uri = null;
}
if (uri != null) {
if (frame == null)
frame = createAndShowJSVGViewerFrame();
frame.showSVGDocument(uri);
frame = null;
} else {
// Let the user know that we are
// skipping this file...
// Note that frame may be null, which is
// a valid argument for showMessageDialog
// NOTE: Need to revisit Resources/Messages usage to
// have a single entry point. Should have a
// formated message here instead of a + ...
JOptionPane.showMessageDialog
(frame,
resources.getString("Error.skipping.file")
+ arguments[i]);
}
i++;
}
} catch (Exception e) {
e.printStackTrace();
printUsage();
}
}
/**
* Prints the command line usage.
*/
protected void printUsage() {
System.out.println();
System.out.println(resources.getString("Command.header"));
System.out.println(resources.getString("Command.syntax"));
System.out.println();
System.out.println(resources.getString("Command.options"));
Iterator it = handlers.keySet().iterator();
while (it.hasNext()) {
String s = (String)it.next();
System.out.println(((OptionHandler)handlers.get(s)).getDescription());
}
}
/**
* This interface represents an option handler.
*/
protected interface OptionHandler {
/**
* Handles the current option.
* @return the index of argument just before the next one to handle.
*/
int handleOption(int i);
/**
* Returns the option description.
*/
String getDescription();
}
/**
* To handle the '-font-size' option.
*/
protected class FontSizeHandler implements OptionHandler {
public int handleOption(int i) {
int size = Integer.parseInt(arguments[++i]);
Font font = new Font("Dialog", Font.PLAIN, size);
FontUIResource fontRes = new FontUIResource(font);
UIManager.put("CheckBox.font", fontRes);
UIManager.put("PopupMenu.font", fontRes);
UIManager.put("TextPane.font", fontRes);
UIManager.put("MenuItem.font", fontRes);
UIManager.put("ComboBox.font", fontRes);
UIManager.put("Button.font", fontRes);
UIManager.put("Tree.font", fontRes);
UIManager.put("ScrollPane.font", fontRes);
UIManager.put("TabbedPane.font", fontRes);
UIManager.put("EditorPane.font", fontRes);
UIManager.put("TitledBorder.font", fontRes);
UIManager.put("Menu.font", fontRes);
UIManager.put("TextArea.font", fontRes);
UIManager.put("OptionPane.font", fontRes);
UIManager.put("DesktopIcon.font", fontRes);
UIManager.put("MenuBar.font", fontRes);
UIManager.put("ToolBar.font", fontRes);
UIManager.put("RadioButton.font", fontRes);
UIManager.put("RadioButtonMenuItem.font", fontRes);
UIManager.put("ToggleButton.font", fontRes);
UIManager.put("ToolTip.font", fontRes);
UIManager.put("ProgressBar.font", fontRes);
UIManager.put("TableHeader.font", fontRes);
UIManager.put("Panel.font", fontRes);
UIManager.put("List.font", fontRes);
UIManager.put("ColorChooser.font", fontRes);
UIManager.put("PasswordField.font", fontRes);
UIManager.put("TextField.font", fontRes);
UIManager.put("Table.font", fontRes);
UIManager.put("Label.font", fontRes);
UIManager.put("InternalFrameTitlePane.font", fontRes);
UIManager.put("CheckBoxMenuItem.font", fontRes);
return i;
}
public String getDescription() {
return resources.getString("Command.font-size");
}
}
// Application ///////////////////////////////////////////////
/**
* Creates and shows a new viewer frame.
*/
public JSVGViewerFrame createAndShowJSVGViewerFrame() {
JSVGViewerFrame mainFrame = new JSVGViewerFrame(this);
mainFrame.setSize(resources.getInteger("Frame.width"),
resources.getInteger("Frame.height"));
mainFrame.setIconImage(frameIcon.getImage());
mainFrame.setTitle(resources.getString("Frame.title"));
mainFrame.show();
viewerFrames.add(mainFrame);
setPreferences(mainFrame);
return mainFrame;
}
/**
* Closes the given viewer frame.
*/
public void closeJSVGViewerFrame(JSVGViewerFrame f) {
f.getJSVGCanvas().stopProcessing();
viewerFrames.remove(f);
if (viewerFrames.size() == 0) {
System.exit(0);
}
f.dispose();
}
/**
* Creates a new application exit action.
*/
public Action createExitAction(JSVGViewerFrame vf) {
return new AbstractAction() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
};
}
/**
* Opens the given link in a new window.
*/
public void openLink(String url) {
JSVGViewerFrame f = createAndShowJSVGViewerFrame();
f.getJSVGCanvas().loadSVGDocument(url);
}
/**
* Returns the XML parser class name.
*/
public String getXMLParserClassName() {
return XMLResourceDescriptor.getXMLParserClassName();
}
/**
* Returns true if the XML parser must be in validation mode, false
* otherwise.
*/
public boolean isXMLParserValidating() {
return preferenceManager.getBoolean
(PreferenceDialog.PREFERENCE_KEY_IS_XML_PARSER_VALIDATING);
}
/**
* Shows the preference dialog.
*/
public void showPreferenceDialog(JSVGViewerFrame f) {
if (preferenceDialog == null) {
preferenceDialog = new PreferenceDialog(preferenceManager);
}
if (preferenceDialog.showDialog() == PreferenceDialog.OK_OPTION) {
try {
preferenceManager.save();
setPreferences();
} catch (Exception e) {
}
}
}
private void setPreferences() throws IOException {
Iterator it = viewerFrames.iterator();
while (it.hasNext()) {
setPreferences((JSVGViewerFrame)it.next());
}
System.setProperty("proxyHost", preferenceManager.getString
(PreferenceDialog.PREFERENCE_KEY_PROXY_HOST));
System.setProperty("proxyPort", preferenceManager.getString
(PreferenceDialog.PREFERENCE_KEY_PROXY_PORT));
installCustomPolicyFile();
securityEnforcer.enforceSecurity
(preferenceManager.getBoolean
(PreferenceDialog.PREFERENCE_KEY_ENFORCE_SECURE_SCRIPTING)
);
}
private void setPreferences(JSVGViewerFrame vf) {
boolean db = preferenceManager.getBoolean
(PreferenceDialog.PREFERENCE_KEY_ENABLE_DOUBLE_BUFFERING);
vf.getJSVGCanvas().setDoubleBufferedRendering(db);
boolean sr = preferenceManager.getBoolean
(PreferenceDialog.PREFERENCE_KEY_SHOW_RENDERING);
vf.getJSVGCanvas().setProgressivePaint(sr);
boolean d = preferenceManager.getBoolean
(PreferenceDialog.PREFERENCE_KEY_SHOW_DEBUG_TRACE);
vf.setDebug(d);
boolean aa = preferenceManager.getBoolean
(PreferenceDialog.PREFERENCE_KEY_AUTO_ADJUST_WINDOW);
vf.setAutoAdjust(aa);
boolean dd = preferenceManager.getBoolean
(PreferenceDialog.PREFERENCE_KEY_SELECTION_XOR_MODE);
vf.getJSVGCanvas().setSelectionOverlayXORMode(dd);
}
/**
* Returns the user languages.
*/
public String getLanguages() {
String s = preferenceManager.getString
(PreferenceDialog.PREFERENCE_KEY_LANGUAGES);
return (s == null)
? Locale.getDefault().getLanguage()
: s;
}
/**
* Returns the user stylesheet uri.
* @return null if no user style sheet was specified.
*/
public String getUserStyleSheetURI() {
return preferenceManager.getString
(PreferenceDialog.PREFERENCE_KEY_USER_STYLESHEET);
}
/**
* Returns the default value for the CSS
* "font-family" property
*/
public String getDefaultFontFamily() {
return preferenceManager.getString
(PreferenceDialog.PREFERENCE_KEY_DEFAULT_FONT_FAMILY);
}
/**
* Returns the CSS media to use.
* @return empty string if no CSS media was specified.
*/
public String getMedia() {
String s = preferenceManager.getString
(PreferenceDialog.PREFERENCE_KEY_CSS_MEDIA);
return (s == null) ? "screen" : s;
}
/**
* Returns true if the selection overlay is painted in XOR mode, false
* otherwise.
*/
public boolean isSelectionOverlayXORMode() {
return preferenceManager.getBoolean
(PreferenceDialog.PREFERENCE_KEY_SELECTION_XOR_MODE);
}
/**
* Returns true if the input scriptType can be loaded in
* this application.
*/
public boolean canLoadScriptType(String scriptType){
if (SVGConstants.SVG_SCRIPT_TYPE_ECMASCRIPT.equals(scriptType)){
return preferenceManager.getBoolean
(PreferenceDialog.PREFERENCE_KEY_LOAD_ECMASCRIPT);
} else if (SVGConstants.SVG_SCRIPT_TYPE_JAVA.equals(scriptType)){
return preferenceManager.getBoolean
(PreferenceDialog.PREFERENCE_KEY_LOAD_JAVA);
} else {
return preferenceManager.getBoolean
(scriptType + UNKNOWN_SCRIPT_TYPE_LOAD_KEY_EXTENSION);
}
}
/**
* Returns the allowed origins for scripts.
* @see ResourceOrigin
*/
public int getAllowedScriptOrigin() {
int ret = preferenceManager.getInteger
(PreferenceDialog.PREFERENCE_KEY_ALLOWED_SCRIPT_ORIGIN);
return ret;
}
/**
* Returns the allowed origins for external
* resources.
* @see ResourceOrigin
*/
public int getAllowedExternalResourceOrigin() {
int ret = preferenceManager.getInteger
(PreferenceDialog.PREFERENCE_KEY_ALLOWED_EXTERNAL_RESOURCE_ORIGIN);
return ret;
}
/**
* Notifies Application of recently visited URI
*/
public void addVisitedURI(String uri) {
if(svgInitializationURI.equals(uri)) {
return;
}
int maxVisitedURIs =
preferenceManager.getInteger
(PREFERENCE_KEY_VISITED_URI_LIST_LENGTH);
if (maxVisitedURIs < 0) {
maxVisitedURIs = 0;
}
if (lastVisited.contains(uri)) {
lastVisited.removeElement(uri);
}
while (lastVisited.size() > 0 && lastVisited.size() > (maxVisitedURIs-1)) {
lastVisited.removeElementAt(0);
}
if (maxVisitedURIs > 0) {
lastVisited.addElement(uri);
}
// Now, save the list of visited URL into the preferences
StringBuffer lastVisitedBuffer = new StringBuffer();
for (int i=0; i<lastVisited.size(); i++) {
lastVisitedBuffer.append(URLEncoder.encode(lastVisited.elementAt(i).toString()));
lastVisitedBuffer.append(URI_SEPARATOR);
}
preferenceManager.setString
(PREFERENCE_KEY_VISITED_URI_LIST,
lastVisitedBuffer.toString());
try {
preferenceManager.save();
} catch (Exception e) {
// As in other places. But this is ugly...
}
}
/**
* Asks Application for a list of recently visited URI.
*/
public String[] getVisitedURIs() {
String[] visitedURIs = new String[lastVisited.size()];
lastVisited.copyInto(visitedURIs);
return visitedURIs;
}
/**
* Initializes the lastVisited array
*/
protected void initializeLastVisited(){
String lastVisitedStr
= preferenceManager.getString(PREFERENCE_KEY_VISITED_URI_LIST);
StringTokenizer st
= new StringTokenizer(lastVisitedStr,
URI_SEPARATOR);
int n = st.countTokens();
int maxVisitedURIs
= preferenceManager.getInteger
(PREFERENCE_KEY_VISITED_URI_LIST_LENGTH);
if (n > maxVisitedURIs) {
n = maxVisitedURIs;
}
for (int i=0; i<n; i++) {
lastVisited.addElement(URLDecoder.decode(st.nextToken()));
}
}
}