<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: nodechangeimpl.hxx,v $
 *
 *  $Revision: 1.11 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 04:30:33 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef CONFIGMGR_CONFIGCHANGEIMPL_HXX_
#define CONFIGMGR_CONFIGCHANGEIMPL_HXX_

#ifndef CONFIGMGR_CONFIGEXCEPT_HXX_
#include "configexcept.hxx"
#endif
#ifndef CONFIGMGR_CONFIGPATH_HXX_
#include "configpath.hxx"
#endif

#ifndef CONFIGMGR_VIEWACCESS_HXX_
#include "viewaccess.hxx"
#endif

#ifndef _RTL_REF_HXX_
#include <rtl/ref.hxx>
#endif
#ifndef _SALHELPER_SIMPLEREFERENCEOBJECT_HXX_
#include <salhelper/simplereferenceobject.hxx>
#endif

#ifndef INCLUDED_VECTOR
#include <vector>
#define INCLUDED_VECTOR
#endif

#ifndef INCLUDED_MEMORY
#include <memory>
#define INCLUDED_MEMORY
#endif

namespace configmgr
{
    class ISubtree;

    namespace view { class ViewTreeAccess; struct Node; struct GroupNode; struct SetNode; }
//-----------------------------------------------------------------------------
    namespace configuration
    {
//-----------------------------------------------------------------------------

        typedef com::sun::star::uno::Type       UnoType;
        typedef com::sun::star::uno::Any        UnoAny;
//-----------------------------------------------------------------------------

        class ValueMemberNode;
        class ValueMemberUpdate;
//-----------------------------------------------------------------------------
        class NodeChangeData;
        class NodeChangeLocation;
        class NodeChangeInformation;
//-----------------------------------------------------------------------------

        typedef rtl::Reference<TreeImpl>        TreeHolder;
        typedef rtl::Reference<ElementTreeImpl> ElementTreeHolder;
//-----------------------------------------------------------------------------
        struct ElementTreeChange
        {
            Path::Component m_aElementName;
            ElementTreeHolder  m_aAddedElement;
            ElementTreeHolder  m_aRemovedElement;

            ElementTreeChange(
                Path::Component const& _aElementName,
                ElementTreeHolder  const& _aAddedElement,
                ElementTreeHolder  const& _aRemovedElement
             )
            : m_aElementName(_aElementName)
            , m_aAddedElement(_aAddedElement)
            , m_aRemovedElement(_aRemovedElement)
            {}

            bool isChange() const
            {
                return !!(m_aAddedElement != m_aRemovedElement);
            }
        };
//-----------------------------------------------------------------------------

        /// represents a node position in some tree
        class NodeChangeImpl
        : public salhelper::SimpleReferenceObject
        {
        public:
            explicit
            NodeChangeImpl(bool bNoCheck = false);

        public:
        // related/affected nodes and trees
            /// the tree within which the change occurs
            TreeHolder getTargetTree() const;

            /// the node that is affected by the change
            NodeOffset getTargetNode() const;

            data::Accessor const& getDataAccessor() const { return m_aDataAccessor; }
        protected:
            /// setup the 'target' node that is to be affected or changed
            void setTarget(data::Accessor const& _aAccessor, TreeHolder const& _aAffectedTree, NodeOffset _nAffectedNode);
            void setTarget(view::Node _aAffectedNode);

            view::ViewTreeAccess getTargetView();
        public:
        // getting information
            typedef sal_uInt32 ChangeCount;
            /*static const ChangeCount*/ enum { scCommonBase = ~0u };

            /// checks, if this represents an actual change - with or without requiring a preceding test
            bool isChange(bool bAllowUntested) const;

            /// return the number of distict changes in this object
            ChangeCount getChangeDataCount() const;

            /// fills in base change location, returns whether it is set
            bool fillChangeLocation(NodeChangeLocation& rChange, ChangeCount _ix = scCommonBase) const;

            /// fills in pre- and post-change values, returns whether they may differ
            bool fillChangeData(NodeChangeData& rChange, ChangeCount _ix) const;

            /// fills in change location and values, returns whether data may be changed
            bool fillChangeInfo(NodeChangeInformation& rChange, ChangeCount _ix) const;

        /// test whether this really is a change to the stored 'changing' node
            void test();

        /// apply this change to the stored 'changing' node
            void apply();

        private:
        /// virtual hooks for some of the public methods
            /// return the number of distict changes in this object
            ChangeCount doGetChangeCount() const;

            /// the path from base to 'changing' node
            virtual RelativePath doGetChangingNodePath(ChangeCount _ix) const = 0;

            /// is the change really affecting a child (or children) of the affected node (true for values)
            virtual bool doIsChangingSubnode() const = 0;

            /// checks, if this represents an actual change (given whether the change has been applied or not)
            virtual bool doIsChange() const = 0;

            /// fills in pre- and post-change values, returns wether they differ
            virtual bool doFillChange(NodeChangeData& rChange, ChangeCount _ix) const = 0;

            /// dry-check whether this is a change
            virtual void doTest( view::Node const& rTarget) = 0;
            /// do apply the actual change
            virtual void doApply( view::Node const& rTarget) = 0;

        private:
            typedef sal_uInt16 State;
            data::Accessor m_aDataAccessor;
            TreeHolder m_aAffectedTree;
            NodeOffset m_nAffectedNode;
            State      m_nState;

            void implApply();
            view::Node implGetTarget();
        };
//-----------------------------------------------------------------------------

        /// represents a node position in some tree
        class ValueChangeImpl
        : public NodeChangeImpl
        {
            Name   m_aName;
            UnoAny m_aNewValue;
            UnoAny m_aOldValue;
        public:
            explicit ValueChangeImpl();
            explicit ValueChangeImpl(UnoAny const& aNewValue);
            explicit ValueChangeImpl(UnoAny const& aNewValue, UnoAny const& aOldValue);
            ~ValueChangeImpl();

        public:
            /// setup the 'target' node that is to be affected or changed
            void setTarget(view::GroupNode const& _aParentNode, Name const& sNodeName);
            void setTarget(data::Accessor const& _aAccessor, TreeHolder const& aAffectedTree, NodeOffset nParentNode, Name const& sNodeName);

        public:
            /// get the name of the value
            Name getValueName() const { return m_aName; }

            /// get the pre-change value (if known)
            UnoAny getOldValue() const { return m_aOldValue; }
            /// get the post-change value (if known)
            UnoAny getNewValue() const { return m_aNewValue; }

        protected:
        // override information items
            /// the path from base to 'affected' node - here is the name of the changing node
            virtual RelativePath doGetChangingNodePath(ChangeCount _ix) const;

            /// is the change really affecting a child of the affected node (true here)
            virtual bool doIsChangingSubnode() const;

        protected:
        // override change information items
            /// checks, if this represents an actual change (given whether the change has been applied or not)
            virtual bool doIsChange() const;

            /// fills in pre- and post-change values, returns wether they differ
            virtual bool doFillChange(NodeChangeData& rChange, ChangeCount _ix) const = 0;

        protected:
        // override apply functionality
            /// retrieve the old value from the given node
            virtual void doTest( view::Node const& rTarget);
            /// do apply the actual change
            virtual void doApply( view::Node const& rTarget);

        protected:
        // new overrideables
            /// extract the pre-change value from the target context
            virtual void preCheckValue(ValueMemberNode& rNode, UnoAny& rOld, UnoAny& rNew);
            /// extract the post-change value from the target context
            virtual void postCheckValue(ValueMemberNode& rNode, UnoAny& rNew);
            /// apply the new value to the target context
            virtual void doApplyChange(ValueMemberUpdate& rNode) = 0;
        };
//-----------------------------------------------------------------------------

        /// represents setting a value node to a given value
        class ValueReplaceImpl
        : public ValueChangeImpl
        {
        public:
            explicit ValueReplaceImpl(UnoAny const& aNewValue);
            explicit ValueReplaceImpl(UnoAny const& aNewValue, UnoAny const& aOldValue);

        protected:
            // implement: set the target to the new value
            virtual void doApplyChange( ValueMemberUpdate& rNode);

            /// fills in pre- and post-change values, returns wether they differ
            virtual bool doFillChange(NodeChangeData& rChange, ChangeCount _ix) const;

//          friend class SetReplaceValueImpl;
        };
//-----------------------------------------------------------------------------

        /// represents resetting a value node to its default value
        class ValueResetImpl
        : public ValueChangeImpl
        {
            bool m_bTargetIsDefault;
        public:
            explicit ValueResetImpl();
            explicit ValueResetImpl(UnoAny const& aNewValue, UnoAny const& aOldValue);

        protected:
            // override: set the new value as well and check the default state
            virtual void preCheckValue(ValueMemberNode& rNode, UnoAny& rOld, UnoAny& rNew);

            /// checks, if this represents an actual change (given whether the change has been applied or not)
            virtual bool doIsChange() const;

            // implement: set the target to default
            virtual void doApplyChange( ValueMemberUpdate& rNode);

            /// fills in pre- and post-change values, returns wether they differ
            virtual bool doFillChange(NodeChangeData& rChange, ChangeCount _ix) const;
        };
//-----------------------------------------------------------------------------

        /// represents a change to a set (as a container)
        class SetChangeImpl
        : public NodeChangeImpl
        {
        public:
            explicit SetChangeImpl(bool bNoCheck = false);

            using NodeChangeImpl::setTarget;

        protected:
        /// virtual hooks for some of the public methods
            /// is the change really affecting a child of the affected node (false here)
            virtual bool doIsChangingSubnode() const;
        };
//-----------------------------------------------------------------------------
        class SetElementFactory;

        /// represents setting to its default state a set (as a container)
        class SetResetImpl
        : public SetChangeImpl
        {
            typedef std::vector< ElementTreeChange >    TreeChanges;

            std::auto_ptr<ISubtree>             m_aDefaultData;
            SetElementFactory&                  m_rElementFactory;
            TreeChanges                         m_aTreeChanges;
        public:
            explicit SetResetImpl(
                SetElementFactory& _rElementFactory,
                std::auto_ptr<ISubtree> _pDefaultData,
                bool _bNoCheck = false);

            ~SetResetImpl();

        protected:
        /// virtual hooks for some of the public methods
            /// retrieve the count of elements affected
            ChangeCount doGetChangeCount() const;

            /// the path from base to 'affected' node
            virtual RelativePath doGetChangingNodePath(ChangeCount _ix) const;

            /// checks, if this represents an actual change (given whether the change has been applied or not)
            virtual bool doIsChange() const;
            /// fills in pre- and post-change values, returns wether they differ
            virtual bool doFillChange(NodeChangeData& rChange, ChangeCount _ix) const;

            /// retrieve the old value from the given node
            virtual void doTest( view::Node const& rTarget);
            /// do apply the actual change
            virtual void doApply( view::Node const& rTarget);
        };
//-----------------------------------------------------------------------------

        /// represents a change to an element of a set (as a container)
        class SetElementChangeImpl
        : public SetChangeImpl
        {
            Path::Component m_aName;
        public:
            explicit SetElementChangeImpl(Path::Component const& aName, bool bNoCheck = false);

            /// the name of the element being changed
            Path::Component getFullElementName() const { return m_aName; }

            /// the name of the element being changed
            Name getElementName() const { return m_aName.getName(); }

        protected:
        /// virtual hooks for some of the public methods
            /// the path from base to 'affected' node - use element name
            virtual RelativePath doGetChangingNodePath(ChangeCount _ix) const;

            /// retrieve the old value from the given node
            virtual void doTest( view::Node const& rTarget);
            /// do apply the actual change
            virtual void doApply( view::Node const& rTarget);

        private:
            /// new overridable: retrieve the old value from a properly typed node
            virtual void doTestElement(view::SetNode const& _aNode, Name const& aName) = 0;
            /// new overridable: apply the change to a properly typed node
            virtual void doApplyToElement(view::SetNode const& _aNode, Name const& aName) = 0;
        };
//-----------------------------------------------------------------------------

        /// represents an insertion into a set of trees
        class SetInsertImpl
        : public SetElementChangeImpl
        {
            ElementTreeHolder m_aNewTree;
        public:
            explicit SetInsertImpl(Path::Component const& aName, ElementTreeHolder const& aNewTree, bool bNoCheck = false);

        protected:
            /// checks, if this represents an actual change (given whether the change has been applied or not)
            virtual bool doIsChange() const;
            /// fills in pre- and post-change values, returns wether they differ
            virtual bool doFillChange(NodeChangeData& rChange, ChangeCount _ix) const;

            /// new overridable: retrieve the old value from a properly typed node
            virtual void doTestElement(view::SetNode const& _aNode, Name const& aName);
            /// new overridable: apply the change to a properly typed node
            virtual void doApplyToElement(view::SetNode const& _aNode, Name const& aName);
        };
//-----------------------------------------------------------------------------

        /// represents a substitution within a set of trees
        class SetReplaceImpl
        : public SetElementChangeImpl
        {
            ElementTreeHolder m_aNewTree;
            ElementTreeHolder m_aOldTree;
        public:
            explicit SetReplaceImpl(Path::Component const& aName, ElementTreeHolder const& aNewTree);
            explicit SetReplaceImpl(Path::Component const& aName, ElementTreeHolder const& aNewTree, ElementTreeHolder const& aOldTree);

        protected:
            /// checks, if this represents an actual change (given whether the change has been applied or not)
            virtual bool doIsChange() const;
            /// fills in pre- and post-change values, returns wether they differ
            virtual bool doFillChange(NodeChangeData& rChange, ChangeCount _ix) const;

            /// new overridable: retrieve the old value from a properly typed node
            virtual void doTestElement(view::SetNode const& _aNode, Name const& aName);
            /// new overridable: apply the change to a properly typed node
            virtual void doApplyToElement(view::SetNode const& _aNode, Name const& aName);
        };
//-----------------------------------------------------------------------------

        /// represents a removal from of a set of trees
        class SetRemoveImpl
        : public SetElementChangeImpl
        {
            ElementTreeHolder m_aOldTree;
        public:
            explicit SetRemoveImpl(Path::Component const& aName);
            explicit SetRemoveImpl(Path::Component const& aName, ElementTreeHolder const& aOldTree);

        protected:
            /// checks, if this represents an actual change (given whether the change has been applied or not)
            virtual bool doIsChange() const;
            /// fills in pre- and post-change values, returns wether they differ
            virtual bool doFillChange(NodeChangeData& rChange, ChangeCount _ix) const;

            /// new overridable: retrieve the old value from a properly typed node
            virtual void doTestElement(view::SetNode const& _aNode, Name const& aName);
            /// new overridable: apply the change to a properly typed node
            virtual void doApplyToElement(view::SetNode const& _aNode, Name const& aName);
        };
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
    }
}

#endif // CONFIGMGR_CONFIGCHANGEIMPL_HXX_
<commit_msg>INTEGRATION: CWS warnings01 (1.11.4); FILE MERGED 2005/11/01 12:47:37 cd 1.11.4.1: #i53898# Warning free code for sun solaris compiler<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: nodechangeimpl.hxx,v $
 *
 *  $Revision: 1.12 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 23:32:49 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef CONFIGMGR_CONFIGCHANGEIMPL_HXX_
#define CONFIGMGR_CONFIGCHANGEIMPL_HXX_

#ifndef CONFIGMGR_CONFIGEXCEPT_HXX_
#include "configexcept.hxx"
#endif
#ifndef CONFIGMGR_CONFIGPATH_HXX_
#include "configpath.hxx"
#endif

#ifndef CONFIGMGR_VIEWACCESS_HXX_
#include "viewaccess.hxx"
#endif

#ifndef _RTL_REF_HXX_
#include <rtl/ref.hxx>
#endif
#ifndef _SALHELPER_SIMPLEREFERENCEOBJECT_HXX_
#include <salhelper/simplereferenceobject.hxx>
#endif

#ifndef INCLUDED_VECTOR
#include <vector>
#define INCLUDED_VECTOR
#endif

#ifndef INCLUDED_MEMORY
#include <memory>
#define INCLUDED_MEMORY
#endif

namespace configmgr
{
    class ISubtree;

    namespace view { class ViewTreeAccess; struct Node; struct GroupNode; struct SetNode; }
//-----------------------------------------------------------------------------
    namespace configuration
    {
//-----------------------------------------------------------------------------

        typedef com::sun::star::uno::Type       UnoType;
        typedef com::sun::star::uno::Any        UnoAny;
//-----------------------------------------------------------------------------

        class ValueMemberNode;
        class ValueMemberUpdate;
//-----------------------------------------------------------------------------
        class NodeChangeData;
        class NodeChangeLocation;
        class NodeChangeInformation;
//-----------------------------------------------------------------------------

        typedef rtl::Reference<TreeImpl>        TreeHolder;
        typedef rtl::Reference<ElementTreeImpl> ElementTreeHolder;
//-----------------------------------------------------------------------------
        struct ElementTreeChange
        {
            Path::Component m_aElementName;
            ElementTreeHolder  m_aAddedElement;
            ElementTreeHolder  m_aRemovedElement;

            ElementTreeChange(
                Path::Component const& _aElementName,
                ElementTreeHolder  const& _aAddedElement,
                ElementTreeHolder  const& _aRemovedElement
             )
            : m_aElementName(_aElementName)
            , m_aAddedElement(_aAddedElement)
            , m_aRemovedElement(_aRemovedElement)
            {}

            bool isChange() const
            {
                return !!(m_aAddedElement != m_aRemovedElement);
            }
        };
//-----------------------------------------------------------------------------

        /// represents a node position in some tree
        class NodeChangeImpl
        : public salhelper::SimpleReferenceObject
        {
        public:
            explicit
            NodeChangeImpl(bool bNoCheck = false);

        public:
        // related/affected nodes and trees
            /// the tree within which the change occurs
            TreeHolder getTargetTree() const;

            /// the node that is affected by the change
            NodeOffset getTargetNode() const;

            data::Accessor const& getDataAccessor() const { return m_aDataAccessor; }
        protected:
            /// setup the 'target' node that is to be affected or changed
            void setTarget(data::Accessor const& _aAccessor, TreeHolder const& _aAffectedTree, NodeOffset _nAffectedNode);
            void setTarget(view::Node _aAffectedNode);

            view::ViewTreeAccess getTargetView();
        public:
        // getting information
            typedef sal_uInt32 ChangeCount;
            /*static const ChangeCount*/ enum { scCommonBase = ~0u };

            /// checks, if this represents an actual change - with or without requiring a preceding test
            bool isChange(bool bAllowUntested) const;

            /// return the number of distict changes in this object
            ChangeCount getChangeDataCount() const;

            /// fills in base change location, returns whether it is set
            bool fillChangeLocation(NodeChangeLocation& rChange, ChangeCount _ix = scCommonBase) const;

            /// fills in pre- and post-change values, returns whether they may differ
            bool fillChangeData(NodeChangeData& rChange, ChangeCount _ix) const;

            /// fills in change location and values, returns whether data may be changed
            bool fillChangeInfo(NodeChangeInformation& rChange, ChangeCount _ix) const;

        /// test whether this really is a change to the stored 'changing' node
            void test();

        /// apply this change to the stored 'changing' node
            void apply();

        private:
        /// virtual hooks for some of the public methods
            /// return the number of distict changes in this object
            ChangeCount doGetChangeCount() const;

            /// the path from base to 'changing' node
            virtual RelativePath doGetChangingNodePath(ChangeCount _ix) const = 0;

            /// is the change really affecting a child (or children) of the affected node (true for values)
            virtual bool doIsChangingSubnode() const = 0;

            /// checks, if this represents an actual change (given whether the change has been applied or not)
            virtual bool doIsChange() const = 0;

            /// fills in pre- and post-change values, returns wether they differ
            virtual bool doFillChange(NodeChangeData& rChange, ChangeCount _ix) const = 0;

            /// dry-check whether this is a change
            virtual void doTest( view::Node const& rTarget) = 0;
            /// do apply the actual change
            virtual void doApply( view::Node const& rTarget) = 0;

        private:
            typedef sal_uInt16 State;
            data::Accessor m_aDataAccessor;
            TreeHolder m_aAffectedTree;
            NodeOffset m_nAffectedNode;
            State      m_nState;

            void implApply();
            view::Node implGetTarget();
        };
//-----------------------------------------------------------------------------

        /// represents a node position in some tree
        class ValueChangeImpl
        : public NodeChangeImpl
        {
            Name   m_aName;
            UnoAny m_aNewValue;
            UnoAny m_aOldValue;
        public:
            explicit ValueChangeImpl();
            explicit ValueChangeImpl(UnoAny const& aNewValue);
            explicit ValueChangeImpl(UnoAny const& aNewValue, UnoAny const& aOldValue);
            ~ValueChangeImpl();

        public:
            /// setup the 'target' node that is to be affected or changed
            void setTarget(view::GroupNode const& _aParentNode, Name const& sNodeName);
            void setTarget(data::Accessor const& _aAccessor, TreeHolder const& aAffectedTree, NodeOffset nParentNode, Name const& sNodeName);

        public:
            /// get the name of the value
            Name getValueName() const { return m_aName; }

            /// get the pre-change value (if known)
            UnoAny getOldValue() const { return m_aOldValue; }
            /// get the post-change value (if known)
            UnoAny getNewValue() const { return m_aNewValue; }

        protected:
                     using NodeChangeImpl::setTarget;
        // override information items
            /// the path from base to 'affected' node - here is the name of the changing node
            virtual RelativePath doGetChangingNodePath(ChangeCount _ix) const;

            /// is the change really affecting a child of the affected node (true here)
            virtual bool doIsChangingSubnode() const;

        protected:
        // override change information items
            /// checks, if this represents an actual change (given whether the change has been applied or not)
            virtual bool doIsChange() const;

            /// fills in pre- and post-change values, returns wether they differ
            virtual bool doFillChange(NodeChangeData& rChange, ChangeCount _ix) const = 0;

        protected:
        // override apply functionality
            /// retrieve the old value from the given node
            virtual void doTest( view::Node const& rTarget);
            /// do apply the actual change
            virtual void doApply( view::Node const& rTarget);

        protected:
        // new overrideables
            /// extract the pre-change value from the target context
            virtual void preCheckValue(ValueMemberNode& rNode, UnoAny& rOld, UnoAny& rNew);
            /// extract the post-change value from the target context
            virtual void postCheckValue(ValueMemberNode& rNode, UnoAny& rNew);
            /// apply the new value to the target context
            virtual void doApplyChange(ValueMemberUpdate& rNode) = 0;
        };
//-----------------------------------------------------------------------------

        /// represents setting a value node to a given value
        class ValueReplaceImpl
        : public ValueChangeImpl
        {
        public:
            explicit ValueReplaceImpl(UnoAny const& aNewValue);
            explicit ValueReplaceImpl(UnoAny const& aNewValue, UnoAny const& aOldValue);

        protected:
            // implement: set the target to the new value
            virtual void doApplyChange( ValueMemberUpdate& rNode);

            /// fills in pre- and post-change values, returns wether they differ
            virtual bool doFillChange(NodeChangeData& rChange, ChangeCount _ix) const;

//          friend class SetReplaceValueImpl;
        };
//-----------------------------------------------------------------------------

        /// represents resetting a value node to its default value
        class ValueResetImpl
        : public ValueChangeImpl
        {
            bool m_bTargetIsDefault;
        public:
            explicit ValueResetImpl();
            explicit ValueResetImpl(UnoAny const& aNewValue, UnoAny const& aOldValue);

        protected:
            // override: set the new value as well and check the default state
            virtual void preCheckValue(ValueMemberNode& rNode, UnoAny& rOld, UnoAny& rNew);

            /// checks, if this represents an actual change (given whether the change has been applied or not)
            virtual bool doIsChange() const;

            // implement: set the target to default
            virtual void doApplyChange( ValueMemberUpdate& rNode);

            /// fills in pre- and post-change values, returns wether they differ
            virtual bool doFillChange(NodeChangeData& rChange, ChangeCount _ix) const;
        };
//-----------------------------------------------------------------------------

        /// represents a change to a set (as a container)
        class SetChangeImpl
        : public NodeChangeImpl
        {
        public:
            explicit SetChangeImpl(bool bNoCheck = false);

            using NodeChangeImpl::setTarget;

        protected:
        /// virtual hooks for some of the public methods
            /// is the change really affecting a child of the affected node (false here)
            virtual bool doIsChangingSubnode() const;
        };
//-----------------------------------------------------------------------------
        class SetElementFactory;

        /// represents setting to its default state a set (as a container)
        class SetResetImpl
        : public SetChangeImpl
        {
            typedef std::vector< ElementTreeChange >    TreeChanges;

            std::auto_ptr<ISubtree>             m_aDefaultData;
            SetElementFactory&                  m_rElementFactory;
            TreeChanges                         m_aTreeChanges;
        public:
            explicit SetResetImpl(
                SetElementFactory& _rElementFactory,
                std::auto_ptr<ISubtree> _pDefaultData,
                bool _bNoCheck = false);

            ~SetResetImpl();

        protected:
        /// virtual hooks for some of the public methods
            /// retrieve the count of elements affected
            ChangeCount doGetChangeCount() const;

            /// the path from base to 'affected' node
            virtual RelativePath doGetChangingNodePath(ChangeCount _ix) const;

            /// checks, if this represents an actual change (given whether the change has been applied or not)
            virtual bool doIsChange() const;
            /// fills in pre- and post-change values, returns wether they differ
            virtual bool doFillChange(NodeChangeData& rChange, ChangeCount _ix) const;

            /// retrieve the old value from the given node
            virtual void doTest( view::Node const& rTarget);
            /// do apply the actual change
            virtual void doApply( view::Node const& rTarget);
        };
//-----------------------------------------------------------------------------

        /// represents a change to an element of a set (as a container)
        class SetElementChangeImpl
        : public SetChangeImpl
        {
            Path::Component m_aName;
        public:
            explicit SetElementChangeImpl(Path::Component const& aName, bool bNoCheck = false);

            /// the name of the element being changed
            Path::Component getFullElementName() const { return m_aName; }

            /// the name of the element being changed
            Name getElementName() const { return m_aName.getName(); }

        protected:
        /// virtual hooks for some of the public methods
            /// the path from base to 'affected' node - use element name
            virtual RelativePath doGetChangingNodePath(ChangeCount _ix) const;

            /// retrieve the old value from the given node
            virtual void doTest( view::Node const& rTarget);
            /// do apply the actual change
            virtual void doApply( view::Node const& rTarget);

        private:
            /// new overridable: retrieve the old value from a properly typed node
            virtual void doTestElement(view::SetNode const& _aNode, Name const& aName) = 0;
            /// new overridable: apply the change to a properly typed node
            virtual void doApplyToElement(view::SetNode const& _aNode, Name const& aName) = 0;
        };
//-----------------------------------------------------------------------------

        /// represents an insertion into a set of trees
        class SetInsertImpl
        : public SetElementChangeImpl
        {
            ElementTreeHolder m_aNewTree;
        public:
            explicit SetInsertImpl(Path::Component const& aName, ElementTreeHolder const& aNewTree, bool bNoCheck = false);

        protected:
            /// checks, if this represents an actual change (given whether the change has been applied or not)
            virtual bool doIsChange() const;
            /// fills in pre- and post-change values, returns wether they differ
            virtual bool doFillChange(NodeChangeData& rChange, ChangeCount _ix) const;

            /// new overridable: retrieve the old value from a properly typed node
            virtual void doTestElement(view::SetNode const& _aNode, Name const& aName);
            /// new overridable: apply the change to a properly typed node
            virtual void doApplyToElement(view::SetNode const& _aNode, Name const& aName);
        };
//-----------------------------------------------------------------------------

        /// represents a substitution within a set of trees
        class SetReplaceImpl
        : public SetElementChangeImpl
        {
            ElementTreeHolder m_aNewTree;
            ElementTreeHolder m_aOldTree;
        public:
            explicit SetReplaceImpl(Path::Component const& aName, ElementTreeHolder const& aNewTree);
            explicit SetReplaceImpl(Path::Component const& aName, ElementTreeHolder const& aNewTree, ElementTreeHolder const& aOldTree);

        protected:
            /// checks, if this represents an actual change (given whether the change has been applied or not)
            virtual bool doIsChange() const;
            /// fills in pre- and post-change values, returns wether they differ
            virtual bool doFillChange(NodeChangeData& rChange, ChangeCount _ix) const;

            /// new overridable: retrieve the old value from a properly typed node
            virtual void doTestElement(view::SetNode const& _aNode, Name const& aName);
            /// new overridable: apply the change to a properly typed node
            virtual void doApplyToElement(view::SetNode const& _aNode, Name const& aName);
        };
//-----------------------------------------------------------------------------

        /// represents a removal from of a set of trees
        class SetRemoveImpl
        : public SetElementChangeImpl
        {
            ElementTreeHolder m_aOldTree;
        public:
            explicit SetRemoveImpl(Path::Component const& aName);
            explicit SetRemoveImpl(Path::Component const& aName, ElementTreeHolder const& aOldTree);

        protected:
            /// checks, if this represents an actual change (given whether the change has been applied or not)
            virtual bool doIsChange() const;
            /// fills in pre- and post-change values, returns wether they differ
            virtual bool doFillChange(NodeChangeData& rChange, ChangeCount _ix) const;

            /// new overridable: retrieve the old value from a properly typed node
            virtual void doTestElement(view::SetNode const& _aNode, Name const& aName);
            /// new overridable: apply the change to a properly typed node
            virtual void doApplyToElement(view::SetNode const& _aNode, Name const& aName);
        };
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
    }
}

#endif // CONFIGMGR_CONFIGCHANGEIMPL_HXX_
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** No Commercial Usage
**
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

#include "environmentwidget.h"

#include <utils/detailswidget.h>
#include <utils/environment.h>
#include <utils/environmentmodel.h>

#include <QtCore/QString>
#include <QtGui/QHeaderView>
#include <QtGui/QPushButton>
#include <QtGui/QTableView>
#include <QtGui/QTextDocument> // for Qt::escape
#include <QtGui/QVBoxLayout>

namespace ProjectExplorer {

////
// EnvironmentWidget::EnvironmentWidget
////

class EnvironmentWidgetPrivate
{
public:
    Utils::EnvironmentModel *m_model;

    QString m_baseEnvironmentText;
    Utils::DetailsWidget *m_detailsContainer;
    QTableView *m_environmentView;
    QPushButton *m_editButton;
    QPushButton *m_addButton;
    QPushButton *m_resetButton;
    QPushButton *m_unsetButton;
};

EnvironmentWidget::EnvironmentWidget(QWidget *parent, QWidget *additionalDetailsWidget)
    : QWidget(parent), d(new EnvironmentWidgetPrivate)
{
    d->m_model = new Utils::EnvironmentModel();
    connect(d->m_model, SIGNAL(userChangesChanged()),
            this, SIGNAL(userChangesChanged()));
    connect(d->m_model, SIGNAL(modelReset()),
            this, SLOT(invalidateCurrentIndex()));

    connect(d->m_model, SIGNAL(focusIndex(QModelIndex)),
            this, SLOT(focusIndex(QModelIndex)));

    QVBoxLayout *vbox = new QVBoxLayout(this);
    vbox->setContentsMargins(0, 0, 0, 0);

    d->m_detailsContainer = new Utils::DetailsWidget(this);

    QWidget *details = new QWidget(d->m_detailsContainer);
    d->m_detailsContainer->setWidget(details);
    details->setVisible(false);

    QVBoxLayout *vbox2 = new QVBoxLayout(details);
    vbox2->setMargin(0);

    if (additionalDetailsWidget)
        vbox2->addWidget(additionalDetailsWidget);

    QHBoxLayout *horizontalLayout = new QHBoxLayout();
    horizontalLayout->setMargin(0);
    d->m_environmentView = new QTableView(this);
    d->m_environmentView->setModel(d->m_model);
    d->m_environmentView->setMinimumHeight(400);
    d->m_environmentView->setGridStyle(Qt::NoPen);
    d->m_environmentView->horizontalHeader()->setStretchLastSection(true);
    d->m_environmentView->horizontalHeader()->setResizeMode(0, QHeaderView::ResizeToContents);
    d->m_environmentView->horizontalHeader()->setHighlightSections(false);
    d->m_environmentView->verticalHeader()->hide();
    QFontMetrics fm(font());
    d->m_environmentView->verticalHeader()->setDefaultSectionSize(qMax(static_cast<int>(fm.height() * 1.2), fm.height() + 4));
    d->m_environmentView->setSelectionMode(QAbstractItemView::SingleSelection);
    horizontalLayout->addWidget(d->m_environmentView);

    QVBoxLayout *buttonLayout = new QVBoxLayout();

    d->m_editButton = new QPushButton(this);
    d->m_editButton->setText(tr("&Edit"));
    buttonLayout->addWidget(d->m_editButton);

    d->m_addButton = new QPushButton(this);
    d->m_addButton->setText(tr("&Add"));
    buttonLayout->addWidget(d->m_addButton);

    d->m_resetButton = new QPushButton(this);
    d->m_resetButton->setEnabled(false);
    d->m_resetButton->setText(tr("&Reset"));
    buttonLayout->addWidget(d->m_resetButton);

    d->m_unsetButton = new QPushButton(this);
    d->m_unsetButton->setEnabled(false);
    d->m_unsetButton->setText(tr("&Unset"));
    buttonLayout->addWidget(d->m_unsetButton);

    QSpacerItem *verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
    buttonLayout->addItem(verticalSpacer);
    horizontalLayout->addLayout(buttonLayout);
    vbox2->addLayout(horizontalLayout);

    vbox->addWidget(d->m_detailsContainer);

    connect(d->m_model, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
            this, SLOT(updateButtons()));

    connect(d->m_editButton, SIGNAL(clicked(bool)),
            this, SLOT(editEnvironmentButtonClicked()));
    connect(d->m_addButton, SIGNAL(clicked(bool)),
            this, SLOT(addEnvironmentButtonClicked()));
    connect(d->m_resetButton, SIGNAL(clicked(bool)),
            this, SLOT(removeEnvironmentButtonClicked()));
    connect(d->m_unsetButton, SIGNAL(clicked(bool)),
            this, SLOT(unsetEnvironmentButtonClicked()));
    connect(d->m_environmentView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
            this, SLOT(environmentCurrentIndexChanged(QModelIndex)));

    connect(d->m_model, SIGNAL(userChangesChanged()), this, SLOT(updateSummaryText()));
}

EnvironmentWidget::~EnvironmentWidget()
{
    delete d->m_model;
    d->m_model = 0;
}

void EnvironmentWidget::focusIndex(const QModelIndex &index)
{
    d->m_environmentView->setCurrentIndex(index);
    d->m_environmentView->setFocus();
}

void EnvironmentWidget::setBaseEnvironment(const Utils::Environment &env)
{
    d->m_model->setBaseEnvironment(env);
}

void EnvironmentWidget::setBaseEnvironmentText(const QString &text)
{
    d->m_baseEnvironmentText = text;
    updateSummaryText();
}

QList<Utils::EnvironmentItem> EnvironmentWidget::userChanges() const
{
    return d->m_model->userChanges();
}

void EnvironmentWidget::setUserChanges(const QList<Utils::EnvironmentItem> &list)
{
    d->m_model->setUserChanges(list);
    updateSummaryText();
}

void EnvironmentWidget::updateSummaryText()
{
    QString text;
    const QList<Utils::EnvironmentItem> &list = d->m_model->userChanges();
    foreach (const Utils::EnvironmentItem &item, list) {
        if (item.name != Utils::EnvironmentModel::tr("<VARIABLE>")) {
            text.append("
");
            if (item.unset)
                text.append(tr("Unset %1").arg(Qt::escape(item.name)));
            else
                text.append(tr("Set %1 to %2").arg(Qt::escape(item.name), Qt::escape(item.value)));
        }
    }

    if (text.isEmpty())
        text.prepend(tr("Using %1").arg(d->m_baseEnvironmentText));
    else
        text.prepend(tr("Using %1 and").arg(d->m_baseEnvironmentText));

    d->m_detailsContainer->setSummaryText(text);
}

void EnvironmentWidget::updateButtons()
{
    environmentCurrentIndexChanged(d->m_environmentView->currentIndex());
}

void EnvironmentWidget::editEnvironmentButtonClicked()
{
    d->m_environmentView->edit(d->m_environmentView->currentIndex());
}

void EnvironmentWidget::addEnvironmentButtonClicked()
{
    QModelIndex index = d->m_model->addVariable();
    d->m_environmentView->setCurrentIndex(index);
    d->m_environmentView->edit(index);
}

void EnvironmentWidget::removeEnvironmentButtonClicked()
{
    const QString &name = d->m_model->indexToVariable(d->m_environmentView->currentIndex());
    d->m_model->resetVariable(name);
}

// unset in Merged Environment Mode means, unset if it comes from the base environment
// or remove when it is just a change we added
void EnvironmentWidget::unsetEnvironmentButtonClicked()
{
    const QString &name = d->m_model->indexToVariable(d->m_environmentView->currentIndex());
    if (!d->m_model->canReset(name))
        d->m_model->resetVariable(name);
    else
        d->m_model->unsetVariable(name);
}

void EnvironmentWidget::environmentCurrentIndexChanged(const QModelIndex &current)
{
    if (current.isValid()) {
        d->m_editButton->setEnabled(true);
        const QString &name = d->m_model->indexToVariable(current);
        bool modified = d->m_model->canReset(name) && d->m_model->changes(name);
        bool unset = d->m_model->canUnset(name);
        d->m_resetButton->setEnabled(modified || unset);
        d->m_unsetButton->setEnabled(!unset);
    } else {
        d->m_editButton->setEnabled(false);
        d->m_resetButton->setEnabled(false);
        d->m_unsetButton->setEnabled(false);
    }
}

void EnvironmentWidget::invalidateCurrentIndex()
{
    environmentCurrentIndexChanged(QModelIndex());
}

} // namespace ProjectExplorer
<commit_msg>EnvironmentWidget: Sort the changes<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** No Commercial Usage
**
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

#include "environmentwidget.h"

#include <utils/detailswidget.h>
#include <utils/environment.h>
#include <utils/environmentmodel.h>

#include <QtCore/QString>
#include <QtGui/QHeaderView>
#include <QtGui/QPushButton>
#include <QtGui/QTableView>
#include <QtGui/QTextDocument> // for Qt::escape
#include <QtGui/QVBoxLayout>

namespace ProjectExplorer {

////
// EnvironmentWidget::EnvironmentWidget
////

class EnvironmentWidgetPrivate
{
public:
    Utils::EnvironmentModel *m_model;

    QString m_baseEnvironmentText;
    Utils::DetailsWidget *m_detailsContainer;
    QTableView *m_environmentView;
    QPushButton *m_editButton;
    QPushButton *m_addButton;
    QPushButton *m_resetButton;
    QPushButton *m_unsetButton;
};

EnvironmentWidget::EnvironmentWidget(QWidget *parent, QWidget *additionalDetailsWidget)
    : QWidget(parent), d(new EnvironmentWidgetPrivate)
{
    d->m_model = new Utils::EnvironmentModel();
    connect(d->m_model, SIGNAL(userChangesChanged()),
            this, SIGNAL(userChangesChanged()));
    connect(d->m_model, SIGNAL(modelReset()),
            this, SLOT(invalidateCurrentIndex()));

    connect(d->m_model, SIGNAL(focusIndex(QModelIndex)),
            this, SLOT(focusIndex(QModelIndex)));

    QVBoxLayout *vbox = new QVBoxLayout(this);
    vbox->setContentsMargins(0, 0, 0, 0);

    d->m_detailsContainer = new Utils::DetailsWidget(this);

    QWidget *details = new QWidget(d->m_detailsContainer);
    d->m_detailsContainer->setWidget(details);
    details->setVisible(false);

    QVBoxLayout *vbox2 = new QVBoxLayout(details);
    vbox2->setMargin(0);

    if (additionalDetailsWidget)
        vbox2->addWidget(additionalDetailsWidget);

    QHBoxLayout *horizontalLayout = new QHBoxLayout();
    horizontalLayout->setMargin(0);
    d->m_environmentView = new QTableView(this);
    d->m_environmentView->setModel(d->m_model);
    d->m_environmentView->setMinimumHeight(400);
    d->m_environmentView->setGridStyle(Qt::NoPen);
    d->m_environmentView->horizontalHeader()->setStretchLastSection(true);
    d->m_environmentView->horizontalHeader()->setResizeMode(0, QHeaderView::ResizeToContents);
    d->m_environmentView->horizontalHeader()->setHighlightSections(false);
    d->m_environmentView->verticalHeader()->hide();
    QFontMetrics fm(font());
    d->m_environmentView->verticalHeader()->setDefaultSectionSize(qMax(static_cast<int>(fm.height() * 1.2), fm.height() + 4));
    d->m_environmentView->setSelectionMode(QAbstractItemView::SingleSelection);
    horizontalLayout->addWidget(d->m_environmentView);

    QVBoxLayout *buttonLayout = new QVBoxLayout();

    d->m_editButton = new QPushButton(this);
    d->m_editButton->setText(tr("&Edit"));
    buttonLayout->addWidget(d->m_editButton);

    d->m_addButton = new QPushButton(this);
    d->m_addButton->setText(tr("&Add"));
    buttonLayout->addWidget(d->m_addButton);

    d->m_resetButton = new QPushButton(this);
    d->m_resetButton->setEnabled(false);
    d->m_resetButton->setText(tr("&Reset"));
    buttonLayout->addWidget(d->m_resetButton);

    d->m_unsetButton = new QPushButton(this);
    d->m_unsetButton->setEnabled(false);
    d->m_unsetButton->setText(tr("&Unset"));
    buttonLayout->addWidget(d->m_unsetButton);

    QSpacerItem *verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
    buttonLayout->addItem(verticalSpacer);
    horizontalLayout->addLayout(buttonLayout);
    vbox2->addLayout(horizontalLayout);

    vbox->addWidget(d->m_detailsContainer);

    connect(d->m_model, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
            this, SLOT(updateButtons()));

    connect(d->m_editButton, SIGNAL(clicked(bool)),
            this, SLOT(editEnvironmentButtonClicked()));
    connect(d->m_addButton, SIGNAL(clicked(bool)),
            this, SLOT(addEnvironmentButtonClicked()));
    connect(d->m_resetButton, SIGNAL(clicked(bool)),
            this, SLOT(removeEnvironmentButtonClicked()));
    connect(d->m_unsetButton, SIGNAL(clicked(bool)),
            this, SLOT(unsetEnvironmentButtonClicked()));
    connect(d->m_environmentView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
            this, SLOT(environmentCurrentIndexChanged(QModelIndex)));

    connect(d->m_model, SIGNAL(userChangesChanged()), this, SLOT(updateSummaryText()));
}

EnvironmentWidget::~EnvironmentWidget()
{
    delete d->m_model;
    d->m_model = 0;
}

void EnvironmentWidget::focusIndex(const QModelIndex &index)
{
    d->m_environmentView->setCurrentIndex(index);
    d->m_environmentView->setFocus();
}

void EnvironmentWidget::setBaseEnvironment(const Utils::Environment &env)
{
    d->m_model->setBaseEnvironment(env);
}

void EnvironmentWidget::setBaseEnvironmentText(const QString &text)
{
    d->m_baseEnvironmentText = text;
    updateSummaryText();
}

QList<Utils::EnvironmentItem> EnvironmentWidget::userChanges() const
{
    return d->m_model->userChanges();
}

void EnvironmentWidget::setUserChanges(const QList<Utils::EnvironmentItem> &list)
{
    d->m_model->setUserChanges(list);
    updateSummaryText();
}

bool sortEnvironmentItem(const Utils::EnvironmentItem &a, const Utils::EnvironmentItem &b)
{
    return a.name < b.name;
}

void EnvironmentWidget::updateSummaryText()
{
    QList<Utils::EnvironmentItem> list = d->m_model->userChanges();
    qSort(list.begin(), list.end(), &sortEnvironmentItem);

    QString text;
    foreach (const Utils::EnvironmentItem &item, list) {
        if (item.name != Utils::EnvironmentModel::tr("<VARIABLE>")) {
            text.append("
");
            if (item.unset)
                text.append(tr("Unset %1").arg(Qt::escape(item.name)));
            else
                text.append(tr("Set %1 to %2").arg(Qt::escape(item.name), Qt::escape(item.value)));
        }
    }

    if (text.isEmpty())
        text.prepend(tr("Using %1").arg(d->m_baseEnvironmentText));
    else
        text.prepend(tr("Using %1 and").arg(d->m_baseEnvironmentText));

    d->m_detailsContainer->setSummaryText(text);
}

void EnvironmentWidget::updateButtons()
{
    environmentCurrentIndexChanged(d->m_environmentView->currentIndex());
}

void EnvironmentWidget::editEnvironmentButtonClicked()
{
    d->m_environmentView->edit(d->m_environmentView->currentIndex());
}

void EnvironmentWidget::addEnvironmentButtonClicked()
{
    QModelIndex index = d->m_model->addVariable();
    d->m_environmentView->setCurrentIndex(index);
    d->m_environmentView->edit(index);
}

void EnvironmentWidget::removeEnvironmentButtonClicked()
{
    const QString &name = d->m_model->indexToVariable(d->m_environmentView->currentIndex());
    d->m_model->resetVariable(name);
}

// unset in Merged Environment Mode means, unset if it comes from the base environment
// or remove when it is just a change we added
void EnvironmentWidget::unsetEnvironmentButtonClicked()
{
    const QString &name = d->m_model->indexToVariable(d->m_environmentView->currentIndex());
    if (!d->m_model->canReset(name))
        d->m_model->resetVariable(name);
    else
        d->m_model->unsetVariable(name);
}

void EnvironmentWidget::environmentCurrentIndexChanged(const QModelIndex &current)
{
    if (current.isValid()) {
        d->m_editButton->setEnabled(true);
        const QString &name = d->m_model->indexToVariable(current);
        bool modified = d->m_model->canReset(name) && d->m_model->changes(name);
        bool unset = d->m_model->canUnset(name);
        d->m_resetButton->setEnabled(modified || unset);
        d->m_unsetButton->setEnabled(!unset);
    } else {
        d->m_editButton->setEnabled(false);
        d->m_resetButton->setEnabled(false);
        d->m_unsetButton->setEnabled(false);
    }
}

void EnvironmentWidget::invalidateCurrentIndex()
{
    environmentCurrentIndexChanged(QModelIndex());
}

} // namespace ProjectExplorer
<|endoftext|>


<commit_before>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2013 Mohammed Nafees <nafees.technocool@gmail.com>
//

#include "ArrowDiscWidget.h"

#include "MarbleWidget.h"

#include <QtGui/QPainter>
#include <QtGui/QMouseEvent>
#include <QtGui/QPixmapCache>
#include <QtGui/QPainterPath>

namespace Marble
{

ArrowDiscWidget::ArrowDiscWidget( QWidget *parent ) :
    QWidget( parent ),
    m_arrowPressed( Qt::NoArrow ),
    m_repetitions( 0 ),
    m_marbleWidget( 0 ),
    m_imagePath( "marble/navigation/navigational_arrows" )
{
    setMouseTracking( true );

    m_initialPressTimer.setSingleShot( true );
    connect( &m_initialPressTimer, SIGNAL(timeout()), SLOT(startPressRepeat()) );
    connect( &m_repeatPressTimer, SIGNAL(timeout()), SLOT(repeatPress()) );
}

ArrowDiscWidget::~ArrowDiscWidget()
{
    QPixmapCache::remove( "marble/navigation/navigational_arrows" );
    QPixmapCache::remove( "marble/navigation/navigational_arrows_hover_bottom" );
    QPixmapCache::remove( "marble/navigation/navigational_arrows_hover_left" );
    QPixmapCache::remove( "marble/navigation/navigational_arrows_hover_right" );
    QPixmapCache::remove( "marble/navigation/navigational_arrows_hover_top" );
    QPixmapCache::remove( "marble/navigation/navigational_arrows_press_bottom" );
    QPixmapCache::remove( "marble/navigation/navigational_arrows_press_left" );
    QPixmapCache::remove( "marble/navigation/navigational_arrows_press_right" );
    QPixmapCache::remove( "marble/navigation/navigational_arrows_press_top" );
}

void ArrowDiscWidget::setMarbleWidget( MarbleWidget *marbleWidget )
{
    m_marbleWidget = marbleWidget;
}

QPixmap ArrowDiscWidget::pixmap( const QString &id )
{
    QPixmap result;
    if ( !QPixmapCache::find( id, result ) ) {
        result = QPixmap( QString( ":/%1.png" ).arg( id ) );
        QPixmapCache::insert( id, result );
    }
    return result;
}

void ArrowDiscWidget::mousePressEvent( QMouseEvent *mouseEvent )
{
    if ( mouseEvent->button() == Qt::LeftButton ) {

        if ( !m_initialPressTimer.isActive() && !m_repeatPressTimer.isActive() ) {
            m_repetitions = 0;
            m_initialPressTimer.start( 300 );
        }

        m_arrowPressed = arrowUnderMouse( mouseEvent->pos() );
        switch ( m_arrowPressed ) {
        case Qt::NoArrow:
            m_imagePath = "marble/navigation/navigational_arrows";
            break;
        case Qt::UpArrow:
            m_imagePath = "marble/navigation/navigational_arrows_press_top";
            m_marbleWidget->moveUp();
            break;
        case Qt::DownArrow:
            m_imagePath = "marble/navigation/navigational_arrows_press_bottom";
            m_marbleWidget->moveDown();
            break;
        case Qt::LeftArrow:
            m_imagePath = "marble/navigation/navigational_arrows_press_left";
            m_marbleWidget->moveLeft();
            break;
        case Qt::RightArrow:
            m_imagePath = "marble/navigation/navigational_arrows_press_right";
            m_marbleWidget->moveRight();
            break;
        }
    }

    repaint();
}

void ArrowDiscWidget::mouseReleaseEvent( QMouseEvent *mouseEvent )
{
    m_initialPressTimer.stop();
    m_repeatPressTimer.stop();
    mouseMoveEvent( mouseEvent );
}

void ArrowDiscWidget::leaveEvent( QEvent* )
{
    if ( m_imagePath != "marble/navigation/navigational_arrows" ) {
        m_imagePath = "marble/navigation/navigational_arrows";
        repaint();
    }
}

void ArrowDiscWidget::startPressRepeat()
{
    repeatPress();

    if ( m_arrowPressed != Qt::NoArrow ) {
        m_repeatPressTimer.start( 100 );
    }
}

void ArrowDiscWidget::repeatPress()
{
    if ( m_repetitions <= 200 ) {
        ++m_repetitions;
        switch ( m_arrowPressed ) {
        case Qt::NoArrow:
            break;
        case Qt::UpArrow:
            m_marbleWidget->moveUp();
            break;
        case Qt::DownArrow:
            m_marbleWidget->moveDown();
            break;
        case Qt::LeftArrow:
            m_marbleWidget->moveLeft();
            break;
        case Qt::RightArrow:
            m_marbleWidget->moveRight();
            break;
        }
    } else {
        m_repeatPressTimer.stop();
    }
}

void ArrowDiscWidget::mouseMoveEvent( QMouseEvent *mouseEvent )
{
    QString const oldPath = m_imagePath;
    switch ( arrowUnderMouse( mouseEvent->pos() ) ) {
    case Qt::NoArrow:
        m_imagePath = "marble/navigation/navigational_arrows";
        break;
    case Qt::UpArrow:
        m_imagePath = "marble/navigation/navigational_arrows_hover_top";
        m_arrowPressed = Qt::UpArrow;
        break;
    case Qt::DownArrow:
        m_imagePath = "marble/navigation/navigational_arrows_hover_bottom";
        m_arrowPressed = Qt::DownArrow;
        break;
    case Qt::LeftArrow:
        m_imagePath = "marble/navigation/navigational_arrows_hover_left";
        m_arrowPressed = Qt::LeftArrow;
        break;
    case Qt::RightArrow:
        m_imagePath = "marble/navigation/navigational_arrows_hover_right";
        m_arrowPressed = Qt::RightArrow;
        break;
    }

    if ( m_imagePath != oldPath ) {
        repaint();
    }
}

void ArrowDiscWidget::repaint()
{
    emit repaintNeeded();
}

Qt::ArrowType ArrowDiscWidget::arrowUnderMouse(const QPoint &position) const
{
    const int min_radius_pow2 = 5*5;
    const int max_radius_pow2 = 28*28;

    // mouse coordinates relative to widget topleft
    int mx = position.x();
    int my = position.y();

    // center coordinates relative to widget topleft
    int cx = width()/2;
    int cy = height()/2;

    int px = mx - cx;
    int py = my - cy;

    int const distance_pow2 = px*px + py*py;

    if ( distance_pow2 >= min_radius_pow2 && distance_pow2 <= max_radius_pow2 ) {
        int const angle = int( atan2( py, px ) * RAD2DEG );
        Q_ASSERT( -180 <= angle && angle <= 180 );

        if ( angle >= 135 || angle < -135 ) {
            return Qt::LeftArrow;
        } else if ( angle < -45 ) {
            return Qt::UpArrow;
        } else if ( angle < 45 ) {
            return Qt::RightArrow;
        } else {
            return Qt::DownArrow;
        }
    }

    return Qt::NoArrow;
}

void ArrowDiscWidget::paintEvent( QPaintEvent * )
{
    Q_ASSERT( !pixmap( m_imagePath ).isNull() );
    QPainter painter( this );
    painter.drawPixmap( 0, 0, pixmap( m_imagePath ) );
    painter.end();
}

}

#include "ArrowDiscWidget.moc"
<commit_msg>Leaving the widget stops press repeats.<commit_after>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2013 Mohammed Nafees <nafees.technocool@gmail.com>
//

#include "ArrowDiscWidget.h"

#include "MarbleWidget.h"

#include <QtGui/QPainter>
#include <QtGui/QMouseEvent>
#include <QtGui/QPixmapCache>
#include <QtGui/QPainterPath>

namespace Marble
{

ArrowDiscWidget::ArrowDiscWidget( QWidget *parent ) :
    QWidget( parent ),
    m_arrowPressed( Qt::NoArrow ),
    m_repetitions( 0 ),
    m_marbleWidget( 0 ),
    m_imagePath( "marble/navigation/navigational_arrows" )
{
    setMouseTracking( true );

    m_initialPressTimer.setSingleShot( true );
    connect( &m_initialPressTimer, SIGNAL(timeout()), SLOT(startPressRepeat()) );
    connect( &m_repeatPressTimer, SIGNAL(timeout()), SLOT(repeatPress()) );
}

ArrowDiscWidget::~ArrowDiscWidget()
{
    QPixmapCache::remove( "marble/navigation/navigational_arrows" );
    QPixmapCache::remove( "marble/navigation/navigational_arrows_hover_bottom" );
    QPixmapCache::remove( "marble/navigation/navigational_arrows_hover_left" );
    QPixmapCache::remove( "marble/navigation/navigational_arrows_hover_right" );
    QPixmapCache::remove( "marble/navigation/navigational_arrows_hover_top" );
    QPixmapCache::remove( "marble/navigation/navigational_arrows_press_bottom" );
    QPixmapCache::remove( "marble/navigation/navigational_arrows_press_left" );
    QPixmapCache::remove( "marble/navigation/navigational_arrows_press_right" );
    QPixmapCache::remove( "marble/navigation/navigational_arrows_press_top" );
}

void ArrowDiscWidget::setMarbleWidget( MarbleWidget *marbleWidget )
{
    m_marbleWidget = marbleWidget;
}

QPixmap ArrowDiscWidget::pixmap( const QString &id )
{
    QPixmap result;
    if ( !QPixmapCache::find( id, result ) ) {
        result = QPixmap( QString( ":/%1.png" ).arg( id ) );
        QPixmapCache::insert( id, result );
    }
    return result;
}

void ArrowDiscWidget::mousePressEvent( QMouseEvent *mouseEvent )
{
    if ( mouseEvent->button() == Qt::LeftButton ) {

        if ( !m_initialPressTimer.isActive() && !m_repeatPressTimer.isActive() ) {
            m_repetitions = 0;
            m_initialPressTimer.start( 300 );
        }

        m_arrowPressed = arrowUnderMouse( mouseEvent->pos() );
        switch ( m_arrowPressed ) {
        case Qt::NoArrow:
            m_imagePath = "marble/navigation/navigational_arrows";
            break;
        case Qt::UpArrow:
            m_imagePath = "marble/navigation/navigational_arrows_press_top";
            m_marbleWidget->moveUp();
            break;
        case Qt::DownArrow:
            m_imagePath = "marble/navigation/navigational_arrows_press_bottom";
            m_marbleWidget->moveDown();
            break;
        case Qt::LeftArrow:
            m_imagePath = "marble/navigation/navigational_arrows_press_left";
            m_marbleWidget->moveLeft();
            break;
        case Qt::RightArrow:
            m_imagePath = "marble/navigation/navigational_arrows_press_right";
            m_marbleWidget->moveRight();
            break;
        }
    }

    repaint();
}

void ArrowDiscWidget::mouseReleaseEvent( QMouseEvent *mouseEvent )
{
    m_initialPressTimer.stop();
    m_repeatPressTimer.stop();
    mouseMoveEvent( mouseEvent );
}

void ArrowDiscWidget::leaveEvent( QEvent* )
{
    if ( m_imagePath != "marble/navigation/navigational_arrows" ) {
        m_imagePath = "marble/navigation/navigational_arrows";
        repaint();
    }

    m_initialPressTimer.stop();
    m_repeatPressTimer.stop();
}

void ArrowDiscWidget::startPressRepeat()
{
    repeatPress();

    if ( m_arrowPressed != Qt::NoArrow ) {
        m_repeatPressTimer.start( 100 );
    }
}

void ArrowDiscWidget::repeatPress()
{
    if ( m_repetitions <= 200 ) {
        ++m_repetitions;
        switch ( m_arrowPressed ) {
        case Qt::NoArrow:
            break;
        case Qt::UpArrow:
            m_marbleWidget->moveUp();
            break;
        case Qt::DownArrow:
            m_marbleWidget->moveDown();
            break;
        case Qt::LeftArrow:
            m_marbleWidget->moveLeft();
            break;
        case Qt::RightArrow:
            m_marbleWidget->moveRight();
            break;
        }
    } else {
        m_repeatPressTimer.stop();
    }
}

void ArrowDiscWidget::mouseMoveEvent( QMouseEvent *mouseEvent )
{
    QString const oldPath = m_imagePath;
    switch ( arrowUnderMouse( mouseEvent->pos() ) ) {
    case Qt::NoArrow:
        m_imagePath = "marble/navigation/navigational_arrows";
        break;
    case Qt::UpArrow:
        m_imagePath = "marble/navigation/navigational_arrows_hover_top";
        m_arrowPressed = Qt::UpArrow;
        break;
    case Qt::DownArrow:
        m_imagePath = "marble/navigation/navigational_arrows_hover_bottom";
        m_arrowPressed = Qt::DownArrow;
        break;
    case Qt::LeftArrow:
        m_imagePath = "marble/navigation/navigational_arrows_hover_left";
        m_arrowPressed = Qt::LeftArrow;
        break;
    case Qt::RightArrow:
        m_imagePath = "marble/navigation/navigational_arrows_hover_right";
        m_arrowPressed = Qt::RightArrow;
        break;
    }

    if ( m_imagePath != oldPath ) {
        repaint();
    }
}

void ArrowDiscWidget::repaint()
{
    emit repaintNeeded();
}

Qt::ArrowType ArrowDiscWidget::arrowUnderMouse(const QPoint &position) const
{
    const int min_radius_pow2 = 5*5;
    const int max_radius_pow2 = 28*28;

    // mouse coordinates relative to widget topleft
    int mx = position.x();
    int my = position.y();

    // center coordinates relative to widget topleft
    int cx = width()/2;
    int cy = height()/2;

    int px = mx - cx;
    int py = my - cy;

    int const distance_pow2 = px*px + py*py;

    if ( distance_pow2 >= min_radius_pow2 && distance_pow2 <= max_radius_pow2 ) {
        int const angle = int( atan2( py, px ) * RAD2DEG );
        Q_ASSERT( -180 <= angle && angle <= 180 );

        if ( angle >= 135 || angle < -135 ) {
            return Qt::LeftArrow;
        } else if ( angle < -45 ) {
            return Qt::UpArrow;
        } else if ( angle < 45 ) {
            return Qt::RightArrow;
        } else {
            return Qt::DownArrow;
        }
    }

    return Qt::NoArrow;
}

void ArrowDiscWidget::paintEvent( QPaintEvent * )
{
    Q_ASSERT( !pixmap( m_imagePath ).isNull() );
    QPainter painter( this );
    painter.drawPixmap( 0, 0, pixmap( m_imagePath ) );
    painter.end();
}

}

#include "ArrowDiscWidget.moc"
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "snippeteditor.h"

#include <texteditor/basetextdocument.h>
#include <texteditor/texteditorconstants.h>
#include <texteditor/normalindenter.h>

#include <QtGui/QTextDocument>
#include <QtGui/QFocusEvent>

using namespace TextEditor;

/*!
    \class TextEditor::SnippetEditorWidget
    \brief The SnippetEditorWidget class is a lightweight editor for code snippets
    with basic support for syntax highlighting, indentation, and others.
    \ingroup Snippets
*/

SnippetEditor::SnippetEditor(SnippetEditorWidget *editor)
    : BaseTextEditor(editor)
{
    setContext(Core::Context(Constants::SNIPPET_EDITOR_ID, Constants::C_TEXTEDITOR));
}

QString SnippetEditor::id() const
{
    return Constants::SNIPPET_EDITOR_ID;
}

SnippetEditorWidget::SnippetEditorWidget(QWidget *parent) : BaseTextEditorWidget(parent)
{
    setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
    setHighlightCurrentLine(false);
    setLineNumbersVisible(false);
    setParenthesesMatchingEnabled(true);
}

void SnippetEditorWidget::setSyntaxHighlighter(TextEditor::SyntaxHighlighter *highlighter)
{
    baseTextDocument()->setSyntaxHighlighter(highlighter);
}

void SnippetEditorWidget::focusOutEvent(QFocusEvent *event)
{
    if (event->reason() != Qt::ActiveWindowFocusReason && document()->isModified()) {
        document()->setModified(false);
        emit snippetContentChanged();
    }
}

BaseTextEditor *SnippetEditorWidget::createEditor()
{
    return new SnippetEditor(this);
}
<commit_msg>Pass focusOutEvent to the superclass<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "snippeteditor.h"

#include <texteditor/basetextdocument.h>
#include <texteditor/texteditorconstants.h>
#include <texteditor/normalindenter.h>

#include <QtGui/QTextDocument>
#include <QtGui/QFocusEvent>

using namespace TextEditor;

/*!
    \class TextEditor::SnippetEditorWidget
    \brief The SnippetEditorWidget class is a lightweight editor for code snippets
    with basic support for syntax highlighting, indentation, and others.
    \ingroup Snippets
*/

SnippetEditor::SnippetEditor(SnippetEditorWidget *editor)
    : BaseTextEditor(editor)
{
    setContext(Core::Context(Constants::SNIPPET_EDITOR_ID, Constants::C_TEXTEDITOR));
}

QString SnippetEditor::id() const
{
    return Constants::SNIPPET_EDITOR_ID;
}

SnippetEditorWidget::SnippetEditorWidget(QWidget *parent) : BaseTextEditorWidget(parent)
{
    setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
    setHighlightCurrentLine(false);
    setLineNumbersVisible(false);
    setParenthesesMatchingEnabled(true);
}

void SnippetEditorWidget::setSyntaxHighlighter(TextEditor::SyntaxHighlighter *highlighter)
{
    baseTextDocument()->setSyntaxHighlighter(highlighter);
}

void SnippetEditorWidget::focusOutEvent(QFocusEvent *event)
{
    if (event->reason() != Qt::ActiveWindowFocusReason && document()->isModified()) {
        document()->setModified(false);
        emit snippetContentChanged();
    }
    BaseTextEditorWidget::focusOutEvent(event);
}

BaseTextEditor *SnippetEditorWidget::createEditor()
{
    return new SnippetEditor(this);
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "private/qparallelanimationgroupjob_p.h"
#include "private/qanimationjobutil_p.h"

QT_BEGIN_NAMESPACE

QParallelAnimationGroupJob::QParallelAnimationGroupJob()
    : QAnimationGroupJob()
    , m_previousLoop(0)
    , m_previousCurrentTime(0)
{
}

QParallelAnimationGroupJob::~QParallelAnimationGroupJob()
{
}

int QParallelAnimationGroupJob::duration() const
{
    int ret = 0;

    for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
        int currentDuration = animation->totalDuration();
        //this takes care of the case where a parallel animation group has controlled and uncontrolled
        //animations, and the uncontrolled stop before the controlled
        if (currentDuration == -1)
            currentDuration = uncontrolledAnimationFinishTime(animation);
        if (currentDuration == -1)
            return -1; // Undetermined length

        ret = qMax(ret, currentDuration);
    }

    return ret;
}

void QParallelAnimationGroupJob::updateCurrentTime(int /*currentTime*/)
{
    if (!firstChild())
        return;

    if (m_currentLoop > m_previousLoop) {
        // simulate completion of the loop
        int dura = duration();
        if (dura > 0) {
            for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
                if (!animation->isStopped())
                    RETURN_IF_DELETED(animation->setCurrentTime(dura));   // will stop
            }
        }
    } else if (m_currentLoop < m_previousLoop) {
        // simulate completion of the loop seeking backwards
        for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
            //we need to make sure the animation is in the right state
            //and then rewind it
            applyGroupState(animation);
            RETURN_IF_DELETED(animation->setCurrentTime(0));
            animation->stop();
        }
    }

    // finally move into the actual time of the current loop
    for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
        const int dura = animation->totalDuration();
        //if the loopcount is bigger we should always start all animations
        if (m_currentLoop > m_previousLoop
            //if we're at the end of the animation, we need to start it if it wasn't already started in this loop
            //this happens in Backward direction where not all animations are started at the same time
            || shouldAnimationStart(animation, m_previousCurrentTime > dura /*startIfAtEnd*/)) {
            applyGroupState(animation);
        }

        if (animation->state() == state()) {
            RETURN_IF_DELETED(animation->setCurrentTime(m_currentTime));
            if (dura > 0 && m_currentTime > dura)
                animation->stop();
        }
    }
    m_previousLoop = m_currentLoop;
    m_previousCurrentTime = m_currentTime;
}

void QParallelAnimationGroupJob::updateState(QAbstractAnimationJob::State newState,
                                          QAbstractAnimationJob::State oldState)
{
    QAnimationGroupJob::updateState(newState, oldState);

    switch (newState) {
    case Stopped:
        for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
            animation->stop();
        break;
    case Paused:
        for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
            if (animation->isRunning())
                animation->pause();
        break;
    case Running:
        for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
            if (oldState == Stopped)
                animation->stop();
            resetUncontrolledAnimationFinishTime(animation);
            animation->setDirection(m_direction);
            if (shouldAnimationStart(animation, oldState == Stopped))
                animation->start();
        }
        break;
    }
}

bool QParallelAnimationGroupJob::shouldAnimationStart(QAbstractAnimationJob *animation, bool startIfAtEnd) const
{
    const int dura = animation->totalDuration();

    if (dura == -1)
        return uncontrolledAnimationFinishTime(animation) == -1;

    if (startIfAtEnd)
        return m_currentTime <= dura;
    if (m_direction == Forward)
        return m_currentTime < dura;
    else //direction == Backward
        return m_currentTime && m_currentTime <= dura;
}

void QParallelAnimationGroupJob::applyGroupState(QAbstractAnimationJob *animation)
{
    switch (m_state)
    {
    case Running:
        animation->start();
        break;
    case Paused:
        animation->pause();
        break;
    case Stopped:
    default:
        break;
    }
}

void QParallelAnimationGroupJob::updateDirection(QAbstractAnimationJob::Direction direction)
{
    //we need to update the direction of the current animation
    if (!isStopped()) {
        for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
            animation->setDirection(direction);
        }
    } else {
        if (direction == Forward) {
            m_previousLoop = 0;
            m_previousCurrentTime = 0;
        } else {
            // Looping backwards with loopCount == -1 does not really work well...
            m_previousLoop = (m_loopCount == -1 ? 0 : m_loopCount - 1);
            m_previousCurrentTime = duration();
        }
    }
}

void QParallelAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimationJob *animation)
{
    Q_ASSERT(animation && (animation->duration() == -1 || animation->loopCount() < 0));
    int uncontrolledRunningCount = 0;

    for (QAbstractAnimationJob *child = firstChild(); child; child = child->nextSibling()) {
        if (child == animation) {
            setUncontrolledAnimationFinishTime(animation, animation->currentTime());
        } else if (child->duration() == -1 || child->loopCount() < 0) {
            if (uncontrolledAnimationFinishTime(child) == -1)
                ++uncontrolledRunningCount;
        }
    }

    if (uncontrolledRunningCount > 0)
        return;

    int maxDuration = 0;
    for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
        maxDuration = qMax(maxDuration, animation->totalDuration());

    if (m_currentTime >= maxDuration)
        stop();
}

QT_END_NAMESPACE

<commit_msg>Avoid using previously declared variables<commit_after>/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "private/qparallelanimationgroupjob_p.h"
#include "private/qanimationjobutil_p.h"

QT_BEGIN_NAMESPACE

QParallelAnimationGroupJob::QParallelAnimationGroupJob()
    : QAnimationGroupJob()
    , m_previousLoop(0)
    , m_previousCurrentTime(0)
{
}

QParallelAnimationGroupJob::~QParallelAnimationGroupJob()
{
}

int QParallelAnimationGroupJob::duration() const
{
    int ret = 0;

    for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
        int currentDuration = animation->totalDuration();
        //this takes care of the case where a parallel animation group has controlled and uncontrolled
        //animations, and the uncontrolled stop before the controlled
        if (currentDuration == -1)
            currentDuration = uncontrolledAnimationFinishTime(animation);
        if (currentDuration == -1)
            return -1; // Undetermined length

        ret = qMax(ret, currentDuration);
    }

    return ret;
}

void QParallelAnimationGroupJob::updateCurrentTime(int /*currentTime*/)
{
    if (!firstChild())
        return;

    if (m_currentLoop > m_previousLoop) {
        // simulate completion of the loop
        int dura = duration();
        if (dura > 0) {
            for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
                if (!animation->isStopped())
                    RETURN_IF_DELETED(animation->setCurrentTime(dura));   // will stop
            }
        }
    } else if (m_currentLoop < m_previousLoop) {
        // simulate completion of the loop seeking backwards
        for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
            //we need to make sure the animation is in the right state
            //and then rewind it
            applyGroupState(animation);
            RETURN_IF_DELETED(animation->setCurrentTime(0));
            animation->stop();
        }
    }

    // finally move into the actual time of the current loop
    for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
        const int dura = animation->totalDuration();
        //if the loopcount is bigger we should always start all animations
        if (m_currentLoop > m_previousLoop
            //if we're at the end of the animation, we need to start it if it wasn't already started in this loop
            //this happens in Backward direction where not all animations are started at the same time
            || shouldAnimationStart(animation, m_previousCurrentTime > dura /*startIfAtEnd*/)) {
            applyGroupState(animation);
        }

        if (animation->state() == state()) {
            RETURN_IF_DELETED(animation->setCurrentTime(m_currentTime));
            if (dura > 0 && m_currentTime > dura)
                animation->stop();
        }
    }
    m_previousLoop = m_currentLoop;
    m_previousCurrentTime = m_currentTime;
}

void QParallelAnimationGroupJob::updateState(QAbstractAnimationJob::State newState,
                                          QAbstractAnimationJob::State oldState)
{
    QAnimationGroupJob::updateState(newState, oldState);

    switch (newState) {
    case Stopped:
        for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
            animation->stop();
        break;
    case Paused:
        for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
            if (animation->isRunning())
                animation->pause();
        break;
    case Running:
        for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
            if (oldState == Stopped)
                animation->stop();
            resetUncontrolledAnimationFinishTime(animation);
            animation->setDirection(m_direction);
            if (shouldAnimationStart(animation, oldState == Stopped))
                animation->start();
        }
        break;
    }
}

bool QParallelAnimationGroupJob::shouldAnimationStart(QAbstractAnimationJob *animation, bool startIfAtEnd) const
{
    const int dura = animation->totalDuration();

    if (dura == -1)
        return uncontrolledAnimationFinishTime(animation) == -1;

    if (startIfAtEnd)
        return m_currentTime <= dura;
    if (m_direction == Forward)
        return m_currentTime < dura;
    else //direction == Backward
        return m_currentTime && m_currentTime <= dura;
}

void QParallelAnimationGroupJob::applyGroupState(QAbstractAnimationJob *animation)
{
    switch (m_state)
    {
    case Running:
        animation->start();
        break;
    case Paused:
        animation->pause();
        break;
    case Stopped:
    default:
        break;
    }
}

void QParallelAnimationGroupJob::updateDirection(QAbstractAnimationJob::Direction direction)
{
    //we need to update the direction of the current animation
    if (!isStopped()) {
        for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
            animation->setDirection(direction);
        }
    } else {
        if (direction == Forward) {
            m_previousLoop = 0;
            m_previousCurrentTime = 0;
        } else {
            // Looping backwards with loopCount == -1 does not really work well...
            m_previousLoop = (m_loopCount == -1 ? 0 : m_loopCount - 1);
            m_previousCurrentTime = duration();
        }
    }
}

void QParallelAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimationJob *animation)
{
    Q_ASSERT(animation && (animation->duration() == -1 || animation->loopCount() < 0));
    int uncontrolledRunningCount = 0;

    for (QAbstractAnimationJob *child = firstChild(); child; child = child->nextSibling()) {
        if (child == animation) {
            setUncontrolledAnimationFinishTime(animation, animation->currentTime());
        } else if (child->duration() == -1 || child->loopCount() < 0) {
            if (uncontrolledAnimationFinishTime(child) == -1)
                ++uncontrolledRunningCount;
        }
    }

    if (uncontrolledRunningCount > 0)
        return;

    int maxDuration = 0;
    for (QAbstractAnimationJob *job = firstChild(); job; job = job->nextSibling())
        maxDuration = qMax(maxDuration, job->totalDuration());

    if (m_currentTime >= maxDuration)
        stop();
}

QT_END_NAMESPACE

<|endoftext|>