1 //------------------------------------------------------------------------------ 2 // Copyright (c) 2001-2002, OpenBeOS 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a 5 // copy of this software and associated documentation files (the "Software"), 6 // to deal in the Software without restriction, including without limitation 7 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 // and/or sell copies of the Software, and to permit persons to whom the 9 // Software is furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 // DEALINGS IN THE SOFTWARE. 21 // 22 // File Name: OutlineListView.cpp 23 // Author: Marc Flerackers (mflerackers@androme.be) 24 // Description: BOutlineListView represents a "nestable" list view. 25 //------------------------------------------------------------------------------ 26 27 // Standard Includes ----------------------------------------------------------- 28 29 // System Includes ------------------------------------------------------------- 30 #include <OutlineListView.h> 31 32 // Project Includes ------------------------------------------------------------ 33 34 // Local Includes -------------------------------------------------------------- 35 36 // Local Defines --------------------------------------------------------------- 37 38 // Globals --------------------------------------------------------------------- 39 40 //------------------------------------------------------------------------------ 41 BOutlineListView::BOutlineListView(BRect frame, const char * name, 42 list_view_type type, uint32 resizeMask, 43 uint32 flags) 44 : BListView(frame, name, type, resizeMask, flags) 45 { 46 } 47 //------------------------------------------------------------------------------ 48 BOutlineListView::BOutlineListView(BMessage *archive) 49 : BListView(archive) 50 { 51 } 52 //------------------------------------------------------------------------------ 53 BOutlineListView::~BOutlineListView() 54 { 55 fullList.MakeEmpty(); 56 } 57 //------------------------------------------------------------------------------ 58 BArchivable *BOutlineListView::Instantiate(BMessage *archive) 59 { 60 if (validate_instantiation(archive, "BOutlineListView")) 61 return new BOutlineListView(archive); 62 else 63 return NULL; 64 } 65 //------------------------------------------------------------------------------ 66 status_t BOutlineListView::Archive(BMessage *data, bool deep) const 67 { 68 return BListView::Archive(data, deep); 69 } 70 //------------------------------------------------------------------------------ 71 void BOutlineListView::MouseDown(BPoint point) 72 { 73 MakeFocus(); 74 75 int32 index = IndexOf(point); 76 77 if (index != -1) 78 { 79 BListItem *item = ItemAt(index); 80 81 if (item->fHasSubitems && 82 LatchRect (ItemFrame(index ), item->fLevel).Contains(point)) 83 { 84 if (item->IsExpanded()) 85 Collapse(item); 86 else 87 Expand(item); 88 } 89 else BListView::MouseDown(point); 90 } 91 } 92 //------------------------------------------------------------------------------ 93 void BOutlineListView::KeyDown(const char *bytes, int32 numBytes) 94 { 95 if (numBytes == 1) 96 { 97 switch (bytes[0]) 98 { 99 case '+': 100 { 101 BListItem *item = ItemAt(CurrentSelection()); 102 103 if ( item && item->fHasSubitems) 104 Expand(item); 105 106 break; 107 } 108 case '-': 109 { 110 BListItem *item = ItemAt(CurrentSelection()); 111 112 if (item && item->fHasSubitems) 113 Collapse(item); 114 115 break; 116 } 117 default: 118 BListView::KeyDown(bytes, numBytes); 119 } 120 } 121 else 122 BListView::KeyDown(bytes, numBytes); 123 } 124 //------------------------------------------------------------------------------ 125 void BOutlineListView::FrameMoved(BPoint new_position) 126 { 127 BListView::FrameMoved(new_position); 128 } 129 //------------------------------------------------------------------------------ 130 void BOutlineListView::FrameResized(float new_width, float new_height) 131 { 132 BListView::FrameResized(new_width, new_height); 133 } 134 //------------------------------------------------------------------------------ 135 void BOutlineListView::MouseUp(BPoint where) 136 { 137 BListView::MouseUp(where); 138 } 139 //------------------------------------------------------------------------------ 140 bool BOutlineListView::AddUnder(BListItem *item, BListItem *superitem) 141 { 142 fullList.AddItem(item, FullListIndexOf(superitem) + 1); 143 144 item->fLevel = superitem->OutlineLevel() + 1; 145 superitem->fHasSubitems = true; 146 147 if (superitem->IsItemVisible() && superitem->IsExpanded()) 148 { 149 item->SetItemVisible(true); 150 151 int32 index = BListView::IndexOf(superitem); 152 153 BListView::AddItem(item, index + 1); 154 Invalidate(LatchRect(ItemFrame(index), superitem->OutlineLevel())); 155 } 156 else 157 item->SetItemVisible(false); 158 159 return true; 160 } 161 //------------------------------------------------------------------------------ 162 bool BOutlineListView::AddItem(BListItem *item) 163 { 164 bool result = fullList.AddItem(item); 165 166 if (!result) 167 return false; 168 169 return BListView::AddItem(item); 170 } 171 //------------------------------------------------------------------------------ 172 bool BOutlineListView::AddItem(BListItem *item, int32 fullListIndex) 173 { 174 if (fullListIndex < 0) 175 fullListIndex = 0; 176 else if (fullListIndex > CountItems()) 177 fullListIndex = CountItems(); 178 179 fullList.AddItem(item, fullListIndex); 180 181 if (item->fLevel > 0) 182 { 183 BListItem *super = SuperitemForIndex(fullListIndex, item->fLevel); 184 185 if (!super->IsItemVisible() || !super->IsExpanded()) 186 return true; 187 } 188 189 int32 list_index = FindPreviousVisibleIndex(fullListIndex); 190 191 return BListView::AddItem(item, IndexOf(FullListItemAt(list_index)) + 1); 192 } 193 //------------------------------------------------------------------------------ 194 bool BOutlineListView::AddList(BList *newItems) 195 { 196 printf("BOutlineListView::AddList Not implemented\n"); 197 return false; 198 } 199 //------------------------------------------------------------------------------ 200 bool BOutlineListView::AddList(BList *newItems, int32 fullListIndex) 201 { 202 printf("BOutlineListView::AddList Not implemented\n"); 203 return false; 204 } 205 //------------------------------------------------------------------------------ 206 bool BOutlineListView::RemoveItem(BListItem *item) 207 { 208 if (!FullListHasItem(item)) 209 return false; 210 211 fullList.RemoveItem(item); 212 if (item->fVisible) 213 BListView::RemoveItem(item); 214 215 // TODO: remove children 216 217 return true; 218 } 219 //------------------------------------------------------------------------------ 220 BListItem *BOutlineListView::RemoveItem(int32 fullListIndex) 221 { 222 BListItem *item = FullListItemAt(fullListIndex); 223 224 if (item == NULL) 225 return NULL; 226 227 fullList.RemoveItem(fullListIndex); 228 if (item->fVisible) 229 BListView::RemoveItem(item); 230 231 // TODO: remove children 232 233 return item; 234 } 235 //------------------------------------------------------------------------------ 236 bool BOutlineListView::RemoveItems(int32 fullListIndex, int32 count) 237 { 238 printf("BOutlineListView::RemoveItems Not implemented\n"); 239 240 return false; 241 } 242 //------------------------------------------------------------------------------ 243 BListItem *BOutlineListView::FullListItemAt(int32 fullListIndex) const 244 { 245 return (BListItem*)fullList.ItemAt(fullListIndex); 246 } 247 //------------------------------------------------------------------------------ 248 int32 BOutlineListView::FullListIndexOf(BPoint point) const 249 { 250 return BListView::IndexOf(point); 251 } 252 //------------------------------------------------------------------------------ 253 int32 BOutlineListView::FullListIndexOf(BListItem *item) const 254 { 255 return fullList.IndexOf(item); 256 } 257 //------------------------------------------------------------------------------ 258 BListItem *BOutlineListView::FullListFirstItem() const 259 { 260 return (BListItem*)fullList.FirstItem(); 261 } 262 //------------------------------------------------------------------------------ 263 BListItem *BOutlineListView::FullListLastItem() const 264 { 265 return (BListItem*)fullList.LastItem(); 266 } 267 //------------------------------------------------------------------------------ 268 bool BOutlineListView::FullListHasItem(BListItem *item) const 269 { 270 return fullList.HasItem(item); 271 } 272 //------------------------------------------------------------------------------ 273 int32 BOutlineListView::FullListCountItems() const 274 { 275 return fullList.CountItems(); 276 } 277 //------------------------------------------------------------------------------ 278 int32 BOutlineListView::FullListCurrentSelection(int32 index) const 279 { 280 int32 i = BListView::CurrentSelection(index); 281 BListItem *item = BListView::ItemAt(i); 282 283 if (item) 284 return fullList.IndexOf(item); 285 else 286 return -1; 287 } 288 //------------------------------------------------------------------------------ 289 void BOutlineListView::MakeEmpty() 290 { 291 fullList.MakeEmpty(); 292 BListView::MakeEmpty(); 293 } 294 //------------------------------------------------------------------------------ 295 bool BOutlineListView::FullListIsEmpty() const 296 { 297 return fullList.IsEmpty(); 298 } 299 //------------------------------------------------------------------------------ 300 void BOutlineListView::FullListDoForEach(bool(*func)(BListItem *)) 301 { 302 printf("BOutlineListView::fullListDoForEach Not implemented\n"); 303 //fullList.DoForEach(func); 304 } 305 //------------------------------------------------------------------------------ 306 void BOutlineListView::FullListDoForEach(bool (*func)(BListItem *, void *), 307 void *data) 308 { 309 printf("BOutlineListView::fullListDoForEach Not implemented\n"); 310 //fullList.DoForEach(func, data); 311 } 312 //------------------------------------------------------------------------------ 313 BListItem *BOutlineListView::Superitem(const BListItem *item) 314 { 315 int32 index = FullListIndexOf((BListItem*)item); 316 317 if (index == -1) 318 return NULL; 319 else 320 return SuperitemForIndex(index, item->OutlineLevel()); 321 } 322 //------------------------------------------------------------------------------ 323 void BOutlineListView::Expand(BListItem *item) 324 { 325 if (!FullListHasItem(item)) 326 return; 327 328 if (item->fExpanded) 329 return; 330 331 item->fExpanded = true; 332 333 uint32 level = item->fLevel, full_index = FullListIndexOf(item), 334 index = IndexOf(item) + 1, count = FullListCountItems() - full_index - 1; 335 BListItem **items = (BListItem**)fullList.Items() + full_index + 1; 336 337 BFont font; 338 GetFont(&font); 339 340 while (count-- > 0 && (*items)->fLevel > level) 341 { 342 if (!(*items)->IsItemVisible()) 343 { 344 //BListView::AddItem((*items), index++); 345 fList.AddItem((*items), index++); 346 (*items)->Update(this,&font); 347 (*items)->SetItemVisible(true); 348 } 349 350 // Skip hidden children 351 if ((*items)->HasSubitems() && !(*items)->IsExpanded()) 352 { 353 uint32 level = (*items)->fLevel; 354 items++; 355 356 while (--count > 0 && (*items)->fLevel > level) 357 items++; 358 } 359 else 360 items++; 361 } 362 363 FixupScrollBar(); 364 Invalidate(); 365 } 366 //------------------------------------------------------------------------------ 367 void BOutlineListView::Collapse(BListItem *item) 368 { 369 if (!FullListHasItem(item)) 370 return; 371 372 if (!item->fExpanded) 373 return; 374 375 item->fExpanded = false; 376 377 uint32 level = item->fLevel, full_index = FullListIndexOf(item), 378 index = IndexOf(item) + 1, count = FullListCountItems() - full_index - 1; 379 BListItem **items = (BListItem**)fullList.Items() + full_index + 1; 380 381 while (count-- > 0 && (*items)->fLevel > level) 382 { 383 if ((*items)->IsItemVisible()) 384 { 385 //BListView::RemoveItem ((*items)); 386 fList.RemoveItem((*items)); 387 (*items)->SetItemVisible(false); 388 } 389 390 items++; 391 } 392 393 FixupScrollBar(); 394 Invalidate(); 395 } 396 //------------------------------------------------------------------------------ 397 bool BOutlineListView::IsExpanded(int32 fullListIndex) 398 { 399 BListItem *item = FullListItemAt(fullListIndex); 400 401 if (!item) 402 return false; 403 404 return item->IsExpanded(); 405 } 406 //------------------------------------------------------------------------------ 407 BHandler *BOutlineListView::ResolveSpecifier(BMessage *msg, int32 index, 408 BMessage *specifier, int32 form, 409 const char *property) 410 { 411 return BListView::ResolveSpecifier(msg, index, specifier, form, property); 412 } 413 //------------------------------------------------------------------------------ 414 status_t BOutlineListView::GetSupportedSuites(BMessage *data) 415 { 416 return BListView::GetSupportedSuites(data); 417 } 418 //------------------------------------------------------------------------------ 419 status_t BOutlineListView::Perform(perform_code d, void *arg) 420 { 421 return BListView::Perform(d, arg); 422 } 423 //------------------------------------------------------------------------------ 424 void BOutlineListView::ResizeToPreferred() 425 { 426 BListView::ResizeToPreferred(); 427 } 428 //------------------------------------------------------------------------------ 429 void BOutlineListView::GetPreferredSize(float *width, float *height) 430 { 431 BListView::GetPreferredSize(width, height); 432 } 433 //------------------------------------------------------------------------------ 434 void BOutlineListView::MakeFocus(bool state) 435 { 436 BListView::MakeFocus(state); 437 } 438 //------------------------------------------------------------------------------ 439 void BOutlineListView::AllAttached() 440 { 441 BListView::AllAttached(); 442 } 443 //------------------------------------------------------------------------------ 444 void BOutlineListView::AllDetached() 445 { 446 BListView::AllDetached(); 447 } 448 //------------------------------------------------------------------------------ 449 void BOutlineListView::DetachedFromWindow() 450 { 451 BListView::DetachedFromWindow(); 452 } 453 //------------------------------------------------------------------------------ 454 void BOutlineListView::FullListSortItems(int (*compareFunc)(const BListItem *, 455 const BListItem *)) 456 { 457 //fullList.SortItems(compareFunc); 458 printf("BOutlineListView::FullListSortItems not implemented\n"); 459 } 460 //------------------------------------------------------------------------------ 461 void BOutlineListView::SortItemsUnder(BListItem *underItem, bool oneLevelOnly, 462 int (*compareFunc)(const BListItem *, const BListItem*)) 463 { 464 printf("BOutlineListView::SortItemsUnder not implemented\n"); 465 } 466 //------------------------------------------------------------------------------ 467 int32 BOutlineListView::CountItemsUnder(BListItem *underItem, 468 bool oneLevelOnly) const 469 { 470 int32 i = IndexOf(underItem); 471 472 if (i == -1) 473 return 0; 474 475 int32 count = 0; 476 477 if (oneLevelOnly) 478 { 479 while (i < FullListCountItems()) 480 { 481 BListItem *item = FullListItemAt(i); 482 483 // If we jump out of the subtree, return count 484 if (item->fLevel < underItem->OutlineLevel()) 485 return count; 486 487 // If the level matches, increase count 488 if (item->fLevel == underItem->OutlineLevel() + 1) 489 count++; 490 491 i++; 492 } 493 } 494 else 495 { 496 while (i < FullListCountItems()) 497 { 498 BListItem *item = FullListItemAt(i); 499 500 // If we jump out of the subtree, return count 501 if (item->fLevel < underItem->OutlineLevel()) 502 return count; 503 504 // Increase count 505 count++; 506 507 i++; 508 } 509 } 510 511 return count; 512 } 513 //------------------------------------------------------------------------------ 514 BListItem *BOutlineListView::EachItemUnder(BListItem *underItem, 515 bool oneLevelOnly, 516 BListItem *(*eachFunc)(BListItem *, 517 void *), void *) 518 { 519 printf("BOutlineListView::EachItemUnder Not implemented\n"); 520 521 return NULL; 522 } 523 //------------------------------------------------------------------------------ 524 BListItem *BOutlineListView::ItemUnderAt(BListItem *underItem, 525 bool oneLevelOnly, int32 index) const 526 { 527 int32 i = IndexOf(underItem); 528 529 if (i == -1) 530 return NULL; 531 532 if (oneLevelOnly) 533 { 534 while (i < FullListCountItems()) 535 { 536 BListItem *item = FullListItemAt(i); 537 538 // If we jump out of the subtree, return NULL 539 if (item->fLevel < underItem->OutlineLevel()) 540 return NULL; 541 542 // If the level matches, check the index 543 if (item->fLevel == underItem->OutlineLevel() + 1) 544 { 545 if (index == 0) 546 return item; 547 else 548 index--; 549 } 550 551 i++; 552 } 553 } 554 else 555 { 556 while (i < FullListCountItems()) 557 { 558 BListItem *item = FullListItemAt(i); 559 560 // If we jump out of the subtree, return NULL 561 if (item->fLevel < underItem->OutlineLevel()) 562 return NULL; 563 564 // Check the index 565 if (index == 0) 566 return item; 567 else 568 index--; 569 570 i++; 571 } 572 } 573 574 return NULL; 575 } 576 //------------------------------------------------------------------------------ 577 bool BOutlineListView::DoMiscellaneous(MiscCode code, MiscData * data) 578 { 579 return BListView::DoMiscellaneous(code, data); 580 } 581 //------------------------------------------------------------------------------ 582 void BOutlineListView::MessageReceived(BMessage *msg) 583 { 584 BListView::MessageReceived(msg); 585 } 586 //------------------------------------------------------------------------------ 587 void BOutlineListView::_ReservedOutlineListView1() {} 588 void BOutlineListView::_ReservedOutlineListView2() {} 589 void BOutlineListView::_ReservedOutlineListView3() {} 590 void BOutlineListView::_ReservedOutlineListView4() {} 591 //------------------------------------------------------------------------------ 592 int32 BOutlineListView::FullListIndex(int32 index) const 593 { 594 BListItem *item = ItemAt(index); 595 596 if (item == NULL) 597 return -1; 598 else 599 return FullListIndexOf(item); 600 } 601 //------------------------------------------------------------------------------ 602 int32 BOutlineListView::ListViewIndex(int32 index) const 603 { 604 BListItem *item = ItemAt(index); 605 606 if (item == NULL) 607 return -1; 608 else 609 return BListView::IndexOf(item); 610 } 611 //------------------------------------------------------------------------------ 612 void BOutlineListView::ExpandOrCollapse(BListItem *underItem, bool expand) 613 { 614 } 615 //------------------------------------------------------------------------------ 616 BRect BOutlineListView::LatchRect(BRect itemRect, int32 level) const 617 { 618 return BRect(itemRect.left, itemRect.top, itemRect.left + 619 (level * 10.0f + 15.0f), itemRect.bottom); 620 } 621 //------------------------------------------------------------------------------ 622 void BOutlineListView::DrawLatch(BRect itemRect, int32 level, bool collapsed, 623 bool highlighted, bool misTracked) 624 { 625 float left = level * 10.0f; 626 627 if (collapsed) 628 { 629 SetHighColor(192, 192, 192); 630 631 FillTriangle(itemRect.LeftTop() + BPoint(left + 4.0f, 2.0f), 632 itemRect.LeftTop() + BPoint(left + 4.0f, 10.0f), 633 itemRect.LeftTop() + BPoint(left + 8.0f, 6.0f)); 634 635 SetHighColor(0, 0, 0); 636 637 StrokeTriangle(itemRect.LeftTop() + BPoint(left + 4.0f, 2.0f), 638 itemRect.LeftTop() + BPoint(left + 4.0f, 10.0f), 639 itemRect.LeftTop() + BPoint(left + 8.0f, 6.0f)); 640 } 641 else 642 { 643 SetHighColor(192, 192, 192); 644 645 FillTriangle(itemRect.LeftTop() + BPoint(left + 2.0f, 4.0f), 646 itemRect.LeftTop() + BPoint(left + 10.0f, 4.0f), 647 itemRect.LeftTop() + BPoint(left + 6.0f, 8.0f)); 648 649 SetHighColor(0, 0, 0); 650 651 StrokeTriangle(itemRect.LeftTop() + BPoint(left + 2.0f, 4.0f), 652 itemRect.LeftTop() + BPoint(left + 10.0f, 4.0f), 653 itemRect.LeftTop() + BPoint(left + 6.0f, 8.0f)); 654 } 655 } 656 //------------------------------------------------------------------------------ 657 void BOutlineListView::DrawItem(BListItem *item, BRect itemRect, bool complete) 658 { 659 if (item->fHasSubitems) 660 DrawLatch(itemRect, item->fLevel, !item->IsExpanded(), false, false); 661 662 itemRect.left += (item->fLevel) * 10.0f + 15.0f; 663 664 item->DrawItem(this, itemRect, complete); 665 } 666 //------------------------------------------------------------------------------ 667 BListItem *BOutlineListView::RemoveCommon(int32 fullListIndex) 668 { 669 return NULL; 670 } 671 //------------------------------------------------------------------------------ 672 BListItem *BOutlineListView::RemoveOne(int32 fullListIndex) 673 { 674 return NULL; 675 } 676 //------------------------------------------------------------------------------ 677 void BOutlineListView::TrackInLatchItem(void *) 678 { 679 } 680 //------------------------------------------------------------------------------ 681 void BOutlineListView::TrackOutLatchItem(void *) 682 { 683 } 684 //------------------------------------------------------------------------------ 685 bool BOutlineListView::OutlineSwapItems(int32 a, int32 b) 686 { 687 return false; 688 } 689 //------------------------------------------------------------------------------ 690 bool BOutlineListView::OutlineMoveItem(int32 from, int32 to) 691 { 692 return false; 693 } 694 //------------------------------------------------------------------------------ 695 bool BOutlineListView::OutlineReplaceItem(int32 index, BListItem *item) 696 { 697 return false; 698 } 699 //------------------------------------------------------------------------------ 700 void BOutlineListView::CommonMoveItems(int32 from, int32 count, int32 to) 701 { 702 } 703 //------------------------------------------------------------------------------ 704 BListItem *BOutlineListView::SuperitemForIndex(int32 fullListIndex, int32 level) 705 { 706 BListItem *item; 707 fullListIndex--; 708 709 while (fullListIndex >= 0) 710 { 711 if ((item = FullListItemAt(fullListIndex))->OutlineLevel() < 712 (uint32)level) 713 return item; 714 715 fullListIndex--; 716 } 717 718 return NULL; 719 } 720 //------------------------------------------------------------------------------ 721 int32 BOutlineListView::FindPreviousVisibleIndex(int32 fullListIndex) 722 { 723 fullListIndex--; 724 725 while (fullListIndex >= 0) 726 { 727 if (FullListItemAt(fullListIndex)->fVisible) 728 return fullListIndex; 729 730 fullListIndex--; 731 } 732 733 return -1; 734 } 735 //------------------------------------------------------------------------------ 736 737 /* 738 * $Log $ 739 * 740 * $Id $ 741 * 742 */ 743