GWTでブラウザへの印刷指示を行う



GWTにおいてブラウザへの印刷指示を行いたい。単純に表示されている内容ではなく、その都度指定したURLもしくは生成したHTMLの内容を印刷したいのである。このモジュールを作成した。

This module orders printing a URL or arbitrary HTML to the browser from within GWT client program.

boolean executed = Print.url("https://www.gwtcenter.com");
OR
boolean executed = Print.html("<html><body>this is test</body></html>");

In case there’s already printing process, then executed will be false.

Print.java


import com.google.gwt.user.client.*; /** * 指定されたURLを印刷するようブラウザに指示する。 * <pre> * boolean executed = Print.url("https://www.gwtcenter.com") * もしくは * boolean executed = Print.html("<html><body>this is test</body></html>"); * </pre> * executed=trueの場合は印刷を起動した。falseの場合は既に印刷処理中。 * @author ysugimura */ public class Print { /** 印刷用iframeに対して印刷指示を何度もトライするためのタイマー値。この間隔でトライする */ private static final int TRY_PRINT_INTERVAL = 100; /** 印刷起動成功後に、iframeを廃棄するまでのタイマー値。ただちに廃棄してはいけないため */ private static final int DISPOSE_INTERVAL = 1000; /** 印刷起動トライ用タイマー */ private static final Timer tryPrintTimer = new Timer() { public void run() { tryPrint(); }}; /** 廃棄用タイマー */ private static final Timer disposeTimer = new Timer() { public void run() { dispose(); }}; /** 印刷対象iframe */ private static PrintFrame printFrame; /** * 指定されたURLを印刷する * @param url 対象とするURL * @return true:印刷を起動した。false:既に印刷実行中のため起動されなかった。 * @throws RuntimeException 例外 */ public static boolean url(String url) { return print(new PrintFrame.Url(url)); } /** * 指定されたHTMLを印刷する * @param html 対象とするHTML * @return true:印刷を起動した。false:既に印刷実行中のため起動されなかった。 * @throws RuntimeException 例外 */ public static boolean html(String html) { return print(new PrintFrame.Html(html)); } /** * {@link PrintFrame}を印刷する * @param targetFrame 印刷対象のiframe * @return true:印刷を起動した。false:既に印刷中 */ private static boolean print(PrintFrame targetFrame) { // 既に印刷中であれば、何もせずfalseを返す。 if (printFrame != null) return false; // URLを持つiframeを作成してドキュメントに追加する (printFrame = targetFrame).attach(); // 印刷試行タイマーを起動する tryPrintTimer.scheduleRepeating(TRY_PRINT_INTERVAL); return true; } /** * 印刷を起動してみる。 * 起動できればtrueを返す。falseの場合は、時間を置いて何度もtryする必要がある。 * @return true:起動された。false:起動されなかった。 */ private static void tryPrint() { // 準備ができてなければ何もせず次を待つ。 if (!printFrame.print()) return; // 印刷が起動された。印刷試行タイマーを解除し、廃棄タイマーを起動する tryPrintTimer.cancel(); disposeTimer.schedule(DISPOSE_INTERVAL); } /** * 廃棄タイマーによって起動され、iframeを廃棄する。 */ private static void dispose() { if (printFrame == null) return; printFrame.dispose(); printFrame = null; } }

PrintFrame.java


import com.google.gwt.dom.client.*; import com.google.gwt.user.client.ui.*; /** * 印刷用iframe * <p> * 指定されたURLあるいはHTMLを印刷するために、ドキュメント中にiframeを作成する。 * このiframeについて印刷指示を行う。 * 印刷が終了したらiframeを廃棄する。 * </p> * @author ysugimura */ abstract class PrintFrame { /** iframe */ protected final Frame frame; /** アタッチされている */ protected boolean attached; protected PrintFrame() { frame = new Frame(); frame.setWidth("0px"); frame.setHeight("0px"); } /** ドキュメントにアタッチする */ public void attach() { if (attached) return; attached = true; RootPanel.get().add(frame); } protected abstract boolean print(); /** * 廃棄する。 * 印刷起動直後に廃棄してはいけない。1秒後などの適当な時間をおいて廃棄を行うこと。 */ public void dispose() { if (!attached) return; frame.removeFromParent(); attached = false; } /** * iframeを印刷する * @param element */ protected static native void print(Element element) /*-{    element = element.contentWindow;    element.focus();    element.print();   }-*/; /** URL印刷用{@link PrintFrame} */ static class Url extends PrintFrame { Url(String url) { frame.setUrl(url); } /** * 印刷を起動する。 * iframeをドキュメントに追加した直後は印刷準備ができていない。 * 返り値がtrueになるまで何度も呼び出す必要がある。 * @return true:印刷起動OK。false:準備ができていない。 */ public boolean print() { assert attached; boolean ready = isReady(); if (!ready) return false; print(frame.getElement()); return true; } /** * 印刷準備ができているかを確認する * iframeコンテンツのURLがiframeのURLに一致すれば準備完了とする。 * @return true:ready、false:not ready */ private boolean isReady() { return frame.getUrl().equals(getContentUrl(frame.getElement())); } /** * iframeのコンテンツのURLを取得する。 * https://stackoverflow.com/questions/7796896/gwt-current-url-of-frames * @param frame * @return */ private native String getContentUrl(Element element) /*-{ if (element.contentDocument !== undefined) { return element.contentDocument.URL; } else if (element.contentWindow !== undefined && element.contentWindow.document !== undefined) { return element.contentWindow.document; } else { return null; } }-*/; } /** * HTML印刷用{@link PrintFrame} */ static class Html extends PrintFrame { private final String html; Html(String html) { this.html = html; } /** * 印刷する。アタッチされていなければいけない。 * 指定されたhtmlをコンテンツとしてセットし、印刷指示を行う */ @Override protected boolean print() { assert attached; if (!setContent(frame.getElement(), html)) return false; print(frame.getElement()); return true; } /** 印刷対象のhtmlをセットする */ private static native boolean setContent(Element element, String html) /*-{ var contentWindow = element.contentWindow; if (contentWindow == null) return false; var doc = contentWindow.document; doc.open(); doc.write(html); doc.close(); return true; }-*/; } }