FDO API Reference Feature Data Objects

SchemaCollection.h

Go to the documentation of this file.
00001 #ifndef _SCHEMACOLLECTION_H_
00002 #define _SCHEMACOLLECTION_H_
00003 
00004 //
00005 // Copyright (C) 2004-2006  Autodesk, Inc.
00006 // 
00007 // This library is free software; you can redistribute it and/or
00008 // modify it under the terms of version 2.1 of the GNU Lesser
00009 // General Public License as published by the Free Software Foundation.
00010 // 
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 // Lesser General Public License for more details.
00015 // 
00016 // You should have received a copy of the GNU Lesser General Public
00017 // License along with this library; if not, write to the Free Software
00018 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019 //
00020 
00021 #ifdef _WIN32
00022 #pragma once
00023 #endif
00024 
00025 #include <FdoStd.h>
00026 #include <Common/NamedCollection.h>
00027 #include <Fdo/Schema/SchemaElement.h>
00028 #include <Fdo/Schema/SchemaException.h>
00029 
00030 /// \brief
00031 /// FdoSchemaCollection is an abstract template class that is used to
00032 /// define schema collections; FdoClassCollection, FdoDatapropertyDefinitionCollection, 
00033 /// FdoFeatureClassCollection, FdoFeatureSchemaCollection, FdoPropertyDefinitionCollection, and
00034 /// FdoRelationCollection.
00035 template <class OBJ> class FdoSchemaCollection : public FdoNamedCollection<OBJ, FdoSchemaException>
00036 {
00037 
00038 protected:
00039 /// \cond DOXYGEN-IGNORE
00040     FdoSchemaCollection()
00041     {
00042     }
00043 
00044     FdoSchemaCollection(FdoSchemaElement* parent) : FdoNamedCollection<OBJ, FdoSchemaException>()
00045     {
00046         m_parent = parent;
00047         m_changeInfoState = 0;
00048         m_listCHANGED = NULL;
00049         m_sizeCHANGED = 0;
00050         if ( m_parent ) 
00051             m_setItemParent = true;
00052         else
00053             m_setItemParent = false;
00054     }
00055 
00056     virtual ~FdoSchemaCollection()
00057     {
00058         if (m_setItemParent && m_parent)
00059         {
00060             for(FdoInt32 i = 0; i < FdoNamedCollection<OBJ, FdoSchemaException>::GetCount(); i++)
00061             {
00062                 OBJ*    pitem = FdoNamedCollection<OBJ, FdoSchemaException>::GetItem(i);
00063 
00064             /// When the collection disappears, the ownership does too.
00065             /// So NULL out the parent.  This is necessary because the
00066             /// parent reference within items is not refcounted to avoid
00067             /// circular references/memory leaks.
00068             /// 
00069             /// \warning
00070             /// The pitem->GetParent() should always equal m_parent, but we cannot verify this
00071             /// because the call to pitem->GetParent() might AddRef() an item that has already
00072             /// been disposed.  So we just NULL it out.
00073             /// 
00074                 pitem->SetParent(NULL);
00075                 FDO_SAFE_RELEASE(pitem);
00076             }
00077         }
00078 
00079         /// Dispose of change information
00080         if (m_listCHANGED)
00081         {
00082             for (FdoInt32 i=0; i < m_sizeCHANGED; i++)
00083             {
00084                 FDO_SAFE_RELEASE(m_listCHANGED[i]);
00085             }
00086             delete [] m_listCHANGED;
00087             m_listCHANGED = NULL;
00088         }
00089     }
00090 /// \endcond
00091 
00092 public:
00093     /// \brief
00094     /// Sets the item in the collection at the specified index to the specified value. Throws an invalid argument exception if the index is out of range.
00095     /// 
00096     /// \param index 
00097     /// Input index
00098     /// \param value 
00099     /// Input value
00100     /// 
00101     /// \return
00102     /// Returns nothing
00103     /// 
00104     FDO_API virtual void SetItem(FdoInt32 index, OBJ* value)
00105     {
00106         if (index < FdoNamedCollection<OBJ, FdoSchemaException>::GetCount() && index >= 0)   // verify index is in bounds
00107         {
00108             if (m_setItemParent && m_parent)
00109             {
00110             /// Validate parentage for object to add.  Membership in a
00111             /// collection implys parentage, and a object can only have
00112             /// one parent.
00113             /// 
00114                 FdoSchemaElement*   pparent = value->GetParent();
00115                 if (pparent)
00116                 {
00117                 /// OK, just restoring collection.
00118                     if (pparent == m_parent && (m_changeInfoState & CHANGEINFO_PROCESSING))
00119                         pparent->Release(); 
00120                     else
00121                     {
00122                         pparent->Release();
00123                         throw FdoSchemaException::Create(FdoException::NLSGetMessage(FDO_NLSID(SCHEMA_10_OBJECTHASPARENT)));
00124                     }
00125                 }
00126             }
00127             _StartChanges();
00128 
00129             if (m_setItemParent && m_parent)
00130                 value->SetParent(m_parent);
00131             /// Adding to a non-owning class does not change the state.
00132             /// \warning
00133             /// Do not change states during Accept/RejectChanges.
00134             ///
00135             if (m_setItemParent
00136                 && !(m_changeInfoState & CHANGEINFO_PROCESSING))
00137             {
00138                 value->SetElementState(FdoSchemaElementState_Added);
00139             }
00140 
00141             OBJ*    pitemOld = FdoNamedCollection<OBJ, FdoSchemaException>::GetItem(index);
00142             FdoSchemaElement*   pparentOldItem = pitemOld->GetParent();
00143             if ( pparentOldItem == m_parent )
00144             {
00145             /// When an object is removed from a collection, that
00146             /// collection's owner is no longer the object's
00147             /// parent.
00148             /// 
00149                 pitemOld->SetParent(NULL);
00150                 pitemOld->SetElementState(FdoSchemaElementState_Detached);
00151             }
00152             FDO_SAFE_RELEASE(pparentOldItem);
00153             FDO_SAFE_RELEASE(pitemOld);
00154         }
00155 
00156         FdoNamedCollection<OBJ, FdoSchemaException>::SetItem(index, value);
00157     }
00158 
00159     /// \brief
00160     /// Adds the specified item to the end of the collection. Returns the index of the newly added item.
00161     /// 
00162     /// \param value 
00163     /// Input value
00164     /// 
00165     /// \return
00166     /// Returns the index of the newly added item
00167     /// 
00168     FDO_API virtual FdoInt32 Add(OBJ* value)
00169     {
00170         if (m_setItemParent && m_parent)
00171         {
00172         /// Validate parentage for object to add.  Membership in a
00173         /// collection implys parentage, and a object can only have
00174         /// one parent.
00175         /// 
00176             FdoSchemaElement*   pparent = value->GetParent();
00177             if (pparent)
00178             {
00179                 if (pparent == m_parent && (m_changeInfoState & CHANGEINFO_PROCESSING))
00180                     pparent->Release(); // OK, just restoring collection
00181                 else
00182                 {
00183                     pparent->Release();
00184                     throw FdoSchemaException::Create(FdoException::NLSGetMessage(FDO_NLSID(SCHEMA_10_OBJECTHASPARENT)));
00185                 }
00186             }
00187         }
00188         _StartChanges();
00189 
00190         if (m_setItemParent && m_parent)
00191             value->SetParent(m_parent);
00192         /// Adding to a non-owning class does not change the state.
00193         /// \warning
00194         /// Do not change states during Accept/RejectChanges.
00195         ///
00196         if (m_setItemParent
00197             && !(m_changeInfoState & CHANGEINFO_PROCESSING))
00198         {
00199             value->SetElementState(FdoSchemaElementState_Added);
00200         }
00201         return FdoNamedCollection<OBJ, FdoSchemaException>::Add(value);
00202     }
00203 
00204     /// \brief
00205     /// Inserts the specified item at the specified index within the collection.
00206     /// Items following the insertion point are moved down to accommodate the new item. 
00207     /// Throws an invalid argument exception if the specified index is out of range.
00208     /// 
00209     /// \param index 
00210     /// Input index
00211     /// \param value 
00212     /// Input value
00213     /// 
00214     /// \return
00215     /// Returns nothing
00216     /// 
00217     FDO_API virtual void Insert(FdoInt32 index, OBJ* value)
00218     {
00219         if (m_setItemParent && m_parent)
00220         {
00221         /// Validate parentage for object to add.  Membership in a
00222         /// collection implys parentage, and a object can only have
00223         /// one parent.
00224         /// 
00225             FdoSchemaElement*   pparent = value->GetParent();
00226             if (pparent)
00227             {
00228             /// OK, just restoring collection.
00229                 if (pparent == m_parent && (m_changeInfoState & CHANGEINFO_PROCESSING))
00230                     pparent->Release();
00231                 else
00232                 {
00233                     pparent->Release();
00234                     throw FdoSchemaException::Create(FdoException::NLSGetMessage(FDO_NLSID(SCHEMA_10_OBJECTHASPARENT)));
00235                 }
00236             }
00237         }
00238         _StartChanges();
00239 
00240         if (m_setItemParent && m_parent)
00241             value->SetParent(m_parent);
00242         /// Adding to a non-owning class does not change the state.
00243         /// \warning
00244         /// Do not change states during Accept/RejectChanges.
00245         ///
00246         if (m_setItemParent
00247             && !(m_changeInfoState & CHANGEINFO_PROCESSING))
00248         {
00249             value->SetElementState(FdoSchemaElementState_Added);
00250         }
00251         FdoNamedCollection<OBJ, FdoSchemaException>::Insert(index, value);
00252     }
00253 
00254     /// \brief
00255     /// Removes all items from the collection.
00256     /// 
00257     /// \return
00258     /// Returns nothing
00259     /// 
00260     FDO_API virtual void Clear()
00261     {
00262         _StartChanges();
00263 
00264         if (m_setItemParent && m_parent)
00265         {
00266             for(FdoInt32 i = 0; i < FdoNamedCollection<OBJ, FdoSchemaException>::GetCount(); i++)
00267             {
00268                 OBJ*    pitem = FdoNamedCollection<OBJ, FdoSchemaException>::GetItem(i);
00269                 FdoSchemaElement*   pparent = pitem->GetParent();
00270 
00271                 if ( pparent == m_parent )
00272                 {
00273                 /// When an object is removed from a collection, that
00274                 /// collection's owner is no longer the object's
00275                 /// parent.
00276                 /// 
00277                     pitem->SetParent(NULL);
00278                     pitem->SetElementState(FdoSchemaElementState_Detached);
00279                 }
00280 
00281                 FDO_SAFE_RELEASE(pparent);
00282                 FDO_SAFE_RELEASE(pitem);
00283             }
00284         }
00285 
00286         FdoNamedCollection<OBJ, FdoSchemaException>::Clear();
00287     }
00288 
00289     /// \brief
00290     /// Removes the specified item from the collection. Throws an invalid argument exception if the item does not exist within the collection.
00291     /// 
00292     /// \param value 
00293     /// Input value
00294     /// 
00295     /// \return
00296     /// Returns nothing
00297     /// 
00298     FDO_API virtual void Remove(const OBJ* value)
00299     {
00300         _StartChanges();
00301 
00302         if (m_setItemParent && m_parent)
00303         {
00304         /// Cast drops const.
00305             OBJ*    pitem = (OBJ*)value;
00306             FdoSchemaElement*   pparent = pitem->GetParent();
00307 
00308             if ( pparent == m_parent )
00309             {
00310             /// When an object is removed from a collection, that
00311             /// collection's owner is no longer the object's
00312             /// parent.
00313             /// 
00314                 pitem->SetParent(NULL);
00315                 pitem->SetElementState(FdoSchemaElementState_Detached);
00316             }
00317 
00318             FDO_SAFE_RELEASE(pparent);
00319         }
00320 
00321         FdoNamedCollection<OBJ, FdoSchemaException>::Remove(value);
00322     }
00323 
00324     /// \brief
00325     /// Removes the specified item from the collection. Throws an invalid argument exception if the item does not exist within the collection.
00326     /// 
00327     /// \param index 
00328     /// Input index
00329     /// 
00330     /// \return
00331     /// Returns nothing
00332     /// 
00333     FDO_API virtual void RemoveAt(FdoInt32 index)
00334     {
00335         _StartChanges();
00336 
00337         if (m_setItemParent && m_parent)
00338         {
00339             OBJ*    pitem = FdoNamedCollection<OBJ, FdoSchemaException>::GetItem(index);
00340             FdoSchemaElement*   pparent = pitem->GetParent();
00341 
00342             if ( pparent == m_parent )
00343             {
00344             /// When an object is removed from a collection, that
00345             /// collection's owner is no longer the object's
00346             /// parent.
00347             /// 
00348                 pitem->SetParent(NULL);
00349                 pitem->SetElementState(FdoSchemaElementState_Detached);
00350             }
00351 
00352             FDO_SAFE_RELEASE(pparent);
00353             FDO_SAFE_RELEASE(pitem);
00354         }
00355 
00356         FdoNamedCollection<OBJ, FdoSchemaException>::RemoveAt(index);
00357     }
00358 
00359 protected:
00360 /// \cond DOXYGEN-IGNORE
00361     /// States stored in the m_changeInfoState bitfield flag
00362     static const unsigned int   CHANGEINFO_PRESENT      = 0x00000001;
00363     static const unsigned int   CHANGEINFO_PROCESSING   = 0x00000002;
00364     static const unsigned int   CHANGEINFO_PROCESSED    = 0x00000004;
00365 
00366     FdoSchemaElement*   m_parent;
00367     bool                m_setItemParent;
00368 
00369     /// FdoFeatureSchema::RejectChanges() support
00370     FdoByte             m_changeInfoState;
00371     OBJ**               m_listCHANGED;
00372     FdoInt32            m_sizeCHANGED;
00373 
00374     virtual void _StartChanges()
00375     {
00376         if (!(m_changeInfoState & (CHANGEINFO_PRESENT|CHANGEINFO_PROCESSING)))
00377         {
00378             m_sizeCHANGED = FdoNamedCollection<OBJ, FdoSchemaException>::GetCount();
00379 
00380             if (m_sizeCHANGED > 0)
00381             {
00382                 m_listCHANGED = new OBJ*[m_sizeCHANGED];
00383                 for (FdoInt32 i=0; i < m_sizeCHANGED; i++)
00384                 {
00385                     m_listCHANGED[i] = FdoNamedCollection<OBJ, FdoSchemaException>::GetItem(i);
00386                 }
00387             }
00388 
00389             m_changeInfoState |= CHANGEINFO_PRESENT;
00390 
00391             if (m_parent)
00392                 m_parent->SetElementState(FdoSchemaElementState_Modified);
00393         }
00394     }
00395 
00396     virtual void _AcceptChanges()
00397     {
00398     /// Already processed.
00399         if (m_changeInfoState & CHANGEINFO_PROCESSED)
00400             return;
00401         m_changeInfoState |= CHANGEINFO_PROCESSED;
00402 
00403         if (m_changeInfoState & CHANGEINFO_PRESENT)
00404         {
00405         /// Reset.
00406             for (FdoInt32 i=0; i < m_sizeCHANGED; i++)
00407             {
00408             /// Accept changes to items once in this collection.
00409                 m_listCHANGED[i]->_AcceptChanges();
00410 
00411             /// Release from change list.
00412                 FDO_SAFE_RELEASE(m_listCHANGED[i]);
00413             }
00414             delete [] m_listCHANGED;
00415             m_listCHANGED = NULL;
00416             m_sizeCHANGED = 0;
00417         }
00418 
00419         /// Accept changes to items currently in this collection.
00420         for (FdoInt32 i=0; i < FdoNamedCollection<OBJ, FdoSchemaException>::GetCount(); i++)
00421         {
00422             FdoPtr<OBJ>    pitem = FdoNamedCollection<OBJ, FdoSchemaException>::GetItem(i);
00423 
00424             if (pitem->GetElementState() == FdoSchemaElementState_Deleted)
00425             {
00426             /// Really remove items marked for deletion.
00427                 RemoveAt(i);
00428                 i--;
00429             }
00430 
00431             pitem->_AcceptChanges();
00432         }
00433     }
00434 
00435     virtual void _RejectChanges()
00436     {
00437         /// Already processed.
00438         if (m_changeInfoState & CHANGEINFO_PROCESSED)
00439             return;
00440         m_changeInfoState |= CHANGEINFO_PROCESSED;
00441 
00442         if (m_changeInfoState & CHANGEINFO_PRESENT)
00443         {
00444         /// Restore.
00445 
00446         /// Reject changes to items currently in this collection.
00447             for (FdoInt32 i=0; i < FdoNamedCollection<OBJ, FdoSchemaException>::GetCount(); i++)
00448             {
00449                 OBJ*    pitem = FdoNamedCollection<OBJ, FdoSchemaException>::GetItem(i);
00450                 pitem->_RejectChanges();
00451                 FDO_SAFE_RELEASE(pitem);
00452             }
00453 
00454             FdoNamedCollection<OBJ, FdoSchemaException>::Clear();
00455             for (FdoInt32 iChanged=0; iChanged < m_sizeCHANGED; iChanged++)
00456             {
00457                 Add(m_listCHANGED[iChanged]);
00458                 FDO_SAFE_RELEASE(m_listCHANGED[iChanged]);
00459             }
00460 
00461             /// Reset.
00462             delete [] m_listCHANGED;
00463             m_listCHANGED = NULL;
00464             m_sizeCHANGED = 0;
00465         }
00466 
00467         /// Reject changes to items now in this collection.
00468         for (FdoInt32 i=0; i < FdoNamedCollection<OBJ, FdoSchemaException>::GetCount(); i++)
00469         {
00470             OBJ*    pitem = FdoNamedCollection<OBJ, FdoSchemaException>::GetItem(i);
00471             pitem->_RejectChanges();
00472             FDO_SAFE_RELEASE(pitem);
00473         }
00474     }
00475 
00476     virtual void _BeginChangeProcessing()
00477     {
00478         /// Already marked for processing.
00479         if (m_changeInfoState & CHANGEINFO_PROCESSING)
00480             return;
00481 
00482         m_changeInfoState |= CHANGEINFO_PROCESSING;
00483 
00484         for (FdoInt32 i=0; i < FdoNamedCollection<OBJ, FdoSchemaException>::GetCount(); i++)
00485         {
00486             OBJ*    pitem = FdoNamedCollection<OBJ, FdoSchemaException>::GetItem(i);
00487             pitem->_BeginChangeProcessing();
00488             FDO_SAFE_RELEASE(pitem);
00489         }
00490     }
00491 
00492     virtual void _EndChangeProcessing()
00493     {
00494         /// Processing flag already cleared.
00495         if (!(m_changeInfoState & CHANGEINFO_PROCESSING))
00496             return;
00497 
00498         for (FdoInt32 i=0; i < FdoNamedCollection<OBJ, FdoSchemaException>::GetCount(); i++)
00499         {
00500             OBJ*    pitem = FdoNamedCollection<OBJ, FdoSchemaException>::GetItem(i);
00501             pitem->_EndChangeProcessing();
00502             FDO_SAFE_RELEASE(pitem);
00503         }
00504 
00505         m_changeInfoState = 0;
00506     }
00507 /// \endcond
00508 };
00509 #endif
00510 
00511 

Comments or suggestions? Send us feedback.