/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is NetBeans. The Initial Developer of the Original
* Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun
* Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.editor;
import javax.swing.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
/** Registry of all annotation types. This is singleton and it also keeps
* the settings whether the annotation types which are not active are
* drawn on the background, whther the combining of annotations is
* turned on or off etc. These settings are shared by all views.
*
* @author David Konecny
* @since 08/2001
*/
public class AnnotationTypes {
/** Whether the pasive glyphs are drawn on the background under the text (boolean). */
public static final String PROP_BACKGROUND_DRAWING = "backgroundDrawing";
/** The alpha of the pasive glyphs drawn on the background under the text (int 0..100%). */
public static final String PROP_BACKGROUND_GLYPH_ALPHA = "backgroundGlyphAlpha";
/** Whether the glyphs should be combined according to combination annotation types (boolean). */
public static final String PROP_COMBINE_GLYPHS = "combineGlyphs";
/** Whether the glyph icon should be drawn over the line numbers (boolean). */
public static final String PROP_GLYPHS_OVER_LINE_NUMBERS = "glyphsOverLineNumbers";
/** Whether the glyph gutter should be shown after opening editor or not (boolean).
* If this value is set to False, the gutter will automatically show after first annotation
* has been added.*/
public static final String PROP_SHOW_GLYPH_GUTTER = "showGlyphGutter";
/** Property which is fired when list of annotation types is changing. */
public static final String PROP_ANNOTATION_TYPES = "annotationTypes";
/** Storage of all properties. */
private Map properties;
/** Support for property change listeners*/
private WeakPropertyChangeSupport support;
/** Static map containing all annotation types: annotation_name <-> annotation_type */
private Map allTypes = null;
/** Flag whether the annotation types were loaded or not */
private boolean loadedTypes = false;
/** Flag whether the properties of this class were loaded or not */
private boolean loadedSettings = false;
/** Flag whether the loading of properties is in progress */
private boolean loadingInProgress = false;
/** Loader for loading annotation types from a storage*/
private Loader loader = null;
/** URL to the default glyph icon */
private static URL defaultGlyphIcon = null;
/** Single instance of this class */
private static AnnotationTypes annoTypes = null;
private AnnotationTypes() {
properties = new HashMap(5*4/3);
support = new WeakPropertyChangeSupport();
}
/** Returns instance of AnnotationTypes singleton. */
public static AnnotationTypes getTypes() {
if (annoTypes == null) {
annoTypes = new AnnotationTypes();
}
return annoTypes;
}
/** Gets Image which represents the default glyph icon. It is
* used in case the annotation type does not have its own icon. */
public static URL getDefaultGlyphURL() {
if (defaultGlyphIcon == null) {
try {
// TODO: in standalone this will not work
defaultGlyphIcon = new URL("nbresloc:/org/netbeans/editor/resources/defaultglyph.gif");
} catch (MalformedURLException ex) {
if( Boolean.getBoolean( "netbeans.debug.exceptions" ) )
ex.printStackTrace();
}
}
return defaultGlyphIcon;
}
/** Getter for BackgroundDrawing property
* @return whether the background drawing should be used or not */
public Boolean isBackgroundDrawing() {
loadSettings();
Boolean b = (Boolean)getProp(PROP_BACKGROUND_DRAWING);
if (b == null)
return Boolean.TRUE;
return b;
}
/** Setter for the BackgroundDrawing property
* @param drawing use background drawing or not */
public void setBackgroundDrawing(Boolean drawing) {
if (!isBackgroundDrawing().equals(drawing)) {
putProp(PROP_BACKGROUND_DRAWING, drawing);
firePropertyChange(PROP_BACKGROUND_DRAWING, null, null);
// force repaint of all documents
Settings.touchValue(null, null);
saveSetting(PROP_BACKGROUND_DRAWING, drawing);
}
}
/** Getter for CombineGlyphs property
* @return whether the combination annotation types are used or not */
public Boolean isCombineGlyphs() {
loadSettings();
Boolean b = (Boolean)getProp(PROP_COMBINE_GLYPHS);
if (b == null)
return Boolean.TRUE;
return b;
}
/** Setter for the CombineGlyphs property
* @param combine combine annotation types */
public void setCombineGlyphs(Boolean combine) {
if (!isCombineGlyphs().equals(combine)) {
putProp(PROP_COMBINE_GLYPHS, combine);
firePropertyChange(PROP_COMBINE_GLYPHS, null, null);
// force repaint of all documents
Settings.touchValue(null, null);
saveSetting(PROP_COMBINE_GLYPHS, combine);
}
}
/** Getter for BackgroundGlyphAlpha property
* @return percentage of alpha (0..100) */
public Integer getBackgroundGlyphAlpha() {
loadSettings();
if (getProp(PROP_BACKGROUND_GLYPH_ALPHA) == null)
return new Integer(40);
return (Integer)getProp(PROP_BACKGROUND_GLYPH_ALPHA);
}
/** Setter for the BackgroundGlyphAlpha property
* @param alpha alpha value in percentage (0..100) */
public void setBackgroundGlyphAlpha(int alpha) {
if (alpha < 0 || alpha > 100) {
return;
}
Integer i = new Integer(alpha);
putProp(PROP_BACKGROUND_GLYPH_ALPHA, i);
firePropertyChange(PROP_BACKGROUND_GLYPH_ALPHA, null, null);
// force repaint of all documents
Settings.touchValue(null, null);
saveSetting(PROP_BACKGROUND_GLYPH_ALPHA, i);
}
/** Getter for GlyphsOverLineNumbers property
* @return whether the glyph should be drawn over the line numbers */
public Boolean isGlyphsOverLineNumbers() {
loadSettings();
Boolean b = (Boolean)getProp(PROP_GLYPHS_OVER_LINE_NUMBERS);
if (b == null)
return Boolean.TRUE;
return b;
}
/** Setter for the GlyphsOverLineNumbers property
* @param over draw the glyphd over the line numbers */
public void setGlyphsOverLineNumbers(Boolean over) {
if (!isGlyphsOverLineNumbers().equals(over)) {
putProp(PROP_GLYPHS_OVER_LINE_NUMBERS, over);
firePropertyChange(PROP_GLYPHS_OVER_LINE_NUMBERS, null, null);
saveSetting(PROP_GLYPHS_OVER_LINE_NUMBERS, over);
}
}
/** Getter for ShowGlyphGutter property
* @return whether the glyph should be shown after opening editor or not */
public Boolean isShowGlyphGutter() {
loadSettings();
Boolean b = (Boolean)getProp(PROP_SHOW_GLYPH_GUTTER);
if (b == null)
return Boolean.TRUE;
return b;
}
/** Setter for the ShowGlyphGutter property
* @param gutter show gutter */
public void setShowGlyphGutter(Boolean gutter) {
if (!isShowGlyphGutter().equals(gutter)) {
putProp(PROP_SHOW_GLYPH_GUTTER, gutter);
firePropertyChange(PROP_SHOW_GLYPH_GUTTER, null, null);
saveSetting(PROP_SHOW_GLYPH_GUTTER, gutter);
}
}
/** Gets property for appropriate string value */
private Object getProp(String prop){
return properties.get(prop);
}
/** Puts property to Map */
private void putProp(Object key, Object value){
if (value == null) {
properties.remove(key);
return;
}
properties.put(key,value);
}
/** Add listeners on changes of annotation type properties
* @param l change listener*/
final public void addPropertyChangeListener(java.beans.PropertyChangeListener l) {
support.addPropertyChangeListener (l);
}
/** Remove listeners on changes of annotation type properties
* @param l change listener*/
final public void removePropertyChangeListener(java.beans.PropertyChangeListener l) {
support.removePropertyChangeListener (l);
}
/** Fire property change to registered listeners. */
final protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
support.firePropertyChange(this, propertyName, oldValue, newValue);
}
/** Initialize the map of all annotation types
* @param map map containing all annotation types */
public final void setTypes(Map map) {
if (allTypes != null) {
allTypes = map;
// loading of annotation types is done in non-AWT thread
// while listeners on this change usually needs to update UI
// that's reason why the change is fired in AWT thread
SwingUtilities.invokeLater(new FirePropertyChange());
} else {
allTypes = map;
}
}
public final void removeType(String name) {
allTypes.remove(name);
SwingUtilities.invokeLater(new FirePropertyChange());
}
/** Returns AnnotationType instance for the given name of the type
* @param name annotation type name
* @return instance describing annotation type */
public final AnnotationType getType(String name) {
loadTypes();
if (allTypes == null)
return null;
return (AnnotationType)allTypes.get(name);
}
/** Iterator of all annotation type names in the system */
public Iterator getAnnotationTypeNames() {
loadTypes();
// if following code throws NPE the problem is that
// in Editors/AnnotationTypes folder there is a XML file
// which could not be succesfully parsed. This resulted
// in that allTypes array is null
Set temp = new HashSet();
temp.addAll(allTypes.keySet());
return temp.iterator();
}
/** Gets count of all annotation type names */
public int getAnnotationTypeNamesCount() {
loadTypes();
return allTypes.keySet().size();
}
/** Gets count of all visible annotation type names */
public int getVisibleAnnotationTypeNamesCount() {
loadTypes();
Iterator i = getAnnotationTypeNames();
int count = 0;
for (; i.hasNext(); ) {
AnnotationType type = getType((String)i.next());
if (type == null)
continue;
if (type.isVisible())
count++;
}
return count;
}
/** Register loader for loading of annotation types */
public void registerLoader(Loader l) {
loader = l;
loadedTypes = false;
loadedSettings = false;
}
/** Check if the types were loaded and load them if not */
private void loadTypes() {
if (loadedTypes || loader == null)
return;
loader.loadTypes();
loadedTypes = true;
}
/** Save changes in one annotation type */
public void saveType(AnnotationType type) {
if (!loadedTypes || loader == null)
return;
loader.saveType(type);
}
/** Check if the settings were loaded and load them if not */
private void loadSettings() {
if (loadedSettings || loader == null || loadingInProgress)
return;
loadingInProgress = true;
loader.loadSettings();
loadingInProgress = false;
loadedSettings = true;
}
/** Save change of property */
public void saveSetting(String settingName, Object value) {
if (!loadedSettings || loader == null)
return;
loader.saveSetting(settingName, value);
}
/** Loader of annotation types. The loader must be registered and is called
* when the annotation types data are queried. */
public interface Loader {
/** Load all annotation types data. */
public void loadTypes();
/** Load properties of this class. */
public void loadSettings();
/** Save one annotation type. */
public void saveType(AnnotationType type);
/** Save changed property of this class. */
public void saveSetting(String settingName, Object value);
}
/** This class is defined instead of two anonymous Runnables which are needed. */
private class FirePropertyChange implements Runnable {
FirePropertyChange() {
}
public void run() {
firePropertyChange(PROP_ANNOTATION_TYPES, null, null);
}
}
}