001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.painter; 020 021import icy.canvas.IcyCanvas; 022import icy.common.CollapsibleEvent; 023import icy.common.UpdateEventHandler; 024import icy.common.listener.ChangeListener; 025import icy.file.xml.XMLPersistent; 026import icy.gui.viewer.Viewer; 027import icy.main.Icy; 028import icy.painter.OverlayEvent.OverlayEventType; 029import icy.sequence.Sequence; 030import icy.system.IcyExceptionHandler; 031import icy.type.point.Point5D; 032import icy.util.ClassUtil; 033import icy.util.StringUtil; 034import icy.util.XMLUtil; 035 036import java.awt.Graphics2D; 037import java.awt.event.KeyEvent; 038import java.awt.event.MouseEvent; 039import java.awt.event.MouseWheelEvent; 040import java.awt.geom.Point2D; 041import java.lang.reflect.Constructor; 042import java.util.ArrayList; 043import java.util.List; 044 045import javax.swing.JPanel; 046 047import org.w3c.dom.Node; 048 049/** 050 * Overlay class.<br> 051 * <br> 052 * This class allow interaction and rich informations display on Sequences.<br> 053 * {@link IcyCanvas} subclasses should propagate mouse and key events to overlay. 054 * 055 * @author Stephane 056 */ 057@SuppressWarnings("deprecation") 058public abstract class Overlay implements Painter, ChangeListener, Comparable<Overlay>, XMLPersistent 059{ 060 /** 061 * Define the overlay priority: 062 * 063 * <pre> 064 * Lowest | BACKGROUND (below image) 065 * | IMAGE (image level) 066 * | SHAPE (just over the image) 067 * | TEXT (over image and shape) 068 * | TOOLTIP (all over the rest) 069 * Highest | TOPMOST (absolute topmost) 070 * </pre> 071 * 072 * You have 4 levels for each category (except TOPMOST) for finest adjustment: 073 * 074 * <pre> 075 * Lowest | LOW 076 * | NORMAL 077 * | HIGH 078 * Highest | TOP 079 * </pre> 080 * 081 * TOP level should be used to give <i>focus<i> to a specific Overlay over all other in the same 082 * category. 083 */ 084 public static enum OverlayPriority 085 { 086 BACKGROUND_LOW, BACKGROUND_NORMAL, BACKGROUND_HIGH, BACKGROUND_TOP, IMAGE_LOW, IMAGE_NORMAL, IMAGE_HIGH, IMAGE_TOP, SHAPE_LOW, SHAPE_NORMAL, SHAPE_HIGH, SHAPE_TOP, TEXT_LOW, TEXT_NORMAL, TEXT_HIGH, TEXT_TOP, TOOLTIP_LOW, TOOLTIP_NORMAL, TOOLTIP_HIGH, TOOLTIP_TOP, TOPMOST 087 } 088 089 public static final String ID_OVERLAY = "overlay"; 090 091 public static final String ID_CLASSNAME = "classname"; 092 public static final String ID_ID = "id"; 093 public static final String ID_NAME = "name"; 094 public static final String ID_PRIORITY = "priority"; 095 public static final String ID_READONLY = "readOnly"; 096 public static final String ID_CANBEREMOVED = "canBeRemoved"; 097 public static final String ID_RECEIVEKEYEVENTONHIDDEN = "receiveKeyEventOnHidden"; 098 public static final String ID_RECEIVEMOUSEEVENTONHIDDEN = "receiveMouseEventOnHidden"; 099 100 public static final String PROPERTY_NAME = ID_NAME; 101 public static final String PROPERTY_PRIORITY = ID_PRIORITY; 102 public static final String PROPERTY_READONLY = ID_READONLY; 103 public static final String PROPERTY_PERSISTENT = "persitent"; 104 public static final String PROPERTY_CANBEREMOVED = ID_CANBEREMOVED; 105 public static final String PROPERTY_RECEIVEKEYEVENTONHIDDEN = ID_RECEIVEKEYEVENTONHIDDEN; 106 public static final String PROPERTY_RECEIVEMOUSEEVENTONHIDDEN = ID_RECEIVEMOUSEEVENTONHIDDEN; 107 108 /** 109 * We consider as tiny object anything with a size of 10 pixels or less 110 */ 111 public static final int LOD_SMALL = 10; 112 public static final int LOD_TINY = 4; 113 114 protected static int id_gen = 1; 115 116 /** 117 * Create a Overlay from a XML node. 118 * 119 * @param node 120 * XML node defining the overlay 121 * @return the created Overlay or <code>null</code> if the Overlay class does not support XML 122 * persistence a default 123 * constructor 124 */ 125 public static Overlay createFromXML(Node node) 126 { 127 if (node == null) 128 return null; 129 130 final String className = XMLUtil.getElementValue(node, ID_CLASSNAME, ""); 131 if (StringUtil.isEmpty(className)) 132 return null; 133 134 final Overlay result; 135 136 try 137 { 138 // search for the specified className 139 final Class<?> clazz = ClassUtil.findClass(className); 140 141 // class found 142 if (clazz != null) 143 { 144 final Class<? extends Overlay> overlayClazz = clazz.asSubclass(Overlay.class); 145 146 // default constructor 147 final Constructor<? extends Overlay> constructor = overlayClazz.getConstructor(new Class[] {}); 148 // build Overlay 149 result = constructor.newInstance(); 150 151 // load properties from XML 152 if (result != null) 153 { 154 // error while loading infos --> return null 155 if (!result.loadFromXML(node)) 156 return null; 157 } 158 159 return result; 160 } 161 } 162 catch (NoSuchMethodException e) 163 { 164 IcyExceptionHandler.handleException(new NoSuchMethodException("Default constructor not found in class '" 165 + className + "', cannot create the Overlay."), true); 166 } 167 catch (ClassNotFoundException e) 168 { 169 IcyExceptionHandler.handleException(new ClassNotFoundException("Cannot find '" + className 170 + "' class, cannot create the Overlay."), true); 171 } 172 catch (Exception e) 173 { 174 IcyExceptionHandler.handleException(e, true); 175 } 176 177 return null; 178 } 179 180 /** 181 * Return the number of Overlay defined in the specified XML node. 182 * 183 * @param node 184 * XML node defining the Overlay list 185 * @return the number of Overlay defined in the XML node. 186 */ 187 public static int getOverlayCount(Node node) 188 { 189 if (node != null) 190 { 191 final List<Node> nodesOverlay = XMLUtil.getChildren(node, ID_OVERLAY); 192 193 if (nodesOverlay != null) 194 return nodesOverlay.size(); 195 } 196 197 return 0; 198 } 199 200 /** 201 * Return a list of Overlay from a XML node. 202 * 203 * @param node 204 * XML node defining the Overlay list 205 * @return a list of Overlay 206 */ 207 public static List<Overlay> loadOverlaysFromXML(Node node) 208 { 209 final List<Overlay> result = new ArrayList<Overlay>(); 210 211 if (node != null) 212 { 213 final List<Node> nodesOverlay = XMLUtil.getChildren(node, ID_OVERLAY); 214 215 if (nodesOverlay != null) 216 { 217 for (Node n : nodesOverlay) 218 { 219 final Overlay overlay = createFromXML(n); 220 221 if (overlay != null) 222 { 223 // we assume this overlay should stay persistent then 224 overlay.setPersistent(true); 225 result.add(overlay); 226 } 227 } 228 } 229 } 230 231 return result; 232 } 233 234 /** 235 * Set a list of Overlay to a XML node. 236 * 237 * @param node 238 * XML node which is used to store the list of Overlay 239 * @param overlays 240 * the list of Overlay to store in the XML node 241 */ 242 public static void saveOverlaysToXML(Node node, List<Overlay> overlays) 243 { 244 if (node != null) 245 { 246 for (Overlay overlay : overlays) 247 { 248 // only save persistent overlay 249 if (overlay.isPersistent()) 250 { 251 final Node nodeOverlay = XMLUtil.addElement(node, ID_OVERLAY); 252 253 if (!overlay.saveToXML(nodeOverlay)) 254 { 255 XMLUtil.removeNode(node, nodeOverlay); 256 System.err.println("Error: the overlay " + overlay.getName() 257 + " was not correctly saved to XML !"); 258 } 259 } 260 } 261 } 262 } 263 264 /** 265 * properties 266 */ 267 protected int id; 268 protected String name; 269 protected OverlayPriority priority; 270 protected boolean persistent; 271 protected boolean readOnly; 272 protected boolean canBeRemoved; 273 protected boolean receiveKeyEventOnHidden; 274 protected boolean receiveMouseEventOnHidden; 275 276 /** 277 * internals 278 */ 279 protected final List<OverlayListener> listeners; 280 protected final UpdateEventHandler updater; 281 282 public Overlay(String name, OverlayPriority priority) 283 { 284 super(); 285 286 synchronized (Overlay.class) 287 { 288 id = id_gen++; 289 } 290 291 this.name = name; 292 this.priority = priority; 293 // by default the overlay is not persistent 294 persistent = false; 295 readOnly = false; 296 canBeRemoved = true; 297 receiveKeyEventOnHidden = false; 298 receiveMouseEventOnHidden = false; 299 300 listeners = new ArrayList<OverlayListener>(); 301 updater = new UpdateEventHandler(this, false); 302 } 303 304 public Overlay(String name) 305 { 306 // create overlay with default priority 307 this(name, OverlayPriority.SHAPE_NORMAL); 308 } 309 310 /** 311 * @return the name 312 */ 313 public String getName() 314 { 315 return name; 316 } 317 318 /** 319 * @param name 320 * the name to set 321 */ 322 public void setName(String name) 323 { 324 if (this.name != name) 325 { 326 this.name = name; 327 propertyChanged(PROPERTY_NAME); 328 } 329 } 330 331 /** 332 * @return the priority 333 */ 334 public OverlayPriority getPriority() 335 { 336 return priority; 337 } 338 339 /** 340 * @param priority 341 * the priority to set 342 */ 343 public void setPriority(OverlayPriority priority) 344 { 345 if (this.priority != priority) 346 { 347 this.priority = priority; 348 propertyChanged(PROPERTY_PRIORITY); 349 } 350 } 351 352 /** 353 * Returns <code>true</code> if the overlay is attached to the specified {@link Sequence}. 354 */ 355 public boolean isAttached(Sequence sequence) 356 { 357 if (sequence != null) 358 return sequence.contains(this); 359 360 return false; 361 } 362 363 /** 364 * @deprecated Use {@link #getCanBeRemoved()} instead. 365 * @see #setCanBeRemoved(boolean) 366 */ 367 @Deprecated 368 public boolean isFixed() 369 { 370 return !getCanBeRemoved(); 371 } 372 373 /** 374 * @deprecated Use {@link #setCanBeRemoved(boolean)} instead. 375 */ 376 @Deprecated 377 public void setFixed(boolean value) 378 { 379 setCanBeRemoved(!value); 380 } 381 382 /** 383 * Returns <code>true</code> if the overlay can be freely removed from the Canvas where it 384 * appears and <code>false</code> otherwise.<br/> 385 * 386 * @see #setCanBeRemoved(boolean) 387 */ 388 public boolean getCanBeRemoved() 389 { 390 return canBeRemoved; 391 } 392 393 /** 394 * Set the <code>canBeRemoved</code> property.<br/> 395 * Set it to false if you want to prevent the overlay to be removed from the Canvas where it 396 * appears. 397 */ 398 public void setCanBeRemoved(boolean value) 399 { 400 if (canBeRemoved != value) 401 { 402 canBeRemoved = value; 403 propertyChanged(PROPERTY_CANBEREMOVED); 404 } 405 } 406 407 /** 408 * Return persistent property.<br/> 409 * When set to <code>true</code> the Overlay will be saved in the Sequence persistent XML data. 410 */ 411 public boolean isPersistent() 412 { 413 return persistent; 414 } 415 416 /** 417 * Set persistent property.<br/> 418 * When set to <code>true</code> the Overlay will be saved in the Sequence persistent XML data 419 * (default is <code>false</code>). 420 */ 421 public void setPersistent(boolean value) 422 { 423 if (persistent != value) 424 { 425 persistent = value; 426 propertyChanged(PROPERTY_PERSISTENT); 427 } 428 } 429 430 /** 431 * Return read only property.<br/> 432 * When set to <code>true</code> we cannot anymore modify overlay properties from the GUI. 433 */ 434 public boolean isReadOnly() 435 { 436 return readOnly; 437 } 438 439 /** 440 * Set read only property.<br/> 441 * When set to <code>true</code> we cannot anymore modify overlay properties from the GUI. 442 */ 443 public void setReadOnly(boolean value) 444 { 445 if (readOnly != value) 446 { 447 readOnly = value; 448 propertyChanged(PROPERTY_READONLY); 449 } 450 } 451 452 /** 453 * @return <code>true</code> is the overlay should receive {@link KeyEvent} even when it is not 454 * visible. 455 */ 456 public boolean getReceiveKeyEventOnHidden() 457 { 458 return receiveKeyEventOnHidden; 459 } 460 461 /** 462 * Set to <code>true</code> if you want to overlay to receive {@link KeyEvent} even when it is 463 * not visible. 464 */ 465 public void setReceiveKeyEventOnHidden(boolean value) 466 { 467 if (receiveKeyEventOnHidden != value) 468 { 469 receiveKeyEventOnHidden = value; 470 propertyChanged(PROPERTY_RECEIVEKEYEVENTONHIDDEN); 471 } 472 } 473 474 /** 475 * @return <code>true</code> is the overlay should receive {@link MouseEvent} even when it is 476 * not visible. 477 */ 478 public boolean getReceiveMouseEventOnHidden() 479 { 480 return receiveMouseEventOnHidden; 481 } 482 483 /** 484 * Set to <code>true</code> if you want to overlay to receive {@link KeyEvent} even when it is 485 * not visible. 486 */ 487 public void setReceiveMouseEventOnHidden(boolean value) 488 { 489 if (receiveMouseEventOnHidden != value) 490 { 491 receiveMouseEventOnHidden = value; 492 propertyChanged(PROPERTY_RECEIVEMOUSEEVENTONHIDDEN); 493 } 494 } 495 496 /** 497 * Override this method to provide an extra options panel for the overlay.<br> 498 * The options panel will appears in the inspector when the layer's overlay is selected. 499 */ 500 public JPanel getOptionsPanel() 501 { 502 return null; 503 } 504 505 /** 506 * @deprecated Use {@link Sequence#addOverlay(Overlay)} instead. 507 */ 508 @Deprecated 509 public void attachTo(Sequence sequence) 510 { 511 if (sequence != null) 512 sequence.addOverlay(this); 513 } 514 515 /** 516 * @deprecated Use {@link Sequence#removeOverlay(Overlay)} instead. 517 */ 518 @Deprecated 519 public void detachFrom(Sequence sequence) 520 { 521 if (sequence != null) 522 sequence.removeOverlay(this); 523 } 524 525 /** 526 * Remove the Overlay from all sequences and canvas where it is currently attached. 527 */ 528 public void remove() 529 { 530 for (Sequence sequence : getSequences()) 531 sequence.removeOverlay(this); 532 for (IcyCanvas canvas : getAttachedCanvas()) 533 canvas.removeLayer(this); 534 } 535 536 /** 537 * Returns all sequences where the overlay is currently attached. 538 */ 539 public List<Sequence> getSequences() 540 { 541 return Icy.getMainInterface().getSequencesContaining(this); 542 } 543 544 /** 545 * Returns all canvas where the overlay is currently present as a layer. 546 */ 547 public List<IcyCanvas> getAttachedCanvas() 548 { 549 final List<IcyCanvas> result = new ArrayList<IcyCanvas>(); 550 551 for (Viewer viewer : Icy.getMainInterface().getViewers()) 552 { 553 final IcyCanvas canvas = viewer.getCanvas(); 554 555 if ((canvas != null) && canvas.hasLayer(this)) 556 result.add(canvas); 557 } 558 559 return result; 560 } 561 562 public void beginUpdate() 563 { 564 updater.beginUpdate(); 565 } 566 567 public void endUpdate() 568 { 569 updater.endUpdate(); 570 } 571 572 public boolean isUpdating() 573 { 574 return updater.isUpdating(); 575 } 576 577 /** 578 * @deprecated Use {@link #painterChanged()} instead. 579 */ 580 @Deprecated 581 public void changed() 582 { 583 painterChanged(); 584 } 585 586 /** 587 * Notify the painter content has changed.<br> 588 * All sequence containing the overlay will be repainted to reflect the change. 589 */ 590 public void painterChanged() 591 { 592 updater.changed(new OverlayEvent(this, OverlayEventType.PAINTER_CHANGED)); 593 } 594 595 /** 596 * Notify the overlay property has changed. 597 */ 598 public void propertyChanged(String propertyName) 599 { 600 updater.changed(new OverlayEvent(this, OverlayEventType.PROPERTY_CHANGED, propertyName)); 601 } 602 603 @Override 604 public void onChanged(CollapsibleEvent object) 605 { 606 fireOverlayChangedEvent((OverlayEvent) object); 607 } 608 609 protected void fireOverlayChangedEvent(OverlayEvent event) 610 { 611 for (OverlayListener listener : new ArrayList<OverlayListener>(listeners)) 612 listener.overlayChanged(event); 613 } 614 615 /** 616 * Add a listener. 617 */ 618 public void addOverlayListener(OverlayListener listener) 619 { 620 listeners.add(listener); 621 } 622 623 /** 624 * Remove a listener. 625 */ 626 public void removeOverlayListener(OverlayListener listener) 627 { 628 listeners.remove(listener); 629 } 630 631 /** 632 * Paint method called to draw the overlay. 633 */ 634 @Override 635 public void paint(Graphics2D g, Sequence sequence, IcyCanvas canvas) 636 { 637 // nothing by default 638 } 639 640 /** 641 * @deprecated Use {@link #mousePressed(MouseEvent, Point5D.Double, IcyCanvas)} instead 642 */ 643 @Deprecated 644 @Override 645 public void mousePressed(MouseEvent e, Point2D imagePoint, IcyCanvas canvas) 646 { 647 // no action by default 648 } 649 650 /** 651 * @deprecated Use {@link #mouseReleased(MouseEvent, Point5D.Double, IcyCanvas)} instead 652 */ 653 @Deprecated 654 @Override 655 public void mouseReleased(MouseEvent e, Point2D imagePoint, IcyCanvas canvas) 656 { 657 // no action by default 658 } 659 660 /** 661 * @deprecated Use {@link #mouseClick(MouseEvent, Point5D.Double, IcyCanvas)} instead 662 */ 663 @Deprecated 664 @Override 665 public void mouseClick(MouseEvent e, Point2D imagePoint, IcyCanvas canvas) 666 { 667 // no action by default 668 } 669 670 /** 671 * @deprecated Use {@link #mouseMove(MouseEvent, Point5D.Double, IcyCanvas)} instead 672 */ 673 @Deprecated 674 @Override 675 public void mouseMove(MouseEvent e, Point2D imagePoint, IcyCanvas canvas) 676 { 677 // no action by default 678 } 679 680 /** 681 * @deprecated Use {@link #mouseDrag(MouseEvent, Point5D.Double, IcyCanvas)} instead 682 */ 683 @Deprecated 684 @Override 685 public void mouseDrag(MouseEvent e, Point2D imagePoint, IcyCanvas canvas) 686 { 687 // no action by default 688 } 689 690 /** 691 * @deprecated Use {@link #mouseEntered(MouseEvent, Point5D.Double, IcyCanvas)} instead 692 */ 693 @Deprecated 694 public void mouseEntered(MouseEvent e, Point2D imagePoint, IcyCanvas canvas) 695 { 696 // no action by default 697 } 698 699 /** 700 * @deprecated Use {@link #mouseExited(MouseEvent, Point5D.Double, IcyCanvas)} instead 701 */ 702 @Deprecated 703 public void mouseExited(MouseEvent e, Point2D imagePoint, IcyCanvas canvas) 704 { 705 // no action by default 706 } 707 708 /** 709 * @deprecated Use {@link #mouseWheelMoved(MouseWheelEvent, Point5D.Double, IcyCanvas)} instead 710 */ 711 @Deprecated 712 public void mouseWheelMoved(MouseWheelEvent e, Point2D imagePoint, IcyCanvas canvas) 713 { 714 // no action by default 715 } 716 717 /** 718 * @deprecated Use {@link #keyPressed(KeyEvent, Point5D.Double, IcyCanvas)} instead 719 */ 720 @Deprecated 721 @Override 722 public void keyPressed(KeyEvent e, Point2D imagePoint, IcyCanvas canvas) 723 { 724 // no action by default 725 } 726 727 /** 728 * @deprecated Use {@link #keyReleased(KeyEvent, Point5D.Double, IcyCanvas)} instead 729 */ 730 @Deprecated 731 @Override 732 public void keyReleased(KeyEvent e, Point2D imagePoint, IcyCanvas canvas) 733 { 734 // no action by default 735 } 736 737 /** 738 * Mouse press event forwarded to the overlay. 739 * 740 * @param e 741 * mouse event 742 * @param imagePoint 743 * mouse position (image coordinates) 744 * @param canvas 745 * icy canvas 746 */ 747 public void mousePressed(MouseEvent e, Point5D.Double imagePoint, IcyCanvas canvas) 748 { 749 // provide backward compatibility 750 if (imagePoint != null) 751 mousePressed(e, imagePoint.toPoint2D(), canvas); 752 else 753 mousePressed(e, (Point2D) null, canvas); 754 } 755 756 /** 757 * Mouse release event forwarded to the overlay. 758 * 759 * @param e 760 * mouse event 761 * @param imagePoint 762 * mouse position (image coordinates) 763 * @param canvas 764 * icy canvas 765 */ 766 public void mouseReleased(MouseEvent e, Point5D.Double imagePoint, IcyCanvas canvas) 767 { 768 // provide backward compatibility 769 if (imagePoint != null) 770 mouseReleased(e, imagePoint.toPoint2D(), canvas); 771 else 772 mouseReleased(e, (Point2D) null, canvas); 773 } 774 775 /** 776 * Mouse click event forwarded to the overlay. 777 * 778 * @param e 779 * mouse event 780 * @param imagePoint 781 * mouse position (image coordinates) 782 * @param canvas 783 * icy canvas 784 */ 785 public void mouseClick(MouseEvent e, Point5D.Double imagePoint, IcyCanvas canvas) 786 { 787 // provide backward compatibility 788 if (imagePoint != null) 789 mouseClick(e, imagePoint.toPoint2D(), canvas); 790 else 791 mouseClick(e, (Point2D) null, canvas); 792 } 793 794 /** 795 * Mouse move event forwarded to the overlay. 796 * 797 * @param e 798 * mouse event 799 * @param imagePoint 800 * mouse position (image coordinates) 801 * @param canvas 802 * icy canvas 803 */ 804 public void mouseMove(MouseEvent e, Point5D.Double imagePoint, IcyCanvas canvas) 805 { 806 // provide backward compatibility 807 if (imagePoint != null) 808 mouseMove(e, imagePoint.toPoint2D(), canvas); 809 else 810 mouseMove(e, (Point2D) null, canvas); 811 } 812 813 /** 814 * Mouse drag event forwarded to the overlay. 815 * 816 * @param e 817 * mouse event 818 * @param imagePoint 819 * mouse position (image coordinates) 820 * @param canvas 821 * icy canvas 822 */ 823 public void mouseDrag(MouseEvent e, Point5D.Double imagePoint, IcyCanvas canvas) 824 { 825 // provide backward compatibility 826 if (imagePoint != null) 827 mouseDrag(e, imagePoint.toPoint2D(), canvas); 828 else 829 mouseDrag(e, (Point2D) null, canvas); 830 } 831 832 /** 833 * Mouse enter event forwarded to the overlay. 834 * 835 * @param e 836 * mouse event 837 * @param imagePoint 838 * mouse position (image coordinates) 839 * @param canvas 840 * icy canvas 841 */ 842 public void mouseEntered(MouseEvent e, Point5D.Double imagePoint, IcyCanvas canvas) 843 { 844 // provide backward compatibility 845 if (imagePoint != null) 846 mouseEntered(e, imagePoint.toPoint2D(), canvas); 847 else 848 mouseEntered(e, (Point2D) null, canvas); 849 } 850 851 /** 852 * Mouse exit event forwarded to the overlay. 853 * 854 * @param e 855 * mouse event 856 * @param imagePoint 857 * mouse position (image coordinates) 858 * @param canvas 859 * icy canvas 860 */ 861 public void mouseExited(MouseEvent e, Point5D.Double imagePoint, IcyCanvas canvas) 862 { 863 // provide backward compatibility 864 if (imagePoint != null) 865 mouseExited(e, imagePoint.toPoint2D(), canvas); 866 else 867 mouseExited(e, (Point2D) null, canvas); 868 } 869 870 /** 871 * Mouse wheel moved event forwarded to the overlay. 872 * 873 * @param e 874 * mouse event 875 * @param imagePoint 876 * mouse position (image coordinates) 877 * @param canvas 878 * icy canvas 879 */ 880 public void mouseWheelMoved(MouseWheelEvent e, Point5D.Double imagePoint, IcyCanvas canvas) 881 { 882 // provide backward compatibility 883 if (imagePoint != null) 884 mouseWheelMoved(e, imagePoint.toPoint2D(), canvas); 885 else 886 mouseWheelMoved(e, (Point2D) null, canvas); 887 } 888 889 /** 890 * Key press event forwarded to the overlay. 891 * 892 * @param e 893 * key event 894 * @param imagePoint 895 * mouse position (image coordinates) 896 * @param canvas 897 * icy canvas 898 */ 899 public void keyPressed(KeyEvent e, Point5D.Double imagePoint, IcyCanvas canvas) 900 { 901 // provide backward compatibility 902 if (imagePoint != null) 903 keyPressed(e, imagePoint.toPoint2D(), canvas); 904 else 905 keyPressed(e, (Point2D) null, canvas); 906 } 907 908 /** 909 * Key release event forwarded to the overlay. 910 * 911 * @param e 912 * key event 913 * @param imagePoint 914 * mouse position (image coordinates) 915 * @param canvas 916 * icy canvas 917 */ 918 public void keyReleased(KeyEvent e, Point5D.Double imagePoint, IcyCanvas canvas) 919 { 920 // provide backward compatibility 921 if (imagePoint != null) 922 keyReleased(e, imagePoint.toPoint2D(), canvas); 923 else 924 keyReleased(e, (Point2D) null, canvas); 925 } 926 927 public boolean loadFromXML(Node node, boolean preserveId) 928 { 929 if (node == null) 930 return false; 931 932 beginUpdate(); 933 try 934 { 935 // FIXME : this can make duplicate id but it is also important to preserve id 936 if (!preserveId) 937 { 938 id = XMLUtil.getElementIntValue(node, ID_ID, 0); 939 synchronized (Overlay.class) 940 { 941 // avoid having same id 942 if (id_gen <= id) 943 id_gen = id + 1; 944 } 945 } 946 setName(XMLUtil.getElementValue(node, ID_NAME, "")); 947 setPriority(OverlayPriority.values()[XMLUtil.getElementIntValue(node, ID_PRIORITY, 948 OverlayPriority.SHAPE_NORMAL.ordinal())]); 949 setReadOnly(XMLUtil.getElementBooleanValue(node, ID_READONLY, false)); 950 setReceiveKeyEventOnHidden(XMLUtil.getElementBooleanValue(node, ID_RECEIVEKEYEVENTONHIDDEN, false)); 951 setReceiveMouseEventOnHidden(XMLUtil.getElementBooleanValue(node, ID_RECEIVEMOUSEEVENTONHIDDEN, false)); 952 } 953 finally 954 { 955 endUpdate(); 956 } 957 958 return true; 959 } 960 961 @Override 962 public boolean loadFromXML(Node node) 963 { 964 return loadFromXML(node, false); 965 } 966 967 @Override 968 public boolean saveToXML(Node node) 969 { 970 if (node == null) 971 return false; 972 973 XMLUtil.setElementValue(node, ID_CLASSNAME, getClass().getName()); 974 XMLUtil.setElementIntValue(node, ID_ID, id); 975 XMLUtil.setElementValue(node, ID_NAME, getName()); 976 XMLUtil.setElementIntValue(node, ID_PRIORITY, getPriority().ordinal()); 977 XMLUtil.setElementBooleanValue(node, ID_READONLY, isReadOnly()); 978 XMLUtil.setElementBooleanValue(node, ID_RECEIVEKEYEVENTONHIDDEN, getReceiveKeyEventOnHidden()); 979 XMLUtil.setElementBooleanValue(node, ID_RECEIVEMOUSEEVENTONHIDDEN, getReceiveMouseEventOnHidden()); 980 981 return true; 982 } 983 984 @Override 985 public int compareTo(Overlay o) 986 { 987 // highest priority first 988 return o.priority.ordinal() - priority.ordinal(); 989 } 990}