8081491: The case print incomplete
Reviewed-by: alexsch, rchamyal
diff --git a/jdk/src/java.desktop/share/classes/javax/swing/TablePrintable.java b/jdk/src/java.desktop/share/classes/javax/swing/TablePrintable.java
index 6b9053f..b47f869 100644
--- a/jdk/src/java.desktop/share/classes/javax/swing/TablePrintable.java
+++ b/jdk/src/java.desktop/share/classes/javax/swing/TablePrintable.java
@@ -205,11 +205,9 @@
*/
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
throws PrinterException {
-
// for easy access to these values
final int imgWidth = (int)pageFormat.getImageableWidth();
final int imgHeight = (int)pageFormat.getImageableHeight();
-
if (imgWidth <= 0) {
throw new PrinterException("Width of printable area is too small.");
}
@@ -302,10 +300,12 @@
// been divided by it
int scaledWidth = (int)(imgWidth / sf);
int scaledHeight = (int)((availableSpace - hclip.height) / sf);
-
// calculate the area of the table to be printed for this page
findNextClip(scaledWidth, scaledHeight);
+ if (!((table.getBounds()).intersects(clip))) {
+ return NO_SUCH_PAGE;
+ }
last++;
}
@@ -343,7 +343,6 @@
tempRect.width = imgWidth;
tempRect.height = availableSpace;
g2d.clip(tempRect);
-
// if we have a scale factor, scale the graphics object to fit
// the entire width
if (sf != 1.0D) {
@@ -389,7 +388,26 @@
// draw a box around the table
g2d.setColor(Color.BLACK);
- g2d.drawRect(0, 0, clip.width, hclip.height + clip.height);
+
+ // compute the visible portion of table and draw the rect around it
+ Rectangle visibleBounds = clip.intersection(table.getBounds());
+ Point upperLeft = visibleBounds.getLocation();
+ Point lowerRight = new Point(visibleBounds.x + visibleBounds.width,
+ visibleBounds.y + visibleBounds.height);
+
+ int rMin = table.rowAtPoint(upperLeft);
+ int rMax = table.rowAtPoint(lowerRight);
+ if (rMin == -1) {
+ rMin = 0;
+ }
+ if (rMax == -1) {
+ rMax = table.getRowCount();
+ }
+ int rowHeight = 0;
+ for(int visrow = rMin; visrow < rMax; visrow++) {
+ rowHeight += table.getRowHeight(visrow);
+ }
+ g2d.drawRect(0, 0, visibleBounds.width, hclip.height + rowHeight);
// dispose the graphics copy
g2d.dispose();
@@ -509,7 +527,6 @@
if (++col >= colCount) {
// reset col to 0 to indicate we're finished all columns
col = 0;
-
break;
}
diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTableUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTableUI.java
index ef0c454..73fd9a5 100644
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTableUI.java
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTableUI.java
@@ -1812,9 +1812,11 @@
boolean ltr = table.getComponentOrientation().isLeftToRight();
- Point upperLeft = clip.getLocation();
- Point lowerRight = new Point(clip.x + clip.width - 1,
- clip.y + clip.height - 1);
+ // compute the visible part of table which needs to be painted
+ Rectangle visibleBounds = clip.intersection(bounds);
+ Point upperLeft = visibleBounds.getLocation();
+ Point lowerRight = new Point(visibleBounds.x + visibleBounds.width - 1,
+ visibleBounds.y + visibleBounds.height - 1);
int rMin = table.rowAtPoint(upperLeft);
int rMax = table.rowAtPoint(lowerRight);
@@ -1843,6 +1845,21 @@
cMax = table.getColumnCount()-1;
}
+ Container comp = SwingUtilities.getUnwrappedParent(table);
+ if (comp != null) {
+ comp = comp.getParent();
+ }
+
+ if (comp != null && !(comp instanceof JViewport) && !(comp instanceof JScrollPane)) {
+ // We did rMax-1 to paint the same number of rows that are drawn on console
+ // otherwise 1 extra row is printed per page than that are displayed
+ // when there is no scrollPane and we do printing of table
+ // but not when rmax is already pointing to index of last row
+ if (rMax != (table.getRowCount() - 1)) {
+ rMax = rMax - 1;
+ }
+ }
+
// Paint the grid.
paintGrid(g, rMin, rMax, cMin, cMax);
diff --git a/jdk/test/java/awt/print/PageFormat/ImageableAreaTest.java b/jdk/test/java/awt/print/PageFormat/ImageableAreaTest.java
index f9e7b4b..7bf37415 100644
--- a/jdk/test/java/awt/print/PageFormat/ImageableAreaTest.java
+++ b/jdk/test/java/awt/print/PageFormat/ImageableAreaTest.java
@@ -45,7 +45,7 @@
/**
* @test
- * @bug 8044444
+ * @bug 8044444 8081491
* @summary The output's 'Page-n' footer does not show completely
* @author Alexandr Scherbatiy
* @run main/manual ImageableAreaTest
@@ -58,11 +58,13 @@
@Override
public void run() {
+
createAndShowTestDialog(
"1. Press the Print Table button\n"
+ " Java print dialog should appear.\n"
+ "2. Press the Print button on the Java Print dialog.\n"
- + "2. Check that the page number is correctly printed.\n"
+ + "3. Check that the page number is correctly printed.\n"
+ + "4. Check only the visible part of the table is printed.\n"
+ "If so, press PASS, else press FAIL.",
"Page number is not correctly printed!",
ImageableAreaTest::printWithJavaPrintDialog);
@@ -71,24 +73,47 @@
"1. Press the Print Table button\n"
+ " The table should be printed without the print dialog.\n"
+ "2. Check that the page number is correctly printed.\n"
+ + "3. Check only the visible part of the table is printed.\n"
+ "If so, press PASS, else press FAIL.",
"Page number is not correctly printed!",
ImageableAreaTest::printWithoutPrintDialog);
+
+
createAndShowTestDialog(
"1. Press the Print Table button\n"
+ " Java print dialog should appear.\n"
+ "2. Press the Print button on the Java Print dialog.\n"
+ "3. Check that the table has about half size of the printed page\n"
+ + "4. Check only the visible part of the table is printed.\n"
+ "If so, press PASS, else press FAIL.",
"Custom imageable area is not correctly printed!",
ImageableAreaTest::printWithCustomImageareaSize);
+
+ createAndShowTestDialog(
+ "1. Press the Print Table button\n"
+ + " Java print dialog should appear.\n"
+ + "2. Press the Print button on the Java Print dialog.\n"
+ + "3. Check that the rows with different height is printed.\n"
+ + "4. Check only the visible part of the table is printed.\n"
+ + "If so, press PASS, else press FAIL.",
+ "Row with different height is not correctly printed!",
+ ImageableAreaTest::printDifferentRowHeight);
+
+ createAndShowTestDialog(
+ "1. Press the Print Table button\n"
+ + " Java print dialog should appear.\n"
+ + "2. Press the Print button on the Java Print dialog.\n"
+ + "3. Check that the only 1 row is shown & printed.\n"
+ + "If so, press PASS, else press FAIL.",
+ "Only 1 Row is not correctly printed!",
+ ImageableAreaTest::printOneRowWithJavaPrintDialog);
}
});
}
private static void printWithJavaPrintDialog() {
- final JTable table = createAuthorTable(42);
+ final JTable table = createAuthorTable(50);
Printable printable = table.getPrintable(
JTable.PrintMode.NORMAL,
new MessageFormat("Author Table"),
@@ -110,7 +135,7 @@
private static void printWithoutPrintDialog() {
- final JTable table = createAuthorTable(42);
+ final JTable table = createAuthorTable(50);
PrintRequestAttributeSet pras
= new HashPrintRequestAttributeSet();
pras.add(new Copies(1));
@@ -132,6 +157,50 @@
}
}
+ private static void printDifferentRowHeight() {
+ final JTable table = createAuthorTable(50);
+ table.setRowHeight(15, table.getRowHeight(15)+10);
+ Printable printable = table.getPrintable(
+ JTable.PrintMode.NORMAL,
+ new MessageFormat("Author Table"),
+ new MessageFormat("Page - {0}"));
+
+ PrinterJob job = PrinterJob.getPrinterJob();
+ job.setPrintable(printable);
+
+ boolean printAccepted = job.printDialog();
+ if (printAccepted) {
+ try {
+ job.print();
+ closeFrame();
+ } catch (PrinterException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ }
+
+ private static void printOneRowWithJavaPrintDialog() {
+ final JTable table = createAuthorTable(1);
+ Printable printable = table.getPrintable(
+ JTable.PrintMode.NORMAL,
+ new MessageFormat("Author Table"),
+ new MessageFormat("Page - {0}"));
+
+ PrinterJob job = PrinterJob.getPrinterJob();
+ job.setPrintable(printable);
+
+ boolean printAccepted = job.printDialog();
+ if (printAccepted) {
+ try {
+ job.print();
+ closeFrame();
+ } catch (PrinterException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
private static void printWithCustomImageareaSize() {
final JTable table = createAuthorTable(18);
PrintRequestAttributeSet printAttributes = new HashPrintRequestAttributeSet();
diff --git a/jdk/test/javax/swing/JTable/JTableScrollTest.java b/jdk/test/javax/swing/JTable/JTableScrollTest.java
new file mode 100644
index 0000000..5e0461c
--- /dev/null
+++ b/jdk/test/javax/swing/JTable/JTableScrollTest.java
@@ -0,0 +1,182 @@
+/* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.Color;
+import java.awt.Dialog;
+import javax.swing.JDialog;
+import javax.swing.JPanel;
+import javax.swing.JFrame;
+import javax.swing.JTable;
+import javax.swing.JTextArea;
+import javax.swing.JButton;
+import javax.swing.table.TableModel;
+import javax.swing.JScrollPane;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.SwingUtilities;
+
+/**
+ * @test
+ * @bug 8081491
+ * @summary Scrolling a JTable creates artifacts
+ * @run main/manual JTableScrollTest
+ */
+public class JTableScrollTest {
+ static JFrame frame = new JFrame();
+ public static void main(String[] args) throws Exception {
+ SwingUtilities.invokeAndWait(new Runnable() {
+
+ @Override
+ public void run() {
+ doTest(JTableScrollTest::createTable);
+ }
+ });
+ }
+
+ private static void createTable() {
+ // final
+ final String[] names = {
+ new String("first_name"),
+ new String("last_name"),
+ new String("favorite_color"),
+ new String("favorite_food")
+ };
+
+ // Create the dummy data (a few rows of names)
+ final Object[][] data = {
+ {"Mike", "Albers", "green", "strawberry"},
+ {"Mark", "Andrews", "blue", "grapes"},
+ {"Brian", "Beck", "black", "raspberry"},
+ {"Lara", "Bunni", "red", "strawberry"},
+ {"Roger", "Brinkley", "blue", "peach"},
+ {"Brent", "Christian", "black", "broccoli"},
+ {"Mark", "Davidson", "darkgreen", "asparagus"},
+ {"Jeff", "Dinkins", "blue", "kiwi"},
+ {"Ewan", "Dinkins", "yellow", "strawberry"},
+ {"Amy", "Fowler", "violet", "raspberry"},
+ {"Hania", "Gajewska", "purple", "raspberry"},
+ {"David", "Geary", "blue", "watermelon"},
+ {"Ryan", "Gosling", "pink", "donut"},
+ {"Eric", "Hawkes", "blue", "pickle"},
+ {"Shannon", "Hickey", "green", "grapes"},
+ {"Earl", "Johnson", "green", "carrot"},
+ {"Robi", "Khan", "green", "apple"},
+ {"Robert", "Kim", "blue", "strawberry"},
+ {"Janet", "Koenig", "turquoise", "peach"},
+ {"Jeff", "Kesselman", "blue", "pineapple"},
+ {"Onno", "Kluyt", "orange", "broccoli"},
+ {"Peter", "Korn", "sunpurple", "sparegrass"},
+ {"Rick", "Levenson", "black", "raspberry"},
+ {"Brian", "Lichtenwalter", "blue", "pear"},
+ {"Malini", "Minasandram", "beige", "corn"},
+ {"Michael", "Martak", "green", "strawberry"},
+ {"David", "Mendenhall", "forestgreen", "peach"},
+ {"Phil", "Milne", "pink", "banana"},
+ {"Lynn", "Monsanto", "cybergreen", "peach"},
+ {"Hans", "Muller", "rustred", "pineapple"},
+ {"Joshua", "Outwater", "blue", "pineapple"},
+ {"Tim", "Prinzing", "blue", "pepper"},
+ {"Raj", "Premkumar", "blue", "broccoli"},
+ {"Howard", "Rosen", "green", "strawberry"},
+ {"Ray", "Ryan", "black", "banana"},
+ {"Georges", "Saab", "aqua", "cantaloupe"},
+ {"Tom", "Santos", "blue", "pepper"},
+ {"Rich", "Schiavi", "blue", "pepper"},
+ {"Nancy", "Schorr", "green", "watermelon"},
+ {"Keith", "Sprochi", "darkgreen", "watermelon"},
+ {"Matt", "Tucker", "eblue", "broccoli"},
+ {"Dmitri", "Trembovetski", "red", "tomato"},
+ {"Scott", "Violet", "violet", "banana"},
+ {"Kathy", "Walrath", "darkgreen", "pear"},
+ };
+
+ // Create a model of the data.
+ TableModel dataModel = new AbstractTableModel() {
+ public int getColumnCount() { return names.length; }
+ public int getRowCount() { return data.length;}
+ public Object getValueAt(int row, int col) {return data[row][col];}
+ public String getColumnName(int column) {return names[column];}
+ public Class getColumnClass(int c) {return getValueAt(0, c).getClass();}
+ public boolean isCellEditable(int row, int col) {return col != 5;}
+ public void setValueAt(Object aValue, int row, int column) { data[row][column] = aValue; }
+ };
+
+ // Create the table
+ JTable tableView = new JTable(dataModel);
+ tableView.setBackground(Color.WHITE);
+ tableView.setForeground(Color.BLACK);
+ tableView.setSize(600, 800);
+ JScrollPane scrollpane = new JScrollPane(tableView);
+ frame.add(scrollpane);
+ frame.pack();
+ frame.setVisible(true);
+ }
+
+ private static void doTest(Runnable action) {
+ String description =
+ "JTable with rows will be displayed along with scrollbar.\n"
+ + "Scroll the table. Verify no arifacts are shown and rows.\n"
+ + " are correctly displayed.";
+ final JDialog dialog = new JDialog();
+ dialog.setTitle("ScrollArtifactTest ");
+ JTextArea textArea = new JTextArea(description);
+ textArea.setEditable(false);
+ final JButton testButton = new JButton("Create Table");
+ final JButton passButton = new JButton("PASS");
+ passButton.setEnabled(false);
+ passButton.addActionListener((e) -> {
+ dialog.dispose();
+ if (frame != null) {
+ frame.setVisible(false);
+ frame.dispose();
+ }
+ });
+ final JButton failButton = new JButton("FAIL");
+ failButton.setEnabled(false);
+ failButton.addActionListener((e) -> {
+ dialog.dispose();
+ if (frame != null) {
+ frame.setVisible(false);
+ frame.dispose();
+ }
+ throw new RuntimeException("Scrollbar artifact shown");
+ });
+ testButton.addActionListener((e) -> {
+ testButton.setEnabled(false);
+ action.run();
+ passButton.setEnabled(true);
+ failButton.setEnabled(true);
+ });
+ JPanel mainPanel = new JPanel(new BorderLayout());
+ mainPanel.add(textArea, BorderLayout.CENTER);
+ JPanel buttonPanel = new JPanel(new FlowLayout());
+ buttonPanel.add(testButton);
+ buttonPanel.add(passButton);
+ buttonPanel.add(failButton);
+ mainPanel.add(buttonPanel, BorderLayout.SOUTH);
+ dialog.add(mainPanel);
+ dialog.pack();
+ dialog.setVisible(true);
+ }
+
+
+}