1 /* 2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include "table/Table.h" 7 8 #include <new> 9 10 11 // #pragma mark - TableField 12 13 14 class TableField : public BField { 15 public: 16 TableField(int32 rowIndex) 17 : 18 fRowIndex(rowIndex) 19 { 20 } 21 22 int32 RowIndex() const 23 { 24 return fRowIndex; 25 } 26 27 void SetRowIndex(int32 rowIndex) 28 { 29 fRowIndex = rowIndex; 30 } 31 32 private: 33 int32 fRowIndex; 34 }; 35 36 37 // #pragma mark - TableModelListener 38 39 40 TableModelListener::~TableModelListener() 41 { 42 } 43 44 45 void 46 TableModelListener::TableRowsAdded(TableModel* model, int32 rowIndex, 47 int32 count) 48 { 49 } 50 51 52 void 53 TableModelListener::TableRowsRemoved(TableModel* model, int32 rowIndex, 54 int32 count) 55 { 56 } 57 58 59 void 60 TableModelListener::TableRowsChanged(TableModel* model, int32 rowIndex, 61 int32 count) 62 { 63 } 64 65 66 void 67 TableModelListener::TableModelReset(TableModel* model) 68 { 69 } 70 71 72 // #pragma mark - TableModel 73 74 75 TableModel::~TableModel() 76 { 77 } 78 79 80 bool 81 TableModel::AddListener(TableModelListener* listener) 82 { 83 return fListeners.AddItem(listener); 84 } 85 86 87 void 88 TableModel::RemoveListener(TableModelListener* listener) 89 { 90 fListeners.RemoveItem(listener); 91 } 92 93 94 void 95 TableModel::NotifyRowsAdded(int32 rowIndex, int32 count) 96 { 97 int32 listenerCount = fListeners.CountItems(); 98 for (int32 i = listenerCount - 1; i >= 0; i--) { 99 TableModelListener* listener = fListeners.ItemAt(i); 100 listener->TableRowsAdded(this, rowIndex, count); 101 } 102 } 103 104 105 void 106 TableModel::NotifyRowsRemoved(int32 rowIndex, int32 count) 107 { 108 int32 listenerCount = fListeners.CountItems(); 109 for (int32 i = listenerCount - 1; i >= 0; i--) { 110 TableModelListener* listener = fListeners.ItemAt(i); 111 listener->TableRowsRemoved(this, rowIndex, count); 112 } 113 } 114 115 116 void 117 TableModel::NotifyRowsChanged(int32 rowIndex, int32 count) 118 { 119 int32 listenerCount = fListeners.CountItems(); 120 for (int32 i = listenerCount - 1; i >= 0; i--) { 121 TableModelListener* listener = fListeners.ItemAt(i); 122 listener->TableRowsChanged(this, rowIndex, count); 123 } 124 } 125 126 127 void 128 TableModel::NotifyTableModelReset() 129 { 130 int32 listenerCount = fListeners.CountItems(); 131 for (int32 i = listenerCount - 1; i >= 0; i--) { 132 TableModelListener* listener = fListeners.ItemAt(i); 133 listener->TableModelReset(this); 134 } 135 } 136 137 138 // #pragma mark - TableSelectionModel 139 140 TableSelectionModel::TableSelectionModel(Table* table) 141 : 142 fTable(table), 143 fRows(NULL), 144 fRowCount(-1) 145 { 146 } 147 148 149 TableSelectionModel::~TableSelectionModel() 150 { 151 delete[] fRows; 152 } 153 154 155 int32 156 TableSelectionModel::CountRows() 157 { 158 _Update(); 159 160 return fRowCount; 161 } 162 163 164 int32 165 TableSelectionModel::RowAt(int32 index) 166 { 167 _Update(); 168 169 return index >= 0 && index < fRowCount ? fRows[index] : -1; 170 } 171 172 173 void 174 TableSelectionModel::_SelectionChanged() 175 { 176 if (fRowCount >= 0) { 177 fRowCount = -1; 178 delete[] fRows; 179 fRows = NULL; 180 } 181 } 182 183 184 void 185 TableSelectionModel::_Update() 186 { 187 if (fRowCount >= 0) 188 return; 189 190 // count the rows 191 fRowCount = 0; 192 BRow* row = NULL; 193 while ((row = fTable->CurrentSelection(row)) != NULL) 194 fRowCount++; 195 196 if (fRowCount == 0) 197 return; 198 199 // allocate row array 200 fRows = new(std::nothrow) int32[fRowCount]; 201 if (fRows == NULL) { 202 fRowCount = 0; 203 return; 204 } 205 206 // get the rows 207 row = NULL; 208 int32 index = 0; 209 while ((row = fTable->CurrentSelection(row)) != NULL) 210 fRows[index++] = fTable->_ModelIndexOfRow(row); 211 } 212 213 214 // #pragma mark - TableToolTipProvider 215 216 217 TableToolTipProvider::~TableToolTipProvider() 218 { 219 } 220 221 222 // #pragma mark - TableListener 223 224 225 TableListener::~TableListener() 226 { 227 } 228 229 230 void 231 TableListener::TableSelectionChanged(Table* table) 232 { 233 } 234 235 236 void 237 TableListener::TableRowInvoked(Table* table, int32 rowIndex) 238 { 239 } 240 241 242 void 243 TableListener::TableCellMouseDown(Table* table, int32 rowIndex, 244 int32 columnIndex, BPoint screenWhere, uint32 buttons) 245 { 246 } 247 248 249 void 250 TableListener::TableCellMouseUp(Table* table, int32 rowIndex, int32 columnIndex, 251 BPoint screenWhere, uint32 buttons) 252 { 253 } 254 255 256 // #pragma mark - Column 257 258 259 class Table::Column : public AbstractColumn { 260 public: 261 Column(TableModel* model, 262 TableColumn* tableColumn); 263 virtual ~Column(); 264 265 virtual void SetModel(AbstractTableModelBase* model); 266 267 protected: 268 virtual void DrawTitle(BRect rect, BView* targetView); 269 virtual void DrawField(BField* field, BRect rect, 270 BView* targetView); 271 virtual int CompareFields(BField* field1, BField* field2); 272 273 virtual void GetColumnName(BString* into) const; 274 virtual float GetPreferredWidth(BField* field, 275 BView* parent) const; 276 277 private: 278 TableModel* fModel; 279 }; 280 281 282 Table::Column::Column(TableModel* model, TableColumn* tableColumn) 283 : 284 AbstractColumn(tableColumn), 285 fModel(model) 286 { 287 } 288 289 290 Table::Column::~Column() 291 { 292 } 293 294 295 void 296 Table::Column::SetModel(AbstractTableModelBase* model) 297 { 298 fModel = dynamic_cast<TableModel*>(model); 299 } 300 301 302 void 303 Table::Column::DrawTitle(BRect rect, BView* targetView) 304 { 305 fTableColumn->DrawTitle(rect, targetView); 306 } 307 308 309 void 310 Table::Column::DrawField(BField* _field, BRect rect, BView* targetView) 311 { 312 TableField* field = dynamic_cast<TableField*>(_field); 313 if (field == NULL) 314 return; 315 316 int32 modelIndex = fTableColumn->ModelIndex(); 317 BVariant value; 318 if (!fModel->GetValueAt(field->RowIndex(), modelIndex, value)) 319 return; 320 fTableColumn->DrawValue(value, rect, targetView); 321 } 322 323 324 int 325 Table::Column::CompareFields(BField* _field1, BField* _field2) 326 { 327 TableField* field1 = dynamic_cast<TableField*>(_field1); 328 TableField* field2 = dynamic_cast<TableField*>(_field2); 329 330 if (field1 == field2) 331 return 0; 332 333 if (field1 == NULL) 334 return -1; 335 if (field2 == NULL) 336 return 1; 337 338 int32 modelIndex = fTableColumn->ModelIndex(); 339 BVariant value1; 340 bool valid1 = fModel->GetValueAt(field1->RowIndex(), modelIndex, value1); 341 BVariant value2; 342 bool valid2 = fModel->GetValueAt(field2->RowIndex(), modelIndex, value2); 343 344 if (!valid1) 345 return valid2 ? -1 : 0; 346 if (!valid2) 347 return 1; 348 349 return fTableColumn->CompareValues(value1, value2); 350 } 351 352 353 void 354 Table::Column::GetColumnName(BString* into) const 355 { 356 fTableColumn->GetColumnName(into); 357 } 358 359 360 float 361 Table::Column::GetPreferredWidth(BField* _field, BView* parent) const 362 { 363 TableField* field = dynamic_cast<TableField*>(_field); 364 if (field == NULL) 365 return Width(); 366 367 int32 modelIndex = fTableColumn->ModelIndex(); 368 BVariant value; 369 if (!fModel->GetValueAt(field->RowIndex(), modelIndex, value)) 370 return Width(); 371 return fTableColumn->GetPreferredWidth(value, parent); 372 } 373 374 375 // #pragma mark - Table 376 377 378 Table::Table(const char* name, uint32 flags, border_style borderStyle, 379 bool showHorizontalScrollbar) 380 : 381 AbstractTable(name, flags, borderStyle, showHorizontalScrollbar), 382 fModel(NULL), 383 fToolTipProvider(NULL), 384 fSelectionModel(this), 385 fIgnoreSelectionChange(0) 386 { 387 } 388 389 390 Table::Table(TableModel* model, const char* name, uint32 flags, 391 border_style borderStyle, bool showHorizontalScrollbar) 392 : 393 AbstractTable(name, flags, borderStyle, showHorizontalScrollbar), 394 fModel(NULL), 395 fToolTipProvider(NULL), 396 fSelectionModel(this), 397 fIgnoreSelectionChange(0) 398 { 399 SetTableModel(model); 400 } 401 402 403 Table::~Table() 404 { 405 for (int32 i = CountColumns() - 1; i >= 0; i--) 406 RemoveColumn(ColumnAt(i)); 407 408 // rows are deleted by the BColumnListView destructor automatically 409 } 410 411 412 void 413 Table::SetTableModel(TableModel* model) 414 { 415 if (model == fModel) 416 return; 417 418 if (fModel != NULL) { 419 fModel->RemoveListener(this); 420 421 fRows.MakeEmpty(); 422 Clear(); 423 424 for (int32 i = 0; AbstractColumn* column = fColumns.ItemAt(i); i++) 425 column->SetModel(NULL); 426 } 427 428 fModel = model; 429 430 if (fModel == NULL) 431 return; 432 433 fModel->AddListener(this); 434 435 for (int32 i = 0; AbstractColumn* column = fColumns.ItemAt(i); i++) 436 column->SetModel(fModel); 437 438 TableRowsAdded(fModel, 0, fModel->CountRows()); 439 } 440 441 442 void 443 Table::SetToolTipProvider(TableToolTipProvider* toolTipProvider) 444 { 445 fToolTipProvider = toolTipProvider; 446 } 447 448 449 TableSelectionModel* 450 Table::SelectionModel() 451 { 452 return &fSelectionModel; 453 } 454 455 456 void 457 Table::SelectRow(int32 rowIndex, bool extendSelection) 458 { 459 BRow* row = fRows.ItemAt(rowIndex); 460 if (row == NULL) 461 return; 462 463 if (!extendSelection) { 464 fIgnoreSelectionChange++; 465 DeselectAll(); 466 fIgnoreSelectionChange--; 467 } 468 469 AddToSelection(row); 470 } 471 472 473 void 474 Table::DeselectRow(int32 rowIndex) 475 { 476 if (BRow* row = fRows.ItemAt(rowIndex)) 477 Deselect(row); 478 } 479 480 481 void 482 Table::DeselectAllRows() 483 { 484 DeselectAll(); 485 } 486 487 488 bool 489 Table::AddTableListener(TableListener* listener) 490 { 491 return fListeners.AddItem(listener); 492 } 493 494 495 void 496 Table::RemoveTableListener(TableListener* listener) 497 { 498 fListeners.RemoveItem(listener); 499 } 500 501 502 bool 503 Table::GetToolTipAt(BPoint point, BToolTip** _tip) 504 { 505 if (fToolTipProvider == NULL) 506 return AbstractTable::GetToolTipAt(point, _tip); 507 508 // get the table row 509 BRow* row = RowAt(point); 510 int32 rowIndex = row != NULL ? _ModelIndexOfRow(row) : -1; 511 if (rowIndex < 0) 512 return AbstractTable::GetToolTipAt(point, _tip); 513 514 // get the table column 515 BColumn* column = ColumnAt(point); 516 int32 columnIndex = column != NULL ? column->LogicalFieldNum() : -1; 517 518 return fToolTipProvider->GetToolTipForTableCell(rowIndex, columnIndex, 519 _tip); 520 } 521 522 523 void 524 Table::SelectionChanged() 525 { 526 if (fIgnoreSelectionChange > 0) 527 return; 528 529 fSelectionModel._SelectionChanged(); 530 531 if (!fListeners.IsEmpty()) { 532 int32 listenerCount = fListeners.CountItems(); 533 for (int32 i = listenerCount - 1; i >= 0; i--) 534 fListeners.ItemAt(i)->TableSelectionChanged(this); 535 } 536 } 537 538 539 AbstractTable::AbstractColumn* 540 Table::CreateColumn(TableColumn* column) 541 { 542 return new Column(fModel, column); 543 } 544 545 546 void 547 Table::ColumnMouseDown(AbstractColumn* column, BRow* row, BField* field, 548 BPoint screenWhere, uint32 buttons) 549 { 550 if (!fListeners.IsEmpty()) { 551 // get the table row and column indices 552 int32 rowIndex = _ModelIndexOfRow(row); 553 int32 columnIndex = column->LogicalFieldNum(); 554 if (rowIndex < 0 || columnIndex < 0) 555 return; 556 557 // notify listeners 558 int32 listenerCount = fListeners.CountItems(); 559 for (int32 i = listenerCount - 1; i >= 0; i--) { 560 fListeners.ItemAt(i)->TableCellMouseDown(this, rowIndex, 561 columnIndex, screenWhere, buttons); 562 } 563 } 564 } 565 566 567 void 568 Table::ColumnMouseUp(AbstractColumn* column, BRow* row, BField* field, 569 BPoint screenWhere, uint32 buttons) 570 { 571 if (!fListeners.IsEmpty()) { 572 // get the table row and column indices 573 int32 rowIndex = _ModelIndexOfRow(row); 574 int32 columnIndex = column->LogicalFieldNum(); 575 if (rowIndex < 0 || columnIndex < 0) 576 return; 577 578 // notify listeners 579 int32 listenerCount = fListeners.CountItems(); 580 for (int32 i = listenerCount - 1; i >= 0; i--) { 581 fListeners.ItemAt(i)->TableCellMouseUp(this, rowIndex, columnIndex, 582 screenWhere, buttons); 583 } 584 } 585 } 586 587 588 void 589 Table::TableRowsAdded(TableModel* model, int32 rowIndex, int32 count) 590 { 591 // create the rows 592 int32 endRow = rowIndex + count; 593 int32 columnCount = fModel->CountColumns(); 594 595 for (int32 i = rowIndex; i < endRow; i++) { 596 // create row 597 BRow* row = new(std::nothrow) BRow(); 598 if (row == NULL) { 599 // TODO: Report error! 600 return; 601 } 602 603 // add dummy fields to row 604 for (int32 columnIndex = 0; columnIndex < columnCount; columnIndex++) { 605 // It would be nice to create only a single field and set it for all 606 // columns, but the row takes ultimate ownership, so it have to be 607 // individual objects. 608 TableField* field = new(std::nothrow) TableField(i); 609 if (field == NULL) { 610 // TODO: Report error! 611 delete row; 612 return; 613 } 614 615 row->SetField(field, columnIndex); 616 } 617 618 // add row 619 if (!fRows.AddItem(row, i)) { 620 // TODO: Report error! 621 delete row; 622 return; 623 } 624 625 AddRow(row, i); 626 } 627 628 // re-index the subsequent rows 629 _UpdateRowIndices(endRow); 630 } 631 632 633 void 634 Table::TableRowsRemoved(TableModel* model, int32 rowIndex, int32 count) 635 { 636 if (rowIndex == 0 && count == fRows.CountItems()) { 637 fRows.MakeEmpty(); 638 Clear(); 639 return; 640 } 641 642 for (int32 i = rowIndex + count - 1; i >= rowIndex; i--) { 643 if (BRow* row = fRows.RemoveItemAt(i)) { 644 RemoveRow(row); 645 delete row; 646 } 647 } 648 649 // re-index the subsequent rows 650 _UpdateRowIndices(rowIndex); 651 } 652 653 654 void 655 Table::TableRowsChanged(TableModel* model, int32 rowIndex, int32 count) 656 { 657 int32 endIndex = rowIndex + count; 658 for (int32 i = rowIndex; i < endIndex; i++) { 659 if (BRow* row = fRows.ItemAt(i)) 660 UpdateRow(row); 661 } 662 } 663 664 665 void 666 Table::TableModelReset(TableModel* model) 667 { 668 Clear(); 669 TableRowsAdded(model, 0, model->CountRows()); 670 } 671 672 673 void 674 Table::ItemInvoked() 675 { 676 if (fListeners.IsEmpty()) 677 return; 678 679 int32 index = _ModelIndexOfRow(CurrentSelection()); 680 if (index < 0) 681 return; 682 683 int32 listenerCount = fListeners.CountItems(); 684 for (int32 i = listenerCount - 1; i >= 0; i--) 685 fListeners.ItemAt(i)->TableRowInvoked(this, index); 686 } 687 688 689 void 690 Table::_UpdateRowIndices(int32 fromIndex) 691 { 692 for (int32 i = fromIndex; BRow* row = fRows.ItemAt(i); i++) { 693 for (int32 k = 0; 694 TableField* field = dynamic_cast<TableField*>(row->GetField(k)); 695 k++) { 696 field->SetRowIndex(i); 697 } 698 } 699 } 700 701 702 int32 703 Table::_ModelIndexOfRow(BRow* row) 704 { 705 if (row == NULL) 706 return -1; 707 708 TableField* field = dynamic_cast<TableField*>(row->GetField(0)); 709 if (field == NULL) 710 return -1; 711 712 return field->RowIndex(); 713 } 714