thombergs / docx-stamper

Easy-to-use template engine for creating docx documents in Java.
MIT License
213 stars 90 forks source link

New comment processors - displayDocPartIf and displayWordIf #99

Open dallanmc opened 2 years ago

dallanmc commented 2 years ago

A couple of new comment processors if anyone is interested:

displayWordIf(condition)

You simply stick this comment around a word (or words!) and it will show or hide those words based on whether the condition resolves to true or false

Why is this useful? Let's say you have a scenario where you want to insert a variable, and that variable could be one 3 or more values and the condition comes from a value in your context. Imagine the following sentence

"The surcharge for your delivery will be x dollars"

let's pretend that x isn't available in the context object, but it's value is based on the customer's loyalty level (which is in the context)

Now, we could stick in a replaceWordWith and add a condition like this: (loyaltyLevel == "bronze"? "15": loyaltyLevel == "silver"? : "10": loyaltyLevel == "gold"? "5")

but this approach can get a bit messy for multiple values

Another solution is to write the sentence as "The surcharge for your delivery will be 5 10 15 dollars" and then put a displayWordIf comment around each of the values and the condition within the value as follows displayWordIf(loyaltyLevel == "bronze")

Hope you get the idea.

Anyway the code modification for this is simple. Just stick the following in the DisplayIfProcessor:

    @Override
    public void displayWordIf(Boolean condition) {
        if (!condition) {
            RunUtil.setText(this.getCurrentRunCoordinates().getRun(), "");
        } // otherwise it will just leave the value as is
    }

displayDocPartIf(condition)

So this one is basically a mashup between displayParagraphIf and repeatDocPart

You can select multiple parts of the documents (let's say an entire section containing 5 paragraphs) and add a single comment displayParagraph(condition). If the condition is true, it will show the commented section. If the condition is false, it will hide the commented section.

You can also use this instead of the displayParagraphIf as it also works for single paragraphs.

This is extremely useful. It currently supports paragraphs and tables within the commented section, but you can add any type of object.

Basically, this is the code to do it. A good chunk of it is borrowed from the repeatDocPart comment, so thanks to that contributor.

add the following to the DisplayIfProcessor class


    private List<Object> objectsToBeRemoved = new ArrayList<>();

    @Override
    public void commitChanges() {
        ObjectDeleter deleter = new ObjectDeleter();
        removeParagraphs(deleter);
        removeTables(deleter);
        removeTableRows(deleter);
        removeObjects(deleter);
    }

    @Override
    public void reset() {
        paragraphsToBeRemoved = new ArrayList<>();
        tablesToBeRemoved = new ArrayList<>();
        tableRowsToBeRemoved = new ArrayList<>();
        objectsToBeRemoved = new ArrayList<>();
    }

    @Override
    public void displayDocPartIf(Boolean condition) {
        if (!condition) {
            CommentWrapper commentWrapper = getCurrentCommentWrapper();
            CommentRangeStart start = commentWrapper.getCommentRangeStart();

            ContentAccessor gcp = findGreatestCommonParent(commentWrapper.getCommentRangeEnd(), (ContentAccessor) start.getParent());
            if (gcp instanceof P) {
                paragraphsToBeRemoved.add((P)gcp);
            } else {
                List<Object> repeatElements = getRepeatElements(commentWrapper, gcp);
                objectsToBeRemoved.addAll(repeatElements);
            }
        }
    }

ObjectDeleter.java:

    public void deleteObject(Object object) {
        if (object instanceof P) {
            deleteParagraph((P)object);
        } else {
            Object unwrappedObject = XmlUtils.unwrap(object);
            if (unwrappedObject instanceof Tbl) {
                deleteTable((Tbl) unwrappedObject);
            }
        } // can add more object types here if you like
    }