GME  13
CoreProject.cpp
Go to the documentation of this file.
00001 
00002 #include "stdafx.h"
00003 
00004 #include "CoreProject.h"
00005 #include "CoreObject.h"
00006 #include "CoreTransactionItem.h"
00007 #include "CoreTerritory.h"
00008 #include "CoreBinFile.h"
00009 #include "CoreMetaProject.h"
00010 //#include "XmlBackEnd.h"
00011 
00012 // --------------------------- CCoreProject
00013 
00014 CCoreProject::CCoreProject()
00015         : m_maxUndoStep( MAX_UNDO_STEP) // = 10, keep value in sync with CMgaProject::getMaxUndoSize()'s default
00016 {
00017         status = 0;
00018         redo_count = 0;
00019 }
00020 
00021 CCoreProject::~CCoreProject()
00022 {
00023         // try to clean up
00024         put_Storage(NULL);
00025 
00026         ASSERT( transactions.empty() );
00027         ASSERT( finaltr_items.empty() );
00028         ASSERT( object_lookup.empty() );
00029         ASSERT( undos.empty() );
00030         ASSERT( pushed_territorys.empty() );
00031         ASSERT( created_territorys.empty() );
00032 }
00033 
00034 // ------- COM methods
00035 
00036 STDMETHODIMP CCoreProject::put_Storage(ICoreStorage *p)
00037 {
00038         COMTRY
00039         {
00040                 if( storage )
00041                 {
00042                         // to prevent being called twice
00043                         CComObjPtr<CCoreProject> self(this);
00044 
00045                         while( InTransaction() )
00046                                 AbortTransaction(TRANSTYPE_ANY);
00047 
00048                         ASSERT( pushed_territorys.empty() );
00049 
00050                         if( !created_territorys.empty() )
00051                         {
00052                                 BeginFinalTr();
00053                                 try
00054                                 {
00055                                         created_territorys_type::iterator i = created_territorys.begin();
00056                                         created_territorys_type::iterator e = created_territorys.end();
00057                                         while( i != e )
00058                                         {
00059                                                 CCoreTerritory *territory = *i;
00060                                                 ASSERT( territory != NULL );
00061 
00062                                                 ++i;
00063 
00064                                                 COMTHROW( territory->Clear() );
00065                                         }
00066                                         
00067                                         CommitFinalTr(false);
00068                                 }
00069                                 catch(hresult_exception &)
00070                                 {
00071                                         AbortFinalTr();
00072 
00073                                         throw;
00074                                 }
00075                         }
00076                         ASSERT( !InTransaction() );
00077 
00078                         while( !undos.empty() )
00079                                 TryDiscardLastItem();
00080 
00081 #ifdef DEBUG_OBJECTLOOKUP
00082                         if( !object_lookup.empty() )
00083                         {
00084                                 AtlTrace("object_lookup begin\n");
00085                                 object_lookup_iterator i = object_lookup.begin();
00086                                 object_lookup_iterator e = object_lookup.end();
00087                                 while( i != e )
00088                                 {
00089                                         (*i).second->Dump();
00090 
00091                                         ++i;
00092                                 }
00093                                 AtlTrace("object_lookup end\n");
00094                         }
00095 #endif
00096 
00097                         object_lookup_iterator i = object_lookup.begin();
00098                         object_lookup_iterator e = object_lookup.end();
00099                         while( i != e )
00100                         {
00101 #ifdef _ATL_DEBUG_INTERFACES
00102                                 CComPtr<IUnknown> obj1 = (IDispatchImpl<ICoreObject, &__uuidof(ICoreObject), &__uuidof(__MGACoreLib)>*)i->second;
00103                                 CComPtr<IUnknown> obj2 = (IDispatchImpl<ICoreObject, &__uuidof(ICoreObject), &__uuidof(__MGACoreLib)>*)i->second;
00104 #endif
00105                                 (*i).second->SetZombie();
00106 
00107                                 ++i;
00108                         }
00109                         object_lookup.clear();
00110                         
00111                         ASSERT( transactions.empty() );
00112                         ASSERT( finaltr_items.empty() );
00113                         ASSERT( object_lookup.empty() );
00114                         ASSERT( undos.empty() );
00115                         ASSERT( pushed_territorys.empty() );
00116                         ASSERT( status == 0 );
00117                         ASSERT( redo_count == 0 );
00118 
00119                         metaproject = NULL;
00120                 }
00121 
00122                 storage = p;
00123 
00124                 if( storage )
00125                 {
00126                         CComObjPtr<ICoreMetaProject> p;
00127                         COMTHROW( storage->get_MetaProject(PutOut(p)) );
00128                         ASSERT( p != NULL );
00129 
00130                         // HACK: we should check that the apartments are the same
00131                         metaproject = CastToMetaProject(p);
00132                 }
00133         }
00134         COMCATCH(;)
00135 }
00136 
00137 STDMETHODIMP CCoreProject::get_Storage(ICoreStorage **p)
00138 {
00139         CHECK_OUT(p);
00140 
00141         CopyTo(storage, p);
00142         return S_OK;
00143 }
00144 
00145 STDMETHODIMP CCoreProject::get_MetaProject(ICoreMetaProject **p)
00146 {
00147         CHECK_OUT(p);
00148 
00149         if( storage == NULL )
00150                 COMRETURN(E_INVALID_USAGE);
00151 
00152         CopyTo(metaproject, p);
00153         return S_OK;
00154 }
00155 
00156 std::string CCoreProject::GetFirstToken(BSTR connection)
00157 {
00158         std::string con;
00159         CopyTo(connection, con);
00160 
00161         size_t pos = con.find('=');
00162         if( pos != std::string::npos )
00163                 con.resize(pos);
00164 
00165         pos = con.find(';');
00166         if( pos != std::string::npos )
00167                 con.resize(pos);
00168 
00169         return con;
00170 }
00171 
00172 STDMETHODIMP CCoreProject::OpenProject2(BSTR connection, long p_undoSize, ICoreMetaProject *p, VARIANT_BOOL *ro_mode)
00173 {
00174         setMaxUndoStep( p_undoSize);
00175         return OpenProject( connection, p, ro_mode);
00176 }
00177 
00178 STDMETHODIMP CCoreProject::OpenProject(BSTR connection, ICoreMetaProject *p, VARIANT_BOOL *ro_mode)
00179 {
00180         if( p == NULL || connection == NULL )
00181                 return E_INVALIDARG;
00182 
00183         if( storage != NULL || metaproject != NULL )
00184                 COMRETURN(E_INVALID_USAGE);
00185 
00186         COMTRY
00187         {
00188                 std::string con = GetFirstToken(connection);
00189 
00190                 CComObjPtr<ICoreStorage> corestorage;
00191 
00192                 if( con == "MGA" )
00193                 {
00194                         CComObjPtr<CCoreBinFile> binfile;
00195                         CreateComObject(binfile);
00196 
00197                         corestorage = binfile;
00198                 }
00199         else if( con == "MGX" )
00200                 {
00201             CComObjPtr<ICoreStorage> xmlfile;
00202             xmlfile.CoCreateInstance( L"Mga.CoreXmlFile" );
00203                         
00204                         corestorage = xmlfile;
00205                 }
00206                 else
00207                         COMTHROW(E_UNKNOWN_STORAGE);
00208 
00209                 ASSERT( corestorage != NULL );
00210 
00211                 COMTHROW( corestorage->put_MetaProject(p) );
00212                 corestorage->__OpenProject(connection, ro_mode);
00213 
00214                 COMTHROW( put_Storage(corestorage) );
00215         }
00216         COMCATCH(;)
00217 }
00218 
00219 STDMETHODIMP CCoreProject::CloseProject(VARIANT_BOOL abort)
00220 {
00221 
00222         if( storage == NULL && metaproject == NULL ) return S_OK;
00223         if( storage == NULL || metaproject == NULL )
00224                 COMRETURN(E_INVALID_USAGE);
00225 
00226         COMTRY
00227         {
00228                 CComObjPtr<ICoreStorage> corestorage;
00229                 corestorage = storage;
00230 
00231                 COMTHROW( put_Storage(NULL) );
00232                 COMTHROW( corestorage->CloseProject(abort) );
00233         }
00234         COMCATCH(;)
00235 }
00236 
00237 STDMETHODIMP CCoreProject::SaveProject(BSTR newname, VARIANT_BOOL keepoldname)
00238 {
00239         if( storage == NULL || metaproject == NULL )
00240                 COMRETURN(E_INVALID_USAGE);
00241 
00242         COMTRY
00243         {
00244                 ICoreStoragePtr corestorage = storage.p;
00245 
00246                 corestorage->__SaveProject(newname, keepoldname);
00247         }
00248         COMCATCH(;)
00249 }
00250 
00251 STDMETHODIMP CCoreProject::CreateProject2(BSTR connection, long p_undoSize, ICoreMetaProject *p)
00252 {
00253         setMaxUndoStep( p_undoSize);
00254         return CreateProject( connection, p);
00255 }
00256 
00257 STDMETHODIMP CCoreProject::CreateProject(BSTR connection, ICoreMetaProject *p)
00258 {
00259         if( p == NULL || connection == NULL )
00260                 return E_INVALIDARG;
00261 
00262         if( storage != NULL || metaproject != NULL )
00263                 COMRETURN(E_INVALID_USAGE);
00264 
00265         COMTRY
00266         {
00267                 std::string con = GetFirstToken(connection);
00268 
00269                 CComObjPtr<ICoreStorage> corestorage;
00270 
00271                 if( con == "MGA" )
00272                 {
00273                         CComObjPtr<CCoreBinFile> binfile;
00274                         CreateComObject(binfile);
00275 
00276                         corestorage = binfile;
00277                 }
00278         else if( con == "MGX" )
00279                 {
00280                         CComObjPtr<ICoreStorage> xmlfile;
00281             COMTHROW(xmlfile.CoCreateInstance(L"Mga.CoreXmlFile"));
00282                         
00283                         corestorage = xmlfile;
00284                 }
00285                 else
00286                         COMTHROW(E_UNKNOWN_STORAGE);
00287 
00288                 ASSERT( corestorage != NULL );
00289 
00290                 COMTHROW( corestorage->put_MetaProject(p) );
00291                 COMTHROW( corestorage->CreateProject(connection) );
00292 
00293                 COMTHROW( put_Storage(corestorage) );
00294         }
00295         COMCATCH(;)
00296 }
00297 
00298 STDMETHODIMP CCoreProject::DeleteProject(BSTR connection)
00299 {
00300         return E_NOTIMPL;
00301 }
00302 
00303 STDMETHODIMP CCoreProject::get_RootObject(ICoreObject **p)
00304 {
00305         return get_Object(METAID_ROOT, OBJID_ROOT, p);
00306 }
00307 
00308 STDMETHODIMP CCoreProject::get_Object(metaid_type metaid, objid_type objid, ICoreObject **p)
00309 {
00310         CHECK_OUT(p);
00311 
00312         if( metaid == 0 || objid == 0 )
00313                 return E_INVALIDARG;
00314 
00315         if( storage == NULL )
00316                 COMRETURN(E_INVALID_USAGE);
00317 
00318         if( !InTransaction() )
00319                 COMRETURN(E_TRANSACTION);
00320 
00321         COMTRY
00322         {
00323                 CComObjPtr<CCoreObject> object = GetObject(metaid, objid);
00324                 ASSERT( object != NULL );
00325 
00326                 MoveTo(object, p);
00327         }
00328         COMCATCH(;)
00329 }
00330 
00331 STDMETHODIMP CCoreProject::CreateObject(metaid_type metaid, ICoreObject **p)
00332 {
00333         CHECK_OUT(p);
00334 
00335         if( metaid == METAID_NONE )
00336                 return E_INVALIDARG;
00337 
00338         if( storage == NULL )
00339                 COMRETURN(E_INVALID_USAGE);
00340 
00341         if( !InWriteTransaction() )
00342                 COMRETURN(E_TRANSACTION);
00343 
00344         COMTRY
00345         {
00346                 CComObjPtr<CCoreObject> object(CreateObject(metaid));
00347                 ASSERT( object != NULL );
00348 
00349                 CopyTo(object, p);
00350         }
00351         COMCATCH(;)
00352 }
00353 
00354 STDMETHODIMP CCoreProject::BeginTransaction(transtype_enum transtype)
00355 {
00356         if (InReadTransaction() && (transtype & TRANSTYPE_READ) == 0)
00357         {
00358                 SetErrorInfo(L"Project is in read-only transaction and cannot be modified");
00359                 return E_INVALID_USAGE;
00360         }
00361         if (storage == NULL || (transtype & TRANSTYPE_ANY) == 0 ||
00362                 (InTransaction() && (transtype & TRANSTYPE_NESTED) == 0))
00363         {
00364                 COMRETURN(E_INVALID_USAGE);
00365         }
00366 
00367         COMTRY
00368         {
00369                 if( InTransaction() )
00370                 {
00371                         // note that in a read-transaction we might have redo_count > 0
00372 
00373                         ASSERT( undos.size() <= m_maxUndoStep + 1);
00374                         ASSERT( undos.size() <= m_maxUndoStep || (transtype & TRANSTYPE_READ) != 0 );
00375 
00376                         BeginNestedTr();
00377                 }
00378                 else
00379                 {
00380                         // if this is a read/write transaction then flush the redo queue
00381                         if( (transtype & TRANSTYPE_READ) == 0 )
00382                         {
00383                                 while( redo_count > 0 )
00384                                         TryDiscardLastItem();
00385 
00386                                 ASSERT( m_maxUndoStep); // m_maxUndoStep better not be 0 (chance of infinite loop)
00387                                 while( undos.size() >= m_maxUndoStep )
00388                                         TryDiscardLastItem();
00389 
00390                                 ASSERT( redo_count == 0 );
00391                         }
00392 
00393                         BeginFinalTr();
00394                 }
00395 
00396                 // we set the transaction type
00397                 transactions.front().readonly = ((transtype & TRANSTYPE_READ) != 0);
00398         }
00399         COMCATCH(;)
00400 }
00401 
00402 STDMETHODIMP CCoreProject::CommitTransaction(transtype_enum transtype)
00403 {
00404         if( storage == NULL || (transtype & TRANSTYPE_ANY) == 0 || !InTransaction() ||
00405                 (limited_size(transactions, 2) == 1 && (transtype & TRANSTYPE_FIRST) == 0) ||
00406                 (transactions.front().readonly != ((transtype & TRANSTYPE_READ) != 0)) )
00407         {
00408                 COMRETURN(E_INVALID_USAGE);
00409         }
00410 
00411         COMTRY
00412         {
00413                 if( limited_size(transactions, 2) >= 2 )
00414                 {
00415                         CommitNestedTr();
00416                 }
00417                 else
00418                 {
00419                         CommitFinalTr(true);
00420                 }
00421         }
00422         COMCATCH(;)
00423 }
00424 
00425 STDMETHODIMP CCoreProject::AbortTransaction(transtype_enum transtype)
00426 {
00427         if( storage == NULL || (transtype & TRANSTYPE_ANY) == 0 || !InTransaction() ||
00428                 (limited_size(transactions, 2) == 1 && (transtype & TRANSTYPE_FIRST) == 0) )
00429         {
00430                 COMRETURN(E_INVALID_USAGE);
00431         }
00432 
00433         COMTRY
00434         {
00435                 if( limited_size(transactions, 2) >= 2 )
00436                 {
00437                         AbortNestedTr();
00438                 }
00439                 else
00440                 {
00441                         AbortFinalTr();
00442                 }
00443         }
00444         COMCATCH(;)
00445 }
00446 
00447 STDMETHODIMP CCoreProject::get_NestedTransactionCount(short *p)
00448 {
00449         CHECK_OUT(p);
00450 
00451         *p = GetNestedTrCount();
00452 
00453         return S_OK;
00454 }
00455 
00456 // ------- Undo
00457 
00458 STDMETHODIMP CCoreProject::UndoTransaction()
00459 {
00460         ASSERT( (int) undos.size() >= redo_count && redo_count >= 0 );
00461 
00462         if( storage == NULL || InTransaction() || (int) undos.size() <= redo_count )
00463                 COMRETURN(E_INVALID_USAGE);
00464 
00465         COMTRY
00466         {
00467                 TryUndoTransaction();
00468         }
00469         COMCATCH(;)
00470 }
00471 
00472 STDMETHODIMP CCoreProject::RedoTransaction()
00473 {
00474         ASSERT( (int) undos.size() >= redo_count && redo_count >= 0 );
00475 
00476         if( storage == NULL || InTransaction() || redo_count <= 0 )
00477                 COMRETURN(E_INVALID_USAGE);
00478 
00479         COMTRY
00480         {
00481                 TryRedoTransaction();
00482         }
00483         COMCATCH(;)
00484 }
00485 
00486 STDMETHODIMP CCoreProject::FlushUndoQueue()
00487 {
00488         ASSERT( (int) undos.size() >= redo_count && redo_count >= 0 );
00489 
00490         if( storage == NULL || InTransaction() )
00491                 COMRETURN(E_INVALID_USAGE);
00492 
00493         COMTRY
00494         {
00495                 while( !undos.empty() )
00496                         TryDiscardLastItem();
00497         }
00498         COMCATCH(;)
00499 }
00500 
00501 STDMETHODIMP CCoreProject::FlushRedoQueue()
00502 {
00503         ASSERT( (int) undos.size() >= redo_count && redo_count >= 0 );
00504 
00505         if( storage == NULL || InTransaction() )
00506                 COMRETURN(E_INVALID_USAGE);
00507 
00508         COMTRY
00509         {
00510                 while( redo_count > 0 )
00511                         TryDiscardLastItem();
00512         }
00513         COMCATCH(;)
00514 }
00515 
00516 STDMETHODIMP CCoreProject::get_UndoQueueSize(short *p)
00517 {
00518         CHECK_OUT(p);
00519 
00520         ASSERT( (int) undos.size() >= redo_count );
00521         *p = undos.size() - redo_count - (InTransaction() ? 1 : 0);
00522         ASSERT( *p >= 0 );
00523 
00524         return S_OK;
00525 }
00526 
00527 STDMETHODIMP CCoreProject::get_RedoQueueSize(short *p)
00528 {
00529         CHECK_OUT(p);
00530 
00531         ASSERT( (int) undos.size() >= redo_count );
00532         *p = redo_count;
00533 
00534         return S_OK;
00535 }
00536 
00537 STDMETHODIMP CCoreProject::CreateTerritory(ICoreTerritory **p)
00538 {
00539         CHECK_OUT(p);
00540 
00541         if( storage == NULL )
00542                 COMRETURN(E_INVALID_USAGE);
00543 
00544         COMTRY
00545         {
00546                 CComObjPtr<CCoreTerritory> territory;
00547                 
00548                 territory = CCoreTerritory::Create(this);
00549                 ASSERT( territory != NULL );
00550 
00551                 CopyTo(territory, p);
00552         }
00553         COMCATCH(;)
00554 }
00555 
00556 STDMETHODIMP CCoreProject::PushTerritory(ICoreTerritory *p)
00557 {
00558         if( p == NULL )
00559                 return E_INVALIDARG;
00560 
00561         if( storage == NULL || !InTransaction() )
00562                 COMRETURN(E_INVALID_USAGE);
00563 
00564         COMTRY
00565         {
00566                 CCoreTerritory *territory = CastTerritory(p);
00567                 pushed_territorys.push_front( territory );
00568         }
00569         COMCATCH(;)
00570 }
00571 
00572 STDMETHODIMP CCoreProject::PopTerritory()
00573 {
00574         if( storage == NULL || pushed_territorys.empty() || !InTransaction() )
00575                 COMRETURN(E_INVALID_USAGE);
00576 
00577         ASSERT( pushed_territorys.front() != NULL );
00578         pushed_territorys.pop_front();
00579 
00580         return S_OK;
00581 }
00582 
00583 // ------- Methods
00584 
00585 CCoreObject *CCoreProject::FindObject(metaid_type metaid, objid_type objid)
00586 {
00587         ASSERT( storage != NULL );
00588         ASSERT( metaid != METAID_NONE && objid != OBJID_NONE );
00589 
00590         metaobjidpair_type idpair;
00591         idpair.metaid = metaid;
00592         idpair.objid = objid;
00593 
00594         object_lookup_iterator i = object_lookup.find(idpair);
00595         if( i != object_lookup.end() )
00596         {
00597                 ASSERT( (*i).second != NULL );
00598                 return (*i).second;
00599         }
00600 
00601         return NULL;
00602 }
00603 
00604 CComObjPtr<CCoreObject> CCoreProject::CreateObject(metaid_type metaid, objid_type objid)
00605 {
00606         ASSERT( storage != NULL );
00607         ASSERT( metaid != METAID_NONE && objid != OBJID_NONE );
00608         ASSERT( InTransaction() );
00609 
00610 #ifdef _DEBUG
00611         metaobjidpair_type idpair;
00612         idpair.metaid = metaid;
00613         idpair.objid = objid;
00614 
00615         ASSERT( object_lookup.find(idpair) == object_lookup.end() );
00616 #endif
00617 
00618         return CCoreObject::Create(this, metaid, objid);
00619 }
00620 
00621 CComObjPtr<CCoreObject> CCoreProject::GetObject(metaid_type metaid, objid_type objid)
00622 {
00623         ASSERT( storage != NULL );
00624         ASSERT( metaid != METAID_NONE && objid != OBJID_NONE );
00625 
00626         metaobjidpair_type idpair;
00627         idpair.metaid = metaid;
00628         idpair.objid = objid;
00629 
00630         object_lookup_iterator i = object_lookup.find(idpair);
00631         if( i != object_lookup.end() )
00632         {
00633                 ASSERT( (*i).second != NULL );
00634                 return (*i).second;
00635         }
00636 
00637         if( !InTransaction() )
00638                 HR_THROW(E_TRANSACTION);
00639 
00640         return CCoreObject::Create(this, metaid, objid);
00641 }
00642 
00643 CComObjPtr<CCoreObject> CCoreProject::CreateObject(metaid_type metaid)
00644 {
00645         ASSERT( storage != NULL );
00646         ASSERT( metaid != METAID_NONE );
00647         ASSERT( InWriteTransaction() );
00648 
00649         COMTHROW( storage->put_MetaID(metaid) );
00650 
00651         objid_type objid = OBJID_NONE;
00652         COMTHROW( storage->CreateObject(&objid) );
00653         ASSERT( objid != OBJID_NONE );
00654 
00655 #ifdef _DEBUG
00656         metaobjidpair_type idpair;
00657         idpair.metaid = metaid;
00658         idpair.objid = objid;
00659         ASSERT( object_lookup.find(idpair) == object_lookup.end() );
00660 #endif
00661 
00662         CComObjPtr<CCoreObject> object(CCoreObject::Create(this, metaid, objid));
00663 
00664         object->FillAfterCreateObject();
00665 
00666         return object;
00667 }
00668 
00669 void CCoreProject::RegisterObject(metaid_type metaid, objid_type objid, CCoreObject *object)
00670 {
00671         ASSERT( storage != NULL );
00672         ASSERT( metaid != 0 && objid != 0 );
00673         ASSERT( object != NULL );
00674 
00675         metaobjidpair_type idpair;
00676         idpair.metaid = metaid;
00677         idpair.objid = objid;
00678 
00679         ASSERT( object_lookup.find(idpair) == object_lookup.end() );
00680         object_lookup.insert( object_lookup_type::value_type(idpair, object) );
00681 }
00682 
00683 void CCoreProject::UnregisterObject(metaid_type metaid, objid_type objid)
00684 {
00685         ASSERT( storage != NULL );
00686         ASSERT( metaid != 0 && objid != 0 );
00687 
00688         metaobjidpair_type idpair;
00689         idpair.metaid = metaid;
00690         idpair.objid = objid;
00691 
00692         if( object_lookup.find(idpair) != object_lookup.end() ) // TL: This used to be an assert
00693         {
00694                 object_lookup.erase( idpair );
00695         }
00696         else
00697         {
00698                 ASSERT(0); // Leave it as an assert, too
00699         }
00700 }
00701 
00702 void CCoreProject::CastProject(ICoreProject *project) const
00703 {
00704         ASSERT( project != NULL );
00705 
00706         if( !IsEqualObject(project, (ICoreProject*)this) )
00707                 HR_THROW(E_SAMEPROJECT);
00708 }
00709 
00710 CCoreObject *CCoreProject::CastObject(ICoreObject *object) const
00711 {
00712         ASSERT( object != NULL );
00713 
00714         CComObjPtr<ICoreProject> project;
00715         COMTHROW( object->get_Project(PutOut(project)) );
00716 
00717         CastProject(project);
00718 
00719         CComObjPtr<IUnknown> p;
00720         COMTHROW( ::QueryInterface(object, p) );
00721         ASSERT( p != NULL );
00722 
00723         CCoreObject *the_object = CastToObject(p);
00724         ASSERT( the_object != NULL );
00725 
00726         if( the_object->GetProject() != this )
00727                 HR_THROW(E_SAMEPROJECT);
00728 
00729         return the_object;
00730 }
00731 
00732 CCoreTerritory *CCoreProject::CastTerritory(ICoreTerritory *territory) const
00733 {
00734         ASSERT( territory != NULL );
00735 
00736         CComObjPtr<ICoreProject> project;
00737         COMTHROW( territory->get_Project(PutOut(project)) );
00738 
00739         CastProject(project);
00740 
00741         CComObjPtr<IUnknown> p;
00742         COMTHROW( ::QueryInterface(territory, p) );
00743         ASSERT( p != NULL );
00744 
00745         CCoreTerritory *the_territory = CastToTerritory(p);
00746         ASSERT( the_territory != NULL );
00747 
00748 #ifndef _ATL_DEBUG_INTERFACES
00749         if( the_territory->GetProject() != this )
00750                 HR_THROW(E_SAMEPROJECT);
00751 #endif
00752 
00753         return the_territory;
00754 }
00755 
00756 CCoreTerritory *CCoreProject::GetTerritory() const
00757 {
00758         if( pushed_territorys.empty() )
00759                 HR_THROW(E_TERRITORY);
00760 
00761         ASSERT( pushed_territorys.front() != NULL );
00762         return pushed_territorys.front();
00763 }
00764 
00765 void CCoreProject::RegisterTerritory(CCoreTerritory *territory)
00766 {
00767         ASSERT( territory != NULL );
00768         ASSERT( territory->GetProject() == this );
00769 
00770 #ifdef DEBUG_CONTAINERS
00771         ASSERT( find(created_territorys.begin(), created_territorys.end(), territory) ==
00772                 created_territorys.end() );
00773 #endif
00774 
00775         created_territorys.push_front(territory);
00776 }
00777 
00778 void CCoreProject::UnregisterTerritory(CCoreTerritory *territory)
00779 {
00780         ASSERT( territory != NULL );
00781         ASSERT( territory->GetProject() == this );
00782 
00783 #ifdef DEBUG_CONTAINERS
00784         ASSERT( find(created_territorys.begin(), created_territorys.end(), territory) !=
00785                 created_territorys.end() );
00786 #endif
00787 
00788         created_territorys.remove(territory);
00789 }
00790 
00791 // ------- Transactions
00792 
00793 int CCoreProject::GetNestedTrCount() const
00794 {
00795         ASSERT( InTransaction() || transactions.empty() );
00796 
00797         return transactions.size();
00798 }
00799 
00800 void CCoreProject::RegisterTransactionItem(CCoreTransactionItem *modified)
00801 {
00802         ASSERT( InTransaction() );
00803         ASSERT( !transactions.empty() );
00804         ASSERT( modified != NULL );
00805 
00806         transaction_items_type &transaction_items = transactions.front().items;
00807 
00808 #ifdef DEBUG_CONTAINERS
00809         ASSERT( find(transaction_items.begin(), transaction_items.end(), modified) == 
00810                 transaction_items.end() );
00811 #endif
00812 
00813         transaction_items.push_front(modified); 
00814 }
00815 
00816 void CCoreProject::RegisterFinalTrItem(CCoreFinalTrItem *modified)
00817 {
00818         ASSERT( InTransaction() );
00819         ASSERT( modified != NULL );
00820 
00821 #ifdef DEBUG_CONTAINERS
00822         ASSERT( find(finaltr_items.begin(), finaltr_items.end(), modified) ==
00823                 finaltr_items.end() );
00824 #endif
00825 
00826         finaltr_items.push_front(modified);
00827 }
00828 
00829 void CCoreProject::RegisterUndoItem(CCoreUndoItem *modified)
00830 {
00831         ASSERT( InWriteTransaction() );
00832         ASSERT( modified != NULL );
00833         ASSERT( !undos.empty() );
00834 
00835 #ifdef DEBUG_CONTAINERS
00836         ASSERT( find(undos.front().begin(), undos.front().end(), modified) ==
00837                 undos.front().end() );
00838 #endif
00839 
00840         undos.front().push_front(modified);
00841 }
00842 
00843 void CCoreProject::BeginFinalTr()
00844 {
00845         ASSERT( transactions.empty() );
00846         ASSERT( finaltr_items.empty() );
00847 
00848 #ifdef TRACE_CORE
00849         AtlTrace("CCoreProject::BeginFinalTr\n");
00850 #endif
00851 
00852         ASSERT( storage );
00853         COMTHROW( storage->BeginTransaction() );
00854 
00855         ASSERT( undos.size() <= m_maxUndoStep );
00856         undos.push_front(undo_type());
00857 
00858         transactions.push_front(transaction_type());
00859         transactions.front().readonly = false;
00860 }
00861 
00862 void CCoreProject::CommitFinalTr(bool undo)
00863 {
00864         ASSERT( transactions.size() == 1 );
00865         ASSERT( !undos.empty() && undos.front().empty() );
00866 
00867 #ifdef TRACE_CORE
00868         AtlTrace("CCoreProject::CommitFinalTr\n");
00869 #endif
00870 
00871         finaltr_items_iterator i = finaltr_items.begin();
00872         finaltr_items_iterator e = finaltr_items.end();
00873         while( i != e )
00874         {
00875                 (*i)->CommitFinalTransaction();
00876                 ++i;
00877         }
00878 
00879         ASSERT( storage );
00880         COMTHROW( storage->CommitTransaction() );
00881 
00882         // nothing will throw here
00883 
00884 #ifdef _DEBUG
00885         transaction_items_iterator j = transactions.front().items.begin();
00886         transaction_items_iterator f = transactions.front().items.end();
00887         while( j != f )
00888         {
00889                 ASSERT( (*j)->IsDirty() );
00890                 ++j;
00891         }
00892 #endif
00893 
00894         ASSERT( !undos.empty() && undos.front().empty() );
00895 
00896         // some objects might get destroyed in CommitFinalTransactionFinish
00897         i = finaltr_items.begin();
00898         ASSERT( e == finaltr_items.end() );
00899 #ifdef _DEBUG
00900         // int finaltr_count = finaltr_items.size();
00901         finaltr_items_type::size_type finaltr_count = 0;
00902         std::for_each(finaltr_items.begin(), finaltr_items.end(), 
00903                 [&finaltr_count](const finaltr_items_type::value_type& e) { finaltr_count++; });
00904 #endif
00905         while( i != e )
00906         {
00907                 // they can register undo_items
00908                 (*i)->CommitFinalTransactionFinish(undo);
00909                 ++i;
00910 
00911                 ASSERT( --finaltr_count >= 0 );
00912         }
00913         ASSERT( finaltr_count == 0 );
00914 
00915         // if this was a read-only transaction, then no one could have registered
00916         ASSERT( !transactions.front().readonly || undos.front().empty() );
00917 
00918         finaltr_items.clear();
00919         transactions.pop_front();
00920                 
00921         // if no undo info here then we don't record it
00922         if( undos.front().empty() )
00923                 undos.pop_front();
00924 
00925         // clear territories
00926         pushed_territorys.clear();
00927 }
00928 
00929 void CCoreProject::AbortFinalTr()
00930 {
00931         ASSERT( transactions.size() == 1 );
00932         ASSERT( !undos.empty() && undos.front().empty() );
00933 
00934 #ifdef TRACE_CORE
00935         AtlTrace("CCoreProject::AbortFinalTr\n");
00936 #endif
00937 
00938         // *** do we want to throw when the abort does not succeed?
00939 
00940         ASSERT( storage );
00941         COMTHROW( storage->AbortTransaction() );
00942 
00943         // nothing will throw here
00944 
00945         undos.pop_front();
00946 
00947 #ifdef _DEBUG
00948         transaction_items_iterator j = transactions.front().items.begin();
00949         transaction_items_iterator f = transactions.front().items.end();
00950         while( j != f )
00951         {
00952                 ASSERT( (*j)->IsDirty() );
00953                 ++j;
00954         }
00955 #endif
00956 
00957         // some objects might get destroyed in AbortFinalTransaction
00958         finaltr_items_iterator i = finaltr_items.begin();
00959         finaltr_items_iterator e = finaltr_items.end();
00960         while( i != e )
00961         {
00962                 (*i)->AbortFinalTransaction();
00963                 ++i;
00964         }
00965 
00966         finaltr_items.clear();
00967         transactions.pop_front();
00968 
00969         // clear territories
00970         pushed_territorys.clear();
00971 }
00972 
00973 void CCoreProject::BeginNestedTr()
00974 {
00975         ASSERT( InTransaction() );
00976         ASSERT( !transactions.empty() );
00977 
00978 #ifdef TRACE_CORE
00979         AtlTrace("CCoreProject::BeginNestedTr\n");
00980 #endif
00981 
00982         transaction_items_iterator i = transactions.front().items.begin();
00983         transaction_items_iterator e = transactions.front().items.end();
00984         while( i != e )
00985         {
00986                 ASSERT( (*i)->IsDirty() );
00987                 (*i)->ChangeDirty(false);
00988                 ASSERT( !(*i)->IsDirty() );
00989 
00990                 ++i;
00991         }
00992 
00993         transactions.push_front(transaction_type());
00994         transactions.front().readonly = false;
00995 }
00996 
00997 void CCoreProject::AbortNestedTr()
00998 {
00999         ASSERT( transactions.size() >= 2 );
01000 
01001 #ifdef TRACE_CORE
01002         AtlTrace("CCoreProject::AbortNestedTr\n");
01003 #endif
01004 
01005         transaction_items_iterator i = transactions.front().items.begin();
01006         transaction_items_iterator e = transactions.front().items.end();
01007         while( i != e )
01008         {
01009                 ASSERT( (*i)->IsDirty() );
01010                 (*i)->AbortNestedTransaction();
01011                 ASSERT( !(*i)->IsDirty() );
01012 
01013                 ++i;
01014         }
01015 
01016         transactions.pop_front();
01017 
01018         i = transactions.front().items.begin();
01019         e = transactions.front().items.end(); // bug correction [zolmol]
01020         while( i != e )
01021         {
01022                 ASSERT( !(*i)->IsDirty() );
01023                 (*i)->ChangeDirty(true);
01024                 ASSERT( (*i)->IsDirty() );
01025 
01026                 ++i;
01027         }
01028 }
01029 
01030 void CCoreProject::CommitNestedTr()
01031 {
01032         ASSERT( transactions.size() >= 2 );
01033 
01034 #ifdef TRACE_CORE
01035         AtlTrace("CCoreProject::CommitNestedTr\n");
01036 #endif
01037 
01038         transaction_type &current = transactions.front();
01039         transactions_iterator previous = ++transactions.begin();
01040 
01041         transaction_items_iterator i = (*previous).items.begin();
01042         transaction_items_iterator e = (*previous).items.end();
01043         while( i != e )
01044         {
01045                 if( (*i)->IsDirty() )
01046                 {
01047 #ifdef DEBUG_CONTAINERS
01048                         ASSERT( find(current.items.begin(), current.items.end(), *i) != current.items.end() );
01049 #endif
01050                         (*i)->DiscardPreviousValue();
01051                 }
01052                 else
01053                 {
01054 #ifdef DEBUG_CONTAINERS
01055                         ASSERT( find(current.items.begin(), current.items.end(), *i) == current.items.end() );
01056 #endif
01057                         (*i)->ChangeDirty(true);
01058                         current.items.push_front( (*i) );
01059                 }
01060 
01061                 ASSERT( (*i)->IsDirty() );
01062 
01063                 ++i;
01064         }
01065 
01066         // don't forget to set the read-only flag;
01067         current.readonly = previous->readonly;
01068         transactions.erase(previous);
01069 }
01070 
01071 void CCoreProject::TryUndoTransaction()
01072 {
01073         ASSERT( !InTransaction() );
01074         ASSERT( transactions.empty() );
01075         ASSERT( finaltr_items.empty() );
01076 
01077         try
01078         {
01079                 ASSERT( storage );
01080                 COMTHROW( storage->BeginTransaction() );
01081 
01082                 transactions.push_front(transaction_type());
01083                 transactions.front().readonly = true;
01084 
01085                 ASSERT( !undos.empty() );
01086 
01087                 undo_items_iterator i = undos.front().begin();
01088                 undo_items_iterator e = undos.front().end();
01089                 while( i != e )
01090                 {
01091                         ASSERT( (*i) != NULL );
01092                         (*i)->UndoTransaction();
01093 
01094                         ++i;
01095                 }
01096 
01097                 ASSERT( transactions.size() == 1 );
01098                 ASSERT( transactions.front().items.empty() );
01099                 ASSERT( finaltr_items.empty() );
01100 
01101                 transactions.pop_front();
01102 
01103                 ASSERT( storage );
01104                 COMTHROW( storage->CommitTransaction() );
01105 
01106                 // nothing will throw here
01107 
01108                 i = undos.front().begin();
01109                 ASSERT( e == undos.front().end() );
01110                 while( i != e )
01111                 {
01112                         ASSERT( (*i) != NULL );
01113                         (*i)->UndoTransactionFinish();
01114 
01115                         ++i;
01116                 }
01117 
01118                 ++redo_count;
01119                 undos.splice(undos.end(), undos, undos.begin());
01120         }
01121         catch(hresult_exception &)
01122         {
01123                 ASSERT(false);
01124 
01125                 if( !transactions.empty() )
01126                 {
01127                         ASSERT( transactions.front().items.empty() );
01128                         transactions.pop_front();
01129                 }
01130                 ASSERT( transactions.empty() );
01131 
01132                 ASSERT( storage );
01133                 storage->AbortTransaction();
01134         }
01135 
01136         ASSERT( transactions.empty() );
01137         ASSERT( finaltr_items.empty() );
01138 }
01139 
01140 void CCoreProject::TryRedoTransaction()
01141 {
01142         ASSERT( !InTransaction() );
01143         ASSERT( transactions.empty() );
01144         ASSERT( finaltr_items.empty() );
01145         ASSERT( !undos.empty() );
01146 
01147         try
01148         {
01149                 ASSERT( storage );
01150                 COMTHROW( storage->BeginTransaction() );
01151 
01152                 transactions.push_front(transaction_type());
01153                 transactions.front().readonly = true;
01154 
01155                 undo_items_iterator i = undos.back().begin();
01156                 undo_items_iterator e = undos.back().end();
01157                 while( i != e )
01158                 {
01159                         ASSERT( (*i) != NULL );
01160                         (*i)->RedoTransaction();
01161 
01162                         ++i;
01163                 }
01164 
01165                 ASSERT( transactions.size() == 1 );
01166                 ASSERT( transactions.front().items.empty() );
01167                 ASSERT( finaltr_items.empty() );
01168 
01169                 transactions.pop_front();
01170 
01171                 ASSERT( storage );
01172                 COMTHROW( storage->CommitTransaction() );
01173 
01174                 // nothing will throw here
01175 
01176                 i = undos.back().begin();
01177                 ASSERT( e == undos.back().end() );
01178                 while( i != e )
01179                 {
01180                         ASSERT( (*i) != NULL );
01181                         (*i)->RedoTransactionFinish();
01182 
01183                         ++i;
01184                 }
01185 
01186                 --redo_count;
01187                 undos.splice(undos.begin(), undos, --undos.end());
01188         }
01189         catch(hresult_exception &)
01190         {
01191                 if( !transactions.empty() )
01192                 {
01193                         ASSERT( transactions.front().items.empty() );
01194                         transactions.pop_front();
01195                 }
01196                 ASSERT( transactions.empty() );
01197 
01198                 ASSERT( storage );
01199                 storage->AbortTransaction();
01200         }
01201 
01202         ASSERT( transactions.empty() );
01203         ASSERT( finaltr_items.empty() );
01204 }
01205 
01206 void CCoreProject::TryDiscardLastItem()
01207 {
01208         ASSERT( !InTransaction() );
01209         ASSERT( transactions.empty() );
01210         ASSERT( finaltr_items.empty() );
01211         ASSERT( !undos.empty() );
01212 
01213         undo_items_type discarded;
01214 
01215         try
01216         {
01217                 ASSERT( storage );
01218                 COMTHROW( storage->BeginTransaction() );
01219 
01220                 transactions.push_front(transaction_type());
01221                 transactions.front().readonly = true;
01222 
01223                 undo_items_iterator i = undos.back().begin();
01224                 undo_items_iterator e = undos.back().end();
01225                 while( i != e )
01226                 {
01227                         ASSERT( (*i) != NULL );
01228                         (*i)->DiscardLastItem();
01229 
01230                         discarded.push_front(*i);
01231 
01232                         ++i;
01233                 }
01234 
01235                 ASSERT( transactions.size() == 1 );
01236                 ASSERT( transactions.front().items.empty() );
01237 
01238                 // now the final transaction items contain the modified locks
01239 
01240                 finaltr_items_iterator j = finaltr_items.begin();
01241                 finaltr_items_iterator d = finaltr_items.end();
01242                 while( j != d )
01243                 {
01244                         (*j)->CommitFinalTransaction();
01245 
01246                         ++j;
01247                 }
01248 
01249                 transactions.pop_front();
01250 
01251                 ASSERT( storage );
01252                 COMTHROW( storage->CommitTransaction() );
01253 
01254                 // nothing will throw here
01255 
01256                 // we clear undo info at attributes, before 
01257                 i = discarded.begin();
01258                 e = discarded.end();
01259                 while( i != e )
01260                 {
01261                         ASSERT( (*i) != NULL );
01262                         (*i)->DiscardLastItemFinish();
01263 
01264                         ++i;
01265                 }
01266 
01267                 discarded.clear();
01268 
01269                 // unloading by locking attributes
01270                 j = finaltr_items.begin();
01271                 ASSERT( d == finaltr_items.end() );
01272                 while( j != d )
01273                 {
01274                         (*j)->CommitFinalTransactionFinish(false);
01275 
01276                         ++j;
01277                 }
01278 
01279                 finaltr_items.clear();
01280 
01281                 if( --redo_count < 0 )
01282                         redo_count = 0;
01283 
01284                 undos.pop_back();
01285         }
01286         catch(hresult_exception &)
01287         {
01288                 undo_items_iterator i = discarded.begin();
01289                 undo_items_iterator e = discarded.end();
01290                 while( i != e )
01291                 {
01292                         ASSERT( (*i) != NULL );
01293                         (*i)->DiscardLastItemCancel();
01294 
01295                         ++i;
01296                 }
01297 
01298                 discarded.clear();
01299 
01300                 finaltr_items_iterator j = finaltr_items.begin();
01301                 finaltr_items_iterator d = finaltr_items.end();
01302                 while( j != d )
01303                 {
01304                         (*j)->AbortFinalTransaction();
01305 
01306                         ++j;
01307                 }
01308 
01309                 finaltr_items.clear();
01310 
01311                 if( !transactions.empty() )
01312                 {
01313                         ASSERT( transactions.front().items.empty() );
01314                         transactions.pop_front();
01315                 }
01316                 ASSERT( transactions.empty() );
01317 
01318                 ASSERT( storage );
01319                 storage->AbortTransaction();
01320         }
01321 
01322         ASSERT( transactions.empty() );
01323         ASSERT( finaltr_items.empty() );
01324         ASSERT( discarded.empty() );
01325 }
01326 
01327 ICoreStorage *CCoreProject::SetStorageObject(CCoreObject *object)
01328 {
01329         ASSERT( object != NULL );
01330 
01331         COMTHROW( storage->put_MetaObject(object->GetMetaObject()) );
01332 
01333         objid_type objid = object->GetObjID();
01334         ASSERT( objid != OBJID_NONE );
01335         
01336         COMTHROW( storage->OpenObject(objid) );
01337         
01338         return storage;
01339 }
01340 
01341 //inline 
01342 void CCoreProject::setMaxUndoStep( long p_undoSize)
01343 {
01344         if( p_undoSize > 0 && p_undoSize < 100)
01345                 m_maxUndoStep = (unsigned long) p_undoSize;
01346 }