1 /*
   2  * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25   test
  26   @bug 8023392
  27   @summary Swing text components printed with spaces between chars
  28   @author Anton Nashatyrev
  29   @run applet/manual=yesno bug8023392.html
  30 */
  31 
  32 import javax.swing.*;
  33 import javax.swing.border.LineBorder;
  34 import java.applet.Applet;
  35 import java.awt.*;
  36 import java.awt.event.ActionEvent;
  37 import java.awt.event.ActionListener;
  38 import java.awt.font.TextAttribute;
  39 import java.awt.print.PageFormat;
  40 import java.awt.print.Printable;
  41 import java.awt.print.PrinterException;
  42 import java.awt.print.PrinterJob;
  43 import java.text.AttributedCharacterIterator;
  44 import java.text.AttributedString;
  45 
  46 
  47 public class bug8023392 extends Applet {
  48     static final String[] instructions = {
  49         "A Frame containing several pairs of labels ((a) and (b)) is displayed.",
  50         "Labels of each pair look the same and are left-aligned (with spaces ",
  51         "between chars).",
  52         "1. Hit the print button.",
  53         "2. Select any available printer (printing to file is also fine).",
  54         "3. Look at the printing result (paper, PDF, PS, etc.):",
  55         "   The (a) and (b) labels should look almost the same and the (a) labels",
  56         "   shouldn't appear as if they are stretched along X axis."};
  57 
  58     public void init() {
  59         this.setLayout(new BorderLayout());
  60         add(new SimplePrint2(), BorderLayout.CENTER);
  61 
  62         Sysout.createDialogWithInstructions(instructions);
  63 
  64     }
  65 
  66     public static class SimplePrint2 extends JPanel
  67             implements ActionListener, Printable {
  68         JLabel label1;
  69         JLabel label2;
  70         JButton printButton;
  71 
  72 
  73         public SimplePrint2() {
  74             setLayout(new BorderLayout());
  75             label1 = new JLabel("2a) a b c d e" +
  76                     "                         ");
  77             label2 = new JLabel("2b) a b c d e");
  78 
  79             Box p1 = new Box(BoxLayout.Y_AXIS);
  80             p1.add(label1);
  81             p1.add(label2);
  82             p1.add(new JLabel("wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww") {
  83                 String s = "3a) a b c d e                                     ";
  84                 @Override
  85                 protected void paintComponent(Graphics g) {
  86                     sun.swing.SwingUtilities2.drawChars(this, g, s.toCharArray(),
  87                             0, s.length(), 0, 15);
  88                 }
  89             });
  90             p1.add(new JLabel("wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww") {
  91                 String s = "3b) a b c d e";
  92                 @Override
  93                 protected void paintComponent(Graphics g) {
  94                     sun.swing.SwingUtilities2.drawChars(this, g, s.toCharArray(),
  95                             0, s.length(), 0, 15);
  96                 }
  97             });
  98             p1.add(new JLabel("wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww") {
  99                 String s = "4a) a b c d e                                     ";
 100                 AttributedCharacterIterator it;
 101                 {
 102                     AttributedString as = new AttributedString(s);
 103                     as.addAttribute(TextAttribute.FONT, getFont());
 104                     as.addAttribute(TextAttribute.FOREGROUND, Color.RED, 3, 8);
 105                     it = as.getIterator();
 106                 }
 107                 @Override
 108                 protected void paintComponent(Graphics g) {
 109                     sun.swing.SwingUtilities2.drawString(this, g, it, 0, 15);
 110                 }
 111             });
 112 
 113             p1.add(new JLabel("wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww") {
 114                 String s = "4b) a b c d e";
 115                 AttributedCharacterIterator it;
 116                 {
 117                     AttributedString as = new AttributedString(s);
 118                     as.addAttribute(TextAttribute.FONT, getFont());
 119                     as.addAttribute(TextAttribute.FOREGROUND, Color.RED, 3, 8);
 120                     it = as.getIterator();
 121                 }
 122                 @Override
 123                 protected void paintComponent(Graphics g) {
 124                     sun.swing.SwingUtilities2.drawString(this, g, it, 0, 15);
 125                 }
 126             });
 127 
 128             JPanel p2 = new JPanel();
 129             printButton = new JButton("Print");
 130             printButton.addActionListener(this);
 131             p2.add(printButton);
 132 
 133             Container c = this;
 134             c.add(p1, BorderLayout.CENTER);
 135             c.add(p2, BorderLayout.SOUTH);
 136 
 137             String[] data = {
 138                     "1a) \u30aa\u30f3\u30e9\u30a4\u30f3\u6d88\u8fbc" +
 139                     "                                              ",
 140                     "1b) \u30aa\u30f3\u30e9\u30a4\u30f3\u6d88\u8fbc"
 141             };
 142             JList l0 = new JList(data);
 143             l0.setVisibleRowCount(l0.getModel().getSize());
 144             JScrollPane jsp = new JScrollPane(l0);
 145             l0.setBorder(new LineBorder(Color.GRAY));
 146             c.add(jsp, BorderLayout.NORTH);
 147 
 148             for (Component comp : new Component[]{label1, label2, printButton}) {
 149                 comp.setFont(new Font("Monospaced", 0, 16));
 150             }
 151         }
 152 
 153         public void actionPerformed(ActionEvent e) {
 154             PrinterJob job = PrinterJob.getPrinterJob();
 155             job.setPrintable(this);
 156             if (job.printDialog()) {
 157                 try {
 158                     job.print();
 159                 } catch (PrinterException ex) {
 160                     ex.printStackTrace();
 161                 }
 162             }
 163         }
 164 
 165         public int print(Graphics graphics,
 166                          PageFormat pageFormat,
 167                          int pageIndex)
 168                 throws PrinterException {
 169             if (pageIndex >= 1) {
 170                 return Printable.NO_SUCH_PAGE;
 171             }
 172 
 173             this.paint(graphics);
 174             return Printable.PAGE_EXISTS;
 175         }
 176     }
 177 }
 178 
 179 
 180 /**
 181  * *************************************************
 182  * Standard Test Machinery
 183  * DO NOT modify anything below -- it's a standard
 184  * chunk of code whose purpose is to make user
 185  * interaction uniform, and thereby make it simpler
 186  * to read and understand someone else's test.
 187  * **************************************************
 188  */
 189 class Sysout {
 190     private static TestDialog dialog;
 191 
 192     public static void createDialogWithInstructions(String[] instructions) {
 193         dialog = new TestDialog(new Frame(), "Instructions");
 194         dialog.printInstructions(instructions);
 195         dialog.show();
 196         println("Any messages for the tester will display here.");
 197     }
 198 
 199     public static void createDialog() {
 200         dialog = new TestDialog(new Frame(), "Instructions");
 201         String[] defInstr = {"Instructions will appear here. ", ""};
 202         dialog.printInstructions(defInstr);
 203         dialog.show();
 204         println("Any messages for the tester will display here.");
 205     }
 206 
 207 
 208     public static void printInstructions(String[] instructions) {
 209         dialog.printInstructions(instructions);
 210     }
 211 
 212 
 213     public static void println(String messageIn) {
 214         dialog.displayMessage(messageIn);
 215     }
 216 
 217 }// Sysout  class
 218 
 219 
 220 class TestDialog extends Dialog {
 221 
 222     TextArea instructionsText;
 223     TextArea messageText;
 224     int maxStringLength = 80;
 225 
 226     //DO NOT call this directly, go through Sysout
 227     public TestDialog(Frame frame, String name) {
 228         super(frame, name);
 229         int scrollBoth = TextArea.SCROLLBARS_BOTH;
 230         instructionsText = new TextArea("", 15, maxStringLength, scrollBoth);
 231         add("North", instructionsText);
 232 
 233         messageText = new TextArea("", 5, maxStringLength, scrollBoth);
 234         add("South", messageText);
 235 
 236         pack();
 237 
 238         show();
 239     }// TestDialog()
 240 
 241     //DO NOT call this directly, go through Sysout
 242     public void printInstructions(String[] instructions) {
 243         //Clear out any current instructions
 244         instructionsText.setText("");
 245 
 246         //Go down array of instruction strings
 247 
 248         String printStr, remainingStr;
 249         for (int i = 0; i < instructions.length; i++) {
 250             //chop up each into pieces maxSringLength long
 251             remainingStr = instructions[i];
 252             while (remainingStr.length() > 0) {
 253                 //if longer than max then chop off first max chars to print
 254                 if (remainingStr.length() >= maxStringLength) {
 255                     //Try to chop on a word boundary
 256                     int posOfSpace = remainingStr.
 257                             lastIndexOf(' ', maxStringLength - 1);
 258 
 259                     if (posOfSpace <= 0) posOfSpace = maxStringLength - 1;
 260 
 261                     printStr = remainingStr.substring(0, posOfSpace + 1);
 262                     remainingStr = remainingStr.substring(posOfSpace + 1);
 263                 }
 264                 //else just print
 265                 else {
 266                     printStr = remainingStr;
 267                     remainingStr = "";
 268                 }
 269 
 270                 instructionsText.append(printStr + "\n");
 271 
 272             }// while
 273 
 274         }// for
 275 
 276     }//printInstructions()
 277 
 278     //DO NOT call this directly, go through Sysout
 279     public void displayMessage(String messageIn) {
 280         messageText.append(messageIn + "\n");
 281     }
 282 
 283 }// TestDialog  class
 284