AttributeManager Class Reference

The attribute manager is currently responsible for managing the application of current attributes. It contains a list of Attribute groups along with instances of current attributes which belong to each group. An attribute group is identified by the RuntimeClass of an object. More...

#include <attrmgr.h>

Inheritance diagram for AttributeManager:

CCObject SimpleCCObject List of all members.

Public Types

enum  AttrsToMakeCurrent { ALL, NOT_APPLIED, NONE }

Public Member Functions

 AttributeManager ()
 ~AttributeManager ()
 Attribute manager destructor Currently destroys all attributes in all attribute groups.
BOOL InitInstance ()
 Creates the current attribute groups, and adds the initial current attributes to them.
AttrsToMakeCurrent GetAttributesToMakeCurrent (List &Attribs, List &AttrGroupsList, BOOL bPasteAttrs)
 To determine which attributes in the Attribs list to make current. The user is prompted where neccessary.
BOOL WeShouldMakeAttrCurrent (BOOL AttributeApplied, NodeAttribute *pAttr, List *pAttrGroupList, BOOL DroppedAttr=FALSE, BOOL AttrDroppedOntoPage=FALSE)
 To determine if we should make an attribute current or not. The routine does NOT delete the Attrib if it is not being made current.
BOOL ApplyCurrentAttribsToNode (NodeRenderableInk *Node)
 This function determines the attribute group associated with the object and then applies all attributes in the group to the object. If the group has a base group then all attributes in the base group with types different to those already applied get added to the object etc.
NodeAttributeGetSelToolCurrentAttribute (CCRuntimeClass *AttrType)
 For finding current attribute pAttrType in the current attribute group specified by the currently selected tool.
NodeAttributeGetCurrentAttribute (CCRuntimeClass *AttrGroup, CCRuntimeClass *AttrType)
 For finding current attribute pAttrType in attribute group pAttrGroup.
void GetCurrentLineAndFillColour (CCRuntimeClass *AttrGroup, DocColour *LineCol, DocColour *FillCol)
BOOL WriteCurrentAttributes (BaseCamelotFilter *pFilter)
 

void UpdateForDeletedColours (ColourList *ParentList)
 Called by the ColourManager when colours in use by the attribute manager may have been deleted.

Static Public Member Functions

static BOOL InitDefaults ()
 Initialises the Attribute Manager. Registers basic attributes Declares attribute preferences When TRUE - Whenever an attribute is applied to objects the attribute becomes a current attribute. When TRUE - The user is prompted before setting a current attribute, except when the LastAttrAppliedBecomesCurrent preference is TRUE when it makes no sense to prompt the user.
static void Deinit ()
static void AttributeSelected (NodeAttribute *Attrib, NodeAttribute *OldAttr=NULL)
 This function should be called whenever an attribute is selected by the user.
static void AttributesSelected (List &AttribsToApply, UINT32 OpName)
 This high level function should be called whenever we need to apply multiple attributes to the selection (eg. PasteAttributes).
static void ApplyAttribToNode (NodeRenderableInk *InkNode, NodeAttribute *NewAttr)
 Replaces an attribute within a specified Ink Node.
static void ReplaceAttributes (NodeAttribute *Attrib, List *OldAttrs)
 

static void UpdateCurrentAttr (NodeAttribute *Attr, BOOL Mutate, List *pAttrGroupList, BOOL TellWorld=TRUE)
 Adds Attr to all attribute groups in the AttrGroupList. If the list is empty then the attribute gets added to the attribute group associated with the selected tool.
static BOOL UpdateCurrentAppliedAttr (NodeAttribute *pAttr, List *pAttrGroupList, BOOL bAttrApplied, BOOL bMutate)
static BOOL UpdateAfterAttrApplied (NodeAttribute *pAttr)
static BOOL CanBeAppliedToSelection (NodeAttribute *Attrib, List *pAttrGroups)
 This function would ideally live in the SelRange. It determines if the attribute can be applied to at least one object in the selection.
static BOOL CanBeAppliedToNode (NodeRenderableInk *pObject, NodeAttribute *Attrib, List *pAttrGroups)
 This function would ideally live in the SelRange. It determines if the attribute can be applied to a specified object.
static void FindDefaultColour (ColourList *ColList, UINT32 NameResID, DocColour *Result)
static UINT32 RegisterDefaultAttribute (CCRuntimeClass *pNodeType, AttributeValue *pValue)
static AttributeEntryGetDefaultAttributes ()
 Get a copy of all the default attributes. This is used by render regions and import filters to initialise themselves to a sensible default state.
static NodeAttributeGetDefaultAttribute (AttrIndex AttrID)
static AttributeValueGetDefaultAttributeVal (AttrIndex AttrID)
static BOOL GetDefaultAttribute (AttrIndex aiToGet, AttributeValue *pavReturn)
 Gets the default value of a particular attribute.
static UINT32 GetNumAttributes ()
 Find out how many attributes have been registered with the attribute manager. This also tells you how long the default attribute array is as returned by AttributeManager::GetDefaultAttributes.
static BOOL ApplyBasedOnDefaults (Node *Target, AttributeEntry *AttrsToApply)
 Given a set of attributes, apply the ones that differ from the defaults to the specified node. Most commonly used by import filters.
static NodeAttributeGetOtherAttrToApply (NodeAttribute *AttrApplied, BOOL *IsMutate)

Static Public Attributes

static BOOL LastAttrAppliedBecomesCurrent = 1
static BOOL AskBeforeSettingCurrentAttr = 0
static BOOL ShouldAskAboutContoneColours = 1
static BOOL HaveAskedAboutContoneColours = 0
static BOOL UserCancelledContoneColours = 0
static BOOL SendMessages = 1
static DocColour DefaultBlack = DocColour(0L, 0L, 0L)
static DocColour DefaultWhite = DocColour(255L, 255L, 255L)
static NodeRenderableInkpLastNodeAppliedTo = NULL
static DocRect LastAppliedBounds = DocRect(0,0,0,0)

Private Member Functions

BOOL CreateCurrentAttributeGroup (CCRuntimeClass *AttrGroup, CCRuntimeClass *BaseGroup, String_256 &GrpName)
 This fn creates a new AttributeGroup. An AttributeGroup will contain a set of current attributes which get applied to new objects which are associated with the group.
NodeAttributeUpdateCurrentAttribute (CCRuntimeClass *AttrGroup, NodeAttribute *Attribute, BOOL fCheckTransparency=TRUE, BOOL DefiningGroups=FALSE, BOOL TellWorld=TRUE, BOOL bForceNewValue=FALSE)
 This function Adds Attribute to the specified AttrGroup.
AttributeGroupGetAttributeGroup (CCRuntimeClass *GroupID)
 This function obtains a pointer to the requested group.
void AddAttributeToGroup (AttributeGroup *pAttrGroup, NodeAttribute *Attribute, BOOL fCheckTransparency, BOOL TellWorld=TRUE, BOOL bRetainValues=FALSE)
 This function is a helper for AttributeManager::UpdateCurrentAttribute. it adds the specified attribute to the specified Attribute group. and BROADCASTS a CurrentAttrChangedMsg message.
BOOL WriteCurrentAttributeGroupRecord (BaseCamelotFilter *pFilter, AttributeGroup *pGroup)
 


Static Private Member Functions

static void ApplyAttribToNodeHelper (NodeRenderableInk *InkNode, NodeAttribute *NewAttr)
 Replaces an attribute within a specified Ink Node.
static BOOL RegisterBasicAttributes ()
 Register all the 'built-in' rendering attributes that Camelot has. This allows us to register these basic attributes first and in a known order, so we can use a constant instead of a variable to access them, thus allowing us to get to these attributes quicker.
static BOOL EnsureTableSpaceAvailable ()

Private Attributes

List AttrGroupList

Static Private Attributes

static AttributeEntryDefaultAttrValues = NULL
static NodeTypeEntryDefaultNodeAttrs = NULL
static UINT32 NumAttributes = 0
static UINT32 AttributeTableSize = 0

Friends

class BaseCamelotFilter

Detailed Description

The attribute manager is currently responsible for managing the application of current attributes. It contains a list of Attribute groups along with instances of current attributes which belong to each group. An attribute group is identified by the RuntimeClass of an object.

Author:
Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
Date:
29/11/93
Each Document should have its own set of current attributes

It has been extended to store default attribute information by Tim

See also:
-

Definition at line 215 of file attrmgr.h.


Member Enumeration Documentation

enum AttributeManager::AttrsToMakeCurrent
 

Enumerator:
ALL 
NOT_APPLIED 
NONE 

Definition at line 255 of file attrmgr.h.

00255 { ALL, NOT_APPLIED, NONE };


Constructor & Destructor Documentation

AttributeManager::AttributeManager  ) 
 

Definition at line 199 of file attrmgr.cpp.

00200 {
00201 }

AttributeManager::~AttributeManager  ) 
 

Attribute manager destructor Currently destroys all attributes in all attribute groups.

Author:
Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
Date:
19/8/94
Parameters:
- [INPUTS]
- [OUTPUTS]
Returns:
-

Errors: -

See also:
-

Definition at line 1069 of file attrmgr.cpp.

01070 {
01071     // Delete all groups 
01072     AttributeGroup* CurrentGroup = (AttributeGroup*)AttrGroupList.GetHead(); 
01073     NodeAttribute* CurrentAttr;
01074     NodeAttribute* NextAttr;  
01075     while (CurrentGroup != NULL)
01076     {
01077         // Delete all attributes in the group 
01078         CurrentAttr = CurrentGroup->AttrListHd;// get pointer to first attribute in the 
01079                                                     // group 
01080         while (CurrentAttr != NULL)
01081         {
01082             NextAttr = (NodeAttribute*)CurrentAttr->FindNext(); 
01083             delete CurrentAttr; 
01084             CurrentAttr = NextAttr;     
01085         }
01086 
01087         delete (AttrGroupList.RemoveItem((ListItem*)CurrentGroup));
01088         CurrentGroup =(AttributeGroup*)AttrGroupList.GetHead();         // Get next group  
01089     }
01090 }


Member Function Documentation

void AttributeManager::AddAttributeToGroup AttributeGroup pAttrGroup,
NodeAttribute Attribute,
BOOL  fCheckTransparency,
BOOL  TellWorld = TRUE,
BOOL  bRetainValues = FALSE
[private]
 

This function is a helper for AttributeManager::UpdateCurrentAttribute. it adds the specified attribute to the specified Attribute group. and BROADCASTS a CurrentAttrChangedMsg message.

Author:
Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
Date:
9/4/95
Parameters:
pAttrGroup,: The attribute group to add the attribute to [INPUTS] Attribute: The attribute to add
fCheckTransparency if TRUE (the default) then the attribute will be tested on insertion into the tree as to whether it needs transparency mode. This is prevented upon Camelot initialisation, when default attributes are inserted in the tree.

TellWorld: Broadcast a CurrentAttrChangedMsg

Returns:
Errors: - Scope: private
See also:
AttributeManager::UpdateCurrentAttribute

Definition at line 1543 of file attrmgr.cpp.

01548 {
01549     // Add Attribute to the group 
01550     if (pAttrGroup->AttrListHd != NULL)
01551         Attribute->AttachNode(pAttrGroup->AttrListHd, NEXT, fCheckTransparency); 
01552     else 
01553         pAttrGroup->AttrListHd = Attribute;
01554     
01555     // If this is a Fill Attribute then we need to make sure its
01556     // in a sensible state.
01557     if (Attribute->IsAFillAttr())
01558     {
01559         AttrFillGeometry* Fill = (AttrFillGeometry*)Attribute;
01560         // Ensure that all it's control points are deselected, else
01561         // when it is applied to an object, the user may get confused.
01562         Fill->DeselectAll();
01563 
01564         if (!bRetainValues && Fill->GetBoundingRect().IsEmpty())
01565         {
01566             // If the bounding box is Empty then we know that this
01567             // fill has never been applied to an object before.
01568             // We ensure that it's control points are Null, so
01569             // they will be set to some sensible default (centre of
01570             // the object usually) when eventually applied.
01571             DocCoord    coord;
01572             Fill->SetStartPoint( &coord );
01573             Fill->SetEndPoint( &coord );
01574             Fill->SetEndPoint2( &coord );
01575         }
01576 
01577     }
01578 
01579     // Tell everyone that the Current Attributes have Changed.
01580     if (TellWorld)
01581     {
01582         BROADCAST_TO_ALL(CurrentAttrChangedMsg()); 
01583     }
01584 }   

void AttributeManager::ApplyAttribToNode NodeRenderableInk InkNode,
NodeAttribute NewAttr
[static]
 

Replaces an attribute within a specified Ink Node.

Author:
Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
Date:
28/1/94
Parameters:
InkNode,: The Ink node whos attribute is to be changed. [INPUTS]
NewAttr: The new attribute that is to replace the Ink Nodes expisting one.

See also:
AttributeManager::AttributeSelected; AttributeManager::ReplaceAttributes

Definition at line 3398 of file attrmgr.cpp.

03399 {
03400     // need to check the case where the selected node
03401     
03402     ApplyAttribToNodeHelper(InkNode, NewAttr);
03403 
03404     // We only need to tell everyone if the node is within the selection
03405     if (InkNode != NULL && (InkNode->IsSelected() || InkNode->IsChildOfSelected()) && SendMessages)
03406     {
03407         // Inform the selection that attributes have changed
03408         SelRange* Sel = GetApplication()->FindSelection();
03409         if (Sel) 
03410             Sel->AttrsHaveChanged(); 
03411 
03412         if (NewAttr->IsKindOf(CC_RUNTIME_CLASS(AttrColourChange)) )
03413         {
03414             // If the Attrib was a Colour Mutator, then we must have changed a colour
03415             // so lets tell someone about it
03416             BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::COLOURATTCHANGED)); 
03417         }
03418         else
03419         {
03420             // We've probably changed a Colour
03421             BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::COLOURATTCHANGED)); 
03422             // and the Attrib may have changed shape or summit. Who knows ?
03423             BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::NONCOLOURATTCHANGED)); 
03424 
03425             if (Sel) Sel->UpdateBounds();
03426         }
03427 
03428         // And ensure that if we've caused the SelRange to set up any delayed message
03429         // broadcasts, that it sends them now rather than at some random time in the future
03430         // when some Op just happens to end.
03431         if (Sel)
03432             Sel->BroadcastAnyPendingMessages();
03433     }
03434 
03435 
03436     delete NewAttr;
03437 }

void AttributeManager::ApplyAttribToNodeHelper NodeRenderableInk InkNode,
NodeAttribute NewAttr
[static, private]
 

Replaces an attribute within a specified Ink Node.

Author:
Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
Date:
28/1/94
Parameters:
InkNode,: The Ink node whos attribute is to be changed. [INPUTS]
NewAttr: The new attribute that is to replace the Ink Nodes expisting one.

Scope: private

See also:
AttributeManager::AttributeSelected; AttributeManager::ReplaceAttributes

Definition at line 3458 of file attrmgr.cpp.

03459 {
03460 #if !defined(EXCLUDE_FROM_RALPH)
03461     BOOL ApplyAttribute = FALSE; 
03462     List AttrGroupList;  
03463 
03464     pLastNodeAppliedTo = NULL;
03465 
03466     if (InkNode != NULL && NewAttr != NULL)
03467     {
03468         ApplyAttribute = CanBeAppliedToNode(InkNode, NewAttr, &AttrGroupList);
03469     }
03470 
03471     if (ApplyAttribute)
03472     {
03473         // Obtain a pointer to the op descriptor for the attribute operation 
03474         OpDescriptor* OpDesc = OpDescriptor::FindOpDescriptor(CC_RUNTIME_CLASS(OpApplyAttribToNode));
03475 
03476         // Get the number of selected fill control points, 'cus we may want to do
03477         // something different depending on how many their are.
03478 
03479 #ifdef BUILDSHADOWS     
03480         // New check which will only be done in BUILDSHADOWS
03481         if(InkNode->IS_KIND_OF(NodeShadow))
03482         {
03483             AttrFillGeometry::SelectionCount = 1;
03484         }
03485         else
03486 #endif
03487         {
03488             AttrFillGeometry::SelectionCount = AttrFillGeometry::CountSelectionControlPoints();
03489         }
03490 
03491 // Removed the following section as we can do this now
03492 /*      if (IS_A(NewAttr, AttrColourDrop))
03493         {
03494             if (IS_A (InkNode, NodeBitmap))
03495             {
03496                 // Ask the user wether or not they want to use a 24bit copy of the BMP or use the Default Bitmap?
03497                 //InformWarning(_R(IDS_BFX_BMP_CONVERT_MSG),_R(IDS_OK),0,0,0,1,2);
03498 
03499                 NodeBitmap* pBitmap = (NodeBitmap*) InkNode;
03500 
03501                 if (pBitmap->GetBitmap ()->ActualBitmap->GetBitmapInfoHeader ()->biBitCount == 32)
03502                 {
03503                     // we don't want the code to fire if were trying to apply a nocolour attribute ....
03504                         
03505                     BOOL isNoColour = FALSE;
03506 
03507                     isNoColour = (((FlatFillAttribute*) NewAttr->GetAttributeValue ())->GetStartColour ()->IsTransparent ());
03508 
03509                     if (!isNoColour)
03510                     {
03511                         // Load and build the question text.
03512                         String_256 QueryString(_R(IDS_QUERYTRANSP322));
03513                                             
03514                         // The only way of bringing up a box with a string in it
03515                         Error::SetError(0, QueryString, 0);
03516                         INT32 DlgResult = InformMessage(NULL, _R(IDS_YES), _R(IDS_NO));
03517                         Error::ClearError();
03518 
03519                         switch (DlgResult)
03520                         {
03521                             case 2:             // NO
03522                                 return;         // break out of this stuff!
03523                         }
03524                     }
03525                 }
03526             }
03527         }
03528 */
03529         // Invoke the operation, passing Attrib as a parameter
03530         OpParam tempParam((void *)InkNode,(void *)NewAttr);
03531         OpDesc->Invoke(&tempParam);
03532     }
03533     
03534     Document* CurrentDoc = Document::GetSelected();
03535     if (CurrentDoc == NULL)
03536         return; // We are not going to be able to do anything if there is no document
03537 
03538     AttributeManager& AttrMgr = CurrentDoc->GetAttributeMgr();
03539 
03540     if (AttrMgr.WeShouldMakeAttrCurrent(ApplyAttribute, NewAttr, &AttrGroupList, 
03541                                         TRUE, // Drag n' drop
03542                                         InkNode == NULL)) // Dropped onto page
03543     {
03544         UpdateCurrentAttr(NewAttr, NewAttr->IsAFillAttr(), &AttrGroupList);
03545 
03546         // Some Attributes require a second attribute to be changed as well.
03547         BOOL IsMutate;
03548         NodeAttribute* pOther = AttributeManager::GetOtherAttrToApply(NewAttr, &IsMutate);
03549     
03550         if (pOther != NULL)
03551         {
03552             UpdateCurrentAttr(pOther, IsMutate, &AttrGroupList); // can't have a NULL AttrGroupList
03553                                                                  // or it will apply to tools list
03554         }
03555 
03556         if (pOther)
03557         {
03558             delete pOther;
03559         }
03560     }
03561 
03562     // Don't forget the AttrGroupList
03563     AttrGroupList.DeleteAll();
03564 #endif
03565 }

BOOL AttributeManager::ApplyBasedOnDefaults Node Target,
AttributeEntry AttrsToApply
[static]
 

Given a set of attributes, apply the ones that differ from the defaults to the specified node. Most commonly used by import filters.

Author:
Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
Date:
12/04/94
Parameters:
Target - the node to apply the attributes to. [INPUTS] AttrsToApply - the attribute array to apply to this node.
Returns:
TRUE if attributes applied to nodes successfully; FALSE if otherwise.

Errors: Out of memory.

Definition at line 2287 of file attrmgr.cpp.

02288 {
02289     // Cycle through each type of attribute, and add it if:
02290     //  (a) It is of a type that can take the attribute, and
02291     //  (b) the attribute is different to the default attribute.
02292 
02293     // There is a short cut for telling if the attribute has been changed from the default;
02294     // if the pointer to the attribute is still the same as our copy, then it can't have
02295     // changed
02296 
02297 // ****** Bodge ********
02298 // We must make the Line and Fill colours in the Default Attrs
02299 // into Index colours in the Current Document !!
02300 /*
02301     DocColour DefBlack;
02302     FindDefaultColour(ColourManager::GetCurrentColourList(),
02303                         _R(IDS_BLACKNAME), &DefBlack);
02304 
02305     ((StrokeColourAttribute*)DefaultAttrValues[ATTR_STROKECOLOUR].pAttr)->SetStartColour(&DefBlack);
02306     ((FillGeometryAttribute*)DefaultAttrValues[ATTR_FILLGEOMETRY].pAttr)->SetStartColour(&DefBlack);
02307 */
02308 // ****** End Bodge ********
02309 
02310     for (INT32 i = NumAttributes - 1; i >= 0; i--)
02311     {
02312         // Has it changed, and is it of the right node type?
02313         if (!AttrsToApply[i].Ignore &&
02314             (DefaultAttrValues[i].pAttr != AttrsToApply[i].pAttr) &&
02315             (Target->IsKindOf(DefaultNodeAttrs[i].pNodeType)))
02316         {
02317             // This node can take this type of attribute.
02318             if ((DefaultAttrValues[i].pAttr == NULL) || 
02319                 (AttrsToApply[i].pAttr->GetRuntimeClass() != 
02320                  DefaultAttrValues[i].pAttr->GetRuntimeClass()) ||
02321                 AttrsToApply[i].pAttr->IsDifferent(DefaultAttrValues[i].pAttr))
02322             {
02323                 // The attribute is different to the default - construct the appropriate 
02324                 // attribute node.
02325                 Node *pNode = AttrsToApply[i].pAttr->MakeNode();
02326 
02327                 // Enough memory?
02328                 if (pNode == NULL)
02329                     return FALSE;
02330 
02331                 // Add it to the target
02332                 pNode->AttachNode(Target, FIRSTCHILD);
02333             }
02334         }
02335         
02336     }
02337 
02338     // All default attributes processed ok.
02339     return TRUE;
02340 }

BOOL AttributeManager::ApplyCurrentAttribsToNode NodeRenderableInk Node  ) 
 

This function determines the attribute group associated with the object and then applies all attributes in the group to the object. If the group has a base group then all attributes in the base group with types different to those already applied get added to the object etc.

Author:
Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
Date:
19/8/94
Returns:
FALSE if we run out of memory
See also:
NodeRenderableInk::GetCurrentAttribGroup

AttributeManager::CreateCurrentAttributeGroup

AttributeManager::UpdateCurrentAttribute

Definition at line 1740 of file attrmgr.cpp.

01741 {
01742     ERROR3IF(Node == NULL, "NULL object passed to AttributeManager::ApplyCurrentAttribsToNode"); 
01743 
01744     // Find the attribute group that contains the attributes we need to initially apply to the
01745     // node.
01746     CCRuntimeClass* IDCurrentAttrGroup = Node->GetCurrentAttribGroup(); 
01747     ERROR3IF (IDCurrentAttrGroup == NULL, "Object has NULL attribute group associated with it");  
01748     
01749     // We need to find out quickly if an attribute has already been applied to Node
01750     // Maps Attribute types to TRUE/FALSE values
01751     CCAttrMap* pAppliedAttrsMap;            
01752     
01753     try
01754     {        
01755         pAppliedAttrsMap = new  CCAttrMap(30);
01756     } 
01757     catch( ... )
01758     {
01759         return FALSE; 
01760     }
01761 
01762     // Loop back here to apply base group attributes
01763     do
01764     {
01765         // Search for IDCurrentAttrGroup
01766         AttributeGroup* CurrentGrp = (AttributeGroup*)AttrGroupList.GetHead(); 
01767         while (CurrentGrp != NULL)
01768         {   
01769             if (CurrentGrp->AttrGroup == IDCurrentAttrGroup) // Found the group 
01770             {
01771                 // Create a copy of each attribute and add it as a child of Node 
01772                 NodeAttribute* CurrentAttrib = CurrentGrp->AttrListHd;
01773                 while (CurrentAttrib != NULL) 
01774                 {
01775                     // Has an attribute of the same type already been applied to the node, 
01776                     // this should only ever be the case if we are applying attributes from a base group !.
01777                     CCRuntimeClass* CurrentAttrType = CurrentAttrib->GetAttributeType(); 
01778 
01779                     void* NotUsed;
01780                     if( !pAppliedAttrsMap->Lookup( CurrentAttrType, NotUsed ) &&
01781                         Node->RequiresAttrib( CurrentAttrib ) )
01782                     {
01783                         // Ensure the nodes bounding box is up to date, so that fill
01784                         // attributes can be scaled correctly.
01785                         Node->InvalidateBoundingRect();
01786                         DocRect NodeBounds = Node->GetBoundingRect(TRUE);
01787 
01788                         // Take a copy of the attribute 
01789                         NodeAttribute* AttribClone = (NodeAttribute*)CurrentAttrib->SimpleCopy(); 
01790                         ERRORIF(!AttribClone, _R(IDE_NOMORE_MEMORY), FALSE);
01791 
01792                         // Scale and move the attributes bounds so that it is ready to apply to the
01793                         // new object.
01794                         AttribClone->TransformToNewBounds(NodeBounds); 
01795                         
01796                         // Attach AttribClone to Node
01797                         AttribClone->AttachNode(Node, FIRSTCHILD); 
01798 
01799                         if (AttribClone->GetAttributeType() == CC_RUNTIME_CLASS(AttrFillGeometry) ||
01800                             AttribClone->GetAttributeType() == CC_RUNTIME_CLASS(AttrTranspFillGeometry))
01801                         {
01802                             // Now the Attribute is in the tree, we need to tell the fill
01803                             // attribute to check that it's control points are valid.
01804                             // Unless the fill we transformed above, this will usually 
01805                             // involve the fill 'centring' itself within the bounds of its
01806                             // parent.
01807                             ((AttrFillGeometry*)AttribClone)->AttributeChanged();
01808                         } // end if 
01809 
01810                         // Add the attributes type to the applied attributes map so that it does not get 
01811                         // applied again.
01812                         pAppliedAttrsMap->SetAt(CurrentAttrType, NULL); 
01813                     }
01814                     CurrentAttrib = (NodeAttribute*)CurrentAttrib->FindNext(); 
01815                 }
01816                 // ok now apply attributes from the base group, if one exists
01817                 IDCurrentAttrGroup = CurrentGrp->BaseGroup;
01818                 break; 
01819             }
01820             CurrentGrp = (AttributeGroup *) AttrGroupList.GetNext(CurrentGrp);
01821             ERROR3IF(CurrentGrp == NULL, "Unable to find attribute group"); 
01822         }
01823         // break takes us here
01824     } while (IDCurrentAttrGroup != NULL);
01825 
01826     delete pAppliedAttrsMap; // Map no longer required
01827     return TRUE;  
01828 }

void AttributeManager::AttributeSelected NodeAttribute Attrib,
NodeAttribute OldAttr = NULL
[static]
 

This function should be called whenever an attribute is selected by the user.

Author:
Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
Date:
13/6/94
Parameters:
Attrib,: The selected attribute. All attributes of the same type in the [INPUTS] selection will be replaced with this attribute. Don't delete this it may become a current attribute.
New Bits Added by Will: When NULL this indicates that the OldAttr parameter should act as a Mutator. A Mutator will change all the fill attributes in the selection to be the same 'type' as the mutator, whilst retaining their individual control points and colours. A special kind of Mutator, 'AttrColourChange' will force all objects in the selection to change their selected control point colours, or to 'Mutate'into an 'AttrFlatFill' if there are no selected control points anywhere in the selection. A Mutator must be derived from AttrFillGeometry.

OldAttr: When no-null, this specifies the node which 'Attrib' is to replace. It is used when an attribute is edited.

When Attrib == NULL, this specifies a Mutator (see above).

Intermediate: TRUE when we expect someone to call AttributeSelected again after this call with the same attr types, same selection and Intermediate set to FALSE

If any nodes are selected the function invokes an operation to apply the attribute to the selected nodes.

If no nodes are selected then the attribute may become a current attribute depending on the preferences.

Returns:
Errors: -
See also:
AttributeManager::ReplaceAttributes; AttributeManager::ApplyAttribToNode

Definition at line 2389 of file attrmgr.cpp.

02390 {
02391 #if !defined(EXCLUDE_FROM_RALPH)
02392     ENSURE( (Attrib != NULL || OldAttr != NULL), "NULL attributes passed to AttributeSelected"); 
02393 
02394     BOOL Mutate = (Attrib == NULL);
02395     AttrFillGeometry* Mutator = NULL;
02396 
02397     pLastNodeAppliedTo = NULL;
02398 
02399     // If parameter one is NULL then we must be doing a Mutation
02400     if (Mutate)
02401     {
02402         ERROR3IF(!OldAttr->IsAFillAttr(), "A Mutator must be a fill attribute");
02403         // Make a more sensible pointer
02404         Mutator = (AttrFillGeometry*)OldAttr;
02405     }
02406 
02407     // If there are any objects selected then the attribute needs to be applied to these objects
02408 //  OpDescriptor* OpDesc = NULL;
02409 //  BOOL MakeAttrCurrent = FALSE; // until we know better
02410 
02411     SelRange* Sel = GetApplication()->FindSelection();
02412     ERROR3IF(Sel==NULL,"Can't find SelRange!");
02413     if (Sel==NULL) return;
02414 
02415     // If there are no objects in the selection, or if none of the selected objects require
02416     // the attribute, then it will not be applied
02417 
02418     BOOL ApplyAttribute; 
02419 
02420     List AttrGroupList;  
02421 
02422     if (Attrib != NULL)
02423     {
02424         ApplyAttribute = CanBeAppliedToSelection(Attrib, &AttrGroupList);
02425     }
02426     else
02427     {
02428         ERROR3IF(OldAttr == NULL, "What are we applying then exactly ??");
02429         ApplyAttribute = CanBeAppliedToSelection(OldAttr, &AttrGroupList); // Mutator 
02430     } 
02431     
02432 
02433     if (ApplyAttribute)
02434     { 
02435         // We need to invoke an operation to apply the attribute to the currently selected 
02436         // objects. 
02437 
02438         // Get the number of selected fill control points, 'cus we may want to do
02439         // something different depending on how many their are.
02440         AttrFillGeometry::SelectionCount = AttrFillGeometry::CountSelectionControlPoints();
02441 
02442         // Obtain a pointer to the op descriptor for the attribute operation 
02443         BOOL bApplying = TRUE;
02444         OpDescriptor* OpDesc = OpDescriptor::FindOpDescriptor(CC_RUNTIME_CLASS(OpApplyAttribToSelected));
02445 
02446         // But first ... Was the pervious Op the same ?
02447         Operation* pLastOp = Document::GetSelected()->GetOpHistory().FindLastOp();
02448 
02449         if (Mutate && pLastOp && pLastOp->GetRuntimeClass() == CC_RUNTIME_CLASS(OpApplyAttribToSelected))
02450         {
02451             // The last operation was similar to this one, but was it exactly the same type ?
02452             OpApplyAttribToSelected* pLastApplyOp = (OpApplyAttribToSelected*)pLastOp;
02453 
02454             if (pLastApplyOp->GetValueChangeType() == Mutator->GetRuntimeClass() &&
02455                 pLastApplyOp->IsMergeableApplyOp())
02456             {
02457                 // Yep, they are exactly the same type of value change.
02458                 // So we don't need to do an undoable op for this new change,
02459                 // we can just invoke a special op that will change the attributes
02460                 // directly.
02461 
02462                 // But first ... Is the selection still the same ?
02463                 RestoreSelectionsAction* pRestoreSelAct = (RestoreSelectionsAction*)
02464                         pLastApplyOp->GetUndoActionList()->FindActionOfClass(CC_RUNTIME_CLASS(RestoreSelectionsAction));
02465                 SelectionState* LastOpsSelection = pRestoreSelAct->GetSelState();
02466 
02467                 SelectionState CurrentSelection;
02468                 CurrentSelection.Record();
02469 
02470                 if (*LastOpsSelection == CurrentSelection)
02471                 {
02472                     FillBlobSelectionState CurrentFillBlobState;
02473                     CurrentFillBlobState.Record();
02474 
02475                     if (OpRepeatApplyAttribToSelected::FillBlobState == CurrentFillBlobState)
02476                     {
02477                         OpDesc = OpDescriptor::FindOpDescriptor(CC_RUNTIME_CLASS(OpRepeatApplyAttribToSelected));
02478                         bApplying = FALSE;
02479                     }
02480                 }
02481             }
02482         }
02483 
02484         // Invoke the operation, passing Attrib as a parameter
02485         OpParam tempParam((void *)Attrib,(void *)OldAttr);
02486         OpDesc->Invoke(&tempParam);
02487 
02488         // Remember the current blob selection state, so we can decide whether or not to
02489         // merge future apply operations
02490         if (bApplying)
02491             OpRepeatApplyAttribToSelected::FillBlobState.Record();
02492 
02493         UpdateAfterAttrApplied(Mutate ? Mutator : NULL);
02494 
02495     }
02496 
02497     BOOL bCurrentUpdated = UpdateCurrentAppliedAttr(Mutate ? Mutator: Attrib, &AttrGroupList, ApplyAttribute, Mutate);
02498     if (!bCurrentUpdated)
02499     {
02500         // Allow fill tools to update after a cancel
02501         BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::NONCOLOURATTCHANGED));
02502     }
02503 
02504     // Tidy up attributes because they were only patterns and are no longer needed
02505     if (Mutate)
02506     {
02507         if (Mutator != NULL)
02508         {
02509             delete Mutator;
02510             Mutator = NULL;
02511         }
02512     }
02513     if (Attrib != NULL)
02514     {
02515         delete Attrib;
02516         Attrib = NULL;
02517     }
02518 
02519     // Don't forget the AttrGroupList
02520     AttrGroupList.DeleteAll();
02521 
02522     // And ensure that if we've caused the SelRange to set up any delayed message
02523     // broadcasts, that it sends them now rather than at some random time in the future
02524     // when some Op just happens to end.
02525     Sel->BroadcastAnyPendingMessages();
02526 #endif
02527 }

void AttributeManager::AttributesSelected List AttribsToApply,
UINT32  OpName
[static]
 

This high level function should be called whenever we need to apply multiple attributes to the selection (eg. PasteAttributes).

Author:
Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
Date:
13/6/94
Parameters:
AttribsToApply,: A list of NodeAttributePtrItems. These are the attributes [INPUTS] which will be applied to the selection. The function does not currently support attribute mutation.
All AttrFillGeometry attributes should have their current bounds set using AttrFillGeometry::SetBoundingRect.

very important ~~~~~~~~~~~~~~

This function only ever applies copies of attributes in the AttribsToApply list. It is the responsibility of the caller to delete these attributes, if this is appropriate.

OpName: The name to give the operation which is performed by this function to apply attributes. eg. 'Paste Attributes'

Parameters:
- [OUTPUTS]
Returns:
-
If any objects are selected then the function invokes an operation to apply the attributes to these objects. Before an AttrFillGeometry is applied to an object it gets moved and scaled.

If no nodes are selected then the attributes may become current depending on the preferences and what the user decides.

See also:
AttributeManager::AttributeSelected

Definition at line 2634 of file attrmgr.cpp.

02635 {
02636 #if !defined(EXCLUDE_FROM_RALPH)
02637     // The AttributeList cannot be empty
02638     ERROR3IF(AttribsToApply.IsEmpty(), "No attributes to apply in AttributeManager::AttributesSelected"); 
02639     if (AttribsToApply.IsEmpty()) return; // nothing to do
02640 
02641     // If there is no current document then there is very little we can do
02642     Document* CurrentDoc = Document::GetSelected();
02643     if (CurrentDoc == NULL)
02644         return; // We are not going to be able to do anything if there is no document
02645 
02646     SelRange* Sel = GetApplication()->FindSelection();
02647     ERROR3IF(Sel==NULL,"Can't find SelRange!");
02648     if (Sel==NULL) return;
02649 
02650     // If there are no objects in the selection, or if none of the selected objects require
02651     // the attribute, then it will not be applied
02652                             
02653     // Obtain a pointer to the op descriptor for the operation 
02654     OpDescriptor* OpDesc = OpDescriptor::FindOpDescriptor(CC_RUNTIME_CLASS(OpApplyAttribsToSelected));
02655                 
02656     List AttrGroupsList;  // Will contain a list of current Attribute group sets. one for each attribute 
02657                           // in the AttribsToApply list. Each item in this list will be a ListListItem.
02658 
02659     BOOL Success;               // FALSE if the operation fails
02660     BOOL AnyAttrsApplied;       // FALSE if the operation has not applied any attributes
02661 
02662     // Build the parameter we are about to pass to the operation
02663     ApplyAttribsToSelectedParam OpParam(&AttribsToApply,
02664                                         OpName, 
02665                                         &AttrGroupsList,        // One per attribute applied
02666                                         &Success,               // Indicates if op was successful
02667                                         &AnyAttrsApplied);      // Indicates if the operation applied
02668                                                                 // any attributes
02669 
02670     
02671     // Invoke the operation
02672     OpDesc->Invoke(&OpParam);
02673 
02674     if (Success)
02675     {
02676         // Inform neccessary parties
02677         if (AnyAttrsApplied)
02678         {
02679             // Inform the selection that attributes have changed
02680             Sel->AttrsHaveChanged();
02681 
02682             // We've probably changed a Colour
02683             BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::COLOURATTCHANGED)); 
02684             // and the Attrib may have changed shape or summit. Who knows ?
02685             BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::NONCOLOURATTCHANGED)); 
02686             Sel->UpdateBounds();
02687         }
02688         
02689         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
02690         // Now decide which attributes in the AttribsToApply list should be made current
02691                                                
02692         AttributeManager& AttrMgr = CurrentDoc->GetAttributeMgr();
02693         AttrsToMakeCurrent AttribsToMakeCurrent = AttrMgr.GetAttributesToMakeCurrent(AttribsToApply, 
02694                                                                              AttrGroupsList,
02695                                                                              FALSE);
02696                                                                     
02697         if (AttribsToMakeCurrent == NONE)
02698         {
02699             // Allow fill tools to update after a cancel
02700             // I'm not sure if we need this ???? Ask Will
02701             BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::NONCOLOURATTCHANGED)); 
02702         }
02703         else
02704         {
02705             BOOL AttributeApplied;
02706             NodeAttributePtrItem* pAttr = (NodeAttributePtrItem*)(AttribsToApply.GetHead());
02707             ListListItem* pAttrsGroups = (ListListItem*) (AttrGroupsList.GetHead());
02708             while (pAttr)
02709             {
02710                 AttributeApplied = (!(pAttrsGroups->list.IsEmpty())); // Empty Current attribute group list
02711                 if (!AttributeApplied || (AttribsToMakeCurrent == ALL))
02712                 {
02713                     // Add attribute to all current attribute groups in the list, or to the 
02714                     // group associated with the current tool if the list is empty.
02715                     UpdateCurrentAttr(pAttr->NodeAttribPtr, 
02716                                       FALSE, // Not a mutator
02717                                       &(pAttrsGroups->list), 
02718                                       FALSE); // Don't tell world yet (too slow)
02719                 }
02720                 pAttr = (NodeAttributePtrItem*)(AttribsToApply.GetNext(pAttr));
02721                 pAttrsGroups = (ListListItem*)(AttrGroupsList.GetNext(pAttrsGroups));
02722             }
02723             // Tell world current attributes have changed
02724             BROADCAST_TO_ALL(CurrentAttrChangedMsg()); 
02725         } 
02726     }
02727     // Tidyup
02728     AttrGroupsList.DeleteAll(); // Delete all group lists 
02729 
02730     // And ensure that if we've caused the SelRange to set up any delayed message
02731     // broadcasts, that it sends them now rather than at some random time in the future
02732     // when some Op just happens to end.
02733     Sel->BroadcastAnyPendingMessages();
02734 #endif
02735 }

BOOL AttributeManager::CanBeAppliedToNode NodeRenderableInk pObject,
NodeAttribute Attrib,
List pAttrGroups
[static]
 

This function would ideally live in the SelRange. It determines if the attribute can be applied to a specified object.

Author:
Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
Date:
27/4/95
Parameters:
Attrib,: The attribute [INPUTS]
AttrGroups,: If the object requires Attrib then this list is updated to [OUTPUTS] include the current attribute group that the attribute should be added to if it were to be made current. This list should be passed in as a parameter to UpdateCurrentAttr.
Returns:
TRUE if the object requires Attrib
See also:
AttributeManager::CanBeAppliedToSelection; AttributeManager::AttributeSelected; AttributeManager::UpdateCurrentAttr

Definition at line 3283 of file attrmgr.cpp.

03285 {
03286     BOOL RequiresAttrib = FALSE; 
03287 
03288     CCRuntimeClass* NewAttrGroup;
03289     CCRuntimeClass* InSetAttrGroup; // One that's already in the list 
03290     AttributeGroupItem* pAttrGrpItem;
03291 
03292     BOOL InSet;
03293 
03294     NodeRenderableInk* Current = pObject;
03295 
03296     if (Current != NULL)
03297     {
03298         if (Current->RequiresAttrib(Attrib))
03299         {
03300             RequiresAttrib = TRUE; 
03301 
03302             // Obtain the attribute group
03303             NewAttrGroup = Current->GetCurrentAttribGroup();
03304             ERROR3IF(NewAttrGroup == NULL, "Object has a NULL attribute group"); 
03305 
03306             InSet = FALSE; 
03307 
03308             // Search the AttrGroups set to see if it's already there
03309             pAttrGrpItem = (AttributeGroupItem*)pAttrGroups->GetHead();
03310             while(pAttrGrpItem != NULL)
03311             {
03312                 InSetAttrGroup = pAttrGrpItem->AttrGroup;
03313                 ERROR3IF(InSetAttrGroup == NULL, "NULL attribute group found");
03314                 if (NewAttrGroup == InSetAttrGroup)
03315                 {
03316                     InSet = TRUE; 
03317                     break; // It's already in the set don't add it
03318                 }
03319                 pAttrGrpItem = (AttributeGroupItem*)pAttrGroups->GetNext(pAttrGrpItem);
03320             }
03321             
03322             if (!InSet) // The AttrGroup needs adding to the pAttrGroups set
03323             {
03324                 // Create a new AttrGroupItem
03325                 pAttrGrpItem = new AttributeGroupItem();
03326                 if (pAttrGrpItem == NULL)
03327                     return FALSE; // Panic !!
03328 
03329                 pAttrGrpItem->AttrGroup = NewAttrGroup;
03330 
03331                 // And add it to our set
03332                 pAttrGroups->AddHead(pAttrGrpItem); // Most recent at start of list.
03333             }  
03334         }
03335     }
03336 
03337     return RequiresAttrib;
03338 }

BOOL AttributeManager::CanBeAppliedToSelection NodeAttribute Attrib,
List pAttrGroups
[static]
 

This function would ideally live in the SelRange. It determines if the attribute can be applied to at least one object in the selection.

Author:
Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
Date:
5/4/95
Parameters:
Attrib,: The attribute [INPUTS]
AttrGroups,: If any of the selected objects requires Attrib then this list [OUTPUTS] is a set of all current attribute groups that the attribute should be added to if it were to be made current. This list should be passed in as a parameter to UpdateCurrentAttr.
If there are no objects in the selection, or if none of the selected objects requires the attribute then this list will be empty on return. UpdateCurrentAttr handles this case by adding the attribute to the attribute group associated with the selected tool.

Returns:
TRUE if at least one object requires Attrib
See also:
AttributeManager::AttributeSelected

AttributeManager::UpdateCurrentAttr

Definition at line 3231 of file attrmgr.cpp.

03232 {
03233 #if !defined(EXCLUDE_FROM_RALPH)
03234     SelRange* Sel = GetApplication()->FindSelection();
03235 
03236     BOOL RequiresAttrib = FALSE; 
03237 
03238     // Go though all the selected nodes
03239     NodeRenderableInk* Current = (NodeRenderableInk*)Sel->FindFirst();
03240     while (Current != NULL)
03241     {
03242         // See if this node requires the attribute
03243         if (CanBeAppliedToNode(Current, Attrib, pAttrGroups))
03244         {
03245             RequiresAttrib = TRUE;
03246             if ((