xref: /haiku/src/kits/tracker/FavoritesMenu.cpp (revision 4f00613311d0bd6b70fa82ce19931c41f071ea4e)
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 #include <Application.h>
36 #include <FindDirectory.h>
37 #include <Message.h>
38 #include <Path.h>
39 #include <Query.h>
40 #include <Roster.h>
41 
42 #include <functional>
43 #include <algorithm>
44 
45 #include "EntryIterator.h"
46 #include "FavoritesMenu.h"
47 #include "IconMenuItem.h"
48 #include "NavMenu.h"
49 #include "PoseView.h"
50 #include "QueryPoseView.h"
51 #include "Tracker.h"
52 #include "Utilities.h"
53 
54 
55 FavoritesMenu::FavoritesMenu(const char *title, BMessage *openFolderMessage,
56 	BMessage *openFileMessage, const BMessenger &target,
57 	bool isSavePanel)
58 	:	BSlowMenu(title),
59 		fOpenFolderMessage(openFolderMessage),
60 		fOpenFileMessage(openFileMessage),
61 		fTarget(target),
62 		fContainer(NULL),
63 		fInitialItemCount(0),
64 		fIsSavePanel(isSavePanel)
65 {
66 }
67 
68 
69 FavoritesMenu::~FavoritesMenu()
70 {
71 	delete fOpenFolderMessage;
72 	delete fOpenFileMessage;
73 	delete fContainer;
74 }
75 
76 
77 bool
78 FavoritesMenu::StartBuildingItemList()
79 {
80 	// initialize the menu building state
81 
82 	if (!fInitialItemCount)
83 		fInitialItemCount = CountItems();
84 	else {
85 		// strip the old items so we can add new fresh ones
86 		int32 count = CountItems() - fInitialItemCount;
87 		// keep the items that were added by the FavoritesMenu creator
88 		while (count--)
89 			delete RemoveItem(fInitialItemCount);
90 	}
91 
92 	fUniqueRefCheck.clear();
93 	fState = kStart;
94 	return true;
95 }
96 
97 
98 bool
99 FavoritesMenu::AddNextItem()
100 {
101 	// run the next chunk of code for a given item adding state
102 
103 	if (fState == kStart) {
104 		fState = kAddingFavorites;
105 		fSectionItemCount = 0;
106 		fAddedSeparatorForSection = false;
107 		// set up adding the GoTo menu items
108 
109 		try {
110 			BPath path;
111 			ThrowOnError( find_directory (B_USER_SETTINGS_DIRECTORY, &path, true) );
112 			path.Append(kGoDirectory);
113 			mkdir(path.Path(), 0777);
114 
115 			BEntry entry(path.Path());
116 			Model startModel(&entry, true);
117 			ThrowOnInitCheckError(&startModel);
118 
119 			if (!startModel.IsContainer())
120 				throw B_ERROR;
121 
122 			if (startModel.IsQuery())
123 				fContainer = new QueryEntryListCollection(&startModel);
124 			else
125 				fContainer = new DirectoryEntryList(*dynamic_cast<BDirectory *>
126 					(startModel.Node()));
127 
128 			ThrowOnInitCheckError(fContainer);
129 			ThrowOnError( fContainer->Rewind() );
130 
131 		} catch (...) {
132 			delete fContainer;
133 			fContainer = NULL;
134 		}
135 	}
136 
137 
138 	if (fState == kAddingFavorites) {
139 		entry_ref ref;
140 		// limit nav menus to 20 items only
141 		if (fContainer
142 			&& fSectionItemCount < 20
143 			&& fContainer->GetNextRef(&ref) == B_OK) {
144 			Model model(&ref, true);
145 			if (model.InitCheck() != B_OK)
146 				return true;
147 
148 			BMenuItem *item = BNavMenu::NewModelItem(&model,
149 				model.IsDirectory() ? fOpenFolderMessage : fOpenFileMessage,
150 				fTarget);
151 
152 			item->SetLabel(ref.name);		// this is the name of the link in the Go dir
153 
154 			if (!fAddedSeparatorForSection) {
155 				fAddedSeparatorForSection = true;
156 				AddItem(new TitledSeparatorItem("Favorite Folders"));
157 			}
158 			fUniqueRefCheck.push_back(*model.EntryRef());
159 			AddItem(item);
160 			fSectionItemCount++;
161 			return true;
162 		}
163 
164 		// done with favorites, set up for adding recent files
165 		fState = kAddingFiles;
166 
167 		fAddedSeparatorForSection = false;
168 
169 		app_info info;
170 		be_app->GetAppInfo(&info);
171 		fItems.MakeEmpty();
172 
173 		int32 apps, docs, folders;
174 		TrackerSettings().RecentCounts(&apps, &docs, &folders);
175 
176 		BRoster().GetRecentDocuments(&fItems, docs, NULL, info.signature);
177 		fIndex = 0;
178 		fSectionItemCount = 0;
179 	}
180 
181 	if (fState == kAddingFiles) {
182 		//	if this is a Save panel, not an Open panel
183 		//	then don't add the recent documents
184 		if (!fIsSavePanel) {
185 			for (;;) {
186 				entry_ref ref;
187 				if (fItems.FindRef("refs", fIndex++, &ref) != B_OK)
188 					break;
189 				Model model(&ref, true);
190 				if (model.InitCheck() != B_OK)
191 					return true;
192 
193 				BMenuItem *item = BNavMenu::NewModelItem(&model, fOpenFileMessage, fTarget);
194 				if (item) {
195 					if (!fAddedSeparatorForSection) {
196 						fAddedSeparatorForSection = true;
197 						AddItem(new TitledSeparatorItem("Recent Documents"));
198 					}
199 					AddItem(item);
200 					fSectionItemCount++;
201 					return true;
202 				}
203 			}
204 		}
205 
206 		// done with recent files, set up for adding recent folders
207 		fState = kAddingFolders;
208 
209 		fAddedSeparatorForSection = false;
210 
211 		app_info info;
212 		be_app->GetAppInfo(&info);
213 		fItems.MakeEmpty();
214 
215 		int32 apps, docs, folders;
216 		TrackerSettings().RecentCounts(&apps, &docs, &folders);
217 
218 		BRoster().GetRecentFolders(&fItems, folders, info.signature);
219 		fIndex = 0;
220 	}
221 
222 	if (fState == kAddingFolders) {
223 		for (;;) {
224 			entry_ref ref;
225 			if (fItems.FindRef("refs", fIndex++, &ref) != B_OK)
226 				break;
227 
228 			// don't add folders that are already in the GoTo section
229 			if (find_if(fUniqueRefCheck.begin(), fUniqueRefCheck.end(),
230 				bind2nd(std::equal_to<entry_ref>(), ref)) != fUniqueRefCheck.end())
231 				continue;
232 
233 			Model model(&ref, true);
234 			if (model.InitCheck() != B_OK)
235 				return true;
236 
237 			BMenuItem *item = BNavMenu::NewModelItem(&model, fOpenFolderMessage,
238 				fTarget, true);
239 			if (item) {
240 				if (!fAddedSeparatorForSection) {
241 					fAddedSeparatorForSection = true;
242 					AddItem(new TitledSeparatorItem("Recent Folders"));
243 				}
244 				AddItem(item);
245 				item->SetEnabled(true);
246 					// BNavMenu::NewModelItem returns a disabled item here -
247 					// need to fix this in BNavMenu::NewModelItem
248 				return true;
249 			}
250 		}
251 	}
252 	return false;
253 }
254 
255 
256 void
257 FavoritesMenu::DoneBuildingItemList()
258 {
259 	SetTargetForItems(fTarget);
260 }
261 
262 
263 void
264 FavoritesMenu::ClearMenuBuildingState()
265 {
266 	delete fContainer;
267 	fContainer = NULL;
268 	fState = kDone;
269 
270 	// force the menu to get rebuilt each time
271 	fMenuBuilt = false;
272 }
273 
274 
275 //	#pragma mark -
276 
277 
278 RecentsMenu::RecentsMenu(const char *name,int32 which,uint32 what,BHandler *target)
279 	: BNavMenu(name, what, target),
280 	fWhich(which),
281 	fRecentsCount(0),
282 	fItemIndex(0)
283 {
284 	int32 applications;
285 	int32 documents;
286 	int32 folders;
287 	TrackerSettings().RecentCounts(&applications,&documents,&folders);
288 
289 	if (fWhich == 0)
290 		fRecentsCount = documents;
291 	else if (fWhich == 1)
292 		fRecentsCount = applications;
293 	else if (fWhich == 2)
294 		fRecentsCount = folders;
295 }
296 
297 
298 void
299 RecentsMenu::DetachedFromWindow()
300 {
301 	//
302 	//	BNavMenu::DetachedFromWindow sets the TypesList to NULL
303 	//
304 	BMenu::DetachedFromWindow();
305 }
306 
307 
308 bool
309 RecentsMenu::StartBuildingItemList()
310 {
311 	int32 count = CountItems()-1;
312 	for (int32 index = count; index >= 0; index--) {
313 		BMenuItem *item = ItemAt(index);
314 		ASSERT(item);
315 
316 		RemoveItem(index);
317 		delete item;
318 	}
319 	//
320 	//	!! note: don't call inherited from here
321 	//	the navref is not set for this menu
322 	//	but it still needs to be a draggable navmenu
323 	//	simply return true so that AddNextItem is called
324 	//
325 	//	return BNavMenu::StartBuildingItemList();
326 	return true;
327 }
328 
329 
330 bool
331 RecentsMenu::AddNextItem()
332 {
333 	if (fRecentsCount > 0 && AddRecents(fRecentsCount))
334 		return true;
335 
336 	fItemIndex = 0;
337 	return false;
338 }
339 
340 
341 bool
342 RecentsMenu::AddRecents(int32 count)
343 {
344 	if (fItemIndex == 0) {
345 		fRecentList.MakeEmpty();
346 		BRoster roster;
347 
348 		switch(fWhich) {
349 			case 0:
350 				roster.GetRecentDocuments(&fRecentList, count);
351 				break;
352 			case 1:
353 				roster.GetRecentApps(&fRecentList, count);
354 				break;
355 			case 2:
356 				roster.GetRecentFolders(&fRecentList, count);
357 				break;
358 			default:
359 				return false;
360 				break;
361 		}
362 	}
363 	for (;;) {
364 		entry_ref ref;
365 		if (fRecentList.FindRef("refs", fItemIndex++, &ref) != B_OK)
366 			break;
367 
368 		if (ref.name && strlen(ref.name) > 0) {
369 			Model model(&ref, true);
370 			ModelMenuItem *item = BNavMenu::NewModelItem(&model,
371 					new BMessage(fMessage.what),
372 					Target(), false, NULL, TypesList());
373 
374 			if (item) {
375 				AddItem(item);
376 
377 				//	return true so that we know to reenter this list
378 				return true;
379 			}
380 			return true;
381 		}
382 	}
383 
384 	//
385 	//	return false if we are done with this list
386 	//
387 	return false;
388 }
389 
390 
391 void
392 RecentsMenu::DoneBuildingItemList()
393 {
394 	//
395 	//	!! note: don't call inherited here
396 	//	the object list is not built
397 	//	and this list does not need to be sorted
398 	//	BNavMenu::DoneBuildingItemList();
399 	//
400 
401 	if (CountItems() <= 0) {
402 		BMenuItem *item = new BMenuItem("<No Recent Items>", 0);
403 		item->SetEnabled(false);
404 		AddItem(item);
405 	} else
406 		SetTargetForItems(Target());
407 }
408 
409 
410 void
411 RecentsMenu::ClearMenuBuildingState()
412 {
413 	fMenuBuilt = false;
414 	BNavMenu::ClearMenuBuildingState();
415 }
416 
417