1998-03-28 05:44:41 +03:00
|
|
|
|
/* -*- 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.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Implementation of the table that is the main component of the personal toolbar.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#include <vector.h>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
|
|
#include "CPersonalToolbarTable.h"
|
|
|
|
|
#include "uapp.h"
|
|
|
|
|
#include "LTableMultiGeometry.h"
|
|
|
|
|
#include "CURLDragHelper.h"
|
|
|
|
|
#include "macutil.h"
|
|
|
|
|
#include "CIconTextDragTask.h"
|
|
|
|
|
#include "resgui.h"
|
|
|
|
|
#include "URDFUtilities.h"
|
1998-05-14 01:24:48 +04:00
|
|
|
|
#include "prefapi.h"
|
1998-03-28 05:44:41 +03:00
|
|
|
|
#include "miconutils.h"
|
|
|
|
|
#include "UMemoryMgr.h"
|
|
|
|
|
|
1998-05-14 01:24:48 +04:00
|
|
|
|
|
1998-03-28 05:44:41 +03:00
|
|
|
|
static const RGBColor blue = { 0, 0, 0xFFFF };
|
1998-06-03 01:00:07 +04:00
|
|
|
|
static const RGBColor black = { 0, 0, 0 };
|
|
|
|
|
static const RGBColor bgColor = { 0xDDDD, 0xDDDD, 0xDDDD };
|
1998-03-28 05:44:41 +03:00
|
|
|
|
|
1998-05-14 01:24:48 +04:00
|
|
|
|
|
1998-03-28 05:44:41 +03:00
|
|
|
|
DragSendDataUPP CPersonalToolbarTable::sSendDataUPP;
|
|
|
|
|
|
1998-05-14 01:24:48 +04:00
|
|
|
|
const char* CPersonalToolbarTable::kMaxButtonCharsPref = "browser.personal_toolbar_button.max_chars";
|
|
|
|
|
const char* CPersonalToolbarTable::kMinButtonCharsPref = "browser.personal_toolbar_button.min_chars";
|
|
|
|
|
|
|
|
|
|
// init to something wacky so we can tell if they have been initialized already and avoid doing
|
|
|
|
|
// it again with every new toolbar
|
|
|
|
|
Uint32 CPersonalToolbarTable :: mMaxToolbarButtonChars = LArray::index_Last;
|
|
|
|
|
Uint32 CPersonalToolbarTable :: mMinToolbarButtonChars = LArray::index_Last;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1998-03-28 05:44:41 +03:00
|
|
|
|
|
|
|
|
|
CPersonalToolbarTable :: CPersonalToolbarTable ( LStream* inStream )
|
|
|
|
|
: LSmallIconTable(inStream), LDragAndDrop ( GetMacPort(), this ),
|
1998-05-14 01:24:48 +04:00
|
|
|
|
mDropCol(LArray::index_Bad), mHiliteCol(LArray::index_Bad), mDropOn(false), mButtonList(NULL),
|
|
|
|
|
mIsInitialized(false)
|
1998-03-28 05:44:41 +03:00
|
|
|
|
{
|
1998-05-14 01:24:48 +04:00
|
|
|
|
// 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();
|
|
|
|
|
HT_Pane toolbarPane = HT_NewPersonalToolbarPane(notifyStruct);
|
|
|
|
|
if ( !toolbarPane )
|
|
|
|
|
throw SomethingBadInHTException();
|
|
|
|
|
mToolbarView = HT_GetSelectedView ( toolbarPane );
|
|
|
|
|
if ( !mToolbarView )
|
|
|
|
|
throw SomethingBadInHTException();
|
|
|
|
|
mToolbarRoot = HT_TopNode ( mToolbarView );
|
|
|
|
|
if ( !mToolbarRoot )
|
|
|
|
|
throw SomethingBadInHTException();
|
|
|
|
|
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. Only do this if the static members have not yet
|
|
|
|
|
// been initialized to prevent doing it with each new toolbar.
|
|
|
|
|
if ( mMaxToolbarButtonChars == LArray::index_Last ) {
|
|
|
|
|
int32 maxToolbarButtonChars, minToolbarButtonChars;
|
|
|
|
|
if ( PREF_GetIntPref(kMaxButtonCharsPref, &maxToolbarButtonChars ) == PREF_ERROR )
|
|
|
|
|
mMaxToolbarButtonChars = kMaxPersonalToolbarChars;
|
|
|
|
|
else
|
|
|
|
|
mMaxToolbarButtonChars = maxToolbarButtonChars;
|
|
|
|
|
if ( PREF_GetIntPref(kMinButtonCharsPref, &minToolbarButtonChars ) == PREF_ERROR )
|
|
|
|
|
mMinToolbarButtonChars = kMinPersonalToolbarChars;
|
|
|
|
|
else
|
|
|
|
|
mMinToolbarButtonChars = minToolbarButtonChars;
|
|
|
|
|
}
|
|
|
|
|
|
1998-03-28 05:44:41 +03:00
|
|
|
|
// LSmallIconTable wants to use a LTableSingleGeometry, but since we want the toolbar
|
|
|
|
|
// to have variable column widths, replace it with a multiGeometry implementation
|
|
|
|
|
if ( mTableGeometry ) {
|
|
|
|
|
delete mTableGeometry;
|
|
|
|
|
mTableGeometry = new LTableMultiGeometry ( this, mFrameSize.width, 20 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // constructor
|
|
|
|
|
|
|
|
|
|
|
1998-05-14 01:24:48 +04:00
|
|
|
|
//
|
|
|
|
|
// Destructor
|
|
|
|
|
//
|
|
|
|
|
// Get rid of the button list. Since it is a list of objects, not pointers, we can just
|
|
|
|
|
// let the vector destructor handle everything.
|
|
|
|
|
//
|
1998-03-28 05:44:41 +03:00
|
|
|
|
CPersonalToolbarTable :: ~CPersonalToolbarTable ( )
|
|
|
|
|
{
|
1998-05-14 01:24:48 +04:00
|
|
|
|
delete mButtonList;
|
|
|
|
|
|
1998-03-28 05:44:41 +03:00
|
|
|
|
} // destructor
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// FinishCreateSelf
|
|
|
|
|
//
|
1998-05-14 01:24:48 +04:00
|
|
|
|
// Makes sure there is one row to put stuff in and creates a drag send proc.
|
|
|
|
|
//
|
1998-03-28 05:44:41 +03:00
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: FinishCreateSelf ( )
|
|
|
|
|
{
|
|
|
|
|
InsertRows ( 1, 1, NULL, 0, false );
|
1998-05-14 01:24:48 +04:00
|
|
|
|
InitializeButtonInfo();
|
|
|
|
|
|
1998-03-28 05:44:41 +03:00
|
|
|
|
if ( !sSendDataUPP) {
|
|
|
|
|
sSendDataUPP = NewDragSendDataProc(LDropArea::HandleDragSendData);
|
|
|
|
|
ThrowIfNil_(sSendDataUPP);
|
|
|
|
|
}
|
|
|
|
|
|
1998-05-14 01:24:48 +04:00
|
|
|
|
mIsInitialized = true;
|
|
|
|
|
|
1998-03-28 05:44:41 +03:00
|
|
|
|
} // FinishCreateSelf
|
|
|
|
|
|
|
|
|
|
|
1998-05-14 01:24:48 +04:00
|
|
|
|
//
|
|
|
|
|
// 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.
|
|
|
|
|
//
|
|
|
|
|
// Why build into an internal list when HT already has it? The assumption is that users
|
|
|
|
|
// will be resizing windows more often than adding things to the personal toolbar. By
|
|
|
|
|
// keeping a list around, when the user resizes, we don't have to go back to HT for all
|
|
|
|
|
// this information but can keep it in our local list. Better still, this also allows us to have the
|
|
|
|
|
// routines that fill in the toolbar not rely directly on and will allow us to more easily
|
|
|
|
|
// rework the underlying toolbar infrastructure in the future.
|
|
|
|
|
//
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: InitializeButtonInfo ( )
|
|
|
|
|
{
|
|
|
|
|
delete mButtonList;
|
|
|
|
|
mButtonList = new ButtonList( HT_GetItemListCount(GetHTView()) );
|
|
|
|
|
ButtonListIterator currButton = mButtonList->begin();
|
|
|
|
|
|
|
|
|
|
HT_Cursor cursor = HT_NewCursor( mToolbarRoot );
|
|
|
|
|
if ( cursor ) {
|
|
|
|
|
HT_Resource currNode = HT_GetNextItem(cursor);
|
|
|
|
|
while ( currNode ) {
|
|
|
|
|
CUserButtonInfo info ( HT_GetNodeName(currNode), HT_GetNodeURL(currNode),
|
|
|
|
|
0, 0, HT_IsContainer(currNode), currNode);
|
|
|
|
|
*currButton = info;
|
|
|
|
|
currNode = HT_GetNextItem(cursor);
|
|
|
|
|
currButton++;
|
|
|
|
|
|
|
|
|
|
} // 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
|
|
|
|
|
CPersonalToolbarTable :: HandleNotification(
|
|
|
|
|
HT_Notification /*notifyStruct*/,
|
|
|
|
|
HT_Resource node,
|
|
|
|
|
HT_Event event)
|
|
|
|
|
{
|
|
|
|
|
switch (event)
|
|
|
|
|
{
|
|
|
|
|
case HT_EVENT_NODE_ADDED:
|
|
|
|
|
case HT_EVENT_VIEW_REFRESH: // catches deletes
|
|
|
|
|
case HT_EVENT_NODE_VPROP_CHANGED:
|
|
|
|
|
{
|
|
|
|
|
// only update toolbar if the this view is the one that changed
|
|
|
|
|
if ( HT_GetView(node) == GetHTView() )
|
|
|
|
|
ToolbarChanged();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// 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
|
|
|
|
|
CPersonalToolbarTable :: ToolbarChanged ( )
|
|
|
|
|
{
|
|
|
|
|
if ( mCols )
|
|
|
|
|
RemoveCols ( mCols, 1, false );
|
|
|
|
|
InitializeButtonInfo(); // out with the old...
|
|
|
|
|
FillInToolbar(); // ...in with the new
|
|
|
|
|
|
|
|
|
|
} // ToolbarHeaderChanged
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// RemoveButton
|
|
|
|
|
//
|
|
|
|
|
// The user has explicitly removed a button from the toolbar in one of the windows (probably
|
|
|
|
|
// by dragging it to the trash). Let HT get rid of it.
|
|
|
|
|
//
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: RemoveButton ( Uint32 inIndex )
|
|
|
|
|
{
|
|
|
|
|
// remove it from HT
|
|
|
|
|
HT_Resource deadNode = HT_GetNthItem ( GetHTView(), URDFUtilities::PPRowToHTRow(inIndex) );
|
|
|
|
|
HT_RemoveChild ( mToolbarRoot, deadNode );
|
|
|
|
|
|
|
|
|
|
// no need to refresh because we will get an HT view update event and
|
|
|
|
|
// refresh at that time. The deleted node will also be removed from the list as it is
|
|
|
|
|
// rebuilt.
|
|
|
|
|
|
|
|
|
|
} // RemoveButton
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// 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
|
|
|
|
|
CPersonalToolbarTable :: AddButton ( HT_Resource inBookmark, Uint32 inIndex )
|
|
|
|
|
{
|
|
|
|
|
// Add this to RDF.
|
|
|
|
|
if ( mButtonList->size() ) {
|
|
|
|
|
// 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;
|
1998-06-12 02:52:56 +04:00
|
|
|
|
HT_Resource dropOn = NULL;
|
|
|
|
|
if ( inIndex <= mButtonList->size() )
|
|
|
|
|
dropOn = GetInfoForPPColumn(inIndex).GetHTResource();
|
|
|
|
|
else {
|
|
|
|
|
dropOn = (*mButtonList)[mButtonList->size() - 1].GetHTResource();
|
1998-05-14 01:24:48 +04:00
|
|
|
|
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
|
|
|
|
|
CPersonalToolbarTable :: AddButton ( const string & inURL, const string & inTitle, Uint32 inIndex )
|
|
|
|
|
{
|
|
|
|
|
// Add this to RDF.
|
|
|
|
|
if ( mButtonList->size() ) {
|
|
|
|
|
// 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;
|
1998-06-12 02:52:56 +04:00
|
|
|
|
HT_Resource dropOn = NULL;
|
|
|
|
|
if ( inIndex <= mButtonList->size() )
|
|
|
|
|
dropOn = GetInfoForPPColumn(inIndex).GetHTResource();
|
|
|
|
|
else {
|
|
|
|
|
dropOn = (*mButtonList)[mButtonList->size() - 1].GetHTResource();
|
1998-05-14 01:24:48 +04:00
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
1998-03-28 05:44:41 +03:00
|
|
|
|
//
|
|
|
|
|
// FillInToolbar
|
|
|
|
|
//
|
1998-05-14 01:24:48 +04:00
|
|
|
|
// Add rows to the table and try to give each column as much space as possible on the fly.
|
|
|
|
|
// Don't make any assumptions about the incoming text mode...be paranoid!
|
1998-03-28 05:44:41 +03:00
|
|
|
|
//
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: FillInToolbar ( )
|
|
|
|
|
{
|
|
|
|
|
const Uint32 kPadRight = 15;
|
|
|
|
|
const Uint32 kBMIconWidth = 28;
|
1998-05-14 01:24:48 +04:00
|
|
|
|
const Uint32 kButtonCount = mButtonList->size();
|
|
|
|
|
const Uint32 kMaxLength = GetMaxToolbarButtonChars();
|
|
|
|
|
const Uint32 kMinLength = GetMinToolbarButtonChars();
|
1998-03-28 05:44:41 +03:00
|
|
|
|
|
|
|
|
|
StTextState saved;
|
|
|
|
|
UTextTraits::SetPortTextTraits(kTextTraitsID);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// create an array that holds the # of characters currently in each column. Initialize this with
|
|
|
|
|
// the min column size (specified in prefs), or less if the title has less chars.
|
|
|
|
|
//
|
1998-05-14 01:24:48 +04:00
|
|
|
|
vector<Uint16> widthArray(kButtonCount);
|
|
|
|
|
vector<Uint16>::iterator widthArrayIter = widthArray.begin();
|
1998-03-28 05:44:41 +03:00
|
|
|
|
Uint16 totalWidth = 0;
|
1998-05-14 01:24:48 +04:00
|
|
|
|
for ( ButtonListConstIterator it = mButtonList->begin(); it != mButtonList->end(); it++ ) {
|
1998-03-28 05:44:41 +03:00
|
|
|
|
|
1998-05-14 01:24:48 +04:00
|
|
|
|
Uint16 numChars = min ( kMinLength, it->GetName().length() );
|
|
|
|
|
*widthArrayIter = numChars;
|
|
|
|
|
totalWidth += ::TextWidth(it->GetName().c_str(), 0, numChars) + kBMIconWidth; // extend the total...
|
1998-03-28 05:44:41 +03:00
|
|
|
|
widthArrayIter++;
|
|
|
|
|
|
|
|
|
|
} // initialize each item
|
|
|
|
|
|
1998-05-14 01:24:48 +04:00
|
|
|
|
|
|
|
|
|
if ( mCols > kButtonCount )
|
|
|
|
|
RemoveRows ( mCols - kButtonCount, 0, false );
|
|
|
|
|
else
|
|
|
|
|
InsertCols ( kButtonCount - mCols, 0, NULL, 0, false );
|
1998-03-28 05:44:41 +03:00
|
|
|
|
|
|
|
|
|
// compute how much room we have left to divvy out after divvying out the minimum above. Leave
|
|
|
|
|
// a few pixels on the right empty...
|
|
|
|
|
int16 emptySpace = (mFrameSize.width - kPadRight) - totalWidth;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// divvy out space to each column, one character at a time to each column
|
|
|
|
|
//
|
|
|
|
|
while ( emptySpace > 0 ) {
|
|
|
|
|
|
|
|
|
|
bool updated = false;
|
1998-05-14 01:24:48 +04:00
|
|
|
|
widthArrayIter = widthArray.begin();
|
|
|
|
|
for ( ButtonListConstIterator it = mButtonList->begin(); it != mButtonList->end(); it++, widthArrayIter++ ) {
|
|
|
|
|
if ( emptySpace && *widthArrayIter < it->GetName().length() && *widthArrayIter < kMaxLength ) {
|
1998-03-28 05:44:41 +03:00
|
|
|
|
// subtract off the single character we're adding to the column
|
1998-05-14 01:24:48 +04:00
|
|
|
|
char addedChar = it->GetName()[*widthArrayIter];
|
1998-03-28 05:44:41 +03:00
|
|
|
|
emptySpace -= ::TextWidth(&addedChar, 0, 1);
|
1998-05-14 01:24:48 +04:00
|
|
|
|
(*widthArrayIter)++;
|
1998-03-28 05:44:41 +03:00
|
|
|
|
updated = true; // we found something to add, allow us to continue
|
|
|
|
|
}
|
|
|
|
|
} // for each column
|
|
|
|
|
|
|
|
|
|
// prevent infinite looping if no column can be expanded and we still have extra room remaining
|
|
|
|
|
if ( !updated )
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
} // while space remains to divvy out
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// assign the widths to the columns and set the data in the columns.
|
|
|
|
|
//
|
|
|
|
|
STableCell where (1, 1);
|
1998-05-14 01:24:48 +04:00
|
|
|
|
widthArrayIter = widthArray.begin();
|
|
|
|
|
for ( ButtonListConstIterator it = mButtonList->begin(); it != mButtonList->end(); it++ ) {
|
1998-03-28 05:44:41 +03:00
|
|
|
|
|
1998-05-14 01:24:48 +04:00
|
|
|
|
const string & bmText = it->GetName();
|
1998-03-28 05:44:41 +03:00
|
|
|
|
Uint32 textLength = bmText.length();
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// fill in the cell with the name of the bookmark and set the column width to
|
|
|
|
|
// the width of the string. If the name is longer than the max, chop it.
|
|
|
|
|
//
|
|
|
|
|
SIconTableRec data;
|
1998-05-14 01:24:48 +04:00
|
|
|
|
Uint16 dispLength = *widthArrayIter;
|
1998-03-28 05:44:41 +03:00
|
|
|
|
::BlockMove ( bmText.c_str(), &data.name[1], dispLength + 1 );
|
|
|
|
|
data.name[0] = dispLength <= kMaxLength ? dispLength : kMaxLength;
|
1998-05-14 01:24:48 +04:00
|
|
|
|
data.iconID = it->IsFolder() ? kFOLDER_ICON : kBOOKMARK_ICON;
|
1998-03-28 05:44:41 +03:00
|
|
|
|
SetCellData ( where, &data, sizeof(SIconTableRec) );
|
|
|
|
|
Uint32 pixelWidth = ::TextWidth(bmText.c_str(), 0, dispLength)+ kBMIconWidth;
|
|
|
|
|
mTableGeometry->SetColWidth ( pixelWidth, where.col, where.col );
|
|
|
|
|
|
|
|
|
|
widthArrayIter++;
|
|
|
|
|
where.col++; // next column, please....
|
|
|
|
|
|
|
|
|
|
} // for each bookmark in the folder
|
|
|
|
|
|
|
|
|
|
Refresh();
|
|
|
|
|
|
|
|
|
|
} // FillInToolbar
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// MouseLeave
|
|
|
|
|
//
|
|
|
|
|
// Called when the mouse leaves the personal toolbar. Redraw the previous selection to get rid
|
|
|
|
|
// of the blue text color.
|
|
|
|
|
//
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: MouseLeave ( )
|
|
|
|
|
{
|
|
|
|
|
STableCell refresh(1, mHiliteCol);
|
|
|
|
|
mHiliteCol = LArray::index_Bad;
|
|
|
|
|
|
|
|
|
|
StClipRgnState savedClip;
|
|
|
|
|
FocusDraw();
|
|
|
|
|
RedrawCellWithTextClipping ( refresh );
|
|
|
|
|
|
|
|
|
|
} // MouseLeave
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// MouseWithin
|
|
|
|
|
//
|
|
|
|
|
// Called while the mouse moves w/in the personal toolbar. Find which cell the mouse is
|
|
|
|
|
// currently over and remember it. If we've moved to a different cell, make sure to
|
|
|
|
|
// refresh the old one so it is drawn normally.
|
|
|
|
|
//
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: MouseWithin ( Point inPortPt, const EventRecord& )
|
|
|
|
|
{
|
|
|
|
|
// get the previous selection
|
|
|
|
|
STableCell old(1, mHiliteCol);
|
|
|
|
|
SPoint32 imagePt;
|
|
|
|
|
PortToLocalPoint(inPortPt);
|
|
|
|
|
LocalToImagePoint(inPortPt, imagePt);
|
|
|
|
|
|
|
|
|
|
STableCell hitCell;
|
|
|
|
|
if ( GetCellHitBy(imagePt, hitCell) )
|
|
|
|
|
if ( old != hitCell ) {
|
|
|
|
|
StClipRgnState savedClip;
|
|
|
|
|
|
|
|
|
|
mHiliteCol = hitCell.col;
|
|
|
|
|
|
|
|
|
|
FocusDraw();
|
|
|
|
|
if ( old.col )
|
|
|
|
|
RedrawCellWithTextClipping(old);
|
|
|
|
|
if ( hitCell.col )
|
|
|
|
|
RedrawCellWithTextClipping(hitCell);
|
|
|
|
|
|
|
|
|
|
ExecuteAttachments(msg_HideTooltip, this); // hide tooltip
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // MouseWithin
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Click
|
|
|
|
|
//
|
|
|
|
|
// Allow drags to occur when another window is in front of us.
|
|
|
|
|
//
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: Click ( SMouseDownEvent& inMouseDown )
|
|
|
|
|
{
|
|
|
|
|
PortToLocalPoint(inMouseDown.whereLocal);
|
|
|
|
|
UpdateClickCount(inMouseDown);
|
|
|
|
|
|
|
|
|
|
if (ExecuteAttachments(msg_Click, &inMouseDown))
|
|
|
|
|
{
|
|
|
|
|
ClickSelf(inMouseDown);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
//
|
|
|
|
|
// Click
|
|
|
|
|
//
|
|
|
|
|
// Overridden to handle clase of drag and drop when communicator is in the background. Code
|
|
|
|
|
// copied from CWPro1 CD sample code (CDragAndDropTable.cp).
|
|
|
|
|
//
|
|
|
|
|
// FOR SOME REASON, THIS DOESN'T WORK....DUNNO WHY...
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: Click ( SMouseDownEvent& inMouseDown )
|
|
|
|
|
{
|
|
|
|
|
if ( inMouseDown.delaySelect && DragAndDropIsPresent() ) {
|
|
|
|
|
|
|
|
|
|
// In order to support dragging from an inactive window,
|
|
|
|
|
// we must explicitly test for delaySelect and the
|
|
|
|
|
// presence of Drag and Drop.
|
|
|
|
|
|
|
|
|
|
// Convert to a local point.
|
|
|
|
|
PortToLocalPoint( inMouseDown.whereLocal );
|
|
|
|
|
|
|
|
|
|
// Execute click attachments.
|
|
|
|
|
if ( ExecuteAttachments( msg_Click, &inMouseDown ) ) {
|
|
|
|
|
|
|
|
|
|
// Handle the actual click event.
|
|
|
|
|
ClickSelf( inMouseDown );
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
// Call inherited for default behavior.
|
|
|
|
|
LTableView::Click( inMouseDown );
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // Click
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// ClickSelect
|
|
|
|
|
//
|
|
|
|
|
// Override to always say that we can be selected, because there is no concept of selection
|
|
|
|
|
// in this toolbar.
|
|
|
|
|
Boolean
|
|
|
|
|
CPersonalToolbarTable :: ClickSelect( const STableCell &/*inCell*/, const SMouseDownEvent &/*inMouseDown*/)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// ClickCell
|
|
|
|
|
//
|
|
|
|
|
// Override the default behavior of selecting a cell to open the url associated with the bookmark
|
|
|
|
|
// there.
|
|
|
|
|
//
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: ClickCell(const STableCell &inCell, const SMouseDownEvent &inMouseDown)
|
|
|
|
|
{
|
|
|
|
|
if ( ::WaitMouseMoved(inMouseDown.macEvent.where) ) {
|
|
|
|
|
|
|
|
|
|
if (LDropArea::DragAndDropIsPresent()) {
|
|
|
|
|
|
|
|
|
|
mDraggedCell = inCell; // save which cell is being dragged for later
|
|
|
|
|
|
|
|
|
|
// create the drag task
|
|
|
|
|
Rect bounds;
|
|
|
|
|
GetLocalCellRect ( inCell, bounds );
|
1998-05-14 01:24:48 +04:00
|
|
|
|
const CUserButtonInfo & data = GetInfoForPPColumn(inCell.col);
|
|
|
|
|
string finalCaption = CURLDragHelper::MakeIconTextValid ( data.GetName().c_str() );
|
|
|
|
|
CIconTextSuite suite ( this, bounds, kBOOKMARK_ICON, finalCaption, data.GetHTResource() );
|
1998-03-28 05:44:41 +03:00
|
|
|
|
CIconTextDragTask theTask(inMouseDown.macEvent, &suite, bounds);
|
|
|
|
|
|
|
|
|
|
// setup our special data transfer proc called upon drag completion
|
|
|
|
|
OSErr theErr = ::SetDragSendProc ( theTask.GetDragReference(), sSendDataUPP, (LDropArea*) this );
|
|
|
|
|
ThrowIfOSErr_(theErr);
|
|
|
|
|
|
|
|
|
|
theTask.DoDrag();
|
|
|
|
|
|
|
|
|
|
// remove the url if it went into the trash
|
|
|
|
|
if ( theTask.DropLocationIsFinderTrash() )
|
1998-05-14 01:24:48 +04:00
|
|
|
|
RemoveButton ( inCell.col );
|
1998-03-28 05:44:41 +03:00
|
|
|
|
|
|
|
|
|
} // if d&d allowed
|
|
|
|
|
|
|
|
|
|
} // if drag
|
|
|
|
|
else {
|
|
|
|
|
|
1998-05-14 01:24:48 +04:00
|
|
|
|
const CUserButtonInfo & data = GetInfoForPPColumn(inCell.col);
|
1998-03-28 05:44:41 +03:00
|
|
|
|
|
|
|
|
|
// code for context menu here, if appropriate....
|
|
|
|
|
|
1998-05-14 01:24:48 +04:00
|
|
|
|
if ( data.IsFolder() ) {
|
1998-03-28 05:44:41 +03:00
|
|
|
|
SysBeep(1);
|
|
|
|
|
}
|
1998-05-14 01:24:48 +04:00
|
|
|
|
else
|
|
|
|
|
CFrontApp::DoGetURL( data.GetURL().c_str() );
|
1998-03-28 05:44:41 +03:00
|
|
|
|
|
|
|
|
|
} // else just a click
|
|
|
|
|
|
|
|
|
|
} // ClickCell
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// RedrawCellWithHilite
|
|
|
|
|
//
|
|
|
|
|
// A helpful utility routine that wraps DrawCell() with calls to setup the drawing params
|
|
|
|
|
// appropriately. When redrawing a cell during a drag and drop, call this routine instead
|
|
|
|
|
// of calling DrawCell directly.
|
|
|
|
|
//
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: RedrawCellWithHilite ( const STableCell inCell, bool inHiliteOn )
|
|
|
|
|
{
|
|
|
|
|
Rect localCellRect;
|
|
|
|
|
GetLocalCellRect ( inCell, localCellRect );
|
|
|
|
|
|
|
|
|
|
// since mDropOn is used as the flag in DrawCell() for whether or not we want to
|
|
|
|
|
// draw the hiliting on the cell, save its value and set it to what was passed in
|
|
|
|
|
// before calling DrawCell().
|
|
|
|
|
StValueChanger<Boolean> oldHilite(mDropOn, inHiliteOn); //<2F><><EFBFBD> won't link with bool type =(
|
|
|
|
|
|
|
|
|
|
// if the hiliting is being turned off, erase the cell so it draws normally again
|
|
|
|
|
if ( !inHiliteOn ) {
|
1998-06-03 01:00:07 +04:00
|
|
|
|
StColorState saved;
|
|
|
|
|
::RGBBackColor(&bgColor);
|
1998-03-28 05:44:41 +03:00
|
|
|
|
::EraseRect(&mTextHiliteRect); // we can be sure this has been previously computed
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DrawCell ( inCell, localCellRect );
|
|
|
|
|
|
|
|
|
|
} // RedrawCellWithHilite
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// DrawCell
|
|
|
|
|
//
|
|
|
|
|
// Override to draw differently when this is the selected cell. Otherwise, pass it back
|
|
|
|
|
// to the inherited routine to draw normally.
|
|
|
|
|
//
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: DrawCell ( const STableCell &inCell, const Rect &inLocalRect )
|
|
|
|
|
{
|
|
|
|
|
StTextState savedText;
|
|
|
|
|
StColorPenState savedColor;
|
1998-06-03 01:00:07 +04:00
|
|
|
|
::RGBForeColor(&black);
|
1998-03-28 05:44:41 +03:00
|
|
|
|
|
|
|
|
|
SIconTableRec iconAndName;
|
|
|
|
|
Uint32 dataSize = sizeof(SIconTableRec);
|
|
|
|
|
GetCellData(inCell, &iconAndName, dataSize);
|
|
|
|
|
|
|
|
|
|
Rect iconRect;
|
|
|
|
|
iconRect.left = inLocalRect.left + 3;
|
|
|
|
|
iconRect.right = iconRect.left + 16;
|
|
|
|
|
iconRect.bottom = inLocalRect.bottom - 2;
|
|
|
|
|
iconRect.top = iconRect.bottom - 16;
|
|
|
|
|
IconTransformType transform = kTransformNone;
|
|
|
|
|
if ( mDropOn ) // handle drop on folder
|
|
|
|
|
transform = kTransformSelected;
|
|
|
|
|
::PlotIconID(&iconRect, atNone, transform, iconAndName.iconID);
|
|
|
|
|
|
|
|
|
|
UTextTraits::SetPortTextTraits(kTextTraitsID);
|
|
|
|
|
|
|
|
|
|
if ( mDropOn ) { // handle drop on folder
|
|
|
|
|
mTextHiliteRect = ComputeTextRect ( iconAndName, inLocalRect );
|
1998-06-03 01:00:07 +04:00
|
|
|
|
StColorState savedColorForTextDrawing;
|
|
|
|
|
::RGBBackColor(&black);
|
1998-03-28 05:44:41 +03:00
|
|
|
|
::EraseRect(&mTextHiliteRect);
|
|
|
|
|
::TextMode(srcXor);
|
|
|
|
|
}
|
|
|
|
|
else if ( mHiliteCol == inCell.col ) {
|
|
|
|
|
TextFace(underline);
|
|
|
|
|
RGBForeColor( &blue );
|
|
|
|
|
}
|
|
|
|
|
::MoveTo(inLocalRect.left + 22, inLocalRect.bottom - 4);
|
|
|
|
|
::DrawString(iconAndName.name);
|
|
|
|
|
|
|
|
|
|
} // DrawCell
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// DoDragSendData
|
|
|
|
|
//
|
|
|
|
|
// When the drag started, the ClickCell() routine cached which cell was the start of the drag in
|
|
|
|
|
// |mDraggedCell|. Extract the URL and Title from this cell and pass it along to the helper
|
|
|
|
|
// routine from CURLDragHelper
|
|
|
|
|
//
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: DoDragSendData( FlavorType inFlavor, ItemReference inItemRef,
|
|
|
|
|
DragReference inDragRef)
|
|
|
|
|
{
|
1998-05-14 01:24:48 +04:00
|
|
|
|
const CUserButtonInfo & dragged = GetInfoForPPColumn ( mDraggedCell.col );
|
|
|
|
|
CURLDragHelper::DoDragSendData ( dragged.GetURL().c_str(),
|
|
|
|
|
const_cast<char*>(dragged.GetName().c_str()),
|
1998-03-28 05:44:41 +03:00
|
|
|
|
inFlavor, inItemRef, inDragRef );
|
|
|
|
|
|
|
|
|
|
} // DoDragSendData
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// HiliteDropArea
|
|
|
|
|
//
|
|
|
|
|
// Show that this toolbar is a drop site for urls
|
|
|
|
|
//
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: HiliteDropArea ( DragReference inDragRef )
|
|
|
|
|
{
|
|
|
|
|
Rect frame;
|
|
|
|
|
CalcLocalFrameRect ( frame );
|
|
|
|
|
|
|
|
|
|
// show the drag hilite in drop area
|
|
|
|
|
RgnHandle rgn = ::NewRgn();
|
|
|
|
|
ThrowIfNil_(rgn);
|
|
|
|
|
::RectRgn ( rgn, &frame );
|
|
|
|
|
::ShowDragHilite ( inDragRef, rgn, true );
|
|
|
|
|
::DisposeRgn ( rgn );
|
|
|
|
|
|
|
|
|
|
} // HiliteDropArea
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// InsideDropArea
|
|
|
|
|
//
|
|
|
|
|
// Called repeatedly while mouse is inside this during a drag. For each column, the cell
|
|
|
|
|
// can be divided into several sections.
|
|
|
|
|
//
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: InsideDropArea ( DragReference inDragRef )
|
|
|
|
|
{
|
|
|
|
|
FocusDraw();
|
|
|
|
|
|
|
|
|
|
Point mouseLoc;
|
|
|
|
|
SPoint32 imagePt;
|
|
|
|
|
::GetDragMouse(inDragRef, &mouseLoc, NULL);
|
|
|
|
|
::GlobalToLocal(&mouseLoc);
|
|
|
|
|
LocalToImagePoint(mouseLoc, imagePt);
|
|
|
|
|
|
|
|
|
|
Rect localRect;
|
|
|
|
|
TableIndexT colMouseIsOver = mTableGeometry->GetColHitBy(imagePt);
|
|
|
|
|
GetLocalCellRect ( STableCell(1, colMouseIsOver), localRect );
|
|
|
|
|
TableIndexT newDropCol;
|
|
|
|
|
bool newDropOn = false;
|
1998-05-14 01:24:48 +04:00
|
|
|
|
if ( colMouseIsOver <= mCols ) {
|
|
|
|
|
const CUserButtonInfo & info = GetInfoForPPColumn(colMouseIsOver);
|
|
|
|
|
if ( info.IsFolder() ) {
|
1998-03-28 05:44:41 +03:00
|
|
|
|
Rect leftSide, rightSide;
|
|
|
|
|
ComputeFolderDropAreas ( localRect, leftSide, rightSide );
|
|
|
|
|
if ( ::PtInRect(mouseLoc, &leftSide) )
|
|
|
|
|
newDropCol = colMouseIsOver; // before this cell
|
|
|
|
|
else if ( ::PtInRect(mouseLoc, &rightSide) )
|
|
|
|
|
newDropCol = colMouseIsOver + 1; // after this cell
|
|
|
|
|
else {
|
|
|
|
|
newDropCol = colMouseIsOver;
|
|
|
|
|
newDropOn = true; // hilite folder, don't draw line
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// draw line between rows
|
|
|
|
|
Rect leftSide, rightSide;
|
|
|
|
|
ComputeItemDropAreas ( localRect, leftSide, rightSide );
|
|
|
|
|
if ( ::PtInRect(mouseLoc, &leftSide) )
|
|
|
|
|
newDropCol = colMouseIsOver; // before this cell
|
|
|
|
|
else
|
|
|
|
|
newDropCol = colMouseIsOver + 1; // after this cell
|
|
|
|
|
}
|
|
|
|
|
} // if drag over existing column
|
|
|
|
|
else {
|
|
|
|
|
// else drag over empty part of toolbar
|
|
|
|
|
newDropCol = mCols + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if something has changed, redraw as necessary
|
|
|
|
|
if ( newDropCol != mDropCol || newDropOn != mDropOn ) {
|
|
|
|
|
|
|
|
|
|
// unhilight old one (if necessary)
|
|
|
|
|
if ( mDropOn )
|
|
|
|
|
RedrawCellWithHilite( STableCell(1, mDropCol), false );
|
|
|
|
|
else
|
|
|
|
|
if ( mDropCol > 0 )
|
|
|
|
|
DrawDividingLine ( mDropCol );
|
|
|
|
|
|
|
|
|
|
mDropCol = newDropCol;
|
|
|
|
|
mDropOn = newDropOn;
|
|
|
|
|
|
|
|
|
|
// hilight new one
|
|
|
|
|
if ( mDropOn )
|
|
|
|
|
RedrawCellWithHilite ( STableCell(1, mDropCol), true );
|
|
|
|
|
else
|
|
|
|
|
DrawDividingLine ( newDropCol );
|
|
|
|
|
|
|
|
|
|
} // if mouse moved to another drop location
|
|
|
|
|
|
|
|
|
|
} // InsideDropArea
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// LeaveDropArea
|
|
|
|
|
//
|
|
|
|
|
// Clean up the drop feedback stuff when the mouse leaves the area
|
|
|
|
|
//
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: LeaveDropArea( DragReference inDragRef )
|
|
|
|
|
{
|
|
|
|
|
FocusDraw();
|
|
|
|
|
|
|
|
|
|
// if we were hiliting a folder, redraw it without the hiliting. If we were drawing a
|
|
|
|
|
// line, undraw it.
|
|
|
|
|
if ( mDropOn )
|
|
|
|
|
RedrawCellWithHilite ( STableCell(1,mDropCol), false );
|
|
|
|
|
else
|
|
|
|
|
DrawDividingLine( mDropCol );
|
|
|
|
|
|
|
|
|
|
mDropCol = LArray::index_Bad;
|
|
|
|
|
mDropOn = false;
|
|
|
|
|
|
|
|
|
|
// Call inherited.
|
|
|
|
|
LDragAndDrop::LeaveDropArea( inDragRef );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// ComputeItemDropAreas
|
|
|
|
|
//
|
|
|
|
|
// When a drag goes over a cell that contains a single node, divide the node in half. The left
|
|
|
|
|
// side will represent dropping before the node, the right side after.
|
|
|
|
|
//
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: ComputeItemDropAreas ( const Rect & inLocalCellRect, Rect & oLeftSide,
|
|
|
|
|
Rect & oRightSide )
|
|
|
|
|
{
|
|
|
|
|
oRightSide = oLeftSide = inLocalCellRect;
|
|
|
|
|
uint16 midPt = (oLeftSide.right - oLeftSide.left) / 2;
|
|
|
|
|
oLeftSide.right = oLeftSide.left + midPt;
|
|
|
|
|
oRightSide.left = oLeftSide.left + midPt + 1;
|
|
|
|
|
|
|
|
|
|
} // ComputeItemDropAreas
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// ComputeFolderDropAreas
|
|
|
|
|
//
|
|
|
|
|
// When a drag goes over a cell that contains a folder, divide the cell area into 3 parts. The middle
|
|
|
|
|
// area, which corresponds to a drop on the folder takes up the majority of the cell space with the
|
|
|
|
|
// left and right areas (corresponding to drop before and drop after, respectively) taking up the rest
|
|
|
|
|
// at the ends.
|
|
|
|
|
//
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: ComputeFolderDropAreas ( const Rect & inLocalCellRect, Rect & oLeftSide,
|
|
|
|
|
Rect & oRightSide )
|
|
|
|
|
{
|
|
|
|
|
// make sure the left/right area widths aren't too big for the cell
|
|
|
|
|
Uint16 endAreaWidth = 20;
|
|
|
|
|
if ( inLocalCellRect.right - inLocalCellRect.left < 50 )
|
|
|
|
|
endAreaWidth = 5;
|
|
|
|
|
|
|
|
|
|
oRightSide = oLeftSide = inLocalCellRect;
|
|
|
|
|
oLeftSide.right = oLeftSide.left + endAreaWidth;
|
|
|
|
|
oRightSide.left = oRightSide.right - endAreaWidth;
|
|
|
|
|
|
|
|
|
|
} // ComputeFolderDropAreas
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// DrawDividingLine
|
|
|
|
|
//
|
|
|
|
|
// Draws a vertical black line before the given column in the toolbar (or undraws if one
|
|
|
|
|
// is already there). If the column given is after the right edge of the last column, it
|
|
|
|
|
// draws after the last column (as the user expects).
|
|
|
|
|
//
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: DrawDividingLine( TableIndexT inCol )
|
|
|
|
|
{
|
1998-05-14 01:24:48 +04:00
|
|
|
|
Uint32 numItems = mButtonList->size();
|
1998-03-28 05:44:41 +03:00
|
|
|
|
if ( !numItems ) // don't draw anything if toolbar empty
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// Setup the target cell.
|
|
|
|
|
STableCell theCell;
|
|
|
|
|
theCell.row = 1;
|
|
|
|
|
theCell.col = inCol;
|
|
|
|
|
|
|
|
|
|
// find the boundary of the cell we're supposed to be drawing the line before. If
|
|
|
|
|
// the incoming column is at the end (greater than the # of buttons) then hack up
|
|
|
|
|
// a boundary rect to draw after the last column.
|
|
|
|
|
Rect cellBounds;
|
|
|
|
|
if ( inCol > numItems ) {
|
|
|
|
|
// get the boundary of the last column
|
|
|
|
|
theCell.col = numItems;
|
|
|
|
|
GetLocalCellRect ( theCell, cellBounds );
|
|
|
|
|
|
|
|
|
|
// make the left edge of our fake column the right edge of the last column
|
|
|
|
|
cellBounds.left = cellBounds.right;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
GetLocalCellRect ( theCell, cellBounds );
|
|
|
|
|
|
|
|
|
|
// Focus the pane and get the table and cell frames.
|
|
|
|
|
Rect theFrame;
|
|
|
|
|
if ( FocusDraw() && CalcLocalFrameRect( theFrame ) ) {
|
|
|
|
|
|
|
|
|
|
// Save the draw state and clip the list view rect.
|
|
|
|
|
StColorPenState theDrawState;
|
|
|
|
|
StClipRgnState theClipState( theFrame );
|
|
|
|
|
|
|
|
|
|
// Setup the color and pen state then draw the line
|
|
|
|
|
::ForeColor( blackColor );
|
|
|
|
|
::PenMode( patXor );
|
|
|
|
|
::PenSize( 2, 2 );
|
|
|
|
|
::MoveTo( cellBounds.left, cellBounds.top );
|
|
|
|
|
::LineTo( cellBounds.left, cellBounds.bottom );
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // DrawDividingLine
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
1998-05-07 01:26:21 +04:00
|
|
|
|
// ReceiveDragItem
|
1998-03-28 05:44:41 +03:00
|
|
|
|
//
|
1998-05-07 01:26:21 +04:00
|
|
|
|
// Pass this along to the implementation in CHTAwareURLDragMixin.
|
1998-03-28 05:44:41 +03:00
|
|
|
|
//
|
1998-05-07 01:26:21 +04:00
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: ReceiveDragItem ( DragReference inDragRef, DragAttributes inDragAttrs,
|
|
|
|
|
ItemReference inItemRef, Rect & inItemBounds )
|
1998-03-28 05:44:41 +03:00
|
|
|
|
{
|
1998-05-07 01:26:21 +04:00
|
|
|
|
CHTAwareURLDragMixin::ReceiveDragItem(inDragRef, inDragAttrs, inItemRef, inItemBounds );
|
1998-03-28 05:44:41 +03:00
|
|
|
|
|
1998-05-07 01:26:21 +04:00
|
|
|
|
} // ReceiveDragItem
|
1998-03-28 05:44:41 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// ItemIsAcceptable
|
|
|
|
|
//
|
|
|
|
|
// If FindBestFlavor() finds an acceptable flavor, then this item can be accepted. If not, it
|
|
|
|
|
// can't. We don't really care at this point what that flavor is.
|
|
|
|
|
//
|
|
|
|
|
Boolean
|
|
|
|
|
CPersonalToolbarTable :: ItemIsAcceptable ( DragReference inDragRef, ItemReference inItemRef )
|
|
|
|
|
{
|
|
|
|
|
FlavorType ignored;
|
|
|
|
|
return FindBestFlavor ( inDragRef, inItemRef, ignored );
|
|
|
|
|
|
|
|
|
|
} // ItemIsAcceptable
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
1998-05-07 01:26:21 +04:00
|
|
|
|
// HandleDropOfHTResource
|
1998-03-28 05:44:41 +03:00
|
|
|
|
//
|
1998-05-07 01:26:21 +04:00
|
|
|
|
// Called when the user drops an HT_Resource from some other HT aware view on the
|
|
|
|
|
// personal toolbar. Add a button for this new item.
|
1998-03-28 05:44:41 +03:00
|
|
|
|
//
|
|
|
|
|
void
|
1998-05-07 01:26:21 +04:00
|
|
|
|
CPersonalToolbarTable :: HandleDropOfHTResource ( HT_Resource inDropNode )
|
1998-03-28 05:44:41 +03:00
|
|
|
|
{
|
1998-05-07 01:26:21 +04:00
|
|
|
|
if ( mDropOn ) {
|
|
|
|
|
SysBeep(1); //<2F><><EFBFBD> implement
|
|
|
|
|
}
|
|
|
|
|
else
|
1998-05-14 01:24:48 +04:00
|
|
|
|
AddButton ( inDropNode, mDropCol );
|
1998-05-07 01:26:21 +04:00
|
|
|
|
|
|
|
|
|
} // HandleDropOfHTResource
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// HandleDropOfPageProxy
|
|
|
|
|
//
|
|
|
|
|
// Called when user drops the page proxy icon (or an embedded url) onto the personal
|
|
|
|
|
// toolbar. Add a button for this new item.
|
|
|
|
|
//
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: HandleDropOfPageProxy ( const char* inURL, const char* inTitle )
|
|
|
|
|
{
|
|
|
|
|
if ( mDropOn ) {
|
|
|
|
|
SysBeep(1); //<2F><><EFBFBD> implement
|
|
|
|
|
}
|
|
|
|
|
else
|
1998-05-14 01:24:48 +04:00
|
|
|
|
AddButton ( inURL, inTitle, mDropCol );
|
1998-05-07 01:26:21 +04:00
|
|
|
|
|
|
|
|
|
} // HandleDropOfPageProxy
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// HandleDropOfLocalFile
|
|
|
|
|
//
|
|
|
|
|
// A local file is just an url and a title, so cheat.
|
|
|
|
|
//
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: HandleDropOfLocalFile ( const char* inFileURL, const char* fileName,
|
|
|
|
|
const HFSFlavor & /*inFileData*/ )
|
|
|
|
|
{
|
|
|
|
|
HandleDropOfPageProxy ( inFileURL, fileName );
|
1998-03-28 05:44:41 +03:00
|
|
|
|
|
1998-05-07 01:26:21 +04:00
|
|
|
|
} // HandleDropOfLocalFile
|
1998-03-28 05:44:41 +03:00
|
|
|
|
|
1998-05-07 01:26:21 +04:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// HandleDropOfText
|
|
|
|
|
//
|
|
|
|
|
// Need to implement
|
|
|
|
|
//
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: HandleDropOfText ( const char* inTextData )
|
|
|
|
|
{
|
|
|
|
|
DebugStr("\pDropping TEXT here not implemented; g");
|
1998-03-28 05:44:41 +03:00
|
|
|
|
|
1998-05-07 01:26:21 +04:00
|
|
|
|
} // HandleDropOfText
|
1998-03-28 05:44:41 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: FindTooltipForMouseLocation ( const EventRecord& inMacEvent,
|
|
|
|
|
StringPtr outTip )
|
|
|
|
|
{
|
|
|
|
|
Point temp = inMacEvent.where;
|
|
|
|
|
SPoint32 where;
|
|
|
|
|
GlobalToPortPoint(temp);
|
|
|
|
|
PortToLocalPoint(temp);
|
|
|
|
|
LocalToImagePoint(temp, where);
|
|
|
|
|
|
|
|
|
|
STableCell hitCell;
|
|
|
|
|
if ( GetCellHitBy(where, hitCell) && hitCell.col <= mCols ) {
|
1998-05-14 01:24:48 +04:00
|
|
|
|
const CUserButtonInfo & bkmk = GetInfoForPPColumn(hitCell.col);
|
|
|
|
|
outTip[0] = bkmk.GetName().length();
|
|
|
|
|
strcpy ( (char*) &outTip[1], bkmk.GetName().c_str() );
|
1998-03-28 05:44:41 +03:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
::GetIndString ( outTip, 10506, 12); // supply a helpful message...
|
|
|
|
|
|
|
|
|
|
} // FindTooltipForMouseLocation
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: ResizeFrameBy ( Int16 inWidth, Int16 inHeight, Boolean inRefresh )
|
|
|
|
|
{
|
|
|
|
|
LSmallIconTable::ResizeFrameBy(inWidth, inHeight, inRefresh);
|
|
|
|
|
|
1998-05-14 01:24:48 +04:00
|
|
|
|
// don't call ToolbarChanged() because that will reload from HT. Nothing has really
|
|
|
|
|
// changed except for the width of the toolbar. Checking if we've gone through
|
|
|
|
|
// FinishCreateSelf() will cut down on the number of times we recompute the toolbar
|
|
|
|
|
// as the window is being created.
|
|
|
|
|
if ( mIsInitialized )
|
|
|
|
|
FillInToolbar();
|
1998-03-28 05:44:41 +03:00
|
|
|
|
|
|
|
|
|
} // ResizeFrameTo
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// ComputeTextRect
|
|
|
|
|
//
|
|
|
|
|
// Compute the area of the text rectangle so we can clip to it on redraw
|
|
|
|
|
//
|
|
|
|
|
Rect
|
|
|
|
|
CPersonalToolbarTable :: ComputeTextRect ( const SIconTableRec & inText, const Rect & inLocalRect )
|
|
|
|
|
{
|
|
|
|
|
Rect textRect;
|
|
|
|
|
|
|
|
|
|
uint16 width = ::TextWidth(inText.name, 1, *inText.name);
|
|
|
|
|
textRect.left = inLocalRect.left + 20;
|
|
|
|
|
textRect.right = textRect.left + width + 2;
|
|
|
|
|
textRect.bottom = inLocalRect.bottom - 1;
|
|
|
|
|
textRect.top = inLocalRect.top + 1;
|
|
|
|
|
|
|
|
|
|
return textRect;
|
|
|
|
|
|
|
|
|
|
} // ComputeTextRect
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// RedrawCellWithTextClipping
|
|
|
|
|
//
|
|
|
|
|
// A pretty way to redraw the cell because it won't flash. This sets the clip region to the
|
|
|
|
|
// text that needs to be redrawn so it looks fast to the user.
|
|
|
|
|
//
|
|
|
|
|
// NOTE: This blows away the current clip region so if you care, you must restore it afterwards. I
|
|
|
|
|
// don't do it here because you may want to make a couple of these calls in a row and restoring the
|
|
|
|
|
// clip rect in between would be a waste. It also blows away the background color.
|
|
|
|
|
//
|
|
|
|
|
void
|
|
|
|
|
CPersonalToolbarTable :: RedrawCellWithTextClipping ( const STableCell & inCell )
|
|
|
|
|
{
|
|
|
|
|
StTextState savedText;
|
|
|
|
|
SIconTableRec iconAndName;
|
|
|
|
|
Rect localRect;
|
|
|
|
|
|
|
|
|
|
UTextTraits::SetPortTextTraits(kTextTraitsID);
|
|
|
|
|
|
|
|
|
|
Uint32 dataSize = sizeof(SIconTableRec);
|
|
|
|
|
GetCellData(inCell, &iconAndName, dataSize);
|
|
|
|
|
GetLocalCellRect ( inCell, localRect );
|
|
|
|
|
Rect textRect = ComputeTextRect(iconAndName,localRect);
|
|
|
|
|
::ClipRect(&textRect);
|
1998-06-03 01:00:07 +04:00
|
|
|
|
::RGBBackColor(&bgColor);
|
1998-03-28 05:44:41 +03:00
|
|
|
|
::EraseRect(&textRect);
|
|
|
|
|
DrawCell(inCell, localRect);
|
|
|
|
|
|
|
|
|
|
} // RedrawCellWithTextClipping
|
1998-05-14 01:24:48 +04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// GetInfoForPPColumn
|
|
|
|
|
//
|
|
|
|
|
// Given a column in a powerplant table, this returns a reference to the appropriate CUserButtonInfo
|
|
|
|
|
// class for that column.
|
|
|
|
|
inline const CUserButtonInfo &
|
|
|
|
|
CPersonalToolbarTable :: GetInfoForPPColumn ( const TableIndexT & inCol ) const
|
|
|
|
|
{
|
|
|
|
|
// recall PP is 1-based and HT (and vectors) are 0 based, so do the conversion first
|
|
|
|
|
return (*mButtonList)[URDFUtilities::PPRowToHTRow(inCol)];
|
|
|
|
|
|
|
|
|
|
} // GetInfoForPPColumn
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Class CUserButtonInfo
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
CUserButtonInfo::CUserButtonInfo( const string & pName, const string & pURL, Uint32 nBitmapID,
|
|
|
|
|
Uint32 nBitmapIndex, bool bIsFolder, HT_Resource inRes )
|
|
|
|
|
: mName(pName), mURL(pURL), mBitmapID(nBitmapID), mBitmapIndex(nBitmapIndex),
|
|
|
|
|
mIsResourceID(true), mIsFolder(bIsFolder), mResource(inRes)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CUserButtonInfo :: CUserButtonInfo ( )
|
|
|
|
|
: mBitmapID(0), mBitmapIndex(0), mIsResourceID(false), mIsFolder(false), mResource(NULL)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CUserButtonInfo::~CUserButtonInfo()
|
|
|
|
|
{
|
|
|
|
|
// string destructor takes care of everything...
|
|
|
|
|
}
|
|
|
|
|
|