#include <selop.h>
Inheritance diagram for SelOperation:
Public Member Functions | |
SelOperation () | |
SelOperation constructor, calls the constructor of the base class. | |
virtual | ~SelOperation () |
SelOperation destructor. | |
BOOL | DoStartSelOp (BOOL RenderEndSelStateBlobs, BOOL RenderStartSelStateBlobs=TRUE, BOOL UndoRenderEndSelStateBlobs=FALSE, BOOL UndoRenderStartSelStateBlobs=FALSE) |
This function must be called by all SelOperations. It does the following:. | |
virtual void | End () |
Calls DoEndSelOp(), then Operation::End(). | |
virtual BOOL | MayChangeNodeBounds () const |
virtual BOOL | GetStarted () const |
virtual BOOL | DoAttributesSelected (List &AttribsToApply, UINT32 OpName, BOOL bPasteAttrs) |
This high level function should be called whenever we need to apply multiple attributes to the selection (eg. PasteAttributes). | |
virtual BOOL | DoApplyAttribsToSelection (OpParam *pOpParam, BOOL bClearIfNoneApplied=FALSE) |
Performs the OpApplyAttribsToSelected operation. This tries to apply the list of attributes in the OpParam->AttribsToApplyList to the selection. If no attribute can be applied then the operation does not generate any actions, and so will be a NOP and be destroyed during End(). | |
virtual BOOL | DoApplyToSelection (List *Attribs, List *AttrGroupList, BOOL *pAttribWasRequired) |
virtual BOOL | DoApply (Node *CurrentNode, NodeAttribute *Attrib, BOOL Mutate, BOOL InvalidateRegion=TRUE, BOOL KeepExistingCharacteristics=TRUE, BOOL *AttribWasRequired=NULL, BOOL *pbCanDiscardUndo=NULL) |
Will not apply the attribute to CurrentNode if it does not require it. | |
Static Public Member Functions | |
static BOOL | DoApply (SelOperation *pOp, Node *CurrentNode, NodeAttribute *Attrib, BOOL Mutate, BOOL InvalidateRegion=TRUE, BOOL KeepExistingCharacteristics=TRUE, BOOL bOptimise=TRUE, BOOL *AttribWasRequired=NULL, BOOL *pbCanDiscardUndo=NULL) |
static BOOL | InvalidateNodeRegion (SelOperation *pOp, NodeRenderableBounded *CurrentNode, NodeAttribute *Attrib, BOOL Mutate) |
static BOOL | ReleaseCachedForAttrApply (NodeRenderableBounded *pNode, BOOL bEffectRootOnly) |
If we have just set an effect attribute then we can avoid releasing cached info of the specified node and all its children... We RELY on invalidations associated with this function not calling ReleaseCached themselves! | |
Protected Member Functions | |
virtual BOOL | ApplyAttributeToBrush (Node *pCurrentNode, NodeAttribute *pAttr) |
Works out if pCurrentNode has an applied brush attribute, and if so then sets up an action to tell the brush to use the attribute being applied. | |
virtual BOOL | ApplyLineWidthToBrush (AttrBrushType *pAttrBrush, NodeRenderableInk *pBrushedNode, NodeAttribute *pAttr) |
If we are applying a line width to a brushed node we need to tell the brush that it must scale to line width. We must also do an additional invalidate region so that if we are increasing in size then the brush will be rerendered properly. | |
virtual BOOL | ApplyStrokeColourToBrush (AttrBrushType *pAttrBrush, NodeRenderableInk *pBrushedNode) |
When a new stroke colour is applied to a brushed object we wish to set the flag that tells the brush to override the named colours in the brush with the colour applied. | |
virtual BOOL | ApplyTransparencyToBrush (AttrBrushType *pAttrBrush, NodeRenderableInk *pBrushedNode) |
When a transparency is applied to a brushed object we need to set a flag in the brush to tell it to use this new transparency. | |
virtual BOOL | ApplyBrushAttr (Node *pCurrentNode, AttrBrushType *pAttrBrush) |
When we apply a brush attribute to an object we want to check to see if the current line width attribute is the same as the default attribute. If it is then we will apply the default line width suggested by the brush itself. This is because people keep on applying brush attributes to 500MP lines and ending up with thousands of brush objects, which makes everything really slow. | |
Private Member Functions | |
BOOL | DoEndSelOp () |
This function gets called automatically by End(). | |
Private Attributes | |
SelectionState * | SelState |
BOOL | m_bStartCalled |
Static Private Attributes | |
static BOOL | RenderEndSelStateBlobs |
static BOOL | RenderStartSelStateBlobs |
static BOOL | UndoRenderEndSelStateBlobs |
static BOOL | UndoRenderStartSelStateBlobs |
Definition at line 121 of file selop.h.
|
SelOperation constructor, calls the constructor of the base class.
Definition at line 138 of file selop.cpp. 00138 : UndoableOperation() 00139 { 00140 m_bStartCalled = FALSE; 00141 }
|
|
SelOperation destructor.
Definition at line 158 of file selop.cpp.
|
|
Works out if pCurrentNode has an applied brush attribute, and if so then sets up an action to tell the brush to use the attribute being applied.
Definition at line 770 of file attrappl.cpp. 00771 { 00772 ERROR2IF(pCurrentNode == NULL, FALSE, "Current node is NULL"); 00773 ERROR2IF(pAttr == NULL, FALSE, "Attribute is NULL"); 00774 00775 // currently this only works for colour changes and transparent fills 00776 if (!pAttr->IsKindOf(CC_RUNTIME_CLASS(AttrStrokeColourChange)) && !pAttr->IsATranspFill() 00777 && !pAttr->IsKindOf(CC_RUNTIME_CLASS(AttrLineWidth)) && !pAttr->IsABrush()) 00778 return TRUE; 00779 00780 // first get the existing brush attribute 00781 AttrBrushType* pAttrBrush = NULL; 00782 // for some reason we don't check the return value here?? 00783 /*BOOL ok =*/ ((NodeRenderableInk*)pCurrentNode)->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrBrushType), 00784 (NodeAttribute**)&pAttrBrush); 00785 00786 // if we're applying a brush attribute then do something else 00787 if (pAttr->IsABrush()) 00788 { 00789 AttrBrushType* pNewAttrBrush = (AttrBrushType*)pAttr; 00790 return ApplyBrushAttr(pCurrentNode, pNewAttrBrush); 00791 } 00792 00793 00794 // there isn't one - thats ok 00795 if (pAttrBrush == NULL || pAttrBrush->GetBrushHandle() == BrushHandle_NoBrush) 00796 return TRUE; 00797 00798 // so now we have a brush attribute, so lets determine what to do: 00799 if (pAttr->IsKindOf(CC_RUNTIME_CLASS(AttrStrokeColourChange))) 00800 { 00801 // only do this is the new colour is not transparent 00802 AttrStrokeColourChange* pStrokeCol = static_cast<AttrStrokeColourChange*>(pAttr); 00803 DocColour* pCol = pStrokeCol->GetStartColour(); 00804 //PORTNOTE("other","Removed DocColour usage") - AMB Unremoved 00805 if (pCol->IsTransparent()) 00806 return TRUE; 00807 00808 return ApplyStrokeColourToBrush(pAttrBrush, (NodeRenderableInk*)pCurrentNode); 00809 } 00810 00811 // Is this a porting comment-out? AMB 00812 // if (pAttr->IsATranspFill()) 00813 // return ApplyTransparencyToBrush(pAttrBrush, (NodeRenderableInk*)pCurrentNode); 00814 if (pAttr->IsKindOf(CC_RUNTIME_CLASS(AttrLineWidth))) 00815 return ApplyLineWidthToBrush(pAttrBrush, (NodeRenderableInk*)pCurrentNode, pAttr); 00816 00817 // trash the cached bounding rect 00818 pAttrBrush->ClearCachedRect(); 00819 00820 // if it isn't one of the above then we dont have to do anything 00821 return TRUE; 00822 }
|
|
When we apply a brush attribute to an object we want to check to see if the current line width attribute is the same as the default attribute. If it is then we will apply the default line width suggested by the brush itself. This is because people keep on applying brush attributes to 500MP lines and ending up with thousands of brush objects, which makes everything really slow.
Definition at line 961 of file attrappl.cpp. 00962 { 00963 ERROR2IF(pCurrentNode == NULL || pAttrBrush == NULL, FALSE, "Null input pointers to OpApplyAttrib::ApplyBrushAttr"); 00964 ERROR2IF(!pCurrentNode->IsAnObject(), FALSE, "Input node is not an ink node in OpApplyAttrib::ApplyBrushAttr"); 00965 00966 // its too complicated when you have compound nodes 00967 if (pCurrentNode->IsCompound()) 00968 return TRUE; 00969 00970 AttrLineWidth* pCurrentLineWidth = NULL; 00971 ((NodeRenderableInk*)pCurrentNode)->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrLineWidth), (NodeAttribute**)&pCurrentLineWidth); 00972 00973 if (pCurrentLineWidth != NULL) 00974 { 00975 // Get the default line width 00976 AttrLineWidth* pDefault = (AttrLineWidth*)(AttributeManager::GetDefaultAttribute(ATTR_LINEWIDTH)); 00977 if (pDefault == NULL) 00978 { 00979 ERROR3("Unable to get default line width, theres no way this can happen Jim!"); 00980 // continue anyway 00981 } 00982 else 00983 { 00984 // check to see if default is the same as current, if not then just leave 00985 if (pCurrentLineWidth->Value.LineWidth != pDefault->Value.LineWidth-1) 00986 { 00987 delete pDefault; 00988 PathProcessorBrush* pPPB = pAttrBrush->GetPathProcessor(); 00989 if (pPPB) 00990 { 00991 BOOL UsesPressure = pAttrBrush->GetPressureCache() != NULL; 00992 pPPB->ScaleToValue(pCurrentLineWidth->Value.LineWidth, !UsesPressure); 00993 pPPB->AdjustSpacingForClosedPath((NodeRenderableInk*)pCurrentNode); 00994 } 00995 00996 return TRUE; 00997 } 00998 delete pDefault; 00999 } 01000 } 01001 01002 01003 // otherwise we want a new line width attribute 01004 MILLIPOINT LineWidth = pAttrBrush->GetDefaultLineWidth(TRUE); 01005 01006 //DoApply makes a copy so we only need to make this local 01007 AttrLineWidth NewLineWidth; 01008 01009 NewLineWidth.Value.LineWidth = LineWidth; 01010 01011 // now apply it 01012 return DoApply(pCurrentNode, &NewLineWidth, FALSE, FALSE); 01013 01014 }
|
|
If we are applying a line width to a brushed node we need to tell the brush that it must scale to line width. We must also do an additional invalidate region so that if we are increasing in size then the brush will be rerendered properly.
Definition at line 921 of file attrappl.cpp. 00923 { 00924 ERROR2IF(pAttrBrush == NULL, FALSE, "Attribute pointer is NULL in OnApplyAttrib::ApplyLineWidthToBrush"); 00925 ERROR2IF(pBrushedNode == NULL, FALSE, "Node pointer is NULL in OnApplyAttrib::ApplyLineWidthToBrush"); 00926 ERROR2IF(pAttr == NULL, FALSE, "Attribute pointer is NULL in OnApplyAttrib::ApplyLineWidthToBrush"); 00927 00928 // if we are on a closed path then ask the PPB to even out the spacing 00929 PathProcessorBrush* pPPB = pAttrBrush->GetPathProcessor(); 00930 if (pPPB != NULL) 00931 { 00932 // scale to the new line width 00933 AttrLineWidth* pLineWidth = (AttrLineWidth*)pAttr; 00934 BOOL UsesPressure = pAttrBrush->GetPressureCache() != NULL; 00935 pPPB->ScaleToValue(pLineWidth->Value.LineWidth, !UsesPressure); 00936 pPPB->AdjustSpacingForClosedPath(pBrushedNode); 00937 } 00938 00939 return TRUE; 00940 }
|
|
When a new stroke colour is applied to a brushed object we wish to set the flag that tells the brush to override the named colours in the brush with the colour applied.
Definition at line 871 of file attrappl.cpp. 00872 { 00873 ERROR2IF(pAttrBrush == NULL, FALSE, "Attribute pointer is NULL in OnApplyAttrib::ApplyStrokeColourToBrush"); 00874 ERROR2IF(pBrushedNode == NULL, FALSE, "Attribute pointer is NULL in OnApplyAttrib::ApplyStrokeColourToBrush"); 00875 00876 00877 00878 00879 // if the brush already uses local colours then don't bother doing anything 00880 PathProcessorBrush *pPPB = pAttrBrush->GetPathProcessor(); 00881 if (pPPB == NULL) 00882 return TRUE; 00883 00884 if (pPPB->GetUseLocalFillColour() || !pPPB->GetUseNamedColours()) 00885 return TRUE; 00886 00887 // make the OpParam 00888 ChangeBrushOpParam Param; 00889 00890 Param.ChangeType = CHANGEBRUSH_USENAMEDCOL; 00891 Param.m_bNewUseNamed = FALSE; 00892 ChangeBrushAction* pAction = NULL; 00893 // initialise the action 00894 if (ChangeBrushAction::Init(this, &UndoActions, pBrushedNode, 00895 &Param, &pAction) == AC_FAIL) 00896 return FALSE; 00897 00898 return TRUE; 00899 }
|
|
When a transparency is applied to a brushed object we need to set a flag in the brush to tell it to use this new transparency.
Definition at line 838 of file attrappl.cpp. 00839 { 00840 ERROR2IF(pAttrBrush == NULL, FALSE, "Attribute pointer is NULL in OnApplyAttrib::ApplyTransparencyToBrush"); 00841 ERROR2IF(pBrushedNode == NULL, FALSE, "Attribute pointer is NULL in OnApplyAttrib::ApplyTransparencyToBrush"); 00842 00843 // make the OpParam 00844 ChangeBrushOpParam Param; 00845 00846 Param.ChangeType = CHANGEBRUSH_USELOCALTRANSP; 00847 Param.m_bNewUseLocalTransp = TRUE; 00848 ChangeBrushAction* pAction = NULL; 00849 // initialise the action 00850 if (ChangeBrushAction::Init(this, &UndoActions, pBrushedNode, &Param, &pAction) == AC_FAIL) 00851 return FALSE; 00852 00853 return TRUE; 00854 }
|
|
Will not apply the attribute to CurrentNode if it does not require it.
Definition at line 229 of file attrappl.cpp. 00237 { 00238 return SelOperation::DoApply(this, CurrentNode, Attrib, Mutate, InvalidateRegion, KeepExistingCols, TRUE, pbAttribWasRequired, pbCanDiscardUndo); 00239 }
|
|
Definition at line 241 of file attrappl.cpp. 00251 { 00252 BOOL AttributeExists = FALSE; // Until we find that the attribute does exist 00253 00254 CCRuntimeClass* AttrType = Attrib->GetAttributeType(); 00255 00256 ERROR3IF(!CurrentNode->IsAnObject(), "Trying to apply an attribute to a non-NodeRenderableInk"); 00257 00258 // We don't allow attributes like 'Quality' to be applied to objects directly. 00259 ERROR3IF(!(Attrib->CanBeAppliedToObject()), "Trying to apply an illegal attribute to the object"); 00260 00261 if (!(Attrib->CanBeAppliedToObject())) 00262 return TRUE; // Just pretend they ever tried. 00263 00264 Node* OriginalCurrentNode = CurrentNode; 00265 00266 if (CurrentNode->IsAnObject()) 00267 { 00268 00269 // Obtain the real object to apply the attribute to 00270 CurrentNode = ((NodeRenderableInk*)CurrentNode)->GetObjectToApplyTo(Attrib->GetAttributeType()); 00271 if (!CurrentNode) 00272 { 00273 ERROR3("OpApplyAttrib::DoApply, Unable to find object to apply to"); 00274 return TRUE; 00275 } 00276 } 00277 00278 // NOTE! Better to get the value of this flag here, now that GetObjectToApplyTo has been called 00279 BOOL bEffectRootOnly = (CurrentNode->IsAnObject() && ((NodeRenderableInk*)CurrentNode)->IsValidEffectAttr(Attrib)); 00280 00281 // If we are applying attributes to the Caret alone then the caller should not retain an undo record 00282 // for this operation... 00283 if (pbCanDiscardUndo) 00284 *pbCanDiscardUndo = *pbCanDiscardUndo && CurrentNode->DiscardsAttributeChildren(); 00285 00286 // BODGE! ------------------------------------------------------------ 00287 // Don't apply stroke transparency as an effect attribute - nothing 00288 // needs it. Test has to be done here because other objects in the 00289 // selection might need it... 00290 if (bEffectRootOnly && AttrType == CC_RUNTIME_CLASS(AttrStrokeTransp)) 00291 return TRUE; 00292 // END-BODGE! -------------------------------------------------------- 00293 00294 // Needed to support adding triggers, who can be multiply applied 00295 BOOL AddEvenIfMultiple = FALSE; 00296 00297 // Do not apply the attribute if CurrentNode does not require it 00298 if ((((NodeRenderableInk*)CurrentNode)->RequiresAttrib(Attrib))) 00299 { 00300 00301 if (pbAttribWasRequired) 00302 *pbAttribWasRequired = TRUE; 00303 00304 if (CurrentNode != OriginalCurrentNode) 00305 { 00306 // BODGE TEXT 00307 // We need to call AllowOp, for the TextStories benefit, 00308 // so that lines know they have been affected 00309 00310 ObjChangeFlags cFlags; 00311 cFlags.Attribute = TRUE; 00312 ObjChangeParam ObjChange(OBJCHANGE_STARTING, cFlags, NULL, pOp); 00313 00314 if (!CurrentNode->AllowOp(&ObjChange)) 00315 { 00316 // It's already passed the test once. 00317 ERROR3("Doing op when no nodes will allow it"); 00318 } 00319 } 00320 00321 // ----------------------------------------------------------------------------- 00322 // Determine if the current node already has an attribute which is the same 00323 // runtime class as Attrib. 00324 Node* n = CurrentNode->FindFirstChild(); 00325 Node* pLastBoundedNode = NULL; 00326 if (bEffectRootOnly) 00327 { 00328 pLastBoundedNode = CurrentNode->FindLastChild(CC_RUNTIME_CLASS(NodeRenderableBounded)); 00329 ERROR3IF(pLastBoundedNode==NULL, "Attempt to apply effect attr to node with no children"); 00330 00331 if (pLastBoundedNode) n = pLastBoundedNode->FindNext(); 00332 } 00333 00334 while (n && (n->IsOrHidesAnAttribute())) 00335 { 00336 // Now lets see if we can find an attribute of the same type 00337 // as the one we are interested in. 00338 if (n->IsAnAttribute()) 00339 { 00340 NodeAttribute* pNdAttr = (NodeAttribute*)n; 00341 00342 if( pNdAttr->GetAttributeType() == AttrType) 00343 { 00344 // Attributes are of the same type (whatever that might mean) 00345 00346 // Look for another attribute of the same Type if we're allowed more than 00347 // one per object 00348 BOOL LookForMultiple = FALSE; 00349 00350 if (Attrib->CanBeMultiplyApplied()) 00351 { 00352 // If the classID's are the same then we want to replace the old one 00353 // (unless they're identical) 00354 if (Attrib->GetAttributeClassID() == pNdAttr->GetAttributeClassID()) 00355 { 00356 LookForMultiple = FALSE; // stop looking now 00357 AddEvenIfMultiple = FALSE; // replace the old one 00358 } 00359 else 00360 { 00361 // they're not the same classID's then we'll add a new one 00362 // but keep looking for a duplicate 00363 LookForMultiple = TRUE; 00364 AddEvenIfMultiple = TRUE; 00365 } 00366 } 00367 00368 // Do the attributes have the same value ?. If they do then there is no point in 00369 // applying it a second time 00370 00371 // to have the same value they must share the same runtime class 00372 if (IS_SAME_CLASS(pNdAttr, Attrib)) 00373 { 00374 // Found an identical attribute, so ignore this apply 00375 if ((*pNdAttr)==(*Attrib)) 00376 return TRUE; // We are not failing, just doing nothing. 00377 00378 if (Attrib->IsABrush()) 00379 ((AttrBrushType*)Attrib)->OnReplaceAttribute((AttrBrushType*)pNdAttr); 00380 } 00381 00382 // if applying a brush attribute we must copy some data over 00383 if (!LookForMultiple) 00384 { 00385 AttributeExists = TRUE; 00386 break; 00387 } 00388 } 00389 } 00390 n = n->FindNext(); // Find next child of CurrentNode 00391 } 00392 00393 // >>>> Temporary BODGE to aid select-inside... 00394 // >>>> ALWAYS clear any attributes of the same type from the subtree (even if the 00395 // >>>> attribute just applied replaced an existing one) so that dubious 00396 // >>>> attribute states (due to this routine not dealing with Select-inside 00397 // >>>> properly yet) can be cleared. 00398 // >>>> NOTE! the current att (n) is passed in to DoRemoveAttTypeFromSubtree so 00399 // >>>> that it won't be deleted along with atts of the same type - that would be 00400 // >>>> (has been) disastrous! 00401 // Triggers can be multiply applied to groups, so we need to check CanBeMultiplyApplied 00402 if (CurrentNode->IsCompound() && !Attrib->CanBeMultiplyApplied() && !bEffectRootOnly) 00403 { 00404 // Remove all instances of attributes of the same type from the subtree. 00405 // This is not neccessary if the AttributeExists flag is TRUE because 00406 // we know in this situation that the subtree cannot contain any other 00407 // instances of the attribute !. 00408 if (pOp && !pOp->DoRemoveAttrTypeFromSubtree(CurrentNode, Attrib->GetAttributeType(), n)) 00409 { 00410 pOp->FailAndExecute(); // Just to make sure 00411 return FALSE; 00412 } 00413 } 00414 00415 // At this point we have Either ..... 00416 // 1. Found an attribute of the same type as the new one, and we will 00417 // now replace it. 00418 // 2. Found the specific attribute we were looking for and will replace 00419 // that. 00420 // 3. Found an attribute to mutate. 00421 // 4. Found no attribute of the correct type, indicating that it has 00422 // been factored out, and we need to put a new one in here. 00423 // 5. The attribute had CanBeMultiplyApplied() set, and no exact same 00424 // Attribute was found. 00425 // 00426 // Have we have got an Attribute to do something with ? 00427 NodeAttribute* AttribClone = NULL; 00428 if ( !AddEvenIfMultiple && n && n->IsAnAttribute()) 00429 { 00430 // Yes ! 00431 NodeAttribute* pAttr = (NodeAttribute*)n; 00432 00433 if (Mutate) 00434 { 00435 // Mutate it into the new type. 00436 AttribClone = ((AttrFillGeometry*)n)->Mutate((AttrFillGeometry*)Attrib, bOptimise); 00437 } 00438 else 00439 { 00440 // We're gunna just replace the attribute with the new one. 00441 00442 // First make a copy of the new attribute. 00443 if (pOp) 00444 ALLOC_WITH_FAIL(AttribClone ,((NodeAttribute*)Attrib->SimpleCopy()), pOp) 00445 else 00446 AttribClone = (NodeAttribute*)Attrib->SimpleCopy(); 00447 if (AttribClone == NULL) 00448 return FALSE; 00449 00450 // Complication !! 00451 // If we are replacing a Fill Attribute and the attribute we are replacing 00452 // is already filled, then we need to extract the colour of the existing 00453 // fill and use them for the new fill. 00454 if ( KeepExistingCols && ((NodeAttribute*)n)->IsAFillAttr() ) 00455 { 00456 AttrFillGeometry* NodeReplaced = (AttrFillGeometry*)n; 00457 00458 // Copy the old fill characteristics into the new Fill 00459 if (!OpApplyAttrib::KeepExistingCharacteristics(NodeReplaced, (AttrFillGeometry*)AttribClone)) 00460 return FALSE; 00461 } 00462 00463 if ( Attrib->IsATranspFill() && Attrib->IsAFlatFill()) 00464 { 00465 ((AttrFillGeometry*)n)->RenderFillBlobs(); 00466 } 00467 } 00468 00469 // If Mutate returned NULL, which means the Mutate 00470 // did nothing, we should return TRUE, which will move 00471 // onto the next object. 00472 if (AttribClone == NULL) 00473 return TRUE; 00474 00475 // ---------------------------------------------------------- 00476 // If we have just set an effect attribute then we can avoid releasing 00477 // cached info of the specified node and all its children... 00478 // 00479 // We RELY on invalidations associated with this function not 00480 // calling ReleaseCached themselves! 00481 // 00482 ReleaseCachedForAttrApply((NodeRenderableBounded*)CurrentNode, bEffectRootOnly); 00483 // ---------------------------------------------------------- 00484 00485 if (InvalidateRegion) 00486 { 00487 // Invalidate the Object before the attribute is applied 00488 if (!InvalidateNodeRegion(pOp, (NodeRenderableBounded*)CurrentNode, Attrib, Mutate)) // Doesn't invalidate cached info! 00489 return FALSE; 00490 } 00491 00492 // Now we have done with the old attribute, so lets hide it, so 00493 // the changes can be undone 00494 // 00495 // Don't write any undo info if we don't have an op or the node 00496 // discards attributes by itself 00497 if (pOp && !CurrentNode->DiscardsAttributeChildren()) 00498 { 00499 // Note that we wouldn't need this test and we wouldn't need 00500 // to use the HideNode/ShowNode actions here if solid fill 00501 // dragging used OpApplyAttrInteractive. Instead it uses an 00502 // older system which relies on the HideNodeAction recording 00503 // a pointer to an attribute at the start of the drag which 00504 // is subsequently updated during the drag. 00505 if (pOp->IsKindOf(CC_RUNTIME_CLASS(OpApplyAttrInteractive))) 00506 { 00507 ApplyAction* pUndoApply; 00508 // Create an action to re-apply the attribute when we undo 00509 if ( ApplyAction::Init(pOp, 00510 pOp->GetUndoActionList(), 00511 CurrentNode, 00512 pAttr, 00513 TRUE, // When the attribute gets hidden we 00514 // must include its size 00515 (Action**)(&pUndoApply)) 00516 == AC_FAIL) 00517 { 00518 return FALSE; 00519 } 00520 pAttr->CascadeDelete(); 00521 delete pAttr; 00522 pAttr = NULL; 00523 } 00524 else 00525 { 00526 if (!pOp->DoHideNode(n, TRUE)) // Include the subtree size 00527 return FALSE; 00528 } 00529 } 00530 else 00531 { 00532 pAttr->CascadeDelete(); 00533 delete pAttr; 00534 pAttr = NULL; 00535 } 00536 00537 } 00538 else // if (n != NULL) 00539 { 00540 // We've not found an attribute to replace, so we'll have to put 00541 // a new one in 00542 NodeAttribute* TempAttr = NULL; 00543 00544 BOOL FoundAttr = ((NodeRenderableInk*)CurrentNode)-> 00545 FindAppliedAttribute(Attrib->GetAttributeType(), &TempAttr); 00546 00547 if (!FoundAttr || TempAttr == NULL) 00548 return FALSE; 00549 00550 if (Mutate) 00551 { 00552 AttribClone = ((AttrFillGeometry*)TempAttr)->Mutate((AttrFillGeometry*)Attrib, bOptimise); 00553 } 00554 else 00555 { 00556 // We'll just put a copy of our attribute in the tree. 00557 if (pOp) 00558 ALLOC_WITH_FAIL(AttribClone ,((NodeAttribute*)Attrib->SimpleCopy()), pOp) 00559 else 00560 AttribClone = (NodeAttribute*)Attrib->SimpleCopy(); 00561 00562 if ( KeepExistingCols && (TempAttr->IsAFillAttr()) ) 00563 { 00564 AttrFillGeometry* NodeReplaced = (AttrFillGeometry*)TempAttr; 00565 00566 // Copy the old fill characteristics into the new Fill 00567 if (!OpApplyAttrib::KeepExistingCharacteristics(NodeReplaced, (AttrFillGeometry*)AttribClone)) 00568 return FALSE; 00569 } 00570 00571 if (Attrib->IsATranspFill() && Attrib->IsAFlatFill()) 00572 { 00573 // If we are mutating into a flat fill, then we need 00574 // to make sure we remove any existing fill blobs. 00575 ((AttrFillGeometry*)TempAttr)->RenderFillBlobs(); 00576 } 00577 } 00578 00579 if (AttribClone) 00580 { 00581 ReleaseCachedForAttrApply((NodeRenderableBounded*)CurrentNode, bEffectRootOnly); 00582 00583 if (InvalidateRegion) 00584 { 00585 // Make sure the node is redrawn 00586 if (!InvalidateNodeRegion(pOp, (NodeRenderableBounded*)CurrentNode, Attrib, Mutate)) // Doesn't invalidate cached info! 00587 return FALSE; 00588 } 00589 } 00590 } 00591 00592 // If the AttribClone has the same value as an applied attribute 00593 // (A default attr if the attribs have been localised). Then we don't want to apply it ! 00594 if (AttribClone && AttribClone->ShouldBeOptimized() && !bEffectRootOnly && bOptimise) 00595 { 00596 NodeAttribute* pAppliedAttr; 00597 if (((NodeRenderableInk*)CurrentNode)->FindAppliedAttribute(AttribClone->GetAttributeType(), 00598 &pAppliedAttr)) 00599 { 00600 // Do the attributes have the same value ? 00601 if ((IS_SAME_CLASS(AttribClone, pAppliedAttr))) 00602 { 00603 if ((*AttribClone)==(*pAppliedAttr)) 00604 { 00605 AttribClone->CascadeDelete(); // Delete the attribute 00606 00607 // If attribute affect's the bounds of the object (eg. a LineWidth) then invalidate the 00608 // bounds of the object 00609 00610 if (pAppliedAttr->EffectsParentBounds()) 00611 { 00612 ((NodeRenderableBounded*)CurrentNode)->InvalidateBoundingRect(TRUE); 00613 } 00614 00615 delete AttribClone; 00616 AttribClone = NULL; 00617 } 00618 } 00619 } 00620 } 00621 00622 // Effect attributes don't optimise so if the value of this is the 00623 // same as the default value we should not add it here 00624 // 00625 if (AttribClone && bEffectRootOnly && AttribClone->HasEquivalentDefaultValue() && bOptimise) 00626 { 00627 // Just allow the attribute to be hidden 00628 AttribClone->CascadeDelete(); // Delete the attribute 00629 delete AttribClone; 00630 AttribClone = NULL; 00631 } 00632 00633 if (AttribClone) 00634 { 00635 // Finally !! We can add the new attribute node into the tree. 00636 if (bEffectRootOnly) 00637 AttribClone->AttachNode(pLastBoundedNode, NEXT); 00638 else 00639 AttribClone->AttachNode(CurrentNode, FIRSTCHILD); 00640 00641 AttributeManager::pLastNodeAppliedTo = (NodeRenderableInk*)CurrentNode; 00642 00643 // And now it's in the tree, we need to make sure that any fill control 00644 // points are valid. 00645 if (AttribClone->IsAFillAttr()) 00646 { 00647 ((AttrFillGeometry*)AttribClone)->AttributeChanged(); 00648 } 00649 00650 if (pOp && !CurrentNode->DiscardsAttributeChildren()) 00651 { 00652 // Note that we wouldn't need this test and we wouldn't need 00653 // to use the HideNode/ShowNode actions here if solid fill 00654 // dragging used OpApplyAttrInteractive. Instead it uses an 00655 // older system which relies on the HideNodeAction recording 00656 // a pointer to an attribute at the start of the drag and the 00657 // contents of the attribute being updated during the drag. 00658 if (pOp->IsKindOf(CC_RUNTIME_CLASS(OpApplyAttrInteractive))) 00659 { 00660 UnApplyAction* pUndoApply; 00661 // Create an action to hide the attribute when we undo 00662 if ( UnApplyAction::Init(pOp, 00663 pOp->GetUndoActionList(), 00664 CurrentNode, 00665 AttribClone, 00666 TRUE, // When the attribute gets hidden we 00667 // must include its size 00668 (Action**)(&pUndoApply)) 00669 == AC_FAIL) 00670 { 00671 AttribClone->CascadeDelete(); 00672 delete (AttribClone); 00673 return FALSE; 00674 } 00675 } 00676 else 00677 { 00678 HideNodeAction* UndoHideNodeAction; 00679 // Create an action to hide the attribute when we undo 00680 if ( HideNodeAction::Init(pOp, 00681 pOp->GetUndoActionList(), 00682 AttribClone, 00683 TRUE, // When the attribute gets hidden we 00684 // must include its size 00685 (Action**)(&UndoHideNodeAction)) 00686 == AC_FAIL) 00687 { 00688 AttribClone->CascadeDelete(); 00689 delete (AttribClone); 00690 return FALSE; 00691 } 00692 } 00693 } 00694 00695 } 00696 00697 ReleaseCachedForAttrApply((NodeRenderableBounded*)CurrentNode, bEffectRootOnly); 00698 00699 if (InvalidateRegion) 00700 { 00701 // Invalidate the node rectangle, now the new attr has been applied 00702 if (!InvalidateNodeRegion(pOp, (NodeRenderableBounded*)CurrentNode, Attrib, Mutate)) // Doesn't invalidate cached info! 00703 return FALSE; 00704 } 00705 } 00706 00707 // we may have to apply this to a brushed node 00708 if (pOp) // TODO: Make this work when no undo op specified? 00709 { 00710 if (!pOp->ApplyAttributeToBrush(CurrentNode, Attrib)) 00711 return FALSE; 00712 } 00713 return TRUE; // success 00714 }
|
|
Performs the OpApplyAttribsToSelected operation. This tries to apply the list of attributes in the OpParam->AttribsToApplyList to the selection. If no attribute can be applied then the operation does not generate any actions, and so will be a NOP and be destroyed during End().
OpParam->undoAttribStrID: Specifies the undo string to display (eg. Paste Atrributes)
Whenever an attribute is applied to an object, the Current AttributeGroup associated with the object is added to the attributes set of current attribute groups. Therefore if an attribute's set is empty then we know that the attribute has not been applied. OpParam->Success: FALSE if the operation failed. i.e. FailAndExecute() was called. anyAttrsApplied: FALSE if the operation has not applied any attributes This Operation currently does not support mutation Definition at line 2388 of file attrappl.cpp. 02389 { 02390 // Ensure that the OpParam is valid 02391 ERROR3IF(!pOpParam, "No parameters passed to OpApplyAttribsToSelected"); 02392 ApplyAttribsToSelectedParam* pParam = (ApplyAttribsToSelectedParam*)pOpParam; 02393 // get inputs 02394 List* pAttrsToApply = pParam->AttribsToApply; 02395 // m_pAttribList = pAttrsToApply; 02396 02397 // UndoAttribStrID = pParam->UndoAttribStrID; // TODO: Fix this? 02398 02399 // and outputs 02400 List* AttrGroupList = pParam->AttrGroupList; 02401 ERROR3IF(!(AttrGroupList->IsEmpty()), 02402 "AttributeGroupList not empty on entry to OpApplyAttribsToSelected"); 02403 BOOL* Success = pParam->Success; 02404 *Success = FALSE; // Let's be pessimistic 02405 BOOL* AppliedAttrs = pParam->AnyAttrsApplied; 02406 *AppliedAttrs = FALSE; 02407 BOOL bAnyApplied = FALSE; 02408 BOOL bWeStartedThisOp = FALSE; 02409 02410 // Create a stable range of objects to apply to 02411 Range SelRng(*(GetApplication()->FindSelection())); 02412 02413 // We need two sets of attribute types 02414 // one for Line level attributes, and one for non Line level attributes. This is because the localise 02415 // and factor out routines require each attribute in the set to be all applicable to the same 02416 // object. This would not be true if our set contained a BOLD, and a LINE_SPACING attribute for example. 02417 02418 // Make our attribute type sets 02419 AttrTypeSet LineLevelAttrTypes; 02420 AttrTypeSet OtherAttrTypes; 02421 NodeAttributePtrItem* pAttrItem = (NodeAttributePtrItem*)(pAttrsToApply->GetHead()); 02422 NodeAttribute* pAttr; 02423 AttrTypeSet* SetToAddTo; 02424 while (pAttrItem) 02425 { 02426 pAttr = pAttrItem->NodeAttribPtr; 02427 ERROR3IF(!pAttr, "Should be an attribute"); 02428 if (pAttr->IsALineLevelAttrib()) 02429 SetToAddTo = &LineLevelAttrTypes; 02430 else 02431 SetToAddTo = &OtherAttrTypes; 02432 02433 if (!SetToAddTo->AddToSet(pAttr->GetAttributeType())) 02434 { 02435 FailAndExecute(); 02436 goto EndOperation; 02437 } 02438 pAttrItem = (NodeAttributePtrItem*)(pAttrsToApply->GetNext(pAttrItem)); 02439 } 02440 02441 // ----------------------------------------------------------- 02442 if (SelRng.FindFirst()!=NULL) 02443 { 02444 SelRange* Sel; 02445 ObjChangeFlags cFlags; 02446 cFlags.Attribute = TRUE; 02447 ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this); 02448 02449 Sel = GetApplication()->FindSelection(); 02450 02451 if (!Sel->AllowOp(&ObjChange)) 02452 { 02453 FailAndExecute(); 02454 goto EndOperation; 02455 } 02456 } 02457 02458 if (!GetStarted()) 02459 { 02460 if (!DoStartSelOp(FALSE,FALSE, TRUE,TRUE)) // Try to record the selection state , don't 02461 // render the blobs though 02462 goto EndOperation; 02463 02464 bWeStartedThisOp = TRUE; 02465 } 02466 02467 // Make a stable range 02468 // Range SelRng(*(GetApplication()->FindSelection())); 02469 02470 // Invalidate objects regions (include blobs because this may be neccessary, 02471 // there is little overhead anyway). 02472 if (!DoInvalidateNodesRegions(SelRng, TRUE, FALSE)) 02473 goto EndOperation; 02474 02475 // Before we apply the attribute to the selection we must localise all attributes 02476 // with the same type that we are going to apply. If we don't do this then the 02477 // tree will be left in an invalid state. 02478 02479 if (!LineLevelAttrTypes.IsEmpty() && SelRng.FindFirst()!=NULL) 02480 { 02481 if (!DoLocaliseForAttrChange(&SelRng, &LineLevelAttrTypes)) 02482 goto EndOperation; 02483 } 02484 02485 if (!OtherAttrTypes.IsEmpty() && SelRng.FindFirst()!=NULL) 02486 { 02487 if (!DoLocaliseForAttrChange(&SelRng, &OtherAttrTypes)) 02488 goto EndOperation; 02489 } 02490 02491 // ----------------------------------------------------------- 02492 if (!DoApplyToSelection(pAttrsToApply, AttrGroupList, &bAnyApplied)) 02493 { 02494 goto EndOperation; 02495 } 02496 02497 // ----------------------------------------------------------- 02498 // If attributes were applied we must factor them out 02499 if (bAnyApplied) 02500 { 02501 // Having applied the attributes, we must now try and factor out the newly 02502 // applied attributes 02503 if (!LineLevelAttrTypes.IsEmpty()) 02504 { 02505 if (!DoFactorOutAfterAttrChange(&SelRng, 02506 &LineLevelAttrTypes)) 02507 { 02508 goto EndOperation; 02509 } 02510 } 02511 02512 if (!OtherAttrTypes.IsEmpty()) 02513 { 02514 if (!DoFactorOutAfterAttrChange(&SelRng, 02515 &OtherAttrTypes)) 02516 { 02517 goto EndOperation; 02518 } 02519 } 02520 02521 { 02522 ObjChangeFlags cFlags; 02523 cFlags.Attribute = TRUE; 02524 02525 ObjChangeParam ObjChange(OBJCHANGE_FINISHED,cFlags,NULL,this); 02526 if (!UpdateChangedNodes(&ObjChange)) 02527 { 02528 FailAndExecute(); 02529 goto EndOperation; 02530 } 02531 } 02532 02533 // Invalidate after 02534 if (!DoInvalidateNodesRegions(SelRng, TRUE, FALSE)) 02535 { 02536 goto EndOperation; 02537 } 02538 } 02539 else if (bClearIfNoneApplied) 02540 { 02541 // We applied no attributes so we can just chuck this undo record 02542 // and all its actions away 02543 SucceedAndDiscard(); 02544 } 02545 02546 // Output values 02547 *Success = TRUE; // If we got here we must have succeeded 02548 *AppliedAttrs = bAnyApplied; // Tell caller if any attributes were applied 02549 02550 EndOperation: 02551 02552 // Delete our lists of attribute types 02553 LineLevelAttrTypes.DeleteAll(); 02554 OtherAttrTypes.DeleteAll(); 02555 02556 if (bWeStartedThisOp) 02557 End(); 02558 02559 return *Success; 02560 }
|
|
Whenever an attribute is applied to an object, the Current AttributeGroup associated with the object is added to the attributes set of current attribute groups. Therefore if an attribute's set is empty then we know that the attribute has not been applied.
Definition at line 2594 of file attrappl.cpp. 02595 { 02596 ERROR3IF(!(AttrGroupList->IsEmpty()), "Invalid output param"); 02597 02598 // Set up a range of all selected nodes 02599 SelRange* pSel = GetApplication()->FindSelection(); 02600 EffectsStack* pStack = pSel->GetEffectsStack(FALSE, FALSE); // Get cached stack, don't escape derived objects (allow attrs to be applie to derived objects) 02601 ERROR3IF(pStack==NULL, "Failed to get PPStack in ApplyToSelection"); 02602 INT32 stackpos = STACKPOS_TOP; 02603 Range* pLevel = pStack->GetLevelRange(&stackpos, FALSE); // Don't escape old controllers, apply attr to base nodes 02604 02605 BOOL bCanDiscardUndo = TRUE; 02606 02607 NodeAttributePtrItem* pAttrItem = (NodeAttributePtrItem*)(Attribs->GetHead()); 02608 while (pAttrItem) 02609 { 02610 NodeAttribute* pAttr = pAttrItem->NodeAttribPtr; 02611 02612 // Create the pAttr's set of current attribute groups { currently empty } 02613 ListListItem* pAttrsSetItem = new ListListItem; 02614 if (!pAttrsSetItem) 02615 goto Failed; 02616 List* pAttrsSet = &(pAttrsSetItem->list); 02617 AttrGroupList->AddTail(pAttrsSetItem); 02618 02619 // While there are still nodes to apply the attribute to 02620 Node* CurrentNode = pLevel->FindFirst(); 02621 // Node* FirstNode = CurrentNode; 02622 while (CurrentNode) 02623 { 02624 NodeAttribute* AttrToApply = pAttr; 02625 BOOL AppliedAttribIsCopy = FALSE; 02626 BOOL ThisAttrWasRequired = FALSE; 02627 if (pAttr->IsAFillAttr()) 02628 { 02629 // Transform the attribute to fit the node's bounds 02630 DocRect NodeBounds = ((NodeRenderableInk*)CurrentNode)->GetBoundingRect(TRUE); 02631 // We will transform a copy of the attribute. 02632 AttrToApply = (NodeAttribute*)(pAttr->SimpleCopy()); 02633 AppliedAttribIsCopy = TRUE; // cos it is 02634 if (!AttrToApply) 02635 goto Failed; 02636 AttrToApply->TransformToNewBounds(NodeBounds); 02637 } 02638 02639 if (!DoApply(CurrentNode, 02640 AttrToApply, 02641 FALSE, // Don't mutate 02642 FALSE, // Don't invalidate region 02643 FALSE, // Don't keep existing characteristics 02644 &ThisAttrWasRequired, 02645 &bCanDiscardUndo)) 02646 { 02647 goto Failed; 02648 } 02649 02650 if (ThisAttrWasRequired) 02651 { 02652 *pAttribWasRequired = TRUE; 02653 02654 // This next bit is a bit yucky, we are in desperate need of templates to implement 02655 // proper sets. 02656 // The attribute was required by the object 02657 // Add the current attribute group associated with the object to the attributes set 02658 // Search the pAttrsSet set to see if it's already there 02659 02660 CCRuntimeClass* NewAttrGroup = ((NodeRenderableInk*)CurrentNode)->GetCurrentAttribGroup(); 02661 ERROR3IF(NewAttrGroup == NULL, "Object has a NULL attribute group"); 02662 BOOL InSet = FALSE; 02663 AttributeGroupItem* pAttrGrpItem = (AttributeGroupItem*)pAttrsSet->GetHead(); 02664 while(pAttrGrpItem != NULL) 02665 { 02666 CCRuntimeClass* InSetAttrGroup = pAttrGrpItem->AttrGroup; 02667 ERROR3IF(InSetAttrGroup == NULL, "NULL attribute group found"); 02668 if (NewAttrGroup == InSetAttrGroup) 02669 { 02670 InSet = TRUE; 02671 break; // It's already in the set don't add it 02672 } 02673 pAttrGrpItem = (AttributeGroupItem*)pAttrsSet->GetNext(pAttrGrpItem); 02674 } 02675 02676 if (!InSet) // The AttrGroup needs adding to the pAttrsSet 02677 { 02678 // Create a new AttrGroupItem 02679 pAttrGrpItem = new AttributeGroupItem(); 02680 if (!pAttrGrpItem) 02681 goto Failed; 02682 02683 pAttrGrpItem->AttrGroup = NewAttrGroup; 02684 02685 // And add it to our set 02686 pAttrsSet->AddHead(pAttrGrpItem); 02687 } 02688 } 02689 02690 if (CurrentNode->IsAnObject()) 02691 ((NodeRenderableInk*)CurrentNode)->InvalidateBoundingRect(); 02692 02693 CurrentNode = pLevel->FindNext(CurrentNode); 02694 if (AppliedAttribIsCopy) 02695 { 02696 delete AttrToApply; // not required 02697 AttrToApply = NULL; 02698 } 02699 } 02700 ContinueSlowJob(); 02701 pAttrItem = (NodeAttributePtrItem*)(Attribs->GetNext(pAttrItem)); 02702 } 02703 02704 // If all nodes report DiscardsAttributeChildren() = TRUE 02705 // Then we can abandon the entire Op once it's finished 02706 if (bCanDiscardUndo) 02707 SucceedAndDiscard(); 02708 02709 return TRUE; 02710 02711 Failed: 02712 // Tidyup, and return FALSE 02713 AttrGroupList->DeleteAll(); 02714 return FALSE; 02715 }
|
|
This high level function should be called whenever we need to apply multiple attributes to the selection (eg. PasteAttributes).
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'
If no nodes are selected then the attributes may become current depending on the preferences and what the user decides.
Definition at line 2779 of file attrmgr.cpp. 02780 { 02781 // The AttributeList cannot be empty 02782 ERROR3IF(AttribsToApply.IsEmpty(), "No attributes to apply in AttributeManager::AttributesSelected"); 02783 if (AttribsToApply.IsEmpty()) return FALSE; // nothing to do 02784 02785 // If there is no current document then there is very little we can do 02786 Document* CurrentDoc = Document::GetSelected(); 02787 if (CurrentDoc == NULL) 02788 return TRUE; // We are not going to be able to do anything if there is no document 02789 02790 SelRange* Sel = GetApplication()->FindSelection(); 02791 ERROR3IF(Sel==NULL,"Can't find SelRange!"); 02792 if (Sel==NULL) return TRUE; 02793 02794 // If there are no objects in the selection, or if none of the selected objects require 02795 // the attribute, then it will not be applied 02796 02797 List AttrGroupsList; // Will contain a list of current Attribute group sets. one for each attribute 02798 // in the AttribsToApply list. Each item in this list will be a ListListItem. 02799 02800 BOOL Success; // FALSE if the operation fails 02801 BOOL AnyAttrsApplied; // FALSE if the operation has not applied any attributes 02802 02803 // Build the parameter we are about to pass to the operation 02804 ApplyAttribsToSelectedParam OpParam(&AttribsToApply, 02805 OpName, 02806 &AttrGroupsList, // One per attribute applied 02807 &Success, // Indicates if op was successful 02808 &AnyAttrsApplied); // Indicates if the operation applied 02809 // any attributes 02810 02811 02812 // Invoke the core of the operation 02813 DoApplyAttribsToSelection(&OpParam, !GetStarted()); // Don't clear actions if the caller already called DoStartSelOp 02814 02815 if (Success) 02816 { 02817 // Inform neccessary parties 02818 if (AnyAttrsApplied) 02819 { 02820 // Inform the selection that attributes have changed 02821 Sel->AttrsHaveChanged(); 02822 02823 // We've probably changed a Colour 02824 BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::COLOURATTCHANGED)); 02825 // and the Attrib may have changed shape or summit. Who knows ? 02826 BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::NONCOLOURATTCHANGED)); 02827 Sel->UpdateBounds(); 02828 } 02829 02830 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 02831 // Now decide which attributes in the AttribsToApply list should be made current 02832 02833 AttributeManager& AttrMgr = CurrentDoc->GetAttributeMgr(); 02834 AttributeManager::AttrsToMakeCurrent AttribsToMakeCurrent = AttrMgr.GetAttributesToMakeCurrent(AttribsToApply, 02835 AttrGroupsList, 02836 bPasteAttrs); 02837 02838 if( AttribsToMakeCurrent == AttributeManager::NONE ) 02839 { 02840 // Allow fill tools to update after a cancel 02841 // I'm not sure if we need this ???? Ask Will 02842 BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::NONCOLOURATTCHANGED)); 02843 } 02844 else 02845 { 02846 BOOL AttributeApplied; 02847 NodeAttributePtrItem* pAttr = (NodeAttributePtrItem*)(AttribsToApply.GetHead()); 02848 ListListItem* pAttrsGroups = (ListListItem*) (AttrGroupsList.GetHead()); 02849 while (pAttr) 02850 { 02851 AttributeApplied = (!(pAttrsGroups->list.IsEmpty())); // Empty Current attribute group list 02852 if (!AttributeApplied || (AttribsToMakeCurrent == AttributeManager::ALL)) 02853 { 02854 // Add attribute to all current attribute groups in the list, or to the 02855 // group associated with the current tool if the list is empty. 02856 AttributeManager::UpdateCurrentAttr(pAttr->NodeAttribPtr, 02857 FALSE, // Not a mutator 02858 &(pAttrsGroups->list), 02859 FALSE); // Don't tell world yet (too slow) 02860 } 02861 pAttr = (NodeAttributePtrItem*)(AttribsToApply.GetNext(pAttr)); 02862 pAttrsGroups = (ListListItem*)(AttrGroupsList.GetNext(pAttrsGroups)); 02863 } 02864 // Tell world current attributes have changed 02865 BROADCAST_TO_ALL(CurrentAttrChangedMsg()); 02866 } 02867 } 02868 // Tidyup 02869 AttrGroupsList.DeleteAll(); // Delete all group lists 02870 02871 // And ensure that if we've caused the SelRange to set up any delayed message 02872 // broadcasts, that it sends them now rather than at some random time in the future 02873 // when some Op just happens to end. 02874 Sel->BroadcastAnyPendingMessages(); 02875 02876 return Success; 02877 }
|
|
This function gets called automatically by End().
Scope: protected
Definition at line 306 of file selop.cpp. 00307 { 00308 // Create a SelectionState object 00309 ALLOC_WITH_FAIL(SelState, (new SelectionState()), this); 00310 if (SelState == NULL) 00311 { 00312 return FALSE; // Failure 00313 } 00314 00315 // We have managed to create a SelectionState instance, now lets try and 00316 // record the current selections 00317 00318 BOOL Success; 00319 00320 CALL_WITH_FAIL(SelState->Record(), this, Success) 00321 00322 if (!Success) // We failed to allocate enough memory to store the selection state 00323 { 00324 // There was insufficient memory to record the selections 00325 delete SelState; // Delete the selection state 00326 SelState = NULL; 00327 return FALSE; 00328 } 00329 00330 // We have successfully managed to create a Selection state, create an action 00331 // to restore the selections when executed 00332 00333 // Recorded the current selection state ok 00334 RestoreSelectionsAction* RestoreAct; 00335 ActionCode ActCode; 00336 00337 // Attempt to initialise the action 00338 ActCode = RestoreSelectionsAction::Init(this, 00339 &UndoActions, 00340 SelState, 00341 FALSE, // Don't Toggle 00342 FALSE, 00343 FALSE, // The SelState is not shared 00344 UndoRenderStartSelStateBlobs, 00345 UndoRenderEndSelStateBlobs, 00346 TRUE, // restore at start of undo 00347 ( Action**)(&RestoreAct)); 00348 if (ActCode == AC_FAIL) 00349 { 00350 delete SelState; // We won't be needing this 00351 return FALSE; 00352 } 00353 00354 // OK the operation should have finished playing with the selection states, so we can turn 00355 // the blob rendering back on. If the operation needs to render the end SelState blobs then 00356 // this is done. 00357 00358 // If the operation needs to restore the blobs then do so 00359 00360 #if !defined(EXCLUDE_FROM_RALPH) 00361 if (RenderEndSelStateBlobs) 00362 { 00363 ENSURE(Camelot.FindSelection() != NULL, "There is no SelRange"); 00364 Node* SelNd = Camelot.FindSelection()->FindFirst(); 00365 if (SelNd != NULL) 00366 { 00367 Spread* SelSpread = (Spread*) SelNd->FindParent(CC_RUNTIME_CLASS(Spread)); 00368 ENSURE(SelSpread != NULL, "Could not find spread of selected item"); 00369 00370 // Put the blobs back 00371 Camelot.GetBlobManager()->RenderOn(NULL, SelSpread); 00372 } 00373 } 00374 #endif 00375 00376 m_bStartCalled = FALSE; 00377 return TRUE; 00378 }
|
|
This function must be called by all SelOperations. It does the following:.
RenderStartSelBlobs: Flag indicating if the blobs should be drawn for the start selection state or not. This flag should be set to TRUE if the bounds of all selected objects at the start of an operation are not invalidated. All operations which insert a new object into the tree will have RenderStartSelBlobs set to TRUE.
Definition at line 201 of file selop.cpp. 00205 { 00206 SelOperation::RenderStartSelStateBlobs = renderStartSelBlobs; 00207 SelOperation::RenderEndSelStateBlobs = renderEndSelStateBlobs; 00208 00209 if (UndorenderEndSelStateBlobs) 00210 SelOperation::UndoRenderEndSelStateBlobs = !renderEndSelStateBlobs; 00211 else 00212 SelOperation::UndoRenderEndSelStateBlobs = renderEndSelStateBlobs; 00213 00214 if (UndorenderStartSelBlobs) 00215 SelOperation::UndoRenderStartSelStateBlobs = !renderStartSelBlobs; 00216 else 00217 SelOperation::UndoRenderStartSelStateBlobs = renderStartSelBlobs; 00218 00219 // Create a SelectionState object 00220 ALLOC_WITH_FAIL(SelState, (new SelectionState()), this); 00221 if (SelState == NULL) 00222 { 00223 return FALSE; // Failure 00224 } 00225 00226 // We have managed to create a SelectionState instance, now lets try and 00227 // record the current selections 00228 00229 BOOL Success; 00230 00231 CALL_WITH_FAIL(SelState->Record(), this, Success) 00232 00233 if (!Success) // We failed to allocate enough memory to store the selection state 00234 { 00235 // There was insufficient memory to record the selections 00236 delete SelState; // Delete the selection state 00237 SelState = NULL; 00238 return FALSE; 00239 } 00240 00241 // We have successfully managed to create a Selection state, create an action 00242 // to restore the selections when executed 00243 00244 // Recorded the current selection state ok 00245 RestoreSelectionsAction* RestoreAct; 00246 ActionCode ActCode; 00247 00248 // Attempt to initialise the action 00249 ActCode = RestoreSelectionsAction::Init(this, 00250 &UndoActions, 00251 SelState, 00252 FALSE, // Don't Toggle 00253 FALSE, 00254 FALSE, // The SelState is not shared 00255 UndoRenderStartSelStateBlobs, // Render the start blobs ? 00256 UndoRenderEndSelStateBlobs, // Render the end blobs ? 00257 FALSE, // End restore 00258 ( Action**)(&RestoreAct)); 00259 00260 00261 #if !defined(EXCLUDE_FROM_RALPH) 00262 if (RenderEndSelStateBlobs) 00263 { 00264 // Remove all existing blobs 00265 ENSURE(Camelot.FindSelection() != NULL, "There is no SelRange"); 00266 Node* SelNd = Camelot.FindSelection()->FindFirst(); 00267 if (SelNd != NULL) 00268 { 00269 Spread* SelSpread = (Spread*) SelNd->FindParent(CC_RUNTIME_CLASS(Spread)); 00270 ENSURE(SelSpread != NULL, "Could not find spread of selected item"); 00271 00272 // Remove the blobs 00273 Camelot.GetBlobManager()->RenderOff(NULL, SelSpread); 00274 } 00275 } 00276 #endif 00277 00278 if (ActCode == AC_FAIL) 00279 { 00280 delete SelState; // We won't be needing this 00281 return FALSE; 00282 } 00283 m_bStartCalled = TRUE; 00284 return TRUE; 00285 }
|
|
Calls DoEndSelOp(), then Operation::End().
Reimplemented from Operation. Reimplemented in OpAsynchClipartImport. Definition at line 398 of file selop.cpp. 00399 { 00400 if (OpStatus == DO && (!OpFlags.Failed)) 00401 { 00402 DoEndSelOp(); // We don't want to perform this if we are undoing or 00403 } 00404 Operation::End(); 00405 }
|
|
Reimplemented from UndoableOperation. Definition at line 139 of file selop.h. 00139 { return m_bStartCalled; }
|
|
Definition at line 1092 of file attrappl.cpp. 01096 { 01097 // Include the blobs, if the attribute will change the parents bounds. 01098 BOOL IncludeBlobs = Attrib->EffectsParentBounds(); 01099 01100 if ( (Mutate && !Attrib->IsAValueChange()) || 01101 Attrib->GetRuntimeClass() == CC_RUNTIME_CLASS(AttrBitmapDpiChange) ) 01102 { 01103 // Check for special cases of, either a mutate from one fill type to another, 01104 // or a dpi change. Both of these can change the blob bounds. 01105 IncludeBlobs = TRUE; 01106 } 01107 01108 // Invalidate the bounds of the node, including the blobs if necessary. 01109 if (pOp) 01110 { 01111 if (!pOp->DoInvalidateNodeRegion(CurrentNode, IncludeBlobs, FALSE, FALSE, FALSE)) // NOTE! We do not release cached info! 01112 // Must be used in conjunction with ApplyToSelection 01113 { 01114 // Summit went wrong. 01115 return FALSE; 01116 } 01117 } 01118 else 01119 { 01120 BaseDocument* pBaseDoc = CurrentNode->FindOwnerDoc(); 01121 if (pBaseDoc && pBaseDoc->IsKindOf(CC_RUNTIME_CLASS(Document))) 01122 { 01123 Document* pDoc = (Document*)pBaseDoc; 01124 Spread* pSpread = (Spread*)CurrentNode->FindParent(CC_RUNTIME_CLASS(Spread)); 01125 DocRect TempRect; 01126 TempRect = (IncludeBlobs ? 01127 (CurrentNode->GetUnionBlobBoundingRect()): 01128 (CurrentNode->GetBoundingRect()) 01129 ); 01130 TempRect = TempRect.Union(CurrentNode->GetEffectStackBounds()); 01131 pDoc->ForceRedraw(pSpread, TempRect, TRUE, CurrentNode, FALSE); 01132 } 01133 } 01134 01135 return TRUE; // All ok 01136 }
|
|
|
If we have just set an effect attribute then we can avoid releasing cached info of the specified node and all its children... We RELY on invalidations associated with this function not calling ReleaseCached themselves!
Definition at line 737 of file attrappl.cpp. 00738 { 00739 if (bEffectRootOnly) 00740 pNode->ReleaseCached(TRUE, FALSE, FALSE, TRUE); // Parents and Derived data only 00741 else 00742 pNode->ReleaseCached(); // Self, Parents, Children and derived data 00743 00744 return TRUE; 00745 }
|
|
|
|
|
|
|
|
|
|
|
|
|