xref: /haiku/src/kits/tracker/QueryPoseView.cpp (revision 2141d2fe3a5df2f55f3590f67660573b50d1d1d3)
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