1 /*
2 * $Id: PdfAction.java 3912 2009-04-26 08:38:15Z blowagie $
3 *
4 * Copyright 2000 by Bruno Lowagie.
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * (the "License"); you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at http://www.mozilla.org/MPL/
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the License.
13 *
14 * The Original Code is 'iText, a free JAVA-PDF library'.
15 *
16 * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
17 * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
18 * All Rights Reserved.
19 * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
20 * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
21 *
22 * Contributor(s): all the names of the contributors are added in the source code
23 * where applicable.
24 *
25 * Alternatively, the contents of this file may be used under the terms of the
26 * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
27 * provisions of LGPL are applicable instead of those above. If you wish to
28 * allow use of your version of this file only under the terms of the LGPL
29 * License and not to allow others to use your version of this file under
30 * the MPL, indicate your decision by deleting the provisions above and
31 * replace them with the notice and other provisions required by the LGPL.
32 * If you do not delete the provisions above, a recipient may use your version
33 * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
34 *
35 * This library is free software; you can redistribute it and/or modify it
36 * under the terms of the MPL as stated above or under the terms of the GNU
37 * Library General Public License as published by the Free Software Foundation;
38 * either version 2 of the License, or any later version.
39 *
40 * This library is distributed in the hope that it will be useful, but WITHOUT
41 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
42 * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
43 * details.
44 *
45 * If you didn't download this code from the following link, you should check if
46 * you aren't using an obsolete version:
47 * http://www.lowagie.com/iText/
48 */
49
50 package com.lowagie.text.pdf;
51
52 import java.io.IOException;
53 import java.net.URL;
54 import java.util.ArrayList;
55
56 import com.lowagie.text.pdf.collection.PdfTargetDictionary;
57
58 /**
59 * A <CODE>PdfAction</CODE> defines an action that can be triggered from a PDF file.
60 *
61 * @see PdfDictionary
62 */
63
64 public class PdfAction extends PdfDictionary {
65
66 /** A named action to go to the first page.
67 */
68 public static final int FIRSTPAGE = 1;
69 /** A named action to go to the previous page.
70 */
71 public static final int PREVPAGE = 2;
72 /** A named action to go to the next page.
73 */
74 public static final int NEXTPAGE = 3;
75 /** A named action to go to the last page.
76 */
77 public static final int LASTPAGE = 4;
78
79 /** A named action to open a print dialog.
80 */
81 public static final int PRINTDIALOG = 5;
82
83 /** a possible submitvalue */
84 public static final int SUBMIT_EXCLUDE = 1;
85 /** a possible submitvalue */
86 public static final int SUBMIT_INCLUDE_NO_VALUE_FIELDS = 2;
87 /** a possible submitvalue */
88 public static final int SUBMIT_HTML_FORMAT = 4;
89 /** a possible submitvalue */
90 public static final int SUBMIT_HTML_GET = 8;
91 /** a possible submitvalue */
92 public static final int SUBMIT_COORDINATES = 16;
93 /** a possible submitvalue */
94 public static final int SUBMIT_XFDF = 32;
95 /** a possible submitvalue */
96 public static final int SUBMIT_INCLUDE_APPEND_SAVES = 64;
97 /** a possible submitvalue */
98 public static final int SUBMIT_INCLUDE_ANNOTATIONS = 128;
99 /** a possible submitvalue */
100 public static final int SUBMIT_PDF = 256;
101 /** a possible submitvalue */
102 public static final int SUBMIT_CANONICAL_FORMAT = 512;
103 /** a possible submitvalue */
104 public static final int SUBMIT_EXCL_NON_USER_ANNOTS = 1024;
105 /** a possible submitvalue */
106 public static final int SUBMIT_EXCL_F_KEY = 2048;
107 /** a possible submitvalue */
108 public static final int SUBMIT_EMBED_FORM = 8196;
109 /** a possible submitvalue */
110 public static final int RESET_EXCLUDE = 1;
111
112 // constructors
113
114 /** Create an empty action.
115 */
116 public PdfAction() {
117 }
118
119 /**
120 * Constructs a new <CODE>PdfAction</CODE> of Subtype URI.
121 *
122 * @param url the Url to go to
123 */
124
125 public PdfAction(URL url) {
126 this(url.toExternalForm());
127 }
128
129 /**
130 * Construct a new <CODE>PdfAction</CODE> of Subtype URI that accepts the x and y coordinate of the position that was clicked.
131 * @param url
132 * @param isMap
133 */
134 public PdfAction(URL url, boolean isMap) {
135 this(url.toExternalForm(), isMap);
136 }
137
138 /**
139 * Constructs a new <CODE>PdfAction</CODE> of Subtype URI.
140 *
141 * @param url the url to go to
142 */
143
144 public PdfAction(String url) {
145 this(url, false);
146 }
147
148 /**
149 * Construct a new <CODE>PdfAction</CODE> of Subtype URI that accepts the x and y coordinate of the position that was clicked.
150 * @param url
151 * @param isMap
152 */
153
154 public PdfAction(String url, boolean isMap) {
155 put(PdfName.S, PdfName.URI);
156 put(PdfName.URI, new PdfString(url));
157 if (isMap)
158 put(PdfName.ISMAP, PdfBoolean.PDFTRUE);
159 }
160
161 /**
162 * Constructs a new <CODE>PdfAction</CODE> of Subtype GoTo.
163 * @param destination the destination to go to
164 */
165
166 PdfAction(PdfIndirectReference destination) {
167 put(PdfName.S, PdfName.GOTO);
168 put(PdfName.D, destination);
169 }
170
171 /**
172 * Constructs a new <CODE>PdfAction</CODE> of Subtype GoToR.
173 * @param filename the file name to go to
174 * @param name the named destination to go to
175 */
176
177 public PdfAction(String filename, String name) {
178 put(PdfName.S, PdfName.GOTOR);
179 put(PdfName.F, new PdfString(filename));
180 put(PdfName.D, new PdfString(name));
181 }
182
183 /**
184 * Constructs a new <CODE>PdfAction</CODE> of Subtype GoToR.
185 * @param filename the file name to go to
186 * @param page the page destination to go to
187 */
188
189 public PdfAction(String filename, int page) {
190 put(PdfName.S, PdfName.GOTOR);
191 put(PdfName.F, new PdfString(filename));
192 put(PdfName.D, new PdfLiteral("[" + (page - 1) + " /FitH 10000]"));
193 }
194
195 /** Implements name actions. The action can be FIRSTPAGE, LASTPAGE,
196 * NEXTPAGE, PREVPAGE and PRINTDIALOG.
197 * @param named the named action
198 */
199 public PdfAction(int named) {
200 put(PdfName.S, PdfName.NAMED);
201 switch (named) {
202 case FIRSTPAGE:
203 put(PdfName.N, PdfName.FIRSTPAGE);
204 break;
205 case LASTPAGE:
206 put(PdfName.N, PdfName.LASTPAGE);
207 break;
208 case NEXTPAGE:
209 put(PdfName.N, PdfName.NEXTPAGE);
210 break;
211 case PREVPAGE:
212 put(PdfName.N, PdfName.PREVPAGE);
213 break;
214 case PRINTDIALOG:
215 put(PdfName.S, PdfName.JAVASCRIPT);
216 put(PdfName.JS, new PdfString("this.print(true);\r"));
217 break;
218 default:
219 throw new RuntimeException("Invalid named action.");
220 }
221 }
222
223 /** Launches an application or a document.
224 * @param application the application to be launched or the document to be opened or printed.
225 * @param parameters (Windows-specific) A parameter string to be passed to the application.
226 * It can be <CODE>null</CODE>.
227 * @param operation (Windows-specific) the operation to perform: "open" - Open a document,
228 * "print" - Print a document.
229 * It can be <CODE>null</CODE>.
230 * @param defaultDir (Windows-specific) the default directory in standard DOS syntax.
231 * It can be <CODE>null</CODE>.
232 */
233 public PdfAction(String application, String parameters, String operation, String defaultDir) {
234 put(PdfName.S, PdfName.LAUNCH);
235 if (parameters == null && operation == null && defaultDir == null)
236 put(PdfName.F, new PdfString(application));
237 else {
238 PdfDictionary dic = new PdfDictionary();
239 dic.put(PdfName.F, new PdfString(application));
240 if (parameters != null)
241 dic.put(PdfName.P, new PdfString(parameters));
242 if (operation != null)
243 dic.put(PdfName.O, new PdfString(operation));
244 if (defaultDir != null)
245 dic.put(PdfName.D, new PdfString(defaultDir));
246 put(PdfName.WIN, dic);
247 }
248 }
249
250 /** Launches an application or a document.
251 * @param application the application to be launched or the document to be opened or printed.
252 * @param parameters (Windows-specific) A parameter string to be passed to the application.
253 * It can be <CODE>null</CODE>.
254 * @param operation (Windows-specific) the operation to perform: "open" - Open a document,
255 * "print" - Print a document.
256 * It can be <CODE>null</CODE>.
257 * @param defaultDir (Windows-specific) the default directory in standard DOS syntax.
258 * It can be <CODE>null</CODE>.
259 * @return a Launch action
260 */
261 public static PdfAction createLaunch(String application, String parameters, String operation, String defaultDir) {
262 return new PdfAction(application, parameters, operation, defaultDir);
263 }
264
265 /**Creates a Rendition action
266 * @param file
267 * @param fs
268 * @param mimeType
269 * @param ref
270 * @return a Media Clip action
271 * @throws IOException
272 */
273 public static PdfAction rendition(String file, PdfFileSpecification fs, String mimeType, PdfIndirectReference ref) throws IOException {
274 PdfAction js = new PdfAction();
275 js.put(PdfName.S, PdfName.RENDITION);
276 js.put(PdfName.R, new PdfRendition(file, fs, mimeType));
277 js.put(new PdfName("OP"), new PdfNumber(0));
278 js.put(new PdfName("AN"), ref);
279 return js;
280 }
281
282 /** Creates a JavaScript action. If the JavaScript is smaller than
283 * 50 characters it will be placed as a string, otherwise it will
284 * be placed as a compressed stream.
285 * @param code the JavaScript code
286 * @param writer the writer for this action
287 * @param unicode select JavaScript unicode. Note that the internal
288 * Acrobat JavaScript engine does not support unicode,
289 * so this may or may not work for you
290 * @return the JavaScript action
291 */
292 public static PdfAction javaScript(String code, PdfWriter writer, boolean unicode) {
293 PdfAction js = new PdfAction();
294 js.put(PdfName.S, PdfName.JAVASCRIPT);
295 if (unicode && code.length() < 50) {
296 js.put(PdfName.JS, new PdfString(code, PdfObject.TEXT_UNICODE));
297 }
298 else if (!unicode && code.length() < 100) {
299 js.put(PdfName.JS, new PdfString(code));
300 }
301 else {
302 try {
303 byte b[] = PdfEncodings.convertToBytes(code, unicode ? PdfObject.TEXT_UNICODE : PdfObject.TEXT_PDFDOCENCODING);
304 PdfStream stream = new PdfStream(b);
305 stream.flateCompress(writer.getCompressionLevel());
306 js.put(PdfName.JS, writer.addToBody(stream).getIndirectReference());
307 }
308 catch (Exception e) {
309 js.put(PdfName.JS, new PdfString(code));
310 }
311 }
312 return js;
313 }
314
315 /** Creates a JavaScript action. If the JavaScript is smaller than
316 * 50 characters it will be place as a string, otherwise it will
317 * be placed as a compressed stream.
318 * @param code the JavaScript code
319 * @param writer the writer for this action
320 * @return the JavaScript action
321 */
322 public static PdfAction javaScript(String code, PdfWriter writer) {
323 return javaScript(code, writer, false);
324 }
325
326 /**
327 * A Hide action hides or shows an object.
328 * @param obj object to hide or show
329 * @param hide true is hide, false is show
330 * @return a Hide Action
331 */
332 static PdfAction createHide(PdfObject obj, boolean hide) {
333 PdfAction action = new PdfAction();
334 action.put(PdfName.S, PdfName.HIDE);
335 action.put(PdfName.T, obj);
336 if (!hide)
337 action.put(PdfName.H, PdfBoolean.PDFFALSE);
338 return action;
339 }
340
341 /**
342 * A Hide action hides or shows an annotation.
343 * @param annot
344 * @param hide
345 * @return A Hide Action
346 */
347 public static PdfAction createHide(PdfAnnotation annot, boolean hide) {
348 return createHide(annot.getIndirectReference(), hide);
349 }
350
351 /**
352 * A Hide action hides or shows an annotation.
353 * @param name
354 * @param hide
355 * @return A Hide Action
356 */
357 public static PdfAction createHide(String name, boolean hide) {
358 return createHide(new PdfString(name), hide);
359 }
360
361 static PdfArray buildArray(Object names[]) {
362 PdfArray array = new PdfArray();
363 for (int k = 0; k < names.length; ++k) {
364 Object obj = names[k];
365 if (obj instanceof String)
366 array.add(new PdfString((String)obj));
367 else if (obj instanceof PdfAnnotation)
368 array.add(((PdfAnnotation)obj).getIndirectReference());
369 else
370 throw new RuntimeException("The array must contain String or PdfAnnotation.");
371 }
372 return array;
373 }
374
375 /**
376 * A Hide action hides or shows objects.
377 * @param names
378 * @param hide
379 * @return A Hide Action
380 */
381 public static PdfAction createHide(Object names[], boolean hide) {
382 return createHide(buildArray(names), hide);
383 }
384
385 /**
386 * Creates a submit form.
387 * @param file the URI to submit the form to
388 * @param names the objects to submit
389 * @param flags submit properties
390 * @return A PdfAction
391 */
392 public static PdfAction createSubmitForm(String file, Object names[], int flags) {
393 PdfAction action = new PdfAction();
394 action.put(PdfName.S, PdfName.SUBMITFORM);
395 PdfDictionary dic = new PdfDictionary();
396 dic.put(PdfName.F, new PdfString(file));
397 dic.put(PdfName.FS, PdfName.URL);
398 action.put(PdfName.F, dic);
399 if (names != null)
400 action.put(PdfName.FIELDS, buildArray(names));
401 action.put(PdfName.FLAGS, new PdfNumber(flags));
402 return action;
403 }
404
405 /**
406 * Creates a resetform.
407 * @param names the objects to reset
408 * @param flags submit properties
409 * @return A PdfAction
410 */
411 public static PdfAction createResetForm(Object names[], int flags) {
412 PdfAction action = new PdfAction();
413 action.put(PdfName.S, PdfName.RESETFORM);
414 if (names != null)
415 action.put(PdfName.FIELDS, buildArray(names));
416 action.put(PdfName.FLAGS, new PdfNumber(flags));
417 return action;
418 }
419
420 /**
421 * Creates an Import field.
422 * @param file
423 * @return A PdfAction
424 */
425 public static PdfAction createImportData(String file) {
426 PdfAction action = new PdfAction();
427 action.put(PdfName.S, PdfName.IMPORTDATA);
428 action.put(PdfName.F, new PdfString(file));
429 return action;
430 }
431
432 /** Add a chained action.
433 * @param na the next action
434 */
435 public void next(PdfAction na) {
436 PdfObject nextAction = get(PdfName.NEXT);
437 if (nextAction == null)
438 put(PdfName.NEXT, na);
439 else if (nextAction.isDictionary()) {
440 PdfArray array = new PdfArray(nextAction);
441 array.add(na);
442 put(PdfName.NEXT, array);
443 }
444 else {
445 ((PdfArray)nextAction).add(na);
446 }
447 }
448
449 /** Creates a GoTo action to an internal page.
450 * @param page the page to go. First page is 1
451 * @param dest the destination for the page
452 * @param writer the writer for this action
453 * @return a GoTo action
454 */
455 public static PdfAction gotoLocalPage(int page, PdfDestination dest, PdfWriter writer) {
456 PdfIndirectReference ref = writer.getPageReference(page);
457 dest.addPage(ref);
458 PdfAction action = new PdfAction();
459 action.put(PdfName.S, PdfName.GOTO);
460 action.put(PdfName.D, dest);
461 return action;
462 }
463
464 /**
465 * Creates a GoTo action to a named destination.
466 * @param dest the named destination
467 * @param isName if true sets the destination as a name, if false sets it as a String
468 * @return a GoTo action
469 */
470 public static PdfAction gotoLocalPage(String dest, boolean isName) {
471 PdfAction action = new PdfAction();
472 action.put(PdfName.S, PdfName.GOTO);
473 if (isName)
474 action.put(PdfName.D, new PdfName(dest));
475 else
476 action.put(PdfName.D, new PdfString(dest, null));
477 return action;
478 }
479
480 /**
481 * Creates a GoToR action to a named destination.
482 * @param filename the file name to go to
483 * @param dest the destination name
484 * @param isName if true sets the destination as a name, if false sets it as a String
485 * @param newWindow open the document in a new window if <CODE>true</CODE>, if false the current document is replaced by the new document.
486 * @return a GoToR action
487 */
488 public static PdfAction gotoRemotePage(String filename, String dest, boolean isName, boolean newWindow) {
489 PdfAction action = new PdfAction();
490 action.put(PdfName.F, new PdfString(filename));
491 action.put(PdfName.S, PdfName.GOTOR);
492 if (isName)
493 action.put(PdfName.D, new PdfName(dest));
494 else
495 action.put(PdfName.D, new PdfString(dest, null));
496 if (newWindow)
497 action.put(PdfName.NEWWINDOW, PdfBoolean.PDFTRUE);
498 return action;
499 }
500
501 /**
502 * Creates a GoToE action to an embedded file.
503 * @param filename the root document of the target (null if the target is in the same document)
504 * @param dest the named destination
505 * @param isName if true sets the destination as a name, if false sets it as a String
506 * @return a GoToE action
507 */
508 public static PdfAction gotoEmbedded(String filename, PdfTargetDictionary target, String dest, boolean isName, boolean newWindow) {
509 if (isName)
510 return gotoEmbedded(filename, target, new PdfName(dest), newWindow);
511 else
512 return gotoEmbedded(filename, target, new PdfString(dest, null), newWindow);
513 }
514
515 /**
516 * Creates a GoToE action to an embedded file.
517 * @param filename the root document of the target (null if the target is in the same document)
518 * @param target a path to the target document of this action
519 * @param dest the destination inside the target document, can be of type PdfDestination, PdfName, or PdfString
520 * @param newWindow if true, the destination document should be opened in a new window
521 * @return a GoToE action
522 */
523 public static PdfAction gotoEmbedded(String filename, PdfTargetDictionary target, PdfObject dest, boolean newWindow) {
524 PdfAction action = new PdfAction();
525 action.put(PdfName.S, PdfName.GOTOE);
526 action.put(PdfName.T, target);
527 action.put(PdfName.D, dest);
528 action.put(PdfName.NEWWINDOW, new PdfBoolean(newWindow));
529 if (filename != null) {
530 action.put(PdfName.F, new PdfString(filename));
531 }
532 return action;
533 }
534
535 /**
536 * A set-OCG-state action (PDF 1.5) sets the state of one or more optional content
537 * groups.
538 * @param state an array consisting of any number of sequences beginning with a <CODE>PdfName</CODE>
539 * or <CODE>String</CODE> (ON, OFF, or Toggle) followed by one or more optional content group dictionaries
540 * <CODE>PdfLayer</CODE> or a <CODE>PdfIndirectReference</CODE> to a <CODE>PdfLayer</CODE>.<br>
541 * The array elements are processed from left to right; each name is applied
542 * to the subsequent groups until the next name is encountered:
543 * <ul>
544 * <li>ON sets the state of subsequent groups to ON</li>
545 * <li>OFF sets the state of subsequent groups to OFF</li>
546 * <li>Toggle reverses the state of subsequent groups</li>
547 * </ul>
548 * @param preserveRB if <CODE>true</CODE>, indicates that radio-button state relationships between optional
549 * content groups (as specified by the RBGroups entry in the current configuration
550 * dictionary) should be preserved when the states in the
551 * <CODE>state</CODE> array are applied. That is, if a group is set to ON (either by ON or Toggle) during
552 * processing of the <CODE>state</CODE> array, any other groups belong to the same radio-button
553 * group are turned OFF. If a group is set to OFF, there is no effect on other groups.<br>
554 * If <CODE>false</CODE>, radio-button state relationships, if any, are ignored
555 * @return the action
556 */
557 public static PdfAction setOCGstate(ArrayList state, boolean preserveRB) {
558 PdfAction action = new PdfAction();
559 action.put(PdfName.S, PdfName.SETOCGSTATE);
560 PdfArray a = new PdfArray();
561 for (int k = 0; k < state.size(); ++k) {
562 Object o = state.get(k);
563 if (o == null)
564 continue;
565 if (o instanceof PdfIndirectReference)
566 a.add((PdfIndirectReference)o);
567 else if (o instanceof PdfLayer)
568 a.add(((PdfLayer)o).getRef());
569 else if (o instanceof PdfName)
570 a.add((PdfName)o);
571 else if (o instanceof String) {
572 PdfName name = null;
573 String s = (String)o;
574 if (s.equalsIgnoreCase("on"))
575 name = PdfName.ON;
576 else if (s.equalsIgnoreCase("off"))
577 name = PdfName.OFF;
578 else if (s.equalsIgnoreCase("toggle"))
579 name = PdfName.TOGGLE;
580 else
581 throw new IllegalArgumentException("A string '" + s + " was passed in state. Only 'ON', 'OFF' and 'Toggle' are allowed.");
582 a.add(name);
583 }
584 else
585 throw new IllegalArgumentException("Invalid type was passed in state: " + o.getClass().getName());
586 }
587 action.put(PdfName.STATE, a);
588 if (!preserveRB)
589 action.put(PdfName.PRESERVERB, PdfBoolean.PDFFALSE);
590 return action;
591 }
592 }
593