package jas.hist; import jas.plot.Axis; import jas.plot.AxisType; import jas.plot.DateAxis; import jas.plot.DoubleAxis; import jas.plot.EditableLabel; import jas.plot.StringAxis; import java.awt.Component; import java.awt.event.ActionEvent; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.Date; import javax.swing.JCheckBoxMenuItem; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; // This has to be public so that the properties dialog can use reflection on it??? // (otherwise get IllegalAccessException) public final class ManagedAxis extends Axis implements JASHistAxis, Externalizable { ManagedAxis(int orientation) { super(orientation); this.dataManager = null; this.binned = false; } ManagedAxis(DataManager dm, int orientation, boolean binned) { super(orientation); this.dataManager = dm; this.binned = binned; } // for deserialization/deserialization only do not call public ManagedAxis() { } void setDataManager(DataManager dm, boolean binned) { this.dataManager = dm; this.binned = binned; } void setDataManager(DataManager dm, boolean binned, AxisType t) { this.dataManager = dm; this.binned = binned; setType(t); } public void writeExternal(ObjectOutput out) throws IOException { out.writeInt(bins); out.writeBoolean(rangeAutomatic); if (!rangeAutomatic) { out.writeDouble(getMin()); out.writeDouble(getMax()); } out.writeBoolean(allowSuppressedZero); out.writeBoolean(fixed); out.writeBoolean(binned); out.writeInt(position); final AxisType type = getType(); out.writeInt(getAxisOrientation()); out.writeBoolean(getOnLeftSide()); out.writeObject(type); out.writeObject(dataManager); // THINGS THAT SHOULD BE INCLUDED LATER (here and in readObject): // - axis colors (i.e., minorTickMarkColor, axisLineColor, textColor, etc.) // (no point in doing this one now because they are always black) // - whether is visible // (no point in doing this now because can't change whether is visible) } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { bins = in.readInt(); rangeAutomatic = in.readBoolean(); if (!rangeAutomatic) { setMin(in.readDouble()); setMax(in.readDouble()); } else attentionNeeded(); allowSuppressedZero = in.readBoolean(); fixed = in.readBoolean(); binned = in.readBoolean(); position = in.readInt(); setAxisOrientation(in.readInt()); setOnLeftSide(in.readBoolean()); setType((AxisType) in.readObject()); dataManager = (DataManager) in.readObject(); } public boolean isVertical() { return getAxisOrientation() == Axis.VERTICAL; } public boolean isLogarithmic() { AxisType type = getType(); if (type instanceof DoubleAxis) { return ((DoubleAxis) type).isLogarithmic(); } return false; } public void setLogarithmic(boolean value) { AxisType type = getType(); if (type instanceof DoubleAxis) { ((DoubleAxis) type).setLogarithmic(value); attentionNeeded(); } } public boolean isShowing() { // TODO: Not supported yet by Axis return true; } public void setShowing(boolean value) { // TODO: Not supported yet by Axis } /** * @return the EditableLabel itself, not just the text * @see #getLabel() */ public EditableLabel getLabelObject() { if (dataManager == null) return null; EditableLabel label = dataManager.getLabel(this); if (label == null) return null; return label; } /** * @return the label text * @see #getLabelObject() */ public String getLabel() { EditableLabel label = dataManager.getLabel(this); return label==null ? "" : label.getText(); } /** * sets the label to be the EditableLabel passed in * @param p_newLabel the new label */ public void setLabelObject(EditableLabel p_newLabel) { dataManager.setLabel(this, p_newLabel); } /** * sets the label text, creating the label if needed * @param s the new text of the label */ public void setLabel(String s) { EditableLabel label = dataManager.getLabel(this); if (label == null) { label = new EditableLabel(s,"Axis Label",JLabel.LEFT); dataManager.setLabel(this, label); } else label.setText(s); revalidate(); // Attract the attention of the layout manager! } public double getMin() { // getParent().validate(); AxisType type = getType(); if (type instanceof DoubleAxis) { return ((DoubleAxis) type).getPlotMin(); } else if (type instanceof DateAxis) { return ((DateAxis) type).getAxisMin()/1000.; } throw new RuntimeException("getMin undefined for this axis type"); } public void setMin(double d) { AxisType type = getType(); if (type instanceof DoubleAxis) { rangeAutomatic = false; ((DoubleAxis) type).setMin(d); attentionNeeded(); } else if (type instanceof DateAxis) { rangeAutomatic = false; ((DateAxis) type).setMin((long) (d*1000)); attentionNeeded(); } else throw new RuntimeException("setMin undefined for this axis type"); } public double getMax() { AxisType type = getType(); if (type instanceof DoubleAxis) { return ((DoubleAxis) type).getPlotMax(); } else if (type instanceof DateAxis) { return ((DateAxis) type).getAxisMax()/1000.; } throw new RuntimeException("getMax undefined for this axis type"); } public void setMax(double d) { AxisType type = getType(); if (type instanceof DoubleAxis) { rangeAutomatic = false; ((DoubleAxis) type).setMax(d); attentionNeeded(); } else if (type instanceof DateAxis) { rangeAutomatic = false; ((DateAxis) type).setMax((long) (d*1000)); invalidate(); attentionNeeded(); } else throw new RuntimeException("setMax undefined for this axis type"); } public void setRange(double min, double max) { setMin(min); setMax(max); } public Object getMinObject() { if (getAxisType() == DATE) return new Date((long) (getMin()*1000)); else return new Double(getMin()); } public Object getMaxObject() { if (getAxisType() == DATE) return new Date((long) (getMax()*1000)); else return new Double(getMax()); } public void setMinObject(Object value) { try { double min; if (getAxisType() == DATE) min = ((Date) value).getTime()/1000; else min = ((Double) value).doubleValue(); setMin(min); // attentionNeeded(); // invalidate(); } catch (ClassCastException x) { throw new IllegalArgumentException("Argument to setMinObject is of wrong type"); } } public void setMaxObject(Object value) { try { double max; if (getAxisType() == DATE) max = ((Date) value).getTime()/1000; else max = ((Double) value).doubleValue(); setMax(max); // attentionNeeded(); // invalidate(); } catch (ClassCastException x) { throw new IllegalArgumentException("Argument to setMaxObject is of wrong type"); } } public boolean getRangeAutomatic() { return rangeAutomatic; } public void setRangeAutomatic(boolean b) { rangeAutomatic = b; attentionNeeded(); } public boolean getAllowSuppressedZero() { return allowSuppressedZero; } public void setAllowSuppressedZero(boolean b) { allowSuppressedZero = b; attentionNeeded(); } public boolean isBinned() { return binned; } public void setBinned(boolean value) { binned = value; } public boolean isFixed() { return fixed; } public void setFixed(boolean value) { fixed = value; } public int getBins() { return bins; } public void setBins(int value) { bins = value; attentionNeeded(); } public double getBinWidth() { if (!binned) return 0; double range = getMax() - getMin(); return range/bins; } public void setBinWidth(double value) { double range = getMax() - getMin(); bins = (int) Math.max(1,range/value); attentionNeeded(); } public boolean getShowOverflows() { return showOverflows; } public void setShowOverflows(boolean value) { showOverflows = value; attentionNeeded(); } public int getLabelPosition() { return 0; } public void setLabelPosition(int pos) { //final int positions[] = //{ // JCLegend.EAST, JCLegend.WEST, JCLegend.NORTHEAST, // JCLegend.SOUTHEAST, JCLegend.NORTHWEST, JCLegend.SOUTHEAST //}; //JCAxisTitle t = yAxis.getTitle(); //if (t != null) t.setPlacement(positions[pos]); } public int getPosition() { return position; } public void setPosition(int value) { //if (!isVertical()) throw new IllegalArgumentException("Cannot set position of X axis"); //if (value == LEFT ) axis.setPlacement(JCAxis.MIN); //else if (value == RIGHT) axis.setPlacement(JCAxis.MAX); //else throw new IllegalArgumentException("Illegal argument to setPosition"); position = value; } public int getAxisType() { AxisType type = getType(); if (type instanceof DateAxis) return DATE; if (type instanceof StringAxis) return STRING; return DOUBLE; } public void setAxisType(int value) { if (value != getAxisType()) { if (value == DATE) { setType(new DateAxis()); } else if (value == STRING) { setType(new StringAxis()); } else { setType(new DoubleAxis()); } } } /** * attention needed is called by ManagedAxis when it wants to attract the * attention of the DataManager, e.g. after the user updates some property. */ private void attentionNeeded() { boolean requestedAttention = needsAttention; needsAttention = true; if (!requestedAttention && dataManager != null) dataManager.invalidate(); } /** * set attention needed can be called by the DataManager to remind itself * it needs to work on the axis */ void setAttentionNeeded() { needsAttention = true; } /** * called by the DataManager when it has updated itself to take into account * changes to the axis. Resets the needsAttention flag. */ void payingAttention() { needsAttention = false; } /** * return true if attnetion is needed */ boolean needsAttention() { return needsAttention; } public void modifyPopupMenu(final JPopupMenu menu, final Component source) { if (dataManager != null && !(dataManager instanceof DefaultDataManager)) { super.modifyPopupMenu(menu,source); if (getAxisType() != JASHistAxis.STRING) // BUG: should have a better way of testing whether these items are appropriate { if (getAxisType() != JASHistAxis.DATE) // BUG: should have a better way of testing whether this item is appropriate { menu.add(new JCheckBoxMenuItem("Logarithmic", isLogarithmic()) { final protected void fireActionPerformed(final ActionEvent e) { setLogarithmic(isSelected()); } }); } menu.add(new JCheckBoxMenuItem("Range Automatic", getRangeAutomatic()) { final protected void fireActionPerformed(final ActionEvent e) { setRangeAutomatic(isSelected()); } }); if (getAxisType() != JASHistAxis.DATE) // BUG: should have a better way of testing whether this item is appropriate { final JCheckBoxMenuItem suppZero = new JCheckBoxMenuItem("Suppressed Zeros", getAllowSuppressedZero()) { final protected void fireActionPerformed(final ActionEvent e) { setAllowSuppressedZero(isSelected()); } }; menu.add(suppZero); suppZero.setEnabled(getRangeAutomatic()); } } menu.add(new JMenuItem("Axis Properties...") { final protected void fireActionPerformed(final ActionEvent e) { dataManager.getPlot().showProperties( getAxisOrientation() == Axis.VERTICAL ? (getOnLeftSide() ? JASHistPropertyDialog.Y_AXIS_LEFT : JASHistPropertyDialog.Y_AXIS_RIGHT) : JASHistPropertyDialog.X_AXIS); } }); } } private int bins; private boolean rangeAutomatic = true; private boolean allowSuppressedZero = true; private boolean showOverflows = false; private boolean needsAttention = true; private boolean fixed = false; private boolean binned; private int position; private DataManager dataManager; }