GME
13
|
00001 // MgaComplexOps.cpp : Implementation of FCO Copy/Move/Derive/Delete operations 00002 #include "stdafx.h" 00003 #include "MgaFCO.h" 00004 #include <map> 00005 #include "MgaComplexOps.h" 00006 #include "MgaSet.h" 00007 #include "limits.h" 00008 #define DETACHED_FROM "_detachedFrom" 00009 00010 00011 00012 00013 00014 void SingleObjTreeDelete(CoreObj &self, bool deleteself) { 00015 CComPtr<ICoreAttributes> atts; 00016 COMTHROW(self->get_Attributes(&atts)); 00017 MGACOLL_ITERATE(ICoreAttribute, atts) { 00018 attrid_type ai; 00019 CComPtr<ICoreMetaAttribute> mattr; 00020 COMTHROW(MGACOLL_ITER->get_MetaAttribute(&mattr)); 00021 COMTHROW(mattr->get_AttrID(&ai)); 00022 if(ai >= ATTRID_COLLECTION) { 00023 ai -= ATTRID_COLLECTION; 00024 if(LINKREF_ATTR(ai) && ai != ATTRID_PARENT) { 00025 CoreObjs collmembers = self[ai + ATTRID_COLLECTION]; 00026 ITERATE_THROUGH(collmembers) { 00027 SingleObjTreeDelete(ITER); 00028 } 00029 } 00030 } 00031 } MGACOLL_ITERATE_END; 00032 if(deleteself) COMTHROW(self->Delete()); 00033 } 00034 00035 00036 void FCO::inDeleteObject() { 00037 long status; 00038 COMTHROW(get_Status(&status)); 00039 metaid_type typ = GetMetaID(self); 00040 if(status == OBJECT_DELETED) 00041 return; // since collections contain objects, it may happen!!! 00042 // Step 1: delete structure of this object, but not the object itself 00043 if(typ == DTID_CONNECTION) { 00044 ITERATE_THROUGH(self[ATTRID_CONNROLE+ATTRID_COLLECTION]) CoreObjMark(ITER[ATTRID_XREF], OBJEVENT_DISCONNECTED); 00045 } 00046 else if(typ == DTID_SET) { 00047 ITERATE_THROUGH(self[ATTRID_SETMEMBER+ATTRID_COLLECTION]) CoreObjMark(ITER[ATTRID_XREF], OBJEVENT_SETEXCLUDED); 00048 } 00049 else if(typ == DTID_REFERENCE) { 00050 CoreObj h = self[ATTRID_REFERENCE]; if(h) CoreObjMark(h, OBJEVENT_REFRELEASED); 00051 } 00052 00053 if(typ != DTID_FOLDER) { 00054 CoreObjs children = self[ATTRID_DERIVED + ATTRID_COLLECTION]; 00055 ITERATE_THROUGH(children) ObjForCore(ITER)->inDeleteObject(); 00056 } 00057 00058 SingleObjTreeDelete(self, false); 00059 00060 // Step 2: delete children, and derivated objects 00061 if(typ == DTID_MODEL || typ == DTID_FOLDER) { 00062 CoreObjs children = self[ATTRID_FCOPARENT + ATTRID_COLLECTION]; 00063 ITERATE_THROUGH(children) ObjForCore(ITER)->inDeleteObject(); 00064 } 00065 // Step 3: mark or delete objects that are affected 00066 CoreObj parent; 00067 if(typ != DTID_FOLDER) { 00068 parent = self[ATTRID_FCOPARENT]; 00069 // REFERENCES set references to empty 00070 CoreObj const nil; // Null COM pointer 00071 { 00072 CoreObjs referringobjs = self[ATTRID_REFERENCE + ATTRID_COLLECTION]; 00073 ITERATE_THROUGH(referringobjs) { 00074 if(ITER.IsDeleted()) continue; // object was deleted during a previous iteration of the same cycle 00075 int todo = MODEMASK(MM_REF, MM_INTO); 00076 if(todo != MM_ERROR && MODEFLAG(MM_REF,MM_FULLDELETE)) { 00077 ObjForCore(ITER)->inDeleteObject(); 00078 } 00079 else { 00080 setcheck(mgaproject, ITER, todo == MM_ERROR ? CHK_ILLEGAL : CHK_CHANGED); 00081 ITER[ATTRID_REFERENCE] = nil; 00082 CoreObjMark(ITER, OBJEVENT_RELATION); 00083 } 00084 } 00085 } 00086 // OTHER types of xrefs: 00087 CoreObjs xrefs = self[ATTRID_XREF + ATTRID_COLLECTION]; 00088 ITERATE_THROUGH(xrefs) { 00089 if(ITER.IsDeleted()) continue; // object was deleted during a previous iteration of the same cycle 00090 switch(GetMetaID(ITER)) { 00091 case DTID_CONNROLE: 00092 // Connection role 00093 { 00094 CoreObj fco = ITER.GetMgaObj(); 00095 int todo = MODEMASK(MM_CONN, MM_INTO); 00096 if(todo != MM_ERROR && MODEFLAG(MM_CONN,MM_FULLDELETE)) { 00097 ObjForCore(fco)->inDeleteObject(); 00098 } 00099 else { 00100 setcheck(mgaproject, fco, todo == MM_ERROR ? CHK_ILLEGAL : CHK_CHANGED); 00101 SingleObjTreeDelete(ITER); 00102 CoreObjMark(fco, OBJEVENT_RELATION); 00103 } 00104 break; 00105 } 00106 case DTID_SETNODE: 00107 // Set 00108 { 00109 CoreObj fco = ITER.GetMgaObj(); 00110 int todo = MODEMASK(MM_SET, MM_INTO); 00111 if(todo != MM_ERROR && MODEFLAG(MM_SET,MM_FULLDELETE)) { 00112 ObjForCore(fco)->inDeleteObject(); 00113 } 00114 else { 00115 setcheck(mgaproject, fco, todo == MM_ERROR ? CHK_ILLEGAL : CHK_CHANGED); 00116 SingleObjTreeDelete(ITER); 00117 CoreObjMark(fco, OBJEVENT_RELATION); 00118 } 00119 break; 00120 } 00121 case DTID_REFATTR: 00122 // REF attribute: set it to NIL 00123 ITER[ATTRID_XREF] = nil; 00124 CoreObjMark(ITER[ATTRID_ATTRPARENT], OBJEVENT_ATTR); 00125 break; 00126 default: 00127 COMTHROW(E_MGA_META_INCOMPATIBILITY); 00128 } 00129 } 00130 if(typ == DTID_REFERENCE) { 00131 CoreObjs segrefs = self[ATTRID_SEGREF + ATTRID_COLLECTION]; 00132 ITERATE_THROUGH(segrefs) { 00133 if(ITER.IsDeleted()) continue; // object was deleted during a previous iteration of the same cycle 00134 CoreObj fco = ITER.GetMgaObj(); 00135 int todo = MODEMASK(MM_CONN, MM_INTO); 00136 if(todo != MM_ERROR && MODEFLAG(MM_CONN,MM_FULLDELETE)) { 00137 ObjForCore(fco)->inDeleteObject(); 00138 } 00139 else { 00140 setcheck(mgaproject, fco, todo == MM_ERROR ? CHK_ILLEGAL : CHK_CHANGED); 00141 SingleObjTreeDelete(CoreObj(ITER[ATTRID_CONNSEG])); 00142 CoreObjMark(fco, OBJEVENT_RELATION); 00143 } 00144 } 00145 } 00146 } 00147 else parent = self[ATTRID_FPARENT]; 00148 00149 //Step4: delete the object itself 00150 COMTHROW(self->Delete()); 00151 SelfMark(OBJEVENT_DESTROYED); 00152 CoreObjMark(parent, OBJEVENT_LOSTCHILD); 00153 } 00154 00155 // PreDelete Notification by Tihamer for the PAMS SynchTool 00156 void FCO::PreDeleteNotify() 00157 { 00158 /* 00159 00160 long status; 00161 COMTHROW(get_Status(&status)); 00162 metaid_type typ = GetMetaID(self); 00163 if(status == OBJECT_DELETED) return; // since collections contain objects, it may happen!!! 00164 */ 00165 metaid_type typ = GetMetaID(self); 00166 00167 if(typ == DTID_MODEL || typ == DTID_FOLDER) 00168 { 00169 CoreObjs children = self[ATTRID_FCOPARENT + ATTRID_COLLECTION]; 00170 ITERATE_THROUGH(children) ObjForCore(ITER)->PreDeleteNotify(); 00171 } 00172 00173 // Notification 00174 PreNotify(OBJEVENT_PRE_DESTROYED, CComVariant()); 00175 } 00176 00177 // Added by lph (Taken from PreDeleteNotify) Notification service for precursory object events 00178 HRESULT FCO::PreNotify(unsigned long changemask, CComVariant param) { 00179 COMTRY { 00180 CMgaProject::addoncoll::iterator ai, abeg = mgaproject->alladdons.begin(), aend = mgaproject->alladdons.end(); 00181 if(abeg != aend) 00182 { 00183 bool push_terr = mgaproject->activeterr != mgaproject->reserveterr; // this method can be reentrant 00184 if (push_terr) 00185 COMTHROW(mgaproject->pushterr(*mgaproject->reserveterr)); 00186 for(ai = abeg; ai != aend; ) 00187 { 00188 CComPtr<CMgaAddOn> t = *ai++; 00189 unsigned long mmask; 00190 if((mmask = (t->eventmask & changemask)) != 0) { 00191 CComPtr<IMgaObject> tt; 00192 getinterface(&tt); 00193 00194 if(t->handler->ObjectEvent(tt, mmask, param) != S_OK) { 00195 ASSERT(("Notification failed", false)); 00196 } 00197 t->notified = true; 00198 } 00199 } 00200 if (push_terr) 00201 COMTHROW(mgaproject->popterr()); 00202 } 00203 } COMCATCH(;) 00204 } 00205 00206 HRESULT FCO::DeleteObject() { 00207 COMTRY_IN_TRANSACTION { 00208 CheckWrite(); 00209 00210 if(self[ATTRID_PERMISSIONS] & LIBRARY_FLAG) { 00211 SetErrorInfo(L"Object is in a library. Library objects cannot be deleted."); 00212 COMRETURN_IN_TRANSACTION(E_MGA_OP_REFUSED); 00213 } 00214 if(self[ATTRID_PERMISSIONS] & READONLY_FLAG) 00215 { 00216 SetErrorInfo(L"Object is read-only"); 00217 COMRETURN_IN_TRANSACTION(E_MGA_OP_REFUSED); 00218 } 00219 // check for non-primary derived 00220 if(self[ATTRID_RELID] >= RELIDSPACE) { 00221 SetErrorInfo(L"Object is derived."); 00222 COMRETURN_IN_TRANSACTION(E_MGA_OP_REFUSED); 00223 } 00224 // check for rootfolder 00225 if(!CoreObj(self[ATTRID_PARENT]).IsContainer()) { 00226 COMTHROW(E_MGA_OP_REFUSED); 00227 } 00228 00229 PreDeleteNotify(); 00230 00231 inDeleteObject(); 00232 00233 docheck(mgaproject); 00234 00235 } COMCATCH_IN_TRANSACTION(;); 00236 } 00237 00238 00242 00243 // take second objects from list1, and put them to the first place into list2 00244 void shiftlist(coreobjpairhash &list1, coreobjhash &list2) { 00245 coreobjpairhash::iterator ii, beg = list1.begin(), end = list1.end(); 00246 for(ii = beg; ii != end; ++ii) list2.insert(coreobjhash::value_type((*ii).second, 0)); 00247 } 00248 00249 00250 void ObjTreeCollect(CMgaProject *mgaproject, CoreObj &self, coreobjhash &crealist, int code ) { 00251 metaid_type s = s = GetMetaID(self); 00252 if(s >= DTID_MODEL && s <= DTID_SET) { 00253 crealist.insert(coreobjhash::value_type(self, 0)); 00254 setcheck(mgaproject, self, code); 00255 } 00256 if(s == DTID_MODEL) { 00257 CoreObjs children = self[ATTRID_FCOPARENT + ATTRID_COLLECTION]; 00258 ITERATE_THROUGH(children) { 00259 ObjTreeCollect(mgaproject, ITER, crealist, code); 00260 } 00261 } 00262 } 00263 00264 // by ZolMol -invented by 00265 void ObjTreeCollectFoldersToo(CMgaProject *mgaproject, CoreObj &self, coreobjhash &crealist, int code ) { 00266 metaid_type s = s = GetMetaID(self); 00267 if(s >= DTID_MODEL && s <= DTID_FOLDER) { 00268 crealist.insert(coreobjhash::value_type(self, 0)); 00269 setcheck(mgaproject, self, code); 00270 } 00271 if(s == DTID_MODEL) { 00272 CoreObjs children = self[ATTRID_FCOPARENT + ATTRID_COLLECTION]; 00273 ITERATE_THROUGH(children) { 00274 ObjTreeCollectFoldersToo(mgaproject, ITER, crealist, code); 00275 } 00276 } 00277 if(s == DTID_FOLDER) { 00278 CoreObjs children = self[ATTRID_FCOPARENT + ATTRID_COLLECTION]; 00279 ITERATE_THROUGH(children) { 00280 ObjTreeCollectFoldersToo(mgaproject, ITER, crealist, code); 00281 } 00282 } 00283 } 00284 00285 void ObjTreeCopy(CMgaProject *mgaproject, CoreObj self, CoreObj &nobj, coreobjpairhash &crealist) 00286 { 00287 metaid_type s; 00288 COMTHROW(mgaproject->dataproject->CreateObject(s = GetMetaID(self), &nobj.ComPtr())); 00289 if( s>= DTID_MODEL && s <= DTID_FOLDER) 00290 assignGuid( mgaproject, nobj); 00291 if(s >= DTID_MODEL && s <= DTID_SET) { 00292 crealist.insert(coreobjpairhash::value_type(self, nobj)); 00293 setcheck(mgaproject, nobj, CHK_NEW); 00294 CoreObjMark(nobj, OBJEVENT_CREATED); 00295 } 00296 00297 CComPtr<ICoreAttributes> atts; 00298 COMTHROW(self->get_Attributes(&atts)); 00299 MGACOLL_ITERATE(ICoreAttribute, atts) { 00300 attrid_type ai; 00301 CComPtr<ICoreMetaAttribute> mattr; 00302 COMTHROW(MGACOLL_ITER->get_MetaAttribute(&mattr)); 00303 COMTHROW(mattr->get_AttrID(&ai)); 00304 if (ai == ATTRID_LOCK) 00305 continue; 00306 if(ai < ATTRID_COLLECTION) { 00307 // remove library flags from a copy 00308 // FIXME this looks wrong 00309 if(ai == ATTRID_PERMISSIONS) nobj[ai] = self[ai] & INSTANCE_FLAG; 00310 else if( ai == ATTRID_GUID1 // don't copy these 00311 || ai == ATTRID_GUID2 00312 || ai == ATTRID_GUID3 00313 || ai == ATTRID_GUID4) {} 00314 else nobj[ai] = static_cast<CComVariant>(self[ai]); 00315 } 00316 else { 00317 ai -= ATTRID_COLLECTION; 00318 if(LINKREF_ATTR(ai)) { 00319 CoreObjs collmembers = self[ai + ATTRID_COLLECTION]; 00320 ITERATE_THROUGH(collmembers) { 00321 CoreObj nchild; 00322 ObjTreeCopy(mgaproject, ITER, nchild, crealist); 00323 nchild[ai] = nobj; 00324 } 00325 } 00326 } 00327 00328 } MGACOLL_ITERATE_END; 00329 } 00330 00331 00332 void ObjTreeCopyFoldersToo(CMgaProject *mgaproject, CoreObj self, CoreObj &nobj, coreobjpairhash &crealist) { 00333 metaid_type s; 00334 COMTHROW(mgaproject->dataproject->CreateObject(s = GetMetaID(self), &nobj.ComPtr())); 00335 if(s >= DTID_MODEL && s <= DTID_FOLDER) { 00336 assignGuid( mgaproject, nobj); 00337 crealist.insert(coreobjpairhash::value_type(self, nobj)); 00338 setcheck(mgaproject, nobj, CHK_NEW); 00339 CoreObjMark(nobj, OBJEVENT_CREATED); 00340 } 00341 00342 CComPtr<ICoreAttributes> atts; 00343 COMTHROW(self->get_Attributes(&atts)); 00344 MGACOLL_ITERATE(ICoreAttribute, atts) { 00345 attrid_type ai; 00346 CComPtr<ICoreMetaAttribute> mattr; 00347 COMTHROW(MGACOLL_ITER->get_MetaAttribute(&mattr)); 00348 COMTHROW(mattr->get_AttrID(&ai)); 00349 if(ai < ATTRID_COLLECTION) { 00350 if (ai == ATTRID_LOCK) 00351 continue; 00352 // remove library flags from a copy 00353 // FIXME this looks wrong 00354 if(ai == ATTRID_PERMISSIONS) nobj[ai] = self[ai] & INSTANCE_FLAG; 00355 else if( ai == ATTRID_GUID1 // don't copy these 00356 || ai == ATTRID_GUID2 00357 || ai == ATTRID_GUID3 00358 || ai == ATTRID_GUID4) {} 00359 else nobj[ai] = static_cast<CComVariant>(self[ai]); 00360 } 00361 else { 00362 ai -= ATTRID_COLLECTION; 00363 if(LINKREF_ATTR(ai)) { 00364 CoreObjs collmembers = self[ai + ATTRID_COLLECTION]; 00365 ITERATE_THROUGH(collmembers) { 00366 CoreObj nchild; 00367 ObjTreeCopyFoldersToo(mgaproject, ITER, nchild, crealist); 00368 nchild[ai] = nobj; 00369 } 00370 } 00371 } 00372 00373 } MGACOLL_ITERATE_END; 00374 } 00375 00376 // get the derived-chain distance of the closest real basetype (or if there is none, the length of the full base chain) 00377 // if the object is not derived, or it is a real subtype/instance (i.e derived not because of its parent) 0 is returned 00378 00379 int GetRealSubtypeDist(CoreObj oldobj) { 00380 CoreObj pp = oldobj; 00381 int derdist = 0; 00382 while(pp[ATTRID_RELID] >= RELIDSPACE) { 00383 pp = pp[ATTRID_DERIVED]; 00384 ASSERT(pp); 00385 derdist++; 00386 } 00387 return derdist; 00388 } 00389 00390 void ObjTreeDist(CoreObj self, int derdist) { 00391 CComPtr<ICoreAttributes> atts; 00392 COMTHROW(self->get_Attributes(&atts)); 00393 MGACOLL_ITERATE(ICoreAttribute, atts) { 00394 attrid_type ai; 00395 CComPtr<ICoreMetaAttribute> mattr; 00396 COMTHROW(MGACOLL_ITER->get_MetaAttribute(&mattr)); 00397 COMTHROW(mattr->get_AttrID(&ai)); 00398 if(ai == ATTRID_DERIVED) { 00399 CoreObj h = self; 00400 for(int i = 0; i < derdist && (h = h[ATTRID_DERIVED]); i++) { 00401 MergeRegs(h,self); 00402 MergeAttrs(h,self); 00403 } 00404 CoreObj p; 00405 self[ai] = p = self.FollowChain(ai, derdist+1); 00406 // FIXME this looks wrong 00407 if(p) self[ATTRID_PERMISSIONS] = p[ATTRID_PERMISSIONS] & INSTANCE_FLAG; 00408 else self[ATTRID_PERMISSIONS] = 0; 00409 } 00410 else if(ai == ATTRID_MASTEROBJ) { 00411 self[ai] = self.FollowChain(ai, derdist+1); 00412 } 00413 if(ai == ATTRID_FCOPARENT + ATTRID_COLLECTION || 00414 ai == ATTRID_CONNROLE + ATTRID_COLLECTION || 00415 ai == ATTRID_SETMEMBER + ATTRID_COLLECTION) { 00416 CoreObjs collmembers = self[ai]; 00417 ITERATE_THROUGH(collmembers) { 00418 ObjTreeDist(ITER, derdist); 00419 } 00420 } 00421 00422 } MGACOLL_ITERATE_END; 00423 } 00424 00425 00427 // ObjTreeDerive 00429 // Create a derived deep copy of 'origobj' to 'newobj' 00430 // -- 'newobj' tree is exact copy of 'origobj' tree, except 00431 // ATTRID_INSTANCE: set if instance, copied from 'origobj' tree othervise 00432 // ATTRID_DERIVED & ATTRID_MASTEROBJ: point to the corresponding object in 'origobj' tree 00433 // ATTRID_GUID1..4, which are assigned new value 00434 // -- on return the new root object 'newobj' will also be contained in the container of 'origobj'. 00435 // -- new FCO-s are inserted in 'crealist' 00437 // !!! RECURSIVE 00439 void ObjTreeDerive(CMgaProject *mgaproject, const CoreObj &origobj, CoreObj &newobj, coreobjpairhash &crealist, long instance) { 00440 metaid_type s; 00441 COMTHROW(mgaproject->dataproject->CreateObject(s = origobj.GetMetaID(), &newobj.ComPtr())); 00442 if( s >= DTID_MODEL && s <= DTID_FOLDER) 00443 assignGuid( mgaproject, newobj); // assigns new value to ATTRID_GUID1..4 00444 if(s >= DTID_MODEL && s <= DTID_SET) { 00445 crealist.insert(coreobjpairhash::value_type(origobj, newobj)); 00446 setcheck(mgaproject, newobj, CHK_NEW); 00447 CoreObjMark(newobj, OBJEVENT_CREATED); 00448 } 00449 00450 CComPtr<ICoreAttributes> atts; 00451 COMTHROW(origobj->get_Attributes(&atts)); 00452 MGACOLL_ITERATE(ICoreAttribute, atts) { 00453 attrid_type ai; 00454 CComPtr<ICoreMetaAttribute> mattr; 00455 COMTHROW(MGACOLL_ITER->get_MetaAttribute(&mattr)); 00456 COMTHROW(mattr->get_AttrID(&ai)); 00457 if(ai < ATTRID_COLLECTION) { 00458 switch(ai) { 00459 case ATTRID_DERIVED: 00460 case ATTRID_MASTEROBJ: 00461 newobj[ai] = origobj; 00462 break; 00463 case ATTRID_PERMISSIONS: 00464 // overwrite copy only if instance 00465 // PETER'S FIX 00466 // newobj[ai] = (origobj[ai] | long(instance)) & INSTANCE_FLAG; 00467 newobj[ai] = (origobj[ai] | long(instance)) & INSTANCE_FLAG; 00468 // PETER END 00469 break; 00470 case ATTRID_RELID: 00471 { 00472 // if newobj[ai] + RELIDSPACE > LONG_MAX 00473 if (newobj[ai] > LONG_MAX - RELIDSPACE) 00474 COMTHROW(E_MGA_LONG_DERIVCHAIN); 00475 long relid = origobj[ai]+RELIDSPACE; 00476 ASSERT(relid > 0); 00477 newobj[ai] = relid; 00478 } 00479 break; 00480 case ATTRID_LASTRELID: 00481 newobj[ai] = 0L; 00482 break; 00483 case ATTRID_REGNODE: 00484 case ATTRID_GUID1: // don't copy these 00485 case ATTRID_GUID2: 00486 case ATTRID_GUID3: 00487 case ATTRID_GUID4: 00488 case ATTRID_LOCK: break; 00489 default: 00490 newobj[ai] = static_cast<CComVariant>(origobj[ai]); 00491 } 00492 } 00493 else { 00494 ai -= ATTRID_COLLECTION; 00495 if(LINKREF_ATTR(ai) && ai != ATTRID_ATTRPARENT) { 00496 CoreObjs collmembers = origobj[ai + ATTRID_COLLECTION]; 00497 ITERATE_THROUGH(collmembers) { 00498 CoreObj nchild; 00499 ObjTreeDerive(mgaproject, ITER, nchild, crealist, instance); 00500 nchild[ai] = newobj; 00501 } 00502 if(ai == ATTRID_FCOPARENT && collmembers.Count() > 0) { 00503 CoreObjMark(newobj, OBJEVENT_NEWCHILD); 00504 } 00505 } 00506 } 00507 00508 } MGACOLL_ITERATE_END; 00509 } 00510 00511 00512 00514 // ObjTreeReconnect 00516 // Reconnects relations in a newly copied/derived tree 00517 // 00518 // -- 'crealist'contains old-new equivalent pairs for quick access 00519 // -- if object is not in crealist, it may still be reconnected 00520 // if it is an internal reference, (i.e., the ends of the pointer belong to the same rootFCO). 00521 // -- if the relation has a masterobj, then the relation of the root masterobj is checked 00522 // -- otherwise the target of the ralation must be contained in the crealist (list of newly created objects) 00523 // -- return value used internally to indicate that the tree contained relations which were not reconnected 00525 // !!! RECURSIVE 00527 bool ObjTreeReconnect(CoreObj self, coreobjpairhash &crealist, CoreObj const &derivtgt) { 00528 typedef struct { metaid_type mid; int search, reconnect; } table; 00529 static const table tab[] = { 00530 {DTID_MODEL, ATTRID_FCOPARENT, 0}, 00531 {DTID_REFERENCE, 0, ATTRID_REFERENCE}, 00532 {DTID_SET, ATTRID_SETMEMBER, 0}, 00533 {DTID_SETNODE, 0, ATTRID_XREF }, 00534 {DTID_CONNECTION, ATTRID_CONNROLE, 0}, 00535 {DTID_CONNROLE, ATTRID_CONNSEG, ATTRID_XREF}, 00536 {DTID_CONNROLESEG, 0, ATTRID_SEGREF} 00537 }; 00538 00539 00540 bool containedexternal = false; 00541 metaid_type n = GetMetaID(self); 00542 00543 for(int i = 0; i < sizeof(tab) / sizeof(tab[0]); i++) { 00544 if(tab[i].mid == n) { 00545 const table *ll = &tab[i]; 00546 if(ll->search) { 00547 CoreObjs children = self[ll->search+ATTRID_COLLECTION]; 00548 if(n == DTID_CONNROLE) { 00549 children.Sort(); 00550 } 00551 ITERATE_THROUGH(children) { 00552 if(ObjTreeReconnect(ITER,crealist, derivtgt)) { 00553 containedexternal = true; 00554 if(n == DTID_CONNROLE) break; // stop processing rolesegments after an ext ref. 00555 } 00556 } 00557 } 00558 if(!containedexternal && ll->reconnect) { 00559 // the relationship pointer will to be reconnected if 00560 // - the object has no master (only possible with copied objects) 00561 // - or the relation in the most original base is internal 00562 if(!self.GetMaster() || IsInternalRelation(self)) { 00563 CoreObj oldr = self[ll->reconnect]; 00564 coreobjpairhash::iterator i = crealist.find(oldr); 00565 if(i != crealist.end()) { 00566 // if it is a reference to a newly created object: use lookup 00567 self[ll->reconnect] = (*i).second; 00568 } 00569 else if(derivtgt) { 00570 ASSERT(CoreObj(derivtgt[ATTRID_DERIVED])); 00571 ASSERT(derivtgt[ATTRID_RELID] < RELIDSPACE); 00572 CoreObj newr; 00573 GetDerivedEquivalent(oldr, derivtgt, newr); 00574 self[ll->reconnect] = newr; 00575 } 00576 else if( n == DTID_SETNODE) // if setnode not found while copying a set, 00577 { // delete the membership entry, thus allow a set to be copied without its members 00578 // previously Sets could not be copied&pasted only along with their members 00579 removemember().DoWithDeriveds(self); 00580 } 00581 } 00582 else containedexternal = true; 00583 } 00584 break; 00585 } 00586 } 00587 return containedexternal; 00588 } 00589 00590 bool ObjTreeReconnectFoldersToo(CoreObj self, coreobjpairhash &crealist, CoreObj const &derivtgt) { 00591 typedef struct { metaid_type mid; int search, reconnect; } table; 00592 static const table tab[] = { 00593 {DTID_FOLDER, ATTRID_FCOPARENT, 0}, 00594 {DTID_MODEL, ATTRID_FCOPARENT, 0}, 00595 {DTID_REFERENCE, 0, ATTRID_REFERENCE}, 00596 {DTID_SET, ATTRID_SETMEMBER, 0}, 00597 {DTID_SETNODE, 0, ATTRID_XREF }, 00598 {DTID_CONNECTION, ATTRID_CONNROLE, 0}, 00599 {DTID_CONNROLE, ATTRID_CONNSEG, ATTRID_XREF}, 00600 {DTID_CONNROLESEG, 0, ATTRID_SEGREF} 00601 }; 00602 00603 00604 bool containedexternal = false; 00605 metaid_type n = GetMetaID(self); 00606 00607 for(int i = 0; i < sizeof(tab) / sizeof(tab[0]); i++) { 00608 if(tab[i].mid == n) { 00609 const table *ll = &tab[i]; 00610 if(ll->search) { 00611 CoreObjs children = self[ll->search+ATTRID_COLLECTION]; 00612 if(n == DTID_CONNROLE) { 00613 children.Sort(); 00614 } 00615 ITERATE_THROUGH(children) { 00616 if (GetMetaID(ITER) == DTID_FOLDER) { 00617 if(ObjTreeReconnectFoldersToo(ITER, crealist, derivtgt)) { 00618 containedexternal = true; 00619 } 00620 } else { 00621 if(ObjTreeReconnect(ITER, crealist, derivtgt)) { 00622 containedexternal = true; 00623 if(n == DTID_CONNROLE) break; // stop processing rolesegments after an ext ref. 00624 } 00625 } 00626 } 00627 } 00628 if(!containedexternal && ll->reconnect) { 00629 // the relationship pointer will to be reconnected if 00630 // - the object has no master (only possible with copied objects) 00631 // - or the relation in the most original base is internal 00632 if(!self.GetMaster() || IsInternalRelation(self)) { 00633 CoreObj oldr = self[ll->reconnect]; 00634 coreobjpairhash::iterator i = crealist.find(oldr); 00635 if(i != crealist.end()) { 00636 // if it is a reference to a newly created object: use lookup 00637 self[ll->reconnect] = (*i).second; 00638 } 00639 else if(derivtgt) { 00640 ASSERT(CoreObj(derivtgt[ATTRID_DERIVED])); 00641 ASSERT(derivtgt[ATTRID_RELID] < RELIDSPACE); 00642 CoreObj newr; 00643 GetDerivedEquivalent(oldr, derivtgt, newr); 00644 self[ll->reconnect] = newr; 00645 } 00646 } 00647 else containedexternal = true; 00648 } 00649 break; 00650 } 00651 } 00652 return containedexternal; 00653 } 00654 00655 00656 00658 // ObjTreeCheckRelations 00660 // Removes outgoing/internal relations (or whole objects) in a newly copied/derived/moved tree 00661 // The policy is based on the project-wide operationsmask queried with MM_OUTOF or MM_INTERNAL masks 00662 // 00663 // -- 'self' is the root of the tree, 00664 // -- 'internals' are all the objects that are considered internal for this operation 00665 // -- all relations hold by references, sets and connections are checked 00666 // -- if the required operation is 00667 // - MM_ERROR: error is signaled 00668 // - MM_CLEAR: the corresponding pointer is cleared 00669 // - MM_CLEAR & MM_FULLDELETE: the object itself is cleared 00670 // - MM_DO: nothing happens 00672 // !!! RECURSIVE 00674 void ObjTreeCheckRelations(CMgaProject *mgaproject, CoreObj &self, coreobjhash &internals) { 00675 typedef struct { metaid_type mid; int search, check, mm; } table; 00676 static const table tab[] = { 00677 {DTID_MODEL, ATTRID_FCOPARENT, 0}, 00678 {DTID_REFERENCE, 0, ATTRID_REFERENCE, MM_REF}, 00679 {DTID_SET, ATTRID_SETMEMBER, 0}, 00680 {DTID_SETNODE, 0, ATTRID_XREF, MM_SET }, 00681 {DTID_CONNECTION, ATTRID_CONNROLE, 0}, 00682 {DTID_CONNROLE, ATTRID_CONNSEG, ATTRID_XREF, MM_CONN}, 00683 {DTID_CONNROLESEG, 0, ATTRID_SEGREF} 00684 }; 00685 00686 metaid_type n = GetMetaID(self); 00687 00688 for(int i = 0; i < sizeof(tab) / sizeof(tab[0]); i++) { 00689 if(tab[i].mid == n) { 00690 const table *ll = &tab[i]; 00691 if(ll->search) { 00692 CoreObjs children = self[ll->search+ATTRID_COLLECTION]; 00693 ITERATE_THROUGH(children) { 00694 if(ITER.IsDeleted()) continue; 00695 ObjTreeCheckRelations(mgaproject, ITER, internals); 00696 } 00697 } 00698 if(ll->check && !self.IsDeleted()) { 00699 CoreObj tgt = self[ll->check]; 00700 int mm2 = (internals.find(tgt) != internals.end()) ? MM_INTERNAL : MM_OUTOF; 00701 switch(MODEMASK(ll->mm, mm2)) { 00702 case MM_ERROR: COMTHROW(E_MGA_OP_REFUSED); 00703 case MM_CLEAR: 00704 self[ll->check] = NULLCOREOBJ; 00705 CoreObj selfobj = self.GetMgaObj(); 00706 if( (GetMetaID(selfobj) == DTID_CONNECTION && ObjForCore(selfobj)->simpleconn()) || 00707 MODEFLAG(ll->mm, MM_FULLDELETE)) { 00708 ObjForCore(selfobj)->inDeleteObject(); 00709 } 00710 else { 00711 if(n != DTID_REFERENCE) { 00712 if(n == DTID_CONNROLESEG) self = self[ATTRID_CONNSEG]; 00713 SingleObjTreeDelete(self); 00714 } 00715 } 00716 } 00717 } 00718 break; 00719 } 00720 } 00721 } 00722 00723 void ObjTreeCheckRelationsFoldersToo(CMgaProject *mgaproject, CoreObj &self, coreobjhash &internals) { 00724 typedef struct { metaid_type mid; int search, check, mm; } table; 00725 static const table tab[] = { 00726 {DTID_FOLDER, ATTRID_FCOPARENT, 0}, 00727 {DTID_MODEL, ATTRID_FCOPARENT, 0}, 00728 {DTID_REFERENCE, 0, ATTRID_REFERENCE, MM_REF}, 00729 {DTID_SET, ATTRID_SETMEMBER, 0}, 00730 {DTID_SETNODE, 0, ATTRID_XREF, MM_SET }, 00731 {DTID_CONNECTION, ATTRID_CONNROLE, 0}, 00732 {DTID_CONNROLE, ATTRID_CONNSEG, ATTRID_XREF, MM_CONN}, 00733 {DTID_CONNROLESEG, 0, ATTRID_SEGREF} 00734 }; 00735 00736 metaid_type n = GetMetaID(self); 00737 00738 for(int i = 0; i < sizeof(tab) / sizeof(tab[0]); i++) { 00739 if(tab[i].mid == n) { 00740 const table *ll = &tab[i]; 00741 if(ll->search) { 00742 CoreObjs children = self[ll->search+ATTRID_COLLECTION]; 00743 ITERATE_THROUGH(children) { 00744 if(ITER.IsDeleted()) continue; 00745 ObjTreeCheckRelationsFoldersToo(mgaproject, ITER, internals); 00746 } 00747 } 00748 if(ll->check && !self.IsDeleted()) { 00749 CoreObj tgt = self[ll->check]; 00750 int mm2 = (internals.find(tgt) != internals.end()) ? MM_INTERNAL : MM_OUTOF; 00751 switch(MODEMASK(ll->mm, mm2)) { 00752 case MM_ERROR: COMTHROW(E_MGA_OP_REFUSED); 00753 case MM_CLEAR: 00754 self[ll->check] = NULLCOREOBJ; 00755 CoreObj selfobj = self.GetMgaObj(); 00756 if( (GetMetaID(selfobj) == DTID_CONNECTION && ObjForCore(selfobj)->simpleconn()) || 00757 MODEFLAG(ll->mm, MM_FULLDELETE)) { 00758 ObjForCore(selfobj)->inDeleteObject(); 00759 } 00760 else { 00761 if(n != DTID_REFERENCE) { 00762 if(n == DTID_CONNROLESEG) self = self[ATTRID_CONNSEG]; 00763 SingleObjTreeDelete(self); 00764 } 00765 } 00766 } 00767 } 00768 break; 00769 } 00770 } 00771 } 00772 00774 // ObjTreeCheckINTORelations 00776 // Removes incoming relations (or whole objects) that point into a newly copied/derived/moved tree 00777 // The policy is based on the project-wide operationsmask queried with MM_INTO mask 00778 // 00779 // -- 'self' is the root of the tree, 00780 // -- 'internals' are all the objects that are considered internal for this operation 00781 // -- all relations that point to objects in the tree are checked. 00782 // -- if the required operation is 00783 // - MM_ERROR: error is signaled 00784 // - MM_CLEAR: the corresponding pointer is cleared 00785 // - MM_CLEAR & MM_FULLDELETE: the object itself is cleared 00786 // - MM_DO: nothing happens 00787 void ObjCheckINTORelations(CMgaProject* mgaproject, CoreObj& self, coreobjhash& internals) { 00788 metaid_type n = GetMetaID(self); 00789 ASSERT(n >= DTID_MODEL && n <= DTID_SET); 00790 if (n == DTID_REFERENCE) { 00791 // GME-311: need to delete connections into refport 'conn_seg' iff 00792 // connection 'rel_owner' is not in internals and 'conn_seg' is the actual connection end (not an intermediary) 00793 CoreObjs conn_segs = self[ATTRID_SEGREF + ATTRID_COLLECTION]; 00794 ITERATE_THROUGH(conn_segs) { 00795 CoreObj conn_seg = ITER; 00796 metaid_type st = GetMetaID(conn_seg); 00797 ASSERT(st == DTID_CONNROLESEG); 00798 if (st != DTID_CONNROLESEG) { 00799 continue; 00800 } 00801 CoreObj rel_owner = conn_seg.GetMgaObj(); 00802 if (!rel_owner) { 00803 continue; // connection might be deleted due to a previous relation 00804 } 00805 ASSERT(GetMetaID(rel_owner) == DTID_CONNECTION); 00806 #ifdef _DEBUG 00807 CoreObj role = conn_seg[ATTRID_CONNSEG]; 00808 CComBSTR conn_name = rel_owner[ATTRID_NAME], role_name = role[ATTRID_NAME]; 00809 #endif 00810 ASSERT(ObjForCore(rel_owner)->simpleconn()); // KMS: don't think we can get here without a simpleconn 00811 if (internals.find(rel_owner) == internals.end() && ObjForCore(rel_owner)->simpleconn()) { 00812 setcheck(mgaproject, rel_owner, CHK_CHANGED); 00813 switch(MODEMASK(MM_CONN, MM_INTO)) { 00814 case MM_ERROR: COMTHROW(E_MGA_OP_REFUSED); 00815 break; 00816 case MM_CLEAR: 00817 if (conn_seg[ATTRID_SEGORDNUM] == 1) { 00818 ObjForCore(rel_owner)->inDeleteObject(); 00819 break; 00820 } 00821 } 00822 } 00823 } 00824 } 00825 00826 CoreObjs xrefs = self[ATTRID_XREF + ATTRID_COLLECTION]; 00827 ITERATE_THROUGH(xrefs) { 00828 metaid_type st = GetMetaID(ITER); 00829 if(st != DTID_SETNODE && st != DTID_CONNROLE) { 00830 continue; 00831 } 00832 CoreObj rel_owner = ITER.GetMgaObj(); 00833 if (!rel_owner) { 00834 continue; // connection/set might be deleted due to a previous relation 00835 } 00836 00837 if(internals.find(rel_owner) == internals.end()) { 00838 int ttt = st == DTID_CONNROLE ? MM_CONN : MM_SET; 00839 setcheck(mgaproject, rel_owner, CHK_CHANGED); 00840 switch(MODEMASK(ttt, MM_INTO)) { 00841 case MM_ERROR: COMTHROW(E_MGA_OP_REFUSED); 00842 break; 00843 case MM_CLEAR: 00844 if (st == DTID_CONNROLE && ObjForCore(rel_owner)->simpleconn()) { 00845 // GME-297: don't delete connections connecting to refports 00846 // (outside connections to inside refports are deleted above) 00847 long count = 0; 00848 CoreObjs refport_refs = ITER[ATTRID_CONNSEG+ATTRID_COLLECTION]; // i.e. refport containers 00849 COMTHROW(refport_refs->get_Count(&count)); 00850 if (count == 0) { 00851 // this connection role is connected directly; it is not connected to a refport 00852 ObjForCore(rel_owner)->inDeleteObject(); 00853 } 00854 } else if (MODEFLAG(ttt, MM_FULLDELETE)) { 00855 ObjForCore(rel_owner)->inDeleteObject(); 00856 } 00857 else { 00858 CoreObjMark(self, st == DTID_CONNROLE ? OBJEVENT_DISCONNECTED : OBJEVENT_SETEXCLUDED); 00859 CoreObjMark(rel_owner, OBJEVENT_RELATION); 00860 SingleObjTreeDelete(ITER); 00861 } 00862 break; 00863 } 00864 } 00865 } 00866 { 00867 CoreObjs refs = self[ATTRID_REFERENCE + ATTRID_COLLECTION]; 00868 ITERATE_THROUGH(refs) { 00869 CoreObj rel_owner = ITER; 00870 if(internals.find(rel_owner) == internals.end()) { 00871 setcheck(mgaproject, rel_owner, CHK_CHANGED); 00872 switch(MODEMASK(MM_REF, MM_INTO)) { 00873 case MM_ERROR: COMTHROW(E_MGA_OP_REFUSED); 00874 case MM_CLEAR: 00875 if(MODEFLAG(MM_REF, MM_FULLDELETE)) { 00876 ObjForCore(rel_owner)->inDeleteObject(); 00877 } 00878 else { 00879 rel_owner[ATTRID_REFERENCE] = NULLCOREOBJ; 00880 CoreObjMark(self, OBJEVENT_REFRELEASED); 00881 CoreObjMark(rel_owner, OBJEVENT_RELATION); 00882 } 00883 } 00884 } 00885 } 00886 } 00887 } 00888 00889 00891 // !!! RECURSIVE 00893 void ObjTreeCheckINTORelations(CMgaProject *mgaproject, CoreObj &self, coreobjhash &internals) { 00894 metaid_type n = GetMetaID(self); 00895 ASSERT(n >= DTID_MODEL && n <= DTID_SET); 00896 ObjCheckINTORelations(mgaproject, self, internals); 00897 00898 if(n == DTID_MODEL) { 00899 CoreObjs children = self[ATTRID_FCOPARENT + ATTRID_COLLECTION]; 00900 ITERATE_THROUGH(children) { 00901 ObjTreeCheckINTORelations(mgaproject, ITER, internals); 00902 } 00903 } 00904 } 00905 00906 00908 // !!! RECURSIVE 00910 void ObjTreeCheckINTORelationsFoldersToo(CMgaProject *mgaproject, CoreObj &self, coreobjhash &internals) { 00911 metaid_type n = GetMetaID(self); 00912 ASSERT(n >= DTID_MODEL && n <= DTID_FOLDER); 00913 if ( n >= DTID_MODEL && n <= DTID_SET) 00914 { 00915 ObjCheckINTORelations(mgaproject, self, internals); 00916 } 00917 if(n == DTID_MODEL || n == DTID_FOLDER) { 00918 CoreObjs children = self[ATTRID_FCOPARENT + ATTRID_COLLECTION]; 00919 ITERATE_THROUGH(children) { 00920 ObjTreeCheckINTORelationsFoldersToo(mgaproject, ITER, internals); 00921 } 00922 } 00923 } 00924 00925 void ObjTreeNotify(CMgaProject *mgaproject, CoreObj &self) { 00926 int k = OBJEVENT_CREATED; 00927 metaid_type typ = GetMetaID(self); 00928 if(typ == DTID_FOLDER || typ == DTID_MODEL) { 00929 CoreObjs children = self[ATTRID_FCOPARENT + ATTRID_COLLECTION]; 00930 ITERATE_THROUGH(children) { 00931 k |= OBJEVENT_NEWCHILD; 00932 ObjTreeNotify(mgaproject, ITER); 00933 } 00934 } 00935 else if(typ == DTID_REFERENCE) { 00936 CoreObj rr = self[ATTRID_REFERENCE]; 00937 if(rr) { 00938 CComPtr<IMgaFCO> fco; 00939 ObjForCore(rr)->getinterface(&fco); 00940 mgaproject->ObjMark(fco, OBJEVENT_REFERENCED); 00941 } 00942 } 00943 else if(typ == DTID_CONNECTION || typ == DTID_SET) { 00944 00945 CoreObjs rrs; 00946 long msg; 00947 if(typ == DTID_SET) { 00948 rrs = self[ATTRID_SETMEMBER+ATTRID_COLLECTION]; 00949 msg = OBJEVENT_SETINCLUDED; 00950 } 00951 else { 00952 rrs = self[ATTRID_CONNROLE+ATTRID_COLLECTION]; 00953 msg = OBJEVENT_CONNECTED; 00954 } 00955 ITERATE_THROUGH(rrs) { 00956 CoreObj fff = ITER[ATTRID_XREF]; 00957 if(fff) { 00958 CComPtr<IMgaFCO> fco; 00959 ObjForCore(fff)->getinterface(&fco); 00960 mgaproject->ObjMark(fco, msg); 00961 } 00962 } 00963 } 00964 ObjForCore(self)->SelfMark(k); 00965 } 00966 00967 // check of obj or any of its children is derived from root 00968 void CheckConflict(CoreObj &b, CoreObj &root) { 00969 00970 if(GetMetaID(b) == DTID_MODEL) { 00971 CoreObj base = b[ATTRID_DERIVED]; 00972 while(base) { 00973 if(COM_EQUAL(base, root)) COMTHROW(E_MGA_OP_REFUSED); 00974 base = base[ATTRID_DERIVED]; 00975 } 00976 CoreObjs children = b[ATTRID_FCOPARENT + ATTRID_COLLECTION]; 00977 ITERATE_THROUGH(children) { 00978 CheckConflict(ITER, root); 00979 } 00980 } 00981 } 00982 00983 00985 // DeriveNewObjs 00988 // !!! RECURSIVE 00990 void ReDeriveNewObjs(CMgaProject *mgaproject, std::vector<CoreObj> &orignobjs, int cnt, int targetlevel) { 00991 ASSERT(targetlevel >= 1); 00992 if(cnt < 1) return; 00993 CoreObj orig = orignobjs[0][ATTRID_PARENT]; 00994 if(!orig.IsFCO()) return; 00995 CoreObjs deriveds = orig[ATTRID_DERIVED+ATTRID_COLLECTION]; 00996 ITERATE_THROUGH(deriveds) { 00997 int i; 00998 // we look for the object (subtypebase) which has been derived primarily (a parent of ITER most probably) 00999 // subtypebase will be used when internal references need to be redirected [ObjTreeReconnect call] 01000 // an internal reference is: 01001 // - part of a model which is derived 01002 // - its target is also part of that model 01003 // when such a reference is found in a derived model it is redirected to 01004 // the target's derived counterpart. more details: GetDerivedEquivalent() [in MgaDeriveOps.cpp] 01005 // WAS: CoreObj subtypebase = ITER.FollowChain(ATTRID_PARENT, targetlevel); 01006 CoreObj subtypebase = ITER.FollowChain(ATTRID_PARENT, targetlevel-1); 01007 coreobjpairhash derivcrealist; 01008 coreobjhash derivmovedlist; 01009 long instance = ITER[ATTRID_PERMISSIONS] & INSTANCE_FLAG; 01010 std::vector<CoreObj> newderiveds(cnt); 01011 for(i = 0; i< cnt; i++) { 01012 ObjTreeDerive(mgaproject, orignobjs[i], newderiveds[i], derivcrealist, instance); 01013 newderiveds[i][ATTRID_FCOPARENT]=ITER; 01014 } 01015 if(cnt) CoreObjMark(ITER, OBJEVENT_NEWCHILD); 01016 // Reroute references 01017 for(i = 0; i< cnt; i++) { 01018 ObjTreeReconnect(newderiveds[i], derivcrealist, subtypebase); 01019 } 01020 shiftlist(derivcrealist, derivmovedlist); 01021 for(i = 0; i< cnt; i++) { 01022 ObjTreeCheckRelations(mgaproject, newderiveds[i], derivmovedlist); 01023 } 01024 ReDeriveNewObjs(mgaproject, newderiveds, cnt, targetlevel); 01025 } 01026 } 01027 01028 01029 void ReDeriveNewObj(CMgaProject *mgaproject, CoreObj &orignobj, int targetlevel) { 01030 std::vector<CoreObj> vv(1); 01031 vv[0] = orignobj; 01032 ReDeriveNewObjs(mgaproject, vv, 1, targetlevel); 01033 } 01034 01035 01036 01040 01041 01042 HRESULT FCO::CopyFCOs(IMgaFCOs *copylist, IMgaMetaRoles *rlist,IMgaFCOs **objs) { 01043 COMTRY_IN_TRANSACTION_MAYBE { 01044 CheckWrite(); 01045 CHECK_MYINPTRSPAR(copylist); 01046 long cnt; 01047 COMTHROW(copylist->get_Count(&cnt)); 01048 if(rlist) { 01049 long rlcnt; 01050 COMTHROW(rlist->get_Count(&rlcnt)); 01051 if(rlcnt != cnt) COMTHROW(E_MGA_BAD_COLLENGTH); 01052 } 01053 metaid_type targettype = GetMetaID(self); 01054 int targetlevel = 0; 01055 CoreObj rootp; 01056 // Pre check: 01057 if(targettype == DTID_MODEL) { 01058 if(self[ATTRID_PERMISSIONS] & ~EXEMPT_FLAG) COMTHROW(E_MGA_NOT_CHANGEABLE); 01059 GetRootOfDeriv(self, rootp, &targetlevel); 01060 if(rootp) { 01061 MGACOLL_ITERATE(IMgaFCO, copylist) { 01062 CheckConflict(CoreObj(MGACOLL_ITER), rootp); 01063 } MGACOLL_ITERATE_END; 01064 } 01065 } 01066 01067 // Copy trees 01068 coreobjpairhash crealist; 01069 int i = 0; 01070 01071 std::vector<CoreObj> nobjs(cnt); 01072 MGACOLL_ITERATE(IMgaFCO, copylist) { 01073 long relId; 01074 COMTHROW(MGACOLL_ITER->get_RelID(&relId)); // GME-335:essentially CheckRead 01075 CoreObj oldobj = CoreObj(MGACOLL_ITER); 01076 ObjForCore(oldobj)->SelfMark(OBJEVENT_COPIED); 01077 int derdist = GetRealSubtypeDist(oldobj); 01078 ObjTreeCopy(mgaproject, oldobj, nobjs[i], crealist); // copy 01079 if(derdist) ObjTreeDist(nobjs[i], derdist); 01080 // assigns a new relid to nobjs[i] 01081 assignnewchild(nobjs[i]); 01082 // derdist is >0 for previously secondary derived objects so if such an object 01083 // was copied (and detached above by ObjTreeDist) then some of its children 01084 // have become archetypes now, but their relid still reflects the secondary 01085 // derived status 01086 // 01087 // we must assign a new relid for the children of nobjs[i] 01088 if(derdist) newrelidforchildren(nobjs[i]); 01089 metaref_type trole = METAREF_NULL; 01090 if(targettype != DTID_FOLDER) { 01091 ASSERT(targettype == DTID_MODEL); 01092 CComPtr<IMgaMetaRole> r; 01093 if(rlist) COMTHROW(rlist->get_Item(i+1, &r)); 01094 CComPtr<IMgaMetaFCO> mf; 01095 COMTHROW(get_Meta(&mf)); 01096 if(!r) { // NO metarole given, inherit that of original object 01097 CComQIPtr<IMgaMetaModel> parentmeta = mf; 01098 if(!parentmeta) COMTHROW(E_MGA_META_INCOMPATIBILITY); 01099 metaref_type t; 01100 t = (nobjs[i])[ATTRID_ROLEMETA]; 01101 if(!t) COMTHROW(E_MGA_NO_ROLE); 01102 CComQIPtr<IMgaMetaRole> metar = mgaproject->FindMetaRef(t); 01103 if(!metar) COMTHROW(E_MGA_META_INCOMPATIBILITY); 01104 CComBSTR rolename; 01105 COMTHROW(metar->get_Name(&rolename)); 01106 COMTHROW(parentmeta->get_RoleByName(rolename, &r)); 01107 if(!r) COMTHROW(E_MGA_NO_ROLE); 01108 } 01109 { 01110 metaref_type kt; 01111 CComPtr<IMgaMetaFCO> mfco; 01112 COMTHROW(r->get_Kind(&mfco)); 01113 COMTHROW(mfco->get_MetaRef(&kt)); 01114 if(kt != (nobjs[i])[ATTRID_META]) 01115 COMTHROW(E_MGA_NO_ROLE); 01116 CComPtr<IMgaMetaModel> mmodel; 01117 COMTHROW(r->get_ParentModel(&mmodel)); 01118 if (!mf.IsEqualObject(mmodel)) 01119 COMTHROW(E_MGA_INVALID_ROLE); 01120 } 01121 01122 COMTHROW(r->get_MetaRef(&trole)); 01123 if(trole == METAREF_NULL) COMTHROW(E_MGA_INVALID_ROLE); 01124 } 01125 (nobjs[i])[ATTRID_ROLEMETA] = trole; 01126 i++; 01127 } MGACOLL_ITERATE_END; 01128 01129 // Reroute references 01130 for(i = 0; i< cnt; i++) { 01131 ObjTreeReconnect(nobjs[i], crealist); 01132 } 01133 01134 coreobjhash newcrealist; 01135 shiftlist(crealist, newcrealist); 01136 01137 for(i = 0; i< cnt; i++) { 01138 ObjTreeCheckRelations(mgaproject, nobjs[i], newcrealist); 01139 } 01140 01141 if(targetlevel >= 0) ReDeriveNewObjs(mgaproject, nobjs, cnt, targetlevel+1); 01142 01143 docheck(mgaproject); 01144 01145 // Assemble return array: 01146 if(objs) { 01147 CREATEEXCOLLECTION_FOR(MgaFCO, q); 01148 for(i = 0; i< cnt; i++) { 01149 CComPtr<IMgaFCO> ff; 01150 ObjForCore(nobjs[i])->getinterface(&ff); 01151 q->Add(ff); 01152 } 01153 *objs = q.Detach(); 01154 } 01155 01156 01157 01158 SelfMark(OBJEVENT_NEWCHILD); 01159 01160 } COMCATCH_IN_TRANSACTION_MAYBE(;); 01161 } 01162 01163 HRESULT FCO::CopyFCODisp(IMgaFCO *copiedobj, IMgaMetaRole *role, IMgaFCO **nobj) 01164 { 01165 COMTRY_IN_TRANSACTION_MAYBE { 01166 CComPtr<IMgaFCO> new_fco; 01167 01168 // copy in param to a folder coll 01169 CREATEEXCOLLECTION_FOR(MgaFCO, q); 01170 q->Add( CComPtr<IMgaFCO>( copiedobj)); 01171 01172 CComPtr<IMgaMetaRoles> roles; 01173 if (role) 01174 { 01175 COMTHROW(roles.CoCreateInstance(L"Mga.MgaMetaRoles", NULL, CLSCTX_INPROC)); 01176 COMTHROW(roles->Append(CComPtr<IMgaMetaRole>(role))); 01177 } 01178 01179 CComPtr<IMgaFCOs> newfcos; 01180 COMTHROW(CopyFCOs( q, roles, &newfcos)); 01181 01182 // extract ret value from returned coll 01183 long cnt = 0; 01184 if( newfcos) COMTHROW( newfcos->get_Count( &cnt)); 01185 if( cnt == 1) COMTHROW( newfcos->get_Item( 1, &new_fco)); 01186 01187 if( nobj) { 01188 *nobj = new_fco.Detach(); 01189 } 01190 } COMCATCH_IN_TRANSACTION_MAYBE(;); 01191 } 01192 01193 01197 01198 01199 // give new value to subobj, and also give the same value to all its slave subobjs 01200 void RedirectMasterTree(CoreObj &subobj, attrid_type ai, CoreObj &newval) { 01201 subobj[ai] = newval; 01202 CoreObjs slso; 01203 slso = subobj[ATTRID_MASTEROBJ+ATTRID_COLLECTION]; 01204 ITERATE_THROUGH(slso) { 01205 RedirectMasterTree(ITER, ai, newval); 01206 } 01207 } 01208 01209 // An object with tree has been moved into a type, fixup relations that used to point from inside 01210 // to the object just moved, i.e. which have just became 'internal' 01211 // self = the target object that may have too many pointers pointing at itself 01212 // selfbase = the base of the subtype/instance (self is contained by that) 01213 // level = the distance between self and selfbase 01214 01215 void ObjTreeInternalize(CMgaProject *mgaproject, CoreObj &self, CoreObj &selfbase, int tlevel) { 01216 CoreObj origbase = selfbase[ATTRID_DERIVED]; 01217 CoreObj orig = self[ATTRID_DERIVED]; 01218 static attrid_type ais[] = {ATTRID_SEGREF, ATTRID_REFERENCE, ATTRID_XREF }; 01219 // do loop for ATTRID_REFERENCE, ATTRID_XREF, and also for ATTRID_SEGREF in case of ref objs 01220 for(int i = (self.GetMetaID() == DTID_REFERENCE) ? 0 : 1; i < DIM(ais); i++) { 01221 attrid_type ai = ais[i]; 01222 CoreObjs rels = orig[ai + ATTRID_COLLECTION]; 01223 ITERATE_THROUGH(rels) { 01224 metaid_type typ = ITER.GetMetaID(); 01225 // 1. The object must be CONNROLE or SETNODE 01226 if(typ != DTID_CONNROLE && typ != DTID_SETNODE) continue; 01227 // 2. The object must not have a master pointing to the same object 01228 CoreObj obmaster = ITER[ATTRID_MASTEROBJ]; 01229 if(obmaster && COM_EQUAL(orig, CoreObj(obmaster[ai]))) continue; 01230 CoreObj srcobj = ITER.GetMgaObj(); 01231 int srclevel; 01232 // 3. The relation object must be part of the same type (i.e common derivation parent) 01233 if(!IsContained(srcobj, origbase, &srclevel)) continue; // it is an external reference 01234 01235 CoreObjs slso = ITER[ATTRID_MASTEROBJ+ATTRID_COLLECTION]; 01236 01237 ITERATE_THROUGH(slso) { 01238 CoreObj derivedsrc = ITER.GetMgaObj(); 01239 if(COM_EQUAL(selfbase, derivedsrc.FollowChain(ATTRID_FCOPARENT, srclevel))) { 01240 ASSERT(COM_EQUAL(orig, CoreObj(ITER[ai]))); 01241 RedirectMasterTree(ITER,ai,self); 01242 setcheck(mgaproject, derivedsrc, CHK_CHANGED); 01243 break; 01244 } 01245 } 01246 } 01247 } 01248 // descend to children, increase level 01249 if(self.GetMetaID() == DTID_MODEL) { 01250 CoreObjs children = self[ATTRID_FCOPARENT + ATTRID_COLLECTION]; 01251 ITERATE_THROUGH(children) { 01252 ObjTreeInternalize(mgaproject, ITER, selfbase, tlevel+1); 01253 } 01254 } 01255 } 01256 01257 01258 01259 01261 // DeriveMoveds 01263 // We have set of objects ('orignobjs') moved into a single model in a (base)type. 01264 // Reflect changes in its deriveds. 01265 // -- 'extmoved' objects must be 01266 // - newly derived, 01267 // - 'internalized' 01268 // - reconnected 01269 // -- others must be located and moved here 01270 // They all need to be checked. 01271 // 01273 // !!! RECURSIVE 01275 void DeriveMoveds(CMgaProject *mgaproject, std::vector<CoreObj> &orignobjs, std::vector<int> &extmoved, int cnt, int targetlevel) 01276 { 01277 if(cnt < 1) return; 01278 01279 CoreObj orig = orignobjs[0][ATTRID_FCOPARENT]; 01280 metaid_type n = GetMetaID( orig); 01281 01282 if (n >= DTID_MODEL && n <= DTID_SET) 01283 { 01284 CoreObjs deriveds = orig[ATTRID_DERIVED+ATTRID_COLLECTION]; 01285 ITERATE_THROUGH(deriveds) { 01286 int i; 01287 CoreObj subtypebase = ITER.FollowChain(ATTRID_FCOPARENT, targetlevel); 01288 coreobjpairhash derivcrealist; 01289 coreobjhash derivmovedlist; 01290 long instance = ITER[ATTRID_PERMISSIONS] & INSTANCE_FLAG; 01291 std::vector<CoreObj> newderiveds(cnt); 01292 for(i = 0; i< cnt; i++) { 01293 if(extmoved[i] < 0) { // the movedobject is a newcomer in the basetype, derive new obj in subtype 01294 ObjTreeDerive(mgaproject, orignobjs[i], newderiveds[i], derivcrealist, instance); 01295 newderiveds[i][ATTRID_FCOPARENT]=ITER; 01296 ObjTreeInternalize(mgaproject, newderiveds[i], subtypebase, targetlevel+1); 01297 } 01298 else { 01299 CoreObj tgt(ITER); // locate the corresponding object in subtype and move it 01300 CoreObjs ders = orignobjs[i][ATTRID_DERIVED+ATTRID_COLLECTION]; 01301 ITERATE_THROUGH(ders) { 01302 CoreObj der(ITER); 01303 if(COM_EQUAL(subtypebase, ITER.FollowChain(ATTRID_FCOPARENT, extmoved[i]))) { 01304 newderiveds[i] = ITER; 01305 CoreObjMark(ITER[ATTRID_FCOPARENT], OBJEVENT_LOSTCHILD); 01306 ITER[ATTRID_FCOPARENT] = tgt; 01307 ITER[ATTRID_ROLEMETA] = orignobjs[i][ATTRID_ROLEMETA]; 01308 ObjTreeCollect(mgaproject, ITER, derivmovedlist, CHK_MOVED); 01309 break; 01310 } 01311 } 01312 ASSERT(ITER_BROKEN); 01313 } 01314 } 01315 CoreObjMark(ITER, OBJEVENT_NEWCHILD); 01316 // Reroute references 01317 for(i = 0; i< cnt; i++) { 01318 ObjTreeReconnect(newderiveds[i], derivcrealist, subtypebase); 01319 } 01320 shiftlist(derivcrealist, derivmovedlist); 01321 for(i = 0; i< cnt; i++) { 01322 ObjTreeCheckRelations(mgaproject, newderiveds[i], derivmovedlist); 01323 } 01324 DeriveMoveds(mgaproject, newderiveds, extmoved, cnt, targetlevel); 01325 01326 for(i = 0; i< cnt; i++) { 01327 ObjTreeCheckINTORelations(mgaproject, newderiveds[i], derivmovedlist); 01328 } 01329 } 01330 } 01331 } 01332 01333 01334 HRESULT FCO::MoveFCOs(IMgaFCOs *movelist, IMgaMetaRoles *rlist,IMgaFCOs **objs) { 01335 COMTRY_IN_TRANSACTION_MAYBE { 01336 CheckWrite(); 01337 CHECK_MYINPTRSPAR(movelist); 01338 long cnt; 01339 COMTHROW(movelist->get_Count(&cnt)); 01340 01341 bool valid = ( cnt > 0); 01342 if ( cnt == 1) 01343 { 01344 valid = false; 01345 // check whether the source folder is the target as well 01346 CComPtr<IMgaFCO> mf; 01347 MGACOLL_ITERATE( IMgaFCO, movelist) { 01348 mf = MGACOLL_ITER; 01349 } MGACOLL_ITERATE_END; 01350 01351 VARIANT_BOOL is_equal; 01352 CComPtr<IMgaFCO> thisptr; 01353 getinterface( &thisptr); 01354 COMTHROW( mf->get_IsEqual( thisptr, &is_equal)); 01355 01356 if (is_equal == VARIANT_FALSE) // not equal 01357 //COMTHROW( E_MGA_INVALID_ARG); // do not copy/move onto itself 01358 valid = true; 01359 } 01360 01361 if ( valid) 01362 { 01363 if(rlist) { 01364 long rlcnt; 01365 COMTHROW(rlist->get_Count(&rlcnt)); 01366 if(rlcnt != cnt) COMTHROW(E_MGA_BAD_COLLENGTH); 01367 } 01368 metaid_type targettype = GetMetaID(self); 01369 int targetlevel = 0; 01370 CoreObj rootp; 01371 // Pre check: 01372 if(targettype == DTID_MODEL) { 01373 if(self[ATTRID_PERMISSIONS] & ~EXEMPT_FLAG) COMTHROW(E_MGA_NOT_CHANGEABLE); 01374 GetRootOfDeriv(self, rootp, &targetlevel); 01375 MGACOLL_ITERATE(IMgaFCO, movelist) { 01376 CoreObj cur = CoreObj(MGACOLL_ITER); 01377 if(IsContained(self, cur)) COMTHROW(E_MGA_OP_REFUSED); 01378 if(cur[ATTRID_RELID] >= RELIDSPACE) COMTHROW(E_MGA_OP_REFUSED); 01379 if(rootp) { 01380 CheckConflict(cur, rootp); 01381 } 01382 } MGACOLL_ITERATE_END; 01383 } 01384 01385 // move trees 01386 coreobjhash moveslist; 01387 int i = 0; 01388 01389 std::vector<CoreObj> nobjs(cnt); 01390 std::vector<int> moved_into(cnt); // >= 0 for objects moved inside the tree, -1 for newcomers 01391 MGACOLL_ITERATE(IMgaFCO, movelist) { 01392 CoreObj cur = nobjs[i] = CoreObj(MGACOLL_ITER); 01393 CoreObj movedobjrootp; 01394 int movedobjlevel; 01395 GetRootOfDeriv(cur, movedobjrootp, &movedobjlevel); 01396 int derdist = GetRealSubtypeDist(cur); 01397 if(derdist) COMTHROW(E_MGA_OP_REFUSED); 01398 // if(derdist) ObjTreeDist(cur, derdist); // move 01399 01400 CoreObj curp = cur[ATTRID_FCOPARENT]; 01401 if(!COM_EQUAL(curp, self)) { 01402 ObjForCore(curp)->CheckWrite(); // parent of cur will change, so check for WRITE permission 01403 CoreObjMark(curp, OBJEVENT_LOSTCHILD); 01404 assignnewchild(cur); 01405 CoreObjMark(cur, OBJEVENT_PARENT); 01406 } 01407 ObjTreeCollect(mgaproject, cur, moveslist, CHK_MOVED); 01408 metaref_type trole = METAREF_NULL; 01409 if(targettype != DTID_FOLDER) { 01410 ASSERT(targettype == DTID_MODEL); 01411 CComPtr<IMgaMetaRole> r; 01412 if(rlist) COMTHROW(rlist->get_Item(i+1, &r)); 01413 if(!r) { // NO metaname given, inherit that of original object 01414 CComPtr<IMgaMetaFCO> mf; 01415 COMTHROW(get_Meta(&mf)); 01416 CComQIPtr<IMgaMetaModel> parentmeta = mf; 01417 if(!parentmeta) COMTHROW(E_MGA_META_INCOMPATIBILITY); 01418 cur[ATTRID_ROLEMETA]; 01419 metaref_type t; 01420 t = (nobjs[i])[ATTRID_ROLEMETA]; 01421 if(!t) COMTHROW(E_MGA_NO_ROLE); 01422 CComQIPtr<IMgaMetaRole> metar = mgaproject->FindMetaRef(t); 01423 if(!metar) COMTHROW(E_MGA_META_INCOMPATIBILITY); 01424 CComBSTR rolename; 01425 COMTHROW(metar->get_Name(&rolename)); 01426 COMTHROW(parentmeta->get_RoleByName(rolename, &r)); 01427 if(!r) COMTHROW(E_MGA_NO_ROLE); 01428 } 01429 { 01430 metaref_type kt; 01431 CComPtr<IMgaMetaFCO> mfco; 01432 COMTHROW(r->get_Kind(&mfco)); 01433 COMTHROW(mfco->get_MetaRef(&kt)); 01434 if(kt != cur[ATTRID_META]) COMTHROW(E_MGA_META_INCOMPATIBILITY); 01435 } 01436 01437 COMTHROW(r->get_MetaRef(&trole)); 01438 if(trole == METAREF_NULL) COMTHROW(E_MGA_INVALID_ROLE); 01439 } 01440 cur[ATTRID_ROLEMETA] = trole; 01441 01442 // Determine what to do with subtypes of the objects moved 01443 CoreObjs ders = cur[ATTRID_DERIVED+ATTRID_COLLECTION]; 01444 if(!rootp || !COM_EQUAL(movedobjrootp, rootp)) { // ********* moving out of a type 01445 moved_into[i] = -1; // ******** true if moving into a type 01446 if(movedobjlevel < 1) { // not derived, or derived as self 01447 // if the object to be moved is a root of derivs, 01448 // and not moved to a model, thst model must not have any subtypes/instances 01449 if(ders.Count() && 01450 targettype == DTID_MODEL && 01451 CoreObjs(self[ATTRID_DERIVED+ATTRID_COLLECTION]).Count()) { 01452 COMTHROW(E_MGA_OP_REFUSED); 01453 } 01454 } 01455 else { 01456 ITERATE_THROUGH(ders) { // ******* erase all previous subtypes 01457 ObjForCore(ITER)->inDeleteObject(); 01458 } 01459 } 01460 } 01461 else moved_into[i] = movedobjlevel; // ***** the object remains under the same rootmodel 01462 i++; 01463 } MGACOLL_ITERATE_END; 01464 01465 for(i = 0; i< cnt; i++) { 01466 ObjTreeCheckRelations(mgaproject, nobjs[i], moveslist); 01467 } 01468 01469 if(targettype == DTID_MODEL) { 01470 DeriveMoveds(mgaproject, nobjs, moved_into, cnt, targetlevel); 01471 } 01472 01473 // Reroute references 01474 for(i = 0; i< cnt; i++) { 01475 ObjTreeCheckINTORelations(mgaproject, nobjs[i], moveslist); 01476 } 01477 01478 01479 docheck(mgaproject); 01480 01481 // Assemble return array: 01482 CREATEEXCOLLECTION_FOR(MgaFCO, q); 01483 for(i = 0; i< cnt; i++) { 01484 CComPtr<IMgaFCO> n; 01485 ObjForCore(nobjs[i])->getinterface(&n); 01486 q->Add(n); 01487 } 01488 01489 01490 if(objs) { 01491 *objs = q.Detach(); 01492 } 01493 01494 01495 SelfMark(OBJEVENT_NEWCHILD); 01496 } // if valid 01497 01498 } COMCATCH_IN_TRANSACTION_MAYBE(;); 01499 } 01500 01501 HRESULT FCO::MoveFCODisp(IMgaFCO *movedobj, IMgaMetaRole *role, IMgaFCO **nobj) 01502 { 01503 COMTRY_IN_TRANSACTION_MAYBE { 01504 CComPtr<IMgaFCO> new_fco; 01505 01506 // copy in param to a folder coll 01507 CREATEEXCOLLECTION_FOR(MgaFCO, q); 01508 q->Add( CComPtr<IMgaFCO>( movedobj)); 01509 01510 CComPtr<IMgaMetaRoles> roles; 01511 if (role) 01512 { 01513 COMTHROW(roles.CoCreateInstance(L"Mga.MgaMetaRoles", NULL, CLSCTX_INPROC)); 01514 COMTHROW(roles->Append(CComPtr<IMgaMetaRole>(role))); 01515 } 01516 01517 CComPtr<IMgaFCOs> newfcos; 01518 COMTHROW(MoveFCOs( q, roles, &newfcos)); 01519 01520 // extract ret value from returned coll 01521 long cnt = 0; 01522 if( newfcos) COMTHROW( newfcos->get_Count( &cnt)); 01523 if( cnt == 1) COMTHROW( newfcos->get_Item( 1, &new_fco)); 01524 01525 if( nobj) { 01526 *nobj = new_fco.Detach(); 01527 } 01528 } COMCATCH_IN_TRANSACTION_MAYBE(;); 01529 } 01530 01531 01535 01536 // do not use with folders 01537 bool IsAnythingDerivedFromChildren(CoreObj cbase) { 01538 if(GetMetaID(cbase) == DTID_MODEL) { 01539 ITERATE_THROUGH(CoreObjs(cbase[ATTRID_FCOPARENT + ATTRID_COLLECTION])) { 01540 if(CoreObjs(ITER[ATTRID_DERIVED + ATTRID_COLLECTION]).Count() || 01541 IsAnythingDerivedFromChildren(ITER) ) return true; 01542 } 01543 } 01544 return false; 01545 } 01546 01547 01548 01549 HRESULT FCO::DeriveFCO(IMgaFCO *base, IMgaMetaRole *role, VARIANT_BOOL binstance, IMgaFCO** newobj) { 01550 COMTRY_IN_TRANSACTION { 01551 CheckWrite(); 01552 CHECK_INBOOLPAR(binstance); 01553 CHECK_MYINPTRPAR(base); 01554 CHECK_OUTPTRPAR(newobj); 01555 metaid_type targettype = GetMetaID(self); 01556 01557 // Pre check: 01558 // ERROR if object is not rootobject 01559 objtype_enum l; 01560 CoreObj cbase(base); 01561 COMTHROW(base->get_ObjType(&l)); 01562 if(l == OBJTYPE_FOLDER) COMTHROW(E_MGA_NOT_DERIVABLE); 01563 //NCH 01564 // COMTHROW(base->GetParent(NULL, &l)); 01565 // if(l != OBJTYPE_FOLDER) COMTHROW(E_MGA_NOT_DERIVABLE); 01566 01567 // Derivable: the FCO parent of base has 0 deriveds 01568 // base already has deriveds, or all the children have 0 deriveds too. 01569 CoreObj parent = cbase[ATTRID_FCOPARENT]; 01570 int lev; 01571 CoreObj rr; 01572 GetRootOfDeriv(cbase, rr, &lev); 01573 if( lev > 0 || 01574 lev == -1 && IsAnythingDerivedFromChildren(cbase) ) { 01575 // COMTHROW(E_MGA_NOT_DERIVABLE); 01576 } 01577 01578 01579 // Check if object to be created or any of its children will become children of their own basetypes 01580 int targetlevel = 0; 01581 if(targettype != DTID_FOLDER) { 01582 if(self[ATTRID_PERMISSIONS] & ~EXEMPT_FLAG) COMTHROW(E_MGA_NOT_CHANGEABLE); 01583 CoreObj root; 01584 GetRootOfDeriv(self, root, &targetlevel); 01585 if(root) { 01586 CoreObj c1(base); 01587 if(COM_EQUAL(root, c1)) COMTHROW(E_MGA_NOT_DERIVABLE); 01588 CheckConflict(c1, root); 01589 } 01590 } 01591 01592 01593 01594 // Copy trees 01595 CoreObj newcoreobj; 01596 coreobjpairhash crealist; 01597 ObjTreeDerive(mgaproject, cbase, newcoreobj, crealist, binstance ? INSTANCE_FLAG : 0); // copy 01598 assignnewchild(newcoreobj); 01599 01600 if (targettype == DTID_FOLDER) 01601 newcoreobj[ATTRID_ROLEMETA] = METAREF_NULL; 01602 else { 01603 metaref_type t; 01604 if(!role) COMTHROW(E_MGA_INVALID_ROLE); 01605 COMTHROW(role->get_MetaRef(&t)); 01606 if(t == METAREF_NULL) COMTHROW(E_MGA_INVALID_ROLE); 01607 { 01608 metaref_type kt; 01609 CComPtr<IMgaMetaFCO> mfco; 01610 COMTHROW(role->get_Kind(&mfco)); 01611 COMTHROW(mfco->get_MetaRef(&kt)); 01612 if(kt != newcoreobj[ATTRID_META])COMTHROW(E_MGA_META_INCOMPATIBILITY); 01613 } 01614 01615 newcoreobj[ATTRID_ROLEMETA] = t; 01616 } 01617 01618 01619 // Reroute references 01620 ObjTreeReconnect(newcoreobj, crealist); 01621 // Post check: 01622 coreobjhash newcrealist; 01623 shiftlist(crealist, newcrealist); 01624 01625 ObjTreeCheckRelations(mgaproject, newcoreobj, newcrealist); 01626 01627 ObjTreeNotify(mgaproject, newcoreobj); 01628 01629 if(targetlevel >= 0) ReDeriveNewObj(mgaproject, newcoreobj, targetlevel+1); 01630 01631 SelfMark(OBJEVENT_NEWCHILD); 01632 ObjFor(base)->SelfMark(OBJEVENT_SUBT_INST); 01633 01634 docheck(mgaproject); 01635 01636 01637 // Notification 01638 ObjForCore(newcoreobj)->getinterface(newobj); 01639 } COMCATCH_IN_TRANSACTION(;) 01640 } 01641 01642 01643 01644 01645 01646 // this recursive method is different from ObjTreeCopy in that it doesn't 01647 // create a new object into 'nobj' as its first step 01648 // some inner collections are copied with the help of ObjTreeCopy 01649 // it doesn't create anything except RegNodes and Attributes which are still tied to the base 01650 void ObjDetachAndMerge( CMgaProject *mgaproject, CoreObj orig, CoreObj &nobj, coreobjpairhash& crealist, unsigned long nextrelid, bool prim = true) 01651 { 01652 bool has_last_relid_attr = false; 01653 unsigned long nb_of_children = 0; 01654 unsigned long last_relid_set = 0; 01655 01656 CComPtr<ICoreAttributes> atts; 01657 COMTHROW(orig->get_Attributes(&atts)); 01658 MGACOLL_ITERATE(ICoreAttribute, atts) { 01659 attrid_type ai; 01660 CComPtr<ICoreMetaAttribute> mattr; 01661 COMTHROW(MGACOLL_ITER->get_MetaAttribute(&mattr)); 01662 COMTHROW(mattr->get_AttrID(&ai)); 01663 if(ai < ATTRID_COLLECTION) { 01664 switch(ai) { 01665 case ATTRID_DERIVED: 01666 case ATTRID_MASTEROBJ: 01667 { 01668 CoreObj nmas = nobj[ai]; 01669 if( nobj.IsFCO() && nmas && nmas.IsFCO()) // save its master's guid into registry 01670 { 01671 CComBSTR bstr; 01672 ObjForCore( nmas)->GetGuidDisp( &bstr); 01673 if( bstr) ObjForCore( nobj)->put_RegistryValue( CComBSTR( DETACHED_FROM), bstr); 01674 } 01675 CComPtr<ICoreAttribute> regattr; 01676 HRESULT hr = orig->get_Attribute(ATTRID_REGNODE, ®attr); 01677 if (SUCCEEDED(hr)) 01678 MergeRegs(orig, nobj); 01679 else if (hr != E_INVALIDARG) 01680 COMTHROW(hr); 01681 nobj[ai] = CComVariant( (IDispatch*) 0);//an empty value; 01682 break; 01683 } 01684 case ATTRID_PERMISSIONS: 01685 { 01686 nobj[ai] = nobj[ai] & ~INSTANCE_FLAG; // remove INSTANCE_FLAG 01687 // do not modify LIBROOT_FLAG LIBRARY_FLAG READONLY_FLAG EXEMPT_FLAG as these are not inherited 01688 // (though LIBROOT_FLAG LIBRARY_FLAG READONLY_FLAG should be false here or CheckWrite would have failed) 01689 01690 break; 01691 } 01692 case ATTRID_RELID: 01693 { 01694 if( !prim) // it was a child of a primary derived, being detached 01695 { 01696 // since it was called recursively we know for sure that 01697 // this object is a secondary derived object along with its 01698 // parent. 01699 // (the level of the derivation in its case might have been 01700 // higher than the parent's level of derivation) 01701 // but since the parent is detached totally from its 01702 // base, these kinds of children (for which the method 01703 // has been invoked recursively) will become archetypes 01704 // no matter how they have been derived originally 01705 // that is why the relid has to be decreased to the 01706 // [0, RELIDSPACE) interval 01707 01708 // revert a secondary derived objects relid to a normal relid 01709 //long relid = nobj[ai]; 01710 //ASSERT( relid >= 0); 01711 //while( relid >= RELIDSPACE) relid -= RELIDSPACE; 01712 01713 if( nextrelid >= 0 && nextrelid < RELIDSPACE) 01714 { 01715 // this command would cause ambiguity if the parent has plain children 01716 //nobj[ai] = relid; // object will be no more secondary derived! 01717 // that is why we use new relids 01718 nobj[ai] = nextrelid; 01719 } 01720 else 01721 { 01722 ASSERT(0); // problem 01723 COMTHROW(E_MGA_LONG_DERIVCHAIN); 01724 } 01725 } 01726 break; 01727 } 01728 case ATTRID_LASTRELID: 01729 { 01730 // unsigned long old_val = nobj[ai]; 01731 // the old value 'nobj[ai]' contains only the number of the plain objects 01732 // this is a temp value (the correct value is inserted upon exit) 01733 //nobj[ai] = 0L; 01734 has_last_relid_attr = true; 01735 break; 01736 } 01737 default: 01738 break; // no copy/change needed in other plain cases 01739 }; // endswitch 01740 } 01741 else if( LINKREF_ATTR(ai-ATTRID_COLLECTION)){ 01742 ai -= ATTRID_COLLECTION; 01743 01744 switch( ai) { 01745 case ATTRID_ATTRPARENT: // copy the unfilled attributes 01746 { 01747 unsigned int owned_attrs(0), inherited_attrs(0), l3(0); 01748 CComBSTR nm; 01749 ObjForCore(nobj)->get_Name( &nm); 01750 01751 std::list<metaref_type> ownedAttrVec; 01752 { 01753 CoreObjs my_attrs = nobj[ai + ATTRID_COLLECTION]; // count first the # of owned attributes 01754 ITERATE_THROUGH(my_attrs) { 01755 ++owned_attrs; 01756 metaref_type attr_i = ITER[ATTRID_META]; 01757 if( std::find( ownedAttrVec.begin(), ownedAttrVec.end(), attr_i) == ownedAttrVec.end()) 01758 ownedAttrVec.push_back( attr_i); 01759 else 01760 ASSERT(0); // can an attribute belong to self twice? 01761 } 01762 } 01763 // owned_attrs is the number of owned attributes 01764 // in case the user overwrites the inherited attribute values 01765 // the instance or subtype gets an additional attribute (initially had none) 01766 // thus in case of detaching, we need to distinguish between owned values 01767 // and inherited values (owned preferred) 01768 01769 { 01770 CoreObjs base_attrs = orig[ai + ATTRID_COLLECTION]; // copy the base's values selectively 01771 ITERATE_THROUGH(base_attrs) { 01772 bool fnd = std::find( ownedAttrVec.begin(), ownedAttrVec.end(), ITER[ATTRID_META]) != ownedAttrVec.end(); 01773 if( !fnd) 01774 { 01775 ++inherited_attrs; 01776 CoreObj nchild; 01777 ObjTreeCopy(mgaproject, ITER, nchild, crealist); 01778 nchild[ai] = nobj; 01779 } 01780 } 01781 } 01782 { 01783 CoreObjs mine = nobj[ai + ATTRID_COLLECTION]; // overwrite with mine 01784 ITERATE_THROUGH( mine) { 01785 ++l3; 01786 } 01787 } 01788 01789 ASSERT( owned_attrs + inherited_attrs == l3); 01790 break; 01791 } 01792 case ATTRID_FCOPARENT: // for all secondary derived fco children-> detach 01793 { 01794 // we will calc the max_relid of those child objects which are not secondary, tertiary, ... objects 01795 // because in case of subtypes not all children originate from the current base: 01796 // some children might be plain objects, and some others may be primary subtypes of other bases 01797 long cur_max_relid = nobj[ATTRID_LASTRELID]; 01798 CoreObjs children = nobj[ai + ATTRID_COLLECTION]; 01799 ITERATE_THROUGH(children) { 01800 // this will help set the last relid correctly 01801 ++nb_of_children; 01802 CoreObj base = (ITER)[ATTRID_DERIVED]; 01803 if( base) // child is also derived 01804 { 01805 VARIANT_BOOL primDer = VARIANT_FALSE; 01806 if( nobj.IsFCO()) ObjForCore( ITER)->get_IsPrimaryDerived( &primDer); 01807 if( primDer != VARIANT_TRUE) // it is a child derived along with 'orig' 01808 { 01809 // detach it as well from its base 01810 ObjDetachAndMerge(mgaproject, base, ITER, crealist, ++cur_max_relid, false); 01811 // increase the cur_max_relid for the next child 01812 // FIXME: should this be max? 01813 nobj[ATTRID_LASTRELID] = last_relid_set = cur_max_relid; 01814 } 01815 else 01816 { // it might be a primary subtype/instance placed into this subtype 01817 // leave this object untouched 01818 } 01819 } 01820 else 01821 { // additional child->no action needed 01822 } 01823 } 01824 break; 01825 } 01826 default: // for all others -> detach 01827 { 01828 CoreObjs collmembers = nobj[ai + ATTRID_COLLECTION]; 01829 ITERATE_THROUGH(collmembers) { 01830 // remove the ATTRID_DERIVED attrs if any? 01831 ObjDetachAndMerge(mgaproject, ITER, ITER, crealist, 0, false); 01832 } 01833 } 01834 }; // endswitch 01835 } 01836 01837 } MGACOLL_ITERATE_END; 01838 01839 if( has_last_relid_attr) // if this CoreObj has RELID_LAST attribute 01840 { 01841 unsigned long r = nobj[ATTRID_LASTRELID]; 01842 ASSERT( last_relid_set >= nb_of_children); 01843 if( r < last_relid_set) 01844 nobj[ATTRID_LASTRELID] = last_relid_set; // fill it with the correct value 01845 } 01846 } 01847 01848 void ObjAttach(CMgaProject *mgaproject, const CoreObj &origobj, CoreObj &newobj, coreobjpairhash &crealist, long instance, bool prim) 01849 { 01850 // this variable will make sure that if an instance is met inside a base (origobj) which is subtyped (!) 01851 // then assure that though a subtype may have additional children, but the instance brach might not 01852 // contain additional children 01853 bool instance_met = false; 01854 CComPtr<ICoreAttributes> atts; 01855 COMTHROW(origobj->get_Attributes(&atts)); 01856 MGACOLL_ITERATE(ICoreAttribute, atts) { 01857 attrid_type ai; 01858 CComPtr<ICoreMetaAttribute> mattr; 01859 COMTHROW(MGACOLL_ITER->get_MetaAttribute(&mattr)); 01860 COMTHROW(mattr->get_AttrID(&ai)); 01861 if(ai < ATTRID_COLLECTION) { 01862 switch(ai) { 01863 case ATTRID_DERIVED: 01864 case ATTRID_MASTEROBJ: 01865 newobj[ai] = origobj; 01866 break; 01867 case ATTRID_PERMISSIONS: 01868 // if it was instance or orig is instance or it is supposed to be an instance: 01869 newobj[ai] = (newobj[ai] | origobj[ai] | long(instance)) & INSTANCE_FLAG; 01870 instance_met = newobj[ai] & INSTANCE_FLAG; 01871 break; 01872 case ATTRID_RELID: 01873 { 01874 if( !prim) 01875 { 01876 // if newobj[ai] + RELIDSPACE > LONG_MAX 01877 if (newobj[ai] > LONG_MAX - RELIDSPACE) 01878 COMTHROW(E_MGA_LONG_DERIVCHAIN); 01879 newobj[ai] = newobj[ai]+RELIDSPACE; //shift its own relid 01880 ASSERT(newobj[ai] >= 0); 01881 } 01882 } 01883 break; 01884 case ATTRID_LASTRELID: 01885 newobj[ai] = 0L; 01886 break; 01887 //default: 01888 // newobj[ai] = static_cast<CComVariant>(origobj[ai]); 01889 } 01890 } 01891 else { 01892 ai -= ATTRID_COLLECTION; 01893 if(LINKREF_ATTR(ai)) { 01894 if( ai == ATTRID_ATTRPARENT) { } // no need to copy attr values since the newobj already had its own 01895 else if( ai == ATTRID_CONSTROWNER) { } 01896 else if( ai == ATTRID_CONNROLE) { } 01897 else if( ai == ATTRID_SETMEMBER) { } 01898 else if(ai == ATTRID_FCOPARENT) { 01899 01900 std::map< int, int> match; 01901 std::map< CoreObj, CoreObj> matchO; 01902 //std::vector<metaref_type> kidsVec, kidsVec2; 01903 //std::vector<std::string> nameVec, nameVec2; 01904 01905 unsigned int kids_o = 0; 01906 {CoreObjs children = origobj[ai + ATTRID_COLLECTION]; 01907 ITERATE_THROUGH(children) { 01908 ++kids_o; 01909 metaref_type role_i = ITER[ATTRID_META]; 01910 //kidsVec.push_back( role_i); 01911 01912 CComBSTR nm_i; 01913 ObjForCore(ITER)->get_Name( &nm_i); 01914 //std::string nm_ii; CopyTo( nm_i, nm_ii); 01915 //nameVec.push_back( nm_ii); 01916 01917 CComBSTR gd_i; 01918 ObjForCore(ITER)->GetGuidDisp( &gd_i); 01919 01920 CoreObj outer_ITER = ITER; 01921 unsigned int kids_n = 0; 01922 bool fnd = false; 01923 {CoreObjs children2 = newobj[ai + ATTRID_COLLECTION]; 01924 ITERATE_THROUGH(children2) { 01925 ++kids_n; 01926 metaref_type role_j = ITER[ATTRID_META]; 01927 //kidsVec2.push_back( role_j); 01928 01929 CComBSTR nm_j; 01930 ObjForCore(ITER)->get_Name( &nm_j); 01931 //std::string nm_jj; CopyTo( nm_j, nm_jj); 01932 //nameVec2.push_back( nm_jj); 01933 01934 CComBSTR gd_j; 01935 ObjForCore(ITER)->get_RegistryValue( CComBSTR( DETACHED_FROM), &gd_j); 01936 01937 // name based equality is considered only if 01938 // no stored master guid (Detached from) was found 01939 if( ( gd_j == gd_i && gd_j.Length() > 0 || nm_j == nm_i && gd_j.Length() == 0) 01940 && role_i == role_j 01941 && match.find(kids_n) == match.end()) // not found <==> not assigned 01942 { 01943 // kids_o <---> kids_n 01944 //ObjAttach( mgaproject, kids_o, kids_n) 01945 ObjAttach( mgaproject, outer_ITER, ITER, crealist, instance, false); 01946 match[kids_n] = kids_o; 01947 matchO[ITER] = outer_ITER; 01948 fnd = true; 01949 break; 01950 } 01951 }} 01952 01953 if( !fnd) 01954 { 01955 CoreObj i; 01956 ObjTreeCopy( mgaproject, ITER, i, crealist);//, instance, false); 01957 ObjAttach( mgaproject, ITER, i, crealist, instance, false); 01958 i[ATTRID_FCOPARENT] = newobj; 01959 } 01960 }} 01961 01962 if( instance || instance_met) 01963 { 01964 unsigned int kids_o( 0), kids_n( 0); 01965 {CoreObjs children = origobj[ai + ATTRID_COLLECTION]; 01966 ITERATE_THROUGH(children) { 01967 ++kids_o; 01968 }} 01969 {CoreObjs children = newobj[ai + ATTRID_COLLECTION]; 01970 ITERATE_THROUGH(children) { 01971 ++kids_n; 01972 }} 01973 01974 if( kids_o != kids_n) // at this point the instance should have the same number of elements like its base 01975 COMTHROW(E_FAIL); 01976 } 01977 } 01978 else { 01979 CoreObjs collmembers = origobj[ai + ATTRID_COLLECTION]; 01980 ITERATE_THROUGH(collmembers) { 01981 CoreObj nchild; 01982 ObjAttach(mgaproject, ITER, nchild, crealist, instance, false); 01983 nchild[ai] = newobj; 01984 } 01985 } 01986 } 01987 } 01988 01989 } MGACOLL_ITERATE_END; 01990 } 01991 01992 void getMeAGuid( long *p_l1, long *p_l2, long *p_l3, long *p_l4) 01993 { 01994 GUID t_guid = GUID_NULL; 01995 COMTHROW(CoCreateGuid(&t_guid)); 01996 01997 ASSERT(t_guid != GUID_NULL); 01998 //char buff[39]; 01999 //sprintf( buff, "{%08lX-%04X-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X}", 02000 // t_guid.Data1, t_guid.Data2, t_guid.Data3, 02001 // t_guid.Data4[0], t_guid.Data4[1], t_guid.Data4[2], t_guid.Data4[3], 02002 // t_guid.Data4[4], t_guid.Data4[5], t_guid.Data4[6], t_guid.Data4[7]); 02003 02004 // thus replace the old guid with a new one 02005 *p_l1 = t_guid.Data1; // Data1: 32 b, Data2, Data 3: 16 b, Data4: 64 bit 02006 *p_l2 = (t_guid.Data2 << 16) + t_guid.Data3; 02007 *p_l3 = (((((t_guid.Data4[0] << 8) + t_guid.Data4[1]) << 8) + t_guid.Data4[2]) << 8) + t_guid.Data4[3]; 02008 *p_l4 = (((((t_guid.Data4[4] << 8) + t_guid.Data4[5]) << 8) + t_guid.Data4[6]) << 8) + t_guid.Data4[7]; 02009 } 02010 02011 void assignGuid( CMgaProject *mgaproject, CoreObj& ss) 02012 { 02013 ASSERT( ss.IsFCO() || ss.IsContainer()); 02014 if( !ss.IsFCO() && !ss.IsContainer()) return; 02015 //if( mgaproject->mgaversion <= 1) return; 02016 02017 long l1(0), l2(0), l3(0), l4(0); 02018 getMeAGuid( &l1, &l2, &l3, &l4); 02019 02020 ss[ATTRID_GUID1] = l1; 02021 ss[ATTRID_GUID2] = l2; 02022 ss[ATTRID_GUID3] = l3; 02023 ss[ATTRID_GUID4] = l4; 02024 } 02025 02026