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