gecko-dev/cmd/macfe/gui/CPersonalToolbarManager.cp
1998-03-28 02:44:41 +00:00

316 lines
10 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.
*/
//
// CPersonalToolbarManager.cp
//
// Implementation of the CPersonalToolbarManager class which handles keeping all the
// personal toolbars in sync. This reads all its info from RDF, not the old BM UI.
//
// I REALLY dislike that most of this code is in Hungarian notation, but the Windows
// code that it originally came from was like that and instead of doing a slew of
// global replaces, I'll just complain about it.
//
#include "CPersonalToolbarManager.h"
#include "CPersonalToolbarTable.h"
#include "URDFUtilities.h"
#include "prefapi.h"
#pragma mark ¥¥ CPersonalToolbarManager
#pragma mark -- Public Methods
const char* CPersonalToolbarManager::kMaxButtonCharsPref = "browser.personal_toolbar_button.max_chars";
const char* CPersonalToolbarManager::kMinButtonCharsPref = "browser.personal_toolbar_button.min_chars";
//
// Constructor
//
// Setup. Assumes that preferences and RDF have been initialized fully by this point.
//
CPersonalToolbarManager :: CPersonalToolbarManager ( )
: mUserButtonInfoArray ( sizeof(CUserButtonInfo*) )
{
// setup our window into the RDF world and register this class as the one to be notified
// when the personal toolbar changes.
HT_Notification notifyStruct = CreateNotificationStruct();
mToolbarView = HT_GetSelectedView ( HT_NewPersonalToolbarPane(notifyStruct) );
Assert_(mToolbarView != NULL);
mToolbarRoot = HT_TopNode ( mToolbarView );
Assert_(mToolbarRoot != NULL);
HT_SetOpenState ( mToolbarRoot, PR_TRUE ); // ensure container is open so we can see its contents
// read in the maximum size we're allowing for personal toolbar items. If not
// found in prefs, use our own
int32 maxToolbarButtonChars, minToolbarButtonChars;
if ( PREF_GetIntPref(kMaxButtonCharsPref, &maxToolbarButtonChars ) == PREF_ERROR )
mMaxToolbarButtonChars = CPersonalToolbarManager::kMaxPersonalToolbarChars;
else
mMaxToolbarButtonChars = maxToolbarButtonChars;
if ( PREF_GetIntPref(kMinButtonCharsPref, &minToolbarButtonChars ) == PREF_ERROR )
mMinToolbarButtonChars = CPersonalToolbarManager::kMinPersonalToolbarChars;
else
mMinToolbarButtonChars = minToolbarButtonChars;
InitializeButtonInfo();
} // constructor
//
// Destructor
//
// The toolbars in individual windows will delete themselves when the window dies and
// unregister themselves as listeners. We don't need to do anything along those
// lines here.
//
CPersonalToolbarManager :: ~CPersonalToolbarManager ( )
{
//¥¥¥ delete the contents of the button list
} // destructor
//
// RegisterNewToolbar
//
// This must be called for each new toolbar created in a browser window. It fills in
// the toolbar with the correct items and registers it as a listener to the messages
// we emit.
//
void
CPersonalToolbarManager :: RegisterNewToolbar ( CPersonalToolbarTable* inBar )
{
AddListener ( inBar );
BroadcastMessage ( k_PTToolbarChanged );
} // RegisterNewToolbar
//
// ToolbarChanged
//
// The user has just made some change to the toolbar, such as manipulating items in the nav center
// or changing the personal toolbar folder. Since these changes could be quite extensive, we
// just clear out the whole thing and start afresh. Tell all the toolbars that they have to
// clear themselves and grab the new information. Changes to the toolbar directly, such as by
// drag and drop, are handled elsewhere.
//
void
CPersonalToolbarManager :: ToolbarChanged ( )
{
RemoveToolbarButtons(); // out with the old...
InitializeButtonInfo(); // ...in with the new
BroadcastMessage ( k_PTToolbarChanged );
} // ToolbarHeaderChanged
//
// AddButton
//
// Given a pre-created HT item, add it to the personal toolbar folder before the
// given id and tell all the toolbars to update. This is called when the user
// drops an item from another RDF source on a personal toolbar
//
void
CPersonalToolbarManager :: AddButton ( HT_Resource inBookmark, Uint32 inIndex )
{
// Add this to RDF.
if ( GetButtons().GetCount() ) {
// If we get back a null resource then we must be trying to drop after
// the last element, or there just plain aren't any in the toolbar. Re-fetch the last element
// (using the correct index) and add the new bookmark AFTER instead of before or just add
// it to the parent for the case of an empty toolbar
PRBool before = PR_TRUE;
HT_Resource dropOn = HT_GetNthItem( mToolbarView, URDFUtilities::PPRowToHTRow(inIndex) );
if ( ! dropOn ) {
dropOn = HT_GetNthItem( mToolbarView, URDFUtilities::PPRowToHTRow(inIndex) - 1 );
before = PR_FALSE;
}
HT_DropHTRAtPos ( dropOn, inBookmark, before );
} // if items in toolbar
else
HT_DropHTROn ( mToolbarRoot, inBookmark );
// no need to tell toolbars to refresh because we will get an HT node added event and
// refresh at that time.
} // Addbutton
//
// AddButton
//
// Given just a URL, add it to the personal toolbar folder before the
// given id and tell all the toolbars to update. This is called when the user
// drops an item from another RDF source on a personal toolbar
//
void
CPersonalToolbarManager :: AddButton ( const string & inURL, const string & inTitle, Uint32 inIndex )
{
// Add this to RDF.
if ( GetButtons().GetCount() ) {
// If we get back a null resource then we must be trying to drop after
// the last element, or there just plain aren't any in the toolbar. Re-fetch the last element
// (using the correct index) and add the new bookmark AFTER instead of before or just add
// it to the parent for the case of an empty toolbar
PRBool before = PR_TRUE;
HT_Resource dropOn = HT_GetNthItem( mToolbarView, URDFUtilities::PPRowToHTRow(inIndex) );
if ( ! dropOn ) {
dropOn = HT_GetNthItem( mToolbarView, URDFUtilities::PPRowToHTRow(inIndex) - 1 );
before = PR_FALSE;
}
HT_DropURLAndTitleAtPos ( dropOn, const_cast<char*>(inURL.c_str()),
const_cast<char*>(inTitle.c_str()), before );
} // if items in toolbar
else
HT_DropURLAndTitleOn ( mToolbarRoot, const_cast<char*>(inURL.c_str()),
const_cast<char*>(inTitle.c_str()) );
// no need to tell toolbars to refresh because we will get an HT node added event and
// refresh at that time.
} // Addbutton
//
// RemoveButton
//
// The user has explicitly removed a button from the toolbar in one of the windows (probably
// by dragging it to the trash). Tell all the other toolbars about it, remove it from our
// own bookkeeping list, then let RDF get rid of it.
//
void
CPersonalToolbarManager :: RemoveButton ( Uint32 inIndex )
{
CUserButtonInfo* deadBookmark;
GetButtons().FetchItemAt ( inIndex, &deadBookmark );
// remove it from RDF
HT_Resource deadNode = HT_GetNthItem ( GetHTView(), URDFUtilities::PPRowToHTRow(inIndex) );
HT_RemoveChild ( mToolbarRoot, deadNode );
delete deadBookmark;
// no need to tell toolbars to refresh because we will get an HT view update event and
// refresh at that time.
} // RemoveButton
//
// RemoveToolbarButtons
//
// Clears out our own internal list of toolbar button information.
//
void
CPersonalToolbarManager :: RemoveToolbarButtons (void)
{
mUserButtonInfoArray.RemoveItemsAt(mUserButtonInfoArray.GetCount(), LArray::index_First);
} // RemoveToolbarButtons
#pragma mark -- Protected Utility Methods
///////////////////////////////////////////////////////////////////////////////////
// CPersonalToolbarManager Helpers
///////////////////////////////////////////////////////////////////////////////////
//
// InitializeButtonInfo
//
// Create our list of information for each bookmark that belongs in the toolbar. This
// involves iterating over the RDF data in the folder pre-selected to be the personal
// toolbar folder, compiling some info about it, and adding to an internal list which
// will be used by each toolbar to build their tables.
//
// ¥¥¥NOTE: this will put folders in the bar if they exist. Strange things may happen if the
// user clicks on them....
//
void
CPersonalToolbarManager :: InitializeButtonInfo(void)
{
HT_Cursor cursor = HT_NewCursor( mToolbarRoot );
if ( cursor ) {
HT_Resource currNode = HT_GetNextItem(cursor);
while ( currNode ) {
CUserButtonInfo *info = new CUserButtonInfo ( HT_GetNodeName(currNode), HT_GetNodeURL(currNode),
0, 0, HT_IsContainer(currNode));
mUserButtonInfoArray.InsertItemsAt(1, LArray::index_Last, &info);
currNode = HT_GetNextItem(cursor);
} // for each top-level node
}
} // InitializeButtonInfo
//
// HandleNotification
//
// Called when the user makes a change to the personal toolbar folder from some other
// place (like the bookmarks view). Reset our internal list and tell our listeners
// that things are now different.
//
void
CPersonalToolbarManager :: HandleNotification(
HT_Notification /*notifyStruct*/,
HT_Resource node,
HT_Event event)
{
switch (event)
{
case HT_EVENT_NODE_ADDED:
case HT_EVENT_VIEW_REFRESH:
case HT_EVENT_NODE_VPROP_CHANGED:
{
// only update toolbar if the quickfile view changes
if ( HT_GetView(node) == mToolbarView )
ToolbarChanged();
break;
}
}
}
#pragma mark ¥¥ class CUserButtonInfo
///////////////////////////////////////////////////////////////////////////////////
// Class CUserButtonInfo
///////////////////////////////////////////////////////////////////////////////////
CUserButtonInfo::CUserButtonInfo( const string & pName, const string & pURL, Uint32 nBitmapID,
Uint32 nBitmapIndex, bool bIsFolder)
: mName(pName), mURL(pURL), mBitmapID(nBitmapID), mBitmapIndex(nBitmapIndex),
mIsResourceID(true), mIsFolder(bIsFolder)
{
}
CUserButtonInfo::~CUserButtonInfo()
{
// string destructor takes care of everything...
}