diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 4c6eab9..3063636 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -18,7 +18,7 @@ object Versions { // Latest Version: // Visit https://central.sonatype.com and search for: g:org.jodconverter a:jodconverter-core - const val jodConverter = "4.4.7" + const val jodConverter = "4.4.9" // Latest Version: // Visit https://central.sonatype.com and search for: g:commons-fileupload a:commons-fileupload diff --git a/samples/spring-boot-rest/src/main/java/org/jodconverter/sample/rest/AcceptAllTrackedChangesFilter.java b/samples/spring-boot-rest/src/main/java/org/jodconverter/sample/rest/AcceptAllTrackedChangesFilter.java new file mode 100644 index 0000000..1fd866e --- /dev/null +++ b/samples/spring-boot-rest/src/main/java/org/jodconverter/sample/rest/AcceptAllTrackedChangesFilter.java @@ -0,0 +1,88 @@ +package org.jodconverter.sample.rest; + +import com.sun.star.beans.PropertyValue; +import com.sun.star.frame.XController; +import com.sun.star.frame.XDispatchHelper; +import com.sun.star.frame.XDispatchProvider; +import com.sun.star.frame.XFrame; +import com.sun.star.frame.XModel; +import com.sun.star.lang.XComponent; +import com.sun.star.uno.XComponentContext; +import org.jodconverter.core.office.OfficeContext; +import org.jodconverter.local.filter.Filter; +import org.jodconverter.local.filter.FilterChain; +import org.jodconverter.local.office.LocalOfficeContext; +import org.jodconverter.local.office.utils.Lo; +import org.jodconverter.local.office.utils.Write; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A {@link Filter} that accepts all tracked changes (redlines) in a Writer document before it is + * passed further down the conversion chain (e.g. exported to PDF). + * + *
By default LibreOffice exports a document with its tracked changes preserved, so the resulting + * PDF may still contain insertion/deletion markup. This filter applies all revisions in memory by + * dispatching the {@code .uno:AcceptAllTrackedChanges} command, producing the clean "final" view. + * + *
Only Writer (text) documents are affected; other document types pass through untouched.
+ */
+public class AcceptAllTrackedChangesFilter implements Filter {
+
+ private static final Logger LOGGER =
+ LoggerFactory.getLogger(AcceptAllTrackedChangesFilter.class);
+
+ private static final String ACCEPT_ALL_TRACKED_CHANGES = ".uno:AcceptAllTrackedChanges";
+
+ @Override
+ public void doFilter(
+ final OfficeContext context, final XComponent document, final FilterChain chain)
+ throws Exception {
+
+ if (Write.isText(document)) {
+ LOGGER.debug("Applying AcceptAllTrackedChangesFilter to text document");
+ acceptAllTrackedChanges(context, document);
+ } else {
+ LOGGER.debug("Skipping AcceptAllTrackedChangesFilter (document is not a text document)");
+ }
+
+ // Continue the conversion chain.
+ chain.doFilter(context, document);
+ }
+
+ private static void acceptAllTrackedChanges(
+ final OfficeContext context, final XComponent document) {
+
+ final XComponentContext componentContext =
+ ((LocalOfficeContext) context).getComponentContext();
+ if (componentContext == null) {
+ LOGGER.warn("No component context available; cannot accept tracked changes");
+ return;
+ }
+
+ final XModel model = Lo.qi(XModel.class, document);
+ final XController controller = model.getCurrentController();
+ if (controller == null) {
+ LOGGER.warn("No controller available; cannot accept tracked changes");
+ return;
+ }
+
+ final XFrame frame = controller.getFrame();
+ if (frame == null) {
+ LOGGER.warn("No frame available; cannot accept tracked changes");
+ return;
+ }
+
+ final XDispatchProvider dispatchProvider = Lo.qi(XDispatchProvider.class, frame);
+ final XDispatchHelper dispatchHelper =
+ Lo.createInstance(
+ componentContext, XDispatchHelper.class, "com.sun.star.frame.DispatchHelper");
+ if (dispatchHelper == null) {
+ LOGGER.warn("Could not create DispatchHelper; cannot accept tracked changes");
+ return;
+ }
+
+ dispatchHelper.executeDispatch(
+ dispatchProvider, ACCEPT_ALL_TRACKED_CHANGES, "", 0, new PropertyValue[0]);
+ }
+}
diff --git a/samples/spring-boot-rest/src/main/java/org/jodconverter/sample/rest/ConverterController.java b/samples/spring-boot-rest/src/main/java/org/jodconverter/sample/rest/ConverterController.java
index 8e1b617..603a63b 100644
--- a/samples/spring-boot-rest/src/main/java/org/jodconverter/sample/rest/ConverterController.java
+++ b/samples/spring-boot-rest/src/main/java/org/jodconverter/sample/rest/ConverterController.java
@@ -15,6 +15,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
@@ -49,6 +50,15 @@ public class ConverterController {
@Autowired
private ParameterDecoder parameterDecoder;
+ /**
+ * Default for whether all tracked changes should be accepted before conversion. Applied when a
+ * request does not explicitly set the {@code acceptTrackedChanges} parameter. Configurable via
+ * the {@code jodconverter.accept-tracked-changes} property (env {@code
+ * JODCONVERTER_ACCEPT_TRACKED_CHANGES}).
+ */
+ @Value("${jodconverter.accept-tracked-changes:false}")
+ private boolean acceptTrackedChangesByDefault;
+
/**
* Creates a new controller.
*
@@ -82,11 +92,17 @@ public ConverterController(final OfficeManager officeManager) {
description = "The document format to convert the input document to.",
required = true)
@RequestParam(name = "format") final String convertToFormat,
+ @Parameter(
+ description =
+ "Whether to accept all tracked changes before converting. Defaults to the"
+ + " server configuration when omitted.")
+ @RequestParam(name = "acceptTrackedChanges", required = false)
+ final Boolean acceptTrackedChanges,
@Parameter(description = "The custom options to apply to the conversion.")
@RequestParam(required = false) final Map