C

Qt Quick Ultralite listmodel Example

// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#pragma once
#include "qul/listproperty.h"
#include <qul/model.h>
#include <platforminterface/allocator.h>

#include <string>
#include <limits>
#include <cstdlib>

// To create a custom ListModel<T>, we need to declare a type T that holds
// the data for each element and is equality comparable.
//
// Here, the data type is AlarmData and it holds the number of seconds before
// the alarm should trigger (negative if it has already triggered), as well
// as a running flag.
struct AlarmData
{
    AlarmData()
        : seconds(0)
        , running(false)
    {}

    AlarmData(int argSeconds, bool argRunning)
        : seconds(argSeconds)
        , running(argRunning)
    {}

    int seconds;
    bool running;
};

inline bool operator==(const AlarmData &lhs, const AlarmData &rhs)
{
    return lhs.seconds == rhs.seconds && lhs.running == rhs.running;
}

// Declare our AlarmModel.
//
// The only requirement is that we implement the pure virtual functions
// count() and data() from ListModel.
//
// We add the other functions to allow our UI to affect the model.
struct AlarmModel : Qul::ListModel<AlarmData>
{
private:
    Qul::DynamicList<AlarmData> m_data;

public:
    // Implement the ListModel interface
    int count() const QUL_DECL_OVERRIDE { return m_data.count(); }
    AlarmData data(int index) const QUL_DECL_OVERRIDE { return m_data[index]; }

    // Construct the model with some example data.
    AlarmModel()
    {
        m_data.append(AlarmData(-5, false));
        m_data.append(AlarmData(11, false));
        m_data.append(AlarmData(23, true));
    }

    // Our app shows a "Pause"/"Unpause" button on each alarm entry.
    // This applies the requested state change to the model and then
    // informs the view about the change with the dataChanged() call.
    void togglePause(int index)
    {
        m_data.at(index).running = !m_data[index].running;
        dataChanged(index);
    }

    // There is a button to remove an alarm entry. This function removes
    // the data for the entry and then calls modelReset() to inform the
    // view that the number of entries in the model has changed.
    void remove(int index)
    {
        m_data.removeAt(index);
        modelReset();
    }

    // Adding a new alarm entry is similar to removing one above.
    void addEntry(int seconds)
    {
        m_data.append(AlarmData(seconds, true));
        modelReset();
    }

    // A Timer calls this function on the model every second to update
    // the state of the alarms.
    void tick()
    {
        for (int i = 0; i < m_data.count(); ++i) {
            AlarmData &entry = m_data.at(i);
            if (entry.running || entry.seconds <= 0) {
                entry.seconds--;
                dataChanged(i);
            }
        }
    }
};