diff --git a/sources/net.sf.j2s.core/META-INF/MANIFEST.MF b/sources/net.sf.j2s.core/META-INF/MANIFEST.MF index be6986b68..bac5aa6c0 100644 --- a/sources/net.sf.j2s.core/META-INF/MANIFEST.MF +++ b/sources/net.sf.j2s.core/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Java2Script Core Bundle-SymbolicName: net.sf.j2s.core;singleton:=true -Bundle-Version: 3.2.7 +Bundle-Version: 3.2.8 Bundle-Activator: net.sf.j2s.core.CorePlugin Bundle-Vendor: j2s.sourceforge.net Require-Bundle: org.eclipse.core.runtime, diff --git a/sources/net.sf.j2s.core/dist/examples.htm b/sources/net.sf.j2s.core/dist/examples.htm new file mode 100644 index 000000000..b1952d211 --- /dev/null +++ b/sources/net.sf.j2s.core/dist/examples.htm @@ -0,0 +1,93 @@ + + +Codestin Search App + + + +

Examples of java2script/SwingJS implementations

+ + + + + + + + + + + + + + +
+The pages listed below are a few of the thousands of implementations +of java2script/SwingJS that can be found on the web. Phase III is the +current phase of development, as of this writing. +If you have a Java applet or application that you would like to see running in JavaScript +or you have questions, feel free to contact +the principal developer of java2script/SwingJS, Bob Hanson at hansonr@stolaf.edu. +For more information, see also the GitHub main page for the java2script/SwingJS project +or the main page for Jmol/JSmol. +

+
+ +

+Phase I (2012-15): AWT Jmol applet to AWT-like JSmol (First-generation java2script transpiler) +

+
JSmol +Proteopedia - Life in 3D, a full *pedia devoted to the structure and function of biological macromolecules, with extensive contextualization of Jmol as JSmol. +

+CheMagic Virtual Model Kit, the most fully developed on-line chemical model kit ever, deeply integrating Jmol to allow far more than just making a molecular model. +

+symmetry@otterbein, one of the most beloved web pages for students of inorganic chemistry, with multiple examples of every three-dimensional point group in relation to molecular structure. +

+Simple.htm, a general page for exploring biological macromolecules (proteins, nucleic acids, carbohydrates) +

+Simple2.htm, a general page for exploring small molecules +

+nmr_predict_1H.htm Draw or search by name for a chemical structure and +simulate its proton nuclear magnect resonance (NMR) spectrum interactively +

+viewspec2, the front-end spectral viewing and analysis page for St. Olaf College's +Bruker 400 MHz cyberenabled NMR spectrometer (with 120-sample BACS autosampler) +

+directory of sample JSmol pages in the +Jmol/JSmol distribution ZIP file +

+
+

+Phase II (2016): Expansion to Swing and other applications and applets (“java2script/SwingJS”) +

+
Additional applet demos +SwingJS Examples +63 physics, math, and chemistry applets created over the course of six months still using the first-generation transpiler. +

+
+

+Phase III (2017-19): Second-generation transpiler and full AWT+Swing run-time environment applied to massive applet and application projects +

+
+Physlet Physics +main page, with 1200 interactive simulations in 39 chapters of introductory physics +

+
+MathePrisma + +ModulK.htm, with 450 interactive applets fully embedded in more than 50 engaging introductions to the major areas of mathematics on 1300 web pages (in German; click on Verschiebungen at the bottom of the page to start the story) +

+
+Jalview + +The JalviewJS examples page illustrating ways the Jalview multisequence alignment desktop can be created within a browser +

+
+ImageJ/SCIFIO + +TestJS-core.html Our first-ever test of transpiled Java SCIFIO in JavaScript, from the December 2019 Dresden bioimaging hackathon +

+io_scif_img_ConvertImg.html A second test, using SCIFIO to convert and download an ICS+IDS image to TIFF format (creates and downloads a TIFF file viewable in FIJI) +

+
+ + + diff --git a/sources/net.sf.j2s.core/dist/swingjs/SwingJS-site.zip b/sources/net.sf.j2s.core/dist/swingjs/SwingJS-site.zip index 763362e7b..0ce709b90 100644 Binary files a/sources/net.sf.j2s.core/dist/swingjs/SwingJS-site.zip and b/sources/net.sf.j2s.core/dist/swingjs/SwingJS-site.zip differ diff --git a/sources/net.sf.j2s.core/dist/swingjs/net.sf.j2s.core.jar b/sources/net.sf.j2s.core/dist/swingjs/net.sf.j2s.core.jar index 033f9a239..ab46e55cd 100644 Binary files a/sources/net.sf.j2s.core/dist/swingjs/net.sf.j2s.core.jar and b/sources/net.sf.j2s.core/dist/swingjs/net.sf.j2s.core.jar differ diff --git a/sources/net.sf.j2s.core/dist/swingjs/timestamp b/sources/net.sf.j2s.core/dist/swingjs/timestamp index 67fd83b6d..52640d02a 100644 --- a/sources/net.sf.j2s.core/dist/swingjs/timestamp +++ b/sources/net.sf.j2s.core/dist/swingjs/timestamp @@ -1 +1 @@ -20200202163957 +20200206154055 diff --git a/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.7/net.sf.j2s.core.jar b/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.7/net.sf.j2s.core.jar index 033f9a239..dd8bbf27a 100644 Binary files a/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.7/net.sf.j2s.core.jar and b/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.7/net.sf.j2s.core.jar differ diff --git a/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.7/timestamp b/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.7/timestamp index 67fd83b6d..9dfac13e4 100644 --- a/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.7/timestamp +++ b/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.7/timestamp @@ -1 +1 @@ -20200202163957 +20200205074936 diff --git a/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.8/DEV_NOTES.txt b/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.8/DEV_NOTES.txt new file mode 100644 index 000000000..ffbc7bf86 --- /dev/null +++ b/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.8/DEV_NOTES.txt @@ -0,0 +1,10 @@ +This is sources/net.sf.j2s.java.core/dist/DEV_NOTES.txt + +_j2sclasslist.txt + +the list of .js files concatenated into coreswingjs.js and minified to coreswingjs.z.js + + +SwingJS-site.zip + +the full site directory for SwingJS including all files not in the test/ directory. diff --git a/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.8/SwingJS-site.zip b/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.8/SwingJS-site.zip new file mode 100644 index 000000000..0ce709b90 Binary files /dev/null and b/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.8/SwingJS-site.zip differ diff --git a/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.8/_j2sclasslist.txt b/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.8/_j2sclasslist.txt new file mode 100644 index 000000000..23c7726ba --- /dev/null +++ b/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.8/_j2sclasslist.txt @@ -0,0 +1,408 @@ +java/applet/Applet.js +java/applet/AppletContext.js +java/applet/AppletStub.js +java/applet/JSApplet.js +java/awt/ActiveEvent.js +java/awt/Adjustable.js +java/awt/AWTEvent.js +java/awt/AWTEventMulticaster.js +java/awt/AWTKeyStroke.js +java/awt/BasicStroke.js +java/awt/BorderLayout.js +java/awt/Button.js +java/awt/Color.js +java/awt/color/ColorSpace.js +java/awt/Component.js +java/awt/ComponentOrientation.js +java/awt/ContainerOrderFocusTraversalPolicy.js +java/awt/Container.js +java/awt/Cursor.js +java/awt/DefaultFocusTraversalPolicy.js +java/awt/DefaultKeyboardFocusManager.js +java/awt/Dialog.js +java/awt/Dimension.js +java/awt/dnd/peer/DropTargetPeer.js +java/awt/event/ActionListener.js +java/awt/event/AdjustmentEvent.js +java/awt/event/AdjustmentListener.js +java/awt/event/AWTEventListener.js +java/awt/event/ComponentAdapter.js +java/awt/event/ComponentEvent.js +java/awt/event/ComponentListener.js +java/awt/event/ContainerListener.js +java/awt/event/FocusEvent.js +java/awt/event/FocusListener.js +java/awt/event/HierarchyBoundsListener.js +java/awt/event/HierarchyListener.js +java/awt/event/InputEvent.js +java/awt/event/InputMethodListener.js +java/awt/event/InvocationEvent.js +java/awt/event/ItemEvent.js +java/awt/event/ItemListener.js +java/awt/event/KeyListener.js +java/awt/event/MouseEvent.js +java/awt/event/MouseListener.js +java/awt/event/MouseMotionListener.js +java/awt/event/MouseWheelListener.js +java/awt/event/TextListener.js +java/awt/event/WindowAdapter.js +java/awt/event/WindowEvent.js +java/awt/event/WindowFocusListener.js +java/awt/event/WindowListener.js +java/awt/event/WindowStateListener.js +java/awt/EventDispatchThread.js +java/awt/EventFilter.js +java/awt/EventQueue.js +java/awt/EventQueueItem.js +java/awt/FlowLayout.js +java/awt/FocusTraversalPolicy.js +java/awt/Font.js +java/awt/font/FontRenderContext.js +java/awt/FontMetrics.js +java/awt/Frame.js +java/awt/geom/AffineTransform.js +java/awt/geom/Dimension2D.js +java/awt/geom/Path2D.js +java/awt/geom/PathIterator.js +java/awt/geom/Point2D.js +java/awt/geom/Rectangle2D.js +java/awt/geom/RectangularShape.js +java/awt/geom/RectIterator.js +java/awt/GraphicsCallback.js +java/awt/GraphicsConfiguration.js +java/awt/GraphicsDevice.js +java/awt/GraphicsEnvironment.js +java/awt/Image.js +java/awt/image/ImageObserver.js +java/awt/Insets.js +java/awt/ItemSelectable.js +java/awt/JSComponent.js +java/awt/JSDialog.js +java/awt/JSFrame.js +java/awt/JSPanel.js +java/awt/KeyboardFocusManager.js +java/awt/KeyEventDispatcher.js +java/awt/KeyEventPostProcessor.js +java/awt/Label.js +java/awt/LayoutManager.js +java/awt/LayoutManager2.js +java/awt/LightweightDispatcher.js +java/awt/Paint.js +java/awt/Panel.js +java/awt/peer/ComponentPeer.js +java/awt/peer/ContainerPeer.js +java/awt/peer/FramePeer.js +java/awt/peer/KeyboardFocusManagerPeer.js +java/awt/peer/LightweightPeer.js +java/awt/peer/WindowPeer.js +java/awt/Point.js +java/awt/Queue.js +java/awt/Rectangle.js +java/awt/RenderingHints.js +java/awt/Scrollbar.js +java/awt/ScrollPane.js +java/awt/Shape.js +java/awt/Stroke.js +java/awt/TextArea.js +java/awt/TextComponent.js +java/awt/TextField.js +java/awt/Toolkit.js +java/awt/Transparency.js +java/awt/Window.js +java/beans/ChangeListenerMap.js +java/beans/PropertyChangeEvent.js +java/beans/PropertyChangeListener.js +java/beans/PropertyChangeSupport.js +java/lang/AbstractStringBuilder.js +java/lang/Class.js +java/lang/Enum.js +java/lang/Iterable.js +java/lang/reflect/Constructor.js +java/lang/reflect/Method.js +java/lang/StringBuffer.js +java/lang/StringBuilder.js +java/lang/Thread.js +java/lang/ThreadGroup.js +java/math/RoundingMode.js +java/net/URL.js +java/net/URLStreamHandlerFactory.js +java/net/HttpURLConnection.js +java/net/URLStreamHandler.js +javax/net/ssl/HttpsUrlConnection.js +java/text/CharacterIterator.js +java/text/DecimalFormat.js +java/text/DecimalFormatSymbols.js +java/text/DigitList.js +java/text/FieldPosition.js +java/text/Format.js +java/text/NumberFormat.js +java/util/AbstractCollection.js +java/util/AbstractList.js +java/util/AbstractMap.js +java/util/AbstractSequentialList.js +java/util/AbstractSet.js +java/util/ArrayList.js +java/util/Arrays.js +java/util/Collection.js +java/util/Collections.js +java/util/Comparator.js +java/util/Deque.js +java/util/Dictionary.js +java/util/Enumeration.js +java/util/EventListener.js +java/util/EventObject.js +java/util/HashMap.js +java/util/HashSet.js +java/util/Hashtable.js +java/util/IdentityHashMap.js +java/util/Iterator.js +java/util/LinkedHashMap.js +java/util/LinkedList.js +java/util/List.js +java/util/ListResourceBundle.js +java/util/Locale.js +java/util/Map.js +java/util/Objects.js +java/util/Queue.js +java/util/Random.js +java/util/RandomAccess.js +java/util/ResourceBundle.js +java/util/Set.js +java/util/TimSort.js +java/util/Vector.js +javajs/api/JSFunction.js +javajs/util/AjaxURLConnection.js +javajs/util/AjaxURLStreamHandlerFactory.js +javajs/util/AU.js +javajs/util/JSThread.js +javajs/util/Lst.js +javajs/util/PT.js +javajs/util/Rdr.js +javajs/util/SB.js +javax/swing/AbstractAction.js +javax/swing/AbstractButton.js +javax/swing/AbstractListModel.js +javax/swing/Action.js +javax/swing/ActionMap.js +javax/swing/AncestorNotifier.js +javax/swing/ArrayTable.js +javax/swing/border/AbstractBorder.js +javax/swing/border/BevelBorder.js +javax/swing/border/Border.js +javax/swing/border/CompoundBorder.js +javax/swing/border/EmptyBorder.js +javax/swing/border/EtchedBorder.js +javax/swing/border/LineBorder.js +javax/swing/border/TitledBorder.js +javax/swing/BorderFactory.js +javax/swing/BoundedRangeModel.js +javax/swing/BoxLayout.js +javax/swing/ButtonGroup.js +javax/swing/ButtonModel.js +javax/swing/ClientPropertyKey.js +javax/swing/ComboBoxModel.js +javax/swing/DefaultBoundedRangeModel.js +javax/swing/DefaultButtonModel.js +javax/swing/DefaultComboBoxModel.js +javax/swing/DefaultSingleSelectionModel.js +javax/swing/DropMode.js +javax/swing/event/AncestorEvent.js +javax/swing/event/AncestorListener.js +javax/swing/event/CaretEvent.js +javax/swing/event/CaretListener.js +javax/swing/event/ChangeEvent.js +javax/swing/event/ChangeListener.js +javax/swing/event/DocumentEvent.js +javax/swing/event/DocumentListener.js +javax/swing/event/EventListenerList.js +javax/swing/event/ListDataEvent.js +javax/swing/event/ListDataListener.js +javax/swing/event/UndoableEditEvent.js +javax/swing/event/UndoableEditListener.js +javax/swing/FocusManager.js +javax/swing/InternalFrameFocusTraversalPolicy.js +javax/swing/LayoutComparator.js +javax/swing/LayoutFocusTraversalPolicy.js +javax/swing/SortingFocusTraversalPolicy.js +javax/swing/SwingContainerOrderFocusTraversalPolicy.js +javax/swing/SwingDefaultFocusTraversalPolicy.js +javax/swing/Icon.js +javax/swing/ImageIcon.js +javax/swing/InputMap.js +javax/swing/JApplet.js +javax/swing/JButton.js +javax/swing/JCheckBox.js +javax/swing/JCheckBoxMenuItem.js +javax/swing/JComboBox.js +javax/swing/JComponent.js +javax/swing/JFrame.js +javax/swing/JLabel.js +javax/swing/JLayeredPane.js +javax/swing/JMenu.js +javax/swing/JMenuBar.js +javax/swing/JMenuItem.js +javax/swing/JPanel.js +javax/swing/JPopupMenu.js +javax/swing/JRadioButtonMenuItem.js +javax/swing/JRootPane.js +javax/swing/JScrollBar.js +javax/swing/JScrollPane.js +javax/swing/JSeparator.js +javax/swing/JTextArea.js +javax/swing/JTextField.js +javax/swing/JToggleButton.js +javax/swing/JViewport.js +javax/swing/KeyboardManager.js +javax/swing/KeyStroke.js +javax/swing/ListModel.js +javax/swing/LookAndFeel.js +javax/swing/MenuElement.js +javax/swing/MutableComboBoxModel.js +javax/swing/plaf/ActionMapUIResource.js +javax/swing/plaf/basic/BasicBorders.js +javax/swing/plaf/BorderUIResource.js +javax/swing/plaf/ColorUIResource.js +javax/swing/plaf/ComponentUI.js +javax/swing/plaf/DimensionUIResource.js +javax/swing/plaf/FontUIResource.js +javax/swing/plaf/InputMapUIResource.js +javax/swing/plaf/InsetsUIResource.js +javax/swing/plaf/UIResource.js +javax/swing/RepaintManager.js +javax/swing/RootPaneContainer.js +javax/swing/Scrollable.js +javax/swing/ScrollPaneConstants.js +javax/swing/ScrollPaneLayout.js +javax/swing/SingleSelectionModel.js +javax/swing/SizeRequirements.js +javax/swing/SwingConstants.js +javax/swing/SwingPaintEventDispatcher.js +javax/swing/SwingUtilities.js +javax/swing/text/AbstractDocument.js +javax/swing/text/AttributeSet.js +javax/swing/text/Caret.js +javax/swing/text/DefaultCaret.js +javax/swing/text/DefaultEditorKit.js +javax/swing/text/Document.js +javax/swing/text/EditorKit.js +javax/swing/text/Element.js +javax/swing/text/GapContent.js +javax/swing/text/GapVector.js +javax/swing/text/JTextComponent.js +javax/swing/text/MutableAttributeSet.js +javax/swing/text/PlainDocument.js +javax/swing/text/PlainView.js +javax/swing/text/Position.js +javax/swing/text/Segment.js +javax/swing/text/SegmentCache.js +javax/swing/text/SimpleAttributeSet.js +javax/swing/text/Style.js +javax/swing/text/StyleConstants.js +javax/swing/text/StyleContext.js +javax/swing/text/TabExpander.js +javax/swing/text/TextAction.js +javax/swing/text/Utilities.js +javax/swing/text/View.js +javax/swing/tree/TreeNode.js +javax/swing/UIDefaults.js +javax/swing/UIManager.js +javax/swing/undo/AbstractUndoableEdit.js +javax/swing/undo/CompoundEdit.js +javax/swing/undo/UndoableEdit.js +javax/swing/ViewportLayout.js +javax/swing/WindowConstants.js +sun/awt/AppContext.js +sun/awt/AWTAutoShutdown.js +sun/awt/CausedFocusEvent.js +sun/awt/ComponentFactory.js +sun/awt/KeyboardFocusManagerPeerProvider.js +sun/awt/MostRecentKeyValue.js +sun/awt/MostRecentThreadAppContext.js +sun/awt/PaintEventDispatcher.js +sun/awt/PostEventQueue.js +sun/awt/RequestFocusController.js +sun/awt/SunToolkit.js +sun/awt/WindowClosingListener.js +sun/awt/WindowClosingSupport.js +sun/awt/image/DataStealer.js +sun/awt/image/IntegerComponentRaster.js +sun/awt/image/IntegerInterleavedRaster.js +sun/awt/image/SunWritableRaster.js +sun/font/FontDesignMetrics.js +sun/swing/DefaultLookup.js +sun/swing/SwingLazyValue.js +sun/text/resources/FormatData.js +sun/text/resources/FormatData_en.js +sun/util/resources/LocaleData.js +swingjs/a2s/A2SContainer.js +swingjs/a2s/A2SEvent.js +swingjs/a2s/A2SListener.js +swingjs/a2s/Applet.js +swingjs/a2s/Button.js +swingjs/a2s/Label.js +swingjs/a2s/Panel.js +swingjs/a2s/Scrollbar.js +swingjs/a2s/ScrollPane.js +swingjs/a2s/TextArea.js +swingjs/a2s/TextField.js +swingjs/api/Interface.js +swingjs/api/js/DOMNode.js +swingjs/api/js/HTML5CanvasContext2D.js +swingjs/api/js/JSInterface.js +swingjs/jquery/JQueryUI.js +swingjs/JSApp.js +swingjs/JSAppletThread.js +swingjs/JSAppletViewer.js +swingjs/JSFocusPeer.js +swingjs/JSFontMetrics.js +swingjs/JSFrameViewer.js +swingjs/JSGraphics2D.js +swingjs/JSGraphicsConfiguration.js +swingjs/JSGraphicsEnvironment.js +swingjs/JSImage.js +swingjs/JSImagekit.js +swingjs/JSMouse.js +swingjs/JSNullComponentPeer.js +swingjs/JSScreenDevice.js +swingjs/JSThreadGroup.js +swingjs/JSToolkit.js +swingjs/JSUtil.js +swingjs/plaf/ButtonListener.js +swingjs/plaf/DefaultMenuLayout.js +swingjs/plaf/HTML5LookAndFeel.js +swingjs/plaf/JSAppletUI.js +swingjs/plaf/JSButtonUI.js +swingjs/plaf/JSCheckBoxMenuItemUI.js +swingjs/plaf/JSCheckBoxUI.js +swingjs/plaf/JSComboBoxUI.js +swingjs/plaf/JSComponentUI.js +swingjs/plaf/JSEventHandler.js +swingjs/plaf/JSFrameUI.js +swingjs/plaf/JSGraphicsUtils.js +swingjs/plaf/JSLabelUI.js +swingjs/plaf/JSLayeredPaneUI.js +swingjs/plaf/JSLightweightUI.js +swingjs/plaf/JSMenuBarUI.js +swingjs/plaf/JSMenuItemUI.js +swingjs/plaf/JSMenuUI.js +swingjs/plaf/JSPanelUI.js +swingjs/plaf/JSPopupMenuSeparatorUI.js +swingjs/plaf/JSPopupMenuUI.js +swingjs/plaf/JSRadioButtonMenuItemUI.js +swingjs/plaf/JSRadioButtonUI.js +swingjs/plaf/JSRootPaneUI.js +swingjs/plaf/JSScrollBarUI.js +swingjs/plaf/JSScrollPaneUI.js +swingjs/plaf/JSSeparatorUI.js +swingjs/plaf/JSSliderUI.js +swingjs/plaf/JSTextAreaUI.js +swingjs/plaf/JSTextFieldUI.js +swingjs/plaf/JSTextUI.js +swingjs/plaf/JSTextViewUI.js +swingjs/plaf/JSViewportUI.js +swingjs/plaf/JSWindowUI.js +swingjs/plaf/LazyActionMap.js +swingjs/plaf/Resizer.js +swingjs/plaf/TextListener.js + + diff --git a/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.8/net.sf.j2s.core.jar b/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.8/net.sf.j2s.core.jar new file mode 100644 index 000000000..ab46e55cd Binary files /dev/null and b/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.8/net.sf.j2s.core.jar differ diff --git a/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.8/timestamp b/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.8/timestamp new file mode 100644 index 000000000..52640d02a --- /dev/null +++ b/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.8/timestamp @@ -0,0 +1 @@ +20200206154055 diff --git a/sources/net.sf.j2s.core/src/net/sf/j2s/core/CorePlugin.java b/sources/net.sf.j2s.core/src/net/sf/j2s/core/CorePlugin.java index 6f2bff89b..e016db2e9 100644 --- a/sources/net.sf.j2s.core/src/net/sf/j2s/core/CorePlugin.java +++ b/sources/net.sf.j2s.core/src/net/sf/j2s/core/CorePlugin.java @@ -25,7 +25,11 @@ public class CorePlugin extends Plugin { * "net.sf.j2s.core.jar" not "net.sf.j2s.core.3.2.5" * */ - public static String VERSION = "3.2.7-v5"; + public static String VERSION = "3.2.8-v1"; + + // if you change the x.x.x number, be sure to also indicate that in + // j2sApplet.js and also (Bob only) update.bat, update-clean.bat + // BH 2020.02.05 -- 3.2.8-v1 reworking of functional interfaces; no longer unqualified // BH 2020.01.31 -- 3.2.7-v5 'L' used instead of 'J' in $fields$ // BH 2020.01.31 -- 3.2.7-v5 java.lang.reflect.* should not be truncated to reflect.* in parameters // BH 2020.01.16 -- 3.2.7-v4 replaces extends java.awt.Component and javax.swing.JComponent diff --git a/sources/net.sf.j2s.core/src/net/sf/j2s/core/Java2ScriptVisitor.java b/sources/net.sf.j2s.core/src/net/sf/j2s/core/Java2ScriptVisitor.java index 4dd395574..6f0f40398 100644 --- a/sources/net.sf.j2s.core/src/net/sf/j2s/core/Java2ScriptVisitor.java +++ b/sources/net.sf.j2s.core/src/net/sf/j2s/core/Java2ScriptVisitor.java @@ -135,6 +135,7 @@ // TODO: superclass inheritance for JAXB XmlAccessorType +//BH 2020.02.05 -- 3.2.8-v1 reworking of functional interfaces; no longer unqualified //BH 2020.01.31 -- 3.2.7-v5 'L' used instead of 'J' in $fields$ //BH 2020.01.31 -- 3.2.7-v5 java.lang.reflect.* should not be truncated to reflect.* //BH 2020.01.16 -- 3.2.7-v4 replaces extends java.awt.Component and javax.swing.JComponent @@ -281,6 +282,7 @@ public class Java2ScriptVisitor extends ASTVisitor { private final static int METHOD_NOTSPECIAL = 0; private final static int METHOD_LITERAL = 1; + private final static int METHOD_LAMBDA_M = 2; private final static int METHOD_LAMBDA_C = 3; private final static int METHOD_CONSTRUCTOR = 4; @@ -429,12 +431,12 @@ static void startCleanBuild() { */ private boolean temp_processingArrayIndex; - /** - * functionalInterface methods add the name$ qualifier even if they are - * parameterized - * - */ - private boolean temp_add$UnqualifiedMethod; +// /** +// * functionalInterface methods add the name$ qualifier even if they are +// * parameterized +// * +// */ +// private boolean temp_add$UnqualifiedMethod; // the three key elements of any class @@ -1297,8 +1299,10 @@ private void processMethodDeclaration(MethodDeclaration mnode, IMethodBinding mB boolean isStatic = isStatic(mBinding); boolean isAbstract = (body == null && !isNative && lambdaType == NOT_LAMBDA); boolean addGeneric = (!isPrivate && !isConstructor && isSynthesizable(mBinding)); - int qualification = (lambdaType != NOT_LAMBDA ? METHOD_FULLY_QUALIFIED - : temp_add$UnqualifiedMethod ? METHOD_$_QUALIFIED : METHOD_FULLY_QUALIFIED); + int qualification = ( + //lambdaType != NOT_LAMBDA ? METHOD_FULLY_QUALIFIED + //: temp_add$UnqualifiedMethod ? METHOD_$_QUALIFIED : + METHOD_FULLY_QUALIFIED); if (isUserApplet && lambdaType == NOT_LAMBDA && !isConstructor && !isStatic && isPublic) qualification |= METHOD_UNQUALIFIED; if (addGeneric) { @@ -1311,7 +1315,7 @@ private void processMethodDeclaration(MethodDeclaration mnode, IMethodBinding mB // allows us to catalog method names for an interface or abstract class return; } - String quotedFinalNameOrArray = getMethodNameWithSyntheticBridgeForDeclaration(mBinding, isConstructor, alias, qualification); + String quotedFinalNameOrArray = getMethodNameWithSyntheticBridgeForDeclaration(mBinding, isConstructor, alias, qualification, lambdaType); boolean isMain = (isStatic && isPublic && mBinding.getName().equals("main") && mBinding.getKey().indexOf(";.main([Ljava/lang/String;)V") >= 0); if (isMain) { @@ -1414,6 +1418,7 @@ public boolean visit(MethodInvocation node) { * @param arguments * @param mBinding * @param expression + * @param lambdaArity */ private boolean addMethodInvocation(SimpleName javaQualifier, List arguments, IMethodBinding mBinding, Expression expression, int lambdaArity) { @@ -1503,6 +1508,7 @@ private boolean addMethodInvocation(SimpleName javaQualifier, List arguments, (expression == null ? METHOD_NULLEXPRESSION : 0) | METHOD_ISQUALIFIED | (lambdaArity >= 0 ? LAMBDA_METHOD : 0) | (isStatic ? FINAL_STATIC : 0)); + //bufferDebug(">>ami " + j2sName + " lambdaArity=" + lambdaArity + " class_localType=" + this.class_localType); String finalMethodNameWith$Params = getFinalMethodNameWith$Params(j2sName, mBinding, null, true, METHOD_NOTSPECIAL); @@ -2072,7 +2078,8 @@ private boolean addClassOrInterface(ASTNode node, ITypeBinding binding, List boolean hasDependents = isEnum; buffer.append(", "); - List unqualifiedMethods = getUnqualifiedMethods(binding, null); +// List unqualifiedMethods = null;//(isLambda ? binding.getFunctionalInterfaceMethod() : null); +// getUnqualifiedMethods(binding, null) : null); List innerClasses = new ArrayList<>(); String innerTypes = ""; if (isAnonymous) { @@ -2409,25 +2416,25 @@ && checkAnnotations(element, CHECK_J2S_IGNORE_AND_ANNOTATIONS)) { // log("default method " + method.getKey()); defpt = buffer.length(); } - boolean addUnqualifiedCurrent = temp_add$UnqualifiedMethod; - if (unqualifiedMethods != null) { - // check for all methods that override a functional interface abstract method, - // as those methods are to be qualified only with $ - - for (int i = unqualifiedMethods.size(); --i >= 0;) { - if (method.overrides(unqualifiedMethods.get(i))) { - temp_add$UnqualifiedMethod = true; - break; - } - } - } +// boolean addUnqualifiedCurrent = temp_add$UnqualifiedMethod; +// if (unqualifiedMethods != null) { +// // check for all methods that override a functional interface abstract method, +// // as those methods are to be qualified only with $ +// +// for (int i = unqualifiedMethods.size(); --i >= 0;) { +// if (method.overrides(unqualifiedMethods.get(i))) { +// temp_add$UnqualifiedMethod = true; +// break; +// } +// } +// } processMethodDeclaration(mnode, method, mnode.parameters(), mnode.getBody(), mnode.isConstructor(), abstractMethodList, NOT_LAMBDA); if (defpt >= 0) { defaults.append(buffer.substring(defpt)); buffer.setLength(defpt); } - temp_add$UnqualifiedMethod = addUnqualifiedCurrent; + // temp_add$UnqualifiedMethod = addUnqualifiedCurrent; } else if (element instanceof AnnotationTypeMemberDeclaration) { processAnnotationTypeMemberDeclaration((AnnotationTypeMemberDeclaration) element); } @@ -2574,34 +2581,34 @@ private void processAnnotationTypeMemberDeclaration(AnnotationTypeMemberDeclarat buffer.setLength(pt); } - /** - * Collect all names of all functional interface abstract methods that this - * class might refer to so that their unqualified. This is not perfect, as it is - * possible to have implementations of specific subtypes of parameterized - * methods. However, it will have to do for now. - * - * @param type - * @param unqualifiedMethods - * @return List of methods that should have raw unparameterized alias - */ - private List getUnqualifiedMethods(ITypeBinding type, List unqualifiedMethods) { - if (type.isArray() || type.isPrimitive()) { - return unqualifiedMethods; - } - ITypeBinding superClass = type.getSuperclass(); - if (superClass != null) - unqualifiedMethods = getUnqualifiedMethods(superClass, unqualifiedMethods); - ITypeBinding[] superInterfaces = type.getInterfaces(); - for (int i = 0; i < superInterfaces.length; i++) - unqualifiedMethods = getUnqualifiedMethods(superInterfaces[i], unqualifiedMethods); - IMethodBinding functionalMethod = type.getFunctionalInterfaceMethod(); - if (functionalMethod != null) { - if (unqualifiedMethods == null) - unqualifiedMethods = new ArrayList(); - unqualifiedMethods.add(functionalMethod); - } - return unqualifiedMethods; - } +// /** +// * Collect all names of all functional interface abstract methods that this +// * class might refer to so that their unqualified. This is not perfect, as it is +// * possible to have implementations of specific subtypes of parameterized +// * methods. However, it will have to do for now. +// * +// * @param type +// * @param unqualifiedMethods +// * @return List of methods that should have raw unparameterized alias +// */ +// private List getUnqualifiedMethods(ITypeBinding type, List unqualifiedMethods) { +// if (type.isArray() || type.isPrimitive()) { +// return unqualifiedMethods; +// } +// ITypeBinding superClass = type.getSuperclass(); +// if (superClass != null) +// unqualifiedMethods = getUnqualifiedMethods(superClass, unqualifiedMethods); +// ITypeBinding[] superInterfaces = type.getInterfaces(); +// for (int i = 0; i < superInterfaces.length; i++) +// unqualifiedMethods = getUnqualifiedMethods(superInterfaces[i], unqualifiedMethods); +// IMethodBinding functionalMethod = type.getFunctionalInterfaceMethod(); +// if (functionalMethod != null) { +// if (unqualifiedMethods == null) +// unqualifiedMethods = new ArrayList(); +// unqualifiedMethods.add(functionalMethod); +// } +// return unqualifiedMethods; +// } /** * If there is no Foo() or Foo(xxx... array), then we need to provide our own @@ -3775,6 +3782,7 @@ private String getFinalDotQualifiedNameForMethod(SimpleName node, IMethodBinding ITypeBinding declaringClass = mBinding.getMethodDeclaration().getDeclaringClass(); String name = mBinding.getName(); if (node == null) { + // not possible? // lambda::method needs to be qualified here only if it is a functional // interface method // otherwise it will be qualified in getQualifiedSimpleNameForinvocation @@ -5307,16 +5315,22 @@ private static ASTNode getAbstractOrAnonymousParentForNode(ASTNode node) { * @param alias name provided using at_j2sAlias * @param mode * @param abstractMethodList + * @param lambdaType * @return j2s-qualified name or an array of j2s-qualified names */ String getMethodNameWithSyntheticBridgeForDeclaration(IMethodBinding mBinding, boolean isConstructor, - String alias, int mode) { + String alias, int mode, int lambdaType) { List names = new ArrayList(); String nodeName = mBinding.getName(); String methodName = (isConstructor ? "c$" : nodeName); ITypeBinding methodClass = mBinding.getDeclaringClass(); + int mtype = (lambdaType == LAMBDA_METHOD || lambdaType == LAMBDA_EXPRESSION ? METHOD_LAMBDA_M : METHOD_NOTSPECIAL); String qname = getFinalMethodNameWith$Params(methodName, mBinding, null, false, METHOD_NOTSPECIAL); names.add(qname); + if (mtype != METHOD_NOTSPECIAL && !qname.endsWith("$")) { + // $O$O$O for lambda as well + names.add(getFinalMethodNameWith$Params(methodName, mBinding, null, false, mtype)); + } if (alias != null) names.add(alias); if((mode & METHOD_ADD_GENERIC) != 0) { @@ -5481,6 +5495,14 @@ private static boolean classHasNoParameterMethod(ITypeBinding methodClass, Strin // return className.length() > 5 && "java.javax".contains(className.substring(0, 5)); // } + /** + * Construct the method parameter string $B$I$O... + * @param nParams + * @param genericTypes + * @param paramTypes + * @param toObject + * @return + */ private String getParamsAsString(int nParams, String[] genericTypes, ITypeBinding[] paramTypes, boolean toObject) { StringBuffer sbParams = new StringBuffer(); // if this is a method invocation and has generics, then we alias that @@ -6296,13 +6318,25 @@ static boolean isJ2SInheritedFieldName(ITypeBinding binding, String name) { // functional interface methods are qualified only by "$", not their parameters. // This is not ideal. - IMethodBinding fm = ( - specialType != METHOD_NOTSPECIAL || javaClassName.equals("java.lang.reflect.Proxy") ? null - : declaringClass.getFunctionalInterfaceMethod()); - if (fm != null && methodName.equals(fm.getName())) - return ensureMethod$Name(j2sName, mBinding, null); + // temporarily disabled + + if (specialType == METHOD_LAMBDA_M) { + for (int i = 0; i < nParams; i++) + j2sName += "$O"; + return j2sName; + } + + IMethodBinding fm = null; +// (specialType != METHOD_NOTSPECIAL +// || javaClassName.equals("java.lang.reflect.Proxy") ? null +// : declaringClass.getFunctionalInterfaceMethod()); + if (fm != null && methodName.equals(fm.getName())) { + String s = ensureMethod$Name(j2sName, mBinding, null); + //bufferDebug(">>s=" + s + " localtype=" + class_localType + " name=" + javaClassName + " declclass=" + declaringClass.getName()); + return s; + } - String s = getParamsAsString(nParams, genericTypes, paramTypes, false); + return j2sName + getParamsAsString(nParams, genericTypes, paramTypes, false); // if (specialType != METHOD_ALIAS && addCallingOption$O && s.indexOf("$T") >= 0 && isJava(javaClassName) && !isJava(class_fullName)) { // @@ -6323,8 +6357,7 @@ static boolean isJ2SInheritedFieldName(ITypeBinding binding, String name) { // // thus, this determination must be made very early. // // } - - return j2sName + s; +// return j2sName + s; } public static class NameMapper { @@ -6739,7 +6772,7 @@ public static void addClassAnnotations(Java2ScriptVisitor visitor, int accessTyp continue; varName = "M:" + mBinding.getName(); methodSignature = visitor.getMethodNameWithSyntheticBridgeForDeclaration(mBinding, - mBinding.isConstructor(), null, METHOD_FULLY_QUALIFIED); + mBinding.isConstructor(), null, METHOD_FULLY_QUALIFIED, NOT_LAMBDA); type = mBinding.getReturnType(); } else if (a.node instanceof AnnotationTypeMemberDeclaration) { MethodDeclaration method = (MethodDeclaration) a.node; diff --git a/sources/net.sf.j2s.java.core/dist/SwingJS-site.zip b/sources/net.sf.j2s.java.core/dist/SwingJS-site.zip index 763362e7b..0ce709b90 100644 Binary files a/sources/net.sf.j2s.java.core/dist/SwingJS-site.zip and b/sources/net.sf.j2s.java.core/dist/SwingJS-site.zip differ diff --git a/sources/net.sf.j2s.java.core/src/java/awt/image/BufferedImage.java b/sources/net.sf.j2s.java.core/src/java/awt/image/BufferedImage.java index 90a20bd81..a41024216 100644 --- a/sources/net.sf.j2s.java.core/src/java/awt/image/BufferedImage.java +++ b/sources/net.sf.j2s.java.core/src/java/awt/image/BufferedImage.java @@ -40,8 +40,14 @@ import java.util.Hashtable; import java.util.Vector; +import sun.awt.image.ByteComponentRaster; +import sun.awt.image.BytePackedRaster; +import sun.awt.image.IntegerComponentRaster; import sun.awt.image.OffScreenImageSource; +import sun.awt.image.ShortComponentRaster; +import sun.awt.image.SunWritableRaster; import swingjs.JSGraphics2D; +import swingjs.JSUtil; import swingjs.api.js.DOMNode; import swingjs.api.js.HTML5Canvas; @@ -70,23 +76,24 @@ public class BufferedImage extends Image implements RenderedImage, Transparency // , WritableRenderedImage { int imageType = TYPE_CUSTOM; - ColorModel colorModel; + ColorModel colorModel; protected WritableRaster raster; OffScreenImageSource osis; @SuppressWarnings("rawtypes") Hashtable properties; boolean isAlphaPremultiplied;// If true, alpha has been premultiplied in - // color channels + // color channels in standard r g b a format protected int[] 秘pix; - protected Object 秘imgNode; // used by JSGraphics2D directly + public Object 秘imgNode; // used by JSGraphics2D directly protected int width, height; private boolean 秘havePix; - protected Object 秘canvas; // created in setRGB + public Object 秘canvas; // created in setRGB public Component 秘component; // for context from component.createImage() private int[] 秘pixSaved; - JSGraphics2D 秘g; // a JSGraphics2D instance - //private static int rangeIndex; + JSGraphics2D 秘g; // a JSGraphics2D instance + // private static int rangeIndex; + private boolean 秘userRaster; /** * Image Type Constants @@ -101,9 +108,9 @@ public class BufferedImage extends Image implements RenderedImage, Transparency /** * Represents an image with 8-bit RGB color components packed into integer * pixels. The image has a {@link DirectColorModel} without alpha. When data - * with non-opaque alpha is stored in an image of this type, the color data - * must be adjusted to a non-premultiplied form and the alpha discarded, as - * described in the {@link java.awt.AlphaComposite} documentation. + * with non-opaque alpha is stored in an image of this type, the color data must + * be adjusted to a non-premultiplied form and the alpha discarded, as described + * in the {@link java.awt.AlphaComposite} documentation. */ public static final int TYPE_INT_RGB = 1; @@ -112,196 +119,165 @@ public class BufferedImage extends Image implements RenderedImage, Transparency * pixels. The image has a DirectColorModel with alpha. The color * data in this image is considered not to be premultiplied with alpha. When * this type is used as the imageType argument to a - * BufferedImage constructor, the created image is consistent - * with images created in the JDK1.1 and earlier releases. + * BufferedImage constructor, the created image is consistent with + * images created in the JDK1.1 and earlier releases. */ public static final int TYPE_INT_ARGB = 2; - /** - * Represents an image with 8-bit RGBA color components packed into - * integer pixels. The image has a DirectColorModel - * with alpha. The color data in this image is considered to be - * premultiplied with alpha. + /** + * Represents an image with 8-bit RGBA color components packed into integer + * pixels. The image has a DirectColorModel with alpha. The color + * data in this image is considered to be premultiplied with alpha. */ - public static final int TYPE_INT_ARGB_PRE = 3; + public static final int TYPE_INT_ARGB_PRE = 3; // - /** - * Represents an image with 8-bit RGB color components, corresponding - * to a Windows- or Solaris- style BGR color model, with the colors - * Blue, Green, and Red packed into integer pixels. There is no alpha. - * The image has a {@link DirectColorModel}. - * When data with non-opaque alpha is stored - * in an image of this type, - * the color data must be adjusted to a non-premultiplied form - * and the alpha discarded, - * as described in the + /** + * Represents an image with 8-bit RGB color components, corresponding to a + * Windows- or Solaris- style BGR color model, with the colors Blue, Green, and + * Red packed into integer pixels. There is no alpha. The image has a + * {@link DirectColorModel}. When data with non-opaque alpha is stored in an + * image of this type, the color data must be adjusted to a non-premultiplied + * form and the alpha discarded, as described in the * {@link java.awt.AlphaComposite} documentation. */ - public static final int TYPE_INT_BGR = 4; - - /** - * Represents an image with 8-bit RGB color components, corresponding - * to a Windows-style BGR color model) with the colors Blue, Green, - * and Red stored in 3 bytes. There is no alpha. The image has a - * ComponentColorModel. - * When data with non-opaque alpha is stored - * in an image of this type, - * the color data must be adjusted to a non-premultiplied form - * and the alpha discarded, - * as described in the - * {@link java.awt.AlphaComposite} documentation. + public static final int TYPE_INT_BGR = 4; + + /** + * Represents an image with 8-bit RGB color components, corresponding to a + * Windows-style BGR color model) with the colors Blue, Green, and Red stored in + * 3 bytes. There is no alpha. The image has a ComponentColorModel. + * When data with non-opaque alpha is stored in an image of this type, the color + * data must be adjusted to a non-premultiplied form and the alpha discarded, as + * described in the {@link java.awt.AlphaComposite} documentation. */ - public static final int TYPE_3BYTE_BGR = 5; - - /** - * Represents an image with 8-bit RGBA color components with the colors - * Blue, Green, and Red stored in 3 bytes and 1 byte of alpha. The - * image has a ComponentColorModel with alpha. The - * color data in this image is considered not to be premultiplied with - * alpha. The byte data is interleaved in a single - * byte array in the order A, B, G, R - * from lower to higher byte addresses within each pixel. - */ - public static final int TYPE_4BYTE_ABGR = 6; - - /** - * Represents an image with 8-bit RGBA color components with the colors - * Blue, Green, and Red stored in 3 bytes and 1 byte of alpha. The - * image has a ComponentColorModel with alpha. The color - * data in this image is considered to be premultiplied with alpha. - * The byte data is interleaved in a single byte array in the order - * A, B, G, R from lower to higher byte addresses within each pixel. - */ - public static final int TYPE_4BYTE_ABGR_PRE = 7; - - /** - * Represents an image with 5-6-5 RGB color components (5-bits red, - * 6-bits green, 5-bits blue) with no alpha. This image has - * a DirectColorModel. - * When data with non-opaque alpha is stored - * in an image of this type, - * the color data must be adjusted to a non-premultiplied form - * and the alpha discarded, - * as described in the - * {@link java.awt.AlphaComposite} documentation. + public static final int TYPE_3BYTE_BGR = 5; + + /** + * Represents an image with 8-bit RGBA color components with the colors Blue, + * Green, and Red stored in 3 bytes and 1 byte of alpha. The image has a + * ComponentColorModel with alpha. The color data in this image is + * considered not to be premultiplied with alpha. The byte data is interleaved + * in a single byte array in the order A, B, G, R from lower to higher byte + * addresses within each pixel. */ - public static final int TYPE_USHORT_565_RGB = 8; - - /** - * Represents an image with 5-5-5 RGB color components (5-bits red, - * 5-bits green, 5-bits blue) with no alpha. This image has - * a DirectColorModel. - * When data with non-opaque alpha is stored - * in an image of this type, - * the color data must be adjusted to a non-premultiplied form - * and the alpha discarded, - * as described in the - * {@link java.awt.AlphaComposite} documentation. + public static final int TYPE_4BYTE_ABGR = 6; + + /** + * Represents an image with 8-bit RGBA color components with the colors Blue, + * Green, and Red stored in 3 bytes and 1 byte of alpha. The image has a + * ComponentColorModel with alpha. The color data in this image is + * considered to be premultiplied with alpha. The byte data is interleaved in a + * single byte array in the order A, B, G, R from lower to higher byte addresses + * within each pixel. */ - public static final int TYPE_USHORT_555_RGB = 9; - - /** - * Represents a unsigned byte grayscale image, non-indexed. This - * image has a ComponentColorModel with a CS_GRAY - * {@link ColorSpace}. - * When data with non-opaque alpha is stored - * in an image of this type, - * the color data must be adjusted to a non-premultiplied form - * and the alpha discarded, - * as described in the + public static final int TYPE_4BYTE_ABGR_PRE = 7; + + /** + * Represents an image with 5-6-5 RGB color components (5-bits red, 6-bits + * green, 5-bits blue) with no alpha. This image has a + * DirectColorModel. When data with non-opaque alpha is stored in + * an image of this type, the color data must be adjusted to a non-premultiplied + * form and the alpha discarded, as described in the * {@link java.awt.AlphaComposite} documentation. */ - public static final int TYPE_BYTE_GRAY = 10; - - /** - * Represents an unsigned short grayscale image, non-indexed). This - * image has a ComponentColorModel with a CS_GRAY - * ColorSpace. - * When data with non-opaque alpha is stored - * in an image of this type, - * the color data must be adjusted to a non-premultiplied form - * and the alpha discarded, - * as described in the + public static final int TYPE_USHORT_565_RGB = 8; + + /** + * Represents an image with 5-5-5 RGB color components (5-bits red, 5-bits + * green, 5-bits blue) with no alpha. This image has a + * DirectColorModel. When data with non-opaque alpha is stored in + * an image of this type, the color data must be adjusted to a non-premultiplied + * form and the alpha discarded, as described in the * {@link java.awt.AlphaComposite} documentation. */ - public static final int TYPE_USHORT_GRAY = 11; - - /** - * Represents an opaque byte-packed 1, 2, or 4 bit image. The - * image has an {@link IndexColorModel} without alpha. When this - * type is used as the imageType argument to the - * BufferedImage constructor that takes an - * imageType argument but no ColorModel - * argument, a 1-bit image is created with an - * IndexColorModel with two colors in the default - * sRGB ColorSpace: {0, 0, 0} and - * {255, 255, 255}. + public static final int TYPE_USHORT_555_RGB = 9; + + /** + * Represents a unsigned byte grayscale image, non-indexed. This image has a + * ComponentColorModel with a CS_GRAY {@link ColorSpace}. When data + * with non-opaque alpha is stored in an image of this type, the color data must + * be adjusted to a non-premultiplied form and the alpha discarded, as described + * in the {@link java.awt.AlphaComposite} documentation. + */ + public static final int TYPE_BYTE_GRAY = 10; + + /** + * Represents an unsigned short grayscale image, non-indexed). This image has a + * ComponentColorModel with a CS_GRAY ColorSpace. When + * data with non-opaque alpha is stored in an image of this type, the color data + * must be adjusted to a non-premultiplied form and the alpha discarded, as + * described in the {@link java.awt.AlphaComposite} documentation. + */ + public static final int TYPE_USHORT_GRAY = 11; + + /** + * Represents an opaque byte-packed 1, 2, or 4 bit image. The image has an + * {@link IndexColorModel} without alpha. When this type is used as the + * imageType argument to the BufferedImage constructor + * that takes an imageType argument but no ColorModel + * argument, a 1-bit image is created with an IndexColorModel with + * two colors in the default sRGB ColorSpace: {0, 0, 0} + * and {255, 255, 255}. * - *

Images with 2 or 4 bits per pixel may be constructed via - * the BufferedImage constructor that takes a - * ColorModel argument by supplying a - * ColorModel with an appropriate map size. + *

+ * Images with 2 or 4 bits per pixel may be constructed via the + * BufferedImage constructor that takes a ColorModel + * argument by supplying a ColorModel with an appropriate map size. * - *

Images with 8 bits per pixel should use the image types - * TYPE_BYTE_INDEXED or TYPE_BYTE_GRAY - * depending on their ColorModel. - - *

When color data is stored in an image of this type, - * the closest color in the colormap is determined - * by the IndexColorModel and the resulting index is stored. - * Approximation and loss of alpha or color components - * can result, depending on the colors in the - * IndexColorModel colormap. - */ - public static final int TYPE_BYTE_BINARY = 12; - - /** + *

+ * Images with 8 bits per pixel should use the image types + * TYPE_BYTE_INDEXED or TYPE_BYTE_GRAY depending on + * their ColorModel. + * + *

+ * When color data is stored in an image of this type, the closest color in the + * colormap is determined by the IndexColorModel and the resulting + * index is stored. Approximation and loss of alpha or color components can + * result, depending on the colors in the IndexColorModel colormap. + */ + public static final int TYPE_BYTE_BINARY = 12; + + /** * Represents an indexed byte image. When this type is used as the - * imageType argument to the BufferedImage - * constructor that takes an imageType argument - * but no ColorModel argument, an - * IndexColorModel is created with - * a 256-color 6/6/6 color cube palette with the rest of the colors - * from 216-255 populated by grayscale values in the - * default sRGB ColorSpace. + * imageType argument to the BufferedImage constructor + * that takes an imageType argument but no ColorModel + * argument, an IndexColorModel is created with a 256-color 6/6/6 + * color cube palette with the rest of the colors from 216-255 populated by + * grayscale values in the default sRGB ColorSpace. * - *

When color data is stored in an image of this type, - * the closest color in the colormap is determined - * by the IndexColorModel and the resulting index is stored. - * Approximation and loss of alpha or color components - * can result, depending on the colors in the - * IndexColorModel colormap. - */ - public static final int TYPE_BYTE_INDEXED = 13; - - // private static final int DCM_RED_MASK = 0x00ff0000; - // private static final int DCM_GREEN_MASK = 0x0000ff00; - // private static final int DCM_BLUE_MASK = 0x000000ff; - // private static final int DCM_ALPHA_MASK = 0xff000000; - // private static final int DCM_565_RED_MASK = 0xf800; - // private static final int DCM_565_GRN_MASK = 0x07E0; - // private static final int DCM_565_BLU_MASK = 0x001F; - // private static final int DCM_555_RED_MASK = 0x7C00; - // private static final int DCM_555_GRN_MASK = 0x03E0; - // private static final int DCM_555_BLU_MASK = 0x001F; - // private static final int DCM_BGR_RED_MASK = 0x0000ff; - // private static final int DCM_BGR_GRN_MASK = 0x00ff00; - // private static final int DCM_BGR_BLU_MASK = 0xff0000; - - /** - * Constructs a BufferedImage of one of the predefined image - * types. The ColorSpace for the image is the default sRGB space. - * - * @param width - * width of the created image - * @param height - * height of the created image - * @param imageType - * type of the created image + *

+ * When color data is stored in an image of this type, the closest color in the + * colormap is determined by the IndexColorModel and the resulting + * index is stored. Approximation and loss of alpha or color components can + * result, depending on the colors in the IndexColorModel colormap. + */ + public static final int TYPE_BYTE_INDEXED = 13; + + private static final int DCM_RED_MASK = 0x00ff0000; + private static final int DCM_GREEN_MASK = 0x0000ff00; + private static final int DCM_BLUE_MASK = 0x000000ff; + private static final int DCM_ALPHA_MASK = 0xff000000; + private static final int DCM_565_RED_MASK = 0xf800; + private static final int DCM_565_GRN_MASK = 0x07E0; + private static final int DCM_565_BLU_MASK = 0x001F; + private static final int DCM_555_RED_MASK = 0x7C00; + private static final int DCM_555_GRN_MASK = 0x03E0; + private static final int DCM_555_BLU_MASK = 0x001F; + private static final int DCM_BGR_RED_MASK = 0x0000ff; + private static final int DCM_BGR_GRN_MASK = 0x00ff00; + private static final int DCM_BGR_BLU_MASK = 0xff0000; + + /** + * Constructs a BufferedImage of one of the predefined image types. + * The ColorSpace for the image is the default sRGB space. + * + * @param width width of the created image + * @param height height of the created image + * @param imageType type of the created image * @see ColorSpace * @see #TYPE_INT_RGB * @see #TYPE_INT_ARGB - * @see #TYPE_INT_ARGB_PRE + * @see #TYPE_INT_ARGB_PRE // SwingJS not implemented * @see #TYPE_INT_BGR * @see #TYPE_3BYTE_BGR * @see #TYPE_4BYTE_ABGR @@ -317,7 +293,7 @@ public BufferedImage(int width, int height, int imageType) { this.width = width; this.height = height; switch (imageType) { - case TYPE_INT_RGB: { + case TYPE_INT_RGB: colorModel = new DirectColorModel(24, 0x00ff0000, // Red 0x0000ff00, // Green 0x000000ff, // Blue @@ -326,281 +302,198 @@ public BufferedImage(int width, int height, int imageType) { raster = colorModel.createCompatibleWritableRaster(width, height); raster.setImage(this); 秘pix = ((DataBufferInt) raster.getDataBuffer()).data; - } break; - - case TYPE_INT_ARGB_PRE: - case TYPE_INT_ARGB: { + case TYPE_INT_ARGB: colorModel = ColorModel.getRGBdefault(); raster = colorModel.createCompatibleWritableRaster(width, height); raster.setImage(this); 秘pix = ((DataBufferInt) raster.getDataBuffer()).data; + break; + case TYPE_INT_ARGB_PRE: + colorModel = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 32, 0x00ff0000, // Red + 0x0000ff00, // Green + 0x000000ff, // Blue + 0xff000000, // Alpha + true, // Alpha Premultiplied + DataBuffer.TYPE_INT); + + raster = colorModel.createCompatibleWritableRaster(width, height); + break; + case TYPE_INT_BGR: + colorModel = new DirectColorModel(24, 0x000000ff, // Red + 0x0000ff00, // Green + 0x00ff0000 // Blue + ); + raster = colorModel.createCompatibleWritableRaster(width, height); + break; + case TYPE_3BYTE_BGR: { + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + int[] nBits = { 8, 8, 8 }; + int[] bOffs = { 2, 1, 0 }; + colorModel = new ComponentColorModel(cs, nBits, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, width * 3, 3, bOffs, null); + } + break; + + case TYPE_4BYTE_ABGR: { + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + int[] nBits = { 8, 8, 8, 8 }; + int[] bOffs = { 3, 2, 1, 0 }; + colorModel = new ComponentColorModel(cs, nBits, true, false, Transparency.TRANSLUCENT, + DataBuffer.TYPE_BYTE); + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, width * 4, 4, bOffs, null); + } + break; + + case TYPE_4BYTE_ABGR_PRE: { + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + int[] nBits = { 8, 8, 8, 8 }; + int[] bOffs = { 3, 2, 1, 0 }; + colorModel = new ComponentColorModel(cs, nBits, true, true, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE); + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, width * 4, 4, bOffs, null); + } + break; + + case TYPE_BYTE_GRAY: { + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY); + int[] nBits = { 8 }; + colorModel = new ComponentColorModel(cs, nBits, false, true, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); + raster = colorModel.createCompatibleWritableRaster(width, height); + } + break; + + case TYPE_USHORT_GRAY: { + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY); + int[] nBits = { 16 }; + colorModel = new ComponentColorModel(cs, nBits, false, true, Transparency.OPAQUE, DataBuffer.TYPE_USHORT); + raster = colorModel.createCompatibleWritableRaster(width, height); + } + break; + + case TYPE_BYTE_BINARY: // B&W + byte[] arr = { (byte) 0, (byte) 0xff }; + colorModel = new IndexColorModel(1, 2, arr, arr, arr); + raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width, height, 1, 1, null); + break; + case TYPE_BYTE_INDEXED: + // Create a 6x6x6 color cube + int[] cmap = new int[256]; + int i = 0; + for (int r = 0; r < 256; r += 51) { + for (int g = 0; g < 256; g += 51) { + for (int b = 0; b < 256; b += 51) { + cmap[i++] = (r << 16) | (g << 8) | b; + } + } + } + // And populate the rest of the cmap with gray values + int grayIncr = 256 / (256 - i); + + // The gray ramp will be between 18 and 252 + int gray = grayIncr * 3; + for (; i < 256; i++) { + cmap[i] = (gray << 16) | (gray << 8) | gray; + gray += grayIncr; + } + colorModel = new IndexColorModel(8, 256, cmap, 0, false, -1, DataBuffer.TYPE_BYTE); + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, 1, null); + break; + case TYPE_USHORT_565_RGB: { + colorModel = new DirectColorModel(16, DCM_565_RED_MASK, DCM_565_GRN_MASK, DCM_565_BLU_MASK); + raster = colorModel.createCompatibleWritableRaster(width, height); + } + break; + case TYPE_USHORT_555_RGB: { + colorModel = new DirectColorModel(15, DCM_555_RED_MASK, DCM_555_GRN_MASK, DCM_555_BLU_MASK); + raster = colorModel.createCompatibleWritableRaster(width, height); } break; - // case TYPE_INT_ARGB_PRE: - // { - // colorModel = new - // DirectColorModel( - // ColorSpace.getInstance(ColorSpace.CS_sRGB), - // 32, - // 0x00ff0000,// Red - // 0x0000ff00,// Green - // 0x000000ff,// Blue - // 0xff000000,// Alpha - // true, // Alpha Premultiplied - // DataBuffer.TYPE_INT - // ); - // - // raster = colorModel.createCompatibleWritableRaster(width, - // height); - // } - // break; - // - // case TYPE_INT_BGR: - // { - // colorModel = new DirectColorModel(24, - // 0x000000ff, // Red - // 0x0000ff00, // Green - // 0x00ff0000 // Blue - // ); - // raster = colorModel.createCompatibleWritableRaster(width, - // height); - // } - // break; - // - // case TYPE_3BYTE_BGR: - // { - // ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); - // int[] nBits = {8, 8, 8}; - // int[] bOffs = {2, 1, 0}; - // colorModel = new ComponentColorModel(cs, nBits, false, false, - // Transparency.OPAQUE, - // DataBuffer.TYPE_BYTE); - // raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, - // width, height, - // width*3, 3, - // bOffs, null); - // } - // break; - // - // case TYPE_4BYTE_ABGR: - // { - // ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); - // int[] nBits = {8, 8, 8, 8}; - // int[] bOffs = {3, 2, 1, 0}; - // colorModel = new ComponentColorModel(cs, nBits, true, false, - // Transparency.TRANSLUCENT, - // DataBuffer.TYPE_BYTE); - // raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, - // width, height, - // width*4, 4, - // bOffs, null); - // } - // break; - // - // case TYPE_4BYTE_ABGR_PRE: - // { - // ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); - // int[] nBits = {8, 8, 8, 8}; - // int[] bOffs = {3, 2, 1, 0}; - // colorModel = new ComponentColorModel(cs, nBits, true, true, - // Transparency.TRANSLUCENT, - // DataBuffer.TYPE_BYTE); - // raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, - // width, height, - // width*4, 4, - // bOffs, null); - // } - // break; - // - // case TYPE_BYTE_GRAY: - // { - // ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY); - // int[] nBits = {8}; - // colorModel = new ComponentColorModel(cs, nBits, false, true, - // Transparency.OPAQUE, - // DataBuffer.TYPE_BYTE); - // raster = colorModel.createCompatibleWritableRaster(width, - // height); - // } - // break; - // - // case TYPE_USHORT_GRAY: - // { - // ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY); - // int[] nBits = {16}; - // colorModel = new ComponentColorModel(cs, nBits, false, true, - // Transparency.OPAQUE, - // DataBuffer.TYPE_USHORT); - // raster = colorModel.createCompatibleWritableRaster(width, - // height); - // } - // break; - // - // case TYPE_BYTE_BINARY: - // { - // byte[] arr = {(byte)0, (byte)0xff}; - // - // colorModel = new IndexColorModel(1, 2, arr, arr, arr); - // raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, - // width, height, 1, 1, null); - // } - // break; - // - // case TYPE_BYTE_INDEXED: - // { - // // Create a 6x6x6 color cube - // int[] cmap = new int[256]; - // int i=0; - // for (int r=0; r < 256; r += 51) { - // for (int g=0; g < 256; g += 51) { - // for (int b=0; b < 256; b += 51) { - // cmap[i++] = (r<<16)|(g<<8)|b; - // } - // } - // } - // // And populate the rest of the cmap with gray values - // int grayIncr = 256/(256-i); - // - // // The gray ramp will be between 18 and 252 - // int gray = grayIncr*3; - // for (; i < 256; i++) { - // cmap[i] = (gray<<16)|(gray<<8)|gray; - // gray += grayIncr; - // } - // - // colorModel = new IndexColorModel(8, 256, cmap, 0, false, -1, - // DataBuffer.TYPE_BYTE); - // raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, - // width, height, 1, null); - // } - // break; - // - // case TYPE_USHORT_565_RGB: - // { - // colorModel = new DirectColorModel(16, - // DCM_565_RED_MASK, - // DCM_565_GRN_MASK, - // DCM_565_BLU_MASK - // ); - // raster = colorModel.createCompatibleWritableRaster(width, - // height); - // } - // break; - // - // case TYPE_USHORT_555_RGB: - // { - // colorModel = new DirectColorModel(15, - // DCM_555_RED_MASK, - // DCM_555_GRN_MASK, - // DCM_555_BLU_MASK - // ); - // raster = colorModel.createCompatibleWritableRaster(width, - // height); - // } - // break; - // default: throw new IllegalArgumentException("Unknown image type " + imageType); } this.imageType = imageType; } - /** - * Constructs a BufferedImage of one of the predefined - * image types: + /** + * Constructs a BufferedImage of one of the predefined image types: * TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED. * - *

If the image type is TYPE_BYTE_BINARY, the number of - * entries in the color model is used to determine whether the - * image should have 1, 2, or 4 bits per pixel. If the color model - * has 1 or 2 entries, the image will have 1 bit per pixel. If it - * has 3 or 4 entries, the image with have 2 bits per pixel. If - * it has between 5 and 16 entries, the image will have 4 bits per - * pixel. Otherwise, an IllegalArgumentException will be thrown. + *

+ * If the image type is TYPE_BYTE_BINARY, the number of entries in the color + * model is used to determine whether the image should have 1, 2, or 4 bits per + * pixel. If the color model has 1 or 2 entries, the image will have 1 bit per + * pixel. If it has 3 or 4 entries, the image with have 2 bits per pixel. If it + * has between 5 and 16 entries, the image will have 4 bits per pixel. + * Otherwise, an IllegalArgumentException will be thrown. * - * @param width width of the created image - * @param height height of the created image + * @param width width of the created image + * @param height height of the created image * @param imageType type of the created image - * @param cm IndexColorModel of the created image - * @throws IllegalArgumentException if the imageType is not - * TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED or if the imageType is - * TYPE_BYTE_BINARY and the color map has more than 16 entries. + * @param cm IndexColorModel of the created image + * @throws IllegalArgumentException if the imageType is not TYPE_BYTE_BINARY or + * TYPE_BYTE_INDEXED or if the imageType is + * TYPE_BYTE_BINARY and the color map has more + * than 16 entries. * @see #TYPE_BYTE_BINARY * @see #TYPE_BYTE_INDEXED */ - public BufferedImage (int width, - int height, - int imageType, - IndexColorModel cm) { - if (cm.hasAlpha() && cm.isAlphaPremultiplied()) { - throw new IllegalArgumentException("This image types do not have "+ - "premultiplied alpha."); - } - this.width = width; - this.height = height; - switch(imageType) { - case TYPE_BYTE_BINARY: - int bits; // Will be set below - int mapSize = cm.getMapSize(); - if (mapSize <= 2) { - bits = 1; - } else if (mapSize <= 4) { - bits = 2; - } else if (mapSize <= 16) { - bits = 4; - } else { - throw new IllegalArgumentException - ("Color map for TYPE_BYTE_BINARY " + - "must have no more than 16 entries"); - } - raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, - width, height, 1, bits, null); - break; - - case TYPE_BYTE_INDEXED: - raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, - width, height, 1, null); - break; - default: - throw new IllegalArgumentException("Invalid image type (" + - imageType+"). Image type must"+ - " be either TYPE_BYTE_BINARY or "+ - " TYPE_BYTE_INDEXED"); - } - - if (!cm.isCompatibleRaster(raster)) { - throw new - IllegalArgumentException("Incompatible image type and IndexColorModel"); - } - - colorModel = cm; - this.imageType = imageType; - } + public BufferedImage(int width, int height, int imageType, IndexColorModel cm) { + if (cm.hasAlpha() && cm.isAlphaPremultiplied()) { + throw new IllegalArgumentException("This image types do not have " + "premultiplied alpha."); + } + this.width = width; + this.height = height; + switch (imageType) { + case TYPE_BYTE_BINARY: + int bits; // Will be set below + int mapSize = cm.getMapSize(); + if (mapSize <= 2) { + bits = 1; + } else if (mapSize <= 4) { + bits = 2; + } else if (mapSize <= 16) { + bits = 4; + } else { + throw new IllegalArgumentException( + "Color map for TYPE_BYTE_BINARY " + "must have no more than 16 entries"); + } + raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width, height, 1, bits, null); + break; + case TYPE_BYTE_INDEXED: + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, 1, null); + break; + default: + throw new IllegalArgumentException("Invalid image type (" + imageType + "). Image type must" + + " be either TYPE_BYTE_BINARY or " + " TYPE_BYTE_INDEXED"); + } + + if (!cm.isCompatibleRaster(raster)) { + throw new IllegalArgumentException("Incompatible image type and IndexColorModel"); + } + + colorModel = cm; + this.imageType = imageType; + } /** * Constructs a new BufferedImage with a specified * ColorModel and Raster. If the number and types of - * bands in the SampleModel of the Raster do not - * match the number and types required by the ColorModel to - * represent its color and alpha components, a {@link RasterFormatException} - * is thrown. This method can multiply or divide the color Raster - * data by alpha to match the alphaPremultiplied state in the + * bands in the SampleModel of the Raster do not match + * the number and types required by the ColorModel to represent its + * color and alpha components, a {@link RasterFormatException} is thrown. This + * method can multiply or divide the color Raster data by alpha to + * match the alphaPremultiplied state in the * ColorModel. Properties for this BufferedImage can * be established by passing in a {@link Hashtable} of String/ * Object pairs. * - * @param cm - * ColorModel for the new image - * @param raster - * Raster for the image data - * @param isRasterPremultiplied - * if true, the data in the raster has been - * premultiplied with alpha. - * @param properties - * Hashtable of String/Object - * pairs. + * @param cm ColorModel for the new image + * @param raster Raster for the image data + * @param isRasterPremultiplied if true, the data in the raster has + * been premultiplied with alpha. + * @param properties Hashtable of + * String/Object pairs. * @exception RasterFormatException if the number and types of * bands in the SampleModel of the Raster * do not match the number and types required by the @@ -618,190 +511,145 @@ public BufferedImage (int width, * FOR NOW THE CODE WHICH DEFINES THE RASTER TYPE IS DUPLICATED BY DVF SEE THE * METHOD DEFINERASTERTYPE @ RASTEROUTPUTMANAGER */ - public BufferedImage(ColorModel cm, WritableRaster raster, - boolean isRasterPremultiplied, Hashtable properties) { - // - // if (!cm.isCompatibleRaster(raster)) { - // throw new - // IllegalArgumentException("Raster "+raster+ - // " is incompatible with ColorModel "+ - // cm); - // } - // + public BufferedImage(ColorModel cm, WritableRaster raster, boolean isRasterPremultiplied, + Hashtable properties) { + + if (!cm.isCompatibleRaster(raster)) { + throw new IllegalArgumentException("Raster " + raster + " is incompatible with ColorModel " + cm); + } + if ((raster.minX != 0) || (raster.minY != 0)) { - throw new IllegalArgumentException("Raster " + raster - + " has minX or minY not equal to zero: " + raster.minX + " " - + raster.minY); + throw new IllegalArgumentException( + "Raster " + raster + " has minX or minY not equal to zero: " + raster.minX + " " + raster.minY); } colorModel = cm; + this.raster = raster; this.width = raster.getWidth(); this.height = raster.getHeight(); raster.setImage(this); - 秘pix = ((DataBufferInt) raster.getDataBuffer()).data; + if (getColorModel() == ColorModel.秘RGBdefault) + 秘pix = ((DataBufferInt) raster.getDataBuffer()).data; + else + 秘userRaster = true; this.properties = properties; - // int numBands = raster.getNumBands(); - // boolean isAlphaPre = cm.isAlphaPremultiplied(); - //ColorSpace cs; + int numBands = raster.getNumBands(); + boolean isAlphaPre = cm.isAlphaPremultiplied(); + ColorSpace cs; // Force the raster data alpha state to match the premultiplied // state in the color model // coerceData(isRasterPremultiplied); - // SampleModel sm = raster.getSampleModel(); - // cs = cm.getColorSpace(); - // int csType = cs.getType(); - // if (csType != ColorSpace.TYPE_RGB) { - // if (csType == ColorSpace.TYPE_GRAY - // && ComponentColorModel.class.equals(cm.getClass())) { - // // Check if this might be a child raster (fix for bug 4240596) - // if (sm instanceof ComponentSampleModel && - // ((ComponentSampleModel)sm).getPixelStride() != numBands) { - // imageType = TYPE_CUSTOM; - // } else if (raster instanceof ByteComponentRaster && - // PixelInterleavedSampleModel.class.equals(sm.getClass()) && - // raster.getNumBands() == 1 && - // cm.getComponentSize(0) == 8 && - // ((ByteComponentRaster)raster).getPixelStride() == 1) { - // imageType = TYPE_BYTE_GRAY; - // } else if (raster instanceof ShortComponentRaster && - // PixelInterleavedSampleModel.class.equals(sm.getClass()) && - // raster.getNumBands() == 1 && - // cm.getComponentSize(0) == 16 && - // ((ShortComponentRaster)raster).getPixelStride() == 1) { - // imageType = TYPE_USHORT_GRAY; - // } - // } else { - // imageType = TYPE_CUSTOM; - // } - // return; - // } + SampleModel sm = raster.getSampleModel(); + cs = cm.getColorSpace(); + int csType = cs.getType(); + if (csType != ColorSpace.TYPE_RGB) { + if (csType == ColorSpace.TYPE_GRAY && ComponentColorModel.class.equals(cm.getClass())) { + // Check if this might be a child raster (fix for bug 4240596) + if (sm instanceof ComponentSampleModel && ((ComponentSampleModel) sm).getPixelStride() != numBands) { + imageType = TYPE_CUSTOM; + } else if (raster instanceof ByteComponentRaster + && PixelInterleavedSampleModel.class.equals(sm.getClass()) && raster.getNumBands() == 1 + && cm.getComponentSize(0) == 8 && ((ByteComponentRaster) raster).getPixelStride() == 1) { + imageType = TYPE_BYTE_GRAY; + } else if (raster instanceof ShortComponentRaster + && PixelInterleavedSampleModel.class.equals(sm.getClass()) && raster.getNumBands() == 1 + && cm.getComponentSize(0) == 16 && ((ShortComponentRaster) raster).getPixelStride() == 1) { + imageType = TYPE_USHORT_GRAY; + } + } else { + imageType = TYPE_CUSTOM; + } + return; + } - // if ((raster instanceof IntegerComponentRaster) && - // (numBands == 3 || numBands == 4)) { - // IntegerComponentRaster iraster = - // (IntegerComponentRaster) raster; - // // Check if the raster params and the color model - // // are correct - // int pixSize = cm.getPixelSize(); - // if (iraster.getPixelStride() == 1 && - // DirectColorModel.class.equals(cm.getClass()) && - // SinglePixelPackedSampleModel.class.equals(sm.getClass()) && - // (pixSize == 32 || pixSize == 24)) - // { - // // Now check on the DirectColorModel params - // DirectColorModel dcm = (DirectColorModel) cm; - // int rmask = dcm.getRedMask(); - // int gmask = dcm.getGreenMask(); - // int bmask = dcm.getBlueMask(); - // if (rmask == DCM_RED_MASK && gmask == DCM_GREEN_MASK && - // bmask == DCM_BLUE_MASK) - // { - // if (dcm.getAlphaMask() == DCM_ALPHA_MASK) { - // imageType = (isAlphaPre - // ? TYPE_INT_ARGB_PRE - // : TYPE_INT_ARGB); - // } - // else { - // // No Alpha - // if (!dcm.hasAlpha()) { - // imageType = TYPE_INT_RGB; - // } - // } - // } // if (dcm.getRedMask() == DCM_RED_MASK && - // else if (rmask == DCM_BGR_RED_MASK && gmask == DCM_BGR_GRN_MASK - // && bmask == DCM_BGR_BLU_MASK) { - // if (!dcm.hasAlpha()) { - // imageType = TYPE_INT_BGR; - // } - // } // if (rmask == DCM_BGR_RED_MASK && - // } // if (iraster.getPixelStride() == 1 - // } // ((raster instanceof IntegerComponentRaster) && - // else if ((IndexColorModel.class.equals(cm.getClass())) && - // (numBands == 1) && - // (!cm.hasAlpha() || !isAlphaPre)) - // { - // IndexColorModel icm = (IndexColorModel) cm; - // int pixSize = icm.getPixelSize(); - // - // if (raster instanceof BytePackedRaster && - // MultiPixelPackedSampleModel.class.equals(sm.getClass())) - // { - // imageType = TYPE_BYTE_BINARY; - // } // if (raster instanceof BytePackedRaster) - // else if (raster instanceof ByteComponentRaster && - // PixelInterleavedSampleModel.class.equals(sm.getClass())) - // { - // ByteComponentRaster braster = (ByteComponentRaster) raster; - // if (braster.getPixelStride() == 1 && pixSize <= 8) { - // imageType = TYPE_BYTE_INDEXED; - // } - // } - // } // else if (cm instanceof IndexColorModel) && (numBands == 1)) - // else if ((raster instanceof ShortComponentRaster) - // && (DirectColorModel.class.equals(cm.getClass())) - // && (SinglePixelPackedSampleModel.class.equals(sm.getClass())) - // && (numBands == 3) - // && !cm.hasAlpha()) - // { - // DirectColorModel dcm = (DirectColorModel) cm; - // if (dcm.getRedMask() == DCM_565_RED_MASK) { - // if (dcm.getGreenMask() == DCM_565_GRN_MASK && - // dcm.getBlueMask() == DCM_565_BLU_MASK) { - // imageType = TYPE_USHORT_565_RGB; - // } - // } - // else if (dcm.getRedMask() == DCM_555_RED_MASK) { - // if (dcm.getGreenMask() == DCM_555_GRN_MASK && - // dcm.getBlueMask() == DCM_555_BLU_MASK) { - // imageType = TYPE_USHORT_555_RGB; - // } - // } - // } // else if ((cm instanceof IndexColorModel) && (numBands == 1)) - // else if ((raster instanceof ByteComponentRaster) - // && (cm instanceof ComponentColorModel) - // && (raster.getSampleModel() instanceof PixelInterleavedSampleModel) - // && (numBands == 3 || numBands == 4)) - // { - // ComponentColorModel ccm = (ComponentColorModel) cm; - // PixelInterleavedSampleModel csm = - // (PixelInterleavedSampleModel)raster.getSampleModel(); - // ByteComponentRaster braster = (ByteComponentRaster) raster; - // int[] offs = csm.getBandOffsets(); - // if (ccm.getNumComponents() != numBands) { - // throw new RasterFormatException("Number of components in "+ - // "ColorModel ("+ - // ccm.getNumComponents()+ - // ") does not match # in "+ - // " Raster ("+numBands+")"); - // } - // int[] nBits = ccm.getComponentSize(); - // boolean is8bit = true; - // for (int i=0; i < numBands; i++) { - // if (nBits[i] != 8) { - // is8bit = false; - // break; - // } - // } - // if (is8bit && - // braster.getPixelStride() == numBands && - // offs[0] == numBands-1 && - // offs[1] == numBands-2 && - // offs[2] == numBands-3 && - // ComponentColorModel.class.equals(ccm.getClass()) && - // PixelInterleavedSampleModel.class.equals(csm.getClass())) - // { - // if (numBands == 3 && !ccm.hasAlpha()) { - // imageType = TYPE_3BYTE_BGR; - // } - // else if (offs[3] == 0 && ccm.hasAlpha()) { - // imageType = (isAlphaPre - // ? TYPE_4BYTE_ABGR_PRE - // : TYPE_4BYTE_ABGR); - // } - // } - // } // else if ((raster instanceof ByteComponentRaster) && + if ((raster instanceof IntegerComponentRaster) && (numBands == 3 || numBands == 4)) { + IntegerComponentRaster iraster = (IntegerComponentRaster) raster; + // Check if the raster params and the color model + // are correct + int pixSize = cm.getPixelSize(); + if (iraster.getPixelStride() == 1 && DirectColorModel.class.equals(cm.getClass()) + && SinglePixelPackedSampleModel.class.equals(sm.getClass()) && (pixSize == 32 || pixSize == 24)) { + // Now check on the DirectColorModel params + DirectColorModel dcm = (DirectColorModel) cm; + int rmask = dcm.getRedMask(); + int gmask = dcm.getGreenMask(); + int bmask = dcm.getBlueMask(); + if (rmask == DCM_RED_MASK && gmask == DCM_GREEN_MASK && bmask == DCM_BLUE_MASK) { + if (dcm.getAlphaMask() == DCM_ALPHA_MASK) { + imageType = (isAlphaPre ? TYPE_INT_ARGB_PRE : TYPE_INT_ARGB); + } else { + // No Alpha + if (!dcm.hasAlpha()) { + imageType = TYPE_INT_RGB; + } + } + } // if (dcm.getRedMask() == DCM_RED_MASK && + else if (rmask == DCM_BGR_RED_MASK && gmask == DCM_BGR_GRN_MASK && bmask == DCM_BGR_BLU_MASK) { + if (!dcm.hasAlpha()) { + imageType = TYPE_INT_BGR; + } + } // if (rmask == DCM_BGR_RED_MASK && + } // if (iraster.getPixelStride() == 1 + } // ((raster instanceof IntegerComponentRaster) && + else if ((IndexColorModel.class.equals(cm.getClass())) && (numBands == 1) && (!cm.hasAlpha() || !isAlphaPre)) { + IndexColorModel icm = (IndexColorModel) cm; + int pixSize = icm.getPixelSize(); + + if (raster instanceof BytePackedRaster && MultiPixelPackedSampleModel.class.equals(sm.getClass())) { + imageType = TYPE_BYTE_BINARY; + } // if (raster instanceof BytePackedRaster) + else if (raster instanceof ByteComponentRaster && PixelInterleavedSampleModel.class.equals(sm.getClass())) { + ByteComponentRaster braster = (ByteComponentRaster) raster; + if (braster.getPixelStride() == 1 && pixSize <= 8) { + imageType = TYPE_BYTE_INDEXED; + } + } + } // else if (cm instanceof IndexColorModel) && (numBands == 1)) + else if ((raster instanceof ShortComponentRaster) && (DirectColorModel.class.equals(cm.getClass())) + && (SinglePixelPackedSampleModel.class.equals(sm.getClass())) && (numBands == 3) && !cm.hasAlpha()) { + DirectColorModel dcm = (DirectColorModel) cm; + if (dcm.getRedMask() == DCM_565_RED_MASK) { + if (dcm.getGreenMask() == DCM_565_GRN_MASK && dcm.getBlueMask() == DCM_565_BLU_MASK) { + imageType = TYPE_USHORT_565_RGB; + } + } else if (dcm.getRedMask() == DCM_555_RED_MASK) { + if (dcm.getGreenMask() == DCM_555_GRN_MASK && dcm.getBlueMask() == DCM_555_BLU_MASK) { + imageType = TYPE_USHORT_555_RGB; + } + } + } // else if ((cm instanceof IndexColorModel) && (numBands == 1)) + else if ((raster instanceof ByteComponentRaster) && (cm instanceof ComponentColorModel) + && (raster.getSampleModel() instanceof PixelInterleavedSampleModel) + && (numBands == 3 || numBands == 4)) { + ComponentColorModel ccm = (ComponentColorModel) cm; + PixelInterleavedSampleModel csm = (PixelInterleavedSampleModel) raster.getSampleModel(); + ByteComponentRaster braster = (ByteComponentRaster) raster; + int[] offs = csm.getBandOffsets(); + if (ccm.getNumComponents() != numBands) { + throw new RasterFormatException("Number of components in " + "ColorModel (" + ccm.getNumComponents() + + ") does not match # in " + " Raster (" + numBands + ")"); + } + int[] nBits = ccm.getComponentSize(); + boolean is8bit = true; + for (int i = 0; i < numBands; i++) { + if (nBits[i] != 8) { + is8bit = false; + break; + } + } + if (is8bit && braster.getPixelStride() == numBands && offs[0] == numBands - 1 && offs[1] == numBands - 2 + && offs[2] == numBands - 3 && ComponentColorModel.class.equals(ccm.getClass()) + && PixelInterleavedSampleModel.class.equals(csm.getClass())) { + if (numBands == 3 && !ccm.hasAlpha()) { + imageType = TYPE_3BYTE_BGR; + } else if (offs[3] == 0 && ccm.hasAlpha()) { + imageType = (isAlphaPre ? TYPE_4BYTE_ABGR_PRE : TYPE_4BYTE_ABGR); + } + } + } // else if ((raster instanceof ByteComponentRaster) && } /** @@ -835,46 +683,42 @@ public int getType() { */ @Override public ColorModel getColorModel() { + // one of Component, Index, or Packed(Direct) return colorModel; } /** * Returns the {@link WritableRaster}. * - * @return the WriteableRaster of this BufferedImage - * . + * @return the WriteableRaster of this BufferedImage . */ public WritableRaster getRaster() { return raster; } - /** - * Returns a WritableRaster representing the alpha - * channel for BufferedImage objects - * with ColorModel objects that support a separate - * spatial alpha channel, such as ComponentColorModel and - * DirectColorModel. Returns null if there - * is no alpha channel associated with the ColorModel in - * this image. This method assumes that for all - * ColorModel objects other than - * IndexColorModel, if the ColorModel - * supports alpha, there is a separate alpha channel - * which is stored as the last band of image data. - * If the image uses an IndexColorModel that - * has alpha in the lookup table, this method returns - * null since there is no spatially discrete alpha - * channel. This method creates a new - * WritableRaster, but shares the data array. + /** + * Returns a WritableRaster representing the alpha channel for + * BufferedImage objects with ColorModel objects that + * support a separate spatial alpha channel, such as + * ComponentColorModel and DirectColorModel. Returns + * null if there is no alpha channel associated with the + * ColorModel in this image. This method assumes that for all + * ColorModel objects other than IndexColorModel, if + * the ColorModel supports alpha, there is a separate alpha channel + * which is stored as the last band of image data. If the image uses an + * IndexColorModel that has alpha in the lookup table, this method + * returns null since there is no spatially discrete alpha channel. + * This method creates a new WritableRaster, but shares the data + * array. + * * @return a WritableRaster or null if this - * BufferedImage has no alpha channel associated - * with its ColorModel. + * BufferedImage has no alpha channel associated with its + * ColorModel. */ - public WritableRaster getAlphaRaster() { - return colorModel.getAlphaRaster(raster); - } - + public WritableRaster getAlphaRaster() { + return colorModel.getAlphaRaster(raster); + } - /** * Returns an integer pixel in the default RGB color model (TYPE_INT_ARGB) and * default sRGB colorspace. Color conversion takes place if this default model @@ -887,11 +731,9 @@ public WritableRaster getAlphaRaster() { * An ArrayOutOfBoundsException may be thrown if the coordinates * are not in bounds. However, explicit bounds checking is not guaranteed. * - * @param x - * the X coordinate of the pixel from which to get the pixel in the + * @param x the X coordinate of the pixel from which to get the pixel in the * default RGB color model and sRGB color space - * @param y - * the Y coordinate of the pixel from which to get the pixel in the + * @param y the Y coordinate of the pixel from which to get the pixel in the * default RGB color model and sRGB color space * @return an integer pixel in the default RGB color model and default sRGB * colorspace. @@ -908,11 +750,11 @@ public int getRGB(int x, int y) { /** * Returns an array of integer pixels in the default RGB color model * (TYPE_INT_ARGB) and default sRGB color space, from a portion of the image - * data. Color conversion takes place if the default model does not match - * the image ColorModel. There are only 8-bits of precision for - * each color component in the returned data when using this method. With a - * specified coordinate (x, y) in the image, the ARGB pixel can be - * accessed in this way: + * data. Color conversion takes place if the default model does not match the + * image ColorModel. There are only 8-bits of precision for each + * color component in the returned data when using this method. With a specified + * coordinate (x, y) in the image, the ARGB pixel can be accessed in this + * way: *

* *
@@ -921,23 +763,16 @@ public int getRGB(int x, int y) {
 	 * 
 	 * 

* - * An ArrayOutOfBoundsException may be thrown if the region is - * not in bounds. However, explicit bounds checking is not guaranteed. - * - * @param startX - * the starting X coordinate - * @param startY - * the starting Y coordinate - * @param w - * width of region - * @param h - * height of region - * @param rgbArray - * if not null, the rgb pixels are written here - * @param offset - * offset into the rgbArray - * @param scansize - * scanline stride for the rgbArray + * An ArrayOutOfBoundsException may be thrown if the region is not + * in bounds. However, explicit bounds checking is not guaranteed. + * + * @param startX the starting X coordinate + * @param startY the starting Y coordinate + * @param w width of region + * @param h height of region + * @param rgbArray if not null, the rgb pixels are written here + * @param offset offset into the rgbArray + * @param scansize scanline stride for the rgbArray * @return array of RGB pixels. * @see #setRGB(int, int, int) * @see #setRGB(int, int, int, int, int[], int, int) @@ -961,40 +796,36 @@ public boolean checkHavePixels() { return false; } - public int[] getRangeRGB(int startX, int startY, int w, int h, - int[] rgbArray, int offset, int scansize) { + public int[] getRangeRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize) { if (秘pix == null && 秘pixSaved == null) checkHavePixels(); int[] pixels = (秘pix == null ? 秘pixSaved : 秘pix); - for (int y = startY, yoff=offset; y < startY + h; y++, yoff += scansize) + for (int y = startY, yoff = offset; y < startY + h; y++, yoff += scansize) for (int off = yoff, x = startX; x < startX + w; x++) rgbArray[off++] = pixels[y * this.width + x]; return rgbArray; } - + /** * Sets a pixel in this BufferedImage to the specified RGB value. - * The pixel is assumed to be in the default RGB color model, TYPE_INT_ARGB, - * and default sRGB color space. For images with an - * IndexColorModel, the index with the nearest color is chosen. + * The pixel is assumed to be in the default RGB color model, TYPE_INT_ARGB, and + * default sRGB color space. For images with an IndexColorModel, + * the index with the nearest color is chosen. * *

* * An ArrayOutOfBoundsException may be thrown if the coordinates * are not in bounds. However, explicit bounds checking is not guaranteed. * - * @param x - * the X coordinate of the pixel to set - * @param y - * the Y coordinate of the pixel to set - * @param rgb - * the RGB value + * @param x the X coordinate of the pixel to set + * @param y the Y coordinate of the pixel to set + * @param rgb the RGB value * @see #getRGB(int, int) * @see #getRGB(int, int, int, int, int[], int, int) */ public synchronized void setRGB(int x, int y, int rgb) { if (checkHavePixels()) - 秘imgNode = null; + 秘imgNode = null; int[] pixels = (秘pix == null ? 秘pixSaved : 秘pix); pixels[y * this.width + x] = rgb; } @@ -1005,9 +836,9 @@ public synchronized void setRGB(int x, int y, int rgb) { * (TYPE_INT_ARGB) and default sRGB color space, into a portion of the image * data. Color conversion takes place if the default model does not match the * image ColorModel. There are only 8-bits of precision for each - * color component in the returned data when using this method. With a - * specified coordinate (x, y) in the this image, the ARGB pixel can be - * accessed in this way: + * color component in the returned data when using this method. With a specified + * coordinate (x, y) in the this image, the ARGB pixel can be accessed in + * this way: * *

 	 * pixel = rgbArray[offset + (y - startY) * scansize + (x - startX)];
@@ -1017,41 +848,33 @@ public synchronized void setRGB(int x, int y, int rgb) {
 	 * 
 	 * 

* - * An ArrayOutOfBoundsException may be thrown if the region is - * not in bounds. However, explicit bounds checking is not guaranteed. - * - * @param startX - * the starting X coordinate - * @param startY - * the starting Y coordinate - * @param w - * width of the region - * @param h - * height of the region - * @param rgbArray - * the rgb pixels - * @param offset - * offset into the rgbArray - * @param scansize - * scanline stride for the rgbArray + * An ArrayOutOfBoundsException may be thrown if the region is not + * in bounds. However, explicit bounds checking is not guaranteed. + * + * @param startX the starting X coordinate + * @param startY the starting Y coordinate + * @param w width of the region + * @param h height of the region + * @param rgbArray the rgb pixels + * @param offset offset into the rgbArray + * @param scansize scanline stride for the rgbArray * @see #getRGB(int, int) * @see #getRGB(int, int, int, int, int[], int, int) */ - public void setRGB(int startX, int startY, int w, int h, int[] rgbArray, - int offset, int scansize) { + public void setRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize) { if (checkHavePixels()) - 秘imgNode = null; + 秘imgNode = null; int[] pixels = (秘pix == null ? 秘pixSaved : 秘pix); int width = this.width; - for (int y = startY, yoff = offset; y < startY + h; y++, yoff += scansize) - for (int x = startX, off = yoff; x < startX + w; x++) + for (int y = startY, yoff = offset; y < startY + h; y++, yoff += scansize) + for (int x = startX, off = yoff; x < startX + w; x++) pixels[y * width + x] = rgbArray[off++]; 秘pix = 秘pixSaved = pixels; // 秘pix is used by getGraphics() // 秘pixSaved is kept in case we need to do this again 秘g = null; // forces new this.秘canvas to be created in getGraphics() - getImageGraphic(); // sets 秘pix = null and creates 秘canvas - + getImageGraphic(); // sets 秘pix = null and creates 秘canvas + } /** @@ -1078,8 +901,7 @@ public int getHeight() { * * Returns the width of the BufferedImage. * - * @param observer - * ignored + * @param observer ignored * @return the width of this BufferedImage */ @Override @@ -1090,8 +912,7 @@ public int getWidth(ImageObserver observer) { /** * Returns the height of the BufferedImage. * - * @param observer - * ignored + * @param observer ignored * @return the height of this BufferedImage */ @Override @@ -1102,8 +923,8 @@ public int getHeight(ImageObserver observer) { /** * Returns the object that produces the pixels for the image. * - * @return the {@link ImageProducer} that is used to produce the pixels for - * this image. + * @return the {@link ImageProducer} that is used to produce the pixels for this + * image. * @see ImageProducer */ @SuppressWarnings("rawtypes") @@ -1128,11 +949,9 @@ public ImageProducer getSource() { * optional comment that can be presented to the user as a description of the * image, its source, or its author. * - * @param name - * the property name - * @param observer - * the ImageObserver that receives notification - * regarding image information + * @param name the property name + * @param observer the ImageObserver that receives notification + * regarding image information * @return an {@link Object} that is the property referred to by the specified * name or null if the properties of this * image are not yet known. @@ -1148,8 +967,7 @@ public Object getProperty(String name, ImageObserver observer) { /** * Returns a property of the image by name. * - * @param name - * the property name + * @param name the property name * @return an Object that is the property referred to by the * specified name. * @throws NullPointerException if the property name is null. @@ -1174,8 +992,7 @@ public Object getProperty(String name) { * compatibility. {@link #createGraphics() createGraphics} is more convenient, * since it is declared to return a Graphics2D. * - * @return a Graphics2D, which can be used to draw into this - * image. + * @return a Graphics2D, which can be used to draw into this image. */ @Override public Graphics getGraphics() { @@ -1195,27 +1012,22 @@ public Graphics2D createGraphics() { /** * Returns a subimage defined by a specified rectangular region. The returned - * BufferedImage shares the same data array as the original - * image. + * BufferedImage shares the same data array as the original image. * - * @param x - * the X coordinate of the upper-left corner of the specified + * @param x the X coordinate of the upper-left corner of the specified * rectangular region - * @param y - * the Y coordinate of the upper-left corner of the specified + * @param y the Y coordinate of the upper-left corner of the specified * rectangular region - * @param w - * the width of the specified rectangular region - * @param h - * the height of the specified rectangular region + * @param w the width of the specified rectangular region + * @param h the height of the specified rectangular region * @return a BufferedImage that is the subimage of this * BufferedImage. * @exception RasterFormatException if the specified area is not * contained within this BufferedImage. */ public BufferedImage getSubimage(int x, int y, int w, int h) { - return new BufferedImage(colorModel, raster.createWritableChild(x, y, w, h, - 0, 0, null), colorModel.isAlphaPremultiplied(), properties); + return new BufferedImage(colorModel, raster.createWritableChild(x, y, w, h, 0, 0, null), + colorModel.isAlphaPremultiplied(), properties); } /** @@ -1255,24 +1067,23 @@ public boolean isAlphaPremultiplied() { */ @Override public String toString() { - return new String("BufferedImage@" + Integer.toHexString(hashCode()) - + ": type = " + imageType + " " + colorModel.toString() + " " + raster.toString()); + return new String("BufferedImage@" + Integer.toHexString(hashCode()) + ": type = " + imageType + " " + + colorModel.toString() + " " + raster.toString()); } /** * Returns a {@link Vector} of {@link RenderedImage} objects that are the - * immediate sources, not the sources of these immediate sources, of image - * data for this BufferedImage. This method returns - * null if the BufferedImage has no information - * about its immediate sources. It returns an empty Vector if the + * immediate sources, not the sources of these immediate sources, of image data + * for this BufferedImage. This method returns null if + * the BufferedImage has no information about its immediate + * sources. It returns an empty Vector if the * BufferedImage has no immediate sources. * * @return a Vector containing immediate sources of this - * BufferedImage object's image date, or - * null if this BufferedImage has no - * information about its immediate sources, or an empty - * Vector if this BufferedImage has no - * immediate sources. + * BufferedImage object's image date, or null + * if this BufferedImage has no information about its + * immediate sources, or an empty Vector if this + * BufferedImage has no immediate sources. */ @Override public Vector getSources() { @@ -1284,9 +1095,9 @@ public Vector getSources() { * getProperty(String)} or null, if no property names are * recognized. * - * @return a String array containing all of the property names - * that getProperty(String) recognizes; or - * null if no property names are recognized. + * @return a String array containing all of the property names that + * getProperty(String) recognizes; or null if + * no property names are recognized. */ @Override public String[] getPropertyNames() { @@ -1294,8 +1105,8 @@ public String[] getPropertyNames() { } /** - * Returns the minimum x coordinate of this BufferedImage. This - * is always zero. + * Returns the minimum x coordinate of this BufferedImage. This is + * always zero. * * @return the minimum x coordinate of this BufferedImage. */ @@ -1305,8 +1116,8 @@ public int getMinX() { } /** - * Returns the minimum y coordinate of this BufferedImage. This - * is always zero. + * Returns the minimum y coordinate of this BufferedImage. This is + * always zero. * * @return the minimum y coordinate of this BufferedImage. */ @@ -1411,13 +1222,11 @@ public int getTileGridYOffset() { /** * Returns tile (tileXtileY). Note that * tileX and tileY are indices into the tile array, - * not pixel locations. The Raster that is returned is live, - * which means that it is updated if the image is changed. + * not pixel locations. The Raster that is returned is live, which + * means that it is updated if the image is changed. * - * @param tileX - * the x index of the requested tile in the tile array - * @param tileY - * the y index of the requested tile in the tile array + * @param tileX the x index of the requested tile in the tile array + * @param tileY the y index of the requested tile in the tile array * @return a Raster that is the tile defined by the arguments * tileX and tileY. * @exception ArrayIndexOutOfBoundsException if both @@ -1450,10 +1259,8 @@ public Raster getData() { int height = raster.getHeight(); int startX = raster.getMinX(); int startY = raster.getMinY(); - WritableRaster wr = Raster.createWritableRaster( - raster.getSampleModel(), - new Point(raster.getSampleModelTranslateX(), raster - .getSampleModelTranslateY())); + WritableRaster wr = Raster.createWritableRaster(raster.getSampleModel(), + new Point(raster.getSampleModelTranslateX(), raster.getSampleModelTranslateY())); Object tdata = null; checkHavePixels(); @@ -1469,8 +1276,7 @@ public Raster getData() { * The Raster returned is a copy of the image data and is not * updated if the image is changed. * - * @param rect - * the region of the BufferedImage to be returned. + * @param rect the region of the BufferedImage to be returned. * @return a Raster that is a copy of the image data of the * specified region of the BufferedImage * @see #setData(Raster) @@ -1496,16 +1302,15 @@ public Raster getData(Rectangle rect) { /** * Computes an arbitrary rectangular region of the BufferedImage - * and copies it into a specified WritableRaster. The region to - * be computed is determined from the bounds of the specified + * and copies it into a specified WritableRaster. The region to be + * computed is determined from the bounds of the specified * WritableRaster. The specified WritableRaster must * have a SampleModel that is compatible with this image. If * outRaster is null, an appropriate * WritableRaster is created. * - * @param outRaster - * a WritableRaster to hold the returned part of the - * image, or null + * @param outRaster a WritableRaster to hold the returned part of + * the image, or null * @return a reference to the supplied or created WritableRaster. */ @Override @@ -1531,11 +1336,10 @@ public WritableRaster copyData(WritableRaster outRaster) { /** * Sets a rectangular region of the image to the contents of the specified * Raster r, which is assumed to be in the same - * coordinate space as the BufferedImage. The operation is - * clipped to the bounds of the BufferedImage. + * coordinate space as the BufferedImage. The operation is clipped + * to the bounds of the BufferedImage. * - * @param r - * the specified Raster + * @param r the specified Raster * @see #getData * @see #getData(Rectangle) */ @@ -1604,61 +1408,62 @@ public void setData(Raster r) { // throw new IllegalArgumentException("Only 1 tile in image"); // } // - /** - * Returns an array of {@link Point} objects indicating which tiles - * are checked out for writing. Returns null if none are - * checked out. - * @return a Point array that indicates the tiles that - * are checked out for writing, or null if no - * tiles are checked out for writing. - */ - public Point[] getWritableTileIndices() { - Point[] p = new Point[1]; - p[0] = new Point(0, 0); - - return p; - } - - /** - * Returns whether or not any tile is checked out for writing. - * Semantically equivalent to + /** + * Returns an array of {@link Point} objects indicating which tiles are checked + * out for writing. Returns null if none are checked out. + * + * @return a Point array that indicates the tiles that are checked + * out for writing, or null if no tiles are checked out for + * writing. + */ + public Point[] getWritableTileIndices() { + Point[] p = new Point[1]; + p[0] = new Point(0, 0); + + return p; + } + + /** + * Returns whether or not any tile is checked out for writing. Semantically + * equivalent to + * *

 	 * (getWritableTileIndices() != null).
 	 * 
+ * * @return true if any tile is checked out for writing; - * false otherwise. - */ - public boolean hasTileWriters () { - return true; - } - - /** - * Checks out a tile for writing. All registered - * TileObservers are notified when a tile goes from having - * no writers to having one writer. - * @param tileX the x index of the tile - * @param tileY the y index of the tile - * @return a WritableRaster that is the tile, indicated by - * the specified indices, to be checked out for writing. - */ - public WritableRaster getWritableTile (int tileX, int tileY) { - return raster; - } - - /** - * Relinquishes permission to write to a tile. If the caller - * continues to write to the tile, the results are undefined. - * Calls to this method should only appear in matching pairs - * with calls to {@link #getWritableTile(int, int) getWritableTile(int, - int)}. Any other leads - * to undefined results. All registered TileObservers - * are notified when a tile goes from having one writer to having no - * writers. + * false otherwise. + */ + public boolean hasTileWriters() { + return true; + } + + /** + * Checks out a tile for writing. All registered TileObservers are + * notified when a tile goes from having no writers to having one writer. + * + * @param tileX the x index of the tile + * @param tileY the y index of the tile + * @return a WritableRaster that is the tile, indicated by the + * specified indices, to be checked out for writing. + */ + public WritableRaster getWritableTile(int tileX, int tileY) { + return raster; + } + + /** + * Relinquishes permission to write to a tile. If the caller continues to write + * to the tile, the results are undefined. Calls to this method should only + * appear in matching pairs with calls to {@link #getWritableTile(int, int) + * getWritableTile(int, int)}. Any other leads to undefined results. All + * registered TileObservers are notified when a tile goes from + * having one writer to having no writers. + * * @param tileX the x index of the tile * @param tileY the y index of the tile */ - public void releaseWritableTile (int tileX, int tileY) { - } + public void releaseWritableTile(int tileX, int tileY) { + } /** * Returns the transparency. Returns either OPAQUE, BITMASK, or TRANSLUCENT. @@ -1674,29 +1479,28 @@ public int getTransparency() { return colorModel.getTransparency(); } - /** * Set the underlying graphics object coming from painting this image * * */ - + public void setImageFromHTML5Canvas(JSGraphics2D g) { this.秘g = g; width = raster.width; height = raster.height; setPixels(); } - + /** - * Extract the int[] data from this image by installing it in a canvas. - * Note that if if img.complete == false, then this will result in a - * black rectangle. + * Extract the int[] data from this image by installing it in a canvas. Note + * that if img.complete == false, then this will result in a black rectangle. * */ @SuppressWarnings("unused") - public void setPixels() { - DOMNode canvas = (秘g == null ? null : /** @j2sNative this.秘g.canvas || */null); + private void setPixels() { + DOMNode canvas = (秘g == null ? null : /** @j2sNative this.秘g.canvas || */ + null); if (canvas == null) canvas = DOMNode.createElement("canvas", null); int w = width; @@ -1704,37 +1508,52 @@ public void setPixels() { int[] data = null; /** * note that setting canvas.width clears it + * * @j2sNative * - * if (!this.秘g) { - * canvas.width = w; - * canvas.height = h; - * } - * var ctx = canvas.getContext("2d"); - * if (!this.秘g) - * ctx.drawImage(this.秘imgNode, 0, 0, w, h); - * data = ctx.getImageData(0, 0, w, h).data; + * if (!this.秘g) { canvas.width = w; canvas.height = h; } var ctx = + * canvas.getContext("2d"); if (!this.秘g) + * ctx.drawImage(this.秘imgNode, 0, 0, w, h); data = + * ctx.getImageData(0, 0, w, h).data; * */ - { + DataBuffer buf = raster.getDataBuffer(); + switch (imageType) { + case TYPE_INT_RGB: +// case TYPE_INT_ARGB_PRE: + case TYPE_INT_ARGB: + DataBufferInt buffer = (DataBufferInt) buf; + toIntARGB(data, 秘pix = buffer.data); + break; + case TYPE_INT_ARGB_PRE: + case TYPE_INT_BGR: + case TYPE_3BYTE_BGR: + case TYPE_4BYTE_ABGR: + case TYPE_4BYTE_ABGR_PRE: + case TYPE_BYTE_GRAY: + case TYPE_USHORT_GRAY: + case TYPE_BYTE_BINARY: + case TYPE_USHORT_565_RGB: + case TYPE_USHORT_555_RGB: + JSUtil.notImplemented("BufferedImage type " + imageType); + break; + case TYPE_BYTE_INDEXED: + } - DataBufferInt buffer = (DataBufferInt) raster.getDataBuffer(); - toIntARGB(data, 秘pix = buffer.data); 秘imgNode = canvas; 秘havePix = true; } - @Override public void flush() { // call this method after drawing to ensure that // pixels are recreated from the HTML5 canvas - 秘pix = null; + 秘pix = null; 秘havePix = false; - // was for surfaceManager only super.flush(); } + /** - * convert [r g b a r g b a ...] into [argb argb argb ...] + * convert [r g b a r g b a ...] into [argb argb argb ...] * * currently does not respect transparency * @@ -1742,30 +1561,29 @@ public void flush() { * @return array of ARGB values * */ - void toIntARGB(int[] imgData, int[] iData) { - /* - * red=imgData.data[0]; - * green=imgData.data[1]; - * blue=imgData.data[2]; - * alpha=imgData.data[3]; - */ - int n = imgData.length / 4; - int a; - for (int i = 0, j = 0; i < n;) { - int argb = (imgData[j++] << 16) | (imgData[j++] << 8) | imgData[j++] | 0xFF000000; - iData[i++] = (imgData[j++] == 0 ? 0 : argb); - } - } - - /** - * - * Get a JSGraphics2D for this image, but don't initialize it with a state save - * the way g.create() or image.getGraphics() or image.createGraphics() do. - * So do NOT execute g.dispose() on the returned object. - * - * @author Bob Hanson - * @return a JSGraphics2D object - */ + private static void toIntARGB(int[] imgData, int[] iData) { + // red=imgData.data[0]; + // green=imgData.data[1]; + // blue=imgData.data[2]; + // alpha=imgData.data[3]; + + int n = imgData.length / 4; + int a; + for (int i = 0, j = 0; i < n;) { + int argb = (imgData[j++] << 16) | (imgData[j++] << 8) | imgData[j++] | 0xFF000000; + iData[i++] = (imgData[j++] == 0 ? 0 : argb); + } + } + + /** + * + * Get a JSGraphics2D for this image, but don't initialize it with a state save + * the way g.create() or image.getGraphics() or image.createGraphics() do. So do + * NOT execute g.dispose() on the returned object. + * + * @author Bob Hanson + * @return a JSGraphics2D object + */ @SuppressWarnings("unused") public Graphics2D getImageGraphic() { if (秘g == null) { @@ -1775,31 +1593,26 @@ public Graphics2D getImageGraphic() { /** * @j2sNative * - * canvas.width = w; - * canvas.height = h; - * + * canvas.width = w; canvas.height = h; + * */ - 秘canvas = canvas; - Object pix = 秘pix; + 秘canvas = canvas; + Object pix = 秘pix; 秘g = new JSGraphics2D(canvas); // we need to draw the image now, because it might // have pixels. Note that Java actually does not // allow creating a Graphics from MemoryImageSource - // so pixels would never be there. + // so pixels would never be there. if (pix != null) 秘g.drawImagePriv(this, 0, 0, null); /** - * @j2sNative - * if (pix) - * pix.img = this; + * @j2sNative if (pix) pix.img = this; * */ - - // 秘pix = null; + flush(); // also setting 秘havePix false - } - Graphics2D g2d = (Graphics2D) (Object)秘g; + Graphics2D g2d = (Graphics2D) (Object) 秘g; if (秘component != null) { g2d.setFont(秘component.getFont()); g2d.setBackground(秘component.getBackground()); @@ -1808,5 +1621,58 @@ public Graphics2D getImageGraphic() { return g2d; } + public boolean 秘isOpaque() { + switch (imageType) { + case TYPE_INT_ARGB: + case TYPE_INT_ARGB_PRE: + case TYPE_4BYTE_ABGR: + case TYPE_4BYTE_ABGR_PRE: + return false; + case TYPE_INT_RGB: + case TYPE_INT_BGR: + case TYPE_3BYTE_BGR: + case TYPE_BYTE_GRAY: + case TYPE_USHORT_GRAY: + case TYPE_BYTE_BINARY: + case TYPE_BYTE_INDEXED: + case TYPE_USHORT_565_RGB: + case TYPE_USHORT_555_RGB: + default: + return true; + } + } + + public int[] get秘pix() { + int[] pixels = null; + Raster r = raster; + int[] p = 秘pix; + + if (getColorModel() == ColorModel.秘RGBdefault) { + int[] rp = ((SunWritableRaster) r).秘pix; + /** + * @j2sNative + * + * return rp || p; + * + */ + } else { + int n = width * height; + int[] a = new int[n]; + getRaster().getPixels(0, 0, width, height, a); + 秘pix = pixels = new int[n * 4]; + for (int i = 0, pt = 0; i < n; i++, pt += 4) { + getColorModel().getComponents(a[i], pixels, pt); + } + } + return pixels; + } + + public DOMNode 秘updateNode(DOMNode imgNode) { + if (秘userRaster) { + Graphics g = getGraphics(); + g.drawImage(this, 0, 0, null); + } + return imgNode; + } } diff --git a/sources/net.sf.j2s.java.core/src/java/awt/image/ColorModel.java b/sources/net.sf.j2s.java.core/src/java/awt/image/ColorModel.java index e52641a5f..28c98446f 100644 --- a/sources/net.sf.j2s.java.core/src/java/awt/image/ColorModel.java +++ b/sources/net.sf.j2s.java.core/src/java/awt/image/ColorModel.java @@ -30,7 +30,14 @@ import java.awt.Transparency; import java.awt.color.ColorSpace; +import java.awt.color.ICC_ColorSpace; +import java.util.Collections; import java.util.Map; +import java.util.WeakHashMap; + +import sun.java2d.cmm.CMSManager; +import sun.java2d.cmm.ColorTransform; +import sun.java2d.cmm.PCMM; /** * The ColorModel abstract class encapsulates the @@ -173,7 +180,7 @@ public abstract class ColorModel implements Transparency{ */ protected int transferType; - private static ColorModel RGBdefault; + static ColorModel 秘RGBdefault; /** * Returns a DirectColorModel that describes the default @@ -192,15 +199,15 @@ public abstract class ColorModel implements Transparency{ * RGB values. */ public static ColorModel getRGBdefault() { - if (RGBdefault == null) { - RGBdefault = new DirectColorModel(32, + if (秘RGBdefault == null) { + 秘RGBdefault = new DirectColorModel(32, 0x00ff0000, // Red 0x0000ff00, // Green 0x000000ff, // Blue 0xff000000 // Alpha ); } - return RGBdefault; + return 秘RGBdefault; } /** @@ -1645,18 +1652,17 @@ public String toString() { ); } - static int getDefaultTransferType(int pixel_bits) { - if (pixel_bits <= 8) { - return DataBuffer.TYPE_BYTE; - } -// else if (pixel_bits <= 16) { -// return DataBuffer.TYPE_USHORT; -// } else if (pixel_bits <= 32) { - return DataBuffer.TYPE_INT; -// } else { -// return DataBuffer.TYPE_UNDEFINED; -// } - } + static int getDefaultTransferType(int pixel_bits) { + if (pixel_bits <= 8) { + return DataBuffer.TYPE_BYTE; + } else if (pixel_bits <= 16) { + return DataBuffer.TYPE_USHORT; + } else if (pixel_bits <= 32) { + return DataBuffer.TYPE_INT; + } else { + return DataBuffer.TYPE_UNDEFINED; + } + } static byte[] l8Tos8 = null; // 8-bit linear to 8-bit non-linear sRGB LUT static byte[] s8Tol8 = null; // 8-bit non-linear sRGB to 8-bit linear LUT @@ -1677,257 +1683,257 @@ static boolean isLinearRGBspace(ColorSpace cs) { } static boolean isLinearGRAYspace(ColorSpace cs) { - return false; -// // Note: CMM.GRAYspace will be null if the linear -// // gray space has not been created yet. -// return (cs == CMSManager.GRAYspace); + // Note: CMM.GRAYspace will be null if the linear + // gray space has not been created yet. + return (cs == CMSManager.GRAYspace); + } + + + static byte[] getLinearRGB8TosRGB8LUT() { + if (l8Tos8 == null) { + l8Tos8 = new byte[256]; + float input, output; + // algorithm for linear RGB to nonlinear sRGB conversion + // is from the IEC 61966-2-1 International Standard, + // Colour Management - Default RGB colour space - sRGB, + // First Edition, 1999-10, + // avaiable for order at http://www.iec.ch + for (int i = 0; i <= 255; i++) { + input = ((float) i) / 255.0f; + if (input <= 0.0031308f) { + output = input * 12.92f; + } else { + output = 1.055f * ((float) Math.pow(input, (1.0 / 2.4))) + - 0.055f; + } + l8Tos8[i] = (byte) Math.round(output * 255.0f); + } + } + return l8Tos8; + } + + static byte[] getsRGB8ToLinearRGB8LUT() { + if (s8Tol8 == null) { + s8Tol8 = new byte[256]; + float input, output; + // algorithm from IEC 61966-2-1 International Standard + for (int i = 0; i <= 255; i++) { + input = ((float) i) / 255.0f; + if (input <= 0.04045f) { + output = input / 12.92f; + } else { + output = (float) Math.pow((input + 0.055f) / 1.055f, 2.4); + } + s8Tol8[i] = (byte) Math.round(output * 255.0f); + } + } + return s8Tol8; + } + + static byte[] getLinearRGB16TosRGB8LUT() { + if (l16Tos8 == null) { + l16Tos8 = new byte[65536]; + float input, output; + // algorithm from IEC 61966-2-1 International Standard + for (int i = 0; i <= 65535; i++) { + input = ((float) i) / 65535.0f; + if (input <= 0.0031308f) { + output = input * 12.92f; + } else { + output = 1.055f * ((float) Math.pow(input, (1.0 / 2.4))) + - 0.055f; + } + l16Tos8[i] = (byte) Math.round(output * 255.0f); + } + } + return l16Tos8; + } + + static short[] getsRGB8ToLinearRGB16LUT() { + if (s8Tol16 == null) { + s8Tol16 = new short[256]; + float input, output; + // algorithm from IEC 61966-2-1 International Standard + for (int i = 0; i <= 255; i++) { + input = ((float) i) / 255.0f; + if (input <= 0.04045f) { + output = input / 12.92f; + } else { + output = (float) Math.pow((input + 0.055f) / 1.055f, 2.4); + } + s8Tol16[i] = (short) Math.round(output * 65535.0f); + } + } + return s8Tol16; + } + + /* + * Return a byte LUT that converts 8-bit gray values in the grayCS + * ColorSpace to the appropriate 8-bit sRGB value. I.e., if lut + * is the byte array returned by this method and sval = lut[gval], + * then the sRGB triple (sval,sval,sval) is the best match to gval. + * Cache references to any computed LUT in a Map. + */ + static byte[] getGray8TosRGB8LUT(ICC_ColorSpace grayCS) { + if (isLinearGRAYspace(grayCS)) { + return getLinearRGB8TosRGB8LUT(); + } + if (g8Tos8Map != null) { + byte[] g8Tos8LUT = (byte []) g8Tos8Map.get(grayCS); + if (g8Tos8LUT != null) { + return g8Tos8LUT; + } + } + byte[] g8Tos8LUT = new byte[256]; + for (int i = 0; i <= 255; i++) { + g8Tos8LUT[i] = (byte) i; + } + ColorTransform[] transformList = new ColorTransform[2]; + PCMM mdl = CMSManager.getModule(); + ICC_ColorSpace srgbCS = + (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_sRGB); + transformList[0] = mdl.createTransform( + grayCS.getProfile(), ColorTransform.Any, ColorTransform.In); + transformList[1] = mdl.createTransform( + srgbCS.getProfile(), ColorTransform.Any, ColorTransform.Out); + ColorTransform t = mdl.createTransform(transformList); + byte[] tmp = t.colorConvert(g8Tos8LUT, null); + for (int i = 0, j= 2; i <= 255; i++, j += 3) { + // All three components of tmp should be equal, since + // the input color space to colorConvert is a gray scale + // space. However, there are slight anomalies in the results. + // Copy tmp starting at index 2, since colorConvert seems + // to be slightly more accurate for the third component! + g8Tos8LUT[i] = tmp[j]; + } + if (g8Tos8Map == null) { + g8Tos8Map = Collections.synchronizedMap(new WeakHashMap(2)); + } + g8Tos8Map.put(grayCS, g8Tos8LUT); + return g8Tos8LUT; } -// static byte[] getLinearRGB8TosRGB8LUT() { -// if (l8Tos8 == null) { -// l8Tos8 = new byte[256]; -// float input, output; -// // algorithm for linear RGB to nonlinear sRGB conversion -// // is from the IEC 61966-2-1 International Standard, -// // Colour Management - Default RGB colour space - sRGB, -// // First Edition, 1999-10, -// // avaiable for order at http://www.iec.ch -// for (int i = 0; i <= 255; i++) { -// input = ((float) i) / 255.0f; -// if (input <= 0.0031308f) { -// output = input * 12.92f; -// } else { -// output = 1.055f * ((float) Math.pow(input, (1.0 / 2.4))) -// - 0.055f; -// } -// l8Tos8[i] = (byte) Math.round(output * 255.0f); -// } -// } -// return l8Tos8; -// } -// -// static byte[] getsRGB8ToLinearRGB8LUT() { -// if (s8Tol8 == null) { -// s8Tol8 = new byte[256]; -// float input, output; -// // algorithm from IEC 61966-2-1 International Standard -// for (int i = 0; i <= 255; i++) { -// input = ((float) i) / 255.0f; -// if (input <= 0.04045f) { -// output = input / 12.92f; -// } else { -// output = (float) Math.pow((input + 0.055f) / 1.055f, 2.4); -// } -// s8Tol8[i] = (byte) Math.round(output * 255.0f); -// } -// } -// return s8Tol8; -// } -// -// static byte[] getLinearRGB16TosRGB8LUT() { -// if (l16Tos8 == null) { -// l16Tos8 = new byte[65536]; -// float input, output; -// // algorithm from IEC 61966-2-1 International Standard -// for (int i = 0; i <= 65535; i++) { -// input = ((float) i) / 65535.0f; -// if (input <= 0.0031308f) { -// output = input * 12.92f; -// } else { -// output = 1.055f * ((float) Math.pow(input, (1.0 / 2.4))) -// - 0.055f; -// } -// l16Tos8[i] = (byte) Math.round(output * 255.0f); -// } -// } -// return l16Tos8; -// } -// -// static short[] getsRGB8ToLinearRGB16LUT() { -// if (s8Tol16 == null) { -// s8Tol16 = new short[256]; -// float input, output; -// // algorithm from IEC 61966-2-1 International Standard -// for (int i = 0; i <= 255; i++) { -// input = ((float) i) / 255.0f; -// if (input <= 0.04045f) { -// output = input / 12.92f; -// } else { -// output = (float) Math.pow((input + 0.055f) / 1.055f, 2.4); -// } -// s8Tol16[i] = (short) Math.round(output * 65535.0f); -// } -// } -// return s8Tol16; -// } -// -// /* -// * Return a byte LUT that converts 8-bit gray values in the grayCS -// * ColorSpace to the appropriate 8-bit sRGB value. I.e., if lut -// * is the byte array returned by this method and sval = lut[gval], -// * then the sRGB triple (sval,sval,sval) is the best match to gval. -// * Cache references to any computed LUT in a Map. -// */ -// static byte[] getGray8TosRGB8LUT(ICC_ColorSpace grayCS) { -// if (isLinearGRAYspace(grayCS)) { -// return getLinearRGB8TosRGB8LUT(); -// } -// if (g8Tos8Map != null) { -// byte[] g8Tos8LUT = (byte []) g8Tos8Map.get(grayCS); -// if (g8Tos8LUT != null) { -// return g8Tos8LUT; -// } -// } -// byte[] g8Tos8LUT = new byte[256]; -// for (int i = 0; i <= 255; i++) { -// g8Tos8LUT[i] = (byte) i; -// } -// ColorTransform[] transformList = new ColorTransform[2]; -// PCMM mdl = CMSManager.getModule(); -// ICC_ColorSpace srgbCS = -// (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_sRGB); -// transformList[0] = mdl.createTransform( -// grayCS.getProfile(), ColorTransform.Any, ColorTransform.In); -// transformList[1] = mdl.createTransform( -// srgbCS.getProfile(), ColorTransform.Any, ColorTransform.Out); -// ColorTransform t = mdl.createTransform(transformList); -// byte[] tmp = t.colorConvert(g8Tos8LUT, null); -// for (int i = 0, j= 2; i <= 255; i++, j += 3) { -// // All three components of tmp should be equal, since -// // the input color space to colorConvert is a gray scale -// // space. However, there are slight anomalies in the results. -// // Copy tmp starting at index 2, since colorConvert seems -// // to be slightly more accurate for the third component! -// g8Tos8LUT[i] = tmp[j]; -// } -// if (g8Tos8Map == null) { -// g8Tos8Map = Collections.synchronizedMap(new WeakHashMap(2)); -// } -// g8Tos8Map.put(grayCS, g8Tos8LUT); -// return g8Tos8LUT; -// } -// -// /* -// * Return a byte LUT that converts 16-bit gray values in the CS_GRAY -// * linear gray ColorSpace to the appropriate 8-bit value in the -// * grayCS ColorSpace. Cache references to any computed LUT in a Map. -// */ -// static byte[] getLinearGray16ToOtherGray8LUT(ICC_ColorSpace grayCS) { -// if (lg16Toog8Map != null) { -// byte[] lg16Toog8LUT = (byte []) lg16Toog8Map.get(grayCS); -// if (lg16Toog8LUT != null) { -// return lg16Toog8LUT; -// } -// } -// short[] tmp = new short[65536]; -// for (int i = 0; i <= 65535; i++) { -// tmp[i] = (short) i; -// } -// ColorTransform[] transformList = new ColorTransform[2]; -// PCMM mdl = CMSManager.getModule(); -// ICC_ColorSpace lgCS = -// (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_GRAY); -// transformList[0] = mdl.createTransform ( -// lgCS.getProfile(), ColorTransform.Any, ColorTransform.In); -// transformList[1] = mdl.createTransform ( -// grayCS.getProfile(), ColorTransform.Any, ColorTransform.Out); -// ColorTransform t = mdl.createTransform(transformList); -// tmp = t.colorConvert(tmp, null); -// byte[] lg16Toog8LUT = new byte[65536]; -// for (int i = 0; i <= 65535; i++) { -// // scale unsigned short (0 - 65535) to unsigned byte (0 - 255) -// lg16Toog8LUT[i] = -// (byte) (((float) (tmp[i] & 0xffff)) * (1.0f /257.0f) + 0.5f); -// } -// if (lg16Toog8Map == null) { -// lg16Toog8Map = Collections.synchronizedMap(new WeakHashMap(2)); -// } -// lg16Toog8Map.put(grayCS, lg16Toog8LUT); -// return lg16Toog8LUT; -// } -// -// /* -// * Return a byte LUT that converts 16-bit gray values in the grayCS -// * ColorSpace to the appropriate 8-bit sRGB value. I.e., if lut -// * is the byte array returned by this method and sval = lut[gval], -// * then the sRGB triple (sval,sval,sval) is the best match to gval. -// * Cache references to any computed LUT in a Map. -// */ -// static byte[] getGray16TosRGB8LUT(ICC_ColorSpace grayCS) { -// if (isLinearGRAYspace(grayCS)) { -// return getLinearRGB16TosRGB8LUT(); -// } -// if (g16Tos8Map != null) { -// byte[] g16Tos8LUT = (byte []) g16Tos8Map.get(grayCS); -// if (g16Tos8LUT != null) { -// return g16Tos8LUT; -// } -// } -// short[] tmp = new short[65536]; -// for (int i = 0; i <= 65535; i++) { -// tmp[i] = (short) i; -// } -// ColorTransform[] transformList = new ColorTransform[2]; -// PCMM mdl = CMSManager.getModule(); -// ICC_ColorSpace srgbCS = -// (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_sRGB); -// transformList[0] = mdl.createTransform ( -// grayCS.getProfile(), ColorTransform.Any, ColorTransform.In); -// transformList[1] = mdl.createTransform ( -// srgbCS.getProfile(), ColorTransform.Any, ColorTransform.Out); -// ColorTransform t = mdl.createTransform(transformList); -// tmp = t.colorConvert(tmp, null); -// byte[] g16Tos8LUT = new byte[65536]; -// for (int i = 0, j= 2; i <= 65535; i++, j += 3) { -// // All three components of tmp should be equal, since -// // the input color space to colorConvert is a gray scale -// // space. However, there are slight anomalies in the results. -// // Copy tmp starting at index 2, since colorConvert seems -// // to be slightly more accurate for the third component! -// -// // scale unsigned short (0 - 65535) to unsigned byte (0 - 255) -// g16Tos8LUT[i] = -// (byte) (((float) (tmp[j] & 0xffff)) * (1.0f /257.0f) + 0.5f); -// } -// if (g16Tos8Map == null) { -// g16Tos8Map = Collections.synchronizedMap(new WeakHashMap(2)); -// } -// g16Tos8Map.put(grayCS, g16Tos8LUT); -// return g16Tos8LUT; -// } -// -// /* -// * Return a short LUT that converts 16-bit gray values in the CS_GRAY -// * linear gray ColorSpace to the appropriate 16-bit value in the -// * grayCS ColorSpace. Cache references to any computed LUT in a Map. -// */ -// static short[] getLinearGray16ToOtherGray16LUT(ICC_ColorSpace grayCS) { -// if (lg16Toog16Map != null) { -// short[] lg16Toog16LUT = (short []) lg16Toog16Map.get(grayCS); -// if (lg16Toog16LUT != null) { -// return lg16Toog16LUT; -// } -// } -// short[] tmp = new short[65536]; -// for (int i = 0; i <= 65535; i++) { -// tmp[i] = (short) i; -// } -// ColorTransform[] transformList = new ColorTransform[2]; -// PCMM mdl = CMSManager.getModule(); -// ICC_ColorSpace lgCS = -// (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_GRAY); -// transformList[0] = mdl.createTransform ( -// lgCS.getProfile(), ColorTransform.Any, ColorTransform.In); -// transformList[1] = mdl.createTransform( -// grayCS.getProfile(), ColorTransform.Any, ColorTransform.Out); -// ColorTransform t = mdl.createTransform( -// transformList); -// short[] lg16Toog16LUT = t.colorConvert(tmp, null); -// if (lg16Toog16Map == null) { -// lg16Toog16Map = Collections.synchronizedMap(new WeakHashMap(2)); -// } -// lg16Toog16Map.put(grayCS, lg16Toog16LUT); -// return lg16Toog16LUT; -// } + /* + * Return a byte LUT that converts 16-bit gray values in the CS_GRAY + * linear gray ColorSpace to the appropriate 8-bit value in the + * grayCS ColorSpace. Cache references to any computed LUT in a Map. + */ + static byte[] getLinearGray16ToOtherGray8LUT(ICC_ColorSpace grayCS) { + if (lg16Toog8Map != null) { + byte[] lg16Toog8LUT = (byte []) lg16Toog8Map.get(grayCS); + if (lg16Toog8LUT != null) { + return lg16Toog8LUT; + } + } + short[] tmp = new short[65536]; + for (int i = 0; i <= 65535; i++) { + tmp[i] = (short) i; + } + ColorTransform[] transformList = new ColorTransform[2]; + PCMM mdl = CMSManager.getModule(); + ICC_ColorSpace lgCS = + (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_GRAY); + transformList[0] = mdl.createTransform ( + lgCS.getProfile(), ColorTransform.Any, ColorTransform.In); + transformList[1] = mdl.createTransform ( + grayCS.getProfile(), ColorTransform.Any, ColorTransform.Out); + ColorTransform t = mdl.createTransform(transformList); + tmp = t.colorConvert(tmp, null); + byte[] lg16Toog8LUT = new byte[65536]; + for (int i = 0; i <= 65535; i++) { + // scale unsigned short (0 - 65535) to unsigned byte (0 - 255) + lg16Toog8LUT[i] = + (byte) (((float) (tmp[i] & 0xffff)) * (1.0f /257.0f) + 0.5f); + } + if (lg16Toog8Map == null) { + lg16Toog8Map = Collections.synchronizedMap(new WeakHashMap(2)); + } + lg16Toog8Map.put(grayCS, lg16Toog8LUT); + return lg16Toog8LUT; + } + + /* + * Return a byte LUT that converts 16-bit gray values in the grayCS + * ColorSpace to the appropriate 8-bit sRGB value. I.e., if lut + * is the byte array returned by this method and sval = lut[gval], + * then the sRGB triple (sval,sval,sval) is the best match to gval. + * Cache references to any computed LUT in a Map. + */ + static byte[] getGray16TosRGB8LUT(ICC_ColorSpace grayCS) { + if (isLinearGRAYspace(grayCS)) { + return getLinearRGB16TosRGB8LUT(); + } + if (g16Tos8Map != null) { + byte[] g16Tos8LUT = (byte []) g16Tos8Map.get(grayCS); + if (g16Tos8LUT != null) { + return g16Tos8LUT; + } + } + short[] tmp = new short[65536]; + for (int i = 0; i <= 65535; i++) { + tmp[i] = (short) i; + } + ColorTransform[] transformList = new ColorTransform[2]; + PCMM mdl = CMSManager.getModule(); + ICC_ColorSpace srgbCS = + (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_sRGB); + transformList[0] = mdl.createTransform ( + grayCS.getProfile(), ColorTransform.Any, ColorTransform.In); + transformList[1] = mdl.createTransform ( + srgbCS.getProfile(), ColorTransform.Any, ColorTransform.Out); + ColorTransform t = mdl.createTransform(transformList); + tmp = t.colorConvert(tmp, null); + byte[] g16Tos8LUT = new byte[65536]; + for (int i = 0, j= 2; i <= 65535; i++, j += 3) { + // All three components of tmp should be equal, since + // the input color space to colorConvert is a gray scale + // space. However, there are slight anomalies in the results. + // Copy tmp starting at index 2, since colorConvert seems + // to be slightly more accurate for the third component! + + // scale unsigned short (0 - 65535) to unsigned byte (0 - 255) + g16Tos8LUT[i] = + (byte) (((float) (tmp[j] & 0xffff)) * (1.0f /257.0f) + 0.5f); + } + if (g16Tos8Map == null) { + g16Tos8Map = Collections.synchronizedMap(new WeakHashMap(2)); + } + g16Tos8Map.put(grayCS, g16Tos8LUT); + return g16Tos8LUT; + } + + /* + * Return a short LUT that converts 16-bit gray values in the CS_GRAY + * linear gray ColorSpace to the appropriate 16-bit value in the + * grayCS ColorSpace. Cache references to any computed LUT in a Map. + */ + static short[] getLinearGray16ToOtherGray16LUT(ICC_ColorSpace grayCS) { + if (lg16Toog16Map != null) { + short[] lg16Toog16LUT = (short []) lg16Toog16Map.get(grayCS); + if (lg16Toog16LUT != null) { + return lg16Toog16LUT; + } + } + short[] tmp = new short[65536]; + for (int i = 0; i <= 65535; i++) { + tmp[i] = (short) i; + } + ColorTransform[] transformList = new ColorTransform[2]; + PCMM mdl = CMSManager.getModule(); + ICC_ColorSpace lgCS = + (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_GRAY); + transformList[0] = mdl.createTransform ( + lgCS.getProfile(), ColorTransform.Any, ColorTransform.In); + transformList[1] = mdl.createTransform( + grayCS.getProfile(), ColorTransform.Any, ColorTransform.Out); + ColorTransform t = mdl.createTransform( + transformList); + short[] lg16Toog16LUT = t.colorConvert(tmp, null); + if (lg16Toog16Map == null) { + lg16Toog16Map = Collections.synchronizedMap(new WeakHashMap(2)); + } + lg16Toog16Map.put(grayCS, lg16Toog16LUT); + return lg16Toog16LUT; + } } diff --git a/sources/net.sf.j2s.java.core/src/java/awt/image/ComponentColorModel.java b/sources/net.sf.j2s.java.core/src/java/awt/image/ComponentColorModel.java index 98a039bc0..f0c93cc1c 100644 --- a/sources/net.sf.j2s.java.core/src/java/awt/image/ComponentColorModel.java +++ b/sources/net.sf.j2s.java.core/src/java/awt/image/ComponentColorModel.java @@ -30,6 +30,7 @@ import java.awt.color.ColorSpace; //import java.awt.color.ICC_ColorSpace; +import java.awt.color.ICC_ColorSpace; /** * A ColorModel class that works with pixel values that @@ -194,7 +195,7 @@ public class ComponentColorModel extends ColorModel { private byte[] tosRGB8LUT; private byte[] fromsRGB8LUT8; private short[] fromsRGB8LUT16; -// private byte[] fromLinearGray16ToOtherGray8LUT; + private byte[] fromLinearGray16ToOtherGray8LUT; private short[] fromLinearGray16ToOtherGray16LUT; private boolean needScaleInit; private boolean noUnnorm; @@ -288,13 +289,13 @@ public ComponentColorModel (ColorSpace colorSpace, signed = true; needScaleInit = true; break; -// case DataBuffer.TYPE_FLOAT: -// case DataBuffer.TYPE_DOUBLE: -// signed = true; -// needScaleInit = false; -// noUnnorm = true; -// nonStdScale = false; -// break; + case DataBuffer.TYPE_FLOAT: + case DataBuffer.TYPE_DOUBLE: + signed = true; + needScaleInit = false; + noUnnorm = true; + nonStdScale = false; + break; default: throw new IllegalArgumentException("This constructor is not "+ "compatible with transferType " + transferType); @@ -414,48 +415,48 @@ private void setupLUTs() { if (is_sRGB) { is_sRGB_stdScale = true; nonStdScale = false; -// } else if (ColorModel.isLinearRGBspace(colorSpace)) { -// // Note that the built-in Linear RGB space has a normalized -// // range of 0.0 - 1.0 for each coordinate. Usage of these -// // LUTs makes that assumption. -// is_LinearRGB_stdScale = true; -// nonStdScale = false; -// if (transferType == DataBuffer.TYPE_BYTE) { -// tosRGB8LUT = ColorModel.getLinearRGB8TosRGB8LUT(); -// fromsRGB8LUT8 = ColorModel.getsRGB8ToLinearRGB8LUT(); -// } else { -// tosRGB8LUT = ColorModel.getLinearRGB16TosRGB8LUT(); -// fromsRGB8LUT16 = ColorModel.getsRGB8ToLinearRGB16LUT(); -// } -// } else if ((colorSpaceType == ColorSpace.TYPE_GRAY) && -// (colorSpace instanceof ICC_ColorSpace) && -// (colorSpace.getMinValue(0) == 0.0f) && -// (colorSpace.getMaxValue(0) == 1.0f)) { -// // Note that a normalized range of 0.0 - 1.0 for the gray -// // component is required, because usage of these LUTs makes -// // that assumption. -// ICC_ColorSpace ics = (ICC_ColorSpace) colorSpace; -// is_ICCGray_stdScale = true; -// nonStdScale = false; -// fromsRGB8LUT16 = ColorModel.getsRGB8ToLinearRGB16LUT(); -// if (ColorModel.isLinearGRAYspace(ics)) { -// is_LinearGray_stdScale = true; -// if (transferType == DataBuffer.TYPE_BYTE) { -// tosRGB8LUT = ColorModel.getGray8TosRGB8LUT(ics); -// } else { -// tosRGB8LUT = ColorModel.getGray16TosRGB8LUT(ics); -// } -// } else { -// if (transferType == DataBuffer.TYPE_BYTE) { -// tosRGB8LUT = ColorModel.getGray8TosRGB8LUT(ics); -// fromLinearGray16ToOtherGray8LUT = -// ColorModel.getLinearGray16ToOtherGray8LUT(ics); -// } else { -// tosRGB8LUT = ColorModel.getGray16TosRGB8LUT(ics); -// fromLinearGray16ToOtherGray16LUT = -// ColorModel.getLinearGray16ToOtherGray16LUT(ics); -// } -// } + } else if (ColorModel.isLinearRGBspace(colorSpace)) { + // Note that the built-in Linear RGB space has a normalized + // range of 0.0 - 1.0 for each coordinate. Usage of these + // LUTs makes that assumption. + is_LinearRGB_stdScale = true; + nonStdScale = false; + if (transferType == DataBuffer.TYPE_BYTE) { + tosRGB8LUT = ColorModel.getLinearRGB8TosRGB8LUT(); + fromsRGB8LUT8 = ColorModel.getsRGB8ToLinearRGB8LUT(); + } else { + tosRGB8LUT = ColorModel.getLinearRGB16TosRGB8LUT(); + fromsRGB8LUT16 = ColorModel.getsRGB8ToLinearRGB16LUT(); + } + } else if ((colorSpaceType == ColorSpace.TYPE_GRAY) && + (colorSpace instanceof ICC_ColorSpace) && + (colorSpace.getMinValue(0) == 0.0f) && + (colorSpace.getMaxValue(0) == 1.0f)) { + // Note that a normalized range of 0.0 - 1.0 for the gray + // component is required, because usage of these LUTs makes + // that assumption. + ICC_ColorSpace ics = (ICC_ColorSpace) colorSpace; + is_ICCGray_stdScale = true; + nonStdScale = false; + fromsRGB8LUT16 = ColorModel.getsRGB8ToLinearRGB16LUT(); + if (ColorModel.isLinearGRAYspace(ics)) { + is_LinearGray_stdScale = true; + if (transferType == DataBuffer.TYPE_BYTE) { + tosRGB8LUT = ColorModel.getGray8TosRGB8LUT(ics); + } else { + tosRGB8LUT = ColorModel.getGray16TosRGB8LUT(ics); + } + } else { + if (transferType == DataBuffer.TYPE_BYTE) { + tosRGB8LUT = ColorModel.getGray8TosRGB8LUT(ics); + fromLinearGray16ToOtherGray8LUT = + ColorModel.getLinearGray16ToOtherGray8LUT(ics); + } else { + tosRGB8LUT = ColorModel.getGray16TosRGB8LUT(ics); + fromLinearGray16ToOtherGray16LUT = + ColorModel.getLinearGray16ToOtherGray16LUT(ics); + } + } } else if (needScaleInit) { // if transferType is byte, ushort, int, or short and we // don't already know the ColorSpace has minVlaue == 0.0f and @@ -822,34 +823,34 @@ private int extractComponent(Object inData, int idx, int precision) { return (int) ((sdata[idx] / 32767.0f) * scalefactor + 0.5f); } } -// case DataBuffer.TYPE_FLOAT: { -// float fdata[] = (float[]) inData; -// float scalefactor = (float) ((1 << precision) - 1); -// if (needAlpha) { -// float f = fdata[numColorComponents]; -// if (f != 0.0f) { -// return (int) (((fdata[idx] / f) * scalefactor) + 0.5f); -// } else { -// return 0; -// } -// } else { -// return (int) (fdata[idx] * scalefactor + 0.5f); -// } -// } -// case DataBuffer.TYPE_DOUBLE: { -// double ddata[] = (double[]) inData; -// double scalefactor = (double) ((1 << precision) - 1); -// if (needAlpha) { -// double d = ddata[numColorComponents]; -// if (d != 0.0) { -// return (int) (((ddata[idx] / d) * scalefactor) + 0.5); -// } else { -// return 0; -// } -// } else { -// return (int) (ddata[idx] * scalefactor + 0.5); -// } -// } + case DataBuffer.TYPE_FLOAT: { + float fdata[] = (float[]) inData; + float scalefactor = (float) ((1 << precision) - 1); + if (needAlpha) { + float f = fdata[numColorComponents]; + if (f != 0.0f) { + return (int) (((fdata[idx] / f) * scalefactor) + 0.5f); + } else { + return 0; + } + } else { + return (int) (fdata[idx] * scalefactor + 0.5f); + } + } + case DataBuffer.TYPE_DOUBLE: { + double ddata[] = (double[]) inData; + double scalefactor = (double) ((1 << precision) - 1); + if (needAlpha) { + double d = ddata[numColorComponents]; + if (d != 0.0) { + return (int) (((ddata[idx] / d) * scalefactor) + 0.5); + } else { + return 0; + } + } else { + return (int) (ddata[idx] * scalefactor + 0.5); + } + } case DataBuffer.TYPE_BYTE: byte bdata[] = (byte[])inData; comp = bdata[idx] & mask; @@ -1067,14 +1068,14 @@ public int getAlpha(Object inData) { short sdata[] = (short[])inData; alpha = (int) ((sdata[aIdx] / 32767.0f) * 255.0f + 0.5f); return alpha; -// case DataBuffer.TYPE_FLOAT: -// float fdata[] = (float[])inData; -// alpha = (int) (fdata[aIdx] * 255.0f + 0.5f); -// return alpha; -// case DataBuffer.TYPE_DOUBLE: -// double ddata[] = (double[])inData; -// alpha = (int) (ddata[aIdx] * 255.0 + 0.5); -// return alpha; + case DataBuffer.TYPE_FLOAT: + float fdata[] = (float[])inData; + alpha = (int) (fdata[aIdx] * 255.0f + 0.5f); + return alpha; + case DataBuffer.TYPE_DOUBLE: + double ddata[] = (double[])inData; + alpha = (int) (ddata[aIdx] * 255.0 + 0.5); + return alpha; case DataBuffer.TYPE_BYTE: byte bdata[] = (byte[])inData; alpha = bdata[aIdx] & mask; @@ -1310,168 +1311,168 @@ public Object getDataElements(int rgb, Object pixel) { } return sdata; } -// case DataBuffer.TYPE_FLOAT: -// { -// float fdata[]; -// if (pixel == null) { -// fdata = new float[numComponents]; -// } else { -// fdata = (float[])pixel; -// } -// float factor; -// if (is_sRGB_stdScale || is_LinearRGB_stdScale) { -// if (is_LinearRGB_stdScale) { -// red = fromsRGB8LUT16[red] & 0xffff; -// grn = fromsRGB8LUT16[grn] & 0xffff; -// blu = fromsRGB8LUT16[blu] & 0xffff; -// factor = 1.0f / 65535.0f; -// } else { -// factor = 1.0f / 255.0f; -// } -// if (supportsAlpha) { -// alp = (rgb>>24) & 0xff; -// fdata[3] = alp * (1.0f / 255.0f); -// if (isAlphaPremultiplied) { -// factor *= fdata[3]; -// } -// } -// fdata[0] = red * factor; -// fdata[1] = grn * factor; -// fdata[2] = blu * factor; -// } else if (is_LinearGray_stdScale) { -// red = fromsRGB8LUT16[red] & 0xffff; -// grn = fromsRGB8LUT16[grn] & 0xffff; -// blu = fromsRGB8LUT16[blu] & 0xffff; -// fdata[0] = ((0.2125f * red) + -// (0.7154f * grn) + -// (0.0721f * blu)) / 65535.0f; -// if (supportsAlpha) { -// alp = (rgb>>24) & 0xff; -// fdata[1] = alp * (1.0f / 255.0f); -// if (isAlphaPremultiplied) { -// fdata[0] *= fdata[1]; -// } -// } -// } else if (is_ICCGray_stdScale) { -// red = fromsRGB8LUT16[red] & 0xffff; -// grn = fromsRGB8LUT16[grn] & 0xffff; -// blu = fromsRGB8LUT16[blu] & 0xffff; -// int gray = (int) ((0.2125f * red) + -// (0.7154f * grn) + -// (0.0721f * blu) + 0.5f); -// fdata[0] = (fromLinearGray16ToOtherGray16LUT[gray] & -// 0xffff) / 65535.0f; -// if (supportsAlpha) { -// alp = (rgb>>24) & 0xff; -// fdata[1] = alp * (1.0f / 255.0f); -// if (isAlphaPremultiplied) { -// fdata[0] *= fdata[1]; -// } -// } -// } else { -// float norm[] = new float[3]; -// factor = 1.0f / 255.0f; -// norm[0] = red * factor; -// norm[1] = grn * factor; -// norm[2] = blu * factor; -// norm = colorSpace.fromRGB(norm); -// if (supportsAlpha) { -// alp = (rgb>>24) & 0xff; -// fdata[numColorComponents] = alp * factor; -// if (isAlphaPremultiplied) { -// factor *= alp; -// for (int i = 0; i < numColorComponents; i++) { -// norm[i] *= factor; -// } -// } -// } -// for (int i = 0; i < numColorComponents; i++) { -// fdata[i] = norm[i]; -// } -// } -// return fdata; -// } -// case DataBuffer.TYPE_DOUBLE: -// { -// double ddata[]; -// if (pixel == null) { -// ddata = new double[numComponents]; -// } else { -// ddata = (double[])pixel; -// } -// if (is_sRGB_stdScale || is_LinearRGB_stdScale) { -// double factor; -// if (is_LinearRGB_stdScale) { -// red = fromsRGB8LUT16[red] & 0xffff; -// grn = fromsRGB8LUT16[grn] & 0xffff; -// blu = fromsRGB8LUT16[blu] & 0xffff; -// factor = 1.0 / 65535.0; -// } else { -// factor = 1.0 / 255.0; -// } -// if (supportsAlpha) { -// alp = (rgb>>24) & 0xff; -// ddata[3] = alp * (1.0 / 255.0); -// if (isAlphaPremultiplied) { -// factor *= ddata[3]; -// } -// } -// ddata[0] = red * factor; -// ddata[1] = grn * factor; -// ddata[2] = blu * factor; -// } else if (is_LinearGray_stdScale) { -// red = fromsRGB8LUT16[red] & 0xffff; -// grn = fromsRGB8LUT16[grn] & 0xffff; -// blu = fromsRGB8LUT16[blu] & 0xffff; -// ddata[0] = ((0.2125 * red) + -// (0.7154 * grn) + -// (0.0721 * blu)) / 65535.0; -// if (supportsAlpha) { -// alp = (rgb>>24) & 0xff; -// ddata[1] = alp * (1.0 / 255.0); -// if (isAlphaPremultiplied) { -// ddata[0] *= ddata[1]; -// } -// } -// } else if (is_ICCGray_stdScale) { -// red = fromsRGB8LUT16[red] & 0xffff; -// grn = fromsRGB8LUT16[grn] & 0xffff; -// blu = fromsRGB8LUT16[blu] & 0xffff; -// int gray = (int) ((0.2125f * red) + -// (0.7154f * grn) + -// (0.0721f * blu) + 0.5f); -// ddata[0] = (fromLinearGray16ToOtherGray16LUT[gray] & -// 0xffff) / 65535.0; -// if (supportsAlpha) { -// alp = (rgb>>24) & 0xff; -// ddata[1] = alp * (1.0 / 255.0); -// if (isAlphaPremultiplied) { -// ddata[0] *= ddata[1]; -// } -// } -// } else { -// float factor = 1.0f / 255.0f; -// float norm[] = new float[3]; -// norm[0] = red * factor; -// norm[1] = grn * factor; -// norm[2] = blu * factor; -// norm = colorSpace.fromRGB(norm); -// if (supportsAlpha) { -// alp = (rgb>>24) & 0xff; -// ddata[numColorComponents] = alp * (1.0 / 255.0); -// if (isAlphaPremultiplied) { -// factor *= alp; -// for (int i = 0; i < numColorComponents; i++) { -// norm[i] *= factor; -// } -// } -// } -// for (int i = 0; i < numColorComponents; i++) { -// ddata[i] = norm[i]; -// } -// } -// return ddata; -// } + case DataBuffer.TYPE_FLOAT: + { + float fdata[]; + if (pixel == null) { + fdata = new float[numComponents]; + } else { + fdata = (float[])pixel; + } + float factor; + if (is_sRGB_stdScale || is_LinearRGB_stdScale) { + if (is_LinearRGB_stdScale) { + red = fromsRGB8LUT16[red] & 0xffff; + grn = fromsRGB8LUT16[grn] & 0xffff; + blu = fromsRGB8LUT16[blu] & 0xffff; + factor = 1.0f / 65535.0f; + } else { + factor = 1.0f / 255.0f; + } + if (supportsAlpha) { + alp = (rgb>>24) & 0xff; + fdata[3] = alp * (1.0f / 255.0f); + if (isAlphaPremultiplied) { + factor *= fdata[3]; + } + } + fdata[0] = red * factor; + fdata[1] = grn * factor; + fdata[2] = blu * factor; + } else if (is_LinearGray_stdScale) { + red = fromsRGB8LUT16[red] & 0xffff; + grn = fromsRGB8LUT16[grn] & 0xffff; + blu = fromsRGB8LUT16[blu] & 0xffff; + fdata[0] = ((0.2125f * red) + + (0.7154f * grn) + + (0.0721f * blu)) / 65535.0f; + if (supportsAlpha) { + alp = (rgb>>24) & 0xff; + fdata[1] = alp * (1.0f / 255.0f); + if (isAlphaPremultiplied) { + fdata[0] *= fdata[1]; + } + } + } else if (is_ICCGray_stdScale) { + red = fromsRGB8LUT16[red] & 0xffff; + grn = fromsRGB8LUT16[grn] & 0xffff; + blu = fromsRGB8LUT16[blu] & 0xffff; + int gray = (int) ((0.2125f * red) + + (0.7154f * grn) + + (0.0721f * blu) + 0.5f); + fdata[0] = (fromLinearGray16ToOtherGray16LUT[gray] & + 0xffff) / 65535.0f; + if (supportsAlpha) { + alp = (rgb>>24) & 0xff; + fdata[1] = alp * (1.0f / 255.0f); + if (isAlphaPremultiplied) { + fdata[0] *= fdata[1]; + } + } + } else { + float norm[] = new float[3]; + factor = 1.0f / 255.0f; + norm[0] = red * factor; + norm[1] = grn * factor; + norm[2] = blu * factor; + norm = colorSpace.fromRGB(norm); + if (supportsAlpha) { + alp = (rgb>>24) & 0xff; + fdata[numColorComponents] = alp * factor; + if (isAlphaPremultiplied) { + factor *= alp; + for (int i = 0; i < numColorComponents; i++) { + norm[i] *= factor; + } + } + } + for (int i = 0; i < numColorComponents; i++) { + fdata[i] = norm[i]; + } + } + return fdata; + } + case DataBuffer.TYPE_DOUBLE: + { + double ddata[]; + if (pixel == null) { + ddata = new double[numComponents]; + } else { + ddata = (double[])pixel; + } + if (is_sRGB_stdScale || is_LinearRGB_stdScale) { + double factor; + if (is_LinearRGB_stdScale) { + red = fromsRGB8LUT16[red] & 0xffff; + grn = fromsRGB8LUT16[grn] & 0xffff; + blu = fromsRGB8LUT16[blu] & 0xffff; + factor = 1.0 / 65535.0; + } else { + factor = 1.0 / 255.0; + } + if (supportsAlpha) { + alp = (rgb>>24) & 0xff; + ddata[3] = alp * (1.0 / 255.0); + if (isAlphaPremultiplied) { + factor *= ddata[3]; + } + } + ddata[0] = red * factor; + ddata[1] = grn * factor; + ddata[2] = blu * factor; + } else if (is_LinearGray_stdScale) { + red = fromsRGB8LUT16[red] & 0xffff; + grn = fromsRGB8LUT16[grn] & 0xffff; + blu = fromsRGB8LUT16[blu] & 0xffff; + ddata[0] = ((0.2125 * red) + + (0.7154 * grn) + + (0.0721 * blu)) / 65535.0; + if (supportsAlpha) { + alp = (rgb>>24) & 0xff; + ddata[1] = alp * (1.0 / 255.0); + if (isAlphaPremultiplied) { + ddata[0] *= ddata[1]; + } + } + } else if (is_ICCGray_stdScale) { + red = fromsRGB8LUT16[red] & 0xffff; + grn = fromsRGB8LUT16[grn] & 0xffff; + blu = fromsRGB8LUT16[blu] & 0xffff; + int gray = (int) ((0.2125f * red) + + (0.7154f * grn) + + (0.0721f * blu) + 0.5f); + ddata[0] = (fromLinearGray16ToOtherGray16LUT[gray] & + 0xffff) / 65535.0; + if (supportsAlpha) { + alp = (rgb>>24) & 0xff; + ddata[1] = alp * (1.0 / 255.0); + if (isAlphaPremultiplied) { + ddata[0] *= ddata[1]; + } + } + } else { + float factor = 1.0f / 255.0f; + float norm[] = new float[3]; + norm[0] = red * factor; + norm[1] = grn * factor; + norm[2] = blu * factor; + norm = colorSpace.fromRGB(norm); + if (supportsAlpha) { + alp = (rgb>>24) & 0xff; + ddata[numColorComponents] = alp * (1.0 / 255.0); + if (isAlphaPremultiplied) { + factor *= alp; + for (int i = 0; i < numColorComponents; i++) { + norm[i] *= factor; + } + } + } + for (int i = 0; i < numColorComponents; i++) { + ddata[i] = norm[i]; + } + } + return ddata; + } } } @@ -2268,49 +2269,49 @@ public Object getDataElements(float[] normComponents, int normOffset, } } return spixel; -// case DataBuffer.TYPE_FLOAT: -// float[] fpixel; -// if (obj == null) { -// fpixel = new float[numComponents]; -// } else { -// fpixel = (float[]) obj; -// } -// if (needAlpha) { -// float alpha = normComponents[numColorComponents + normOffset]; -// for (int c = 0, nc = normOffset; c < numColorComponents; -// c++, nc++) { -// fpixel[c] = normComponents[nc] * alpha; -// } -// fpixel[numColorComponents] = alpha; -// } else { -// for (int c = 0, nc = normOffset; c < numComponents; -// c++, nc++) { -// fpixel[c] = normComponents[nc]; -// } -// } -// return fpixel; -// case DataBuffer.TYPE_DOUBLE: -// double[] dpixel; -// if (obj == null) { -// dpixel = new double[numComponents]; -// } else { -// dpixel = (double[]) obj; -// } -// if (needAlpha) { -// double alpha = -// (double) (normComponents[numColorComponents + normOffset]); -// for (int c = 0, nc = normOffset; c < numColorComponents; -// c++, nc++) { -// dpixel[c] = normComponents[nc] * alpha; -// } -// dpixel[numColorComponents] = alpha; -// } else { -// for (int c = 0, nc = normOffset; c < numComponents; -// c++, nc++) { -// dpixel[c] = (double) normComponents[nc]; -// } -// } -// return dpixel; + case DataBuffer.TYPE_FLOAT: + float[] fpixel; + if (obj == null) { + fpixel = new float[numComponents]; + } else { + fpixel = (float[]) obj; + } + if (needAlpha) { + float alpha = normComponents[numColorComponents + normOffset]; + for (int c = 0, nc = normOffset; c < numColorComponents; + c++, nc++) { + fpixel[c] = normComponents[nc] * alpha; + } + fpixel[numColorComponents] = alpha; + } else { + for (int c = 0, nc = normOffset; c < numComponents; + c++, nc++) { + fpixel[c] = normComponents[nc]; + } + } + return fpixel; + case DataBuffer.TYPE_DOUBLE: + double[] dpixel; + if (obj == null) { + dpixel = new double[numComponents]; + } else { + dpixel = (double[]) obj; + } + if (needAlpha) { + double alpha = + (double) (normComponents[numColorComponents + normOffset]); + for (int c = 0, nc = normOffset; c < numColorComponents; + c++, nc++) { + dpixel[c] = normComponents[nc] * alpha; + } + dpixel[numColorComponents] = alpha; + } else { + for (int c = 0, nc = normOffset; c < numComponents; + c++, nc++) { + dpixel[c] = (double) normComponents[nc]; + } + } + return dpixel; default: throw new UnsupportedOperationException("This method has not been "+ "implemented for transferType " + @@ -2397,18 +2398,18 @@ public float[] getNormalizedComponents(Object pixel, normComponents[nc] = ((float) spixel[c]) / 32767.0f; } break; -// case DataBuffer.TYPE_FLOAT: -// float[] fpixel = (float[]) pixel; -// for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) { -// normComponents[nc] = fpixel[c]; -// } -// break; -// case DataBuffer.TYPE_DOUBLE: -// double[] dpixel = (double[]) pixel; -// for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) { -// normComponents[nc] = (float) dpixel[c]; -// } -// break; + case DataBuffer.TYPE_FLOAT: + float[] fpixel = (float[]) pixel; + for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) { + normComponents[nc] = fpixel[c]; + } + break; + case DataBuffer.TYPE_DOUBLE: + double[] dpixel = (double[]) pixel; + for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) { + normComponents[nc] = (float) dpixel[c]; + } + break; default: throw new UnsupportedOperationException("This method has not been "+ "implemented for transferType " + @@ -2598,56 +2599,56 @@ public ColorModel coerceData (WritableRaster raster, } } break; -// case DataBuffer.TYPE_FLOAT: { -// float pixel[] = null; -// float zpixel[] = null; -// for (int y = 0; y < h; y++, rY++) { -// rX = rminX; -// for (int x = 0; x < w; x++, rX++) { -// pixel = (float[]) raster.getDataElements(rX, rY, -// pixel); -// normAlpha = pixel[aIdx]; -// if (normAlpha != 0.0f) { -// for (int c=0; c < aIdx; c++) { -// pixel[c] *= normAlpha; -// } -// raster.setDataElements(rX, rY, pixel); -// } else { -// if (zpixel == null) { -// zpixel = new float[numComponents]; -// java.util.Arrays.fill(zpixel, 0.0f); -// } -// raster.setDataElements(rX, rY, zpixel); -// } -// } -// } -// } -// break; -// case DataBuffer.TYPE_DOUBLE: { -// double pixel[] = null; -// double zpixel[] = null; -// for (int y = 0; y < h; y++, rY++) { -// rX = rminX; -// for (int x = 0; x < w; x++, rX++) { -// pixel = (double[]) raster.getDataElements(rX, rY, -// pixel); -// double dnormAlpha = pixel[aIdx]; -// if (dnormAlpha != 0.0) { -// for (int c=0; c < aIdx; c++) { -// pixel[c] *= dnormAlpha; -// } -// raster.setDataElements(rX, rY, pixel); -// } else { -// if (zpixel == null) { -// zpixel = new double[numComponents]; -// java.util.Arrays.fill(zpixel, 0.0); -// } -// raster.setDataElements(rX, rY, zpixel); -// } -// } -// } -// } -// break; + case DataBuffer.TYPE_FLOAT: { + float pixel[] = null; + float zpixel[] = null; + for (int y = 0; y < h; y++, rY++) { + rX = rminX; + for (int x = 0; x < w; x++, rX++) { + pixel = (float[]) raster.getDataElements(rX, rY, + pixel); + normAlpha = pixel[aIdx]; + if (normAlpha != 0.0f) { + for (int c=0; c < aIdx; c++) { + pixel[c] *= normAlpha; + } + raster.setDataElements(rX, rY, pixel); + } else { + if (zpixel == null) { + zpixel = new float[numComponents]; + java.util.Arrays.fill(zpixel, 0.0f); + } + raster.setDataElements(rX, rY, zpixel); + } + } + } + } + break; + case DataBuffer.TYPE_DOUBLE: { + double pixel[] = null; + double zpixel[] = null; + for (int y = 0; y < h; y++, rY++) { + rX = rminX; + for (int x = 0; x < w; x++, rX++) { + pixel = (double[]) raster.getDataElements(rX, rY, + pixel); + double dnormAlpha = pixel[aIdx]; + if (dnormAlpha != 0.0) { + for (int c=0; c < aIdx; c++) { + pixel[c] *= dnormAlpha; + } + raster.setDataElements(rX, rY, pixel); + } else { + if (zpixel == null) { + zpixel = new double[numComponents]; + java.util.Arrays.fill(zpixel, 0.0); + } + raster.setDataElements(rX, rY, zpixel); + } + } + } + } + break; default: throw new UnsupportedOperationException("This method has not been "+ "implemented for transferType " + transferType); @@ -2740,44 +2741,44 @@ public ColorModel coerceData (WritableRaster raster, } } break; -// case DataBuffer.TYPE_FLOAT: { -// float pixel[] = null; -// for (int y = 0; y < h; y++, rY++) { -// rX = rminX; -// for (int x = 0; x < w; x++, rX++) { -// pixel = (float[])raster.getDataElements(rX, rY, -// pixel); -// normAlpha = pixel[aIdx]; -// if (normAlpha != 0.0f) { -// float invAlpha = 1.0f / normAlpha; -// for (int c=0; c < aIdx; c++) { -// pixel[c] *= invAlpha; -// } -// raster.setDataElements(rX, rY, pixel); -// } -// } -// } -// } -// break; -// case DataBuffer.TYPE_DOUBLE: { -// double pixel[] = null; -// for (int y = 0; y < h; y++, rY++) { -// rX = rminX; -// for (int x = 0; x < w; x++, rX++) { -// pixel = (double[])raster.getDataElements(rX, rY, -// pixel); -// double dnormAlpha = pixel[aIdx]; -// if (dnormAlpha != 0.0) { -// double invAlpha = 1.0 / dnormAlpha; -// for (int c=0; c < aIdx; c++) { -// pixel[c] *= invAlpha; -// } -// raster.setDataElements(rX, rY, pixel); -// } -// } -// } -// } -// break; + case DataBuffer.TYPE_FLOAT: { + float pixel[] = null; + for (int y = 0; y < h; y++, rY++) { + rX = rminX; + for (int x = 0; x < w; x++, rX++) { + pixel = (float[])raster.getDataElements(rX, rY, + pixel); + normAlpha = pixel[aIdx]; + if (normAlpha != 0.0f) { + float invAlpha = 1.0f / normAlpha; + for (int c=0; c < aIdx; c++) { + pixel[c] *= invAlpha; + } + raster.setDataElements(rX, rY, pixel); + } + } + } + } + break; + case DataBuffer.TYPE_DOUBLE: { + double pixel[] = null; + for (int y = 0; y < h; y++, rY++) { + rX = rminX; + for (int x = 0; x < w; x++, rX++) { + pixel = (double[])raster.getDataElements(rX, rY, + pixel); + double dnormAlpha = pixel[aIdx]; + if (dnormAlpha != 0.0) { + double invAlpha = 1.0 / dnormAlpha; + for (int c=0; c < aIdx; c++) { + pixel[c] *= invAlpha; + } + raster.setDataElements(rX, rY, pixel); + } + } + } + } + break; default: throw new UnsupportedOperationException("This method has not been "+ "implemented for transferType " + transferType); diff --git a/sources/net.sf.j2s.java.core/src/java/awt/image/DirectColorModel.java b/sources/net.sf.j2s.java.core/src/java/awt/image/DirectColorModel.java index dac1451e6..4a1179bb0 100644 --- a/sources/net.sf.j2s.java.core/src/java/awt/image/DirectColorModel.java +++ b/sources/net.sf.j2s.java.core/src/java/awt/image/DirectColorModel.java @@ -114,14 +114,14 @@ public class DirectColorModel extends PackedColorModel { private int green_mask; private int blue_mask; private int alpha_mask; -// private int red_offset; -// private int green_offset; -// private int blue_offset; -// private int alpha_offset; -// private int red_scale; -// private int green_scale; -// private int blue_scale; -// private int alpha_scale; + private int red_offset; + private int green_offset; + private int blue_offset; + private int alpha_offset; + private int red_scale; + private int green_scale; + private int blue_scale; + private int alpha_scale; private boolean is_LinearRGB; private int lRGBprecision; private byte[] tosRGB8LUT; @@ -186,7 +186,7 @@ public DirectColorModel(int bits, int rmask, int gmask, bits, rmask, gmask, bmask, amask, false, amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT, ColorModel.getDefaultTransferType(bits)); - // SwingJS setFields(); + setFields(); } /** @@ -511,10 +511,10 @@ public int getRed(Object inData) { byte bdata[] = (byte[])inData; pixel = bdata[0] & 0xff; break; -// case DataBuffer.TYPE_USHORT: -// short sdata[] = (short[])inData; -// pixel = sdata[0] & 0xffff; -// break; + case DataBuffer.TYPE_USHORT: + short sdata[] = (short[])inData; + pixel = sdata[0] & 0xffff; + break; case DataBuffer.TYPE_INT: int idata[] = (int[])inData; pixel = idata[0]; @@ -565,10 +565,10 @@ public int getGreen(Object inData) { byte bdata[] = (byte[])inData; pixel = bdata[0] & 0xff; break; -// case DataBuffer.TYPE_USHORT: -// short sdata[] = (short[])inData; -// pixel = sdata[0] & 0xffff; -// break; + case DataBuffer.TYPE_USHORT: + short sdata[] = (short[])inData; + pixel = sdata[0] & 0xffff; + break; case DataBuffer.TYPE_INT: int idata[] = (int[])inData; pixel = idata[0]; @@ -619,10 +619,10 @@ public int getBlue(Object inData) { byte bdata[] = (byte[])inData; pixel = bdata[0] & 0xff; break; -// case DataBuffer.TYPE_USHORT: -// short sdata[] = (short[])inData; -// pixel = sdata[0] & 0xffff; -// break; + case DataBuffer.TYPE_USHORT: + short sdata[] = (short[])inData; + pixel = sdata[0] & 0xffff; + break; case DataBuffer.TYPE_INT: int idata[] = (int[])inData; pixel = idata[0]; @@ -670,10 +670,10 @@ public int getAlpha(Object inData) { byte bdata[] = (byte[])inData; pixel = bdata[0] & 0xff; break; -// case DataBuffer.TYPE_USHORT: -// short sdata[] = (short[])inData; -// pixel = sdata[0] & 0xffff; -// break; + case DataBuffer.TYPE_USHORT: + short sdata[] = (short[])inData; + pixel = sdata[0] & 0xffff; + break; case DataBuffer.TYPE_INT: int idata[] = (int[])inData; pixel = idata[0]; @@ -719,10 +719,10 @@ public int getRGB(Object inData) { byte bdata[] = (byte[])inData; pixel = bdata[0] & 0xff; break; -// case DataBuffer.TYPE_USHORT: -// short sdata[] = (short[])inData; -// pixel = sdata[0] & 0xffff; -// break; + case DataBuffer.TYPE_USHORT: + short sdata[] = (short[])inData; + pixel = sdata[0] & 0xffff; + break; case DataBuffer.TYPE_INT: int idata[] = (int[])inData; pixel = idata[0]; @@ -899,16 +899,16 @@ public Object getDataElements(int rgb, Object pixel) { bdata[0] = (byte)(0xff&intpixel[0]); return bdata; } -// case DataBuffer.TYPE_USHORT:{ -// short sdata[]; -// if (pixel == null) { -// sdata = new short[1]; -// } else { -// sdata = (short[])pixel; -// } -// sdata[0] = (short)(intpixel[0]&0xffff); -// return sdata; -// } + case DataBuffer.TYPE_USHORT:{ + short sdata[]; + if (pixel == null) { + sdata = new short[1]; + } else { + sdata = (short[])pixel; + } + sdata[0] = (short)(intpixel[0]&0xffff); + return sdata; + } case DataBuffer.TYPE_INT: return intpixel; } @@ -998,10 +998,10 @@ final public int[] getComponents(Object pixel, int[] components, byte bdata[] = (byte[])pixel; intpixel = bdata[0] & 0xff; break; -// case DataBuffer.TYPE_USHORT: -// short sdata[] = (short[])pixel; -// intpixel = sdata[0] & 0xffff; -// break; + case DataBuffer.TYPE_USHORT: + short sdata[] = (short[])pixel; + intpixel = sdata[0] & 0xffff; + break; case DataBuffer.TYPE_INT: int idata[] = (int[])pixel; intpixel = idata[0]; @@ -1045,14 +1045,14 @@ final public WritableRaster createCompatibleWritableRaster (int w, bandmasks[1] = green_mask; bandmasks[2] = blue_mask; - if (pixel_bits > 8) {// SwingJS 16) { + if (pixel_bits > 16) { return Raster.createPackedRaster(DataBuffer.TYPE_INT, w,h,bandmasks,null); } -// else if (pixel_bits > 8) { -// return Raster.createPackedRaster(DataBuffer.TYPE_USHORT, -// w,h,bandmasks,null); -// } + else if (pixel_bits > 8) { + return Raster.createPackedRaster(DataBuffer.TYPE_USHORT, + w,h,bandmasks,null); + } else { return Raster.createPackedRaster(DataBuffer.TYPE_BYTE, w,h,bandmasks,null); @@ -1144,15 +1144,15 @@ public Object getDataElements(int[] components, int offset, Object obj) { byte bdata[] = {(byte)(pixel&0xff)}; return bdata; } -// case DataBuffer.TYPE_USHORT: -// if (obj instanceof short[]) { -// short sdata[] = (short[])obj; -// sdata[0] = (short)(pixel&0xffff); -// return sdata; -// } else { -// short sdata[] = {(short)(pixel&0xffff)}; -// return sdata; -// } + case DataBuffer.TYPE_USHORT: + if (obj instanceof short[]) { + short sdata[] = (short[])obj; + sdata[0] = (short)(pixel&0xffff); + return sdata; + } else { + short sdata[] = {(short)(pixel&0xffff)}; + return sdata; + } case DataBuffer.TYPE_INT: if (obj instanceof int[]) { int idata[] = (int[])obj; @@ -1168,256 +1168,256 @@ public Object getDataElements(int[] components, int offset, Object obj) { } } -// /** -// * Forces the raster data to match the state specified in the -// * isAlphaPremultiplied variable, assuming the data is -// * currently correctly described by this ColorModel. It -// * may multiply or divide the color raster data by alpha, or do -// * nothing if the data is in the correct state. If the data needs to -// * be coerced, this method will also return an instance of this -// * ColorModel with the isAlphaPremultiplied -// * flag set appropriately. This method will throw a -// * UnsupportedOperationException if this transferType is -// * not supported by this ColorModel. Since -// * ColorModel can be subclassed, subclasses inherit the -// * implementation of this method and if they don't override it then -// * they throw an exception if they use an unsupported transferType. -// * -// * @param raster the WritableRaster data -// * @param isAlphaPremultiplied true if the alpha is -// * premultiplied; false otherwise -// * @return a ColorModel object that represents the -// * coerced data. -// * @exception UnsupportedOperationException if this -// * transferType is not supported by this -// * color model -// */ -// final public ColorModel coerceData (WritableRaster raster, -// boolean isAlphaPremultiplied) -// { -// if (!supportsAlpha || -// this.isAlphaPremultiplied() == isAlphaPremultiplied) { -// return this; -// } -// -// int w = raster.getWidth(); -// int h = raster.getHeight(); -// int aIdx = numColorComponents; -// float normAlpha; -// float alphaScale = 1.0f / ((float) ((1 << nBits[aIdx]) - 1)); -// -// int rminX = raster.getMinX(); -// int rY = raster.getMinY(); -// int rX; -// int pixel[] = null; -// int zpixel[] = null; -// -// if (isAlphaPremultiplied) { -// // Must mean that we are currently not premultiplied so -// // multiply by alpha -// switch (transferType) { -// case DataBuffer.TYPE_BYTE: { -// for (int y = 0; y < h; y++, rY++) { -// rX = rminX; -// for (int x = 0; x < w; x++, rX++) { -// pixel = raster.getPixel(rX, rY, pixel); -// normAlpha = pixel[aIdx] * alphaScale; -// if (normAlpha != 0.f) { -// for (int c=0; c < aIdx; c++) { -// pixel[c] = (int) (pixel[c] * normAlpha + -// 0.5f); -// } -// raster.setPixel(rX, rY, pixel); -// } else { -// if (zpixel == null) { -// zpixel = new int[numComponents]; -// java.util.Arrays.fill(zpixel, 0); -// } -// raster.setPixel(rX, rY, zpixel); -// } -// } -// } -// } -// break; -// case DataBuffer.TYPE_USHORT: { -// for (int y = 0; y < h; y++, rY++) { -// rX = rminX; -// for (int x = 0; x < w; x++, rX++) { -// pixel = raster.getPixel(rX, rY, pixel); -// normAlpha = pixel[aIdx] * alphaScale; -// if (normAlpha != 0.f) { -// for (int c=0; c < aIdx; c++) { -// pixel[c] = (int) (pixel[c] * normAlpha + -// 0.5f); -// } -// raster.setPixel(rX, rY, pixel); -// } else { -// if (zpixel == null) { -// zpixel = new int[numComponents]; -// java.util.Arrays.fill(zpixel, 0); -// } -// raster.setPixel(rX, rY, zpixel); -// } -// } -// } -// } -// break; -// case DataBuffer.TYPE_INT: { -// for (int y = 0; y < h; y++, rY++) { -// rX = rminX; -// for (int x = 0; x < w; x++, rX++) { -// pixel = raster.getPixel(rX, rY, pixel); -// normAlpha = pixel[aIdx] * alphaScale; -// if (normAlpha != 0.f) { -// for (int c=0; c < aIdx; c++) { -// pixel[c] = (int) (pixel[c] * normAlpha + -// 0.5f); -// } -// raster.setPixel(rX, rY, pixel); -// } else { -// if (zpixel == null) { -// zpixel = new int[numComponents]; -// java.util.Arrays.fill(zpixel, 0); -// } -// raster.setPixel(rX, rY, zpixel); -// } -// } -// } -// } -// break; -// default: -// throw new UnsupportedOperationException("This method has not been "+ -// "implemented for transferType " + transferType); -// } -// } -// else { -// // We are premultiplied and want to divide it out -// switch (transferType) { -// case DataBuffer.TYPE_BYTE: { -// for (int y = 0; y < h; y++, rY++) { -// rX = rminX; -// for (int x = 0; x < w; x++, rX++) { -// pixel = raster.getPixel(rX, rY, pixel); -// normAlpha = pixel[aIdx] * alphaScale; -// if (normAlpha != 0.0f) { -// float invAlpha = 1.0f / normAlpha; -// for (int c=0; c < aIdx; c++) { -// pixel[c] = (int) (pixel[c] * invAlpha + -// 0.5f); -// } -// raster.setPixel(rX, rY, pixel); -// } -// } -// } -// } -// break; -// case DataBuffer.TYPE_USHORT: { -// for (int y = 0; y < h; y++, rY++) { -// rX = rminX; -// for (int x = 0; x < w; x++, rX++) { -// pixel = raster.getPixel(rX, rY, pixel); -// normAlpha = pixel[aIdx] * alphaScale; -// if (normAlpha != 0) { -// float invAlpha = 1.0f / normAlpha; -// for (int c=0; c < aIdx; c++) { -// pixel[c] = (int) (pixel[c] * invAlpha + -// 0.5f); -// } -// raster.setPixel(rX, rY, pixel); -// } -// } -// } -// } -// break; -// case DataBuffer.TYPE_INT: { -// for (int y = 0; y < h; y++, rY++) { -// rX = rminX; -// for (int x = 0; x < w; x++, rX++) { -// pixel = raster.getPixel(rX, rY, pixel); -// normAlpha = pixel[aIdx] * alphaScale; -// if (normAlpha != 0) { -// float invAlpha = 1.0f / normAlpha; -// for (int c=0; c < aIdx; c++) { -// pixel[c] = (int) (pixel[c] * invAlpha + -// 0.5f); -// } -// raster.setPixel(rX, rY, pixel); -// } -// } -// } -// } -// break; -// default: -// throw new UnsupportedOperationException("This method has not been "+ -// "implemented for transferType " + transferType); -// } -// } -// -// // Return a new color model -// return new DirectColorModel(colorSpace, pixel_bits, maskArray[0], -// maskArray[1], maskArray[2], maskArray[3], -// isAlphaPremultiplied, -// transferType); -// -// } + /** + * Forces the raster data to match the state specified in the + * isAlphaPremultiplied variable, assuming the data is + * currently correctly described by this ColorModel. It + * may multiply or divide the color raster data by alpha, or do + * nothing if the data is in the correct state. If the data needs to + * be coerced, this method will also return an instance of this + * ColorModel with the isAlphaPremultiplied + * flag set appropriately. This method will throw a + * UnsupportedOperationException if this transferType is + * not supported by this ColorModel. Since + * ColorModel can be subclassed, subclasses inherit the + * implementation of this method and if they don't override it then + * they throw an exception if they use an unsupported transferType. + * + * @param raster the WritableRaster data + * @param isAlphaPremultiplied true if the alpha is + * premultiplied; false otherwise + * @return a ColorModel object that represents the + * coerced data. + * @exception UnsupportedOperationException if this + * transferType is not supported by this + * color model + */ + final public ColorModel coerceData (WritableRaster raster, + boolean isAlphaPremultiplied) + { + if (!supportsAlpha || + this.isAlphaPremultiplied() == isAlphaPremultiplied) { + return this; + } -// /** -// * Returns true if raster is compatible -// * with this ColorModel and false if it is -// * not. -// * @param raster the {@link Raster} object to test for compatibility -// * @return true if raster is compatible -// * with this ColorModel; false otherwise. -// */ -// public boolean isCompatibleRaster(Raster raster) { -// SampleModel sm = raster.getSampleModel(); -// SinglePixelPackedSampleModel spsm; -// if (sm instanceof SinglePixelPackedSampleModel) { -// spsm = (SinglePixelPackedSampleModel) sm; -// } -// else { -// return false; -// } -// if (spsm.getNumBands() != getNumComponents()) { -// return false; -// } -// -// int[] bitMasks = spsm.getBitMasks(); -// for (int i=0; itrue if raster is compatible + * with this ColorModel and false if it is + * not. + * @param raster the {@link Raster} object to test for compatibility + * @return true if raster is compatible + * with this ColorModel; false otherwise. + */ + public boolean isCompatibleRaster(Raster raster) { + SampleModel sm = raster.getSampleModel(); + SinglePixelPackedSampleModel spsm; + if (sm instanceof SinglePixelPackedSampleModel) { + spsm = (SinglePixelPackedSampleModel) sm; + } + else { + return false; + } + if (spsm.getNumBands() != getNumComponents()) { + return false; + } + + int[] bitMasks = spsm.getBitMasks(); + for (int i=0; iString that represents this diff --git a/sources/net.sf.j2s.java.core/src/java/awt/image/IndexColorModel.java b/sources/net.sf.j2s.java.core/src/java/awt/image/IndexColorModel.java index eeddfc3ba..7a87c4e8b 100644 --- a/sources/net.sf.j2s.java.core/src/java/awt/image/IndexColorModel.java +++ b/sources/net.sf.j2s.java.core/src/java/awt/image/IndexColorModel.java @@ -31,6 +31,7 @@ import java.awt.Transparency; import java.awt.color.ColorSpace; //import java.math.BigInteger; +import java.math.BigInteger; /** * The IndexColorModel class is a ColorModel @@ -130,7 +131,7 @@ public class IndexColorModel extends ColorModel { private int pixel_mask; private int transparent_index = -1; private boolean allgrayopaque; -// private BigInteger validBits; + private BigInteger validBits; // private sun.awt.image.BufImgSurfaceData .ICMColorData colorData = null; @@ -433,79 +434,79 @@ public IndexColorModel(int bits, int size, calculatePixelMask(); } -// /** -// * Constructs an IndexColorModel from an -// * int array where each int is -// * comprised of red, green, blue, and alpha -// * components in the default RGB color model format. -// * The array must have enough values in it to fill all -// * of the needed component arrays of the specified size. -// * The ColorSpace is the default sRGB space. -// * The transparency value may be any of Transparency.OPAQUE, -// * Transparency.BITMASK, -// * or Transparency.TRANSLUCENT -// * depending on the arguments, as specified -// * in the class description above. -// * The transfer type must be one of DataBuffer.TYPE_BYTE -// * DataBuffer.TYPE_USHORT. -// * The BigInteger object specifies the valid/invalid pixels -// * in the cmap array. A pixel is valid if the -// * BigInteger value at that index is set, and is invalid -// * if the BigInteger bit at that index is not set. -// * @param bits the number of bits each pixel occupies -// * @param size the size of the color component array -// * @param cmap the array of color components -// * @param start the starting offset of the first color component -// * @param transferType the specified data type -// * @param validBits a BigInteger object. If a bit is -// * set in the BigInteger, the pixel at that index is valid. -// * If a bit is not set, the pixel at that index -// * is considered invalid. If null, all pixels are valid. -// * Only bits from 0 to the map size are considered. -// * @throws IllegalArgumentException if bits is less -// * than 1 or greater than 16 -// * @throws IllegalArgumentException if size is less -// * than 1 -// * @throws IllegalArgumentException if transferType is not -// * one of DataBuffer.TYPE_BYTE or -// * DataBuffer.TYPE_USHORT -// * -// * @since 1.3 -// */ -// public IndexColorModel(int bits, int size, int cmap[], int start, -// int transferType, BigInteger validBits) { -// super (bits, alphaBits, -// ColorSpace.getInstance(ColorSpace.CS_sRGB), -// true, false, TRANSLUCENT, -// transferType); -// -// if (bits < 1 || bits > 16) { -// throw new IllegalArgumentException("Number of bits must be between" -// +" 1 and 16."); -// } -// if (size < 1) { -// throw new IllegalArgumentException("Map size ("+size+ -// ") must be >= 1"); -// } -// if ((transferType != DataBuffer.TYPE_BYTE) && -// (transferType != DataBuffer.TYPE_USHORT)) { -// throw new IllegalArgumentException("transferType must be either" + -// "DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT"); -// } -// -// if (validBits != null) { -// // Check to see if it is all valid -// for (int i=0; i < size; i++) { -// if (!validBits.testBit(i)) { -// this.validBits = validBits; -// break; -// } -// } -// } -// -// setRGBs(size, cmap, start, true); -// calculatePixelMask(); -// } + /** + * Constructs an IndexColorModel from an + * int array where each int is + * comprised of red, green, blue, and alpha + * components in the default RGB color model format. + * The array must have enough values in it to fill all + * of the needed component arrays of the specified size. + * The ColorSpace is the default sRGB space. + * The transparency value may be any of Transparency.OPAQUE, + * Transparency.BITMASK, + * or Transparency.TRANSLUCENT + * depending on the arguments, as specified + * in the class description above. + * The transfer type must be one of DataBuffer.TYPE_BYTE + * DataBuffer.TYPE_USHORT. + * The BigInteger object specifies the valid/invalid pixels + * in the cmap array. A pixel is valid if the + * BigInteger value at that index is set, and is invalid + * if the BigInteger bit at that index is not set. + * @param bits the number of bits each pixel occupies + * @param size the size of the color component array + * @param cmap the array of color components + * @param start the starting offset of the first color component + * @param transferType the specified data type + * @param validBits a BigInteger object. If a bit is + * set in the BigInteger, the pixel at that index is valid. + * If a bit is not set, the pixel at that index + * is considered invalid. If null, all pixels are valid. + * Only bits from 0 to the map size are considered. + * @throws IllegalArgumentException if bits is less + * than 1 or greater than 16 + * @throws IllegalArgumentException if size is less + * than 1 + * @throws IllegalArgumentException if transferType is not + * one of DataBuffer.TYPE_BYTE or + * DataBuffer.TYPE_USHORT + * + * @since 1.3 + */ + public IndexColorModel(int bits, int size, int cmap[], int start, + int transferType, BigInteger validBits) { + super (bits, alphaBits, + ColorSpace.getInstance(ColorSpace.CS_sRGB), + true, false, TRANSLUCENT, + transferType); + + if (bits < 1 || bits > 16) { + throw new IllegalArgumentException("Number of bits must be between" + +" 1 and 16."); + } + if (size < 1) { + throw new IllegalArgumentException("Map size ("+size+ + ") must be >= 1"); + } + if ((transferType != DataBuffer.TYPE_BYTE) && + (transferType != DataBuffer.TYPE_USHORT)) { + throw new IllegalArgumentException("transferType must be either" + + "DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT"); + } + + if (validBits != null) { + // Check to see if it is all valid + for (int i=0; i < size; i++) { + if (!validBits.testBit(i)) { + this.validBits = validBits; + break; + } + } + } + + setRGBs(size, cmap, start, true); + calculatePixelMask(); + } private void setRGBs(int size, byte r[], byte g[], byte b[], byte a[]) { if (size < 1) { @@ -550,11 +551,11 @@ private void setRGBs(int size, int cmap[], int start, boolean hasalpha) { int j = start; int transparency = OPAQUE; boolean allgray = true; -// BigInteger validBits = this.validBits; + BigInteger validBits = this.validBits; for (int i = 0; i < size; i++, j++) { -// if (validBits != null && !validBits.testBit(i)) { -// continue; -// } + if (validBits != null && !validBits.testBit(i)) { + continue; + } int cmaprgb = cmap[j]; int r = (cmaprgb >> 16) & 0xff; int g = (cmaprgb >> 8) & 0xff; @@ -589,15 +590,15 @@ private int calcRealMapSize(int bits, int size) { return Math.max(newSize, 256); } -// private BigInteger getAllValid() { -// int numbytes = (map_size+7)/8; -// byte[] valid = new byte[numbytes]; -// java.util.Arrays.fill(valid, (byte)0xff); -// valid[0] = (byte)(0xff >>> (numbytes*8 - map_size)); -// -// return new BigInteger(1, valid); -// } -// + private BigInteger getAllValid() { + int numbytes = (map_size+7)/8; + byte[] valid = new byte[numbytes]; + java.util.Arrays.fill(valid, (byte)0xff); + valid[0] = (byte)(0xff >>> (numbytes*8 - map_size)); + + return new BigInteger(1, valid); + } + /** * Returns the transparency. Returns either OPAQUE, BITMASK, * or TRANSLUCENT @@ -1318,14 +1319,14 @@ public WritableRaster createCompatibleWritableRaster(int w, int h) { raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, w, h, 1, pixel_bits, null); } -// else if (pixel_bits <= 8) { -// raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, -// w,h,1,null); -// } -// else if (pixel_bits <= 16) { -// raster = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT, -// w,h,1,null); -// } + else if (pixel_bits <= 8) { + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, + w,h,1,null); + } + else if (pixel_bits <= 16) { + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT, + w,h,1,null); + } else { throw new UnsupportedOperationException("This method is not supported "+ @@ -1494,25 +1495,25 @@ public boolean isValid() { return true;//(validBits == null); } -// /** -// * Returns a BigInteger that indicates the valid/invalid -// * pixels in the colormap. A bit is valid if the -// * BigInteger value at that index is set, and is invalid -// * if the BigInteger value at that index is not set. -// * The only valid ranges to query in the BigInteger are -// * between 0 and the map size. -// * @return a BigInteger indicating the valid/invalid pixels. -// * @since 1.3 -// */ -// public BigInteger getValidPixels() { -// if (validBits == null) { -// return getAllValid(); -// } -// else { -// return validBits; -// } -// } -// + /** + * Returns a BigInteger that indicates the valid/invalid + * pixels in the colormap. A bit is valid if the + * BigInteger value at that index is set, and is invalid + * if the BigInteger value at that index is not set. + * The only valid ranges to query in the BigInteger are + * between 0 and the map size. + * @return a BigInteger indicating the valid/invalid pixels. + * @since 1.3 + */ + public BigInteger getValidPixels() { + if (validBits == null) { + return getAllValid(); + } + else { + return validBits; + } + } + /** * Disposes of system resources associated with this * ColorModel once this ColorModel is no diff --git a/sources/net.sf.j2s.java.core/src/java/awt/image/LookupOp.java b/sources/net.sf.j2s.java.core/src/java/awt/image/LookupOp.java index 2a2018e8b..8f21ae777 100644 --- a/sources/net.sf.j2s.java.core/src/java/awt/image/LookupOp.java +++ b/sources/net.sf.j2s.java.core/src/java/awt/image/LookupOp.java @@ -30,6 +30,7 @@ package java.awt.image; import java.awt.RenderingHints; +import java.awt.Transparency; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import sun.awt.image.ImagingLib; @@ -304,10 +305,10 @@ public final WritableRaster filter (Raster src, WritableRaster dst) { byteFilter ((ByteLookupTable) ltable, src, dst, width, height, numBands); } -// else if (ltable instanceof ShortLookupTable) { -// shortFilter ((ShortLookupTable) ltable, src, dst, width, -// height, numBands); -// } + else if (ltable instanceof ShortLookupTable) { + shortFilter ((ShortLookupTable) ltable, src, dst, width, + height, numBands); + } else { // Not one we recognize so do it slowly int sminX = src.getMinX(); @@ -373,60 +374,59 @@ public BufferedImage createCompatibleDestImage (BufferedImage src, BufferedImage image; int w = src.getWidth(); int h = src.getHeight(); -// int transferType = DataBuffer.TYPE_BYTE; + int transferType = DataBuffer.TYPE_BYTE; if (destCM == null) { ColorModel cm = src.getColorModel(); -// Raster raster = src.getRaster(); -// SwingJS not supported -// if (cm instanceof ComponentColorModel) { -// DataBuffer db = raster.getDataBuffer(); -// boolean hasAlpha = cm.hasAlpha(); -// boolean isPre = cm.isAlphaPremultiplied(); -// int trans = cm.getTransparency(); -// int[] nbits = null; -// if (ltable instanceof ByteLookupTable) { -// if (db.getDataType() == db.TYPE_USHORT) { -// // Dst raster should be of type byte -// if (hasAlpha) { -// nbits = new int[2]; -// if (trans == cm.BITMASK) { -// nbits[1] = 1; -// } -// else { -// nbits[1] = 8; -// } -// } -// else { -// nbits = new int[1]; -// } -// nbits[0] = 8; -// } -// // For byte, no need to change the cm -// } -// else if (ltable instanceof ShortLookupTable) { -// transferType = DataBuffer.TYPE_USHORT; -// if (db.getDataType() == db.TYPE_BYTE) { -// if (hasAlpha) { -// nbits = new int[2]; -// if (trans == cm.BITMASK) { -// nbits[1] = 1; -// } -// else { -// nbits[1] = 16; -// } -// } -// else { -// nbits = new int[1]; -// } -// nbits[0] = 16; -// } -// } -// if (nbits != null) { -// cm = new ComponentColorModel(cm.getColorSpace(), -// nbits, hasAlpha, isPre, -// trans, transferType); -// } -// } + Raster raster = src.getRaster(); + if (cm instanceof ComponentColorModel) { + DataBuffer db = raster.getDataBuffer(); + boolean hasAlpha = cm.hasAlpha(); + boolean isPre = cm.isAlphaPremultiplied(); + int trans = cm.getTransparency(); + int[] nbits = null; + if (ltable instanceof ByteLookupTable) { + if (db.getDataType() == DataBuffer.TYPE_USHORT) { + // Dst raster should be of type byte + if (hasAlpha) { + nbits = new int[2]; + if (trans == Transparency.BITMASK) { + nbits[1] = 1; + } + else { + nbits[1] = 8; + } + } + else { + nbits = new int[1]; + } + nbits[0] = 8; + } + // For byte, no need to change the cm + } + else if (ltable instanceof ShortLookupTable) { + transferType = DataBuffer.TYPE_USHORT; + if (db.getDataType() == DataBuffer.TYPE_BYTE) { + if (hasAlpha) { + nbits = new int[2]; + if (trans == Transparency.BITMASK) { + nbits[1] = 1; + } + else { + nbits[1] = 16; + } + } + else { + nbits = new int[1]; + } + nbits[0] = 16; + } + } + if (nbits != null) { + cm = new ComponentColorModel(cm.getColorSpace(), + nbits, hasAlpha, isPre, + trans, transferType); + } + } image = new BufferedImage(cm, cm.createCompatibleWritableRaster(w, h), cm.isAlphaPremultiplied(), @@ -534,49 +534,49 @@ private final void byteFilter(ByteLookupTable lookup, Raster src, } } -// private final void shortFilter(ShortLookupTable lookup, Raster src, -// WritableRaster dst, -// int width, int height, int numBands) { -// int band; -// int[] srcPix = null; -// -// // Find the ref to the table and the offset -// short[][] table = lookup.getTable(); -// int offset = lookup.getOffset(); -// int tidx; -// int step=1; -// -// // Check if it is one lookup applied to all bands -// if (table.length == 1) { -// step=0; -// } -// -// int x = 0; -// int y = 0; -// int index; -// int maxShort = (1<<16)-1; -// // Loop through the data -// for (y=0; y < height; y++) { -// tidx = 0; -// for ( band=0; band < numBands; band++, tidx+=step) { -// // Find data for this band, scanline -// srcPix = src.getSamples(0, y, width, 1, band, srcPix); -// -// for ( x=0; x < width; x++) { -// index = srcPix[x]-offset; -// if (index < 0 || index > maxShort) { -// throw new -// IllegalArgumentException("index out of range "+ -// index+" x is "+x+ -// "srcPix[x]="+srcPix[x] -// +" offset="+ offset); -// } -// // Do the lookup -// srcPix[x] = table[tidx][index]; -// } -// // Put it back -// dst.setSamples(0, y, width, 1, band, srcPix); -// } -// } -// } + private final void shortFilter(ShortLookupTable lookup, Raster src, + WritableRaster dst, + int width, int height, int numBands) { + int band; + int[] srcPix = null; + + // Find the ref to the table and the offset + short[][] table = lookup.getTable(); + int offset = lookup.getOffset(); + int tidx; + int step=1; + + // Check if it is one lookup applied to all bands + if (table.length == 1) { + step=0; + } + + int x = 0; + int y = 0; + int index; + int maxShort = (1<<16)-1; + // Loop through the data + for (y=0; y < height; y++) { + tidx = 0; + for ( band=0; band < numBands; band++, tidx+=step) { + // Find data for this band, scanline + srcPix = src.getSamples(0, y, width, 1, band, srcPix); + + for ( x=0; x < width; x++) { + index = srcPix[x]-offset; + if (index < 0 || index > maxShort) { + throw new + IllegalArgumentException("index out of range "+ + index+" x is "+x+ + "srcPix[x]="+srcPix[x] + +" offset="+ offset); + } + // Do the lookup + srcPix[x] = table[tidx][index]; + } + // Put it back + dst.setSamples(0, y, width, 1, band, srcPix); + } + } + } } diff --git a/sources/net.sf.j2s.java.core/src/java/awt/image/MemoryImageSource.java b/sources/net.sf.j2s.java.core/src/java/awt/image/MemoryImageSource.java index 9f0f70501..6e33c3ad6 100644 --- a/sources/net.sf.j2s.java.core/src/java/awt/image/MemoryImageSource.java +++ b/sources/net.sf.j2s.java.core/src/java/awt/image/MemoryImageSource.java @@ -28,15 +28,10 @@ package java.awt.image; -import java.awt.image.ImageConsumer; -import java.awt.image.ImageProducer; -import java.awt.Graphics; -import java.awt.image.ColorModel; +import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; -import java.util.Enumeration; -import javajs.util.AU; import swingjs.JSGraphics2D; /** @@ -111,7 +106,6 @@ * @author Animation capabilities inspired by the * MemoryAnimationSource class written by Garth Dickie */ -@SuppressWarnings({"rawtypes", "unchecked"}) public class MemoryImageSource implements ImageProducer { int width; int height; @@ -461,7 +455,7 @@ public synchronized void newPixels(int x, int y, int w, int h) { * @see #setAnimated * @see #setFullBufferUpdates */ - @SuppressWarnings({ "unused", "null" }) + @SuppressWarnings({ "unused" }) public synchronized void newPixels(int x, int y, int w, int h, boolean framenotify) { diff --git a/sources/net.sf.j2s.java.core/src/java/awt/image/MultiPixelPackedSampleModel.java b/sources/net.sf.j2s.java.core/src/java/awt/image/MultiPixelPackedSampleModel.java index 5a0a01447..4aec1b5cf 100644 --- a/sources/net.sf.j2s.java.core/src/java/awt/image/MultiPixelPackedSampleModel.java +++ b/sources/net.sf.j2s.java.core/src/java/awt/image/MultiPixelPackedSampleModel.java @@ -113,7 +113,7 @@ public MultiPixelPackedSampleModel(int dataType, DataBuffer.getDataTypeSize(dataType), 0); if (dataType != DataBuffer.TYPE_BYTE && -// dataType != DataBuffer.TYPE_USHORT && + dataType != DataBuffer.TYPE_USHORT && dataType != DataBuffer.TYPE_INT) { throw new IllegalArgumentException("Unsupported data type "+ dataType); @@ -149,7 +149,7 @@ public MultiPixelPackedSampleModel(int dataType, int w, int h, int dataBitOffset) { super(dataType, w, h, 1); if (dataType != DataBuffer.TYPE_BYTE && -// dataType != DataBuffer.TYPE_USHORT && + dataType != DataBuffer.TYPE_USHORT && dataType != DataBuffer.TYPE_INT) { throw new IllegalArgumentException("Unsupported data type "+ dataType); @@ -208,9 +208,9 @@ public DataBuffer createDataBuffer() { case DataBuffer.TYPE_BYTE: dataBuffer = new DataBufferByte(size+(dataBitOffset+7)/8); break; -// case DataBuffer.TYPE_USHORT: -// dataBuffer = new DataBufferUShort(size+(dataBitOffset+15)/16); -// break; + case DataBuffer.TYPE_USHORT: + dataBuffer = new DataBufferUShort(size+(dataBitOffset+15)/16); + break; case DataBuffer.TYPE_INT: dataBuffer = new DataBufferInt(size+(dataBitOffset+31)/32); break; @@ -312,13 +312,12 @@ public int getDataBitOffset() { */ @Override public int getTransferType() { -// SwingJS - everything is done in ints here -// if (pixelBitStride > 16) + if (pixelBitStride > 16) return DataBuffer.TYPE_INT; -// else if (pixelBitStride > 8) -// return DataBuffer.TYPE_USHORT; -// else -// return DataBuffer.TYPE_BYTE; + else if (pixelBitStride > 8) + return DataBuffer.TYPE_USHORT; + else + return DataBuffer.TYPE_BYTE; } /** @@ -493,22 +492,22 @@ public Object getDataElements(int x, int y, Object obj, DataBuffer data) { obj = (Object)bdata; break; -// case DataBuffer.TYPE_USHORT: -// -// short[] sdata; -// -// if (obj == null) -// sdata = new short[1]; -// else -// sdata = (short[])obj; -// -// element = data.getElem(y*scanlineStride + -// bitnum/dataElementSize); -// sdata[0] = (short)((element >> shift) & bitMask); -// -// obj = (Object)sdata; -// break; -// + case DataBuffer.TYPE_USHORT: + + short[] sdata; + + if (obj == null) + sdata = new short[1]; + else + sdata = (short[])obj; + + element = data.getElem(y*scanlineStride + + bitnum/dataElementSize); + sdata[0] = (short)((element >> shift) & bitMask); + + obj = (Object)sdata; + break; + case DataBuffer.TYPE_INT: int[] idata; @@ -628,13 +627,13 @@ public void setDataElements(int x, int y, Object obj, DataBuffer data) { data.setElem(index, element); break; -// case DataBuffer.TYPE_USHORT: -// -// short[] sarray = (short[])obj; -// element |= ( ((int)(sarray[0])&0xffff) & bitMask) << shift; -// data.setElem(index, element); -// break; -// + case DataBuffer.TYPE_USHORT: + + short[] sarray = (short[])obj; + element |= ( ((int)(sarray[0])&0xffff) & bitMask) << shift; + data.setElem(index, element); + break; + case DataBuffer.TYPE_INT: int[] iarray = (int[])obj; diff --git a/sources/net.sf.j2s.java.core/src/java/awt/image/Raster.java b/sources/net.sf.j2s.java.core/src/java/awt/image/Raster.java index 4ae4868df..3072cc4e1 100644 --- a/sources/net.sf.j2s.java.core/src/java/awt/image/Raster.java +++ b/sources/net.sf.j2s.java.core/src/java/awt/image/Raster.java @@ -412,10 +412,10 @@ public static WritableRaster createBandedRaster(int dataType, d = new DataBufferByte(size, banks); break; -// case DataBuffer.TYPE_USHORT: -// d = new DataBufferUShort(size, banks); -// break; -// + case DataBuffer.TYPE_USHORT: + d = new DataBufferUShort(size, banks); + break; + case DataBuffer.TYPE_INT: d = new DataBufferInt(size, banks); break; @@ -470,10 +470,10 @@ public static WritableRaster createPackedRaster(int dataType, d = new DataBufferByte(w*h); break; -// case DataBuffer.TYPE_USHORT: -// d = new DataBufferUShort(w*h); -// break; -// + case DataBuffer.TYPE_USHORT: + d = new DataBufferUShort(w*h); + break; + case DataBuffer.TYPE_INT: d = new DataBufferInt(w*h); break; @@ -561,7 +561,7 @@ public static WritableRaster createPackedRaster(int dataType, } switch(dataType) { case DataBuffer.TYPE_BYTE: -// case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_USHORT: case DataBuffer.TYPE_INT: break; default: @@ -583,10 +583,10 @@ public static WritableRaster createPackedRaster(int dataType, d = new DataBufferByte((int)(Math.ceil(fw/(8/bitsPerBand)))*h); break; -// case DataBuffer.TYPE_USHORT: -// d = new DataBufferUShort((int)(Math.ceil(fw/(16/bitsPerBand)))*h); -// break; -// + case DataBuffer.TYPE_USHORT: + d = new DataBufferUShort((int)(Math.ceil(fw/(16/bitsPerBand)))*h); + break; + case DataBuffer.TYPE_INT: d = new DataBufferInt((int)(Math.ceil(fw/(32/bitsPerBand)))*h); break; @@ -660,8 +660,7 @@ public static WritableRaster createInterleavedRaster(DataBuffer dataBuffer, case DataBuffer.TYPE_USHORT: JSUtil.notImplemented("USHORT-interleaved raster"); - return null; -// return new ShortInterleavedRaster(csm, dataBuffer, location); + return new ShortInterleavedRaster(csm, dataBuffer, location); default: throw new IllegalArgumentException("Unsupported data type " + @@ -953,75 +952,75 @@ public static WritableRaster createWritableRaster(SampleModel sm, return createWritableRaster(sm, sm.createDataBuffer(), location); } - /** - * Creates a WritableRaster with the specified SampleModel and DataBuffer. - * The upper left corner of the Raster is given by the location argument. - * If location is null, (0, 0) will be used. - * @param sm the specified SampleModel - * @param db the specified DataBuffer - * @param location the upper-left corner of the - * WritableRaster - * @return a WritableRaster with the specified - * SampleModel, DataBuffer, and - * location. - * @throws RasterFormatException if computing either - * location.x + sm.getWidth() or - * location.y + sm.getHeight() results in integer - * overflow - * @throws RasterFormatException if db has more - * than one bank and sm is a - * PixelInterleavedSampleModel, SinglePixelPackedSampleModel, - * or MultiPixelPackedSampleModel. - * @throws NullPointerException if either SampleModel or DataBuffer is null - */ - public static WritableRaster createWritableRaster(SampleModel sm, - DataBuffer db, - Point location) { - if ((sm == null) || (db == null)) { - throw new NullPointerException("SampleModel and DataBuffer cannot be null"); - } - if (location == null) { - location = new Point(0,0); - } - - int dataType = sm.getDataType(); - - if (dataType == DataBuffer.TYPE_INT) { // SwingJS - SunWritableRaster r = new SunWritableRaster(sm,db,location); - r.秘pix = SunWritableRaster.stealData((DataBufferInt) db, 0); - return r; - } - - if (sm instanceof PixelInterleavedSampleModel) { - switch(dataType) { - case DataBuffer.TYPE_BYTE: - return new ByteInterleavedRaster(sm, db, location); - - case DataBuffer.TYPE_USHORT: - return new ShortInterleavedRaster(sm, db, location); - } - } else if (sm instanceof SinglePixelPackedSampleModel) { - switch(dataType) { - case DataBuffer.TYPE_BYTE: - return new ByteInterleavedRaster(sm, db, location); - - case DataBuffer.TYPE_USHORT: - return new ShortInterleavedRaster(sm, db, location); - - case DataBuffer.TYPE_INT: - return new IntegerInterleavedRaster(sm, db, location); - } - } else - if (sm instanceof MultiPixelPackedSampleModel && - dataType == DataBuffer.TYPE_BYTE && - sm.getSampleSize(0) < 8) { - return new BytePackedRaster(sm, db, location); - } - - // we couldn't do anything special - do the generic thing + /** + * Creates a WritableRaster with the specified SampleModel and DataBuffer. The + * upper left corner of the Raster is given by the location argument. If + * location is null, (0, 0) will be used. + * + * @param sm the specified SampleModel + * @param db the specified DataBuffer + * @param location the upper-left corner of the WritableRaster + * @return a WritableRaster with the specified + * SampleModel, DataBuffer, and location. + * @throws RasterFormatException if computing either + * location.x + sm.getWidth() or + * location.y + sm.getHeight() + * results in integer overflow + * @throws RasterFormatException if db has more than one bank and + * sm is a + * PixelInterleavedSampleModel, + * SinglePixelPackedSampleModel, or + * MultiPixelPackedSampleModel. + * @throws NullPointerException if either SampleModel or DataBuffer is null + */ + public static WritableRaster createWritableRaster(SampleModel sm, DataBuffer db, Point location) { + if ((sm == null) || (db == null)) { + throw new NullPointerException("SampleModel and DataBuffer cannot be null"); + } + if (location == null) { + location = new Point(0, 0); + } - return new BytePackedRaster(sm, db, location); - } + int dataType = sm.getDataType(); + + SunWritableRaster r = null; + + if (sm instanceof PixelInterleavedSampleModel) { + switch (dataType) { + case DataBuffer.TYPE_BYTE: + r = new ByteInterleavedRaster(sm, db, location); + break; + case DataBuffer.TYPE_USHORT: + r = new ShortInterleavedRaster(sm, db, location); + break; + } + } else if (sm instanceof SinglePixelPackedSampleModel) { + switch (dataType) { + case DataBuffer.TYPE_BYTE: + r = new ByteInterleavedRaster(sm, db, location); + break; + case DataBuffer.TYPE_USHORT: + r = new ShortInterleavedRaster(sm, db, location); + break; + case DataBuffer.TYPE_INT: + r = new IntegerInterleavedRaster(sm, db, location); + //r = new SunWritableRaster(sm, db, location); + // TODO -- THIS IS NOT GENERALLY RIGHT + r.秘pix = SunWritableRaster.stealData((DataBufferInt) db, 0); + break; + } + } else if (sm instanceof MultiPixelPackedSampleModel && dataType == DataBuffer.TYPE_BYTE + && sm.getSampleSize(0) < 8) { + r = new BytePackedRaster(sm, db, location); + } + + if (r == null) { + // we couldn't do anything special - do the generic thing + + r = new BytePackedRaster(sm, db, location); + } + return r; + } /** * Constructs a Raster with the given SampleModel. The Raster's diff --git a/sources/net.sf.j2s.java.core/src/java/awt/image/RescaleOp.java b/sources/net.sf.j2s.java.core/src/java/awt/image/RescaleOp.java index f225deda7..4ab7f0ae1 100644 --- a/sources/net.sf.j2s.java.core/src/java/awt/image/RescaleOp.java +++ b/sources/net.sf.j2s.java.core/src/java/awt/image/RescaleOp.java @@ -268,7 +268,7 @@ private boolean canUseLookup(Raster src, Raster dst) { // int datatype = src.getDataBuffer().getDataType(); if(datatype != DataBuffer.TYPE_BYTE -// && datatype != DataBuffer.TYPE_USHORT + && datatype != DataBuffer.TYPE_USHORT ) { return false; } diff --git a/sources/net.sf.j2s.java.core/src/java/awt/image/SampleModel.java b/sources/net.sf.j2s.java.core/src/java/awt/image/SampleModel.java index 9eaee0d6d..ef14e41d3 100644 --- a/sources/net.sf.j2s.java.core/src/java/awt/image/SampleModel.java +++ b/sources/net.sf.j2s.java.core/src/java/awt/image/SampleModel.java @@ -84,6 +84,9 @@ public abstract class SampleModel { + + public int[] 秘pix; + /** Width in pixels of the region of image data that this SampleModel * describes. */ @@ -389,7 +392,7 @@ public Object getDataElements(int x, int y, int w, int h, obj = (Object)bdata; break; -// case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_USHORT: case DataBuffer.TYPE_SHORT: short[] sdata; @@ -604,23 +607,23 @@ public void setDataElements(int x, int y, int w, int h, } break; -// case DataBuffer.TYPE_USHORT: -// case DataBuffer.TYPE_SHORT: -// -// short[] sarray = (short[])obj; -// short[] stemp = new short[numDataElems]; -// -// for (int i=y; i + * Warning: + * Serialized objects of this class will not be compatible with + * future Swing releases. The current serialization support is + * appropriate for short term storage or RMI between applications running + * the same version of Swing. As of 1.4, support for long term storage + * of all JavaBeans™ + * has been added to the java.beans package. + * Please see {@link java.beans.XMLEncoder}. + * + * @author Scott Violet + */ + +public class FixedHeightLayoutCache extends AbstractLayoutCache { + /** Root node. */ + private FHTreeStateNode root; + + /** Number of rows currently visible. */ + private int rowCount; + + /** + * Used in getting sizes for nodes to avoid creating a new Rectangle + * every time a size is needed. + */ + private Rectangle boundsBuffer; + + /** + * Maps from TreePath to a FHTreeStateNode. + */ + private Hashtable treePathMapping; + + /** + * Used for getting path/row information. + */ + private SearchInfo info; + + private Stack> tempStacks; + + + public FixedHeightLayoutCache() { + super(); + tempStacks = new Stack>(); + boundsBuffer = new Rectangle(); + treePathMapping = new Hashtable(); + info = new SearchInfo(); + setRowHeight(1); + } + + /** + * Sets the TreeModel that will provide the data. + * + * @param newModel the TreeModel that is to provide the data + */ + public void setModel(TreeModel newModel) { + super.setModel(newModel); + rebuild(false); + } + + /** + * Determines whether or not the root node from + * the TreeModel is visible. + * + * @param rootVisible true if the root node of the tree is to be displayed + * @see #rootVisible + */ + public void setRootVisible(boolean rootVisible) { + if(isRootVisible() != rootVisible) { + super.setRootVisible(rootVisible); + if(root != null) { + if(rootVisible) { + rowCount++; + root.adjustRowBy(1); + } + else { + rowCount--; + root.adjustRowBy(-1); + } + visibleNodesChanged(); + } + } + } + + /** + * Sets the height of each cell. If rowHeight is less than or equal to + * 0 this will throw an IllegalArgumentException. + * + * @param rowHeight the height of each cell, in pixels + */ + public void setRowHeight(int rowHeight) { + if(rowHeight <= 0) + throw new IllegalArgumentException("FixedHeightLayoutCache only supports row heights greater than 0"); + if(getRowHeight() != rowHeight) { + super.setRowHeight(rowHeight); + visibleNodesChanged(); + } + } + + /** + * Returns the number of visible rows. + */ + public int getRowCount() { + return rowCount; + } + + /** + * Does nothing, FixedHeightLayoutCache doesn't cache width, and that + * is all that could change. + */ + public void invalidatePathBounds(TreePath path) { + } + + + /** + * Informs the TreeState that it needs to recalculate all the sizes + * it is referencing. + */ + public void invalidateSizes() { + // Nothing to do here, rowHeight still same, which is all + // this is interested in, visible region may have changed though. + visibleNodesChanged(); + } + + /** + * Returns true if the value identified by row is currently expanded. + */ + public boolean isExpanded(TreePath path) { + if(path != null) { + FHTreeStateNode lastNode = getNodeForPath(path, true, false); + + return (lastNode != null && lastNode.isExpanded()); + } + return false; + } + + /** + * Returns a rectangle giving the bounds needed to draw path. + * + * @param path a TreePath specifying a node + * @param placeIn a Rectangle object giving the available space + * @return a Rectangle object specifying the space to be used + */ + public Rectangle getBounds(TreePath path, Rectangle placeIn) { + if(path == null) + return null; + + FHTreeStateNode node = getNodeForPath(path, true, false); + + if(node != null) + return getBounds(node, -1, placeIn); + + // node hasn't been created yet. + TreePath parentPath = path.getParentPath(); + + node = getNodeForPath(parentPath, true, false); + if (node != null && node.isExpanded()) { + int childIndex = treeModel.getIndexOfChild + (parentPath.getLastPathComponent(), + path.getLastPathComponent()); + + if(childIndex != -1) + return getBounds(node, childIndex, placeIn); + } + return null; + } + + /** + * Returns the path for passed in row. If row is not visible + * null is returned. + */ + public TreePath getPathForRow(int row) { + if(row >= 0 && row < getRowCount()) { + if(root.getPathForRow(row, getRowCount(), info)) { + return info.getPath(); + } + } + return null; + } + + /** + * Returns the row that the last item identified in path is visible + * at. Will return -1 if any of the elements in path are not + * currently visible. + */ + public int getRowForPath(TreePath path) { + if(path == null || root == null) + return -1; + + FHTreeStateNode node = getNodeForPath(path, true, false); + + if(node != null) + return node.getRow(); + + TreePath parentPath = path.getParentPath(); + + node = getNodeForPath(parentPath, true, false); + if(node != null && node.isExpanded()) { + return node.getRowToModelIndex(treeModel.getIndexOfChild + (parentPath.getLastPathComponent(), + path.getLastPathComponent())); + } + return -1; + } + + /** + * Returns the path to the node that is closest to x,y. If + * there is nothing currently visible this will return null, otherwise + * it'll always return a valid path. If you need to test if the + * returned object is exactly at x, y you should get the bounds for + * the returned path and test x, y against that. + */ + public TreePath getPathClosestTo(int x, int y) { + if(getRowCount() == 0) + return null; + + int row = getRowContainingYLocation(y); + + return getPathForRow(row); + } + + /** + * Returns the number of visible children for row. + */ + public int getVisibleChildCount(TreePath path) { + FHTreeStateNode node = getNodeForPath(path, true, false); + + if(node == null) + return 0; + return node.getTotalChildCount(); + } + + /** + * Returns an Enumerator that increments over the visible paths + * starting at the passed in location. The ordering of the enumeration + * is based on how the paths are displayed. + */ + public Enumeration getVisiblePathsFrom(TreePath path) { + if(path == null) + return null; + + FHTreeStateNode node = getNodeForPath(path, true, false); + + if(node != null) { + return new VisibleFHTreeStateNodeEnumeration(node); + } + TreePath parentPath = path.getParentPath(); + + node = getNodeForPath(parentPath, true, false); + if(node != null && node.isExpanded()) { + return new VisibleFHTreeStateNodeEnumeration(node, + treeModel.getIndexOfChild(parentPath.getLastPathComponent(), + path.getLastPathComponent())); + } + return null; + } + + /** + * Marks the path path expanded state to + * isExpanded. + */ + public void setExpandedState(TreePath path, boolean isExpanded) { + if(isExpanded) + ensurePathIsExpanded(path, true); + else if(path != null) { + TreePath parentPath = path.getParentPath(); + + // YECK! Make the parent expanded. + if(parentPath != null) { + FHTreeStateNode parentNode = getNodeForPath(parentPath, + false, true); + if(parentNode != null) + parentNode.makeVisible(); + } + // And collapse the child. + FHTreeStateNode childNode = getNodeForPath(path, true, + false); + + if(childNode != null) + childNode.collapse(true); + } + } + + /** + * Returns true if the path is expanded, and visible. + */ + public boolean getExpandedState(TreePath path) { + FHTreeStateNode node = getNodeForPath(path, true, false); + + return (node != null) ? (node.isVisible() && node.isExpanded()) : + false; + } + + // + // TreeModelListener methods + // + + /** + *

Invoked after a node (or a set of siblings) has changed in some + * way. The node(s) have not changed locations in the tree or + * altered their children arrays, but other attributes have + * changed and may affect presentation. Example: the name of a + * file has changed, but it is in the same location in the file + * system.

+ * + *

e.path() returns the path the parent of the changed node(s).

+ * + *

e.childIndices() returns the index(es) of the changed node(s).

+ */ + public void treeNodesChanged(TreeModelEvent e) { + if(e != null) { + int changedIndexs[]; + FHTreeStateNode changedParent = getNodeForPath + (SwingUtilities2.getTreePath(e, getModel()), false, false); + int maxCounter; + + changedIndexs = e.getChildIndices(); + /* Only need to update the children if the node has been + expanded once. */ + // PENDING(scott): make sure childIndexs is sorted! + if (changedParent != null) { + if (changedIndexs != null && + (maxCounter = changedIndexs.length) > 0) { + Object parentValue = changedParent.getUserObject(); + + for(int counter = 0; counter < maxCounter; counter++) { + FHTreeStateNode child = changedParent. + getChildAtModelIndex(changedIndexs[counter]); + + if(child != null) { + child.setUserObject(treeModel.getChild(parentValue, + changedIndexs[counter])); + } + } + if(changedParent.isVisible() && changedParent.isExpanded()) + visibleNodesChanged(); + } + // Null for root indicates it changed. + else if (changedParent == root && changedParent.isVisible() && + changedParent.isExpanded()) { + visibleNodesChanged(); + } + } + } + } + + /** + *

Invoked after nodes have been inserted into the tree.

+ * + *

e.path() returns the parent of the new nodes + *

e.childIndices() returns the indices of the new nodes in + * ascending order. + */ + public void treeNodesInserted(TreeModelEvent e) { + if(e != null) { + int changedIndexs[]; + FHTreeStateNode changedParent = getNodeForPath + (SwingUtilities2.getTreePath(e, getModel()), false, false); + int maxCounter; + + changedIndexs = e.getChildIndices(); + /* Only need to update the children if the node has been + expanded once. */ + // PENDING(scott): make sure childIndexs is sorted! + if(changedParent != null && changedIndexs != null && + (maxCounter = changedIndexs.length) > 0) { + boolean isVisible = + (changedParent.isVisible() && + changedParent.isExpanded()); + + for(int counter = 0; counter < maxCounter; counter++) { + changedParent.childInsertedAtModelIndex + (changedIndexs[counter], isVisible); + } + if(isVisible && treeSelectionModel != null) + treeSelectionModel.resetRowSelection(); + if(changedParent.isVisible()) + this.visibleNodesChanged(); + } + } + } + + /** + *

Invoked after nodes have been removed from the tree. Note that + * if a subtree is removed from the tree, this method may only be + * invoked once for the root of the removed subtree, not once for + * each individual set of siblings removed.

+ * + *

e.path() returns the former parent of the deleted nodes.

+ * + *

e.childIndices() returns the indices the nodes had before they were deleted in ascending order.

+ */ + public void treeNodesRemoved(TreeModelEvent e) { + if(e != null) { + int changedIndexs[]; + int maxCounter; + TreePath parentPath = SwingUtilities2.getTreePath(e, getModel()); + FHTreeStateNode changedParentNode = getNodeForPath + (parentPath, false, false); + + changedIndexs = e.getChildIndices(); + // PENDING(scott): make sure that changedIndexs are sorted in + // ascending order. + if(changedParentNode != null && changedIndexs != null && + (maxCounter = changedIndexs.length) > 0) { + Object[] children = e.getChildren(); + boolean isVisible = + (changedParentNode.isVisible() && + changedParentNode.isExpanded()); + + for(int counter = maxCounter - 1; counter >= 0; counter--) { + changedParentNode.removeChildAtModelIndex + (changedIndexs[counter], isVisible); + } + if(isVisible) { + if(treeSelectionModel != null) + treeSelectionModel.resetRowSelection(); + if (treeModel.getChildCount(changedParentNode. + getUserObject()) == 0 && + changedParentNode.isLeaf()) { + // Node has become a leaf, collapse it. + changedParentNode.collapse(false); + } + visibleNodesChanged(); + } + else if(changedParentNode.isVisible()) + visibleNodesChanged(); + } + } + } + + /** + *

Invoked after the tree has drastically changed structure from a + * given node down. If the path returned by e.getPath() is of length + * one and the first element does not identify the current root node + * the first element should become the new root of the tree. + * + *

e.path() holds the path to the node.

+ *

e.childIndices() returns null.

+ */ + public void treeStructureChanged(TreeModelEvent e) { + if(e != null) { + TreePath changedPath = SwingUtilities2.getTreePath(e, getModel()); + FHTreeStateNode changedNode = getNodeForPath + (changedPath, false, false); + + // Check if root has changed, either to a null root, or + // to an entirely new root. + if (changedNode == root || + (changedNode == null && + ((changedPath == null && treeModel != null && + treeModel.getRoot() == null) || + (changedPath != null && changedPath.getPathCount() <= 1)))) { + rebuild(true); + } + else if(changedNode != null) { + boolean wasExpanded, wasVisible; + FHTreeStateNode parent = (FHTreeStateNode) + changedNode.getParent(); + + wasExpanded = changedNode.isExpanded(); + wasVisible = changedNode.isVisible(); + + int index = parent.getIndex(changedNode); + changedNode.collapse(false); + parent.remove(index); + + if(wasVisible && wasExpanded) { + int row = changedNode.getRow(); + parent.resetChildrenRowsFrom(row, index, + changedNode.getChildIndex()); + changedNode = getNodeForPath(changedPath, false, true); + changedNode.expand(); + } + if(treeSelectionModel != null && wasVisible && wasExpanded) + treeSelectionModel.resetRowSelection(); + if(wasVisible) + this.visibleNodesChanged(); + } + } + } + + + // + // Local methods + // + + private void visibleNodesChanged() { + } + + /** + * Returns the bounds for the given node. If childIndex + * is -1, the bounds of parent are returned, otherwise + * the bounds of the node at childIndex are returned. + */ + private Rectangle getBounds(FHTreeStateNode parent, int childIndex, + Rectangle placeIn) { + boolean expanded; + int level; + int row; + Object value; + + if(childIndex == -1) { + // Getting bounds for parent + row = parent.getRow(); + value = parent.getUserObject(); + expanded = parent.isExpanded(); + level = parent.getLevel(); + } + else { + row = parent.getRowToModelIndex(childIndex); + value = treeModel.getChild(parent.getUserObject(), childIndex); + expanded = false; + level = parent.getLevel() + 1; + } + + Rectangle bounds = getNodeDimensions(value, row, level, + expanded, boundsBuffer); + // No node dimensions, bail. + if(bounds == null) + return null; + + if(placeIn == null) + placeIn = new Rectangle(); + + placeIn.x = bounds.x; + placeIn.height = getRowHeight(); + placeIn.y = row * placeIn.height; + placeIn.width = bounds.width; + return placeIn; + } + + /** + * Adjust the large row count of the AbstractTreeUI the receiver was + * created with. + */ + private void adjustRowCountBy(int changeAmount) { + rowCount += changeAmount; + } + + /** + * Adds a mapping for node. + */ + private void addMapping(FHTreeStateNode node) { + treePathMapping.put(node.getTreePath(), node); + } + + /** + * Removes the mapping for a previously added node. + */ + private void removeMapping(FHTreeStateNode node) { + treePathMapping.remove(node.getTreePath()); + } + + /** + * Returns the node previously added for path. This may + * return null, if you to create a node use getNodeForPath. + */ + private FHTreeStateNode getMapping(TreePath path) { + return treePathMapping.get(path); + } + + /** + * Sent to completely rebuild the visible tree. All nodes are collapsed. + */ + private void rebuild(boolean clearSelection) { + Object rootUO; + + treePathMapping.clear(); + if(treeModel != null && (rootUO = treeModel.getRoot()) != null) { + root = createNodeForValue(rootUO, 0); + root.path = new TreePath(rootUO); + addMapping(root); + if(isRootVisible()) { + rowCount = 1; + root.row = 0; + } + else { + rowCount = 0; + root.row = -1; + } + root.expand(); + } + else { + root = null; + rowCount = 0; + } + if(clearSelection && treeSelectionModel != null) { + treeSelectionModel.clearSelection(); + } + this.visibleNodesChanged(); + } + + /** + * Returns the index of the row containing location. If there + * are no rows, -1 is returned. If location is beyond the last + * row index, the last row index is returned. + */ + private int getRowContainingYLocation(int location) { + if(getRowCount() == 0) + return -1; + return Math.max(0, Math.min(getRowCount() - 1, + location / getRowHeight())); + } + + /** + * Ensures that all the path components in path are expanded, accept + * for the last component which will only be expanded if expandLast + * is true. + * Returns true if succesful in finding the path. + */ + private boolean ensurePathIsExpanded(TreePath aPath, + boolean expandLast) { + if(aPath != null) { + // Make sure the last entry isn't a leaf. + if(treeModel.isLeaf(aPath.getLastPathComponent())) { + aPath = aPath.getParentPath(); + expandLast = true; + } + if(aPath != null) { + FHTreeStateNode lastNode = getNodeForPath(aPath, false, + true); + + if(lastNode != null) { + lastNode.makeVisible(); + if(expandLast) + lastNode.expand(); + return true; + } + } + } + return false; + } + + /** + * Creates and returns an instance of FHTreeStateNode. + */ + private FHTreeStateNode createNodeForValue(Object value,int childIndex) { + return new FHTreeStateNode(value, childIndex, -1); + } + + /** + * Messages getTreeNodeForPage(path, onlyIfVisible, shouldCreate, + * path.length) as long as path is non-null and the length is {@literal >} 0. + * Otherwise returns null. + */ + private FHTreeStateNode getNodeForPath(TreePath path, + boolean onlyIfVisible, + boolean shouldCreate) { + if(path != null) { + FHTreeStateNode node; + + node = getMapping(path); + if(node != null) { + if(onlyIfVisible && !node.isVisible()) + return null; + return node; + } + if(onlyIfVisible) + return null; + + // Check all the parent paths, until a match is found. + Stack paths; + + if(tempStacks.size() == 0) { + paths = new Stack(); + } + else { + paths = tempStacks.pop(); + } + + try { + paths.push(path); + path = path.getParentPath(); + node = null; + while(path != null) { + node = getMapping(path); + if(node != null) { + // Found a match, create entries for all paths in + // paths. + while(node != null && paths.size() > 0) { + path = paths.pop(); + node = node.createChildFor(path. + getLastPathComponent()); + } + return node; + } + paths.push(path); + path = path.getParentPath(); + } + } + finally { + paths.removeAllElements(); + tempStacks.push(paths); + } + // If we get here it means they share a different root! + return null; + } + return null; + } + + /** + * FHTreeStateNode is used to track what has been expanded. + * FHTreeStateNode differs from VariableHeightTreeState.TreeStateNode + * in that it is highly model intensive. That is almost all queries to a + * FHTreeStateNode result in the TreeModel being queried. And it + * obviously does not support variable sized row heights. + */ + private class FHTreeStateNode extends DefaultMutableTreeNode { + /** Is this node expanded? */ + protected boolean isExpanded; + + /** Index of this node from the model. */ + protected int childIndex; + + /** Child count of the receiver. */ + protected int childCount; + + /** Row of the receiver. This is only valid if the row is expanded. + */ + protected int row; + + /** Path of this node. */ + protected TreePath path; + + + public FHTreeStateNode(Object userObject, int childIndex, int row) { + super(userObject); + this.childIndex = childIndex; + this.row = row; + } + + // + // Overriden DefaultMutableTreeNode methods + // + + /** + * Messaged when this node is added somewhere, resets the path + * and adds a mapping from path to this node. + */ + public void setParent(MutableTreeNode parent) { + super.setParent(parent); + if(parent != null) { + path = ((FHTreeStateNode)parent).getTreePath(). + pathByAddingChild(getUserObject()); + addMapping(this); + } + } + + /** + * Messaged when this node is removed from its parent, this messages + * removedFromMapping to remove all the children. + */ + public void remove(int childIndex) { + FHTreeStateNode node = (FHTreeStateNode)getChildAt(childIndex); + + node.removeFromMapping(); + super.remove(childIndex); + } + + /** + * Messaged to set the user object. This resets the path. + */ + public void setUserObject(Object o) { + super.setUserObject(o); + if(path != null) { + FHTreeStateNode parent = (FHTreeStateNode)getParent(); + + if(parent != null) + resetChildrenPaths(parent.getTreePath()); + else + resetChildrenPaths(null); + } + } + + // + // + + /** + * Returns the index of the receiver in the model. + */ + public int getChildIndex() { + return childIndex; + } + + /** + * Returns the TreePath of the receiver. + */ + public TreePath getTreePath() { + return path; + } + + /** + * Returns the child for the passed in model index, this will + * return null if the child for index + * has not yet been created (expanded). + */ + public FHTreeStateNode getChildAtModelIndex(int index) { + // PENDING: Make this a binary search! + for(int counter = getChildCount() - 1; counter >= 0; counter--) + if(((FHTreeStateNode)getChildAt(counter)).childIndex == index) + return (FHTreeStateNode)getChildAt(counter); + return null; + } + + /** + * Returns true if this node is visible. This is determined by + * asking all the parents if they are expanded. + */ + public boolean isVisible() { + FHTreeStateNode parent = (FHTreeStateNode)getParent(); + + if(parent == null) + return true; + return (parent.isExpanded() && parent.isVisible()); + } + + /** + * Returns the row of the receiver. + */ + public int getRow() { + return row; + } + + /** + * Returns the row of the child with a model index of + * index. + */ + public int getRowToModelIndex(int index) { + FHTreeStateNode child; + int lastRow = getRow() + 1; + int retValue = lastRow; + + // This too could be a binary search! + for(int counter = 0, maxCounter = getChildCount(); + counter < maxCounter; counter++) { + child = (FHTreeStateNode)getChildAt(counter); + if(child.childIndex >= index) { + if(child.childIndex == index) + return child.row; + if(counter == 0) + return getRow() + 1 + index; + return child.row - (child.childIndex - index); + } + } + // YECK! + return getRow() + 1 + getTotalChildCount() - + (childCount - index); + } + + /** + * Returns the number of children in the receiver by descending all + * expanded nodes and messaging them with getTotalChildCount. + */ + public int getTotalChildCount() { + if(isExpanded()) { + FHTreeStateNode parent = (FHTreeStateNode)getParent(); + int pIndex; + + if(parent != null && (pIndex = parent.getIndex(this)) + 1 < + parent.getChildCount()) { + // This node has a created sibling, to calc total + // child count directly from that! + FHTreeStateNode nextSibling = (FHTreeStateNode)parent. + getChildAt(pIndex + 1); + + return nextSibling.row - row - + (nextSibling.childIndex - childIndex); + } + else { + int retCount = childCount; + + for(int counter = getChildCount() - 1; counter >= 0; + counter--) { + retCount += ((FHTreeStateNode)getChildAt(counter)) + .getTotalChildCount(); + } + return retCount; + } + } + return 0; + } + + /** + * Returns true if this node is expanded. + */ + public boolean isExpanded() { + return isExpanded; + } + + /** + * The highest visible nodes have a depth of 0. + */ + public int getVisibleLevel() { + if (isRootVisible()) { + return getLevel(); + } else { + return getLevel() - 1; + } + } + + /** + * Recreates the receivers path, and all its children's paths. + */ + protected void resetChildrenPaths(TreePath parentPath) { + removeMapping(this); + if(parentPath == null) + path = new TreePath(getUserObject()); + else + path = parentPath.pathByAddingChild(getUserObject()); + addMapping(this); + for(int counter = getChildCount() - 1; counter >= 0; counter--) + ((FHTreeStateNode)getChildAt(counter)). + resetChildrenPaths(path); + } + + /** + * Removes the receiver, and all its children, from the mapping + * table. + */ + protected void removeFromMapping() { + if(path != null) { + removeMapping(this); + for(int counter = getChildCount() - 1; counter >= 0; counter--) + ((FHTreeStateNode)getChildAt(counter)).removeFromMapping(); + } + } + + /** + * Creates a new node to represent userObject. + * This does NOT check to ensure there isn't already a child node + * to manage userObject. + */ + protected FHTreeStateNode createChildFor(Object userObject) { + int newChildIndex = treeModel.getIndexOfChild + (getUserObject(), userObject); + + if(newChildIndex < 0) + return null; + + FHTreeStateNode aNode; + FHTreeStateNode child = createNodeForValue(userObject, + newChildIndex); + int childRow; + + if(isVisible()) { + childRow = getRowToModelIndex(newChildIndex); + } + else { + childRow = -1; + } + child.row = childRow; + for(int counter = 0, maxCounter = getChildCount(); + counter < maxCounter; counter++) { + aNode = (FHTreeStateNode)getChildAt(counter); + if(aNode.childIndex > newChildIndex) { + insert(child, counter); + return child; + } + } + add(child); + return child; + } + + /** + * Adjusts the receiver, and all its children rows by + * amount. + */ + protected void adjustRowBy(int amount) { + row += amount; + if(isExpanded) { + for(int counter = getChildCount() - 1; counter >= 0; + counter--) + ((FHTreeStateNode)getChildAt(counter)).adjustRowBy(amount); + } + } + + /** + * Adjusts this node, its child, and its parent starting at + * an index of index index is the index of the child + * to start adjusting from, which is not necessarily the model + * index. + */ + protected void adjustRowBy(int amount, int startIndex) { + // Could check isVisible, but probably isn't worth it. + if(isExpanded) { + // children following startIndex. + for(int counter = getChildCount() - 1; counter >= startIndex; + counter--) + ((FHTreeStateNode)getChildAt(counter)).adjustRowBy(amount); + } + // Parent + FHTreeStateNode parent = (FHTreeStateNode)getParent(); + + if(parent != null) { + parent.adjustRowBy(amount, parent.getIndex(this) + 1); + } + } + + /** + * Messaged when the node has expanded. This updates all of + * the receivers children rows, as well as the total row count. + */ + protected void didExpand() { + int nextRow = setRowAndChildren(row); + FHTreeStateNode parent = (FHTreeStateNode)getParent(); + int childRowCount = nextRow - row - 1; + + if(parent != null) { + parent.adjustRowBy(childRowCount, parent.getIndex(this) + 1); + } + adjustRowCountBy(childRowCount); + } + + /** + * Sets the receivers row to nextRow and recursively + * updates all the children of the receivers rows. The index the + * next row is to be placed as is returned. + */ + protected int setRowAndChildren(int nextRow) { + row = nextRow; + + if(!isExpanded()) + return row + 1; + + int lastRow = row + 1; + int lastModelIndex = 0; + FHTreeStateNode child; + int maxCounter = getChildCount(); + + for(int counter = 0; counter < maxCounter; counter++) { + child = (FHTreeStateNode)getChildAt(counter); + lastRow += (child.childIndex - lastModelIndex); + lastModelIndex = child.childIndex + 1; + if(child.isExpanded) { + lastRow = child.setRowAndChildren(lastRow); + } + else { + child.row = lastRow++; + } + } + return lastRow + childCount - lastModelIndex; + } + + /** + * Resets the receivers children's rows. Starting with the child + * at childIndex (and modelIndex) to + * newRow. This uses setRowAndChildren + * to recursively descend children, and uses + * resetRowSelection to ascend parents. + */ + // This can be rather expensive, but is needed for the collapse + // case this is resulting from a remove (although I could fix + // that by having instances of FHTreeStateNode hold a ref to + // the number of children). I prefer this though, making determing + // the row of a particular node fast is very nice! + protected void resetChildrenRowsFrom(int newRow, int childIndex, + int modelIndex) { + int lastRow = newRow; + int lastModelIndex = modelIndex; + FHTreeStateNode node; + int maxCounter = getChildCount(); + + for(int counter = childIndex; counter < maxCounter; counter++) { + node = (FHTreeStateNode)getChildAt(counter); + lastRow += (node.childIndex - lastModelIndex); + lastModelIndex = node.childIndex + 1; + if(node.isExpanded) { + lastRow = node.setRowAndChildren(lastRow); + } + else { + node.row = lastRow++; + } + } + lastRow += childCount - lastModelIndex; + node = (FHTreeStateNode)getParent(); + if(node != null) { + node.resetChildrenRowsFrom(lastRow, node.getIndex(this) + 1, + this.childIndex + 1); + } + else { // This is the root, reset total ROWCOUNT! + rowCount = lastRow; + } + } + + /** + * Makes the receiver visible, but invoking + * expandParentAndReceiver on the superclass. + */ + protected void makeVisible() { + FHTreeStateNode parent = (FHTreeStateNode)getParent(); + + if(parent != null) + parent.expandParentAndReceiver(); + } + + /** + * Invokes expandParentAndReceiver on the parent, + * and expands the receiver. + */ + protected void expandParentAndReceiver() { + FHTreeStateNode parent = (FHTreeStateNode)getParent(); + + if(parent != null) + parent.expandParentAndReceiver(); + expand(); + } + + /** + * Expands the receiver. + */ + protected void expand() { + if(!isExpanded && !isLeaf()) { + boolean visible = isVisible(); + + isExpanded = true; + childCount = treeModel.getChildCount(getUserObject()); + + if(visible) { + didExpand(); + } + + // Update the selection model. + if(visible && treeSelectionModel != null) { + treeSelectionModel.resetRowSelection(); + } + } + } + + /** + * Collapses the receiver. If adjustRows is true, + * the rows of nodes after the receiver are adjusted. + */ + protected void collapse(boolean adjustRows) { + if(isExpanded) { + if(isVisible() && adjustRows) { + int childCount = getTotalChildCount(); + + isExpanded = false; + adjustRowCountBy(-childCount); + // We can do this because adjustRowBy won't descend + // the children. + adjustRowBy(-childCount, 0); + } + else + isExpanded = false; + + if(adjustRows && isVisible() && treeSelectionModel != null) + treeSelectionModel.resetRowSelection(); + } + } + + /** + * Returns true if the receiver is a leaf. + */ + public boolean isLeaf() { + TreeModel model = getModel(); + + return (model != null) ? model.isLeaf(this.getUserObject()) : + true; + } + + /** + * Adds newChild to this nodes children at the appropriate location. + * The location is determined from the childIndex of newChild. + */ + protected void addNode(FHTreeStateNode newChild) { + boolean added = false; + int childIndex = newChild.getChildIndex(); + + for(int counter = 0, maxCounter = getChildCount(); + counter < maxCounter; counter++) { + if(((FHTreeStateNode)getChildAt(counter)).getChildIndex() > + childIndex) { + added = true; + insert(newChild, counter); + counter = maxCounter; + } + } + if(!added) + add(newChild); + } + + /** + * Removes the child at modelIndex. + * isChildVisible should be true if the receiver + * is visible and expanded. + */ + protected void removeChildAtModelIndex(int modelIndex, + boolean isChildVisible) { + FHTreeStateNode childNode = getChildAtModelIndex(modelIndex); + + if(childNode != null) { + int row = childNode.getRow(); + int index = getIndex(childNode); + + childNode.collapse(false); + remove(index); + adjustChildIndexs(index, -1); + childCount--; + if(isChildVisible) { + // Adjust the rows. + resetChildrenRowsFrom(row, index, modelIndex); + } + } + else { + int maxCounter = getChildCount(); + FHTreeStateNode aChild; + + for(int counter = 0; counter < maxCounter; counter++) { + aChild = (FHTreeStateNode)getChildAt(counter); + if(aChild.childIndex >= modelIndex) { + if(isChildVisible) { + adjustRowBy(-1, counter); + adjustRowCountBy(-1); + } + // Since matched and children are always sorted by + // index, no need to continue testing with the + // above. + for(; counter < maxCounter; counter++) + ((FHTreeStateNode)getChildAt(counter)). + childIndex--; + childCount--; + return; + } + } + // No children to adjust, but it was a child, so we still need + // to adjust nodes after this one. + if(isChildVisible) { + adjustRowBy(-1, maxCounter); + adjustRowCountBy(-1); + } + childCount--; + } + } + + /** + * Adjusts the child indexs of the receivers children by + * amount, starting at index. + */ + protected void adjustChildIndexs(int index, int amount) { + for(int counter = index, maxCounter = getChildCount(); + counter < maxCounter; counter++) { + ((FHTreeStateNode)getChildAt(counter)).childIndex += amount; + } + } + + /** + * Messaged when a child has been inserted at index. For all the + * children that have a childIndex ≥ index their index is incremented + * by one. + */ + protected void childInsertedAtModelIndex(int index, + boolean isExpandedAndVisible) { + FHTreeStateNode aChild; + int maxCounter = getChildCount(); + + for(int counter = 0; counter < maxCounter; counter++) { + aChild = (FHTreeStateNode)getChildAt(counter); + if(aChild.childIndex >= index) { + if(isExpandedAndVisible) { + adjustRowBy(1, counter); + adjustRowCountBy(1); + } + /* Since matched and children are always sorted by + index, no need to continue testing with the above. */ + for(; counter < maxCounter; counter++) + ((FHTreeStateNode)getChildAt(counter)).childIndex++; + childCount++; + return; + } + } + // No children to adjust, but it was a child, so we still need + // to adjust nodes after this one. + if(isExpandedAndVisible) { + adjustRowBy(1, maxCounter); + adjustRowCountBy(1); + } + childCount++; + } + + /** + * Returns true if there is a row for row. + * nextRow gives the bounds of the receiver. + * Information about the found row is returned in info. + * This should be invoked on root with nextRow set + * to getRowCount(). + */ + protected boolean getPathForRow(int row, int nextRow, + SearchInfo info) { + if(this.row == row) { + info.node = this; + info.isNodeParentNode = false; + info.childIndex = childIndex; + return true; + } + + FHTreeStateNode child; + FHTreeStateNode lastChild = null; + + for(int counter = 0, maxCounter = getChildCount(); + counter < maxCounter; counter++) { + child = (FHTreeStateNode)getChildAt(counter); + if(child.row > row) { + if(counter == 0) { + // No node exists for it, and is first. + info.node = this; + info.isNodeParentNode = true; + info.childIndex = row - this.row - 1; + return true; + } + else { + // May have been in last child's bounds. + int lastChildEndRow = 1 + child.row - + (child.childIndex - lastChild.childIndex); + + if(row < lastChildEndRow) { + return lastChild.getPathForRow(row, + lastChildEndRow, info); + } + // Between last child and child, but not in last child + info.node = this; + info.isNodeParentNode = true; + info.childIndex = row - lastChildEndRow + + lastChild.childIndex + 1; + return true; + } + } + lastChild = child; + } + + // Not in children, but we should have it, offset from + // nextRow. + if(lastChild != null) { + int lastChildEndRow = nextRow - + (childCount - lastChild.childIndex) + 1; + + if(row < lastChildEndRow) { + return lastChild.getPathForRow(row, lastChildEndRow, info); + } + // Between last child and child, but not in last child + info.node = this; + info.isNodeParentNode = true; + info.childIndex = row - lastChildEndRow + + lastChild.childIndex + 1; + return true; + } + else { + // No children. + int retChildIndex = row - this.row - 1; + + if(retChildIndex >= childCount) { + return false; + } + info.node = this; + info.isNodeParentNode = true; + info.childIndex = retChildIndex; + return true; + } + } + + /** + * Asks all the children of the receiver for their totalChildCount + * and returns this value (plus stopIndex). + */ + protected int getCountTo(int stopIndex) { + FHTreeStateNode aChild; + int retCount = stopIndex + 1; + + for(int counter = 0, maxCounter = getChildCount(); + counter < maxCounter; counter++) { + aChild = (FHTreeStateNode)getChildAt(counter); + if(aChild.childIndex >= stopIndex) + counter = maxCounter; + else + retCount += aChild.getTotalChildCount(); + } + if(parent != null) + return retCount + ((FHTreeStateNode)getParent()) + .getCountTo(childIndex); + if(!isRootVisible()) + return (retCount - 1); + return retCount; + } + + /** + * Returns the number of children that are expanded to + * stopIndex. This does not include the number + * of children that the child at stopIndex might + * have. + */ + protected int getNumExpandedChildrenTo(int stopIndex) { + FHTreeStateNode aChild; + int retCount = stopIndex; + + for(int counter = 0, maxCounter = getChildCount(); + counter < maxCounter; counter++) { + aChild = (FHTreeStateNode)getChildAt(counter); + if(aChild.childIndex >= stopIndex) + return retCount; + else { + retCount += aChild.getTotalChildCount(); + } + } + return retCount; + } + + /** + * Messaged when this node either expands or collapses. + */ + protected void didAdjustTree() { + } + + } // FixedHeightLayoutCache.FHTreeStateNode + + + /** + * Used as a placeholder when getting the path in FHTreeStateNodes. + */ + private class SearchInfo { + protected FHTreeStateNode node; + protected boolean isNodeParentNode; + protected int childIndex; + + protected TreePath getPath() { + if(node == null) + return null; + + if(isNodeParentNode) + return node.getTreePath().pathByAddingChild(treeModel.getChild + (node.getUserObject(), + childIndex)); + return node.path; + } + } // FixedHeightLayoutCache.SearchInfo + + + /** + * An enumerator to iterate through visible nodes. + */ + // This is very similar to + // VariableHeightTreeState.VisibleTreeStateNodeEnumeration + private class VisibleFHTreeStateNodeEnumeration + implements Enumeration + { + /** Parent thats children are being enumerated. */ + protected FHTreeStateNode parent; + /** Index of next child. An index of -1 signifies parent should be + * visibled next. */ + protected int nextIndex; + /** Number of children in parent. */ + protected int childCount; + + protected VisibleFHTreeStateNodeEnumeration(FHTreeStateNode node) { + this(node, -1); + } + + protected VisibleFHTreeStateNodeEnumeration(FHTreeStateNode parent, + int startIndex) { + this.parent = parent; + this.nextIndex = startIndex; + this.childCount = treeModel.getChildCount(this.parent. + getUserObject()); + } + + /** + * @return true if more visible nodes. + */ + public boolean hasMoreElements() { + return (parent != null); + } + + /** + * @return next visible TreePath. + */ + public TreePath nextElement() { + if(!hasMoreElements()) + throw new NoSuchElementException("No more visible paths"); + + TreePath retObject; + + if(nextIndex == -1) + retObject = parent.getTreePath(); + else { + FHTreeStateNode node = parent.getChildAtModelIndex(nextIndex); + + if(node == null) + retObject = parent.getTreePath().pathByAddingChild + (treeModel.getChild(parent.getUserObject(), + nextIndex)); + else + retObject = node.getTreePath(); + } + updateNextObject(); + return retObject; + } + + /** + * Determines the next object by invoking updateNextIndex + * and if not succesful findNextValidParent. + */ + protected void updateNextObject() { + if(!updateNextIndex()) { + findNextValidParent(); + } + } + + /** + * Finds the next valid parent, this should be called when nextIndex + * is beyond the number of children of the current parent. + */ + protected boolean findNextValidParent() { + if(parent == root) { + // mark as invalid! + parent = null; + return false; + } + while(parent != null) { + FHTreeStateNode newParent = (FHTreeStateNode)parent. + getParent(); + + if(newParent != null) { + nextIndex = parent.childIndex; + parent = newParent; + childCount = treeModel.getChildCount + (parent.getUserObject()); + if(updateNextIndex()) + return true; + } + else + parent = null; + } + return false; + } + + /** + * Updates nextIndex returning false if it is beyond + * the number of children of parent. + */ + protected boolean updateNextIndex() { + // nextIndex == -1 identifies receiver, make sure is expanded + // before descend. + if(nextIndex == -1 && !parent.isExpanded()) { + return false; + } + + // Check that it can have kids + if(childCount == 0) { + return false; + } + // Make sure next index not beyond child count. + else if(++nextIndex >= childCount) { + return false; + } + + FHTreeStateNode child = parent.getChildAtModelIndex(nextIndex); + + if(child != null && child.isExpanded()) { + parent = child; + nextIndex = -1; + childCount = treeModel.getChildCount(child.getUserObject()); + } + return true; + } + } // FixedHeightLayoutCache.VisibleFHTreeStateNodeEnumeration +} diff --git a/sources/net.sf.j2s.java.core/src/javax/swing/tree/VariableHeightLayoutCache.java b/sources/net.sf.j2s.java.core/src/javax/swing/tree/VariableHeightLayoutCache.java new file mode 100644 index 000000000..ca60ea86c --- /dev/null +++ b/sources/net.sf.j2s.java.core/src/javax/swing/tree/VariableHeightLayoutCache.java @@ -0,0 +1,1768 @@ +/* + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javax.swing.tree; + +import javax.swing.event.TreeModelEvent; +import java.awt.Rectangle; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.NoSuchElementException; +import java.util.Stack; +import java.util.Vector; + +import sun.swing.SwingUtilities2; + +/** + * NOTE: This will become more open in a future release. + *

+ * Warning: + * Serialized objects of this class will not be compatible with + * future Swing releases. The current serialization support is + * appropriate for short term storage or RMI between applications running + * the same version of Swing. As of 1.4, support for long term storage + * of all JavaBeans™ + * has been added to the java.beans package. + * Please see {@link java.beans.XMLEncoder}. + * + * @author Rob Davis + * @author Ray Ryan + * @author Scott Violet + */ + +public class VariableHeightLayoutCache extends AbstractLayoutCache { + /** + * The array of nodes that are currently visible, in the order they + * are displayed. + */ + private Vector visibleNodes; + + /** + * This is set to true if one of the entries has an invalid size. + */ + private boolean updateNodeSizes; + + /** + * The root node of the internal cache of nodes that have been shown. + * If the treeModel is vending a network rather than a true tree, + * there may be one cached node for each path to a modeled node. + */ + private TreeStateNode root; + + /** + * Used in getting sizes for nodes to avoid creating a new Rectangle + * every time a size is needed. + */ + private Rectangle boundsBuffer; + + /** + * Maps from TreePath to a TreeStateNode. + */ + private Hashtable treePathMapping; + + /** + * A stack of stacks. + */ + private Stack> tempStacks; + + + public VariableHeightLayoutCache() { + super(); + tempStacks = new Stack>(); + visibleNodes = new Vector(); + boundsBuffer = new Rectangle(); + treePathMapping = new Hashtable(); + } + + /** + * Sets the TreeModel that will provide the data. + * + * @param newModel the TreeModel that is to provide the data + * @beaninfo + * bound: true + * description: The TreeModel that will provide the data. + */ + public void setModel(TreeModel newModel) { + super.setModel(newModel); + rebuild(false); + } + + /** + * Determines whether or not the root node from + * the TreeModel is visible. + * + * @param rootVisible true if the root node of the tree is to be displayed + * @see #rootVisible + * @beaninfo + * bound: true + * description: Whether or not the root node + * from the TreeModel is visible. + */ + public void setRootVisible(boolean rootVisible) { + if(isRootVisible() != rootVisible && root != null) { + if(rootVisible) { + root.updatePreferredSize(0); + visibleNodes.insertElementAt(root, 0); + } + else if(visibleNodes.size() > 0) { + visibleNodes.removeElementAt(0); + if(treeSelectionModel != null) + treeSelectionModel.removeSelectionPath + (root.getTreePath()); + } + if(treeSelectionModel != null) + treeSelectionModel.resetRowSelection(); + if(getRowCount() > 0) + getNode(0).setYOrigin(0); + updateYLocationsFrom(0); + visibleNodesChanged(); + } + super.setRootVisible(rootVisible); + } + + /** + * Sets the height of each cell. If the specified value + * is less than or equal to zero the current cell renderer is + * queried for each row's height. + * + * @param rowHeight the height of each cell, in pixels + * @beaninfo + * bound: true + * description: The height of each cell. + */ + public void setRowHeight(int rowHeight) { + if(rowHeight != getRowHeight()) { + super.setRowHeight(rowHeight); + invalidateSizes(); + this.visibleNodesChanged(); + } + } + + /** + * Sets the renderer that is responsible for drawing nodes in the tree. + * @param nd the renderer + */ + public void setNodeDimensions(NodeDimensions nd) { + super.setNodeDimensions(nd); + invalidateSizes(); + visibleNodesChanged(); + } + + /** + * Marks the path path expanded state to + * isExpanded. + * @param path the TreePath of interest + * @param isExpanded true if the path should be expanded, otherwise false + */ + public void setExpandedState(TreePath path, boolean isExpanded) { + if(path != null) { + if(isExpanded) + ensurePathIsExpanded(path, true); + else { + TreeStateNode node = getNodeForPath(path, false, true); + + if(node != null) { + node.makeVisible(); + node.collapse(); + } + } + } + } + + /** + * Returns true if the path is expanded, and visible. + * @return true if the path is expanded and visible, otherwise false + */ + public boolean getExpandedState(TreePath path) { + TreeStateNode node = getNodeForPath(path, true, false); + + return (node != null) ? (node.isVisible() && node.isExpanded()) : + false; + } + + /** + * Returns the Rectangle enclosing the label portion + * into which the item identified by path will be drawn. + * + * @param path the path to be drawn + * @param placeIn the bounds of the enclosing rectangle + * @return the bounds of the enclosing rectangle or null + * if the node could not be ascertained + */ + public Rectangle getBounds(TreePath path, Rectangle placeIn) { + TreeStateNode node = getNodeForPath(path, true, false); + + if(node != null) { + if(updateNodeSizes) + updateNodeSizes(false); + return node.getNodeBounds(placeIn); + } + return null; + } + + /** + * Returns the path for row. If row + * is not visible, null is returned. + * + * @param row the location of interest + * @return the path for row, or null + * if row is not visible + */ + public TreePath getPathForRow(int row) { + if(row >= 0 && row < getRowCount()) { + return getNode(row).getTreePath(); + } + return null; + } + + /** + * Returns the row where the last item identified in path is visible. + * Will return -1 if any of the elements in path are not + * currently visible. + * + * @param path the TreePath of interest + * @return the row where the last item in path is visible + */ + public int getRowForPath(TreePath path) { + if(path == null) + return -1; + + TreeStateNode visNode = getNodeForPath(path, true, false); + + if(visNode != null) + return visNode.getRow(); + return -1; + } + + /** + * Returns the number of visible rows. + * @return the number of visible rows + */ + public int getRowCount() { + return visibleNodes.size(); + } + + /** + * Instructs the LayoutCache that the bounds for + * path are invalid, and need to be updated. + * + * @param path the TreePath which is now invalid + */ + public void invalidatePathBounds(TreePath path) { + TreeStateNode node = getNodeForPath(path, true, false); + + if(node != null) { + node.markSizeInvalid(); + if(node.isVisible()) + updateYLocationsFrom(node.getRow()); + } + } + + /** + * Returns the preferred height. + * @return the preferred height + */ + public int getPreferredHeight() { + // Get the height + int rowCount = getRowCount(); + + if(rowCount > 0) { + TreeStateNode node = getNode(rowCount - 1); + + return node.getYOrigin() + node.getPreferredHeight(); + } + return 0; + } + + /** + * Returns the preferred width and height for the region in + * visibleRegion. + * + * @param bounds the region being queried + */ + public int getPreferredWidth(Rectangle bounds) { + if(updateNodeSizes) + updateNodeSizes(false); + + return getMaxNodeWidth(); + } + + /** + * Returns the path to the node that is closest to x,y. If + * there is nothing currently visible this will return null, + * otherwise it will always return a valid path. + * If you need to test if the + * returned object is exactly at x, y you should get the bounds for + * the returned path and test x, y against that. + * + * @param x the x-coordinate + * @param y the y-coordinate + * @return the path to the node that is closest to x, y + */ + public TreePath getPathClosestTo(int x, int y) { + if(getRowCount() == 0) + return null; + + if(updateNodeSizes) + updateNodeSizes(false); + + int row = getRowContainingYLocation(y); + + return getNode(row).getTreePath(); + } + + /** + * Returns an Enumerator that increments over the visible paths + * starting at the passed in location. The ordering of the enumeration + * is based on how the paths are displayed. + * + * @param path the location in the TreePath to start + * @return an Enumerator that increments over the visible + * paths + */ + public Enumeration getVisiblePathsFrom(TreePath path) { + TreeStateNode node = getNodeForPath(path, true, false); + + if(node != null) { + return new VisibleTreeStateNodeEnumeration(node); + } + return null; + } + + /** + * Returns the number of visible children for path. + * @return the number of visible children for path + */ + public int getVisibleChildCount(TreePath path) { + TreeStateNode node = getNodeForPath(path, true, false); + + return (node != null) ? node.getVisibleChildCount() : 0; + } + + /** + * Informs the TreeState that it needs to recalculate + * all the sizes it is referencing. + */ + public void invalidateSizes() { + if(root != null) + root.deepMarkSizeInvalid(); + if(!isFixedRowHeight() && visibleNodes.size() > 0) { + updateNodeSizes(true); + } + } + + /** + * Returns true if the value identified by path is + * currently expanded. + * @return true if the value identified by path is + * currently expanded + */ + public boolean isExpanded(TreePath path) { + if(path != null) { + TreeStateNode lastNode = getNodeForPath(path, true, false); + + return (lastNode != null && lastNode.isExpanded()); + } + return false; + } + + // + // TreeModelListener methods + // + + /** + * Invoked after a node (or a set of siblings) has changed in some + * way. The node(s) have not changed locations in the tree or + * altered their children arrays, but other attributes have + * changed and may affect presentation. Example: the name of a + * file has changed, but it is in the same location in the file + * system. + * + *

e.path returns the path the parent of the + * changed node(s). + * + *

e.childIndices returns the index(es) of the + * changed node(s). + * + * @param e the TreeModelEvent of interest + */ + public void treeNodesChanged(TreeModelEvent e) { + if(e != null) { + int changedIndexs[]; + TreeStateNode changedNode; + + changedIndexs = e.getChildIndices(); + changedNode = getNodeForPath(SwingUtilities2.getTreePath(e, getModel()), false, false); + if(changedNode != null) { + Object changedValue = changedNode.getValue(); + + /* Update the size of the changed node, as well as all the + child indexs that are passed in. */ + changedNode.updatePreferredSize(); + if(changedNode.hasBeenExpanded() && changedIndexs != null) { + int counter; + TreeStateNode changedChildNode; + + for(counter = 0; counter < changedIndexs.length; + counter++) { + changedChildNode = (TreeStateNode)changedNode + .getChildAt(changedIndexs[counter]); + /* Reset the user object. */ + changedChildNode.setUserObject + (treeModel.getChild(changedValue, + changedIndexs[counter])); + changedChildNode.updatePreferredSize(); + } + } + else if (changedNode == root) { + // Null indicies for root indicates it changed. + changedNode.updatePreferredSize(); + } + if(!isFixedRowHeight()) { + int aRow = changedNode.getRow(); + + if(aRow != -1) + this.updateYLocationsFrom(aRow); + } + this.visibleNodesChanged(); + } + } + } + + + /** + * Invoked after nodes have been inserted into the tree. + * + *

e.path returns the parent of the new nodes. + *

e.childIndices returns the indices of the new nodes in + * ascending order. + * + * @param e the TreeModelEvent of interest + */ + public void treeNodesInserted(TreeModelEvent e) { + if(e != null) { + int changedIndexs[]; + TreeStateNode changedParentNode; + + changedIndexs = e.getChildIndices(); + changedParentNode = getNodeForPath(SwingUtilities2.getTreePath(e, getModel()), false, false); + /* Only need to update the children if the node has been + expanded once. */ + // PENDING(scott): make sure childIndexs is sorted! + if(changedParentNode != null && changedIndexs != null && + changedIndexs.length > 0) { + if(changedParentNode.hasBeenExpanded()) { + boolean makeVisible; + int counter; + Object changedParent; + TreeStateNode newNode; + int oldChildCount = changedParentNode. + getChildCount(); + + changedParent = changedParentNode.getValue(); + makeVisible = ((changedParentNode == root && + !rootVisible) || + (changedParentNode.getRow() != -1 && + changedParentNode.isExpanded())); + for(counter = 0;counter < changedIndexs.length;counter++) + { + newNode = this.createNodeAt(changedParentNode, + changedIndexs[counter]); + } + if(oldChildCount == 0) { + // Update the size of the parent. + changedParentNode.updatePreferredSize(); + } + if(treeSelectionModel != null) + treeSelectionModel.resetRowSelection(); + /* Update the y origins from the index of the parent + to the end of the visible rows. */ + if(!isFixedRowHeight() && (makeVisible || + (oldChildCount == 0 && + changedParentNode.isVisible()))) { + if(changedParentNode == root) + this.updateYLocationsFrom(0); + else + this.updateYLocationsFrom(changedParentNode. + getRow()); + this.visibleNodesChanged(); + } + else if(makeVisible) + this.visibleNodesChanged(); + } + else if(treeModel.getChildCount(changedParentNode.getValue()) + - changedIndexs.length == 0) { + changedParentNode.updatePreferredSize(); + if(!isFixedRowHeight() && changedParentNode.isVisible()) + updateYLocationsFrom(changedParentNode.getRow()); + } + } + } + } + + /** + * Invoked after nodes have been removed from the tree. Note that + * if a subtree is removed from the tree, this method may only be + * invoked once for the root of the removed subtree, not once for + * each individual set of siblings removed. + * + *

e.path returns the former parent of the deleted nodes. + * + *

e.childIndices returns the indices the nodes had + * before they were deleted in ascending order. + * + * @param e the TreeModelEvent of interest + */ + public void treeNodesRemoved(TreeModelEvent e) { + if(e != null) { + int changedIndexs[]; + TreeStateNode changedParentNode; + + changedIndexs = e.getChildIndices(); + changedParentNode = getNodeForPath(SwingUtilities2.getTreePath(e, getModel()), false, false); + // PENDING(scott): make sure that changedIndexs are sorted in + // ascending order. + if(changedParentNode != null && changedIndexs != null && + changedIndexs.length > 0) { + if(changedParentNode.hasBeenExpanded()) { + boolean makeInvisible; + int counter; + int removedRow; + TreeStateNode removedNode; + + makeInvisible = ((changedParentNode == root && + !rootVisible) || + (changedParentNode.getRow() != -1 && + changedParentNode.isExpanded())); + for(counter = changedIndexs.length - 1;counter >= 0; + counter--) { + removedNode = (TreeStateNode)changedParentNode. + getChildAt(changedIndexs[counter]); + if(removedNode.isExpanded()) { + removedNode.collapse(false); + } + + /* Let the selection model now. */ + if(makeInvisible) { + removedRow = removedNode.getRow(); + if(removedRow != -1) { + visibleNodes.removeElementAt(removedRow); + } + } + changedParentNode.remove(changedIndexs[counter]); + } + if(changedParentNode.getChildCount() == 0) { + // Update the size of the parent. + changedParentNode.updatePreferredSize(); + if (changedParentNode.isExpanded() && + changedParentNode.isLeaf()) { + // Node has become a leaf, collapse it. + changedParentNode.collapse(false); + } + } + if(treeSelectionModel != null) + treeSelectionModel.resetRowSelection(); + /* Update the y origins from the index of the parent + to the end of the visible rows. */ + if(!isFixedRowHeight() && (makeInvisible || + (changedParentNode.getChildCount() == 0 && + changedParentNode.isVisible()))) { + if(changedParentNode == root) { + /* It is possible for first row to have been + removed if the root isn't visible, in which + case ylocations will be off! */ + if(getRowCount() > 0) + getNode(0).setYOrigin(0); + updateYLocationsFrom(0); + } + else + updateYLocationsFrom(changedParentNode.getRow()); + this.visibleNodesChanged(); + } + else if(makeInvisible) + this.visibleNodesChanged(); + } + else if(treeModel.getChildCount(changedParentNode.getValue()) + == 0) { + changedParentNode.updatePreferredSize(); + if(!isFixedRowHeight() && changedParentNode.isVisible()) + this.updateYLocationsFrom(changedParentNode.getRow()); + } + } + } + } + + /** + * Invoked after the tree has drastically changed structure from a + * given node down. If the path returned by e.getPath + * is of length one and the first element does not identify the + * current root node the first element should become the new root + * of the tree. + * + *

e.path holds the path to the node. + *

e.childIndices returns null. + * + * @param e the TreeModelEvent of interest + */ + public void treeStructureChanged(TreeModelEvent e) { + if(e != null) + { + TreePath changedPath = SwingUtilities2.getTreePath(e, getModel()); + TreeStateNode changedNode; + + changedNode = getNodeForPath(changedPath, false, false); + + // Check if root has changed, either to a null root, or + // to an entirely new root. + if(changedNode == root || + (changedNode == null && + ((changedPath == null && treeModel != null && + treeModel.getRoot() == null) || + (changedPath != null && changedPath.getPathCount() == 1)))) { + rebuild(true); + } + else if(changedNode != null) { + int nodeIndex, oldRow; + TreeStateNode newNode, parent; + boolean wasExpanded, wasVisible; + int newIndex; + + wasExpanded = changedNode.isExpanded(); + wasVisible = (changedNode.getRow() != -1); + /* Remove the current node and recreate a new one. */ + parent = (TreeStateNode)changedNode.getParent(); + nodeIndex = parent.getIndex(changedNode); + if(wasVisible && wasExpanded) { + changedNode.collapse(false); + } + if(wasVisible) + visibleNodes.removeElement(changedNode); + changedNode.removeFromParent(); + createNodeAt(parent, nodeIndex); + newNode = (TreeStateNode)parent.getChildAt(nodeIndex); + if(wasVisible && wasExpanded) + newNode.expand(false); + newIndex = newNode.getRow(); + if(!isFixedRowHeight() && wasVisible) { + if(newIndex == 0) + updateYLocationsFrom(newIndex); + else + updateYLocationsFrom(newIndex - 1); + this.visibleNodesChanged(); + } + else if(wasVisible) + this.visibleNodesChanged(); + } + } + } + + + // + // Local methods + // + + private void visibleNodesChanged() { + } + + /** + * Adds a mapping for node. + */ + private void addMapping(TreeStateNode node) { + treePathMapping.put(node.getTreePath(), node); + } + + /** + * Removes the mapping for a previously added node. + */ + private void removeMapping(TreeStateNode node) { + treePathMapping.remove(node.getTreePath()); + } + + /** + * Returns the node previously added for path. This may + * return null, if you to create a node use getNodeForPath. + */ + private TreeStateNode getMapping(TreePath path) { + return treePathMapping.get(path); + } + + /** + * Retursn the bounds for row, row by reference in + * placeIn. If placeIn is null a new + * Rectangle will be created and returned. + */ + private Rectangle getBounds(int row, Rectangle placeIn) { + if(updateNodeSizes) + updateNodeSizes(false); + + if(row >= 0 && row < getRowCount()) { + return getNode(row).getNodeBounds(placeIn); + } + return null; + } + + /** + * Completely rebuild the tree, all expanded state, and node caches are + * removed. All nodes are collapsed, except the root. + */ + private void rebuild(boolean clearSelection) { + Object rootObject; + + treePathMapping.clear(); + if(treeModel != null && (rootObject = treeModel.getRoot()) != null) { + root = createNodeForValue(rootObject); + root.path = new TreePath(rootObject); + addMapping(root); + root.updatePreferredSize(0); + visibleNodes.removeAllElements(); + if (isRootVisible()) + visibleNodes.addElement(root); + if(!root.isExpanded()) + root.expand(); + else { + Enumeration cursor = root.children(); + while(cursor.hasMoreElements()) { + visibleNodes.addElement(cursor.nextElement()); + } + if(!isFixedRowHeight()) + updateYLocationsFrom(0); + } + } + else { + visibleNodes.removeAllElements(); + root = null; + } + if(clearSelection && treeSelectionModel != null) { + treeSelectionModel.clearSelection(); + } + this.visibleNodesChanged(); + } + + /** + * Creates a new node to represent the node at childIndex in + * parents children. This should be called if the node doesn't + * already exist and parent has been expanded at least once. + * The newly created node will be made visible if parent is + * currently expanded. This does not update the position of any + * cells, nor update the selection if it needs to be. If succesful + * in creating the new TreeStateNode, it is returned, otherwise + * null is returned. + */ + private TreeStateNode createNodeAt(TreeStateNode parent, + int childIndex) { + boolean isParentRoot; + Object newValue; + TreeStateNode newChildNode; + + newValue = treeModel.getChild(parent.getValue(), childIndex); + newChildNode = createNodeForValue(newValue); + parent.insert(newChildNode, childIndex); + newChildNode.updatePreferredSize(-1); + isParentRoot = (parent == root); + if(newChildNode != null && parent.isExpanded() && + (parent.getRow() != -1 || isParentRoot)) { + int newRow; + + /* Find the new row to insert this newly visible node at. */ + if(childIndex == 0) { + if(isParentRoot && !isRootVisible()) + newRow = 0; + else + newRow = parent.getRow() + 1; + } + else if(childIndex == parent.getChildCount()) + newRow = parent.getLastVisibleNode().getRow() + 1; + else { + TreeStateNode previousNode; + + previousNode = (TreeStateNode)parent. + getChildAt(childIndex - 1); + newRow = previousNode.getLastVisibleNode().getRow() + 1; + } + visibleNodes.insertElementAt(newChildNode, newRow); + } + return newChildNode; + } + + /** + * Returns the TreeStateNode identified by path. This mirrors + * the behavior of getNodeForPath, but tries to take advantage of + * path if it is an instance of AbstractTreePath. + */ + private TreeStateNode getNodeForPath(TreePath path, + boolean onlyIfVisible, + boolean shouldCreate) { + if(path != null) { + TreeStateNode node; + + node = getMapping(path); + if(node != null) { + if(onlyIfVisible && !node.isVisible()) + return null; + return node; + } + + // Check all the parent paths, until a match is found. + Stack paths; + + if(tempStacks.size() == 0) { + paths = new Stack(); + } + else { + paths = tempStacks.pop(); + } + + try { + paths.push(path); + path = path.getParentPath(); + node = null; + while(path != null) { + node = getMapping(path); + if(node != null) { + // Found a match, create entries for all paths in + // paths. + while(node != null && paths.size() > 0) { + path = paths.pop(); + node.getLoadedChildren(shouldCreate); + + int childIndex = treeModel. + getIndexOfChild(node.getUserObject(), + path.getLastPathComponent()); + + if(childIndex == -1 || + childIndex >= node.getChildCount() || + (onlyIfVisible && !node.isVisible())) { + node = null; + } + else + node = (TreeStateNode)node.getChildAt + (childIndex); + } + return node; + } + paths.push(path); + path = path.getParentPath(); + } + } + finally { + paths.removeAllElements(); + tempStacks.push(paths); + } + // If we get here it means they share a different root! + // We could throw an exception... + } + return null; + } + + /** + * Updates the y locations of all of the visible nodes after + * location. + */ + private void updateYLocationsFrom(int location) { + if(location >= 0 && location < getRowCount()) { + int counter, maxCounter, newYOrigin; + TreeStateNode aNode; + + aNode = getNode(location); + newYOrigin = aNode.getYOrigin() + aNode.getPreferredHeight(); + for(counter = location + 1, maxCounter = visibleNodes.size(); + counter < maxCounter;counter++) { + aNode = (TreeStateNode)visibleNodes. + elementAt(counter); + aNode.setYOrigin(newYOrigin); + newYOrigin += aNode.getPreferredHeight(); + } + } + } + + /** + * Resets the y origin of all the visible nodes as well as messaging + * all the visible nodes to updatePreferredSize(). You should not + * normally have to call this. Expanding and contracting the nodes + * automaticly adjusts the locations. + * updateAll determines if updatePreferredSize() is call on all nodes + * or just those that don't have a valid size. + */ + private void updateNodeSizes(boolean updateAll) { + int aY, counter, maxCounter; + TreeStateNode node; + + updateNodeSizes = false; + for(aY = counter = 0, maxCounter = visibleNodes.size(); + counter < maxCounter; counter++) { + node = (TreeStateNode)visibleNodes.elementAt(counter); + node.setYOrigin(aY); + if(updateAll || !node.hasValidSize()) + node.updatePreferredSize(counter); + aY += node.getPreferredHeight(); + } + } + + /** + * Returns the index of the row containing location. If there + * are no rows, -1 is returned. If location is beyond the last + * row index, the last row index is returned. + */ + private int getRowContainingYLocation(int location) { + if(isFixedRowHeight()) { + if(getRowCount() == 0) + return -1; + return Math.max(0, Math.min(getRowCount() - 1, + location / getRowHeight())); + } + + int max, maxY, mid, min, minY; + TreeStateNode node; + + if((max = getRowCount()) <= 0) + return -1; + mid = min = 0; + while(min < max) { + mid = (max - min) / 2 + min; + node = (TreeStateNode)visibleNodes.elementAt(mid); + minY = node.getYOrigin(); + maxY = minY + node.getPreferredHeight(); + if(location < minY) { + max = mid - 1; + } + else if(location >= maxY) { + min = mid + 1; + } + else + break; + } + if(min == max) { + mid = min; + if(mid >= getRowCount()) + mid = getRowCount() - 1; + } + return mid; + } + + /** + * Ensures that all the path components in path are expanded, accept + * for the last component which will only be expanded if expandLast + * is true. + * Returns true if succesful in finding the path. + */ + private void ensurePathIsExpanded(TreePath aPath, boolean expandLast) { + if(aPath != null) { + // Make sure the last entry isn't a leaf. + if(treeModel.isLeaf(aPath.getLastPathComponent())) { + aPath = aPath.getParentPath(); + expandLast = true; + } + if(aPath != null) { + TreeStateNode lastNode = getNodeForPath(aPath, false, + true); + + if(lastNode != null) { + lastNode.makeVisible(); + if(expandLast) + lastNode.expand(); + } + } + } + } + + /** + * Returns the AbstractTreeUI.VisibleNode displayed at the given row + */ + private TreeStateNode getNode(int row) { + return (TreeStateNode)visibleNodes.elementAt(row); + } + + /** + * Returns the maximum node width. + */ + private int getMaxNodeWidth() { + int maxWidth = 0; + int nodeWidth; + int counter; + TreeStateNode node; + + for(counter = getRowCount() - 1;counter >= 0;counter--) { + node = this.getNode(counter); + nodeWidth = node.getPreferredWidth() + node.getXOrigin(); + if(nodeWidth > maxWidth) + maxWidth = nodeWidth; + } + return maxWidth; + } + + /** + * Responsible for creating a TreeStateNode that will be used + * to track display information about value. + */ + private TreeStateNode createNodeForValue(Object value) { + return new TreeStateNode(value); + } + + + /** + * TreeStateNode is used to keep track of each of + * the nodes that have been expanded. This will also cache the preferred + * size of the value it represents. + */ + private class TreeStateNode extends DefaultMutableTreeNode { + /** Preferred size needed to draw the user object. */ + protected int preferredWidth; + protected int preferredHeight; + + /** X location that the user object will be drawn at. */ + protected int xOrigin; + + /** Y location that the user object will be drawn at. */ + protected int yOrigin; + + /** Is this node currently expanded? */ + protected boolean expanded; + + /** Has this node been expanded at least once? */ + protected boolean hasBeenExpanded; + + /** Path of this node. */ + protected TreePath path; + + + public TreeStateNode(Object value) { + super(value); + } + + // + // Overriden DefaultMutableTreeNode methods + // + + /** + * Messaged when this node is added somewhere, resets the path + * and adds a mapping from path to this node. + */ + public void setParent(MutableTreeNode parent) { + super.setParent(parent); + if(parent != null) { + path = ((TreeStateNode)parent).getTreePath(). + pathByAddingChild(getUserObject()); + addMapping(this); + } + } + + /** + * Messaged when this node is removed from its parent, this messages + * removedFromMapping to remove all the children. + */ + public void remove(int childIndex) { + TreeStateNode node = (TreeStateNode)getChildAt(childIndex); + + node.removeFromMapping(); + super.remove(childIndex); + } + + /** + * Messaged to set the user object. This resets the path. + */ + public void setUserObject(Object o) { + super.setUserObject(o); + if(path != null) { + TreeStateNode parent = (TreeStateNode)getParent(); + + if(parent != null) + resetChildrenPaths(parent.getTreePath()); + else + resetChildrenPaths(null); + } + } + + /** + * Returns the children of the receiver. + * If the receiver is not currently expanded, this will return an + * empty enumeration. + */ + public Enumeration children() { + if (!this.isExpanded()) { + return DefaultMutableTreeNode.EMPTY_ENUMERATION; + } else { + return super.children(); + } + } + + /** + * Returns true if the receiver is a leaf. + */ + public boolean isLeaf() { + return getModel().isLeaf(this.getValue()); + } + + // + // VariableHeightLayoutCache + // + + /** + * Returns the location and size of this node. + */ + public Rectangle getNodeBounds(Rectangle placeIn) { + if(placeIn == null) + placeIn = new Rectangle(getXOrigin(), getYOrigin(), + getPreferredWidth(), + getPreferredHeight()); + else { + placeIn.x = getXOrigin(); + placeIn.y = getYOrigin(); + placeIn.width = getPreferredWidth(); + placeIn.height = getPreferredHeight(); + } + return placeIn; + } + + /** + * @return x location to draw node at. + */ + public int getXOrigin() { + if(!hasValidSize()) + updatePreferredSize(getRow()); + return xOrigin; + } + + /** + * Returns the y origin the user object will be drawn at. + */ + public int getYOrigin() { + if(isFixedRowHeight()) { + int aRow = getRow(); + + if(aRow == -1) + return -1; + return getRowHeight() * aRow; + } + return yOrigin; + } + + /** + * Returns the preferred height of the receiver. + */ + public int getPreferredHeight() { + if(isFixedRowHeight()) + return getRowHeight(); + else if(!hasValidSize()) + updatePreferredSize(getRow()); + return preferredHeight; + } + + /** + * Returns the preferred width of the receiver. + */ + public int getPreferredWidth() { + if(!hasValidSize()) + updatePreferredSize(getRow()); + return preferredWidth; + } + + /** + * Returns true if this node has a valid size. + */ + public boolean hasValidSize() { + return (preferredHeight != 0); + } + + /** + * Returns the row of the receiver. + */ + public int getRow() { + return visibleNodes.indexOf(this); + } + + /** + * Returns true if this node has been expanded at least once. + */ + public boolean hasBeenExpanded() { + return hasBeenExpanded; + } + + /** + * Returns true if the receiver has been expanded. + */ + public boolean isExpanded() { + return expanded; + } + + /** + * Returns the last visible node that is a child of this + * instance. + */ + public TreeStateNode getLastVisibleNode() { + TreeStateNode node = this; + + while(node.isExpanded() && node.getChildCount() > 0) + node = (TreeStateNode)node.getLastChild(); + return node; + } + + /** + * Returns true if the receiver is currently visible. + */ + public boolean isVisible() { + if(this == root) + return true; + + TreeStateNode parent = (TreeStateNode)getParent(); + + return (parent != null && parent.isExpanded() && + parent.isVisible()); + } + + /** + * Returns the number of children this will have. If the children + * have not yet been loaded, this messages the model. + */ + public int getModelChildCount() { + if(hasBeenExpanded) + return super.getChildCount(); + return getModel().getChildCount(getValue()); + } + + /** + * Returns the number of visible children, that is the number of + * children that are expanded, or leafs. + */ + public int getVisibleChildCount() { + int childCount = 0; + + if(isExpanded()) { + int maxCounter = getChildCount(); + + childCount += maxCounter; + for(int counter = 0; counter < maxCounter; counter++) + childCount += ((TreeStateNode)getChildAt(counter)). + getVisibleChildCount(); + } + return childCount; + } + + /** + * Toggles the receiver between expanded and collapsed. + */ + public void toggleExpanded() { + if (isExpanded()) { + collapse(); + } else { + expand(); + } + } + + /** + * Makes the receiver visible, but invoking + * expandParentAndReceiver on the superclass. + */ + public void makeVisible() { + TreeStateNode parent = (TreeStateNode)getParent(); + + if(parent != null) + parent.expandParentAndReceiver(); + } + + /** + * Expands the receiver. + */ + public void expand() { + expand(true); + } + + /** + * Collapses the receiver. + */ + public void collapse() { + collapse(true); + } + + /** + * Returns the value the receiver is representing. This is a cover + * for getUserObject. + */ + public Object getValue() { + return getUserObject(); + } + + /** + * Returns a TreePath instance for this node. + */ + public TreePath getTreePath() { + return path; + } + + // + // Local methods + // + + /** + * Recreates the receivers path, and all its children's paths. + */ + protected void resetChildrenPaths(TreePath parentPath) { + removeMapping(this); + if(parentPath == null) + path = new TreePath(getUserObject()); + else + path = parentPath.pathByAddingChild(getUserObject()); + addMapping(this); + for(int counter = getChildCount() - 1; counter >= 0; counter--) + ((TreeStateNode)getChildAt(counter)).resetChildrenPaths(path); + } + + /** + * Sets y origin the user object will be drawn at to + * newYOrigin. + */ + protected void setYOrigin(int newYOrigin) { + yOrigin = newYOrigin; + } + + /** + * Shifts the y origin by offset. + */ + protected void shiftYOriginBy(int offset) { + yOrigin += offset; + } + + /** + * Updates the receivers preferredSize by invoking + * updatePreferredSize with an argument of -1. + */ + protected void updatePreferredSize() { + updatePreferredSize(getRow()); + } + + /** + * Updates the preferred size by asking the current renderer + * for the Dimension needed to draw the user object this + * instance represents. + */ + protected void updatePreferredSize(int index) { + Rectangle bounds = getNodeDimensions(this.getUserObject(), + index, getLevel(), + isExpanded(), + boundsBuffer); + + if(bounds == null) { + xOrigin = 0; + preferredWidth = preferredHeight = 0; + updateNodeSizes = true; + } + else if(bounds.height == 0) { + xOrigin = 0; + preferredWidth = preferredHeight = 0; + updateNodeSizes = true; + } + else { + xOrigin = bounds.x; + preferredWidth = bounds.width; + if(isFixedRowHeight()) + preferredHeight = getRowHeight(); + else + preferredHeight = bounds.height; + } + } + + /** + * Marks the receivers size as invalid. Next time the size, location + * is asked for it will be obtained. + */ + protected void markSizeInvalid() { + preferredHeight = 0; + } + + /** + * Marks the receivers size, and all its descendants sizes, as invalid. + */ + protected void deepMarkSizeInvalid() { + markSizeInvalid(); + for(int counter = getChildCount() - 1; counter >= 0; counter--) + ((TreeStateNode)getChildAt(counter)).deepMarkSizeInvalid(); + } + + /** + * Returns the children of the receiver. If the children haven't + * been loaded from the model and + * createIfNeeded is true, the children are first + * loaded. + */ + protected Enumeration getLoadedChildren(boolean createIfNeeded) { + if(!createIfNeeded || hasBeenExpanded) + return super.children(); + + TreeStateNode newNode; + Object realNode = getValue(); + TreeModel treeModel = getModel(); + int count = treeModel.getChildCount(realNode); + + hasBeenExpanded = true; + + int childRow = getRow(); + + if(childRow == -1) { + for (int i = 0; i < count; i++) { + newNode = createNodeForValue + (treeModel.getChild(realNode, i)); + this.add(newNode); + newNode.updatePreferredSize(-1); + } + } + else { + childRow++; + for (int i = 0; i < count; i++) { + newNode = createNodeForValue + (treeModel.getChild(realNode, i)); + this.add(newNode); + newNode.updatePreferredSize(childRow++); + } + } + return super.children(); + } + + /** + * Messaged from expand and collapse. This is meant for subclassers + * that may wish to do something interesting with this. + */ + protected void didAdjustTree() { + } + + /** + * Invokes expandParentAndReceiver on the parent, + * and expands the receiver. + */ + protected void expandParentAndReceiver() { + TreeStateNode parent = (TreeStateNode)getParent(); + + if(parent != null) + parent.expandParentAndReceiver(); + expand(); + } + + /** + * Expands this node in the tree. This will load the children + * from the treeModel if this node has not previously been + * expanded. If adjustTree is true the tree and selection + * are updated accordingly. + */ + protected void expand(boolean adjustTree) { + if (!isExpanded() && !isLeaf()) { + boolean isFixed = isFixedRowHeight(); + int startHeight = getPreferredHeight(); + int originalRow = getRow(); + + expanded = true; + updatePreferredSize(originalRow); + + if (!hasBeenExpanded) { + TreeStateNode newNode; + Object realNode = getValue(); + TreeModel treeModel = getModel(); + int count = treeModel.getChildCount(realNode); + + hasBeenExpanded = true; + if(originalRow == -1) { + for (int i = 0; i < count; i++) { + newNode = createNodeForValue(treeModel.getChild + (realNode, i)); + this.add(newNode); + newNode.updatePreferredSize(-1); + } + } + else { + int offset = originalRow + 1; + for (int i = 0; i < count; i++) { + newNode = createNodeForValue(treeModel.getChild + (realNode, i)); + this.add(newNode); + newNode.updatePreferredSize(offset); + } + } + } + + int i = originalRow; + Enumeration cursor = preorderEnumeration(); + cursor.nextElement(); // don't add me, I'm already in + + int newYOrigin; + + if(isFixed) + newYOrigin = 0; + else if(this == root && !isRootVisible()) + newYOrigin = 0; + else + newYOrigin = getYOrigin() + this.getPreferredHeight(); + TreeStateNode aNode; + if(!isFixed) { + while (cursor.hasMoreElements()) { + aNode = (TreeStateNode)cursor.nextElement(); + if(!updateNodeSizes && !aNode.hasValidSize()) + aNode.updatePreferredSize(i + 1); + aNode.setYOrigin(newYOrigin); + newYOrigin += aNode.getPreferredHeight(); + visibleNodes.insertElementAt(aNode, ++i); + } + } + else { + while (cursor.hasMoreElements()) { + aNode = (TreeStateNode)cursor.nextElement(); + visibleNodes.insertElementAt(aNode, ++i); + } + } + + if(adjustTree && (originalRow != i || + getPreferredHeight() != startHeight)) { + // Adjust the Y origin of any nodes following this row. + if(!isFixed && ++i < getRowCount()) { + int counter; + int heightDiff = newYOrigin - + (getYOrigin() + getPreferredHeight()) + + (getPreferredHeight() - startHeight); + + for(counter = visibleNodes.size() - 1;counter >= i; + counter--) + ((TreeStateNode)visibleNodes.elementAt(counter)). + shiftYOriginBy(heightDiff); + } + didAdjustTree(); + visibleNodesChanged(); + } + + // Update the rows in the selection + if(treeSelectionModel != null) { + treeSelectionModel.resetRowSelection(); + } + } + } + + /** + * Collapses this node in the tree. If adjustTree is + * true the tree and selection are updated accordingly. + */ + protected void collapse(boolean adjustTree) { + if (isExpanded()) { + Enumeration cursor = preorderEnumeration(); + cursor.nextElement(); // don't remove me, I'm still visible + int rowsDeleted = 0; + boolean isFixed = isFixedRowHeight(); + int lastYEnd; + if(isFixed) + lastYEnd = 0; + else + lastYEnd = getPreferredHeight() + getYOrigin(); + int startHeight = getPreferredHeight(); + int startYEnd = lastYEnd; + int myRow = getRow(); + + if(!isFixed) { + while(cursor.hasMoreElements()) { + TreeStateNode node = (TreeStateNode)cursor. + nextElement(); + if (node.isVisible()) { + rowsDeleted++; + //visibleNodes.removeElement(node); + lastYEnd = node.getYOrigin() + + node.getPreferredHeight(); + } + } + } + else { + while(cursor.hasMoreElements()) { + TreeStateNode node = (TreeStateNode)cursor. + nextElement(); + if (node.isVisible()) { + rowsDeleted++; + //visibleNodes.removeElement(node); + } + } + } + + // Clean up the visible nodes. + for (int counter = rowsDeleted + myRow; counter > myRow; + counter--) { + visibleNodes.removeElementAt(counter); + } + + expanded = false; + + if(myRow == -1) + markSizeInvalid(); + else if (adjustTree) + updatePreferredSize(myRow); + + if(myRow != -1 && adjustTree && + (rowsDeleted > 0 || startHeight != getPreferredHeight())) { + // Adjust the Y origin of any rows following this one. + startYEnd += (getPreferredHeight() - startHeight); + if(!isFixed && (myRow + 1) < getRowCount() && + startYEnd != lastYEnd) { + int counter, maxCounter, shiftAmount; + + shiftAmount = startYEnd - lastYEnd; + for(counter = myRow + 1, maxCounter = + visibleNodes.size(); + counter < maxCounter;counter++) + ((TreeStateNode)visibleNodes.elementAt(counter)) + .shiftYOriginBy(shiftAmount); + } + didAdjustTree(); + visibleNodesChanged(); + } + if(treeSelectionModel != null && rowsDeleted > 0 && + myRow != -1) { + treeSelectionModel.resetRowSelection(); + } + } + } + + /** + * Removes the receiver, and all its children, from the mapping + * table. + */ + protected void removeFromMapping() { + if(path != null) { + removeMapping(this); + for(int counter = getChildCount() - 1; counter >= 0; counter--) + ((TreeStateNode)getChildAt(counter)).removeFromMapping(); + } + } + } // End of VariableHeightLayoutCache.TreeStateNode + + + /** + * An enumerator to iterate through visible nodes. + */ + private class VisibleTreeStateNodeEnumeration implements + Enumeration { + /** Parent thats children are being enumerated. */ + protected TreeStateNode parent; + /** Index of next child. An index of -1 signifies parent should be + * visibled next. */ + protected int nextIndex; + /** Number of children in parent. */ + protected int childCount; + + protected VisibleTreeStateNodeEnumeration(TreeStateNode node) { + this(node, -1); + } + + protected VisibleTreeStateNodeEnumeration(TreeStateNode parent, + int startIndex) { + this.parent = parent; + this.nextIndex = startIndex; + this.childCount = this.parent.getChildCount(); + } + + /** + * @return true if more visible nodes. + */ + public boolean hasMoreElements() { + return (parent != null); + } + + /** + * @return next visible TreePath. + */ + public TreePath nextElement() { + if(!hasMoreElements()) + throw new NoSuchElementException("No more visible paths"); + + TreePath retObject; + + if(nextIndex == -1) { + retObject = parent.getTreePath(); + } + else { + TreeStateNode node = (TreeStateNode)parent. + getChildAt(nextIndex); + + retObject = node.getTreePath(); + } + updateNextObject(); + return retObject; + } + + /** + * Determines the next object by invoking updateNextIndex + * and if not succesful findNextValidParent. + */ + protected void updateNextObject() { + if(!updateNextIndex()) { + findNextValidParent(); + } + } + + /** + * Finds the next valid parent, this should be called when nextIndex + * is beyond the number of children of the current parent. + */ + protected boolean findNextValidParent() { + if(parent == root) { + // mark as invalid! + parent = null; + return false; + } + while(parent != null) { + TreeStateNode newParent = (TreeStateNode)parent. + getParent(); + + if(newParent != null) { + nextIndex = newParent.getIndex(parent); + parent = newParent; + childCount = parent.getChildCount(); + if(updateNextIndex()) + return true; + } + else + parent = null; + } + return false; + } + + /** + * Updates nextIndex returning false if it is beyond + * the number of children of parent. + */ + protected boolean updateNextIndex() { + // nextIndex == -1 identifies receiver, make sure is expanded + // before descend. + if(nextIndex == -1 && !parent.isExpanded()) + return false; + + // Check that it can have kids + if(childCount == 0) + return false; + // Make sure next index not beyond child count. + else if(++nextIndex >= childCount) + return false; + + TreeStateNode child = (TreeStateNode)parent. + getChildAt(nextIndex); + + if(child != null && child.isExpanded()) { + parent = child; + nextIndex = -1; + childCount = child.getChildCount(); + } + return true; + } + } // VariableHeightLayoutCache.VisibleTreeStateNodeEnumeration +} diff --git a/sources/net.sf.j2s.java.core/src/javax/swing/tree/package.html b/sources/net.sf.j2s.java.core/src/javax/swing/tree/package.html new file mode 100644 index 000000000..b6b58bbda --- /dev/null +++ b/sources/net.sf.j2s.java.core/src/javax/swing/tree/package.html @@ -0,0 +1,62 @@ + + + + +Codestin Search App + + + +Provides classes and interfaces for dealing with +javax.swing.JTree. You use these classes and interfaces if you want +control over how trees are constructed, updated, and rendered, as well +as how data associated with the tree nodes are viewed and managed. + +

+Note: +Most of the Swing API is not thread safe. +For details, see +Threads and Swing, +a section in +The Java Tutorial. + + +

Related Documentation

+ +For overviews, tutorials, examples, guides, and tool documentation, please see: + + + +@since 1.2 +@serial exclude + + + diff --git a/sources/net.sf.j2s.java.core/src/sun/awt/image/SunWritableRaster.java b/sources/net.sf.j2s.java.core/src/sun/awt/image/SunWritableRaster.java index 86a043ae9..3d8fd7501 100644 --- a/sources/net.sf.j2s.java.core/src/sun/awt/image/SunWritableRaster.java +++ b/sources/net.sf.j2s.java.core/src/sun/awt/image/SunWritableRaster.java @@ -48,10 +48,13 @@ */ public class SunWritableRaster extends WritableRaster { - private static DataStealer stealer; + + // temporary only, until we figure out how to do this. public int[] 秘pix; + private static DataStealer stealer; + private static DataStealer getStealer() { return (stealer == null ? stealer = new DataStealer() { @Override diff --git a/sources/net.sf.j2s.java.core/src/swingjs/JSGraphics2D.java b/sources/net.sf.j2s.java.core/src/swingjs/JSGraphics2D.java index 75073f6dd..881f86375 100644 --- a/sources/net.sf.j2s.java.core/src/swingjs/JSGraphics2D.java +++ b/sources/net.sf.j2s.java.core/src/swingjs/JSGraphics2D.java @@ -7,7 +7,6 @@ import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.Image; import java.awt.Paint; @@ -47,7 +46,6 @@ * @author Bob Hanson hansonr@stolaf.edu */ -@SuppressWarnings({ "rawtypes", "unchecked", "deprecation" }) public class JSGraphics2D implements // Graphics2D, Cloneable { @@ -505,7 +503,7 @@ public boolean drawImage(Image img, int x, int y, int width, int height, ImageOb private DOMNode getImageNode(Image img) { // backgroundPainted = true; DOMNode imgNode = DOMNode.getImageNode(img); - return (imgNode == null ? JSGraphicsCompositor.createImageNode(img) : imgNode); + return (imgNode == null ? JSGraphicsCompositor.createImageNode(img) : ((BufferedImage) img).秘updateNode(imgNode)); } private void observe(Image img, ImageObserver observer, boolean isOK) { @@ -572,62 +570,62 @@ private boolean drawImageXT(Image img, AffineTransform xform, ImageObserver obs) @SuppressWarnings("unused") public boolean drawImagePriv(Image img, int x, int y, ImageObserver observer) { -// backgroundPainted = true; if (img != null) { - int[] pixels = null; - boolean isRGB = false; // usually RGBA - /** - * @j2sNative - * - * pixels = img.raster.秘pix ||img.秘pix; isRGB = (img.imageType == 1); - * - */ - DOMNode imgNode = null; int width = ((BufferedImage) img).getRaster().getWidth(); int height = ((BufferedImage) img).getRaster().getHeight(); - + double[] m = HTML5CanvasContext2D.getMatrix(ctx, transform); + int type = ((BufferedImage) img).getType(); + boolean isOpaque = ((BufferedImage) img).秘isOpaque(); + int[] pixels = (isTranslationOnly(m) ? ((BufferedImage) img).get秘pix() : null); + DOMNode imgNode = null; if (pixels == null) { if ((imgNode = getImageNode(img)) != null) ctx.drawImage(imgNode, x, y, width, height); } else { - drawDirect(pixels, x, y, width, height, isRGB); + boolean isPerPixel = (pixels.length == width * height); + if (buf8 == null || x != lastx || y != lasty || nx != width || ny != height) { + imageData = ctx.getImageData(x, y, width, height); + buf8 = imageData.data; + lastx = x; + lasty = y; + nx = width; + ny = height; + } + if (isPerPixel) { + for (int pt = 0, i = 0, n = Math.min(buf8.length / 4, pixels.length); i < n; i++) { + int argb = pixels[i]; + buf8[pt++] = (argb >> 16) & 0xFF; + buf8[pt++] = (argb >> 8) & 0xFF; + buf8[pt++] = argb & 0xFF; + buf8[pt++] = (isOpaque ? 0xFF : (argb >> 24) & 0xFF); + } + } else if (isOpaque) { + for (int i = 0, n = Math.min(buf8.length, pixels.length); i < n; i++) { + buf8[i] = pixels[i++]; + buf8[i] = pixels[i++]; + buf8[i] = pixels[i++]; + buf8[i] = 0xFF; + } + } else { + for (int i = 0, n = Math.min(buf8.length, pixels.length); i < n; i++) { + buf8[i] = pixels[i]; + } + } + x += m[4]; + y += m[5]; + ctx.putImageData(imageData, x, y); } if (observer != null) - observe(img, observer, imgNode != null); + observe(img, observer, imgNode != null || pixels != null); } return true; } - public void drawDirect(int[] pixels, int x, int y, int width, int height, boolean isRGB) { - if (buf8 == null || x != lastx || y != lasty || nx != width || ny != height) { - imageData = ctx.getImageData(x, y, width, height); - buf8 = imageData.data; - lastx = x; - lasty = y; - nx = width; - ny = height; - } - double[] m = new double[6]; - transform.getMatrix(m); - if (m[0] != 1 || m[1] != 0 || m[2] != 0 || m[3] != 1) - System.err.println("Unsupported transform"); - x += m[4]; - y += m[5]; - for (int pt = 0, i = 0, n = Math.min(buf8.length / 4, pixels.length); i < n; i++) { - int argb = pixels[i]; - buf8[pt++] = (argb >> 16) & 0xFF; - buf8[pt++] = (argb >> 8) & 0xFF; - buf8[pt++] = argb & 0xFF; - buf8[pt++] = (isRGB ? 0xFF : (argb >> 24) & 0xFF); - } - double[] m = HTML5CanvasContext2D.getMatrix(ctx, transform); - if (m[0] != 1 || m[1] != 0 || m[2] != 0 || m[3] != 1) - System.err.println("Unsupported transform"); - x += m[4]; - y += m[5]; - ctx.putImageData(imageData, x, y); + private static boolean isTranslationOnly(double[] m) { + return ( m[0] == 1 && m[1] == 0 + && m[2] == 0 && m[3] == 1); } - + public boolean hit(Rectangle rect, Shape s, boolean onStroke) { JSUtil.notImplemented(null); return false; @@ -886,6 +884,7 @@ public void scale(double sx, double sy) { public void transform(AffineTransform t) { transformCTX(t); transform.concatenate(t); + HTML5CanvasContext2D.getMatrix(ctx, null); } private void transformCTX(AffineTransform t) { diff --git a/sources/net.sf.j2s.java.core/src/swingjs/JSGraphicsCompositor.java b/sources/net.sf.j2s.java.core/src/swingjs/JSGraphicsCompositor.java index e56cb4d43..4ae966bb3 100644 --- a/sources/net.sf.j2s.java.core/src/swingjs/JSGraphicsCompositor.java +++ b/sources/net.sf.j2s.java.core/src/swingjs/JSGraphicsCompositor.java @@ -308,31 +308,18 @@ private static int lookupByteBI(BufferedImage src, BufferedImage dst, byte[][] t * @return */ public static DOMNode createImageNode(Image img) { - DOMNode imgNode = null; - /** - * @j2sNative - * - * imgNode = img.秘imgNode; - * - */ - {} + JSImage jsi = (JSImage) img; + DOMNode imgNode = (DOMNode) jsi.秘imgNode; if (imgNode == null && img instanceof BufferedImage) { - int w = ((JSImage)img).getWidth(); - int h = ((JSImage)img).getHeight(); - /** - * @j2sNative - * - * var canvas = img.秘canvas; - * if (canvas == null) { - * img.getGraphics$(); - * canvas = img.秘canvas; - * } - * imgNode = canvas; - * imgNode.style.width = w + "px"; - * imgNode.style.height = h + "px"; - * - */ - {} + int w = jsi.getWidth(); + int h = jsi.getHeight(); + DOMNode canvas = (DOMNode) jsi.秘canvas; + if (canvas == null) { + img.getGraphics(); + canvas = (DOMNode) jsi.秘canvas; + } + imgNode = canvas; + DOMNode.setSize(imgNode, w, h); // note: images created some other way are presumed to have int[] pix defined and possibly byte[pix] } return imgNode; diff --git a/sources/net.sf.j2s.java.core/src/swingjs/JSImage.java b/sources/net.sf.j2s.java.core/src/swingjs/JSImage.java index b89f3913d..d636bdea2 100644 --- a/sources/net.sf.j2s.java.core/src/swingjs/JSImage.java +++ b/sources/net.sf.j2s.java.core/src/swingjs/JSImage.java @@ -8,38 +8,29 @@ import swingjs.api.js.DOMNode; /** - * A JavaScript version of BufferedImage. + * A JavaScript version of BufferedImage. * - * Created from JSImagekit when creating an image - * from byte[] or from loading a GIF, PNG, or JPG image. + * Created from JSImagekit when creating an image from byte[] or from loading a + * GIF, PNG, or JPG image. * - * The difference is that when from byte[] data, the - * field 秘pix will be initialized to the raster data, - * but 秘imgNode will be null; when an image is used, then - * 秘pix will be there, but it will not be populated unless - * a call to setRGB is made. Until then, JSGraphics2D.drawImage will - * simply use the image itself. But the 秘pix data will still - * be available as 秘imgNode.pbuf32. - * - * Only integer raster data RGB and ARGB have been implemented. - * - * useful states: - * - * _domNode != null ==> came from an image node (image file) - * 秘canvas != null ==> an image has been created from raster data + * The difference is that when from byte[] data, the field 秘pix will be + * initialized to the raster data, but 秘imgNode will be null. * + * When an image is used, then 秘pix will be there, but it will not be populated + * unless a call to setRGB is made. Until then, JSGraphics2D.drawImage will + * simply use the image itself. * + * useful states: (needs checking) * + * a) 秘imgNode != null implies came from an image node (image file) + * + * b) 秘canvas != null implies an image has been created from raster data * * @author Bob Hanson * */ public class JSImage extends BufferedImage { - // a BufferedImage in name only, actually; - - // TODO: implement simple ColorModel and Raster - public String src; public JSImage(int[] argb, int width, int height, String src) { @@ -65,7 +56,7 @@ public void getDOMImage(byte[] b, String type) { * //if (this.callback) img.onload = this.callback; * img.src = dataurl; */ - {} + 秘imgNode = img; } @@ -79,4 +70,10 @@ public Image setComponent(Component c) { return this; } + @Override + public DOMNode 秘updateNode(DOMNode imgNode) { + return imgNode; + } + + } diff --git a/sources/net.sf.j2s.java.core/src/swingjs/api/js/HTML5CanvasContext2D.java b/sources/net.sf.j2s.java.core/src/swingjs/api/js/HTML5CanvasContext2D.java index 0ced65e96..28a82c005 100644 --- a/sources/net.sf.j2s.java.core/src/swingjs/api/js/HTML5CanvasContext2D.java +++ b/sources/net.sf.j2s.java.core/src/swingjs/api/js/HTML5CanvasContext2D.java @@ -115,6 +115,10 @@ public static int getSavedLevel(HTML5CanvasContext2D ctx) { public static double[] getMatrix(HTML5CanvasContext2D ctx, AffineTransform transform) { double[] m = /** @j2sNative ctx._m || */ null; + if (transform == null) { + /** @j2sNative ctx._m = null; */ + return null; + } if (m == null) { m = new double[6]; /** diff --git a/sources/net.sf.j2s.java.core/src/swingjs/api/js/JQueryObject.java b/sources/net.sf.j2s.java.core/src/swingjs/api/js/JQueryObject.java index 32545c9e6..92fab426d 100644 --- a/sources/net.sf.j2s.java.core/src/swingjs/api/js/JQueryObject.java +++ b/sources/net.sf.j2s.java.core/src/swingjs/api/js/JQueryObject.java @@ -100,6 +100,10 @@ public interface J2SCB extends JQueryObject { } + + public static DOMNode getDOMNode(JQueryObject jnode) { + return (jnode == null ? null : ((DOMNode[]) (Object) jnode)[0]); + } } diff --git a/sources/net.sf.j2s.java.core/src/swingjs/plaf/HTML5LookAndFeel.java b/sources/net.sf.j2s.java.core/src/swingjs/plaf/HTML5LookAndFeel.java index dc83b1be6..12cef429d 100644 --- a/sources/net.sf.j2s.java.core/src/swingjs/plaf/HTML5LookAndFeel.java +++ b/sources/net.sf.j2s.java.core/src/swingjs/plaf/HTML5LookAndFeel.java @@ -2047,7 +2047,7 @@ public Object createValue(UIDefaults table) { Boolean.TRUE, "Tree.lineTypeDashed", Boolean.FALSE, - // "Tree.font", dialogPlain12, + "Tree.font", dialogPlain12, "Tree.background", window, "Tree.foreground", @@ -2060,25 +2060,25 @@ public Object createValue(UIDefaults table) { table.get("text"), "Tree.selectionForeground", textHighlightText, "Tree.selectionBackground", textHighlight, - // "Tree.selectionBorderColor", black, - // "Tree.dropLineColor", controlShadow, - // "Tree.editorBorder", blackLineBorder, + "Tree.selectionBorderColor", black, + "Tree.dropLineColor", controlShadow, + "Tree.editorBorder", blackLineBorder, "Tree.leftChildIndent", new Integer(7), "Tree.rightChildIndent", new Integer(13), "Tree.rowHeight", new Integer(16), "Tree.scrollsOnExpand", Boolean.TRUE, - // "Tree.openIcon", SwingUtilities2.makeIcon(getClass(), - // HTML5LookAndFeel.class, - // "icons/TreeOpen.gif"), - // "Tree.closedIcon", SwingUtilities2.makeIcon(getClass(), - // HTML5LookAndFeel.class, - // "icons/TreeClosed.gif"), - // "Tree.leafIcon", SwingUtilities2.makeIcon(getClass(), - // HTML5LookAndFeel.class, - // "icons/TreeLeaf.gif"), - // "Tree.expandedIcon", null, - // "Tree.collapsedIcon", null, - // "Tree.changeSelectionWithFocus", Boolean.TRUE, - // "Tree.drawsFocusBorderAroundIcon", Boolean.FALSE, +// "Tree.openIcon", SwingUtilities2.makeIcon(getClass(), +// HTML5LookAndFeel.class, +// "icons/TreeOpen.gif"), +// "Tree.closedIcon", SwingUtilities2.makeIcon(getClass(), +// HTML5LookAndFeel.class, +// "icons/TreeClosed.gif"), +// "Tree.leafIcon", SwingUtilities2.makeIcon(getClass(), +// HTML5LookAndFeel.class, +// "icons/TreeLeaf.gif"), + "Tree.expandedIcon", null, + "Tree.collapsedIcon", null, + "Tree.changeSelectionWithFocus", Boolean.TRUE, + "Tree.drawsFocusBorderAroundIcon", Boolean.FALSE, "Tree.timeFactor", oneThousand, // "Tree.focusInputMap", // new UIDefaults.LazyInputMap(new Object[] { diff --git a/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSComponentUI.java b/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSComponentUI.java index be70a5b0f..dd72136f4 100644 --- a/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSComponentUI.java +++ b/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSComponentUI.java @@ -332,7 +332,7 @@ protected void restoreCellNodes(DOMNode td) { * for a JLabel or AbstractButton, including JMenuItems * */ - protected DOMNode centeringNode; + public DOMNode centeringNode; /** * an icon image -- non-null means we do have an icon diff --git a/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSEditorPaneUI.java b/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSEditorPaneUI.java index 8ecdb57f3..a582fb82b 100644 --- a/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSEditorPaneUI.java +++ b/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSEditorPaneUI.java @@ -61,6 +61,8 @@ public class JSEditorPaneUI extends JSTextUI { private static final String JSTAB = "    "; private static final int SPACES_PER_TAB = 4; + + protected boolean isTextPane = false; public JSEditorPaneUI() { isEditorPane = isTextView = true; @@ -203,7 +205,7 @@ public DOMNode updateDOMNode() { } textListener.checkDocument(); setCssFont(domNode, c.getFont()); - DOMNode.setAttrs(domNode, "contentEditable", TRUE, "spellcheck", FALSE); + DOMNode.setAttrs(domNode, "contentEditable", editor.isEditable() ? TRUE : FALSE, "spellcheck", FALSE); if (jc.getTopLevelAncestor() != null) { if (editor.getText() != mytext) { setText(null); @@ -290,7 +292,7 @@ public void propertyChange(PropertyChangeEvent e) { // private int getJSDocOffset(DOMNode node) { int pt = 0; - while (node != domNode) { + while (node != domNode && node != null) { DOMNode sib = DOMNode.getPreviousSibling(node); while (sib != null) { pt += getJSCharCount(sib); @@ -328,12 +330,19 @@ public void setText(String text) { if (text == null) text = editor.getText(); mytext = text; + isHTML = text.startsWith("
"; + html = sb.toString() + "

"; + } //System.out.println(html); if (html == currentHTML) return; @@ -352,6 +361,17 @@ public void setText(String text) { } } + private String getInner(String html, String body) { + int pt = html.indexOf("<" + body); + if (pt >= 0) { + html = html.substring(html.indexOf(">", pt) + 1); + pt = html.lastIndexOf(""); + if (pt >= 0) + html = html.substring(0, pt); + } + return html; + } + /** * after setting text, it is necessary to update all descendents to be clickable */ @@ -420,6 +440,9 @@ else if (isSup) if (t.indexOf('\t') >= 0) { t = PT.rep(t, "\t", JSTAB); } + if (t.indexOf('<') >= 0) { + t = PT.rep(t, "<", "<"); + } sb.append(t); } if (isSup) @@ -764,7 +787,6 @@ private void fixTabRange(Object[] r) { DOMNode node = (DOMNode)r[0]; boolean isStart = /** @j2sNative r[1] == 0|| */false; if (isJSTAB(node)) { - System.out.println("fixtab"); if (isStart) { } else { diff --git a/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSLabelUI.java b/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSLabelUI.java index 6e29c2004..e8994e4c5 100644 --- a/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSLabelUI.java +++ b/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSLabelUI.java @@ -136,4 +136,7 @@ static Dimension getMinimumSizePeer(JComponent jc, Object label) { return new Dimension(fm.stringWidth(s) + 14, fm.getHeight() + adj); } + public void setVisible(boolean b) { + super.setVisible(b); + } } diff --git a/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSListUI.java b/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSListUI.java index 9cdd945c7..d794cf700 100644 --- a/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSListUI.java +++ b/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSListUI.java @@ -115,7 +115,7 @@ public class JSListUI extends JSLightweightUI //true, but unnecessary implements me = this; } - String itemHTML = null; +// String itemHTML = null; @Override public DOMNode updateDOMNode() { @@ -405,7 +405,7 @@ private void paintImpl(Graphics g, JComponent c) { // to new x,y coordinates. needFilling = false; - itemHTML = ""; +// itemHTML = ""; switch (layoutOrientation) { case JList.VERTICAL_WRAP: if (list.getHeight() != listHeight) { diff --git a/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSTableUI.java b/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSTableUI.java index 925c91311..ef4816efe 100644 --- a/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSTableUI.java +++ b/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSTableUI.java @@ -1760,7 +1760,8 @@ protected void installDefaults() { private JScrollPane getScrollPane() { Container parent; - return (JScrollPane) ((parent = table.getParent()) == null ? null : parent.getParent()); // should be the scrollpane + parent = ((parent = table.getParent()) == null ? null : parent.getParent()); + return (parent instanceof JScrollPane ? (JScrollPane) parent : null); } private void installDefaults2() { diff --git a/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSTextPaneUI.java b/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSTextPaneUI.java index fd73e1fe5..a30d4c4a5 100644 --- a/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSTextPaneUI.java +++ b/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSTextPaneUI.java @@ -26,6 +26,13 @@ public class JSTextPaneUI extends JSEditorPaneUI { + + public JSTextPaneUI() { + super(); + isTextPane = true; + } + + @Override protected String getPropertyPrefix() { return "TextPane"; diff --git a/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSTreeUI.java b/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSTreeUI.java index 91219781e..ff87e0113 100644 --- a/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSTreeUI.java +++ b/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSTreeUI.java @@ -32,7 +32,6 @@ import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; -import java.awt.datatransfer.Transferable; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; @@ -49,9 +48,6 @@ import java.awt.event.MouseMotionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; import java.util.Enumeration; import java.util.Hashtable; @@ -83,8 +79,6 @@ import javax.swing.event.TreeModelListener; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; -import javax.swing.plaf.ComponentUI; -import javax.swing.plaf.TreeUI; import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicGraphicsUtils; import javax.swing.text.Position; @@ -104,6 +98,7 @@ import sun.swing.SwingUtilities2; import sun.swing.UIAction; import swingjs.api.js.DOMNode; +import swingjs.api.js.JQueryObject; /** * SwingJS starting point was BasicTreeUI; @@ -117,7 +112,7 @@ * @author Shannon Hickey (drag and drop) */ -public class JSTreeUI extends JSComponentUI { +public class JSTreeUI extends JSPanelUI { private static final StringBuilder BASELINE_COMPONENT_KEY = new StringBuilder("Tree.baselineComponent"); // Old actions forward to an instance of this. @@ -291,6 +286,8 @@ public class JSTreeUI extends JSComponentUI { */ private MouseEvent releaseEvent; + private String selectionBackground; + // public static ComponentUI createUI(JComponent x) { // return new JSTreeUI(); // } @@ -364,13 +361,22 @@ public JSTreeUI() { super(); } + @Override public DOMNode updateDOMNode() { - // TODO - super.updateDOMNode(); if (domNode == null) { - domNode = DOMNode.createElement("div", id); + + domNode = focusNode = enableNode = newDOMObject("div", id); + // maybe DOMNode.setAttrInt(domNode, "tabIndex", 1); + //innerNode = newDOMObject("div", id + "_inner"); + addFocusHandler(); + +// domNode.appendChild(innerNode); + // tell j2sApplet.js that we will handle all the mouse clicks here +// setDataComponent(focusNode); +// bindJSKeyEvents(focusNode, false); } - return domNode; + setBackgroundImpl(jc.getBackground()); + return updateDOMNodeCUI(); } protected Color getHashColor() { @@ -707,6 +713,7 @@ public TreePath getEditingPath(JTree tree) { // Install methods // + @Override public void installUI(JComponent c) { if (c == null) { throw new NullPointerException("null component passed to JSTreeUI.installUI()"); @@ -770,6 +777,7 @@ protected void installDefaults() { if (tree.getBackground() == null || tree.getBackground() instanceof UIResource) { tree.setBackground(UIManager.getColor("Tree.background")); } + selectionBackground = toCSSString(UIManager.getColor("Tree.selectionBackground")); if (getHashColor() == null || getHashColor() instanceof UIResource) { setHashColor(UIManager.getColor("Tree.hash")); } @@ -1029,6 +1037,7 @@ protected TreeModelListener createTreeModelListener() { // Uninstall methods // + @Override public void uninstallUI(JComponent c) { completeEditing(); @@ -1143,6 +1152,7 @@ private void redoTheLayout() { * @see javax.swing.JComponent#getBaseline(int, int) * @since 1.6 */ + @Override public int getBaseline(JComponent c, int width, int height) { super.getBaseline(c, width, height); UIDefaults lafDefaults = UIManager.getLookAndFeelDefaults(); @@ -1171,6 +1181,7 @@ public int getBaseline(JComponent c, int width, int height) { * @see javax.swing.JComponent#getBaseline(int, int) * @since 1.6 */ + @Override public Component.BaselineResizeBehavior getBaselineResizeBehavior(JComponent c) { super.getBaselineResizeBehavior(c); return Component.BaselineResizeBehavior.CONSTANT_ASCENT; @@ -1180,7 +1191,9 @@ public Component.BaselineResizeBehavior getBaselineResizeBehavior(JComponent c) // Painting routines. // + @Override public void paint(Graphics g, JComponent c) { + super.paint(g, c); if (tree != c) { throw new InternalError("incorrect component"); } @@ -1211,7 +1224,6 @@ public void paint(Graphics g, JComponent c) { drawingCache.put(parentPath, Boolean.TRUE); parentPath = parentPath.getParentPath(); } - boolean done = false; // Information for the node being rendered. boolean isExpanded; @@ -1269,11 +1281,25 @@ public void paint(Graphics g, JComponent c) { paintDropLine(g); // Empty out the renderer pane, allowing renderers to be gc'ed. - rendererPane.removeAll(); + + //rendererPane.removeAll(); drawingCache.clear(); } + private String getPathID(TreePath path) { + String s = ""; + while (path != null) { + s = "_" + getNodeId(path) + s; + path = path.getParentPath(); + } + return id + s; + } + + private String getNodeId(TreePath path) { + return (path == null ? "" : "" + path.hashCode()); + } + /** * Tells if a {@code DropLocation} should be indicated by a line between nodes. * This is meant for {@code javax.swing.DropMode.INSERT} and @@ -1495,7 +1521,6 @@ protected void paintExpandControl(Graphics g, Rectangle clipBounds, Insets inset middleXOfKnob = bounds.x + bounds.width + getRightChildIndent() - 1; } int middleYOfKnob = bounds.y + (bounds.height / 2); - if (isExpanded) { Icon expandedIcon = getExpandedIcon(); if (expandedIcon != null) @@ -1505,9 +1530,37 @@ protected void paintExpandControl(Graphics g, Rectangle clipBounds, Insets inset if (collapsedIcon != null) drawCentered(tree, g, collapsedIcon, middleXOfKnob, middleYOfKnob); } + displayJSPath(path, isExpanded); } } + private void displayJSPath(TreePath path, boolean isExpanded) { + String myid = getPathID(path); + $("[id^=" + myid + "_]").css("display",isExpanded ? "block" : "none"); + } +// +// private void hideCollapsedPath(TreePath path) { +// String myid = getPathID(path); +// Object p = path.getLastPathComponent(); +// if (p instanceof TreeNode) { +// TreeNode t = (TreeNode) p; +// DOMNode[] divs = (DOMNode[]) (Object) $("#" + myid).find("*"); +// for (int i = t.getChildCount(); --i >= 0;) { +// /** @j2sNative xxm = myid */ +// +// TreeNode tc = t.getChildAt(i); +// System.out.println("hide collapsed " + myid + " " + tc + " " + divs[i]); +// } +// +// +// } +// } +// +// private void hideItem(JComponent c, TreePath path) { +// c.setVisible(false); +// } +// + /** * Paints the renderer part of a row. The receiver should NOT modify * clipBounds, or insets. @@ -1524,13 +1577,46 @@ protected void paintRow(Graphics g, Rectangle clipBounds, Insets insets, Rectang leadIndex = getLeadSelectionRow(); } else leadIndex = -1; - - Component component; - - component = currentCellRenderer.getTreeCellRendererComponent(tree, path.getLastPathComponent(), - tree.isRowSelected(row), isExpanded, isLeaf, row, (leadIndex == row)); - - rendererPane.paintComponent(g, component, tree, bounds.x, bounds.y, bounds.width, bounds.height, true); + updateItem(g, path, row, isExpanded, isLeaf, leadIndex == row, bounds, true); + } + + private void updateItem(Graphics g, TreePath path, int row, boolean isExpanded, boolean isLeaf, boolean isLead, + Rectangle bounds, boolean isVisible) { + Component component = currentCellRenderer.getTreeCellRendererComponent(tree, path.getLastPathComponent(), + tree.isRowSelected(row), isExpanded, isLeaf, row, isLead); + int cx = bounds.x; + int cy = bounds.y; + int cw = bounds.width; + int ch = bounds.height; + if (isVisible) + rendererPane.paintComponent(g, component, tree, cx, cy, cw, ch, true); + updateItemHTML((JComponent) component, path, cx, cy, cw, tree.getRowHeight()); + } + + private void updateItemHTML(JComponent c, TreePath path, int left, int top, int width, int height) { + c.setSize(width, height); + c.setVisible(true); + JSComponentUI ui = c.秘getUI(); + DOMNode node = ui.getListNode(); + ui.updateDOMNode(); + String myid = getPathID(path); + JQueryObject jnode = $((DOMNode) (Object) ("#" + myid)); + DOMNode div = JQueryObject.getDOMNode(jnode); + //System.out.println("updateItemHTML " + " " + myid + " " + path); + if (div == null) { + div = newDOMObject("div", myid); + div.appendChild(node); + domNode.appendChild(div); + } else { + jnode.empty(); + if (node != null) + jnode.append(node); + } + // Rectangle r = getCellBounds1(list, index); + DOMNode.setSize(node, width, height); + DOMNode.setTopLeftAbsolute(node, top, left); + DOMNode.setStyles(node, "display", null); + $("#" + DOMNode.getAttrInt(node,"id") + "_txt").css("background", path.equals(tree.getSelectionPath()) ? selectionBackground : null); } /** @@ -1652,8 +1738,10 @@ protected int getRowX(int row, int depth) { * invokes updateExpandedDescendants with the root path. */ protected void updateLayoutCacheExpandedNodes() { - if (treeModel != null && treeModel.getRoot() != null) - updateExpandedDescendants(new TreePath(treeModel.getRoot())); + if (treeModel != null && treeModel.getRoot() != null) { + TreePath rootPath = new TreePath(treeModel.getRoot()); + updateExpandedDescendants(rootPath); + } } private void updateLayoutCacheExpandedNodesIfNecessary() { @@ -1680,7 +1768,7 @@ protected void updateExpandedDescendants(TreePath path) { Enumeration descendants = tree.getExpandedDescendants(path); if (descendants != null) { - while (descendants.hasMoreElements()) { + while (descendants.hasMoreElements()) { path = (TreePath) descendants.nextElement(); treeState.setExpandedState(path, true); } @@ -1955,6 +2043,7 @@ public Dimension getPreferredMinSize() { * Returns the preferred size to properly display the tree, this is a cover * method for getPreferredSize(c, true). */ + @Override public Dimension getPreferredSize(JComponent c) { return getPreferredSize(c, true); } @@ -1983,6 +2072,7 @@ public Dimension getPreferredSize(JComponent c, boolean checkConsistency) { * Returns the minimum size for this component. Which will be the min preferred * size or 0, 0. */ + @Override public Dimension getMinimumSize(JComponent c) { if (this.getPreferredMinSize() != null) return this.getPreferredMinSize(); @@ -1993,6 +2083,7 @@ public Dimension getMinimumSize(JComponent c) { * Returns the maximum size for this component, which will be the preferred size * if the instance is currently in a JTree, or 0, 0. */ + @Override public Dimension getMaximumSize(JComponent c) { if (tree != null) return getPreferredSize(tree); @@ -2337,11 +2428,7 @@ else if (SwingUtilities.isLeftMouseButton(event)) { */ protected boolean isLeaf(int row) { TreePath path = getPathForRow(tree, row); - - if (path != null) - return treeModel.isLeaf(path.getLastPathComponent()); - // Have to return something here... - return true; + return (path == null || treeModel.isLeaf(path.getLastPathComponent())); } // @@ -2465,6 +2552,7 @@ public class TreeExpansionHandler implements TreeExpansionListener { /** * Called whenever an item in the tree has been expanded. */ + @Override public void treeExpanded(TreeExpansionEvent event) { getHandler().treeExpanded(event); } @@ -2472,6 +2560,7 @@ public void treeExpanded(TreeExpansionEvent event) { /** * Called whenever an item in the tree has been collapsed. */ + @Override public void treeCollapsed(TreeExpansionEvent event) { getHandler().treeCollapsed(event); } @@ -2488,6 +2577,7 @@ public class ComponentHandler extends ComponentAdapter implements ActionListener /** ScrollBar that is being adjusted. */ protected JScrollBar scrollBar; + @Override public void componentMoved(ComponentEvent e) { if (timer == null) { JScrollPane scrollPane = getScrollPane(); @@ -2538,6 +2628,7 @@ protected JScrollPane getScrollPane() { * Public as a result of Timer. If the scrollBar is null, or not adjusting, this * stops the timer and updates the sizing. */ + @Override public void actionPerformed(ActionEvent ae) { if (scrollBar == null || !scrollBar.getValueIsAdjusting()) { if (timer != null) @@ -2559,18 +2650,22 @@ public class TreeModelHandler implements TreeModelListener { // new functionality add it to the Handler, but make sure this // class calls into the Handler. + @Override public void treeNodesChanged(TreeModelEvent e) { getHandler().treeNodesChanged(e); } + @Override public void treeNodesInserted(TreeModelEvent e) { getHandler().treeNodesInserted(e); } + @Override public void treeNodesRemoved(TreeModelEvent e) { getHandler().treeNodesRemoved(e); } + @Override public void treeStructureChanged(TreeModelEvent e) { getHandler().treeStructureChanged(e); } @@ -2591,6 +2686,7 @@ public class TreeSelectionHandler implements TreeSelectionListener { * Messaged when the selection changes in the tree we're displaying for. Stops * editing, messages super and displays the changed paths. */ + @Override public void valueChanged(TreeSelectionEvent event) { getHandler().valueChanged(event); } @@ -2608,11 +2704,13 @@ public class CellEditorHandler implements CellEditorListener { // class calls into the Handler. /** Messaged when editing has stopped in the tree. */ + @Override public void editingStopped(ChangeEvent e) { getHandler().editingStopped(e); } /** Messaged when editing has been canceled in the tree. */ + @Override public void editingCanceled(ChangeEvent e) { getHandler().editingCanceled(e); } @@ -2646,14 +2744,17 @@ public class KeyHandler extends KeyAdapter { * alphanumeric key pressed by the user. Subsequent same key presses move the * keyboard focus to the next object that starts with the same letter. */ + @Override public void keyTyped(KeyEvent e) { getHandler().keyTyped(e); } + @Override public void keyPressed(KeyEvent e) { getHandler().keyPressed(e); } + @Override public void keyReleased(KeyEvent e) { getHandler().keyReleased(e); } @@ -2671,6 +2772,7 @@ public class FocusHandler implements FocusListener { /** * Invoked when focus is activated on the tree we're in, redraws the lead row. */ + @Override public void focusGained(FocusEvent e) { getHandler().focusGained(e); } @@ -2678,6 +2780,7 @@ public void focusGained(FocusEvent e) { /** * Invoked when focus is activated on the tree we're in, redraws the lead row. */ + @Override public void focusLost(FocusEvent e) { getHandler().focusLost(e); } @@ -2692,6 +2795,7 @@ public class NodeDimensionsHandler extends AbstractLayoutCache.NodeDimensions { /** * Responsible for getting the size of a particular node. */ + @Override public Rectangle getNodeDimensions(Object value, int row, int depth, boolean expanded, Rectangle size) { // Return size of editing component, if editing and asking // for editing row. @@ -2757,10 +2861,12 @@ public class MouseHandler extends MouseAdapter implements MouseMotionListener { /** * Invoked when a mouse button has been pressed on a component. */ + @Override public void mousePressed(MouseEvent e) { getHandler().mousePressed(e); } + @Override public void mouseDragged(MouseEvent e) { getHandler().mouseDragged(e); } @@ -2771,10 +2877,12 @@ public void mouseDragged(MouseEvent e) { * * @since 1.4 */ + @Override public void mouseMoved(MouseEvent e) { getHandler().mouseMoved(e); } + @Override public void mouseReleased(MouseEvent e) { getHandler().mouseReleased(e); } @@ -2791,6 +2899,7 @@ public class PropertyChangeHandler implements PropertyChangeListener { // new functionality add it to the Handler, but make sure this // class calls into the Handler. + @Override public void propertyChange(PropertyChangeEvent event) { getHandler().propertyChange(event); } @@ -2807,6 +2916,7 @@ public class SelectionModelPropertyChangeHandler implements PropertyChangeListen // new functionality add it to the Handler, but make sure this // class calls into the Handler. + @Override public void propertyChange(PropertyChangeEvent event) { getHandler().propertyChange(event); } @@ -2836,12 +2946,14 @@ private TreeTraverseAction(int direction, String name, boolean changeSelection) this.changeSelection = changeSelection; } + @Override public void actionPerformed(ActionEvent e) { if (tree != null) { SHARED_ACTION.traverse(tree, JSTreeUI.this, direction, changeSelection); } } + @Override public boolean isEnabled() { return (tree != null && tree.isEnabled()); } @@ -2867,12 +2979,14 @@ private TreePageAction(int direction, String name, boolean addToSelection, boole this.changeSelection = changeSelection; } + @Override public void actionPerformed(ActionEvent e) { if (tree != null) { SHARED_ACTION.page(tree, JSTreeUI.this, direction, addToSelection, changeSelection); } } + @Override public boolean isEnabled() { return (tree != null && tree.isEnabled()); } @@ -2903,12 +3017,14 @@ private TreeIncrementAction(int direction, String name, boolean addToSelection, this.changeSelection = changeSelection; } + @Override public void actionPerformed(ActionEvent e) { if (tree != null) { SHARED_ACTION.increment(tree, JSTreeUI.this, direction, addToSelection, changeSelection); } } + @Override public boolean isEnabled() { return (tree != null && tree.isEnabled()); } @@ -2935,12 +3051,14 @@ private TreeHomeAction(int direction, String name, boolean addToSelection, boole this.addToSelection = addToSelection; } + @Override public void actionPerformed(ActionEvent e) { if (tree != null) { SHARED_ACTION.home(tree, JSTreeUI.this, direction, addToSelection, changeSelection); } } + @Override public boolean isEnabled() { return (tree != null && tree.isEnabled()); } @@ -2954,12 +3072,14 @@ public class TreeToggleAction extends AbstractAction { public TreeToggleAction(String name) { } + @Override public void actionPerformed(ActionEvent e) { if (tree != null) { SHARED_ACTION.toggle(tree, JSTreeUI.this); } } + @Override public boolean isEnabled() { return (tree != null && tree.isEnabled()); } @@ -2973,12 +3093,14 @@ public class TreeCancelEditingAction extends AbstractAction { public TreeCancelEditingAction(String name) { } + @Override public void actionPerformed(ActionEvent e) { if (tree != null) { SHARED_ACTION.cancelEditing(tree, JSTreeUI.this); } } + @Override public boolean isEnabled() { return (tree != null && tree.isEnabled() && isEditing(tree)); } @@ -3014,6 +3136,7 @@ public MouseInputHandler(Component source, Component destination, MouseEvent eve this.focusComponent = focusComponent; } + @Override public void mouseClicked(MouseEvent e) { if (destination != null) { dispatchedEvent = true; @@ -3021,27 +3144,32 @@ public void mouseClicked(MouseEvent e) { } } + @Override public void mousePressed(MouseEvent e) { } + @Override public void mouseReleased(MouseEvent e) { if (destination != null) destination.dispatchEvent(SwingUtilities.convertMouseEvent(source, e, destination)); removeFromSource(); } + @Override public void mouseEntered(MouseEvent e) { if (!SwingUtilities.isLeftMouseButton(e)) { removeFromSource(); } } + @Override public void mouseExited(MouseEvent e) { if (!SwingUtilities.isLeftMouseButton(e)) { removeFromSource(); } } + @Override public void mouseDragged(MouseEvent e) { if (destination != null) { dispatchedEvent = true; @@ -3049,6 +3177,7 @@ public void mouseDragged(MouseEvent e) { } } + @Override public void mouseMoved(MouseEvent e) { removeFromSource(); } @@ -3184,6 +3313,7 @@ private class Handler implements CellEditorListener, FocusListener, KeyListener, * is treated as the prefix with appropriate number of the same letters followed * by first typed another letter. */ + @Override public void keyTyped(KeyEvent e) { // handle first letter navigation if (tree != null && tree.getRowCount() > 0 && tree.hasFocus() && tree.isEnabled()) { @@ -3238,6 +3368,7 @@ public void keyTyped(KeyEvent e) { * Checks to see if the key event is a navigation key to prevent dispatching * these keys for the first letter navigation. */ + @Override public void keyPressed(KeyEvent e) { if (tree != null && isNavigationKey(e)) { prefix = ""; @@ -3246,6 +3377,7 @@ public void keyPressed(KeyEvent e) { } } + @Override public void keyReleased(KeyEvent e) { } @@ -3264,6 +3396,7 @@ private boolean isNavigationKey(KeyEvent event) { // // PropertyChangeListener // + @Override public void propertyChange(PropertyChangeEvent event) { if (event.getSource() == treeSelectionModel) { treeSelectionModel.resetRowSelection(); @@ -3376,18 +3509,22 @@ private boolean isActualPath(TreePath path, int x, int y) { return (x >= bounds.x) && (x <= (bounds.x + bounds.width)); } + @Override public void mouseClicked(MouseEvent e) { } + @Override public void mouseEntered(MouseEvent e) { } + @Override public void mouseExited(MouseEvent e) { } /** * Invoked when a mouse button has been pressed on a component. */ + @Override public void mousePressed(MouseEvent e) { if (SwingUtilities2.shouldIgnore(e, tree)) { return; @@ -3488,6 +3625,7 @@ public void dragStarting(MouseEvent me) { pressedPath = null; } + @Override public void mouseDragged(MouseEvent e) { if (SwingUtilities2.shouldIgnore(e, tree)) { return; @@ -3503,9 +3641,11 @@ public void mouseDragged(MouseEvent e) { * Invoked when the mouse button has been moved on a component (with no buttons * no down). */ + @Override public void mouseMoved(MouseEvent e) { } + @Override public void mouseReleased(MouseEvent e) { if (SwingUtilities2.shouldIgnore(e, tree)) { return; @@ -3551,6 +3691,7 @@ && isActualPath(pressedPath, pressedEvent.getX(), pressedEvent.getY())) { // // FocusListener // + @Override public void focusGained(FocusEvent e) { if (tree != null) { Rectangle pBounds; @@ -3564,6 +3705,7 @@ public void focusGained(FocusEvent e) { } } + @Override public void focusLost(FocusEvent e) { focusGained(e); } @@ -3571,11 +3713,13 @@ public void focusLost(FocusEvent e) { // // CellEditorListener // + @Override public void editingStopped(ChangeEvent e) { completeEditing(false, false, true); } /** Messaged when editing has been canceled in the tree. */ + @Override public void editingCanceled(ChangeEvent e) { completeEditing(false, false, false); } @@ -3583,6 +3727,7 @@ public void editingCanceled(ChangeEvent e) { // // TreeSelectionListener // + @Override public void valueChanged(TreeSelectionEvent event) { valueChangedOnPress = true; @@ -3654,6 +3799,7 @@ public void valueChanged(TreeSelectionEvent event) { // // TreeExpansionListener // + @Override public void treeExpanded(TreeExpansionEvent event) { if (event != null && tree != null) { TreePath path = event.getPath(); @@ -3662,6 +3808,7 @@ public void treeExpanded(TreeExpansionEvent event) { } } + @Override public void treeCollapsed(TreeExpansionEvent event) { if (event != null && tree != null) { TreePath path = event.getPath(); @@ -3678,6 +3825,7 @@ public void treeCollapsed(TreeExpansionEvent event) { // // TreeModelListener // + @Override public void treeNodesChanged(TreeModelEvent e) { if (treeState != null && e != null) { TreePath parentPath = SwingUtilities2.getTreePath(e, getModel()); @@ -3722,6 +3870,7 @@ public void treeNodesChanged(TreeModelEvent e) { } } + @Override public void treeNodesInserted(TreeModelEvent e) { if (treeState != null && e != null) { treeState.treeNodesInserted(e); @@ -3745,6 +3894,7 @@ public void treeNodesInserted(TreeModelEvent e) { } } + @Override public void treeNodesRemoved(TreeModelEvent e) { if (treeState != null && e != null) { treeState.treeNodesRemoved(e); @@ -3758,6 +3908,7 @@ public void treeNodesRemoved(TreeModelEvent e) { } } + @Override public void treeStructureChanged(TreeModelEvent e) { if (treeState != null && e != null) { treeState.treeStructureChanged(e); @@ -3833,6 +3984,7 @@ private static class Actions extends UIAction { super(key); } + @Override public boolean isEnabled(Object o) { if (o instanceof JTree) { if (getName() == CANCEL_EDITING) { @@ -3842,6 +3994,7 @@ public boolean isEnabled(Object o) { return true; } + @Override public void actionPerformed(ActionEvent e) { JTree tree = (JTree) e.getSource(); JSTreeUI ui = (JSTreeUI) tree.getUI();// HTML5LookAndFeel.getUIOfType(tree.getUI(), JSTreeUI.class); @@ -4301,6 +4454,7 @@ private void home(JTree tree, final JSTreeUI ui, int direction, boolean addToSel } if (ui.isLargeModel()) { SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { ui.ensureRowsAreVisible(rowCount - 1, rowCount - 1); } diff --git a/sources/net.sf.j2s.java.core/src/swingjs/plaf/TreeClosed.gif b/sources/net.sf.j2s.java.core/src/swingjs/plaf/TreeClosed.gif new file mode 100644 index 000000000..fa34e2f5e Binary files /dev/null and b/sources/net.sf.j2s.java.core/src/swingjs/plaf/TreeClosed.gif differ diff --git a/sources/net.sf.j2s.java.core/src/swingjs/plaf/TreeOpen.gif b/sources/net.sf.j2s.java.core/src/swingjs/plaf/TreeOpen.gif new file mode 100644 index 000000000..fa34e2f5e Binary files /dev/null and b/sources/net.sf.j2s.java.core/src/swingjs/plaf/TreeOpen.gif differ diff --git a/sources/net.sf.j2s.java.core/src/test/Test_.java b/sources/net.sf.j2s.java.core/src/test/Test_.java index 127e47a5e..911fd0fdd 100644 --- a/sources/net.sf.j2s.java.core/src/test/Test_.java +++ b/sources/net.sf.j2s.java.core/src/test/Test_.java @@ -138,6 +138,7 @@ public static void main(String[] args) { Test_GenericAnon.main(args); Test_GenericEABIXY2.main(args); Test_GenericExt2.main(args); + Test_Image.main(args); Test_Init.main(args); Test_Inner.main(args); Test_Instance.main(args); diff --git a/sources/net.sf.j2s.java.core/src/test/Test_Image.java b/sources/net.sf.j2s.java.core/src/test/Test_Image.java new file mode 100644 index 000000000..3b53fbb65 --- /dev/null +++ b/sources/net.sf.j2s.java.core/src/test/Test_Image.java @@ -0,0 +1,43 @@ +package test; + +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.IndexColorModel; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; + +/** + * Check for fields initialization timing. + * + * @author RM + * + */ +public class Test_Image extends Test_ { + + public static void main(String[] args) { + + int nx = 4, ny = 4; + int len = ((nx+7)/8)*ny; // each row starts on a byte boundary + byte[] packedData = new byte[len]; + for (int i = 0; i < len; i++) { + packedData[i] = (byte) i; + } + DataBuffer databuffer = new DataBufferByte(packedData, len); + WritableRaster raster = Raster.createPackedRaster(databuffer, nx, ny, 1, null); + // default colors are red and blue + ColorModel colorModel = new IndexColorModel(1, 2, new byte[] {(byte) 255, (byte) 0}, new byte[] {(byte) 0, (byte) 0}, new byte[] {(byte) 0, (byte) 255}); + BufferedImage image = new BufferedImage(colorModel, raster, false, null); + + int n = nx * ny; + int[] pixels = new int[n * 4]; + for (int i = 0, pt = 0; i < n; i++, pt+=4) { + image.getColorModel().getComponents(i, pixels, pt); + System.out.println(pixels[pt] + " " + pixels[pt+1] + " " + pixels[pt+2] + " " + pixels[pt+3]); + } + + System.out.println("Test_Image OK"); + } + +} diff --git a/sources/net.sf.j2s.java.core/src/test/Test_Interface.java b/sources/net.sf.j2s.java.core/src/test/Test_Interface.java index 1d35ce62b..02368c4a9 100644 --- a/sources/net.sf.j2s.java.core/src/test/Test_Interface.java +++ b/sources/net.sf.j2s.java.core/src/test/Test_Interface.java @@ -1,37 +1,57 @@ package test; -public interface Test_Interface { - +public interface Test_Interface { + int x = 3; String y = "y"; String[] s = new String[3]; - + class Inner extends Test_ { String test(String s) { return s; } } - + public static int doTest(int i) { return i + 1; } - + public interface Test_Interface_inner { // This mus be wrapped, or C$ changes definitions } - - public static void main(String[] args) { - ClassLoader.getSystemClassLoader().setClassAssertionStatus("test.Test_Interface", true); - - Inner inner = new Inner(); - System.out.println(inner.test("1") == "1"); - - assert(inner.test("1") == "1"); - - System.out.println("in the interface " + x + " " + y); - assert("3 y".equals(x + " " + y)); - System.out.println("Test_Interface OK"); - - } - + + class Int1 implements Test_inta1 { + + + @Override + public String testInt(Number n) { + return n.toString(); + } + + public String testInt() { + return null; + } + } + public static void main(String[] args) { + + String xx = ((Test_inta1)new Int1()).testInt(Integer.valueOf(1)); + if (!"1".equals(xx)) + throw new AssertionError(); + + +// ClassLoader.getSystemClassLoader().setClassAssertionStatus("test.Test_Interface", true); + + Inner inner = new Inner(); + System.out.println(inner.test("1") == "1"); + + if (!"1".equals(inner.test("1"))) + throw new AssertionError(); + + System.out.println("in the interface " + x + " " + y); + if (!("3 y".equals(x + " " + y))) + throw new AssertionError(); + System.out.println("Test_Interface OK"); + + } + } \ No newline at end of file diff --git a/sources/net.sf.j2s.java.core/src/test/Test_Interface2.java b/sources/net.sf.j2s.java.core/src/test/Test_Interface2.java index ef3520dd4..f0fe3b1e9 100644 --- a/sources/net.sf.j2s.java.core/src/test/Test_Interface2.java +++ b/sources/net.sf.j2s.java.core/src/test/Test_Interface2.java @@ -1,18 +1,17 @@ package test; -public class Test_Interface2 implements Test_Interface { - +public class Test_Interface2 implements Test_Interface { + static int x = 5; - - public static void main(String[] args) { - ClassLoader.getSystemClassLoader().setClassAssertionStatus("test.Test_Interface", true); - System.out.println("in the interface " + x + " " + y + " " + s.length); - assert("5 y".equals(x + " " + y)); - assert(Test_Interface3.doTest(3) == 4); - System.out.println("Test_Interface OK"); - - } + public static void main(String[] args) { + ClassLoader.getSystemClassLoader().setClassAssertionStatus("test.Test_Interface", true); + System.out.println("in the interface " + x + " " + y + " " + s.length); + if (!"5 y".equals(x + " " + y)) + throw new AssertionError(); + if (Test_Interface3.doTest(3) != 4) + throw new AssertionError(); + System.out.println("Test_Interface2 OK"); + } - } \ No newline at end of file diff --git a/sources/net.sf.j2s.java.core/src/test/components/TreeDemo.java b/sources/net.sf.j2s.java.core/src/test/components/TreeDemo.java new file mode 100644 index 000000000..97edcbac9 --- /dev/null +++ b/sources/net.sf.j2s.java.core/src/test/components/TreeDemo.java @@ -0,0 +1,285 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package test.components; + +/** + * This application that requires the following additional files: + * TreeDemoHelp.html + * arnold.html + * bloch.html + * chan.html + * jls.html + * swingtutorial.html + * tutorial.html + * tutorialcont.html + * vm.html + */ +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.UIManager; + +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreeSelectionModel; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; + +import java.net.URL; +import java.io.IOException; +import java.awt.Dimension; +import java.awt.GridLayout; + +public class TreeDemo extends JPanel + implements TreeSelectionListener { + private JEditorPane htmlPane; + private JTree tree; + private URL helpURL; + private static boolean DEBUG = false; + + //Optionally play with line styles. Possible values are + //"Angled" (the default), "Horizontal", and "None". + private static boolean playWithLineStyle = false; + private static String lineStyle = "Horizontal"; + + //Optionally set the look and feel. + private static boolean useSystemLookAndFeel = false; + + public TreeDemo() { + super(new GridLayout(1,0)); + + //Create the nodes. + DefaultMutableTreeNode top = + new DefaultMutableTreeNode("The Java Series"); + createNodes(top); + + //Create a tree that allows one selection at a time. + tree = new JTree(top); + tree.getSelectionModel().setSelectionMode + (TreeSelectionModel.SINGLE_TREE_SELECTION); + + //Listen for when the selection changes. + tree.addTreeSelectionListener(this); + + if (playWithLineStyle) { + System.out.println("line style = " + lineStyle); + tree.putClientProperty("JTree.lineStyle", lineStyle); + } + + //Create the scroll pane and add the tree to it. + JScrollPane treeView = new JScrollPane(tree); + + //Create the HTML viewing pane. + htmlPane = new JEditorPane(); + htmlPane.setEditable(false); + initHelp(); + JScrollPane htmlView = new JScrollPane(htmlPane); + + //Add the scroll panes to a split pane. + JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); + splitPane.setTopComponent(treeView); + splitPane.setBottomComponent(htmlView); + + Dimension minimumSize = new Dimension(100, 50); + htmlView.setMinimumSize(minimumSize); + treeView.setMinimumSize(minimumSize); + splitPane.setDividerLocation(100); + splitPane.setPreferredSize(new Dimension(500, 300)); + + //Add the split pane to this panel. + add(splitPane); + } + + /** Required by TreeSelectionListener interface. */ + public void valueChanged(TreeSelectionEvent e) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) + tree.getLastSelectedPathComponent(); + + if (node == null) return; + + Object nodeInfo = node.getUserObject(); + if (node.isLeaf()) { + BookInfo book = (BookInfo)nodeInfo; + displayURL(book.bookURL); + if (DEBUG) { + System.out.print(book.bookURL + ": \n "); + } + } else { + displayURL(helpURL); + } + if (DEBUG) { + System.out.println(nodeInfo.toString()); + } + } + + private class BookInfo { + public String bookName; + public URL bookURL; + + public BookInfo(String book, String filename) { + bookName = book; + bookURL = getClass().getResource("html/" + filename); + if (bookURL == null) { + System.err.println("Couldn't find file: " + + filename); + } + } + + public String toString() { + return bookName; + } + } + + private void initHelp() { + String s = "TreeDemoHelp.html"; + helpURL = getClass().getResource(s); + if (helpURL == null) { + System.err.println("Couldn't open help file: " + s); + } else if (DEBUG) { + System.out.println("Help URL is " + helpURL); + } + + displayURL(helpURL); + } + + private void displayURL(URL url) { + try { + if (url != null) { + htmlPane.setPage(url); + } else { //null url + htmlPane.setText("File Not Found"); + if (DEBUG) { + System.out.println("Attempted to display a null URL."); + } + } + } catch (IOException e) { + System.err.println("Attempted to read a bad URL: " + url); + } + } + + private void createNodes(DefaultMutableTreeNode top) { + DefaultMutableTreeNode category = null; + DefaultMutableTreeNode book = null; + + category = new DefaultMutableTreeNode("Books for Java Programmers"); + top.add(category); + + //original Tutorial + book = new DefaultMutableTreeNode(new BookInfo + ("The Java Tutorial: A Short Course on the Basics", + "tutorial.html")); + category.add(book); + + //Tutorial Continued + book = new DefaultMutableTreeNode(new BookInfo + ("The Java Tutorial Continued: The Rest of the JDK", + "tutorialcont.html")); + category.add(book); + + //JFC Swing Tutorial + book = new DefaultMutableTreeNode(new BookInfo + ("The JFC Swing Tutorial: A Guide to Constructing GUIs", + "swingtutorial.html")); + category.add(book); + + //Bloch + book = new DefaultMutableTreeNode(new BookInfo + ("Effective Java Programming Language Guide", + "bloch.html")); + category.add(book); + + //Arnold/Gosling + book = new DefaultMutableTreeNode(new BookInfo + ("The Java Programming Language", "arnold.html")); + category.add(book); + + //Chan + book = new DefaultMutableTreeNode(new BookInfo + ("The Java Developers Almanac", + "chan.html")); + category.add(book); + + category = new DefaultMutableTreeNode("Books for Java Implementers"); + top.add(category); + + //VM + book = new DefaultMutableTreeNode(new BookInfo + ("The Java Virtual Machine Specification", + "vm.html")); + category.add(book); + + //Language Spec + book = new DefaultMutableTreeNode(new BookInfo + ("The Java Language Specification", + "jls.html")); + category.add(book); + } + + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event dispatch thread. + */ + private static void createAndShowGUI() { + if (useSystemLookAndFeel) { + try { + UIManager.setLookAndFeel( + UIManager.getSystemLookAndFeelClassName()); + } catch (Exception e) { + System.err.println("Couldn't use system look and feel."); + } + } + + //Create and set up the window. + JFrame frame = new JFrame("TreeDemo"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + //Add content to the window. + frame.add(new TreeDemo()); + + //Display the window. + frame.pack(); + frame.setVisible(true); + } + + public static void main(String[] args) { + //Schedule a job for the event dispatch thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + public void run() { + createAndShowGUI(); + } + }); + } +} diff --git a/sources/net.sf.j2s.java.core/src/test/components/TreeDemoHelp.html b/sources/net.sf.j2s.java.core/src/test/components/TreeDemoHelp.html new file mode 100644 index 000000000..787f7f997 --- /dev/null +++ b/sources/net.sf.j2s.java.core/src/test/components/TreeDemoHelp.html @@ -0,0 +1,17 @@ + + +

Tree Demo

+ +This is the help file (TreeDemoHelp.html) +for the tree demo. +Selecting any branch node in the tree results +in this file being displayed. +When you select a leaf node (a book), +this pane displays an HTML file for that book. + +

+This demo uses a split pane +to separate the tree and this HTML view. +Drag the divider up or down to change the space distribution. + + diff --git a/sources/net.sf.j2s.java.core/src/test/components/html/arnold.html b/sources/net.sf.j2s.java.core/src/test/components/html/arnold.html new file mode 100644 index 000000000..f414fbb7f --- /dev/null +++ b/sources/net.sf.j2s.java.core/src/test/components/html/arnold.html @@ -0,0 +1,11 @@ + + +

+The Java Programming Language +

+ +

+blah, blah, blah, blah, blah... + + + diff --git a/sources/net.sf.j2s.java.core/src/test/components/html/bloch.html b/sources/net.sf.j2s.java.core/src/test/components/html/bloch.html new file mode 100644 index 000000000..55792445b --- /dev/null +++ b/sources/net.sf.j2s.java.core/src/test/components/html/bloch.html @@ -0,0 +1,13 @@ + + +

+Effective Java +
+Programming Language Guide +

+ +

+blah, blah, blah, blah, blah... + + + diff --git a/sources/net.sf.j2s.java.core/src/test/components/html/chan.html b/sources/net.sf.j2s.java.core/src/test/components/html/chan.html new file mode 100644 index 000000000..303be54b3 --- /dev/null +++ b/sources/net.sf.j2s.java.core/src/test/components/html/chan.html @@ -0,0 +1,11 @@ + + +

+The Java Developers Almanac +

+ +

+blah, blah, blah, blah, blah... + + + diff --git a/sources/net.sf.j2s.java.core/src/test/components/html/jls.html b/sources/net.sf.j2s.java.core/src/test/components/html/jls.html new file mode 100644 index 000000000..8bfc368a5 --- /dev/null +++ b/sources/net.sf.j2s.java.core/src/test/components/html/jls.html @@ -0,0 +1,11 @@ + + +

+The Java Language Specification +

+ +

+blah, blah, blah, blah, blah... + + + diff --git a/sources/net.sf.j2s.java.core/src/test/components/html/swingtutorial.html b/sources/net.sf.j2s.java.core/src/test/components/html/swingtutorial.html new file mode 100644 index 000000000..80930148d --- /dev/null +++ b/sources/net.sf.j2s.java.core/src/test/components/html/swingtutorial.html @@ -0,0 +1,14 @@ + + +

+The JFC Swing Tutorial +

+ +

+This is the UI trail from the original Tutorial, +updated and expanded to reflect the Swing components. +More fun than a barrel full of monkeys! +Much more fun than a root canal! + + + diff --git a/sources/net.sf.j2s.java.core/src/test/components/html/tutorial.html b/sources/net.sf.j2s.java.core/src/test/components/html/tutorial.html new file mode 100644 index 000000000..95673f12e --- /dev/null +++ b/sources/net.sf.j2s.java.core/src/test/components/html/tutorial.html @@ -0,0 +1,13 @@ + + +

+The Java Tutorial +

+ +

+The one, the only. Well, it hasn't been the only for quite a while now. +This is the original Tutorial book. +The third edition includes a chapter about Swing. + + + diff --git a/sources/net.sf.j2s.java.core/src/test/components/html/tutorialcont.html b/sources/net.sf.j2s.java.core/src/test/components/html/tutorialcont.html new file mode 100644 index 000000000..62bb6ebe3 --- /dev/null +++ b/sources/net.sf.j2s.java.core/src/test/components/html/tutorialcont.html @@ -0,0 +1,11 @@ + + +

+The Java Tutorial Continued +

+ +

+Latest version online only + + + diff --git a/sources/net.sf.j2s.java.core/src/test/components/html/vm.html b/sources/net.sf.j2s.java.core/src/test/components/html/vm.html new file mode 100644 index 000000000..69e61f4f4 --- /dev/null +++ b/sources/net.sf.j2s.java.core/src/test/components/html/vm.html @@ -0,0 +1,11 @@ + + +

+The Java Virtual Machine Specification +

+ +

+blah, blah, blah, blah, blah... + + +