diff --git a/Examples/.gitignore b/Examples/.gitignore
deleted file mode 100644
index 3d690c19..00000000
--- a/Examples/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-.idea/
-target/
-*.iml
-~*
-*.*~
-*[Oo]ut*
diff --git a/Examples/.project b/Examples/.project
deleted file mode 100644
index f7b6dad8..00000000
--- a/Examples/.project
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
- Aspose.Words Examples
-
-
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
- org.eclipse.m2e.core.maven2Builder
-
-
-
-
-
- org.eclipse.m2e.core.maven2Nature
- org.eclipse.jdt.core.javanature
-
-
-
- 1356841242113
- src
- 26
-
- org.eclipse.ui.ide.multiFilter
- 1.0-name-matches-false-false-bin
-
-
-
-
diff --git a/Examples/ApiExamples/Java/pom.xml b/Examples/ApiExamples/Java/pom.xml
new file mode 100644
index 00000000..595e0188
--- /dev/null
+++ b/Examples/ApiExamples/Java/pom.xml
@@ -0,0 +1,109 @@
+
+
+ 4.0.0
+
+
+ UTF-8
+
+
+ com.aspose.apiexamples
+ ApiExamples-Tests
+ 1.0-SNAPSHOT
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.0
+
+ 1.8
+ 1.8
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.0.0-M4
+
+ ${basedir}/src/main/java/
+ ${project.build.directory}/classes/
+
+ **/Ex*.java
+
+
+
+
+
+
+
+
+ AsposeJavaAPI
+ Aspose Java API
+ https://releases.aspose.com/java/repo/
+
+
+ com.springsource.repository.bundles.external
+ SpringSource Enterprise Bundle Repository - External Bundle Releases
+ https://repository.springsource.com/maven/bundles/external
+
+
+
+
+
+ com.aspose
+ aspose-words
+ 25.9
+ jdk17
+
+
+ com.aspose
+ aspose-words
+ 25.9
+ shaping-harfbuzz-plugin
+
+
+ com.aspose
+ aspose-barcode
+ 25.8
+ jdk18
+
+
+ com.aspose
+ aspose-pdf
+ 25.8
+ jdk17
+
+
+ org.testng
+ testng
+ 7.5.1
+
+
+ javax.media.jai
+ com.springsource.javax.media.jai.core
+ 1.1.3
+
+
+ net.sf.ucanaccess
+ ucanaccess
+ 3.0.6
+
+
+ commons-io
+ commons-io
+ 2.16.1
+
+
+ org.apache.commons
+ commons-collections4
+ 4.4
+
+
+ org.apache.poi
+ poi
+ 5.0.0
+
+
+
\ No newline at end of file
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ApiExampleBase.java b/Examples/ApiExamples/Java/src/main/java/Examples/ApiExampleBase.java
new file mode 100644
index 00000000..dc8a8d80
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ApiExampleBase.java
@@ -0,0 +1,197 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.words.CurrentThreadSettings;
+import com.aspose.words.License;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+
+import java.io.File;
+import java.net.URI;
+import java.util.Locale;
+
+/**
+ * Provides common infrastructure for all API examples that are implemented as unit tests.
+ */
+public class ApiExampleBase {
+
+ /**
+ * Test artifacts directory.
+ */
+ private final File artifactsDirPath = new File(getArtifactsDir());
+
+ /**
+ * Delete all dirs and files from directory.
+ *
+ * @param dir directory to be deleted
+ */
+ private static void deleteDir(final File dir) {
+ String[] entries = dir.list();
+ for (String s : entries) {
+ File currentFile = new File(dir.getPath(), s);
+ if (currentFile.isDirectory()) {
+ deleteDir(currentFile);
+ } else {
+ currentFile.delete();
+ }
+ }
+ dir.delete();
+ }
+
+ /**
+ * Delete and create new empty directory for test artifacts.
+ *
+ * @throws Exception exception for setUnlimitedLicense()
+ */
+ @BeforeClass(alwaysRun = true)
+ public void setUp() throws Exception {
+ CurrentThreadSettings.setLocale(Locale.US);
+ setUnlimitedLicense();
+
+ if (!artifactsDirPath.exists()) {
+ artifactsDirPath.mkdir();
+ } else {
+ deleteDir(artifactsDirPath);
+ artifactsDirPath.mkdir();
+ }
+ }
+
+ /**
+ * Delete all dirs and files from directory for test artifacts.
+ */
+ @AfterClass(alwaysRun = true)
+ public void tearDown() {
+ deleteDir(artifactsDirPath);
+ }
+
+ /**
+ * Set java licence for using library without any restrictions.
+ *
+ * @throws Exception exception for setting licence
+ */
+ private static void setUnlimitedLicense() throws Exception {
+ // This is where the test license is on my development machine.
+ String testLicenseFileName = getLicenseDir() + "Aspose.Total.Java.lic";
+ if (new File(testLicenseFileName).exists()) {
+ // This shows how to use an Aspose.Words license when you have purchased one.
+ // You don't have to specify full path as shown here. You can specify just the
+ // file name if you copy the license file into the same folder as your application
+ // binaries or you add the license to your project as an embedded resource.
+ License wordsLicense = new License();
+ wordsLicense.setLicense(testLicenseFileName);
+
+ com.aspose.pdf.License pdfLicense = new com.aspose.pdf.License();
+ pdfLicense.setLicense(testLicenseFileName);
+
+ com.aspose.barcode.License barcodeLicense = new com.aspose.barcode.License();
+ barcodeLicense.setLicense(testLicenseFileName);
+ }
+ }
+
+ /**
+ * Gets the path to the license used by the code examples.
+ *
+ * @return licence directory
+ */
+ static String getLicenseDir() {
+ return G_LICENSE_DIR;
+ }
+
+ /**
+ * Gets the path to the documents used by the code examples. Ends with a back slash.
+ *
+ * @return directory for test artifacts
+ */
+ static String getArtifactsDir() {
+ return G_ARTIFACTS_DIR;
+ }
+
+ /**
+ * Gets the path to the documents used by the code examples. Ends with a back slash.
+ *
+ * @return directory with expected documents
+ */
+ static String getGoldsDir() {
+ return G_GOLDS_DIR;
+ }
+
+ /**
+ * Gets the path to the documents used by the code examples. Ends with a back slash.
+ *
+ * @return directory with documents for testing
+ */
+ static String getMyDir() {
+ return G_MY_DIR;
+ }
+
+ /**
+ * Gets the path to the images used by the code examples. Ends with a back slash.
+ *
+ * @return directory with images for testing
+ */
+ protected static String getImageDir() {
+ return G_IMAGE_DIR;
+ }
+
+ /**
+ * Gets the path to the codebase directory.
+ *
+ * @return directory with data files for testing
+ */
+ static String getDatabaseDir() {
+ return G_DATABASE_DIR;
+ }
+
+ /**
+ * Gets the path of the free fonts. Ends with a back slash.
+ *
+ * @return directory with public fonts for testing
+ */
+ static String getFontsDir() {
+ return G_FONTS_DIR;
+ }
+
+ /**
+ * Gets the path to the codebase directory.
+ *
+ * @return url with aspose logo image
+ */
+ static URI getAsposelogoUri() {
+ return G_ASPOSELOGO_URI;
+ }
+
+ private static final String G_ASSEMBLY_DIR;
+ private static final String G_CODE_BASE_DIR;
+ private static final String G_LICENSE_DIR;
+ private static final String G_ARTIFACTS_DIR;
+ private static final String G_GOLDS_DIR;
+ private static final String G_MY_DIR;
+ private static final String G_IMAGE_DIR;
+ private static final String G_DATABASE_DIR;
+ private static final String G_FONTS_DIR;
+ private static final URI G_ASPOSELOGO_URI;
+
+ static {
+ try {
+ G_ASSEMBLY_DIR = System.getProperty("user.dir");
+ G_CODE_BASE_DIR = new File(G_ASSEMBLY_DIR).getParentFile().getParentFile() + File.separator;
+ G_LICENSE_DIR = G_CODE_BASE_DIR + "Data" + File.separator + "License" + File.separator;
+ G_ARTIFACTS_DIR = G_CODE_BASE_DIR + "Data" + File.separator + "Artifacts" + File.separator;
+ G_GOLDS_DIR = G_CODE_BASE_DIR + "Data" + File.separator + "Golds" + File.separator;
+ G_MY_DIR = G_CODE_BASE_DIR + "Data" + File.separator;
+ G_IMAGE_DIR = G_CODE_BASE_DIR + "Data" + File.separator + "Images" + File.separator;
+ G_DATABASE_DIR = G_CODE_BASE_DIR + "Data" + File.separator + "Database" + File.separator;
+ G_FONTS_DIR = G_CODE_BASE_DIR + "Data" + File.separator + "MyFonts" + File.separator;
+ G_ASPOSELOGO_URI = new URI("https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/CustomBarcodeGenerator.java b/Examples/ApiExamples/Java/src/main/java/Examples/CustomBarcodeGenerator.java
new file mode 100644
index 00000000..b21bae55
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/CustomBarcodeGenerator.java
@@ -0,0 +1,266 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.barcode.generation.*;
+import com.aspose.words.BarcodeParameters;
+import com.aspose.words.IBarcodeGenerator;
+
+import java.awt.*;
+import java.awt.image.BufferedImage;
+
+class CustomBarcodeGeneratorUtils {
+ ///
+ /// Converts a height value in twips to pixels using a default DPI of 96.
+ ///
+ /// The height value in twips.
+ /// The default value to return if the conversion fails.
+ /// The height value in pixels.
+ public static double twipsToPixels(String heightInTwips, double defVal) {
+ return twipsToPixels(heightInTwips, 96.0, defVal);
+ }
+
+ ///
+ /// Converts a height value in twips to pixels based on the given resolution.
+ ///
+ /// The height value in twips to be converted.
+ /// The resolution in pixels per inch.
+ /// The default value to be returned if the conversion fails.
+ /// The converted height value in pixels.
+ public static double twipsToPixels(String heightInTwips, double resolution, double defVal) {
+ try {
+ int lVal = Integer.parseInt(heightInTwips);
+ return (lVal / 1440.0) * resolution;
+ } catch (Exception e) {
+ return defVal;
+ }
+ }
+
+ ///
+ /// Gets the rotation angle in degrees based on the given rotation angle string.
+ ///
+ /// The rotation angle string.
+ /// The default value to return if the rotation angle is not recognized.
+ /// The rotation angle in degrees.
+ public static float getRotationAngle(String rotationAngle, float defVal) {
+ switch (rotationAngle) {
+ case "0":
+ return 0f;
+ case "1":
+ return 270f;
+ case "2":
+ return 180f;
+ case "3":
+ return 90f;
+ default:
+ return defVal;
+ }
+ }
+
+ ///
+ /// Converts a string representation of an error correction level to a QRErrorLevel enum value.
+ ///
+ /// The string representation of the error correction level.
+ /// The default error correction level to return if the input is invalid.
+ /// The corresponding QRErrorLevel enum value.
+ public static QRErrorLevel getQRCorrectionLevel(String errorCorrectionLevel, QRErrorLevel def) {
+ switch (errorCorrectionLevel) {
+ case "0":
+ return QRErrorLevel.LEVEL_L;
+ case "1":
+ return QRErrorLevel.LEVEL_M;
+ case "2":
+ return QRErrorLevel.LEVEL_Q;
+ case "3":
+ return QRErrorLevel.LEVEL_H;
+ default:
+ return def;
+ }
+ }
+
+ ///
+ /// Gets the barcode encode type based on the given encode type from Word.
+ ///
+ /// The encode type from Word.
+ /// The barcode encode type.
+ public static SymbologyEncodeType getBarcodeEncodeType(String encodeTypeFromWord) {
+ // https://support.microsoft.com/en-au/office/field-codes-displaybarcode-6d81eade-762d-4b44-ae81-f9d3d9e07be3
+ switch (encodeTypeFromWord) {
+ case "QR":
+ return EncodeTypes.QR;
+ case "CODE128":
+ return EncodeTypes.CODE_128;
+ case "CODE39":
+ return EncodeTypes.CODE_39;
+ case "JPPOST":
+ return EncodeTypes.RM_4_SCC;
+ case "EAN8":
+ case "JAN8":
+ return EncodeTypes.EAN_8;
+ case "EAN13":
+ case "JAN13":
+ return EncodeTypes.EAN_13;
+ case "UPCA":
+ return EncodeTypes.UPCA;
+ case "UPCE":
+ return EncodeTypes.UPCE;
+ case "CASE":
+ case "ITF14":
+ return EncodeTypes.ITF_14;
+ case "NW7":
+ return EncodeTypes.CODABAR;
+ default:
+ return EncodeTypes.NONE;
+ }
+ }
+
+ ///
+ /// Converts a hexadecimal color string to a Color object.
+ ///
+ /// The hexadecimal color string to convert.
+ /// The default Color value to return if the conversion fails.
+ /// The Color object representing the converted color, or the default value if the conversion fails.
+ public static Color convertColor(String inputColor, Color defVal) {
+ if (inputColor == null || inputColor.isEmpty()) return defVal;
+ try {
+ int color = Integer.parseInt(inputColor, 16);
+ // Return Color.FromArgb((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF);
+ return new Color((color & 0xFF), ((color >> 8) & 0xFF), ((color >> 16) & 0xFF));
+ } catch (Exception e) {
+ return defVal;
+ }
+ }
+
+ ///
+ /// Calculates the scale factor based on the provided string representation.
+ ///
+ /// The string representation of the scale factor.
+ /// The default value to return if the scale factor cannot be parsed.
+ ///
+ /// The scale factor as a decimal value between 0 and 1, or the default value if the scale factor cannot be parsed.
+ ///
+ public static double scaleFactor(String scaleFactor, double defVal) {
+ try {
+ int scale = Integer.parseInt(scaleFactor);
+ return scale / 100.0;
+ } catch (Exception e) {
+ return defVal;
+ }
+ }
+
+ ///
+ /// Sets the position code style for a barcode generator.
+ ///
+ /// The barcode generator.
+ /// The position code style to set.
+ /// The barcode value.
+ public static void setPosCodeStyle(BarcodeGenerator gen, String posCodeStyle, String barcodeValue) {
+ switch (posCodeStyle) {
+ // STD default and without changes.
+ case "SUP2":
+ gen.setCodeText(barcodeValue.substring((0), (0) + (barcodeValue.length() - 2)));
+ gen.getParameters().getBarcode().getSupplement().setSupplementData(barcodeValue.substring((barcodeValue.length() - 2), (barcodeValue.length() - 2) + (2)));
+ break;
+ case "SUP5":
+ gen.setCodeText(barcodeValue.substring((0), (0) + (barcodeValue.length() - 5)));
+ gen.getParameters().getBarcode().getSupplement().setSupplementData(barcodeValue.substring((barcodeValue.length() - 5), (barcodeValue.length() - 5) + (5)));
+ break;
+ case "CASE":
+ gen.getParameters().getBorder().setVisible(true);
+ gen.getParameters().getBorder().setColor(gen.getParameters().getBarcode().getBarColor());
+ gen.getParameters().getBorder().setDashStyle(BorderDashStyle.SOLID);
+ gen.getParameters().getBorder().getWidth().setPixels(gen.getParameters().getBarcode().getXDimension().getPixels() * 5);
+ break;
+ }
+ }
+
+ public static final double DEFAULT_QRX_DIMENSION_IN_PIXELS = 4.0;
+ public static final double DEFAULT_1_DX_DIMENSION_IN_PIXELS = 1.0;
+
+ ///
+ /// Draws an error image with the specified exception message.
+ ///
+ /// The exception containing the error message.
+ /// A Bitmap object representing the error image.
+ public static BufferedImage drawErrorImage(Exception error) {
+ BufferedImage bmp = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
+
+ Graphics2D grf = bmp.createGraphics();
+ grf.setColor(Color.WHITE);
+ grf.fillRect(0, 0, bmp.getWidth(), bmp.getHeight());
+ grf.setFont(new Font("Microsoft Sans Serif", 8, FontStyle.REGULAR));
+ grf.setColor(Color.RED);
+ grf.drawString(error.getMessage(), 0, 0);
+
+ return bmp;
+ }
+
+ public static BufferedImage convertImageToWord(BufferedImage bmp) {
+ return bmp;
+ }
+}
+
+class CustomBarcodeGenerator implements IBarcodeGenerator {
+ public BufferedImage getBarcodeImage(BarcodeParameters parameters) {
+ try {
+ BarcodeGenerator gen = new BarcodeGenerator(CustomBarcodeGeneratorUtils.getBarcodeEncodeType(parameters.getBarcodeType()), parameters.getBarcodeValue());
+
+ // Set color.
+ gen.getParameters().getBarcode().setBarColor(CustomBarcodeGeneratorUtils.convertColor(parameters.getForegroundColor(), gen.getParameters().getBarcode().getBarColor()));
+ gen.getParameters().setBackColor(CustomBarcodeGeneratorUtils.convertColor(parameters.getBackgroundColor(), gen.getParameters().getBackColor()));
+
+ // Set display or hide text.
+ if (!parameters.getDisplayText())
+ gen.getParameters().getBarcode().getCodeTextParameters().setLocation(CodeLocation.NONE);
+ else
+ gen.getParameters().getBarcode().getCodeTextParameters().setLocation(CodeLocation.BELOW);
+
+ // Set QR Code error correction level.s
+ gen.getParameters().getBarcode().getQR().setQrErrorLevel(QRErrorLevel.LEVEL_H);
+ String errorCorrectionLevel = parameters.getErrorCorrectionLevel();
+ if (errorCorrectionLevel != null)
+ gen.getParameters().getBarcode().getQR().setQrErrorLevel(CustomBarcodeGeneratorUtils.getQRCorrectionLevel(errorCorrectionLevel, gen.getParameters().getBarcode().getQR().getQrErrorLevel()));
+
+ // Set rotation angle.
+ String symbolRotation = parameters.getSymbolRotation();
+ if (symbolRotation != null)
+ gen.getParameters().setRotationAngle(CustomBarcodeGeneratorUtils.getRotationAngle(symbolRotation, gen.getParameters().getRotationAngle()));
+
+ // Set scaling factor.
+ double scalingFactor = 1.0;
+ if (parameters.getScalingFactor() != null)
+ scalingFactor = CustomBarcodeGeneratorUtils.scaleFactor(parameters.getScalingFactor(), scalingFactor);
+
+ // Set size.
+ if (gen.getBarcodeType() == EncodeTypes.QR)
+ gen.getParameters().getBarcode().getXDimension().setPixels((float) Math.max(1.0, Math.round(CustomBarcodeGeneratorUtils.DEFAULT_QRX_DIMENSION_IN_PIXELS * scalingFactor)));
+ else
+ gen.getParameters().getBarcode().getXDimension().setPixels((float) Math.max(1.0, Math.round(CustomBarcodeGeneratorUtils.DEFAULT_1_DX_DIMENSION_IN_PIXELS * scalingFactor)));
+
+ //Set height.
+ String symbolHeight = parameters.getSymbolHeight();
+ if (symbolHeight != null)
+ gen.getParameters().getBarcode().getBarHeight().setPixels((float) Math.max(5.0,
+ Math.round(CustomBarcodeGeneratorUtils.twipsToPixels(symbolHeight, gen.getParameters().getBarcode().getBarHeight().getPixels()) * scalingFactor)));
+
+ // Set style of a Point-of-Sale barcode.
+ String posCodeStyle = parameters.getPosCodeStyle();
+ if (posCodeStyle != null)
+ CustomBarcodeGeneratorUtils.setPosCodeStyle(gen, posCodeStyle, parameters.getBarcodeValue());
+
+ return CustomBarcodeGeneratorUtils.convertImageToWord(gen.generateBarCodeImage());
+ } catch (Exception e) {
+ return CustomBarcodeGeneratorUtils.convertImageToWord(CustomBarcodeGeneratorUtils.drawErrorImage(e));
+ }
+ }
+
+ public BufferedImage getOldBarcodeImage(BarcodeParameters parameters) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/DocumentHelper.java b/Examples/ApiExamples/Java/src/main/java/Examples/DocumentHelper.java
new file mode 100644
index 00000000..493de655
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/DocumentHelper.java
@@ -0,0 +1,489 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.words.*;
+import org.testng.Assert;
+
+import java.io.*;
+import java.sql.ResultSet;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.regex.Pattern;
+
+import static Examples.ApiExampleBase.getDatabaseDir;
+
+/**
+ * Functions for operations with document and content.
+ */
+public final class DocumentHelper {
+
+ private DocumentHelper() {
+ //not called
+ }
+
+ /**
+ * Create simple document without run in the paragraph.
+ *
+ * @return new document without any text
+ * @throws Exception exception for creating new document
+ */
+ static Document createDocumentWithoutDummyText() throws Exception {
+ Document doc = new Document();
+
+ //Remove the previous changes of the document
+ doc.removeAllChildren();
+
+ //Set the document author
+ doc.getBuiltInDocumentProperties().setAuthor("Test Author");
+
+ //Create paragraph without run
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ builder.writeln();
+
+ return doc;
+ }
+
+ /**
+ * Create new document with text.
+ *
+ * @return new document with dummy text
+ * @throws Exception exception for creating new document
+ */
+ static Document createDocumentFillWithDummyText() throws Exception {
+ Document doc = new Document();
+
+ //Remove the previous changes of the document
+ doc.removeAllChildren();
+
+ //Set the document author
+ doc.getBuiltInDocumentProperties().setAuthor("Test Author");
+
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ builder.write("Page ");
+ builder.insertField("PAGE", "");
+ builder.write(" of ");
+ builder.insertField("NUMPAGES", "");
+
+ //Insert new table with two rows and two cells
+ insertTable(builder);
+
+ builder.writeln("Hello World!");
+
+ // Continued on page 2 of the document content
+ builder.insertBreak(BreakType.PAGE_BREAK);
+
+ //Insert TOC entries
+ insertToc(builder);
+
+ return doc;
+ }
+
+ /**
+ * Find text in file.
+ *
+ * @param path file path
+ * @param expression expression for text search
+ * @throws IOException exception for reading file
+ */
+ static void findTextInFile(final String path, final String expression) throws IOException {
+ BufferedReader sr = new BufferedReader(new FileReader(path));
+ try {
+ String line = sr.readLine();
+ while (line != null) {
+ if (line.isEmpty()) {
+ line = sr.readLine();
+ continue;
+ }
+
+ if (line.contains(expression)) {
+ System.out.println(line);
+ break;
+ } else {
+ line = sr.readLine();
+ if (line == null)
+ {
+ Assert.fail();
+ break;
+ }
+ }
+ }
+ } finally {
+ if (sr != null) {
+ sr.close();
+ }
+ }
+ }
+
+ /**
+ * Create new document template for reporting engine.
+ *
+ * @param templateText template text
+ * @throws Exception exception for creating new document
+ */
+ static Document createSimpleDocument(final String templateText) throws Exception {
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ builder.write(templateText);
+
+ return doc;
+ }
+
+ /**
+ * Create new document with textbox shape and some query.
+ *
+ * @param templateText template text
+ * @param shapeType type of shape
+ * @throws Exception exception for creating new document
+ */
+ static Document createTemplateDocumentWithDrawObjects(final String templateText, final int shapeType) throws Exception {
+ final double shapeWidth = 431.5;
+ final double shapeHeight = 431.5;
+
+ Document doc = new Document();
+
+ // Create textbox shape.
+ Shape shape = new Shape(doc, shapeType);
+ shape.setWidth(shapeWidth);
+ shape.setHeight(shapeHeight);
+
+ Paragraph paragraph = new Paragraph(doc);
+ paragraph.appendChild(new Run(doc, templateText));
+
+ // Insert paragraph into the textbox.
+ shape.appendChild(paragraph);
+
+ // Insert textbox into the document.
+ doc.getFirstSection().getBody().getFirstParagraph().appendChild(shape);
+
+ return doc;
+ }
+
+ /**
+ * Compare word documents.
+ *
+ * @param filePathDoc1 First document path
+ * @param filePathDoc2 Second document path
+ * @return Result of compare document
+ * @throws Exception exception for creating new document
+ */
+ static boolean compareDocs(final String filePathDoc1, final String filePathDoc2) throws Exception {
+ Document doc1 = new Document(filePathDoc1);
+ Document doc2 = new Document(filePathDoc2);
+
+ return doc1.getText().equals(doc2.getText());
+
+ }
+
+ /**
+ * Insert run into the current document
+ *
+ * @param doc Current document
+ * @param text Custom text
+ * @param paraIndex Paragraph index
+ */
+ static Run insertNewRun(final Document doc, final String text, final int paraIndex) {
+ Paragraph para = getParagraph(doc, paraIndex);
+
+ Run run = new Run(doc);
+ run.setText(text);
+
+ para.appendChild(run);
+
+ return run;
+ }
+
+ /**
+ * Insert text into the current document.
+ *
+ * @param builder Current document builder
+ * @param textStrings Custom text
+ */
+ static void insertBuilderText(final DocumentBuilder builder, final String[] textStrings) {
+ for (String textString : textStrings) {
+ builder.writeln(textString);
+ }
+ }
+
+ /**
+ * Get paragraph text of the current document.
+ *
+ * @param doc Current document
+ * @param paraIndex Paragraph number from collection
+ */
+ static String getParagraphText(final Document doc, final int paraIndex) {
+ return doc.getFirstSection().getBody().getParagraphs().get(paraIndex).getText();
+ }
+
+ /**
+ * Insert new table in the document.
+ *
+ * @param builder Current document builder
+ * @throws Exception exception for setting width to fit the table contents
+ */
+ static Table insertTable(final DocumentBuilder builder) throws Exception {
+ //Start creating a new table
+ Table table = builder.startTable();
+
+ //Insert Row 1 Cell 1
+ builder.insertCell();
+ builder.write("Date");
+
+ //Set width to fit the table contents
+ table.autoFit(AutoFitBehavior.AUTO_FIT_TO_CONTENTS);
+
+ //Insert Row 1 Cell 2
+ builder.insertCell();
+ builder.write(" ");
+
+ builder.endRow();
+
+ //Insert Row 2 Cell 1
+ builder.insertCell();
+ builder.write("Author");
+
+ //Insert Row 2 Cell 2
+ builder.insertCell();
+ builder.write(" ");
+
+ builder.endRow();
+
+ builder.endTable();
+
+ return table;
+ }
+
+ /**
+ * Insert TOC entries in the document
+ *
+ * @param builder The builder
+ */
+ static void insertToc(final DocumentBuilder builder) {
+ // Creating TOC entries
+ builder.getParagraphFormat().setStyleIdentifier(StyleIdentifier.HEADING_1);
+
+ builder.writeln("Heading 1");
+
+ builder.getParagraphFormat().setStyleIdentifier(StyleIdentifier.HEADING_2);
+
+ builder.writeln("Heading 1.1");
+
+ builder.getParagraphFormat().setStyleIdentifier(StyleIdentifier.HEADING_4);
+
+ builder.writeln("Heading 1.1.1.1");
+
+ builder.getParagraphFormat().setStyleIdentifier(StyleIdentifier.HEADING_5);
+
+ builder.writeln("Heading 1.1.1.1.1");
+
+ builder.getParagraphFormat().setStyleIdentifier(StyleIdentifier.HEADING_9);
+
+ builder.writeln("Heading 1.1.1.1.1.1.1.1.1");
+ }
+
+ /**
+ * Get section text of the current document
+ *
+ * @param doc Current document
+ * @param secIndex Section number from collection
+ * @return current document section text
+ */
+ static String getSectionText(final Document doc, final int secIndex) {
+ return doc.getSections().get(secIndex).getText();
+ }
+
+ /**
+ * Get paragraph of the current document
+ *
+ * @param doc Current document
+ * @param paraIndex Paragraph number from collection
+ * @return current document paragraph
+ */
+ static Paragraph getParagraph(final Document doc, final int paraIndex) {
+ return doc.getFirstSection().getBody().getParagraphs().get(paraIndex);
+ }
+
+ /**
+ * Get paragraph of the current document.
+ *
+ * @param inputStream stream with test image
+ * @return byte array
+ * @throws IOException exception for reading array stream
+ */
+ static byte[] getBytesFromStream(final InputStream inputStream) throws IOException {
+ final int bufferSize = 1024;
+ int len;
+
+ ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
+ byte[] buffer = new byte[bufferSize];
+
+ while ((len = inputStream.read(buffer)) != -1) {
+ byteBuffer.write(buffer, 0, len);
+ }
+ return byteBuffer.toByteArray();
+ }
+
+ /**
+ * Create specific date for tests.
+ *
+ * @return specific date
+ */
+ static Date createDate(int year, int month, int day) {
+ Calendar cal = Calendar.getInstance();
+ cal.set(year, month, day);
+ return cal.getTime();
+ }
+
+ /**
+ * Create specific date for tests.
+ *
+ * @return specific date
+ */
+ static Date createDate(int year, int month, int day, int hours, int minuts, int seconds) {
+ Calendar cal = Calendar.getInstance();
+ cal.set(year, month, day, hours, minuts, seconds);
+ return cal.getTime();
+ }
+
+ /**
+ * Create date without time for tests.
+ *
+ * @return specific date without time
+ */
+ static Date getDateWithoutTimeUsingFormat(Date date)
+ throws ParseException {
+ SimpleDateFormat formatter = new SimpleDateFormat(
+ "dd/MM/yyyy");
+ return formatter.parse(formatter.format(date));
+ }
+
+ /**
+ * Get date base on system configuration.
+ *
+ * @return specific date without time
+ */
+ static LocalDate getLocalDate(Date date)
+ {
+ return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()).toLocalDate();
+ }
+
+ static ArrayList directoryGetFiles(final String dirname, final String filenamePattern) {
+ File dirFile = new File(dirname);
+ Pattern re = Pattern.compile(filenamePattern.replace("*", ".*").replace("?", ".?"));
+ ArrayList dirFiles = new ArrayList<>();
+ for (File file : dirFile.listFiles()) {
+ if (file.isDirectory()) {
+ dirFiles.addAll(directoryGetFiles(file.getPath(), filenamePattern));
+ } else {
+ if (re.matcher(file.getName()).matches()) {
+ dirFiles.add(file.getPath());
+ }
+ }
+ }
+ return dirFiles;
+ }
+
+ /**
+ * Utility function that creates a connection, command,
+ * executes the command and return the result in a DataTable.
+ */
+ static ResultSet executeDataTable(final String commandText) throws Exception {
+ // Loads the driver
+ Class.forName("net.ucanaccess.jdbc.UcanaccessDriver");
+
+ // Open the database connection
+ String connString = "jdbc:ucanaccess://" + getDatabaseDir() + "Northwind.accdb";
+
+ // From Wikipedia: The Sun driver has a known issue with character encoding and Microsoft Access databases
+ // Microsoft Access may use an encoding that is not correctly translated by the driver, leading to the replacement
+ // in strings of, for example, accented characters by question marks
+ //
+ // In this case I have to set CP1252 for the european characters to come through in the data values
+ java.util.Properties props = new java.util.Properties();
+ props.put("charSet", "Cp1252");
+ props.put("UID", "Admin");
+
+ // DSN-less DB connection
+ java.sql.Connection conn = java.sql.DriverManager.getConnection(connString, props);
+
+ // Create and execute a command
+ java.sql.Statement statement = conn.createStatement();
+ return statement.executeQuery(commandText);
+ }
+
+ ///
+ /// Save the document to a stream, immediately re-open it and return the newly opened version
+ ///
+ ///
+ /// Used for testing how document features are preserved after saving/loading
+ ///
+ /// The document we wish to re-open
+ static Document saveOpen(Document doc) throws Exception {
+ ByteArrayOutputStream docStream = new ByteArrayOutputStream();
+ try {
+ doc.save(docStream, new OoxmlSaveOptions(SaveFormat.DOCX));
+ return new Document(new ByteArrayInputStream(docStream.toByteArray()));
+ } finally {
+ if (docStream != null) docStream.close();
+ }
+ }
+
+ static int getListItemCount(NodeCollection paragraphs) {
+ int listItemCount = 0;
+
+ for (Paragraph para : (Iterable) paragraphs) {
+ if (para.getListFormat().isListItem()) {
+ listItemCount++;
+ }
+ }
+
+ return listItemCount;
+ }
+
+ static int getListLevelNumberCount(NodeCollection paragraphs, int listLevelNumber) {
+ int listLevelNumberCount = 0;
+
+ for (Paragraph para : (Iterable) paragraphs) {
+ if (para.getListFormat().getListLevelNumber() == listLevelNumber) {
+ listLevelNumberCount++;
+ }
+ }
+
+ return listLevelNumberCount;
+ }
+
+ static int getFieldsCount(FieldCollection fields, int fieldType) {
+ int fieldsCount = 0;
+
+ for (Field field : fields) {
+ if (field.getType() == fieldType) {
+ fieldsCount++;
+ }
+ }
+
+ return fieldsCount;
+ }
+
+ static Object getField(FieldCollection fields, int fieldType) {
+ for (Field field : fields) {
+ if (field.getType() == fieldType)
+ return field;
+ }
+
+ return null;
+ }
+}
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ExAI.java b/Examples/ApiExamples/Java/src/main/java/Examples/ExAI.java
new file mode 100644
index 00000000..96e078b6
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ExAI.java
@@ -0,0 +1,130 @@
+package Examples;
+
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.words.*;
+import org.testng.annotations.Test;
+
+@Test
+public class ExAI extends ApiExampleBase
+{
+ @Test (enabled = false, description = "This test should be run manually to manage API requests amount")
+ public void aiSummarize() throws Exception
+ {
+ //ExStart:AiSummarize
+ //GistId:72d57eeddb7fb342fd51b26e5fcf9642
+ //ExFor:GoogleAiModel
+ //ExFor:OpenAiModel
+ //ExFor:OpenAiModel.WithOrganization(String)
+ //ExFor:OpenAiModel.WithProject(String)
+ //ExFor:AiModel
+ //ExFor:AiModel.Summarize(Document, SummarizeOptions)
+ //ExFor:AiModel.Summarize(Document[], SummarizeOptions)
+ //ExFor:AiModel.Create(AiModelType)
+ //ExFor:AiModel.WithApiKey(String)
+ //ExFor:AiModelType
+ //ExFor:SummarizeOptions
+ //ExFor:SummarizeOptions.#ctor
+ //ExFor:SummarizeOptions.SummaryLength
+ //ExFor:SummaryLength
+ //ExSummary:Shows how to summarize text using OpenAI and Google models.
+ Document firstDoc = new Document(getMyDir() + "Big document.docx");
+ Document secondDoc = new Document(getMyDir() + "Document.docx");
+
+ String apiKey = System.getenv("API_KEY");
+ // Use OpenAI or Google generative language models.
+ AiModel model = ((OpenAiModel)AiModel.create(AiModelType.GPT_4_O_MINI).withApiKey(apiKey)).withOrganization("Organization").withProject("Project");
+
+ SummarizeOptions options = new SummarizeOptions();
+
+ options.setSummaryLength(SummaryLength.SHORT);
+ Document oneDocumentSummary = model.summarize(firstDoc, options);
+ oneDocumentSummary.save(getArtifactsDir() + "AI.AiSummarize.One.docx");
+
+ options.setSummaryLength(SummaryLength.LONG);
+ Document multiDocumentSummary = model.summarize(new Document[] { firstDoc, secondDoc }, options);
+ multiDocumentSummary.save(getArtifactsDir() + "AI.AiSummarize.Multi.docx");
+ //ExEnd:AiSummarize
+ }
+
+ @Test (enabled = false, description = "This test should be run manually to manage API requests amount")
+ public void aiTranslate() throws Exception
+ {
+ //ExStart:AiTranslate
+ //GistId:93fefe5344a8337b931d0fed5c028225
+ //ExFor:AiModel.Translate(Document, AI.Language)
+ //ExFor:AI.Language
+ //ExSummary:Shows how to translate text using Google models.
+ Document doc = new Document(getMyDir() + "Document.docx");
+
+ String apiKey = System.getenv("API_KEY");
+ // Use Google generative language models.
+ AiModel model = AiModel.create(AiModelType.GEMINI_15_FLASH).withApiKey(apiKey);
+
+ Document translatedDoc = model.translate(doc, Language.ARABIC);
+ translatedDoc.save(getArtifactsDir() + "AI.AiTranslate.docx");
+ //ExEnd:AiTranslate
+ }
+
+ @Test (enabled = false, description = "This test should be run manually to manage API requests amount")
+ public void aiGrammar() throws Exception
+ {
+ //ExStart:AiGrammar
+ //GistId:c012c14781944ce4cc5e31f35b08060a
+ //ExFor:AiModel.CheckGrammar(Document, CheckGrammarOptions)
+ //ExFor:CheckGrammarOptions
+ //ExSummary:Shows how to check the grammar of a document.
+ Document doc = new Document(getMyDir() + "Big document.docx");
+
+ String apiKey = System.getenv("API_KEY");
+ // Use OpenAI generative language models.
+ AiModel model = AiModel.create(AiModelType.GPT_4_O_MINI).withApiKey(apiKey);
+
+ CheckGrammarOptions grammarOptions = new CheckGrammarOptions();
+ grammarOptions.setImproveStylistics(true);
+
+ Document proofedDoc = model.checkGrammar(doc, grammarOptions);
+ proofedDoc.save(getArtifactsDir() + "AI.AiGrammar.docx");
+ //ExEnd:AiGrammar
+ }
+
+ //ExStart:SelfHostedModel
+ //GistId:2af5a850f2e0a83c3b114274a838c092
+ //ExFor:OpenAiModel
+ //ExSummary:Shows how to use self-hosted AI model based on OpenAiModel.
+ @Test (enabled = false, description = "This test should be run manually when you are configuring your model") //ExSkip
+ public void selfHostedModel() throws Exception
+ {
+ Document doc = new Document(getMyDir() + "Big document.docx");
+
+ String apiKey = System.getenv("API_KEY");
+ // Use OpenAI generative language models.
+ AiModel model = new CustomAiModel().withApiKey(apiKey);
+
+ Document translatedDoc = model.translate(doc, Language.RUSSIAN);
+ translatedDoc.save(getArtifactsDir() + "AI.SelfHostedModel.docx");
+ }
+
+ ///
+ /// Custom self-hosted AI model.
+ ///
+ static class CustomAiModel extends OpenAiModel
+ {
+ ///
+ /// Gets custom URL of the model.
+ ///
+ protected /*override*/ String getUrl() { return "https://localhost/"; }
+
+ ///
+ /// Gets model name.
+ ///
+ protected /*override*/ String getName() { return "my-model-24b"; }
+ }
+ //ExEnd:SelfHostedModel
+}
+
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ExAbsolutePositionTab.java b/Examples/ApiExamples/Java/src/main/java/Examples/ExAbsolutePositionTab.java
new file mode 100644
index 00000000..d78acfc7
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ExAbsolutePositionTab.java
@@ -0,0 +1,93 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.words.*;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+@Test
+public class ExAbsolutePositionTab extends ApiExampleBase {
+ //ExStart
+ //ExFor:AbsolutePositionTab
+ //ExFor:AbsolutePositionTab.Accept(DocumentVisitor)
+ //ExFor:DocumentVisitor.VisitAbsolutePositionTab
+ //ExFor:Body.Accept(DocumentVisitor)
+ //ExFor:Body.AcceptStart(DocumentVisitor)
+ //ExFor:Body.AcceptEnd(DocumentVisitor)
+ //ExFor:VisitorAction
+ //ExSummary:Shows how to process absolute position tab characters with a document visitor.
+ @Test //ExSkip
+ public void documentToTxt() throws Exception {
+ Document doc = new Document(getMyDir() + "Absolute position tab.docx");
+
+ // Extract the text contents of our document by accepting this custom document visitor.
+ DocTextExtractor myDocTextExtractor = new DocTextExtractor();
+ Section fisrtSection = doc.getFirstSection();
+ fisrtSection.getBody().accept(myDocTextExtractor);
+ // Visit only start of the document body.
+ fisrtSection.getBody().acceptStart(myDocTextExtractor);
+ // Visit only end of the document body.
+ fisrtSection.getBody().acceptEnd(myDocTextExtractor);
+
+ // The absolute position tab, which has no equivalent in string form, has been explicitly converted to a tab character.
+ Assert.assertEquals("Before AbsolutePositionTab\tAfter AbsolutePositionTab", myDocTextExtractor.getText());
+
+ // An AbsolutePositionTab can accept a DocumentVisitor by itself too.
+ AbsolutePositionTab absPositionTab = (AbsolutePositionTab) doc.getFirstSection().getBody().getFirstParagraph().getChild(NodeType.SPECIAL_CHAR, 0, true);
+
+ myDocTextExtractor = new DocTextExtractor();
+ absPositionTab.accept(myDocTextExtractor);
+
+ Assert.assertEquals("\t", myDocTextExtractor.getText());
+ }
+
+ ///
+ /// Collects the text contents of all runs in the visited document. Replaces all absolute tab characters with ordinary tabs.
+ ///
+ public static class DocTextExtractor extends DocumentVisitor {
+ public DocTextExtractor() {
+ mBuilder = new StringBuilder();
+ }
+
+ ///
+ /// Called when a Run node is encountered in the document.
+ ///
+ public int visitRun(final Run run) {
+ appendText(run.getText());
+ return VisitorAction.CONTINUE;
+ }
+
+ ///
+ /// Called when an AbsolutePositionTab node is encountered in the document.
+ ///
+ public int visitAbsolutePositionTab(final AbsolutePositionTab tab) {
+ mBuilder.append("\t");
+
+ return VisitorAction.CONTINUE;
+ }
+
+ ///
+ /// Adds text to the current output. Honors the enabled/disabled output flag.
+ ///
+ public void appendText(final String text) {
+ mBuilder.append(text);
+ }
+
+ ///
+ /// Plain text of the document that was accumulated by the visitor.
+ ///
+ public String getText() {
+ return mBuilder.toString();
+ }
+
+ private final StringBuilder mBuilder;
+ }
+ //ExEnd
+}
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ExBookmarks.java b/Examples/ApiExamples/Java/src/main/java/Examples/ExBookmarks.java
new file mode 100644
index 00000000..7fdb2303
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ExBookmarks.java
@@ -0,0 +1,247 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.words.*;
+import org.apache.commons.collections4.IterableUtils;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.text.MessageFormat;
+import java.util.Collections;
+import java.util.Iterator;
+
+
+@Test
+public class ExBookmarks extends ApiExampleBase {
+ @Test
+ public void insert() throws Exception {
+ //ExStart
+ //ExFor:Bookmark.Name
+ //ExSummary:Shows how to insert a bookmark.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // A valid bookmark has a name, a BookmarkStart, and a BookmarkEnd node.
+ // Any whitespace in the names of bookmarks will be converted to underscores if we open the saved document with Microsoft Word.
+ // If we highlight the bookmark's name in Microsoft Word via Insert -> Links -> Bookmark, and press "Go To",
+ // the cursor will jump to the text enclosed between the BookmarkStart and BookmarkEnd nodes.
+ builder.startBookmark("My Bookmark");
+ builder.write("Contents of MyBookmark.");
+ builder.endBookmark("My Bookmark");
+
+ // Bookmarks are stored in this collection.
+ Assert.assertEquals("My Bookmark", doc.getRange().getBookmarks().get(0).getName());
+
+ doc.save(getArtifactsDir() + "Bookmarks.Insert.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Bookmarks.Insert.docx");
+
+ Assert.assertEquals("My Bookmark", doc.getRange().getBookmarks().get(0).getName());
+ }
+
+ //ExStart
+ //ExFor:Bookmark
+ //ExFor:Bookmark.Name
+ //ExFor:Bookmark.Text
+ //ExFor:Bookmark.BookmarkStart
+ //ExFor:Bookmark.BookmarkEnd
+ //ExFor:BookmarkStart
+ //ExFor:BookmarkStart.#ctor
+ //ExFor:BookmarkEnd
+ //ExFor:BookmarkEnd.#ctor
+ //ExFor:BookmarkStart.Accept(DocumentVisitor)
+ //ExFor:BookmarkEnd.Accept(DocumentVisitor)
+ //ExFor:BookmarkStart.Bookmark
+ //ExFor:BookmarkStart.GetText
+ //ExFor:BookmarkStart.Name
+ //ExFor:BookmarkEnd.Name
+ //ExFor:BookmarkCollection
+ //ExFor:BookmarkCollection.Item(Int32)
+ //ExFor:BookmarkCollection.Item(String)
+ //ExFor:BookmarkCollection.GetEnumerator
+ //ExFor:Range.Bookmarks
+ //ExFor:DocumentVisitor.VisitBookmarkStart
+ //ExFor:DocumentVisitor.VisitBookmarkEnd
+ //ExSummary:Shows how to add bookmarks and update their contents.
+ @Test //ExSkip
+ public void createUpdateAndPrintBookmarks() throws Exception {
+ // Create a document with three bookmarks, then use a custom document visitor implementation to print their contents.
+ Document doc = createDocumentWithBookmarks(3);
+ BookmarkCollection bookmarks = doc.getRange().getBookmarks();
+ Assert.assertEquals(3, bookmarks.getCount()); //ExSkip
+
+ printAllBookmarkInfo(bookmarks);
+
+ // Bookmarks can be accessed in the bookmark collection by index or name, and their names can be updated.
+ bookmarks.get(0).setName("{bookmarks[0].Name}_NewName");
+ bookmarks.get("MyBookmark_2").setText("Updated text contents of {bookmarks[1].Name}");
+
+ // Print all bookmarks again to see updated values.
+ printAllBookmarkInfo(bookmarks);
+ }
+
+ ///
+ /// Create a document with a given number of bookmarks.
+ ///
+ private static Document createDocumentWithBookmarks(int numberOfBookmarks) throws Exception {
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ for (int i = 1; i <= numberOfBookmarks; i++) {
+ String bookmarkName = "MyBookmark_" + i;
+
+ builder.write("Text before bookmark.");
+ builder.startBookmark(bookmarkName);
+ builder.write(MessageFormat.format("Text inside {0}.", bookmarkName));
+ builder.endBookmark(bookmarkName);
+ builder.writeln("Text after bookmark.");
+ }
+
+ return doc;
+ }
+
+ ///
+ /// Use an iterator and a visitor to print info of every bookmark in the collection.
+ ///
+ private static void printAllBookmarkInfo(BookmarkCollection bookmarks) throws Exception {
+ BookmarkInfoPrinter bookmarkVisitor = new BookmarkInfoPrinter();
+
+ // Get each bookmark in the collection to accept a visitor that will print its contents.
+ Iterator enumerator = bookmarks.iterator();
+
+ while (enumerator.hasNext()) {
+ Bookmark currentBookmark = enumerator.next();
+
+ if (currentBookmark != null) {
+ currentBookmark.getBookmarkStart().accept(bookmarkVisitor);
+ currentBookmark.getBookmarkEnd().accept(bookmarkVisitor);
+
+ System.out.println(currentBookmark.getBookmarkStart().getText());
+ }
+ }
+ }
+
+ ///
+ /// Prints contents of every visited bookmark to the console.
+ ///
+ public static class BookmarkInfoPrinter extends DocumentVisitor {
+ public int visitBookmarkStart(BookmarkStart bookmarkStart) throws Exception {
+ System.out.println(MessageFormat.format("BookmarkStart name: \"{0}\", Content: \"{1}\"", bookmarkStart.getName(),
+ bookmarkStart.getBookmark().getText()));
+ return VisitorAction.CONTINUE;
+ }
+
+ public int visitBookmarkEnd(BookmarkEnd bookmarkEnd) {
+ System.out.println(MessageFormat.format("BookmarkEnd name: \"{0}\"", bookmarkEnd.getName()));
+ return VisitorAction.CONTINUE;
+ }
+ }
+ //ExEnd
+
+ @Test
+ public void tableColumnBookmarks() throws Exception {
+ //ExStart
+ //ExFor:Bookmark.IsColumn
+ //ExFor:Bookmark.FirstColumn
+ //ExFor:Bookmark.LastColumn
+ //ExSummary:Shows how to get information about table column bookmarks.
+ Document doc = new Document(getMyDir() + "Table column bookmarks.doc");
+ for (Bookmark bookmark : doc.getRange().getBookmarks()) {
+ // If a bookmark encloses columns of a table, it is a table column bookmark, and its IsColumn flag set to true.
+ System.out.println(MessageFormat.format("Bookmark: {0}{1}", bookmark.getName(), bookmark.isColumn() ? " (Column)" : ""));
+ if (bookmark.isColumn()) {
+ Row row = (Row) bookmark.getBookmarkStart().getAncestor(NodeType.ROW);
+ if (row != null && bookmark.getFirstColumn() < row.getCells().getCount()) {
+ // Print the contents of the first and last columns enclosed by the bookmark.
+ System.out.println(row.getCells().get(bookmark.getFirstColumn()).getText().trim());
+ System.out.println(row.getCells().get(bookmark.getLastColumn()).getText().trim());
+ }
+ }
+ }
+ //ExEnd
+
+ doc = DocumentHelper.saveOpen(doc);
+
+ Bookmark firstTableColumnBookmark = doc.getRange().getBookmarks().get("FirstTableColumnBookmark");
+ Bookmark secondTableColumnBookmark = doc.getRange().getBookmarks().get("SecondTableColumnBookmark");
+
+ Assert.assertTrue(firstTableColumnBookmark.isColumn());
+ Assert.assertEquals(firstTableColumnBookmark.getFirstColumn(), 1);
+ Assert.assertEquals(firstTableColumnBookmark.getLastColumn(), 3);
+
+ Assert.assertTrue(secondTableColumnBookmark.isColumn());
+ Assert.assertEquals(secondTableColumnBookmark.getFirstColumn(), 0);
+ Assert.assertEquals(secondTableColumnBookmark.getLastColumn(), 3);
+ }
+
+ @Test
+ public void remove() throws Exception {
+ //ExStart
+ //ExFor:BookmarkCollection.Clear
+ //ExFor:BookmarkCollection.Count
+ //ExFor:BookmarkCollection.Remove(Bookmark)
+ //ExFor:BookmarkCollection.Remove(String)
+ //ExFor:BookmarkCollection.RemoveAt
+ //ExFor:Bookmark.Remove
+ //ExSummary:Shows how to remove bookmarks from a document.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert five bookmarks with text inside their boundaries.
+ for (int i = 1; i <= 5; i++) {
+ String bookmarkName = "MyBookmark_" + i;
+
+ builder.startBookmark(bookmarkName);
+ builder.write(MessageFormat.format("Text inside {0}.", bookmarkName));
+ builder.endBookmark(bookmarkName);
+ builder.insertBreak(BreakType.PARAGRAPH_BREAK);
+ }
+
+ // This collection stores bookmarks.
+ BookmarkCollection bookmarks = doc.getRange().getBookmarks();
+
+ Assert.assertEquals(5, bookmarks.getCount());
+
+ // There are several ways of removing bookmarks.
+ // 1 - Calling the bookmark's Remove method:
+ bookmarks.get("MyBookmark_1").remove();
+
+ Assert.assertFalse(IterableUtils.matchesAny(bookmarks, b -> b.getName() == "MyBookmark_1"));
+
+ // 2 - Passing the bookmark to the collection's Remove method:
+ Bookmark bookmark = doc.getRange().getBookmarks().get(0);
+ doc.getRange().getBookmarks().remove(bookmark);
+
+ Assert.assertFalse(IterableUtils.matchesAny(bookmarks, b -> b.getName() == "MyBookmark_2"));
+
+ // 3 - Removing a bookmark from the collection by name:
+ doc.getRange().getBookmarks().remove("MyBookmark_3");
+
+ Assert.assertFalse(IterableUtils.matchesAny(bookmarks, b -> b.getName() == "MyBookmark_3"));
+
+ // 4 - Removing a bookmark at an index in the bookmark collection:
+ doc.getRange().getBookmarks().removeAt(0);
+
+ Assert.assertFalse(IterableUtils.matchesAny(bookmarks, b -> b.getName() == "MyBookmark_4"));
+
+ // We can clear the entire bookmark collection.
+ bookmarks.clear();
+
+ // The text that was inside the bookmarks is still present in the document.
+ Assert.assertEquals(bookmarks.getCount(), 0);
+ Assert.assertEquals("Text inside MyBookmark_1.\r" +
+ "Text inside MyBookmark_2.\r" +
+ "Text inside MyBookmark_3.\r" +
+ "Text inside MyBookmark_4.\r" +
+ "Text inside MyBookmark_5.", doc.getText().trim());
+ //ExEnd
+ }
+}
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ExBookmarksOutlineLevelCollection.java b/Examples/ApiExamples/Java/src/main/java/Examples/ExBookmarksOutlineLevelCollection.java
new file mode 100644
index 00000000..6baa3034
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ExBookmarksOutlineLevelCollection.java
@@ -0,0 +1,100 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.pdf.facades.Bookmarks;
+import com.aspose.pdf.facades.PdfBookmarkEditor;
+import com.aspose.words.BookmarksOutlineLevelCollection;
+import com.aspose.words.Document;
+import com.aspose.words.DocumentBuilder;
+import com.aspose.words.PdfSaveOptions;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+
+@Test
+public class ExBookmarksOutlineLevelCollection extends ApiExampleBase {
+ @Test
+ public void bookmarkLevels() throws Exception {
+ //ExStart
+ //ExFor:BookmarksOutlineLevelCollection
+ //ExFor:BookmarksOutlineLevelCollection.Add(String, Int32)
+ //ExFor:BookmarksOutlineLevelCollection.Clear
+ //ExFor:BookmarksOutlineLevelCollection.Contains(String)
+ //ExFor:BookmarksOutlineLevelCollection.Count
+ //ExFor:BookmarksOutlineLevelCollection.IndexOfKey(String)
+ //ExFor:BookmarksOutlineLevelCollection.Item(Int32)
+ //ExFor:BookmarksOutlineLevelCollection.Item(String)
+ //ExFor:BookmarksOutlineLevelCollection.Remove(String)
+ //ExFor:BookmarksOutlineLevelCollection.RemoveAt(Int32)
+ //ExFor:OutlineOptions.BookmarksOutlineLevels
+ //ExSummary:Shows how to set outline levels for bookmarks.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert a bookmark with another bookmark nested inside it.
+ builder.startBookmark("Bookmark 1");
+ builder.writeln("Text inside Bookmark 1.");
+
+ builder.startBookmark("Bookmark 2");
+ builder.writeln("Text inside Bookmark 1 and 2.");
+ builder.endBookmark("Bookmark 2");
+
+ builder.writeln("Text inside Bookmark 1.");
+ builder.endBookmark("Bookmark 1");
+
+ // Insert another bookmark.
+ builder.startBookmark("Bookmark 3");
+ builder.writeln("Text inside Bookmark 3.");
+ builder.endBookmark("Bookmark 3");
+
+ // When saving to .pdf, bookmarks can be accessed via a drop-down menu and used as anchors by most readers.
+ // Bookmarks can also have numeric values for outline levels,
+ // enabling lower level outline entries to hide higher-level child entries when collapsed in the reader.
+ PdfSaveOptions pdfSaveOptions = new PdfSaveOptions();
+ BookmarksOutlineLevelCollection outlineLevels = pdfSaveOptions.getOutlineOptions().getBookmarksOutlineLevels();
+
+ outlineLevels.add("Bookmark 1", 1);
+ outlineLevels.add("Bookmark 2", 2);
+ outlineLevels.add("Bookmark 3", 3);
+
+ Assert.assertEquals(outlineLevels.getCount(), 3);
+ Assert.assertTrue(outlineLevels.contains("Bookmark 1"));
+ Assert.assertEquals(outlineLevels.get(0), 1);
+ Assert.assertEquals(outlineLevels.get("Bookmark 2"), 2);
+ Assert.assertEquals(outlineLevels.indexOfKey("Bookmark 3"), 2);
+
+ // We can remove two elements so that only the outline level designation for "Bookmark 1" is left.
+ outlineLevels.removeAt(2);
+ outlineLevels.remove("Bookmark 2");
+
+ // There are nine outline levels. Their numbering will be optimized during the save operation.
+ // In this case, levels "5" and "9" will become "2" and "3".
+ outlineLevels.add("Bookmark 2", 5);
+ outlineLevels.add("Bookmark 3", 9);
+
+ doc.save(getArtifactsDir() + "BookmarksOutlineLevelCollection.BookmarkLevels.pdf", pdfSaveOptions);
+
+ // Emptying this collection will preserve the bookmarks and put them all on the same outline level.
+ outlineLevels.clear();
+ //ExEnd
+
+ PdfBookmarkEditor bookmarkEditor = new PdfBookmarkEditor();
+ bookmarkEditor.bindPdf(getArtifactsDir() + "BookmarksOutlineLevelCollection.BookmarkLevels.pdf");
+
+ Bookmarks bookmarks = bookmarkEditor.extractBookmarks();
+
+ Assert.assertEquals(3, bookmarks.stream().count());
+ Assert.assertEquals("Bookmark 1", bookmarks.get(0).getTitle());
+ Assert.assertEquals("Bookmark 2", bookmarks.get(1).getTitle());
+ Assert.assertEquals("Bookmark 3", bookmarks.get(2).getTitle());
+
+ bookmarkEditor.close();
+ }
+}
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ExBorder.java b/Examples/ApiExamples/Java/src/main/java/Examples/ExBorder.java
new file mode 100644
index 00000000..dad6f49a
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ExBorder.java
@@ -0,0 +1,267 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.words.*;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.awt.*;
+import java.text.MessageFormat;
+
+public class ExBorder extends ApiExampleBase {
+ @Test
+ public void fontBorder() throws Exception {
+ //ExStart
+ //ExFor:Border
+ //ExFor:Border.Color
+ //ExFor:Border.LineWidth
+ //ExFor:Border.LineStyle
+ //ExFor:Font.Border
+ //ExFor:LineStyle
+ //ExFor:Font
+ //ExFor:DocumentBuilder.Font
+ //ExFor:DocumentBuilder.Write(String)
+ //ExSummary:Shows how to insert a string surrounded by a border into a document.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ builder.getFont().getBorder().setColor(Color.GREEN);
+ builder.getFont().getBorder().setLineWidth(2.5);
+ builder.getFont().getBorder().setLineStyle(LineStyle.DASH_DOT_STROKER);
+
+ builder.write("Text surrounded by green border.");
+
+ doc.save(getArtifactsDir() + "Border.FontBorder.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Border.FontBorder.docx");
+ Border border = doc.getFirstSection().getBody().getFirstParagraph().getRuns().get(0).getFont().getBorder();
+
+ Assert.assertEquals(Color.GREEN.getRGB(), border.getColor().getRGB());
+ Assert.assertEquals(2.5d, border.getLineWidth());
+ Assert.assertEquals(LineStyle.DASH_DOT_STROKER, border.getLineStyle());
+ }
+
+ @Test
+ public void paragraphTopBorder() throws Exception {
+ //ExStart
+ //ExFor:BorderCollection
+ //ExFor:Border.ThemeColor
+ //ExFor:Border.TintAndShade
+ //ExFor:Border
+ //ExFor:BorderType
+ //ExFor:ParagraphFormat.Borders
+ //ExSummary:Shows how to insert a paragraph with a top border.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Border topBorder = builder.getParagraphFormat().getBorders().getByBorderType(BorderType.TOP);
+ topBorder.setLineWidth(4.0d);
+ topBorder.setLineStyle(LineStyle.DASH_SMALL_GAP);
+ // Set ThemeColor only when LineWidth or LineStyle setted.
+ topBorder.setThemeColor(ThemeColor.ACCENT_1);
+ topBorder.setTintAndShade(0.25d);
+
+ builder.writeln("Text with a top border.");
+
+ doc.save(getArtifactsDir() + "Border.ParagraphTopBorder.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Border.ParagraphTopBorder.docx");
+ Border border = doc.getFirstSection().getBody().getFirstParagraph().getParagraphFormat().getBorders().getByBorderType(BorderType.TOP);
+
+ Assert.assertEquals(4.0d, border.getLineWidth());
+ Assert.assertEquals(LineStyle.DASH_SMALL_GAP, border.getLineStyle());
+ Assert.assertEquals(ThemeColor.ACCENT_1, border.getThemeColor());
+ Assert.assertEquals(0.25d, border.getTintAndShade(), 0.01);
+ }
+
+ @Test
+ public void clearFormatting() throws Exception {
+ //ExStart
+ //ExFor:Border.ClearFormatting
+ //ExFor:Border.IsVisible
+ //ExSummary:Shows how to remove borders from a paragraph.
+ Document doc = new Document(getMyDir() + "Borders.docx");
+
+ // Each paragraph has an individual set of borders.
+ // We can access the settings for the appearance of these borders via the paragraph format object.
+ BorderCollection borders = doc.getFirstSection().getBody().getFirstParagraph().getParagraphFormat().getBorders();
+
+ Assert.assertEquals(Color.RED.getRGB(), borders.get(0).getColor().getRGB());
+ Assert.assertEquals(3.0d, borders.get(0).getLineWidth());
+ Assert.assertEquals(LineStyle.SINGLE, borders.get(0).getLineStyle());
+ Assert.assertTrue(borders.get(0).isVisible());
+
+ // We can remove a border at once by running the ClearFormatting method.
+ // Running this method on every border of a paragraph will remove all its borders.
+ for (Border border : borders)
+ border.clearFormatting();
+
+ Assert.assertEquals(0, borders.get(0).getColor().getRGB());
+ Assert.assertEquals(0.0d, borders.get(0).getLineWidth());
+ Assert.assertEquals(LineStyle.NONE, borders.get(0).getLineStyle());
+ Assert.assertFalse(borders.get(0).isVisible());
+
+ doc.save(getArtifactsDir() + "Border.ClearFormatting.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Border.ClearFormatting.docx");
+
+ for (Border testBorder : doc.getFirstSection().getBody().getFirstParagraph().getParagraphFormat().getBorders()) {
+ Assert.assertEquals(0, testBorder.getColor().getRGB());
+ Assert.assertEquals(0.0d, testBorder.getLineWidth());
+ Assert.assertEquals(LineStyle.NONE, testBorder.getLineStyle());
+ }
+ }
+
+ @Test
+ public void sharedElements() throws Exception {
+ //ExStart
+ //ExFor:Border.Equals(Object)
+ //ExFor:Border.Equals(Border)
+ //ExFor:Border.GetHashCode
+ //ExFor:BorderCollection.Count
+ //ExFor:BorderCollection.Equals(BorderCollection)
+ //ExFor:BorderCollection.Item(Int32)
+ //ExSummary:Shows how border collections can share elements.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ builder.writeln("Paragraph 1.");
+ builder.write("Paragraph 2.");
+
+ // Since we used the same border configuration while creating
+ // these paragraphs, their border collections share the same elements.
+ BorderCollection firstParagraphBorders = doc.getFirstSection().getBody().getFirstParagraph().getParagraphFormat().getBorders();
+ BorderCollection secondParagraphBorders = builder.getCurrentParagraph().getParagraphFormat().getBorders();
+ Assert.assertEquals(6, firstParagraphBorders.getCount()); //ExSkip
+
+ for (int i = 0; i < firstParagraphBorders.getCount(); i++) {
+ Assert.assertTrue(firstParagraphBorders.get(i).equals(secondParagraphBorders.get(i)));
+ Assert.assertEquals(firstParagraphBorders.get(i).hashCode(), secondParagraphBorders.get(i).hashCode());
+ Assert.assertFalse(firstParagraphBorders.get(i).isVisible());
+ }
+
+ for (Border border : secondParagraphBorders)
+ border.setLineStyle(LineStyle.DOT_DASH);
+
+ // After changing the line style of the borders in just the second paragraph,
+ // the border collections no longer share the same elements.
+ for (int i = 0; i < firstParagraphBorders.getCount(); i++) {
+ Assert.assertFalse(firstParagraphBorders.get(i).equals(secondParagraphBorders.get(i)));
+ Assert.assertNotEquals(firstParagraphBorders.get(i).hashCode(), secondParagraphBorders.get(i).hashCode());
+
+ // Changing the appearance of an empty border makes it visible.
+ Assert.assertTrue(secondParagraphBorders.get(i).isVisible());
+ }
+
+ doc.save(getArtifactsDir() + "Border.SharedElements.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Border.SharedElements.docx");
+ ParagraphCollection paragraphs = doc.getFirstSection().getBody().getParagraphs();
+
+ for (Border testBorder : paragraphs.get(0).getParagraphFormat().getBorders())
+ Assert.assertEquals(LineStyle.NONE, testBorder.getLineStyle());
+
+ for (Border testBorder : paragraphs.get(1).getParagraphFormat().getBorders())
+ Assert.assertEquals(LineStyle.DOT_DASH, testBorder.getLineStyle());
+ }
+
+ @Test
+ public void horizontalBorders() throws Exception {
+ //ExStart
+ //ExFor:BorderCollection.Horizontal
+ //ExSummary:Shows how to apply settings to horizontal borders to a paragraph's format.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Create a red horizontal border for the paragraph. Any paragraphs created afterwards will inherit these border settings.
+ BorderCollection borders = doc.getFirstSection().getBody().getFirstParagraph().getParagraphFormat().getBorders();
+ borders.getHorizontal().setColor(Color.RED);
+ borders.getHorizontal().setLineStyle(LineStyle.DASH_SMALL_GAP);
+ borders.getHorizontal().setLineWidth(3.0);
+
+ // Write text to the document without creating a new paragraph afterward.
+ // Since there is no paragraph underneath, the horizontal border will not be visible.
+ builder.write("Paragraph above horizontal border.");
+
+ // Once we add a second paragraph, the border of the first paragraph will become visible.
+ builder.insertParagraph();
+ builder.write("Paragraph below horizontal border.");
+
+ doc.save(getArtifactsDir() + "Border.HorizontalBorders.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Border.HorizontalBorders.docx");
+ ParagraphCollection paragraphs = doc.getFirstSection().getBody().getParagraphs();
+
+ Assert.assertEquals(LineStyle.DASH_SMALL_GAP, paragraphs.get(0).getParagraphFormat().getBorders().getByBorderType(BorderType.HORIZONTAL).getLineStyle());
+ Assert.assertEquals(LineStyle.DASH_SMALL_GAP, paragraphs.get(1).getParagraphFormat().getBorders().getByBorderType(BorderType.HORIZONTAL).getLineStyle());
+ }
+
+ @Test
+ public void verticalBorders() throws Exception {
+ //ExStart
+ //ExFor:BorderCollection.Horizontal
+ //ExFor:BorderCollection.Vertical
+ //ExFor:Cell.LastParagraph
+ //ExSummary:Shows how to apply settings to vertical borders to a table row's format.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Create a table with red and blue inner borders.
+ Table table = builder.startTable();
+
+ for (int i = 0; i < 3; i++) {
+ builder.insertCell();
+ builder.write(MessageFormat.format("Row {0}, Column 1", i + 1));
+ builder.insertCell();
+ builder.write(MessageFormat.format("Row {0}, Column 2", i + 1));
+
+ Row row = builder.endRow();
+ BorderCollection borders = row.getRowFormat().getBorders();
+
+ // Adjust the appearance of borders that will appear between rows.
+ borders.getHorizontal().setColor(Color.RED);
+ borders.getHorizontal().setLineStyle(LineStyle.DOT);
+ borders.getHorizontal().setLineWidth(2.0d);
+
+ // Adjust the appearance of borders that will appear between cells.
+ borders.getVertical().setColor(Color.BLUE);
+ borders.getVertical().setLineStyle(LineStyle.DOT);
+ borders.getVertical().setLineWidth(2.0d);
+ }
+
+ // A row format, and a cell's inner paragraph use different border settings.
+ Border border = table.getFirstRow().getFirstCell().getLastParagraph().getParagraphFormat().getBorders().getVertical();
+
+ Assert.assertEquals(0, border.getColor().getRGB());
+ Assert.assertEquals(0.0d, border.getLineWidth());
+ Assert.assertEquals(LineStyle.NONE, border.getLineStyle());
+
+ doc.save(getArtifactsDir() + "Border.VerticalBorders.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Border.VerticalBorders.docx");
+ table = doc.getFirstSection().getBody().getTables().get(0);
+
+ for (Row row : (Iterable) table.getChildNodes(NodeType.ROW, true)) {
+ Assert.assertEquals(Color.RED.getRGB(), row.getRowFormat().getBorders().getHorizontal().getColor().getRGB());
+ Assert.assertEquals(LineStyle.DOT, row.getRowFormat().getBorders().getHorizontal().getLineStyle());
+ Assert.assertEquals(2.0d, row.getRowFormat().getBorders().getHorizontal().getLineWidth());
+
+ Assert.assertEquals(Color.BLUE.getRGB(), row.getRowFormat().getBorders().getVertical().getColor().getRGB());
+ Assert.assertEquals(LineStyle.DOT, row.getRowFormat().getBorders().getVertical().getLineStyle());
+ Assert.assertEquals(2.0d, row.getRowFormat().getBorders().getVertical().getLineWidth());
+ }
+ }
+}
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ExBorderCollection.java b/Examples/ApiExamples/Java/src/main/java/Examples/ExBorderCollection.java
new file mode 100644
index 00000000..d2185a28
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ExBorderCollection.java
@@ -0,0 +1,89 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.words.*;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.awt.*;
+import java.util.Iterator;
+
+public class ExBorderCollection extends ApiExampleBase {
+ @Test
+ public void getBordersEnumerator() throws Exception {
+ //ExStart
+ //ExFor:BorderCollection.GetEnumerator
+ //ExSummary:Shows how to iterate over and edit all of the borders in a paragraph format object.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Configure the builder's paragraph format settings to create a green wave border on all sides.
+ BorderCollection borders = builder.getParagraphFormat().getBorders();
+
+ Iterator enumerator = borders.iterator();
+ while (enumerator.hasNext()) {
+ Border border = enumerator.next();
+ border.setColor(Color.green);
+ border.setLineStyle(LineStyle.WAVE);
+ border.setLineWidth(3.0);
+ }
+
+ // Insert a paragraph. Our border settings will determine the appearance of its border.
+ builder.writeln("Hello world!");
+
+ doc.save(getArtifactsDir() + "BorderCollection.GetBordersEnumerator.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "BorderCollection.GetBordersEnumerator.docx");
+
+ for (Border border : doc.getFirstSection().getBody().getFirstParagraph().getParagraphFormat().getBorders()) {
+ Assert.assertEquals(Color.green.getRGB(), border.getColor().getRGB());
+ Assert.assertEquals(LineStyle.WAVE, border.getLineStyle());
+ Assert.assertEquals(3.0d, border.getLineWidth());
+ }
+ }
+
+ @Test
+ public void removeAllBorders() throws Exception {
+ //ExStart
+ //ExFor:BorderCollection.ClearFormatting
+ //ExSummary:Shows how to remove all borders from all paragraphs in a document.
+ Document doc = new Document(getMyDir() + "Borders.docx");
+
+ // The first paragraph of this document has visible borders with these settings.
+ BorderCollection firstParagraphBorders = doc.getFirstSection().getBody().getFirstParagraph().getParagraphFormat().getBorders();
+
+ Assert.assertEquals(Color.RED.getRGB(), firstParagraphBorders.getColor().getRGB());
+ Assert.assertEquals(LineStyle.SINGLE, firstParagraphBorders.getLineStyle());
+ Assert.assertEquals(3.0d, firstParagraphBorders.getLineWidth());
+
+ // Use the "ClearFormatting" method on each paragraph to remove all borders.
+ for (Paragraph paragraph : doc.getFirstSection().getBody().getParagraphs()) {
+ paragraph.getParagraphFormat().getBorders().clearFormatting();
+
+ for (Border border : paragraph.getParagraphFormat().getBorders()) {
+ Assert.assertEquals(0, border.getColor().getRGB());
+ Assert.assertEquals(LineStyle.NONE, border.getLineStyle());
+ Assert.assertEquals(0.0d, border.getLineWidth());
+ }
+ }
+
+ doc.save(getArtifactsDir() + "BorderCollection.RemoveAllBorders.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "BorderCollection.RemoveAllBorders.docx");
+
+ for (Border border : doc.getFirstSection().getBody().getFirstParagraph().getParagraphFormat().getBorders()) {
+ Assert.assertEquals(0, border.getColor().getRGB());
+ Assert.assertEquals(LineStyle.NONE, border.getLineStyle());
+ Assert.assertEquals(0.0d, border.getLineWidth());
+ }
+ }
+}
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ExBuildVersion.java b/Examples/ApiExamples/Java/src/main/java/Examples/ExBuildVersion.java
new file mode 100644
index 00000000..409bfb7b
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ExBuildVersion.java
@@ -0,0 +1,32 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.words.BuildVersionInfo;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.text.MessageFormat;
+import java.util.regex.Pattern;
+
+public class ExBuildVersion extends ApiExampleBase {
+ @Test
+ public void printBuildVersionInfo() {
+ //ExStart
+ //ExFor:BuildVersionInfo
+ //ExFor:BuildVersionInfo.Product
+ //ExFor:BuildVersionInfo.Version
+ //ExSummary:Shows how to display information about your installed version of Aspose.Words.
+ System.out.println(MessageFormat.format("I am currently using {0}, version number {1}!", BuildVersionInfo.getProduct(), BuildVersionInfo.getVersion()));
+ //ExEnd
+
+ Assert.assertEquals("Aspose.Words for Java", BuildVersionInfo.getProduct());
+ Assert.assertTrue(Pattern.compile("[0-9]{2}.[0-9]{1,2}").matcher(BuildVersionInfo.getVersion()).find());
+ }
+}
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ExBuildingBlocks.java b/Examples/ApiExamples/Java/src/main/java/Examples/ExBuildingBlocks.java
new file mode 100644
index 00000000..576e6000
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ExBuildingBlocks.java
@@ -0,0 +1,249 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.words.*;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.UUID;
+
+@Test
+public class ExBuildingBlocks extends ApiExampleBase {
+ //ExStart
+ //ExFor:Document.GlossaryDocument
+ //ExFor:BuildingBlock
+ //ExFor:BuildingBlock.#ctor(GlossaryDocument)
+ //ExFor:BuildingBlock.Accept(DocumentVisitor)
+ //ExFor:BuildingBlock.AcceptStart(DocumentVisitor)
+ //ExFor:BuildingBlock.AcceptEnd(DocumentVisitor)
+ //ExFor:BuildingBlock.Behavior
+ //ExFor:BuildingBlock.Category
+ //ExFor:BuildingBlock.Description
+ //ExFor:BuildingBlock.FirstSection
+ //ExFor:BuildingBlock.Gallery
+ //ExFor:BuildingBlock.Guid
+ //ExFor:BuildingBlock.LastSection
+ //ExFor:BuildingBlock.Name
+ //ExFor:BuildingBlock.Sections
+ //ExFor:BuildingBlock.Type
+ //ExFor:BuildingBlockBehavior
+ //ExFor:BuildingBlockType
+ //ExSummary:Shows how to add a custom building block to a document.
+ @Test //ExSkip
+ public void createAndInsert() throws Exception {
+ // A document's glossary document stores building blocks.
+ Document doc = new Document();
+ GlossaryDocument glossaryDoc = new GlossaryDocument();
+ doc.setGlossaryDocument(glossaryDoc);
+
+ // Create a building block, name it, and then add it to the glossary document.
+ BuildingBlock block = new BuildingBlock(glossaryDoc);
+ block.setName("Custom Block");
+
+ glossaryDoc.appendChild(block);
+
+ // All new building block GUIDs have the same zero value by default, and we can give them a new unique value.
+ Assert.assertEquals(block.getGuid().toString(), "00000000-0000-0000-0000-000000000000");
+
+ block.setGuid(UUID.randomUUID());
+
+ // The following properties categorize building blocks
+ // in the menu we can access in Microsoft Word via "Insert" -> "Quick Parts" -> "Building Blocks Organizer".
+ Assert.assertEquals(block.getCategory(), "(Empty Category)");
+ Assert.assertEquals(block.getType(), BuildingBlockType.NONE);
+ Assert.assertEquals(block.getGallery(), BuildingBlockGallery.ALL);
+ Assert.assertEquals(block.getBehavior(), BuildingBlockBehavior.CONTENT);
+
+ // Before we can add this building block to our document, we will need to give it some contents,
+ // which we will do using a document visitor. This visitor will also set a category, gallery, and behavior.
+ BuildingBlockVisitor visitor = new BuildingBlockVisitor(glossaryDoc);
+ // Visit start/end of the BuildingBlock.
+ block.accept(visitor);
+
+ // We can access the block that we just made from the glossary document.
+ BuildingBlock customBlock = glossaryDoc.getBuildingBlock(BuildingBlockGallery.QUICK_PARTS,
+ "My custom building blocks", "Custom Block");
+
+ // The block itself is a section that contains the text.
+ Assert.assertEquals(MessageFormat.format("Text inside {0}\f", customBlock.getName()), customBlock.getFirstSection().getBody().getFirstParagraph().getText());
+ Assert.assertEquals(customBlock.getFirstSection(), customBlock.getLastSection());
+ Assert.assertEquals("My custom building blocks", customBlock.getCategory()); //ExSkip
+ Assert.assertEquals(BuildingBlockType.NONE, customBlock.getType()); //ExSkip
+ Assert.assertEquals(BuildingBlockGallery.QUICK_PARTS, customBlock.getGallery()); //ExSkip
+ Assert.assertEquals(BuildingBlockBehavior.PARAGRAPH, customBlock.getBehavior()); //ExSkip
+
+ // Now, we can insert it into the document as a new section.
+ doc.appendChild(doc.importNode(customBlock.getFirstSection(), true));
+
+ // We can also find it in Microsoft Word's Building Blocks Organizer and place it manually.
+ doc.save(getArtifactsDir() + "BuildingBlocks.CreateAndInsert.dotx");
+ }
+
+ ///
+ /// Sets up a visited building block to be inserted into the document as a quick part and adds text to its contents.
+ ///
+ public static class BuildingBlockVisitor extends DocumentVisitor {
+ public BuildingBlockVisitor(final GlossaryDocument ownerGlossaryDoc) {
+ mBuilder = new StringBuilder();
+ mGlossaryDoc = ownerGlossaryDoc;
+ }
+
+ public int visitBuildingBlockStart(final BuildingBlock block) {
+ // Configure the building block as a quick part, and add properties used by Building Blocks Organizer.
+ block.setBehavior(BuildingBlockBehavior.PARAGRAPH);
+ block.setCategory("My custom building blocks");
+ block.setDescription("Using this block in the Quick Parts section of word will place its contents at the cursor.");
+ block.setGallery(BuildingBlockGallery.QUICK_PARTS);
+
+ // Add a section with text.
+ // Inserting the block into the document will append this section with its child nodes at the location.
+ Section section = new Section(mGlossaryDoc);
+ block.appendChild(section);
+ block.getFirstSection().ensureMinimum();
+
+ Run run = new Run(mGlossaryDoc, "Text inside " + block.getName());
+ block.getFirstSection().getBody().getFirstParagraph().appendChild(run);
+
+ return VisitorAction.CONTINUE;
+ }
+
+ public int visitBuildingBlockEnd(final BuildingBlock block) {
+ mBuilder.append("Visited " + block.getName() + "\r\n");
+ return VisitorAction.CONTINUE;
+ }
+
+ private final StringBuilder mBuilder;
+ private final GlossaryDocument mGlossaryDoc;
+ }
+ //ExEnd
+
+ //ExStart
+ //ExFor:GlossaryDocument
+ //ExFor:GlossaryDocument.Accept(DocumentVisitor)
+ //ExFor:GlossaryDocument.AcceptStart(DocumentVisitor)
+ //ExFor:GlossaryDocument.AcceptEnd(DocumentVisitor)
+ //ExFor:GlossaryDocument.BuildingBlocks
+ //ExFor:GlossaryDocument.FirstBuildingBlock
+ //ExFor:GlossaryDocument.GetBuildingBlock(BuildingBlockGallery,String,String)
+ //ExFor:GlossaryDocument.LastBuildingBlock
+ //ExFor:BuildingBlockCollection
+ //ExFor:BuildingBlockCollection.Item(Int32)
+ //ExFor:BuildingBlockCollection.ToArray
+ //ExFor:BuildingBlockGallery
+ //ExFor:DocumentVisitor.VisitBuildingBlockEnd(BuildingBlock)
+ //ExFor:DocumentVisitor.VisitBuildingBlockStart(BuildingBlock)
+ //ExFor:DocumentVisitor.VisitGlossaryDocumentEnd(GlossaryDocument)
+ //ExFor:DocumentVisitor.VisitGlossaryDocumentStart(GlossaryDocument)
+ //ExSummary:Shows ways of accessing building blocks in a glossary document.
+ @Test //ExSkip
+ public void glossaryDocument() throws Exception {
+ Document doc = new Document();
+ GlossaryDocument glossaryDoc = new GlossaryDocument();
+
+ glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 1"));
+ glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 2"));
+ glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 3"));
+ glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 4"));
+ glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 5"));
+
+ Assert.assertEquals(glossaryDoc.getBuildingBlocks().getCount(), 5);
+
+ doc.setGlossaryDocument(glossaryDoc);
+
+ // There are various ways of accessing building blocks.
+ // 1 - Get the first/last building blocks in the collection:
+ Assert.assertEquals("Block 1", glossaryDoc.getFirstBuildingBlock().getName());
+ Assert.assertEquals("Block 5", glossaryDoc.getLastBuildingBlock().getName());
+
+ // 2 - Get a building block by index:
+ Assert.assertEquals("Block 2", glossaryDoc.getBuildingBlocks().get(1).getName());
+ Assert.assertEquals("Block 3", glossaryDoc.getBuildingBlocks().toArray()[2].getName());
+
+ // 3 - Get the first building block that matches a gallery, name and category:
+ Assert.assertEquals("Block 4",
+ glossaryDoc.getBuildingBlock(BuildingBlockGallery.ALL, "(Empty Category)", "Block 4").getName());
+
+ // We will do that using a custom visitor,
+ // which will give every BuildingBlock in the GlossaryDocument a unique GUID
+ GlossaryDocVisitor visitor = new GlossaryDocVisitor();
+ // Visit start/end of the Glossary document.
+ glossaryDoc.accept(visitor);
+ // Visit only start of the Glossary document.
+ glossaryDoc.acceptStart(visitor);
+ // Visit only end of the Glossary document.
+ glossaryDoc.acceptEnd(visitor);
+ Assert.assertEquals(5, visitor.getDictionary().size()); //ExSkip
+
+ System.out.println(visitor.getText());
+
+ // In Microsoft Word, we can access the building blocks via "Insert" -> "Quick Parts" -> "Building Blocks Organizer".
+ doc.save(getArtifactsDir() + "BuildingBlocks.GlossaryDocument.dotx");
+ }
+
+ public static BuildingBlock createNewBuildingBlock(final GlossaryDocument glossaryDoc, final String buildingBlockName) {
+ BuildingBlock buildingBlock = new BuildingBlock(glossaryDoc);
+ buildingBlock.setName(buildingBlockName);
+
+ return buildingBlock;
+ }
+
+ ///
+ /// Gives each building block in a visited glossary document a unique GUID.
+ /// Stores the GUID-building block pairs in a dictionary.
+ ///
+ public static class GlossaryDocVisitor extends DocumentVisitor {
+ public GlossaryDocVisitor() {
+ mBlocksByGuid = new HashMap<>();
+ mBuilder = new StringBuilder();
+ }
+
+ public String getText() {
+ return mBuilder.toString();
+ }
+
+ public HashMap getDictionary() {
+ return mBlocksByGuid;
+ }
+
+ public int visitGlossaryDocumentStart(final GlossaryDocument glossary) {
+ mBuilder.append("Glossary document found!\n");
+ return VisitorAction.CONTINUE;
+ }
+
+ public int visitGlossaryDocumentEnd(final GlossaryDocument glossary) {
+ mBuilder.append("Reached end of glossary!\n");
+ mBuilder.append("BuildingBlocks found: " + mBlocksByGuid.size() + "\r\n");
+ return VisitorAction.CONTINUE;
+ }
+
+ public int visitBuildingBlockStart(final BuildingBlock block) {
+ Assert.assertEquals("00000000-0000-0000-0000-000000000000", block.getGuid().toString()); //ExSkip
+ block.setGuid(UUID.randomUUID());
+ mBlocksByGuid.put(block.getGuid(), block);
+ return VisitorAction.CONTINUE;
+ }
+
+ public int visitBuildingBlockEnd(final BuildingBlock block) {
+ mBuilder.append("\tVisited block \"" + block.getName() + "\"" + "\r\n");
+ mBuilder.append("\t Type: " + block.getType() + "\r\n");
+ mBuilder.append("\t Gallery: " + block.getGallery() + "\r\n");
+ mBuilder.append("\t Behavior: " + block.getBehavior() + "\r\n");
+ mBuilder.append("\t Description: " + block.getDescription() + "\r\n");
+
+ return VisitorAction.CONTINUE;
+ }
+
+ private final HashMap mBlocksByGuid;
+ private final StringBuilder mBuilder;
+ }
+ //ExEnd
+}
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ExCellFormat.java b/Examples/ApiExamples/Java/src/main/java/Examples/ExCellFormat.java
new file mode 100644
index 00000000..88dbc081
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ExCellFormat.java
@@ -0,0 +1,137 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.words.*;
+import org.apache.commons.lang.StringUtils;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class ExCellFormat extends ApiExampleBase {
+ @Test
+ public void verticalMerge() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.EndRow
+ //ExFor:CellMerge
+ //ExFor:CellFormat.VerticalMerge
+ //ExSummary:Shows how to merge table cells vertically.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert a cell into the first column of the first row.
+ // This cell will be the first in a range of vertically merged cells.
+ builder.insertCell();
+ builder.getCellFormat().setVerticalMerge(CellMerge.FIRST);
+ builder.write("Text in merged cells.");
+
+ // Insert a cell into the second column of the first row, then end the row.
+ // Also, configure the builder to disable vertical merging in created cells.
+ builder.insertCell();
+ builder.getCellFormat().setVerticalMerge(CellMerge.NONE);
+ builder.write("Text in unmerged cell.");
+ builder.endRow();
+
+ // Insert a cell into the first column of the second row.
+ // Instead of adding text contents, we will merge this cell with the first cell that we added directly above.
+ builder.insertCell();
+ builder.getCellFormat().setVerticalMerge(CellMerge.PREVIOUS);
+
+ // Insert another independent cell in the second column of the second row.
+ builder.insertCell();
+ builder.getCellFormat().setVerticalMerge(CellMerge.NONE);
+ builder.write("Text in unmerged cell.");
+ builder.endRow();
+ builder.endTable();
+
+ doc.save(getArtifactsDir() + "CellFormat.VerticalMerge.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "CellFormat.VerticalMerge.docx");
+ Table table = doc.getFirstSection().getBody().getTables().get(0);
+
+ Assert.assertEquals(CellMerge.FIRST, table.getRows().get(0).getCells().get(0).getCellFormat().getVerticalMerge());
+ Assert.assertEquals(CellMerge.PREVIOUS, table.getRows().get(1).getCells().get(0).getCellFormat().getVerticalMerge());
+ Assert.assertEquals("Text in merged cells.", StringUtils.strip(table.getRows().get(0).getCells().get(0).getText(), String.valueOf('\u0007')));
+ Assert.assertNotEquals(table.getRows().get(0).getCells().get(0).getText(), table.getRows().get(1).getCells().get(0).getText());
+ }
+
+ @Test
+ public void horizontalMerge() throws Exception {
+ //ExStart
+ //ExFor:CellMerge
+ //ExFor:CellFormat.HorizontalMerge
+ //ExSummary:Shows how to merge table cells horizontally.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert a cell into the first column of the first row.
+ // This cell will be the first in a range of horizontally merged cells.
+ builder.insertCell();
+ builder.getCellFormat().setHorizontalMerge(CellMerge.FIRST);
+ builder.write("Text in merged cells.");
+
+ // Insert a cell into the second column of the first row. Instead of adding text contents,
+ // we will merge this cell with the first cell that we added directly to the left.
+ builder.insertCell();
+ builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
+ builder.endRow();
+
+ // Insert two more unmerged cells to the second row.
+ builder.getCellFormat().setHorizontalMerge(CellMerge.NONE);
+ builder.insertCell();
+ builder.write("Text in unmerged cell.");
+ builder.insertCell();
+ builder.write("Text in unmerged cell.");
+ builder.endRow();
+ builder.endTable();
+
+ doc.save(getArtifactsDir() + "CellFormat.HorizontalMerge.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "CellFormat.HorizontalMerge.docx");
+ Table table = doc.getFirstSection().getBody().getTables().get(0);
+
+ Assert.assertEquals(1, table.getRows().get(0).getCells().getCount());
+ Assert.assertEquals(CellMerge.NONE, table.getRows().get(0).getCells().get(0).getCellFormat().getHorizontalMerge());
+
+ Assert.assertEquals("Text in merged cells.", StringUtils.strip(table.getRows().get(0).getCells().get(0).getText(), String.valueOf('\u0007')));
+ }
+
+ @Test
+ public void padding() throws Exception {
+ //ExStart
+ //ExFor:CellFormat.SetPaddings
+ //ExSummary:Shows how to pad the contents of a cell with whitespace.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Set a padding distance (in points) between the border and the text contents
+ // of each table cell we create with the document builder.
+ builder.getCellFormat().setPaddings(5.0, 10.0, 40.0, 50.0);
+
+ // Create a table with one cell whose contents will have whitespace padding.
+ builder.startTable();
+ builder.insertCell();
+ builder.write("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. " +
+ "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.");
+
+ doc.save(getArtifactsDir() + "CellFormat.Padding.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "CellFormat.Padding.docx");
+
+ Table table = doc.getFirstSection().getBody().getTables().get(0);
+ Cell cell = table.getRows().get(0).getCells().get(0);
+
+ Assert.assertEquals(cell.getCellFormat().getLeftPadding(), 5.0);
+ Assert.assertEquals(cell.getCellFormat().getTopPadding(), 10.0);
+ Assert.assertEquals(cell.getCellFormat().getRightPadding(), 40.0);
+ Assert.assertEquals(cell.getCellFormat().getBottomPadding(), 50.0);
+ }
+}
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ExCertificateHolder.java b/Examples/ApiExamples/Java/src/main/java/Examples/ExCertificateHolder.java
new file mode 100644
index 00000000..87b7e2e2
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ExCertificateHolder.java
@@ -0,0 +1,37 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.words.CertificateHolder;
+import org.testng.annotations.Test;
+
+import java.io.FileInputStream;
+
+@Test
+public class ExCertificateHolder extends ApiExampleBase {
+ @Test
+ public void create() throws Exception {
+ //ExStart
+ //ExFor:CertificateHolder.Create(Byte[], SecureString)
+ //ExFor:CertificateHolder.Create(Byte[], String)
+ //ExFor:CertificateHolder.Create(String, String, String)
+ //ExSummary:Shows how to create CertificateHolder objects.
+ // Below are four ways of creating CertificateHolder objects.
+ // 1 - Load a PKCS #12 file into a byte array and apply its password:
+ byte[] certBytes = DocumentHelper.getBytesFromStream(new FileInputStream(getMyDir() + "morzal.pfx"));
+ CertificateHolder.create(certBytes, "aw");
+
+ // 2 - Use a valid alias:
+ CertificateHolder.create(getMyDir() + "morzal.pfx", "aw", "c20be521-11ea-4976-81ed-865fbbfc9f24");
+
+ // 3 - Pass "null" as the alias in order to use the first available alias that returns a private key:
+ CertificateHolder.create(getMyDir() + "morzal.pfx", "aw", null);
+ //ExEnd
+ }
+}
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ExCharts.java b/Examples/ApiExamples/Java/src/main/java/Examples/ExCharts.java
new file mode 100644
index 00000000..64d592f7
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ExCharts.java
@@ -0,0 +1,2604 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.words.*;
+import com.aspose.words.Shape;
+import org.apache.commons.collections4.IterableUtils;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.awt.*;
+import java.text.DecimalFormatSymbols;
+import java.text.MessageFormat;
+import java.text.NumberFormat;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Locale;
+
+@Test
+public class ExCharts extends ApiExampleBase {
+ @Test
+ public void chartTitle() throws Exception {
+ //ExStart:ChartTitle
+ //GistId:6d898be16b796fcf7448ad3bfe18e51c
+ //ExFor:Chart
+ //ExFor:Chart.Title
+ //ExFor:ChartTitle
+ //ExFor:ChartTitle.Overlay
+ //ExFor:ChartTitle.Show
+ //ExFor:ChartTitle.Text
+ //ExFor:ChartTitle.Font
+ //ExSummary:Shows how to insert a chart and set a title.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert a chart shape with a document builder and get its chart.
+ Shape chartShape = builder.insertChart(ChartType.BAR, 400.0, 300.0);
+ Chart chart = chartShape.getChart();
+
+ // Use the "Title" property to give our chart a title, which appears at the top center of the chart area.
+ ChartTitle title = chart.getTitle();
+ title.setText("My Chart");
+ title.getFont().setSize(15.0);
+ title.getFont().setColor(Color.BLUE);
+
+ // Set the "Show" property to "true" to make the title visible.
+ title.setShow(true);
+
+ // Set the "Overlay" property to "true" Give other chart elements more room by allowing them to overlap the title
+ title.setOverlay(true);
+
+ doc.save(getArtifactsDir() + "Charts.ChartTitle.docx");
+ //ExEnd:ChartTitle
+
+ doc = new Document(getArtifactsDir() + "Charts.ChartTitle.docx");
+ chartShape = (Shape) doc.getChild(NodeType.SHAPE, 0, true);
+
+ Assert.assertEquals(ShapeType.NON_PRIMITIVE, chartShape.getShapeType());
+ Assert.assertTrue(chartShape.hasChart());
+
+ title = chartShape.getChart().getTitle();
+
+ Assert.assertEquals("My Chart", title.getText());
+ Assert.assertTrue(title.getOverlay());
+ Assert.assertTrue(title.getShow());
+ }
+
+ @Test
+ public void dataLabelNumberFormat() throws Exception {
+ //ExStart
+ //ExFor:ChartDataLabelCollection.NumberFormat
+ //ExFor:ChartDataLabelCollection.Font
+ //ExFor:ChartNumberFormat.FormatCode
+ //ExFor:ChartSeries.HasDataLabels
+ //ExSummary:Shows how to enable and configure data labels for a chart series.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Add a line chart, then clear its demo data series to start with a clean chart,
+ // and then set a title.
+ Shape shape = builder.insertChart(ChartType.LINE, 500.0, 300.0);
+ Chart chart = shape.getChart();
+ chart.getSeries().clear();
+ chart.getTitle().setText("Monthly sales report");
+
+ // Insert a custom chart series with months as categories for the X-axis,
+ // and respective decimal amounts for the Y-axis.
+ ChartSeries series = chart.getSeries().add("Revenue",
+ new String[]{"January", "February", "March"},
+ new double[]{25.611d, 21.439d, 33.750d});
+
+ // Enable data labels, and then apply a custom number format for values displayed in the data labels.
+ // This format will treat displayed decimal values as millions of US Dollars.
+ series.hasDataLabels(true);
+ ChartDataLabelCollection dataLabels = series.getDataLabels();
+ dataLabels.setShowValue(true);
+ dataLabels.getNumberFormat().setFormatCode("\"US$\" #,##0.000\"M\"");
+ dataLabels.getFont().setSize(12.0);
+
+ doc.save(getArtifactsDir() + "Charts.DataLabelNumberFormat.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Charts.DataLabelNumberFormat.docx");
+ series = ((Shape) doc.getChild(NodeType.SHAPE, 0, true)).getChart().getSeries().get(0);
+
+ Assert.assertTrue(series.hasDataLabels());
+ Assert.assertTrue(series.getDataLabels().getShowValue());
+ Assert.assertEquals("\"US$\" #,##0.000\"M\"", series.getDataLabels().getNumberFormat().getFormatCode());
+ }
+
+ @Test
+ public void axisProperties() throws Exception {
+ //ExStart
+ //ExFor:ChartAxis
+ //ExFor:ChartAxis.CategoryType
+ //ExFor:ChartAxis.Crosses
+ //ExFor:ChartAxis.ReverseOrder
+ //ExFor:ChartAxis.MajorTickMark
+ //ExFor:ChartAxis.MinorTickMark
+ //ExFor:ChartAxis.MajorUnit
+ //ExFor:ChartAxis.MinorUnit
+ //ExFor:ChartAxis.Document
+ //ExFor:ChartAxis.TickLabels
+ //ExFor:ChartAxis.Format
+ //ExFor:AxisTickLabels
+ //ExFor:AxisTickLabels.Offset
+ //ExFor:AxisTickLabels.Position
+ //ExFor:AxisTickLabels.IsAutoSpacing
+ //ExFor:AxisTickLabels.Alignment
+ //ExFor:AxisTickLabels.Font
+ //ExFor:AxisTickLabels.Spacing
+ //ExFor:ChartAxis.TickMarkSpacing
+ //ExFor:AxisCategoryType
+ //ExFor:AxisCrosses
+ //ExFor:Chart.AxisX
+ //ExFor:Chart.AxisY
+ //ExFor:Chart.AxisZ
+ //ExSummary:Shows how to insert a chart and modify the appearance of its axes.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.COLUMN, 500.0, 300.0);
+ Chart chart = shape.getChart();
+
+ // Clear the chart's demo data series to start with a clean chart.
+ chart.getSeries().clear();
+
+ // Insert a chart series with categories for the X-axis and respective numeric values for the Y-axis.
+ chart.getSeries().add("Aspose Test Series",
+ new String[]{"Word", "PDF", "Excel", "GoogleDocs", "Note"},
+ new double[]{640.0, 320.0, 280.0, 120.0, 150.0});
+
+ // Chart axes have various options that can change their appearance,
+ // such as their direction, major/minor unit ticks, and tick marks.
+ ChartAxis xAxis = chart.getAxisX();
+ xAxis.setCategoryType(AxisCategoryType.CATEGORY);
+ xAxis.setCrosses(AxisCrosses.MINIMUM);
+ xAxis.setReverseOrder(false);
+ xAxis.setMajorTickMark(AxisTickMark.INSIDE);
+ xAxis.setMinorTickMark(AxisTickMark.CROSS);
+ xAxis.setMajorUnit(10.0d);
+ xAxis.setMinorUnit(15.0d);
+ xAxis.getTickLabels().setOffset(50);
+ xAxis.getTickLabels().setPosition(AxisTickLabelPosition.LOW);
+ xAxis.getTickLabels().isAutoSpacing(false);
+ xAxis.setTickMarkSpacing(1);
+
+ Assert.assertEquals(doc, xAxis.getDocument());
+
+ ChartAxis yAxis = chart.getAxisY();
+ yAxis.setCategoryType(AxisCategoryType.AUTOMATIC);
+ yAxis.setCrosses(AxisCrosses.MAXIMUM);
+ yAxis.setReverseOrder(true);
+ yAxis.setMajorTickMark(AxisTickMark.INSIDE);
+ yAxis.setMinorTickMark(AxisTickMark.CROSS);
+ yAxis.setMajorUnit(100.0d);
+ yAxis.setMinorUnit(20.0d);
+ yAxis.getTickLabels().setPosition(AxisTickLabelPosition.NEXT_TO_AXIS);
+ yAxis.getTickLabels().setAlignment(ParagraphAlignment.CENTER);
+ yAxis.getTickLabels().getFont().setColor(Color.RED);
+ yAxis.getTickLabels().setSpacing(1);
+
+ // Column charts do not have a Z-axis.
+ Assert.assertNull(chart.getAxisZ());
+
+ doc.save(getArtifactsDir() + "Charts.AxisProperties.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Charts.AxisProperties.docx");
+ chart = ((Shape) doc.getChild(NodeType.SHAPE, 0, true)).getChart();
+
+ Assert.assertEquals(AxisCategoryType.CATEGORY, chart.getAxisX().getCategoryType());
+ Assert.assertEquals(AxisCrosses.MINIMUM, chart.getAxisX().getCrosses());
+ Assert.assertFalse(chart.getAxisX().getReverseOrder());
+ Assert.assertEquals(AxisTickMark.INSIDE, chart.getAxisX().getMajorTickMark());
+ Assert.assertEquals(AxisTickMark.CROSS, chart.getAxisX().getMinorTickMark());
+ Assert.assertEquals(1.0d, chart.getAxisX().getMajorUnit());
+ Assert.assertEquals(0.5d, chart.getAxisX().getMinorUnit());
+ Assert.assertEquals(50, chart.getAxisX().getTickLabels().getOffset());
+ Assert.assertEquals(AxisTickLabelPosition.LOW, chart.getAxisX().getTickLabels().getPosition());
+ Assert.assertFalse(chart.getAxisX().getTickLabels().isAutoSpacing());
+ Assert.assertEquals(1, chart.getAxisX().getTickMarkSpacing());
+ Assert.assertTrue(chart.getAxisX().getFormat().isDefined());
+
+ Assert.assertEquals(AxisCategoryType.CATEGORY, chart.getAxisY().getCategoryType());
+ Assert.assertEquals(AxisCrosses.MAXIMUM, chart.getAxisY().getCrosses());
+ Assert.assertTrue(chart.getAxisY().getReverseOrder());
+ Assert.assertEquals(AxisTickMark.INSIDE, chart.getAxisY().getMajorTickMark());
+ Assert.assertEquals(AxisTickMark.CROSS, chart.getAxisY().getMinorTickMark());
+ Assert.assertEquals(100.0d, chart.getAxisY().getMajorUnit());
+ Assert.assertEquals(20.0d, chart.getAxisY().getMinorUnit());
+ Assert.assertEquals(AxisTickLabelPosition.NEXT_TO_AXIS, chart.getAxisY().getTickLabels().getPosition());
+ Assert.assertEquals(ParagraphAlignment.CENTER, chart.getAxisY().getTickLabels().getAlignment());
+ Assert.assertEquals(Color.RED.getRGB(), chart.getAxisY().getTickLabels().getFont().getColor().getRGB());
+ Assert.assertEquals(1, chart.getAxisY().getTickLabels().getSpacing());
+ Assert.assertTrue(chart.getAxisY().getFormat().isDefined());
+ }
+
+ @Test
+ public void axisCollection() throws Exception
+ {
+ //ExStart
+ //ExFor:ChartAxisCollection
+ //ExFor:Chart.Axes
+ //ExSummary:Shows how to work with axes collection.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.COLUMN, 500.0, 300.0);
+ Chart chart = shape.getChart();
+
+ // Hide the major grid lines on the primary and secondary Y axes.
+ for (ChartAxis axis : chart.getAxes())
+ {
+ if (axis.getType() == ChartAxisType.VALUE)
+ axis.hasMajorGridlines(false);
+ }
+
+ doc.save(getArtifactsDir() + "Charts.AxisCollection.docx");
+ //ExEnd
+ }
+
+ @Test
+ public void dateTimeValues() throws Exception {
+ //ExStart
+ //ExFor:AxisBound
+ //ExFor:AxisBound.#ctor(Double)
+ //ExFor:AxisBound.#ctor(DateTime)
+ //ExFor:AxisScaling.Minimum
+ //ExFor:AxisScaling.Maximum
+ //ExFor:ChartAxis.Scaling
+ //ExFor:AxisTickMark
+ //ExFor:AxisTickLabelPosition
+ //ExFor:AxisTimeUnit
+ //ExFor:ChartAxis.BaseTimeUnit
+ //ExFor:ChartAxis.HasMajorGridlines
+ //ExFor:ChartAxis.HasMinorGridlines
+ //ExSummary:Shows how to insert chart with date/time values.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.LINE, 500.0, 300.0);
+ Chart chart = shape.getChart();
+
+ // Clear the chart's demo data series to start with a clean chart.
+ chart.getSeries().clear();
+
+ // Add a custom series containing date/time values for the X-axis, and respective decimal values for the Y-axis.
+ chart.getSeries().add("Aspose Test Series",
+ new Date[]
+ {
+ DocumentHelper.createDate(2017, 11, 6), DocumentHelper.createDate(2017, 11, 9), DocumentHelper.createDate(2017, 11, 15),
+ DocumentHelper.createDate(2017, 11, 21), DocumentHelper.createDate(2017, 11, 25), DocumentHelper.createDate(2017, 11, 29)
+ },
+ new double[]{1.2, 0.3, 2.1, 2.9, 4.2, 5.3});
+
+
+ // Set lower and upper bounds for the X-axis.
+ ChartAxis xAxis = chart.getAxisX();
+ Date datetimeMin = DocumentHelper.createDate(2017, 11, 5);
+ xAxis.getScaling().setMinimum(new AxisBound(datetimeMin));
+ Date datetimeMax = DocumentHelper.createDate(2017, 12, 3);
+ xAxis.getScaling().setMaximum(new AxisBound(datetimeMax));
+
+ // Set the major units of the X-axis to a week, and the minor units to a day.
+ xAxis.setBaseTimeUnit(AxisTimeUnit.DAYS);
+ xAxis.setMajorUnit(7.0d);
+ xAxis.setMajorTickMark(AxisTickMark.CROSS);
+ xAxis.setMinorUnit(1.0d);
+ xAxis.setMinorTickMark(AxisTickMark.OUTSIDE);
+ xAxis.hasMajorGridlines(true);
+ xAxis.hasMinorGridlines(true);
+
+ // Define Y-axis properties for decimal values.
+ ChartAxis yAxis = chart.getAxisY();
+ yAxis.getTickLabels().setPosition(AxisTickLabelPosition.HIGH);
+ yAxis.setMajorUnit(100.0d);
+ yAxis.setMinorUnit(50.0d);
+ yAxis.getDisplayUnit().setUnit(AxisBuiltInUnit.HUNDREDS);
+ yAxis.getScaling().setMinimum(new AxisBound(100.0));
+ yAxis.getScaling().setMaximum(new AxisBound(700.0));
+ yAxis.hasMajorGridlines(true);
+ yAxis.hasMinorGridlines(true);
+
+ doc.save(getArtifactsDir() + "Charts.DateTimeValues.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Charts.DateTimeValues.docx");
+ chart = ((Shape) doc.getChild(NodeType.SHAPE, 0, true)).getChart();
+
+ Assert.assertEquals(datetimeMin, chart.getAxisX().getScaling().getMinimum().getValueAsDate());
+ Assert.assertEquals(datetimeMax, chart.getAxisX().getScaling().getMaximum().getValueAsDate());
+ Assert.assertEquals(AxisTimeUnit.DAYS, chart.getAxisX().getBaseTimeUnit());
+ Assert.assertEquals(7.0d, chart.getAxisX().getMajorUnit());
+ Assert.assertEquals(1.0d, chart.getAxisX().getMinorUnit());
+ Assert.assertEquals(AxisTickMark.CROSS, chart.getAxisX().getMajorTickMark());
+ Assert.assertEquals(AxisTickMark.OUTSIDE, chart.getAxisX().getMinorTickMark());
+ Assert.assertEquals(true, chart.getAxisX().hasMajorGridlines());
+ Assert.assertEquals(true, chart.getAxisX().hasMinorGridlines());
+
+ Assert.assertEquals(AxisTickLabelPosition.HIGH, chart.getAxisY().getTickLabels().getPosition());
+ Assert.assertEquals(100.0d, chart.getAxisY().getMajorUnit());
+ Assert.assertEquals(50.0d, chart.getAxisY().getMinorUnit());
+ Assert.assertEquals(AxisBuiltInUnit.HUNDREDS, chart.getAxisY().getDisplayUnit().getUnit());
+ Assert.assertEquals(new AxisBound(100.0), chart.getAxisY().getScaling().getMinimum());
+ Assert.assertEquals(new AxisBound(700.0), chart.getAxisY().getScaling().getMaximum());
+ Assert.assertEquals(true, chart.getAxisY().hasMajorGridlines());
+ Assert.assertEquals(true, chart.getAxisY().hasMinorGridlines());
+ }
+
+ @Test
+ public void hideChartAxis() throws Exception {
+ //ExStart
+ //ExFor:ChartAxis.Hidden
+ //ExSummary:Shows how to hide chart axes.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.LINE, 500.0, 300.0);
+ Chart chart = shape.getChart();
+
+ // Clear the chart's demo data series to start with a clean chart.
+ chart.getSeries().clear();
+
+ // Add a custom series with categories for the X-axis, and respective decimal values for the Y-axis.
+ chart.getSeries().add("AW Series 1",
+ new String[]{"Item 1", "Item 2", "Item 3", "Item 4", "Item 5"},
+ new double[]{1.2, 0.3, 2.1, 2.9, 4.2});
+
+ // Hide the chart axes to simplify the appearance of the chart.
+ chart.getAxisX().setHidden(true);
+ chart.getAxisY().setHidden(true);
+
+ doc.save(getArtifactsDir() + "Charts.HideChartAxis.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Charts.HideChartAxis.docx");
+ chart = ((Shape) doc.getChild(NodeType.SHAPE, 0, true)).getChart();
+
+ Assert.assertEquals(chart.getAxisX().getHidden(), true);
+ Assert.assertEquals(chart.getAxisY().getHidden(), true);
+ }
+
+ @Test
+ public void setNumberFormatToChartAxis() throws Exception {
+ //ExStart
+ //ExFor:ChartAxis.NumberFormat
+ //ExFor:ChartNumberFormat
+ //ExFor:ChartNumberFormat.FormatCode
+ //ExFor:ChartNumberFormat.IsLinkedToSource
+ //ExSummary:Shows how to set formatting for chart values.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.COLUMN, 500.0, 300.0);
+ Chart chart = shape.getChart();
+
+ // Clear the chart's demo data series to start with a clean chart.
+ chart.getSeries().clear();
+
+ // Add a custom series to the chart with categories for the X-axis,
+ // and large respective numeric values for the Y-axis.
+ chart.getSeries().add("Aspose Test Series",
+ new String[]{"Word", "PDF", "Excel", "GoogleDocs", "Note"},
+ new double[]{1900000.0, 850000.0, 2100000.0, 600000.0, 1500000.0});
+
+ // Set the number format of the Y-axis tick labels to not group digits with commas.
+ chart.getAxisY().getNumberFormat().setFormatCode("#,##0");
+
+ // This flag can override the above value and draw the number format from the source cell.
+ Assert.assertFalse(chart.getAxisY().getNumberFormat().isLinkedToSource());
+
+ doc.save(getArtifactsDir() + "Charts.SetNumberFormatToChartAxis.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Charts.SetNumberFormatToChartAxis.docx");
+ chart = ((Shape) doc.getChild(NodeType.SHAPE, 0, true)).getChart();
+
+ Assert.assertEquals("#,##0", chart.getAxisY().getNumberFormat().getFormatCode());
+ }
+
+ @Test (dataProvider = "testDisplayChartsWithConversionDataProvider")
+ public void testDisplayChartsWithConversion(int chartType) throws Exception
+ {
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(chartType, 500.0, 300.0);
+ Chart chart = shape.getChart();
+ chart.getSeries().clear();
+
+ chart.getSeries().add("Aspose Test Series",
+ new String[] { "Word", "PDF", "Excel", "GoogleDocs", "Note" },
+ new double[] { 1900000.0, 850000.0, 2100000.0, 600000.0, 1500000.0 });
+
+ doc.save(getArtifactsDir() + "Charts.TestDisplayChartsWithConversion.docx");
+ doc.save(getArtifactsDir() + "Charts.TestDisplayChartsWithConversion.pdf");
+ }
+
+ //JAVA-added data provider for test method
+ @DataProvider(name = "testDisplayChartsWithConversionDataProvider")
+ public static Object[][] testDisplayChartsWithConversionDataProvider() throws Exception
+ {
+ return new Object[][]
+ {
+ {ChartType.COLUMN},
+ {ChartType.LINE},
+ {ChartType.PIE},
+ {ChartType.BAR},
+ {ChartType.AREA},
+ };
+ }
+
+ @Test
+ public void surface3DChart() throws Exception
+ {
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.SURFACE_3_D, 500.0, 300.0);
+ Chart chart = shape.getChart();
+ chart.getSeries().clear();
+
+ chart.getSeries().add("Aspose Test Series 1",
+ new String[] { "Word", "PDF", "Excel", "GoogleDocs", "Note" },
+ new double[] { 1900000.0, 850000.0, 2100000.0, 600000.0, 1500000.0 });
+
+ chart.getSeries().add("Aspose Test Series 2",
+ new String[] { "Word", "PDF", "Excel", "GoogleDocs", "Note" },
+ new double[] { 900000.0, 50000.0, 1100000.0, 400000.0, 2500000.0 });
+
+ chart.getSeries().add("Aspose Test Series 3",
+ new String[] { "Word", "PDF", "Excel", "GoogleDocs", "Note" },
+ new double[] { 500000.0, 820000.0, 1500000.0, 400000.0, 100000.0 });
+
+ doc.save(getArtifactsDir() + "Charts.SurfaceChart.docx");
+ doc.save(getArtifactsDir() + "Charts.SurfaceChart.pdf");
+ }
+
+ @Test
+ public void dataLabelsBubbleChart() throws Exception {
+ //ExStart
+ //ExFor:ChartDataLabelCollection.Separator
+ //ExFor:ChartDataLabelCollection.ShowBubbleSize
+ //ExFor:ChartDataLabelCollection.ShowCategoryName
+ //ExFor:ChartDataLabelCollection.ShowSeriesName
+ //ExSummary:Shows how to work with data labels of a bubble chart.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Chart chart = builder.insertChart(ChartType.BUBBLE, 500.0, 300.0).getChart();
+
+ // Clear the chart's demo data series to start with a clean chart.
+ chart.getSeries().clear();
+
+ // Add a custom series with X/Y coordinates and diameter of each of the bubbles.
+ ChartSeries series = chart.getSeries().add("Aspose Test Series",
+ new double[]{2.9, 3.5, 1.1, 4.0, 4.0},
+ new double[]{1.9, 8.5, 2.1, 6.0, 1.5},
+ new double[]{9.0, 4.5, 2.5, 8.0, 5.0});
+
+ // Enable data labels, and then modify their appearance.
+ series.hasDataLabels(true);
+ ChartDataLabelCollection dataLabels = series.getDataLabels();
+ dataLabels.setShowBubbleSize(true);
+ dataLabels.setShowCategoryName(true);
+ dataLabels.setShowSeriesName(true);
+ dataLabels.setSeparator(" & ");
+
+ doc.save(getArtifactsDir() + "Charts.DataLabelsBubbleChart.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Charts.DataLabelsBubbleChart.docx");
+ dataLabels = ((Shape) doc.getChild(NodeType.SHAPE, 0, true)).getChart().getSeries().get(0).getDataLabels();
+
+ Assert.assertTrue(dataLabels.getShowBubbleSize());
+ Assert.assertTrue(dataLabels.getShowCategoryName());
+ Assert.assertTrue(dataLabels.getShowSeriesName());
+ Assert.assertEquals(" & ", dataLabels.getSeparator());
+ }
+
+ @Test
+ public void dataLabelsPieChart() throws Exception {
+ //ExStart
+ //ExFor:ChartDataLabelCollection.Separator
+ //ExFor:ChartDataLabelCollection.ShowLeaderLines
+ //ExFor:ChartDataLabelCollection.ShowLegendKey
+ //ExFor:ChartDataLabelCollection.ShowPercentage
+ //ExFor:ChartDataLabelCollection.ShowValue
+ //ExSummary:Shows how to work with data labels of a pie chart.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Chart chart = builder.insertChart(ChartType.PIE, 500.0, 300.0).getChart();
+
+ // Clear the chart's demo data series to start with a clean chart.
+ chart.getSeries().clear();
+
+ // Insert a custom chart series with a category name for each of the sectors, and their frequency table.
+ ChartSeries series = chart.getSeries().add("Aspose Test Series",
+ new String[]{"Word", "PDF", "Excel"},
+ new double[]{2.7, 3.2, 0.8});
+
+ // Enable data labels that will display both percentage and frequency of each sector, and modify their appearance.
+ series.hasDataLabels(true);
+ ChartDataLabelCollection dataLabels = series.getDataLabels();
+ dataLabels.setShowLeaderLines(true);
+ dataLabels.setShowLegendKey(true);
+ dataLabels.setShowPercentage(true);
+ dataLabels.setShowValue(true);
+ dataLabels.setSeparator("; ");
+
+ doc.save(getArtifactsDir() + "Charts.DataLabelsPieChart.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Charts.DataLabelsPieChart.docx");
+ dataLabels = ((Shape) doc.getChild(NodeType.SHAPE, 0, true)).getChart().getSeries().get(0).getDataLabels();
+
+ Assert.assertTrue(dataLabels.getShowLeaderLines());
+ Assert.assertTrue(dataLabels.getShowLegendKey());
+ Assert.assertTrue(dataLabels.getShowPercentage());
+ Assert.assertTrue(dataLabels.getShowValue());
+ Assert.assertEquals("; ", dataLabels.getSeparator());
+ }
+
+ //ExStart
+ //ExFor:ChartSeries
+ //ExFor:ChartSeries.DataLabels
+ //ExFor:ChartSeries.DataPoints
+ //ExFor:ChartSeries.Name
+ //ExFor:ChartSeries.Explosion
+ //ExFor:ChartDataLabel
+ //ExFor:ChartDataLabel.Index
+ //ExFor:ChartDataLabel.IsVisible
+ //ExFor:ChartDataLabel.NumberFormat
+ //ExFor:ChartDataLabel.Separator
+ //ExFor:ChartDataLabel.ShowCategoryName
+ //ExFor:ChartDataLabel.ShowDataLabelsRange
+ //ExFor:ChartDataLabel.ShowLeaderLines
+ //ExFor:ChartDataLabel.ShowLegendKey
+ //ExFor:ChartDataLabel.ShowPercentage
+ //ExFor:ChartDataLabel.ShowSeriesName
+ //ExFor:ChartDataLabel.ShowValue
+ //ExFor:ChartDataLabel.IsHidden
+ //ExFor:ChartDataLabel.Format
+ //ExFor:ChartDataLabel.ClearFormat
+ //ExFor:ChartDataLabelCollection
+ //ExFor:ChartDataLabelCollection.ShowDataLabelsRange
+ //ExFor:ChartDataLabelCollection.ClearFormat
+ //ExFor:ChartDataLabelCollection.Count
+ //ExFor:ChartDataLabelCollection.GetEnumerator
+ //ExFor:ChartDataLabelCollection.Item(Int32)
+ //ExSummary:Shows how to apply labels to data points in a line chart.
+ @Test //ExSkip
+ public void dataLabels() throws Exception {
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape chartShape = builder.insertChart(ChartType.LINE, 400.0, 300.0);
+ Chart chart = chartShape.getChart();
+
+ Assert.assertEquals(3, chart.getSeries().getCount());
+ Assert.assertEquals("Series 1", chart.getSeries().get(0).getName());
+ Assert.assertEquals("Series 2", chart.getSeries().get(1).getName());
+ Assert.assertEquals("Series 3", chart.getSeries().get(2).getName());
+
+ // Apply data labels to every series in the chart.
+ // These labels will appear next to each data point in the graph and display its value.
+ for (ChartSeries series : chart.getSeries()) {
+ applyDataLabels(series, 4, "000.0", ", ");
+ Assert.assertEquals(series.getDataLabels().getCount(), 4);
+ }
+
+ // Change the separator string for every data label in a series.
+ Iterator enumerator = chart.getSeries().get(0).getDataLabels().iterator();
+ while (enumerator.hasNext()) {
+ Assert.assertEquals(enumerator.next().getSeparator(), ", ");
+ enumerator.next().setSeparator(" & ");
+ }
+
+ ChartDataLabel dataLabel = chart.getSeries().get(1).getDataLabels().get(2);
+ dataLabel.getFormat().getFill().setColor(Color.RED);
+
+ // For a cleaner looking graph, we can remove data labels individually.
+ dataLabel.clearFormat();
+
+ // We can also strip an entire series of its data labels at once.
+ chart.getSeries().get(2).getDataLabels().clearFormat();
+
+ doc.save(getArtifactsDir() + "Charts.DataLabels.docx");
+ }
+
+ ///
+ /// Apply data labels with custom number format and separator to several data points in a series.
+ ///
+ private static void applyDataLabels(ChartSeries series, int labelsCount, String numberFormat, String separator) {
+ series.hasDataLabels(true);
+ series.setExplosion(40);
+
+ for (int i = 0; i < labelsCount; i++) {
+ Assert.assertFalse(series.getDataLabels().get(i).isVisible());
+
+ series.getDataLabels().get(i).setShowCategoryName(true);
+ series.getDataLabels().get(i).setShowSeriesName(true);
+ series.getDataLabels().get(i).setShowValue(true);
+ series.getDataLabels().get(i).setShowLeaderLines(true);
+ series.getDataLabels().get(i).setShowLegendKey(true);
+ series.getDataLabels().get(i).setShowPercentage(false);
+ Assert.assertFalse(series.getDataLabels().get(i).isHidden());
+ Assert.assertFalse(series.getDataLabels().get(i).getShowDataLabelsRange());
+
+ series.getDataLabels().get(i).getNumberFormat().setFormatCode(numberFormat);
+ series.getDataLabels().get(i).setSeparator(separator);
+
+ Assert.assertFalse(series.getDataLabels().get(i).getShowDataLabelsRange());
+ Assert.assertTrue(series.getDataLabels().get(i).isVisible());
+ Assert.assertFalse(series.getDataLabels().get(i).isHidden());
+ }
+ }
+ //ExEnd
+
+ //ExStart
+ //ExFor:ChartSeries.Smooth
+ //ExFor:ChartSeries.InvertIfNegative
+ //ExFor:ChartDataPoint
+ //ExFor:ChartDataPoint.Format
+ //ExFor:ChartDataPoint.ClearFormat
+ //ExFor:ChartDataPoint.Index
+ //ExFor:ChartDataPointCollection
+ //ExFor:ChartDataPointCollection.ClearFormat
+ //ExFor:ChartDataPointCollection.Count
+ //ExFor:ChartDataPointCollection.GetEnumerator
+ //ExFor:ChartDataPointCollection.Item(Int32)
+ //ExFor:ChartMarker
+ //ExFor:ChartMarker.Size
+ //ExFor:ChartMarker.Symbol
+ //ExFor:IChartDataPoint
+ //ExFor:IChartDataPoint.InvertIfNegative
+ //ExFor:ChartDataPoint.InvertIfNegative
+ //ExFor:IChartDataPoint.Marker
+ //ExFor:MarkerSymbol
+ //ExSummary:Shows how to work with data points on a line chart.
+ @Test//ExSkip
+ public void chartDataPoint() throws Exception {
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.LINE, 500.0, 350.0);
+ Chart chart = shape.getChart();
+
+ Assert.assertEquals(3, chart.getSeries().getCount());
+ Assert.assertEquals("Series 1", chart.getSeries().get(0).getName());
+ Assert.assertEquals("Series 2", chart.getSeries().get(1).getName());
+ Assert.assertEquals("Series 3", chart.getSeries().get(2).getName());
+
+ // Emphasize the chart's data points by making them appear as diamond shapes.
+ for (ChartSeries series : chart.getSeries())
+ applyDataPoints(series, 4, MarkerSymbol.DIAMOND, 15);
+
+ // Smooth out the line that represents the first data series.
+ chart.getSeries().get(0).setSmooth(true);
+
+ // Verify that data points for the first series will not invert their colors if the value is negative.
+ Iterator enumerator = chart.getSeries().get(0).getDataPoints().iterator();
+ while (enumerator.hasNext()) {
+ Assert.assertFalse(enumerator.next().getInvertIfNegative());
+ }
+
+ ChartDataPoint dataPoint = chart.getSeries().get(1).getDataPoints().get(2);
+ dataPoint.getFormat().getFill().setColor(Color.RED);
+
+ // For a cleaner looking graph, we can clear format individually.
+ dataPoint.clearFormat();
+
+ // We can also strip an entire series of data points at once.
+ chart.getSeries().get(2).getDataPoints().clearFormat();
+
+ doc.save(getArtifactsDir() + "Charts.ChartDataPoint.docx");
+ }
+
+ ///
+ /// Applies a number of data points to a series.
+ ///
+ private static void applyDataPoints(ChartSeries series, int dataPointsCount, int markerSymbol, int dataPointSize) {
+ for (int i = 0; i < dataPointsCount; i++) {
+ ChartDataPoint point = series.getDataPoints().get(i);
+ point.getMarker().setSymbol(markerSymbol);
+ point.getMarker().setSize(dataPointSize);
+
+ Assert.assertEquals(point.getIndex(), i);
+ }
+ }
+ //ExEnd
+
+ @Test
+ public void pieChartExplosion() throws Exception {
+ //ExStart
+ //ExFor:IChartDataPoint.Explosion
+ //ExFor:ChartDataPoint.Explosion
+ //ExSummary:Shows how to move the slices of a pie chart away from the center.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.PIE, 500.0, 350.0);
+ Chart chart = shape.getChart();
+
+ Assert.assertEquals(1, chart.getSeries().getCount());
+ Assert.assertEquals("Sales", chart.getSeries().get(0).getName());
+
+ // "Slices" of a pie chart may be moved away from the center by a distance via the respective data point's Explosion attribute.
+ // Add a data point to the first portion of the pie chart and move it away from the center by 10 points.
+ // Aspose.Words create data points automatically if them does not exist.
+ ChartDataPoint dataPoint = chart.getSeries().get(0).getDataPoints().get(0);
+ dataPoint.setExplosion(10);
+
+ // Displace the second portion by a greater distance.
+ dataPoint = chart.getSeries().get(0).getDataPoints().get(1);
+ dataPoint.setExplosion(40);
+
+ doc.save(getArtifactsDir() + "Charts.PieChartExplosion.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Charts.PieChartExplosion.docx");
+ ChartSeries series = ((Shape) doc.getChild(NodeType.SHAPE, 0, true)).getChart().getSeries().get(0);
+
+ Assert.assertEquals(10, series.getDataPoints().get(0).getExplosion());
+ Assert.assertEquals(40, series.getDataPoints().get(1).getExplosion());
+ }
+
+ @Test
+ public void bubble3D() throws Exception {
+ //ExStart
+ //ExFor:ChartDataLabel.ShowBubbleSize
+ //ExFor:ChartDataLabel.Font
+ //ExFor:IChartDataPoint.Bubble3D
+ //ExFor:ChartSeries.Bubble3D
+ //ExSummary:Shows how to use 3D effects with bubble charts.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.BUBBLE_3_D, 500.0, 350.0);
+ Chart chart = shape.getChart();
+
+ Assert.assertEquals(1, chart.getSeries().getCount());
+ Assert.assertEquals("Y-Values", chart.getSeries().get(0).getName());
+ Assert.assertTrue(chart.getSeries().get(0).getBubble3D());
+
+ // Apply a data label to each bubble that displays its diameter.
+ for (int i = 0; i < 3; i++) {
+ chart.getSeries().get(0).hasDataLabels(true);
+ ChartDataLabel cdl = chart.getSeries().get(0).getDataLabels().get(i);
+ chart.getSeries().get(0).getDataLabels().get(i).getFont().setSize(12.0);
+ cdl.setShowBubbleSize(true);
+ }
+
+ doc.save(getArtifactsDir() + "Charts.Bubble3D.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Charts.Bubble3D.docx");
+ ChartSeries series = ((Shape) doc.getChild(NodeType.SHAPE, 0, true)).getChart().getSeries().get(0);
+
+ for (int i = 0; i < 3; i++) {
+ Assert.assertTrue(series.getDataLabels().get(i).getShowBubbleSize());
+ Assert.assertTrue(series.getDataLabels().get(i).getShowBubbleSize());
+ }
+ }
+
+ //ExStart
+ //ExFor:ChartAxis.Type
+ //ExFor:ChartAxisType
+ //ExFor:ChartType
+ //ExFor:Chart.Series
+ //ExFor:ChartSeriesCollection.Add(String,DateTime[],Double[])
+ //ExFor:ChartSeriesCollection.Add(String,Double[],Double[])
+ //ExFor:ChartSeriesCollection.Add(String,Double[],Double[],Double[])
+ //ExFor:ChartSeriesCollection.Add(String,String[],Double[])
+ //ExSummary:Shows how to create an appropriate type of chart series for a graph type.
+ @Test //ExSkip
+ public void chartSeriesCollection() throws Exception {
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // There are several ways of populating a chart's series collection.
+ // Different series schemas are intended for different chart types.
+ // 1 - Column chart with columns grouped and banded along the X-axis by category:
+ Chart chart = appendChart(builder, ChartType.COLUMN, 500.0, 300.0);
+
+ String[] categories = {"Category 1", "Category 2", "Category 3"};
+
+ // Insert two series of decimal values containing a value for each respective category.
+ // This column chart will have three groups, each with two columns.
+ chart.getSeries().add("Series 1", categories, new double[]{76.6, 82.1, 91.6});
+ chart.getSeries().add("Series 2", categories, new double[]{64.2, 79.5, 94.0});
+
+ // Categories are distributed along the X-axis, and values are distributed along the Y-axis.
+ Assert.assertEquals(ChartAxisType.CATEGORY, chart.getAxisX().getType());
+ Assert.assertEquals(ChartAxisType.VALUE, chart.getAxisY().getType());
+
+ // 2 - Area chart with dates distributed along the X-axis:
+ chart = appendChart(builder, ChartType.AREA, 500.0, 300.0);
+
+ Date[] dates = {DocumentHelper.createDate(2014, 3, 31),
+ DocumentHelper.createDate(2017, 1, 23),
+ DocumentHelper.createDate(2017, 6, 18),
+ DocumentHelper.createDate(2019, 11, 22),
+ DocumentHelper.createDate(2020, 9, 7)
+ };
+
+ // Insert a series with a decimal value for each respective date.
+ // The dates will be distributed along a linear X-axis,
+ // and the values added to this series will create data points.
+ chart.getSeries().add("Series 1", dates, new double[]{15.8, 21.5, 22.9, 28.7, 33.1});
+
+ Assert.assertEquals(ChartAxisType.CATEGORY, chart.getAxisX().getType());
+ Assert.assertEquals(ChartAxisType.VALUE, chart.getAxisY().getType());
+
+ // 3 - 2D scatter plot:
+ chart = appendChart(builder, ChartType.SCATTER, 500.0, 300.0);
+
+ // Each series will need two decimal arrays of equal length.
+ // The first array contains X-values, and the second contains corresponding Y-values
+ // of data points on the chart's graph.
+ chart.getSeries().add("Series 1",
+ new double[]{3.1, 3.5, 6.3, 4.1, 2.2, 8.3, 1.2, 3.6},
+ new double[]{3.1, 6.3, 4.6, 0.9, 8.5, 4.2, 2.3, 9.9});
+ chart.getSeries().add("Series 2",
+ new double[]{2.6, 7.3, 4.5, 6.6, 2.1, 9.3, 0.7, 3.3},
+ new double[]{7.1, 6.6, 3.5, 7.8, 7.7, 9.5, 1.3, 4.6});
+
+ Assert.assertEquals(ChartAxisType.VALUE, chart.getAxisX().getType());
+ Assert.assertEquals(ChartAxisType.VALUE, chart.getAxisY().getType());
+
+ // 4 - Bubble chart:
+ chart = appendChart(builder, ChartType.BUBBLE, 500.0, 300.0);
+
+ // Each series will need three decimal arrays of equal length.
+ // The first array contains X-values, the second contains corresponding Y-values,
+ // and the third contains diameters for each of the graph's data points.
+ chart.getSeries().add("Series 1",
+ new double[]{1.1, 5.0, 9.8},
+ new double[]{1.2, 4.9, 9.9},
+ new double[]{2.0, 4.0, 8.0});
+
+ doc.save(getArtifactsDir() + "Charts.ChartSeriesCollection.docx");
+ }
+
+ ///
+ /// Insert a chart using a document builder of a specified ChartType, width and height, and remove its demo data.
+ ///
+ private static Chart appendChart(DocumentBuilder builder, /*ChartType*/int chartType, double width, double height) throws Exception {
+ Shape chartShape = builder.insertChart(chartType, width, height);
+ Chart chart = chartShape.getChart();
+ chart.getSeries().clear();
+ Assert.assertEquals(0, chart.getSeries().getCount()); //ExSkip
+
+ return chart;
+ }
+ //ExEnd
+
+ @Test
+ public void chartSeriesCollectionModify() throws Exception {
+ //ExStart
+ //ExFor:ChartSeriesCollection
+ //ExFor:ChartSeriesCollection.Clear
+ //ExFor:ChartSeriesCollection.Count
+ //ExFor:ChartSeriesCollection.GetEnumerator
+ //ExFor:ChartSeriesCollection.Item(Int32)
+ //ExFor:ChartSeriesCollection.RemoveAt(Int32)
+ //ExSummary:Shows how to add and remove series data in a chart.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert a column chart that will contain three series of demo data by default.
+ Shape chartShape = builder.insertChart(ChartType.COLUMN, 400.0, 300.0);
+ Chart chart = chartShape.getChart();
+
+ // Each series has four decimal values: one for each of the four categories.
+ // Four clusters of three columns will represent this data.
+ ChartSeriesCollection chartData = chart.getSeries();
+
+ Assert.assertEquals(3, chartData.getCount());
+
+ // Print the name of every series in the chart.
+ Iterator enumerator = chart.getSeries().iterator();
+ while (enumerator.hasNext()) {
+ System.out.println(enumerator.next().getName());
+ }
+
+ // These are the names of the categories in the chart.
+ String[] categories = {"Category 1", "Category 2", "Category 3", "Category 4"};
+
+ // We can add a series with new values for existing categories.
+ // This chart will now contain four clusters of four columns.
+ chart.getSeries().add("Series 4", categories, new double[]{4.4, 7.0, 3.5, 2.1});
+ Assert.assertEquals(4, chartData.getCount()); //ExSkip
+ Assert.assertEquals("Series 4", chartData.get(3).getName()); //ExSkip
+
+ // A chart series can also be removed by index, like this.
+ // This will remove one of the three demo series that came with the chart.
+ chartData.removeAt(2);
+
+ Assert.assertFalse(IterableUtils.matchesAny(chartData, s -> s.getName() == "Series 3"));
+ Assert.assertEquals(3, chartData.getCount()); //ExSkip
+ Assert.assertEquals("Series 4", chartData.get(2).getName()); //ExSkip
+
+ // We can also clear all the chart's data at once with this method.
+ // When creating a new chart, this is the way to wipe all the demo data
+ // before we can begin working on a blank chart.
+ chartData.clear();
+ Assert.assertEquals(0, chartData.getCount()); //ExSkip
+
+ //ExEnd
+ }
+
+ @Test
+ public void axisScaling() throws Exception {
+ //ExStart
+ //ExFor:AxisScaleType
+ //ExFor:AxisScaling
+ //ExFor:AxisScaling.LogBase
+ //ExFor:AxisScaling.Type
+ //ExSummary:Shows how to apply logarithmic scaling to a chart axis.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape chartShape = builder.insertChart(ChartType.SCATTER, 450.0, 300.0);
+ Chart chart = chartShape.getChart();
+
+ // Clear the chart's demo data series to start with a clean chart.
+ chart.getSeries().clear();
+
+ // Insert a series with X/Y coordinates for five points.
+ chart.getSeries().add("Series 1",
+ new double[]{1.0, 2.0, 3.0, 4.0, 5.0},
+ new double[]{1.0, 20.0, 400.0, 8000.0, 160000.0});
+
+ // The scaling of the X-axis is linear by default,
+ // displaying evenly incrementing values that cover our X-value range (0, 1, 2, 3...).
+ // A linear axis is not ideal for our Y-values
+ // since the points with the smaller Y-values will be harder to read.
+ // A logarithmic scaling with a base of 20 (1, 20, 400, 8000...)
+ // will spread the plotted points, allowing us to read their values on the chart more easily.
+ chart.getAxisY().getScaling().setType(AxisScaleType.LOGARITHMIC);
+ chart.getAxisY().getScaling().setLogBase(20.0);
+
+ doc.save(getArtifactsDir() + "Charts.AxisScaling.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Charts.AxisScaling.docx");
+ chart = ((Shape) doc.getChild(NodeType.SHAPE, 0, true)).getChart();
+
+ Assert.assertEquals(AxisScaleType.LINEAR, chart.getAxisX().getScaling().getType());
+ Assert.assertEquals(AxisScaleType.LOGARITHMIC, chart.getAxisY().getScaling().getType());
+ Assert.assertEquals(20.0d, chart.getAxisY().getScaling().getLogBase());
+ }
+
+ @Test
+ public void axisBound() throws Exception {
+ //ExStart
+ //ExFor:AxisBound.#ctor
+ //ExFor:AxisBound.IsAuto
+ //ExFor:AxisBound.Value
+ //ExFor:AxisBound.ValueAsDate
+ //ExSummary:Shows how to set custom axis bounds.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape chartShape = builder.insertChart(ChartType.SCATTER, 450.0, 300.0);
+ Chart chart = chartShape.getChart();
+
+ // Clear the chart's demo data series to start with a clean chart.
+ chart.getSeries().clear();
+
+ // Add a series with two decimal arrays. The first array contains the X-values,
+ // and the second contains corresponding Y-values for points in the scatter chart.
+ chart.getSeries().add("Series 1",
+ new double[]{1.1, 5.4, 7.9, 3.5, 2.1, 9.7},
+ new double[]{2.1, 0.3, 0.6, 3.3, 1.4, 1.9});
+
+ // By default, default scaling is applied to the graph's X and Y-axes,
+ // so that both their ranges are big enough to encompass every X and Y-value of every series.
+ Assert.assertTrue(chart.getAxisX().getScaling().getMinimum().isAuto());
+
+ // We can define our own axis bounds.
+ // In this case, we will make both the X and Y-axis rulers show a range of 0 to 10.
+ chart.getAxisX().getScaling().setMinimum(new AxisBound(0.0));
+ chart.getAxisX().getScaling().setMaximum(new AxisBound(10.0));
+ chart.getAxisY().getScaling().setMinimum(new AxisBound(0.0));
+ chart.getAxisY().getScaling().setMaximum(new AxisBound(10.0));
+
+ Assert.assertFalse(chart.getAxisX().getScaling().getMinimum().isAuto());
+ Assert.assertFalse(chart.getAxisY().getScaling().getMinimum().isAuto());
+
+ // Create a line chart with a series requiring a range of dates on the X-axis, and decimal values for the Y-axis.
+ chartShape = builder.insertChart(ChartType.LINE, 450.0, 300.0);
+ chart = chartShape.getChart();
+ chart.getSeries().clear();
+
+ Date[] dates = {DocumentHelper.createDate(1973, 5, 11),
+ DocumentHelper.createDate(1981, 2, 4),
+ DocumentHelper.createDate(1985, 9, 23),
+ DocumentHelper.createDate(1989, 6, 28),
+ DocumentHelper.createDate(1994, 12, 15)
+ };
+
+ chart.getSeries().add("Series 1", dates, new double[]{3.0, 4.7, 5.9, 7.1, 8.9});
+
+ // We can set axis bounds in the form of dates as well, limiting the chart to a period.
+ // Setting the range to 1980-1990 will omit the two of the series values
+ // that are outside of the range from the graph.
+
+ Date datetimeMin = DocumentHelper.createDate(1980, 1, 1);
+ chart.getAxisX().getScaling().setMinimum(new AxisBound(datetimeMin));
+ Date datetimeMax = DocumentHelper.createDate(1980, 1, 1);
+ chart.getAxisX().getScaling().setMaximum(new AxisBound(datetimeMax));
+
+ doc.save(getArtifactsDir() + "Charts.AxisBound.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Charts.AxisBound.docx");
+ chart = ((Shape) doc.getChild(NodeType.SHAPE, 0, true)).getChart();
+
+ Assert.assertFalse(chart.getAxisX().getScaling().getMinimum().isAuto());
+ Assert.assertEquals(0.0d, chart.getAxisX().getScaling().getMinimum().getValue());
+ Assert.assertEquals(10.0d, chart.getAxisX().getScaling().getMaximum().getValue());
+
+ Assert.assertFalse(chart.getAxisY().getScaling().getMinimum().isAuto());
+ Assert.assertEquals(0.0d, chart.getAxisY().getScaling().getMinimum().getValue());
+ Assert.assertEquals(10.0d, chart.getAxisY().getScaling().getMaximum().getValue());
+
+ chart = ((Shape) doc.getChild(NodeType.SHAPE, 1, true)).getChart();
+
+ Assert.assertFalse(chart.getAxisX().getScaling().getMinimum().isAuto());
+ Assert.assertEquals(datetimeMin, chart.getAxisX().getScaling().getMinimum().getValueAsDate());
+ Assert.assertEquals(datetimeMax, chart.getAxisX().getScaling().getMaximum().getValueAsDate());
+
+ Assert.assertTrue(chart.getAxisY().getScaling().getMinimum().isAuto());
+ }
+
+ @Test
+ public void chartLegend() throws Exception {
+ //ExStart
+ //ExFor:Chart.Legend
+ //ExFor:ChartLegend
+ //ExFor:ChartLegend.Overlay
+ //ExFor:ChartLegend.Position
+ //ExFor:LegendPosition
+ //ExSummary:Shows how to edit the appearance of a chart's legend.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.LINE, 450.0, 300.0);
+ Chart chart = shape.getChart();
+
+ Assert.assertEquals(3, chart.getSeries().getCount());
+ Assert.assertEquals("Series 1", chart.getSeries().get(0).getName());
+ Assert.assertEquals("Series 2", chart.getSeries().get(1).getName());
+ Assert.assertEquals("Series 3", chart.getSeries().get(2).getName());
+
+ // Move the chart's legend to the top right corner.
+ ChartLegend legend = chart.getLegend();
+ legend.setPosition(LegendPosition.TOP_RIGHT);
+
+ // Give other chart elements, such as the graph, more room by allowing them to overlap the legend.
+ legend.setOverlay(true);
+
+ doc.save(getArtifactsDir() + "Charts.ChartLegend.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Charts.ChartLegend.docx");
+
+ legend = ((Shape) doc.getChild(NodeType.SHAPE, 0, true)).getChart().getLegend();
+
+ Assert.assertTrue(legend.getOverlay());
+ Assert.assertEquals(LegendPosition.TOP_RIGHT, legend.getPosition());
+ }
+
+ @Test
+ public void axisCross() throws Exception {
+ //ExStart
+ //ExFor:ChartAxis.AxisBetweenCategories
+ //ExFor:ChartAxis.CrossesAt
+ //ExSummary:Shows how to get a graph axis to cross at a custom location.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.COLUMN, 450.0, 250.0);
+ Chart chart = shape.getChart();
+
+ Assert.assertEquals(3, chart.getSeries().getCount());
+ Assert.assertEquals("Series 1", chart.getSeries().get(0).getName());
+ Assert.assertEquals("Series 2", chart.getSeries().get(1).getName());
+ Assert.assertEquals("Series 3", chart.getSeries().get(2).getName());
+
+ // For column charts, the Y-axis crosses at zero by default,
+ // which means that columns for all values below zero point down to represent negative values.
+ // We can set a different value for the Y-axis crossing. In this case, we will set it to 3.
+ ChartAxis axis = chart.getAxisX();
+ axis.setCrosses(AxisCrosses.CUSTOM);
+ axis.setCrossesAt(3.0);
+ axis.setAxisBetweenCategories(true);
+
+ doc.save(getArtifactsDir() + "Charts.AxisCross.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Charts.AxisCross.docx");
+ axis = ((Shape) doc.getChild(NodeType.SHAPE, 0, true)).getChart().getAxisX();
+
+ Assert.assertTrue(axis.getAxisBetweenCategories());
+ Assert.assertEquals(AxisCrosses.CUSTOM, axis.getCrosses());
+ Assert.assertEquals(3.0, axis.getCrossesAt());
+ }
+
+ @Test
+ public void axisDisplayUnit() throws Exception {
+ //ExStart
+ //ExFor:AxisBuiltInUnit
+ //ExFor:ChartAxis.DisplayUnit
+ //ExFor:ChartAxis.MajorUnitIsAuto
+ //ExFor:ChartAxis.MajorUnitScale
+ //ExFor:ChartAxis.MinorUnitIsAuto
+ //ExFor:ChartAxis.MinorUnitScale
+ //ExFor:AxisDisplayUnit
+ //ExFor:AxisDisplayUnit.CustomUnit
+ //ExFor:AxisDisplayUnit.Unit
+ //ExFor:AxisDisplayUnit.Document
+ //ExSummary:Shows how to manipulate the tick marks and displayed values of a chart axis.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.SCATTER, 450.0, 250.0);
+ Chart chart = shape.getChart();
+
+ Assert.assertEquals(1, chart.getSeries().getCount());
+ Assert.assertEquals("Y-Values", chart.getSeries().get(0).getName());
+
+ // Set the minor tick marks of the Y-axis to point away from the plot area,
+ // and the major tick marks to cross the axis.
+ ChartAxis axis = chart.getAxisY();
+ axis.setMajorTickMark(AxisTickMark.CROSS);
+ axis.setMinorTickMark(AxisTickMark.OUTSIDE);
+
+ // Set they Y-axis to show a major tick every 10 units, and a minor tick every 1 unit.
+ axis.setMajorUnit(10.0);
+ axis.setMinorUnit(1.0);
+
+ // Set the Y-axis bounds to -10 and 20.
+ // This Y-axis will now display 4 major tick marks and 27 minor tick marks.
+ axis.getScaling().setMinimum(new AxisBound(-10));
+ axis.getScaling().setMaximum(new AxisBound(20.0));
+
+ // For the X-axis, set the major tick marks at every 10 units,
+ // every minor tick mark at 2.5 units.
+ axis = chart.getAxisX();
+ axis.setMajorUnit(10.0);
+ axis.setMinorUnit(2.5);
+
+ // Configure both types of tick marks to appear inside the graph plot area.
+ axis.setMajorTickMark(AxisTickMark.INSIDE);
+ axis.setMinorTickMark(AxisTickMark.INSIDE);
+
+ // Set the X-axis bounds so that the X-axis spans 5 major tick marks and 12 minor tick marks.
+ axis.getScaling().setMinimum(new AxisBound(-10));
+ axis.getScaling().setMaximum(new AxisBound(30.0));
+ axis.getTickLabels().setAlignment(ParagraphAlignment.RIGHT);
+
+ Assert.assertEquals(1, axis.getTickLabels().getSpacing());
+ Assert.assertEquals(doc, axis.getDisplayUnit().getDocument());
+
+ // Set the tick labels to display their value in millions.
+ axis.getDisplayUnit().setUnit(AxisBuiltInUnit.MILLIONS);
+
+ // We can set a more specific value by which tick labels will display their values.
+ // This statement is equivalent to the one above.
+ axis.getDisplayUnit().setCustomUnit(1000000.0);
+ Assert.assertEquals(AxisBuiltInUnit.CUSTOM, axis.getDisplayUnit().getUnit()); //ExSkip
+
+ doc.save(getArtifactsDir() + "Charts.AxisDisplayUnit.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Charts.AxisDisplayUnit.docx");
+ shape = (Shape) doc.getChild(NodeType.SHAPE, 0, true);
+
+ Assert.assertEquals(450.0d, shape.getWidth());
+ Assert.assertEquals(250.0d, shape.getHeight());
+
+ axis = shape.getChart().getAxisX();
+
+ Assert.assertEquals(AxisTickMark.INSIDE, axis.getMajorTickMark());
+ Assert.assertEquals(AxisTickMark.INSIDE, axis.getMinorTickMark());
+ Assert.assertEquals(10.0d, axis.getMajorUnit());
+ Assert.assertEquals(-10.0d, axis.getScaling().getMinimum().getValue());
+ Assert.assertEquals(30.0d, axis.getScaling().getMaximum().getValue());
+ Assert.assertEquals(1, axis.getTickLabels().getSpacing());
+ Assert.assertEquals(ParagraphAlignment.RIGHT, axis.getTickLabels().getAlignment());
+ Assert.assertEquals(AxisBuiltInUnit.CUSTOM, axis.getDisplayUnit().getUnit());
+ Assert.assertEquals(1000000.0d, axis.getDisplayUnit().getCustomUnit());
+
+ axis = shape.getChart().getAxisY();
+
+ Assert.assertEquals(AxisTickMark.CROSS, axis.getMajorTickMark());
+ Assert.assertEquals(AxisTickMark.OUTSIDE, axis.getMinorTickMark());
+ Assert.assertEquals(10.0d, axis.getMajorUnit());
+ Assert.assertEquals(1.0d, axis.getMinorUnit());
+ Assert.assertEquals(-10.0d, axis.getScaling().getMinimum().getValue());
+ Assert.assertEquals(20.0d, axis.getScaling().getMaximum().getValue());
+ }
+
+ @Test
+ public void markerFormatting() throws Exception
+ {
+ //ExStart
+ //ExFor:ChartDataPoint.Marker
+ //ExFor:ChartMarker.Format
+ //ExFor:ChartFormat.Fill
+ //ExFor:ChartSeries.Marker
+ //ExFor:ChartFormat.Stroke
+ //ExFor:Stroke.ForeColor
+ //ExFor:Stroke.BackColor
+ //ExFor:Stroke.Visible
+ //ExFor:Stroke.Transparency
+ //ExFor:PresetTexture
+ //ExFor:Fill.PresetTextured(PresetTexture)
+ //ExSummary:Show how to set marker formatting.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.SCATTER, 432.0, 252.0);
+ Chart chart = shape.getChart();
+
+ // Delete default generated series.
+ chart.getSeries().clear();
+ ChartSeries series = chart.getSeries().add("AW Series 1", new double[] { 0.7, 1.8, 2.6, 3.9 },
+ new double[] { 2.7, 3.2, 0.8, 1.7 });
+
+ // Set marker formatting.
+ series.getMarker().setSize(40);
+ series.getMarker().setSymbol(MarkerSymbol.SQUARE);
+ ChartDataPointCollection dataPoints = series.getDataPoints();
+ dataPoints.get(0).getMarker().getFormat().getFill().presetTextured(PresetTexture.DENIM);
+ dataPoints.get(0).getMarker().getFormat().getStroke().setForeColor(Color.YELLOW);
+ dataPoints.get(0).getMarker().getFormat().getStroke().setBackColor(Color.RED);
+ dataPoints.get(1).getMarker().getFormat().getFill().presetTextured(PresetTexture.WATER_DROPLETS);
+ dataPoints.get(1).getMarker().getFormat().getStroke().setForeColor(Color.YELLOW);
+ dataPoints.get(1).getMarker().getFormat().getStroke().setVisible(false);
+ dataPoints.get(2).getMarker().getFormat().getFill().presetTextured(PresetTexture.GREEN_MARBLE);
+ dataPoints.get(2).getMarker().getFormat().getStroke().setForeColor(Color.YELLOW);
+ dataPoints.get(3).getMarker().getFormat().getFill().presetTextured(PresetTexture.OAK);
+ dataPoints.get(3).getMarker().getFormat().getStroke().setForeColor(Color.YELLOW);
+ dataPoints.get(3).getMarker().getFormat().getStroke().setTransparency(0.5);
+
+ doc.save(getArtifactsDir() + "Charts.MarkerFormatting.docx");
+ //ExEnd
+ }
+
+ @Test
+ public void seriesColor() throws Exception
+ {
+ //ExStart
+ //ExFor:ChartSeries.Format
+ //ExSummary:Sows how to set series color.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.COLUMN, 432.0, 252.0);
+
+ Chart chart = shape.getChart();
+ ChartSeriesCollection seriesColl = chart.getSeries();
+
+ // Delete default generated series.
+ seriesColl.clear();
+
+ // Create category names array.
+ String[] categories = new String[] { "Category 1", "Category 2" };
+
+ // Adding new series. Value and category arrays must be the same size.
+ ChartSeries series1 = seriesColl.add("Series 1", categories, new double[] { 1.0, 2.0 });
+ ChartSeries series2 = seriesColl.add("Series 2", categories, new double[] { 3.0, 4.0 });
+ ChartSeries series3 = seriesColl.add("Series 3", categories, new double[] { 5.0, 6.0 });
+
+ // Set series color.
+ series1.getFormat().getFill().setForeColor(Color.RED);
+ series2.getFormat().getFill().setForeColor(Color.YELLOW);
+ series3.getFormat().getFill().setForeColor(Color.BLUE);
+
+ doc.save(getArtifactsDir() + "Charts.SeriesColor.docx");
+ //ExEnd
+ }
+
+ @Test
+ public void dataPointsFormatting() throws Exception
+ {
+ //ExStart
+ //ExFor:ChartDataPoint.Format
+ //ExSummary:Shows how to set individual formatting for categories of a column chart.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.COLUMN, 432.0, 252.0);
+ Chart chart = shape.getChart();
+
+ // Delete default generated series.
+ chart.getSeries().clear();
+
+ // Adding new series.
+ ChartSeries series = chart.getSeries().add("Series 1",
+ new String[] { "Category 1", "Category 2", "Category 3", "Category 4" },
+ new double[] { 1.0, 2.0, 3.0, 4.0 });
+
+ // Set column formatting.
+ ChartDataPointCollection dataPoints = series.getDataPoints();
+ dataPoints.get(0).getFormat().getFill().presetTextured(PresetTexture.DENIM);
+ dataPoints.get(1).getFormat().getFill().setForeColor(Color.RED);
+ dataPoints.get(2).getFormat().getFill().setForeColor(Color.YELLOW);
+ dataPoints.get(3).getFormat().getFill().setForeColor(Color.BLUE);
+
+ doc.save(getArtifactsDir() + "Charts.DataPointsFormatting.docx");
+ //ExEnd
+ }
+
+ @Test
+ public void legendEntries() throws Exception
+ {
+ //ExStart
+ //ExFor:ChartLegendEntryCollection
+ //ExFor:ChartLegend.LegendEntries
+ //ExFor:ChartLegendEntry.IsHidden
+ //ExSummary:Shows how to work with a legend entry for chart series.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.COLUMN, 432.0, 252.0);
+
+ Chart chart = shape.getChart();
+ ChartSeriesCollection series = chart.getSeries();
+ series.clear();
+
+ String[] categories = new String[] { "AW Category 1", "AW Category 2" };
+
+ ChartSeries series1 = series.add("Series 1", categories, new double[] { 1.0, 2.0 });
+ series.add("Series 2", categories, new double[] { 3.0, 4.0 });
+ series.add("Series 3", categories, new double[] { 5.0, 6.0 });
+ series.add("Series 4", categories, new double[] { 0.0, 0.0 });
+
+ ChartLegendEntryCollection legendEntries = chart.getLegend().getLegendEntries();
+ legendEntries.get(3).isHidden(true);
+
+ doc.save(getArtifactsDir() + "Charts.LegendEntries.docx");
+ //ExEnd
+ }
+
+ @Test
+ public void legendFont() throws Exception
+ {
+ //ExStart:LegendFont
+ //GistId:66dd22f0854357e394a013b536e2181b
+ //ExFor:ChartLegendEntry
+ //ExFor:ChartLegendEntry.Font
+ //ExFor:ChartLegend.Font
+ //ExFor:ChartSeries.LegendEntry
+ //ExSummary:Shows how to work with a legend font.
+ Document doc = new Document(getMyDir() + "Reporting engine template - Chart series (Java).docx");
+ Chart chart = ((Shape)doc.getChild(NodeType.SHAPE, 0, true)).getChart();
+
+ ChartLegend chartLegend = chart.getLegend();
+ // Set default font size all legend entries.
+ chartLegend.getFont().setSize(14.0);
+ // Change font for specific legend entry.
+ chartLegend.getLegendEntries().get(1).getFont().setItalic(true);
+ chartLegend.getLegendEntries().get(1).getFont().setSize(12.0);
+ // Get legend entry for chart series.
+ ChartLegendEntry legendEntry = chart.getSeries().get(0).getLegendEntry();
+
+ doc.save(getArtifactsDir() + "Charts.LegendFont.docx");
+ //ExEnd:LegendFont
+ }
+
+ @Test
+ public void removeSpecificChartSeries() throws Exception
+ {
+ //ExStart
+ //ExFor:ChartSeries.SeriesType
+ //ExFor:ChartSeriesType
+ //ExSummary:Shows how to remove specific chart serie.
+ Document doc = new Document(getMyDir() + "Reporting engine template - Chart series (Java).docx");
+ Chart chart = ((Shape)doc.getChild(NodeType.SHAPE, 0, true)).getChart();
+
+ // Remove all series of the Column type.
+ for (int i = chart.getSeries().getCount() - 1; i >= 0; i--)
+ {
+ if (chart.getSeries().get(i).getSeriesType() == ChartSeriesType.COLUMN)
+ chart.getSeries().removeAt(i);
+ }
+
+ chart.getSeries().add(
+ "Aspose Series",
+ new String[] { "Category 1", "Category 2", "Category 3", "Category 4" },
+ new double[] { 5.6, 7.1, 2.9, 8.9 });
+
+ doc.save(getArtifactsDir() + "Charts.RemoveSpecificChartSeries.docx");
+ //ExEnd
+ }
+
+ @Test
+ public void populateChartWithData() throws Exception
+ {
+ //ExStart
+ //ExFor:ChartXValue
+ //ExFor:ChartXValue.FromDouble(Double)
+ //ExFor:ChartYValue.FromDouble(Double)
+ //ExFor:ChartSeries.Add(ChartXValue)
+ //ExFor:ChartSeries.Add(ChartXValue, ChartYValue)
+ //ExFor:ChartSeries.Add(ChartXValue, ChartYValue, double)
+ //ExFor:ChartSeries.ClearValues
+ //ExFor:ChartSeries.Clear
+ //ExSummary:Shows how to populate chart series with data.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.COLUMN, 432.0, 252.0);
+ Chart chart = shape.getChart();
+ ChartSeries series1 = chart.getSeries().get(0);
+
+ // Clear X and Y values of the first series.
+ series1.clearValues();
+
+ // Populate the series with data.
+ series1.add(ChartXValue.fromDouble(3.0), ChartYValue.fromDouble(10.0), 10.0);
+ series1.add(ChartXValue.fromDouble(5.0), ChartYValue.fromDouble(5.0));
+ series1.add(ChartXValue.fromDouble(7.0), ChartYValue.fromDouble(11.0));
+ series1.add(ChartXValue.fromDouble(9.0));
+
+ ChartSeries series2 = chart.getSeries().get(1);
+
+ // Clear X and Y values of the second series.
+ series2.clear();
+
+ // Populate the series with data.
+ series2.add(ChartXValue.fromDouble(2.0), ChartYValue.fromDouble(4.0));
+ series2.add(ChartXValue.fromDouble(4.0), ChartYValue.fromDouble(7.0));
+ series2.add(ChartXValue.fromDouble(6.0), ChartYValue.fromDouble(14.0));
+ series2.add(ChartXValue.fromDouble(8.0), ChartYValue.fromDouble(7.0));
+
+ doc.save(getArtifactsDir() + "Charts.PopulateChartWithData.docx");
+ //ExEnd
+ }
+
+ @Test
+ public void getChartSeriesData() throws Exception
+ {
+ //ExStart
+ //ExFor:ChartXValueCollection
+ //ExFor:ChartYValueCollection
+ //ExSummary:Shows how to get chart series data.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder();
+
+ Shape shape = builder.insertChart(ChartType.COLUMN, 432.0, 252.0);
+ Chart chart = shape.getChart();
+ ChartSeries series = chart.getSeries().get(0);
+
+ double minValue = Double.MAX_VALUE;
+ int minValueIndex = 0;
+ double maxValue = -Double.MAX_VALUE;
+ int maxValueIndex = 0;
+
+ for (int i = 0; i < series.getYValues().getCount(); i++)
+ {
+ // Clear individual format of all data points.
+ // Data points and data values are one-to-one in column charts.
+ series.getDataPoints().get(i).clearFormat();
+
+ // Get Y value.
+ double yValue = series.getYValues().get(i).getDoubleValue();
+
+ if (yValue < minValue)
+ {
+ minValue = yValue;
+ minValueIndex = i;
+ }
+
+ if (yValue > maxValue)
+ {
+ maxValue = yValue;
+ maxValueIndex = i;
+ }
+ }
+
+ // Change colors of the max and min values.
+ series.getDataPoints().get(minValueIndex).getFormat().getFill().setForeColor(Color.RED);
+ series.getDataPoints().get(maxValueIndex).getFormat().getFill().setForeColor(Color.GREEN);
+
+ doc.save(getArtifactsDir() + "Charts.GetChartSeriesData.docx");
+ //ExEnd
+ }
+
+ @Test
+ public void chartDataValues() throws Exception
+ {
+ //ExStart
+ //ExFor:ChartXValue.FromString(String)
+ //ExFor:ChartSeries.Remove(Int32)
+ //ExFor:ChartSeries.Add(ChartXValue, ChartYValue)
+ //ExSummary:Shows how to add/remove chart data values.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder();
+
+ Shape shape = builder.insertChart(ChartType.COLUMN, 432.0, 252.0);
+ Chart chart = shape.getChart();
+ ChartSeries department1Series = chart.getSeries().get(0);
+ ChartSeries department2Series = chart.getSeries().get(1);
+
+ // Remove the first value in the both series.
+ department1Series.remove(0);
+ department2Series.remove(0);
+
+ // Add new values to the both series.
+ ChartXValue newXCategory = ChartXValue.fromString("Q1, 2023");
+ department1Series.add(newXCategory, ChartYValue.fromDouble(10.3));
+ department2Series.add(newXCategory, ChartYValue.fromDouble(5.7));
+
+ doc.save(getArtifactsDir() + "Charts.ChartDataValues.docx");
+ //ExEnd
+ }
+
+ @Test
+ public void formatDataLables() throws Exception
+ {
+ //ExStart
+ //ExFor:ChartDataLabelCollection.Format
+ //ExFor:ChartFormat.ShapeType
+ //ExFor:ChartShapeType
+ //ExSummary:Shows how to set fill, stroke and callout formatting for chart data labels.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.COLUMN, 432.0, 252.0);
+ Chart chart = shape.getChart();
+
+ // Delete default generated series.
+ chart.getSeries().clear();
+
+ // Add new series.
+ ChartSeries series = chart.getSeries().add("AW Series 1",
+ new String[] { "AW Category 1", "AW Category 2", "AW Category 3", "AW Category 4" },
+ new double[] { 100.0, 200.0, 300.0, 400.0 });
+
+ // Show data labels.
+ series.hasDataLabels(true);
+ series.getDataLabels().setShowValue(true);
+
+ // Format data labels as callouts.
+ ChartFormat format = series.getDataLabels().getFormat();
+ format.setShapeType(ChartShapeType.WEDGE_RECT_CALLOUT);
+ format.getStroke().setColor(Color.lightGray);
+ format.getFill().solid(Color.GREEN);
+ series.getDataLabels().getFont().setColor(Color.YELLOW);
+
+ // Change fill and stroke of an individual data label.
+ ChartFormat labelFormat = series.getDataLabels().get(0).getFormat();
+ labelFormat.getStroke().setColor(Color.BLUE);
+ labelFormat.getFill().solid(Color.BLUE);
+
+ doc.save(getArtifactsDir() + "Charts.FormatDataLables.docx");
+ //ExEnd
+ }
+
+ @Test
+ public void chartAxisTitle() throws Exception
+ {
+ //ExStart:ChartAxisTitle
+ //GistId:6d898be16b796fcf7448ad3bfe18e51c
+ //ExFor:ChartAxis.Title
+ //ExFor:ChartAxisTitle
+ //ExFor:ChartAxisTitle.Text
+ //ExFor:ChartAxisTitle.Show
+ //ExFor:ChartAxisTitle.Overlay
+ //ExFor:ChartAxisTitle.Font
+ //ExSummary:Shows how to set chart axis title.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.COLUMN, 432.0, 252.0);
+
+ Chart chart = shape.getChart();
+ ChartSeriesCollection seriesColl = chart.getSeries();
+ // Delete default generated series.
+ seriesColl.clear();
+
+ seriesColl.add("AW Series 1", new String[] { "AW Category 1", "AW Category 2" }, new double[] { 1.0, 2.0 });
+
+ // Set axis title.
+ ChartAxisTitle chartAxisXTitle = chart.getAxisX().getTitle();
+ chartAxisXTitle.setText("Categories");
+ chartAxisXTitle.setShow(true);
+ ChartAxisTitle chartAxisYTitle = chart.getAxisY().getTitle();
+ chartAxisYTitle.setText("Values");
+ chartAxisYTitle.setShow(true);
+ chartAxisYTitle.setOverlay(true);
+ chartAxisYTitle.getFont().setSize(12.0);
+ chartAxisYTitle.getFont().setColor(Color.BLUE);
+
+ doc.save(getArtifactsDir() + "Charts.ChartAxisTitle.docx");
+ //ExEnd:ChartAxisTitle
+ }
+
+ @Test (dataProvider = "dataArraysWrongSizeDataProvider")
+ public void dataArraysWrongSize(double[] seriesValue, Class exception) throws Exception
+ {
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.LINE, 500.0, 300.0);
+ ChartSeriesCollection seriesColl = shape.getChart().getSeries();
+ seriesColl.clear();
+
+ String[] categories = { "Word", null, "Excel", "GoogleDocs", "Note", null };
+ if (exception == null)
+ seriesColl.add("AW Series", categories, seriesValue);
+ else
+ Assert.assertThrows(exception, () -> seriesColl.add("AW Series", categories, seriesValue));
+ }
+
+ @DataProvider(name = "dataArraysWrongSizeDataProvider")
+ public static Object[][] dataArraysWrongSizeDataProvider() throws Exception
+ {
+ return new Object[][]
+ {
+ {new double[] { 1.0, 2.0, Double.NaN, 4.0, 5.0, 6.0 }, null},
+ {new double[] { Double.NaN, 4.0, 5.0, Double.NaN, 7.0, 8.0 }, null},
+ {new double[] { Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, 9.0 }, null},
+ {new double[] { Double.NaN, 4.0, 5.0, Double.NaN, Double.NaN }, IllegalArgumentException.class},
+ {new double[] { Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN }, IllegalArgumentException.class},
+ };
+ }
+
+ @Test
+ public void copyDataPointFormat() throws Exception
+ {
+ //ExStart:CopyDataPointFormat
+ //GistId:6d898be16b796fcf7448ad3bfe18e51c
+ //ExFor:ChartSeries.CopyFormatFrom(int)
+ //ExFor:ChartDataPointCollection.HasDefaultFormat(int)
+ //ExFor:ChartDataPointCollection.CopyFormat(int, int)
+ //ExSummary:Shows how to copy data point format.
+ Document doc = new Document(getMyDir() + "DataPoint format.docx");
+
+ // Get the chart and series to update format.
+ Shape shape = (Shape)doc.getChild(NodeType.SHAPE, 0, true);
+ ChartSeries series = shape.getChart().getSeries().get(0);
+ ChartDataPointCollection dataPoints = series.getDataPoints();
+
+ Assert.assertTrue(dataPoints.hasDefaultFormat(0));
+ Assert.assertFalse(dataPoints.hasDefaultFormat(1));
+
+ // Copy format of the data point with index 1 to the data point with index 2
+ // so that the data point 2 looks the same as the data point 1.
+ dataPoints.copyFormat(0, 1);
+
+ Assert.assertTrue(dataPoints.hasDefaultFormat(0));
+ Assert.assertTrue(dataPoints.hasDefaultFormat(1));
+
+ // Copy format of the data point with index 0 to the series defaults so that all data points
+ // in the series that have the default format look the same as the data point 0.
+ series.copyFormatFrom(1);
+
+ Assert.assertTrue(dataPoints.hasDefaultFormat(0));
+ Assert.assertTrue(dataPoints.hasDefaultFormat(1));
+
+ doc.save(getArtifactsDir() + "Charts.CopyDataPointFormat.docx");
+ //ExEnd:CopyDataPointFormat
+ }
+
+ @Test
+ public void resetDataPointFill() throws Exception
+ {
+ //ExStart:ResetDataPointFill
+ //GistId:6d898be16b796fcf7448ad3bfe18e51c
+ //ExFor:ChartFormat.IsDefined
+ //ExFor:ChartFormat.SetDefaultFill
+ //ExSummary:Shows how to reset the fill to the default value defined in the series.
+ Document doc = new Document(getMyDir() + "DataPoint format.docx");
+
+ Shape shape = (Shape)doc.getChild(NodeType.SHAPE, 0, true);
+ ChartSeries series = shape.getChart().getSeries().get(0);
+ ChartDataPoint dataPoint = series.getDataPoints().get(1);
+
+ Assert.assertTrue(dataPoint.getFormat().isDefined());
+
+ dataPoint.getFormat().setDefaultFill();
+
+ doc.save(getArtifactsDir() + "Charts.ResetDataPointFill.docx");
+ //ExEnd:ResetDataPointFill
+ }
+
+ @Test
+ public void dataTable() throws Exception
+ {
+ //ExStart:DataTable
+ //GistId:9c17d666c47318436785490829a3984f
+ //ExFor:Chart.DataTable
+ //ExFor:ChartDataTable
+ //ExFor:ChartDataTable.Show
+ //ExFor:ChartDataTable.Format
+ //ExFor:ChartDataTable.Font
+ //ExFor:ChartDataTable.HasLegendKeys
+ //ExFor:ChartDataTable.HasHorizontalBorder
+ //ExFor:ChartDataTable.HasVerticalBorder
+ //ExFor:ChartDataTable.HasOutlineBorder
+ //ExSummary:Shows how to show data table with chart series data.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.COLUMN, 432.0, 252.0);
+ Chart chart = shape.getChart();
+
+ ChartSeriesCollection series = chart.getSeries();
+ series.clear();
+ double[] xValues = new double[] { 2020.0, 2021.0, 2022.0, 2023.0 };
+ series.add("Series1", xValues, new double[] { 5.0, 11.0, 2.0, 7.0 });
+ series.add("Series2", xValues, new double[] { 6.0, 5.5, 7.0, 7.8 });
+ series.add("Series3", xValues, new double[] { 10.0, 8.0, 7.0, 9.0 });
+
+ ChartDataTable dataTable = chart.getDataTable();
+ dataTable.setShow(true);
+
+ dataTable.hasLegendKeys(false);
+ dataTable.hasHorizontalBorder(false);
+ dataTable.hasVerticalBorder(false);
+ dataTable.hasOutlineBorder(false);
+
+ dataTable.getFont().setItalic(true);
+ dataTable.getFormat().getStroke().setWeight(1.0);
+ dataTable.getFormat().getStroke().setDashStyle(DashStyle.SHORT_DOT);
+ dataTable.getFormat().getStroke().setColor(Color.BLUE);
+
+ doc.save(getArtifactsDir() + "Charts.DataTable.docx");
+ //ExEnd:DataTable
+ }
+
+ @Test
+ public void chartFormat() throws Exception
+ {
+ //ExStart:ChartFormat
+ //GistId:31b7350f8d91d4b12eb43978940d566a
+ //ExFor:ChartFormat
+ //ExFor:Chart.Format
+ //ExFor:ChartTitle.Format
+ //ExFor:ChartAxisTitle.Format
+ //ExFor:ChartLegend.Format
+ //ExFor:Fill.Solid(Color)
+ //ExSummary:Shows how to use chart formating.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.COLUMN, 432.0, 252.0);
+ Chart chart = shape.getChart();
+
+ // Delete series generated by default.
+ ChartSeriesCollection series = chart.getSeries();
+ series.clear();
+
+ String[] categories = new String[] { "Category 1", "Category 2" };
+ series.add("Series 1", categories, new double[] { 1.0, 2.0 });
+ series.add("Series 2", categories, new double[] { 3.0, 4.0 });
+
+ // Format chart background.
+ chart.getFormat().getFill().solid(Color.darkGray);
+
+ // Hide axis tick labels.
+ chart.getAxisX().getTickLabels().setPosition(AxisTickLabelPosition.NONE);
+ chart.getAxisY().getTickLabels().setPosition(AxisTickLabelPosition.NONE);
+
+ // Format chart title.
+ chart.getTitle().getFormat().getFill().solid(Color.yellow);
+
+ // Format axis title.
+ chart.getAxisX().getTitle().setShow(true);
+ chart.getAxisX().getTitle().getFormat().getFill().solid(Color.yellow);
+
+ // Format legend.
+ chart.getLegend().getFormat().getFill().solid(Color.yellow);
+
+ doc.save(getArtifactsDir() + "Charts.ChartFormat.docx");
+ //ExEnd:ChartFormat
+
+ doc = new Document(getArtifactsDir() + "Charts.ChartFormat.docx");
+
+ shape = (Shape)doc.getChild(NodeType.SHAPE, 0, true);
+ chart = shape.getChart();
+
+ Assert.assertEquals(Color.darkGray.getRGB(), chart.getFormat().getFill().getColor().getRGB());
+ Assert.assertEquals(Color.yellow.getRGB(), chart.getTitle().getFormat().getFill().getColor().getRGB());
+ Assert.assertEquals(Color.yellow.getRGB(), chart.getAxisX().getTitle().getFormat().getFill().getColor().getRGB());
+ Assert.assertEquals(Color.yellow.getRGB(), chart.getLegend().getFormat().getFill().getColor().getRGB());
+ }
+
+ @Test
+ public void secondaryAxis() throws Exception
+ {
+ //ExStart:SecondaryAxis
+ //GistId:f99d87e10ab87a581c52206321d8b617
+ //ExFor:ChartSeriesGroup
+ //ExFor:ChartSeriesGroup.SeriesType
+ //ExFor:ChartSeriesGroup.AxisGroup
+ //ExFor:ChartSeriesGroup.AxisX
+ //ExFor:ChartSeriesGroup.AxisY
+ //ExFor:ChartSeriesGroup.Series
+ //ExFor:ChartSeriesGroupCollection
+ //ExFor:ChartSeriesGroupCollection.Add(ChartSeriesType)
+ //ExFor:AxisGroup
+ //ExSummary:Shows how to work with the secondary axis of chart.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.LINE, 450.0, 250.0);
+ Chart chart = shape.getChart();
+ ChartSeriesCollection series = chart.getSeries();
+
+ // Delete default generated series.
+ series.clear();
+
+ String[] categories = new String[] { "Category 1", "Category 2", "Category 3" };
+ series.add("Series 1 of primary series group", categories, new double[] { 2.0, 3.0, 4.0 });
+ series.add("Series 2 of primary series group", categories, new double[] { 5.0, 2.0, 3.0 });
+
+ // Create an additional series group, also of the line type.
+ ChartSeriesGroup newSeriesGroup = chart.getSeriesGroups().add(ChartSeriesType.LINE);
+ // Specify the use of secondary axes for the new series group.
+ newSeriesGroup.setAxisGroup(AxisGroup.SECONDARY);
+ // Hide the secondary X axis.
+ newSeriesGroup.getAxisX().setHidden(true);
+ // Define title of the secondary Y axis.
+ newSeriesGroup.getAxisY().getTitle().setShow(true);
+ newSeriesGroup.getAxisY().getTitle().setText("Secondary Y axis");
+
+ Assert.assertEquals(ChartSeriesType.LINE, newSeriesGroup.getSeriesType());
+
+ // Add a series to the new series group.
+ ChartSeries series3 =
+ newSeriesGroup.getSeries().add("Series of secondary series group", categories, new double[] { 13.0, 11.0, 16.0 });
+ series3.getFormat().getStroke().setWeight(3.5);
+
+ doc.save(getArtifactsDir() + "Charts.SecondaryAxis.docx");
+ //ExEnd:SecondaryAxis
+ }
+
+ @Test
+ public void configureGapOverlap() throws Exception
+ {
+ //ExStart:ConfigureGapOverlap
+ //GistId:f99d87e10ab87a581c52206321d8b617
+ //ExFor:Chart.SeriesGroups
+ //ExFor:ChartSeriesGroup.GapWidth
+ //ExFor:ChartSeriesGroup.Overlap
+ //ExSummary:Show how to configure gap width and overlap.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.COLUMN, 450.0, 250.0);
+ ChartSeriesGroup seriesGroup = shape.getChart().getSeriesGroups().get(0);
+
+ // Set column gap width and overlap.
+ seriesGroup.setGapWidth(450);
+ seriesGroup.setOverlap(-75);
+
+ doc.save(getArtifactsDir() + "Charts.ConfigureGapOverlap.docx");
+ //ExEnd:ConfigureGapOverlap
+ }
+
+ @Test
+ public void bubbleScale() throws Exception
+ {
+ //ExStart:BubbleScale
+ //GistId:f99d87e10ab87a581c52206321d8b617
+ //ExFor:ChartSeriesGroup.BubbleScale
+ //ExSummary:Show how to set size of the bubbles.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert a bubble 3D chart.
+ Shape shape = builder.insertChart(ChartType.BUBBLE_3_D, 450.0, 250.0);
+ ChartSeriesGroup seriesGroup = shape.getChart().getSeriesGroups().get(0);
+
+ // Set bubble scale to 200%.
+ seriesGroup.setBubbleScale(200);
+
+ doc.save(getArtifactsDir() + "Charts.BubbleScale.docx");
+ //ExEnd:BubbleScale
+ }
+
+ @Test
+ public void removeSecondaryAxis() throws Exception
+ {
+ //ExStart:RemoveSecondaryAxis
+ //GistId:f99d87e10ab87a581c52206321d8b617
+ //ExFor:ChartSeriesGroupCollection.Count
+ //ExFor:ChartSeriesGroupCollection.Item(Int32)
+ //ExFor:ChartSeriesGroupCollection.RemoveAt(Int32)
+ //ExSummary:Show how to remove secondary axis.
+ Document doc = new Document(getMyDir() + "Combo chart.docx");
+
+ Shape shape = (Shape)doc.getChild(NodeType.SHAPE, 0, true);
+ Chart chart = shape.getChart();
+ ChartSeriesGroupCollection seriesGroups = chart.getSeriesGroups();
+
+ // Find secondary axis and remove from the collection.
+ for (int i = 0; i < seriesGroups.getCount(); i++)
+ if (seriesGroups.get(i).getAxisGroup() == AxisGroup.SECONDARY)
+ seriesGroups.removeAt(i);
+ //ExEnd:RemoveSecondaryAxis
+ }
+
+ @Test
+ public void treemapChart() throws Exception
+ {
+ //ExStart:TreemapChart
+ //GistId:a76df4b18bee76d169e55cdf6af8129c
+ //ExFor:ChartSeriesCollection.Add(String, ChartMultilevelValue[], double[])
+ //ExFor:ChartMultilevelValue
+ //ExFor:ChartMultilevelValue.#ctor(String, String, String)
+ //ExFor:ChartMultilevelValue.#ctor(String, String)
+ //ExFor:ChartMultilevelValue.#ctor(String)
+ //ExSummary:Shows how to create treemap chart.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert a Treemap chart.
+ Shape shape = builder.insertChart(ChartType.TREEMAP, 450.0, 280.0);
+ Chart chart = shape.getChart();
+ chart.getTitle().setText("World Population");
+
+ // Delete default generated series.
+ chart.getSeries().clear();
+
+ // Add a series.
+ ChartSeries series = chart.getSeries().add(
+ "Population by Region",
+ new ChartMultilevelValue[]
+ {
+ new ChartMultilevelValue("Asia", "China"),
+ new ChartMultilevelValue("Asia", "India"),
+ new ChartMultilevelValue("Asia", "Indonesia"),
+ new ChartMultilevelValue("Asia", "Pakistan"),
+ new ChartMultilevelValue("Asia", "Bangladesh"),
+ new ChartMultilevelValue("Asia", "Japan"),
+ new ChartMultilevelValue("Asia", "Philippines"),
+ new ChartMultilevelValue("Asia", "Other"),
+ new ChartMultilevelValue("Africa", "Nigeria"),
+ new ChartMultilevelValue("Africa", "Ethiopia"),
+ new ChartMultilevelValue("Africa", "Egypt"),
+ new ChartMultilevelValue("Africa", "Other"),
+ new ChartMultilevelValue("Europe", "Russia"),
+ new ChartMultilevelValue("Europe", "Germany"),
+ new ChartMultilevelValue("Europe", "Other"),
+ new ChartMultilevelValue("Latin America", "Brazil"),
+ new ChartMultilevelValue("Latin America", "Mexico"),
+ new ChartMultilevelValue("Latin America", "Other"),
+ new ChartMultilevelValue("Northern America", "United States", "Other"),
+ new ChartMultilevelValue("Northern America", "Other"),
+ new ChartMultilevelValue("Oceania")
+ },
+ new double[]
+ {
+ 1409670000.0, 1400744000.0, 279118866.0, 241499431.0, 169828911.0, 123930000.0, 112892781.0, 764000000.0,
+ 223800000.0, 107334000.0, 105914499.0, 903000000.0,
+ 146150789.0, 84607016.0, 516000000.0,
+ 203080756.0, 129713690.0, 310000000.0,
+ 335893238.0, 35000000.0,
+ 42000000.0
+ });
+
+ // Show data labels.
+ series.hasDataLabels(true);
+ series.getDataLabels().setShowValue(true);
+ series.getDataLabels().setShowCategoryName(true);
+ DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.getDefault());
+ String thousandSeparator = Character.toString(symbols.getGroupingSeparator());
+ series.getDataLabels().getNumberFormat().setFormatCode(String.format("#{0}0", thousandSeparator));
+
+ doc.save(getArtifactsDir() + "Charts.Treemap.docx");
+ //ExEnd:TreemapChart
+ }
+
+ @Test
+ public void sunburstChart() throws Exception
+ {
+ //ExStart:SunburstChart
+ //GistId:a76df4b18bee76d169e55cdf6af8129c
+ //ExFor:ChartSeriesCollection.Add(String, ChartMultilevelValue[], double[])
+ //ExSummary:Shows how to create sunburst chart.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert a Sunburst chart.
+ Shape shape = builder.insertChart(ChartType.SUNBURST, 450.0, 450.0);
+ Chart chart = shape.getChart();
+ chart.getTitle().setText("Sales");
+
+ // Delete default generated series.
+ chart.getSeries().clear();
+
+ // Add a series.
+ ChartSeries series = chart.getSeries().add(
+ "Sales",
+ new ChartMultilevelValue[]
+ {
+ new ChartMultilevelValue("Sales - Europe", "UK", "London Dep."),
+ new ChartMultilevelValue("Sales - Europe", "UK", "Liverpool Dep."),
+ new ChartMultilevelValue("Sales - Europe", "UK", "Manchester Dep."),
+ new ChartMultilevelValue("Sales - Europe", "France", "Paris Dep."),
+ new ChartMultilevelValue("Sales - Europe", "France", "Lyon Dep."),
+ new ChartMultilevelValue("Sales - NA", "USA", "Denver Dep."),
+ new ChartMultilevelValue("Sales - NA", "USA", "Seattle Dep."),
+ new ChartMultilevelValue("Sales - NA", "USA", "Detroit Dep."),
+ new ChartMultilevelValue("Sales - NA", "USA", "Houston Dep."),
+ new ChartMultilevelValue("Sales - NA", "Canada", "Toronto Dep."),
+ new ChartMultilevelValue("Sales - NA", "Canada", "Montreal Dep."),
+ new ChartMultilevelValue("Sales - Oceania", "Australia", "Sydney Dep."),
+ new ChartMultilevelValue("Sales - Oceania", "New Zealand", "Auckland Dep.")
+ },
+ new double[] { 1236.0, 851.0, 536.0, 468.0, 179.0, 527.0, 799.0, 1148.0, 921.0, 457.0, 482.0, 761.0, 694.0 });
+
+ // Show data labels.
+ series.hasDataLabels(true);
+ series.getDataLabels().setShowValue(false);
+ series.getDataLabels().setShowCategoryName(true);
+
+ doc.save(getArtifactsDir() + "Charts.Sunburst.docx");
+ //ExEnd:SunburstChart
+ }
+
+ @Test
+ public void histogramChart() throws Exception
+ {
+ //ExStart:HistogramChart
+ //GistId:a76df4b18bee76d169e55cdf6af8129c
+ //ExFor:ChartSeriesCollection.Add(String, double[])
+ //ExSummary:Shows how to create histogram chart.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert a Histogram chart.
+ Shape shape = builder.insertChart(ChartType.HISTOGRAM, 450.0, 450.0);
+ Chart chart = shape.getChart();
+ chart.getTitle().setText("Avg Temperature since 1991");
+
+ // Delete default generated series.
+ chart.getSeries().clear();
+
+ // Add a series.
+ chart.getSeries().add(
+ "Avg Temperature",
+ new double[]
+ {
+ 51.8, 53.6, 50.3, 54.7, 53.9, 54.3, 53.4, 52.9, 53.3, 53.7, 53.8, 52.0, 55.0, 52.1, 53.4,
+ 53.8, 53.8, 51.9, 52.1, 52.7, 51.8, 56.6, 53.3, 55.6, 56.3, 56.2, 56.1, 56.2, 53.6, 55.7,
+ 56.3, 55.9, 55.6
+ });
+
+ doc.save(getArtifactsDir() + "Charts.Histogram.docx");
+ //ExEnd:HistogramChart
+ }
+
+ @Test
+ public void paretoChart() throws Exception
+ {
+ //ExStart:ParetoChart
+ //GistId:a76df4b18bee76d169e55cdf6af8129c
+ //ExFor:ChartSeriesCollection.Add(String, String[], double[])
+ //ExSummary:Shows how to create pareto chart.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert a Pareto chart.
+ Shape shape = builder.insertChart(ChartType.PARETO, 450.0, 450.0);
+ Chart chart = shape.getChart();
+ chart.getTitle().setText("Best-Selling Car");
+
+ // Delete default generated series.
+ chart.getSeries().clear();
+
+ // Add a series.
+ chart.getSeries().add(
+ "Best-Selling Car",
+ new String[] { "Tesla Model Y", "Toyota Corolla", "Toyota RAV4", "Ford F-Series", "Honda CR-V" },
+ new double[] { 1.43, 0.91, 1.17, 0.98, 0.85 });
+
+ doc.save(getArtifactsDir() + "Charts.Pareto.docx");
+ //ExEnd:ParetoChart
+ }
+
+ @Test
+ public void boxAndWhiskerChart() throws Exception
+ {
+ //ExStart:BoxAndWhiskerChart
+ //GistId:a76df4b18bee76d169e55cdf6af8129c
+ //ExFor:ChartSeriesCollection.Add(String, String[], double[])
+ //ExSummary:Shows how to create box and whisker chart.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert a Box & Whisker chart.
+ Shape shape = builder.insertChart(ChartType.BOX_AND_WHISKER, 450.0, 450.0);
+ Chart chart = shape.getChart();
+ chart.getTitle().setText("Points by Years");
+
+ // Delete default generated series.
+ chart.getSeries().clear();
+
+ // Add a series.
+ ChartSeries series = chart.getSeries().add(
+ "Points by Years",
+ new String[]
+ {
+ "WC", "WC", "WC", "WC", "WC", "WC", "WC", "WC", "WC", "WC",
+ "NR", "NR", "NR", "NR", "NR", "NR", "NR", "NR", "NR", "NR",
+ "NA", "NA", "NA", "NA", "NA", "NA", "NA", "NA", "NA", "NA"
+ },
+ new double[]
+ {
+ 91.0, 80.0, 100.0, 77.0, 90.0, 104.0, 105.0, 118.0, 120.0, 101.0,
+ 114.0, 107.0, 110.0, 60.0, 79.0, 78.0, 77.0, 102.0, 101.0, 113.0,
+ 94.0, 93.0, 84.0, 71.0, 80.0, 103.0, 80.0, 94.0, 100.0, 101.0
+ });
+
+ // Show data labels.
+ series.hasDataLabels(true);
+
+ doc.save(getArtifactsDir() + "Charts.BoxAndWhisker.docx");
+ //ExEnd:BoxAndWhiskerChart
+ }
+
+ @Test
+ public void waterfallChart() throws Exception
+ {
+ //ExStart:WaterfallChart
+ //GistId:a76df4b18bee76d169e55cdf6af8129c
+ //ExFor:ChartSeriesCollection.Add(String, String[], double[], bool[])
+ //ExSummary:Shows how to create waterfall chart.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert a Waterfall chart.
+ Shape shape = builder.insertChart(ChartType.WATERFALL, 450.0, 450.0);
+ Chart chart = shape.getChart();
+ chart.getTitle().setText("New Zealand GDP");
+
+ // Delete default generated series.
+ chart.getSeries().clear();
+
+ // Add a series.
+ ChartSeries series = chart.getSeries().add(
+ "New Zealand GDP",
+ new String[] { "2018", "2019 growth", "2020 growth", "2020", "2021 growth", "2022 growth", "2022" },
+ new double[] { 100.0, 0.57, -0.25, 100.32, 20.22, -2.92, 117.62 },
+ new boolean[] { true, false, false, true, false, false, true });
+
+ // Show data labels.
+ series.hasDataLabels(true);
+
+ doc.save(getArtifactsDir() + "Charts.Waterfall.docx");
+ //ExEnd:WaterfallChart
+ }
+
+ @Test
+ public void funnelChart() throws Exception
+ {
+ //ExStart:FunnelChart
+ //GistId:a76df4b18bee76d169e55cdf6af8129c
+ //ExFor:ChartSeriesCollection.Add(String, String[], double[])
+ //ExSummary:Shows how to create funnel chart.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert a Funnel chart.
+ Shape shape = builder.insertChart(ChartType.FUNNEL, 450.0, 450.0);
+ Chart chart = shape.getChart();
+ chart.getTitle().setText("Population by Age Group");
+
+ // Delete default generated series.
+ chart.getSeries().clear();
+
+ // Add a series.
+ ChartSeries series = chart.getSeries().add(
+ "Population by Age Group",
+ new String[] { "0-9", "10-19", "20-29", "30-39", "40-49", "50-59", "60-69", "70-79", "80-89", "90-" },
+ new double[] { 0.121, 0.128, 0.132, 0.146, 0.124, 0.124, 0.111, 0.075, 0.032, 0.007 });
+
+ // Show data labels.
+ series.hasDataLabels(true);
+ DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.getDefault());
+ String decimalSeparator = Character.toString(symbols.getGroupingSeparator());
+ series.getDataLabels().getNumberFormat().setFormatCode("0" + decimalSeparator + "0%");
+
+ doc.save(getArtifactsDir() + "Charts.Funnel.docx");
+ //ExEnd:FunnelChart
+ }
+
+ @Test
+ public void labelOrientationRotation() throws Exception
+ {
+ //ExStart:LabelOrientationRotation
+ //GistId:67585b023474b7f73b0066dd022cf938
+ //ExFor:ChartDataLabelCollection.Orientation
+ //ExFor:ChartDataLabelCollection.Rotation
+ //ExFor:ChartDataLabel.Rotation
+ //ExFor:ChartDataLabel.Orientation
+ //ExFor:ShapeTextOrientation
+ //ExSummary:Shows how to change orientation and rotation for data labels.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.COLUMN, 432.0, 252.0);
+ ChartSeries series = shape.getChart().getSeries().get(0);
+ ChartDataLabelCollection dataLabels = series.getDataLabels();
+
+ // Show data labels.
+ series.hasDataLabels(true);
+ dataLabels.setShowValue(true);
+ dataLabels.setShowCategoryName(true);
+
+ // Define data label shape.
+ dataLabels.getFormat().setShapeType(ChartShapeType.UP_ARROW);
+ dataLabels.getFormat().getStroke().getFill().solid(Color.blue);
+
+ // Set data label orientation and rotation for the entire series.
+ dataLabels.setOrientation(ShapeTextOrientation.VERTICAL_FAR_EAST);
+ dataLabels.setRotation(-45);
+
+ // Change orientation and rotation of the first data label.
+ dataLabels.get(0).setOrientation(ShapeTextOrientation.HORIZONTAL);
+ dataLabels.get(0).setRotation(45);
+
+ doc.save(getArtifactsDir() + "Charts.LabelOrientationRotation.docx");
+ //ExEnd:LabelOrientationRotation
+ }
+
+ @Test
+ public void tickLabelsOrientationRotation() throws Exception
+ {
+ //ExStart:TickLabelsOrientationRotation
+ //GistId:0ede368e82d1e97d02e615a76923846b
+ //ExFor:AxisTickLabels.Rotation
+ //ExFor:AxisTickLabels.Orientation
+ //ExSummary:Shows how to change orientation and rotation for axis tick labels.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert a column chart.
+ Shape shape = builder.insertChart(ChartType.COLUMN, 432.0, 252.0);
+ AxisTickLabels xTickLabels = shape.getChart().getAxisX().getTickLabels();
+ AxisTickLabels yTickLabels = shape.getChart().getAxisY().getTickLabels();
+
+ // Set axis tick label orientation and rotation.
+ xTickLabels.setOrientation(ShapeTextOrientation.VERTICAL_FAR_EAST);
+ xTickLabels.setRotation(-30);
+ yTickLabels.setOrientation(ShapeTextOrientation.HORIZONTAL);
+ yTickLabels.setRotation(45);
+
+ doc.save(getArtifactsDir() + "Charts.TickLabelsOrientationRotation.docx");
+ //ExEnd:TickLabelsOrientationRotation
+ }
+
+ @Test
+ public void doughnutChart() throws Exception
+ {
+ //ExStart:DoughnutChart
+ //GistId:3f058a176ba0e9f656c60c6d60d757a1
+ //ExFor:ChartSeriesGroup.DoughnutHoleSize
+ //ExFor:ChartSeriesGroup.FirstSliceAngle
+ //ExSummary:Shows how to create and format Doughnut chart.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.DOUGHNUT, 400.0, 400.0);
+ Chart chart = shape.getChart();
+ // Delete the default generated series.
+ chart.getSeries().clear();
+
+ String[] categories = new String[] { "Category 1", "Category 2", "Category 3" };
+ chart.getSeries().add("Series 1", categories, new double[] { 4.0, 2.0, 5.0 });
+
+ // Format the Doughnut chart.
+ ChartSeriesGroup seriesGroup = chart.getSeriesGroups().get(0);
+ seriesGroup.setDoughnutHoleSize(10);
+ seriesGroup.setFirstSliceAngle(270);
+
+ doc.save(getArtifactsDir() + "Charts.DoughnutChart.docx");
+ //ExEnd:DoughnutChart
+ }
+
+ @Test
+ public void pieOfPieChart() throws Exception
+ {
+ //ExStart:PieOfPieChart
+ //GistId:3f058a176ba0e9f656c60c6d60d757a1
+ //ExFor:ChartSeriesGroup.SecondSectionSize
+ //ExSummary:Shows how to create and format pie of Pie chart.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.PIE_OF_PIE, 440.0, 300.0);
+ Chart chart = shape.getChart();
+ // Delete the default generated series.
+ chart.getSeries().clear();
+
+ String[] categories = new String[] { "Category 1", "Category 2", "Category 3", "Category 4" };
+ chart.getSeries().add("Series 1", categories, new double[] { 11.0, 8.0, 4.0, 3.0 });
+
+ // Format the Pie of Pie chart.
+ ChartSeriesGroup seriesGroup = chart.getSeriesGroups().get(0);
+ seriesGroup.setGapWidth(10);
+ seriesGroup.setSecondSectionSize(77);
+
+ doc.save(getArtifactsDir() + "Charts.PieOfPieChart.docx");
+ //ExEnd:PieOfPieChart
+ }
+
+ @Test
+ public void formatCode() throws Exception
+ {
+ //ExStart:FormatCode
+ //GistId:72d57eeddb7fb342fd51b26e5fcf9642
+ //ExFor:ChartXValueCollection.FormatCode
+ //ExFor:ChartYValueCollection.FormatCode
+ //ExFor:BubbleSizeCollection.FormatCode
+ //ExFor:ChartSeries.BubbleSizes
+ //ExFor:ChartSeries.XValues
+ //ExFor:ChartSeries.YValues
+ //ExSummary:Shows how to work with the format code of the chart data.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert a Bubble chart.
+ Shape shape = builder.insertChart(ChartType.BUBBLE, 432.0, 252.0);
+ Chart chart = shape.getChart();
+
+ // Delete default generated series.
+ chart.getSeries().clear();
+
+ ChartSeries series = chart.getSeries().add(
+ "Series1",
+ new double[] { 1.0, 1.9, 2.45, 3.0 },
+ new double[] { 1.0, -0.9, 1.82, 0.0 },
+ new double[] { 2.0, 1.1, 2.95, 2.0 });
+
+ // Show data labels.
+ series.hasDataLabels(true);
+ series.getDataLabels().setShowCategoryName(true);
+ series.getDataLabels().setShowValue(true);
+ series.getDataLabels().setShowBubbleSize(true);
+
+ // Set data format codes.
+ series.getXValues().setFormatCode("#,##0.0#");
+ series.getYValues().setFormatCode("#,##0.0#;[Red]\\-#,##0.0#");
+ series.getBubbleSizes().setFormatCode("#,##0.0#");
+
+ doc.save(getArtifactsDir() + "Charts.FormatCode.docx");
+ //ExEnd:FormatCode
+
+ doc = new Document(getArtifactsDir() + "Charts.FormatCode.docx");
+ shape = (Shape)doc.getChild(NodeType.SHAPE, 0, true);
+ chart = shape.getChart();
+
+ ChartSeriesCollection seriesCollection = chart.getSeries();
+ for (ChartSeries seriesProperties : seriesCollection)
+ {
+ Assert.assertEquals("#,##0.0#", seriesProperties.getXValues().getFormatCode());
+ Assert.assertEquals("#,##0.0#;[Red]\\-#,##0.0#", seriesProperties.getYValues().getFormatCode());
+ Assert.assertEquals("#,##0.0#", seriesProperties.getBubbleSizes().getFormatCode());
+ }
+ }
+
+ @Test
+ public void dataLablePosition() throws Exception
+ {
+ //ExStart:DataLablePosition
+ //GistId:93fefe5344a8337b931d0fed5c028225
+ //ExFor:ChartDataLabelCollection.Position
+ //ExFor:ChartDataLabel.Position
+ //ExFor:ChartDataLabelPosition
+ //ExSummary:Shows how to set the position of the data label.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert column chart.
+ Shape shape = builder.insertChart(ChartType.COLUMN, 432.0, 252.0);
+ Chart chart = shape.getChart();
+ ChartSeriesCollection seriesColl = chart.getSeries();
+
+ // Delete default generated series.
+ seriesColl.clear();
+
+ // Add series.
+ ChartSeries series = seriesColl.add(
+ "Series 1",
+ new String[] { "Category 1", "Category 2", "Category 3" },
+ new double[] { 4.0, 5.0, 6.0 });
+
+ // Show data labels and set font color.
+ series.hasDataLabels(true);
+ ChartDataLabelCollection dataLabels = series.getDataLabels();
+ dataLabels.setShowValue(true);
+ dataLabels.getFont().setColor(Color.WHITE);
+
+ // Set data label position.
+ dataLabels.setPosition(ChartDataLabelPosition.INSIDE_BASE);
+ dataLabels.get(0).setPosition(ChartDataLabelPosition.OUTSIDE_END);
+ dataLabels.get(0).getFont().setColor(Color.RED);
+
+ doc.save(getArtifactsDir() + "Charts.LabelPosition.docx");
+ //ExEnd:DataLablePosition
+ }
+
+ @Test
+ public void doughnutChartLabelPosition() throws Exception
+ {
+ //ExStart:DoughnutChartLabelPosition
+ //GistId:93fefe5344a8337b931d0fed5c028225
+ //ExFor:ChartDataLabel.Left
+ //ExFor:ChartDataLabel.LeftMode
+ //ExFor:ChartDataLabel.Top
+ //ExFor:ChartDataLabel.TopMode
+ //ExFor:ChartDataLabelLocationMode
+ //ExSummary:Shows how to place data labels of doughnut chart outside doughnut.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ final int CHART_WIDTH = 432;
+ final int CHART_HEIGHT = 252;
+ Shape shape = builder.insertChart(ChartType.DOUGHNUT, CHART_WIDTH, CHART_HEIGHT);
+ Chart chart = shape.getChart();
+ ChartSeriesCollection seriesColl = chart.getSeries();
+ // Delete default generated series.
+ seriesColl.clear();
+
+ // Hide the legend.
+ chart.getLegend().setPosition(LegendPosition.NONE);
+
+ // Generate data.
+ final int DATA_LENGTH = 20;
+ double totalValue = 0.0;
+ String[] categories = new String[DATA_LENGTH];
+ double[] values = new double[DATA_LENGTH];
+ for (int i = 0; i < DATA_LENGTH; i++)
+ {
+ categories[i] = MessageFormat.format("Category {0}", i);
+ values[i] = DATA_LENGTH - i;
+ totalValue += values[i];
+ }
+
+ ChartSeries series = seriesColl.add("Series 1", categories, values);
+ series.hasDataLabels(true);
+
+ ChartDataLabelCollection dataLabels = series.getDataLabels();
+ dataLabels.setShowValue(true);
+ dataLabels.setShowLeaderLines(true);
+
+ // The Position property cannot be used for doughnut charts. Let's place data labels using the Left and Top
+ // properties around a circle outside of the chart doughnut.
+ // The origin is in the upper left corner of the chart.
+
+ final double TITLE_AREA_HEIGHT = 25.5; // This can be calculated using title text and font.
+ final double DOUGHNUT_CENTER_Y = TITLE_AREA_HEIGHT + (CHART_HEIGHT - TITLE_AREA_HEIGHT) / 2.0;
+ final double DOUGHNUT_CENTER_X = CHART_WIDTH / 2d;
+ final double LABEL_HEIGHT = 16.5; // This can be calculated using label font.
+ final double ONE_CHAR_LABEL_WIDTH = 12.75; // This can be calculated for each label using its text and font.
+ final double TWO_CHAR_LABEL_WIDTH = 17.25; // This can be calculated for each label using its text and font.
+ final double Y_MARGIN = 0.75;
+ final double LABEL_MARGIN = 1.5;
+ final double LABEL_CIRCLE_RADIUS = CHART_HEIGHT - DOUGHNUT_CENTER_Y - Y_MARGIN - LABEL_HEIGHT / 2.0;
+
+ // Because the data points start at the top, the X coordinates used in the Left and Top properties of
+ // the data labels point to the right and the Y coordinates point down, the starting angle is -PI/2.
+ double totalAngle = -Math.PI / 2f;
+ ChartDataLabel previousLabel = null;
+
+ for (int i = 0; i < series.getYValues().getCount(); i++)
+ {
+ ChartDataLabel dataLabel = dataLabels.get(i);
+
+ double value = series.getYValues().get(i).getDoubleValue();
+ double labelWidth;
+ if (value < 10)
+ labelWidth = ONE_CHAR_LABEL_WIDTH;
+ else
+ labelWidth = TWO_CHAR_LABEL_WIDTH;
+ double labelSegmentAngle = value / totalValue * 2.0 * Math.PI;
+ double labelAngle = labelSegmentAngle / 2.0 + totalAngle;
+ double labelCenterX = LABEL_CIRCLE_RADIUS * Math.cos(labelAngle) + DOUGHNUT_CENTER_X;
+ double labelCenterY = LABEL_CIRCLE_RADIUS * Math.sin(labelAngle) + DOUGHNUT_CENTER_Y;
+ double labelLeft = labelCenterX - labelWidth / 2.0;
+ double labelTop = labelCenterY - LABEL_HEIGHT / 2.0;
+
+ // If the current data label overlaps other labels, move it horizontally.
+ if ((previousLabel != null) &&
+ (Math.abs(previousLabel.getTop() - labelTop) < LABEL_HEIGHT) &&
+ (Math.abs(previousLabel.getLeft() - labelLeft) < labelWidth))
+ {
+ // Move right on the top, left on the bottom.
+ boolean isOnTop = (totalAngle < 0) || (totalAngle >= Math.PI);
+ int factor;
+ if (isOnTop)
+ factor = 1;
+ else
+ factor = -1;
+
+ labelLeft = previousLabel.getLeft() + labelWidth * factor + LABEL_MARGIN;
+ }
+
+ dataLabel.setLeft(labelLeft);
+ dataLabel.setLeftMode(ChartDataLabelLocationMode.ABSOLUTE);
+ dataLabel.setTop(labelTop);
+ dataLabel.setTopMode(ChartDataLabelLocationMode.ABSOLUTE);
+
+ totalAngle += labelSegmentAngle;
+ previousLabel = dataLabel;
+ }
+
+ doc.save(getArtifactsDir() + "Charts.DoughnutChartLabelPosition.docx");
+ //ExEnd:DoughnutChartLabelPosition
+ }
+
+ @Test
+ public void insertChartSeries() throws Exception
+ {
+ //ExStart
+ //ExFor:ChartSeries.Insert(Int32, ChartXValue)
+ //ExFor:ChartSeries.Insert(Int32, ChartXValue, ChartYValue)
+ //ExFor:ChartSeries.Insert(Int32, ChartXValue, ChartYValue, double)
+ //ExSummary:Shows how to insert data into a chart series.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape shape = builder.insertChart(ChartType.LINE, 432.0, 252.0);
+ Chart chart = shape.getChart();
+ ChartSeries series1 = chart.getSeries().get(0);
+
+ // Clear X and Y values of the first series.
+ series1.clearValues();
+ // Populate the series with data.
+ series1.insert(0, ChartXValue.fromDouble(3.0));
+ series1.insert(1, ChartXValue.fromDouble(3.0), ChartYValue.fromDouble(10.0));
+ series1.insert(2, ChartXValue.fromDouble(3.0), ChartYValue.fromDouble(10.0));
+ series1.insert(3, ChartXValue.fromDouble(3.0), ChartYValue.fromDouble(10.0), 10.0);
+
+ doc.save(getArtifactsDir() + "Charts.PopulateChartWithData.docx");
+ //ExEnd
+ }
+
+ @Test
+ public void setChartStyle() throws Exception
+ {
+ //ExStart:SetChartStyle
+ //GistId:b62c3f2b553726aa85992f50f6d39aaa
+ //ExFor:ChartStyle
+ //ExSummary:Shows how to set and get chart style.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert a chart in the Black style.
+ builder.insertChart(ChartType.COLUMN, 400.0, 250.0, ChartStyle.BLACK);
+
+ doc.save(getArtifactsDir() + "Charts.SetChartStyle.docx");
+
+ doc = new Document(getArtifactsDir() + "Charts.SetChartStyle.docx");
+
+ // Get a chart to update.
+ Shape shape = (Shape)doc.getChild(NodeType.SHAPE, 0, true);
+ Chart chart = shape.getChart();
+
+ // Get the chart style.
+ Assert.assertEquals(ChartStyle.BLACK, chart.getStyle());
+ //ExEnd:SetChartStyle
+ }
+}
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ExChmLoadOptions.java b/Examples/ApiExamples/Java/src/main/java/Examples/ExChmLoadOptions.java
new file mode 100644
index 00000000..47c99279
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ExChmLoadOptions.java
@@ -0,0 +1,42 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import org.testng.annotations.Test;
+import com.aspose.words.ChmLoadOptions;
+import com.aspose.words.Document;
+
+import java.io.ByteArrayInputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+@Test
+public class ExChmLoadOptions extends ApiExampleBase
+{
+ @Test
+ public void originalFileName() throws Exception
+ {
+ //ExStart
+ //ExFor:ChmLoadOptions
+ //ExFor:ChmLoadOptions.#ctor
+ //ExFor:ChmLoadOptions.OriginalFileName
+ //ExSummary:Shows how to resolve URLs like "ms-its:myfile.chm::/index.htm".
+ // Our document contains URLs like "ms-its:amhelp.chm::....htm", but it has a different name,
+ // so file links don't work after saving it to HTML.
+ // We need to define the original filename in 'ChmLoadOptions' to avoid this behavior.
+ ChmLoadOptions loadOptions = new ChmLoadOptions(); { loadOptions.setOriginalFileName("amhelp.chm"); }
+
+ Document doc = new Document(new ByteArrayInputStream(Files.readAllBytes(Paths.get(getMyDir() + "Document with ms-its links.chm"))),
+ loadOptions);
+
+ doc.save(getArtifactsDir() + "ExChmLoadOptions.OriginalFileName.html");
+ //ExEnd
+ }
+}
+
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ExCleanupOptions.java b/Examples/ApiExamples/Java/src/main/java/Examples/ExCleanupOptions.java
new file mode 100644
index 00000000..6f767c72
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ExCleanupOptions.java
@@ -0,0 +1,117 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.words.List;
+import com.aspose.words.*;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.awt.*;
+
+public class ExCleanupOptions extends ApiExampleBase {
+ @Test
+ public void removeUnusedResources() throws Exception {
+ //ExStart
+ //ExFor:Document.Cleanup(CleanupOptions)
+ //ExFor:CleanupOptions
+ //ExFor:CleanupOptions.UnusedLists
+ //ExFor:CleanupOptions.UnusedStyles
+ //ExFor:CleanupOptions.UnusedBuiltinStyles
+ //ExSummary:Shows how to remove all unused custom styles from a document.
+ Document doc = new Document();
+
+ doc.getStyles().add(StyleType.LIST, "MyListStyle1");
+ doc.getStyles().add(StyleType.LIST, "MyListStyle2");
+ doc.getStyles().add(StyleType.CHARACTER, "MyParagraphStyle1");
+ doc.getStyles().add(StyleType.CHARACTER, "MyParagraphStyle2");
+
+ // Combined with the built-in styles, the document now has eight styles.
+ // A custom style is marked as "used" while there is any text within the document
+ // formatted in that style. This means that the 4 styles we added are currently unused.
+ Assert.assertEquals(8, doc.getStyles().getCount());
+
+ // Apply a custom character style, and then a custom list style. Doing so will mark them as "used".
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ builder.getFont().setStyle(doc.getStyles().get("MyParagraphStyle1"));
+ builder.writeln("Hello world!");
+
+ List docList = doc.getLists().add(doc.getStyles().get("MyListStyle1"));
+ builder.getListFormat().setList(docList);
+ builder.writeln("Item 1");
+ builder.writeln("Item 2");
+
+ // Now, there is one unused character style and one unused list style.
+ // The Cleanup() method, when configured with a CleanupOptions object, can target unused styles and remove them.
+ CleanupOptions cleanupOptions = new CleanupOptions();
+ cleanupOptions.setUnusedLists(true);
+ cleanupOptions.setUnusedStyles(true);
+ cleanupOptions.setUnusedBuiltinStyles(true);
+
+ doc.cleanup(cleanupOptions);
+
+ Assert.assertEquals(4, doc.getStyles().getCount());
+
+ // Removing every node that a custom style is applied to marks it as "unused" again.
+ // Rerun the Cleanup method to remove them.
+ doc.getFirstSection().getBody().removeAllChildren();
+ doc.cleanup(cleanupOptions);
+
+ Assert.assertEquals(2, doc.getStyles().getCount());
+ //ExEnd
+ }
+
+ @Test
+ public void removeDuplicateStyles() throws Exception {
+ //ExStart
+ //ExFor:CleanupOptions.DuplicateStyle
+ //ExSummary:Shows how to remove duplicated styles from the document.
+ Document doc = new Document();
+
+ // Add two styles to the document with identical properties,
+ // but different names. The second style is considered a duplicate of the first.
+ Style myStyle = doc.getStyles().add(StyleType.PARAGRAPH, "MyStyle1");
+ myStyle.getFont().setSize(14.0);
+ myStyle.getFont().setName("Courier New");
+ myStyle.getFont().setColor(Color.BLUE);
+
+ Style duplicateStyle = doc.getStyles().add(StyleType.PARAGRAPH, "MyStyle2");
+ duplicateStyle.getFont().setSize(14.0);
+ duplicateStyle.getFont().setName("Courier New");
+ duplicateStyle.getFont().setColor(Color.BLUE);
+
+ Assert.assertEquals(6, doc.getStyles().getCount());
+
+ // Apply both styles to different paragraphs within the document.
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ builder.getParagraphFormat().setStyleName(myStyle.getName());
+ builder.writeln("Hello world!");
+
+ builder.getParagraphFormat().setStyleName(duplicateStyle.getName());
+ builder.writeln("Hello again!");
+
+ ParagraphCollection paragraphs = doc.getFirstSection().getBody().getParagraphs();
+
+ Assert.assertEquals(myStyle, paragraphs.get(0).getParagraphFormat().getStyle());
+ Assert.assertEquals(duplicateStyle, paragraphs.get(1).getParagraphFormat().getStyle());
+
+ // Configure a CleanOptions object, then call the Cleanup method to substitute all duplicate styles
+ // with the original and remove the duplicates from the document.
+ CleanupOptions cleanupOptions = new CleanupOptions();
+ cleanupOptions.setDuplicateStyle(true);
+
+ doc.cleanup(cleanupOptions);
+
+ Assert.assertEquals(5, doc.getStyles().getCount());
+ Assert.assertEquals(myStyle, paragraphs.get(0).getParagraphFormat().getStyle());
+ Assert.assertEquals(myStyle, paragraphs.get(1).getParagraphFormat().getStyle());
+ //ExEnd
+ }
+}
+
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ExComment.java b/Examples/ApiExamples/Java/src/main/java/Examples/ExComment.java
new file mode 100644
index 00000000..c5caf9bb
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ExComment.java
@@ -0,0 +1,349 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.words.*;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.text.MessageFormat;
+import java.util.Date;
+
+public class ExComment extends ApiExampleBase {
+ @Test
+ public void addCommentWithReply() throws Exception {
+ //ExStart
+ //ExFor:Comment
+ //ExFor:Comment.SetText(String)
+ //ExFor:Comment.AddReply(String, String, DateTime, String)
+ //ExSummary:Shows how to add a comment to a document, and then reply to it.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Comment comment = new Comment(doc, "John Doe", "J.D.", new Date());
+ comment.setText("My comment.");
+
+ // Place the comment at a node in the document's body.
+ // This comment will show up at the location of its paragraph,
+ // outside the right-side margin of the page, and with a dotted line connecting it to its paragraph.
+ builder.getCurrentParagraph().appendChild(comment);
+
+ // Add a reply, which will show up under its parent comment.
+ comment.addReply("Joe Bloggs", "J.B.", new Date(), "New reply");
+
+ // Comments and replies are both Comment nodes.
+ Assert.assertEquals(2, doc.getChildNodes(NodeType.COMMENT, true).getCount());
+
+ // Comments that do not reply to other comments are "top-level". They have no ancestor comments.
+ Assert.assertNull(comment.getAncestor());
+
+ // Replies have an ancestor top-level comment.
+ Assert.assertEquals(comment, comment.getReplies().get(0).getAncestor());
+
+ doc.save(getArtifactsDir() + "Comment.AddCommentWithReply.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Comment.AddCommentWithReply.docx");
+ Comment docComment = (Comment) doc.getChild(NodeType.COMMENT, 0, true);
+
+ Assert.assertEquals(1, docComment.getCount());
+ Assert.assertEquals(1, comment.getReplies().getCount());
+
+ Assert.assertEquals("\u0005My comment.\r", docComment.getText());
+ Assert.assertEquals("\u0005New reply\r", docComment.getReplies().get(0).getText());
+ }
+
+ @Test
+ public void printAllComments() throws Exception {
+ //ExStart
+ //ExFor:Comment.Ancestor
+ //ExFor:Comment.Author
+ //ExFor:Comment.Replies
+ //ExFor:CompositeNode.GetEnumerator
+ //ExFor:CompositeNode.GetChildNodes(NodeType, Boolean)
+ //ExSummary:Shows how to print all of a document's comments and their replies.
+ Document doc = new Document(getMyDir() + "Comments.docx");
+
+ NodeCollection comments = doc.getChildNodes(NodeType.COMMENT, true);
+ Assert.assertEquals(12, comments.getCount()); //ExSkip
+
+ // If a comment has no ancestor, it is a "top-level" comment as opposed to a reply-type comment.
+ // Print all top-level comments along with any replies they may have.
+ for (Comment comment : (Iterable) comments) {
+ if (comment.getAncestor() == null) {
+ System.out.println("Top-level comment:");
+ System.out.println("\t\"{comment.GetText().Trim()}\", by {comment.Author}");
+ System.out.println("Has {comment.Replies.Count} replies");
+ for (Comment commentReply : comment.getReplies()) {
+ System.out.println("\t\"{commentReply.GetText().Trim()}\", by {commentReply.Author}");
+ }
+ System.out.println();
+ }
+ }
+ //ExEnd
+ }
+
+ @Test
+ public void removeCommentReplies() throws Exception {
+ //ExStart
+ //ExFor:Comment.RemoveAllReplies
+ //ExFor:Comment.RemoveReply(Comment)
+ //ExFor:CommentCollection.Item(Int32)
+ //ExSummary:Shows how to remove comment replies.
+ Document doc = new Document();
+
+ Comment comment = new Comment(doc, "John Doe", "J.D.", new Date());
+ comment.setText("My comment.");
+
+ doc.getFirstSection().getBody().getFirstParagraph().appendChild(comment);
+
+ comment.addReply("Joe Bloggs", "J.B.", new Date(), "New reply");
+ comment.addReply("Joe Bloggs", "J.B.", new Date(), "Another reply");
+
+ Assert.assertEquals(2, comment.getReplies().getCount());
+
+ // Below are two ways of removing replies from a comment.
+ // 1 - Use the "RemoveReply" method to remove replies from a comment individually:
+ comment.removeReply(comment.getReplies().get(0));
+
+ Assert.assertEquals(1, comment.getReplies().getCount());
+
+ // 2 - Use the "RemoveAllReplies" method to remove all replies from a comment at once:
+ comment.removeAllReplies();
+
+ Assert.assertEquals(0, comment.getReplies().getCount());
+ //ExEnd
+ }
+
+ @Test
+ public void done() throws Exception {
+ //ExStart
+ //ExFor:Comment.Done
+ //ExFor:CommentCollection
+ //ExSummary:Shows how to mark a comment as "done".
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ builder.writeln("Helo world!");
+
+ // Insert a comment to point out an error.
+ Comment comment = new Comment(doc, "John Doe", "J.D.", new Date());
+ comment.setText("Fix the spelling error!");
+ doc.getFirstSection().getBody().getFirstParagraph().appendChild(comment);
+
+ // Comments have a "Done" flag, which is set to "false" by default.
+ // If a comment suggests that we make a change within the document,
+ // we can apply the change, and then also set the "Done" flag afterwards to indicate the correction.
+ Assert.assertFalse(comment.getDone());
+
+ doc.getFirstSection().getBody().getFirstParagraph().getRuns().get(0).setText("Hello world!");
+ comment.setDone(true);
+
+ // Comments that are "done" will differentiate themselves
+ // from ones that are not "done" with a faded text color.
+ comment = new Comment(doc, "John Doe", "J.D.", new Date());
+ comment.setText("Add text to this paragraph.");
+ builder.getCurrentParagraph().appendChild(comment);
+
+ doc.save(getArtifactsDir() + "Comment.Done.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Comment.Done.docx");
+ comment = (Comment) doc.getChildNodes(NodeType.COMMENT, true).get(0);
+
+ Assert.assertTrue(comment.getDone());
+ Assert.assertEquals("Fix the spelling error!", comment.getText().trim());
+ Assert.assertEquals("Hello world!", doc.getFirstSection().getBody().getFirstParagraph().getRuns().get(0).getText());
+ }
+
+ //ExStart
+ //ExFor:Comment.Done
+ //ExFor:Comment.#ctor(DocumentBase)
+ //ExFor:Comment.Accept(DocumentVisitor)
+ //ExFor:Comment.AcceptStart(DocumentVisitor)
+ //ExFor:Comment.AcceptEnd(DocumentVisitor)
+ //ExFor:Comment.DateTime
+ //ExFor:Comment.Id
+ //ExFor:Comment.Initial
+ //ExFor:CommentRangeEnd
+ //ExFor:CommentRangeEnd.#ctor(DocumentBase,Int32)
+ //ExFor:CommentRangeEnd.Accept(DocumentVisitor)
+ //ExFor:CommentRangeEnd.Id
+ //ExFor:CommentRangeStart
+ //ExFor:CommentRangeStart.#ctor(DocumentBase,Int32)
+ //ExFor:CommentRangeStart.Accept(DocumentVisitor)
+ //ExFor:CommentRangeStart.Id
+ //ExSummary:Shows how print the contents of all comments and their comment ranges using a document visitor.
+ @Test //ExSkip
+ public void createCommentsAndPrintAllInfo() throws Exception {
+ Document doc = new Document();
+
+ Comment newComment = new Comment(doc);
+ {
+ newComment.setAuthor("VDeryushev");
+ newComment.setInitial("VD");
+ newComment.setDateTime(new Date());
+ }
+
+ newComment.setText("Comment regarding text.");
+
+ // Add text to the document, warp it in a comment range, and then add your comment.
+ Paragraph para = doc.getFirstSection().getBody().getFirstParagraph();
+ para.appendChild(new CommentRangeStart(doc, newComment.getId()));
+ para.appendChild(new Run(doc, "Commented text."));
+ para.appendChild(new CommentRangeEnd(doc, newComment.getId()));
+ para.appendChild(newComment);
+
+ // Add two replies to the comment.
+ newComment.addReply("John Doe", "JD", new Date(), "New reply.");
+ newComment.addReply("John Doe", "JD", new Date(), "Another reply.");
+
+ printAllCommentInfo(doc.getChildNodes(NodeType.COMMENT, true));
+ }
+
+ ///
+ /// Iterates over every top-level comment and prints its comment range, contents, and replies.
+ ///
+ private static void printAllCommentInfo(NodeCollection comments) throws Exception {
+ CommentInfoPrinter commentVisitor = new CommentInfoPrinter();
+
+ // Iterate over all top-level comments. Unlike reply-type comments, top-level comments have no ancestor.
+ for (Comment comment : (Iterable) comments) {
+ if (comment.getAncestor() == null) {
+ // First, visit the start of the comment range.
+ CommentRangeStart commentRangeStart = (CommentRangeStart) comment.getPreviousSibling().getPreviousSibling().getPreviousSibling();
+ commentRangeStart.accept(commentVisitor);
+
+ // Then, visit the comment, and any replies that it may have.
+ comment.accept(commentVisitor);
+
+ for (Comment reply : comment.getReplies())
+ reply.accept(commentVisitor);
+
+ // Finally, visit the end of the comment range, and then print the visitor's text contents.
+ CommentRangeEnd commentRangeEnd = (CommentRangeEnd) comment.getPreviousSibling();
+ commentRangeEnd.accept(commentVisitor);
+
+ System.out.println(commentVisitor.getText());
+ }
+ }
+ }
+
+ ///
+ /// Prints information and contents of all comments and comment ranges encountered in the document.
+ ///
+ public static class CommentInfoPrinter extends DocumentVisitor {
+ public CommentInfoPrinter() {
+ mBuilder = new StringBuilder();
+ mVisitorIsInsideComment = false;
+ }
+
+ ///
+ /// Gets the plain text of the document that was accumulated by the visitor.
+ ///
+ public String getText() {
+ return mBuilder.toString();
+ }
+
+ ///
+ /// Called when a Run node is encountered in the document.
+ ///
+ public int visitRun(Run run) {
+ if (mVisitorIsInsideComment) indentAndAppendLine("[Run] \"" + run.getText() + "\"");
+
+ return VisitorAction.CONTINUE;
+ }
+
+ ///
+ /// Called when a CommentRangeStart node is encountered in the document.
+ ///
+ public int visitCommentRangeStart(CommentRangeStart commentRangeStart) {
+ indentAndAppendLine("[Comment range start] ID: " + commentRangeStart.getId());
+ mDocTraversalDepth++;
+ mVisitorIsInsideComment = true;
+
+ return VisitorAction.CONTINUE;
+ }
+
+ ///
+ /// Called when a CommentRangeEnd node is encountered in the document.
+ ///
+ public int visitCommentRangeEnd(CommentRangeEnd commentRangeEnd) {
+ mDocTraversalDepth--;
+ indentAndAppendLine("[Comment range end] ID: " + commentRangeEnd.getId() + "\n");
+ mVisitorIsInsideComment = false;
+
+ return VisitorAction.CONTINUE;
+ }
+
+ ///
+ /// Called when a Comment node is encountered in the document.
+ ///
+ public int visitCommentStart(Comment comment) {
+ indentAndAppendLine(MessageFormat.format("[Comment start] For comment range ID {0}, By {1} on {2}", comment.getId(),
+ comment.getAuthor(), comment.getDateTime()));
+ mDocTraversalDepth++;
+ mVisitorIsInsideComment = true;
+
+ return VisitorAction.CONTINUE;
+ }
+
+ ///
+ /// Called when the visiting of a Comment node is ended in the document.
+ ///
+ public int visitCommentEnd(Comment comment) {
+ mDocTraversalDepth--;
+ indentAndAppendLine("[Comment end]");
+ mVisitorIsInsideComment = false;
+
+ return VisitorAction.CONTINUE;
+ }
+
+ ///
+ /// Append a line to the StringBuilder and indent it depending on how deep the visitor is into the document tree.
+ ///
+ ///
+ private void indentAndAppendLine(String text) {
+ for (int i = 0; i < mDocTraversalDepth; i++) {
+ mBuilder.append("| ");
+ }
+
+ mBuilder.append(text + "\r\n");
+ }
+
+ private boolean mVisitorIsInsideComment;
+ private int mDocTraversalDepth;
+ private final StringBuilder mBuilder;
+ }
+ //ExEnd
+
+ @Test
+ public void utcDateTime() throws Exception
+ {
+ //ExStart:UtcDateTime
+ //GistId:a76df4b18bee76d169e55cdf6af8129c
+ //ExFor:Comment.DateTimeUtc
+ //ExSummary:Shows how to get UTC date and time.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Date dateTime = new Date();
+ Comment comment = new Comment(doc, "John Doe", "J.D.", dateTime);
+ comment.setText("My comment.");
+
+ builder.getCurrentParagraph().appendChild(comment);
+
+ doc.save(getArtifactsDir() + "Comment.UtcDateTime.docx");
+ doc = new Document(getArtifactsDir() + "Comment.UtcDateTime.docx");
+
+ comment = (Comment)doc.getChild(NodeType.COMMENT, 0, true);
+ // DateTimeUtc return data without milliseconds.
+ Assert.assertEquals(dateTime.toString(), comment.getDateTimeUtc().toString());
+ //ExEnd:UtcDateTime
+ }
+}
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ExCompatibilityOptions.java b/Examples/ApiExamples/Java/src/main/java/Examples/ExCompatibilityOptions.java
new file mode 100644
index 00000000..5f08ea1e
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ExCompatibilityOptions.java
@@ -0,0 +1,391 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.words.CompatibilityOptions;
+import com.aspose.words.Document;
+import com.aspose.words.MsWordVersion;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+
+@Test
+public class ExCompatibilityOptions extends ApiExampleBase
+{
+ //ExStart
+ //ExFor:Compatibility
+ //ExFor:CompatibilityOptions
+ //ExFor:CompatibilityOptions.OptimizeFor(MsWordVersion)
+ //ExFor:Document.CompatibilityOptions
+ //ExFor:MsWordVersion
+ //ExFor:CompatibilityOptions.AdjustLineHeightInTable
+ //ExFor:CompatibilityOptions.AlignTablesRowByRow
+ //ExFor:CompatibilityOptions.AllowSpaceOfSameStyleInTable
+ //ExFor:CompatibilityOptions.ApplyBreakingRules
+ //ExFor:CompatibilityOptions.AutofitToFirstFixedWidthCell
+ //ExFor:CompatibilityOptions.AutoSpaceLikeWord95
+ //ExFor:CompatibilityOptions.BalanceSingleByteDoubleByteWidth
+ //ExFor:CompatibilityOptions.CachedColBalance
+ //ExFor:CompatibilityOptions.ConvMailMergeEsc
+ //ExFor:CompatibilityOptions.DisableOpenTypeFontFormattingFeatures
+ //ExFor:CompatibilityOptions.DisplayHangulFixedWidth
+ //ExFor:CompatibilityOptions.DoNotAutofitConstrainedTables
+ //ExFor:CompatibilityOptions.DoNotBreakConstrainedForcedTable
+ //ExFor:CompatibilityOptions.DoNotBreakWrappedTables
+ //ExFor:CompatibilityOptions.DoNotExpandShiftReturn
+ //ExFor:CompatibilityOptions.DoNotLeaveBackslashAlone
+ //ExFor:CompatibilityOptions.DoNotSnapToGridInCell
+ //ExFor:CompatibilityOptions.DoNotSuppressIndentation
+ //ExFor:CompatibilityOptions.DoNotSuppressParagraphBorders
+ //ExFor:CompatibilityOptions.DoNotUseEastAsianBreakRules
+ //ExFor:CompatibilityOptions.DoNotUseHTMLParagraphAutoSpacing
+ //ExFor:CompatibilityOptions.DoNotUseIndentAsNumberingTabStop
+ //ExFor:CompatibilityOptions.DoNotVertAlignCellWithSp
+ //ExFor:CompatibilityOptions.DoNotVertAlignInTxbx
+ //ExFor:CompatibilityOptions.DoNotWrapTextWithPunct
+ //ExFor:CompatibilityOptions.FootnoteLayoutLikeWW8
+ //ExFor:CompatibilityOptions.ForgetLastTabAlignment
+ //ExFor:CompatibilityOptions.GrowAutofit
+ //ExFor:CompatibilityOptions.LayoutRawTableWidth
+ //ExFor:CompatibilityOptions.LayoutTableRowsApart
+ //ExFor:CompatibilityOptions.LineWrapLikeWord6
+ //ExFor:CompatibilityOptions.MWSmallCaps
+ //ExFor:CompatibilityOptions.NoColumnBalance
+ //ExFor:CompatibilityOptions.NoExtraLineSpacing
+ //ExFor:CompatibilityOptions.NoLeading
+ //ExFor:CompatibilityOptions.NoSpaceRaiseLower
+ //ExFor:CompatibilityOptions.NoTabHangInd
+ //ExFor:CompatibilityOptions.OverrideTableStyleFontSizeAndJustification
+ //ExFor:CompatibilityOptions.PrintBodyTextBeforeHeader
+ //ExFor:CompatibilityOptions.PrintColBlack
+ //ExFor:CompatibilityOptions.SelectFldWithFirstOrLastChar
+ //ExFor:CompatibilityOptions.ShapeLayoutLikeWW8
+ //ExFor:CompatibilityOptions.ShowBreaksInFrames
+ //ExFor:CompatibilityOptions.SpaceForUL
+ //ExFor:CompatibilityOptions.SpacingInWholePoints
+ //ExFor:CompatibilityOptions.SplitPgBreakAndParaMark
+ //ExFor:CompatibilityOptions.SubFontBySize
+ //ExFor:CompatibilityOptions.SuppressBottomSpacing
+ //ExFor:CompatibilityOptions.SuppressSpacingAtTopOfPage
+ //ExFor:CompatibilityOptions.SuppressSpBfAfterPgBrk
+ //ExFor:CompatibilityOptions.SuppressTopSpacing
+ //ExFor:CompatibilityOptions.SuppressTopSpacingWP
+ //ExFor:CompatibilityOptions.SwapBordersFacingPgs
+ //ExFor:CompatibilityOptions.SwapInsideAndOutsideForMirrorIndentsAndRelativePositioning
+ //ExFor:CompatibilityOptions.TransparentMetafiles
+ //ExFor:CompatibilityOptions.TruncateFontHeightsLikeWP6
+ //ExFor:CompatibilityOptions.UICompat97To2003
+ //ExFor:CompatibilityOptions.UlTrailSpace
+ //ExFor:CompatibilityOptions.UnderlineTabInNumList
+ //ExFor:CompatibilityOptions.UseAltKinsokuLineBreakRules
+ //ExFor:CompatibilityOptions.UseAnsiKerningPairs
+ //ExFor:CompatibilityOptions.UseFELayout
+ //ExFor:CompatibilityOptions.UseNormalStyleForList
+ //ExFor:CompatibilityOptions.UsePrinterMetrics
+ //ExFor:CompatibilityOptions.UseSingleBorderforContiguousCells
+ //ExFor:CompatibilityOptions.UseWord2002TableStyleRules
+ //ExFor:CompatibilityOptions.UseWord2010TableStyleRules
+ //ExFor:CompatibilityOptions.UseWord97LineBreakRules
+ //ExFor:CompatibilityOptions.WPJustification
+ //ExFor:CompatibilityOptions.WPSpaceWidth
+ //ExFor:CompatibilityOptions.WrapTrailSpaces
+ //ExSummary:Shows how to optimize the document for different versions of Microsoft Word.
+ @Test //ExSkip
+ public void optimizeFor() throws Exception
+ {
+ Document doc = new Document();
+
+ // This object contains an extensive list of flags unique to each document
+ // that allow us to facilitate backward compatibility with older versions of Microsoft Word.
+ CompatibilityOptions options = doc.getCompatibilityOptions();
+
+ // Print the default settings for a blank document.
+ System.out.println("\nDefault optimization settings:");
+ printCompatibilityOptions(options);
+
+ // We can access these settings in Microsoft Word via "File" -> "Options" -> "Advanced" -> "Compatibility options for...".
+ doc.save(getArtifactsDir() + "CompatibilityOptions.OptimizeFor.DefaultSettings.docx");
+
+ // We can use the OptimizeFor method to ensure optimal compatibility with a specific Microsoft Word version.
+ doc.getCompatibilityOptions().optimizeFor(MsWordVersion.WORD_2010);
+ System.out.println("\nOptimized for Word 2010:");
+ printCompatibilityOptions(options);
+
+ doc.getCompatibilityOptions().optimizeFor(MsWordVersion.WORD_2000);
+ System.out.println("\nOptimized for Word 2000:");
+ printCompatibilityOptions(options);
+ }
+
+ ///
+ /// Groups all flags in a document's compatibility options object by state, then prints each group.
+ ///
+ private static void printCompatibilityOptions(CompatibilityOptions options)
+ {
+ ArrayList enabledOptions = new ArrayList();
+ ArrayList disabledOptions = new ArrayList();
+ addOptionName(options.getAdjustLineHeightInTable(), "AdjustLineHeightInTable", enabledOptions, disabledOptions);
+ addOptionName(options.getAlignTablesRowByRow(), "AlignTablesRowByRow", enabledOptions, disabledOptions);
+ addOptionName(options.getAllowSpaceOfSameStyleInTable(), "AllowSpaceOfSameStyleInTable", enabledOptions, disabledOptions);
+ addOptionName(options.getApplyBreakingRules(), "ApplyBreakingRules", enabledOptions, disabledOptions);
+ addOptionName(options.getAutoSpaceLikeWord95(), "AutoSpaceLikeWord95", enabledOptions, disabledOptions);
+ addOptionName(options.getAutofitToFirstFixedWidthCell(), "AutofitToFirstFixedWidthCell", enabledOptions, disabledOptions);
+ addOptionName(options.getBalanceSingleByteDoubleByteWidth(), "BalanceSingleByteDoubleByteWidth", enabledOptions, disabledOptions);
+ addOptionName(options.getCachedColBalance(), "CachedColBalance", enabledOptions, disabledOptions);
+ addOptionName(options.getConvMailMergeEsc(), "ConvMailMergeEsc", enabledOptions, disabledOptions);
+ addOptionName(options.getDisableOpenTypeFontFormattingFeatures(), "DisableOpenTypeFontFormattingFeatures", enabledOptions, disabledOptions);
+ addOptionName(options.getDisplayHangulFixedWidth(), "DisplayHangulFixedWidth", enabledOptions, disabledOptions);
+ addOptionName(options.getDoNotAutofitConstrainedTables(), "DoNotAutofitConstrainedTables", enabledOptions, disabledOptions);
+ addOptionName(options.getDoNotBreakConstrainedForcedTable(), "DoNotBreakConstrainedForcedTable", enabledOptions, disabledOptions);
+ addOptionName(options.getDoNotBreakWrappedTables(), "DoNotBreakWrappedTables", enabledOptions, disabledOptions);
+ addOptionName(options.getDoNotExpandShiftReturn(), "DoNotExpandShiftReturn", enabledOptions, disabledOptions);
+ addOptionName(options.getDoNotLeaveBackslashAlone(), "DoNotLeaveBackslashAlone", enabledOptions, disabledOptions);
+ addOptionName(options.getDoNotSnapToGridInCell(), "DoNotSnapToGridInCell", enabledOptions, disabledOptions);
+ addOptionName(options.getDoNotSuppressIndentation(), "DoNotSnapToGridInCell", enabledOptions, disabledOptions);
+ addOptionName(options.getDoNotSuppressParagraphBorders(), "DoNotSuppressParagraphBorders", enabledOptions, disabledOptions);
+ addOptionName(options.getDoNotUseEastAsianBreakRules(), "DoNotUseEastAsianBreakRules", enabledOptions, disabledOptions);
+ addOptionName(options.getDoNotUseHTMLParagraphAutoSpacing(), "DoNotUseHTMLParagraphAutoSpacing", enabledOptions, disabledOptions);
+ addOptionName(options.getDoNotUseIndentAsNumberingTabStop(), "DoNotUseIndentAsNumberingTabStop", enabledOptions, disabledOptions);
+ addOptionName(options.getDoNotVertAlignCellWithSp(), "DoNotVertAlignCellWithSp", enabledOptions, disabledOptions);
+ addOptionName(options.getDoNotVertAlignInTxbx(), "DoNotVertAlignInTxbx", enabledOptions, disabledOptions);
+ addOptionName(options.getDoNotWrapTextWithPunct(), "DoNotWrapTextWithPunct", enabledOptions, disabledOptions);
+ addOptionName(options.getFootnoteLayoutLikeWW8(), "FootnoteLayoutLikeWW8", enabledOptions, disabledOptions);
+ addOptionName(options.getForgetLastTabAlignment(), "ForgetLastTabAlignment", enabledOptions, disabledOptions);
+ addOptionName(options.getGrowAutofit(), "GrowAutofit", enabledOptions, disabledOptions);
+ addOptionName(options.getLayoutRawTableWidth(), "LayoutRawTableWidth", enabledOptions, disabledOptions);
+ addOptionName(options.getLayoutTableRowsApart(), "LayoutTableRowsApart", enabledOptions, disabledOptions);
+ addOptionName(options.getLineWrapLikeWord6(), "LineWrapLikeWord6", enabledOptions, disabledOptions);
+ addOptionName(options.getMWSmallCaps(), "MWSmallCaps", enabledOptions, disabledOptions);
+ addOptionName(options.getNoColumnBalance(), "NoColumnBalance", enabledOptions, disabledOptions);
+ addOptionName(options.getNoExtraLineSpacing(), "NoExtraLineSpacing", enabledOptions, disabledOptions);
+ addOptionName(options.getNoLeading(), "NoLeading", enabledOptions, disabledOptions);
+ addOptionName(options.getNoSpaceRaiseLower(), "NoSpaceRaiseLower", enabledOptions, disabledOptions);
+ addOptionName(options.getNoTabHangInd(), "NoTabHangInd", enabledOptions, disabledOptions);
+ addOptionName(options.getOverrideTableStyleFontSizeAndJustification(), "OverrideTableStyleFontSizeAndJustification", enabledOptions, disabledOptions);
+ addOptionName(options.getPrintBodyTextBeforeHeader(), "PrintBodyTextBeforeHeader", enabledOptions, disabledOptions);
+ addOptionName(options.getPrintColBlack(), "PrintColBlack", enabledOptions, disabledOptions);
+ addOptionName(options.getSelectFldWithFirstOrLastChar(), "SelectFldWithFirstOrLastChar", enabledOptions, disabledOptions);
+ addOptionName(options.getShapeLayoutLikeWW8(), "ShapeLayoutLikeWW8", enabledOptions, disabledOptions);
+ addOptionName(options.getShowBreaksInFrames(), "ShowBreaksInFrames", enabledOptions, disabledOptions);
+ addOptionName(options.getSpaceForUL(), "SpaceForUL", enabledOptions, disabledOptions);
+ addOptionName(options.getSpacingInWholePoints(), "SpacingInWholePoints", enabledOptions, disabledOptions);
+ addOptionName(options.getSplitPgBreakAndParaMark(), "SplitPgBreakAndParaMark", enabledOptions, disabledOptions);
+ addOptionName(options.getSubFontBySize(), "SubFontBySize", enabledOptions, disabledOptions);
+ addOptionName(options.getSuppressBottomSpacing(), "SuppressBottomSpacing", enabledOptions, disabledOptions);
+ addOptionName(options.getSuppressSpBfAfterPgBrk(), "SuppressSpBfAfterPgBrk", enabledOptions, disabledOptions);
+ addOptionName(options.getSuppressSpacingAtTopOfPage(), "SuppressSpacingAtTopOfPage", enabledOptions, disabledOptions);
+ addOptionName(options.getSuppressTopSpacing(), "SuppressTopSpacing", enabledOptions, disabledOptions);
+ addOptionName(options.getSuppressTopSpacingWP(), "SuppressTopSpacingWP", enabledOptions, disabledOptions);
+ addOptionName(options.getSwapBordersFacingPgs(), "SwapBordersFacingPgs", enabledOptions, disabledOptions);
+ addOptionName(options.getSwapInsideAndOutsideForMirrorIndentsAndRelativePositioning(), "SwapInsideAndOutsideForMirrorIndentsAndRelativePositioning", enabledOptions, disabledOptions);
+ addOptionName(options.getTransparentMetafiles(), "TransparentMetafiles", enabledOptions, disabledOptions);
+ addOptionName(options.getTruncateFontHeightsLikeWP6(), "TruncateFontHeightsLikeWP6", enabledOptions, disabledOptions);
+ addOptionName(options.getUICompat97To2003(), "UICompat97To2003", enabledOptions, disabledOptions);
+ addOptionName(options.getUlTrailSpace(), "UlTrailSpace", enabledOptions, disabledOptions);
+ addOptionName(options.getUnderlineTabInNumList(), "UnderlineTabInNumList", enabledOptions, disabledOptions);
+ addOptionName(options.getUseAltKinsokuLineBreakRules(), "UseAltKinsokuLineBreakRules", enabledOptions, disabledOptions);
+ addOptionName(options.getUseAnsiKerningPairs(), "UseAnsiKerningPairs", enabledOptions, disabledOptions);
+ addOptionName(options.getUseFELayout(), "UseFELayout", enabledOptions, disabledOptions);
+ addOptionName(options.getUseNormalStyleForList(), "UseNormalStyleForList", enabledOptions, disabledOptions);
+ addOptionName(options.getUsePrinterMetrics(), "UsePrinterMetrics", enabledOptions, disabledOptions);
+ addOptionName(options.getUseSingleBorderforContiguousCells(), "UseSingleBorderforContiguousCells", enabledOptions, disabledOptions);
+ addOptionName(options.getUseWord2002TableStyleRules(), "UseWord2002TableStyleRules", enabledOptions, disabledOptions);
+ addOptionName(options.getUseWord2010TableStyleRules(), "UseWord2010TableStyleRules", enabledOptions, disabledOptions);
+ addOptionName(options.getUseWord97LineBreakRules(), "UseWord97LineBreakRules", enabledOptions, disabledOptions);
+ addOptionName(options.getWPJustification(), "WPJustification", enabledOptions, disabledOptions);
+ addOptionName(options.getWPSpaceWidth(), "WPSpaceWidth", enabledOptions, disabledOptions);
+ addOptionName(options.getWrapTrailSpaces(), "WrapTrailSpaces", enabledOptions, disabledOptions);
+ System.out.println("\tEnabled options:");
+ for (String optionName : enabledOptions)
+ System.out.println("\t\t{optionName}");
+ System.out.println("\tDisabled options:");
+ for (String optionName : disabledOptions)
+ System.out.println("\t\t{optionName}");
+ }
+
+ private static void addOptionName(boolean option, String optionName, ArrayList enabledOptions, ArrayList disabledOptions)
+ {
+ if (option)
+ enabledOptions.add(optionName);
+ else
+ disabledOptions.add(optionName);
+ }
+ //ExEnd
+
+ @Test
+ public void tables() throws Exception {
+ Document doc = new Document();
+
+ CompatibilityOptions compatibilityOptions = doc.getCompatibilityOptions();
+ compatibilityOptions.optimizeFor(MsWordVersion.WORD_2002);
+
+ Assert.assertEquals(false, compatibilityOptions.getAdjustLineHeightInTable());
+ Assert.assertEquals(false, compatibilityOptions.getAlignTablesRowByRow());
+ Assert.assertEquals(true, compatibilityOptions.getAllowSpaceOfSameStyleInTable());
+ Assert.assertEquals(true, compatibilityOptions.getDoNotAutofitConstrainedTables());
+ Assert.assertEquals(true, compatibilityOptions.getDoNotBreakConstrainedForcedTable());
+ Assert.assertEquals(false, compatibilityOptions.getDoNotBreakWrappedTables());
+ Assert.assertEquals(false, compatibilityOptions.getDoNotSnapToGridInCell());
+ Assert.assertEquals(false, compatibilityOptions.getDoNotUseHTMLParagraphAutoSpacing());
+ Assert.assertEquals(true, compatibilityOptions.getDoNotVertAlignCellWithSp());
+ Assert.assertEquals(false, compatibilityOptions.getForgetLastTabAlignment());
+ Assert.assertEquals(true, compatibilityOptions.getGrowAutofit());
+ Assert.assertEquals(false, compatibilityOptions.getLayoutRawTableWidth());
+ Assert.assertEquals(false, compatibilityOptions.getLayoutTableRowsApart());
+ Assert.assertEquals(false, compatibilityOptions.getNoColumnBalance());
+ Assert.assertEquals(false, compatibilityOptions.getOverrideTableStyleFontSizeAndJustification());
+ Assert.assertEquals(false, compatibilityOptions.getUseSingleBorderforContiguousCells());
+ Assert.assertEquals(true, compatibilityOptions.getUseWord2002TableStyleRules());
+ Assert.assertEquals(false, compatibilityOptions.getUseWord2010TableStyleRules());
+
+ // In the output document, these settings can be accessed in Microsoft Word via
+ // File -> Options -> Advanced -> Compatibility options for...
+ doc.save(getArtifactsDir() + "CompatibilityOptions.Tables.docx");
+ }
+
+ @Test
+ public void breaks() throws Exception {
+ Document doc = new Document();
+
+ CompatibilityOptions compatibilityOptions = doc.getCompatibilityOptions();
+ compatibilityOptions.optimizeFor(MsWordVersion.WORD_2000);
+
+ Assert.assertEquals(false, compatibilityOptions.getApplyBreakingRules());
+ Assert.assertEquals(true, compatibilityOptions.getDoNotUseEastAsianBreakRules());
+ Assert.assertEquals(false, compatibilityOptions.getShowBreaksInFrames());
+ Assert.assertEquals(true, compatibilityOptions.getSplitPgBreakAndParaMark());
+ Assert.assertEquals(true, compatibilityOptions.getUseAltKinsokuLineBreakRules());
+ Assert.assertEquals(false, compatibilityOptions.getUseWord97LineBreakRules());
+
+ // In the output document, these settings can be accessed in Microsoft Word via
+ // File -> Options -> Advanced -> Compatibility options for...
+ doc.save(getArtifactsDir() + "CompatibilityOptions.Breaks.docx");
+ }
+
+ @Test
+ public void spacing() throws Exception {
+ Document doc = new Document();
+
+ CompatibilityOptions compatibilityOptions = doc.getCompatibilityOptions();
+ compatibilityOptions.optimizeFor(MsWordVersion.WORD_2000);
+
+ Assert.assertEquals(false, compatibilityOptions.getAutoSpaceLikeWord95());
+ Assert.assertEquals(true, compatibilityOptions.getDisplayHangulFixedWidth());
+ Assert.assertEquals(false, compatibilityOptions.getNoExtraLineSpacing());
+ Assert.assertEquals(false, compatibilityOptions.getNoLeading());
+ Assert.assertEquals(false, compatibilityOptions.getNoSpaceRaiseLower());
+ Assert.assertEquals(false, compatibilityOptions.getSpaceForUL());
+ Assert.assertEquals(false, compatibilityOptions.getSpacingInWholePoints());
+ Assert.assertEquals(false, compatibilityOptions.getSuppressBottomSpacing());
+ Assert.assertEquals(false, compatibilityOptions.getSuppressSpBfAfterPgBrk());
+ Assert.assertEquals(false, compatibilityOptions.getSuppressSpacingAtTopOfPage());
+ Assert.assertEquals(false, compatibilityOptions.getSuppressTopSpacing());
+ Assert.assertEquals(false, compatibilityOptions.getUlTrailSpace());
+
+ // In the output document, these settings can be accessed in Microsoft Word via
+ // File -> Options -> Advanced -> Compatibility options for...
+ doc.save(getArtifactsDir() + "CompatibilityOptions.Spacing.docx");
+ }
+
+ @Test
+ public void wordPerfect() throws Exception {
+ Document doc = new Document();
+
+ CompatibilityOptions compatibilityOptions = doc.getCompatibilityOptions();
+ compatibilityOptions.optimizeFor(MsWordVersion.WORD_2000);
+
+ Assert.assertEquals(false, compatibilityOptions.getSuppressTopSpacingWP());
+ Assert.assertEquals(false, compatibilityOptions.getTruncateFontHeightsLikeWP6());
+ Assert.assertEquals(false, compatibilityOptions.getWPJustification());
+ Assert.assertEquals(false, compatibilityOptions.getWPSpaceWidth());
+ Assert.assertEquals(false, compatibilityOptions.getWrapTrailSpaces());
+
+ // In the output document, these settings can be accessed in Microsoft Word via
+ // File -> Options -> Advanced -> Compatibility options for...
+ doc.save(getArtifactsDir() + "CompatibilityOptions.WordPerfect.docx");
+ }
+
+ @Test
+ public void alignment() throws Exception {
+ Document doc = new Document();
+
+ CompatibilityOptions compatibilityOptions = doc.getCompatibilityOptions();
+ compatibilityOptions.optimizeFor(MsWordVersion.WORD_2000);
+
+ Assert.assertEquals(true, compatibilityOptions.getCachedColBalance());
+ Assert.assertEquals(true, compatibilityOptions.getDoNotVertAlignInTxbx());
+ Assert.assertEquals(true, compatibilityOptions.getDoNotWrapTextWithPunct());
+ Assert.assertEquals(false, compatibilityOptions.getNoTabHangInd());
+
+ // In the output document, these settings can be accessed in Microsoft Word via
+ // File -> Options -> Advanced -> Compatibility options for...
+ doc.save(getArtifactsDir() + "CompatibilityOptions.Alignment.docx");
+ }
+
+ @Test
+ public void legacy() throws Exception {
+ Document doc = new Document();
+
+ CompatibilityOptions compatibilityOptions = doc.getCompatibilityOptions();
+ compatibilityOptions.optimizeFor(MsWordVersion.WORD_2000);
+
+ Assert.assertEquals(false, compatibilityOptions.getFootnoteLayoutLikeWW8());
+ Assert.assertEquals(false, compatibilityOptions.getLineWrapLikeWord6());
+ Assert.assertEquals(false, compatibilityOptions.getMWSmallCaps());
+ Assert.assertEquals(false, compatibilityOptions.getShapeLayoutLikeWW8());
+ Assert.assertEquals(false, compatibilityOptions.getUICompat97To2003());
+
+ // In the output document, these settings can be accessed in Microsoft Word via
+ // File -> Options -> Advanced -> Compatibility options for...
+ doc.save(getArtifactsDir() + "CompatibilityOptions.Legacy.docx");
+ }
+
+ @Test
+ public void list() throws Exception {
+ Document doc = new Document();
+
+ CompatibilityOptions compatibilityOptions = doc.getCompatibilityOptions();
+ compatibilityOptions.optimizeFor(MsWordVersion.WORD_2000);
+
+ Assert.assertEquals(true, compatibilityOptions.getUnderlineTabInNumList());
+ Assert.assertEquals(true, compatibilityOptions.getUseNormalStyleForList());
+
+ // In the output document, these settings can be accessed in Microsoft Word via
+ // File -> Options -> Advanced -> Compatibility options for...
+ doc.save(getArtifactsDir() + "CompatibilityOptions.List.docx");
+ }
+
+ @Test
+ public void misc() throws Exception {
+ Document doc = new Document();
+
+ CompatibilityOptions compatibilityOptions = doc.getCompatibilityOptions();
+ compatibilityOptions.optimizeFor(MsWordVersion.WORD_2000);
+
+ Assert.assertEquals(false, compatibilityOptions.getBalanceSingleByteDoubleByteWidth());
+ Assert.assertEquals(false, compatibilityOptions.getConvMailMergeEsc());
+ Assert.assertEquals(false, compatibilityOptions.getDoNotExpandShiftReturn());
+ Assert.assertEquals(false, compatibilityOptions.getDoNotLeaveBackslashAlone());
+ Assert.assertEquals(false, compatibilityOptions.getDoNotSuppressParagraphBorders());
+ Assert.assertEquals(true, compatibilityOptions.getDoNotUseIndentAsNumberingTabStop());
+ Assert.assertEquals(false, compatibilityOptions.getPrintBodyTextBeforeHeader());
+ Assert.assertEquals(false, compatibilityOptions.getPrintColBlack());
+ Assert.assertEquals(true, compatibilityOptions.getSelectFldWithFirstOrLastChar());
+ Assert.assertEquals(false, compatibilityOptions.getSubFontBySize());
+ Assert.assertEquals(false, compatibilityOptions.getSwapBordersFacingPgs());
+ Assert.assertEquals(false, compatibilityOptions.getTransparentMetafiles());
+ Assert.assertEquals(true, compatibilityOptions.getUseAnsiKerningPairs());
+ Assert.assertEquals(false, compatibilityOptions.getUseFELayout());
+ Assert.assertEquals(false, compatibilityOptions.getUsePrinterMetrics());
+
+ // In the output document, these settings can be accessed in Microsoft Word via
+ // File -> Options -> Advanced -> Compatibility options for...
+ doc.save(getArtifactsDir() + "CompatibilityOptions.Misc.docx");
+ }
+}
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ExControlChar.java b/Examples/ApiExamples/Java/src/main/java/Examples/ExControlChar.java
new file mode 100644
index 00000000..67adda9e
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ExControlChar.java
@@ -0,0 +1,139 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.words.*;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.text.MessageFormat;
+
+@Test
+public class ExControlChar extends ApiExampleBase {
+ @Test
+ public void carriageReturn() throws Exception {
+ //ExStart
+ //ExFor:ControlChar
+ //ExFor:ControlChar.Cr
+ //ExFor:Node.GetText
+ //ExSummary:Shows how to use control characters.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert paragraphs with text with DocumentBuilder.
+ builder.writeln("Hello world!");
+ builder.writeln("Hello again!");
+
+ // Converting the document to text form reveals that control characters
+ // represent some of the document's structural elements, such as page breaks.
+ Assert.assertEquals(MessageFormat.format("Hello world!{0}", ControlChar.CR) +
+ MessageFormat.format("Hello again!{0}", ControlChar.CR) +
+ ControlChar.PAGE_BREAK, doc.getText());
+
+ // When converting a document to string form,
+ // we can omit some of the control characters with the Trim method.
+ Assert.assertEquals(MessageFormat.format("Hello world!{0}", ControlChar.CR) +
+ "Hello again!", doc.getText().trim());
+ //ExEnd
+ }
+
+ @Test
+ public void insertControlChars() throws Exception {
+ //ExStart
+ //ExFor:ControlChar.Cell
+ //ExFor:ControlChar.ColumnBreak
+ //ExFor:ControlChar.CrLf
+ //ExFor:ControlChar.Lf
+ //ExFor:ControlChar.LineBreak
+ //ExFor:ControlChar.LineFeed
+ //ExFor:ControlChar.NonBreakingSpace
+ //ExFor:ControlChar.PageBreak
+ //ExFor:ControlChar.ParagraphBreak
+ //ExFor:ControlChar.SectionBreak
+ //ExFor:ControlChar.CellChar
+ //ExFor:ControlChar.ColumnBreakChar
+ //ExFor:ControlChar.DefaultTextInputChar
+ //ExFor:ControlChar.FieldEndChar
+ //ExFor:ControlChar.FieldStartChar
+ //ExFor:ControlChar.FieldSeparatorChar
+ //ExFor:ControlChar.LineBreakChar
+ //ExFor:ControlChar.LineFeedChar
+ //ExFor:ControlChar.NonBreakingHyphenChar
+ //ExFor:ControlChar.NonBreakingSpaceChar
+ //ExFor:ControlChar.OptionalHyphenChar
+ //ExFor:ControlChar.PageBreakChar
+ //ExFor:ControlChar.ParagraphBreakChar
+ //ExFor:ControlChar.SectionBreakChar
+ //ExFor:ControlChar.SpaceChar
+ //ExSummary:Shows how to add various control characters to a document.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Add a regular space.
+ builder.write("Before space." + ControlChar.SPACE_CHAR + "After space.");
+
+ // Add an NBSP, which is a non-breaking space.
+ // Unlike the regular space, this space cannot have an automatic line break at its position.
+ builder.write("Before space." + ControlChar.NON_BREAKING_SPACE + "After space.");
+
+ // Add a tab character.
+ builder.write("Before tab." + ControlChar.TAB + "After tab.");
+
+ // Add a line break.
+ builder.write("Before line break." + ControlChar.LINE_BREAK + "After line break.");
+
+ // Add a new line and starts a new paragraph.
+ Assert.assertEquals(1, doc.getFirstSection().getBody().getChildNodes(NodeType.PARAGRAPH, true).getCount());
+ builder.write("Before line feed." + ControlChar.LINE_FEED + "After line feed.");
+ Assert.assertEquals(2, doc.getFirstSection().getBody().getChildNodes(NodeType.PARAGRAPH, true).getCount());
+
+ // The line feed character has two versions.
+ Assert.assertEquals(ControlChar.LINE_FEED, ControlChar.LF);
+
+ // Carriage returns and line feeds can be represented together by one character.
+ Assert.assertEquals(ControlChar.CR_LF, ControlChar.CR + ControlChar.LF);
+
+ // Add a paragraph break, which will start a new paragraph.
+ builder.write("Before paragraph break." + ControlChar.PARAGRAPH_BREAK + "After paragraph break.");
+ Assert.assertEquals(doc.getFirstSection().getBody().getChildNodes(NodeType.PARAGRAPH, true).getCount(), 3);
+
+ // Add a section break. This does not make a new section or paragraph.
+ Assert.assertEquals(doc.getSections().getCount(), 1);
+ builder.write("Before section break." + ControlChar.SECTION_BREAK + "After section break.");
+ Assert.assertEquals(doc.getSections().getCount(), 1);
+
+ // Add a page break.
+ builder.write("Before page break." + ControlChar.PAGE_BREAK + "After page break.");
+
+ // A page break is the same value as a section break.
+ Assert.assertEquals(ControlChar.PAGE_BREAK, ControlChar.SECTION_BREAK);
+
+ // Insert a new section, and then set its column count to two.
+ doc.appendChild(new Section(doc));
+ builder.moveToSection(1);
+ builder.getCurrentSection().getPageSetup().getTextColumns().setCount(2);
+
+ // We can use a control character to mark the point where text moves to the next column.
+ builder.write("Text at end of column 1." + ControlChar.COLUMN_BREAK + "Text at beginning of column 2.");
+
+ doc.save(getArtifactsDir() + "ControlChar.InsertControlChars.docx");
+
+ // There are char and string counterparts for most characters.
+ Assert.assertEquals(ControlChar.CELL.toCharArray()[0], ControlChar.CELL_CHAR);
+ Assert.assertEquals(ControlChar.NON_BREAKING_SPACE.toCharArray()[0], ControlChar.NON_BREAKING_SPACE_CHAR);
+ Assert.assertEquals(ControlChar.TAB.toCharArray()[0], ControlChar.TAB_CHAR);
+ Assert.assertEquals(ControlChar.LINE_BREAK.toCharArray()[0], ControlChar.LINE_BREAK_CHAR);
+ Assert.assertEquals(ControlChar.LINE_FEED.toCharArray()[0], ControlChar.LINE_FEED_CHAR);
+ Assert.assertEquals(ControlChar.PARAGRAPH_BREAK.toCharArray()[0], ControlChar.PARAGRAPH_BREAK_CHAR);
+ Assert.assertEquals(ControlChar.SECTION_BREAK.toCharArray()[0], ControlChar.SECTION_BREAK_CHAR);
+ Assert.assertEquals(ControlChar.PAGE_BREAK.toCharArray()[0], ControlChar.SECTION_BREAK_CHAR);
+ Assert.assertEquals(ControlChar.COLUMN_BREAK.toCharArray()[0], ControlChar.COLUMN_BREAK_CHAR);
+ //ExEnd
+ }
+}
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ExDigitalSignatureCollection.java b/Examples/ApiExamples/Java/src/main/java/Examples/ExDigitalSignatureCollection.java
new file mode 100644
index 00000000..dbfd2325
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ExDigitalSignatureCollection.java
@@ -0,0 +1,62 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.words.DigitalSignature;
+import com.aspose.words.DigitalSignatureCollection;
+import com.aspose.words.DigitalSignatureType;
+import com.aspose.words.DigitalSignatureUtil;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.Iterator;
+
+public class ExDigitalSignatureCollection extends ApiExampleBase {
+ @Test
+ public void iterator() throws Exception {
+ //ExStart
+ //ExFor:DigitalSignatureCollection.GetEnumerator
+ //ExSummary:Shows how to print all the digital signatures of a signed document.
+ DigitalSignatureCollection digitalSignatures =
+ DigitalSignatureUtil.loadSignatures(getMyDir() + "Digitally signed.docx");
+
+ Iterator enumerator = digitalSignatures.iterator();
+ while (enumerator.hasNext()) {
+ DigitalSignature ds = enumerator.next();
+
+ if (ds != null)
+ System.out.println(ds.toString());
+ }
+ //ExEnd
+
+ Assert.assertEquals(1, digitalSignatures.getCount());
+
+ DigitalSignature signature = digitalSignatures.get(0);
+
+ Assert.assertTrue(signature.isValid());
+ Assert.assertEquals(DigitalSignatureType.XML_DSIG, signature.getSignatureType());
+ Assert.assertEquals("Test Sign", signature.getComments());
+
+ Assert.assertEquals(signature.getIssuerName(), signature.getIssuerName());
+ Assert.assertEquals(signature.getSubjectName(), signature.getSubjectName());
+
+ Assert.assertEquals("CN=VeriSign Class 3 Code Signing 2009-2 CA, " +
+ "OU=Terms of use at https://www.verisign.com/rpa (c)09, " +
+ "OU=VeriSign Trust Network, " +
+ "O=\"VeriSign, Inc.\", " +
+ "C=US", signature.getIssuerName());
+
+ Assert.assertEquals("CN=Aspose Pty Ltd, " +
+ "OU=Digital ID Class 3 - Microsoft Software Validation v2, " +
+ "O=Aspose Pty Ltd, " +
+ "L=Lane Cove, " +
+ "S=New South Wales, " +
+ "C=AU", signature.getSubjectName());
+ }
+}
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ExDigitalSignatureUtil.java b/Examples/ApiExamples/Java/src/main/java/Examples/ExDigitalSignatureUtil.java
new file mode 100644
index 00000000..d7c3467a
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ExDigitalSignatureUtil.java
@@ -0,0 +1,249 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.words.*;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Date;
+
+public class ExDigitalSignatureUtil extends ApiExampleBase {
+ @Test
+ public void load() throws Exception {
+ //ExStart
+ //ExFor:DigitalSignatureUtil
+ //ExFor:DigitalSignatureUtil.LoadSignatures(String)
+ //ExFor:DigitalSignatureUtil.LoadSignatures(Stream)
+ //ExSummary:Shows how to load signatures from a digitally signed document.
+ // There are two ways of loading a signed document's collection of digital signatures using the DigitalSignatureUtil class.
+ // 1 - Load from a document from a local file system filename:
+ DigitalSignatureCollection digitalSignatures =
+ DigitalSignatureUtil.loadSignatures(getMyDir() + "Digitally signed.docx");
+
+ // If this collection is nonempty, then we can verify that the document is digitally signed.
+ Assert.assertEquals(1, digitalSignatures.getCount());
+
+ // 2 - Load from a document from a FileStream:
+ InputStream stream = new FileInputStream(getMyDir() + "Digitally signed.docx");
+ try {
+ digitalSignatures = DigitalSignatureUtil.loadSignatures(stream);
+ Assert.assertEquals(1, digitalSignatures.getCount());
+ } finally {
+ if (stream != null) stream.close();
+ }
+ //ExEnd
+ }
+
+ @Test
+ public void remove() throws Exception {
+ //ExStart
+ //ExFor:DigitalSignatureUtil
+ //ExFor:DigitalSignatureUtil.LoadSignatures(String)
+ //ExFor:DigitalSignatureUtil.RemoveAllSignatures(Stream, Stream)
+ //ExFor:DigitalSignatureUtil.RemoveAllSignatures(String, String)
+ //ExSummary:Shows how to remove digital signatures from a digitally signed document.
+ // There are two ways of using the DigitalSignatureUtil class to remove digital signatures
+ // from a signed document by saving an unsigned copy of it somewhere else in the local file system.
+ // 1 - Determine the locations of both the signed document and the unsigned copy by filename strings:
+ DigitalSignatureUtil.removeAllSignatures(getMyDir() + "Digitally signed.docx",
+ getArtifactsDir() + "DigitalSignatureUtil.LoadAndRemove.FromString.docx");
+
+ // 2 - Determine the locations of both the signed document and the unsigned copy by file streams:
+ InputStream streamIn = new FileInputStream(getMyDir() + "Digitally signed.docx");
+ try {
+ OutputStream streamOut = new FileOutputStream(getArtifactsDir() + "DigitalSignatureUtil.LoadAndRemove.FromStream.docx");
+ try {
+ DigitalSignatureUtil.removeAllSignatures(streamIn, streamOut);
+ } finally {
+ if (streamOut != null) streamOut.close();
+ }
+ } finally {
+ if (streamIn != null) streamIn.close();
+ }
+
+ // Verify that both our output documents have no digital signatures.
+ Assert.assertEquals(DigitalSignatureUtil.loadSignatures(getArtifactsDir() + "DigitalSignatureUtil.LoadAndRemove.FromString.docx").getCount(), 0);
+ Assert.assertEquals(DigitalSignatureUtil.loadSignatures(getArtifactsDir() + "DigitalSignatureUtil.LoadAndRemove.FromStream.docx").getCount(), 0);
+ //ExEnd
+ }
+
+ @Test
+ public void removeSignatures() throws Exception
+ {
+ DigitalSignatureUtil.removeAllSignatures(getMyDir() + "Digitally signed.odt",
+ getArtifactsDir() + "DigitalSignatureUtil.RemoveSignatures.odt");
+
+ Assert.assertEquals(DigitalSignatureUtil.loadSignatures(getArtifactsDir() + "DigitalSignatureUtil.RemoveSignatures.odt").getCount(), 0);
+ }
+
+ @Test(description = "WORDSNET-16868, WORDSJAVA-2406", enabled = false)
+ public void signDocument() throws Exception {
+ //ExStart
+ //ExFor:CertificateHolder
+ //ExFor:CertificateHolder.Create(String, String)
+ //ExFor:DigitalSignatureUtil.Sign(Stream, Stream, CertificateHolder, SignOptions)
+ //ExFor:DigitalSignatures.SignOptions
+ //ExFor:SignOptions.Comments
+ //ExFor:SignOptions.SignTime
+ //ExSummary:Shows how to digitally sign documents.
+ // Create an X.509 certificate from a PKCS#12 store, which should contain a private key.
+ CertificateHolder certificateHolder = CertificateHolder.create(getMyDir() + "morzal.pfx", "aw");
+
+ // Create a comment and date which will be applied with our new digital signature.
+ SignOptions signOptions = new SignOptions();
+ {
+ signOptions.setComments("My comment");
+ signOptions.setSignTime(new Date());
+ }
+
+ // Take an unsigned document from the local file system via a file stream,
+ // then create a signed copy of it determined by the filename of the output file stream.
+ InputStream streamIn = new FileInputStream(getMyDir() + "Document.docx");
+ try {
+ OutputStream streamOut = new FileOutputStream(getArtifactsDir() + "DigitalSignatureUtil.SignDocument.docx");
+ try {
+ DigitalSignatureUtil.sign(streamIn, streamOut, certificateHolder, signOptions);
+ } finally {
+ if (streamOut != null) streamOut.close();
+ }
+ } finally {
+ if (streamIn != null) streamIn.close();
+ }
+ //ExEnd
+
+ InputStream stream = new FileInputStream(getArtifactsDir() + "DigitalSignatureUtil.SignDocument.docx");
+ try {
+ DigitalSignatureCollection digitalSignatures = DigitalSignatureUtil.loadSignatures(stream);
+ Assert.assertEquals(1, digitalSignatures.getCount());
+
+ DigitalSignature signature = digitalSignatures.get(0);
+
+ Assert.assertTrue(signature.isValid());
+ Assert.assertEquals(DigitalSignatureType.XML_DSIG, signature.getSignatureType());
+ Assert.assertEquals(signOptions.getSignTime().toString(), signature.getSignTime().toString());
+ Assert.assertEquals("My comment", signature.getComments());
+ } finally {
+ if (stream != null) stream.close();
+ }
+ }
+
+ @Test(description = "WORDSNET-16868")
+ public void decryptionPassword() throws Exception {
+ //ExStart
+ //ExFor:CertificateHolder
+ //ExFor:SignOptions.DecryptionPassword
+ //ExFor:LoadOptions.Password
+ //ExSummary:Shows how to sign encrypted document file.
+ // Create an X.509 certificate from a PKCS#12 store, which should contain a private key.
+ CertificateHolder certificateHolder = CertificateHolder.create(getMyDir() + "morzal.pfx", "aw");
+
+ // Create a comment, date, and decryption password which will be applied with our new digital signature.
+ SignOptions signOptions = new SignOptions();
+ {
+ signOptions.setComments("Comment");
+ signOptions.setSignTime(new Date());
+ signOptions.setDecryptionPassword("docPassword");
+ }
+
+ // Set a local system filename for the unsigned input document, and an output filename for its new digitally signed copy.
+ String inputFileName = getMyDir() + "Encrypted.docx";
+ String outputFileName = getArtifactsDir() + "DigitalSignatureUtil.DecryptionPassword.docx";
+
+ DigitalSignatureUtil.sign(inputFileName, outputFileName, certificateHolder, signOptions);
+ //ExEnd
+
+ // Open encrypted document from a file.
+ LoadOptions loadOptions = new LoadOptions("docPassword");
+ Assert.assertEquals(signOptions.getDecryptionPassword(), loadOptions.getPassword());
+
+ // Check that encrypted document was successfully signed.
+ Document signedDoc = new Document(outputFileName, loadOptions);
+ DigitalSignatureCollection signatures = signedDoc.getDigitalSignatures();
+
+ Assert.assertEquals(1, signatures.getCount());
+ Assert.assertTrue(signatures.isValid());
+ }
+
+ @Test(description = "WORDSNET-13036, WORDSNET-16868")
+ public void signDocumentObfuscationBug() throws Exception {
+ CertificateHolder ch = CertificateHolder.create(getMyDir() + "morzal.pfx", "aw");
+
+ Document doc = new Document(getMyDir() + "Structured document tags.docx");
+ String outputFileName = getArtifactsDir() + "DigitalSignatureUtil.SignDocumentObfuscationBug.doc";
+
+ SignOptions signOptions = new SignOptions();
+ signOptions.setComments("Comment");
+ signOptions.setSignTime(new Date());
+
+ DigitalSignatureUtil.sign(doc.getOriginalFileName(), outputFileName, ch, signOptions);
+ }
+
+ @Test(description = "WORDSNET-16868")
+ public void incorrectDecryptionPassword() throws Exception {
+ CertificateHolder certificateHolder = CertificateHolder.create(getMyDir() + "morzal.pfx", "aw");
+
+ Document doc = new Document(getMyDir() + "Encrypted.docx", new LoadOptions("docPassword"));
+ String outputFileName = getArtifactsDir() + "DigitalSignatureUtil.IncorrectDecryptionPassword.docx";
+
+ SignOptions signOptions = new SignOptions();
+ {
+ signOptions.setComments("Comment");
+ signOptions.setSignTime(new Date());
+ signOptions.setDecryptionPassword("docPassword1");
+ }
+
+ Assert.assertThrows(IncorrectPasswordException.class, () -> DigitalSignatureUtil.sign(doc.getOriginalFileName(), outputFileName, certificateHolder, signOptions));
+ }
+
+ @Test
+ public void noArgumentsForSing() {
+ SignOptions signOptions = new SignOptions();
+
+ signOptions.setComments("");
+ signOptions.setSignTime(new Date());
+ signOptions.setDecryptionPassword("");
+
+ Assert.assertThrows(IllegalArgumentException.class, () -> DigitalSignatureUtil.sign("", "", null, signOptions));
+ }
+
+ @Test
+ public void noCertificateForSign() throws Exception {
+ Document doc = new Document(getMyDir() + "Digitally signed.docx");
+
+ SignOptions signOptions = new SignOptions();
+ signOptions.setComments("Comment");
+ signOptions.setSignTime(new Date());
+ signOptions.setDecryptionPassword("docPassword");
+
+ Assert.assertThrows(NullPointerException.class, () -> DigitalSignatureUtil.sign(doc.getOriginalFileName(),
+ getArtifactsDir() + "DigitalSignatureUtil.NoCertificateForSign.docx", null, signOptions));
+ }
+
+ @Test
+ public void xmlDsig() throws Exception
+ {
+ //ExStart:XmlDsig
+ //GistId:6280fd6c1c1854468bea095ec2af902b
+ //ExFor:SignOptions.XmlDsigLevel
+ //ExFor:XmlDsigLevel
+ //ExSummary:Shows how to sign document based on XML-DSig standard.
+ CertificateHolder certificateHolder = CertificateHolder.create(getMyDir() + "morzal.pfx", "aw");
+ SignOptions signOptions = new SignOptions(); { signOptions.setXmlDsigLevel(XmlDsigLevel.X_AD_ES_EPES); }
+
+ String inputFileName = getMyDir() + "Document.docx";
+ String outputFileName = getArtifactsDir() + "DigitalSignatureUtil.XmlDsig.docx";
+ DigitalSignatureUtil.sign(inputFileName, outputFileName, certificateHolder, signOptions);
+ //ExEnd:XmlDsig
+ }
+}
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ExDocSaveOptions.java b/Examples/ApiExamples/Java/src/main/java/Examples/ExDocSaveOptions.java
new file mode 100644
index 00000000..b724f9cd
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ExDocSaveOptions.java
@@ -0,0 +1,200 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.words.*;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.util.Calendar;
+import java.util.Date;
+
+@Test
+public class ExDocSaveOptions extends ApiExampleBase {
+ @Test
+ public void saveAsDoc() throws Exception {
+ //ExStart
+ //ExFor:DocSaveOptions
+ //ExFor:DocSaveOptions.#ctor
+ //ExFor:DocSaveOptions.#ctor(SaveFormat)
+ //ExFor:DocSaveOptions.Password
+ //ExFor:DocSaveOptions.SaveFormat
+ //ExFor:DocSaveOptions.SaveRoutingSlip
+ //ExFor:IncorrectPasswordException
+ //ExSummary:Shows how to set save options for older Microsoft Word formats.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ builder.write("Hello world!");
+
+ DocSaveOptions options = new DocSaveOptions(SaveFormat.DOC);
+
+ // Set a password which will protect the loading of the document by Microsoft Word or Aspose.Words.
+ // Note that this does not encrypt the contents of the document in any way.
+ options.setPassword("MyPassword");
+
+ // If the document contains a routing slip, we can preserve it while saving by setting this flag to true.
+ options.setSaveRoutingSlip(true);
+
+ doc.save(getArtifactsDir() + "DocSaveOptions.SaveAsDoc.doc", options);
+
+ // To be able to load the document,
+ // we will need to apply the password we specified in the DocSaveOptions object in a LoadOptions object.
+ Assert.assertThrows(IncorrectPasswordException.class, () -> new Document(getArtifactsDir() + "DocSaveOptions.SaveAsDoc.doc"));
+
+ LoadOptions loadOptions = new LoadOptions("MyPassword");
+ doc = new Document(getArtifactsDir() + "DocSaveOptions.SaveAsDoc.doc", loadOptions);
+
+ Assert.assertEquals("Hello world!", doc.getText().trim());
+ //ExEnd
+ }
+
+ @Test
+ public void tempFolder() throws Exception {
+ //ExStart
+ //ExFor:SaveOptions.TempFolder
+ //ExSummary:Shows how to use the hard drive instead of memory when saving a document.
+ Document doc = new Document(getMyDir() + "Rendering.docx");
+
+ // When we save a document, various elements are temporarily stored in memory as the save operation is taking place.
+ // We can use this option to use a temporary folder in the local file system instead,
+ // which will reduce our application's memory overhead.
+ DocSaveOptions options = new DocSaveOptions();
+ options.setTempFolder(getArtifactsDir() + "TempFiles");
+
+ // The specified temporary folder must exist in the local file system before the save operation.
+ new File(options.getTempFolder()).mkdir();
+
+ doc.save(getArtifactsDir() + "DocSaveOptions.TempFolder.doc", options);
+
+ // The folder will persist with no residual contents from the load operation.
+ Assert.assertEquals(new File(options.getTempFolder()).listFiles().length, 0);
+ //ExEnd
+ }
+
+ @Test
+ public void pictureBullets() throws Exception {
+ //ExStart
+ //ExFor:DocSaveOptions.SavePictureBullet
+ //ExSummary:Shows how to omit PictureBullet data from the document when saving.
+ Document doc = new Document(getMyDir() + "Image bullet points.docx");
+ Assert.assertNotNull(doc.getLists().get(0).getListLevels().get(0).getImageData()); //ExSkip
+
+ // Some word processors, such as Microsoft Word 97, are incompatible with PictureBullet data.
+ // By setting a flag in the SaveOptions object,
+ // we can convert all image bullet points to ordinary bullet points while saving.
+ DocSaveOptions saveOptions = new DocSaveOptions(SaveFormat.DOC);
+ saveOptions.setSavePictureBullet(false);
+
+ doc.save(getArtifactsDir() + "DocSaveOptions.PictureBullets.doc", saveOptions);
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocSaveOptions.PictureBullets.doc");
+
+ Assert.assertNull(doc.getLists().get(0).getListLevels().get(0).getImageData());
+ }
+
+ @Test(dataProvider = "updateLastPrintedPropertyDataProvider")
+ public void updateLastPrintedProperty(boolean isUpdateLastPrintedProperty) throws Exception {
+ //ExStart
+ //ExFor:SaveOptions.UpdateLastPrintedProperty
+ //ExSummary:Shows how to update a document's "Last printed" property when saving.
+ Document doc = new Document();
+
+ Calendar calendar = Calendar.getInstance();
+ calendar.set(2019, 11, 20);
+ doc.getBuiltInDocumentProperties().setLastPrinted(calendar.getTime());
+
+ // This flag determines whether the last printed date, which is a built-in property, is updated.
+ // If so, then the date of the document's most recent save operation
+ // with this SaveOptions object passed as a parameter is used as the print date.
+ DocSaveOptions saveOptions = new DocSaveOptions();
+ saveOptions.setUpdateLastPrintedProperty(isUpdateLastPrintedProperty);
+
+ // In Microsoft Word 2003, this property can be found via File -> Properties -> Statistics -> Printed.
+ // It can also be displayed in the document's body by using a PRINTDATE field.
+ doc.save(getArtifactsDir() + "DocSaveOptions.UpdateLastPrintedProperty.doc", saveOptions);
+ //ExEnd
+ }
+
+ @DataProvider(name = "updateLastPrintedPropertyDataProvider")
+ public static Object[][] updateLastPrintedPropertyDataProvider() {
+ return new Object[][]
+ {
+ {true},
+ {false},
+ };
+ }
+
+ @Test (dataProvider = "updateCreatedTimePropertyDataProvider")
+ public void updateCreatedTimeProperty(boolean isUpdateCreatedTimeProperty) throws Exception
+ {
+ //ExStart
+ //ExFor:SaveOptions.UpdateCreatedTimeProperty
+ //ExSummary:Shows how to update a document's "CreatedTime" property when saving.
+ Document doc = new Document();
+
+ Calendar calendar = Calendar.getInstance();
+ calendar.set(2019, 11, 20);
+ doc.getBuiltInDocumentProperties().setCreatedTime(calendar.getTime());
+
+ // This flag determines whether the created time, which is a built-in property, is updated.
+ // If so, then the date of the document's most recent save operation
+ // with this SaveOptions object passed as a parameter is used as the created time.
+ DocSaveOptions saveOptions = new DocSaveOptions();
+ saveOptions.setUpdateCreatedTimeProperty(isUpdateCreatedTimeProperty);
+
+ doc.save(getArtifactsDir() + "DocSaveOptions.UpdateCreatedTimeProperty.docx", saveOptions);
+ //ExEnd
+ }
+
+ @DataProvider(name = "updateCreatedTimePropertyDataProvider")
+ public static Object[][] updateCreatedTimePropertyDataProvider() {
+ return new Object[][]
+ {
+ {true},
+ {false},
+ };
+ }
+
+ @Test(dataProvider = "alwaysCompressMetafilesDataProvider")
+ public void alwaysCompressMetafiles(boolean compressAllMetafiles) throws Exception {
+ //ExStart
+ //ExFor:DocSaveOptions.AlwaysCompressMetafiles
+ //ExSummary:Shows how to change metafiles compression in a document while saving.
+ // Open a document that contains a Microsoft Equation 3.0 formula.
+ Document doc = new Document(getMyDir() + "Microsoft equation object.docx");
+
+ // When we save a document, smaller metafiles are not compressed for performance reasons.
+ // We can set a flag in a SaveOptions object to compress every metafile when saving.
+ // Some editors such as LibreOffice cannot read uncompressed metafiles.
+ DocSaveOptions saveOptions = new DocSaveOptions();
+ saveOptions.setAlwaysCompressMetafiles(compressAllMetafiles);
+
+ doc.save(getArtifactsDir() + "DocSaveOptions.AlwaysCompressMetafiles.docx", saveOptions);
+ //ExEnd
+
+ long testedFileLength = new File(getArtifactsDir() + "DocSaveOptions.AlwaysCompressMetafiles.docx").length();
+
+ if (compressAllMetafiles)
+ Assert.assertTrue(testedFileLength < 13315);
+ else
+ Assert.assertTrue(testedFileLength <= 30000);
+ }
+
+ @DataProvider(name = "alwaysCompressMetafilesDataProvider")
+ public static Object[][] alwaysCompressMetafilesDataProvider() {
+ return new Object[][]
+ {
+ {false},
+ {true},
+ };
+ }
+}
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ExDocument.java b/Examples/ApiExamples/Java/src/main/java/Examples/ExDocument.java
new file mode 100644
index 00000000..eb8cc180
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ExDocument.java
@@ -0,0 +1,2665 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.pdf.TextAbsorber;
+import com.aspose.words.Font;
+import com.aspose.words.List;
+import com.aspose.words.Shape;
+import com.aspose.words.*;
+import com.aspose.words.shaping.harfbuzz.HarfBuzzTextShaperFactory;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.io.*;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.file.Files;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+@Test
+public class ExDocument extends ApiExampleBase
+{
+ @Test
+ public void createSimpleDocument() throws Exception
+ {
+ //ExStart:CreateSimpleDocument
+ //GistId:6d898be16b796fcf7448ad3bfe18e51c
+ //ExFor:DocumentBase.Document
+ //ExFor:Document.#ctor()
+ //ExSummary:Shows how to create simple document.
+ Document doc = new Document();
+
+ // New Document objects by default come with the minimal set of nodes
+ // required to begin adding content such as text and shapes: a Section, a Body, and a Paragraph.
+ doc.appendChild(new Section(doc))
+ .appendChild(new Body(doc))
+ .appendChild(new Paragraph(doc))
+ .appendChild(new Run(doc, "Hello world!"));
+ //ExEnd:CreateSimpleDocument
+ }
+
+ @Test
+ public void constructor() throws Exception {
+ //ExStart
+ //ExFor:Document.#ctor()
+ //ExFor:Document.#ctor(String,LoadOptions)
+ //ExSummary:Shows how to create and load documents.
+ // There are two ways of creating a Document object using Aspose.Words.
+ // 1 - Create a blank document:
+ Document doc = new Document();
+
+ // New Document objects by default come with the minimal set of nodes
+ // required to begin adding content such as text and shapes: a Section, a Body, and a Paragraph.
+ doc.getFirstSection().getBody().getFirstParagraph().appendChild(new Run(doc, "Hello world!"));
+
+ // 2 - Load a document that exists in the local file system:
+ doc = new Document(getMyDir() + "Document.docx");
+
+ // Loaded documents will have contents that we can access and edit.
+ Assert.assertEquals("Hello World!", doc.getFirstSection().getBody().getFirstParagraph().getText().trim());
+
+ // Some operations that need to occur during loading, such as using a password to decrypt a document,
+ // can be done by passing a LoadOptions object when loading the document.
+ doc = new Document(getMyDir() + "Encrypted.docx", new LoadOptions("docPassword"));
+
+ Assert.assertEquals("Test encrypted document.", doc.getFirstSection().getBody().getFirstParagraph().getText().trim());
+ //ExEnd
+ }
+
+ @Test
+ public void loadFromStream() throws Exception {
+ //ExStart
+ //ExFor:Document.#ctor(Stream)
+ //ExSummary:Shows how to load a document using a stream.
+ InputStream stream = new FileInputStream(getMyDir() + "Document.docx");
+ try {
+ Document doc = new Document(stream);
+ Assert.assertEquals("Hello World!", doc.getFirstSection().getBody().getText().trim());
+ } finally {
+ if (stream != null) stream.close();
+ }
+ //ExEnd
+ }
+
+ @Test
+ public void loadFromWeb() throws Exception {
+ //ExStart
+ //ExFor:Document.#ctor(Stream)
+ //ExSummary:Shows how to retrieve a document from a URL and saves it to disk in a different format.
+ // This is the URL address pointing to where to find the document
+ URL url = new URL("https://filesamples.com/samples/document/docx/sample3.docx");
+
+ // The easiest way to load our document from the internet is make use of the URLConnection class
+ URLConnection webClient = url.openConnection();
+ webClient.addRequestProperty("User-Agent", "Mozilla");
+ webClient.setReadTimeout(5000);
+ webClient.setConnectTimeout(5000);
+
+ // Download the bytes from the location referenced by the URL
+ InputStream inputStream = webClient.getInputStream();
+
+ // Convert the input stream to a byte array
+ int pos;
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ while ((pos = inputStream.read()) != -1) bos.write(pos);
+
+ byte[] dataBytes = bos.toByteArray();
+ Assert.assertNotEquals(dataBytes, null); //ExSkip
+
+ // Wrap the bytes representing the document in memory into a stream object
+ ByteArrayInputStream byteStream = new ByteArrayInputStream(dataBytes);
+
+ // Load this memory stream into a new Aspose.Words Document
+ // The file format of the passed data is inferred from the content of the bytes itself
+ // You can load any document format supported by Aspose.Words in the same way
+ Document doc = new Document(byteStream);
+ Assert.assertTrue(doc.getText().contains("There are eight section headings in this document")); //ExSkip
+
+ // Convert the document to any format supported by Aspose.Words and save
+ doc.save(getArtifactsDir() + "Document.OpenDocumentFromWeb.docx");
+ //ExEnd
+ }
+
+ @Test
+ public void convertToPdf() throws Exception {
+ //ExStart
+ //ExFor:Document.#ctor(String)
+ //ExFor:Document.Save(String)
+ //ExSummary:Shows how to open a document and convert it to .PDF.
+ Document doc = new Document(getMyDir() + "Document.docx");
+
+ doc.save(getArtifactsDir() + "Document.ConvertToPdf.pdf");
+ //ExEnd
+ }
+
+ @Test(groups = "IgnoreOnJenkins")
+ public void openType() throws Exception {
+ //ExStart
+ //ExFor:LayoutOptions.TextShaperFactory
+ //ExSummary:Shows how to support OpenType features using the HarfBuzz text shaping engine.
+ Document doc = new Document(getMyDir() + "OpenType text shaping.docx");
+
+ // Aspose.Words can use externally provided text shaper objects,
+ // which represent fonts and compute shaping information for text.
+ // A text shaper factory is necessary for documents that use multiple fonts.
+ // When the text shaper factory set, the layout uses OpenType features.
+ // An Instance property returns a static BasicTextShaperCache object wrapping HarfBuzzTextShaperFactory.
+ doc.getLayoutOptions().setTextShaperFactory(HarfBuzzTextShaperFactory.getInstance());
+
+ // Currently, text shaping is performing when exporting to PDF or XPS formats.
+ doc.save(getArtifactsDir() + "Document.OpenType.pdf");
+ //ExEnd
+ }
+
+ @Test
+ public void detectMobiDocumentFormat() throws Exception
+ {
+ FileFormatInfo info = FileFormatUtil.detectFileFormat(getMyDir() + "Document.mobi");
+ Assert.assertEquals(info.getLoadFormat(), LoadFormat.MOBI);
+ }
+
+ @Test
+ public void detectPdfDocumentFormat() throws Exception {
+ FileFormatInfo info = FileFormatUtil.detectFileFormat(getMyDir() + "Pdf Document.pdf");
+ Assert.assertEquals(info.getLoadFormat(), LoadFormat.PDF);
+ }
+
+ @Test
+ public void openFromStreamWithBaseUri() throws Exception {
+ //ExStart
+ //ExFor:Document.#ctor(Stream,LoadOptions)
+ //ExFor:LoadOptions.#ctor
+ //ExFor:LoadOptions.BaseUri
+ //ExFor:ShapeBase.IsImage
+ //ExSummary:Shows how to open an HTML document with images from a stream using a base URI.
+ InputStream stream = new FileInputStream(getMyDir() + "Document.html");
+ try /*JAVA: was using*/ {
+ // Pass the URI of the base folder while loading it
+ // so that any images with relative URIs in the HTML document can be found.
+ LoadOptions loadOptions = new LoadOptions();
+ loadOptions.setBaseUri(getImageDir());
+
+ Document doc = new Document(stream, loadOptions);
+
+ // Verify that the first shape of the document contains a valid image.
+ Shape shape = (Shape) doc.getChild(NodeType.SHAPE, 0, true);
+
+ Assert.assertTrue(shape.isImage());
+ Assert.assertNotNull(shape.getImageData().getImageBytes());
+ Assert.assertEquals(32.0, ConvertUtil.pointToPixel(shape.getWidth()), 0.01);
+ Assert.assertEquals(32.0, ConvertUtil.pointToPixel(shape.getHeight()), 0.01);
+ } finally {
+ if (stream != null) stream.close();
+ }
+ //ExEnd
+ }
+
+ @Test(enabled = false, description = "Need to rework")
+ public void insertHtmlFromWebPage() throws Exception {
+ //ExStart
+ //ExFor:Document.#ctor(Stream, LoadOptions)
+ //ExFor:LoadOptions.#ctor(LoadFormat, String, String)
+ //ExFor:LoadFormat
+ //ExSummary:Shows how to insert the HTML contents from a web page into a new document.
+ URL url = new URL("https://www.aspose.com");
+
+ // The easiest way to load our document from the internet is make use of the URLConnection class.
+ URLConnection webClient = url.openConnection();
+
+ // Download the bytes from the location referenced by the URL.
+ InputStream inputStream = webClient.getInputStream();
+
+ // Convert the input stream to a byte array.
+ int pos;
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ while ((pos = inputStream.read()) != -1) bos.write(pos);
+
+ byte[] dataBytes = bos.toByteArray();
+
+ // Wrap the bytes representing the document in memory into a stream object.
+ ByteArrayInputStream byteStream = new ByteArrayInputStream(dataBytes);
+
+ // The baseUri property should be set to ensure any relative img paths are retrieved correctly.
+ LoadOptions options = new LoadOptions(LoadFormat.HTML, "", url.getPath());
+
+ // Load the HTML document from stream and pass the LoadOptions object.
+ Document doc = new Document(byteStream, options);
+
+ doc.save(getArtifactsDir() + "Document.InsertHtmlFromWebPage.docx");
+ //ExEnd
+
+ TestUtil.verifyWebResponseStatusCode(200, url);
+ }
+
+ @Test
+ public void loadEncrypted() throws Exception {
+ //ExStart
+ //ExFor:Document.#ctor(Stream,LoadOptions)
+ //ExFor:Document.#ctor(String,LoadOptions)
+ //ExFor:LoadOptions
+ //ExFor:LoadOptions.#ctor(String)
+ //ExSummary:Shows how to load an encrypted Microsoft Word document.
+ Document doc;
+
+ // Aspose.Words throw an exception if we try to open an encrypted document without its password.
+ Assert.assertThrows(IncorrectPasswordException.class, () -> new Document(getMyDir() + "Encrypted.docx"));
+
+ // When loading such a document, the password is passed to the document's constructor using a LoadOptions object.
+ LoadOptions options = new LoadOptions("docPassword");
+
+ // There are two ways of loading an encrypted document with a LoadOptions object.
+ // 1 - Load the document from the local file system by filename:
+ doc = new Document(getMyDir() + "Encrypted.docx", options);
+ Assert.assertEquals("Test encrypted document.", doc.getText().trim()); //ExSkip
+
+ // 2 - Load the document from a stream:
+ InputStream stream = new FileInputStream(getMyDir() + "Encrypted.docx");
+ try {
+ doc = new Document(stream, options);
+ Assert.assertEquals("Test encrypted document.", doc.getText().trim()); //ExSkip
+ } finally {
+ if (stream != null) stream.close();
+ }
+ //ExEnd
+ }
+
+ @Test
+ public void notSupportedWarning() throws Exception
+ {
+ //ExStart
+ //ExFor:WarningInfoCollection.Count
+ //ExFor:WarningInfoCollection.Item(Int32)
+ //ExSummary:Shows how to get warnings about unsupported formats.
+ WarningInfoCollection warings = new WarningInfoCollection();
+ LoadOptions loadOptions = new LoadOptions();
+ loadOptions.setWarningCallback(warings);
+ Document doc = new Document(getMyDir() + "FB2 document.fb2", loadOptions);
+
+ Assert.assertEquals("The original file load format is FB2, which is not supported by Aspose.Words. The file is loaded as an XML document.", warings.get(0).getDescription());
+ //ExEnd
+ }
+
+ @Test
+ public void tempFolder() throws Exception {
+ //ExStart
+ //ExFor:LoadOptions.TempFolder
+ //ExSummary:Shows how to load a document using temporary files.
+ // Note that such an approach can reduce memory usage but degrades speed.
+ LoadOptions loadOptions = new LoadOptions();
+ loadOptions.setTempFolder("C:\\TempFolder\\");
+
+ // Ensure that the directory exists and load.
+ new File(loadOptions.getTempFolder()).mkdir();
+
+ Document doc = new Document(getMyDir() + "Document.docx", loadOptions);
+ //ExEnd
+ }
+
+ @Test
+ public void convertToHtml() throws Exception {
+ //ExStart
+ //ExFor:Document.Save(String,SaveFormat)
+ //ExFor:SaveFormat
+ //ExSummary:Shows how to convert from DOCX to HTML format.
+ Document doc = new Document(getMyDir() + "Document.docx");
+ doc.save(getArtifactsDir() + "Document.ConvertToHtml.html", SaveFormat.HTML);
+ //ExEnd
+ }
+
+ @Test
+ public void convertToMhtml() throws Exception {
+ Document doc = new Document(getMyDir() + "Document.docx");
+ doc.save(getArtifactsDir() + "Document.ConvertToMhtml.mht");
+ }
+
+ @Test
+ public void convertToTxt() throws Exception {
+ Document doc = new Document(getMyDir() + "Document.docx");
+ doc.save(getArtifactsDir() + "Document.ConvertToTxt.txt");
+ }
+
+ @Test
+ public void convertToEpub() throws Exception {
+ Document doc = new Document(getMyDir() + "Rendering.docx");
+ doc.save(getArtifactsDir() + "Document.ConvertToEpub.epub");
+ }
+
+ @Test
+ public void saveToStream() throws Exception {
+ //ExStart
+ //ExFor:Document.Save(Stream,SaveFormat)
+ //ExSummary:Shows how to save a document to a stream.
+ Document doc = new Document(getMyDir() + "Document.docx");
+
+ ByteArrayOutputStream dstStream = new ByteArrayOutputStream();
+ try {
+ doc.save(dstStream, SaveFormat.DOCX);
+
+ byte[] dataBytes = dstStream.toByteArray();
+ ByteArrayInputStream byteStream = new ByteArrayInputStream(dataBytes);
+
+ // Verify that the stream contains the document.
+ Assert.assertEquals("Hello World!", new Document(byteStream).getFirstSection().getBody().getText().trim());
+ } finally {
+ if (dstStream != null) dstStream.close();
+ }
+ //ExEnd
+ }
+
+ //ExStart
+ //ExFor:Range.Fields
+ //ExFor:INodeChangingCallback
+ //ExFor:INodeChangingCallback.NodeInserting
+ //ExFor:INodeChangingCallback.NodeInserted
+ //ExFor:INodeChangingCallback.NodeRemoving
+ //ExFor:INodeChangingCallback.NodeRemoved
+ //ExFor:NodeChangingArgs
+ //ExFor:NodeChangingArgs.Node
+ //ExFor:DocumentBase.NodeChangingCallback
+ //ExSummary:Shows how customize node changing with a callback.
+ @Test //ExSkip
+ public void fontChangeViaCallback() throws Exception {
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Set the node changing callback to custom implementation,
+ // then add/remove nodes to get it to generate a log.
+ HandleNodeChangingFontChanger callback = new HandleNodeChangingFontChanger();
+ doc.setNodeChangingCallback(callback);
+
+ builder.writeln("Hello world!");
+ builder.writeln("Hello again!");
+ builder.insertField(" HYPERLINK \"https://www.google.com/\" ");
+ builder.insertShape(ShapeType.RECTANGLE, 300.0, 300.0);
+
+ doc.getRange().getFields().get(0).remove();
+
+ System.out.println(callback.getLog());
+ testFontChangeViaCallback(callback.getLog()); //ExSkip
+ }
+
+ ///
+ /// Logs the date and time of each node insertion and removal.
+ /// Sets a custom font name/size for the text contents of Run nodes.
+ ///
+ public static class HandleNodeChangingFontChanger implements INodeChangingCallback {
+ public void nodeInserted(NodeChangingArgs args) {
+ mLog.append(MessageFormat.format("\tType:\t{0}", args.getNode().getNodeType()));
+ mLog.append(MessageFormat.format("\tHash:\t{0}", args.getNode().hashCode()));
+
+ if (args.getNode().getNodeType() == NodeType.RUN) {
+ Font font = ((Run) args.getNode()).getFont();
+ mLog.append(MessageFormat.format("\tFont:\tChanged from \"{0}\" {1}pt", font.getName(), font.getSize()));
+
+ font.setSize(24.0);
+ font.setName("Arial");
+
+ mLog.append(MessageFormat.format(" to \"{0}\" {1}pt", font.getName(), font.getSize()));
+ mLog.append(MessageFormat.format("\tContents:\n\t\t\"{0}\"", args.getNode().getText()));
+ }
+ }
+
+ public void nodeInserting(NodeChangingArgs args) {
+ mLog.append(MessageFormat.format("\n{0}\tNode insertion:", new Date()));
+ }
+
+ public void nodeRemoved(NodeChangingArgs args) {
+ mLog.append(MessageFormat.format("\tType:\t{0}", args.getNode().getNodeType()));
+ mLog.append(MessageFormat.format("\tHash code:\t{0}", args.getNode().hashCode()));
+ }
+
+ public void nodeRemoving(NodeChangingArgs args) {
+ mLog.append(MessageFormat.format("\n{0}\tNode removal:", new Date()));
+ }
+
+ public String getLog() {
+ return mLog.toString();
+ }
+
+ private final StringBuilder mLog = new StringBuilder();
+ }
+ //ExEnd
+
+ private static void testFontChangeViaCallback(String log) {
+ Assert.assertEquals(10, getLogCount(log, "insertion"));
+ Assert.assertEquals(5, getLogCount(log, "removal"));
+ }
+
+ private static int getLogCount(String log, String pattern) {
+ Matcher matcher = Pattern.compile(pattern).matcher(log);
+
+ int count = 0;
+ while (matcher.find())
+ count++;
+
+ return count;
+ }
+
+ @Test
+ public void appendDocument() throws Exception {
+ //ExStart
+ //ExFor:Document.AppendDocument(Document, ImportFormatMode)
+ //ExSummary:Shows how to append a document to the end of another document.
+ Document srcDoc = new Document();
+ srcDoc.getFirstSection().getBody().appendParagraph("Source document text. ");
+
+ Document dstDoc = new Document();
+ dstDoc.getFirstSection().getBody().appendParagraph("Destination document text. ");
+
+ // Append the source document to the destination document while preserving its formatting,
+ // then save the source document to the local file system.
+ dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING);
+ Assert.assertEquals(2, dstDoc.getSections().getCount()); //ExSkip
+
+ dstDoc.save(getArtifactsDir() + "Document.AppendDocument.docx");
+ //ExEnd
+
+ String outDocText = new Document(getArtifactsDir() + "Document.AppendDocument.docx").getText();
+
+ Assert.assertTrue(outDocText.startsWith(dstDoc.getText()));
+ Assert.assertTrue(outDocText.endsWith(srcDoc.getText()));
+ }
+
+ @Test
+ // The file path used below does not point to an existing file.
+ public void appendDocumentFromAutomation() throws Exception {
+ Document doc = new Document();
+
+ // We should call this method to clear this document of any existing content.
+ doc.removeAllChildren();
+
+ final int RECORD_COUNT = 5;
+ for (int i = 1; i <= RECORD_COUNT; i++) {
+ Document srcDoc = new Document();
+
+ Assert.assertThrows(FileNotFoundException.class, () -> new Document("C:\\DetailsList.doc"));
+
+ // Append the source document at the end of the destination document.
+ doc.appendDocument(srcDoc, ImportFormatMode.USE_DESTINATION_STYLES);
+
+ // Automation required you to insert a new section break at this point, however, in Aspose.Words we
+ // do not need to do anything here as the appended document is imported as separate sections already
+
+ // Unlink all headers/footers in this section from the previous section headers/footers
+ // if this is the second document or above being appended.
+ if (i > 1) {
+ int finalI = i;
+ Assert.assertThrows(NullPointerException.class, () -> doc.getSections().get(finalI).getHeadersFooters().linkToPrevious(false));
+ }
+ }
+ }
+
+ @Test (dataProvider = "importListDataProvider")
+ public void importList(boolean isKeepSourceNumbering) throws Exception
+ {
+ //ExStart
+ //ExFor:ImportFormatOptions.KeepSourceNumbering
+ //ExSummary:Shows how to import a document with numbered lists.
+ Document srcDoc = new Document(getMyDir() + "List source.docx");
+ Document dstDoc = new Document(getMyDir() + "List destination.docx");
+
+ Assert.assertEquals(dstDoc.getLists().getCount(), 4);
+
+ ImportFormatOptions options = new ImportFormatOptions();
+
+ // If there is a clash of list styles, apply the list format of the source document.
+ // Set the "KeepSourceNumbering" property to "false" to not import any list numbers into the destination document.
+ // Set the "KeepSourceNumbering" property to "true" import all clashing
+ // list style numbering with the same appearance that it had in the source document.
+ options.setKeepSourceNumbering(isKeepSourceNumbering);
+
+ dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING, options);
+ dstDoc.updateListLabels();
+
+ if (isKeepSourceNumbering)
+ Assert.assertEquals(dstDoc.getLists().getCount(), 5);
+ else
+ Assert.assertEquals(dstDoc.getLists().getCount(), 4);
+ //ExEnd
+ }
+
+ @DataProvider(name = "importListDataProvider")
+ public static Object[][] importListDataProvider() {
+ return new Object[][]
+ {
+ {true},
+ {false},
+ };
+ }
+
+ @Test
+ public void keepSourceNumberingSameListIds() throws Exception
+ {
+ //ExStart
+ //ExFor:ImportFormatOptions.KeepSourceNumbering
+ //ExFor:NodeImporter.#ctor(DocumentBase, DocumentBase, ImportFormatMode, ImportFormatOptions)
+ //ExSummary:Shows how resolve a clash when importing documents that have lists with the same list definition identifier.
+ Document srcDoc = new Document(getMyDir() + "List with the same definition identifier - source.docx");
+ Document dstDoc = new Document(getMyDir() + "List with the same definition identifier - destination.docx");
+
+ ImportFormatOptions importFormatOptions = new ImportFormatOptions();
+
+ // Set the "KeepSourceNumbering" property to "true" to apply a different list definition ID
+ // to identical styles as Aspose.Words imports them into destination documents.
+ importFormatOptions.setKeepSourceNumbering(true);
+ dstDoc.appendDocument(srcDoc, ImportFormatMode.USE_DESTINATION_STYLES, importFormatOptions);
+
+ dstDoc.updateListLabels();
+ //ExEnd
+
+ String paraText = dstDoc.getSections().get(1).getBody().getLastParagraph().getText();
+
+ Assert.assertTrue(paraText.startsWith("13->13"), paraText);
+ Assert.assertEquals("1.", dstDoc.getSections().get(1).getBody().getLastParagraph().getListLabel().getLabelString());
+ }
+
+ @Test
+ public void mergePastedLists() throws Exception
+ {
+ //ExStart
+ //ExFor:ImportFormatOptions.MergePastedLists
+ //ExSummary:Shows how to merge lists from a documents.
+ Document srcDoc = new Document(getMyDir() + "List item.docx");
+ Document dstDoc = new Document(getMyDir() + "List destination.docx");
+
+ ImportFormatOptions options = new ImportFormatOptions(); { options.setMergePastedLists(true); }
+
+ // Set the "MergePastedLists" property to "true" pasted lists will be merged with surrounding lists.
+ dstDoc.appendDocument(srcDoc, ImportFormatMode.USE_DESTINATION_STYLES, options);
+
+ dstDoc.save(getArtifactsDir() + "Document.MergePastedLists.docx");
+ //ExEnd
+ }
+
+ @Test
+ public void forceCopyStyles() throws Exception
+ {
+ //ExStart
+ //ExFor:ImportFormatOptions.ForceCopyStyles
+ //ExSummary:Shows how to copy source styles with unique names forcibly.
+ // Both documents contain MyStyle1 and MyStyle2, MyStyle3 exists only in a source document.
+ Document srcDoc = new Document(getMyDir() + "Styles source.docx");
+ Document dstDoc = new Document(getMyDir() + "Styles destination.docx");
+
+ ImportFormatOptions options = new ImportFormatOptions(); { options.setForceCopyStyles(true); }
+ dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING, options);
+
+ ParagraphCollection paras = dstDoc.getSections().get(1).getBody().getParagraphs();
+
+ Assert.assertEquals(paras.get(0).getParagraphFormat().getStyle().getName(), "MyStyle1_0");
+ Assert.assertEquals(paras.get(1).getParagraphFormat().getStyle().getName(), "MyStyle2_0");
+ Assert.assertEquals(paras.get(2).getParagraphFormat().getStyle().getName(), "MyStyle3");
+ //ExEnd
+ }
+
+ @Test
+ public void adjustSentenceAndWordSpacing() throws Exception
+ {
+ //ExStart
+ //ExFor:ImportFormatOptions.AdjustSentenceAndWordSpacing
+ //ExSummary:Shows how to adjust sentence and word spacing automatically.
+ Document srcDoc = new Document();
+ Document dstDoc = new Document();
+
+ DocumentBuilder builder = new DocumentBuilder(srcDoc);
+ builder.write("Dolor sit amet.");
+
+ builder = new DocumentBuilder(dstDoc);
+ builder.write("Lorem ipsum.");
+
+ ImportFormatOptions options = new ImportFormatOptions(); { options.setAdjustSentenceAndWordSpacing(true); }
+ builder.insertDocument(srcDoc, ImportFormatMode.USE_DESTINATION_STYLES, options);
+
+ Assert.assertEquals("Lorem ipsum. Dolor sit amet.", dstDoc.getFirstSection().getBody().getFirstParagraph().getText().trim());
+ //ExEnd
+ }
+
+ @Test
+ public void validateIndividualDocumentSignatures() throws Exception {
+ //ExStart
+ //ExFor:CertificateHolder.Certificate
+ //ExFor:Document.DigitalSignatures
+ //ExFor:DigitalSignature
+ //ExFor:DigitalSignatureCollection
+ //ExFor:DigitalSignature.IsValid
+ //ExFor:DigitalSignature.Comments
+ //ExFor:DigitalSignature.SignTime
+ //ExFor:DigitalSignature.SignatureType
+ //ExSummary:Shows how to validate and display information about each signature in a document.
+ Document doc = new Document(getMyDir() + "Digitally signed.docx");
+
+ for (DigitalSignature signature : doc.getDigitalSignatures()) {
+ System.out.println("*** Signature Found ***");
+ System.out.println("Is valid: " + signature.isValid());
+ // This property is available in MS Word documents only
+ System.out.println("Reason for signing: " + signature.getComments());
+ System.out.println("Signature type: " + signature.getSignatureType());
+ System.out.println("Time of signing: " + signature.getSignTime());
+ System.out.println("Subject name: " + signature.getSubjectName());
+ System.out.println("Issuer name: " + signature.getIssuerName());
+ System.out.println();
+ }
+ //ExEnd
+
+ Assert.assertEquals(1, doc.getDigitalSignatures().getCount());
+
+ DigitalSignature digitalSig = doc.getDigitalSignatures().get(0);
+
+ Assert.assertTrue(digitalSig.isValid());
+ Assert.assertEquals("Test Sign", digitalSig.getComments());
+ Assert.assertEquals("XmlDsig", DigitalSignatureType.toString(digitalSig.getSignatureType()));
+ Assert.assertTrue(digitalSig.getSubjectName().contains("Aspose Pty Ltd"));
+ Assert.assertTrue(digitalSig.getIssuerName().contains("VeriSign"));
+ }
+
+ @Test
+ public void digitalSignature() throws Exception {
+ //ExStart
+ //ExFor:DigitalSignature.CertificateHolder
+ //ExFor:DigitalSignature.IssuerName
+ //ExFor:DigitalSignature.SubjectName
+ //ExFor:DigitalSignatureCollection
+ //ExFor:DigitalSignatureCollection.IsValid
+ //ExFor:DigitalSignatureCollection.Count
+ //ExFor:DigitalSignatureCollection.Item(Int32)
+ //ExFor:DigitalSignatureUtil.Sign(Stream, Stream, CertificateHolder)
+ //ExFor:DigitalSignatureUtil.Sign(String, String, CertificateHolder)
+ //ExFor:DigitalSignatureType
+ //ExFor:Document.DigitalSignatures
+ //ExSummary:Shows how to sign documents with X.509 certificates.
+ // Verify that a document is not signed.
+ Assert.assertFalse(FileFormatUtil.detectFileFormat(getMyDir() + "Document.docx").hasDigitalSignature());
+
+ // Create a CertificateHolder object from a PKCS12 file, which we will use to sign the document.
+ CertificateHolder certificateHolder = CertificateHolder.create(getMyDir() + "morzal.pfx", "aw", null);
+
+ SignOptions signOptions = new SignOptions();
+ signOptions.setSignTime(new Date());
+
+ // There are two ways of saving a signed copy of a document to the local file system:
+ // 1 - Designate a document by a local system filename and save a signed copy at a location specified by another filename.
+ DigitalSignatureUtil.sign(getMyDir() + "Document.docx", getArtifactsDir() + "Document.DigitalSignature.docx",
+ certificateHolder, signOptions);
+
+ Assert.assertTrue(FileFormatUtil.detectFileFormat(getArtifactsDir() + "Document.DigitalSignature.docx").hasDigitalSignature());
+
+ // 2 - Take a document from a stream, and save a signed copy to another stream.
+ InputStream inDoc = new FileInputStream(getMyDir() + "Document.docx");
+ try {
+ OutputStream outDoc = new FileOutputStream(getArtifactsDir() + "Document.DigitalSignature.docx");
+ try {
+ DigitalSignatureUtil.sign(inDoc, outDoc, certificateHolder);
+ } finally {
+ if (outDoc != null) outDoc.close();
+ }
+ } finally {
+ if (inDoc != null) inDoc.close();
+ }
+
+ Assert.assertTrue(FileFormatUtil.detectFileFormat(getArtifactsDir() + "Document.DigitalSignature.docx").hasDigitalSignature());
+
+ // Please verify that all of the document's digital signatures are valid and check their details.
+ Document signedDoc = new Document(getArtifactsDir() + "Document.DigitalSignature.docx");
+ DigitalSignatureCollection digitalSignatureCollection = signedDoc.getDigitalSignatures();
+
+ Assert.assertTrue(digitalSignatureCollection.isValid());
+ Assert.assertEquals(1, digitalSignatureCollection.getCount());
+ Assert.assertEquals(DigitalSignatureType.XML_DSIG, digitalSignatureCollection.get(0).getSignatureType());
+ Assert.assertEquals("CN=Morzal.Me", signedDoc.getDigitalSignatures().get(0).getIssuerName());
+ Assert.assertEquals("CN=Morzal.Me", signedDoc.getDigitalSignatures().get(0).getSubjectName());
+ //ExEnd
+ }
+
+ @Test
+ public void signatureValue() throws Exception
+ {
+ //ExStart
+ //ExFor:DigitalSignature.SignatureValue
+ //ExSummary:Shows how to get a digital signature value from a digitally signed document.
+ Document doc = new Document(getMyDir() + "Digitally signed.docx");
+
+ for (DigitalSignature digitalSignature : doc.getDigitalSignatures())
+ {
+ String signatureValue = Base64.getEncoder().encodeToString(digitalSignature.getSignatureValue());
+ Assert.assertEquals("K1cVLLg2kbJRAzT5WK+m++G8eEO+l7S+5ENdjMxxTXkFzGUfvwxREuJdSFj9AbD" +
+ "MhnGvDURv9KEhC25DDF1al8NRVR71TF3CjHVZXpYu7edQS5/yLw/k5CiFZzCp1+MmhOdYPcVO+Fm" +
+ "+9fKr2iNLeyYB+fgEeZHfTqTFM2WwAqo=", signatureValue);
+ }
+ //ExEnd
+ }
+
+ @Test
+ public void appendAllDocumentsInFolder() throws Exception {
+ //ExStart
+ //ExFor:Document.AppendDocument(Document, ImportFormatMode)
+ //ExSummary:Shows how to append all the documents in a folder to the end of a template document.
+ Document dstDoc = new Document();
+
+ DocumentBuilder builder = new DocumentBuilder(dstDoc);
+ builder.getParagraphFormat().setStyleIdentifier(StyleIdentifier.HEADING_1);
+ builder.writeln("Template Document");
+ builder.getParagraphFormat().setStyleIdentifier(StyleIdentifier.NORMAL);
+ builder.writeln("Some content here");
+ Assert.assertEquals(5, dstDoc.getStyles().getCount()); //ExSkip
+ Assert.assertEquals(1, dstDoc.getSections().getCount()); //ExSkip
+
+ // Append all unencrypted documents with the .doc extension
+ // from our local file system directory to the base document.
+ for (File fileName : new File(getMyDir()).listFiles((f, name) -> name.endsWith(".doc"))) {
+ FileFormatInfo info = FileFormatUtil.detectFileFormat(fileName.getPath());
+ if (info.isEncrypted())
+ continue;
+
+ Document srcDoc = new Document(fileName.getPath());
+ dstDoc.appendDocument(srcDoc, ImportFormatMode.USE_DESTINATION_STYLES);
+ }
+
+ dstDoc.save(getArtifactsDir() + "Document.AppendAllDocumentsInFolder.doc");
+ //ExEnd
+
+ Assert.assertEquals(7, dstDoc.getStyles().getCount());
+ Assert.assertEquals(10, dstDoc.getSections().getCount());
+ }
+
+ @Test
+ public void joinRunsWithSameFormatting() throws Exception {
+ //ExStart
+ //ExFor:Document.JoinRunsWithSameFormatting
+ //ExSummary:Shows how to join runs in a document to reduce unneeded runs.
+ // Open a document that contains adjacent runs of text with identical formatting,
+ // which commonly occurs if we edit the same paragraph multiple times in Microsoft Word.
+ Document doc = new Document(getMyDir() + "Rendering.docx");
+
+ // If any number of these runs are adjacent with identical formatting,
+ // then the document may be simplified.
+ Assert.assertEquals(317, doc.getChildNodes(NodeType.RUN, true).getCount());
+
+ // Combine such runs with this method and verify the number of run joins that will take place.
+ Assert.assertEquals(121, doc.joinRunsWithSameFormatting());
+
+ // The number of joins and the number of runs we have after the join
+ // should add up the number of runs we had initially.
+ Assert.assertEquals(196, doc.getChildNodes(NodeType.RUN, true).getCount());
+ //ExEnd
+ }
+
+ @Test
+ public void defaultTabStop() throws Exception {
+ //ExStart
+ //ExFor:Document.DefaultTabStop
+ //ExFor:ControlChar.Tab
+ //ExFor:ControlChar.TabChar
+ //ExSummary:Shows how to set a custom interval for tab stop positions.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Set tab stops to appear every 72 points (1 inch).
+ builder.getDocument().setDefaultTabStop(72.0);
+
+ // Each tab character snaps the text after it to the next closest tab stop position.
+ builder.writeln("Hello" + ControlChar.TAB + "World!");
+ builder.writeln("Hello" + ControlChar.TAB_CHAR + "World!");
+ //ExEnd
+
+ doc = DocumentHelper.saveOpen(doc);
+ Assert.assertEquals(72.0, doc.getDefaultTabStop());
+ }
+
+ @Test
+ public void cloneDocument() throws Exception {
+ //ExStart
+ //ExFor:Document.Clone
+ //ExSummary:Shows how to deep clone a document.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ builder.write("Hello world!");
+
+ // Cloning will produce a new document with the same contents as the original,
+ // but with a unique copy of each of the original document's nodes.
+ Document clone = doc.deepClone();
+
+ Assert.assertEquals(doc.getFirstSection().getBody().getFirstParagraph().getRuns().get(0).getText(),
+ clone.getFirstSection().getBody().getFirstParagraph().getRuns().get(0).getText());
+ Assert.assertNotEquals(doc.getFirstSection().getBody().getFirstParagraph().getRuns().get(0).hashCode(),
+ clone.getFirstSection().getBody().getFirstParagraph().getRuns().get(0).hashCode());
+ //ExEnd
+ }
+
+ @Test
+ public void documentGetTextToString() throws Exception {
+ //ExStart
+ //ExFor:CompositeNode.GetText
+ //ExFor:Node.ToString(SaveFormat)
+ //ExSummary:Shows the difference between calling the GetText and ToString methods on a node.
+ Document doc = new Document();
+
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ builder.insertField("MERGEFIELD Field");
+
+ // GetText will retrieve the visible text as well as field codes and special characters.
+ Assert.assertEquals("\u0013MERGEFIELD Field\u0014«Field»\u0015\f", doc.getText());
+
+ // ToString will give us the document's appearance if saved to a passed save format.
+ Assert.assertEquals("«Field»\r\n", doc.toString(SaveFormat.TEXT));
+ //ExEnd
+ }
+
+ @Test
+ public void documentByteArray() throws Exception {
+ Document doc = new Document(getMyDir() + "Document.docx");
+
+ ByteArrayOutputStream streamOut = new ByteArrayOutputStream();
+ doc.save(streamOut, SaveFormat.DOCX);
+
+ byte[] docBytes = streamOut.toByteArray();
+
+ ByteArrayInputStream streamIn = new ByteArrayInputStream(docBytes);
+
+ Document loadDoc = new Document(streamIn);
+ Assert.assertEquals(doc.getText(), loadDoc.getText());
+ }
+
+ @Test
+ public void protectUnprotect() throws Exception {
+ //ExStart
+ //ExFor:Document.Protect(ProtectionType,String)
+ //ExFor:Document.ProtectionType
+ //ExFor:Document.Unprotect
+ //ExFor:Document.Unprotect(String)
+ //ExSummary:Shows how to protect and unprotect a document.
+ Document doc = new Document();
+ doc.protect(ProtectionType.READ_ONLY, "password");
+
+ Assert.assertEquals(ProtectionType.READ_ONLY, doc.getProtectionType());
+
+ // If we open this document with Microsoft Word intending to edit it,
+ // we will need to apply the password to get through the protection.
+ doc.save(getArtifactsDir() + "Document.Protect.docx");
+
+ // Note that the protection only applies to Microsoft Word users opening our document.
+ // We have not encrypted the document in any way, and we do not need the password to open and edit it programmatically.
+ Document protectedDoc = new Document(getArtifactsDir() + "Document.Protect.docx");
+
+ Assert.assertEquals(ProtectionType.READ_ONLY, protectedDoc.getProtectionType());
+
+ DocumentBuilder builder = new DocumentBuilder(protectedDoc);
+ builder.writeln("Text added to a protected document.");
+ Assert.assertEquals("Text added to a protected document.", protectedDoc.getRange().getText().trim()); //ExSkip
+
+ // There are two ways of removing protection from a document.
+ // 1 - With no password:
+ doc.unprotect();
+
+ Assert.assertEquals(ProtectionType.NO_PROTECTION, doc.getProtectionType());
+
+ doc.protect(ProtectionType.READ_ONLY, "NewPassword");
+
+ Assert.assertEquals(ProtectionType.READ_ONLY, doc.getProtectionType());
+
+ doc.unprotect("WrongPassword");
+
+ Assert.assertEquals(ProtectionType.READ_ONLY, doc.getProtectionType());
+
+ // 2 - With the correct password:
+ doc.unprotect("NewPassword");
+
+ Assert.assertEquals(ProtectionType.NO_PROTECTION, doc.getProtectionType());
+ //ExEnd
+ }
+
+ @Test
+ public void documentEnsureMinimum() throws Exception {
+ //ExStart
+ //ExFor:Document.EnsureMinimum
+ //ExSummary:Shows how to ensure that a document contains the minimal set of nodes required for editing its contents.
+ // A newly created document contains one child Section, which includes one child Body and one child Paragraph.
+ // We can edit the document body's contents by adding nodes such as Runs or inline Shapes to that paragraph.
+ Document doc = new Document();
+ NodeCollection nodes = doc.getChildNodes(NodeType.ANY, true);
+
+ Assert.assertEquals(NodeType.SECTION, nodes.get(0).getNodeType());
+ Assert.assertEquals(doc, nodes.get(0).getParentNode());
+
+ Assert.assertEquals(NodeType.BODY, nodes.get(1).getNodeType());
+ Assert.assertEquals(nodes.get(0), nodes.get(1).getParentNode());
+
+ Assert.assertEquals(NodeType.PARAGRAPH, nodes.get(2).getNodeType());
+ Assert.assertEquals(nodes.get(1), nodes.get(2).getParentNode());
+
+ // This is the minimal set of nodes that we need to be able to edit the document.
+ // We will no longer be able to edit the document if we remove any of them.
+ doc.removeAllChildren();
+
+ Assert.assertEquals(0, doc.getChildNodes(NodeType.ANY, true).getCount());
+
+ // Call this method to make sure that the document has at least those three nodes so we can edit it again.
+ doc.ensureMinimum();
+
+ Assert.assertEquals(NodeType.SECTION, nodes.get(0).getNodeType());
+ Assert.assertEquals(NodeType.BODY, nodes.get(1).getNodeType());
+ Assert.assertEquals(NodeType.PARAGRAPH, nodes.get(2).getNodeType());
+
+ ((Paragraph) nodes.get(2)).getRuns().add(new Run(doc, "Hello world!"));
+ //ExEnd
+
+ Assert.assertEquals("Hello world!", doc.getText().trim());
+ }
+
+ @Test
+ public void removeMacrosFromDocument() throws Exception {
+ //ExStart
+ //ExFor:Document.RemoveMacros
+ //ExSummary:Shows how to remove all macros from a document.
+ Document doc = new Document(getMyDir() + "Macro.docm");
+
+ Assert.assertTrue(doc.hasMacros());
+ Assert.assertEquals("Project", doc.getVbaProject().getName());
+
+ // Remove the document's VBA project, along with all its macros.
+ doc.removeMacros();
+
+ Assert.assertFalse(doc.hasMacros());
+ Assert.assertNull(doc.getVbaProject());
+ //ExEnd
+ }
+
+ @Test
+ public void getPageCount() throws Exception {
+ //ExStart
+ //ExFor:Document.PageCount
+ //ExSummary:Shows how to count the number of pages in the document.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ builder.write("Page 1");
+ builder.insertBreak(BreakType.PAGE_BREAK);
+ builder.write("Page 2");
+ builder.insertBreak(BreakType.PAGE_BREAK);
+ builder.write("Page 3");
+
+ // Verify the expected page count of the document.
+ Assert.assertEquals(3, doc.getPageCount());
+
+ // Getting the PageCount property invoked the document's page layout to calculate the value.
+ // This operation will not need to be re-done when rendering the document to a fixed page save format,
+ // such as .pdf. So you can save some time, especially with more complex documents.
+ doc.save(getArtifactsDir() + "Document.GetPageCount.pdf");
+ //ExEnd
+ }
+
+ @Test
+ public void getUpdatedPageProperties() throws Exception {
+ //ExStart
+ //ExFor:Document.UpdateWordCount()
+ //ExFor:Document.UpdateWordCount(Boolean)
+ //ExFor:BuiltInDocumentProperties.Characters
+ //ExFor:BuiltInDocumentProperties.Words
+ //ExFor:BuiltInDocumentProperties.Paragraphs
+ //ExFor:BuiltInDocumentProperties.Lines
+ //ExSummary:Shows how to update all list labels in a document.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ builder.writeln("Lorem ipsum dolor sit amet, consectetur adipiscing elit, " +
+ "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
+ builder.write("Ut enim ad minim veniam, " +
+ "quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.");
+
+ // Aspose.Words does not track document metrics like these in real time.
+ Assert.assertEquals(0, doc.getBuiltInDocumentProperties().getCharacters());
+ Assert.assertEquals(0, doc.getBuiltInDocumentProperties().getWords());
+ Assert.assertEquals(1, doc.getBuiltInDocumentProperties().getParagraphs());
+ Assert.assertEquals(1, doc.getBuiltInDocumentProperties().getLines());
+
+ // To get accurate values for three of these properties, we will need to update them manually.
+ doc.updateWordCount();
+
+ Assert.assertEquals(196, doc.getBuiltInDocumentProperties().getCharacters());
+ Assert.assertEquals(36, doc.getBuiltInDocumentProperties().getWords());
+ Assert.assertEquals(2, doc.getBuiltInDocumentProperties().getParagraphs());
+
+ // For the line count, we will need to call a specific overload of the updating method.
+ Assert.assertEquals(1, doc.getBuiltInDocumentProperties().getLines());
+
+ doc.updateWordCount(true);
+
+ Assert.assertEquals(4, doc.getBuiltInDocumentProperties().getLines());
+ //ExEnd
+ }
+
+ @Test
+ public void tableStyleToDirectFormatting() throws Exception {
+ //ExStart
+ //ExFor:CompositeNode.GetChild
+ //ExFor:Document.ExpandTableStylesToDirectFormatting
+ //ExSummary:Shows how to apply the properties of a table's style directly to the table's elements.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Table table = builder.startTable();
+ builder.insertCell();
+ builder.write("Hello world!");
+ builder.endTable();
+
+ TableStyle tableStyle = (TableStyle) doc.getStyles().add(StyleType.TABLE, "MyTableStyle1");
+ tableStyle.setRowStripe(3);
+ tableStyle.setCellSpacing(5.0);
+ tableStyle.getShading().setBackgroundPatternColor(Color.WHITE);
+ tableStyle.getBorders().setColor(Color.BLUE);
+ tableStyle.getBorders().setLineStyle(LineStyle.DOT_DASH);
+
+ table.setStyle(tableStyle);
+
+ // This method concerns table style properties such as the ones we set above.
+ doc.expandTableStylesToDirectFormatting();
+
+ doc.save(getArtifactsDir() + "Document.TableStyleToDirectFormatting.docx");
+ //ExEnd
+
+ TestUtil.docPackageFileContainsString("",
+ getArtifactsDir() + "Document.TableStyleToDirectFormatting.docx", "word/document.xml");
+ TestUtil.docPackageFileContainsString("",
+ getArtifactsDir() + "Document.TableStyleToDirectFormatting.docx", "word/document.xml");
+ TestUtil.docPackageFileContainsString("",
+ getArtifactsDir() + "Document.TableStyleToDirectFormatting.docx", "word/document.xml");
+ }
+
+ @Test
+ public void getOriginalFileInfo() throws Exception {
+ //ExStart
+ //ExFor:Document.OriginalFileName
+ //ExFor:Document.OriginalLoadFormat
+ //ExSummary:Shows how to retrieve details of a document's load operation.
+ Document doc = new Document(getMyDir() + "Document.docx");
+
+ Assert.assertEquals(getMyDir() + "Document.docx", doc.getOriginalFileName());
+ Assert.assertEquals(LoadFormat.DOCX, doc.getOriginalLoadFormat());
+ //ExEnd
+ }
+
+ @Test(description = "WORDSNET-16099")
+ public void footnoteColumns() throws Exception {
+ //ExStart
+ //ExFor:FootnoteOptions
+ //ExFor:FootnoteOptions.Columns
+ //ExSummary:Shows how to split the footnote section into a given number of columns.
+ Document doc = new Document(getMyDir() + "Footnotes and endnotes.docx");
+ Assert.assertEquals(0, doc.getFootnoteOptions().getColumns()); //ExSkip
+
+ doc.getFootnoteOptions().setColumns(2);
+ doc.save(getArtifactsDir() + "Document.FootnoteColumns.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Document.FootnoteColumns.docx");
+
+ Assert.assertEquals(2, doc.getFirstSection().getPageSetup().getFootnoteOptions().getColumns());
+ }
+
+ @Test
+ public void removeExternalSchemaReferences() throws Exception {
+ //ExStart
+ //ExFor:Document.RemoveExternalSchemaReferences
+ //ExSummary:Shows how to remove all external XML schema references from a document.
+ Document doc = new Document(getMyDir() + "External XML schema.docx");
+
+ doc.removeExternalSchemaReferences();
+ //ExEnd
+ }
+
+ @Test
+ public void updateThumbnail() throws Exception {
+ //ExStart
+ //ExFor:Document.UpdateThumbnail()
+ //ExFor:Document.UpdateThumbnail(ThumbnailGeneratingOptions)
+ //ExFor:ThumbnailGeneratingOptions
+ //ExFor:ThumbnailGeneratingOptions.GenerateFromFirstPage
+ //ExFor:ThumbnailGeneratingOptions.ThumbnailSize
+ //ExSummary:Shows how to update a document's thumbnail.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ builder.writeln("Hello world!");
+ builder.insertImage(getImageDir() + "Logo.jpg");
+
+ // There are two ways of setting a thumbnail image when saving a document to .epub.
+ // 1 - Use the document's first page:
+ doc.updateThumbnail();
+ doc.save(getArtifactsDir() + "Document.UpdateThumbnail.FirstPage.epub");
+
+ // 2 - Use the first image found in the document:
+ ThumbnailGeneratingOptions options = new ThumbnailGeneratingOptions();
+ Assert.assertEquals(new Dimension(600, 900), options.getThumbnailSize()); //ExSKip
+ Assert.assertTrue(options.getGenerateFromFirstPage()); //ExSkip
+ options.setThumbnailSize(new Dimension(400, 400));
+ options.setGenerateFromFirstPage(false);
+
+ doc.updateThumbnail(options);
+ doc.save(getArtifactsDir() + "Document.UpdateThumbnail.FirstImage.epub");
+ //ExEnd
+ }
+
+ @Test
+ public void hyphenationOptions() throws Exception {
+ //ExStart
+ //ExFor:Document.HyphenationOptions
+ //ExFor:HyphenationOptions
+ //ExFor:HyphenationOptions.AutoHyphenation
+ //ExFor:HyphenationOptions.ConsecutiveHyphenLimit
+ //ExFor:HyphenationOptions.HyphenationZone
+ //ExFor:HyphenationOptions.HyphenateCaps
+ //ExSummary:Shows how to configure automatic hyphenation.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ builder.getFont().setSize(24.0);
+ builder.writeln("Lorem ipsum dolor sit amet, consectetur adipiscing elit, " +
+ "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
+
+ doc.getHyphenationOptions().setAutoHyphenation(true);
+ doc.getHyphenationOptions().setConsecutiveHyphenLimit(2);
+ doc.getHyphenationOptions().setHyphenationZone(720);
+ doc.getHyphenationOptions().setHyphenateCaps(true);
+
+ doc.save(getArtifactsDir() + "Document.HyphenationOptions.docx");
+ //ExEnd
+
+ Assert.assertEquals(true, doc.getHyphenationOptions().getAutoHyphenation());
+ Assert.assertEquals(2, doc.getHyphenationOptions().getConsecutiveHyphenLimit());
+ Assert.assertEquals(720, doc.getHyphenationOptions().getHyphenationZone());
+ Assert.assertEquals(true, doc.getHyphenationOptions().getHyphenateCaps());
+
+ Assert.assertTrue(DocumentHelper.compareDocs(getArtifactsDir() + "Document.HyphenationOptions.docx",
+ getGoldsDir() + "Document.HyphenationOptions Gold.docx"));
+ }
+
+ @Test
+ public void hyphenationOptionsDefaultValues() throws Exception {
+ Document doc = new Document();
+ doc = DocumentHelper.saveOpen(doc);
+
+ Assert.assertEquals(false, doc.getHyphenationOptions().getAutoHyphenation());
+ Assert.assertEquals(0, doc.getHyphenationOptions().getConsecutiveHyphenLimit());
+ Assert.assertEquals(360, doc.getHyphenationOptions().getHyphenationZone()); // 0.25 inch
+ Assert.assertEquals(true, doc.getHyphenationOptions().getHyphenateCaps());
+ }
+
+ @Test
+ public void hyphenationOptionsExceptions() throws Exception {
+ Document doc = new Document();
+
+ doc.getHyphenationOptions().setConsecutiveHyphenLimit(0);
+ Assert.assertThrows(IllegalArgumentException.class, () -> doc.getHyphenationOptions().setHyphenationZone(0));
+
+ Assert.assertThrows(IllegalArgumentException.class, () -> doc.getHyphenationOptions().setConsecutiveHyphenLimit(-1));
+ doc.getHyphenationOptions().setHyphenationZone(360);
+ }
+
+ @Test
+ public void ooxmlComplianceVersion() throws Exception {
+ //ExStart
+ //ExFor:Document.Compliance
+ //ExSummary:Shows how to read a loaded document's Open Office XML compliance version.
+ // The compliance version varies between documents created by different versions of Microsoft Word.
+ Document doc = new Document(getMyDir() + "Document.doc");
+
+ Assert.assertEquals(doc.getCompliance(), OoxmlCompliance.ECMA_376_2006);
+
+ doc = new Document(getMyDir() + "Document.docx");
+
+ Assert.assertEquals(doc.getCompliance(), OoxmlCompliance.ISO_29500_2008_TRANSITIONAL);
+ //ExEnd
+ }
+
+ @Test(enabled = false, description = "WORDSNET-20342")
+ public void imageSaveOptions() throws Exception {
+ //ExStart
+ //ExFor:Document.Save(String, SaveOptions)
+ //ExFor:SaveOptions.UseAntiAliasing
+ //ExFor:SaveOptions.UseHighQualityRendering
+ //ExSummary:Shows how to improve the quality of a rendered document with SaveOptions.
+ Document doc = new Document(getMyDir() + "Rendering.docx");
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ builder.getFont().setSize(60.0);
+ builder.writeln("Some text.");
+
+ SaveOptions options = new ImageSaveOptions(SaveFormat.JPEG);
+ Assert.assertFalse(options.getUseAntiAliasing()); //ExSkip
+ Assert.assertFalse(options.getUseHighQualityRendering()); //ExSkip
+
+ doc.save(getArtifactsDir() + "Document.ImageSaveOptions.Default.jpg", options);
+
+ options.setUseAntiAliasing(true);
+ options.setUseHighQualityRendering(true);
+
+ doc.save(getArtifactsDir() + "Document.ImageSaveOptions.HighQuality.jpg", options);
+ //ExEnd
+
+ TestUtil.verifyImage(794, 1122, getArtifactsDir() + "Document.ImageSaveOptions.Default.jpg");
+ TestUtil.verifyImage(794, 1122, getArtifactsDir() + "Document.ImageSaveOptions.HighQuality.jpg");
+ }
+
+ @Test
+ public void cleanup() throws Exception {
+ //ExStart
+ //ExFor:Document.Cleanup
+ //ExSummary:Shows how to remove unused custom styles from a document.
+ Document doc = new Document();
+
+ doc.getStyles().add(StyleType.LIST, "MyListStyle1");
+ doc.getStyles().add(StyleType.LIST, "MyListStyle2");
+ doc.getStyles().add(StyleType.CHARACTER, "MyParagraphStyle1");
+ doc.getStyles().add(StyleType.CHARACTER, "MyParagraphStyle2");
+
+ // Combined with the built-in styles, the document now has eight styles.
+ // A custom style counts as "used" while applied to some part of the document,
+ // which means that the four styles we added are currently unused.
+ Assert.assertEquals(8, doc.getStyles().getCount());
+
+ // Apply a custom character style, and then a custom list style. Doing so will mark the styles as "used".
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ builder.getFont().setStyle(doc.getStyles().get("MyParagraphStyle1"));
+ builder.writeln("Hello world!");
+
+ List docList = doc.getLists().add(doc.getStyles().get("MyListStyle1"));
+ builder.getListFormat().setList(docList);
+ builder.writeln("Item 1");
+ builder.writeln("Item 2");
+
+ doc.cleanup();
+
+ Assert.assertEquals(6, doc.getStyles().getCount());
+
+ // Removing every node that a custom style is applied to marks it as "unused" again.
+ // Run the Cleanup method again to remove them.
+ doc.getFirstSection().getBody().removeAllChildren();
+ doc.cleanup();
+
+ Assert.assertEquals(4, doc.getStyles().getCount());
+ //ExEnd
+ }
+
+ @Test
+ public void automaticallyUpdateStyles() throws Exception {
+ //ExStart
+ //ExFor:Document.AutomaticallyUpdateStyles
+ //ExSummary:Shows how to attach a template to a document.
+ Document doc = new Document();
+
+ // Microsoft Word documents by default come with an attached template called "Normal.dotm".
+ // There is no default template for blank Aspose.Words documents.
+ Assert.assertEquals("", doc.getAttachedTemplate());
+
+ // Attach a template, then set the flag to apply style changes
+ // within the template to styles in our document.
+ doc.setAttachedTemplate(getMyDir() + "Business brochure.dotx");
+ doc.setAutomaticallyUpdateStyles(true);
+
+ doc.save(getArtifactsDir() + "Document.AutomaticallyUpdateStyles.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Document.AutomaticallyUpdateStyles.docx");
+
+ Assert.assertTrue(doc.getAutomaticallyUpdateStyles());
+ Assert.assertEquals(getMyDir() + "Business brochure.dotx", doc.getAttachedTemplate());
+ Assert.assertTrue(new File(doc.getAttachedTemplate()).exists());
+ }
+
+ @Test
+ public void defaultTemplate() throws Exception {
+ //ExStart
+ //ExFor:Document.AttachedTemplate
+ //ExFor:Document.AutomaticallyUpdateStyles
+ //ExFor:SaveOptions.CreateSaveOptions(String)
+ //ExFor:SaveOptions.DefaultTemplate
+ //ExSummary:Shows how to set a default template for documents that do not have attached templates.
+ Document doc = new Document();
+
+ // Enable automatic style updating, but do not attach a template document.
+ doc.setAutomaticallyUpdateStyles(true);
+
+ Assert.assertEquals("", doc.getAttachedTemplate());
+
+ // Since there is no template document, the document had nowhere to track style changes.
+ // Use a SaveOptions object to automatically set a template
+ // if a document that we are saving does not have one.
+ SaveOptions options = SaveOptions.createSaveOptions("Document.DefaultTemplate.docx");
+ options.setDefaultTemplate(getMyDir() + "Business brochure.dotx");
+
+ doc.save(getArtifactsDir() + "Document.DefaultTemplate.docx", options);
+ //ExEnd
+
+ Assert.assertTrue(new File(options.getDefaultTemplate()).exists());
+ }
+
+ @Test
+ public void useSubstitutions() throws Exception
+ {
+ //ExStart
+ //ExFor:FindReplaceOptions.#ctor()
+ //ExFor:FindReplaceOptions.UseSubstitutions
+ //ExFor:FindReplaceOptions.LegacyMode
+ //ExSummary:Shows how to recognize and use substitutions within replacement patterns.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ builder.write("Jason gave money to Paul.");
+
+ String regex = "([A-z]+) gave money to ([A-z]+)";
+
+ FindReplaceOptions options = new FindReplaceOptions();
+ options.setUseSubstitutions(true);
+
+ // Using legacy mode does not support many advanced features, so we need to set it to 'false'.
+ options.setLegacyMode(false);
+
+ doc.getRange().replace(Pattern.compile(regex), "$2 took money from $1", options);
+
+ Assert.assertEquals(doc.getText(), "Paul took money from Jason.\f");
+ //ExEnd
+ }
+
+ @Test
+ public void setInvalidateFieldTypes() throws Exception
+ {
+ //ExStart
+ //ExFor:Document.NormalizeFieldTypes
+ //ExFor:Range.NormalizeFieldTypes
+ //ExSummary:Shows how to get the keep a field's type up to date with its field code.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Field field = builder.insertField("DATE", null);
+
+ // Aspose.Words automatically detects field types based on field codes.
+ Assert.assertEquals(FieldType.FIELD_DATE, field.getType());
+
+ // Manually change the raw text of the field, which determines the field code.
+ Run fieldText = (Run) doc.getFirstSection().getBody().getFirstParagraph().getChildNodes(NodeType.RUN, true).get(0);
+ Assert.assertEquals("DATE", fieldText.getText()); //ExSkip
+ fieldText.setText("PAGE");
+
+ // Changing the field code has changed this field to one of a different type,
+ // but the field's type properties still display the old type.
+ Assert.assertEquals("PAGE", field.getFieldCode());
+ Assert.assertEquals(FieldType.FIELD_DATE, field.getType());
+ Assert.assertEquals(FieldType.FIELD_DATE, field.getStart().getFieldType());
+ Assert.assertEquals(FieldType.FIELD_DATE, field.getSeparator().getFieldType());
+ Assert.assertEquals(FieldType.FIELD_DATE, field.getEnd().getFieldType());
+
+ // Update those properties with this method to display current value.
+ doc.normalizeFieldTypes();
+
+ Assert.assertEquals(FieldType.FIELD_PAGE, field.getType());
+ Assert.assertEquals(FieldType.FIELD_PAGE, field.getStart().getFieldType());
+ Assert.assertEquals(FieldType.FIELD_PAGE, field.getSeparator().getFieldType());
+ Assert.assertEquals(FieldType.FIELD_PAGE, field.getEnd().getFieldType());
+ //ExEnd
+ }
+
+ @Test(dataProvider = "layoutOptionsHiddenTextDataProvider")
+ public void layoutOptionsHiddenText(boolean showHiddenText) throws Exception {
+ //ExStart
+ //ExFor:Document.LayoutOptions
+ //ExFor:LayoutOptions
+ //ExFor:LayoutOptions.ShowHiddenText
+ //ExSummary:Shows how to hide text in a rendered output document.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ Assert.assertFalse(doc.getLayoutOptions().getShowHiddenText()); //ExSkip
+
+ // Insert hidden text, then specify whether we wish to omit it from a rendered document.
+ builder.writeln("This text is not hidden.");
+ builder.getFont().setHidden(true);
+ builder.writeln("This text is hidden.");
+
+ doc.getLayoutOptions().setShowHiddenText(showHiddenText);
+
+ doc.save(getArtifactsDir() + "Document.LayoutOptionsHiddenText.pdf");
+ //ExEnd
+
+ com.aspose.pdf.Document pdfDoc = new com.aspose.pdf.Document(getArtifactsDir() + "Document.LayoutOptionsHiddenText.pdf");
+ TextAbsorber textAbsorber = new TextAbsorber();
+ textAbsorber.visit(pdfDoc);
+
+ Assert.assertEquals(showHiddenText
+ ? MessageFormat.format("This text is not hidden.{0}This text is hidden.", System.lineSeparator())
+ : "This text is not hidden.", textAbsorber.getText());
+
+ pdfDoc.close();
+ }
+
+ @DataProvider(name = "layoutOptionsHiddenTextDataProvider")
+ public static Object[][] layoutOptionsHiddenTextDataProvider() {
+ return new Object[][]
+ {
+ {false},
+ {true},
+ };
+ }
+
+ @Test(dataProvider = "layoutOptionsParagraphMarksDataProvider")
+ public void layoutOptionsParagraphMarks(boolean showParagraphMarks) throws Exception {
+ //ExStart
+ //ExFor:Document.LayoutOptions
+ //ExFor:LayoutOptions
+ //ExFor:LayoutOptions.ShowParagraphMarks
+ //ExSummary:Shows how to show paragraph marks in a rendered output document.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ Assert.assertFalse(doc.getLayoutOptions().getShowParagraphMarks()); //ExSkip
+
+ // Add some paragraphs, then enable paragraph marks to show the ends of paragraphs
+ // with a pilcrow (¶) symbol when we render the document.
+ builder.writeln("Hello world!");
+ builder.writeln("Hello again!");
+
+ doc.getLayoutOptions().setShowParagraphMarks(showParagraphMarks);
+
+ doc.save(getArtifactsDir() + "Document.LayoutOptionsParagraphMarks.pdf");
+ //ExEnd
+
+ com.aspose.pdf.Document pdfDoc = new com.aspose.pdf.Document(getArtifactsDir() + "Document.LayoutOptionsParagraphMarks.pdf");
+ TextAbsorber textAbsorber = new TextAbsorber();
+ textAbsorber.visit(pdfDoc);
+
+ Assert.assertEquals(showParagraphMarks ?
+ MessageFormat.format("Hello world!¶{0}Hello again!¶{1}¶", System.lineSeparator(), System.lineSeparator()) :
+ MessageFormat.format("Hello world!{0}Hello again!", System.lineSeparator()), textAbsorber.getText());
+
+ pdfDoc.close();
+ }
+
+ //JAVA-added data provider for test method
+ @DataProvider(name = "layoutOptionsParagraphMarksDataProvider")
+ public static Object[][] layoutOptionsParagraphMarksDataProvider() throws Exception {
+ return new Object[][]
+ {
+ {false},
+ {true},
+ };
+ }
+
+ @Test
+ public void updatePageLayout() throws Exception {
+ //ExStart
+ //ExFor:StyleCollection.Item(String)
+ //ExFor:SectionCollection.Item(Int32)
+ //ExFor:Document.UpdatePageLayout
+ //ExFor:Margins
+ //ExFor:PageSetup.Margins
+ //ExSummary:Shows when to recalculate the page layout of the document.
+ Document doc = new Document(getMyDir() + "Rendering.docx");
+
+ // Saving a document to PDF, to an image, or printing for the first time will automatically
+ // cache the layout of the document within its pages.
+ doc.save(getArtifactsDir() + "Document.UpdatePageLayout.1.pdf");
+
+ // Modify the document in some way.
+ doc.getStyles().get("Normal").getFont().setSize(6.0);
+ doc.getSections().get(0).getPageSetup().setOrientation(Orientation.LANDSCAPE);
+ doc.getSections().get(0).getPageSetup().setMargins(Margins.MIRRORED);
+
+ // In the current version of Aspose.Words, modifying the document does not automatically rebuild
+ // the cached page layout. If we wish for the cached layout
+ // to stay up to date, we will need to update it manually.
+ doc.updatePageLayout();
+
+ doc.save(getArtifactsDir() + "Document.UpdatePageLayout.2.pdf");
+ //ExEnd
+ }
+
+ @Test
+ public void docPackageCustomParts() throws Exception {
+ //ExStart
+ //ExFor:CustomPart
+ //ExFor:CustomPart.ContentType
+ //ExFor:CustomPart.RelationshipType
+ //ExFor:CustomPart.IsExternal
+ //ExFor:CustomPart.Data
+ //ExFor:CustomPart.Name
+ //ExFor:CustomPart.Clone
+ //ExFor:CustomPartCollection
+ //ExFor:CustomPartCollection.Add(CustomPart)
+ //ExFor:CustomPartCollection.Clear
+ //ExFor:CustomPartCollection.Clone
+ //ExFor:CustomPartCollection.Count
+ //ExFor:CustomPartCollection.GetEnumerator
+ //ExFor:CustomPartCollection.Item(Int32)
+ //ExFor:CustomPartCollection.RemoveAt(Int32)
+ //ExFor:Document.PackageCustomParts
+ //ExSummary:Shows how to access a document's arbitrary custom parts collection.
+ Document doc = new Document(getMyDir() + "Custom parts OOXML package.docx");
+
+ Assert.assertEquals(2, doc.getPackageCustomParts().getCount());
+
+ // Clone the second part, then add the clone to the collection.
+ CustomPart clonedPart = doc.getPackageCustomParts().get(1).deepClone();
+ doc.getPackageCustomParts().add(clonedPart);
+ testDocPackageCustomParts(doc.getPackageCustomParts()); //ExSkip
+
+ Assert.assertEquals(3, doc.getPackageCustomParts().getCount());
+
+ // Enumerate over the collection and print every part.
+ Iterator enumerator = doc.getPackageCustomParts().iterator();
+
+ int index = 0;
+ while (enumerator.hasNext()) {
+ CustomPart customPart = enumerator.next();
+ System.out.println(MessageFormat.format("Part index {0}:", index));
+ System.out.println(MessageFormat.format("\tName: {0}", customPart.getName()));
+ System.out.println(MessageFormat.format("\tContentType: {0}", customPart.getContentType()));
+ System.out.println(MessageFormat.format("\tRelationshipType: {0}", customPart.getRelationshipType()));
+ if (customPart.isExternal()) {
+ System.out.println("\tSourced from outside the document");
+ } else {
+ System.out.println(MessageFormat.format("\tSourced from within the document, length: {0} bytes", customPart.getData().length));
+ }
+ index++;
+ }
+
+ // We can remove elements from this collection individually, or all at once.
+ doc.getPackageCustomParts().removeAt(2);
+
+ Assert.assertEquals(2, doc.getPackageCustomParts().getCount());
+
+ doc.getPackageCustomParts().clear();
+
+ Assert.assertEquals(0, doc.getPackageCustomParts().getCount());
+ //ExEnd
+ }
+
+ private static void testDocPackageCustomParts(CustomPartCollection parts) {
+ Assert.assertEquals(3, parts.getCount());
+
+ Assert.assertEquals("/payload/payload_on_package.test", parts.get(0).getName());
+ Assert.assertEquals("mytest/somedata", parts.get(0).getContentType());
+ Assert.assertEquals("http://mytest.payload.internal", parts.get(0).getRelationshipType());
+ Assert.assertEquals(false, parts.get(0).isExternal());
+ Assert.assertEquals(18, parts.get(0).getData().length);
+
+ Assert.assertEquals("http://www.aspose.com/Images/aspose-logo.jpg", parts.get(1).getName());
+ Assert.assertEquals("", parts.get(1).getContentType());
+ Assert.assertEquals("http://mytest.payload.external", parts.get(1).getRelationshipType());
+ Assert.assertEquals(true, parts.get(1).isExternal());
+ Assert.assertEquals(0, parts.get(1).getData().length);
+
+ Assert.assertEquals("http://www.aspose.com/Images/aspose-logo.jpg", parts.get(2).getName());
+ Assert.assertEquals("", parts.get(2).getContentType());
+ Assert.assertEquals("http://mytest.payload.external", parts.get(2).getRelationshipType());
+ Assert.assertEquals(true, parts.get(2).isExternal());
+ Assert.assertEquals(0, parts.get(2).getData().length);
+ }
+
+ @Test(dataProvider = "shadeFormDataDataProvider")
+ public void shadeFormData(boolean useGreyShading) throws Exception {
+ //ExStart
+ //ExFor:Document.ShadeFormData
+ //ExSummary:Shows how to apply gray shading to form fields.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ Assert.assertTrue(doc.getShadeFormData()); //ExSkip
+
+ builder.write("Hello world! ");
+ builder.insertTextInput("My form field", TextFormFieldType.REGULAR, "",
+ "Text contents of form field, which are shaded in grey by default.", 0);
+
+ // We can turn the grey shading off, so the bookmarked text will blend in with the other text.
+ doc.setShadeFormData(useGreyShading);
+ doc.save(getArtifactsDir() + "Document.ShadeFormData.docx");
+ //ExEnd
+ }
+
+ //JAVA-added data provider for test method
+ @DataProvider(name = "shadeFormDataDataProvider")
+ public static Object[][] shadeFormDataDataProvider() throws Exception {
+ return new Object[][]
+ {
+ {false},
+ {true},
+ };
+ }
+
+ @Test
+ public void versionsCount() throws Exception {
+ //ExStart
+ //ExFor:Document.VersionsCount
+ //ExSummary:Shows how to work with the versions count feature of older Microsoft Word documents.
+ Document doc = new Document(getMyDir() + "Versions.doc");
+
+ // We can read this property of a document, but we cannot preserve it while saving.
+ Assert.assertEquals(4, doc.getVersionsCount());
+
+ doc.save(getArtifactsDir() + "Document.VersionsCount.doc");
+ doc = new Document(getArtifactsDir() + "Document.VersionsCount.doc");
+
+ Assert.assertEquals(0, doc.getVersionsCount());
+ //ExEnd
+ }
+
+ @Test
+ public void writeProtection() throws Exception {
+ //ExStart
+ //ExFor:Document.WriteProtection
+ //ExFor:WriteProtection
+ //ExFor:WriteProtection.IsWriteProtected
+ //ExFor:WriteProtection.ReadOnlyRecommended
+ //ExFor:WriteProtection.SetPassword(String)
+ //ExFor:WriteProtection.ValidatePassword(String)
+ //ExSummary:Shows how to protect a document with a password.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ builder.writeln("Hello world! This document is protected.");
+ Assert.assertFalse(doc.getWriteProtection().isWriteProtected()); //ExSkip
+ Assert.assertFalse(doc.getWriteProtection().getReadOnlyRecommended()); //ExSkip
+
+ // Enter a password up to 15 characters in length, and then verify the document's protection status.
+ doc.getWriteProtection().setPassword("MyPassword");
+ doc.getWriteProtection().setReadOnlyRecommended(true);
+
+ Assert.assertTrue(doc.getWriteProtection().isWriteProtected());
+ Assert.assertTrue(doc.getWriteProtection().validatePassword("MyPassword"));
+
+ // Protection does not prevent the document from being edited programmatically, nor does it encrypt the contents.
+ doc.save(getArtifactsDir() + "Document.WriteProtection.docx");
+ doc = new Document(getArtifactsDir() + "Document.WriteProtection.docx");
+
+ Assert.assertTrue(doc.getWriteProtection().isWriteProtected());
+
+ builder = new DocumentBuilder(doc);
+ builder.moveToDocumentEnd();
+ builder.writeln("Writing text in a protected document.");
+
+ Assert.assertEquals("Hello world! This document is protected." +
+ "\rWriting text in a protected document.", doc.getText().trim());
+ //ExEnd
+
+ Assert.assertTrue(doc.getWriteProtection().getReadOnlyRecommended());
+ Assert.assertTrue(doc.getWriteProtection().validatePassword("MyPassword"));
+ Assert.assertFalse(doc.getWriteProtection().validatePassword("wrongpassword"));
+ }
+
+ @Test(dataProvider = "removePersonalInformationDataProvider")
+ public void removePersonalInformation(boolean saveWithoutPersonalInfo) throws Exception {
+ //ExStart
+ //ExFor:Document.RemovePersonalInformation
+ //ExSummary:Shows how to enable the removal of personal information during a manual save.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert some content with personal information.
+ doc.getBuiltInDocumentProperties().setAuthor("John Doe");
+ doc.getBuiltInDocumentProperties().setCompany("Placeholder Inc.");
+
+ doc.startTrackRevisions(doc.getBuiltInDocumentProperties().getAuthor(), new Date());
+ builder.write("Hello world!");
+ doc.stopTrackRevisions();
+
+ // This flag is equivalent to File -> Options -> Trust Center -> Trust Center Settings... ->
+ // Privacy Options -> "Remove personal information from file properties on save" in Microsoft Word.
+ doc.setRemovePersonalInformation(saveWithoutPersonalInfo);
+
+ // This option will not take effect during a save operation made using Aspose.Words.
+ // Personal data will be removed from our document with the flag set when we save it manually using Microsoft Word.
+ doc.save(getArtifactsDir() + "Document.RemovePersonalInformation.docx");
+ doc = new Document(getArtifactsDir() + "Document.RemovePersonalInformation.docx");
+
+ Assert.assertEquals(saveWithoutPersonalInfo, doc.getRemovePersonalInformation());
+ Assert.assertEquals("John Doe", doc.getBuiltInDocumentProperties().getAuthor());
+ Assert.assertEquals("Placeholder Inc.", doc.getBuiltInDocumentProperties().getCompany());
+ Assert.assertEquals("John Doe", doc.getRevisions().get(0).getAuthor());
+ //ExEnd
+ }
+
+ @DataProvider(name = "removePersonalInformationDataProvider")
+ public static Object[][] removePersonalInformationDataProvider() throws Exception {
+ return new Object[][]
+ {
+ {false},
+ {true},
+ };
+ }
+
+ @Test
+ public void showComments() throws Exception
+ {
+ //ExStart
+ //ExFor:LayoutOptions.CommentDisplayMode
+ //ExFor:CommentDisplayMode
+ //ExSummary:Shows how to show comments when saving a document to a rendered format.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ builder.write("Hello world!");
+
+ Comment comment = new Comment(doc, "John Doe", "J.D.", new Date());
+ comment.setText("My comment.");
+ builder.getCurrentParagraph().appendChild(comment);
+
+ // ShowInAnnotations is only available in Pdf1.7 and Pdf1.5 formats.
+ // In other formats, it will work similarly to Hide.
+ doc.getLayoutOptions().setCommentDisplayMode(CommentDisplayMode.SHOW_IN_ANNOTATIONS);
+
+ doc.save(getArtifactsDir() + "Document.ShowCommentsInAnnotations.pdf");
+
+ // Note that it's required to rebuild the document page layout (via Document.UpdatePageLayout() method)
+ // after changing the Document.LayoutOptions values.
+ doc.getLayoutOptions().setCommentDisplayMode(CommentDisplayMode.SHOW_IN_BALLOONS);
+ doc.updatePageLayout();
+
+ doc.save(getArtifactsDir() + "Document.ShowCommentsInBalloons.pdf");
+ //ExEnd
+
+ com.aspose.pdf.Document pdfDoc =
+ new com.aspose.pdf.Document(getArtifactsDir() + "Document.ShowCommentsInBalloons.pdf");
+ TextAbsorber textAbsorber = new TextAbsorber();
+ textAbsorber.visit(pdfDoc);
+
+ Assert.assertEquals(
+ "Hello world! Commented [J.D.1]: My comment.",
+ textAbsorber.getText());
+
+ pdfDoc.close();
+ }
+
+ @Test
+ public void copyTemplateStylesViaDocument() throws Exception {
+ //ExStart
+ //ExFor:Document.CopyStylesFromTemplate(Document)
+ //ExSummary:Shows how to copies styles from the template to a document via Document.
+ Document template = new Document(getMyDir() + "Rendering.docx");
+ Document target = new Document(getMyDir() + "Document.docx");
+
+ Assert.assertEquals(template.getStyles().getCount(), 18); //ExSkip
+ Assert.assertEquals(target.getStyles().getCount(), 12); //ExSkip
+
+ target.copyStylesFromTemplate(template);
+ //ExEnd
+ Assert.assertEquals(target.getStyles().getCount(), 22); //ExSkip
+ }
+
+ @Test
+ public void copyTemplateStylesViaDocumentNew() throws Exception {
+ //ExStart
+ //ExFor:Document.CopyStylesFromTemplate(Document)
+ //ExFor:Document.CopyStylesFromTemplate(String)
+ //ExSummary:Shows how to copy styles from one document to another.
+ // Create a document, and then add styles that we will copy to another document.
+ Document template = new Document();
+
+ Style style = template.getStyles().add(StyleType.PARAGRAPH, "TemplateStyle1");
+ style.getFont().setName("Times New Roman");
+ style.getFont().setColor(Color.WHITE);
+
+ style = template.getStyles().add(StyleType.PARAGRAPH, "TemplateStyle2");
+ style.getFont().setName("Arial");
+ style.getFont().setColor(Color.RED);
+
+ style = template.getStyles().add(StyleType.PARAGRAPH, "TemplateStyle3");
+ style.getFont().setName("Courier New");
+ style.getFont().setColor(Color.BLUE);
+
+ Assert.assertEquals(7, template.getStyles().getCount());
+
+ // Create a document which we will copy the styles to.
+ Document target = new Document();
+
+ // Create a style with the same name as a style from the template document and add it to the target document.
+ style = target.getStyles().add(StyleType.PARAGRAPH, "TemplateStyle3");
+ style.getFont().setName("Calibri");
+ style.getFont().setColor(Color.ORANGE);
+
+ Assert.assertEquals(5, target.getStyles().getCount());
+
+ // There are two ways of calling the method to copy all the styles from one document to another.
+ // 1 - Passing the template document object:
+ target.copyStylesFromTemplate(template);
+
+ // Copying styles adds all styles from the template document to the target
+ // and overwrites existing styles with the same name.
+ Assert.assertEquals(7, target.getStyles().getCount());
+
+ Assert.assertEquals("Courier New", target.getStyles().get("TemplateStyle3").getFont().getName());
+ Assert.assertEquals(Color.BLUE.getRGB(), target.getStyles().get("TemplateStyle3").getFont().getColor().getRGB());
+
+ // 2 - Passing the local system filename of a template document:
+ target.copyStylesFromTemplate(getMyDir() + "Rendering.docx");
+
+ Assert.assertEquals(21, target.getStyles().getCount());
+ //ExEnd
+ }
+
+ @Test
+ public void readMacrosFromExistingDocument() throws Exception {
+ //ExStart
+ //ExFor:Document.VbaProject
+ //ExFor:VbaModuleCollection
+ //ExFor:VbaModuleCollection.Count
+ //ExFor:VbaModuleCollection.Item(System.Int32)
+ //ExFor:VbaModuleCollection.Item(System.String)
+ //ExFor:VbaModuleCollection.Remove
+ //ExFor:VbaModule
+ //ExFor:VbaModule.Name
+ //ExFor:VbaModule.SourceCode
+ //ExFor:VbaProject
+ //ExFor:VbaProject.Name
+ //ExFor:VbaProject.Modules
+ //ExFor:VbaProject.CodePage
+ //ExFor:VbaProject.IsSigned
+ //ExSummary:Shows how to access a document's VBA project information.
+ Document doc = new Document(getMyDir() + "VBA project.docm");
+
+ // A VBA project contains a collection of VBA modules.
+ VbaProject vbaProject = doc.getVbaProject();
+ Assert.assertTrue(vbaProject.isSigned()); //ExSkip
+ System.out.println(vbaProject.isSigned()
+ ? MessageFormat.format("Project name: {0} signed; Project code page: {1}; Modules count: {2}\n", vbaProject.getName(), vbaProject.getCodePage(), vbaProject.getModules().getCount())
+ : MessageFormat.format("Project name: {0} not signed; Project code page: {1}; Modules count: {2}\n", vbaProject.getName(), vbaProject.getCodePage(), vbaProject.getModules().getCount()));
+
+ VbaModuleCollection vbaModules = doc.getVbaProject().getModules();
+
+ Assert.assertEquals(vbaModules.getCount(), 3);
+
+ for (VbaModule module : vbaModules) {
+ System.out.println(MessageFormat.format("Module name: {0};\nModule code:\n{1}\n", module.getName(), module.getSourceCode()));
+ }
+
+ // Set new source code for VBA module. You can access VBA modules in the collection either by index or by name.
+ vbaModules.get(0).setSourceCode("Your VBA code...");
+ vbaModules.get("Module1").setSourceCode("Your VBA code...");
+
+ // Remove a module from the collection.
+ vbaModules.remove(vbaModules.get(2));
+ //ExEnd
+
+ Assert.assertEquals("AsposeVBAtest", vbaProject.getName());
+ Assert.assertEquals(2, vbaProject.getModules().getCount());
+ Assert.assertEquals(1251, vbaProject.getCodePage());
+ Assert.assertFalse(vbaProject.isSigned());
+
+ Assert.assertEquals("ThisDocument", vbaModules.get(0).getName());
+ Assert.assertEquals("Your VBA code...", vbaModules.get(0).getSourceCode());
+
+ Assert.assertEquals("Module1", vbaModules.get(1).getName());
+ Assert.assertEquals("Your VBA code...", vbaModules.get(1).getSourceCode());
+ }
+
+ @Test
+ public void saveOutputParameters() throws Exception {
+ //ExStart
+ //ExFor:SaveOutputParameters
+ //ExFor:SaveOutputParameters.ContentType
+ //ExSummary:Shows how to access output parameters of a document's save operation.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ builder.writeln("Hello world!");
+
+ // After we save a document, we can access the Internet Media Type (MIME type) of the newly created output document.
+ SaveOutputParameters parameters = doc.save(getArtifactsDir() + "Document.SaveOutputParameters.doc");
+
+ Assert.assertEquals("application/msword", parameters.getContentType());
+
+ // This property changes depending on the save format.
+ parameters = doc.save(getArtifactsDir() + "Document.SaveOutputParameters.pdf");
+
+ Assert.assertEquals("application/pdf", parameters.getContentType());
+ //ExEnd
+ }
+
+ @Test
+ public void subDocument() throws Exception {
+ //ExStart
+ //ExFor:SubDocument
+ //ExFor:SubDocument.NodeType
+ //ExSummary:Shows how to access a master document's subdocument.
+ Document doc = new Document(getMyDir() + "Master document.docx");
+
+ NodeCollection subDocuments = doc.getChildNodes(NodeType.SUB_DOCUMENT, true);
+ Assert.assertEquals(1, subDocuments.getCount()); //ExSkip
+
+ // This node serves as a reference to an external document, and its contents cannot be accessed.
+ SubDocument subDocument = (SubDocument) subDocuments.get(0);
+
+ Assert.assertFalse(subDocument.isComposite());
+ //ExEnd
+ }
+
+ @Test
+ public void createWebExtension() throws Exception {
+ //ExStart
+ //ExFor:BaseWebExtensionCollection`1.Add(`0)
+ //ExFor:BaseWebExtensionCollection`1.Clear
+ //ExFor:Document.WebExtensionTaskPanes
+ //ExFor:TaskPane
+ //ExFor:TaskPane.DockState
+ //ExFor:TaskPane.IsVisible
+ //ExFor:TaskPane.Width
+ //ExFor:TaskPane.IsLocked
+ //ExFor:TaskPane.WebExtension
+ //ExFor:TaskPane.Row
+ //ExFor:WebExtension
+ //ExFor:WebExtension.Id
+ //ExFor:WebExtension.AlternateReferences
+ //ExFor:WebExtension.Reference
+ //ExFor:WebExtension.Properties
+ //ExFor:WebExtension.Bindings
+ //ExFor:WebExtension.IsFrozen
+ //ExFor:WebExtensionReference
+ //ExFor:WebExtensionReference.Id
+ //ExFor:WebExtensionReference.Version
+ //ExFor:WebExtensionReference.StoreType
+ //ExFor:WebExtensionReference.Store
+ //ExFor:WebExtensionPropertyCollection
+ //ExFor:WebExtensionBindingCollection
+ //ExFor:WebExtensionProperty.#ctor(String, String)
+ //ExFor:WebExtensionProperty.Name
+ //ExFor:WebExtensionProperty.Value
+ //ExFor:WebExtensionBinding.#ctor(String, WebExtensionBindingType, String)
+ //ExFor:WebExtensionStoreType
+ //ExFor:WebExtensionBindingType
+ //ExFor:TaskPaneDockState
+ //ExFor:TaskPaneCollection
+ //ExFor:WebExtensionBinding.Id
+ //ExFor:WebExtensionBinding.AppRef
+ //ExFor:WebExtensionBinding.BindingType
+ //ExSummary:Shows how to add a web extension to a document.
+ Document doc = new Document();
+
+ // Create task pane with "MyScript" add-in, which will be used by the document,
+ // then set its default location.
+ TaskPane myScriptTaskPane = new TaskPane();
+ doc.getWebExtensionTaskPanes().add(myScriptTaskPane);
+ myScriptTaskPane.setDockState(TaskPaneDockState.RIGHT);
+ myScriptTaskPane.isVisible(true);
+ myScriptTaskPane.setWidth(300.0);
+ myScriptTaskPane.isLocked(true);
+
+ // If there are multiple task panes in the same docking location, we can set this index to arrange them.
+ myScriptTaskPane.setRow(1);
+
+ // Create an add-in called "MyScript Math Sample", which the task pane will display within.
+ WebExtension webExtension = myScriptTaskPane.getWebExtension();
+
+ // Set application store reference parameters for our add-in, such as the ID.
+ webExtension.getReference().setId("WA104380646");
+ webExtension.getReference().setVersion("1.0.0.0");
+ webExtension.getReference().setStoreType(WebExtensionStoreType.OMEX);
+ webExtension.getReference().setStore("English (United States)");
+ webExtension.getProperties().add(new WebExtensionProperty("MyScript", "MyScript Math Sample"));
+ webExtension.getBindings().add(new WebExtensionBinding("MyScript", WebExtensionBindingType.TEXT, "104380646"));
+
+ // Allow the user to interact with the add-in.
+ webExtension.isFrozen(false);
+
+ // We can access the web extension in Microsoft Word via Developer -> Add-ins.
+ doc.save(getArtifactsDir() + "Document.WebExtension.docx");
+
+ // Remove all web extension task panes at once like this.
+ doc.getWebExtensionTaskPanes().clear();
+
+ Assert.assertEquals(0, doc.getWebExtensionTaskPanes().getCount());
+
+ doc = new Document(getArtifactsDir() + "Document.WebExtension.docx");
+
+ myScriptTaskPane = doc.getWebExtensionTaskPanes().get(0);
+ Assert.assertEquals(TaskPaneDockState.RIGHT, myScriptTaskPane.getDockState());
+ Assert.assertTrue(myScriptTaskPane.isVisible());
+ Assert.assertEquals(300.0d, myScriptTaskPane.getWidth());
+ Assert.assertTrue(myScriptTaskPane.isLocked());
+ Assert.assertEquals(1, myScriptTaskPane.getRow());
+
+ webExtension = myScriptTaskPane.getWebExtension();
+ Assert.assertEquals("", webExtension.getId());
+
+ Assert.assertEquals("WA104380646", webExtension.getReference().getId());
+ Assert.assertEquals("1.0.0.0", webExtension.getReference().getVersion());
+ Assert.assertEquals(WebExtensionStoreType.OMEX, webExtension.getReference().getStoreType());
+ Assert.assertEquals("English (United States)", webExtension.getReference().getStore());
+ Assert.assertEquals(0, webExtension.getAlternateReferences().getCount());
+
+ Assert.assertEquals("MyScript", webExtension.getProperties().get(0).getName());
+ Assert.assertEquals("MyScript Math Sample", webExtension.getProperties().get(0).getValue());
+
+ Assert.assertEquals("MyScript", webExtension.getBindings().get(0).getId());
+ Assert.assertEquals(WebExtensionBindingType.TEXT, webExtension.getBindings().get(0).getBindingType());
+ Assert.assertEquals("104380646", webExtension.getBindings().get(0).getAppRef());
+
+ Assert.assertFalse(webExtension.isFrozen());
+ //ExEnd
+ }
+
+ @Test
+ public void getWebExtensionInfo() throws Exception {
+ //ExStart
+ //ExFor:BaseWebExtensionCollection`1
+ //ExFor:BaseWebExtensionCollection`1.GetEnumerator
+ //ExFor:BaseWebExtensionCollection`1.Remove(Int32)
+ //ExFor:BaseWebExtensionCollection`1.Count
+ //ExFor:BaseWebExtensionCollection`1.Item(Int32)
+ //ExSummary:Shows how to work with a document's collection of web extensions.
+ Document doc = new Document(getMyDir() + "Web extension.docx");
+
+ Assert.assertEquals(1, doc.getWebExtensionTaskPanes().getCount());
+
+ // Print all properties of the document's web extension.
+ WebExtensionPropertyCollection webExtensionPropertyCollection = doc.getWebExtensionTaskPanes().get(0).getWebExtension().getProperties();
+ Iterator enumerator = webExtensionPropertyCollection.iterator();
+
+ while (enumerator.hasNext()) {
+ WebExtensionProperty webExtensionProperty = enumerator.next();
+ System.out.println("Binding name: {webExtensionProperty.Name}; Binding value: {webExtensionProperty.Value}");
+ }
+
+ // Remove the web extension.
+ doc.getWebExtensionTaskPanes().remove(0);
+
+ Assert.assertEquals(0, doc.getWebExtensionTaskPanes().getCount());
+ //ExEnd
+ }
+
+ @Test
+ public void epubCover() throws Exception {
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ builder.writeln("Hello world!");
+
+ // When saving to .epub, some Microsoft Word document properties convert to .epub metadata.
+ doc.getBuiltInDocumentProperties().setAuthor("John Doe");
+ doc.getBuiltInDocumentProperties().setTitle("My Book Title");
+
+ // The thumbnail we specify here can become the cover image.
+ byte[] image = DocumentHelper.getBytesFromStream(new FileInputStream(getImageDir() + "Transparent background logo.png"));
+ doc.getBuiltInDocumentProperties().setThumbnail(image);
+
+ doc.save(getArtifactsDir() + "Document.EpubCover.epub");
+ }
+
+ @Test
+ public void textWatermark() throws Exception {
+ //ExStart
+ //ExFor:Document.Watermark
+ //ExFor:Watermark
+ //ExFor:Watermark.SetText(String)
+ //ExFor:Watermark.SetText(String, TextWatermarkOptions)
+ //ExFor:Watermark.Remove
+ //ExFor:TextWatermarkOptions
+ //ExFor:TextWatermarkOptions.FontFamily
+ //ExFor:TextWatermarkOptions.FontSize
+ //ExFor:TextWatermarkOptions.Color
+ //ExFor:TextWatermarkOptions.Layout
+ //ExFor:TextWatermarkOptions.IsSemitrasparent
+ //ExFor:WatermarkLayout
+ //ExFor:WatermarkType
+ //ExFor:Watermark.Type
+ //ExSummary:Shows how to create a text watermark.
+ Document doc = new Document();
+
+ // Add a plain text watermark.
+ doc.getWatermark().setText("Aspose Watermark");
+
+ // If we wish to edit the text formatting using it as a watermark,
+ // we can do so by passing a TextWatermarkOptions object when creating the watermark.
+ TextWatermarkOptions textWatermarkOptions = new TextWatermarkOptions();
+ textWatermarkOptions.setFontFamily("Arial");
+ textWatermarkOptions.setFontSize(36f);
+ textWatermarkOptions.setColor(Color.BLACK);
+ textWatermarkOptions.setLayout(WatermarkLayout.DIAGONAL);
+ textWatermarkOptions.isSemitrasparent(false);
+
+ doc.getWatermark().setText("Aspose Watermark", textWatermarkOptions);
+
+ doc.save(getArtifactsDir() + "Document.TextWatermark.docx");
+
+ // We can remove a watermark from a document like this.
+ if (doc.getWatermark().getType() == WatermarkType.TEXT)
+ doc.getWatermark().remove();
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Document.TextWatermark.docx");
+
+ Assert.assertEquals(WatermarkType.TEXT, doc.getWatermark().getType());
+ }
+
+ @Test
+ public void imageWatermark() throws Exception {
+ //ExStart
+ //ExFor:Watermark.SetImage(Image)
+ //ExFor:Watermark.SetImage(Image, ImageWatermarkOptions)
+ //ExFor:Watermark.SetImage(String, ImageWatermarkOptions)
+ //ExFor:ImageWatermarkOptions
+ //ExFor:ImageWatermarkOptions.Scale
+ //ExFor:ImageWatermarkOptions.IsWashout
+ //ExSummary:Shows how to create a watermark from an image in the local file system.
+ Document doc = new Document();
+
+ // Modify the image watermark's appearance with an ImageWatermarkOptions object,
+ // then pass it while creating a watermark from an image file.
+ ImageWatermarkOptions imageWatermarkOptions = new ImageWatermarkOptions();
+ imageWatermarkOptions.setScale(5.0);
+ imageWatermarkOptions.isWashout(false);
+
+ // We have a different options to insert image:
+ doc.getWatermark().setImage(ImageIO.read(new File(getImageDir() + "Logo.jpg")), imageWatermarkOptions);
+
+ doc.getWatermark().setImage(ImageIO.read(new File(getImageDir() + "Logo.jpg")));
+
+ doc.getWatermark().setImage(getImageDir() + "Logo.jpg", imageWatermarkOptions);
+
+ doc.save(getArtifactsDir() + "Document.ImageWatermark.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Document.ImageWatermark.docx");
+
+ Assert.assertEquals(WatermarkType.IMAGE, doc.getWatermark().getType());
+ }
+
+ @Test
+ public void imageWatermarkStream() throws Exception
+ {
+ //ExStart:ImageWatermarkStream
+ //GistId:cc5f9f2033531562b29954d9f73776a5
+ //ExFor:Watermark.SetImage(Stream, ImageWatermarkOptions)
+ //ExSummary:Shows how to create a watermark from an image stream.
+ Document doc = new Document();
+
+ // Modify the image watermark's appearance with an ImageWatermarkOptions object,
+ // then pass it while creating a watermark from an image file.
+ ImageWatermarkOptions imageWatermarkOptions = new ImageWatermarkOptions();
+ imageWatermarkOptions.setScale(5.0);
+
+ try (FileInputStream imageStream = new FileInputStream(getImageDir() + "Logo.jpg")) {
+ doc.getWatermark().setImage(imageStream, imageWatermarkOptions);
+ }
+
+ doc.save(getArtifactsDir() + "Document.ImageWatermarkStream.docx");
+ //ExEnd:ImageWatermarkStream
+
+ doc = new Document(getArtifactsDir() + "Document.ImageWatermarkStream.docx");
+ Assert.assertEquals(WatermarkType.IMAGE, doc.getWatermark().getType());
+ }
+
+ @Test(dataProvider = "spellingAndGrammarErrorsDataProvider")
+ public void spellingAndGrammarErrors(boolean showErrors) throws Exception
+ {
+ //ExStart
+ //ExFor:Document.ShowGrammaticalErrors
+ //ExFor:Document.ShowSpellingErrors
+ //ExSummary:Shows how to show/hide errors in the document.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert two sentences with mistakes that would be picked up
+ // by the spelling and grammar checkers in Microsoft Word.
+ builder.writeln("There is a speling error in this sentence.");
+ builder.writeln("Their is a grammatical error in this sentence.");
+
+ // If these options are enabled, then spelling errors will be underlined
+ // in the output document by a jagged red line, and a double blue line will highlight grammatical mistakes.
+ doc.setShowGrammaticalErrors(showErrors);
+ doc.setShowSpellingErrors(showErrors);
+
+ doc.save(getArtifactsDir() + "Document.SpellingAndGrammarErrors.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Document.SpellingAndGrammarErrors.docx");
+
+ Assert.assertEquals(showErrors, doc.getShowGrammaticalErrors());
+ Assert.assertEquals(showErrors, doc.getShowSpellingErrors());
+ }
+
+ //JAVA-added data provider for test method
+ @DataProvider(name = "spellingAndGrammarErrorsDataProvider")
+ public static Object[][] spellingAndGrammarErrorsDataProvider() throws Exception {
+ return new Object[][]
+ {
+ {false},
+ {true},
+ };
+ }
+
+ @DataProvider(name = "granularityCompareOptionDataProvider")
+ public static Object[][] granularityCompareOptionDataProvider() throws Exception {
+ return new Object[][]
+ {
+ {Granularity.CHAR_LEVEL},
+ {Granularity.WORD_LEVEL},
+ };
+ }
+
+ @Test
+ public void ignorePrinterMetrics() throws Exception {
+ //ExStart
+ //ExFor:LayoutOptions.IgnorePrinterMetrics
+ //ExSummary:Shows how to ignore 'Use printer metrics to lay out document' option.
+ Document doc = new Document(getMyDir() + "Rendering.docx");
+
+ doc.getLayoutOptions().setIgnorePrinterMetrics(false);
+
+ doc.save(getArtifactsDir() + "Document.IgnorePrinterMetrics.docx");
+ //ExEnd
+ }
+
+ @Test
+ public void extractPages() throws Exception {
+ //ExStart
+ //ExFor:Document.ExtractPages(int, int)
+ //ExSummary:Shows how to get specified range of pages from the document.
+ Document doc = new Document(getMyDir() + "Layout entities.docx");
+
+ doc = doc.extractPages(0, 2);
+
+ doc.save(getArtifactsDir() + "Document.ExtractPages.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "Document.ExtractPages.docx");
+ Assert.assertEquals(doc.getPageCount(), 2);
+ }
+
+ @Test(dataProvider = "spellingOrGrammarDataProvider")
+ public void spellingOrGrammar(boolean checkSpellingGrammar) throws Exception {
+ //ExStart
+ //ExFor:Document.SpellingChecked
+ //ExFor:Document.GrammarChecked
+ //ExSummary:Shows how to set spelling or grammar verifying.
+ Document doc = new Document();
+
+ // The string with spelling errors.
+ doc.getFirstSection().getBody().getFirstParagraph().getRuns().add(new Run(doc, "The speeling in this documentz is all broked."));
+
+ // Spelling/Grammar check start if we set properties to false.
+ // We can see all errors in Microsoft Word via Review -> Spelling & Grammar.
+ // Note that Microsoft Word does not start grammar/spell check automatically for DOC and RTF document format.
+ doc.setSpellingChecked(checkSpellingGrammar);
+ doc.setGrammarChecked(checkSpellingGrammar);
+
+ doc.save(getArtifactsDir() + "Document.SpellingOrGrammar.docx");
+ //ExEnd
+ }
+
+ @DataProvider(name = "spellingOrGrammarDataProvider")
+ public static Object[][] spellingOrGrammarDataProvider() {
+ return new Object[][]
+ {
+ {true},
+ {false},
+ };
+ }
+
+ @Test
+ public void allowEmbeddingPostScriptFonts() throws Exception {
+ //ExStart
+ //ExFor:SaveOptions.AllowEmbeddingPostScriptFonts
+ //ExSummary:Shows how to save the document with PostScript font.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ builder.getFont().setName("PostScriptFont");
+ builder.writeln("Some text with PostScript font.");
+
+ // Load the font with PostScript to use in the document.
+ MemoryFontSource otf = new MemoryFontSource(DocumentHelper.getBytesFromStream(new FileInputStream(getFontsDir() + "AllegroOpen.otf")));
+ doc.setFontSettings(new FontSettings());
+ doc.getFontSettings().setFontsSources(new FontSourceBase[]{otf});
+
+ // Embed TrueType fonts.
+ doc.getFontInfos().setEmbedTrueTypeFonts(true);
+
+ // Allow embedding PostScript fonts while embedding TrueType fonts.
+ // Microsoft Word does not embed PostScript fonts, but can open documents with embedded fonts of this type.
+ SaveOptions saveOptions = SaveOptions.createSaveOptions(SaveFormat.DOCX);
+ saveOptions.setAllowEmbeddingPostScriptFonts(true);
+
+ doc.save(getArtifactsDir() + "Document.AllowEmbeddingPostScriptFonts.docx", saveOptions);
+ //ExEnd
+ }
+
+ @Test
+ public void frameset() throws Exception
+ {
+ //ExStart
+ //ExFor:Document.Frameset
+ //ExFor:Frameset
+ //ExFor:Frameset.FrameDefaultUrl
+ //ExFor:Frameset.IsFrameLinkToFile
+ //ExFor:Frameset.ChildFramesets
+ //ExFor:FramesetCollection
+ //ExFor:FramesetCollection.Count
+ //ExFor:FramesetCollection.Item(Int32)
+ //ExSummary:Shows how to access frames on-page.
+ // Document contains several frames with links to other documents.
+ Document doc = new Document(getMyDir() + "Frameset.docx");
+
+ Assert.assertEquals(3, doc.getFrameset().getChildFramesets().getCount());
+ // We can check the default URL (a web page URL or local document) or if the frame is an external resource.
+ Assert.assertEquals("https://file-examples-com.github.io/uploads/2017/02/file-sample_100kB.docx",
+ doc.getFrameset().getChildFramesets().get(0).getChildFramesets().get(0).getFrameDefaultUrl());
+ Assert.assertTrue(doc.getFrameset().getChildFramesets().get(0).getChildFramesets().get(0).isFrameLinkToFile());
+
+ Assert.assertEquals("Document.docx", doc.getFrameset().getChildFramesets().get(1).getFrameDefaultUrl());
+ Assert.assertFalse(doc.getFrameset().getChildFramesets().get(1).isFrameLinkToFile());
+
+ // Change properties for one of our frames.
+ doc.getFrameset().getChildFramesets().get(0).getChildFramesets().get(0).setFrameDefaultUrl("https://github.com/aspose-words/Aspose.Words-for-.NET/blob/master/Examples/Data/Absolute%20position%20tab.docx");
+ doc.getFrameset().getChildFramesets().get(0).getChildFramesets().get(0).isFrameLinkToFile(false);
+ //ExEnd
+
+ doc = DocumentHelper.saveOpen(doc);
+
+ Assert.assertEquals(
+ "https://github.com/aspose-words/Aspose.Words-for-.NET/blob/master/Examples/Data/Absolute%20position%20tab.docx",
+ doc.getFrameset().getChildFramesets().get(0).getChildFramesets().get(0).getFrameDefaultUrl());
+ Assert.assertFalse(doc.getFrameset().getChildFramesets().get(0).getChildFramesets().get(0).isFrameLinkToFile());
+ }
+
+ @Test
+ public void openAzw() throws Exception
+ {
+ FileFormatInfo info = FileFormatUtil.detectFileFormat(getMyDir() + "Azw3 document.azw3");
+ Assert.assertEquals(info.getLoadFormat(), LoadFormat.AZW_3);
+
+ Document doc = new Document(getMyDir() + "Azw3 document.azw3");
+ Assert.assertTrue(doc.getText().contains("Hachette Book Group USA"));
+ }
+
+ @Test(enabled = false, description = "https://issue.auckland.dynabic.com/issues/WORDSJAVA-2892")
+ public void openEpub() throws Exception
+ {
+ FileFormatInfo info = FileFormatUtil.detectFileFormat(getMyDir() + "Epub document.epub");
+ Assert.assertEquals(info.getLoadFormat(), LoadFormat.EPUB);
+
+ Document doc = new Document(getMyDir() + "Epub document.epub");
+ Assert.assertTrue(doc.getText().contains("Down the Rabbit-Hole"));
+ }
+
+ @Test
+ public void openXml() throws Exception
+ {
+ FileFormatInfo info = FileFormatUtil.detectFileFormat(getMyDir() + "Mail merge data - Customers.xml");
+ Assert.assertEquals(info.getLoadFormat(), LoadFormat.XML);
+
+ Document doc = new Document(getMyDir() + "Mail merge data - Purchase order.xml");
+ Assert.assertTrue(doc.getText().contains("Ellen Adams\r123 Maple Street"));
+ }
+
+ @Test
+ public void moveToStructuredDocumentTag() throws Exception
+ {
+ //ExStart
+ //ExFor:DocumentBuilder.MoveToStructuredDocumentTag(int, int)
+ //ExFor:DocumentBuilder.MoveToStructuredDocumentTag(StructuredDocumentTag, int)
+ //ExFor:DocumentBuilder.IsAtEndOfStructuredDocumentTag
+ //ExFor:DocumentBuilder.CurrentStructuredDocumentTag
+ //ExSummary:Shows how to move cursor of DocumentBuilder inside a structured document tag.
+ Document doc = new Document(getMyDir() + "Structured document tags.docx");
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // There is a several ways to move the cursor:
+ // 1 - Move to the first character of structured document tag by index.
+ builder.moveToStructuredDocumentTag(1, 1);
+
+ // 2 - Move to the first character of structured document tag by object.
+ StructuredDocumentTag tag = (StructuredDocumentTag)doc.getChild(NodeType.STRUCTURED_DOCUMENT_TAG, 2, true);
+ builder.moveToStructuredDocumentTag(tag, 1);
+ builder.write(" New text.");
+
+ Assert.assertEquals("R New text.ichText", tag.getText().trim());
+
+ // 3 - Move to the end of the second structured document tag.
+ builder.moveToStructuredDocumentTag(1, -1);
+ Assert.assertTrue(builder.isAtEndOfStructuredDocumentTag());
+
+ // Get currently selected structured document tag.
+ builder.getCurrentStructuredDocumentTag().setColor(Color.GREEN);
+
+ doc.save(getArtifactsDir() + "Document.MoveToStructuredDocumentTag.docx");
+ //ExEnd
+ }
+
+ @Test
+ public void includeTextboxesFootnotesEndnotesInStat() throws Exception
+ {
+ //ExStart
+ //ExFor:Document.IncludeTextboxesFootnotesEndnotesInStat
+ //ExSummary: Shows how to include or exclude textboxes, footnotes and endnotes from word count statistics.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ builder.writeln("Lorem ipsum");
+ builder.insertFootnote(FootnoteType.FOOTNOTE, "sit amet");
+
+ // By default option is set to 'false'.
+ doc.updateWordCount();
+ // Words count without textboxes, footnotes and endnotes.
+ Assert.assertEquals(2, doc.getBuiltInDocumentProperties().getWords());
+
+ doc.setIncludeTextboxesFootnotesEndnotesInStat(true);
+ doc.updateWordCount();
+ // Words count with textboxes, footnotes and endnotes.
+ Assert.assertEquals(4, doc.getBuiltInDocumentProperties().getWords());
+ //ExEnd
+ }
+
+ @Test
+ public void setJustificationMode() throws Exception
+ {
+ //ExStart
+ //ExFor:Document.JustificationMode
+ //ExFor:JustificationMode
+ //ExSummary:Shows how to manage character spacing control.
+ Document doc = new Document(getMyDir() + "Document.docx");
+
+ int justificationMode = doc.getJustificationMode();
+ if (justificationMode == JustificationMode.EXPAND)
+ doc.setJustificationMode(JustificationMode.COMPRESS);
+
+ doc.save(getArtifactsDir() + "Document.SetJustificationMode.docx");
+ //ExEnd
+ }
+
+ @Test
+ public void pageIsInColor() throws Exception
+ {
+ //ExStart
+ //ExFor:PageInfo.Colored
+ //ExFor:Document.GetPageInfo(Int32)
+ //ExSummary:Shows how to check whether the page is in color or not.
+ Document doc = new Document(getMyDir() + "Document.docx");
+
+ // Check that the first page of the document is not colored.
+ Assert.assertFalse(doc.getPageInfo(0).getColored());
+ //ExEnd
+ }
+
+ @Test
+ public void insertDocumentInline() throws Exception
+ {
+ //ExStart:InsertDocumentInline
+ //GistId:3428e84add5beb0d46a8face6e5fc858
+ //ExFor:DocumentBuilder.InsertDocumentInline(Document, ImportFormatMode, ImportFormatOptions)
+ //ExSummary:Shows how to insert a document inline at the cursor position.
+ DocumentBuilder srcDoc = new DocumentBuilder();
+ srcDoc.write("[src content]");
+
+ // Create destination document.
+ DocumentBuilder dstDoc = new DocumentBuilder();
+ dstDoc.write("Before ");
+ dstDoc.insertNode(new BookmarkStart(dstDoc.getDocument(), "src_place"));
+ dstDoc.insertNode(new BookmarkEnd(dstDoc.getDocument(), "src_place"));
+ dstDoc.write(" after");
+
+ Assert.assertEquals("Before after", dstDoc.getDocument().getText().trim());
+
+ // Insert source document into destination inline.
+ dstDoc.moveToBookmark("src_place");
+ dstDoc.insertDocumentInline(srcDoc.getDocument(), ImportFormatMode.USE_DESTINATION_STYLES, new ImportFormatOptions());
+
+ Assert.assertEquals("Before [src content] after", dstDoc.getDocument().getText().trim());
+ //ExEnd:InsertDocumentInline
+ }
+
+ @Test (dataProvider = "saveDocumentToStreamDataProvider")
+ public void saveDocumentToStream(int saveFormat) throws Exception
+ {
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ builder.writeln("Lorem ipsum");
+
+ try (ByteArrayOutputStream stream = new ByteArrayOutputStream())
+ {
+ if (saveFormat == SaveFormat.HTML_FIXED)
+ {
+ HtmlFixedSaveOptions saveOptions = new HtmlFixedSaveOptions();
+ saveOptions.setExportEmbeddedCss(true);
+ saveOptions.setExportEmbeddedFonts(true);
+ saveOptions.setSaveFormat(saveFormat);
+
+ doc.save(stream, saveOptions);
+ }
+ else if (saveFormat == SaveFormat.XAML_FIXED)
+ {
+ XamlFixedSaveOptions saveOptions = new XamlFixedSaveOptions();
+ saveOptions.setResourcesFolder(getArtifactsDir());
+ saveOptions.setSaveFormat(saveFormat);
+
+ doc.save(stream, saveOptions);
+ }
+ else
+ doc.save(stream, saveFormat);
+ }
+ }
+
+ @DataProvider(name = "saveDocumentToStreamDataProvider")
+ public static Object[][] saveDocumentToStreamDataProvider() {
+ return new Object[][]
+ {
+ {SaveFormat.DOC},
+ {SaveFormat.DOT},
+ {SaveFormat.DOCX},
+ {SaveFormat.DOCM},
+ {SaveFormat.DOTX},
+ {SaveFormat.DOTM},
+ {SaveFormat.FLAT_OPC},
+ {SaveFormat.FLAT_OPC_MACRO_ENABLED},
+ {SaveFormat.FLAT_OPC_TEMPLATE},
+ {SaveFormat.FLAT_OPC_TEMPLATE_MACRO_ENABLED},
+ {SaveFormat.RTF},
+ {SaveFormat.WORD_ML},
+ {SaveFormat.PDF},
+ {SaveFormat.XPS},
+ {SaveFormat.XAML_FIXED},
+ {SaveFormat.SVG},
+ {SaveFormat.HTML_FIXED},
+ {SaveFormat.OPEN_XPS},
+ {SaveFormat.PS},
+ {SaveFormat.PCL},
+ {SaveFormat.HTML},
+ {SaveFormat.MHTML},
+ {SaveFormat.EPUB},
+ {SaveFormat.AZW_3},
+ {SaveFormat.MOBI},
+ {SaveFormat.ODT},
+ {SaveFormat.OTT},
+ {SaveFormat.TEXT},
+ {SaveFormat.XAML_FLOW},
+ {SaveFormat.XAML_FLOW_PACK},
+ {SaveFormat.MARKDOWN},
+ {SaveFormat.XLSX},
+ {SaveFormat.TIFF},
+ {SaveFormat.PNG},
+ {SaveFormat.BMP},
+ {SaveFormat.EMF},
+ {SaveFormat.JPEG},
+ {SaveFormat.GIF},
+ {SaveFormat.EPS},
+ };
+ }
+
+ @Test
+ public void hasMacros() throws Exception
+ {
+ //ExStart:HasMacros
+ //GistId:f99d87e10ab87a581c52206321d8b617
+ //ExFor:FileFormatInfo.HasMacros
+ //ExSummary:Shows how to check VBA macro presence without loading document.
+ FileFormatInfo fileFormatInfo = FileFormatUtil.detectFileFormat(getMyDir() + "Macro.docm");
+ Assert.assertTrue(fileFormatInfo.hasMacros());
+ //ExEnd:HasMacros
+ }
+
+ @Test
+ public void punctuationKerning() throws Exception
+ {
+ //ExStart
+ //ExFor:Document.PunctuationKerning
+ //ExSummary:Shows how to work with kerning applies to both Latin text and punctuation.
+ Document doc = new Document(getMyDir() + "Document.docx");
+ Assert.assertTrue(doc.getPunctuationKerning());
+ //ExEnd
+ }
+
+ @Test
+ public void removeBlankPages() throws Exception
+ {
+ //ExStart
+ //ExFor:Document.RemoveBlankPages
+ //ExSummary:Shows how to remove blank pages from the document.
+ Document doc = new Document(getMyDir() + "Blank pages.docx");
+ Assert.assertEquals(2, doc.getPageCount());
+ doc.removeBlankPages();
+ doc.updatePageLayout();
+ Assert.assertEquals(1, doc.getPageCount());
+ //ExEnd
+ }
+
+ @Test
+ public void extractPagesWithOptions() throws Exception
+ {
+ //ExStart:ExtractPagesWithOptions
+ //GistId:571cc6e23284a2ec075d15d4c32e3bbf
+ //ExFor:Document.ExtractPages(int, int)
+ //ExFor:PageExtractOptions
+ //ExFor:PageExtractOptions.UpdatePageStartingNumber
+ //ExFor:PageExtractOptions.UnlinkPagesNumberFields
+ //ExSummary:Show how to reset the initial page numbering and save the NUMPAGE field.
+ Document doc = new Document(getMyDir() + "Page fields.docx");
+
+ // Default behavior:
+ // The extracted page numbering is the same as in the original document, as if we had selected "Print 2 pages" in MS Word.
+ // The start page will be set to 2 and the field indicating the number of pages will be removed
+ // and replaced with a constant value equal to the number of pages.
+ Document extractedDoc1 = doc.extractPages(1, 1);
+ extractedDoc1.save(getArtifactsDir() + "Document.ExtractPagesWithOptions.Default.docx");
+
+ Assert.assertEquals(1, extractedDoc1.getRange().getFields().getCount()); //ExSkip
+
+ // Altered behavior:
+ // The extracted page numbering is reset and a new one begins,
+ // as if we had copied the contents of the second page and pasted it into a new document.
+ // The start page will be set to 1 and the field indicating the number of pages will be left unchanged
+ // and will show the current number of pages.
+ PageExtractOptions extractOptions = new PageExtractOptions();
+ extractOptions.setUpdatePageStartingNumber(false);
+ extractOptions.setUnlinkPagesNumberFields(false);
+ Document extractedDoc2 = doc.extractPages(1, 1, extractOptions);
+ extractedDoc2.save(getArtifactsDir() + "Document.ExtractPagesWithOptions.Options.docx");
+ //ExEnd:ExtractPagesWithOptions
+
+ Assert.assertEquals(2, extractedDoc2.getRange().getFields().getCount());
+ }
+}
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ExDocumentBase.java b/Examples/ApiExamples/Java/src/main/java/Examples/ExDocumentBase.java
new file mode 100644
index 00000000..8f087b36
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ExDocumentBase.java
@@ -0,0 +1,262 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.pdf.ColorType;
+import com.aspose.pdf.XImage;
+import com.aspose.words.Shape;
+import com.aspose.words.*;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.awt.*;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+@Test
+public class ExDocumentBase extends ApiExampleBase {
+ @Test
+ public void constructor() throws Exception {
+ //ExStart
+ //ExFor:DocumentBase
+ //ExSummary:Shows how to initialize the subclasses of DocumentBase.
+ Document doc = new Document();
+
+ Assert.assertEquals(DocumentBase.class, doc.getClass().getSuperclass());
+
+ GlossaryDocument glossaryDoc = new GlossaryDocument();
+ doc.setGlossaryDocument(glossaryDoc);
+
+ Assert.assertEquals(DocumentBase.class, glossaryDoc.getClass().getSuperclass());
+ //ExEnd
+ }
+
+ @Test
+ public void setPageColor() throws Exception {
+ //ExStart
+ //ExFor:DocumentBase.PageColor
+ //ExSummary:Shows how to set the background color for all pages of a document.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ builder.writeln("Hello world!");
+
+ doc.setPageColor(Color.lightGray);
+
+ doc.save(getArtifactsDir() + "DocumentBase.SetPageColor.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBase.SetPageColor.docx");
+ Assert.assertEquals(Color.lightGray.getRGB(), doc.getPageColor().getRGB());
+ }
+
+ @Test
+ public void importNode() throws Exception {
+ //ExStart
+ //ExFor:DocumentBase.ImportNode(Node, Boolean)
+ //ExSummary:Shows how to import a node from one document to another.
+ Document srcDoc = new Document();
+ Document dstDoc = new Document();
+
+ srcDoc.getFirstSection().getBody().getFirstParagraph().appendChild(
+ new Run(srcDoc, "Source document first paragraph text."));
+ dstDoc.getFirstSection().getBody().getFirstParagraph().appendChild(
+ new Run(dstDoc, "Destination document first paragraph text."));
+
+ // Every node has a parent document, which is the document that contains the node.
+ // Inserting a node into a document that the node does not belong to will throw an exception.
+ Assert.assertNotEquals(dstDoc, srcDoc.getFirstSection().getDocument());
+ Assert.assertThrows(IllegalArgumentException.class, () -> dstDoc.appendChild(srcDoc.getFirstSection()));
+
+ // Use the ImportNode method to create a copy of a node, which will have the document
+ // that called the ImportNode method set as its new owner document.
+ Section importedSection = (Section) dstDoc.importNode(srcDoc.getFirstSection(), true);
+
+ Assert.assertEquals(dstDoc, importedSection.getDocument());
+
+ // We can now insert the node into the document.
+ dstDoc.appendChild(importedSection);
+
+ Assert.assertEquals("Destination document first paragraph text.\r\nSource document first paragraph text.\r\n",
+ dstDoc.toString(SaveFormat.TEXT));
+ //ExEnd
+
+ Assert.assertNotEquals(importedSection, srcDoc.getFirstSection());
+ Assert.assertNotEquals(importedSection.getDocument(), srcDoc.getFirstSection().getDocument());
+ Assert.assertEquals(importedSection.getBody().getFirstParagraph().getText(),
+ srcDoc.getFirstSection().getBody().getFirstParagraph().getText());
+ }
+
+ @Test
+ public void importNodeCustom() throws Exception {
+ //ExStart
+ //ExFor:DocumentBase.ImportNode(Node, Boolean, ImportFormatMode)
+ //ExSummary:Shows how to import node from source document to destination document with specific options.
+ // Create two documents and add a character style to each document.
+ // Configure the styles to have the same name, but different text formatting.
+ Document srcDoc = new Document();
+ Style srcStyle = srcDoc.getStyles().add(StyleType.CHARACTER, "My style");
+ srcStyle.getFont().setName("Courier New");
+ DocumentBuilder srcBuilder = new DocumentBuilder(srcDoc);
+ srcBuilder.getFont().setStyle(srcStyle);
+ srcBuilder.writeln("Source document text.");
+
+ Document dstDoc = new Document();
+ Style dstStyle = dstDoc.getStyles().add(StyleType.CHARACTER, "My style");
+ dstStyle.getFont().setName("Calibri");
+ DocumentBuilder dstBuilder = new DocumentBuilder(dstDoc);
+ dstBuilder.getFont().setStyle(dstStyle);
+ dstBuilder.writeln("Destination document text.");
+
+ // Import the Section from the destination document into the source document, causing a style name collision.
+ // If we use destination styles, then the imported source text with the same style name
+ // as destination text will adopt the destination style.
+ Section importedSection = (Section) dstDoc.importNode(srcDoc.getFirstSection(), true, ImportFormatMode.USE_DESTINATION_STYLES);
+ Assert.assertEquals("Source document text.", importedSection.getBody().getParagraphs().get(0).getRuns().get(0).getText().trim()); //ExSkip
+ Assert.assertNull(dstDoc.getStyles().get("My style_0")); //ExSkip
+ Assert.assertEquals(dstStyle.getFont().getName(), importedSection.getBody().getFirstParagraph().getRuns().get(0).getFont().getName());
+ Assert.assertEquals(dstStyle.getName(), importedSection.getBody().getFirstParagraph().getRuns().get(0).getFont().getStyleName());
+
+ // If we use ImportFormatMode.KeepDifferentStyles, the source style is preserved,
+ // and the naming clash resolves by adding a suffix.
+ dstDoc.importNode(srcDoc.getFirstSection(), true, ImportFormatMode.KEEP_DIFFERENT_STYLES);
+ Assert.assertEquals(dstStyle.getFont().getName(), dstDoc.getStyles().get("My style").getFont().getName());
+ Assert.assertEquals(srcStyle.getFont().getName(), dstDoc.getStyles().get("My style_0").getFont().getName());
+ //ExEnd
+ }
+
+ @Test
+ public void backgroundShape() throws Exception {
+ //ExStart
+ //ExFor:DocumentBase.BackgroundShape
+ //ExSummary:Shows how to set a background shape for every page of a document.
+ Document doc = new Document();
+
+ Assert.assertNull(doc.getBackgroundShape());
+
+ // The only shape type that we can use as a background is a rectangle.
+ Shape shapeRectangle = new Shape(doc, ShapeType.RECTANGLE);
+
+ // There are two ways of using this shape as a page background.
+ // 1 - A flat color:
+ shapeRectangle.setFillColor(Color.BLUE);
+ doc.setBackgroundShape(shapeRectangle);
+
+ doc.save(getArtifactsDir() + "DocumentBase.BackgroundShape.FlatColor.docx");
+
+ // 2 - An image:
+ shapeRectangle = new Shape(doc, ShapeType.RECTANGLE);
+ shapeRectangle.getImageData().setImage(getImageDir() + "Transparent background logo.png");
+
+ // Adjust the image's appearance to make it more suitable as a watermark.
+ shapeRectangle.getImageData().setContrast(0.2);
+ shapeRectangle.getImageData().setBrightness(0.7);
+
+ doc.setBackgroundShape(shapeRectangle);
+
+ Assert.assertTrue(doc.getBackgroundShape().hasImage());
+
+ PdfSaveOptions saveOptions = new PdfSaveOptions();
+ saveOptions.setCacheBackgroundGraphics(false);
+
+ // Microsoft Word does not support shapes with images as backgrounds,
+ // but we can still see these backgrounds in other save formats such as .pdf.
+ doc.save(getArtifactsDir() + "DocumentBase.BackgroundShape.Image.pdf", saveOptions);
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBase.BackgroundShape.FlatColor.docx");
+
+ Assert.assertEquals(Color.BLUE.getRGB(), doc.getBackgroundShape().getFillColor().getRGB());
+
+ com.aspose.pdf.Document pdfDocument = new com.aspose.pdf.Document(getArtifactsDir() + "DocumentBase.BackgroundShape.Image.pdf");
+ XImage pdfDocImage = pdfDocument.getPages().get_Item(1).getResources().getImages().get_Item(1);
+
+ Assert.assertEquals(400, pdfDocImage.getWidth());
+ Assert.assertEquals(400, pdfDocImage.getHeight());
+ Assert.assertEquals(ColorType.Rgb, pdfDocImage.getColorType());
+
+ pdfDocument.close();
+ }
+
+ //ExStart
+ //ExFor:DocumentBase.ResourceLoadingCallback
+ //ExFor:IResourceLoadingCallback
+ //ExFor:IResourceLoadingCallback.ResourceLoading(ResourceLoadingArgs)
+ //ExFor:ResourceLoadingAction
+ //ExFor:ResourceLoadingArgs
+ //ExFor:ResourceLoadingArgs.OriginalUri
+ //ExFor:ResourceLoadingArgs.ResourceType
+ //ExFor:ResourceLoadingArgs.SetData(Byte[])
+ //ExFor:ResourceType
+ //ExSummary:Shows how to customize the process of loading external resources into a document.
+ @Test //ExSkip
+ public void resourceLoadingCallback() throws Exception {
+ Document doc = new Document();
+ doc.setResourceLoadingCallback(new ImageNameHandler());
+
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Images usually are inserted using a URI, or a byte array.
+ // Every instance of a resource load will call our callback's ResourceLoading method.
+ builder.insertImage("Google logo");
+ builder.insertImage("Aspose logo");
+ builder.insertImage("Watermark");
+
+ Assert.assertEquals(3, doc.getChildNodes(NodeType.SHAPE, true).getCount());
+
+ doc.save(getArtifactsDir() + "DocumentBase.ResourceLoadingCallback.docx");
+ testResourceLoadingCallback(new Document(getArtifactsDir() + "DocumentBase.ResourceLoadingCallback.docx")); //ExSkip
+ }
+
+ ///
+ /// Allows us to load images into a document using predefined shorthands, as opposed to URIs.
+ /// This will separate image loading logic from the rest of the document construction.
+ ///
+ private static class ImageNameHandler implements IResourceLoadingCallback {
+ public int resourceLoading(final ResourceLoadingArgs args) throws URISyntaxException, IOException {
+ if (args.getResourceType() == ResourceType.IMAGE) {
+ // If this callback encounters one of the image shorthands while loading an image,
+ // it will apply unique logic for each defined shorthand instead of treating it as a URI.
+ if ("Google logo".equals(args.getOriginalUri())) {
+ args.setData(DocumentHelper.getBytesFromStream(new URI("http://www.google.com/images/logos/ps_logo2.png").toURL().openStream()));
+
+ return ResourceLoadingAction.USER_PROVIDED;
+ }
+
+ if ("Aspose logo".equals(args.getOriginalUri())) {
+ args.setData(DocumentHelper.getBytesFromStream(getAsposelogoUri().toURL().openStream()));
+
+ return ResourceLoadingAction.USER_PROVIDED;
+ }
+
+ if ("Watermark".equals(args.getOriginalUri())) {
+ InputStream imageStream = new FileInputStream(getImageDir() + "Transparent background logo.png");
+ args.setData(DocumentHelper.getBytesFromStream(imageStream));
+
+ return ResourceLoadingAction.USER_PROVIDED;
+ }
+ }
+
+ return ResourceLoadingAction.DEFAULT;
+ }
+ }
+ //ExEnd
+
+ private void testResourceLoadingCallback(Document doc) throws Exception {
+ for (Shape shape : (Iterable) doc.getChildNodes(NodeType.SHAPE, true)) {
+ Assert.assertTrue(shape.hasImage());
+ Assert.assertNotEquals(shape.getImageData().getImageBytes(), new byte[0]);
+ }
+
+ TestUtil.verifyWebResponseStatusCode(200, new URL("http://www.google.com/images/logos/ps_logo2.png"));
+ }
+}
diff --git a/Examples/ApiExamples/Java/src/main/java/Examples/ExDocumentBuilder.java b/Examples/ApiExamples/Java/src/main/java/Examples/ExDocumentBuilder.java
new file mode 100644
index 00000000..4f8b2676
--- /dev/null
+++ b/Examples/ApiExamples/Java/src/main/java/Examples/ExDocumentBuilder.java
@@ -0,0 +1,3574 @@
+package Examples;
+
+//////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
+//
+// This file is part of Aspose.Words. The source code in this file
+// is only intended as a supplement to the documentation, and is provided
+// "as is", without warranty of any kind, either expressed or implied.
+//////////////////////////////////////////////////////////////////////////
+
+import com.aspose.words.Font;
+import com.aspose.words.List;
+import com.aspose.words.Shape;
+import com.aspose.words.*;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.IOUtils;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.net.URL;
+import java.text.DecimalFormat;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.UUID;
+
+public class ExDocumentBuilder extends ApiExampleBase {
+ @Test
+ public void writeAndFont() throws Exception {
+ //ExStart
+ //ExFor:Font.Size
+ //ExFor:Font.Bold
+ //ExFor:Font.Name
+ //ExFor:Font.Color
+ //ExFor:Font.Underline
+ //ExFor:DocumentBuilder.#ctor
+ //ExSummary:Shows how to insert formatted text using DocumentBuilder.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Specify font formatting, then add text.
+ Font font = builder.getFont();
+ font.setSize(16.0);
+ font.setBold(true);
+ font.setColor(Color.BLUE);
+ font.setName("Courier New");
+ font.setUnderline(Underline.DASH);
+
+ builder.write("Hello world!");
+ //ExEnd
+
+ doc = DocumentHelper.saveOpen(builder.getDocument());
+ Run firstRun = doc.getFirstSection().getBody().getParagraphs().get(0).getRuns().get(0);
+
+ Assert.assertEquals("Hello world!", firstRun.getText().trim());
+ Assert.assertEquals(16.0, firstRun.getFont().getSize());
+ Assert.assertTrue(firstRun.getFont().getBold());
+ Assert.assertEquals("Courier New", firstRun.getFont().getName());
+ Assert.assertEquals(Color.BLUE.getRGB(), firstRun.getFont().getColor().getRGB());
+ Assert.assertEquals(Underline.DASH, firstRun.getFont().getUnderline());
+ }
+
+ @Test
+ public void headersAndFooters() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder
+ //ExFor:DocumentBuilder.#ctor(Document)
+ //ExFor:DocumentBuilder.MoveToHeaderFooter
+ //ExFor:DocumentBuilder.MoveToSection
+ //ExFor:DocumentBuilder.InsertBreak
+ //ExFor:DocumentBuilder.Writeln
+ //ExFor:HeaderFooterType
+ //ExFor:PageSetup.DifferentFirstPageHeaderFooter
+ //ExFor:PageSetup.OddAndEvenPagesHeaderFooter
+ //ExFor:BreakType
+ //ExSummary:Shows how to create headers and footers in a document using DocumentBuilder.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Specify that we want different headers and footers for first, even and odd pages.
+ builder.getPageSetup().setDifferentFirstPageHeaderFooter(true);
+ builder.getPageSetup().setOddAndEvenPagesHeaderFooter(true);
+
+ // Create the headers, then add three pages to the document to display each header type.
+ builder.moveToHeaderFooter(HeaderFooterType.HEADER_FIRST);
+ builder.write("Header for the first page");
+ builder.moveToHeaderFooter(HeaderFooterType.HEADER_EVEN);
+ builder.write("Header for even pages");
+ builder.moveToHeaderFooter(HeaderFooterType.HEADER_PRIMARY);
+ builder.write("Header for all other pages");
+
+ builder.moveToSection(0);
+ builder.writeln("Page1");
+ builder.insertBreak(BreakType.PAGE_BREAK);
+ builder.writeln("Page2");
+ builder.insertBreak(BreakType.PAGE_BREAK);
+ builder.writeln("Page3");
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.HeadersAndFooters.docx");
+ //ExEnd
+
+ HeaderFooterCollection headersFooters =
+ new Document(getArtifactsDir() + "DocumentBuilder.HeadersAndFooters.docx").getFirstSection().getHeadersFooters();
+
+ Assert.assertEquals(3, headersFooters.getCount());
+ Assert.assertEquals("Header for the first page", headersFooters.getByHeaderFooterType(HeaderFooterType.HEADER_FIRST).getText().trim());
+ Assert.assertEquals("Header for even pages", headersFooters.getByHeaderFooterType(HeaderFooterType.HEADER_EVEN).getText().trim());
+ Assert.assertEquals("Header for all other pages", headersFooters.getByHeaderFooterType(HeaderFooterType.HEADER_PRIMARY).getText().trim());
+
+ }
+
+ @Test
+ public void mergeFields() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertField(String)
+ //ExFor:DocumentBuilder.MoveToMergeField(String, Boolean, Boolean)
+ //ExSummary:Shows how to insert fields, and move the document builder's cursor to them.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ builder.insertField("MERGEFIELD MyMergeField1 \\* MERGEFORMAT");
+ builder.insertField("MERGEFIELD MyMergeField2 \\* MERGEFORMAT");
+
+ // Move the cursor to the first MERGEFIELD.
+ builder.moveToMergeField("MyMergeField1", true, false);
+
+ // Note that the cursor is placed immediately after the first MERGEFIELD, and before the second.
+ Assert.assertEquals(doc.getRange().getFields().get(1).getStart(), builder.getCurrentNode());
+ Assert.assertEquals(doc.getRange().getFields().get(0).getEnd(), builder.getCurrentNode().getPreviousSibling());
+
+ // If we wish to edit the field's field code or contents using the builder,
+ // its cursor would need to be inside a field.
+ // To place it inside a field, we would need to call the document builder's MoveTo method
+ // and pass the field's start or separator node as an argument.
+ builder.write(" Text between our merge fields. ");
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.MergeFields.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.MergeFields.docx");
+
+ Assert.assertEquals("MERGEFIELD MyMergeField1 \\* MERGEFORMAT\u0014«MyMergeField1»\u0015" +
+ " Text between our merge fields. " +
+ "\u0013MERGEFIELD MyMergeField2 \\* MERGEFORMAT\u0014«MyMergeField2»", doc.getText().trim());
+ Assert.assertEquals(2, doc.getRange().getFields().getCount());
+
+ TestUtil.verifyField(FieldType.FIELD_MERGE_FIELD, "MERGEFIELD MyMergeField1 \\* MERGEFORMAT", "«MyMergeField1»", doc.getRange().getFields().get(0));
+ TestUtil.verifyField(FieldType.FIELD_MERGE_FIELD, "MERGEFIELD MyMergeField2 \\* MERGEFORMAT", "«MyMergeField2»", doc.getRange().getFields().get(1));
+ }
+
+ @Test
+ public void insertHorizontalRule() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertHorizontalRule
+ //ExFor:ShapeBase.IsHorizontalRule
+ //ExFor:Shape.HorizontalRuleFormat
+ //ExFor:HorizontalRuleAlignment
+ //ExFor:HorizontalRuleFormat
+ //ExFor:HorizontalRuleFormat.Alignment
+ //ExFor:HorizontalRuleFormat.WidthPercent
+ //ExFor:HorizontalRuleFormat.Height
+ //ExFor:HorizontalRuleFormat.Color
+ //ExFor:HorizontalRuleFormat.NoShade
+ //ExSummary:Shows how to insert a horizontal rule shape, and customize its formatting.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ Shape shape = builder.insertHorizontalRule();
+
+ HorizontalRuleFormat horizontalRuleFormat = shape.getHorizontalRuleFormat();
+ horizontalRuleFormat.setAlignment(HorizontalRuleAlignment.CENTER);
+ horizontalRuleFormat.setWidthPercent(70.0);
+ horizontalRuleFormat.setHeight(3.0);
+ horizontalRuleFormat.setColor(Color.BLUE);
+ horizontalRuleFormat.setNoShade(true);
+
+ Assert.assertTrue(shape.isHorizontalRule());
+ Assert.assertTrue(shape.getHorizontalRuleFormat().getNoShade());
+ //ExEnd
+
+ doc = DocumentHelper.saveOpen(doc);
+ shape = (Shape) doc.getChild(NodeType.SHAPE, 0, true);
+
+ Assert.assertEquals(HorizontalRuleAlignment.CENTER, shape.getHorizontalRuleFormat().getAlignment());
+ Assert.assertEquals(70.0, shape.getHorizontalRuleFormat().getWidthPercent());
+ Assert.assertEquals(3.0, shape.getHorizontalRuleFormat().getHeight());
+ Assert.assertEquals(Color.BLUE.getRGB(), shape.getHorizontalRuleFormat().getColor().getRGB());
+ }
+
+ @Test(description = "Checking the boundary conditions of WidthPercent and Height properties")
+ public void horizontalRuleFormatExceptions() throws Exception {
+ DocumentBuilder builder = new DocumentBuilder();
+ Shape shape = builder.insertHorizontalRule();
+
+ HorizontalRuleFormat horizontalRuleFormat = shape.getHorizontalRuleFormat();
+ horizontalRuleFormat.setWidthPercent(1.0);
+ horizontalRuleFormat.setWidthPercent(100.0);
+ Assert.assertThrows(IllegalArgumentException.class, () -> horizontalRuleFormat.setWidthPercent(0.0));
+ Assert.assertThrows(IllegalArgumentException.class, () -> horizontalRuleFormat.setWidthPercent(101.0));
+
+ horizontalRuleFormat.setHeight(0.0);
+ horizontalRuleFormat.setHeight(1584.0);
+ Assert.assertThrows(IllegalArgumentException.class, () -> horizontalRuleFormat.setHeight(-1));
+ Assert.assertThrows(IllegalArgumentException.class, () -> horizontalRuleFormat.setHeight(1585.0));
+ }
+
+ @Test
+ public void insertHyperlink() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertHyperlink
+ //ExFor:Font.ClearFormatting
+ //ExFor:Font.Color
+ //ExFor:Font.Underline
+ //ExFor:Underline
+ //ExSummary:Shows how to insert a hyperlink field.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ builder.write("For more information, please visit the ");
+
+ // Insert a hyperlink and emphasize it with custom formatting.
+ // The hyperlink will be a clickable piece of text which will take us to the location specified in the URL.
+ builder.getFont().setColor(Color.BLUE);
+ builder.getFont().setUnderline(Underline.SINGLE);
+ builder.insertHyperlink("Google website", "https://www.google.com", false);
+ builder.getFont().clearFormatting();
+ builder.writeln(".");
+
+ // Ctrl + left clicking the link in the text in Microsoft Word will take us to the URL via a new web browser window.
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertHyperlink.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertHyperlink.docx");
+
+ FieldHyperlink hyperlink = (FieldHyperlink)doc.getRange().getFields().get(0);
+ Assert.assertEquals("https://www.google.com", hyperlink.getAddress());
+ TestUtil.verifyWebResponseStatusCode(200, new URL(hyperlink.getAddress()));
+
+ // This field is written as w:hyperlink element therefore field code cannot have formatting.
+ Run fieldCode = (Run)hyperlink.getStart().getNextSibling();
+ Assert.assertEquals("HYPERLINK \"https://www.google.com\"", fieldCode.getText().trim());
+
+ Run fieldResult = (Run)hyperlink.getSeparator().getNextSibling();
+
+ Assert.assertEquals(Color.BLUE.getRGB(), fieldResult.getFont().getColor().getRGB());
+ Assert.assertEquals(Underline.SINGLE, fieldResult.getFont().getUnderline());
+ Assert.assertEquals("Google website", fieldResult.getText().trim());
+ }
+
+ @Test
+ public void pushPopFont() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.PushFont
+ //ExFor:DocumentBuilder.PopFont
+ //ExFor:DocumentBuilder.InsertHyperlink
+ //ExSummary:Shows how to use a document builder's formatting stack.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Set up font formatting, then write the text that goes before the hyperlink.
+ builder.getFont().setName("Arial");
+ builder.getFont().setSize(24.0);
+ builder.write("To visit Google, hold Ctrl and click ");
+
+ // Preserve our current formatting configuration on the stack.
+ builder.pushFont();
+
+ // Alter the builder's current formatting by applying a new style.
+ builder.getFont().setStyleIdentifier(StyleIdentifier.HYPERLINK);
+ builder.insertHyperlink("here", "http://www.google.com", false);
+
+ Assert.assertEquals(Color.BLUE.getRGB(), builder.getFont().getColor().getRGB());
+ Assert.assertEquals(Underline.SINGLE, builder.getFont().getUnderline());
+
+ // Restore the font formatting that we saved earlier and remove the element from the stack.
+ builder.popFont();
+
+ Assert.assertEquals(0, builder.getFont().getColor().getRGB());
+ Assert.assertEquals(Underline.NONE, builder.getFont().getUnderline());
+
+ builder.write(". We hope you enjoyed the example.");
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.PushPopFont.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.PushPopFont.docx");
+ RunCollection runs = doc.getFirstSection().getBody().getFirstParagraph().getRuns();
+
+ Assert.assertEquals(4, runs.getCount());
+
+ Assert.assertEquals("To visit Google, hold Ctrl and click", runs.get(0).getText().trim());
+ Assert.assertEquals(". We hope you enjoyed the example.", runs.get(3).getText().trim());
+ Assert.assertEquals(runs.get(0).getFont().getColor(), runs.get(3).getFont().getColor());
+ Assert.assertEquals(runs.get(0).getFont().getUnderline(), runs.get(3).getFont().getUnderline());
+
+ Assert.assertEquals("here", runs.get(2).getText().trim());
+ Assert.assertEquals(Color.BLUE.getRGB(), runs.get(2).getFont().getColor().getRGB());
+ Assert.assertEquals(Underline.SINGLE, runs.get(2).getFont().getUnderline());
+ Assert.assertNotEquals(runs.get(0).getFont().getColor(), runs.get(2).getFont().getColor());
+ Assert.assertNotEquals(runs.get(0).getFont().getUnderline(), runs.get(2).getFont().getUnderline());
+ }
+
+ @Test
+ public void insertWatermark() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.MoveToHeaderFooter
+ //ExFor:PageSetup.PageWidth
+ //ExFor:PageSetup.PageHeight
+ //ExFor:WrapType
+ //ExFor:RelativeHorizontalPosition
+ //ExFor:RelativeVerticalPosition
+ //ExSummary:Shows how to insert an image, and use it as a watermark.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert the image into the header so that it will be visible on every page.
+ builder.moveToHeaderFooter(HeaderFooterType.HEADER_PRIMARY);
+ Shape shape = builder.insertImage(getImageDir() + "Transparent background logo.png");
+ shape.setWrapType(WrapType.NONE);
+ shape.setBehindText(true);
+
+ // Place the image at the center of the page.
+ shape.setRelativeHorizontalPosition(RelativeHorizontalPosition.PAGE);
+ shape.setRelativeVerticalPosition(RelativeVerticalPosition.PAGE);
+ shape.setLeft((builder.getPageSetup().getPageWidth() - shape.getWidth()) / 2.0);
+ shape.setTop((builder.getPageSetup().getPageHeight() - shape.getHeight()) / 2.0);
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertWatermark.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertWatermark.docx");
+ shape = (Shape) doc.getFirstSection().getHeadersFooters().getByHeaderFooterType(HeaderFooterType.HEADER_PRIMARY).getChild(NodeType.SHAPE, 0, true);
+
+ TestUtil.verifyImageInShape(400, 400, ImageType.PNG, shape);
+ Assert.assertEquals(WrapType.NONE, shape.getWrapType());
+ Assert.assertTrue(shape.getBehindText());
+ Assert.assertEquals(RelativeHorizontalPosition.PAGE, shape.getRelativeHorizontalPosition());
+ Assert.assertEquals(RelativeVerticalPosition.PAGE, shape.getRelativeVerticalPosition());
+ Assert.assertEquals((doc.getFirstSection().getPageSetup().getPageWidth() - shape.getWidth()) / 2.0, shape.getLeft());
+ Assert.assertEquals((doc.getFirstSection().getPageSetup().getPageHeight() - shape.getHeight()) / 2.0, shape.getTop());
+ }
+
+ @Test
+ public void insertOleObject() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertOleObject(String, Boolean, Boolean, Stream)
+ //ExFor:DocumentBuilder.InsertOleObject(String, String, Boolean, Boolean, Stream)
+ //ExFor:DocumentBuilder.InsertOleObjectAsIcon(String, Boolean, String, String)
+ //ExSummary:Shows how to insert an OLE object into a document.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // OLE objects are links to files in our local file system that can be opened by other installed applications.
+ // Double clicking these shapes will launch the application, and then use it to open the linked object.
+ // There are three ways of using the InsertOleObject method to insert these shapes and configure their appearance.
+ // If 'presentation' is omitted and 'asIcon' is set, this overloaded method selects
+ // the icon according to the file extension and uses the filename for the icon caption.
+ // 1 - Image taken from the local file system:
+ builder.insertOleObject(getMyDir() + "Spreadsheet.xlsx", false, false, new FileInputStream(getImageDir() + "Logo.jpg"));
+
+ // If 'presentation' is omitted and 'asIcon' is set, this overloaded method selects
+ // the icon according to 'progId' and uses the filename for the icon caption.
+ // 2 - Icon based on the application that will open the object:
+ builder.insertOleObject(getMyDir() + "Spreadsheet.xlsx", "Excel.Sheet", false, true, new FileInputStream(getImageDir() + "Logo.jpg"));
+
+ // If 'iconFile' and 'iconCaption' are omitted, this overloaded method selects
+ // the icon according to 'progId' and uses the predefined icon caption.
+ // 3 - Image icon that's 32 x 32 pixels or smaller from the local file system, with a custom caption:
+ builder.insertOleObjectAsIcon(getMyDir() + "Presentation.pptx", false, getImageDir() + "Logo icon.ico",
+ "Double click to view presentation!");
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertOleObject.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertOleObject.docx");
+ Shape shape = (Shape) doc.getChild(NodeType.SHAPE, 0, true);
+
+ Assert.assertEquals(ShapeType.OLE_OBJECT, shape.getShapeType());
+ Assert.assertEquals("Excel.Sheet.12", shape.getOleFormat().getProgId());
+ Assert.assertEquals(".xlsx", shape.getOleFormat().getSuggestedExtension());
+
+ shape = (Shape) doc.getChild(NodeType.SHAPE, 1, true);
+
+ Assert.assertEquals(ShapeType.OLE_OBJECT, shape.getShapeType());
+ Assert.assertEquals("Package", shape.getOleFormat().getProgId());
+ Assert.assertEquals(".xlsx", shape.getOleFormat().getSuggestedExtension());
+
+ shape = (Shape) doc.getChild(NodeType.SHAPE, 2, true);
+
+ Assert.assertEquals(ShapeType.OLE_OBJECT, shape.getShapeType());
+ Assert.assertEquals("PowerPoint.Show.12", shape.getOleFormat().getProgId());
+ Assert.assertEquals(".pptx", shape.getOleFormat().getSuggestedExtension());
+ }
+
+ @Test
+ public void insertHtml() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertHtml(String)
+ //ExSummary:Shows how to use a document builder to insert html content into a document.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ final String HTML = "
Paragraph right
" +
+ "Implicit paragraph left" +
+ "
Div center
" +
+ "
Heading 1 left.
";
+
+ builder.insertHtml(HTML);
+
+ // Inserting HTML code parses the formatting of each element into equivalent document text formatting.
+ ParagraphCollection paragraphs = doc.getFirstSection().getBody().getParagraphs();
+
+ Assert.assertEquals("Paragraph right", paragraphs.get(0).getText().trim());
+ Assert.assertEquals(ParagraphAlignment.RIGHT, paragraphs.get(0).getParagraphFormat().getAlignment());
+
+ Assert.assertEquals("Implicit paragraph left", paragraphs.get(1).getText().trim());
+ Assert.assertEquals(ParagraphAlignment.LEFT, paragraphs.get(1).getParagraphFormat().getAlignment());
+ Assert.assertTrue(paragraphs.get(1).getRuns().get(0).getFont().getBold());
+
+ Assert.assertEquals("Div center", paragraphs.get(2).getText().trim());
+ Assert.assertEquals(ParagraphAlignment.CENTER, paragraphs.get(2).getParagraphFormat().getAlignment());
+
+ Assert.assertEquals("Heading 1 left.", paragraphs.get(3).getText().trim());
+ Assert.assertEquals("Heading 1", paragraphs.get(3).getParagraphFormat().getStyle().getName());
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertHtml.docx");
+ //ExEnd
+ }
+
+ @Test(dataProvider = "insertHtmlWithFormattingDataProvider")
+ public void insertHtmlWithFormatting(boolean useBuilderFormatting) throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertHtml(String, Boolean)
+ //ExSummary:Shows how to apply a document builder's formatting while inserting HTML content.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Set a text alignment for the builder, insert an HTML paragraph with a specified alignment, and one without.
+ builder.getParagraphFormat().setAlignment(ParagraphAlignment.DISTRIBUTED);
+ builder.insertHtml(
+ "
Paragraph 1.
" +
+ "
Paragraph 2.
", useBuilderFormatting);
+
+ ParagraphCollection paragraphs = doc.getFirstSection().getBody().getParagraphs();
+
+ // The first paragraph has an alignment specified. When InsertHtml parses the HTML code,
+ // the paragraph alignment value found in the HTML code always supersedes the document builder's value.
+ Assert.assertEquals("Paragraph 1.", paragraphs.get(0).getText().trim());
+ Assert.assertEquals(ParagraphAlignment.RIGHT, paragraphs.get(0).getParagraphFormat().getAlignment());
+
+ // The second paragraph has no alignment specified. It can have its alignment value filled in
+ // by the builder's value depending on the flag we passed to the InsertHtml method.
+ Assert.assertEquals("Paragraph 2.", paragraphs.get(1).getText().trim());
+ Assert.assertEquals(useBuilderFormatting ? ParagraphAlignment.DISTRIBUTED : ParagraphAlignment.LEFT,
+ paragraphs.get(1).getParagraphFormat().getAlignment());
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertHtmlWithFormatting.docx");
+ //ExEnd
+ }
+
+ //JAVA-added data provider for test method
+ @DataProvider(name = "insertHtmlWithFormattingDataProvider")
+ public static Object[][] insertHtmlWithFormattingDataProvider() throws Exception {
+ return new Object[][]
+ {
+ {false},
+ {true},
+ };
+ }
+
+ @Test
+ public void mathMl() throws Exception {
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ final String mathML =
+ "";
+
+ builder.insertHtml(mathML);
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.MathML.docx");
+ doc.save(getArtifactsDir() + "DocumentBuilder.MathML.pdf");
+
+ Assert.assertTrue(DocumentHelper.compareDocs(getGoldsDir() + "DocumentBuilder.MathML Gold.docx", getArtifactsDir() + "DocumentBuilder.MathML.docx"));
+ }
+
+ @Test
+ public void insertTextAndBookmark() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.StartBookmark
+ //ExFor:DocumentBuilder.EndBookmark
+ //ExSummary:Shows how create a bookmark.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // A valid bookmark needs to have document body text enclosed by
+ // BookmarkStart and BookmarkEnd nodes created with a matching bookmark name.
+ builder.startBookmark("MyBookmark");
+ builder.writeln("Hello world!");
+ builder.endBookmark("MyBookmark");
+
+ Assert.assertEquals(1, doc.getRange().getBookmarks().getCount());
+ Assert.assertEquals("MyBookmark", doc.getRange().getBookmarks().get(0).getName());
+ Assert.assertEquals("Hello world!", doc.getRange().getBookmarks().get(0).getText().trim());
+ //ExEnd
+ }
+
+ @Test
+ public void createColumnBookmark() throws Exception
+ {
+ //ExStart
+ //ExFor:DocumentBuilder.StartColumnBookmark
+ //ExFor:DocumentBuilder.EndColumnBookmark
+ //ExSummary:Shows how to create a column bookmark.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ builder.startTable();
+
+ builder.insertCell();
+ // Cells 1,2,4,5 will be bookmarked.
+ builder.startColumnBookmark("MyBookmark_1");
+ // Badly formed bookmarks or bookmarks with duplicate names will be ignored when the document is saved.
+ builder.startColumnBookmark("MyBookmark_1");
+ builder.startColumnBookmark("BadStartBookmark");
+ builder.write("Cell 1");
+
+ builder.insertCell();
+ builder.write("Cell 2");
+
+ builder.insertCell();
+ builder.write("Cell 3");
+
+ builder.endRow();
+
+ builder.insertCell();
+ builder.write("Cell 4");
+
+ builder.insertCell();
+ builder.write("Cell 5");
+ builder.endColumnBookmark("MyBookmark_1");
+ builder.endColumnBookmark("MyBookmark_1");
+
+ Assert.assertThrows(IllegalStateException.class, () -> builder.endColumnBookmark("BadEndBookmark")); //ExSkip
+
+ builder.insertCell();
+ builder.write("Cell 6");
+
+ builder.endRow();
+ builder.endTable();
+
+ doc.save(getArtifactsDir() + "Bookmarks.CreateColumnBookmark.docx");
+ //ExEnd
+ }
+
+ @Test
+ public void createForm() throws Exception
+ {
+ //ExStart
+ //ExFor:TextFormFieldType
+ //ExFor:DocumentBuilder.InsertTextInput
+ //ExFor:DocumentBuilder.InsertComboBox
+ //ExSummary:Shows how to create form fields.
+ DocumentBuilder builder = new DocumentBuilder();
+
+ // Form fields are objects in the document that the user can interact with by being prompted to enter values.
+ // We can create them using a document builder, and below are two ways of doing so.
+ // 1 - Basic text input:
+ builder.insertTextInput("My text input", TextFormFieldType.REGULAR,
+ "", "Enter your name here", 30);
+
+ // 2 - Combo box with prompt text, and a range of possible values:
+ String[] items =
+ {
+ "-- Select your favorite footwear --", "Sneakers", "Oxfords", "Flip-flops", "Other"
+ };
+
+ builder.insertParagraph();
+ builder.insertComboBox("My combo box", items, 0);
+
+ builder.getDocument().save(getArtifactsDir() + "DocumentBuilder.CreateForm.docx");
+ //ExEnd
+
+ Document doc = new Document(getArtifactsDir() + "DocumentBuilder.CreateForm.docx");
+ FormField formField = doc.getRange().getFormFields().get(0);
+
+ Assert.assertEquals("My text input", formField.getName());
+ Assert.assertEquals(TextFormFieldType.REGULAR, formField.getTextInputType());
+ Assert.assertEquals("Enter your name here", formField.getResult());
+
+ formField = doc.getRange().getFormFields().get(1);
+
+ Assert.assertEquals("My combo box", formField.getName());
+ Assert.assertEquals(TextFormFieldType.REGULAR, formField.getTextInputType());
+ Assert.assertEquals("-- Select your favorite footwear --", formField.getResult());
+ Assert.assertEquals(0, formField.getDropDownSelectedIndex());
+ Assert.assertEquals(Arrays.asList("-- Select your favorite footwear --", "Sneakers", "Oxfords", "Flip-flops", "Other"),
+ formField.getDropDownItems());
+ }
+
+ @Test
+ public void insertCheckBox() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertCheckBox(string, bool, bool, int)
+ //ExFor:DocumentBuilder.InsertCheckBox(String, bool, int)
+ //ExSummary:Shows how to insert checkboxes into the document.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert checkboxes of varying sizes and default checked statuses.
+ builder.write("Unchecked check box of a default size: ");
+ builder.insertCheckBox("", false, false, 0);
+ builder.insertParagraph();
+
+ builder.write("Large checked check box: ");
+ builder.insertCheckBox("CheckBox_Default", true, true, 50);
+ builder.insertParagraph();
+
+ // Form fields have a name length limit of 20 characters.
+ builder.write("Very large checked check box: ");
+ builder.insertCheckBox("CheckBox_OnlyCheckedValue", true, 100);
+
+ Assert.assertEquals("CheckBox_OnlyChecked", doc.getRange().getFormFields().get(2).getName());
+
+ // We can interact with these check boxes in Microsoft Word by double clicking them.
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertCheckBox.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertCheckBox.docx");
+
+ FormFieldCollection formFields = doc.getRange().getFormFields();
+
+ Assert.assertEquals("", formFields.get(0).getName());
+ Assert.assertEquals(false, formFields.get(0).getChecked());
+ Assert.assertEquals(false, formFields.get(0).getDefault());
+ Assert.assertEquals(10.0, formFields.get(0).getCheckBoxSize());
+
+ Assert.assertEquals("CheckBox_Default", formFields.get(1).getName());
+ Assert.assertEquals(true, formFields.get(1).getChecked());
+ Assert.assertEquals(true, formFields.get(1).getDefault());
+ Assert.assertEquals(50.0, formFields.get(1).getCheckBoxSize());
+
+ Assert.assertEquals("CheckBox_OnlyChecked", formFields.get(2).getName());
+ Assert.assertEquals(true, formFields.get(2).getChecked());
+ Assert.assertEquals(true, formFields.get(2).getDefault());
+ Assert.assertEquals(100.0, formFields.get(2).getCheckBoxSize());
+ }
+
+ @Test
+ public void insertCheckBoxEmptyName() throws Exception {
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Checking that the checkbox insertion with an empty name working correctly.
+ builder.insertCheckBox("", true, false, 1);
+ builder.insertCheckBox("", false, 1);
+ }
+
+ @Test
+ public void workingWithNodes() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.MoveTo(Node)
+ //ExFor:DocumentBuilder.MoveToBookmark(String)
+ //ExFor:DocumentBuilder.CurrentParagraph
+ //ExFor:DocumentBuilder.CurrentNode
+ //ExFor:DocumentBuilder.MoveToDocumentStart
+ //ExFor:DocumentBuilder.MoveToDocumentEnd
+ //ExFor:DocumentBuilder.IsAtEndOfParagraph
+ //ExFor:DocumentBuilder.IsAtStartOfParagraph
+ //ExSummary:Shows how to move a document builder's cursor to different nodes in a document.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Create a valid bookmark, an entity that consists of nodes enclosed by a bookmark start node,
+ // and a bookmark end node.
+ builder.startBookmark("MyBookmark");
+ builder.write("Bookmark contents.");
+ builder.endBookmark("MyBookmark");
+
+ NodeCollection firstParagraphNodes = doc.getFirstSection().getBody().getFirstParagraph().getChildNodes(NodeType.ANY, false);
+
+ Assert.assertEquals(NodeType.BOOKMARK_START, firstParagraphNodes.get(0).getNodeType());
+ Assert.assertEquals(NodeType.RUN, firstParagraphNodes.get(1).getNodeType());
+ Assert.assertEquals("Bookmark contents.", firstParagraphNodes.get(1).getText().trim());
+ Assert.assertEquals(NodeType.BOOKMARK_END, firstParagraphNodes.get(2).getNodeType());
+
+ // The document builder's cursor is always ahead of the node that we last added with it.
+ // If the builder's cursor is at the end of the document, its current node will be null.
+ // The previous node is the bookmark end node that we last added.
+ // Adding new nodes with the builder will append them to the last node.
+ Assert.assertNull(builder.getCurrentNode());
+
+ // If we wish to edit a different part of the document with the builder,
+ // we will need to bring its cursor to the node we wish to edit.
+ builder.moveToBookmark("MyBookmark");
+
+ // Moving it to a bookmark will move it to the first node within the bookmark start and end nodes, the enclosed run.
+ Assert.assertEquals(firstParagraphNodes.get(1), builder.getCurrentNode());
+
+ // We can also move the cursor to an individual node like this.
+ builder.moveTo(doc.getFirstSection().getBody().getFirstParagraph().getChildNodes(NodeType.ANY, false).get(0));
+
+ Assert.assertEquals(NodeType.BOOKMARK_START, builder.getCurrentNode().getNodeType());
+ Assert.assertEquals(doc.getFirstSection().getBody().getFirstParagraph(), builder.getCurrentParagraph());
+ Assert.assertTrue(builder.isAtStartOfParagraph());
+
+ // We can use specific methods to move to the start/end of a document.
+ builder.moveToDocumentEnd();
+
+ Assert.assertTrue(builder.isAtEndOfParagraph());
+
+ builder.moveToDocumentStart();
+
+ Assert.assertTrue(builder.isAtStartOfParagraph());
+ //ExEnd
+ }
+
+ @Test
+ public void fillMergeFields() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.MoveToMergeField(String)
+ //ExFor:DocumentBuilder.Bold
+ //ExFor:DocumentBuilder.Italic
+ //ExSummary:Shows how to fill MERGEFIELDs with data with a document builder instead of a mail merge.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert some MERGEFIELDS, which accept data from columns of the same name in a data source during a mail merge,
+ // and then fill them manually.
+ builder.insertField(" MERGEFIELD Chairman ");
+ builder.insertField(" MERGEFIELD ChiefFinancialOfficer ");
+ builder.insertField(" MERGEFIELD ChiefTechnologyOfficer ");
+
+ builder.moveToMergeField("Chairman");
+ builder.setBold(true);
+ builder.writeln("John Doe");
+
+ builder.moveToMergeField("ChiefFinancialOfficer");
+ builder.setItalic(true);
+ builder.writeln("Jane Doe");
+
+ builder.moveToMergeField("ChiefTechnologyOfficer");
+ builder.setItalic(true);
+ builder.writeln("John Bloggs");
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.FillMergeFields.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.FillMergeFields.docx");
+ ParagraphCollection paragraphs = doc.getFirstSection().getBody().getParagraphs();
+
+ Assert.assertTrue(paragraphs.get(0).getRuns().get(0).getFont().getBold());
+ Assert.assertEquals("John Doe", paragraphs.get(0).getRuns().get(0).getText().trim());
+
+ Assert.assertTrue(paragraphs.get(1).getRuns().get(0).getFont().getItalic());
+ Assert.assertEquals("Jane Doe", paragraphs.get(1).getRuns().get(0).getText().trim());
+
+ Assert.assertTrue(paragraphs.get(2).getRuns().get(0).getFont().getItalic());
+ Assert.assertEquals("John Bloggs", paragraphs.get(2).getRuns().get(0).getText().trim());
+
+ }
+
+ @Test
+ public void insertToc() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertTableOfContents
+ //ExFor:Document.UpdateFields
+ //ExFor:DocumentBuilder.#ctor(Document)
+ //ExFor:ParagraphFormat.StyleIdentifier
+ //ExFor:DocumentBuilder.InsertBreak
+ //ExFor:BreakType
+ //ExSummary:Shows how to insert a Table of contents (TOC) into a document using heading styles as entries.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert a table of contents for the first page of the document.
+ // Configure the table to pick up paragraphs with headings of levels 1 to 3.
+ // Also, set its entries to be hyperlinks that will take us
+ // to the location of the heading when left-clicked in Microsoft Word.
+ builder.insertTableOfContents("\\o \"1-3\" \\h \\z \\u");
+ builder.insertBreak(BreakType.PAGE_BREAK);
+
+ // Populate the table of contents by adding paragraphs with heading styles.
+ // Each such heading with a level between 1 and 3 will create an entry in the table.
+ builder.getParagraphFormat().setStyleIdentifier(StyleIdentifier.HEADING_1);
+ builder.writeln("Heading 1");
+
+ builder.getParagraphFormat().setStyleIdentifier(StyleIdentifier.HEADING_2);
+ builder.writeln("Heading 1.1");
+ builder.writeln("Heading 1.2");
+
+ builder.getParagraphFormat().setStyleIdentifier(StyleIdentifier.HEADING_1);
+ builder.writeln("Heading 2");
+ builder.writeln("Heading 3");
+
+ builder.getParagraphFormat().setStyleIdentifier(StyleIdentifier.HEADING_2);
+ builder.writeln("Heading 3.1");
+
+ builder.getParagraphFormat().setStyleIdentifier(StyleIdentifier.HEADING_3);
+ builder.writeln("Heading 3.1.1");
+ builder.writeln("Heading 3.1.2");
+ builder.writeln("Heading 3.1.3");
+
+ builder.getParagraphFormat().setStyleIdentifier(StyleIdentifier.HEADING_4);
+ builder.writeln("Heading 3.1.3.1");
+ builder.writeln("Heading 3.1.3.2");
+
+ builder.getParagraphFormat().setStyleIdentifier(StyleIdentifier.HEADING_2);
+ builder.writeln("Heading 3.2");
+ builder.writeln("Heading 3.3");
+
+ // A table of contents is a field of a type that needs to be updated to show an up-to-date result.
+ doc.updateFields();
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertToc.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertToc.docx");
+ FieldToc tableOfContents = (FieldToc) doc.getRange().getFields().get(0);
+
+ Assert.assertEquals("1-3", tableOfContents.getHeadingLevelRange());
+ Assert.assertTrue(tableOfContents.getInsertHyperlinks());
+ Assert.assertTrue(tableOfContents.getHideInWebLayout());
+ Assert.assertTrue(tableOfContents.getUseParagraphOutlineLevel());
+ }
+
+ @Test
+ public void insertTable() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder
+ //ExFor:DocumentBuilder.Write(String)
+ //ExFor:DocumentBuilder.StartTable
+ //ExFor:DocumentBuilder.InsertCell
+ //ExFor:DocumentBuilder.EndRow
+ //ExFor:DocumentBuilder.EndTable
+ //ExFor:DocumentBuilder.CellFormat
+ //ExFor:DocumentBuilder.RowFormat
+ //ExFor:CellFormat
+ //ExFor:CellFormat.FitText
+ //ExFor:CellFormat.Width
+ //ExFor:CellFormat.VerticalAlignment
+ //ExFor:CellFormat.Shading
+ //ExFor:CellFormat.Orientation
+ //ExFor:CellFormat.WrapText
+ //ExFor:RowFormat
+ //ExFor:RowFormat.Borders
+ //ExFor:RowFormat.ClearFormatting
+ //ExFor:Shading.ClearFormatting
+ //ExSummary:Shows how to build a table with custom borders.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ builder.startTable();
+
+ // Setting table formatting options for a document builder
+ // will apply them to every row and cell that we add with it.
+ builder.getParagraphFormat().setAlignment(ParagraphAlignment.CENTER);
+
+ builder.getCellFormat().clearFormatting();
+ builder.getCellFormat().setWidth(150.0);
+ builder.getCellFormat().setVerticalAlignment(CellVerticalAlignment.CENTER);
+ builder.getCellFormat().getShading().setBackgroundPatternColor(Color.GREEN);
+ builder.getCellFormat().setWrapText(false);
+ builder.getCellFormat().setFitText(true);
+
+ builder.getRowFormat().clearFormatting();
+ builder.getRowFormat().setHeightRule(HeightRule.EXACTLY);
+ builder.getRowFormat().setHeight(50.0);
+ builder.getRowFormat().getBorders().setLineStyle(LineStyle.ENGRAVE_3_D);
+ builder.getRowFormat().getBorders().setColor(Color.ORANGE);
+
+ builder.insertCell();
+ builder.write("Row 1, Col 1");
+
+ builder.insertCell();
+ builder.write("Row 1, Col 2");
+ builder.endRow();
+
+ // Changing the formatting will apply it to the current cell,
+ // and any new cells that we create with the builder afterward.
+ // This will not affect the cells that we have added previously.
+ builder.getCellFormat().getShading().clearFormatting();
+
+ builder.insertCell();
+ builder.write("Row 2, Col 1");
+
+ builder.insertCell();
+ builder.write("Row 2, Col 2");
+
+ builder.endRow();
+
+ // Increase row height to fit the vertical text.
+ builder.insertCell();
+ builder.getRowFormat().setHeight(150.0);
+ builder.getCellFormat().setOrientation(TextOrientation.UPWARD);
+ builder.write("Row 3, Col 1");
+
+ builder.insertCell();
+ builder.getCellFormat().setOrientation(TextOrientation.DOWNWARD);
+ builder.write("Row 3, Col 2");
+
+ builder.endRow();
+ builder.endTable();
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertTable.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertTable.docx");
+ Table table = (Table) doc.getChild(NodeType.TABLE, 0, true);
+
+ Assert.assertEquals("Row 1, Col 1", table.getRows().get(0).getCells().get(0).getText().trim());
+ Assert.assertEquals("Row 1, Col 2", table.getRows().get(0).getCells().get(1).getText().trim());
+ Assert.assertEquals(HeightRule.EXACTLY, table.getRows().get(0).getRowFormat().getHeightRule());
+ Assert.assertEquals(50.0d, table.getRows().get(0).getRowFormat().getHeight());
+ Assert.assertEquals(LineStyle.ENGRAVE_3_D, table.getRows().get(0).getRowFormat().getBorders().getLineStyle());
+ Assert.assertEquals(Color.ORANGE.getRGB(), table.getRows().get(0).getRowFormat().getBorders().getColor().getRGB());
+
+ for (Cell c : table.getRows().get(0).getCells()) {
+ Assert.assertEquals(150.0, c.getCellFormat().getWidth());
+ Assert.assertEquals(CellVerticalAlignment.CENTER, c.getCellFormat().getVerticalAlignment());
+ Assert.assertEquals(Color.GREEN.getRGB(), c.getCellFormat().getShading().getBackgroundPatternColor().getRGB());
+ Assert.assertFalse(c.getCellFormat().getWrapText());
+ Assert.assertTrue(c.getCellFormat().getFitText());
+
+ Assert.assertEquals(ParagraphAlignment.CENTER, c.getFirstParagraph().getParagraphFormat().getAlignment());
+ }
+
+ Assert.assertEquals("Row 2, Col 1", table.getRows().get(1).getCells().get(0).getText().trim());
+ Assert.assertEquals("Row 2, Col 2", table.getRows().get(1).getCells().get(1).getText().trim());
+
+
+ for (Cell c : table.getRows().get(1).getCells()) {
+ Assert.assertEquals(150.0, c.getCellFormat().getWidth());
+ Assert.assertEquals(CellVerticalAlignment.CENTER, c.getCellFormat().getVerticalAlignment());
+ Assert.assertEquals(0, c.getCellFormat().getShading().getBackgroundPatternColor().getRGB());
+ Assert.assertFalse(c.getCellFormat().getWrapText());
+ Assert.assertTrue(c.getCellFormat().getFitText());
+
+ Assert.assertEquals(ParagraphAlignment.CENTER, c.getFirstParagraph().getParagraphFormat().getAlignment());
+ }
+
+ Assert.assertEquals(150.0, table.getRows().get(2).getRowFormat().getHeight());
+
+ Assert.assertEquals("Row 3, Col 1", table.getRows().get(2).getCells().get(0).getText().trim());
+ Assert.assertEquals(TextOrientation.UPWARD, table.getRows().get(2).getCells().get(0).getCellFormat().getOrientation());
+ Assert.assertEquals(ParagraphAlignment.CENTER, table.getRows().get(2).getCells().get(0).getFirstParagraph().getParagraphFormat().getAlignment());
+
+ Assert.assertEquals("Row 3, Col 2", table.getRows().get(2).getCells().get(1).getText().trim());
+ Assert.assertEquals(TextOrientation.DOWNWARD, table.getRows().get(2).getCells().get(1).getCellFormat().getOrientation());
+ Assert.assertEquals(ParagraphAlignment.CENTER, table.getRows().get(2).getCells().get(1).getFirstParagraph().getParagraphFormat().getAlignment());
+ }
+
+ @Test
+ public void insertTableWithStyle() throws Exception {
+ //ExStart
+ //ExFor:Table.StyleIdentifier
+ //ExFor:Table.StyleOptions
+ //ExFor:TableStyleOptions
+ //ExFor:Table.AutoFit
+ //ExFor:AutoFitBehavior
+ //ExSummary:Shows how to build a new table while applying a style.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ Table table = builder.startTable();
+
+ // We must insert at least one row before setting any table formatting.
+ builder.insertCell();
+
+ // Set the table style used based on the style identifier.
+ // Note that not all table styles are available when saving to .doc format.
+ table.setStyleIdentifier(StyleIdentifier.MEDIUM_SHADING_1_ACCENT_1);
+
+ // Partially apply the style to features of the table based on predicates, then build the table.
+ table.setStyleOptions(TableStyleOptions.FIRST_COLUMN | TableStyleOptions.ROW_BANDS | TableStyleOptions.FIRST_ROW);
+ table.autoFit(AutoFitBehavior.AUTO_FIT_TO_CONTENTS);
+
+ builder.writeln("Item");
+ builder.getCellFormat().setRightPadding(40.0);
+ builder.insertCell();
+ builder.writeln("Quantity (kg)");
+ builder.endRow();
+
+ builder.insertCell();
+ builder.writeln("Apples");
+ builder.insertCell();
+ builder.writeln("20");
+ builder.endRow();
+
+ builder.insertCell();
+ builder.writeln("Bananas");
+ builder.insertCell();
+ builder.writeln("40");
+ builder.endRow();
+
+ builder.insertCell();
+ builder.writeln("Carrots");
+ builder.insertCell();
+ builder.writeln("50");
+ builder.endRow();
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertTableWithStyle.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertTableWithStyle.docx");
+
+ doc.expandTableStylesToDirectFormatting();
+
+ Assert.assertEquals("Medium Shading 1 Accent 1", table.getStyle().getName());
+ Assert.assertEquals(TableStyleOptions.FIRST_COLUMN | TableStyleOptions.ROW_BANDS | TableStyleOptions.FIRST_ROW,
+ table.getStyleOptions());
+ Assert.assertEquals(189, (table.getFirstRow().getFirstCell().getCellFormat().getShading().getBackgroundPatternColor().getBlue() & 0xFF));
+ Assert.assertEquals(Color.WHITE.getRGB(), table.getFirstRow().getFirstCell().getFirstParagraph().getRuns().get(0).getFont().getColor().getRGB());
+ Assert.assertNotEquals(Color.BLUE.getRGB(),
+ (table.getLastRow().getFirstCell().getCellFormat().getShading().getBackgroundPatternColor().getBlue() & 0xFF));
+ Assert.assertEquals(0, table.getLastRow().getFirstCell().getFirstParagraph().getRuns().get(0).getFont().getColor().getRGB());
+ }
+
+ @Test
+ public void insertTableSetHeadingRow() throws Exception {
+ //ExStart
+ //ExFor:RowFormat.HeadingFormat
+ //ExSummary:Shows how to build a table with rows that repeat on every page.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Table table = builder.startTable();
+
+ // Any rows inserted while the "HeadingFormat" flag is set to "true"
+ // will show up at the top of the table on every page that it spans.
+ builder.getRowFormat().setHeadingFormat(true);
+ builder.getParagraphFormat().setAlignment(ParagraphAlignment.CENTER);
+ builder.getCellFormat().setWidth(100.0);
+ builder.insertCell();
+ builder.write("Heading row 1");
+ builder.endRow();
+ builder.insertCell();
+ builder.write("Heading row 2");
+ builder.endRow();
+
+ builder.getCellFormat().setWidth(50.0);
+ builder.getParagraphFormat().clearFormatting();
+ builder.getRowFormat().setHeadingFormat(false);
+
+ // Add enough rows for the table to span two pages.
+ for (int i = 0; i < 50; i++) {
+ builder.insertCell();
+ builder.write(MessageFormat.format("Row {0}, column 1.", table.getRows().toArray().length));
+ builder.insertCell();
+ builder.write(MessageFormat.format("Row {0}, column 2.", table.getRows().toArray().length));
+ builder.endRow();
+ }
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertTableSetHeadingRow.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertTableSetHeadingRow.docx");
+ table = doc.getFirstSection().getBody().getTables().get(0);
+
+ for (int i = 0; i < table.getRows().getCount(); i++)
+ Assert.assertEquals(i < 2, table.getRows().get(i).getRowFormat().getHeadingFormat());
+ }
+
+ @Test
+ public void insertTableWithPreferredWidth() throws Exception {
+ //ExStart
+ //ExFor:Table.PreferredWidth
+ //ExFor:PreferredWidth.FromPercent
+ //ExFor:PreferredWidth
+ //ExSummary:Shows how to set a table to auto fit to 50% of the width of the page.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Table table = builder.startTable();
+ builder.insertCell();
+ builder.write("Cell #1");
+ builder.insertCell();
+ builder.write("Cell #2");
+ builder.insertCell();
+ builder.write("Cell #3");
+
+ table.setPreferredWidth(PreferredWidth.fromPercent(50.0));
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertTableWithPreferredWidth.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertTableWithPreferredWidth.docx");
+ table = doc.getFirstSection().getBody().getTables().get(0);
+
+ Assert.assertEquals(PreferredWidthType.PERCENT, table.getPreferredWidth().getType());
+ Assert.assertEquals(50.0, table.getPreferredWidth().getValue());
+ }
+
+ @Test
+ public void insertCellsWithPreferredWidths() throws Exception {
+ //ExStart
+ //ExFor:CellFormat.PreferredWidth
+ //ExFor:PreferredWidth
+ //ExFor:PreferredWidth.Auto
+ //ExFor:PreferredWidth.Equals(PreferredWidth)
+ //ExFor:PreferredWidth.Equals(Object)
+ //ExFor:PreferredWidth.FromPoints
+ //ExFor:PreferredWidth.FromPercent
+ //ExFor:PreferredWidth.GetHashCode
+ //ExFor:PreferredWidth.ToString
+ //ExSummary:Shows how to set a preferred width for table cells.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ Table table = builder.startTable();
+
+ // There are two ways of applying the "PreferredWidth" class to table cells.
+ // 1 - Set an absolute preferred width based on points:
+ builder.insertCell();
+ builder.getCellFormat().setPreferredWidth(PreferredWidth.fromPoints(40.0));
+ builder.getCellFormat().getShading().setBackgroundPatternColor(Color.YELLOW);
+ builder.writeln(MessageFormat.format("Cell with a width of {0}.", builder.getCellFormat().getPreferredWidth()));
+
+ // 2 - Set a relative preferred width based on percent of the table's width:
+ builder.insertCell();
+ builder.getCellFormat().setPreferredWidth(PreferredWidth.fromPercent(20.0));
+ builder.getCellFormat().getShading().setBackgroundPatternColor(Color.BLUE);
+ builder.writeln(MessageFormat.format("Cell with a width of {0}.", builder.getCellFormat().getPreferredWidth()));
+
+ builder.insertCell();
+
+ // A cell with no preferred width specified will take up the rest of the available space.
+ builder.getCellFormat().setPreferredWidth(PreferredWidth.AUTO);
+
+ // Each configuration of the "PreferredWidth" property creates a new object.
+ Assert.assertNotEquals(table.getFirstRow().getCells().get(1).getCellFormat().getPreferredWidth().hashCode(),
+ builder.getCellFormat().getPreferredWidth().hashCode());
+
+ builder.getCellFormat().getShading().setBackgroundPatternColor(Color.GREEN);
+ builder.writeln("Automatically sized cell.");
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertCellsWithPreferredWidths.docx");
+ //ExEnd
+
+ Assert.assertEquals(100.0d, PreferredWidth.fromPercent(100.0).getValue());
+ Assert.assertEquals(100.0d, PreferredWidth.fromPoints(100.0).getValue());
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertCellsWithPreferredWidths.docx");
+ table = doc.getFirstSection().getBody().getTables().get(0);
+
+ Assert.assertEquals(PreferredWidthType.POINTS, table.getFirstRow().getCells().get(0).getCellFormat().getPreferredWidth().getType());
+ Assert.assertEquals(40.0d, table.getFirstRow().getCells().get(0).getCellFormat().getPreferredWidth().getValue());
+ Assert.assertEquals("Cell with a width of 800.", table.getFirstRow().getCells().get(0).getText().trim());
+
+ Assert.assertEquals(PreferredWidthType.PERCENT, table.getFirstRow().getCells().get(1).getCellFormat().getPreferredWidth().getType());
+ Assert.assertEquals(20.0d, table.getFirstRow().getCells().get(1).getCellFormat().getPreferredWidth().getValue());
+ Assert.assertEquals("Cell with a width of 20%.", table.getFirstRow().getCells().get(1).getText().trim());
+
+ Assert.assertEquals(PreferredWidthType.AUTO, table.getFirstRow().getCells().get(2).getCellFormat().getPreferredWidth().getType());
+ Assert.assertEquals(0.0d, table.getFirstRow().getCells().get(2).getCellFormat().getPreferredWidth().getValue());
+ Assert.assertEquals("Automatically sized cell.", table.getFirstRow().getCells().get(2).getText().trim());
+ }
+
+ @Test
+ public void insertTableFromHtml() throws Exception {
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert the table from HTML. Note that AutoFitSettings does not apply to tables
+ // inserted from HTML.
+ builder.insertHtml("
" + "
" + "
Row 1, Cell 1
" + "
Row 1, Cell 2
" + "
" +
+ "
" + "
Row 2, Cell 2
" + "
Row 2, Cell 2
" + "
" + "
");
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertTableFromHtml.docx");
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertTableFromHtml.docx");
+
+ Assert.assertEquals(1, doc.getChildNodes(NodeType.TABLE, true).getCount());
+ Assert.assertEquals(2, doc.getChildNodes(NodeType.ROW, true).getCount());
+ Assert.assertEquals(4, doc.getChildNodes(NodeType.CELL, true).getCount());
+ }
+
+ @Test
+ public void insertNestedTable() throws Exception {
+ //ExStart
+ //ExFor:Cell.FirstParagraph
+ //ExSummary:Shows how to create a nested table using a document builder.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Build the outer table.
+ Cell cell = builder.insertCell();
+ builder.writeln("Outer Table Cell 1");
+ builder.insertCell();
+ builder.writeln("Outer Table Cell 2");
+ builder.endTable();
+
+ // Move to the first cell of the outer table, the build another table inside the cell.
+ builder.moveTo(cell.getFirstParagraph());
+ builder.insertCell();
+ builder.writeln("Inner Table Cell 1");
+ builder.insertCell();
+ builder.writeln("Inner Table Cell 2");
+ builder.endTable();
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertNestedTable.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertNestedTable.docx");
+
+ Assert.assertEquals(2, doc.getChildNodes(NodeType.TABLE, true).getCount());
+ Assert.assertEquals(4, doc.getChildNodes(NodeType.CELL, true).getCount());
+ Assert.assertEquals(1, cell.getTables().get(0).getCount());
+ Assert.assertEquals(2, cell.getTables().get(0).getFirstRow().getCells().getCount());
+ }
+
+ @Test
+ public void createTable() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder
+ //ExFor:DocumentBuilder.Write(String)
+ //ExFor:DocumentBuilder.InsertCell
+ //ExSummary:Shows how to use a document builder to create a table.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Start the table, then populate the first row with two cells.
+ builder.startTable();
+ builder.insertCell();
+ builder.write("Row 1, Cell 1.");
+ builder.insertCell();
+ builder.write("Row 1, Cell 2.");
+
+ // Call the builder's "EndRow" method to start a new row.
+ builder.endRow();
+ builder.insertCell();
+ builder.write("Row 2, Cell 1.");
+ builder.insertCell();
+ builder.write("Row 2, Cell 2.");
+ builder.endTable();
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.CreateTable.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.CreateTable.docx");
+ Table table = doc.getFirstSection().getBody().getTables().get(0);
+
+ Assert.assertEquals(4, table.getChildNodes(NodeType.CELL, true).getCount());
+
+ Assert.assertEquals("Row 1, Cell 1.", table.getRows().get(0).getCells().get(0).getText().trim());
+ Assert.assertEquals("Row 1, Cell 2.", table.getRows().get(0).getCells().get(1).getText().trim());
+ Assert.assertEquals("Row 2, Cell 1.", table.getRows().get(1).getCells().get(0).getText().trim());
+ Assert.assertEquals("Row 2, Cell 2.", table.getRows().get(1).getCells().get(1).getText().trim());
+ }
+
+ @Test
+ public void buildFormattedTable() throws Exception {
+ //ExStart
+ //ExFor:RowFormat.Height
+ //ExFor:RowFormat.HeightRule
+ //ExFor:Table.LeftIndent
+ //ExFor:DocumentBuilder.ParagraphFormat
+ //ExFor:DocumentBuilder.Font
+ //ExSummary:Shows how to create a formatted table using DocumentBuilder.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Table table = builder.startTable();
+ builder.insertCell();
+ table.setLeftIndent(20.0);
+
+ // Set some formatting options for text and table appearance.
+ builder.getRowFormat().setHeight(40.0);
+ builder.getRowFormat().setHeightRule(HeightRule.AT_LEAST);
+ builder.getCellFormat().getShading().setBackgroundPatternColor(new Color((198), (217), (241)));
+
+ builder.getParagraphFormat().setAlignment(ParagraphAlignment.CENTER);
+ builder.getFont().setSize(16.0);
+ builder.getFont().setName("Arial");
+ builder.getFont().setBold(true);
+
+ // Configuring the formatting options in a document builder will apply them
+ // to the current cell/row its cursor is in,
+ // as well as any new cells and rows created using that builder.
+ builder.write("Header Row,\n Cell 1");
+ builder.insertCell();
+ builder.write("Header Row,\n Cell 2");
+ builder.insertCell();
+ builder.write("Header Row,\n Cell 3");
+ builder.endRow();
+
+ // Reconfigure the builder's formatting objects for new rows and cells that we are about to make.
+ // The builder will not apply these to the first row already created so that it will stand out as a header row.
+ builder.getCellFormat().getShading().setBackgroundPatternColor(Color.WHITE);
+ builder.getCellFormat().setVerticalAlignment(CellVerticalAlignment.CENTER);
+ builder.getRowFormat().setHeight(30.0);
+ builder.getRowFormat().setHeightRule(HeightRule.AUTO);
+ builder.insertCell();
+ builder.getFont().setSize(12.0);
+ builder.getFont().setBold(false);
+
+ builder.write("Row 1, Cell 1.");
+ builder.insertCell();
+ builder.write("Row 1, Cell 2.");
+ builder.insertCell();
+ builder.write("Row 1, Cell 3.");
+ builder.endRow();
+ builder.insertCell();
+ builder.write("Row 2, Cell 1.");
+ builder.insertCell();
+ builder.write("Row 2, Cell 2.");
+ builder.insertCell();
+ builder.write("Row 2, Cell 3.");
+ builder.endRow();
+ builder.endTable();
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.CreateFormattedTable.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.CreateFormattedTable.docx");
+ table = doc.getFirstSection().getBody().getTables().get(0);
+
+ Assert.assertEquals(20.0d, table.getLeftIndent());
+
+ Assert.assertEquals(HeightRule.AT_LEAST, table.getRows().get(0).getRowFormat().getHeightRule());
+ Assert.assertEquals(40.0d, table.getRows().get(0).getRowFormat().getHeight());
+
+ for (Cell c : (Iterable) doc.getChildNodes(NodeType.CELL, true)) {
+ Assert.assertEquals(ParagraphAlignment.CENTER, c.getFirstParagraph().getParagraphFormat().getAlignment());
+
+ for (Run r : c.getFirstParagraph().getRuns()) {
+ Assert.assertEquals("Arial", r.getFont().getName());
+
+ if (c.getParentRow() == table.getFirstRow()) {
+ Assert.assertEquals(16.0, r.getFont().getSize());
+ Assert.assertTrue(r.getFont().getBold());
+ } else {
+ Assert.assertEquals(12.0, r.getFont().getSize());
+ Assert.assertFalse(r.getFont().getBold());
+ }
+ }
+ }
+ }
+
+ @Test
+ public void tableBordersAndShading() throws Exception {
+ //ExStart
+ //ExFor:Shading
+ //ExFor:Table.SetBorders
+ //ExFor:BorderCollection.Left
+ //ExFor:BorderCollection.Right
+ //ExFor:BorderCollection.Top
+ //ExFor:BorderCollection.Bottom
+ //ExSummary:Shows how to apply border and shading color while building a table.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Start a table and set a default color/thickness for its borders.
+ Table table = builder.startTable();
+ table.setBorders(LineStyle.SINGLE, 2.0, Color.BLACK);
+
+ // Create a row with two cells with different background colors.
+ builder.insertCell();
+ builder.getCellFormat().getShading().setBackgroundPatternColor(Color.RED);
+ builder.writeln("Row 1, Cell 1.");
+ builder.insertCell();
+ builder.getCellFormat().getShading().setBackgroundPatternColor(Color.GREEN);
+ builder.writeln("Row 1, Cell 2.");
+ builder.endRow();
+
+ // Reset cell formatting to disable the background colors
+ // set a custom border thickness for all new cells created by the builder,
+ // then build a second row.
+ builder.getCellFormat().clearFormatting();
+ builder.getCellFormat().getBorders().getLeft().setLineWidth(4.0);
+ builder.getCellFormat().getBorders().getRight().setLineWidth(4.0);
+ builder.getCellFormat().getBorders().getTop().setLineWidth(4.0);
+ builder.getCellFormat().getBorders().getBottom().setLineWidth(4.0);
+
+ builder.insertCell();
+ builder.writeln("Row 2, Cell 1.");
+ builder.insertCell();
+ builder.writeln("Row 2, Cell 2.");
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.TableBordersAndShading.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.TableBordersAndShading.docx");
+ table = doc.getFirstSection().getBody().getTables().get(0);
+
+ for (Cell c : table.getFirstRow()) {
+ Assert.assertEquals(0.5d, c.getCellFormat().getBorders().getTop().getLineWidth());
+ Assert.assertEquals(0.5d, c.getCellFormat().getBorders().getBottom().getLineWidth());
+ Assert.assertEquals(0.5d, c.getCellFormat().getBorders().getLeft().getLineWidth());
+ Assert.assertEquals(0.5d, c.getCellFormat().getBorders().getRight().getLineWidth());
+
+ Assert.assertEquals(0, c.getCellFormat().getBorders().getLeft().getColor().getRGB());
+ Assert.assertEquals(LineStyle.SINGLE, c.getCellFormat().getBorders().getLeft().getLineStyle());
+ }
+
+ Assert.assertEquals(Color.RED.getRGB(),
+ table.getFirstRow().getFirstCell().getCellFormat().getShading().getBackgroundPatternColor().getRGB());
+ Assert.assertEquals(Color.GREEN.getRGB(),
+ table.getFirstRow().getCells().get(1).getCellFormat().getShading().getBackgroundPatternColor().getRGB());
+
+ for (Cell c : table.getLastRow()) {
+ Assert.assertEquals(4.0d, c.getCellFormat().getBorders().getTop().getLineWidth());
+ Assert.assertEquals(4.0d, c.getCellFormat().getBorders().getBottom().getLineWidth());
+ Assert.assertEquals(4.0d, c.getCellFormat().getBorders().getLeft().getLineWidth());
+ Assert.assertEquals(4.0d, c.getCellFormat().getBorders().getRight().getLineWidth());
+
+ Assert.assertEquals(0, c.getCellFormat().getBorders().getLeft().getColor().getRGB());
+ Assert.assertEquals(LineStyle.SINGLE, c.getCellFormat().getBorders().getLeft().getLineStyle());
+ Assert.assertEquals(0, c.getCellFormat().getShading().getBackgroundPatternColor().getRGB());
+ }
+ }
+
+ @Test
+ public void setPreferredTypeConvertUtil() throws Exception {
+ //ExStart
+ //ExFor:PreferredWidth.FromPoints
+ //ExSummary:Shows how to use unit conversion tools while specifying a preferred width for a cell.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Table table = builder.startTable();
+ builder.getCellFormat().setPreferredWidth(PreferredWidth.fromPoints(ConvertUtil.inchToPoint(3.0)));
+ builder.insertCell();
+
+ Assert.assertEquals(216.0d, table.getFirstRow().getFirstCell().getCellFormat().getPreferredWidth().getValue());
+ //ExEnd
+ }
+
+ @Test
+ public void insertHyperlinkToLocalBookmark() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.StartBookmark
+ //ExFor:DocumentBuilder.EndBookmark
+ //ExFor:DocumentBuilder.InsertHyperlink
+ //ExSummary:Shows how to insert a hyperlink which references a local bookmark.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ builder.startBookmark("Bookmark1");
+ builder.write("Bookmarked text. ");
+ builder.endBookmark("Bookmark1");
+ builder.writeln("Text outside of the bookmark.");
+
+ // Insert a HYPERLINK field that links to the bookmark. We can pass field switches
+ // to the "InsertHyperlink" method as part of the argument containing the referenced bookmark's name.
+ builder.getFont().setColor(Color.BLUE);
+ builder.getFont().setUnderline(Underline.SINGLE);
+ FieldHyperlink hyperlink = (FieldHyperlink)builder.insertHyperlink("Link to Bookmark1", "Bookmark1", true);
+ hyperlink.setScreenTip("Hyperlink Tip");
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertHyperlinkToLocalBookmark.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertHyperlinkToLocalBookmark.docx");
+ hyperlink = (FieldHyperlink)doc.getRange().getFields().get(0);
+
+ TestUtil.verifyField(FieldType.FIELD_HYPERLINK, " HYPERLINK \\l \"Bookmark1\" \\o \"Hyperlink Tip\" ", "Link to Bookmark1", hyperlink);
+ Assert.assertEquals("Bookmark1", hyperlink.getSubAddress());
+ Assert.assertEquals("Hyperlink Tip", hyperlink.getScreenTip());
+ Assert.assertTrue(IterableUtils.matchesAny(doc.getRange().getBookmarks(), b -> b.getName().contains("Bookmark1")));
+ }
+
+ @Test
+ public void cursorPosition() throws Exception {
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ builder.write("Hello world!");
+
+ // If the builder's cursor is at the end of the document,
+ // there will be no nodes in front of it so that the current node will be null.
+ Assert.assertNull(builder.getCurrentNode());
+
+ Assert.assertEquals("Hello world!", builder.getCurrentParagraph().getText().trim());
+
+ // Move to the beginning of the document and place the cursor at an existing node.
+ builder.moveToDocumentStart();
+ Assert.assertEquals(NodeType.RUN, builder.getCurrentNode().getNodeType());
+ }
+
+ @Test
+ public void moveTo() throws Exception {
+ //ExStart
+ //ExFor:Story.LastParagraph
+ //ExFor:DocumentBuilder.MoveTo(Node)
+ //ExSummary:Shows how to move a DocumentBuilder's cursor position to a specified node.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ builder.writeln("Run 1. ");
+
+ // The document builder has a cursor, which acts as the part of the document
+ // where the builder appends new nodes when we use its document construction methods.
+ // This cursor functions in the same way as Microsoft Word's blinking cursor,
+ // and it also always ends up immediately after any node that the builder just inserted.
+ // To append content to a different part of the document,
+ // we can move the cursor to a different node with the "MoveTo" method.
+ Assert.assertEquals(doc.getFirstSection().getBody().getLastParagraph(), builder.getCurrentParagraph()); //ExSkip
+ builder.moveTo(doc.getFirstSection().getBody().getFirstParagraph().getRuns().get(0));
+ Assert.assertEquals(doc.getFirstSection().getBody().getFirstParagraph(), builder.getCurrentParagraph()); //ExSkip
+
+ // The cursor is now in front of the node that we moved it to.
+ // Adding a second run will insert it in front of the first run.
+ builder.writeln("Run 2. ");
+
+ Assert.assertEquals("Run 2. \rRun 1.", doc.getText().trim());
+
+ // Move the cursor to the end of the document to continue appending text to the end as before.
+ builder.moveTo(doc.getLastSection().getBody().getLastParagraph());
+ builder.writeln("Run 3. ");
+
+ Assert.assertEquals("Run 2. \rRun 1. \rRun 3.", doc.getText().trim());
+ Assert.assertEquals(doc.getFirstSection().getBody().getLastParagraph(), builder.getCurrentParagraph()); //ExSkip
+
+ //ExEnd
+ }
+
+ @Test
+ public void moveToParagraph() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.MoveToParagraph
+ //ExSummary:Shows how to move a builder's cursor position to a specified paragraph.
+ Document doc = new Document(getMyDir() + "Paragraphs.docx");
+ ParagraphCollection paragraphs = doc.getFirstSection().getBody().getParagraphs();
+
+ Assert.assertEquals(22, paragraphs.getCount());
+
+ // Create document builder to edit the document. The builder's cursor,
+ // which is the point where it will insert new nodes when we call its document construction methods,
+ // is currently at the beginning of the document.
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Assert.assertEquals(0, paragraphs.indexOf(builder.getCurrentParagraph()));
+
+ // Move that cursor to a different paragraph will place that cursor in front of that paragraph.
+ builder.moveToParagraph(2, 0);
+ Assert.assertEquals(2, paragraphs.indexOf(builder.getCurrentParagraph())); //ExSkip
+
+ // Any new content that we add will be inserted at that point.
+ builder.writeln("This is a new third paragraph. ");
+ //ExEnd
+
+ Assert.assertEquals(3, paragraphs.indexOf(builder.getCurrentParagraph()));
+
+ doc = DocumentHelper.saveOpen(doc);
+
+ Assert.assertEquals("This is a new third paragraph.", doc.getFirstSection().getBody().getParagraphs().get(2).getText().trim());
+ }
+
+ @Test
+ public void moveToCell() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.MoveToCell
+ //ExSummary:Shows how to move a document builder's cursor to a cell in a table.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Create an empty 2x2 table.
+ builder.startTable();
+ builder.insertCell();
+ builder.insertCell();
+ builder.endRow();
+ builder.insertCell();
+ builder.insertCell();
+ builder.endTable();
+
+ // Because we have ended the table with the EndTable method,
+ // the document builder's cursor is currently outside the table.
+ // This cursor has the same function as Microsoft Word's blinking text cursor.
+ // It can also be moved to a different location in the document using the builder's MoveTo methods.
+ // We can move the cursor back inside the table to a specific cell.
+ builder.moveToCell(0, 1, 1, 0);
+ builder.write("Column 2, cell 2.");
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.MoveToCell.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.MoveToCell.docx");
+
+ Table table = doc.getFirstSection().getBody().getTables().get(0);
+
+ Assert.assertEquals("Column 2, cell 2.", table.getRows().get(1).getCells().get(1).getText().trim());
+ }
+
+ @Test
+ public void moveToBookmark() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.MoveToBookmark(String, Boolean, Boolean)
+ //ExSummary:Shows how to move a document builder's node insertion point cursor to a bookmark.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // A valid bookmark consists of a BookmarkStart node, a BookmarkEnd node with a
+ // matching bookmark name somewhere afterward, and contents enclosed by those nodes.
+ builder.startBookmark("MyBookmark");
+ builder.write("Hello world! ");
+ builder.endBookmark("MyBookmark");
+
+ // There are 4 ways of moving a document builder's cursor to a bookmark.
+ // If we are between the BookmarkStart and BookmarkEnd nodes, the cursor will be inside the bookmark.
+ // This means that any text added by the builder will become a part of the bookmark.
+ // 1 - Outside of the bookmark, in front of the BookmarkStart node:
+ Assert.assertTrue(builder.moveToBookmark("MyBookmark", true, false));
+ builder.write("1. ");
+
+ Assert.assertEquals("Hello world! ", doc.getRange().getBookmarks().get("MyBookmark").getText());
+ Assert.assertEquals("1. Hello world!", doc.getText().trim());
+
+ // 2 - Inside the bookmark, right after the BookmarkStart node:
+ Assert.assertTrue(builder.moveToBookmark("MyBookmark", true, true));
+ builder.write("2. ");
+
+ Assert.assertEquals("2. Hello world! ", doc.getRange().getBookmarks().get("MyBookmark").getText());
+ Assert.assertEquals("1. 2. Hello world!", doc.getText().trim());
+
+ // 2 - Inside the bookmark, right in front of the BookmarkEnd node:
+ Assert.assertTrue(builder.moveToBookmark("MyBookmark", false, false));
+ builder.write("3. ");
+
+ Assert.assertEquals("2. Hello world! 3. ", doc.getRange().getBookmarks().get("MyBookmark").getText());
+ Assert.assertEquals("1. 2. Hello world! 3.", doc.getText().trim());
+
+ // 4 - Outside of the bookmark, after the BookmarkEnd node:
+ Assert.assertTrue(builder.moveToBookmark("MyBookmark", false, true));
+ builder.write("4.");
+
+ Assert.assertEquals("2. Hello world! 3. ", doc.getRange().getBookmarks().get("MyBookmark").getText());
+ Assert.assertEquals("1. 2. Hello world! 3. 4.", doc.getText().trim());
+ //ExEnd
+ }
+
+ @Test
+ public void buildTable() throws Exception {
+ //ExStart
+ //ExFor:Table
+ //ExFor:DocumentBuilder.StartTable
+ //ExFor:DocumentBuilder.EndRow
+ //ExFor:DocumentBuilder.EndTable
+ //ExFor:DocumentBuilder.CellFormat
+ //ExFor:DocumentBuilder.RowFormat
+ //ExFor:DocumentBuilder.Write(String)
+ //ExFor:DocumentBuilder.Writeln(String)
+ //ExFor:CellVerticalAlignment
+ //ExFor:CellFormat.Orientation
+ //ExFor:TextOrientation
+ //ExFor:AutoFitBehavior
+ //ExSummary:Shows how to build a formatted 2x2 table.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Table table = builder.startTable();
+ builder.insertCell();
+ builder.getCellFormat().setVerticalAlignment(CellVerticalAlignment.CENTER);
+ builder.write("Row 1, cell 1.");
+ builder.insertCell();
+ builder.write("Row 1, cell 2.");
+ builder.endRow();
+
+ // While building the table, the document builder will apply its current RowFormat/CellFormat property values
+ // to the current row/cell that its cursor is in and any new rows/cells as it creates them.
+ Assert.assertEquals(CellVerticalAlignment.CENTER, table.getRows().get(0).getCells().get(0).getCellFormat().getVerticalAlignment());
+ Assert.assertEquals(CellVerticalAlignment.CENTER, table.getRows().get(0).getCells().get(1).getCellFormat().getVerticalAlignment());
+
+ builder.insertCell();
+ builder.getRowFormat().setHeight(100.0);
+ builder.getRowFormat().setHeightRule(HeightRule.EXACTLY);
+ builder.getCellFormat().setOrientation(TextOrientation.UPWARD);
+ builder.write("Row 2, cell 1.");
+ builder.insertCell();
+ builder.getCellFormat().setOrientation(TextOrientation.DOWNWARD);
+ builder.write("Row 2, cell 2.");
+ builder.endRow();
+ builder.endTable();
+
+ // Previously added rows and cells are not retroactively affected by changes to the builder's formatting.
+ Assert.assertEquals(0.0, table.getRows().get(0).getRowFormat().getHeight());
+ Assert.assertEquals(HeightRule.AUTO, table.getRows().get(0).getRowFormat().getHeightRule());
+ Assert.assertEquals(100.0, table.getRows().get(1).getRowFormat().getHeight());
+ Assert.assertEquals(HeightRule.EXACTLY, table.getRows().get(1).getRowFormat().getHeightRule());
+ Assert.assertEquals(TextOrientation.UPWARD, table.getRows().get(1).getCells().get(0).getCellFormat().getOrientation());
+ Assert.assertEquals(TextOrientation.DOWNWARD, table.getRows().get(1).getCells().get(1).getCellFormat().getOrientation());
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.BuildTable.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.BuildTable.docx");
+ table = doc.getFirstSection().getBody().getTables().get(0);
+
+ Assert.assertEquals(2, table.getRows().getCount());
+ Assert.assertEquals(2, table.getRows().get(0).getCells().getCount());
+ Assert.assertEquals(2, table.getRows().get(1).getCells().getCount());
+
+ Assert.assertEquals(0.0, table.getRows().get(0).getRowFormat().getHeight());
+ Assert.assertEquals(HeightRule.AUTO, table.getRows().get(0).getRowFormat().getHeightRule());
+ Assert.assertEquals(100.0, table.getRows().get(1).getRowFormat().getHeight());
+ Assert.assertEquals(HeightRule.EXACTLY, table.getRows().get(1).getRowFormat().getHeightRule());
+
+ Assert.assertEquals("Row 1, cell 1.", table.getRows().get(0).getCells().get(0).getText().trim());
+ Assert.assertEquals(CellVerticalAlignment.CENTER, table.getRows().get(0).getCells().get(0).getCellFormat().getVerticalAlignment());
+
+ Assert.assertEquals("Row 1, cell 2.", table.getRows().get(0).getCells().get(1).getText().trim());
+
+ Assert.assertEquals("Row 2, cell 1.", table.getRows().get(1).getCells().get(0).getText().trim());
+ Assert.assertEquals(TextOrientation.UPWARD, table.getRows().get(1).getCells().get(0).getCellFormat().getOrientation());
+
+ Assert.assertEquals("Row 2, cell 2.", table.getRows().get(1).getCells().get(1).getText().trim());
+ Assert.assertEquals(TextOrientation.DOWNWARD, table.getRows().get(1).getCells().get(1).getCellFormat().getOrientation());
+ }
+
+ @Test
+ public void tableCellVerticalRotatedFarEastTextOrientation() throws Exception {
+ Document doc = new Document(getMyDir() + "Rotated cell text.docx");
+
+ Table table = doc.getFirstSection().getBody().getTables().get(0);
+ Cell cell = table.getFirstRow().getFirstCell();
+
+ Assert.assertEquals(cell.getCellFormat().getOrientation(), TextOrientation.VERTICAL_ROTATED_FAR_EAST);
+
+ doc = DocumentHelper.saveOpen(doc);
+
+ table = (Table) doc.getChild(NodeType.TABLE, 0, true);
+ cell = table.getFirstRow().getFirstCell();
+
+ Assert.assertEquals(cell.getCellFormat().getOrientation(), TextOrientation.VERTICAL_ROTATED_FAR_EAST);
+ }
+
+ @Test
+ public void insertFloatingImage() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertImage(String, RelativeHorizontalPosition, Double, RelativeVerticalPosition, Double, Double, Double, WrapType)
+ //ExSummary:Shows how to insert an image.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // There are two ways of using a document builder to source an image and then insert it as a floating shape.
+ // 1 - From a file in the local file system:
+ builder.insertImage(getImageDir() + "Transparent background logo.png", RelativeHorizontalPosition.MARGIN, 100.0,
+ RelativeVerticalPosition.MARGIN, 0.0, 200.0, 200.0, WrapType.SQUARE);
+
+ // 2 - From a URL:
+ builder.insertImage(getAsposelogoUri().toString(), RelativeHorizontalPosition.MARGIN, 100.0,
+ RelativeVerticalPosition.MARGIN, 250.0, 200.0, 200.0, WrapType.SQUARE);
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertFloatingImage.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertFloatingImage.docx");
+ Shape image = (Shape) doc.getChild(NodeType.SHAPE, 0, true);
+
+ TestUtil.verifyImageInShape(400, 400, ImageType.PNG, image);
+ Assert.assertEquals(100.0d, image.getLeft());
+ Assert.assertEquals(0.0d, image.getTop());
+ Assert.assertEquals(200.0d, image.getWidth());
+ Assert.assertEquals(200.0d, image.getHeight());
+ Assert.assertEquals(WrapType.SQUARE, image.getWrapType());
+ Assert.assertEquals(RelativeHorizontalPosition.MARGIN, image.getRelativeHorizontalPosition());
+ Assert.assertEquals(RelativeVerticalPosition.MARGIN, image.getRelativeVerticalPosition());
+
+ image = (Shape) doc.getChild(NodeType.SHAPE, 1, true);
+
+ TestUtil.verifyImageInShape(272, 92, ImageType.PNG, image);
+ Assert.assertEquals(100.0d, image.getLeft());
+ Assert.assertEquals(250.0d, image.getTop());
+ Assert.assertEquals(200.0d, image.getWidth());
+ Assert.assertEquals(200.0d, image.getHeight());
+ Assert.assertEquals(WrapType.SQUARE, image.getWrapType());
+ Assert.assertEquals(RelativeHorizontalPosition.MARGIN, image.getRelativeHorizontalPosition());
+ Assert.assertEquals(RelativeVerticalPosition.MARGIN, image.getRelativeVerticalPosition());
+ }
+
+ @Test
+ public void insertImageOriginalSize() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertImage(String, RelativeHorizontalPosition, Double, RelativeVerticalPosition, Double, Double, Double, WrapType)
+ //ExSummary:Shows how to insert an image from the local file system into a document while preserving its dimensions.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // The InsertImage method creates a floating shape with the passed image in its image data.
+ // We can specify the dimensions of the shape can be passing them to this method.
+ Shape imageShape = builder.insertImage(getImageDir() + "Logo.jpg", RelativeHorizontalPosition.MARGIN, 0.0,
+ RelativeVerticalPosition.MARGIN, 0.0, -1, -1, WrapType.SQUARE);
+
+ // Passing negative values as the intended dimensions will automatically define
+ // the shape's dimensions based on the dimensions of its image.
+ Assert.assertEquals(300.0d, imageShape.getWidth());
+ Assert.assertEquals(300.0d, imageShape.getHeight());
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertImageOriginalSize.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertImageOriginalSize.docx");
+ imageShape = (Shape) doc.getChild(NodeType.SHAPE, 0, true);
+
+ TestUtil.verifyImageInShape(400, 400, ImageType.JPEG, imageShape);
+ Assert.assertEquals(0.0d, imageShape.getLeft());
+ Assert.assertEquals(0.0d, imageShape.getTop());
+ Assert.assertEquals(300.0d, imageShape.getWidth());
+ Assert.assertEquals(300.0d, imageShape.getHeight());
+ Assert.assertEquals(WrapType.SQUARE, imageShape.getWrapType());
+ Assert.assertEquals(RelativeHorizontalPosition.MARGIN, imageShape.getRelativeHorizontalPosition());
+ Assert.assertEquals(RelativeVerticalPosition.MARGIN, imageShape.getRelativeVerticalPosition());
+ }
+
+ @Test
+ public void insertTextInput() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertTextInput
+ //ExSummary:Shows how to insert a text input form field into a document.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert a form that prompts the user to enter text.
+ builder.insertTextInput("TextInput", TextFormFieldType.REGULAR, "", "Enter your text here", 0);
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertTextInput.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertTextInput.docx");
+ FormField formField = doc.getRange().getFormFields().get(0);
+
+ Assert.assertTrue(formField.getEnabled());
+ Assert.assertEquals("TextInput", formField.getName());
+ Assert.assertEquals(0, formField.getMaxLength());
+ Assert.assertEquals("Enter your text here", formField.getResult());
+ Assert.assertEquals(FieldType.FIELD_FORM_TEXT_INPUT, formField.getType());
+ Assert.assertEquals("", formField.getTextInputFormat());
+ Assert.assertEquals(TextFormFieldType.REGULAR, formField.getTextInputType());
+ }
+
+ @Test
+ public void insertComboBox() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertComboBox
+ //ExSummary:Shows how to insert a combo box form field into a document.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert a form that prompts the user to pick one of the items from the menu.
+ builder.write("Pick a fruit: ");
+ String[] items = {"Apple", "Banana", "Cherry"};
+ builder.insertComboBox("DropDown", items, 0);
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertComboBox.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertComboBox.docx");
+ FormField formField = doc.getRange().getFormFields().get(0);
+
+ Assert.assertTrue(formField.getEnabled());
+ Assert.assertEquals("DropDown", formField.getName());
+ Assert.assertEquals(0, formField.getDropDownSelectedIndex());
+ Assert.assertEquals(items.length, formField.getDropDownItems().getCount());
+ Assert.assertEquals(FieldType.FIELD_FORM_DROP_DOWN, formField.getType());
+ }
+
+ @Test(description = "WORDSNET-16868, WORDSJAVA-2406", enabled = false)
+ public void signatureLineProviderId() throws Exception {
+ //ExStart
+ //ExFor:SignatureLine.IsSigned
+ //ExFor:SignatureLine.IsValid
+ //ExFor:SignatureLine.ProviderId
+ //ExFor:SignatureLineOptions
+ //ExFor:SignatureLineOptions.ShowDate
+ //ExFor:SignatureLineOptions.Email
+ //ExFor:SignatureLineOptions.DefaultInstructions
+ //ExFor:SignatureLineOptions.Instructions
+ //ExFor:SignatureLineOptions.AllowComments
+ //ExFor:DocumentBuilder.InsertSignatureLine(SignatureLineOptions)
+ //ExFor:SignOptions.ProviderId
+ //ExSummary:Shows how to sign a document with a personal certificate and a signature line.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ SignatureLineOptions signatureLineOptions = new SignatureLineOptions();
+ signatureLineOptions.setSigner("vderyushev");
+ signatureLineOptions.setSignerTitle("QA");
+ signatureLineOptions.setEmail("vderyushev@aspose.com");
+ signatureLineOptions.setShowDate(true);
+ signatureLineOptions.setDefaultInstructions(false);
+ signatureLineOptions.setInstructions("Please sign here.");
+ signatureLineOptions.setAllowComments(true);
+
+ SignatureLine signatureLine = builder.insertSignatureLine(signatureLineOptions).getSignatureLine();
+ signatureLine.setProviderId(UUID.fromString("CF5A7BB4-8F3C-4756-9DF6-BEF7F13259A2"));
+
+ Assert.assertFalse(signatureLine.isSigned());
+ Assert.assertFalse(signatureLine.isValid());
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.SignatureLineProviderId.docx");
+
+ Date currentDate = new Date();
+
+ SignOptions signOptions = new SignOptions();
+ signOptions.setSignatureLineId(signatureLine.getId());
+ signOptions.setProviderId(signatureLine.getProviderId());
+ signOptions.setComments("Document was signed by vderyushev");
+ signOptions.setSignTime(currentDate);
+
+ CertificateHolder certHolder = CertificateHolder.create(getMyDir() + "morzal.pfx", "aw");
+
+ DigitalSignatureUtil.sign(getArtifactsDir() + "DocumentBuilder.SignatureLineProviderId.docx",
+ getArtifactsDir() + "DocumentBuilder.SignatureLineProviderId.Signed.docx", certHolder, signOptions);
+
+ // Re-open our saved document, and verify that the "IsSigned" and "IsValid" properties both equal "true",
+ // indicating that the signature line contains a signature.
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.SignatureLineProviderId.Signed.docx");
+ Shape shape = (Shape) doc.getChild(NodeType.SHAPE, 0, true);
+ signatureLine = shape.getSignatureLine();
+
+ Assert.assertTrue(signatureLine.isSigned());
+ Assert.assertTrue(signatureLine.isValid());
+ //ExEnd
+
+ Assert.assertEquals("vderyushev", signatureLine.getSigner());
+ Assert.assertEquals("QA", signatureLine.getSignerTitle());
+ Assert.assertEquals("vderyushev@aspose.com", signatureLine.getEmail());
+ Assert.assertTrue(signatureLine.getShowDate());
+ Assert.assertFalse(signatureLine.getDefaultInstructions());
+ Assert.assertEquals("Please sign here.", signatureLine.getInstructions());
+ Assert.assertTrue(signatureLine.getAllowComments());
+ Assert.assertTrue(signatureLine.isSigned());
+ Assert.assertTrue(signatureLine.isValid());
+
+ DigitalSignatureCollection signatures = DigitalSignatureUtil.loadSignatures(
+ getArtifactsDir() + "DocumentBuilder.SignatureLineProviderId.Signed.docx");
+
+ Assert.assertEquals(1, signatures.getCount());
+ Assert.assertTrue(signatures.get(0).isValid());
+ Assert.assertEquals("Document was signed by vderyushev", signatures.get(0).getComments());
+ Assert.assertEquals(currentDate, signatures.get(0).getSignTime());
+ Assert.assertEquals("CN=Morzal.Me", signatures.get(0).getIssuerName());
+ Assert.assertEquals(DigitalSignatureType.XML_DSIG, signatures.get(0).getSignatureType());
+ }
+
+ @Test
+ public void signatureLineInline() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertSignatureLine(SignatureLineOptions, RelativeHorizontalPosition, Double, RelativeVerticalPosition, Double, WrapType)
+ //ExSummary:Shows how to insert an inline signature line into a document.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ SignatureLineOptions options = new SignatureLineOptions();
+ options.setSigner("John Doe");
+ options.setSignerTitle("Manager");
+ options.setEmail("johndoe@aspose.com");
+ options.setShowDate(true);
+ options.setDefaultInstructions(false);
+ options.setInstructions("Please sign here.");
+ options.setAllowComments(true);
+
+ builder.insertSignatureLine(options, RelativeHorizontalPosition.RIGHT_MARGIN, 2.0,
+ RelativeVerticalPosition.PAGE, 3.0, WrapType.INLINE);
+
+ // The signature line can be signed in Microsoft Word by double clicking it.
+ doc.save(getArtifactsDir() + "DocumentBuilder.SignatureLineInline.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.SignatureLineInline.docx");
+
+ Shape shape = (Shape) doc.getChild(NodeType.SHAPE, 0, true);
+ SignatureLine signatureLine = shape.getSignatureLine();
+
+ Assert.assertEquals(signatureLine.getSigner(), "John Doe");
+ Assert.assertEquals(signatureLine.getSignerTitle(), "Manager");
+ Assert.assertEquals(signatureLine.getEmail(), "johndoe@aspose.com");
+ Assert.assertEquals(signatureLine.getShowDate(), true);
+ Assert.assertEquals(signatureLine.getDefaultInstructions(), false);
+ Assert.assertEquals(signatureLine.getInstructions(), "Please sign here.");
+ Assert.assertEquals(signatureLine.getAllowComments(), true);
+ Assert.assertEquals(signatureLine.isSigned(), false);
+ Assert.assertEquals(signatureLine.isValid(), false);
+ }
+
+ @Test
+ public void setParagraphFormatting() throws Exception {
+ //ExStart
+ //ExFor:ParagraphFormat.RightIndent
+ //ExFor:ParagraphFormat.LeftIndent
+ //ExSummary:Shows how to configure paragraph formatting to create off-center text.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Center all text that the document builder writes, and set up indents.
+ // The indent configuration below will create a body of text that will sit asymmetrically on the page.
+ // The "center" that we align the text to will be the middle of the body of text, not the middle of the page.
+ ParagraphFormat paragraphFormat = builder.getParagraphFormat();
+ paragraphFormat.setAlignment(ParagraphAlignment.CENTER);
+ paragraphFormat.setLeftIndent(100.0);
+ paragraphFormat.setRightIndent(50.0);
+ paragraphFormat.setSpaceAfter(25.0);
+
+ builder.writeln(
+ "This paragraph demonstrates how left and right indentation affects word wrapping.");
+ builder.writeln(
+ "The space between the above paragraph and this one depends on the DocumentBuilder's paragraph format.");
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.SetParagraphFormatting.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.SetParagraphFormatting.docx");
+
+ for (Paragraph paragraph : doc.getFirstSection().getBody().getParagraphs()) {
+ Assert.assertEquals(ParagraphAlignment.CENTER, paragraph.getParagraphFormat().getAlignment());
+ Assert.assertEquals(100.0d, paragraph.getParagraphFormat().getLeftIndent());
+ Assert.assertEquals(50.0d, paragraph.getParagraphFormat().getRightIndent());
+ Assert.assertEquals(25.0d, paragraph.getParagraphFormat().getSpaceAfter());
+ }
+ }
+
+ @Test
+ public void setCellFormatting() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.CellFormat
+ //ExFor:CellFormat.Width
+ //ExFor:CellFormat.LeftPadding
+ //ExFor:CellFormat.RightPadding
+ //ExFor:CellFormat.TopPadding
+ //ExFor:CellFormat.BottomPadding
+ //ExFor:DocumentBuilder.StartTable
+ //ExFor:DocumentBuilder.EndTable
+ //ExSummary:Shows how to format cells with a document builder.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Table table = builder.startTable();
+ builder.insertCell();
+ builder.write("Row 1, cell 1.");
+
+ // Insert a second cell, and then configure cell text padding options.
+ // The builder will apply these settings at its current cell, and any new cells creates afterwards.
+ builder.insertCell();
+
+ CellFormat cellFormat = builder.getCellFormat();
+ cellFormat.setWidth(250.0);
+ cellFormat.setLeftPadding(30.0);
+ cellFormat.setRightPadding(30.0);
+ cellFormat.setTopPadding(30.0);
+ cellFormat.setBottomPadding(30.0);
+
+ builder.write("Row 1, cell 2.");
+ builder.endRow();
+ builder.endTable();
+
+ // The first cell was unaffected by the padding reconfiguration, and still holds the default values.
+ Assert.assertEquals(0.0d, table.getFirstRow().getCells().get(0).getCellFormat().getWidth());
+ Assert.assertEquals(5.4d, table.getFirstRow().getCells().get(0).getCellFormat().getLeftPadding());
+ Assert.assertEquals(5.4d, table.getFirstRow().getCells().get(0).getCellFormat().getRightPadding());
+ Assert.assertEquals(0.0d, table.getFirstRow().getCells().get(0).getCellFormat().getTopPadding());
+ Assert.assertEquals(0.0d, table.getFirstRow().getCells().get(0).getCellFormat().getBottomPadding());
+
+ Assert.assertEquals(250.0d, table.getFirstRow().getCells().get(1).getCellFormat().getWidth());
+ Assert.assertEquals(30.0d, table.getFirstRow().getCells().get(1).getCellFormat().getLeftPadding());
+ Assert.assertEquals(30.0d, table.getFirstRow().getCells().get(1).getCellFormat().getRightPadding());
+ Assert.assertEquals(30.0d, table.getFirstRow().getCells().get(1).getCellFormat().getTopPadding());
+ Assert.assertEquals(30.0d, table.getFirstRow().getCells().get(1).getCellFormat().getBottomPadding());
+
+ // The first cell will still grow in the output document to match the size of its neighboring cell.
+ doc.save(getArtifactsDir() + "DocumentBuilder.SetCellFormatting.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.SetCellFormatting.docx");
+ table = doc.getFirstSection().getBody().getTables().get(0);
+
+ Assert.assertEquals(157.0d, table.getFirstRow().getCells().get(0).getCellFormat().getWidth());
+ Assert.assertEquals(5.4d, table.getFirstRow().getCells().get(0).getCellFormat().getLeftPadding());
+ Assert.assertEquals(5.4d, table.getFirstRow().getCells().get(0).getCellFormat().getRightPadding());
+ Assert.assertEquals(0.0d, table.getFirstRow().getCells().get(0).getCellFormat().getTopPadding());
+ Assert.assertEquals(0.0d, table.getFirstRow().getCells().get(0).getCellFormat().getBottomPadding());
+
+ Assert.assertEquals(310.0d, table.getFirstRow().getCells().get(1).getCellFormat().getWidth());
+ Assert.assertEquals(30.0d, table.getFirstRow().getCells().get(1).getCellFormat().getLeftPadding());
+ Assert.assertEquals(30.0d, table.getFirstRow().getCells().get(1).getCellFormat().getRightPadding());
+ Assert.assertEquals(30.0d, table.getFirstRow().getCells().get(1).getCellFormat().getTopPadding());
+ Assert.assertEquals(30.0d, table.getFirstRow().getCells().get(1).getCellFormat().getBottomPadding());
+ }
+
+ @Test
+ public void setRowFormatting() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.RowFormat
+ //ExFor:HeightRule
+ //ExFor:RowFormat.Height
+ //ExFor:RowFormat.HeightRule
+ //ExSummary:Shows how to format rows with a document builder.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Table table = builder.startTable();
+ builder.insertCell();
+ builder.write("Row 1, cell 1.");
+
+ // Start a second row, and then configure its height. The builder will apply these settings to
+ // its current row, as well as any new rows it creates afterwards.
+ builder.endRow();
+
+ RowFormat rowFormat = builder.getRowFormat();
+ rowFormat.setHeight(100.0);
+ rowFormat.setHeightRule(HeightRule.EXACTLY);
+
+ builder.insertCell();
+ builder.write("Row 2, cell 1.");
+ builder.endTable();
+
+ // The first row was unaffected by the padding reconfiguration and still holds the default values.
+ Assert.assertEquals(0.0d, table.getRows().get(0).getRowFormat().getHeight());
+ Assert.assertEquals(HeightRule.AUTO, table.getRows().get(0).getRowFormat().getHeightRule());
+
+ Assert.assertEquals(100.0d, table.getRows().get(1).getRowFormat().getHeight());
+ Assert.assertEquals(HeightRule.EXACTLY, table.getRows().get(1).getRowFormat().getHeightRule());
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.SetRowFormatting.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.SetRowFormatting.docx");
+ table = doc.getFirstSection().getBody().getTables().get(0);
+
+ Assert.assertEquals(0.0d, table.getRows().get(0).getRowFormat().getHeight());
+ Assert.assertEquals(HeightRule.AUTO, table.getRows().get(0).getRowFormat().getHeightRule());
+
+ Assert.assertEquals(100.0d, table.getRows().get(1).getRowFormat().getHeight());
+ Assert.assertEquals(HeightRule.EXACTLY, table.getRows().get(1).getRowFormat().getHeightRule());
+ }
+
+ @Test
+ public void insertFootnote() throws Exception {
+ //ExStart
+ //ExFor:FootnoteType
+ //ExFor:DocumentBuilder.InsertFootnote(FootnoteType,String)
+ //ExFor:DocumentBuilder.InsertFootnote(FootnoteType,String,String)
+ //ExSummary:Shows how to reference text with a footnote and an endnote.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert some text and mark it with a footnote with the IsAuto property set to "true" by default,
+ // so the marker seen in the body text will be auto-numbered at "1",
+ // and the footnote will appear at the bottom of the page.
+ builder.write("This text will be referenced by a footnote.");
+ builder.insertFootnote(FootnoteType.FOOTNOTE, "Footnote comment regarding referenced text.");
+
+ // Insert more text and mark it with an endnote with a custom reference mark,
+ // which will be used in place of the number "2" and set "IsAuto" to false.
+ builder.write("This text will be referenced by an endnote.");
+ builder.insertFootnote(FootnoteType.ENDNOTE, "Endnote comment regarding referenced text.", "CustomMark");
+
+ // Footnotes always appear at the bottom of their referenced text,
+ // so this page break will not affect the footnote.
+ // On the other hand, endnotes are always at the end of the document
+ // so that this page break will push the endnote down to the next page.
+ builder.insertBreak(BreakType.PAGE_BREAK);
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertFootnote.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertFootnote.docx");
+
+ TestUtil.verifyFootnote(FootnoteType.FOOTNOTE, true, "",
+ "Footnote comment regarding referenced text.", (Footnote) doc.getChild(NodeType.FOOTNOTE, 0, true));
+ TestUtil.verifyFootnote(FootnoteType.ENDNOTE, false, "CustomMark",
+ "CustomMark Endnote comment regarding referenced text.", (Footnote) doc.getChild(NodeType.FOOTNOTE, 1, true));
+ }
+
+ @Test
+ public void applyBordersAndShading() throws Exception {
+ //ExStart
+ //ExFor:BorderCollection.Item(BorderType)
+ //ExFor:Shading
+ //ExFor:TextureIndex
+ //ExFor:ParagraphFormat.Shading
+ //ExFor:Shading.Texture
+ //ExFor:Shading.BackgroundPatternColor
+ //ExFor:Shading.ForegroundPatternColor
+ //ExSummary:Shows how to decorate text with borders and shading.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ BorderCollection borders = builder.getParagraphFormat().getBorders();
+ borders.setDistanceFromText(20.0);
+ borders.getByBorderType(BorderType.LEFT).setLineStyle(LineStyle.DOUBLE);
+ borders.getByBorderType(BorderType.RIGHT).setLineStyle(LineStyle.DOUBLE);
+ borders.getByBorderType(BorderType.TOP).setLineStyle(LineStyle.DOUBLE);
+ borders.getByBorderType(BorderType.BOTTOM).setLineStyle(LineStyle.DOUBLE);
+
+ Shading shading = builder.getParagraphFormat().getShading();
+ shading.setTexture(TextureIndex.TEXTURE_DIAGONAL_CROSS);
+ shading.setBackgroundPatternColor(new Color(240, 128, 128)); // Light Coral
+ shading.setForegroundPatternColor(new Color(255, 160, 122)); // Light Salmon
+
+ builder.write("This paragraph is formatted with a double border and shading.");
+ doc.save(getArtifactsDir() + "DocumentBuilder.ApplyBordersAndShading.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.ApplyBordersAndShading.docx");
+ borders = doc.getFirstSection().getBody().getFirstParagraph().getParagraphFormat().getBorders();
+
+ Assert.assertEquals(20.0d, borders.getDistanceFromText());
+ Assert.assertEquals(LineStyle.DOUBLE, borders.getByBorderType(BorderType.LEFT).getLineStyle());
+ Assert.assertEquals(LineStyle.DOUBLE, borders.getByBorderType(BorderType.RIGHT).getLineStyle());
+ Assert.assertEquals(LineStyle.DOUBLE, borders.getByBorderType(BorderType.TOP).getLineStyle());
+ Assert.assertEquals(LineStyle.DOUBLE, borders.getByBorderType(BorderType.BOTTOM).getLineStyle());
+
+ Assert.assertEquals(TextureIndex.TEXTURE_DIAGONAL_CROSS, shading.getTexture());
+ Assert.assertEquals(Color.decode("#f08080").getRGB(), shading.getBackgroundPatternColor().getRGB());
+ Assert.assertEquals(Color.decode("#ffa07a").getRGB(), shading.getForegroundPatternColor().getRGB());
+ }
+
+ @Test
+ public void deleteRow() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.DeleteRow
+ //ExSummary:Shows how to delete a row from a table.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Table table = builder.startTable();
+ builder.insertCell();
+ builder.write("Row 1, cell 1.");
+ builder.insertCell();
+ builder.write("Row 1, cell 2.");
+ builder.endRow();
+ builder.insertCell();
+ builder.write("Row 2, cell 1.");
+ builder.insertCell();
+ builder.write("Row 2, cell 2.");
+ builder.endTable();
+
+ Assert.assertEquals(2, table.getRows().getCount());
+
+ // Delete the first row of the first table in the document.
+ builder.deleteRow(0, 0);
+
+ Assert.assertEquals(1, table.getRows().getCount());
+ Assert.assertEquals("Row 2, cell 1.\u0007Row 2, cell 2.", table.getText().trim());
+ //ExEnd
+ }
+
+ @Test (dataProvider = "appendDocumentAndResolveStylesDataProvider")
+ public void appendDocumentAndResolveStyles(boolean keepSourceNumbering) throws Exception
+ {
+ //ExStart
+ //ExFor:Document.AppendDocument(Document, ImportFormatMode, ImportFormatOptions)
+ //ExSummary:Shows how to manage list style clashes while appending a document.
+ // Load a document with text in a custom style and clone it.
+ Document srcDoc = new Document(getMyDir() + "Custom list numbering.docx");
+ Document dstDoc = srcDoc.deepClone();
+
+ // We now have two documents, each with an identical style named "CustomStyle".
+ // Change the text color for one of the styles to set it apart from the other.
+ dstDoc.getStyles().get("CustomStyle").getFont().setColor(Color.RED);
+
+ // If there is a clash of list styles, apply the list format of the source document.
+ // Set the "KeepSourceNumbering" property to "false" to not import any list numbers into the destination document.
+ // Set the "KeepSourceNumbering" property to "true" import all clashing
+ // list style numbering with the same appearance that it had in the source document.
+ ImportFormatOptions options = new ImportFormatOptions();
+ options.setKeepSourceNumbering(keepSourceNumbering);
+
+ // Joining two documents that have different styles that share the same name causes a style clash.
+ // We can specify an import format mode while appending documents to resolve this clash.
+ dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_DIFFERENT_STYLES, options);
+ dstDoc.updateListLabels();
+
+ dstDoc.save(getArtifactsDir() + "DocumentBuilder.AppendDocumentAndResolveStyles.docx");
+ //ExEnd
+ }
+
+ @DataProvider(name = "appendDocumentAndResolveStylesDataProvider")
+ public static Object[][] appendDocumentAndResolveStylesDataProvider() {
+ return new Object[][]
+ {
+ {false},
+ {true},
+ };
+ }
+
+ @Test (dataProvider = "insertDocumentAndResolveStylesDataProvider")
+ public void insertDocumentAndResolveStyles(boolean keepSourceNumbering) throws Exception
+ {
+ //ExStart
+ //ExFor:Document.AppendDocument(Document, ImportFormatMode, ImportFormatOptions)
+ //ExSummary:Shows how to manage list style clashes while inserting a document.
+ Document dstDoc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(dstDoc);
+ builder.insertBreak(BreakType.PARAGRAPH_BREAK);
+
+ dstDoc.getLists().add(ListTemplate.NUMBER_DEFAULT);
+ List list = dstDoc.getLists().get(0);
+
+ builder.getListFormat().setList(list);
+
+ for (int i = 1; i <= 15; i++)
+ builder.write(MessageFormat.format("List Item {0}\n", i));
+
+ Document attachDoc = (Document)dstDoc.deepClone(true);
+
+ // If there is a clash of list styles, apply the list format of the source document.
+ // Set the "KeepSourceNumbering" property to "false" to not import any list numbers into the destination document.
+ // Set the "KeepSourceNumbering" property to "true" import all clashing
+ // list style numbering with the same appearance that it had in the source document.
+ ImportFormatOptions importOptions = new ImportFormatOptions();
+ importOptions.setKeepSourceNumbering(keepSourceNumbering);
+
+ builder.insertBreak(BreakType.SECTION_BREAK_NEW_PAGE);
+ builder.insertDocument(attachDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING, importOptions);
+
+ dstDoc.save(getArtifactsDir() + "DocumentBuilder.InsertDocumentAndResolveStyles.docx");
+ //ExEnd
+ }
+
+ @DataProvider(name = "insertDocumentAndResolveStylesDataProvider")
+ public static Object[][] insertDocumentAndResolveStylesDataProvider() {
+ return new Object[][]
+ {
+ {false},
+ {true},
+ };
+ }
+
+ @Test (dataProvider = "loadDocumentWithListNumberingDataProvider")
+ public void loadDocumentWithListNumbering(boolean keepSourceNumbering) throws Exception
+ {
+ //ExStart
+ //ExFor:Document.AppendDocument(Document, ImportFormatMode, ImportFormatOptions)
+ //ExSummary:Shows how to manage list style clashes while appending a clone of a document to itself.
+ Document srcDoc = new Document(getMyDir() + "List item.docx");
+ Document dstDoc = new Document(getMyDir() + "List item.docx");
+
+ // If there is a clash of list styles, apply the list format of the source document.
+ // Set the "KeepSourceNumbering" property to "false" to not import any list numbers into the destination document.
+ // Set the "KeepSourceNumbering" property to "true" import all clashing
+ // list style numbering with the same appearance that it had in the source document.
+ DocumentBuilder builder = new DocumentBuilder(dstDoc);
+ builder.moveToDocumentEnd();
+ builder.insertBreak(BreakType.SECTION_BREAK_NEW_PAGE);
+
+ ImportFormatOptions options = new ImportFormatOptions();
+ options.setKeepSourceNumbering(keepSourceNumbering);
+ builder.insertDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING, options);
+
+ dstDoc.updateListLabels();
+ //ExEnd
+ }
+
+ @DataProvider(name = "loadDocumentWithListNumberingDataProvider")
+ public static Object[][] loadDocumentWithListNumberingDataProvider() {
+ return new Object[][]
+ {
+ {false},
+ {true},
+ };
+ }
+
+ @Test (dataProvider = "ignoreTextBoxesDataProvider")
+ public void ignoreTextBoxes(boolean ignoreTextBoxes) throws Exception
+ {
+ //ExStart
+ //ExFor:ImportFormatOptions.IgnoreTextBoxes
+ //ExSummary:Shows how to manage text box formatting while appending a document.
+ // Create a document that will have nodes from another document inserted into it.
+ Document dstDoc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(dstDoc);
+
+ builder.writeln("Hello world!");
+
+ // Create another document with a text box, which we will import into the first document.
+ Document srcDoc = new Document();
+ builder = new DocumentBuilder(srcDoc);
+
+ Shape textBox = builder.insertShape(ShapeType.TEXT_BOX, 300.0, 100.0);
+ builder.moveTo(textBox.getFirstParagraph());
+ builder.getParagraphFormat().getStyle().getFont().setName("Courier New");
+ builder.getParagraphFormat().getStyle().getFont().setSize(24.0);
+ builder.write("Textbox contents");
+
+ // Set a flag to specify whether to clear or preserve text box formatting
+ // while importing them to other documents.
+ ImportFormatOptions importFormatOptions = new ImportFormatOptions();
+ importFormatOptions.setIgnoreTextBoxes(ignoreTextBoxes);
+
+ // Import the text box from the source document into the destination document,
+ // and then verify whether we have preserved the styling of its text contents.
+ NodeImporter importer = new NodeImporter(srcDoc, dstDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING, importFormatOptions);
+ Shape importedTextBox = (Shape) importer.importNode(textBox, true);
+ dstDoc.getFirstSection().getBody().getParagraphs().get(1).appendChild(importedTextBox);
+
+ if (ignoreTextBoxes) {
+ Assert.assertEquals(12.0d, importedTextBox.getFirstParagraph().getRuns().get(0).getFont().getSize());
+ Assert.assertEquals("Times New Roman", importedTextBox.getFirstParagraph().getRuns().get(0).getFont().getName());
+ } else {
+ Assert.assertEquals(24.0d, importedTextBox.getFirstParagraph().getRuns().get(0).getFont().getSize());
+ Assert.assertEquals("Courier New", importedTextBox.getFirstParagraph().getRuns().get(0).getFont().getName());
+ }
+
+ dstDoc.save(getArtifactsDir() + "DocumentBuilder.IgnoreTextBoxes.docx");
+ //ExEnd
+ }
+
+ @DataProvider(name = "ignoreTextBoxesDataProvider")
+ public static Object[][] ignoreTextBoxesDataProvider() {
+ return new Object[][]
+ {
+ {true},
+ {false},
+ };
+ }
+
+ @Test(dataProvider = "moveToFieldDataProvider")
+ public void moveToField(boolean moveCursorToAfterTheField) throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.MoveToField
+ //ExSummary:Shows how to move a document builder's node insertion point cursor to a specific field.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert a field using the DocumentBuilder and add a run of text after it.
+ Field field = builder.insertField(" AUTHOR \"John Doe\" ");
+
+ // The builder's cursor is currently at end of the document.
+ Assert.assertNull(builder.getCurrentNode());
+
+ // Move the cursor to the field while specifying whether to place that cursor before or after the field.
+ builder.moveToField(field, moveCursorToAfterTheField);
+
+ // Note that the cursor is outside of the field in both cases.
+ // This means that we cannot edit the field using the builder like this.
+ // To edit a field, we can use the builder's MoveTo method on a field's FieldStart
+ // or FieldSeparator node to place the cursor inside.
+ if (moveCursorToAfterTheField) {
+ Assert.assertNull(builder.getCurrentNode());
+ builder.write(" Text immediately after the field.");
+
+ Assert.assertEquals("AUTHOR \"John Doe\" \u0014John Doe\u0015 Text immediately after the field.",
+ doc.getText().trim());
+ } else {
+ Assert.assertEquals(field.getStart(), builder.getCurrentNode());
+ builder.write("Text immediately before the field. ");
+
+ Assert.assertEquals("Text immediately before the field. \u0013 AUTHOR \"John Doe\" \u0014John Doe",
+ doc.getText().trim());
+ }
+ //ExEnd
+ }
+
+ @DataProvider(name = "moveToFieldDataProvider")
+ public static Object[][] moveToFieldDataProvider() {
+ return new Object[][]
+ {
+ {false},
+ {true},
+ };
+ }
+
+ @Test
+ public void insertOleObjectException() throws Exception {
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Assert.assertThrows(RuntimeException.class, () -> builder.insertOleObject("", "checkbox", false, true, null));
+ }
+
+ @Test
+ public void insertPieChart() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertChart(ChartType, Double, Double)
+ //ExSummary:Shows how to insert a pie chart into a document.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Chart chart = builder.insertChart(ChartType.PIE, ConvertUtil.pixelToPoint(300.0),
+ ConvertUtil.pixelToPoint(300.0)).getChart();
+ Assert.assertEquals(225.0d, ConvertUtil.pixelToPoint(300.0)); //ExSkip
+ chart.getSeries().clear();
+ chart.getSeries().add("My fruit",
+ new String[]{"Apples", "Bananas", "Cherries"},
+ new double[]{1.3, 2.2, 1.5});
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertPieChart.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertPieChart.docx");
+ Shape chartShape = (Shape) doc.getChild(NodeType.SHAPE, 0, true);
+
+ Assert.assertEquals("Chart Title", chartShape.getChart().getTitle().getText());
+ Assert.assertEquals(225.0d, chartShape.getWidth());
+ Assert.assertEquals(225.0d, chartShape.getHeight());
+ }
+
+ @Test
+ public void insertChartRelativePosition() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertChart(ChartType, RelativeHorizontalPosition, Double, RelativeVerticalPosition, Double, Double, Double, WrapType)
+ //ExSummary:Shows how to specify position and wrapping while inserting a chart.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ builder.insertChart(ChartType.PIE, RelativeHorizontalPosition.MARGIN, 100.0, RelativeVerticalPosition.MARGIN, 100.0, 200.0, 100.0, WrapType.SQUARE);
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertedChartRelativePosition.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertedChartRelativePosition.docx");
+ Shape chartShape = (Shape) doc.getChild(NodeType.SHAPE, 0, true);
+
+ Assert.assertEquals(100.0d, chartShape.getTop());
+ Assert.assertEquals(100.0d, chartShape.getLeft());
+ Assert.assertEquals(200.0d, chartShape.getWidth());
+ Assert.assertEquals(100.0d, chartShape.getHeight());
+ Assert.assertEquals(WrapType.SQUARE, chartShape.getWrapType());
+ Assert.assertEquals(RelativeHorizontalPosition.MARGIN, chartShape.getRelativeHorizontalPosition());
+ Assert.assertEquals(RelativeVerticalPosition.MARGIN, chartShape.getRelativeVerticalPosition());
+ }
+
+ @Test
+ public void insertField() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertField(String)
+ //ExFor:Field
+ //ExFor:Field.Result
+ //ExFor:Field.GetFieldCode
+ //ExFor:Field.Type
+ //ExFor:FieldType
+ //ExSummary:Shows how to insert a field into a document using a field code.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Field dateField = builder.insertField("DATE \\* MERGEFORMAT");
+
+ Assert.assertEquals(FieldType.FIELD_DATE, dateField.getType());
+ Assert.assertEquals("DATE \\* MERGEFORMAT", dateField.getFieldCode());
+ //ExEnd
+ }
+
+ @Test(dataProvider = "insertFieldAndUpdateDataProvider")
+ public void insertFieldAndUpdate(boolean updateInsertedFieldsImmediately) throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertField(FieldType, Boolean)
+ //ExFor:Field.Update
+ //ExSummary:Shows how to insert a field into a document using FieldType.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert two fields while passing a flag which determines whether to update them as the builder inserts them.
+ // In some cases, updating fields could be computationally expensive, and it may be a good idea to defer the update.
+ doc.getBuiltInDocumentProperties().setAuthor("John Doe");
+ builder.write("This document was written by ");
+ builder.insertField(FieldType.FIELD_AUTHOR, updateInsertedFieldsImmediately);
+
+ builder.insertParagraph();
+ builder.write("\nThis is page ");
+ builder.insertField(FieldType.FIELD_PAGE, updateInsertedFieldsImmediately);
+
+ Assert.assertEquals(" AUTHOR ", doc.getRange().getFields().get(0).getFieldCode());
+ Assert.assertEquals(" PAGE ", doc.getRange().getFields().get(1).getFieldCode());
+
+ if (updateInsertedFieldsImmediately) {
+ Assert.assertEquals("John Doe", doc.getRange().getFields().get(0).getResult());
+ Assert.assertEquals("1", doc.getRange().getFields().get(1).getResult());
+ } else {
+ Assert.assertEquals("", doc.getRange().getFields().get(0).getResult());
+ Assert.assertEquals("", doc.getRange().getFields().get(1).getResult());
+
+ // We will need to update these fields using the update methods manually.
+ doc.getRange().getFields().get(0).update();
+
+ Assert.assertEquals("John Doe", doc.getRange().getFields().get(0).getResult());
+
+ doc.updateFields();
+
+ Assert.assertEquals("1", doc.getRange().getFields().get(1).getResult());
+ }
+ //ExEnd
+
+ doc = DocumentHelper.saveOpen(doc);
+
+ Assert.assertEquals("This document was written by \u0013 AUTHOR \u0014John Doe\u0015" +
+ "\r\rThis is page \u0013 PAGE \u00141", doc.getText().trim());
+
+ TestUtil.verifyField(FieldType.FIELD_AUTHOR, " AUTHOR ", "John Doe", doc.getRange().getFields().get(0));
+ TestUtil.verifyField(FieldType.FIELD_PAGE, " PAGE ", "1", doc.getRange().getFields().get(1));
+ }
+
+ @DataProvider(name = "insertFieldAndUpdateDataProvider")
+ public static Object[][] insertFieldAndUpdateDataProvider() throws Exception {
+ return new Object[][]
+ {
+ {false},
+ {true},
+ };
+ }
+
+ //ExStart
+ //ExFor:IFieldResultFormatter
+ //ExFor:IFieldResultFormatter.Format(Double, GeneralFormat)
+ //ExFor:IFieldResultFormatter.Format(String, GeneralFormat)
+ //ExFor:IFieldResultFormatter.FormatDateTime(DateTime, String, CalendarType)
+ //ExFor:IFieldResultFormatter.FormatNumeric(Double, String)
+ //ExFor:FieldOptions.ResultFormatter
+ //ExFor:CalendarType
+ //ExSummary:Shows how to automatically apply a custom format to field results as the fields are updated.
+ @Test //ExSkip
+ public void fieldResultFormatting() throws Exception {
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ FieldResultFormatter formatter = new FieldResultFormatter("$%d", "Date: %tb", "Item # %s:");
+ doc.getFieldOptions().setResultFormatter(formatter);
+
+ // Our field result formatter applies a custom format to newly created fields of three types of formats.
+ // Field result formatters apply new formatting to fields as they are updated,
+ // which happens as soon as we create them using this InsertField method overload.
+ // 1 - Numeric:
+ builder.insertField(" = 2 + 3 \\# $###");
+
+ Assert.assertEquals("$5", doc.getRange().getFields().get(0).getResult());
+ Assert.assertEquals(1, formatter.countFormatInvocations(FieldResultFormatter.FormatInvocationType.NUMERIC));
+
+ // 2 - Date/time:
+ builder.insertField("DATE \\@ \"d MMMM yyyy\"");
+
+ Assert.assertTrue(doc.getRange().getFields().get(1).getResult().startsWith("Date: "));
+ Assert.assertEquals(1, formatter.countFormatInvocations(FieldResultFormatter.FormatInvocationType.DATE_TIME));
+
+ // 3 - General:
+ builder.insertField("QUOTE \"2\" \\* Ordinal");
+
+ Assert.assertEquals("Item # 2:", doc.getRange().getFields().get(2).getResult());
+ Assert.assertEquals(1, formatter.countFormatInvocations(FieldResultFormatter.FormatInvocationType.GENERAL));
+
+ formatter.printFormatInvocations();
+ }
+
+ ///
+ /// When fields with formatting are updated, this formatter will override their formatting
+ /// with a custom format, while tracking every invocation.
+ ///
+ private static class FieldResultFormatter implements IFieldResultFormatter {
+ public FieldResultFormatter(String numberFormat, String dateFormat, String generalFormat) {
+ mNumberFormat = numberFormat;
+ mDateFormat = dateFormat;
+ mGeneralFormat = generalFormat;
+ }
+
+ public String formatNumeric(double value, String format) {
+ if (mNumberFormat.isEmpty())
+ return null;
+
+ String newValue = String.format(mNumberFormat, (long) value);
+ mFormatInvocations.add(new FormatInvocation(FormatInvocationType.NUMERIC, value, format, newValue));
+ return newValue;
+ }
+
+ public String formatDateTime(Date value, String format, int calendarType) {
+ if (mDateFormat.isEmpty())
+ return null;
+
+ String newValue = String.format(mDateFormat, value);
+ mFormatInvocations.add(new FormatInvocation(FormatInvocationType.DATE_TIME, MessageFormat.format("{0} ({1})", value, calendarType), format, newValue));
+ return newValue;
+ }
+
+ public String format(String value, int format) {
+ return format((Object) value, format);
+ }
+
+ public String format(double value, int format) {
+ return format((Object) value, format);
+ }
+
+ private String format(Object value, int format) {
+ if (mGeneralFormat.isEmpty())
+ return null;
+
+ String newValue = String.format(mGeneralFormat, new DecimalFormat("#.####").format(value));
+ mFormatInvocations.add(new FormatInvocation(FormatInvocationType.GENERAL, value, GeneralFormat.toString(format), newValue));
+ return newValue;
+ }
+
+ public int countFormatInvocations(int formatInvocationType) {
+ if (formatInvocationType == FormatInvocationType.ALL)
+ return getFormatInvocations().size();
+
+ return (int) IterableUtils.countMatches(getFormatInvocations(), i -> i.getFormatInvocationType() == formatInvocationType);
+ }
+
+ public void printFormatInvocations() {
+ for (FormatInvocation f : getFormatInvocations())
+ System.out.println(MessageFormat.format("Invocation type:\t{0}\n" +
+ "\tOriginal value:\t\t{1}\n" +
+ "\tOriginal format:\t{2}\n" +
+ "\tNew value:\t\t\t{3}\n", f.getFormatInvocationType(), f.getValue(), f.getOriginalFormat(), f.getNewValue()));
+ }
+
+ private final String mNumberFormat;
+ private final String mDateFormat;
+ private final String mGeneralFormat;
+
+ private ArrayList getFormatInvocations() {
+ return mFormatInvocations;
+ }
+
+ private final ArrayList mFormatInvocations = new ArrayList<>();
+
+ private static class FormatInvocation {
+ public int getFormatInvocationType() {
+ return mFormatInvocationType;
+ }
+
+ private final int mFormatInvocationType;
+
+ public Object getValue() {
+ return mValue;
+ }
+
+ private final Object mValue;
+
+ public String getOriginalFormat() {
+ return mOriginalFormat;
+ }
+
+ private final String mOriginalFormat;
+
+ public String getNewValue() {
+ return mNewValue;
+ }
+
+ private final String mNewValue;
+
+ public FormatInvocation(int formatInvocationType, Object value, String originalFormat, String newValue) {
+ mValue = value;
+ mFormatInvocationType = formatInvocationType;
+ mOriginalFormat = originalFormat;
+ mNewValue = newValue;
+ }
+ }
+
+ public final class FormatInvocationType {
+ private FormatInvocationType() {
+ }
+
+ public static final int NUMERIC = 0;
+ public static final int DATE_TIME = 1;
+ public static final int GENERAL = 2;
+ public static final int ALL = 3;
+
+ public static final int length = 4;
+ }
+ }
+ //ExEnd
+
+ @Test
+ public void insertVideoWithUrl() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertOnlineVideo(String, Double, Double)
+ //ExSummary:Shows how to insert an online video into a document using a URL.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ builder.insertOnlineVideo("https://youtu.be/g1N9ke8Prmk", 360.0, 270.0);
+
+ // We can watch the video from Microsoft Word by clicking on the shape.
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertVideoWithUrl.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertVideoWithUrl.docx");
+ Shape shape = (Shape) doc.getChild(NodeType.SHAPE, 0, true);
+
+ TestUtil.verifyImageInShape(480, 360, ImageType.JPEG, shape);
+
+ Assert.assertEquals(360.0d, shape.getWidth());
+ Assert.assertEquals(270.0d, shape.getHeight());
+ }
+
+ @Test
+ public void insertUnderline() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.Underline
+ //ExSummary:Shows how to format text inserted by a document builder.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ builder.setUnderline(Underline.DASH);
+ builder.getFont().setColor(Color.BLUE);
+ builder.getFont().setSize(32.0);
+
+ // The builder applies formatting to its current paragraph and any new text added by it afterward.
+ builder.writeln("Large, blue, and underlined text.");
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertUnderline.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertUnderline.docx");
+ Run firstRun = doc.getFirstSection().getBody().getFirstParagraph().getRuns().get(0);
+
+ Assert.assertEquals("Large, blue, and underlined text.", firstRun.getText().trim());
+ Assert.assertEquals(Underline.DASH, firstRun.getFont().getUnderline());
+ Assert.assertEquals(Color.BLUE.getRGB(), firstRun.getFont().getColor().getRGB());
+ Assert.assertEquals(32.0d, firstRun.getFont().getSize());
+ }
+
+ @Test
+ public void currentStory() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.CurrentStory
+ //ExSummary:Shows how to work with a document builder's current story.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // A Story is a type of node that has child Paragraph nodes, such as a Body.
+ Assert.assertEquals(builder.getCurrentStory(), doc.getFirstSection().getBody());
+ Assert.assertEquals(builder.getCurrentStory(), builder.getCurrentParagraph().getParentNode());
+ Assert.assertEquals(StoryType.MAIN_TEXT, builder.getCurrentStory().getStoryType());
+
+ builder.getCurrentStory().appendParagraph("Text added to current Story.");
+
+ // A Story can also contain tables.
+ Table table = builder.startTable();
+ builder.insertCell();
+ builder.write("Row 1, cell 1");
+ builder.insertCell();
+ builder.write("Row 1, cell 2");
+ builder.endTable();
+
+ Assert.assertTrue(builder.getCurrentStory().getTables().contains(table));
+ //ExEnd
+
+ doc = DocumentHelper.saveOpen(doc);
+ Assert.assertEquals(1, doc.getFirstSection().getBody().getTables().getCount());
+ Assert.assertEquals("Row 1, cell 1\u0007Row 1, cell 2\u0007\u0007\rText added to current Story.", doc.getFirstSection().getBody().getText().trim());
+ }
+
+ @Test
+ public void insertOleObjects() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertOleObject(Stream, String, Boolean, Stream)
+ //ExSummary:Shows how to use document builder to embed OLE objects in a document.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Insert a Microsoft Excel spreadsheet from the local file system
+ // into the document while keeping its default appearance.
+ InputStream spreadsheetStream = new FileInputStream(getMyDir() + "Spreadsheet.xlsx");
+ InputStream representingImage = new FileInputStream(getImageDir() + "Logo.jpg");
+ try {
+ builder.writeln("Spreadsheet Ole object:");
+ builder.insertOleObject(spreadsheetStream, "OleObject.xlsx", false, representingImage);
+ } finally {
+ if (spreadsheetStream != null) spreadsheetStream.close();
+ }
+
+ // Double-click these objects in Microsoft Word to open
+ // the linked files using their respective applications.
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertOleObjects.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertOleObjects.docx");
+
+ Assert.assertEquals(1, doc.getChildNodes(NodeType.SHAPE, true).getCount());
+
+ Shape shape = (Shape) doc.getChild(NodeType.SHAPE, 0, true);
+ Assert.assertEquals("", shape.getOleFormat().getIconCaption());
+ Assert.assertFalse(shape.getOleFormat().getOleIcon());
+ }
+
+ @Test
+ public void insertStyleSeparator() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertStyleSeparator
+ //ExSummary:Shows how to work with style separators.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Each paragraph can only have one style.
+ // The InsertStyleSeparator method allows us to work around this limitation.
+ builder.getParagraphFormat().setStyleIdentifier(StyleIdentifier.HEADING_1);
+ builder.write("This text is in a Heading style. ");
+ builder.insertStyleSeparator();
+
+ Style paraStyle = builder.getDocument().getStyles().add(StyleType.PARAGRAPH, "MyParaStyle");
+ paraStyle.getFont().setBold(false);
+ paraStyle.getFont().setSize(8.0);
+ paraStyle.getFont().setName("Arial");
+
+ builder.getParagraphFormat().setStyleName(paraStyle.getName());
+ builder.write("This text is in a custom style. ");
+
+ // Calling the InsertStyleSeparator method creates another paragraph,
+ // which can have a different style to the previous. There will be no break between paragraphs.
+ // The text in the output document will look like one paragraph with two styles.
+ Assert.assertEquals(2, doc.getFirstSection().getBody().getParagraphs().getCount());
+ Assert.assertEquals("Heading 1", doc.getFirstSection().getBody().getParagraphs().get(0).getParagraphFormat().getStyle().getName());
+ Assert.assertEquals("MyParaStyle", doc.getFirstSection().getBody().getParagraphs().get(1).getParagraphFormat().getStyle().getName());
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertStyleSeparator.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertStyleSeparator.docx");
+
+ Assert.assertEquals(2, doc.getFirstSection().getBody().getParagraphs().getCount());
+ Assert.assertEquals("This text is in a Heading style. \r This text is in a custom style.",
+ doc.getText().trim());
+ Assert.assertEquals("Heading 1", doc.getFirstSection().getBody().getParagraphs().get(0).getParagraphFormat().getStyle().getName());
+ Assert.assertEquals("MyParaStyle", doc.getFirstSection().getBody().getParagraphs().get(1).getParagraphFormat().getStyle().getName());
+ Assert.assertEquals(" ", doc.getFirstSection().getBody().getParagraphs().get(1).getRuns().get(0).getText());
+ TestUtil.docPackageFileContainsString("w:rPr>",
+ getArtifactsDir() + "DocumentBuilder.InsertStyleSeparator.docx", "document.xml");
+ TestUtil.docPackageFileContainsString("",
+ getArtifactsDir() + "DocumentBuilder.InsertStyleSeparator.docx", "document.xml");
+ }
+
+ @Test(enabled = false, description = "Bug: does not insert headers and footers, all lists (bullets, numbering, multilevel) breaks")
+ public void insertDocument() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertDocument(Document, ImportFormatMode)
+ //ExFor:ImportFormatMode
+ //ExSummary:Shows how to insert a document into another document.
+ Document doc = new Document(getMyDir() + "Document.docx");
+
+ DocumentBuilder builder = new DocumentBuilder(doc);
+ builder.moveToDocumentEnd();
+ builder.insertBreak(BreakType.PAGE_BREAK);
+
+ Document docToInsert = new Document(getMyDir() + "Formatted elements.docx");
+
+ builder.insertDocument(docToInsert, ImportFormatMode.KEEP_SOURCE_FORMATTING);
+ builder.getDocument().save(getArtifactsDir() + "DocumentBuilder.InsertDocument.docx");
+ //ExEnd
+
+ Assert.assertEquals(29, doc.getStyles().getCount());
+ Assert.assertTrue(DocumentHelper.compareDocs(getArtifactsDir() + "DocumentBuilder.InsertDocument.docx",
+ getGoldsDir() + "DocumentBuilder.InsertDocument Gold.docx"));
+ }
+
+ @Test
+ public void smartStyleBehavior() throws Exception {
+ //ExStart
+ //ExFor:ImportFormatOptions
+ //ExFor:ImportFormatOptions.SmartStyleBehavior
+ //ExFor:DocumentBuilder.InsertDocument(Document, ImportFormatMode, ImportFormatOptions)
+ //ExSummary:Shows how to resolve duplicate styles while inserting documents.
+ Document dstDoc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(dstDoc);
+
+ Style myStyle = builder.getDocument().getStyles().add(StyleType.PARAGRAPH, "MyStyle");
+ myStyle.getFont().setSize(14.0);
+ myStyle.getFont().setName("Courier New");
+ myStyle.getFont().setColor(Color.BLUE);
+
+ builder.getParagraphFormat().setStyleName(myStyle.getName());
+ builder.writeln("Hello world!");
+
+ // Clone the document and edit the clone's "MyStyle" style, so it is a different color than that of the original.
+ // If we insert the clone into the original document, the two styles with the same name will cause a clash.
+ Document srcDoc = dstDoc.deepClone();
+ srcDoc.getStyles().get("MyStyle").getFont().setColor(Color.RED);
+
+ // When we enable SmartStyleBehavior and use the KeepSourceFormatting import format mode,
+ // Aspose.Words will resolve style clashes by converting source document styles.
+ // with the same names as destination styles into direct paragraph attributes.
+ ImportFormatOptions options = new ImportFormatOptions();
+ options.setSmartStyleBehavior(true);
+
+ builder.insertDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING, options);
+
+ dstDoc.save(getArtifactsDir() + "DocumentBuilder.SmartStyleBehavior.docx");
+ //ExEnd
+
+ dstDoc = new Document(getArtifactsDir() + "DocumentBuilder.SmartStyleBehavior.docx");
+
+ Assert.assertEquals(Color.BLUE.getRGB(), dstDoc.getStyles().get("MyStyle").getFont().getColor().getRGB());
+ Assert.assertEquals("MyStyle", dstDoc.getFirstSection().getBody().getParagraphs().get(0).getParagraphFormat().getStyle().getName());
+
+ Assert.assertEquals("Normal", dstDoc.getFirstSection().getBody().getParagraphs().get(1).getParagraphFormat().getStyle().getName());
+ Assert.assertEquals(14.0, dstDoc.getFirstSection().getBody().getParagraphs().get(1).getRuns().get(0).getFont().getSize());
+ Assert.assertEquals("Courier New", dstDoc.getFirstSection().getBody().getParagraphs().get(1).getRuns().get(0).getFont().getName());
+ Assert.assertEquals(Color.RED.getRGB(), dstDoc.getFirstSection().getBody().getParagraphs().get(1).getRuns().get(0).getFont().getColor().getRGB());
+ }
+
+ @Test
+ public void emphasesWarningSourceMarkdown() throws Exception
+ {
+ //ExStart
+ //ExFor:WarningInfo.Source
+ //ExFor:WarningSource
+ //ExSummary:Shows how to work with the warning source.
+ Document doc = new Document(getMyDir() + "Emphases markdown warning.docx");
+
+ WarningInfoCollection warnings = new WarningInfoCollection();
+ doc.setWarningCallback(warnings);
+ doc.save(getArtifactsDir() + "DocumentBuilder.EmphasesWarningSourceMarkdown.md");
+
+ for (WarningInfo warningInfo : warnings) {
+ if (warningInfo.getSource() == WarningSource.MARKDOWN)
+ Assert.assertEquals("The (*, 0:11) cannot be properly written into Markdown.", warningInfo.getDescription());
+ }
+ //ExEnd
+ }
+
+ @Test
+ public void doNotIgnoreHeaderFooter() throws Exception {
+ //ExStart
+ //ExFor:ImportFormatOptions.IgnoreHeaderFooter
+ //ExSummary:Shows how to specifies ignoring or not source formatting of headers/footers content.
+ Document dstDoc = new Document(getMyDir() + "Document.docx");
+ Document srcDoc = new Document(getMyDir() + "Header and footer types.docx");
+
+ // If 'IgnoreHeaderFooter' is false then the original formatting for header/footer content
+ // from "Header and footer types.docx" will be used.
+ // If 'IgnoreHeaderFooter' is true then the formatting for header/footer content
+ // from "Document.docx" will be used.
+ ImportFormatOptions importFormatOptions = new ImportFormatOptions();
+ importFormatOptions.setIgnoreHeaderFooter(false);
+
+ dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING, importFormatOptions);
+
+ dstDoc.save(getArtifactsDir() + "DocumentBuilder.DoNotIgnoreHeaderFooter.docx");
+ //ExEnd
+ }
+
+ public void markdownDocumentEmphases() throws Exception {
+ DocumentBuilder builder = new DocumentBuilder();
+
+ // Bold and Italic are represented as Font.Bold and Font.Italic.
+ builder.getFont().setItalic(true);
+ builder.writeln("This text will be italic");
+
+ // Use clear formatting if we don't want to combine styles between paragraphs.
+ builder.getFont().clearFormatting();
+
+ builder.getFont().setBold(true);
+ builder.writeln("This text will be bold");
+
+ builder.getFont().clearFormatting();
+
+ builder.getFont().setItalic(true);
+ builder.write("You ");
+ builder.getFont().setBold(true);
+ builder.write("can");
+ builder.getFont().setBold(false);
+ builder.writeln(" combine them");
+
+ builder.getFont().clearFormatting();
+
+ builder.getFont().setStrikeThrough(true);
+ builder.writeln("This text will be strikethrough");
+
+ // Markdown treats asterisks (*), underscores (_) and tilde (~) as indicators of emphasis.
+ builder.getDocument().save(getArtifactsDir() + "DocumentBuilder.MarkdownDocument.md");
+ }
+
+ public void markdownDocumentInlineCode() throws Exception {
+ Document doc = new Document(getArtifactsDir() + "DocumentBuilder.MarkdownDocument.md");
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Prepare our created document for further work
+ // and clear paragraph formatting not to use the previous styles.
+ builder.moveToDocumentEnd();
+ builder.getParagraphFormat().clearFormatting();
+ builder.writeln("\n");
+
+ // Style with name that starts from word InlineCode, followed by optional dot (.) and number of backticks (`).
+ // If number of backticks is missed, then one backtick will be used by default.
+ Style inlineCode1BackTicks = doc.getStyles().add(StyleType.CHARACTER, "InlineCode");
+ builder.getFont().setStyle(inlineCode1BackTicks);
+ builder.writeln("Text with InlineCode style with one backtick");
+
+ // Use optional dot (.) and number of backticks (`).
+ // There will be 3 backticks.
+ Style inlineCode3BackTicks = doc.getStyles().add(StyleType.CHARACTER, "InlineCode.3");
+ builder.getFont().setStyle(inlineCode3BackTicks);
+ builder.writeln("Text with InlineCode style with 3 backticks");
+
+ builder.getDocument().save(getArtifactsDir() + "DocumentBuilder.MarkdownDocument.md");
+ }
+
+ public void markdownDocumentHeadings() throws Exception {
+ Document doc = new Document(getArtifactsDir() + "DocumentBuilder.MarkdownDocument.md");
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Prepare our created document for further work
+ // and clear paragraph formatting not to use the previous styles.
+ builder.moveToDocumentEnd();
+ builder.getParagraphFormat().clearFormatting();
+ builder.writeln("\n");
+
+ // By default, Heading styles in Word may have bold and italic formatting.
+ // If we do not want text to be emphasized, set these properties explicitly to false.
+ // Thus we can't use 'builder.Font.ClearFormatting()' because Bold/Italic will be set to true.
+ builder.getFont().setBold(false);
+ builder.getFont().setItalic(false);
+
+ // Create for one heading for each level.
+ builder.getParagraphFormat().setStyleName("Heading 1");
+ builder.getFont().setItalic(true);
+ builder.writeln("This is an italic H1 tag");
+
+ // Reset our styles from the previous paragraph to not combine styles between paragraphs.
+ builder.getFont().setBold(false);
+ builder.getFont().setItalic(false);
+
+ // Structure-enhanced text heading can be added through style inheritance.
+ Style setextHeading1 = doc.getStyles().add(StyleType.PARAGRAPH, "SetextHeading1");
+ builder.getParagraphFormat().setStyle(setextHeading1);
+ doc.getStyles().get("SetextHeading1").setBaseStyleName("Heading 1");
+ builder.writeln("SetextHeading 1");
+
+ builder.getParagraphFormat().setStyleName("Heading 2");
+ builder.writeln("This is an H2 tag");
+
+ builder.getFont().setBold(false);
+ builder.getFont().setItalic(false);
+
+ Style setextHeading2 = doc.getStyles().add(StyleType.PARAGRAPH, "SetextHeading2");
+ builder.getParagraphFormat().setStyle(setextHeading2);
+ doc.getStyles().get("SetextHeading2").setBaseStyleName("Heading 2");
+ builder.writeln("SetextHeading 2");
+
+ builder.getParagraphFormat().setStyle(doc.getStyles().get("Heading 3"));
+ builder.writeln("This is an H3 tag");
+
+ builder.getFont().setBold(false);
+ builder.getFont().setItalic(false);
+
+ builder.getParagraphFormat().setStyle(doc.getStyles().get("Heading 4"));
+ builder.getFont().setBold(true);
+ builder.writeln("This is an bold H4 tag");
+
+ builder.getFont().setBold(false);
+ builder.getFont().setItalic(false);
+
+ builder.getParagraphFormat().setStyle(doc.getStyles().get("Heading 5"));
+ builder.getFont().setItalic(true);
+ builder.getFont().setBold(true);
+ builder.writeln("This is an italic and bold H5 tag");
+
+ builder.getFont().setBold(false);
+ builder.getFont().setItalic(false);
+
+ builder.getParagraphFormat().setStyle(doc.getStyles().get("Heading 6"));
+ builder.writeln("This is an H6 tag");
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.MarkdownDocument.md");
+ }
+
+ public void markdownDocumentBlockquotes() throws Exception {
+ Document doc = new Document(getArtifactsDir() + "DocumentBuilder.MarkdownDocument.md");
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Prepare our created document for further work
+ // and clear paragraph formatting not to use the previous styles.
+ builder.moveToDocumentEnd();
+ builder.getParagraphFormat().clearFormatting();
+ builder.writeln("\n");
+
+ // By default, the document stores blockquote style for the first level.
+ builder.getParagraphFormat().setStyleName("Quote");
+ builder.writeln("Blockquote");
+
+ // Create styles for nested levels through style inheritance.
+ Style quoteLevel2 = doc.getStyles().add(StyleType.PARAGRAPH, "Quote1");
+ builder.getParagraphFormat().setStyle(quoteLevel2);
+ doc.getStyles().get("Quote1").setBaseStyleName("Quote");
+ builder.writeln("1. Nested blockquote");
+
+ Style quoteLevel3 = doc.getStyles().add(StyleType.PARAGRAPH, "Quote2");
+ builder.getParagraphFormat().setStyle(quoteLevel3);
+ doc.getStyles().get("Quote2").setBaseStyleName("Quote1");
+ builder.getFont().setItalic(true);
+ builder.writeln("2. Nested italic blockquote");
+
+ Style quoteLevel4 = doc.getStyles().add(StyleType.PARAGRAPH, "Quote3");
+ builder.getParagraphFormat().setStyle(quoteLevel4);
+ doc.getStyles().get("Quote3").setBaseStyleName("Quote2");
+ builder.getFont().setItalic(false);
+ builder.getFont().setBold(true);
+ builder.writeln("3. Nested bold blockquote");
+
+ Style quoteLevel5 = doc.getStyles().add(StyleType.PARAGRAPH, "Quote4");
+ builder.getParagraphFormat().setStyle(quoteLevel5);
+ doc.getStyles().get("Quote4").setBaseStyleName("Quote3");
+ builder.getFont().setBold(false);
+ builder.writeln("4. Nested blockquote");
+
+ Style quoteLevel6 = doc.getStyles().add(StyleType.PARAGRAPH, "Quote5");
+ builder.getParagraphFormat().setStyle(quoteLevel6);
+ doc.getStyles().get("Quote5").setBaseStyleName("Quote4");
+ builder.writeln("5. Nested blockquote");
+
+ Style quoteLevel7 = doc.getStyles().add(StyleType.PARAGRAPH, "Quote6");
+ builder.getParagraphFormat().setStyle(quoteLevel7);
+ doc.getStyles().get("Quote6").setBaseStyleName("Quote5");
+ builder.getFont().setItalic(true);
+ builder.getFont().setBold(true);
+ builder.writeln("6. Nested italic bold blockquote");
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.MarkdownDocument.md");
+ }
+
+ public void markdownDocumentIndentedCode() throws Exception {
+ Document doc = new Document(getArtifactsDir() + "DocumentBuilder.MarkdownDocument.md");
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Prepare our created document for further work
+ // and clear paragraph formatting not to use the previous styles.
+ builder.moveToDocumentEnd();
+ builder.writeln("\n");
+ builder.getParagraphFormat().clearFormatting();
+ builder.writeln("\n");
+
+ Style indentedCode = doc.getStyles().add(StyleType.PARAGRAPH, "IndentedCode");
+ builder.getParagraphFormat().setStyle(indentedCode);
+ builder.writeln("This is an indented code");
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.MarkdownDocument.md");
+ }
+
+ public void markdownDocumentFencedCode() throws Exception {
+ Document doc = new Document(getArtifactsDir() + "DocumentBuilder.MarkdownDocument.md");
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Prepare our created document for further work
+ // and clear paragraph formatting not to use the previous styles.
+ builder.moveToDocumentEnd();
+ builder.writeln("\n");
+ builder.getParagraphFormat().clearFormatting();
+ builder.writeln("\n");
+
+ Style fencedCode = doc.getStyles().add(StyleType.PARAGRAPH, "FencedCode");
+ builder.getParagraphFormat().setStyle(fencedCode);
+ builder.writeln("This is a fenced code");
+
+ Style fencedCodeWithInfo = doc.getStyles().add(StyleType.PARAGRAPH, "FencedCode.C#");
+ builder.getParagraphFormat().setStyle(fencedCodeWithInfo);
+ builder.writeln("This is a fenced code with info string");
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.MarkdownDocument.md");
+ }
+
+ public void markdownDocumentHorizontalRule() throws Exception {
+ Document doc = new Document(getArtifactsDir() + "DocumentBuilder.MarkdownDocument.md");
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Prepare our created document for further work
+ // and clear paragraph formatting not to use the previous styles.
+ builder.moveToDocumentEnd();
+ builder.getParagraphFormat().clearFormatting();
+ builder.writeln("\n");
+
+ // Insert HorizontalRule that will be present in .md file as '-----'.
+ builder.insertHorizontalRule();
+
+ builder.getDocument().save(getArtifactsDir() + "DocumentBuilder.MarkdownDocument.md");
+ }
+
+ public void markdownDocumentBulletedList() throws Exception {
+ Document doc = new Document(getArtifactsDir() + "DocumentBuilder.MarkdownDocument.md");
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // Prepare our created document for further work
+ // and clear paragraph formatting not to use the previous styles.
+ builder.moveToDocumentEnd();
+ builder.getParagraphFormat().clearFormatting();
+ builder.writeln("\n");
+
+ // Bulleted lists are represented using paragraph numbering.
+ builder.getListFormat().applyBulletDefault();
+ // There can be 3 types of bulleted lists.
+ // The only diff in a numbering format of the very first level are ‘-’, ‘+’ or ‘*’ respectively.
+ builder.getListFormat().getList().getListLevels().get(0).setNumberFormat("-");
+
+ builder.writeln("Item 1");
+ builder.writeln("Item 2");
+ builder.getListFormat().listIndent();
+ builder.writeln("Item 2a");
+ builder.writeln("Item 2b");
+
+ builder.getDocument().save(getArtifactsDir() + "DocumentBuilder.MarkdownDocument.md");
+ }
+
+ @Test (description = "WORDSNET-19850", dataProvider = "loadMarkdownDocumentAndAssertContentDataProvider")
+ public void loadMarkdownDocumentAndAssertContent(String text, String styleName, boolean isItalic, boolean isBold) throws Exception {
+ // Prepare document to test.
+ markdownDocumentEmphases();
+ markdownDocumentInlineCode();
+ markdownDocumentHeadings();
+ markdownDocumentBlockquotes();
+ markdownDocumentIndentedCode();
+ markdownDocumentFencedCode();
+ markdownDocumentHorizontalRule();
+ markdownDocumentBulletedList();
+
+ // Load created document from previous tests.
+ Document doc = new Document(getArtifactsDir() + "DocumentBuilder.MarkdownDocument.md");
+ ParagraphCollection paragraphs = doc.getFirstSection().getBody().getParagraphs();
+
+ for (Paragraph paragraph : paragraphs) {
+ if (paragraph.getRuns().getCount() != 0) {
+ // Check that all document text has the necessary styles.
+ if (paragraph.getRuns().get(0).getText().equals(text) && !text.contains("InlineCode")) {
+ Assert.assertEquals(styleName, paragraph.getParagraphFormat().getStyle().getName());
+ Assert.assertEquals(isItalic, paragraph.getRuns().get(0).getFont().getItalic());
+ Assert.assertEquals(isBold, paragraph.getRuns().get(0).getFont().getBold());
+ } else if (paragraph.getRuns().get(0).getText().equals(text) && text.contains("InlineCode")) {
+ Assert.assertEquals(styleName, paragraph.getRuns().get(0).getFont().getStyleName());
+ }
+ }
+
+ // Check that document also has a HorizontalRule present as a shape.
+ NodeCollection shapesCollection = doc.getFirstSection().getBody().getChildNodes(NodeType.SHAPE, true);
+ Shape horizontalRuleShape = (Shape) shapesCollection.get(0);
+
+ Assert.assertTrue(shapesCollection.getCount() == 1);
+ Assert.assertTrue(horizontalRuleShape.isHorizontalRule());
+ }
+ }
+
+ @DataProvider(name = "loadMarkdownDocumentAndAssertContentDataProvider")
+ public static Object[][] loadMarkdownDocumentAndAssertContentDataProvider() throws Exception {
+ return new Object[][]
+ {
+ {"Italic", "Normal", true, false},
+ {"Bold", "Normal", false, true},
+ {"ItalicBold", "Normal", true, true},
+ {"Text with InlineCode style with one backtick", "InlineCode", false, false},
+ {"Text with InlineCode style with 3 backticks", "InlineCode.3", false, false},
+ {"This is an italic H1 tag", "Heading 1", true, false},
+ {"SetextHeading 1", "SetextHeading1", false, false},
+ {"This is an H2 tag", "Heading 2", false, false},
+ {"SetextHeading 2", "SetextHeading2", false, false},
+ {"This is an H3 tag", "Heading 3", false, false},
+ {"This is an bold H4 tag", "Heading 4", false, true},
+ {"This is an italic and bold H5 tag", "Heading 5", true, true},
+ {"This is an H6 tag", "Heading 6", false, false},
+ {"Blockquote", "Quote", false, false},
+ {"1. Nested blockquote", "Quote1", false, false},
+ {"2. Nested italic blockquote", "Quote2", true, false},
+ {"3. Nested bold blockquote", "Quote3", false, true},
+ {"4. Nested blockquote", "Quote4", false, false},
+ {"5. Nested blockquote", "Quote5", false, false},
+ {"6. Nested italic bold blockquote", "Quote6", true, true},
+ {"This is an indented code", "IndentedCode", false, false},
+ {"This is a fenced code", "FencedCode", false, false},
+ {"This is a fenced code with info string", "FencedCode.C#", false, false},
+ {"Item 1", "Normal", false, false},
+ };
+ }
+
+ @Test(dataProvider = "markdownDocumentTableContentAlignmentDataProvider")
+ public void markdownDocumentTableContentAlignment(int tableContentAlignment) throws Exception {
+ DocumentBuilder builder = new DocumentBuilder();
+
+ builder.insertCell();
+ builder.getParagraphFormat().setAlignment(ParagraphAlignment.RIGHT);
+ builder.write("Cell1");
+ builder.insertCell();
+ builder.getParagraphFormat().setAlignment(ParagraphAlignment.CENTER);
+ builder.write("Cell2");
+
+ MarkdownSaveOptions saveOptions = new MarkdownSaveOptions();
+ saveOptions.setTableContentAlignment(tableContentAlignment);
+
+ builder.getDocument().save(getArtifactsDir() + "DocumentBuilder.MarkdownDocumentTableContentAlignment.md", saveOptions);
+
+ Document doc = new Document(getArtifactsDir() + "DocumentBuilder.MarkdownDocumentTableContentAlignment.md");
+ Table table = doc.getFirstSection().getBody().getTables().get(0);
+
+ switch (tableContentAlignment) {
+ case TableContentAlignment.AUTO:
+ Assert.assertEquals(ParagraphAlignment.RIGHT,
+ table.getFirstRow().getCells().get(0).getFirstParagraph().getParagraphFormat().getAlignment());
+ Assert.assertEquals(ParagraphAlignment.CENTER,
+ table.getFirstRow().getCells().get(1).getFirstParagraph().getParagraphFormat().getAlignment());
+ break;
+ case TableContentAlignment.LEFT:
+ Assert.assertEquals(ParagraphAlignment.LEFT,
+ table.getFirstRow().getCells().get(0).getFirstParagraph().getParagraphFormat().getAlignment());
+ Assert.assertEquals(ParagraphAlignment.LEFT,
+ table.getFirstRow().getCells().get(1).getFirstParagraph().getParagraphFormat().getAlignment());
+ break;
+ case TableContentAlignment.CENTER:
+ Assert.assertEquals(ParagraphAlignment.CENTER,
+ table.getFirstRow().getCells().get(0).getFirstParagraph().getParagraphFormat().getAlignment());
+ Assert.assertEquals(ParagraphAlignment.CENTER,
+ table.getFirstRow().getCells().get(1).getFirstParagraph().getParagraphFormat().getAlignment());
+ break;
+ case TableContentAlignment.RIGHT:
+ Assert.assertEquals(ParagraphAlignment.RIGHT,
+ table.getFirstRow().getCells().get(0).getFirstParagraph().getParagraphFormat().getAlignment());
+ Assert.assertEquals(ParagraphAlignment.RIGHT,
+ table.getFirstRow().getCells().get(1).getFirstParagraph().getParagraphFormat().getAlignment());
+ break;
+ }
+ }
+
+ @DataProvider(name = "markdownDocumentTableContentAlignmentDataProvider")
+ public static Object[][] markdownDocumentTableContentAlignmentDataProvider() {
+ return new Object[][]
+ {
+ {TableContentAlignment.LEFT},
+ {TableContentAlignment.RIGHT},
+ {TableContentAlignment.CENTER},
+ {TableContentAlignment.AUTO},
+ };
+ }
+
+ @Test
+ public void insertOnlineVideo() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertOnlineVideo(String, RelativeHorizontalPosition, Double, RelativeVerticalPosition, Double, Double, Double, WrapType)
+ //ExSummary:Shows how to insert an online video into a document.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ String videoUrl = "https://vimeo.com/52477838";
+
+ // Insert a shape that plays a video from the web when clicked in Microsoft Word.
+ // This rectangular shape will contain an image based on the first frame of the linked video
+ // and a "play button" visual prompt. The video has an aspect ratio of 16:9.
+ // We will set the shape's size to that ratio, so the image does not appear stretched.
+ builder.insertOnlineVideo(videoUrl, RelativeHorizontalPosition.LEFT_MARGIN, 0.0,
+ RelativeVerticalPosition.TOP_MARGIN, 0.0, 320.0, 180.0, WrapType.SQUARE);
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertOnlineVideo.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertOnlineVideo.docx");
+ Shape shape = (Shape) doc.getChild(NodeType.SHAPE, 0, true);
+
+ TestUtil.verifyImageInShape(640, 360, ImageType.JPEG, shape);
+
+ Assert.assertEquals(320.0d, shape.getWidth());
+ Assert.assertEquals(180.0d, shape.getHeight());
+ Assert.assertEquals(0.0d, shape.getLeft());
+ Assert.assertEquals(0.0d, shape.getTop());
+ Assert.assertEquals(WrapType.SQUARE, shape.getWrapType());
+ Assert.assertEquals(RelativeVerticalPosition.TOP_MARGIN, shape.getRelativeVerticalPosition());
+ Assert.assertEquals(RelativeHorizontalPosition.LEFT_MARGIN, shape.getRelativeHorizontalPosition());
+
+ Assert.assertEquals("https://vimeo.com/52477838", shape.getHRef());
+ TestUtil.verifyWebResponseStatusCode(200, new URL(shape.getHRef()));
+ }
+
+ @Test
+ public void insertOnlineVideoCustomThumbnail() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertOnlineVideo(String, String, Byte[], Double, Double)
+ //ExFor:DocumentBuilder.InsertOnlineVideo(String, String, Byte[], RelativeHorizontalPosition, Double, RelativeVerticalPosition, Double, Double, Double, WrapType)
+ //ExSummary:Shows how to insert an online video into a document with a custom thumbnail.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ String videoUrl = "https://vimeo.com/52477838";
+ String videoEmbedCode = "";
+
+ byte[] thumbnailImageBytes = IOUtils.toByteArray(getAsposelogoUri().toURL().openStream());
+
+ BufferedImage image = ImageIO.read(new ByteArrayInputStream(thumbnailImageBytes));
+
+ // Below are two ways of creating a shape with a custom thumbnail, which links to an online video
+ // that will play when we click on the shape in Microsoft Word.
+ // 1 - Insert an inline shape at the builder's node insertion cursor:
+ builder.insertOnlineVideo(videoUrl, videoEmbedCode, thumbnailImageBytes, image.getWidth(), image.getHeight());
+
+ builder.insertBreak(BreakType.PAGE_BREAK);
+
+ // 2 - Insert a floating shape:
+ double left = builder.getPageSetup().getRightMargin() - image.getWidth();
+ double top = builder.getPageSetup().getBottomMargin() - image.getHeight();
+
+ builder.insertOnlineVideo(videoUrl, videoEmbedCode, thumbnailImageBytes,
+ RelativeHorizontalPosition.RIGHT_MARGIN, left, RelativeVerticalPosition.BOTTOM_MARGIN, top,
+ image.getWidth(), image.getHeight(), WrapType.SQUARE);
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertOnlineVideoCustomThumbnail.docx");
+ //ExEnd
+
+ doc = new Document(getArtifactsDir() + "DocumentBuilder.InsertOnlineVideoCustomThumbnail.docx");
+ Shape shape = (Shape) doc.getChild(NodeType.SHAPE, 0, true);
+
+ TestUtil.verifyImageInShape(272, 92, ImageType.PNG, shape);
+ Assert.assertEquals(272.0d, shape.getWidth());
+ Assert.assertEquals(92.0d, shape.getHeight());
+ Assert.assertEquals(0.0d, shape.getLeft());
+ Assert.assertEquals(0.0d, shape.getTop());
+ Assert.assertEquals(WrapType.INLINE, shape.getWrapType());
+ Assert.assertEquals(RelativeVerticalPosition.PARAGRAPH, shape.getRelativeVerticalPosition());
+ Assert.assertEquals(RelativeHorizontalPosition.COLUMN, shape.getRelativeHorizontalPosition());
+
+ Assert.assertEquals("https://vimeo.com/52477838", shape.getHRef());
+
+ shape = (Shape) doc.getChild(NodeType.SHAPE, 1, true);
+
+ TestUtil.verifyImageInShape(272, 92, ImageType.PNG, shape);
+ Assert.assertEquals(272, shape.getWidth());
+ Assert.assertEquals(92.0d, shape.getHeight());
+ Assert.assertEquals(-200.0d, shape.getLeft());
+ Assert.assertEquals(-20.0d, shape.getTop());
+ Assert.assertEquals(WrapType.SQUARE, shape.getWrapType());
+ Assert.assertEquals(RelativeVerticalPosition.BOTTOM_MARGIN, shape.getRelativeVerticalPosition());
+ Assert.assertEquals(RelativeHorizontalPosition.RIGHT_MARGIN, shape.getRelativeHorizontalPosition());
+
+ Assert.assertEquals("https://vimeo.com/52477838", shape.getHRef());
+ TestUtil.verifyWebResponseStatusCode(200, new URL(shape.getHRef()));
+ }
+
+ @Test
+ public void insertOleObjectAsIcon() throws Exception {
+ //ExStart
+ //ExFor:DocumentBuilder.InsertOleObjectAsIcon(String, String, Boolean, String, String)
+ //ExFor:DocumentBuilder.InsertOleObjectAsIcon(Stream, String, String, String)
+ //ExSummary:Shows how to insert an embedded or linked OLE object as icon into the document.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ // If 'iconFile' and 'iconCaption' are omitted, this overloaded method selects
+ // the icon according to 'progId' and uses the filename for the icon caption.
+ builder.insertOleObjectAsIcon(getMyDir() + "Presentation.pptx", "Package", false, getImageDir() + "Logo icon.ico", "My embedded file");
+
+ builder.insertBreak(BreakType.LINE_BREAK);
+
+ try (FileInputStream stream = new FileInputStream(getMyDir() + "Presentation.pptx")) {
+ // If 'iconFile' and 'iconCaption' are omitted, this overloaded method selects
+ // the icon according to the file extension and uses the filename for the icon caption.
+ Shape shape = builder.insertOleObjectAsIcon(stream, "PowerPoint.Application", getImageDir() + "Logo icon.ico",
+ "My embedded file stream");
+
+ OlePackage setOlePackage = shape.getOleFormat().getOlePackage();
+ setOlePackage.setFileName("Presentation.pptx");
+ setOlePackage.setDisplayName("Presentation.pptx");
+ }
+
+ doc.save(getArtifactsDir() + "DocumentBuilder.InsertOleObjectAsIcon.docx");
+ //ExEnd
+ }
+
+ @Test
+ public void preserveBlocks() throws Exception
+ {
+ //ExStart
+ //ExFor:HtmlInsertOptions
+ //ExSummary:Shows how to allows better preserve borders and margins seen.
+ final String HTML = "\n \n
"));
+ }
+ //ExEnd
+ }
+
+ @DataProvider(name = "exportPageMarginsDataProvider")
+ public static Object[][] exportPageMarginsDataProvider() {
+ return new Object[][]
+ {
+ {false},
+ {true},
+ };
+ }
+
+ @Test(dataProvider = "exportPageSetupDataProvider")
+ public void exportPageSetup(boolean exportPageSetup) throws Exception {
+ //ExStart
+ //ExFor:HtmlSaveOptions.ExportPageSetup
+ //ExSummary:Shows how decide whether to preserve section structure/page setup information when saving to HTML.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ builder.write("Section 1");
+ builder.insertBreak(BreakType.SECTION_BREAK_NEW_PAGE);
+ builder.write("Section 2");
+
+ PageSetup pageSetup = doc.getSections().get(0).getPageSetup();
+ pageSetup.setTopMargin(36.0);
+ pageSetup.setBottomMargin(36.0);
+ pageSetup.setPaperSize(PaperSize.A5);
+
+ // When saving the document to HTML, we can pass a SaveOptions object
+ // to decide whether to preserve or discard page setup settings.
+ // If we set the "ExportPageSetup" flag to "true", the output HTML document will contain our page setup configuration.
+ // If we set the "ExportPageSetup" flag to "false", the save operation will discard our page setup settings
+ // for the first section, and both sections will look identical.
+ HtmlSaveOptions options = new HtmlSaveOptions();
+ {
+ options.setExportPageSetup(exportPageSetup);
+ }
+
+ doc.save(getArtifactsDir() + "HtmlSaveOptions.ExportPageSetup.html", options);
+
+ String outDocContents = FileUtils.readFileToString(new File(getArtifactsDir() + "HtmlSaveOptions.ExportPageSetup.html"), StandardCharsets.UTF_8);
+
+ if (exportPageSetup) {
+ Assert.assertTrue(outDocContents.contains(
+ ""));
+
+ Assert.assertTrue(outDocContents.contains(
+ "
"));
+ }
+ //ExEnd
+ }
+
+ @DataProvider(name = "exportPageSetupDataProvider")
+ public static Object[][] exportPageSetupDataProvider() {
+ return new Object[][]
+ {
+ {false},
+ {true},
+ };
+ }
+
+ @Test(dataProvider = "relativeFontSizeDataProvider")
+ public void relativeFontSize(boolean exportRelativeFontSize) throws Exception {
+ //ExStart
+ //ExFor:HtmlSaveOptions.ExportRelativeFontSize
+ //ExSummary:Shows how to use relative font sizes when saving to .html.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ builder.writeln("Default font size, ");
+ builder.getFont().setSize(24.0);
+ builder.writeln("2x default font size,");
+ builder.getFont().setSize(96.0);
+ builder.write("8x default font size");
+
+ // When we save the document to HTML, we can pass a SaveOptions object
+ // to determine whether to use relative or absolute font sizes.
+ // Set the "ExportRelativeFontSize" flag to "true" to declare font sizes
+ // using the "em" measurement unit, which is a factor that multiplies the current font size.
+ // Set the "ExportRelativeFontSize" flag to "false" to declare font sizes
+ // using the "pt" measurement unit, which is the font's absolute size in points.
+ HtmlSaveOptions options = new HtmlSaveOptions();
+ {
+ options.setExportRelativeFontSize(exportRelativeFontSize);
+ }
+
+ doc.save(getArtifactsDir() + "HtmlSaveOptions.RelativeFontSize.html", options);
+
+ String outDocContents = FileUtils.readFileToString(new File(getArtifactsDir() + "HtmlSaveOptions.RelativeFontSize.html"), StandardCharsets.UTF_8);
+
+ if (exportRelativeFontSize) {
+ Assert.assertTrue(outDocContents.contains(
+ "" +
+ "
" +
+ ""));
+ }
+ //ExEnd
+ }
+
+ @DataProvider(name = "relativeFontSizeDataProvider")
+ public static Object[][] relativeFontSizeDataProvider() {
+ return new Object[][]
+ {
+ {false},
+ {true},
+ };
+ }
+
+ @Test(dataProvider = "exportShapesDataProvider")
+ public void exportShapes(boolean exportShapesAsSvg) throws Exception {
+ //ExStart
+ //ExFor:HtmlSaveOptions.ExportShapesAsSvg
+ //ExSummary:Shows how to export shape as scalable vector graphics.
+ Document doc = new Document();
+ DocumentBuilder builder = new DocumentBuilder(doc);
+
+ Shape textBox = builder.insertShape(ShapeType.TEXT_BOX, 100.0, 60.0);
+ builder.moveTo(textBox.getFirstParagraph());
+ builder.write("My text box");
+
+ // When we save the document to HTML, we can pass a SaveOptions object
+ // to determine how the saving operation will export text box shapes.
+ // If we set the "ExportTextBoxAsSvg" flag to "true",
+ // the save operation will convert shapes with text into SVG objects.
+ // If we set the "ExportTextBoxAsSvg" flag to "false",
+ // the save operation will convert shapes with text into images.
+ HtmlSaveOptions options = new HtmlSaveOptions();
+ {
+ options.setExportShapesAsSvg(exportShapesAsSvg);
+ }
+
+ doc.save(getArtifactsDir() + "HtmlSaveOptions.ExportTextBox.html", options);
+
+ String outDocContents = FileUtils.readFileToString(new File(getArtifactsDir() + "HtmlSaveOptions.ExportTextBox.html"), StandardCharsets.UTF_8);
+
+ if (exportShapesAsSvg) {
+ Assert.assertTrue(outDocContents.contains(
+ "" +
+ "