1 /*
2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
462
463 // --- local methods -----------------------------------------------
464
465 /**
466 * Returns the maximum number of key/value pairs to try and
467 * compress into unique/immutable sets. Any sets above this
468 * limit will use hashtables and be a MutableAttributeSet.
469 *
470 * @return the threshold
471 */
472 protected int getCompressionThreshold() {
473 return THRESHOLD;
474 }
475
476 /**
477 * Create a compact set of attributes that might be shared.
478 * This is a hook for subclasses that want to alter the
479 * behavior of SmallAttributeSet. This can be reimplemented
480 * to return an AttributeSet that provides some sort of
481 * attribute conversion.
482 *
483 * @param a The set of attributes to be represented in the
484 * the compact form.
485 */
486 protected SmallAttributeSet createSmallAttributeSet(AttributeSet a) {
487 return new SmallAttributeSet(a);
488 }
489
490 /**
491 * Create a large set of attributes that should trade off
492 * space for time. This set will not be shared. This is
493 * a hook for subclasses that want to alter the behavior
494 * of the larger attribute storage format (which is
495 * SimpleAttributeSet by default). This can be reimplemented
496 * to return a MutableAttributeSet that provides some sort of
497 * attribute conversion.
498 *
499 * @param a The set of attributes to be represented in the
500 * the larger form.
501 */
502 protected MutableAttributeSet createLargeAttributeSet(AttributeSet a) {
503 return new SimpleAttributeSet(a);
504 }
505
506 /**
507 * Clean the unused immutable sets out of the hashtable.
508 */
509 synchronized void removeUnusedSets() {
510 attributesPool.size(); // force WeakHashMap to expunge stale entries
511 }
512
513 /**
514 * Search for an existing attribute set using the current search
515 * parameters. If a matching set is found, return it. If a match
516 * is not found, we create a new set and add it to the pool.
517 */
518 AttributeSet getImmutableUniqueSet() {
519 // PENDING(prinz) should consider finding a alternative to
520 // generating extra garbage on search key.
541 }
542
543 /**
544 * Converts a StyleContext to a String.
545 *
546 * @return the string
547 */
548 public String toString() {
549 removeUnusedSets();
550 String s = "";
551 for (SmallAttributeSet set : attributesPool.keySet()) {
552 s = s + set + "\n";
553 }
554 return s;
555 }
556
557 // --- serialization ---------------------------------------------
558
559 /**
560 * Context-specific handling of writing out attributes
561 */
562 public void writeAttributes(ObjectOutputStream out,
563 AttributeSet a) throws IOException {
564 writeAttributeSet(out, a);
565 }
566
567 /**
568 * Context-specific handling of reading in attributes
569 */
570 public void readAttributes(ObjectInputStream in,
571 MutableAttributeSet a) throws ClassNotFoundException, IOException {
572 readAttributeSet(in, a);
573 }
574
575 /**
576 * Writes a set of attributes to the given object stream
577 * for the purpose of serialization. This will take
578 * special care to deal with static attribute keys that
579 * have been registered wit the
580 * <code>registerStaticAttributeKey</code> method.
581 * Any attribute key not registered as a static key
582 * will be serialized directly. All values are expected
583 * to be serializable.
584 *
585 * @param out the output stream
586 * @param a the attribute set
587 * @exception IOException on any I/O error
588 */
668 * by toString should not have the class reference
669 * in it (ie it should be reimplemented from the
670 * definition in Object) in order to be the same when
671 * recomputed later.
672 *
673 * @param key the non-null object key
674 */
675 public static void registerStaticAttributeKey(Object key) {
676 String ioFmt = key.getClass().getName() + "." + key.toString();
677 if (freezeKeyMap == null) {
678 freezeKeyMap = new Hashtable<Object, String>();
679 thawKeyMap = new Hashtable<String, Object>();
680 }
681 freezeKeyMap.put(key, ioFmt);
682 thawKeyMap.put(ioFmt, key);
683 }
684
685 /**
686 * Returns the object previously registered with
687 * <code>registerStaticAttributeKey</code>.
688 */
689 public static Object getStaticAttribute(Object key) {
690 if (thawKeyMap == null || key == null) {
691 return null;
692 }
693 return thawKeyMap.get(key);
694 }
695
696 /**
697 * Returns the String that <code>key</code> will be registered with
698 * @see #getStaticAttribute
699 * @see #registerStaticAttributeKey
700 */
701 public static Object getStaticAttributeKey(Object key) {
702 return key.getClass().getName() + "." + key.toString();
703 }
704
705 private void writeObject(java.io.ObjectOutputStream s)
706 throws IOException
707 {
708 // clean out unused sets before saving
709 removeUnusedSets();
710
711 s.defaultWriteObject();
712 }
713
714 private void readObject(ObjectInputStream s)
715 throws ClassNotFoundException, IOException
716 {
717 fontSearch = new FontKey(null, 0, 0);
718 fontTable = new Hashtable<>();
719 search = new SimpleAttributeSet();
755 * to be cleaned out of the hashtable they are stored
756 * in.
757 */
758 private int unusedSets;
759
760 /**
761 * The threshold for no longer sharing the set of attributes
762 * in an immutable table.
763 */
764 static final int THRESHOLD = 9;
765
766 /**
767 * This class holds a small number of attributes in an array.
768 * The storage format is key, value, key, value, etc. The size
769 * of the set is the length of the array divided by two. By
770 * default, this is the class that will be used to store attributes
771 * when held in the compact sharable form.
772 */
773 public class SmallAttributeSet implements AttributeSet {
774
775 public SmallAttributeSet(Object[] attributes) {
776 this.attributes = attributes;
777 updateResolveParent();
778 }
779
780 public SmallAttributeSet(AttributeSet attrs) {
781 int n = attrs.getAttributeCount();
782 Object[] tbl = new Object[2 * n];
783 Enumeration<?> names = attrs.getAttributeNames();
784 int i = 0;
785 while (names.hasMoreElements()) {
786 tbl[i] = names.nextElement();
787 tbl[i+1] = attrs.getAttribute(tbl[i]);
788 i += 2;
789 }
790 attributes = tbl;
791 updateResolveParent();
792 }
793
794 private void updateResolveParent() {
795 resolveParent = null;
796 Object[] tbl = attributes;
797 for (int i = 0; i < tbl.length; i += 2) {
798 if (tbl[i] == StyleConstants.ResolveAttribute) {
799 resolveParent = (AttributeSet)tbl[i + 1];
801 }
802 }
803 }
804
805 Object getLocalAttribute(Object nm) {
806 if (nm == StyleConstants.ResolveAttribute) {
807 return resolveParent;
808 }
809 Object[] tbl = attributes;
810 for (int i = 0; i < tbl.length; i += 2) {
811 if (nm.equals(tbl[i])) {
812 return tbl[i+1];
813 }
814 }
815 return null;
816 }
817
818 // --- Object methods -------------------------
819
820 /**
821 * Returns a string showing the key/value pairs
822 */
823 public String toString() {
824 String s = "{";
825 Object[] tbl = attributes;
826 for (int i = 0; i < tbl.length; i += 2) {
827 if (tbl[i+1] instanceof AttributeSet) {
828 // don't recurse
829 s = s + tbl[i] + "=" + "AttributeSet" + ",";
830 } else {
831 s = s + tbl[i] + "=" + tbl[i+1] + ",";
832 }
833 }
834 s = s + "}";
835 return s;
836 }
837
838 /**
839 * Returns a hashcode for this set of attributes.
840 * @return a hashcode value for this set of attributes.
841 */
1365 * @see EventListenerList
1366 */
1367 protected void fireStateChanged() {
1368 // Guaranteed to return a non-null array
1369 Object[] listeners = listenerList.getListenerList();
1370 // Process the listeners last to first, notifying
1371 // those that are interested in this event
1372 for (int i = listeners.length-2; i>=0; i-=2) {
1373 if (listeners[i]==ChangeListener.class) {
1374 // Lazily create the event:
1375 if (changeEvent == null)
1376 changeEvent = new ChangeEvent(this);
1377 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
1378 }
1379 }
1380 }
1381
1382 /**
1383 * Return an array of all the listeners of the given type that
1384 * were added to this model.
1385 *
1386 * @return all of the objects receiving <em>listenerType</em> notifications
1387 * from this model
1388 *
1389 * @since 1.3
1390 */
1391 public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
1392 return listenerList.getListeners(listenerType);
1393 }
1394
1395 // --- AttributeSet ----------------------------
1396 // delegated to the immutable field "attributes"
1397
1398 /**
1399 * Gets the number of attributes that are defined.
1400 *
1401 * @return the number of attributes >= 0
1402 * @see AttributeSet#getAttributeCount
1403 */
1404 public int getAttributeCount() {
1405 return attributes.getAttributeCount();
|
1 /*
2 * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
462
463 // --- local methods -----------------------------------------------
464
465 /**
466 * Returns the maximum number of key/value pairs to try and
467 * compress into unique/immutable sets. Any sets above this
468 * limit will use hashtables and be a MutableAttributeSet.
469 *
470 * @return the threshold
471 */
472 protected int getCompressionThreshold() {
473 return THRESHOLD;
474 }
475
476 /**
477 * Create a compact set of attributes that might be shared.
478 * This is a hook for subclasses that want to alter the
479 * behavior of SmallAttributeSet. This can be reimplemented
480 * to return an AttributeSet that provides some sort of
481 * attribute conversion.
482 * @param a The set of attributes to be represented in the
483 * the compact form.
484 * @return a compact set of attributes that might be shared
485 */
486 protected SmallAttributeSet createSmallAttributeSet(AttributeSet a) {
487 return new SmallAttributeSet(a);
488 }
489
490 /**
491 * Create a large set of attributes that should trade off
492 * space for time. This set will not be shared. This is
493 * a hook for subclasses that want to alter the behavior
494 * of the larger attribute storage format (which is
495 * SimpleAttributeSet by default). This can be reimplemented
496 * to return a MutableAttributeSet that provides some sort of
497 * attribute conversion.
498 *
499 * @param a The set of attributes to be represented in the
500 * the larger form.
501 * @return a large set of attributes that should trade off
502 * space for time
503 */
504 protected MutableAttributeSet createLargeAttributeSet(AttributeSet a) {
505 return new SimpleAttributeSet(a);
506 }
507
508 /**
509 * Clean the unused immutable sets out of the hashtable.
510 */
511 synchronized void removeUnusedSets() {
512 attributesPool.size(); // force WeakHashMap to expunge stale entries
513 }
514
515 /**
516 * Search for an existing attribute set using the current search
517 * parameters. If a matching set is found, return it. If a match
518 * is not found, we create a new set and add it to the pool.
519 */
520 AttributeSet getImmutableUniqueSet() {
521 // PENDING(prinz) should consider finding a alternative to
522 // generating extra garbage on search key.
543 }
544
545 /**
546 * Converts a StyleContext to a String.
547 *
548 * @return the string
549 */
550 public String toString() {
551 removeUnusedSets();
552 String s = "";
553 for (SmallAttributeSet set : attributesPool.keySet()) {
554 s = s + set + "\n";
555 }
556 return s;
557 }
558
559 // --- serialization ---------------------------------------------
560
561 /**
562 * Context-specific handling of writing out attributes
563 * @param out the output stream
564 * @param a the attribute set
565 * @exception IOException on any I/O error
566 */
567 public void writeAttributes(ObjectOutputStream out,
568 AttributeSet a) throws IOException {
569 writeAttributeSet(out, a);
570 }
571
572 /**
573 * Context-specific handling of reading in attributes
574 * @param in the object stream to read the attribute data from.
575 * @param a the attribute set to place the attribute
576 * definitions in.
577 * @exception ClassNotFoundException passed upward if encountered
578 * when reading the object stream.
579 * @exception IOException passed upward if encountered when
580 * reading the object stream.
581 */
582 public void readAttributes(ObjectInputStream in,
583 MutableAttributeSet a) throws ClassNotFoundException, IOException {
584 readAttributeSet(in, a);
585 }
586
587 /**
588 * Writes a set of attributes to the given object stream
589 * for the purpose of serialization. This will take
590 * special care to deal with static attribute keys that
591 * have been registered wit the
592 * <code>registerStaticAttributeKey</code> method.
593 * Any attribute key not registered as a static key
594 * will be serialized directly. All values are expected
595 * to be serializable.
596 *
597 * @param out the output stream
598 * @param a the attribute set
599 * @exception IOException on any I/O error
600 */
680 * by toString should not have the class reference
681 * in it (ie it should be reimplemented from the
682 * definition in Object) in order to be the same when
683 * recomputed later.
684 *
685 * @param key the non-null object key
686 */
687 public static void registerStaticAttributeKey(Object key) {
688 String ioFmt = key.getClass().getName() + "." + key.toString();
689 if (freezeKeyMap == null) {
690 freezeKeyMap = new Hashtable<Object, String>();
691 thawKeyMap = new Hashtable<String, Object>();
692 }
693 freezeKeyMap.put(key, ioFmt);
694 thawKeyMap.put(ioFmt, key);
695 }
696
697 /**
698 * Returns the object previously registered with
699 * <code>registerStaticAttributeKey</code>.
700 * @param key the object key
701 * @return Returns the object previously registered with
702 * {@code registerStaticAttributeKey}
703 */
704 public static Object getStaticAttribute(Object key) {
705 if (thawKeyMap == null || key == null) {
706 return null;
707 }
708 return thawKeyMap.get(key);
709 }
710
711 /**
712 * Returns the String that <code>key</code> will be registered with.
713 * @see #getStaticAttribute
714 * @see #registerStaticAttributeKey
715 * @param key the object key
716 * @return the String that {@code key} will be registered with
717 */
718 public static Object getStaticAttributeKey(Object key) {
719 return key.getClass().getName() + "." + key.toString();
720 }
721
722 private void writeObject(java.io.ObjectOutputStream s)
723 throws IOException
724 {
725 // clean out unused sets before saving
726 removeUnusedSets();
727
728 s.defaultWriteObject();
729 }
730
731 private void readObject(ObjectInputStream s)
732 throws ClassNotFoundException, IOException
733 {
734 fontSearch = new FontKey(null, 0, 0);
735 fontTable = new Hashtable<>();
736 search = new SimpleAttributeSet();
772 * to be cleaned out of the hashtable they are stored
773 * in.
774 */
775 private int unusedSets;
776
777 /**
778 * The threshold for no longer sharing the set of attributes
779 * in an immutable table.
780 */
781 static final int THRESHOLD = 9;
782
783 /**
784 * This class holds a small number of attributes in an array.
785 * The storage format is key, value, key, value, etc. The size
786 * of the set is the length of the array divided by two. By
787 * default, this is the class that will be used to store attributes
788 * when held in the compact sharable form.
789 */
790 public class SmallAttributeSet implements AttributeSet {
791
792 /**
793 * Constructs a SmallAttributeSet.
794 * @param attributes the attributes
795 */
796 public SmallAttributeSet(Object[] attributes) {
797 this.attributes = attributes;
798 updateResolveParent();
799 }
800
801 /**
802 * Constructs a SmallAttributeSet.
803 * @param attrs the attributes
804 */
805 public SmallAttributeSet(AttributeSet attrs) {
806 int n = attrs.getAttributeCount();
807 Object[] tbl = new Object[2 * n];
808 Enumeration<?> names = attrs.getAttributeNames();
809 int i = 0;
810 while (names.hasMoreElements()) {
811 tbl[i] = names.nextElement();
812 tbl[i+1] = attrs.getAttribute(tbl[i]);
813 i += 2;
814 }
815 attributes = tbl;
816 updateResolveParent();
817 }
818
819 private void updateResolveParent() {
820 resolveParent = null;
821 Object[] tbl = attributes;
822 for (int i = 0; i < tbl.length; i += 2) {
823 if (tbl[i] == StyleConstants.ResolveAttribute) {
824 resolveParent = (AttributeSet)tbl[i + 1];
826 }
827 }
828 }
829
830 Object getLocalAttribute(Object nm) {
831 if (nm == StyleConstants.ResolveAttribute) {
832 return resolveParent;
833 }
834 Object[] tbl = attributes;
835 for (int i = 0; i < tbl.length; i += 2) {
836 if (nm.equals(tbl[i])) {
837 return tbl[i+1];
838 }
839 }
840 return null;
841 }
842
843 // --- Object methods -------------------------
844
845 /**
846 * Returns a string showing the key/value pairs.
847 * @return a string showing the key/value pairs
848 */
849 public String toString() {
850 String s = "{";
851 Object[] tbl = attributes;
852 for (int i = 0; i < tbl.length; i += 2) {
853 if (tbl[i+1] instanceof AttributeSet) {
854 // don't recurse
855 s = s + tbl[i] + "=" + "AttributeSet" + ",";
856 } else {
857 s = s + tbl[i] + "=" + tbl[i+1] + ",";
858 }
859 }
860 s = s + "}";
861 return s;
862 }
863
864 /**
865 * Returns a hashcode for this set of attributes.
866 * @return a hashcode value for this set of attributes.
867 */
1391 * @see EventListenerList
1392 */
1393 protected void fireStateChanged() {
1394 // Guaranteed to return a non-null array
1395 Object[] listeners = listenerList.getListenerList();
1396 // Process the listeners last to first, notifying
1397 // those that are interested in this event
1398 for (int i = listeners.length-2; i>=0; i-=2) {
1399 if (listeners[i]==ChangeListener.class) {
1400 // Lazily create the event:
1401 if (changeEvent == null)
1402 changeEvent = new ChangeEvent(this);
1403 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
1404 }
1405 }
1406 }
1407
1408 /**
1409 * Return an array of all the listeners of the given type that
1410 * were added to this model.
1411 * @param <T> the listener type
1412 * @param listenerType the type of listeners requested
1413 * @return all of the objects receiving <em>listenerType</em> notifications
1414 * from this model
1415 *
1416 * @since 1.3
1417 */
1418 public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
1419 return listenerList.getListeners(listenerType);
1420 }
1421
1422 // --- AttributeSet ----------------------------
1423 // delegated to the immutable field "attributes"
1424
1425 /**
1426 * Gets the number of attributes that are defined.
1427 *
1428 * @return the number of attributes >= 0
1429 * @see AttributeSet#getAttributeCount
1430 */
1431 public int getAttributeCount() {
1432 return attributes.getAttributeCount();
|