1 /* 2 Open Tracker License 3 4 Terms and Conditions 5 6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved. 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy of 9 this software and associated documentation files (the "Software"), to deal in 10 the Software without restriction, including without limitation the rights to 11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12 of the Software, and to permit persons to whom the Software is furnished to do 13 so, subject to the following conditions: 14 15 The above copyright notice and this permission notice applies to all licensees 16 and shall be included in all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION 23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25 Except as contained in this notice, the name of Be Incorporated shall not be 26 used in advertising or otherwise to promote the sale, use or other dealings in 27 this Software without prior written authorization from Be Incorporated. 28 29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks 30 of Be Incorporated in the United States and other countries. Other brand product 31 names are registered trademarks or trademarks of their respective holders. 32 All rights reserved. 33 */ 34 35 36 #include "QueryPoseView.h" 37 38 #include <new> 39 40 #include <Catalog.h> 41 #include <Debug.h> 42 #include <Locale.h> 43 #include <NodeMonitor.h> 44 #include <Query.h> 45 #include <Volume.h> 46 #include <VolumeRoster.h> 47 #include <Window.h> 48 49 #include "Attributes.h" 50 #include "AttributeStream.h" 51 #include "AutoLock.h" 52 #include "Commands.h" 53 #include "FindPanel.h" 54 #include "FSUtils.h" 55 #include "MimeTypeList.h" 56 #include "MimeTypes.h" 57 #include "Tracker.h" 58 59 #include <fs_attr.h> 60 61 62 using std::nothrow; 63 64 65 #undef B_TRANSLATION_CONTEXT 66 #define B_TRANSLATION_CONTEXT "QueryPoseView" 67 68 69 // Currently filtering out Trash doesn't node monitor too well - if you 70 // remove an item from the Trash, it doesn't show up in the query result 71 // To do this properly, we would have to node monitor everything BQuery 72 // returns and after a node monitor re-chech if it should be part of 73 // query results and add/remove appropriately. Right now only moving to 74 // Trash is supported 75 76 77 // #pragma mark - BQueryPoseView 78 79 80 BQueryPoseView::BQueryPoseView(Model* model) 81 : 82 BPoseView(model, kListMode), 83 fRefFilter(NULL), 84 fQueryList(NULL), 85 fQueryListContainer(NULL), 86 fCreateOldPoseList(false) 87 { 88 } 89 90 91 BQueryPoseView::~BQueryPoseView() 92 { 93 delete fQueryListContainer; 94 } 95 96 97 bool 98 FolderFilterFunction(const entry_ref* directory, const entry_ref* model) 99 { 100 if (directory == NULL || model == NULL) 101 return false; 102 103 BPath directoryPath(directory); 104 BPath modelPath(model); 105 106 if (directoryPath.InitCheck() != B_OK || modelPath.InitCheck() != B_OK) 107 return false; 108 109 char* requiredDirectoryPath = const_cast<char*>(directoryPath.Path()); 110 strcat(requiredDirectoryPath, "/"); 111 // only supports searching completely in the directories as well as subdirectories for now. 112 return strncmp(requiredDirectoryPath, modelPath.Path(), strlen(requiredDirectoryPath)) == 0; 113 } 114 115 116 bool 117 QueryRefFilter::PassThroughDirectoryFilters(const entry_ref* ref) const 118 { 119 int32 count = fDirectoryFilters.CountItems(); 120 bool passed = count == 0; 121 // in this context, even if the model passes through a single filter, it is considered 122 // as the folder selections are combined with OR! and not AND! 123 124 for (int32 i = 0; i < count; i++) { 125 entry_ref* filterDirectory = fDirectoryFilters.ItemAt(i); 126 if (FolderFilterFunction(filterDirectory, ref)) { 127 passed = true; 128 break; 129 } 130 } 131 132 return passed; 133 } 134 135 136 void 137 BQueryPoseView::MessageReceived(BMessage* message) 138 { 139 switch (message->what) { 140 case kFSClipboardChanges: 141 { 142 // poses have always to be updated for the query view 143 UpdatePosesClipboardModeFromClipboard(message); 144 break; 145 } 146 147 default: 148 _inherited::MessageReceived(message); 149 break; 150 } 151 } 152 153 154 void 155 BQueryPoseView::EditQueries() 156 { 157 BMessage message(kEditQuery); 158 message.AddRef("refs", TargetModel()->EntryRef()); 159 BMessenger(kTrackerSignature, -1, 0).SendMessage(&message); 160 } 161 162 163 void 164 BQueryPoseView::SetupDefaultColumnsIfNeeded() 165 { 166 // in case there were errors getting some columns 167 if (CountColumns() != 0) 168 return; 169 170 AddColumn(new BColumn(B_TRANSLATE("Name"), 145, 171 B_ALIGN_LEFT, kAttrStatName, B_STRING_TYPE, true, true)); 172 AddColumn(new BColumn(B_TRANSLATE("Location"), 225, 173 B_ALIGN_LEFT, kAttrPath, B_STRING_TYPE, true, false)); 174 AddColumn(new BColumn(B_TRANSLATE("Size"), 80, 175 B_ALIGN_RIGHT, kAttrStatSize, B_OFF_T_TYPE, true, false)); 176 AddColumn(new BColumn(B_TRANSLATE("Modified"), 150, 177 B_ALIGN_LEFT, kAttrStatModified, B_TIME_TYPE, true, false)); 178 } 179 180 181 void 182 BQueryPoseView::RestoreState(AttributeStreamNode* node) 183 { 184 _inherited::RestoreState(node); 185 fViewState->SetViewMode(kListMode); 186 } 187 188 189 void 190 BQueryPoseView::RestoreState(const BMessage &message) 191 { 192 _inherited::RestoreState(message); 193 fViewState->SetViewMode(kListMode); 194 } 195 196 197 void 198 BQueryPoseView::SavePoseLocations(BRect*) 199 { 200 } 201 202 203 void 204 BQueryPoseView::SetViewMode(uint32) 205 { 206 } 207 208 209 void 210 BQueryPoseView::OpenParent() 211 { 212 } 213 214 215 void 216 BQueryPoseView::Refresh() 217 { 218 PRINT(("refreshing dynamic date query\n")); 219 220 // cause the old AddPosesTask to die 221 fAddPosesThreads.clear(); 222 delete fQueryListContainer; 223 fQueryListContainer = NULL; 224 225 fCreateOldPoseList = true; 226 AddPoses(TargetModel()); 227 TargetModel()->CloseNode(); 228 229 ResetOrigin(); 230 ResetPosePlacementHint(); 231 } 232 233 234 void 235 BQueryPoseView::AddPosesCompleted() 236 { 237 ASSERT(Window()->IsLocked()); 238 239 PoseList* oldPoseList = fQueryListContainer->OldPoseList(); 240 if (oldPoseList != NULL) { 241 int32 count = oldPoseList->CountItems(); 242 for (int32 index = count - 1; index >= 0; index--) { 243 BPose* pose = oldPoseList->ItemAt(index); 244 DeletePose(pose->TargetModel()->NodeRef()); 245 } 246 fQueryListContainer->ClearOldPoseList(); 247 } 248 249 _inherited::AddPosesCompleted(); 250 } 251 252 253 // When using dynamic dates, such as "today", need to refresh the query 254 // window every now and then 255 256 EntryListBase* 257 BQueryPoseView::InitDirentIterator(const entry_ref* ref) 258 { 259 BEntry entry(ref); 260 if (entry.InitCheck() != B_OK) 261 return NULL; 262 263 Model sourceModel(&entry, true); 264 if (sourceModel.InitCheck() != B_OK) 265 return NULL; 266 267 ASSERT(sourceModel.IsQuery()); 268 269 // old pose list is used for finding poses that no longer match a 270 // dynamic date query during a Refresh call 271 PoseList* oldPoseList = NULL; 272 if (fCreateOldPoseList) { 273 oldPoseList = new PoseList(10, false); 274 oldPoseList->AddList(fPoseList); 275 } 276 277 fQueryListContainer = new QueryEntryListCollection(&sourceModel, this, 278 oldPoseList); 279 fCreateOldPoseList = false; 280 281 if (fQueryListContainer->InitCheck() != B_OK) { 282 delete fQueryListContainer; 283 fQueryListContainer = NULL; 284 return NULL; 285 } 286 287 TTracker::WatchNode(sourceModel.NodeRef(), B_WATCH_NAME | B_WATCH_STAT 288 | B_WATCH_ATTR, this); 289 290 fQueryList = fQueryListContainer->QueryList(); 291 292 if (fQueryListContainer->DynamicDateQuery()) { 293 // calculate the time to trigger the query refresh - next midnight 294 295 time_t now = time(0); 296 297 time_t nextMidnight = now + 60 * 60 * 24; 298 // move ahead by a day 299 tm timeData; 300 localtime_r(&nextMidnight, &timeData); 301 timeData.tm_sec = 0; 302 timeData.tm_min = 0; 303 timeData.tm_hour = 0; 304 nextMidnight = mktime(&timeData); 305 306 time_t nextHour = now + 60 * 60; 307 // move ahead by a hour 308 localtime_r(&nextHour, &timeData); 309 timeData.tm_sec = 0; 310 timeData.tm_min = 0; 311 nextHour = mktime(&timeData); 312 313 PRINT(("%" B_PRIdTIME " minutes, %" B_PRIdTIME " seconds till next hour\n", 314 (nextHour - now) / 60, (nextHour - now) % 60)); 315 316 time_t nextMinute = now + 60; 317 // move ahead by a minute 318 localtime_r(&nextMinute, &timeData); 319 timeData.tm_sec = 0; 320 nextMinute = mktime(&timeData); 321 322 PRINT(("%" B_PRIdTIME " seconds till next minute\n", nextMinute - now)); 323 324 bigtime_t delta; 325 if (fQueryListContainer->DynamicDateRefreshEveryMinute()) 326 delta = nextMinute - now; 327 else if (fQueryListContainer->DynamicDateRefreshEveryHour()) 328 delta = nextHour - now; 329 else 330 delta = nextMidnight - now; 331 332 #if DEBUG 333 int32 secondsTillMidnight = (nextMidnight - now); 334 int32 minutesTillMidnight = secondsTillMidnight/60; 335 secondsTillMidnight %= 60; 336 int32 hoursTillMidnight = minutesTillMidnight/60; 337 minutesTillMidnight %= 60; 338 339 PRINT(("%" B_PRId32 " hours, %" B_PRId32 " minutes, %" B_PRId32 340 " seconds till midnight\n", hoursTillMidnight, minutesTillMidnight, 341 secondsTillMidnight)); 342 343 int32 refreshInSeconds = delta % 60; 344 int32 refreshInMinutes = delta / 60; 345 int32 refreshInHours = refreshInMinutes / 60; 346 refreshInMinutes %= 60; 347 348 PRINT(("next refresh in %" B_PRId32 " hours, %" B_PRId32 "minutes, %" 349 B_PRId32 " seconds\n", refreshInHours, refreshInMinutes, 350 refreshInSeconds)); 351 #endif 352 353 // bump up to microseconds 354 delta *= 1000000; 355 356 TTracker* tracker = dynamic_cast<TTracker*>(be_app); 357 ThrowOnAssert(tracker != NULL); 358 359 tracker->MainTaskLoop()->RunLater( 360 NewLockingMemberFunctionObject(&BQueryPoseView::Refresh, this), 361 delta); 362 } 363 364 QueryRefFilter* filter = new QueryRefFilter(fQueryListContainer->ShowResultsFromTrash()); 365 TargetModel()->OpenNode(); 366 filter->LoadDirectoryFiltersFromFile(TargetModel()->Node()); 367 TargetModel()->CloseNode(); 368 SetRefFilter(filter); 369 370 return fQueryListContainer->Clone(); 371 } 372 373 374 uint32 375 BQueryPoseView::WatchNewNodeMask() 376 { 377 return B_WATCH_NAME | B_WATCH_STAT | B_WATCH_ATTR; 378 } 379 380 381 const char* 382 BQueryPoseView::SearchForType() const 383 { 384 if (!fSearchForMimeType.Length()) { 385 BModelOpener opener(TargetModel()); 386 BString buffer; 387 attr_info attrInfo; 388 389 // read the type of files we are looking for 390 status_t status 391 = TargetModel()->Node()->GetAttrInfo(kAttrQueryInitialMime, 392 &attrInfo); 393 if (status == B_OK) { 394 TargetModel()->Node()->ReadAttrString(kAttrQueryInitialMime, 395 &buffer); 396 } 397 398 TTracker* tracker = dynamic_cast<TTracker*>(be_app); 399 if (tracker != NULL && buffer.Length() > 0) { 400 const ShortMimeInfo* info = tracker->MimeTypes()->FindMimeType( 401 buffer.String()); 402 if (info != NULL) 403 fSearchForMimeType = info->InternalName(); 404 } 405 406 if (!fSearchForMimeType.Length()) 407 fSearchForMimeType = B_FILE_MIMETYPE; 408 } 409 410 return fSearchForMimeType.String(); 411 } 412 413 414 bool 415 BQueryPoseView::ActiveOnDevice(dev_t device) const 416 { 417 int32 count = fQueryList->CountItems(); 418 for (int32 index = 0; index < count; index++) { 419 if (fQueryList->ItemAt(index)->TargetDevice() == device) 420 return true; 421 } 422 423 return false; 424 } 425 426 427 // #pragma mark - QueryRefFilter 428 429 430 QueryRefFilter::QueryRefFilter(bool showResultsFromTrash) 431 : 432 fShowResultsFromTrash(showResultsFromTrash) 433 { 434 } 435 436 437 QueryRefFilter::~QueryRefFilter() 438 { 439 int32 count = fDirectoryFilters.CountItems(); 440 for (int32 i = 0; i < count; i++) 441 delete fDirectoryFilters.RemoveItemAt(0); 442 } 443 444 445 status_t 446 QueryRefFilter::LoadDirectoryFiltersFromFile(const BNode* node) 447 { 448 // params checking 449 if (node == NULL || node->InitCheck() != B_OK) 450 return B_BAD_VALUE; 451 452 struct attr_info info; 453 status_t error = node->GetAttrInfo("_trk/directories", &info); 454 if (error != B_OK) 455 return error; 456 457 BString bufferString; 458 char* buffer = bufferString.LockBuffer(info.size); 459 if (node->ReadAttr("_trk/directories", B_MESSAGE_TYPE, 0, buffer, info.size) != info.size) 460 return B_ERROR; 461 462 BMessage message; 463 error = message.Unflatten(buffer); 464 if (error != B_OK) 465 return error; 466 467 int32 count; 468 if ((error = message.GetInfo("refs", NULL, &count)) != B_OK) 469 return error; 470 471 for (int32 i = 0; i < count; i++) { 472 entry_ref ref; 473 if ((error = message.FindRef("refs", i, &ref)) != B_OK) 474 continue; 475 476 AddDirectoryFilter(&ref); 477 } 478 479 return B_OK; 480 } 481 482 483 status_t 484 QueryRefFilter::AddDirectoryFilter(const entry_ref* ref) 485 { 486 if (ref == NULL) 487 return B_BAD_VALUE; 488 489 // checking for duplicates 490 int32 count = fDirectoryFilters.CountItems(); 491 for (int32 i = 0; i < count; i++) { 492 entry_ref* item = fDirectoryFilters.ItemAt(i); 493 if (ref != NULL && item != NULL && *item == *ref) 494 return B_CANCELED; 495 } 496 497 BEntry entry(ref, true); 498 if (entry.InitCheck() != B_OK || !entry.Exists() || !entry.IsDirectory()) 499 return B_ERROR; 500 501 entry_ref symlinkTraversedRef; 502 entry.GetRef(&symlinkTraversedRef); 503 504 fDirectoryFilters.AddItem(new entry_ref(symlinkTraversedRef)); 505 return B_OK; 506 } 507 508 509 bool 510 QueryRefFilter::Filter(const entry_ref* ref, BNode* node, stat_beos* st, 511 const char* filetype) 512 { 513 TTracker* tracker = dynamic_cast<TTracker*>(be_app); 514 return !(!fShowResultsFromTrash && tracker != NULL && tracker->InTrashNode(ref)) 515 && PassThroughDirectoryFilters(ref); 516 } 517 518 519 // #pragma mark - QueryEntryListCollection 520 521 522 QueryEntryListCollection::QueryEntryListCollection(Model* model, 523 BHandler* target, PoseList* oldPoseList) 524 : 525 fQueryListRep(new QueryListRep(new BObjectList<BQuery>(5, true))) 526 { 527 Rewind(); 528 attr_info info; 529 BQuery query; 530 531 BNode* modelNode = model->Node(); 532 if (modelNode == NULL) { 533 fStatus = B_ERROR; 534 return; 535 } 536 537 // read the actual query string 538 fStatus = modelNode->GetAttrInfo(kAttrQueryString, &info); 539 if (fStatus != B_OK) 540 return; 541 542 BString buffer; 543 if (modelNode->ReadAttr(kAttrQueryString, B_STRING_TYPE, 0, 544 buffer.LockBuffer((int32)info.size), 545 (size_t)info.size) != info.size) { 546 fStatus = B_ERROR; 547 return; 548 } 549 550 buffer.UnlockBuffer(); 551 552 // read the extra options 553 MoreOptionsStruct saveMoreOptions; 554 if (ReadAttr(modelNode, kAttrQueryMoreOptions, 555 kAttrQueryMoreOptionsForeign, B_RAW_TYPE, 0, &saveMoreOptions, 556 sizeof(MoreOptionsStruct), 557 &MoreOptionsStruct::EndianSwap) != kReadAttrFailed) { 558 fQueryListRep->fShowResultsFromTrash = saveMoreOptions.searchTrash; 559 } 560 561 fStatus = query.SetPredicate(buffer.String()); 562 563 fQueryListRep->fOldPoseList = oldPoseList; 564 fQueryListRep->fDynamicDateQuery = false; 565 566 fQueryListRep->fRefreshEveryHour = false; 567 fQueryListRep->fRefreshEveryMinute = false; 568 569 if (modelNode->ReadAttr(kAttrDynamicDateQuery, B_BOOL_TYPE, 0, 570 &fQueryListRep->fDynamicDateQuery, 571 sizeof(bool)) != sizeof(bool)) { 572 fQueryListRep->fDynamicDateQuery = false; 573 } 574 575 if (fQueryListRep->fDynamicDateQuery) { 576 // only refresh every minute on debug builds 577 fQueryListRep->fRefreshEveryMinute = buffer.IFindFirst("second") != -1 578 || buffer.IFindFirst("minute") != -1; 579 fQueryListRep->fRefreshEveryHour = fQueryListRep->fRefreshEveryMinute 580 || buffer.IFindFirst("hour") != -1; 581 582 #if !DEBUG 583 // don't refresh every minute unless we are running debug build 584 fQueryListRep->fRefreshEveryMinute = false; 585 #endif 586 } 587 588 if (fStatus != B_OK) 589 return; 590 591 bool searchAllVolumes = true; 592 status_t result = B_OK; 593 594 // get volumes to perform query on 595 if (modelNode->GetAttrInfo(kAttrQueryVolume, &info) == B_OK) { 596 char* buffer = NULL; 597 598 if ((buffer = (char*)malloc((size_t)info.size)) != NULL 599 && modelNode->ReadAttr(kAttrQueryVolume, B_MESSAGE_TYPE, 0, 600 buffer, (size_t)info.size) == info.size) { 601 BMessage message; 602 if (message.Unflatten(buffer) == B_OK) { 603 for (int32 index = 0; ;index++) { 604 ASSERT(index < 100); 605 BVolume volume; 606 // match a volume with the info embedded in 607 // the message 608 result = MatchArchivedVolume(&volume, &message, index); 609 if (result == B_OK) { 610 // start the query on this volume 611 result = FetchOneQuery(&query, target, 612 fQueryListRep->fQueryList, &volume); 613 if (result != B_OK) 614 continue; 615 616 searchAllVolumes = false; 617 } else if (result != B_DEV_BAD_DRIVE_NUM) { 618 // if B_DEV_BAD_DRIVE_NUM, the volume just isn't 619 // mounted this time around, keep looking for more 620 // if other error, bail 621 break; 622 } 623 } 624 } 625 } 626 627 free(buffer); 628 } 629 630 if (searchAllVolumes) { 631 // no specific volumes embedded in query, search everything 632 BVolumeRoster roster; 633 BVolume volume; 634 635 roster.Rewind(); 636 while (roster.GetNextVolume(&volume) == B_OK) 637 if (volume.IsPersistent() && volume.KnowsQuery()) { 638 result = FetchOneQuery(&query, target, 639 fQueryListRep->fQueryList, &volume); 640 if (result != B_OK) 641 continue; 642 } 643 } 644 645 fStatus = B_OK; 646 647 return; 648 } 649 650 651 status_t 652 QueryEntryListCollection::FetchOneQuery(const BQuery* copyThis, 653 BHandler* target, BObjectList<BQuery>* list, BVolume* volume) 654 { 655 BQuery* query = new (nothrow) BQuery; 656 if (query == NULL) 657 return B_NO_MEMORY; 658 659 // have to fake a copy constructor here because BQuery doesn't have 660 // a copy constructor 661 BString buffer; 662 const_cast<BQuery*>(copyThis)->GetPredicate(&buffer); 663 query->SetPredicate(buffer.String()); 664 665 query->SetTarget(BMessenger(target)); 666 query->SetVolume(volume); 667 668 status_t result = query->Fetch(); 669 if (result != B_OK) { 670 PRINT(("fetch error %s\n", strerror(result))); 671 delete query; 672 return result; 673 } 674 675 list->AddItem(query); 676 677 return B_OK; 678 } 679 680 681 QueryEntryListCollection::~QueryEntryListCollection() 682 { 683 if (fQueryListRep->CloseQueryList()) 684 delete fQueryListRep; 685 } 686 687 688 QueryEntryListCollection* 689 QueryEntryListCollection::Clone() 690 { 691 fQueryListRep->OpenQueryList(); 692 return new QueryEntryListCollection(*this); 693 } 694 695 696 // #pragma mark - QueryEntryListCollection 697 698 699 QueryEntryListCollection::QueryEntryListCollection( 700 const QueryEntryListCollection &cloneThis) 701 : 702 EntryListBase(), 703 fQueryListRep(cloneThis.fQueryListRep) 704 { 705 // only to be used by the Clone routine 706 } 707 708 709 void 710 QueryEntryListCollection::ClearOldPoseList() 711 { 712 delete fQueryListRep->fOldPoseList; 713 fQueryListRep->fOldPoseList = NULL; 714 } 715 716 717 status_t 718 QueryEntryListCollection::GetNextEntry(BEntry* entry, bool traverse) 719 { 720 status_t result = B_ERROR; 721 722 for (int32 count = fQueryListRep->fQueryList->CountItems(); 723 fQueryListRep->fQueryListIndex < count; 724 fQueryListRep->fQueryListIndex++) { 725 result = fQueryListRep->fQueryList-> 726 ItemAt(fQueryListRep->fQueryListIndex)-> 727 GetNextEntry(entry, traverse); 728 if (result == B_OK) 729 break; 730 } 731 732 return result; 733 } 734 735 736 int32 737 QueryEntryListCollection::GetNextDirents(struct dirent* buffer, size_t length, 738 int32 count) 739 { 740 int32 result = 0; 741 742 for (int32 queryCount = fQueryListRep->fQueryList->CountItems(); 743 fQueryListRep->fQueryListIndex < queryCount; 744 fQueryListRep->fQueryListIndex++) { 745 result = fQueryListRep->fQueryList-> 746 ItemAt(fQueryListRep->fQueryListIndex)-> 747 GetNextDirents(buffer, length, count); 748 if (result > 0) 749 break; 750 } 751 752 return result; 753 } 754 755 756 status_t 757 QueryEntryListCollection::GetNextRef(entry_ref* ref) 758 { 759 status_t result = B_ERROR; 760 761 for (int32 count = fQueryListRep->fQueryList->CountItems(); 762 fQueryListRep->fQueryListIndex < count; 763 fQueryListRep->fQueryListIndex++) { 764 765 result = fQueryListRep->fQueryList-> 766 ItemAt(fQueryListRep->fQueryListIndex)->GetNextRef(ref); 767 if (result == B_OK) 768 break; 769 } 770 771 return result; 772 } 773 774 775 status_t 776 QueryEntryListCollection::Rewind() 777 { 778 fQueryListRep->fQueryListIndex = 0; 779 780 return B_OK; 781 } 782 783 784 int32 785 QueryEntryListCollection::CountEntries() 786 { 787 return 0; 788 } 789 790 791 bool 792 QueryEntryListCollection::ShowResultsFromTrash() const 793 { 794 return fQueryListRep->fShowResultsFromTrash; 795 } 796 797 798 bool 799 QueryEntryListCollection::DynamicDateQuery() const 800 { 801 return fQueryListRep->fDynamicDateQuery; 802 } 803 804 805 bool 806 QueryEntryListCollection::DynamicDateRefreshEveryHour() const 807 { 808 return fQueryListRep->fRefreshEveryHour; 809 } 810 811 812 bool 813 QueryEntryListCollection::DynamicDateRefreshEveryMinute() const 814 { 815 return fQueryListRep->fRefreshEveryMinute; 816 } 817