<?xml version="1.0" encoding="utf-8"?>
<feed version="0.3" xmlns="http://purl.org/atom/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="en">
<title>Sergey Groznyh&apos;s Blog</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/g_s_m/" />
<modified>2007-09-07T07:56:16Z</modified>
<tagline></tagline>
<id>tag:weblogs.java.net,2008:/blog/g_s_m/380</id>
<generator url="http://www.movabletype.org/" version="3.01D">Movable Type</generator>
<copyright>Copyright (c) 2007, g_s_m</copyright>
<entry>
<title>Generating Print Preview of Swing Text Components</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/g_s_m/archive/2007/09/generating_prin_1.html" />
<modified>2007-09-07T07:56:16Z</modified>
<issued>2007-09-05T12:42:03Z</issued>
<id>tag:weblogs.java.net,2007:/blog/g_s_m/380.8181</id>
<created>2007-09-05T12:42:03Z</created>
<summary type="text/plain">How to create print preview of Swing Text components: what are the necessary parts involved and how do they cooperate.</summary>
<author>
<name>g_s_m</name>

<email>Sergey.Groznyh@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/g_s_m/">
<![CDATA[<style type="text/css">
  code, pre { color: navy; }
  pre { border: solid gray 1px; margin: 1em 2em; padding: 1em; }
</style>

<p>This question, &#x201c;how to generate print preview of Java Swing
components,&#x201d; is asked often on various discussion forums, because
currently (as of version 6) the Java SE doesn't have standard facilities for
building print previews.  While working on the Swing Tutorial, I tried to address this issue under the topic &#x201c;Using
<code>JTextComponent.getPrintable</code> method.&#x201d; This will
hopefully appear in the updated version of the Swing Tutorial for JDK6.  In the
meantime, I'll put the relevant information here.</p>

<p>There exist several resources on the Internet related to generating print previews in Java, but in most cases they are either commercial, or use an outdated API, or
attempt to build some all-in-one custom dialog solution without paying much
attention to details.  In this issue I'll try to focus on <em>how</em>
to create a print preview&#x2014;what necessary parts are involved and
how they do communicate.</p>

<h3>What to Print</h3>

<p>The <code>JTextComponent</code> class defines
the <code>getPrintable</code> method which returns an instance of
the <code>Printable</code> interface containing a single
method, <code>print</code>.  Assuming the <code>textComponent</code> is
a <code>JTextComponent</code> object we are going to generate print preview for, the
following code shows how to obtain a <code>Printable</code> instance out
of it.</p>

<pre>
Printable p = textComponent.getPrintable();
</pre>


<h3>Page Format</h3>

<p>Next thing we need to know is the parameters of the output media,
most important ones being the physical page dimensions.  In real-life
situation the available page dimensions should be obtained by querying
some <code>PrintService</code> known to your Java environment.  For
the purposes of this example we'll just use the default page
format.</p>

<pre>
PageFormat f = new PageFormat();
int pageWidth = f.getWidth();
int pageHeight = f.getHeight();
</pre>

<h3>Where to Print</h3>

<p>Then we need a print destination that will receive the actual drawing commands. The destination should be an instance of
the <code>Graphics</code> class.  A simple way of obtaining
this is using the <code>BufferedImage</code> class as 
physical backing store.  This class defines the
<code>getGraphics</code> method which returns a <code>Graphics</code>
instance.</p>

<pre>
Image page = new BufferedImage(
        pageWidth, pageHeight, BufferedImage.TYPE_INT_ARGB);
Graphics g = page.getGraphics();
</pre>

<h3>How to Print</h3>

<p>Now we are ready to generate page images.  We need to repeatedly
invoke the <code>print</code> method on the <code>Printable</code>
instance, specifying the page number to print (0 is
the <em>first</em> page) and the
<code>Graphic</code> and <code>PageFormat</code> objects.
The <code>print</code> method returns some status code.  The value
of <code>PAGE_EXISTS</code> indicates the success of the operation.
</p>

<pre>
for (int n = 0; p.print(g, f, n) == Printable.PAGE_EXISTS; n++) {
    // N-th page printed successfully
}
</pre>

<h3>How to Scale</h3>

<p>The generated page image is usually too large for on-screen
display, so we need to shrink the image for viewing.  The following
code creates an image with size reduced by two times on both dimensions.</p>

<pre>
double scaleFactor = 0.5;
int previewWidth = (int) (pageWidth * scaleFactor);
int previewHeight = (int) (pageHeight * scaleFactor);
Image preview = page.getScaledInstance(
        previewWidth, previewHeight, SCALE_SMOOTH);
</pre>

<h3>Back to Swing</h3>

<p>Until now we dealt mostly with 2D and AWT parts of the Client Java API.
Now we need to place the generated preview image into some Swing
component.  For this we'll create a subclass of the <code>JPanel</code>,
implementing the custom <code>paintComponent</code> method and
overriding
the <code>getPreferredSize</code>, <code>getMinimumSize</code>
and <code>getMaximumSize</code> methods so our preview component is
laid out correctly.</p>

<pre>
JPanel previewPane = new JPanel() {
    public void paintComponent(Graphics g) {
        g.drawImage(preview, 0, 0, previewWidth, previewHeight, null);
    }

    public Dimension getPreferredSize() {
        return new Dimension(previewWidth, previewHeight);
    }

    public Dimension getMinimumSize() {
        return getPreferredSize();
    }

    public Dimension getMaximumSize() {
        return getPreferredSize();
    }
}
</pre>


<p>The resulting print preview pane can then be added to Swing
container, just like any other Swing component.</p>

<p>Below are links to the example containing the complete print
preview implementation as described in this issue.  Using this
implementation, the print preview functionality could be added to any
text component in a couple lines of code.</p>

<p>Please note that in order to run this demo, you'll need Java runtime version 1.6 (aka 6.0) or higher.</p>

<div align="center">
  <a href="/blog/g_s_m/archive/PrintPreviewDemo.zip">Get Demo Source</a>
</div>

<div align="center">
   <a href="/blog/g_s_m/archive/PrintPreviewDemo.jar">Download Jar File</a>
</div>

<p>The demo displays a chapter from &#x201c;Alice in Wonderland&#x201d; in the
<code>JEditorPane</code> component.  Print preview window could be
activated from menu or by using a keyboard shortcut.  Standard Java
Print Dialog could be invoked from inside the print preview.</p>

]]>

</content>
</entry>
<entry>
<title>Removing elements from Swing HTML in JDK6</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/g_s_m/archive/2007/08/removing_elemen_2.html" />
<modified>2007-09-05T12:03:20Z</modified>
<issued>2007-08-01T18:12:40Z</issued>
<id>tag:weblogs.java.net,2007:/blog/g_s_m/380.7958</id>
<created>2007-08-01T18:12:40Z</created>
<summary type="text/plain">How to remove elements from Swing HTMLDocument in JDK6</summary>
<author>
<name>g_s_m</name>

<email>Sergey.Groznyh@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/g_s_m/">
<![CDATA[<style>
pre, code { color: navy; }
pre { border: solid gray 1px; margin: 1em 2em; padding: 0em 1em; }
</style>

<p>After I
published <a
href="http://weblogs.java.net/blog/g_s_m/archive/2007/06/removing_elemen_1.html">the
entry</a> on removing elements from Swing HTMLDocument in JDK7, I got
a question from a reader: but how to actually remove elements in JDK6?
There's no easy way, but what is the <em>hard</em> way?</p>

<p>Well, there exist a bunch of methods, to various degrees of
ugliness, let's look at one of them.  It's neither pretty nor
effective, but has the advantage of being simple enough.</p>

<p>The method is to serialize all the sibling elements
using <code>HTMLWriter</code> class, concatenate the serialized
strings, and re-parse the resulting text
using <code>setInnerHTML</code> method with the parent element as the
target.</p>

<p>The following code illustrates this approach.</p>

<pre>

void removeElement(HTMLDocument d, Element e) throws Exception {
    Element p = e.getParentElement();
    int n = p.getElementCount();
    String s = "";
    for (int i = 0; i < n; i++) {
        Element c = p.getElement(i);
        if (c != e) {
            s += getElementText(d, c);
        }
    }
    d.setInnerHTML(p, s);
}

</pre>

<p>The tricky thing is, how to serialize not the complete document but
a single element only.  There exist a constructor in
the <code>HTMLWriter</code> class that allows to specify only a
fragment of the document to serialize, and we could use element's
start and end offsets as the fragment boundaries.  But by default the
writer will output all ancestors of the element up to the root to make
serialized form the complete HTML document.</p>

<p>To overcome this, we need to override
the <code>getElementIterator</code> method which returns the root of
the element hierarchy to serialize.  In the <code>HTMLWriter</code>
implementation it returns the document root element.  We'll implement
it to return just the element to serialize.</p>

<pre>

String getElementText(HTMLDocument d, final Element e) throws Exception {
    StringWriter sw = new StringWriter();
    int p0 = e.getStartOffset();
    int p1 = e.getEndOffset();
    new HTMLWriter(sw, d, p0, p1 - p0) {
        protected ElementIterator getElementIterator() {
            return new ElementIterator(e);
        }
    }.write();
    return sw.toString();
}

</pre>

<p>Note that if we try to remove the sole child element, the behavior
of this method differs from <code>removeElement</code> in JDK7.  In
JDK7 the parent element is removed as well, recursively.  In the above
example nothing is removed (to make the example simple).  To get the
JDK7 behavior, we need to traverse to the nearest parent element that
is <em>not</em> a sole child and remove it instead of the original
element.</p>
]]>

</content>
</entry>
<entry>
<title>Removing elements from Swing HTMLDocument</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/g_s_m/archive/2007/06/removing_elemen_1.html" />
<modified>2007-09-05T12:03:20Z</modified>
<issued>2007-06-18T16:36:03Z</issued>
<id>tag:weblogs.java.net,2007:/blog/g_s_m/380.7672</id>
<created>2007-06-18T16:36:03Z</created>
<summary type="text/plain">this entry explains how to remove elements from the Swing HTML document.</summary>
<author>
<name>g_s_m</name>

<email>Sergey.Groznyh@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/g_s_m/">
<![CDATA[<?xml version='1.0'?>

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Removing elements from Swing HTMLDocument</title>
    <style type="text/css">
      .htmlsrc, .javacode {
          font-family: monospace; font-size: 1em; color: navy;
      }
      pre.javacode, .htmlsrc, .htmlview {
          margin: 1em 2em; padding: 0em 1em; border: thin solid black;
    </style>
  </head>
  <body>
    <p>Suppose you have an HTML document, like this:</p>
    
          <pre class="htmlsrc">

&lt;ul>
  &lt;li id="LI1">Item 1&lt;/li>
  &lt;li id="LI2">Item 2&lt;/li>
  &lt;li id="LI3">Item 3&lt;/li>
&lt;/ul>
          </pre>

    <p>And you want to programmatically remove one of the list items (say,
    the second one).</p>

    <p>For this, you load the document into Swing&#x2019;s <code
    class="javacode">JEditorPane</code> component:</p>

    <pre class="javacode">

JEditorPane p = new JEditorPane();
p.setContentType("text/html");
p.setText("<em>HTML text from the above example</em>");
    </pre>

    <p>As you know the HTML element&#x2019;s ID, you can easily obtain
    a reference to the corresponding <code
    class="javacode">Element</code> object:</p>

    <pre class="javacode">

HTMLDocument d = (HTMLDocument) p.getDocument();
Element e = d.getElement("LI2");
    </pre>

    <p>But how to remove this element from the document?  A quick
    glance through the <code class="javacode">HTMLDocument</code> API
    reveals the natural candidate for the task: the <code
    class="javacode">setOuterHTML</code> method which allows to
    replace an arbitrary element with some new content.  So you think,
    &#x201c;if I specify an empty string as the new content, the
    element will be just removed from the document as there&#x2019;s no
    replacement.&#x201d; Pretty simple and elegant solution,
    really.</p>

    <p>Except that it doesn&#x2019;t work.</p>

    <p>The <code class="javacode">setOuterHTML</code> method is
    implemented so that if there&#x2019;s no content in the
    replacement string, the target document won&#x2019;t be altered at
    all.  The method call is just a no-op in this case.</p>

    <p>So how to actually remove an element from the document?  Quite
    surprisingly, until recently there was no easy way of doing this.</p>

    <p>Starting with <a href="http://download.java.net/jdk7/">JDK7
    build 10</a>, the Swing Text subsystem provides the new public
    method in the <code class="javacode">DefaultStyledDocument</code>
    class: the <code class="javacode">removeElement</code> method. It
    takes an element to remove as the sole parameter and removes the
    element from the document tree, as well as the corresponding text
    from the document content.  So in order to remove the element, you
    just invoke this method:</p>

    <pre class="javacode">

d.removeElement(e);
    </pre>

    <p>Due to specifics of the default <code
    class="javacode">Element</code> and <code
    class="javacode">Content</code> implementations, there are some
    caveats:</p>

    <ul>
      <li>Empty branch elements are not allowed in the default
      implementation; so if you remove the last child of some element,
      the element itself will be removed as well, recursively (this
      means that if you need to <em>replace</em> the sole child, you
      should <em>add</em> the new child first and <em>then</em> remove
      the old one, not vice-versa).
      </li>

      <li>Element-less documents are not allowed in the default
      implementation; so you&#x2019;ll get an exception if you try to
      remove the last leaf element in the document (because this will
      eventually require removal of the document root element).
      </li>

      <li>The default <code class="javacode">Content</code>
      implementation requires the presence of the trailing newline
      character in the document; so if you remove the leaf element
      containing the trailing newline, it will be added to
      the preceding leaf element (unless that element already ends
      with newline).
      </li>
    </ul>

  </body>
</html>]]>

</content>
</entry>

</feed>