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 status_t 503 Table::GetCellRectAt(int32 rowIndex, int32 colIndex, BRect& _output) const 504 { 505 BRow* row = fRows.ItemAt(rowIndex); 506 if (row == NULL) 507 return B_ENTRY_NOT_FOUND; 508 509 AbstractColumn* column = fColumns.ItemAt(colIndex); 510 if (column == NULL) 511 return B_ENTRY_NOT_FOUND; 512 513 _output = GetFieldRect(row, column); 514 515 return B_OK; 516 } 517 518 519 bool 520 Table::GetToolTipAt(BPoint point, BToolTip** _tip) 521 { 522 if (fToolTipProvider == NULL) 523 return AbstractTable::GetToolTipAt(point, _tip); 524 525 // get the table row 526 BRow* row = RowAt(point); 527 int32 rowIndex = row != NULL ? _ModelIndexOfRow(row) : -1; 528 if (rowIndex < 0) 529 return AbstractTable::GetToolTipAt(point, _tip); 530 531 // get the table column 532 BColumn* column = ColumnAt(point); 533 int32 columnIndex = column != NULL ? column->LogicalFieldNum() : -1; 534 535 return fToolTipProvider->GetToolTipForTableCell(rowIndex, columnIndex, 536 _tip); 537 } 538 539 540 void 541 Table::SelectionChanged() 542 { 543 if (fIgnoreSelectionChange > 0) 544 return; 545 546 fSelectionModel._SelectionChanged(); 547 548 if (!fListeners.IsEmpty()) { 549 int32 listenerCount = fListeners.CountItems(); 550 for (int32 i = listenerCount - 1; i >= 0; i--) 551 fListeners.ItemAt(i)->TableSelectionChanged(this); 552 } 553 } 554 555 556 AbstractTable::AbstractColumn* 557 Table::CreateColumn(TableColumn* column) 558 { 559 return new Column(fModel, column); 560 } 561 562 563 void 564 Table::ColumnMouseDown(AbstractColumn* column, BRow* row, BField* field, 565 BPoint screenWhere, uint32 buttons) 566 { 567 if (!fListeners.IsEmpty()) { 568 // get the table row and column indices 569 int32 rowIndex = _ModelIndexOfRow(row); 570 int32 columnIndex = column->LogicalFieldNum(); 571 if (rowIndex < 0 || columnIndex < 0) 572 return; 573 574 // notify listeners 575 int32 listenerCount = fListeners.CountItems(); 576 for (int32 i = listenerCount - 1; i >= 0; i--) { 577 fListeners.ItemAt(i)->TableCellMouseDown(this, rowIndex, 578 columnIndex, screenWhere, buttons); 579 } 580 } 581 } 582 583 584 void 585 Table::ColumnMouseUp(AbstractColumn* column, BRow* row, BField* field, 586 BPoint screenWhere, uint32 buttons) 587 { 588 if (!fListeners.IsEmpty()) { 589 // get the table row and column indices 590 int32 rowIndex = _ModelIndexOfRow(row); 591 int32 columnIndex = column->LogicalFieldNum(); 592 if (rowIndex < 0 || columnIndex < 0) 593 return; 594 595 // notify listeners 596 int32 listenerCount = fListeners.CountItems(); 597 for (int32 i = listenerCount - 1; i >= 0; i--) { 598 fListeners.ItemAt(i)->TableCellMouseUp(this, rowIndex, columnIndex, 599 screenWhere, buttons); 600 } 601 } 602 } 603 604 605 void 606 Table::TableRowsAdded(TableModel* model, int32 rowIndex, int32 count) 607 { 608 // create the rows 609 int32 endRow = rowIndex + count; 610 int32 columnCount = fModel->CountColumns(); 611 612 for (int32 i = rowIndex; i < endRow; i++) { 613 // create row 614 BRow* row = new(std::nothrow) BRow(); 615 if (row == NULL) { 616 // TODO: Report error! 617 return; 618 } 619 620 // add dummy fields to row 621 for (int32 columnIndex = 0; columnIndex < columnCount; columnIndex++) { 622 // It would be nice to create only a single field and set it for all 623 // columns, but the row takes ultimate ownership, so it have to be 624 // individual objects. 625 TableField* field = new(std::nothrow) TableField(i); 626 if (field == NULL) { 627 // TODO: Report error! 628 delete row; 629 return; 630 } 631 632 row->SetField(field, columnIndex); 633 } 634 635 // add row 636 if (!fRows.AddItem(row, i)) { 637 // TODO: Report error! 638 delete row; 639 return; 640 } 641 642 AddRow(row, i); 643 } 644 645 // re-index the subsequent rows 646 _UpdateRowIndices(endRow); 647 } 648 649 650 void 651 Table::TableRowsRemoved(TableModel* model, int32 rowIndex, int32 count) 652 { 653 if (rowIndex == 0 && count == fRows.CountItems()) { 654 fRows.MakeEmpty(); 655 Clear(); 656 return; 657 } 658 659 for (int32 i = rowIndex + count - 1; i >= rowIndex; i--) { 660 if (BRow* row = fRows.RemoveItemAt(i)) { 661 RemoveRow(row); 662 delete row; 663 } 664 } 665 666 // re-index the subsequent rows 667 _UpdateRowIndices(rowIndex); 668 } 669 670 671 void 672 Table::TableRowsChanged(TableModel* model, int32 rowIndex, int32 count) 673 { 674 int32 endIndex = rowIndex + count; 675 for (int32 i = rowIndex; i < endIndex; i++) { 676 if (BRow* row = fRows.ItemAt(i)) 677 UpdateRow(row); 678 } 679 } 680 681 682 void 683 Table::TableModelReset(TableModel* model) 684 { 685 Clear(); 686 TableRowsAdded(model, 0, model->CountRows()); 687 } 688 689 690 void 691 Table::ItemInvoked() 692 { 693 if (fListeners.IsEmpty()) 694 return; 695 696 int32 index = _ModelIndexOfRow(CurrentSelection()); 697 if (index < 0) 698 return; 699 700 int32 listenerCount = fListeners.CountItems(); 701 for (int32 i = listenerCount - 1; i >= 0; i--) 702 fListeners.ItemAt(i)->TableRowInvoked(this, index); 703 } 704 705 706 void 707 Table::_UpdateRowIndices(int32 fromIndex) 708 { 709 for (int32 i = fromIndex; BRow* row = fRows.ItemAt(i); i++) { 710 for (int32 k = 0; 711 TableField* field = dynamic_cast<TableField*>(row->GetField(k)); 712 k++) { 713 field->SetRowIndex(i); 714 } 715 } 716 } 717 718 719 int32 720 Table::_ModelIndexOfRow(BRow* row) 721 { 722 if (row == NULL) 723 return -1; 724 725 TableField* field = dynamic_cast<TableField*>(row->GetField(0)); 726 if (field == NULL) 727 return -1; 728 729 return field->RowIndex(); 730 } 731