JDK-4995337 : print dialog does not remember changes made to page setup
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 1.4.1
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2004-02-16
  • Updated: 2005-02-01
  • Resolved: 2004-12-23
Related Reports
Duplicate :  
Description
ary. */ public void dispose() { if (m_bReset) { m_tree.setBackground( m_clrBackground ); DefaultTreeCellRenderer rdr = (DefaultTreeCellRenderer) m_tree.getCellRenderer();
rdr.setBackgroundSelectionColor(    m_clrBackgroundSelection    );
rdr.setBackgroundNonSelectionColor( m_clrBackgroundNonSelection );
rdr.setTextSelectionColor(          m_clrTextSelection          );
rdr.setTextNonSelectionColor(       m_clrTextNonSelection       );
rdr.setBorderSelectionColor(        m_clrBorderSelection        );
}
}
} // cTreePrinter
}
==========================================

Display process view on a job or impact analysis on a table or column.  Select print.  Page setup dialog is displayed. Cancel page setup dialog.  Print dialog is displayed. Select properties and select landscape on properties dialog. View is NOT printed in landscape.

Again, using java.awt.print.PrinterJob. It appears like the java code does not expect the properties dialog to exist on the print dialog. If a page format of landscape is used in the PrinterJob, landscape is not initially set in the properties dialog either.



======================================================================
Name: rv122619			Date: 02/16/2004

See attached code: 2 files MainFRame.java and ComponentPrinter.java 

File 1:MainFrame.java

/**
* Title:        MainFrame.java
* Description:
*/
package com.sas.test;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.WindowEvent;
import java.awt.print.PageFormat;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
/*
*
*
*
*
*/
public class MainFrame extends JFrame
{
private AbstractAction m_actFile;
private AbstractAction m_actPrint;
private AbstractAction m_actPageSetup;
private AbstractAction m_actExit;
private JTree            m_tree;
private DefaultTreeModel m_mdl;

private PageFormat       m_page;

public MainFrame()
{
setDefaultCloseOperation( EXIT_ON_CLOSE );
initialize();
setLocation( new Point( 200, 200 ) );
setSize( new Dimension( 550, 250 ) );
}
private void initialize()
{
setTitle( "PrintTest" );
createActions();
createMainMenu();
createContents();
}

private void createActions()
{
m_actFile      = new cFileAction();
m_actPrint     = new cPrintAction();
m_actPageSetup = new cPageSetupAction();
m_actExit      = new cExitAction();
}

private void createMainMenu()
{
JMenuBar menuMain = new JMenuBar();

JMenu menuFile = new JMenu( m_actFile );
menuFile.add( m_actPrint     );
menuFile.add( m_actPageSetup );
menuFile.addSeparator();
menuFile.add( m_actExit      );

menuMain.add( menuFile );

this.setJMenuBar( menuMain );
}
private void createContents()
{
m_tree = new JTree();
m_mdl  = (DefaultTreeModel) m_tree.getModel(); DefaultMutableTreeNode nodeRoot = (DefaultMutableTreeNode) m_mdl.getRoot(); nodeRoot.setUserObject( "ReconnectTableFail1" ); m_mdl.nodeChanged( nodeRoot ); expand( m_tree, nodeRoot );

JScrollPane scrTree = new JScrollPane( m_tree );
JPanel pnlContents = (JPanel) getContentPane(); pnlContents.setLayout( new GridBagLayout() ); pnlContents.add( scrTree, new GridBagConstraints( 0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets( 0, 0, 0, 0 ), 0, 0 ) ); }

private void expand( JTree tree, TreeNode node )
{
if (node.isLeaf())
return;

TreeNode[] aPathNodes = ((DefaultTreeModel) m_tree.getModel()).getPathToRoot( node ); tree.expandPath( new TreePath( aPathNodes ) ); for ( int iChild=0; iChild<node.getChildCount(); iChild++ ) expand( tree, node.getChildAt( iChild ) ); } public static void main( String[] saArgs ) { // set the UI to the system UI try { UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() ); }
catch (ClassNotFoundException          e) {}
catch (IllegalAccessException          e) {}
catch (InstantiationException          e) {}
catch (UnsupportedLookAndFeelException e) {}
// create the main frame and show it
MainFrame f = new MainFrame();
f.setVisible( true );
}

protected class cFileAction extends AbstractAction
{
public cFileAction()
{
putValue( AbstractAction.NAME,              "File"             );
putValue( AbstractAction.SHORT_DESCRIPTION, "Files"            );
putValue( AbstractAction.MNEMONIC_KEY,      new Integer( 'F' ) );
putValue( AbstractAction.SMALL_ICON,        null               );
}

public void actionPerformed( ActionEvent e )
{
}
} // cFileAction

protected class cPrintAction extends AbstractAction
{
public cPrintAction()
{
putValue( AbstractAction.NAME,              "Print..."         );
putValue( AbstractAction.SHORT_DESCRIPTION, "Prints"           );
putValue( AbstractAction.MNEMONIC_KEY,      new Integer( 'P' ) );
putValue( AbstractAction.SMALL_ICON,        null               );
}

public void actionPerformed( ActionEvent e )
{
if (m_page == null)
m_page = new PageFormat();
PrinterJob pjob = PrinterJob.getPrinterJob();
pjob.setJobName( "My Print Job" );
JTree treePrint = new JTree( m_mdl );
expand( treePrint, (TreeNode) treePrint.getModel().getRoot() ); ComponentPrinter printer = ComponentPrinter.createPrinter( treePrint, m_page, false ); pjob.setPageable( printer ); if (pjob.printDialog()) { try { pjob.print(); } catch (PrinterException ex) { JOptionPane.showConfirmDialog( MainFrame.this, ex.getLocalizedMessage(), "Print Error", JOptionPane.OK_OPTION, JOptionPane.ERROR_MESSAGE ); } }

printer.dispose();
}
} // cPrintAction

protected class cPageSetupAction extends AbstractAction
{
public cPageSetupAction()
{
putValue( AbstractAction.NAME,              "Page Setup..."          );
putValue( AbstractAction.SHORT_DESCRIPTION, "Setups the page layout" );
putValue( AbstractAction.MNEMONIC_KEY,      new Integer( 'P' )       );
putValue( AbstractAction.SMALL_ICON,        null               );
}

public void actionPerformed( ActionEvent e )
{
if (m_page == null)
m_page = new PageFormat();
PrinterJob pjob = PrinterJob.getPrinterJob();
pjob.setJobName( "My Print Job" );
m_page = pjob.pageDialog( m_page );
System.out.println( "Orientation=" + m_page.getOrientation() ); } } // cPageSetupAction

protected class cExitAction extends AbstractAction
{
public cExitAction()
{
putValue( AbstractAction.NAME,              "Exit"             );
putValue( AbstractAction.SHORT_DESCRIPTION, "Exits"            );
putValue( AbstractAction.MNEMONIC_KEY,      new Integer( 'x' ) );
putValue( AbstractAction.SMALL_ICON,        null               );
}

public void actionPerformed( ActionEvent e )
{
// there should be a better way to do this but there is no close // and this seems to be what the system exit menu does, so ... MainFrame.this.dispatchEvent( new WindowEvent( MainFrame.this,  WindowEvent.WINDOW_CLOSING ) ); } } // cExitAction

}
==========================================

File 2:ComponentPrinter.java

/*
*
* To change the template for this generated file go to
* Window&gt;Preferences&gt;Java&gt;Code Generation&gt;
* Code and Comments
*/
package com.sas.test;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.print.PageFormat;
import java.awt.print.Pageable;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import javax.swing.JComponent;
import javax.swing.JTree;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeCellRenderer;
/**
* WsComponentPrinter prints a component using the given page format.  The
* component may be visible or not visible.
* <p>
* There are two ways to create a WsComponentPrinter.  The first way is to just
* instantiate one (via new).  The second way is to use one of the createPrinter
* methods.  The difference is that there are extended versions of this class
* that do special things to make rendering a component to a printer better.
* For example, there is an extended version of the class for a JTree that sets
* its background colors to white so that the printed version looks like a
* document.  Using the createPrinter methods will return these specialized
* versions of the component.
*/
public class ComponentPrinter implements Pageable, Printable
{
private JComponent m_cmp;
private PageFormat m_page;
private int        m_nPagesX;
private int        m_nPagesY;
private int        m_xOrigin;
private int        m_yOrigin;
/**
* Creates a component printer.  Use this method to get a component-specific
* instance of this class.  It is not required to use createPrinter but using
* it does ensure that a component specific version of WsComponentPrinter, if
* there is one, will be returned.
*
* @param cmp  the component to print
* @param page the page format
*/
public static ComponentPrinter createPrinter( JComponent cmp, PageFormat page ) { return createPrinter( cmp, page, true ); }
/**
* Creates a component printer.  Use this method to get a component-specific
* instance of this class.  It is not required to use createPrinter but using
* it does ensure that a component specific version of WsComponentPrinter, if
* there is one, will be returned.  This method also allows the caller to
* specify whether to print the component as is or with modifications to make
* it print nicer.
*
* @param cmp   the component to print
* @param page  the page format
* @param bAsIs true=print component as is,
*              false=change foreground/background colors to black/white
*/
public static ComponentPrinter createPrinter( JComponent cmp, PageFormat page, boolean bAsIs ) { if (cmp instanceof JTree) return new cTreePrinter( (JTree) cmp, page, bAsIs ); else return new ComponentPrinter( cmp, page ); }
/**
* Constructs a component printer.
*
* @param cmp  the component to print
* @param page the page format
*
* @see createPrinter(JComponent, PageFormat)
* @see createPrinter(JComponent, PageFormat, boolean)
*/
public ComponentPrinter( JComponent cmp, PageFormat page )
{
m_cmp  = cmp;
m_page = page;
}
/**
* Disposes of the component printer.  Resets the renderer if necessary. */ public void dispose() { }
//------------------------------------------------------------------------
// Pageable interface
//------------------------------------------------------------------------
/**
* Gets the number of pages it will take to print the tree.
*
* @return the number of pages
*
* @see java.awt.print.Pageable#getNumberOfPages()
*/
public int getNumberOfPages()
{
// get the height and width of the component
// if the component has not been sized, use its preferred size int cxCmp = m_cmp.getWidth(); int cyCmp = m_cmp.getHeight(); if ((cxCmp == 0) && (cyCmp == 0)) { m_cmp.setSize( m_cmp.getPreferredSize() ); cxCmp = m_cmp.getWidth(); cyCmp = m_cmp.getHeight(); }

int cxPage = (int) m_page.getImageableWidth();
int cyPage = (int) m_page.getImageableHeight();
m_nPagesX = (cxCmp + cxPage - 1) / cxPage;
m_nPagesY = (cyCmp + cyPage - 1) / cyPage;
return m_nPagesX * m_nPagesY;
}
/**
* Gets the page format for the page specified.
*
* @param iPage the page index
*
* @return the page format
*
* @throws IndexOutOfBoundsException if the page index is out of bounds.
*
* @see java.awt.print.Pageable#getPageFormat(int)
*/
public PageFormat getPageFormat( int iPage ) throws IndexOutOfBoundsException { validatePageIndex( iPage ); return m_page; }
/**
* Returns the printable responsible for rendering the page.
*
* @param iPage the page index
*
* @return the printable responsible for rendering the page
*
* @throws IndexOutOfBoundsException if the page index is out of bounds.
*
* @see java.awt.print.Pageable#getPrintable(int)
*/
public Printable getPrintable( int iPage ) throws IndexOutOfBoundsException { validatePageIndex( iPage ); m_xOrigin = (int) ((iPage % m_nPagesX) * m_page.getImageableWidth()); m_yOrigin = (int) ((iPage / m_nPagesX) * m_page.getImageableHeight()); return this; }
/**
* Validates the page index.
*
* @param iPage the page index
*
* @throws IndexOutOfBoundsException if the page index is out of bounds. */ protected void validatePageIndex( int iPage ) throws IndexOutOfBoundsException { if ((iPage < 0) || (iPage >= getNumberOfPages())) throw new IndexOutOfBoundsException(); }
//------------------------------------------------------------------------
// Printable interface
//------------------------------------------------------------------------
/**
* Prints the component.
*
* @param g     the graphics context to which to render the page formatting
* @param page  the page format
* @param iPage the page index
*
* @return PAGE_EXISTS if the page is rendered successfully or
*         NO_SUCH_PAGE if the page does not exist (which is never returned)
*
* @throws PrinterException
*
* @see java.awt.print.Printable#print(Graphics, PageFormat, int) */ public int print( Graphics g, PageFormat page, int iPage ) throws PrinterException { // if the page format supports printing, then let it print if (page instanceof Printable)
((Printable) page).print( g, page, iPage );

System.out.println( "Printing:Orientation=" + page.getOrientation() ); // create a graphics context for drawing the formatted page so that // no changes are made to original graphic context.  make sure the created // graphics context gets disposed Graphics2D g2d = (Graphics2D) g.create(); try { int xPage  = (int) page.getImageableX(); int yPage  = (int) page.getImageableY();
//          int cxPage = (int) page.getImageableWidth();   -- for debug purposes below
//          int cyPage = (int) page.getImageableHeight();  -- for debug purposes below
g2d.translate( xPage, yPage );

// draw the box and x for debugging purpose
//          g2d.drawRect(      0, 0, cxPage, cyPage );
//          g2d.drawLine(      0, 0, cxPage, cyPage );
//          g2d.drawLine( cxPage, 0,      0, cyPage );

g2d.translate( -m_xOrigin, -m_yOrigin );
m_cmp.printAll( g2d );
}
finally
{
g2d.dispose();
}

return Printable.PAGE_EXISTS;
}
/**
* cTreePrinter prints a tree component.  If the tree uses a
* DefaultTreeCellRenderer and the print is not "as is", the printer changes
* the colors of the tree to be black on white to give a better appearance
* when printing.
*/
protected static class cTreePrinter extends ComponentPrinter
{
private JTree   m_tree;
private boolean m_bReset;
private Color   m_clrBackground;
private Color   m_clrBackgroundSelection;
private Color   m_clrBackgroundNonSelection;
private Color   m_clrTextSelection;
private Color   m_clrTextNonSelection;
private Color   m_clrBorderSelection;
/**
* Constructs a tree printer.
*
* @param tree the tree
* @param page the page format
* @param bAsIs true=print component as is,
*              false=change foreground/background colors to black/white
*/
public cTreePrinter( JTree tree, PageFormat page, boolean bAsIs ) { super( tree, page ); m_tree = tree; if (!bAsIs) { TreeCellRenderer rdr = tree.getCellRenderer(); if (rdr instanceof DefaultTreeCellRenderer) { DefaultTreeCellRenderer rdrDefault = (DefaultTreeCellRenderer) rdr;
m_clrBackground             = tree.getBackground();

m_clrBackgroundSelection    = rdrDefault.getBackgroundSelectionColor();
m_clrBackgroundNonSelection = rdrDefault.getBackgroundNonSelectionColor();
m_clrTextSelection          = rdrDefault.getTextSelectionColor();
m_clrTextNonSelection       = rdrDefault.getTextNonSelectionColor();
m_clrBorderSelection        = rdrDefault.getBorderSelectionColor();
m_bReset = true;
tree.setBackground( Color.white );
rdrDefault.setBackgroundSelectionColor(    Color.white );
rdrDefault.setBackgroundNonSelectionColor( Color.white );
rdrDefault.setTextSelectionColor(          Color.black );
rdrDefault.setTextNonSelectionColor(       Color.black );
rdrDefault.setBorderSelectionColor(        Color.white );
}
}
}

/**
* Disposes of a tree printer.  Resets the renderer if necess

Comments
EVALUATION Name: osR10079 Date: 02/16/2004 The problem is reproducible with all jdks from 1.3.1 (I don't have earlier version to check right now). I think, that this behavior is observable for all jdk versions. So, this is not a regression. I think we should investigate it in next release. ###@###.### Feb 17, 2004 This is already fixed in Tiger. Marking as dup of 4869575. ###@###.### 2004-12-23 17:42:43 GMT ========================================== It has recently been noted that the fix to this in 4899575 doesn't help because the application is using PrinterJob.setPageable(). To restate the problem: The application is displaying pageDialog(). On Microsoft Windows this dialog often has a print vendor supplied control which allows a user to change the paper size and orientation. The API PrinterJob.printDialog() can't report this back to the application as all it returns is a boolean. When the app has supplied a "Printable" via the setPrintable(Printable) method then JDK can internally update the PageFormat passed to the print(..) method to correspond to the one the user selected. A case can even be made for doing this with Printable.setPrintable(Printable painter, PageFormat format) so long as the user change is after the application called this method - ie whoever sets it last wins. However when the application elects to call PrinterJob.setPageable() it is contracting to explicitly and directly provide the PageFormat to the print(..) method. The problem then is that if the user has changed their page preferences in printDialog() there is no way at all for the application to know this. So by choosing setPageable() the application has also chosen to ignore such changes by the user. This is entirely consistent with the design of setPageable as the point is that the application can supply different PageFormats for each page of the job. So the application will need to be recoded to use setPrintable(). There is one other alternative, which is to use PrinterJob.printDialog(PrintRequestAttributeSet attributes) The attributes argument is mutated in response to the user's selections and will contain info as to the updated paper size etc. This can be used to reconstitute a PageFormat although this needs careful coding. Also currently using a PrintRequestAttributeSet implies the swing cross-platform dialog - it cannot be used with the native dialog. ###@###.### 2005-1-06 19:04:38 GMT
06-01-2005

WORK AROUND Name: rv122619 Date: 02/16/2004 None ====================================================================== Name: osR10079 Date: 02/17/2004 Set page property in page setup dialog. ###@###.### Feb 17, 2004 ======================================================================
14-08-2004