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;
}-*/;
}
}