// $Id: ngscan.cpp 1282 2006-06-09 09:46:49Z alex $ /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE ================================XARAHEADERSTART=========================== Xara LX, a vector drawing and manipulation program. Copyright (C) 1993-2006 Xara Group Ltd. Copyright on certain contributions may be held in joint with their respective authors. See AUTHORS file for details. LICENSE TO USE AND MODIFY SOFTWARE ---------------------------------- This file is part of Xara LX. Xara LX is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. Xara LX and its component source files are distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Xara LX (see the file GPL in the root directory of the distribution); if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ADDITIONAL RIGHTS ----------------- Conditional upon your continuing compliance with the GNU General Public License described above, Xara Group Ltd grants to you certain additional rights. The additional rights are to use, modify, and distribute the software together with the wxWidgets library, the wxXtra library, and the "CDraw" library and any other such library that any version of Xara LX relased by Xara Group Ltd requires in order to compile and execute, including the static linking of that library to XaraLX. In the case of the "CDraw" library, you may satisfy obligation under the GNU General Public License to provide source code by providing a binary copy of the library concerned and a copy of the license accompanying it. Nothing in this section restricts any of the rights you have under the GNU General Public License. SCOPE OF LICENSE ---------------- This license applies to this program (XaraLX) and its constituent source files only, and does not necessarily apply to other Xara products which may in part share the same code base, and are subject to their own licensing terms. This license does not apply to files in the wxXtra directory, which are built into a separate library, and are subject to the wxWindows license contained within that directory in the file "WXXTRA-LICENSE". This license does not apply to the binary libraries (if any) within the "libs" directory, which are subject to a separate license contained within that directory in the file "LIBS-LICENSE". ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS ---------------------------------------------- Subject to the terms of the GNU Public License (see above), you are free to do whatever you like with your modifications. However, you may (at your option) wish contribute them to Xara's source tree. You can find details of how to do this at: http://www.xaraxtreme.org/developers/ Prior to contributing your modifications, you will need to complete our contributor agreement. This can be found at: http://www.xaraxtreme.org/developers/contribute/ Please note that Xara will not accept modifications which modify any of the text between the start and end of this header (marked XARAHEADERSTART and XARAHEADEREND). MARKS ----- Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara designs are registered or unregistered trademarks, design-marks, and/or service marks of Xara Group Ltd. All rights in these marks are reserved. Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. http://www.xara.com/ =================================XARAHEADEREND============================ */ /* $Header: /Camelot/kernel/ngscan.cpp 12 16/12/03 17:23 Phil $ The various scans made over documents and the selected objects by the Attribute gallery. */ #include "camtypes.h" #include "ngcore.h" #include "ngitem.h" #include "ngprop.h" #include "ngscan.h" #include "ngsentry.h" #include "extender.h" #include //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "undoop.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "objchge.h" //#include "ink.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "nodeattr.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "layer.h" #include "keypress.h" #include "nodebmp.h" // for NodeBitmap #include "nodershp.h" // for NodeRegularShape #include "ophist.h" //#include "cxfrech.h" // TemplateAttribute - in camtypes.h [AUTOMATICALLY REMOVED] //#include "attrval.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "userattr.h" #include "tmpltatr.h" //#include "mario.h" #include "nodershp.h" // for NodeRegularShape #include "nodebmp.h" // for NodeBitmap // for text story stuff #include "nodetxts.h" #include "nodetxtl.h" #include "nodetext.h" //#include "sliceres.h" #ifdef _DEBUG #undef THIS_FILE static char BASED_CODE THIS_FILE[] = __FILE__; #endif DECLARE_SOURCE("$Revision: 1282 $"); #define new CAM_DEBUG_NEW // This is shared between all instances of AllowOpScan so an operation can make // multiple allow scans on the same OCP. ObjChangeParam AllowOpScan::m_OCP; /******************************************************************************************** > BaseSelectScan::BaseSelectScan(BaseSelectScan::Change eChange, BOOL fQuiet = FALSE) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: eChange --- how to change the selection: TOGGLE, DESELECT, SELECT, SELECT_EXCLUSIVE fQuiet --- don't redraw blobs or broadcast messages Purpose: Constructs an BaseSelectScan object. SeeAlso: NodeScan ********************************************************************************************/ BaseSelectScan::BaseSelectScan(BaseSelectScan::Change eChange, BOOL fQuiet) : NodeScan(&theSelectedDocument), m_eChange(eChange), m_fShout(!fQuiet), m_nAffected(0) { // Empty. } /******************************************************************************************** > virtual BOOL BaseSelectScan::OnSelectable(NodeRenderable* pRender) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pRender --- the object whose selection state is to be changed Returns: The previous selection state of the object. Purpose: Helper function for BaseSelectScan derivatives that change the selection state of renderable nodes. ********************************************************************************************/ BOOL BaseSelectScan::OnSelectable(NodeRenderable* pRender) { // Check for the effects of the layer containing the object. Node* pNode = pRender; while (pNode != 0) { if (pNode->IsLayer()) { // Quit now if the layer is invisible or locked. Layer* pLayer = (Layer*) pNode; if (/*!pLayer->IsVisible() ||*/ pLayer->IsLocked()) return FALSE; break; } pNode = pNode->FindParent(); } // Perform the selection change. BOOL fPrevSel = pRender->IsSelected(); switch (m_eChange) { case TOGGLE: if (fPrevSel) pRender->DeSelect(m_fShout); else pRender->Select(m_fShout); break; case DESELECT: pRender->DeSelect(m_fShout); break; default: pRender->Select(m_fShout); break; } // Keep count of how many we've changed. ++m_nAffected; return fPrevSel; } /******************************************************************************************** > virtual BOOL BaseSelectScan::Pre() Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pNode --- the current node in the scan Purpose: Clears the selection first if the new state isn't "toggle" and the gallery ctrl-key isn't down. Returns: TRUE, continue scanning. SeeAlso: NodeScan ********************************************************************************************/ BOOL BaseSelectScan::Pre() { // If selecting exclusively then clear the selection of all objects first and count // them towards a call to Update(). if (m_eChange == SELECT_EXCLUSIVE) { m_nAffected += (INT32) GetApplication()->FindSelection()->Count(); NodeRenderableInk::DeselectAll(m_fShout, FALSE); } return TRUE; } /******************************************************************************************** > virtual BOOL BaseSelectScan::Do(Node* pNode) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pNode --- the current node in the scan Returns: TRUE, continue scanning. Purpose: Called by SelectScan when the 'select' action is executed. Tests the given node for membership of each highlighted set and changes it's selection status accordingly. SeeAlso: BaseSelectScan ********************************************************************************************/ BOOL BaseSelectScan::Do(Node* pNode) { // Let OnSelectable() control the continuation of the scan. return pNode->IsNodeRenderableClass() ? OnSelectable((NodeRenderable*) pNode) : TRUE; } /******************************************************************************************** > virtual BOOL BaseSelectScan::Post() Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Purpose: Called by BaseSelectScan after the selection is changed. Updates the application's selection range object. SeeAlso: NodeScan ********************************************************************************************/ BOOL BaseSelectScan::Post() { if (m_nAffected != 0) GetApplication()->FindSelection()->Update(m_fShout); return TRUE; } /******************************************************************************************** > SelectScan::SelectScan(SGNameItem* pItem, BaseSelectScan::Change eChange, BOOL fQuiet = FALSE) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pItem --- the set of objects to change the selection of eChange --- how to change the selection: TOGGLE, DESELECT, SELECT, SELECT_EXCLUSIVE Purpose: Constructs an SelectScan object. SeeAlso: BaseSelectScan ********************************************************************************************/ SelectScan::SelectScan(SGNameItem* pItem, BaseSelectScan::Change eChange, BOOL fQuiet) : BaseSelectScan(eChange, fQuiet), m_pItem(pItem) { // Empty. } /******************************************************************************************** > virtual BOOL SelectScan::OnSelectable(NodeRenderable* pRender) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pRender --- the current renderable node in the selection scan Returns: TRUE, continue scanning. Purpose: Called by SelectScan when the 'select' action is executed. Tests the given node for membership of each highlighted set and changes it's selection status accordingly. SeeAlso: BaseSelectScan ********************************************************************************************/ BOOL SelectScan::OnSelectable(NodeRenderable* pRender) { // If the node is a member then change its selection state. if (m_pItem->IsMember(pRender)) { // what it does is look at the text story if we are trying to select a text char // and we will be selecting the story // then just set the story to the end result // rather than selecting one char at a time (sjk 1/8/00) if (pRender->IsATextChar() && m_eChange != TOGGLE) { Node * pStory = pRender->FindParent(CC_RUNTIME_CLASS(TextStory)); if (pStory && m_pItem->IsMember(pStory)) { BOOL TurnOff = (m_eChange == DESELECT); if (pStory->IsSelected() != TurnOff) { if (TurnOff) pRender->DeSelect(m_fShout); else pRender->Select(m_fShout); } // keep the counts right m_nAffected++; return TRUE; } } BaseSelectScan::OnSelectable(pRender); } return TRUE; } /******************************************************************************************** > SelectUnionScan::SelectUnionScan(BaseSelectScan::Change eChange) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: eChange --- how to change the selection: TOGGLE, RESET, SET, SET_EXCLUSIVE Purpose: Constructs an SelectUnionScan object. SeeAlso: BaseSelectScan ********************************************************************************************/ SelectUnionScan::SelectUnionScan(BaseSelectScan::Change eChange) : BaseSelectScan(eChange) { // Empty. } /******************************************************************************************** > virtual BOOL SelectUnionScan::OnSelectable(NodeRenderable* pRender) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pRender --- the current renderable node in the scan Purpose: Called by SelectUnionScan when the 'select' action is executed. Tests the given node for membership of the highlighted SGNameItems and changes its selection status if it is a member of any. SeeAlso: BaseSelectScan ********************************************************************************************/ BOOL SelectUnionScan::OnSelectable(NodeRenderable* pRender) { // If it's a member of any highlighted SGNameItem then change its selection. if (Test(pRender, Test::IS_MEMBER).ForEach() != 0) BaseSelectScan::OnSelectable(pRender); return TRUE; } /******************************************************************************************** > SelectUnionScan::Test::Test(NodeRenderable* pRender, SelectUnionScan::Test::Question eQ) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pRender --- the renderable node to test for membership of any highlighted SGNameItems. eQ --- SelectUnionScan::Test::IS_MEMBER or IS_NON_MEMBER. Purpose: Constructs an SelectUnionScan::Test object. SeeAlso: DocScan; BaseSelectScan ********************************************************************************************/ SelectUnionScan::Test::Test(NodeRenderable* pRender, SelectUnionScan::Test::Question eQ) : NameItemIter(NameItemIter::HIGHLIGHTED_ITEMS), m_pRender(pRender), m_nXor((BOOL) eQ) { // Empty. } /******************************************************************************************** > virtual BOOL SelectUnionScan::Test::Do(SGNameItem* pItem) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pItem --- the current item in the iteration SeeAlso: BaseSelectScan; SelectUnionScan::Test ********************************************************************************************/ BOOL SelectUnionScan::Test::Do(SGNameItem* pItem) { return pItem->IsMember(m_pRender) ^ m_nXor; } /******************************************************************************************** > SelectIntersectScan::SelectIntersectScan(BaseSelectScan::Change eChange) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: eChange --- how to change the selection: TOGGLE, RESET, SET, SET_EXCLUSIVE Purpose: Constructs an SelectIntersectScan object. SeeAlso: DocScan; BaseSelectScan ********************************************************************************************/ SelectIntersectScan::SelectIntersectScan(BaseSelectScan::Change eChange) : SelectUnionScan(eChange) { // Empty. } /******************************************************************************************** > virtual BOOL SelectIntersectScan::Do(NodeRenderable* pRender) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pNode --- the current node in the scan Purpose: Called by SelectIntersectScan when the 'intersect' action is executed. Tests the given node for membership of all highlighted sets and changes it's selection status accordingly. SeeAlso: BaseSelectScan ********************************************************************************************/ BOOL SelectIntersectScan::OnSelectable(NodeRenderable* pRender) { // If it's a member of every highlighted SGNameItem then change its selection. if (Test(pRender, Test::IS_NON_MEMBER).ForEach() == 0) BaseSelectScan::OnSelectable(pRender); return TRUE; } /******************************************************************************************** > AllowOpScan::AllowOpScan(UndoableOperation* pOp, NodeScan::Source* ps) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pOp --- the UndoableOperation to scan for "allowance". ps --- the source for nodes to scan over, by default the 'selected' document's tree. Purpose: Constructs an AllowOpScan object, which checks AllowOp for the given operation on all nodes in the tree which are members of highlighted items in the 'Used Names' group of the Name Gallery. Defines the ObjChangeParam as STARTING. SeeAlso: NodeScan; ObjChangeParam; UndoableOperation ********************************************************************************************/ AllowOpScan::AllowOpScan(UndoableOperation* pOp, NodeScan::Source* ps) : UndoableNodeScan(pOp, ps) { // Set up the change flags etc. m_OCP.Define(OBJCHANGE_STARTING, ObjChangeFlags(FALSE, FALSE, FALSE, TRUE), 0, m_pOp); } /******************************************************************************************** > virtual BOOL AllowOpScan::Do(Node* pNode) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pNode --- the node to call AllowOp for if it is a member of a highlighted set in the Name Gallery. Purpose: Tests if the given node is a member of a set that the user has highlighted in the Name Gallery and if so, calls AllowOp on it. SeeAlso: AllowOpScan::IsLitUsedName; Node::AllowOp ********************************************************************************************/ BOOL AllowOpScan::Do(Node* pNode) { // If the node is a highlighted member of a "used names" set then call it's AllowOp // function and stop the iteration if it refuses the op. If it isn't a member then // ignore it. return IsLitUsedName(pNode).ForEach() == 0 || pNode->AllowOp(&m_OCP); } /******************************************************************************************** > virtual BOOL AllowOpScan::Update() Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pOp --- the UndoableOperation to scan for "allowance". pOCP --- the ObjChangeParam block to use Purpose: Defines the ObjChangeParam as FINISHED and calls UpdateChangedNodes. Returns: TRUE if successful. SeeAlso: ObjChangeParam; UndoableOperation ********************************************************************************************/ BOOL AllowOpScan::Update() { // Update all parents of changed nodes. m_OCP.Define(OBJCHANGE_FINISHED, ObjChangeFlags(FALSE, FALSE, FALSE, TRUE), 0, m_pOp); return m_pOp->UpdateChangedNodes(&m_OCP); } /******************************************************************************************** > AllowOpScan::IsLitUsedName::IsLitUsedName(Node* pNode) Author: Justin_Flude (Xara Group Ltd) Created: 27/7/99 Inputs: pNode --- the node to test for membership of a set within the 'Used Names' group of the Name Gallery. Purpose: Tests if the given Node is a member of a set within the Attribute gallery. SeeAlso: AllowOpScan; NameItemIter ********************************************************************************************/ AllowOpScan::IsLitUsedName::IsLitUsedName(Node* pNode) : NameIterOp(pNode) { // Empty. } /******************************************************************************************** > virtual BOOL AllowOpScan::IsLitUsedName::Do(SGNameItem* pItem) Author: Justin_Flude (Xara Group Ltd) Created: 27/7/99 Inputs: pItem --- the set item to test for membership Purpose: Tests if the Node passed to the constructor is a member of the given set item. SeeAlso: AllowOpScan::IsLitUsedName; SGNameItem::IsMember ********************************************************************************************/ BOOL AllowOpScan::IsLitUsedName::Do(SGNameItem* pItem) { // Quit as soon as we find a set item the object is a member of. ForEach will return // the address of the first set item the object is within. return !pItem->IsMember(m_pNode); } /******************************************************************************************** > AllowOpSingleScan::AllowOpSingleScan(UndoableOperation* pOp, NodeScan::Source* ps, const StringBase& strName) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pOp --- the UndoableOperation to scan set strName for "allowance". ps --- the source for candidate nodes to scan over, by default the 'selected' document's tree. strName --- name of the set whose members are to be scanned Purpose: Constructs an AllowOpSingleScan object, which checks AllowOp for the given operation on all nodes in the tree which are members of the specified set. SeeAlso: NodeScan; AllowOpScan; OpDeleteNames; ObjChangeParam; UndoableOperation ********************************************************************************************/ AllowOpSingleScan::AllowOpSingleScan(UndoableOperation* pOp, NodeScan::Source* ps, const StringBase& strName) : AllowOpScan(pOp, ps), m_strName(strName), m_pUsedNames(NameGallery::Instance()->GetUsedNames()) { ERROR3IF(m_pUsedNames == 0, "AllowOpSingleScan::AllowOpSingleScan: no used names"); } /******************************************************************************************** > virtual BOOL AllowOpSingleScan::Do(Node* pNode) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pNode --- the node to call AllowOp for if it is a member of a specified set. Purpose: Tests if the given node is a member of a specified and if so, calls AllowOp on it. SeeAlso: AllowOpScan::Do; SGUsedNames::IsMember; Node::AllowOp ********************************************************************************************/ BOOL AllowOpSingleScan::Do(Node* pNode) { // Stop iterating if the node is a member which doesn't allow the op. return !m_pUsedNames->IsMember(pNode, m_strName) || pNode->AllowOp(&m_OCP); } /******************************************************************************************** > static BOOL ApplyNameToNode(const StringBase& strName, Node* pNode, UndoableOperation* pOp, INT32 BarNo) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: strName --- the node to apply a name to pNode --- the name to apply to the node pOp --- the Operation context in which to manipulate nodes BarNo --- the bar number if it has one Returns: TRUE if successful. Purpose: Helper function to create a new Wix object name attribute and attach it to the given node in an undoable way. Errors: Out of memory. SeeAlso: ApplyScan ********************************************************************************************/ static BOOL ApplyNameToNode(const StringBase& strName, Node* pNode, UndoableOperation* pOp, INT32 BarNo) { // Try to create a new object name attribute to apply to the target node. TemplateAttribute* pta; String_256 BarName = ""; if (BarNo >= 0) { BarName.MakeMsg(_R(IDS_BARNAME), BarNo+1); } ALLOC_WITH_FAIL(pta, (new TemplateAttribute(TA_NAME, BarNo >= 0 ? BarName : _T("") , strName)), pOp); ERRORIF(pta == 0, _R(IDE_NOMORE_MEMORY), FALSE); // If the target node is an object, check that the attribute type is required by it, // and make a note for the attribute manager of the object being applied to. if (pNode->IsAnObject()) { NodeRenderableInk* pObj = (NodeRenderableInk*) pNode; if (!pObj->RequiresAttrib(pta)) { // (No objects reject Wix attributes, AFAIK) TRACEUSER( "JustinF", _T("ApplyNameToNode: %s failed RequireAttrib at 0x%p\n"), pObj->GetRuntimeClass()->m_lpszClassName, pObj); delete pta; return FALSE; } AttributeManager::pLastNodeAppliedTo = pObj; } // Attach the new attribute and make a note for the AttributeManager. pta->AttachNode(pNode, FIRSTCHILD); /* *** DUBIOUS TEXT BODGE *** // If we are applying the attribute to a node which discards its attribute children // (like the caret) then we should not generate any undo for the operation. if (m_pNode->DiscardsAttributeChildren()) SucceedAndDiscard(); // JCF: this is a bodge for the text tool, copied from // OpApplyAttribToSelected::ApplyToSelection:- // // "EOL nodes can now have attributes, but the last EOL cannot // be selected by the user, causing the text tool to show // when it shouldn't really. So if the last node in the range is // the node before the last EOL in a text story then we apply the // attribute to the EOL too." Node* pLastNode = selRange.FindLast(); if (pLastNode != 0 && pLastNode->IsAVisibleTextNode()) { // "Alternative approach to fix other EOLNode problems that have appeared, ie. // (Bugs 5371 & 5372). If the AbstractTextChar following the last selected node // is an EOLNode then apply to it too." AbstractTextChar* pNextChr = (AbstractTextChar*) pLastNode->FindNext(CC_RUNTIME_CLASS(AbstractTextChar)); if (pNextChr != 0 && pNextChr->IsAnEOLNode() && !DoApply(pNextChr, pAttrib, pSets)) { delete pAttrib; FailAndExecute(); End(); return; } } */ // Create an action to hide the new attribute when we Undo. HideNodeAction* pHideAct; if (AC_FAIL == HideNodeAction::Init(pOp, pOp->GetUndoActions(), pta, TRUE, (Action**) &pHideAct)) { pta->CascadeDelete(); delete pta; return FALSE; } // Success. return TRUE; } /******************************************************************************************** > ApplyScan::ApplyScan(UndoableOperation* pOp, NodeScan::Source* ps) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pOp --- the UndoableOperation that is the context for this scanning ps --- the source for nodes to scan over Purpose: Constructs an ApplyScan object SeeAlso: UndoableNodeScan; OpApplyNames; ApplyScan::ApplyItems ********************************************************************************************/ ApplyScan::ApplyScan(UndoableOperation* pOp, NodeScan::Source* ps) : UndoableNodeScan(pOp, ps) { // Empty. } /******************************************************************************************** > virtual BOOL ApplyScan::Do(Node* pNode) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pNode --- the node to apply names to Purpose: Applies names highlighted in the Attribute gallery to the given node. SeeAlso: OpApplyNames; ApplyScan::ApplyItems ********************************************************************************************/ BOOL ApplyScan::Do(Node* pNode) { // Apply all highlighted 'Used Names' to the node. return ApplyItems(pNode, m_pOp).ForEach() == 0; } /******************************************************************************************** > ApplyScan::ApplyItems::ApplyItems(Node* pNode, UndoableOperation* pOp) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pNode --- the node to apply highlighted items' names pOp --- the Operation context in which to manipulate the attrs. SeeAlso: OpApplyNames::Do ********************************************************************************************/ ApplyScan::ApplyItems::ApplyItems(Node* pNode, UndoableOperation* pOp) : NameIterOp(pNode, pOp) { // Empty. } /******************************************************************************************** > BOOL ApplyScan::ApplyItems::Do(SGNameItem* pItem) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pItem --- the highlighted set item whose name is to be applied Purpose: Applies the Wix ObjectName attributes that apply to objects. SeeAlso: OpApplyNames ********************************************************************************************/ BOOL ApplyScan::ApplyItems::Do(SGNameItem* pItem) { // If the object is already a member of the item's set then ignore it. if (pItem->IsMember(m_pNode)) return TRUE; // Extract the name from the item and apply it. String_256 strName; pItem->GetNameText(&strName); return ApplyNameToNode(strName, m_pNode, m_pOp, pItem->m_BarNumber); } /******************************************************************************************** > ApplySingleScan::ApplySingleScan(UndoableOperation* pOp, NodeScan::Source* ps, const StringBase& strName) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pOp --- the UndoableOperation that is the context for this scanning ps --- the source for nodes to scan over strName --- the name to apply to the selected objects Purpose: Constructs an ApplySingleScan object SeeAlso: ApplyScan; UndoableNodeScan; OpApplyNames::DoWithParam ********************************************************************************************/ ApplySingleScan::ApplySingleScan(UndoableOperation* pOp, NodeScan::Source* ps, const StringBase& strName) : ApplyScan(pOp, ps), m_strName(strName) { // Empty. } /******************************************************************************************** > virtual BOOL ApplySingleScan::Do(Node* pNode) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pNode --- the node to apply the name to Purpose: Applies the name passed to the constructor to all the selected objects. SeeAlso: ApplyScan; UndoableNodeScan; OpApplyNames::DoWithParam ********************************************************************************************/ BOOL ApplySingleScan::Do(Node* pNode) { return ApplyNameToNode(m_strName, pNode, m_pOp, -1); } /******************************************************************************************** > static NodeSetProperty* ApplyPropToNode(const StringBase& strName, Node* pNode, NodeSetProperty* pCopyPropNode, UndoableOperation* pOp) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: strName --- the node to 'apply' a property to pNode --- the property to 'apply' to the node pOp --- the Operation context in which to manipulate nodes pCopyPropNode --- the NodeSetProperty whose properties are to be copied into the 'applied' property, or null for no copy and default properties. Returns: Pointer to the newly 'applied' NodeSetProperty, or null for failure. Purpose: Helper function to create a new NodeSetProperty, with default properties, and attach it to the given node in an undoable way. Errors: Out of memory. SeeAlso: ApplyPropScan ********************************************************************************************/ static NodeSetProperty* ApplyPropToNode(const StringBase& strName, Node* pNode, NodeSetProperty* pCopyPropNode, UndoableOperation* pOp) { // If the set sentinel already has a NodeSetProperty for the given name then // do nothing. NodeSetProperty* psp = Document::GetSelected()->GetSetSentinel()->FindPropertyNode(strName); if (psp != 0) return psp; // Try to create a new property node to 'apply' to the sentinel. ALLOC_WITH_FAIL(psp, (new NodeSetProperty(strName)), pOp); ERRORIF(psp == 0, _R(IDE_NOMORE_MEMORY), 0); // Try to make a bunch of default or copied properties for it. NodeSetProperty * fOK=psp; // we use this as a boolean flag ALLOC_WITH_FAIL(psp, ((pCopyPropNode != 0 ? psp->CopyProperties(pCopyPropNode) : psp->CreateDefaults())?psp:NULL), pOp); if (!fOK) { delete psp; ERROR1RAW(_R(IDE_NOMORE_MEMORY)); return 0; } // Attach the new property and create an action to hide it when we Undo. HideNodeAction* pHideAct; psp->AttachNode(pNode, LASTCHILD); if (AC_FAIL == HideNodeAction::Init(pOp, pOp->GetUndoActions(), psp, TRUE, (Action**) &pHideAct)) { psp->CascadeDelete(); delete psp; return 0; } // Success. return psp; } /******************************************************************************************** > ApplyPropScan::ApplyPropScan(UndoableOperation* pOp, NodeScan::Source* ps, const StringBase& strName, NodeSetProperty* pCopyPropNode = 0) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pOp --- the UndoableOperation that is the context for this scanning strName --- the name to apply to the selected objects pCopyPropNode --- the NodeSetProperty whose properties are to be copied into the 'applied' property, or null for no copy and default properties. Purpose: Constructs an ApplyPropScan object SeeAlso: ApplySingleScan; ApplyScan; UndoableNodeScan; OpApplyNames::DoWithParam ********************************************************************************************/ ApplyPropScan::ApplyPropScan(UndoableOperation* pOp, const StringBase& strName, NodeSetProperty* pCopyPropNode) : ApplySingleScan(pOp, &theSetSentinel, strName), m_pCopyPropNode(pCopyPropNode) { // Empty. } /******************************************************************************************** > virtual BOOL ApplyPropScan::Do(Node* pNode) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pNode --- the node to apply the name to Purpose: Applies a default property to the given node (ie. the set sentinel). SeeAlso: ApplySingleScan; ApplyScan; UndoableNodeScan; OpApplyNames::DoWithParam ********************************************************************************************/ BOOL ApplyPropScan::Do(Node* pNode) { return ApplyPropToNode(m_strName, pNode, m_pCopyPropNode, m_pOp) != 0; } /******************************************************************************************** > HideScan::HideScan(UndoableOperation* pOp, NodeScan::Source* ps) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pOp --- the UndoableOperation that is the context for this scanning Purpose: Constructs a HideScan object, which scans through the tree for objects which are members of highlighted 'Used Names' sets in the Name Gallery and excludes them from their sets by hiding the Wix ObjectName attributes which apply to them. SeeAlso: UndoableNodeScan; OpDeleteNames; HideScan::HideItems ********************************************************************************************/ HideScan::HideScan(UndoableOperation* pOp, NodeScan::Source* ps) : UndoableNodeScan(pOp, ps) { // Empty. } /******************************************************************************************** > virtual BOOL HideScan::Do(Node* pNode) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pNode --- the node to test for membership of a highlighted set and if necessary exclude it from the set Purpose: Excludes the given node from any highlighted sets in the Name Gallery. SeeAlso: OpDeleteNames; HideScan::HideItems ********************************************************************************************/ BOOL HideScan::Do(Node* pNode) { // If the object is a highlighted member of a "used names" set then hide its // Wix ObjectName attribute. return HideItems(pNode, m_pOp).ForEach() == 0; } /******************************************************************************************** > HideScan::HideItems::HideItems(Node* pNode, UndoableOperation* pOp) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pNode --- the node to test for membership of a highlighted set and if necessary exclude it from the set pOp -- the Operation context in which to manipulate the attrs. Purpose: Excludes the given node from any highlighted sets in the Name Gallery. SeeAlso: OpDeleteNames ********************************************************************************************/ HideScan::HideItems::HideItems(Node* pNode, UndoableOperation* pOp) : NameIterOp(pNode, pOp) { // Empty. } /******************************************************************************************** > BOOL HideScan::HideItems::Do(SGNameItem* pItem) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pItem --- the set item to test membership of Purpose: Hides Wix ObjectName attributes that are applied to nodes within the given set item. SeeAlso: OpDeleteNames ********************************************************************************************/ BOOL HideScan::HideItems::Do(SGNameItem* pItem) { // If the node is a member of the item's set then exclude it from the set. if (pItem->IsMember(m_pNode)) { // Find the exact Wix attribute that makes the node a member of pItem's set. TemplateAttribute* pAttr; for (pAttr = (TemplateAttribute*) m_pNode->FindFirstAttr( &Node::IsAnObjectName ); pAttr != 0; pAttr = (TemplateAttribute*) pAttr->FindNextAttr( &Node::IsAnObjectName )) if (pItem->IsEqual(pAttr->GetParam())) break; // Try to hide the attribute. ERROR3IF(pAttr == 0, "HideScan::HideItems::Do: can't find TemplateAttribute"); if (!m_pOp->DoHideNode(pAttr, TRUE, 0, TRUE)) return FALSE; } // Continue scanning items. return TRUE; } /******************************************************************************************** > HidePropScan::HidePropScan(UndoableOperation* pOp) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pOp --- the UndoableOperation that is the context for this scanning Purpose: Constructs a HidePropScan object, which hides set properties for names highlighted in the Attribute gallery. SeeAlso: UndoableNodeScan; OpDeleteNames; HidePropScan::HideProp ********************************************************************************************/ HidePropScan::HidePropScan(UndoableOperation* pOp) : HideScan(pOp, &theSetSentinel) { // Empty. } /******************************************************************************************** > virtual BOOL HidePropScan::Do(Node* pNode) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pNode --- the document's NodeSetSentinel. Purpose: Excludes the given node from any highlighted sets in the Name Gallery. SeeAlso: OpDeleteNames; HidePropScan::HideProp ********************************************************************************************/ BOOL HidePropScan::Do(Node* pNode) { // If the object is a highlighted member of a "used names" set then hide its // properties. return HideProp(pNode, m_pOp).ForEach() == 0; } /******************************************************************************************** > HidePropScan::HideProp::HideProp(Node* pNode, UndoableOperation* pOp) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pNode --- the document's NodeSetSentinel. pOp -- the Operation context in which to manipulate the attrs. Purpose: Excludes the given node from any highlighted sets in the Name Gallery. SeeAlso: OpDeleteNames ********************************************************************************************/ HidePropScan::HideProp::HideProp(Node* pNode, UndoableOperation* pOp) : HideScan::HideItems(pNode, pOp) { ERROR3IF(pNode == 0 || !pNode->IS_KIND_OF(NodeSetSentinel), "HidePropScan::HideProp::HideProp: not a NodeSetSentinel"); } /******************************************************************************************** > BOOL HidePropScan::HideProp::Do(SGNameItem* pItem) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pItem --- the set item to test membership of Purpose: Hides set properties for all given item in the Attribute gallery. SeeAlso: OpDeleteNames ********************************************************************************************/ BOOL HidePropScan::HideProp::Do(SGNameItem* pItem) { // If the node is a member of the item's set then hide its associated property node. if (pItem->IsMember(m_pNode)) { // Find the property. String_256 strName; pItem->GetNameText(&strName); NodeSetProperty* pPropNode = Document::GetSelected()->GetSetSentinel()->FindPropertyNode(strName); // Try to hide the attribute. //ERROR3IF(pPropNode == 0, "HidePropScan::HideProp::Do: can't find NodeSetProperty"); if (!pPropNode) return TRUE; // trying to delete something that isn't there! Surely we have already succeeded! if (!m_pOp->DoHideNode(pPropNode, TRUE, 0, TRUE)) return FALSE; } // Continue scanning items. return TRUE; } /******************************************************************************************** > HideSingleScan::HideSingleScan(UndoableOperation* pOp, NodeScan::Source* ps, const StringBase& strName) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pOp --- the UndoableOperation that is the context for this scanning ps --- the source for candidate nodes to scan over strName --- the object name to hide Purpose: Constructs a HideSingleScan object, which hides set properties for names highlighted in the Attribute gallery. SeeAlso: UndoableNodeScan; HideSingleScan::Do; OpChangeSetProperties::DoWithParam ********************************************************************************************/ HideSingleScan::HideSingleScan(UndoableOperation* pOp, NodeScan::Source* ps, const StringBase& strName) : HideScan(pOp, ps), m_strName(strName), m_pUsedNames(NameGallery::Instance()->GetUsedNames()) { ERROR3IF(m_pUsedNames == 0, "HideSingleScan::HideSingleScan: no used names"); } /******************************************************************************************** > virtual BOOL HideSingleScan::Do(Node* pNode) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pNode --- the node to consider hiding. Purpose: Excludes the given node from a specified set if it's a member. SeeAlso: HideSingleScan::HideSingleScan; SGUsedNames::IsMember ********************************************************************************************/ BOOL HideSingleScan::Do(Node* pNode) { // If the node is a member of the set then hide it's attribute. if (m_pUsedNames->IsMember(pNode, m_strName)) { // Find the exact Wix attribute that makes the node a member of the set. TemplateAttribute* pAttr; for (pAttr = (TemplateAttribute*) pNode->FindFirstAttr( &Node::IsAnObjectName ); pAttr != 0; pAttr = (TemplateAttribute*) pAttr->FindNextAttr( &Node::IsAnObjectName )) if (pAttr->GetParam() == m_strName) break; // Try to hide the attribute. ERROR3IF(pAttr == 0, "HideSingleScan::Do: can't find TemplateAttribute"); if (!m_pOp->DoHideNode(pAttr, TRUE, 0, TRUE)) return FALSE; } // Continue scanning items. return TRUE; } /******************************************************************************************** > CreateDisplayScan::CreateDisplayScan() Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Purpose: Constructs a CreateDisplayScan object. SeeAlso: NodeScan ********************************************************************************************/ CreateDisplayScan::CreateDisplayScan() : NodeScan(&theSelectedDocument) { // Empty. } /******************************************************************************************** > virtual BOOL CreateDisplayScan::Pre() Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Purpose: Called by CreateDisplayScan when the gallery display is (re)created. Resets the running counters of total and selected objects in each display item. SeeAlso: NodeScan ********************************************************************************************/ BOOL CreateDisplayScan::Pre() { return ClearCounters().ForEach() == 0; } /******************************************************************************************** > virtual BOOL CreateDisplayScan::Do(Node* pNode) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pNode --- the current node in the scan Purpose: Called by CreateDisplayScan when the gallery display is (re)created. Tests the given node for membership of each set and if it is a member, creates a new SGNameItem for its name ('attribute value') if one doesn't already exist, and includes it in the running counts of total and selected objects. SeeAlso: NodeScan ********************************************************************************************/ BOOL CreateDisplayScan::Do(Node* pNode) { // Create/register with the sets that contain pInkNode as a member. return CreateItems(pNode).ForEach() == 0; } /******************************************************************************************** > virtual BOOL CreateDisplayScan::Post() Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Purpose: Called by CreateDisplayScan when the gallery display is (re)created. Deletes any SGNameItems which don't have any members and folds any groups that don't have items. SeeAlso: NodeScan ********************************************************************************************/ BOOL CreateDisplayScan::Post() { return DelItemIfUnref().ForEach() == 0 && FoldGroupIfEmpty().ForEach() == 0; } /******************************************************************************************** > virtual BOOL CreateDisplayScan::ClearCounters::Do(SGNameItem* pItem) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pItem --- current item in the iteration Purpose: Resets (zeroes) the total and selected counters in all items. SeeAlso: CreateDisplayScan; NameItemIter ********************************************************************************************/ BOOL CreateDisplayScan::ClearCounters::Do(SGNameItem* pItem) { pItem->Reset(); return TRUE; } /******************************************************************************************** > CreateDisplayScan::CreateItems::CreateItems(Node* pNode) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pNode --- the node to pass to the Do function Purpose: Constructs a CreateDisplayScan::CreateItems object. SeeAlso: CreateDisplayScan; NameGroupIter ********************************************************************************************/ CreateDisplayScan::CreateItems::CreateItems(Node* pNode) : m_pNode(pNode) { // Empty. } /******************************************************************************************** > virtual BOOL CreateDisplayScan::CreateItems::Do(SGNameGroup* pGroup) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pGroup --- current group in the iteration Purpose: Creates items for all the sets in pGroup. SeeAlso: CreateDisplayScan; NameItemIter ********************************************************************************************/ BOOL CreateDisplayScan::CreateItems::Do(SGNameGroup* pGroup) { return pGroup->CreateItems(m_pNode); } /******************************************************************************************** > virtual BOOL CreateDisplayScan::DelItemIfNoRef::Do(SGNameItem* pItem) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pItem --- current item in the iteration Purpose: Deletes the names of items which no longer refer to any objects. ********************************************************************************************/ BOOL CreateDisplayScan::DelItemIfUnref::Do(SGNameItem* pItem) { // Basic integrity checks for the number of objects & nodes encountered. ERROR3IF(pItem->GetNodeCount() < pItem->GetObjectCount(), "CreateDisplayScan::DelItemIfNoRef::Do: nodes < objects"); ERROR3IF(pItem->GetNodeCount() > pItem->GetObjectCount() + 1, "CreateDisplayScan::DelItemIfNoRef::Do: nodes > objects + 1"); ERROR3IF(pItem->GetSelectedCount() > pItem->GetObjectCount(), "CreateDisplayScan::DelItemIfNoRef::Do: selected > objects"); // Does the item's set not contain any objects? if (pItem->GetNodeCount() == 0) { pItem->RemoveFromTree(); delete pItem; } // 'Decimate the contentless 'til the bitter end', sayeth Tiberius. return TRUE; } /******************************************************************************************** > virtual BOOL CreateDisplayScan::FoldGroupIfEmpty::Do(SGNameGroup* pGroup) Author: Justin_Flude (Xara Group Ltd) Created: 27/5/99 Inputs: pGroup --- current group in the iteration Purpose: Folds groups which have no items. ********************************************************************************************/ BOOL CreateDisplayScan::FoldGroupIfEmpty::Do(SGNameGroup* pGroup) { // Is the group item-less and unfolded? if (pGroup->GetChild() == 0 && !pGroup->Flags.Folded) { // Remember to unfold this group as soon as it has items again. But if the user // has folded the group deliberately then we don't interfere with it. pGroup->Flags.Reserved |= 1; pGroup->Flags.Folded = TRUE; } return TRUE; }