зеркало из https://github.com/mozilla/pjs.git
402 строки
11 KiB
C++
402 строки
11 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||
*
|
||
* The contents of this file are subject to the Netscape Public License
|
||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||
* http://www.mozilla.org/NPL/
|
||
*
|
||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||
* for the specific language governing rights and limitations under the
|
||
* NPL.
|
||
*
|
||
* The Initial Developer of this code under the NPL is Netscape
|
||
* Communications Corporation. Portions created by Netscape are
|
||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||
* Reserved.
|
||
*/
|
||
|
||
// Handle creating and maintaining the top-level bookmarks menu. It pulls the info
|
||
// out of the RDF container the user designates as their "quickfile menu" and listens
|
||
// to the messages from RDF to update it.
|
||
|
||
#include "CBookmarksAttachment.h"
|
||
|
||
#include "htrdf.h"
|
||
#include "CNetscapeWindow.h"
|
||
#include "URDFUtilities.h"
|
||
#include "net.h"
|
||
#include "resgui.h"
|
||
#include "uapp.h"
|
||
#include "macutil.h"
|
||
|
||
#include "UMenuUtils.h"
|
||
|
||
#include <Icons.h>
|
||
#include <Sound.h>
|
||
|
||
|
||
LMenu *CBookmarksAttachment::sMenu = NULL;
|
||
Boolean CBookmarksAttachment::sInvalidMenu = true;
|
||
LArray CBookmarksAttachment::sMenusList; // this will use the default constructor
|
||
|
||
HT_View CBookmarksAttachment::sQuickfileView = NULL;
|
||
|
||
const uint32 PERM_BOOKMARK_ITEMS = 2;
|
||
const CommandT cmd_BookmarkHierItem = BOOKMARKS_MENU_BASE_LAST;
|
||
|
||
|
||
//===========================================================
|
||
// CBookmarksAttachment
|
||
//===========================================================
|
||
CBookmarksAttachment::CBookmarksAttachment()
|
||
{
|
||
InitQuickfileView();
|
||
}
|
||
|
||
|
||
//
|
||
// InitQuickfileView
|
||
//
|
||
// Called at startup to get a new view from the HT backend that represents the
|
||
// bookmarks menu. This can be called multiple times without problems.
|
||
//
|
||
void
|
||
CBookmarksAttachment :: InitQuickfileView ( )
|
||
{
|
||
if ( ! sQuickfileView ) {
|
||
HT_Notification notifyStruct = CreateNotificationStruct();
|
||
HT_Pane quickfilePane = HT_NewQuickFilePane(notifyStruct);
|
||
|
||
sQuickfileView = HT_GetSelectedView(quickfilePane);
|
||
}
|
||
|
||
} // InitQuickfileView
|
||
|
||
|
||
void
|
||
CBookmarksAttachment :: HandleNotification( HT_Notification /* notifyStruct*/,
|
||
HT_Resource node, HT_Event event, void *token, uint32 tokenType)
|
||
{
|
||
switch (event) {
|
||
|
||
case HT_EVENT_NODE_ADDED:
|
||
case HT_EVENT_VIEW_REFRESH:
|
||
// only update menu if the quickfile view changes
|
||
//<2F><><EFBFBD>We need a way to not update on node_added events else we add items to the
|
||
//<2F><><EFBFBD>bookmarks menu on the order of N^2 where N is # of bookmarks.
|
||
if ( HT_GetView(node) == sQuickfileView ) {
|
||
sInvalidMenu = true;
|
||
UpdateMenu();
|
||
}
|
||
break;
|
||
|
||
case HT_EVENT_NODE_VPROP_CHANGED:
|
||
// optimization: only update when the name column changes
|
||
break;
|
||
|
||
case HT_EVENT_NODE_DELETED_DATA:
|
||
case HT_EVENT_NODE_DELETED_NODATA:
|
||
// free FE data, but don't update the menu yet (HT not in good state)
|
||
break;
|
||
|
||
} // case of which event
|
||
|
||
} // HandleNotification
|
||
|
||
|
||
// Processes:
|
||
//
|
||
void CBookmarksAttachment::ExecuteSelf( MessageT inMessage, void* ioParam )
|
||
{
|
||
mExecuteHost = FALSE;
|
||
|
||
switch ( inMessage )
|
||
{
|
||
CNetscapeWindow *bookmarkableWindow = nil;
|
||
|
||
case msg_CommandStatus:
|
||
{
|
||
SCommandStatus* status = (SCommandStatus*)ioParam;
|
||
|
||
switch ( status->command )
|
||
{
|
||
|
||
default:
|
||
if (CFrontApp::GetApplication()->HasBookmarksMenu())
|
||
{
|
||
if ( status->command >= BOOKMARKS_MENU_BASE && status->command <= BOOKMARKS_MENU_BASE_LAST )
|
||
{
|
||
*(status->enabled) = TRUE;
|
||
*(status->usesMark) = FALSE;
|
||
return;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
|
||
default:
|
||
{
|
||
if (CFrontApp::GetApplication()->HasBookmarksMenu())
|
||
{
|
||
if ( inMessage >= BOOKMARKS_MENU_BASE && inMessage <= BOOKMARKS_MENU_BASE_LAST )
|
||
{
|
||
Uint32 index = inMessage - BOOKMARKS_MENU_BASE;
|
||
|
||
// load the url
|
||
HT_Resource itemNode = HT_GetNthItem(sQuickfileView, index);
|
||
char* url = HT_GetNodeURL( itemNode );
|
||
if ( !URDFUtilities::LaunchNode(itemNode) && url )
|
||
CFrontApp::DoGetURL ( url );
|
||
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
mExecuteHost = TRUE; // Let application handle it
|
||
}
|
||
|
||
|
||
void CBookmarksAttachment::AddToBookmarks( const char* url, const CStr255& title )
|
||
{
|
||
HT_Resource topNode = HT_TopNode ( sQuickfileView );
|
||
HT_AddBookmark ( const_cast<char*>(url), title );
|
||
}
|
||
|
||
|
||
LMenu *CBookmarksAttachment::GetMenu()
|
||
{
|
||
if (!sMenu)
|
||
{
|
||
sMenu = new LMenu(cBookmarksMenuID);
|
||
|
||
if (sMenu)
|
||
{
|
||
MenuHandle macMenu = sMenu->GetMacMenuH();
|
||
|
||
if (macMenu)
|
||
UMenuUtils::ConvertToIconMenu(macMenu, 15312);
|
||
}
|
||
}
|
||
return sMenu;
|
||
}
|
||
|
||
void CBookmarksAttachment::UpdateMenu()
|
||
{
|
||
if (CFrontApp::GetApplication()->HasBookmarksMenu())
|
||
{
|
||
if (!sInvalidMenu || !GetMenu() || !LMenuBar::GetCurrentMenuBar() )
|
||
return;
|
||
|
||
int i;
|
||
|
||
// <20> delete all the dynamically created menus
|
||
// <20><>delete all the hierarchical menus we have added from the menubar
|
||
for ( i = 1; i <= sMenusList.GetCount(); i++ )
|
||
{
|
||
LMenu* m;
|
||
sMenusList.FetchItemAt( i, &m );
|
||
if ( m )
|
||
LMenuBar::GetCurrentMenuBar()->RemoveMenu( m );
|
||
delete m;
|
||
}
|
||
|
||
// <20> delete all the menu items after the line in Bookmark menu
|
||
MenuHandle menu = sMenu->GetMacMenuH();
|
||
if ( menu )
|
||
{
|
||
int howMany = ::CountMItems( menu );
|
||
for ( i = howMany; i > PERM_BOOKMARK_ITEMS; i-- )
|
||
sMenu->RemoveItem( i );
|
||
}
|
||
sMenusList.RemoveItemsAt( sMenusList.GetCount(), 1 );
|
||
|
||
// <20> walk through the list, and let the submenus be inserted recursively
|
||
int nextMenuID = cBookmarksFirstHierMenuID;
|
||
FillMenuFromList( HT_TopNode(sQuickfileView), sMenu, nextMenuID, PERM_BOOKMARK_ITEMS, 0 );
|
||
|
||
sInvalidMenu = false;
|
||
}
|
||
}
|
||
|
||
// <20><>recursively create submenus, given a list ptr
|
||
// returns NULL if the menu cannot be created
|
||
// it creates submenus recursively
|
||
void CBookmarksAttachment::FillMenuFromList(
|
||
HT_Resource top,
|
||
LMenu* newMenu,
|
||
int& nextMenuID, // next menu to create
|
||
int whichItem, // id of the first item to insert
|
||
int depth ) // how deep are we?
|
||
{
|
||
// keep us from infinite recursion if the data file contains an infinite loop
|
||
if ( depth > 4 )
|
||
return;
|
||
|
||
if (CFrontApp::GetApplication()->HasBookmarksMenu())
|
||
{
|
||
Try_
|
||
{
|
||
ThrowIfNil_( newMenu );
|
||
MenuHandle mHand = newMenu->GetMacMenuH();
|
||
|
||
ThrowIfNil_( mHand );
|
||
|
||
// <20><>remove all the extra items if they exist
|
||
long removeThese = ::CountMItems( mHand ) - whichItem;
|
||
for ( long i = 1; i < removeThese; i++ )
|
||
newMenu->RemoveItem( whichItem );
|
||
|
||
MenuHandle theMacMenu = newMenu->GetMacMenuH();
|
||
|
||
// Open up the container and get an iterator on its contents (we have to open it before
|
||
// we can see anything inside it). If the cursor is null, it is probably because the container
|
||
// is locked so just put up a leaf item (disabled, of course) and bail.
|
||
HT_SetOpenState ( top, PR_TRUE );
|
||
HT_Cursor cursor = HT_NewCursor( top );
|
||
if ( !cursor ) {
|
||
whichItem = UMenuUtils::InsertMenuItem(theMacMenu, "\pLocked", whichItem);
|
||
newMenu->SetCommand(whichItem, 0);
|
||
return;
|
||
}
|
||
|
||
HT_Resource currNode = HT_GetNextItem(cursor);
|
||
while ( currNode )
|
||
{
|
||
if ( HT_IsSeparator(currNode) )
|
||
newMenu->InsertCommand( "\p-", cmd_Nothing, whichItem++ );
|
||
else if ( ! HT_IsContainer(currNode) )
|
||
{
|
||
// <20> should really convert this to menu chars
|
||
CStr255 urlName( HT_GetNodeName(currNode) );
|
||
CreateMenuString( urlName );
|
||
|
||
whichItem = UMenuUtils::InsertMenuItem(theMacMenu, urlName, whichItem); // returns actual insert loc
|
||
newMenu->SetCommand(whichItem, BOOKMARKS_MENU_BASE + HT_GetNodeIndex(sQuickfileView, currNode) );
|
||
|
||
}
|
||
else
|
||
{
|
||
CStr255 headerName( HT_GetNodeName(currNode) );
|
||
CreateMenuString( headerName );
|
||
|
||
whichItem = UMenuUtils::InsertMenuItem(theMacMenu, headerName, whichItem); // returns actual insert loc
|
||
newMenu->SetCommand(whichItem, cmd_BookmarkHierItem);
|
||
|
||
// <20><>do we have space to create more?
|
||
if ( nextMenuID <= cBookmarksLastHierMenuID)
|
||
{
|
||
LMenu* subMenu = (LMenuBar::GetCurrentMenuBar())->FetchMenu( nextMenuID );
|
||
if ( !subMenu )
|
||
{
|
||
StringHandle menuStringH = GetString( NEW_RESID );
|
||
Assert_(menuStringH);
|
||
if (menuStringH)
|
||
{
|
||
StHandleLocker locker((Handle)menuStringH);
|
||
subMenu = new LMenu( nextMenuID,
|
||
(unsigned char *)*menuStringH );
|
||
LMenuBar::GetCurrentMenuBar()->InstallMenu( subMenu, hierMenu );
|
||
}
|
||
}
|
||
else
|
||
SysBeep( 1 );
|
||
|
||
nextMenuID++;
|
||
|
||
// Skip the "Apple" menu or we're in deep donuts.
|
||
if (nextMenuID == MENU_Apple)
|
||
nextMenuID++;
|
||
|
||
if ( subMenu )
|
||
{
|
||
sMenusList.InsertItemsAt( 1, LArray::index_Last, &subMenu );
|
||
// <20><>make item hierarchical
|
||
::SetItemCmd( mHand, whichItem, hMenuCmd );
|
||
::SetItemMark( mHand, whichItem, subMenu->GetMenuID() );
|
||
if ( currNode )
|
||
FillMenuFromList( currNode, subMenu, nextMenuID, 0, depth+1 );
|
||
}
|
||
}
|
||
}
|
||
|
||
currNode = HT_GetNextItem ( cursor );
|
||
|
||
} // while
|
||
}
|
||
Catch_( inErr )
|
||
{
|
||
}
|
||
EndCatch_
|
||
}
|
||
}
|
||
|
||
void CBookmarksAttachment::RemoveMenus()
|
||
{
|
||
if (CFrontApp::GetApplication()->HasBookmarksMenu())
|
||
{
|
||
if (sMenu)
|
||
{
|
||
LMenuBar *currentMenuBar = LMenuBar::GetCurrentMenuBar();
|
||
|
||
if (currentMenuBar)
|
||
{
|
||
currentMenuBar->RemoveMenu(sMenu);
|
||
|
||
for (ArrayIndexT index = 1; index <= sMenusList.GetCount(); ++index)
|
||
{
|
||
LMenu *menu;
|
||
sMenusList.FetchItemAt(index, &menu);
|
||
|
||
if (menu)
|
||
currentMenuBar->RemoveMenu(menu);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void CBookmarksAttachment::InstallMenus()
|
||
{
|
||
if (CFrontApp::GetApplication()->HasBookmarksMenu())
|
||
{
|
||
if (GetMenu())
|
||
{
|
||
LMenuBar *currentMenuBar = LMenuBar::GetCurrentMenuBar();
|
||
|
||
if (currentMenuBar)
|
||
{
|
||
for (ArrayIndexT index = sMenusList.GetCount(); index > 0; --index)
|
||
{
|
||
LMenu *menu;
|
||
sMenusList.FetchItemAt(index, &menu);
|
||
|
||
if (menu)
|
||
{
|
||
StValueChanger<EDebugAction> okayToFail(gDebugThrow, debugAction_Nothing);
|
||
currentMenuBar->InstallMenu(menu, hierMenu);
|
||
}
|
||
}
|
||
StValueChanger<EDebugAction> okayToFail(gDebugThrow, debugAction_Nothing);
|
||
currentMenuBar->InstallMenu(sMenu, InstallMenu_AtEnd);
|
||
#if 0
|
||
// no more Guide menu. Leave this here in case mktg wants to replace it with something (pinkerton).
|
||
LMenu *directoryMenu = currentMenuBar->FetchMenu(cDirectoryMenuID);
|
||
|
||
if (directoryMenu)
|
||
{
|
||
CFrontApp::BuildConfigurableMenu( directoryMenu->GetMacMenuH(), "menu.places.item" );
|
||
|
||
for (short index2 = CountMItems(directoryMenu->GetMacMenuH()); index2 > 0; --index2)
|
||
directoryMenu->SetCommand(index2, DIR_MENU_BASE + index2 - 1);
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
}
|