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 // rows are deleted by the BColumnListView destructor automatically 406 } 407 408 409 void 410 Table::SetTableModel(TableModel* model) 411 { 412 if (model == fModel) 413 return; 414 415 if (fModel != NULL) { 416 fModel->RemoveListener(this); 417 418 fRows.MakeEmpty(); 419 Clear(); 420 421 for (int32 i = 0; AbstractColumn* column = fColumns.ItemAt(i); i++) 422 column->SetModel(NULL); 423 } 424 425 fModel = model; 426 427 if (fModel == NULL) 428 return; 429 430 fModel->AddListener(this); 431 432 for (int32 i = 0; AbstractColumn* column = fColumns.ItemAt(i); i++) 433 column->SetModel(fModel); 434 435 TableRowsAdded(fModel, 0, fModel->CountRows()); 436 } 437 438 439 void 440 Table::SetToolTipProvider(TableToolTipProvider* toolTipProvider) 441 { 442 fToolTipProvider = toolTipProvider; 443 } 444 445 446 TableSelectionModel* 447 Table::SelectionModel() 448 { 449 return &fSelectionModel; 450 } 451 452 453 void 454 Table::SelectRow(int32 rowIndex, bool extendSelection) 455 { 456 BRow* row = fRows.ItemAt(rowIndex); 457 if (row == NULL) 458 return; 459 460 if (!extendSelection) { 461 fIgnoreSelectionChange++; 462 DeselectAll(); 463 fIgnoreSelectionChange--; 464 } 465 466 AddToSelection(row); 467 } 468 469 470 void 471 Table::DeselectRow(int32 rowIndex) 472 { 473 if (BRow* row = fRows.ItemAt(rowIndex)) 474 Deselect(row); 475 } 476 477 478 void 479 Table::DeselectAllRows() 480 { 481 DeselectAll(); 482 } 483 484 485 bool 486 Table::AddTableListener(TableListener* listener) 487 { 488 return fListeners.AddItem(listener); 489 } 490 491 492 void 493 Table::RemoveTableListener(TableListener* listener) 494 { 495 fListeners.RemoveItem(listener); 496 } 497 498 499 status_t 500 Table::GetCellRectAt(int32 rowIndex, int32 colIndex, BRect& _output) const 501 { 502 BRow* row = fRows.ItemAt(rowIndex); 503 if (row == NULL) 504 return B_ENTRY_NOT_FOUND; 505 506 AbstractColumn* column = fColumns.ItemAt(colIndex); 507 if (column == NULL) 508 return B_ENTRY_NOT_FOUND; 509 510 _output = GetFieldRect(row, column); 511 512 return B_OK; 513 } 514 515 516 bool 517 Table::GetToolTipAt(BPoint point, BToolTip** _tip) 518 { 519 if (fToolTipProvider == NULL) 520 return AbstractTable::GetToolTipAt(point, _tip); 521 522 // get the table row 523 BRow* row = RowAt(point); 524 int32 rowIndex = row != NULL ? _ModelIndexOfRow(row) : -1; 525 if (rowIndex < 0) 526 return AbstractTable::GetToolTipAt(point, _tip); 527 528 // get the table column 529 BColumn* column = ColumnAt(point); 530 int32 columnIndex = column != NULL ? column->LogicalFieldNum() : -1; 531 532 return fToolTipProvider->GetToolTipForTableCell(rowIndex, columnIndex, 533 _tip); 534 } 535 536 537 void 538 Table::SelectionChanged() 539 { 540 if (fIgnoreSelectionChange > 0) 541 return; 542 543 fSelectionModel._SelectionChanged(); 544 545 if (!fListeners.IsEmpty()) { 546 int32 listenerCount = fListeners.CountItems(); 547 for (int32 i = listenerCount - 1; i >= 0; i--) 548 fListeners.ItemAt(i)->TableSelectionChanged(this); 549 } 550 } 551 552 553 AbstractTable::AbstractColumn* 554 Table::CreateColumn(TableColumn* column) 555 { 556 return new Column(fModel, column); 557 } 558 559 560 void 561 Table::ColumnMouseDown(AbstractColumn* column, BRow* row, BField* field, 562 BPoint screenWhere, uint32 buttons) 563 { 564 if (!fListeners.IsEmpty()) { 565 // get the table row and column indices 566 int32 rowIndex = _ModelIndexOfRow(row); 567 int32 columnIndex = column->LogicalFieldNum(); 568 if (rowIndex < 0 || columnIndex < 0) 569 return; 570 571 // notify listeners 572 int32 listenerCount = fListeners.CountItems(); 573 for (int32 i = listenerCount - 1; i >= 0; i--) { 574 fListeners.ItemAt(i)->TableCellMouseDown(this, rowIndex, 575 columnIndex, screenWhere, buttons); 576 } 577 } 578 } 579 580 581 void 582 Table::ColumnMouseUp(AbstractColumn* column, BRow* row, BField* field, 583 BPoint screenWhere, uint32 buttons) 584 { 585 if (!fListeners.IsEmpty()) { 586 // get the table row and column indices 587 int32 rowIndex = _ModelIndexOfRow(row); 588 int32 columnIndex = column->LogicalFieldNum(); 589 if (rowIndex < 0 || columnIndex < 0) 590 return; 591 592 // notify listeners 593 int32 listenerCount = fListeners.CountItems(); 594 for (int32 i = listenerCount - 1; i >= 0; i--) { 595 fListeners.ItemAt(i)->TableCellMouseUp(this, rowIndex, columnIndex, 596 screenWhere, buttons); 597 } 598 } 599 } 600 601 602 void 603 Table::TableRowsAdded(TableModel* model, int32 rowIndex, int32 count) 604 { 605 // create the rows 606 int32 endRow = rowIndex + count; 607 int32 columnCount = fModel->CountColumns(); 608 609 for (int32 i = rowIndex; i < endRow; i++) { 610 // create row 611 BRow* row = new(std::nothrow) BRow(); 612 if (row == NULL) { 613 // TODO: Report error! 614 return; 615 } 616 617 // add dummy fields to row 618 for (int32 columnIndex = 0; columnIndex < columnCount; columnIndex++) { 619 // It would be nice to create only a single field and set it for all 620 // columns, but the row takes ultimate ownership, so it have to be 621 // individual objects. 622 TableField* field = new(std::nothrow) TableField(i); 623 if (field == NULL) { 624 // TODO: Report error! 625 delete row; 626 return; 627 } 628 629 row->SetField(field, columnIndex); 630 } 631 632 // add row 633 if (!fRows.AddItem(row, i)) { 634 // TODO: Report error! 635 delete row; 636 return; 637 } 638 639 AddRow(row, i); 640 } 641 642 // re-index the subsequent rows 643 _UpdateRowIndices(endRow); 644 } 645 646 647 void 648 Table::TableRowsRemoved(TableModel* model, int32 rowIndex, int32 count) 649 { 650 if (rowIndex == 0 && count == fRows.CountItems()) { 651 fRows.MakeEmpty(); 652 Clear(); 653 return; 654 } 655 656 for (int32 i = rowIndex + count - 1; i >= rowIndex; i--) { 657 if (BRow* row = fRows.RemoveItemAt(i)) { 658 RemoveRow(row); 659 delete row; 660 } 661 } 662 663 // re-index the subsequent rows 664 _UpdateRowIndices(rowIndex); 665 } 666 667 668 void 669 Table::TableRowsChanged(TableModel* model, int32 rowIndex, int32 count) 670 { 671 int32 endIndex = rowIndex + count; 672 for (int32 i = rowIndex; i < endIndex; i++) { 673 if (BRow* row = fRows.ItemAt(i)) 674 UpdateRow(row); 675 } 676 } 677 678 679 void 680 Table::TableModelReset(TableModel* model) 681 { 682 Clear(); 683 TableRowsAdded(model, 0, model->CountRows()); 684 } 685 686 687 void 688 Table::ItemInvoked() 689 { 690 if (fListeners.IsEmpty()) 691 return; 692 693 int32 index = _ModelIndexOfRow(CurrentSelection()); 694 if (index < 0) 695 return; 696 697 int32 listenerCount = fListeners.CountItems(); 698 for (int32 i = listenerCount - 1; i >= 0; i--) 699 fListeners.ItemAt(i)->TableRowInvoked(this, index); 700 } 701 702 703 void 704 Table::_UpdateRowIndices(int32 fromIndex) 705 { 706 for (int32 i = fromIndex; BRow* row = fRows.ItemAt(i); i++) { 707 for (int32 k = 0; 708 TableField* field = dynamic_cast<TableField*>(row->GetField(k)); 709 k++) { 710 field->SetRowIndex(i); 711 } 712 } 713 } 714 715 716 int32 717 Table::_ModelIndexOfRow(BRow* row) 718 { 719 if (row == NULL) 720 return -1; 721 722 TableField* field = dynamic_cast<TableField*>(row->GetField(0)); 723 if (field == NULL) 724 return -1; 725 726 return field->RowIndex(); 727 } 728