6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
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:
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.
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.
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.
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered
30 trademarks of Be Incorporated in the United States and other countries. Other
31 brand product names are registered trademarks or trademarks of their respective
37 #include "DeskbarMenu.h"
50 #include "DeskbarUtils.h"
51 #include "IconMenuItem.h"
52 #include "MountMenu.h"
53 #include "RecentItems.h"
54 #include "StatusView.h"
56 #include "tracker_private.h"
58 #undef B_TRANSLATION_CONTEXT
59 #define B_TRANSLATION_CONTEXT "DeskbarMenu"
61 #define ROSTER_SIG "application/x-vnd.Be-ROST"
63 #ifdef MOUNT_MENU_IN_DESKBAR
64 class DeskbarMountMenu
: public BPrivate::MountMenu
{
66 DeskbarMountMenu(const char* name
);
67 virtual bool AddDynamicItem(add_state s
);
69 #endif // MOUNT_MENU_IN_DESKBAR
71 //#define SHOW_RECENT_FIND_ITEMS
74 BMenu
* TrackerBuildRecentFindItemsMenu(const char*);
77 using namespace BPrivate
;
80 // #pragma mark - TDeskbarMenu
83 TDeskbarMenu::TDeskbarMenu(TBarView
* barView
)
85 BNavMenu("DeskbarMenu", B_REFS_RECEIVED
, DefaultTarget()),
93 TDeskbarMenu::AttachedToWindow()
95 if (fBarView
!= NULL
&& fBarView
->LockLooper()) {
96 if (fBarView
->Dragging()) {
97 SetTypesList(fBarView
->CachedTypesList());
98 SetTarget(BMessenger(fBarView
));
99 SetTrackingHookDeep(this, fBarView
->MenuTrackingHook
,
100 fBarView
->GetTrackingHookData());
101 fBarView
->DragStart();
104 SetTarget(DefaultTarget());
105 SetTrackingHookDeep(this, NULL
, NULL
);
108 fBarView
->UnlockLooper();
111 BNavMenu::AttachedToWindow();
116 TDeskbarMenu::DetachedFromWindow()
118 if (fBarView
!= NULL
) {
119 BLooper
* looper
= fBarView
->Looper();
120 if (looper
!= NULL
&& looper
->Lock()) {
121 fBarView
->DragStop();
126 // don't call BNavMenu::DetachedFromWindow
127 // it sets the TypesList to NULL
128 BMenu::DetachedFromWindow();
133 TDeskbarMenu::StartBuildingItemList()
135 RemoveItems(0, CountItems(), true);
137 return BNavMenu::StartBuildingItemList();
142 TDeskbarMenu::DoneBuildingItemList()
144 if (fItemList
->CountItems() <= 0) {
146 = new BMenuItem(B_TRANSLATE("<Deskbar folder is empty>"), 0);
147 item
->SetEnabled(false);
150 BNavMenu::DoneBuildingItemList();
155 TDeskbarMenu::AddNextItem()
157 if (fAddState
== kStart
)
158 return AddStandardDeskbarMenuItems();
160 TrackingHookData
* data
= fBarView
->GetTrackingHookData();
161 if (fAddState
== kAddingRecents
) {
162 static const char* recentTitle
[] = {
163 B_TRANSLATE_MARK("Recent documents"),
164 B_TRANSLATE_MARK("Recent folders"),
165 B_TRANSLATE_MARK("Recent applications")};
166 const int recentType
[] = {kRecentDocuments
, kRecentFolders
,
167 kRecentApplications
};
168 const int recentTypes
= 3;
169 TRecentsMenu
* recentItem
[recentTypes
];
171 bool enabled
= false;
173 for (int i
= 0; i
< recentTypes
; i
++) {
175 = new TRecentsMenu(B_TRANSLATE_NOCOLLECT(recentTitle
[i
]),
176 fBarView
, recentType
[i
]);
179 enabled
|= recentItem
[i
]->RecentsEnabled();
184 for (int i
= 0; i
< recentTypes
; i
++) {
188 if (recentItem
[i
]->RecentsEnabled()) {
189 recentItem
[i
]->SetTypesList(TypesList());
190 recentItem
[i
]->SetTarget(Target());
191 AddItem(recentItem
[i
]);
194 if (data
&& fBarView
&& fBarView
->Dragging()) {
195 recentItem
[i
]->InitTrackingHook(data
->fTrackingHook
,
196 &data
->fTarget
, data
->fDragMessage
);
200 for (int i
= 0; i
< recentTypes
; i
++)
201 delete recentItem
[i
];
205 fAddState
= kAddingDeskbarMenu
;
209 if (fAddState
== kAddingDeskbarMenu
) {
210 // keep reentering and adding items
211 // until this returns false
212 bool done
= BNavMenu::AddNextItem();
213 BMenuItem
* item
= ItemAt(CountItems() - 1);
215 BNavMenu
* menu
= dynamic_cast<BNavMenu
*>(item
->Menu());
217 if (data
&& fBarView
->Dragging()) {
218 menu
->InitTrackingHook(data
->fTrackingHook
,
219 &data
->fTarget
, data
->fDragMessage
);
221 menu
->InitTrackingHook(0, NULL
, NULL
);
235 TDeskbarMenu::AddStandardDeskbarMenuItems()
237 bool dragging
= false;
239 dragging
= fBarView
->Dragging();
243 // One of them is used if HAIKU_DISTRO_COMPATIBILITY_OFFICIAL, and the other if
244 // not. However, we want both of them to end up in the catalog, so we have to
245 // make them visible to collectcatkeys in either case.
246 B_TRANSLATE_MARK_VOID("About Haiku")
247 B_TRANSLATE_MARK_VOID("About this system")
249 item
= new BMenuItem(
250 #ifdef HAIKU_DISTRO_COMPATIBILITY_OFFICIAL
251 B_TRANSLATE_NOCOLLECT("About Haiku")
253 B_TRANSLATE_NOCOLLECT("About this system")
255 , new BMessage(kShowSplash
));
256 item
->SetEnabled(!dragging
);
259 static const char* kFindMenuItemStr
260 = B_TRANSLATE_MARK("Find" B_UTF8_ELLIPSIS
);
262 #ifdef SHOW_RECENT_FIND_ITEMS
263 item
= new BMenuItem(
264 TrackerBuildRecentFindItemsMenu(kFindMenuItemStr
),
265 new BMessage(kFindButton
));
267 item
= new BMenuItem(B_TRANSLATE_NOCOLLECT(kFindMenuItemStr
),
268 new BMessage(kFindButton
));
270 item
->SetEnabled(!dragging
);
273 item
= new BMenuItem(B_TRANSLATE("Show replicants"),
274 new BMessage(kToggleDraggers
));
275 item
->SetEnabled(!dragging
);
276 item
->SetMarked(BDragger::AreDraggersDrawn());
279 static const char* kMountMenuStr
= B_TRANSLATE_MARK("Mount");
281 #ifdef MOUNT_MENU_IN_DESKBAR
282 DeskbarMountMenu
* mountMenu
= new DeskbarMountMenu(
283 B_TRANSLATE_NOCOLLECT(kMountMenuStr
));
284 mountMenu
->SetEnabled(!dragging
);
288 item
= new BMenuItem(B_TRANSLATE("Deskbar preferences" B_UTF8_ELLIPSIS
),
289 new BMessage(kConfigShow
));
290 item
->SetTarget(be_app
);
295 BMenu
* shutdownMenu
= new BMenu(B_TRANSLATE("Shutdown" B_UTF8_ELLIPSIS
));
297 item
= new BMenuItem(B_TRANSLATE("Restart system"),
298 new BMessage(kRebootSystem
));
299 item
->SetEnabled(!dragging
);
300 shutdownMenu
->AddItem(item
);
302 B_TRANSLATE_MARK_VOID("Suspend");
305 if (_kapm_control_(APM_CHECK_ENABLED
) == B_OK
) {
306 item
= new BMenuItem(B_TRANSLATE_NOCOLLECT("Suspend"),
307 new BMessage(kSuspendSystem
));
308 item
->SetEnabled(!dragging
);
309 shutdownMenu
->AddItem(item
);
313 item
= new BMenuItem(B_TRANSLATE("Power off"),
314 new BMessage(kShutdownSystem
));
315 item
->SetEnabled(!dragging
);
316 shutdownMenu
->AddItem(item
);
317 shutdownMenu
->SetFont(be_plain_font
);
319 shutdownMenu
->SetTargetForItems(be_app
);
320 BMessage
* message
= new BMessage(kShutdownSystem
);
321 message
->AddBool("confirm", true);
322 AddItem(new BMenuItem(shutdownMenu
, message
));
324 fAddState
= kAddingRecents
;
331 TDeskbarMenu::ClearMenuBuildingState()
335 // force the menu to get rebuilt each time
336 BNavMenu::ClearMenuBuildingState();
341 TDeskbarMenu::ResetTargets()
343 // This method does not recurse into submenus
344 // and does not affect menu items in submenus.
345 // (e.g. "Restart System" and "Power Off")
347 BNavMenu::ResetTargets();
349 // if we are dragging, set the target to whatever was set
350 // else set it to the default (Tracker)
351 if (!fBarView
->Dragging())
352 SetTarget(DefaultTarget());
354 // now set the target for the menuitems to the currently
355 // set target, which may or may not be tracker
356 SetTargetForItems(Target());
358 for (int32 i
= 0; ; i
++) {
359 BMenuItem
* item
= ItemAt(i
);
363 if (item
->Message()) {
364 switch (item
->Message()->what
) {
366 item
->SetTarget(BMessenger(kTrackerSignature
));
370 case kToggleDraggers
:
374 case kExpandNewTeams
:
376 case kResizeTeamIcons
:
377 case kSortRunningApps
:
381 case kShutdownSystem
:
382 case kRealignReplicants
:
387 case kGetClockSettings
:
388 item
->SetTarget(be_app
);
397 TDeskbarMenu::ScreenLocation()
399 bool vertical
= fBarView
->Vertical();
400 int32 expando
= (fBarView
->State() == kExpandoState
);
403 BRect rect
= Supermenu()->Bounds();
404 Supermenu()->ConvertToScreen(&rect
);
406 if (expando
&& vertical
&& fBarView
->Left()) {
408 point
= rect
.RightTop() + BPoint(0, 3);
409 } else if (expando
&& vertical
&& !fBarView
->Left()) {
411 point
= rect
.LeftTop() - BPoint(Bounds().Width(), 0) + BPoint(0, 3);
413 point
= BMenu::ScreenLocation();
421 TDeskbarMenu::DefaultTarget()
423 // if Tracker is not available we target the BarApp
424 BMessenger
target(kTrackerSignature
);
425 if (target
.IsValid())
428 return BMessenger(be_app
);
435 TRecentsMenu::TRecentsMenu(const char* name
, TBarView
* bar
, int32 which
,
436 const char* signature
, entry_ref
* appRef
)
437 : BNavMenu(name
, B_REFS_RECEIVED
, TDeskbarMenu::DefaultTarget()),
442 fRecentsEnabled(false),
446 TBarApp
* app
= dynamic_cast<TBarApp
*>(be_app
);
451 case kRecentDocuments
:
452 fRecentsCount
= app
->Settings()->recentDocsCount
;
453 fRecentsEnabled
= app
->Settings()->recentDocsEnabled
;
455 case kRecentApplications
:
456 fRecentsCount
= app
->Settings()->recentAppsCount
;
457 fRecentsEnabled
= app
->Settings()->recentAppsEnabled
;
459 case kRecentAppDocuments
:
460 fRecentsCount
= app
->Settings()->recentDocsCount
;
461 fRecentsEnabled
= app
->Settings()->recentDocsEnabled
;
462 if (signature
!= NULL
)
463 fSignature
= strdup(signature
);
465 fAppRef
= new entry_ref(*appRef
);
468 fRecentsCount
= app
->Settings()->recentFoldersCount
;
469 fRecentsEnabled
= app
->Settings()->recentFoldersEnabled
;
475 TRecentsMenu::~TRecentsMenu()
483 TRecentsMenu::DetachedFromWindow()
485 // BNavMenu::DetachedFromWindow sets the TypesList to NULL
486 BMenu::DetachedFromWindow();
491 TRecentsMenu::StartBuildingItemList()
493 RemoveItems(0, CountItems(), true);
495 // !! note: don't call inherited from here
496 // the navref is not set for this menu
497 // but it still needs to be a draggable navmenu
498 // simply return true so that AddNextItem is called
500 // return BNavMenu::StartBuildingItemList();
506 TRecentsMenu::AddNextItem()
508 if (fRecentsCount
> 0 && fRecentsEnabled
&& AddRecents(fRecentsCount
))
517 TRecentsMenu::AddRecents(int32 count
)
519 if (fItemIndex
== 0) {
520 fRecentList
.MakeEmpty();
524 case kRecentDocuments
:
525 roster
.GetRecentDocuments(&fRecentList
, count
);
527 case kRecentApplications
:
528 roster
.GetRecentApps(&fRecentList
, count
);
530 case kRecentAppDocuments
:
531 roster
.GetRecentDocuments(&fRecentList
, count
, NULL
,
535 roster
.GetRecentFolders(&fRecentList
, count
);
544 if (fRecentList
.FindRef("refs", fItemIndex
++, &ref
) != B_OK
)
547 if (ref
.name
&& strlen(ref
.name
) > 0) {
548 Model
model(&ref
, true);
550 if (fWhich
!= kRecentApplications
) {
551 BMessage
* message
= new BMessage(B_REFS_RECEIVED
);
552 if (fWhich
== kRecentAppDocuments
) {
553 // add application as handler
554 message
->AddRef("handler", fAppRef
);
557 ModelMenuItem
* item
= BNavMenu::NewModelItem(&model
,
558 message
, Target(), false, NULL
, TypesList());
563 // The application items expand to a list of recent documents
564 // for that application - so they must be handled extra
565 BFile
file(&ref
, B_READ_ONLY
);
566 char signature
[B_MIME_TYPE_LENGTH
];
568 BAppFileInfo
appInfo(&file
);
569 if (appInfo
.InitCheck() != B_OK
570 || appInfo
.GetSignature(signature
) != B_OK
)
573 ModelMenuItem
* item
= NULL
;
575 be_roster
->GetRecentDocuments(&doc
, 1, NULL
, signature
);
576 // ToDo: check if the documents do exist at all to
577 // avoid the creation of the submenu.
579 if (doc
.CountNames(B_REF_TYPE
) > 0) {
580 // create recents menu that will contain the recent docs of
582 TRecentsMenu
* docs
= new TRecentsMenu(model
.Name(),
583 fBarView
, kRecentAppDocuments
, signature
, &ref
);
584 docs
->SetTypesList(TypesList());
585 docs
->SetTarget(Target());
587 item
= new ModelMenuItem(&model
, docs
);
589 item
= new ModelMenuItem(&model
, model
.Name(), NULL
);
592 // add refs-message so that the recent app can be launched
593 BMessage
* msg
= new BMessage(B_REFS_RECEIVED
);
594 msg
->AddRef("refs", &ref
);
595 item
->SetMessage(msg
);
596 item
->SetTarget(Target());
602 // return true so that we know to reenter this list
607 // return false if we are done with this list
613 TRecentsMenu::DoneBuildingItemList()
615 // !! note: don't call inherited here
616 // the object list is not built
617 // and this list does not need to be sorted
618 // BNavMenu::DoneBuildingItemList();
620 if (CountItems() > 0)
621 SetTargetForItems(Target());
626 TRecentsMenu::ClearMenuBuildingState()
629 BNavMenu::ClearMenuBuildingState();
634 TRecentsMenu::ResetTargets()
636 BNavMenu::ResetTargets();
638 // if we are dragging, set the target to whatever was set
639 // else set it to the default (Tracker)
640 if (!fBarView
->Dragging())
641 SetTarget(TDeskbarMenu::DefaultTarget());
643 // now set the target for the menuitems to the currently
644 // set target, which may or may not be tracker
645 SetTargetForItems(Target());
649 // #pragma mark - DeskbarMountMenu
652 #ifdef MOUNT_MENU_IN_DESKBAR
653 DeskbarMountMenu::DeskbarMountMenu(const char* name
)
654 : BPrivate::MountMenu(name
)
656 SetFont(be_plain_font
);
661 DeskbarMountMenu::AddDynamicItem(add_state s
)
663 BPrivate::MountMenu::AddDynamicItem(s
);
665 SetTargetForItems(BMessenger(kTrackerSignature
));
669 #endif // MOUNT_MENU_IN_DESKBAR