package cytoscape.editor.cyAnnotator.Annotations; import java.awt.*; import java.awt.event.*; import cytoscape.editor.cyAnnotator.modifyAnnotations.mArrow; import cytoscape.editor.cyAnnotator.modifyAnnotations.mTextAnnotation; import cytoscape.Cytoscape; import cytoscape.ding.DingNetworkView; import ding.view.*; import javax.swing.*; import java.util.*; /** * * @author Avinash Thummala */ //A BasicTextAnnotation Class public class TextAnnotation extends Component{ private String text; private int componentNumber=0; public double zoom, tempZoom, arrowLength=7.0;; private int initialFontSize=12, arrowIndex=0; public Font font=new Font("Arial", Font.PLAIN,initialFontSize); private Color color=Color.BLACK, arrowColor=Color.BLACK; private boolean drawArrow=false, arrowDrawn=false, selected=false; public boolean pointOnArrow=false; private ArrayList arrowEndPoints; private BasicStroke arrowStroke=new BasicStroke(2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); public boolean usedForPreviews=false; public TextAnnotation(){ } public TextAnnotation(int x, int y, String text, int compCount, double zoom){ this.text=text; this.componentNumber=compCount; this.zoom=zoom; this.setLocation(x, y); } //Verification methods public boolean isImageAnnotation(){ return false; } public boolean isShapeAnnotation(){ return false; } public boolean isTextAnnotation(){ return true; } public boolean isBoundedAnnotation(){ return false; } public boolean isSelected(){ return selected; } public boolean isPointOnLine(int x, int y, int x1, int y1, int x2, int y2) { if( Math.abs( Math.abs( (y-y1)*(x2-x1) )-Math.abs( (y2-y1)*(x-x1) ) )<120 ) return true; else return false; } public boolean isPointOnThickLine(int x, int y, int x1, int y1, int x2, int y2, int xCounter, int yCounter) { int numRounds=3; for(int i=numRounds;i>=0;i--){ if(isPointOnLine(x, y, x1+i*xCounter, y1+i*yCounter, x2+i*xCounter, y2+i*yCounter)) return true; } xCounter*=-1; yCounter*=-1; for(int i=numRounds;i>=1;i--){ if(isPointOnLine(x, y, x1+i*xCounter, y1+i*yCounter, x2+i*xCounter, y2+i*yCounter)) return true; } return false; } public boolean isPointOnArrow(int x, int y, int x1, int y1, int x2, int y2){ if(x2>=x1) { if(y2>=y1) { if( isPointOnThickLine(x, y, x1, y1, x2, y2, -1, 1) ) return true; } else { if( isPointOnThickLine(x, y, x1, y1, x2, y2, -1, -1)) return true; } } else { if(y2>=y1) { if( isPointOnThickLine(x, y, x2, y2, x1, y1, -1, -1)) return true; } else { if( isPointOnThickLine(x, y, x2, y2, x1, y1, -1, 1)) return true; } } return false; } public int isPointOnArrow(int x, int y){ if(!arrowDrawn) return -1; for(int i=0;i<arrowEndPoints.size();i++){ Point p=getArrowStartPoint((TextAnnotation)arrowEndPoints.get(i)); if( isPointOnArrow(x, y, p.x, p.y, ((TextAnnotation)arrowEndPoints.get(i)).getX(), ((TextAnnotation)arrowEndPoints.get(i)).getY() ) ) return i; } return -1; } public boolean isPointInComponentOnly(int pX, int pY){ int x=getX(), y=getY(); if(pX>=x && pX<=(x+getAnnotationWidth()) && pY>=y && pY<=(y+getAnnotationHeight()) ) return true; else return false; } public boolean isPointInComponent(int pX, int pY){ if( isPointInComponentOnly(pX,pY) ) return true; else { int temp=isPointOnArrow(pX, pY); arrowIndex=temp; if(arrowIndex==-1) pointOnArrow=false; else pointOnArrow=true; return pointOnArrow; } } //Get Methods public Color getArrowColor(){ return arrowColor; } public Color getTextColor(){ return color; } public int getZone(int x, int y){ if(isPointInComponentOnly(x, y)) return 0; int midX=getTopX()+getAnnotationWidth()/2, midY=getTopY(); if(x<=midX){ if(y<=midY) return 3; else if(y<=midY+getAnnotationHeight()) return 4; else return 5; } else{ if(y<=midY) return 2; else if(y<=midY+getAnnotationHeight()) return 1; else return 6; } } public int getQuadrant(Point p1, Point p2){ if(p2.x >= p1.x){ if(p2.y<=p1.y) return 1; else return 4; } else{ if(p2.y<=p1.y) return 2; else return 3; } } public Point getArrowStartPoint(TextAnnotation temp){ int x=0, y=0, zone=getZone(temp.getX(), temp.getY()); if(zone==1){ x=getTopX()+getAnnotationWidth(); y=getTopY()+getAnnotationHeight()/2; } else if(zone==2 || zone==3){ x=getTopX()+getAnnotationWidth()/2; y=getTopY(); } else if(zone==4){ x=getTopX(); y=getTopY()+getAnnotationHeight()/2; } else{ x=getTopX()+getAnnotationWidth()/2; y=getTopY()+getAnnotationHeight(); } return new Point(x,y); } public int getTopX(){ return getX(); } public int getTopY(){ return getY(); } public BasicStroke getArrowStroke(){ return arrowStroke; } public int getAnnotationWidth(){ return getTextWidth(); } public int getAnnotationHeight(){ return getTextHeight(); } public boolean getArrowDrawn(){ return arrowDrawn; } public double getZoom(){ return zoom; } public boolean getDrawArrow(){ return drawArrow; } public int getComponentNumber(){ return componentNumber; } @Override public Font getFont(){ return font; } public String getText(){ return text; } public double getTempZoom(){ return tempZoom; } public int getTextWidth(){ FontMetrics fontMetrics=this.getGraphics().getFontMetrics(font); return fontMetrics.stringWidth(text); } public int getTextHeight(){ FontMetrics fontMetrics=this.getGraphics().getFontMetrics(font); return fontMetrics.getHeight(); } public int getTextWidth(Graphics2D g2){ FontMetrics fontMetrics=g2.getFontMetrics(font); return fontMetrics.stringWidth(text); } public int getTextHeight(Graphics2D g2){ FontMetrics fontMetrics=g2.getFontMetrics(font); return fontMetrics.getHeight(); } @Override public Component getComponentAt(int x, int y) { if(isPointInComponent(x,y)) return this; else return null; } //Set methods public void setArrowPoints(int pX, int pY){ int zone=getZone(pX,pY); if(zone==0){ arrowDrawn=false; return; } else{ if(arrowEndPoints==null) arrowEndPoints=new ArrayList(); //The ArrowEndPoints are also set up as TextAnnotations of null size. //They have been implemented this way, so as to handle the change in viewports TextAnnotation arrowEndPoint=new TextAnnotation(pX, pY,"",((DingNetworkView)Cytoscape.getCurrentNetworkView()).getCanvas(DGraphView.Canvas.FOREGROUND_CANVAS).getComponentCount(), ((DingNetworkView)Cytoscape.getCurrentNetworkView()).getZoom()); arrowEndPoint.setSize(0, 0); ((ArbitraryGraphicsCanvas)((DingNetworkView)Cytoscape.getCurrentNetworkView()).getCanvas(DGraphView.Canvas.FOREGROUND_CANVAS)).add(arrowEndPoint); arrowEndPoints.add(arrowEndPoint); } } public void setArrowStroke(BasicStroke newStroke){ arrowStroke=newStroke; } public void setDrawArrow(boolean val){ drawArrow=val; } public void setArrowDrawn(boolean val){ arrowDrawn=val; } public void setZoom(double zoom){ this.zoom=zoom; } public void setSelected(boolean val){ this.selected=val; } public void setComponentNumber(int val){ componentNumber=val; } @Override public void setFont(Font newFont){ font=newFont; } public void setTextColor(Color newColor){ this.color=newColor; } public void setEdgeColor(Color newColor){ } public void setFillColor(Color newColor){ } public void setArrowColor(Color newColor){ arrowColor=newColor; } public void setText(String newText){ this.text=newText; } public void setTempZoom(double zoom){ this.tempZoom=zoom; } public void print(Graphics g){ paint(g); } @Override public void paint(Graphics g) { Graphics2D g2=(Graphics2D)g; //Setting up Anti-aliasing for high quality rendering g2.setComposite(AlphaComposite.Src); g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR); g2.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON); if(arrowDrawn){ //For any annotation that points to some locations for(int i=0;i<arrowEndPoints.size();i++){ Point p=getArrowStartPoint((TextAnnotation)arrowEndPoints.get(i)); g2.setColor( ((TextAnnotation)arrowEndPoints.get(i)).getArrowColor() ); g2.setStroke( ((TextAnnotation)arrowEndPoints.get(i)).getArrowStroke() ); g2.drawLine(p.x, p.y, ((TextAnnotation)arrowEndPoints.get(i)).getX(), ((TextAnnotation)arrowEndPoints.get(i)).getY()); drawArrow(g2, p, new Point(((TextAnnotation)arrowEndPoints.get(i)).getX(), ((TextAnnotation)arrowEndPoints.get(i)).getY()) ); } } if(isBoundedAnnotation()) return; else if(isTextAnnotation()){ g2.setColor(color); g2.setFont(font); if(usedForPreviews) { g2.drawChars(getText().toCharArray(), 0, getText().length(), getX()+(int)(getWidth()-getTextWidth(g2))/2, getY()+(int)(getHeight()+getTextHeight(g2))/2 ); return; } g2.drawChars(getText().toCharArray(), 0, getText().length(), getX(), getY()+getTextHeight()); } if(isSelected() && ( isTextAnnotation() || isImageAnnotation() ) ){ //Selected Annotations will have a yellow border g2.setColor(Color.YELLOW); g2.setStroke(new BasicStroke(2.0f)); if(isImageAnnotation()) g2.drawRect(getTopX(), getTopY(), getAnnotationWidth(), getAnnotationHeight()); else g2.drawRect(getTopX(), getTopY(), getAnnotationWidth(), (int)(getAnnotationHeight()*1.5)); } } public void drawArrow(Graphics2D g, Point p1, Point p2){ double angle=Math.atan(((double)(p1.y-p2.y))/((double)(p2.x-p1.x))); int quad=getQuadrant(p1, p2); if(angle >=0 ){ if(angle<=Math.PI/4){ double m1=Math.tan(angle + 3*Math.PI/4); double m2=Math.tan(angle + Math.PI/4); if(quad==1){ double x2=p2.x-arrowLength/(Math.sqrt(1+m1*m1)); double y2=p2.y-Math.abs(arrowLength*m1/(Math.sqrt(1+m1*m1))); g.drawLine(p2.x, p2.y, (int)Math.round(x2), (int)Math.round(y2) ); x2=p2.x-arrowLength/(Math.sqrt(1+m2*m2)); y2=p2.y+Math.abs(arrowLength*m2/(Math.sqrt(1+m2*m2))); g.drawLine(p2.x, p2.y, (int)Math.round(x2), (int)Math.round(y2) ); } else if(quad==3){ double x2=p2.x+arrowLength/(Math.sqrt(1+m1*m1)); double y2=p2.y+Math.abs(arrowLength*m1/(Math.sqrt(1+m1*m1))); g.drawLine(p2.x, p2.y, (int)Math.round(x2), (int)Math.round(y2) ); x2=p2.x+arrowLength/(Math.sqrt(1+m2*m2)); y2=p2.y-Math.abs(arrowLength*m2/(Math.sqrt(1+m2*m2))); g.drawLine(p2.x, p2.y, (int)Math.round(x2), (int)Math.round(y2) ); } } else if(angle<=Math.PI/2){ double m1=Math.tan(angle - Math.PI/4); double m2=Math.tan(angle + Math.PI/4); if(quad==1){ double x2=p2.x-arrowLength/(Math.sqrt(1+m1*m1)); double y2=p2.y+Math.abs(arrowLength*m1/(Math.sqrt(1+m1*m1))); g.drawLine(p2.x, p2.y, (int)Math.round(x2), (int)Math.round(y2) ); x2=p2.x+arrowLength/(Math.sqrt(1+m2*m2)); y2=p2.y+Math.abs(arrowLength*m2/(Math.sqrt(1+m2*m2))); g.drawLine(p2.x, p2.y, (int)Math.round(x2), (int)Math.round(y2) ); } else if(quad==3){ double x2=p2.x+arrowLength/(Math.sqrt(1+m1*m1)); double y2=p2.y-Math.abs(arrowLength*m1/(Math.sqrt(1+m1*m1))); g.drawLine(p2.x, p2.y, (int)Math.round(x2), (int)Math.round(y2) ); x2=p2.x-arrowLength/(Math.sqrt(1+m2*m2)); y2=p2.y-Math.abs(arrowLength*m2/(Math.sqrt(1+m2*m2))); g.drawLine(p2.x, p2.y, (int)Math.round(x2), (int)Math.round(y2) ); } } } else{ if(Math.abs(angle)<=Math.PI/4){ double m1=Math.tan(3*Math.PI/4 + angle); double m2=Math.tan(Math.PI/4 + angle); if(quad==4){ double x2=p2.x-arrowLength/(Math.sqrt(1+m1*m1)); double y2=p2.y-Math.abs(arrowLength*m1/(Math.sqrt(1+m1*m1))); g.drawLine(p2.x, p2.y, (int)Math.round(x2), (int)Math.round(y2) ); x2=p2.x-arrowLength/(Math.sqrt(1+m2*m2)); y2=p2.y+Math.abs(arrowLength*m2/(Math.sqrt(1+m2*m2))); g.drawLine(p2.x, p2.y, (int)Math.round(x2), (int)Math.round(y2) ); } else if(quad==2){ double x2=p2.x+arrowLength/(Math.sqrt(1+m1*m1)); double y2=p2.y+Math.abs(arrowLength*m1/(Math.sqrt(1+m1*m1))); g.drawLine(p2.x, p2.y, (int)Math.round(x2), (int)Math.round(y2) ); x2=p2.x+arrowLength/(Math.sqrt(1+m2*m2)); y2=p2.y-Math.abs(arrowLength*m2/(Math.sqrt(1+m2*m2))); g.drawLine(p2.x, p2.y, (int)Math.round(x2), (int)Math.round(y2) ); } } else{ double m1=Math.tan(3*Math.PI/4 + angle); double m2=Math.tan(5*Math.PI/4 + angle); if(quad==4){ double x2=p2.x+arrowLength/(Math.sqrt(1+m1*m1)); double y2=p2.y-Math.abs(arrowLength*m1/(Math.sqrt(1+m1*m1))); g.drawLine(p2.x, p2.y, (int)Math.round(x2), (int)Math.round(y2) ); x2=p2.x-arrowLength/(Math.sqrt(1+m2*m2)); y2=p2.y-Math.abs(arrowLength*m2/(Math.sqrt(1+m2*m2))); g.drawLine(p2.x, p2.y, (int)Math.round(x2), (int)Math.round(y2) ); } else if(quad==2){ double x2=p2.x-arrowLength/(Math.sqrt(1+m1*m1)); double y2=p2.y+Math.abs(arrowLength*m1/(Math.sqrt(1+m1*m1))); g.drawLine(p2.x, p2.y, (int)Math.round(x2), (int)Math.round(y2) ); x2=p2.x+arrowLength/(Math.sqrt(1+m2*m2)); y2=p2.y+Math.abs(arrowLength*m2/(Math.sqrt(1+m2*m2))); g.drawLine(p2.x, p2.y, (int)Math.round(x2), (int)Math.round(y2) ); } } } } public void adjustSpecificFont(double newZoom){ font=font.deriveFont(((float)(newZoom/tempZoom))*font.getSize2D()); tempZoom=newZoom; setBounds(getX(), getY(), getAnnotationWidth(), getAnnotationHeight()); } public void adjustFont(double newZoom){ font=font.deriveFont(((float)(newZoom/zoom))*font.getSize2D()); setBounds(getX(), getY(), getAnnotationWidth(), getAnnotationHeight()); adjustArrowThickness(newZoom); zoom=newZoom; } public void adjustArrowThickness(double newZoom){ if(!arrowDrawn) return; float factor=(float)(newZoom/zoom); arrowLength*=factor; for(int i=0;i<arrowEndPoints.size();i++) { BasicStroke stroke=((TextAnnotation)arrowEndPoints.get(i)).getArrowStroke(); ((TextAnnotation)arrowEndPoints.get(i)).setArrowStroke( new BasicStroke(factor*stroke.getLineWidth(), stroke.getEndCap(), stroke.getLineJoin()) ); } } public void addModifyMenuItem(JPopupMenu popup){ JMenuItem modify=new JMenuItem("Modify Properties"); modify.addActionListener(new modifyTextAnnotationListener()); popup.add(modify); } public JPopupMenu createPopUp(){ JPopupMenu popup=new JPopupMenu(); if(pointOnArrow) { JMenuItem modArrow=new JMenuItem("Modify Properties"); modArrow.addActionListener(new modifyArrowListener()); popup.add(modArrow); popup.add(new JSeparator()); JMenuItem remArrow=new JMenuItem("Remove Arrow"); remArrow.addActionListener(new removeArrowListener()); popup.add(remArrow); pointOnArrow=false; } else { if(!isImageAnnotation()) { addModifyMenuItem(popup); popup.add(new JSeparator()); } JMenuItem removeAnnotation=new JMenuItem("Remove Annotation"); removeAnnotation.addActionListener(new removeAnnotationListener()); JMenuItem addArrow=new JMenuItem("Add Arrow"); addArrow.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e) { TextAnnotation.this.setDrawArrow(true); } }); popup.add(removeAnnotation); popup.add(addArrow); } return popup; } public void showChangePopup(MouseEvent e){ createPopUp().show(e.getComponent(), e.getX(), e.getY()); } class modifyTextAnnotationListener implements ActionListener{ public void actionPerformed(ActionEvent e){ mTextAnnotation mTAnnotation=new mTextAnnotation(TextAnnotation.this); mTAnnotation.setVisible(true); mTAnnotation.setSize(474, 504); mTAnnotation.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); mTAnnotation.setResizable(false); mTAnnotation.setLocation(TextAnnotation.this.getX(), TextAnnotation.this.getY()); } } class removeArrowListener implements ActionListener{ public void actionPerformed(ActionEvent e){ int remPos=((TextAnnotation)TextAnnotation.this.arrowEndPoints.get(arrowIndex)).getComponentNumber(); int num=((DingNetworkView)Cytoscape.getCurrentNetworkView()).getCanvas(DGraphView.Canvas.FOREGROUND_CANVAS).getComponentCount(); for(int i=remPos+1;i<num;i++) ((TextAnnotation)((DingNetworkView)Cytoscape.getCurrentNetworkView()).getCanvas(DGraphView.Canvas.FOREGROUND_CANVAS).getComponent(i)).setComponentNumber(i-1); ((DingNetworkView)Cytoscape.getCurrentNetworkView()).getCanvas(DGraphView.Canvas.FOREGROUND_CANVAS).remove((TextAnnotation)TextAnnotation.this.arrowEndPoints.get(arrowIndex)); TextAnnotation.this.arrowEndPoints.remove(arrowIndex); if(TextAnnotation.this.arrowEndPoints.isEmpty()) TextAnnotation.this.arrowDrawn=false; Cytoscape.getDesktop().getNetworkViewManager().getInternalFrameComponent(Cytoscape.getCurrentNetworkView()).repaint(); } } class modifyArrowListener implements ActionListener{ public void actionPerformed(ActionEvent e){ mArrow modArrow=new mArrow((TextAnnotation)TextAnnotation.this.arrowEndPoints.get(arrowIndex)); modArrow.setSize(375, 220); modArrow.setVisible(true); } } class removeAnnotationListener implements ActionListener{ public void actionPerformed(ActionEvent e){ //When an Annotation is removed we have to adjust the componentNumbers of the anotations added //after this Annotation int remPos=TextAnnotation.this.getComponentNumber(); int num=((DingNetworkView)Cytoscape.getCurrentNetworkView()).getCanvas(DGraphView.Canvas.FOREGROUND_CANVAS).getComponentCount(); for(int i=remPos+1;i<num;i++) ((TextAnnotation)((DingNetworkView)Cytoscape.getCurrentNetworkView()).getCanvas(DGraphView.Canvas.FOREGROUND_CANVAS).getComponent(i)).setComponentNumber(i-1); ((DingNetworkView)Cytoscape.getCurrentNetworkView()).getCanvas(DGraphView.Canvas.FOREGROUND_CANVAS).remove(TextAnnotation.this); if(TextAnnotation.this.getArrowDrawn()){ for(int temp=0; temp<TextAnnotation.this.arrowEndPoints.size(); temp++){ remPos=((TextAnnotation)TextAnnotation.this.arrowEndPoints.get(temp)).getComponentNumber()-1; num--; for(int i=remPos+1;i<num;i++) ((TextAnnotation)((DingNetworkView)Cytoscape.getCurrentNetworkView()).getCanvas(DGraphView.Canvas.FOREGROUND_CANVAS).getComponent(i)).setComponentNumber(i-1); ((DingNetworkView)Cytoscape.getCurrentNetworkView()).getCanvas(DGraphView.Canvas.FOREGROUND_CANVAS).remove((TextAnnotation)TextAnnotation.this.arrowEndPoints.get(temp)); } } Cytoscape.getDesktop().getNetworkViewManager().getInternalFrameComponent(Cytoscape.getCurrentNetworkView()).repaint(); } } }