#ifndef GENERIC_TABLE_H
#define GENERIC_TABLE_H
#include <string>
#include <vector>
#include <stdarg.h>
#include <stdint.h>
#include <QVariant>
#include "NonCopyable.h"
class GenericTableBase
{
public:
GenericTableBase(bool a_readOnly)
{
m_callbackData = 0;
m_updateCallback = 0;
m_readOnly = a_readOnly;
m_currentRow = -1;
}
virtual ~GenericTableBase() {}
virtual void notifyObservers() {}
virtual void dropData(const char* a_string) {}
virtual size_t size() { return 0; }
virtual QVariant value(int a_row, int a_column) const { return "Invalid"; }
virtual void setValue(int a_row, int a_column, const QVariant& a_value) {}
// No need to call this directly, it should be called and hooked up by the UI code for the table
void RegisterCallbackOnChange(void(*a_callback)(void *data), void* a_callbackData)
{
m_updateCallback = a_callback;
m_callbackData = a_callbackData;
}
// Column names/titles
std::vector<std::string> m_columnNames;
std::vector<QVariant::Type> m_columnTypes;
bool m_readOnly;
int m_currentRow;
void(*m_updateCallback)(void* data);
void* m_callbackData;
};
template <typename RowType>
class GenericTable : public GenericTableBase
{
public:
// When using, terminate argument list with an argument of 0
GenericTable(bool a_readOnly, const char* a_str1 = 0, ...) : GenericTableBase(a_readOnly)
{
va_list args;
va_start(args, a_str1);
const char* str = a_str1;
while (str)
{
m_columnNames.push_back(std::string(str));
m_columnTypes.push_back(va_arg(args, QVariant::Type));
str = va_arg(args, const char*);
}
va_end(args);
}
void push_back(RowType item)
{
m_data.push_back(item);
}
size_t size()
{
return m_data.size();
}
QVariant value(int a_row, int a_column) const
{
return m_data[a_row].value(a_column);
}
void setValue(int a_row, int a_column, const QVariant& a_value)
{
updateData(a_row, a_column, a_value);
}
bool updateData(uint32_t a_row, uint32_t a_column, const QVariant& a_val)
{
if (m_readOnly)
return false;
m_data[a_row].setValue(a_column, a_val);
if (m_updateCallback)
m_updateCallback(m_callbackData);
notifyObservers();
return true;
}
// When making changes to the table, create a Transaction object at the
// beginning of the code block that surrounds the code that is making the changes
// (currently everything is assumed to be single threaded)
class Transaction : private NonCopyable
{
public:
explicit Transaction(GenericTable<RowType>& a_parent) : m_parent(a_parent) {}
~Transaction() { if (m_parent.m_updateCallback) m_parent.m_updateCallback(m_parent.m_callbackData); }
private:
GenericTable<RowType>& m_parent;
};
private:
std::vector<RowType> m_data;
};
#endif // GENERIC_TABLE_H