/*
* Copyright 2011 Uwe Krueger.
*
* 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 com.mandelsoft.mand.tool;
import com.mandelsoft.mand.util.MandelColormapCache;
import com.mandelsoft.util.upd.UpdatableObject;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ButtonGroup;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.Timer;
import javax.swing.border.BevelBorder;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListDataEvent;
import com.mandelsoft.io.FileAbstractFile;
import com.mandelsoft.mand.MandelData;
import com.mandelsoft.io.AbstractFile;
import com.mandelsoft.mand.Environment;
import com.mandelsoft.mand.IllegalConfigurationException;
import com.mandelsoft.mand.MandelInfo;
import com.mandelsoft.mand.MandelName;
import com.mandelsoft.mand.QualifiedMandelName;
import com.mandelsoft.mand.image.ImageListener;
import com.mandelsoft.mand.image.MandelImage;
import com.mandelsoft.mand.tool.MandelAreaCreationDialog.MandelAreaEvent;
import com.mandelsoft.mand.tool.MandelAreaCreationDialog.MandelAreaListener;
import com.mandelsoft.mand.tool.cm.ColormapDialog;
import com.mandelsoft.mand.cm.ColormapModel;
import com.mandelsoft.mand.tool.mapper.MapperModel;
import com.mandelsoft.mand.util.MandArith;
import com.mandelsoft.mand.util.MandUtils;
import com.mandelsoft.swing.BufferedComponent;
import com.mandelsoft.swing.BufferedComponent.RectEvent;
import com.mandelsoft.swing.BufferedComponent.RectEventListener;
import com.mandelsoft.swing.BufferedComponent.RectModifiedEvent;
import com.mandelsoft.swing.BufferedComponent.RectModifiedEventListener;
import com.mandelsoft.swing.BufferedComponent.RectangleSelector;
import com.mandelsoft.swing.BufferedComponent.VisibleRect;
import com.mandelsoft.swing.ProportionProvider;
import com.mandelsoft.swing.WindowControlAction;
import com.mandelsoft.util.ChangeEvent;
import com.mandelsoft.mand.MandelRaster;
import com.mandelsoft.mand.Settings;
import com.mandelsoft.mand.cm.Colormap;
import com.mandelsoft.mand.cm.ColormapSource;
import com.mandelsoft.mand.image.MandelAreaImage;
import com.mandelsoft.mand.scan.MandelFolder;
import com.mandelsoft.mand.scan.MandelHandle;
import com.mandelsoft.mand.scan.MandelScanner;
import com.mandelsoft.mand.scan.MandelScannerListener;
import com.mandelsoft.mand.scan.MandelScannerListenerAdapter;
import com.mandelsoft.mand.tool.slideshow.DefaultSlideShowModel;
import com.mandelsoft.mand.tool.slideshow.SlideShowDestination;
import com.mandelsoft.mand.tool.slideshow.SlideShowModel;
import com.mandelsoft.mand.tool.slideshow.SlideShowSourceAdapter;
import com.mandelsoft.mand.util.ArrayMandelList;
import com.mandelsoft.mand.util.CachedUpstreamColormapSource;
import com.mandelsoft.mand.util.MandelList;
import com.mandelsoft.mand.util.MemoryMandelListFolderTree;
import com.mandelsoft.swing.AbstractListDataListener;
import com.mandelsoft.swing.BooleanAttribute;
import com.mandelsoft.swing.BufferedComponent.ProportionalRectangleSelector;
import com.mandelsoft.swing.BufferedComponent.RectPointEvent;
import com.mandelsoft.swing.BufferedComponent.RectangleActionEvent;
import com.mandelsoft.swing.BufferedComponent.VisibleRectFilter;
import com.mandelsoft.swing.BufferedFrame;
import com.mandelsoft.swing.ChangeListenerSupport;
import com.mandelsoft.swing.Corner;
import com.mandelsoft.swing.Dimensions;
import com.mandelsoft.swing.GBC;
import com.mandelsoft.swing.GBCPanel;
import com.mandelsoft.swing.OptionalAction;
import com.mandelsoft.swing.RectanglePoint;
import com.mandelsoft.swing.RenderedComponent;
import com.mandelsoft.swing.RenewStateListener;
import com.mandelsoft.swing.ScaleAdapter;
import com.mandelsoft.swing.ScaleEvent;
import com.mandelsoft.swing.UpdatableJMenu;
import com.mandelsoft.swing.UpdatableJMenuItem;
import com.mandelsoft.swing.UpdatableJPopupMenu;
import com.mandelsoft.swing.UpdatableAction;
import com.mandelsoft.util.upd.UpdateSource;
import com.mandelsoft.util.upd.UpdateSourceSupport;
import com.mandelsoft.util.Utils;
import com.mandelsoft.util.upd.BooleanUpdateCondition;
import com.mandelsoft.util.upd.UpdateContext;
import com.mandelsoft.util.upd.UpdateReason;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.util.HashSet;
import java.util.ListIterator;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JTextField;
import javax.swing.ListModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ListDataListener;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;
/**
*
* @author Uwe Krueger
*/
public class MandelImagePanel extends GBCPanel
implements MandelWindowAccess,
UpdateSource {
static public boolean debug=false;
static public boolean debugHL=false;
static public boolean iterPathActive=false;
static private BasicStroke dashed=new BasicStroke(1, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND, 10, new float[]{4, 4}, 0);
static private BasicStroke favorite=new BasicStroke(2, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND);
/////////////////////////////////////////////////////////////////////////
// Area Selection Model
/////////////////////////////////////////////////////////////////////////
private class AreaSelectionModel extends DefaultComboBoxModel {
private class Selector {
private String name;
private BufferedComponent.RectangleSelector sel;
Selector(String name, BufferedComponent.RectangleSelector sel)
{
this.name=name;
this.sel=sel;
sel.setStroke(dashed);
}
public String getName()
{
return name;
}
public RectangleSelector getSelector()
{
return sel;
}
@Override
public String toString()
{
return getName();
}
}
public AreaSelectionModel()
{
addElement(new Selector("Centered Proportional",
new BufferedComponent.CenteredProportionalRectangleSelector(imagepropprov)));
addElement(new Selector("Proportional",
new BufferedComponent.ProportionalRectangleSelector(imagepropprov)));
setSelectedItem(null);
this.addListDataListener(new AbstractListDataListener() {
@Override
public void contentsChanged(ListDataEvent e)
{
if (debug) System.out.println("select SELECTOR "+getSelectedItem());
if (!isReadonly()) {
buffer.setRectangleSelector(getRectangleSelector());
setProportionProvider(proportion.getProportionProvider());
}
}
});
}
public RectangleSelector getRectangleSelector()
{
if (getSelectedItem()==null) return null;
return ((Selector)getSelectedItem()).getSelector();
}
public void setProportionProvider(ProportionProvider d)
{
if (d!=null) {
RectangleSelector s=getRectangleSelector();
if (s instanceof ProportionalRectangleSelector) {
ProportionalRectangleSelector p=(ProportionalRectangleSelector)s;
p.setProportionProvider(d);
}
}
}
}
/////////////////////////////////////////////////////////////////////////
// Proportion Selection Model
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
// Image Proportion
private class AreaProportionProvider implements ProportionProvider {
public double getProportion()
{
MandelInfo info=getMandelInfo();
//double d=MandUtils.div(info.getDX(),info.getDY()).doubleValue();
double d=MandUtils.div(info.getDY(), info.getDX()).doubleValue()*
info.getRX()/info.getRY()*info.getRX()/info.getRY();
if (debug) System.out.println("proportion is "+d);
return d;
}
}
/////////////////////////////////////////////////////////////////////////
// Creation Dialog Proportion
private class CreationDialogProportionProvider extends AreaProportionProvider {
@Override
public double getProportion()
{
double d=0;
if (create!=null && create.isVisible()) {
MandelInfo info=create.getInfo();
if (info!=null) {
d=MandUtils.getProportion(info.getRX(),info.getRY(), getMandelInfo());
}
}
if (d==0.0) d=super.getProportion();
return d;
}
}
/////////////////////////////////////////////////////////////////////////
// attrributes
private AreaProportionProvider imagepropprov=new AreaProportionProvider();
private AreaProportionProvider creatpropprov=new CreationDialogProportionProvider();
/////////////////////////////////////////////////////////////////////////
// Selection Model
public class ProportionSelectionModel extends DefaultComboBoxModel {
private class Proportion {
private String name;
private ProportionProvider provider;
Proportion(String name, ProportionProvider provider)
{
this.name=name;
this.provider=provider;
}
public String getName()
{
return name;
}
public ProportionProvider getProportionProvider()
{
return provider;
}
@Override
public String toString()
{
return getName();
}
}
public ProportionSelectionModel()
{
addElement(new Proportion("Image Proportion",
imagepropprov));
addElement(new Proportion("3:2",
new ProportionProvider.Proportion(3.0/2.0)));
addElement(new Proportion("10:7",
new ProportionProvider.Proportion(10.0/7.0)));
addElement(new Proportion("4:3",
new ProportionProvider.Proportion(4.0/3.0)));
addElement(new Proportion("1:1",
new ProportionProvider.Proportion(1.0/1.0)));
addElement(new Proportion("Creation Dialog Proportion",
creatpropprov));
setSelectedItem(null);
this.addListDataListener(new AbstractListDataListener() {
@Override
public void contentsChanged(ListDataEvent e)
{
if (debug) System.out.println("select PROPORTION "+getSelectedItem());
if (!isReadonly()) {
selector.setProportionProvider(getProportionProvider());
}
}
});
}
public ProportionProvider getProportionProvider()
{
if (getSelectedItem()==null) return null;
return ((Proportion)getSelectedItem()).getProportionProvider();
}
}
////////////////////////////////////////////////////////////////////////////
// Tooltip handling
////////////////////////////////////////////////////////////////////////////
/////////////////
// Pixel Info
public class PixelInfoToolTipHandler implements
BufferedComponent.ToolTipHandler {
public String getToolTipText(MouseEvent event)
{
MandelRaster r;
Point p=new Point((int)(event.getY()/filterscale),
(int)(event.getX()/filterscale));
r=image.getRasterData();
int d=(r.getRaster())[(int)p.getX()][(int)p.getY()];
return "("+event.getX()+","+event.getY()+"): "+d;
}
}
/////////////////
// Sub Area Names
public class SubAreaToolTipHandler implements BufferedComponent.ToolTipHandler {
private MandelName last;
private String text;
public String getToolTipText(MouseEvent event)
{
String sub=findSubName(event.getPoint());
if (sub!=null) {
MandelName mn=QualifiedMandelName.create(sub).getMandelName();
text=sub;
if (mn!=null && !mn.equals(last)) {
int ic=count(mn,getEnvironment().getImageDataScanner());
if (getEnvironment().isReadonly()) {
if (ic==1) text=sub+" ("+ic+" sub area)";
else text=sub+" ("+ic+" sub areas)";
}
else {
int ir=count(mn,getEnvironment().getInfoScanner());
if (ic==1) text=sub+" ("+ic+" sub area, "+ir+" pending)";
else text=sub+" ("+ic+" sub areas, "+ir+" pending)";
}
}
}
else {
last=null;
text=null;
}
return text;
}
}
private int count(MandelName mn, MandelScanner s)
{
int cnt=0;
for (MandelName n:s.getMandelNames()) {
if (mn.isHigher(n)) cnt++;
}
return cnt;
}
/////////////////////////////////////////////////////////////////////////
// Tool Tip Selection Model
public class ToolTipSelectionModel extends DefaultComboBoxModel {
//////////////////////////////
// ToolTip Flavor
private class ToolTipFlavor {
private String name;
private String id;
private BufferedComponent.ToolTipHandler handler;
ToolTipFlavor(String id, String name,
BufferedComponent.ToolTipHandler handler)
{
this.id=id;
this.name=name;
this.handler=handler;
}
public String getName()
{
return name;
}
public String getId()
{
return id;
}
public BufferedComponent.ToolTipHandler getToolTipHandler()
{
return handler;
}
@Override
public String toString()
{
return getName();
}
}
//////////////////////////////
// ToolTip handler Wrapper
private class MandelToolTipHandlerWrapper implements
BufferedComponent.ToolTipHandler {
private BufferedComponent.ToolTipHandler actual;
public void setToolTipHandler(BufferedComponent.ToolTipHandler h)
{
actual=h;
}
public String getToolTipText(MouseEvent event)
{
return actual==null?null:actual.getToolTipText(event);
}
}
//////////////////////////////
private MandelToolTipHandlerWrapper wrapper;
public ToolTipSelectionModel()
{ ToolTipFlavor def;
wrapper = new MandelToolTipHandlerWrapper();
this.addListDataListener(new AbstractListDataListener() {
@Override
public void contentsChanged(ListDataEvent e)
{
if (debug) System.out.println("select ToolTip "+getSelectedItem());
wrapper.setToolTipHandler(getActualToolTipHandler());
}
});
addElement(def=new ToolTipFlavor("PIXELINFO", "Pixel Info",
new PixelInfoToolTipHandler()));
addElement(new ToolTipFlavor("SUBAREANAME", "SubArea Name",
new SubAreaToolTipHandler()));
// setSelectedItem(def);
// wrapper.setToolTipHandler(def.getToolTipHandler());
}
private BufferedComponent.ToolTipHandler getActualToolTipHandler()
{
if (getSelectedItem()==null) return null;
return ((ToolTipFlavor)getSelectedItem()).getToolTipHandler();
}
public String getSelectedItemId()
{
if (getSelectedItem()==null) return null;
return ((ToolTipFlavor)getSelectedItem()).getId();
}
public boolean setSelectedItemId(String id)
{
int size=getSize();
for (int i=0; i<size; i++) {
ToolTipFlavor item=(ToolTipFlavor)getElementAt(i);
if (item.getId().equals(id)) {
System.out.println("select tool tip mode "+id);
setSelectedItem(item);
return true;
}
}
return false;
}
public BufferedComponent.ToolTipHandler getToolTipHandler()
{
return wrapper;
}
}
/////////////////////////////////////////////////////////////////////////
// Direct List Modification
public class ListModifierMenu extends JMenu {
private MandelListModel model;
public ListModifierMenu(String name, MandelListModel model)
{
super(name);
this.model=model;
if (isValid()) {
addItems();
}
}
public void cleanupModel()
{
}
public MandelListModel getMandelModel()
{
return model;
}
protected void addItems()
{
if ((model)!=null) {
if (model.isModifiable()) {
MandelListModel m=getMandelModel();
JMenuItem it=new JMenuItem(new AddListEntryAction(m));
add(it);
it=new JMenuItem(new RemoveListEntryAction(m));
add(it);
if (m instanceof MandelListTableModel) {
add(new OpenListShortcutAction(
(MandelListTableModel)m,getText()));
}
}
}
}
@Override
public boolean isValid()
{
return model!=null && model.isModifiable();
}
}
///////////////////////////////////////////
public class DynListModifierMenu extends ListModifierMenu {
public DynListModifierMenu(String name, MandelListModel model)
{
super(name,model);
}
@Override
protected void addItems()
{
if (!isValid()) return;
super.addItems();
add(new RemoveListShortcutAction(getMandelModel()));
}
}
///////////////////////////////////////////
public class LoadableListModifier extends ListModifierMenu {
private MandelListModelMenu load;
public LoadableListModifier(String name, MandelListTableModel model)
{ super(name,model);
}
@Override
public void cleanupModel()
{
if (load!=null) load.setMandelListModel(null);
}
@Override
protected void addItems()
{
if (!isValid()) return;
super.addItems();
load=new MandelListModelMenu(MandelImagePanel.this,getMandelModel());
add(load);
}
}
///////////////////////////////////////////
public class EnvListener implements LinkListener {
private void update(MandelName n)
{
if (getMandelName().equals(n)) updateLinks();
}
public void linkAdded(MandelName src, MandelName dst)
{
update(src);
update(dst);
}
public void linkRemoved(MandelName src, MandelName dst)
{
update(src);
update(dst);
}
}
///////////////////////////////////////////
public class Mark extends ExplicitHighlight {
private DefaultMandelListListModel previous;
public Mark(Environment env)
{
super("marked",true);
previous=new DefaultMandelListListModel(new ArrayMandelList(),
env.getAllScanner());
previous.setModifiable(true);
previous.setDuplicates(true);
}
@Override
public void setQualifiedName(QualifiedMandelName name)
{
QualifiedMandelName mn=name.getBaseName();
int size=previous.getSize();
super.setQualifiedName(name);
if (size==0 || !previous.getElementAt(0).equals(mn)) {
previous.add(0, mn);
if (size>=20) {
previous.remove(20);
}
}
}
}
private class ConfiguredBooleanAttribute extends BooleanAttribute {
public ConfiguredBooleanAttribute(JComponent component, String property,
String label, boolean b)
{ super(component,property,label,b);
configure();
}
public ConfiguredBooleanAttribute(JComponent component, String property,
boolean b)
{ super(component,property,b);
configure();
}
public ConfiguredBooleanAttribute(JComponent component, String property,
String label)
{ super(component,property,label);
configure();
}
public ConfiguredBooleanAttribute(JComponent component, String property)
{ super(component,property);
configure();
}
private void configure()
{
setState(getEnvironment().getToolSwitch("config."+getPropertyName(),isSet()));
}
}
/////////////////////////////////////////////////////////////////////////
// MandelImagePanel
/////////////////////////////////////////////////////////////////////////
private Buffer buffer;
private double filterscale=1.0;
private double maxx=0;
private ToolEnvironment env;
private boolean showSubMode;
private ChangeListenerSupport listeners=new ChangeListenerSupport();
private ExplicitHighlight lastname;
private Mark marked;
private ExplicitHighlights explicitHighlights;
private QualifiedMandelName name;
private MandelListMenu subareas;
private MandelListModelMenu gotolinks;
private AbstractMandelListModelMenu showlinks;
private AbstractMandelListModelMenu removelinks;
private JMenu linkhist;
private JPopupMenu linkhistpopup;
private LinkListener linkListener;
private MandelListModel keyareas;
private MandelListModelMenu keyareasmenu;
private MandelListModelMenu keyareaspopupmenu;
private MandelImage image;
private MapperModel mappermodel;
private ColormapModel colormapmodel;
private Colormap defcolormap;
private Environment.FileInfo fileinfo;
private History history;
private MandelSubAreaCreationDialog create;
private ColormapDialog colormapDialog;
private ImageControl imageDialog;
private MandelListsDialog listsDialog;
private JuliaDialog juliaDialog;
private IterationPathDialog iterDialog;
private ImageListener imageListener;
private List<ListModifierMenu> listModifiers;
private Action parentAction;
private Action areaUpAction;
private Action forkAction;
private Action showSubAction;
private Action hideSubAction;
private Action refreshSubAction;
private Action showColormapAction;
private Action showMetaAction;
private Action variationAction;
private Action linksGaleryAction;
private Action keyareasGaleryAction;
private Action zoomGaleryAction;
private Action cloneAction;
private Action gotoAction;
private Action saveAction;
private Action areaCMSaveAction;
private Action areaCMDeleteAction;
private Action areaCMAction;
private Action showListsControlAction;
private Action showJuliaAction;
private Action showIterationPathAction;
private Action areaDownAction;
private int highlight_mode=H_FAVORITES;
private static final int H_NONE=0;
private static final int H_FAVORITES=1;
private static final int H_UNSEEN=2;
private static final int H_LAST=3;
private JScrollPane scrollpane;
private MandelAreaImage initialImage;
private boolean partial;
private SlideShowModel slideshowmodel;
private AreaSelectionModel selector;
private ProportionSelectionModel proportion;
private ToolTipSelectionModel tooltip;
private BooleanAttribute parentcolormap;
private BooleanAttribute fullareanames;
private BooleanAttribute automark_parent;
private BooleanAttribute automark_keyarea;
private BooleanAttribute automark_fork;
private BooleanAttribute autoshow_info;
private MandelWindowsMenuListener mandelwindowslistener;
private ExplicitHighlight highlighted;
private Timer highlight_timer;
private boolean highlight_active;
private Rotator rotator;
private MandelScannerListener msl;
public MandelImagePanel(ToolEnvironment env,
MandelAreaImage img) throws IOException
{
this(env,img,00);
}
public MandelImagePanel(ToolEnvironment env,
MandelAreaImage img, int maxx) throws IOException
{
this.env=env;
this.maxx=maxx;
this.subareas=new MandelListMenu(this);
this.subareas.setSorted(true);
this.subareas.setUseShortnames(true);
this.gotolinks=new MandelListModelMenu("Load Image",this,null);
this.gotolinks.setSorted(true);
this.showlinks=new AbstractMandelListModelMenu("Show Image",this,null) {
@Override
protected void selectArea(QualifiedMandelName name)
{
try {
getEnvironment().createMandelImageFrame(name);
}
catch (IOException ex) {
JOptionPane.showMessageDialog(getWindow(),
"Cannot load image: "+name,
"Mandel IO", JOptionPane.WARNING_MESSAGE);
}
}
};
this.showlinks.setSorted(true);
this.linkhist=new JMenu("Parent Links");
this.linkhistpopup=new JPopupMenu("Parent Links");
this.linkListener=new EnvListener();
this.removelinks=new AbstractMandelListModelMenu("Remove Link",this,null){
@Override
protected void selectArea(QualifiedMandelName name)
{
getEnvironment().removeLink(getMandelName(), name.getMandelName());
}
};
this.removelinks.setSorted(true);
this.keyareas=new DefaultMandelListListModel(new ArrayMandelList(),
env.getAllScanner());
this.keyareas.setModifiable(true);
this.highlighted=new ExplicitHighlight("highlighted", true);
this.lastname=new ExplicitHighlight("lastshown");
this.marked=new Mark(env);
this.explicitHighlights=new ExplicitHighlights();
this.explicitHighlights.add(highlighted);
this.explicitHighlights.add(marked);
this.explicitHighlights.add(lastname);
this.slideshowmodel=new DefaultSlideShowModel(new SlideShowDestination() {
public QualifiedMandelName getCurrentQualifiedMandelName()
{
return MandelImagePanel.this.getQualifiedMandelName();
}
public boolean show(QualifiedMandelName name)
{
return MandelImagePanel.this.setImage(name);
}
public boolean show(MandelName name)
{
return MandelImagePanel.this.setImage(name);
}
public void setHighLight(QualifiedMandelName name)
{
MandelImagePanel.this.setHighLight(name);
}
public Window getWindow()
{
return MandelImagePanel.this.getWindow();
}
});
this.highlight_timer=new Timer(5000,new HighlightHandler());
this.selector=new AreaSelectionModel();
this.proportion=new ProportionSelectionModel();
this.tooltip=new ToolTipSelectionModel();
this.parentcolormap=new ConfiguredBooleanAttribute(this,"upstream-colormap",
"Use upstream colormap as default",true);
this.autoshow_info=new ConfiguredBooleanAttribute(this,"show-info-popup",
"Show info popup at image switch");
this.automark_fork=new ConfiguredBooleanAttribute(this,"automark-fork",
"Auto Mark for Fork Navigation");
this.automark_keyarea=new ConfiguredBooleanAttribute(this,"automark-keyarea",
"Auto Mark for Key Area Navigation",true);
this.automark_parent=new ConfiguredBooleanAttribute(this,"automark-parent",
"Auto Mark for Parent Navigation");
this.fullareanames=new ConfiguredBooleanAttribute(this,"full-areanames",
"Show Full Sub Area Names") {
@Override
protected void afterStateChange()
{
System.out.println("full "+isSet());
Iterator<VisibleRect> i=buffer.getRects();
while(i.hasNext()) {
VisibleRect r=i.next();
String l=MandelImagePanel.this.getLabel(MandelName.create(r.getName()));
if (l!=null) r.setLabel(l);
}
}
};
this.buffer=new Buffer(filter(img.getImage()));
this.buffer.setShowDecoration(env.getCopyright()!=null);
this.buffer.setDecoration(env.getCopyright(img.getInfo()));
//this.buffer.setBorder(BorderFactory.createLineBorder(Color.blue,5));
this.buffer.setBorder(null);
this.buffer.getDecorationModel().setLabel("Show Subarea Names");
this.buffer.getPixelToolTipModel().setLabel("Pixel Tooltip");
this.scrollpane=new JScrollPane(buffer);
//scrollpane.setBorder(BorderFactory.createLineBorder(Color.red,5));
scrollpane.setBorder(null);
scrollpane.getViewport().addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e)
{
//System.out.println("RS: "+e);
JViewport vp=scrollpane.getViewport();
if (vp!=null) {
if (debug) System.out.println("PREF:"+buffer.getPreferredSize());
if (debug) System.out.println("VP: "+vp.getViewPosition());
if (debug) System.out.println("VP: "+vp.getExtentSize());
partial=!buffer.getPreferredSize().equals(vp.getExtentSize());
}
else partial=false;
}
});
add(this.scrollpane,GBC(0,0,GBC.BOTH));
//this.setBorder(BorderFactory.createLineBorder(Color.black,5));
this.setBorder(null);
this.initialImage=img;
this.buffer.setLimitWindowSize(true);
}
private class Buffer extends BufferedComponent {
private Decoration decoration;
public Buffer(BufferedImage image)
{
super(image);
decoration=new Decoration();
}
public void setDecoration(String s)
{
decoration.setDecoration(s);
}
public Decoration getDecoration()
{
return decoration;
}
@Override
public void setShowDecoration(boolean showDecoration)
{
decoration.setShowDecoration(showDecoration);
}
@Override
protected void paintChildren(Graphics g)
{
super.paintChildren(g);
if (decoration.showDecoration())
decoration.paintDecoration(g,getWidth(),getHeight());
}
}
//////////////////////////////////////////////////////////////////////
@Override
protected void panelBound()
{
MandelAreaImage img=initialImage;
initialImage=null;
super.panelBound();
MandelWindowAccess frame=this;
Colormap cm=env.getDefaultColormap();
this.history=new History(env.getImageDataScanner());
this.mappermodel=new MapperModel();
this.colormapmodel=new ColormapModel(cm);
this.colormapmodel.addChangeListener(new ColModelChangeListener());
rotator=new Rotator(colormapmodel);
imageListener=new MandelFrameImageListner();
create=new MandelSubAreaCreationDialog(frame,"Mandel Sub Area Creation");
colormapDialog=new ColormapDialog(frame,"Main Colormap",this.colormapmodel);
imageDialog=new ImageControl(frame);
listsDialog=new MandelListsDialog(frame);
listsDialog.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e)
{
showListsControlAction.setEnabled(true);
}
});
juliaDialog=new JuliaDialog(frame,300,300);
juliaDialog.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e)
{
showJuliaAction.setEnabled(true);
}
});
iterDialog=new IterationPathDialog(frame,300,300);
iterDialog.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e)
{
showIterationPathAction.setEnabled(true);
}
});
SelectAreaListener arealistener=new SelectAreaListener();
buffer.setSelectInvisible(true);
buffer.addRectEventListener(arealistener);
buffer.addRectModifiedEventListener(arealistener);
if (!isReadonly()) {
selector.setSelectedItem(selector.getElementAt(0));
proportion.setSelectedItem(proportion.getElementAt(0));
}
buffer.addScaleEventListener(new ScaleAdapter() {
@Override
public void componentScaled(ScaleEvent e)
{
setTitle();
if (debug) System.out.println("buf: "+getImagePane().getPreferredSize());
if (debug) System.out.println("VP: "+getScrollPane().getViewport().getExtentSize());
//if (!isPartial()) setInitialSize();
}
});
create.addCreationListener(new SubAreaListener());
parentAction=new ParentAction();
areaUpAction=new AreaUpAction();
forkAction=new ForkAction();
showSubAction=new ShowSubAction();
hideSubAction=new HideSubAction();
refreshSubAction=new RefreshSubAction();
showColormapAction=new ShowColormapAction(colormapDialog);
if (!isReadonly()) variationAction=new VariationAction();
showMetaAction=new ShowMetaAction();
linksGaleryAction=new LinksGaleryAction();
keyareasGaleryAction=new KeyAreasGaleryAction();
zoomGaleryAction=new ZoomGaleryAction();
cloneAction=new CloneAction();
gotoAction=new GotoAction();
if (!isReadonly()) {
saveAction=new SaveAction();
areaCMSaveAction=new AreaCMSaveAction();
areaCMDeleteAction=new AreaCMDeleteAction();
}
areaCMAction=new AreaCMAction();
showListsControlAction=new ShowListsControlAction();
showJuliaAction=new ShowJuliaAction();
showIterationPathAction=new ShowIterationPathAction();
areaDownAction=new AreaDownAction();
// pane.addRectPointEventListener(new CornerListener());
buffer.addActionListener(parentAction, Corner.BOTTOM_LEFT);
buffer.addActionListener(showSubAction, Corner.BOTTOM_RIGHT);
buffer.addActionListener(hideSubAction, Corner.BOTTOM_RIGHT);
buffer.addActionListener(showColormapAction, Corner.TOP_RIGHT);
buffer.addActionListener(showMetaAction, Corner.TOP_LEFT);
buffer.addActionListener(areaDownAction, RectanglePoint.MIDDLE_BOTTOM);
buffer.addActionListener(new LinksAction(), RectanglePoint.MIDDLE_LEFT);
buffer.addActionListener(new KeyAreasAction(), RectanglePoint.MIDDLE_RIGHT);
buffer.getContentPane().addMouseMotionListener(new PixelListener());
buffer.setInheritsPopupMenu(true);
scrollpane.setInheritsPopupMenu(true);
hideSubAction.setEnabled(false);
refreshSubAction.setEnabled(false);
setupMenu();
getWindow().addWindowListener(new WindowAdapter(){
@Override
public void windowClosed(WindowEvent e)
{
if (debug) System.out.println("FRAME closed");
clear();
}
});
buffer.setScaleMode(true);
// finally set the image
setImageData(img, false);
msl=new MandelScannerListenerAdapter() {
@Override
public void addMandelFile(MandelScanner s, MandelHandle h)
{
handle(h);
}
@Override
public void removeMandelFile(MandelScanner s, MandelHandle h)
{
handle(h);
}
@Override
public void scannerChanged(MandelScanner s)
{
handle(null);
}
private void handle(MandelHandle h)
{
boolean doit=false;
if (h==null) doit=true;
else {
QualifiedMandelName qn=h.getName();
if (qn!=null && qn.getMandelName().getParentName()!=null) {
if (qn.getMandelName().getParentName().equals(getMandelName())) {
doit=true;
}
}
}
if (doit) {
System.out.println("*** do update sub rects");
_updateSubRects(false);
}
}
};
getEnvironment().getAllScanner().addMandelScannerListener(msl);
getEnvironment().addLinkListener(linkListener);
}
@Override
protected void panelUnbound()
{
super.panelUnbound();
for (ListModifierMenu m:listModifiers) m.cleanupModel();
if (msl!=null) {
getEnvironment().getAllScanner().removeMandelScannerListener(msl);
}
getEnvironment().removeLinkListener(linkListener);
getEnvironment().getMandelWindowsModel().removeListDataListener(
mandelwindowslistener);
gotolinks.setMandelListModel(null);
showlinks.setMandelListModel(null);
removelinks.setMandelListModel(null);
cancel();
}
//////////////////////////////////////////////////////////////////////
private UpdateSourceSupport uss=new UpdateSourceSupport();
public void addUpdatableObject(UpdatableObject o)
{
uss.addUpdatableObject(o);
}
public void removeUpdatableObject(UpdatableObject o)
{
uss.removeUpdatableObject(o);
}
protected void updateObjects()
{
UpdateContext ctx=new UpdateContext(this);
uss.updateObjects(ctx);
}
protected void updateObjects(String prop, Object value)
{
UpdateContext ctx=new UpdateContext(this,
new UpdateReason.Factory(this).setProperty(prop, value));
uss.updateObjects(ctx);
}
//////////////////////////////////////////////////////////////////////
public void cancel()
{
slideshowmodel.cancel();
if (rotator!=null) rotator.cancel();
}
public void setImageDecoration(String s)
{
buffer.setDecoration(s);
}
public BooleanAttribute getSelectInvisibleModel()
{
return buffer.getSelectInvisibleModel();
}
public BooleanAttribute getDecorationModel()
{
return buffer.getDecorationModel();
}
public BooleanAttribute getPixelToolTipModel()
{
return buffer.getPixelToolTipModel();
}
public BooleanAttribute getParentColormapModel()
{
return parentcolormap;
}
public BooleanAttribute getFullAreaNamesModel()
{
return fullareanames;
}
public BooleanAttribute getAutoShowInfoModel()
{
return autoshow_info;
}
public BooleanAttribute getAutoMarkForkModel()
{
return automark_fork;
}
public BooleanAttribute getAutoMarkKeyAreaModel()
{
return automark_keyarea;
}
public BooleanAttribute getAutoMarkParentModel()
{
return automark_parent;
}
public ComboBoxModel getAreaSelectorModel()
{
return selector;
}
public ProportionSelectionModel getProportionSelectionModel()
{
return proportion;
}
public ToolTipSelectionModel getToolTipSelectionModel()
{
return tooltip;
}
public SlideShowModel getSlideShowModel()
{
return slideshowmodel;
}
public BufferedComponent getImagePane()
{
return buffer;
}
public JScrollPane getScrollPane()
{
return scrollpane;
}
public boolean isPartial()
{
return partial;
}
public void setInitialSize()
{
Dimension id=buffer.getPreferredSize();
Dimension sd=Toolkit.getDefaultToolkit().getScreenSize();
Dimension d=new Dimension(id);
Insets insets=getInsets();
if (debug) System.out.println("bufsize:"+id);
if (debug) System.out.println("scrsize:"+sd);
Dimensions.mod.add(d,insets.left+insets.right,insets.top+insets.bottom);
Dimensions.mod.sub(sd,BufferedFrame.FRAME_INSETS,BufferedFrame.FRAME_INSETS+20);
Dimensions.mod.limit(d,sd);
if (debug) System.out.println("ressize:"+d);
setPreferredSize(d);
}
public MandelImagePanel getMandelImagePane()
{
return this;
}
public void paintDecoration(Graphics g, int w, int h)
{
getDecoration().paintDecoration(g, w, h);
}
public Decoration getDecoration()
{
return buffer.getDecoration();
}
public Window getMandelWindow()
{
return getWindow();
}
private class ColModelChangeListener implements ChangeListener {
public void stateChanged(javax.swing.event.ChangeEvent e)
{
boolean mod=getMandelData().isModified();
if (colormapmodel.getColormap()!=image.getColormap()) {
image.setColormap(colormapmodel.getResizeMode(),
colormapmodel.getColormap());
}
if (debug) System.out.println("setting default colormap to actual colormap");
defcolormap=colormapmodel.getColormap();
if (!mod) { // so far there is no content related update handler
//image.getMandelData().setModified(true);
updateObjects("colormap",colormapmodel.getColormap());
}
}
}
private class MandelFrameImageListner implements ImageListener {
public void stateToBeChanged(ChangeEvent e)
{
if (debug) System.out.println("image to be changed...");
getImagePane().hideAllRects();
}
public void stateChanged(ChangeEvent e)
{
if (debug) System.out.println("image changed...");
if (image.getColormap()!=null) {
if (debug) System.out.println(" setting image and default colormap");
colormapmodel.setColormap(defcolormap=image.getColormap());
}
colormapmodel.setModifiable(image.getRasterData()!=null);
if (image.getImage()!=buffer.getImage()) {
if (debug) System.out.println(" set changed image to buffer");
BufferedImage tmp=filter(image.getImage());
BufferedImage cur=buffer.getImage();
if (cur.getWidth()==tmp.getWidth() && cur.getHeight()==tmp.getHeight()) {
cur.getGraphics().drawImage(tmp, 0, 0, null);
}
else {
buffer.setImage(tmp);
MandelImagePanel.this._updateSubRects(false,getMandelName(),subAreasShown());
}
}
if (subAreasShown()) {
if (debug) System.out.println(" show areas");
getImagePane().showAllRects();
}
fireChangeEvent();
getImagePane().repaint();
}
}
private void clear()
{
if (this.image!=null) {
this.image.removeImageListener(imageListener);
this.image=null;
}
if (browserModel!=null) {
browserModel.clear();
browserModel=null;
}
cancel();
}
public boolean isReadonly()
{ return getEnvironment().isReadonly();
}
public int getMaxFrame()
{
return (int)maxx;
}
private JMenu listmenu=new JMenu("List Shortcuts");
private void addListModifierMenu(ListModifierMenu m)
{
if (m.isValid()) {
listModifiers.add(m);
listmenu.add(m);
}
}
public void addListShortcut(String name, MandelListModel model)
{
addListModifierMenu(new DynListModifierMenu(name,model));
}
public boolean hasListShortcut(MandelListModel model)
{
return hasListShortcut(model.getList());
}
public boolean hasListShortcut(MandelList l)
{
for (ListModifierMenu m:listModifiers) {
if (m.getMandelModel().getList()==l) {
return true;
}
}
return false;
}
public void removeListShortcut(MandelListModel model)
{
removeListShortcut(model.getList());
}
public void removeListShortcut(MandelList l)
{
for (ListModifierMenu m:listModifiers) {
if (m.getMandelModel().getList()==l) {
listModifiers.remove(m);
listmenu.remove(m);
break; // avoid concurrent modification exception
}
}
}
//
// Provide menu for foreign mandel window frames
//
private class MandelWindowsMenuListener implements MenuListener,
ActionListener,
ListDataListener {
private JMenu menu;
public MandelWindowsMenuListener(JMenu menu)
{
this.menu=menu;
menu.setEnabled(getEnvironment().getMandelWindowsModel().getSize()>1);
}
protected Action createAction(final QualifiedMandelName n)
{
Action a=new AbstractAction(n.toString()) {
public void actionPerformed(ActionEvent e)
{
getEnvironment().addLink(getMandelName(), n.getMandelName());
}
};
MandelListModel m=getEnvironment().getLinkModel(getMandelName());
// avoid self links and duplicates
a.setEnabled((m==null || m.getList().get(n.getMandelName())==null) &&
(!n.getMandelName().equals(getMandelName())));
return a;
}
public void menuSelected(MenuEvent e)
{
menu.removeAll();
ListModel m=getEnvironment().getMandelWindowsModel();
for (int i=0; i<m.getSize(); i++) {
MandelImageFrame f=(MandelImageFrame) m.getElementAt(i);
if (f!=MandelImagePanel.this.getMandelWindow()) {
menu.add(createAction(f.getQualifiedName()));
}
}
}
public void menuDeselected(MenuEvent e)
{
menuCanceled(e);
}
public void menuCanceled(MenuEvent e)
{
menu.removeAll();
}
private void windowModelChanged(ListDataEvent e)
{
menu.setEnabled(((ListModel)e.getSource()).getSize()>1);
}
public void intervalAdded(ListDataEvent e)
{
windowModelChanged(e);
}
public void intervalRemoved(ListDataEvent e)
{
windowModelChanged(e);
}
public void contentsChanged(ListDataEvent e)
{
windowModelChanged(e);
}
public void actionPerformed(ActionEvent e)
{
System.out.println("action on windows menu");
}
}
private void setupMenu()
{
// JMenu favorites=null;
// JMenu todos=null;
// JMenu memory=null;
JMenuItem it;
UpdatableJPopupMenu menu=new UpdatableJPopupMenu();
addUpdatableObject(menu);
menu.setBorder(new BevelBorder(BevelBorder.RAISED));
listModifiers=new ArrayList<ListModifierMenu>();
addListModifierMenu(new ListModifierMenu("Favorites",getEnvironment().getFavoritesModel()));
addListModifierMenu(new ListModifierMenu("Todos",getEnvironment().getTodosModel()));
addListModifierMenu(new ListModifierMenu("Key Areas",getEnvironment().getAreasModel()));
addListModifierMenu(new LoadableListModifier("Memory",getEnvironment().getMemoryModel()));
String shortcuts=env.getProperty(Settings.LIST_SHORTCUTS);
System.out.println("default shortcuts: "+shortcuts);
if (!Utils.isEmpty(shortcuts)) {
StringTokenizer t=new StringTokenizer(shortcuts,";");
String p;
while ((t.hasMoreTokens())) {
p=t.nextToken();
MandelListModel m=env.getMandelListModel(p);
if (m!=null) {
int ix=p.lastIndexOf('/');
if (ix>=0) p=p.substring(ix+1);
addListShortcut(p,m);
}
}
}
///////////////////////////////////////////////////
JMenu mark=new UpdatableJMenu("Mark");
addMarkAction(mark,new GotoMarkAction());
mark.add(new JMenuItem(new SetMarkAction()));
addMarkAction(mark,new CloneAction("Show Image") {
@Override
protected QualifiedMandelName getQualifiedMandelName()
{
return marked.getQualifiedName();
}
});
addMarkAction(mark,new CommonAncestorAction());
addMarkAction(mark,areaDownAction);
addMarkAction(mark,new KeyAreaDownAction());
addMarkAction(mark,new ForkAreaDownAction());
addMarkAction(mark,new MemorizeMarkAction());
if (!isReadonly()) {
addMarkAction(mark,new LinkFromMarkAction());
addMarkAction(mark,new UnlinkFromMarkAction());
}
addMarkAction(mark,new SwapMarkAction());
addMarkAction(mark,new ClearMarkAction());
mark.add(new MandelListModelMenu("Previous",this,marked.previous));
///////////////////////////////////////////////////
JMenu highlight=new JMenu("Sub area highlight");
ButtonGroup group = new ButtonGroup();
it = new JRadioButtonMenuItem(new NoHighlightAction());
// it.setMnemonic(KeyEvent.VK_R);
group.add(it);
highlight.add(it);
it = new JRadioButtonMenuItem(new FavoritesHighlightAction());
it.setSelected(true);
//it.setMnemonic(KeyEvent.VK_O);
group.add(it);
highlight.add(it);
if (!isReadonly()) {
it=new JRadioButtonMenuItem(new UnseenHighlightAction());
//it.setMnemonic(KeyEvent.VK_O);
group.add(it);
highlight.add(it);
}
it = new JRadioButtonMenuItem(new LastHighlightAction());
//it.setMnemonic(KeyEvent.VK_O);
group.add(it);
highlight.add(it);
///////////////////////////////////////////////////
JMenu subarea=new UpdatableJMenu("Sub areas");
it=new JMenuItem(showSubAction);
subarea.add(it);
it=new JMenuItem(refreshSubAction);
subarea.add(it);
it=new JMenuItem(hideSubAction);
subarea.add(it);
subarea.add(subareas);
//////////////////////
menu.add(listmenu);
menu.add(mark);
menu.add(highlight);
menu.add(subarea);
menu.addSeparator();
it=new JMenuItem(showColormapAction);
menu.add(it);
menu.add(rotator.createMenu());
it=new JMenuItem(new WindowControlAction(getWindow(),"Image Control",
imageDialog));
menu.add(it);
menu.addSeparator();
it=new JMenuItem(showMetaAction);
menu.add(it);
JMenu galerymenu=new JMenu("Galeries");
galerymenu.add(linksGaleryAction);
galerymenu.add(keyareasGaleryAction);
galerymenu.add(zoomGaleryAction);
///////////////////////////////////////////////////
JMenu windowLink=new JMenu("Link To Other Display Area");
mandelwindowslistener=new MandelWindowsMenuListener(windowLink);
windowLink.addActionListener(mandelwindowslistener);
windowLink.addMenuListener(mandelwindowslistener);
getEnvironment().getMandelWindowsModel().addListDataListener(mandelwindowslistener);
JMenu linkmenu=new JMenu("Links");
linkmenu.add(gotolinks);
linkmenu.add(showlinks);
linkmenu.add(windowLink);
linkmenu.add(removelinks);
linkmenu.add(linkhist);
menu.add(galerymenu);
menu.add(linkmenu);
MandelListMenu.SelectAction selectAction;
menu.add(keyareasmenu=new MandelListModelMenu("Key Areas",this,keyareas));
keyareasmenu.addSelectAction(selectAction=new MandelListMenu.SelectAction() {
public void selectArea(MandelWindowAccess access, QualifiedMandelName name)
{
if (automark_keyarea.isSet()) {
setAutoMark();
}
}
});
keyareaspopupmenu=new MandelListModelMenu("Key Areas",this,keyareas);
keyareaspopupmenu.addSelectAction(selectAction);
it=new UpdatableJMenuItem(areaUpAction);
menu.add(it);
it=new UpdatableJMenuItem(forkAction);
menu.add(it);
it=new UpdatableJMenuItem(parentAction);
menu.add(it);
if (!isReadonly()) {
it=new JMenuItem(variationAction);
menu.add(it);
RecalcAction ra=new RecalcAction();
ra.setCleanupWindow(true);
this.addRenewStateListener(ra);
it=new JMenuItem(ra);
menu.add(it);
}
menu.add(getEnvironment().getListActions().createMenu(this,
new MandelNameSelector() {
public QualifiedMandelName getSelectedMandelName()
{ return getQualifiedMandelName(); }
}));
menu.addSeparator();
it=new JMenuItem(showListsControlAction);
menu.add(it);
it=new JMenuItem(new ShowBrowserAction());
menu.add(it);
menu.add(gotoAction);
menu.addSeparator();
menu.add(showJuliaAction);
if (iterPathActive) menu.add(showIterationPathAction);
menu.add(slideshowmodel.createMenu(this,
new SlideShowSourceAdapter(new MainSlideShowOneMode(),
new MainSlideShowTwoMode())));
menu.add(cloneAction);
JMenu submenu=new UpdatableJMenu("Area Colormap");
menu.add(submenu);
if (!isReadonly()) {
menu.add(saveAction);
submenu.add(new UpdatableJMenuItem(areaCMSaveAction));
submenu.add(new UpdatableJMenuItem(areaCMDeleteAction));
}
submenu.add(new UpdatableJMenuItem(areaCMAction));
it=new UpdatableJMenuItem(new HomeAction());
menu.add(it);
it=new JMenuItem(env.getToolControlAction());
menu.add(it);
menu.add(new JPopupMenu.Separator());
it=new JMenuItem(new AboutAction());
menu.add(it);
if (getWindow() instanceof JFrame) {
it=new JMenuItem("Close");
it.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
getWindow().dispose();
}
});
menu.add(it);
}
setComponentPopupMenu(menu);
}
private class MainSlideShowOneMode extends SlideShowSourceAdapter.OneModeAdapter {
@Override
public QualifiedMandelName getSingleName(SlideShowModel model)
{
return getQualifiedMandelName();
}
}
private class MainSlideShowTwoMode extends SlideShowSourceAdapter.TwoModeAdapter {
@Override
public QualifiedMandelName getFirstName(SlideShowModel model)
{
return getQualifiedMandelName();
}
@Override
public QualifiedMandelName getSecondName(SlideShowModel model)
{
return getMark();
}
}
///////////////////////////////////////////////////////////////////////////
private void addMarkAction(JMenu menu, Action action)
{
action.setEnabled(false);
JMenuItem it=new UpdatableJMenuItem(action);
menu.add(it);
}
private MandelListFolderTreeModel browserModel;
private MandelListFolderTreeModel memoryModel;
public MandelListFolderTreeModel getMandelBrowserModel()
{
if (browserModel==null) {
ComposedMandelListFolderTreeModel local;
memoryModel=new DefaultMandelListFolderTreeModel(new MemoryMandelListFolderTree("memory"),
env.getAllScanner());
memoryModel.setModifiable(true);
browserModel=getEnvironment().getMandelListFolderTreeModel();
local=new ComposedMandelListFolderTreeModel("list", null);
local.setModifiable(!getEnvironment().isReadonly());
local.addFolderTreeModel(browserModel, "general");
local.addListModel(getHistory(), "history", false);
local.addFolderTreeModel(memoryModel, "window memory");
browserModel=local;
}
return browserModel;
}
public History getHistory()
{ return history;
}
public MandelWindowAccess getFrameAccess()
{ return this;
}
public ToolEnvironment getEnvironment()
{ return env;
}
public MandelName getMandelName()
{ return name.getMandelName();
}
public QualifiedMandelName getQualifiedMandelName()
{ return name;
}
public QualifiedMandelName getQualifiedName()
{ return name;
}
public MandelData getMandelData()
{ return image==null?null:image.getMandelData();
}
public MandelImage getMandelImage()
{ return image;
}
public MandelInfo getMandelInfo()
{
return image==null?null:image.getMandelData().getInfo();
}
public MapperModel getMapperModel()
{ return mappermodel;
}
public ColormapModel getColormapModel()
{ return colormapmodel;
}
public boolean hasColormap()
{
return image.getColormap()!=null;
}
private void setTitle()
{ String scale="";
//System.out.println("Image scale="+getImagePane().getScale());
if (Math.round(getImagePane().getScale()*100)!=100.0) {
scale=" ["+Math.round(getImagePane().getScale()*100)+"%]";
}
Window w=getWindow();
if (w instanceof Frame) {
((Frame)w).setTitle("Mandel Image "+name+scale);
}
}
private void setHighLight(QualifiedMandelName name)
{
this.highlighted.setQualifiedName(name);
if (name!=null) showSubRect(name, true);
}
private void setImage(BufferedImage image)
{
if (debug) System.out.println("image to buffer");
image=filter(image);
buffer.setImage(image);
buffer.setScale(1);
if (debug) System.out.println("image buffer set");
}
private void updateKeyAreas()
{
System.out.println("update upstream key areas");
MandelList list=getEnvironment().getAreas();
keyareas.clear();
if (!name.isRoot()) {
MandelName loop=name.getMandelName().getParentName();
while (!loop.isRoot()) {
QualifiedMandelName n=new QualifiedMandelName(loop);
if (list.contains(n)) {
keyareas.add(n);
System.out.println(" found "+n);
}
loop=loop.getParentName();
}
}
keyareasGaleryAction.setEnabled(!keyareas.getList().isEmpty());
}
private void updateLinks()
{
MandelListModel m=getEnvironment().getLinkModel(name.getMandelName());
linksGaleryAction.setEnabled(m!=null && !m.getList().isEmpty());
gotolinks.setMandelListModel(m);
showlinks.setMandelListModel(m);
removelinks.setMandelListModel(m);
MandelName loop=name.getMandelName();
boolean found=false;
boolean parent=false;
linkhist.removeAll();
linkhist.setEnabled(false);
linkhistpopup.removeAll();
linkhistpopup.setEnabled(false);
while (!loop.isRoot()) {
m=getEnvironment().getLinkModel(loop);
if (m!=null && m.getList().size()>0) {
if (parent) {
System.out.println("found parent links for "+loop);
linkhist.add(new MandelListModelMenu(loop.getName(),this,m));
linkhist.setEnabled(found=true);
}
linkhistpopup.add(new MandelListModelMenu(loop.getName(),this,m));
linkhistpopup.setEnabled(true);
}
loop=loop.getParentName();
parent=true;
}
if (!found) System.out.println("no parent links found");
}
private void setImageData(MandelAreaImage img, boolean showlast)
{
QualifiedMandelName name=img.getName();
System.out.println("setup image for file ="+img.getMandelData().getFile());
stopHighLight();
if (this.image!=null) {
img.removeImageListener(imageListener);
this.buffer.setToolTipHandler(null);
}
this.lastname.setEnabled(showlast);
this.lastname.setQualifiedName(this.name);
if (highlight_mode==H_LAST) highlighted.setName(lastname);
this.name=name;
this.image=img;
if (img.getRasterData()!=null) {
this.buffer.setToolTipHandler(tooltip.getToolTipHandler());
}
if (!hasColormap()) {
showColormapAction.setEnabled(false);
}
else {
showColormapAction.setEnabled(true);
}
img.addImageListener(imageListener);
imageListener.stateChanged(null);
if (!isPartial()) setInitialSize();
history.add(name);
updateLinks();
updateKeyAreas();
infoPopup.setData(img.getInfo(), name);
updateSubRects();
updateObjects("area",name);
if (autoshow_info.isSet()) showInfoPopup();
if (env.handleRasterSeen(img.getMandelData().getFile())) {
MandelHandle h=env.getAutoImageDataScanner().getMandelHandle(name);
if (h!=null) img.getMandelData().setFile(h.getFile());
else {
System.out.println("*** no raster file found for "+name+" after relocate");
}
}
buffer.setDecoration(env.getCopyright(img.getInfo()));
setTitle();
fireRenewState();
fireChangeEvent();
if (debug) System.out.println("image setup done");
}
protected BufferedImage filter(BufferedImage image)
{
if (maxx>0) {
filterscale=maxx/image.getWidth();
double y=maxx*image.getHeight()/image.getWidth();
if (image.getWidth()>maxx) {
BufferedImage n=new BufferedImage((int)maxx, (int)y,
BufferedImage.TYPE_INT_RGB);
Graphics2D g=n.createGraphics();
g.drawImage(image, 0, 0, (int)maxx, (int)y, null);
image=n;
}
}
else filterscale=1;
return image;
}
private Colormap getDefColormap()
{
if (defcolormap==null) {
return colormapmodel.getColormap();
}
return defcolormap;
}
/////////////////////////////////////////////////////////////////////////
// Image Factories
/////////////////////////////////////////////////////////////////////////
public MandelAreaImage getMandelImage(MandelName name) throws IOException
{
fileinfo=new Environment.FileInfo();
MandelAreaImage im=env.getMandelImage(name,colormapmodel.getResizeMode(),
createColormapSource(name, fileinfo),
mappermodel.getMapper(),fileinfo);
return im;
}
public MandelAreaImage getMandelImage(QualifiedMandelName name) throws IOException
{
fileinfo=new Environment.FileInfo();
MandelAreaImage im=env.getMandelImage(name,colormapmodel.getResizeMode(),
createColormapSource(name.getMandelName(), fileinfo),
mappermodel.getMapper(),fileinfo);
return im;
}
public MandelAreaImage getMandelImage(MandelHandle h) throws IOException
{
fileinfo=new Environment.FileInfo();
MandelAreaImage im=env.getMandelImage(h, colormapmodel.getResizeMode(),
createColormapSource(h.getName().getMandelName(), fileinfo),
mappermodel.getMapper(),fileinfo);
return im;
}
synchronized
public MandelColormapCache getColormapCache()
{
return getEnvironment().getColormapCache();
}
private ColormapSource createColormapSource(MandelName n,
Environment.FileInfo fileinfo)
{
if (parentcolormap.isSet()) {
return new PanelColormapSource(n, fileinfo);
}
else {
return getDefColormap();
}
}
private class PanelColormapSource extends CachedUpstreamColormapSource {
private Environment.FileInfo fileinfo;
public PanelColormapSource(MandelName n, Environment.FileInfo fileinfo)
{
super(n,getEnvironment().getAreaColormapScanner(),getColormapCache());
this.fileinfo=fileinfo;
}
@Override
protected Colormap optimizedLoad(MandelHandle h)
{
if (!h.getHeader().isAreaColormap() &&
getMandelName()!=null&&getMandelName().isAbove(getBasename())) {
if (h.getName().getMandelName().isAbove(getMandelName())) {
if (debug)
System.out.println("new area is downstream");
return getDefColormap();
}
}
return super.optimizedLoad(h);
}
@Override
protected void colormapFound(MandelHandle h, Colormap cm)
{
if (cm!=getDefColormap()) {
super.colormapFound(h, cm);
if (fileinfo!=null) fileinfo.setColormap(cm);
}
}
@Override
public Colormap getColormap()
{
Colormap cm=super.getColormap();
if (cm==null) cm=getDefColormap();
return cm;
}
}
////////////////////////
private abstract class ImageFactory<T> {
protected T arg;
public ImageFactory(T arg)
{
this.arg=arg;
}
abstract MandelAreaImage getMandelImage() throws IOException;
@Override
public String toString()
{
return arg.toString();
}
}
private class MandelNameImageFactory extends ImageFactory<MandelName> {
public MandelNameImageFactory(MandelName arg)
{
super(arg);
}
public MandelAreaImage getMandelImage() throws IOException
{
return MandelImagePanel.this.getMandelImage(arg);
}
}
private class QualifiedMandelNameImageFactory
extends ImageFactory<QualifiedMandelName> {
public QualifiedMandelNameImageFactory(QualifiedMandelName arg)
{
super(arg);
}
public MandelAreaImage getMandelImage() throws IOException
{
return MandelImagePanel.this.getMandelImage(arg);
}
}
private class MandelHandleImageFactory extends ImageFactory<MandelHandle> {
public MandelHandleImageFactory(MandelHandle arg)
{
super(arg);
}
public MandelAreaImage getMandelImage() throws IOException
{
return MandelImagePanel.this.getMandelImage(arg);
}
}
//////////////////////////////////////////////////////////////////////////
// Image setter
//////////////////////////////////////////////////////////////////////////
private boolean setImage(ImageFactory fac, boolean showlast)
{
try {
setBusy(true);
Colormap def=defcolormap;
MandelAreaImage img=fac.getMandelImage();
if (img==null) {
if (debug) System.out.println(fac+" not found -> rescan");
env.rescan();
img=fac.getMandelImage();
}
if (img!=null) {
if (debug) System.out.println("got image for "+fac);
setImage(img.getImage());
setImageData(img, showlast);
if (fileinfo.getColormap()==null) {
if (debug) {
System.out.println("-> finally preserving default colormap "+
def.getSize());
}
defcolormap=def;
}
else {
if (debug) System.out.println("-> finally keeping current colormap");
}
return true;
}
else mandelInfo("No image for "+fac+" found.");
}
catch (IOException ex) {
mandelError("cannot load "+name,ex);
}
finally {
setBusy(false);
}
return false;
}
public boolean setImage(MandelName name)
{
return setImage(name,false);
}
public boolean setImage(MandelName name, boolean showlast)
{
return setImage(new MandelNameImageFactory(name),showlast);
}
public boolean setImage(QualifiedMandelName name)
{
return setImage(name,false);
}
public boolean setImage(QualifiedMandelName name, boolean showlast)
{
return setImage(new QualifiedMandelNameImageFactory(name),showlast);
}
public boolean setImage(MandelHandle h)
{
return setImage(h,false);
}
public boolean setImage(MandelHandle h, boolean showlast)
{
return setImage(new MandelHandleImageFactory(h),showlast);
}
////////////////////////////////////////////////////////////////////////////
private boolean busy;
private Cursor origcursor;
private JComponent getCC()
{ return getImagePane().getContentPane();
}
protected void setBusy(boolean b)
{
if (b!=busy) {
if (b) {
if (debug) System.out.println("-------------------------------------------------");
if (debug) System.out.println("set busy");
origcursor=getImagePane().getCursor();
getImagePane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
}
else {
if (debug) System.out.println("orig cursor");
getImagePane().setCursor(origcursor);
}
}
busy=b;
}
public void addChangeListener(ChangeListener h)
{
listeners.addChangeListener(h);
}
public void removeChangeListener(ChangeListener h)
{
listeners.removeChangeListener(h);
}
protected void fireChangeEvent()
{
listeners.fireChangeEvent(this);
}
public void showColormap()
{
showColormapAction.setEnabled(false);
}
public void hideColormap()
{
showColormapAction.setEnabled(true);
}
//////////////////////////////////////////////////////////////////////////
// Visible Rect handling
//////////////////////////////////////////////////////////////////////////
private VisibleRectFilter subareafilter=new VisibleRectFilter() {
public boolean match(VisibleRect r)
{
return r.getName()!=null;
}
};
public boolean subAreasShown()
{
return hideSubAction.isEnabled();
}
private String getLabel(MandelName n)
{
if (n==null) return null;
if (fullareanames.isSet() || !n.getParentName().equals(getMandelName())) {
return n.getName();
}
return n.getSubAreaName();
}
////////////////////////////////////////////////////////////////////////////
// sub area highlight
public class ExplicitHighlight {
private String id;
private QualifiedMandelName name;
private boolean enabled;
public ExplicitHighlight(String id, boolean enabled)
{
this.id=id;
this.enabled=enabled;
}
public ExplicitHighlight(String id)
{
this(id,false);
}
public boolean isActive()
{
return enabled && name!=null &&
MandelImagePanel.this.getMandelName().isHigher(getMandelName());
}
public void setEnabled(boolean enabled)
{
this.enabled=enabled;
}
public boolean isEnabled()
{
return enabled;
}
public MandelName getMandelName()
{
if (name==null) return null;
return name.getMandelName();
}
public QualifiedMandelName getQualifiedName()
{
return name;
}
public void setQualifiedName(QualifiedMandelName name)
{
this.name=name;
}
public void setName(ExplicitHighlight hl)
{
setQualifiedName(hl.getQualifiedName());
}
public boolean isSet()
{
return name!=null;
}
public void clear()
{
name=null;
}
@Override
public String toString()
{
return "ExplicitHighlight{"+"id="+id+"; name="+name+"; enabled="+enabled+
"; active="+isActive()+'}';
}
}
public final class ExplicitHighlights {
private List<ExplicitHighlight> list;
public ExplicitHighlights()
{
list=new ArrayList<ExplicitHighlight>();
}
public void add(ExplicitHighlight hl)
{
if (!list.contains(hl)) list.add(hl);
}
public void remove(ExplicitHighlight hl)
{
list.remove(hl);
}
public Handler createHandler()
{
return new Handler();
}
public final class Handler {
private List<ExplicitHighlight> list;
private Handler()
{
list=new ArrayList<ExplicitHighlight>();
for (ExplicitHighlight h:ExplicitHighlights.this.list) {
if (h.isActive() && !contains(h.getQualifiedName())) {
if (debugHL) System.out.println("-- add "+h);
list.add(h);
}
else {
if (debugHL) System.out.println("-- ignore "+h);
}
}
}
public boolean contains(QualifiedMandelName n)
{
if (n==null) return false;
return contains(n.getMandelName());
}
public boolean contains(MandelName n)
{
if (n!=null) for (ExplicitHighlight h:list) {
if (h.getQualifiedName().getMandelName().equals(n)) return true;
}
return false;
}
public void handleAlreadyShown(QualifiedMandelName n)
{
if (n==null) return;
handleAlreadyShown(n.getMandelName());
}
public void handleAlreadyShown(MandelName n)
{
if (n==null) return;
ListIterator<ExplicitHighlight> i=list.listIterator();
while (i.hasNext()) {
ExplicitHighlight h=i.next();
if (h.getQualifiedName().getMandelName().equals(n)) {
if (debugHL) System.out.println("-- remove already seen "+h);
i.remove();
}
}
}
public void show()
{
for (ExplicitHighlight h:list) {
if (debugHL) System.out.println("-- show "+h);
showSubRect(h.getQualifiedName(),true);
}
}
}
}
private void updateSubRects()
{
_updateSubRects(true);
}
public void updateSubRects(MandelName name, boolean vis)
{
_updateSubRects(true,name,vis);
}
private void _updateSubRects(boolean rescan)
{
Set<MandelName> subs;
getImagePane().discardAllRects(subareafilter);
subareas.clear();
_updateSubRects(rescan, getMandelName(),subAreasShown());
//
// if (subAreasShown()) {
// //System.out.println("Show all rects");
// getImagePane().showAllRects();
// }
}
private void _updateSubRects(boolean rescan, MandelName name, boolean vis)
{ Set<MandelName> subs;
MandelScanner scanner=env.getAutoMetaScanner();
ExplicitHighlights.Handler highlights=explicitHighlights.createHandler();
if (rescan) scanner.rescan(false);
subs=MandUtils.getSubNames(name, scanner);
if (debug) System.out.println("**** found "+subs.size()+" sub areas");
for (MandelName n:subs) {
if (showSubRect(n,vis)) highlights.handleAlreadyShown(n);
subareas.add(new QualifiedMandelName(n));
}
highlights.show();
}
private boolean showSubRect(MandelName n, boolean vis)
{
MandelHandle h=env.getMetaScanner().getMandelInfo(n);
return showSubRect(h,vis);
}
private boolean showSubRect(QualifiedMandelName n, boolean vis)
{
MandelHandle h=env.getMetaScanner().getMandelInfo(n);
return showSubRect(h,vis);
}
private boolean showSubRect(MandelHandle h, boolean vis)
{
if (h==null) return false;
MandelName n=h.getName().getMandelName();
MandelData data;
try {
data=h.getInfo();
}
catch (IOException ex) {
data=null;
}
if (debug) System.out.println(" found "+n+": "+h.getHeader().getTypeDesc()+": "+data);
VisibleRect rect=getImagePane().getRect(n.getName());
if (data==null) {
if (rect!=null) rect.discard();
}
else {
MandelInfo info=data.getInfo();
boolean ht=(highlighted.isActive() && highlight(n));
if (rect==null) rect=getImagePane().createRect(n.getName(),
getLabel(n), info);
updateRect(rect, info);
rect.setVisible(ht||vis);
if (ht) {
highlight_active=true;
highlight_timer.restart();
}
if (!h.getHeader().hasImageData()) rect.setStroke(dashed);
else {
if (highlight(n)) {
rect.setStroke(favorite);
}
else {
rect.setStroke(null);
}
}
rect.setFixed(true);
return ht||vis;
}
return false;
}
public void showSubRects()
{
showSubAction.setEnabled(false);
hideSubAction.setEnabled(true);
refreshSubAction.setEnabled(true);
showSubMode=true;
updateSubRects();
}
public void hideSubRects()
{
showSubAction.setEnabled(true);
hideSubAction.setEnabled(false);
refreshSubAction.setEnabled(false);
showSubMode=false;
getImagePane().hideAllRects();
}
public String findSubName(Point p)
{
VisibleRect r=getImagePane().findRect(p, true, true);
if (r!=null) return r.getName();
return null;
}
////////////////////////////////////////////////////////////////////////////
// Actions
////////////////////////////////////////////////////////////////////////////
private boolean highlight(MandelName n)
{
if (highlighted.isActive() && highlighted.getMandelName().equals(n)) return true;
switch (highlight_mode) {
case H_FAVORITES:
return MandUtils.isAbove(n,getEnvironment().getFavorites().getRoot());
case H_UNSEEN:
return MandUtils.isAbove(n,getEnvironment().getUnseenRastersModel().getList());
}
return false;
}
private class NoHighlightAction extends AbstractAction {
public NoHighlightAction()
{ super("None");
}
public void actionPerformed(ActionEvent e)
{
highlight_mode=H_NONE;
updateSubRects();
if (debug) System.out.println("No highlight");
}
}
private class FavoritesHighlightAction extends AbstractAction {
public FavoritesHighlightAction()
{ super("Favorites");
}
public void actionPerformed(ActionEvent e)
{
highlight_mode=H_FAVORITES;
updateSubRects();
if (debug) System.out.println("Favorites highlight");
}
}
private class UnseenHighlightAction extends AbstractAction {
public UnseenHighlightAction()
{ super("Unseen");
}
public void actionPerformed(ActionEvent e)
{
highlight_mode=H_UNSEEN;
updateSubRects();
if (debug) System.out.println("Unseen highlight");
}
}
private class LastHighlightAction extends AbstractAction {
public LastHighlightAction()
{ super("Last Area");
}
public void actionPerformed(ActionEvent e)
{
highlight_mode=H_LAST;
updateSubRects();
if (debug) System.out.println("Last highlight");
}
}
////////////////////////////////////////////////////////////////////////////
private class RecalcAction extends WindowControlAction {
public RecalcAction()
{ super(MandelImagePanel.this.getWindow(),"Refine", new Creator());
}
}
private class Creator implements WindowControlAction.WindowCreator {
public Window createWindow(Window owner)
{
return new MandelImageRecalcDialog(MandelImagePanel.this.getFrameAccess(),
"Refinement Request",
getQualifiedMandelName(),getMandelData());
}
}
////////////////////////////////////////////////////////////////////////////
private class ParentAction extends UpdatableAction {
public ParentAction()
{ super("Parent");
}
public void actionPerformed(ActionEvent e)
{
if (!getMandelName().isRoot()) {
if (automark_parent.isSet()) {
setAutoMark();
}
setImage(getMandelName().getParentName());
}
}
@Override
public void updateObject(UpdateContext ctx)
{
setEnabled(!getMandelName().isRoot());
}
}
////////////////////////////////////////////////////////////////////////////
public void setMark()
{
setMark(getQualifiedMandelName());
}
public void setMark(QualifiedMandelName n)
{
if (n==null) clearMark();
else {
marked.setQualifiedName(n);
if (marked.isActive()) {
updateSubRects();
}
updateObjects("mark",marked.getQualifiedName());
}
}
public void setAutoMark()
{
if (!marked.isSet() || !getMandelName().isAbove(marked.getMandelName())) {
setMark();
}
}
public QualifiedMandelName getMark()
{
return marked.getQualifiedName();
}
public void clearMark()
{
if (!marked.isSet()) return;
boolean was_active=marked.isActive();
marked.clear();
if (was_active) {
updateSubRects();
}
updateObjects("mark",marked.getQualifiedName());
}
/////////////////////////////
private abstract class MarkActionBase extends OptionalAction {
public MarkActionBase(String name)
{ super(name);
}
protected boolean isPossible()
{
return getMark()!=null;
}
public void actionPerformed(ActionEvent e)
{
if (isPossible()) {
markActionPerformed(e);
}
}
protected abstract void markActionPerformed(ActionEvent e);
}
private class SetMarkAction extends AbstractAction {
public SetMarkAction()
{ super("Set");
}
public void actionPerformed(ActionEvent e)
{
setMark(getQualifiedMandelName());
}
}
private class SwapMarkAction extends MarkActionBase {
public SwapMarkAction()
{ super("Swap");
}
protected void markActionPerformed(ActionEvent e)
{
QualifiedMandelName old=getQualifiedMandelName();
setImage(marked.getQualifiedName());
setMark(old);
}
}
private class ClearMarkAction extends MarkActionBase {
public ClearMarkAction()
{ super("Clear");
}
protected void markActionPerformed(ActionEvent e)
{
clearMark();
}
}
private class GotoMarkAction extends MarkActionBase {
public GotoMarkAction()
{ super("Jump");
}
protected void markActionPerformed(ActionEvent e)
{
setImage(marked.getQualifiedName());
}
@Override
public void updateObject(UpdateContext ctx)
{
super.updateObject(ctx);
putValue(Action.NAME, marked.isSet()?marked.getQualifiedName().toString()
:"Jump");
}
}
private class MemorizeMarkAction extends MarkActionBase {
public MemorizeMarkAction()
{ super("Memorize");
}
protected void markActionPerformed(ActionEvent e)
{
getEnvironment().getMemoryModel().add(marked.getQualifiedName());
}
}
private class LinkFromMarkAction extends MarkActionBase {
public LinkFromMarkAction()
{ super("Link from");
}
protected void markActionPerformed(ActionEvent e)
{
getEnvironment().addLink(marked.getMandelName(), getMandelName());
}
}
private class UnlinkFromMarkAction extends MarkActionBase {
public UnlinkFromMarkAction()
{ super("Unlink from");
}
protected void markActionPerformed(ActionEvent e)
{
getEnvironment().removeLink(marked.getMandelName(), getMandelName());
}
}
////////////////////////////////////////////////////////////////////////////
private class CommonAncestorAction extends MarkActionBase {
public CommonAncestorAction()
{ super("Common Ancestor");
}
protected void markActionPerformed(ActionEvent e)
{
MandelName n=getMandelName();
while (!n.isAbove(marked.getMandelName())) n=n.getParentName();
setImage(n, true);
}
@Override
protected boolean isPossible()
{
return super.isPossible() &&
!getMandelName().isAbove(marked.getMandelName());
}
}
////////////////////////////////////////////////////////////////////////////
public MandelName getAreaMarker(MandelName n)
{
MandelList list=getEnvironment().getAreas();
if (list!=null) {
while (!n.isRoot()) {
n=n.getParentName();
if (list.get(n)!=null) return n;
}
}
return null;
}
private class AreaUpAction extends OptionalAction {
public AreaUpAction()
{ super("Key Area");
}
public void actionPerformed(ActionEvent e)
{
MandelList list=getEnvironment().getAreas();
if (list!=null) {
MandelName n=getAreaMarker(getMandelName());
if (n!=null) {
if (automark_keyarea.isSet()) {
setAutoMark();
}
setImage(n);
}
}
}
@Override
protected boolean isPossible()
{
return getAreaMarker(getMandelName())!=null;
}
}
////////////////////////////////////////////////////////////////////////////
public MandelName getNextAreaMarker(QualifiedMandelName n)
{
if (n==null) return null;
return getNextAreaMarker(n.getMandelName());
}
public MandelName getNextAreaMarker(MandelName n)
{
if (n==null) return null;
if (!getMandelName().isHigher(n)) return null;
MandelName next=getMandelName();
MandelList list=getEnvironment().getAreas();
do {
next=next.sub(n);
}
while (!next.equals(n) && list.get(next)==null);
return next;
}
private abstract class AboveMarkAction extends MarkActionBase {
public AboveMarkAction(String name)
{
super(name);
}
@Override
protected boolean isPossible()
{
return super.isPossible() &&
getMandelName().isHigher(getMark().getMandelName());
}
/**
* prototype condition evaluation for all instances of AboveMarkAction
* not overriding isPossible methods. Must be derived class to
* provide prototype identity.
*/
private class UpdateCondition extends BooleanUpdateCondition {
public UpdateCondition()
{
super(AboveMarkAction.this.isPossible());
}
}
/**
* must be overridden, also, if a derived class redefines isPossible().
* keep expensive condition evaluation in update context to reuse
* the evaluation result for other derived classes sharing the
* same condition.
* @param ctx update context used to cache condition evaluation
* @return per update cached result of isPossible();
*/
@Override
protected boolean isPossible(UpdateContext ctx)
{
UpdateCondition c=ctx.getEntry(UpdateCondition.class);
if (c==null) {
c=ctx.setEntry(UpdateCondition.class, new UpdateCondition());
}
return c.isTrue();
}
}
private MandelName getNextForkMarker(MandelName n)
{
if (getMark()==null) return null;
MandelName name=getMark().getMandelName();
while (!n.equals(name) && (n=n.sub(name))!=null) {
Set<MandelName> set=MandUtils.getSubNames(n, env.getAllScanner());
if (set!=null&&set.size()>1) return n;
}
return null;
}
private class ForkAreaDownAction extends AboveMarkAction {
public ForkAreaDownAction()
{ super("Fork Area Down");
}
protected void markActionPerformed(ActionEvent e)
{
MandelName n=getNextForkMarker(getMandelName());
if (n!=null) {
setImage(n);
}
}
}
private class KeyAreaDownAction extends AboveMarkAction {
public KeyAreaDownAction()
{ super("Key Area Down");
}
protected void markActionPerformed(ActionEvent e)
{
MandelList list=getEnvironment().getAreas();
QualifiedMandelName name=getMark();
if (list!=null && name!=null) {
MandelName n=getNextAreaMarker(name.getMandelName());
if (n!=null) {
setImage(n);
}
}
}
}
private class AreaDownAction extends AboveMarkAction {
public AreaDownAction()
{ super("Down");
}
protected void markActionPerformed(ActionEvent e)
{
QualifiedMandelName name=getMark();
MandelName n=getMandelName();
n=n.sub(name.getMandelName());
if (n!=null) {
setImage(n);
}
}
}
private class LinksGaleryAction extends OptionalAction {
public LinksGaleryAction()
{
super("Links");
}
private MandelListModel getListModel()
{
return getEnvironment().getLinkModel(getMandelName());
}
@Override
protected boolean isPossible()
{
MandelListModel m=getListModel();
return (m!=null && !m.getList().isEmpty());
}
public void actionPerformed(ActionEvent e)
{
if (isPossible()) {
MandelListModel m=getListModel();
MandelList ml=new ArrayMandelList(m.getList());
String title="Links Galery for "+getMandelName()+
" ("+Utils.sizeString(ml.size(), "entry")+")";
System.out.println(title);
new MandelListGaleryDialog(MandelImagePanel.this.getFrameAccess(), ml, title);
}
}
}
private class KeyAreasGaleryAction extends AbstractAction {
public KeyAreasGaleryAction()
{
super("Key areas");
}
public void actionPerformed(ActionEvent e)
{
MandelListModel m=keyareas;
if (m!=null && !m.getList().isEmpty()) {
MandelList ml=new ArrayMandelList(m.getList());
String title="Key Areas Galery for "+getMandelName()+
" ("+Utils.sizeString(ml.size(), "entry")+")";
System.out.println(title);
new MandelListGaleryDialog(MandelImagePanel.this.getFrameAccess(), ml, title);
}
}
}
private class ZoomGaleryAction extends AbstractAction {
public ZoomGaleryAction()
{
super("Zoom");
}
public void actionPerformed(ActionEvent e)
{
MandelList ml=new ArrayMandelList();
MandelName n=getMandelName();
ml.add(getQualifiedName());
while (!n.isRoot()) {
n=n.getParentName();
ml.add(0, new QualifiedMandelName(n));
}
String title="Zoom Galery for "+getMandelName()
+" ("+Utils.sizeString(ml.size(), "entry")+")";
System.out.println(title);
new MandelListGaleryDialog(MandelImagePanel.this.getFrameAccess(), ml,
title);
}
}
private class LinksAction extends AbstractAction {
public LinksAction()
{ super("Links");
}
public void actionPerformed(ActionEvent e)
{
JPopupMenu m=linkhistpopup;
if (m.isEnabled()) {
RectPointEvent re=((RectangleActionEvent)e).getRectanglePointEvent();
m.show(MandelImagePanel.this,re.getX(), re.getY());
}
}
}
private class KeyAreasAction extends AbstractAction {
public KeyAreasAction()
{ super("KeyAreas");
}
public void actionPerformed(ActionEvent e)
{
if (keyareaspopupmenu.isEnabled()) {
RectPointEvent re=((RectangleActionEvent)e).getRectanglePointEvent();
JPopupMenu m=keyareaspopupmenu.getPopupMenu();
m.show(MandelImagePanel.this,re.getX(), re.getY());
}
}
}
////////////////////////////////////////////////////////////////////////////
public MandelName getFork(MandelName n)
{
MandelList list=getEnvironment().getAreas();
if (list!=null) {
while (!n.isRoot()) {
n=n.getParentName();
Set<MandelName> set=MandUtils.getSubNames(n, env.getAllScanner());
if (set!=null && set.size()>1) return n;
}
}
return null;
}
private class ForkAction extends UpdatableAction {
public ForkAction()
{ super("Last Fork");
}
public void actionPerformed(ActionEvent e)
{
MandelList list=getEnvironment().getAreas();
if (list!=null) {
MandelName n=getFork(getMandelName());
if (n!=null) {
if (automark_fork.isSet()) {
setAutoMark();
}
setImage(n);
}
}
}
@Override
public void updateObject(UpdateContext ctx)
{
setEnabled(getFork(getMandelName())!=null);
}
}
////////////////////////////////////////////////////////////////////////////
private class ShowSubAction extends AbstractAction {
public ShowSubAction()
{ super("Show Sub Areas");
}
public void actionPerformed(ActionEvent e)
{
showSubRects();
//System.out.println("shown "+this);
}
}
////////////////////////////////////////////////////////////////////////////
private class RefreshSubAction extends AbstractAction {
public RefreshSubAction()
{ super("Refresh Sub Areas");
}
public void actionPerformed(ActionEvent e)
{
updateSubRects();
}
}
////////////////////////////////////////////////////////////////////////////
private class HideSubAction extends AbstractAction {
public HideSubAction()
{ super("Hide Sub Areas");
}
public void actionPerformed(ActionEvent e)
{
hideSubRects();
}
}
////////////////////////////////////////////////////////////////////////////
private class ShowMetaAction extends AbstractAction {
public ShowMetaAction()
{ super("Image Meta Data");
}
public void actionPerformed(ActionEvent e)
{
MandelAreaViewDialog v;
QualifiedMandelName name=getQualifiedMandelName();
MandelData data=getMandelData();
// MandelHandle found=env.getImageDataScanner().getMandelData(name);
// if (found==null) {
// env.rescan();
// found=env.getImageDataScanner().getMandelData(name);
// }
// if (found!=null) {
// //System.out.println("file="+found.getFile());
// }
v=new MandelImageAreaDialog(
MandelImagePanel.this.getFrameAccess(),
"Mandel Image Meta Information",
name, data);
v.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
v.setVisible(true);
}
}
////////////////////////////////////////////////////////////////////////////
private class ShowColormapAction extends WindowControlAction<ColormapDialog> {
public ShowColormapAction(ColormapDialog cm)
{ super(MandelImagePanel.this.getWindow(),"Colormap", cm);
}
}
////////////////////////////////////////////////////////////////////////////
private class ShowListsControlAction extends AbstractAction {
public ShowListsControlAction()
{ super("Lists");
}
public void actionPerformed(ActionEvent e)
{
if (!listsDialog.isVisible()) {
listsDialog.setVisible(true);
setEnabled(false);
}
}
}
////////////////////////////////////////////////////////////////////////////
private class ShowJuliaAction extends AbstractAction {
public ShowJuliaAction()
{ super("Show Julia");
}
public void actionPerformed(ActionEvent e)
{
if (!juliaDialog.isVisible()) {
juliaDialog.setVisible(true);
juliaDialog.update(1, 1);
setEnabled(false);
}
}
}
////////////////////////////////////////////////////////////////////////////
private class ShowIterationPathAction extends AbstractAction {
public ShowIterationPathAction()
{ super("Show Iteration Path");
}
public void actionPerformed(ActionEvent e)
{
if (!iterDialog.isVisible()) {
iterDialog.setVisible(true);
iterDialog.update(getMandelInfo().getLimitIt(),1, 1);
setEnabled(false);
}
}
}
////////////////////////////////////////////////////////////////////////////
private class ShowBrowserAction extends AbstractAction {
public ShowBrowserAction()
{ super("List Browser");
}
public void actionPerformed(ActionEvent e)
{
MandelBrowserDialog b=new MandelBrowserDialog(
MandelImagePanel.this.getFrameAccess(),
getMandelBrowserModel());
b.setVisible(true);
}
}
////////////////////////////////////////////////////////////////////////////
private class CloneAction extends OptionalAction {
public CloneAction()
{
this("New Window");
}
public CloneAction(String name)
{
super(name);
}
protected boolean isPossible()
{
return getQualifiedMandelName()!=null;
}
protected QualifiedMandelName getQualifiedMandelName()
{
return MandelImagePanel.this.getQualifiedMandelName();
}
public void actionPerformed(ActionEvent e)
{
if (isPossible()) try {
QualifiedMandelName name=getQualifiedMandelName();
MandelAreaImage img=getMandelImage(name);
if (img!=null) {
getEnvironment().createMandelImageFrame(img,
(int)MandelImagePanel.this.maxx);
}
else {
mandelError("Image "+name+" not found");
}
}
catch (IOException ex) {
mandelError("Image cannot be loaded",ex);
}
}
}
////////////////////////////////////////////////////////////////////////////
private class SaveAction extends AbstractAction {
public SaveAction()
{
super("Save");
}
public void actionPerformed(ActionEvent e)
{
ToolEnvironment env=getEnvironment();
MandelImage img=getMandelImage();
MandelData d=img.getMandelData();
AbstractFile f=d.getFile();
String n=f.getName();
int ix=n.lastIndexOf('.');
long lm=f.getLastModified();
File save=env.mapToRasterImageFile(f);
d.setFile(new FileAbstractFile(save));
env.startUpdate();
try {
d.setTemporary(false);
d.getInfo().setImageCreationTime(System.currentTimeMillis());
d.write();
if (!d.getFile().equals(f)) {
if (!getEnvironment().backupRasterFile(f)) {
if (getEnvironment().isCleanupRaster()) {
//System.out.println("delete "+f);
if (f.isFile()) {
MandelFolder.Util.delete(f.getFile());
}
}
}
}
getEnvironment().getColormapCache().add(getQualifiedName(),
new Colormap(d.getColormap()));
}
catch (IOException io) {
mandelError("Image cannot be saved",io);
}
finally {
env.finishUpdate();
}
}
}
////////////////////////////////////////////////////////////////////////////
private class AreaCMSaveAction extends UpdatableAction {
public AreaCMSaveAction()
{
super("Save");
}
public void actionPerformed(ActionEvent e)
{
ToolEnvironment env=getEnvironment();
MandelImage img=getMandelImage();
MandelData d=img.getMandelData();
AbstractFile f=d.getFile();
MandelData mc=new MandelData(d.getInfo());
mc.setColormap(ColormapModel.ResizeMode.RESIZE_LOCK_COLORS, d.getColormap());
String n=f.getName();
int ix=n.lastIndexOf('.');
long lm=f.getLastModified();
File save=env.mapToAreaColormapFile(f);
mc.setFile(new FileAbstractFile(save));
env.startUpdate();
try {
mc.setTemporary(false);
mc.write();
getEnvironment().getColormapCache().add(getQualifiedName(),
new Colormap(mc.getColormap()));
updateObjects("areacm",getMandelName());
}
catch (IOException io) {
mandelError("Area colormap cannot be saved",io);
}
finally {
env.finishUpdate();
}
}
@Override
public void updateObject(UpdateContext ctx)
{
System.out.println(ctx.getReason().getReason()+": "+getMandelData().isModified());
setEnabled(getMandelData().isModified());
}
}
////////////////////////////////////////////////////////////////////////////
private class AreaCMDeleteAction extends UpdatableAction {
public AreaCMDeleteAction()
{
super("Delete");
}
public void actionPerformed(ActionEvent e)
{
ToolEnvironment env=getEnvironment();
MandelHandle h=null;
Set<MandelHandle> set=env.getAreaColormapScanner().getMandelHandles(getMandelName());
if (set!=null) {
for (MandelHandle mh:set) {
if (mh.getHeader().isAreaColormap()) {
h=mh;
break;
}
}
}
if (h!=null) {
env.startUpdate();
try {
if (h.getFile().isFile()) {
MandelFolder.Util.delete(h.getFile().getFile());
getEnvironment().getColormapCache().remove(getMandelName());
updateObjects("areacm",getMandelName());
}
}
catch (IOException io) {
mandelError("Area colormap "+h.getFile()+"cannot be deleted", io);
}
finally {
env.finishUpdate();
}
}
}
@Override
public void updateObject(UpdateContext ctx)
{ boolean b=false;
Set<MandelHandle> set=env.getAreaColormapScanner().getMandelHandles(getMandelName());
if (set!=null) {
for (MandelHandle mh:set) {
if (mh.getHeader().isAreaColormap()) {
b=true;
break;
}
}
}
setEnabled(b);
}
}
////////////////////////////////////////////////////////////////////////////
private class AreaCMAction extends UpdatableAction {
private MandelName name;
public AreaCMAction()
{
super("Upstream");
}
public void actionPerformed(ActionEvent e)
{
MandelImagePanel.this.setImage(name);
}
@Override
public void updateObject(UpdateContext ctx)
{ boolean b=false;
MandelName n=getMandelName();
do {
Set<MandelHandle> set=env.getAreaColormapScanner().
getMandelHandles(n);
if (set!=null) {
for (MandelHandle mh:set) {
if (mh.getHeader().isAreaColormap()) {
b=true;
break;
}
}
}
if (!b) n=n.getParentName();
}
while (!b && n!=null);
setEnabled(b);
if (b) {
name=n;
putValue(Action.NAME, n.getName());
}
else {
putValue(Action.NAME,"upstream");
}
}
}
////////////////////////////////////////////////////////////////////////////
private class HomeAction extends UpdatableAction {
public HomeAction()
{
super("Home");
}
public void actionPerformed(ActionEvent e)
{
setImage(MandelName.ROOT);
}
@Override
public void updateObject(UpdateContext ctx)
{
setEnabled(!getMandelName().isRoot());
}
}
////////////////////////////////////////////////////////////////////////////
private abstract class AbstractListAction extends AbstractAction {
private MandelListModel model;
public AbstractListAction(MandelListModel model, String cmd)
{ super(cmd);
this.model=model;
}
public MandelListModel getModel()
{ return model;
}
}
////////////////////////////////////////////////////////////////////////////
private class AddListEntryAction extends AbstractListAction {
public AddListEntryAction(MandelListModel model)
{ super(model,"Add");
}
public void actionPerformed(ActionEvent e)
{ getModel().add(name);
}
}
////////////////////////////////////////////////////////////////////////////
private class RemoveListEntryAction extends AbstractListAction {
public RemoveListEntryAction(MandelListModel model)
{ super(model,"Remove");
}
public void actionPerformed(ActionEvent e)
{ getModel().remove(name);
}
}
////////////////////////////////////////////////////////////////////////////
private class RemoveListShortcutAction extends AbstractListAction {
public RemoveListShortcutAction(MandelListModel model)
{
super(model,"Remove Shortcut");
}
public void actionPerformed(ActionEvent e)
{
removeListShortcut(getModel());
}
}
////////////////////////////////////////////////////////////////////////////
private class OpenListShortcutAction extends AbstractListAction {
private String name;
public OpenListShortcutAction(MandelListTableModel model, String name)
{
super(model,"Open List");
this.name=name;
}
public void actionPerformed(ActionEvent e)
{
new MandelListDialog(getFrameAccess(),name,(MandelListTableModel)getModel());
}
}
////////////////////////////////////////////////////////////////////////////
private class VariationAction extends AbstractAction {
public VariationAction()
{ super("Variation");
}
public void actionPerformed(ActionEvent e)
{
MandelVariationCreationDialog f=
new MandelVariationCreationDialog(
MandelImagePanel.this.getFrameAccess(),
"Variation for "+getMandelName());
f.setVisible(true);
}
}
private class AboutAction extends AbstractAction {
public AboutAction()
{
super("About");
}
public void actionPerformed(ActionEvent e)
{
new AboutBox(MandelImagePanel.this.getWindow()).setVisible(true);
}
}
private class GotoAction extends WindowControlAction<GotoDialog> {
public GotoAction()
{
super(MandelImagePanel.this.getMandelWindow(),
"Goto",new GotoDialog(MandelImagePanel.this));
}
}
////////////////////////////////////////////////////////////////////////////
private void mandelError(String msg)
{
JOptionPane.showMessageDialog(MandelImagePanel.this,
msg,
"Error",
JOptionPane.ERROR_MESSAGE);
}
private void mandelError(String msg, Exception ex)
{
JOptionPane.showMessageDialog(MandelImagePanel.this,
msg+": "+ex,
"Error",
JOptionPane.ERROR_MESSAGE);
}
private void mandelInfo(String msg)
{
JOptionPane.showMessageDialog(MandelImagePanel.this,
msg,
"Info",
JOptionPane.INFORMATION_MESSAGE);
}
public class SelectAreaListener implements RectEventListener,
RectModifiedEventListener {
private MandelHandle getMandelInfo(String n)
{ MandelHandle data=null;
MandelName name=MandelName.create(n);
if (name!=null) {
data=env.getImageDataScanner().getMandelInfo(name);
if (data==null) {
//System.out.println("no image found for "+name);
data=env.getMetaScanner().getMandelInfo(name);
}
if (data==null) {
env.rescan();
data=env.getMetaScanner().getMandelInfo(name);
}
if (data==null) {
mandelError("cannot find mandel data for area "+name);
}
}
return data;
}
private void updateDialog(VisibleRect rect, MandelHandle data,
boolean created)
{
//System.out.println("update info");
if (created) {
// start new area
create.setRect(null);
if (data!=null) {
create.setAutoMode(false);
create.setFilename(data.getFile().getPath(), false);
}
else {
create.setAutoMode(true);
create.setFilename(null, true);
}
}
inupdate=true;
rect.setVisible(true);
create.setRect(rect);
create.setVisible(true);
inupdate=false;
//System.out.println("update info done");
}
public void buttonClicked(RectEvent e)
{ VisibleRect rect=e.getRect();
String n=rect.getName();
//System.out.println("clicked at area "+n);
if (e.getButton()==MouseEvent.BUTTON1 && e.getClickCount()==2) {
// edit are meta data
if (e.isControlDown() && !isReadonly()) {
if (!com.mandelsoft.util.Utils.isEmpty(n)&&rect.getOwner()!=null) {
MandelHandle data=getMandelInfo(n);
if (data!=null) {
if (!data.getHeader().isInfo()) {
mandelError("area "+n+" already proccesed");
return;
}
rect.setFixed(false);
updateDialog(rect,data,true);
}
}
}
// show area meta data
else if (e.isShiftDown()) {
MandelAreaViewDialog v;
if (!com.mandelsoft.util.Utils.isEmpty(n)&&rect.getOwner()!=null) {
MandelHandle data=getMandelInfo(n);
if (data!=null) {
try {
v=new MandelImageAreaDialog(MandelImagePanel.this.getFrameAccess(),
"Mandel Image Meta Information",
data.getName(), data.getInfo());
v.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
v.setVisible(true);
}
catch (IOException ex) {
System.err.println("*** cannot read "+data.getFile()+": "+ex);
}
}
}
}
// show area as image
else {
//System.out.println("rect selected for image "+e.getRect());
if (!com.mandelsoft.util.Utils.isEmpty(n)&&rect.getOwner()!=null) {
MandelName name=MandelName.create(n);
if (name!=null) {
setImage(name);
}
}
}
// end chain
}
if (e.getButton()==MouseEvent.BUTTON1 && e.getClickCount()==1) {
// show sub sub areas
if (e.isAltDown()) {
if (debug) System.out.println("show sub sub "+n);
if (!com.mandelsoft.util.Utils.isEmpty(n)&&rect.getOwner()!=null) {
MandelHandle data=getMandelInfo(n);
if (data!=null) {
showSubRect(data.getName(),true);
updateSubRects(data.getName().getMandelName(),true);
}
}
repaint();
}
}
}
synchronized
public void rectModified(RectModifiedEvent e)
{ VisibleRect rect=e.getRect();
MandelInfo info;
boolean created;
if (e.getAction()==RectModifiedEvent.RECT_CREATED) {
if (debug) System.out.println("rect created "+rect+
" prop="+(((double)rect.getWidth())/rect.getHeight()));
info=new MandelInfo(MandelImagePanel.this.getMandelInfo());
info.setKeywords(new HashSet<String>());
rect.setOwner(info);
created=true;
}
else {
//System.out.println("rect modified "+e.getRect());
info=(MandelInfo)rect.getOwner();
//System.out.println(" owner="+info);
created=false;
}
//System.out.println("RECT "+info);
if (info!=null) {
updateInfo(info,rect._getRect());
ProportionProvider p=proportion.getProportionProvider();
if (p!=imagepropprov) {
if (!created) {
MandelInfo dia=create.getInfo();
info.setRX(dia.getRX());
info.setRY(dia.getRY());
System.out.println(""+dia.getRX()+"/"+dia.getRY());
}
// adjust pixel size according to selected proportion
if (((double)info.getRX())/info.getRY()!=p.getProportion()) {
info.setRY((int)((double)info.getRX()/p.getProportion()));
}
}
updateDialog(rect,null,created);
}
}
}
private boolean inupdate;
synchronized
public void updateInfo(MandelInfo info, Rectangle rect)
{
if (getMandelInfo()==null) return;
//System.out.println("parent is "+getMandelInfo());
ToolUtils.updateInfo(info, rect, getMandelInfo(),filterscale);
}
synchronized
public void updateRect(VisibleRect rect, MandelInfo info)
{
if (inupdate || getMandelInfo()==null) return;
ToolUtils.updateRect(info,rect,getMandelInfo(),filterscale);
//System.out.println("update rect "+rect+"("+inupdate+")");
}
public class SubAreaListener implements MandelAreaListener {
public void areaActionPerformed(MandelAreaEvent e)
{
if (debug) System.out.println("sub area event "+e.getId());
MandelName name=e.getName();
if (e.getId()==MandelAreaEvent.MA_UPDATE) {
updateSubRects();
}
if (e.getId()==MandelAreaEvent.MA_CREATED) {
MandelInfo info=e.getInfo();
VisibleRect rect=e.getRect();
if (debug) try {
System.out.println("area selected name="+name+", info="+info+
",rect="+rect+" prop="+(rect.getWidth()/rect.getHeight()));
}
catch (RuntimeException ex) {
}
if (name!=null&&info!=null&&rect!=null) {
// keep rect, notfy as handled
if (!subAreasShown()) {
System.out.println("*** keep rect");
((MandelSubAreaCreationDialog)e.getSource()).setRectHandled();
// rect.discard();
//MandelImagePanel.this.getImagePane().findRect(name.getMandelName());
rect.setName(name.getName());
rect.setLabel(getLabel(name));
rect.setOwner(new MandelInfo(info));
rect.setFixed(true);
rect.activate();
}
}
}
if (e.getId()==MandelAreaEvent.MA_DELETED) {
VisibleRect rect=e.getRect();
if (rect!=null) {
if (debug) System.out.println("discard rect");
rect.discard();
}
updateSubRects();
}
}
}
/////////////////////////////////////////////////////////////////////////
// Info Popup
/////////////////////////////////////////////////////////////////////////
public class InfoPopup extends RenderedComponent {
private JLayeredPane active;
private JTextField info;
private JTextField magn;
private JTextField min;
private JTextField max;
private JTextField time;
private Timer timer;
private QualifiedMandelName name;
public InfoPopup()
{
timer=new Timer(2000,new HideHandler());
JPanel effective=new JPanel();
FlowLayout l=(FlowLayout)effective.getLayout();
l.setHgap(5);
l.setVgap(5);
effective.add(new JLabel("Info: "));
effective.add(info=createField());
effective.add(new JLabel("Magn: "));
effective.add(magn=createField());
effective.add(new JLabel("Min: "));
effective.add(min=createField());
effective.add(new JLabel("Max: "));
effective.add(max=createField());
effective.add(new JLabel("Time: "));
effective.add(time=createField());
effective.validate();
setEffectiveComponent(effective);
setOpaque(false);
addMouseListener(new MouseListener());
}
private JTextField createField()
{
JTextField f=new JTextField("");
f.setEditable(false);
f.setBorder(null);
return f;
}
public boolean isActive()
{
return active!=null;
}
public void setData(MandelInfo i, QualifiedMandelName name)
{
int m=MandUtils.getMagnification(i);
setMagnification(m);
setInfo(name);
setMin(i.getMinIt());
setMax(i.getMaxIt());
setTime(i.getTime());
}
public void setInfo(QualifiedMandelName name)
{
this.name=name;
updateInfo();
}
private void updateInfo()
{
String info=MandelAreaViewDialog.getInfoString(getEnvironment(),name);
int ic=count(name.getMandelName(), getEnvironment().getImageDataScanner());
if (!info.isEmpty()) info+=", ";
if (ic==1) info=info+""+ic+" sub area";
else info=info+""+ic+" sub areas";
setInfo(info);
validate();
}
public void setInfo(String v)
{
if (v==null || v.length()==0) v=" ";
info.setText(v);
}
public void setMagnification(int v)
{
magn.setText("1e"+v);
}
public void setMin(int v)
{
min.setText(""+v);
}
public void setMax(int v)
{
max.setText(""+v);
}
public void setTime(long t)
{
time.setText(MandelImageAreaDialog.formatTime(t));
}
public void showAt(Component c, Point p)
{
timer.start();
updateInfo();
JRootPane rp=SwingUtilities.getRootPane(c);
Point rpp=SwingUtilities.convertPoint(c, p, rp);
Dimension d=getPreferredSize();
setVisible(true);
setBounds(rpp.x, rpp.y, (int)d.getWidth(), (int)d.getHeight());
if (debug) System.out.println("show "+getBounds());
(active=rp.getLayeredPane()).add(this, JLayeredPane.PALETTE_LAYER+1);
rp.repaint();
}
private void _hide()
{
if (debug) System.out.println("disable popup");
timer.stop();
setVisible(false);
if (active!=null) {
active.remove(InfoPopup.this);
}
active=null;
}
/////////////////////////////////////////////////
private class MouseListener extends MouseAdapter {
@Override
public void mouseEntered(MouseEvent e)
{
timer.stop();
}
@Override
public void mouseExited(MouseEvent e)
{
timer.restart();
}
}
private class HideHandler implements ActionListener {
public void actionPerformed(ActionEvent e)
{
_hide();
}
}
}
private InfoPopup infoPopup=new InfoPopup();
public void showInfoPopup()
{
JViewport vp=scrollpane.getViewport();
Rectangle vr=vp.getViewRect();
int w=vr.width/2;
Dimension d=infoPopup.getPreferredSize();
Point dst=new Point(w-d.width/2/*+vr.x*/, 0/*vr.y*/);
infoPopup.showAt(this, dst);
}
public class PixelListener extends MouseAdapter {
@Override
public void mouseMoved(MouseEvent e)
{
int px,py;
/********************************************/
JViewport vp=scrollpane.getViewport();
Rectangle vr=vp.getViewRect();
px=e.getX()-vr.x;
py=e.getY()-vr.y;
if (py<BufferedComponent.CORNER_RECT) {
int w=vr.width/2;
if (Math.abs(w-px)<BufferedComponent.CORNER_RECT*6) {
if (debug) {
JRootPane rp=SwingUtilities.getRootPane(e.getComponent());
Point rpp=SwingUtilities.convertPoint(e.getComponent(), e.getPoint(),
rp);
System.out.println(":"+e.getX()+","+e.getY()+":"+vp.getViewRect()
+"--- "+rpp.x+","+rpp.y);
}
if (!infoPopup.isActive()) {
showInfoPopup();
// Dimension d=infoPopup.getPreferredSize();
// Point dst=new Point(w-d.width/2+vr.x, vr.y);
// infoPopup.showAt(e.getComponent(), dst);
}
}
}
/********************************************/
px=(int)(buffer.translateX(e)/filterscale);
py=(int)(buffer.translateY(e)/filterscale);
if (e.isAltDown()) {
// notify julia dialog
if (juliaDialog.isVisible() || iterDialog.isVisible()) {
//System.out.println("julia "+e.getX()+","+e.getY());
MandelInfo parent=getMandelInfo();
BigDecimal x=MandArith.sub(parent.getXM(),
MandArith.div(parent.getDX(), 2));
BigDecimal y=MandArith.add(parent.getYM(),
MandArith.div(parent.getDY(), 2));
BigDecimal jx=MandArith.add(x,MandArith.div(
MandArith.mul(parent.getDX(),px),parent.getRX()));
BigDecimal jy=MandArith.sub(y,MandArith.div(
MandArith.mul(parent.getDY(),py),parent.getRY()));
if (juliaDialog.isVisible())
juliaDialog.update(jx.doubleValue(), jy.doubleValue());
if (iterDialog.isVisible())
iterDialog.update(parent.getLimitIt(),jx.doubleValue(), jy.doubleValue());
}
}
try {
// notify colormap dialog to highlight colormap entry
if (hasColormap()) {
//System.out.println("x: "+e.getX()+" -> "+px);
//System.out.println("y: "+e.getY()+" -> "+py);
colormapDialog.hightLight(
getMandelImage().getColormapIndex(px,py));
}
}
catch (UnsupportedOperationException ex) {
}
}
}
////////////////////////////////////////////////////////////////////////////
// temporary area highlighting
////////////////////////////////////////////////////////////////////////////
private class HighlightHandler implements ActionListener {
public void actionPerformed(ActionEvent e)
{
if (highlight_active) {
stopHighLight();
updateSubRects();
}
}
}
private void stopHighLight()
{
if (highlight_active) highlight_timer.stop();
highlight_active=false;
highlighted.clear();
}
////////////////////////////////////////////////////////////////////////////
// colormap rotation
////////////////////////////////////////////////////////////////////////////
private static class Rotator extends Timer implements ActionListener {
private ColormapModel model;
private Colormap orig;
private boolean active;
private boolean updating;
private Action rotate=new RotateAction();
private Action stop=new StopAction();
private ChangeListener listener=new StopListener();
public Rotator(ColormapModel model)
{
super(100, null);
addActionListener(this);
this.model=model;
setActive(false);
}
public JMenu createMenu()
{
JMenu menu=new JMenu("Rotate Colors");
menu.add(new JMenuItem(rotate));
menu.add(new JMenuItem(stop));
return menu;
}
private void setActive(boolean b)
{
active=b;
rotate.setEnabled(!b);
stop.setEnabled(b);
}
public void rotate()
{
if (!active) {
setActive(true);
orig=model.getColormap();
model.setColormap(new Colormap(orig));
model.addChangeListener(listener);
start();
}
}
public void cancel()
{
cancel(true);
}
private void cancel(boolean reset)
{
if (active) {
setActive(false);
stop();
model.removeChangeListener(listener);
if (reset) model.setColormap(orig);
}
}
public void actionPerformed(ActionEvent e)
{
Colormap cm=model.getColormap();
updating=true;
cm.startModification();
Color old=cm.getColor(1);
for (int i=2; i<cm.getSize(); i++) {
cm.setColor(i-1, cm.getColor(i));
}
cm.setColor(cm.getSize()-1, old);
cm.endModification();
updating=false;
start();
}
private class StopListener implements ChangeListener {
public void stateChanged(javax.swing.event.ChangeEvent e)
{
if (!updating) cancel(false);
}
}
private class RotateAction extends AbstractAction {
public RotateAction()
{ super("Rotate");
}
public void actionPerformed(ActionEvent e)
{
rotate();
}
}
private class StopAction extends AbstractAction {
public StopAction()
{
super("Stop");
}
public void actionPerformed(ActionEvent e)
{
cancel();
}
}
}
///////////////////////////////////////////////////////////////////////////
// renew state listeners
///////////////////////////////////////////////////////////////////////////
private List<RenewStateListener> rnlisteners=new ArrayList<RenewStateListener>();
public void addRenewStateListener(RenewStateListener l)
{
rnlisteners.add(l);
}
public void removeRenewStateListener(RenewStateListener l)
{
rnlisteners.remove(l);
}
protected void fireRenewState()
{
for (RenewStateListener l:rnlisteners) {
try {
l.renewState(getWindow());
}
catch (Exception e) {
e.printStackTrace(System.err);
}
}
}
///////////////////////////////////////////////////////////////////////////
// main
///////////////////////////////////////////////////////////////////////////
private static class TestFrame extends JFrame
implements MandelWindowAccess {
MandelImagePanel panel;
public TestFrame(ToolEnvironment env, MandelAreaImage img) throws IOException
{
panel=new MandelImagePanel(env,img);
add(panel);
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public ColormapModel getColormapModel()
{
return panel.getColormapModel();
}
public ToolEnvironment getEnvironment()
{
return panel.getEnvironment();
}
public Window getMandelWindow()
{
return this;
}
public MandelData getMandelData()
{
return panel.getMandelData();
}
public MandelImage getMandelImage()
{
return panel.getMandelImage();
}
public MandelName getMandelName()
{
return panel.getMandelName();
}
public MapperModel getMapperModel()
{
return panel.getMapperModel();
}
public QualifiedMandelName getQualifiedName()
{
return panel.getQualifiedName();
}
public MandelImagePanel getMandelImagePane()
{
return panel;
}
public History getHistory()
{
return panel.getHistory();
}
}
public static void main(final String[] args)
{
try {
ToolEnvironment env;
env=new ToolEnvironment(args);
synchronized (env) {
try {
createWindow(env);
}
catch (IllegalArgumentException ia) {
System.out.println("illegal mandel name");
}
}
}
catch (IllegalConfigurationException ex) {
System.out.println("illegal config: "+ex);
}
}
static void createWindow(final ToolEnvironment env)
{
EventQueue.invokeLater(new Runnable() {
public void run()
{
synchronized (env) {
try {
MandelAreaImage img=env.getMandelImage(env.getInitialName());
JFrame frame=new TestFrame(env, img);
}
catch (IOException io) {
System.out.println("cannot read image");
}
}
}
});
}
}