1
28 package demo.view.viewmode;
29
30 import demo.view.DemoBase;
31 import y.base.Node;
32 import y.base.NodeCursor;
33 import y.geom.YRectangle;
34 import y.view.EditMode;
35 import y.view.Graph2D;
36 import y.view.Graph2DTraversal;
37 import y.view.Graph2DView;
38 import y.view.HitInfo;
39 import y.view.HtmlLabelConfiguration;
40 import y.view.Mouse2DEvent;
41 import y.view.NodeLabel;
42 import y.view.NodeRealizer;
43 import y.view.TooltipMode;
44 import y.view.YLabel;
45
46 import java.awt.Cursor;
47 import java.awt.EventQueue;
48 import java.awt.Point;
49 import java.awt.RenderingHints;
50 import java.awt.event.MouseEvent;
51 import java.awt.geom.Point2D;
52 import java.net.URL;
53 import java.util.Locale;
54 import java.util.Map;
55 import javax.swing.JDialog;
56 import javax.swing.JOptionPane;
57 import javax.swing.event.HyperlinkEvent;
58 import javax.swing.event.HyperlinkListener;
59
60
85 public class HyperlinkDemo extends DemoBase {
86 private static final String HTML_LABEL_CONFIG = "HtmlLabel";
87 private boolean fractionMetricsForSizeCalculationEnabled;
88
89 public HyperlinkDemo() {
90 loadInitialGraph();
91 }
92
93 protected void loadInitialGraph() {
94 loadGraph("resource/HyperlinkDemo.graphml");
95 }
96
97 protected void initialize() {
98 super.initialize();
99
100 fractionMetricsForSizeCalculationEnabled = YLabel.isFractionMetricsForSizeCalculationEnabled();
104 YLabel.setFractionMetricsForSizeCalculationEnabled(true);
105 view.getRenderingHints().put(
106 RenderingHints.KEY_FRACTIONALMETRICS,
107 RenderingHints.VALUE_FRACTIONALMETRICS_ON);
108 }
109
110
114 public void dispose() {
115 YLabel.setFractionMetricsForSizeCalculationEnabled(fractionMetricsForSizeCalculationEnabled);
116 }
117
118
122 protected void configureDefaultRealizers() {
123 final YLabel.Factory f = NodeLabel.getFactory();
124 final HtmlLabelConfiguration impl = new HtmlLabelConfiguration();
125 final Map impls = f.createDefaultConfigurationMap();
126 impls.put(YLabel.Painter.class, impl);
127 impls.put(YLabel.Layout.class, impl);
128 impls.put(YLabel.BoundsProvider.class, impl);
129 f.addConfiguration(HTML_LABEL_CONFIG, impls);
130
131 super.configureDefaultRealizers();
132 }
133
134
139 protected EditMode createEditMode() {
140 return new HyperlinkEditMode();
141 }
142
143
146 protected TooltipMode createTooltipMode() {
147 return null;
148 }
149
150 public static void main( String[] args ) {
151 EventQueue.invokeLater(new Runnable() {
152 public void run() {
153 Locale.setDefault(Locale.ENGLISH);
154 initLnF();
155 (new HyperlinkDemo()).start();
156 }
157 });
158 }
159
160
164 private static final class HyperlinkEditMode extends EditMode {
165 HyperlinkEditMode() {
166 allowResizeNodes(false);
167 allowNodeCreation(false);
168 }
169
170
174 protected void hyperlinkUpdate( final HyperlinkEvent e ) {
175 (new EventHandler(view)).hyperlinkUpdate(e);
176 }
177
178
186 protected void nodeClicked(
187 final Graph2D graph,
188 final Node node,
189 final boolean wasSelected,
190 final double x,
191 final double y,
192 final boolean modifierSet
193 ) {
194 final NodeRealizer nr = graph.getRealizer(node);
195 if (nr.labelCount() > 0) {
196 for (int i = nr.labelCount(); i --> 0;) {
197 final NodeLabel nl = nr.getLabel(i);
198 if (nl.contains(x, y)) {
199 if (labelClickedImpl(nl, x, y)) {
200 return;
201 }
202 }
203 }
204 }
205 super.nodeClicked(graph, node, wasSelected, x, y, modifierSet);
206 }
207
208
211 protected void labelClicked(
212 final Graph2D graph,
213 final YLabel label,
214 final boolean wasSelected,
215 final double x, final double y,
216 final boolean modifierSet
217 ) {
218 if (labelClickedImpl(label, x, y)) {
219 return;
220 }
221 super.labelClicked(graph, label, wasSelected, x, y, modifierSet);
222 }
223
224
233 private boolean labelClickedImpl(
234 final YLabel label,
235 final double x, final double y
236 ) {
237 if (HTML_LABEL_CONFIG.equals(label.getConfiguration())) {
238 final HtmlLabelConfiguration htmlSupport = getHtmlConfiguration();
239 final EventHolder callback = new EventHolder();
240 htmlSupport.handleLabelEvent(
252 label,
253 createEvent(x, y, lastReleaseEvent, MouseEvent.MOUSE_PRESSED),
254 null);
255 htmlSupport.handleLabelEvent(
256 label,
257 createEvent(x, y, lastReleaseEvent, MouseEvent.MOUSE_RELEASED),
258 callback);
259 htmlSupport.handleLabelEvent(
260 label,
261 createEvent(x, y, lastReleaseEvent, MouseEvent.MOUSE_CLICKED),
262 callback);
263 final HyperlinkEvent e = callback.getEvent();
264 if (e != null) {
265 hyperlinkUpdate(e);
266 return true;
267 }
268 }
269 return false;
270 }
271
272
273
279 public void mouseMoved( final double x, final double y ) {
280 final HitInfo info = view.getHitInfoFactory().createHitInfo(
282 x, y, Graph2DTraversal.NODE_LABELS, true);
283 if (info.hasHitNodeLabels()) {
284 final NodeLabel label = info.getHitNodeLabel();
285 if (HTML_LABEL_CONFIG.equals(label.getConfiguration())) {
287 final HtmlLabelConfiguration htmlSupport = getHtmlConfiguration();
288 final EventHolder callback = new EventHolder();
289 htmlSupport.handleLabelEvent(
292 label,
293 createEvent(x, y, lastMoveEvent, MouseEvent.MOUSE_MOVED),
294 callback);
295 final HyperlinkEvent e = callback.getEvent();
296 if (e != null) {
297 if (e.getEventType() == HyperlinkEvent.EventType.ENTERED) {
298 view.setViewCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
301 } else if (e.getEventType() == HyperlinkEvent.EventType.EXITED) {
302 view.setViewCursor(Cursor.getDefaultCursor());
303 }
304 }
305 return;
306 }
307 }
308
309 super.mouseMoved(x, y);
310 }
311
312
313
323 private Mouse2DEvent createEvent(
324 final double x, final double y,
325 final MouseEvent e,
326 final int id
327 ) {
328 return new Mouse2DEvent(
329 e.getSource(),
330 this,
331 id,
332 e.getWhen(),
333 e.getModifiersEx(),
334 x,
335 y,
336 e.getButton(),
337 e.getClickCount(),
338 e.isPopupTrigger());
339 }
340
341 private static HtmlLabelConfiguration getHtmlConfiguration() {
342 return (HtmlLabelConfiguration) NodeLabel.getFactory().getImplementation(
343 HTML_LABEL_CONFIG, YLabel.Painter.class);
344 }
345 }
346
347
350 private static class EventHolder implements HyperlinkListener {
351 private HyperlinkEvent event;
352
353
357 public void hyperlinkUpdate( final HyperlinkEvent e ) {
358 event = e;
359 }
360
361
365 HyperlinkEvent getEvent() {
366 return event;
367 }
368 }
369
370
373 private static class EventHandler implements HyperlinkListener {
374 private final Graph2DView view;
375
376 EventHandler( final Graph2DView view ) {
377 this.view = view;
378 }
379
380
384 public void hyperlinkUpdate( final HyperlinkEvent e ) {
385 if (e instanceof HtmlLabelConfiguration.LabelHyperlinkEvent) {
387 if (isGraphNavigationEvent(e)) {
391 navigateTo((HtmlLabelConfiguration.LabelHyperlinkEvent) e);
392 } else {
393 displayExternalLink((HtmlLabelConfiguration.LabelHyperlinkEvent) e);
394 }
395 }
396 }
397
398
406 private boolean isGraphNavigationEvent( final HyperlinkEvent e ) {
407 final URL url = e.getURL();
408 if (url == null) {
409 final String desc = e.getDescription();
410 return desc != null && desc.startsWith("graph://");
411 } else {
412 return "graph".equals(url.getProtocol());
413 }
414 }
415
416
420 private void displayExternalLink( final HtmlLabelConfiguration.LabelHyperlinkEvent e ) {
421 final YLabel label = e.getLabel();
422 final YRectangle lbox = label.getBox();
423 final Point l = view.getLocationOnScreen();
424 final int vx = l.x + view.toViewCoordX(lbox.getX());
425 final int vy = l.y + view.toViewCoordY(lbox.getY() + lbox.getHeight());
426
427 final String title = "External Link";
428 final String message =
429 title +
430 "\nHref: " + e.getDescription();
431 final JOptionPane jop = new JOptionPane(message, JOptionPane.INFORMATION_MESSAGE);
432 final JDialog jd = jop.createDialog(view, title);
433 jd.setLocation(vx, vy);
434 jd.setVisible(true);
435 }
436
437
443 private void navigateTo( final HtmlLabelConfiguration.LabelHyperlinkEvent e ) {
444 final String destination;
445 final URL url = e.getURL();
446 if (url == null) {
447 destination = e.getDescription().substring(8);
448 } else {
449 destination = url.getPath();
450 }
451
452 final Graph2D g = view.getGraph2D();
455 for (NodeCursor nc = g.nodes(); nc.ok(); nc.next()) {
456 final NodeRealizer nr = g.getRealizer(nc.node());
457 if (nr.labelCount() > 0) {
458 final String s = nr.getLabelText();
459 if (s.indexOf("<a name=\"" + destination + "\">") > -1) {
460 navigateTo(nr);
461 break;
462 }
463 }
464 }
465 }
466
467
471 private void navigateTo( final NodeRealizer realizer ) {
472 view.setViewCursor(Cursor.getDefaultCursor());
473 final double z = view.getZoom();
474 final double cx = realizer.getCenterX();
475 final double cy = realizer.getCenterY();
476 view.focusView(z, new Point2D.Double(cx, cy), true);
477 }
478 }
479 }
480