Skip to main content
Skip table of contents

Progress Monitoring

📌 Overview

Some Mako operations, particularly those operating on large documents, can take a long time. In an interactive application, evidence of progress by means of UI element such as a progress bar or even just a “spinner” of some kind reassures the user that something is happening and that the application has not hung.

Mako provides these classes to enable implementation of such mechanisms:

Class

Description

IProgressMonitor

An abstract class encapsulating both an IProgressTick and an IAbort so that the caller can monitor the progress and/or abort the processing.

IProgressTick

An abstract class allowing a callback to monitor the progress of a task. The callback can either pass an integer (from 0 to a maximum value) or a float (0.0 to 1.0) which represents the progress of the task.

IAbort

A simple class to signal an abort in processing.

In principle, adding progress monitoring involves these steps:

  • Create a progress tick call back function

  • Create an IProgressTick referencing the call back function

  • Creating an IProgressMonitor with the IProgressTickinstance and an IAbortinstance

  • Attach the progress monitor to the process to be monitored by passing in the IProgressMonitor instance

Thereafter, the call back function will be called on a regular ‘tick’, the number of which is determined by the work being done. The interval of the ticks can be controlled, and a maximum number can be specified, so that as the process continues, the tick will incrementally approach the maximum. The tick call back can be an integer or a float.

The call back can also interrupt the process by signalling an abort. This is shown in the accompanying page that looks in more detail at monitoring transforms.

Sample Code

To help you understand how to implement progress monitoring in your development, we have created sample code, attached, that does the following:

✅Demonstrates the Use of IProgressMonitor, IProgressTick, and IAbort

  • The code initializes and uses progress-related objects, showing how to:

    • Create progress monitors (IProgressMonitor::create).

    • Attach them to different stages of processing (custom transformation, general transformation, transform chain).

    • Use IProgressTick to trigger progress updates.

Multiple Progress Monitors for Different Stages

  • The sample shows progress tracking at multiple levels:

    • Custom Transform (m_customTransformProgressMonitor)

    • Single Transform (m_transformProgressMonitor)

    • Transform Chain (m_transformChainProgressMonitor)

    These show how to instrument various stages of their processing pipeline.

Encapsulation of Progress Handling (ProgressHandler Class)

  • ProgressHandler::create() simplifies instantiation.

  • The tick() method demonstrates periodic updates.

  • The callbackInt() method links progress updates back to the ProgressHandler.

Code Examples

Examples are provided in C++ & C#. For the full implementations, see Visual Studio Projects/ProgressMonitoring, Java Projects/ProgressMonitoring or Python Projects/ProgressMonitoring . Below are some relevant snippets.

ProgressHandler class

CPP
class ProgressHandler
{
    // This section should be customised
public:
    explicit ProgressHandler(std::string info = "") : m_info(std::move(info)), m_tickCount(0) {}

    void tick(uint32_t currentCount, uint32_t maxCount)
    {
        m_tickCount++;

        printf("%s : %d\n", m_info.c_str(), m_tickCount);
        fflush(stdout);
    }

    // Everything below this part can be reused
    IProgressTickPtr    m_progressTick;

    static std::shared_ptr<ProgressHandler>  create(const std::string& info)
    {
        std::shared_ptr<ProgressHandler> progressHandler = std::make_shared<ProgressHandler>(info);
        progressHandler->m_progressTick = IProgressTick::create(callbackInt, progressHandler.get());

        return progressHandler;
    }

protected:
    static void callbackInt(void* priv, uint32_t currentCount, uint32_t maxCount)
    {
        ProgressHandler* progressHandler = (ProgressHandler*)priv;
        progressHandler->tick(currentCount, maxCount);
    }

private:
    std::string     m_info;
    int             m_tickCount;
};
C#
class ProgressHandler : IProgressTickIntCallback
    {
        private readonly string info;
        private int tickCount;

        public IProgressTick ProgressTick { get; private set; }

        public ProgressHandler(string info)
        {
            this.info = info;
            tickCount = 0;
            ProgressTick = IProgressTick.create(this.getCallbackFunc(), this.getPriv());
        }

        public override void tick(uint currentCount, uint maxCount)
        {
            tickCount++;
            Console.WriteLine($"{info} : {tickCount}");
        }
    }
JAVA
static class ProgressHandler extends IProgressTickIntCallback
    {
        private final String info;
        private int tickCount;
        public IProgressTick progressTick;

        public ProgressHandler(String info) {
            this.info = info;
            this.tickCount = 0;

            // Create callback + tick object
            this.progressTick = IProgressTick.create(getCallbackFunc(), getPriv());
        }

        @Override
        public void tick(long currentCount, long maxCount) {
            tickCount++;
            System.out.println(info + " : " + tickCount);
        }
    }
PY
class ProgressHandler(IProgressTickIntCallback):
    def __init__(self, info):
        super().__init__()
        self.info = info
        self.tick_count = 0
        self.progress_tick = IProgressTick.create(self.getCallbackFunc(), self.getPriv())

    def tick(self, current_count, max_count):
        self.tick_count += 1
        print(f"{self.info} : {self.tick_count}")

Create Progress Monitors

CPP
// ----- Create ProgressHandlers -----
std::shared_ptr<ProgressHandler>    customTransformProgressHandler = ProgressHandler::create("customtransform");
std::shared_ptr<ProgressHandler>    transformProgressHandler = ProgressHandler::create("transform");
std::shared_ptr<ProgressHandler>    transformChainProgressHandler = ProgressHandler::create("transformChain");

// ----- Create ProgressMonitors -----
IAbortPtr abort = IAbort::create();

cvtParams.m_customTransformProgressMonitor = IProgressMonitor::create(customTransformProgressHandler->m_progressTick, abort);
cvtParams.m_transformProgressMonitor = IProgressMonitor::create(transformProgressHandler->m_progressTick, abort);
cvtParams.m_transformChainProgressMonitor = IProgressMonitor::create(transformChainProgressHandler->m_progressTick, abort);
C#
// ----- Create ProgressHandlers -----
ProgressHandler customHandler = new ProgressHandler("customtransform");
ProgressHandler transformHandler = new ProgressHandler("transform");
ProgressHandler chainHandler = new ProgressHandler("transformchain");

// ----- Create ProgressMonitors -----
var abort = IAbort.create();
cvtParams.CustomTransformProgressMonitor = IProgressMonitor.create(customHandler.ProgressTick, abort);
cvtParams.TransformProgressMonitor = IProgressMonitor.create(transformHandler.ProgressTick, abort);
cvtParams.TransformChainProgressMonitor = IProgressMonitor.create(chainHandler.ProgressTick, abort);
JAVA
// ----- Create ProgressHandlers -----
ProgressHandler customHandler = new ProgressHandler("customtransform");
ProgressHandler transformHandler = new ProgressHandler("transform");
ProgressHandler chainHandler = new ProgressHandler("transformchain");

// ----- Create ProgressMonitors -----
IAbort abort = IAbort.create();
cvtParams.customTransformProgressMonitor = IProgressMonitor.create(customHandler.progressTick, abort);
cvtParams.transformProgressMonitor = IProgressMonitor.create(transformHandler.progressTick, abort);
cvtParams.transformChainProgressMonitor = IProgressMonitor.create(chainHandler.progressTick, abort);
PY
// ----- Create ProgressHandlers -----
custom_handler = ProgressHandler("customtransform")
transform_handler = ProgressHandler("transform")
chain_handler = ProgressHandler("transformchain")

// ----- Create ProgressMonitors -----
abort = IAbort.create()
cvt_params.custom_transform_progress_monitor = IProgressMonitor.create(custom_handler.progress_tick, abort)
cvt_params.transform_progress_monitor = IProgressMonitor.create(transform_handler.progress_tick, abort)
cvt_params.transform_chain_progress_monitor = IProgressMonitor.create(chain_handler.progress_tick, abort)

Add progress monitors to transforms

CPP
// Create the transform
CEmptyTransformImplementation implementation(jawsMako);
ITransformPtr customTransform = ICustomTransform::create(jawsMako, &implementation);
customTransform->setProgressMonitor(cvtParams.m_customTransformProgressMonitor);

IColorConverterTransformPtr ccTransform = IColorConverterTransform::create(jawsMako);
IDOMColorSpacePtr deviceCmyk = IDOMColorSpaceDeviceCMYK::create(jawsMako);
ccTransform->setTargetSpace(deviceCmyk);
ccTransform->setProgressMonitor(cvtParams.m_transformProgressMonitor);


ITransformChainPtr transformChain;
{
    IColorConverterTransformPtr colorConverter = IColorConverterTransform::create(jawsMako);
    transformChain = ITransformChain::create(jawsMako, cvtParams.m_transformChainProgressMonitor);
    transformChain->pushTransform(colorConverter);
}
C#
// Create transforms
var customImpl = new EmptyTransformImplementation(jawsMako);
var customTransform = ICustomTransform.create(jawsMako, customImpl);
customTransform.setProgressMonitor(cvtParams.CustomTransformProgressMonitor);

var ccTransform = IColorConverterTransform.create(jawsMako);
var deviceCmyk = IDOMColorSpaceDeviceCMYK.create(jawsMako);
ccTransform.setTargetSpace(deviceCmyk);
ccTransform.setProgressMonitor(cvtParams.TransformProgressMonitor);

var transformChain = ITransformChain.create(jawsMako, cvtParams.TransformChainProgressMonitor);
var colorConverter = IColorConverterTransform.create(jawsMako);
transformChain.pushTransform(colorConverter);
JAVA
// Create transforms
var customImpl = new EmptyTransformImplementation(jawsMako);
var customTransform = ICustomTransform.create(jawsMako, customImpl);
customTransform.setProgressMonitor(cvtParams.customTransformProgressMonitor);

var ccTransform = IColorConverterTransform.create(jawsMako);
var deviceCmyk = IDOMColorSpaceDeviceCMYK.create(jawsMako.getFactory());
ccTransform.setTargetSpace(deviceCmyk);
ccTransform.setProgressMonitor(cvtParams.transformProgressMonitor);

var transformChain = ITransformChain.create(jawsMako, cvtParams.transformChainProgressMonitor);
var colorConverter = IColorConverterTransform.create(jawsMako);
transformChain.pushTransform(colorConverter);
PY
# Create transforms
custom_impl = EmptyTransformImplementation(jaws_mako)
custom_transform = ICustomTransform.create(jaws_mako, custom_impl)
custom_transform.setProgressMonitor(cvt_params.custom_transform_progress_monitor)

cc_transform = IColorConverterTransform.create(jaws_mako)
device_cmyk = IDOMColorSpaceDeviceCMYK.create(jaws_mako.getFactory())
cc_transform.setTargetSpace(device_cmyk)
cc_transform.setProgressMonitor(cvt_params.transform_progress_monitor)

transform_chain = ITransformChain.create(jaws_mako, cvt_params.transform_chain_progress_monitor)
color_converter = IColorConverterTransform.create(jaws_mako)
transform_chain.pushTransform(color_converter)
JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.