package org.autoplot.dom; import java.awt.Color; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import org.autoplot.MouseModuleType; import org.das2.graph.DasColorBar; /** * Bean for holding Autoplot configuration options. Note there are a few AutoplotUI prefs here that shouldn't be, * like scriptVisible which indicates if the script tab is shown. * @author jbf */ public final class Options extends DomNode { public static final String PROP_COLOR = "color"; public static final String PROP_FILLCOLOR = "fillColor"; /** * try to recycle old axis settings. If the new range is near the * old range, then just use the old range. */ public static final String VALUE_AUTORANGE_TYPE_RELUCTANT="reluctant"; public Options() { logger.fine("creating new Options node"); } protected boolean scriptVisible = false; public static final String PROP_SCRIPTVISIBLE = "scriptVisible"; public boolean isScriptVisible() { return scriptVisible; } public void setScriptVisible(boolean scriptVisible) { boolean oldScriptVisible = this.scriptVisible; this.scriptVisible = scriptVisible; propertyChangeSupport.firePropertyChange(PROP_SCRIPTVISIBLE, oldScriptVisible, scriptVisible); } protected boolean logConsoleVisible = false; public static final String PROP_LOGCONSOLEVISIBLE = "logConsoleVisible"; public boolean isLogConsoleVisible() { return logConsoleVisible; } public void setLogConsoleVisible(boolean logConsoleVisible) { boolean oldLogConsoleVisible = this.logConsoleVisible; this.logConsoleVisible = logConsoleVisible; propertyChangeSupport.firePropertyChange(PROP_LOGCONSOLEVISIBLE, oldLogConsoleVisible, logConsoleVisible); } /** * true when the data tab is visible. */ public static final String PROP_DATAVISIBLE = "dataVisible"; protected boolean dataVisible = false; public boolean isDataVisible() { return dataVisible; } public void setDataVisible(boolean dataVisible) { boolean oldDataVisible = this.dataVisible; this.dataVisible = dataVisible; propertyChangeSupport.firePropertyChange(PROP_DATAVISIBLE, oldDataVisible, dataVisible); } /** * true when the layout tab is visible. */ public static final String PROP_LAYOUTVISIBLE = "layoutVisible"; protected boolean layoutVisible = false; public boolean isLayoutVisible() { return layoutVisible; } public void setLayoutVisible(boolean layoutVisible) { boolean oldLayoutVisible = this.layoutVisible; this.layoutVisible = layoutVisible; propertyChangeSupport.firePropertyChange(PROP_LAYOUTVISIBLE, oldLayoutVisible, layoutVisible); } protected boolean serverEnabled = false; public static final String PROP_SERVERENABLED = "serverEnabled"; public boolean isServerEnabled() { return serverEnabled; } public void setServerEnabled(boolean serverEnabled) { boolean oldServerEnabled = this.serverEnabled; this.serverEnabled = serverEnabled; propertyChangeSupport.firePropertyChange(PROP_SERVERENABLED, oldServerEnabled, serverEnabled); } protected String canvasFont = "sans-12"; public static final String PROP_CANVASFONT = "canvasFont"; public String getCanvasFont() { return canvasFont; } public void setCanvasFont(String canvasFont) { String oldCanvasFont = this.canvasFont; this.canvasFont = canvasFont; propertyChangeSupport.firePropertyChange(PROP_CANVASFONT, oldCanvasFont, canvasFont); } protected int width = 640; public static final String PROP_WIDTH = "width"; public int getWidth() { return width; } /** * set the initial width of the canvases in pixels * @param width */ public void setWidth(int width) { int oldWidth = this.width; this.width = width; propertyChangeSupport.firePropertyChange(PROP_WIDTH, oldWidth, width); } protected int height = 480; public static final String PROP_HEIGHT = "height"; public int getHeight() { return height; } /** * set the initial height of the canvases in pixels * @param height */ public void setHeight(int height) { int oldHeight = this.height; this.height = height; propertyChangeSupport.firePropertyChange(PROP_HEIGHT, oldHeight, height); } protected Color foreground = Color.black; public static final String PROP_FOREGROUND = "foreground"; public Color getForeground() { return foreground; } public void setForeground(Color foreground) { Color oldForeground = this.foreground; this.foreground = new Color(foreground.getRGB()); //otherwise can't serialize propertyChangeSupport.firePropertyChange(PROP_FOREGROUND, oldForeground, foreground); } protected Color background = Color.white; public static final String PROP_BACKGROUND = "background"; public Color getBackground() { return background; } public void setBackground(Color background) { Color oldBackground = this.background; this.background = new Color(background.getRGB()); //otherwise can't serialize propertyChangeSupport.firePropertyChange(PROP_BACKGROUND, oldBackground, background); } /** * Holds value of property color. */ protected Color color = Color.BLACK; /** * Getter for property color. * @return Value of property color. */ public Color getColor() { return this.color; } /** * Setter for property color. * @param color New value of property color. */ public void setColor(Color color) { Color oldColor = this.color; this.color = new Color(color.getRGB()); //otherwise can't serialize propertyChangeSupport.firePropertyChange(PROP_COLOR, oldColor, color); } /** * Holds value of property fillColor. */ protected Color fillColor = Color.DARK_GRAY; /** * Getter for property fillColor. * @return Value of property fillColor. */ public Color getFillColor() { return this.fillColor; } /** * Setter for property fillColor. * @param fillColor New value of property fillColor. */ public void setFillColor(Color fillColor) { Color oldFillColor = this.fillColor; this.fillColor = new Color(fillColor.getRGB()); //otherwise can't serialize propertyChangeSupport.firePropertyChange(PROP_FILLCOLOR, oldFillColor, fillColor); } public final static String PROP_COLORTABLE= "colortable"; protected DasColorBar.Type colortable= DasColorBar.Type.COLOR_WEDGE; public DasColorBar.Type getColortable() { return this.colortable; } public void setColortable(DasColorBar.Type colortable) { Object oldVal= this.colortable; this.colortable = colortable; propertyChangeSupport.firePropertyChange( PROP_COLORTABLE, oldVal, this.colortable ); } protected boolean oppositeAxisVisible = false; public static final String PROP_OPPOSITEAXISVISIBLE = "oppositeAxisVisible"; public boolean isOppositeAxisVisible() { return oppositeAxisVisible; } public void setOppositeAxisVisible(boolean oppositeAxisVisible) { boolean oldOppositeAxisVisible = this.oppositeAxisVisible; this.oppositeAxisVisible = oppositeAxisVisible; propertyChangeSupport.firePropertyChange(PROP_OPPOSITEAXISVISIBLE, oldOppositeAxisVisible, oppositeAxisVisible); } protected String ticklen = "0.66em"; public static final String PROP_TICKLEN = "ticklen"; public String getTicklen() { return ticklen; } public void setTicklen(String ticklen) { String oldTicklen = this.ticklen; this.ticklen = ticklen; propertyChangeSupport.firePropertyChange(PROP_TICKLEN, oldTicklen, ticklen); } protected String lineThickness = "1px"; public static final String PROP_LINE_THICKNESS = "lineThickness"; public String getLineThickness() { return lineThickness; } /** * lineThickness is the thickness of axes and ticks. * @param lineThickness */ public void setLineThickness(String lineThickness) { String oldLineThickness = this.lineThickness; this.lineThickness = lineThickness; propertyChangeSupport.firePropertyChange(PROP_LINE_THICKNESS, oldLineThickness, lineThickness); } /** * for multiline labels, the alignment, where 0 is left, 0.5 is center, and 1.0 is right. */ protected float multiLineTextAlignment = 0.5f; public static final String PROP_MULTILINETEXTALIGNMENT = "multiLineTextAlignment"; public float getMultiLineTextAlignment() { return multiLineTextAlignment; } public void setMultiLineTextAlignment(float multiLineTextAlignment) { float oldMultiLineTextAlignment = this.multiLineTextAlignment; this.multiLineTextAlignment = multiLineTextAlignment; propertyChangeSupport.firePropertyChange(PROP_MULTILINETEXTALIGNMENT, oldMultiLineTextAlignment, multiLineTextAlignment); } protected boolean flipColorbarLabel = false; public static final String PROP_FLIPCOLORBARLABEL = "flipColorbarLabel"; public boolean isFlipColorbarLabel() { return flipColorbarLabel; } public void setFlipColorbarLabel(boolean flipColorbarLabel) { boolean oldFlipColorbarLabel = this.flipColorbarLabel; this.flipColorbarLabel = flipColorbarLabel; propertyChangeSupport.firePropertyChange(PROP_FLIPCOLORBARLABEL, oldFlipColorbarLabel, flipColorbarLabel); } protected boolean specialEffects = false; /** * property specialEffects * enables/disables things like animated axes, etc. */ public static final String PROP_SPECIALEFFECTS = "specialEffects"; public boolean isSpecialEffects() { return specialEffects; } public void setSpecialEffects(boolean specialEffects) { boolean oldSpecialEffects = this.specialEffects; this.specialEffects = specialEffects; propertyChangeSupport.firePropertyChange(PROP_SPECIALEFFECTS, oldSpecialEffects, specialEffects); } /** * property drawAntiAlias * should plot symbols and lines be anti aliased? */ protected boolean drawAntiAlias = true; public static final String PROP_DRAWANTIALIAS = "drawAntiAlias"; public boolean isDrawAntiAlias() { return drawAntiAlias; } public void setDrawAntiAlias(boolean drawAntiAlias) { boolean oldDrawAntiAlias = this.drawAntiAlias; this.drawAntiAlias = drawAntiAlias; propertyChangeSupport.firePropertyChange(PROP_DRAWANTIALIAS, oldDrawAntiAlias, drawAntiAlias); } /** * property textAntiAlias * should text labels be anti aliased? */ protected boolean textAntiAlias = true; public static final String PROP_TEXTANTIALIAS = "textAntiAlias"; public boolean isTextAntiAlias() { return textAntiAlias; } public void setTextAntiAlias(boolean textAntiAlias) { boolean oldTextAntiAlias = this.textAntiAlias; this.textAntiAlias = textAntiAlias; propertyChangeSupport.firePropertyChange(PROP_TEXTANTIALIAS, oldTextAntiAlias, textAntiAlias); } protected boolean drawGrid = false; public static final String PROP_DRAWGRID = "drawGrid"; public boolean isDrawGrid() { return drawGrid; } public void setDrawGrid(boolean drawGrid) { boolean oldDrawGrid = this.drawGrid; this.drawGrid = drawGrid; propertyChangeSupport.firePropertyChange(PROP_DRAWGRID, oldDrawGrid, drawGrid); } protected boolean drawMinorGrid = false; public static final String PROP_DRAWMINORGRID = "drawMinorGrid"; public boolean isDrawMinorGrid() { return drawMinorGrid; } public void setDrawMinorGrid(boolean drawMinorGrid) { boolean oldDrawMinorGrid = this.drawMinorGrid; this.drawMinorGrid = drawMinorGrid; propertyChangeSupport.firePropertyChange(PROP_DRAWMINORGRID, oldDrawMinorGrid, drawMinorGrid); } /** * overRendering is a hint to the plots that the data outside the visible axis bounds should be rendered * so that operations like pan are more fluid. */ public static final String PROP_OVERRENDERING = "overRendering"; protected boolean overRendering = false; public boolean isOverRendering() { return overRendering; } public void setOverRendering(boolean overRendering) { boolean oldValue = this.overRendering; this.overRendering = overRendering; propertyChangeSupport.firePropertyChange(PROP_OVERRENDERING, oldValue, overRendering); } protected boolean autoranging = true; public static final String PROP_AUTORANGING = "autoranging"; public boolean isAutoranging() { return this.autoranging; } public void setAutoranging(boolean newautoranging) { boolean oldautoranging = autoranging; this.autoranging = newautoranging; propertyChangeSupport.firePropertyChange(PROP_AUTORANGING, oldautoranging, newautoranging); } /** * "" or "reluctant" */ private String autorangeType = ""; public static final String PROP_AUTORANGETYPE = "autorangeType"; public String getAutorangeType() { return autorangeType; } public void setAutorangeType( String autorangeType ) { String oldAutorangeType = this.autorangeType; this.autorangeType = autorangeType; propertyChangeSupport.firePropertyChange(PROP_AUTORANGETYPE, oldAutorangeType, autorangeType); } protected boolean autolabelling = true; public static final String PROP_AUTOLABELLING = "autolabelling"; public boolean isAutolabelling() { return autolabelling; } public void setAutolabelling(boolean autolabelling) { boolean oldAutolabelling = this.autolabelling; this.autolabelling = autolabelling; propertyChangeSupport.firePropertyChange(PROP_AUTOLABELLING, oldAutolabelling, autolabelling); } protected boolean autolayout = true; public static final String PROP_AUTOLAYOUT = "autolayout"; public boolean isAutolayout() { return autolayout; } public void setAutolayout(boolean autolayout) { boolean oldAutolayout = this.autolayout; this.autolayout = autolayout; propertyChangeSupport.firePropertyChange(PROP_AUTOLAYOUT, oldAutolayout, autolayout); } /** * Use Day of Year, rather than Y,M,D for labels. */ protected boolean dayOfYear= false; public static final String PROP_DAY_OF_YEAR = "dayOfYear"; public boolean isDayOfYear() { return dayOfYear; } public void setDayOfYear(boolean dayOfYear) { boolean old= this.dayOfYear; this.dayOfYear = dayOfYear; propertyChangeSupport.firePropertyChange(PROP_DAY_OF_YEAR, old, dayOfYear ); } /** * Use time range editor instead of Data Set Selector. */ public static final String PROP_USE_TIME_RANGE_EDITOR="useTimeRangeEditor"; protected boolean useTimeRangeEditor= false; public boolean isUseTimeRangeEditor() { return useTimeRangeEditor; } public void setUseTimeRangeEditor(boolean useTimeRangeEditor) { boolean old= this.useTimeRangeEditor; this.useTimeRangeEditor = useTimeRangeEditor; propertyChangeSupport.firePropertyChange(PROP_USE_TIME_RANGE_EDITOR, old, useTimeRangeEditor ); } /** * Use Nearest neighbor rebinning for viewing spectrograms. */ protected boolean nearestNeighbor= false; public static final String PROP_NEARESTNEIGHBOR = "nearestNeighbor"; public boolean isNearestNeighbor() { return nearestNeighbor; } public void setNearestNeighbor(boolean nearestNeighbor) { boolean old= this.nearestNeighbor; this.nearestNeighbor = nearestNeighbor; propertyChangeSupport.firePropertyChange(PROP_NEARESTNEIGHBOR, old, nearestNeighbor ); } /** * the preference for mouse module. */ protected MouseModuleType mouseModule = MouseModuleType.boxZoom; public static final String PROP_MOUSEMODULE = "mouseModule"; public MouseModuleType getMouseModule() { return mouseModule; } public void setMouseModule( MouseModuleType mouseModule) { MouseModuleType oldMouseModule = this.mouseModule; this.mouseModule = mouseModule; propertyChangeSupport.firePropertyChange(PROP_MOUSEMODULE, oldMouseModule, mouseModule); } /** * the slice preference. Should slices be shown from the rebinned pixels or from the original data */ protected boolean sliceRebinnedData = false; public static final String PROP_SLICEREBINNEDDATA = "sliceRebinnedData"; public boolean isSliceRebinnedData() { return sliceRebinnedData; } public void setSliceRebinnedData(boolean sliceRebinnedData) { boolean oldSliceRebinnedData = this.sliceRebinnedData; this.sliceRebinnedData = sliceRebinnedData; propertyChangeSupport.firePropertyChange(PROP_SLICEREBINNEDDATA, oldSliceRebinnedData, sliceRebinnedData); } /** * the tag printed on plots to indicate the date when it was created. */ protected String printingTag = ""; public static final String PROP_PRINTINGTAG = "printingTag"; public String getPrintingTag() { return printingTag; } public void setPrintingTag(String printingTag) { String oldPrintingTag= this.printingTag; this.printingTag = printingTag; propertyChangeSupport.firePropertyChange(PROP_PRINTINGTAG, oldPrintingTag, printingTag); } /** * the level of messages that are displayed when printing. */ protected Level printingLogLevel = Level.ALL; public static final String PROP_PRINTINGLOGLEVEL = "printingLogLevel"; public Level getPrintingLogLevel() { return printingLogLevel; } public void setPrintingLogLevel(Level printingLogLevel) { Level oldPrintingLogLevel = this.printingLogLevel; this.printingLogLevel = printingLogLevel; propertyChangeSupport.firePropertyChange(PROP_PRINTINGLOGLEVEL, oldPrintingLogLevel, printingLogLevel); } /** * the level of messages that are shown on the display. */ protected Level displayLogLevel = Level.ALL; public static final String PROP_DISPLAYLOGLEVEL = "displayLogLevel"; public Level getDisplayLogLevel() { return displayLogLevel; } public void setDisplayLogLevel(Level displayLogLevel) { Level oldDisplayLogLevel = this.displayLogLevel; this.displayLogLevel = displayLogLevel; propertyChangeSupport.firePropertyChange(PROP_DISPLAYLOGLEVEL, oldDisplayLogLevel, displayLogLevel); } /** * the number of seconds the message bubbles are shown. 300 or more seconds * will mean the message bubble is not erased. */ protected int logMessageTimeoutSec = 20; public static final String PROP_LOGMESSAGETIMEOUTSEC = "logMessageTimeoutSec"; public int getLogMessageTimeoutSec() { return logMessageTimeoutSec; } public void setLogMessageTimeoutSec(int logMessageTimeoutSec) { int oldLogMessageTimeoutSec = this.logMessageTimeoutSec; this.logMessageTimeoutSec = logMessageTimeoutSec; propertyChangeSupport.firePropertyChange(PROP_LOGMESSAGETIMEOUTSEC, oldLogMessageTimeoutSec, logMessageTimeoutSec); } /** * scan the data for the next available chunk, instead of stepping to next interval */ protected boolean scanEnabled = true; public static final String PROP_SCANENABLED = "scanEnabled"; public boolean isScanEnabled() { return scanEnabled; } public void setScanEnabled(boolean scanEnabled) { boolean oldScanEnabled = this.scanEnabled; this.scanEnabled = scanEnabled; propertyChangeSupport.firePropertyChange(PROP_SCANENABLED, oldScanEnabled, scanEnabled ); } /** * synchronizes any property having to do with the appearance of the * plot. This includes user preferences like the axis grid, and also performance * switches which may have a minor effect on appearance such as overrendering. * This was introduced to support createPngWalk, which should have an appearance * as close as possible to the vap. * @param n the node * @param exclude the properties to exclude. */ public void syncToAll( DomNode n,List exclude ) { this.syncTo(n,exclude); if ( !( n instanceof Options ) ) throw new IllegalArgumentException("node should be a Options"); Options that = (Options) n; if ( !exclude.contains(PROP_DRAWGRID) ) this.setDrawGrid( that.isDrawGrid() ); if ( !exclude.contains(PROP_DRAWMINORGRID) ) this.setDrawMinorGrid( that.isDrawMinorGrid() ); if ( !exclude.contains(PROP_MULTILINETEXTALIGNMENT) ) this.setMultiLineTextAlignment( that.getMultiLineTextAlignment() ); if ( !exclude.contains(PROP_OVERRENDERING) ) this.setOverRendering( that.isOverRendering() ); if ( !exclude.contains(PROP_TEXTANTIALIAS) ) this.setTextAntiAlias( that.isTextAntiAlias() ); if ( !exclude.contains(PROP_PRINTINGLOGLEVEL) ) this.setPrintingLogLevel( that.getPrintingLogLevel() ); if ( !exclude.contains(PROP_DISPLAYLOGLEVEL) ) this.setDisplayLogLevel( that.getDisplayLogLevel() ); if ( !exclude.contains(PROP_DAY_OF_YEAR) ) this.setDayOfYear( that.isDayOfYear() ); } // Note these are weird: I'm not sure if I've just forgotten items or this was intentional. // I suspect that it is intentional that a subset of the options are treated this way. Seems like // there was an issue with colors if I didn't do this. Anyway, we sync useTimeRangeEditor because // of the use case where a product is turned over to a person who doesn't want to see URIs. /** * synchronizes to another node, except unlike other nodes where this is * thorough by default, this is the minimal set of properties that * will provide a usable display. These include the colors and the fonts, * and the timeRange editor mode, flip colorbar label, the ticklen, and last * scanEnabled. * @see https://sourceforge.net/p/autoplot/bugs/2175/ * @param n the node * @param exclude the properties to exclude. */ @Override public void syncTo( DomNode n,List exclude ) { super.syncTo(n,exclude); if ( !( n instanceof Options ) ) throw new IllegalArgumentException("node should be a Options"); Options that = (Options) n; if ( !exclude.contains(PROP_BACKGROUND) ) this.setBackground(that.getBackground()); if ( !exclude.contains(PROP_FOREGROUND) ) this.setForeground(that.getForeground()); if ( !exclude.contains(PROP_COLOR) )this.setColor(that.getColor()); if ( !exclude.contains(PROP_FILLCOLOR) )this.setFillColor(that.getFillColor()); if ( !exclude.contains(PROP_COLORTABLE) )this.setColortable(that.getColortable()); if ( !exclude.contains(PROP_CANVASFONT) )this.setCanvasFont(that.getCanvasFont()); if ( !exclude.contains(PROP_USE_TIME_RANGE_EDITOR) ) this.setUseTimeRangeEditor(that.isUseTimeRangeEditor()); if ( !exclude.contains(PROP_FLIPCOLORBARLABEL) ) this.setFlipColorbarLabel(that.isFlipColorbarLabel()); if ( !exclude.contains(PROP_TICKLEN) ) this.setTicklen( that.getTicklen() ); if ( !exclude.contains(PROP_OPPOSITEAXISVISIBLE ) ) this.setOppositeAxisVisible( that.isOppositeAxisVisible() ); if ( !exclude.contains(PROP_LINE_THICKNESS) ) this.setLineThickness( that.getLineThickness() ); if ( !exclude.contains(PROP_SCANENABLED) ) this.setScanEnabled( that.isScanEnabled() ); } @Override public void syncTo(DomNode n) { this.syncTo(n, new ArrayList() ); } @Override public List diffs(DomNode node) { if ( !( node instanceof Options ) ) throw new IllegalArgumentException("node should be a Options"); Options that = (Options) node; List result = super.diffs(node); boolean b; b = that.getBackground().equals(this.getBackground()); if (!b) result.add(new PropertyChangeDiff(PROP_BACKGROUND, that.getBackground(), this.getBackground())); b = that.getForeground().equals(this.getForeground()); if (!b) result.add(new PropertyChangeDiff(PROP_FOREGROUND, that.getForeground(), this.getForeground())); b = that.getColor().equals(this.getColor()); if (!b) result.add(new PropertyChangeDiff(PROP_COLOR, that.getColor(), this.getColor())); b = that.getFillColor().equals(this.getFillColor()); if (!b) result.add(new PropertyChangeDiff(PROP_FILLCOLOR, that.getFillColor(), this.getFillColor())); b = that.getColortable().equals(this.getColortable()); if (!b) result.add(new PropertyChangeDiff(PROP_COLORTABLE, that.getColortable(), this.getColortable())); b = that.getCanvasFont().equals(this.getCanvasFont()); if (!b) result.add(new PropertyChangeDiff(PROP_CANVASFONT, that.getCanvasFont(), this.getCanvasFont())); b = that.isUseTimeRangeEditor() == this.isUseTimeRangeEditor(); if (!b) result.add(new PropertyChangeDiff(PROP_USE_TIME_RANGE_EDITOR, that.isUseTimeRangeEditor(), this.isUseTimeRangeEditor())); b = that.isFlipColorbarLabel()==this.isFlipColorbarLabel(); if (!b) result.add(new PropertyChangeDiff(PROP_FLIPCOLORBARLABEL, that.isFlipColorbarLabel(), this.isFlipColorbarLabel() )); b = that.getTicklen().equals(this.getTicklen() ); if (!b) result.add(new PropertyChangeDiff(PROP_TICKLEN, that.getTicklen(), this.getTicklen())); b = that.getLineThickness().equals(this.getLineThickness() ); if (!b) result.add(new PropertyChangeDiff(PROP_OPPOSITEAXISVISIBLE, that.isOppositeAxisVisible(), this.isOppositeAxisVisible() )); b = that.getLineThickness().equals(this.getLineThickness() ); if (!b) result.add(new PropertyChangeDiff(PROP_LINE_THICKNESS, that.getLineThickness(), this.getLineThickness())); b = that.isScanEnabled()== this.isScanEnabled(); if (!b) result.add(new PropertyChangeDiff(PROP_SCANENABLED, that.isScanEnabled(), this.isScanEnabled() )); return result; } private OptionsPrefsController controller=null; public OptionsPrefsController getController() { return this.controller; } /** * set the controller for this node. This can only be called once. * @param controller */ protected void setController( OptionsPrefsController controller ) { if ( this.controller!=null ) { throw new IllegalArgumentException("controller has already been set"); } this.controller= controller; } @Override public DomNode copy() { Options that= new Options(); that.setBackground( this.getBackground() ); that.setForeground( this.getForeground() ); that.setColor( this.getColor() ); that.setFillColor( this.getFillColor() ); that.setColortable( this.getColortable() ); that.setCanvasFont( this.getCanvasFont() ); that.setUseTimeRangeEditor( this.isUseTimeRangeEditor() ); that.setFlipColorbarLabel( this.isFlipColorbarLabel() ); that.setTicklen( this.getTicklen() ); that.setOppositeAxisVisible( this.isOppositeAxisVisible() ); that.setLineThickness( this.getLineThickness() ); that.setScanEnabled( this.isScanEnabled() ); return that; } }