Skip to main content
Skip table of contents

Using IProgressEventHandler to Report Progress When Saving a File

📌 Overview

This article explains how to use the new IProgressEventHandler API to report progress when saving a file in Mako. It also compares this new event-based mechanism with the existing tick-based IProgressTick approach, described in Progress Monitoring in Mako, which is commonly used for progress reporting in custom transforms.

ℹ️ Key Concepts: IProgressEventHandler vs IProgressTick

Feature

IProgressTick

IProgressEventHandler

Reporting Style

Tick-based (integer/float increments)

Event-based (specific operation events)

Typical Use

Custom transforms

Saving files

Callback Signature

tick(currentCount, maxCount)

handleEvent(Event evt)

Events Supported

None (just ticks)

Page write start/end, node write start/end

Integration

IProgressMonitor::create(const IProgressTickPtr &progressTick)

IProgressMonitor::setProgressEventHandler(const IProgressEventHandlerPtr &progressEventHandler)

Granularity

Coarse (progress bar style)

Fine (event-driven, detailed)

💪 Usage

  • Use IProgressTick for simple, linear progress reporting (e.g., custom transforms where only a percentage or tick count is needed).

  • Use IProgressEventHandler for more detailed, event-driven reporting (e.g., when you want to track the start/end of pages or nodes during file save operations).

⌨️ Code Examples

1. Tick-Based Progress Reporting with IProgressTick - extract from ProgressMonitoring.cpp.

CPP
class ProgressHandler {
public:
    // This section should be customised
    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
    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;
    IProgressTickPtr m_progressTick;
};

2. Event-Based Progress Reporting with IProgressEventHandler - extract from ProgressEventHandling.cpp

CPP
class ProgressEventHandler {
public:
    // This section should be customised
    ProgressEventHandler() : m_pageCount(0), m_nodeCount(0), m_nodeDepth(0) {}
    void handleEvent(IProgressEventHandler::Event evt) {
        int id;
        switch (evt) {
        case IProgressEventHandler::eEvtPageWriteStart:
            m_pageCount++;
            m_nodeCount = 0;
            m_nodeDepth = 0;
            m_nodes.clear();
            printf("start of page %d\n", m_pageCount);
            break;
        case IProgressEventHandler::eEvtPageWriteEnd:
            printf("end of page %d, got %d node events\n", m_pageCount, m_nodeCount);
            if (m_nodeDepth != 0) printf("mismatch in node write start/end %d\n", m_nodeDepth);
            break;
        case IProgressEventHandler::eEvtNodeWriteStart:
            id = ++m_nodeCount;
            m_nodeDepth++;
            m_nodes.push_back(id);
            if (id % 500 == 0) {
                printf("start of node %d\n", id);
            }
            break;
        case IProgressEventHandler::eEvtNodeWriteEnd:
            m_nodeDepth--;
            if (m_nodes.empty())
                printf("mismatch, empty nodes\n");
            else {
                id = m_nodes.back();
                m_nodes.pop_back();
                if (id % 500 == 0) {
                    printf("end of node %d\n", id);
                }
            }
            break;
        default:
            break;
        }
    }
    // Everything below this part can be reused
    static std::shared_ptr<ProgressEventHandler> create() {
        std::shared_ptr<ProgressEventHandler> progressEventHandler = std::make_shared<ProgressEventHandler>();
        progressEventHandler->m_progressEventHandler = IProgressEventHandler::create(callback, progressEventHandler.get());
        return progressEventHandler;
    }
    int m_pageCount;
    int m_nodeCount;
    int m_nodeDepth;
    std::deque<int> m_nodes;
    IProgressEventHandlerPtr m_progressEventHandler;
protected:
    static void callback(void* priv, IProgressEventHandler::Event evt) {
        ProgressEventHandler* progressEventHandler = (ProgressEventHandler*)priv;
        if (progressEventHandler)
            progressEventHandler->handleEvent(evt);
    }
};

Integration Example: Saving a File with Progress Events

CPP
// Create a progress monitor and set the event handler
IProgressMonitorPtr monitor = IProgressMonitor::create(IAbortPtr());
auto handler = ProgressEventHandler::create();
monitor->setProgressEventHandler(handler->m_progressEventHandler);

// Pass the monitor to IOutput::create() when saving a file
IOutputPtr output = IOutput::create(..., monitor, ...);

☑️ Conclusion

The IProgressEventHandler API provides a more flexible and granular way to report progress when saving files. For legacy or simple scenarios, IProgressTick remains available. Choose the mechanism that best fits your reporting needs.

📚 Additional Resources

If you need additional help, see our API documentation for detailed information on class/method usage, or raise a support ticket via our customer portal.

JavaScript errors detected

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

If this problem persists, please contact our support.