* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "table/Table.h"
#include <new>
class TableField : public BField {
public:
TableField(int32 rowIndex)
:
fRowIndex(rowIndex)
{
}
int32 RowIndex() const
{
return fRowIndex;
}
void SetRowIndex(int32 rowIndex)
{
fRowIndex = rowIndex;
}
private:
int32 fRowIndex;
};
TableModelListener::~TableModelListener()
{
}
void
TableModelListener::TableRowsAdded(TableModel* model, int32 rowIndex,
int32 count)
{
}
void
TableModelListener::TableRowsRemoved(TableModel* model, int32 rowIndex,
int32 count)
{
}
void
TableModelListener::TableRowsChanged(TableModel* model, int32 rowIndex,
int32 count)
{
}
void
TableModelListener::TableModelReset(TableModel* model)
{
}
TableModel::~TableModel()
{
}
bool
TableModel::AddListener(TableModelListener* listener)
{
return fListeners.AddItem(listener);
}
void
TableModel::RemoveListener(TableModelListener* listener)
{
fListeners.RemoveItem(listener);
}
void
TableModel::NotifyRowsAdded(int32 rowIndex, int32 count)
{
int32 listenerCount = fListeners.CountItems();
for (int32 i = listenerCount - 1; i >= 0; i--) {
TableModelListener* listener = fListeners.ItemAt(i);
listener->TableRowsAdded(this, rowIndex, count);
}
}
void
TableModel::NotifyRowsRemoved(int32 rowIndex, int32 count)
{
int32 listenerCount = fListeners.CountItems();
for (int32 i = listenerCount - 1; i >= 0; i--) {
TableModelListener* listener = fListeners.ItemAt(i);
listener->TableRowsRemoved(this, rowIndex, count);
}
}
void
TableModel::NotifyRowsChanged(int32 rowIndex, int32 count)
{
int32 listenerCount = fListeners.CountItems();
for (int32 i = listenerCount - 1; i >= 0; i--) {
TableModelListener* listener = fListeners.ItemAt(i);
listener->TableRowsChanged(this, rowIndex, count);
}
}
void
TableModel::NotifyTableModelReset()
{
int32 listenerCount = fListeners.CountItems();
for (int32 i = listenerCount - 1; i >= 0; i--) {
TableModelListener* listener = fListeners.ItemAt(i);
listener->TableModelReset(this);
}
}
TableSelectionModel::TableSelectionModel(Table* table)
:
fTable(table),
fRows(NULL),
fRowCount(-1)
{
}
TableSelectionModel::~TableSelectionModel()
{
delete[] fRows;
}
int32
TableSelectionModel::CountRows()
{
_Update();
return fRowCount;
}
int32
TableSelectionModel::RowAt(int32 index)
{
_Update();
return index >= 0 && index < fRowCount ? fRows[index] : -1;
}
void
TableSelectionModel::_SelectionChanged()
{
if (fRowCount >= 0) {
fRowCount = -1;
delete[] fRows;
fRows = NULL;
}
}
void
TableSelectionModel::_Update()
{
if (fRowCount >= 0)
return;
fRowCount = 0;
BRow* row = NULL;
while ((row = fTable->CurrentSelection(row)) != NULL)
fRowCount++;
if (fRowCount == 0)
return;
fRows = new(std::nothrow) int32[fRowCount];
if (fRows == NULL) {
fRowCount = 0;
return;
}
row = NULL;
int32 index = 0;
while ((row = fTable->CurrentSelection(row)) != NULL)
fRows[index++] = fTable->_ModelIndexOfRow(row);
}
TableToolTipProvider::~TableToolTipProvider()
{
}
TableListener::~TableListener()
{
}
void
TableListener::TableSelectionChanged(Table* table)
{
}
void
TableListener::TableRowInvoked(Table* table, int32 rowIndex)
{
}
void
TableListener::TableCellMouseDown(Table* table, int32 rowIndex,
int32 columnIndex, BPoint screenWhere, uint32 buttons)
{
}
void
TableListener::TableCellMouseUp(Table* table, int32 rowIndex, int32 columnIndex,
BPoint screenWhere, uint32 buttons)
{
}
class Table::Column : public AbstractColumn {
public:
Column(TableModel* model,
TableColumn* tableColumn);
virtual ~Column();
virtual void SetModel(AbstractTableModelBase* model);
protected:
virtual void DrawTitle(BRect rect, BView* targetView);
virtual void DrawField(BField* field, BRect rect,
BView* targetView);
virtual int CompareFields(BField* field1, BField* field2);
virtual void GetColumnName(BString* into) const;
virtual float GetPreferredWidth(BField* field,
BView* parent) const;
private:
TableModel* fModel;
};
Table::Column::Column(TableModel* model, TableColumn* tableColumn)
:
AbstractColumn(tableColumn),
fModel(model)
{
}
Table::Column::~Column()
{
}
void
Table::Column::SetModel(AbstractTableModelBase* model)
{
fModel = dynamic_cast<TableModel*>(model);
}
void
Table::Column::DrawTitle(BRect rect, BView* targetView)
{
fTableColumn->DrawTitle(rect, targetView);
}
void
Table::Column::DrawField(BField* _field, BRect rect, BView* targetView)
{
TableField* field = dynamic_cast<TableField*>(_field);
if (field == NULL)
return;
int32 modelIndex = fTableColumn->ModelIndex();
BVariant value;
if (!fModel->GetValueAt(field->RowIndex(), modelIndex, value))
return;
fTableColumn->DrawValue(value, rect, targetView);
}
int
Table::Column::CompareFields(BField* _field1, BField* _field2)
{
TableField* field1 = dynamic_cast<TableField*>(_field1);
TableField* field2 = dynamic_cast<TableField*>(_field2);
if (field1 == field2)
return 0;
if (field1 == NULL)
return -1;
if (field2 == NULL)
return 1;
int32 modelIndex = fTableColumn->ModelIndex();
BVariant value1;
bool valid1 = fModel->GetValueAt(field1->RowIndex(), modelIndex, value1);
BVariant value2;
bool valid2 = fModel->GetValueAt(field2->RowIndex(), modelIndex, value2);
if (!valid1)
return valid2 ? -1 : 0;
if (!valid2)
return 1;
return fTableColumn->CompareValues(value1, value2);
}
void
Table::Column::GetColumnName(BString* into) const
{
fTableColumn->GetColumnName(into);
}
float
Table::Column::GetPreferredWidth(BField* _field, BView* parent) const
{
TableField* field = dynamic_cast<TableField*>(_field);
if (field == NULL)
return Width();
int32 modelIndex = fTableColumn->ModelIndex();
BVariant value;
if (!fModel->GetValueAt(field->RowIndex(), modelIndex, value))
return Width();
return fTableColumn->GetPreferredWidth(value, parent);
}
Table::Table(const char* name, uint32 flags, border_style borderStyle,
bool showHorizontalScrollbar)
:
AbstractTable(name, flags, borderStyle, showHorizontalScrollbar),
fModel(NULL),
fToolTipProvider(NULL),
fSelectionModel(this),
fIgnoreSelectionChange(0)
{
}
Table::Table(TableModel* model, const char* name, uint32 flags,
border_style borderStyle, bool showHorizontalScrollbar)
:
AbstractTable(name, flags, borderStyle, showHorizontalScrollbar),
fModel(NULL),
fToolTipProvider(NULL),
fSelectionModel(this),
fIgnoreSelectionChange(0)
{
SetTableModel(model);
}
Table::~Table()
{
}
void
Table::SetTableModel(TableModel* model)
{
if (model == fModel)
return;
if (fModel != NULL) {
fModel->RemoveListener(this);
fRows.MakeEmpty();
Clear();
for (int32 i = 0; AbstractColumn* column = fColumns.ItemAt(i); i++)
column->SetModel(NULL);
}
fModel = model;
if (fModel == NULL)
return;
fModel->AddListener(this);
for (int32 i = 0; AbstractColumn* column = fColumns.ItemAt(i); i++)
column->SetModel(fModel);
TableRowsAdded(fModel, 0, fModel->CountRows());
}
void
Table::SetToolTipProvider(TableToolTipProvider* toolTipProvider)
{
fToolTipProvider = toolTipProvider;
}
TableSelectionModel*
Table::SelectionModel()
{
return &fSelectionModel;
}
void
Table::SelectRow(int32 rowIndex, bool extendSelection)
{
BRow* row = fRows.ItemAt(rowIndex);
if (row == NULL)
return;
if (!extendSelection) {
fIgnoreSelectionChange++;
DeselectAll();
fIgnoreSelectionChange--;
}
AddToSelection(row);
}
void
Table::DeselectRow(int32 rowIndex)
{
if (BRow* row = fRows.ItemAt(rowIndex))
Deselect(row);
}
void
Table::DeselectAllRows()
{
DeselectAll();
}
bool
Table::AddTableListener(TableListener* listener)
{
return fListeners.AddItem(listener);
}
void
Table::RemoveTableListener(TableListener* listener)
{
fListeners.RemoveItem(listener);
}
status_t
Table::GetCellRectAt(int32 rowIndex, int32 colIndex, BRect& _output) const
{
BRow* row = fRows.ItemAt(rowIndex);
if (row == NULL)
return B_ENTRY_NOT_FOUND;
AbstractColumn* column = fColumns.ItemAt(colIndex);
if (column == NULL)
return B_ENTRY_NOT_FOUND;
_output = GetFieldRect(row, column);
return B_OK;
}
bool
Table::GetToolTipAt(BPoint point, BToolTip** _tip)
{
if (fToolTipProvider == NULL)
return AbstractTable::GetToolTipAt(point, _tip);
BRow* row = RowAt(point);
int32 rowIndex = row != NULL ? _ModelIndexOfRow(row) : -1;
if (rowIndex < 0)
return AbstractTable::GetToolTipAt(point, _tip);
BColumn* column = ColumnAt(point);
int32 columnIndex = column != NULL ? column->LogicalFieldNum() : -1;
return fToolTipProvider->GetToolTipForTableCell(rowIndex, columnIndex,
_tip);
}
void
Table::SelectionChanged()
{
if (fIgnoreSelectionChange > 0)
return;
fSelectionModel._SelectionChanged();
if (!fListeners.IsEmpty()) {
int32 listenerCount = fListeners.CountItems();
for (int32 i = listenerCount - 1; i >= 0; i--)
fListeners.ItemAt(i)->TableSelectionChanged(this);
}
}
AbstractTable::AbstractColumn*
Table::CreateColumn(TableColumn* column)
{
return new Column(fModel, column);
}
void
Table::ColumnMouseDown(AbstractColumn* column, BRow* row, BField* field,
BPoint screenWhere, uint32 buttons)
{
if (!fListeners.IsEmpty()) {
int32 rowIndex = _ModelIndexOfRow(row);
int32 columnIndex = column->LogicalFieldNum();
if (rowIndex < 0 || columnIndex < 0)
return;
int32 listenerCount = fListeners.CountItems();
for (int32 i = listenerCount - 1; i >= 0; i--) {
fListeners.ItemAt(i)->TableCellMouseDown(this, rowIndex,
columnIndex, screenWhere, buttons);
}
}
}
void
Table::ColumnMouseUp(AbstractColumn* column, BRow* row, BField* field,
BPoint screenWhere, uint32 buttons)
{
if (!fListeners.IsEmpty()) {
int32 rowIndex = _ModelIndexOfRow(row);
int32 columnIndex = column->LogicalFieldNum();
if (rowIndex < 0 || columnIndex < 0)
return;
int32 listenerCount = fListeners.CountItems();
for (int32 i = listenerCount - 1; i >= 0; i--) {
fListeners.ItemAt(i)->TableCellMouseUp(this, rowIndex, columnIndex,
screenWhere, buttons);
}
}
}
void
Table::TableRowsAdded(TableModel* model, int32 rowIndex, int32 count)
{
int32 endRow = rowIndex + count;
int32 columnCount = fModel->CountColumns();
for (int32 i = rowIndex; i < endRow; i++) {
BRow* row = new(std::nothrow) BRow();
if (row == NULL) {
return;
}
for (int32 columnIndex = 0; columnIndex < columnCount; columnIndex++) {
TableField* field = new(std::nothrow) TableField(i);
if (field == NULL) {
delete row;
return;
}
row->SetField(field, columnIndex);
}
if (!fRows.AddItem(row, i)) {
delete row;
return;
}
AddRow(row, i);
}
_UpdateRowIndices(endRow);
}
void
Table::TableRowsRemoved(TableModel* model, int32 rowIndex, int32 count)
{
if (rowIndex == 0 && count == fRows.CountItems()) {
fRows.MakeEmpty();
Clear();
return;
}
for (int32 i = rowIndex + count - 1; i >= rowIndex; i--) {
if (BRow* row = fRows.RemoveItemAt(i)) {
RemoveRow(row);
delete row;
}
}
_UpdateRowIndices(rowIndex);
}
void
Table::TableRowsChanged(TableModel* model, int32 rowIndex, int32 count)
{
int32 endIndex = rowIndex + count;
for (int32 i = rowIndex; i < endIndex; i++) {
if (BRow* row = fRows.ItemAt(i))
UpdateRow(row);
}
}
void
Table::TableModelReset(TableModel* model)
{
Clear();
TableRowsAdded(model, 0, model->CountRows());
}
void
Table::ItemInvoked()
{
if (fListeners.IsEmpty())
return;
int32 index = _ModelIndexOfRow(CurrentSelection());
if (index < 0)
return;
int32 listenerCount = fListeners.CountItems();
for (int32 i = listenerCount - 1; i >= 0; i--)
fListeners.ItemAt(i)->TableRowInvoked(this, index);
}
void
Table::_UpdateRowIndices(int32 fromIndex)
{
for (int32 i = fromIndex; BRow* row = fRows.ItemAt(i); i++) {
for (int32 k = 0;
TableField* field = dynamic_cast<TableField*>(row->GetField(k));
k++) {
field->SetRowIndex(i);
}
}
}
int32
Table::_ModelIndexOfRow(BRow* row)
{
if (row == NULL)
return -1;
TableField* field = dynamic_cast<TableField*>(row->GetField(0));
if (field == NULL)
return -1;
return field->RowIndex();
}