001/* 002 * Copyright 2006 - 2013 003 * Stefan Balev <stefan.balev@graphstream-project.org> 004 * Julien Baudry <julien.baudry@graphstream-project.org> 005 * Antoine Dutot <antoine.dutot@graphstream-project.org> 006 * Yoann Pigné <yoann.pigne@graphstream-project.org> 007 * Guilhelm Savin <guilhelm.savin@graphstream-project.org> 008 * 009 * This file is part of GraphStream <http://graphstream-project.org>. 010 * 011 * GraphStream is a library whose purpose is to handle static or dynamic 012 * graph, create them from scratch, file or any source and display them. 013 * 014 * This program is free software distributed under the terms of two licenses, the 015 * CeCILL-C license that fits European law, and the GNU Lesser General Public 016 * License. You can use, modify and/ or redistribute the software under the terms 017 * of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following 018 * URL <http://www.cecill.info> or under the terms of the GNU LGPL as published by 019 * the Free Software Foundation, either version 3 of the License, or (at your 020 * option) any later version. 021 * 022 * This program is distributed in the hope that it will be useful, but WITHOUT ANY 023 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 024 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 025 * 026 * You should have received a copy of the GNU Lesser General Public License 027 * along with this program. If not, see <http://www.gnu.org/licenses/>. 028 * 029 * The fact that you are presently reading this means that you have had 030 * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms. 031 */ 032package org.graphstream.ui.swingViewer; 033 034import java.awt.BorderLayout; 035import java.awt.Graphics; 036import java.awt.Graphics2D; 037import java.awt.event.WindowEvent; 038import java.awt.event.WindowListener; 039import java.util.ArrayList; 040 041import javax.swing.JFrame; 042 043import org.graphstream.ui.graphicGraph.GraphicElement; 044import org.graphstream.ui.graphicGraph.GraphicGraph; 045import org.graphstream.ui.swingViewer.util.Camera; 046import org.graphstream.ui.swingViewer.util.DefaultMouseManager; 047import org.graphstream.ui.swingViewer.util.DefaultShortcutManager; 048import org.graphstream.ui.swingViewer.util.MouseManager; 049import org.graphstream.ui.swingViewer.util.ShortcutManager; 050 051/** 052 * Base for constructing views. 053 * 054 * <p> 055 * This base view is an abstract class that provides mechanism that are 056 * necessary in any view : 057 * <ul> 058 * <li>the painting and repainting mechanism.</li> 059 * <li>the optional frame handling.</li> 060 * <li>the frame closing protocol.</li> 061 * </ul> 062 * </p> 063 * 064 * <p> 065 * This view also handle a current selection of nodes and sprites. 066 * </p> 067 * 068 * <h3>The painting mechanism</h3> 069 * 070 * <p> 071 * The main method to implement is {@link #render(Graphics2D)}. This method is 072 * called each time the graph needs to be rendered anew in the canvas. 073 * </p> 074 * 075 * <p> 076 * The {@link #render(Graphics2D)} is called only when a repainting is really 077 * needed. 078 * </p> 079 * 080 * <p> 081 * All the painting, by default, is deferred to a {@link GraphRenderer} 082 * instance. This mechanism allows developers that do not want to mess with the 083 * viewer/view mechanisms to render a graph in any Swing surface. 084 * </p> 085 * 086 * <h3>The optional frame handling</h3> 087 * 088 * <p> 089 * This abstract view is able to create a frame that is added around this panel 090 * (each view is a JPanel instance). The frame can be removed at any time. 091 * </p> 092 * 093 * <h3>The frame closing protocol</h3> 094 * 095 * <p> 096 * This abstract view handles the closing protocol. This means that it will 097 * close the view if needed, or only hide it to allow reopening it later. 098 * Furthermore it adds the "ui.viewClosed" attribute to the graph when the view 099 * is closed or hidden, and removes it when the view is shown. The value of this 100 * graph attribute is the identifier of the view. 101 * </p> 102 */ 103public class DefaultView extends View implements WindowListener 104{ 105 private static final long serialVersionUID = - 4489484861592064398L; 106 107 /** 108 * Parent viewer. 109 */ 110 protected Viewer viewer; 111 112 /** 113 * The graph to render, shortcut to the viewers reference. 114 */ 115 protected GraphicGraph graph; 116 117 /** 118 * The (optional) frame. 119 */ 120 protected JFrame frame; 121 122 /** 123 * Manager for events with the keyboard. 124 */ 125 protected ShortcutManager shortcuts; 126 127 /** 128 * Manager for events with the mouse. 129 */ 130 protected MouseManager mouseClicks; 131 132 /** 133 * The graph renderer. 134 */ 135 protected GraphRenderer renderer; 136 137 // Construction 138 139 public DefaultView(Viewer viewer, String identifier, GraphRenderer renderer) { 140 super(identifier); 141 142 this.viewer = viewer; 143 this.graph = viewer.getGraphicGraph(); 144 this.renderer = renderer; 145 146 setOpaque(false); 147 setDoubleBuffered(true); 148 setMouseManager(null); 149 setShortcutManager(null); 150 renderer.open(graph, this); 151 } 152 153 // Access 154 155 // Command 156 157 @Override 158 public Camera getCamera() { 159 return renderer.getCamera(); 160 } 161 162 @Override 163 public void display(GraphicGraph graph, boolean graphChanged) { 164 repaint(); 165 } 166 167 @Override 168 public void paintComponent(Graphics g) { 169 super.paintComponent(g); 170 checkTitle(); 171 Graphics2D g2 = (Graphics2D) g; 172 render(g2); 173 } 174 175 protected void checkTitle() { 176 if (frame != null) { 177 String titleAttr = String.format("ui.%s.title", getId()); 178 String title = (String) graph.getLabel(titleAttr); 179 180 if (title == null) { 181 title = (String) graph.getLabel("ui.default.title"); 182 183 if (title == null) 184 title = (String) graph.getLabel("ui.title"); 185 } 186 187 if (title != null) 188 frame.setTitle(title); 189 } 190 } 191 192 @Override 193 public void close(GraphicGraph graph) { 194 renderer.close(); 195 graph.addAttribute("ui.viewClosed", getId()); 196 197 removeKeyListener(shortcuts); 198 shortcuts.release(); 199 mouseClicks.release(); 200 201 openInAFrame(false); 202 } 203 204 @Override 205 public void resizeFrame(int width, int height) { 206 if (frame != null) { 207 frame.setSize(width, height); 208 } 209 } 210 211 @Override 212 public void openInAFrame(boolean on) { 213 if (on) { 214 if (frame == null) { 215 frame = new JFrame("GraphStream"); 216 frame.setLayout(new BorderLayout()); 217 frame.add(this, BorderLayout.CENTER); 218 frame.setSize(800, 600); 219 frame.setVisible(true); 220 frame.addWindowListener(this); 221 frame.addKeyListener(shortcuts); 222 } else { 223 frame.setVisible(true); 224 } 225 } else { 226 if (frame != null) { 227 frame.removeWindowListener(this); 228 frame.removeKeyListener(shortcuts); 229 frame.remove(this); 230 frame.setVisible(false); 231 frame.dispose(); 232 } 233 } 234 } 235 236 public void render(Graphics2D g) { 237 renderer.render(g, getX(), getY(), getWidth(), getHeight()); 238 239 String screenshot = (String) graph.getLabel("ui.screenshot"); 240 241 if (screenshot != null) { 242 graph.removeAttribute("ui.screenshot"); 243 renderer.screenshot(screenshot, getWidth(), getHeight()); 244 } 245 } 246 247 // Selection 248 249 @Override 250 public void beginSelectionAt(double x1, double y1) { 251 renderer.beginSelectionAt(x1, y1); 252 repaint(); 253 } 254 255 @Override 256 public void selectionGrowsAt(double x, double y) { 257 renderer.selectionGrowsAt(x, y); 258 repaint(); 259 } 260 261 @Override 262 public void endSelectionAt(double x2, double y2) { 263 renderer.endSelectionAt(x2, y2); 264 repaint(); 265 } 266 267 // Window Listener 268 269 public void windowActivated(WindowEvent e) { 270 } 271 272 public void windowClosed(WindowEvent e) { 273 } 274 275 public void windowClosing(WindowEvent e) { 276 graph.addAttribute("ui.viewClosed", getId()); 277 278 switch (viewer.getCloseFramePolicy()) { 279 case CLOSE_VIEWER: 280 viewer.removeView(getId()); 281 break; 282 case HIDE_ONLY: 283 if (frame != null) 284 frame.setVisible(false); 285 break; 286 case EXIT: 287 System.exit(0); 288 default: 289 throw new RuntimeException( 290 String 291 .format( 292 "The %s view is not up to date, do not know %s CloseFramePolicy.", 293 getClass().getName(), viewer 294 .getCloseFramePolicy())); 295 } 296 } 297 298 public void windowDeactivated(WindowEvent e) { 299 } 300 301 public void windowDeiconified(WindowEvent e) { 302 } 303 304 public void windowIconified(WindowEvent e) { 305 } 306 307 public void windowOpened(WindowEvent e) { 308 graph.removeAttribute("ui.viewClosed"); 309 } 310 311 // Methods deferred to the renderer 312 313 @Override 314 public ArrayList<GraphicElement> allNodesOrSpritesIn(double x1, double y1, 315 double x2, double y2) { 316 return renderer.allNodesOrSpritesIn(x1, y1, x2, y2); 317 } 318 319 @Override 320 public GraphicElement findNodeOrSpriteAt(double x, double y) { 321 return renderer.findNodeOrSpriteAt(x, y); 322 } 323 324 @Override 325 public void moveElementAtPx(GraphicElement element, double x, double y) { 326 // The feedback on the node positions is often off since not needed 327 // and generating lots of events. We activate it here since the 328 // movement of the node is decided by the viewer. This is one of the 329 // only moment when the viewer really moves a node. 330 boolean on = graph.feedbackXYZ(); 331 graph.feedbackXYZ(true); 332 renderer.moveElementAtPx(element, x, y); 333 graph.feedbackXYZ(on); 334 } 335 336 @Override 337 public void freezeElement(GraphicElement element, boolean frozen) { 338 if(frozen) { 339 element.addAttribute("layout.frozen"); 340 } else { 341 element.removeAttribute("layout.frozen"); 342 } 343 } 344 345 @Override 346 public void setBackLayerRenderer(LayerRenderer renderer) { 347 this.renderer.setBackLayerRenderer(renderer); 348 repaint(); 349 } 350 351 @Override 352 public void setForeLayoutRenderer(LayerRenderer renderer) { 353 this.renderer.setForeLayoutRenderer(renderer); 354 repaint(); 355 } 356 357 @Override 358 public void setMouseManager(MouseManager manager) { 359 if(mouseClicks != null) 360 mouseClicks.release(); 361 362 if(manager == null) 363 manager = new DefaultMouseManager(); 364 365 manager.init(graph, this); 366 367 mouseClicks = manager; 368 } 369 370 @Override 371 public void setShortcutManager(ShortcutManager manager) { 372 if(shortcuts != null) 373 shortcuts.release(); 374 375 if(manager == null) 376 manager = new DefaultShortcutManager(); 377 378 manager.init(graph, this); 379 380 shortcuts = manager; 381 } 382}