Newer
Older
WickedDocs / Framework / GenericTable.h
#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((QVariant::Type)va_arg(args, int));
      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