/*
* #!
* Ontopia Vizigator
* #-
* Copyright (C) 2001 - 2013 The Ontopia Project
* #-
* 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 net.ontopia.topicmaps.viz;
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.swing.Icon;
import com.touchgraph.graphlayout.Edge;
import com.touchgraph.graphlayout.Node;
import com.touchgraph.graphlayout.TGPanel;
/**
* INTERNAL: Common abstract superclass for all nodes representing
* Topic Maps constructs.
*/
public abstract class TMAbstractNode extends Node implements Recoverable {
protected Icon icon;
protected boolean underMouse = false;
protected TopicMapView topicMapView;
public TMAbstractNode(String id) {
super(id);
super.setVisible(true);
}
/**
* setVisible is not supported in Vizigator.
*/
public final void setVisible(boolean visible) {
}
/**
* Workaround that avoids mouseover icon hanging around after hiding node.
*/
public void removeMouseoverIcon() {
underMouse = false;
}
public static Color textColourForBackground(Color c) {
if (((c.getRed() + c.getGreen() + c.getBlue()) / 3) > 130)
return Color.black;
return Color.white;
}
public boolean hasPathTo(TMAbstractNode target, Set visited) {
if (equals(target)) return true;
if (visited.contains(this)) return false;
visited.add(this);
for (Iterator iter = getVisibleEdges(); iter.hasNext();) {
TMAbstractEdge edge = (TMAbstractEdge) iter.next();
TMAbstractNode neighbour = (TMAbstractNode) edge.getOtherEndpt(this);
if (neighbour.hasPathTo(target, visited)) return true;
}
return false;
}
/**
* @return An iterator on all the edges.
*/
public Iterator getEdges() {
// For some strange reason, the superclass implementation
// of this method returns NULL if there are no edges !!!
Iterator result = super.getEdges();
if (result == null) return Collections.EMPTY_LIST.iterator();
return result;
}
/**
* @return An iterator on the edges that are currently visible.
*/
public Iterator getVisibleEdges() {
ArrayList result = new ArrayList();
for (Iterator iter = getEdges(); iter.hasNext();) {
Edge edge = (Edge) iter.next();
if (edge.isVisible())
result.add(edge);
}
return result.iterator();
}
/**
* @return A list of the edges that are currently visible.
*/
public List getVisibleEdgesList() {
ArrayList result = new ArrayList();
for (Iterator iter = getEdges(); iter.hasNext();) {
Edge edge = (Edge) iter.next();
if (edge.isVisible()) result.add(edge);
}
return result;
}
/**
* Set the node background color. Also applies a simple colour inversion
* algorithm on the text colour.
*/
public void setBackColor(Color bgColor) {
super.setBackColor(bgColor);
setTextColor(TMAbstractNode.textColourForBackground(bgColor));
}
public Icon getIcon() {
return icon;
}
public void setIcon(Icon icon) {
this.icon = icon;
}
public Color getPaintBorderColor(TGPanel tgPanel) {
if (this == tgPanel.getDragNode()) return BORDER_DRAG_COLOR;
else if (this == tgPanel.getMouseOverN()) return BORDER_MOUSE_OVER_COLOR;
return TGPanel.BACK_COLOR;
}
public Color getPaintBackColor(TGPanel tgPanel) {
// Overwritten to allways show @backColor except when selected
if (this == tgPanel.getSelect()) return BACK_SELECT_COLOR;
return backColor;
}
protected void drawNeighboursInForeground(Graphics g, TGPanel tgPanel) {
int ix = (int)drawx;
int iy = (int)drawy;
double d = Math.sqrt(getWidth() * getWidth() + getHeight() * getHeight());
// Calculate size of circle, based on neighbouring nodes.
Iterator edges = getEdges();
while (edges.hasNext()) {
TMAbstractEdge currentEdge = (TMAbstractEdge)edges.next();
TMAbstractNode currentNode = (TMAbstractNode)currentEdge
.getOtherEndpt(this);
topicMapView.queueInForeground(currentEdge);
topicMapView.queueInForeground(currentNode);
double currentX = currentNode.drawx;
double currentY = currentNode.drawy;
double currentWidth = Math.abs((drawx - currentX) * 2) +
currentNode.getWidth();
double currentHeight = Math.abs((drawy - currentY) * 2) +
currentNode.getHeight();
double currentD = (int)Math.sqrt(currentWidth * currentWidth +
currentHeight * currentHeight);
if (currentD > d)
d = currentD;
}
int diameter = (int)d;
Color circleColor = Color.darkGray;
int red = circleColor.getRed();
int green = circleColor.getGreen();
int blue = circleColor.getBlue();
int alpha = (int)(circleColor.getAlpha() * 0.75);
circleColor = new Color(red, green, blue, alpha);
g.setColor(circleColor);
if (topicMapView.controller.showNeighbouringCircle)
g.fillOval(ix - diameter/2, iy - diameter / 2, diameter, diameter);
topicMapView.queueInForeground(this);
}
/**
* This is how TG gets the color it actually uses for the painting, which in
* our case may be different from the preset text color.
*/
public Color getPaintTextColor(TGPanel tgPanel) {
if (this == tgPanel.getSelect())
// given the select color, black is right
return Color.black;
return textColor; // this is what the TG impl of this method does
}
protected void setUnderMouse(TGPanel tgPanel) {
underMouse = (tgPanel.getMouseOverN() == this);
}
public void setUnderMouseForced(boolean under) {
underMouse = under;
}
}