diff options
273 files changed, 27261 insertions, 5567 deletions
@@ -1,3 +1,684 @@ +2006-05-20 Andrew John Hughes <gnu_andrew@member.fsf.org> + + * native/jni/java-nio/gnu_java_nio_VMChannel.c: + (JCL_print_buffer): Fix to work with -Werror on 64-bit + platforms. + +2006-05-20 Sven de Marothy <sven@physto.se> + + * java/awt/Font.java (getNumGlyphs): Call correct peer method. + +2006-05-20 Sven de Marothy <sven@physto.se> + + * gnu/java/awt/print/JavaPrinterJob.java + (print): Use PostScriptGraphics2D. + * gnu/java/awt/print/PostScriptGraphics2D.java: New file. + +2006-05-20 Sven de Marothy <sven@physto.se> + + * javax/swing/text/html/MinimalHTMLWriter.java: New file + +2006-05-20 Raif S. Naffah <raif@swiftdsl.com.au> + + * gnu/java/security/OID.java: Updated copyright year. + (OID): Removed unused Javadoc param tag. + * gnu/java/security/prng/PRNGFactory.java: Removed unused import. + * gnu/java/security/hash/MD4.java: Fixed a Javadoc link. + +2006-05-20 Raif S. Naffah <raif@swiftdsl.com.au> + + * gnu/javax/crypto/jce/keyring/GnuKeyring.java (engineAliases): + Formatting. + Added trace/debug statements. + (engineSetCertificateEntry): Ensure alias is not already used for a Key + Entry. Also ensure that any previous entry for this alias is removed + before a new one is added. + (engineGetKey): Do not trace/log passwords. + Trace key's class name only. + (engineSetKeyEntry): Ensure alias is not alredy used for a Trusted + Certificate Entry. Also ensure that previous entry for this alias is + removed before a new one is added. + (engineLoad): Do not trace/log passwords. + (engineStore): Likewise. + (engineSize): Use size of enumeration instead of collection size. + +2006-05-20 Raif S. Naffah <raif@swiftdsl.com.au> + + * gnu/javax/crypto/keyring/PrivateKeyEntry.java: Formatting. + (toString): New method. + * gnu/javax/crypto/keyring/PasswordEncryptedEntry.java (decrypt): + Do not trace/log passwords. + Set masked to false before decoding envelope. + Do not set payload to null. + (encrypt): Set masked to true. + * gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java (verify): + Do not trace/log passwords. + Set masked to false before decoding envelope. + Do not set payload to null. + Added trace/debug statements. + (authenticate): Do not trace/log passwords. + Set masked to true. + Added trace/debug statements. + (getMac): Added trace/debug statements. + * gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java + (remove(String)): Changed the signature to return a boolean. + (toString): New method. + * gnu/javax/crypto/keyring/GnuPublicKeyring.java (containsCertificate): + Formatting + (getCertificate): Likewise. + (putCertificate): Likewise. + (load): Likewise. + Do not trace/log passwords. + (store): Likewise. + * gnu/javax/crypto/keyring/GnuPrivateKeyring.java (getPrivateKey): + Do not trace/log passwords. + Added more trace/logging statements. + (putPrivateKey): Do not trace/log passwords. + Trace only key's class name. + Formatting. + (containsPublicKey): Formatting. + (getPublicKey): Likewise. + Trace only key's class name. + (putPublicKey): Trace only key's class name. + (containsCertPath): Formatting. + (getCertPath): Likewise. + (putCertPath): Likewise. + (load): Do not trace/log passwords. + Formatting. + (store): Likewise. + * gnu/javax/crypto/keyring/EnvelopeEntry.java (log): New field. + (add): Do not set payload to null. + Added trace/debug statements. + (containsAlias): Added trace/debug statements. + (get): Likewise. + (remove(Entry)): Likewise. + (remove(String)): Likewise. + Changed the signature to return a boolean. + Do not set payload to null unless really removed. + (toString): New method. + (decodeEnvelope): Clear entries before proceeding. + (makeAliasList): Added trace/debug statements. + Ensure only non-null aliases and alias-lists are added. + * gnu/javax/crypto/keyring/Entry.java (log): New field. + (TYPES): New constant. + (toString): New method. + (defaultDecode): Add trace/debug statement. + +2006-05-20 Raif S. Naffah <raif@swiftdsl.com.au> + + * tools/gnu/classpath/tools/keytool/ListCmd.java (rfc): + Increased visibility. + (setup): Do not trace/log passwords. + (parsed): Was not setting correct (rfc) field; fixed. + (print1Chain): Formatting. + * tools/gnu/classpath/tools/keytool/DeleteCmd.java (setup): + Do not trace/log passwords. + * tools/gnu/classpath/tools/keytool/ExportCmd.java (setup): Likewise. + * tools/gnu/classpath/tools/keytool/GenKeyCmd.java (setup): Likewise. + * tools/gnu/classpath/tools/keytool/IdentityDBCmd.java (setup): Likewise. + * tools/gnu/classpath/tools/keytool/KeyCloneCmd.java (setup): Likewise. + * tools/gnu/classpath/tools/keytool/StorePasswdCmd.java (setup): Likewise. + * tools/gnu/classpath/tools/keytool/ImportCmd.java (setup): Likewise. + (orderChain): Added FIXME. + * tools/gnu/classpath/tools/keytool/CertReqCmd.java (setup): + Do not trace/log passwords. + Removed commented out code. + * tools/gnu/classpath/tools/keytool/KeyPasswdCmd.java (setup): Likewise. + * tools/gnu/classpath/tools/keytool/SelfCertCmd.java (setup): Likewise. + * tools/gnu/classpath/tools/keytool/Command.java (doCommand): Formatting. + (setKeystoreURLParam): Likewise. + (setKeystorePasswordParam): Do not trace/log passwords. + (saveKeyStore): Likewise. + +2006-05-19 Roman Kennke <kennke@aicas.com> + + * gnu/java/awt/java2d/AbstractGraphics2D.java + Added class docs. + (pixel): Removed obsolete field. + (draw(Shape)): Removed commented out code. + (drawImage): Formatting. + (drawString): Added optimization hook. + (setPaint): Removed rawSetForeground(). + (getFontRenderContext): Return context with correct transform. + (drawGlyphVector): Draw complete outline in one go. + (copyArea): Added optimization hook. + (clearRect): Added optimization hook. + (drawImage): Added optimization hook. + (fillShape): (Temporarily) Set antialiasing off by default for + font rendering. Adjust the shape by some bits to improve rendering. + Pass clip bounds to the render methods. + (drawPixel): Removed. + (rawSetPixel): Removed. + (rawSetForeground): Removed. + (rawDrawLine): Default impl calls standard pipeline. + (rawDrawString): New method, calls standard pipeline for rendering. + (rawClearRect): New method, calls standard pipeline for rendering. + (rawFillRect): New method, calls standard pipeline for rendering. + (rawDrawImage): New method, calls standard pipeline for rendering. + (rawCopyArea): New method. + (copyAreaImpl): New method. + (rawFillShape): Renamed to fillShapeImpl(). Small optimization + for rendering. + (fillShapeAntialias): Fixed AA rendering. + (fillScanlineAA): Fixed AA rendering. + (getSegments): Take offset into account. + +2006-05-19 Sven de Marothy <sven@physto.se> + + * javax/swing/text/AbstractWriter.java + (getText): Fix parameters (start, length) not (start, end). + +2006-05-19 Tom Tromey <tromey@redhat.com> + + PR classpath/27444: + * gnu/java/net/loader/URLLoader.java (getClassPath): Documented. + Changed return type. + * java/net/URLClassLoader.java (urlloaders): Removed. + (addURLImpl): Updated. + * gnu/java/net/loader/JarURLLoader.java (initialized): New field. + (indexSet): Likewise. + (classPath): Changed type. + (JarURLLoader): New constructor. + (initialize): New method. + (getResource): Use index set if it exists. + (getClassPath): Updated. + * gnu/java/net/IndexListParser.java (IndexListParser): Avoid NPE. + (prefixes): New field. + (headers): Removed. + (IndexListParser): Fill in prefixes. + (clearAll): Clear prefixes. + (getHeaders): Changed return type. + +2006-05-19 Audrius Meskauskas <AudriusA@Bioinformatics.org> + + * javax/swing/plaf/basic/BasicTableHeaderUI.java + (MouseInputHandler.mouseExitted): No nothing there. + (MouseInputHandler.endDragging): Move column to the + first/last position if released outside the horizontal + table range. + +2006-05-19 Lillian Angel <langel@redhat.com> + + * java/awt/font/GlyphVector.java + (getGlyphCharIndex): Implemented. + (getGlyphCharIndices): Implemented. + (getGlyphOutline): Implemented. + (getGlyphVisualBounds): Implemented. + (getGlyphVisualBounds): Implemented. + (getPixelBounds): Implemented. + (getLayoutFlags): Implemented. + +2006-05-19 Robert Schuster <robertschuster@fsfe.org> + + * java/awt/LightweightDispatcher.java: Added field dragButton and + documentation for it. + (handleMouseEvent): Rewritten MOUSE_PRESSED case in switch-statement, + added subexpression to if-clause in MOUSE_RELEASED case. + +2006-05-19 Robert Schuster <robertschuster@fsfe.org> + + * javax/swing/metal/MetalButtonUI.java: + (update): Removed some subexpression from if-clause and call + updateWithGradient. + (updateWithGradient): New method. + +2006-05-19 Roman Kennke <kennke@aicas.com> + + * javax/swing/JComponent.java + (findOverlapFreeParent): Implemented algorithm for finding + overlapping in component hierarchy. + +2006-05-19 Jeroen Frijters <jeroen@frijters.net> + + * java/lang/Thread.java + (contextClassLoaderIsSystemClassLoader): New field. + (Thread(ThreadGroup,Runnable)): Call createAnonymousThreadName. + (Thread(VMThread,String,int,boolean)): Call createAnonymousThreadName + and set contextClassLoaderIsSystemClassLoader. + (Thread(ThreadGroup,Runnable,String,long)): + Set contextClassLoaderIsSystemClassLoader. + (createAnonymousThreadName): New method. + (getContextClassLoader): Check contextClassLoaderIsSystemClassLoader + and fixed security check. + (setContextClassLoader): Clear contextClassLoaderIsSystemClassLoader. + +2006-05-19 Robert Schuster <robertschuster@fsfe.org> + + * javax/swing/plaf/basic/BasicToolBarUI.java: + (createNonRolloverBorder): Rewritten. + (createRolloverBorder): Rewritten. + (setToNonRolloverBorder): Store old border instance in hashtable. + (setToRolloverBorder): Store old border instance in hashtable, use + AbstractButton instead of JButton in statements. + (setBorderToNormal): Rewritten. + * javax/swing/plaf/metal/MetalLookAndFeel.java: + (initComponentDefaults): Added values for ToolBar.rolloverBorder and + ToolBar.nonrolloverBorder. + +2006-05-18 Thomas Fitzsimmons <fitzsim@redhat.com> + + * javax/imageio/stream/ImageInputStreamImpl.java: Complete. + * javax/imageio/stream/MemoryCacheImageInputStream.java: Likewise. + +2006-05-18 Lillian Angel <langel@redhat.com> + + * java/awt/font/GlyphMetrics.java + (getLSB): Implemented. + (getRSB): Implemented. + +2006-05-18 Lillian Angel <langel@redhat.com> + + * java/awt/font/GraphicAttribute.java: + Documented entire class. + (GraphicAttribute): Added check for alignment. + (getBounds): Implemented. + (getJustificationInfo): Implemented. + +2006-05-18 Robert Schuster <robertschuster@fsfe.org> + + * java/awt/LightweightDispatcher.java: + (handleMouseEvent): Added note, added subexpression to if-statement. + +2006-05-18 Robert Schuster <robertschuster@fsfe.org> + + * javax/swing/plaf/basic/BasicToolBarUI.java: + (navigateFocusedComp): Marked as stub. + (createRolloverBorder): Create a different Border instance, added note. + * javax/swing/plaf/metal/MetalBorders.java: + (ButtonBorder): Added documentation. + (ButtonBorder.paintDefaultButtonBorder): Added else-block. + (ButtonBorder.paintOceanButtonBorder): Added else-block, added + subexpression into if-else cascade, added note. + +2006-05-18 Lillian Angel <langel@redhat.com> + + * java/awt/font/ShapeGraphicAttribute.java: + Documented entire class. + (ShapeGraphicAttribute): Initialized bounds field. + (draw): Implemented. + (equals): Implemented. + (getAdvance): Implemented. + (getAscent): Implemented. + (getBounds): Implemented. + (getDescent): Implemented. + (hashCode): Implemented. + +2006-05-18 Roman Kennke <kennke@aicas.com> + + * javax/swing/CellRendererPane.java + (CellRendererPane): Set CellRendererPane to invisible. + +2006-05-18 Roman Kennke <kennke@aicas.com> + + * gnu/java/awt/peer/gtk/GdkGraphics.java + (clipRect): Removed old intersection statement. + +2006-05-18 Roman Kennke <kennke@aicas.com> + + * gnu/java/awt/peer/gtk/GdkGraphics.java + (clipRect): Don't use Rectangle.intersection() to avoid creating + 2 unnecessary Rectangle instances and fix a clipping problem. + (computeIntersection): New helper method, adapted from SwingUtilities. + +2006-05-18 Roman Kennke <kennke@aicas.com> + + * javax/swing/JComponent.java + (isCompletelyDirty): Removed. + (paint): Don't mark children as clean, this is no longer necessary. + (findOverlapFreeParent): Don't stop at Viewports, this breaks + painting when something overlaps the viewport (like a popup/menu). + * javax/swing/RepaintManager.java + (currentRepaintManagers): Made package private to avoid accessor + methods. + (dirtyComponents): Made private. + (dirtyComponentsWork): Made private. + (markCompletelyDirty): Fixed bounds of dirtyrect to be + component-local not parent-local. Do not set flag in JComponent. + (markCompletelyClean): Don't set JComponent flag. + (isCompletelyDirty): Rewritten to return true when the complete + component is marked dirty. + (paintDirtyRegions): Improved parent-merging so that the merged-in + components don't get painted too. 'Outsourced' the compilation + of the repaint root components. + (compileRepaintRoots): New helper method. + +2006-05-18 Roman Kennke <kennke@aicas.com> + + PR 26368 + * javax/swing/text/GapContent.java + (GapContentPosition(int)): Use adapted binarySearch method to + allow for having a greater array than number of entries. + (numMarks): New field, holds the end of the marks list. + (GapContent): Initialize positionMarks with size of 10 instead of 0. + (shiftGapStartDown): Adjusted for new setPositionsInRange signature. + (shiftGapEndUp): Adjusted for new setPositionsInRange signature. + (setPositionsInRange): Changed signature to narrow the purpose and + special cases inside. Reimplemented to crunch together equal marks. + (adjustPositionsInRange): Added assertion to make sure we do + not accidentally change the order of the mark. Added some debug + output for a special case of which I don't know if it even exists. + (resetMarksAtZero): Made impl simpler. + (dumpMarks): New debug helper method. + (insertMark): Grow array in bigger chunks to avoid excessive copying. + (binarySearch): New method. An adaption of Arrays.binarySearch() + that allows for an maxIndex parameter. + +2006-05-18 Roman Kennke <kennke@aicas.com> + + * javax/swing/KeyboardManager.java + (topLevelLookup): Use WeakHashMap to avoid memory leak. + +2006-05-18 Jeroen Frijters <jeroen@frijters.net> + + * gnu/java/net/loader/JarURLLoader.java + (JarURLLoader): Use a slightly more efficient URL constructor. + +2006-05-18 David Gilbert <david.gilbert@object-refinery.com> + + * gnu/java/awt/print/JavaPrinterGraphics.java + (drawImage(Image, int, int, Color, ImageObserver)): Fix endless loop, + (drawImage(Image, int, int, ImageObserver)): Likewise, + (drawImage(Image, int, int, int, int, Color, ImageObserver)): Likewise, + (drawImage(Image, int, int, int, int, ImageObserver)): Likewise, + (drawImage(Image, int, int, int, int, int, int, int, int, Color, + ImageObserver)): Likewise, + (drawImage(Image, int, int, int, int, int, int, int, int, + ImageObserver)): Likewise. + +2006-05-17 Tom Tromey <tromey@redhat.com> + + * tools/gnu/classpath/tools/jar/Indexer.java (indexJarFile): Use a + LinkedHashSet. + +2006-05-17 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/border/AbstractBorder.java: Source code formatting fixes, + * javax/swing/border/BevelBorder.java: Likewise, + * javax/swing/border/CompoundBorder.java: Likewise, + * javax/swing/border/TitledBorder.java: Likewise. + +2006-05-17 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/table/AbstractTableModel.java: Formatting fixes, + * javax/swing/table/DefaultTableModel.java: Likewise, + * javax/swing/table/TableCellEditor.java: Likewise, + * javax/swing/table/TableCellRenderer.java: Likewise. + +2006-05-17 Lillian Angel <langel@redhat.com> + + * java/awt/font/ImageGraphicAttribute.java: + Documented entire class. + (ImageGraphicAttribute): Changed to call this. + (ImageGraphicAttribute): Implemented. + (draw): Implemented. + (equals): Implemented. + (getAdvance): Implemented. + (getAscent): Implemented. + (getBounds): Implemented. + (getDescent): Implemented. + (hashCode): Implemented. + * javax/swing/text/html/HTMLDocument.java + (create): Removed. Sufficent enough for + super to be called. + (insert): Likewise. + (insertUpdate): Likewise. + (processHTMLFrameHyperlinkEvent): Marked as stub. + (start): Removed FIXME. + (end): Likewise. + (start): Called super. + (end): Called super. + (getElement): removed unneeded code. + (setParagraphAttribute): Removed. Sufficent enough + for super to be called. + (fireChangedUpdate): Likewise. + (fireUndoableEditUpdate): Likewise. + +2006-05-17 Lillian Angel <langel@redhat.com> + + * java/awt/TexturePaint.java: + Added documentation for class and all functions. + (getTransparency): Implemented. + +2006-05-17 Roman Kennke <kennke@aicas.com> + + * java/awt/LightweightDispatcher.java + (findTarget): Translate point to child components. + +2006-05-17 Roman Kennke <kennke@aicas.com> + + PR 26368 + * javax/swing/text/GapContent.java + (GapContentPosition): Do no more implement Comparable. + (GapContentPosition.mark): Removed field. + (GapContentPosition.index): New field to hold the index into + the positions array. + (GapContentPosition(int)): Rewritten to use the new indirection + to the positions array. + (GapContentPosition.compareTo): Removed. + (GapContentPosition.getOffset): Synchronized. Fetch mark from + positionMarks array. + (WeakPositionComparator): Removed obsolete class. + (positions): Changed type to WeakHashMap. + (positionMarks): New field, holds the marks of the positions. + (GapContent): Initialize new fields. + (createPosition): Rewritten to use the new indirection + to the positions array. + (getPositionsInRange): Rewritten to use the new indirection + to the positions array. + (setPositionsInRange): Rewritten to use the new indirection + to the positions array. + (adjustPositionsInRange): Rewritten to use the new indirection + to the positions array. + (insertMark): New helper method. + (clearPositionReferences): Removed obsolete methods. + +2006-05-17 Lillian Angel <langel@redhat.com> + + * java/awt/GraphicsConfiguration.java + (getImageCapabilities): Implemented. + (getBufferCapabilities): Implemented. + +2006-05-17 Lillian Angel <langel@redhat.com> + + * javax/swing/plaf/basic/BasicSliderUI.java + (focusGained): Implemented. + (focusLost): Implemented. + (paint): Added code to paint the focus. + * javax/swing/plaf/metal/MetalSliderUI.java + (paintThumb): Added code to set the thumbColor. + (paintFocus): Implemented properly. + +2006-05-17 Audrius Meskauskas <AudriusA@Bioinformatics.org> + + PR 27383 + * javax/naming/spi/NamingManager.java (getURLContext): + Always search for the factory class in all possible places + and use VMStackWalker. + (forName): New method. + +2006-05-17 Roman Kennke <kennke@aicas.com> + + * java/awt/LightweightDispatcher.java + (handleMouseEvent): Fixed search algorithm for finding the + mouse event target. + (findTarget): Fixed search algorithm for finding the + mouse event target. + +2006-05-17 Audrius Meskauskas <AudriusA@Bioinformatics.org> + + * javax/naming/spi/NamingManager.java: Documented. + +2006-05-17 Mark Wielaard <mark@klomp.org> + + * THANKYOU: Add Trevor Linton <tlinton@xmission.com>. + * gnu/javax/imageio/jpeg/DCT.java: Cleanup Todo copyright. + * gnu/javax/imageio/jpeg/YCbCr_ColorSpace.java: Likewise. + * gnu/javax/imageio/jpeg/ZigZag.java: Likewise. + +2006-05-17 Robert Schuster <robertschuster@fsfe.org> + + Fixes PR 26947. + * javax/swing/plaf/basic/BasicInternalFrameUI.java: Updated copyright + year. + (BorderListener.mouseClicked): Detect double-clicks in title pane, + copied code from + BasicInternalFrameTitlePaneUI.MaximizeAction.actionPerformed(). + +2006-05-17 Robert Schuster <robertschuster@fsfe.org> + + Fixes PR 27626. + * java/awt/LightweightDispatcher.java: + (handleMouseEvent): Moved assignment into switch-block, added notes. + +2006-05-16 Lillian Angel <langel@redhat.com> + + * javax/swing/text/StyleContext.java: + Changed staticAttributeKeys to be a Hashtable. + (getStaticAttribute): Implemented. + (getStaticAttributeKey): Implemented. + (readAttributeSet): Implemented. + (writeAttributeSet): Added FIXME. Not sure how + to implement this. + (readAttributes): Implemented. + (writeAttributes): Implemented. + (registerStaticAttibuteKey): Fixed to add key to + the hash table. + +2006-05-16 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/DefaultButtonModel.java + (setGroup): Removed event notification. + +2006-05-16 Lillian Angel <langel@redhat.com> + + * javax/swing/plaf/basic/BasicComboBoxUI.java + (installKeyboardActions): Implemented. + (uninstallKeyboardActions): Implemented. + * javax/swing/plaf/basic/BasicComboPopup.java + (uninstallKeyboardActions): Removed FIXME. Nothing + to be done here. + (installKeyboardActions): Likewise. + * javax/swing/plaf/basic/BasicTextUI.java + (uninstallKeyboardActions): Implemented. + * javax/swing/plaf/basic/BasicTreeUI.java: + Added field for hashColor. + Marked stub methods. + (getHashColor): Implemented to use field. + (setHashColor): Likewise. + (getRowX): Implemented. + (NodeDimensions.getRowX): Changed to use BasicTreeUI.getRowX. + +2006-05-16 Roman Kennke <kennke@aicas.com> + + PR 26521 + * javax/swing/JTable.java + (rowHeights): New field. + (initializeLocalVars): Call setRowHeigt instead of rowHeight=, + in order to initialize rowHeights correctly. + (tableChanged): Nullify rowHeights when model changes. Only + create default columns from model when corresponding property + is set. Sync table model with rowHeights as appropriate. + (valueChanged): Call repaint with the correct rectangle. + (rowAtPoint): Handle rowHeights. + (getCellRect): Mostly rewritten. Check for boundaries + of model and return (0,0,0,0) or (0,0,width,height) when outside. + Handle component orientation. Round correctly. + (getRowHeight(int)): Implemented for variable row height. + (setRowHeight(int,int)): Implemented for variable row height. + (setRowHeight(int)): Nullify rowHeights. + (setModel): Notify tableChanged(). + * javax/swing/plaf/basic/BasicTableUI.java + (installDefaults): Create rendererPane in installUI. + (installUI): Create and install rendererPane. + (uninstallUI): Uninstall rendererPane and nullify rendererPane + and table. + (paint): Correctly handle rowMargin. + +2006-05-16 Tom Tromey <tromey@redhat.com> + + PR classpath/27563: + * java/text/NumberFormat.java (getIntegerInstance): Use + "integerFormat", not "numberFormat". + +2006-05-16 Lillian Angel <langel@redhat.com> + + * javax/swing/JPopupMenu.java + (addMenuKeyListener): Implemented. + (removeMenuKeyListener): Implemented. + (getMenuKeyListeners): Implemented. + * javax/swing/ProgressMonitor.java: + Added new protected field. + (getAccessibleContext): Implemented. + +2006-05-16 Lillian Angel <langel@redhat.com> + + * javax/swing/JFileChooser.java: + Added new private field. + (setDragEnabled): Implemented. + (getDragEnabled): Implemented. + +2006-05-16 Lillian Angel <langel@redhat.com> + + * java/awt/Window.java + (applyResourceBundle): Implemented. + +2006-05-16 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/DefaultButtonModel.java + (setSelected): If new SELECTED state is false, clear ARMED and PRESSED + states also. + +2006-05-16 Audrius Meskauskas <AudriusA@Bioinformatics.org> + + * javax/swing/JList.java (getSelectedValues): + Ask the value for the indexed array element. + +2006-05-16 Roman Kennke <kennke@aicas.com> + + * javax/swing/JTable.java + (valueChanged): Also repaint when table has only 1 row. Fixed + repaint rectangle to span the entire changed rows. + +2006-05-16 Roman Kennke <kennke@aicas.com> + + PR 24031 + * javax/swing/JOptionPane.java + (startModal): Rewritten. The events are now dispatched, even + when the event dispatch thread gets blocked by the call + to this method. Also, mouse events get intercepted outside the + internal frame. + +2006-05-16 Audrius Meskauskas <AudriusA@Bioinformatics.org> + + * javax/swing/plaf/basic/BasicInternalFrameUI.java + (BorderListener.mouseDragged):Do not set cursor + if the frame is being dragged. + +2006-05-16 Audrius Meskauskas <AudriusA@Bioinformatics.org> + + * javax/swing/plaf/basic/BasicInternalFrameUI.java + (BorderListener): Rewritten. (InternalFrameBorder): + Made package private. + (InternalFrameBorder.offset): + Renamed to cornerSize, made package private. + (bSize): Made package private. + +2006-05-16 Roman Kennke <kennke@aicas.com> + + * javax/swing/JMenu.java + (AccessibleJMenu.getAccessibleChildrenCount): Implemented. + (AccessibleJMenu.getAccessibleChild): Implemented. + (AccessibleJMenu.getAccessibleSelection): Implemented. + (AccessibleJMenu.getAccessibleSelection(int)): Implemented. + (AccessibleJMenu.isAccessibleChildSelected): Implemented. + (AccessibleJMenu.getAccessibleRole): Documented. + (AccessibleJMenu.getAccessibleSelectionCount): Implemented. + (AccessibleJMenu.addAccessibleSelection): Implemented. + (AccessibleJMenu.removeAccessibleSelection): Implemented. + (AccessibleJMenu.clearAccessibleSelection): Implemented. + (AccessibleJMenu.selectAllAccessibleSelection): Implemented. + (createPath): New helper method. + 2006-05-15 Tom Tromey <tromey@redhat.com> * java/text/MessageFormat.java (format): Now varargs. @@ -6,6 +687,48 @@ * java/lang/Thread.java (State): Fixed typo. +2006-05-15 Tom Tromey <tromey@redhat.com> + + * java/net/URLClassLoader.java: Moved inner classes to + gnu.java.net.loader. + (factoryCache): Changed type. + (URL_LOADER_PREFIX): New constant. + (URLClassLoader): Updated for new factoryCache. + (addURLImpl): Use reflection to search for a loader. + (findClass): Use getClass method on URLLoader. + (getURLStreamHandler): Removed. + * gnu/java/net/loader/URLLoader.java: New file, extracted + from URLClassLoader. + * gnu/java/net/loader/Resource.java: Likewise. + * gnu/java/net/loader/FileResource.java: Likewise. + * gnu/java/net/loader/FileURLLoaderjava: Likewise. + * gnu/java/net/loader/JarURLLoader.java: Likewise. + * gnu/java/net/loader/JarURLResource.java: Likewise. + * gnu/java/net/loader/RemoteURLLoader.java: Likewise. + * gnu/java/net/loader/RemoteResource.java: Likewise. + * gnu/java/net/loader/ULRStreamHandlerCache.java: New file. + +2006-05-15 Sven de Marothy <sven@physto.se> + + * native/target/generic/target_generic_network.h: + Add a pair of parenthesis. + +2006-05-15 Mark Wielaard <mark@klomp.org> + + * java/awt/Graphics2D.java: Remove PrinterJob import. + +2006-05-15 Mark Wielaard <mark@klomp.org> + + * doc/www.gnu.org/announce/20060515.wml: New file. + * doc/www.gnu.org/newsitems.txt: Add 0.91 release announcement. + * doc/www.gnu.org/downloads/downloads.wml: Add 0.91. + +2006-05-15 Thomas Fitzsimmons <fitzsim@redhat.com> + + * NEWS: Announce inclusion of gcjwebplugin. + Announce inclusion of appletviewer. + * INSTALL: Note gcjwebplugin dependencies. + 2006-05-15 Mark Wielaard <mark@klomp.org> * configure.ac (VERSION): Set to 0.91-generics. @@ -19,6 +742,247 @@ * README: Added CACAO to list of VMs. +2006-05-15 Audrius Meskauskas <AudriusA@Bioinformatics.org> + + * javax/swing/RepaintManager.java (paintDirtyRegions): + Break loop as soon as the component repaint is merged + with some parent. (ComponentComparator): Removed. + (comparator): Removed. + +2006-05-15 Roman Kennke <kennke@aicas.com> + + * javax/swing/border/TitledBorder.java + (paintBorderWithTitle): Fixed indentation. + +2006-05-15 Roman Kennke <kennke@aicas.com> + + * javax/swing/border/TitledBorder.java + (layoutBorderWithTitle): Fetch border using getBorder() instead + of using the border field directly. Allows for the use of + an UI supplied border in the case when a null border was set. + Fixed component orientation. + (paintBorderWithTitle): Fetch border using getBorder() instead + of using the border field directly. Allows for the use of + an UI supplied border in the case when a null border was set. + +2006-05-15 Audrius Meskauskas <AudriusA@Bioinformatics.org> + + * javax/swing/RepaintManager.java (paintDirtyRegions): Rewritten. + (contains): New method. + +2006-05-15 Tom Tromey <tromey@redhat.com> + + * resource/gnu/classpath/tools/jar/messages.properties: Fixed + argument indices. + * resource/gnu/classpath/tools/getopt/Messages.properties: Fixed + argument indices. + +2006-05-15 Audrius Meskauskas <AudriusA@Bioinformatics.org> + + * javax/swing/JComponent.java (findOverlapParent): Stop loop at + JViewport's. + * javax/swing/RepaintManager.java (addDirtyRegion): Always add the given + region. (paintDirtyRegions): Rewritten. + +2006-05-15 Tom Tromey <tromey@redhat.com> + + * tools/gnu/classpath/tools/jar/Main.java (setArchiveFile): Use + MessageFormat. + * tools/gnu/classpath/tools/jar/Indexer.java (indexJarFile): Use + MessageFormat. + * tools/gnu/classpath/tools/jar/Extractor.java: Externalized strings. + (run): Use MessageFormat. + * resource/gnu/classpath/tools/jar/messages.properties: New file. + * tools/gnu/classpath/tools/jar/Creator.java: Externalized strings. + (writeFile): Use MessageFormat. + +2006-05-15 Jeroen Frijters <jeroen@frijters.net> + + * java/awt/Toolkit.java (getDefaultToolkit): Use Class.forName() + instead of directly calling the class loader. + +2006-05-15 Tom Tromey <tromey@redhat.com> + + * tools/gnu/classpath/tools/getopt/Option.java (getDescription): + Removed old comment. + * tools/gnu/classpath/tools/getopt/ClasspathToolParser.java: + Externalized strings. + (getVersionString): Use MessageFormat. + * tools/gnu/classpath/tools/getopt/Messages.java: New file. + * resource/gnu/classpath/tools/getopt/Messages.properties: New file. + * tools/gnu/classpath/tools/getopt/Parser.java: Externalized strings. + (getArgument): Use a MessageFormat. + (handleLongOption): Likewise. + (parse): Likewise. + +2006-05-15 Robert Schuster <robertschuster@fsfe.org> + + Fixes PR 27197. + * javax/swing/text/FieldView.java: + (paint): Calculate intersection between clip and allocation area and + set that as new clip. + +2006-05-15 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/text/JTextComponent.java: Marked stub methods. + +2006-05-15 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/JTable.java: Marked stub methods. + +2006-05-15 Raif S. Naffah <raif@swiftdsl.com.au> + + * tools/gnu/classpath/tools/jarsigner/Main.java: + Increased visibility of fields used by parser anonymous classes. + (KEYTOOL_TOOL): New constant. + (cmdLineParser): Changed type to ToolParser. + (fileAndAlias): new field. + (main): Don't catch OptionException. + (processArgs): Removed validation checks; now handled by ToolParser. + (getParser): Removed. + (ToolParserCallback): New inner class. + (ToolParser): Likewise. + +2006-05-15 Audrius Meskauskas <AudriusA@Bioinformatics.org> + + * javax/swing/JTable.java (TableTextArea.scrollRectToVisible): + Removed. + +2006-05-15 Audrius Meskauskas <AudriusA@Bioinformatics.org> + + * javax/swing/DefaultDesktopManager.java (endDraggingFrame, + endResizingFrame): Do not repaint, unless in the outline mode. + +2006-05-15 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/JTabbedPane.java + (AccessibleJTabbedPane.getAccessibleRole): Implemented, + (AccessibleJTabbedPane.getAccessibleChildrenCount): Implemented, + (AccessibleJTabbedPane.getAccessibleSelection()): Implemented, + (AccessibleJTabbedPane.getAccessibleAt): Implemented, + (AccessibleJTabbedPane.getAccessibleSelectionCount): Implemented, + (AccessibleJTabbedPane.getAccessibleSelection(int)): Implemented, + (AccessibleJTabbedPane.isAccessibleChildSelected): Implemented, + (AccessibleJTabbedPane.addAccessibleSelection): Implemented, + (AccessibleJTabbedPane.removeAccessibleSelection): Implemented, + (AccessibleJTabbedPane.clearAccessibleSelection): Implemented, + (AccessibleJTabbedPane.selectAllAccessibleSelection): Implemented, + (Page.getAccessibleName): Implemented. + +2006-05-15 Audrius Meskauskas <AudriusA@Bioinformatics.org> + + * javax/swing/DefaultDesktopManager.java (setBoundsForFrame): + Do not repaint nor revalidate here. + +2006-05-15 Audrius Meskauskas <AudriusA@Bioinformatics.org> + + * javax/swing/RepaintManager.java (addDirtyRegion): + If there is a lightweight parent, recursively add the corresponding + region of the parent instead. + +2006-05-15 David Gilbert <david.gilbert@object-refinery.com> + + * java/awt/Graphics2D.java: Added some API doc comments. + +2006-05-15 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/JTabbedPane.java + (paramString): Reimplemented, + (getAccessibleContext): Added API docs. + +2006-05-15 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/JFileChooser.java + (paramString): Reimplemented, + (getAccessibleContext): Updated API docs, + (AccessibleJFileChooser): Added API docs. + +2006-05-14 Tom Tromey <tromey@redhat.com> + + * tools/gnu/classpath/tools/jar/Updater.java (run): No longer throws + OptionException. + * tools/gnu/classpath/tools/jar/Creator.java (run): No longer throws + OptionException. + * tools/gnu/classpath/tools/jar/Action.java (run): No longer throws + OptionException. + * tools/gnu/classpath/tools/jar/Indexer.java (run): Removed. Moved + validation to JarParser. + * tools/gnu/classpath/tools/jar/Main.java (JarParser): New class. + (run): Moved validation to JarParser. Don't throw OptionException. + (initializeParser): Create a JarParser. + (main): Don't catch OptionException. + * tools/gnu/classpath/tools/getopt/Parser.java (printHelp): No longer + public. + (validate): New method. + (parse): Call it. Print '-help' in error message when long-only. + +2006-05-14 Tom Tromey <tromey@redhat.com> + + * gnu/java/awt/print/JavaPrinterJob.java (setPrintable): Fixed + assignment. + +2006-05-15 Sven de Marothy <sven@physto.se> + + * gnu/java/awt/print/JavaPrinterGraphics.java: + Sweeping changes I can't be bothered to document in detail. + * gnu/java/awt/print/JavaPrinterJob.java + (getPageAttributes): New method. + (setPageable,cancel,isCancelled): Implement. + +2006-05-14 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/JCheckBoxMenuItem.java + (requestFocus): Fixed typo in API docs, + (paramString): Just call super.paramString(), + (getAccessibleContext): Added API docs, + (AccessibleJCheckBoxMenuItem): Likewise. + +2006-05-14 Tom Tromey <tromey@redhat.com> + + * tools/gnu/classpath/tools/jar/Indexer.java + (writeCommandLineEntries): Simplify insertion. + * tools/gnu/classpath/tools/jar/Main.java (run): Don't allow both + -m and -M. + +2006-05-14 Tom Tromey <tromey@redhat.com> + + PR classpath/27514: + * gnu/java/net/IndexListParser.java (JAR_INDEX_FILE): Renamed. Now + constant. + (JAR_INDEX_VERSION_KEY): Likewise. + (IndexListParser): Updated. + (getVersionInfo): Likewise. + * tools/gnu/classpath/tools/jar/Indexer.java: New file. + * tools/gnu/classpath/tools/jar/Action.java (run): Now throws + OptionException. + * tools/gnu/classpath/tools/jar/Main.java (initializeParser): Handle + -i. + (ModeOption): New constructor. + (parsed): Updated. Use setArchiveFile. + (setArchiveFile): New method. + (run): Handle no-argument case. + (main): Emit --help message on option error. + * tools/gnu/classpath/tools/jar/Updater.java (inputJar): New field. + (createManifest): New method. + (run): Updated. Throws OptionException. Correctly copy zip entry. + * tools/gnu/classpath/tools/jar/Creator.java (createManifest): New + method. + (writeManifest): Removed. + (outputStream): Now a JarOutputStream. + (writeCommandLineEntries): Changed parameters. Updated callers. + (run): Throws OptionException. + * java/util/jar/JarOutputStream.java (putNextEntry): Typo fix. + * java/util/jar/Manifest.java (read): Typo fix. + +2006-05-14 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/JMenuItem.java + (paramString): Fixed class name in API doc comment. + +2006-05-14 Tom Tromey <tromey@redhat.com> + + * native/plugin/.cvsignore: Updated. + 2006-05-14 Mark Wielaard <mark@klomp.org> * native/jni/java-net/javanet.c (_javanet_accept): Don't use C++ @@ -64,20 +1028,395 @@ (replace): Flipped if-expression and its blocks, added note, invoke insertString and remove instead of insertStringImpl and removeImpl. +2006-05-14 Raif S. Naffah <raif@swiftdsl.com.au> + + * tools/gnu/classpath/tools/jarsigner/Main.java (main): Formatting. + +2006-05-14 Raif S. Naffah <raif@swiftdsl.com.au> + + * resource/gnu/classpath/tools/keytool/MessageBundle.properties: + Added help text. + * tools/gnu/classpath/tools/keytool/keytool.txt: Removed + * tools/gnu/classpath/tools/keytool/StorePasswdCmd.java: + Increased visibility of fields used by parser anonymous classes. + (processArgs): Removed. + (getParser): New method. + * tools/gnu/classpath/tools/keytool/SelfCertCmd.java: Likewise. + (setup): Mark (Eclipse) strings that need not be externalised. + (start): Likewise. + * tools/gnu/classpath/tools/keytool/PrintCertCmd.java: Likewise. + * tools/gnu/classpath/tools/keytool/Main.java: Amended to use getopt + command line option parsing. + * tools/gnu/classpath/tools/keytool/ListCmd.java: + Increased visibility of fields used by parser anonymous classes. + (processArgs): Removed. + (setup): set 'all' local field. + (getParser): New method. + * tools/gnu/classpath/tools/keytool/KeyPasswdCmd.java: + Increased visibility of fields used by parser anonymous classes. + (processArgs): Removed. + (getParser): New method. + * tools/gnu/classpath/tools/keytool/KeyCloneCmd.java: Likewise. + (setNewKeyPassword): Fixed comments. + * tools/gnu/classpath/tools/keytool/ImportCmd.java: + Increased visibility of fields used by parser anonymous classes. + (processArgs): Removed. + (getParser): New method. + (findTrustInCACerts): Mark (Eclipse) strings that need not be + externalised. + * tools/gnu/classpath/tools/keytool/GenKeyCmd.java: + Increased visibility of fields used by parser anonymous classes. + (processArgs): Removed. + (setup): Mark (Eclipse) strings that need not be externalised. + (getParser): New method. + * tools/gnu/classpath/tools/keytool/IdentityDBCmd.java: Likewise. + * tools/gnu/classpath/tools/keytool/DeleteCmd.java: + Increased visibility of fields used by parser anonymous classes. + (processArgs): Removed. + (getParser): New method. + * tools/gnu/classpath/tools/keytool/CertReqCmd.java: Likewise. + (ATTRIBUTES_OPT): New constant. + * tools/gnu/classpath/tools/keytool/ExportCmd.java: + Increased visibility of fields used by parser anonymous classes. + (processArgs): Removed. + (setup): Mark (Eclipse) strings that need not be externalised. + (start): Likewise. + Reduced logging level. + (getParser): New method. + * tools/gnu/classpath/tools/keytool/Command.java + (processArgs): Made it concrete. + (getParser): New abstract method. + * tools/Makefile.am (KEYTOOL_HELPS): Removed. + +2006-05-13 Casey Marshall <csm@gnu.org> + + Patch by Michael Barker <mike@middlesoft.co.uk>. + * gnu/java/nio/PipeImpl.java: Retrofitted to use VMChannel. + * gnu/java/nio/SelectorImpl.java (register): Added condition for + gnu.java.nio.SocketChannelSelectionKeyImpl. + * gnu/java/nio/SocketChannelSelectionKeyImpl.java: new file. + * gnu/java/nio/channels/FileChannelImpl.java: retrofitted to use + VMChannel. + * include/gnu_java_nio_VMChannel.h: new file. + * java/nio/FileChannel.java (read,write): changed to call abstract + method. + * native/jni/java-nio/gnu_java_nio_VMChannel.c: new file. + * native/jni/java-nio/Makefile.am (libjavanio_SOURCES): add + `gnu_java_nio_VMChannel.c.' + * vm/reference/gnu/java/nio/VMChannel.java: new file. + +2006-05-14 Robert Schuster <robertschuster@fsfe.org> + + * javax/swing/text/AbstractDocument.java: + (insertString): Flipped if-expression and its blocks. + (remove): Dito. + (replace): Flipped if-expression and its blocks, added note, invoke + insertString and remove instead of insertStringImpl and removeImpl. + 2006-05-13 Tom Tromey <tromey@redhat.com> * java/nio/ByteBufferImpl.java (compact): Always set position. +2006-05-13 Sven de Marothy <sven@physto.se> + + * gnu/java/awt/print/JavaPrinterGraphics.java + (spoolPostScript): Use a faster writer. + +2006-05-13 Sven de Marothy <sven@physto.se> + + * gnu/java/awt/print/JavaPrinterGraphics.java + (colorTripleHex): Reimplement better. + +2006-05-13 Sven de Marothy <sven@physto.se> + + * javax/swing/text/html/HTMLDocument.java + (CharacterAction.start): Translate tag to StyleAttribute. + (pushCharacterStyle): Push copy of attributes onto stack. + * gnu/javax/swing/text/html/CharacterAttributeTranslator.java: + New file + +2006-05-13 Sven de Marothy <sven@physto.se> + + * gnu/javax/print/ipp/IppRequest.java (send): Set a timeout. + * java/awt/print/PrinterJob.java + (getPrinterJob): Return a JavaPrinterJob + (setPrintService,getPrintService): Implement. + * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkImage.c: + (getPixels): Gtk_threads_enter required. + * gnu/java/awt/print/JavaPrinterGraphics.java + * gnu/java/awt/print/JavaPrinterJob.java + * gnu/java/awt/print/SpooledDocumet.java: + New files. + +2006-05-13 Robert Schuster <robertschuster@fsfe.org> + + * javax/swing/text/TextAction.java: + (HorizontalMovementAction): New inner class. + (VerticalMovementAction): New inner class. + * javax/swing/text/DefaultEditorKit.java: Added assigning instances of + new inner classes to array 'defaultActions'. + (SelectionBeginWordAction): New inner class. + (SelectionEndWordAction): New inner class. + (BeginWordAction): New inner class. + (EndWordAction): New inner class. + (PreviousWordAction.actionPerformed): Rewritten. + (SelectLineAction): New inner class. + (SelectWordAction): New inner class. + (SelectionDownAction): Rewritten. + (SelectionUpAction): Rewritten. + (DownAction): Rewritten. + (UpAction): Rewritten. + (SelectionForwardAction): Rewritten. + (SelectionBackwardAction): Rewritten. + (ForwardAction): Rewritten. + (BackwardAction): Rewritten. + (BeginAction): New inner class. + (EndAction): New inner class. + (DefaultKeyTypedAction.actionPerformed): Use int variant of + Character.isISOControl. + +2006-05-13 Robert Schuster <robertschuster@fsfe.org> + + * examples/gnu/classpath/examples/swing/NavigationFilterDemo.java: + (WordFilter.getNextVisualPositionFrom): Added statement to check + for variable pt not being null. + +2006-05-13 Robert Schuster <robertschuster@fsfe.org> + + * javax/swing/text/Utilities.java: + (getNextWord): Fixed grammar in exception message. + (getPreviousWord): Changed expression in first if-clause, added sub- + expression to if-clause in while-loop. + (getWordStart): Changed expression in if-clause. + getNextVisualPositionFrom): Added package-private helper method. + +2006-05-13 Audrius Meskauskas <AudriusA@Bioinformatics.org> + + * javax/swing/tree/DefaultTreeSelectionModel.java (leadRow): + Initialise to -1. + +2006-05-13 Raif S. Naffah <raif@swiftdsl.com.au> + + * resource/gnu/classpath/tools/jarsigner/MessageBundle.properties: + Added help text. + * tools/Makefile.am (JARSIGNER_HELPS): Removed. + * tools/gnu/classpath/tools/jarsigner/jarsigner.txt: Removed. + * tools/gnu/classpath/tools/jarsigner/Main.java: + Increased visibility of fields used by parser anonymous classes. + (HELP_PATH): Removed. + (cmdLineParser): New field. + (main): Handle JVM exit status. + Handle command line parsing exceptions. + (processArgs): Use getopt command line parser. + (getParser): New method. + (setupCommonParams): Removed checks now handled by processArgs(). + (setupSigningParams): Likewise. + * tools/gnu/classpath/tools/jarsigner/JarSigner.java (start): + Reuse an existing message-bundle constant. + +2006-05-12 Tom Tromey <tromey@redhat.com> + + * gnu/java/net/protocol/jar/Connection.java (getHeaderField): + Explicitly specify class for synchronization. + +2006-05-12 Tom Tromey <tromey@redhat.com> + + * java/util/logging/Logger.java (resetLogger): Fixed typo. + +2006-05-12 Sven de Marothy <sven@physto.se> + + * gnu/java/net/protocol/http/HTTPConnection.java (get): Add timeout parameter. + * gnu/java/net/protocol/http/HTTPURLConnection.java + (setConnectTimeout): New method. + (getConnection): Add timeout parameter. + * java/net/URLConnection.java + (getConnectTimeout, setConnectTimeout): Implement. + * native/target/generic/target_generic_network.h: + Set correct socket parameters SO_SNDTIMEO and SO_RCVTIMEO. + +2006-05-12 Sven de Marothy <sven@physto.se> + + * gnu/javax/print/CupsServer.java + (CupsServer): Make the Cups host configurable. + * java/lang/System.java: Document the system property. + +2006-05-12 Roman Kennke <kennke@aicas.com> + + * javax/swing/border/TitledBorder.java + (paintBorder): Rewritten for simplicity and correctness. + (layoutBorderWithTitle): New helper method. + (paintBorderWithTitle): New helper method. + (getBorderInsets): Rewritten. + (getMinimumSize): Rewritten. + (getRealJustification): Removed. + (getMeasurements): Removed. + (Measurements): Removed. + +2006-05-12 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/plaf/basic/BasicPanelUI.java + (sharedUI): New field, + (createUI): Return a shared instance rather than a new instance, + (installUI): Reformatted and added API docs, + (installDefaults): Install border if one is defined, + (uninstallDefaults): Uninstall border. + +2006-05-12 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/JProgressBar.java: Updated API docs all over. + +2006-05-11 Lillian Angel <langel@redhat.com> + + * java/awt/ContainerOrderFocusTraversalPolicy.java + (getComponentAfter): Should not throw exception if + the ancestor is null. Added a check for this. + Also, changed to use new helper function, we should + iterate through all the components at least once. + (getNextAvailableComponent): New helper function. + (getPrevAvailableComponent): New helper function. + (getComponentBefore): Should not throw exception if + the ancestor is null. Added a check for this. + Also, changed to use new helper function, we should + iterate through all the components at least once. + (getFirstComponent): Changed check to manually check + fields. Calling accept() casts the object to a Component, + so different values may be returned. + (getLastComponent): Likewise. + +2006-05-11 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/plaf/metal/MetalBorders.java: Clean up formatting/style, + * javax/swing/plaf/metal/MetalButtonUI.java: Likewise, + * javax/swing/plaf/metal/MetalCheckBoxUI.java: Likewise, + * javax/swing/plaf/metal/MetalComboBoxButton.java: Likewise, + * javax/swing/plaf/metal/MetalComboBoxIcon.java: Likewise, + * javax/swing/plaf/metal/MetalFileChooserUI.java: Likewise, + * javax/swing/plaf/metal/MetalIconFactory.java: Likewise, + * javax/swing/plaf/metal/MetalInternalFrameTitlePane.java: Likewise, + * javax/swing/plaf/metal/MetalLookAndFeel.java: Likewise, + * javax/swing/plaf/metal/MetalPopupMenuSeparatorUI.java: Likewise, + * javax/swing/plaf/metal/MetalRootPaneUI.java: Likewise, + * javax/swing/plaf/metal/MetalScrollBarUI.java: Likewise, + * javax/swing/plaf/metal/MetalSeparatorUI.java: Likewise, + * javax/swing/plaf/metal/MetalSliderUI.java: Likewise, + * javax/swing/plaf/metal/MetalSplitPaneDivider.java: Likewise, + * javax/swing/plaf/metal/MetalTabbedPaneUI.java: Likewise, + * javax/swing/plaf/metal/MetalToolTipUI.java: Likewise, + * javax/swing/plaf/metal/MetalUtils.java: Likewise. + +2006-05-11 Robert Schuster <robertschuster@fsfe.org> + + * javax/swing/text/DefaultCaret.java: Made field 'textComponent' + package-private, added field 'active'. + (PropertyChangeHandler.propertyChange): Added variable 'name', added + cases to update field 'active'. + (mouseDragged): Added documentation, added if-clause to update + selection or caret position. + (mouseClicked): Added early return when text component is disabled. + (focusGained): Moved statements into an if-clause. + (focusLost): Added subexpression to if-clause. + (install): Preset value of 'active'. + (paint): Added subexpression to if-clause. + (isVisible): Extended return expression. + * javax/swing/text/JTextComponent.java: + (copy): Copy only if component is enabled. + (cut): Cut only if component is enabled and editable. + (paste): Dito. + +2006-05-11 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/plaf/multi/MultiComboBoxUI.java: Minor formatting change, + * javax/swing/plaf/multi/MultiFileChooserUI.java: Likewise, + * javax/swing/plaf/multi/MultiListUI.java: Likewise, + * javax/swing/plaf/multi/MultiLookAndFeel.java: Likewise, + * javax/swing/plaf/multi/MultiOptionPaneUI.java: Likewise, + * javax/swing/plaf/multi/MultiSplitPaneUI.java: Likewise, + * javax/swing/plaf/multi/MultiTabbedPaneUI.java: Likewise. + +2006-05-11 Roman Kennke <kennke@aicas.com> + + * gnu/java/awt/font/GNUGlyphVector.java + (GNUGlyphVector): Don't apply the font renderer context's + transform. + 2006-05-11 Mark Wielaard <mark@klomp.org> * java/util/logging/Logger.java (global): Initialize inside static PrivilegedAction. +2006-05-11 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/JFrame.java + (EXIT_ON_CLOSE): Added note to API docs, + (close_action): Renamed closeAction, + (JFrame()): Change title to "", + (JFrame(String)): Added API docs, + (getAccessibleContext): Likewise, + (getDefaultCloseOperation): Updated for renamed field, added API docs, + (processWindowEvent): Updated for renamed field, + (setDefaultCloseOperation): Likewise, and updated API docs. + +2006-05-11 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/JFrame.java + (paramString): Reimplemented, + * javax/swing/SwingUtilities.java + (convertWindowConstantToString): New method. + +2006-05-11 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/WindowConstants.java: Updated API docs. + +2006-05-11 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/plaf/basic/BasicToggleButtonUI.java: Updated API docs, + (createUI): Removed 'final' qualifier for parameter, + (paint): Reformatted. + +2006-05-11 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/plaf/basic/BasicCheckBoxUI.java: Added API docs plus, + (createUI): Removed 'final' qualifier on method argument. + +2006-05-11 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/plaf/basic/BasicCheckBoxUI.java + (getDefaultIcon): Removed this redundant method. + +2006-05-11 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/plaf/basic/BasicRadioButtonUI.java + (paint): Pass component size to paintFocus(). + +2006-05-11 Robert Schuster <robertschuster@fsfe.org> + + * java/awt/Component.java: + (dispatchEventImpl): Added comment. + + 2006-05-11 Mark Wielaard <mark@klomp.org> + + * tools/gnu/classpath/tools/appletviewer/Main.java (main): Cast + Option constructor null argument to String. + 2006-05-11 Mark Wielaard <mark@klomp.org> * java/awt/geom/GeneralPath.java (WIND_EVEN_ODD, WIND_NON_ZERO): Fully qualify PathIterator constants +2006-05-11 Robert Schuster <robertschuster@fsfe.org> + + * java/awt/Component.java: + (dispatchEventImpl): Added subexpression to if-clause. + +2006-05-11 Mark Wielaard <mark@klomp.org> + + * java/util/Collections.java (UnmodifiableMapEntry): Qualify + Map.Entry. + +2006-05-10 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/TransferHandler.java: Marked stub methods. + 2006-05-10 Roman Kennke <kennke@aicas.com> PR classpath/27481 @@ -91,6 +1430,143 @@ * javax/swing/JRootPane.java (createContentPane): Don't set background to null. +2006-05-10 Sven de Marothy <sven@physto.se> + + * java/awt/print/PrinterJob.java: + (lookupPrintServices): Un-comment-out. + +2006-05-11 Raif S. Naffah <raif@swiftdsl.com.au> + + * tools/gnu/classpath/tools/getopt/OptionGroup.java + (FILLER): New constant. + (formatText(PrintStream,String,int)): New method. + (formatText(PrintStream,String,int,Locale)): Likewise. + (printHelp): Use formatText method. + * tools/gnu/classpath/tools/getopt/Parser.java + (MAX_LINE_LENGTH): New constant. + (formatText(PrintStream,String)): New method. + (formatText(PrintStream,String,Locale)): Likewise. + (printHelp): New method. + (printHelp(PrintStream)): Increased visibility to protected. + Use formatText method. + +2006-05-10 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/plaf/metal/MetalRadioButtonUI.java + (installDefaults): Use getPropertyPrefix() to allow subclasses to + modify the lookup key. + +2006-05-10 Lillian Angel <langel@redhat.com> + + * java/util/SimpleTimeZone.java: Reverted patch. + (SimpleTimeZone): Throw exception if startMonth == + endMonth. + (SimpleTimeZone): Likewise. + (checkRule): Rewritten to properly check all values (more + efficently). + This code is now more stable, at least less buggy than before. + Fixed API documentation. + (setStartRule): Moved checkRule call to end. + (setStartRule): Likewise. + (setEndRule): Likewise. + (setEndRule): Likewise. + +2006-05-10 Roman Kennke <kennke@aicas.com> + + * gnu/java/awt/peer/swing/SwingComponent.java: + Some API comment fixlets. + * gnu/java/awt/peer/swing/SwingComponentPeer.java: + (createImage): Create a BufferedImage, not a Toolkit image. + (paint): Removed bogus API comment. + (prepareImage): Added checks to avoid NPE. + * gnu/java/awt/peer/swing/SwingContainerPeer.java: + (getInsets): Added check to avoid NPE. + (handleMouseEvent): Added check to avoid NPE. + * gnu/java/awt/peer/swing/SwingFramePeer.java: + Some API comment fixlets. + * gnu/java/awt/peer/swing/SwingMenuBarPeer.java: + Some API comment fixlets. + * gnu/java/awt/peer/swing/SwingTextFieldPeer.java: + Changed start_pos name to startPos. + * gnu/java/awt/peer/swing/SwingWindowPeer.java: + Some API comment fixlets. + +2006-05-10 David Gilbert <david.gilbert@object-refinery.com> + + * java/awt/BasicStroke.java + (equals): Fixed typo in HTML tag for API doc comment. + +2006-05-10 Gary Benson <gbenson@redhat.com> + + * java/lang/ThreadGroup.java (parent): Make package-private. + * java/lang/SecurityManager.java (checkAccess(Thread)): + Reference ThreadGroup.parent directly to avoid extra checks. + * java/lang/SecurityManager.java (checkAccess(ThreadGroup)): + Likewise. + +2006-05-10 Roman Kennke <kennke@aicas.com> + + Reported by Ingo Proetel (proetel@aicas.com) + * java/awt/EventDispatchThread.java + (DEFAULT_PRIORITY): New constant field. + (EventDispatchThread()): Added gnu.awt.dispatchthread.priority + system property for adjusting the priority of the event + dispatch thread. + +2006-05-10 Roman Kennke <kennke@aicas.com> + + Reported by Ingo Proetel (proetel@aicas.com) + * java/awt/image/ColorModel.java + (S_RGB_MODEL): New constant field. + (getRGBDefault): Return constant SRGBColorModel. + (SRGBColorModel): Specialized color model for sRGB. + +2006-05-10 Roman Kennke <kennke@aicas.com> + + * java/awt/ColorPaintContext.java + (getRaster): Create Raster with (0,0) as source location. + +2006-05-10 Roman Kennke <kennke@aicas.com> + + * gnu/java/awt/java2d/AlphaCompositeContext.java + (compose): Don't premultiply alpha to alpha itself. + +2006-05-10 Roman Kennke <kennke@aicas.com> + + * gnu/java/awt/java2d/AbstractGraphics2D.java + (drawImage(Image,AffineTransform,ImageObserver)): Implemented. + (drawImageImpl(Image,AffineTransform,ImageObserver,Rectangle)): + New method. + (drawImage(BufferedImage,BufferedImageOp,int,int)): Implemented. + (drawRenderedImage(RenderedImage,AffineTransform)): Implemented. + (drawRenderedImageImpl(RenderedImage,AffineTransform,Rectangle)): + New method. + (drawRenderableImage(RenderableImage,AffineTransform)): Implemented. + (drawRenderableImageImpl(RenderableImage,AffineTransform,Rectangle)): + New method. + (scale): Inverse transform by doing 1/scale instead of -scale. + (drawImage(Image,int,int,ImageObserver)): Implemented. + (drawImage(Image,int,int,int,int,ImageObserver)): Implemented. + (drawImage(Image,int,int,Color,ImageObserver)): Implemented. + (drawImage(Image,int,int,int,int,Color,ImageObserver)): Implemented. + (drawImage(Image,int,int,int,int,int,int,int,int,ImageObserver)): + Implemented. + (drawImage(Image,int,int,int,int,int,int,int,int,Color,ImageObserver)): + Implemented. + (fillScanline): Work on translated destination raster for + correct compositin. + (init): Fetch the clip after the destination raster is initialized. + * gnu/java/awt/java2d/ImagePaint.java: New file. + * gnu/java/awt/java2d/RasterGraphics + (drawImage): Removed. + +2006-05-09 Thomas Fitzsimmons <fitzsim@redhat.com> + + * resource/gnu/classpath/tools/appletviewer/MessagesBundle.properties: + Clarify option descriptions. + * tools/gnu/classpath/tools/appletviewer/Main.java: Use all + uppercase for metasyntactic variables. + 2006-05-09 Robert Schuster <robertschuster@fsfe.org> PR classpath/24216 @@ -100,6 +1576,200 @@ (removeImpl): Added argument check. (replace): Added more documentation, added argument check. +2006-05-09 Tom Tromey <tromey@redhat.com> + + * tools/.cvsignore: Added appletviewer. + +2006-05-09 Tom Tromey <tromey@redhat.com> + + * tools/gnu/classpath/tools/getopt/Parser.java (printHelp): Skip + empty groups. + +2006-05-09 Tom Tromey <tromey@redhat.com> + + * tools/gnu/classpath/tools/getopt/OptionGroup.java (printHelp): + Special case for '-J'. Use space instead of '='. + * tools/gnu/classpath/tools/getopt/Parser.java (setHeader): Added + comment. + +2006-05-09 Thomas Fitzsimmons <fitzsim@redhat.com> + + * configure.ac: Add --disable-plugin and --with-vm options. Check + for plugin support headers and libraries. + * native/Makefile.am: Recurse into plugin directory. + * native/plugin/.cvsignore: New file. + * native/plugin/Makefile.am: New file. + * native/plugin/gcjwebplugin.cc: New file. + * tools/Makefile.am: Install appletviewer wrapper script. + * tools/appletviewer.in: Replace VM location heuristic with + VM_BINARY configure substitution. + +2006-05-09 Tom Tromey <tromey@redhat.com> + + * tools/gnu/classpath/tools/getopt/OptionGroup.java (printHelp): Added + an initial pass to look for short options. Added 'longOnly' option. + * tools/gnu/classpath/tools/appletviewer/Main.java (main): Removed -J + option. + * tools/gnu/classpath/tools/getopt/Parser.java (parsed): Put stadnard + options into final group. Added -J. + (add): Insert new groups before final group. + (printHelp): Updated. + +2006-05-09 Audrius Meskauskas <AudriusA@Bioinformatics.org> + + PR 27518 + * tools/gnu/classpath/tools/giop/GRMIC.java (main), + tools/gnu/classpath/tools/rmi/RMIC.java (main): + Expect -classpath option. + * tools/gnu/classpath/tools/rmi/RMIC.txt, + tools/gnu/classpath/tools/giop/GRMIC.txt: Documenting + -classpath option. + tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java + (classLoader): New field. (loadClass, setClassPath): + New methods. + +2006-05-09 Roman Kennke <kennke@aicas.com> + + * gnu/java/awt/java2d/RasterGraphics.java + (RasterGraphics): Call init() and super(). + (drawImage): Temporary drawImage impl until AbstractGraphics2D has + this. + +2006-05-09 Gary Benson <gbenson@redhat.com> + + * java/lang/Thread.java (Thread): Always perform threadgroup + access checks on thread creation. + +2006-05-09 Chris Burdess <dog@gnu.org> + + * gnu/xml/dom/DomNode.java: Permit comments and PIs in doctype nodes to + be preserved during cloneNode. + +2006-05-09 Audrius Meskauskas <AudriusA@Bioinformatics.org> + + PR 27517 + * tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java (compile): + Do not demand all thrown exceptions to be an instance of RemoteException. + +2006-05-09 Thomas Fitzsimmons <fitzsim@redhat.com> + + * resource/gnu/classpath/tools/appletviewer/MessagesBundle.properties: + Use hash-style comments. + * resource/gnu/classpath/tools/appletviewer/MessagesBundle_de.properties: + Likewise. + +2006-05-09 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/JLabel.java + (paramString): Added more attribute details, + * javax/swing/SwingUtilities.java + (convertHorizontalAlignmentCodeToString): New method, + (convertVerticalAlignmentCodeToString): New method. + +2006-05-08 Tom Tromey <tromey@redhat.com> + + * tools/gnu/classpath/tools/jar/Updater.java (run): Updated. + * tools/gnu/classpath/tools/jar/Main.java: Use javadoc for fields. + * tools/gnu/classpath/tools/jar/Lister.java (listJar): Use + ZipInputStream. + (run): Updated. + * tools/gnu/classpath/tools/jar/Extractor.java (run): Use System.err + for verbose. + (run): Use ZipInputStream. + (initSet): New method. + (shouldExtract): Likewise. + (run): Use new methods. + * tools/gnu/classpath/tools/jar/Creator.java + (writeCommandLineEntries): New overload. + (writeFile): Use System.err for verbose. + (writeManifest): New method. + (writtenItems): New field. + (writeFile): Update it. + (writeCommandLineEntries): Return void. Call writeManifest. + (addEntries): Don't add extra '/'. + * NEWS: Mention jar. + +2006-05-08 Lillian Angel <langel@redhat.com> + + * gnu/java/net/IndexListParser.java: New class. + * java/net/URLClassLoader.java + (JarURLLoader): Fixed code to use new class. + +2006-05-08 Roman Kennke <kennke@aicas.com> + + * javax/swing/JComboBox.java + (AccessibleJComboBox.getAccessibleChildrenCount): Implemented. + (AccessibleJComboBox.getAccessibleChild): Implemented. + (AccessibleJComboBox.getAccessibleSelection()): Implemented. + (AccessibleJComboBox.getAccessibleSelection(int)): Implemented. + (AccessibleJComboBox.isAccessibleChildSelected): Implemented. + (AccessibleJComboBox.getAccessibleAction): Implemented. + (AccessibleJComboBox.getAccessibleActionDescription): Implemented. + (AccessibleJComboBox.getAccessibleActionCount): Implemented. + (AccessibleJComboBox.doAccessibleAction): Implemented. + (AccessibleJComboBox.getAccessibleSelectionCount): Implemented. + (AccessibleJComboBox.addAccessibleSelection): Implemented. + (AccessibleJComboBox.removeAccessibleSelection): Implemented. + (AccessibleJComboBox.clearAccessibleSelection): Implemented. + (AccessibleJComboBox.selectAllAccessibleSelection): Implemented. + +2006-05-08 Thomas Fitzsimmons <fitzsim@redhat.com> + + * configure.ac: Add support for building appletviewer. + * resource/gnu/classpath/tools/appletviewer/MessagesBundle.properties: + New file. + * resource/gnu/classpath/tools/appletviewer/MessagesBundle_de.properties: + New file. + * tools/appletviewer.c: New file. + * tools/appletviewer.in: New file. + * tools/gnu/classpath/tools/appletviewer/AppletClassLoader.java: + New file. + * tools/gnu/classpath/tools/appletviewer/AppletSecurityManager.java: + New file. + * tools/gnu/classpath/tools/appletviewer/AppletTag.java: New file. + * tools/gnu/classpath/tools/appletviewer/AppletWarning.java: New + file. + * tools/gnu/classpath/tools/appletviewer/CommonAppletContext.java: + New file. + * tools/gnu/classpath/tools/appletviewer/CommonAppletStub.java: + New file. + * tools/gnu/classpath/tools/appletviewer/ConsoleDialog.java: New + file. + * tools/gnu/classpath/tools/appletviewer/ErrorApplet.java: New + file. + * tools/gnu/classpath/tools/appletviewer/Main.java: New file. + * tools/gnu/classpath/tools/appletviewer/PluginAppletContext.java: + New file. + * tools/gnu/classpath/tools/appletviewer/PluginAppletViewer.java: + New file. + * tools/gnu/classpath/tools/appletviewer/PluginAppletWindow.java: + New file. + * tools/gnu/classpath/tools/appletviewer/StandaloneAppletContext.java: + New file. + * tools/gnu/classpath/tools/appletviewer/StandaloneAppletViewer.java: + New file. + * tools/gnu/classpath/tools/appletviewer/StandaloneAppletWindow.java: + New file. + * tools/gnu/classpath/tools/appletviewer/TagParser.java: New + file. + +2006-05-08 Tom Tromey <tromey@redhat.com> + + * tools/gnu/classpath/tools/getopt/ClasspathToolParser.java: New file. + * tools/gnu/classpath/tools/jar/Action.java: New file. + * tools/gnu/classpath/tools/jar/Creator.java: New file. + * tools/gnu/classpath/tools/jar/Entry.java: New file. + * tools/gnu/classpath/tools/jar/Extractor.java: New file. + * tools/gnu/classpath/tools/jar/Lister.java: New file. + * tools/gnu/classpath/tools/jar/Main.java: New file. + * tools/gnu/classpath/tools/jar/Updater.java: New file. + * tools/gnu/classpath/tools/getopt/Option.java: New file. + * tools/gnu/classpath/tools/getopt/OptionException.java: New file. + * tools/gnu/classpath/tools/getopt/OptionGroup.java: New file. + * tools/gnu/classpath/tools/getopt/Parser.java: New file. + * tools/gnu/classpath/tools/getopt/FileArgumentCallback.java: New + file. + 2006-05-08 Lillian Angel <langel@redhat.com> * java/net/URLClassLoader.java @@ -108,7 +1778,25 @@ 2006-05-08 Roman Kennke <kennke@aicas.com> - PR classpath/27481 + * gnu/java/awt/java2d/AbstractGraphics2D.java + (fill): Removed commented out code. + (fillShape): Also determine the outline of the clip and feed + it into the rendering method. Use new helper method for + converting the shapes into lists of segments. + (getUserBounds): Removed obsolete method. + (rawFillShape): Respect the clip when rendering shapes. + (fillShapeAntialias): Adjusted signature for new clipped rendering. + However, the implementation can't clip still. + (getSegments): New helper method for converting a shape into + a list of segments. + (clipShape): Removed obsolete method. + * gnu/java/awt/java2d/PolyEdge.java + (isClip): New field. + (PolyEdge): Added isField argument to constructor. + +2006-05-08 Roman Kennke <kennke@aicas.com> + + PR 27481 * javax/swing/JRootPane.java (createContentPane): Set background of the content pane to null, so that the content pane inherits its background from the @@ -116,7 +1804,7 @@ 2006-05-08 Roman Kennke <kennke@aicas.com> - PR classpath/27480 + PR 27480 * javax/swing/ButtonGroup.java (add): Check if new button is selected and if so, deselect other buttons in the group. @@ -130,27 +1818,27 @@ 2006-05-08 Roman Kennke <kennke@aicas.com> - PR classpath/27461 + PR 27461 * javax/swing/ImageIcon.java (ImageIcon(URL)): Set description to URL.toString(). 2006-05-08 Roman Kennke <kennke@aicas.com> - PR classpath/27482 + PR 27482 * javax/swing/JTable.java (IconCellRenderer.getTableCellRendererComponent): Set icon to null when cell value is null. 2006-05-08 Roman Kennke <kennke@aicas.com> - PR classpath/27484 + PR 27484 * javax/swing/DefaultDesktopManager.java (closeFrame): Don't perform default close action on the frame to prevent endless loop. 2006-05-08 Roman Kennke <kennke@aicas.com> - PR classpath/27485 + PR 27485 * javax/swing/table/DefaultTableModel.java (addExtraRows): New helper method. (checkSize): New helper method. @@ -161,10 +1849,19 @@ 2006-05-08 Roman Kennke <kennke@aicas.com> - PR classpath/27486 + PR 27486 * javax/swing/JTable.java (setValueAt): Allow setting values even when table is editable. +2006-05-08 Tom Tromey <tromey@redhat.com> + + * java/text/SimpleDateFormat.java (compileFormat): Added missing + space to error message. + +2006-05-08 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/AbstractButton.java: Fixed comment typos. + 2006-05-07 Andrew John Hughes <gnu_andrew@member.fsf.org> PR classpath/27435: @@ -175,19 +1872,13 @@ Fixed PR27343 * java/util/Calendar.java (setTimeZone): Force recalculation. - + 2006-05-07 Sven de Marothy <sven@physto.se> Fixed PR27463 * javax/swing/plaf/metal/MetalInternalFrameTitlePane.java (propertyChange): Handle FRAME_ICON_PROPERTY property. - -2006-05-06 Sven de Marothy <sven@physto.se> - - Fixed PR27454 - * gnu/java/awt/peer/gtk/GtkImage: (drawPixels,drawPixelsScaled): - Check for zero image sizes. - + 2006-05-07 Andrew John Hughes <gnu_andrew@member.fsf.org> PR classpath/27311: @@ -197,16 +1888,34 @@ (formatInternal(double,StringFormatBuffer,FieldPosition)): Don't calculate the exponent when the number is 0 or less. Also, use log10 instead of log now it's available. + +2006-05-07 Raif S. Naffah <raif@swiftdsl.com.au> -2006-05-07 Sven de Marothy <sven@physto.se> + * gnu/javax/crypto/keyring/PrimitiveEntry.java (PrimitiveEntry): + Use instance's field creationDate not the constructor's argument. + * gnu/javax/crypto/keyring/PasswordEncryptedEntry.java: + Removed unused imports. + Sorted imports. + (log): New field. + (decrypt): Added trace/debug/timing statements. + (encrypt): Likewise. + Use PRNG instead of instantiating every time a new SecureRandom. + * gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java: + Removed unused imports. + Sorted imports. + (log): New field. + (verify): Added trace/debug/timing statements. + (authenticate): Likewise. + Use PRNG instead of instantiating every time a new SecureRandom. - Fixed PR27455 - * gnu/java/awt/peer/GLightweightPeer.java (mouseEntered): Remove. - * java/awt/Component.java (processMouseEvent): - Do lightweight cursor handling. - * javax/swing/plaf/basic/BasicTableHeaderUI.java - (endResizing,mouseMoved): Save and reset original cursor, not the - default one. +2006-05-07 Raif S. Naffah <raif@swiftdsl.com.au> + + * gnu/classpath/debug/Simple1LineFormatter.java (DAT_FORMAT): Removed. + (THREAD_FORMAT): Likewise. + (dateFormat): Added field. + (threadFormat): Added field. + (format): Initialize instance fields if null. + Use StringBuilder instead of StringBuffer. 2006-05-07 Roman Kennke <kennke@aicas.com> @@ -237,6 +1946,66 @@ (compose): Fixed loops, conditions and logic to make compositing work correctly. +2006-05-07 Roman Kennke <kennke@aicas.com> + + * java/awt/ColorPaintContext.java + (ColorPaintContext): Fixed filling of the raster. + +2006-05-07 Sven de Marothy <sven@physto.se> + + Fixed PR27455 + * gnu/java/awt/peer/GLightweightPeer.java (mouseEntered): Remove. + * java/awt/Component.java (processMouseEvent): + Do lightweight cursor handling. + * javax/swing/plaf/basic/BasicTableHeaderUI.java + (endResizing,mouseMoved): Save and reset original cursor, not the + default one. + +2006-05-07 Audrius Meskauskas <AudriusA@Bioinformatics.org> + + PR 27298 + * javax/swing/plaf/basic/BasicTreeUI.java (NodeDimensionsHandler. + getNodeDimensions): Mind the size of the node icon. (getRowX): + use totalChildIndent. (TreeExpansionHandler): Set maximal height + to zero on events. (nullIcon): New field. (getCurrentControlIcon): + Return nullIcon if there is no other icon. (getNodeIcon): New method. + (installDefaults): assign totalChildIndent. (installUI): Call + updateExpandedDescendants. (paintHorizontalPartOfLeg): Rewritten. + (paintRow): Rewritten. (updateRenderer): Do not set the renderer for + the tree. + +2006-05-06 Sven de Marothy <sven@physto.se> + + Fixed PR27454 + * gnu/java/awt/peer/gtk/GtkImage: (drawPixels,drawPixelsScaled): + Check for zero image sizes. + +2006-05-06 Olivier Jolly <olivier.jolly@pcedev.com> + + Fixed PR27362 + * java/util/Calendar.java (clear(int)): Forced internal state + completion before performing a field clearing. + +2006-05-06 Olivier Jolly <olivier.jolly@pcedev.com> + + * java/util/Collections.java(UnmodifiableMap.UnmodifiableEntrySet. + UnmodifiableMapEntry): New Map.Entry implementation which is immutable. + (UnmodifiableMap.UnmodifiableEntrySet.iterator, + UnmodifiableMap.UnmodifiableEntrySet.toArray, + UnmodifiableMap.UnmodifiableEntrySet.toArray(Object[])): Used + UnmodifiableMapEntry as part of their return value. + +2006-05-06 Raif S. Naffah <raif@swiftdsl.com.au> + + * tools/keytool.sh.in: Removed (renamed to keytool.in). + * tools/jarsigner.in: Removed (renamed to jarsigner.in). + * tools/Makefile.am: Include jarsigner and keytool classes in tools.zip. + Generate jarsigner and keytool scripts. + * tools/keytool.in: New file (renamed from keytool.sh.in). + * tools/jarsigner.in: New file (renamed from jarsigner.sh.in). + * tools/.cvsignore: Replaced *.sh with * + * configure.ac: Replaced tools/*.sh with tools/*. + 2006-05-05 Roman Kennke <kennke@aicas.com> * java/awt/image/ColorModel.java @@ -253,6 +2022,58 @@ * javax/swing/JTable.java (tableChanged): Sync selection model with table model changes. +2006-05-05 Audrius Meskauskas <AudriusA@Bioinformatics.org> + + * javax/swing/plaf/basic/BasicTreeUI.java (paint): Return early + if there are no visible nodes to paint. + +2006-05-05 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/JOptionPane.java: API doc updates. + +2006-05-05 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/JToolBar.java + (paramString): Reimplemented. + +2006-05-05 David Gilbert <david.gilbert@object-refinery.com> + + * javax/swing/JScrollBar.java + (paramString): Reimplemented. + +2006-05-04 Tom Tromey <tromey@redhat.com> + + PR classpath/27375: + * java/util/zip/ZipFile.java (entries): Now a LinkedHashMap. + (readEntries): Updated. + (getEntries): Likewise. + (getEntry): Likewise. + (getInputStream): Likewise. + +2006-05-04 Thomas Fitzsimmons <fitzsim@redhat.com> + + * gnu/javax/imageio/jpeg/DCT.java, + gnu/javax/imageio/jpeg/HuffmanTable.java, + gnu/javax/imageio/jpeg/JPEGComponent.java, + gnu/javax/imageio/jpeg/JPEGDecoder.java, + gnu/javax/imageio/jpeg/JPEGException.java, + gnu/javax/imageio/jpeg/JPEGFrame.java, + gnu/javax/imageio/jpeg/JPEGImageInputStream.java, + gnu/javax/imageio/jpeg/JPEGImageReader.java, + gnu/javax/imageio/jpeg/JPEGImageReaderSpi.java, + gnu/javax/imageio/jpeg/JPEGMarker.java, + gnu/javax/imageio/jpeg/JPEGMarkerFoundException.java, + gnu/javax/imageio/jpeg/JPEGScan.java, + gnu/javax/imageio/jpeg/YCbCr_ColorSpace.java, + gnu/javax/imageio/jpeg/ZigZag.java: New files. + +2006-05-04 Lillian Angel <langel@redhat.com> + + * javax/swing/JLabel.java + (JLabel): Pass in an empty string for the text parameter. + (JLabel): Likewise. + (JLabel): Likewise. + 2006-05-04 Roman Kennke <kennke@aicas.com> * javax/swing/plaf/basic/BasicButtonListener.java @@ -268,18 +2089,17 @@ * javax/swing/JLabel.java (AccessibleJLabel.getSelectedText): Return null instead of "". (AccessibleJLabel.getSelectionStart): Added comment why - return -1 is correct here. + return -1 is correct here. (AccessibleJLabel.getSelectionEnd): Added comment why - return -1 is correct here. - (AccessibleJLabel.getCharacterAttribute): Added comment about - what to do here. + return -1 is correct here. + (AccessibleJLabel.getCharacterAttribute): Added comment about what + to do here. (AccessibleJLabel.getCharCount): Added comment about what - to do here. - (AccessibleJLabel.getCharacterBounds): Tagged as not - implemented. + to do here. + (AccessibleJLabel.getCharacterBounds): Tagged as not implemented. (AccessibleJLabel.getIndexAtPoint): Tagged as not implemented. (paramString): Return super.paramString() here, this provides - a more meaningful output. + a more meaningful output. 2006-05-04 Roman Kennke <kennke@aicas.com> @@ -291,49 +2111,41 @@ * javax/swing/AbstractButton.java (addImpl): New method. Installs an OverlayLayout if no other layout has been installed before. - (setLayout): New method. Detect if a client app installs a - custom layout. - + (setLayout): New method. Detect if a client app installs a custom + layout. + 2006-05-04 Roman Kennke <kennke@aicas.com> - * javax/swing/table/DefaultTableCellModel.java + * javax/swing/table/DefaultTableCellRenderer.java (noFocusBorder): Fixed width of empty border to 1. (getTableCellRendererComponent): Don't change the colors for focuses cells. Fixed border for focused cells. - + 2006-05-04 Roman Kennke <kennke@aicas.com> * javax/swing/JTable.java - (moveToCellBeingEdited): Adjust bounding box - of editing component to exactly cover the grid. + (moveToCellBeingEdited): Adjust bounding box of editing component + to exactly cover the grid. * javax/swing/plaf/basic/BasicTableUI.java - (paint): Paint grid to the bottom and right of - the cells instead of left and top. Adjust bounding - box of cells accordingly. + (paint): Paint grid to the bottom and right of the cells instead + of left and top. Adjust bounding box of cells accordingly. * javax/swing/plaf/metal/MetalLookAndFeel.java - (initComponentDefaults): Fixed color of JTable - selection border. + (initComponentDefaults): Fixed color of JTable selection border. * javax/swing/plaf/metal/OceanTheme.java - (addCustomEntriesToTable): Fixed color of JTable - selection border. + (addCustomEntriesToTable): Fixed color of JTable selection border. 2006-05-04 Raif S. Naffah <raif@swiftdsl.com.au> * tools/gnu/classpath/tools/keytool/ExportCmd.java (setup): Use _alias instead of alias. -2006-05-04 Lillian Angel <langel@redhat.com> - - * javax/swing/JLabel.java - (JLabel): Pass in an empty string for the text parameter. - (JLabel): Likewise. - (JLabel): Likewise. +2006-05-03 Andrew John Hughes <gnu_andrew@member.fsf.org> -2006-05-05 Audrius Meskauskas <AudriusA@Bioinformatics.org> + * configure.ac: + Set version to 0.92-pre. + * NEWS: + Add space for 0.92 entries. - * javax/swing/plaf/basic/BasicTreeUI.java (paint): Return early - if there are no visible nodes to paint. - 2006-05-03 Andrew John Hughes <gnu_andrew@member.fsf.org> * include/Makefile.am: @@ -1527,7 +3339,7 @@ 2006-04-21 David Gilbert <david.gilbert@object-refinery.com> * javax/swing/border/AbstractBorder.java: API doc updates, - * javax/swing/border/BevelBorder.java: Likewise, + * javax/swing/border/BevelBorder.java: Likewise, * javax/swing/border/CompoundBorder.java: Likewise, * javax/swing/border/EtchedBorder.java: Likewise, * javax/swing/border/LineBorder.java: Likewise, @@ -1885,7 +3697,8 @@ 2006-04-18 Robert Schuster <robertschuster@fsfe.org> - * javax/swing/plaf/basic/BasicTextUI.java: Implemented. + * javax/swing/plaf/basic/BasicTextUI.java: + (getNextVisualPositionFrom): Implemented. 2006-04-18 David Gilbert <david.gilbert@object-refinery.com> @@ -5576,21 +7389,6 @@ * vm/reference/gnu/classpath/Unsafe.java: New class to handle low-level facilities for concurrency. -2006-03-19 Michael Barker <mike@middlesoft.co.uk> - - * vm/reference/gnu/java/nio/VMChannel.java: Added, supports setting - non-blocking and scatter-gather io operations. - * gnu/java/nio/PipeImpl.java: Retrofitted to use VMChannel - * gnu/java/nio/SelectorImpl.java - (register) Added condition for gnu.java.nio.SocketChannelSelectionKeyImpl - * gnu/java/nio/SocketChannelSelectionKeyImpl.java Added. - * gnu/java/nio/channels/FileChannelImpl.java: Retrofitted to use VMChannel - * java/nio/FileChannel.java - (read (ByteBuffer)) Changed to call abstract method. - (write (ByteBuffer)) Changed to call abstract method. - * include/gnu_java_nio_VMChannel.h: Added. - * native/jni/java-nio/gnu_java_nio_VMChannel.c: Added. - 2006-03-19 Mark Wielaard <mark@klomp.org> * include/Makefile.am: Rename PlainDatagramSocketImpl to @@ -12120,7 +13918,7 @@ (AccessibleJComponent.changeSupport): Changed to be a java.beans.PropertyChangeSupport rather than SwingPropertyChangeSupport. - (AccessibleJComponent.AccesibleJComponent()): Change initialization + (AccessibleJComponent.AccessibleJComponent()): Change initialization of above field. (changeSupport): Removed unneeded field. (removePropertyChangeListener): Removed unneeded methods. @@ -54,6 +54,9 @@ Suggested Software For building the Cairo GdkGraphics2D backend you need at least Cairo 0.5.0. + For building gcjwebplugin you'll need the Mozilla plugin + support headers and libraries. + For building the Qt AWT peer JNI native libraries you have to specify --enable-qt-peer and need the following library: @@ -1,3 +1,10 @@ +New in release 0.92 (UNRELEASED) + +* A Mozilla plugin, 'gcjwebplugin', is now included. It introduces a + dependency on the Mozilla plugin support headers and libraries. +* An 'appletviewer' tool is now included. +* A 'jar' tool is now included. + New in release 0.91 (May 15, 2006) * Experimental activation (java.rmi.activation) support, including RMI @@ -27,6 +27,7 @@ Steven Hugg (hugg@pobox.com) jockey@aromasoft.com Isaac Jones (ijones@cis.ohio-state.edu) Oskar Liljeblad (osk@hem.passagen.se) +Trevor Linton (tlinton@xmission.com) Casey Marshall (rsdio@metastatic.org) Steve Mayer (SMayer@dynamicsoft.com) Matt Mucklo (mmucklo@jumpsmart.com) diff --git a/configure.ac b/configure.ac index 60348845b..533247e92 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ dnl ----------------------------------------------------------- dnl define([AC_CACHE_LOAD], )dnl dnl define([AC_CACHE_SAVE], )dnl -AC_INIT([GNU Classpath],[0.91-generics],[classpath@gnu.org],[classpath]) +AC_INIT([GNU Classpath],[0.92-generics-pre],[classpath@gnu.org],[classpath]) AC_CONFIG_SRCDIR(java/lang/System.java) AC_CANONICAL_TARGET @@ -195,12 +195,24 @@ AC_ARG_ENABLE([qt-peer], [COMPILE_QT_PEER=no]) AM_CONDITIONAL(CREATE_QT_PEER_LIBRARIES, test "x${COMPILE_QT_PEER}" = xyes) +dnl ----------------------------------------------------------- +dnl Plugin (enabled by default) +dnl ----------------------------------------------------------- +AC_ARG_ENABLE([plugin], + [AS_HELP_STRING(--disable-plugin,compile gcjwebplugin (disabled by --disable-plugin) [default=yes])], + [case "${enableval}" in + yes) COMPILE_PLUGIN=yes ;; + no) COMPILE_PLUGIN=no ;; + *) COMPILE_PLUGIN=yes ;; + esac], + [COMPILE_PLUGIN=yes]) +AM_CONDITIONAL(CREATE_PLUGIN, test "x${COMPILE_PLUGIN}" = xyes) dnl ----------------------------------------------------------- dnl Sets the native libraries installation dir dnl ----------------------------------------------------------- AC_ARG_WITH([native-libdir], - [AS_HELP_STRING(--with-native-libdir,sets the installation directore for native libraries [default='${libdir}/${PACKAGE}'])], + [AS_HELP_STRING(--with-native-libdir,sets the installation directory for native libraries [default='${libdir}/${PACKAGE}'])], [ nativeexeclibdir=${withval} ], @@ -225,6 +237,20 @@ AC_ARG_WITH([glibj-dir], AC_SUBST(glibjdir) dnl ----------------------------------------------------------- +dnl Sets the VM name for use in tool wrapper scripts +dnl ----------------------------------------------------------- +AC_ARG_WITH([vm], + [AS_HELP_STRING(--with-vm,sets the VM binary name [default='${prefix}/bin/jamvm'])], + [ + VM_BINARY=${withval} + ], + [ + VM_BINARY='${prefix}/bin/jamvm' + ]) + +AC_SUBST(VM_BINARY) + +dnl ----------------------------------------------------------- dnl Regenerate headers at build time (disabled by default) dnl ----------------------------------------------------------- AC_ARG_ENABLE([regen-headers], @@ -441,6 +467,19 @@ if test "x${COMPILE_JNI}" = xyes; then AC_SUBST(QT_CFLAGS) AC_SUBST(QT_LIBS) fi + + dnl Check for plugin support headers and libraries. + if test "x${COMPILE_PLUGIN}" = xyes; then + PKG_CHECK_MODULES(MOZILLA, mozilla-plugin) + PKG_CHECK_MODULES(GLIB, glib-2.0) + + AC_SUBST(MOZILLA_CFLAGS) + AC_SUBST(MOZILLA_LIBS) + AC_SUBST(GLIB_CFLAGS) + AC_SUBST(GLIB_LIBS) + + AC_SUBST(PLUGIN_DIR, $HOME/.mozilla/plugins/) + fi fi CLASSPATH_WITH_JAVAH @@ -665,6 +704,7 @@ native/jni/qt-peer/Makefile native/jni/xmlj/Makefile native/jni/midi-alsa/Makefile native/jni/midi-dssi/Makefile +native/plugin/Makefile native/target/Makefile native/target/Linux/Makefile native/target/generic/Makefile @@ -674,11 +714,15 @@ scripts/classpath.spec lib/Makefile lib/gen-classlist.sh lib/copy-vmresources.sh +tools/appletviewer tools/Makefile -tools/jarsigner.sh -tools/keytool.sh +tools/jarsigner +tools/keytool examples/Makefile examples/Makefile.jawt]) AC_CONFIG_COMMANDS([gen-classlist],[chmod 755 lib/gen-classlist.sh]) AC_CONFIG_COMMANDS([copy-vmresources],[chmod 755 lib/copy-vmresources.sh]) +AC_CONFIG_COMMANDS([appletviewer],[chmod 755 tools/appletviewer]) +AC_CONFIG_COMMANDS([jarsigner],[chmod 755 tools/jarsigner]) +AC_CONFIG_COMMANDS([keytool],[chmod 755 tools/keytool]) AC_OUTPUT diff --git a/doc/www.gnu.org/announce/20060515.wml b/doc/www.gnu.org/announce/20060515.wml new file mode 100644 index 000000000..deb127f86 --- /dev/null +++ b/doc/www.gnu.org/announce/20060515.wml @@ -0,0 +1,217 @@ +#!wml --include=.. + +#use wml::std::page +#use wml::std::lang +#use wml::fmt::isolatin +#use wml::std::case global=upper + +<lang:star:slice:> + +<set-var last-modified-author="mjw"> + +#include <include/macros.wml> + +<header title="GNU Classpath 0.91 Announcement (2006-05-15)"> +<pre> +GNU Classpath 0.91 "All for One, One for All" released + +GNU Classpath, essential libraries for java, is a project to create +free core class libraries for use with runtimes, compilers and tools +for the java programming language. + +The GNU Classpath developer snapshot releases are not directly aimed +at the end user but are meant to be integrated into larger development +platforms. For example the GCC (gcj) and Kaffe projects will use the +developer snapshots as a base for future versions. More projects based +on GNU Classpath: http://www.gnu.org/software/classpath/stories.html + +Some highlights of changes in this release (more extensive list below): + + RMI activation daemon and persistent naming service tools are now + included. Print service discovery, single document print jobs and + support for client-formatted print data through CUPS has been + added. Support for custom mouse cursors, system clipboard and + selection access has been implemented. A Free Swing OceanTheme and + support for assistive technologies (accessibility) has been + added. The VM runtime interface has been merged with the generics + version to support annotations and other 1.5 language features. + +GNU Classpath 0.91 does not yet support all new 1.5 additions, but +there is also an experimental GNU Classpath "generics" release. +classpath-0.91-generics contains a version of the core library that +uses the new 1.5 language features such as generics and +enumerations. ECJ, JamVM, IKVM and Cacao are known to support the +generics release. And you can use it to run Eclipse 3.1 with it to +develop programs that use the new 1.5 language and core library +additions. classpath-generics is a work in progress and not as +extensively tested as our regular releases. But please try it out if +you want to help us test the new 1.5 support of the core libraries. + +The GNU Classpath developers site http://developer.classpath.org/ +provides detailed information on how to start with helping the GNU +Classpath project and gives an overview of the core class library +packages currently provided. For each snapshot release generated +documentation is provided through the GNU Classpath Tools gjdoc +project. A documentation generation framework for java source +files used by the GNU project. Full documentation on the currently +implementated packages and classes can be found at: +http://developer.classpath.org/doc/ + +For more information about the project see also: + +- GNU Classpath home page: + http://www.gnu.org/software/classpath/ + +- Developer information (wiki): + http://developer.classpath.org/ + +- Full class documentation + http://developer.classpath.org/doc/ + +- GNU Classpath hackers: + http://planet.classpath.org/ + +- Autobuilder, current build status, build snapshots: + http://builder.classpath.org/ + +- Application test pages (wiki) + http://developer.classpath.org/mediation/FreeAWTTestApps + http://developer.classpath.org/mediation/FreeSwingTestApps + http://developer.classpath.org/mediation/FreeSWTTestApps + +- GNU Classpath hacking with Eclipse (wiki) + http://developer.classpath.org/mediation/ClasspathHackingWithEclipse + +- GNU Classpath promotion banners: + http://developer.classpath.org/mediation/ClasspathBanners + +This release depends on gtk+ 2.4 for AWT support. But gtk+ 2.6 or +higher is recommended. Included, but not activated by default in this +release is a Graphics2D implementation based on the Cairo Graphics +framework (http://www.cairographics.org). Enabling this makes programs +like JFreeChart and JEdit start up on GNU Classpath based runtimes. +To enable this support install the cairo 0.5.x snapshot, configure GNU +Classpath with --enable-gtk-cairo. + +One of the major focuses of the GNU Classpath project is expanding and +using the Mauve test suite for Compatibility, Completeness and +Correctness checking. Various groups around GNU Classpath collaborate +on the free software Mauve test suite which contains more than 45.000 +core library tests. Mauve has various modules for testing core class +library implementations, byte code verifiers, source to byte code and +native code compiler tests. Mauve also contains the Wonka visual test +suite and the Jacks Compiler Killer Suite. +See for more information: http://www.sourceware.org/mauve/ +This release passes 44975 out of 45537 Mauve core library tests. + +Conformance reports for the included jaxp support can be found in the +doc/README.jaxp file. + +GNU Classpath 0.91 can be downloaded from +ftp://ftp.gnu.org/pub/gnu/classpath/ +or one of the ftp.gnu.org mirrors +http://www.gnu.org/order/ftp.html + +File: classpath-0.91.tar.gz +MD5sum: 3ce11b4b990b108c5ab93894fcc61be6 +SHA1sum: fcbfdf64f7a990f1747621772a2e9e69d0baaab7 + +File: classpath-0.91-generics.tar.gz (EXPERIMENTAL) +MD5sum: e79132b1b8441523b8f4f6a8f2d2910b +SHA1sum: 90be3b2115e8a0288bcb6e2d1860fe58b42c77b5 + +New in release 0.91 (May 14, 2006) +(See the ChangeLog file for a full list of changes.) + +* Experimental activation (java.rmi.activation) support, including RMI + activation daemon and persistent naming service tools. +* Experimental printing support: The API implementation of the javax.print + packages has been finished and work on the printing provider implementation + started. Currently supported features from the Java Print Service API are + print service discovery (CUPS registered printers), single document print + jobs and support for client-formatted print data. An example application + (see: examples/gnu/classpath/examples/print/Demo) has been added to show + the API usage for service discovery and printing of files. +* The GTKToolkit now gives access to the both the system clipboard and + system selection. +* Custom mouse cursor support has been added to the gtk+ peers. And cursors + can now also be set on light-weight components. +* Free Swing improvements: Support for OceanTheme has been mostly completed + and turned on as default Metal theme. X11-style Copy and Paste behavior in + text components with the middle mouse button. Support cursor changes on + various components when resizing. Support for Look and Feel window + decorations has been added. +* Updated locale data information to CLDR 1.3. +* Various bugs in Classpath's SecureRandom implementations have been + fixed; that class now respects the "securerandom.source" security + property and the "java.security.egd" system property. +* Support for assistive technologies has been added to AWT and Swing. + +Runtime interface changes: + +* A new class, VMArray, is now available which separates the native + array creation method from java.lang.reflect.Array. +* A new class, gnu.classpath.Unsafe, is provided for handling the + new low-level operations required by java.util.concurrent. +* The reference implementations of Method, Constructor, and Field + now have a new native getModifiersInternal() method. The public + getModifiers() method in each case has been rewritten in terms of + this method. +* The reference implementation of VMThread has been updated to handle + the new Thread.UncaughtExceptionHandler support. +* A new class, java.security.VMSecureRandom, is now available that is + used to generate random numbers for seeding cryptographically-secure + pseudo-random number generators. +* VMClass and the reference implementations of Method, Constructor and Field + now include a number of 1.5 methods imported from the generics branch. + These are all optional (in the sense that the methods associated with them + merely fail on use if the VM doesn't provide them, rather than the + VM failing altogether), but VMs should aim to support them where possible. +* The implementation of java.lang.instrument has been merged to the main + branch from the generics branch. +* The VM interfaces of the main branch and the generics branch are now + consistent with one another. As a result, the main branch includes an + additional environ() function in VMSystem and an additional argument has + been added to nativeSpawn() in VMProcess. +* Annotation support is now available in the main branch, if the VM supports + it. The VM should implement VMClass.getDeclaredAnnotations, + Constructor.getAnnotation, Constructor.getDeclaredAnnotations, + Field.getAnnotation, Field.getDeclaredAnnotations, Method.getAnnotation and + Method.getDeclaredAnnotations. +* java.lang.Package now has a new constructor that takes the defining + ClassLoader as an extra argument. If you use a custom version of + VMClassLoader, please switch it to use this constructor. +* The reference implementation of VMClassLoader.getBootPackages() now + reads the META-INF/INDEX.LIST resource using the java.boot.class.path + system property. + +New/Untested/Disabled Features: + + The following new features are included, but not ready for + production yet. They are explicitly disabled and not supported. But + if you want to help with the development of these new features we + are interested in feedback. You will have to explicitly enable them + to try them out (and they will most likely contain bugs). If you are + interested in any of these then please join the mailing-list and + follow development in CVS. + +* Cairo Gtk+ Graphics2D support, enabled by giving configure + --enable-gtk-cairo. +* QT4 AWT peers, enable by giving configure --enable-qt-peer. + +The following people helped with this release: + +Andrew John Hughes, Anthony Balkissoon, Arnaud Vandyck, Audrius +Meskauskas, Bernhard Rosenkraenzer, Bryce McKinlay, Caolan McNamara, +Carsten Neumann, Casey Marshall, Chris Burdess, Christian Thalinger, +Dalibor Topic, David Gilbert, Fridjof Siebert, Gary Benson, Ito +Kazumitsu, Jeroen Frijters, John K Peterson, John Sullivan, Keith +Seitz, Lillian Angel, Mark Wielaard, Michael Barker, Michael Koch, +Nicolas Geoffray, Olivier Jolly, Paul Jenner, Rafael H. Schloming, +Raif S. Naffah, Riccardo Mottola, Robert Schuster, Roman Kennke, +Sascha Brawer, Stephen White, Sven de Marothy, Thomas Fitzsimmons, +Tom Tromey and Wolfgang Baer. + +We would also like to thank the numerous bug reporters and testers! +</pre> +<footer> diff --git a/doc/www.gnu.org/downloads/downloads.wml b/doc/www.gnu.org/downloads/downloads.wml index e9333aea0..838783472 100644 --- a/doc/www.gnu.org/downloads/downloads.wml +++ b/doc/www.gnu.org/downloads/downloads.wml @@ -77,10 +77,10 @@ sub mylink { <download-block> <download - date="06 March 2006" - version="0.90" - url="ftp://ftp.gnu.org/gnu/classpath/classpath-0.90.tar.gz" - notes="http://www.gnu.org/software/classpath/announce/20060306.html" + date="15 May 2006" + version="0.91" + url="ftp://ftp.gnu.org/gnu/classpath/classpath-0.91.tar.gz" + notes="http://www.gnu.org/software/classpath/announce/20060515.html" > <!-- download @@ -100,6 +100,12 @@ sub mylink { <download-block> <download + date="06 March 2006" + version="0.90" + url="ftp://ftp.gnu.org/gnu/classpath/classpath-0.90.tar.gz" + notes="http://www.gnu.org/software/classpath/announce/20060306.html" +> +<download date="13 January 2006" version="0.20" url="ftp://ftp.gnu.org/gnu/classpath/classpath-0.20.tar.gz" diff --git a/doc/www.gnu.org/newsitems.txt b/doc/www.gnu.org/newsitems.txt index 64577b6f0..df0066500 100644 --- a/doc/www.gnu.org/newsitems.txt +++ b/doc/www.gnu.org/newsitems.txt @@ -1,3 +1,8 @@ +<newsitem date="15 May 2006"> +<createlink name="GNU Classpath 0.91" + url="announce/20060515.html"> +</newsitem> + <newsitem date="06 Mar 2006"> <createlink name="GNU Classpath 0.90" url="announce/20060306.html"> diff --git a/examples/gnu/classpath/examples/swing/NavigationFilterDemo.java b/examples/gnu/classpath/examples/swing/NavigationFilterDemo.java index 6c1be74cc..5184e5ba0 100644 --- a/examples/gnu/classpath/examples/swing/NavigationFilterDemo.java +++ b/examples/gnu/classpath/examples/swing/NavigationFilterDemo.java @@ -160,7 +160,7 @@ public class NavigationFilterDemo pt = text.getCaret().getMagicCaretPosition(); // Calculate its position above. - newpos = Utilities.getPositionAbove(text, pos, pt.x); + newpos = Utilities.getPositionAbove(text, pos, (pt != null) ? pt.x : 0); // If we have a valid position, then calculate the next word start // from there. @@ -173,7 +173,7 @@ public class NavigationFilterDemo pt = text.getCaret().getMagicCaretPosition(); // Calculate its position below. - newpos = Utilities.getPositionBelow(text, pos, pt.x); + newpos = Utilities.getPositionBelow(text, pos, (pt != null) ? pt.x : 0); // If we have a valid position, then calculate the next word start // from there. @@ -192,7 +192,6 @@ public class NavigationFilterDemo else return Utilities.getPreviousWord(text, newpos); case SwingConstants.EAST: - // Simply calculate the next word's start offset. return Utilities.getNextWord(text, newpos); default: // Do whatever the super implementation did. diff --git a/gnu/classpath/debug/Simple1LineFormatter.java b/gnu/classpath/debug/Simple1LineFormatter.java index 0bdf22a19..a95f8a9d2 100644 --- a/gnu/classpath/debug/Simple1LineFormatter.java +++ b/gnu/classpath/debug/Simple1LineFormatter.java @@ -91,20 +91,27 @@ public class Simple1LineFormatter extends Formatter { private static final String DAT_PATTERN = "yyyy-MM-dd HH:mm:ss.SSSS Z "; - private static final DateFormat DAT_FORMAT = new SimpleDateFormat(DAT_PATTERN); private static final String THREAD_PATTERN = " #########0;-#########0"; - private static final NumberFormat THREAD_FORMAT = new DecimalFormat(THREAD_PATTERN); private static final String SPACES_32 = " "; private static final String SPACES_6 = " "; private static final String LS = SystemProperties.getProperty("line.separator"); + private DateFormat dateFormat; + private NumberFormat threadFormat; + // default 0-arguments constructor public String format(LogRecord record) { - StringBuffer sb = new StringBuffer(180) - .append(DAT_FORMAT.format(new Date(record.getMillis()))) - .append(THREAD_FORMAT.format(record.getThreadID())) + if (dateFormat == null) + dateFormat = new SimpleDateFormat(DAT_PATTERN); + + if (threadFormat == null) + threadFormat = new DecimalFormat(THREAD_PATTERN); + + StringBuilder sb = new StringBuilder(180) + .append(dateFormat.format(new Date(record.getMillis()))) + .append(threadFormat.format(record.getThreadID())) .append(" "); String s = record.getSourceClassName(); if (s == null) diff --git a/gnu/java/awt/font/GNUGlyphVector.java b/gnu/java/awt/font/GNUGlyphVector.java index 9688698de..f17a45113 100644 --- a/gnu/java/awt/font/GNUGlyphVector.java +++ b/gnu/java/awt/font/GNUGlyphVector.java @@ -110,7 +110,7 @@ public class GNUGlyphVector fontSize = font.getSize2D(); transform = font.getTransform(); // returns a modifiable copy - transform.concatenate(renderContext.getTransform()); + //transform.concatenate(renderContext.getTransform()); } diff --git a/gnu/java/awt/java2d/AbstractGraphics2D.java b/gnu/java/awt/java2d/AbstractGraphics2D.java index c2a5ac4be..6408a264d 100644 --- a/gnu/java/awt/java2d/AbstractGraphics2D.java +++ b/gnu/java/awt/java2d/AbstractGraphics2D.java @@ -84,7 +84,48 @@ import java.util.Iterator; import java.util.Map; /** - * Implements general and shared behaviour for Graphics2D implementation. + * This is a 100% Java implementation of the Java2D rendering pipeline. It is + * meant as a base class for Graphics2D implementations. + * + * <h2>Backend interface</h2> + * <p> + * The backend must at the very least provide a Raster which the the rendering + * pipeline can paint into. This must be implemented in + * {@link #getDestinationRaster()}. For some backends that might be enough, like + * when the target surface can be directly access via the raster (like in + * BufferedImages). Other targets need some way to synchronize the raster with + * the surface, which can be achieved by implementing the + * {@link #updateRaster(Raster, int, int, int, int)} method, which always gets + * called after a chunk of data got painted into the raster. + * </p> + * <p>The backend is free to provide implementations for the various raw* + * methods for optimized AWT 1.1 style painting of some primitives. This should + * accelerate painting of Swing greatly. When doing so, the backend must also + * keep track of the clip and translation, probably by overriding + * some clip and translate methods. Don't forget to message super in such a + * case.</p> + * + * <h2>Acceleration options</h2> + * <p> + * The fact that it is + * pure Java makes it a little slow. However, there are several ways of + * accelerating the rendering pipeline: + * <ol> + * <li><em>Optimization hooks for AWT 1.1 - like graphics operations.</em> + * The most important methods from the {@link java.awt.Graphics} class + * have a corresponding <code>raw*</code> method, which get called when + * several optimization conditions are fullfilled. These conditions are + * described below. Subclasses can override these methods and delegate + * it directly to a native backend.</li> + * <li><em>Native PaintContexts and CompositeContext.</em> The implementations + * for the 3 PaintContexts and AlphaCompositeContext can be accelerated + * using native code. These have proved to two of the most performance + * critical points in the rendering pipeline and cannot really be done quickly + * in plain Java because they involve lots of shuffling around with large + * arrays. In fact, you really would want to let the graphics card to the + * work, they are made for this.</li> + * </ol> + * </p> * * @author Roman Kennke (kennke@aicas.com) */ @@ -146,11 +187,6 @@ public abstract class AbstractGraphics2D private Raster paintRaster; /** - * A cached pixel array. - */ - private int[] pixel; - - /** * The raster of the destination surface. This is where the painting is * performed. */ @@ -168,7 +204,7 @@ public abstract class AbstractGraphics2D private transient ArrayList[] edgeTable; /** - * Indicates if cerain graphics primitives can be rendered in an optimized + * Indicates if certain graphics primitives can be rendered in an optimized * fashion. This will be the case if the following conditions are met: * - The transform may only be a translation, no rotation, shearing or * scaling. @@ -198,8 +234,6 @@ public abstract class AbstractGraphics2D hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_DEFAULT); renderingHints = new RenderingHints(hints); - - pixel = new int[4]; } /** @@ -212,40 +246,211 @@ public abstract class AbstractGraphics2D { // Stroke the shape. Shape strokedShape = stroke.createStrokedShape(shape); - - // Clip the stroked shape. -// Shape clipped = clipShape(strokedShape); -// if (clipped != null) -// { -// // Fill the shape. -// fillShape(clipped, false); -// } - // FIXME: Clipping doesn't seem to work. + // Fill the stroked shape. fillShape(strokedShape, false); } - public boolean drawImage(Image image, AffineTransform xform, ImageObserver obs) + + /** + * Draws the specified image and apply the transform for image space -> + * user space conversion. + * + * This method is implemented to special case RenderableImages and + * RenderedImages and delegate to + * {@link #drawRenderableImage(RenderableImage, AffineTransform)} and + * {@link #drawRenderedImage(RenderedImage, AffineTransform)} accordingly. + * Other image types are not yet handled. + * + * @param image the image to be rendered + * @param xform the transform from image space to user space + * @param obs the image observer to be notified + */ + public boolean drawImage(Image image, AffineTransform xform, + ImageObserver obs) { - // FIXME: Implement this. - throw new UnsupportedOperationException("Not yet implemented"); + boolean ret = false; + Rectangle areaOfInterest = new Rectangle(0, 0, image.getWidth(obs), + image.getHeight(obs)); + return drawImageImpl(image, xform, obs, areaOfInterest); + } + + /** + * Draws the specified image and apply the transform for image space -> + * user space conversion. This method only draw the part of the image + * specified by <code>areaOfInterest</code>. + * + * This method is implemented to special case RenderableImages and + * RenderedImages and delegate to + * {@link #drawRenderableImage(RenderableImage, AffineTransform)} and + * {@link #drawRenderedImage(RenderedImage, AffineTransform)} accordingly. + * Other image types are not yet handled. + * + * @param image the image to be rendered + * @param xform the transform from image space to user space + * @param obs the image observer to be notified + * @param areaOfInterest the area in image space that is rendered + */ + private boolean drawImageImpl(Image image, AffineTransform xform, + ImageObserver obs, Rectangle areaOfInterest) + { + boolean ret; + if (image == null) + { + ret = true; + } + else if (image instanceof RenderedImage) + { + // FIXME: Handle the ImageObserver. + drawRenderedImageImpl((RenderedImage) image, xform, areaOfInterest); + ret = true; + } + else if (image instanceof RenderableImage) + { + // FIXME: Handle the ImageObserver. + drawRenderableImageImpl((RenderableImage) image, xform, areaOfInterest); + ret = true; + } + else + { + // FIXME: Implement rendering of other Image types. + ret = false; + } + return ret; } + /** + * Renders a BufferedImage and applies the specified BufferedImageOp before + * to filter the BufferedImage somehow. The resulting BufferedImage is then + * passed on to {@link #drawRenderedImage(RenderedImage, AffineTransform)} + * to perform the final rendering. + * + * @param image the source buffered image + * @param op the filter to apply to the buffered image before rendering + * @param x the x coordinate to render the image to + * @param y the y coordinate to render the image to + */ public void drawImage(BufferedImage image, BufferedImageOp op, int x, int y) { - // FIXME: Implement this. - throw new UnsupportedOperationException("Not yet implemented"); + BufferedImage filtered = + op.createCompatibleDestImage(image, image.getColorModel()); + AffineTransform t = new AffineTransform(); + t.translate(x, y); + drawRenderedImage(filtered, t); } + /** + * Renders the specified image to the destination raster. The specified + * transform is used to convert the image into user space. The transform + * of this AbstractGraphics2D object is used to transform from user space + * to device space. + * + * The rendering is performed using the scanline algorithm that performs the + * rendering of other shapes and a custom Paint implementation, that supplies + * the pixel values of the rendered image. + * + * @param image the image to render to the destination raster + * @param xform the transform from image space to user space + */ public void drawRenderedImage(RenderedImage image, AffineTransform xform) { - // FIXME: Implement this. - throw new UnsupportedOperationException("Not yet implemented"); + Rectangle areaOfInterest = new Rectangle(image.getMinX(), + image.getHeight(), + image.getWidth(), + image.getHeight()); + drawRenderedImageImpl(image, xform, areaOfInterest); + } + + /** + * Renders the specified image to the destination raster. The specified + * transform is used to convert the image into user space. The transform + * of this AbstractGraphics2D object is used to transform from user space + * to device space. Only the area specified by <code>areaOfInterest</code> + * is finally rendered to the target. + * + * The rendering is performed using the scanline algorithm that performs the + * rendering of other shapes and a custom Paint implementation, that supplies + * the pixel values of the rendered image. + * + * @param image the image to render to the destination raster + * @param xform the transform from image space to user space + */ + private void drawRenderedImageImpl(RenderedImage image, + AffineTransform xform, + Rectangle areaOfInterest) + { + // First we compute the transformation. This is made up of 3 parts: + // 1. The areaOfInterest -> image space transform. + // 2. The image space -> user space transform. + // 3. The user space -> device space transform. + AffineTransform t = new AffineTransform(); + t.translate(- areaOfInterest.x - image.getMinX(), + - areaOfInterest.y - image.getMinY()); + t.concatenate(xform); + t.concatenate(transform); + AffineTransform it = null; + try + { + it = t.createInverse(); + } + catch (NoninvertibleTransformException ex) + { + // Ignore -- we return if the transform is not invertible. + } + if (it != null) + { + // Transform the area of interest into user space. + GeneralPath aoi = new GeneralPath(areaOfInterest); + aoi.transform(xform); + // Render the shape using the standard renderer, but with a temporary + // ImagePaint. + ImagePaint p = new ImagePaint(image, it); + Paint savedPaint = paint; + try + { + paint = p; + fillShape(aoi, false); + } + finally + { + paint = savedPaint; + } + } } + /** + * Renders a renderable image. This produces a RenderedImage, which is + * then passed to {@link #drawRenderedImage(RenderedImage, AffineTransform)} + * to perform the final rendering. + * + * @param image the renderable image to be rendered + * @param xform the transform from image space to user space + */ public void drawRenderableImage(RenderableImage image, AffineTransform xform) { - // FIXME: Implement this. - throw new UnsupportedOperationException("Not yet implemented"); + Rectangle areaOfInterest = new Rectangle((int) image.getMinX(), + (int) image.getHeight(), + (int) image.getWidth(), + (int) image.getHeight()); + drawRenderableImageImpl(image, xform, areaOfInterest); + + } + + /** + * Renders a renderable image. This produces a RenderedImage, which is + * then passed to {@link #drawRenderedImage(RenderedImage, AffineTransform)} + * to perform the final rendering. Only the area of the image specified + * by <code>areaOfInterest</code> is rendered. + * + * @param image the renderable image to be rendered + * @param xform the transform from image space to user space + */ + private void drawRenderableImageImpl(RenderableImage image, + AffineTransform xform, + Rectangle areaOfInterest) + { + // TODO: Maybe make more clever usage of a RenderContext here. + RenderedImage rendered = image.createDefaultRendering(); + drawRenderedImageImpl(rendered, xform, areaOfInterest); } /** @@ -257,9 +462,14 @@ public abstract class AbstractGraphics2D */ public void drawString(String text, int x, int y) { - FontRenderContext ctx = getFontRenderContext(); - GlyphVector gv = font.createGlyphVector(ctx, text.toCharArray()); - drawGlyphVector(gv, x, y); + if (isOptimized) + rawDrawString(text, x, y); + else + { + FontRenderContext ctx = getFontRenderContext(); + GlyphVector gv = font.createGlyphVector(ctx, text.toCharArray()); + drawGlyphVector(gv, x, y); + } } /** @@ -313,9 +523,6 @@ public abstract class AbstractGraphics2D */ public void fill(Shape shape) { -// Shape clipped = clipShape(shape); -// if (clipped != null) -// fillShape(clipped, false); fillShape(shape, false); } @@ -355,7 +562,6 @@ public abstract class AbstractGraphics2D else { updateOptimization(); - rawSetForeground((Color) paint); } } } @@ -537,7 +743,7 @@ public abstract class AbstractGraphics2D if (clip != null) { AffineTransform clipTransform = new AffineTransform(); - clipTransform.scale(-scaleX, -scaleY); + clipTransform.scale(1 / scaleX, 1 / scaleY); updateClip(clipTransform); } updateOptimization(); @@ -712,8 +918,7 @@ public abstract class AbstractGraphics2D public FontRenderContext getFontRenderContext() { - //return new FontRenderContext(transform, false, false); - return new FontRenderContext(new AffineTransform(), false, false); + return new FontRenderContext(transform, false, true); } /** @@ -726,22 +931,15 @@ public abstract class AbstractGraphics2D public void drawGlyphVector(GlyphVector gv, float x, float y) { int numGlyphs = gv.getNumGlyphs(); - AffineTransform t = new AffineTransform(); - t.translate(x, y); - -// // TODO: We could use fill(gv.getOutline()), but that seems to be - // slightly more inefficient. + translate(x, y); + // TODO: We could use fill(gv.getOutline()), but that seems to be + // slightly more inefficient. for (int i = 0; i < numGlyphs; i++) { - //fill(gv.getGlyphVisualBounds(i)); - GeneralPath p = new GeneralPath(gv.getGlyphOutline(i)); - p.transform(t); - //Shape clipped = clipShape(p); - //if (clipped != null) - // fillShape(clipped, true); - // FIXME: Clipping doesn't seem to work correctly. - fillShape(p, true); + Shape o = gv.getGlyphOutline(i); + fillShape(o, true); } + translate(-x, -y); } /** @@ -919,8 +1117,10 @@ public abstract class AbstractGraphics2D public void copyArea(int x, int y, int width, int height, int dx, int dy) { - // FIXME: Implement this. - throw new UnsupportedOperationException("Not yet implemented"); + if (isOptimized) + rawCopyArea(x, y, width, height, dx, dy); + else + copyAreaImpl(x, y, width, height, dx, dy); } /** @@ -979,11 +1179,15 @@ public abstract class AbstractGraphics2D */ public void clearRect(int x, int y, int width, int height) { - Paint savedForeground = getPaint(); - setPaint(getBackground()); - //System.err.println("clearRect transform type: " + transform.getType()); - fillRect(x, y, width, height); - setPaint(savedForeground); + if (isOptimized) + rawClearRect(x, y, width, height); + else + { + Paint savedForeground = getPaint(); + setPaint(getBackground()); + fillRect(x, y, width, height); + setPaint(savedForeground); + } } /** @@ -1088,47 +1292,153 @@ public abstract class AbstractGraphics2D fill(new Polygon(xPoints, yPoints, npoints)); } + /** + * Draws the specified image at the specified location. This forwards + * to {@link #drawImage(Image, AffineTransform, ImageObserver)}. + * + * @param image the image to render + * @param x the x location to render to + * @param y the y location to render to + * @param observer the image observer to receive notification + */ public boolean drawImage(Image image, int x, int y, ImageObserver observer) { - // FIXME: Implement this. - throw new UnsupportedOperationException("Not yet implemented"); + boolean ret; + if (isOptimized) + ret = rawDrawImage(image, x, y, observer); + else + { + AffineTransform t = new AffineTransform(); + t.translate(x, y); + ret = drawImage(image, t, observer); + } + return ret; } + /** + * Draws the specified image at the specified location. The image + * is scaled to the specified width and height. This forwards + * to {@link #drawImage(Image, AffineTransform, ImageObserver)}. + * + * @param image the image to render + * @param x the x location to render to + * @param y the y location to render to + * @param width the target width of the image + * @param height the target height of the image + * @param observer the image observer to receive notification + */ public boolean drawImage(Image image, int x, int y, int width, int height, ImageObserver observer) { - // FIXME: Implement this. - throw new UnsupportedOperationException("Not yet implemented"); + AffineTransform t = new AffineTransform(); + t.translate(x, y); + double scaleX = (double) image.getWidth(observer) / (double) width; + double scaleY = (double) image.getHeight(observer) / (double) height; + t.scale(scaleX, scaleY); + return drawImage(image, t, observer); } + /** + * Draws the specified image at the specified location. This forwards + * to {@link #drawImage(Image, AffineTransform, ImageObserver)}. + * + * @param image the image to render + * @param x the x location to render to + * @param y the y location to render to + * @param bgcolor the background color to use for transparent pixels + * @param observer the image observer to receive notification + */ public boolean drawImage(Image image, int x, int y, Color bgcolor, ImageObserver observer) { - // FIXME: Implement this. - throw new UnsupportedOperationException("Not yet implemented"); + AffineTransform t = new AffineTransform(); + t.translate(x, y); + // TODO: Somehow implement the background option. + return drawImage(image, t, observer); } + /** + * Draws the specified image at the specified location. The image + * is scaled to the specified width and height. This forwards + * to {@link #drawImage(Image, AffineTransform, ImageObserver)}. + * + * @param image the image to render + * @param x the x location to render to + * @param y the y location to render to + * @param width the target width of the image + * @param height the target height of the image + * @param bgcolor the background color to use for transparent pixels + * @param observer the image observer to receive notification + */ public boolean drawImage(Image image, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) { - // FIXME: Implement this. - throw new UnsupportedOperationException("Not yet implemented"); + AffineTransform t = new AffineTransform(); + t.translate(x, y); + double scaleX = (double) image.getWidth(observer) / (double) width; + double scaleY = (double) image.getHeight(observer) / (double) height; + t.scale(scaleX, scaleY); + // TODO: Somehow implement the background option. + return drawImage(image, t, observer); } + /** + * Draws an image fragment to a rectangular area of the target. + * + * @param image the image to render + * @param dx1 the first corner of the destination rectangle + * @param dy1 the first corner of the destination rectangle + * @param dx2 the second corner of the destination rectangle + * @param dy2 the second corner of the destination rectangle + * @param sx1 the first corner of the source rectangle + * @param sy1 the first corner of the source rectangle + * @param sx2 the second corner of the source rectangle + * @param sy2 the second corner of the source rectangle + * @param observer the image observer to be notified + */ public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) { - // FIXME: Implement this. - throw new UnsupportedOperationException("Not yet implemented"); + int sx = Math.min(sx1, sx1); + int sy = Math.min(sy1, sy2); + int sw = Math.abs(sx1 - sx2); + int sh = Math.abs(sy1 - sy2); + int dx = Math.min(dx1, dx1); + int dy = Math.min(dy1, dy2); + int dw = Math.abs(dx1 - dx2); + int dh = Math.abs(dy1 - dy2); + + AffineTransform t = new AffineTransform(); + t.translate(sx - dx, sy - dy); + double scaleX = (double) sw / (double) dw; + double scaleY = (double) sh / (double) dh; + t.scale(scaleX, scaleY); + Rectangle areaOfInterest = new Rectangle(sx, sy, sw, sh); + return drawImageImpl(image, t, observer, areaOfInterest); } + /** + * Draws an image fragment to a rectangular area of the target. + * + * @param image the image to render + * @param dx1 the first corner of the destination rectangle + * @param dy1 the first corner of the destination rectangle + * @param dx2 the second corner of the destination rectangle + * @param dy2 the second corner of the destination rectangle + * @param sx1 the first corner of the source rectangle + * @param sy1 the first corner of the source rectangle + * @param sx2 the second corner of the source rectangle + * @param sy2 the second corner of the source rectangle + * @param bgcolor the background color to use for transparent pixels + * @param observer the image observer to be notified + */ public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer) { - // FIXME: Implement this. - throw new UnsupportedOperationException("Not yet implemented"); + // FIXME: Do something with bgcolor. + return drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer); } /** @@ -1155,8 +1465,8 @@ public abstract class AbstractGraphics2D Object v = renderingHints.get(RenderingHints.KEY_TEXT_ANTIALIASING); // We default to antialiasing on for text as long as we have no // good hinting implemented. - antialias = (v == RenderingHints.VALUE_TEXT_ANTIALIAS_ON - || v == RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT); + antialias = (v == RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + //|| v == RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT); } else { @@ -1164,237 +1474,150 @@ public abstract class AbstractGraphics2D antialias = (v == RenderingHints.VALUE_ANTIALIAS_ON); } - Rectangle2D userBounds = s.getBounds2D(); - - // Flatten the path. TODO: Determine the best flattening factor - // wrt to speed and quality. - PathIterator path = s.getPathIterator(getTransform(), 1.0); - - // Build up polygons and let the native backend render this using - // rawFillShape() which would provide a default implementation for - // drawPixel using a PolyScan algorithm. - double[] seg = new double[6]; - - // TODO: Use ArrayList<PolyEdge> here when availble. - ArrayList segs = new ArrayList(); - double segX = 0.; // The start point of the current edge. - double segY = 0.; - double polyX = 0.; // The start point of the current polygon. - double polyY = 0.; - - double minX = Integer.MAX_VALUE; - double maxX = Integer.MIN_VALUE; - double minY = Integer.MAX_VALUE; - double maxY = Integer.MIN_VALUE; + double offs = 0.5; + if (antialias) + offs = offs / AA_SAMPLING; - //System.err.println("fill polygon"); - while (! path.isDone()) - { - int segType = path.currentSegment(seg); - minX = Math.min(minX, seg[0]); - maxX = Math.max(maxX, seg[0]); - minY = Math.min(minY, seg[1]); - maxY = Math.max(maxY, seg[1]); - - //System.err.println("segment: " + segType + ", " + seg[0] + ", " + seg[1]); - if (segType == PathIterator.SEG_MOVETO) - { - segX = seg[0]; - segY = seg[1]; - polyX = seg[0]; - polyY = seg[1]; - } - else if (segType == PathIterator.SEG_CLOSE) - { - // Close the polyline. - PolyEdge edge = new PolyEdge(segX, segY, polyX, polyY); - segs.add(edge); - } - else if (segType == PathIterator.SEG_LINETO) - { - PolyEdge edge = new PolyEdge(segX, segY, seg[0], seg[1]); - segs.add(edge); - segX = seg[0]; - segY = seg[1]; - } - path.next(); - } + Rectangle2D userBounds = s.getBounds2D(); + Rectangle2D deviceBounds = new Rectangle2D.Double(); + ArrayList segs = getSegments(s, transform, deviceBounds, false, offs); + Rectangle2D clipBounds = new Rectangle2D.Double(); + ArrayList clipSegs = getSegments(clip, transform, clipBounds, true, offs); + segs.addAll(clipSegs); + Rectangle2D inclClipBounds = new Rectangle2D.Double(); + Rectangle2D.union(clipBounds, deviceBounds, inclClipBounds); if (segs.size() > 0) { if (antialias) - fillShapeAntialias(segs, minX, minY, maxX, maxY, userBounds); + fillShapeAntialias(segs, deviceBounds, userBounds, inclClipBounds); else - rawFillShape(segs, minX, minY, maxX, maxY, userBounds); + fillShapeImpl(segs, deviceBounds, userBounds, inclClipBounds); } } /** - * Draws one pixel in the target coordinate space. This method draws the - * specified pixel by getting the painting pixel for that coordinate - * from the paintContext and compositing the pixel with the compositeContext. - * The resulting pixel is then set by calling {@link #rawSetPixel}. + * Returns the color model of this Graphics object. * - * @param x the x coordinate - * @param y the y coordinate + * @return the color model of this Graphics object */ - protected void drawPixel(int x, int y) - { - // FIXME: Implement efficient compositing. - if (! (paint instanceof Color)) - { - int[] paintPixel = paintRaster.getPixel(x, y, pixel); - Color c = new Color(paintPixel[0], paintPixel[1], paintPixel[2]); - rawSetForeground(c); - } - rawSetPixel(x, y); - } + protected abstract ColorModel getColorModel(); /** - * Draws a pixel in the target coordinate space using the specified color. - * - * @param x the x coordinate - * @param y the y coordinate + * Returns the bounds of the target. + * + * @return the bounds of the target */ - protected void rawSetPixel(int x, int y) + protected Rectangle getDeviceBounds() { - // FIXME: Provide default implementation or remove method. + return destinationRaster.getBounds(); } /** - * Sets the foreground color for drawing. + * Draws a line in optimization mode. The implementation should respect the + * clip and translation. It can assume that the clip is a rectangle and that + * the transform is only a translating transform. * - * @param c the color to set + * @param x0 the starting point, X coordinate + * @param y0 the starting point, Y coordinate + * @param x1 the end point, X coordinate + * @param y1 the end point, Y coordinate */ - protected void rawSetForeground(Color c) - { - // Probably remove method. - } - - protected void rawSetForeground(int r, int g, int b) + protected void rawDrawLine(int x0, int y0, int x1, int y1) { - rawSetForeground(new Color(r, g, b)); + draw(new Line2D.Float(x0, y0, x1, y1)); } /** - * Returns the color model of this Graphics object. + * Draws a string in optimization mode. The implementation should respect the + * clip and translation. It can assume that the clip is a rectangle and that + * the transform is only a translating transform. * - * @return the color model of this Graphics object + * @param text the string to be drawn + * @param x the start of the baseline, X coordinate + * @param y the start of the baseline, Y coordinate */ - protected abstract ColorModel getColorModel(); + protected void rawDrawString(String text, int x, int y) + { + FontRenderContext ctx = getFontRenderContext(); + GlyphVector gv = font.createGlyphVector(ctx, text.toCharArray()); + drawGlyphVector(gv, x, y); + } /** - * Returns the bounds of the target. + * Clears a rectangle in optimization mode. The implementation should respect the + * clip and translation. It can assume that the clip is a rectangle and that + * the transform is only a translating transform. * - * @return the bounds of the target + * @param x the upper left corner, X coordinate + * @param y the upper left corner, Y coordinate + * @param w the width + * @param h the height */ - protected Rectangle getDeviceBounds() + protected void rawClearRect(int x, int y, int w, int h) { - return destinationRaster.getBounds(); + Paint savedForeground = getPaint(); + setPaint(getBackground()); + rawFillRect(x, y, w, h); + setPaint(savedForeground); } /** - * Returns the bounds of the drawing area in user space. + * Fills a rectangle in optimization mode. The implementation should respect + * the clip but can assume that it is a rectangle. * - * @return the bounds of the drawing area in user space + * @param x the upper left corner, X coordinate + * @param y the upper left corner, Y coordinate + * @param w the width + * @param h the height */ - protected Rectangle2D getUserBounds() + protected void rawFillRect(int x, int y, int w, int h) { - PathIterator pathIter = getDeviceBounds().getPathIterator(getTransform()); - GeneralPath path = new GeneralPath(); - path.append(pathIter, true); - return path.getBounds(); - + fill(new Rectangle(x, y, w, h)); } + /** - * Draws a line in optimization mode. The implementation should respect the - * clip but can assume that it is a rectangle. + * Draws an image in optimization mode. The implementation should respect + * the clip but can assume that it is a rectangle. * - * @param x0 the starting point, X coordinate - * @param y0 the starting point, Y coordinate - * @param x1 the end point, X coordinate - * @param y1 the end point, Y coordinate + * @param image the image to be painted + * @param x the location, X coordinate + * @param y the location, Y coordinate + * @param obs the image observer to be notified + * + * @return <code>true</code> when the image is painted completely, + * <code>false</code> if it is still rendered */ - protected void rawDrawLine(int x0, int y0, int x1, int y1) + protected boolean rawDrawImage(Image image, int x, int y, ImageObserver obs) { - // This is an implementation of Bresenham's line drawing algorithm. - int dy = y1 - y0; - int dx = x1 - x0; - int stepx, stepy; - - if (dy < 0) - { - dy = -dy; - stepy = -1; - } - else - { - stepy = 1; - } - if (dx < 0) - { - dx = -dx; - stepx = -1; - } - else - { - stepx = 1; - } - dy <<= 1; - dx <<= 1; - - drawPixel(x0, y0); - if (dx > dy) - { - int fraction = dy - (dx >> 1); // same as 2*dy - dx - while (x0 != x1) - { - if (fraction >= 0) - { - y0 += stepy; - fraction -= dx; - } - x0 += stepx; - fraction += dy; - drawPixel(x0, y0); - } - } - else - { - int fraction = dx - (dy >> 1); - while (y0 != y1) - { - if (fraction >= 0) - { - x0 += stepx; - fraction -= dy; - } - y0 += stepy; - fraction += dx; - drawPixel(x0, y0); - } - } + AffineTransform t = new AffineTransform(); + t.translate(x, y); + return drawImage(image, t, obs); } /** - * Fills a rectangle in optimization mode. The implementation should respect - * the clip but can assume that it is a rectangle. + * Copies a rectangular region to another location. * * @param x the upper left corner, X coordinate * @param y the upper left corner, Y coordinate * @param w the width * @param h the height + * @param dx + * @param dy */ - protected void rawFillRect(int x, int y, int w, int h) + protected void rawCopyArea(int x, int y, int w, int h, int dx, int dy) { - int x2 = x + w; - int y2 = y + h; - for (int xc = x; xc < x2; xc++) - { - for (int yc = y; yc < y2; yc++) - { - drawPixel(xc, yc); - } - } + copyAreaImpl(x, y, w, h, dx, dy); + } + + // Private implementation methods. + + /** + * Copies a rectangular area of the target raster to a different location. + */ + private void copyAreaImpl(int x, int y, int w, int h, int dx, int dy) + { + // FIXME: Implement this properly. + throw new UnsupportedOperationException("Not implemented yet."); } /** @@ -1404,8 +1627,9 @@ public abstract class AbstractGraphics2D * * The polygon is already clipped when this method is called. */ - protected void rawFillShape(ArrayList segs, double minX, double minY, - double maxX, double maxY, Rectangle2D userBounds) + private void fillShapeImpl(ArrayList segs, Rectangle2D deviceBounds2D, + Rectangle2D userBounds, + Rectangle2D inclClipBounds) { // This is an implementation of a polygon scanline conversion algorithm // described here: @@ -1414,19 +1638,25 @@ public abstract class AbstractGraphics2D // Create table of all edges. // The edge buckets, sorted and indexed by their Y values. + double minX = deviceBounds2D.getMinX(); + double minY = deviceBounds2D.getMinY(); + double maxX = deviceBounds2D.getMaxX(); + double maxY = deviceBounds2D.getMaxY(); + double icMinY = inclClipBounds.getMinY(); + double icMaxY = inclClipBounds.getMaxY(); Rectangle deviceBounds = new Rectangle((int) minX, (int) minY, (int) Math.ceil(maxX) - (int) minX, (int) Math.ceil(maxY) - (int) minY); PaintContext pCtx = paint.createContext(getColorModel(), deviceBounds, userBounds, transform, renderingHints); - ArrayList[] edgeTable = new ArrayList[(int) Math.ceil(maxY) - - (int) Math.ceil(minY) + 1]; + ArrayList[] edgeTable = new ArrayList[(int) Math.ceil(icMaxY) + - (int) Math.ceil(icMinY) + 1]; for (Iterator i = segs.iterator(); i.hasNext();) { PolyEdge edge = (PolyEdge) i.next(); - int yindex = (int) ((int) Math.ceil(edge.y0) - (int) Math.ceil(minY)); + int yindex = (int) ((int) Math.ceil(edge.y0) - (int) Math.ceil(icMinY)); if (edgeTable[yindex] == null) // Create bucket when needed. edgeTable[yindex] = new ArrayList(); edgeTable[yindex].add(edge); // Add edge to the bucket of its line. @@ -1446,7 +1676,7 @@ public abstract class AbstractGraphics2D PolyEdgeComparator comparator = new PolyEdgeComparator(); // Scan all relevant lines. - int minYInt = (int) Math.ceil(minY); + int minYInt = (int) Math.ceil(icMinY); for (int y = minYInt; y <= maxY; y++) { ArrayList bucket = edgeTable[y - minYInt]; @@ -1497,35 +1727,30 @@ public abstract class AbstractGraphics2D // Now draw all pixels inside the polygon. // This is the last edge that intersected the scanline. PolyEdge previous = null; // Gets initialized below. - boolean active = false; + boolean insideShape = false; + boolean insideClip = false; //System.err.println("scanline: " + y); for (Iterator i = activeEdges.iterator(); i.hasNext();) { PolyEdge edge = (PolyEdge) i.next(); - // Only fill scanline, if the current edge actually intersects - // the scanline. There may be edges that lie completely - // within the current scanline. - //System.err.println("previous: " + previous); - //System.err.println("edge: " + edge); - if (active) + if (edge.y1 <= y) + continue; + + // Draw scanline when we are inside the shape AND inside the + // clip. + if (insideClip && insideShape) { - if (edge.y1 > y) - { - int x0 = (int) previous.xIntersection; - int x1 = (int) edge.xIntersection; - fillScanline(pCtx, x0, x1, y); - previous = edge; - active = false; - } + int x0 = (int) previous.xIntersection; + int x1 = (int) edge.xIntersection; + if (x0 < x1) + fillScanline(pCtx, x0, x1, y); } + // Update state. + previous = edge; + if (edge.isClip) + insideClip = ! insideClip; else - { - if (edge.y1 > y) - { - previous = edge; - active = true; - } - } + insideShape = ! insideShape; } } pCtx.dispose(); @@ -1545,7 +1770,8 @@ public abstract class AbstractGraphics2D CompositeContext cCtx = composite.createContext(paintColorModel, getColorModel(), renderingHints); - cCtx.compose(paintRaster, destinationRaster, destinationRaster); + WritableRaster targetChild = destinationRaster.createWritableTranslatedChild(-x0,- y); + cCtx.compose(paintRaster, targetChild, targetChild); updateRaster(destinationRaster, x0, y, x1 - x0, 1); cCtx.dispose(); } @@ -1554,14 +1780,10 @@ public abstract class AbstractGraphics2D * Fills arbitrary shapes in an anti-aliased fashion. * * @param segs the line segments which define the shape which is to be filled - * @param minX the bounding box, left X - * @param minY the bounding box, upper Y - * @param maxX the bounding box, right X - * @param maxY the bounding box, lower Y */ - private void fillShapeAntialias(ArrayList segs, double minX, double minY, - double maxX, double maxY, - Rectangle2D userBounds) + private void fillShapeAntialias(ArrayList segs, Rectangle2D deviceBounds2D, + Rectangle2D userBounds, + Rectangle2D inclClipBounds) { // This is an implementation of a polygon scanline conversion algorithm // described here: @@ -1569,23 +1791,32 @@ public abstract class AbstractGraphics2D // The antialiasing is implemented using a sampling technique, we do // not scan whole lines but fractions of the line. + double minX = deviceBounds2D.getMinX(); + double minY = deviceBounds2D.getMinY(); + double maxX = deviceBounds2D.getMaxX(); + double maxY = deviceBounds2D.getMaxY(); + double icMinY = inclClipBounds.getMinY(); + double icMaxY = inclClipBounds.getMaxY(); + double icMinX = inclClipBounds.getMinX(); + double icMaxX = inclClipBounds.getMaxX(); Rectangle deviceBounds = new Rectangle((int) minX, (int) minY, (int) Math.ceil(maxX) - (int) minX, (int) Math.ceil(maxY) - (int) minY); - PaintContext pCtx = paint.createContext(getColorModel(), deviceBounds, + PaintContext pCtx = paint.createContext(ColorModel.getRGBdefault(), + deviceBounds, userBounds, transform, renderingHints); // This array will contain the oversampled transparency values for // each pixel in the scanline. - int numScanlines = (int) Math.ceil(maxY) - (int) minY; - int numScanlinePixels = (int) Math.ceil(maxX) - (int) minX + 1; + int numScanlines = (int) Math.ceil(icMaxY) - (int) icMinY; + int numScanlinePixels = (int) Math.ceil(icMaxX) - (int) icMinX + 1; if (alpha == null || alpha.length < (numScanlinePixels + 1)) alpha = new int[numScanlinePixels + 1]; - int firstLine = (int) minY; + int firstLine = (int) icMinY; //System.err.println("minY: " + minY); - int firstSubline = (int) (Math.ceil((minY - Math.floor(minY)) * AA_SAMPLING)); + int firstSubline = (int) (Math.ceil((icMinY - Math.floor(icMinY)) * AA_SAMPLING)); double firstLineDouble = firstLine + firstSubline / (double) AA_SAMPLING; //System.err.println("firstSubline: " + firstSubline); @@ -1630,8 +1861,11 @@ public abstract class AbstractGraphics2D // Scan all lines. int yindex = 0; //System.err.println("firstLine: " + firstLine + ", maxY: " + maxY + ", firstSubline: " + firstSubline); - for (int y = firstLine; y <= maxY; y++) + for (int y = firstLine; y <= icMaxY; y++) { + int leftX = (int) icMaxX; + int rightX = (int) icMinX; + boolean emptyScanline = true; for (int subY = firstSubline; subY < AA_SAMPLING; subY++) { //System.err.println("scanline: " + y + ", subScanline: " + subY); @@ -1688,17 +1922,16 @@ public abstract class AbstractGraphics2D // Now draw all pixels inside the polygon. // This is the last edge that intersected the scanline. PolyEdge previous = null; // Gets initialized below. - boolean active = false; + boolean insideClip = false; + boolean insideShape = false; //System.err.println("scanline: " + y + ", subscanline: " + subY); for (Iterator i = activeEdges.iterator(); i.hasNext();) { PolyEdge edge = (PolyEdge) i.next(); - // Only fill scanline, if the current edge actually intersects - // the scanline. There may be edges that lie completely - // within the current scanline. - //System.err.println("previous: " + previous); - //System.err.println("edge: " + edge); - if (active) + if (edge.y1 <= (y + (subY / (double) AA_SAMPLING))) + continue; + + if (insideClip && insideShape) { // TODO: Use integer arithmetics here. if (edge.y1 > (y + (subY / (double) AA_SAMPLING))) @@ -1709,32 +1942,30 @@ public abstract class AbstractGraphics2D int x1 = (int) Math.min(Math.max(edge.xIntersection, minX), maxX); //System.err.println("minX: " + minX + ", x0: " + x0 + ", x1: " + x1 + ", maxX: " + maxX); // TODO: Pull out cast. - alpha[x0 - (int) minX]++; - alpha[x1 - (int) minX + 1]--; - previous = edge; - active = false; + int left = x0 - (int) minX; + int right = x1 - (int) minX + 1; + alpha[left]++; + alpha[right]--; + leftX = Math.min(x0, leftX); + rightX = Math.max(x1+2, rightX); + emptyScanline = false; } } + previous = edge; + if (edge.isClip) + insideClip = ! insideClip; else - { - // TODO: Use integer arithmetics here. - if (edge.y1 > (y + (subY / (double) AA_SAMPLING))) - { - //System.err.println(edge); - previous = edge; - active = true; - } - } + insideShape = ! insideShape; } yindex++; } firstSubline = 0; // Render full scanline. //System.err.println("scanline: " + y); - fillScanlineAA(alpha, (int) minX, (int) y, numScanlinePixels, pCtx); + if (! emptyScanline) + fillScanlineAA(alpha, leftX, (int) y, rightX - leftX, pCtx, + (int) minX); } - if (paint instanceof Color && composite == AlphaComposite.SrcOver) - rawSetForeground((Color) paint); pCtx.dispose(); } @@ -1748,40 +1979,54 @@ public abstract class AbstractGraphics2D * @param x0 the beginning of the scanline * @param y the y coordinate of the line */ - private void fillScanlineAA(int[] alpha, int x0, int y, int numScanlinePixels, - PaintContext pCtx) + private void fillScanlineAA(int[] alpha, int x0, int yy, int numPixels, + PaintContext pCtx, int offs) { - // FIXME: This doesn't work. Fixit. CompositeContext cCtx = composite.createContext(pCtx.getColorModel(), getColorModel(), renderingHints); - Raster paintRaster = pCtx.getRaster(x0, y, numScanlinePixels, 1); - System.err.println("paintColorModel: " + pCtx.getColorModel()); + Raster paintRaster = pCtx.getRaster(x0, yy, numPixels, 1); + //System.err.println("paintColorModel: " + pCtx.getColorModel()); WritableRaster aaRaster = paintRaster.createCompatibleWritableRaster(); int numBands = paintRaster.getNumBands(); - int[] pixels = new int[numScanlinePixels + paintRaster.getNumBands()]; - pixels = paintRaster.getPixels(x0, y, numScanlinePixels, 1, pixels); ColorModel cm = pCtx.getColorModel(); - double lastAlpha = 0.; int lastAlphaInt = 0; - int[] components = new int[4]; - - for (int i = 0; i < pixels.length; i++) + + Object pixel = null; + int[] comps = null; + int x1 = x0 + numPixels; + for (int x = x0; x < x1; x++) { + int i = x - offs; if (alpha[i] != 0) { lastAlphaInt += alpha[i]; - lastAlpha = lastAlphaInt / AA_SAMPLING; + lastAlpha = (double) lastAlphaInt / (double) AA_SAMPLING; + alpha[i] = 0; } - components = cm.getComponents(pixel[i], components, 0); - components[0] = (int) (components[0] * lastAlpha); - pixel[i] = cm.getDataElement(components, 0); + pixel = paintRaster.getDataElements(x - x0, 0, pixel); + comps = cm.getComponents(pixel, comps, 0); + if (cm.hasAlpha() && ! cm.isAlphaPremultiplied()) + comps[comps.length - 1] *= lastAlpha; + else + { + int max; + if (cm.hasAlpha()) + max = comps.length - 2; + else + max = comps.length - 1; + for (int j = 0; j < max; j++) + comps[j] *= lastAlpha; + } + pixel = cm.getDataElements(comps, 0, pixel); + aaRaster.setDataElements(x - x0, 0, pixel); } - aaRaster.setPixels(0, 0, numScanlinePixels, 1, pixels); - cCtx.compose(aaRaster, destinationRaster, destinationRaster); - updateRaster(destinationRaster, x0, y, numScanlinePixels, 1); + WritableRaster targetChild = + destinationRaster.createWritableTranslatedChild(-x0, -yy); + cCtx.compose(aaRaster, targetChild, targetChild); + updateRaster(destinationRaster, x0, yy, numPixels, 1); cCtx.dispose(); } @@ -1799,8 +2044,8 @@ public abstract class AbstractGraphics2D // FIXME: Should not be necessary. A clip of null should mean // 'clip against device bounds. - clip = getDeviceBounds(); destinationRaster = getDestinationRaster(); + clip = getDeviceBounds(); } /** @@ -1913,40 +2158,77 @@ public abstract class AbstractGraphics2D } /** - * Clips the specified shape using the current clip. If the resulting shape - * is empty, this will return <code>null</code>. + * Converts the specified shape into a list of segments. * - * @param s the shape to clip + * @param s the shape to convert + * @param t the transformation to apply before converting + * @param deviceBounds an output parameter; holds the bounding rectangle of + * s in device space after return + * @param isClip true when the shape is a clip, false for normal shapes; + * this influences the settings in the created PolyEdge instances. * - * @return the clipped shape or <code>null</code> if the result is empty + * @return a list of PolyEdge that form the shape in device space */ - private Shape clipShape(Shape s) + private ArrayList getSegments(Shape s, AffineTransform t, + Rectangle2D deviceBounds, boolean isClip, + double offs) { - Shape clipped = null; + // Flatten the path. TODO: Determine the best flattening factor + // wrt to speed and quality. + PathIterator path = s.getPathIterator(getTransform(), 1.0); - // Clip the shape if necessary. - if (clip != null) - { - Area a; - if (! (s instanceof Area)) - a = new Area(s); - else - a = (Area) s; + // Build up polygons and let the native backend render this using + // rawFillShape() which would provide a default implementation for + // drawPixel using a PolyScan algorithm. + double[] seg = new double[6]; - Area clipArea; - if (! (clip instanceof Area)) - clipArea = new Area(clip); - else - clipArea = (Area) clip; + // TODO: Use ArrayList<PolyEdge> here when availble. + ArrayList segs = new ArrayList(); + double segX = 0.; // The start point of the current edge. + double segY = 0.; + double polyX = 0.; // The start point of the current polygon. + double polyY = 0.; - a.intersect(clipArea); - if (! a.isEmpty()) - clipped = a; - } - else + double minX = Integer.MAX_VALUE; + double maxX = Integer.MIN_VALUE; + double minY = Integer.MAX_VALUE; + double maxY = Integer.MIN_VALUE; + + //System.err.println("fill polygon"); + while (! path.isDone()) { - clipped = s; + int segType = path.currentSegment(seg); + minX = Math.min(minX, seg[0]); + maxX = Math.max(maxX, seg[0]); + minY = Math.min(minY, seg[1]); + maxY = Math.max(maxY, seg[1]); + + //System.err.println("segment: " + segType + ", " + seg[0] + ", " + seg[1]); + if (segType == PathIterator.SEG_MOVETO) + { + segX = seg[0]; + segY = seg[1]; + polyX = seg[0]; + polyY = seg[1]; + } + else if (segType == PathIterator.SEG_CLOSE) + { + // Close the polyline. + PolyEdge edge = new PolyEdge(segX, segY - offs, + polyX, polyY - offs, isClip); + segs.add(edge); + } + else if (segType == PathIterator.SEG_LINETO) + { + PolyEdge edge = new PolyEdge(segX, segY - offs, + seg[0], seg[1] - offs, isClip); + segs.add(edge); + segX = seg[0]; + segY = seg[1]; + } + path.next(); } - return clipped; + deviceBounds.setRect(minX, minY, maxX - minX, maxY - minY); + return segs; } } diff --git a/gnu/java/awt/java2d/AlphaCompositeContext.java b/gnu/java/awt/java2d/AlphaCompositeContext.java index e67c92148..2e3690d83 100644 --- a/gnu/java/awt/java2d/AlphaCompositeContext.java +++ b/gnu/java/awt/java2d/AlphaCompositeContext.java @@ -236,7 +236,7 @@ public class AlphaCompositeContext } else { - for (int i = srcComponentsLength - 1; i >= 0; i--) + for (int i = srcComponentsLength - 2; i >= 0; i--) srcComponents[i] *= srcComponents[srcComponentsLength - 1]; } if (! dstColorModel.isAlphaPremultiplied()) diff --git a/gnu/java/awt/java2d/ImagePaint.java b/gnu/java/awt/java2d/ImagePaint.java new file mode 100644 index 000000000..7e5fb5638 --- /dev/null +++ b/gnu/java/awt/java2d/ImagePaint.java @@ -0,0 +1,192 @@ +/* ImagePaint.java -- Supplies the pixels for image rendering + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.java2d; + +import java.awt.Paint; +import java.awt.PaintContext; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Transparency; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.WritableRaster; + +/** + * This class is used as a temporary Paint object to supply the pixel values + * for image rendering using the normal scanline conversion implementation. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class ImagePaint + implements Paint +{ + + /** + * The PaintContext implementation for the ImagePaint. + */ + private class ImagePaintContext + implements PaintContext + { + + /** + * The target raster. + */ + private WritableRaster target; + + /** + * Nothing to do here. + */ + public void dispose() + { + // Nothing to do here. + } + + /** + * Returns the color model. + * + * @return the color model + */ + public ColorModel getColorModel() + { + return image.getColorModel(); + } + + /** + * Supplies the pixel to be rendered. + * + * @see PaintContext#getRaster(int, int, int, int) + */ + public Raster getRaster(int x1, int y1, int w, int h) + { + ensureRasterSize(w, h); + int x2 = x1 + w; + int y2 = y1 + h; + float[] src = new float[2]; + float[] dest = new float[2]; + Raster source = image.getData(); + int minX = source.getMinX(); + int maxX = source.getWidth() + minX; + int minY = source.getMinY(); + int maxY = source.getHeight() + minY; + Object pixel = null; + for (int y = y1; y < y2; y++) + { + for (int x = x1; x < x2; x++) + { + src[0] = x; + src[1] = y; + transform.transform(src, 0, dest, 0, 1); + int dx = (int) dest[0]; + int dy = (int) dest[1]; + // Pixels outside the source image are not of interest, skip + // them. + if (dx >= minX && dx < maxX && dy >= minY && dy < maxY) + { + pixel = source.getDataElements(dx, dy, pixel); + target.setDataElements(x - x1, y - y1, pixel); + } + } + } + return target; + } + + /** + * Ensures that the target raster exists and has at least the specified + * size. + * + * @param w the requested target width + * @param h the requested target height + */ + private void ensureRasterSize(int w, int h) + { + if (target == null || target.getWidth() < w || target.getHeight() < h) + { + Raster s = image.getData(); + target = s.createCompatibleWritableRaster(w, h); + } + } + } + + /** + * The image to render. + */ + RenderedImage image; + + /** + * The transform from image space to device space. This is the inversed + * transform of the concatenated + * transform image space -> user space -> device space transform. + */ + AffineTransform transform; + + /** + * Creates a new ImagePaint for rendering the specified image using the + * specified device space -> image space transform. This transform + * is the inversed transform of the usual image space -> user space -> device + * space transform. + * + * The ImagePaint will only render the image in the specified area of + * interest (which is specified in image space). + * + * @param i the image to render + * @param t the device space to user space transform + */ + ImagePaint(RenderedImage i, AffineTransform t) + { + image = i; + transform = t; + } + + public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, + Rectangle2D userBounds, + AffineTransform xform, + RenderingHints hints) + { + return new ImagePaintContext(); + } + + public int getTransparency() + { + return Transparency.OPAQUE; + } + +} diff --git a/gnu/java/awt/java2d/PolyEdge.java b/gnu/java/awt/java2d/PolyEdge.java index 621bd3ad8..8dbdbabcb 100644 --- a/gnu/java/awt/java2d/PolyEdge.java +++ b/gnu/java/awt/java2d/PolyEdge.java @@ -65,6 +65,11 @@ public class PolyEdge double xIntersection; /** + * Indicates whether this edge is from the clip or from the target shape. + */ + boolean isClip; + + /** * Creates a new PolyEdge with the specified coordinates. * * @param x0 the starting point, x coordinate @@ -72,8 +77,9 @@ public class PolyEdge * @param x1 the end point, x coordinate * @param y1 the end point, y coordinate */ - PolyEdge(double x0, double y0, double x1, double y1) + PolyEdge(double x0, double y0, double x1, double y1, boolean clip) { + isClip = clip; if (y0 < y1) { this.x0 = x0; diff --git a/gnu/java/awt/java2d/RasterGraphics.java b/gnu/java/awt/java2d/RasterGraphics.java new file mode 100644 index 000000000..98d47b406 --- /dev/null +++ b/gnu/java/awt/java2d/RasterGraphics.java @@ -0,0 +1,103 @@ +/* RasterGraphics.java -- A Graphics2D impl for Rasters + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.java2d; + +import java.awt.GraphicsConfiguration; +import java.awt.image.ColorModel; +import java.awt.image.WritableRaster; + +/** + * A Graphics2D implementation that operates on Raster objects. This is + * primarily used for BufferedImages, but can theoretically be used on + * arbitrary WritableRasters. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class RasterGraphics + extends AbstractGraphics2D +{ + + /** + * The raster on which we operate. + */ + private WritableRaster raster; + + /** + * The color model of this Graphics instance. + */ + private ColorModel colorModel; + + public RasterGraphics(WritableRaster r, ColorModel cm) + { + super(); + raster = r; + colorModel = cm; + init(); + } + + /** + * Returns the color model of this Graphics object. + * + * @return the color model of this Graphics object + */ + protected ColorModel getColorModel() + { + return colorModel; + } + + /** + * Returns a WritableRaster that is used by this class to perform the + * rendering in. It is not necessary that the target surface immediately + * reflects changes in the raster. Updates to the raster are notified via + * {@link AbstractGraphics2D#updateRaster}. + * + * @return the destination raster + */ + protected WritableRaster getDestinationRaster() + { + return raster; + } + + public GraphicsConfiguration getDeviceConfiguration() + { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/gnu/java/awt/peer/gtk/GdkGraphics.java b/gnu/java/awt/peer/gtk/GdkGraphics.java index 3c3cbdf32..a5b9ff135 100644 --- a/gnu/java/awt/peer/gtk/GdkGraphics.java +++ b/gnu/java/awt/peer/gtk/GdkGraphics.java @@ -39,6 +39,7 @@ exception statement from your version. */ package gnu.java.awt.peer.gtk; import gnu.classpath.Configuration; +import gnu.java.awt.AWTUtilities; import java.awt.Color; import java.awt.Dimension; @@ -160,7 +161,7 @@ public class GdkGraphics extends Graphics if (component != null && ! component.isRealized ()) return; - clip = clip.intersection (new Rectangle (x, y, width, height)); + computeIntersection(x, y, width, height, clip); setClipRectangle (clip.x, clip.y, clip.width, clip.height); } @@ -493,4 +494,26 @@ public class GdkGraphics extends Graphics component = g.component; nativeCopyState(g); } + + private Rectangle computeIntersection(int x, int y, int w, int h, + Rectangle rect) + { + int x2 = (int) rect.x; + int y2 = (int) rect.y; + int w2 = (int) rect.width; + int h2 = (int) rect.height; + + int dx = (x > x2) ? x : x2; + int dy = (y > y2) ? y : y2; + int dw = (x + w < x2 + w2) ? (x + w - dx) : (x2 + w2 - dx); + int dh = (y + h < y2 + h2) ? (y + h - dy) : (y2 + h2 - dy); + + if (dw >= 0 && dh >= 0) + rect.setBounds(dx, dy, dw, dh); + else + rect.setBounds(0, 0, 0, 0); + + return rect; + } + } diff --git a/gnu/java/awt/peer/swing/SwingComponent.java b/gnu/java/awt/peer/swing/SwingComponent.java index 04ca7294f..a51b758ad 100644 --- a/gnu/java/awt/peer/swing/SwingComponent.java +++ b/gnu/java/awt/peer/swing/SwingComponent.java @@ -62,7 +62,7 @@ public interface SwingComponent /** * Handles a mouse event. This is usually forwarded to - * {@link Component#processMouseMotionEvent(MouseEvent)} of the swing + * {@link java.awt.Component#processMouseMotionEvent(MouseEvent)} of the swing * component. * * @param ev the mouse event @@ -71,7 +71,7 @@ public interface SwingComponent /** * Handles a mouse motion event. This is usually forwarded to - * {@link Component#processMouseEvent(MouseEvent)} of the swing + * {@link java.awt.Component#processMouseEvent(MouseEvent)} of the swing * component. * * @param ev the mouse motion event @@ -80,7 +80,7 @@ public interface SwingComponent /** * Handles a key event. This is usually forwarded to - * {@link Component#processKeyEvent(KeyEvent)} of the swing + * {@link java.awt.Component#processKeyEvent(KeyEvent)} of the swing * component. * * @param ev the key event diff --git a/gnu/java/awt/peer/swing/SwingComponentPeer.java b/gnu/java/awt/peer/swing/SwingComponentPeer.java index 5d484e021..f60c8e96c 100644 --- a/gnu/java/awt/peer/swing/SwingComponentPeer.java +++ b/gnu/java/awt/peer/swing/SwingComponentPeer.java @@ -48,6 +48,8 @@ import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; import java.awt.Image; import java.awt.Point; import java.awt.Rectangle; @@ -98,8 +100,9 @@ public class SwingComponentPeer /** * Creates a SwingComponentPeer instance. Subclasses are expected to call - * this constructor and thereafter call {@link #init(Component, JComponent)} - * in order to setup the AWT and Swing components properly. + * this constructor and thereafter call + * {@link #init(Component, SwingComponent)} in order to setup the AWT and + * Swing components properly. */ protected SwingComponentPeer() { @@ -164,9 +167,12 @@ public class SwingComponentPeer */ public Image createImage(int width, int height) { - Component parent = awtComponent.getParent(); - ComponentPeer parentPeer = parent.getPeer(); - return parentPeer.createImage(width, height); + GraphicsEnvironment graphicsEnv = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice dev = graphicsEnv.getDefaultScreenDevice(); + GraphicsConfiguration conf = dev.getDefaultConfiguration(); + Image image = conf.createCompatibleImage(width, height); + return image; } /** @@ -442,20 +448,6 @@ public class SwingComponentPeer return retVal; } - /** - * Prepares an image for rendering on this component. This is called by - * {@link Component#prepareImage(Image, int, int, ImageObserver)}. - * - * @param img the image to prepare - * @param width the desired width of the rendered image - * @param height the desired height of the rendered image - * @param ob the image observer to be notified of updates in the preparation - * process - * - * @return <code>true</code> if the image has been fully prepared, - * <code>false</code> otherwise (in which case the image observer - * receives updates) - */ public void paint(Graphics graphics) { // FIXME: I don't know what this method is supposed to do. @@ -478,8 +470,17 @@ public class SwingComponentPeer public boolean prepareImage(Image img, int width, int height, ImageObserver ob) { Component parent = awtComponent.getParent(); - ComponentPeer parentPeer = parent.getPeer(); - return parentPeer.prepareImage(img, width, height, ob); + boolean res; + if(parent != null) + { + ComponentPeer parentPeer = parent.getPeer(); + res = parentPeer.prepareImage(img, width, height, ob); + } + else + { + res = Toolkit.getDefaultToolkit().prepareImage(img, width, height, ob); + } + return res; } public void print(Graphics graphics) diff --git a/gnu/java/awt/peer/swing/SwingContainerPeer.java b/gnu/java/awt/peer/swing/SwingContainerPeer.java index 0b2fb992f..f433e1b5c 100644 --- a/gnu/java/awt/peer/swing/SwingContainerPeer.java +++ b/gnu/java/awt/peer/swing/SwingContainerPeer.java @@ -92,7 +92,12 @@ public class SwingContainerPeer */ public Insets getInsets() { - return insets(); + Insets retVal; + if (swingComponent != null) + retVal = swingComponent.getJComponent().getInsets(); + else + retVal = new Insets(0, 0, 0, 0); + return retVal; } /** @@ -209,6 +214,8 @@ public class SwingContainerPeer protected void handleMouseEvent(MouseEvent ev) { Component comp = awtComponent.getComponentAt(ev.getPoint()); + if(comp == null) + comp = awtComponent; if (comp != null) { ComponentPeer peer = comp.getPeer(); diff --git a/gnu/java/awt/peer/swing/SwingFramePeer.java b/gnu/java/awt/peer/swing/SwingFramePeer.java index fea1b504a..0d5a02d78 100644 --- a/gnu/java/awt/peer/swing/SwingFramePeer.java +++ b/gnu/java/awt/peer/swing/SwingFramePeer.java @@ -53,9 +53,9 @@ import java.awt.peer.FramePeer; * As a minimum, a subclass must implement all the remaining abstract methods * as well as the following methods: * <ul> - * <li>{@link ComponentPeer#getLocationOnScreen()}</li> - * <li>{@link ComponentPeer#getGraphics()}</li> - * <li>{@link ComponentPeer#createImage(int, int)}</li> + * <li>{@link java.awt.peer.ComponentPeer#getLocationOnScreen()}</li> + * <li>{@link java.awt.peer.ComponentPeer#getGraphics()}</li> + * <li>{@link java.awt.peer.ComponentPeer#createImage(int, int)}</li> * </ul> * * @author Roman Kennke (kennke@aicas.com) diff --git a/gnu/java/awt/peer/swing/SwingMenuBarPeer.java b/gnu/java/awt/peer/swing/SwingMenuBarPeer.java index bd9dcd77a..0033efb02 100644 --- a/gnu/java/awt/peer/swing/SwingMenuBarPeer.java +++ b/gnu/java/awt/peer/swing/SwingMenuBarPeer.java @@ -174,7 +174,7 @@ public class SwingMenuBarPeer /** * Adds a help menu to the menu bar. * - * @param m the menu to add + * @param menu the menu to add */ public void addHelpMenu(Menu menu) { diff --git a/gnu/java/awt/peer/swing/SwingTextFieldPeer.java b/gnu/java/awt/peer/swing/SwingTextFieldPeer.java index a4c6d82d2..0c3b4e726 100644 --- a/gnu/java/awt/peer/swing/SwingTextFieldPeer.java +++ b/gnu/java/awt/peer/swing/SwingTextFieldPeer.java @@ -283,7 +283,7 @@ public class SwingTextFieldPeer * @param startPos the start index of the selection * @param endPos the start index of the selection */ - public void select(int start_pos, int endPos) + public void select(int startPos, int endPos) { // TODO: Must be implemented. } diff --git a/gnu/java/awt/peer/swing/SwingWindowPeer.java b/gnu/java/awt/peer/swing/SwingWindowPeer.java index 2f89795ca..43a509b95 100644 --- a/gnu/java/awt/peer/swing/SwingWindowPeer.java +++ b/gnu/java/awt/peer/swing/SwingWindowPeer.java @@ -48,9 +48,9 @@ import java.awt.peer.WindowPeer; * As a minimum, a subclass must implement all the remaining abstract methods * as well as the following methods: * <ul> - * <li>{@link ComponentPeer#getLocationOnScreen()}</li> - * <li>{@link ComponentPeer#getGraphics()}</li> - * <li>{@link ComponentPeer#createImage(int, int)}</li> + * <li>{@link java.awt.peer.ComponentPeer#getLocationOnScreen()}</li> + * <li>{@link java.awt.peer.ComponentPeer#getGraphics()}</li> + * <li>{@link java.awt.peer.ComponentPeer#createImage(int, int)}</li> * </ul> * * @author Roman Kennke (kennke@aicas.com) diff --git a/gnu/java/awt/print/JavaPrinterGraphics.java b/gnu/java/awt/print/JavaPrinterGraphics.java new file mode 100644 index 000000000..af31309ed --- /dev/null +++ b/gnu/java/awt/print/JavaPrinterGraphics.java @@ -0,0 +1,518 @@ +/* JavaPrinterGraphics.java -- AWT printer rendering class. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.print; + +import gnu.java.awt.peer.gtk.GtkImage; + +import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.image.ImageObserver; +import java.awt.image.PixelGrabber; +import java.awt.print.PageFormat; +import java.awt.print.Pageable; +import java.awt.print.Paper; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterGraphics; +import java.awt.print.PrinterJob; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.text.AttributedCharacterIterator; + +/** + * Graphics context to draw to PostScript. + * + * @author Sven de Marothy + */ +public class JavaPrinterGraphics extends Graphics implements PrinterGraphics +{ + + /** + * The used graphics context. + */ + private Graphics g; + + /** + * The associated printer job. + */ + private PrinterJob printerJob; + + /** + * Rendering resolution + */ + private static final double DPI = 72.0; + + /** + * Rendered image size. + */ + private int xSize, ySize; + + /** + * The image to render to. + */ + private Image image; + + public JavaPrinterGraphics( PrinterJob printerJob ) + { + this.printerJob = printerJob; + } + + /** + * Spool a document to PostScript. + * If Pageable is non-null, it will print that, otherwise it will use + * the supplied printable and pageFormat. + */ + public SpooledDocument spoolPostScript(Printable printable, + PageFormat pageFormat, + Pageable pageable) + throws PrinterException + { + try + { + // spool to a temporary file + File temp = File.createTempFile("cpspool", ".ps"); + temp.deleteOnExit(); + + PrintWriter out = new PrintWriter + (new BufferedWriter + (new OutputStreamWriter + (new FileOutputStream(temp), "ISO8859_1"), 1000000)); + + writePSHeader(out); + + if(pageable != null) + { + for(int index = 0; index < pageable.getNumberOfPages(); index++) + spoolPage(out, pageable.getPrintable(index), + pageable.getPageFormat(index), index); + } + else + { + int index = 0; + while(spoolPage(out, printable, pageFormat, index++) == + Printable.PAGE_EXISTS); + } + out.println("%%Trailer"); + out.println("%%EOF"); + out.close(); + return new SpooledDocument( temp ); + } + catch (IOException e) + { + PrinterException pe = new PrinterException(); + pe.initCause(e); + throw pe; + } + } + + /** + * Spools a single page, returns NO_SUCH_PAGE unsuccessful, + * PAGE_EXISTS if it was. + */ + public int spoolPage(PrintWriter out, + Printable printable, + PageFormat pageFormat, + int index) throws IOException, PrinterException + { + initImage( pageFormat ); + if(printable.print(this, pageFormat, index) == Printable.NO_SUCH_PAGE) + return Printable.NO_SUCH_PAGE; + g.dispose(); + g = null; + writePage( out, pageFormat ); + return Printable.PAGE_EXISTS; + } + + private void initImage(PageFormat pageFormat) + { + // Create a really big image and draw to that. + xSize = (int)(DPI*pageFormat.getWidth()/72.0); + ySize = (int)(DPI*pageFormat.getHeight()/72.0); + + // Swap X and Y sizes if it's a Landscape page. + if( pageFormat.getOrientation() != PageFormat.PORTRAIT ) + { + int t = xSize; + xSize = ySize; + ySize = t; + } + + // FIXME: This should at least be BufferedImage. + // Fix once we have a working B.I. + // Graphics2D should also be supported of course. + image = new GtkImage(xSize, ySize); + + g = image.getGraphics(); + setColor(Color.white); + fillRect(0, 0, xSize, ySize); + setColor(Color.black); + } + + private void writePSHeader(PrintWriter out) + { + out.println("%!PS-Adobe-3.0"); + out.println("%%Title: "+printerJob.getJobName()); + out.println("%%Creator: GNU Classpath "); + out.println("%%DocumentData: Clean8Bit"); + + out.println("%%DocumentNeededResources: font Times-Roman Helvetica Courier"); + // out.println("%%Pages: "+); // FIXME # pages. + out.println("%%EndComments"); + + out.println("%%BeginProlog"); + out.println("%%EndProlog"); + out.println("%%BeginSetup"); + + // FIXME: Paper name + // E.g. "A4" "Letter" + // out.println("%%BeginFeature: *PageSize A4"); + + out.println("%%EndFeature"); + + out.println("%%EndSetup"); + + // out.println("%%Page: 1 1"); + } + + private void writePage(PrintWriter out, PageFormat pageFormat) + { + out.println("%%BeginPageSetup"); + + Paper p = pageFormat.getPaper(); + double pWidth = p.getWidth(); + double pHeight = p.getHeight(); + + if( pageFormat.getOrientation() == PageFormat.PORTRAIT ) + out.println( "%%Orientation: Portrait" ); + else + { + out.println( "%%Orientation: Landscape" ); + double t = pWidth; + pWidth = pHeight; + pHeight = t; + } + + out.println("gsave % first save"); + + // 595x842; 612x792 respectively + out.println("<< /PageSize [" +pWidth + " "+pHeight+ "] >> setpagedevice"); + + // invert the Y axis so that we get screen-like coordinates instead. + AffineTransform pageTransform = new AffineTransform(); + if( pageFormat.getOrientation() == PageFormat.REVERSE_LANDSCAPE ) + { + pageTransform.translate(pWidth, pHeight); + pageTransform.scale(-1.0, -1.0); + } + concatCTM(out, pageTransform); + out.println("%%EndPageSetup"); + + out.println("gsave"); + + + // Draw the image + out.println(xSize+" "+ySize+" 8 [1 0 0 -1 0 "+ySize+" ]"); + out.println("{currentfile 3 string readhexstring pop} bind"); + out.println("false 3 colorimage"); + int[] pixels = new int[xSize * ySize]; + PixelGrabber pg = new PixelGrabber(image, 0, 0, xSize, ySize, pixels, 0, xSize); + + try { + pg.grabPixels(); + } catch (InterruptedException e) { + out.println("% Bug getting pixels!"); + } + + int n = 0; + for (int j = 0; j < ySize; j++) { + for (int i = 0; i < xSize; i++) { + out.print( colorTripleHex(pixels[j * xSize + i]) ); + if(((++n)%11) == 0) out.println(); + } + } + + out.println(); + out.println("%%EOF"); + out.println("grestore"); + out.println("showpage"); + } + + /** + * Get a nonsperated hex RGB triple, e.g. FFFFFF = white + */ + private String colorTripleHex(int num){ + String s = ""; + + try { + s = Integer.toHexString( ( num & 0x00FFFFFF ) ); + if( s.length() < 6 ) + { + s = "000000"+s; + return s.substring(s.length()-6); + } + } catch (Exception e){ + s = "FFFFFF"; + } + + return s; + } + + private void concatCTM(PrintWriter out, AffineTransform Tx){ + double[] matrixElements = new double[6]; + Tx.getMatrix(matrixElements); + + out.print("[ "); + for(int i=0;i<6;i++) + out.print(matrixElements[i]+" "); + out.println("] concat"); + } + + //----------------------------------------------------------------------------- + /** + * PrinterGraphics method - Returns the printer job associated with this object. + */ + public PrinterJob getPrinterJob() + { + return printerJob; + } + + /** + * The rest of the methods here are just pass-throughs to g. + */ + public void clearRect(int x, int y, int width, int height) + { + g.clearRect(x, y, width, height); + } + + public void clipRect(int x, int y, int width, int height) + { + g.clipRect(x, y, width, height); + } + + public void copyArea(int x, int y, int width, int height, int dx, int dy) + { + g.copyArea(x, y, width, height, dx, dy); + } + + public Graphics create() + { + return g.create(); + } + + public void dispose() + { + } + + public void drawArc(int x, int y, int width, int height, int startAngle, + int arcAngle) + { + g.drawArc(x, y, width, height, startAngle, arcAngle); + } + + public boolean drawImage(Image img, int x, int y, Color bgcolor, + ImageObserver observer) + { + return g.drawImage(img, x, y, bgcolor, observer); + } + + public boolean drawImage(Image img, int x, int y, ImageObserver observer) + { + return g.drawImage(img, x, y, observer); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, + Color bgcolor, ImageObserver observer) + { + return g.drawImage(img, x, y, width, height, bgcolor, observer); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, + ImageObserver observer) + { + return g.drawImage(img, x, y, width, height, observer); + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, Color bgcolor, + ImageObserver observer) + { + return g.drawImage(img, dx1, dy1, dx2, dy2, + sx1, sy1, sx2, sy2, bgcolor, observer); + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, ImageObserver observer) + { + return g.drawImage(img, dx1, dy1, dx2, dy2, + sx1, sy1, sx2, sy2, observer); + } + + public void drawLine(int x1, int y1, int x2, int y2) + { + g.drawLine(x1, y1, x2, y2); + } + + public void drawOval(int x, int y, int width, int height) + { + g.drawOval(x, y, width, height); + } + + public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) + { + g.drawPolygon(xPoints, yPoints, nPoints); + } + + public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) + { + g.drawPolyline(xPoints, yPoints, nPoints); + } + + public void drawRoundRect(int x, int y, int width, int height, + int arcWidth, int arcHeight) + { + g.drawRoundRect(x, y, width, height, arcWidth, arcHeight); + } + + public void drawString(AttributedCharacterIterator iterator, int x, int y) + { + g.drawString(iterator, x, y); + } + + public void drawString(String str, int x, int y) + { + g.drawString(str, x, y); + } + + public void fillArc(int x, int y, int width, int height, + int startAngle, int arcAngle) + { + g.fillArc(x, y, width, height, startAngle, arcAngle); + } + + public void fillOval(int x, int y, int width, int height) + { + g.fillOval(x, y, width, height); + } + + public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) + { + g.fillPolygon(xPoints, yPoints, nPoints); + } + + public void fillRect(int x, int y, int width, int height) + { + g.fillRect(x, y, width, height); + } + + public void fillRoundRect(int x, int y, int width, int height, + int arcWidth, int arcHeight) + { + g.fillRoundRect(x, y, width, height, arcWidth, arcHeight); + } + + public Shape getClip() + { + return g.getClip(); + } + + public Rectangle getClipBounds() + { + return g.getClipBounds(); + } + + public Color getColor() + { + return g.getColor(); + } + + public Font getFont() + { + return g.getFont(); + } + + public FontMetrics getFontMetrics(Font f) + { + return g.getFontMetrics(f); + } + + public void setClip(int x, int y, int width, int height) + { + g.setClip(x, y, width, height); + } + + public void setClip(Shape clip) + { + g.setClip(clip); + } + + public void setColor(Color c) + { + g.setColor(c); + } + + public void setFont(Font font) + { + g.setFont(font); + } + + public void setPaintMode() + { + g.setPaintMode(); + } + + public void setXORMode(Color c1) + { + g.setXORMode(c1); + } + + public void translate(int x, int y) + { + g.translate(x, y); + } +} + diff --git a/gnu/java/awt/print/JavaPrinterJob.java b/gnu/java/awt/print/JavaPrinterJob.java new file mode 100644 index 000000000..adeeba04a --- /dev/null +++ b/gnu/java/awt/print/JavaPrinterJob.java @@ -0,0 +1,403 @@ +/* JavaPrinterJob.java -- AWT printing implemented on javax.print. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.print; + +import java.awt.HeadlessException; +import java.awt.print.PageFormat; +import java.awt.print.Pageable; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; +import java.util.Locale; + +import javax.print.CancelablePrintJob; +import javax.print.DocFlavor; +import javax.print.DocPrintJob; +import javax.print.PrintException; +import javax.print.PrintService; +import javax.print.PrintServiceLookup; +import javax.print.ServiceUI; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.IntegerSyntax; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.print.attribute.TextSyntax; +import javax.print.attribute.standard.Copies; +import javax.print.attribute.standard.JobName; +import javax.print.attribute.standard.OrientationRequested; +import javax.print.attribute.standard.RequestingUserName; + +/** + * This is the default implementation of PrinterJob + * + * @author Sven de Marothy + */ +public class JavaPrinterJob extends PrinterJob +{ + /** + * The print service associated with this job + */ + private PrintService printer = null; + + /** + * Printing options; + */ + private PrintRequestAttributeSet attributes; + + /** + * Available print services + */ + private static PrintService[] services; + + /** + * The actual print job. + */ + private DocPrintJob printJob; + + /** + * The Printable object to print. + */ + private Printable printable; + + /** + * Page format. + */ + private PageFormat pageFormat; + + /** + * A pageable, or null + */ + private Pageable pageable = null; + + /** + * Cancelled or not + */ + private boolean cancelled = false; + + static + { + // lookup all services without any constraints + services = PrintServiceLookup.lookupPrintServices + (DocFlavor.INPUT_STREAM.POSTSCRIPT, null); + } + + private static final Class copyClass = (new Copies(1)).getClass(); + private static final Class jobNameClass = (new JobName("", null)).getClass(); + private static final Class userNameClass = (new RequestingUserName("", null)).getClass(); + + /** + * Initializes a new instance of <code>PrinterJob</code>. + */ + public JavaPrinterJob() + { + attributes = new HashPrintRequestAttributeSet(); + setCopies(1); + setJobName("Java Printing"); + pageFormat = new PageFormat(); // default page format. + } + + private void getPageAttributes() + { + OrientationRequested orientation = (OrientationRequested) + attributes.get( OrientationRequested.LANDSCAPE.getCategory() ); + if( orientation == null) + return; + + if( orientation.equals(OrientationRequested.PORTRAIT) ) + pageFormat.setOrientation(PageFormat.PORTRAIT); + else if( orientation.equals(OrientationRequested.LANDSCAPE) ) + pageFormat.setOrientation(PageFormat.LANDSCAPE); + else if( orientation.equals(OrientationRequested.REVERSE_LANDSCAPE) ) + pageFormat.setOrientation(PageFormat.REVERSE_LANDSCAPE); + } + + /** + * Returns the number of copies to be printed. + * + * @return The number of copies to be printed. + */ + public int getCopies() + { + return ((IntegerSyntax)attributes.get( jobNameClass )).getValue(); + } + + /** + * Sets the number of copies to be printed. + * + * @param copies The number of copies to be printed. + */ + public void setCopies(int copies) + { + attributes.add( new Copies( copies ) ); + } + + /** + * Returns the name of the print job. + * + * @return The name of the print job. + */ + public String getJobName() + { + return ((TextSyntax)attributes.get( jobNameClass )).getValue(); + } + + /** + * Sets the name of the print job. + * + * @param job_name The name of the print job. + */ + public void setJobName(String job_name) + { + attributes.add( new JobName(job_name, Locale.getDefault()) ); + } + + /** + * Returns the printing user name. + * + * @return The printing username. + */ + public String getUserName() + { + return ((TextSyntax)attributes.get( userNameClass )).getValue(); + } + + /** + * Cancels an in progress print job. + */ + public void cancel() + { + try + { + if(printJob != null && (printJob instanceof CancelablePrintJob)) + { + ((CancelablePrintJob)printJob).cancel(); + cancelled = true; + } + } + catch(PrintException pe) + { + } + } + + /** + * Tests whether or not this job has been cancelled. + * + * @return <code>true</code> if this job has been cancelled, <code>false</code> + * otherwise. + */ + public boolean isCancelled() + { + return cancelled; + } + + /** + * Clones the specified <code>PageFormat</code> object then alters the + * clone so that it represents the default page format. + * + * @param page_format The <code>PageFormat</code> to clone. + * + * @return A new default page format. + */ + public PageFormat defaultPage(PageFormat page_format) + { + return new PageFormat(); + } + + /** + * Displays a dialog box to the user which allows the page format + * attributes to be modified. + * + * @param page_format The <code>PageFormat</code> object to modify. + * + * @return The modified <code>PageFormat</code>. + */ + public PageFormat pageDialog(PageFormat page_format) + throws HeadlessException + { + return defaultPage(null); + } + + /** + * Prints the pages. + */ + public void print() throws PrinterException + { + if( printable == null && pageable == null ) // nothing to print? + return; + + PostScriptGraphics2D pg = new PostScriptGraphics2D( this ); + SpooledDocument doc = pg.spoolPostScript( printable, pageFormat, + pageable ); + + cancelled = false; + printJob = printer.createPrintJob(); + try + { + printJob.print(doc, attributes); + } + catch (PrintException pe) + { + PrinterException p = new PrinterException(); + p.initCause(pe); + throw p; + } + // no printjob active. + printJob = null; + } + + /** + * Prints the page with given attributes. + */ + public void print (PrintRequestAttributeSet attributes) + throws PrinterException + { + this.attributes = attributes; + print(); + } + + /** + * Displays a dialog box to the user which allows the print job + * attributes to be modified. + * + * @return <code>false</code> if the user cancels the dialog box, + * <code>true</code> otherwise. + */ + public boolean printDialog() throws HeadlessException + { + return printDialog( attributes ); + } + + /** + * Displays a dialog box to the user which allows the print job + * attributes to be modified. + * + * @return <code>false</code> if the user cancels the dialog box, + * <code>true</code> otherwise. + */ + public boolean printDialog(PrintRequestAttributeSet attributes) + throws HeadlessException + { + PrintService chosenPrinter = ServiceUI.printDialog + (null, 50, 50, services, null, + DocFlavor.INPUT_STREAM.POSTSCRIPT, attributes); + + getPageAttributes(); + + if( chosenPrinter != null ) + { + try + { + setPrintService( chosenPrinter ); + } + catch(PrinterException pe) + { + // Should not happen. + } + return true; + } + return false; + } + + /** + * This sets the pages that are to be printed. + * + * @param pageable The pages to be printed, which may not be <code>null</code>. + */ + public void setPageable(Pageable pageable) + { + if( pageable == null ) + throw new NullPointerException("Pageable cannot be null."); + this.pageable = pageable; + } + + /** + * Sets this specified <code>Printable</code> as the one to use for + * rendering the pages on the print device. + * + * @param printable The <code>Printable</code> for the print job. + */ + public void setPrintable(Printable printable) + { + this.printable = printable; + } + + /** + * Sets the <code>Printable</code> and the page format for the pages + * to be printed. + * + * @param printable The <code>Printable</code> for the print job. + * @param page_format The <code>PageFormat</code> for the print job. + */ + public void setPrintable(Printable printable, PageFormat page_format) + { + this.printable = printable; + this.pageFormat = page_format; + } + + /** + * Makes any alterations to the specified <code>PageFormat</code> + * necessary to make it work with the current printer. The alterations + * are made to a clone of the input object, which is then returned. + * + * @param page_format The <code>PageFormat</code> to validate. + * + * @return The validated <code>PageFormat</code>. + */ + public PageFormat validatePage(PageFormat page_format) + { + // FIXME + return page_format; + } + + /** + * Change the printer for this print job to service. Subclasses that + * support setting the print service override this method. Throws + * PrinterException when the class doesn't support setting the printer, + * the service doesn't support Pageable or Printable interfaces for 2D + * print output. + * @param service The new printer to use. + * @throws PrinterException if service is not valid. + */ + public void setPrintService(PrintService service) + throws PrinterException + { + if(!service.isDocFlavorSupported(DocFlavor.INPUT_STREAM.POSTSCRIPT)) + throw new PrinterException("This printer service is not supported."); + printer = service; + } +} diff --git a/gnu/java/awt/print/PostScriptGraphics2D.java b/gnu/java/awt/print/PostScriptGraphics2D.java new file mode 100644 index 000000000..2303f44b7 --- /dev/null +++ b/gnu/java/awt/print/PostScriptGraphics2D.java @@ -0,0 +1,1349 @@ +/* PostScriptGraphics2D.java -- AWT printer rendering class. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.print; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Paint; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.geom.AffineTransform; +import java.awt.geom.Arc2D; +import java.awt.geom.Ellipse2D; +import java.awt.geom.RoundRectangle2D; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.TextLayout; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.renderable.RenderableImage; +import java.awt.image.RenderedImage; +import java.awt.image.ImageObserver; +import java.awt.image.PixelGrabber; +import java.awt.print.PageFormat; +import java.awt.print.Pageable; +import java.awt.print.Paper; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterGraphics; +import java.awt.print.PrinterJob; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.text.AttributedCharacterIterator; +import java.util.Map; + +/** + * Class PostScriptGraphics2D - Class that implements the Graphics2D object, + * writing the output to a PostScript or EPS file + * + * @author Sven de Marothy + * + */ +class PostScriptGraphics2D extends Graphics2D +{ + /** + * The associated printer job. + */ + private PrinterJob printerJob; + + /** + * Output file. + */ + private PrintWriter out; + + // Graphics data + private AffineTransform currentTransform = new AffineTransform(); + private AffineTransform pageTransform; + private RenderingHints renderingHints; + private Paint currentPaint = null; + private Shape clipShape = null; + private Font currentFont = null; + private Color currentColor = Color.black; + private Color backgroundColor = Color.white; + private Stroke currentStroke = null; + private static Stroke ordinaryStroke = new BasicStroke(0.0f, + BasicStroke.CAP_BUTT, + BasicStroke.JOIN_MITER); + private float cx; // current drawing position + private float cy; // current drawing position + private boolean currentFontIsPS; // set if currentFont is one of the above + + // settings + private double pageX = 595; + private double pageY = 842; + private double Y = pageY; + private boolean gradientOn = false; + + /** + * Constructor + * + */ + public PostScriptGraphics2D( PrinterJob pg ) + { + printerJob = pg; + // create transform objects + pageTransform = new AffineTransform(); + currentTransform = new AffineTransform(); + + /* + Create Rendering hints + No text aliasing + Quality color and rendering + Bicubic interpolation + Fractional metrics supported + */ + renderingHints = new RenderingHints(null); + renderingHints.put(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_QUALITY); + renderingHints.put(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); + renderingHints.put(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BICUBIC); + renderingHints.put(RenderingHints.KEY_FRACTIONALMETRICS, + RenderingHints.VALUE_FRACTIONALMETRICS_ON); + renderingHints.put(RenderingHints.KEY_COLOR_RENDERING, + RenderingHints.VALUE_COLOR_RENDER_QUALITY); + } + + /** + * Spool a document to PostScript. + * If Pageable is non-null, it will print that, otherwise it will use + * the supplied printable and pageFormat. + */ + public SpooledDocument spoolPostScript(Printable printable, + PageFormat pageFormat, + Pageable pageable) + throws PrinterException + { + try + { + // spool to a temporary file + File temp = File.createTempFile("cpspool", ".ps"); + temp.deleteOnExit(); + + out = new PrintWriter(new BufferedWriter + (new OutputStreamWriter + (new FileOutputStream(temp), + "ISO8859_1"), 1000000)); + + writePSHeader(); + + if(pageable != null) + { + for(int index = 0; index < pageable.getNumberOfPages(); index++) + spoolPage(out, pageable.getPrintable(index), + pageable.getPageFormat(index), index); + } + else + { + int index = 0; + while(spoolPage(out, printable, pageFormat, index++) == + Printable.PAGE_EXISTS); + } + out.println("%%Trailer"); + out.println("%%EOF"); + out.close(); + return new SpooledDocument( temp ); + } + catch (IOException e) + { + PrinterException pe = new PrinterException(); + pe.initCause(e); + throw pe; + } + } + + //-------------------------------------------------------------------------- + + /** + * Write the postscript file header, + * setup the page format and transforms. + */ + private void writePSHeader() + { + out.println("%!PS-Adobe-3.0"); + out.println("%%Title: "+printerJob.getJobName()); + out.println("%%Creator: GNU Classpath "); + out.println("%%DocumentData: Clean8Bit"); + + out.println("%%DocumentNeededResources: font Times-Roman Helvetica Courier"); + out.println("%%EndComments"); + + out.println("%%BeginProlog"); + out.println("%%EndProlog"); + out.println("%%BeginSetup"); + + out.println("%%EndFeature"); + setupFonts(); + out.println("%%EndSetup"); + + // set default fonts and colors + setFont( new Font("Dialog", Font.PLAIN, 12) ); + currentColor = Color.white; + currentStroke = new BasicStroke(); + setPaint(currentColor); + setStroke(currentStroke); + } + + /** + * setupFonts - set up the font dictionaries for + * helvetica, times and courier + */ + private void setupFonts() + { + out.println("/helveticaISO"); + out.println("/Helvetica findfont dup length dict begin"); + out.println("{ 1 index /FID eq { pop pop } { def } ifelse } forall"); + out.println("/Encoding ISOLatin1Encoding def"); + out.println("currentdict end definefont pop"); + + out.println("/timesISO"); + out.println("/Times-Roman findfont dup length dict begin"); + out.println("{ 1 index /FID eq { pop pop } { def } ifelse } forall"); + out.println("/Encoding ISOLatin1Encoding def"); + out.println("currentdict end definefont pop"); + + out.println("/courierISO"); + out.println("/Courier findfont dup length dict begin"); + out.println("{ 1 index /FID eq { pop pop } { def } ifelse } forall"); + out.println("/Encoding ISOLatin1Encoding def"); + out.println("currentdict end definefont pop"); + } + + /** + * Spools a single page, returns NO_SUCH_PAGE unsuccessful, + * PAGE_EXISTS if it was. + */ + public int spoolPage(PrintWriter out, + Printable printable, + PageFormat pageFormat, + int index) throws IOException, PrinterException + { + out.println("%%BeginPageSetup"); + + Paper p = pageFormat.getPaper(); + pageX = p.getWidth(); + pageY = p.getHeight(); + + if( pageFormat.getOrientation() == PageFormat.PORTRAIT ) + out.println( "%%Orientation: Portrait" ); + else + { + out.println( "%%Orientation: Landscape" ); + double t = pageX; + pageX = pageY; + pageY = t; + } + + setClip(0, 0, (int)pageX, (int)pageY); + + out.println("gsave % first save"); + + // 595x842; 612x792 respectively + out.println("<< /PageSize [" +pageX + " "+pageY+ "] >> setpagedevice"); + + if( pageFormat.getOrientation() != PageFormat.LANDSCAPE ) + { + pageTransform.translate(pageX, 0); + pageTransform.scale(-1.0, 1.0); + } + + // save the original CTM + pushCTM(); + concatCTM(pageTransform); + setTransform(new AffineTransform()); + + out.println("%%EndPageSetup"); + + out.println("gsave"); + + if( printable.print(this, pageFormat, index) == Printable.NO_SUCH_PAGE ) + return Printable.NO_SUCH_PAGE; + + out.println("grestore"); + out.println("showpage"); + + return Printable.PAGE_EXISTS; + } + + /** push the Current Transformation Matrix onto the PS stack */ + private void pushCTM() + { + out.println("matrix currentmatrix % pushCTM()"); + } + + /** pop the Current Transformation Matrix from the PS stack */ + private void popCTM() + { + out.println("setmatrix % restore CTM"); + } + + /////////////////////////////////////////////////////////////////////////// + + public Graphics create() + { + return null; + } + + public void drawOval(int x, int y, int width, int height) + { + out.println("% drawOval()"); + setStroke(ordinaryStroke); + draw(new Ellipse2D.Double(x, y, width, height)); + setStroke(currentStroke); + } + + public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) + { + if (nPoints <= 0 || xPoints.length < nPoints || yPoints.length < nPoints) + return; + out.println("newpath % drawPolyLine()"); + out.println(xPoints[0] + " " + yPoints[0] + " moveto"); + for (int i = 1; i < nPoints; i++) + out.println(xPoints[i] + " " + yPoints[i] + " lineto"); + out.println("closepath"); + out.println("stroke"); + } + + public void drawRoundRect(int x, int y, int width, int height, int arcWidth, + int arcHeight) + { + out.println("% drawRoundRect()"); + RoundRectangle2D.Double rr = new RoundRectangle2D.Double(x, y, width, + height, arcWidth, + arcHeight); + setStroke(ordinaryStroke); + draw(rr); + setStroke(currentStroke); + } + + public void fillRoundRect(int x, int y, int width, int height, int arcWidth, + int arcHeight) + { + out.println("% fillRoundRect()"); + RoundRectangle2D.Double rr = new RoundRectangle2D.Double(x, y, width, + height, arcWidth, + arcHeight); + fill(rr); + } + + public void drawArc(int x, int y, int width, int height, int startAngle, + int arcAngle) + { + setStroke(ordinaryStroke); + draw(new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.OPEN)); + setStroke(currentStroke); + } + + public void fillArc(int x, int y, int width, int height, int startAngle, + int arcAngle) + { + fill(new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.PIE)); + } + + public void fillOval(int x, int y, int width, int height) + { + out.println("% fillOval()"); + fill( new Ellipse2D.Double(x, y, width, height) ); + } + + public void fillPolygon(int[] x, int[] y, int nPoints) + { + out.println("% fillPolygon()"); + fill( new Polygon(x, y, nPoints) ); + } + + public void drawLine(int x1, int y1, int x2, int y2) + { + out.println("% drawLine()"); + setStroke(ordinaryStroke); + out.println("newpath"); + out.println(x1 + " " + (y1) + " moveto"); + out.println(x2 + " " + (y2) + " lineto"); + out.println("stroke"); + setStroke(currentStroke); + } + + //--------------- Image drawing ------------------------------------------ + public boolean drawImage(Image img, int x, int y, Color bgcolor, + ImageObserver observer) + { + int w = img.getWidth(null); + int h = img.getHeight(null); + + return drawImage(img, x, y, x + w, y + h, 0, 0, w - 1, h - 1, bgcolor, + observer); + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, Color bgcolor, + ImageObserver observer) + { + int n = 0; + boolean flipx = false; + boolean flipy = false; + + // swap X and Y's + if (sx1 > sx2) + { + n = sx1; + sx1 = sx2; + sx2 = n; + flipx = ! flipx; + } + if (sy1 > sy2) + { + n = sy1; + sy1 = sy2; + sy2 = n; + flipy = ! flipy; + } + if (dx1 > dx2) + { + n = dx1; + dx1 = dx2; + dx2 = n; + flipx = ! flipx; + } + if (dy1 > dy2) + { + n = dy1; + dy1 = dy2; + dy2 = n; + flipy = ! flipy; + } + n = 0; + int sw = sx2 - sx1; // source width + int sh = sy2 - sy1; // source height + int[] pixels = new int[sw * sh]; // pixel buffer + int dw = dx2 - dx1; // destination width + int dh = dy2 - dy1; // destination height + double x_scale = ((double) dw) / ((double) sw); + double y_scale = ((double) dh) / ((double) sh); + + out.println("% drawImage() 2"); + out.println("gsave"); + out.println(dx1 + " " + dy1 + " translate"); + out.println(dw + " " + dh + " scale"); + out.println(sw + " " + sh + " 8 [" + (flipx ? -sw : sw) + " 0 0 " + + (flipy ? -sh : sh) + " " + (flipx ? sw : 0) + " " + + (flipy ? sh : 0) + " ]"); + out.println("{currentfile 3 string readhexstring pop} bind"); + out.println("false 3 colorimage"); + + PixelGrabber pg = new PixelGrabber(img, sx1, sy1, sw, sh, pixels, 0, sw); + try + { + pg.grabPixels(); + } + catch (InterruptedException e) + { + System.err.println("interrupted waiting for pixels!"); + return (false); + } + + if ((pg.getStatus() & ImageObserver.ABORT) != 0) + { + System.err.println("image fetch aborted or errored"); + return (false); + } + + for (int j = 0; j < sh; j++) + { + for (int i = 0; i < sw; i++) + { + out.print(colorTripleHex(new Color(pixels[j * sw + i]))); + if (((++n) % 11) == 0) + out.println(); + } + } + + out.println(); + out.println("%%EOF"); + out.println("grestore"); + return true; + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + ImageObserver observer) + { + return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, + observer); + } + + public boolean drawImage(Image img, int x, int y, ImageObserver observer) + { + return drawImage(img, x, y, null, observer); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, + Color bgcolor, ImageObserver observer) + { + int sw = img.getWidth(null); + int sh = img.getHeight(null); + return drawImage(img, x, y, x + width, y + height, /* destination */ + 0, 0, sw - 1, sh - 1, /* source */ + bgcolor, observer); + // correct? + } + + public boolean drawImage(Image img, int x, int y, int width, int height, + ImageObserver observer) + { + return drawImage(img, x, y, width, height, null, observer); + } + + /** Renders a BufferedImage that is filtered with a BufferedImageOp. */ + public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) + { + BufferedImage result = op.filter(img, null); + drawImage(result, x, y, null); + } + + /** Renders an image, applying a transform from image space + into user space before drawing. */ + public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) + { + AffineTransform oldTransform = new AffineTransform(currentTransform); + boolean ret; + + transform(xform); + ret = drawImage(img, 0, 0, null, obs); + setTransform(oldTransform); + + return ret; + } + + /** Renders a RenderableImage, applying a transform from image + space into user space before drawing. */ + public void drawRenderableImage(RenderableImage img, AffineTransform xform) + { + // FIXME + } + + /** Renders a RenderedImage, applying a transform from + image space into user space before drawing. */ + public void drawRenderedImage(RenderedImage img, AffineTransform xform) + { + // FIXME + } + + //------------------------------------------------------------------------- + public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) + { + setStroke(ordinaryStroke); + draw(new Polygon(xPoints, yPoints, nPoints)); + setStroke(currentStroke); + } + + public void drawString(String str, int x, int y) + { + drawString(str, (float) x, (float) y); + } + + public void drawString(String str, float x, float y) + { + if( str.trim().equals("") ) + return; // don't draw whitespace, silly! + + if( currentFontIsPS ) + { + drawStringPSFont(str, x, y); + return; + } + + TextLayout text = new TextLayout(str, currentFont, getFontRenderContext()); + Shape s = text.getOutline(AffineTransform.getTranslateInstance(x, y)); + drawStringShape(s); + } + + private void drawStringPSFont(String str, float x, float y) + { + out.println("% drawString PS font"); + out.println(x + " " + y + " moveto"); + saveAndInvertAxis(); + out.println("(" + str + ") show"); + restoreAxis(); + } + + private void saveAndInvertAxis() + { + // Invert the Y axis of the CTM. + popCTM(); + pushCTM(); + + double[] test = + { + pageTransform.getScaleX(), pageTransform.getShearY(), + pageTransform.getShearX(), pageTransform.getScaleY(), + pageTransform.getTranslateX(), + -pageTransform.getTranslateY() + pageY + }; + + double[] test2 = + { + currentTransform.getScaleX(), + currentTransform.getShearY(), + -currentTransform.getShearX(), + -currentTransform.getScaleY(), + currentTransform.getTranslateX(), + currentTransform.getTranslateY() + }; + + AffineTransform total = new AffineTransform(test); + total.concatenate(new AffineTransform(test2)); + concatCTM(total); + } + + private void restoreAxis() + { + // reset the CTM + popCTM(); + pushCTM(); + AffineTransform total = new AffineTransform(pageTransform); + total.concatenate(currentTransform); + concatCTM(total); + } + + /** + * special drawing routine for string shapes, + * which need to be drawn with the Y axis uninverted. + */ + private void drawStringShape(Shape s) + { + saveAndInvertAxis(); + + // draw the shape s with an inverted Y axis. + PathIterator pi = s.getPathIterator(new AffineTransform()); + float[] coords = new float[6]; + + while (! pi.isDone()) + { + switch (pi.currentSegment(coords)) + { + case PathIterator.SEG_MOVETO: + out.println((coords[0]) + " " + (Y - coords[1]) + " moveto"); + cx = coords[0]; + cy = coords[1]; + break; + case PathIterator.SEG_LINETO: + out.println((coords[0]) + " " + (Y - coords[1]) + " lineto"); + cx = coords[0]; + cy = coords[1]; + break; + case PathIterator.SEG_QUADTO: + // convert to cubic bezier points + float x1 = (cx + 2 * coords[0]) / 3; + float y1 = (cy + 2 * coords[1]) / 3; + float x2 = (2 * coords[2] + coords[0]) / 3; + float y2 = (2 * coords[3] + coords[1]) / 3; + + out.print((x1) + " " + (Y - y1) + " "); + out.print((x2) + " " + (Y - y2) + " "); + out.println((coords[2]) + " " + (Y - coords[3]) + " curveto"); + cx = coords[2]; + cy = coords[3]; + break; + case PathIterator.SEG_CUBICTO: + out.print((coords[0]) + " " + (Y - coords[1]) + " "); + out.print((coords[2]) + " " + (Y - coords[3]) + " "); + out.println((coords[4]) + " " + (Y - coords[5]) + " curveto"); + cx = coords[4]; + cy = coords[5]; + break; + case PathIterator.SEG_CLOSE: + out.println("closepath"); + break; + } + pi.next(); + } + out.println("fill"); + + restoreAxis(); + } + + public void setColor(Color c) + { + /* don't set the color if it's already set */ + if (c.equals(currentColor)) + return; + gradientOn = false; + currentColor = c; + currentPaint = c; // Graphics2D extends colors to paint + + out.println(colorTriple(c) + " setrgbcolor"); + } + + public void clearRect(int x, int y, int width, int height) + { + out.println("% clearRect"); + Color c = currentColor; + setColor(backgroundColor); + fill(new Rectangle2D.Double(x, y, width, height)); + setColor(c); + } + + public void clipRect(int x, int y, int width, int height) + { + clip(new Rectangle2D.Double(x, y, width, height)); + } + + public void copyArea(int x, int y, int width, int height, int dx, int dy) + { + // FIXME + } + + public void fillRect(int x, int y, int width, int height) + { + fill(new Rectangle2D.Double(x, y, width, height)); + } + + public void dispose() + { + } + + public void setClip(int x, int y, int width, int height) + { + out.println("% setClip()"); + setClip(new Rectangle2D.Double(x, y, width, height)); + } + + public void setClip(Shape s) + { + clip(s); + } + + public Shape getClip() + { + return clipShape; + } + + public Rectangle getClipBounds() + { + return clipShape.getBounds(); + } + + public Color getColor() + { + return currentColor; + } + + public Font getFont() + { + return currentFont; + } + + public FontMetrics getFontMetrics() + { + return getFontMetrics(currentFont); + } + + public FontMetrics getFontMetrics(Font f) + { + // FIXME + return null; + } + + public void setFont(Font font) + { + out.println("% setfont()"); + if (font == null) + // use the default font + font = new Font("Dialog", Font.PLAIN, 12); + currentFont = font; + setPSFont(); // set up the PostScript fonts + } + + /** + * Setup the postscript font if the current font is one + */ + private void setPSFont() + { + currentFontIsPS = false; + + String s = currentFont.getName(); + out.println("% setPSFont: Fontname: " + s); + if (s.equalsIgnoreCase("Helvetica") || s.equalsIgnoreCase("SansSerif")) + out.print("/helveticaISO findfont "); + else if (s.equalsIgnoreCase("Times New Roman")) + out.print("/timesISO findfont "); + else if (s.equalsIgnoreCase("Courier")) + out.print("/courierISO findfont "); + else + return; + + currentFontIsPS = true; + + out.print(currentFont.getSize() + " scalefont "); + out.println("setfont"); + } + + /** XOR mode is not supported */ + public void setPaintMode() + { + } + + /** XOR mode is not supported */ + public void setXORMode(Color c1) + { + } + + public void close() + { + out.println("showpage"); + out.println("%%Trailer"); + out.println("grestore % restore original stuff"); + out.println("%%EOF"); + + try + { + out.close(); + } + catch (Exception e) + { + } + out = null; + } + + //---------------------------------------------------------------- + // Graphics2D stuff ---------------------------------------------- + + /** Sets the values of an arbitrary number of + preferences for the rendering algorithms. */ + public void addRenderingHints(Map hints) + { + /* rendering hint changes are disallowed */ + } + + /** write a shape to the file */ + private void writeShape(Shape s) + { + PathIterator pi = s.getPathIterator(new AffineTransform()); + float[] coords = new float[6]; + + while (! pi.isDone()) + { + switch (pi.currentSegment(coords)) + { + case PathIterator.SEG_MOVETO: + out.println(coords[0] + " " + (coords[1]) + " moveto"); + cx = coords[0]; + cy = coords[1]; + break; + case PathIterator.SEG_LINETO: + out.println(coords[0] + " " + (coords[1]) + " lineto"); + cx = coords[0]; + cy = coords[1]; + break; + case PathIterator.SEG_QUADTO: + // convert to cubic bezier points + float x1 = (cx + 2 * coords[0]) / 3; + float y1 = (cy + 2 * coords[1]) / 3; + float x2 = (2 * coords[2] + coords[0]) / 3; + float y2 = (2 * coords[3] + coords[1]) / 3; + + out.print(x1 + " " + (Y - y1) + " "); + out.print(x2 + " " + (Y - y2) + " "); + out.println(coords[2] + " " + (Y - coords[3]) + " curveto"); + cx = coords[2]; + cy = coords[3]; + break; + case PathIterator.SEG_CUBICTO: + out.print(coords[0] + " " + coords[1] + " "); + out.print(coords[2] + " " + coords[3] + " "); + out.println(coords[4] + " " + coords[5] + " curveto"); + cx = coords[4]; + cy = coords[5]; + break; + case PathIterator.SEG_CLOSE: + out.println("closepath"); + break; + } + pi.next(); + } + } + + /** Intersects the current Clip with the interior of + the specified Shape and sets the Clip to the resulting intersection. */ + public void clip(Shape s) + { + clipShape = s; + out.println("% clip INACTIVE"); + // writeShape(s); + // out.println("clip"); + } + + /** Strokes the outline of a Shape using the + settings of the current Graphics2D context.*/ + public void draw(Shape s) + { + if(!(currentStroke instanceof BasicStroke)) + fill(currentStroke.createStrokedShape(s)); + + out.println("% draw"); + writeShape(s); + out.println("stroke"); + } + + /** Renders the text of the specified GlyphVector using the + Graphics2D context's rendering attributes. */ + public void drawGlyphVector(GlyphVector gv, float x, float y) + { + out.println("% drawGlyphVector"); + Shape s = gv.getOutline(); + drawStringShape(AffineTransform.getTranslateInstance(x, y) + .createTransformedShape(s)); + } + + /** Renders the text of the specified iterator, + using the Graphics2D context's current Paint.*/ + public void drawString(AttributedCharacterIterator iterator, float x, float y) + { + TextLayout text = new TextLayout(iterator, getFontRenderContext()); + Shape s = text.getOutline(AffineTransform.getTranslateInstance(x, y)); + drawStringShape(s); + } + + /** Renders the text of the specified iterator, + using the Graphics2D context's current Paint. */ + public void drawString(AttributedCharacterIterator iterator, int x, int y) + { + drawString(iterator, (float) x, (float) y); + } + + /** Fills the interior of a Shape using the settings of the Graphics2D context. */ + public void fill(Shape s) + { + out.println("% fill"); + if (! gradientOn) + { + writeShape(s); + out.println("fill"); + } + else + { + out.println("gsave"); + writeShape(s); + out.println("clip"); + writeGradient(); + out.println("shfill"); + out.println("grestore"); + } + } + + /** Returns the background color used for clearing a region. */ + public Color getBackground() + { + return backgroundColor; + } + + /** Returns the current Composite in the Graphics2D context. */ + public Composite getComposite() + { + // FIXME + return null; + } + + /** Returns the device configuration associated with this Graphics2D. */ + public GraphicsConfiguration getDeviceConfiguration() + { + // FIXME + out.println("% getDeviceConfiguration()"); + return null; + } + + /** Get the rendering context of the Font within this Graphics2D context. */ + public FontRenderContext getFontRenderContext() + { + out.println("% getFontRenderContext()"); + + double[] scaling = + { + pageTransform.getScaleX(), 0, 0, + -pageTransform.getScaleY(), 0, 0 + }; + + return (new FontRenderContext(new AffineTransform(scaling), false, true)); + } + + /** Returns the current Paint of the Graphics2D context. */ + public Paint getPaint() + { + return currentPaint; + } + + /** Returns the value of a single preference for the rendering algorithms. */ + public Object getRenderingHint(RenderingHints.Key hintKey) + { + return renderingHints.get(hintKey); + } + + /** Gets the preferences for the rendering algorithms. */ + public RenderingHints getRenderingHints() + { + return renderingHints; + } + + /** Returns the current Stroke in the Graphics2D context. */ + public Stroke getStroke() + { + return currentStroke; + } + + /** Returns a copy of the current Transform in the Graphics2D context. */ + public AffineTransform getTransform() + { + return currentTransform; + } + + /** + * Checks whether or not the specified Shape intersects + * the specified Rectangle, which is in device space. + */ + public boolean hit(Rectangle rect, Shape s, boolean onStroke) + { + Rectangle2D.Double r = new Rectangle2D.Double(rect.getX(), rect.getY(), + rect.getWidth(), + rect.getHeight()); + return s.intersects(r); + } + + /** Sets the background color for the Graphics2D context.*/ + public void setBackground(Color color) + { + out.println("% setBackground(" + color + ")"); + backgroundColor = color; + } + + /** Sets the Composite for the Graphics2D context. + Not supported. */ + public void setComposite(Composite comp) + { + } + + /** Sets the Paint attribute for the Graphics2D context.*/ + public void setPaint(Paint paint) + { + currentPaint = paint; + gradientOn = false; + if (paint instanceof Color) + { + setColor((Color) paint); + return; + } + if (paint instanceof GradientPaint) + { + gradientOn = true; + return; + } + } + + /* get a space seperated 0.0 - 1.0 color RGB triple */ + private String colorTriple(Color c) + { + return (((double) c.getRed() / 255.0) + " " + + ((double) c.getGreen() / 255.0) + " " + + ((double) c.getBlue() / 255.0)); + } + + /** + * Get a nonsperated hex RGB triple, eg FFFFFF = white + * used by writeGradient and drawImage + */ + private String colorTripleHex(Color c) + { + String r = "00" + Integer.toHexString(c.getRed()); + r = r.substring(r.length() - 2); + String g = "00" + Integer.toHexString(c.getGreen()); + g = g.substring(g.length() - 2); + String b = "00" + Integer.toHexString(c.getBlue()); + b = b.substring(b.length() - 2); + return r + g + b; + } + + /* write the current gradient fill */ + private void writeGradient() + { + GradientPaint paint = (GradientPaint) currentPaint; + out.println("% writeGradient()"); + + int n = 1; + double x; + double y; + double dx; + double dy; + Point2D p1 = currentTransform.transform(paint.getPoint1(), null); + Point2D p2 = currentTransform.transform(paint.getPoint2(), null); + x = p1.getX(); + y = p1.getY(); + dx = p2.getX() - x; + dy = p2.getY() - y; + + // get number of repetitions + while (x + n * dx < pageY && y + n * dy < pageX && x + n * dx > 0 + && y + n * dy > 0) + n++; + + out.println("<<"); // start + out.println("/ShadingType 2"); // gradient fill + out.println("/ColorSpace [ /DeviceRGB ]"); // RGB colors + out.print("/Coords ["); + out.print(x + " " + y + " " + (x + n * dx) + " " + (y + n * dy) + " "); + out.println("]"); // coordinates defining the axis + out.println("/Function <<"); + out.println("/FunctionType 0"); + out.println("/Order 1"); + out.println("/Domain [ 0 1 ]"); + out.println("/Range [ 0 1 0 1 0 1 ]"); + out.println("/BitsPerSample 8"); + out.println("/Size [ " + (1 + n) + " ]"); + out.print("/DataSource < " + colorTripleHex(paint.getColor1()) + " " + + colorTripleHex(paint.getColor2()) + " "); + for (; n > 1; n--) + if (paint.isCyclic()) + { + if ((n % 2) == 1) + out.print(colorTripleHex(paint.getColor1()) + " "); + else + out.print(colorTripleHex(paint.getColor2()) + " "); + } + else + out.print(colorTripleHex(paint.getColor2()) + " "); + out.println(">"); + out.println(">>"); + out.println(">>"); + } + + /** Sets the value of a single preference for the rendering algorithms. */ + public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) + { + /* we don't allow the changing of rendering hints. */ + } + + /** Replaces the values of all preferences for the rendering algorithms + with the specified hints. */ + public void setRenderingHints(Map hints) + { + /* we don't allow the changing of rendering hints. */ + } + + /** + * Sets the Stroke for the Graphics2D context. BasicStroke fully implemented. + */ + public void setStroke(Stroke s) + { + currentStroke = s; + + if (! (s instanceof BasicStroke)) + return; + + BasicStroke bs = (BasicStroke) s; + out.println("% setStroke()"); + try + { + // set the line width + out.println(bs.getLineWidth() + " setlinewidth"); + + // set the line dash + float[] dashArray = bs.getDashArray(); + if (dashArray != null) + { + out.print("[ "); + for (int i = 0; i < dashArray.length; i++) + out.print(dashArray[i] + " "); + out.println("] " + bs.getDashPhase() + " setdash"); + } + else + out.println("[] 0 setdash"); // set solid + + // set the line cap + switch (bs.getEndCap()) + { + case BasicStroke.CAP_BUTT: + out.println("0 setlinecap"); + break; + case BasicStroke.CAP_ROUND: + out.println("1 setlinecap"); + break; + case BasicStroke.CAP_SQUARE: + out.println("2 setlinecap"); + break; + } + + // set the line join + switch (bs.getLineJoin()) + { + case BasicStroke.JOIN_BEVEL: + out.println("2 setlinejoin"); + break; + case BasicStroke.JOIN_MITER: + out.println("0 setlinejoin"); + out.println(bs.getMiterLimit() + " setmiterlimit"); + break; + case BasicStroke.JOIN_ROUND: + out.println("1 setlinejoin"); + break; + } + } + catch (Exception e) + { + out.println("% Exception in setStroke()"); + } + } + + //////////////////// TRANSFORM SETTING ///////////////////////////////////// + private void concatCTM(AffineTransform Tx) + { + double[] matrixElements = new double[6]; + Tx.getMatrix(matrixElements); + + out.print("[ "); + for (int i = 0; i < 6; i++) + out.print(matrixElements[i] + " "); + out.println("] concat"); + } + + /** Sets the Transform in the Graphics2D context. */ + public void setTransform(AffineTransform Tx) + { + // set the transformation matrix; + currentTransform = Tx; + + // concatenate the current transform and the page transform + AffineTransform totalTransform = new AffineTransform(pageTransform); + totalTransform.concatenate(currentTransform); + out.println("% setTransform()"); + out.println("% pageTransform:" + pageTransform); + out.println("% currentTransform:" + currentTransform); + out.println("% totalTransform:" + totalTransform); + + popCTM(); + pushCTM(); // set the CTM to it's original state + concatCTM(totalTransform); // apply our transforms + } + + /** Composes an AffineTransform object with the Transform + in this Graphics2D according to the rule last-specified-first-applied. */ + public void transform(AffineTransform Tx) + { + // concatenate the current transform + currentTransform.concatenate(Tx); + // and the PS CTM + concatCTM(Tx); + } + + ////////////////////////// TRANSFORMS ////////////////////////////////////// + + /** shear transform */ + public void shear(double shx, double shy) + { + out.println("% shear()"); + AffineTransform Tx = new AffineTransform(); + Tx.shear(shx, shy); + transform(Tx); + } + + /** Translates the origin of the Graphics2D context + to the point (x, y) in the current coordinate system. */ + public void translate(int x, int y) + { + out.println("% translate()"); + AffineTransform Tx = new AffineTransform(); + Tx.translate(x, y); + transform(Tx); + } + + /** Translates the origin of the Graphics2D context + to the point (x, y) in the current coordinate system. */ + public void translate(double x, double y) + { + out.println("% translate(" + x + ", " + y + ")"); + AffineTransform Tx = new AffineTransform(); + Tx.translate(x, y); + transform(Tx); + } + + /** Concatenates the current Graphics2D Transform with a rotation transform.*/ + public void rotate(double theta) + { + out.println("% rotate(" + theta + ")"); + AffineTransform Tx = new AffineTransform(); + Tx.rotate(theta); + transform(Tx); + } + + /** Concatenates the current Graphics2D Transform with + a translated rotation transform.*/ + public void rotate(double theta, double x, double y) + { + out.println("% rotate()"); + AffineTransform Tx = new AffineTransform(); + Tx.rotate(theta, x, y); + transform(Tx); + } + + /** Concatenates the current Graphics2D Transform with a scaling + transformation Subsequent rendering is resized according to the + specified scaling factors relative to the previous scaling.*/ + public void scale(double sx, double sy) + { + out.println("% scale(" + sx + ", " + sy + ")"); + AffineTransform Tx = new AffineTransform(); + Tx.scale(sx, sy); + transform(Tx); + } +} diff --git a/gnu/java/awt/print/SpooledDocument.java b/gnu/java/awt/print/SpooledDocument.java new file mode 100644 index 000000000..b606a2ef6 --- /dev/null +++ b/gnu/java/awt/print/SpooledDocument.java @@ -0,0 +1,91 @@ +/* SpooledDocument.java -- Reurgitate a spooled PostScript file + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.print; + +import javax.print.Doc; +import javax.print.DocFlavor; +import javax.print.attribute.DocAttributeSet; +import java.io.File; +import java.io.IOException; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.Reader; +import java.io.InputStream; +import java.io.InputStreamReader; + +public class SpooledDocument implements Doc +{ + private FileInputStream fis; + + public SpooledDocument(File file) + { + try + { + fis = new FileInputStream(file); + } + catch (FileNotFoundException ffne) + { + // Shouldn't happen. + } + } + + public DocAttributeSet getAttributes() + { + return null; + } + + public DocFlavor getDocFlavor() + { + return DocFlavor.INPUT_STREAM.POSTSCRIPT; + } + + public Object getPrintData() + { + return fis; + } + + public Reader getReaderForText() + { + return new InputStreamReader(fis); + } + + public InputStream getStreamForBytes() + { + return fis; + } +} diff --git a/gnu/java/net/IndexListParser.java b/gnu/java/net/IndexListParser.java new file mode 100644 index 000000000..23d2aa660 --- /dev/null +++ b/gnu/java/net/IndexListParser.java @@ -0,0 +1,177 @@ +/* IndexListParser.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.jar.JarFile; + +/** + * The INDEX.LIST file contains sections each separated by a blank line. + * Each section defines the content of a jar, with a + * header defining the jar file path name, followed by a list of paths. + * The jar file paths are relative to the codebase of the root jar. + * + Specification + index file : version-info blankline section* + version-info : JarIndex-Version: version-number + version-number : digit+{.digit+}* + section : body blankline + body : header name* + header : char+.jar newline + name : char+ newline + + * @author langel at redhat dot com + */ +public class IndexListParser +{ + public static final String JAR_INDEX_FILE = "META-INF/INDEX.LIST"; + public static final String JAR_INDEX_VERSION_KEY = "JarIndex-Version: "; + + double versionNumber; + // Map each jar to the prefixes defined for the jar. + // This is intentionally kept in insertion order. + LinkedHashMap prefixes = new LinkedHashMap(); + + /** + * Parses the given jarfile's INDEX.LIST file if it exists. + * + * @param jarfile - the given jar file + * @param baseJarURL - the codebase of the jar file + * @param baseURL - the base url for the headers + */ + public IndexListParser(JarFile jarfile, URL baseJarURL, URL baseURL) + { + try + { + // Parse INDEX.LIST if it exists + if (jarfile.getEntry(JAR_INDEX_FILE) != null) + { + BufferedReader br = new BufferedReader(new InputStreamReader(new URL(baseJarURL, + JAR_INDEX_FILE).openStream())); + + // Must start with version info + String line = br.readLine(); + if (!line.startsWith(JAR_INDEX_VERSION_KEY)) + return; + versionNumber = Double.parseDouble(line.substring(JAR_INDEX_VERSION_KEY.length()).trim()); + + // Blank line must be next + line = br.readLine(); + if (! "".equals(line)) + { + clearAll(); + return; + } + + // May contain sections. + while ((line = br.readLine()) != null) + { + URL jarURL = new URL(baseURL, line); + HashSet values = new HashSet(); + + // Read the names in the section. + while ((line = br.readLine()) != null) + { + // Stop at section boundary. + if ("".equals(line)) + break; + values.add(line.trim()); + } + prefixes.put(jarURL, values); + // Might have seen an early EOF. + if (line == null) + break; + } + + br.close(); + } + // else INDEX.LIST does not exist + } + catch (Exception ex) + { + clearAll(); + } + } + + /** + * Clears all the variables. This is called when parsing fails. + */ + void clearAll() + { + versionNumber = 0; + prefixes = null; + } + + /** + * Gets the version info for the file. + * + * @return the version info. + */ + public String getVersionInfo() + { + return JAR_INDEX_VERSION_KEY + getVersionNumber(); + } + + /** + * Gets the version number of the file. + * + * @return the version number. + */ + public double getVersionNumber() + { + return versionNumber; + } + + /** + * Gets the map of all the headers found in the file. + * The keys in the map are URLs of jars. The values in the map + * are Sets of package prefixes (and top-level file names), as + * specifed in INDEX.LIST. + * + * @return an map of all the headers, or null if no INDEX.LIST was found + */ + public LinkedHashMap getHeaders() + { + return prefixes; + } +} diff --git a/gnu/java/net/loader/FileResource.java b/gnu/java/net/loader/FileResource.java new file mode 100644 index 000000000..8071bbf91 --- /dev/null +++ b/gnu/java/net/loader/FileResource.java @@ -0,0 +1,82 @@ +/* FileResource.java -- a Resource for file URLs + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.loader; + + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; + +public final class FileResource extends Resource +{ + final File file; + + public FileResource(FileURLLoader loader, File file) + { + super(loader); + this.file = file; + } + + public InputStream getInputStream() throws IOException + { + return new FileInputStream(file); + } + + public int getLength() + { + return (int) file.length(); + } + + public URL getURL() + { + try + { + return file.toURL(); + } + catch (MalformedURLException e) + { + InternalError ie = new InternalError(); + ie.initCause(e); + throw ie; + } + } +}
\ No newline at end of file diff --git a/gnu/java/net/loader/FileURLLoader.java b/gnu/java/net/loader/FileURLLoader.java new file mode 100644 index 000000000..39d33a4e4 --- /dev/null +++ b/gnu/java/net/loader/FileURLLoader.java @@ -0,0 +1,145 @@ +/* FileURLLoader.java -- a URLLoader for file URLs + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.loader; + + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.URLStreamHandlerFactory; +import java.util.StringTokenizer; + +/** + * A <code>FileURLLoader</code> is a type of <code>URLLoader</code> + * only loading from file url. + */ +public final class FileURLLoader extends URLLoader +{ + File dir; //the file for this file url + + public FileURLLoader(URLClassLoader classloader, + URLStreamHandlerCache cache, + URLStreamHandlerFactory factory, + URL url, URL absoluteUrl) + { + super(classloader, cache, factory, url, absoluteUrl); + dir = new File(absoluteUrl.getFile()); + } + + /** get resource with the name "name" in the file url */ + public Resource getResource(String name) + { + try + { + // Make sure that all components in name are valid by walking through + // them + File file = walkPathComponents(name); + + if (file == null) + return null; + + return new FileResource(this, file); + } + catch (IOException e) + { + // Fall through... + } + return null; + } + + /** + * Walk all path tokens and check them for validity. At no moment, we are + * allowed to reach a directory located "above" the root directory, stored + * in "dir" property. We are also not allowed to enter a non existing + * directory or a non directory component (plain file, symbolic link, ...). + * An empty or null path is valid. Pathnames components are separated by + * <code>File.separatorChar</code> + * + * @param resourceFileName the name to be checked for validity. + * @return the canonical file pointed by the resourceFileName or null if the + * walking failed + * @throws IOException in case of issue when creating the canonical + * resulting file + * @see File#separatorChar + */ + private File walkPathComponents(String resourceFileName) throws IOException + { + StringTokenizer stringTokenizer = new StringTokenizer(resourceFileName, File.separator); + File currentFile = dir; + int tokenCount = stringTokenizer.countTokens(); + + for (int i = 0; i < tokenCount - 1; i++) + { + String currentToken = stringTokenizer.nextToken(); + + // If we are at the root directory and trying to go up, the walking is + // finished with an error + if ("..".equals(currentToken) && currentFile.equals(dir)) + return null; + + currentFile = new File(currentFile, currentToken); + + // If the current file doesn't exist or is not a directory, the walking is + // finished with an error + if (! (currentFile.exists() && currentFile.isDirectory())) + return null; + + } + + // Treat the last token differently, if it exists, because it does not need + // to be a directory + if (tokenCount > 0) + { + String currentToken = stringTokenizer.nextToken(); + + if ("..".equals(currentToken) && currentFile.equals(dir)) + return null; + + currentFile = new File(currentFile, currentToken); + + // If the current file doesn't exist, the walking is + // finished with an error + if (! currentFile.exists()) + return null; + } + + return currentFile.getCanonicalFile(); + } +}
\ No newline at end of file diff --git a/gnu/java/net/loader/JarURLLoader.java b/gnu/java/net/loader/JarURLLoader.java new file mode 100644 index 000000000..130c6fc95 --- /dev/null +++ b/gnu/java/net/loader/JarURLLoader.java @@ -0,0 +1,209 @@ +package gnu.java.net.loader; + +import gnu.java.net.IndexListParser; + +import java.io.IOException; +import java.net.JarURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.URLStreamHandlerFactory; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + +/** + * A <code>JarURLLoader</code> is a type of <code>URLLoader</code> + * only loading from jar url. + */ +public final class JarURLLoader extends URLLoader +{ + // True if we've initialized -- i.e., tried open the jar file. + boolean initialized; + // The jar file for this url. + JarFile jarfile; + // Base jar: url for all resources loaded from jar. + final URL baseJarURL; + // The "Class-Path" attribute of this Jar's manifest. + ArrayList classPath; + // If not null, a mapping from INDEX.LIST for this jar only. + // This is a set of all prefixes and top-level files that + // ought to be available in this jar. + Set indexSet; + + // This constructor is used internally. It purposely does not open + // the jar file -- it defers this until later. This allows us to + // implement INDEX.LIST lazy-loading semantics. + private JarURLLoader(URLClassLoader classloader, URLStreamHandlerCache cache, + URLStreamHandlerFactory factory, + URL baseURL, URL absoluteUrl, + Set indexSet) + { + super(classloader, cache, factory, baseURL, absoluteUrl); + + URL newBaseURL = null; + try + { + // Cache url prefix for all resources in this jar url. + String base = baseURL.toExternalForm() + "!/"; + newBaseURL = new URL("jar", "", -1, base, cache.get(factory, "jar")); + } + catch (MalformedURLException ignore) + { + // Ignore. + } + this.baseJarURL = newBaseURL; + this.classPath = null; + this.indexSet = indexSet; + } + + // This constructor is used by URLClassLoader. It will immediately + // try to read the jar file, in case we've found an index or a class-path + // setting. FIXME: it would be nice to defer this as well, but URLClassLoader + // makes this hard. + public JarURLLoader(URLClassLoader classloader, URLStreamHandlerCache cache, + URLStreamHandlerFactory factory, + URL baseURL, URL absoluteUrl) + { + this(classloader, cache, factory, baseURL, absoluteUrl, null); + initialize(); + } + + private void initialize() + { + JarFile jarfile = null; + try + { + jarfile = + ((JarURLConnection) baseJarURL.openConnection()).getJarFile(); + + Manifest manifest; + Attributes attributes; + String classPathString; + + IndexListParser parser = new IndexListParser(jarfile, baseJarURL, + baseURL); + LinkedHashMap indexMap = parser.getHeaders(); + if (indexMap != null) + { + // Note that the index also computes + // the resulting Class-Path -- there are jars out there + // where the index lists some required jars which do + // not appear in the Class-Path attribute in the manifest. + this.classPath = new ArrayList(); + Iterator it = indexMap.entrySet().iterator(); + while (it.hasNext()) + { + LinkedHashMap.Entry entry = (LinkedHashMap.Entry) it.next(); + URL subURL = (URL) entry.getKey(); + Set prefixes = (Set) entry.getValue(); + if (subURL.equals(baseURL)) + this.indexSet = prefixes; + else + { + JarURLLoader subLoader = new JarURLLoader(classloader, + cache, + factory, subURL, + subURL, + prefixes); + // Note that we don't care if the sub-loader itself has an + // index or a class-path -- only the top-level jar + // file gets this treatment; its index should cover + // everything. + this.classPath.add(subLoader); + } + } + } + else if ((manifest = jarfile.getManifest()) != null + && (attributes = manifest.getMainAttributes()) != null + && ((classPathString + = attributes.getValue(Attributes.Name.CLASS_PATH)) + != null)) + { + this.classPath = new ArrayList(); + StringTokenizer st = new StringTokenizer(classPathString, " "); + while (st.hasMoreElements ()) + { + String e = st.nextToken (); + try + { + URL subURL = new URL(baseURL, e); + JarURLLoader subLoader = new JarURLLoader(classloader, + cache, factory, + subURL, subURL); + this.classPath.add(subLoader); + ArrayList extra = subLoader.getClassPath(); + if (extra != null) + this.classPath.addAll(extra); + } + catch (java.net.MalformedURLException xx) + { + // Give up + } + } + } + } + catch (IOException ioe) + { + /* ignored */ + } + + this.jarfile = jarfile; + this.initialized = true; + } + + /** get resource with the name "name" in the jar url */ + public Resource getResource(String name) + { + if (name.startsWith("/")) + name = name.substring(1); + if (indexSet != null) + { + // Trust the index. + String basename = name; + int offset = basename.lastIndexOf('/'); + if (offset != -1) + basename = basename.substring(0, offset); + if (! indexSet.contains(basename)) + return null; + // FIXME: if the index claim to hold the resource, and jar file + // doesn't have it, we're supposed to throw an exception. However, + // in our model this is tricky to implement, as another URLLoader from + // the same top-level jar may have an overlapping index entry. + } + + if (! initialized) + initialize(); + if (jarfile == null) + return null; + + JarEntry je = jarfile.getJarEntry(name); + if (je != null) + return new JarURLResource(this, name, je); + else + return null; + } + + public Manifest getManifest() + { + try + { + return (jarfile == null) ? null : jarfile.getManifest(); + } + catch (IOException ioe) + { + return null; + } + } + + public ArrayList getClassPath() + { + return classPath; + } +}
\ No newline at end of file diff --git a/gnu/java/net/loader/JarURLResource.java b/gnu/java/net/loader/JarURLResource.java new file mode 100644 index 000000000..a9db5ce0b --- /dev/null +++ b/gnu/java/net/loader/JarURLResource.java @@ -0,0 +1,94 @@ +/* JarURLResource.java -- a Resource for jar URLs + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.loader; + + +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.cert.Certificate; +import java.util.jar.JarEntry; + +public final class JarURLResource extends Resource +{ + private final JarEntry entry; + private final String name; + + public JarURLResource(JarURLLoader loader, String name, JarEntry entry) + { + super(loader); + this.entry = entry; + this.name = name; + } + + public InputStream getInputStream() throws IOException + { + return ((JarURLLoader) loader).jarfile.getInputStream(entry); + } + + public int getLength() + { + return (int) entry.getSize(); + } + + public Certificate[] getCertificates() + { + // We have to get the entry from the jar file again, because the + // certificates will not be available until the entire entry has + // been read. + return ((JarEntry) ((JarURLLoader) loader).jarfile.getEntry(name)) + .getCertificates(); + } + + public URL getURL() + { + try + { + return new URL(((JarURLLoader) loader).baseJarURL, name, + loader.cache.get(loader.factory, "jar")); + } + catch (MalformedURLException e) + { + InternalError ie = new InternalError(); + ie.initCause(e); + throw ie; + } + } +}
\ No newline at end of file diff --git a/gnu/java/net/loader/RemoteResource.java b/gnu/java/net/loader/RemoteResource.java new file mode 100644 index 000000000..f18031581 --- /dev/null +++ b/gnu/java/net/loader/RemoteResource.java @@ -0,0 +1,78 @@ +/* Resource.java -- a Resource for "remote" URLs + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.loader; + + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +/** + * A resource from some remote location. + */ +public final class RemoteResource extends Resource +{ + private final URL url; + private final InputStream stream; + final int length; + + public RemoteResource(RemoteURLLoader loader, String name, URL url, + InputStream stream, int length) + { + super(loader); + this.url = url; + this.stream = stream; + this.length = length; + } + + public InputStream getInputStream() throws IOException + { + return stream; + } + + public int getLength() + { + return length; + } + + public URL getURL() + { + return url; + } +}
\ No newline at end of file diff --git a/gnu/java/net/loader/RemoteURLLoader.java b/gnu/java/net/loader/RemoteURLLoader.java new file mode 100644 index 000000000..f044740fa --- /dev/null +++ b/gnu/java/net/loader/RemoteURLLoader.java @@ -0,0 +1,101 @@ +/* RemoteURLLoader.java -- a URLLoader for "remote" objects + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.loader; + + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.URLConnection; +import java.net.URLStreamHandlerFactory; + +/** + * Loader for remote directories. + */ +public final class RemoteURLLoader extends URLLoader +{ + private final String protocol; + + public RemoteURLLoader(URLClassLoader classloader, + URLStreamHandlerCache cache, + URLStreamHandlerFactory factory, + URL url) + { + super(classloader, cache, factory, url); + protocol = url.getProtocol(); + } + + /** + * Get a remote resource. + * Returns null if no such resource exists. + */ + public Resource getResource(String name) + { + try + { + URL url = new URL(baseURL, name, cache.get(factory, protocol)); + URLConnection connection = url.openConnection(); + + // Open the connection and check the stream + // just to be sure it exists. + int length = connection.getContentLength(); + InputStream stream = connection.getInputStream(); + + // We can do some extra checking if it is a http request + if (connection instanceof HttpURLConnection) + { + int response = + ((HttpURLConnection) connection).getResponseCode(); + if (response / 100 != 2) + return null; + } + + if (stream != null) + return new RemoteResource(this, name, url, stream, length); + else + return null; + } + catch (IOException ioe) + { + return null; + } + } +}
\ No newline at end of file diff --git a/gnu/java/net/loader/Resource.java b/gnu/java/net/loader/Resource.java new file mode 100644 index 000000000..e367a3388 --- /dev/null +++ b/gnu/java/net/loader/Resource.java @@ -0,0 +1,110 @@ +/* Resource.java -- a resource for URLLoader + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.loader; + + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.security.CodeSource; +import java.security.cert.Certificate; + +/** + * A <code>Resource</code> represents a resource in some + * <code>URLLoader</code>. It also contains all information (e.g., + * <code>URL</code>, <code>CodeSource</code>, <code>Manifest</code> and + * <code>InputStream</code>) that is necessary for loading resources + * and creating classes from a <code>URL</code>. + */ +public abstract class Resource +{ + final URLLoader loader; + + public Resource(URLLoader loader) + { + this.loader = loader; + } + + /** + * Returns the non-null <code>CodeSource</code> associated with + * this resource. + */ + public CodeSource getCodeSource() + { + Certificate[] certs = getCertificates(); + if (certs == null) + return loader.noCertCodeSource; + else + return new CodeSource(loader.baseURL, certs); + } + + /** + * Returns <code>Certificates</code> associated with this + * resource, or null when there are none. + */ + public Certificate[] getCertificates() + { + return null; + } + + /** + * Return the URLLoader for this resource. + */ + public final URLLoader getLoader() + { + return loader; + } + + /** + * Return a <code>URL</code> that can be used to access this resource. + */ + public abstract URL getURL(); + + /** + * Returns the size of this <code>Resource</code> in bytes or + * <code>-1</code> when unknown. + */ + public abstract int getLength(); + + /** + * Returns the non-null <code>InputStream</code> through which + * this resource can be loaded. + */ + public abstract InputStream getInputStream() throws IOException; +}
\ No newline at end of file diff --git a/gnu/java/net/loader/URLLoader.java b/gnu/java/net/loader/URLLoader.java new file mode 100644 index 000000000..d073c5429 --- /dev/null +++ b/gnu/java/net/loader/URLLoader.java @@ -0,0 +1,147 @@ +/* URLLoader.java -- base helper class for URLClassLoader + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.loader; + +import java.net.URL; +import java.net.URLClassLoader; +import java.net.URLStreamHandlerFactory; +import java.security.CodeSource; +import java.util.ArrayList; +import java.util.jar.Manifest; + +/** + * A <code>URLLoader</code> contains all logic to load resources from a + * given base <code>URL</code>. + */ +public abstract class URLLoader +{ + /** + * Our classloader to get info from if needed. + */ + final URLClassLoader classloader; + + /** + * The base URL from which all resources are loaded. + */ + final URL baseURL; + + /** + * The stream handler factory. + */ + final URLStreamHandlerFactory factory; + + /** + * The source for stream handlers. + */ + final URLStreamHandlerCache cache; + + /** + * A <code>CodeSource</code> without any associated certificates. + * It is common for classes to not have certificates associated + * with them. If they come from the same <code>URLLoader</code> + * then it is safe to share the associated <code>CodeSource</code> + * between them since <code>CodeSource</code> is immutable. + */ + final CodeSource noCertCodeSource; + + public URLLoader(URLClassLoader classloader, URLStreamHandlerCache cache, + URLStreamHandlerFactory factory, + URL baseURL) + { + this(classloader, cache, factory, baseURL, baseURL); + } + + public URLLoader(URLClassLoader classloader, URLStreamHandlerCache cache, + URLStreamHandlerFactory factory, + URL baseURL, URL overrideURL) + { + this.classloader = classloader; + this.baseURL = baseURL; + this.factory = factory; + this.cache = cache; + this.noCertCodeSource = new CodeSource(overrideURL, null); + } + + /** + * Return the base URL of this loader. + */ + public final URL getBaseURL() + { + return baseURL; + } + + /** + * Returns a <code>Class</code> loaded by this + * <code>URLLoader</code>, or <code>null</code> when this loader + * either can't load the class or doesn't know how to load classes + * at all. Most subclasses do not need to override this; it is only + * useful in situations where the subclass has a more direct way of + * making <code>Class</code> objects. + */ + public Class getClass(String className) + { + return null; + } + + /** + * Returns a <code>Resource</code> loaded by this + * <code>URLLoader</code>, or <code>null</code> when no + * <code>Resource</code> with the given name exists. + */ + public abstract Resource getResource(String s); + + /** + * Returns the <code>Manifest</code> associated with the + * <code>Resource</code>s loaded by this <code>URLLoader</code> or + * <code>null</code> there is no such <code>Manifest</code>. + */ + public Manifest getManifest() + { + return null; + } + + /** + * Return a list of new URLLoader objects representing any + * class path entries added by this container. + */ + public ArrayList getClassPath() + { + return null; + } +}
\ No newline at end of file diff --git a/gnu/java/net/loader/URLStreamHandlerCache.java b/gnu/java/net/loader/URLStreamHandlerCache.java new file mode 100644 index 000000000..295a15d2b --- /dev/null +++ b/gnu/java/net/loader/URLStreamHandlerCache.java @@ -0,0 +1,84 @@ +/* URLStreamHandlerCache.java -- a cache for URLStreamHandlers + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.loader; + +import java.net.URLStreamHandler; +import java.net.URLStreamHandlerFactory; +import java.util.HashMap; + +/** + */ +public class URLStreamHandlerCache +{ + /** + * A cache to store mappings between handler factory and its + * private protocol handler cache (also a HashMap), so we can avoid + * creating handlers each time the same protocol comes. + */ + private HashMap factoryCache = new HashMap(5); + + public URLStreamHandlerCache() + { + } + + public synchronized void add(URLStreamHandlerFactory factory) + { + // Since we only support three protocols so far, 5 is enough + // for cache initial size. + if (factory != null && factoryCache.get(factory) == null) + factoryCache.put(factory, new HashMap(5)); + } + + public synchronized URLStreamHandler get(URLStreamHandlerFactory factory, + String protocol) + { + if (factory == null) + return null; + // Check if there're handler for the same protocol in cache. + HashMap cache = (HashMap) factoryCache.get(factory); + URLStreamHandler handler = (URLStreamHandler) cache.get(protocol); + if (handler == null) + { + // Add it to cache. + handler = factory.createURLStreamHandler(protocol); + cache.put(protocol, handler); + } + return handler; + } +} diff --git a/gnu/java/net/protocol/http/HTTPConnection.java b/gnu/java/net/protocol/http/HTTPConnection.java index 33d9756aa..f5e831c6a 100644 --- a/gnu/java/net/protocol/http/HTTPConnection.java +++ b/gnu/java/net/protocol/http/HTTPConnection.java @@ -466,7 +466,8 @@ public class HTTPConnection */ synchronized HTTPConnection get(String host, int port, - boolean secure) + boolean secure, + int connectionTimeout, int timeout) { String ttl = SystemProperties.getProperty("classpath.net.http.keepAliveTTL"); @@ -494,7 +495,7 @@ public class HTTPConnection } if (c == null) { - c = new HTTPConnection(host, port, secure); + c = new HTTPConnection(host, port, secure, connectionTimeout, timeout); c.setPool(this); } return c; diff --git a/gnu/java/net/protocol/http/HTTPURLConnection.java b/gnu/java/net/protocol/http/HTTPURLConnection.java index 0dce7c75b..a46d1204b 100644 --- a/gnu/java/net/protocol/http/HTTPURLConnection.java +++ b/gnu/java/net/protocol/http/HTTPURLConnection.java @@ -65,7 +65,7 @@ import javax.net.ssl.SSLSocketFactory; * @author Chris Burdess (dog@gnu.org) */ public class HTTPURLConnection - extends HttpsURLConnection + extends HttpsURLConnection implements HandshakeCompletedListener { /* @@ -346,11 +346,11 @@ public class HTTPURLConnection HTTPConnection connection; if (keepAlive) { - connection = HTTPConnection.Pool.instance.get(host, port, secure); + connection = HTTPConnection.Pool.instance.get(host, port, secure, getConnectTimeout(), 0); } else { - connection = new HTTPConnection(host, port, secure); + connection = new HTTPConnection(host, port, secure, 0, getConnectTimeout()); } return connection; } @@ -653,5 +653,27 @@ public class HTTPURLConnection handshakeEvent = event; } + /** + * Set the connection timeout speed, in milliseconds, or zero if the timeout + * is to be considered infinite. + * + * Overloaded. + * + */ + public void setConnectTimeout(int timeout) + throws IllegalArgumentException + { + super.setConnectTimeout( timeout ); + if( connection == null ) + return; + try + { + connection.getSocket().setSoTimeout( timeout ); + } + catch(IOException se) + { + // Ignore socket exceptions. + } + } } diff --git a/gnu/java/net/protocol/jar/Connection.java b/gnu/java/net/protocol/jar/Connection.java index 41c5d6dcf..f99806ae4 100644 --- a/gnu/java/net/protocol/jar/Connection.java +++ b/gnu/java/net/protocol/jar/Connection.java @@ -188,7 +188,7 @@ public final class Connection extends JarURLConnection else if (field.equals("last-modified")) { // Both creating and manipulating dateFormat need synchronization. - synchronized (this.getClass()) + synchronized (Connection.class) { if (dateFormat == null) dateFormat = new SimpleDateFormat diff --git a/gnu/java/nio/PipeImpl.java b/gnu/java/nio/PipeImpl.java index f7b01c8b7..cccaa3988 100644 --- a/gnu/java/nio/PipeImpl.java +++ b/gnu/java/nio/PipeImpl.java @@ -37,6 +37,7 @@ exception statement from your version. */ package gnu.java.nio; + import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.Pipe; @@ -47,12 +48,14 @@ class PipeImpl extends Pipe public static final class SourceChannelImpl extends Pipe.SourceChannel { private int native_fd; + private VMChannel vmch; public SourceChannelImpl (SelectorProvider selectorProvider, int native_fd) { super (selectorProvider); this.native_fd = native_fd; + vmch = VMChannel.getVMChannel(this); } protected final void implCloseSelectableChannel() @@ -64,19 +67,19 @@ class PipeImpl extends Pipe protected void implConfigureBlocking (boolean blocking) throws IOException { - throw new Error ("Not implemented"); + vmch.setBlocking(blocking); } public final int read (ByteBuffer src) throws IOException { - throw new Error ("Not implemented"); + return vmch.read(src); } public final long read (ByteBuffer[] srcs) throws IOException { - return read (srcs, 0, srcs.length); + return vmch.readScattering(srcs, 0, srcs.length); } public final synchronized long read (ByteBuffer[] srcs, int offset, @@ -89,13 +92,7 @@ class PipeImpl extends Pipe || len > srcs.length - offset) throw new IndexOutOfBoundsException(); - long bytesRead = 0; - - for (int index = 0; index < len; index++) - bytesRead += read (srcs [offset + index]); - - return bytesRead; - + return vmch.readScattering(srcs, offset, len); } public final int getNativeFD() @@ -107,12 +104,14 @@ class PipeImpl extends Pipe public static final class SinkChannelImpl extends Pipe.SinkChannel { private int native_fd; + private VMChannel vmch; public SinkChannelImpl (SelectorProvider selectorProvider, int native_fd) { super (selectorProvider); this.native_fd = native_fd; + vmch = VMChannel.getVMChannel(this); } protected final void implCloseSelectableChannel() @@ -124,19 +123,19 @@ class PipeImpl extends Pipe protected final void implConfigureBlocking (boolean blocking) throws IOException { - throw new Error ("Not implemented"); + vmch.setBlocking(blocking); } public final int write (ByteBuffer dst) throws IOException { - throw new Error ("Not implemented"); + return vmch.write(dst); } public final long write (ByteBuffer[] srcs) throws IOException { - return write (srcs, 0, srcs.length); + return vmch.writeGathering(srcs, 0, srcs.length); } public final synchronized long write (ByteBuffer[] srcs, int offset, int len) @@ -147,13 +146,8 @@ class PipeImpl extends Pipe || len < 0 || len > srcs.length - offset) throw new IndexOutOfBoundsException(); - - long bytesWritten = 0; - for (int index = 0; index < len; index++) - bytesWritten += write (srcs [offset + index]); - - return bytesWritten; + return vmch.writeGathering(srcs, offset, len); } public final int getNativeFD() diff --git a/gnu/java/nio/SelectorImpl.java b/gnu/java/nio/SelectorImpl.java index 5d4e93156..ecfb5e7dc 100644 --- a/gnu/java/nio/SelectorImpl.java +++ b/gnu/java/nio/SelectorImpl.java @@ -379,6 +379,8 @@ public class SelectorImpl extends AbstractSelector result = new DatagramChannelSelectionKey (ch, this); else if (ch instanceof ServerSocketChannelImpl) result = new ServerSocketChannelSelectionKey (ch, this); + else if (ch instanceof gnu.java.nio.SocketChannelImpl) + result = new gnu.java.nio.SocketChannelSelectionKeyImpl((gnu.java.nio.SocketChannelImpl)ch, this); else throw new InternalError ("No known channel type"); diff --git a/gnu/java/nio/SocketChannelSelectionKeyImpl.java b/gnu/java/nio/SocketChannelSelectionKeyImpl.java new file mode 100644 index 000000000..30fb2dfba --- /dev/null +++ b/gnu/java/nio/SocketChannelSelectionKeyImpl.java @@ -0,0 +1,69 @@ +/* SocketChannelSelectionKey.java -- Selection key for Socket Channel + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.nio; + + +/** + * @author Michael Barker <mike@middlesoft.co.uk> + * + */ +public class SocketChannelSelectionKeyImpl extends SelectionKeyImpl +{ + + SocketChannelImpl ch; + + /** + * @param ch + * @param impl + */ + public SocketChannelSelectionKeyImpl(SocketChannelImpl ch, SelectorImpl impl) + { + super(ch, impl); + this.ch = (SocketChannelImpl) ch; + } + + /** + * Returns the native file/socket descriptor as an int. + */ + public int getNativeFD() + { + return ch.getPlainSocketImpl().getNativeFD(); + } + +} diff --git a/gnu/java/nio/channels/FileChannelImpl.java b/gnu/java/nio/channels/FileChannelImpl.java index 671ae5bb1..ed439e141 100644 --- a/gnu/java/nio/channels/FileChannelImpl.java +++ b/gnu/java/nio/channels/FileChannelImpl.java @@ -40,6 +40,7 @@ package gnu.java.nio.channels; import gnu.classpath.Configuration; import gnu.java.nio.FileLockImpl; +import gnu.java.nio.VMChannel; import java.io.File; import java.io.FileNotFoundException; @@ -102,6 +103,7 @@ public final class FileChannelImpl extends FileChannel // we want to make sure this has the value -1. This is the most // efficient way to accomplish that. private int fd = -1; + private VMChannel ch; private int mode; @@ -123,6 +125,7 @@ public final class FileChannelImpl extends FileChannel description = path; fd = open (path, mode); this.mode = mode; + this.ch = VMChannel.getVMChannel(this); // First open the file and then check if it is a a directory // to avoid race condition. @@ -155,6 +158,7 @@ public final class FileChannelImpl extends FileChannel this.fd = fd; this.mode = mode; this.description = "descriptor(" + fd + ")"; + this.ch = VMChannel.getVMChannel(this); } private native int open (String path, int mode) throws FileNotFoundException; @@ -181,6 +185,7 @@ public final class FileChannelImpl extends FileChannel public int read (ByteBuffer dst) throws IOException { + /* int result; byte[] buffer = new byte [dst.remaining ()]; @@ -190,6 +195,8 @@ public final class FileChannelImpl extends FileChannel dst.put (buffer, 0, result); return result; + */ + return ch.read(dst); } public int read (ByteBuffer dst, long position) @@ -214,33 +221,12 @@ public final class FileChannelImpl extends FileChannel public long read (ByteBuffer[] dsts, int offset, int length) throws IOException { - long result = 0; - - for (int i = offset; i < offset + length; i++) - { - result += read (dsts [i]); - } - - return result; + return ch.readScattering(dsts, offset, length); } public int write (ByteBuffer src) throws IOException { - int len = src.remaining (); - if (src.hasArray()) - { - byte[] buffer = src.array(); - write(buffer, src.arrayOffset() + src.position(), len); - src.position(src.position() + len); - } - else - { - // Use a more efficient native method! FIXME! - byte[] buffer = new byte [len]; - src.get (buffer, 0, len); - write (buffer, 0, len); - } - return len; + return ch.write(src); } public int write (ByteBuffer src, long position) @@ -274,14 +260,7 @@ public final class FileChannelImpl extends FileChannel public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { - long result = 0; - - for (int i = offset;i < offset + length;i++) - { - result += write (srcs[i]); - } - - return result; + return ch.writeGathering(srcs, offset, length); } public native MappedByteBuffer mapImpl (char mode, long position, int size) @@ -563,4 +542,12 @@ public final class FileChannelImpl extends FileChannel + ",mode=" + mode + "," + description + "]"); } + + /** + * @return The native file descriptor. + */ + public int getNativeFD() + { + return fd; + } } diff --git a/gnu/java/security/OID.java b/gnu/java/security/OID.java index 473b6ba5a..822ca3427 100644 --- a/gnu/java/security/OID.java +++ b/gnu/java/security/OID.java @@ -1,5 +1,5 @@ /* OID.java -- numeric representation of an object identifier - Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -211,7 +211,6 @@ public class OID implements Cloneable, Comparable, java.io.Serializable /** * Construct a new OID from the given DER bytes. * - * @param root The root OID. * @param encoded The encoded relative OID. * @param relative The relative flag. */ diff --git a/gnu/java/security/hash/MD4.java b/gnu/java/security/hash/MD4.java index a09eb1705..215cd9837 100644 --- a/gnu/java/security/hash/MD4.java +++ b/gnu/java/security/hash/MD4.java @@ -44,7 +44,7 @@ import gnu.java.security.util.Util; /** * <p>An implementation of Ron Rivest's MD4 message digest algorithm.</p> * - * <p>MD4 was the precursor to the stronger {@link gnu.crypto.hash.MD5} + * <p>MD4 was the precursor to the stronger {@link gnu.java.security.hash.MD5} * algorithm, and while not considered cryptograpically secure itself, MD4 is * in use in various applications. It is slightly faster than MD5.</p> * diff --git a/gnu/java/security/prng/PRNGFactory.java b/gnu/java/security/prng/PRNGFactory.java index 8b5141456..1699d9e7e 100644 --- a/gnu/java/security/prng/PRNGFactory.java +++ b/gnu/java/security/prng/PRNGFactory.java @@ -42,7 +42,6 @@ import gnu.java.security.Registry; import java.util.Collections; import java.util.HashSet; -import java.util.Iterator; import java.util.Set; /** diff --git a/gnu/javax/crypto/jce/keyring/GnuKeyring.java b/gnu/javax/crypto/jce/keyring/GnuKeyring.java index d2501f893..5eeb2a306 100644 --- a/gnu/javax/crypto/jce/keyring/GnuKeyring.java +++ b/gnu/javax/crypto/jce/keyring/GnuKeyring.java @@ -90,30 +90,44 @@ public class GnuKeyring public Enumeration engineAliases() { + log.entering(this.getClass().getName(), "engineAliases"); ensureLoaded(); Enumeration result; if (privateKR == null) result = Collections.enumeration(Collections.EMPTY_SET); - else - { - Set aliases = new HashSet(); - for (Enumeration e = privateKR.aliases(); e.hasMoreElements();) - { - String alias = (String) e.nextElement(); - if (alias != null) - aliases.add(alias); - } - - for (Enumeration e = publicKR.aliases(); e.hasMoreElements();) - { - String alias = (String) e.nextElement(); - if (alias != null) - aliases.add(alias); - } - - result = Collections.enumeration(aliases); - } - + else + { + Set aliases = new HashSet(); + for (Enumeration e = privateKR.aliases(); e.hasMoreElements();) + { + String alias = (String) e.nextElement(); + if (alias != null) + { + alias = alias.trim(); + if (alias.length() > 0) + { + log.finest("Adding alias (from private keyring): " + alias); + aliases.add(alias); + } + } + } + for (Enumeration e = publicKR.aliases(); e.hasMoreElements();) + { + String alias = (String) e.nextElement(); + if (alias != null) + { + alias = alias.trim(); + if (alias.length() > 0) + { + log.finest("Adding alias (from public keyring): " + alias); + aliases.add(alias); + } + } + } + log.finest("Will enumerate: " + aliases); + result = Collections.enumeration(aliases); + } + log.exiting(this.getClass().getName(), "engineAliases"); return result; } @@ -181,13 +195,23 @@ public class GnuKeyring } public void engineSetCertificateEntry(String alias, Certificate cert) + throws KeyStoreException { log.entering(this.getClass().getName(), "engineSetCertificateEntry", new Object[] { alias, cert }); - ensureLoaded(); - publicKR.putCertificate(alias, cert); + if (privateKR.containsAlias(alias)) + throw new KeyStoreException("Alias [" + alias + + "] already exists and DOES NOT identify a " + + "Trusted Certificate Entry"); + if (publicKR.containsCertificate(alias)) + { + log.fine("Public keyring already contains Alias [" + alias + + "]. Will remove it"); + publicKR.remove(alias); + } + publicKR.putCertificate(alias, cert); log.exiting(this.getClass().getName(), "engineSetCertificateEntry"); } @@ -218,9 +242,7 @@ public class GnuKeyring public Key engineGetKey(String alias, char[] password) throws UnrecoverableKeyException { - log.entering(this.getClass().getName(), "engineGetKey", - String.valueOf(password)); - + log.entering(this.getClass().getName(), "engineGetKey", alias); ensureLoaded(); Key result = null; if (password == null) @@ -231,7 +253,8 @@ public class GnuKeyring else if (privateKR.containsPrivateKey(alias)) result = privateKR.getPrivateKey(alias, password); - log.exiting(this.getClass().getName(), "engineGetKey", result); + log.exiting(this.getClass().getName(), "engineGetKey", + result == null ? "null" : result.getClass().getName()); return result; } @@ -240,20 +263,28 @@ public class GnuKeyring throws KeyStoreException { log.entering(this.getClass().getName(), "engineSetKeyEntry", - new Object[] { alias, key, password, chain }); + new Object[] { alias, key.getClass().getName(), chain }); ensureLoaded(); + if (publicKR.containsAlias(alias)) + throw new KeyStoreException("Alias [" + alias + + "] already exists and DOES NOT identify a " + + "Key Entry"); if (key instanceof PublicKey) - privateKR.putPublicKey(alias, (PublicKey) key); + { + privateKR.remove(alias); + PublicKey pk = (PublicKey) key; + privateKR.putPublicKey(alias, pk); + } else { if (! (key instanceof PrivateKey) && ! (key instanceof SecretKey)) throw new KeyStoreException("cannot store keys of type " + key.getClass().getName()); + privateKR.remove(alias); privateKR.putCertPath(alias, chain); log.finest("About to put private key in keyring..."); privateKR.putPrivateKey(alias, key, password); } - log.exiting(this.getClass().getName(), "engineSetKeyEntry"); } @@ -292,7 +323,7 @@ public class GnuKeyring public void engineLoad(InputStream in, char[] password) throws IOException { - log.entering(this.getClass().getName(), "engineLoad", String.valueOf(password)); + log.entering(this.getClass().getName(), "engineLoad"); if (in != null) { if (! in.markSupported()) @@ -305,14 +336,12 @@ public class GnuKeyring createNewKeyrings(); loaded = true; - log.exiting(this.getClass().getName(), "engineLoad"); } public void engineStore(OutputStream out, char[] password) throws IOException { - log.entering(this.getClass().getName(), "engineStore", String.valueOf(password)); - + log.entering(this.getClass().getName(), "engineStore"); ensureLoaded(); HashMap attr = new HashMap(); attr.put(IKeyring.KEYRING_DATA_OUT, out); @@ -320,14 +349,18 @@ public class GnuKeyring privateKR.store(attr); publicKR.store(attr); - log.exiting(this.getClass().getName(), "engineStore"); } public int engineSize() { - ensureLoaded(); - return privateKR.size() + publicKR.size(); + log.entering(this.getClass().getName(), "engineSize"); + int result = 0; + for (Enumeration e = engineAliases(); e.hasMoreElements(); result++) + e.nextElement(); + + log.exiting(this.getClass().getName(), "engineSize", Integer.valueOf(result)); + return result; } /** diff --git a/gnu/javax/crypto/keyring/Entry.java b/gnu/javax/crypto/keyring/Entry.java index fa7f49679..2f311271a 100644 --- a/gnu/javax/crypto/keyring/Entry.java +++ b/gnu/javax/crypto/keyring/Entry.java @@ -41,16 +41,23 @@ package gnu.javax.crypto.keyring; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.util.logging.Logger; /** * An immutable class representing a single entry in a keyring. */ public abstract class Entry { - // Fields. // ------------------------------------------------------------------------ + private static final Logger log = Logger.getLogger(Entry.class.getName()); + private static final String[] TYPES = new String[] + { + "Encrypted", "PasswordEncrypted", "Authenticated", "PasswordAuthenticated", + "Compressed", "Certificate", "PublicKey", "PrivateKey", "CertPath", + "BinaryData" + }; /** This entry's type identifier. */ protected int type; @@ -145,6 +152,17 @@ public abstract class Entry out.write(payload); } + public String toString() + { + + return new StringBuilder("Entry{") + .append("type=").append(TYPES[type]) + .append(", properties=").append(properties) + .append(", payload=") + .append(payload == null? "-" : "byte[" + payload.length + "]") + .append("}").toString(); + } + /** * Generic decoding method, which simply decodes the properties field * and reads the payload field. @@ -161,6 +179,7 @@ public abstract class Entry { throw new IOException("corrupt length"); } + log.finest("About to instantiate new payload byte array for " + this); payload = new byte[len]; in.readFully(payload); } diff --git a/gnu/javax/crypto/keyring/EnvelopeEntry.java b/gnu/javax/crypto/keyring/EnvelopeEntry.java index 25b1dc2a0..2a57a23da 100644 --- a/gnu/javax/crypto/keyring/EnvelopeEntry.java +++ b/gnu/javax/crypto/keyring/EnvelopeEntry.java @@ -42,13 +42,12 @@ import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; - import java.util.ArrayList; -import java.util.Date; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.StringTokenizer; +import java.util.logging.Logger; /** * An envelope entry is a generic container for some number of primitive @@ -56,10 +55,10 @@ import java.util.StringTokenizer; */ public abstract class EnvelopeEntry extends Entry { - // Fields. // ------------------------------------------------------------------------ + private static final Logger log = Logger.getLogger(EnvelopeEntry.class.getName()); /** The envelope that contains this one (if any). */ protected EnvelopeEntry containingEnvelope; @@ -95,16 +94,17 @@ public abstract class EnvelopeEntry extends Entry */ public void add(Entry entry) { - if (!containsEntry(entry)) + log.entering(this.getClass().getName(), "add", entry); + if (! containsEntry(entry)) { if (entry instanceof EnvelopeEntry) - { - ((EnvelopeEntry) entry).setContainingEnvelope(this); - } + ((EnvelopeEntry) entry).setContainingEnvelope(this); + entries.add(entry); - payload = null; + log.finest("Payload is " + (payload == null ? "" : "not ") + "null"); makeAliasList(); } + log.exiting(this.getClass().getName(), "add"); } /** @@ -117,20 +117,22 @@ public abstract class EnvelopeEntry extends Entry */ public boolean containsAlias(String alias) { + log.entering(this.getClass().getName(), "containsAlias", alias); String aliases = getAliasList(); - if (aliases == null) - { - return false; - } - StringTokenizer tok = new StringTokenizer(aliases, ";"); - while (tok.hasMoreTokens()) + log.finest("aliases = [" + aliases + "]"); + boolean result = false; + if (aliases != null) { - if (tok.nextToken().equals(alias)) - { - return true; - } + StringTokenizer tok = new StringTokenizer(aliases, ";"); + while (tok.hasMoreTokens()) + if (tok.nextToken().equals(alias)) + { + result = true; + break; + } } - return false; + log.exiting(this.getClass().getName(), "containsAlias", Boolean.valueOf(result)); + return result; } /** @@ -180,34 +182,41 @@ public abstract class EnvelopeEntry extends Entry */ public List get(String alias) { + log.entering(this.getClass().getName(), "get", alias); + List result = new LinkedList(); for (Iterator it = entries.iterator(); it.hasNext();) { Entry e = (Entry) it.next(); if (e instanceof EnvelopeEntry) { - if (!((EnvelopeEntry) e).containsAlias(alias)) - { - continue; - } - if (e instanceof MaskableEnvelopeEntry) + EnvelopeEntry ee = (EnvelopeEntry) e; + if (! ee.containsAlias(alias)) + continue; + + if (ee instanceof MaskableEnvelopeEntry) { - if (((MaskableEnvelopeEntry) e).isMasked()) + MaskableEnvelopeEntry mee = (MaskableEnvelopeEntry) ee; + if (mee.isMasked()) { - result.add(e); + log.finer("Processing masked entry: " + mee); + result.add(mee); continue; } } - result.addAll(((EnvelopeEntry) e).get(alias)); + + log.finer("Processing unmasked entry: " + ee); + result.addAll(ee.get(alias)); } else if (e instanceof PrimitiveEntry) { - if (((PrimitiveEntry) e).getAlias().equals(alias)) - { - result.add(e); - } + PrimitiveEntry pe = (PrimitiveEntry) e; + if (pe.getAlias().equals(alias)) + result.add(e); } } + + log.exiting(this.getClass().getName(), "get", result); return result; } @@ -238,6 +247,7 @@ public abstract class EnvelopeEntry extends Entry */ public boolean remove(Entry entry) { + log.entering(this.getClass().getName(), "remove", entry); boolean ret = false; for (Iterator it = entries.iterator(); it.hasNext();) { @@ -268,36 +278,63 @@ public abstract class EnvelopeEntry extends Entry } if (ret) { + log.finest("State before: " + this); payload = null; makeAliasList(); + log.finest("State after: " + this); } + log.exiting(this.getClass().getName(), "remove", Boolean.valueOf(ret)); return ret; } /** * Removes all primitive entries that have the specified alias. - * + * * @param alias The alias of the entries to remove. + * @return <code>true</code> if <code>alias</code> was present and was + * successfully trmoved. Returns <code>false</code> if + * <code>alias</code> was not present in the list of aliases in this + * envelope. */ - public void remove(String alias) + public boolean remove(String alias) { + log.entering(this.getClass().getName(), "remove", alias); + boolean result = false; for (Iterator it = entries.iterator(); it.hasNext();) { Entry e = (Entry) it.next(); if (e instanceof EnvelopeEntry) { - ((EnvelopeEntry) e).remove(alias); + EnvelopeEntry ee = (EnvelopeEntry) e; + result = ee.remove(alias) || result; } else if (e instanceof PrimitiveEntry) { - if (((PrimitiveEntry) e).getAlias().equals(alias)) + PrimitiveEntry pe = (PrimitiveEntry) e; + if (pe.getAlias().equals(alias)) { it.remove(); + result = true; } } } - payload = null; - makeAliasList(); + if (result) + { + log.finest("State before: " + this); + payload = null; + makeAliasList(); + log.finest("State after: " + this); + } + log.exiting(this.getClass().getName(), "remove", Boolean.valueOf(result)); + return result; + } + + public String toString() + { + return new StringBuilder("Envelope{") + .append(super.toString()) + .append(", entries=").append(entries) + .append("}").toString(); } // Protected methods. @@ -324,6 +361,7 @@ public abstract class EnvelopeEntry extends Entry protected void decodeEnvelope(DataInputStream in) throws IOException { + this.entries.clear(); while (true) { int type = in.read(); @@ -372,27 +410,39 @@ public abstract class EnvelopeEntry extends Entry private void makeAliasList() { - if (entries.isEmpty()) - return; - StringBuffer buf = new StringBuffer(); - for (Iterator it = entries.iterator(); it.hasNext();) + log.entering(this.getClass().getName(), "makeAliasList"); + if (! entries.isEmpty()) { - Entry entry = (Entry) it.next(); - if (entry instanceof EnvelopeEntry) - { - buf.append(((EnvelopeEntry) entry).getAliasList()); - } - else if (entry instanceof PrimitiveEntry) + StringBuilder buf = new StringBuilder(); + String aliasOrList; + for (Iterator it = entries.iterator(); it.hasNext();) { - buf.append(((PrimitiveEntry) entry).getAlias()); + Entry entry = (Entry) it.next(); + aliasOrList = null; + if (entry instanceof EnvelopeEntry) + aliasOrList = ((EnvelopeEntry) entry).getAliasList(); + else if (entry instanceof PrimitiveEntry) + aliasOrList = ((PrimitiveEntry) entry).getAlias(); + else + log.fine("Entry with no Alias. Ignored: " + entry); + + if (aliasOrList != null) + { + aliasOrList = aliasOrList.trim(); + if (aliasOrList.trim().length() > 0) + { + buf.append(aliasOrList); + if (it.hasNext()) + buf.append(';'); + } + } } - if (it.hasNext()) - buf.append(';'); - } - properties.put("alias-list", buf.toString()); - if (containingEnvelope != null) - { - containingEnvelope.makeAliasList(); + String aliasList = buf.toString(); + properties.put("alias-list", aliasList); + log.finer("alias-list=[" + aliasList + "]"); + if (containingEnvelope != null) + containingEnvelope.makeAliasList(); } + log.exiting(this.getClass().getName(), "makeAliasList"); } } diff --git a/gnu/javax/crypto/keyring/GnuPrivateKeyring.java b/gnu/javax/crypto/keyring/GnuPrivateKeyring.java index c1fe30e67..bd5a96227 100644 --- a/gnu/javax/crypto/keyring/GnuPrivateKeyring.java +++ b/gnu/javax/crypto/keyring/GnuPrivateKeyring.java @@ -106,7 +106,6 @@ public class GnuPrivateKeyring extends BaseKeyring implements IPrivateKeyring public boolean containsPrivateKey(String alias) { log.entering(this.getClass().getName(), "containsPrivateKey", alias); - boolean result = false; if (containsAlias(alias)) for (Iterator it = get(alias).iterator(); it.hasNext();) @@ -115,7 +114,6 @@ public class GnuPrivateKeyring extends BaseKeyring implements IPrivateKeyring result = true; break; } - log.exiting(this.getClass().getName(), "containsPrivateKey", Boolean.valueOf(result)); return result; @@ -124,17 +122,15 @@ public class GnuPrivateKeyring extends BaseKeyring implements IPrivateKeyring public Key getPrivateKey(String alias, char[] password) throws UnrecoverableKeyException { - log.entering(this.getClass().getName(), "getPrivateKey", - new Object[] { alias, String.valueOf(password) }); - + log.entering(this.getClass().getName(), "getPrivateKey", alias); Key result = null; if (containsAlias(alias)) { PasswordAuthenticatedEntry e1 = null; - PasswordEncryptedEntry e2 = null; for (Iterator it = get(alias).iterator(); it.hasNext();) { Entry e = (Entry) it.next(); + log.finest("Entry: " + e); if (e instanceof PasswordAuthenticatedEntry) { e1 = (PasswordAuthenticatedEntry) e; @@ -142,6 +138,7 @@ public class GnuPrivateKeyring extends BaseKeyring implements IPrivateKeyring } } + log.finest("e1 = " + e1); if (e1 != null) { try @@ -150,9 +147,11 @@ public class GnuPrivateKeyring extends BaseKeyring implements IPrivateKeyring } catch (Exception e) { + log.throwing(this.getClass().getName(), "getPrivateKey", e); throw new UnrecoverableKeyException("authentication failed"); } + PasswordEncryptedEntry e2 = null; for (Iterator it = e1.getEntries().iterator(); it.hasNext();) { Entry e = (Entry) it.next(); @@ -171,6 +170,7 @@ public class GnuPrivateKeyring extends BaseKeyring implements IPrivateKeyring } catch (Exception e) { + log.throwing(this.getClass().getName(), "getPrivateKey", e); throw new UnrecoverableKeyException("decryption failed"); } @@ -186,31 +186,26 @@ public class GnuPrivateKeyring extends BaseKeyring implements IPrivateKeyring } } } - - log.exiting(this.getClass().getName(), "getPrivateKey", result); + log.exiting(this.getClass().getName(), "getPrivateKey", + result == null ? "null" : result.getClass().getName()); return result; } public void putPrivateKey(String alias, Key key, char[] password) { log.entering(this.getClass().getName(), "putPrivateKey", - new Object[] { alias, key, String.valueOf(password) }); - + new Object[] { alias, key.getClass().getName() }); if (! containsPrivateKey(alias)) { alias = fixAlias(alias); Properties p = new Properties(); p.put("alias", alias); PrivateKeyEntry pke = new PrivateKeyEntry(key, new Date(), p); + + log.finest("About to encrypt the key..."); PasswordEncryptedEntry enc; enc = new PasswordEncryptedEntry(cipher, mode, keylen, new Properties()); enc.add(pke); - - PasswordAuthenticatedEntry auth; - auth = new PasswordAuthenticatedEntry(mac, maclen, new Properties()); - auth.add(enc); - - log.finest("About to encrypt the key..."); try { enc.encode(null, password); @@ -218,11 +213,14 @@ public class GnuPrivateKeyring extends BaseKeyring implements IPrivateKeyring catch (IOException x) { log.log(Level.FINER, "Exception while encrypting the key. " - + "Rethrow as IllegalArgumentException", x); + + "Rethrow as IllegalArgumentException", x); throw new IllegalArgumentException(x.toString()); } log.finest("About to authenticate the encrypted key..."); + PasswordAuthenticatedEntry auth; + auth = new PasswordAuthenticatedEntry(mac, maclen, new Properties()); + auth.add(enc); try { auth.encode(null, password); @@ -230,7 +228,7 @@ public class GnuPrivateKeyring extends BaseKeyring implements IPrivateKeyring catch (IOException x) { log.log(Level.FINER, "Exception while authenticating the encrypted " - + "key. Rethrow as IllegalArgumentException", x); + + "key. Rethrow as IllegalArgumentException", x); throw new IllegalArgumentException(x.toString()); } @@ -245,7 +243,6 @@ public class GnuPrivateKeyring extends BaseKeyring implements IPrivateKeyring public boolean containsPublicKey(String alias) { log.entering(this.getClass().getName(), "containsPublicKey", alias); - boolean result = false; if (containsAlias(alias)) for (Iterator it = get(alias).iterator(); it.hasNext();) @@ -254,7 +251,6 @@ public class GnuPrivateKeyring extends BaseKeyring implements IPrivateKeyring result = true; break; } - log.exiting(this.getClass().getName(), "containsPublicKey", Boolean.valueOf(result)); return result; @@ -263,7 +259,6 @@ public class GnuPrivateKeyring extends BaseKeyring implements IPrivateKeyring public PublicKey getPublicKey(String alias) { log.entering(this.getClass().getName(), "getPublicKey", alias); - PublicKey result = null; if (containsAlias(alias)) for (Iterator it = get(alias).iterator(); it.hasNext();) @@ -275,16 +270,15 @@ public class GnuPrivateKeyring extends BaseKeyring implements IPrivateKeyring break; } } - - log.exiting(this.getClass().getName(), "getPublicKey", result); + log.exiting(this.getClass().getName(), "getPublicKey", + result == null ? "null" : result.getClass().getName()); return result; } public void putPublicKey(String alias, PublicKey key) { log.entering(this.getClass().getName(), "putPublicKey", - new Object[] { alias, key }); - + new Object[] { alias, key.getClass().getName() }); if (! containsPublicKey(alias)) { Properties p = new Properties(); @@ -300,7 +294,6 @@ public class GnuPrivateKeyring extends BaseKeyring implements IPrivateKeyring public boolean containsCertPath(String alias) { log.entering(this.getClass().getName(), "containsCertPath", alias); - boolean result = false; if (containsAlias(alias)) for (Iterator it = get(alias).iterator(); it.hasNext();) @@ -309,7 +302,6 @@ public class GnuPrivateKeyring extends BaseKeyring implements IPrivateKeyring result = true; break; } - log.exiting(this.getClass().getName(), "containsCertPath", Boolean.valueOf(result)); return result; @@ -318,7 +310,6 @@ public class GnuPrivateKeyring extends BaseKeyring implements IPrivateKeyring public Certificate[] getCertPath(String alias) { log.entering(this.getClass().getName(), "getCertPath", alias); - Certificate[] result = null; if (containsAlias(alias)) for (Iterator it = get(alias).iterator(); it.hasNext();) @@ -330,7 +321,6 @@ public class GnuPrivateKeyring extends BaseKeyring implements IPrivateKeyring break; } } - log.exiting(this.getClass().getName(), "getCertPath", result); return result; } @@ -339,7 +329,6 @@ public class GnuPrivateKeyring extends BaseKeyring implements IPrivateKeyring { log.entering(this.getClass().getName(), "putCertPath", new Object[] { alias, path }); - if (! containsCertPath(alias)) { Properties p = new Properties(); @@ -354,28 +343,23 @@ public class GnuPrivateKeyring extends BaseKeyring implements IPrivateKeyring protected void load(InputStream in, char[] password) throws IOException { - log.entering(this.getClass().getName(), "load", - new Object[] { in, String.valueOf(password) }); - + log.entering(this.getClass().getName(), "load"); if (in.read() != USAGE) throw new MalformedKeyringException("incompatible keyring usage"); if (in.read() != PasswordAuthenticatedEntry.TYPE) throw new MalformedKeyringException("expecting password-authenticated entry tag"); - keyring = PasswordAuthenticatedEntry.decode(new DataInputStream(in), password); - + keyring = PasswordAuthenticatedEntry.decode(new DataInputStream(in), + password); log.exiting(this.getClass().getName(), "load"); } protected void store(OutputStream out, char[] password) throws IOException { - log.entering(this.getClass().getName(), "store", - new Object[] { out, String.valueOf(password) }); - + log.entering(this.getClass().getName(), "store"); out.write(USAGE); keyring.encode(new DataOutputStream(out), password); - log.exiting(this.getClass().getName(), "store"); } } diff --git a/gnu/javax/crypto/keyring/GnuPublicKeyring.java b/gnu/javax/crypto/keyring/GnuPublicKeyring.java index 490eb4458..7e1182bc1 100644 --- a/gnu/javax/crypto/keyring/GnuPublicKeyring.java +++ b/gnu/javax/crypto/keyring/GnuPublicKeyring.java @@ -78,7 +78,6 @@ public class GnuPublicKeyring extends BaseKeyring implements IPublicKeyring public boolean containsCertificate(String alias) { log.entering(this.getClass().getName(), "containsCertificate", alias); - boolean result = false; if (containsAlias(alias)) for (Iterator it = get(alias).iterator(); it.hasNext();) @@ -87,7 +86,6 @@ public class GnuPublicKeyring extends BaseKeyring implements IPublicKeyring result = true; break; } - log.exiting(this.getClass().getName(), "containsCertificate", Boolean.valueOf(result)); return result; @@ -96,7 +94,6 @@ public class GnuPublicKeyring extends BaseKeyring implements IPublicKeyring public Certificate getCertificate(String alias) { log.entering(this.getClass().getName(), "getCertificate", alias); - Certificate result = null; if (containsAlias(alias)) for (Iterator it = get(alias).iterator(); it.hasNext();) @@ -108,7 +105,6 @@ public class GnuPublicKeyring extends BaseKeyring implements IPublicKeyring break; } } - log.exiting(this.getClass().getName(), "getCertificate", result); return result; } @@ -117,7 +113,6 @@ public class GnuPublicKeyring extends BaseKeyring implements IPublicKeyring { log.entering(this.getClass().getName(), "putCertificate", new Object[] { alias, cert }); - if (! containsCertificate(alias)) { Properties p = new Properties(); @@ -132,9 +127,7 @@ public class GnuPublicKeyring extends BaseKeyring implements IPublicKeyring protected void load(InputStream in, char[] password) throws IOException { - log.entering(this.getClass().getName(), "load", - new Object[] { in, String.valueOf(password) }); - + log.entering(this.getClass().getName(), "load"); if (in.read() != USAGE) throw new MalformedKeyringException("incompatible keyring usage"); @@ -143,18 +136,14 @@ public class GnuPublicKeyring extends BaseKeyring implements IPublicKeyring DataInputStream dis = new DataInputStream(in); keyring = PasswordAuthenticatedEntry.decode(dis, password); - log.exiting(this.getClass().getName(), "load"); } protected void store(OutputStream out, char[] password) throws IOException { - log.entering(this.getClass().getName(), "store", - new Object[] { out, String.valueOf(password) }); - + log.entering(this.getClass().getName(), "store"); out.write(USAGE); keyring.encode(new DataOutputStream(out), password); - log.exiting(this.getClass().getName(), "store"); } } diff --git a/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java b/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java index 7fed7c40c..653d62ced 100644 --- a/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java +++ b/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java @@ -48,7 +48,6 @@ import java.util.List; */ public abstract class MaskableEnvelopeEntry extends EnvelopeEntry { - // Fields. // ------------------------------------------------------------------------ @@ -137,12 +136,19 @@ public abstract class MaskableEnvelopeEntry extends EnvelopeEntry return super.remove(entry); } - public void remove(String alias) + public boolean remove(String alias) { if (isMasked()) - { - throw new IllegalStateException("masked envelope"); - } - super.remove(alias); + throw new IllegalStateException("masked envelope"); + + return super.remove(alias); + } + + public String toString() + { + return new StringBuilder("MaskableEnvelope{") + .append(super.toString()) + .append(", masked=").append(masked) + .append("}").toString(); } } diff --git a/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java b/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java index 2e3a0d145..96d4fc4db 100644 --- a/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java +++ b/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java @@ -41,6 +41,7 @@ package gnu.javax.crypto.keyring; import gnu.java.security.Registry; import gnu.java.security.prng.IRandom; import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.PRNG; import gnu.java.security.util.Util; import gnu.javax.crypto.mac.IMac; import gnu.javax.crypto.mac.MacFactory; @@ -55,10 +56,10 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.security.InvalidKeyException; -import java.security.SecureRandom; import java.util.Arrays; -import java.util.Iterator; import java.util.HashMap; +import java.util.Iterator; +import java.util.logging.Logger; /** * <p>An entry authenticated with a password-based MAC.</p> @@ -66,10 +67,10 @@ import java.util.HashMap; public final class PasswordAuthenticatedEntry extends MaskableEnvelopeEntry implements PasswordProtectedEntry, Registry { - // Constants and variables // ------------------------------------------------------------------------- + private static final Logger log = Logger.getLogger(PasswordAuthenticatedEntry.class.getName()); public static final int TYPE = 3; // Constructor(s) @@ -145,54 +146,64 @@ public final class PasswordAuthenticatedEntry extends MaskableEnvelopeEntry public void verify(char[] password) { - if (!isMasked() || payload == null) - { - return; - } - IMac m = null; - try - { - m = getMac(password); - } - catch (Exception x) + log.entering(this.getClass().getName(), "verify"); + if (isMasked() && payload != null) { - throw new IllegalArgumentException(x.toString()); - } + log.finest("payload to verify: " + Util.dumpString(payload)); + long tt = - System.currentTimeMillis(); + IMac m = null; + try + { + m = getMac(password); + } + catch (Exception x) + { + throw new IllegalArgumentException(x.toString(), x); + } - m.update(payload, 0, payload.length - m.macSize()); - byte[] macValue = new byte[m.macSize()]; - System.arraycopy(payload, payload.length - macValue.length, macValue, 0, - macValue.length); - if (!Arrays.equals(macValue, m.digest())) - { - throw new IllegalArgumentException("MAC verification failed"); - } - try - { - DataInputStream in = new DataInputStream( - new ByteArrayInputStream( - payload, - 0, - payload.length - - m.macSize())); - decodeEnvelope(in); - } - catch (IOException ioe) - { - throw new IllegalArgumentException("malformed keyring fragment"); + int limit = payload.length - m.macSize(); + m.update(payload, 0, limit); + byte[] macValue = new byte[m.macSize()]; + System.arraycopy(payload, payload.length - macValue.length, macValue, 0, + macValue.length); + if (! Arrays.equals(macValue, m.digest())) + throw new IllegalArgumentException("MAC verification failed"); + + setMasked(false); + + ByteArrayInputStream bais; + try + { + bais = new ByteArrayInputStream(payload, 0, limit); + DataInputStream in = new DataInputStream(bais); + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("malformed keyring fragment"); + } + + tt += System.currentTimeMillis(); + log.finer("Verified in " + tt + "ms."); } - setMasked(false); - payload = null; + else + log.finer("Skip verification; " + (isMasked() ? "null payload" : "unmasked")); + log.exiting(this.getClass().getName(), "verify"); } public void authenticate(char[] password) throws IOException { + log.entering(this.getClass().getName(), "authenticate"); + long tt = - System.currentTimeMillis(); + long t1 = - System.currentTimeMillis(); + if (isMasked()) - { - throw new IllegalStateException("entry is masked"); - } + throw new IllegalStateException("entry is masked"); + byte[] salt = new byte[8]; - new SecureRandom ().nextBytes (salt); + PRNG.getInstance().nextBytes(salt); + t1 += System.currentTimeMillis(); + log.finer("-- Generated salt in " + t1 + "ms."); properties.put("salt", Util.toString(salt)); IMac m = getMac(password); ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); @@ -201,10 +212,21 @@ public final class PasswordAuthenticatedEntry extends MaskableEnvelopeEntry for (Iterator it = entries.iterator(); it.hasNext();) { Entry entry = (Entry) it.next(); + log.finer("-- About to authenticate one " + entry); + t1 = - System.currentTimeMillis(); entry.encode(out2); + t1 += System.currentTimeMillis(); + log.finer("-- Authenticated an Entry in " + t1 + "ms."); } bout.write(m.digest()); + payload = bout.toByteArray(); + log.finest("authenticated payload: " + Util.dumpString(payload)); + setMasked(true); + + tt += System.currentTimeMillis(); + log.finer("Authenticated in " + tt + "ms."); + log.exiting(this.getClass().getName(), "authenticate"); } public void encode(DataOutputStream out, char[] password) throws IOException @@ -217,6 +239,7 @@ public final class PasswordAuthenticatedEntry extends MaskableEnvelopeEntry { if (payload == null) { + log.fine("Null payload: " + this); throw new IllegalStateException("mac not computed"); } } @@ -226,26 +249,25 @@ public final class PasswordAuthenticatedEntry extends MaskableEnvelopeEntry private IMac getMac(char[] password) throws MalformedKeyringException { - if (!properties.containsKey("salt")) - { - throw new MalformedKeyringException("no salt"); - } - byte[] salt = Util.toBytesFromString(properties.get("salt")); - IMac mac = MacFactory.getInstance(properties.get("mac")); + log.entering(this.getClass().getName(), "getMac"); + String saltString = properties.get("salt"); + if (saltString == null) + throw new MalformedKeyringException("no salt"); + + byte[] salt = Util.toBytesFromString(saltString); + String macAlgorithm = properties.get("mac"); + IMac mac = MacFactory.getInstance(macAlgorithm); if (mac == null) - { - throw new MalformedKeyringException("no such mac: " - + properties.get("mac")); - } - int keylen = mac.macSize(); - int maclen = 0; - if (!properties.containsKey("maclen")) - { - throw new MalformedKeyringException("no MAC length"); - } + throw new MalformedKeyringException("no such mac: " + macAlgorithm); + + String macLenString = properties.get("maclen"); + if (macLenString == null) + throw new MalformedKeyringException("no MAC length"); + + int maclen; try { - maclen = Integer.parseInt(properties.get("maclen")); + maclen = Integer.parseInt(macLenString); } catch (NumberFormatException nfe) { @@ -259,6 +281,7 @@ public final class PasswordAuthenticatedEntry extends MaskableEnvelopeEntry IRandom kdf = PRNGFactory.getInstance("PBKDF2-HMAC-SHA"); kdf.init(pbAttr); + int keylen = mac.macSize(); byte[] dk = new byte[keylen]; try { @@ -280,6 +303,7 @@ public final class PasswordAuthenticatedEntry extends MaskableEnvelopeEntry { throw new Error(shouldNotHappen.toString()); } + log.exiting(this.getClass().getName(), "getMac"); return mac; } } diff --git a/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java b/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java index 26b4032bd..24ab98266 100644 --- a/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java +++ b/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java @@ -41,8 +41,8 @@ package gnu.javax.crypto.keyring; import gnu.java.security.Registry; import gnu.java.security.prng.IRandom; import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.PRNG; import gnu.java.security.util.Util; - import gnu.javax.crypto.cipher.CipherFactory; import gnu.javax.crypto.cipher.IBlockCipher; import gnu.javax.crypto.mode.IMode; @@ -58,16 +58,10 @@ import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; - import java.security.InvalidKeyException; -import java.security.SecureRandom; - -import java.util.Arrays; -import java.util.Collections; -import java.util.Date; -import java.util.Iterator; import java.util.HashMap; -import java.util.List; +import java.util.Iterator; +import java.util.logging.Logger; /** * An envelope that is encrypted with a password-derived key. @@ -75,10 +69,10 @@ import java.util.List; public class PasswordEncryptedEntry extends MaskableEnvelopeEntry implements PasswordProtectedEntry, Registry { - // Constants and fields. // ------------------------------------------------------------------------ + private static final Logger log = Logger.getLogger(PasswordEncryptedEntry.class.getName()); public static final int TYPE = 1; // Constructors. @@ -138,43 +132,53 @@ public class PasswordEncryptedEntry extends MaskableEnvelopeEntry implements public void decrypt(char[] password) throws IllegalArgumentException, WrongPaddingException { - if (!isMasked() || payload == null) - { - return; - } - IMode mode = getMode(password, IMode.DECRYPTION); - IPad padding = PadFactory.getInstance("PKCS7"); - padding.init(mode.currentBlockSize()); - byte[] buf = new byte[payload.length]; - int count = 0; - for (int i = 0; i < payload.length; i++) - { - mode.update(payload, count, buf, count); - count += mode.currentBlockSize(); - } - int padlen = padding.unpad(buf, 0, buf.length); - DataInputStream in = new DataInputStream( - new ByteArrayInputStream( - buf, - 0, - buf.length - - padlen)); - try - { - decodeEnvelope(in); - } - catch (IOException ioe) + log.entering(this.getClass().getName(), "decrypt"); + if (isMasked() && payload != null) { - throw new IllegalArgumentException("decryption failed"); + long tt = - System.currentTimeMillis(); + IMode mode = getMode(password, IMode.DECRYPTION); + IPad padding = PadFactory.getInstance("PKCS7"); + padding.init(mode.currentBlockSize()); + byte[] buf = new byte[payload.length]; + int count = 0; + while (count + mode.currentBlockSize() <= payload.length) + { + mode.update(payload, count, buf, count); + count += mode.currentBlockSize(); + } + int padlen = padding.unpad(buf, 0, buf.length); + + setMasked(false); + + ByteArrayInputStream baos = new ByteArrayInputStream(buf, 0, + buf.length - padlen); + DataInputStream in = new DataInputStream(baos); + try + { + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("decryption failed"); + } + tt += System.currentTimeMillis(); + log.finer("Decrypted in " + tt + "ms."); } - setMasked(false); - payload = null; + else + log.finer("Skip decryption; " + (isMasked() ? "null payload" : "unmasked")); + log.exiting(this.getClass().getName(), "decrypt"); } public void encrypt(char[] password) throws IOException { + log.entering(this.getClass().getName(), "encrypt", String.valueOf(password)); + long tt = - System.currentTimeMillis(); + long t1 = - System.currentTimeMillis(); + byte[] salt = new byte[8]; - new SecureRandom ().nextBytes (salt); + PRNG.getInstance().nextBytes(salt); + t1 += System.currentTimeMillis(); + log.finer("-- Generated salt in " + t1 + "ms."); properties.put("salt", Util.toString(salt)); IMode mode = getMode(password, IMode.ENCRYPTION); IPad pad = PadFactory.getInstance("PKCS7"); @@ -184,7 +188,11 @@ public class PasswordEncryptedEntry extends MaskableEnvelopeEntry implements for (Iterator it = entries.iterator(); it.hasNext();) { Entry entry = (Entry) it.next(); + log.finer("-- About to encode one " + entry); + t1 = - System.currentTimeMillis(); entry.encode(out2); + t1 += System.currentTimeMillis(); + log.finer("-- Encoded an Entry in " + t1 + "ms."); } byte[] plaintext = bout.toByteArray(); byte[] padding = pad.pad(plaintext, 0, plaintext.length); @@ -200,6 +208,12 @@ public class PasswordEncryptedEntry extends MaskableEnvelopeEntry implements count += mode.currentBlockSize(); } mode.update(lastBlock, 0, payload, count); + + setMasked(true); + + tt += System.currentTimeMillis(); + log.finer("Encrypted in " + tt + "ms."); + log.exiting(this.getClass().getName(), "encrypt"); } public void encode(DataOutputStream out, char[] password) throws IOException @@ -212,6 +226,7 @@ public class PasswordEncryptedEntry extends MaskableEnvelopeEntry implements { if (payload == null) { + log.fine("Null payload: " + this); throw new IllegalStateException("not encrypted"); } } diff --git a/gnu/javax/crypto/keyring/PrimitiveEntry.java b/gnu/javax/crypto/keyring/PrimitiveEntry.java index 4c9ff0ff1..f5e63e996 100644 --- a/gnu/javax/crypto/keyring/PrimitiveEntry.java +++ b/gnu/javax/crypto/keyring/PrimitiveEntry.java @@ -69,10 +69,9 @@ public abstract class PrimitiveEntry extends Entry if (!this.properties.containsKey("alias") || this.properties.get("alias").length() == 0) { - throw new IllegalArgumentException( - "primitive entries MUST have an alias"); + throw new IllegalArgumentException("primitive entries MUST have an alias"); } - this.properties.put("creation-date", String.valueOf(creationDate.getTime())); + this.properties.put("creation-date", String.valueOf(this.creationDate.getTime())); } protected PrimitiveEntry(int type) diff --git a/gnu/javax/crypto/keyring/PrivateKeyEntry.java b/gnu/javax/crypto/keyring/PrivateKeyEntry.java index 882495633..cf5b41287 100644 --- a/gnu/javax/crypto/keyring/PrivateKeyEntry.java +++ b/gnu/javax/crypto/keyring/PrivateKeyEntry.java @@ -42,12 +42,10 @@ import gnu.java.security.key.IKeyPairCodec; import gnu.java.security.key.KeyPairCodecFactory; import gnu.java.security.key.dss.DSSPrivateKey; import gnu.java.security.key.rsa.GnuRSAPrivateKey; - import gnu.javax.crypto.key.GnuSecretKey; import gnu.javax.crypto.key.dh.GnuDHPrivateKey; import java.io.DataInputStream; -import java.io.DataOutputStream; import java.io.IOException; import java.security.Key; import java.security.KeyFactory; @@ -56,11 +54,11 @@ import java.security.spec.PKCS8EncodedKeySpec; import java.util.Date; /** - * <p>An immutable class representing a private or secret key entry.</p> + * An immutable class representing a private or secret key entry. */ -public final class PrivateKeyEntry extends PrimitiveEntry +public final class PrivateKeyEntry + extends PrimitiveEntry { - // Constants and variables // ------------------------------------------------------------------------- @@ -73,7 +71,7 @@ public final class PrivateKeyEntry extends PrimitiveEntry // ------------------------------------------------------------------------- /** - * <p>Creates a new key entry.</p> + * Creates a new key entry. * * @param key The key. * @param creationDate The entry creation date. @@ -85,13 +83,11 @@ public final class PrivateKeyEntry extends PrimitiveEntry super(TYPE, creationDate, properties); if (key == null) - { - throw new IllegalArgumentException("no private key"); - } - if (!(key instanceof PrivateKey) && !(key instanceof GnuSecretKey)) - { - throw new IllegalArgumentException("not a private or secret key"); - } + throw new IllegalArgumentException("no private key"); + + if (! (key instanceof PrivateKey) && ! (key instanceof GnuSecretKey)) + throw new IllegalArgumentException("not a private or secret key"); + this.key = key; } @@ -109,9 +105,8 @@ public final class PrivateKeyEntry extends PrimitiveEntry entry.defaultDecode(in); String type = entry.properties.get("type"); if (type == null) - { - throw new MalformedKeyringException("no key type"); - } + throw new MalformedKeyringException("no key type"); + if (type.equalsIgnoreCase("RAW-DSS")) { IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss"); @@ -128,42 +123,38 @@ public final class PrivateKeyEntry extends PrimitiveEntry entry.key = coder.decodePrivateKey(entry.payload); } else if (type.equalsIgnoreCase("RAW")) - { - entry.key = new GnuSecretKey(entry.payload, null); - } + entry.key = new GnuSecretKey(entry.payload, null); else if (type.equalsIgnoreCase("PKCS8")) { try { KeyFactory kf = KeyFactory.getInstance("RSA"); - entry.key = kf.generatePrivate(new PKCS8EncodedKeySpec( - entry.payload)); + PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(entry.payload); + entry.key = kf.generatePrivate(ks); } - catch (Exception x) + catch (Exception ignored) { } + if (entry.key == null) { try { KeyFactory kf = KeyFactory.getInstance("DSA"); - entry.key = kf.generatePrivate(new PKCS8EncodedKeySpec( - entry.payload)); + PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(entry.payload); + entry.key = kf.generatePrivate(ks); } - catch (Exception x) + catch (Exception ignored) { } + if (entry.key == null) - { - throw new MalformedKeyringException( - "could not decode PKCS#8 key"); - } + throw new MalformedKeyringException("could not decode PKCS#8 key"); } } else - { - throw new MalformedKeyringException("unsupported key type " + type); - } + throw new MalformedKeyringException("unsupported key type " + type); + return entry; } @@ -171,7 +162,7 @@ public final class PrivateKeyEntry extends PrimitiveEntry // ------------------------------------------------------------------------- /** - * <p>Returns this entry's key.</p> + * Returns this entry's key. * * @return The key. */ @@ -212,8 +203,12 @@ public final class PrivateKeyEntry extends PrimitiveEntry payload = key.getEncoded(); } else - { - throw new IllegalArgumentException("unsupported private key"); - } + throw new IllegalArgumentException("unsupported private key"); + } + + public String toString() + { + return "PrivateKeyEntry{key=" + + (key == null ? "-" : key.getClass().getName()) + "}"; } } diff --git a/gnu/javax/imageio/jpeg/DCT.java b/gnu/javax/imageio/jpeg/DCT.java new file mode 100644 index 000000000..91b6eb88f --- /dev/null +++ b/gnu/javax/imageio/jpeg/DCT.java @@ -0,0 +1,347 @@ +/* DCT.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +/** + * Discrete Cosine Transformations. + */ +public class DCT +{ + + /** + * Cosine matrix + */ + public double c[][] = new double[8][8]; + + /** + * Transformed cosine matrix + */ + public double cT[][] = new double[8][8]; + + public DCT() + { + initMatrix(); + } + + /** + * Figure A.3.3 IDCT, Cu Cv on A-5 of the ISO DIS 10918-1. Requirements and + * Guidelines. + * + * @param u + * @return + */ + public static double C(int u) + { + return ((u == 0) ? (double) 1 / (double) Math.sqrt((double) 2) + : (double) 1); + } + + /** + * Initialize matrix values for the fast_idct function + */ + private void initMatrix() + { + for (int j = 0; j < 8; j++) + { + double nn = (double) (8); + c[0][j] = 1.0 / Math.sqrt(nn); + cT[j][0] = c[0][j]; + } + for (int i = 1; i < 8; i++) + { + for (int j = 0; j < 8; j++) + { + double jj = (double) j; + double ii = (double) i; + c[i][j] = + Math.sqrt(2.0 / 8.0) + * Math.cos(((2.0 * jj + 1.0) * ii * Math.PI) / (2.0 * 8.0)); + cT[j][i] = c[i][j]; + } + } + } + + /** + * slow_idct - Figure A.3.3 IDCT (informative) on A-5 of the ISO DIS + * 10918-1. Requirements and Guidelines. This is a slow IDCT, there are + * better algorithms to use, it's fairly expensive with processor speed. + * + * @param matrix + * @return + */ + public static double[][] slow_idct(double[][] matrix) + { + double[][] output = new double[matrix.length][matrix.length]; + for (int y = 0; y < 8; y++) + { + for (int x = 0; x < 8; x++) + { + double val = 0; + for (double v = 0; v < 8; v++) + { + double innerloop = 0; + for (double u = 0; u < 8; u++) + innerloop += (DCT.C((int) u) / (double) 2) + * matrix[(int) v][(int) u] + * Math.cos((2 * x + 1) * u * Math.PI / (double) 16) + * Math.cos((2 * y + 1) * v * Math.PI / (double) 16); + val += (DCT.C((int) v) / (double) 2) * innerloop; + } + output[y][x] = (val + 128); + } + } + return (output); + } + + public static float[][] slow_fdct(float[][] value) + { + float[][] buffer = new float[8][8]; + + for (int u = 0; u < 8; u++) + { + for (int v = 0; v < 8; v++) + { + buffer[u][v] = + (float) (1 / 4) * (float) C((int) u) * (float) C((int) v); + float innerval = 0; + for (int x = 0; x < 8; x++) + { + for (int y = 0; y < 8; y++) + { + innerval += value[y][x] + * Math.cos(((2 * x + 1) * u * Math.PI) / 16) + * Math.cos(((2 * y + 1) * v * Math.PI) / 16); + } + } + buffer[u][v] *= innerval; + } + } + return (buffer); + } + + public float[][] fast_fdct(float[][] input) + { + float output[][] = new float[8][8]; + double temp[][] = new double[8][8]; + double temp1; + int i; + int j; + int k; + + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + temp[i][j] = 0.0; + for (k = 0; k < 8; k++) + { + temp[i][j] += (((int) (input[i][k]) - 128) * cT[k][j]); + } + } + } + + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + temp1 = 0.0; + + for (k = 0; k < 8; k++) + { + temp1 += (c[i][k] * temp[k][j]); + } + + output[i][j] = (int) Math.round(temp1) * 8; + } + } + + return output; + } + + /** + * fast_idct - Figure A.3.3 IDCT (informative) on A-5 of the ISO DIS + * 10918-1. Requires and Guidelines. This is a fast IDCT, it much more + * effecient and only inaccurate at about 1/1000th of a percent of values + * analyzed. Cannot be static because initMatrix must run before any + * fast_idct values can be computed. + * + * @param input + * @return + */ + public double[][] fast_idct(double[][] input) + { + double output[][] = new double[8][8]; + double temp[][] = new double[8][8]; + double temp1; + int i, j, k; + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + temp[i][j] = 0.0; + for (k = 0; k < 8; k++) + { + temp[i][j] += input[i][k] * c[k][j]; + } + } + } + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + temp1 = 0.0; + for (k = 0; k < 8; k++) + temp1 += cT[i][k] * temp[k][j]; + temp1 += 128.0; + if (temp1 < 0) + output[i][j] = 0; + else if (temp1 > 255) + output[i][j] = 255; + else + output[i][j] = (int) Math.round(temp1); + } + } + return output; + } + + public double[][] idj_fast_fdct(float input[][]) + { + double output[][] = new double[8][8]; + double tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + double tmp10, tmp11, tmp12, tmp13; + double z1, z2, z3, z4, z5, z11, z13; + int i; + int j; + + // Subtracts 128 from the input values + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + output[i][j] = ((double) input[i][j] - (double) 128.0); + // input[i][j] -= 128; + + } + } + + for (i = 0; i < 8; i++) + { + tmp0 = output[i][0] + output[i][7]; + tmp7 = output[i][0] - output[i][7]; + tmp1 = output[i][1] + output[i][6]; + tmp6 = output[i][1] - output[i][6]; + tmp2 = output[i][2] + output[i][5]; + tmp5 = output[i][2] - output[i][5]; + tmp3 = output[i][3] + output[i][4]; + tmp4 = output[i][3] - output[i][4]; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + output[i][0] = tmp10 + tmp11; + output[i][4] = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * (double) 0.707106781; + output[i][2] = tmp13 + z1; + output[i][6] = tmp13 - z1; + + tmp10 = tmp4 + tmp5; + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + z5 = (tmp10 - tmp12) * (double) 0.382683433; + z2 = ((double) 0.541196100) * tmp10 + z5; + z4 = ((double) 1.306562965) * tmp12 + z5; + z3 = tmp11 * ((double) 0.707106781); + + z11 = tmp7 + z3; + z13 = tmp7 - z3; + + output[i][5] = z13 + z2; + output[i][3] = z13 - z2; + output[i][1] = z11 + z4; + output[i][7] = z11 - z4; + } + + for (i = 0; i < 8; i++) + { + tmp0 = output[0][i] + output[7][i]; + tmp7 = output[0][i] - output[7][i]; + tmp1 = output[1][i] + output[6][i]; + tmp6 = output[1][i] - output[6][i]; + tmp2 = output[2][i] + output[5][i]; + tmp5 = output[2][i] - output[5][i]; + tmp3 = output[3][i] + output[4][i]; + tmp4 = output[3][i] - output[4][i]; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + output[0][i] = tmp10 + tmp11; + output[4][i] = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * (double) 0.707106781; + output[2][i] = tmp13 + z1; + output[6][i] = tmp13 - z1; + + tmp10 = tmp4 + tmp5; + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + z5 = (tmp10 - tmp12) * (double) 0.382683433; + z2 = ((double) 0.541196100) * tmp10 + z5; + z4 = ((double) 1.306562965) * tmp12 + z5; + z3 = tmp11 * ((double) 0.707106781); + + z11 = tmp7 + z3; + z13 = tmp7 - z3; + + output[5][i] = z13 + z2; + output[3][i] = z13 - z2; + output[1][i] = z11 + z4; + output[7][i] = z11 - z4; + } + + return output; + } + +} diff --git a/gnu/javax/imageio/jpeg/HuffmanTable.java b/gnu/javax/imageio/jpeg/HuffmanTable.java new file mode 100644 index 000000000..78f3c1c4f --- /dev/null +++ b/gnu/javax/imageio/jpeg/HuffmanTable.java @@ -0,0 +1,207 @@ +/* HuffmanTable.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.io.IOException; + +import javax.imageio.plugins.jpeg.JPEGHuffmanTable; + + +/** + * This Object construct a JPEGHuffmanTable which can be used to encode/decode + * a scan from a JPEG codec stream. The table must be initalized with either a + * BITS byte amount and a Huffman Table Value for decoding or a Huffman Size + * and Huffman Code table for encoding. + */ +public class HuffmanTable +{ + public final static int HUFFMAN_MAX_TABLES = 4; + + private short[] huffcode = new short[256]; + private short[] huffsize = new short[256]; + private short[] EHUFCO; + private short[] EHUFSI; + private short[] valptr = new short[16]; + private short[] mincode = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1,-1,-1}; + private short[] maxcode = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}; + private short[] huffval; + private short[] bits; + + static byte JPEG_DC_TABLE = 0; + static byte JPEG_AC_TABLE = 1; + + private short lastk = 0; + + public HuffmanTable(JPEGHuffmanTable table) + { + huffcode = table.getValues(); + bits = table.getLengths(); + } + + /** + * Generated from FIGURE C.1 - Generation of table of Huffman code sizes on + * ISO DIS 10918-1. Requirements and Guidelines + */ + private void generateSizeTable() + { + short index=0; + for(short i=0; i < bits.length ; i++) + { + for(short j=0; j < bits[i] ; j++) + { + huffsize[index] = (short) (i+1); + index++; + } + } + lastk = index; + } + + /** + * Generated from FIGURE C.2 - Generation of table of Huffman codes on + * ISO DIS 10918-1. Requirements and Guidelines + */ + private void generateCodeTable() + { + short k=0; + short si = huffsize[0]; + short code = 0; + for(short i=0; i < huffsize.length ; i++) + { + while(huffsize[k]==si) + { + huffcode[k] = code; + code++; + k++; + } + code <<= 1; + si++; + } + } + + /** + * Generated from FIGURE F.15 - Generation of decode table generation on + * ISO DIS 10918-1. Requirements and Guidelines + */ + private void generateDecoderTables() + { + short bitcount = 0; + for(int i=0; i < 16 ; i++) + { + if(bits[i]!=0) + valptr[i] = bitcount; + for(int j=0 ; j < bits[i] ; j++) + { + if(huffcode[j+bitcount] < mincode[i] || mincode[i] == -1) + mincode[i] = huffcode[j+bitcount]; + + if(huffcode[j+bitcount] > maxcode[i]) + maxcode[i] = huffcode[j+bitcount]; + } + if(mincode[i]!=-1) + valptr[i] = (short) (valptr[i] - mincode[i]); + bitcount += bits[i]; + } + } + + /** + * Generated from FIGURE C.3 - Generation of Order Codes and tables EHUFCO + * and EHUFSI from the ISO DIS 10918-1. Requirements and Guidelines + */ + public void orderCodes(boolean isDC) + { + EHUFCO = new short[isDC ? 15 : 255]; + EHUFSI = new short[isDC ? 15 : 255]; + + for (int p=0; p < lastk ; p++) + { + int i = huffval[p]; + if(i < 0 || i > EHUFCO.length || EHUFSI[i]!=0) + System.err.println("Error, bad huffman table."); + EHUFCO[i] = huffcode[p]; + EHUFSI[i] = huffsize[p]; + } + } + + /** + * Generated from FIGURE F.12 - Extending the sign bit of a decoded value in on + * ISO DIS 10918-1. Requirements and Guidelines<p> + * + * @param diff TODO + * @param t TODO + * @return TODO + */ + public static int extend(int diff, int t) + { + int Vt = (int)Math.pow(2,(t-1)); + if(diff<Vt) + { + Vt=(-1 << t)+1; + diff=diff+Vt; + } + return diff; + } + + /** + * Generated from FIGURE F.16 - Procedure for DECODE on + * ISO DIS 10918-1. Requirements and Guidelines<p> + * + * This function takes in a dynamic amount of bits and using the Huffman + * table returns information on how many bits must be read in to a byte in + * order to reconstruct said byte. + * + * @param JPEGStream the bits of the data stream. + */ + public int decode(JPEGImageInputStream JPEGStream) + throws IOException, JPEGException + { + int i=0; + short code = (short) JPEGStream.readBits(1); + while(code > maxcode[i]) + { + i++; + code <<= 1; + code |= JPEGStream.readBits(1); + } + int val = huffval[code+(valptr[i])]; + if(val < 0) + val = 256 + val; + return val; + } +} diff --git a/gnu/javax/imageio/jpeg/JPEGComponent.java b/gnu/javax/imageio/jpeg/JPEGComponent.java new file mode 100644 index 000000000..d5799fd41 --- /dev/null +++ b/gnu/javax/imageio/jpeg/JPEGComponent.java @@ -0,0 +1,351 @@ +/* JPEGComponent.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.util.ArrayList; +import java.io.IOException; +import java.awt.image.WritableRaster; + +import javax.imageio.plugins.jpeg.JPEGHuffmanTable; + +/** + * This class holds the methods to decode and write a component information to + * a raster. + */ +public class JPEGComponent +{ + public byte factorH, factorV, component_id, quant_id; + public int width = 0, height = 0, maxV = 0, maxH = 0; + public HuffmanTable ACTable; + public HuffmanTable DCTable; + public int[] quantizationTable; + public double previousDC = 0; + ArrayList data = new ArrayList(); + + /** + * Initializes the component + * + * @param id + * @param factorHorizontal + * @param factorVertical + * @param quantizationID + */ + public JPEGComponent(byte id, byte factorHorizontal, byte factorVertical, + byte quantizationID) + { + component_id = id; + factorH = factorHorizontal; + factorV = factorVertical; + quant_id = quantizationID; + } + + /** + * If a restart marker is found with too little of an MCU count (i.e. our + * Restart Interval is 63 and we have 61 we copy the last MCU until it's + * full) + * + * @param index + * @param length + */ + public void padMCU(int index, int length) + { + double[] src = (double[]) data.get(index - 1); + for (int i = 0; i < length; i++) + data.add(index, src); + } + + /** + * Reset the interval by setting the previous DC value + */ + public void resetInterval() + { + previousDC = 0; + } + + /** + * Run the Quantization backward method on all of the block data. + */ + public void quantitizeData() + { + for (int i = 0; i < data.size(); i++) + { + double[] mydata = (double[]) data.get(i); + for (int j = 0; j < mydata.length; j++) + mydata[j] *= quantizationTable[j]; + } + } + + public void setDCTable(JPEGHuffmanTable table) + { + DCTable = new HuffmanTable(table); + } + + public void setACTable(JPEGHuffmanTable table) + { + ACTable = new HuffmanTable(table); + } + + /** + * Run the Inverse DCT method on all of the block data + */ + public void idctData(DCT myDCT) + { + for (int i = 0; i < data.size(); i++) + data.add(i,myDCT.fast_idct(ZigZag.decode8x8_map((double[]) data.remove(i)))); + } + + /** + * This scales up the component size based on the factor size. This + * calculates everyting up automatically so it's simply ran at the end of + * the frame to normalize the size of all of the components. + */ + public void scaleByFactors() + { + int factorUpVertical = maxV / factorV; + int factorUpHorizontal = maxH / factorH; + + if (factorUpVertical > 1) + { + for (int i = 0; i < data.size(); i++) + { + double[][] src = (double[][]) data.remove(i); + double[][] dest = + new double[src.length * factorUpVertical][src[0].length]; + for (int j = 0; j < src.length; j++) + { + for (int u = 0; u < factorUpVertical; u++) + { + dest[j * factorUpVertical + u] = src[j]; + } + } + data.add(i, dest); + } + } + + if (factorUpHorizontal > 1) + { + for (int i = 0; i < data.size(); i++) + { + double[][] src = (double[][]) data.remove(i); + double[][] dest = + new double[src.length][src[0].length * factorUpHorizontal]; + for (int j = 0; j < src.length; j++) + { + for (int u = 0; u < src[0].length; u++) + { + for (int v = 0; v < factorUpHorizontal; v++) + dest[j][u * factorUpHorizontal + v] = src[j][u]; + } + } + data.add(i, dest); + } + } + } + + /** + * This write the block of data to the raster throwing out anything that + * spills over the raster width or height. + * + * @param raster + * @param data + * @param compIndex + * @param x + * @param y + */ + public void writeBlock(WritableRaster raster, double[][] data, + int compIndex, int x, int y) + { + for (int yIndex = 0; yIndex < data.length; yIndex++) + { + for (int xIndex = 0; xIndex < data[yIndex].length; xIndex++) + { + // The if statement is needed because blocks can spill over the + // frame width because they are padded to make sure we keep the + // height of the block the same as the width of the block + if (x + xIndex < raster.getWidth() + && y + yIndex < raster.getHeight()) + raster.setSample(x + xIndex, y + yIndex, compIndex, + data[yIndex][xIndex]); + } + } + } + + /** + * This writes data to a raster block, so really it's reading not writing + * but it writes the data to the raster block by factor size in a zig zag + * fashion. This has the helper function writeBlock which does the actual + * writing. + * + * @param raster + * @param componentIndex + */ + public void writeData(WritableRaster raster, int componentIndex) + { + int x = 0, y = 0, lastblockheight = 0, incrementblock = 0; + + // Keep looping through all of the blocks until there are no more. + while(data.size() > 0) + { + int blockwidth = 0; + int blockheight = 0; + + if (x >= raster.getWidth()) + { + x = 0; + y += incrementblock; + } + + // Loop through the horizontal component blocks of the MCU first + // then for each horizontal line write out all of the vertical + // components + for (int factorVIndex = 0; factorVIndex < factorV; factorVIndex++) + { + blockwidth = 0; + + for (int factorHIndex = 0; factorHIndex < factorH; factorHIndex++) + { + // Captures the width of this block so we can increment the + // X coordinate + double[][] blockdata = (double[][]) data.remove(0); + + // Writes the data at the specific X and Y coordinate of + // this component + writeBlock(raster, blockdata, componentIndex, x, y); + blockwidth += blockdata[0].length; + x += blockdata[0].length; + blockheight = blockdata.length; + } + y += blockheight; + x -= blockwidth; + lastblockheight += blockheight; + } + y -= lastblockheight; + incrementblock = lastblockheight; + lastblockheight = 0; + x += blockwidth; + } + } + + /** + * Set the quantization table for this component. + * + * @param quanttable + */ + public void setQuantizationTable(int[] quanttable) + { + quantizationTable = quanttable; + } + + /** + * Read in a partial MCU for this component + * + * @param stream TODO + * @throws JPEGException TODO + * @throws IOException TODO + */ + public void readComponentMCU(JPEGImageInputStream stream) + throws JPEGException, IOException + { + for (int i = 0; i < factorH * factorV; i++) + { + double dc = decode_dc_coefficient(stream); + double[] datablock = decode_ac_coefficients(stream); + datablock[0] = dc; + data.add(datablock); + } + } + + /** + * Generated from text on F-22, F.2.2.1 - Huffman decoding of DC + * coefficients on ISO DIS 10918-1. Requirements and Guidelines. + * + * @param JPEGStream TODO + * + * @return TODO + * @throws JPEGException TODO + * @throws IOException TODO + */ + public double decode_dc_coefficient(JPEGImageInputStream JPEGStream) + throws JPEGException, IOException + { + int t = DCTable.decode(JPEGStream); + double diff = JPEGStream.readBits(t); + diff = HuffmanTable.extend((int) diff, t); + diff = (previousDC + diff); + previousDC = diff; + return diff; + } + + /** + * Generated from text on F-23, F.13 - Huffman decoded of AC coefficients + * on ISO DIS 10918-1. Requirements and Guidelines. + * + * @param JPEGStream TODO + * @return TODO + * + * @throws JPEGException TODO + * @throws IOException TODO + */ + public double[] decode_ac_coefficients(JPEGImageInputStream JPEGStream) + throws JPEGException, IOException + { + double[] zz = new double[64]; + + for (int k = 1; k < 64; k++) + { + int s = ACTable.decode(JPEGStream); + int r = s >> 4; + s &= 15; + + if (s != 0) + { + k += r; + r = (int) JPEGStream.readBits(s); + s = (int) HuffmanTable.extend(r, s); + zz[k] = s; + } + else + { + if (r != 15) + return (zz); + k += 15; + } + } + return zz; + } +} diff --git a/gnu/javax/imageio/jpeg/JPEGDecoder.java b/gnu/javax/imageio/jpeg/JPEGDecoder.java new file mode 100644 index 000000000..3610ebe87 --- /dev/null +++ b/gnu/javax/imageio/jpeg/JPEGDecoder.java @@ -0,0 +1,630 @@ +/* JPEGDecoder.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.io.IOException; +import java.nio.ByteOrder; + +import javax.imageio.*; +import javax.imageio.plugins.jpeg.JPEGHuffmanTable; +import javax.imageio.plugins.jpeg.JPEGQTable; +import javax.imageio.spi.*; +import javax.imageio.metadata.*; +import javax.imageio.stream.ImageInputStream; + +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Iterator; +import java.awt.Point; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ComponentColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; + +public class JPEGDecoder +{ + byte majorVersion; + byte minorVersion; + byte units; + short Xdensity; + short Ydensity; + byte Xthumbnail; + byte Ythumbnail; + byte[] thumbnail; + BufferedImage image; + int width; + int height; + + byte marker; + + /** + * This decoder expects JFIF 1.02 encoding. + */ + public static final byte MAJOR_VERSION = (byte) 1; + public static final byte MINOR_VERSION = (byte) 2; + + /** + * The length of the JFIF field not including thumbnail data. + */ + public static final short JFIF_FIXED_LENGTH = 16; + + /** + * The length of the JFIF extension field not including extension + * data. + */ + public static final short JFXX_FIXED_LENGTH = 8; + + private JPEGImageInputStream jpegStream; + + ArrayList jpegFrames = new ArrayList(); + + JPEGHuffmanTable[] dcTables = new JPEGHuffmanTable[4]; + JPEGHuffmanTable[] acTables = new JPEGHuffmanTable[4]; + JPEGQTable[] qTables = new JPEGQTable[4]; + + public int getHeight() + { + return height; + } + + public int getWidth() + { + return width; + } + public JPEGDecoder(ImageInputStream in) + throws IOException, JPEGException + { + jpegStream = new JPEGImageInputStream(in); + jpegStream.setByteOrder(ByteOrder.LITTLE_ENDIAN); + + if (jpegStream.findNextMarker() != JPEGMarker.SOI) + throw new JPEGException("Failed to find SOI marker."); + + if (jpegStream.findNextMarker() != JPEGMarker.APP0) + throw new JPEGException("Failed to find APP0 marker."); + + int length = jpegStream.readShort(); + if (!(length >= JFIF_FIXED_LENGTH)) + throw new JPEGException("Failed to find JFIF field."); + + byte[] identifier = new byte[5]; + jpegStream.read(identifier); + if (identifier[0] != JPEGMarker.JFIF_J + || identifier[1] != JPEGMarker.JFIF_F + || identifier[2] != JPEGMarker.JFIF_I + || identifier[3] != JPEGMarker.JFIF_F + || identifier[4] != JPEGMarker.X00) + throw new JPEGException("Failed to read JFIF identifier."); + + majorVersion = jpegStream.readByte(); + minorVersion = jpegStream.readByte(); + if (majorVersion != MAJOR_VERSION + || (majorVersion == MAJOR_VERSION + && minorVersion < MINOR_VERSION)) + throw new JPEGException("Unsupported JFIF version."); + + units = jpegStream.readByte(); + if (units > (byte) 2) + throw new JPEGException("Units field is out of range."); + + Xdensity = jpegStream.readShort(); + Ydensity = jpegStream.readShort(); + Xthumbnail = jpegStream.readByte(); + Ythumbnail = jpegStream.readByte(); + + // 3 * for RGB data + int thumbnailLength = 3 * Xthumbnail * Ythumbnail; + if (length > JFIF_FIXED_LENGTH + && thumbnailLength != length - JFIF_FIXED_LENGTH) + throw new JPEGException("Invalid length, Xthumbnail" + + " or Ythumbnail field."); + + if (thumbnailLength > 0) + { + thumbnail = new byte[thumbnailLength]; + if (jpegStream.read(thumbnail) != thumbnailLength) + throw new IOException("Failed to read thumbnail."); + } + } + + public void decode() + throws IOException + { + System.out.println ("DECODE!!!"); + // The frames in this jpeg are loaded into a list. There is + // usually just one frame except in heirarchial progression where + // there are multiple frames. + JPEGFrame frame = null; + + // The restart interval defines how many MCU's we should have + // between the 8-modulo restart marker. The restart markers allow + // us to tell whether or not our decoding process is working + // correctly, also if there is corruption in the image we can + // recover with these restart intervals. (See RSTm DRI). + int resetInterval = 0; + + // The JPEGDecoder constructor parses the JFIF field. At this + // point jpegStream points to the first byte after the JFIF field. + + // Find the first marker after the JFIF field. + byte marker = jpegStream.findNextMarker(); + + // Check for a JFIF extension field directly following the JFIF + // header and advance the current marker to the next marker in the + // stream, if necessary. + decodeJFIFExtension(); + + // Loop through until there are no more markers to read in, at + // that point everything is loaded into the jpegFrames array and + // can be processed. + while (true) + { + switch (marker) + { + // APPn Application Reserved Information - Just throw this + // information away because we wont be using it. + case JPEGMarker.APP0: + case JPEGMarker.APP1: + case JPEGMarker.APP2: + case JPEGMarker.APP3: + case JPEGMarker.APP4: + case JPEGMarker.APP5: + case JPEGMarker.APP6: + case JPEGMarker.APP7: + case JPEGMarker.APP8: + case JPEGMarker.APP9: + case JPEGMarker.APP10: + case JPEGMarker.APP11: + case JPEGMarker.APP12: + case JPEGMarker.APP13: + case JPEGMarker.APP14: + case JPEGMarker.APP15: + jpegStream.skipBytes(jpegStream.readShort() - 2); + break; + + case JPEGMarker.SOF0: + // SOFn Start of Frame Marker, Baseline DCT - This is the start + // of the frame header that defines certain variables that will + // be carried out through the rest of the encoding. Multiple + // frames are used in a heirarchiel system, however most JPEG's + // only contain a single frame. + jpegFrames.add(new JPEGFrame()); + frame = (JPEGFrame) jpegFrames.get(jpegFrames.size() - 1); + // Skip the frame length. + jpegStream.readShort(); + // Bits percision, either 8 or 12. + frame.setPrecision(jpegStream.readByte()); + // Scan lines = to the height of the frame. + frame.setScanLines(jpegStream.readShort()); + // Scan samples per line = to the width of the frame. + frame.setSamplesPerLine(jpegStream.readShort()); + // Number of Color Components (or channels). + frame.setComponentCount(jpegStream.readByte()); + + // Set the color mode for this frame, so far only 2 color + // modes are supported. + if (frame.getComponentCount() == 1) + frame.setColorMode(JPEGFrame.JPEG_COLOR_GRAY); + else + frame.setColorMode(JPEGFrame.JPEG_COLOR_YCbCr); + // Add all of the necessary components to the frame. + for (int i = 0; i < frame.getComponentCount(); i++) + frame.addComponent(jpegStream.readByte(), jpegStream.readByte(), + jpegStream.readByte()); + break; + + case JPEGMarker.SOF2: + jpegFrames.add(new JPEGFrame()); + frame = (JPEGFrame) jpegFrames.get(jpegFrames.size() - 1); + // Skip the frame length. + jpegStream.readShort(); + // Bits percision, either 8 or 12. + frame.setPrecision(jpegStream.readByte()); + // Scan lines = to the height of the frame. + frame.setScanLines(jpegStream.readShort()); + // Scan samples per line = to the width of the frame. + frame.setSamplesPerLine(jpegStream.readShort()); + // Number of Color Components (or channels). + frame.setComponentCount(jpegStream.readByte()); + + // Set the color mode for this frame, so far only 2 color + // modes are supported. + if (frame.getComponentCount() == 1) + frame.setColorMode(JPEGFrame.JPEG_COLOR_GRAY); + else + frame.setColorMode(JPEGFrame.JPEG_COLOR_YCbCr); + + // Add all of the necessary components to the frame. + for (int i = 0; i < frame.getComponentCount(); i++) + frame.addComponent(jpegStream.readByte(), jpegStream.readByte(), + jpegStream.readByte()); + break; + + case JPEGMarker.DHT: + // DHT non-SOF Marker - Huffman Table is required for decoding + // the JPEG stream, when we receive a marker we load in first + // the table length (16 bits), the table class (4 bits), table + // identifier (4 bits), then we load in 16 bytes and each byte + // represents the count of bytes to load in for each of the 16 + // bytes. We load this into an array to use later and move on 4 + // huffman tables can only be used in an image. + int huffmanLength = (jpegStream.readShort() - 2); + + // Keep looping until we are out of length. + int index = huffmanLength; + + // Multiple tables may be defined within a DHT marker. This + // will keep reading until there are no tables left, most + // of the time there are just one tables. + while (index > 0) + { + // Read the identifier information and class + // information about the Huffman table, then read the + // 16 byte codelength in and read in the Huffman values + // and put it into table info. + byte huffmanInfo = jpegStream.readByte(); + byte tableClass = (byte) (huffmanInfo >> 4); + byte huffmanIndex = (byte) (huffmanInfo & 0x0f); + short[] codeLength = new short[16]; + jpegStream.readFully(codeLength, 0, codeLength.length); + int huffmanValueLen = 0; + for (int i = 0; i < 16; i++) + huffmanValueLen += codeLength[i]; + index -= (huffmanValueLen + 17); + short[] huffmanVal = new short[huffmanValueLen]; + for (int i = 0; i < huffmanVal.length; i++) + huffmanVal[i] = jpegStream.readByte(); + // Assign DC Huffman Table. + if (tableClass == HuffmanTable.JPEG_DC_TABLE) + dcTables[(int) huffmanIndex] = new JPEGHuffmanTable(codeLength, + huffmanVal); + // Assign AC Huffman Table. + else if (tableClass == HuffmanTable.JPEG_AC_TABLE) + acTables[(int) huffmanIndex] = new JPEGHuffmanTable(codeLength, + huffmanVal); + } + break; + case JPEGMarker.DQT: + // DQT non-SOF Marker - This defines the quantization + // coeffecients, this allows us to figure out the quality of + // compression and unencode the data. The data is loaded and + // then stored in to an array. + short quantizationLength = (short) (jpegStream.readShort() - 2); + for (int j = 0; j < quantizationLength / 65; j++) + { + byte quantSpecs = jpegStream.readByte(); + int[] quantData = new int[64]; + if ((byte) (quantSpecs >> 4) == 0) + // Precision 8 bit. + { + for (int i = 0; i < 64; i++) + quantData[i] = jpegStream.readByte(); + + } + else if ((byte) (quantSpecs >> 4) == 1) + // Precision 16 bit. + { + for (int i = 0; i < 64; i++) + quantData[i] = jpegStream.readShort(); + } + qTables[(int) (quantSpecs & 0x0f)] = new JPEGQTable (quantData); + } + break; + case JPEGMarker.SOS: + // SOS non-SOF Marker - Start Of Scan Marker, this is where the + // actual data is stored in a interlaced or non-interlaced with + // from 1-4 components of color data, if three components most + // likely a YCrCb model, this is a fairly complex process. + + // Read in the scan length. + jpegStream.readShort(); + // Number of components in the scan. + byte numberOfComponents = jpegStream.readByte(); + byte[] componentSelector = new byte[numberOfComponents]; + for (int i = 0; i < numberOfComponents; i++) + { + // Component ID, packed byte containing the Id for the + // AC table and DC table. + byte componentID = jpegStream.readByte(); + byte tableInfo = jpegStream.readByte(); + frame.setHuffmanTables(componentID, + acTables[(byte) (tableInfo >> 4)], + dcTables[(byte) (tableInfo & 0x0f)]); + componentSelector[i] = componentID; + } + byte startSpectralSelection = jpegStream.readByte(); + byte endSpectralSelection = jpegStream.readByte(); + byte successiveApproximation = jpegStream.readByte(); + + int mcuIndex = 0; + int mcuTotalIndex = 0; + // This loops through until a MarkerTagFound exception is + // found, if the marker tag is a RST (Restart Marker) it + // simply skips it and moves on this system does not handle + // corrupt data streams very well, it could be improved by + // handling misplaced restart markers. + while (true) + { + try + { + // Loop though capturing MCU, instruct each + // component to read in its necessary count, for + // scaling factors the components automatically + // read in how much they need + for (int compIndex = 0; compIndex < numberOfComponents; compIndex++) + { + JPEGComponent comp = (JPEGComponent) frame.components.getComponentByID(componentSelector[compIndex]); + comp.readComponentMCU(jpegStream); + } + mcuIndex++; + mcuTotalIndex++; + } + // We've found a marker, see if the marker is a restart + // marker or just the next marker in the stream. If + // it's the next marker in the stream break out of the + // while loop, if it's just a restart marker skip it + catch (JPEGMarkerFoundException bse) + { + // Handle JPEG Restart Markers, this is where the + // count of MCU's per interval is compared with + // the count actually obtained, if it's short then + // pad on some MCU's ONLY for components that are + // greater than one. Also restart the DC prediction + // to zero. + if (marker == JPEGMarker.RST0 + || marker == JPEGMarker.RST1 + || marker == JPEGMarker.RST2 + || marker == JPEGMarker.RST3 + || marker == JPEGMarker.RST4 + || marker == JPEGMarker.RST5 + || marker == JPEGMarker.RST6 + || marker == JPEGMarker.RST7) + { + for (int compIndex = 0; compIndex < numberOfComponents; compIndex++) + { + JPEGComponent comp = (JPEGComponent) frame.components.getComponentByID(componentSelector[compIndex]); + if (compIndex > 1) + comp.padMCU(mcuTotalIndex, resetInterval - mcuIndex); + comp.resetInterval(); + } + mcuTotalIndex += (resetInterval - mcuIndex); + mcuIndex = 0; + } + else + { + // We're at the end of our scan, exit out. + break; + } + } + } + break; + case JPEGMarker.DRI: + // DRI - This defines the restart interval, if we have a + // restart interval when we reach our restart modulo calculate + // whether the count of MCU's specified in the restart + // interval have been reached, if they havent then pad with + // whatever MCU was last used, this is supposed to be a form of + // error recovery but it turns out that some JPEG encoders + // purposely cause missing MCU's on repeating MCU's to compress + // data even more (even though it adds an extra layer of + // complexity.. But since when is JPEG easy? + jpegStream.skipBytes(2); + resetInterval = jpegStream.readShort(); + break; + case JPEGMarker.COM: + // COM - This is a comment that was inserted into the JPEG, we + // simply skip over the comment because it's really of no + // importance, usually contains a verbal description of the + // application or author who created the JPEG. + jpegStream.skipBytes(jpegStream.readShort() - 2); + break; + case JPEGMarker.DNL: + // DNL - This sets the height of the image. This is the Define + // Number Lines for the image, I'm not sure exactly why we need + // this but, whatever we'll abide. + frame.setScanLines(jpegStream.readShort()); + break; + case JPEGMarker.EOI: + // EOI - End of Image, this processes the frames and turns the + // frames into a buffered image. + + if (jpegFrames.size() == 0) + { + return; + } + else if (jpegFrames.size() == 1) + { + // Only one frame, JPEG Non-Heirarchial Frame. + + DCT myDCT = new DCT(); + WritableRaster raster = + Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, + frame.width, + frame.height, + frame.getComponentCount(), + new Point(0, 0)); + + // Unencode the data. + for (int i = 0; i < frame.getComponentCount(); i++) + { + JPEGComponent comp = + (JPEGComponent) frame.components.get(i); + comp.setQuantizationTable(qTables[comp.quant_id].getTable()); + comp.quantitizeData(); + comp.idctData(myDCT); + } + // Scale the image and write the data to the raster. + for (int i = 0; i < frame.getComponentCount(); i++) + { + JPEGComponent comp = (JPEGComponent) frame.components.get(i); + comp.scaleByFactors(); + comp.writeData(raster, i); + // Ensure garbage collection. + comp = null; + } + // Grayscale Color Image (1 Component). + if (frame.getComponentCount() == 1) + { + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY); + ComponentColorModel ccm = + new ComponentColorModel(cs, false, false, + Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + image = new BufferedImage(ccm, raster, false, + new Hashtable()); + } + // YCbCr Color Image (3 Components). + else if (frame.getComponentCount() == 3) + { + ComponentColorModel ccm = + new ComponentColorModel(new YCbCr_ColorSpace(), false, + false, Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + image = new BufferedImage(ccm, raster, false, + new Hashtable()); + } + // Possibly CMYK or RGBA ? + else + { + throw new JPEGException("Unsupported Color Mode: 4 " + + "Component Color Mode found."); + } + height = frame.height; + width = frame.width; + } + else + { + //JPEG Heirarchial Frame (progressive or baseline). + throw new JPEGException("Unsupported Codec Type:" + + " Hierarchial JPEG"); + } + break; + case JPEGMarker.SOF1: + // ERROR - If we encounter any of the following marker codes + // error out with a codec exception, progressive, heirarchial, + // differential, arithmetic, lossless JPEG's are not supported. + // This is where enhancements can be made for future versions. + // Thankfully 99% of all JPEG's are baseline DCT. + throw new JPEGException("Unsupported Codec Type: Extended " + + "Sequential DCT JPEG's Not-Supported"); + //case JPEGMarker.SOF2: + // throw new JPEGException("Unsupported Codec Type: Progressive DCT JPEG's Not-Supported"); + case JPEGMarker.SOF3: + throw new JPEGException("Unsupported Codec Type:" + + " Lossless (sequential)"); + case JPEGMarker.SOF5: + throw new JPEGException("Unsupported Codec Type:" + + " Differential sequential DCT"); + case JPEGMarker.SOF6: + throw new JPEGException("Unsupported Codec Type:" + + " Differential progressive DCT"); + case JPEGMarker.SOF7: + throw new JPEGException("Unsupported Codec Type:" + + " Differential lossless"); + case JPEGMarker.SOF9: + case JPEGMarker.SOF10: + case JPEGMarker.SOF11: + case JPEGMarker.SOF13: + case JPEGMarker.SOF14: + case JPEGMarker.SOF15: + throw new JPEGException("Unsupported Codec Type:" + + " Arithmetic Coding Frame"); + default: + // Unknown marker found, ignore it. + } + marker = jpegStream.findNextMarker(); + } + } + + // If the current marker is APP0, tries to decode a JFIF extension + // and advances the current marker to the next marker in the stream. + private void decodeJFIFExtension() throws IOException + { + if (marker == JPEGMarker.APP0) + { + int length = jpegStream.readShort(); + + if (length >= JFXX_FIXED_LENGTH) + { + byte[] identifier = new byte[5]; + jpegStream.read(identifier); + if (identifier[0] != JPEGMarker.JFIF_J + || identifier[1] != JPEGMarker.JFIF_F + || identifier[2] != JPEGMarker.JFIF_X + || identifier[3] != JPEGMarker.JFIF_X + || identifier[4] != JPEGMarker.X00) + // Not a JFXX field. Ignore it and continue. + jpegStream.skipBytes(length - 7); + else + { + byte extension_code = jpegStream.readByte(); + + switch (extension_code) + { + case JPEGMarker.JFXX_JPEG: + // FIXME: add support for JFIF Extension: + // Thumbnail coded using JPEG. + jpegStream.skipBytes(length - 8); + case JPEGMarker.JFXX_ONE_BPP: + // FIXME: add support for JFIF Extension: + // Thumbnail stored using 1 byte/pixel. + jpegStream.skipBytes(length - 8); + case JPEGMarker.JFXX_THREE_BPP: + // FIXME: add support for JFIF Extension: + // Thumbnail stored using 3 bytes/pixel. + jpegStream.skipBytes(length - 8); + } + } + } + else + { + // Unknown APP0 marker. Ignore it and continue. + jpegStream.skipBytes(length - 2); + } + marker = jpegStream.findNextMarker(); + } + } + + public BufferedImage getImage() + { + return image; + } +} diff --git a/gnu/javax/imageio/jpeg/JPEGException.java b/gnu/javax/imageio/jpeg/JPEGException.java new file mode 100644 index 000000000..b684069cc --- /dev/null +++ b/gnu/javax/imageio/jpeg/JPEGException.java @@ -0,0 +1,55 @@ +/* JPEGException.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +// FIXME: change to IIOException +import java.io.IOException; +import javax.imageio.*; +import javax.imageio.spi.*; +import javax.imageio.metadata.*; +import javax.imageio.stream.ImageInputStream; +import java.util.Iterator; +import java.awt.image.BufferedImage; + +public class JPEGException extends IIOException +{ + public JPEGException(String message) + { + super(message); + } +} diff --git a/gnu/javax/imageio/jpeg/JPEGFrame.java b/gnu/javax/imageio/jpeg/JPEGFrame.java new file mode 100644 index 000000000..9b958f98f --- /dev/null +++ b/gnu/javax/imageio/jpeg/JPEGFrame.java @@ -0,0 +1,108 @@ +/* JPEGFrame.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import javax.imageio.plugins.jpeg.JPEGHuffmanTable; + +public class JPEGFrame +{ + public final static byte JPEG_COLOR_GRAY = 1; + public final static byte JPEG_COLOR_RGB = 2; + public final static byte JPEG_COLOR_YCbCr = 3; + public final static byte JPEG_COLOR_CMYK = 4; + + public byte precision = 8; + public byte colorMode = JPEGFrame.JPEG_COLOR_YCbCr; + public byte componentCount = 0; + + public short width=0, height=0; + + public JPEGScan components; + + public JPEGFrame() + { + components = new JPEGScan(); + } + + public void addComponent(byte componentID, byte sampleFactors, + byte quantizationTableID) + { + byte sampleHorizontalFactor = (byte)(sampleFactors >> 4); + byte sampleVerticalFactor = (byte)(sampleFactors & 0x0f); + components.addComponent(componentID, sampleHorizontalFactor, + sampleVerticalFactor, quantizationTableID); + } + + public void setPrecision(byte data) + { + precision = data; + } + + public void setScanLines(short data) + { + height = data; + } + + public void setSamplesPerLine(short data) + { + width = data; + } + + public void setColorMode(byte data) + { + colorMode = data; + } + + public void setComponentCount(byte data) + { + componentCount = data; + } + + public byte getComponentCount() + { + return componentCount; + } + + public void setHuffmanTables(byte componentID, JPEGHuffmanTable ACTable, + JPEGHuffmanTable DCTable) + { + JPEGComponent comp = (JPEGComponent)components.getComponentByID(componentID); + comp.setACTable(ACTable); + comp.setDCTable(DCTable); + } +} diff --git a/gnu/javax/imageio/jpeg/JPEGImageInputStream.java b/gnu/javax/imageio/jpeg/JPEGImageInputStream.java new file mode 100644 index 000000000..4ae909baf --- /dev/null +++ b/gnu/javax/imageio/jpeg/JPEGImageInputStream.java @@ -0,0 +1,195 @@ +/* JPEGImageInputStream.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.io.EOFException; +import java.io.IOException; +import javax.imageio.*; +import javax.imageio.spi.*; +import javax.imageio.metadata.*; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.ImageInputStreamImpl; + +import java.util.Iterator; +import java.awt.image.BufferedImage; + +public class JPEGImageInputStream + extends ImageInputStreamImpl +{ + private ImageInputStream in; + + byte marker; + + public JPEGImageInputStream(ImageInputStream in) + { + super(); + + this.in = in; + } + + public int read() + throws IOException + { + setBitOffset(0); + return in.read(); + } + + public int read(byte[] data, int offset, int len) + throws IOException + { + setBitOffset(0); + return in.read(data, offset, len); + } + + /** + * Pull a byte from the stream, this checks to see if the byte is 0xff + * and if the next byte isn't 0x00 (stuffed byte) it errors out. If it's + * 0x00 then it simply ignores the byte. + * + * @return the next byte in the buffer + * + * @throws IOException TODO + * @throws BitStreamException TODO + */ + private byte pullByte() throws IOException, JPEGMarkerFoundException + { + byte mybyte = readByte(); + // FIXME: handle multiple 0xff in a row + if(mybyte==(byte)(0xff)) + { + byte secondbyte = readByte(); + if(secondbyte != (byte)(0x00)) + { + marker = secondbyte; + throw new JPEGMarkerFoundException(); + } + } + return mybyte; + } + + /** + * This returns the marker that was last encountered. This should only be + * used if removeBit() throws a MarkerTagFound exception. + * + * @return marker as byte + */ + public byte getMarker() + { + return marker; + } + + /** + * Removes a bit from the buffer. (Removes from the top of a queue). This + * also checks for markers and throws MarkerTagFound exception if it does. + * If MarkerTagFound is thrown you can use getMarker() method to get the + * marker that caused the throw. + * + * @param l specifies how many bits you want to remove and add to the + * integer + * @return the amount of bits specified by l as an integer + * + * @throws IOException TODO + * @throws JPEGMarkerFoundException + * @throws BitStreamException TODO + */ + public int readBit() + throws IOException, JPEGMarkerFoundException +{ + checkClosed(); + + // Calc new bit offset here, readByte resets it. + int newOffset = (bitOffset + 1) & 0x7; + + byte data = pullByte(); + + if (bitOffset != 0) + { + seek(getStreamPosition() - 1); + data = (byte) (data >> (8 - newOffset)); + } + + bitOffset = newOffset; + return data & 0x1; +} + + + /** + * This method skips over the the data and finds the next position + * in the bit sequence with a X'FF' X'??' sequence. Multiple X'FF + * bytes in sequence are considered padding and interpreted as one + * X'FF byte. + * + * @return the next marker byte in the stream + * @throws IOException if the end of the stream is reached + * unexpectedly + */ + public byte findNextMarker() + throws IOException + { + boolean marked0xff = false; + byte byteinfo = JPEGMarker.X00; + + setBitOffset(0); + while (true) + { + byteinfo = readByte(); + if (!marked0xff) + { + if (byteinfo == JPEGMarker.XFF) + marked0xff = true; + } + else + { + if (byteinfo == JPEGMarker.XFF) + // Ignore the value 0xff when it is immediately + // followed by another 0xff byte. + continue; + else if (byteinfo == JPEGMarker.X00) + // The sequence 0xff 0x00 is used to encode the + // actual value 0xff. So restart our search for a + // marker. + marked0xff = false; + else + // One or more 0xff values were follwed by a + // non-0x00, non-0xff value so return this as the + // marker byte. + return byteinfo; + } + } + } +} diff --git a/gnu/javax/imageio/jpeg/JPEGImageReader.java b/gnu/javax/imageio/jpeg/JPEGImageReader.java new file mode 100644 index 000000000..51bc0ce37 --- /dev/null +++ b/gnu/javax/imageio/jpeg/JPEGImageReader.java @@ -0,0 +1,141 @@ +/* JPEGImageReader.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.io.IOException; +import javax.imageio.*; +import javax.imageio.spi.*; +import javax.imageio.metadata.*; +import javax.imageio.stream.ImageInputStream; +import java.util.Iterator; +import java.awt.image.BufferedImage; + +public class JPEGImageReader extends ImageReader +{ + JPEGDecoder decoder; + + protected JPEGImageReader(ImageReaderSpi originatingProvider) + { + super(originatingProvider); + System.out.println("JPEGIMAGEREADER!!!"); + } + + // Abstract ImageReader methods. + public int getHeight(int imageIndex) + throws IOException + { + checkIndex(imageIndex); + decodeStream(); + return decoder.getHeight(); + } + + public IIOMetadata getImageMetadata(int imageIndex) + throws IOException + { + // FIXME: handle metadata + checkIndex(imageIndex); + return null; + } + + public Iterator getImageTypes(int imageIndex) + throws IOException + { + return null; + } + + public int getNumImages(boolean allowSearch) + throws IOException + { + return 1; + } + + public IIOMetadata getStreamMetadata() + throws IOException + { + // FIXME: handle metadata + return null; + } + + public int getWidth(int imageIndex) + throws IOException + { + checkIndex(imageIndex); + decodeStream(); + return decoder.getWidth(); + } + + public BufferedImage read(int imageIndex, ImageReadParam param) + throws IOException + { + checkIndex(imageIndex); + decodeStream(); + return decoder.getImage(); + } + + // private helper methods + private void checkIndex(int imageIndex) + throws IndexOutOfBoundsException + { + if (imageIndex != 0) + throw new IndexOutOfBoundsException(); + } + + private void checkStream() throws IOException + { + if (!(input instanceof ImageInputStream)) + throw new IllegalStateException("Input not an ImageInputStream."); + if(input == null) + throw new IllegalStateException("No input stream."); + } + + private void decodeStream() + throws IOException, IIOException + { + System.out.println("DECONDING 1"); + if (decoder != null) + return; + + System.out.println("DECONDING 2"); + checkStream(); + + System.out.println("DECONDING 3"); + decoder = new JPEGDecoder((ImageInputStream)input); + System.out.println("DECONDING 4"); + decoder.decode(); + } +} diff --git a/gnu/javax/imageio/jpeg/JPEGImageReaderSpi.java b/gnu/javax/imageio/jpeg/JPEGImageReaderSpi.java new file mode 100644 index 000000000..c1e9adf60 --- /dev/null +++ b/gnu/javax/imageio/jpeg/JPEGImageReaderSpi.java @@ -0,0 +1,137 @@ +/* JPEGImageReaderSpi.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.io.IOException; +import java.util.Locale; +import javax.imageio.ImageReader; +import javax.imageio.spi.ImageReaderSpi; +import javax.imageio.spi.IIORegistry; +import javax.imageio.stream.ImageInputStream; + +public class JPEGImageReaderSpi extends ImageReaderSpi +{ + static final String vendorName = "GNU"; + static final String version = "0.1"; + static final String readerClassName = + "gnu.javax.imageio.jpeg.JPEGImageReader"; + static final String[] names = { "JPEG" }; + static final String[] suffixes = { ".jpeg", ".jpg", ".jpe" }; + static final String[] MIMETypes = { "image/jpeg" }; + static final String[] writerSpiNames = + { "gnu.javax.imageio.jpeg.JPEGImageWriterSpi" }; + + static final boolean supportsStandardStreamMetadataFormat = false; + static final String nativeStreamMetadataFormatName = null; + static final String nativeStreamMetadataFormatClassName = null; + static final String[] extraStreamMetadataFormatNames = null; + static final String[] extraStreamMetadataFormatClassNames = null; + static final boolean supportsStandardImageMetadataFormat = false; + static final String nativeImageMetadataFormatName = null; + static final String nativeImageMetadataFormatClassName = null; + static final String[] extraImageMetadataFormatNames = null; + static final String[] extraImageMetadataFormatClassNames = null; + + private static JPEGImageReaderSpi readerSpi; + + public JPEGImageReaderSpi() + { + super(vendorName, version, + names, suffixes, MIMETypes, + readerClassName, + STANDARD_INPUT_TYPE, // Accept ImageInputStreams + writerSpiNames, + supportsStandardStreamMetadataFormat, + nativeStreamMetadataFormatName, + nativeStreamMetadataFormatClassName, + extraStreamMetadataFormatNames, + extraStreamMetadataFormatClassNames, + supportsStandardImageMetadataFormat, + nativeImageMetadataFormatName, + nativeImageMetadataFormatClassName, + extraImageMetadataFormatNames, + extraImageMetadataFormatClassNames); + System.out.println ("JPEGImageReaderSPI!!!"); + } + + public String getDescription(Locale locale) + { + return "JPEG ISO 10918-1, JFIF V1.02"; + } + + public boolean canDecodeInput(Object input) + throws IOException + { + if (!(input instanceof ImageInputStream)) + return false; + + ImageInputStream in = (ImageInputStream) input; + boolean retval; + + in.mark(); + try + { + new JPEGDecoder(in); + retval = true; + } + catch(JPEGException e) + { + retval = false; + } + in.reset(); + + return retval; + } + + public ImageReader createReaderInstance(Object extension) + { + return new JPEGImageReader(this); + } + + public static void registerSpis(IIORegistry reg) + { + reg.registerServiceProvider(getReaderSpi(), ImageReaderSpi.class); + } + + public static synchronized JPEGImageReaderSpi getReaderSpi() + { + if (readerSpi == null) + readerSpi = new JPEGImageReaderSpi(); + return readerSpi; + } +} diff --git a/gnu/javax/imageio/jpeg/JPEGMarker.java b/gnu/javax/imageio/jpeg/JPEGMarker.java new file mode 100644 index 000000000..c80a0ca78 --- /dev/null +++ b/gnu/javax/imageio/jpeg/JPEGMarker.java @@ -0,0 +1,205 @@ +/* JPEGMarker.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +public class JPEGMarker +{ + /** + * JFIF identifiers. + */ + public final static byte JFIF_J = (byte) 0x4a; + public final static byte JFIF_F = (byte) 0x46; + public final static byte JFIF_I = (byte) 0x49; + public final static byte JFIF_X = (byte) 0x46; + + /** + * JFIF extension codes. + */ + public final static byte JFXX_JPEG = (byte) 0x10; + public final static byte JFXX_ONE_BPP = (byte) 0x11; + public final static byte JFXX_THREE_BPP = (byte) 0x13; + + /** + * Marker prefix byte. + */ + public final static byte XFF = (byte) 0xff; + + /** + * Marker byte that represents a literal 0xff. + */ + public final static byte X00 = (byte) 0x00; + + /** + * Application Reserved Keyword. + */ + public final static byte APP0 = (byte) 0xe0; + + public final static byte APP1 = (byte) 0xe1; + public final static byte APP2 = (byte) 0xe2; + public final static byte APP3 = (byte) 0xe3; + public final static byte APP4 = (byte) 0xe4; + public final static byte APP5 = (byte) 0xe5; + public final static byte APP6 = (byte) 0xe6; + public final static byte APP7 = (byte) 0xe7; + public final static byte APP8 = (byte) 0xe8; + public final static byte APP9 = (byte) 0xe9; + public final static byte APP10 = (byte) 0xea; + public final static byte APP11 = (byte) 0xeb; + public final static byte APP12 = (byte) 0xec; + public final static byte APP13 = (byte) 0xed; + public final static byte APP14 = (byte) 0xee; + public final static byte APP15 = (byte) 0xef; + + /** + * Modulo Restart Interval. + */ + public final static byte RST0 = (byte) 0xd0; + + public final static byte RST1 = (byte) 0xd1; + public final static byte RST2 = (byte) 0xd2; + public final static byte RST3 = (byte) 0xd3; + public final static byte RST4 = (byte) 0xd4; + public final static byte RST5 = (byte) 0xd5; + public final static byte RST6 = (byte) 0xd6; + public final static byte RST7 = (byte) 0xd7; + + /** + * Nondifferential Huffman-coding frame (baseline dct). + */ + public final static byte SOF0 = (byte) 0xc0; + + /** + * Nondifferential Huffman-coding frame (extended dct). + */ + public final static byte SOF1 = (byte) 0xc1; + + /** + * Nondifferential Huffman-coding frame (progressive dct). + */ + public final static byte SOF2 = (byte) 0xc2; + + /** + * Nondifferential Huffman-coding frame Lossless (Sequential). + */ + public final static byte SOF3 = (byte) 0xc3; + + /** + * Differential Huffman-coding frame Sequential DCT. + */ + public final static byte SOF5 = (byte) 0xc5; + + /** + * Differential Huffman-coding frame Progressive DCT. + */ + public final static byte SOF6 = (byte) 0xc6; + + /** + * Differential Huffman-coding frame lossless. + */ + public final static byte SOF7 = (byte) 0xc7; + + /** + * Nondifferential Arithmetic-coding frame (extended dct). + */ + public final static byte SOF9 = (byte) 0xc9; + + /** + * Nondifferential Arithmetic-coding frame (progressive dct). + */ + public final static byte SOF10 = (byte) 0xca; + + /** + * Nondifferential Arithmetic-coding frame (lossless). + */ + public final static byte SOF11 = (byte) 0xcb; + + /** + * Differential Arithmetic-coding frame (sequential dct). + */ + public final static byte SOF13 = (byte) 0xcd; + + /** + * Differential Arithmetic-coding frame (progressive dct). + */ + public final static byte SOF14 = (byte) 0xce; + + /** + * Differential Arithmetic-coding frame (lossless). + */ + public final static byte SOF15 = (byte) 0xcf; + + /** + * Huffman Table. + */ + public final static byte DHT = (byte) 0xc4; + + /** + * Quantization Table. + */ + public final static byte DQT = (byte) 0xdb; + + /** + * Start of Scan. + */ + public final static byte SOS = (byte) 0xda; + + /** + * Defined Restart Interval. + */ + public final static byte DRI = (byte) 0xdd; + + /** + * Comment in JPEG. + */ + public final static byte COM = (byte) 0xfe; + + /** + * Start of Image. + */ + public final static byte SOI = (byte) 0xd8; + + /** + * End of Image. + */ + public final static byte EOI = (byte) 0xd9; + + /** + * Define Number of Lines. + */ + public final static byte DNL = (byte) 0xdc; +} diff --git a/gnu/javax/imageio/jpeg/JPEGMarkerFoundException.java b/gnu/javax/imageio/jpeg/JPEGMarkerFoundException.java new file mode 100644 index 000000000..2e72d495b --- /dev/null +++ b/gnu/javax/imageio/jpeg/JPEGMarkerFoundException.java @@ -0,0 +1,50 @@ +/* JPEGMarkerFoundException.java -- FIXME: briefly describe file purpose + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.imageio.jpeg; + +import java.io.IOException; + +public class JPEGMarkerFoundException + extends IOException +{ + public JPEGMarkerFoundException() + { + super(""); + } +} diff --git a/gnu/javax/imageio/jpeg/JPEGScan.java b/gnu/javax/imageio/jpeg/JPEGScan.java new file mode 100644 index 000000000..e07251021 --- /dev/null +++ b/gnu/javax/imageio/jpeg/JPEGScan.java @@ -0,0 +1,151 @@ +/* JPEGScan.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.util.ArrayList; + +public class JPEGScan +{ + private int maxHeight = 0, maxWidth = 0, maxV = 0, maxH = 0; + private int numOfComponents = 0, numOfComponentBlocks = 0; + private ArrayList components = new ArrayList(); + + public JPEGScan() + { + // Nothing to do here. + } + + public JPEGScan(int h, int w) + { + maxHeight=h; + maxWidth=w; + } + + private void recalculateDimensions() + { + JPEGComponent comp; + + // Compute the maximum H, maximum V factors defined in Annex A of the ISO + // DIS 10918-1. + for(int i=0; i < components.size() ; i++) + { + comp = (JPEGComponent)components.get(i); + if(comp.factorH > maxH) + maxH=comp.factorH; + if(comp.factorV > maxV) + maxV=comp.factorV; + } + + for(int i=0; i < components.size() ; i++) + { + comp = (JPEGComponent)components.get(i); + comp.maxH = maxH; + comp.maxV = maxV; + } + + } + + public void addComponent(byte id, byte factorHorizontal, byte factorVertical, + byte quantizationID) + { + JPEGComponent component = new JPEGComponent(id, factorHorizontal, factorVertical, quantizationID); + components.add((Object)component); + recalculateDimensions(); + numOfComponents++; + numOfComponentBlocks += factorHorizontal*factorVertical; + } + + public JPEGComponent getComponentByID(byte id) + { + JPEGComponent comp = (JPEGComponent)components.get(0); + for(int i=0; i < components.size() ; i++) + { + comp=(JPEGComponent)components.get(i); + if(comp.component_id==id) + break; + } + return(comp); + } + + public JPEGComponent get(int id) + { + return((JPEGComponent)components.get(id)); + } + + public int getX(byte id) + { + JPEGComponent comp = getComponentByID(id); + return(comp.width); + } + + public int getY(byte id) + { + JPEGComponent comp = getComponentByID(id); + return(comp.height); + } + + public int getMaxV() + { + return(maxV); + } + + public int getMaxH() + { + return(maxH); + } + + public void setWidth(int w) + { + maxWidth=w; + } + + public void setHeight(int h) + { + maxHeight=h; + } + + public int size() + { + return(numOfComponents); + } + + public int sizeComponentBlocks() + { + return(numOfComponentBlocks); + } +} diff --git a/gnu/javax/imageio/jpeg/YCbCr_ColorSpace.java b/gnu/javax/imageio/jpeg/YCbCr_ColorSpace.java new file mode 100644 index 000000000..a3970b7fa --- /dev/null +++ b/gnu/javax/imageio/jpeg/YCbCr_ColorSpace.java @@ -0,0 +1,113 @@ +/* YCbCr_ColorSpace.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.awt.color.ColorSpace; + +public class YCbCr_ColorSpace extends ColorSpace { + public YCbCr_ColorSpace() { + super(ColorSpace.TYPE_YCbCr, 3); + } + + public float[] fromCIEXYZ(float[] data) { + return(new float[data.length]); + } + + public float[] toCIEXYZ(float[] data) { + return(new float[data.length]); + } + + public float[] fromRGB(float[] data) { + return(new float[data.length]); + } + + /* YCbCr to RGB range 0 to 1 */ + public float[] toRGB(float[] data) { + float[] dest = new float[3]; + + data[0] *= 255; + data[1] *= 255; + data[2] *= 255; + + dest[0] = (float)data[0] + (float)1.402*((float)data[2]-(float)128); + dest[1] = (float)data[0] - (float)0.34414*((float)data[1]-(float)128) - (float)0.71414*((float)data[2]-(float)128); + dest[2] = (float)data[0] + (float)1.772*((float)data[1]-(float)128); + + dest[0] /= 255; + dest[1] /= 255; + dest[2] /= 255; + + //dest[0] = ((float)1.164*((float)data[0]*(float)255 - (float)16) + (float)1.596*((float)data[2]*(float)255 - (float)128))/(float)255; + //dest[1] = ((float)1.164*((float)data[0]*(float)255 - (float)16) - (float)0.813*((float)data[2]*(float)255 - (float)128) - (float)0.392*(data[1]*255 - 128))/(float)255; + //dest[2] = ((float)1.164*((float)data[0]*(float)255 - (float)16) + (float)2.017*((float)data[1]*(float)255 - (float)128))/(float)255; + + //System.err.println("toRGB values received: 0: "+data[0]+" 1: "+data[1]+" 2: "+data[2]+" sent: 0: "+dest[0]+" 1: "+dest[1]+" 2: "+dest[2]); + if(dest[0] < (float)0) + dest[0] = 0; + if(dest[1] < (float)0) + dest[1] = 0; + if(dest[2] < (float)0) + dest[2] = 0; + + if(dest[0] > (float)1) + dest[0] = 1; + if(dest[1] > (float)1) + dest[1] = 1; + if(dest[2] > (float)1) + dest[2] = 1; + + + return(dest); + } + + /* RGB to YCbCr range 0-255 */ + public static float[] toYCbCr(float[] data) { + float[] dest = new float[3]; + //dest[0] = (float)0.257*data[0] + (float)0.504*data[1] + (float)0.098*data[2] + 16; + //dest[1] = (float)-0.148*data[0] - (float)0.291*data[1] + (float)0.439*data[2] + 128; + //dest[2] = (float)0.439*data[0] - (float)0.368*data[1] - (float)0.071*data[2] + 128; + + dest[0] = (float)((0.299 * (float)data[0] + 0.587 * (float)data[1] + 0.114 * (float)data[2])); + dest[1] = 128 + (float)((-0.16874 * (float)data[0] - 0.33126 * (float)data[1] + 0.5 * (float)data[2])); + dest[2] = 128 + (float)((0.5 * (float)data[0] - 0.41869 * (float)data[1] - 0.08131 * (float)data[2])); + + + return(dest); + + } +} diff --git a/gnu/javax/imageio/jpeg/ZigZag.java b/gnu/javax/imageio/jpeg/ZigZag.java new file mode 100644 index 000000000..0c19d74ff --- /dev/null +++ b/gnu/javax/imageio/jpeg/ZigZag.java @@ -0,0 +1,520 @@ +/* ZigZag.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +/** + * This class implements the Zig Zag Algorithm on any array with + * the same amount of rows and columns. It takes a matrix and in turn builds an + * encoded byte array (or double array) from it. The adverse is also true, this + * will take a byte or double array and build a matrix based on the zig zag + * algorithm. + * <p>This is used exclusively in the JPEG DCT encoding.</p> + */ +public class ZigZag +{ + public final static boolean ZIGZAG_FORWARD = true; + public final static boolean ZIGZAG_BACKWARD = false; + public final static int ZIGZAG_8X8_MAP[] = + { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 + }; + + /** + * Encodes a matrix of equal width and height to a byte array. + * + * @param matrix + * + * @return + */ + public static byte[] encode(byte[][] matrix) + { + byte[] buffer = new byte[matrix.length ^ 2]; + boolean direction = ZigZag.ZIGZAG_FORWARD; + int x = 0, y = 0, index = 0; + for (int zigIndex = 0; zigIndex < (matrix.length * 2 - 1); + zigIndex++, direction = !direction) + { + if (direction == ZigZag.ZIGZAG_FORWARD) + { + while (x >= 0 && y != matrix.length) + { + if (x == matrix.length) + { + x--; + y++; + } + buffer[index] = matrix[x][y]; + y++; + x--; + index++; + } + x++; + } + else + { + while (y >= 0 && x != matrix.length) + { + if (y == matrix.length) + { + y--; + x++; + } + buffer[index] = matrix[x][y]; + y--; + x++; + index++; + } + y++; + } + } + return (buffer); + } + + /** + * Encodes a matrix of equal width and height to a double array + * + * @param matrix + * + * @return + */ + public static double[] encode(double[][] matrix) + { + double[] buffer = new double[matrix.length * matrix.length]; + boolean direction = ZigZag.ZIGZAG_FORWARD; + int x = 0, y = 0, index = 0; + for (int zigIndex = 0; zigIndex < (matrix.length * 2 - 1); + zigIndex++, direction = !direction) + { + if (direction == ZigZag.ZIGZAG_FORWARD) + { + while (x >= 0 && y != matrix.length) + { + if (x == matrix.length) + { + x--; + y++; + } + buffer[index] = matrix[x][y]; + y++; + x--; + index++; + } + x++; + } + else + { + while (y >= 0 && x != matrix.length) + { + if (y == matrix.length) + { + y--; + x++; + } + buffer[index] = matrix[x][y]; + y--; + x++; + index++; + } + y++; + } + } + return (buffer); + } + + /** + * Encodes a matrix of equal width and height to a float array + * + * @param matrix + * + * @return + */ + public static float[] encode(float[][] matrix) + { + float[] buffer = new float[matrix.length * matrix.length]; + boolean direction = ZigZag.ZIGZAG_FORWARD; + int x = 0, y = 0, index = 0; + for (int zigIndex = 0; zigIndex < (matrix.length * 2 - 1); + zigIndex++, direction = !direction) + { + if (direction == ZigZag.ZIGZAG_FORWARD) + { + while (x >= 0 && y != matrix.length) + { + if (x == matrix.length) + { + x--; + y++; + } + buffer[index] = matrix[x][y]; + y++; + x--; + index++; + } + x++; + } + else + { + while (y >= 0 && x != matrix.length) + { + if (y == matrix.length) + { + y--; + x++; + } + buffer[index] = matrix[x][y]; + y--; + x++; + index++; + } + y++; + } + } + return (buffer); + } + + /** + * Encodes a matrix of equal width and height to a float array + * + * @param matrix + * + * @return + */ + public static short[] encode(short[][] matrix) + { + short[] buffer = new short[matrix.length * matrix.length]; + boolean direction = ZigZag.ZIGZAG_FORWARD; + int x = 0, y = 0, index = 0; + for (int zigIndex = 0; zigIndex < (matrix.length * 2 - 1); + zigIndex++, direction = !direction) + { + if (direction == ZigZag.ZIGZAG_FORWARD) + { + while (x >= 0 && y != matrix.length) + { + if (x == matrix.length) + { + x--; + y++; + } + buffer[index] = matrix[x][y]; + y++; + x--; + index++; + } + x++; + } + else + { + while (y >= 0 && x != matrix.length) + { + if (y == matrix.length) + { + y--; + x++; + } + buffer[index] = matrix[x][y]; + y--; + x++; + index++; + } + y++; + } + } + return (buffer); + } + + /** + * Convert a double array into a matrix with the same amount of columns and + * rows with length sqrt(double array length) + * + * @param data + * + * @return + */ + public static double[][] decode(double[] data) + { + return decode(data, (int) Math.sqrt(data.length), + (int) Math.sqrt(data.length)); + } + + /** + * Convert a byte array into a matrix with the same amount of columns and + * rows with length sqrt(double array length) + * + * @param data + * + * @return + */ + public static byte[][] decode(byte[] data) + { + return decode(data, (int) Math.sqrt(data.length), + (int) Math.sqrt(data.length)); + } + + public static int[][] decode(int[] data) + { + return decode(data, (int) Math.sqrt(data.length), + (int) Math.sqrt(data.length)); + } + + public static byte[][] decode(byte[] data, int width, int height) + { + byte[][] buffer = new byte[height][width]; + + for (int v = 0; v < height; v++) + for (int z = 0; z < width; z++) + buffer[v][z] = 11; + + boolean dir = ZigZag.ZIGZAG_FORWARD; + int xindex = 0, yindex = 0, dataindex = 0; + + while (xindex < width && yindex < height && dataindex < data.length) + { + buffer[yindex][xindex] = data[dataindex]; + dataindex++; + + if (dir == ZigZag.ZIGZAG_FORWARD) + { + if (yindex == 0 || xindex == (width - 1)) + { + dir = ZigZag.ZIGZAG_BACKWARD; + if (xindex == (width - 1)) + yindex++; + else + xindex++; + } + else + { + yindex--; + xindex++; + } + } + else + { /* Backwards */ + if (xindex == 0 || yindex == (height - 1)) + { + dir = ZigZag.ZIGZAG_FORWARD; + if (yindex == (height - 1)) + xindex++; + else + yindex++; + } + else + { + yindex++; + xindex--; + } + } + } + return (buffer); + } + + public static double[][] decode(double[] data, int width, int height) + { + double[][] buffer = new double[height][width]; + + for (int v = 0; v < height; v++) + for (int z = 0; z < width; z++) + buffer[v][z] = 11; + + boolean dir = ZigZag.ZIGZAG_FORWARD; + int xindex = 0, yindex = 0, dataindex = 0; + + while (xindex < width && yindex < height && dataindex < data.length) + { + buffer[yindex][xindex] = data[dataindex]; + dataindex++; + System.err.println("Setting " + dataindex + " to row: " + yindex + + " column: " + xindex + " yourval:" + + (yindex*8+xindex)); + if (dir == ZigZag.ZIGZAG_FORWARD) + { + if (yindex == 0 || xindex == (width - 1)) + { + dir = ZigZag.ZIGZAG_BACKWARD; + if (xindex == (width - 1)) + yindex++; + else + xindex++; + } + else + { + yindex--; + xindex++; + } + } + else + { /* Backwards */ + if (xindex == 0 || yindex == (height - 1)) + { + dir = ZigZag.ZIGZAG_FORWARD; + if (yindex == (height - 1)) + xindex++; + else + yindex++; + } + else + { + yindex++; + xindex--; + } + } + } + return (buffer); + } + + public static float[][] decode(float[] data, int width, int height) + { + float[][] buffer = new float[height][width]; + + for (int v = 0; v < height; v++) + for (int z = 0; z < width; z++) + buffer[v][z] = 11; + + boolean dir = ZigZag.ZIGZAG_FORWARD; + int xindex = 0, yindex = 0, dataindex = 0; + + while (xindex < width && yindex < height && dataindex < data.length) + { + buffer[yindex][xindex] = data[dataindex]; + dataindex++; + + if (dir == ZigZag.ZIGZAG_FORWARD) + { + if (yindex == 0 || xindex == (width - 1)) + { + dir = ZigZag.ZIGZAG_BACKWARD; + if (xindex == (width - 1)) + yindex++; + else + xindex++; + } + else + { + yindex--; + xindex++; + } + } + else + { /* Backwards */ + if (xindex == 0 || yindex == (height - 1)) + { + dir = ZigZag.ZIGZAG_FORWARD; + if (yindex == (height - 1)) + xindex++; + else + yindex++; + } + else + { + yindex++; + xindex--; + } + } + } + return (buffer); + } + + public static int[][] decode(int[] data, int width, int height) + { + int[][] buffer = new int[height][width]; + + for (int v = 0; v < height; v++) + for (int z = 0; z < width; z++) + buffer[v][z] = 11; + + boolean dir = ZigZag.ZIGZAG_FORWARD; + int xindex = 0, yindex = 0, dataindex = 0; + + while (xindex < width && yindex < height && dataindex < data.length) + { + buffer[yindex][xindex] = data[dataindex]; + dataindex++; + + if (dir == ZigZag.ZIGZAG_FORWARD) + { + if (yindex == 0 || xindex == (width - 1)) + { + dir = ZigZag.ZIGZAG_BACKWARD; + if (xindex == (width - 1)) + yindex++; + else + xindex++; + } + else + { + yindex--; + xindex++; + } + } + else + { /* Backwards */ + if (xindex == 0 || yindex == (height - 1)) + { + dir = ZigZag.ZIGZAG_FORWARD; + if (yindex == (height - 1)) + xindex++; + else + yindex++; + } + else + { + yindex++; + xindex--; + } + } + } + return (buffer); + } + + public static double[][] decode8x8_map(double input[]) + { + double[][] output = new double[8][8]; + for(int i=0; i < 64 ; i++) + output[ZIGZAG_8X8_MAP[i]/8][ZIGZAG_8X8_MAP[i]%8] = input[i]; + return (output); + } + +} diff --git a/gnu/javax/print/CupsServer.java b/gnu/javax/print/CupsServer.java index 6d9601fb9..0486e69de 100644 --- a/gnu/javax/print/CupsServer.java +++ b/gnu/javax/print/CupsServer.java @@ -84,24 +84,43 @@ public class CupsServer /** * Creates a <code>CupsServer</code> object which - * tries to connect to the cups server on localhost. + * tries to connect to a cups server. + * + * If <code>gnu.javax.print.server</code> is explicitly set, then + * that hostname will be used. Otherwise it will default to localhost. * * @param username the username * @param password the password for the username. */ public CupsServer(String username, String password) { + this.username = username; + this.password = password; + + this.uri = null; + try + { + String serv = System.getProperty("gnu.javax.print.server"); + if( serv != null ) + this.uri = new URI("http://"+serv+":631"); + } + catch(URISyntaxException use) + { + throw new RuntimeException("gnu.javax.print.CupsServer value is not a valid hostname."); + } + catch(SecurityException se) + { + } + try { - this.uri = new URI("http://localhost:631"); + if( this.uri == null ) + this.uri = new URI("http://localhost:631"); } catch (URISyntaxException e) { // does not happen } - - this.username = username; - this.password = password; } /** @@ -193,7 +212,7 @@ public class CupsServer Map printerAttributes = (Map) prAttr.get(i); Set uris = (Set) printerAttributes.get(PrinterUriSupported.class); PrinterUriSupported uri = (PrinterUriSupported) uris.toArray()[0]; - + try { CupsPrintService cups = new CupsPrintService(uri.getURI(), diff --git a/gnu/javax/print/ipp/IppRequest.java b/gnu/javax/print/ipp/IppRequest.java index 8abab5192..ccfa9b272 100644 --- a/gnu/javax/print/ipp/IppRequest.java +++ b/gnu/javax/print/ipp/IppRequest.java @@ -119,6 +119,11 @@ public class IppRequest { /** + * The printer-poll timeout. + */ + private static final int timeout = 1000; + + /** * Helper class used to write the attributes of a request * into the supplied data output stream in the correct way. * @@ -838,7 +843,12 @@ public class IppRequest out.flush(); stream.flush(); - + + // Set the connection timeout, for if the printer is offline. + // FIXME: The print services polling should probably be done in its + // own thread. + connection.setConnectTimeout( timeout ); + int responseCode = responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) diff --git a/gnu/javax/swing/text/html/CharacterAttributeTranslator.java b/gnu/javax/swing/text/html/CharacterAttributeTranslator.java new file mode 100644 index 000000000..9718189da --- /dev/null +++ b/gnu/javax/swing/text/html/CharacterAttributeTranslator.java @@ -0,0 +1,156 @@ +/* CharacterAttributeTranslator.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.swing.text.html; + +import java.awt.Color; +import java.util.HashMap; +import javax.swing.text.AbstractDocument; +import javax.swing.text.AttributeSet; +import javax.swing.text.BadLocationException; +import javax.swing.text.DefaultStyledDocument; +import javax.swing.text.Element; +import javax.swing.text.ElementIterator; +import javax.swing.text.GapContent; +import javax.swing.text.MutableAttributeSet; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.StyleConstants; +import javax.swing.text.html.HTML.Tag; + +/** + * This is a small utility class to translate HTML character attributes to + * Swing StyleConstants + */ +public class CharacterAttributeTranslator +{ + private static final HashMap colorMap = new HashMap(); + static + { + colorMap.put("aqua" , "#00FFFF"); + colorMap.put("blue" , "#0000FF"); + colorMap.put("black", "#000000"); + colorMap.put("fuchsia" , "#FF00FF"); + colorMap.put("gray" , "#808080"); + colorMap.put("green" , "#008000"); + colorMap.put("lime" , "#00FF00"); + colorMap.put("maroon" , "#800000"); + colorMap.put("navy" , "#000080"); + colorMap.put("olive" , "#808000"); + colorMap.put("purple" , "#800080"); + colorMap.put("red" , "#FF0000"); + colorMap.put("silver" , "#C0C0C0"); + colorMap.put("teal" , "#008080"); + colorMap.put("white" , "#FFFFFF"); + colorMap.put("yellow" , "#FFFF00"); + }; + + private static Color getColor(String s) + { + String s2 = (String)colorMap.get(s.toLowerCase()); + if( s2 == null ) + s2 = s; + try + { + return Color.decode(s2); + } + catch(NumberFormatException nfe) + { + return null; + } + } + + public static boolean translateTag(MutableAttributeSet charAttr, + Tag t, MutableAttributeSet a) + { + if(t == Tag.FONT) + { + if(a.getAttribute("color") != null) + { + Color c = getColor(""+a.getAttribute("color")); + if( c == null ) + return false; + charAttr.addAttribute(StyleConstants.Foreground, c); + return true; + } + + if(a.getAttribute("size") != null) + { + // FIXME + // charAttr.addAttribute(StyleConstants.FontSize, + // new java.lang.Integer(72)); + return true; + } + } + + if( t == Tag.B ) + { + charAttr.addAttribute(StyleConstants.Bold, new Boolean(true)); + return true; + } + + if( t == Tag.I ) + { + charAttr.addAttribute(StyleConstants.Italic, new Boolean(true)); + return true; + } + + if( t == Tag.U ) + { + charAttr.addAttribute(StyleConstants.Underline, new Boolean(true)); + return true; + } + + if( t == Tag.STRIKE ) + { + charAttr.addAttribute(StyleConstants.StrikeThrough, new Boolean(true)); + return true; + } + + if( t == Tag.SUP ) + { + charAttr.addAttribute(StyleConstants.Superscript, new Boolean(true)); + return true; + } + + if( t == Tag.SUB ) + { + charAttr.addAttribute(StyleConstants.Subscript, new Boolean(true)); + return true; + } + return false; + } +} diff --git a/include/gnu_java_nio_VMChannel.h b/include/gnu_java_nio_VMChannel.h new file mode 100644 index 000000000..28f9048d2 --- /dev/null +++ b/include/gnu_java_nio_VMChannel.h @@ -0,0 +1,24 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ + +#ifndef __gnu_java_nio_VMChannel__ +#define __gnu_java_nio_VMChannel__ + +#include <jni.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +JNIEXPORT void JNICALL Java_gnu_java_nio_VMChannel_setBlocking (JNIEnv *env, jobject, jint, jboolean); +JNIEXPORT jint JNICALL Java_gnu_java_nio_VMChannel_read (JNIEnv *env, jobject, jint, jobject); +JNIEXPORT jlong JNICALL Java_gnu_java_nio_VMChannel_readScattering (JNIEnv *env, jobject, jint, jobjectArray, jint, jint); +JNIEXPORT jint JNICALL Java_gnu_java_nio_VMChannel_write (JNIEnv *env, jobject, jint, jobject); +JNIEXPORT jlong JNICALL Java_gnu_java_nio_VMChannel_writeGathering (JNIEnv *env, jobject, jint, jobjectArray, jint, jint); +JNIEXPORT void JNICALL Java_gnu_java_nio_VMChannel_initIDs (JNIEnv *env, jclass); + +#ifdef __cplusplus +} +#endif + +#endif /* __gnu_java_nio_VMChannel__ */ diff --git a/java/awt/BasicStroke.java b/java/awt/BasicStroke.java index bf111d080..3e259216f 100644 --- a/java/awt/BasicStroke.java +++ b/java/awt/BasicStroke.java @@ -363,7 +363,7 @@ public class BasicStroke implements Stroke * Compares this <code>BasicStroke</code> for equality with an arbitrary * object. This method returns <code>true</code> if and only if: * <ul> - * <li><code>o</code> is an instanceof <code>BasicStroke</code>;<li> + * <li><code>o</code> is an instanceof <code>BasicStroke</code>;</li> * <li>this object has the same width, line cap style, line join style, * miter limit, dash array and dash phase as <code>o</code>.</li> * </ul> diff --git a/java/awt/ColorPaintContext.java b/java/awt/ColorPaintContext.java index 82a78f63f..2996f899f 100644 --- a/java/awt/ColorPaintContext.java +++ b/java/awt/ColorPaintContext.java @@ -117,7 +117,7 @@ class ColorPaintContext implements PaintContext { cachedRaster = new ColorRaster(colorModel, 0, 0, width, height, color); } - return cachedRaster.createChild(0 ,0 ,width ,height ,x ,y , null); + return cachedRaster.createChild(0 ,0 ,width ,height ,0 ,0 , null); } /** @@ -138,13 +138,13 @@ class ColorPaintContext implements PaintContext * @param rgbPixel The RGB value of the color for this raster. */ ColorRaster(ColorModel cm,int x, int y, int width, int height, int rgbPixel) - { + { super(cm.createCompatibleSampleModel(width,height),new Point(x,y)); Object pixel = cm.getDataElements(rgbPixel,null); - getSampleModel().setDataElements(0, 0, - width, height, - multiplyData(pixel,null,width*height), - dataBuffer); + int[] pixelComps = cm.getComponents(pixel, null, 0); + int[] d = (int[]) multiplyData(pixelComps,null,width*height); + getSampleModel().setPixels(0, 0, width, height, d, + dataBuffer); } diff --git a/java/awt/Component.java b/java/awt/Component.java index 2decae576..dcebc7403 100644 --- a/java/awt/Component.java +++ b/java/awt/Component.java @@ -5053,7 +5053,12 @@ p * <li>the set of backward traversal keys .dispatchEvent(e)) return; case MouseEvent.MOUSE_PRESSED: - if (isLightweight() && !e.isConsumed()) + // A mouse click on an enabled lightweight component + // which has not yet been marked as consumed by any + // other mouse listener results in a focus traversal + // to that component. + if (isLightweight() + && isEnabled() && !e.isConsumed()) requestFocus(); break; } diff --git a/java/awt/ContainerOrderFocusTraversalPolicy.java b/java/awt/ContainerOrderFocusTraversalPolicy.java index 152482c88..23b4ac2e8 100644 --- a/java/awt/ContainerOrderFocusTraversalPolicy.java +++ b/java/awt/ContainerOrderFocusTraversalPolicy.java @@ -111,14 +111,16 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy ancestor = current.getFocusCycleRootAncestor (); if (ancestor == prevAncestor) { - // We've reached the top focus cycle root ancestor. Check - // if it is root. - if (ancestor != root) + // We've reached the top focus cycle root ancestor. Check + // if it is root. + if (ancestor == null) + ancestor = root; + else if (ancestor != root) throw new IllegalArgumentException ("the given container is not" + " a focus cycle root of the" + " current component"); - else - break; + else + break; } prevAncestor = ancestor; } @@ -136,7 +138,6 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy return getFirstComponent ((Container) current); Container parent = current.getParent (); - synchronized (parent.getTreeLock ()) { Component[] components = parent.getComponents (); @@ -146,47 +147,104 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy // Find component's index. for (int i = 0; i < numComponents; i++) { - if (components[i] == current) + if (components[i].equals(current)) componentIndex = i; } - // Search forward for the next acceptable component. - for (int i = componentIndex + 1; i < numComponents; i++) - { - if (accept (components[i])) - return components[i]; + // Search forward for the next acceptable component. + // Search through all components at least one time + // i.e. start at componentIndex + 1 --> nComponents -1 --> 0 ---> componentIndex + int i = componentIndex + 1; + int end = numComponents - 1; + Component next = getNextAvailableComponent(components, i, end); + if (next != null) + return next; + + // Now check remainder of components from 0 to componentIndex + i = 0; + end = componentIndex; + next = getNextAvailableComponent(components, i, end); + if (next != null) + return next; + + // No focusable components after current in its Container. So go + // to the next Component after current's Container (parent). + Component result = getComponentAfter (root, parent); + return result; + } + } + + /** + * Gets the next available component in the array between the given range. + * + * @param components - the array of components. + * @param start - where to start + * @param end - where to end + * @return next component if found + */ + private Component getNextAvailableComponent(Component[] components, int start, int end) + { + while (start <= end) + { + Component c = components[start]; + + if (c.visible && c.isDisplayable() && c.enabled && c.focusable) + return c; - if (components[i] instanceof Container) - { - Component result = getFirstComponent ((Container) components[i]); + if (c instanceof Container) + { + Component result = getFirstComponent((Container) c); - if (result != null - && implicitDownCycleTraversal) - return result; - } + if (result != null && implicitDownCycleTraversal && result.visible + && result.isDisplayable() && result.enabled && result.focusable) + return result; } + start++; + } - // No focusable components after current in its Container. So go - // to the next Component after current's Container (parent). - Component result = getComponentAfter (root, parent); + return null; + } - return result; + /** + * Gets the previous available component in the array between the given range. + * + * @param components - the array of components. + * @param start - where to start + * @param end - where to end + * @return previous component if found + */ + Component getPrevAvailableComponent(Component[] components, int start, int end) + { + while (start >= end) + { + Component c = components[start]; + if (c.visible && c.isDisplayable() && c.enabled && c.focusable) + return c; + + if (c instanceof Container) + { + Component result = getLastComponent((Container) c); + + if (result != null + && (result.visible && result.isDisplayable() && result.enabled && result.focusable)) + return result; + } + start--; } + return null; } /** * Returns the Component that should receive the focus before - * <code>current</code>. <code>root</code> must be a focus cycle - * root of current. - * + * <code>current</code>. <code>root</code> must be a focus cycle root of + * current. + * * @param root a focus cycle root of current * @param current a (possibly indirect) child of root, or root itself - * - * @return the previous Component in the focus traversal order for - * root, or null if no acceptable Component exists. - * - * @exception IllegalArgumentException If root is not a focus cycle - * root of current, or if either root or current is null. + * @return the previous Component in the focus traversal order for root, or + * null if no acceptable Component exists. + * @exception IllegalArgumentException If root is not a focus cycle root of + * current, or if either root or current is null. */ public Component getComponentBefore (Container root, Component current) { @@ -207,7 +265,9 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy { // We've reached the top focus cycle root ancestor. Check // if it is root. - if (ancestor != root) + if (ancestor == null) + ancestor = root; + else if (ancestor != root) throw new IllegalArgumentException ("the given container is not" + " a focus cycle root of the" + " current component"); @@ -244,20 +304,20 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy componentIndex = i; } - // Search backward for the next acceptable component. - for (int i = componentIndex - 1; i >= 0; i--) - { - if (accept (components[i])) - return components[i]; - - if (components[i] instanceof Container) - { - Component result = getLastComponent ((Container) components[i]); - - if (result != null) - return result; - } - } + // Search through all components at least one time + // i.e. start at componentIndex - 1 --> 0 --> numComponents -1 ---> componentIndex + int i = componentIndex - 1; + int end = 0; + Component prev = getPrevAvailableComponent(components, i, end); + if (prev != null) + return prev; + + // Now check remainder of components + i = numComponents -1; + end = componentIndex; + prev = getPrevAvailableComponent(components, i, end); + if (prev != null) + return prev; // No focusable components before current in its Container. So go // to the previous Component before current's Container (parent). @@ -286,7 +346,8 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy || !root.isDisplayable ()) return null; - if (accept (root)) + if (root.visible && root.isDisplayable() && root.enabled + && root.focusable) return root; Component[] componentArray = root.getComponents (); @@ -295,14 +356,16 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy { Component component = componentArray [i]; - if (accept (component)) + if (component.visible && component.isDisplayable() && component.enabled + && component.focusable) return component; if (component instanceof Container) { Component result = getFirstComponent ((Container) component); - if (result != null) + if (result != null + && (result.visible && result.isDisplayable() && result.enabled && result.focusable)) return result; } } @@ -329,7 +392,8 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy || !root.isDisplayable ()) return null; - if (accept (root)) + if (root.visible && root.isDisplayable() && root.enabled + && root.focusable) return root; Component[] componentArray = root.getComponents (); @@ -338,14 +402,17 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy { Component component = componentArray [i]; - if (accept (component)) + if (component.visible && component.isDisplayable() && component.enabled + && component.focusable) return component; if (component instanceof Container) { Component result = getLastComponent ((Container) component); - if (result != null) + if (result != null && + result.visible && result.isDisplayable() && result.enabled + && result.focusable) return result; } } diff --git a/java/awt/EventDispatchThread.java b/java/awt/EventDispatchThread.java index a64cdae85..7cb8af831 100644 --- a/java/awt/EventDispatchThread.java +++ b/java/awt/EventDispatchThread.java @@ -43,6 +43,11 @@ package java.awt; */ class EventDispatchThread extends Thread { + /** + * The default priority when no property has been set. + */ + private static final int DEFAULT_PRIORITY = NORM_PRIORITY + 1; + private static int dispatchThreadNum; private EventQueue queue; @@ -52,7 +57,22 @@ class EventDispatchThread extends Thread super(); setName("AWT-EventQueue-" + ++dispatchThreadNum); this.queue = queue; - setPriority(NORM_PRIORITY + 1); + + int priority = DEFAULT_PRIORITY; + try + { + String priorityString = + System.getProperty("gnu.awt.dispatchthread.priority"); + if (priorityString != null) + { + priority = Integer.parseInt(priorityString); + } + } + catch (NumberFormatException ex) + { + // Ignore and use default. + } + setPriority(priority); } public void run() diff --git a/java/awt/Font.java b/java/awt/Font.java index ba96ad940..ceff55878 100644 --- a/java/awt/Font.java +++ b/java/awt/Font.java @@ -1014,7 +1014,7 @@ public class Font implements Serializable */ public int getNumGlyphs() { - return peer.getMissingGlyphCode(this); + return peer.getNumGlyphs(this); } /** diff --git a/java/awt/Graphics2D.java b/java/awt/Graphics2D.java index de71993ae..53d7ca5e6 100644 --- a/java/awt/Graphics2D.java +++ b/java/awt/Graphics2D.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2000, 2002, 2004 Free Software Foundation +/* Copyright (C) 2000, 2002, 2004, 2006, Free Software Foundation This file is part of GNU Classpath. @@ -45,10 +45,35 @@ import java.awt.image.BufferedImageOp; import java.awt.image.ImageObserver; import java.awt.image.RenderedImage; import java.awt.image.renderable.RenderableImage; +import java.awt.print.PageFormat; +import java.awt.print.Printable; import java.text.AttributedCharacterIterator; import java.util.Map; /** + * An abstract class defining a device independent two-dimensional vector + * graphics API. Concrete subclasses implement this API for output of + * vector graphics to: (*) + * <p> + * <ul> + * <li>a {@link javax.swing.JComponent} - in the + * {@link javax.swing.JComponent#paint(Graphics)} method, the incoming + * {@link Graphics} should always be an instance of + * <code>Graphics2D</code> (*);</li> + * <li>a {@link BufferedImage} - see + * {@link BufferedImage#createGraphics()} (*);</li> + * <li>a {@link PrinterJob} - in the + * {@link Printable#print(Graphics, PageFormat, int)} method, the incoming + * {@link Graphics} should always be an instance of <code>Graphics2D</code> + * (*).</li> + * </ul> + * <p> + * (*) Support for this API is not fully implemented in GNU Classpath yet. + * <p> + * Third party libraries provide support for output to other formats via this + * API, including encapsulated postscript (EPS), portable document format (PDF), + * and scalable vector graphics (SVG). + * * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) */ public abstract class Graphics2D extends Graphics @@ -70,6 +95,14 @@ public abstract class Graphics2D extends Graphics super.fill3DRect(x, y, width, height, raised); } + /** + * Draws an outline around a shape using the current stroke and paint. + * + * @param shape the shape (<code>null</code> not permitted). + * + * @see #getStroke() + * @see #getPaint() + */ public abstract void draw(Shape shape); public abstract boolean drawImage(Image image, AffineTransform xform, @@ -86,18 +119,57 @@ public abstract class Graphics2D extends Graphics public abstract void drawRenderableImage(RenderableImage image, AffineTransform xform); + /** + * Draws a string at the specified location, using the current font. + * + * @param text the string to draw. + * @param x the x-coordinate. + * @param y the y-coordinate. + * + * @see Graphics#setFont(Font) + */ public abstract void drawString(String text, int x, int y); + /** + * Draws a string at the specified location, using the current font. + * + * @param text the string to draw. + * @param x the x-coordinate. + * @param y the y-coordinate. + * + * @see Graphics#setFont(Font) + */ public abstract void drawString(String text, float x, float y); + /** + * Draws an attributed string at the specified location. + * + * @param iterator the source of the attributed text. + * @param x the x-coordinate. + * @param y the y-coordinate. + */ public abstract void drawString(AttributedCharacterIterator iterator, int x, int y); + /** + * Draws an attributed string at the specified location. + * + * @param iterator the source of the attributed text. + * @param x the x-coordinate. + * @param y the y-coordinate. + */ public abstract void drawString(AttributedCharacterIterator iterator, float x, float y); - // public abstract void drawGlyphVector(GlyphVector g, float x, float y); - + /** + * Fills the interior of the specified <code>shape</code> using the current + * paint. + * + * @param shape the shape to fill (<code>null</code> not permitted). + * + * @see #draw(Shape) + * @see #getPaint() + */ public abstract void fill(Shape shape); public abstract boolean hit(Rectangle rect, Shape text, @@ -105,21 +177,72 @@ public abstract class Graphics2D extends Graphics public abstract GraphicsConfiguration getDeviceConfiguration(); + /** + * Sets the current compositing rule. + * + * @param comp the composite. + * + * @see #getComposite() + */ public abstract void setComposite(Composite comp); + /** + * Sets the paint to be used for subsequent drawing operations. + * + * @param paint the paint (<code>null</code> not permitted). + * + * @see #getPaint() + */ public abstract void setPaint(Paint paint); + /** + * Sets the stroke to be used for subsequent drawing operations. + * + * @param stroke the stroke (<code>null</code> not permitted). + * + * @see #getStroke() + */ public abstract void setStroke(Stroke stroke); + /** + * Adds or updates a hint in the current rendering hints table. + * + * @param hintKey the hint key. + * @param hintValue the hint value. + */ public abstract void setRenderingHint(RenderingHints.Key hintKey, Object hintValue); + /** + * Returns the current value of a rendering hint. + * + * @param hintKey the key for the hint. + * + * @return The value for the specified hint. + */ public abstract Object getRenderingHint(RenderingHints.Key hintKey); + /** + * Replaces the current rendering hints with the supplied hints. + * + * @param hints the hints. + * + * @see #addRenderingHints(Map) + */ public abstract void setRenderingHints(Map<?,?> hints); + /** + * Adds/updates the rendering hint. + * + * @param hints the hints to add or update. + */ public abstract void addRenderingHints(Map<?,?> hints); + /** + * Returns the current rendering hints. + * + * @return The current rendering hints. + */ public abstract RenderingHints getRenderingHints(); public abstract void translate(int x, int y); @@ -134,25 +257,104 @@ public abstract class Graphics2D extends Graphics public abstract void shear(double shearX, double shearY); - public abstract void transform(AffineTransform Tx); + /** + * Sets the current transform to a concatenation of <code>transform</code> + * and the existing transform. + * + * @param transform the transform. + */ + public abstract void transform(AffineTransform transform); - public abstract void setTransform(AffineTransform Tx); - + /** + * Sets the current transform. If the caller specifies a <code>null</code> + * transform, this method should set the current transform to the + * identity transform. + * + * @param transform the transform (<code>null</code> permitted). + * + * @see #getTransform() + */ + public abstract void setTransform(AffineTransform transform); + + /** + * Returns the current transform. + * + * @return The current transform. + * + * @see #setTransform(AffineTransform) + */ public abstract AffineTransform getTransform(); + /** + * Returns the current paint. + * + * @return The current paint. + * + * @see #setPaint(Paint) + */ public abstract Paint getPaint(); + /** + * Returns the current compositing rule. + * + * @return The current compositing rule. + * + * @see #setComposite(Composite) + */ public abstract Composite getComposite(); + /** + * Sets the background color (used by the + * {@link Graphics#clearRect(int, int, int, int)} method). + * + * @param color the color. + * + * @see #getBackground() + */ public abstract void setBackground(Color color); + /** + * Returns the color used by the + * {@link Graphics#clearRect(int, int, int, int)} method. + * + * @return The background color. + * + * @see #setBackground(Color) + */ public abstract Color getBackground(); + /** + * Returns the current stroke. + * + * @return The current stroke. + * + * @see #setStroke(Stroke) + */ public abstract Stroke getStroke(); + /** + * Sets the clip region to the intersection of the current clipping region + * and <code>s</code>. + * + * @param s the shape to intersect with the current clipping region. + * + * @see Graphics#setClip(Shape) + */ public abstract void clip(Shape s); - public abstract FontRenderContext getFontRenderContext (); - - public abstract void drawGlyphVector (GlyphVector g, float x, float y); + /** + * Returns the font render context. + * + * @return The font render context. + */ + public abstract FontRenderContext getFontRenderContext(); + + /** + * Draws a glyph vector at the specified location. + * + * @param g the glyph vector. + * @param x the x-coordinate. + * @param y the y-coordinate. + */ + public abstract void drawGlyphVector(GlyphVector g, float x, float y); } diff --git a/java/awt/GraphicsConfiguration.java b/java/awt/GraphicsConfiguration.java index f68a1e6ba..792b2cc1b 100644 --- a/java/awt/GraphicsConfiguration.java +++ b/java/awt/GraphicsConfiguration.java @@ -65,6 +65,13 @@ import java.awt.image.VolatileImage; */ public abstract class GraphicsConfiguration { + + /** The cached image capabilities. */ + private ImageCapabilities imageCapabilities; + + /** The cached buffer capabilities. */ + private BufferCapabilities bufferCapabilities; + /** * The default constructor. * @@ -218,9 +225,14 @@ public abstract class GraphicsConfiguration * @since 1.4 */ public BufferCapabilities getBufferCapabilities() - throws NotImplementedException { - throw new Error("not implemented"); + if (imageCapabilities == null) + getImageCapabilities(); + + if (bufferCapabilities == null) + bufferCapabilities = new BufferCapabilities(imageCapabilities, + imageCapabilities, null); + return bufferCapabilities; } /** @@ -230,8 +242,9 @@ public abstract class GraphicsConfiguration * @since 1.4 */ public ImageCapabilities getImageCapabilities() - throws NotImplementedException { - throw new Error("not implemented"); + if (imageCapabilities == null) + imageCapabilities = new ImageCapabilities(false); + return imageCapabilities; } } // class GraphicsConfiguration diff --git a/java/awt/LightweightDispatcher.java b/java/awt/LightweightDispatcher.java index 860646402..3be18910b 100644 --- a/java/awt/LightweightDispatcher.java +++ b/java/awt/LightweightDispatcher.java @@ -67,6 +67,13 @@ class LightweightDispatcher * as well as the MOUSE_RELEASED event following the dragging. */ private Component dragTarget; + + /** + * Stores the button number which started the drag operation. This is needed + * because we want to handle only one drag operation and only the button that + * started the dragging should be able to stop it (by a button release). + */ + private int dragButton; /** * The last mouse event target. If the target changes, additional @@ -121,15 +128,41 @@ class LightweightDispatcher /** * Handles all mouse events that are targetted at toplevel containers * (Window instances) and dispatches them to the correct lightweight child. - * + * * @param ev the mouse event * @return whether or not we found a lightweight that handled the event. */ private boolean handleMouseEvent(MouseEvent ev) { Window window = (Window) ev.getSource(); - Component target = window.findComponentAt(ev.getX(), ev.getY()); - target = findTarget(target); + // Find the target for the mouse event. We first seach the deepest + // component at the specified location. The we go up to its parent and + // try to find a neighbor of the deepest component that is suitable as + // mouse event target (it must be showing, at that location and have either + // a MouseListener or MouseMotionListener installed). If no such component + // is found, then we walk up the container hierarchy and find the next + // container that has a MouseListener or MouseMotionListener installed. + Component deepest = window.findComponentAt(ev.getX(), ev.getY()); + if (deepest == null) + return false; + Container parent = deepest.getParent(); + Point loc = ev.getPoint(); + loc = AWTUtilities.convertPoint(window, loc.x, loc.y, parent); + Component target = null; + if (parent != null) + { + target = findTarget(deepest.getParent(), loc); + while (target == null && parent != null) + { + if (parent.getMouseListeners().length > 0 + || parent.getMouseMotionListeners().length > 0) + { + target = parent; + } + else + parent = parent.getParent(); + } + } if (target == null || target.isLightweight()) { // Dispatch additional MOUSE_EXITED and MOUSE_ENTERED if event target @@ -146,7 +179,16 @@ class LightweightDispatcher ev.getClickCount(), ev.isPopupTrigger()); lastTarget.dispatchEvent(mouseExited); } - if (target != null) + + // If a target exists dispatch the MOUSE_ENTERED event only if + // there is currently no component from which a drag operation + // started (dragTarget == null) or the target is that component + // (dragTarget == target) + // That way a user can click and hold on a button (putting it into + // the armed state), move the cursor above other buttons without + // affecting their rollover state and get back to the initial + // button. + if (target != null && (dragTarget == null || dragTarget == target)) { Point p = AWTUtilities.convertPoint(window, ev.getX(), ev.getY(), target); @@ -161,12 +203,30 @@ class LightweightDispatcher switch (ev.getID()) { case MouseEvent.MOUSE_PRESSED: - dragTarget = target; + // Handle the start of a drag operation or discard the event if + // one is already in progress. This prevents focus changes with the + // other mouse buttons when one is used for dragging. + if (dragTarget == null) + { + lastTarget = dragTarget = target; + + // Save the button that started the drag operation. + dragButton = ev.getButton(); + } + else + return false; + break; case MouseEvent.MOUSE_RELEASED: - if (dragTarget != null) - target = dragTarget; - dragTarget = null; + // Stop the drag operation only when the button that started + // it was released. + if (dragTarget != null && dragButton == ev.getButton()) + { + target = dragTarget; + dragTarget = null; + } + + lastTarget = target; break; case MouseEvent.MOUSE_CLICKED: // When we receive a MOUSE_CLICKED, we set the target to the @@ -174,18 +234,24 @@ class LightweightDispatcher // This is necessary for the case when the MOUSE_RELEASED has // caused the original target (like an internal component) go // away. + // This line is the reason why it is not possible to move the + // 'lastTarget = target' assignment before the switch-statement. target = lastTarget; break; case MouseEvent.MOUSE_DRAGGED: + // We consider only dragTarget for redispatching the event still + // we have to act in a way that the newly found target component + // was handled. + lastTarget = target; target = dragTarget; break; default: - // Do nothing in other cases. + // Only declare current target as the old value in all other + // cases. + lastTarget = target; break; } - lastTarget = target; - if (target != null) { Point targetCoordinates = @@ -195,6 +261,7 @@ class LightweightDispatcher ev.translatePoint(dx, dy); ev.setSource(target); target.dispatchEvent(ev); + // We reset the event, so that the normal event dispatching is not // influenced by this modified event. ev.setSource(window); @@ -209,19 +276,36 @@ class LightweightDispatcher /** * Finds the actual target for a mouseevent, starting at <code>c</code>. - * This searches upwards the component hierarchy until it finds a component - * that has a mouselistener attached. + * This searches through the children of the container and finds the first + * one which is showing, at the location from the mouse event and has + * a MouseListener or MouseMotionListener attached. If no such child component + * is found, null is returned. * - * @param c the component to start searching from + * @param c the container to search through + * @param loc the mouse event point * - * @return the actual receiver of the mouse event + * @return the actual receiver of the mouse event, or null, if no such + * component has been found */ - private Component findTarget(Component c) + private Component findTarget(Container c, Point loc) { - Component target = c; - while (target != null && target.getMouseListeners().length == 0) + Component[] children = c.getComponents(); + Component target = null; + if (c != null) { - target = target.getParent(); + Point childLoc; + for (int i = 0; i < children.length; i++) + { + Component child = children[i]; + childLoc = AWTUtilities.convertPoint(c, loc.x, loc.y, child); + if (child.isShowing() && child.contains(childLoc) + && (child.getMouseListeners().length > 0 + || child.getMouseMotionListeners().length > 0)) + { + target = child; + break; + } + } } return target; } diff --git a/java/awt/TexturePaint.java b/java/awt/TexturePaint.java index 57d7574c3..39cc892a6 100644 --- a/java/awt/TexturePaint.java +++ b/java/awt/TexturePaint.java @@ -45,35 +45,74 @@ import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; -/** STUB CLASS ONLY */ +/** + * This class provides a way to fill a Shape with a texture that is + * specified by a BufferedImage. + */ public class TexturePaint implements Paint { private final BufferedImage texture; private final Rectangle2D anchor; + + /** + * Constructor. + * + * @param texture - the texture + * @param anchor - the shape + */ public TexturePaint(BufferedImage texture, Rectangle2D anchor) { this.texture = texture; this.anchor = anchor; } + + /** + * Gets the texture image. + * + * @return the texture + */ public BufferedImage getImage() { return texture; } + + /** + * Gets the shape anchor. + * + * @return the shape anchor + */ public Rectangle2D getAnchorRect() { return anchor; } + + /** + * Creates the context used to paint the texture. + * + * @param cm - the ColorModel that receives the Paint data. Used only as a hint. + * @param deviceBounds - the device space being rendered. + * @param userBounds - the user space being rendered + * @param xform - the AffineTransform from user space into device space + * @param hints - a RenderingHints object that is used to specify how the + * pattern is rendered + * @return the paint context used to paint the texture + */ public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds, - AffineTransform xform, - RenderingHints hints) - throws NotImplementedException + AffineTransform xform, RenderingHints hints) + throws NotImplementedException { - throw new Error("not implemented"); + // FIXME: Not implemented. + return null; } + + /** + * Returns the transparency mode. + * + * @return the transparency mode. + */ public int getTransparency() - throws NotImplementedException { - throw new Error("not implemented"); + return texture.getTransparency(); } } // class TexturePaint diff --git a/java/awt/Toolkit.java b/java/awt/Toolkit.java index ee9123b1e..99863fab0 100644 --- a/java/awt/Toolkit.java +++ b/java/awt/Toolkit.java @@ -547,7 +547,7 @@ public abstract class Toolkit return ClassLoader.getSystemClassLoader(); } }); - Class cls = cl.loadClass(toolkit_name); + Class cls = Class.forName(toolkit_name, true, cl); Object obj = cls.newInstance(); if (!(obj instanceof Toolkit)) throw new AWTError(toolkit_name + " is not a subclass of " + diff --git a/java/awt/Window.java b/java/awt/Window.java index 2be2d5f17..aa0689ce8 100644 --- a/java/awt/Window.java +++ b/java/awt/Window.java @@ -1052,12 +1052,11 @@ public class Window extends Container implements Accessible /** * @since 1.2 * - * @deprecated + * @deprecated replaced by Component.applyComponentOrientation. */ public void applyResourceBundle(ResourceBundle rb) - throws NotImplementedException { - throw new Error ("Not implemented"); + applyComponentOrientation(ComponentOrientation.getOrientation(rb)); } /** diff --git a/java/awt/font/GlyphMetrics.java b/java/awt/font/GlyphMetrics.java index 18aaedc71..0a78d3052 100644 --- a/java/awt/font/GlyphMetrics.java +++ b/java/awt/font/GlyphMetrics.java @@ -38,8 +38,6 @@ exception statement from your version. */ package java.awt.font; -import gnu.classpath.NotImplementedException; - import java.awt.geom.Rectangle2D; /** @@ -94,16 +92,18 @@ public final class GlyphMetrics return bounds; } - public float getLSB () - throws NotImplementedException + public float getLSB() { - throw new Error ("not implemented"); + if (horizontal) + return (float) bounds.getX(); + return (float) bounds.getY(); } - public float getRSB () - throws NotImplementedException + public float getRSB() { - throw new Error ("not implemented"); + if (horizontal) + return (float) (advanceX - (bounds.getX() + bounds.getWidth())); + return (float) (advanceY - (bounds.getY() + bounds.getHeight())); } public int getType () diff --git a/java/awt/font/GlyphVector.java b/java/awt/font/GlyphVector.java index 8d8a51d68..f4cb01b95 100644 --- a/java/awt/font/GlyphVector.java +++ b/java/awt/font/GlyphVector.java @@ -38,8 +38,6 @@ exception statement from your version. */ package java.awt.font; -import gnu.classpath.NotImplementedException; - import java.awt.Font; import java.awt.Rectangle; import java.awt.Shape; @@ -48,6 +46,7 @@ import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; /** + * @author Lillian Angel (langel at redhat dot com) * @author Michael Koch */ public abstract class GlyphVector implements Cloneable @@ -72,16 +71,22 @@ public abstract class GlyphVector implements Cloneable public abstract FontRenderContext getFontRenderContext (); public int getGlyphCharIndex (int glyphIndex) - throws NotImplementedException { - throw new Error ("not implemented"); + return glyphIndex; } - public int[] getGlyphCharIndices (int beginGlyphIndex, int numEntries, - int[] codeReturn) - throws NotImplementedException + public int[] getGlyphCharIndices(int beginGlyphIndex, int numEntries, + int[] codeReturn) { - throw new Error ("not implemented"); + if (codeReturn == null) + codeReturn = new int[numEntries]; + + int i = 0; + int j = beginGlyphIndex; + while (j < numEntries) + codeReturn[i++] = getGlyphCharIndex(j++); + + return codeReturn; } public abstract int getGlyphCode (int glyphIndex); @@ -98,17 +103,27 @@ public abstract class GlyphVector implements Cloneable public abstract Shape getGlyphOutline (int glyphIndex); - public Shape getGlyphOutline (int glyphIndex, float x, float y) - throws NotImplementedException + public Shape getGlyphOutline(int glyphIndex, float x, float y) { - throw new Error ("not implemented"); + Shape s = getGlyphOutline(glyphIndex); + + // This is the only way to translate the origin of a shape + AffineTransform at = AffineTransform.getTranslateInstance(x, y); + return at.createTransformedShape(s); } - public Rectangle getGlyphPixelBounds (int index, FontRenderContext renderFRC, - float x, float y) - throws NotImplementedException + public Rectangle getGlyphPixelBounds(int index, FontRenderContext renderFRC, + float x, float y) { - throw new Error ("not implemented"); + Rectangle bounds = new Rectangle(); + Rectangle2D rect = getGlyphVisualBounds(index).getBounds2D(); + + bounds.x = (int) (rect.getX() + x); + bounds.y = (int) (rect.getY() + y); + bounds.width = (int) rect.getMaxX() - bounds.x; + bounds.height = (int) rect.getMaxY() - bounds.y; + + return bounds; } public abstract Point2D getGlyphPosition (int glyphIndex); @@ -121,10 +136,9 @@ public abstract class GlyphVector implements Cloneable public abstract Shape getGlyphVisualBounds (int glyphIndex); - public int getLayoutFlags () - throws NotImplementedException + public int getLayoutFlags() { - throw new Error ("not implemented"); + return 0; } public abstract Rectangle2D getLogicalBounds (); @@ -137,9 +151,16 @@ public abstract class GlyphVector implements Cloneable public Rectangle getPixelBounds (FontRenderContext renderFRC, float x, float y) - throws NotImplementedException { - throw new Error ("not implemented"); + Rectangle bounds = new Rectangle(); + Rectangle2D rect = getVisualBounds(); + + bounds.x = (int) (rect.getX() + x); + bounds.y = (int) (rect.getY() + y); + bounds.width = (int) rect.getMaxX() - bounds.x; + bounds.height = (int) rect.getMaxY() - bounds.y; + + return bounds; } public abstract Rectangle2D getVisualBounds (); diff --git a/java/awt/font/GraphicAttribute.java b/java/awt/font/GraphicAttribute.java index 107f16dcd..19f781bcc 100644 --- a/java/awt/font/GraphicAttribute.java +++ b/java/awt/font/GraphicAttribute.java @@ -38,51 +38,100 @@ exception statement from your version. */ package java.awt.font; -import gnu.classpath.NotImplementedException; - import java.awt.Graphics2D; import java.awt.geom.Rectangle2D; /** + * This class represents a graphic embedded in text. + * * @author Michael Koch + * @author Lillian Angel (langel at redhat dot com) */ public abstract class GraphicAttribute { - public static final int BOTTOM_ALIGNMENT = -2; + public static final int BOTTOM_ALIGNMENT = - 2; public static final int CENTER_BASELINE = 1; public static final int HANGING_BASELINE = 2; public static final int ROMAN_BASELINE = 0; - public static final int TOP_ALIGNMENT = -1; + public static final int TOP_ALIGNMENT = - 1; private int alignment; - - protected GraphicAttribute (int alignment) + + /** + * Constructor. + * + * @param alignment - the alignment to use for the graphic + */ + protected GraphicAttribute(int alignment) { + if (alignment < BOTTOM_ALIGNMENT || alignment > HANGING_BASELINE) + throw new IllegalArgumentException("Invalid alignment"); this.alignment = alignment; } - public abstract void draw (Graphics2D graphics, float x, float y); - - public abstract float getAdvance (); - - public final int getAlignment () + /** + * Draws the graphic. + * + * @param graphics - the graphics configuration to use + * @param x - the x location + * @param y - the y location + */ + public abstract void draw(Graphics2D graphics, float x, float y); + + /** + * Gets the distance from the origin of its graphic to the right side of the + * bounds of its graphic. + * + * @return the advance + */ + public abstract float getAdvance(); + + /** + * Gets the positive distance from the origin of its graphic to the top of + * bounds. + * + * @return the ascent + */ + public abstract float getAscent(); + + /** + * Gets the distance from the origin of its graphic to the bottom of the bounds. + * + * @return the descent + */ + public abstract float getDescent(); + + /** + * Gets the alignment. + * + * @return the alignment + */ + public final int getAlignment() { return alignment; } - public abstract float getAscent (); - - public Rectangle2D getBounds () - throws NotImplementedException + /** + * Returns a Rectangle2D that encloses the rendered area. + * Default bounds is the rectangle (0, -ascent, advance, ascent+descent). + * + * @return the bounds of the rendered area + */ + public Rectangle2D getBounds() { - throw new Error ("not implemented"); + float asc = getAscent(); + return new Rectangle2D.Float(0, - asc, getAdvance(), asc + getDescent()); } - public abstract float getDescent (); - - public GlyphJustificationInfo getJustificationInfo () - throws NotImplementedException + /** + * Returns the justification information for this object. + * + * @return the justification information + */ + public GlyphJustificationInfo getJustificationInfo() { - throw new Error ("not implemented"); + float adv = getAdvance(); + return new GlyphJustificationInfo(adv, false, 2, adv / 3, adv / 3, false, + 1, 0, 0); } } diff --git a/java/awt/font/ImageGraphicAttribute.java b/java/awt/font/ImageGraphicAttribute.java index c050255ee..3e4fdcf73 100644 --- a/java/awt/font/ImageGraphicAttribute.java +++ b/java/awt/font/ImageGraphicAttribute.java @@ -38,82 +38,150 @@ exception statement from your version. */ package java.awt.font; -import gnu.classpath.NotImplementedException; - import java.awt.Graphics2D; import java.awt.Image; import java.awt.geom.Rectangle2D; /** + * This is an implementation of GraphicAttribute which draws images in a + * TextLayout. + * + * @author Lillian Angel * @author Michael Koch */ -public final class ImageGraphicAttribute extends GraphicAttribute +public final class ImageGraphicAttribute + extends GraphicAttribute { private Image image; - - public ImageGraphicAttribute (Image image, int alignment) + private float originX; + private float originY; + + /** + * Constucts an instance from the specified Image. The origin is at (0, 0). + * + * @param image - image to construct from. + * @param alignment - the alignment + */ + public ImageGraphicAttribute(Image image, int alignment) { - super (alignment); - this.image = image; + this(image, alignment, 0, 0); } - public ImageGraphicAttribute (Image image, int alignment, float originX, - float originY) - throws NotImplementedException + /** + * Constucts an instance from the specified Image. The origin is at (originX, + * originY). + * + * @param image - image to construct from + * @param alignment - the alignment + * @param originX - x point of origin + * @param originY - y point of origin + */ + public ImageGraphicAttribute(Image image, int alignment, float originX, + float originY) { - super (alignment); + super(alignment); this.image = image; - - throw new Error ("not implemented"); + this.originX = originX; + this.originY = originY; } - public void draw (Graphics2D graphics, float x, float y) - throws NotImplementedException + /** + * Draws the image at the specified location, relative to the + * origin. + * + * @param g - the graphics to use to render the image + * @param x - the x location + * @param y - the y location + */ + public void draw(Graphics2D g, float x, float y) { - throw new Error ("not implemented"); + g.drawImage(image, (int) (x - originX), (int) (y - originY), null); } - public boolean equals (Object obj) + /** + * Compares this to the specified Object + * + * @param obj - the object to compare + * @return true if the obj and this are equivalent + */ + public boolean equals(Object obj) { if (! (obj instanceof ImageGraphicAttribute)) return false; - return equals ((ImageGraphicAttribute) obj); + return equals((ImageGraphicAttribute) obj); } - public boolean equals (ImageGraphicAttribute rhs) - throws NotImplementedException + /** + * Compares this to the ImageGraphicAttribute given, by + * comparing all fields and values. + * + * @param rhs - the ImageGraphicAttribute to compare + * @return true if the object given is equivalent to this + */ + public boolean equals(ImageGraphicAttribute rhs) { - throw new Error ("not implemented"); + return ((this == rhs) || ((this.getAscent() == rhs.getAscent()) + && (this.getAdvance() == rhs.getAdvance()) + && (this.getAlignment() == rhs.getAlignment()) + && (this.getBounds().equals(rhs.getBounds())) + && (this.getDescent() == rhs.getDescent()) + && (this.hashCode() == rhs.hashCode()) + && (this.image.equals(rhs.image)) + && (this.originX == rhs.originX) + && (this.originY == rhs.originY))); } - public float getAdvance () - throws NotImplementedException + /** + * Returns distance from the origin to the right edge of the image of this. + * + * @return the advance + */ + public float getAdvance() { - throw new Error ("not implemented"); + return Math.max(0, image.getWidth(null) - originX); } - public float getAscent () - throws NotImplementedException + /** + * Returns the the distance from the top of the image to the origin of this. + * + * @return the ascent. + */ + public float getAscent() { - throw new Error ("not implemented"); + return Math.max(0, originY); } - public Rectangle2D getBounds () - throws NotImplementedException + /** + * Gets the bounds of the object rendered, relative to the position. + * + * @return the bounds of the object rendered, relative to the position. + */ + public Rectangle2D getBounds() { - throw new Error ("not implemented"); + // This is equivalent to what Sun's JDK returns. + // I am not entirely sure why the origin is negative. + return new Rectangle2D.Float(- originX, - originY, image.getWidth(null), + image.getHeight(null)); } - public float getDescent () - throws NotImplementedException + /** + * Returns the distance from the origin to the bottom of the image. + * + * @return the descent + */ + public float getDescent() { - throw new Error ("not implemented"); + return Math.max(0, image.getHeight(null) - originY); } - public int hashCode () - throws NotImplementedException + /** + * Gets the hash code for this image. + * + * @return the hash code + */ + public int hashCode() { - throw new Error ("not implemented"); + return image.hashCode(); } } diff --git a/java/awt/font/ShapeGraphicAttribute.java b/java/awt/font/ShapeGraphicAttribute.java index d5320854c..06814972b 100644 --- a/java/awt/font/ShapeGraphicAttribute.java +++ b/java/awt/font/ShapeGraphicAttribute.java @@ -38,74 +38,148 @@ exception statement from your version. */ package java.awt.font; -import gnu.classpath.NotImplementedException; - import java.awt.Graphics2D; import java.awt.Shape; import java.awt.geom.Rectangle2D; +/** + * This is an implementation of GraphicAttribute that draws shapes in a TextLayout. + * + * @author Lillian Angel (langel at redhat dot com) + */ public final class ShapeGraphicAttribute extends GraphicAttribute { + /** True if the shape should be filled. */ public static final boolean FILL = false; + + /** True if the shape should be stroked with a 1-pixel wide stroke. */ public static final boolean STROKE = true; private Shape shape; private boolean stroke; + private Rectangle2D bounds; - public ShapeGraphicAttribute (Shape shape, int alignment, boolean stroke) + /** + * Constructor. + * + * @param shape - the Shape to render. The Shape is rendered with its origin. + * @param alignment - the alignment + * @param stroke - true if the Shape should be stroked; false if the Shape + * should be filled. + */ + public ShapeGraphicAttribute(Shape shape, int alignment, boolean stroke) { - super (alignment); + super(alignment); this.shape = shape; this.stroke = stroke; + this.bounds = shape.getBounds2D(); } - public void draw (Graphics2D graphics, float x, float y) - throws NotImplementedException + /** + * Draws the graphic at the given location. + * + * @param graphics - the graphics to use. + * @param x - the x location to draw at. + * @param y - the y location to draw at. + */ + public void draw(Graphics2D graphics, float x, float y) { - throw new Error ("not implemented"); + graphics.translate(x, y); + if (stroke == STROKE) + graphics.draw(shape); + else + graphics.fill(shape); + graphics.translate(- x, - y); } - public boolean equals (Object obj) + /** + * Compares this ShapeGraphicAttribute to obj. + * + * @param obj - the object to compare. + */ + public boolean equals(Object obj) { if (! (obj instanceof ShapeGraphicAttribute)) return false; - return equals ((ShapeGraphicAttribute) obj); + return equals((ShapeGraphicAttribute) obj); } - public boolean equals (ShapeGraphicAttribute rhs) + /** + * Compares this ShapeGraphicAttribute to rhs. + * + * @param rhs - the ShapeGraphicAttribute to compare. + */ + public boolean equals(ShapeGraphicAttribute rhs) { - return (shape.equals (rhs.shape) - && getAlignment () == rhs.getAlignment () - && stroke == rhs.stroke); + return (this == rhs || (this.shape.equals(rhs.shape) + && getAlignment() == rhs.getAlignment() + && stroke == rhs.stroke + && getAdvance() == rhs.getAdvance() + && getAscent() == rhs.getAscent() + && getBounds().equals(rhs.getBounds()) + && getDescent() == rhs.getDescent() + && hashCode() == rhs.hashCode())); } - public float getAdvance () - throws NotImplementedException + /** + * Gets the distance from the origin of its Shape to the right side of the + * bounds of its Shape. + * + * @return the advance + */ + public float getAdvance() { - throw new Error ("not implemented"); + return Math.max(0, (float) bounds.getMaxX()); } - public float getAscent () - throws NotImplementedException + /** + * Gets the positive distance from the origin of its Shape to the top of + * bounds. + * + * @return the ascent + */ + public float getAscent() { - throw new Error ("not implemented"); + return Math.max(0, -(float) bounds.getMinY()); } - public Rectangle2D getBounds () + /** + * Gets the distance from the origin of its Shape to the bottom of the bounds. + * + * @return the descent + */ + public float getDescent() { - return shape.getBounds2D (); + return Math.max(0, (float) bounds.getMaxY()); } - public float getDescent () - throws NotImplementedException + /** + * Returns a Rectangle2D that encloses all of the bits drawn by this shape. + * + * @return the bounds of the shape. + */ + public Rectangle2D getBounds() { - throw new Error ("not implemented"); + Rectangle2D.Float bounds = new Rectangle2D.Float(); + bounds.setRect(this.bounds); + + if (stroke == STROKE) + { + bounds.width++; + bounds.height++; + } + + return bounds; } - public int hashCode () + /** + * Gets the hash code. + * + * @return the hash code. + */ + public int hashCode() { - // FIXME: Check what SUN does here - return shape.hashCode (); + return shape.hashCode(); } } diff --git a/java/awt/image/ColorModel.java b/java/awt/image/ColorModel.java index 40307f2b9..e2f5378b4 100644 --- a/java/awt/image/ColorModel.java +++ b/java/awt/image/ColorModel.java @@ -92,7 +92,12 @@ public abstract class ColorModel implements Transparency int transparency; boolean hasAlpha; boolean isAlphaPremultiplied; - + + /** + * The standard color model for the common sRGB. + */ + private static final ColorModel S_RGB_MODEL = new SRGBColorModel(); + static int[] nArray(int value, int times) { int[] array = new int[times]; @@ -196,7 +201,7 @@ public abstract class ColorModel implements Transparency */ public static ColorModel getRGBdefault() { - return new DirectColorModel(32, 0xff0000, 0xff00, 0xff, 0xff000000); + return S_RGB_MODEL; } public final boolean hasAlpha() @@ -761,4 +766,56 @@ public abstract class ColorModel implements Transparency { return getClass().getName() + "[" + stringParam() + "]"; } + + /** + * A color model optimized for standard sRGB. + */ + private static class SRGBColorModel + extends DirectColorModel + { + + SRGBColorModel() + { + super(32,0x00FF0000,0x0000FF00,0x000000FF,0xFF000000); + } + + public int getAlpha(Object inData) + { + return ((((int[]) inData)[0]) >> 24) & 0xFF; + } + + public int getBlue(Object inData) + { + return ((((int[]) inData)[0])) & 0xFF; + } + + public int getGreen(Object inData) + { + return ((((int[]) inData)[0]) >> 8) & 0xFF; + } + + public int getRed(Object inData) + { + return ((((int[]) inData)[0]) >> 16) & 0xFF; + } + + public int getRGB(Object inData) + { + return ((int[]) inData)[0]; + } + + public Object getDataElements(int rgb, Object pixel) + { + if(pixel == null) + { + pixel = new int[]{rgb}; + } + else + { + ((int[]) pixel)[0] = rgb; + } + + return pixel; + } + } } diff --git a/java/awt/print/PrinterJob.java b/java/awt/print/PrinterJob.java index 7f67a6b04..8afada167 100644 --- a/java/awt/print/PrinterJob.java +++ b/java/awt/print/PrinterJob.java @@ -38,9 +38,13 @@ exception statement from your version. */ package java.awt.print; -import java.awt.HeadlessException; +import gnu.java.awt.print.JavaPrinterJob; +import java.awt.HeadlessException; import javax.print.PrintService; +import javax.print.PrintServiceLookup; +import javax.print.DocFlavor; +import javax.print.StreamPrintServiceFactory; import javax.print.attribute.PrintRequestAttributeSet; /** @@ -60,8 +64,7 @@ public abstract class PrinterJob */ public static PrinterJob getPrinterJob() { - // FIXME: Need to fix this to load a default implementation instance. - return new NoPrinterJob(); + return new JavaPrinterJob(); } /** @@ -244,13 +247,11 @@ public abstract class PrinterJob */ public static PrintService[] lookupPrintServices() { - return new PrintService[0]; - // FIXME: - // Enable this when javax.print has this implemented. -// return PrintServiceLookup.lookupPrintServices( -// new DocFlavor("application/x-java-jvm-local-objectref", -// "java.awt.print.Pageable"), -// null); + return PrintServiceLookup.lookupPrintServices + ( + new DocFlavor("application/x-java-jvm-local-objectref", + "java.awt.print.Pageable"), + null); } /** @@ -263,8 +264,8 @@ public abstract class PrinterJob * @return Array of stream print services, could be empty. * @since 1.4 */ - // FIXME: - // Enable when javax.print has StreamPrintServiceFactory + // FIXME: + // Enable when StreamPrintServiceFactory has lookupStreamServiceFactories // public static StreamPrintServiceFactory[] lookupStreamPrintServices(String mimeType) // { // return StreamPrintServiceFactory.lookupStreamServiceFactories( @@ -282,7 +283,7 @@ public abstract class PrinterJob */ public PrintService getPrintService() { - return null; + return printer; } /** @@ -297,6 +298,6 @@ public abstract class PrinterJob public void setPrintService(PrintService service) throws PrinterException { - throw new PrinterException(); + printer = service; } } diff --git a/java/lang/SecurityManager.java b/java/lang/SecurityManager.java index c069f3440..61b4612b1 100644 --- a/java/lang/SecurityManager.java +++ b/java/lang/SecurityManager.java @@ -421,7 +421,7 @@ public class SecurityManager public void checkAccess(Thread thread) { if (thread.getThreadGroup() != null - && thread.getThreadGroup().getParent() == null) + && thread.getThreadGroup().parent == null) checkPermission(new RuntimePermission("modifyThread")); } @@ -454,7 +454,7 @@ public class SecurityManager */ public void checkAccess(ThreadGroup g) { - if (g.getParent() == null) + if (g.parent == null) checkPermission(new RuntimePermission("modifyThreadGroup")); } diff --git a/java/lang/System.java b/java/lang/System.java index 0c78a532d..6a914820d 100644 --- a/java/lang/System.java +++ b/java/lang/System.java @@ -362,6 +362,7 @@ public final class System * <dt>gnu.java.io.encoding_scheme_alias.iso-latin-_?</dt> <dd>8859_?</dd> * <dt>gnu.java.io.encoding_scheme_alias.latin?</dt> <dd>8859_?</dd> * <dt>gnu.java.io.encoding_scheme_alias.utf-8</dt> <dd>UTF8</dd> + * <dt>gnu.javax.print.server</dt> <dd>Hostname of external CUPS server.</dd> * </dl> * * @return the system properties, will never be null diff --git a/java/lang/Thread.java b/java/lang/Thread.java index 51e0c107a..e5a654c1b 100644 --- a/java/lang/Thread.java +++ b/java/lang/Thread.java @@ -38,6 +38,7 @@ exception statement from your version. */ package java.lang; +import gnu.classpath.VMStackWalker; import gnu.java.util.WeakIdentityHashMap; import java.security.Permission; import java.util.Map; @@ -131,7 +132,8 @@ public class Thread implements Runnable /** The context classloader for this Thread. */ private ClassLoader contextClassLoader; - + private boolean contextClassLoaderIsSystemClassLoader; + /** This thread's ID. */ private final long threadId; @@ -251,7 +253,7 @@ public class Thread implements Runnable */ public Thread(ThreadGroup group, Runnable target) { - this(group, target, "Thread-" + ++numAnonymousThreadsCreated, 0); + this(group, target, createAnonymousThreadName(), 0); } /** @@ -350,7 +352,7 @@ public class Thread implements Runnable if (group == null) group = current.group; } - else if (sm != null) + if (sm != null) sm.checkAccess(group); this.group = group; @@ -367,6 +369,8 @@ public class Thread implements Runnable priority = current.priority; daemon = current.daemon; contextClassLoader = current.contextClassLoader; + contextClassLoaderIsSystemClassLoader = + current.contextClassLoaderIsSystemClassLoader; group.addThread(this); InheritableThreadLocal.newChildThread(this); @@ -376,6 +380,9 @@ public class Thread implements Runnable * Used by the VM to create thread objects for threads started outside * of Java. Note: caller is responsible for adding the thread to * a group and InheritableThreadLocal. + * Note: This constructor should not call any methods that could result + * in a call to Thread.currentThread(), because that makes life harder + * for the VM. * * @param vmThread the native thread * @param name the thread name or null to use the default naming scheme @@ -387,16 +394,33 @@ public class Thread implements Runnable this.vmThread = vmThread; this.runnable = null; if (name == null) - name = "Thread-" + ++numAnonymousThreadsCreated; + name = createAnonymousThreadName(); this.name = name; this.priority = priority; this.daemon = daemon; - this.contextClassLoader = ClassLoader.getSystemClassLoader(); + // By default the context class loader is the system class loader, + // we set a flag to signal this because we don't want to call + // ClassLoader.getSystemClassLoader() at this point, because on + // VMs that lazily create the system class loader that might result + // in running user code (when a custom system class loader is specified) + // and that user code could call Thread.currentThread(). + // ClassLoader.getSystemClassLoader() can also return null, if the system + // is currently in the process of constructing the system class loader + // (and, as above, the constructiong sequence calls Thread.currenThread()). + contextClassLoaderIsSystemClassLoader = true; synchronized (Thread.class) { this.threadId = nextThreadId++; } } + + /** + * Generate a name for an anonymous thread. + */ + private static synchronized String createAnonymousThreadName() + { + return "Thread-" + ++numAnonymousThreadsCreated; + } /** * Get the number of active threads in the current Thread's ThreadGroup. @@ -748,12 +772,18 @@ public class Thread implements Runnable */ public synchronized ClassLoader getContextClassLoader() { - // Bypass System.getSecurityManager, for bootstrap efficiency. + ClassLoader loader = contextClassLoaderIsSystemClassLoader ? + ClassLoader.getSystemClassLoader() : contextClassLoader; + // Check if we may get the classloader SecurityManager sm = SecurityManager.current; - if (sm != null) - // XXX Don't check this if the caller's class loader is an ancestor. - sm.checkPermission(new RuntimePermission("getClassLoader")); - return contextClassLoader; + if (loader != null && sm != null) + { + // Get the calling classloader + ClassLoader cl = VMStackWalker.getCallingClassLoader(); + if (cl != null && !cl.isAncestorOf(loader)) + sm.checkPermission(new RuntimePermission("getClassLoader")); + } + return loader; } /** @@ -774,6 +804,7 @@ public class Thread implements Runnable if (sm != null) sm.checkPermission(new RuntimePermission("setContextClassLoader")); this.contextClassLoader = classloader; + contextClassLoaderIsSystemClassLoader = false; } /** diff --git a/java/lang/ThreadGroup.java b/java/lang/ThreadGroup.java index 7fbef88f4..daddf43e3 100644 --- a/java/lang/ThreadGroup.java +++ b/java/lang/ThreadGroup.java @@ -66,7 +66,7 @@ public class ThreadGroup implements UncaughtExceptionHandler static boolean had_uncaught_exception; /** The parent thread group. */ - private final ThreadGroup parent; + final ThreadGroup parent; /** The group name, non-null. */ final String name; diff --git a/java/net/URLClassLoader.java b/java/net/URLClassLoader.java index abe54e18e..7e2353ac2 100644 --- a/java/net/URLClassLoader.java +++ b/java/net/URLClassLoader.java @@ -39,15 +39,21 @@ exception statement from your version. */ package java.net; -import java.io.BufferedReader; +import gnu.java.net.loader.FileURLLoader; +import gnu.java.net.loader.JarURLLoader; +import gnu.java.net.loader.RemoteURLLoader; +import gnu.java.net.loader.Resource; +import gnu.java.net.loader.URLLoader; +import gnu.java.net.loader.URLStreamHandlerCache; + import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.File; -import java.io.FileInputStream; import java.io.FilePermission; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.security.AccessControlContext; import java.security.AccessController; import java.security.CodeSource; @@ -55,14 +61,10 @@ import java.security.PermissionCollection; import java.security.PrivilegedAction; import java.security.SecureClassLoader; import java.security.cert.Certificate; +import java.util.ArrayList; import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.StringTokenizer; import java.util.Vector; import java.util.jar.Attributes; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; import java.util.jar.Manifest; @@ -128,19 +130,17 @@ public class URLClassLoader extends SecureClassLoader // Class Variables /** - * A global cache to store mappings between URLLoader and URL, - * so we can avoid do all the homework each time the same URL - * comes. - * XXX - Keeps these loaders forever which prevents garbage collection. + * A cache to store mappings between handler factory and its + * private protocol handler cache (also a HashMap), so we can avoid + * creating handlers each time the same protocol comes. */ - private static HashMap urlloaders = new HashMap(); + private static URLStreamHandlerCache factoryCache + = new URLStreamHandlerCache(); /** - * A cache to store mappings between handler factory and its - * private protocol handler cache (also a HashMap), so we can avoid - * create handlers each time the same protocol comes. + * The prefix for URL loaders. */ - private static HashMap factoryCache = new HashMap(5); + private static final String URL_LOADER_PREFIX = "gnu.java.net.loader.Load_"; // Instance variables @@ -168,516 +168,6 @@ public class URLClassLoader extends SecureClassLoader // Helper classes /** - * A <code>URLLoader</code> contains all logic to load resources from a - * given base <code>URL</code>. - */ - abstract static class URLLoader - { - /** - * Our classloader to get info from if needed. - */ - final URLClassLoader classloader; - - /** - * The base URL from which all resources are loaded. - */ - final URL baseURL; - - /** - * A <code>CodeSource</code> without any associated certificates. - * It is common for classes to not have certificates associated - * with them. If they come from the same <code>URLLoader</code> - * then it is safe to share the associated <code>CodeSource</code> - * between them since <code>CodeSource</code> is immutable. - */ - final CodeSource noCertCodeSource; - - URLLoader(URLClassLoader classloader, URL baseURL) - { - this(classloader, baseURL, baseURL); - } - - URLLoader(URLClassLoader classloader, URL baseURL, URL overrideURL) - { - this.classloader = classloader; - this.baseURL = baseURL; - this.noCertCodeSource = new CodeSource(overrideURL, null); - } - - /** - * Returns a <code>Resource</code> loaded by this - * <code>URLLoader</code>, or <code>null</code> when no - * <code>Resource</code> with the given name exists. - */ - abstract Resource getResource(String s); - - /** - * Returns the <code>Manifest</code> associated with the - * <code>Resource</code>s loaded by this <code>URLLoader</code> or - * <code>null</code> there is no such <code>Manifest</code>. - */ - Manifest getManifest() - { - return null; - } - - Vector getClassPath() - { - return null; - } - } - - /** - * A <code>Resource</code> represents a resource in some - * <code>URLLoader</code>. It also contains all information (e.g., - * <code>URL</code>, <code>CodeSource</code>, <code>Manifest</code> and - * <code>InputStream</code>) that is necessary for loading resources - * and creating classes from a <code>URL</code>. - */ - abstract static class Resource - { - final URLLoader loader; - - Resource(URLLoader loader) - { - this.loader = loader; - } - - /** - * Returns the non-null <code>CodeSource</code> associated with - * this resource. - */ - CodeSource getCodeSource() - { - Certificate[] certs = getCertificates(); - if (certs == null) - return loader.noCertCodeSource; - else - return new CodeSource(loader.baseURL, certs); - } - - /** - * Returns <code>Certificates</code> associated with this - * resource, or null when there are none. - */ - Certificate[] getCertificates() - { - return null; - } - - /** - * Return a <code>URL</code> that can be used to access this resource. - */ - abstract URL getURL(); - - /** - * Returns the size of this <code>Resource</code> in bytes or - * <code>-1</code> when unknown. - */ - abstract int getLength(); - - /** - * Returns the non-null <code>InputStream</code> through which - * this resource can be loaded. - */ - abstract InputStream getInputStream() throws IOException; - } - - /** - * A <code>JarURLLoader</code> is a type of <code>URLLoader</code> - * only loading from jar url. - */ - static final class JarURLLoader extends URLLoader - { - final JarFile jarfile; // The jar file for this url - final URL baseJarURL; // Base jar: url for all resources loaded from jar - - Vector classPath; // The "Class-Path" attribute of this Jar's manifest - - public JarURLLoader(URLClassLoader classloader, URL baseURL, - URL absoluteUrl) - { - super(classloader, baseURL, absoluteUrl); - - // Cache url prefix for all resources in this jar url. - String external = baseURL.toExternalForm(); - StringBuffer sb = new StringBuffer(external.length() + 6); - sb.append("jar:"); - sb.append(external); - sb.append("!/"); - String jarURL = sb.toString(); - - this.classPath = null; - URL baseJarURL = null; - JarFile jarfile = null; - try - { - baseJarURL = - new URL(null, jarURL, classloader.getURLStreamHandler("jar")); - - jarfile = - ((JarURLConnection) baseJarURL.openConnection()).getJarFile(); - - Manifest manifest; - Attributes attributes; - String classPathString; - - this.classPath = new Vector(); - - // This goes through the cached jar files listed - // in the INDEX.LIST file. All the jars found are added - // to the classPath vector so they can be loaded. - String dir = "META-INF/INDEX.LIST"; - if (jarfile.getEntry(dir) != null) - { - BufferedReader br = new BufferedReader(new InputStreamReader(new URL(baseJarURL, - dir).openStream())); - String line = br.readLine(); - while (line != null) - { - if (line.endsWith(".jar")) - { - try - { - this.classPath.add(new URL(baseURL, line)); - } - catch (java.net.MalformedURLException xx) - { - // Give up - } - } - line = br.readLine(); - } - } - else if ((manifest = jarfile.getManifest()) != null - && (attributes = manifest.getMainAttributes()) != null - && ((classPathString - = attributes.getValue(Attributes.Name.CLASS_PATH)) - != null)) - { - StringTokenizer st = new StringTokenizer(classPathString, " "); - while (st.hasMoreElements ()) - { - String e = st.nextToken (); - try - { - this.classPath.add(new URL(baseURL, e)); - } - catch (java.net.MalformedURLException xx) - { - // Give up - } - } - } - } - catch (IOException ioe) - { - /* ignored */ - } - - this.baseJarURL = baseJarURL; - this.jarfile = jarfile; - } - - /** get resource with the name "name" in the jar url */ - Resource getResource(String name) - { - if (jarfile == null) - return null; - - if (name.startsWith("/")) - name = name.substring(1); - - JarEntry je = jarfile.getJarEntry(name); - if (je != null) - return new JarURLResource(this, name, je); - else - return null; - } - - Manifest getManifest() - { - try - { - return (jarfile == null) ? null : jarfile.getManifest(); - } - catch (IOException ioe) - { - return null; - } - } - - Vector getClassPath() - { - return classPath; - } - } - - static final class JarURLResource extends Resource - { - private final JarEntry entry; - private final String name; - - JarURLResource(JarURLLoader loader, String name, JarEntry entry) - { - super(loader); - this.entry = entry; - this.name = name; - } - - InputStream getInputStream() throws IOException - { - return ((JarURLLoader) loader).jarfile.getInputStream(entry); - } - - int getLength() - { - return (int) entry.getSize(); - } - - Certificate[] getCertificates() - { - // We have to get the entry from the jar file again, because the - // certificates will not be available until the entire entry has - // been read. - return ((JarEntry) ((JarURLLoader) loader).jarfile.getEntry(name)) - .getCertificates(); - } - - URL getURL() - { - try - { - return new URL(((JarURLLoader) loader).baseJarURL, name, - loader.classloader.getURLStreamHandler("jar")); - } - catch (MalformedURLException e) - { - InternalError ie = new InternalError(); - ie.initCause(e); - throw ie; - } - } - } - - /** - * Loader for remote directories. - */ - static final class RemoteURLLoader extends URLLoader - { - private final String protocol; - - RemoteURLLoader(URLClassLoader classloader, URL url) - { - super(classloader, url); - protocol = url.getProtocol(); - } - - /** - * Get a remote resource. - * Returns null if no such resource exists. - */ - Resource getResource(String name) - { - try - { - URL url = - new URL(baseURL, name, classloader.getURLStreamHandler(protocol)); - URLConnection connection = url.openConnection(); - - // Open the connection and check the stream - // just to be sure it exists. - int length = connection.getContentLength(); - InputStream stream = connection.getInputStream(); - - // We can do some extra checking if it is a http request - if (connection instanceof HttpURLConnection) - { - int response = - ((HttpURLConnection) connection).getResponseCode(); - if (response / 100 != 2) - return null; - } - - if (stream != null) - return new RemoteResource(this, name, url, stream, length); - else - return null; - } - catch (IOException ioe) - { - return null; - } - } - } - - /** - * A resource from some remote location. - */ - static final class RemoteResource extends Resource - { - private final URL url; - private final InputStream stream; - private final int length; - - RemoteResource(RemoteURLLoader loader, String name, URL url, - InputStream stream, int length) - { - super(loader); - this.url = url; - this.stream = stream; - this.length = length; - } - - InputStream getInputStream() throws IOException - { - return stream; - } - - public int getLength() - { - return length; - } - - public URL getURL() - { - return url; - } - } - - /** - * A <code>FileURLLoader</code> is a type of <code>URLLoader</code> - * only loading from file url. - */ - static final class FileURLLoader extends URLLoader - { - File dir; //the file for this file url - - FileURLLoader(URLClassLoader classloader, URL url, URL absoluteUrl) - { - super(classloader, url, absoluteUrl); - dir = new File(absoluteUrl.getFile()); - } - - /** get resource with the name "name" in the file url */ - Resource getResource(String name) - { - try - { - // Make sure that all components in name are valid by walking through - // them - File file = walkPathComponents(name); - - if (file == null) - return null; - - return new FileResource(this, file); - } - catch (IOException e) - { - // Fall through... - } - return null; - } - - /** - * Walk all path tokens and check them for validity. At no moment, we are - * allowed to reach a directory located "above" the root directory, stored - * in "dir" property. We are also not allowed to enter a non existing - * directory or a non directory component (plain file, symbolic link, ...). - * An empty or null path is valid. Pathnames components are separated by - * <code>File.separatorChar</code> - * - * @param resourceFileName the name to be checked for validity. - * @return the canonical file pointed by the resourceFileName or null if the - * walking failed - * @throws IOException in case of issue when creating the canonical - * resulting file - * @see File#separatorChar - */ - private File walkPathComponents(String resourceFileName) throws IOException - { - StringTokenizer stringTokenizer = new StringTokenizer(resourceFileName, File.separator); - File currentFile = dir; - int tokenCount = stringTokenizer.countTokens(); - - for (int i = 0; i < tokenCount - 1; i++) - { - String currentToken = stringTokenizer.nextToken(); - - // If we are at the root directory and trying to go up, the walking is - // finished with an error - if ("..".equals(currentToken) && currentFile.equals(dir)) - return null; - - currentFile = new File(currentFile, currentToken); - - // If the current file doesn't exist or is not a directory, the walking is - // finished with an error - if (! (currentFile.exists() && currentFile.isDirectory())) - return null; - - } - - // Treat the last token differently, if it exists, because it does not need - // to be a directory - if (tokenCount > 0) - { - String currentToken = stringTokenizer.nextToken(); - - if ("..".equals(currentToken) && currentFile.equals(dir)) - return null; - - currentFile = new File(currentFile, currentToken); - - // If the current file doesn't exist, the walking is - // finished with an error - if (! currentFile.exists()) - return null; - } - - return currentFile.getCanonicalFile(); - } - } - - static final class FileResource extends Resource - { - final File file; - - FileResource(FileURLLoader loader, File file) - { - super(loader); - this.file = file; - } - - InputStream getInputStream() throws IOException - { - return new FileInputStream(file); - } - - public int getLength() - { - return (int) file.length(); - } - - public URL getURL() - { - try - { - return file.toURL(); - } - catch (MalformedURLException e) - { - InternalError ie = new InternalError(); - ie.initCause(e); - throw ie; - } - } - } - - // Constructors - - /** * Creates a URLClassLoader that gets classes from the supplied URLs. * To determine if this classloader may be created the constructor of * the super class (<code>SecureClassLoader</code>) is called first, which @@ -774,14 +264,8 @@ public class URLClassLoader extends SecureClassLoader this.factory = factory; addURLs(urls); - // If this factory is still not in factoryCache, add it, - // since we only support three protocols so far, 5 is enough - // for cache initial size - synchronized (factoryCache) - { - if (factory != null && factoryCache.get(factory) == null) - factoryCache.put(factory, new HashMap(5)); - } + // If this factory is still not in factoryCache, add it. + factoryCache.add(factory); } // Methods @@ -806,72 +290,114 @@ public class URLClassLoader extends SecureClassLoader // Reset the toString() value. thisString = null; - // Check global cache to see if there're already url loader - // for this url. - URLLoader loader = (URLLoader) urlloaders.get(newUrl); - if (loader == null) + // Create a loader for this URL. + URLLoader loader = null; + String file = newUrl.getFile(); + String protocol = newUrl.getProtocol(); + + // If we have a file: URL, we want to make it absolute + // here, before we decide whether it is really a jar. + URL absoluteURL; + if ("file".equals (protocol)) + { + File dir = new File(file); + URL absUrl; + try + { + absoluteURL = dir.getCanonicalFile().toURL(); + } + catch (IOException ignore) + { + try + { + absoluteURL = dir.getAbsoluteFile().toURL(); + } + catch (MalformedURLException _) + { + // This really should not happen. + absoluteURL = newUrl; + } + } + } + else { - String file = newUrl.getFile(); - String protocol = newUrl.getProtocol(); + // This doesn't hurt, and it simplifies the logic a + // little. + absoluteURL = newUrl; + } - // If we have a file: URL, we want to make it absolute - // here, before we decide whether it is really a jar. - URL absoluteURL; - if ("file".equals (protocol)) - { - File dir = new File(file); - URL absUrl; - try - { - absoluteURL = dir.getCanonicalFile().toURL(); - } - catch (IOException ignore) - { - try - { - absoluteURL = dir.getAbsoluteFile().toURL(); - } - catch (MalformedURLException _) - { - // This really should not happen. - absoluteURL = newUrl; - } - } - } - else - { - // This doesn't hurt, and it simplifies the logic a - // little. - absoluteURL = newUrl; - } + // First see if we can find a handler with the correct name. + try + { + Class handler = Class.forName(URL_LOADER_PREFIX + protocol); + Class[] argTypes = new Class[] { URLClassLoader.class, + URLStreamHandlerCache.class, + URLStreamHandlerFactory.class, + URL.class, + URL.class }; + Constructor k = handler.getDeclaredConstructor(argTypes); + loader + = (URLLoader) k.newInstance(new Object[] { this, + factoryCache, + factory, + newUrl, + absoluteURL }); + } + catch (ClassNotFoundException ignore) + { + // Fall through. + } + catch (NoSuchMethodException nsme) + { + // Programming error in the class library. + InternalError vme + = new InternalError("couldn't find URLLoader constructor"); + vme.initCause(nsme); + throw vme; + } + catch (InstantiationException inste) + { + // Programming error in the class library. + InternalError vme + = new InternalError("couldn't instantiate URLLoader"); + vme.initCause(inste); + throw vme; + } + catch (InvocationTargetException ite) + { + // Programming error in the class library. + InternalError vme + = new InternalError("error instantiating URLLoader"); + vme.initCause(ite); + throw vme; + } + catch (IllegalAccessException illae) + { + // Programming error in the class library. + InternalError vme + = new InternalError("invalid access to URLLoader"); + vme.initCause(illae); + throw vme; + } - // Check that it is not a directory + if (loader == null) + { + // If it is not a directory, use the jar loader. if (! (file.endsWith("/") || file.endsWith(File.separator))) - loader = new JarURLLoader(this, newUrl, absoluteURL); + loader = new JarURLLoader(this, factoryCache, factory, + newUrl, absoluteURL); else if ("file".equals(protocol)) - loader = new FileURLLoader(this, newUrl, absoluteURL); + loader = new FileURLLoader(this, factoryCache, factory, + newUrl, absoluteURL); else - loader = new RemoteURLLoader(this, newUrl); - - // Cache it. - urlloaders.put(newUrl, loader); + loader = new RemoteURLLoader(this, factoryCache, factory, + newUrl); } urlinfos.add(loader); - - Vector extraUrls = loader.getClassPath(); - if (extraUrls != null) - { - Iterator it = extraUrls.iterator(); - while (it.hasNext()) - { - URL url = (URL)it.next(); - URLLoader extraLoader = (URLLoader) urlloaders.get(url); - if (! urlinfos.contains (extraLoader)) - addURLImpl(url); - } - } - + ArrayList extra = loader.getClassPath(); + if (extra != null) + urlinfos.addAll(extra); } } @@ -987,7 +513,20 @@ public class URLClassLoader extends SecureClassLoader { // Just try to find the resource by the (almost) same name String resourceName = className.replace('.', '/') + ".class"; - Resource resource = findURLResource(resourceName); + int max = urlinfos.size(); + Resource resource = null; + for (int i = 0; i < max && resource == null; i++) + { + URLLoader loader = (URLLoader)urlinfos.elementAt(i); + if (loader == null) + continue; + + Class k = loader.getClass(className); + if (k != null) + return k; + + resource = loader.getResource(resourceName); + } if (resource == null) throw new ClassNotFoundException(className + " not found in " + this); @@ -1049,12 +588,13 @@ public class URLClassLoader extends SecureClassLoader if (packageName != null && getPackage(packageName) == null) { // define the package - Manifest manifest = resource.loader.getManifest(); + Manifest manifest = resource.getLoader().getManifest(); if (manifest == null) definePackage(packageName, null, null, null, null, null, null, null); else - definePackage(packageName, manifest, resource.loader.baseURL); + definePackage(packageName, manifest, + resource.getLoader().getBaseURL()); } // And finally construct the class! @@ -1166,34 +706,6 @@ public class URLClassLoader extends SecureClassLoader } /** - * If the URLStreamHandlerFactory has been set this return the appropriate - * URLStreamHandler for the given protocol, if not set returns null. - * - * @param protocol the protocol for which we need a URLStreamHandler - * @return the appropriate URLStreamHandler or null - */ - URLStreamHandler getURLStreamHandler(String protocol) - { - if (factory == null) - return null; - - URLStreamHandler handler; - synchronized (factoryCache) - { - // Check if there're handler for the same protocol in cache. - HashMap cache = (HashMap) factoryCache.get(factory); - handler = (URLStreamHandler) cache.get(protocol); - if (handler == null) - { - // Add it to cache. - handler = factory.createURLStreamHandler(protocol); - cache.put(protocol, handler); - } - } - return handler; - } - - /** * Finds all the resources with a particular name from all the locations. * * @param resourceName the name of the resource to lookup diff --git a/java/net/URLConnection.java b/java/net/URLConnection.java index b6b6435dc..a17ba2e20 100644 --- a/java/net/URLConnection.java +++ b/java/net/URLConnection.java @@ -174,6 +174,11 @@ public abstract class URLConnection private static SimpleDateFormat[] dateFormats; private static boolean dateformats_initialized; + + /** + * The timeout period. + */ + private int timeout; /* Cached ParsePosition, used when parsing dates. */ private ParsePosition position; @@ -213,6 +218,38 @@ public abstract class URLConnection } /** + * Returns the connection timeout speed, in milliseconds, or zero if the timeout + * is infinite or not set. + * + * @return The timeout. + * + * @since 1.5 + */ + public int getConnectTimeout() + { + return timeout; + } + + /** + * Set the connection timeout speed, in milliseconds, or zero if the timeout + * is to be considered infinite. Note that in certain socket + * implementations/platforms this method may not have any effect. + * + * Throws an <code>IllegalArgumentException</code> if timeout < 0. + * + * @param timeout - The timeout, in milliseconds. + * + * @since 1.5 + */ + public void setConnectTimeout(int timeout) + throws IllegalArgumentException + { + if( timeout < 0 ) + throw new IllegalArgumentException("Timeout must be 0 or positive."); + this.timeout = timeout; + } + + /** * Returns the value of the content-length header field or -1 if the value * is not known or not present. * diff --git a/java/nio/channels/FileChannel.java b/java/nio/channels/FileChannel.java index 0eefffbe9..3aa199909 100644 --- a/java/nio/channels/FileChannel.java +++ b/java/nio/channels/FileChannel.java @@ -114,12 +114,7 @@ public abstract class FileChannel extends AbstractInterruptibleChannel */ public final long write(ByteBuffer[] srcs) throws IOException { - long result = 0; - - for (int i = 0; i < srcs.length; i++) - result += write(srcs[i]); - - return result; + return write(srcs, 0, srcs.length); } /** @@ -169,12 +164,7 @@ public abstract class FileChannel extends AbstractInterruptibleChannel */ public final long read(ByteBuffer[] dsts) throws IOException { - long result = 0; - - for (int i = 0; i < dsts.length; i++) - read(dsts[i]); - - return result; + return read(dsts, 0, dsts.length); } /** diff --git a/java/text/NumberFormat.java b/java/text/NumberFormat.java index 58e640cc5..1b96afcd5 100644 --- a/java/text/NumberFormat.java +++ b/java/text/NumberFormat.java @@ -484,7 +484,7 @@ public abstract class NumberFormat extends Format implements Cloneable */ public static NumberFormat getIntegerInstance(Locale locale) { - NumberFormat format = computeInstance (locale, "numberFormat", "#,##0"); + NumberFormat format = computeInstance (locale, "integerFormat", "#,##0"); format.setMaximumFractionDigits(0); format.setParseIntegerOnly (true); return format; diff --git a/java/text/SimpleDateFormat.java b/java/text/SimpleDateFormat.java index 00c08507e..2825c7bed 100644 --- a/java/text/SimpleDateFormat.java +++ b/java/text/SimpleDateFormat.java @@ -307,7 +307,7 @@ public class SimpleDateFormat extends DateFormat // Not a valid letter throw new IllegalArgumentException("Invalid letter " + thisChar + - "encountered at character " + " encountered at character " + i + "."); } else if (thisChar == '\'') diff --git a/java/util/Calendar.java b/java/util/Calendar.java index f0f1e37de..6865230c8 100644 --- a/java/util/Calendar.java +++ b/java/util/Calendar.java @@ -878,6 +878,7 @@ public abstract class Calendar 1, 1970, JANUARY, 1, 1, 1, 1, THURSDAY, 1, AM, 0, 0, 0, 0, 0, zone.getRawOffset(), 0 }; + complete(); isTimeSet = false; areFieldsSet = false; isSet[field] = false; diff --git a/java/util/Collections.java b/java/util/Collections.java index d4d26ce25..40268379a 100644 --- a/java/util/Collections.java +++ b/java/util/Collections.java @@ -1,5 +1,5 @@ /* Collections.java -- Utility class with methods to operate on collections - Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005 + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -4979,7 +4979,7 @@ public class Collections public Set<Map.Entry<K, V>> entrySet() { if (entries == null) - entries = new UnmodifiableEntrySet<Map.Entry<K,V>>(m.entrySet()); + entries = new UnmodifiableEntrySet<K,V>(m.entrySet()); return entries; } @@ -4989,10 +4989,91 @@ public class Collections * * @author Eric Blake (ebb9@email.byu.edu) */ - private static final class UnmodifiableEntrySet<T> - extends UnmodifiableSet<T> + private static final class UnmodifiableEntrySet<K,V> + extends UnmodifiableSet<Map.Entry<K,V>> implements Serializable { + // Unmodifiable implementation of Map.Entry used as return value for + // UnmodifiableEntrySet accessors (iterator, toArray, toArray(Object[])) + private static final class UnmodifiableMapEntry<K,V> + implements Map.Entry<K,V> + { + private final Map.Entry<K,V> e; + + private UnmodifiableMapEntry(Map.Entry<K,V> e) + { + super(); + this.e = e; + } + + /** + * Returns <code>true</code> if the object, o, is also a map entry + * with an identical key and value. + * + * @param o the object to compare. + * @return <code>true</code> if o is an equivalent map entry. + */ + public boolean equals(Object o) + { + return e.equals(o); + } + + /** + * Returns the key of this map entry. + * + * @return the key. + */ + public K getKey() + { + return e.getKey(); + } + + /** + * Returns the value of this map entry. + * + * @return the value. + */ + public V getValue() + { + return e.getValue(); + } + + /** + * Computes the hash code of this map entry. The computation is + * described in the <code>Map</code> interface documentation. + * + * @return the hash code of this entry. + * @see Map#hashCode() + */ + public int hashCode() + { + return e.hashCode(); + } + + /** + * Blocks the alteration of the value of this map entry. This method + * never returns, throwing an exception instead. + * + * @param value The new value. + * @throws UnsupportedOperationException as an unmodifiable map entry + * does not support the <code>setValue()</code> operation. + */ + public V setValue(V value) + { + throw new UnsupportedOperationException(); + } + + /** + * Returns a textual representation of the map entry. + * + * @return The map entry as a <code>String</code>. + */ + public String toString() + { + return e.toString(); + } + } + /** * Compatible with JDK 1.4. */ @@ -5002,15 +5083,15 @@ public class Collections * Wrap a given set. * @param s the set to wrap */ - UnmodifiableEntrySet(Set<T> s) + UnmodifiableEntrySet(Set<Map.Entry<K,V>> s) { super(s); } // The iterator must return unmodifiable map entries. - public Iterator<T> iterator() + public Iterator<Map.Entry<K,V>> iterator() { - return new UnmodifiableIterator<T>(c.iterator()) + return new UnmodifiableIterator<Map.Entry<K,V>>(c.iterator()) { /** * Obtains the next element from the underlying set of @@ -5019,83 +5100,45 @@ public class Collections * @return the next element in the collection. * @throws NoSuchElementException if there are no more elements. */ - public T next() + public Map.Entry<K,V> next() { - final Map.Entry e = (Map.Entry) super.next(); - return (T) new Map.Entry() - { - /** - * Returns <code>true</code> if the object, o, is also a map entry with an - * identical key and value. - * - * @param o the object to compare. - * @return <code>true</code> if o is an equivalent map entry. - */ - public boolean equals(Object o) - { - return e.equals(o); - } - - /** - * Returns the key of this map entry. - * - * @return the key. - */ - public Object getKey() - { - return e.getKey(); - } - - /** - * Returns the value of this map entry. - * - * @return the value. - */ - public Object getValue() - { - return e.getValue(); - } - - /** - * Computes the hash code of this map entry. - * The computation is described in the <code>Map</code> - * interface documentation. - * - * @return the hash code of this entry. - * @see Map#hashCode() - */ - public int hashCode() - { - return e.hashCode(); - } - - /** - * Blocks the alteration of the value of this map entry. - * This method never returns, throwing an exception instead. - * - * @param value The new value. - * @throws UnsupportedOperationException as an unmodifiable - * map entry does not support the <code>setValue()</code> - * operation. - */ - public Object setValue(Object value) - { - throw new UnsupportedOperationException(); - } - - /** - * Returns a textual representation of the map entry. - * - * @return The map entry as a <code>String</code>. - */ - public String toString() - { - return e.toString(); - } - }; - } + final Map.Entry<K,V> e = super.next(); + return new UnmodifiableMapEntry<K,V>(e); + } }; } + + // The array returned is an array of UnmodifiableMapEntry instead of + // Map.Entry + public Map.Entry<K,V>[] toArray() + { + Map.Entry<K,V>[] mapEntryResult = (Map.Entry<K,V>[]) super.toArray(); + UnmodifiableMapEntry<K,V> result[] = null; + + if (mapEntryResult != null) + { + result = (UnmodifiableMapEntry<K,V>[]) + new UnmodifiableMapEntry[mapEntryResult.length]; + for (int i = 0; i < mapEntryResult.length; ++i) + result[i] = new UnmodifiableMapEntry(mapEntryResult[i]); + } + return result; + } + + // The array returned is an array of UnmodifiableMapEntry instead of + // Map.Entry + public Map.Entry<K,V>[] toArray(Map.Entry<K,V>[] array) + { + super.toArray(array); + + if (array != null) + for (int i = 0; i < array.length; i++) + array[i] = + new UnmodifiableMapEntry<K,V>(array[i]); + return array; + } + + } // class UnmodifiableEntrySet /** diff --git a/java/util/jar/JarOutputStream.java b/java/util/jar/JarOutputStream.java index 2c8c2f08d..46c71b38c 100644 --- a/java/util/jar/JarOutputStream.java +++ b/java/util/jar/JarOutputStream.java @@ -101,7 +101,7 @@ public class JarOutputStream extends ZipOutputStream /** * Prepares the JarOutputStream for writing the next entry. - * This implementation just calls <code>super.putNextEntre()</code>. + * This implementation just calls <code>super.putNextEntry()</code>. * * @param entry The information for the next entry * @exception IOException when some unexpected I/O exception occurred diff --git a/java/util/jar/Manifest.java b/java/util/jar/Manifest.java index d6e04b7c7..8effc2878 100644 --- a/java/util/jar/Manifest.java +++ b/java/util/jar/Manifest.java @@ -1,4 +1,4 @@ -/* Manifest.java -- Reads, writes and manipulaties jar manifest files +/* Manifest.java -- Reads, writes and manipulates jar manifest files Copyright (C) 2000, 2004 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -152,7 +152,7 @@ public class Manifest implements Cloneable } /** - * Read and merge a <code>Mainfest</code> from the designated input stream. + * Read and merge a <code>Manifest</code> from the designated input stream. * * @param in the input stream to read from. * @throws IOException if an I/O related exception occurs during the process. diff --git a/java/util/logging/Logger.java b/java/util/logging/Logger.java index 29f19e440..46588e542 100644 --- a/java/util/logging/Logger.java +++ b/java/util/logging/Logger.java @@ -1209,7 +1209,7 @@ public class Logger /** * Reset and close handlers attached to this logger. This function is package - * private because it must only be avaiable to the LogManager. + * private because it must only be available to the LogManager. */ void resetLogger() { diff --git a/java/util/zip/ZipFile.java b/java/util/zip/ZipFile.java index fed32203c..d031f5329 100644 --- a/java/util/zip/ZipFile.java +++ b/java/util/zip/ZipFile.java @@ -49,8 +49,8 @@ import java.io.InputStream; import java.io.RandomAccessFile; import java.io.UnsupportedEncodingException; import java.util.Enumeration; -import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedHashMap; /** * This class represents a Zip archive. You can ask for the contained @@ -88,7 +88,7 @@ public class ZipFile implements ZipConstants private final RandomAccessFile raf; // The entries of this zip file when initialized and not yet closed. - private HashMap<String, ZipEntry> entries; + private LinkedHashMap<String, ZipEntry> entries; private boolean closed = false; @@ -250,7 +250,7 @@ public class ZipFile implements ZipConstants throw new EOFException(name); int centralOffset = inp.readLeInt(); - entries = new HashMap<String, ZipEntry> (count+count/2); + entries = new LinkedHashMap<String, ZipEntry> (count+count/2); inp.seek(centralOffset); for (int i = 0; i < count; i++) @@ -347,7 +347,7 @@ public class ZipFile implements ZipConstants * @exception IllegalStateException when the ZipFile has already been closed. * @exception IOException when the entries could not be read. */ - private HashMap<String, ZipEntry> getEntries() throws IOException + private LinkedHashMap<String, ZipEntry> getEntries() throws IOException { synchronized(raf) { @@ -375,7 +375,7 @@ public class ZipFile implements ZipConstants try { - HashMap<String, ZipEntry> entries = getEntries(); + LinkedHashMap<String, ZipEntry> entries = getEntries(); ZipEntry entry = entries.get(name); // If we didn't find it, maybe it's a directory. if (entry == null && !name.endsWith("/")) @@ -414,7 +414,7 @@ public class ZipFile implements ZipConstants { checkClosed(); - HashMap<String, ZipEntry> entries = getEntries(); + LinkedHashMap<String, ZipEntry> entries = getEntries(); String name = entry.getName(); ZipEntry zipEntry = entries.get(name); if (zipEntry == null) diff --git a/javax/imageio/stream/ImageInputStreamImpl.java b/javax/imageio/stream/ImageInputStreamImpl.java index c1a5dd404..71eec41a9 100644 --- a/javax/imageio/stream/ImageInputStreamImpl.java +++ b/javax/imageio/stream/ImageInputStreamImpl.java @@ -81,7 +81,8 @@ public abstract class ImageInputStreamImpl implements ImageInputStream protected void finalize() throws Throwable { - close(); + if (!closed) + close(); } public void flush() @@ -154,38 +155,43 @@ public abstract class ImageInputStreamImpl implements ImageInputStream } catch (IOException e) { - // Ignored. + throw new RuntimeException(e); } } public abstract int read() throws IOException; + public abstract int read(byte[] data, int offset, int len) + throws IOException; + public int read(byte[] data) throws IOException { return read(data, 0, data.length); } - public abstract int read(byte[] data, int offset, int len) - throws IOException; - public int readBit() throws IOException { checkClosed(); - // Calc new bit offset here, readByte resets it. + // Calculate new bit offset here as readByte clears it. int newOffset = (bitOffset + 1) & 0x7; + // Clears bitOffset. byte data = readByte(); - - if (bitOffset != 0) + + // If newOffset is 0 it means we just read the 8th bit in a byte + // and therefore we want to advance to the next byte. Otherwise + // we want to roll back the stream one byte so that future readBit + // calls read bits from the same current byte. + if (newOffset != 0) { - seek(getStreamPosition() - 1); - data = (byte) (data >> (8 - newOffset)); + seek(getStreamPosition() - 1); + data = (byte) (data >> (8 - newOffset)); } - + bitOffset = newOffset; return data & 0x1; } @@ -198,17 +204,13 @@ public abstract class ImageInputStreamImpl implements ImageInputStream if (numBits < 0 || numBits > 64) throw new IllegalArgumentException(); - if (numBits == 0) - return 0L; - long bits = 0L; - + for (int i = 0; i < numBits; i++) { bits <<= 1; bits |= readBit(); } - return bits; } @@ -216,12 +218,15 @@ public abstract class ImageInputStreamImpl implements ImageInputStream throws IOException { byte data = readByte(); + return data != 0; } public byte readByte() throws IOException { + checkClosed(); + int data = read(); if (data == -1) @@ -233,10 +238,7 @@ public abstract class ImageInputStreamImpl implements ImageInputStream public void readBytes(IIOByteBuffer buffer, int len) throws IOException { - int result = read(buffer.getData(), buffer.getOffset(), len); - - if (result == -1 || result < len) - throw new EOFException(); + readFullyPrivate(buffer.getData(), buffer.getOffset(), len); buffer.setLength(len); } @@ -250,13 +252,13 @@ public abstract class ImageInputStreamImpl implements ImageInputStream public double readDouble() throws IOException { - return (double) readLong(); + return Double.longBitsToDouble(readLong()); } public float readFloat() throws IOException { - return (float) readInt(); + return Float.intBitsToFloat(readInt()); } public void readFully(byte[] data) @@ -268,8 +270,7 @@ public abstract class ImageInputStreamImpl implements ImageInputStream public void readFully(byte[] data, int offset, int len) throws IOException { - for (int i = 0; i < len; ++i) - data[offset + i] = readByte(); + readFullyPrivate(data, offset, len); } public void readFully(char[] data, int offset, int len) @@ -317,23 +318,20 @@ public abstract class ImageInputStreamImpl implements ImageInputStream public int readInt() throws IOException { - int result = read(buffer, 0, 4); + readFullyPrivate(buffer, 0, 4); - if (result == -1) - throw new EOFException(); - if (getByteOrder() == ByteOrder.LITTLE_ENDIAN) - { - return ((buffer[0] & 0xff) - + (buffer[1] << 8) - + (buffer[2] << 16) - + (buffer[3] << 24)); - } + return (int) + (((int) (buffer[0] & 0xff) << 0) + | ((int) (buffer[1] & 0xff) << 8) + | ((int) (buffer[2] & 0xff) << 16) + | ((int) (buffer[3] & 0xff) << 24)); - return ((buffer[4] << 24) - + (buffer[3] << 16) - + (buffer[2] << 8) - + (buffer[1] & 0xff)); + return (int) + (((int) (buffer[0] & 0xff) << 24) + + ((int) (buffer[1] & 0xff) << 16) + + ((int) (buffer[2] & 0xff) << 8) + + ((int) (buffer[3] & 0xff) << 0)); } public String readLine() @@ -345,94 +343,101 @@ public abstract class ImageInputStreamImpl implements ImageInputStream boolean eol = false; StringBuffer buffer = new StringBuffer(); - while (!eol && (c = read()) != -1) + c = read(); + if (c == -1) + return null; + + while (!eol) { switch(c) { case '\r': - // Consume following \n' - long oldPosition = getStreamPosition(); - if (read() != '\n') - seek(oldPosition); + // Check for following '\n'. + long oldPosition = getStreamPosition(); + c = read(); + if (c == -1 || c == '\n') + eol = true; + else + { + seek(oldPosition); + eol = true; + } + continue; + case '\n': eol = true; - break; + continue; + default: buffer.append((char) c); break; } + c = read(); + if (c == -1) + eol = true; } - if (c == -1 && buffer.length() == 0) - return null; - return buffer.toString(); } public long readLong() throws IOException { - int result = read(buffer, 0, 8); + readFullyPrivate(buffer, 0, 8); - if (result == -1) - throw new EOFException(); - if (getByteOrder() == ByteOrder.LITTLE_ENDIAN) - { - return ((buffer[0] & 0xff) - + (((buffer[1] & 0xff)) << 8) - + (((buffer[2] & 0xff)) << 16) - + (((buffer[3] & 0xffL)) << 24) - + (((buffer[4] & 0xffL)) << 32) - + (((buffer[5] & 0xffL)) << 40) - + (((buffer[6] & 0xffL)) << 48) - + (((long) buffer[7]) << 56)); - } - - return ((((long) buffer[7]) << 56) - + ((buffer[6] & 0xffL) << 48) - + ((buffer[5] & 0xffL) << 40) - + ((buffer[4] & 0xffL) << 32) - + ((buffer[3] & 0xffL) << 24) - + ((buffer[2] & 0xff) << 16) - + ((buffer[1] & 0xff) << 8) - + (buffer[0] & 0xff)); + return (long) + (((long) (buffer[0] & 0xff) << 0) + | ((long) (buffer[1] & 0xff) << 8) + | ((long) (buffer[2] & 0xff) << 16) + | ((long) (buffer[3] & 0xff) << 24) + | ((long) (buffer[4] & 0xff) << 32) + | ((long) (buffer[5] & 0xff) << 40) + | ((long) (buffer[6] & 0xff) << 48) + | ((long) (buffer[7] & 0xff) << 56)); + + return (long) + (((long) (buffer[0] & 0xff) << 56) + | ((long) (buffer[1] & 0xff) << 48) + | ((long) (buffer[2] & 0xff) << 40) + | ((long) (buffer[3] & 0xff) << 32) + | ((long) (buffer[4] & 0xff) << 24) + | ((long) (buffer[5] & 0xff) << 16) + | ((long) (buffer[6] & 0xff) << 8) + | ((long) (buffer[7] & 0xff) << 0)); } public short readShort() throws IOException { - int result = read(buffer, 0, 2); + readFullyPrivate(buffer, 0, 2); - if (result == -1) - throw new EOFException(); - if (getByteOrder() == ByteOrder.LITTLE_ENDIAN) - { - return (short) ((buffer[0] & 0xff) - + (buffer[1] << 8)); - } + return (short) + (((short) (buffer[0] & 0xff) << 0) + | ((short) (buffer[1] & 0xff) << 8)); - return (short) ((buffer[0] << 8) - + (buffer[1] & 0xff)); + return (short) + (((short) (buffer[0] & 0xff) << 8) + | ((short) (buffer[1] & 0xff) << 0)); } public int readUnsignedByte() throws IOException { - return readByte() & 0xff; + return (int) readByte() & 0xff; } public long readUnsignedInt() throws IOException { - return readInt() & 0xffffffff; + return (long) readInt() & 0xffffffffL; } public int readUnsignedShort() throws IOException { - return readShort() & 0xffff; + return (int) readShort() & 0xffff; } public String readUTF() @@ -442,7 +447,8 @@ public abstract class ImageInputStreamImpl implements ImageInputStream String data; ByteOrder old = getByteOrder(); - setByteOrder(ByteOrder.BIG_ENDIAN); // Strings are always big endian. + // Strings are always big endian. + setByteOrder(ByteOrder.BIG_ENDIAN); try { @@ -483,7 +489,7 @@ public abstract class ImageInputStreamImpl implements ImageInputStream checkClosed(); if (bitOffset < 0 || bitOffset > 7) - throw new IllegalArgumentException(); + throw new IllegalArgumentException("bitOffset not between 0 and 7 inclusive"); this.bitOffset = bitOffset; } @@ -512,4 +518,23 @@ public abstract class ImageInputStreamImpl implements ImageInputStream bitOffset = 0; return num; } + + private void readFullyPrivate (byte[] buf, int offset, int len) throws IOException + { + checkClosed(); + + if (len < 0) + throw new IndexOutOfBoundsException("Negative length: " + len); + + while (len > 0) + { + // read will block until some data is available. + int numread = read (buf, offset, len); + if (numread < 0) + throw new EOFException (); + len -= numread; + offset += numread; + } + bitOffset = 0; + } } diff --git a/javax/imageio/stream/MemoryCacheImageInputStream.java b/javax/imageio/stream/MemoryCacheImageInputStream.java index 935408c9a..da8a958bb 100644 --- a/javax/imageio/stream/MemoryCacheImageInputStream.java +++ b/javax/imageio/stream/MemoryCacheImageInputStream.java @@ -38,10 +38,11 @@ exception statement from your version. */ package javax.imageio.stream; -import gnu.classpath.NotImplementedException; - +import java.io.BufferedInputStream; +import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; /** * @author Michael Koch (konqueror@gmx.de) @@ -49,10 +50,15 @@ import java.io.InputStream; public class MemoryCacheImageInputStream extends ImageInputStreamImpl { private InputStream stream; + private BufferedInputStream buffer; + + private int READLIMIT = 2048; public MemoryCacheImageInputStream(InputStream stream) { this.stream = stream; + buffer = new BufferedInputStream(stream); + buffer.mark(READLIMIT); } public void close() @@ -63,10 +69,13 @@ public class MemoryCacheImageInputStream extends ImageInputStreamImpl } public void flushBefore(long position) - throws IOException, NotImplementedException + throws IOException { - // FIXME: Implement me. - throw new Error("not implemented"); + long prevFlushedPosition = getFlushedPosition(); + super.flushBefore(position); + buffer.reset(); + buffer.skip(getFlushedPosition() - prevFlushedPosition); + buffer.mark(READLIMIT); } public boolean isCached() @@ -88,13 +97,33 @@ public class MemoryCacheImageInputStream extends ImageInputStreamImpl throws IOException { setBitOffset(0); - return stream.read(); + int retval = buffer.read(); + + if (retval != -1) + streamPos++; + + return retval; } public int read(byte[] data, int offset, int len) throws IOException { setBitOffset(0); - return stream.read(data, offset, len); + int retval = buffer.read(data, offset, len); + + if (retval != -1) + { + streamPos += retval; + } + + return retval; + } + + public void seek(long position) + throws IOException + { + super.seek(position); + buffer.reset(); + buffer.skip(position - getFlushedPosition()); } } diff --git a/javax/naming/spi/NamingManager.java b/javax/naming/spi/NamingManager.java index 9b1fae8ad..8fdc39f47 100644 --- a/javax/naming/spi/NamingManager.java +++ b/javax/naming/spi/NamingManager.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.naming.spi; +import gnu.classpath.VMStackWalker; + import java.util.Enumeration; import java.util.Hashtable; import java.util.StringTokenizer; @@ -52,8 +54,18 @@ import javax.naming.Reference; import javax.naming.Referenceable; import javax.naming.StringRefAddr; +/** + * Contains methods for creating context objects and objects referred to by + * location information. The location is specified in the scope of the + * certain naming or directory service. + */ public class NamingManager { + /** + * The environment property into which getContinuationContext() stores the + * value of the CannotProceedException parameter. The value of this field + * is <i>java.naming.spi.CannotProceedException<i>. + */ public static final String CPE = "java.naming.spi.CannotProceedException"; private static InitialContextFactoryBuilder icfb; @@ -66,11 +78,36 @@ public class NamingManager { } + /** + * Checks if the initial context factory builder has been set. + * + * @return true if the builder has been set + * + * @see #setInitialContextFactoryBuilder(InitialContextFactoryBuilder) + */ public static boolean hasInitialContextFactoryBuilder () { return icfb != null; } + /** + * Creates the initial context. If the initial object factory builder has + * been set with {@link #setObjectFactoryBuilder(ObjectFactoryBuilder)}, + * the work is delegated to this builder. Otherwise, the method searches + * for the property Context.INITIAL_CONTEXT_FACTORY first in the passed + * table and then in the system properties. The value of this property is + * uses as a class name to install the context factory. The corresponding + * class must exist, be public and have the public parameterless constructor. + * + * @param environment the properties, used to create the context. + * + * @return the created context + * + * @throws NoInitialContextException if the initial builder is not set, + * the property Context.INITIAL_CONTEXT_FACTORY is missing of the + * class, named by this property, cannot be instantiated. + * @throws NamingException if throws by the context factory + */ public static Context getInitialContext (Hashtable<?, ?> environment) throws NamingException { @@ -113,76 +150,191 @@ public class NamingManager return icf.getInitialContext (environment); } - static Context getURLContext (Object refInfo, - Name name, - Context nameCtx, - String scheme, - Hashtable<?, ?> environment) - throws NamingException + /** + * <p> + * Creates the URL context for the given URL scheme id. + * </p> + * <p> + * The class name of the factory that creates the context has the naming + * pattern scheme-idURLContextFactory. For instance, the factory for the "ftp" + * sheme should be named "ftpURLContextFactory". + * </p> + * <p> + * The Context.URL_PKG_PREFIXES environment property contains the + * colon-separated list of the possible package prefixes. The package name is + * constructed concatenating the package prefix with the scheme id. This + * property is searched in the passed <i>environment</i> parameter and later + * in the system properties. + * </p> + * <p> + * If the factory class cannot be found in the specified packages, system will + * try to use the default internal factory for the given scheme. + * </p> + * <p> + * After the factory is instantiated, its method + * {@link ObjectFactory#getObjectInstance(Object, Name, Context, Hashtable)} + * is called to create and return the object instance. + * + * @param refInfo passed to the factory + * @param name passed to the factory + * @param nameCtx passed to the factory + * @param scheme the url scheme that must be supported by the given context + * @param environment the properties for creating the factory and context (may + * be null) + * @return the created context + * @throws NamingException if thrown by the factory when creating the context. + */ + static Context getURLContext(Object refInfo, Name name, Context nameCtx, + String scheme, Hashtable<?,?> environment) + throws NamingException { - String prefixes = null; - if (environment != null) - prefixes = (String) environment.get (Context.URL_PKG_PREFIXES); - if (prefixes == null) - prefixes = System.getProperty (Context.URL_PKG_PREFIXES); - if (prefixes == null) + // Specified as the default in the docs. Unclear if this is + // right for us. + String defaultPrefix = "com.sun.jndi.url"; + + StringBuffer allPrefixes = new StringBuffer(); + + String prefixes; + if (environment != null) + { + prefixes = (String) environment.get(Context.URL_PKG_PREFIXES); + if (prefixes != null) + allPrefixes.append(prefixes); + } + + prefixes = System.getProperty(Context.URL_PKG_PREFIXES); + if (prefixes != null) { - // Specified as the default in the docs. Unclear if this is - // right for us. - prefixes = "com.sun.jndi.url"; + if (allPrefixes.length() > 0) + allPrefixes.append(':'); + allPrefixes.append(prefixes); } - scheme = scheme + "." + scheme + "URLContextFactory"; - - StringTokenizer tokens = new StringTokenizer (prefixes, ":"); - while (tokens.hasMoreTokens ()) - { - String aTry = tokens.nextToken (); - try - { - Class factoryClass = Class.forName (aTry + "." + scheme, - true, - Thread.currentThread().getContextClassLoader()); - ObjectFactory factory = - (ObjectFactory) factoryClass.newInstance (); - Object obj = factory.getObjectInstance (refInfo, name, - nameCtx, environment); - Context ctx = (Context) obj; - if (ctx != null) - return ctx; - } - catch (ClassNotFoundException _1) - { - // Ignore it. - } - catch (ClassCastException _2) - { - // This means that the class we found was not an - // ObjectFactory or that the factory returned something - // which was not a Context. - } - catch (InstantiationException _3) - { - // If we couldn't instantiate the factory we might get - // this. - } - catch (IllegalAccessException _4) - { - // Another possibility when instantiating. - } - catch (NamingException _5) - { - throw _5; - } - catch (Exception _6) - { - // Anything from getObjectInstance. - } - } + if (allPrefixes.length() > 0) + allPrefixes.append(':'); + allPrefixes.append(defaultPrefix); + scheme = scheme + "." + scheme + "URLContextFactory"; + + StringTokenizer tokens = new StringTokenizer(allPrefixes.toString(), ":"); + while (tokens.hasMoreTokens()) + { + String aTry = tokens.nextToken(); + try + { + String tryClass = aTry + "." + scheme; + Class factoryClass = forName(tryClass); + if (factoryClass != null) + { + ObjectFactory factory = (ObjectFactory) factoryClass.newInstance(); + Object obj = factory.getObjectInstance(refInfo, name, nameCtx, + environment); + Context ctx = (Context) obj; + if (ctx != null) + return ctx; + } + } + catch (ClassNotFoundException _1) + { + // Ignore it. + } + catch (ClassCastException _2) + { + // This means that the class we found was not an + // ObjectFactory or that the factory returned something + // which was not a Context. + } + catch (InstantiationException _3) + { + // If we couldn't instantiate the factory we might get + // this. + } + catch (IllegalAccessException _4) + { + // Another possibility when instantiating. + } + catch (NamingException _5) + { + throw _5; + } + catch (Exception _6) + { + // Anything from getObjectInstance. + } + } + return null; } + /** + * Load the class with the given name. This method tries to use the context + * class loader first. If this fails, it searches for the suitable class + * loader in the caller stack trace. This method is a central point where all + * requests to find a class by name are delegated. + */ + static Class forName(String className) + { + try + { + return Class.forName(className, true, + Thread.currentThread().getContextClassLoader()); + } + catch (ClassNotFoundException nex) + { + /** + * Returns the first user defined class loader on the call stack, or + * null when no non-null class loader was found. + */ + Class[] ctx = VMStackWalker.getClassContext(); + for (int i = 0; i < ctx.length; i++) + { + // Since we live in a class loaded by the bootstrap + // class loader, getClassLoader is safe to call without + // needing to be wrapped in a privileged action. + ClassLoader cl = ctx[i].getClassLoader(); + try + { + if (cl != null) + return Class.forName(className, true, cl); + } + catch (ClassNotFoundException nex2) + { + // Try next. + } + } + } + return null; + } + + + /** + * <p> + * Creates the URL context for the given URL scheme id. + * </p> + * <p> + * The class name of the factory that creates the context has the naming + * pattern scheme-idURLContextFactory. For instance, the factory for the + * "ftp" scheme should be named "ftpURLContextFactory". + * The Context.URL_PKG_PREFIXES environment property contains the + * colon-separated list of the possible package prefixes. The package name + * is constructed by concatenating the package prefix with the scheme id. + * </p> + * <p> + * If the factory class cannot be found in the specified packages, the + * system will try to use the default internal factory for the given scheme. + * </p> + * <p> + * After the factory is instantiated, its method + * {@link ObjectFactory#getObjectInstance(Object, Name, Context, Hashtable)} + * is called to create and return the object instance. + * + * @param scheme the url scheme that must be supported by the given context + * @param environment the properties for creating the factory and context + * (may be null) + * @return the created context + * @throws NamingException if thrown by the factory when creating the + * context. + */ public static Context getURLContext (String scheme, Hashtable<?, ?> environment) throws NamingException @@ -190,6 +342,17 @@ public class NamingManager return getURLContext (null, null, null, scheme, environment); } + /** + * Sets the initial object factory builder. + * + * @param builder the builder to set + * + * @throws SecurityException if the builder cannot be installed due + * security restrictions. + * @throws NamingException if the builder cannot be installed due other + * reasons + * @throws IllegalStateException if setting the builder repeatedly + */ public static void setObjectFactoryBuilder (ObjectFactoryBuilder builder) throws NamingException { @@ -198,7 +361,7 @@ public class NamingManager sm.checkSetFactory (); // Once the builder is installed it cannot be replaced. if (ofb != null) - throw new IllegalStateException ("builder already installed"); + throw new IllegalStateException ("object factory builder already installed"); if (builder != null) ofb = builder; } @@ -312,7 +475,21 @@ public class NamingManager return obj == null ? refInfo : obj; } - public static void setInitialContextFactoryBuilder (InitialContextFactoryBuilder builder) + /** + * Sets the initial context factory builder. + * + * @param builder the builder to set + * + * @throws SecurityException if the builder cannot be installed due + * security restrictions. + * @throws NamingException if the builder cannot be installed due other + * reasons + * @throws IllegalStateException if setting the builder repeatedly + * + * @see #hasInitialContextFactoryBuilder() + */ + public static void setInitialContextFactoryBuilder + (InitialContextFactoryBuilder builder) throws NamingException { SecurityManager sm = System.getSecurityManager (); @@ -320,11 +497,23 @@ public class NamingManager sm.checkSetFactory (); // Once the builder is installed it cannot be replaced. if (icfb != null) - throw new IllegalStateException ("builder already installed"); + throw new IllegalStateException ("ctx factory builder already installed"); if (builder != null) icfb = builder; } - + + /** + * Creates a context in which the context operation must be continued. + * This method is used by operations on names that span multiple namespaces. + * + * @param cpe the exception that triggered this continuation. This method + * obtains the environment ({@link CannotProceedException#getEnvironment()} + * and sets the environment property {@link #CPE} = cpe. + * + * @return a non null context for continuing the operation + * + * @throws NamingException if the naming problems have occured + */ public static Context getContinuationContext (CannotProceedException cpe) throws NamingException { diff --git a/javax/swing/AbstractButton.java b/javax/swing/AbstractButton.java index 348daece1..9b2b526f3 100644 --- a/javax/swing/AbstractButton.java +++ b/javax/swing/AbstractButton.java @@ -1,5 +1,5 @@ /* AbstractButton.java -- Provides basic button functionality. - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -274,7 +274,7 @@ public abstract class AbstractButton extends JComponent protected ChangeListener changeListener; /** - * The time in miliseconds in which clicks get coalesced into a single + * The time in milliseconds in which clicks get coalesced into a single * <code>ActionEvent</code>. */ long multiClickThreshhold; @@ -445,7 +445,7 @@ public abstract class AbstractButton extends JComponent * {@link AccessibleState#FOCUSED}, {@link AccessibleState#PRESSED} and * {@link AccessibleState#CHECKED}. * - * @return the curren state of this accessible object + * @return the current state of this accessible object */ public AccessibleStateSet getAccessibleStateSet() { @@ -651,8 +651,8 @@ public abstract class AbstractButton extends JComponent * Returns the minimum accessible value for the AccessibleAbstractButton, * which is <code>0</code>. * - * @return the maxinimum accessible value for the AccessibleAbstractButton, - * which is <code>1</code> + * @return the minimimum accessible value for the AccessibleAbstractButton, + * which is <code>0</code> */ public Number getMinimumAccessibleValue() { diff --git a/javax/swing/CellRendererPane.java b/javax/swing/CellRendererPane.java index b3d6f6a73..764a4c500 100644 --- a/javax/swing/CellRendererPane.java +++ b/javax/swing/CellRendererPane.java @@ -93,7 +93,7 @@ public class CellRendererPane extends Container implements Accessible */ public CellRendererPane() { - // Nothing to do here. + setVisible(false); } /** diff --git a/javax/swing/DefaultButtonModel.java b/javax/swing/DefaultButtonModel.java index 201ee2a8c..bc2662e65 100644 --- a/javax/swing/DefaultButtonModel.java +++ b/javax/swing/DefaultButtonModel.java @@ -1,5 +1,5 @@ /* DefaultButtonModel.java -- - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -63,7 +63,7 @@ import javax.swing.event.EventListenerList; * change to the "selected" property will trigger the firing of an ItemEvent * in addition to ChangeEvent. This is true whether the model is enabled or * not. One other state change is special: the transition from "enabled, - * armed and pressd" to "enabled, armed and not-pressed". This is considered + * armed and pressed" to "enabled, armed and not-pressed". This is considered * the "trailing edge" of a successful mouse click, and therefore fires an * ActionEvent in addition to a ChangeEvent. In all other respects this class * is just a container of boolean flags. @@ -371,7 +371,7 @@ public class DefaultButtonModel implements ButtonModel, Serializable if (e) stateMask = stateMask | ENABLED; else - stateMask = stateMask & (~ENABLED); + stateMask = stateMask & (~ENABLED) & (~ARMED) & (~PRESSED); // notify interested ChangeListeners fireStateChanged(); @@ -555,21 +555,21 @@ public class DefaultButtonModel implements ButtonModel, Serializable * one model in a given group can have their "selected" property be * <code>true</code> at a time. * - * @param g The new "group" property + * @param g The new "group" property (<code>null</code> permitted). + * + * @see #getGroup() */ public void setGroup(ButtonGroup g) { - if (group != g) - { - group = g; - fireStateChanged(); - } + group = g; } /** * Returns the current value of the model's "group" property. * * @return The value of the "group" property + * + * @see #setGroup(ButtonGroup) */ public ButtonGroup getGroup() { diff --git a/javax/swing/DefaultDesktopManager.java b/javax/swing/DefaultDesktopManager.java index 0304461ad..11f03a715 100644 --- a/javax/swing/DefaultDesktopManager.java +++ b/javax/swing/DefaultDesktopManager.java @@ -400,8 +400,8 @@ public class DefaultDesktopManager implements DesktopManager, Serializable dragCache.width, dragCache.height); pane = null; dragCache = null; + component.repaint(); } - component.repaint(); } /** @@ -463,8 +463,8 @@ public class DefaultDesktopManager implements DesktopManager, Serializable dragCache.width, dragCache.height); pane = null; dragCache = null; + component.repaint(); } - component.repaint(); } /** @@ -481,13 +481,6 @@ public class DefaultDesktopManager implements DesktopManager, Serializable int newWidth, int newHeight) { component.setBounds(newX, newY, newWidth, newHeight); - component.revalidate(); - - // If not null, I'd rather repaint the parent - if (component.getParent() != null) - component.getParent().repaint(); - else - component.repaint(); } /** diff --git a/javax/swing/JCheckBoxMenuItem.java b/javax/swing/JCheckBoxMenuItem.java index 815244259..3222d189f 100644 --- a/javax/swing/JCheckBoxMenuItem.java +++ b/javax/swing/JCheckBoxMenuItem.java @@ -1,5 +1,5 @@ /* JCheckBoxMenuItem.java -- - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -204,7 +204,7 @@ public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants, /** * This method overrides JComponent.requestFocus with an empty * implementation, since JCheckBoxMenuItems should not - * receve focus in general. + * receive focus in general. */ public void requestFocus() { @@ -212,16 +212,28 @@ public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants, } /** - * A string that describes this JCheckBoxMenuItem. Normally only used - * for debugging. + * Returns a string describing the attributes for the + * <code>JCheckBoxMenuItem</code> component, for use in debugging. The + * return value is guaranteed to be non-<code>null</code>, but the format + * of the string may vary between implementations. * - * @return A string describing this JCheckBoxMenuItem + * @return A string describing the attributes of the + * <code>JCheckBoxMenuItem</code>. */ protected String paramString() { - return "JCheckBoxMenuItem"; + // calling super seems to be sufficient to match the reference + // implementation here... + return super.paramString(); } + /** + * Returns the object that provides accessibility features for this + * <code>JCheckBoxMenuItem</code> component. + * + * @return The accessible context (an instance of + * {@link AccessibleJCheckBoxMenuItem}). + */ public AccessibleContext getAccessibleContext() { if (accessibleContext == null) @@ -231,20 +243,29 @@ public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants, } /** - * Accessibility support for <code>JCheckBoxMenuItem</code>. + * Provides the accessibility features for the <code>JCheckBoxMenuItem</code> + * component. + * + * @see JCheckBoxMenuItem#getAccessibleContext() */ protected class AccessibleJCheckBoxMenuItem extends AccessibleJMenuItem { private static final long serialVersionUID = 1079958073579370777L; /** - * Creates a new AccessibleJCheckBoxMenuItem object. + * Creates a new <code>AccessibleJCheckBoxMenuItem</code> instance. */ protected AccessibleJCheckBoxMenuItem() { // Nothing to do here. } + /** + * Returns the accessible role for the <code>JCheckBoxMenuItem</code> + * component. + * + * @return {@link AccessibleRole#CHECK_BOX}. + */ public AccessibleRole getAccessibleRole() { return AccessibleRole.CHECK_BOX; diff --git a/javax/swing/JComboBox.java b/javax/swing/JComboBox.java index 17bcf1f99..38776f17f 100644 --- a/javax/swing/JComboBox.java +++ b/javax/swing/JComboBox.java @@ -38,8 +38,6 @@ exception statement from your version. */ package javax.swing; -import gnu.classpath.NotImplementedException; - import java.awt.ItemSelectable; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -60,6 +58,8 @@ import javax.swing.event.ListDataListener; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import javax.swing.plaf.ComboBoxUI; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.ComboPopup; /** * A component that allows a user to select any item in its list and @@ -1246,34 +1246,102 @@ public class JComboBox extends JComponent implements ItemSelectable, // Nothing to do here. } + /** + * Returns the number of accessible children of this object. The + * implementation of AccessibleJComboBox delegates this call to the UI + * of the associated JComboBox. + * + * @return the number of accessible children of this object + * + * @see ComponentUI#getAccessibleChildrenCount(JComponent) + */ public int getAccessibleChildrenCount() - throws NotImplementedException { - return 0; + ComponentUI ui = getUI(); + int count; + if (ui != null) + count = ui.getAccessibleChildrenCount(JComboBox.this); + else + count = super.getAccessibleChildrenCount(); + return count; } - public Accessible getAccessibleChild(int value0) - throws NotImplementedException + /** + * Returns the number of accessible children of this object. The + * implementation of AccessibleJComboBox delegates this call to the UI + * of the associated JComboBox. + * + * @param index the index of the accessible child to fetch + * + * @return the number of accessible children of this object + * + * @see ComponentUI#getAccessibleChild(JComponent, int) + */ + public Accessible getAccessibleChild(int index) { - return null; + ComponentUI ui = getUI(); + Accessible child = null; + if (ui != null) + child = ui.getAccessibleChild(JComboBox.this, index); + else + child = super.getAccessibleChild(index); + return child; } + /** + * Returns the AccessibleSelection object associated with this object. + * AccessibleJComboBoxes handle their selection themselves, so this + * always returns <code>this</code>. + * + * @return the AccessibleSelection object associated with this object + */ public AccessibleSelection getAccessibleSelection() - throws NotImplementedException { - return null; + return this; } - public Accessible getAccessibleSelection(int value0) - throws NotImplementedException + /** + * Returns the accessible selection from this AccssibleJComboBox. + * + * @param index the index of the selected child to fetch + * + * @return the accessible selection from this AccssibleJComboBox + */ + public Accessible getAccessibleSelection(int index) { - return null; + // Get hold of the actual popup. + Accessible popup = getUI().getAccessibleChild(JComboBox.this, 0); + Accessible selected = null; + if (popup != null && popup instanceof ComboPopup) + { + ComboPopup cPopup = (ComboPopup) popup; + // Query the list for the currently selected child. + JList l = cPopup.getList(); + AccessibleContext listCtx = l.getAccessibleContext(); + if (listCtx != null) + { + AccessibleSelection s = listCtx.getAccessibleSelection(); + if (s != null) + { + selected = s.getAccessibleSelection(index); + } + } + } + return selected; } - public boolean isAccessibleChildSelected(int value0) - throws NotImplementedException + /** + * Returns <code>true</code> if the accessible child with the specified + * <code>index</code> is selected, <code>false</code> otherwise. + * + * @param index the index of the accessible child + * + * @return <code>true</code> if the accessible child with the specified + * <code>index</code> is selected, <code>false</code> otherwise + */ + public boolean isAccessibleChildSelected(int index) { - return false; + return getSelectedIndex() == index; } /** @@ -1286,58 +1354,121 @@ public class JComboBox extends JComponent implements ItemSelectable, return AccessibleRole.COMBO_BOX; } + /** + * Returns the accessible action associated to this accessible object. + * AccessibleJComboBox implements its own AccessibleAction, so this + * method returns <code>this</code>. + * + * @return the accessible action associated to this accessible object + */ public AccessibleAction getAccessibleAction() - throws NotImplementedException { - return null; + return this; } - public String getAccessibleActionDescription(int value0) - throws NotImplementedException + /** + * Returns the description of the specified action. AccessibleJComboBox + * implements 1 action (toggle the popup menu) and thus returns + * <code>UIManager.getString("ComboBox.togglePopupText")</code> + * + * @param actionIndex the index of the action for which to return the + * description + * + * @return the description of the specified action + */ + public String getAccessibleActionDescription(int actionIndex) { - return null; + return UIManager.getString("ComboBox.togglePopupText"); } + /** + * Returns the number of accessible actions that can be performed by + * this object. AccessibleJComboBox implement s one accessible action + * (toggle the popup menu), so this method always returns <code>1</code>. + * + * @return the number of accessible actions that can be performed by + * this object + */ public int getAccessibleActionCount() - throws NotImplementedException { - return 0; + return 1; } - public boolean doAccessibleAction(int value0) - throws NotImplementedException + /** + * Performs the accessible action with the specified index. + * AccessibleJComboBox has 1 accessible action + * (<code>actionIndex == 0</code>), which is to toggle the + * popup menu. All other action indices have no effect and return + * <code<>false</code>. + * + * @param actionIndex the index of the action to perform + * + * @return <code>true</code> if the action has been performed, + * <code>false</code> otherwise + */ + public boolean doAccessibleAction(int actionIndex) { - return false; + boolean actionPerformed = false; + if (actionIndex == 0) + { + setPopupVisible(! isPopupVisible()); + actionPerformed = true; + } + return actionPerformed; } + /** + * Returns the number of selected accessible children of this object. This + * returns <code>1</code> if the combobox has a selected entry, + * <code>0</code> otherwise. + * + * @return the number of selected accessible children of this object + */ public int getAccessibleSelectionCount() - throws NotImplementedException { - return 0; + Object sel = getSelectedItem(); + int count = 0; + if (sel != null) + count = 1; + return count; } - public void addAccessibleSelection(int value0) - throws NotImplementedException + /** + * Sets the current selection to the specified <code>index</code>. + * + * @param index the index to set as selection + */ + public void addAccessibleSelection(int index) { - // TODO: Implement this properly. + setSelectedIndex(index); } - public void removeAccessibleSelection(int value0) - throws NotImplementedException + /** + * Removes the specified index from the current selection. + * + * @param index the index to remove from the selection + */ + public void removeAccessibleSelection(int index) { - // TODO: Implement this properly. + if (getSelectedIndex() == index) + clearAccessibleSelection(); } + /** + * Clears the current selection. + */ public void clearAccessibleSelection() - throws NotImplementedException { - // TODO: Implement this properly. + setSelectedIndex(-1); } + /** + * Multiple selection is not supported by AccessibleJComboBox, so this + * does nothing. + */ public void selectAllAccessibleSelection() - throws NotImplementedException { - // TODO: Implement this properly. + // Nothing to do here. } } } diff --git a/javax/swing/JComponent.java b/javax/swing/JComponent.java index ba3712b88..dbbad5c21 100644 --- a/javax/swing/JComponent.java +++ b/javax/swing/JComponent.java @@ -760,13 +760,6 @@ public abstract class JComponent extends Container implements Serializable public static final int WHEN_IN_FOCUSED_WINDOW = 2; /** - * Indicates if this component is completely dirty or not. This is used - * by the RepaintManager's - * {@link RepaintManager#isCompletelyDirty(JComponent)} method. - */ - boolean isCompletelyDirty = false; - - /** * Indicates if the opaque property has been set by a client program or by * the UI. * @@ -1763,11 +1756,6 @@ public abstract class JComponent extends Container implements Serializable paintComponent(g2); paintBorder(g2); paintChildren(g2); - Rectangle clip = g2.getClipBounds(); - if (clip == null - || (clip.x == 0 && clip.y == 0 && clip.width == getWidth() - && clip.height == getHeight())) - RepaintManager.currentManager(this).markCompletelyClean(this); } } } @@ -3554,6 +3542,7 @@ public abstract class JComponent extends Container implements Serializable Rectangle currentClip = clip; Component found = this; Container parent = this; + while (parent != null && !(parent instanceof Window)) { Container newParent = parent.getParent(); @@ -3569,15 +3558,42 @@ public abstract class JComponent extends Container implements Serializable parent = newParent; continue; } - // If the parent is not optimizedDrawingEnabled, we must paint the - // parent. + + // If the parent is not optimizedDrawingEnabled, we must check if the + // parent or some neighbor overlaps the current clip. + + // This is the current clip converted to the parent's coordinate + // system. TODO: We can do this more efficiently by succesively + // cumulating the parent-child translations. Rectangle target = SwingUtilities.convertRectangle(found, currentClip, newParent); - found = newParent; - currentClip = target; + + // We have an overlap if either: + // - The new parent itself doesn't completely cover the clip + // (this can be the case with viewports). + // - If some higher-level (than the current) children of the new parent + // intersect the target rectangle. + Rectangle parentRect = SwingUtilities.getLocalBounds(newParent); + boolean haveOverlap = + ! SwingUtilities.isRectangleContainingRectangle(parentRect, target); + if (! haveOverlap) + { + Component[] children = newParent.getComponents(); + for (int i = 0; children[i] != parent && !haveOverlap; i++) + { + Rectangle childRect = children[i].getBounds(); + haveOverlap = target.intersects(childRect); + } + } + if (haveOverlap) + { + found = newParent; + currentClip = target; + } parent = newParent; } + //System.err.println("overlapfree parent: " + found); return found; } diff --git a/javax/swing/JFileChooser.java b/javax/swing/JFileChooser.java index 7da3a132d..64f9bd0f4 100644 --- a/javax/swing/JFileChooser.java +++ b/javax/swing/JFileChooser.java @@ -1,5 +1,5 @@ /* JFileChooser.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,10 +37,9 @@ exception statement from your version. */ package javax.swing; -import gnu.classpath.NotImplementedException; - import java.awt.Component; import java.awt.Frame; +import java.awt.GraphicsEnvironment; import java.awt.HeadlessException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -389,6 +388,13 @@ public class JFileChooser extends JComponent implements Accessible * @see #setSelectedFile(File) */ private File selectedFile; + + /** + * The drag enabled property. + * @see #setDragEnabled(boolean) + * @see #getDragEnabled() + */ + private boolean dragEnabled; /** * Creates a new <code>JFileChooser</code> object. @@ -487,26 +493,31 @@ public class JFileChooser extends JComponent implements Accessible } /** - * DOCUMENT ME! - * - * @param b DOCUMENT ME! + * Sets the dragEnabled property, this disables/enables automatic drag + * handling (drag and drop) on this component. The default value of the + * dragEnabled property is false. + * + * Some look and feels might not support automatic drag and drop; they + * will ignore this property. + * + * @param b - the new dragEnabled value */ public void setDragEnabled(boolean b) - throws NotImplementedException { - // FIXME: Implement + if (b && GraphicsEnvironment.isHeadless()) + throw new HeadlessException(); + + dragEnabled = b; } /** - * DOCUMENT ME! + * Returns true if dragging is enabled. * - * @return DOCUMENT ME! + * @return true if dragging is enabled. */ public boolean getDragEnabled() - throws NotImplementedException { - // FIXME: Implement - return false; + return dragEnabled; } /** @@ -1514,19 +1525,60 @@ public class JFileChooser extends JComponent implements Accessible } /** - * DOCUMENT ME! + * Returns a string describing the attributes for the + * <code>JFileChooser</code> component, for use in debugging. The return + * value is guaranteed to be non-<code>null</code>, but the format of the + * string may vary between implementations. * - * @return DOCUMENT ME! + * @return A string describing the attributes of the + * <code>JFileChooser</code>. */ protected String paramString() { - return "JFileChooser"; + StringBuffer sb = new StringBuffer(super.paramString()); + sb.append(",approveButtonText="); + if (approveButtonText != null) + sb.append(approveButtonText); + sb.append(",currentDirectory="); + if (currentDir != null) + sb.append(currentDir); + sb.append(",dialogTitle="); + if (dialogTitle != null) + sb.append(dialogTitle); + sb.append(",dialogType="); + if (dialogType == OPEN_DIALOG) + sb.append("OPEN_DIALOG"); + if (dialogType == SAVE_DIALOG) + sb.append("SAVE_DIALOG"); + if (dialogType == CUSTOM_DIALOG) + sb.append("CUSTOM_DIALOG"); + sb.append(",fileSelectionMode="); + if (fileSelectionMode == FILES_ONLY) + sb.append("FILES_ONLY"); + if (fileSelectionMode == DIRECTORIES_ONLY) + sb.append("DIRECTORIES_ONLY"); + if (fileSelectionMode == FILES_AND_DIRECTORIES) + sb.append("FILES_AND_DIRECTORIES"); + sb.append(",returnValue="); + if (retval == APPROVE_OPTION) + sb.append("APPROVE_OPTION"); + if (retval == CANCEL_OPTION) + sb.append("CANCEL_OPTION"); + if (retval == ERROR_OPTION) + sb.append("ERROR_OPTION"); + sb.append(",selectedFile="); + if (selectedFile != null) + sb.append(selectedFile); + sb.append(",useFileHiding=").append(fileHiding); + return sb.toString(); } /** - * Returns the accessible context. + * Returns the object that provides accessibility features for this + * <code>JFileChooser</code> component. * - * @return The accessible context. + * @return The accessible context (an instance of + * {@link AccessibleJFileChooser}). */ public AccessibleContext getAccessibleContext() { @@ -1536,16 +1588,26 @@ public class JFileChooser extends JComponent implements Accessible } /** - * Accessibility support for JFileChooser + * Provides the accessibility features for the <code>JFileChooser</code> + * component. */ protected class AccessibleJFileChooser extends JComponent.AccessibleJComponent { + /** + * Creates a new instance of <code>AccessibleJFileChooser</code>. + */ protected AccessibleJFileChooser() { // Nothing to do here. } + /** + * Returns the accessible role for the <code>JFileChooser</code> + * component. + * + * @return {@link AccessibleRole#FILE_CHOOSER}. + */ public AccessibleRole getAccessibleRole() { return AccessibleRole.FILE_CHOOSER; diff --git a/javax/swing/JFrame.java b/javax/swing/JFrame.java index d25120560..11b9c1fd3 100644 --- a/javax/swing/JFrame.java +++ b/javax/swing/JFrame.java @@ -1,5 +1,5 @@ /* JFrame.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -86,6 +86,8 @@ public class JFrame extends Frame /** * A flag for {@link #setDefaultCloseOperation(int)}, indicating that the * application should be exited, when this <code>JFrame</code> is closed. + * Note that in version 1.4, the equivalent constant has been added to + * {@link WindowConstants}. * * @since 1.3 */ @@ -93,7 +95,7 @@ public class JFrame extends Frame private static final long serialVersionUID = -3362141868504252139L; private static boolean defaultLookAndFeelDecorated; - private int close_action = HIDE_ON_CLOSE; + private int closeAction = HIDE_ON_CLOSE; protected AccessibleContext accessibleContext; protected JRootPane rootPane; @@ -102,12 +104,20 @@ public class JFrame extends Frame */ protected boolean rootPaneCheckingEnabled = false; + /** + * Creates a new frame with an empty string for the title. + */ public JFrame() { - super("JFrame"); + super(""); frameInit(); } + /** + * Creates a new <code>JFrame</code> with the specified title. + * + * @param title the frame title (<code>null</code> permitted). + */ public JFrame(String title) { super(title); @@ -289,6 +299,12 @@ public class JFrame extends Frame return defaultLookAndFeelDecorated; } + /** + * Returns the object that provides accessibility features for this + * <code>JFrame</code>. + * + * @return The accessible context (an instance of {@link AccessibleJFrame}). + */ public AccessibleContext getAccessibleContext() { if (accessibleContext == null) @@ -296,14 +312,39 @@ public class JFrame extends Frame return accessibleContext; } + /** + * Returns a code for the default operation when the frame is closed. The + * default value is {@link WindowConstants#HIDE_ON_CLOSE}. + * + * @return One of: {@link WindowConstants#DO_NOTHING_ON_CLOSE}, + * {@link WindowConstants#HIDE_ON_CLOSE}, + * {@link WindowConstants#DISPOSE_ON_CLOSE}, {@link #EXIT_ON_CLOSE}. + * + * @see #setDefaultCloseOperation(int) + */ public int getDefaultCloseOperation() { - return close_action; + return closeAction; } + /** + * Returns a string describing the attributes for the <code>JFrame</code>, + * for use in debugging. The return value is guaranteed to be + * non-<code>null</code>, but the format may vary between implementations. + * + * @return A string describing the attributes of the <code>JFrame</code>. + */ protected String paramString() { - return "JFrame"; + StringBuffer sb = new StringBuffer(super.paramString()); + sb.append(",defaultCloseOperation="); + sb.append(SwingUtilities.convertWindowConstantToString( + getDefaultCloseOperation())); + sb.append(",rootPane="); + if (rootPane != null) + sb.append(rootPane); + sb.append(",rootPaneCheckingEnabled=").append(rootPaneCheckingEnabled); + return sb.toString(); } protected void processWindowEvent(WindowEvent e) @@ -313,7 +354,7 @@ public class JFrame extends Frame { case WindowEvent.WINDOW_CLOSING: { - switch (close_action) + switch (closeAction) { case EXIT_ON_CLOSE: { @@ -346,17 +387,22 @@ public class JFrame extends Frame } /** - * Defines what happens when this frame is closed. Can be one off - * <code>EXIT_ON_CLOSE</code>, - * <code>DISPOSE_ON_CLOSE</code>, - * <code>HIDE_ON_CLOSE</code> or - * <code>DO_NOTHING_ON_CLOSE</code>. - * The default is <code>HIDE_ON_CLOSE</code>. - * When <code>EXIT_ON_CLOSE</code> is specified this method calls + * Sets the default operation that is performed when this frame is closed. + * The default is <code>HIDE_ON_CLOSE</code>. When + * <code>EXIT_ON_CLOSE</code> is specified this method calls * <code>SecurityManager.checkExit(0)</code> which might throw a - * <code>SecurityException</code>. When the specified operation is - * not one of the above a <code>IllegalArgumentException</code> is - * thrown. + * <code>SecurityException</code>. + * + * @param operation a code for the operation (one of: + * {@link WindowConstants#DO_NOTHING_ON_CLOSE}, + * {@link WindowConstants#HIDE_ON_CLOSE}, + * {@link WindowConstants#DISPOSE_ON_CLOSE} and + * {@link WindowConstants#EXIT_ON_CLOSE}). + * + * @throws IllegalArgumentException if <code>operation</code> is not one of + * the specified codes. + * + * @see #getDefaultCloseOperation() */ public void setDefaultCloseOperation(int operation) { @@ -366,8 +412,9 @@ public class JFrame extends Frame if (operation != EXIT_ON_CLOSE && operation != DISPOSE_ON_CLOSE && operation != HIDE_ON_CLOSE && operation != DO_NOTHING_ON_CLOSE) - throw new IllegalArgumentException("defaultCloseOperation must be EXIT_ON_CLOSE, HIDE_ON_CLOSE, DISPOSE_ON_CLOSE, or DO_NOTHING_ON_CLOSE"); + throw new IllegalArgumentException("operation must be EXIT_ON_CLOSE, " + + "HIDE_ON_CLOSE, DISPOSE_ON_CLOSE, or DO_NOTHING_ON_CLOSE"); - close_action = operation; + closeAction = operation; } } diff --git a/javax/swing/JLabel.java b/javax/swing/JLabel.java index a993fb8f3..a2dbb3251 100644 --- a/javax/swing/JLabel.java +++ b/javax/swing/JLabel.java @@ -1,5 +1,5 @@ /* JLabel.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -297,7 +297,6 @@ public class JLabel extends JComponent implements Accessible, SwingConstants } } - /** DOCUMENT ME! */ private static final long serialVersionUID = 5496508283662221534L; static final String LABEL_PROPERTY = "labeledBy"; @@ -452,14 +451,42 @@ public class JLabel extends JComponent implements Accessible, SwingConstants } /** - * This method is used primarily for debugging purposes and returns a string - * that can be used to represent this label. + * Returns a string describing the attributes for the <code>JLabel</code> + * component, for use in debugging. The return value is guaranteed to be + * non-<code>null</code>, but the format of the string may vary between + * implementations. * - * @return A string to represent this label. + * @return A string describing the attributes of the <code>JLabel</code>. */ protected String paramString() { - return super.paramString(); + StringBuffer sb = new StringBuffer(super.paramString()); + sb.append(",defaultIcon="); + if (icon != null) + sb.append(icon); + sb.append(",disabledIcon="); + if (disabledIcon != null) + sb.append(disabledIcon); + sb.append(",horizontalAlignment="); + sb.append(SwingUtilities.convertHorizontalAlignmentCodeToString( + horizontalAlignment)); + sb.append(",horizontalTextPosition="); + sb.append(SwingUtilities.convertHorizontalAlignmentCodeToString( + horizontalTextPosition)); + sb.append(",iconTextGap=").append(iconTextGap); + sb.append(",labelFor="); + if (labelFor != null) + sb.append(labelFor); + sb.append(",text="); + if (text != null) + sb.append(text); + sb.append(",verticalAlignment="); + sb.append(SwingUtilities.convertVerticalAlignmentCodeToString( + verticalAlignment)); + sb.append(",verticalTextPosition="); + sb.append(SwingUtilities.convertVerticalAlignmentCodeToString( + verticalTextPosition)); + return sb.toString(); } /** @@ -902,9 +929,10 @@ public class JLabel extends JComponent implements Accessible, SwingConstants } /** - * DOCUMENT ME! + * Returns the object that provides accessibility features for this + * <code>JLabel</code> component. * - * @return The accessible context. + * @return The accessible context (an instance of {@link AccessibleJLabel}). */ public AccessibleContext getAccessibleContext() { diff --git a/javax/swing/JList.java b/javax/swing/JList.java index 13ca094bb..1710541f4 100644 --- a/javax/swing/JList.java +++ b/javax/swing/JList.java @@ -1475,19 +1475,18 @@ public class JList extends JComponent implements Accessible, Scrollable } /** - * Returns all the values in the list's {@link #model} property which - * are selected, according to the list's {@link #selectionModel} property. - * + * Returns all the values in the list's {@link #model} property which are + * selected, according to the list's {@link #selectionModel} property. + * * @return An array containing all the selected values - * * @see #setSelectedValue */ public Object[] getSelectedValues() { - int [] idx = getSelectedIndices(); - Object [] v = new Object[idx.length]; + int[] idx = getSelectedIndices(); + Object[] v = new Object[idx.length]; for (int i = 0; i < idx.length; ++i) - v[i] = getModel().getElementAt(i); + v[i] = getModel().getElementAt(idx[i]); return v; } diff --git a/javax/swing/JMenu.java b/javax/swing/JMenu.java index 37ed14854..02cb20eab 100644 --- a/javax/swing/JMenu.java +++ b/javax/swing/JMenu.java @@ -38,8 +38,6 @@ exception statement from your version. */ package javax.swing; -import gnu.classpath.NotImplementedException; - import java.awt.Component; import java.awt.Point; import java.awt.event.KeyEvent; @@ -48,6 +46,7 @@ import java.awt.event.WindowEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.Serializable; +import java.util.ArrayList; import java.util.EventListener; import javax.accessibility.Accessible; @@ -811,7 +810,9 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement return accessibleContext; } - // FIXME: This inner class is a complete stub and needs to be implemented. + /** + * Implements support for assisitive technologies for <code>JMenu</code>. + */ protected class AccessibleJMenu extends AccessibleJMenuItem implements AccessibleSelection { @@ -822,69 +823,245 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement // Nothing to do here. } + /** + * Returns the number of accessible children of this object. + * + * @return the number of accessible children of this object + */ public int getAccessibleChildrenCount() - throws NotImplementedException { - return 0; + Component[] children = getMenuComponents(); + int count = 0; + for (int i = 0; i < children.length; i++) + { + if (children[i] instanceof Accessible) + count++; + } + return count; } - public Accessible getAccessibleChild(int value0) - throws NotImplementedException + /** + * Returns the accessible child with the specified <code>index</code>. + * + * @param index the index of the child to fetch + * + * @return the accessible child with the specified <code>index</code> + */ + public Accessible getAccessibleChild(int index) { - return null; + Component[] children = getMenuComponents(); + int count = 0; + Accessible found = null; + for (int i = 0; i < children.length; i++) + { + if (children[i] instanceof Accessible) + { + if (count == index) + { + found = (Accessible) children[i]; + break; + } + count++; + } + } + return found; } + /** + * Returns the accessible selection of this object. AccessibleJMenus handle + * their selection themselves, so we always return <code>this</code> here. + * + * @return the accessible selection of this object + */ public AccessibleSelection getAccessibleSelection() - throws NotImplementedException { - return null; + return this; } - public Accessible getAccessibleSelection(int value0) - throws NotImplementedException + /** + * Returns the selected accessible child with the specified + * <code>index</code>. + * + * @param index the index of the accessible selected child to return + * + * @return the selected accessible child with the specified + * <code>index</code> + */ + public Accessible getAccessibleSelection(int index) { - return null; + Accessible selected = null; + // Only one item can be selected, which must therefore have index == 0. + if (index == 0) + { + MenuSelectionManager msm = MenuSelectionManager.defaultManager(); + MenuElement[] me = msm.getSelectedPath(); + if (me != null) + { + for (int i = 0; i < me.length; i++) + { + if (me[i] == JMenu.this) + { + // This JMenu is selected, find and return the next + // JMenuItem in the path. + do + { + if (me[i] instanceof Accessible) + { + selected = (Accessible) me[i]; + break; + } + i++; + } while (i < me.length); + } + if (selected != null) + break; + } + } + } + return selected; } - public boolean isAccessibleChildSelected(int value0) - throws NotImplementedException + /** + * Returns <code>true</code> if the accessible child with the specified + * index is selected, <code>false</code> otherwise. + * + * @param index the index of the accessible child to check + * + * @return <code>true</code> if the accessible child with the specified + * index is selected, <code>false</code> otherwise + */ + public boolean isAccessibleChildSelected(int index) { - return false; + boolean selected = false; + MenuSelectionManager msm = MenuSelectionManager.defaultManager(); + MenuElement[] me = msm.getSelectedPath(); + if (me != null) + { + Accessible toBeFound = getAccessibleChild(index); + for (int i = 0; i < me.length; i++) + { + if (me[i] == toBeFound) + { + selected = true; + break; + } + } + } + return selected; } + /** + * Returns the accessible role of this object, which is + * {@link AccessibleRole#MENU} for the AccessibleJMenu. + * + * @return the accessible role of this object + */ public AccessibleRole getAccessibleRole() { return AccessibleRole.MENU; } + /** + * Returns the number of selected accessible children. This will be + * <code>0</code> if no item is selected, or <code>1</code> if an item + * is selected. AccessibleJMenu can have maximum 1 selected item. + * + * @return the number of selected accessible children + */ public int getAccessibleSelectionCount() - throws NotImplementedException { - return 0; + int count = 0; + MenuSelectionManager msm = MenuSelectionManager.defaultManager(); + MenuElement[] me = msm.getSelectedPath(); + if (me != null) + { + for (int i = 0; i < me.length; i++) + { + if (me[i] == JMenu.this) + { + if (i + 1 < me.length) + { + count = 1; + break; + } + } + } + } + return count; } - public void addAccessibleSelection(int value0) - throws NotImplementedException + /** + * Selects the accessible child with the specified index. + * + * @param index the index of the accessible child to select + */ + public void addAccessibleSelection(int index) { - // TODO: Implement this properly. + Accessible child = getAccessibleChild(index); + if (child != null && child instanceof JMenuItem) + { + JMenuItem mi = (JMenuItem) child; + MenuSelectionManager msm = MenuSelectionManager.defaultManager(); + msm.setSelectedPath(createPath(JMenu.this)); + } } - public void removeAccessibleSelection(int value0) - throws NotImplementedException + /** + * Removes the item with the specified index from the selection. + * + * @param index the index of the selected item to remove from the selection + */ + public void removeAccessibleSelection(int index) { - // TODO: Implement this properly. + Accessible child = getAccessibleChild(index); + if (child != null) + { + MenuSelectionManager msm = MenuSelectionManager.defaultManager(); + MenuElement[] oldSelection = msm.getSelectedPath(); + for (int i = 0; i < oldSelection.length; i++) + { + if (oldSelection[i] == child) + { + // Found the specified child in the selection. Remove it + // from the selection. + MenuElement[] newSel = new MenuElement[i - 1]; + System.arraycopy(oldSelection, 0, newSel, 0, i - 1); + msm.setSelectedPath(newSel); + break; + } + } + } } + /** + * Removes all possibly selected accessible children of this object from + * the selection. + */ public void clearAccessibleSelection() - throws NotImplementedException { - // TODO: Implement this properly. + MenuSelectionManager msm = MenuSelectionManager.defaultManager(); + MenuElement[] oldSelection = msm.getSelectedPath(); + for (int i = 0; i < oldSelection.length; i++) + { + if (oldSelection[i] == JMenu.this) + { + // Found this menu in the selection. Remove all children from + // the selection. + MenuElement[] newSel = new MenuElement[i]; + System.arraycopy(oldSelection, 0, newSel, 0, i); + msm.setSelectedPath(newSel); + break; + } + } } + /** + * AccessibleJMenu don't support multiple selection, so this method + * does nothing. + */ public void selectAllAccessibleSelection() - throws NotImplementedException { - // TODO: Implement this properly. + // Nothing to do here. } } @@ -939,4 +1116,44 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement } } + /** + * Creates an array to be feeded as argument to + * {@link MenuSelectionManager#setSelectedPath(MenuElement[])} for the + * specified element. This has the effect of selecting the specified element + * and all its parents. + * + * @param leaf the leaf element for which to create the selected path + * + * @return the selected path array + */ + MenuElement[] createPath(JMenu leaf) + { + ArrayList path = new ArrayList(); + MenuElement[] array = null; + Component current = leaf.getPopupMenu(); + while (true) + { + if (current instanceof JPopupMenu) + { + JPopupMenu popupMenu = (JPopupMenu) current; + path.add(0, popupMenu); + current = popupMenu.getInvoker(); + } + else if (current instanceof JMenu) + { + JMenu menu = (JMenu) current; + path.add(0, menu); + current = menu.getParent(); + } + else if (current instanceof JMenuBar) + { + JMenuBar menuBar = (JMenuBar) current; + path.add(0, menuBar); + array = new MenuElement[path.size()]; + array = (MenuElement[]) path.toArray(array); + break; + } + } + return array; + } } diff --git a/javax/swing/JMenuItem.java b/javax/swing/JMenuItem.java index 272c1cfe6..f04008bcd 100644 --- a/javax/swing/JMenuItem.java +++ b/javax/swing/JMenuItem.java @@ -673,7 +673,7 @@ public class JMenuItem extends AbstractButton implements Accessible, } /** - * Returns a string describing the attributes for the <code>JToolTip</code> + * Returns a string describing the attributes for the <code>JMenuItem</code> * component, for use in debugging. The return value is guaranteed to be * non-<code>null</code>, but the format of the string may vary between * implementations. diff --git a/javax/swing/JOptionPane.java b/javax/swing/JOptionPane.java index 0bef12b61..f94905538 100644 --- a/javax/swing/JOptionPane.java +++ b/javax/swing/JOptionPane.java @@ -1,5 +1,5 @@ /* JOptionPane.java - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,14 +38,20 @@ exception statement from your version. */ package javax.swing; +import java.awt.AWTEvent; +import java.awt.ActiveEvent; import java.awt.Component; +import java.awt.Container; +import java.awt.EventQueue; import java.awt.Frame; +import java.awt.MenuComponent; +import java.awt.Toolkit; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseMotionAdapter; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; -import javax.swing.event.InternalFrameAdapter; -import javax.swing.event.InternalFrameEvent; import javax.swing.plaf.OptionPaneUI; /** @@ -57,17 +63,15 @@ import javax.swing.plaf.OptionPaneUI; public class JOptionPane extends JComponent implements Accessible { /** - * DOCUMENT ME! + * Provides the accessibility features for the <code>JOptionPane</code> + * component. */ - // FIXME: This inner class is a complete stub and needs to be implemented - // properly. protected class AccessibleJOptionPane extends JComponent.AccessibleJComponent { - /** DOCUMENT ME! */ private static final long serialVersionUID = 686071432213084821L; /** - * Creates a new AccessibleJOptionPane object. + * Creates a new <code>AccessibleJOptionPane</code> instance. */ protected AccessibleJOptionPane() { @@ -86,7 +90,6 @@ public class JOptionPane extends JComponent implements Accessible } } - /** DOCUMENT ME! */ private static final long serialVersionUID = 5231143276678566796L; /** The value returned when cancel option is selected. */ @@ -431,9 +434,11 @@ public class JOptionPane extends JComponent implements Accessible } /** - * DOCUMENT ME! + * Returns the object that provides accessibility features for this + * <code>JOptionPane</code> component. * - * @return DOCUMENT ME! + * @return The accessible context (an instance of + * {@link AccessibleJOptionPane}). */ public AccessibleContext getAccessibleContext() { @@ -1529,31 +1534,64 @@ public class JOptionPane extends JComponent implements Accessible */ private static void startModal(JInternalFrame f) { - synchronized (f) - { - final JInternalFrame tmp = f; - tmp.toFront(); - - f.addInternalFrameListener(new InternalFrameAdapter() - { - public void internalFrameClosed(InternalFrameEvent e) - { - synchronized (tmp) - { - tmp.removeInternalFrameListener(this); - tmp.notifyAll(); - } - } - }); - try - { - while (! f.isClosed()) - f.wait(); - } - catch (InterruptedException ignored) - { - // Ignore this Exception. - } - } + // We need to add an additional glasspane-like component directly + // below the frame, which intercepts all mouse events that are not + // directed at the frame itself. + JPanel modalInterceptor = new JPanel(); + modalInterceptor.setOpaque(false); + JLayeredPane lp = JLayeredPane.getLayeredPaneAbove(f); + lp.setLayer(modalInterceptor, JLayeredPane.MODAL_LAYER.intValue()); + modalInterceptor.setBounds(0, 0, lp.getWidth(), lp.getHeight()); + modalInterceptor.addMouseListener(new MouseAdapter(){}); + modalInterceptor.addMouseMotionListener(new MouseMotionAdapter(){}); + lp.add(modalInterceptor); + f.toFront(); + + // We need to explicitly dispatch events when we are blocking the event + // dispatch thread. + EventQueue queue = Toolkit.getDefaultToolkit().getSystemEventQueue(); + try + { + while (! f.isClosed()) + { + if (EventQueue.isDispatchThread()) + { + // The getNextEventMethod() issues wait() when no + // event is available, so we don't need do explicitly wait(). + AWTEvent ev = queue.getNextEvent(); + // This mimics EventQueue.dispatchEvent(). We can't use + // EventQueue.dispatchEvent() directly, because it is + // protected, unfortunately. + if (ev instanceof ActiveEvent) + ((ActiveEvent) ev).dispatch(); + else if (ev.getSource() instanceof Component) + ((Component) ev.getSource()).dispatchEvent(ev); + else if (ev.getSource() instanceof MenuComponent) + ((MenuComponent) ev.getSource()).dispatchEvent(ev); + // Other events are ignored as per spec in + // EventQueue.dispatchEvent + } + else + { + // Give other threads a chance to become active. + Thread.yield(); + } + } + } + catch (InterruptedException ex) + { + // If we get interrupted, then leave the modal state. + } + finally + { + // Clean up the modal interceptor. + lp.remove(modalInterceptor); + + // Remove the internal frame from its parent, so it is no longer + // lurking around and clogging memory. + Container parent = f.getParent(); + if (parent != null) + parent.remove(f); + } } } diff --git a/javax/swing/JPopupMenu.java b/javax/swing/JPopupMenu.java index a54bd777f..c7890ea0e 100644 --- a/javax/swing/JPopupMenu.java +++ b/javax/swing/JPopupMenu.java @@ -52,6 +52,7 @@ import java.util.EventListener; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; +import javax.swing.event.MenuKeyListener; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import javax.swing.plaf.PopupMenuUI; @@ -410,6 +411,36 @@ public class JPopupMenu extends JComponent implements Accessible, MenuElement } /** + * Adds a MenuKeyListener to the popup. + * + * @param l - the listener to add. + */ + public void addMenuKeyListener(MenuKeyListener l) + { + listenerList.add(MenuKeyListener.class, l); + } + + /** + * Removes a MenuKeyListener from the popup. + * + * @param l - the listener to remove. + */ + public void removeMenuKeyListener(MenuKeyListener l) + { + listenerList.remove(MenuKeyListener.class, l); + } + + /** + * Returns array of getMenuKeyListeners that are listening to JPopupMenu. + * + * @return array of getMenuKeyListeners that are listening to JPopupMenu + */ + public MenuKeyListener[] getMenuKeyListeners() + { + return ((MenuKeyListener[]) listenerList.getListeners(MenuKeyListener.class)); + } + + /** * Adds popupMenuListener to listen for PopupMenuEvents fired * by the JPopupMenu * diff --git a/javax/swing/JProgressBar.java b/javax/swing/JProgressBar.java index db936f64a..ed2d0088d 100644 --- a/javax/swing/JProgressBar.java +++ b/javax/swing/JProgressBar.java @@ -53,15 +53,14 @@ import javax.swing.event.ChangeListener; import javax.swing.plaf.ProgressBarUI; /** - * The ProgressBar is a widget that displays in two modes. In - * determinate mode, it displays fills a percentage of its bar - * based on its current value. In indeterminate mode, it creates - * box and bounces it between its bounds. - * + * A component that displays a visual indicator of the progress of a task. The + * component has two modes: determinate and indeterminate. In determinate mode, + * the <code>JProgressBar</code> fills a percentage of its bar based on its + * current value. In indeterminate mode, it creates box and bounces it between + * its bounds. * <p> - * JProgressBars have the following properties: + * This component has the following properties: * </p> - * * <table> * <tr><th> Property </th><th> Stored in </th><th> Bound? </th></tr> * <tr><td> borderPainted </td><td> progressBar </td><td> yes </td></tr> @@ -193,33 +192,67 @@ public class JProgressBar extends JComponent implements SwingConstants, private static final long serialVersionUID = 1980046021813598781L; - /** Whether the ProgressBar is determinate. */ + /** + * A flag that determines the mode (<code>true</code> for indeterminate, + * <code>false</code> for determinate). + */ private transient boolean indeterminate = false; - /** The orientation of the ProgressBar. Always set by constructor. */ + /** + * The orientation of the <code>JProgressBar</code> + * ({@link SwingConstants#HORIZONTAL} or {@link SwingConstants#VERTICAL}). + * Defaults to {@link SwingConstants#HORIZONTAL}. + * @see #setOrientation(int) + */ protected int orientation; - /** Whether borders should be painted. */ + /** + * A flag the controls whether or not the component's border is painted. + * The default is <code>true</code>. + * @see #setBorderPainted(boolean) + */ protected boolean paintBorder = true; - /** The model describing this ProgressBar. */ + /** + * The model defining the bounds and current value for the progress bar. + * @see #setModel(BoundedRangeModel) + */ protected BoundedRangeModel model; - /** The string that is displayed by the ProgressBar. */ + /** + * A custom string for display in the progress bar. If this is + * <code>null</code>, a default string will be generated. + * @see #setString(String) + */ protected String progressString; - /** Whether the string should be painted. */ + /** + * A flag that controls whether a string is displayed within the progress + * bar. + * @see #setStringPainted(boolean) + */ protected boolean paintString = false; - /** The static changeEvent passed to all ChangeListeners. */ + /** + * A single change event reused for all events. + * @see #fireStateChanged() + */ protected transient ChangeEvent changeEvent; - /** The ChangeListener that listens to the model. */ + /** + * The listener that is registered with the model. */ protected ChangeListener changeListener; /** - * Creates a new horizontally oriented JProgressBar object - * with a minimum of 0 and a maximum of 100. + * Creates a new <code>JProgressBar</code> with default attributes. The + * following defaults are used: + * <p> + * <ul> + * <li><code>value</code>: 0;</li> + * <li><code>minimum</code>: 0;</li> + * <li><code>maximum</code>: 100;</li> + * <li><code>orientation</code>: {@link SwingConstants#HORIZONTAL}.</li> + * </ul> */ public JProgressBar() { @@ -227,13 +260,20 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * Creates a new JProgressBar object with a minimum of 0, - * a maximum of 100, and the given orientation. - * - * @param orientation The orientation of the JProgressBar. + * Creates a new <code>JProgressBar</code> with the specified + * <code>orientation</code>. The following defaults are used: + * <p> + * <ul> + * <li><code>value</code>: 0;</li> + * <li><code>minimum</code>: 0;</li> + * <li><code>maximum</code>: 100;</li> + * </ul> * - * @throws IllegalArgumentException if <code>orientation</code> is not either - * {@link #HORIZONTAL} or {@link #VERTICAL}. + * @param orientation the orientation ({@link #HORIZONTAL} or + * {@link #VERTICAL}). + * + * @throws IllegalArgumentException if <code>orientation</code> is not one of + * the specified values. */ public JProgressBar(int orientation) { @@ -241,11 +281,16 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * Creates a new horizontally oriented JProgressBar object - * with the given minimum and maximum. - * - * @param minimum The minimum of the JProgressBar. - * @param maximum The maximum of the JProgressBar. + * Creates a new <code>JProgressBar</code> with the specified value range. + * The following defaults are used: + * <p> + * <ul> + * <li><code>value</code>: <code>minimum</code>;</li> + * <li><code>orientation</code>: {@link SwingConstants#HORIZONTAL}.</li> + * </ul> + * + * @param minimum the lower bound of the value range. + * @param maximum the upper bound of the value range. */ public JProgressBar(int minimum, int maximum) { @@ -253,15 +298,20 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * Creates a new JProgressBar object with the given minimum, - * maximum, and orientation. - * - * @param minimum The minimum of the JProgressBar. - * @param maximum The maximum of the JProgressBar. - * @param orientation The orientation of the JProgressBar. + * Creates a new <code>JProgressBar</code> with the specified range and + * orientation. The following defaults are used: + * <p> + * <ul> + * <li><code>value</code>: <code>minimum</code>;</li> + * </ul> + * + * @param minimum the lower bound of the value range. + * @param maximum the upper bound of the value range. + * @param orientation the orientation ({@link #HORIZONTAL} or + * {@link #VERTICAL}). * - * @throws IllegalArgumentException if <code>orientation</code> is not either - * {@link #HORIZONTAL} or {@link #VERTICAL}. + * @throws IllegalArgumentException if <code>orientation</code> is not one of + * the specified values. */ public JProgressBar(int orientation, int minimum, int maximum) { @@ -276,10 +326,14 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * Creates a new horizontally oriented JProgressBar object - * with the given model. - * - * @param model The model to be used with the JProgressBar. + * Creates a new <code>JProgressBar</code> with the specified model. The + * following defaults are used: + * <p> + * <ul> + * <li><code>orientation</code>: {@link SwingConstants#HORIZONTAL}.</li> + * </ul> + * + * @param model the model (<code>null</code> not permitted). */ public JProgressBar(BoundedRangeModel model) { @@ -291,9 +345,12 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method returns the current value of the JProgressBar. + * Returns the current value for the <code>JProgressBar</code>. This value + * is fetched from the model. * - * @return The current value of the JProgressBar. + * @return The current value. + * + * @see #setValue(int) */ public int getValue() { @@ -301,9 +358,20 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method sets the value of the JProgressBar. + * Sets the current value for the <code>JProgressBar</code>. The value is + * stored in the component's <code>model</code> (see {@link #getModel()}). + * If the new value is different to the old value, a {@link ChangeEvent} is + * sent to the model's registered listeners. In turn, this triggers a call + * to {@link #fireStateChanged()} which will send a <code>ChangeEvent</code> + * to this component's registered listeners. + * <p> + * If <code>value</code> is outside the range <code>minimum</code> to + * <code>maximum</code>, it will be set to the nearest of those boundary + * values. * - * @param value The value of the JProgressBar. + * @param value the new value. + * + * @see #getValue() */ public void setValue(int value) { @@ -311,23 +379,29 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method paints the border of the JProgressBar + * Paints the component's border, but only if {@link #isBorderPainted()} + * returns <code>true</code>. * - * @param graphics The graphics object to paint with. + * @param graphics the graphics object to paint with. + * + * @see #setBorderPainted(boolean) */ protected void paintBorder(Graphics graphics) { Border border = getBorder(); if (paintBorder && border != null) - border.paintBorder(this, graphics, 0, 0, - getWidth(), - getHeight()); + border.paintBorder(this, graphics, 0, 0, getWidth(), getHeight()); } /** - * This method returns the orientation of the JProgressBar. + * Returns the orientation of the <code>JProgressBar</code> component, which + * is either {@link SwingConstants#HORIZONTAL} or + * {@link SwingConstants#VERTICAL}. The default orientation is + * <code>HORIZONTAL</code>. * - * @return The orientation of the JProgressBar. + * @return The orientation. + * + * @see #setOrientation(int) */ public int getOrientation() { @@ -335,12 +409,17 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method changes the orientation property. The orientation of the - * JProgressBar can be either horizontal or vertical. + * Sets the orientation for this <code>JProgressBar</code> component and, + * if the value changes, sends a {@link PropertyChangeEvent} (with the + * property name <code>"orientation"</code>) to all registered listeners. * - * @param orientation The orientation of the JProgressBar. + * @param orientation the orientation ({@link #HORIZONTAL} or + * {@link #VERTICAL}). + * * @throws IllegalArgumentException if <code>orientation</code> is not - * either {@link #HORIZONTAL} or {@link #VERTICAL}. + * one of the listed values. + * + * @see #getOrientation() */ public void setOrientation(int orientation) { @@ -349,17 +428,21 @@ public class JProgressBar extends JComponent implements SwingConstants, + " is not a legal orientation"); if (this.orientation != orientation) { - int oldOrientation = this.orientation; - this.orientation = orientation; - firePropertyChange("orientation", oldOrientation, - this.orientation); + int oldOrientation = this.orientation; + this.orientation = orientation; + firePropertyChange("orientation", oldOrientation, this.orientation); } } /** - * This method returns whether the progressString will be painted. + * Returns the flag that controls whether or not the string returned by + * {@link #getString()} is displayed by the <code>JProgressBar</code> + * component. * - * @return Whether the string is painted. + * @return <code>true</code> if the string should be displayed, and + * <code>false</code> otherwise. + * + * @see #setStringPainted(boolean) */ public boolean isStringPainted() { @@ -367,28 +450,37 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method changes the stringPainted property. + * Sets the flag that controls whether or not the string returned by + * {@link #getString()} is displayed by the <code>JProgressBar</code> + * component. If the flag value changes, a {@link PropertyChangeEvent} (with + * the property name <code>"stringPainted"</code>) is sent to all registered + * listeners. * - * @param painted Whether the string is painted. + * @param painted the new flag value. + * + * @see #isStringPainted() + * @see #setString(String) */ public void setStringPainted(boolean painted) { if (paintString != painted) { - boolean oldPainted = paintString; - paintString = painted; - firePropertyChange("stringPainted", oldPainted, - paintString); + boolean oldPainted = paintString; + paintString = painted; + firePropertyChange("stringPainted", oldPainted, paintString); } } /** - * This method returns the string that is painted if the - * stringPainted property is set to true. If there is no - * string set, it will return a string containing the - * JProgressBar's value as a percent. + * Returns the string that is painted on the <code>JProgressBar</code> if + * {@link #isStringPainted()} returns <code>true</code>. If no string has + * been explicitly set, this method will return a string displaying the + * value of {@link #getPercentComplete()}. * - * @return The string that is painted. + * @return The string. + * + * @see #setString(String) + * @see #setStringPainted(boolean) */ public String getString() { @@ -399,12 +491,16 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method changes the string property. The string - * given will be the one painted. If you want to - * revert to the default string given, set the - * string to null. + * Sets the string to display within the progress bar and, if the new value + * is different to the old value, sends a {@link PropertyChangeEvent} (with + * the property name <code>"string"</code>) to all registered listeners. If + * the string is set to <code>null</code>, {@link #getString()} will return + * a default string. * - * @param string The string to be painted. + * @param string the string (<code>null</code> permitted). + * + * @see #getString() + * @see #setStringPainted(boolean) */ public void setString(String string) { @@ -412,32 +508,35 @@ public class JProgressBar extends JComponent implements SwingConstants, string != progressString) || (string != null && ! string.equals(progressString))) { - String oldString = progressString; - progressString = string; - firePropertyChange("string", oldString, progressString); + String oldString = progressString; + progressString = string; + firePropertyChange("string", oldString, progressString); } } /** - * This method returns the percent of the bar - * that is "complete". (This is the amount value / (max - min)). + * Returns the current value expressed as a percentage. This is calculated + * as <code>(value - min) / (max - min)</code>. * - * @return DOCUMENT ME! + * @return The percentage (a value in the range 0.0 to 1.0). */ public double getPercentComplete() { if (getMaximum() == getMinimum()) return 1.0; else - return (double) (model.getValue() - model.getMinimum()) / (model - .getMaximum() - - model.getMinimum()); + return (double) (model.getValue() - model.getMinimum()) + / (model.getMaximum() - model.getMinimum()); } /** - * This method returns whether the border is painted. + * Returns a flag that controls whether or not the component's border is + * painted. The default value is <code>true</code>. * - * @return Whether the border is painted. + * @return <code>true</code> if the component's border should be painted, + * and <code>false</code> otherwise. + * + * @see #setBorderPainted(boolean) */ public boolean isBorderPainted() { @@ -445,25 +544,30 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method changes the borderPainted property. + * Sets the flag that controls whether or not the component's border is + * painted. If the flag value is changed, this method sends a + * {@link PropertyChangeEvent} (with the property name "borderPainted") to + * all registered listeners. * - * @param painted Whether the border is painted. + * @param painted the new flag value. + * + * @see #isBorderPainted() + * @see #paintBorder */ public void setBorderPainted(boolean painted) { if (painted != paintBorder) { - boolean oldPainted = paintBorder; - paintBorder = painted; - firePropertyChange("borderPainted", oldPainted, - paintBorder); + boolean oldPainted = paintBorder; + paintBorder = painted; + firePropertyChange("borderPainted", oldPainted, paintBorder); } } /** - * This method returns the JProgressBar's UI delegate. + * Returns the UI delegate for this <code>JProgressBar</code>. * - * @return This JProgressBar's UI delegate. + * @return The UI delegate. */ public ProgressBarUI getUI() { @@ -471,9 +575,9 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method changes the UI property for this JProgressBar. + * Sets the UI delegate for this component. * - * @param ui The new UI delegate. + * @param ui the new UI delegate. */ public void setUI(ProgressBarUI ui) { @@ -481,8 +585,8 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method reverts the UI delegate for this JProgressBar - * to the default for this Look and Feel. + * Sets this <code>JProgressBar</code>'s UI delegate to the default + * (obtained from the {@link UIManager}) for the current look and feel. */ public void updateUI() { @@ -490,11 +594,11 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method returns the identifier to allow the UIManager - * to pick the correct class to act as the UI for - * this JProgressBar. + * Returns the suffix (<code>"ProgressBarUI"</code> in this case) used to + * determine the class name for a UI delegate that can provide the look and + * feel for a <code>JProgressBar</code>. * - * @return The UIClassID: "ProgressBarUI". + * @return <code>"ProgressBarUI"</code>. */ public String getUIClassID() { @@ -502,27 +606,33 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method returns a ChangeListener that gets registered - * model. By default, the ChangeListener, propagates the - * ChangeEvents to the ChangeListeners of the JProgressBar. + * Creates a new {@link ChangeListener} that calls + * {@link #fireStateChanged()} whenever it receives a {@link ChangeEvent} + * (typically from the component's <code>model</code>). This listener is + * registered with the progress bar's model, so that changes made to the + * model directly will automatically result in the progress bar's listeners + * being notified also. * - * @return A new ChangeListener. + * @return A new listener. */ protected ChangeListener createChangeListener() { return new ChangeListener() { - public void stateChanged(ChangeEvent ce) - { - fireStateChanged(); - } + public void stateChanged(ChangeEvent ce) + { + fireStateChanged(); + } }; } /** - * This method adds a ChangeListener to this JProgressBar. + * Registers a listener with this component so that it will receive + * notification of component state changes. * - * @param listener The ChangeListener to add to this JProgressBar. + * @param listener the listener. + * + * @see #removeChangeListener(ChangeListener) */ public void addChangeListener(ChangeListener listener) { @@ -530,9 +640,12 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method removes a ChangeListener from this JProgressBar. + * Deregisters a listener so that it no longer receives notification of + * component state changes. * - * @param listener The ChangeListener to remove from this JProgressBar. + * @param listener the listener. + * + * @see #addChangeListener(ChangeListener) */ public void removeChangeListener(ChangeListener listener) { @@ -540,10 +653,12 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method returns an array of all ChangeListeners listening to this - * progress bar. + * Returns an array of the listeners that are registered with this component. + * The array may be empty, but is never <code>null</code>. * - * @return An array of ChangeListeners listening to this progress bar. + * @return An array of listeners. + * + * @since 1.4 */ public ChangeListener[] getChangeListeners() { @@ -551,9 +666,10 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method is called when the JProgressBar receives a ChangeEvent - * from its model. This simply propagates the event (changing the source - * to the JProgressBar) to the JProgressBar's listeners. + * Sends a {@link ChangeEvent} to all registered listeners to indicate that + * the state of the <code>JProgressBar</code> has changed. + * + * @see #createChangeListener() */ protected void fireStateChanged() { @@ -562,15 +678,17 @@ public class JProgressBar extends JComponent implements SwingConstants, changeEvent = new ChangeEvent(this); for (int i = changeListeners.length - 2; i >= 0; i -= 2) { - if (changeListeners[i] == ChangeListener.class) - ((ChangeListener) changeListeners[i + 1]).stateChanged(changeEvent); + if (changeListeners[i] == ChangeListener.class) + ((ChangeListener) changeListeners[i + 1]).stateChanged(changeEvent); } } /** - * This method returns the model used with this JProgressBar. + * Returns the model for the <code>JProgressBar</code>. * - * @return The model used with this JProgressBar. + * @return The model (never <code>null</code>). + * + * @see #setModel(BoundedRangeModel) */ public BoundedRangeModel getModel() { @@ -578,25 +696,32 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method changes the model property for this JProgressBar. + * Sets the model for the <code>JProgressBar</code> and sends a + * {@link ChangeEvent} to all registered listeners. * - * @param model The model to use with this JProgressBar. + * @param model the model (<code>null</code> not permitted). + * + * @see #getModel() */ public void setModel(BoundedRangeModel model) { if (model != this.model) { this.model.removeChangeListener(changeListener); - this.model = model; - this.model.addChangeListener(changeListener); - fireStateChanged(); + this.model = model; + this.model.addChangeListener(changeListener); + fireStateChanged(); } } /** - * This method returns the minimum value of this JProgressBar. + * Returns the minimum value for the <code>JProgressBar</code>. This defines + * the lower bound for the current value, and is stored in the component's + * <code>model</code>. * - * @return The minimum value of this JProgressBar. + * @return The minimum value. + * + * @see #setMinimum(int) */ public int getMinimum() { @@ -604,9 +729,16 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method sets the minimum value of this JProgressBar. - * - * @param minimum The minimum value of this JProgressBar. + * Sets the minimum value for the <code>JProgressBar</code>. The value is + * stored in the component's <code>model</code> (see {@link #getModel()}). + * If the new value is different to the old value, a {@link ChangeEvent} is + * sent to the model's registered listeners. In turn, this triggers a call + * to {@link #fireStateChanged()} which will send a <code>ChangeEvent</code> + * to this component's registered listeners. + * + * @param minimum the minimum value. + * + * @see #getMinimum() */ public void setMinimum(int minimum) { @@ -614,9 +746,13 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method returns the maximum value of this JProgressBar. + * Returns the maximum value for the <code>JProgressBar</code>. This defines + * the upper bound for the current value, and is stored in the component's + * <code>model</code>. * - * @return The maximum value of this JProgressBar. + * @return The maximum value. + * + * @see #setMaximum(int) */ public int getMaximum() { @@ -624,9 +760,16 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method sets the maximum value of this JProgressBar. + * Sets the maximum value for the <code>JProgressBar</code>. The value is + * stored in the component's <code>model</code> (see {@link #getModel()}). + * If the new value is different to the old value, a {@link ChangeEvent} is + * sent to the model's registered listeners. In turn, this triggers a call + * to {@link #fireStateChanged()} which will send a <code>ChangeEvent</code> + * to this component's registered listeners. * - * @param maximum The maximum value of this JProgressBar. + * @param maximum the maximum value. + * + * @see #getMaximum() */ public void setMaximum(int maximum) { @@ -659,29 +802,40 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method changes the indeterminate property. If the - * JProgressBar is determinate, it paints a percentage - * of the bar described by its value. If it is indeterminate, - * it simply bounces a box between the ends of the bar; the - * value of the JProgressBar is ignored. + * Sets the flag that controls the mode for this <code>JProgressBar</code> + * (<code>true</code> for indeterminate mode, and <code>false</code> for + * determinate mode). If the flag value changes, this method sends a + * {@link PropertyChangeEvent} (with the property name + * <code>"indeterminate"</code>) to all registered listeners. + * <p> + * If the <code>JProgressBar</code> is determinate, it paints a percentage + * of the bar described by its value. If it is indeterminate, it simply + * bounces a box between the ends of the bar; the value of the + * <code>JProgressBar</code> is ignored. * - * @param newValue Whether the JProgressBar is indeterminate. + * @param flag the new flag value. + * + * @see #isIndeterminate() + * @since 1.4 */ - public void setIndeterminate(boolean newValue) + public void setIndeterminate(boolean flag) { - if (indeterminate != newValue) + if (indeterminate != flag) { - boolean olddeter = indeterminate; - indeterminate = newValue; - firePropertyChange("indeterminate", olddeter, - indeterminate); + indeterminate = flag; + firePropertyChange("indeterminate", !flag, indeterminate); } } /** - * This method returns whether the JProgressBar is indeterminate. + * Returns a flag that indicates the mode for this <code>JProgressBar</code> + * (<code>true</code> for indeterminate mode, and <code>false</code> for + * determinate mode). * - * @return Whether this JProgressBar is indeterminate. + * @return A flag indicating the mode for the <code>JProgressBar</code>. + * + * @see #setIndeterminate(boolean) + * @since 1.4 */ public boolean isIndeterminate() { diff --git a/javax/swing/JScrollBar.java b/javax/swing/JScrollBar.java index bca246873..bf0803ab5 100644 --- a/javax/swing/JScrollBar.java +++ b/javax/swing/JScrollBar.java @@ -643,14 +643,24 @@ public class JScrollBar extends JComponent implements Adjustable, Accessible } /** - * A string that describes this JScrollBar. Normally only used - * for debugging. + * Returns a string describing the attributes for the <code>JScrollBar</code> + * component, for use in debugging. The return value is guaranteed to be + * non-<code>null</code>, but the format of the string may vary between + * implementations. * - * @return A string describing this JScrollBar. + * @return A string describing the attributes of the <code>JScrollBar</code>. */ protected String paramString() { - return "JScrollBar"; + StringBuffer sb = new StringBuffer(super.paramString()); + sb.append(",blockIncrement=").append(blockIncrement); + sb.append(",orientation="); + if (this.orientation == JScrollBar.HORIZONTAL) + sb.append("HORIZONTAL"); + else + sb.append("VERTICAL"); + sb.append(",unitIncrement=").append(unitIncrement); + return sb.toString(); } /** diff --git a/javax/swing/JTabbedPane.java b/javax/swing/JTabbedPane.java index 34ab8eeaa..76cc74eab 100644 --- a/javax/swing/JTabbedPane.java +++ b/javax/swing/JTabbedPane.java @@ -1,5 +1,5 @@ /* JTabbedPane.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -79,8 +79,6 @@ public class JTabbedPane extends JComponent implements Serializable, /** * Accessibility support for <code>JTabbedPane</code>. */ - // FIXME: This inner class is a complete stub and must be implemented - // properly. protected class AccessibleJTabbedPane extends JComponent.AccessibleJComponent implements AccessibleSelection, ChangeListener { @@ -106,7 +104,7 @@ public class JTabbedPane extends JComponent implements Serializable, public void stateChanged(ChangeEvent e) throws NotImplementedException { - // Implement this properly. + // FIXME: Implement this properly. } /** @@ -116,9 +114,8 @@ public class JTabbedPane extends JComponent implements Serializable, * @return the accessible role of the <code>JTabbedPane</code> */ public AccessibleRole getAccessibleRole() - throws NotImplementedException { - return null; + return AccessibleRole.PAGE_TAB_LIST; } /** @@ -129,9 +126,8 @@ public class JTabbedPane extends JComponent implements Serializable, * <code>JTabbedPane</code> */ public int getAccessibleChildrenCount() - throws NotImplementedException { - return 0; + return getTabCount(); } /** @@ -158,9 +154,8 @@ public class JTabbedPane extends JComponent implements Serializable, * @return the current selection state of the <code>JTabbedPane</code> */ public AccessibleSelection getAccessibleSelection() - throws NotImplementedException { - return null; + return this; } /** @@ -175,90 +170,99 @@ public class JTabbedPane extends JComponent implements Serializable, * this location */ public Accessible getAccessibleAt(Point p) - throws NotImplementedException { - return null; + int tabIndex = indexAtLocation(p.x, p.y); + if (tabIndex >= 0) + return getAccessibleChild(tabIndex); + else + return getAccessibleSelection(0); } /** - * The number of selected child components of the - * <code>JTabbedPane</code>. This will be <code>0</code> if the - * <code>JTabbedPane</code> has no children, or <code>1</code> otherwise, - * since there is always exactly one tab selected. + * Returns the number of selected child components of the + * <code>JTabbedPane</code>. The reference implementation appears + * to return <code>1</code> always and we do the same. * - * @return number of selected child components of the - * <code>JTabbedPane</code> + * @return <code>1</code> */ public int getAccessibleSelectionCount() - throws NotImplementedException { - return 0; + return 1; } /** - * DOCUMENT ME! + * Returns the selected tab, or <code>null</code> if there is no + * selection. * - * @param i DOCUMENT ME! + * @param i the selection index (ignored here). * - * @return DOCUMENT ME! + * @return The selected tab, or <code>null</code>. */ public Accessible getAccessibleSelection(int i) - throws NotImplementedException { - return null; + Accessible result = null; + int selected = getSelectedIndex(); + if (selected >= 0) + result = (Page) tabs.get(selected); + return result; } /** - * DOCUMENT ME! + * Returns <code>true</code> if the specified child is selected, + * and <code>false</code> otherwise. * - * @param i DOCUMENT ME! + * @param i the child index. * - * @return DOCUMENT ME! + * @return A boolean. */ public boolean isAccessibleChildSelected(int i) - throws NotImplementedException { - return false; + return i == getSelectedIndex(); } /** - * DOCUMENT ME! + * Selects the specified tab. * - * @param i DOCUMENT ME! + * @param i the index of the item to select. */ public void addAccessibleSelection(int i) - throws NotImplementedException { - // TODO: Implement this properly. + setSelectedIndex(i); } /** - * DOCUMENT ME! + * Does nothing - it makes no sense to remove a selection for a + * tabbed pane, since one tab must always be selected. * - * @param i DOCUMENT ME! + * @param i the item index. + * + * @see #addAccessibleSelection(int) */ public void removeAccessibleSelection(int i) - throws NotImplementedException { - // TODO: Implement this properly. + // do nothing } /** - * DOCUMENT ME! + * Does nothing - it makes no sense to clear the selection for + * a tabbed pane, since one tab must always be selected. + * + * @see #addAccessibleSelection(int) */ public void clearAccessibleSelection() - throws NotImplementedException { - // TODO: Implement this properly. + // do nothing } /** - * DOCUMENT ME! + * Does nothing - it makes no sense to select all for a tabbed + * pane, since only one tab can be selected at a time. + * + * @see #addAccessibleSelection(int) */ public void selectAllAccessibleSelection() - throws NotImplementedException { - // TODO: Implement this properly. + // do nothing } } @@ -267,7 +271,6 @@ public class JTabbedPane extends JComponent implements Serializable, */ protected class ModelListener implements ChangeListener, Serializable { - /** DOCUMENT ME! */ private static final long serialVersionUID = 497359819958114132L; /** @@ -446,7 +449,6 @@ public class JTabbedPane extends JComponent implements Serializable, return title; } - /** DOCUMENT ME! */ private static final long serialVersionUID = 1614381073220130939L; /** @@ -598,6 +600,19 @@ public class JTabbedPane extends JComponent implements Serializable, } /** + * Returns the accessible name for this tab. + * + * @return The accessible name. + */ + public String getAccessibleName() + { + if (accessibleName != null) + return accessibleName; + else + return title; + } + + /** * Returns the accessible role of this tab, which is always * {@link AccessibleRole#PAGE_TAB}. * @@ -1623,20 +1638,35 @@ public class JTabbedPane extends JComponent implements Serializable, } /** - * This method returns a string representation of this JTabbedPane. It is - * mainly used for debugging purposes. + * Returns a string describing the attributes for the + * <code>JTabbedPane</code> component, for use in debugging. The return + * value is guaranteed to be non-<code>null</code>, but the format of the + * string may vary between implementations. * - * @return A string representation of this JTabbedPane. + * @return A string describing the attributes of the + * <code>JTabbedPane</code>. */ protected String paramString() { - return "JTabbedPane"; + StringBuffer sb = new StringBuffer(super.paramString()); + sb.append(",tabPlacement="); + if (tabPlacement == TOP) + sb.append("TOP"); + if (tabPlacement == BOTTOM) + sb.append("BOTTOM"); + if (tabPlacement == LEFT) + sb.append("LEFT"); + if (tabPlacement == RIGHT) + sb.append("RIGHT"); + return sb.toString(); } /** - * DOCUMENT ME! + * Returns the object that provides accessibility features for this + * <code>JTabbedPane</code> component. * - * @return DOCUMENT ME! + * @return The accessible context (an instance of + * {@link AccessibleJTabbedPane}). */ public AccessibleContext getAccessibleContext() { diff --git a/javax/swing/JTable.java b/javax/swing/JTable.java index 1298f128d..a4ef6fbcd 100644 --- a/javax/swing/JTable.java +++ b/javax/swing/JTable.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing; +import gnu.classpath.NotImplementedException; + import java.awt.Color; import java.awt.Component; import java.awt.Cursor; @@ -163,6 +165,7 @@ public class JTable * @return the accessible row for the table cell */ public AccessibleRole getAccessibleRole() + throws NotImplementedException { // TODO: What is the role of the table cell? return AccessibleRole.UNKNOWN; @@ -174,6 +177,7 @@ public class JTable * @return the accessible state set of this accessible table cell */ public AccessibleStateSet getAccessibleStateSet() + throws NotImplementedException { // TODO: What state shoiuld be returned here? return new AccessibleStateSet(); @@ -617,45 +621,47 @@ public class JTable } public Accessible getAccessibleSelection(int i) + throws NotImplementedException { // TODO Auto-generated method stub return null; } public boolean isAccessibleChildSelected(int i) + throws NotImplementedException { // TODO Auto-generated method stub return false; } public void addAccessibleSelection(int i) + throws NotImplementedException { - // TODO Auto-generated method stub - + // TODO Auto-generated method stub } public void removeAccessibleSelection(int i) + throws NotImplementedException { - // TODO Auto-generated method stub - + // TODO Auto-generated method stub } public void clearAccessibleSelection() + throws NotImplementedException { // TODO Auto-generated method stub - } public void selectAllAccessibleSelection() + throws NotImplementedException { // TODO Auto-generated method stub - } public void valueChanged(ListSelectionEvent event) + throws NotImplementedException { - // TODO Auto-generated method stub - + // TODO Auto-generated method stub } /** @@ -685,6 +691,7 @@ public class JTable * @param event the table model event */ public void tableRowsInserted(TableModelEvent event) + throws NotImplementedException { // TODO: What to do here, if anything? This might be a hook method for // subclasses... @@ -697,51 +704,52 @@ public class JTable * @param event the table model event */ public void tableRowsDeleted(TableModelEvent event) + throws NotImplementedException { // TODO: What to do here, if anything? This might be a hook method for // subclasses... } public void columnAdded(TableColumnModelEvent event) + throws NotImplementedException { - // TODO Auto-generated method stub - + // TODO Auto-generated method stub } public void columnMarginChanged(ChangeEvent event) + throws NotImplementedException { // TODO Auto-generated method stub - } public void columnMoved(TableColumnModelEvent event) + throws NotImplementedException { // TODO Auto-generated method stub - } public void columnRemoved(TableColumnModelEvent event) + throws NotImplementedException { // TODO Auto-generated method stub - } public void columnSelectionChanged(ListSelectionEvent event) + throws NotImplementedException { // TODO Auto-generated method stub - } public void editingCanceled(ChangeEvent event) + throws NotImplementedException { // TODO Auto-generated method stub - } public void editingStopped(ChangeEvent event) + throws NotImplementedException { // TODO Auto-generated method stub - } /** @@ -785,150 +793,170 @@ public class JTable } public int getAccessibleRow(int index) + throws NotImplementedException { // TODO Auto-generated method stub return 0; } public int getAccessibleColumn(int index) + throws NotImplementedException { // TODO Auto-generated method stub return 0; } public int getAccessibleIndex(int r, int c) + throws NotImplementedException { // TODO Auto-generated method stub return 0; } public Accessible getAccessibleCaption() + throws NotImplementedException { // TODO Auto-generated method stub return null; } public void setAccessibleCaption(Accessible caption) + throws NotImplementedException { // TODO Auto-generated method stub - } public Accessible getAccessibleSummary() + throws NotImplementedException { // TODO Auto-generated method stub return null; } public void setAccessibleSummary(Accessible summary) + throws NotImplementedException { // TODO Auto-generated method stub - } public int getAccessibleRowCount() + throws NotImplementedException { // TODO Auto-generated method stub return 0; } public int getAccessibleColumnCount() + throws NotImplementedException { // TODO Auto-generated method stub return 0; } public Accessible getAccessibleAt(int r, int c) + throws NotImplementedException { // TODO Auto-generated method stub return null; } public int getAccessibleRowExtentAt(int r, int c) + throws NotImplementedException { // TODO Auto-generated method stub return 0; } public int getAccessibleColumnExtentAt(int r, int c) + throws NotImplementedException { // TODO Auto-generated method stub return 0; } public AccessibleTable getAccessibleRowHeader() + throws NotImplementedException { // TODO Auto-generated method stub return null; } public void setAccessibleRowHeader(AccessibleTable header) + throws NotImplementedException { - // TODO Auto-generated method stub - + // TODO Auto-generated method stub } public AccessibleTable getAccessibleColumnHeader() + throws NotImplementedException { // TODO Auto-generated method stub return null; } public void setAccessibleColumnHeader(AccessibleTable header) + throws NotImplementedException { - // TODO Auto-generated method stub - + // TODO Auto-generated method stub } public Accessible getAccessibleRowDescription(int r) + throws NotImplementedException { // TODO Auto-generated method stub return null; } public void setAccessibleRowDescription(int r, Accessible description) + throws NotImplementedException { - // TODO Auto-generated method stub - + // TODO Auto-generated method stub } public Accessible getAccessibleColumnDescription(int c) + throws NotImplementedException { // TODO Auto-generated method stub return null; } public void setAccessibleColumnDescription(int c, Accessible description) + throws NotImplementedException { // TODO Auto-generated method stub } public boolean isAccessibleSelected(int r, int c) + throws NotImplementedException { // TODO Auto-generated method stub return false; } public boolean isAccessibleRowSelected(int r) + throws NotImplementedException { // TODO Auto-generated method stub return false; } public boolean isAccessibleColumnSelected(int c) + throws NotImplementedException { // TODO Auto-generated method stub return false; } public int[] getSelectedAccessibleRows() + throws NotImplementedException { // TODO Auto-generated method stub return null; } public int[] getSelectedAccessibleColumns() + throws NotImplementedException { // TODO Auto-generated method stub return null; @@ -1272,17 +1300,6 @@ public class JTable { setBorder(BorderFactory.createLineBorder(getGridColor(), 2)); } - - /** - * With not this method overridden, the scroll pane scrolls to the - * top left cornec (untranslated position of the caret) after the first - * keystroke. - */ - public void scrollRectToVisible(Rectangle r) - { - // Do nothing here. If the editing session starts outside the visible - // bounds, the editCellAt will scroll. - } } @@ -1588,6 +1605,21 @@ public class JTable private boolean clientRowHeightSet = false; /** + * Stores the sizes and positions of each row, when using non-uniform row + * heights. Initially the height of all rows is equal and stored in + * {link #rowHeight}. However, when an application calls + * {@link #setRowHeight(int,int)}, the table switches to non-uniform + * row height mode which stores the row heights in the SizeSequence + * object instead. + * + * @see #setRowHeight(int) + * @see #getRowHeight() + * @see #getRowHeight(int) + * @see #setRowHeight(int, int) + */ + private SizeSequence rowHeights; + + /** * Creates a new <code>JTable</code> instance. */ public JTable () @@ -1727,7 +1759,7 @@ public class JTable createDefaultEditors(); this.autoResizeMode = AUTO_RESIZE_SUBSEQUENT_COLUMNS; - this.rowHeight = 16; + setRowHeight(16); this.rowMargin = 1; this.rowSelectionAllowed = true; // this.accessibleContext = new AccessibleJTable(); @@ -1958,7 +1990,13 @@ public class JTable // changed and the flag autoCreateColumnsFromModel is set if ((event == null || (event.getFirstRow() == TableModelEvent.HEADER_ROW)) && autoCreateColumnsFromModel) - createDefaultColumnsFromModel(); + { + rowHeights = null; + if (getAutoCreateColumnsFromModel()) + createDefaultColumnsFromModel(); + resizeAndRepaint(); + return; + } // If the structure changes, we need to revalidate, since that might // affect the size parameters of the JTable. Otherwise we only need @@ -1975,6 +2013,8 @@ public class JTable if (last < 0) last = getRowCount() - 1; selectionModel.insertIndexInterval(first, last - first + 1, true); + if (rowHeights != null) + rowHeights.insertEntries(first, last - first + 1, rowHeight); } revalidate(); } @@ -1990,6 +2030,8 @@ public class JTable if (last < 0) last = getRowCount() - 1; selectionModel.removeIndexInterval(first, last); + if (rowHeights != null) + rowHeights.removeEntries(first, last - first + 1); } if (dataModel.getRowCount() == 0) clearSelection(); @@ -2004,14 +2046,14 @@ public class JTable */ public void valueChanged (ListSelectionEvent event) { - // Does not make sense for the table with the single row. - if (getRowCount() < 2) - return; - - int y_gap = rowMargin; - int y0 = (getRowHeight() + y_gap) * (event.getFirstIndex()); - int yn = (getRowHeight() + y_gap) * (event.getLastIndex()+1); - repaint(0, y0, getWidth(), yn-y0); + // Repaint the changed region. + int first = Math.max(0, Math.min(getRowCount() - 1, event.getFirstIndex())); + int last = Math.max(0, Math.min(getRowCount() - 1, event.getLastIndex())); + Rectangle rect1 = getCellRect(first, 0, false); + Rectangle rect2 = getCellRect(last, getColumnCount() - 1, false); + SwingUtilities.computeUnion(rect2.x, rect2.y, rect2.width, rect2.height, + rect1); + repaint(rect1); } /** @@ -2053,10 +2095,16 @@ public class JTable if (point != null) { int nrows = getRowCount(); - int height = getRowHeight() + getRowMargin(); + int r; int y = point.y; + if (rowHeights == null) + { + int height = getRowHeight(); + r = y / height; + } + else + r = rowHeights.getIndex(y); - int r = y / height; if (r < 0 || r >= nrows) return -1; else @@ -2086,27 +2134,70 @@ public class JTable int column, boolean includeSpacing) { - int height = getRowHeight(row); - int width = columnModel.getColumn(column).getWidth(); - int x_gap = columnModel.getColumnMargin(); - int y_gap = rowMargin; + Rectangle cellRect = new Rectangle(0, 0, 0, 0); - column = Math.max(0, Math.min(column, getColumnCount() - 1)); - row = Math.max(0, Math.min(row, getRowCount() - 1)); - - int x = 0; - int y = (height + y_gap) * row; + // Check for valid range vertically. + if (row >= getRowCount()) + { + cellRect.height = getHeight(); + } + else if (row >= 0) + { + cellRect.height = getRowHeight(row); + if (rowHeights == null) + cellRect.y = row * cellRect.height; + else + cellRect.y = rowHeights.getPosition(row); - for (int i = 0; i < column; ++i) - x += columnModel.getColumn(i).getWidth(); - - Rectangle rect = new Rectangle(); + if (! includeSpacing) + { + // The rounding here is important. + int rMargin = getRowMargin(); + cellRect.y += rMargin / 2; + cellRect.height -= rMargin; + } + } + // else row < 0, y = height = 0 - if (includeSpacing) - rect.setBounds(x, y, width, height +y_gap); + // Check for valid range horizontally. + if (column < 0) + { + if (! getComponentOrientation().isLeftToRight()) + { + cellRect.x = getWidth(); + } + } + else if (column >= getColumnCount()) + { + if (getComponentOrientation().isLeftToRight()) + { + cellRect.x = getWidth(); + } + } else - rect.setBounds(x, y, width - x_gap, height); - return rect; + { + TableColumnModel tcm = getColumnModel(); + if (getComponentOrientation().isLeftToRight()) + { + for (int i = 0; i < column; i++) + cellRect.x += tcm.getColumn(i).getWidth(); + } + else + { + for (int i = tcm.getColumnCount() - 1; i > column; i--) + cellRect.x += tcm.getColumn(i).getWidth(); + } + cellRect.width = tcm.getColumn(column).getWidth(); + if (! includeSpacing) + { + // The rounding here is important. + int cMargin = tcm.getColumnMargin(); + cellRect.x += cMargin / 2; + cellRect.width -= cMargin; + } + } + + return cellRect; } public void clearSelection() @@ -2354,7 +2445,6 @@ public class JTable int row, int column) { - boolean rowSelAllowed = getRowSelectionAllowed(); boolean colSelAllowed = getColumnSelectionAllowed(); boolean isSel = false; @@ -2418,9 +2508,10 @@ public class JTable */ public int getRowHeight(int row) { - // FIXME: return the height of the specified row - // which may be different from the general rowHeight - return rowHeight; + int rh = rowHeight; + if (rowHeights != null) + rh = rowHeights.getSize(row); + return rh; } @@ -2780,9 +2871,14 @@ public class JTable } /** - * Set the value of the {@link #rowHeight} property. + * Sets the height for all rows in the table. If you want to change the + * height of a single row instead, use {@link #setRowHeight(int, int)}. + * + * @param r the height to set for all rows * - * @param r The new value of the rowHeight property + * @see #getRowHeight() + * @see #setRowHeight(int, int) + * @see #getRowHeight(int) */ public void setRowHeight(int r) { @@ -2792,21 +2888,24 @@ public class JTable clientRowHeightSet = true; rowHeight = r; + rowHeights = null; revalidate(); repaint(); } /** - * Sets the value of the rowHeight property for the specified - * row. + * Sets the height of a single row in the table. * - * @param rh is the new rowHeight - * @param row is the row to change the rowHeight of + * @param rh the new row height + * @param row the row to change the height of */ public void setRowHeight(int row, int rh) { - setRowHeight(rh); - // FIXME: not implemented + if (rowHeights == null) + { + rowHeights = new SizeSequence(getRowCount(), rowHeight); + } + rowHeights.setSize(row, rh); } /** @@ -2878,6 +2977,10 @@ public class JTable // Add table as TableModelListener to new model. dataModel.addTableModelListener(this); + // Notify the tableChanged method. + tableChanged(new TableModelEvent(dataModel, + TableModelEvent.HEADER_ROW)); + // Automatically create columns. if (autoCreateColumnsFromModel) createDefaultColumnsFromModel(); @@ -3866,4 +3969,5 @@ public class JTable super.setUIProperty(propertyName, value); } } + } diff --git a/javax/swing/JToolBar.java b/javax/swing/JToolBar.java index b576b4f2a..fe4d2ae20 100644 --- a/javax/swing/JToolBar.java +++ b/javax/swing/JToolBar.java @@ -1,5 +1,5 @@ /* JToolBar.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -757,14 +757,28 @@ public class JToolBar extends JComponent implements SwingConstants, Accessible } // addImpl() /** - * This method returns a String description of the JToolBar. + * Returns a string describing the attributes for the <code>JToolBar</code> + * component, for use in debugging. The return value is guaranteed to be + * non-<code>null</code>, but the format of the string may vary between + * implementations. * - * @return A String description of the JToolBar. + * @return A string describing the attributes of the <code>JToolBar</code>. */ protected String paramString() { - return "JToolBar"; - } // paramString() + StringBuffer sb = new StringBuffer(super.paramString()); + sb.append(",floatable=").append(floatable); + sb.append(",margin="); + if (margin != null) + sb.append(margin); + sb.append(",orientation="); + if (orientation == HORIZONTAL) + sb.append("HORIZONTAL"); + else + sb.append(VERTICAL); + sb.append(",paintBorder=").append(paintBorder); + return sb.toString(); + } /** * Returns the object that provides accessibility features for this diff --git a/javax/swing/KeyboardManager.java b/javax/swing/KeyboardManager.java index 4f778f733..f7ac9496c 100644 --- a/javax/swing/KeyboardManager.java +++ b/javax/swing/KeyboardManager.java @@ -46,6 +46,7 @@ import java.awt.event.KeyEvent; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; +import java.util.WeakHashMap; /** * This class maintains a mapping from top-level containers to a @@ -65,7 +66,7 @@ class KeyboardManager * A mapping between top level containers and Hashtables that * map KeyStrokes to Components. */ - Hashtable topLevelLookup = new Hashtable(); + WeakHashMap topLevelLookup = new WeakHashMap(); /** * A mapping between top level containers and Vectors of JMenuBars diff --git a/javax/swing/ProgressMonitor.java b/javax/swing/ProgressMonitor.java index 73e36b9ca..28d22e8a6 100644 --- a/javax/swing/ProgressMonitor.java +++ b/javax/swing/ProgressMonitor.java @@ -38,8 +38,10 @@ exception statement from your version. */ package javax.swing; import java.awt.Component; -import java.awt.event.ActionListener; import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.accessibility.AccessibleContext; /** * <p>Using this class you can easily monitor tasks where you cannot @@ -62,6 +64,12 @@ import java.awt.event.ActionEvent; */ public class ProgressMonitor { + + /** + * The accessible content for this component + */ + protected AccessibleContext accessibleContext; + /** * parentComponent */ @@ -439,5 +447,14 @@ public class ProgressMonitor timestamp = now; } } - + + /** + * Gets the accessible context. + * + * @return the accessible context. + */ + public AccessibleContext getAccessibleContext() + { + return accessibleContext; + } } diff --git a/javax/swing/RepaintManager.java b/javax/swing/RepaintManager.java index 8508996f5..e1416a422 100644 --- a/javax/swing/RepaintManager.java +++ b/javax/swing/RepaintManager.java @@ -47,9 +47,8 @@ import java.awt.Rectangle; import java.awt.Window; import java.awt.image.VolatileImage; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; @@ -63,19 +62,20 @@ import java.util.WeakHashMap; * double buffer surface is used by root components to paint * themselves.</p> * - * <p>In general, painting is very confusing in swing. see <a + * <p>See <a * href="http://java.sun.com/products/jfc/tsc/articles/painting/index.html">this * document</a> for more details.</p> * * @author Roman Kennke (kennke@aicas.com) * @author Graydon Hoare (graydon@redhat.com) + * @author Audrius Meskauskas (audriusa@bioinformatics.org) */ public class RepaintManager { /** * The current repaint managers, indexed by their ThreadGroups. */ - private static WeakHashMap currentRepaintManagers; + static WeakHashMap currentRepaintManagers; /** * A rectangle object to be reused in damaged regions calculation. @@ -134,44 +134,6 @@ public class RepaintManager } - /** - * Compares two components using their depths in the component hierarchy. - * A component with a lesser depth (higher level components) are sorted - * before components with a deeper depth (low level components). This is used - * to order paint requests, so that the higher level components are painted - * before the low level components get painted. - * - * @author Roman Kennke (kennke@aicas.com) - */ - private class ComponentComparator implements Comparator - { - - /** - * Compares two components. - * - * @param o1 the first component - * @param o2 the second component - * - * @return a negative integer, if <code>o1</code> is bigger in than - * <code>o2</code>, zero, if both are at the same size and a - * positive integer, if <code>o1</code> is smaller than - * <code>o2</code> - */ - public int compare(Object o1, Object o2) - { - if (o1 instanceof JComponent && o2 instanceof JComponent) - { - JComponent c1 = (JComponent) o1; - Rectangle d1 = (Rectangle) dirtyComponentsWork.get(c1); - JComponent c2 = (JComponent) o2; - Rectangle d2 = (Rectangle) dirtyComponentsWork.get(c2); - return d2.width * d2.height - d1.width * d1.height; - } - throw new ClassCastException("This comparator can only be used with " - + "JComponents"); - } - } - /** * A table storing the dirty regions of components. The keys of this * table are components, the values are rectangles. Each component maps @@ -187,18 +149,13 @@ public class RepaintManager * @see #markCompletelyClean * @see #markCompletelyDirty */ - HashMap dirtyComponents; + private HashMap dirtyComponents; /** * The dirtyComponents which is used in paintDiryRegions to avoid unnecessary * locking. */ - HashMap dirtyComponentsWork; - - /** - * The comparator used for ordered inserting into the repaintOrder list. - */ - private transient Comparator comparator; + private HashMap dirtyComponentsWork; /** * A single, shared instance of the helper class. Any methods which mark @@ -422,6 +379,9 @@ public class RepaintManager { if (w <= 0 || h <= 0 || !component.isShowing()) return; + + Component parent = component.getParent(); + component.computeVisibleRect(rectCache); SwingUtilities.computeIntersection(x, y, w, h, rectCache); @@ -485,8 +445,7 @@ public class RepaintManager public void markCompletelyDirty(JComponent component) { Rectangle r = component.getBounds(); - addDirtyRegion(component, r.x, r.y, r.width, r.height); - component.isCompletelyDirty = true; + addDirtyRegion(component, 0, 0, r.width, r.height); } /** @@ -506,7 +465,6 @@ public class RepaintManager { dirtyComponents.remove(component); } - component.isCompletelyDirty = false; } /** @@ -525,9 +483,13 @@ public class RepaintManager */ public boolean isCompletelyDirty(JComponent component) { - if (! dirtyComponents.containsKey(component)) - return false; - return component.isCompletelyDirty; + boolean retVal = false; + if (dirtyComponents.containsKey(component)) + { + Rectangle dirtyRegion = (Rectangle) dirtyComponents.get(component); + retVal = dirtyRegion.equals(SwingUtilities.getLocalBounds(component)); + } + return retVal; } /** @@ -554,8 +516,8 @@ public class RepaintManager } /** - * Repaint all regions of all components which have been marked dirty in - * the {@link #dirtyComponents} table. + * Repaint all regions of all components which have been marked dirty in the + * {@link #dirtyComponents} table. */ public void paintDirtyRegions() { @@ -571,29 +533,76 @@ public class RepaintManager dirtyComponentsWork = swap; } - ArrayList repaintOrder = new ArrayList(dirtyComponentsWork.size());; - // We sort the components by their size here. This way we have a good - // chance that painting the bigger components also paints the smaller - // components and we don't need to paint them twice. - repaintOrder.addAll(dirtyComponentsWork.keySet()); + // Compile a set of repaint roots. + HashSet repaintRoots = new HashSet(); + Set components = dirtyComponentsWork.keySet(); + for (Iterator i = components.iterator(); i.hasNext();) + { + JComponent dirty = (JComponent) i.next(); + compileRepaintRoots(dirtyComponentsWork, dirty, repaintRoots); + } - if (comparator == null) - comparator = new ComponentComparator(); - Collections.sort(repaintOrder, comparator); repaintUnderway = true; - for (Iterator i = repaintOrder.iterator(); i.hasNext();) + for (Iterator i = repaintRoots.iterator(); i.hasNext();) { JComponent comp = (JComponent) i.next(); - // If a component is marked completely clean in the meantime, then skip - // it. Rectangle damaged = (Rectangle) dirtyComponentsWork.remove(comp); if (damaged == null || damaged.isEmpty()) continue; comp.paintImmediately(damaged); } + dirtyComponentsWork.clear(); repaintUnderway = false; commitRemainingBuffers(); } + + /** + * Compiles a list of components that really get repainted. This is called + * once for each component in the dirtyComponents HashMap, each time with + * another <code>dirty</code> parameter. This searches up the component + * hierarchy of <code>dirty</code> to find the highest parent that is also + * marked dirty and merges the dirty regions. + * + * @param dirtyRegions the dirty regions + * @param dirty the component for which to find the repaint root + * @param roots the list to which new repaint roots get appended + */ + private void compileRepaintRoots(HashMap dirtyRegions, JComponent dirty, + HashSet roots) + { + Component current = dirty; + Component root = dirty; + + // Search the highest component that is also marked dirty. + Component parent; + while (true) + { + parent = current.getParent(); + if (parent == null || !(parent instanceof JComponent)) + break; + + current = parent; + // We can skip to the next up when this parent is not dirty. + if (dirtyRegions.containsKey(parent)) + { + root = current; + } + } + + // Merge the rectangles of the root and the requested component if + // the are different. + if (root != dirty) + { + Rectangle dirtyRect = (Rectangle) dirtyRegions.get(dirty); + dirtyRect = SwingUtilities.convertRectangle(dirty, dirtyRect, root); + Rectangle rootRect = (Rectangle) dirtyRegions.get(root); + SwingUtilities.computeUnion(dirtyRect.x, dirtyRect.y, dirtyRect.width, + dirtyRect.height, rootRect); + } + + // Adds the root to the roots set. + roots.add(root); + } /** * Get an offscreen buffer for painting a component's image. This image diff --git a/javax/swing/SwingUtilities.java b/javax/swing/SwingUtilities.java index b5ef61bd9..212423a66 100644 --- a/javax/swing/SwingUtilities.java +++ b/javax/swing/SwingUtilities.java @@ -1446,4 +1446,157 @@ public class SwingUtilities KeyboardManager km = KeyboardManager.getManager(); return km.processKeyStroke(c, s, ev); } + + /** + * Returns a string representing one of the horizontal alignment codes + * defined in the {@link SwingConstants} interface. The following table + * lists the constants and return values: + * <p> + * <table border="0"> + * <tr> + * <th>Code:</th><th>Returned String:</th> + * </tr> + * <tr> + * <td>{@link SwingConstants#CENTER}</td> + * <td><code>"CENTER"</code></td> + * </tr> + * <tr> + * <td>{@link SwingConstants#LEFT}</td> + * <td><code>"LEFT"</code></td> + * </tr> + * <tr> + * <td>{@link SwingConstants#RIGHT}</td> + * <td><code>"RIGHT"</code></td> + * </tr> + * <tr> + * <td>{@link SwingConstants#LEADING}</td> + * <td><code>"LEADING"</code></td> + * </tr> + * <tr> + * <td>{@link SwingConstants#TRAILING}</td> + * <td><code>"TRAILING"</code></td> + * </tr> + * </table> + * </p> + * If the supplied code is not one of those listed, this methods will throw + * an {@link IllegalArgumentException}. + * + * @param code the code. + * + * @return A string representing the given code. + */ + static String convertHorizontalAlignmentCodeToString(int code) + { + switch (code) + { + case SwingConstants.CENTER: + return "CENTER"; + case SwingConstants.LEFT: + return "LEFT"; + case SwingConstants.RIGHT: + return "RIGHT"; + case SwingConstants.LEADING: + return "LEADING"; + case SwingConstants.TRAILING: + return "TRAILING"; + default: + throw new IllegalArgumentException("Unrecognised code: " + code); + } + } + + /** + * Returns a string representing one of the vertical alignment codes + * defined in the {@link SwingConstants} interface. The following table + * lists the constants and return values: + * <p> + * <table border="0"> + * <tr> + * <th>Code:</th><th>Returned String:</th> + * </tr> + * <tr> + * <td>{@link SwingConstants#CENTER}</td> + * <td><code>"CENTER"</code></td> + * </tr> + * <tr> + * <td>{@link SwingConstants#TOP}</td> + * <td><code>"TOP"</code></td> + * </tr> + * <tr> + * <td>{@link SwingConstants#BOTTOM}</td> + * <td><code>"BOTTOM"</code></td> + * </tr> + * </table> + * </p> + * If the supplied code is not one of those listed, this methods will throw + * an {@link IllegalArgumentException}. + * + * @param code the code. + * + * @return A string representing the given code. + */ + static String convertVerticalAlignmentCodeToString(int code) + { + switch (code) + { + case SwingConstants.CENTER: + return "CENTER"; + case SwingConstants.TOP: + return "TOP"; + case SwingConstants.BOTTOM: + return "BOTTOM"; + default: + throw new IllegalArgumentException("Unrecognised code: " + code); + } + } + + /** + * Returns a string representing one of the default operation codes + * defined in the {@link WindowConstants} interface. The following table + * lists the constants and return values: + * <p> + * <table border="0"> + * <tr> + * <th>Code:</th><th>Returned String:</th> + * </tr> + * <tr> + * <td>{@link WindowConstants#DO_NOTHING_ON_CLOSE}</td> + * <td><code>"DO_NOTHING_ON_CLOSE"</code></td> + * </tr> + * <tr> + * <td>{@link WindowConstants#HIDE_ON_CLOSE}</td> + * <td><code>"HIDE_ON_CLOSE"</code></td> + * </tr> + * <tr> + * <td>{@link WindowConstants#DISPOSE_ON_CLOSE}</td> + * <td><code>"DISPOSE_ON_CLOSE"</code></td> + * </tr> + * <tr> + * <td>{@link WindowConstants#EXIT_ON_CLOSE}</td> + * <td><code>"EXIT_ON_CLOSE"</code></td> + * </tr> + * </table> + * </p> + * If the supplied code is not one of those listed, this method will throw + * an {@link IllegalArgumentException}. + * + * @param code the code. + * + * @return A string representing the given code. + */ + static String convertWindowConstantToString(int code) + { + switch (code) + { + case WindowConstants.DO_NOTHING_ON_CLOSE: + return "DO_NOTHING_ON_CLOSE"; + case WindowConstants.HIDE_ON_CLOSE: + return "HIDE_ON_CLOSE"; + case WindowConstants.DISPOSE_ON_CLOSE: + return "DISPOSE_ON_CLOSE"; + case WindowConstants.EXIT_ON_CLOSE: + return "EXIT_ON_CLOSE"; + default: + throw new IllegalArgumentException("Unrecognised code: " + code); + } + } } diff --git a/javax/swing/TransferHandler.java b/javax/swing/TransferHandler.java index 830feee83..40a36b27d 100644 --- a/javax/swing/TransferHandler.java +++ b/javax/swing/TransferHandler.java @@ -1,5 +1,5 @@ /* TransferHandler.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,12 +38,14 @@ exception statement from your version. */ package javax.swing; +import gnu.classpath.NotImplementedException; + +import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.event.ActionEvent; import java.awt.event.InputEvent; -import java.awt.Toolkit; import java.io.Serializable; public class TransferHandler implements Serializable @@ -147,42 +149,48 @@ public class TransferHandler implements Serializable this.sourceActions = property != null ? COPY : NONE; } - public boolean canImport (JComponent c, DataFlavor[] flavors) + public boolean canImport(JComponent c, DataFlavor[] flavors) + throws NotImplementedException { return false; } protected Transferable createTransferable(JComponent c) + throws NotImplementedException { return null; } - public void exportAsDrag (JComponent c, InputEvent e, int action) + public void exportAsDrag(JComponent c, InputEvent e, int action) + throws NotImplementedException { // TODO: Implement this properly } - protected void exportDone (JComponent c, Transferable data, int action) + protected void exportDone(JComponent c, Transferable data, int action) + throws NotImplementedException { // TODO: Implement this properly } public void exportToClipboard(JComponent c, Clipboard clip, int action) + throws NotImplementedException { // TODO: Implement this properly } - public int getSourceActions (JComponent c) + public int getSourceActions(JComponent c) { return sourceActions; } - public Icon getVisualRepresentation (Transferable t) + public Icon getVisualRepresentation(Transferable t) { return visualRepresentation; } - public boolean importData (JComponent c, Transferable t) + public boolean importData(JComponent c, Transferable t) + throws NotImplementedException { return false; } diff --git a/javax/swing/WindowConstants.java b/javax/swing/WindowConstants.java index aaa0cb9a3..598a61e14 100644 --- a/javax/swing/WindowConstants.java +++ b/javax/swing/WindowConstants.java @@ -1,5 +1,5 @@ /* WindowConstants.java -- - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,31 +38,42 @@ exception statement from your version. */ package javax.swing; /** - * Defines some constants that are used in Swing's top-level - * containers. - * + * Defines some constants that are used in Swing's top-level containers. See + * the following methods: + * <ul> + * <li>{@link JFrame#setDefaultCloseOperation(int)};</li> + * <li>{@link JInternalFrame#setDefaultCloseOperation(int)};</li> + * <li>{@link JDialog#setDefaultCloseOperation(int)};</li> + * </ul> + * * @author Andrew Selkirk */ public interface WindowConstants { /** - * DO_NOTHING_ON_CLOSE + * Do nothing when the container is closed. */ int DO_NOTHING_ON_CLOSE = 0; /** - * HIDE_ON_CLOSE + * Hide the container when it is closed. */ int HIDE_ON_CLOSE = 1; /** - * DISPOSE_ON_CLOSE + * Dispose the container when it is closed. + * + * @see Window#dispose() */ int DISPOSE_ON_CLOSE = 2; /** - * EXIT_ON_CLOSE + * Exit the application when the container is closed. + * + * @see System#exit(int) + * + * @since 1.4 */ - int EXIT_ON_CLOSE =3; + int EXIT_ON_CLOSE = 3; } diff --git a/javax/swing/border/AbstractBorder.java b/javax/swing/border/AbstractBorder.java index c995de1c2..16bb238c3 100644 --- a/javax/swing/border/AbstractBorder.java +++ b/javax/swing/border/AbstractBorder.java @@ -194,6 +194,6 @@ public abstract class AbstractBorder implements Border, Serializable height -= borderInsets.top + borderInsets.bottom; } - return new Rectangle (x, y, width, height); + return new Rectangle(x, y, width, height); } } diff --git a/javax/swing/border/BevelBorder.java b/javax/swing/border/BevelBorder.java index 403c35c04..5b4761e9e 100644 --- a/javax/swing/border/BevelBorder.java +++ b/javax/swing/border/BevelBorder.java @@ -479,7 +479,7 @@ public class BevelBorder extends AbstractBorder ((highlightOuter == null) || (highlightOuter.getAlpha() == 255)) && ((highlightInner == null) || (highlightInner.getAlpha() == 255)) && ((shadowInner == null) || (shadowInner.getAlpha() == 255)) - && ((shadowOuter == null) ||(shadowOuter.getAlpha() == 255)); + && ((shadowOuter == null) || (shadowOuter.getAlpha() == 255)); } diff --git a/javax/swing/border/CompoundBorder.java b/javax/swing/border/CompoundBorder.java index a69c5e20a..2ee639cf9 100644 --- a/javax/swing/border/CompoundBorder.java +++ b/javax/swing/border/CompoundBorder.java @@ -178,7 +178,7 @@ public class CompoundBorder extends AbstractBorder Insets borderInsets; if (insets == null) - insets = new Insets (0,0,0,0); + insets = new Insets(0, 0, 0, 0); else insets.left = insets.right = insets.top = insets.bottom = 0; @@ -217,7 +217,7 @@ public class CompoundBorder extends AbstractBorder // the implementation from AbstractBorder. However, we want // to be compatible with the API specification, which overrides // the getBorderInsets(Component) method. - return getBorderInsets (c, null); + return getBorderInsets(c, null); } /** @@ -239,7 +239,7 @@ public class CompoundBorder extends AbstractBorder * * @return The inside border (possibly <code>null</code>). */ - public Border getInsideBorder () + public Border getInsideBorder() { return insideBorder; } diff --git a/javax/swing/border/TitledBorder.java b/javax/swing/border/TitledBorder.java index 38b575423..56146e01d 100644 --- a/javax/swing/border/TitledBorder.java +++ b/javax/swing/border/TitledBorder.java @@ -45,11 +45,10 @@ import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Insets; -import java.awt.Shape; -import java.awt.font.FontRenderContext; -import java.awt.font.LineMetrics; -import java.awt.geom.AffineTransform; +import java.awt.Point; +import java.awt.Rectangle; +import javax.swing.SwingUtilities; import javax.swing.UIManager; @@ -464,191 +463,238 @@ public class TitledBorder extends AbstractBorder public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { - Measurements mes = getMeasurements(c); - Font oldFont = g.getFont(); - Color oldColor = g.getColor(); - - /** - * A local helper class for painting the border without changing - * any pixels inside the rectangle of the title text. - */ - class BorderPainter - { - private Component c; - private Border b; - private int x, y, width, height; - - /** - * Constructs a BorderPainter. - * - * @param c the component whose border is being painted. - * @param b the border object. - * @param x the x coordinate of the rectangle delimiting the border. - * @param y the y coordinate of the rectangle delimiting the border. - * @param width the width of the rectangle delimiting the border. - * @param height the width of the rectangle delimiting the border. - */ - public BorderPainter(Component c, Border b, - int x, int y, int width, int height) - { - this.c = c; - this.b = b; - this.x = x; - this.y = y; - this.width = width; - this.height = height; - } + Rectangle borderRect = new Rectangle(x + EDGE_SPACING, y + EDGE_SPACING, + width - (EDGE_SPACING * 2), + height - (EDGE_SPACING * 2)); + Point textLoc = new Point(); + + // Save color and font. + Color savedColor = g.getColor(); + Font savedFont = g.getFont(); + + // The font metrics. + Font font = getFont(c); + g.setFont(font); + FontMetrics fm = c.getFontMetrics(font); + + layoutBorderWithTitle(c, fm, borderRect, textLoc); + paintBorderWithTitle(c, g, x, y, width, height, borderRect, textLoc, fm); + + g.setColor(getTitleColor()); + g.drawString(getTitle(), textLoc.x, textLoc.y); + g.setFont(savedFont); + g.setColor(savedColor); + } + /** + * Calculates the bounding box of the inner border and the location of the + * title string. + * + * @param c the component on which to paint the border + * @param fm the font metrics + * @param borderRect output parameter, holds the bounding box of the inner + * border on method exit + * @param textLoc output parameter, holds the location of the title text + * on method exit + */ + private void layoutBorderWithTitle(Component c, FontMetrics fm, + Rectangle borderRect, + Point textLoc) + { + Border b = getBorder(); + + // The font metrics. + int fontHeight = fm.getHeight(); + int fontDescent = fm.getDescent(); + int fontAscent = fm.getAscent(); + int titleWidth = fm.stringWidth(getTitle()); + + // The base insets. + Insets insets; + if (b == null) + insets = new Insets(0, 0, 0, 0); + else + insets = b.getBorderInsets(c); - /** - * Paints the entire border. - */ - public void paint(Graphics g) - { - if (b != null) - b.paintBorder(c, g, x, y, width, height); - } + // The offset of the border rectangle, dependend on the title placement. + int offset; + // Layout border and text vertically. + int titlePosition = getTitlePosition(); + switch (titlePosition) + { + case ABOVE_BOTTOM: + textLoc.y = borderRect.y + borderRect.height - insets.bottom + - fontDescent - TEXT_SPACING; + break; + case BOTTOM: + borderRect.height -= fontHeight / 2; + textLoc.y = borderRect.y + borderRect.height - fontDescent + + (fontAscent + fontDescent - insets.bottom) / 2; + break; + case BELOW_BOTTOM: + borderRect.height -= fontHeight; + textLoc.y = borderRect.y + borderRect.height + fontAscent + + TEXT_SPACING; + break; + case ABOVE_TOP: + offset = fontAscent + fontDescent + + Math.max(EDGE_SPACING, TEXT_SPACING * 2) - EDGE_SPACING; + borderRect.y += offset; + borderRect.height -= offset; + textLoc.y = borderRect.y - (fontDescent + TEXT_SPACING); + break; + case BELOW_TOP: + textLoc.y = borderRect.y + insets.top + fontAscent + TEXT_SPACING; + break; + case TOP: + case DEFAULT_POSITION: + default: + offset = Math.max(0, ((fontAscent / 2) + TEXT_SPACING) - EDGE_SPACING); + borderRect.y += offset; + borderRect.height -= offset; + textLoc.y = borderRect.y - fontDescent + + (insets.top + fontAscent + fontDescent) / 2; + break; + } - /** - * Paints the border, clipping the drawing operation to a - * given rectangular area. - */ - private void paint(Graphics g, - int clipX, int clipY, int clipWidth, int clipHeight) + // Layout border and text horizontally. + int justification = getTitleJustification(); + // Adjust justification for LEADING and TRAILING depending on the direction + // of the component. + if (c.getComponentOrientation().isLeftToRight()) { - Shape oldClip = g.getClip(); - try - { - g.clipRect(clipX, clipY, clipWidth, clipHeight); - paint(g); - } - finally - { - g.setClip(oldClip); - } + if (justification == LEADING || justification == DEFAULT_JUSTIFICATION) + justification = LEFT; + else if (justification == TRAILING) + justification = RIGHT; } - - - /** - * Paints the border without affecting a given rectangular area. - * This is used for painting the border without drawing anything - * underneath the title text. - * - * <p>Since we do not want to introduce unnecessary dependencies - * on Java 2D, we perform the clipping without constructive geometry - * (provided by java.awt.geom.Area). Instead, the border’s - * bounding rectangle is split into smaller parts, which are then - * clipped and painted individually.: - * - * <p><pre> - * +--------------------+ +--------------------+ - * | | | 1 | - * | +--------+ | +---+--------+-------+ - * | | hole | | |====> | 2 | hole | 3 | - * | +--------+ | |---+--------+-------+ - * | | | 4 | - * +--------------------+ +--------------------+</pre> - * - */ - public void paintExcept(Graphics g, - int holeX, int holeY, int holeWidth, int holeHeight) + else { - int stripeHeight; - - stripeHeight = holeY - y; - if (stripeHeight > 0) - paint(g, x, y, width, stripeHeight); // patch #1 in the image above - - stripeHeight = holeHeight; - if (stripeHeight > 0) - { - paint(g, x, holeY, holeX - x, stripeHeight); // patches #2 and #3 - paint(g, holeX + holeWidth, holeY, x + width - (holeX + holeWidth), stripeHeight); - } - - stripeHeight = height - (holeY - y + holeHeight); - if (stripeHeight > 0) - paint(g, x, y + height - stripeHeight, width, stripeHeight); // #4 + if (justification == LEADING || justification == DEFAULT_JUSTIFICATION) + justification = RIGHT; + else if (justification == TRAILING) + justification = LEFT; } - }; - - BorderPainter bp; - int textX, textY, borderWidth, borderHeight; - - borderWidth = width - (mes.outerSpacing.left + mes.outerSpacing.right); - borderHeight = height - (mes.outerSpacing.top + mes.outerSpacing.bottom); - bp = new BorderPainter(c, getBorder(), - x + mes.outerSpacing.left, y + mes.outerSpacing.top, - borderWidth, borderHeight); - switch (getRealTitleJustification(c)) + switch (justification) { - case LEFT: - textX = x + EDGE_SPACING + TEXT_INSET_H; - break; - - case CENTER: - textX = x + (borderWidth - mes.textWidth) / 2; - break; - - case RIGHT: - textX = x + borderWidth - (mes.textWidth + TEXT_INSET_H); - break; - - default: - throw new IllegalStateException(); + case CENTER: + textLoc.x = borderRect.x + (borderRect.width - titleWidth) / 2; + break; + case RIGHT: + textLoc.x = borderRect.x + borderRect.width - titleWidth + - TEXT_INSET_H - insets.right; + break; + case LEFT: + default: + textLoc.x = borderRect.x + TEXT_INSET_H + insets.left; } + } - switch (titlePosition) - { - case ABOVE_TOP: - textY = y + EDGE_SPACING; - break; - - case TOP: - case DEFAULT_POSITION: - default: - textY = y + mes.outerSpacing.top + mes.borderInsets.top - mes.textAscent - + mes.lineHeight; - break; - - case BELOW_TOP: - textY = y + mes.outerSpacing.top + mes.borderInsets.top + TEXT_SPACING; - break; - - case ABOVE_BOTTOM: - textY = y + height - mes.outerSpacing.bottom - mes.borderInsets.bottom - - TEXT_SPACING - (mes.textAscent + mes.textDescent); - break; - - case BOTTOM: - case BELOW_BOTTOM: - textY = y + height - (mes.textAscent + mes.textDescent); - break; - } + /** + * Paints the border with the title. + * + * @param c the component to paint on + * @param g the graphics context used for paintin + * @param x the upper left corner of the whole border + * @param y the upper left corner of the whole border + * @param width the width of the whole border + * @param height the width of the whole border + * @param borderRect the bounding box of the inner border + * @param textLoc the location of the border title + * @param fm the font metrics of the title + */ + private void paintBorderWithTitle(Component c, Graphics g, int x, int y, + int width, int height, + Rectangle borderRect, Point textLoc, + FontMetrics fm) + { + Border b = getBorder(); + int fontDescent = fm.getDescent(); + int fontAscent = fm.getAscent(); + int titleWidth = fm.stringWidth(getTitle()); - if (mes.trimmedText == null) - bp.paint(g); - else - { - try + if (b != null) { - g.setFont(mes.font); - g.setColor(getTitleColor()); - g.drawString(mes.trimmedText, textX, textY + mes.textAscent); + // Paint border in segments, when the title is painted above the + // border. + if (((titlePosition == TOP || titlePosition == DEFAULT_POSITION) + && (borderRect.y > textLoc.y - fontAscent)) + || (titlePosition == BOTTOM + && borderRect.y + borderRect.height < textLoc.y + fontDescent)) + { + Rectangle clip = new Rectangle(); + Rectangle saved = g.getClipBounds(); + + // Paint border left from the text. + clip.setBounds(saved); + SwingUtilities.computeIntersection(x, y, textLoc.x - x - 1, + height, clip); + if (! clip.isEmpty()) + { + g.setClip(clip); + b.paintBorder(c, g, borderRect.x, borderRect.y, + borderRect.width, + borderRect.height); + } + // Paint border right from the text. + clip.setBounds(saved); + SwingUtilities.computeIntersection(textLoc.x + titleWidth + 1, y, + x + width - (textLoc.x + titleWidth + 1), height, clip); + if (! clip.isEmpty()) + { + g.setClip(clip); + b.paintBorder(c, g, borderRect.x, borderRect.y, + borderRect.width, + borderRect.height); + } + + if (titlePosition == TOP || titlePosition == DEFAULT_POSITION) + { + // Paint border below the text. + clip.setBounds(saved); + SwingUtilities.computeIntersection(textLoc.x - 1, + textLoc.y + fontDescent, + titleWidth + 2, + y + height - textLoc.y - fontDescent, + clip); + if (! clip.isEmpty()) + { + g.setClip(clip); + b.paintBorder(c, g, borderRect.x, borderRect.y, + borderRect.width, + borderRect.height); + } + + } + else + { + // Paint border above the text. + clip.setBounds(saved); + SwingUtilities.computeIntersection(textLoc.x - 1, y, + titleWidth + 2, + textLoc.y - fontDescent - y, + clip); + if (! clip.isEmpty()) + { + g.setClip(clip); + b.paintBorder(c, g, borderRect.x, borderRect.y, + borderRect.width, + borderRect.height); + } + + } + g.setClip(saved); + } + else + { + b.paintBorder(c, g, borderRect.x, borderRect.y, borderRect.width, + borderRect.height); + } } - finally - { - g.setFont(oldFont); - g.setColor(oldColor); - } - bp.paintExcept(g, textX, textY, - mes.textWidth, mes.textAscent + mes.textDescent); - } } - - + /** * Measures the width of this border. * @@ -682,7 +728,72 @@ public class TitledBorder extends AbstractBorder */ public Insets getBorderInsets(Component c, Insets insets) { - return getMeasurements(c).getContentInsets(insets); + // Initialize insets with the insets from our border. + Border border = getBorder(); + if (border != null) + { + if (border instanceof AbstractBorder) + { + AbstractBorder aBorder = (AbstractBorder) border; + aBorder.getBorderInsets(c, insets); + } + else + { + Insets i = border.getBorderInsets(c); + insets.top = i.top; + insets.bottom = i.bottom; + insets.left = i.left; + insets.right = i.right; + } + } + else + { + insets.top = 0; + insets.bottom = 0; + insets.left = 0; + insets.right = 0; + } + + // Add spacing. + insets.top += EDGE_SPACING + TEXT_SPACING; + insets.bottom += EDGE_SPACING + TEXT_SPACING; + insets.left += EDGE_SPACING + TEXT_SPACING; + insets.right += EDGE_SPACING + TEXT_SPACING; + + String title = getTitle(); + if (c != null && title != null && !title.equals("")) + { + Font font = getFont(c); + FontMetrics fm = c.getFontMetrics(font); + int ascent = fm.getAscent(); + int descent = fm.getDescent(); + int height = fm.getHeight(); + switch (getTitlePosition()) + { + case ABOVE_BOTTOM: + insets.bottom += ascent + descent + TEXT_SPACING; + break; + case BOTTOM: + insets.bottom += ascent + descent; + break; + case BELOW_BOTTOM: + insets.bottom += height; + break; + case ABOVE_TOP: + insets.top += ascent + descent + + Math.max(EDGE_SPACING, TEXT_SPACING * 2) + - EDGE_SPACING; + break; + case BELOW_TOP: + insets.top += ascent + descent + TEXT_SPACING; + break; + case TOP: + case DEFAULT_POSITION: + default: + insets.top += ascent + descent; + } + } + return insets; } @@ -919,7 +1030,26 @@ public class TitledBorder extends AbstractBorder */ public Dimension getMinimumSize(Component c) { - return getMeasurements(c).getMinimumSize(); + Insets i = getBorderInsets(c); + Dimension minSize = new Dimension(i.left + i.right, i.top + i.bottom); + Font font = getFont(c); + FontMetrics fm = c.getFontMetrics(font); + int titleWidth = fm.stringWidth(getTitle()); + switch (getTitlePosition()) + { + case ABOVE_TOP: + case BELOW_BOTTOM: + minSize.width = Math.max(minSize.width, titleWidth); + break; + case BELOW_TOP: + case ABOVE_BOTTOM: + case TOP: + case BOTTOM: + case DEFAULT_POSITION: + default: + minSize.width += titleWidth; + } + return minSize; } @@ -943,253 +1073,4 @@ public class TitledBorder extends AbstractBorder return new Font("Dialog", Font.PLAIN, 12); } - - /** - * Returns the horizontal alignment of the title text in relation to - * the border, mapping the component-dependent alignment constants - * {@link #LEADING}, {@link #TRAILING} and {@link #DEFAULT_JUSTIFICATION} - * to the correct value according to the embedded component’s - * orientation. - * - * @param c the Component for which this TitledBorder is the border. - * - * @return one of the values {@link #LEFT}, {@link #CENTER}, or {@link - * #RIGHT}. - */ - private int getRealTitleJustification(Component c) - { - switch (titleJustification) - { - case DEFAULT_JUSTIFICATION: - case LEADING: - if ((c == null) || c.getComponentOrientation().isLeftToRight()) - return LEFT; - else - return RIGHT; - - case TRAILING: - if ((c == null) || c.getComponentOrientation().isLeftToRight()) - return RIGHT; - else - return LEFT; - - default: - return titleJustification; - } - } - - - /** - * Performs various measurements for the current state of this TitledBorder - * and the given Component. - * - * @param c the component (<code>null</code> not permitted). - * - * @return Various measurements. - */ - private Measurements getMeasurements(Component c) - { - Measurements m = new Measurements(); - FontMetrics fmet; - - m.font = getFont(c); - fmet = c.getFontMetrics(m.font); - m.border = getBorder(); - if (m.border != null) - m.borderInsets = m.border.getBorderInsets(c); - else - m.borderInsets = new Insets(0, 0, 0, 0); - - if (title != null) - { - m.trimmedText = title.trim(); - if (m.trimmedText.length() == 0) - m.trimmedText = null; - } - - if (m.trimmedText != null) - { - m.textAscent = fmet.getAscent(); - m.textDescent = fmet.getDescent() + fmet.getLeading(); - - FontRenderContext frc = new FontRenderContext(new AffineTransform(), - false, false); - LineMetrics lmet = m.font.getLineMetrics(m.trimmedText, 0, - m.trimmedText.length(), frc); - m.lineHeight = (int) lmet.getStrikethroughOffset(); - - // Fallback in case that LineMetrics is not available/working. - if (m.lineHeight == 0) - m.lineHeight = (int) (0.3333 * (double) m.textAscent); - m.textWidth = fmet.stringWidth(m.trimmedText) + 3; - } - else - { - m.textAscent = 0; - m.textDescent = 0; - } - - m.innerSpacing = new Insets(EDGE_SPACING, EDGE_SPACING, EDGE_SPACING, - EDGE_SPACING); - m.outerSpacing = new Insets(EDGE_SPACING, EDGE_SPACING, EDGE_SPACING, - EDGE_SPACING); - - switch (titlePosition) - { - case ABOVE_TOP: - m.outerSpacing.top += m.textAscent + m.textDescent + TEXT_SPACING; - break; - - case TOP: - m.outerSpacing.top += m.textDescent + m.lineHeight; - m.innerSpacing.top += m.textAscent - m.lineHeight; - break; - - case BELOW_TOP: - m.innerSpacing.top += m.textAscent + m.textDescent + TEXT_SPACING; - break; - - case ABOVE_BOTTOM: - m.innerSpacing.bottom += m.textAscent + m.textDescent + TEXT_SPACING; - break; - - case BOTTOM: - m.innerSpacing.bottom += Math.max(m.textAscent - m.lineHeight, 0); - m.outerSpacing.bottom += m.textDescent + m.lineHeight; - break; - - case BELOW_BOTTOM: - m.outerSpacing.bottom += m.textAscent + m.textDescent; - break; - - default: - m.outerSpacing.top += m.textAscent; - } - - return m; - } - - - /** - * A private helper class for holding the result of measuring the - * distances of a TitledBorder. While it would be possible to cache - * these objects, it does not seem to be worth the effort. Note that - * invalidating the cache would be tricky, especially since there is - * no notification mechanism that would inform the cache when - * border has changed, so it would return different insets. - */ - private static class Measurements - { - /** - * The font used for displaying the title text. Note that it can - * well be that the TitledBorder’s font is <code>null</code>, - * which means that the font is to be retrieved from the current - * LookAndFeel. In this case, this <code>font</code> field will - * contain the result of the retrieval. Therefore, it is safe - * to assume that this <code>font</code> field will never have - * a <code>null</code> value. - */ - Font font; - - - /** - * The number of pixels between the base line and the top of the - * text box. - */ - int textAscent; - - - /** - * The number of pixels between the base line and the bottom of - * the text box. - */ - int textDescent; - - /** - * The number of pixels between the base line and the height where - * a strike-through would be drawn. - */ - int lineHeight; - - /** - * The title text after removing leading and trailing white space - * characters. If the title consists only of white space, the - * value of <code>trimmedText</code> will be <code>null</code>. - */ - String trimmedText; - - - /** - * The width of the trimmed title text in pixels. - */ - int textWidth; - - - /** - * The border that constitutes the interior border - * underneath the title text. - */ - Border border; - - - /** - * The distance between the TitledBorder and the interior border. - */ - Insets outerSpacing; - - /** - * The width of the interior border, as returned by - * <code>border.getBorderInsets()</code>. - */ - Insets borderInsets; - - - /** - * The distance between the interior border and the nested - * Component for which this TitledBorder is a border. - */ - Insets innerSpacing; - - - /** - * Determines the insets of the nested component when it has a - * TitledBorder as its border. Used by {@link - * TitledBorder#getBorderInsets(Component, Insets)}. - * - * @param i an Insets object for storing the results into, or - * <code>null</code> to cause the creation of a - * new instance. - * - * @return the <code>i</code> object, or a new Insets object - * if <code>null</code> was passed for <code>i</code>. - */ - public Insets getContentInsets(Insets i) - { - if (i == null) - i = new Insets(0, 0, 0, 0); - i.left = outerSpacing.left + borderInsets.left + innerSpacing.left; - i.right = outerSpacing.right + borderInsets.right + innerSpacing.right; - i.top = outerSpacing.top + borderInsets.top + innerSpacing.top; - i.bottom = outerSpacing.bottom + borderInsets.bottom + innerSpacing.bottom; - return i; - } - - - /** - * Calculates the minimum size needed for displaying the border - * and its title. Used by {@link TitledBorder#getMinimumSize(Component)}. - * - * @return The minimum size. - */ - public Dimension getMinimumSize() - { - int width; - Insets insets; - - insets = getContentInsets(null); - width = Math.max(insets.left + insets.right, textWidth + 2 - * TEXT_INSET_H); - return new Dimension(width, insets.top + insets.bottom); - } - } } diff --git a/javax/swing/plaf/basic/BasicCheckBoxUI.java b/javax/swing/plaf/basic/BasicCheckBoxUI.java index 14dadb85c..1010139b8 100644 --- a/javax/swing/plaf/basic/BasicCheckBoxUI.java +++ b/javax/swing/plaf/basic/BasicCheckBoxUI.java @@ -1,5 +1,5 @@ /* BasicCheckBoxUI.java - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,25 +38,32 @@ exception statement from your version. */ package javax.swing.plaf.basic; -import javax.swing.Icon; +import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; +/** + * A UI delegate for the {@link JCheckBox} component. + */ public class BasicCheckBoxUI extends BasicRadioButtonUI { - public static ComponentUI createUI(final JComponent c) { + /** + * Returns a UI delegate (that is, an instance of this class) for the + * specified component. + * + * @param c the component (this should be a {@link JCheckBox}). + * + * @return A new instance of <code>BasicCheckBoxUI</code>. + */ + public static ComponentUI createUI(JComponent c) { return new BasicCheckBoxUI(); } - public Icon getDefaultIcon() - { - return UIManager.getIcon("CheckBox.icon"); - } - /** - * Returns the prefix for entries in the {@link UIManager} defaults table. + * Returns the prefix for entries in the {@link UIManager} defaults table + * (<code>"CheckBox."</code> in this case). * * @return "CheckBox." */ diff --git a/javax/swing/plaf/basic/BasicComboBoxUI.java b/javax/swing/plaf/basic/BasicComboBoxUI.java index 557eea93f..0f0949543 100644 --- a/javax/swing/plaf/basic/BasicComboBoxUI.java +++ b/javax/swing/plaf/basic/BasicComboBoxUI.java @@ -38,8 +38,6 @@ exception statement from your version. */ package javax.swing.plaf.basic; -import gnu.classpath.NotImplementedException; - import java.awt.Color; import java.awt.Component; import java.awt.Container; @@ -66,12 +64,14 @@ import javax.swing.CellRendererPane; import javax.swing.ComboBoxEditor; import javax.swing.ComboBoxModel; import javax.swing.DefaultListCellRenderer; +import javax.swing.InputMap; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JList; import javax.swing.ListCellRenderer; import javax.swing.LookAndFeel; +import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; @@ -974,19 +974,23 @@ public class BasicComboBoxUI extends ComboBoxUI * by the look and feel. */ protected void installKeyboardActions() - throws NotImplementedException { - // FIXME: Need to implement. + SwingUtilities.replaceUIInputMap(comboBox, + JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, + (InputMap) UIManager.get("ComboBox.ancestorInputMap")); + + // Install any action maps here. } - + /** * Uninstalls the keyboard actions for the {@link JComboBox} there were * installed by in {@link #installListeners}. */ protected void uninstallKeyboardActions() - throws NotImplementedException { - // FIXME: Need to implement. + SwingUtilities.replaceUIInputMap(comboBox, + JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null); + // Uninstall any action maps here. } /** diff --git a/javax/swing/plaf/basic/BasicComboPopup.java b/javax/swing/plaf/basic/BasicComboPopup.java index d4eabc602..0d822955b 100644 --- a/javax/swing/plaf/basic/BasicComboPopup.java +++ b/javax/swing/plaf/basic/BasicComboPopup.java @@ -38,8 +38,6 @@ exception statement from your version. */ package javax.swing.plaf.basic; -import gnu.classpath.NotImplementedException; - import java.awt.Color; import java.awt.Component; import java.awt.Dimension; @@ -294,9 +292,8 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup * This method uninstalls keyboard actions installed by the UI. */ protected void uninstallKeyboardActions() - throws NotImplementedException { - // FIXME: Need to implement + // Nothing to do here. } /** @@ -559,12 +556,11 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup } /** - * DOCUMENT ME! + * Installs the keyboard actions. */ protected void installKeyboardActions() - throws NotImplementedException { - // FIXME: Need to implement + // Nothing to do here } /** diff --git a/javax/swing/plaf/basic/BasicInternalFrameUI.java b/javax/swing/plaf/basic/BasicInternalFrameUI.java index 7ec3aa074..a5f87653f 100644 --- a/javax/swing/plaf/basic/BasicInternalFrameUI.java +++ b/javax/swing/plaf/basic/BasicInternalFrameUI.java @@ -1,5 +1,5 @@ /* BasicInternalFrameUI.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -57,6 +57,7 @@ import java.awt.event.ComponentListener; import java.awt.event.MouseEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.beans.PropertyVetoException; import javax.swing.DefaultDesktopManager; import javax.swing.DesktopManager; @@ -168,10 +169,9 @@ public class BasicInternalFrameUI extends InternalFrameUI implements SwingConstants { /** - * If true, the cursor is being already shown in the alternative "resize" - * shape. + * The current shape of the cursor. */ - transient boolean showingResizeCursor; + transient int showingCursor; /** FIXME: Use for something. */ protected final int RESIZE_NONE = 0; @@ -187,7 +187,7 @@ public class BasicInternalFrameUI extends InternalFrameUI /** Cache rectangle that can be reused. */ private transient Rectangle cacheRect = new Rectangle(); - + /** * This method is called when the mouse is clicked. * @@ -195,6 +195,20 @@ public class BasicInternalFrameUI extends InternalFrameUI */ public void mouseClicked(MouseEvent e) { + // Do minimization/maximization when double-clicking in the title pane. + if (e.getSource() == titlePane && e.getClickCount() == 2) + try + { + if (frame.isMaximizable() && ! frame.isMaximum()) + frame.setMaximum(true); + else if (frame.isMaximum()) + frame.setMaximum(false); + } + catch (PropertyVetoException pve) + { + // We do nothing if the attempt has been vetoed. + } + // There is nothing to do when the mouse is clicked // on the border. } @@ -223,34 +237,34 @@ public class BasicInternalFrameUI extends InternalFrameUI { switch (direction) { - case NORTH: + case Cursor.N_RESIZE_CURSOR: cacheRect.setBounds(b.x, Math.min(b.y + y, b.y + b.height - min.height), b.width, b.height - y); break; - case NORTH_EAST: + case Cursor.NE_RESIZE_CURSOR: cacheRect.setBounds(b.x, Math.min(b.y + y, b.y + b.height - - min.height), x, + - min.height), x + 1, b.height - y); break; - case EAST: - cacheRect.setBounds(b.x, b.y, x, b.height); + case Cursor.E_RESIZE_CURSOR: + cacheRect.setBounds(b.x, b.y, x + 1, b.height); break; - case SOUTH_EAST: - cacheRect.setBounds(b.x, b.y, x, y); + case Cursor.SE_RESIZE_CURSOR: + cacheRect.setBounds(b.x, b.y, x + 1, y + 1); break; - case SOUTH: - cacheRect.setBounds(b.x, b.y, b.width, y); + case Cursor.S_RESIZE_CURSOR: + cacheRect.setBounds(b.x, b.y, b.width, y + 1); break; - case SOUTH_WEST: + case Cursor.SW_RESIZE_CURSOR: cacheRect.setBounds(Math.min(b.x + x, b.x + b.width - min.width), - b.y, b.width - x, y); + b.y, b.width - x, y + 1); break; - case WEST: + case Cursor.W_RESIZE_CURSOR: cacheRect.setBounds(Math.min(b.x + x, b.x + b.width - min.width), b.y, b.width - x, b.height); break; - case NORTH_WEST: + case Cursor.NW_RESIZE_CURSOR: cacheRect.setBounds( Math.min(b.x + x, b.x + b.width - min.width), Math.min(b.y + y, b.y + b.height - min.height), @@ -260,6 +274,7 @@ public class BasicInternalFrameUI extends InternalFrameUI dm.resizeFrame(frame, cacheRect.x, cacheRect.y, Math.max(min.width, cacheRect.width), Math.max(min.height, cacheRect.height)); + setCursor(e); } else if (e.getSource() == titlePane) { @@ -277,11 +292,10 @@ public class BasicInternalFrameUI extends InternalFrameUI */ public void mouseExited(MouseEvent e) { - // Reset the cursor shape. - if (showingResizeCursor) + if (showingCursor != Cursor.DEFAULT_CURSOR) { frame.setCursor(Cursor.getDefaultCursor()); - showingResizeCursor = false; + showingCursor = Cursor.DEFAULT_CURSOR; } } @@ -293,53 +307,36 @@ public class BasicInternalFrameUI extends InternalFrameUI public void mouseMoved(MouseEvent e) { // Turn off the resize cursor if we are in the frame header. - if (showingResizeCursor && e.getSource() != frame) + if (showingCursor != Cursor.DEFAULT_CURSOR && e.getSource() != frame) { frame.setCursor(Cursor.getDefaultCursor()); - showingResizeCursor = false; + showingCursor = Cursor.DEFAULT_CURSOR; } else if (e.getSource()==frame && frame.isResizable()) { - int cursor; - switch (sectionOfClick(e.getX(), e.getY())) - { - case NORTH: - cursor = Cursor.N_RESIZE_CURSOR; - break; - case NORTH_EAST: - cursor = Cursor.NE_RESIZE_CURSOR; - break; - case EAST: - cursor = Cursor.E_RESIZE_CURSOR; - break; - case SOUTH_EAST: - cursor = Cursor.SE_RESIZE_CURSOR; - break; - case SOUTH: - cursor = Cursor.S_RESIZE_CURSOR; - break; - case SOUTH_WEST: - cursor = Cursor.SW_RESIZE_CURSOR; - break; - case WEST: - cursor = Cursor.W_RESIZE_CURSOR; - break; - case NORTH_WEST: - cursor = Cursor.NW_RESIZE_CURSOR; - break; - default: - cursor = Cursor.DEFAULT_CURSOR; - } - + setCursor(e); + } + } + + /** + * Set the mouse cursor, how applicable. + * + * @param e the current mouse event. + */ + void setCursor(MouseEvent e) + { + int cursor = sectionOfClick(e.getX(), e.getY()); + if (cursor != showingCursor) + { Cursor resize = Cursor.getPredefinedCursor(cursor); frame.setCursor(resize); - showingResizeCursor = true; + showingCursor = cursor; } } /** * This method is called when the mouse is pressed. - * + * * @param e The MouseEvent. */ public void mousePressed(MouseEvent e) @@ -383,6 +380,8 @@ public class BasicInternalFrameUI extends InternalFrameUI dm.endDraggingFrame(frame); frame.putClientProperty("bufferedDragging", null); } + + setCursor(e); } /** @@ -392,30 +391,31 @@ public class BasicInternalFrameUI extends InternalFrameUI * @param x The x coordinate of the MouseEvent. * @param y The y coordinate of the MouseEvent. * - * @return The direction of the resize (a SwingConstant direction). + * @return The cursor constant, determining the resizing direction. */ private int sectionOfClick(int x, int y) { - Insets insets = frame.getInsets(); Rectangle b = frame.getBounds(); - if (x < insets.left && y < insets.top) - return NORTH_WEST; - else if (x > b.width - insets.right && y < insets.top) - return NORTH_EAST; - else if (x > b.width - insets.right && y > b.height - insets.bottom) - return SOUTH_EAST; - else if (x < insets.left && y > b.height - insets.bottom) - return SOUTH_WEST; - else if (y < insets.top) - return NORTH; - else if (x < insets.left) - return WEST; - else if (y > b.height - insets.bottom) - return SOUTH; - else if (x > b.width - insets.right) - return EAST; - - return -1; + int corner = InternalFrameBorder.cornerSize; + + if (x < corner && y < corner) + return Cursor.NW_RESIZE_CURSOR; + else if (x > b.width - corner && y < corner) + return Cursor.NE_RESIZE_CURSOR; + else if (x > b.width - corner && y > b.height - corner) + return Cursor.SE_RESIZE_CURSOR; + else if (x < corner && y > b.height - corner) + return Cursor.SW_RESIZE_CURSOR; + else if (y < corner) + return Cursor.N_RESIZE_CURSOR; + else if (x < corner) + return Cursor.W_RESIZE_CURSOR; + else if (y > b.height - corner) + return Cursor.S_RESIZE_CURSOR; + else if (x > b.width - corner) + return Cursor.E_RESIZE_CURSOR; + + return Cursor.DEFAULT_CURSOR; } } @@ -992,14 +992,18 @@ public class BasicInternalFrameUI extends InternalFrameUI /** * This helper class is the border for the JInternalFrame. */ - private class InternalFrameBorder extends AbstractBorder implements + class InternalFrameBorder extends AbstractBorder implements UIResource { - /** The width of the border. */ - private static final int bSize = 5; + /** + * The width of the border. + */ + static final int bSize = 5; - /** The size of the corners. */ - private static final int offset = 10; + /** + * The size of the corners (also used by the mouse listener). + */ + static final int cornerSize = 10; /** * This method returns whether the border is opaque. @@ -1069,10 +1073,12 @@ public class BasicInternalFrameUI extends InternalFrameUI g.fillRect(0, y3, b.width, bSize); g.fillRect(x3, 0, bSize, b.height); - g.fill3DRect(0, offset, bSize, b.height - 2 * offset, false); - g.fill3DRect(offset, 0, b.width - 2 * offset, bSize, false); - g.fill3DRect(offset, b.height - bSize, b.width - 2 * offset, bSize, false); - g.fill3DRect(b.width - bSize, offset, bSize, b.height - 2 * offset, false); + g.fill3DRect(0, cornerSize, bSize, b.height - 2 * cornerSize, false); + g.fill3DRect(cornerSize, 0, b.width - 2 * cornerSize, bSize, false); + g.fill3DRect(cornerSize, b.height - bSize, b.width - 2 * cornerSize, + bSize, false); + g.fill3DRect(b.width - bSize, cornerSize, bSize, + b.height - 2 * cornerSize, false); g.translate(-x, -y); g.setColor(saved); diff --git a/javax/swing/plaf/basic/BasicPanelUI.java b/javax/swing/plaf/basic/BasicPanelUI.java index 4f535f653..458f10204 100644 --- a/javax/swing/plaf/basic/BasicPanelUI.java +++ b/javax/swing/plaf/basic/BasicPanelUI.java @@ -1,5 +1,5 @@ /* BasicPanelUI.java - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -44,33 +44,68 @@ import javax.swing.LookAndFeel; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.PanelUI; +/** + * A UI delegate for the {@link JPanel} component. + */ public class BasicPanelUI extends PanelUI { - public static ComponentUI createUI(JComponent x) + /** + * A UI delegate that can be shared by all panels (because the delegate is + * stateless). + */ + static BasicPanelUI sharedUI; + + /** + * Returns a UI delegate for the specified component. + * + * @param panel the panel. + */ + public static ComponentUI createUI(JComponent panel) { - return new BasicPanelUI(); + if (sharedUI == null) + sharedUI = new BasicPanelUI(); + return sharedUI; } + /** + * Installs this UI delegate in the specified component. + * + * @param c the component (should be a {@link JPanel}, <code>null</code> not + * permitted). + */ public void installUI(JComponent c) { super.installUI(c); if (c instanceof JPanel) { - JPanel p = (JPanel) c; - installDefaults(p); + JPanel p = (JPanel) c; + installDefaults(p); } } + /** + * Installs the defaults for this UI delegate in the specified panel. + * + * @param p the panel (<code>null</code> not permitted). + */ protected void installDefaults(JPanel p) { LookAndFeel.installColorsAndFont(p, "Panel.background", "Panel.foreground", "Panel.font"); + + // A test against the reference implementation shows that this method will + // install a border if one is defined in the UIDefaults table (even though + // the BasicLookAndFeel doesn't actually define a "Panel.border"). This + // test was written after discovering that a null argument to + // uninstallDefaults throws a NullPointerException in + // LookAndFeel.uninstallBorder()... + LookAndFeel.installBorder(p, "Panel.border"); } /** - * Uninstalls this UI from the JPanel. + * Uninstalls this UI delegate from the specified component. * - * @param c the JPanel from which to uninstall this UI + * @param c the component (<code>null</code> not permitted). */ public void uninstallUI(JComponent c) { @@ -78,13 +113,20 @@ public class BasicPanelUI extends PanelUI } /** - * Uninstalls the UI defaults that have been install through - * {@link #installDefaults}. + * Uninstalls the UI defaults for the specified panel. * - * @param p the panel from which to uninstall the UI defaults + * @param p the panel (<code>null</code> not permitted). */ protected void uninstallDefaults(JPanel p) { - // Nothing to do here. + // Tests on the reference implementation showed this method: + // (1) doesn't actually remove the installed colors and font installed + // by installDefaults(), it isn't necessary; + // (2) throws a NullPointerException in LookAndFeel.uninstallBorder() if + // p is null. Strangely, no border is installed by the + // BasicLookAndFeel - perhaps this is needed by another LAF? + + LookAndFeel.uninstallBorder(p); } + } diff --git a/javax/swing/plaf/basic/BasicRadioButtonUI.java b/javax/swing/plaf/basic/BasicRadioButtonUI.java index a66fa28e6..64a1deca5 100644 --- a/javax/swing/plaf/basic/BasicRadioButtonUI.java +++ b/javax/swing/plaf/basic/BasicRadioButtonUI.java @@ -1,5 +1,5 @@ /* BasicRadioButtonUI.java - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -167,9 +167,8 @@ public class BasicRadioButtonUI extends BasicToggleButtonUI } if (text != null) paintText(g, b, tr, text); - // TODO: Figure out what is the size parameter? if (b.hasFocus() && b.isFocusPainted() && m.isEnabled()) - paintFocus(g, tr, null); + paintFocus(g, tr, c.getSize()); } /** @@ -177,9 +176,8 @@ public class BasicRadioButtonUI extends BasicToggleButtonUI * * @param g the graphics context * @param tr the rectangle for the text label - * @param size the size (??) + * @param size the size of the <code>JRadioButton</code> component. */ - // TODO: Figure out what for is the size parameter. protected void paintFocus(Graphics g, Rectangle tr, Dimension size) { Color focusColor = UIManager.getColor(getPropertyPrefix() + ".focus"); diff --git a/javax/swing/plaf/basic/BasicSliderUI.java b/javax/swing/plaf/basic/BasicSliderUI.java index 137ab55a6..0569768a6 100644 --- a/javax/swing/plaf/basic/BasicSliderUI.java +++ b/javax/swing/plaf/basic/BasicSliderUI.java @@ -38,8 +38,6 @@ exception statement from your version. */ package javax.swing.plaf.basic; -import gnu.classpath.NotImplementedException; - import java.awt.Color; import java.awt.Component; import java.awt.ComponentOrientation; @@ -70,6 +68,7 @@ import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JSlider; import javax.swing.LookAndFeel; +import javax.swing.RepaintManager; import javax.swing.SwingUtilities; import javax.swing.Timer; import javax.swing.UIManager; @@ -209,9 +208,9 @@ public class BasicSliderUI extends SliderUI * @param e A {@link FocusEvent}. */ public void focusGained(FocusEvent e) - throws NotImplementedException { - // FIXME: implement. + slider.repaint(); + hasFocus = true; } /** @@ -221,9 +220,9 @@ public class BasicSliderUI extends SliderUI * @param e A {@link FocusEvent}. */ public void focusLost(FocusEvent e) - throws NotImplementedException { - // FIXME: implement. + slider.repaint(); + hasFocus = false; } } @@ -592,6 +591,9 @@ public class BasicSliderUI extends SliderUI /** The focus color. */ private transient Color focusColor; + + /** True if the slider has focus. */ + private transient boolean hasFocus; /** * Creates a new Basic look and feel Slider UI. @@ -1548,9 +1550,11 @@ public class BasicSliderUI extends SliderUI paintTicks(g); if (slider.getPaintLabels()) paintLabels(g); - - //FIXME: Paint focus. + paintThumb(g); + + if (hasFocus) + paintFocus(g); } /** @@ -1602,7 +1606,7 @@ public class BasicSliderUI extends SliderUI Color saved_color = g.getColor(); g.setColor(getFocusColor()); - + g.drawRect(focusRect.x, focusRect.y, focusRect.width, focusRect.height); g.setColor(saved_color); @@ -1989,7 +1993,7 @@ public class BasicSliderUI extends SliderUI public void paintThumb(Graphics g) { Color saved_color = g.getColor(); - + Point a = new Point(thumbRect.x, thumbRect.y); Point b = new Point(a); Point c = new Point(a); @@ -1997,11 +2001,11 @@ public class BasicSliderUI extends SliderUI Point e = new Point(a); Polygon bright; - Polygon light; // light shadow - Polygon dark; // dark shadow + Polygon light; // light shadow + Polygon dark; // dark shadow Polygon all; - // This will be in X-dimension if the slider is inverted and y if it isn't. + // This will be in X-dimension if the slider is inverted and y if it isn't. int turnPoint; if (slider.getOrientation() == JSlider.HORIZONTAL) @@ -2016,13 +2020,15 @@ public class BasicSliderUI extends SliderUI bright = new Polygon(new int[] { b.x - 1, a.x, e.x, d.x }, new int[] { b.y, a.y, e.y, d.y }, 4); - dark = new Polygon(new int[] { b.x, c.x, d.x + 1 }, - new int[] { b.y, c.y - 1, d.y }, 3); - - light = new Polygon(new int[] { b.x - 1, c.x - 1, d.x + 1 }, - new int[] { b.y + 1, c.y - 1, d.y - 1 }, 3); - - all = new Polygon(new int[] { a.x + 1, b.x - 2, c.x - 2, d.x, e.x + 1 }, + dark = new Polygon(new int[] { b.x, c.x, d.x + 1 }, new int[] { b.y, + c.y - 1, + d.y }, 3); + + light = new Polygon(new int[] { b.x - 1, c.x - 1, d.x + 1 }, + new int[] { b.y + 1, c.y - 1, d.y - 1 }, 3); + + all = new Polygon( + new int[] { a.x + 1, b.x - 2, c.x - 2, d.x, e.x + 1 }, new int[] { a.y + 1, b.y + 1, c.y - 1, d.y - 1, e.y }, 5); } @@ -2038,15 +2044,16 @@ public class BasicSliderUI extends SliderUI bright = new Polygon(new int[] { c.x - 1, b.x, a.x, e.x }, new int[] { c.y - 1, b.y, a.y, e.y - 1 }, 4); - dark = new Polygon(new int[] { c.x, d.x, e.x }, - new int[] { c.y, d.y, e.y }, 3); + dark = new Polygon(new int[] { c.x, d.x, e.x }, new int[] { c.y, d.y, + e.y }, 3); - light = new Polygon(new int[] { c.x - 1, d.x, e.x + 1}, - new int[] { c.y, d.y - 1, e.y - 1}, 3); - all = new Polygon(new int[] { a.x + 1, b.x, c.x - 2, c.x - 2, d.x, - e.x + 1 }, - new int[] { a.y + 1, b.y + 1, c.y - 1, c.y, d.y - 2, - e.y - 2 }, 6); + light = new Polygon(new int[] { c.x - 1, d.x, e.x + 1 }, + new int[] { c.y, d.y - 1, e.y - 1 }, 3); + all = new Polygon(new int[] { a.x + 1, b.x, c.x - 2, c.x - 2, d.x, + e.x + 1 }, new int[] { a.y + 1, b.y + 1, + c.y - 1, c.y, + d.y - 2, e.y - 2 }, + 6); } g.setColor(Color.WHITE); @@ -2057,7 +2064,7 @@ public class BasicSliderUI extends SliderUI g.setColor(Color.GRAY); g.drawPolyline(light.xpoints, light.ypoints, light.npoints); - + g.setColor(Color.LIGHT_GRAY); g.drawPolyline(all.xpoints, all.ypoints, all.npoints); g.fillPolygon(all); diff --git a/javax/swing/plaf/basic/BasicTableHeaderUI.java b/javax/swing/plaf/basic/BasicTableHeaderUI.java index cfbebda21..ce8846ff8 100644 --- a/javax/swing/plaf/basic/BasicTableHeaderUI.java +++ b/javax/swing/plaf/basic/BasicTableHeaderUI.java @@ -199,10 +199,7 @@ public class BasicTableHeaderUI extends TableHeaderUI */ public void mouseExited(MouseEvent e) { - if (header.getResizingColumn() != null && header.getResizingAllowed()) - endResizing(); - if (header.getDraggedColumn() != null && header.getReorderingAllowed()) - endDragging(null); + // Nothing to do. } /** @@ -363,25 +360,20 @@ public class BasicTableHeaderUI extends TableHeaderUI void endDragging(MouseEvent e) { header.setDraggedColumn(null); - - // Return if the mouse have left the header area while pressed. - if (e == null) - { - header.repaint(draggingHeaderRect); - draggingHeaderRect = null; - return; - } - else - draggingHeaderRect = null; + draggingHeaderRect = null; TableColumnModel model = header.getColumnModel(); // Find where have we dragged the column. int x = e.getX(); int p = 0; - int col = - 1; + + int col = model.getColumnCount()-1; int n = model.getColumnCount(); + // This loop does not find the column if the mouse if out of the + // right boundary of the table header. Then we make this column the + // rightmost column. Scan: for (int i = 0; i < n; i++) { p += model.getColumn(i).getWidth(); @@ -391,8 +383,8 @@ public class BasicTableHeaderUI extends TableHeaderUI break Scan; } } - if (col >= 0) - header.getTable().moveColumn(draggingColumnNumber, col); + + header.getTable().moveColumn(draggingColumnNumber, col); } } diff --git a/javax/swing/plaf/basic/BasicTableUI.java b/javax/swing/plaf/basic/BasicTableUI.java index ef491cbf1..64638b45a 100644 --- a/javax/swing/plaf/basic/BasicTableUI.java +++ b/javax/swing/plaf/basic/BasicTableUI.java @@ -428,7 +428,6 @@ public class BasicTableUI extends TableUI table.setSelectionForeground(UIManager.getColor("Table.selectionForeground")); table.setSelectionBackground(UIManager.getColor("Table.selectionBackground")); table.setOpaque(true); - rendererPane = new CellRendererPane(); } protected void installKeyboardActions() @@ -1188,6 +1187,9 @@ public class BasicTableUI extends TableUI public void installUI(JComponent comp) { table = (JTable)comp; + rendererPane = new CellRendererPane(); + table.add(rendererPane); + installDefaults(); installKeyboardActions(); installListeners(); @@ -1197,7 +1199,11 @@ public class BasicTableUI extends TableUI { uninstallListeners(); uninstallKeyboardActions(); - uninstallDefaults(); + uninstallDefaults(); + + table.remove(rendererPane); + rendererPane = null; + table = null; } /** @@ -1257,7 +1263,6 @@ public class BasicTableUI extends TableUI } Rectangle bounds = table.getCellRect(r0, c0, false); - // The left boundary of the area being repainted. int left = bounds.x; @@ -1278,9 +1283,9 @@ public class BasicTableUI extends TableUI bounds.x += widths[c] + columnMargin; } bounds.x = left; - bounds.y += table.getRowHeight(r) + rowMargin; + bounds.y += table.getRowHeight(r); // Update row height for tables with custom heights. - bounds.height = table.getRowHeight(r + 1); + bounds.height = table.getRowHeight(r + 1) - rowMargin; } bottom = bounds.y - rowMargin; @@ -1311,7 +1316,7 @@ public class BasicTableUI extends TableUI { // The horizontal grid is draw below the cells, so we // add before drawing. - y += table.getRowHeight(r) + rowMargin; + y += table.getRowHeight(r);// + rowMargin; gfx.drawLine(left, y, p2.x, y); } gfx.setColor(save); diff --git a/javax/swing/plaf/basic/BasicTextUI.java b/javax/swing/plaf/basic/BasicTextUI.java index 3b620f049..6fa37af5c 100644 --- a/javax/swing/plaf/basic/BasicTextUI.java +++ b/javax/swing/plaf/basic/BasicTextUI.java @@ -38,8 +38,6 @@ exception statement from your version. */ package javax.swing.plaf.basic; -import gnu.classpath.NotImplementedException; - import java.awt.Color; import java.awt.Container; import java.awt.Dimension; @@ -831,9 +829,9 @@ public abstract class BasicTextUI extends TextUI * this UI. */ protected void uninstallKeyboardActions() - throws NotImplementedException { - // FIXME: Uninstall keyboard actions here. + SwingUtilities.replaceUIInputMap(textComponent, JComponent.WHEN_FOCUSED, null); + SwingUtilities.replaceUIActionMap(textComponent, null); } /** diff --git a/javax/swing/plaf/basic/BasicToggleButtonUI.java b/javax/swing/plaf/basic/BasicToggleButtonUI.java index 896ea0c89..921648670 100644 --- a/javax/swing/plaf/basic/BasicToggleButtonUI.java +++ b/javax/swing/plaf/basic/BasicToggleButtonUI.java @@ -1,5 +1,5 @@ /* BasicToggleButtonUI.java - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -44,21 +44,35 @@ import java.awt.Rectangle; import javax.swing.AbstractButton; import javax.swing.JComponent; +import javax.swing.JToggleButton; import javax.swing.SwingUtilities; +import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; +/** + * A UI delegate for the {@link JToggleButton} component. + */ public class BasicToggleButtonUI extends BasicButtonUI { - public static ComponentUI createUI(final JComponent component) + + /** + * Returns a UI delegate for the specified component. + * + * @param component the component (should be an instance of + * {@link JToggleButton}). + * + * @return An instance of <code>BasicToggleButtonUI</code>. + */ + public static ComponentUI createUI(JComponent component) { return new BasicToggleButtonUI(); } /** - * Returns the prefix for the UI defaults property for this UI class. - * This is 'ToggleButton' for this class. + * Returns the prefix for entries in the {@link UIManager} defaults table + * (<code>"ToggleButton."</code> in this case). * - * @return the prefix for the UI defaults property + * @return <code>"ToggleButton."</code> */ protected String getPropertyPrefix() { @@ -89,15 +103,10 @@ public class BasicToggleButtonUI extends BasicButtonUI else vr = SwingUtilities.getLocalBounds(b); String text = SwingUtilities.layoutCompoundLabel(c, g.getFontMetrics(f), - b.getText(), - currentIcon(b), - b.getVerticalAlignment(), - b.getHorizontalAlignment(), - b.getVerticalTextPosition(), - b.getHorizontalTextPosition(), - vr, ir, tr, - b.getIconTextGap() - + defaultTextShiftOffset); + b.getText(), currentIcon(b), b.getVerticalAlignment(), + b.getHorizontalAlignment(), b.getVerticalTextPosition(), + b.getHorizontalTextPosition(), vr, ir, tr, b.getIconTextGap() + + defaultTextShiftOffset); if ((b.getModel().isArmed() && b.getModel().isPressed()) || b.isSelected()) diff --git a/javax/swing/plaf/basic/BasicToolBarUI.java b/javax/swing/plaf/basic/BasicToolBarUI.java index 80fec6a77..eabac1570 100644 --- a/javax/swing/plaf/basic/BasicToolBarUI.java +++ b/javax/swing/plaf/basic/BasicToolBarUI.java @@ -1,5 +1,5 @@ /* BasicToolBarUI.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -75,11 +75,12 @@ import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.border.Border; -import javax.swing.border.EtchedBorder; +import javax.swing.border.CompoundBorder; import javax.swing.event.MouseInputListener; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ToolBarUI; import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicBorders.ButtonBorder; /** * This is the Basic Look and Feel UI class for JToolBar. @@ -310,8 +311,19 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants */ protected Border createNonRolloverBorder() { - return new EtchedBorder(); - } + Border b = UIManager.getBorder("ToolBar.nonrolloverBorder"); + + if (b == null) + { + b = new CompoundBorder( + new ButtonBorder(UIManager.getColor("Button.shadow"), + UIManager.getColor("Button.darkShadow"), + UIManager.getColor("Button.light"), + UIManager.getColor("Button.highlight")), + BasicBorders.getMarginBorder()); + } + + return b; } /** * This method creates a new PropertyChangeListener for the JToolBar. @@ -331,18 +343,19 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants */ protected Border createRolloverBorder() { - return new EtchedBorder() + Border b = UIManager.getBorder("ToolBar.rolloverBorder"); + + if (b == null) { - public void paintBorder(Component c, Graphics g, int x, int y, - int width, int height) - { - if (c instanceof JButton) - { - if (((JButton) c).getModel().isRollover()) - super.paintBorder(c, g, x, y, width, height); - } - } - }; + b = new CompoundBorder( + new ButtonBorder(UIManager.getColor("Button.shadow"), + UIManager.getColor("Button.darkShadow"), + UIManager.getColor("Button.light"), + UIManager.getColor("Button.highlight")), + BasicBorders.getMarginBorder()); + } + + return b; } /** @@ -745,6 +758,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants * @param direction The direction to give focus to. */ protected void navigateFocusedComp(int direction) + throws NotImplementedException { // FIXME: Implement. } @@ -761,6 +775,10 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants { AbstractButton b = (AbstractButton) c; b.setRolloverEnabled(false); + + // Save old border in hashtable. + borders.put(b, b.getBorder()); + b.setBorder(nonRolloverBorder); } } @@ -772,11 +790,11 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants */ protected void setBorderToNormal(Component c) { - if (c instanceof JButton) + if (c instanceof AbstractButton) { - JButton b = (JButton) c; - Border border = (Border) borders.get(b); - b.setBorder(border); + AbstractButton b = (AbstractButton) c; + b.setRolloverEnabled(true); + b.setBorder((Border) borders.remove(b)); } } @@ -787,11 +805,15 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants */ protected void setBorderToRollover(Component c) { - if (c instanceof JButton) + if (c instanceof AbstractButton) { - JButton b = (JButton) c; - b.setRolloverEnabled(true); - b.setBorder(rolloverBorder); + AbstractButton b = (AbstractButton) c; + b.setRolloverEnabled(false); + + // Save old border in hashtable. + borders.put(b, b.getBorder()); + + b.setBorder(rolloverBorder); } } diff --git a/javax/swing/plaf/basic/BasicTreeUI.java b/javax/swing/plaf/basic/BasicTreeUI.java index 48ad1b93d..df8fbd01d 100644 --- a/javax/swing/plaf/basic/BasicTreeUI.java +++ b/javax/swing/plaf/basic/BasicTreeUI.java @@ -38,6 +38,7 @@ package javax.swing.plaf.basic; +import gnu.classpath.NotImplementedException; import gnu.javax.swing.tree.GnuPath; import java.awt.Color; @@ -251,6 +252,9 @@ public class BasicTreeUI /** The max height of the nodes in the tree. */ int maxHeight = 0; + + /** The hash color. */ + Color hashColor; /** Listeners */ PropertyChangeListener propertyChangeListener; @@ -279,6 +283,11 @@ public class BasicTreeUI * not the double mouse click) on the selected tree node. */ Timer startEditTimer; + + /** + * The zero size icon, used for expand controls, if they are not visible. + */ + static Icon nullIcon; /** * The special value of the mouse event is sent indicating that this is not @@ -331,7 +340,7 @@ public class BasicTreeUI */ protected Color getHashColor() { - return UIManager.getColor("Tree.hash"); + return hashColor; } /** @@ -341,8 +350,7 @@ public class BasicTreeUI */ protected void setHashColor(Color color) { - // FIXME: Putting something in the UIDefaults map is certainly wrong. - UIManager.put("Tree.hash", color); + hashColor = color; } /** @@ -673,6 +681,20 @@ public class BasicTreeUI treeState.setRowHeight(maxHeight); return maxHeight; } + + /** + * Get the tree node icon. + */ + Icon getNodeIcon(TreePath path) + { + Object node = path.getLastPathComponent(); + if (treeModel.isLeaf(node)) + return UIManager.getIcon("Tree.leafIcon"); + else if (treeState.getExpandedState(path)) + return UIManager.getIcon("Tree.openIcon"); + else + return UIManager.getIcon("Tree.closedIcon"); + } /** * Returns the path for passed in row. If row is not visible null is returned. @@ -800,6 +822,7 @@ public class BasicTreeUI * default/listeners have been installed. */ protected void prepareForUIInstall() + throws NotImplementedException { // TODO: Implement this properly. } @@ -809,6 +832,7 @@ public class BasicTreeUI * installed. */ protected void completeUIInstall() + throws NotImplementedException { // TODO: Implement this properly. } @@ -818,6 +842,7 @@ public class BasicTreeUI * uninstalled. */ protected void completeUIUninstall() + throws NotImplementedException { // TODO: Implement this properly. } @@ -1132,14 +1157,10 @@ public class BasicTreeUI protected void updateRenderer() { if (tree != null) - { - if (tree.getCellRenderer() == null) - { - if (currentCellRenderer == null) - currentCellRenderer = createDefaultCellRenderer(); - tree.setCellRenderer(currentCellRenderer); - } - } + currentCellRenderer = tree.getCellRenderer(); + + if (currentCellRenderer == null) + currentCellRenderer = createDefaultCellRenderer(); } /** @@ -1206,6 +1227,7 @@ public class BasicTreeUI rightChildIndent = UIManager.getInt("Tree.rightChildIndent"); leftChildIndent = UIManager.getInt("Tree.leftChildIndent"); + totalChildIndent = rightChildIndent + leftChildIndent; setRowHeight(UIManager.getInt("Tree.rowHeight")); tree.setRowHeight(getRowHeight()); tree.setScrollsOnExpand(UIManager.getBoolean("Tree.scrollsOnExpand")); @@ -1332,10 +1354,11 @@ public class BasicTreeUI treeSelectionModel = tree.getSelectionModel(); setRootVisible(tree.isRootVisible()); treeState.setRootVisible(tree.isRootVisible()); + updateExpandedDescendants(new TreePath(new Object[] { treeModel.getRoot() })); completeUIInstall(); } - + /** * Uninstall the defaults for the tree */ @@ -1785,7 +1808,9 @@ public class BasicTreeUI * the event. */ protected boolean isToggleEvent(MouseEvent event) + throws NotImplementedException { + // FIXME: Not implemented. return true; } @@ -1968,6 +1993,7 @@ public class BasicTreeUI * @param e the event that occurs when moving the component */ public void componentMoved(ComponentEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -1977,6 +2003,7 @@ public class BasicTreeUI * the bounds */ protected void startTimer() + throws NotImplementedException { // TODO: Implement this properly. } @@ -1987,7 +2014,9 @@ public class BasicTreeUI * @return JScrollPane housing the JTree, or null if one isn't found. */ protected JScrollPane getScrollPane() + throws NotImplementedException { + // FIXME: Not implemented. return null; } @@ -1998,6 +2027,7 @@ public class BasicTreeUI * @param ae is the action performed */ public void actionPerformed(ActionEvent ae) + throws NotImplementedException { // TODO: Implement this properly. } @@ -2080,7 +2110,7 @@ public class BasicTreeUI { repaintLeadRow(); } - + /** * Repaint the lead row. */ @@ -2122,6 +2152,7 @@ public class BasicTreeUI * @param e the key typed */ public void keyTyped(KeyEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2132,6 +2163,7 @@ public class BasicTreeUI * @param e the key pressed */ public void keyPressed(KeyEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2142,6 +2174,7 @@ public class BasicTreeUI * @param e the key released */ public void keyReleased(KeyEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2271,6 +2304,7 @@ public class BasicTreeUI * @param e is the mouse event that occured */ public void mouseDragged(MouseEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2282,6 +2316,7 @@ public class BasicTreeUI * @param e the mouse event that occured */ public void mouseMoved(MouseEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2292,6 +2327,7 @@ public class BasicTreeUI * @param e is the mouse event that occured */ public void mouseReleased(MouseEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2332,6 +2368,7 @@ public class BasicTreeUI * @param e mouse event that occured */ public void mouseClicked(MouseEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2342,6 +2379,7 @@ public class BasicTreeUI * @param e mouse event that occured */ public void mousePressed(MouseEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2352,6 +2390,7 @@ public class BasicTreeUI * @param e mouse event that occured */ public void mouseReleased(MouseEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2362,6 +2401,7 @@ public class BasicTreeUI * @param e mouse event that occured */ public void mouseEntered(MouseEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2372,6 +2412,7 @@ public class BasicTreeUI * @param e mouse event that occured */ public void mouseExited(MouseEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2385,6 +2426,7 @@ public class BasicTreeUI * @param e mouse event that occured */ public void mouseDragged(MouseEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2396,6 +2438,7 @@ public class BasicTreeUI * @param e mouse event that occured */ public void mouseMoved(MouseEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2404,6 +2447,7 @@ public class BasicTreeUI * Removes event from the source */ protected void removeFromSource() + throws NotImplementedException { // TODO: Implement this properly. } @@ -2450,10 +2494,11 @@ public class BasicTreeUI if (s != null) { + TreePath path = treeState.getPathForRow(row); size.x = getRowX(row, depth); size.width = SwingUtilities.computeStringWidth(fm, s); - size.width = size.width + getCurrentControlIcon(null).getIconWidth() - + gap; + size.width = size.width + getCurrentControlIcon(path).getIconWidth() + + gap + getNodeIcon(path).getIconWidth(); size.height = getMaxHeight(tree); size.y = size.height * row; } @@ -2468,8 +2513,7 @@ public class BasicTreeUI */ protected int getRowX(int row, int depth) { - int iw = getCurrentControlIcon(null).getIconWidth(); - return depth * (rightChildIndent + iw/2); + return BasicTreeUI.this.getRowX(row, depth); } }// NodeDimensionsHandler @@ -2540,6 +2584,7 @@ public class BasicTreeUI * the property that has changed. */ public void propertyChange(PropertyChangeEvent event) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2556,6 +2601,7 @@ public class BasicTreeUI * Constructor */ public TreeCancelEditingAction(String name) + throws NotImplementedException { // TODO: Implement this properly. } @@ -2566,6 +2612,7 @@ public class BasicTreeUI * @param e event that occured */ public void actionPerformed(ActionEvent e) + throws NotImplementedException { // TODO: Implement this properly. } @@ -2576,6 +2623,7 @@ public class BasicTreeUI * @return true if the action is enabled, false otherwise */ public boolean isEnabled() + throws NotImplementedException { // TODO: Implement this properly. return false; @@ -2606,6 +2654,8 @@ public class BasicTreeUI { validCachedPreferredSize = false; treeState.setExpandedState(event.getPath(), true); + // The maximal cell height may change + maxHeight = 0; tree.revalidate(); tree.repaint(); } @@ -2619,6 +2669,8 @@ public class BasicTreeUI { validCachedPreferredSize = false; treeState.setExpandedState(event.getPath(), false); + // The maximal cell height may change + maxHeight = 0; tree.revalidate(); tree.repaint(); } @@ -2642,6 +2694,7 @@ public class BasicTreeUI * @param name is the name of the direction */ public TreeHomeAction(int direction, String name) + throws NotImplementedException { // TODO: Implement this properly } @@ -2652,6 +2705,7 @@ public class BasicTreeUI * @param e is the event that occured */ public void actionPerformed(ActionEvent e) + throws NotImplementedException { // TODO: Implement this properly } @@ -2662,6 +2716,7 @@ public class BasicTreeUI * @return true if the action is enabled. */ public boolean isEnabled() + throws NotImplementedException { // TODO: Implement this properly return false; @@ -2686,6 +2741,7 @@ public class BasicTreeUI * @param name is the name of the direction */ public TreeIncrementAction(int direction, String name) + throws NotImplementedException { // TODO: Implement this properly } @@ -2775,6 +2831,7 @@ public class BasicTreeUI * @return true if the action is enabled. */ public boolean isEnabled() + throws NotImplementedException { // TODO: Implement this properly return false; @@ -2891,6 +2948,7 @@ public class BasicTreeUI * @param e is the event that occured */ public void actionPerformed(ActionEvent e) + throws NotImplementedException { // TODO: Implement this properly. } @@ -2901,7 +2959,9 @@ public class BasicTreeUI * @return true if the action is enabled. */ public boolean isEnabled() + throws NotImplementedException { + // FIXME: Not implemented. return false; } }// TreePageAction @@ -2973,6 +3033,7 @@ public class BasicTreeUI * @param e the event that occured */ public void actionPerformed(ActionEvent e) + throws NotImplementedException { // TODO: Implement this properly. } @@ -2983,7 +3044,9 @@ public class BasicTreeUI * @return true if the action is enabled, false otherwise */ public boolean isEnabled() + throws NotImplementedException { + // FIXME: Not implemented. return false; } } // TreeToggleAction @@ -3067,6 +3130,7 @@ public class BasicTreeUI * @return true if the action is enabled, false otherwise */ public boolean isEnabled() + throws NotImplementedException { // TODO: Implement this properly return false; @@ -3094,9 +3158,35 @@ public class BasicTreeUI */ Icon getCurrentControlIcon(TreePath path) { - if (tree.isExpanded(path)) - return expandedIcon; - return collapsedIcon; + if (hasControlIcons()) + { + if (tree.isExpanded(path)) + return expandedIcon; + else + return collapsedIcon; + } + else + { + if (nullIcon == null) + nullIcon = new Icon() + { + public int getIconHeight() + { + return 0; + } + + public int getIconWidth() + { + return 0; + } + + public void paintIcon(Component c, Graphics g, int x, int y) + { + // No action here. + } + }; + return nullIcon; + } } /** @@ -3323,10 +3413,8 @@ public class BasicTreeUI { if (row != 0) { - Icon icon = getCurrentControlIcon(path); - int iconW = icon.getIconWidth(); paintHorizontalLine(g, tree, bounds.y + bounds.height / 2, - bounds.x - iconW/2 - gap, bounds.x - gap); + bounds.x - leftChildIndent - gap, bounds.x - gap); } } @@ -3379,15 +3467,13 @@ public class BasicTreeUI paintExpandControl(g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf); - TreeCellRenderer dtcr = tree.getCellRenderer(); - if (dtcr == null) - dtcr = createDefaultCellRenderer(); + TreeCellRenderer dtcr = currentCellRenderer; boolean focused = false; - if (treeSelectionModel!= null) - focused = treeSelectionModel.getLeadSelectionRow() == row - && tree.isFocusOwner(); - + if (treeSelectionModel != null) + focused = treeSelectionModel.getLeadSelectionRow() == row + && tree.isFocusOwner(); + Component c = dtcr.getTreeCellRendererComponent(tree, node, selected, isExpanded, isLeaf, row, focused); @@ -3399,6 +3485,7 @@ public class BasicTreeUI * Prepares for the UI to uninstall. */ protected void prepareForUIUninstall() + throws NotImplementedException { // TODO: Implement this properly. } @@ -3440,4 +3527,14 @@ public class BasicTreeUI editingComponent = null; tree.requestFocus(); } + + /** + * Returns the amount to indent the given row + * + * @return amount to indent the given row. + */ + protected int getRowX(int row, int depth) + { + return depth * totalChildIndent; + } } // BasicTreeUI diff --git a/javax/swing/plaf/metal/MetalBorders.java b/javax/swing/plaf/metal/MetalBorders.java index 98a00ee0a..7c41180ae 100644 --- a/javax/swing/plaf/metal/MetalBorders.java +++ b/javax/swing/plaf/metal/MetalBorders.java @@ -103,7 +103,16 @@ public class MetalBorders private static BasicBorders.MarginBorder marginBorder; /** - * A border used for {@link JButton} components. + * <p>A border used for {@link JButton} components.</p> + * + * <p>This {@link Border} implementation can handle only instances of + * {@link AbstractButton} and their subclasses.</p> + * + * <p>If the Metal Look and Feel's current theme is 'Ocean' the border + * will be painted with a special highlight when the mouse cursor if + * over the button (ie. the property <code>rollover</code> of the + * button's model is <code>true</code>) and is not a <b>direct</b> + * child of a {@link JToolBar}.</p> */ public static class ButtonBorder extends AbstractBorder implements UIResource { @@ -157,8 +166,14 @@ public class MetalBorders { ButtonModel bmodel = null; + // The RI will fail with a ClassCastException in such a situation. + // This code tries to be more helpful. if (c instanceof AbstractButton) bmodel = ((AbstractButton) c).getModel(); + else + throw new IllegalStateException("A ButtonBorder is supposed to work " + + "only with AbstractButton and" + + "subclasses."); Color darkShadow = MetalLookAndFeel.getControlDarkShadow(); Color shadow = MetalLookAndFeel.getControlShadow(); @@ -191,7 +206,7 @@ public class MetalBorders { // The normal border. This is used when the button is not // pressed or the button is not armed. - if (! (bmodel.isPressed() && bmodel.isArmed()) ) + if (! (bmodel.isPressed() && bmodel.isArmed())) { // draw light border g.setColor(light); @@ -246,8 +261,14 @@ public class MetalBorders { ButtonModel bmodel = null; + // The RI will fail with a ClassCastException in such a situation. + // This code tries to be more helpful. if (c instanceof AbstractButton) bmodel = ((AbstractButton) c).getModel(); + else + throw new IllegalStateException("A ButtonBorder is supposed to work " + + "only with AbstractButton and" + + "subclasses."); Color darkShadow = MetalLookAndFeel.getControlDarkShadow(); Color shadow = MetalLookAndFeel.getControlShadow(); @@ -267,8 +288,10 @@ public class MetalBorders g.drawRect(x, y, w - 1, h - 1); g.drawRect(x + 1, y + 1, w - 3, h - 3); } - else if (bmodel.isRollover()) + else if (bmodel.isRollover() && !(c.getParent() instanceof JToolBar)) { + // Paint a bigger border when the mouse is over the button but + // only if it is *not* part of a JToolBar. g.setColor(shadow); g.drawRect(x, y, w - 1, h - 1); g.drawRect(x + 2, y + 2, w - 5, h - 5); @@ -568,12 +591,12 @@ public class MetalBorders { boolean enabledTextBorder; if (c instanceof JTextComponent) - { - JTextComponent tc = (JTextComponent) c; - enabledTextBorder = tc.isEnabled() && tc.isEditable(); - } + { + JTextComponent tc = (JTextComponent) c; + enabledTextBorder = tc.isEnabled() && tc.isEditable(); + } else - enabledTextBorder = false; + enabledTextBorder = false; if (enabledTextBorder) super.paintBorder(c, g, x, y, w, h); @@ -829,35 +852,36 @@ public class MetalBorders { Color dark = MetalLookAndFeel.getPrimaryControlDarkShadow(); Color light = MetalLookAndFeel.getPrimaryControlHighlight(); - if (c instanceof JMenu) { - JMenu menu = (JMenu) c; - if (menu.isSelected()) + if (c instanceof JMenu) { - g.setColor(dark); - g.drawLine(x, y, x, y + h); - g.drawLine(x, y, x + w, y); - g.drawLine(x + w - 2, y + 1, x + w - 2, y + h); - g.setColor(light); - g.drawLine(x + w - 1, y + 1, x + w - 1, y + h); + JMenu menu = (JMenu) c; + if (menu.isSelected()) + { + g.setColor(dark); + g.drawLine(x, y, x, y + h); + g.drawLine(x, y, x + w, y); + g.drawLine(x + w - 2, y + 1, x + w - 2, y + h); + g.setColor(light); + g.drawLine(x + w - 1, y + 1, x + w - 1, y + h); + } } - } else if (c instanceof JMenuItem) - { - JMenuItem item = (JMenuItem) c; - if (item.isArmed()) - { - g.setColor(dark); - g.drawLine(x, y, x + w, y); - g.setColor(light); - g.drawLine(x, y + h - 1, x + w, y + h - 1); - } - else - { - // Normally we draw a light line on the left. - g.setColor(light); - g.drawLine(x, y, x, y + h); - } - } + { + JMenuItem item = (JMenuItem) c; + if (item.isArmed()) + { + g.setColor(dark); + g.drawLine(x, y, x + w, y); + g.setColor(light); + g.drawLine(x, y + h - 1, x + w, y + h - 1); + } + else + { + // Normally we draw a light line on the left. + g.setColor(light); + g.drawLine(x, y, x, y + h); + } + } } /** @@ -1469,8 +1493,8 @@ public class MetalBorders { Border outer = new ButtonBorder(); Border inner = getMarginBorder(); - buttonBorder = new BorderUIResource.CompoundBorderUIResource - (outer, inner); + buttonBorder = new BorderUIResource.CompoundBorderUIResource(outer, + inner); } return buttonBorder; } @@ -1488,8 +1512,8 @@ public class MetalBorders { Border outer = new ToggleButtonBorder(); Border inner = getMarginBorder(); - toggleButtonBorder = new BorderUIResource.CompoundBorderUIResource - (outer, inner); + toggleButtonBorder = new BorderUIResource.CompoundBorderUIResource( + outer, inner); } return toggleButtonBorder; } diff --git a/javax/swing/plaf/metal/MetalButtonUI.java b/javax/swing/plaf/metal/MetalButtonUI.java index 83cd33662..d6cc1bc07 100644 --- a/javax/swing/plaf/metal/MetalButtonUI.java +++ b/javax/swing/plaf/metal/MetalButtonUI.java @@ -39,6 +39,7 @@ exception statement from your version. */ package javax.swing.plaf.metal; import java.awt.Color; +import java.awt.Container; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; @@ -48,7 +49,9 @@ import javax.swing.AbstractButton; import javax.swing.ButtonModel; import javax.swing.JButton; import javax.swing.JComponent; +import javax.swing.JToolBar; import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.UIResource; @@ -121,7 +124,8 @@ public class MetalButtonUI * * @return A new instance of <code>MetalButtonUI</code>. */ - public static ComponentUI createUI(JComponent c) { + public static ComponentUI createUI(JComponent c) + { return new MetalButtonUI(); } @@ -187,7 +191,8 @@ public class MetalButtonUI * @param iconRect the icon bounds. */ protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect, - Rectangle textRect, Rectangle iconRect) { + Rectangle textRect, Rectangle iconRect) + { if (b.isEnabled() && b.hasFocus() && b.isFocusPainted()) { Color savedColor = g.getColor(); @@ -235,19 +240,63 @@ public class MetalButtonUI public void update(Graphics g, JComponent c) { AbstractButton b = (AbstractButton) c; - ButtonModel m = b.getModel(); if (b.isContentAreaFilled() && (UIManager.get(getPropertyPrefix() + "gradient") != null) - && ! m.isPressed() && ! m.isArmed() && b.isEnabled() && (b.getBackground() instanceof UIResource)) + updateWidthGradient(g, b, b.getParent()); + else + super.update(g, c); + } + + private void updateWidthGradient(Graphics g, AbstractButton b, Container parent) + { + ButtonModel m = b.getModel(); + String gradientPropertyName = getPropertyPrefix() + "gradient"; + + // Gradient painting behavior depends on whether the button is part of a + // JToolBar. + if (parent instanceof JToolBar) + { + if (! m.isPressed() && ! m.isArmed()) + { + if (m.isRollover()) + { + // Paint the gradient when the mouse cursor hovers over the + // button but is not pressed down. + MetalUtils.paintGradient(g, 0, 0, b.getWidth(), b.getHeight(), + SwingConstants.VERTICAL, + gradientPropertyName); + } + else + { + // If mouse does not hover over the button let the JToolBar + // paint itself at the location where the button is (the button + // is transparent). + + // There where cases where the button was not repainted and + // therefore showed its old state. With this statement it does + // not happen. + b.repaint(); + + Rectangle area = new Rectangle(); + SwingUtilities.calculateInnerArea(b, area); + SwingUtilities.convertRectangle(b, area, b.getParent()); + b.getParent().repaint(area.x, area.y, area.width, area.height); + } + } + + } + else if (! m.isPressed() && ! m.isArmed()) { - MetalUtils.paintGradient(g, 0, 0, c.getWidth(), c.getHeight(), + // When the button is not part of a JToolBar just paint itself with a + // gradient and everything is fine. + MetalUtils.paintGradient(g, 0, 0, b.getWidth(), b.getHeight(), SwingConstants.VERTICAL, - getPropertyPrefix() + "gradient"); - paint(g, c); + gradientPropertyName); } - else - super.update(g, c); + + paint(g, b); } + } diff --git a/javax/swing/plaf/metal/MetalCheckBoxUI.java b/javax/swing/plaf/metal/MetalCheckBoxUI.java index b4f6f0a56..c7941642e 100644 --- a/javax/swing/plaf/metal/MetalCheckBoxUI.java +++ b/javax/swing/plaf/metal/MetalCheckBoxUI.java @@ -52,7 +52,7 @@ public class MetalCheckBoxUI // FIXME: maybe replace by a Map of instances when this becomes stateful /** The shared UI instance for JCheckBoxes. */ - private static MetalCheckBoxUI instance = null; + private static MetalCheckBoxUI instance; /** * Constructs a new instance of MetalCheckBoxUI. diff --git a/javax/swing/plaf/metal/MetalComboBoxButton.java b/javax/swing/plaf/metal/MetalComboBoxButton.java index 3787a98c3..6a528de2b 100644 --- a/javax/swing/plaf/metal/MetalComboBoxButton.java +++ b/javax/swing/plaf/metal/MetalComboBoxButton.java @@ -256,9 +256,8 @@ public class MetalComboBoxButton { ListCellRenderer renderer = comboBox.getRenderer(); boolean pressed = this.getModel().isPressed(); - Component comp= renderer.getListCellRendererComponent(listBox, - comboBox.getSelectedItem(), - -1, false, false); + Component comp = renderer.getListCellRendererComponent(listBox, + comboBox.getSelectedItem(), -1, false, false); comp.setFont(rendererPane.getFont()); if (model.isArmed() && model.isPressed()) { diff --git a/javax/swing/plaf/metal/MetalComboBoxIcon.java b/javax/swing/plaf/metal/MetalComboBoxIcon.java index f21c5af61..944ce3944 100644 --- a/javax/swing/plaf/metal/MetalComboBoxIcon.java +++ b/javax/swing/plaf/metal/MetalComboBoxIcon.java @@ -48,7 +48,8 @@ import javax.swing.Icon; /** * An icon used by the {@link MetalComboBoxUI} class. */ -public class MetalComboBoxIcon implements Icon, Serializable { +public class MetalComboBoxIcon implements Icon, Serializable +{ /** * Creates a new icon. diff --git a/javax/swing/plaf/metal/MetalFileChooserUI.java b/javax/swing/plaf/metal/MetalFileChooserUI.java index cb94c87b8..1219ad9fd 100644 --- a/javax/swing/plaf/metal/MetalFileChooserUI.java +++ b/javax/swing/plaf/metal/MetalFileChooserUI.java @@ -52,12 +52,13 @@ import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; -import java.text.NumberFormat; - import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; - import java.io.File; +import java.sql.Date; +import java.text.DateFormat; +import java.text.NumberFormat; +import java.util.List; import javax.swing.AbstractAction; import javax.swing.AbstractListModel; @@ -79,7 +80,6 @@ import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.JToggleButton; -import javax.swing.JViewport; import javax.swing.ListModel; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; @@ -94,12 +94,6 @@ import javax.swing.plaf.basic.BasicFileChooserUI; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; -import java.sql.Date; - -import java.text.DateFormat; - -import java.util.List; - /** * A UI delegate for the {@link JFileChooser} component. This class is only @@ -350,7 +344,7 @@ public class MetalFileChooserUI setDirectorySelected(false); File currentDirectory = filechooser.getCurrentDirectory(); setDirectory(currentDirectory); - boolean hasParent = (currentDirectory.getParentFile() != null); + boolean hasParent = currentDirectory.getParentFile() != null; getChangeToParentDirectoryAction().setEnabled(hasParent); } @@ -648,15 +642,15 @@ public class MetalFileChooserUI FileView v = getFileView(getFileChooser()); File f = (File) value; if (f != null) - { - setText(v.getName(f)); - setIcon(v.getIcon(f)); - } + { + setText(v.getName(f)); + setIcon(v.getIcon(f)); + } else - { - setText(""); - setIcon(null); - } + { + setText(""); + setIcon(null); + } setOpaque(true); if (isSelected) { @@ -962,10 +956,9 @@ public class MetalFileChooserUI { String text = editField.getText(); if (text != null && text != "" && !text.equals(fc.getName(editFile))) - if (editFile.renameTo - (fc.getFileSystemView().createFileObject - (fc.getCurrentDirectory(), text))) - rescanCurrentDirectory(fc); + if (editFile.renameTo(fc.getFileSystemView().createFileObject( + fc.getCurrentDirectory(), text))) + rescanCurrentDirectory(fc); list.remove(editField); } startEditing = false; @@ -1018,7 +1011,7 @@ public class MetalFileChooserUI JFileChooser fc; /** The last selected file. */ - Object lastSelected = null; + Object lastSelected; /** * Stores the current file that is being edited. @@ -1032,10 +1025,8 @@ public class MetalFileChooserUI /** * Creates a new listener. * - * @param table - * the directory/file table - * @param fc - * the JFileChooser + * @param table the directory/file table + * @param fc the JFileChooser */ public TableClickListener(JTable table, JFileChooser fc) { @@ -1051,8 +1042,7 @@ public class MetalFileChooserUI /** * Receives notification of a mouse click event. * - * @param e - * the event. + * @param e the event. */ public void mouseClicked(MouseEvent e) { @@ -1156,10 +1146,9 @@ public class MetalFileChooserUI { String text = editField.getText(); if (text != null && text != "" && !text.equals(fc.getName(editFile))) - if (editFile.renameTo - (fc.getFileSystemView().createFileObject - (fc.getCurrentDirectory(), text))) - rescanCurrentDirectory(fc); + if (editFile.renameTo(fc.getFileSystemView().createFileObject( + fc.getCurrentDirectory(), text))) + rescanCurrentDirectory(fc); table.remove(editField); } startEditing = false; @@ -1636,8 +1625,7 @@ public class MetalFileChooserUI /** * Formats bytes into the appropriate size. * - * @param bytes - - * the number of bytes to convert + * @param bytes the number of bytes to convert * @return a string representation of the size */ private String formatSize(long bytes) @@ -1838,7 +1826,7 @@ public class MetalFileChooserUI /** * Updates the current directory. * - * @param the file chooser to update. + * @param fc the file chooser to update. */ public void rescanCurrentDirectory(JFileChooser fc) { @@ -1966,7 +1954,8 @@ public class MetalFileChooserUI * * @param component the component. */ - public void removeLayoutComponent(Component component) { + public void removeLayoutComponent(Component component) + { // do nothing } } @@ -2072,7 +2061,8 @@ public class MetalFileChooserUI * * @param component the component. */ - public void removeLayoutComponent(Component component) { + public void removeLayoutComponent(Component component) + { // do nothing } } diff --git a/javax/swing/plaf/metal/MetalIconFactory.java b/javax/swing/plaf/metal/MetalIconFactory.java index d24a05262..4e4c863c9 100644 --- a/javax/swing/plaf/metal/MetalIconFactory.java +++ b/javax/swing/plaf/metal/MetalIconFactory.java @@ -617,7 +617,8 @@ public class MetalIconFactory implements Serializable * * @return The width of the icon. */ - public int getIconWidth() { + public int getIconWidth() + { return 16; } diff --git a/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java b/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java index f74828e56..dd0c48639 100644 --- a/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java +++ b/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java @@ -95,7 +95,7 @@ public class MetalInternalFrameTitlePane extends BasicInternalFrameTitlePane String propName = e.getPropertyName(); if (e.getPropertyName().equals(JInternalFrame.FRAME_ICON_PROPERTY)) { - title.setIcon( frame.getFrameIcon() ); + title.setIcon(frame.getFrameIcon()); } else if (propName.equals("JInternalFrame.isPalette")) { @@ -387,8 +387,8 @@ public class MetalInternalFrameTitlePane extends BasicInternalFrameTitlePane paintPalette(g); else { - paintTitleBackground(g); - paintChildren(g); + paintTitleBackground(g); + paintChildren(g); Dimension d = getSize(); if (frame.isSelected()) g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); @@ -421,7 +421,8 @@ public class MetalInternalFrameTitlePane extends BasicInternalFrameTitlePane endX = Math.max(closeButton.getX(), endX); endX -= 7; if (endX > startX) - MetalUtils.fillMetalPattern(this, g, startX, 3, endX - startX, getHeight() - 6, Color.white, Color.gray); + MetalUtils.fillMetalPattern(this, g, startX, 3, endX - startX, + getHeight() - 6, Color.white, Color.gray); } g.setColor(savedColor); } diff --git a/javax/swing/plaf/metal/MetalLookAndFeel.java b/javax/swing/plaf/metal/MetalLookAndFeel.java index d7cd9ab24..73b0a64bd 100644 --- a/javax/swing/plaf/metal/MetalLookAndFeel.java +++ b/javax/swing/plaf/metal/MetalLookAndFeel.java @@ -67,7 +67,7 @@ import javax.swing.plaf.basic.BasicLookAndFeel; * }</pre> */ public class MetalLookAndFeel extends BasicLookAndFeel -{ +{ private static final long serialVersionUID = 6680646159193457980L; /** The current theme. */ @@ -888,11 +888,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel "CheckBox.font", new FontUIResource("Dialog", Font.BOLD, 12), "CheckBox.foreground", getControlTextColor(), "CheckBox.icon", - new UIDefaults.ProxyLazyValue - ("javax.swing.plaf.metal.MetalCheckBoxIcon"), + new UIDefaults.ProxyLazyValue("javax.swing.plaf.metal.MetalCheckBoxIcon"), "CheckBox.checkIcon", - new UIDefaults.ProxyLazyValue - ("javax.swing.plaf.metal.MetalCheckBoxIcon"), + new UIDefaults.ProxyLazyValue("javax.swing.plaf.metal.MetalCheckBoxIcon"), "Checkbox.select", getControlShadow(), "CheckBoxMenuItem.acceleratorFont", new FontUIResource("Dialog", Font.PLAIN, 10), @@ -964,7 +962,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel "FileChooser.detailsViewIcon", MetalIconFactory.getFileChooserDetailViewIcon(), "FileChooser.fileNameLabelMnemonic", new Integer(78), - "FileChooser.filesOfTypeLabelMnemonic",new Integer(84), + "FileChooser.filesOfTypeLabelMnemonic", new Integer(84), "FileChooser.lookInLabelMnemonic", new Integer(73), "FileView.computerIcon", MetalIconFactory.getTreeComputerIcon(), "FileView.directoryIcon", MetalIconFactory.getTreeFolderIcon(), @@ -1273,6 +1271,8 @@ public class MetalLookAndFeel extends BasicLookAndFeel "ToolBar.light", getControlHighlight(), "ToolBar.shadow", getControlShadow(), "ToolBar.border", new MetalBorders.ToolBarBorder(), + "ToolBar.rolloverBorder", MetalBorders.getToolbarButtonBorder(), + "ToolBar.nonrolloverBorder", MetalBorders.getToolbarButtonBorder(), "ToolTip.background", getPrimaryControl(), "ToolTip.backgroundInactive", getControl(), diff --git a/javax/swing/plaf/metal/MetalPopupMenuSeparatorUI.java b/javax/swing/plaf/metal/MetalPopupMenuSeparatorUI.java index 44a2d3bcd..7c580f90f 100644 --- a/javax/swing/plaf/metal/MetalPopupMenuSeparatorUI.java +++ b/javax/swing/plaf/metal/MetalPopupMenuSeparatorUI.java @@ -51,7 +51,7 @@ public class MetalPopupMenuSeparatorUI // FIXME: maybe replace by a Map of instances when this becomes stateful /** The shared UI instance for MetalPopupMenuSeparatorUIs */ - private static MetalPopupMenuSeparatorUI instance = null; + private static MetalPopupMenuSeparatorUI instance; /** * Constructs a new instance of <code>MetalPopupMenuSeparatorUI</code>. diff --git a/javax/swing/plaf/metal/MetalRadioButtonUI.java b/javax/swing/plaf/metal/MetalRadioButtonUI.java index 9fb960f68..046e4942e 100644 --- a/javax/swing/plaf/metal/MetalRadioButtonUI.java +++ b/javax/swing/plaf/metal/MetalRadioButtonUI.java @@ -1,5 +1,5 @@ /* MetalRadioButtonUI.java - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -95,9 +95,10 @@ public class MetalRadioButtonUI public void installDefaults(AbstractButton b) { super.installDefaults(b); - disabledTextColor = UIManager.getColor("RadioButton.disabledText"); - focusColor = UIManager.getColor("RadioButton.focus"); - selectColor = UIManager.getColor("RadioButton.select"); + String prefix = getPropertyPrefix(); + disabledTextColor = UIManager.getColor(prefix + "disabledText"); + focusColor = UIManager.getColor(prefix + "focus"); + selectColor = UIManager.getColor(prefix + "select"); } /** diff --git a/javax/swing/plaf/metal/MetalRootPaneUI.java b/javax/swing/plaf/metal/MetalRootPaneUI.java index 6cabc7e86..eaee5bf92 100644 --- a/javax/swing/plaf/metal/MetalRootPaneUI.java +++ b/javax/swing/plaf/metal/MetalRootPaneUI.java @@ -958,7 +958,7 @@ public class MetalRootPaneUI /** * The shared UI instance for MetalRootPaneUIs. */ - private static MetalRootPaneUI instance = null; + private static MetalRootPaneUI instance; /** * Constructs a shared instance of <code>MetalRootPaneUI</code>. diff --git a/javax/swing/plaf/metal/MetalScrollBarUI.java b/javax/swing/plaf/metal/MetalScrollBarUI.java index c7dfd11e4..75f2750ae 100644 --- a/javax/swing/plaf/metal/MetalScrollBarUI.java +++ b/javax/swing/plaf/metal/MetalScrollBarUI.java @@ -90,14 +90,14 @@ public class MetalScrollBarUI extends BasicScrollBarUI if (e.getPropertyName().equals(FREE_STANDING_PROP)) { Boolean prop = (Boolean) e.getNewValue(); - isFreeStanding = (prop == null ? true : prop.booleanValue()); - if (increaseButton != null) - increaseButton.setFreeStanding(isFreeStanding); - if (decreaseButton != null) - decreaseButton.setFreeStanding(isFreeStanding); + isFreeStanding = prop == null ? true : prop.booleanValue(); + if (increaseButton != null) + increaseButton.setFreeStanding(isFreeStanding); + if (decreaseButton != null) + decreaseButton.setFreeStanding(isFreeStanding); } else - super.propertyChange(e); + super.propertyChange(e); } } @@ -167,7 +167,7 @@ public class MetalScrollBarUI extends BasicScrollBarUI // createDecreaseButton() are called (unless there is somewhere earlier // that we can do this). Boolean prop = (Boolean) scrollbar.getClientProperty(FREE_STANDING_PROP); - isFreeStanding = (prop == null ? true : prop.booleanValue()); + isFreeStanding = prop == null ? true : prop.booleanValue(); scrollBarShadowColor = UIManager.getColor("ScrollBar.shadow"); super.installDefaults(); } @@ -401,7 +401,7 @@ public class MetalScrollBarUI extends BasicScrollBarUI { g.drawLine(x, y, x + w - 1, y); g.drawLine(x, y, x, y + h - 1); - g.drawLine(x + w - 1, y, x + w - 1, y + h -1); + g.drawLine(x + w - 1, y, x + w - 1, y + h - 1); } // then the highlight diff --git a/javax/swing/plaf/metal/MetalSeparatorUI.java b/javax/swing/plaf/metal/MetalSeparatorUI.java index 1d48e9be2..6d7818f8b 100644 --- a/javax/swing/plaf/metal/MetalSeparatorUI.java +++ b/javax/swing/plaf/metal/MetalSeparatorUI.java @@ -58,7 +58,7 @@ public class MetalSeparatorUI // FIXME: maybe replace by a Map of instances when this becomes stateful /** The shared UI instance for MetalSeparatorUIs */ - private static MetalSeparatorUI instance = null; + private static MetalSeparatorUI instance; /** * Constructs a new instance of <code>MetalSeparatorUI</code>. diff --git a/javax/swing/plaf/metal/MetalSliderUI.java b/javax/swing/plaf/metal/MetalSliderUI.java index f97717f31..0f824418c 100644 --- a/javax/swing/plaf/metal/MetalSliderUI.java +++ b/javax/swing/plaf/metal/MetalSliderUI.java @@ -192,10 +192,13 @@ public class MetalSliderUI extends BasicSliderUI */ public void paintThumb(Graphics g) { + Color save = g.getColor(); + g.setColor(thumbColor); if (slider.getOrientation() == JSlider.HORIZONTAL) horizThumbIcon.paintIcon(slider, g, thumbRect.x, thumbRect.y); else vertThumbIcon.paintIcon(slider, g, thumbRect.x, thumbRect.y); + g.setColor(save); } /** @@ -229,9 +232,9 @@ public class MetalSliderUI extends BasicSliderUI if (slider.isEnabled()) { int xPos = xPositionForValue(slider.getValue()); - int x = (slider.getInverted() ? xPos : trackRect.x); - int w = (slider.getInverted() ? trackX + trackW - xPos - : xPos - trackRect.x); + int x = slider.getInverted() ? xPos : trackRect.x; + int w = slider.getInverted() ? trackX + trackW - xPos + : xPos - trackRect.x; g.setColor(MetalLookAndFeel.getWhite()); g.drawLine(x + 1, trackY + 1, x + w - 3, trackY + 1); g.setColor(UIManager.getColor("Slider.altTrackColor")); @@ -245,9 +248,9 @@ public class MetalSliderUI extends BasicSliderUI else if (filledSlider) { int xPos = xPositionForValue(slider.getValue()); - int x = (slider.getInverted() ? xPos : trackRect.x); - int w = (slider.getInverted() ? trackX + trackW - xPos - : xPos - trackRect.x); + int x = slider.getInverted() ? xPos : trackRect.x; + int w = slider.getInverted() ? trackX + trackW - xPos + : xPos - trackRect.x; g.setColor(MetalLookAndFeel.getControlShadow()); g.fillRect(x + 1, trackY + 1, w - 3, getTrackWidth() - 3); if (slider.isEnabled()) @@ -280,9 +283,9 @@ public class MetalSliderUI extends BasicSliderUI if (slider.isEnabled()) { int yPos = yPositionForValue(slider.getValue()); - int y = (slider.getInverted() ? trackY : yPos); - int h = (slider.getInverted() ? yPos - trackY - : trackY + trackH - yPos); + int y = slider.getInverted() ? trackY : yPos; + int h = slider.getInverted() ? yPos - trackY + : trackY + trackH - yPos; g.setColor(MetalLookAndFeel.getWhite()); g.drawLine(trackX + 1, y + 1, trackX + 1, y + h - 3); @@ -297,9 +300,9 @@ public class MetalSliderUI extends BasicSliderUI else if (filledSlider) { int yPos = yPositionForValue(slider.getValue()); - int y = (slider.getInverted() ? trackY : yPos); - int h = (slider.getInverted() ? yPos - trackY - : trackY + trackH - yPos); + int y = slider.getInverted() ? trackY : yPos; + int h = slider.getInverted() ? yPos - trackY + : trackY + trackH - yPos; g.setColor(MetalLookAndFeel.getControlShadow()); g.fillRect(trackX + 1, y + 1, getTrackWidth() - 3, h - 3); if (slider.isEnabled()) @@ -323,7 +326,8 @@ public class MetalSliderUI extends BasicSliderUI */ public void paintFocus(Graphics g) { - // do nothing as focus is shown by different color on thumb control + thumbColor = getFocusColor(); + paintThumb(g); } /** @@ -368,8 +372,8 @@ public class MetalSliderUI extends BasicSliderUI */ protected int getTrackLength() { - return (slider.getOrientation() == JSlider.HORIZONTAL - ? tickRect.width : tickRect.height); + return slider.getOrientation() == JSlider.HORIZONTAL + ? tickRect.width : tickRect.height; } /** diff --git a/javax/swing/plaf/metal/MetalSplitPaneDivider.java b/javax/swing/plaf/metal/MetalSplitPaneDivider.java index 9c592bd51..ba4e314f3 100644 --- a/javax/swing/plaf/metal/MetalSplitPaneDivider.java +++ b/javax/swing/plaf/metal/MetalSplitPaneDivider.java @@ -42,7 +42,6 @@ import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Graphics; -import java.awt.Insets; import java.awt.LayoutManager; import java.awt.Point; @@ -159,8 +158,8 @@ class MetalSplitPaneDivider extends BasicSplitPaneDivider if ((c1 instanceof BasicArrowButton) && (c2 instanceof BasicArrowButton)) { - lb = ((BasicArrowButton) c1); - rb = ((BasicArrowButton) c2); + lb = (BasicArrowButton) c1; + rb = (BasicArrowButton) c2; } } if (rb != null && lb != null) diff --git a/javax/swing/plaf/metal/MetalTabbedPaneUI.java b/javax/swing/plaf/metal/MetalTabbedPaneUI.java index 39dec3d66..c49abe832 100644 --- a/javax/swing/plaf/metal/MetalTabbedPaneUI.java +++ b/javax/swing/plaf/metal/MetalTabbedPaneUI.java @@ -607,11 +607,11 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI } else { - if (isOcean && tabIndex == tabPane.getSelectedIndex()+ 1) + if (isOcean && tabIndex == tabPane.getSelectedIndex() + 1) { g.setColor(oceanSelectedBorder); } - if (tabIndex != tabRuns[runCount- 1]) + if (tabIndex != tabRuns[runCount - 1]) { g.drawLine(0, 0, 0, bottom); } @@ -856,7 +856,7 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI // run directly above the content or the selected tab is not visible, // then we draw an unbroken line. if (tabPlacement != TOP || selectedIndex < 0 - || rect.y + rect.height + 1 < y || rect.x < x ||rect.x > x + w) + || rect.y + rect.height + 1 < y || rect.x < x || rect.x > x + w) { g.drawLine(x, y, x + w - 2, y); if (isOcean && tabPlacement == TOP) diff --git a/javax/swing/plaf/metal/MetalToolTipUI.java b/javax/swing/plaf/metal/MetalToolTipUI.java index f183ed5a1..d1040347f 100644 --- a/javax/swing/plaf/metal/MetalToolTipUI.java +++ b/javax/swing/plaf/metal/MetalToolTipUI.java @@ -75,7 +75,7 @@ public class MetalToolTipUI public static final int padSpaceBetweenStrings = 12; /** The shared UI instance. */ - private static MetalToolTipUI instance = null; + private static MetalToolTipUI instance; /** A flag controlling the visibility of the accelerator (if there is one). */ private boolean isAcceleratorHidden; @@ -256,8 +256,8 @@ public class MetalToolTipUI g.setColor(acceleratorForeground); fm = t.getFontMetrics(acceleratorFont); int width = fm.stringWidth(acceleratorString); - g.drawString(acceleratorString, vr.x + vr.width - width - padSpaceBetweenStrings/2, - vr.y + vr.height - fm.getDescent()); + g.drawString(acceleratorString, vr.x + vr.width - width + - padSpaceBetweenStrings / 2, vr.y + vr.height - fm.getDescent()); } g.setColor(saved); diff --git a/javax/swing/plaf/metal/MetalUtils.java b/javax/swing/plaf/metal/MetalUtils.java index 03617aa40..72cbb34a6 100644 --- a/javax/swing/plaf/metal/MetalUtils.java +++ b/javax/swing/plaf/metal/MetalUtils.java @@ -104,7 +104,7 @@ class MetalUtils else g.setColor(dark); - for (int mX = x + (xOff); mX < (x + w); mX += 4) + for (int mX = x + xOff; mX < (x + w); mX += 4) { g.drawLine(mX, mY, mX, mY); } diff --git a/javax/swing/plaf/multi/MultiComboBoxUI.java b/javax/swing/plaf/multi/MultiComboBoxUI.java index 05279d7d6..33b432152 100644 --- a/javax/swing/plaf/multi/MultiComboBoxUI.java +++ b/javax/swing/plaf/multi/MultiComboBoxUI.java @@ -357,7 +357,8 @@ public class MultiComboBoxUI extends ComboBoxUI * @param c the component. * @param visible the visible state. */ - public void setPopupVisible(JComboBox c, boolean visible) { + public void setPopupVisible(JComboBox c, boolean visible) + { Iterator iterator = uis.iterator(); while (iterator.hasNext()) { @@ -376,7 +377,8 @@ public class MultiComboBoxUI extends ComboBoxUI * * @return The result for the UI delegate from the primary look and feel. */ - public boolean isPopupVisible(JComboBox c) { + public boolean isPopupVisible(JComboBox c) + { boolean result = false; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -406,7 +408,8 @@ public class MultiComboBoxUI extends ComboBoxUI * UI delegate in the primary look and feel, and <code>false</code> * otherwise. */ - public boolean isFocusTraversable(JComboBox c) { + public boolean isFocusTraversable(JComboBox c) + { boolean result = false; Iterator iterator = uis.iterator(); // first UI delegate provides the return value diff --git a/javax/swing/plaf/multi/MultiFileChooserUI.java b/javax/swing/plaf/multi/MultiFileChooserUI.java index 6f8826010..719f04374 100644 --- a/javax/swing/plaf/multi/MultiFileChooserUI.java +++ b/javax/swing/plaf/multi/MultiFileChooserUI.java @@ -364,7 +364,8 @@ public class MultiFileChooserUI extends FileChooserUI * @return The filter returned by the UI delegate from the primary * look and feel. */ - public FileFilter getAcceptAllFileFilter(JFileChooser chooser) { + public FileFilter getAcceptAllFileFilter(JFileChooser chooser) + { FileFilter result = null; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -393,7 +394,8 @@ public class MultiFileChooserUI extends FileChooserUI * @return The view returned by the UI delegate from the primary * look and feel. */ - public FileView getFileView(JFileChooser chooser) { + public FileView getFileView(JFileChooser chooser) + { FileView result = null; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -422,7 +424,8 @@ public class MultiFileChooserUI extends FileChooserUI * @return The text returned by the UI delegate from the primary * look and feel. */ - public String getApproveButtonText(JFileChooser chooser) { + public String getApproveButtonText(JFileChooser chooser) + { String result = null; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -451,7 +454,8 @@ public class MultiFileChooserUI extends FileChooserUI * @return The title returned by the UI delegate from the primary * look and feel. */ - public String getDialogTitle(JFileChooser chooser) { + public String getDialogTitle(JFileChooser chooser) + { String result = null; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -476,7 +480,8 @@ public class MultiFileChooserUI extends FileChooserUI * * @param chooser the file chooser. */ - public void rescanCurrentDirectory(JFileChooser chooser) { + public void rescanCurrentDirectory(JFileChooser chooser) + { Iterator iterator = uis.iterator(); while (iterator.hasNext()) { @@ -493,7 +498,8 @@ public class MultiFileChooserUI extends FileChooserUI * @param chooser the file chooser. * @param file the file. */ - public void ensureFileIsVisible(JFileChooser chooser, File file) { + public void ensureFileIsVisible(JFileChooser chooser, File file) + { Iterator iterator = uis.iterator(); while (iterator.hasNext()) { diff --git a/javax/swing/plaf/multi/MultiListUI.java b/javax/swing/plaf/multi/MultiListUI.java index 7350b4541..78c22419f 100644 --- a/javax/swing/plaf/multi/MultiListUI.java +++ b/javax/swing/plaf/multi/MultiListUI.java @@ -364,7 +364,8 @@ public class MultiListUI extends ListUI * @return The index returned by the UI delegate from the primary * look and feel. */ - public int locationToIndex(JList list, Point location) { + public int locationToIndex(JList list, Point location) + { int result = 0; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -394,7 +395,8 @@ public class MultiListUI extends ListUI * @return The location returned by the UI delegate from the primary * look and feel. */ - public Point indexToLocation(JList list, int index) { + public Point indexToLocation(JList list, int index) + { Point result = null; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -425,7 +427,8 @@ public class MultiListUI extends ListUI * @return The bounds returned by the UI delegate from the primary * look and feel. */ - public Rectangle getCellBounds(JList list, int index1, int index2) { + public Rectangle getCellBounds(JList list, int index1, int index2) + { Rectangle result = null; Iterator iterator = uis.iterator(); // first UI delegate provides the return value diff --git a/javax/swing/plaf/multi/MultiLookAndFeel.java b/javax/swing/plaf/multi/MultiLookAndFeel.java index 2bd358dd0..12351655a 100644 --- a/javax/swing/plaf/multi/MultiLookAndFeel.java +++ b/javax/swing/plaf/multi/MultiLookAndFeel.java @@ -49,7 +49,8 @@ import javax.swing.plaf.ComponentUI; * A look and feel that provides the ability to use auxiliary look and feels * in addition to the primary look and feel. */ -public class MultiLookAndFeel extends LookAndFeel { +public class MultiLookAndFeel extends LookAndFeel +{ /** * Creates a new instance of the look and feel. diff --git a/javax/swing/plaf/multi/MultiOptionPaneUI.java b/javax/swing/plaf/multi/MultiOptionPaneUI.java index c5cb913a0..8d6f3861c 100644 --- a/javax/swing/plaf/multi/MultiOptionPaneUI.java +++ b/javax/swing/plaf/multi/MultiOptionPaneUI.java @@ -356,7 +356,8 @@ public class MultiOptionPaneUI extends OptionPaneUI * * @param pane the option pane. */ - public void selectInitialValue(JOptionPane pane) { + public void selectInitialValue(JOptionPane pane) + { Iterator iterator = uis.iterator(); while (iterator.hasNext()) { @@ -375,7 +376,8 @@ public class MultiOptionPaneUI extends OptionPaneUI * * @return The result for the UI delegate from the primary look and feel. */ - public boolean containsCustomComponents(JOptionPane pane) { + public boolean containsCustomComponents(JOptionPane pane) + { boolean result = false; Iterator iterator = uis.iterator(); // first UI delegate provides the return value diff --git a/javax/swing/plaf/multi/MultiSplitPaneUI.java b/javax/swing/plaf/multi/MultiSplitPaneUI.java index f481f8109..70ea4f13b 100644 --- a/javax/swing/plaf/multi/MultiSplitPaneUI.java +++ b/javax/swing/plaf/multi/MultiSplitPaneUI.java @@ -356,7 +356,8 @@ public class MultiSplitPaneUI extends SplitPaneUI * * @param pane the component. */ - public void resetToPreferredSizes(JSplitPane pane) { + public void resetToPreferredSizes(JSplitPane pane) + { Iterator iterator = uis.iterator(); while (iterator.hasNext()) { @@ -372,7 +373,8 @@ public class MultiSplitPaneUI extends SplitPaneUI * @param pane the component. * @param location the location. */ - public void setDividerLocation(JSplitPane pane, int location) { + public void setDividerLocation(JSplitPane pane, int location) + { Iterator iterator = uis.iterator(); while (iterator.hasNext()) { @@ -392,7 +394,8 @@ public class MultiSplitPaneUI extends SplitPaneUI * @return The location returned by the UI delegate from the primary * look and feel. */ - public int getDividerLocation(JSplitPane pane) { + public int getDividerLocation(JSplitPane pane) + { int result = 0; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -421,7 +424,8 @@ public class MultiSplitPaneUI extends SplitPaneUI * @return The location returned by the UI delegate from the primary * look and feel. */ - public int getMinimumDividerLocation(JSplitPane pane) { + public int getMinimumDividerLocation(JSplitPane pane) + { int result = 0; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -450,7 +454,8 @@ public class MultiSplitPaneUI extends SplitPaneUI * @return The location returned by the UI delegate from the primary * look and feel. */ - public int getMaximumDividerLocation(JSplitPane pane) { + public int getMaximumDividerLocation(JSplitPane pane) + { int result = 0; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -476,7 +481,8 @@ public class MultiSplitPaneUI extends SplitPaneUI * @param pane the component. * @param g the graphics device. */ - public void finishedPaintingChildren(JSplitPane pane, Graphics g) { + public void finishedPaintingChildren(JSplitPane pane, Graphics g) + { Iterator iterator = uis.iterator(); while (iterator.hasNext()) { diff --git a/javax/swing/plaf/multi/MultiTabbedPaneUI.java b/javax/swing/plaf/multi/MultiTabbedPaneUI.java index 575de192a..2a2599bde 100644 --- a/javax/swing/plaf/multi/MultiTabbedPaneUI.java +++ b/javax/swing/plaf/multi/MultiTabbedPaneUI.java @@ -364,7 +364,8 @@ public class MultiTabbedPaneUI extends TabbedPaneUI * @return The tab index returned by the UI delegate from the primary * look and feel. */ - public int tabForCoordinate(JTabbedPane pane, int x, int y) { + public int tabForCoordinate(JTabbedPane pane, int x, int y) + { int result = 0; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -394,7 +395,8 @@ public class MultiTabbedPaneUI extends TabbedPaneUI * @return The bounds returned by the UI delegate from the primary * look and feel. */ - public Rectangle getTabBounds(JTabbedPane pane, int index) { + public Rectangle getTabBounds(JTabbedPane pane, int index) + { Rectangle result = null; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -423,7 +425,8 @@ public class MultiTabbedPaneUI extends TabbedPaneUI * @return The count returned by the UI delegate from the primary * look and feel. */ - public int getTabRunCount(JTabbedPane pane) { + public int getTabRunCount(JTabbedPane pane) + { int result = 0; Iterator iterator = uis.iterator(); // first UI delegate provides the return value diff --git a/javax/swing/table/AbstractTableModel.java b/javax/swing/table/AbstractTableModel.java index bda716ee7..66b6a0743 100644 --- a/javax/swing/table/AbstractTableModel.java +++ b/javax/swing/table/AbstractTableModel.java @@ -1,5 +1,5 @@ /* AbstractTableModel.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -83,7 +83,7 @@ public abstract class AbstractTableModel implements TableModel, Serializable StringBuffer buffer = new StringBuffer(); while (columnIndex >= 0) { - buffer.insert (0, (char) ('A' + columnIndex % 26)); + buffer.insert(0, (char) ('A' + columnIndex % 26)); columnIndex = columnIndex / 26 - 1; } return buffer.toString(); @@ -221,7 +221,7 @@ public abstract class AbstractTableModel implements TableModel, Serializable * @param firstRow the index of the first row. * @param lastRow the index of the last row. */ - public void fireTableRowsInserted (int firstRow, int lastRow) + public void fireTableRowsInserted(int firstRow, int lastRow) { fireTableChanged(new TableModelEvent(this, firstRow, lastRow, TableModelEvent.ALL_COLUMNS, @@ -235,7 +235,7 @@ public abstract class AbstractTableModel implements TableModel, Serializable * @param firstRow the index of the first row. * @param lastRow the index of the last row. */ - public void fireTableRowsUpdated (int firstRow, int lastRow) + public void fireTableRowsUpdated(int firstRow, int lastRow) { fireTableChanged(new TableModelEvent(this, firstRow, lastRow, TableModelEvent.ALL_COLUMNS, @@ -263,7 +263,7 @@ public abstract class AbstractTableModel implements TableModel, Serializable * @param row the row index. * @param column the column index. */ - public void fireTableCellUpdated (int row, int column) + public void fireTableCellUpdated(int row, int column) { fireTableChanged(new TableModelEvent(this, row, row, column)); } @@ -282,7 +282,7 @@ public abstract class AbstractTableModel implements TableModel, Serializable for (index = 0; index < list.length; index += 2) { listener = (TableModelListener) list [index + 1]; - listener.tableChanged (event); + listener.tableChanged(event); } } diff --git a/javax/swing/table/DefaultTableModel.java b/javax/swing/table/DefaultTableModel.java index 09be2f752..79285903c 100644 --- a/javax/swing/table/DefaultTableModel.java +++ b/javax/swing/table/DefaultTableModel.java @@ -1,5 +1,5 @@ /* DefaultTableModel.java -- - Copyright (C) 2002, 2004, 2005, Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -249,7 +249,7 @@ public class DefaultTableModel extends AbstractTableModel public void setColumnIdentifiers(Vector columnIdentifiers) { this.columnIdentifiers = columnIdentifiers; - setColumnCount((columnIdentifiers == null ? 0 : columnIdentifiers.size())); + setColumnCount(columnIdentifiers == null ? 0 : columnIdentifiers.size()); } /** @@ -289,13 +289,13 @@ public class DefaultTableModel extends AbstractTableModel if (rowCount < existingRowCount) { dataVector.setSize(rowCount); - fireTableRowsDeleted(rowCount,existingRowCount-1); + fireTableRowsDeleted(rowCount, existingRowCount - 1); } else { int rowsToAdd = rowCount - existingRowCount; addExtraRows(rowsToAdd, columnIdentifiers.size()); - fireTableRowsInserted(existingRowCount,rowCount-1); + fireTableRowsInserted(existingRowCount, rowCount - 1); } } @@ -353,7 +353,8 @@ public class DefaultTableModel extends AbstractTableModel * @param columnName the column name (<code>null</code> permitted). * @param columnData the column data. */ - public void addColumn(Object columnName, Object[] columnData) { + public void addColumn(Object columnName, Object[] columnData) + { if (columnData != null) { // check columnData array for cases where the number of items @@ -384,7 +385,8 @@ public class DefaultTableModel extends AbstractTableModel * * @param rowData the row data (<code>null</code> permitted). */ - public void addRow(Vector rowData) { + public void addRow(Vector rowData) + { int rowIndex = dataVector.size(); dataVector.add(rowData); newRowsAdded(new TableModelEvent( @@ -398,7 +400,8 @@ public class DefaultTableModel extends AbstractTableModel * * @param rowData the row data (<code>null</code> permitted). */ - public void addRow(Object[] rowData) { + public void addRow(Object[] rowData) + { addRow(convertToVector(rowData)); } @@ -408,9 +411,10 @@ public class DefaultTableModel extends AbstractTableModel * @param row the row index. * @param rowData the row data. */ - public void insertRow(int row, Vector rowData) { + public void insertRow(int row, Vector rowData) + { dataVector.add(row, rowData); - fireTableRowsInserted(row,row); + fireTableRowsInserted(row, row); } /** @@ -419,7 +423,8 @@ public class DefaultTableModel extends AbstractTableModel * @param row the row index. * @param rowData the row data. */ - public void insertRow(int row, Object[] rowData) { + public void insertRow(int row, Object[] rowData) + { insertRow(row, convertToVector(rowData)); } @@ -431,7 +436,8 @@ public class DefaultTableModel extends AbstractTableModel * @param endIndex the end row. * @param toIndex the row to move to. */ - public void moveRow(int startIndex, int endIndex, int toIndex) { + public void moveRow(int startIndex, int endIndex, int toIndex) + { Vector removed = new Vector(); for (int i = endIndex; i >= startIndex; i--) { @@ -452,9 +458,10 @@ public class DefaultTableModel extends AbstractTableModel * * @param row the row index. */ - public void removeRow(int row) { + public void removeRow(int row) + { dataVector.remove(row); - fireTableRowsDeleted(row,row); + fireTableRowsDeleted(row, row); } /** @@ -462,7 +469,8 @@ public class DefaultTableModel extends AbstractTableModel * * @return The row count. */ - public int getRowCount() { + public int getRowCount() + { return dataVector.size(); } @@ -471,8 +479,9 @@ public class DefaultTableModel extends AbstractTableModel * * @return The column count. */ - public int getColumnCount() { - return (columnIdentifiers == null ? 0 : columnIdentifiers.size()); + public int getColumnCount() + { + return columnIdentifiers == null ? 0 : columnIdentifiers.size(); } /** @@ -485,7 +494,8 @@ public class DefaultTableModel extends AbstractTableModel * * @return The column name. */ - public String getColumnName(int column) { + public String getColumnName(int column) + { String result = ""; if (columnIdentifiers == null) result = super.getColumnName(column); @@ -516,7 +526,8 @@ public class DefaultTableModel extends AbstractTableModel * * @return <code>true</code> in all cases. */ - public boolean isCellEditable(int row, int column) { + public boolean isCellEditable(int row, int column) + { return true; } @@ -529,7 +540,8 @@ public class DefaultTableModel extends AbstractTableModel * @return The value (<code>Object</code>, possibly <code>null</code>) at * the specified cell in the table. */ - public Object getValueAt(int row, int column) { + public Object getValueAt(int row, int column) + { return ((Vector) dataVector.get(row)).get(column); } @@ -541,9 +553,10 @@ public class DefaultTableModel extends AbstractTableModel * @param row the row index. * @param column the column index. */ - public void setValueAt(Object value, int row, int column) { + public void setValueAt(Object value, int row, int column) + { ((Vector) dataVector.get(row)).set(column, value); - fireTableCellUpdated(row,column); + fireTableCellUpdated(row, column); } /** @@ -554,7 +567,8 @@ public class DefaultTableModel extends AbstractTableModel * @return A vector (or <code>null</code> if the data array * is <code>null</code>). */ - protected static Vector convertToVector(Object[] data) { + protected static Vector convertToVector(Object[] data) + { if (data == null) return null; Vector vector = new Vector(data.length); @@ -571,7 +585,8 @@ public class DefaultTableModel extends AbstractTableModel * @return A vector (or <code>null</code> if the data array * is <code>null</code>. */ - protected static Vector convertToVector(Object[][] data) { + protected static Vector convertToVector(Object[][] data) + { if (data == null) return null; Vector vector = new Vector(data.length); diff --git a/javax/swing/table/TableCellEditor.java b/javax/swing/table/TableCellEditor.java index b355311dc..15070a755 100644 --- a/javax/swing/table/TableCellEditor.java +++ b/javax/swing/table/TableCellEditor.java @@ -47,19 +47,19 @@ import javax.swing.JTable; * TableCellEditor public interface * @author Andrew Selkirk */ -public interface TableCellEditor extends CellEditor { +public interface TableCellEditor extends CellEditor +{ - /** - * Get table cell editor component - * @param table JTable - * @param value Value of cell - * @param isSelected Cell selected - * @param row Row of cell - * @param column Column of cell - * @returns Component - */ - Component getTableCellEditorComponent(JTable table, - Object value, boolean isSelected, int row, int column); + /** + * Get table cell editor component + * @param table JTable + * @param value Value of cell + * @param isSelected Cell selected + * @param row Row of cell + * @param column Column of cell + * @return Component + */ + Component getTableCellEditorComponent(JTable table, Object value, + boolean isSelected, int row, int column); - -} // TableCellEditor +} diff --git a/javax/swing/table/TableCellRenderer.java b/javax/swing/table/TableCellRenderer.java index 639b4b9ad..6c1fecf56 100644 --- a/javax/swing/table/TableCellRenderer.java +++ b/javax/swing/table/TableCellRenderer.java @@ -46,21 +46,21 @@ import javax.swing.JTable; * TableCellRenderer public interface * @author Andrew Selkirk */ -public interface TableCellRenderer { +public interface TableCellRenderer +{ - /** - * Get table cell renderer component - * @param table JTable - * @param value Value of cell - * @param isSelected Cell selected - * @param hasFocus Cell has focus - * @param row Row of cell - * @param column Column of cell - * @returns Component - */ - Component getTableCellRendererComponent(JTable table, - Object value, boolean isSelected, boolean hasFocus, - int row, int column); + /** + * Get table cell renderer component + * @param table JTable + * @param value Value of cell + * @param isSelected Cell selected + * @param hasFocus Cell has focus + * @param row Row of cell + * @param column Column of cell + * @return Component + */ + Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column); -} // TableCellRenderer +} diff --git a/javax/swing/text/AbstractWriter.java b/javax/swing/text/AbstractWriter.java index d5fc395e1..8d5a6075d 100644 --- a/javax/swing/text/AbstractWriter.java +++ b/javax/swing/text/AbstractWriter.java @@ -183,7 +183,8 @@ public abstract class AbstractWriter if (! elt.isLeaf()) throw new BadLocationException("Element is not a leaf", elt.getStartOffset()); - return document.getText(elt.getStartOffset(), elt.getEndOffset()); + return document.getText(elt.getStartOffset(), + elt.getEndOffset() - elt.getStartOffset()); } /** diff --git a/javax/swing/text/DefaultCaret.java b/javax/swing/text/DefaultCaret.java index 3bef80d9e..ce93cf56e 100644 --- a/javax/swing/text/DefaultCaret.java +++ b/javax/swing/text/DefaultCaret.java @@ -216,13 +216,26 @@ public class DefaultCaret extends Rectangle */ public void propertyChange(PropertyChangeEvent e) { - if (e.getPropertyName().equals("document")) + String name = e.getPropertyName(); + + if (name.equals("document")) { Document oldDoc = (Document) e.getOldValue(); oldDoc.removeDocumentListener(documentListener); Document newDoc = (Document) e.getNewValue(); newDoc.addDocumentListener(documentListener); } + else if (name.equals("editable")) + { + active = (((Boolean) e.getNewValue()).booleanValue() + && textComponent.isEnabled()); + } + else if (name.equals("enabled")) + { + active = (((Boolean) e.getNewValue()).booleanValue() + && textComponent.isEditable()); + } + } } @@ -281,8 +294,10 @@ public class DefaultCaret extends Rectangle /** * The text component in which this caret is installed. + * + * (Package private to avoid synthetic accessor method.) */ - private JTextComponent textComponent; + JTextComponent textComponent; /** * Indicates if the selection should be visible or not. @@ -314,6 +329,12 @@ public class DefaultCaret extends Rectangle * package private to avoid an accessor method. */ boolean visible = false; + + /** Indicates whether the text component where the caret is installed is + * editable and enabled. If either of these properties is <code>false</code> + * the caret is not drawn. + */ + boolean active = true; /** * The current highlight entry. @@ -388,14 +409,23 @@ public class DefaultCaret extends Rectangle /** * Moves the caret position when the mouse is dragged over the text - * component, modifying the selection accordingly. + * component, modifying the selectiony. + * + * <p>When the text component where the caret is installed is disabled, + * the selection is not change but you can still scroll the text and + * update the caret's location.</p> * * @param event the <code>MouseEvent</code> describing the drag operation */ public void mouseDragged(MouseEvent event) { if (event.getButton() == MouseEvent.BUTTON1) - moveCaret(event); + { + if (textComponent.isEnabled()) + moveCaret(event); + else + positionCaret(event); + } } /** @@ -426,6 +456,10 @@ public class DefaultCaret extends Rectangle */ public void mouseClicked(MouseEvent event) { + // Do not modify selection if component is disabled. + if (!textComponent.isEnabled()) + return; + int count = event.getClickCount(); if (event.getButton() == MouseEvent.BUTTON1 && count >= 2) @@ -523,7 +557,7 @@ public class DefaultCaret extends Rectangle // implemented (in regard to text components): // - a left-click moves the caret // - a left-click when shift is held down expands the selection - // - a right-click or click with any additionaly mouse button + // - a right-click or click with any additional mouse button // on a text component is ignored // - a middle-click positions the caret and pastes the clipboard // contents. @@ -540,6 +574,7 @@ public class DefaultCaret extends Rectangle else { positionCaret(event); + textComponent.paste(); } else @@ -564,8 +599,11 @@ public class DefaultCaret extends Rectangle */ public void focusGained(FocusEvent event) { - setVisible(true); - updateTimerStatus(); + if (textComponent.isEditable()) + { + setVisible(true); + updateTimerStatus(); + } } /** @@ -575,9 +613,10 @@ public class DefaultCaret extends Rectangle */ public void focusLost(FocusEvent event) { - if (event.isTemporary() == false) + if (textComponent.isEditable() && event.isTemporary() == false) { setVisible(false); + // Stop the blinker, if running. if (blinkTimer != null && blinkTimer.isRunning()) blinkTimer.stop(); @@ -670,6 +709,7 @@ public class DefaultCaret extends Rectangle textComponent.addPropertyChangeListener(propertyChangeListener); documentListener = new DocumentHandler(); textComponent.getDocument().addDocumentListener(documentListener); + active = textComponent.isEditable() && textComponent.isEnabled(); repaint(); } @@ -872,7 +912,7 @@ public class DefaultCaret extends Rectangle } // Now draw the caret on the new position if visible. - if (visible) + if (visible && active) { g.setColor(textComponent.getCaretColor()); g.drawLine(rect.x, rect.y, rect.x, rect.y + rect.height - 1); @@ -1013,7 +1053,9 @@ public class DefaultCaret extends Rectangle this.dot = Math.max(this.dot, 0); handleHighlight(); + appear(); + adjustVisibility(this); } } @@ -1050,7 +1092,9 @@ public class DefaultCaret extends Rectangle this.mark = this.dot; clearHighlight(); + appear(); + adjustVisibility(this); } } @@ -1104,7 +1148,7 @@ public class DefaultCaret extends Rectangle */ public boolean isVisible() { - return visible; + return visible && active; } /** diff --git a/javax/swing/text/DefaultEditorKit.java b/javax/swing/text/DefaultEditorKit.java index 1b686182b..8602e69f8 100644 --- a/javax/swing/text/DefaultEditorKit.java +++ b/javax/swing/text/DefaultEditorKit.java @@ -52,6 +52,7 @@ import java.io.Reader; import java.io.Writer; import javax.swing.Action; +import javax.swing.SwingConstants; /** * The default implementation of {@link EditorKit}. This <code>EditorKit</code> @@ -60,6 +61,7 @@ import javax.swing.Action; * * @author original author unknown * @author Roman Kennke (roman@kennke.org) + * @author Robert Schuster (robertschuster@fsfe.org) */ public class DefaultEditorKit extends EditorKit { @@ -123,6 +125,122 @@ public class DefaultEditorKit extends EditorKit } } + static class SelectionBeginWordAction extends TextAction + { + SelectionBeginWordAction() + { + super(selectionBeginWordAction); + } + + public void actionPerformed(ActionEvent event) + { + try + { + JTextComponent t = getTextComponent(event); + + if (t != null) + { + int offs = Utilities.getWordStart(t, t.getCaretPosition()); + + Caret c = t.getCaret(); + c.moveDot(offs); + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + } + catch(BadLocationException ble) + { + // Can't happen. + } + } + } + + static class SelectionEndWordAction extends TextAction + { + SelectionEndWordAction() + { + super(selectionEndWordAction); + } + + public void actionPerformed(ActionEvent event) + { + try + { + JTextComponent t = getTextComponent(event); + + if (t != null) + { + int offs = Utilities.getWordEnd(t, t.getCaretPosition()); + + Caret c = t.getCaret(); + c.moveDot(offs); + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + } + catch(BadLocationException ble) + { + // Can't happen. + } + } + } + + static class BeginWordAction extends TextAction + { + BeginWordAction() + { + super(beginWordAction); + } + + public void actionPerformed(ActionEvent event) + { + try + { + JTextComponent t = getTextComponent(event); + + if (t != null) + { + int offs = Utilities.getWordStart(t, t.getCaretPosition()); + + Caret c = t.getCaret(); + c.setDot(offs); + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + } + catch(BadLocationException ble) + { + // Can't happen. + } + } + } + + static class EndWordAction extends TextAction + { + EndWordAction() + { + super(endWordAction); + } + + public void actionPerformed(ActionEvent event) + { + try + { + JTextComponent t = getTextComponent(event); + + if (t != null) + { + int offs = Utilities.getWordEnd(t, t.getCaretPosition()); + + Caret c = t.getCaret(); + c.setDot(offs); + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + } + catch(BadLocationException ble) + { + // Can't happen. + } + } + } + static class PreviousWordAction extends TextAction { @@ -258,336 +376,260 @@ public class DefaultEditorKit extends EditorKit } } } - - static class SelectionEndLineAction - extends TextAction + + static class SelectionBeginLineAction + extends TextAction { - SelectionEndLineAction() + + SelectionBeginLineAction() { - super(selectionEndLineAction); + super(selectionBeginLineAction); } public void actionPerformed(ActionEvent event) { JTextComponent t = getTextComponent(event); - try - { - Point p = t.modelToView(t.getCaret().getDot()).getLocation(); - int cur = t.getCaretPosition(); - int y = p.y; - int length = t.getDocument().getLength(); - while (y == p.y && cur < length) - y = t.modelToView(++cur).getLocation().y; - if (cur != length) - cur--; - - Caret c = t.getCaret(); - c.moveDot(cur); - c.setMagicCaretPosition(t.modelToView(cur).getLocation()); - } - catch (BadLocationException ble) - { - // Nothing to do here - } + Caret c = t.getCaret(); + try + { + int offs = Utilities.getRowStart(t, c.getDot()); + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + catch(BadLocationException ble) + { + // Can't happen. + } + } } - static class SelectionBeginLineAction + static class SelectionEndLineAction extends TextAction { - SelectionBeginLineAction() + SelectionEndLineAction() { - super(selectionBeginLineAction); + super(selectionEndLineAction); } public void actionPerformed(ActionEvent event) { JTextComponent t = getTextComponent(event); - + Caret c = t.getCaret(); try - { - // TODO: There is a more efficent solution, but - // viewToModel doesn't work properly. - Point p = t.modelToView(t.getCaret().getDot()).getLocation(); - - int cur = t.getCaretPosition(); - int y = p.y; - - while (y == p.y && cur > 0) - y = t.modelToView(--cur).getLocation().y; - if (cur != 0) - cur++; - - Caret c = t.getCaret(); - c.moveDot(cur); - c.setMagicCaretPosition(t.modelToView(cur).getLocation()); - } - catch (BadLocationException ble) - { - // Do nothing here. - } + { + int offs = Utilities.getRowEnd(t, c.getDot()); + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + catch(BadLocationException ble) + { + // Can't happen. + } + } } - - static class SelectionDownAction - extends TextAction + + static class SelectLineAction extends TextAction { - SelectionDownAction() + SelectLineAction() { - super(selectionDownAction); + super(selectLineAction); } - + public void actionPerformed(ActionEvent event) { JTextComponent t = getTextComponent(event); + Caret c = t.getCaret(); try { - if (t != null) - { - Caret c = t.getCaret(); - // The magic caret position may be null when the caret - // has not moved yet. - Point mcp = c.getMagicCaretPosition(); - int x = (mcp != null) ? mcp.x : 0; - int pos = Utilities.getPositionBelow(t, t.getCaretPosition(), x); - - if (pos > -1) - t.moveCaretPosition(pos); - } + int offs1 = Utilities.getRowStart(t, c.getDot()); + int offs2 = Utilities.getRowEnd(t, c.getDot()); + + c.setDot(offs2); + c.moveDot(offs1); + + c.setMagicCaretPosition(t.modelToView(offs2).getLocation()); } - catch(BadLocationException ble) + catch(BadLocationException ble) { - // FIXME: Swallowing allowed? + // Can't happen. } } } - - static class SelectionUpAction - extends TextAction + + static class SelectWordAction extends TextAction { - SelectionUpAction() + SelectWordAction() { - super(selectionUpAction); + super(selectWordAction); } - + public void actionPerformed(ActionEvent event) { JTextComponent t = getTextComponent(event); + Caret c = t.getCaret(); + int dot = c.getDot(); + try { - if (t != null) + int wordStart = Utilities.getWordStart(t, dot); + + if (dot == wordStart) { - Caret c = t.getCaret(); - // The magic caret position may be null when the caret - // has not moved yet. - Point mcp = c.getMagicCaretPosition(); - int x = (mcp != null) ? mcp.x : 0; - int pos = Utilities.getPositionAbove(t, t.getCaretPosition(), x); + // Current cursor position is on the first character in a word. + c.setDot(wordStart); + c.moveDot(Utilities.getWordEnd(t, wordStart)); + } + else + { + // Current cursor position is not on the first character + // in a word. + int nextWord = Utilities.getNextWord(t, dot); + int previousWord = Utilities.getPreviousWord(t, dot); + int previousWordEnd = Utilities.getWordEnd(t, previousWord); - if (pos > -1) - t.moveCaretPosition(pos); + // Cursor position is in the space between two words. In such a + // situation just select the space. + if (dot >= previousWordEnd && dot <= nextWord) + { + c.setDot(previousWordEnd); + c.moveDot(nextWord); + } + else + { + // Cursor position is inside a word. Just select it then. + c.setDot(previousWord); + c.moveDot(previousWordEnd); + } } + + // If the position was updated change the magic caret position + // as well. + if (c.getDot() != dot) + c.setMagicCaretPosition(t.modelToView(c.getDot()).getLocation()); + } - catch(BadLocationException ble) + catch(BadLocationException ble) { - // FIXME: Swallowing allowed? + // Can't happen. } } } + static class SelectionDownAction + extends TextAction.VerticalMovementAction + { + SelectionDownAction() + { + super(selectionDownAction, SwingConstants.SOUTH); + } + + protected void actionPerformedImpl(Caret c, int offs) + { + c.moveDot(offs); + } + + } + + static class SelectionUpAction + extends TextAction.VerticalMovementAction + { + SelectionUpAction() + { + super(selectionUpAction, SwingConstants.NORTH); + } + + protected void actionPerformedImpl(Caret c, int offs) + { + c.moveDot(offs); + } + + } + static class SelectionForwardAction - extends TextAction + extends TextAction.HorizontalMovementAction { SelectionForwardAction() { - super(selectionForwardAction); + super(selectionForwardAction, SwingConstants.EAST); } - public void actionPerformed(ActionEvent event) + protected void actionPerformedImpl(Caret c, int offs) { - JTextComponent t = getTextComponent(event); - if (t != null) - { - int offs = t.getCaretPosition() + 1; - - if(offs <= t.getDocument().getLength()) - { - Caret c = t.getCaret(); - c.moveDot(offs); - try - { - c.setMagicCaretPosition(t.modelToView(offs).getLocation()); - } - catch(BadLocationException ble) - { - // Can't happen. - } - } - } + c.moveDot(offs); } } static class SelectionBackwardAction - extends TextAction + extends TextAction.HorizontalMovementAction { SelectionBackwardAction() { - super(selectionBackwardAction); + super(selectionBackwardAction, SwingConstants.WEST); } - public void actionPerformed(ActionEvent event) + protected void actionPerformedImpl(Caret c, int offs) { - JTextComponent t = getTextComponent(event); - if (t != null) - { - int offs = t.getCaretPosition() - 1; - - if(offs >= 0) - { - Caret c = t.getCaret(); - c.moveDot(offs); - try - { - c.setMagicCaretPosition(t.modelToView(offs).getLocation()); - } - catch(BadLocationException ble) - { - // Can't happen. - } - } - } + c.moveDot(offs); } } static class DownAction - extends TextAction + extends TextAction.VerticalMovementAction { DownAction() { - super(downAction); + super(downAction, SwingConstants.SOUTH); } - public void actionPerformed(ActionEvent event) + protected void actionPerformedImpl(Caret c, int offs) { - JTextComponent t = getTextComponent(event); - try - { - if (t != null) - { - Caret c = t.getCaret(); - // The magic caret position may be null when the caret - // has not moved yet. - Point mcp = c.getMagicCaretPosition(); - int x = (mcp != null) ? mcp.x : 0; - int pos = Utilities.getPositionBelow(t, t.getCaretPosition(), x); - - if (pos > -1) - t.setCaretPosition(pos); - } - } - catch(BadLocationException ble) - { - // FIXME: Swallowing allowed? - } + c.setDot(offs); } } static class UpAction - extends TextAction + extends TextAction.VerticalMovementAction { UpAction() { - super(upAction); + super(upAction, SwingConstants.NORTH); } - public void actionPerformed(ActionEvent event) + protected void actionPerformedImpl(Caret c, int offs) { - JTextComponent t = getTextComponent(event); - try - { - if (t != null) - { - Caret c = t.getCaret(); - // The magic caret position may be null when the caret - // has not moved yet. - Point mcp = c.getMagicCaretPosition(); - int x = (mcp != null) ? mcp.x : 0; - int pos = Utilities.getPositionAbove(t, t.getCaretPosition(), x); - - if (pos > -1) - t.setCaretPosition(pos); - } - } - catch(BadLocationException ble) - { - // FIXME: Swallowing allowed? - } + c.setDot(offs); } + } static class ForwardAction - extends TextAction + extends TextAction.HorizontalMovementAction { ForwardAction() { - super(forwardAction); + super(forwardAction, SwingConstants.EAST); } - public void actionPerformed(ActionEvent event) + protected void actionPerformedImpl(Caret c, int offs) { - JTextComponent t = getTextComponent(event); - if (t != null) - { - int offs = t.getCaretPosition() + 1; - if (offs <= t.getDocument().getLength()) - { - Caret c = t.getCaret(); - c.setDot(offs); - - try - { - c.setMagicCaretPosition(t.modelToView(offs).getLocation()); - } - catch (BadLocationException ble) - { - // Should not happen. - } - } - } - + c.setDot(offs); } + } static class BackwardAction - extends TextAction + extends TextAction.HorizontalMovementAction { BackwardAction() { - super(backwardAction); + super(backwardAction, SwingConstants.WEST); } - public void actionPerformed(ActionEvent event) + protected void actionPerformedImpl(Caret c, int offs) { - JTextComponent t = getTextComponent(event); - if (t != null) - { - int offs = t.getCaretPosition() - 1; - if (offs >= 0) - { - Caret c = t.getCaret(); - c.setDot(offs); - - try - { - c.setMagicCaretPosition(t.modelToView(offs).getLocation()); - } - catch (BadLocationException ble) - { - // Should not happen. - } - } - } + c.setDot(offs); } + } static class DeletePrevCharAction @@ -720,6 +762,55 @@ public class DefaultEditorKit extends EditorKit } } + static class BeginAction extends TextAction + { + + BeginAction() + { + super(beginAction); + } + + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + Caret c = t.getCaret(); + c.setDot(0); + try + { + c.setMagicCaretPosition(t.modelToView(0).getLocation()); + } + catch(BadLocationException ble) + { + // Can't happen. + } + } + } + + static class EndAction extends TextAction + { + + EndAction() + { + super(endAction); + } + + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + int offs = t.getDocument().getLength(); + Caret c = t.getCaret(); + c.setDot(offs); + try + { + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + catch(BadLocationException ble) + { + // Can't happen. + } + } + } + /** * Creates a beep on the PC speaker. * @@ -867,8 +958,8 @@ public class DefaultEditorKit extends EditorKit // first we filter the following events: // - control characters // - key events with the ALT modifier (FIXME: filter that too!) - char c = event.getActionCommand().charAt(0); - if (Character.isISOControl(c)) + int cp = event.getActionCommand().codePointAt(0); + if (Character.isISOControl(cp)) return; JTextComponent t = getTextComponent(event); @@ -1345,8 +1436,6 @@ public class DefaultEditorKit extends EditorKit * The <code>Action</code>s that are supported by the * <code>DefaultEditorKit</code>. */ - // TODO: All these inner classes look ugly. Maybe work out a better way - // to handle this. private static Action[] defaultActions = new Action[] { // These classes are public because they are so in the RI. @@ -1387,9 +1476,21 @@ public class DefaultEditorKit extends EditorKit new PreviousWordAction(), new SelectionPreviousWordAction(), + new BeginAction(), new SelectionBeginAction(), + + new EndAction(), new SelectionEndAction(), + + new BeginWordAction(), + new SelectionBeginWordAction(), + + new EndWordAction(), + new SelectionEndWordAction(), + new SelectAllAction(), + new SelectLineAction(), + new SelectWordAction() }; /** diff --git a/javax/swing/text/FieldView.java b/javax/swing/text/FieldView.java index 0c2f0fef1..f41f90130 100644 --- a/javax/swing/text/FieldView.java +++ b/javax/swing/text/FieldView.java @@ -50,6 +50,7 @@ import java.awt.event.ActionListener; import javax.swing.BoundedRangeModel; import javax.swing.JTextField; +import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; @@ -241,12 +242,29 @@ public class FieldView extends PlainView Shape newAlloc = adjustAllocation(s); - // Set a clip to prevent drawing outside of the allocation area. - // TODO: Is there a better way to achieve this? Shape clip = g.getClip(); - g.setClip(s); + if (clip != null) + { + // Reason for this: The allocation area is always determined by the + // size of the component (and its insets) regardless of whether + // parts of the component are invisible or not (e.g. when the + // component is part of a JScrollPane and partly moved out of + // the user-visible range). However the clip of the Graphics + // instance may be adjusted properly to that condition but + // does not handle insets. By calculating the intersection + // we get the correct clip to paint the text in all cases. + Rectangle r = s.getBounds(); + Rectangle cb = clip.getBounds(); + SwingUtilities.computeIntersection(r.x, r.y, r.width, r.height, cb); + + g.setClip(cb); + } + else + g.setClip(s); + super.paint(g, newAlloc); g.setClip(clip); + } public void insertUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) diff --git a/javax/swing/text/GapContent.java b/javax/swing/text/GapContent.java index 219accb40..780297ce9 100644 --- a/javax/swing/text/GapContent.java +++ b/javax/swing/text/GapContent.java @@ -39,13 +39,10 @@ exception statement from your version. */ package javax.swing.text; import java.io.Serializable; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; import java.util.Iterator; -import java.util.ListIterator; +import java.util.Set; import java.util.Vector; +import java.util.WeakHashMap; import javax.swing.undo.AbstractUndoableEdit; import javax.swing.undo.CannotRedoException; @@ -60,8 +57,6 @@ import javax.swing.undo.UndoableEdit; * minimal (simple array access). The array only has to be shifted around when * the insertion point moves (then the gap also moves and one array copy is * necessary) or when the gap is filled up and the buffer has to be enlarged. - * - * TODO: Implement UndoableEdit support stuff */ public class GapContent implements AbstractDocument.Content, Serializable @@ -71,11 +66,14 @@ public class GapContent * A {@link Position} implementation for <code>GapContent</code>. */ private class GapContentPosition - implements Position, Comparable + implements Position { - /** The index within the buffer array. */ - int mark; + /** + * The index to the positionMarks array entry, which in turn holds the + * mark into the buffer array. + */ + int index; /** * Creates a new GapContentPosition object. @@ -84,33 +82,20 @@ public class GapContent */ GapContentPosition(int mark) { - this.mark = mark; - } - - /** - * Comparable interface implementation. This is used to store all - * positions in an ordered fashion. - * - * @param o the object to be compared to this - * - * @return a negative integer if this is less than <code>o</code>, zero - * if both are equal or a positive integer if this is greater than - * <code>o</code> - * - * @throws ClassCastException if <code>o</code> is not a - * GapContentPosition or Integer object - */ - public int compareTo(Object o) - { - if (o instanceof Integer) + // Try to find the mark in the positionMarks array, and store the index + // to it. + synchronized (GapContent.this) { - int otherMark = ((Integer) o).intValue(); - return mark - otherMark; - } - else - { - GapContentPosition other = (GapContentPosition) o; - return mark - other.mark; + int i = binarySearch(positionMarks, mark, numMarks); + if (i >= 0) // mark found + { + index = i; + } + else + { + index = -i - 1; + insertMark(index, mark); + } } } @@ -121,14 +106,19 @@ public class GapContent */ public int getOffset() { - // Check precondition. - assert mark <= gapStart || mark >= gapEnd : "mark: " + mark - + ", gapStart: " + gapStart - + ", gapEnd: " + gapEnd; - if (mark <= gapStart) - return mark; - else - return mark - (gapEnd - gapStart); + synchronized (GapContent.this) + { + // Fetch the actual mark. + int mark = positionMarks[index]; + // Check precondition. + assert mark <= gapStart || mark >= gapEnd : "mark: " + mark + + ", gapStart: " + gapStart + + ", gapEnd: " + gapEnd; + int res = mark; + if (mark > gapStart) + res -= (gapEnd - gapStart); + return res; + } } } @@ -209,40 +199,6 @@ public class GapContent } - /** - * Compares WeakReference objects in a List by comparing the referenced - * objects instead. - * - * @author Roman Kennke (kennke@aicas.com) - */ - private class WeakPositionComparator - implements Comparator - { - - /** - * Compares two objects of type WeakReference. The objects are compared - * using the referenced objects compareTo() method. - */ - public int compare(Object o1, Object o2) - { - // Unwrap references. - if (o1 instanceof WeakReference) - o1 = ((WeakReference) o1).get(); - if (o2 instanceof WeakReference) - o2 = ((WeakReference) o2).get(); - - GapContentPosition p1 = (GapContentPosition) o1; - GapContentPosition p2 = (GapContentPosition) o2; - - int retVal; - if (p1 == null || p2 == null) - retVal = -1; - else - retVal = p1.compareTo(p2); - return retVal; - } - } - /** The serialization UID (compatible with JDK1.5). */ private static final long serialVersionUID = -6226052713477823730L; @@ -267,12 +223,26 @@ public class GapContent */ int gapEnd; + // FIXME: We might want to track GC'ed GapContentPositions and remove their + // corresponding marks, or alternativly, perform some regular cleanup of + // the positionMarks array. + + /** + * Holds the marks for positions. These marks are referenced by the + * GapContentPosition instances by an index into this array. + */ + int[] positionMarks; + /** - * The positions generated by this GapContent. They are kept in an ordered - * fashion, so they can be looked up easily. The value objects will be - * WeakReference objects that in turn hold GapContentPosition objects. + * The number of elements in the positionMarks array. The positionMarks array + * might be bigger than the actual number of elements. */ - private ArrayList positions; + int numMarks; + + /** + * (Weakly) Stores the GapContentPosition instances. + */ + WeakHashMap positions; /** * Creates a new GapContent object. @@ -294,7 +264,9 @@ public class GapContent gapStart = 1; gapEnd = size; buffer[0] = '\n'; - positions = new ArrayList(); + positions = new WeakHashMap(); + positionMarks = new int[10]; + numMarks = 0; } /** @@ -483,26 +455,30 @@ public class GapContent */ public Position createPosition(final int offset) throws BadLocationException { - if (offset < 0 || offset > length()) - throw new BadLocationException("The offset was out of the bounds of this" - + " buffer", offset); - - clearPositionReferences(); - - // We store the actual array index in the GapContentPosition. The real - // offset is then calculated in the GapContentPosition. - int mark = offset; - if (offset >= gapStart) - mark += gapEnd - gapStart; - GapContentPosition pos = new GapContentPosition(mark); - WeakReference r = new WeakReference(pos); - - // Add this into our list in a sorted fashion. - int index = Collections.binarySearch(positions, r, - new WeakPositionComparator()); - if (index < 0) - index = -(index + 1); - positions.add(index, r); + // We try to find a GapContentPosition at the specified offset and return + // that. Otherwise we must create a new one. + GapContentPosition pos = null; + Set positionSet = positions.keySet(); + for (Iterator i = positionSet.iterator(); i.hasNext();) + { + GapContentPosition p = (GapContentPosition) i.next(); + if (p.getOffset() == offset) + { + pos = p; + break; + } + } + + // If none was found, then create and return a new one. + if (pos == null) + { + int mark = offset; + if (mark >= gapStart) + mark += (gapEnd - gapStart); + pos = new GapContentPosition(mark); + positions.put(pos, null); + } + return pos; } @@ -542,7 +518,6 @@ public class GapContent { if (newGapStart == gapStart) return; - int newGapEnd = newGapStart + gapEnd - gapStart; if (newGapStart < gapStart) { @@ -583,7 +558,7 @@ public class GapContent assert newGapStart < gapStart : "The new gap start must be less than the " + "old gap start."; - setPositionsInRange(newGapStart, gapStart - newGapStart, gapStart); + setPositionsInRange(newGapStart, gapStart, false); gapStart = newGapStart; } @@ -602,7 +577,7 @@ public class GapContent assert newGapEnd > gapEnd : "The new gap end must be greater than the " + "old gap end."; - setPositionsInRange(gapEnd, newGapEnd - gapEnd, newGapEnd); + setPositionsInRange(gapEnd, newGapEnd, false); gapEnd = newGapEnd; } @@ -688,85 +663,79 @@ public class GapContent else res.clear(); - int endOffset = offset + length; - - int index1 = Collections.binarySearch(positions, - new GapContentPosition(offset), - new WeakPositionComparator()); - if (index1 < 0) - index1 = -(index1 + 1); - - // Search the first index with the specified offset. The binarySearch does - // not necessarily find the first one. - while (index1 > 0) - { - WeakReference r = (WeakReference) positions.get(index1 - 1); - GapContentPosition p = (GapContentPosition) r.get(); - if (p != null && p.mark == offset || p == null) - index1--; - else - break; - } + int endOffs = offset + length; - for (ListIterator i = positions.listIterator(index1); i.hasNext();) + Set positionSet = positions.keySet(); + for (Iterator i = positionSet.iterator(); i.hasNext();) { - WeakReference r = (WeakReference) i.next(); - GapContentPosition p = (GapContentPosition) r.get(); - if (p == null) - continue; - - if (p.mark > endOffset) - break; - if (p.mark >= offset && p.mark <= endOffset) + GapContentPosition p = (GapContentPosition) i.next(); + int offs = p.getOffset(); + if (offs >= offset && offs < endOffs) res.add(p); } + return res; } /** - * Sets the mark of all <code>Position</code>s that are in the range - * specified by <code>offset</code> and </code>length</code> within - * the buffer array to <code>value</code> + * Crunches all positions in the specified range to either the start or + * end of that interval. The interval boundaries are meant to be inclusive + * [start, end]. * - * @param offset the start offset of the range to search - * @param length the length of the range to search - * @param value the new value for each mark + * @param start the start offset of the range + * @param end the end offset of the range + * @param toStart a boolean indicating if the positions should be crunched + * to the start (true) or to the end (false) */ - private void setPositionsInRange(int offset, int length, int value) + private void setPositionsInRange(int start, int end, boolean toStart) { - int endOffset = offset + length; - - int index1 = Collections.binarySearch(positions, - new GapContentPosition(offset), - new WeakPositionComparator()); - if (index1 < 0) - index1 = -(index1 + 1); - - // Search the first index with the specified offset. The binarySearch does - // not necessarily find the first one. - while (index1 > 0) + // We slump together all the GapContentPositions to point to + // one mark. So this is implemented as follows: + // 1. Remove all the marks in the specified range. + // 2. Insert one new mark at the correct location. + // 3. Adjust all affected GapContentPosition instances to point to + // this new mark. + + synchronized (this) { - WeakReference r = (WeakReference) positions.get(index1 - 1); - GapContentPosition p = (GapContentPosition) r.get(); - if (p != null && p.mark == offset || p == null) - index1--; + int startIndex = binarySearch(positionMarks, start, numMarks); + if (startIndex < 0) // Translate to insertion index, if not found. + startIndex = - startIndex - 1; + int endIndex = binarySearch(positionMarks, end, numMarks); + if (endIndex < 0) // Translate to insertion index - 1, if not found. + endIndex = - endIndex - 2; + + // Update the marks. + // We have inclusive interval bounds, but let one element over for + // filling in the new value. + int removed = endIndex - startIndex; + if (removed <= 0) + return; + System.arraycopy(positionMarks, endIndex + 1, positionMarks, + startIndex + 1, positionMarks.length - endIndex - 1); + numMarks -= removed; + if (toStart) + { + positionMarks[startIndex] = start; + } else - break; - } - - for (ListIterator i = positions.listIterator(index1); i.hasNext();) - { - WeakReference r = (WeakReference) i.next(); - GapContentPosition p = (GapContentPosition) r.get(); - if (p == null) - continue; - - if (p.mark > endOffset) - break; - - if (p.mark >= offset && p.mark <= endOffset) - p.mark = value; - } + { + positionMarks[startIndex] = end; + } + + // Update all affected GapContentPositions to point to the new index + // and all GapContentPositions that come after the interval to + // have their index moved by -removed. + Set positionSet = positions.keySet(); + for (Iterator i = positionSet.iterator(); i.hasNext();) + { + GapContentPosition p = (GapContentPosition) i.next(); + if (p.index > start || p.index <= end) + p.index = start; + else if (p.index > end) + p.index -= removed; + } + } } /** @@ -780,39 +749,44 @@ public class GapContent */ private void adjustPositionsInRange(int offset, int length, int incr) { - int endOffset = offset + length; + int endMark = offset + length; - int index1 = Collections.binarySearch(positions, - new GapContentPosition(offset), - new WeakPositionComparator()); - if (index1 < 0) - index1 = -(index1 + 1); - - // Search the first index with the specified offset. The binarySearch does - // not necessarily find the first one. - while (index1 > 0) + synchronized (this) { - WeakReference r = (WeakReference) positions.get(index1 - 1); - GapContentPosition p = (GapContentPosition) r.get(); - if (p != null && p.mark == offset || p == null) - index1--; - else - break; + // Find the start and end indices in the positionMarks array. + int startIndex = binarySearch(positionMarks, offset, numMarks); + if (startIndex < 0) // Translate to insertion index, if not found. + startIndex = - startIndex - 1; + int endIndex = binarySearch(positionMarks, endMark, numMarks); + if (endIndex < 0) // Translate to insertion index - 1, if not found. + endIndex = - endIndex - 2; + + // We must not change the order of the marks, this would have + // unpredictable results while binary-searching the marks. + assert (startIndex <= 0 + || positionMarks[startIndex - 1] + <= positionMarks [startIndex] + incr) + && (endIndex >= numMarks - 1 + || positionMarks[endIndex + 1] + >= positionMarks[endIndex] + incr) + : "Adjusting the marks must not change their order"; + + // Some debug helper output to determine if the start or end of the + // should ever be coalesced together with adjecent marks. + if (startIndex > 0 && positionMarks[startIndex - 1] + == positionMarks[startIndex] + incr) + System.err.println("DEBUG: We could coalesce the start of the region" + + " in GapContent.adjustPositionsInRange()"); + if (endIndex < numMarks - 1 && positionMarks[endIndex + 1] + == positionMarks[endIndex] + incr) + System.err.println("DEBUG: We could coalesce the end of the region" + + " in GapContent.adjustPositionsInRange()"); + + // Actually adjust the marks. + for (int i = startIndex; i <= endIndex; i++) + positionMarks[i] += incr; } - for (ListIterator i = positions.listIterator(index1); i.hasNext();) - { - WeakReference r = (WeakReference) i.next(); - GapContentPosition p = (GapContentPosition) r.get(); - if (p == null) - continue; - - if (p.mark > endOffset) - break; - - if (p.mark >= offset && p.mark <= endOffset) - p.mark += incr; - } } /** @@ -826,7 +800,7 @@ public class GapContent if (gapStart != 0) return; - setPositionsInRange(gapEnd, 0, 0); + positionMarks[0] = 0; } /** @@ -866,27 +840,94 @@ public class GapContent System.err.println(); } - private void dumpPositions() + /** + * Prints out the position marks. + */ + private void dumpMarks() + { + System.err.print("positionMarks: "); + for (int i = 0; i < positionMarks.length; i++) + System.err.print(positionMarks[i] + ", "); + System.err.println(); + } + + /** + * Inserts a mark into the positionMarks array. This must update all the + * GapContentPosition instances in positions that come after insertionPoint. + * + * This is package private to avoid synthetic accessor methods. + * + * @param insertionPoint the index at which to insert the mark + * @param mark the mark to insert + */ + void insertMark(int insertionPoint, int mark) { - for (Iterator i = positions.iterator(); i.hasNext();) + synchronized (this) { - WeakReference r = (WeakReference) i.next(); - GapContentPosition pos = (GapContentPosition) r.get(); - System.err.println("position at: " + pos.mark); + // Update the positions. + Set positionSet = positions.keySet(); + for (Iterator i = positionSet.iterator(); i.hasNext();) + { + GapContentPosition p = (GapContentPosition) i.next(); + if (p.index >= insertionPoint) + p.index++; + } + + // Update the position marks. + if (positionMarks.length <= numMarks) + { + int[] newMarks = new int[positionMarks.length + 10]; + System.arraycopy(positionMarks, 0, newMarks, 0, insertionPoint); + newMarks[insertionPoint] = mark; + System.arraycopy(positionMarks, insertionPoint, newMarks, + insertionPoint + 1, + numMarks - insertionPoint); + positionMarks = newMarks; + } + else + { + System.arraycopy(positionMarks, insertionPoint, positionMarks, + insertionPoint + 1, + numMarks - insertionPoint); + positionMarks[insertionPoint] = mark; + } + numMarks++; } } /** - * Clears all GC'ed references in the positions array. + * An adaption of {@link java.util.Arrays#binarySearch(int[], int)} to + * specify a maximum index up to which the array is searched. This allows + * us to have some trailing entries that we ignore. + * + * This is package private to avoid synthetic accessor methods. + * + * @param a the array + * @param key the key to search for + * @param maxIndex the maximum index up to which the search is performed + * + * @return the index of the found entry, or (-(index)-1) for the + * insertion point when not found + * + * @see java.util.Arrays#binarySearch(int[], int) */ - private void clearPositionReferences() + int binarySearch(int[] a, int key, int maxIndex) { - Iterator i = positions.iterator(); - while (i.hasNext()) + int low = 0; + int hi = maxIndex - 1; + int mid = 0; + while (low <= hi) { - WeakReference r = (WeakReference) i.next(); - if (r.get() == null) - i.remove(); + mid = (low + hi) >> 1; + final int d = a[mid]; + if (d == key) + return mid; + else if (d > key) + hi = mid - 1; + else + // This gets the insertion point right on the last loop. + low = ++mid; } + return -mid - 1; } } diff --git a/javax/swing/text/JTextComponent.java b/javax/swing/text/JTextComponent.java index 1103de9b4..9de151dfb 100644 --- a/javax/swing/text/JTextComponent.java +++ b/javax/swing/text/JTextComponent.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.text; +import gnu.classpath.NotImplementedException; + import java.awt.AWTEvent; import java.awt.Color; import java.awt.Dimension; @@ -176,6 +178,7 @@ public abstract class JTextComponent extends JComponent * @param e - caret event */ public void caretUpdate(CaretEvent e) + throws NotImplementedException { // TODO: fire appropriate event. dot = e.getDot(); @@ -187,6 +190,7 @@ public abstract class JTextComponent extends JComponent * @return the accessible state set of this component */ public AccessibleStateSet getAccessibleStateSet() + throws NotImplementedException { AccessibleStateSet state = super.getAccessibleStateSet(); // TODO: Figure out what state must be added here to the super's state. @@ -237,6 +241,7 @@ public abstract class JTextComponent extends JComponent * @param e - document event */ public void insertUpdate(DocumentEvent e) + throws NotImplementedException { // TODO } @@ -248,6 +253,7 @@ public abstract class JTextComponent extends JComponent * @param e - document event */ public void removeUpdate(DocumentEvent e) + throws NotImplementedException { // TODO } @@ -259,6 +265,7 @@ public abstract class JTextComponent extends JComponent * @param e - document event */ public void changedUpdate(DocumentEvent e) + throws NotImplementedException { // TODO } @@ -271,6 +278,7 @@ public abstract class JTextComponent extends JComponent * @return the character index, or -1 */ public int getIndexAtPoint(Point p) + throws NotImplementedException { return 0; // TODO } @@ -289,6 +297,7 @@ public abstract class JTextComponent extends JComponent * @return the bounding box, may be empty or null. */ public Rectangle getCharacterBounds(int index) + throws NotImplementedException { return null; // TODO } @@ -311,6 +320,7 @@ public abstract class JTextComponent extends JComponent * @return the character's attributes */ public AttributeSet getCharacterAttribute(int index) + throws NotImplementedException { return null; // TODO } @@ -324,6 +334,7 @@ public abstract class JTextComponent extends JComponent * @return the selection of text at that index, or null */ public String getAtIndex(int part, int index) + throws NotImplementedException { return null; // TODO } @@ -337,6 +348,7 @@ public abstract class JTextComponent extends JComponent * @return the selection of text after that index, or null */ public String getAfterIndex(int part, int index) + throws NotImplementedException { return null; // TODO } @@ -350,6 +362,7 @@ public abstract class JTextComponent extends JComponent * @return the selection of text before that index, or null */ public String getBeforeIndex(int part, int index) + throws NotImplementedException { return null; // TODO } @@ -361,6 +374,7 @@ public abstract class JTextComponent extends JComponent * @return the 0-based number of actions */ public int getAccessibleActionCount() + throws NotImplementedException { return 0; // TODO } @@ -369,11 +383,11 @@ public abstract class JTextComponent extends JComponent * Get a description for the specified action. Returns null if out of * bounds. * - * @param i - * the action to describe, 0-based + * @param i the action to describe, 0-based * @return description of the action */ public String getAccessibleActionDescription(int i) + throws NotImplementedException { // TODO: Not implemented fully return super.getAccessibleDescription(); @@ -386,6 +400,7 @@ public abstract class JTextComponent extends JComponent * @return true if the action was performed */ public boolean doAccessibleAction(int i) + throws NotImplementedException { return false; // TODO } @@ -396,6 +411,7 @@ public abstract class JTextComponent extends JComponent * @param s the new text */ public void setTextContents(String s) + throws NotImplementedException { // TODO } @@ -407,6 +423,7 @@ public abstract class JTextComponent extends JComponent * @param s the new text */ public void insertTextAtIndex(int index, String s) + throws NotImplementedException { replaceText(index, index, s); } @@ -495,6 +512,7 @@ public abstract class JTextComponent extends JComponent * @param s the new attribute set for the range */ public void setAttributes(int start, int end, AttributeSet s) + throws NotImplementedException { // TODO } @@ -1365,7 +1383,7 @@ public abstract class JTextComponent extends JComponent { if (editable == newValue) return; - + boolean oldValue = editable; editable = newValue; firePropertyChange("editable", oldValue, newValue); @@ -1725,17 +1743,20 @@ public abstract class JTextComponent extends JComponent public void copy() { + if (isEnabled()) doTransferAction("copy", TransferHandler.getCopyAction()); } public void cut() { - doTransferAction("cut", TransferHandler.getCutAction()); + if (editable && isEnabled()) + doTransferAction("cut", TransferHandler.getCutAction()); } public void paste() { - doTransferAction("paste", TransferHandler.getPasteAction()); + if (editable && isEnabled()) + doTransferAction("paste", TransferHandler.getPasteAction()); } private void doTransferAction(String name, Action action) diff --git a/javax/swing/text/StyleContext.java b/javax/swing/text/StyleContext.java index 1c772e4cf..5150351dd 100644 --- a/javax/swing/text/StyleContext.java +++ b/javax/swing/text/StyleContext.java @@ -413,7 +413,7 @@ public class StyleContext /** * These attribute keys are handled specially in serialization. */ - private static HashSet staticAttributeKeys = new HashSet(); + private static Hashtable staticAttributeKeys = new Hashtable(); EventListenerList listenerList; Hashtable styleTable; @@ -708,44 +708,107 @@ public class StyleContext } } - - // FIXME: there's some sort of quasi-serialization stuff in here which I - // have left incomplete; I'm not sure I understand the intent properly. - + /** + * Gets the object previously registered with registerStaticAttributeKey. + * + * @param key - the key that was registered. + * @return the object previously registered with registerStaticAttributeKey. + */ public static Object getStaticAttribute(Object key) - throws NotImplementedException { - throw new InternalError("not implemented"); + if (key == null) + return null; + return staticAttributeKeys.get(key); } + /** + * Returns the String that key will be registered with + * registerStaticAttributeKey. + * + * @param key - the key that will be registered. + * @return the string the key will be registered with. + */ public static Object getStaticAttributeKey(Object key) - throws NotImplementedException { - throw new InternalError("not implemented"); + return key.getClass().getName() + "." + key.toString(); } + /** + * Reads a set of attributes from the given object input stream. This will + * attempt to restore keys that were static objects by considering only the + * keys that have were registered with registerStaticAttributeKey. The + * attributes retrieved will be placed into the given set. + * + * @param in - the stream to read from + * @param a - the set of attributes + * @throws ClassNotFoundException - may be encountered when reading from + * stream + * @throws IOException - any I/O error + */ public static void readAttributeSet(ObjectInputStream in, MutableAttributeSet a) - throws ClassNotFoundException, IOException, NotImplementedException + throws ClassNotFoundException, IOException { - throw new InternalError("not implemented"); + if (in == null || a == null) + return; + + Object key = in.readObject(); + Object val = in.readObject(); + while (key != null && val != null) + { + Object staticKey = staticAttributeKeys.get(key); + Object staticVal = staticAttributeKeys.get(val); + + if (staticKey != null) + key = staticKey; + if (staticVal != null) + val = staticVal; + + a.addAttribute(key, val); + key = in.readObject(); + val = in.readObject(); + } } + /** + * TODO: DOCUMENT ME! + * + * @param out - stream to write to + * @param a - the attribute set + * @throws IOException - any I/O error + */ public static void writeAttributeSet(ObjectOutputStream out, AttributeSet a) throws IOException, NotImplementedException { - throw new InternalError("not implemented"); + // FIXME: Not implemented } + /** + * Handles reading in the attributes. + * @see #readAttributeSet(ObjectInputStream, MutableAttributeSet) + * + * @param in - the stream to read from + * @param a - the set of attributes + * @throws ClassNotFoundException - may be encountered when reading from stream + * @throws IOException - any I/O error + */ public void readAttributes(ObjectInputStream in, MutableAttributeSet a) - throws ClassNotFoundException, IOException, NotImplementedException + throws ClassNotFoundException, IOException { - throw new InternalError("not implemented"); + readAttributeSet(in, a); } + /** + * Handles writing of the given attributes. + * @see #writeAttributeSet(ObjectOutputStream, AttributeSet) + * + * @param out - stream to write to + * @param a - the attribute set + * @throws IOException - any I/O error + */ public void writeAttributes(ObjectOutputStream out, AttributeSet a) - throws IOException, NotImplementedException + throws IOException { - throw new InternalError("not implemented"); + writeAttributeSet(out, a); } /** @@ -760,6 +823,8 @@ public class StyleContext */ public static void registerStaticAttributeKey(Object key) { - staticAttributeKeys.add(key); + if (key != null) + staticAttributeKeys.put(key.getClass().getName() + "." + key.toString(), + key); } } diff --git a/javax/swing/text/TextAction.java b/javax/swing/text/TextAction.java index 3ba5100c5..28dbff00a 100644 --- a/javax/swing/text/TextAction.java +++ b/javax/swing/text/TextAction.java @@ -38,12 +38,14 @@ exception statement from your version. */ package javax.swing.text; +import java.awt.Point; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.HashSet; import javax.swing.AbstractAction; import javax.swing.Action; +import javax.swing.SwingConstants; /** * TextAction @@ -108,4 +110,106 @@ public abstract class TextAction extends AbstractAction { return null; // TODO } + + /** Abstract helper class which implements everything needed for an + * Action implementation in <code>DefaultEditorKit</code> which + * does horizontal movement (and selection). + */ + abstract static class HorizontalMovementAction extends TextAction + { + int dir; + + HorizontalMovementAction(String name, int direction) + { + super(name); + dir = direction; + } + + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + try + { + if (t != null) + { + int offs + = Utilities.getNextVisualPositionFrom(t, + t.getCaretPosition(), + dir); + + Caret c = t.getCaret(); + + actionPerformedImpl(c, offs); + + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + } + catch(BadLocationException ble) + { + throw + (InternalError) new InternalError("Illegal offset").initCause(ble); + } + + } + + protected abstract void actionPerformedImpl(Caret c, int offs) + throws BadLocationException; + } + + /** Abstract helper class which implements everything needed for an + * Action implementation in <code>DefaultEditorKit</code> which + * does vertical movement (and selection). + */ + abstract static class VerticalMovementAction extends TextAction + { + int dir; + + VerticalMovementAction(String name, int direction) + { + super(name); + dir = direction; + } + + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + try + { + if (t != null) + { + Caret c = t.getCaret(); + // The magic caret position may be null when the caret + // has not moved yet. + Point mcp = c.getMagicCaretPosition(); + + int pos; + if (mcp != null) + { + mcp.y = t.modelToView(c.getDot()).y; + pos = t.viewToModel(mcp); + } + else + pos = c.getDot(); + + pos = Utilities.getNextVisualPositionFrom(t, + t.getCaretPosition(), + dir); + + if (pos > -1) + actionPerformedImpl(c, pos); + } + } + catch(BadLocationException ble) + { + throw + (InternalError) new InternalError("Illegal offset").initCause(ble); + } + } + + protected abstract void actionPerformedImpl(Caret c, int offs) + throws BadLocationException; + + } + + } diff --git a/javax/swing/text/Utilities.java b/javax/swing/text/Utilities.java index f154e55aa..36361f497 100644 --- a/javax/swing/text/Utilities.java +++ b/javax/swing/text/Utilities.java @@ -43,6 +43,9 @@ import java.awt.Graphics; import java.awt.Point; import java.text.BreakIterator; +import javax.swing.SwingConstants; +import javax.swing.text.Position.Bias; + /** * A set of utilities to deal with text. This is used by several other classes * inside this package. @@ -337,7 +340,7 @@ public class Utilities // location or is not whitespace (meaning it is a number or // punctuation). The first case means that 'last' denotes the // beginning of a word while the second case means it is the start - // of some else. + // of something else. if (Character.isLetter(cp) || !Character.isWhitespace(cp)) return last; @@ -346,7 +349,7 @@ public class Utilities current = wb.next(); } - throw new BadLocationException("no more word", offs); + throw new BadLocationException("no more words", offs); } /** @@ -363,24 +366,36 @@ public class Utilities public static final int getPreviousWord(JTextComponent c, int offs) throws BadLocationException { - if (offs < 0 || offs > (c.getText().length() - 1)) - throw new BadLocationException("invalid offset specified", offs); String text = c.getText(); + + if (offs <= 0 || offs > text.length()) + throw new BadLocationException("invalid offset specified", offs); + BreakIterator wb = BreakIterator.getWordInstance(); wb.setText(text); int last = wb.preceding(offs); int current = wb.previous(); + int cp; while (current != BreakIterator.DONE) { for (int i = last; i < offs; i++) { - if (Character.isLetter(text.codePointAt(i))) + cp = text.codePointAt(i); + + // Return the last found bound if there is a letter at the current + // location or is not whitespace (meaning it is a number or + // punctuation). The first case means that 'last' denotes the + // beginning of a word while the second case means it is the start + // of some else. + if (Character.isLetter(cp) + || !Character.isWhitespace(cp)) return last; } last = current; current = wb.previous(); } + return 0; } @@ -394,14 +409,17 @@ public class Utilities public static final int getWordStart(JTextComponent c, int offs) throws BadLocationException { - if (offs < 0 || offs >= c.getText().length()) + String text = c.getText(); + + if (offs < 0 || offs > text.length()) throw new BadLocationException("invalid offset specified", offs); - String text = c.getText(); BreakIterator wb = BreakIterator.getWordInstance(); wb.setText(text); + if (wb.isBoundary(offs)) return offs; + return wb.preceding(offs); } @@ -674,4 +692,38 @@ public class Utilities else return offs+1; } + + /** This is an internal helper method which is used by the + * <code>javax.swing.text</code> package. It simply delegates the + * call to a method with the same name on the <code>NavigationFilter</code> + * of the provided <code>JTextComponent</code> (if it has one) or its UI. + * + * If the underlying method throws a <code>BadLocationException</code> it + * will be swallowed and the initial offset is returned. + */ + static int getNextVisualPositionFrom(JTextComponent t, int offset, int direction) + { + NavigationFilter nf = t.getNavigationFilter(); + + try + { + return (nf != null) + ? nf.getNextVisualPositionFrom(t, + offset, + Bias.Forward, + direction, + null) + : t.getUI().getNextVisualPositionFrom(t, + offset, + Bias.Forward, + direction, + null); + } + catch (BadLocationException ble) + { + return offset; + } + + } + } diff --git a/javax/swing/text/html/HTMLDocument.java b/javax/swing/text/html/HTMLDocument.java index 24f743ed2..c3d276178 100644 --- a/javax/swing/text/html/HTMLDocument.java +++ b/javax/swing/text/html/HTMLDocument.java @@ -40,14 +40,12 @@ package javax.swing.text.html; import gnu.classpath.NotImplementedException; +import gnu.javax.swing.text.html.CharacterAttributeTranslator; import java.io.IOException; import java.net.URL; import java.util.HashMap; import java.util.Stack; import java.util.Vector; - -import javax.swing.event.DocumentEvent; -import javax.swing.event.UndoableEditEvent; import javax.swing.text.AbstractDocument; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; @@ -131,21 +129,6 @@ public class HTMLDocument extends DefaultStyledDocument } /** - * Replaces the contents of the document with the given element - * specifications. This is called before insert if the loading is done - * in bursts. This is the only method called if loading the document - * entirely in one burst. - * - * @param data - the date that replaces the content of the document - */ - protected void create(DefaultStyledDocument.ElementSpec[] data) - { - // Once the super behaviour is properly implemented it should be sufficient - // to simply call super.create(data). - super.create(data); - } - - /** * This method creates a root element for the new document. * * @return the new default root @@ -216,41 +199,6 @@ public class HTMLDocument extends DefaultStyledDocument } /** - * Inserts new elements in bulk. This is how elements get created in the - * document. The parsing determines what structure is needed and creates the - * specification as a set of tokens that describe the edit while leaving the - * document free of a write-lock. This method can then be called in bursts by - * the reader to acquire a write-lock for a shorter duration (i.e. while the - * document is actually being altered). - * - * @param offset - the starting offset - * @param data - the element data - * @throws BadLocationException - if the given position does not - * represent a valid location in the associated document. - */ - protected void insert(int offset, DefaultStyledDocument.ElementSpec[] data) - throws BadLocationException - { - super.insert(offset, data); - } - - /** - * Updates document structure as a result of text insertion. This will happen - * within a write lock. This implementation simply parses the inserted content - * for line breaks and builds up a set of instructions for the element buffer. - * - * @param chng - a description of the document change - * @param attr - the attributes - */ - protected void insertUpdate(AbstractDocument.DefaultDocumentEvent chng, - AttributeSet attr) - { - // FIXME: Not implemented - System.out.println("insertUpdate not implemented"); - super.insertUpdate(chng, attr); - } - - /** * Returns the parser used by this HTMLDocument to insert HTML. * * @return the parser used by this HTMLDocument to insert HTML. @@ -414,6 +362,7 @@ public class HTMLDocument extends DefaultStyledDocument } public void processHTMLFrameHyperlinkEvent(HTMLFrameHyperlinkEvent event) + throws NotImplementedException { // TODO: Implement this properly. } @@ -646,12 +595,16 @@ public class HTMLDocument extends DefaultStyledDocument { // Put the old attribute set on the stack. pushCharacterStyle(); - - // And create the new one by adding the attributes in <code>a</code>. - if (a != null) - charAttr.addAttribute(t, a.copyAttributes()); + + // Translate tag.. return if succesful. + if(CharacterAttributeTranslator.translateTag(charAttr, t, a)) + return; + + // Just add the attributes in <code>a</code>. + if (a != null) + charAttr.addAttribute(t, a.copyAttributes()); } - + /** * Called when an end tag is seen for one of the types of tags associated * with this Action. @@ -745,7 +698,6 @@ public class HTMLDocument extends DefaultStyledDocument */ public void start(HTML.Tag t, MutableAttributeSet a) { - // FIXME: What else must be done here? blockOpen(t, a); } @@ -755,7 +707,6 @@ public class HTMLDocument extends DefaultStyledDocument */ public void end(HTML.Tag t) { - // FIXME: What else must be done here? blockClose(t); } } @@ -771,6 +722,7 @@ public class HTMLDocument extends DefaultStyledDocument { // FIXME: Implement. print ("PreAction.start not implemented"); + super.start(t, a); } /** @@ -782,6 +734,7 @@ public class HTMLDocument extends DefaultStyledDocument { // FIXME: Implement. print ("PreAction.end not implemented"); + super.end(t); } } @@ -1131,7 +1084,7 @@ public class HTMLDocument extends DefaultStyledDocument */ protected void pushCharacterStyle() { - charAttrStack.push(charAttr); + charAttrStack.push(charAttr.copyAttributes()); } /** @@ -1565,8 +1518,8 @@ public class HTMLDocument extends DefaultStyledDocument */ public Element getElement(String attrId) { - Element root = getDefaultRootElement(); - return getElement(root, HTML.getAttributeKey(attrId) , attrId); + return getElement(getDefaultRootElement(), HTML.getAttributeKey(attrId), + attrId); } /** @@ -1690,53 +1643,4 @@ public class HTMLDocument extends DefaultStyledDocument // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit? System.out.println("insertAfterStart not implemented"); } - - /** - * This method sets the attributes associated with the paragraph containing - * offset. If replace is false, s is merged with existing attributes. The - * length argument determines how many characters are affected by the new - * attributes. This is often the entire paragraph. - * - * @param offset - - * the offset into the paragraph (must be at least 0) - * @param length - - * the number of characters affected (must be at least 0) - * @param s - - * the attributes - * @param replace - - * whether to replace existing attributes, or merge them - */ - public void setParagraphAttributes(int offset, int length, AttributeSet s, - boolean replace) - throws NotImplementedException - { - // FIXME: Not implemented. - System.out.println("setParagraphAttributes not implemented"); - super.setParagraphAttributes(offset, length, s, replace); - } - - /** - * This method flags a change in the document. - * - * @param e - the Document event - */ - protected void fireChangedUpdate(DocumentEvent e) - throws NotImplementedException - { - // FIXME: Not implemented. - System.out.println("fireChangedUpdate not implemented"); - super.fireChangedUpdate(e); - } - - /** - * This method fires an event intended to be caught by Undo listeners. It - * simply calls the super version inherited from DefaultStyledDocument. With - * this method, an HTML editor could easily provide undo support. - * - * @param e - the UndoableEditEvent - */ - protected void fireUndoableEditUpdate(UndoableEditEvent e) - { - super.fireUndoableEditUpdate(e); - } } diff --git a/javax/swing/text/html/MinimalHTMLWriter.java b/javax/swing/text/html/MinimalHTMLWriter.java new file mode 100644 index 000000000..4dc67298a --- /dev/null +++ b/javax/swing/text/html/MinimalHTMLWriter.java @@ -0,0 +1,452 @@ +/* MinimalHTMLWriter.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text.html; + +import javax.swing.text.AttributeSet; +import javax.swing.text.AbstractWriter; +import javax.swing.text.BadLocationException; +import javax.swing.text.DefaultStyledDocument; +import javax.swing.text.Element; +import javax.swing.text.ElementIterator; +import javax.swing.text.StyleConstants; +import javax.swing.text.Style; +import javax.swing.text.StyledDocument; +import java.io.Writer; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Stack; +import java.awt.Color; + +/** + * MinimalHTMLWriter, + * A minimal AbstractWriter implementation for HTML. + * + * @author Sven de Marothy + */ +public class MinimalHTMLWriter extends AbstractWriter +{ + private StyledDocument doc; + private Stack tagStack; + private boolean inFontTag = false; + + /** + * Constructs a MinimalHTMLWriter. + * @param w - a Writer, for output. + * @param doc - the document + */ + public MinimalHTMLWriter(Writer w, StyledDocument doc) + { + super(w, doc); + this.doc = doc; + tagStack = new Stack(); + } + + /** + * Constructs a MinimalHTMLWriter. + * @param w - a Writer, for output. + * @param doc - the document + * @param pos - start position + * @param len - length + */ + public MinimalHTMLWriter(Writer w, StyledDocument doc, int pos, int len) + { + super(w, doc, pos, len); + this.doc = doc; + tagStack = new Stack(); + } + + /** + * Starts a span tag. + */ + protected void startFontTag(String style) throws IOException + { + if( inFontTag() ) + endOpenTags(); + writeStartTag("<span style=\""+style+"\">"); + inFontTag = true; + } + + /** + * Returns whether the writer is within two span tags. + */ + protected boolean inFontTag() + { + return inFontTag; + } + + /** + * Ends a span tag. + */ + protected void endFontTag() throws IOException + { + writeEndTag("</span>"); + inFontTag = false; + } + + /** + * Write the entire HTML document. + */ + public synchronized void write() throws IOException, BadLocationException + { + writeStartTag("<html>"); + writeHeader(); + writeBody(); + writeEndTag("</html>"); + } + + /** + * Write a start tag and increment the indent. + */ + protected void writeStartTag(String tag) throws IOException + { + indent(); + write(tag+NEWLINE); + incrIndent(); + } + + /** + * Write an ending tag and decrement the indent. + */ + protected void writeEndTag(String endTag) throws IOException + { + decrIndent(); + indent(); + write(endTag+NEWLINE); + } + + /** + * Write the HTML header. + */ + protected void writeHeader() throws IOException + { + writeStartTag("<head>"); + writeStartTag("<style>"); + writeStartTag("<!--"); + writeStyles(); + writeEndTag("-->"); + writeEndTag("</style>"); + writeEndTag("</head>"); + } + + /** + * Write a paragraph start tag. + */ + protected void writeStartParagraph(Element elem) throws IOException + { + indent(); + write("<p class=default>"+NEWLINE); // FIXME: Class value = ? + incrIndent(); + } + + /** + * Write a paragraph end tag, closes any other open tags. + */ + protected void writeEndParagraph() throws IOException + { + endOpenTags(); + writeEndTag("</p>"); + } + + /** + * Writes the body of the HTML document. + */ + protected void writeBody() throws IOException, BadLocationException + { + writeStartTag("<body>"); + + ElementIterator ei = getElementIterator(); + Element e = ei.first(); + boolean inParagraph = false; + do + { + if( e.isLeaf() ) + { + boolean hasNL = (getText(e).indexOf(NEWLINE) != -1); + if( !inParagraph && hasText( e ) ) + { + writeStartParagraph(e); + inParagraph = true; + } + + if( hasText( e ) ) + writeContent(e, true); + + if( hasNL && inParagraph ) + { + writeEndParagraph(); + inParagraph = false; + } + else + endOpenTags(); + } + } + while((e = ei.next()) != null); + + writeEndTag("</body>"); + } + + protected void text(Element elem) throws IOException, BadLocationException + { + write( getText(elem).trim() ); + } + + /** + * Write bold, indent and underline tags. + */ + protected void writeHTMLTags(AttributeSet attr) throws IOException + { + if(attr.getAttribute(StyleConstants.Bold) != null) + if(((Boolean)attr.getAttribute(StyleConstants.Bold)).booleanValue()) + { + write("<b>"); + tagStack.push("</b>"); + } + if(attr.getAttribute(StyleConstants.Italic) != null) + if(((Boolean)attr.getAttribute(StyleConstants.Italic)).booleanValue()) + { + write("<i>"); + tagStack.push("</i>"); + } + if(attr.getAttribute(StyleConstants.Underline) != null) + if(((Boolean)attr.getAttribute(StyleConstants.Underline)).booleanValue()) + { + write("<u>"); + tagStack.push("</u>"); + } + } + + /** + * Returns whether the element contains text or not. + */ + protected boolean isText(Element elem) + { + return (elem.getEndOffset() != elem.getStartOffset()); + } + + /** + * Writes the content of an element. + */ + protected void writeContent(Element elem, boolean needsIndenting) + throws IOException, BadLocationException + { + writeNonHTMLAttributes(elem.getAttributes()); + if(needsIndenting) + indent(); + writeHTMLTags(elem.getAttributes()); + if( isText(elem) ) + text(elem); + else + writeLeaf(elem); + + endOpenTags(); + } + + /** + * Writes a non-text leaf element. + */ + protected void writeLeaf(Element e) throws IOException + { + // NOTE: Haven't tested if this is correct. + if(e.getName().equals(StyleConstants.IconElementName)) + writeImage(e); + else + writeComponent(e); + } + + /** + * Write the HTML attributes which do not have tag equivalents, + * e.g. attributes other than bold/italic/underlined. + */ + protected void writeNonHTMLAttributes(AttributeSet attr) throws IOException + { + String style = ""; + + // Alignment? Background? + + if( StyleConstants.getForeground(attr) != null ) + style = style + "color: " + + getColor(StyleConstants.getForeground(attr)) + "; "; + + style = style + "font-size: "+StyleConstants.getFontSize(attr)+"pt; "; + style = style + "font-family: "+StyleConstants.getFontFamily(attr); + + startFontTag(style); + } + + /** + * Write the styles used. + */ + protected void writeStyles() throws IOException + { + if(doc instanceof DefaultStyledDocument) + { + Enumeration styles = ((DefaultStyledDocument)doc).getStyleNames(); + while(styles.hasMoreElements()) + writeStyle(doc.getStyle((String)styles.nextElement())); + } + else + { // What else to do here? + Style s = (Style)doc.getStyle("default"); + if(s != null) + writeStyle( s ); + } + } + + /** + * Write a set of attributes. + */ + protected void writeAttributes(AttributeSet attr) throws IOException + { + Enumeration attribs = attr.getAttributeNames(); + while(attribs.hasMoreElements()) + { + Object attribName = attribs.nextElement(); + String name = attribName.toString(); + String output = getAttribute(name, attr.getAttribute(attribName)); + if( output != null ) + { + indent(); + write( output + NEWLINE ); + } + } + } + + /** + * Deliberately unimplemented, handles component elements. + */ + protected void writeComponent(Element elem) + { + } + + /** + * Deliberately unimplemented. + * Writes StyleConstants.IconElementName elements. + */ + protected void writeImage(Element elem) + { + } + + // -------------------- Private methods. -------------------------------- + + /** + * Write a single style attribute + */ + private String getAttribute(String name, Object a) throws IOException + { + if(name.equals("foreground")) + return "foreground:"+getColor((Color)a)+";"; + if(name.equals("background")) + return "background:"+getColor((Color)a)+";"; + if(name.equals("italic")) + return "italic:"+(((Boolean)a).booleanValue() ? "italic;" : ";"); + if(name.equals("bold")) + return "bold:"+(((Boolean)a).booleanValue() ? "bold;" : "normal;"); + if(name.equals("family")) + return "family:" + a + ";"; + if(name.equals("size")) + { + int size = ((Integer)a).intValue(); + int htmlSize; + if( size > 24 ) + htmlSize = 7; + else if( size > 18 ) + htmlSize = 6; + else if( size > 14 ) + htmlSize = 5; + else if( size > 12 ) + htmlSize = 4; + else if( size > 10 ) + htmlSize = 3; + else if( size > 8 ) + htmlSize = 2; + else + htmlSize = 1; + + return "size:" + htmlSize + ";"; + } + + return null; + } + + /** + * Stupid that Color doesn't have a method for this. + */ + private String getColor(Color c) + { + String r = "00" + Integer.toHexString(c.getRed()); + r = r.substring(r.length() - 2); + String g = "00" + Integer.toHexString(c.getGreen()); + g = g.substring(g.length() - 2); + String b = "00" + Integer.toHexString(c.getBlue()); + b = b.substring(b.length() - 2); + return "#" + r + g + b; + } + + /** + * Empty the stack of open tags + */ + private void endOpenTags() throws IOException + { + while(!tagStack.empty()) + write((String)tagStack.pop()); + + if( inFontTag() ) + { + write(""+NEWLINE); + endFontTag(); + } + } + + /** + * Output a single style + */ + private void writeStyle(Style s) throws IOException + { + if( s == null ) + return; + + writeStartTag("p."+s.getName()+" {"); + writeAttributes(s); + writeEndTag("}"); + } + + private boolean hasText(Element e) throws BadLocationException + { + return (getText(e).trim().length() > 0); + } +} diff --git a/native/Makefile.am b/native/Makefile.am index 4fa593e03..25aa364d1 100644 --- a/native/Makefile.am +++ b/native/Makefile.am @@ -8,6 +8,10 @@ if CREATE_GTK_PEER_LIBRARIES JAWTDIR = jawt endif -SUBDIRS = fdlibm $(JNIDIR) $(JAWTDIR) target -DIST_SUBDIRS = fdlibm jni jawt target +if CREATE_PLUGIN + PLUGINDIR = plugin +endif + +SUBDIRS = fdlibm $(JNIDIR) $(JAWTDIR) $(PLUGINDIR) target +DIST_SUBDIRS = fdlibm jni jawt plugin target diff --git a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkImage.c b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkImage.c index 92bc09edd..b40e86289 100644 --- a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkImage.c +++ b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkImage.c @@ -154,6 +154,8 @@ Java_gnu_java_awt_peer_gtk_GtkImage_getPixels(JNIEnv *env, jobject obj) jint *result_array_iter, *dst; int i,j; + gdk_threads_enter (); + pixbuf = cp_gtk_image_get_pixbuf (env, obj); width = gdk_pixbuf_get_width (pixbuf); height = gdk_pixbuf_get_height (pixbuf); @@ -195,6 +197,7 @@ Java_gnu_java_awt_peer_gtk_GtkImage_getPixels(JNIEnv *env, jobject obj) (*env)->ReleaseIntArrayElements (env, result_array, result_array_iter, 0); + gdk_threads_leave (); return result_array; } @@ -527,6 +530,7 @@ GdkPixbuf *cp_gtk_image_get_pixbuf (JNIEnv *env, jobject obj) /* Get a pixmap */ pixmap = (GdkPixmap *)getData (env, obj); + pixbuf = gdk_pixbuf_get_from_drawable (NULL, pixmap, gdk_drawable_get_colormap( pixmap ), diff --git a/native/jni/java-nio/Makefile.am b/native/jni/java-nio/Makefile.am index af564373b..c3f6caf62 100644 --- a/native/jni/java-nio/Makefile.am +++ b/native/jni/java-nio/Makefile.am @@ -1,6 +1,7 @@ nativeexeclib_LTLIBRARIES = libjavanio.la libjavanio_la_SOURCES = gnu_java_nio_VMPipe.c \ + gnu_java_nio_VMChannel.c \ gnu_java_nio_VMSelector.c \ gnu_java_nio_channels_FileChannelImpl.c \ gnu_java_nio_charset_iconv_IconvDecoder.c \ diff --git a/native/jni/java-nio/gnu_java_nio_VMChannel.c b/native/jni/java-nio/gnu_java_nio_VMChannel.c new file mode 100644 index 000000000..5571bed27 --- /dev/null +++ b/native/jni/java-nio/gnu_java_nio_VMChannel.c @@ -0,0 +1,525 @@ +/* gnu_java_nio_VMChannel.c - + Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +#include <config.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <sys/uio.h> +#include <string.h> + +#include <jni.h> +#include <jcl.h> + +#include "gnu_java_nio_VMChannel.h" + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif /* HAVE_FCNTL_H */ + +#define IO_EXCEPTION "java/io/IOException" +#define NON_READABLE_CHANNEL_EXCEPTION "java/nio/channels/NonReadableChannelException" +#define NON_WRITABLE_CHANNEL_EXCEPTION "java/nio/channels/NonWritableChannelException" + +/* + * Limit to maximum of 16 buffers + */ +#define JCL_IOV_MAX 16 + +#ifdef __cplusplus +extern "C" +{ +#endif + +enum JCL_buffer_type { DIRECT, ARRAY, UNKNOWN }; + +struct JCL_buffer +{ + enum JCL_buffer_type type; + jbyte *ptr; + jint offset; + jint position; + jint limit; + jint count; +}; + +jmethodID get_method_id(JNIEnv *, jclass, const char *, const char *); +void JCL_print_buffer(JNIEnv *, struct JCL_buffer *); +int JCL_init_buffer(JNIEnv *, struct JCL_buffer *, jobject); +void JCL_release_buffer(JNIEnv *, struct JCL_buffer *, jobject, jint); +void JCL_cleanup_buffers(JNIEnv *, struct JCL_buffer *, jint, jobjectArray, jint, jlong); + +static jfieldID address_fid; +static jmethodID get_position_mid; +static jmethodID set_position_mid; +static jmethodID get_limit_mid; +static jmethodID set_limit_mid; +static jmethodID has_array_mid; +static jmethodID array_mid; +static jmethodID array_offset_mid; + +jmethodID +get_method_id(JNIEnv *env, jclass clazz, const char *name, + const char *sig) +{ + jmethodID mid = (*env)->GetMethodID(env, clazz, name, sig); + if (mid == NULL) + { + JCL_ThrowException(env, "java/lang/InternalError", name); + return NULL; + } + + return mid; +} + +void +JCL_print_buffer(JNIEnv *env __attribute__((__unused__)), struct JCL_buffer *buf) +{ + fprintf(stdout, "Buffer - type: %d, ptr: %p\n", buf->type, buf->ptr); + fflush(stdout); +} + + +int +JCL_init_buffer(JNIEnv *env, struct JCL_buffer *buf, jobject bbuf) +{ + jobject address = (*env)->GetObjectField(env, bbuf, address_fid); + + buf->position = (*env)->CallIntMethod(env, bbuf, get_position_mid); + buf->limit = (*env)->CallIntMethod(env, bbuf, get_limit_mid); + buf->offset = 0; + buf->count = 0; + buf->type = UNKNOWN; + + if (address != NULL) + { + buf->ptr = (jbyte *) JCL_GetRawData(env, address); + buf->type = DIRECT; + (*env)->DeleteLocalRef(env, address); + } + else + { + jboolean has_array; + has_array = (*env)->CallBooleanMethod(env, bbuf, has_array_mid); + + if (has_array == JNI_TRUE) + { + jbyteArray arr; + buf->offset = (*env)->CallIntMethod(env, bbuf, array_offset_mid); + arr = (*env)->CallObjectMethod(env, bbuf, array_mid); + buf->ptr = (*env)->GetByteArrayElements(env, arr, 0); + buf->type = ARRAY; + (*env)->DeleteLocalRef(env, arr); + } + else + { + return -1; + } + } + + return 0; +} + +void +JCL_release_buffer(JNIEnv *env, struct JCL_buffer *buf, jobject bbuf, + jint action) +{ + jbyteArray arr; + + /* Set the position to the appropriate value */ + if (buf->count > 0) + { + jobject bbufTemp; + bbufTemp = (*env)->CallObjectMethod(env, bbuf, set_position_mid, + buf->position + buf->count); + (*env)->DeleteLocalRef(env, bbufTemp); + } + + switch (buf->type) + { + case DIRECT: + break; + case ARRAY: + arr = (*env)->CallObjectMethod(env, bbuf, array_mid); + (*env)->ReleaseByteArrayElements(env, arr, buf->ptr, action); + (*env)->DeleteLocalRef(env, arr); + break; + case UNKNOWN: + /* TODO: Handle buffers that are not direct or array backed */ + break; + } +} + +void +JCL_cleanup_buffers(JNIEnv *env, + struct JCL_buffer *bi_list, + jint vec_len, + jobjectArray bbufs, + jint offset, + jlong num_bytes) +{ + jint i; + + /* Update all of the bbufs with the approriate information */ + for (i = 0; i < vec_len; i++) + { + struct JCL_buffer* buf; + jobject bbuf; + + buf = &bi_list[i]; + bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i); + + if (num_bytes > (buf->limit - buf->position)) + buf->count = (buf->limit - buf->position); + else + buf->count = num_bytes; + + num_bytes -= buf->count; + + JCL_release_buffer(env, buf, bbuf, JNI_ABORT); + (*env)->DeleteLocalRef(env, bbuf); + } +} + + +JNIEXPORT void JNICALL +Java_gnu_java_nio_VMChannel_initIDs (JNIEnv *env, + jclass clazz __attribute__ ((__unused__))) +{ + jclass bufferClass = JCL_FindClass(env, "java/nio/Buffer"); + jclass byteBufferClass = JCL_FindClass(env, "java/nio/ByteBuffer"); + + address_fid = (*env)->GetFieldID(env, bufferClass, "address", + "Lgnu/classpath/Pointer;"); + if (address_fid == NULL) + { + JCL_ThrowException(env, "java/lang/InternalError", + "Unable to find internal field"); + return; + } + + get_position_mid = get_method_id(env, bufferClass, "position", "()I"); + set_position_mid = get_method_id(env, bufferClass, "position", + "(I)Ljava/nio/Buffer;"); + get_limit_mid = get_method_id(env, bufferClass, "limit", "()I"); + set_limit_mid = get_method_id(env, bufferClass, "limit", + "(I)Ljava/nio/Buffer;"); + has_array_mid = get_method_id(env, byteBufferClass, "hasArray", "()Z"); + array_mid = get_method_id(env, byteBufferClass, "array", "()[B"); + array_offset_mid = get_method_id(env, byteBufferClass, "arrayOffset", "()I"); +} + +JNIEXPORT void JNICALL +Java_gnu_java_nio_VMChannel_setBlocking (JNIEnv *env, + jobject o __attribute__ ((__unused__)), + jint fd, + jboolean blocking) +{ + int opts; + + opts = fcntl(fd, F_GETFL); + if (opts < 0) + { + JCL_ThrowException(env, IO_EXCEPTION, + "Failed to get flags for file desriptor"); + return; + } + + if (blocking) + opts |= O_NONBLOCK; + else + opts &= ~(O_NONBLOCK); + + opts = fcntl(fd, F_SETFL, opts); + + if (opts < 0) + { + JCL_ThrowException(env, IO_EXCEPTION, + "Failed to set flags for file desriptor"); + return; + } +} + + +JNIEXPORT jint JNICALL +Java_gnu_java_nio_VMChannel_read (JNIEnv *env, + jobject o __attribute__ ((__unused__)), + jint fd, + jobject bbuf) +{ + jint len; + ssize_t result; + struct JCL_buffer buf; + + if (JCL_init_buffer(env, &buf, bbuf) < 0) + { + /* TODO: Rethrown exception */ + JCL_ThrowException (env, IO_EXCEPTION, "Buffer initialisation failed"); + return -1; + } + + len = buf.limit - buf.position; + + result = read(fd, &(buf.ptr[buf.position + buf.offset]), len); + buf.count = result; + + if (result == 0) + result = -1; /* End Of File */ + else if (result == -1) + { + buf.count = 0; + if (errno == EAGAIN) /* Non-blocking */ + result = 0; + else if (errno == EBADF) /* Bad fd */ + { + JCL_release_buffer(env, &buf, bbuf, JNI_ABORT); + JCL_ThrowException (env, NON_READABLE_CHANNEL_EXCEPTION, + strerror(errno)); + return -1; + } + else + { + JCL_release_buffer(env, &buf, bbuf, JNI_ABORT); + JCL_ThrowException (env, IO_EXCEPTION, strerror(errno)); + return -1; + } + } + else + + JCL_release_buffer(env, &buf, bbuf, JNI_COMMIT); + + return result; +} + +JNIEXPORT jint JNICALL +Java_gnu_java_nio_VMChannel_write (JNIEnv *env, + jobject o __attribute__ ((__unused__)), + jint fd, + jobject bbuf) +{ + jint len; + ssize_t result; + struct JCL_buffer buf; + + if (JCL_init_buffer(env, &buf, bbuf) < 0) + { + /* TODO: Rethrown exception */ + JCL_ThrowException (env, IO_EXCEPTION, "Buffer initialisation failed"); + return -1; + } + + len = buf.limit - buf.position; + + result = write(fd, &(buf.ptr[buf.position + buf.offset]), len); + buf.count = result; + + if (result == -1) + { + if (errno == EAGAIN) /* Non-blocking */ + result = 0; + else + { + JCL_release_buffer(env, &buf, bbuf, JNI_ABORT); + JCL_ThrowException(env, IO_EXCEPTION, strerror(errno)); + return -1; + } + } + + JCL_release_buffer(env, &buf, bbuf, JNI_ABORT); + + return result; +} + + +/* + * Implementation of a scattering read. Will use the appropriate + * vector based read call (currently readv on Linux). + * + * This has a limit to the number of buffers that will be read. It + * will not make muliple readv calls. This is to ensure that operations + * are atomic. Currently it is limited to 16 buffers. This is for + * compatibiliy with Sun. + */ +JNIEXPORT jlong JNICALL +Java_gnu_java_nio_VMChannel_readScattering (JNIEnv *env, + jobject o __attribute__ ((__unused__)), + jint fd, + jobjectArray bbufs, + jint offset, + jint length) +{ + jint i; +/* jboolean is_error = JNI_FALSE; */ +/* char *error_msg; */ + struct iovec buffers[JCL_IOV_MAX]; + struct JCL_buffer bi_list[JCL_IOV_MAX]; + ssize_t result; + jint vec_len = length < JCL_IOV_MAX ? length : JCL_IOV_MAX; + jlong bytes_read = 0; + + /* Build the vector of buffers to read into */ + for (i = 0; i < vec_len; i++) + { + struct JCL_buffer* buf; + jobject bbuf; + + buf = &bi_list[i]; + bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i); + + JCL_init_buffer(env, buf, bbuf); + + buffers[i].iov_base = &(buf->ptr[buf->position + buf->offset]); + buffers[i].iov_len = buf->limit - buf->position; + (*env)->DeleteLocalRef(env, bbuf); + } + + /* Work the scattering magic */ + result = readv(fd, buffers, vec_len); + bytes_read = (jlong) result; + + /* Handle the response */ + if (result < 0) + { + if (errno == EAGAIN) /* Non blocking */ + result = 0; + else if (errno == EBADF) /* Bad fd */ + { + JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read); + JCL_ThrowException (env, NON_READABLE_CHANNEL_EXCEPTION, + strerror(errno)); + return -1; + } + else + { + JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read); + JCL_ThrowException (env, IO_EXCEPTION, strerror(errno)); + return -1; + } + bytes_read = 0; + } + else if (result == 0) /* EOF */ + { + result = -1; + } + + JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read); + + return (jlong) result; +} + +/* + * Implementation of a gathering write. Will use the appropriate + * vector based read call (currently readv on Linux). + * + * This has a limit to the number of buffers that will be read. It + * will not make muliple readv calls. This is to ensure that operations + * are atomic. Currently it is limited to 16 buffers. This is for + * compatibiliy with Sun. + */ +JNIEXPORT jlong JNICALL +Java_gnu_java_nio_VMChannel_writeGathering (JNIEnv *env, + jobject o __attribute__ ((__unused__)), + jint fd, + jobjectArray bbufs, + jint offset, + jint length) +{ + int i; +/* jboolean is_error = JNI_FALSE; */ +/* char *error_msg; */ + struct iovec buffers[JCL_IOV_MAX]; + struct JCL_buffer bi_list[JCL_IOV_MAX]; + ssize_t result; + jint vec_len = length < JCL_IOV_MAX ? length : JCL_IOV_MAX; + jlong bytes_written; + + + /* Build the vector of buffers to read into */ + for (i = 0; i < vec_len; i++) + { + struct JCL_buffer* buf; + jobject bbuf; + + buf = &bi_list[i]; + bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i); + + JCL_init_buffer(env, buf, bbuf); + + buffers[i].iov_base = &(buf->ptr[buf->position + buf->offset]); + buffers[i].iov_len = buf->limit - buf->position; + (*env)->DeleteLocalRef(env, bbuf); + } + + /* Work the gathering magic */ + result = writev(fd, buffers, vec_len); + bytes_written = (jlong) result; + + if (result < 0) + { + bytes_written = 0; + if (errno == EAGAIN) /* Non blocking */ + result = 0; + else if (errno == EBADF) /* Bad fd */ + { + JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, + bytes_written); + JCL_ThrowException (env, NON_WRITABLE_CHANNEL_EXCEPTION, + strerror(errno)); + return -1; + } + else + { + JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, + bytes_written); + JCL_ThrowException (env, IO_EXCEPTION, strerror(errno)); + return -1; + } + } + else if (result == 0) /* EOF?? Does this happen on a write */ + result = -1; + + JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_written); + return (jlong) result; +} + + + + +#ifdef __cplusplus +} +#endif diff --git a/native/plugin/.cvsignore b/native/plugin/.cvsignore new file mode 100644 index 000000000..17cbfe80b --- /dev/null +++ b/native/plugin/.cvsignore @@ -0,0 +1,6 @@ +Makefile.in +.deps +.libs +libgcjwebplugin_la-gcjwebplugin.lo +libgcjwebplugin.la +Makefile diff --git a/native/plugin/Makefile.am b/native/plugin/Makefile.am new file mode 100644 index 000000000..7358381eb --- /dev/null +++ b/native/plugin/Makefile.am @@ -0,0 +1,18 @@ +lib_LTLIBRARIES = libgcjwebplugin.la + +libgcjwebplugin_la_SOURCES = gcjwebplugin.cc + +libgcjwebplugin_la_CXXFLAGS = \ + -Wall -DAPPLETVIEWER_EXECUTABLE="\"$(bindir)/appletviewer\"" \ + $(MOZILLA_CFLAGS) $(GLIB_CFLAGS) + +libgcjwebplugin_la_LDFLAGS = -avoid-version \ + $(GLIB_LIBS) \ + -lstdc++ + +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + $(INSTALL) -d -m0755 $(DESTDIR)@PLUGIN_DIR@ + $(INSTALL) .libs/libgcjwebplugin.so $(DESTDIR)@PLUGIN_DIR@ + +uninstall-libLTLIBRARIES: + rm -f $(DESTDIR)@PLUGIN_DIR@/libgcjwebplugin.so diff --git a/native/plugin/gcjwebplugin.cc b/native/plugin/gcjwebplugin.cc new file mode 100644 index 000000000..bbb9809be --- /dev/null +++ b/native/plugin/gcjwebplugin.cc @@ -0,0 +1,1411 @@ +/* gcjwebplugin.cc -- web browser plugin to execute Java applets + Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +// System includes. +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +// Netscape plugin API includes. +#include <npapi.h> +#include <npupp.h> + +// GLib includes. +#include <glib.h> + +// gcjwebplugin includes. +#include "config.h" + +// Documentbase retrieval includes. +#include <nsIPluginInstance.h> +#include <nsIPluginInstancePeer.h> +#include <nsIPluginTagInfo2.h> + +// Debugging macros. +#define PLUGIN_DEBUG(message) \ + g_print ("GCJ PLUGIN: thread %p: %s\n", g_thread_self (), message) + +#define PLUGIN_DEBUG_TWO(first, second) \ + g_print ("GCJ PLUGIN: thread %p: %s %s\n", g_thread_self (), \ + first, second) + +// Error reporting macros. +#define PLUGIN_ERROR(message) \ + g_printerr ("%s:%d: thread %p: Error: %s\n", __FILE__, __LINE__, \ + g_thread_self (), message) + +#define PLUGIN_ERROR_TWO(first, second) \ + g_printerr ("%s:%d: thread %p: Error: %s: %s\n", __FILE__, __LINE__, \ + g_thread_self (), first, second) + +// Plugin information passed to about:plugins. +#define PLUGIN_NAME "GCJ Web Browser Plugin" +#define PLUGIN_DESC "The " PLUGIN_NAME " executes Java applets." +#define PLUGIN_MIME_DESC \ + "application/x-java-vm:class,jar:GCJ;" \ + "application/x-java-applet:class,jar:GCJ;" \ + "application/x-java-applet;version=1.1:class,jar:GCJ;" \ + "application/x-java-applet;version=1.1.1:class,jar:GCJ;" \ + "application/x-java-applet;version=1.1.2:class,jar:GCJ;" \ + "application/x-java-applet;version=1.1.3:class,jar:GCJ;" \ + "application/x-java-applet;version=1.2:class,jar:GCJ;" \ + "application/x-java-applet;version=1.2.1:class,jar:GCJ;" \ + "application/x-java-applet;version=1.2.2:class,jar:GCJ;" \ + "application/x-java-applet;version=1.3:class,jar:GCJ;" \ + "application/x-java-applet;version=1.3.1:class,jar:GCJ;" \ + "application/x-java-applet;version=1.4:class,jar:GCJ;" \ + "application/x-java-applet;version=1.4.1:class,jar:GCJ;" \ + "application/x-java-applet;version=1.4.2:class,jar:GCJ;" \ + "application/x-java-applet;jpi-version=1.4.2_01:class,jar:GCJ;" \ + "application/x-java-bean:class,jar:GCJ;" \ + "application/x-java-bean;version=1.1:class,jar:GCJ;" \ + "application/x-java-bean;version=1.1.1:class,jar:GCJ;" \ + "application/x-java-bean;version=1.1.2:class,jar:GCJ;" \ + "application/x-java-bean;version=1.1.3:class,jar:GCJ;" \ + "application/x-java-bean;version=1.2:class,jar:GCJ;" \ + "application/x-java-bean;version=1.2.1:class,jar:GCJ;" \ + "application/x-java-bean;version=1.2.2:class,jar:GCJ;" \ + "application/x-java-bean;version=1.3:class,jar:GCJ;" \ + "application/x-java-bean;version=1.3.1:class,jar:GCJ;" \ + "application/x-java-bean;version=1.4:class,jar:GCJ;" \ + "application/x-java-bean;version=1.4.1:class,jar:GCJ;" \ + "application/x-java-bean;version=1.4.2:class,jar:GCJ;" \ + "application/x-java-bean;jpi-version=1.4.2_01:class,jar:GCJ;" +#define PLUGIN_URL NS_INLINE_PLUGIN_CONTRACTID_PREFIX NS_JVM_MIME_TYPE +#define PLUGIN_MIME_TYPE "application/x-java-vm" +#define PLUGIN_FILE_EXTS "class,jar,zip" +#define PLUGIN_MIME_COUNT 1 + +// Directory in which named pipes are created. +#define PIPE_DIRECTORY "/tmp" + +// Documentbase retrieval required definition. +static NS_DEFINE_IID (kIPluginTagInfo2IID, NS_IPLUGINTAGINFO2_IID); + +// Browser function table. +static NPNetscapeFuncs browserFunctions; + +// GCJPluginData stores all the data associated with a single plugin +// instance. A separate plugin instance is created for each <APPLET> +// tag. For now, each plugin instance spawns its own applet viewer +// process but this may need to change if we find pages containing +// multiple applets that expect to be running in the same VM. +struct GCJPluginData +{ + // A unique identifier for this plugin window. + gchar* instance_string; + // Applet viewer input pipe name. + gchar* in_pipe_name; + // Applet viewer input channel. + GIOChannel* in_from_appletviewer; + // Applet viewer input watch source. + gint in_watch_source; + // Applet viewer output pipe name. + gchar* out_pipe_name; + // Applet viewer output channel. + GIOChannel* out_to_appletviewer; + // Applet viewer output watch source. + gint out_watch_source; + // Mutex to protect appletviewer_alive. + GMutex* appletviewer_mutex; + // Back-pointer to the plugin instance to which this data belongs. + // This should not be freed but instead simply set to NULL. + NPP owner; + // FALSE if the applet viewer process has died. All code + // communicating with the applet viewer should check this flag + // before attempting to read from/write to the applet viewer pipes. + gboolean appletviewer_alive; + // The address of the plugin window. This should not be freed but + // instead simply set to NULL. + gpointer window_handle; + // The last plugin window width sent to us by the browser. + guint32 window_width; + // The last plugin window height sent to us by the browser. + guint32 window_height; +}; + +// Documentbase retrieval type-punning union. +typedef union +{ + void** void_field; + nsIPluginTagInfo2** info_field; +} info_union; + +// Static instance helper functions. +// Have the browser allocate a new GCJPluginData structure. +static void plugin_data_new (GCJPluginData** data); +// Documentbase retrieval. +static gchar* plugin_get_documentbase (NPP instance); +// Callback used to monitor input pipe status. +static gboolean plugin_in_pipe_callback (GIOChannel* source, + GIOCondition condition, + gpointer plugin_data); +// Callback used to monitor output pipe status. +static gboolean plugin_out_pipe_callback (GIOChannel* source, + GIOCondition condition, + gpointer plugin_data); +static void plugin_start_appletviewer (GCJPluginData* data); +static gchar* plugin_create_applet_tag (int16 argc, char* argn[], + char* argv[]); +static void plugin_send_message_to_appletviewer (GCJPluginData* data, + gchar const* message); +static void plugin_stop_appletviewer (GCJPluginData* data); +// Uninitialize GCJPluginData structure and delete pipes. +static void plugin_data_destroy (GCJPluginData** data); + +// Global instance counter. +// Mutex to protect plugin_instance_counter. +static GMutex* plugin_instance_mutex = NULL; +// A counter used to create uniquely named pipes. +static gulong plugin_instance_counter = 0; + +// Functions prefixed by GCJ_ are instance functions. They are called +// by the browser and operate on instances of GCJPluginData. +// Functions prefixed by plugin_ are static helper functions. +// Functions prefixed by NP_ are factory functions. They are called +// by the browser and provide functionality needed to create plugin +// instances. + +// INSTANCE FUNCTIONS + +// Creates a new gcjwebplugin instance. This function creates a +// GCJPluginData* and stores it in instance->pdata. The following +// GCJPluginData fiels are initialized: instance_string, in_pipe_name, +// in_from_appletviewer, in_watch_source, out_pipe_name, +// out_to_appletviewer, out_watch_source, appletviewer_mutex, owner, +// appletviewer_alive. In addition two pipe files are created. All +// of those fields must be properly destroyed, and the pipes deleted, +// by GCJ_Destroy. If an error occurs during initialization then this +// function will free anything that's been allocated so far, set +// instance->pdata to NULL and return an error code. +NPError +GCJ_New (NPMIMEType pluginType, NPP instance, uint16 mode, + int16 argc, char* argn[], char* argv[], + NPSavedData* saved) +{ + PLUGIN_DEBUG ("GCJ_New"); + + NPError np_error = NPERR_NO_ERROR; + GCJPluginData* data = NULL; + GError* channel_error = NULL; + gchar* documentbase = NULL; + gchar* read_message = NULL; + gchar* applet_tag = NULL; + gchar* tag_message = NULL; + + if (!instance) + { + PLUGIN_ERROR ("Browser-provided instance pointer is NULL."); + np_error = NPERR_INVALID_INSTANCE_ERROR; + goto cleanup_done; + } + + // Initialize threads (needed for mutexes). + if (!g_thread_supported ()) + g_thread_init (NULL); + + // data + plugin_data_new (&data); + if (data == NULL) + { + PLUGIN_ERROR ("Failed to allocate plugin data."); + np_error = NPERR_OUT_OF_MEMORY_ERROR; + goto cleanup_done; + } + + // Initialize data->instance_string. + // + // instance_string should be unique for this process so we use a + // combination of getpid and plugin_instance_counter. + // + // Critical region. Reference and increment plugin_instance_counter + // global. + g_mutex_lock (plugin_instance_mutex); + + // data->instance_string + data->instance_string = g_strdup_printf ("instance-%d-%ld", + getpid (), + plugin_instance_counter++); + + g_mutex_unlock (plugin_instance_mutex); + + // data->appletviewer_mutex + data->appletviewer_mutex = g_mutex_new (); + + // Documentbase retrieval. + documentbase = plugin_get_documentbase (instance); + if (!documentbase) + { + PLUGIN_ERROR ("Documentbase retrieval failed." + " Browser not Mozilla-based?"); + goto cleanup_appletviewer_mutex; + } + + // Create appletviewer-to-plugin pipe which we refer to as the input + // pipe. + + // data->in_pipe_name + data->in_pipe_name = g_strdup_printf (PIPE_DIRECTORY + "/gcj-%s-appletviewer-to-plugin", + data->instance_string); + if (!data->in_pipe_name) + { + PLUGIN_ERROR ("Failed to create input pipe name."); + np_error = NPERR_OUT_OF_MEMORY_ERROR; + // If data->in_pipe_name is NULL then the g_free at + // cleanup_in_pipe_name will simply return. + goto cleanup_in_pipe_name; + } + + if (mkfifo (data->in_pipe_name, 0700) == -1 && errno != EEXIST) + { + PLUGIN_ERROR_TWO ("Failed to create input pipe", strerror (errno)); + np_error = NPERR_GENERIC_ERROR; + goto cleanup_in_pipe_name; + } + + // Create plugin-to-appletviewer pipe which we refer to as the + // output pipe. + + // data->out_pipe_name + data->out_pipe_name = g_strdup_printf (PIPE_DIRECTORY + "/gcj-%s-plugin-to-appletviewer", + data->instance_string); + + if (!data->out_pipe_name) + { + PLUGIN_ERROR ("Failed to create output pipe name."); + np_error = NPERR_OUT_OF_MEMORY_ERROR; + goto cleanup_out_pipe_name; + } + + if (mkfifo (data->out_pipe_name, 0700) == -1 && errno != EEXIST) + { + PLUGIN_ERROR_TWO ("Failed to create output pipe", strerror (errno)); + np_error = NPERR_GENERIC_ERROR; + goto cleanup_out_pipe_name; + } + + // Start a separate appletviewer process for each applet, even if + // there are multiple applets in the same page. We may need to + // change this behaviour if we find pages with multiple applets that + // rely on being run in the same VM. + + // Critical region. Hold appletviewer_mutex while we start the + // appletviewer, create the IO channels and install the channel + // watch callbacks. + g_mutex_lock (data->appletviewer_mutex); + + plugin_start_appletviewer (data); + + // Create plugin-to-appletviewer channel. The default encoding for + // the file is UTF-8. + // data->out_to_appletviewer + data->out_to_appletviewer = g_io_channel_new_file (data->out_pipe_name, + "w", &channel_error); + if (!data->out_to_appletviewer) + { + PLUGIN_ERROR_TWO ("Failed to create output channel", + channel_error->message); + np_error = NPERR_GENERIC_ERROR; + goto cleanup_out_to_appletviewer; + } + if (channel_error) + { + g_error_free (channel_error); + channel_error = NULL; + } + + // Watch for hangup and error signals on the output pipe. + data->out_watch_source = + g_io_add_watch (data->out_to_appletviewer, + (GIOCondition) (G_IO_ERR | G_IO_HUP), + plugin_out_pipe_callback, (gpointer) data); + + // Create appletviewer-to-plugin channel. The default encoding for + // the file is UTF-8. + // data->in_from_appletviewer + data->in_from_appletviewer = g_io_channel_new_file (data->in_pipe_name, + "r", &channel_error); + if (!data->in_from_appletviewer) + { + PLUGIN_ERROR_TWO ("Failed to create input channel", + channel_error->message); + np_error = NPERR_GENERIC_ERROR; + goto cleanup_in_from_appletviewer; + } + if (channel_error) + { + g_error_free (channel_error); + channel_error = NULL; + } + + // Watch for hangup and error signals on the input pipe. + data->in_watch_source = + g_io_add_watch (data->in_from_appletviewer, + (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_HUP), + plugin_in_pipe_callback, (gpointer) data); + + // Wait until we receive confirmation that the appletviewer has + // started. + if (g_io_channel_read_line (data->in_from_appletviewer, + &read_message, NULL, NULL, + &channel_error) + != G_IO_STATUS_NORMAL) + { + PLUGIN_ERROR_TWO ("Receiving confirmation from appletviewer failed", + channel_error->message); + np_error = NPERR_GENERIC_ERROR; + goto cleanup_in_watch_source; + } + if (channel_error) + { + g_error_free (channel_error); + channel_error = NULL; + } + + PLUGIN_DEBUG ("GCJ_New: got confirmation that appletviewer is running."); + data->appletviewer_alive = TRUE; + + // Send applet tag message to appletviewer. + applet_tag = plugin_create_applet_tag (argc, argn, argv); + tag_message = g_strconcat ("tag ", documentbase, " ", applet_tag, NULL); + + plugin_send_message_to_appletviewer (data, data->instance_string); + plugin_send_message_to_appletviewer (data, tag_message); + + g_mutex_unlock (data->appletviewer_mutex); + + // If initialization succeeded entirely then we store the plugin + // data in the instance structure and return. Otherwise we free the + // data we've allocated so far and set instance->pdata to NULL. + + // Set back-pointer to owner instance. + data->owner = instance; + instance->pdata = data; + goto cleanup_done; + + // An error occurred while initializing the plugin data or spawning + // the appletviewer so we free the data we've already allocated. + + cleanup_in_watch_source: + // Removing a source is harmless if it fails since it just means the + // source has already been removed. + g_source_remove (data->in_watch_source); + data->in_watch_source = 0; + + cleanup_in_from_appletviewer: + if (data->in_from_appletviewer) + g_io_channel_unref (data->in_from_appletviewer); + data->in_from_appletviewer = NULL; + + // cleanup_out_watch_source: + g_source_remove (data->out_watch_source); + data->out_watch_source = 0; + + cleanup_out_to_appletviewer: + if (data->out_to_appletviewer) + g_io_channel_unref (data->out_to_appletviewer); + data->out_to_appletviewer = NULL; + + // cleanup_out_pipe: + // Delete output pipe. + unlink (data->out_pipe_name); + + cleanup_out_pipe_name: + g_free (data->out_pipe_name); + data->out_pipe_name = NULL; + + // cleanup_in_pipe: + // Delete input pipe. + unlink (data->in_pipe_name); + + cleanup_in_pipe_name: + g_free (data->in_pipe_name); + data->in_pipe_name = NULL; + + cleanup_appletviewer_mutex: + g_free (data->appletviewer_mutex); + data->appletviewer_mutex = NULL; + + // cleanup_instance_string: + g_free (data->instance_string); + data->instance_string = NULL; + + // cleanup_data: + // Eliminate back-pointer to plugin instance. + data->owner = NULL; + (*browserFunctions.memfree) (data); + data = NULL; + + // Initialization failed so return a NULL pointer for the browser + // data. + instance->pdata = NULL; + + cleanup_done: + + g_free (tag_message); + tag_message = NULL; + g_free (applet_tag); + applet_tag = NULL; + g_free (read_message); + read_message = NULL; + g_free (documentbase); + documentbase = NULL; + + PLUGIN_DEBUG ("GCJ_New return"); + + return np_error; +} + +NPError +GCJ_GetValue (NPP instance, NPPVariable variable, void* value) +{ + PLUGIN_DEBUG ("GCJ_GetValue"); + + NPError np_error = NPERR_NO_ERROR; + + switch (variable) + { + // This plugin needs XEmbed support. + case NPPVpluginNeedsXEmbed: + { + PLUGIN_DEBUG ("GCJ_GetValue: returning TRUE for NeedsXEmbed."); + PRBool* bool_value = (PRBool*) value; + *bool_value = PR_TRUE; + } + break; + + default: + PLUGIN_ERROR ("Unknown plugin value requested."); + np_error = NPERR_GENERIC_ERROR; + break; + } + + PLUGIN_DEBUG ("GCJ_GetValue return"); + + return np_error; +} + +NPError +GCJ_Destroy (NPP instance, NPSavedData** save) +{ + PLUGIN_DEBUG ("GCJ_Destroy"); + + GCJPluginData* data = (GCJPluginData*) instance->pdata; + + if (data) + { + // Critical region. Stop the appletviewer. + g_mutex_lock (data->appletviewer_mutex); + + // Tell the appletviewer to destroy its embedded plugin window. + plugin_send_message_to_appletviewer (data, "destroy"); + // Shut down the appletviewer. + plugin_stop_appletviewer (data); + + g_mutex_unlock (data->appletviewer_mutex); + + // Free plugin data. + plugin_data_destroy (&data); + } + + PLUGIN_DEBUG ("GCJ_Destroy return"); + + return NPERR_NO_ERROR; +} + +NPError +GCJ_SetWindow (NPP instance, NPWindow* window) +{ + PLUGIN_DEBUG ("GCJ_SetWindow"); + + if (instance == NULL) + { + PLUGIN_ERROR ("Invalid instance."); + + return NPERR_INVALID_INSTANCE_ERROR; + } + + GCJPluginData* data = (GCJPluginData*) instance->pdata; + + // Simply return if we receive a NULL window. + if ((window == NULL) || (window->window == NULL)) + { + PLUGIN_DEBUG ("GCJ_SetWindow: got NULL window."); + + return NPERR_NO_ERROR; + } + + if (data->window_handle) + { + // The window already exists. + if (data->window_handle == window->window) + { + // The parent window is the same as in previous calls. + PLUGIN_DEBUG ("GCJ_SetWindow: window already exists."); + + // Critical region. Read data->appletviewer_mutex and send + // a message to the appletviewer. + g_mutex_lock (data->appletviewer_mutex); + + if (data->appletviewer_alive) + { + // The window is the same as it was for the last + // SetWindow call. + if (window->width != data->window_width) + { + PLUGIN_DEBUG ("GCJ_SetWindow: window width changed."); + // The width of the plugin window has changed. + + // Send the new width to the appletviewer. + plugin_send_message_to_appletviewer (data, + data->instance_string); + gchar* width_message = g_strdup_printf ("width %d", + window->width); + plugin_send_message_to_appletviewer (data, width_message); + g_free (width_message); + + // Store the new width. + data->window_width = window->width; + } + + if (window->height != data->window_height) + { + PLUGIN_DEBUG ("GCJ_SetWindow: window height changed."); + // The height of the plugin window has changed. + + // Send the new height to the appletviewer. + plugin_send_message_to_appletviewer (data, + data->instance_string); + gchar* height_message = g_strdup_printf ("height %d", + window->height); + plugin_send_message_to_appletviewer (data, height_message); + g_free (height_message); + + // Store the new height. + data->window_height = window->height; + } + } + else + { + // The appletviewer is not running. + PLUGIN_DEBUG ("GCJ_SetWindow: appletviewer is not running."); + } + + g_mutex_unlock (data->appletviewer_mutex); + } + else + { + // The parent window has changed. This branch does run but + // doing nothing in response seems to be sufficient. + PLUGIN_DEBUG ("GCJ_SetWindow: parent window changed."); + } + } + else + { + PLUGIN_DEBUG ("GCJ_SetWindow: setting window."); + + // Critical region. Send messages to appletviewer. + g_mutex_lock (data->appletviewer_mutex); + + plugin_send_message_to_appletviewer (data, data->instance_string); + gchar *window_message = g_strdup_printf ("handle %ld", + (gulong) window->window); + plugin_send_message_to_appletviewer (data, window_message); + g_free (window_message); + + g_mutex_unlock (data->appletviewer_mutex); + + // Store the window handle. + data->window_handle = window->window; + } + + PLUGIN_DEBUG ("GCJ_SetWindow return"); + + return NPERR_NO_ERROR; +} + +NPError +GCJ_NewStream (NPP instance, NPMIMEType type, NPStream* stream, + NPBool seekable, uint16* stype) +{ + PLUGIN_DEBUG ("GCJ_NewStream"); + + PLUGIN_DEBUG ("GCJ_NewStream return"); + + return NPERR_NO_ERROR; +} + +void +GCJ_StreamAsFile (NPP instance, NPStream* stream, const char* filename) +{ + PLUGIN_DEBUG ("GCJ_StreamAsFile"); + + PLUGIN_DEBUG ("GCJ_StreamAsFile return"); +} + +NPError +GCJ_DestroyStream (NPP instance, NPStream* stream, NPReason reason) +{ + PLUGIN_DEBUG ("GCJ_DestroyStream"); + + PLUGIN_DEBUG ("GCJ_DestroyStream return"); + + return NPERR_NO_ERROR; +} + +int32 +GCJ_WriteReady (NPP instance, NPStream* stream) +{ + PLUGIN_DEBUG ("GCJ_WriteReady"); + + PLUGIN_DEBUG ("GCJ_WriteReady return"); + + return 0; +} + +int32 +GCJ_Write (NPP instance, NPStream* stream, int32 offset, int32 len, + void* buffer) +{ + PLUGIN_DEBUG ("GCJ_Write"); + + PLUGIN_DEBUG ("GCJ_Write return"); + + return 0; +} + +void +GCJ_Print (NPP instance, NPPrint* platformPrint) +{ + PLUGIN_DEBUG ("GCJ_Print"); + + PLUGIN_DEBUG ("GCJ_Print return"); +} + +int16 +GCJ_HandleEvent (NPP instance, void* event) +{ + PLUGIN_DEBUG ("GCJ_HandleEvent"); + + PLUGIN_DEBUG ("GCJ_HandleEvent return"); + + return 0; +} + +void +GCJ_URLNotify (NPP instance, const char* url, NPReason reason, + void* notifyData) +{ + PLUGIN_DEBUG ("GCJ_URLNotify"); + + PLUGIN_DEBUG ("GCJ_URLNotify return"); +} + +jref +GCJ_GetJavaClass (void) +{ + PLUGIN_DEBUG ("GCJ_GetJavaClass"); + + PLUGIN_DEBUG ("GCJ_GetJavaClass return"); + + return 0; +} + +// HELPER FUNCTIONS + +static void +plugin_data_new (GCJPluginData** data) +{ + PLUGIN_DEBUG ("plugin_data_new"); + + *data = (GCJPluginData*) + (*browserFunctions.memalloc) (sizeof (struct GCJPluginData)); + + // appletviewer_alive is false until the applet viewer is spawned. + if (*data) + memset (*data, 0, sizeof (struct GCJPluginData)); + + PLUGIN_DEBUG ("plugin_data_new return"); +} + +// Documentbase retrieval. This function gets the current document's +// documentbase. This function relies on browser-private data so it +// will only work when the plugin is loaded in a Mozilla-based +// browser. We could not find a way to retrieve the documentbase +// using the original Netscape plugin API so we use the XPCOM API +// instead. +static gchar* +plugin_get_documentbase (NPP instance) +{ + PLUGIN_DEBUG ("plugin_get_documentbase"); + + nsIPluginInstance* xpcom_instance = NULL; + nsIPluginInstancePeer* peer = NULL; + nsresult result = 0; + nsIPluginTagInfo2* pluginTagInfo2 = NULL; + info_union u = { NULL }; + char const* documentbase = NULL; + gchar* documentbase_copy = NULL; + + xpcom_instance = (nsIPluginInstance*) (instance->ndata); + if (!xpcom_instance) + { + PLUGIN_ERROR ("xpcom_instance is NULL."); + goto cleanup_done; + } + + xpcom_instance->GetPeer (&peer); + if (!peer) + { + PLUGIN_ERROR ("peer is NULL."); + goto cleanup_done; + } + + u.info_field = &pluginTagInfo2; + + result = peer->QueryInterface (kIPluginTagInfo2IID, + u.void_field); + if (result || !pluginTagInfo2) + { + PLUGIN_ERROR ("pluginTagInfo2 retrieval failed."); + goto cleanup_peer; + } + + pluginTagInfo2->GetDocumentBase (&documentbase); + + if (!documentbase) + { + PLUGIN_ERROR ("documentbase is NULL."); + goto cleanup_plugintaginfo2; + } + + documentbase_copy = g_strdup (documentbase); + + // Release references. + cleanup_plugintaginfo2: + NS_RELEASE (pluginTagInfo2); + + cleanup_peer: + NS_RELEASE (peer); + + cleanup_done: + PLUGIN_DEBUG ("plugin_get_documentbase return"); + + return documentbase_copy; +} + +// plugin_in_pipe_callback is called when data is available on the +// input pipe, or when the appletviewer crashes or is killed. It may +// be called after data has been destroyed in which case it simply +// returns FALSE to remove itself from the glib main loop. +static gboolean +plugin_in_pipe_callback (GIOChannel* source, + GIOCondition condition, + gpointer plugin_data) +{ + PLUGIN_DEBUG ("plugin_in_pipe_callback"); + + GCJPluginData* data = (GCJPluginData*) plugin_data; + gboolean keep_installed = TRUE; + + // If data is NULL then GCJ_Destroy has already been called and + // plugin_in_pipe_callback is being called after plugin + // destruction. In that case all we need to do is return FALSE so + // that the plugin_in_pipe_callback watch is removed. + if (data) + { + // Critical region. Set or clear data->appletviewer_alive. + g_mutex_lock (data->appletviewer_mutex); + + if (condition & G_IO_IN) + { + GError* channel_error = NULL; + gchar* message = NULL; + + if (g_io_channel_read_line (data->in_from_appletviewer, + &message, NULL, NULL, + &channel_error) + != G_IO_STATUS_NORMAL) + { + PLUGIN_ERROR_TWO ("Failed to read line from input channel", + channel_error->message); + } + else + { + if (g_str_has_prefix (message, "url ")) + { + gchar** parts = g_strsplit (message, " ", 3); + PLUGIN_DEBUG_TWO ("plugin_in_pipe_callback:" + " opening URL", parts[1]); + PLUGIN_DEBUG_TWO ("plugin_in_pipe_callback:" + " URL target", parts[2]); + // Open the URL in a new browser window. + NPError np_error = + (*browserFunctions.geturl) (data->owner, parts[1], parts[2]); + if (np_error != NPERR_NO_ERROR) + PLUGIN_ERROR ("Failed to load URL."); + g_strfreev (parts); + parts = NULL; + } + else if (g_str_has_prefix (message, "status ")) + { + gchar** parts = g_strsplit (message, " ", 2); + + PLUGIN_DEBUG_TWO ("plugin_in_pipe_callback:" + " setting status", parts[1]); + (*browserFunctions.status) (data->owner, parts[1]); + g_strfreev (parts); + parts = NULL; + } + g_print (" PIPE: plugin read %s\n", message); + } + + if (channel_error) + { + g_error_free (channel_error); + channel_error = NULL; + } + + g_free (message); + message = NULL; + + keep_installed = TRUE; + } + + if (condition & (G_IO_ERR | G_IO_HUP)) + { + PLUGIN_DEBUG ("appletviewer has stopped."); + data->appletviewer_alive = FALSE; + keep_installed = FALSE; + } + g_mutex_unlock (data->appletviewer_mutex); + } + + PLUGIN_DEBUG ("plugin_in_pipe_callback return"); + + return keep_installed; +} + +// plugin_out_pipe_callback is called when the appletviewer crashes or +// is killed. It may be called after data has been destroyed in which +// case it simply returns FALSE to remove itself from the glib main +// loop. +static gboolean +plugin_out_pipe_callback (GIOChannel* source, + GIOCondition condition, + gpointer plugin_data) +{ + PLUGIN_DEBUG ("plugin_out_pipe_callback"); + + GCJPluginData* data = (GCJPluginData*) plugin_data; + + // If data is NULL then GCJ_Destroy has already been called and + // plugin_out_pipe_callback is being called after plugin + // destruction. In that case all we need to do is return FALSE so + // that the plugin_out_pipe_callback watch is removed. + if (data) + { + // Critical region. Clear data->appletviewer_alive. + g_mutex_lock (data->appletviewer_mutex); + + PLUGIN_DEBUG ("plugin_out_pipe_callback: appletviewer has stopped."); + data->appletviewer_alive = FALSE; + + g_mutex_unlock (data->appletviewer_mutex); + } + + PLUGIN_DEBUG ("plugin_out_pipe_callback return"); + + return FALSE; +} + +static void +plugin_start_appletviewer (GCJPluginData* data) +{ + PLUGIN_DEBUG ("plugin_start_appletviewer"); + + if (!data->appletviewer_alive) + { + GError* spawn_error = NULL; + gchar* command_line[3] = { NULL, NULL, NULL }; + + command_line[0] = g_strdup (APPLETVIEWER_EXECUTABLE); + // Output from plugin's perspective is appletviewer's input. + // Input from plugin's perspective is appletviewer's output. + command_line[1] = g_strdup_printf ("--plugin=%s,%s", + data->out_pipe_name, + data->in_pipe_name); + command_line[2] = NULL; + + if (!g_spawn_async (NULL, command_line, NULL, (GSpawnFlags) 0, + NULL, NULL, NULL, &spawn_error)) + { + PLUGIN_ERROR_TWO ("Failed to spawn applet viewer", + spawn_error->message); + goto cleanup; + } + + cleanup: + g_free (command_line[0]); + g_free (command_line[1]); + g_free (command_line[2]); + if (spawn_error) + { + g_error_free (spawn_error); + spawn_error = NULL; + } + } + + PLUGIN_DEBUG ("plugin_start_appletviewer return"); +} + +// Build up the applet tag string that we'll send to the applet +// viewer. +static gchar* +plugin_create_applet_tag (int16 argc, char* argn[], char* argv[]) +{ + PLUGIN_DEBUG ("plugin_create_applet_tag"); + + gchar* applet_tag = g_strdup ("<EMBED "); + gchar* parameters = g_strdup (""); + + for (int16 i = 0; i < argc; i++) + { + if (!g_ascii_strcasecmp (argn[i], "code")) + { + gchar* code = g_strdup_printf ("CODE=\"%s\" ", argv[i]); + applet_tag = g_strconcat (applet_tag, code, NULL); + g_free (code); + } + else if (!g_ascii_strcasecmp (argn[i], "codebase")) + { + gchar* codebase = g_strdup_printf ("CODEBASE=\"%s\" ", argv[i]); + applet_tag = g_strconcat (applet_tag, codebase, NULL); + g_free (codebase); + } + else if (!g_ascii_strcasecmp (argn[i], "archive")) + { + gchar* archive = g_strdup_printf ("ARCHIVE=\"%s\" ", argv[i]); + applet_tag = g_strconcat (applet_tag, archive, NULL); + g_free (archive); + } + else if (!g_ascii_strcasecmp (argn[i], "width")) + { + gchar* width = g_strdup_printf ("WIDTH=\"%s\" ", argv[i]); + applet_tag = g_strconcat (applet_tag, width, NULL); + g_free (width); + } + else if (!g_ascii_strcasecmp (argn[i], "height")) + { + gchar* height = g_strdup_printf ("HEIGHT=\"%s\" ", argv[i]); + applet_tag = g_strconcat (applet_tag, height, NULL); + g_free (height); + } + else + { + // Escape the parameter value so that line termination + // characters will pass through the pipe. + if (argv[i] != '\0') + { + gchar* escaped = g_strescape (argv[i], NULL); + parameters = g_strconcat (parameters, "<PARAM NAME=\"", argn[i], + "\" VALUE=\"", escaped, "\">", NULL); + g_free (escaped); + } + } + } + + applet_tag = g_strconcat (applet_tag, ">", parameters, "</EMBED>", NULL); + + g_free (parameters); + parameters = NULL; + + PLUGIN_DEBUG ("plugin_create_applet_tag return"); + + return applet_tag; +} + +// plugin_send_message_to_appletviewer must be called while holding +// data->appletviewer_mutex. +static void +plugin_send_message_to_appletviewer (GCJPluginData* data, gchar const* message) +{ + PLUGIN_DEBUG ("plugin_send_message_to_appletviewer"); + + if (data->appletviewer_alive) + { + GError* channel_error = NULL; + gchar* newline_message = NULL; + gsize bytes_written = 0; + + // Send message to appletviewer. + newline_message = g_strdup_printf ("%s\n", message); + + // g_io_channel_write_chars will return something other than + // G_IO_STATUS_NORMAL if not all the data is written. In that + // case we fail rather than retrying. + if (g_io_channel_write_chars (data->out_to_appletviewer, + newline_message, -1, &bytes_written, + &channel_error) + != G_IO_STATUS_NORMAL) + PLUGIN_ERROR_TWO ("Failed to write bytes to output channel", + channel_error->message); + + if (channel_error) + { + g_error_free (channel_error); + channel_error = NULL; + } + + if (g_io_channel_flush (data->out_to_appletviewer, &channel_error) + != G_IO_STATUS_NORMAL) + PLUGIN_ERROR_TWO ("Failed to flush bytes to output channel", + channel_error->message); + + if (channel_error) + { + g_error_free (channel_error); + channel_error = NULL; + } + g_free (newline_message); + + g_print (" PIPE: plugin wrote %s\n", message); + } + + PLUGIN_DEBUG ("plugin_send_message_to_appletviewer return"); +} + +// Stop the appletviewer process. When this is called the +// appletviewer can be in any of three states: running, crashed or +// hung. If the appletviewer is running then sending it "shutdown" +// will cause it to exit. This will cause +// plugin_out_pipe_callback/plugin_in_pipe_callback to be called and +// the input and output channels to be shut down. If the appletviewer +// has crashed then plugin_out_pipe_callback/plugin_in_pipe_callback +// would already have been called and data->appletviewer_alive cleared +// in which case this function simply returns. If the appletviewer is +// hung then this function will be successful and the input and output +// watches will be removed by plugin_data_destroy. +// plugin_stop_appletviewer must be called with +// data->appletviewer_mutex held. +static void +plugin_stop_appletviewer (GCJPluginData* data) +{ + PLUGIN_DEBUG ("plugin_stop_appletviewer"); + + if (data->appletviewer_alive) + { + // Shut down the appletviewer. + GError* channel_error = NULL; + gsize bytes_written = 0; + + if (data->out_to_appletviewer) + { + if (g_io_channel_write_chars (data->out_to_appletviewer, "shutdown", + -1, &bytes_written, &channel_error) + != G_IO_STATUS_NORMAL) + PLUGIN_ERROR_TWO ("Failed to write shutdown message to" + " appletviewer", channel_error->message); + + if (channel_error) + { + g_error_free (channel_error); + channel_error = NULL; + } + + if (g_io_channel_flush (data->out_to_appletviewer, &channel_error) + != G_IO_STATUS_NORMAL) + PLUGIN_ERROR_TWO ("Failed to write shutdown message to" + " appletviewer", channel_error->message); + + if (channel_error) + { + g_error_free (channel_error); + channel_error = NULL; + } + + if (g_io_channel_shutdown (data->out_to_appletviewer, + TRUE, &channel_error) + != G_IO_STATUS_NORMAL) + PLUGIN_ERROR_TWO ("Failed to shut down appletviewer" + " output channel", channel_error->message); + + if (channel_error) + { + g_error_free (channel_error); + channel_error = NULL; + } + } + + if (data->in_from_appletviewer) + { + if (g_io_channel_shutdown (data->in_from_appletviewer, + TRUE, &channel_error) + != G_IO_STATUS_NORMAL) + PLUGIN_ERROR_TWO ("Failed to shut down appletviewer" + " input channel", channel_error->message); + + if (channel_error) + { + g_error_free (channel_error); + channel_error = NULL; + } + } + } + + PLUGIN_DEBUG ("plugin_stop_appletviewer return"); +} + +static void +plugin_data_destroy (GCJPluginData** data) +{ + PLUGIN_DEBUG ("plugin_data_destroy"); + + GCJPluginData* tofree = *data; + + tofree->window_handle = NULL; + tofree->window_height = 0; + tofree->window_width = 0; + + // Copied from GCJ_New. + + // cleanup_in_watch_source: + // Removing a source is harmless if it fails since it just means the + // source has already been removed. + g_source_remove (tofree->in_watch_source); + tofree->in_watch_source = 0; + + // cleanup_in_from_appletviewer: + if (tofree->in_from_appletviewer) + g_io_channel_unref (tofree->in_from_appletviewer); + tofree->in_from_appletviewer = NULL; + + // cleanup_out_watch_source: + g_source_remove (tofree->out_watch_source); + tofree->out_watch_source = 0; + + // cleanup_out_to_appletviewer: + if (tofree->out_to_appletviewer) + g_io_channel_unref (tofree->out_to_appletviewer); + tofree->out_to_appletviewer = NULL; + + // cleanup_out_pipe: + // Delete output pipe. + unlink (tofree->out_pipe_name); + + // cleanup_out_pipe_name: + g_free (tofree->out_pipe_name); + tofree->out_pipe_name = NULL; + + // cleanup_in_pipe: + // Delete input pipe. + unlink (tofree->in_pipe_name); + + // cleanup_in_pipe_name: + g_free (tofree->in_pipe_name); + tofree->in_pipe_name = NULL; + + // cleanup_appletviewer_mutex: + g_free (tofree->appletviewer_mutex); + tofree->appletviewer_mutex = NULL; + + // cleanup_instance_string: + g_free (tofree->instance_string); + tofree->instance_string = NULL; + + // cleanup_data: + // Eliminate back-pointer to plugin instance. + tofree->owner = NULL; + (*browserFunctions.memfree) (tofree); + tofree = NULL; + + PLUGIN_DEBUG ("plugin_data_destroy return"); +} + +// FACTORY FUNCTIONS + +// Provides the browser with pointers to the plugin functions that we +// implement and initializes a local table with browser functions that +// we may wish to call. Called once, after browser startup and before +// the first plugin instance is created. +NPError +NP_Initialize (NPNetscapeFuncs* browserTable, NPPluginFuncs* pluginTable) +{ + PLUGIN_DEBUG ("NP_Initialize"); + + if ((browserTable == NULL) || (pluginTable == NULL)) + { + PLUGIN_ERROR ("Browser or plugin function table is NULL."); + + return NPERR_INVALID_FUNCTABLE_ERROR; + } + + // Ensure that the major version of the plugin API that the browser + // expects is not more recent than the major version of the API that + // we've implemented. + if ((browserTable->version >> 8) > NP_VERSION_MAJOR) + { + PLUGIN_ERROR ("Incompatible version."); + + return NPERR_INCOMPATIBLE_VERSION_ERROR; + } + + // Ensure that the plugin function table we've received is large + // enough to store the number of functions that we may provide. + if (pluginTable->size < sizeof (NPPluginFuncs)) + { + PLUGIN_ERROR ("Invalid plugin function table."); + + return NPERR_INVALID_FUNCTABLE_ERROR; + } + + // Ensure that the browser function table is large enough to store + // the number of browser functions that we may use. + if (browserTable->size < sizeof (NPNetscapeFuncs)) + { + PLUGIN_ERROR ("Invalid browser function table."); + + return NPERR_INVALID_FUNCTABLE_ERROR; + } + + // Store in a local table the browser functions that we may use. + browserFunctions.version = browserTable->version; + browserFunctions.size = browserTable->size; + browserFunctions.posturl = browserTable->posturl; + browserFunctions.geturl = browserTable->geturl; + browserFunctions.geturlnotify = browserTable->geturlnotify; + browserFunctions.requestread = browserTable->requestread; + browserFunctions.newstream = browserTable->newstream; + browserFunctions.write = browserTable->write; + browserFunctions.destroystream = browserTable->destroystream; + browserFunctions.status = browserTable->status; + browserFunctions.uagent = browserTable->uagent; + browserFunctions.memalloc = browserTable->memalloc; + browserFunctions.memfree = browserTable->memfree; + browserFunctions.memflush = browserTable->memflush; + browserFunctions.reloadplugins = browserTable->reloadplugins; + browserFunctions.getvalue = browserTable->getvalue; + + // Return to the browser the plugin functions that we implement. + pluginTable->version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR; + pluginTable->size = sizeof (NPPluginFuncs); + pluginTable->newp = NewNPP_NewProc (GCJ_New); + pluginTable->destroy = NewNPP_DestroyProc (GCJ_Destroy); + pluginTable->setwindow = NewNPP_SetWindowProc (GCJ_SetWindow); + pluginTable->newstream = NewNPP_NewStreamProc (GCJ_NewStream); + pluginTable->destroystream = NewNPP_DestroyStreamProc (GCJ_DestroyStream); + pluginTable->asfile = NewNPP_StreamAsFileProc (GCJ_StreamAsFile); + pluginTable->writeready = NewNPP_WriteReadyProc (GCJ_WriteReady); + pluginTable->write = NewNPP_WriteProc (GCJ_Write); + pluginTable->print = NewNPP_PrintProc (GCJ_Print); + pluginTable->urlnotify = NewNPP_URLNotifyProc (GCJ_URLNotify); + pluginTable->getvalue = NewNPP_GetValueProc (GCJ_GetValue); + + plugin_instance_mutex = g_mutex_new (); + + PLUGIN_DEBUG ("NP_Initialize: using " APPLETVIEWER_EXECUTABLE "."); + + PLUGIN_DEBUG ("NP_Initialize return"); + + return NPERR_NO_ERROR; +} + +// Returns a string describing the MIME type that this plugin +// handles. +char* +NP_GetMIMEDescription (void) +{ + PLUGIN_DEBUG ("NP_GetMIMEDescription"); + + PLUGIN_DEBUG ("NP_GetMIMEDescription return"); + + return (char*) PLUGIN_MIME_DESC; +} + +// Returns a value relevant to the plugin as a whole. The browser +// calls this function to obtain information about the plugin. +NPError +NP_GetValue (void* future, NPPVariable variable, void* value) +{ + PLUGIN_DEBUG ("NP_GetValue"); + + NPError result = NPERR_NO_ERROR; + gchar** char_value = (gchar**) value; + + switch (variable) + { + case NPPVpluginNameString: + PLUGIN_DEBUG ("NP_GetValue: returning plugin name."); + *char_value = g_strdup (PLUGIN_NAME " " PACKAGE_VERSION); + break; + + case NPPVpluginDescriptionString: + PLUGIN_DEBUG ("NP_GetValue: returning plugin description."); + *char_value = g_strdup (PLUGIN_DESC); + break; + + default: + PLUGIN_ERROR ("Unknown plugin value requested."); + result = NPERR_GENERIC_ERROR; + break; + } + + PLUGIN_DEBUG ("NP_GetValue return"); + + return result; +} + +// Shuts down the plugin. Called after the last plugin instance is +// destroyed. +NPError +NP_Shutdown (void) +{ + PLUGIN_DEBUG ("NP_Shutdown"); + + // Free mutex. + g_mutex_free (plugin_instance_mutex); + plugin_instance_mutex = NULL; + + PLUGIN_DEBUG ("NP_Shutdown return"); + + return NPERR_NO_ERROR; +} diff --git a/native/target/generic/target_generic_network.h b/native/target/generic/target_generic_network.h index 4488ea876..99bb5d765 100644 --- a/native/target/generic/target_generic_network.h +++ b/native/target/generic/target_generic_network.h @@ -682,7 +682,8 @@ Systems : all \ __value.tv_sec = flag / 1000; \ __value.tv_usec = (flag % 1000) * 1000; \ - result=(setsockopt(socketDescriptor,SOL_SOCKET,SO_TIMEOUT,&__value,sizeof(__value))==0)?TARGET_NATIVE_OK:TARGET_NATIVE_ERROR; \ + result = ( (setsockopt(socketDescriptor, SOL_SOCKET, SO_SNDTIMEO, &__value, sizeof(__value)) | \ + setsockopt(socketDescriptor, SOL_SOCKET, SO_RCVTIMEO, &__value, sizeof(__value))) == 0) ? TARGET_NATIVE_OK : TARGET_NATIVE_ERROR; \ } while (0) #endif diff --git a/resource/gnu/classpath/tools/appletviewer/MessagesBundle.properties b/resource/gnu/classpath/tools/appletviewer/MessagesBundle.properties new file mode 100644 index 000000000..bbd7618a6 --- /dev/null +++ b/resource/gnu/classpath/tools/appletviewer/MessagesBundle.properties @@ -0,0 +1,70 @@ +# MessagesBundle.properties -- English language messages +# Copyright (C) 2004, 2006 Free Software Foundation, Inc. +# +# This file is part of GNU Classpath. +# +# GNU Classpath is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# GNU Classpath 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 for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Classpath; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA. +# +# Linking this library statically or dynamically with other modules is +# making a combined work based on this library. Thus, the terms and +# conditions of the GNU General Public License cover the whole +# combination. +# +# As a special exception, the copyright holders of this library give you +# permission to link this library with independent modules to produce an +# executable, regardless of the license terms of these independent +# modules, and to copy and distribute the resulting executable under +# terms of your choice, provided that you also meet, for each linked +# independent module, the terms and conditions of the license of that +# module. An independent module is a module which is not derived from +# or based on this library. If you modify this library, you may extend +# this exception to your version of the library, but you are not +# obligated to do so. If you do not wish to do so, delete this +# exception statement from your version. + +gcjwebplugin.code_description=specify the code attribute +gcjwebplugin.codebase_description=specify the codebase attribute +gcjwebplugin.archive_description=specify the archive attribute +gcjwebplugin.width_description=specify the width attribute +gcjwebplugin.height_description=specify the height attribute +gcjwebplugin.param_description=specify the parameter arguments +gcjwebplugin.plugin_description=enable plugin mode +gcjwebplugin.verbose_description=enable verbose mode +gcjwebplugin.debug_description=enable debugging mode (not implemented) +gcjwebplugin.encoding_description=specify the HTML character encoding + +gcjwebplugin.no_input_files=appletviewer: no input files + +gcjwebplugin.menu_title=Applet +gcjwebplugin.menu_reload=Reload +gcjwebplugin.menu_restart=Restart +gcjwebplugin.menu_start=Start +gcjwebplugin.menu_stop=Stop +gcjwebplugin.menu_clone=Clone ... +gcjwebplugin.menu_quit=Quit +gcjwebplugin.menu_close=Close +gcjwebplugin.menu_tag=Tag ... +gcjwebplugin.menu_info=Info ... +gcjwebplugin.menu_edit=Edit +gcjwebplugin.menu_encoding=Character Encoding +gcjwebplugin.menu_print=Print ... +gcjwebplugin.menu_properties=Properties ... +gcjwebplugin.menu_cancel=Cancel +gcjwebplugin.menu_save=Save ... + +gcjwebplugin.console_title=GCJ web plugin console +gcjwebplugin.console_clear=Clear +gcjwebplugin.console_hide=Hide diff --git a/resource/gnu/classpath/tools/appletviewer/MessagesBundle_de.properties b/resource/gnu/classpath/tools/appletviewer/MessagesBundle_de.properties new file mode 100644 index 000000000..036b86f30 --- /dev/null +++ b/resource/gnu/classpath/tools/appletviewer/MessagesBundle_de.properties @@ -0,0 +1,75 @@ +# MessagesBundle_de.properties -- German language messages +# Copyright (C) 2004, 2006 Free Software Foundation, Inc. +# +# This file is part of GNU Classpath. +# +# GNU Classpath is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# GNU Classpath 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 for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Classpath; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA. +# +# Linking this library statically or dynamically with other modules is +# making a combined work based on this library. Thus, the terms and +# conditions of the GNU General Public License cover the whole +# combination. +# +# As a special exception, the copyright holders of this library give you +# permission to link this library with independent modules to produce an +# executable, regardless of the license terms of these independent +# modules, and to copy and distribute the resulting executable under +# terms of your choice, provided that you also meet, for each linked +# independent module, the terms and conditions of the license of that +# module. An independent module is a module which is not derived from +# or based on this library. If you modify this library, you may extend +# this exception to your version of the library, but you are not +# obligated to do so. If you do not wish to do so, delete this +# exception statement from your version. + +# FIXME: rewrite this: +gcjwebplugin.help.0=Syntax: appletviewer [Optionen] <Dateiname>.class | <Dateiname>.html... | URL... +gcjwebplugin.help.1=Optionen: +gcjwebplugin.help.2= --help Diese Hilfe anzeigen and beenden +gcjwebplugin.help.3= --version Version anzeigen und beenden +gcjwebplugin.help.4= --code=<Klassenname>[.class] Applet mit Klassen- oder Dateiname ausführen +gcjwebplugin.help.5= --codebase=<Verzeichnis> Applet-Codebasis setzen +gcjwebplugin.help.6= --archive=<Dateiname>.jar[,...] Archive zum Klassenlader hinzufügen +gcjwebplugin.help.7= --param=<Name>,<Wert> Parameter an Applet übergeben +gcjwebplugin.help.8= --width=<Breite> Setze Breite des Appletfensters +gcjwebplugin.help.9= --height=<Höhe> Setze Höhe des Appletfensters +gcjwebplugin.help.10= --plugin=<Eingabepipe>,<Ausgabepipe> Pluginmodus einschalten +gcjwebplugin.help.11= -debug Starten des Applet-Viewers im Java-Debugger (nicht implementiert) +gcjwebplugin.help.12= -encoding <Codierung> Angabe der von HTML-Dateien verwendeten Zeichencodierung +gcjwebplugin.help.13= -J<Laufzeit-Flag> Übergeben des Arguments an den Java-Interpreter + +gcjwebplugin.no_input_files=appletviewer: keine Dateien angegeben + +gcjwebplugin.menu_title=Applet +gcjwebplugin.menu_reload=Neu laden +gcjwebplugin.menu_restart=Neu starten +gcjwebplugin.menu_start=Start +gcjwebplugin.menu_stop=Stop +gcjwebplugin.menu_clone=Klonen ... +gcjwebplugin.menu_quit=Beenden +gcjwebplugin.menu_tag=Tag ... +gcjwebplugin.menu_info=Informationen ... +gcjwebplugin.menu_edit=Bearbeiten +gcjwebplugin.menu_encoding=Zeichenkodierung +gcjwebplugin.menu_print=Drucken ... +gcjwebplugin.menu_properties=Eigenschaften ... +gcjwebplugin.menu_close=Schließen +gcjwebplugin.menu_cancel=Abbrechen +gcjwebplugin.menu_save=Speichern unter ... + +gcjwebplugin.console_title=GCJ web plugin Konsole +gcjwebplugin.console_clear=Löschen +gcjwebplugin.console_hide=Schließen diff --git a/resource/gnu/classpath/tools/getopt/Messages.properties b/resource/gnu/classpath/tools/getopt/Messages.properties new file mode 100644 index 000000000..42827e6e3 --- /dev/null +++ b/resource/gnu/classpath/tools/getopt/Messages.properties @@ -0,0 +1,49 @@ +# MessagesBundle.properties -- English language messages +# Copyright (C) 2006 Free Software Foundation, Inc. +# +# This file is part of GNU Classpath. +# +# GNU Classpath is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# GNU Classpath 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 for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Classpath; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA. +# +# Linking this library statically or dynamically with other modules is +# making a combined work based on this library. Thus, the terms and +# conditions of the GNU General Public License cover the whole +# combination. +# +# As a special exception, the copyright holders of this library give you +# permission to link this library with independent modules to produce an +# executable, regardless of the license terms of these independent +# modules, and to copy and distribute the resulting executable under +# terms of your choice, provided that you also meet, for each linked +# independent module, the terms and conditions of the license of that +# module. An independent module is a module which is not derived from +# or based on this library. If you modify this library, you may extend +# this exception to your version of the library, but you are not +# obligated to do so. If you do not wish to do so, delete this +# exception statement from your version. + +Parser.StdOptions=Standard options +Parser.PrintHelp=print this help, then exit +Parser.PrintVersion=print version number, then exit +Parser.JArgument=pass argument to the Java runtime +Parser.JName=OPTION +Parser.ArgReqd=option ''{0}'' requires an argument +Parser.Unrecognized=unrecognized option ''{0}'' +Parser.NoArg=option ''{0}'' doesn''t allow an argument +Parser.UnrecDash=unrecognized option ''-{0}'' +Parser.TryHelpShort=Try ''{0} -help'' for more information +Parser.TryHelpLong=Try ''{0} --help'' for more information +ClasspathToolParser.VersionFormat={0} (GNU Classpath) {1}\n\nCopyright 2006 Free Software Foundation, Inc.\nThis is free software; see the source for copying conditions. There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. diff --git a/resource/gnu/classpath/tools/jar/messages.properties b/resource/gnu/classpath/tools/jar/messages.properties new file mode 100644 index 000000000..e589a210f --- /dev/null +++ b/resource/gnu/classpath/tools/jar/messages.properties @@ -0,0 +1,71 @@ +# messages.properties -- English language messages +# Copyright (C) 2006 Free Software Foundation, Inc. +# +# This file is part of GNU Classpath. +# +# GNU Classpath is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# GNU Classpath 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 for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Classpath; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA. +# +# Linking this library statically or dynamically with other modules is +# making a combined work based on this library. Thus, the terms and +# conditions of the GNU General Public License cover the whole +# combination. +# +# As a special exception, the copyright holders of this library give you +# permission to link this library with independent modules to produce an +# executable, regardless of the license terms of these independent +# modules, and to copy and distribute the resulting executable under +# terms of your choice, provided that you also meet, for each linked +# independent module, the terms and conditions of the license of that +# module. An independent module is a module which is not derived from +# or based on this library. If you modify this library, you may extend +# this exception to your version of the library, but you are not +# obligated to do so. If you do not wish to do so, delete this +# exception statement from your version. + +Creator.Ignoring=ignoring entry {0} +Creator.Adding=adding: {0} (in={1,number,integer}) (out={2,number,integer}) (stored {3,number,integer}%) +Extractor.Created=\ \ created: {0} +Extractor.Extracted=\ extracted: {0} +Extractor.Inflated=\ \ inflated: {0} +Indexer.Indexing=indexing: {0} +Main.ArchiveAlreadySet=archive file name already set to {0} +Main.ModeAlreaySet=operation mode already specified +Main.MustSpecify=must specify one of -t, -c, -u, -x, or -i +Main.TwoArgsReqd=-C argument requires both directory and filename +Main.CantHaveBoth=can't specify both -m and -M +Main.NoFilesWithi=can't specify file arguments when using -i +Main.NoMAndi=can't specify -M with -i +Main.AnotherNomAndi=can't specify -m with -i +Main.Usage=Usage: jar -ctxui [OPTIONS] jar-file [-C DIR FILE] FILE... +Main.OpMode=Operation mode +Main.Create=create a new archive +Main.Extract=extract from archive +Main.List=list archive contents +Main.Update=update archive +Main.Index=compute archive index +Main.FileArg=FILE +Main.OpMods=Operation modifiers +Main.ArchiveName=specify archive file name +Main.FileArg2=FILE +Main.NoZip=store only; no ZIP compression +Main.Verbose=verbose operation +Main.NoManifest=do not create a manifest file +Main.ManifestName=specify manifest file +Main.ManifestArgName=FILE +Main.FileNameGroup=File name selection +Main.ChangeDir=change to directory before the next file +Main.ChangeDirArg=DIR FILE +Main.InternalError=jar: internal error: diff --git a/resource/gnu/classpath/tools/jarsigner/MessageBundle.properties b/resource/gnu/classpath/tools/jarsigner/MessageBundle.properties new file mode 100644 index 000000000..565041f21 --- /dev/null +++ b/resource/gnu/classpath/tools/jarsigner/MessageBundle.properties @@ -0,0 +1,84 @@ +# default locale messages for gnu.classpath.tools.jarsigner package + +Main.7=jarsigner: +Main.9=jarsigner error: +Main.70=JAR file [{0}] is NOT a file object +Main.72=JAR file [{0}] is NOT readable +#Main.85=Option '-keystore' is not defined or is an empty string, and 'user.home' is unknown +Main.85=Unable to locate a valid key store +Main.92=Enter key store password: +Main.6=Designated alias [{0}] MUST be known to the key store in use +Main.2=\ +Usage: jarsigner [OPTION]... FILE ALIAS\n\ +\ \ \ \ \ \ \ \ jarsigner -verify [OPTION]... FILE\n\ +Java ARchive (JAR) file signing and verification tool.\n\ +\n\ +FILE is the .JAR file to sign or to verify.\n\ +\n\ +ALIAS must be a known Alias of a Key Entry in the designated key store. The \ +private key material associated with this Alias is used for signing FILE. if \ +ALIAS is required, but was omitted, "mykey" will be used instead. +Main.1=Please report bugs at http://www.gnu.org/software/classpath/bugs.html +Main.0=Signing options +Main.95=Designated alias [{0}] MUST be an Alias of a Key Entry +Main.97=Enter key password for <{0}>: +Main.99=Key associated with [{0}] MUST be a private key +Main.101=Location of the key store to use. The default value is a file-based \ +scheme whose path is the file named ".keystore" in your home directory.\n\ +If URL is malformed, the tool will use URL as a file-name of a key store; \ +i.e. as if the protocol was "file:". +Main.102=URL +Main.104=Type of the key store to use. If omitted, the default value is that \ +of the property "keystore.type" in the security properties file. +Main.105=STORE_TYPE +Main.107=Password to unlock the key store. If omitted, you will be prompted \ +to provide a password. +Main.108=PASSWORD +Main.110=Password to unlock the Key Entry associated with ALIAS. If omitted, \ +the tool will use the same password protecting the key store. If this fails, \ +you will be prompted to provide a password. +Main.111=PASSWORD +Main.113=A literal to construct file names for both the .SF and .DSA signature \ +files --which will be placed in the META-INF directory of the signed JAR. \ +Permissible characters are in the range [a-zA-Z0-9_-].\n\ +If omitted, the first 8 characters of ALIAS will be used. Characters outside \ +that range will be replaced by underscores. +Main.114=NAME +Main.116=Name of the signed JAR file. If omitted, the signed JAR will be \ +named the same as FILE; i.e. the input file will be replaced with its signed \ +copy. +Main.117=FILE +Main.118=Verification options +Main.120=Verify an already signed FILE. +Main.122=Use with -verbose to see more detailed information about the \ +certificates of ALIAS. +Main.123=Common options +Main.125=Output more verbose messages during processing. +Main.127=Include --otherwise do not-- the .SF file in the .DSA generated file. +Main.129=Include in the .SF generated file --otherwise do not-- a header \ +containing a hash of the whole manifest file. +Main.131=Fully qualified class name of a Security Provider to add to the JVM \ +in-use. +Main.132=PROVIDER_CLASS_NAME +Main.133=Missing FILE argument. + +JarSigner.1=\ \ signing: +JarSigner.2=\ updating: +JarSigner.8=\ \ \ adding: +JarSigner.14=Jar signed. + +JarVerifier.2=Jar is not signed --no signature files found. +JarVerifier.3=Jar verification failed. +JarVerifier.4=Jar partially verified --{0,numer} of {1,number} signers. +JarVerifier.7=Jar verified --{0,number} signer(s). +JarVerifier.13=Signature Block missing for {0} +JarVerifier.14=At least one SignerInfo element MUST be present in a Signature \ +Block (.DSA file) +JarVerifier.16=Missing EncryptedDigest in Signature Block (.DSA file) first \ +SignerInfo element + +SFHelper.1=Helper is NOT finished +SFHelper.4=.SF file has NOT been generated +SFHelper.6=Unknown or unsupported private key algorithm +SFHelper.9=Helper is NOT ready +SFHelper.10=Helper is NOT started diff --git a/resource/gnu/classpath/tools/keytool/MessageBundle.properties b/resource/gnu/classpath/tools/keytool/MessageBundle.properties new file mode 100644 index 000000000..2362d6a84 --- /dev/null +++ b/resource/gnu/classpath/tools/keytool/MessageBundle.properties @@ -0,0 +1,503 @@ +# default locale messages for gnu.classpath.tools.keytool package + +Main.6=keytool: {0} +Main.8=keytool error: {0} +Main.18=Unrecognized command: {0} +Main.19=Usage: keytool [COMMAND] [-- COMMAND]...\n\ +Manage private keys and public certificates. +Main.20=Please report bugs at http://www.gnu.org/software/classpath/bugs.html +Main.21=Available commands +Main.22=Generate a Key Entry, eventually creating a key store.\n\ +[-alias ALIAS] [-keyalg ALGORITHM] [-keysize KEY_SIZE]\n\ +[-sigalg ALGORITHM] [-dname NAME] [-keypass PASSWORD]\n\ +[-validity DAY_COUNT] [-storetype STORE_TYPE]\n\ +[-keystore URL] [-storepass PASSWORD]\n\ +[-provider PROVIDER_CLASS_NAME] [-v]. +Main.23=Add Key Entries and Trusted Certificates.\n\ +[-alias ALIAS] [-file FILE] [-keypass PASSWORD]\n\ +[-noprompt] [-trustcacerts] [-storetype STORE_TYPE]\n\ +[-keystore URL] [-storepass PASSWORD]\n\ +[-provider PROVIDER_CLASS_NAME] [-v]. +Main.24=Generate a self-signed Trusted Certificate.\n\ +[-alias ALIAS] [-sigalg ALGORITHM] [-dname NAME]\n\ +[-validity DAY_COUNT] [-keypass PASSWORD]\n\ +[-storetype STORE_TYPE] [-keystore URL]\n\ +[-storepass PASSWORD] [-provider PROVIDER_CLASS_NAME] [-v]. +Main.25=NOT IMPLEMENTED YET. Import JDK1.1 Identity Database.\n\ +[-file FILE] [-storetype STORE_TYPE] [-keystore URL]\n\ +[-storepass PASSWORD] [-provider PROVIDER_CLASS_NAME] [-v]. +Main.26=Issue a Certificate Signing Request (CSR).\n\ +[-alias ALIAS] [-sigalg ALGORITHM] [-file FILE]\n\ +[-keypass PASSWORD] [-storetype STORE_TYPE] [-keystore URL]\n\ +[-storepass PASSWORD] [-provider PROVIDER_CLASS_NAME] [-v]\n\ +[-attributes]. +Main.27=Export a Certificate from a key store.\n\ +[-alias ALIAS] [-file FILE] [-storetype STORE_TYPE]\n\ +[-keystore URL] [-storepass PASSWORD]\n\ +[-provider PROVIDER_CLASS_NAME] [-rfc] [-v]. +Main.28=Print one or all Certificates in a key store to STDOUT.\n\ +[-alias ALIAS] [-storetype STORE_TYPE] [-keystore URL]\n\ +[-storepass PASSWORD] [-provider PROVIDER_CLASS_NAME] [-rfc] [-v]. +Main.29=Print a human-readable form of a Certificate in a FILE.\n\ +[-file FILE] [-v]. +Main.30=Clone a Key Entry in a key store.\n\ +[-alias ALIAS] [-dest ALIAS] [-keypass PASSWORD]\n\ +[-new PASSWORD] [-storetype STORE_TYPE] [-keystore URL]\n\ +[-storepass PASSWORD] [-provider PROVIDER_CLASS_NAME] [-v]. +Main.31=Change the password protecting a key store.\n\ +[-new PASSWORD] [-storetype STORE_TYPE] [-keystore URL]\n\ +[-storepass PASSWORD] [-provider PROVIDER_CLASS_NAME] [-v]. +Main.32=Change the password protecting a Key Entry in a key store.\n\ +[-alias ALIAS] [-keypass PASSWORD] [-new PASSWORD]\n\ +[-storetype STORE_TYPE] [-keystore URL]\n\ +[-storepass PASSWORD] [-provider PROVIDER_CLASS_NAME] [-v]. +Main.33=Delete a Key Entry or a Trusted Certificate from a key store.\n\ +[-alias ALIAS] [-storetype STORE_TYPE] [-keystore URL]\n\ +[-storepass PASSWORD] [-provider PROVIDER_CLASS_NAME] [-v]. + +Command.19=Failed creating new file at {0} +Command.20=Unable to find a suitable signature algorithm named {0}, although we found a key-pair generation algorithm named {1} +Command.21=Enter key password for <{0}>: +Command.23=A correct key password MUST be provided +Command.24=Enter key store password: +#Command.36=Option '-keystore' is undefined, or is an empty string, and 'user.home' is unknown +Command.36=Unable to locate a valid key store +Command.40=Provider fully qualified class name: +Command.42=File object [{0}] exists but is NOT a file +Command.44=File [{0}] exists but is NOT writable +Command.46=File object [{0}] MUST be an existing readable file +Command.48=Signature algorithm is missing and private key is of unknown or unsupported type +Command.51=Validity period MUST be greater than zero +Command.52=Unable to get signature algorithm name +Command.60=Unknown or unsupported signature algorithm: {0} +Command.63=Saving key store at {0} +Command.66=Owner: {0} +Command.67=Issuer: {0} +Command.68=Serial number: {0,number} +Command.69=Valid from: {0,date,full} - {0,time,full} +Command.70=\ \ \ \ \ until: {0,date,full} - {0,time,full} +Command.71=Certificate fingerprints +Command.72=\ \ \ \ \ \ MD5: {0} +Command.73=\ \ SHA-160: {0} +Command.75=Alias [{0}] MUST be knwon to the key store +Command.77=Alias [{0}] MUST be associated with a Key Entry + +CertReqCmd.27=Certification request stored in {0} +CertReqCmd.28=Submit this to your CA +CertReqCmd.25=Usage: keytool -certreq [OPTION]...\n\ +Generate a PKCS#10 Certificate Signing Request (CSR) and write it to a \ +designated output destination.\n\n\ +IMPORTANT: Some documentation claims that the Attributes field, in the CSR is \ +OPTIONAL while RFC-2986 implies the opposite. This implementation considers \ +this field, by default, as OPTIONAL, unless option -attributes is specified. +CertReqCmd.24=Please report bugs at http://www.gnu.org/software/classpath/bugs.html +CertReqCmd.23=Command options +CertReqCmd.22=Alias of an entry in the key store on whose behalf the CSR is \ +generated. The value "mykey" (all lower case, without the enclosing quotes) \ +is used when this option is omitted. +CertReqCmd.21=ALIAS +CertReqCmd.20=Name of the digital signature algorithm to use for signing the \ +certificate. If omitted, a default value is chosen based on the type of the \ +private key associated with ALIAS. If the key is a "DSA" one, the value for \ +signature algorithm will be "SHA1withDSA". If on the other hand the key is \ +an "RSA" one, then "MD5withRSA" will be the signature algorithm. +CertReqCmd.19=ALGORITHM +CertReqCmd.18=Destination of the generated CSR. STDOUT is used if this \ +option is omitted. +CertReqCmd.17=FILE +CertReqCmd.16=Password to unlock the Key Entry associated with ALIAS. If \ +omitted, the tool will attempt to unlock the Key Entry using the same password \ +protecting the key store. If this fails, you will be prompted for a password. +CertReqCmd.14=Type of the key store to use. If omitted, the default value is \ +that of the property "keystore.type" in the security properties file. +CertReqCmd.13=STORE_TYPE +CertReqCmd.12=Location of the key store to use. The default value is a \ +file-based scheme whose path is the file named ".keystore" in your home \ +directory.\n\ +If URL is malformed, the tool will use URL as a file-name of a key store; \ +i.e. as if the protocol was "file:". +CertReqCmd.11=URL +CertReqCmd.10=Password to unlock the key store. If omitted, you will be \ +prompted for one. +CertReqCmd.9=PASSWORD +CertReqCmd.8=Fully qualified class name of a Security Provider to add to the \ +JVM in-use. +CertReqCmd.7=PROVIDER_CLASS_NAME +CertReqCmd.6=Emit more verbose messages. +CertReqCmd.5=Force the tool to encode a NULL DER value in the CSR as the value \ +of the Attributes field. + +DeleteCmd.19=Enter the Alias to delete: +DeleteCmd.18=Usage: keytool -delete [OPTION]...\n\ +Delete a designated key store entry. +DeleteCmd.17=Please report bugs at http://www.gnu.org/software/classpath/bugs.html +DeleteCmd.16=Command options +DeleteCmd.15=Alias of an entry to delete. The value "mykey" (all lower case, \ +without the enclosing quotes) is used when this option is omitted. +DeleteCmd.14=ALIAS +DeleteCmd.13=Type of the key store to use. If omitted, the default value is \ +that of the property "keystore.type" in the security properties file. +DeleteCmd.12=STORE_TYPE +DeleteCmd.11=Location of the key store to use. The default value is a \ +file-based scheme whose path is the file named ".keystore" in your home \ +directory.\n\ +If URL is malformed, the tool will use URL as a file-name of a key store; \ +i.e. as if the protocol was "file:". +DeleteCmd.10=URL +DeleteCmd.20=Alias MUST NOT be null or an empty string +DeleteCmd.9=Password to unlock the key store. If omitted, you will be \ +prompted for one. +DeleteCmd.8=PASSWORD +DeleteCmd.7=Fully qualified class name of a Security Provider to add to the \ +JVM in-use. +DeleteCmd.6=PROVIDER_CLASS_NAME +DeleteCmd.5=Emit more verbose messages. + +GenKeyCmd.0=\nYou are about to enter information that will be incorporated into\n\ +your certificate request. This information is what is called a\n\ +Distinguished Name or DN. There are quite a few fields but you\n\ +can use supplied default values, displayed between brackets, by just\n\ +hitting <Enter>, or blank the field by entering the <.> character\n\ +before hitting <Enter>.\n\n +GenKeyCmd.6=The Sample Company +GenKeyCmd.7=Sydney +GenKeyCmd.8=NSW +GenKeyCmd.9=AU +GenKeyCmd.10=Common Name (hostname, IP, or your name): +GenKeyCmd.11=Organization Name (company) [{0}]: +GenKeyCmd.13=Organizational Unit Name (department, division): +GenKeyCmd.14=Locality Name (city, district) [{0}]: +GenKeyCmd.16=State or Province Name (full name) [{0}]: +GenKeyCmd.18=Country Name (2 letter code) [{0}]: +GenKeyCmd.54=Key size MUST be greater than zero +GenKeyCmd.57=Usage: keytool -genkey [OPTION]...\n\ +Generate a new key-pair and save these credentials in the key store as a Key \ +Entry, associated with a designated Alias. +GenKeyCmd.58=Please report bugs at http://www.gnu.org/software/classpath/bugs.html +GenKeyCmd.59=Command options +GenKeyCmd.60=Alias of the Key Entry to generate. The value "mykey" (all lower \ +case, without the enclosing quotes) is used when this option is omitted. +GenKeyCmd.61=ALIAS +GenKeyCmd.62=Name of the key-pair generation algorithm. The default value is \ +"DSS" (a synonym for the Digital Signature Algorithm also known as DSA). +GenKeyCmd.63=ALGORITHM +GenKeyCmd.64=Number of bits of the shared modulus, for both the public and \ +private keys, to use for the new keys. If omitted, 1024 is used. +GenKeyCmd.65=SIZE +GenKeyCmd.66=Name of the digital signature algorithm to use for signing the \ +certificate. If omitted, a default value is chosen based on the type of the \ +private key associated with ALIAS. If the key is a "DSA" one, the value for \ +signature algorithm will be "SHA1withDSA". If on the other hand the key is \ +an "RSA" one, then "MD5withRSA" will be the signature algorithm. +GenKeyCmd.68=The X.500 Distinguished Name of the Subject of the generated \ +certificate. If omitted you will be prompted for one. +GenKeyCmd.69=NAME +GenKeyCmd.70=Password to protect the newly created Key Entry. If omitted, \ +you will be prompted to provide a password. +GenKeyCmd.71=PASSWORD +GenKeyCmd.72=Number of days the generated certificate is valid for. If \ +omitted, 90 is used. +GenKeyCmd.73=DAY_COUNT +GenKeyCmd.74=Type of the key store to use. If omitted, the default value is \ +that of the property "keystore.type" in the security properties file. +GenKeyCmd.75=STORE_TYPE +GenKeyCmd.76=Location of the key store to use. The default value is a \ +file-based scheme whose path is the file named ".keystore" in your home \ +directory.\n\ +If URL is malformed, the tool will use URL as a file-name of a key store; \ +i.e. as if the protocol was "file:". +GenKeyCmd.77=URL +GenKeyCmd.78=Password to unlock the key store. If omitted, you will be \ +prompted for one. +GenKeyCmd.80=Fully qualified class name of a Security Provider to add to the \ +JVM in-use. +GenKeyCmd.81=PROVIDER_CLASS_NAME +GenKeyCmd.82=Emit more verbose messages. + +StorePasswdCmd.19=Too many failed attempts +StorePasswdCmd.18=Usage: keytool -storepasswd [OPTION]...\n\ +Change the password protecting a key store. +StorePasswdCmd.17=Please report bugs at http://www.gnu.org/software/classpath/bugs.html +StorePasswdCmd.16=Command options +StorePasswdCmd.15=The new, and different, password to protect the key store. \ +If omitted, you will be prompted for one. +StorePasswdCmd.13=Type of the key store to use. If omitted, the default value is \ +that of the property "keystore.type" in the security properties file. +StorePasswdCmd.12=STORE_TYPE +StorePasswdCmd.11=Location of the key store to use. The default value is a \ +file-based scheme whose path is the file named ".keystore" in your home \ +directory.\n\ +If URL is malformed, the tool will use URL as a file-name of a key store; \ +i.e. as if the protocol was "file:". +StorePasswdCmd.10=URL +StorePasswdCmd.20=Enter new key store password: +StorePasswdCmd.21=Password MUST be at least 6 characters. +StorePasswdCmd.22=New password MUST be different than the old one. +StorePasswdCmd.23=Re-enter new key store password: +StorePasswdCmd.24=Passwords MUST be the same in both attempts. +StorePasswdCmd.9=Password to unlock the key store. If omitted, you will be \ +prompted for one. +StorePasswdCmd.8=PASSWORD +StorePasswdCmd.7=Fully qualified class name of a Security Provider to add to the \ +JVM in-use. +StorePasswdCmd.6=PROVIDER_CLASS_NAME +StorePasswdCmd.5=Emit more verbose messages. + +KeyPasswdCmd.24=Enter new key password for <{0}>: +KeyPasswdCmd.28=Re-enter new key password for <{0}>: +KeyPasswdCmd.23=Usage: keytool -keypasswd [OPTION]...\n\ +Change the password protecting a Key Entry. +KeyPasswdCmd.22=Please report bugs at http://www.gnu.org/software/classpath/bugs.html +KeyPasswdCmd.21=Command options +KeyPasswdCmd.20=The Alias which password is to be changed. +KeyPasswdCmd.19=ALIAS +KeyPasswdCmd.18=Password to unlock ALIAS. If omitted, the tool will attempt \ +to unlock the Key Entry using the same password protecting the key store. If \ +this fails, you will be prompted for a password. +KeyPasswdCmd.16=The new, and different, password to protect ALIAS. +KeyPasswdCmd.14=Type of the key store to use. If omitted, the default value is \ +that of the property "keystore.type" in the security properties file. +KeyPasswdCmd.13=STORE_TYPE +KeyPasswdCmd.12=Location of the key store to use. The default value is a \ +file-based scheme whose path is the file named ".keystore" in your home \ +directory.\n\ +If URL is malformed, the tool will use URL as a file-name of a key store; \ +i.e. as if the protocol was "file:". +KeyPasswdCmd.11=URL +KeyPasswdCmd.10=Password to unlock the key store. If omitted, you will be \ +prompted for one. +KeyPasswdCmd.9=PASSWORD +KeyPasswdCmd.8=Fully qualified class name of a Security Provider to add to the \ +JVM in-use. +KeyPasswdCmd.7=PROVIDER_CLASS_NAME +KeyPasswdCmd.6=Emit more verbose messages. + +KeyCloneCmd.23=Destination Alias MUST NOT exist in key store +KeyCloneCmd.26=Enter destination alias: +KeyCloneCmd.27=Destination alias MUST NOT be null nor empty +KeyCloneCmd.28=Enter new key password for <{0}> [{1}]: +KeyCloneCmd.22=Usage: keytool -keyclone [OPTION]...\n\ +Clone an existing Key Entry and store it under a new (different) Alias \ +protecting its private key material with possibly a new password. +KeyCloneCmd.21=Please report bugs at http://www.gnu.org/software/classpath/bugs.html +KeyCloneCmd.20=Command options +KeyCloneCmd.19=Alias of an entry to clone. The value "mykey" (all lower case, \ +without the enclosing quotes) is used when this option is omitted. +KeyCloneCmd.17=Alias to identify the cloned copy of the Key Entry. +KeyCloneCmd.16=ALIAS +KeyCloneCmd.15=Password to unlock the Key Entry associated with the Alias to \ +clone. If omitted, the tool will attempt to unlock the Key Entry using the \ +same password protecting the key store. If this fails, you will be prompted \ +for a password. +KeyCloneCmd.13=Password to protect the cloned copy of the Key Entry. If \ +omitted, you will be prompted to provide one. +KeyCloneCmd.11=Type of the key store to use. If omitted, the default value is \ +that of the property "keystore.type" in the security properties file. +KeyCloneCmd.10=STORE_TYPE +KeyCloneCmd.9=Location of the key store to use. The default value is a \ +file-based scheme whose path is the file named ".keystore" in your home \ +directory.\n\ +If URL is malformed, the tool will use URL as a file-name of a key store; \ +i.e. as if the protocol was "file:". +KeyCloneCmd.8=URL +KeyCloneCmd.7=Password to unlock the key store. If omitted, you will be \ +prompted for one. +KeyCloneCmd.6=PASSWORD +KeyCloneCmd.5=Fully qualified class name of a Security Provider to add to the \ +JVM in-use. +KeyCloneCmd.4=PROVIDER_CLASS_NAME +KeyCloneCmd.3=Emit more verbose messages. + +ListCmd.21=Key store type: {0} +ListCmd.22=Key store provider: {0} +ListCmd.24=Key store contains {0,number} entry(ies) +ListCmd.20=Usage: keytool -list [OPTION]...\n\ +Print one or all of the key store entries to STDOUT. Usually this command \ +will only print a fingerprint of the certificate, unless either -rfc or -v \ +is specified. +ListCmd.30=Alias name: {0} +ListCmd.31=Creation timestamp: {0,date,full} - {0,time,full} +ListCmd.32=Entry type: trusted-certificate +ListCmd.33=Entry type: key-entry +ListCmd.34=Alias [{0}] is unknown to the key store +ListCmd.38=Certificate chain length: {0,number} +ListCmd.39=Certificate[1]: +ListCmd.40=Certificate[{0,number}]: +ListCmd.42=******************************************* +ListCmd.43=-----BEGIN CERTIFICATE----- +ListCmd.44=-----END CERTIFICATE----- +ListCmd.45=Certificate fingerprint (MD5): {0} +ListCmd.19=Please report bugs at http://www.gnu.org/software/classpath/bugs.html +ListCmd.18=Command options +ListCmd.17=Alias of an entry to list. If omitted, all entries are listed. +ListCmd.16=ALIAS +ListCmd.15=Type of the key store to use. If omitted, the default value is \ +that of the property "keystore.type" in the security properties file. +ListCmd.14=STORE_TYPE +ListCmd.13=Location of the key store to use. The default value is a \ +file-based scheme whose path is the file named ".keystore" in your home \ +directory.\n\ +If URL is malformed, the tool will use URL as a file-name of a key store; \ +i.e. as if the protocol was "file:". +ListCmd.12=URL +ListCmd.11=Password to unlock the key store. If omitted, you will be \ +prompted for one. +ListCmd.10=PASSWORD +ListCmd.9=Fully qualified class name of a Security Provider to add to the \ +JVM in-use. +ListCmd.8=PROVIDER_CLASS_NAME +ListCmd.7=Output the certificate in human-readable format, even if -rfc is \ +also specified. +ListCmd.6=Use RFC-1421 specifications when encoding the output. + +ImportCmd.34=Failed to establish chain-of-trust from reply +ImportCmd.37=Unable to find anchor certificate for {0} +ImportCmd.38=Public keys, in key store and certificate, MUST be of the same type +ImportCmd.32=Can this certificate be trusted? +ImportCmd.40=Key entry associated with {0} has an unknown or unsupported public key type {1} +ImportCmd.41=Public keys, in key store and certificate, MUST be the same +ImportCmd.29=Certificate was added to the key store +ImportCmd.28=Certificate was not added to the key store +ImportCmd.27=Usage: keytool -import [OPTION]...\n\ +Read an X.509 certificate, or a PKCS#7 Certificate Reply from a designated \ +input source and incorporate the certificates into the key store. +ImportCmd.26=Please report bugs at http://www.gnu.org/software/classpath/bugs.html +ImportCmd.25=Command options +ImportCmd.24=If ALIAS does not already exist in the key store, the tool treats \ +the certificate in FILE as a new Trusted Certificate.\n\ +If ALIAS exists in the key store, the tool will treat the certificate(s) in \ +FILE as a Certificate Reply (which can be a chain of certificates). +ImportCmd.23=ALIAS +ImportCmd.22=Location of the Certificate or Certificate Reply to import. +ImportCmd.21=FILE +ImportCmd.20=Password to protect the Key Entry associated with ALIAS. If \ +this option is omitted, and the chain-of-trust for the Certificate Reply has \ +been established, the tool will first attempt to unlock the Key Entry using \ +the same password protecting the key store. If this fails, you will be \ +prompted to provide a password. +ImportCmd.19=PASSWORD +ImportCmd.18=Prevent the tool from prompting the user. +ImportCmd.17=Additionally use a key store, of type "JKS", named "cacerts", \ +and located in lib/security in an installed Java Runtime Environment, when \ +trying to establish chains-of-trust. +ImportCmd.16=Type of the key store to use. If omitted, the default value is \ +that of the property "keystore.type" in the security properties file. +ImportCmd.15=STORE_TYPE +ImportCmd.14=Location of the key store to use. The default value is a \ +file-based scheme whose path is the file named ".keystore" in your home \ +directory.\n\ +If URL is malformed, the tool will use URL as a file-name of a key store; \ +i.e. as if the protocol was "file:". +ImportCmd.13=URL +ImportCmd.12=Password to unlock the key store. If omitted, you will be \ +prompted for one. +ImportCmd.11=PASSWORD +ImportCmd.10=Fully qualified class name of a Security Provider to add to the \ +JVM in-use. +ImportCmd.9=PROVIDER_CLASS_NAME +ImportCmd.8=Emit more verbose messages. + +ExportCmd.17=Usage: keytool -export [OPTION]...\n\ +Export a certificate stored in the key store to a designated output \ +destination, either in binary format or in RFC-1421 compliant encoding. +ExportCmd.18=Please report bugs at http://www.gnu.org/software/classpath/bugs.html +ExportCmd.19=Command options +ExportCmd.20=Alias of an entry to export. The value "mykey" (all lower case, \ +without the enclosing quotes) is used when this option is omitted. +ExportCmd.21=ALIAS +ExportCmd.22=Destination of the exported certificate. STDOUT is used if this \ +option is omitted. +ExportCmd.23=FILE +ExportCmd.24=Type of the key store to use. If omitted, the default value is \ +that of the property "keystore.type" in the security properties file. +ExportCmd.25=STORE_TYPE +ExportCmd.26=Location of the key store to use. The default value is a \ +file-based scheme whose path is the file named ".keystore" in your home \ +directory.\n\ +If URL is malformed, the tool will use URL as a file-name of a key store; \ +i.e. as if the protocol was "file:". +ExportCmd.27=URL +ExportCmd.28=Password to unlock the key store. If omitted, you will be \ +prompted for one. +ExportCmd.29=PASSWORD +ExportCmd.30=Fully qualified class name of a Security Provider to add to the \ +JVM in-use. +ExportCmd.31=PROVIDER_CLASS_NAME +ExportCmd.32=Use RFC-1421 specifications when encoding the output. +ExportCmd.33=Output the certificate in binary DER encoding, which is the \ +default format. If -rfc is also present, this option is ignored. + +IdentityDBCmd.7=Usage: keytool -identitydb [OPTION]...\n\ +NOT IMPLEMENTED YET. Import a JDK 1.1 style Identity Database. +IdentityDBCmd.8=Please report bugs at http://www.gnu.org/software/classpath/bugs.html +IdentityDBCmd.9=Command options +IdentityDBCmd.10=Location of the Identity Database to import. If omitted, \ +STDIN is used. +IdentityDBCmd.11=FILE +IdentityDBCmd.12=Type of the key store to use. If omitted, the default value is \ +that of the property "keystore.type" in the security properties file. +IdentityDBCmd.13=STORE_TYPE +IdentityDBCmd.14=Location of the key store to use. The default value is a \ +file-based scheme whose path is the file named ".keystore" in your home \ +directory.\n\ +If URL is malformed, the tool will use URL as a file-name of a key store; \ +i.e. as if the protocol was "file:". +IdentityDBCmd.15=URL +IdentityDBCmd.16=Password to unlock the key store. If omitted, you will be \ +prompted for one. +IdentityDBCmd.17=PASSWORD +IdentityDBCmd.18=Fully qualified class name of a Security Provider to add to the \ +JVM in-use. +IdentityDBCmd.19=PROVIDER_CLASS_NAME +IdentityDBCmd.20=Emit more verbose messages. + +PrintCertCmd.5=Usage: keytool -printcert [OPTION]...\n\ +Read a certificate from FILE and print it to STDOUT in a human-readable form. +PrintCertCmd.6=Please report bugs at http://www.gnu.org/software/classpath/bugs.html +PrintCertCmd.7=Command options +PrintCertCmd.8=Location of the certificate to print. If omitted, STDIN is used. +PrintCertCmd.9=FILE +PrintCertCmd.10=Emit more verbose messages. + +SelfCertCmd.14=Usage: keytool -selfcert [OPTION]...\n\ +Generate a self-signed X.509 version 1 certificate.\n\n\ +The newly generated certificate will form a chain of one element which will \ +replace the previous chain associated with ALIAS. +SelfCertCmd.15=Please report bugs at http://www.gnu.org/software/classpath/bugs.html +SelfCertCmd.16=Command options +SelfCertCmd.17=Alias of the Key Entry to select. The value "mykey" (all lower \ +case, without the enclosing quotes) is used when this option is omitted. +SelfCertCmd.18=ALIAS +SelfCertCmd.19=Name of the digital signature algorithm to use for signing the \ +certificate. If omitted, a default value is chosen based on the type of the \ +private key associated with ALIAS. If the key is a "DSA" one, the value for \ +signature algorithm will be "SHA1withDSA". If on the other hand the key is \ +an "RSA" one, then "MD5withRSA" will be the signature algorithm. +SelfCertCmd.20=ALGORITHM +SelfCertCmd.21=The X.500 Distinguished Name of the Subject of the generated \ +certificate. If omitted the Distinguished Name of the base certificate in \ +the chain associated with ALIAS is used instead. +SelfCertCmd.22=NAME +SelfCertCmd.23=Password to unlock the Key Entry associated with ALIAS. If \ +omitted, the tool will attempt to unlock the Key Entry using the same password \ +protecting the key store. If this fails, you will be prompted for a password. +SelfCertCmd.24=PASSWORD +SelfCertCmd.25=Number of days the generated certificate is valid for. If \ +omitted, 90 is used. +SelfCertCmd.26=DAY_COUNT +SelfCertCmd.27=Type of the key store to use. If omitted, the default value is \ +that of the property "keystore.type" in the security properties file. +SelfCertCmd.28=STORE_TYPE +SelfCertCmd.29=Location of the key store to use. The default value is a \ +file-based scheme whose path is the file named ".keystore" in your home \ +directory.\n\ +If URL is malformed, the tool will use URL as a file-name of a key store; \ +i.e. as if the protocol was "file:". +SelfCertCmd.30=URL +SelfCertCmd.31=Password to unlock the key store. If omitted, you will be \ +prompted for one. +SelfCertCmd.32=PASSWORD +SelfCertCmd.33=Fully qualified class name of a Security Provider to add to the \ +JVM in-use. +SelfCertCmd.34=PROVIDER_CLASS_NAME +SelfCertCmd.35=Emit more verbose messages. diff --git a/tools/.cvsignore b/tools/.cvsignore index 4bbf2266e..cf3688511 100644 --- a/tools/.cvsignore +++ b/tools/.cvsignore @@ -1,5 +1,6 @@ -jarsigner.sh -keytool.sh +jarsigner +keytool Makefile.in Makefile tools.zip +appletviewer diff --git a/tools/Makefile.am b/tools/Makefile.am index 5a47d18e4..cd69bc04f 100755 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -13,6 +13,9 @@ error dunno how to setup the JCOMPILER and compile endif endif +bin_SCRIPTS = appletviewer jarsigner keytool +EXTRA_DIST = appletviewer.in appletviewer.c jarsigner.in keytool.in + # All our example java source files TOOLS_JAVA_FILES = $(srcdir)/gnu/classpath/tools/*.java $(srcdir)/gnu/classpath/tools/*/*.java $(srcdir)/gnu/classpath/tools/*/*/*.java @@ -24,7 +27,7 @@ TOOLS_ZIP = tools.zip BUILT_SOURCES = $(TOOLS_ZIP) # The templates that must be included into the generated zip file. -GRMIC_TEMPLATES = $(srcdir)/gnu/classpath/tools/giop/grmic/templates/*.jav +GRMIC_TEMPLATES = $(srcdir)/gnu/classpath/tools/giop/grmic/templates/*.jav RMIC_TEMPLATES = $(srcdir)/gnu/classpath/tools/rmi/rmic/templates/*.jav TOOLS_TEMPLATES = $(GRMIC_TEMPLATES) $(RMIC_TEMPLATES) @@ -68,11 +71,14 @@ dist-hook: $(TOOLS_ZIP): $(TOOLS_JAVA_FILES) mkdir -p classes/gnu/classpath/tools/giop/grmic/templates mkdir -p classes/gnu/classpath/tools/rmi/rmic/templates + mkdir -p classes/gnu/classpath/tools/appletviewer + mkdir -p classes/gnu/classpath/tools/jarsigner + mkdir -p classes/gnu/classpath/tools/keytool cp $(RMIC_TEMPLATES) classes/gnu/classpath/tools/rmi/rmic/templates - cp $(GRMIC_TEMPLATES) classes/gnu/classpath/tools/giop/grmic/templates + cp $(GRMIC_TEMPLATES) classes/gnu/classpath/tools/giop/grmic/templates cp $(RMI_HELPS) classes/gnu/classpath/tools/rmi/ cp $(GIOP_HELPS) classes/gnu/classpath/tools/giop/ - $(JCOMPILER) -d classes $(TOOLS_JAVA_FILES) + $(JCOMPILER) -d classes $(TOOLS_JAVA_FILES) (cd classes; \ if test "$(ZIP)" != ""; then $(ZIP) -r ../$(TOOLS_ZIP) .; fi; \ if test "$(FASTJAR)" != ""; then $(FASTJAR) cf ../$(TOOLS_ZIP) .; fi; \ diff --git a/tools/appletviewer.c b/tools/appletviewer.c new file mode 100644 index 000000000..2609ccaf6 --- /dev/null +++ b/tools/appletviewer.c @@ -0,0 +1,235 @@ +/* appletviewer.c -- a native appletviewer wrapper for VMs that + support the JNI invocation interface + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +#include <jni.h> +#include <glib.h> +#include <string.h> +#include <stdlib.h> +#include "config.h" + +#ifndef JNI_VERSION_1_2 +# error JNI version 1.2 or greater required +#endif + +union env_union +{ + void *void_env; + JNIEnv *jni_env; +}; + +int +main (int argc, const char** argv) +{ + union env_union tmp; + JNIEnv* env; + JavaVM* jvm; + JavaVMInitArgs vm_args; + jint result; + jclass class_id; + jmethodID method_id; + jstring str; + jclass string_class_id; + jobjectArray args_array; + char** non_vm_argv; + int non_vm_argc; + int i; + int classpath_found = 0; + + env = NULL; + jvm = NULL; + + vm_args.nOptions = 0; + vm_args.options = NULL; + + non_vm_argc = 0; + non_vm_argv = NULL; + + if (argc > 1) + { + for (i = 1; i < argc; i++) + { + if (!strncmp (argv[i], "-J", 2)) + { + if (!strncmp (argv[i], "-J-Djava.class.path=", 20)) + classpath_found = 1; + + /* A virtual machine option. */ + vm_args.options = (JavaVMOption*) realloc (vm_args.options, (vm_args.nOptions + 1) * sizeof (JavaVMOption)); + + if (vm_args.options == NULL) + { + g_printerr ("appletviewer: realloc failed.\n"); + goto destroy; + } + + if (strlen (argv[i]) == 2) + { + g_printerr ("appletviewer: the -J option must not be followed by a space.\n"); + goto destroy; + } + else + vm_args.options[vm_args.nOptions++].optionString = g_strdup (argv[i] + 2); + } + else if (!strncmp (argv[i], "--version", 9) + && argv[i][9] == '\0') + { + g_print ("appletviewer (GCJ Applet Viewer) " PACKAGE_VERSION "\n"); + exit (0); + } + else if (!strncmp (argv[i], "-debug", 6) + && argv[i][6] == '\0') + { + /* FIXME: Ignore for now. The debug option will be + unsupported until we have the ability to debug + bytecode. For now, just strip it out of the argument + list. */ + } + else + { + non_vm_argv = (char**) realloc (non_vm_argv, (non_vm_argc + 1) * sizeof (char*)); + if (non_vm_argv == NULL) + { + g_printerr ("appletviewer: realloc failed.\n"); + goto destroy; + } + non_vm_argv[non_vm_argc++] = g_strdup (argv[i]); + } + } + } + + if (!classpath_found) + { + /* Set the invocation classpath. */ + vm_args.options = (JavaVMOption*) realloc (vm_args.options, (vm_args.nOptions + 1) * sizeof (JavaVMOption)); + + if (vm_args.options == NULL) + { + g_printerr ("appletviewer: realloc failed.\n"); + goto destroy; + } + + vm_args.options[vm_args.nOptions++].optionString = "-Djava.class.path=" "@datadir@/@PACKAGE@/tools.zip"; + } + + /* Terminate vm_args.options with a NULL element. */ + vm_args.options = (JavaVMOption*) realloc (vm_args.options, (vm_args.nOptions + 1) * sizeof (JavaVMOption)); + if (vm_args.options == NULL) + { + g_printerr ("appletviewer: realloc failed.\n"); + goto destroy; + } + vm_args.options[vm_args.nOptions].optionString = NULL; + + /* Terminate non_vm_argv with a NULL element. */ + non_vm_argv = (char**) realloc (non_vm_argv, (non_vm_argc + 1) * sizeof (char*)); + if (non_vm_argv == NULL) + { + g_printerr ("appletviewer: realloc failed.\n"); + goto destroy; + } + non_vm_argv[non_vm_argc] = NULL; + + vm_args.version = JNI_VERSION_1_2; + vm_args.ignoreUnrecognized = JNI_TRUE; + + result = JNI_CreateJavaVM (&jvm, &tmp.void_env, &vm_args); + + if (result < 0) + { + g_printerr ("appletviewer: couldn't create virtual machine\n"); + goto destroy; + } + + env = tmp.jni_env; + + string_class_id = (*env)->FindClass (env, "java/lang/String"); + if (string_class_id == NULL) + { + g_printerr ("appletviewer: FindClass failed.\n"); + goto destroy; + } + + args_array = (*env)->NewObjectArray (env, non_vm_argc, string_class_id, NULL); + if (args_array == NULL) + { + g_printerr ("appletviewer: NewObjectArray failed.\n"); + goto destroy; + } + + for (i = 0; i < non_vm_argc; i++) + { + str = (*env)->NewStringUTF (env, non_vm_argv[i]); + if (str == NULL) + { + g_printerr ("appletviewer: NewStringUTF failed.\n"); + goto destroy; + } + + (*env)->SetObjectArrayElement (env, args_array, i, str); + } + + class_id = (*env)->FindClass (env, "gnu/classpath/tools/appletviewer/Main"); + if (class_id == NULL) + { + g_printerr ("appletviewer: FindClass failed.\n"); + goto destroy; + } + + method_id = (*env)->GetStaticMethodID (env, class_id, "main", "([Ljava/lang/String;)V"); + + if (method_id == NULL) + { + g_printerr ("appletviewer: GetStaticMethodID failed.\n"); + goto destroy; + } + + (*env)->CallStaticVoidMethod (env, class_id, method_id, args_array); + + destroy: + + if (env != NULL) + { + if ((*env)->ExceptionOccurred (env)) + (*env)->ExceptionDescribe (env); + + if (jvm != NULL) + (*jvm)->DestroyJavaVM (jvm); + } + + return 1; +} diff --git a/tools/appletviewer.in b/tools/appletviewer.in new file mode 100644 index 000000000..81e39ad91 --- /dev/null +++ b/tools/appletviewer.in @@ -0,0 +1,46 @@ +#!/bin/sh + +## Copyright (C) 2006 Free Software Foundation, Inc. +## +## This file is a part of GNU Classpath. +## +## GNU Classpath is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or (at +## your option) any later version. +## +## GNU Classpath 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 for more details. +## +## You should have received a copy of the GNU General Public License +## along with GNU Classpath; if not, write to the Free Software +## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +## USA. +## +## Linking this library statically or dynamically with other modules is +## making a combined work based on this library. Thus, the terms and +## conditions of the GNU General Public License cover the whole +## combination. +## +## As a special exception, the copyright holders of this library give you +## permission to link this library with independent modules to produce an +## executable, regardless of the license terms of these independent +## modules, and to copy and distribute the resulting executable under +## terms of your choice, provided that you also meet, for each linked +## independent module, the terms and conditions of the license of that +## module. An independent module is a module which is not derived from +## or based on this library. If you modify this library, you may extend +## this exception to your version of the library, but you are not +## obligated to do so. If you do not wish to do so, delete this +## exception statement from your version. +## +## A simple shell script to launch the GNU Classpath appletviewer tool. +## + +prefix=@prefix@ +tools_dir=@datadir@/@PACKAGE@ +tools_cp=${tools_dir}/tools.zip + +exec @VM_BINARY@ -Xbootclasspath/p:"${tools_cp}" gnu.classpath.tools.appletviewer.Main $@ diff --git a/tools/gnu/classpath/tools/appletviewer/AppletClassLoader.java b/tools/gnu/classpath/tools/appletviewer/AppletClassLoader.java new file mode 100644 index 000000000..dfbedfe36 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/AppletClassLoader.java @@ -0,0 +1,81 @@ +/* AppletClassLoader -- a loader for applet classes + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.classpath.tools.appletviewer; + +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; + +public class AppletClassLoader extends URLClassLoader +{ + /** + * Constructs a new <code>AppletLoader</code> object. + * + * @param codebase the codebase of the applet + * @param archives the urls to add to the search path + */ + public AppletClassLoader(URL codebase, ArrayList archives) + { + super(new URL[0]); + + for (int count = 0; count < archives.size(); count++) + addURL((URL) archives.get(count)); + + addURL(codebase); + } + + /** + * Finds the specified class. This method should be overridden by + * class loader implementations that follow the delegation model for + * loading classes, and will be invoked by the loadClass method after + * checking the parent class loader for the requested class. The default + * implementation throws a ClassNotFoundException. + * + * (description copied from java.lang.ClassLoader.findClass(String)) + * + * @param name The name of the class. + * + * @return the resulting <code>Class</code> object. + * + * @exception ClassNotFoundException if the class is not found. + */ + protected Class findClass(String name) throws ClassNotFoundException + { + return super.findClass(name); + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/AppletSecurityManager.java b/tools/gnu/classpath/tools/appletviewer/AppletSecurityManager.java new file mode 100644 index 000000000..32ab31639 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/AppletSecurityManager.java @@ -0,0 +1,95 @@ +/* AppletSecurityManager.java -- an applet security manager + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.classpath.tools.appletviewer; + +import java.io.FilePermission; +import java.net.SocketPermission; +import java.security.Permission; +import java.security.SecurityPermission; +import java.util.PropertyPermission; + +class AppletSecurityManager extends SecurityManager +{ + private boolean plugin; + + AppletSecurityManager(boolean plugin) + { + this.plugin = plugin; + } + + public void checkPermission(Permission permission) + { + if (permission == null) + throw new NullPointerException(); + + // FIXME: we need to restrict this. + // + // libgcj asks for "java.io.FilePermission <<ALL FILES>> execute" + // to be able to execute "addr2line" to get proper stack traces. + if (permission instanceof FilePermission) + return; + + // FIXME: we need to restrict this. + if (permission instanceof SecurityPermission) + return; + + // FIXME: is this really needed ? + if (permission instanceof PropertyPermission) + return; + + // Needed to allow to access AWT event queue. + if (permission.getName().equals("accessEventQueue")) + return; + + // Needed to create a class loader for each codebase. + if (permission.getName().equals("createClassLoader")) + return; + + // FIXME: we need to allow access to codebase here. + + if (permission instanceof SocketPermission // for net access + || permission instanceof RuntimePermission) // for checkWrite(FileDescriptor) + return; + + if (! plugin && permission.getName().equals("exitVM")) + return; + + // Reject all other permissions. + throw new SecurityException(); + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/AppletTag.java b/tools/gnu/classpath/tools/appletviewer/AppletTag.java new file mode 100644 index 000000000..b2d7ccb2b --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/AppletTag.java @@ -0,0 +1,485 @@ +/* AppletTag.java -- a representation of an HTML APPLET tag + Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.classpath.tools.appletviewer; + +import gnu.xml.dom.html2.DomHTMLAppletElement; +import gnu.xml.dom.html2.DomHTMLEmbedElement; +import gnu.xml.dom.html2.DomHTMLObjectElement; + +import java.awt.Dimension; +import java.awt.Toolkit; + +import java.io.File; + +import java.net.MalformedURLException; +import java.net.URL; + +import java.text.NumberFormat; +import java.text.ParseException; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Locale; + +/** + * @author Lillian Angel (langel@redhat.com) + * @author Thomas Fitzsimmons (fitzsim@redhat.com) + */ +class AppletTag +{ + + /** + * The document base of this applet. + */ + URL documentbase; + + /** + * name of applet tag. + */ + String name = ""; + + /** + * code of applet tag. + */ + String code = ""; + + /** + * codebase of applet tag. + */ + String codebase = ""; + + /** + * The archives. + */ + ArrayList archives = new ArrayList(); + + /** + * The parameters. + */ + HashMap parameters = new HashMap(); + + /** + * The screen size. + */ + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + + /** + * Default constructor. + */ + AppletTag() + { + // Do nothing. + } + + /** + * Constructs an AppletTag and parses the given applet element. + * + * @param appElement - the Applet element to parse. + */ + AppletTag(DomHTMLAppletElement appElement) + { + name = appElement.getName(); + parameters.put("name", name); + + parameters.put("object", appElement.getObject()); + parameters.put("align", appElement.getAlign()); + parameters.put("alt", appElement.getAlt()); + parameters.put("height", appElement.getHeight()); + parameters.put("hspace", Integer.toString(appElement.getHspace())); + parameters.put("vspace", Integer.toString(appElement.getVspace())); + parameters.put("width", appElement.getWidth()); + + TagParser.parseParams(appElement, this); + + if (code.equals("")) + { + code = appElement.getCode(); + if (code.equals("")) + code = appElement.getCls(); + } + + // Must initialize codebase before archives + if (codebase.equals("")) + { + codebase = appElement.getCodeBase(); + if (codebase.equals("")) + codebase = appElement.getSrc(); + } + + if (archives.size() == 0) + { + String arcs = ""; + String arch = appElement.getArchive(); + + if (code.indexOf(".") < 0) + arcs = code + ".jar"; + + if (!arch.equals("")) + arcs += "," + arch; + + if (!arcs.equals("")) + archives = TagParser.parseArchives(arcs, this); + } + } + + /** + * Constructs an AppletTag and parses the given embed element. + * + * @param embElement - the Embed element to parse. + */ + AppletTag(DomHTMLEmbedElement embElement) + { + // In an EMBED tag, a parameter is any non-standard attribute. This + // is a problem for applets that take parameters named "code", + // "codebase", "archive", "object", or "type". The solution is to + // allow the same attributes, prefixed by "java_". The presence of + // a "java_" attribute indicates that the non-prefixed attribute + // should be interpreted as a parameter. For example if "java_code" + // and "code" attributes are present in the EMBED tag then the + // "code" attribute is interpreted as a parameter. + + name = embElement.getName(); + parameters.put("name", name); + + String jobj = embElement.getJavaObject(); + if (!jobj.equals("")) + parameters.put("java_object", jobj); + else + parameters.put("object", embElement.getObject()); + + parameters.put("width", embElement.getWidth()); + parameters.put("height", embElement.getHeight()); + parameters.put("align", embElement.getAlign()); + parameters.put("alt", embElement.getAlt()); + parameters.put("hspace", Integer.toString(embElement.getHspace())); + parameters.put("mayscript", embElement.getMayscript()); + parameters.put("pluginspage", embElement.getPluginsPage()); + parameters.put("title", embElement.getTitle()); + parameters.put("type", embElement.getType()); + parameters.put("java_type", embElement.getJavaType()); + parameters.put("vspace", Integer.toString(embElement.getVspace())); + + TagParser.parseParams(embElement, this); + + // Must initialize codebase before archives + if (codebase.equals("")) + { + String javacb = embElement.getJavaCodeBase(); + if (!javacb.equals("")) + codebase = javacb; + else + codebase = embElement.getCodeBase(); + } + + if (code.equals("")) + { + String jcode = embElement.getJavaCode(); + if (!jcode.equals("")) + code = jcode; + else + code = embElement.getCode(); + } + + if (archives.size() == 0) + { + String arcs = ""; + String jarch = embElement.getJavaArchive(); + String arch = embElement.getArchive(); + + if (code.indexOf(".") < 0) + arcs = code + ".jar"; + + if (!jarch.equals("")) + arcs += "," + jarch; + else if (!arch.equals("")) + arcs += "," + arch; + + if (!arcs.equals("")) + archives = TagParser.parseArchives(arcs, this); + } + } + + /** + * Constructs an AppletTag and parses the given object element. + * + * @param objElement - the Object element to parse. + */ + AppletTag(DomHTMLObjectElement objElement) + { + // In an OBJECT tag, a parameter is any non-standard attribute. This + // is a problem for applets that take parameters named "code", + // "codebase", "archive", "object", or "type". The solution is to + // allow the same attributes, prefixed by "java_". The presence of + // a "java_" attribute indicates that the non-prefixed attribute + // should be interpreted as a parameter. For example if "java_code" + // and "code" attributes are present in the OBJECT tag then the + // "code" attribute is interpreted as a parameter. + + name = objElement.getName(); + parameters.put("name", name); + + String jobj = objElement.getJavaObject(); + if (!jobj.equals("")) + parameters.put("java_object", jobj); + else + parameters.put("object", objElement.getObject()); + + parameters.put("type", objElement.getType()); + parameters.put("java_type", objElement.getJavaType()); + parameters.put("align", objElement.getAlign()); + parameters.put("codetype", objElement.getCodeType()); + parameters.put("data", objElement.getData()); + parameters.put("declare", Boolean.toString(objElement.getDeclare())); + parameters.put("height", objElement.getHeight()); + parameters.put("hspace", Integer.toString(objElement.getHspace())); + parameters.put("border", objElement.getBorder()); + parameters.put("standby", objElement.getStandby()); + parameters.put("tabindex", Integer.toString(objElement.getTabIndex())); + parameters.put("usemap", objElement.getUseMap()); + parameters.put("vspace", Integer.toString(objElement.getVspace())); + parameters.put("width", objElement.getWidth()); + parameters.put("mayscript", objElement.getMayscript()); + parameters.put("scriptable", objElement.getScriptable()); + + TagParser.parseParams(objElement, this); + + // Must initialize codebase before archives + if (codebase.equals("")) + { + String javacb = objElement.getJavaCodeBase(); + if (! javacb.equals("")) + codebase = javacb; + else + codebase = objElement.getCodeBase(); + } + + if (code.equals("")) + { + String jcode = objElement.getJavaCode(); + if (!jcode.equals("")) + code = jcode; + else + code = objElement.getCode(); + } + + if (archives.size() == 0) + { + String arcs = ""; + String jarch = objElement.getJavaArchive(); + String arch = objElement.getArchive(); + + if (code.indexOf(".") < 0) + arcs = code + ".jar"; + + if (!jarch.equals("")) + arcs += "," + jarch; + else if (!arch.equals("")) + arcs += "," + arch; + + if (!arcs.equals("")) + archives = TagParser.parseArchives(arcs, this); + } + } + + /** + * String representation of the tag. + * + * @return the string representation. + */ + public String toString() + { + return (" name=" + name + "\n" + " code=" + code + "\n" + " codebase=" + + codebase + "\n" + " archive=" + archives + "\n" + " parameters=" + + parameters + "\n" + " documentbase=" + documentbase + "\n"); + } + + /** + * Returns the size of the applet. + * + * @return the size. + */ + Dimension getSize() + { + Dimension size = new Dimension(320, 200); + + try + { + String widthStr = (String) parameters.get("width"); + + if (widthStr != null && ! widthStr.equals("")) + { + if (widthStr.charAt(widthStr.length() - 1) == '%') + { + double p = NumberFormat.getPercentInstance(Locale.US).parse(widthStr).intValue() / 100.0; + size.width = (int)(p * screenSize.width); + } + else + size.width = NumberFormat.getInstance(Locale.US).parse(widthStr).intValue(); + } + } + catch (ParseException e) + { + // Use default. + } + + try + { + String heightStr = (String) parameters.get("height"); + + if (heightStr != null && !heightStr.equals("")) + { + if (heightStr.charAt(heightStr.length() - 1) == '%') + { + double p = NumberFormat.getPercentInstance(Locale.US).parse(heightStr).intValue() / 100.0; + size.height = (int) (p * screenSize.height); + } + else + size.height = NumberFormat.getInstance(Locale.US).parse(heightStr).intValue(); + } + } + catch (ParseException e) + { + // Use default. + } + + return size; + } + + /** + * Gets the code base. + * + * @return the codebase. + */ + String getCodeBase() + { + return codebase; + } + + /** + * Gets the archive list. + * + * @return the archive list. + */ + ArrayList getArchives() + { + return archives; + } + + /** + * Gets the code. + * + * @return the code. + */ + String getCode() + { + return code; + } + + /** + * Gets the document base. + * + * @return the document base. + */ + URL getDocumentBase() + { + return documentbase; + } + + /** + * Gets the specified parameter. + * + * @param name - the specified parameter. + * @return the parameter. + */ + String getParameter(String name) + { + return (String) parameters.get(name.toLowerCase()); + } + + /** + * Prepends the base to the codebase. + * + * @return the new URL. + */ + URL prependCodeBase(String base) throws MalformedURLException + { + if (documentbase == null) + documentbase = TagParser.db; + + URL fullcodebase; + + //If no codebase was specified, default to documentbase. + if (codebase.equals("")) + { + if (documentbase.getFile().endsWith(File.separator)) + fullcodebase = documentbase; + else + { + String dirname = documentbase.getFile(); + + // Determine dirname for file by stripping everything + // past the last file separator. + dirname = dirname.substring(0, + dirname.lastIndexOf(File.separatorChar) + 1); + + fullcodebase = new URL(documentbase.getProtocol(), + documentbase.getHost(), + documentbase.getPort(), dirname); + } + } + else + { + // codebase was specified. + URL codebaseURL = new URL(documentbase, codebase); + + if ("file".equals(codebaseURL.getProtocol())) + { + if (new File(codebaseURL.getFile()).isDirectory() && !codebase.endsWith(File.separator)) + fullcodebase = new URL(documentbase, codebase + File.separator); + else + fullcodebase = new URL(documentbase, codebase); + } + else if (codebase.endsWith(File.separator)) + fullcodebase = new URL(documentbase, codebase); + else + fullcodebase = new URL(documentbase, codebase + File.separator); + } + + return new URL(fullcodebase, base); + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/AppletWarning.java b/tools/gnu/classpath/tools/appletviewer/AppletWarning.java new file mode 100644 index 000000000..b2376a4cb --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/AppletWarning.java @@ -0,0 +1,66 @@ +/* AppletWarning -- a security warning message display dialog + Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.classpath.tools.appletviewer; + +import javax.swing.JOptionPane; + +/** + * @author Michael Koch (konqueror@gmx.de) + */ +public class AppletWarning +{ + private static String TITLE = "WARNING"; + private static boolean showWarning = false; + + private static String MESSAGE = + "The current version of this applet plugin does not provide\n" + + "a security manager capable of handling Java (tm) applets. Applets\n" + + "have UNRESTRICTED access to your computer. This means they can do\n" + + "anything you can do, like deleting all your important data.\n\n" + + "Continue ?"; + + public static int show() + { + if (showWarning) + return JOptionPane.showConfirmDialog(null, MESSAGE, TITLE, + JOptionPane.YES_NO_OPTION, + JOptionPane.WARNING_MESSAGE); + else + return JOptionPane.YES_OPTION; + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/CommonAppletContext.java b/tools/gnu/classpath/tools/appletviewer/CommonAppletContext.java new file mode 100644 index 000000000..7e118e931 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/CommonAppletContext.java @@ -0,0 +1,133 @@ +/* CommonAppletContext.java -- a common applet's context + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.classpath.tools.appletviewer; + +import java.applet.Applet; +import java.applet.AppletContext; +import java.applet.AudioClip; +import java.awt.Image; +import java.awt.Toolkit; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + + +/* + * CommonAppletContext represents the common context stuff for both + * types, plugins and standalone. + */ +abstract class CommonAppletContext + implements AppletContext +{ + // FIXME: this needs to be static, and we need one AppletContext per + // Applet. + List applets = new ArrayList(); + HashMap streams = new HashMap(); + + void addApplet(Applet applet) + { + applets.add(applet); + } + + /////////////////////////////// + //// AppletContext methods //// + /////////////////////////////// + public AudioClip getAudioClip(URL url) + { + return Applet.newAudioClip(url); + } + + public Image getImage(URL url) + { + return Toolkit.getDefaultToolkit().getImage(url); + } + + public Applet getApplet(String name) + { + Applet a; + String appletName; + Iterator i = applets.iterator(); + + while (i.hasNext()) + { + a = (Applet) i.next(); + + appletName = a.getParameter("name"); + if (a != null && appletName != null && appletName.equals(name)) + return a; + } + return null; + } + + public Enumeration getApplets() + { + return Collections.enumeration(applets); + } + + public void showDocument(URL url) + { + showDocument(url, "_self"); + } + + /* + // FIXME: implement. + public abstract void showDocument (URL url, String target); + + // FIXME: implement. + public abstract void showStatus (String status); + */ + public void setStream(String key, InputStream stream) + { + streams.put(key, stream); + } + + public InputStream getStream(String key) + { + return (InputStream) streams.get(key); + } + + public Iterator getStreamKeys() + { + return streams.keySet().iterator(); + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/CommonAppletStub.java b/tools/gnu/classpath/tools/appletviewer/CommonAppletStub.java new file mode 100644 index 000000000..bc0cc45e1 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/CommonAppletStub.java @@ -0,0 +1,138 @@ +/* CommonAppletStub.java -- an applet-browser interface class + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.classpath.tools.appletviewer; + +import java.applet.AppletContext; +import java.applet.AppletStub; +import java.applet.Applet; +import java.net.MalformedURLException; +import java.net.URL; + + +class CommonAppletStub + implements AppletStub +{ + private AppletTag tag; + private AppletContext context; + private Applet applet; + + CommonAppletStub(AppletTag tag, AppletContext context, Applet applet) + { + this.tag = tag; + this.context = context; + this.applet = applet; + } + + //////////////////////////////// + ////// AppletStub Methods ////// + //////////////////////////////// + + /** + * Tests whether or not this applet is currently active. An applet + * becomes active just before the browser invokes start (), and + * becomes inactive just before the browser invokes stop (). + * + * @return true if applet is active, false otherwise + */ + public boolean isActive() + { + return true; + } + + /** + * Returns the basename URL of the document in which this applet is + * embedded. + * + * @return the document base url. + */ + public URL getDocumentBase() + { + return tag.getDocumentBase(); + } + + /** + * Returns the URL of the code base for this applet. + * + * @return the codebase url + */ + public URL getCodeBase() + { + try + { + return tag.prependCodeBase(""); + } + catch (MalformedURLException e) + { + throw new RuntimeException("unknown codebase"); + } + } + + /** + * Returns the value of the specified parameter that was specified + * in the <code>APPLET</code> tag for this applet. + * + * @param name the key name + * + * @return the key value + */ + public String getParameter(String name) + { + return (String) tag.getParameter(name.toLowerCase()); + } + + /** + * Returns the applet context for this applet. + * + * @return the context + */ + public AppletContext getAppletContext() + { + return context; + } + + /** + * Requests that the applet window for this applet be resized. + * + * @param width the new witdh + * @param height the new height + */ + public void appletResize(int width, int height) + { + applet.setBounds (0, 0, width, height); + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/ConsoleDialog.java b/tools/gnu/classpath/tools/appletviewer/ConsoleDialog.java new file mode 100644 index 000000000..9c937cc77 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/ConsoleDialog.java @@ -0,0 +1,175 @@ +/* ConsoleDialog -- a console dialog for applets + Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.classpath.tools.appletviewer; + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.TextArea; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; + + +/** + * This class is a little dialog showing standard output and standard error output. + * + * @author Michael Koch (konqueror@gmx.de) + */ +public class ConsoleDialog extends Frame + implements ActionListener +{ + static class InternalOutputStream extends OutputStream + { + private ConsoleDialog console; + + public InternalOutputStream(ConsoleDialog console) + { + super(); + this.console = console; + } + + public void write(int data) throws IOException + { + console.print(String.valueOf((char) data)); + } + } + + private TextArea textArea; + private Button buttonClear; + private Button buttonHide; + private PrintStream printStream; + + /** + * Creates a console dialog object. + */ + public ConsoleDialog() + { + super(Main.messages.getString("gcjwebplugin.console_title")); + + setSize(400, 200); + setLayout(new BorderLayout()); + addWindowListener(new WindowAdapter() + { + public void windowClosing(WindowEvent event) + { + hide(); + } + }); + + textArea = new TextArea(); + textArea.setEditable(false); + add(textArea); + + Panel panel = new Panel(); + panel.setLayout(new FlowLayout()); + add(panel, BorderLayout.SOUTH); + + buttonClear = new Button(Main.messages.getString("gcjwebplugin.console_clear")); + buttonClear.addActionListener(this); + panel.add(buttonClear); + + buttonHide = new Button(Main.messages.getString("gcjwebplugin.console_hide")); + buttonHide.addActionListener(this); + panel.add(buttonHide); + + printStream = new PrintStream(new InternalOutputStream(this)); + clearTextArea(); + } + + /** + * Clears the content of the textarea and inserts the initial text. + */ + public void clearTextArea() + { + textArea.setText(""); + + println("java.vm.version: " + System.getProperty("java.vm.version")); + println("java.vm.vendor: " + System.getProperty("java.vm.vendor")); + } + + /** + * Print a message into the console dialog. + * + * @param message the message to print. + */ + public void print(String message) + { + textArea.append(message); + } + + /** + * Print a line into the console dialog. + * + * @param message the line to print. + */ + public void println(String message) + { + print(message + "\n"); + } + + /** + * Perform actions on button clicks inside the console dialog. + * + * @param event the event. + */ + public void actionPerformed(ActionEvent event) + { + if (event.getSource() == buttonHide) + hide(); // Hide console window. + else if (event.getSource() == buttonClear) + clearTextArea(); // Clear text area and insert standard messages. + } + + /** + * Returns a <code>PrintStream</code> object that prints into the + * console dialog. + * + * @return the <code>PrintStream</code> object. + */ + public PrintStream getPrintStream() + { + return printStream; + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/ErrorApplet.java b/tools/gnu/classpath/tools/appletviewer/ErrorApplet.java new file mode 100644 index 000000000..059dbee40 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/ErrorApplet.java @@ -0,0 +1,53 @@ +/* ErrorApplet.java -- an applet to load in case of an error + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.classpath.tools.appletviewer; + +import java.applet.Applet; +import java.awt.BorderLayout; +import java.awt.Button; + +public class ErrorApplet extends Applet +{ + public ErrorApplet(String message) + { + setLayout(new BorderLayout()); + + Button button = new Button(message); + add(button); + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/Main.java b/tools/gnu/classpath/tools/appletviewer/Main.java new file mode 100644 index 000000000..1d9fed2b0 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/Main.java @@ -0,0 +1,293 @@ +/* Main.java -- a standalone viewer for Java applets + Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.classpath.tools.appletviewer; + +import gnu.classpath.tools.getopt.ClasspathToolParser; +import gnu.classpath.tools.getopt.Option; +import gnu.classpath.tools.getopt.OptionException; +import gnu.classpath.tools.getopt.OptionGroup; +import gnu.classpath.tools.getopt.Parser; +import java.applet.Applet; +import java.awt.Dimension; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.ResourceBundle; + + +class Main +{ + /** + * The localized strings are kept in a separate file. + */ + public static final ResourceBundle messages = ResourceBundle.getBundle + ("gnu.classpath.tools.appletviewer.MessagesBundle"); + + private static HashMap classLoaderCache = new HashMap(); + + private static ClassLoader getClassLoader(URL codebase, ArrayList archives) + { + // Should load class loader each time. It is possible that there + // are more than one applet to be loaded with different archives. + AppletClassLoader loader = new AppletClassLoader(codebase, archives); + classLoaderCache.put(codebase, loader); + + return loader; + } + + private static String code = null; + private static String codebase = null; + private static String archive = null; + private static List parameters = new ArrayList(); + private static Dimension dimensions = new Dimension(-1, -1); + private static String pipeInName = null; + private static String pipeOutName = null; + private static boolean pluginMode = false; + private static Parser parser = null; + + static Applet createApplet(AppletTag tag) + { + Applet applet = null; + + try + { + ClassLoader loader = getClassLoader(tag.prependCodeBase(""), + tag.getArchives()); + String code = tag.getCode(); + + if (code.endsWith(".class")) + code = code.substring(0, code.length() - 6).replace('/', '.'); + + Class c = loader.loadClass(code); + applet = (Applet) c.newInstance(); + } + catch (Exception e) + { + e.printStackTrace(); + } + + if (applet == null) + applet = new ErrorApplet("Error loading applet"); + + return applet; + } + + protected static boolean verbose; + + /** + * The main method starting the applet viewer. + * + * @param args the arguments given on the command line. + * + * @exception IOException if an error occurs. + */ + public static void main(String[] args) throws IOException + { + parser = new ClasspathToolParser("appletviewer", true); + parser.setHeader("usage: appletviewer [OPTION] -code CODE | URL..."); + + OptionGroup attributeGroup = new OptionGroup("Applet tag options"); + + attributeGroup.add(new Option("code", Main.messages.getString + ("gcjwebplugin.code_description"), + "CODE") + { + public void parsed(String argument) throws OptionException + { + code = argument; + } + }); + attributeGroup.add(new Option("codebase", Main.messages.getString + ("gcjwebplugin.codebase_description"), + "CODEBASE") + { + public void parsed(String argument) throws OptionException + { + codebase = argument; + } + }); + attributeGroup.add(new Option("archive", Main.messages.getString + ("gcjwebplugin.archive_description"), + "ARCHIVE") + { + public void parsed(String argument) throws OptionException + { + archive = argument; + } + }); + attributeGroup.add(new Option("width", Main.messages.getString + ("gcjwebplugin.width_description"), + "WIDTH") + { + public void parsed(String argument) throws OptionException + { + dimensions.width = Integer.parseInt(argument); + } + }); + attributeGroup.add(new Option("height", Main.messages.getString + ("gcjwebplugin.height_description"), + "HEIGHT") + { + public void parsed(String argument) throws OptionException + { + dimensions.height = Integer.parseInt(argument); + } + }); + attributeGroup.add(new Option("param", Main.messages.getString + ("gcjwebplugin.param_description"), + "NAME,VALUE") + { + public void parsed(String argument) throws OptionException + { + parameters.add(argument); + } + }); + OptionGroup pluginGroup = new OptionGroup("Plugin option"); + pluginGroup.add(new Option("plugin", Main.messages.getString + ("gcjwebplugin.plugin_description"), + "INPUT,OUTPUT") + { + public void parsed(String argument) throws OptionException + { + pluginMode = true; + int comma = argument.indexOf(','); + pipeInName = argument.substring(0, comma); + pipeOutName = argument.substring(comma + 1); + } + }); + OptionGroup debuggingGroup = new OptionGroup("Debugging option"); + debuggingGroup.add(new Option("verbose", Main.messages.getString + ("gcjwebplugin.verbose_description"), + (String) null) + { + public void parsed(String argument) throws OptionException + { + verbose = true; + } + }); + OptionGroup compatibilityGroup = new OptionGroup("Compatibility options"); + compatibilityGroup.add(new Option("debug", Main.messages.getString + ("gcjwebplugin.debug_description"), + (String) null) + { + public void parsed(String argument) throws OptionException + { + // Currently ignored. + } + }); + compatibilityGroup.add(new Option("encoding", Main.messages.getString + ("gcjwebplugin.encoding_description"), + "CHARSET") + { + public void parsed(String argument) throws OptionException + { + // FIXME: We should probably be using + // java.nio.charset.CharsetDecoder to handle the encoding. What + // is the status of Classpath's implementation? + } + }); + parser.add(attributeGroup); + parser.add(pluginGroup); + parser.add(debuggingGroup); + parser.add(compatibilityGroup); + + String[] urls = parser.parse(args); + + // Print arguments. + printArguments(args); + + args = urls; + + if (dimensions.height < 0) + dimensions.height = 200; + + if (dimensions.width < 0) + dimensions.width = (int) (1.6 * dimensions.height); + + //System.setSecurityManager(new AppletSecurityManager(pluginMode)); + + if (pluginMode) + { + InputStream in; + OutputStream out; + + in = new FileInputStream(pipeInName); + out = new FileOutputStream(pipeOutName); + + PluginAppletViewer.start(in, out); + } + else + { + if (code == null) + { + // The --code option wasn't given and there are no URL + // arguments so we have nothing to work with. + if (args.length == 0) + { + System.err.println(Main.messages.getString("gcjwebplugin.no_input_files")); + System.exit(1); + } + // Create a standalone appletviewer from a list of URLs. + new StandaloneAppletViewer(args); + } + else + { + // Create a standalone appletviewer from the --code + // option. + new StandaloneAppletViewer(code, codebase, archive, parameters, dimensions); + } + } + } + + static void printArguments(String[] args) + { + if (verbose) + { + System.out.println("raw arguments:"); + + for (int i = 0; i < args.length; i++) + System.out.println(" " + args[i]); + } + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/PluginAppletContext.java b/tools/gnu/classpath/tools/appletviewer/PluginAppletContext.java new file mode 100644 index 000000000..a0e6acd12 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/PluginAppletContext.java @@ -0,0 +1,72 @@ +/* PluginAppletContext.java -- an applet's context within a web browser + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.classpath.tools.appletviewer; + +import java.net.URL; +import java.io.IOException; + +/* + * PluginAppletContext represents the context within a webpage of a + * group of applets that all share the same codebase. + */ +class PluginAppletContext extends CommonAppletContext +{ + public void showDocument(URL url, String target) + { + try + { + PluginAppletViewer.write("url " + url + " " + target); + } + catch(IOException e) + { + System.err.println("showDocument failed: " + e); + } + } + + public void showStatus(String status) + { + try + { + PluginAppletViewer.write("status " + status); + } + catch(IOException e) + { + System.err.println("showDocument failed: " + e); + } + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/PluginAppletViewer.java b/tools/gnu/classpath/tools/appletviewer/PluginAppletViewer.java new file mode 100644 index 000000000..fdb8097b4 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/PluginAppletViewer.java @@ -0,0 +1,172 @@ +/* PluginAppletViewer.java -- manages embeddable applet windows + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.classpath.tools.appletviewer; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.MalformedURLException; +import java.nio.charset.Charset; +import java.util.HashMap; + + +/** + * PluginAppletViewer communicates through pipes with a web browser + * plugin. A PluginAppletViewer manages applet windows that may be + * embedded into web pages. + */ +class PluginAppletViewer +{ + // A mapping of instance IDs to PluginAppletWindows. + static HashMap appletWindows = new HashMap (); + + private static BufferedReader pluginInputStream; + private static BufferedWriter pluginOutputStream; + + static void start(InputStream inputStream, OutputStream outputStream) + throws MalformedURLException, IOException + { + // Set up input and output pipes. Use UTF-8 encoding. + pluginInputStream = + new BufferedReader(new InputStreamReader(inputStream, + Charset.forName("UTF-8"))); + pluginOutputStream = + new BufferedWriter(new OutputStreamWriter(outputStream, + Charset.forName("UTF-8"))); + + write("running"); + + // Read first message. + String message = read(); + + PluginAppletWindow currentWindow = null; + + while (true) + { + if (message.startsWith("instance")) + { + // Read applet instance identifier. + String key = message.substring(9); + + if (appletWindows.get(key) == null) + appletWindows.put(key, new PluginAppletWindow()); + + currentWindow = (PluginAppletWindow) appletWindows.get(key); + } + else if (message.startsWith("tag")) + { + int pos = message.indexOf(' ', 4); + String documentbase = message.substring(4, pos); + String tag = message.substring(pos + 1); + currentWindow.setParser(tag, documentbase); + } + else if (message.startsWith("handle")) + { + long handle = Long.parseLong(message.substring(7)); + + currentWindow.setHandle(handle); + } + else if (message.startsWith("width")) + { + int width = Integer.parseInt(message.substring(6)); + + currentWindow.setSize(width, currentWindow.getHeight()); + } + else if (message.startsWith("height")) + { + int height = Integer.parseInt(message.substring(7)); + + currentWindow.setSize(currentWindow.getWidth(), height); + } + else if (message.startsWith("destroy")) + { + appletWindows.remove(currentWindow); + currentWindow.dispose(); + } + + // Read next message. + message = read(); + } + } + + /** + * Write string to plugin. + * + * @param message the message to write + * + * @exception IOException if an error occurs + */ + static void write(String message) throws IOException + { + pluginOutputStream.write(message, 0, message.length()); + pluginOutputStream.newLine(); + pluginOutputStream.flush(); + + System.err.println(" PIPE: applet viewer wrote: " + message); + } + + /** + * Read string from plugin. + * + * @return the read string + * + * @exception IOException if an error occurs + */ + static String read() throws IOException + { + String message = pluginInputStream.readLine(); + + System.err.println(" PIPE: applet viewer read: " + message); + + if (message == null || message.equals("shutdown")) + { + // Close input/output channels to plugin. + pluginInputStream.close(); + pluginOutputStream.close(); + + System.err.println("appletviewer: exiting plugin applet viewer"); + System.exit(0); + } + + return message; + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/PluginAppletWindow.java b/tools/gnu/classpath/tools/appletviewer/PluginAppletWindow.java new file mode 100644 index 000000000..6d36e1cf0 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/PluginAppletWindow.java @@ -0,0 +1,454 @@ +/* PluginAppletWindow.java -- an embeddable applet window + Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.classpath.tools.appletviewer; + +import gnu.java.awt.EmbeddedWindow; + +import java.applet.Applet; +import java.applet.AppletContext; +import java.awt.Dimension; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.ContainerEvent; +import java.awt.event.ContainerListener; +import java.awt.event.HierarchyBoundsListener; +import java.awt.event.HierarchyEvent; +import java.awt.event.HierarchyListener; +import java.awt.event.InputMethodEvent; +import java.awt.event.InputMethodListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.io.IOException; +import java.io.StringReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; + +import javax.swing.JOptionPane; + + +class PluginAppletWindow + extends EmbeddedWindow + implements ContainerListener, ComponentListener, MouseListener, + MouseMotionListener, InputMethodListener, HierarchyListener, + HierarchyBoundsListener +{ + + // This class implements various listeners because the author of an applet + // may attach listeners to it, unaware of the applet's parent (this class). + // So, we must pass all listener events on this plugin applet window to the + // actual applet. + + private static HashMap contexts = new HashMap(); + private Applet applet; + private TagParser parser; + private AppletTag tag; + + PluginAppletWindow() + { + super(); + addContainerListener(this); + addComponentListener(this); + addMouseListener(this); + addMouseMotionListener(this); + addInputMethodListener(this); + addHierarchyListener(this); + addHierarchyBoundsListener(this); + } + + /////////////////////////////////// + /// ContainerListener Methods ///// + /////////////////////////////////// + + /** + * This method is called when a component is added to the container. + * + * @param event the <code>ContainerEvent</code> indicating component + * addition + */ + public void componentAdded(ContainerEvent event) + { + if (applet != null) + { + ContainerListener[] l = applet.getContainerListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentAdded(event); + } + } + + /** + * This method is called when a component is removed from the container. + * + * @param event the <code>ContainerEvent</code> indicating component removal + */ + public void componentRemoved(ContainerEvent event) + { + if (applet != null) + { + ContainerListener[] l = applet.getContainerListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentRemoved(event); + } + } + + /////////////////////////////////// + /// ComponentListener Methods ///// + /////////////////////////////////// + + /** + * This method is called when the component is resized. + * + * @param event the <code>ComponentEvent</code> indicating the resize + */ + public void componentResized(ComponentEvent event) + { + if (applet != null) + { + ComponentListener[] l = applet.getComponentListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentResized(event); + } + } + + /** + * This method is called when the component is moved. + * + * @param event the <code>ComponentEvent</code> indicating the move + */ + public void componentMoved(ComponentEvent event) + { + if (applet != null) + { + ComponentListener[] l = applet.getComponentListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentMoved(event); + } + } + + /** + * This method is called when the component is made visible. + * + * @param event the <code>ComponentEvent</code> indicating the visibility + */ + public void componentShown(ComponentEvent event) + { + if (applet != null) + { + ComponentListener[] l = applet.getComponentListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentShown(event); + } + } + + /** + * This method is called when the component is hidden. + * + * @param event the <code>ComponentEvent</code> indicating the visibility + */ + public void componentHidden(ComponentEvent event) + { + if (applet != null) + { + ComponentListener[] l = applet.getComponentListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentHidden(event); + } + } + + /////////////////////////////////// + ////// MouseListener Methods ////// + /////////////////////////////////// + + /** + * This method is called when the mouse is clicked (pressed and released + * in short succession) on a component. + * + * @param event the <code>MouseEvent</code> indicating the click + */ + public void mouseClicked(MouseEvent event) + { + if (applet != null) + { + MouseListener[] l = applet.getMouseListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseClicked(event); + } + } + + /** + * This method is called when the mouse is pressed over a component. + * + * @param event the <code>MouseEvent</code> for the press + */ + public void mousePressed(MouseEvent event) + { + if (applet != null) + { + MouseListener[] l = applet.getMouseListeners(); + for (int i = 0; i < l.length; i++) + l[i].mousePressed(event); + } + } + + /** + * This method is called when the mouse is released over a component. + * + * @param event the <code>MouseEvent</code> for the release + */ + public void mouseReleased(MouseEvent event) + { + if (applet != null) + { + MouseListener[] l = applet.getMouseListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseReleased(event); + } + } + + /** + * This method is called when the mouse enters a component. + * + * @param event the <code>MouseEvent</code> for the entry + */ + public void mouseEntered(MouseEvent event) + { + if (applet != null) + { + MouseListener[] l = applet.getMouseListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseEntered(event); + } + } + + /** + * This method is called when the mouse exits a component. + * + * @param event the <code>MouseEvent</code> for the exit + */ + public void mouseExited(MouseEvent event) + { + if (applet != null) + { + MouseListener[] l = applet.getMouseListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseExited(event); + } + } + + /////////////////////////////////// + /// MouseMotionListener Methods /// + /////////////////////////////////// + + /** + * This method is called when the mouse is moved over a component + * while a button has been pressed. + * + * @param event the <code>MouseEvent</code> indicating the motion + */ + public void mouseDragged(MouseEvent event) + { + if (applet != null) + { + MouseMotionListener[] l = applet.getMouseMotionListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseDragged(event); + } + } + + /** + * This method is called when the mouse is moved over a component + * while no button is pressed. + * + * @param event the <code>MouseEvent</code> indicating the motion + */ + public void mouseMoved(MouseEvent event) + { + if (applet != null) + { + MouseMotionListener[] l = applet.getMouseMotionListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseMoved(event); + } + } + + /////////////////////////////////// + /// InputMethodListener Methods /// + /////////////////////////////////// + + /** + * This method is called when the text is changed. + * + * @param event the <code>InputMethodEvent</code> indicating the text change + */ + public void inputMethodTextChanged(InputMethodEvent event) + { + if (applet != null) + { + InputMethodListener[] l = applet.getInputMethodListeners(); + for (int i = 0; i < l.length; i++) + l[i].inputMethodTextChanged(event); + } + } + + /** + * This method is called when the cursor position within the text is changed. + * + * @param event the <code>InputMethodEvent</code> indicating the change + */ + public void caretPositionChanged(InputMethodEvent event) + { + if (applet != null) + { + InputMethodListener[] l = applet.getInputMethodListeners(); + for (int i = 0; i < l.length; i++) + l[i].caretPositionChanged(event); + } + } + + /////////////////////////////////// + //// HierarchyListener Methods //// + /////////////////////////////////// + + /** + * Called when the hierarchy of this component changes. Use + * <code>getChangeFlags()</code> on the event to see what exactly changed. + * + * @param e the event describing the change + */ + public void hierarchyChanged(HierarchyEvent event) + { + if (applet != null) + { + HierarchyListener[] l = applet.getHierarchyListeners(); + for (int i = 0; i < l.length; i++) + l[i].hierarchyChanged(event); + } + } + + ///////////////////////////////////////// + //// HierarchyBoundsListener Methods //// + ///////////////////////////////////////// + + /** + * Called when an ancestor component of the source is moved. + * + * @param e the event describing the ancestor's motion + */ + public void ancestorMoved(HierarchyEvent e) + { + if (applet != null) + { + HierarchyBoundsListener[] l = applet.getHierarchyBoundsListeners(); + for (int i = 0; i < l.length; i++) + l[i].ancestorMoved(e); + } + } + + /** + * Called when an ancestor component is resized. + * + * @param e the event describing the ancestor's resizing + */ + public void ancestorResized(HierarchyEvent e) + { + if (applet != null) + { + HierarchyBoundsListener[] l = applet.getHierarchyBoundsListeners(); + for (int i = 0; i < l.length; i++) + l[i].ancestorResized(e); + } + } + + void setParser(String tag, String documentbase) throws MalformedURLException, IOException + { + URL documentbaseURL = TagParser.getLocationToURL(documentbase); + StringReader in = new StringReader(tag); + this.parser = new TagParser(in, documentbaseURL); + } + + // ///////////////////////////////// + // //// EmbeddedWindow Method ////// + // ///////////////////////////////// + + /** + * Set the native handle of the window system to embed the window in. + * + * @param handle the native handle. + */ + public void setHandle(long handle) + { + super.setHandle(handle); + addNotify(); + + ArrayList l = parser.parseAppletTags(); + int s = l.size(); + + for (int i = 0; i < s; i++) + { + tag = (AppletTag) l.get(i); + applet = Main.createApplet(tag); + + if (contexts.get(tag.getCodeBase()) == null) + contexts.put(tag.getCodeBase(), new PluginAppletContext()); + + int result = AppletWarning.show(); + if (result == JOptionPane.NO_OPTION) + return; + + add(applet); + + AppletContext context = (AppletContext) contexts.get(tag.getCodeBase()); + ((PluginAppletContext) context).addApplet(applet); + + applet.setStub(new CommonAppletStub(tag, context, applet)); + Dimension size = getSize(); + if (size.width == 0 || size.height == 0) + size = tag.getSize(); + applet.setSize(size); + + // Initialize the applet before showing this window so that + // the applet doesn't receive events before it has been + // initialized. + applet.init(); + applet.start(); + setVisible(true); + } + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/StandaloneAppletContext.java b/tools/gnu/classpath/tools/appletviewer/StandaloneAppletContext.java new file mode 100644 index 000000000..a779f068a --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/StandaloneAppletContext.java @@ -0,0 +1,75 @@ +/* StandaloneAppletContext.java -- an applet's context within the + standalone viewer + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.classpath.tools.appletviewer; + +import java.net.URL; +import java.util.Iterator; +import java.util.List; + + +/** + * StandaloneAppletContext represents the context within a webpage of a + * group of applets that all share the same codebase. + */ +class StandaloneAppletContext extends CommonAppletContext +{ + private List appletWindows; + + StandaloneAppletContext(List appletWindows) + { + this.appletWindows = appletWindows; + } + + public void showDocument(URL url, String target) + { + System.err.println("showDocument is not implemented in standalone mode"); + } + + // In standalone mode, there are potentially several windows, each + // with its own status bar. In plugin mode, all the applets in the + // same context (on the same page) share the browser's status bar. + // The best way to simulate the plugin mode behaviour in standalone + // mode is to show the same status on each window's status bar. + public void showStatus(String status) + { + Iterator window = appletWindows.iterator(); + while (window.hasNext()) + ((StandaloneAppletWindow) window.next()).showStatus(status); + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/StandaloneAppletViewer.java b/tools/gnu/classpath/tools/appletviewer/StandaloneAppletViewer.java new file mode 100644 index 000000000..2b58f4b87 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/StandaloneAppletViewer.java @@ -0,0 +1,144 @@ +/* StandaloneAppletViewer.java -- a standalone viewer for Java applets + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.classpath.tools.appletviewer; + +import java.awt.Dimension; +import java.io.File; +import java.io.IOException; +import java.io.StringReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.StringTokenizer; + + +/** + * StandaloneAppletViewer displays an applet in its own Frame. Most + * of the context that is available to an applet within a webpage is + * available to it in StandaloneAppletViewer. + */ +class StandaloneAppletViewer extends Main +{ + static ArrayList appletTags = new ArrayList(); + static ArrayList appletWindows = new ArrayList(); + + StandaloneAppletViewer(String[] urls) + throws MalformedURLException, IOException + { + // Handle each file specified on the command line. + for (int i = 0; i < urls.length; i++) + { + TagParser parser = new TagParser(urls[i]); + appletTags.addAll(parser.parseAppletTags()); + } + + printTags(); + createWindows(); + } + + StandaloneAppletViewer(String code, String codebase, String archives, + List parameters, Dimension dimensions) + throws IOException + { + if (!(code.equals("") || code.endsWith(".class"))) + { + System.err.println("appletviewer: option '--code' requires a class filename"); + System.exit(1); + } + + String tagString = + "<EMBED" + + " CODE=\"" + code + "\"" + + " WIDTH=" + dimensions.width + + " HEIGHT=" + dimensions.height + + " CODEBASE=\"" + codebase + "\"" + + " ARCHIVE=\"" + archives + "\">"; + + // Handle parameters. + Iterator pairs = parameters.iterator(); + while (pairs.hasNext()) + { + StringTokenizer paramTokenizer = + new StringTokenizer((String) pairs.next(), ","); + tagString += + "<PARAM NAME=" + paramTokenizer.nextToken().trim() + " VALUE=" + + paramTokenizer.nextToken().trim() + ">"; + } + + tagString += "</EMBED>"; + + StringReader reader = new StringReader(tagString); + String path = System.getProperty("user.dir") + File.separator; + TagParser parser = new TagParser(reader, + new URL("file", "", path)); + appletTags.addAll(parser.parseAppletTags()); + + printTags(); + createWindows(); + } + + void printTags() + { + if (verbose) + { + System.out.println("parsed applet tags:"); + + for (int i = 0; i < appletTags.size(); i++) + { + AppletTag tag = (AppletTag) appletTags.get(i); + + System.out.println(" tag " + i + ":"); + System.out.println(tag); + } + } + } + + void createWindows() + { + for (int i = 0; i < appletTags.size(); i++) + { + AppletTag tag = (AppletTag) appletTags.get(i); + + // Create a StandaloneAppletWindow and add it to the + // appletWindows list. + new StandaloneAppletWindow(tag, appletWindows); + } + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/StandaloneAppletWindow.java b/tools/gnu/classpath/tools/appletviewer/StandaloneAppletWindow.java new file mode 100644 index 000000000..3b337bf80 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/StandaloneAppletWindow.java @@ -0,0 +1,559 @@ +/* StandaloneAppletWindow.java -- an applet frame + Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.classpath.tools.appletviewer; + +import java.applet.Applet; +import java.applet.AppletContext; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Insets; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.ContainerEvent; +import java.awt.event.ContainerListener; +import java.awt.event.HierarchyBoundsListener; +import java.awt.event.HierarchyEvent; +import java.awt.event.HierarchyListener; +import java.awt.event.InputMethodEvent; +import java.awt.event.InputMethodListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.HashMap; +import java.util.List; + +class StandaloneAppletWindow + extends Frame + implements ActionListener, ContainerListener, ComponentListener, + MouseListener, MouseMotionListener, InputMethodListener, HierarchyListener, + HierarchyBoundsListener +{ + + // This class implements various listeners because the author of an applet + // may attach listeners to it, unaware of the applet's parent (this class). + // So, we must pass all listener events on this plugin applet window to the + // actual applet. + + private static int testWindowCount; + private static HashMap contexts = new HashMap(); + private Applet applet; + private Label status = new Label(); + + private MenuItem restartItem; + private MenuItem reloadItem; + private MenuItem cancelItem; + private MenuItem saveItem; + private MenuItem startItem; + private MenuItem cloneItem; + private MenuItem tagItem; + private MenuItem infoItem; + private MenuItem editItem; + private MenuItem encodingItem; + private MenuItem printItem; + private MenuItem propertiesItem; + private MenuItem closeItem; + private MenuItem quitItem; + + StandaloneAppletWindow(AppletTag tag, List appletWindows) + { + appletWindows.add(this); + applet = Main.createApplet(tag); + + if (contexts.get(tag.codebase) == null) + contexts.put(tag.codebase, new StandaloneAppletContext(appletWindows)); + + setLayout(new BorderLayout()); + add(applet, BorderLayout.CENTER); + add(status, BorderLayout.SOUTH); + + addWindowListener(new WindowAdapter() + { + public void windowClosing(WindowEvent event) + { + applet.stop(); + StandaloneAppletWindow.this.hide(); + System.exit(0); + } + }); + + addContainerListener(this); + addComponentListener(this); + addMouseListener(this); + addMouseMotionListener(this); + addInputMethodListener(this); + addHierarchyListener(this); + addHierarchyBoundsListener(this); + + restartItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_restart")); + restartItem.setEnabled(false); + restartItem.addActionListener(this); + reloadItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_reload")); + reloadItem.setEnabled(false); + reloadItem.addActionListener(this); + cancelItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_cancel")); + cancelItem.setEnabled(false); + cancelItem.addActionListener(this); + saveItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_save")); + saveItem.setEnabled(false); + saveItem.addActionListener(this); + startItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_start")); + startItem.setEnabled(false); + startItem.addActionListener(this); + cloneItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_clone")); + cloneItem.setEnabled(false); + cloneItem.addActionListener(this); + closeItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_close")); + closeItem.setEnabled(false); + closeItem.addActionListener(this); + tagItem = + new MenuItem(Main.messages.getString("gcjwebplugin.menu_tag")); + tagItem.setEnabled(false); + tagItem.addActionListener(this); + infoItem = + new MenuItem(Main.messages.getString("gcjwebplugin.menu_info")); + infoItem.setEnabled(false); + infoItem.addActionListener(this); + editItem = + new MenuItem(Main.messages.getString("gcjwebplugin.menu_edit")); + editItem.setEnabled(false); + editItem.addActionListener(this); + editItem.setEnabled(false); + encodingItem = + new MenuItem(Main.messages.getString("gcjwebplugin.menu_encoding")); + encodingItem.setEnabled(false); + encodingItem.addActionListener(this); + printItem = + new MenuItem(Main.messages.getString("gcjwebplugin.menu_print")); + printItem.setEnabled(false); + printItem.addActionListener(this); + propertiesItem = + new MenuItem(Main.messages.getString("gcjwebplugin.menu_properties")); + propertiesItem.setEnabled(false); + propertiesItem.addActionListener(this); + quitItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_quit")); + quitItem.addActionListener(this); + + MenuBar menuBar = new MenuBar(); + Menu menuApplet = new Menu(Main.messages.getString("gcjwebplugin.menu_title")); + menuBar.add(menuApplet); + menuApplet.add(restartItem); + menuApplet.add(reloadItem); + menuApplet.add(cancelItem); + menuApplet.add(saveItem); + menuApplet.add(startItem); + menuApplet.add(cloneItem); + menuApplet.addSeparator(); + menuApplet.add(tagItem); + menuApplet.add(infoItem); + menuApplet.add(editItem); + menuApplet.add(encodingItem); + menuApplet.addSeparator(); + menuApplet.add(printItem); + menuApplet.addSeparator(); + menuApplet.add(propertiesItem); + menuApplet.addSeparator(); + menuApplet.add(closeItem); + menuApplet.add(quitItem); + setMenuBar(menuBar); + setTitle("GCJ Applet Viewer: " + tag.code); + + AppletContext context = (AppletContext) contexts.get(tag.codebase); + ((StandaloneAppletContext) context).addApplet(applet); + + applet.setStub(new CommonAppletStub(tag, context, applet)); + + // Create the frame's peer. Otherwise getPreferredSize will read + // its insets as 0. + addNotify(); + Insets i = getInsets(); + Dimension size = tag.getSize(); + setSize(i.left + size.width + i.right, + i.top + size.height + status.getPreferredSize().height + + i.bottom); + applet.setSize(size); + + // Initialize the applet before showing this window so that the + // applet doesn't receive events before it has been initialized. + applet.init(); + applet.start(); + setVisible(true); + } + + private void closeWindow() + { + applet.stop(); + StandaloneAppletViewer.appletWindows.remove(this); + StandaloneAppletWindow.this.hide(); + } + + public void actionPerformed(ActionEvent e) + { + if (e.getSource() == quitItem) + { + closeWindow(); + System.exit(0); + } + else if (e.getSource() == closeItem) + { + // Close current window. + closeWindow(); + + // Exit if there are other windows left. + if (StandaloneAppletViewer.appletWindows.isEmpty()) + System.exit(0); + } + } + + void showStatus(String status) + { + this.status.setText(status); + } + + + /////////////////////////////////// + /// ContainerListener Methods ///// + /////////////////////////////////// + + /** + * This method is called when a component is added to the container. + * + * @param event the <code>ContainerEvent</code> indicating component + * addition + */ + public void componentAdded(ContainerEvent event) + { + if (applet != null) + { + ContainerListener[] l = applet.getContainerListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentAdded(event); + } + } + + /** + * This method is called when a component is removed from the container. + * + * @param event the <code>ContainerEvent</code> indicating component removal + */ + public void componentRemoved(ContainerEvent event) + { + if (applet != null) + { + ContainerListener[] l = applet.getContainerListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentRemoved(event); + } + } + + /////////////////////////////////// + /// ComponentListener Methods ///// + /////////////////////////////////// + + /** + * This method is called when the component is resized. + * + * @param event the <code>ComponentEvent</code> indicating the resize + */ + public void componentResized(ComponentEvent event) + { + if (applet != null) + { + ComponentListener[] l = applet.getComponentListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentResized(event); + } + } + + /** + * This method is called when the component is moved. + * + * @param event the <code>ComponentEvent</code> indicating the move + */ + public void componentMoved(ComponentEvent event) + { + if (applet != null) + { + ComponentListener[] l = applet.getComponentListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentMoved(event); + } + } + + /** + * This method is called when the component is made visible. + * + * @param event the <code>ComponentEvent</code> indicating the visibility + */ + public void componentShown(ComponentEvent event) + { + if (applet != null) + { + ComponentListener[] l = applet.getComponentListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentShown(event); + } + } + + /** + * This method is called when the component is hidden. + * + * @param event the <code>ComponentEvent</code> indicating the visibility + */ + public void componentHidden(ComponentEvent event) + { + if (applet != null) + { + ComponentListener[] l = applet.getComponentListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentHidden(event); + } + } + + /////////////////////////////////// + ////// MouseListener Methods ////// + /////////////////////////////////// + + /** + * This method is called when the mouse is clicked (pressed and released + * in short succession) on a component. + * + * @param event the <code>MouseEvent</code> indicating the click + */ + public void mouseClicked(MouseEvent event) + { + if (applet != null) + { + MouseListener[] l = applet.getMouseListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseClicked(event); + } + } + + /** + * This method is called when the mouse is pressed over a component. + * + * @param event the <code>MouseEvent</code> for the press + */ + public void mousePressed(MouseEvent event) + { + if (applet != null) + { + MouseListener[] l = applet.getMouseListeners(); + for (int i = 0; i < l.length; i++) + l[i].mousePressed(event); + } + } + + /** + * This method is called when the mouse is released over a component. + * + * @param event the <code>MouseEvent</code> for the release + */ + public void mouseReleased(MouseEvent event) + { + if (applet != null) + { + MouseListener[] l = applet.getMouseListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseReleased(event); + } + } + + /** + * This method is called when the mouse enters a component. + * + * @param event the <code>MouseEvent</code> for the entry + */ + public void mouseEntered(MouseEvent event) + { + if (applet != null) + { + MouseListener[] l = applet.getMouseListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseEntered(event); + } + } + + /** + * This method is called when the mouse exits a component. + * + * @param event the <code>MouseEvent</code> for the exit + */ + public void mouseExited(MouseEvent event) + { + if (applet != null) + { + MouseListener[] l = applet.getMouseListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseExited(event); + } + } + + /////////////////////////////////// + /// MouseMotionListener Methods /// + /////////////////////////////////// + + /** + * This method is called when the mouse is moved over a component + * while a button has been pressed. + * + * @param event the <code>MouseEvent</code> indicating the motion + */ + public void mouseDragged(MouseEvent event) + { + if (applet != null) + { + MouseMotionListener[] l = applet.getMouseMotionListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseDragged(event); + } + } + + /** + * This method is called when the mouse is moved over a component + * while no button is pressed. + * + * @param event the <code>MouseEvent</code> indicating the motion + */ + public void mouseMoved(MouseEvent event) + { + if (applet != null) + { + MouseMotionListener[] l = applet.getMouseMotionListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseMoved(event); + } + } + + /////////////////////////////////// + /// InputMethodListener Methods /// + /////////////////////////////////// + + /** + * This method is called when the text is changed. + * + * @param event the <code>InputMethodEvent</code> indicating the text change + */ + public void inputMethodTextChanged(InputMethodEvent event) + { + if (applet != null) + { + InputMethodListener[] l = applet.getInputMethodListeners(); + for (int i = 0; i < l.length; i++) + l[i].inputMethodTextChanged(event); + } + } + + /** + * This method is called when the cursor position within the text is changed. + * + * @param event the <code>InputMethodEvent</code> indicating the change + */ + public void caretPositionChanged(InputMethodEvent event) + { + if (applet != null) + { + InputMethodListener[] l = applet.getInputMethodListeners(); + for (int i = 0; i < l.length; i++) + l[i].caretPositionChanged(event); + } + } + + /////////////////////////////////// + //// HierarchyListener Methods //// + /////////////////////////////////// + + /** + * Called when the hierarchy of this component changes. Use + * <code>getChangeFlags()</code> on the event to see what exactly changed. + * + * @param e the event describing the change + */ + public void hierarchyChanged(HierarchyEvent event) + { + if (applet != null) + { + HierarchyListener[] l = applet.getHierarchyListeners(); + for (int i = 0; i < l.length; i++) + l[i].hierarchyChanged(event); + } + } + + ///////////////////////////////////////// + //// HierarchyBoundsListener Methods //// + ///////////////////////////////////////// + + /** + * Called when an ancestor component of the source is moved. + * + * @param e the event describing the ancestor's motion + */ + public void ancestorMoved(HierarchyEvent e) + { + if (applet != null) + { + HierarchyBoundsListener[] l = applet.getHierarchyBoundsListeners(); + for (int i = 0; i < l.length; i++) + l[i].ancestorMoved(e); + } + } + + /** + * Called when an ancestor component is resized. + * + * @param e the event describing the ancestor's resizing + */ + public void ancestorResized(HierarchyEvent e) + { + if (applet != null) + { + HierarchyBoundsListener[] l = applet.getHierarchyBoundsListeners(); + for (int i = 0; i < l.length; i++) + l[i].ancestorResized(e); + } + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/TagParser.java b/tools/gnu/classpath/tools/appletviewer/TagParser.java new file mode 100644 index 000000000..68dce97e0 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/TagParser.java @@ -0,0 +1,302 @@ +/* TagParser.java -- a parser for applet tags + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.classpath.tools.appletviewer; + +import gnu.javax.swing.text.html.parser.HTML_401F; + +import gnu.xml.dom.DomNode; +import gnu.xml.dom.html2.DomHTMLAppletElement; +import gnu.xml.dom.html2.DomHTMLDocument; +import gnu.xml.dom.html2.DomHTMLEmbedElement; +import gnu.xml.dom.html2.DomHTMLObjectElement; +import gnu.xml.dom.html2.DomHTMLParamElement; +import gnu.xml.dom.html2.DomHTMLParser; + +import java.io.File; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.Reader; + +import java.net.MalformedURLException; +import java.net.URL; + +import java.util.ArrayList; +import java.util.StringTokenizer; +import java.util.Vector; + +import org.w3c.dom.NodeList; + + +public class TagParser +{ + + /** + * Parsed document. + */ + DomHTMLDocument document; + + /** + * The document base of this applet. + */ + URL documentbase; + + /** + * The document base of all the applets. + */ + static URL db; + + /** + * The tags in the document. + */ + Vector tags = new Vector(); + + /** + * Default constructor. + */ + TagParser() + { + // Do nothing. + } + + /** + * Constructs and parses document using the given location. + * + * @param location - location of applet + */ + TagParser(String location) throws IOException + { + documentbase = getLocationToURL(location); + db = documentbase; + InputStreamReader in = new InputStreamReader(documentbase.openStream()); + document = (DomHTMLDocument) (new DomHTMLParser(HTML_401F.getInstance()).parseDocument(in)); + } + + /** + * Constructs and parses document. + * + * @param in - Reader to parse document from. + * @param documentBase - the URL of the applet + * @throws IOException - is thrown if any IO error occurs. + */ + TagParser(Reader in, URL documentBase) throws IOException + { + documentbase = documentBase; + db = documentbase; + document = (DomHTMLDocument) (new DomHTMLParser(HTML_401F.getInstance()).parseDocument(in)); + } + + /** + * Parses all applet tags in document. + * + * @return a list of AppletTag objects representing the applet tags + * in document + */ + ArrayList parseAppletTags() + { + ArrayList allTags = new ArrayList(); + if (document == null) + return null;; + + recurseDocument(document.getChildNodes()); + + int sz = tags.size(); + for (int j = 0; j < sz; j++) + { + Object curr = tags.get(j); + // Order of checking is important here. + // Must check embed element before applet element + // because DomHTMLEmbedElement extends DomHTMLAppletElement + AppletTag a = null; + if (curr instanceof DomHTMLEmbedElement) + a = new AppletTag((DomHTMLEmbedElement) curr); + else if (curr instanceof DomHTMLAppletElement) + a = new AppletTag((DomHTMLAppletElement) curr); + else if (curr instanceof DomHTMLObjectElement) + a = new AppletTag((DomHTMLObjectElement) curr); + a.documentbase = documentbase; + allTags.add(a); + } + + return allTags; + } + + /** + * Recurses the document in search for the appropriate tags. + * + * @param list - the Node list. + */ + private void recurseDocument(NodeList list) + { + // Recurse and store all APPLET, OBJECT and EMBED tags. + int length = list.getLength(); + for (int i = 0; i < length; i++) + { + DomNode curr = (DomNode) list.item(i); + if ((curr instanceof DomHTMLEmbedElement) || + (curr instanceof DomHTMLAppletElement) || + (curr instanceof DomHTMLObjectElement)) + tags.add(curr); + recurseDocument(curr.getChildNodes()); + } + } + + /** + * Parses the param elements for a given node. + * + * @param node - the node element to parse. + */ + static void parseParams(DomNode node, AppletTag t) + { + boolean ja = false; + boolean jb = false; + boolean jc = false; + NodeList l = node.getChildNodes(); + int size = l.getLength(); + + if (size != 0) + for (int i = 0; i < size; i++) + { + Object c = l.item(i); + if (! (c instanceof DomHTMLParamElement)) + continue; + DomHTMLParamElement curr = (DomHTMLParamElement) c; + String key = curr.getName(); + String val = curr.getValue(); + + if (key.equals("java_code")) + { + jc = true; + t.code = val; + } + else if (key.equals("java_codebase")) + { + jb = true; + t.codebase = val; + } + else if (!jc && key.equals("code")) + t.code = val; + else if (!jc && key.equals("classid")) + { + int x = val.indexOf(":"); + if (x != -1) + val = val.substring(x + 1); + t.code = val; + } + else if (!jb && key.equals("codebase")) + t.codebase = val; + else if (key.equals("java_archive")) + { + ja = true; + t.archives = parseArchives(val, t); + val = t.archives.toString(); + } + else if (!ja && key.equals("archive")) + { + t.archives = parseArchives(val, t); + val = t.archives.toString(); + } + + t.parameters.put(key.toLowerCase(), val); + } + } + + /** + * Parses the archive string and returns a list. + * + * @param the list of archives (comma-separated) in a String. + */ + static ArrayList parseArchives(String arcs, AppletTag t) + { + try + { + ArrayList list = new ArrayList(); + + StringTokenizer tagTokenizer = new StringTokenizer(arcs, ","); + while (tagTokenizer.hasMoreTokens()) + list.add(t.prependCodeBase(tagTokenizer.nextToken().trim())); + + return list; + } + catch (MalformedURLException e) + { + } + return null; + } + + /** + * Gets the location to the URL, given a location. + * + * @param location - the given location. + * @return the URL. + */ + static URL getLocationToURL(String location) throws IOException + { + URL tmpDocumentBase = null; + + try + { + // Try parsing location as a URL. + tmpDocumentBase = new URL(location); + + // If no file was specified in the URL the assume the user + // meant the root page. + String f = tmpDocumentBase.getFile(); + if (f.indexOf(".") == -1 && !f.endsWith(File.separator)) + if (new File(tmpDocumentBase.getFile()).isDirectory()) + tmpDocumentBase = new URL(location.concat(File.separator)); + } + catch (MalformedURLException e) + { + // location is not a URL. See if it is an HTML file. + String path; + + if (location.startsWith(File.separator)) + path = new File(location).getCanonicalPath(); + else + path = new File(System.getProperty("user.dir") + File.separator + + location).getCanonicalPath(); + + tmpDocumentBase = new URL("file", "", path); + + if (new File(tmpDocumentBase.getFile()).isDirectory()) + tmpDocumentBase = new URL("file", "", path + File.separator); + } + + return tmpDocumentBase; + } +} diff --git a/tools/gnu/classpath/tools/getopt/ClasspathToolParser.java b/tools/gnu/classpath/tools/getopt/ClasspathToolParser.java new file mode 100644 index 000000000..e712056ef --- /dev/null +++ b/tools/gnu/classpath/tools/getopt/ClasspathToolParser.java @@ -0,0 +1,73 @@ +/* ClasspathToolParser.java -- Parser subclass for classpath tools + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.classpath.tools.getopt; + +import java.text.MessageFormat; + +import gnu.classpath.Configuration; + +/** + * This is like the Parser class, but is specialized for use by + * tools distributed with GNU Classpath. In particular it automatically + * computes the version string using the program's name. + */ +public class ClasspathToolParser + extends Parser +{ + private static String getVersionString(String programName) + { + String fmt = (Messages.getString("ClasspathToolParser.VersionFormat")); //$NON-NLS-1$ + return MessageFormat.format(fmt, + new Object[] + { + programName, + Configuration.CLASSPATH_VERSION + }); + } + + public ClasspathToolParser(String programName) + { + super(programName, getVersionString(programName)); + } + + public ClasspathToolParser(String programName, boolean longOnly) + { + super(programName, getVersionString(programName), longOnly); + } +} diff --git a/tools/gnu/classpath/tools/getopt/FileArgumentCallback.java b/tools/gnu/classpath/tools/getopt/FileArgumentCallback.java new file mode 100644 index 000000000..0c44745c9 --- /dev/null +++ b/tools/gnu/classpath/tools/getopt/FileArgumentCallback.java @@ -0,0 +1,61 @@ +/* FileArgumentCallback.java - handle non-option command line arguments + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.classpath.tools.getopt; + +/** + * This is a callback class which is used when a "file name" is found by the + * command-line parser. A file name is any command-line argument which does not + * start with a dash and which is not the argument of some preceding option. + */ +public abstract class FileArgumentCallback +{ + /** + * Create a new instance. + */ + protected FileArgumentCallback() + { + } + + /** + * This is called when a file argument is seen. + * + * @param fileArgument the file name + */ + public abstract void notifyFile(String fileArgument); +} diff --git a/tools/gnu/classpath/tools/getopt/Messages.java b/tools/gnu/classpath/tools/getopt/Messages.java new file mode 100644 index 000000000..3c963d786 --- /dev/null +++ b/tools/gnu/classpath/tools/getopt/Messages.java @@ -0,0 +1,67 @@ +/* Messages.java -- i18n support for getopt + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.getopt; + +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +public class Messages +{ + private static final String BUNDLE_NAME + = "gnu.classpath.tools.getopt.Messages"; //$NON-NLS-1$ + + private static final ResourceBundle RESOURCE_BUNDLE + = ResourceBundle.getBundle(BUNDLE_NAME); + + private Messages() + { + } + + public static String getString(String key) + { + try + { + return RESOURCE_BUNDLE.getString(key); + } + catch (MissingResourceException e) + { + return '!' + key + '!'; + } + } +} diff --git a/tools/gnu/classpath/tools/getopt/Option.java b/tools/gnu/classpath/tools/getopt/Option.java new file mode 100644 index 000000000..6f775e4a1 --- /dev/null +++ b/tools/gnu/classpath/tools/getopt/Option.java @@ -0,0 +1,200 @@ +/* Option.java - represent a command-line option + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.getopt; + +/** + * This is the base class representing an option. An option can have a short + * form. This is a single character, like '-x'. An option can have a long form, + * like '--verbose'; if the parser is working in "long option only" mode, then a + * long flag has a single dash, like '-verbose'. Both a long and a short form + * may be specified; it is not valid to have neither. A description is mandatory + * for options; this is used to automatically generate '--help' output. + */ +public abstract class Option +{ + private char shortName; + + private String longName; + + private String description; + + private String argumentName; + + /** + * Create a new option with the given short name and description. + * + * @param shortName the short name + * @param description the description + */ + protected Option(char shortName, String description) + { + this.shortName = shortName; + this.description = description; + } + + /** + * Create a new option with the given short name and description. + * + * @param shortName the short name + * @param description the description + * @param argumentName the descriptive name of the argument, if this option + * takes an argument; otherwise null + */ + protected Option(char shortName, String description, String argumentName) + { + this.shortName = shortName; + this.description = description; + this.argumentName = argumentName; + } + + /** + * Create a new option with the given long name and description. The long name + * should be specified without any leading dashes. + * + * @param longName the long name + * @param description the description + */ + protected Option(String longName, String description) + { + this.longName = longName; + this.description = description; + } + + /** + * Create a new option with the given long name and description. The long name + * should be specified without any leading dashes. + * + * @param longName the long name + * @param description the description + * @param argumentName the descriptive name of the argument, if this option + * takes an argument; otherwise null + */ + protected Option(String longName, String description, String argumentName) + { + this.longName = longName; + this.description = description; + this.argumentName = argumentName; + } + + /** + * Create a new option with the given short and long names and description. + * The long name should be specified without any leading dashes. + * + * @param longName the long name + * @param shortName the short name + * @param description the description + */ + protected Option(String longName, char shortName, String description) + { + this.shortName = shortName; + this.longName = longName; + this.description = description; + } + + /** + * Create a new option with the given short and long names and description. + * The long name should be specified without any leading dashes. + * + * @param longName the long name + * @param shortName the short name + * @param description the description + * @param argumentName the descriptive name of the argument, if this option + * takes an argument; otherwise null + */ + protected Option(String longName, char shortName, String description, + String argumentName) + { + this.shortName = shortName; + this.longName = longName; + this.argumentName = argumentName; + this.description = description; + } + + /** + * Return the short name of the option, or \0 if none. + */ + public char getShortName() + { + return shortName; + } + + /** + * Return the long name of the option, or null if none. + */ + public String getLongName() + { + return longName; + } + + /** + * Return true if the argument takes an option. + */ + public boolean getTakesArgument() + { + return argumentName != null; + } + + /** + * Return the name of the argument. If the option does not take an argument, + * returns null. + */ + public String getArgumentName() + { + return argumentName; + } + + /** + * Return the description of the option. + */ + public String getDescription() + { + return description; + } + + /** + * This is called by the parser when this option is recognized. It may be + * called multiple times during a single parse. If this option takes an + * argument, the argument will be passed in. Otherwise the argument will be + * null. + * + * @param argument the argument + * @throws OptionException if the option or its argument is somehow invalid + */ + public abstract void parsed(String argument) throws OptionException; +} diff --git a/tools/gnu/classpath/tools/getopt/OptionException.java b/tools/gnu/classpath/tools/getopt/OptionException.java new file mode 100644 index 000000000..a09d716f4 --- /dev/null +++ b/tools/gnu/classpath/tools/getopt/OptionException.java @@ -0,0 +1,52 @@ +/* OptionException.java - when command-line processing fails + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.getopt; + +/** + * An OptionException is thrown internally when an error is seen when parsing a + * command line. + */ +public class OptionException + extends Exception +{ + public OptionException(String message) + { + super(message); + } +} diff --git a/tools/gnu/classpath/tools/getopt/OptionGroup.java b/tools/gnu/classpath/tools/getopt/OptionGroup.java new file mode 100644 index 000000000..f7d966d94 --- /dev/null +++ b/tools/gnu/classpath/tools/getopt/OptionGroup.java @@ -0,0 +1,271 @@ +/* OptionGroup.java - a group of related command-line options + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.getopt; + +import java.io.PrintStream; +import java.text.BreakIterator; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Locale; + +/** + * An option group holds a collection of Options. It also has a name. Option + * groups are primarily useful for grouping help output. + */ +public class OptionGroup +{ + /** An 80-character string of whitespaces to use as a source for padding. */ + private static final String FILLER = " " + + " "; + private String name; + + ArrayList options = new ArrayList(); + + /** + * Create a new nameless option group. This can only be used by Parser. + */ + OptionGroup() + { + } + + /** + * Create a new option group with the indicated name. + * + * @param name the name + */ + public OptionGroup(String name) + { + this.name = name; + } + + /** + * Print a designated text to a {@link PrintStream}, eventually wrapping the + * lines of text so as to ensure that the width of each line does not overflow + * {@link Parser#MAX_LINE_LENGTH} columns. The line-wrapping is done with a + * {@link BreakIterator} using the default {@link Locale}. + * <p> + * The text to print may contain <code>\n</code> characters. This method will + * force a line-break for each such character. + * + * @param out the {@link PrintStream} destination of the formatted text. + * @param text the text to print. + * @param leftMargin a positive value indicating the column position of the + * start of the first line. Continuation lines, if they exist, are + * printed starting at <code>leftMargin + 2</code> as per GNU + * convention. + * @see Parser#MAX_LINE_LENGTH + */ + protected static void formatText(PrintStream out, String text, int leftMargin) + { + formatText(out, text, leftMargin, Locale.getDefault()); + } + + /** + * Similar to the method with the same name and three arguments, except that + * the caller MUST specify a non-null {@link Locale} instance. + * <p> + * Print a designated text to a {@link PrintStream}, eventually wrapping the + * lines of text so as to ensure that the width of each line does not overflow + * {@link Parser#MAX_LINE_LENGTH} columns. The line-wrapping is done with a + * {@link BreakIterator} using the designated {@link Locale}. + * <p> + * The text to print may contain <code>\n</code> characters. This method will + * force a line-break for each such character. + * + * @param out the {@link PrintStream} destination of the formatted text. + * @param text the text to print. + * @param leftMargin a positive value indicating the column position of the + * start of the first line. Continuation lines, if they exist, are + * printed starting at <code>leftMargin + 2</code> as per GNU + * convention. + * @param aLocale the {@link Locale} instance to use when constructing the + * {@link BreakIterator}. + * @see Parser#MAX_LINE_LENGTH + */ + protected static void formatText(PrintStream out, String text, int leftMargin, + Locale aLocale) + { + BreakIterator bit = BreakIterator.getLineInstance(aLocale); + String[] lines = text.split("\n"); + int length = leftMargin; + String leftPadding = FILLER.substring(0, leftMargin + 2); + for (int i = 0; i < lines.length; i++) + { + text = lines[i]; + bit.setText(text); + int start = bit.first(); + int finish; + while ((finish = bit.next()) != BreakIterator.DONE) + { + String word = text.substring(start, finish); + length += word.length(); + if (length >= Parser.MAX_LINE_LENGTH) + { + out.println(); + out.print(leftPadding); + length = word.length() + leftMargin + 2; + } + out.print(word); + start = finish; + } + out.println(); + if (i != lines.length - 1) + { + length = leftMargin + 2; + out.print(leftPadding); + } + } + } + + /** + * Add an option to this option group. + * + * @param opt the option to add + */ + public void add(Option opt) + { + options.add(opt); + } + + /** + * Print the help output for this option group. + * + * @param out the stream to which to print + */ + public void printHelp(PrintStream out, boolean longOnly) + { + // Compute maximum lengths. + int maxArgLen = 0; + boolean shortOptionSeen = false; + Iterator it; + + // The first pass only looks to see if we have a short option. + it = options.iterator(); + while (it.hasNext()) + { + Option option = (Option) it.next(); + if (option.getShortName() != '\0') + { + shortOptionSeen = true; + break; + } + } + + it = options.iterator(); + while (it.hasNext()) + { + Option option = (Option) it.next(); + String argName = option.getArgumentName(); + // First compute the width required for the short + // option. "2" is the initial indentation. In the + // GNU style we don't print an argument name for + // a short option if there is also a long name for + // the option. + int thisArgLen = 2; + if (shortOptionSeen) + thisArgLen += 4; + if (option.getLongName() != null) + { + // Handle either '-' or '--'. + thisArgLen += 1 + option.getLongName().length(); + if (! longOnly) + ++thisArgLen; + } + // Add in the width of the argument name. + if (argName != null) + thisArgLen += 1 + argName.length(); + maxArgLen = Math.max(maxArgLen, thisArgLen); + } + + // Print the help. + if (name != null) + out.println(name + ":"); + it = options.iterator(); + while (it.hasNext()) + { + Option option = (Option) it.next(); + String argName = option.getArgumentName(); + int column = 0; + if (option.getShortName() != '\0') + { + out.print(" -"); + out.print(option.getShortName()); + column += 4; + if (option.getLongName() == null) + { + if (argName != null) + { + // This is a silly hack just for '-J'. We don't + // support joined options in general, but this option + // is filtered out before argument processing can see it. + if (option.getShortName() != 'J') + { + out.print(' '); + ++column; + } + out.print(argName); + column += argName.length(); + } + out.print(" "); + } + else + out.print(", "); + column += 2; + } + // Indent the long option past the short options, if one + // was seen. + for (; column < (shortOptionSeen ? 6 : 2); ++column) + out.print(' '); + if (option.getLongName() != null) + { + out.print(longOnly ? "-" : "--"); + out.print(option.getLongName()); + column += (longOnly ? 1 : 2) + option.getLongName().length(); + if (argName != null) + { + out.print(" " + argName); + column += 1 + argName.length(); + } + } + // FIXME: should have a better heuristic for padding. + out.print(FILLER.substring(0, maxArgLen + 4 - column)); + formatText(out, option.getDescription(), maxArgLen + 4); + } + } +} diff --git a/tools/gnu/classpath/tools/getopt/Parser.java b/tools/gnu/classpath/tools/getopt/Parser.java new file mode 100644 index 000000000..082cf8945 --- /dev/null +++ b/tools/gnu/classpath/tools/getopt/Parser.java @@ -0,0 +1,454 @@ +/* Parser.java - parse command line options + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.getopt; + +import java.io.PrintStream; +import java.text.BreakIterator; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Locale; + +/** + * An instance of this class is used to parse command-line options. It does "GNU + * style" argument recognition and also automatically handles "--help" and + * "--version" processing. It can also be put in "long option only" mode. In + * this mode long options are recognized with a single dash (as well as a double + * dash) and strings of options like "-abc" are never parsed as a collection of + * short options. + */ +public class Parser +{ + /** The maximum right column position. */ + public static final int MAX_LINE_LENGTH = 80; + + private String programName; + + private String headerText; + + private String footerText; + + private boolean longOnly; + + private ArrayList options = new ArrayList(); + + private ArrayList optionGroups = new ArrayList(); + + private OptionGroup defaultGroup = new OptionGroup(); + + // These are used while parsing. + private int currentIndex; + + private String[] args; + + /** + * Create a new parser. The program name is used when printing error messages. + * The version string is printed verbatim in response to "--version". + * + * @param programName the name of the program + * @param versionString the program's version information + */ + public Parser(String programName, String versionString) + { + this(programName, versionString, false); + } + + /** + * Print a designated text to a {@link PrintStream}, eventually wrapping the + * lines of text so as to ensure that the width of each line does not overflow + * {@link #MAX_LINE_LENGTH} columns. The line-wrapping is done with a + * {@link BreakIterator} using the default {@link Locale}. + * <p> + * The text to print may contain <code>\n</code> characters. This method will + * force a line-break for each such character. + * + * @param out the {@link PrintStream} destination of the formatted text. + * @param text the text to print. + * @see Parser#MAX_LINE_LENGTH + */ + protected static void formatText(PrintStream out, String text) + { + formatText(out, text, Locale.getDefault()); + } + + /** + * Similar to the method with the same name and two arguments, except that the + * caller MUST specify a non-null {@link Locale} instance. + * <p> + * Print a designated text to a {@link PrintStream}, eventually wrapping the + * lines of text so as to ensure that the width of each line does not overflow + * {@link #MAX_LINE_LENGTH} columns. The line-wrapping is done with a + * {@link BreakIterator} using the designated {@link Locale}. + * <p> + * The text to print may contain <code>\n</code> characters. This method will + * force a line-break for each such character. + * + * @param out the {@link PrintStream} destination of the formatted text. + * @param text the text to print. + * @param aLocale the {@link Locale} instance to use when constructing the + * {@link BreakIterator}. + * @see Parser#MAX_LINE_LENGTH + */ + protected static void formatText(PrintStream out, String text, Locale aLocale) + { + BreakIterator bit = BreakIterator.getLineInstance(aLocale); + String[] lines = text.split("\n"); //$NON-NLS-1$ + for (int i = 0; i < lines.length; i++) + { + text = lines[i]; + bit.setText(text); + int length = 0; + int finish; + int start = bit.first(); + while ((finish = bit.next()) != BreakIterator.DONE) + { + String word = text.substring(start, finish); + length += word.length(); + if (length >= MAX_LINE_LENGTH) + { + out.println(); + length = word.length(); + } + out.print(word); + start = finish; + } + out.println(); + } + } + + /** + * Create a new parser. The program name is used when printing error messages. + * The version string is printed verbatim in response to "--version". + * + * @param programName the name of the program + * @param versionString the program's version information + * @param longOnly true if the parser should work in long-option-only mode + */ + public Parser(String programName, final String versionString, boolean longOnly) + { + this.programName = programName; + this.longOnly = longOnly; + + // Put standard options in their own section near the end. + OptionGroup finalGroup = new OptionGroup(Messages.getString("Parser.StdOptions")); //$NON-NLS-1$ + finalGroup.add(new Option("help", Messages.getString("Parser.PrintHelp")) //$NON-NLS-1$ //$NON-NLS-2$ + { + public void parsed(String argument) throws OptionException + { + printHelp(System.out); + System.exit(0); + } + }); + finalGroup.add(new Option("version", Messages.getString("Parser.PrintVersion")) //$NON-NLS-1$ //$NON-NLS-2$ + { + public void parsed(String argument) throws OptionException + { + System.out.println(versionString); + System.exit(0); + } + }); + finalGroup.add(new Option('J', Messages.getString("Parser.JArgument"), Messages.getString("Parser.JName")) //$NON-NLS-1$ //$NON-NLS-2$ + { + public void parsed(String argument) throws OptionException + { + // -J should be handled by the appletviewer wrapper binary. + // We add it here so that it shows up in the --help output. + // Note that there is a special case for this in OptionGroup. + } + }); + add(finalGroup); + + add(defaultGroup); + } + + /** + * Set the header text that is printed by --help. + * + * @param headerText the header text + */ + public void setHeader(String headerText) + { + this.headerText = headerText; + } + + /** + * Set the footer text that is printed by --help. + * + * @param footerText the footer text + */ + public void setFooter(String footerText) + { + this.footerText = footerText; + } + + /** + * Add an option to this parser. The option is added to the default option + * group; this affects where it is placed in the help output. + * + * @param opt the option + */ + public synchronized void add(Option opt) + { + options.add(opt); + defaultGroup.add(opt); + } + + /** + * Add an option group to this parser. All the options in this group will be + * recognized by the parser. + * + * @param group the option group + */ + public synchronized void add(OptionGroup group) + { + options.addAll(group.options); + // This ensures that the final group always appears at the end + // of the options. + if (optionGroups.isEmpty()) + optionGroups.add(group); + else + optionGroups.add(optionGroups.size() - 1, group); + } + + public void printHelp() + { + this.printHelp(System.out); + } + + void printHelp(PrintStream out) + { + if (headerText != null) + { + formatText(out, headerText); + out.println(); + } + + Iterator it = optionGroups.iterator(); + while (it.hasNext()) + { + OptionGroup group = (OptionGroup) it.next(); + // An option group might be empty, in which case we don't + // want to print it.. + if (! group.options.isEmpty()) + { + group.printHelp(out, longOnly); + out.println(); + } + } + + if (footerText != null) + formatText(out, footerText); + } + + /** + * This method can be overridden by subclassses to provide some option + * validation. It is called by the parser after all options have been + * parsed. If an option validation problem is encountered, this should + * throw an {@link OptionException} whose message should be shown to + * the user. + * <p> + * It is better to do validation here than after {@link #parse(String[])} + * returns, because the parser will print a message referring the + * user to the <code>--help</code> option. + * <p> + * The base implementation does nothing. + * + * @throws OptionException the error encountered + */ + protected void validate() throws OptionException + { + // Base implementation does nothing. + } + + private String getArgument(String request) throws OptionException + { + ++currentIndex; + if (currentIndex >= args.length) + { + String message + = MessageFormat.format(Messages.getString("Parser.ArgReqd"), //$NON-NLS-1$ + new Object[] { request }); + throw new OptionException(request); + } + return args[currentIndex]; + } + + private void handleLongOption(String real, int index) throws OptionException + { + String option = real.substring(index); + String justName = option; + int eq = option.indexOf('='); + if (eq != - 1) + justName = option.substring(0, eq); + Option found = null; + for (int i = options.size() - 1; i >= 0; --i) + { + Option opt = (Option) options.get(i); + if (justName.equals(opt.getLongName())) + { + found = opt; + break; + } + } + if (found == null) + { + String msg = MessageFormat.format(Messages.getString("Parser.Unrecognized"), //$NON-NLS-1$ + new Object[] { real }); + throw new OptionException(msg); + } + String argument = null; + if (found.getTakesArgument()) + { + if (eq == - 1) + argument = getArgument(real); + else + argument = option.substring(eq + 1); + } + else if (eq != - 1) + { + String msg + = MessageFormat.format(Messages.getString("Parser.NoArg"), //$NON-NLS-1$ + new Object[] { real.substring(0, eq + index) }); + throw new OptionException(msg); + } + found.parsed(argument); + } + + private void handleShortOption(char option) throws OptionException + { + Option found = null; + for (int i = options.size() - 1; i >= 0; --i) + { + Option opt = (Option) options.get(i); + if (option == opt.getShortName()) + { + found = opt; + break; + } + } + if (found == null) + { + String msg = MessageFormat.format(Messages.getString("Parser.UnrecDash"), //$NON-NLS-1$ + new Object[] { "" + option }); //$NON-NLS-1$ + throw new OptionException(msg); + } + String argument = null; + if (found.getTakesArgument()) + argument = getArgument("-" + option); //$NON-NLS-1$ + found.parsed(argument); + } + + private void handleShortOptions(String option) throws OptionException + { + for (int i = 1; i < option.length(); ++i) + { + handleShortOption(option.charAt(i)); + } + } + + /** + * Parse a command line. Any files which are found will be passed to the file + * argument callback. This method will exit on error or when --help or + * --version is specified. + * + * @param inArgs the command-line arguments + * @param files the file argument callback + */ + public synchronized void parse(String[] inArgs, FileArgumentCallback files) + { + try + { + args = inArgs; + for (currentIndex = 0; currentIndex < args.length; ++currentIndex) + { + if (args[currentIndex].length() == 0 + || args[currentIndex].charAt(0) != '-' + || "-".equals(args[currentIndex])) //$NON-NLS-1$ + { + files.notifyFile(args[currentIndex]); + continue; + } + if ("--".equals(args[currentIndex])) //$NON-NLS-1$ + break; + if (args[currentIndex].charAt(1) == '-') + handleLongOption(args[currentIndex], 2); + else if (longOnly) + handleLongOption(args[currentIndex], 1); + else + handleShortOptions(args[currentIndex]); + } + // Add remaining arguments to leftovers. + for (++currentIndex; currentIndex < args.length; ++currentIndex) + files.notifyFile(args[currentIndex]); + // See if something went wrong. + validate(); + } + catch (OptionException err) + { + System.err.println(programName + ": " + err.getMessage()); //$NON-NLS-1$ + String fmt; + if (longOnly) + fmt = Messages.getString("Parser.TryHelpShort"); //$NON-NLS-1$ + else + fmt = Messages.getString("Parser.TryHelpLong"); //$NON-NLS-1$ + String msg = MessageFormat.format(fmt, new Object[] { programName }); + System.err.println(programName + ": " + msg); //$NON-NLS-1$ + System.exit(1); + } + } + + /** + * Parse a command line. Any files which are found will be returned. This + * method will exit on error or when --help or --version is specified. + * + * @param inArgs the command-line arguments + */ + public String[] parse(String[] inArgs) + { + final ArrayList fileResult = new ArrayList(); + parse(inArgs, new FileArgumentCallback() + { + public void notifyFile(String fileArgument) + { + fileResult.add(fileArgument); + } + }); + return (String[]) fileResult.toArray(new String[0]); + } +} diff --git a/tools/gnu/classpath/tools/giop/GRMIC.java b/tools/gnu/classpath/tools/giop/GRMIC.java index a372cfd66..c910d7083 100644 --- a/tools/gnu/classpath/tools/giop/GRMIC.java +++ b/tools/gnu/classpath/tools/giop/GRMIC.java @@ -104,6 +104,17 @@ public class GRMIC else HelpPrinter.printHelpAndExit(HelpPath); } + else if (c.equals("-classpath")) + { + int f = i + 1; + if (f < args.length) + { + compiler.setClassPath(args[f]); + i++; + } + else + HelpPrinter.printHelpAndExit(HelpPath); + } else if (c.charAt(0) != '-') // No more options - start of class list. { @@ -124,17 +135,7 @@ public class GRMIC if (args[i].charAt(0) != '-') { compiler.reset(); - Class c = null; - try - { - c = Thread.currentThread().getContextClassLoader().loadClass( - args[i]); - } - catch (ClassNotFoundException e) - { - System.err.println(args[i] + " class not found."); - System.exit(1); - } + Class c = compiler.loadClass(args[i]); compiler.compile(c); String packag = compiler.getPackageName().replace('.', '/'); diff --git a/tools/gnu/classpath/tools/giop/GRMIC.txt b/tools/gnu/classpath/tools/giop/GRMIC.txt index 08aaf148f..875bcdbcf 100644 --- a/tools/gnu/classpath/tools/giop/GRMIC.txt +++ b/tools/gnu/classpath/tools/giop/GRMIC.txt @@ -9,18 +9,20 @@ Please report bugs at http://www.gnu.org/software/classpath/bugs.html Usage: grmic <options> <class names> where <options> includes: - -poa Generate the Servant based ties (default) - -impl Generate the obsoleted ObjectImpl based ties - (for backward compatibility) - -nowarn Show no warnings - -nowrite Do not write any files (check for errors only) - -d <folder> Place generated files into the given folder + -poa Generate the Servant based ties (default) + -impl Generate the obsoleted ObjectImpl based ties + (for backward compatibility) + -nowarn Show no warnings + -nowrite Do not write any files (check for errors only) + -d <folder> Place generated files into the given folder + -classpath <path> Specifies the path, where to find the classes being + compiled - -help Print this help text - -v Print version - -verbose Verbose output - -force Try to generate code even if the input classes seem not - consistent with RMI specification. + -help Print this help text + -v Print version + -verbose Verbose output + -force Try to generate code even if the input classes seem not + consistent with RMI specification. and <class names> can include one or more non abstract classes that implement diff --git a/tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java b/tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java index 4beba1c9f..6d895a14c 100644 --- a/tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java +++ b/tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java @@ -23,7 +23,11 @@ package gnu.classpath.tools.giop.grmic; import gnu.classpath.tools.AbstractMethodGenerator; +import java.io.File; import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; import java.rmi.Remote; import java.rmi.RemoteException; import java.util.ArrayList; @@ -33,6 +37,7 @@ import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.Properties; +import java.util.StringTokenizer; import java.util.TreeSet; /** @@ -104,6 +109,11 @@ public class GiopRmicCompiler * Force mode - do not check the exceptions */ protected boolean force = false; + + /** + * The class loader to load the class being compiled. + */ + ClassLoader classLoader; /** * Clear data, preparing for the next compilation. @@ -116,6 +126,78 @@ public class GiopRmicCompiler methods.clear(); vars.clear(); } + + /** + * Set the class path (handle the -classpath key) + * + * @param classPath the class path to set. + */ + public void setClassPath(String classPath) + { + classLoader = Thread.currentThread().getContextClassLoader(); + StringTokenizer tok = new StringTokenizer(classPath, File.pathSeparator, + true); + ArrayList urls = new ArrayList(tok.countTokens()); + String s = null; + try + { + while (tok.hasMoreTokens()) + { + s = tok.nextToken(); + if (s.equals(File.pathSeparator)) + urls.add(new File(".").toURL()); + else + { + urls.add(new File(s).toURL()); + if (tok.hasMoreTokens()) + { + // Skip the separator. + tok.nextToken(); + // If the classpath ended with a separator, + // append the current directory. + if (! tok.hasMoreTokens()) + urls.add(new File(".").toURL()); + } + } + } + } + catch (MalformedURLException ex) + { + System.err.println("Malformed path '" + s + "' in classpath '" + + classPath + "'"); + System.exit(1); + } + URL[] u = new URL[urls.size()]; + for (int i = 0; i < u.length; i++) + { + u[i] = (URL) urls.get(i); + } + + classLoader = new URLClassLoader(u, classLoader); + } + + /** + * Loads the class with the given name (uses class path, if applicable) + * + * @param name the name of the class. + */ + public Class loadClass(String name) + { + ClassLoader loader = classLoader; + if (loader == null) + loader = Thread.currentThread().getContextClassLoader(); + try + { + return loader.loadClass(name); + } + catch (ClassNotFoundException e) + { + System.err.println(name+" not found on "+loader); + System.exit(1); + // Unreacheable code. + return null; + } + } /** * Compile the given class (the instance of Remote), generating the stub and @@ -193,12 +275,12 @@ public class GiopRmicCompiler remEx = true; break; } - if (! remEx && !force) - throw new CompilationError(m[i].getName() + ", defined in " - + c.getName() - + ", does not throw " - + RemoteException.class.getName()); - } + } + if (! remEx && !force) + throw new CompilationError(m[i].getName() + ", defined in " + + c.getName() + + ", does not throw " + + RemoteException.class.getName()); AbstractMethodGenerator mm = createMethodGenerator(m[i]); methods.add(mm); } diff --git a/tools/gnu/classpath/tools/jar/Action.java b/tools/gnu/classpath/tools/jar/Action.java new file mode 100644 index 000000000..6363157ae --- /dev/null +++ b/tools/gnu/classpath/tools/jar/Action.java @@ -0,0 +1,51 @@ +/* Action.java - an action taken by the jar driver + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.jar; + +import java.io.IOException; + +public abstract class Action +{ + protected Action() + { + } + + public abstract void run(Main parameters) + throws IOException; +} diff --git a/tools/gnu/classpath/tools/jar/Creator.java b/tools/gnu/classpath/tools/jar/Creator.java new file mode 100644 index 000000000..55159660d --- /dev/null +++ b/tools/gnu/classpath/tools/jar/Creator.java @@ -0,0 +1,247 @@ +/* Creator.java - create a new jar file + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.jar; + +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; +import java.util.zip.CRC32; +import java.util.zip.ZipEntry; + +public class Creator + extends Action +{ + JarOutputStream outputStream; + HashSet writtenItems = new HashSet(); + // The manifest to use, or null if we don't want a manifest. + Manifest manifest; + + private long copyFile(CRC32 crc, InputStream is, OutputStream output) + throws IOException + { + byte[] buffer = new byte[1024]; + long size = 0; + while (true) + { + int len = is.read(buffer); + if (len == - 1) + break; + size += len; + output.write(buffer, 0, len); + crc.update(buffer, 0, len); + } + output.close(); + return size; + } + + protected void writeFile(boolean isDirectory, InputStream inputFile, + String filename, boolean verbose) + throws IOException + { + if (writtenItems.contains(filename)) + { + if (verbose) + { + String msg = MessageFormat.format(Messages.getString("Creator.Ignoring"), //$NON-NLS-1$ + new Object[] { filename }); + System.err.println(msg); + } + return; + } + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + CRC32 crc = new CRC32(); + long size; + if (isDirectory) + { + size = 0; + } + else + { + size = copyFile(crc, inputFile, out); + } + + ZipEntry entry = new ZipEntry(filename); + entry.setCrc(crc.getValue()); + entry.setSize(size); + + outputStream.putNextEntry(entry); + out.writeTo(outputStream); + outputStream.closeEntry(); + writtenItems.add(filename); + + if (verbose) + { + long csize = entry.getCompressedSize(); + long perc; + if (size == 0) + perc = 0; + else + perc = 100 - (100 * csize) / size; + String msg = MessageFormat.format(Messages.getString("Creator.Adding"), //$NON-NLS-1$ + new Object[] + { + filename, + Long.valueOf(size), + Long.valueOf(entry.getSize()), + Long.valueOf(perc) + }); + System.err.println(msg); + } + } + + protected void writeFile(File file, String filename, boolean verbose) + throws IOException + { + boolean isDirectory = file.isDirectory(); + InputStream inputStream = null; + if (isDirectory) + { + if (filename.charAt(filename.length() - 1) != '/') + filename += '/'; + } + else + inputStream = new FileInputStream(file); + writeFile(isDirectory, inputStream, filename, verbose); + } + + private void addEntries(ArrayList result, Entry entry) + { + if (entry.file.isDirectory()) + { + String name = entry.name; + if (name.charAt(name.length() - 1) != '/') + { + name += '/'; + entry = new Entry(entry.file, name); + } + result.add(entry); + String[] files = entry.file.list(); + for (int i = 0; i < files.length; ++i) + addEntries(result, new Entry(new File(entry.file, files[i]), + entry.name + files[i])); + } + else + result.add(entry); + } + + private ArrayList getAllEntries(Main parameters) + { + Iterator it = parameters.entries.iterator(); + ArrayList allEntries = new ArrayList(); + while (it.hasNext()) + { + Entry entry = (Entry) it.next(); + addEntries(allEntries, entry); + } + return allEntries; + } + + private void writeCommandLineEntries(Main parameters) + throws IOException + { + // We've already written the manifest, make sure to mark it. + writtenItems.add("META-INF/"); //$NON-NLS-1$ + writtenItems.add(JarFile.MANIFEST_NAME); + + ArrayList allEntries = getAllEntries(parameters); + Iterator it = allEntries.iterator(); + while (it.hasNext()) + { + Entry entry = (Entry) it.next(); + writeFile(entry.file, entry.name, parameters.verbose); + } + } + + protected Manifest createManifest(Main parameters) + throws IOException + { + if (! parameters.wantManifest) + return null; + if (parameters.manifestFile != null) + { + // User specified a manifest file. + InputStream contents = new FileInputStream(parameters.manifestFile); + return new Manifest(contents); + } + return new Manifest(); + } + + protected void writeCommandLineEntries(Main parameters, OutputStream os) + throws IOException + { + manifest = createManifest(parameters); + outputStream = new JarOutputStream(os, manifest); + // FIXME: in Classpath this sets the method too late for the + // manifest file. + outputStream.setMethod(parameters.storageMode); + writeCommandLineEntries(parameters); + } + + protected void close() throws IOException + { + outputStream.finish(); + outputStream.close(); + } + + public void run(Main parameters) throws IOException + { + if (parameters.archiveFile == null || parameters.archiveFile.equals("-")) //$NON-NLS-1$ + writeCommandLineEntries(parameters, System.out); + else + { + OutputStream os + = new BufferedOutputStream(new FileOutputStream(parameters.archiveFile)); + writeCommandLineEntries(parameters, os); + } + close(); + } +} diff --git a/tools/gnu/classpath/tools/jar/Entry.java b/tools/gnu/classpath/tools/jar/Entry.java new file mode 100644 index 000000000..aa8679aab --- /dev/null +++ b/tools/gnu/classpath/tools/jar/Entry.java @@ -0,0 +1,60 @@ +/* Entry.java - represent a single file to write to a jar + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.jar; + +import java.io.File; + +public class Entry +{ + public File file; + + public String name; + + public Entry(File file, String name) + { + this.file = file; + this.name = name; + } + + public Entry(File file) + { + this.file = file; + this.name = file.toString(); + } +} diff --git a/tools/gnu/classpath/tools/jar/Extractor.java b/tools/gnu/classpath/tools/jar/Extractor.java new file mode 100644 index 000000000..ed647cbfe --- /dev/null +++ b/tools/gnu/classpath/tools/jar/Extractor.java @@ -0,0 +1,164 @@ +/* Extractor.java - action to extract from a jar file + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.jar; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +public class Extractor + extends Action +{ + // This is a set of all the items specified on the command line. + // It is null if none were specified. + private HashSet allItems; + + private void copyFile(InputStream input, File output) throws IOException + { + FileOutputStream os = new FileOutputStream(output); + byte[] buffer = new byte[1024]; + while (true) + { + int len = input.read(buffer); + if (len == - 1) + break; + os.write(buffer, 0, len); + } + os.close(); + } + + private void initSet(ArrayList entries) + { + if (entries == null || entries.isEmpty()) + return; + allItems = new HashSet(); + Iterator it = entries.iterator(); + while (it.hasNext()) + { + Entry entry = (Entry) it.next(); + int len = entry.name.length(); + while (len > 0 && entry.name.charAt(len - 1) == '/') + --len; + String name = entry.name.substring(0, len); + allItems.add(name); + } + } + + private boolean shouldExtract(String filename) + { + if (allItems == null) + return true; + while (filename.length() > 0) + { + if (allItems.contains(filename)) + return true; + int index = filename.lastIndexOf('/'); + if (index == -1) + break; + filename = filename.substring(0, index); + } + return false; + } + + public void run(Main parameters) throws IOException + { + // Figure out what we want to extract. + initSet(parameters.entries); + // Open the input file. + ZipInputStream zis; + File zfile = parameters.archiveFile; + if (zfile == null || "-".equals(zfile.getName())) //$NON-NLS-1$ + zis = new ZipInputStream(System.in); + else + { + InputStream ins = new BufferedInputStream(new FileInputStream(zfile)); + zis = new ZipInputStream(ins); + } + // Extract stuff. + while (true) + { + ZipEntry entry = zis.getNextEntry(); + if (entry == null) + break; + if (! shouldExtract(entry.getName())) + continue; + File file = new File(entry.getName()); + if (entry.isDirectory()) + { + if (file.mkdirs()) + { + if (parameters.verbose) + { + String msg + = MessageFormat.format(Messages.getString("Extractor.Created"), //$NON-NLS-1$ + new Object[] { file }); + System.err.println(msg); + } + } + continue; + } + + File parent = file.getParentFile(); + if (parent != null) + parent.mkdirs(); + + copyFile(zis, file); + + if (parameters.verbose) + { + String fmt; + if (entry.getMethod() == ZipEntry.STORED) + fmt = Messages.getString("Extractor.Extracted"); //$NON-NLS-1$ + else + fmt = Messages.getString("Extractor.Inflated"); //$NON-NLS-1$ + String msg = MessageFormat.format(fmt, new Object[] { file }); + System.err.println(msg); + } + } + } +} diff --git a/tools/gnu/classpath/tools/jar/Indexer.java b/tools/gnu/classpath/tools/jar/Indexer.java new file mode 100644 index 000000000..aae25f821 --- /dev/null +++ b/tools/gnu/classpath/tools/jar/Indexer.java @@ -0,0 +1,144 @@ +/* Indexer.java -- add index.list file to jar + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.classpath.tools.jar; + +import gnu.java.net.IndexListParser; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.text.MessageFormat; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.StringTokenizer; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + +public class Indexer + extends Updater +{ + private void indexJarFile(StringBuffer result, File fileName, + boolean verbose) + throws IOException + { + if (verbose) + { + String msg = MessageFormat.format(Messages.getString("Indexer.Indexing"), //$NON-NLS-1$ + new Object[] { fileName }); + System.err.println(msg); + } + JarFile jf = new JarFile(fileName); + + // Index the files in this jar. + // The results look a little better if we keep them + // in insertion order. + LinkedHashSet entries = new LinkedHashSet(); + Enumeration e = jf.entries(); + while (e.hasMoreElements()) + { + JarEntry entry = (JarEntry) e.nextElement(); + String name = entry.getName(); + if (name.startsWith("META-INF/")) //$NON-NLS-1$ + continue; + int index = name.lastIndexOf('/'); + if (index != -1) + name = name.substring(0, index); + entries.add(name); + } + if (! entries.isEmpty()) + { + result.append(fileName); + // Any line ending will do. + result.append('\n'); + Iterator i = entries.iterator(); + while (i.hasNext()) + { + result.append(i.next()); + result.append('\n'); + } + // Paragraph break. + result.append('\n'); + } + + // Now read pointed-to jars. + Manifest m = jf.getManifest(); + if (m != null) + { + File parent = fileName.getParentFile(); + Attributes attrs = m.getMainAttributes(); + String jars = attrs.getValue(Attributes.Name.CLASS_PATH); + if (jars != null) + { + StringTokenizer st = new StringTokenizer(jars, " "); //$NON-NLS-1$ + while (st.hasMoreTokens()) + { + String name = st.nextToken(); + indexJarFile(result, new File(parent, name), verbose); + } + } + } + + jf.close(); + } + + protected void writeCommandLineEntries(Main parameters, OutputStream os) + throws IOException + { + // This is a pretty lame design. We know the super call will + // only have side effects and won't actually write anything important. + super.writeCommandLineEntries(parameters, os); + + // Now compute our index file and write it. + StringBuffer contents = new StringBuffer(); + indexJarFile(contents, parameters.archiveFile, parameters.verbose); + if (contents.length() != 0) + { + // Insert in reverse order to avoid computing anything. + contents.insert(0, "1.0\n\n"); //$NON-NLS-1$ + contents.insert(0, IndexListParser.JAR_INDEX_VERSION_KEY); + ByteArrayInputStream in + = new ByteArrayInputStream(contents.toString().getBytes()); + writeFile(false, in, IndexListParser.JAR_INDEX_FILE, parameters.verbose); + } + } +} diff --git a/tools/gnu/classpath/tools/jar/Lister.java b/tools/gnu/classpath/tools/jar/Lister.java new file mode 100644 index 000000000..ee4fb725e --- /dev/null +++ b/tools/gnu/classpath/tools/jar/Lister.java @@ -0,0 +1,90 @@ +/* Lister.java - action to list contents of a jar file + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.jar; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Date; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +public class Lister + extends Action +{ + private void listJar(ZipInputStream zis, boolean verbose) throws IOException + { + MessageFormat format = null; + if (verbose) + format = new MessageFormat(" {0,date,E M dd HH:mm:ss z yyyy} {1}"); + while (true) + { + ZipEntry entry = zis.getNextEntry(); + if (entry == null) + break; + if (verbose) + { + // No easy way to right-justify the size using + // MessageFormat -- how odd. + long size = entry.getSize(); + String s = " " + size; + int index = Math.min(s.length() - 5, 5); + System.out.print(s.substring(index)); + Object[] values = new Object[] { new Date(entry.getTime()), + entry.getName() }; + System.out.println(format.format(values)); + } + else + System.out.println(entry.getName()); + } + } + + public void run(Main parameters) throws IOException + { + File file = parameters.archiveFile; + ZipInputStream zis; + if (file == null || "-".equals(file.getName())) + zis = new ZipInputStream(System.in); + else + zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(file))); + listJar(zis, parameters.verbose); + } +} diff --git a/tools/gnu/classpath/tools/jar/Main.java b/tools/gnu/classpath/tools/jar/Main.java new file mode 100644 index 000000000..8ea770bb6 --- /dev/null +++ b/tools/gnu/classpath/tools/jar/Main.java @@ -0,0 +1,266 @@ +/* Main.java - jar program main() + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.jar; + +import gnu.classpath.tools.getopt.ClasspathToolParser; +import gnu.classpath.tools.getopt.FileArgumentCallback; +import gnu.classpath.tools.getopt.Option; +import gnu.classpath.tools.getopt.OptionException; +import gnu.classpath.tools.getopt.OptionGroup; +import gnu.classpath.tools.getopt.Parser; + +import java.io.File; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.zip.ZipOutputStream; + +public class Main +{ + /** The mode of operation. This is the class representing + * the action; we make a new instance before using it. It + * must be a subclass of Action. 'null' means the mode + * has not yet been set. */ + Class operationMode; + + /** The archive file name. */ + File archiveFile; + + /** The zip storage mode. */ + int storageMode = ZipOutputStream.DEFLATED; + + /** True if we should read file names from stdin. */ + boolean readNamesFromStdin = false; + + /** True for verbose mode. */ + boolean verbose = false; + + /** True if we want a manifest file. */ + boolean wantManifest = true; + + /** Name of manifest file to use. */ + File manifestFile; + + /** A list of Entry objects, each describing a file to write. */ + ArrayList entries = new ArrayList(); + + /** Used only while parsing, holds the first argument for -C. */ + String changedDirectory; + + void setArchiveFile(String filename) throws OptionException + { + if (archiveFile != null) + { + String fmt = MessageFormat.format(Messages.getString("Main.ArchiveAlreadySet"), //$NON-NLS-1$ + new Object[] { archiveFile }); + throw new OptionException(fmt); + } + archiveFile = new File(filename); + } + + class HandleFile + extends FileArgumentCallback + { + public void notifyFile(String fileArgument) + { + Entry entry; + if (changedDirectory != null) + { + entry = new Entry(new File(changedDirectory, fileArgument), + fileArgument); + changedDirectory = null; + } + else + entry = new Entry(new File(fileArgument)); + entries.add(entry); + } + } + + // An option that knows how to set the operation mode. + private class ModeOption + extends Option + { + private Class mode; + + public ModeOption(char shortName, String description, Class mode) + { + super(shortName, description); + this.mode = mode; + } + + public ModeOption(char shortName, String description, String argName, + Class mode) + { + super(shortName, description, argName); + this.mode = mode; + } + + public void parsed(String argument) throws OptionException + { + if (operationMode != null) + throw new OptionException(Messages.getString("Main.ModeAlreaySet")); //$NON-NLS-1$ + operationMode = mode; + // We know this is only the case for -i. + if (argument != null) + setArchiveFile(argument); + } + } + + private class JarParser extends ClasspathToolParser + { + public JarParser(String name) + { + super(name); + } + + protected void validate() throws OptionException + { + if (operationMode == null) + throw new OptionException(Messages.getString("Main.MustSpecify")); //$NON-NLS-1$ + if (changedDirectory != null) + throw new OptionException(Messages.getString("Main.TwoArgsReqd")); //$NON-NLS-1$ + if (! wantManifest && manifestFile != null) + throw new OptionException(Messages.getString("Main.CantHaveBoth")); //$NON-NLS-1$ + if (operationMode == Indexer.class) + { + // Some extra validation for -i. + if (! entries.isEmpty()) + throw new OptionException(Messages.getString("Main.NoFilesWithi")); //$NON-NLS-1$ + if (! wantManifest) + throw new OptionException(Messages.getString("Main.NoMAndi")); //$NON-NLS-1$ + if (manifestFile != null) + throw new OptionException(Messages.getString("Main.AnotherNomAndi")); //$NON-NLS-1$ + } + } + } + + private Parser initializeParser() + { + Parser p = new JarParser("jar"); //$NON-NLS-1$ + p.setHeader(Messages.getString("Main.Usage")); //$NON-NLS-1$ + + OptionGroup grp = new OptionGroup(Messages.getString("Main.OpMode")); //$NON-NLS-1$ + grp.add(new ModeOption('c', Messages.getString("Main.Create"), Creator.class)); //$NON-NLS-1$ + grp.add(new ModeOption('x', Messages.getString("Main.Extract"), Extractor.class)); //$NON-NLS-1$ + grp.add(new ModeOption('t', Messages.getString("Main.List"), Lister.class)); //$NON-NLS-1$ + grp.add(new ModeOption('u', Messages.getString("Main.Update"), Updater.class)); //$NON-NLS-1$ + // Note that -i works in-place and explicitly requires a file name. + grp.add(new ModeOption('i', Messages.getString("Main.Index"), Messages.getString("Main.FileArg"), Indexer.class)); //$NON-NLS-1$ //$NON-NLS-2$ + p.add(grp); + + grp = new OptionGroup(Messages.getString("Main.OpMods")); //$NON-NLS-1$ + grp.add(new Option('f', Messages.getString("Main.ArchiveName"), Messages.getString("Main.FileArg2")) //$NON-NLS-1$ //$NON-NLS-2$ + { + public void parsed(String argument) throws OptionException + { + setArchiveFile(argument); + } + }); + grp.add(new Option('0', Messages.getString("Main.NoZip")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + storageMode = ZipOutputStream.STORED; + } + }); + grp.add(new Option('v', Messages.getString("Main.Verbose")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + verbose = true; + } + }); + grp.add(new Option('M', Messages.getString("Main.NoManifest")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + wantManifest = false; + } + }); + grp.add(new Option('m', Messages.getString("Main.ManifestName"), Messages.getString("Main.ManifestArgName")) //$NON-NLS-1$ //$NON-NLS-2$ + { + public void parsed(String argument) throws OptionException + { + manifestFile = new File(argument); + } + }); + // -@ + p.add(grp); + + grp = new OptionGroup(Messages.getString("Main.FileNameGroup")); //$NON-NLS-1$ + grp.add(new Option('C', Messages.getString("Main.ChangeDir"), //$NON-NLS-1$ + Messages.getString("Main.ChangeDirArg")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + changedDirectory = argument; + } + }); + p.add(grp); + + return p; + } + + private void run(String[] args) + throws InstantiationException, IllegalAccessException, IOException + { + Parser p = initializeParser(); + // Special hack to emulate old tar-style commands. + if (args.length > 0 && args[0].charAt(0) != '-') + args[0] = '-' + args[0]; + p.parse(args, new HandleFile()); + Action t = (Action) operationMode.newInstance(); + t.run(this); + } + + public static void main(String[] args) + { + Main jarprogram = new Main(); + try + { + jarprogram.run(args); + } + catch (Exception e) + { + System.err.println(Messages.getString("Main.InternalError")); //$NON-NLS-1$ + e.printStackTrace(System.err); + System.exit(1); + } + } +} diff --git a/tools/gnu/classpath/tools/jar/Messages.java b/tools/gnu/classpath/tools/jar/Messages.java new file mode 100644 index 000000000..ea54bd08f --- /dev/null +++ b/tools/gnu/classpath/tools/jar/Messages.java @@ -0,0 +1,67 @@ +/* Messages.java -- localization support for jar + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.jar; + +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +public class Messages +{ + private static final String BUNDLE_NAME + = "gnu.classpath.tools.jar.messages"; //$NON-NLS-1$ + + private static final ResourceBundle RESOURCE_BUNDLE + = ResourceBundle.getBundle(BUNDLE_NAME); + + private Messages() + { + } + + public static String getString(String key) + { + try + { + return RESOURCE_BUNDLE.getString(key); + } + catch (MissingResourceException e) + { + return '!' + key + '!'; + } + } +} diff --git a/tools/gnu/classpath/tools/jar/Updater.java b/tools/gnu/classpath/tools/jar/Updater.java new file mode 100644 index 000000000..29586befd --- /dev/null +++ b/tools/gnu/classpath/tools/jar/Updater.java @@ -0,0 +1,91 @@ +/* Updater.java - action to update a jar file + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.jar; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Enumeration; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.zip.ZipEntry; + +public class Updater + extends Creator +{ + JarFile inputJar; + + protected Manifest createManifest(Main parameters) throws IOException + { + Manifest result = inputJar.getManifest(); + if (result == null) + return super.createManifest(parameters); + if (parameters.manifestFile != null) + result.read(new FileInputStream(parameters.manifestFile)); + return result; + } + + public void run(Main parameters) throws IOException + { + // Set this early so that createManifest can use it. + inputJar = new JarFile(parameters.archiveFile); + + // Write all the new entries to a temporary file. + File tmpFile = File.createTempFile("jarcopy", null); + OutputStream os = new BufferedOutputStream(new FileOutputStream(tmpFile)); + writeCommandLineEntries(parameters, os); + + // Now read the old file and copy extra entries to the new file. + Enumeration e = inputJar.entries(); + while (e.hasMoreElements()) + { + ZipEntry entry = (ZipEntry) e.nextElement(); + if (writtenItems.contains(entry.getName())) + continue; + writeFile(entry.isDirectory(), inputJar.getInputStream(entry), + entry.getName(), parameters.verbose); + } + + close(); + tmpFile.renameTo(parameters.archiveFile); + } +} diff --git a/tools/gnu/classpath/tools/jarsigner/JarSigner.java b/tools/gnu/classpath/tools/jarsigner/JarSigner.java index 40bee9fe9..8d3bc31af 100644 --- a/tools/gnu/classpath/tools/jarsigner/JarSigner.java +++ b/tools/gnu/classpath/tools/jarsigner/JarSigner.java @@ -141,7 +141,7 @@ public class JarSigner main.isInternalSF()); log.finer("Created .DSA file"); //$NON-NLS-1$ if (main.isVerbose()) - System.out.println(Messages.getString("JarSigner.11") + dsaFileName); //$NON-NLS-1$ + System.out.println(Messages.getString("JarSigner.8") + dsaFileName); //$NON-NLS-1$ // cleanup outSignedJarFile.close(); diff --git a/tools/gnu/classpath/tools/jarsigner/Main.java b/tools/gnu/classpath/tools/jarsigner/Main.java index f460a96cc..6928bce59 100644 --- a/tools/gnu/classpath/tools/jarsigner/Main.java +++ b/tools/gnu/classpath/tools/jarsigner/Main.java @@ -39,9 +39,13 @@ exception statement from your version. */ package gnu.classpath.tools.jarsigner; import gnu.classpath.SystemProperties; -import gnu.classpath.tools.HelpPrinter; import gnu.classpath.tools.common.CallbackUtil; import gnu.classpath.tools.common.ProviderUtil; +import gnu.classpath.tools.getopt.ClasspathToolParser; +import gnu.classpath.tools.getopt.FileArgumentCallback; +import gnu.classpath.tools.getopt.Option; +import gnu.classpath.tools.getopt.OptionException; +import gnu.classpath.tools.getopt.OptionGroup; import gnu.java.security.OID; import gnu.java.security.Registry; import gnu.javax.security.auth.callback.ConsoleCallbackHandler; @@ -61,6 +65,7 @@ import java.security.Security; import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateException; +import java.util.ArrayList; import java.util.Locale; import java.util.jar.Attributes.Name; import java.util.logging.Logger; @@ -81,8 +86,8 @@ import javax.security.auth.callback.UnsupportedCallbackException; */ public class Main { - private static final Logger log = Logger.getLogger(Main.class.getName()); - private static final String HELP_PATH = "jarsigner/jarsigner.txt"; //$NON-NLS-1$ + protected static final Logger log = Logger.getLogger(Main.class.getName()); + static final String KEYTOOL_TOOL = "jarsigner"; //$NON-NLS-1$ private static final Locale EN_US_LOCALE = new Locale("en", "US"); //$NON-NLS-1$ //$NON-NLS-2$ static final String DIGEST = "SHA1-Digest"; //$NON-NLS-1$ static final String DIGEST_MANIFEST = "SHA1-Digest-Manifest"; //$NON-NLS-1$ @@ -91,20 +96,20 @@ public class Main static final OID DSA_SIGNATURE_OID = new OID(Registry.DSA_OID_STRING); static final OID RSA_SIGNATURE_OID = new OID(Registry.RSA_OID_STRING); - private boolean verify; - private String ksURL; - private String ksType; - private String password; - private String ksPassword; - private String sigFileName; - private String signedJarFileName; - private boolean verbose; - private boolean certs; - private boolean internalSF; - private boolean sectionsOnly; - private String providerClassName; - private String jarFileName; - private String alias; + protected boolean verify; + protected String ksURL; + protected String ksType; + protected String password; + protected String ksPassword; + protected String sigFileName; + protected String signedJarFileName; + protected boolean verbose; + protected boolean certs; + protected boolean internalSF; + protected boolean sectionsOnly; + protected String providerClassName; + protected String jarFileName; + protected String alias; protected Provider provider; private boolean providerInstalled; @@ -115,6 +120,9 @@ public class Main private Certificate[] signerCertificateChain; /** The callback handler to use when needing to interact with user. */ private CallbackHandler handler; + /** The command line parser. */ + private ToolParser cmdLineParser; + protected ArrayList fileAndAlias = new ArrayList();; private Main() { @@ -126,10 +134,12 @@ public class Main log.entering(Main.class.getName(), "main", args); //$NON-NLS-1$ Main tool = new Main(); + int result = 1; try { tool.processArgs(args); tool.start(); + result = 0; } catch (SecurityException x) { @@ -141,11 +151,13 @@ public class Main log.throwing(Main.class.getName(), "main", x); //$NON-NLS-1$ System.err.println(Messages.getString("Main.9") + x); //$NON-NLS-1$ } + finally + { + tool.teardown(); + } - tool.teardown(); - - log.exiting(Main.class.getName(), "main"); //$NON-NLS-1$ - // System.exit(0); + log.exiting(Main.class.getName(), "main", Integer.valueOf(result)); //$NON-NLS-1$ + System.exit(result); } // helper methods ----------------------------------------------------------- @@ -155,65 +167,15 @@ public class Main * preparation for the user desired action. * * @param args an array of options (strings). - * @throws Exception if an exceptio occurs during the process. + * @throws Exception if an exception occurs during the process. */ private void processArgs(String[] args) throws Exception { log.entering(this.getClass().getName(), "processArgs", args); //$NON-NLS-1$ - HelpPrinter.checkHelpKey(args, HELP_PATH); - if (args == null || args.length == 0) - HelpPrinter.printHelpAndExit(HELP_PATH); - - int limit = args.length; - log.finest("args.length=" + limit); //$NON-NLS-1$ - int i = 0; - String opt; - while (i < limit) - { - opt = args[i++]; - log.finest("args[" + (i - 1) + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$ - if (opt == null || opt.length() == 0) - continue; - - if ("-verify".equals(opt)) // -verify //$NON-NLS-1$ - verify = true; - else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$ - ksURL = args[i++]; - else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$ - ksType = args[i++]; - else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$ - ksPassword = args[i++]; - else if ("-keypass".equals(opt)) // -keypass PASSWORD //$NON-NLS-1$ - password = args[i++]; - else if ("-sigfile".equals(opt)) // -sigfile NAME //$NON-NLS-1$ - sigFileName = args[i++]; - else if ("-signedjar".equals(opt)) // -signedjar FILE_NAME //$NON-NLS-1$ - signedJarFileName = args[i++]; - else if ("-verbose".equals(opt)) // -verbose //$NON-NLS-1$ - verbose = true; - else if ("-certs".equals(opt)) // -certs //$NON-NLS-1$ - certs = true; - else if ("-internalsf".equals(opt)) // -internalsf //$NON-NLS-1$ - internalSF = true; - else if ("-sectionsonly".equals(opt)) // -sectionsonly //$NON-NLS-1$ - sectionsOnly = true; - else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$ - providerClassName = args[i++]; - else - { - jarFileName = opt; - if (! verify) - alias = args[i++]; - - break; - } - } - - if (i < limit) // more options than needed - log.fine("Last argument is assumed at index #" + (i - 1) //$NON-NLS-1$ - + ". Remaining arguments (" + args[i] //$NON-NLS-1$ - + "...) will be ignored"); //$NON-NLS-1$ + cmdLineParser = new ToolParser(); + cmdLineParser.initializeParser(); + cmdLineParser.parse(args, new ToolParserCallback()); setupCommonParams(); if (verify) @@ -319,9 +281,6 @@ public class Main { log.entering(this.getClass().getName(), "setupCommonParams"); //$NON-NLS-1$ - if (jarFileName == null) - HelpPrinter.printHelpAndExit(HELP_PATH); - File jar = new File(jarFileName); if (! jar.exists()) throw new FileNotFoundException(jarFileName); @@ -429,9 +388,6 @@ public class Main InputStream stream = url.openStream(); store.load(stream, ksPasswordChars); - if (alias == null) - HelpPrinter.printHelpAndExit(HELP_PATH); - if (! store.containsAlias(alias)) throw new SecurityException(Messages.getFormattedString("Main.6", alias)); //$NON-NLS-1$ @@ -564,4 +520,155 @@ public class Main return handler; } + + private class ToolParserCallback + extends FileArgumentCallback + { + public void notifyFile(String fileArgument) + { + fileAndAlias.add(fileArgument); + } + } + + private class ToolParser + extends ClasspathToolParser + { + public ToolParser() + { + super(KEYTOOL_TOOL, true); + } + + protected void validate() throws OptionException + { + if (fileAndAlias.size() < 1) + throw new OptionException(Messages.getString("Main.133")); //$NON-NLS-1$ + + jarFileName = (String) fileAndAlias.get(0); + if (! verify) // must have an ALIAS. use "mykey" if undefined + if (fileAndAlias.size() < 2) + { + log.finer("Missing ALIAS argument. Will use [mykey] instead"); //$NON-NLS-1$ + alias = "mykey"; //$NON-NLS-1$ + } + else + alias = (String) fileAndAlias.get(1); + } + + public void initializeParser() + { + setHeader(Messages.getString("Main.2")); //$NON-NLS-1$ + setFooter(Messages.getString("Main.1")); //$NON-NLS-1$ + OptionGroup signGroup = new OptionGroup(Messages.getString("Main.0")); //$NON-NLS-1$ + signGroup.add(new Option("keystore", //$NON-NLS-1$ + Messages.getString("Main.101"), //$NON-NLS-1$ + Messages.getString("Main.102")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + ksURL = argument; + } + }); + signGroup.add(new Option("storetype", //$NON-NLS-1$ + Messages.getString("Main.104"), //$NON-NLS-1$ + Messages.getString("Main.105")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + ksType = argument; + } + }); + signGroup.add(new Option("storepass", //$NON-NLS-1$ + Messages.getString("Main.107"), //$NON-NLS-1$ + Messages.getString("Main.108")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + ksPassword = argument; + } + }); + signGroup.add(new Option("keypass", //$NON-NLS-1$ + Messages.getString("Main.110"), //$NON-NLS-1$ + Messages.getString("Main.111")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + password = argument; + } + }); + signGroup.add(new Option("sigfile", //$NON-NLS-1$ + Messages.getString("Main.113"), //$NON-NLS-1$ + Messages.getString("Main.114")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + sigFileName = argument; + } + }); + signGroup.add(new Option("signedjar", //$NON-NLS-1$ + Messages.getString("Main.116"), //$NON-NLS-1$ + Messages.getString("Main.117")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + signedJarFileName = argument; + } + }); + add(signGroup); + + OptionGroup verifyGroup = new OptionGroup(Messages.getString("Main.118")); //$NON-NLS-1$ + verifyGroup.add(new Option("verify", //$NON-NLS-1$ + Messages.getString("Main.120")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + verify = true; + } + }); + verifyGroup.add(new Option("certs", //$NON-NLS-1$ + Messages.getString("Main.122")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + certs = true; + } + }); + add(verifyGroup); + + OptionGroup commonGroup = new OptionGroup(Messages.getString("Main.123")); //$NON-NLS-1$ + commonGroup.add(new Option("verbose", //$NON-NLS-1$ + Messages.getString("Main.125")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + verbose = true; + } + }); + commonGroup.add(new Option("internalsf", //$NON-NLS-1$ + Messages.getString("Main.127")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + internalSF = true; + } + }); + commonGroup.add(new Option("sectionsonly", //$NON-NLS-1$ + Messages.getString("Main.129")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + sectionsOnly = true; + } + }); + commonGroup.add(new Option("provider", //$NON-NLS-1$ + Messages.getString("Main.131"), //$NON-NLS-1$ + Messages.getString("Main.132")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + providerClassName = argument; + } + }); + add(commonGroup); + } + } } diff --git a/tools/gnu/classpath/tools/jarsigner/jarsigner.txt b/tools/gnu/classpath/tools/jarsigner/jarsigner.txt deleted file mode 100644 index e615609c1..000000000 --- a/tools/gnu/classpath/tools/jarsigner/jarsigner.txt +++ /dev/null @@ -1,116 +0,0 @@ -NAME - jarsigner - Java ARchive (JAR) file signing and verification tool - -SYNOPSIS - jarsigner [OPTION]... FILE ALIAS - jarsigner -verify [OPTION]... FILE - -DESCRIPTION - When the first form is used, the tool signs the designated JAR file. - The second form, on the other hand, is used to verify a previously - signed JAR file. - - FILE is the .JAR file to process; i.e. to sign if the first syntax form - is used, or to verify if the second syntax form is used instead. - - ALIAS must be a known Alias of a Key Entry in the designated key store. - The private key material associated with this Alias is then used for - signing the designated .JAR file. - -SIGNING OPTIONS - -keystore URL - Use this option to specify the location of the key store to use. - The default value is a file URL referencing the file named - ".keystore" (all lower case and without the enclosing quotes) - located in the path returned by the call to - java.lang.System#getProperty(String) using "user.home" as - argument. - - If a URL was specified, but was found to be malformed --e.g. - missing protocol element-- the tool will attempt to use the URL - value as a file-name (with absolute or relative path-name) of a - key store --as if the protocol was "file:". - - -storetype STORE_TYPE - Use this option to specify the type of the key store to use. - The default value, if this option is omitted, is that of the - property "keystore.type" in the security properties file, which - is obtained by invoking the static method call getDefaultType() - in java.security.KeyStore. - - -storepass PASSWORD - Use this option to specify the password which will be used to - unlock the key store. If this option is missing, the User will - be prompted to provide a password. - - -keypass PASSWORD - Use this option to specify the password which the tool will use - to unlock the Key Entry associated with the designated Alias. - - If this option is omitted, the tool will first attempt to unlock - the Key Entry using the same password protecting the key store. - If this fails, you will then be prompted to provide a password. - - -sigfile NAME - Use this option to designate a literal that will be used to - construct file names for both the .SF and .DSA signature files. - These files will be generated, by the tool, and placed in the - META-INF directory of the signed JAR. Permissible characters - for NAME must be in the range "a-zA-Z0-9_-". All characters - will be converted to upper-case ones. - - If this option is missing, the first eight characters of the - ALIAS argument will be used. When this is the case, any - character in ALIAS that is outside the permissible range of - characters will be replaced by an underscore. - - -signedjar FILE_NAME - Use this option to specify the file name of the signed JAR. If - this option is omitted, then the signed JAR will be named the - same as FILE; i.e. the input JAR file will be replaced with the - signed copy. - -VERIFICATION OPTIONS - -verify - Use this option to indicate that the tool is to be used for - verification purposes. - - -certs This option is used in conjunction with the -verbose option. - When present, along with the -verbose option, the tool will - print more detailed information about the certificates of the - signer(s) being processed. - -COMMON OPTIONS - -verbose - Use this option to force the tool to generate more verbose - messages, during its processing. - - -internalsf - When present, the tool will include --which otherwise it does - not-- the .SF file in the .DSA generated file. - - -sectionsonly - When present, the tool will include in the .SF generated file - --which otherwise it does not-- a header containing a hash of - the whole manifest file. When that header is included, the - tool can quickly check, during verification, if the hash (in - the header) matches or not the manifest file. - - -provider PROVIDER_CLASS_NAME - A fully qualified class name of a Security Provider to add to - the current list of Security Providers already installed in the - JVM in-use. If a provider class is specified with this option, - and was successfully added to the runtime --i.e. it was not - already installed-- then the tool will attempt to remove this - Security Provider before exiting. - - -help Prints this help text. - -REPORTING BUGS - Please report bugs at http://www.gnu.org/software/classpath/bugs.html - -COPYRIGHT - Copyright (C) 2006 Free Software Foundation, Inc. - This is free software; see the source for copying conditions. There is - NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR - PURPOSE. diff --git a/tools/gnu/classpath/tools/keytool/CertReqCmd.java b/tools/gnu/classpath/tools/keytool/CertReqCmd.java index 0c64246e8..3de97e589 100644 --- a/tools/gnu/classpath/tools/keytool/CertReqCmd.java +++ b/tools/gnu/classpath/tools/keytool/CertReqCmd.java @@ -38,6 +38,11 @@ exception statement from your version. */ package gnu.classpath.tools.keytool; +import gnu.classpath.tools.getopt.ClasspathToolParser; +import gnu.classpath.tools.getopt.Option; +import gnu.classpath.tools.getopt.OptionException; +import gnu.classpath.tools.getopt.OptionGroup; +import gnu.classpath.tools.getopt.Parser; import gnu.java.security.OID; import gnu.java.security.der.BitString; import gnu.java.security.der.DER; @@ -170,15 +175,16 @@ import javax.security.auth.x500.X500Principal; class CertReqCmd extends Command { private static final Logger log = Logger.getLogger(CertReqCmd.class.getName()); - private String _alias; - private String _sigAlgorithm; - private String _certReqFileName; - private String _password; - private String _ksType; - private String _ksURL; - private String _ksPassword; - private String _providerClassName; - private boolean nullAttributes; + private static final String ATTRIBUTES_OPT = "attributes"; //$NON-NLS-1$ + protected String _alias; + protected String _sigAlgorithm; + protected String _certReqFileName; + protected String _password; + protected String _ksType; + protected String _ksURL; + protected String _ksPassword; + protected String _providerClassName; + protected boolean nullAttributes; // default 0-arguments constructor @@ -246,60 +252,19 @@ class CertReqCmd extends Command // life-cycle methods ------------------------------------------------------- - int processArgs(String[] args, int i) - { - int limit = args.length; - String opt; - while (++i < limit) - { - opt = args[i]; - log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$ - if (opt == null || opt.length() == 0) - continue; - - if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$ - _alias = args[++i]; - else if ("-sigalg".equals(opt)) // -sigalg ALGORITHM //$NON-NLS-1$ - _sigAlgorithm = args[++i]; - else if ("-file".equals(opt)) // -file FILE_NAME //$NON-NLS-1$ - _certReqFileName = args[++i]; - else if ("-keypass".equals(opt)) // -keypass PASSWORD //$NON-NLS-1$ - _password = args[++i]; - else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$ - _ksType = args[++i]; - else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$ - _ksURL = args[++i]; - else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$ - _ksPassword = args[++i]; - else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$ - _providerClassName = args[++i]; - else if ("-v".equals(opt)) //$NON-NLS-1$ - verbose = true; - else if ("-attributes".equals(opt)) //$NON-NLS-1$ - nullAttributes = true; - else - break; - } - - return i; - } - void setup() throws Exception { setOutputStreamParam(_certReqFileName); setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL); setAliasParam(_alias); setKeyPasswordNoPrompt(_password); -// setSignatureAlgorithm(_sigAlgorithm); log.finer("-certreq handler will use the following options:"); //$NON-NLS-1$ log.finer(" -alias=" + alias); //$NON-NLS-1$ log.finer(" -sigalg=" + _sigAlgorithm); //$NON-NLS-1$ log.finer(" -file=" + _certReqFileName); //$NON-NLS-1$ - log.finer(" -keypass=" + _password); //$NON-NLS-1$ log.finer(" -storetype=" + storeType); //$NON-NLS-1$ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$ - log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$ log.finer(" -provider=" + provider); //$NON-NLS-1$ log.finer(" -v=" + verbose); //$NON-NLS-1$ log.finer(" -attributes=" + nullAttributes); //$NON-NLS-1$ @@ -346,6 +311,108 @@ class CertReqCmd extends Command // own methods -------------------------------------------------------------- + Parser getParser() + { + log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$ + + Parser result = new ClasspathToolParser(Main.CERTREQ_CMD, true); + result.setHeader(Messages.getString("CertReqCmd.25")); //$NON-NLS-1$ + result.setFooter(Messages.getString("CertReqCmd.24")); //$NON-NLS-1$ + OptionGroup options = new OptionGroup(Messages.getString("CertReqCmd.23")); //$NON-NLS-1$ + options.add(new Option(Main.ALIAS_OPT, + Messages.getString("CertReqCmd.22"), //$NON-NLS-1$ + Messages.getString("CertReqCmd.21")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _alias = argument; + } + }); + options.add(new Option(Main.SIGALG_OPT, + Messages.getString("CertReqCmd.20"), //$NON-NLS-1$ + Messages.getString("CertReqCmd.19")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _sigAlgorithm = argument; + } + }); + options.add(new Option(Main.FILE_OPT, + Messages.getString("CertReqCmd.18"), //$NON-NLS-1$ + Messages.getString("CertReqCmd.17")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _certReqFileName = argument; + } + }); + options.add(new Option(Main.KEYPASS_OPT, + Messages.getString("CertReqCmd.16"), //$NON-NLS-1$ + Messages.getString("CertReqCmd.9")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _password = argument; + } + }); + options.add(new Option(Main.STORETYPE_OPT, + Messages.getString("CertReqCmd.14"), //$NON-NLS-1$ + Messages.getString("CertReqCmd.13")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksType = argument; + } + }); + options.add(new Option(Main.KEYSTORE_OPT, + Messages.getString("CertReqCmd.12"), //$NON-NLS-1$ + Messages.getString("CertReqCmd.11")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksURL = argument; + } + }); + options.add(new Option(Main.STOREPASS_OPT, + Messages.getString("CertReqCmd.10"), //$NON-NLS-1$ + Messages.getString("CertReqCmd.9")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksPassword = argument; + } + }); + options.add(new Option(Main.PROVIDER_OPT, + Messages.getString("CertReqCmd.8"), //$NON-NLS-1$ + Messages.getString("CertReqCmd.7")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _providerClassName = argument; + } + }); + options.add(new Option(Main.VERBOSE_OPT, + Messages.getString("CertReqCmd.6")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + verbose = true; + } + }); + options.add(new Option(ATTRIBUTES_OPT, + Messages.getString("CertReqCmd.5")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + nullAttributes = true; + } + }); + result.add(options); + + log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$ + return result; + } + /** * @param aliasName * @param publicKey diff --git a/tools/gnu/classpath/tools/keytool/Command.java b/tools/gnu/classpath/tools/keytool/Command.java index a59614644..0d8c56334 100644 --- a/tools/gnu/classpath/tools/keytool/Command.java +++ b/tools/gnu/classpath/tools/keytool/Command.java @@ -42,6 +42,7 @@ import gnu.classpath.SystemProperties; import gnu.classpath.tools.common.CallbackUtil; import gnu.classpath.tools.common.ProviderUtil; import gnu.classpath.tools.common.SecurityProviderInfo; +import gnu.classpath.tools.getopt.Parser; import gnu.java.security.OID; import gnu.java.security.Registry; import gnu.java.security.der.BitString; @@ -193,14 +194,14 @@ abstract class Command public void doCommand() throws Exception { try - { - setup(); - start(); - } + { + setup(); + start(); + } finally - { - teardown(); - } + { + teardown(); + } } /** @@ -228,11 +229,18 @@ abstract class Command * * @param args an array of options for this handler and possibly other * commands and their options. - * @param startIndex the index of the first argument in <code>args</code> to - * process. - * @return the index of the first unprocessed argument in <code>args</code>. + * @return the remaining un-processed <code>args</code>. */ - abstract int processArgs(String[] args, int startIndex); + String[] processArgs(String[] args) + { + log.entering(this.getClass().getName(), "processArgs", args); //$NON-NLS-1$ + + Parser cmdOptionsParser = getParser(); + String[] result = cmdOptionsParser.parse(args); + + log.exiting(this.getClass().getName(), "processArgs", result); //$NON-NLS-1$ + return result; + } /** * Initialize this concrete command handler for later invocation of the @@ -346,6 +354,12 @@ abstract class Command // parameter setup and validation methods ----------------------------------- /** + * @return a {@link Parser} that knows how to parse the concrete command's + * options. + */ + abstract Parser getParser(); + + /** * Convenience method to setup the key store given its type, its password, its * location and portentially a specialized security provider. * @@ -486,7 +500,6 @@ abstract class Command storePasswordChars = pcb.getPassword(); pcb.clearPassword(); } - log.finest("storePasswordChars = [" + String.valueOf(storePasswordChars)+ "]"); //$NON-NLS-1$ //$NON-NLS-2$ } /** @@ -575,7 +588,7 @@ abstract class Command catch (IOException x) { log.fine("Exception while closing the key store input stream: " + x //$NON-NLS-1$ - + ". Ignore"); //$NON-NLS-1$ + + ". Ignore"); //$NON-NLS-1$ } } @@ -970,7 +983,7 @@ abstract class Command protected void saveKeyStore(char[] password) throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException { - log.entering(this.getClass().getName(), "saveKeyStore", String.valueOf(password)); //$NON-NLS-1$ + log.entering(this.getClass().getName(), "saveKeyStore"); //$NON-NLS-1$ URLConnection con = storeURL.openConnection(); con.setDoOutput(true); diff --git a/tools/gnu/classpath/tools/keytool/DeleteCmd.java b/tools/gnu/classpath/tools/keytool/DeleteCmd.java index 968af50f8..9022f1c20 100644 --- a/tools/gnu/classpath/tools/keytool/DeleteCmd.java +++ b/tools/gnu/classpath/tools/keytool/DeleteCmd.java @@ -38,6 +38,12 @@ exception statement from your version. */ package gnu.classpath.tools.keytool; +import gnu.classpath.tools.getopt.ClasspathToolParser; +import gnu.classpath.tools.getopt.Option; +import gnu.classpath.tools.getopt.OptionException; +import gnu.classpath.tools.getopt.OptionGroup; +import gnu.classpath.tools.getopt.Parser; + import java.io.IOException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; @@ -106,11 +112,11 @@ import javax.security.auth.callback.UnsupportedCallbackException; class DeleteCmd extends Command { private static final Logger log = Logger.getLogger(DeleteCmd.class.getName()); - private String _alias; - private String _ksType; - private String _ksURL; - private String _ksPassword; - private String _providerClassName; + protected String _alias; + protected String _ksType; + protected String _ksURL; + protected String _ksPassword; + protected String _providerClassName; // default 0-arguments constructor @@ -148,36 +154,6 @@ class DeleteCmd extends Command // life-cycle methods ------------------------------------------------------- - int processArgs(String[] args, int i) - { - int limit = args.length; - String opt; - while (++i < limit) - { - opt = args[i]; - log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$ - if (opt == null || opt.length() == 0) - continue; - - if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$ - _alias = args[++i]; - else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$ - _ksType = args[++i]; - else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$ - _ksURL = args[++i]; - else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$ - _ksPassword = args[++i]; - else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$ - _providerClassName = args[++i]; - else if ("-v".equals(opt)) //$NON-NLS-1$ - verbose = true; - else - break; - } - - return i; - } - void setup() throws Exception { setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL); @@ -187,7 +163,6 @@ class DeleteCmd extends Command log.finer(" -alias=" + alias); //$NON-NLS-1$ log.finer(" -storetype=" + storeType); //$NON-NLS-1$ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$ - log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$ log.finer(" -provider=" + provider); //$NON-NLS-1$ log.finer(" -v=" + verbose); //$NON-NLS-1$ } @@ -206,6 +181,73 @@ class DeleteCmd extends Command // own methods -------------------------------------------------------------- + Parser getParser() + { + log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$ + + Parser result = new ClasspathToolParser(Main.DELETE_CMD, true); + result.setHeader(Messages.getString("DeleteCmd.18")); //$NON-NLS-1$ + result.setFooter(Messages.getString("DeleteCmd.17")); //$NON-NLS-1$ + OptionGroup options = new OptionGroup(Messages.getString("DeleteCmd.16")); //$NON-NLS-1$ + options.add(new Option(Main.ALIAS_OPT, + Messages.getString("DeleteCmd.15"), //$NON-NLS-1$ + Messages.getString("DeleteCmd.14")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _alias = argument; + } + }); + options.add(new Option(Main.STORETYPE_OPT, + Messages.getString("DeleteCmd.13"), //$NON-NLS-1$ + Messages.getString("DeleteCmd.12")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksType = argument; + } + }); + options.add(new Option(Main.KEYSTORE_OPT, + Messages.getString("DeleteCmd.11"), //$NON-NLS-1$ + Messages.getString("DeleteCmd.10")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksURL = argument; + } + }); + options.add(new Option(Main.STOREPASS_OPT, + Messages.getString("DeleteCmd.9"), //$NON-NLS-1$ + Messages.getString("DeleteCmd.8")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksPassword = argument; + } + }); + options.add(new Option(Main.PROVIDER_OPT, + Messages.getString("DeleteCmd.7"), //$NON-NLS-1$ + Messages.getString("DeleteCmd.6")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _providerClassName = argument; + } + }); + options.add(new Option(Main.VERBOSE_OPT, + Messages.getString("DeleteCmd.5")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + verbose = true; + } + }); + result.add(options); + + log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$ + return result; + } + /** * Set the alias to delete from the key store. * <p> diff --git a/tools/gnu/classpath/tools/keytool/ExportCmd.java b/tools/gnu/classpath/tools/keytool/ExportCmd.java index c1c0d4f83..49582a944 100644 --- a/tools/gnu/classpath/tools/keytool/ExportCmd.java +++ b/tools/gnu/classpath/tools/keytool/ExportCmd.java @@ -38,6 +38,11 @@ exception statement from your version. */ package gnu.classpath.tools.keytool; +import gnu.classpath.tools.getopt.ClasspathToolParser; +import gnu.classpath.tools.getopt.Option; +import gnu.classpath.tools.getopt.OptionException; +import gnu.classpath.tools.getopt.OptionGroup; +import gnu.classpath.tools.getopt.Parser; import gnu.java.security.util.Base64; import java.io.IOException; @@ -119,13 +124,13 @@ import java.util.logging.Logger; class ExportCmd extends Command { private static final Logger log = Logger.getLogger(ExportCmd.class.getName()); - private String _alias; - private String _certFileName; - private String _ksType; - private String _ksURL; - private String _ksPassword; - private String _providerClassName; - private boolean rfc; + protected String _alias; + protected String _certFileName; + protected String _ksType; + protected String _ksURL; + protected String _ksPassword; + protected String _providerClassName; + protected boolean rfc; // default 0-arguments constructor @@ -178,72 +183,37 @@ class ExportCmd extends Command // life-cycle methods ------------------------------------------------------- - int processArgs(String[] args, int i) - { - int limit = args.length; - String opt; - while (++i < limit) - { - opt = args[i]; - log.finest("args[" + i + "]=" + opt); - if (opt == null || opt.length() == 0) - continue; - - if ("-alias".equals(opt)) // -alias ALIAS - _alias = args[++i]; - else if ("-file".equals(opt)) // -file FILE_NAME - _certFileName = args[++i]; - else if ("-storetype".equals(opt)) // -storetype STORE_TYPE - _ksType = args[++i]; - else if ("-keystore".equals(opt)) // -keystore URL - _ksURL = args[++i]; - else if ("-storepass".equals(opt)) // -storepass PASSWORD - _ksPassword = args[++i]; - else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME - _providerClassName = args[++i]; - else if ("-rfc".equals(opt)) - rfc = true; - else if ("-v".equals(opt)) - verbose = true; - else - break; - } - - return i; - } - void setup() throws Exception { setOutputStreamParam(_certFileName); setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL); setAliasParam(_alias); - log.finer("-export handler will use the following options:"); - log.finer(" -alias=" + alias); - log.finer(" -file=" + _certFileName); - log.finer(" -storetype=" + storeType); - log.finer(" -keystore=" + storeURL); - log.finer(" -storepass=" + String.valueOf(storePasswordChars)); - log.finer(" -provider=" + provider); - log.finer(" -rfc=" + rfc); - log.finer(" -v=" + verbose); + log.finer("-export handler will use the following options:"); //$NON-NLS-1$ + log.finer(" -alias=" + alias); //$NON-NLS-1$ + log.finer(" -file=" + _certFileName); //$NON-NLS-1$ + log.finer(" -storetype=" + storeType); //$NON-NLS-1$ + log.finer(" -keystore=" + storeURL); //$NON-NLS-1$ + log.finer(" -provider=" + provider); //$NON-NLS-1$ + log.finer(" -rfc=" + rfc); //$NON-NLS-1$ + log.finer(" -v=" + verbose); //$NON-NLS-1$ } void start() throws KeyStoreException, CertificateEncodingException, IOException { - log.entering(this.getClass().getName(), "start"); + log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$ ensureStoreContainsAlias(); Certificate certificate; if (store.isCertificateEntry(alias)) { - log.fine("Alias [" + alias + "] is a trusted certificate"); + log.finer("Alias [" + alias + "] is a trusted certificate"); //$NON-NLS-1$ //$NON-NLS-2$ certificate = store.getCertificate(alias); } else { - log.fine("Alias [" + alias + "] is a key entry"); + log.finer("Alias [" + alias + "] is a key entry"); //$NON-NLS-1$ //$NON-NLS-2$ Certificate[] chain = store.getCertificateChain(alias); certificate = chain[0]; } @@ -253,14 +223,100 @@ class ExportCmd extends Command { String encoded = Base64.encode(derBytes, 0, derBytes.length, true); PrintWriter pw = new PrintWriter(outStream, true); - pw.println("-----BEGIN CERTIFICATE-----"); + pw.println("-----BEGIN CERTIFICATE-----"); //$NON-NLS-1$ pw.println(encoded); - pw.println("-----END CERTIFICATE-----"); + pw.println("-----END CERTIFICATE-----"); //$NON-NLS-1$ } else outStream.write(derBytes); // stream is closed in Command.teardown() - log.exiting(this.getClass().getName(), "start"); + log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$ + } + + // own methods -------------------------------------------------------------- + + Parser getParser() + { + log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$ + + Parser result = new ClasspathToolParser(Main.EXPORT_CMD, true); + result.setHeader(Messages.getString("ExportCmd.17")); //$NON-NLS-1$ + result.setFooter(Messages.getString("ExportCmd.18")); //$NON-NLS-1$ + OptionGroup options = new OptionGroup(Messages.getString("ExportCmd.19")); //$NON-NLS-1$ + options.add(new Option(Main.ALIAS_OPT, + Messages.getString("ExportCmd.20"), //$NON-NLS-1$ + Messages.getString("ExportCmd.21")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _alias = argument; + } + }); + options.add(new Option(Main.FILE_OPT, + Messages.getString("ExportCmd.22"), //$NON-NLS-1$ + Messages.getString("ExportCmd.23")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _certFileName = argument; + } + }); + options.add(new Option(Main.STORETYPE_OPT, + Messages.getString("ExportCmd.24"), //$NON-NLS-1$ + Messages.getString("ExportCmd.25")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksType = argument; + } + }); + options.add(new Option(Main.KEYSTORE_OPT, + Messages.getString("ExportCmd.26"), //$NON-NLS-1$ + Messages.getString("ExportCmd.27")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksURL = argument; + } + }); + options.add(new Option(Main.STOREPASS_OPT, + Messages.getString("ExportCmd.28"), //$NON-NLS-1$ + Messages.getString("ExportCmd.29")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksPassword = argument; + } + }); + options.add(new Option(Main.PROVIDER_OPT, + Messages.getString("ExportCmd.30"), //$NON-NLS-1$ + Messages.getString("ExportCmd.31")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _providerClassName = argument; + } + }); + options.add(new Option(Main.RFC_OPT, + Messages.getString("ExportCmd.32")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + rfc = true; + } + }); + options.add(new Option(Main.VERBOSE_OPT, + Messages.getString("ExportCmd.33")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + verbose = true; + } + }); + result.add(options); + + log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$ + return result; } } diff --git a/tools/gnu/classpath/tools/keytool/GenKeyCmd.java b/tools/gnu/classpath/tools/keytool/GenKeyCmd.java index 2d92134c2..4d4ca7a74 100644 --- a/tools/gnu/classpath/tools/keytool/GenKeyCmd.java +++ b/tools/gnu/classpath/tools/keytool/GenKeyCmd.java @@ -38,6 +38,11 @@ exception statement from your version. */ package gnu.classpath.tools.keytool; +import gnu.classpath.tools.getopt.ClasspathToolParser; +import gnu.classpath.tools.getopt.Option; +import gnu.classpath.tools.getopt.OptionException; +import gnu.classpath.tools.getopt.OptionGroup; +import gnu.classpath.tools.getopt.Parser; import gnu.java.security.util.Util; import gnu.java.security.x509.X500DistinguishedName; @@ -198,19 +203,20 @@ class GenKeyCmd extends Command /** Default key size in bits. */ private static final int DEFAULT_KEY_SIZE = 1024; - private String _alias; - private String _keyAlgorithm; - private String _keySizeStr; - private String _sigAlgorithm; - private String _dName; - private String _password; - private String _validityStr; - private String _ksType; - private String _ksURL; - private String _ksPassword; - private String _providerClassName; + protected String _alias; + protected String _keyAlgorithm; + protected String _keySizeStr; + protected String _sigAlgorithm; + protected String _dName; + protected String _password; + protected String _validityStr; + protected String _ksType; + protected String _ksURL; + protected String _ksPassword; + protected String _providerClassName; private int keySize; private X500DistinguishedName distinguishedName; + private Parser cmdOptionsParser; // default 0-arguments constructor @@ -294,48 +300,6 @@ class GenKeyCmd extends Command // life-cycle methods ------------------------------------------------------- - int processArgs(String[] args, int i) - { - int limit = args.length; - String opt; - while (++i < limit) - { - opt = args[i]; - log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$ - if (opt == null || opt.length() == 0) - continue; - - if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$ - _alias = args[++i]; - else if ("-keyalg".equals(opt)) // -keyalg ALGORITHM //$NON-NLS-1$ - _keyAlgorithm = args[++i]; - else if ("-keysize".equals(opt)) // -keysize KEY_SIZE //$NON-NLS-1$ - _keySizeStr = args[++i]; - else if ("-sigalg".equals(opt)) // -sigalg ALGORITHM //$NON-NLS-1$ - _sigAlgorithm = args[++i]; - else if ("-dname".equals(opt)) // -dname NAME //$NON-NLS-1$ - _dName = args[++i]; - else if ("-keypass".equals(opt)) // -keypass PASSWORD //$NON-NLS-1$ - _password = args[++i]; - else if ("-validity".equals(opt)) // -validity DAY_COUNT //$NON-NLS-1$ - _validityStr = args[++i]; - else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$ - _ksType = args[++i]; - else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$ - _ksURL = args[++i]; - else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$ - _ksPassword = args[++i]; - else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$ - _providerClassName = args[++i]; - else if ("-v".equals(opt)) //$NON-NLS-1$ - verbose = true; - else - break; - } - - return i; - } - void setup() throws Exception { setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL); @@ -352,11 +316,9 @@ class GenKeyCmd extends Command log.finer(" -keysize=" + keySize); //$NON-NLS-1$ log.finer(" -sigalg=" + signatureAlgorithm.getAlgorithm()); //$NON-NLS-1$ log.finer(" -dname=" + distinguishedName); //$NON-NLS-1$ - log.finer(" -keypass=" + String.valueOf(keyPasswordChars)); //$NON-NLS-1$ log.finer(" -validity=" + validityInDays); //$NON-NLS-1$ log.finer(" -storetype=" + storeType); //$NON-NLS-1$ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$ - log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$ log.finer(" -provider=" + provider); //$NON-NLS-1$ log.finer(" -v=" + verbose); //$NON-NLS-1$ } @@ -368,14 +330,14 @@ class GenKeyCmd extends Command log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$ // 1. generate a new key-pair - log.fine("About to generate key-pair..."); + log.finer("About to generate key-pair..."); //$NON-NLS-1$ keyPairGenerator.initialize(keySize); KeyPair kp = keyPairGenerator.generateKeyPair(); PublicKey publicKey = kp.getPublic(); PrivateKey privateKey = kp.getPrivate(); // 2. generate a self-signed certificate - log.fine("About to generate a self-signed certificate..."); + log.finer("About to generate a self-signed certificate..."); //$NON-NLS-1$ byte[] derBytes = getSelfSignedCertificate(distinguishedName, publicKey, privateKey); @@ -398,6 +360,127 @@ class GenKeyCmd extends Command // own methods -------------------------------------------------------------- + Parser getParser() + { + log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$ + + Parser result = new ClasspathToolParser(Main.GENKEY_CMD, true); + result.setHeader(Messages.getString("GenKeyCmd.57")); //$NON-NLS-1$ + result.setFooter(Messages.getString("GenKeyCmd.58")); //$NON-NLS-1$ + OptionGroup options = new OptionGroup(Messages.getString("GenKeyCmd.59")); //$NON-NLS-1$ + options.add(new Option(Main.ALIAS_OPT, + Messages.getString("GenKeyCmd.60"), //$NON-NLS-1$ + Messages.getString("GenKeyCmd.61")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _alias = argument; + } + }); + options.add(new Option(Main.KEYALG_OPT, + Messages.getString("GenKeyCmd.62"), //$NON-NLS-1$ + Messages.getString("GenKeyCmd.63")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _keyAlgorithm = argument; + } + }); + options.add(new Option(Main.KEYSIZE_OPT, + Messages.getString("GenKeyCmd.64"), //$NON-NLS-1$ + Messages.getString("GenKeyCmd.65")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _keySizeStr = argument; + } + }); + options.add(new Option(Main.SIGALG_OPT, + Messages.getString("GenKeyCmd.66"), //$NON-NLS-1$ + Messages.getString("GenKeyCmd.63")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _sigAlgorithm = argument; + } + }); + options.add(new Option(Main.DNAME_OPT, + Messages.getString("GenKeyCmd.68"), //$NON-NLS-1$ + Messages.getString("GenKeyCmd.69")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _dName = argument; + } + }); + options.add(new Option(Main.KEYPASS_OPT, + Messages.getString("GenKeyCmd.70"), //$NON-NLS-1$ + Messages.getString("GenKeyCmd.71")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _password = argument; + } + }); + options.add(new Option(Main.VALIDITY_OPT, + Messages.getString("GenKeyCmd.72"), //$NON-NLS-1$ + Messages.getString("GenKeyCmd.73")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _validityStr = argument; + } + }); + options.add(new Option(Main.STORETYPE_OPT, + Messages.getString("GenKeyCmd.74"), //$NON-NLS-1$ + Messages.getString("GenKeyCmd.75")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksType = argument; + } + }); + options.add(new Option(Main.KEYSTORE_OPT, + Messages.getString("GenKeyCmd.76"), //$NON-NLS-1$ + Messages.getString("GenKeyCmd.77")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksURL = argument; + } + }); + options.add(new Option(Main.STOREPASS_OPT, + Messages.getString("GenKeyCmd.78"), //$NON-NLS-1$ + Messages.getString("GenKeyCmd.71")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksPassword = argument; + } + }); + options.add(new Option(Main.PROVIDER_OPT, + Messages.getString("GenKeyCmd.80"), //$NON-NLS-1$ + Messages.getString("GenKeyCmd.81")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _providerClassName = argument; + } + }); + options.add(new Option(Main.VERBOSE_OPT, + Messages.getString("GenKeyCmd.82")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + verbose = true; + } + }); + result.add(options); + + log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$ + return result; + } + /** * @param size the desired key size as a string. * @throws NumberFormatException if the string does not represent a valid diff --git a/tools/gnu/classpath/tools/keytool/IdentityDBCmd.java b/tools/gnu/classpath/tools/keytool/IdentityDBCmd.java index cb6b6dac2..11d0f68da 100644 --- a/tools/gnu/classpath/tools/keytool/IdentityDBCmd.java +++ b/tools/gnu/classpath/tools/keytool/IdentityDBCmd.java @@ -38,6 +38,12 @@ exception statement from your version. */ package gnu.classpath.tools.keytool; +import gnu.classpath.tools.getopt.ClasspathToolParser; +import gnu.classpath.tools.getopt.Option; +import gnu.classpath.tools.getopt.OptionException; +import gnu.classpath.tools.getopt.OptionGroup; +import gnu.classpath.tools.getopt.Parser; + import java.util.logging.Logger; /** @@ -97,11 +103,11 @@ import java.util.logging.Logger; class IdentityDBCmd extends Command { private static final Logger log = Logger.getLogger(IdentityDBCmd.class.getName()); - private String _idbFileName; - private String _ksType; - private String _ksURL; - private String _ksPassword; - private String _providerClassName; + protected String _idbFileName; + protected String _ksType; + protected String _ksURL; + protected String _ksPassword; + protected String _providerClassName; // default 0-arguments constructor @@ -139,47 +145,85 @@ class IdentityDBCmd extends Command // life-cycle methods ------------------------------------------------------- - int processArgs(String[] args, int i) + void setup() throws Exception { - int limit = args.length; - String opt; - while (++i < limit) - { - opt = args[i]; - log.finest("args[" + i + "]=" + opt); - if (opt == null || opt.length() == 0) - continue; - - if ("-file".equals(opt)) // -file FILE_NAME - _idbFileName = args[++i]; - else if ("-storetype".equals(opt)) // -storetype STORE_TYPE - _ksType = args[++i]; - else if ("-keystore".equals(opt)) // -keystore URL - _ksURL = args[++i]; - else if ("-storepass".equals(opt)) // -storepass PASSWORD - _ksPassword = args[++i]; - else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME - _providerClassName = args[++i]; - else if ("-v".equals(opt)) - verbose = true; - else - break; - } + setInputStreamParam(_idbFileName); + setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL); - return i; + log.finer("-identitydb handler will use the following options:"); //$NON-NLS-1$ + log.finer(" -file=" + _idbFileName); //$NON-NLS-1$ + log.finer(" -storetype=" + storeType); //$NON-NLS-1$ + log.finer(" -keystore=" + storeURL); //$NON-NLS-1$ + log.finer(" -provider=" + provider); //$NON-NLS-1$ + log.finer(" -v=" + verbose); //$NON-NLS-1$ } - void setup() throws Exception + // own methods -------------------------------------------------------------- + + Parser getParser() { - setInputStreamParam(_idbFileName); - setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL); + log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$ + + Parser result = new ClasspathToolParser(Main.IDENTITYDB_CMD, true); + result.setHeader(Messages.getString("IdentityDBCmd.7")); //$NON-NLS-1$ + result.setFooter(Messages.getString("IdentityDBCmd.8")); //$NON-NLS-1$ + OptionGroup options = new OptionGroup(Messages.getString("IdentityDBCmd.9")); //$NON-NLS-1$ + options.add(new Option(Main.FILE_OPT, + Messages.getString("IdentityDBCmd.10"), //$NON-NLS-1$ + Messages.getString("IdentityDBCmd.11")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _idbFileName = argument; + } + }); + options.add(new Option(Main.STORETYPE_OPT, + Messages.getString("IdentityDBCmd.12"), //$NON-NLS-1$ + Messages.getString("IdentityDBCmd.13")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksType = argument; + } + }); + options.add(new Option(Main.KEYSTORE_OPT, + Messages.getString("IdentityDBCmd.14"), //$NON-NLS-1$ + Messages.getString("IdentityDBCmd.15")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksURL = argument; + } + }); + options.add(new Option(Main.STOREPASS_OPT, + Messages.getString("IdentityDBCmd.16"), //$NON-NLS-1$ + Messages.getString("IdentityDBCmd.17")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksPassword = argument; + } + }); + options.add(new Option(Main.PROVIDER_OPT, + Messages.getString("IdentityDBCmd.18"), //$NON-NLS-1$ + Messages.getString("IdentityDBCmd.19")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _providerClassName = argument; + } + }); + options.add(new Option(Main.VERBOSE_OPT, + Messages.getString("IdentityDBCmd.20")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + verbose = true; + } + }); + result.add(options); - log.finer("-identitydb handler will use the following options:"); - log.finer(" -file=" + _idbFileName); - log.finer(" -storetype=" + storeType); - log.finer(" -keystore=" + storeURL); - log.finer(" -storepass=" + new String(storePasswordChars)); - log.finer(" -provider=" + provider); - log.finer(" -v=" + verbose); + log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$ + return result; } } diff --git a/tools/gnu/classpath/tools/keytool/ImportCmd.java b/tools/gnu/classpath/tools/keytool/ImportCmd.java index b5058b581..2d587be08 100644 --- a/tools/gnu/classpath/tools/keytool/ImportCmd.java +++ b/tools/gnu/classpath/tools/keytool/ImportCmd.java @@ -39,6 +39,11 @@ exception statement from your version. */ package gnu.classpath.tools.keytool; import gnu.classpath.SystemProperties; +import gnu.classpath.tools.getopt.ClasspathToolParser; +import gnu.classpath.tools.getopt.Option; +import gnu.classpath.tools.getopt.OptionException; +import gnu.classpath.tools.getopt.OptionGroup; +import gnu.classpath.tools.getopt.Parser; import gnu.java.security.x509.X509CertPath; import java.io.FileInputStream; @@ -181,15 +186,15 @@ import javax.security.auth.callback.UnsupportedCallbackException; class ImportCmd extends Command { private static final Logger log = Logger.getLogger(ImportCmd.class.getName()); - private String _alias; - private String _certFileName; - private String _password; - private boolean noPrompt; - private boolean trustCACerts; - private String _ksType; - private String _ksURL; - private String _ksPassword; - private String _providerClassName; + protected String _alias; + protected String _certFileName; + protected String _password; + protected boolean noPrompt; + protected boolean trustCACerts; + protected String _ksType; + protected String _ksURL; + protected String _ksPassword; + protected String _providerClassName; private CertificateFactory x509Factory; private boolean imported; @@ -259,44 +264,6 @@ class ImportCmd extends Command // life-cycle methods ------------------------------------------------------- - int processArgs(String[] args, int i) - { - int limit = args.length; - String opt; - while (++i < limit) - { - opt = args[i]; - log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$ - if (opt == null || opt.length() == 0) - continue; - - if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$ - _alias = args[++i]; - else if ("-file".equals(opt)) // -file FILE_NAME //$NON-NLS-1$ - _certFileName = args[++i]; - else if ("-keypass".equals(opt)) // -keypass PASSWORD //$NON-NLS-1$ - _password = args[++i]; - else if ("-noprompt".equals(opt)) //$NON-NLS-1$ - noPrompt = true; - else if ("-trustcacerts".equals(opt)) //$NON-NLS-1$ - trustCACerts = true; - else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$ - _ksType = args[++i]; - else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$ - _ksURL = args[++i]; - else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$ - _ksPassword = args[++i]; - else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$ - _providerClassName = args[++i]; - else if ("-v".equals(opt)) //$NON-NLS-1$ - verbose = true; - else - break; - } - - return i; - } - void setup() throws Exception { setInputStreamParam(_certFileName); @@ -307,12 +274,10 @@ class ImportCmd extends Command log.finer("-import handler will use the following options:"); //$NON-NLS-1$ log.finer(" -alias=" + alias); //$NON-NLS-1$ log.finer(" -file=" + _certFileName); //$NON-NLS-1$ - log.finer(" -keypass=" + _password); //$NON-NLS-1$ log.finer(" -noprompt=" + noPrompt); //$NON-NLS-1$ log.finer(" -trustcacerts=" + trustCACerts); //$NON-NLS-1$ log.finer(" -storetype=" + storeType); //$NON-NLS-1$ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$ - log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$ log.finer(" -provider=" + provider); //$NON-NLS-1$ log.finer(" -v=" + verbose); //$NON-NLS-1$ } @@ -339,6 +304,107 @@ class ImportCmd extends Command // own methods -------------------------------------------------------------- + Parser getParser() + { + log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$ + + Parser result = new ClasspathToolParser(Main.IMPORT_CMD, true); + result.setHeader(Messages.getString("ImportCmd.27")); //$NON-NLS-1$ + result.setFooter(Messages.getString("ImportCmd.26")); //$NON-NLS-1$ + OptionGroup options = new OptionGroup(Messages.getString("ImportCmd.25")); //$NON-NLS-1$ + options.add(new Option(Main.ALIAS_OPT, + Messages.getString("ImportCmd.24"), //$NON-NLS-1$ + Messages.getString("ImportCmd.23")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _alias = argument; + } + }); + options.add(new Option(Main.FILE_OPT, + Messages.getString("ImportCmd.22"), //$NON-NLS-1$ + Messages.getString("ImportCmd.21")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _certFileName = argument; + } + }); + options.add(new Option(Main.KEYPASS_OPT, + Messages.getString("ImportCmd.20"), //$NON-NLS-1$ + Messages.getString("ImportCmd.19")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _password = argument; + } + }); + options.add(new Option("noprompt", //$NON-NLS-1$ + Messages.getString("ImportCmd.18")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + noPrompt = true; + } + }); + options.add(new Option("trustcacerts", //$NON-NLS-1$ + Messages.getString("ImportCmd.17")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + trustCACerts = true; + } + }); + options.add(new Option(Main.STORETYPE_OPT, + Messages.getString("ImportCmd.16"), //$NON-NLS-1$ + Messages.getString("ImportCmd.15")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksType = argument; + } + }); + options.add(new Option(Main.KEYSTORE_OPT, + Messages.getString("ImportCmd.14"), //$NON-NLS-1$ + Messages.getString("ImportCmd.13")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksURL = argument; + } + }); + options.add(new Option(Main.STOREPASS_OPT, + Messages.getString("ImportCmd.12"), //$NON-NLS-1$ + Messages.getString("ImportCmd.11")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksPassword = argument; + } + }); + options.add(new Option(Main.PROVIDER_OPT, + Messages.getString("ImportCmd.10"), //$NON-NLS-1$ + Messages.getString("ImportCmd.9")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _providerClassName = argument; + } + }); + options.add(new Option(Main.VERBOSE_OPT, + Messages.getString("ImportCmd.8")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + verbose = true; + } + }); + result.add(options); + + log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$ + return result; + } + /** * When importing a new trusted certificate, <i>alias</i> MUST NOT yet exist * in the key store. @@ -607,7 +673,7 @@ class ImportCmd extends Command log.entering(this.getClass().getName(), "orderChain"); //$NON-NLS-1$ LinkedList result = new LinkedList(); - + // FIXME: really order it! log.entering(this.getClass().getName(), "orderChain", result); //$NON-NLS-1$ return result; @@ -715,7 +781,7 @@ class ImportCmd extends Command try { KeyStore cacerts = KeyStore.getInstance("jks"); //$NON-NLS-1$ - String cacertsPath = SystemProperties.getProperty("java.home"); + String cacertsPath = SystemProperties.getProperty("java.home"); //$NON-NLS-1$ String fs = SystemProperties.getProperty("file.separator"); //$NON-NLS-1$ cacertsPath = new StringBuilder(cacertsPath).append(fs) .append("lib").append(fs) //$NON-NLS-1$ diff --git a/tools/gnu/classpath/tools/keytool/KeyCloneCmd.java b/tools/gnu/classpath/tools/keytool/KeyCloneCmd.java index 5936719f7..a60fef936 100644 --- a/tools/gnu/classpath/tools/keytool/KeyCloneCmd.java +++ b/tools/gnu/classpath/tools/keytool/KeyCloneCmd.java @@ -38,6 +38,12 @@ exception statement from your version. */ package gnu.classpath.tools.keytool; +import gnu.classpath.tools.getopt.ClasspathToolParser; +import gnu.classpath.tools.getopt.Option; +import gnu.classpath.tools.getopt.OptionException; +import gnu.classpath.tools.getopt.OptionGroup; +import gnu.classpath.tools.getopt.Parser; + import java.io.IOException; import java.security.Key; import java.security.KeyStoreException; @@ -132,14 +138,14 @@ import javax.security.auth.callback.UnsupportedCallbackException; class KeyCloneCmd extends Command { private static final Logger log = Logger.getLogger(KeyCloneCmd.class.getName()); - private String _alias; - private String _destAlias; - private String _password; - private String _newPassword; - private String _ksType; - private String _ksURL; - private String _ksPassword; - private String _providerClassName; + protected String _alias; + protected String _destAlias; + protected String _password; + protected String _newPassword; + protected String _ksType; + protected String _ksURL; + protected String _ksPassword; + protected String _providerClassName; private String destinationAlias; private char[] newKeyPasswordChars; @@ -197,58 +203,18 @@ class KeyCloneCmd extends Command // life-cycle methods ------------------------------------------------------- - int processArgs(String[] args, int i) - { - int limit = args.length; - String opt; - while (++i < limit) - { - opt = args[i]; - log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$ - if (opt == null || opt.length() == 0) - continue; - - if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$ - _alias = args[++i]; - else if ("-dest".equals(opt)) // -dest ALIAS //$NON-NLS-1$ - _destAlias = args[++i]; - else if ("-keypass".equals(opt)) // -keypass PASSWORD //$NON-NLS-1$ - _password = args[++i]; - else if ("-new".equals(opt)) // -new PASSWORD //$NON-NLS-1$ - _newPassword = args[++i]; - else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$ - _ksType = args[++i]; - else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$ - _ksURL = args[++i]; - else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$ - _ksPassword = args[++i]; - else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$ - _providerClassName = args[++i]; - else if ("-v".equals(opt)) //$NON-NLS-1$ - verbose = true; - else - break; - } - - return i; - } - void setup() throws Exception { setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL); setAliasParam(_alias); setKeyPasswordNoPrompt(_password); setDestinationAlias(_destAlias); -// setNewKeyPassword(_newPassword); log.finer("-keyclone handler will use the following options:"); //$NON-NLS-1$ log.finer(" -alias=" + alias); //$NON-NLS-1$ log.finer(" -dest=" + destinationAlias); //$NON-NLS-1$ - log.finer(" -keypass=" + _password); //$NON-NLS-1$ - log.finer(" -new=" + _newPassword); //$NON-NLS-1$ log.finer(" -storetype=" + storeType); //$NON-NLS-1$ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$ - log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$ log.finer(" -provider=" + provider); //$NON-NLS-1$ log.finer(" -v=" + verbose); //$NON-NLS-1$ } @@ -276,6 +242,100 @@ class KeyCloneCmd extends Command // own methods -------------------------------------------------------------- + Parser getParser() + { + log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$ + + Parser result = new ClasspathToolParser(Main.KEYCLONE_CMD, true); + result.setHeader(Messages.getString("KeyCloneCmd.22")); //$NON-NLS-1$ + result.setFooter(Messages.getString("KeyCloneCmd.21")); //$NON-NLS-1$ + OptionGroup options = new OptionGroup(Messages.getString("KeyCloneCmd.20")); //$NON-NLS-1$ + options.add(new Option(Main.ALIAS_OPT, + Messages.getString("KeyCloneCmd.19"), //$NON-NLS-1$ + Messages.getString("KeyCloneCmd.16")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _alias = argument; + } + }); + options.add(new Option(Main.DEST_OPT, + Messages.getString("KeyCloneCmd.17"), //$NON-NLS-1$ + Messages.getString("KeyCloneCmd.16")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _destAlias = argument; + } + }); + options.add(new Option(Main.KEYPASS_OPT, + Messages.getString("KeyCloneCmd.15"), //$NON-NLS-1$ + Messages.getString("KeyCloneCmd.6")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _password = argument; + } + }); + options.add(new Option(Main.NEW_OPT, + Messages.getString("KeyCloneCmd.13"), //$NON-NLS-1$ + Messages.getString("KeyCloneCmd.6")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _newPassword = argument; + } + }); + options.add(new Option(Main.STORETYPE_OPT, + Messages.getString("KeyCloneCmd.11"), //$NON-NLS-1$ + Messages.getString("KeyCloneCmd.10")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksType = argument; + } + }); + options.add(new Option(Main.KEYSTORE_OPT, + Messages.getString("KeyCloneCmd.9"), //$NON-NLS-1$ + Messages.getString("KeyCloneCmd.8")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksURL = argument; + } + }); + options.add(new Option(Main.STOREPASS_OPT, + Messages.getString("KeyCloneCmd.7"), //$NON-NLS-1$ + Messages.getString("KeyCloneCmd.6")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksPassword = argument; + } + }); + options.add(new Option(Main.PROVIDER_OPT, + Messages.getString("KeyCloneCmd.5"), //$NON-NLS-1$ + Messages.getString("KeyCloneCmd.4")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _providerClassName = argument; + } + }); + options.add(new Option(Main.VERBOSE_OPT, + Messages.getString("KeyCloneCmd.3")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + verbose = true; + } + }); + result.add(options); + + log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$ + return result; + } + private void setDestinationAlias(String name) throws IOException, UnsupportedCallbackException { @@ -294,9 +354,9 @@ class KeyCloneCmd extends Command private void setNewKeyPassword(String password) throws IOException, UnsupportedCallbackException { - if (password != null) // ask user to provide one + if (password != null) newKeyPasswordChars = password.toCharArray(); - else + else // ask user to provide one { boolean ok = false; Callback[] prompts = new Callback[1]; diff --git a/tools/gnu/classpath/tools/keytool/KeyPasswdCmd.java b/tools/gnu/classpath/tools/keytool/KeyPasswdCmd.java index 9dc7b8164..5cf25eb0f 100644 --- a/tools/gnu/classpath/tools/keytool/KeyPasswdCmd.java +++ b/tools/gnu/classpath/tools/keytool/KeyPasswdCmd.java @@ -39,6 +39,11 @@ exception statement from your version. */ package gnu.classpath.tools.keytool; import gnu.classpath.SystemProperties; +import gnu.classpath.tools.getopt.ClasspathToolParser; +import gnu.classpath.tools.getopt.Option; +import gnu.classpath.tools.getopt.OptionException; +import gnu.classpath.tools.getopt.OptionGroup; +import gnu.classpath.tools.getopt.Parser; import java.io.IOException; import java.security.Key; @@ -128,13 +133,13 @@ import javax.security.auth.callback.UnsupportedCallbackException; class KeyPasswdCmd extends Command { private static final Logger log = Logger.getLogger(KeyPasswdCmd.class.getName()); - private String _alias; - private String _password; - private String _newPassword; - private String _ksType; - private String _ksURL; - private String _ksPassword; - private String _providerClassName; + protected String _alias; + protected String _password; + protected String _newPassword; + protected String _ksType; + protected String _ksURL; + protected String _ksPassword; + protected String _providerClassName; private char[] newPasswordChars; // default 0-arguments constructor @@ -185,54 +190,17 @@ class KeyPasswdCmd extends Command // life-cycle methods ------------------------------------------------------- - int processArgs(String[] args, int i) - { - int limit = args.length; - String opt; - while (++i < limit) - { - opt = args[i]; - log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$ - if (opt == null || opt.length() == 0) - continue; - - if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$ - _alias = args[++i]; - else if ("-keypass".equals(opt)) // -keypass PASSWORD //$NON-NLS-1$ - _password = args[++i]; - else if ("-new".equals(opt)) // -new PASSWORD //$NON-NLS-1$ - _newPassword = args[++i]; - else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$ - _ksType = args[++i]; - else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$ - _ksURL = args[++i]; - else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$ - _ksPassword = args[++i]; - else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$ - _providerClassName = args[++i]; - else if ("-v".equals(opt)) //$NON-NLS-1$ - verbose = true; - else - break; - } - - return i; - } - void setup() throws Exception { setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL); setAliasParam(_alias); setKeyPasswordNoPrompt(_password); -// setNewKeyPassword(_newPassword); log.finer("-keypasswd handler will use the following options:"); //$NON-NLS-1$ log.finer(" -alias=" + alias); //$NON-NLS-1$ - log.finer(" -keypass=" + _password); //$NON-NLS-1$ log.finer(" -new=" + _newPassword); //$NON-NLS-1$ log.finer(" -storetype=" + storeType); //$NON-NLS-1$ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$ - log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$ log.finer(" -provider=" + provider); //$NON-NLS-1$ log.finer(" -v=" + verbose); //$NON-NLS-1$ } @@ -259,6 +227,91 @@ class KeyPasswdCmd extends Command // own methods -------------------------------------------------------------- + Parser getParser() + { + log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$ + + Parser result = new ClasspathToolParser(Main.KEYPASSWD_CMD, true); + result.setHeader(Messages.getString("KeyPasswdCmd.23")); //$NON-NLS-1$ + result.setFooter(Messages.getString("KeyPasswdCmd.22")); //$NON-NLS-1$ + OptionGroup options = new OptionGroup(Messages.getString("KeyPasswdCmd.21")); //$NON-NLS-1$ + options.add(new Option(Main.ALIAS_OPT, + Messages.getString("KeyPasswdCmd.20"), //$NON-NLS-1$ + Messages.getString("KeyPasswdCmd.19")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _alias = argument; + } + }); + options.add(new Option(Main.KEYPASS_OPT, + Messages.getString("KeyPasswdCmd.18"), //$NON-NLS-1$ + Messages.getString("KeyPasswdCmd.9")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _password = argument; + } + }); + options.add(new Option(Main.NEW_OPT, + Messages.getString("KeyPasswdCmd.16"), //$NON-NLS-1$ + Messages.getString("KeyPasswdCmd.9")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _newPassword = argument; + } + }); + options.add(new Option(Main.STORETYPE_OPT, + Messages.getString("KeyPasswdCmd.14"), //$NON-NLS-1$ + Messages.getString("KeyPasswdCmd.13")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksType = argument; + } + }); + options.add(new Option(Main.KEYSTORE_OPT, + Messages.getString("KeyPasswdCmd.12"), //$NON-NLS-1$ + Messages.getString("KeyPasswdCmd.11")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksURL = argument; + } + }); + options.add(new Option(Main.STOREPASS_OPT, + Messages.getString("KeyPasswdCmd.10"), //$NON-NLS-1$ + Messages.getString("KeyPasswdCmd.9")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksPassword = argument; + } + }); + options.add(new Option(Main.PROVIDER_OPT, + Messages.getString("KeyPasswdCmd.8"), //$NON-NLS-1$ + Messages.getString("KeyPasswdCmd.7")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _providerClassName = argument; + } + }); + options.add(new Option(Main.VERBOSE_OPT, + Messages.getString("KeyPasswdCmd.6")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + verbose = true; + } + }); + result.add(options); + + log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$ + return result; + } + /** * Set the new password to use for protecting Alias's private key. * diff --git a/tools/gnu/classpath/tools/keytool/ListCmd.java b/tools/gnu/classpath/tools/keytool/ListCmd.java index 655242785..674099307 100644 --- a/tools/gnu/classpath/tools/keytool/ListCmd.java +++ b/tools/gnu/classpath/tools/keytool/ListCmd.java @@ -38,6 +38,11 @@ exception statement from your version. */ package gnu.classpath.tools.keytool; +import gnu.classpath.tools.getopt.ClasspathToolParser; +import gnu.classpath.tools.getopt.Option; +import gnu.classpath.tools.getopt.OptionException; +import gnu.classpath.tools.getopt.OptionGroup; +import gnu.classpath.tools.getopt.Parser; import gnu.java.security.util.Base64; import java.io.IOException; @@ -113,12 +118,12 @@ import java.util.logging.Logger; class ListCmd extends Command { private static final Logger log = Logger.getLogger(ListCmd.class.getName()); - private String _alias; - private String _ksType; - private String _ksURL; - private String _ksPassword; - private String _providerClassName; - private boolean rfc; + protected String _alias; + protected String _ksType; + protected String _ksURL; + protected String _ksPassword; + protected String _providerClassName; + protected boolean rfc; private boolean all; // default 0-arguments constructor @@ -166,44 +171,11 @@ class ListCmd extends Command // life-cycle methods ------------------------------------------------------- - int processArgs(String[] args, int i) - { - int limit = args.length; - String opt; - while (++i < limit) - { - opt = args[i]; - log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$ - if (opt == null || opt.length() == 0) - continue; - - if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$ - _alias = args[++i]; - else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$ - _ksType = args[++i]; - else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$ - _ksURL = args[++i]; - else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$ - _ksPassword = args[++i]; - else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$ - _providerClassName = args[++i]; - else if ("-v".equals(opt)) //$NON-NLS-1$ - verbose = true; - else if ("-rfc".equals(opt)) //$NON-NLS-1$ - rfc = true; - else - break; - } - - all = _alias == null; - - return i; - } - void setup() throws Exception { setOutputStreamParam(null); // use stdout setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL); + all = _alias == null; if (! all) setAliasParam(_alias); @@ -218,7 +190,6 @@ class ListCmd extends Command log.finer(" -alias=" + alias); //$NON-NLS-1$ log.finer(" -storetype=" + storeType); //$NON-NLS-1$ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$ - log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$ log.finer(" -provider=" + provider); //$NON-NLS-1$ log.finer(" -v=" + verbose); //$NON-NLS-1$ log.finer(" -rfc=" + rfc); //$NON-NLS-1$ @@ -254,6 +225,81 @@ class ListCmd extends Command // own methods -------------------------------------------------------------- + Parser getParser() + { + log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$ + + Parser result = new ClasspathToolParser(Main.LIST_CMD, true); + result.setHeader(Messages.getString("ListCmd.20")); //$NON-NLS-1$ + result.setFooter(Messages.getString("ListCmd.19")); //$NON-NLS-1$ + OptionGroup options = new OptionGroup(Messages.getString("ListCmd.18")); //$NON-NLS-1$ + options.add(new Option(Main.ALIAS_OPT, + Messages.getString("ListCmd.17"), //$NON-NLS-1$ + Messages.getString("ListCmd.16")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _alias = argument; + } + }); + options.add(new Option(Main.STORETYPE_OPT, + Messages.getString("ListCmd.15"), //$NON-NLS-1$ + Messages.getString("ListCmd.14")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksType = argument; + } + }); + options.add(new Option(Main.KEYSTORE_OPT, + Messages.getString("ListCmd.13"), //$NON-NLS-1$ + Messages.getString("ListCmd.12")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksURL = argument; + } + }); + options.add(new Option(Main.STOREPASS_OPT, + Messages.getString("ListCmd.11"), //$NON-NLS-1$ + Messages.getString("ListCmd.10")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksPassword = argument; + } + }); + options.add(new Option(Main.PROVIDER_OPT, + Messages.getString("ListCmd.9"), //$NON-NLS-1$ + Messages.getString("ListCmd.8")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _providerClassName = argument; + } + }); + options.add(new Option(Main.VERBOSE_OPT, + Messages.getString("ListCmd.7")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + verbose = true; + } + }); + options.add(new Option(Main.RFC_OPT, + Messages.getString("ListCmd.6")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + rfc = true; + } + }); + result.add(options); + + log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$ + return result; + } + /** * Prints the certificate(s) associated with the designated alias. * @@ -312,7 +358,7 @@ class ListCmd extends Command private void print1Chain(Certificate[] chain, PrintWriter writer) throws CertificateEncodingException { - if (!verbose && !rfc) + if (! verbose && ! rfc) fingerprint(chain[0], writer); else { diff --git a/tools/gnu/classpath/tools/keytool/Main.java b/tools/gnu/classpath/tools/keytool/Main.java index fb7aa4509..582aba082 100644 --- a/tools/gnu/classpath/tools/keytool/Main.java +++ b/tools/gnu/classpath/tools/keytool/Main.java @@ -38,8 +38,12 @@ exception statement from your version. */ package gnu.classpath.tools.keytool; -import gnu.classpath.tools.HelpPrinter; import gnu.classpath.tools.common.ProviderUtil; +import gnu.classpath.tools.getopt.ClasspathToolParser; +import gnu.classpath.tools.getopt.Option; +import gnu.classpath.tools.getopt.OptionException; +import gnu.classpath.tools.getopt.OptionGroup; +import gnu.classpath.tools.getopt.Parser; import gnu.java.security.Registry; import gnu.javax.crypto.jce.GnuCrypto; import gnu.javax.security.auth.callback.GnuCallbacks; @@ -57,8 +61,51 @@ import java.util.logging.Logger; public class Main { private static final Logger log = Logger.getLogger(Main.class.getName()); - /** The relative file path to the command tool's help text. */ - private static final String HELP_PATH = "keytool/keytool.txt"; //$NON-NLS-1$ + static final String KEYTOOL_TOOL = "keytool"; //$NON-NLS-1$ + static final String GENKEY_CMD = "genkey"; //$NON-NLS-1$ + static final String IMPORT_CMD = "import"; //$NON-NLS-1$ + static final String SELFCERT_CMD = "selfcert"; //$NON-NLS-1$ + static final String IDENTITYDB_CMD = "identitydb"; //$NON-NLS-1$ + static final String CERTREQ_CMD = "certreq"; //$NON-NLS-1$ + static final String EXPORT_CMD = "export"; //$NON-NLS-1$ + static final String LIST_CMD = "list"; //$NON-NLS-1$ + static final String PRINTCERT_CMD = "printcert"; //$NON-NLS-1$ + static final String KEYCLONE_CMD = "keyclone"; //$NON-NLS-1$ + static final String STOREPASSWD_CMD = "storepasswd"; //$NON-NLS-1$ + static final String KEYPASSWD_CMD = "keypasswd"; //$NON-NLS-1$ + static final String DELETE_CMD = "delete"; //$NON-NLS-1$ + + static final String _GENKEY = "-" + GENKEY_CMD; //$NON-NLS-1$ + static final String _IMPORT = "-" + IMPORT_CMD; //$NON-NLS-1$ + static final String _SELFCERT = "-" + SELFCERT_CMD; //$NON-NLS-1$ + static final String _IDENTITYDB = "-" + IDENTITYDB_CMD; //$NON-NLS-1$ + static final String _CERTREQ = "-" + CERTREQ_CMD; //$NON-NLS-1$ + static final String _EXPORT = "-" + EXPORT_CMD; //$NON-NLS-1$ + static final String _LIST = "-" + LIST_CMD; //$NON-NLS-1$ + static final String _PRINTCERT = "-" + PRINTCERT_CMD; //$NON-NLS-1$ + static final String _KEYCLONE = "-" + KEYCLONE_CMD; //$NON-NLS-1$ + static final String _STOREPASSWD = "-" + STOREPASSWD_CMD; //$NON-NLS-1$ + static final String _KEYPASSWD = "-" + KEYPASSWD_CMD; //$NON-NLS-1$ + static final String _DELETE = "-" + DELETE_CMD; //$NON-NLS-1$ + static final String _HELP = "-help"; //$NON-NLS-1$ + + static final String ALIAS_OPT = "alias"; //$NON-NLS-1$ + static final String SIGALG_OPT = "sigalg"; //$NON-NLS-1$ + static final String KEYALG_OPT = "keyalg"; //$NON-NLS-1$ + static final String KEYSIZE_OPT = "keysize"; //$NON-NLS-1$ + static final String KEYPASS_OPT = "keypass"; //$NON-NLS-1$ + static final String VALIDITY_OPT = "validity"; //$NON-NLS-1$ + static final String STORETYPE_OPT = "storetype"; //$NON-NLS-1$ + static final String STOREPASS_OPT = "storepass"; //$NON-NLS-1$ + static final String KEYSTORE_OPT = "keystore"; //$NON-NLS-1$ + static final String PROVIDER_OPT = "provider"; //$NON-NLS-1$ + static final String FILE_OPT = "file"; //$NON-NLS-1$ + static final String VERBOSE_OPT = "v"; //$NON-NLS-1$ + static final String DEST_OPT = "dest"; //$NON-NLS-1$ + static final String NEW_OPT = "new"; //$NON-NLS-1$ + static final String RFC_OPT = "rfc"; //$NON-NLS-1$ + static final String DNAME_OPT = "dname"; //$NON-NLS-1$ + /** The Preferences key name for the last issued certificate serial nbr. */ static final String LAST_SERIAL_NUMBER = "lastSerialNumber"; //$NON-NLS-1$ /** Constant denoting the X.509 certificate type. */ @@ -70,6 +117,8 @@ public class Main private int gnuCryptoProviderNdx = -2; /** The new position of GNU Callbacks provider if it is not already installed. */ private int gnuCallbacksNdx = -2; + /** The command line parser. */ + private Parser cmdLineParser; private Main() { @@ -81,117 +130,140 @@ public class Main log.entering(Main.class.getName(), "main", args); //$NON-NLS-1$ Main tool = new Main(); + int result = 1; try { tool.setup(); tool.start(args); + result = 0; + } + catch (OptionException x) + { + System.err.println(x.getMessage()); + if (tool.cmdLineParser != null) + tool.cmdLineParser.printHelp(); } catch (SecurityException x) { log.throwing(Main.class.getName(), "main", x); //$NON-NLS-1$ - System.err.println(Messages.getString("Main.6") + x.getMessage()); //$NON-NLS-1$ + System.err.println(Messages.getFormattedString("Main.6", //$NON-NLS-1$ + x.getMessage())); } catch (Exception x) { log.throwing(Main.class.getName(), "main", x); //$NON-NLS-1$ - System.err.println(Messages.getString("Main.8") + x); //$NON-NLS-1$ + System.err.println(Messages.getFormattedString("Main.8", x)); //$NON-NLS-1$ } finally - { - tool.teardown(); - } + { + tool.teardown(); + } - log.exiting(Main.class.getName(), "main"); //$NON-NLS-1$ - // System.exit(0); + log.exiting(Main.class.getName(), "main", Integer.valueOf(result)); //$NON-NLS-1$ + System.exit(result); } // helper methods ----------------------------------------------------------- + private void setup() + { + log.entering(this.getClass().getName(), "setup"); //$NON-NLS-1$ + + cmdLineParser = getParser(); + gnuCryptoProviderNdx = ProviderUtil.addProvider(new GnuCrypto()); + gnuCallbacksNdx = ProviderUtil.addProvider(new GnuCallbacks()); + + log.exiting(this.getClass().getName(), "setup"); //$NON-NLS-1$ + } + private void start(String[] args) throws Exception { - log.entering(this.getClass().getName(), "start", args); //$NON-NLS-1$ + log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$ - if (args == null) - args = new String[0]; + if (args == null || args.length == 0) + throw new OptionException(""); //$NON-NLS-1$ - int limit = args.length; - log.finest("args.length=" + limit); //$NON-NLS-1$ - int i = 0; String opt; Command cmd; - while (i < limit) + while (args.length > 0) { - opt = args[i]; - log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$ - if (opt == null || opt.length() == 0) - continue; - + opt = args[0]; cmd = null; - if ("-genkey".equals(opt)) //$NON-NLS-1$ + if (_GENKEY.equals(opt)) cmd = new GenKeyCmd(); - else if ("-import".equals(opt)) //$NON-NLS-1$ + else if (_IMPORT.equals(opt)) cmd = new ImportCmd(); - else if ("-selfcert".equals(opt)) //$NON-NLS-1$ + else if (_SELFCERT.equals(opt)) cmd = new SelfCertCmd(); - else if ("-identitydb".equals(opt)) //$NON-NLS-1$ + else if (_IDENTITYDB.equals(opt)) cmd = new IdentityDBCmd(); - else if ("-certreq".equals(opt)) //$NON-NLS-1$ + else if (_CERTREQ.equals(opt)) cmd = new CertReqCmd(); - else if ("-export".equals(opt)) //$NON-NLS-1$ + else if (_EXPORT.equals(opt)) cmd = new ExportCmd(); - else if ("-list".equals(opt)) //$NON-NLS-1$ + else if (_LIST.equals(opt)) cmd = new ListCmd(); - else if ("-printcert".equals(opt)) //$NON-NLS-1$ + else if (_PRINTCERT.equals(opt)) cmd = new PrintCertCmd(); - else if ("-keyclone".equals(opt)) //$NON-NLS-1$ + else if (_KEYCLONE.equals(opt)) cmd = new KeyCloneCmd(); - else if ("-storepasswd".equals(opt)) //$NON-NLS-1$ + else if (_STOREPASSWD.equals(opt)) cmd = new StorePasswdCmd(); - else if ("-keypasswd".equals(opt)) //$NON-NLS-1$ + else if (_KEYPASSWD.equals(opt)) cmd = new KeyPasswdCmd(); - else if ("-delete".equals(opt)) //$NON-NLS-1$ + else if (_DELETE.equals(opt)) cmd = new DeleteCmd(); - else if ("-help".equals(opt)) //$NON-NLS-1$ - { - printHelp(); - i++; - } + else if (_HELP.equals(opt)) + throw new OptionException(""); //$NON-NLS-1$ else - { - log.fine("Unknown command [" + opt + "] at index #" + i //$NON-NLS-1$ //$NON-NLS-2$ - + ". Arguments from that token onward will be ignored"); //$NON-NLS-1$ - break; - } - - if (cmd != null) - { - i = cmd.processArgs(args, i); - cmd.doCommand(); - } - } - - // the -help command is the default; i.e. - // keytool - // is equivalent to: - // keytool -help - if (i == 0) - printHelp(); + throw new OptionException(Messages.getFormattedString("Main.18", //$NON-NLS-1$ + opt)); - if (i < limit) // more options than needed - log.fine("Last recognized argument is assumed at index #" + (i - 1) //$NON-NLS-1$ - + ". Remaining arguments (" + args[i] + "...) will be ignored"); //$NON-NLS-1$ //$NON-NLS-2$ + String[] cmdArgs = new String[args.length - 1]; + System.arraycopy(args, 1, cmdArgs, 0, cmdArgs.length); + args = cmd.processArgs(cmdArgs); + cmd.doCommand(); + } log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$ } - private void setup() + private Parser getParser() { - log.entering(this.getClass().getName(), "setup"); //$NON-NLS-1$ - - gnuCryptoProviderNdx = ProviderUtil.addProvider(new GnuCrypto()); - gnuCallbacksNdx = ProviderUtil.addProvider(new GnuCallbacks()); - - log.exiting(this.getClass().getName(), "setup"); //$NON-NLS-1$ + log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$ + + Parser result = new ClasspathToolParser(KEYTOOL_TOOL, true); + result.setHeader(Messages.getString("Main.19")); //$NON-NLS-1$ + result.setFooter(Messages.getString("Main.20")); //$NON-NLS-1$ + OptionGroup cmdGroup = new OptionGroup(Messages.getString("Main.21")); //$NON-NLS-1$ + cmdGroup.add(new NoParseOption(GENKEY_CMD, + Messages.getString("Main.22"))); //$NON-NLS-1$ + cmdGroup.add(new NoParseOption(IMPORT_CMD, + Messages.getString("Main.23"))); //$NON-NLS-1$ + cmdGroup.add(new NoParseOption(SELFCERT_CMD, + Messages.getString("Main.24"))); //$NON-NLS-1$ + cmdGroup.add(new NoParseOption(IDENTITYDB_CMD, + Messages.getString("Main.25"))); //$NON-NLS-1$ + cmdGroup.add(new NoParseOption(CERTREQ_CMD, + Messages.getString("Main.26"))); //$NON-NLS-1$ + cmdGroup.add(new NoParseOption(EXPORT_CMD, + Messages.getString("Main.27"))); //$NON-NLS-1$ + cmdGroup.add(new NoParseOption(LIST_CMD, + Messages.getString("Main.28"))); //$NON-NLS-1$ + cmdGroup.add(new NoParseOption(PRINTCERT_CMD, + Messages.getString("Main.29"))); //$NON-NLS-1$ + cmdGroup.add(new NoParseOption(KEYCLONE_CMD, + Messages.getString("Main.30"))); //$NON-NLS-1$ + cmdGroup.add(new NoParseOption(STOREPASSWD_CMD, + Messages.getString("Main.31"))); //$NON-NLS-1$ + cmdGroup.add(new NoParseOption(KEYPASSWD_CMD, + Messages.getString("Main.32"))); //$NON-NLS-1$ + cmdGroup.add(new NoParseOption(DELETE_CMD, + Messages.getString("Main.33"))); //$NON-NLS-1$ + result.add(cmdGroup); + + log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$ + return result; } private void teardown() @@ -213,7 +285,28 @@ public class Main if (helpPrinted) return; - HelpPrinter.printHelp(HELP_PATH); helpPrinted = true; } + + // Inner class(es) + // ========================================================================== + + private class NoParseOption + extends Option + { + public NoParseOption(String name, String description) + { + super(name, description); + } + + public NoParseOption(String name, String description, String param) + { + super(name, description, param); + } + + public void parsed(String argument) throws OptionException + { + // do nothing + } + } } diff --git a/tools/gnu/classpath/tools/keytool/PrintCertCmd.java b/tools/gnu/classpath/tools/keytool/PrintCertCmd.java index 9ba1d5970..d259258e7 100644 --- a/tools/gnu/classpath/tools/keytool/PrintCertCmd.java +++ b/tools/gnu/classpath/tools/keytool/PrintCertCmd.java @@ -38,6 +38,12 @@ exception statement from your version. */ package gnu.classpath.tools.keytool; +import gnu.classpath.tools.getopt.ClasspathToolParser; +import gnu.classpath.tools.getopt.Option; +import gnu.classpath.tools.getopt.OptionException; +import gnu.classpath.tools.getopt.OptionGroup; +import gnu.classpath.tools.getopt.Parser; + import java.io.PrintWriter; import java.security.cert.Certificate; import java.security.cert.CertificateException; @@ -63,7 +69,7 @@ import java.util.logging.Logger; class PrintCertCmd extends Command { private static final Logger log = Logger.getLogger(PrintCertCmd.class.getName()); - private String _certFileName; + protected String _certFileName; // default 0-arguments constructor @@ -77,40 +83,18 @@ class PrintCertCmd extends Command // life-cycle methods ------------------------------------------------------- - int processArgs(String[] args, int i) - { - int limit = args.length; - String opt; - while (++i < limit) - { - opt = args[i]; - log.finest("args[" + i + "]=" + opt); - if (opt == null || opt.length() == 0) - continue; - - if ("-file".equals(opt)) // -file FILE_NAME - _certFileName = args[++i]; - else if ("-v".equals(opt)) - verbose = true; - else - break; - } - - return i; - } - void setup() throws Exception { setInputStreamParam(_certFileName); - log.finer("-printcert handler will use the following options:"); - log.finer(" -file=" + _certFileName); - log.finer(" -v=" + verbose); + log.finer("-printcert handler will use the following options:"); //$NON-NLS-1$ + log.finer(" -file=" + _certFileName); //$NON-NLS-1$ + log.finer(" -v=" + verbose); //$NON-NLS-1$ } void start() throws CertificateException { - log.entering(getClass().getName(), "start"); + log.entering(getClass().getName(), "start"); //$NON-NLS-1$ CertificateFactory x509Factory = CertificateFactory.getInstance(Main.X_509); Certificate certificate = x509Factory.generateCertificate(inStream); @@ -118,6 +102,39 @@ class PrintCertCmd extends Command writer.println(); printVerbose(certificate, writer); - log.exiting(getClass().getName(), "start"); + log.exiting(getClass().getName(), "start"); //$NON-NLS-1$ + } + + // own methods -------------------------------------------------------------- + + Parser getParser() + { + log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$ + + Parser result = new ClasspathToolParser(Main.PRINTCERT_CMD, true); + result.setHeader(Messages.getString("PrintCertCmd.5")); //$NON-NLS-1$ + result.setFooter(Messages.getString("PrintCertCmd.6")); //$NON-NLS-1$ + OptionGroup options = new OptionGroup(Messages.getString("PrintCertCmd.7")); //$NON-NLS-1$ + options.add(new Option(Main.FILE_OPT, + Messages.getString("PrintCertCmd.8"), //$NON-NLS-1$ + Messages.getString("PrintCertCmd.9")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _certFileName = argument; + } + }); + options.add(new Option(Main.VERBOSE_OPT, + Messages.getString("PrintCertCmd.10")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + verbose = true; + } + }); + result.add(options); + + log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$ + return result; } } diff --git a/tools/gnu/classpath/tools/keytool/SelfCertCmd.java b/tools/gnu/classpath/tools/keytool/SelfCertCmd.java index db7d45994..418bce49f 100644 --- a/tools/gnu/classpath/tools/keytool/SelfCertCmd.java +++ b/tools/gnu/classpath/tools/keytool/SelfCertCmd.java @@ -38,6 +38,11 @@ exception statement from your version. */ package gnu.classpath.tools.keytool; +import gnu.classpath.tools.getopt.ClasspathToolParser; +import gnu.classpath.tools.getopt.Option; +import gnu.classpath.tools.getopt.OptionException; +import gnu.classpath.tools.getopt.OptionGroup; +import gnu.classpath.tools.getopt.Parser; import gnu.java.security.x509.X500DistinguishedName; import java.io.ByteArrayInputStream; @@ -171,15 +176,15 @@ import javax.security.auth.x500.X500Principal; class SelfCertCmd extends Command { private static final Logger log = Logger.getLogger(SelfCertCmd.class.getName()); - private String _alias; - private String _sigAlgorithm; - private String _dName; - private String _password; - private String _validityStr; - private String _ksType; - private String _ksURL; - private String _ksPassword; - private String _providerClassName; + protected String _alias; + protected String _sigAlgorithm; + protected String _dName; + protected String _password; + protected String _validityStr; + protected String _ksType; + protected String _ksURL; + protected String _ksPassword; + protected String _providerClassName; private X500DistinguishedName distinguishedName; private int validityInDays; @@ -253,71 +258,29 @@ class SelfCertCmd extends Command // life-cycle methods ------------------------------------------------------- - int processArgs(String[] args, int i) - { - int limit = args.length; - String opt; - while (++i < limit) - { - opt = args[i]; - log.finest("args[" + i + "]=" + opt); - if (opt == null || opt.length() == 0) - continue; - - if ("-alias".equals(opt)) // -alias ALIAS - _alias = args[++i]; - else if ("-sigalg".equals(opt)) // -sigalg ALGORITHM - _sigAlgorithm = args[++i]; - else if ("-dname".equals(opt)) // -dname NAME - _dName = args[++i]; - else if ("-keypass".equals(opt)) // -keypass PASSWORD - _password = args[++i]; - else if ("-validity".equals(opt)) // -validity DAY_COUNT - _validityStr = args[++i]; - else if ("-storetype".equals(opt)) // -storetype STORE_TYPE - _ksType = args[++i]; - else if ("-keystore".equals(opt)) // -keystore URL - _ksURL = args[++i]; - else if ("-storepass".equals(opt)) // -storepass PASSWORD - _ksPassword = args[++i]; - else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME - _providerClassName = args[++i]; - else if ("-v".equals(opt)) - verbose = true; - else - break; - } - - return i; - } - void setup() throws Exception { setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL); setAliasParam(_alias); setKeyPasswordNoPrompt(_password); -// setDName(_dName); setValidityParam(_validityStr); -// setSignatureAlgorithm(_sigAlgorithm); - - log.finer("-selfcert handler will use the following options:"); - log.finer(" -alias=" + alias); - log.finer(" -sigalg=" + _sigAlgorithm); - log.finer(" -dname=" + _dName); - log.finer(" -keypass=" + _password); - log.finer(" -validity=" + validityInDays); - log.finer(" -storetype=" + storeType); - log.finer(" -keystore=" + storeURL); - log.finer(" -storepass=" + String.valueOf(storePasswordChars)); - log.finer(" -provider=" + provider); - log.finer(" -v=" + verbose); + + log.finer("-selfcert handler will use the following options:"); //$NON-NLS-1$ + log.finer(" -alias=" + alias); //$NON-NLS-1$ + log.finer(" -sigalg=" + _sigAlgorithm); //$NON-NLS-1$ + log.finer(" -dname=" + _dName); //$NON-NLS-1$ + log.finer(" -validity=" + validityInDays); //$NON-NLS-1$ + log.finer(" -storetype=" + storeType); //$NON-NLS-1$ + log.finer(" -keystore=" + storeURL); //$NON-NLS-1$ + log.finer(" -provider=" + provider); //$NON-NLS-1$ + log.finer(" -v=" + verbose); //$NON-NLS-1$ } void start() throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException, IOException, UnsupportedCallbackException, InvalidKeyException, SignatureException, CertificateException { - log.entering(getClass().getName(), "start"); + log.entering(getClass().getName(), "start"); //$NON-NLS-1$ // 1. get the key entry and certificate chain associated to alias Key privateKey = getAliasPrivateKey(); @@ -337,7 +300,7 @@ class SelfCertCmd extends Command byte[] derBytes = getSelfSignedCertificate(distinguishedName, publicKey, (PrivateKey) privateKey); - CertificateFactory x509Factory = CertificateFactory.getInstance("X.509"); + CertificateFactory x509Factory = CertificateFactory.getInstance("X.509"); //$NON-NLS-1$ ByteArrayInputStream bais = new ByteArrayInputStream(derBytes); Certificate certificate = x509Factory.generateCertificate(bais); @@ -348,11 +311,114 @@ class SelfCertCmd extends Command // 7. persist the key store saveKeyStore(); - log.exiting(getClass().getName(), "start"); + log.exiting(getClass().getName(), "start"); //$NON-NLS-1$ } // own methods -------------------------------------------------------------- + Parser getParser() + { + log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$ + + Parser result = new ClasspathToolParser(Main.SELFCERT_CMD, true); + result.setHeader(Messages.getString("SelfCertCmd.14")); //$NON-NLS-1$ + result.setFooter(Messages.getString("SelfCertCmd.15")); //$NON-NLS-1$ + OptionGroup options = new OptionGroup(Messages.getString("SelfCertCmd.16")); //$NON-NLS-1$ + options.add(new Option(Main.ALIAS_OPT, + Messages.getString("SelfCertCmd.17"), //$NON-NLS-1$ + Messages.getString("SelfCertCmd.18")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _alias = argument; + } + }); + options.add(new Option(Main.SIGALG_OPT, + Messages.getString("SelfCertCmd.19"), //$NON-NLS-1$ + Messages.getString("SelfCertCmd.20")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _sigAlgorithm = argument; + } + }); + options.add(new Option(Main.DNAME_OPT, + Messages.getString("SelfCertCmd.21"), //$NON-NLS-1$ + Messages.getString("SelfCertCmd.22")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _dName = argument; + } + }); + options.add(new Option(Main.KEYPASS_OPT, + Messages.getString("SelfCertCmd.23"), //$NON-NLS-1$ + Messages.getString("SelfCertCmd.24")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _password = argument; + } + }); + options.add(new Option(Main.VALIDITY_OPT, + Messages.getString("SelfCertCmd.25"), //$NON-NLS-1$ + Messages.getString("SelfCertCmd.26")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _validityStr = argument; + } + }); + options.add(new Option(Main.STORETYPE_OPT, + Messages.getString("SelfCertCmd.27"), //$NON-NLS-1$ + Messages.getString("SelfCertCmd.28")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksType = argument; + } + }); + options.add(new Option(Main.KEYSTORE_OPT, + Messages.getString("SelfCertCmd.29"), //$NON-NLS-1$ + Messages.getString("SelfCertCmd.30")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksURL = argument; + } + }); + options.add(new Option(Main.STOREPASS_OPT, + Messages.getString("SelfCertCmd.31"), //$NON-NLS-1$ + Messages.getString("SelfCertCmd.32")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksPassword = argument; + } + }); + options.add(new Option(Main.PROVIDER_OPT, + Messages.getString("SelfCertCmd.33"), //$NON-NLS-1$ + Messages.getString("SelfCertCmd.34")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _providerClassName = argument; + } + }); + options.add(new Option(Main.VERBOSE_OPT, + Messages.getString("SelfCertCmd.35")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + verbose = true; + } + }); + result.add(options); + + log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$ + return result; + } + private void setDName(String name, X500Principal defaultName) { if (name != null && name.trim().length() > 0) diff --git a/tools/gnu/classpath/tools/keytool/StorePasswdCmd.java b/tools/gnu/classpath/tools/keytool/StorePasswdCmd.java index 1eb053c1c..e9262bd71 100644 --- a/tools/gnu/classpath/tools/keytool/StorePasswdCmd.java +++ b/tools/gnu/classpath/tools/keytool/StorePasswdCmd.java @@ -39,6 +39,11 @@ exception statement from your version. */ package gnu.classpath.tools.keytool; import gnu.classpath.SystemProperties; +import gnu.classpath.tools.getopt.ClasspathToolParser; +import gnu.classpath.tools.getopt.Option; +import gnu.classpath.tools.getopt.OptionException; +import gnu.classpath.tools.getopt.OptionGroup; +import gnu.classpath.tools.getopt.Parser; import java.io.IOException; import java.security.KeyStoreException; @@ -107,11 +112,11 @@ import javax.security.auth.callback.UnsupportedCallbackException; class StorePasswdCmd extends Command { private static final Logger log = Logger.getLogger(StorePasswdCmd.class.getName()); - private String _newPassword; - private String _ksType; - private String _ksURL; - private String _ksPassword; - private String _providerClassName; + protected String _newPassword; + protected String _ksType; + protected String _ksURL; + protected String _ksPassword; + protected String _providerClassName; private char[] newStorePasswordChars; // default 0-arguments constructor @@ -150,46 +155,14 @@ class StorePasswdCmd extends Command // life-cycle methods ------------------------------------------------------- - int processArgs(String[] args, int i) - { - int limit = args.length; - String opt; - while (++i < limit) - { - opt = args[i]; - log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$ - if (opt == null || opt.length() == 0) - continue; - - if ("-new".equals(opt)) // -new PASSWORD //$NON-NLS-1$ - _newPassword = args[++i]; - else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$ - _ksType = args[++i]; - else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$ - _ksURL = args[++i]; - else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$ - _ksPassword = args[++i]; - else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$ - _providerClassName = args[++i]; - else if ("-v".equals(opt)) //$NON-NLS-1$ - verbose = true; - else - break; - } - - return i; - } - void setup() throws Exception { setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL); setNewKeystorePassword(_newPassword); log.finer("-storepasswd handler will use the following options:"); //$NON-NLS-1$ - log.finer(" -new=" + String.valueOf(newStorePasswordChars)); //$NON-NLS-1$ log.finer(" -storetype=" + storeType); //$NON-NLS-1$ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$ - log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$ log.finer(" -provider=" + provider); //$NON-NLS-1$ log.finer(" -v=" + verbose); //$NON-NLS-1$ } @@ -206,6 +179,73 @@ class StorePasswdCmd extends Command // own methods -------------------------------------------------------------- + Parser getParser() + { + log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$ + + Parser result = new ClasspathToolParser(Main.STOREPASSWD_CMD, true); + result.setHeader(Messages.getString("StorePasswdCmd.18")); //$NON-NLS-1$ + result.setFooter(Messages.getString("StorePasswdCmd.17")); //$NON-NLS-1$ + OptionGroup options = new OptionGroup(Messages.getString("StorePasswdCmd.16")); //$NON-NLS-1$ + options.add(new Option(Main.NEW_OPT, + Messages.getString("StorePasswdCmd.15"), //$NON-NLS-1$ + Messages.getString("StorePasswdCmd.8")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _newPassword = argument; + } + }); + options.add(new Option(Main.STORETYPE_OPT, + Messages.getString("StorePasswdCmd.13"), //$NON-NLS-1$ + Messages.getString("StorePasswdCmd.12")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksType = argument; + } + }); + options.add(new Option(Main.KEYSTORE_OPT, + Messages.getString("StorePasswdCmd.11"), //$NON-NLS-1$ + Messages.getString("StorePasswdCmd.10")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksURL = argument; + } + }); + options.add(new Option(Main.STOREPASS_OPT, + Messages.getString("StorePasswdCmd.9"), //$NON-NLS-1$ + Messages.getString("StorePasswdCmd.8")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _ksPassword = argument; + } + }); + options.add(new Option(Main.PROVIDER_OPT, + Messages.getString("StorePasswdCmd.7"), //$NON-NLS-1$ + Messages.getString("StorePasswdCmd.6")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + _providerClassName = argument; + } + }); + options.add(new Option(Main.VERBOSE_OPT, + Messages.getString("StorePasswdCmd.5")) //$NON-NLS-1$ + { + public void parsed(String argument) throws OptionException + { + verbose = true; + } + }); + result.add(options); + + log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$ + return result; + } + protected void setNewKeystorePassword(String password) throws IOException, UnsupportedCallbackException { diff --git a/tools/gnu/classpath/tools/keytool/keytool.txt b/tools/gnu/classpath/tools/keytool/keytool.txt deleted file mode 100644 index 15f9b96f9..000000000 --- a/tools/gnu/classpath/tools/keytool/keytool.txt +++ /dev/null @@ -1,616 +0,0 @@ -NAME - keytool - manage private keys and public certificates - -SYNOPSIS - keytool [COMMAND]... - -DESCRIPTION - A Java-based tool for managing both Key Entries as well as Trusted - Certificates. - - Multiple COMMANDs may be specified at once, each complete with its own - options. keytool will parse all the arguments, before processing, and - executing, each COMMAND. If an exception occurs while executing one - COMMAND keytool will abort. - - A COMMAND can be one of the followings: - - -genkey [OPTION]... - Generate a new Key Entry, eventually creating a new key store. - - -import [OPTION]... - Add, to a key store, Key Entries (private keys and certificate - chains authenticating the public keys) and Trusted Certificates - (3rd party certificates which can be used as Trust anchors when - building chains-of-trust). - - -selfcert [OPTION]... - Generate a new self-signed Trusted Certificate. - - -identitydb [OPTION]... - NOT IMPLEMENTED YET. - Import a JDK 1.1 style Identity Database. - - -certreq [OPTION]... - Issue a Certificate Signing Request (CSR) which can be then sent - to a Certification Authority (CA) to issue a certificate signed - (by the CA) and authenticating the Subject of the request. - - -export [OPTION]... - Export a Certificate from a key store. - - -list [OPTION]... - Print one or all Certificates in a key store to STDOUT. - - -printcert [OPTION]... - Print a human-readable form of a Certificate in a designated - file to STDOUT. - - -keyclone [OPTION]... - Clone a Key Entry in a key store. - - -storepasswd [OPTION]... - Change the password protecting a key store. - - -keypasswd [OPTION]... - Change the password protecting a Key Entry in a key store. - - -delete [OPTION]... - Delete a Key Entry or a Trusted Certificate from a key store. - - -help Display this text. - -OPTIONS COMMON TO MORE THAN ONE COMMAND - The following OPTIONs are used in more than one COMMAND. They are - described here to reduce redundancy. - - -alias ALIAS - Every entry, be it a Key Entry or a Trusted Certificate, in a - key store is uniquely identified by a user-defined Alias string. - Use this option to specify the Alias to use when referring to an - entry in the key store. Unless specified otherwise, a default - value of "mykey" (all lower case, without the enclosing quotes) - shall be used when this option is omitted from the command line. - - -keyalg ALGORITHM - Use this option to specify the canonical name of the key-pair - generation algorithm. The default value for this option is - "DSS" (a synonym for the Digital Signature Algorithm also known - as DSA). - - -keysize SIZE - Use this option to specify the number of bits of the shared - modulus (for both the public and private keys) to use when - generating new keys. A default value of 1024 will be used if - this option is omitted from the command line. - - -validity DAY_COUNT - Use this option to specify the number of days a newly generated - certificate will be valid for. The default value is 90 (days) - if this option is omitted from the command line. - - -storetype STORE_TYPE - Use this option to specify the type of the key store to use. - The default value, if this option is omitted, is that of the - property "keystore.type" in the security properties file, which - is obtained by invoking the static method call getDefaultType() - in java.security.KeyStore. - - -storepass PASSWORD - Use this option to specify the password protecting the key - store. If this option is omitted from the command line, you - will be prompted to provide a password. - - -keystore URL - Use this option to specify the location of the key store to use. - The default value is a file URL referencing the file named - ".keystore" (all lower case and without the enclosing quotes) - located in the path returned by the call to - java.lang.System#getProperty(String) using "user.home" as - argument. - - If a URL was specified, but was found to be malformed --e.g. - missing protocol element-- the tool will attempt to use the URL - value as a file-name (with absolute or relative path-name) of a - key store --as if the protocol was "file:". - - -provider PROVIDER_CLASS_NAME - A fully qualified class name of a Security Provider to add to - the current list of Security Providers already installed in the - JVM in-use. If a provider class is specified with this option, - and was successfully added to the runtime --i.e. it was not - already installed-- then the tool will attempt to remove this - Security Provider before exiting. - - -file FILE_NAME - Use this option to designate a file to use with a command. When - specified with this option, the value is expected to be the - fully qualified path of a file accessible by the File System. - Depending on the command, the file may be used as input or as - output. When this option is omitted from the command line, - STDIN will be used instead, as the source of input, and STDOUT - will be used instead as the output destination. - - -v Unless specified otherwise, use this option to enable more - verbose output. - -X.500 DISTINGUISHED NAME - A Distinguished Name (or DN) MUST be supplied with some of the COMMANDs - using a -dname option. The syntax of a valid value for this option MUST - follow RFC-2253 specifications. Namely the following components (with - their accepted meaning) will be recognized. Note that the component - name is case-insensitive: - - CN The Common Name; e.g. "host.domain.com" - OU The Organizational Unit; e.g. "IT Department" - O The Organization Name; e.g. "The Sample Company" - L The Locality Name; e.g. "Sydney" - ST The State Name; e.g. "New South Wales" - C The 2-letter Country identifier; e.g. "AU" - - When specified with a -dname option, each pair of component/value will - be separated from the other with a comma. Each component and value pair - MUST be separated by an equal sign. For example, the following is - a valid DN value: - - CN=host.domain.com, O=The Sample Company, L=Sydney, ST=NSW, C=AU - - If the Distinguished Name is required, and no valid default value can be - used, the tool will prompt you to enter the information through the - console. - --genkey COMMAND - Generate a new key-pair (both private and public keys), and save these - credentials in the key store as a Key Entry, associated with the - designated (if was specified in the -alias option) or default (if the - -alias option is omitted) Alias. - - The private key material will be protected with a user-defined password - (see -keypass option). The public key on the other hand will be part - of a self-signed X.509 certificate, which will form a 1-element chain - and will be saved in the key store. - - -alias ALIAS - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -keyalg ALGORITHM - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -keysize KEY_SIZE - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -sigalg ALGORITHM - The canonical name of the digital signature algorithm to use for - signing certificates. If this option is omitted, a default - value will be chosen based on the type of the key-pair; i.e. the - algorithm that ends up being used by the -keyalg option. If the - key-pair generation algorithm is "DSA", the value for the - signature algorithm will be "SHA1withDSA". If on the other hand - the key-pair generation algorithm is "RSA", then the tool will - use "MD5withRSA" as the signature algorithm. - - -dname NAME - This a mandatory value for the command. If no value is - specified --i.e. the -dname option is omitted-- the tool will - prompt you to enter a Distinguished Name to use as both the - Owner and Issuer of the generated self-signed certificate. - - (see X.500 DISTINGUISHED NAME) - - -keypass PASSWORD - Use this option to specify the password which the tool will use - to protect the newly created Key Entry. - - If this option is omitted, you will be prompted to provide a - password. - - -validity DAY_COUNT - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -storetype STORE_TYPE - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -keystore URL - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -storepass PASSWORD - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -provider PROVIDER_CLASS_NAME - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - --import COMMAND - Read an X.509 certificate, or a PKCS#7 Certificate Reply from a - designated input source and incorporate the certificates into the key - store. - - If the Alias does not already exist in the key store, the tool treats - the certificate read from the input source as a new Trusted Certificate. - It then attempts to discover a chain-of-trust, starting from that - certificate and ending at another Trusted Certificate, already stored in - the key store. If the -trustcacerts option is present, an additional - key store, of type "JKS" named "cacerts", and assumed to be present in - ${JAVA_HOME}/lib/security will also be consulted if found --${JAVA_HOME} - refers to the location of an installed Java Runtime Environment (JRE). - If no chain-of-trust can be established, and unless the -noprompt option - has been specified, the certificate is printed to STDOUT and the user is - prompted for a confirmation. - - If Alias exists in the key store, the tool will treat the certificate(s) - read from the input source as a Certificate Reply, which can be a chain - of certificates, that eventually would replace the chain of certificates - associated with the Key Entry of that Alias. The substitution of the - certificates only occurs if a chain-of-trust can be established between - the bottom certificate of the chain read from the input file and the - Trusted Certificates already present in the key store. Again, if the - -trustcacerts option is specified, additional Trusted Certificates in - the same "cacerts" key store will be considered. If no chain-of-trust - can be established, the operation will abort. - - -alias ALIAS - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -file FILE_NAME - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -keypass PASSWORD - Use this option to specify the password which the tool will use - to protect the Key Entry associated with the designated Alias, - when replacing this Alias' chain of certificates with that found - in the certificate reply. - - If this option is omitted, and the chain-of-trust for the - certificate reply has been established, the tool will first - attempt to unlock the Key Entry using the same password - protecting the key store. If this fails, you will then be - prompted to provide a password. - - -noprompt - Use this option to prevent the tool from prompting the user. - - -trustcacerts - Use this option to indicate to the tool that a key store, of - type "JKS", named "cacerts", and usually located in lib/security - in an installed Java Runtime Environment should be considered - when trying to establish chain-of-trusts. - - -storetype STORE_TYPE - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -keystore URL - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -storepass PASSWORD - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -provider PROVIDER_CLASS_NAME - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - --selfcert COMMAND - Generate a self-signed X.509 version 1 certificate. The newly generated - certificate will form a chain of one element which will replace the - previous chain associated with the designated Alias (if -alias option - was specified), or the default Alias (if -alias option was omitted). - - -alias ALIAS - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -sigalg ALGORITHM - The canonical name of the digital signature algorithm to use for - signing the certificate. If this option is omitted, a default - value will be chosen based on the type of the private key - associated with the designated Alias. If the private key is a - "DSA" one, the value for the signature algorithm will be - "SHA1withDSA". If on the other hand the private key is an "RSA" - one, then the tool will use "MD5withRSA" as the signature - algorithm. - - -dname NAME - Use this option to specify the Distinguished Name of the newly - generated self-signed certificate. If this option is omitted, - the existing Distinguished Name of the base certificate in the - chain associated with the designated Alias will be used instead. - - (see X.500 DISTINGUISHED NAME) - - -validity DAY_COUNT - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -keypass PASSWORD - Use this option to specify the password which the tool will use - to unlock the Key Entry associated with the designated Alias. - - If this option is omitted, the tool will first attempt to unlock - the Key Entry using the same password protecting the key store. - If this fails, you will then be prompted to provide a password. - - -storetype STORE_TYPE - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -keystore URL - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -storepass PASSWORD - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -provider PROVIDER_CLASS_NAME - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - --identitydb COMMAND - NOT IMPLEMENTED YET. - - Import a JDK 1.1 style Identity Database. - - -file FILE_NAME - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -storetype STORE_TYPE - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -keystore URL - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -storepass PASSWORD - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -provider PROVIDER_CLASS_NAME - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - --certreq COMMAND - Generate a PKCS#10 Certificate Signing Request (CSR) and writes it to - a designated output destination. The contents of the destination - should look something like the following: - - -----BEGIN NEW CERTIFICATE REQUEST----- - MIICYTCCAiECAQAwXzEUMBIGA1UEAwwLcnNuQGdudS5vcmcxGzAZBgNVBAoMElUg - Q29tcGFueTEPMA0GA1UEBwwGU3lkbmV5MQwwCgYDVQQIDANOU1cxCzAJBgNVBACC - ... - FCTlKlok8KwGuIVwNVOfQLRX+O5kAhQ/a4RTZme2L8PnpvgRwrf7Eg8D6w== - -----END NEW CERTIFICATE REQUEST----- - - IMPORTANT: Some documentation (e.g. RSA examples) claims that the - Attributes field, in the CSR is OPTIONAL while RFC-2986 implies the - opposite. This implementation considers this field, by default, as - OPTIONAL, unless the option -attributes is specified on the command - line. - - -alias ALIAS - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -sigalg ALGORITHM - The canonical name of the digital signature algorithm to use for - signing the certificate. If this option is omitted, a default - value will be chosen based on the type of the private key - associated with the designated Alias. If the private key is a - "DSA" one, the value for the signature algorithm will be - "SHA1withDSA". If on the other hand the private key is an "RSA" - one, then the tool will use "MD5withRSA" as the signature - algorithm. - - -file FILE_NAME - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -keypass PASSWORD - Use this option to specify the password which the tool will use - to unlock the Key Entry associated with the designated Alias. - - If this option is omitted, the tool will first attempt to unlock - the Key Entry using the same password protecting the key store. - If this fails, you will then be prompted to provide a password. - - -storetype STORE_TYPE - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -keystore URL - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -storepass PASSWORD - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -provider PROVIDER_CLASS_NAME - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -attributes - Use this option to force the tool to encode a NULL DER value in - the CSR as the value of the Attributes field. - --export COMMAND - Export a certificate stored in the key store to a designated output - destination, either in binary format (if the -v option is specified), - or in RFC-1421 compliant encoding (if the -rfc option is specified - instead). - - -alias ALIAS - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -file FILE_NAME - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -storetype STORE_TYPE - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -keystore URL - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -storepass PASSWORD - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -provider PROVIDER_CLASS_NAME - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -rfc Use RFC-1421 specifications when encoding the output. - - -v Output the certificate in binary DER encoding. This is the - default output format of the command if neither -rfc nor -v - options were detected on the command line. If both this option - and the -rfc option are detected on the command line, the tool - will opt for the RFC-1421 style encoding. - --list COMMAND - Print one or all of the key store entries to STDOUT. Usually this - command will only print a fingerprint of the certificate, unless either - the -rfc or the -v option is specified. - - -alias ALIAS - If this option is omitted, the tool will print ALL the entries - found in the key store. - - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -storetype STORE_TYPE - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -keystore URL - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -storepass PASSWORD - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -provider PROVIDER_CLASS_NAME - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -rfc Use RFC-1421 specifications when encoding the output. - - -v Output the certificate in human-readable format. If both this - option and the -rfc option are detected on the command line, - the tool will opt for the human-readable form and will not - abort the command. - --printcert COMMAND - Read a certificate from a designated input source and print it to STDOUT - in a human-readable form. - - -file FILE_NAME - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - --keyclone COMMAND - Clone an existing Key Entry and store it under a new (different) Alias - protecting, its private key material with possibly a new password. - - -alias ALIAS - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -dest ALIAS - Use this option to specify the new Alias which will be used to - identify the cloned copy of the Key Entry. - - -keypass PASSWORD - Use this option to specify the password which the tool will use - to unlock the Key Entry associated with the designated Alias. - - If this option is omitted, the tool will first attempt to unlock - the Key Entry using the same password protecting the key store. - If this fails, you will then be prompted to provide a password. - - -new PASSWORD - Use this option to specify the password protecting the private - key material of the newly cloned copy of the Key Entry. - - -storetype STORE_TYPE - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -keystore URL - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -storepass PASSWORD - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -provider PROVIDER_CLASS_NAME - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - --storepasswd COMMAND - Change the password protecting a key store. - - -new PASSWORD - The new, and different, password which will be used to protect - the designated key store. - - -storetype STORE_TYPE - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -keystore URL - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -storepass PASSWORD - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -provider PROVIDER_CLASS_NAME - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - --keypasswd COMMAND - Change the password protecting the private key material of a designated - Key Entry. - - -alias ALIAS - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -keypass PASSWORD - Use this option to specify the password which the tool will use - to unlock the Key Entry associated with the designated Alias. - - If this option is omitted, the tool will first attempt to unlock - the Key Entry using the same password protecting the key store. - If this fails, you will then be prompted to provide a password. - - -new PASSWORD - The new, and different, password which will be used to protect - the private key material of the designated Key Entry. - - -storetype STORE_TYPE - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -keystore URL - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -storepass PASSWORD - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -provider PROVIDER_CLASS_NAME - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - --delete COMMAND - Delete a designated key store entry. - - -alias ALIAS - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -storetype STORE_TYPE - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -keystore URL - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -storepass PASSWORD - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -provider PROVIDER_CLASS_NAME - (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - - -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND) - -REPORTING BUGS - Please report bugs at http://www.gnu.org/software/classpath/bugs.html - -COPYRIGHT - Copyright (C) 2006 Free Software Foundation, Inc. - This is free software; see the source for copying conditions. There is - NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR - PURPOSE. diff --git a/tools/gnu/classpath/tools/rmi/RMIC.java b/tools/gnu/classpath/tools/rmi/RMIC.java index c44453011..fa4d87c17 100644 --- a/tools/gnu/classpath/tools/rmi/RMIC.java +++ b/tools/gnu/classpath/tools/rmi/RMIC.java @@ -41,7 +41,7 @@ public class RMIC /** * The version of the compiler. */ - public static String VERSION = "0.0 alpha pre"; + public static String VERSION = "0.01 alpha pre"; /** * The GRMIC compiler methods @@ -112,6 +112,17 @@ public class RMIC else HelpPrinter.printHelpAndExit(HelpPath); } + else if (c.equals("-classpath")) + { + int f = i + 1; + if (f < args.length) + { + compiler.setClassPath(args[f]); + i++; + } + else + HelpPrinter.printHelpAndExit(HelpPath); + } else if (c.charAt(0) != '-') // No more options - start of class list. { @@ -132,17 +143,7 @@ public class RMIC if (args[i].charAt(0) != '-') { compiler.reset(); - Class c = null; - try - { - c = Thread.currentThread().getContextClassLoader().loadClass( - args[i]); - } - catch (ClassNotFoundException e) - { - System.err.println(args[i] + " class not found."); - System.exit(1); - } + Class c = compiler.loadClass(args[i]); compiler.compile(c); String packag = compiler.getPackageName().replace('.', '/'); diff --git a/tools/gnu/classpath/tools/rmi/RMIC.txt b/tools/gnu/classpath/tools/rmi/RMIC.txt index 7ec371e9a..882cca553 100644 --- a/tools/gnu/classpath/tools/rmi/RMIC.txt +++ b/tools/gnu/classpath/tools/rmi/RMIC.txt @@ -9,25 +9,29 @@ Please report bugs at http://www.gnu.org/software/classpath/bugs.html Usage: rmic <options> <class names> where <options> includes: - -nowarn Show no warnings - -nowrite Do not write any files (check for errors only) - -d <folder> Place generated files into the given folder + -nowarn Show no warnings + -nowrite Do not write any files (check for errors only) + -d <folder> Place generated files into the given folder + -classpath <path> Specifies the path, where to find the classes being + compiled - -help Print this help text - -v Print version - -verbose Verbose output - -force Try to generate code even if the input classes seem not - consistent with RMI specification. + -help Print this help text + -v Print version + -verbose Verbose output + -force Try to generate code even if the input classes seem not + consistent with RMI specification. - -1.2 Generate v 1.2 stubs (default)* + -1.2 Generate v 1.2 stubs (default)* - -iiop Generate stubs and ties for the GIOP based RMI package extension, - javax.rmi. With this key, the two additional keys are accepted: - -poa Generate the Servant based ties (default) - -impl Generate the obsoleted ObjectImpl based ties - (for backward compatibility) - -help Show more details on the giop stub and tie generator options. - -giop Same as -iiop* + -iiop Generate stubs and ties for the GIOP based RMI package + extension, javax.rmi. With this key, the two additional + keys are accepted: + -poa Generate the Servant based ties (default) + -impl Generate the obsoleted ObjectImpl based ties + (for backward compatibility) + -help Show more details on the giop stub and tie generator + options. + -giop Same as -iiop* and <class names> can include one or more non abstract classes that implement diff --git a/tools/jarsigner.sh.in b/tools/jarsigner.in index cea95a288..cea95a288 100644 --- a/tools/jarsigner.sh.in +++ b/tools/jarsigner.in diff --git a/tools/keytool.sh.in b/tools/keytool.in index 6c11dc407..6c11dc407 100644 --- a/tools/keytool.sh.in +++ b/tools/keytool.in diff --git a/vm/reference/gnu/java/nio/VMChannel.java b/vm/reference/gnu/java/nio/VMChannel.java new file mode 100644 index 000000000..fdea8ff62 --- /dev/null +++ b/vm/reference/gnu/java/nio/VMChannel.java @@ -0,0 +1,197 @@ +/* VMChannel.java -- Native interface suppling channel operations. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.nio; + +import gnu.classpath.Configuration; +import gnu.java.net.PlainSocketImpl; +import gnu.java.nio.PipeImpl.SinkChannelImpl; +import gnu.java.nio.PipeImpl.SourceChannelImpl; +import gnu.java.nio.channels.FileChannelImpl; + +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * Native interface to support configuring of channel to run in a non-blocking + * manner and support scatter/gather io operations. + * + * @author Michael Barker <mike@middlesoft.co.uk> + * + */ +public class VMChannel +{ + private final int fd; + + private VMChannel(int fd) + { + this.fd = fd; + } + + public static VMChannel getVMChannel(PlainSocketImpl socket) + { + return new VMChannel(socket.getNativeFD()); + } + + public static VMChannel getVMChannel(SourceChannelImpl source) + { + return new VMChannel(source.getNativeFD()); + } + + public static VMChannel getVMChannel(SinkChannelImpl sink) + { + return new VMChannel(sink.getNativeFD()); + } + + public static VMChannel getVMChannel(FileChannelImpl file) + { + return new VMChannel(file.getNativeFD()); + } + + static + { + // load the shared library needed for native methods. + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary ("javanio"); + } + initIDs(); + } + + /** + * Set the file descriptor to have the required blocking + * setting. + * + * @param fd + * @param blocking + */ + public native void setBlocking(int fd, boolean blocking); + + public void setBlocking(boolean blocking) + { + setBlocking(fd, blocking); + } + + + /** + * Reads a byte buffer directly using the supplied file descriptor. + * Assumes that the buffer is a DirectBuffer. + * + * @param fd Native file descriptor to read from. + * @param dst Direct Byte Buffer to read to. + * @return Number of bytes read. + * @throws IOException If an error occurs or dst is not a direct buffers. + */ + native int read(int fd, ByteBuffer dst) + throws IOException; + + public int read(ByteBuffer dst) + throws IOException + { + return read(fd, dst); + } + + /** + * Reads into byte buffers directly using the supplied file descriptor. + * Assumes that the buffer list contains DirectBuffers. Will perform a + * scattering read. + * + * @param fd Native file descriptor to read from. + * @param dsts An array direct byte buffers. + * @param offset Index of the first buffer to read to. + * @param length The number of buffers to read to. + * @return Number of bytes read. + * @throws IOException If an error occurs or the dsts are not direct buffers. + */ + native long readScattering(int fd, ByteBuffer[] dsts, int offset, int length) + throws IOException; + + public long readScattering(ByteBuffer[] dsts, int offset, int length) + throws IOException + { + if (offset + length > dsts.length) + throw new IndexOutOfBoundsException("offset + length > dsts.length"); + + return readScattering(fd, dsts, offset, length); + } + + /** + * Writes from a direct byte bufer using the supplied file descriptor. + * Assumes the buffer is a DirectBuffer. + * + * @param fd + * @param src + * @return Number of bytes written. + * @throws IOException + */ + native int write(int fd, ByteBuffer src) + throws IOException; + + public int write(ByteBuffer src) + throws IOException + { + return write(fd, src); + } + + /** + * Writes from byte buffers directly using the supplied file descriptor. + * Assumes the that buffer list constains DirectBuffers. Will perform + * as gathering write. + * + * @param fd + * @param srcs + * @param offset + * @param length + * @return Number of bytes written. + * @throws IOException + */ + native long writeGathering(int fd, ByteBuffer[] srcs, int offset, int length) + throws IOException; + + public long writeGathering(ByteBuffer[] srcs, int offset, int length) + throws IOException + { + if (offset + length > srcs.length) + throw new IndexOutOfBoundsException("offset + length > srcs.length"); + + return writeGathering(fd, srcs, offset, length); + } + + private native static void initIDs(); + +} |