GME
13
|
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 ¤t = 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 }