GME
13
|
00001 // MgaFolder.cpp : Implementation of FCO Folder and container operations 00002 #include "stdafx.h" 00003 #include <map> 00004 #include <stdio.h> 00005 #include "MgaFCO.h" 00006 #include "MgaLibOps.h" // by ZolMol 00007 #include "MgaComplexOps.h" // by ZolMol 00008 00010 // CMgaFolder 00011 00012 00013 HRESULT FCO::get_MetaFolder(IMgaMetaFolder **pVal) { 00014 COMTRY { 00015 CheckRead(); 00016 CHECK_OUTPTRPAR(pVal); 00017 *pVal = CComQIPtr<IMgaMetaFolder>(mgaproject->FindMetaRef(self[ATTRID_META])).Detach(); 00018 } COMCATCH(;) 00019 } 00020 00021 00022 00023 HRESULT FCO::CreateFolder(IMgaMetaFolder *meta, IMgaFolder **nf) 00024 { 00025 COMTRY_IN_TRANSACTION_MAYBE { 00026 CheckWrite(); 00027 if(self[ATTRID_PERMISSIONS] & LIBROOT_FLAG) COMTHROW(E_MGA_NOT_CHANGEABLE); 00028 CHECK_INPTRPAR(meta); 00029 CHECK_OUTPTRPAR(nf); 00030 CheckWrite(); 00031 CoreObj subfolder; 00032 COMTHROW(mgaproject->dataproject->CreateObject(DTID_FOLDER,&subfolder.ComPtr())); 00033 assignGuid( mgaproject, subfolder); 00034 assignnewchild(subfolder); 00035 metaref_type mr; 00036 COMTHROW(meta->get_MetaRef(&mr)); 00037 subfolder[ATTRID_META]=mr; 00038 auto nff = ObjForCore(subfolder); 00039 nff->initialname(); 00040 COMTHROW(nff->Check()); 00041 nff->SelfMark(OBJEVENT_CREATED); 00042 SelfMark(OBJEVENT_NEWCHILD); 00043 nff->getinterface(nf); 00044 } 00045 COMCATCH_IN_TRANSACTION_MAYBE(;); 00046 } 00047 00048 00049 // 00050 // by ZolMol 00051 // called from CMgaFolder::CopyFolders 00052 // 00053 HRESULT FCO::CopyFolders(IMgaFolders *copylist, IMgaFolders **objs) 00054 { 00055 COMTRY_IN_TRANSACTION { 00056 CheckWrite(); 00057 CHECK_MYINPTRSPARFOLDER(copylist); 00058 long cnt; 00059 COMTHROW(copylist->get_Count(&cnt)); 00060 00061 metaid_type targettype = GetMetaID(self); 00062 00063 // Pre check: 00064 if(targettype == DTID_FOLDER) 00065 { 00066 if(self[ATTRID_PERMISSIONS] & ~EXEMPT_FLAG) 00067 COMTHROW(E_MGA_NOT_CHANGEABLE); 00068 } 00069 else 00070 ASSERT(0); // where else can a a folder be copied? 00071 00072 // Copy trees 00073 coreobjpairhash crealist; 00074 int i = 0; 00075 00076 std::vector<CoreObj> nobjs(cnt); 00077 MGACOLL_ITERATE(IMgaFolder, copylist) { 00078 CoreObj oldobj = CoreObj(MGACOLL_ITER); 00079 ObjForCore(oldobj)->SelfMark(OBJEVENT_COPIED); 00080 ObjTreeCopyFoldersToo(mgaproject, oldobj, nobjs[i], crealist); // copy 00081 assignnewchild(nobjs[i]); 00082 00083 CComPtr<IMgaMetaFolder> meta_of_copied_f; 00084 COMTHROW( MGACOLL_ITER->get_MetaFolder( &meta_of_copied_f)); 00085 00086 if( !meta_of_copied_f) 00087 COMTHROW(E_MGA_META_INCOMPATIBILITY); 00088 00089 metaref_type copied_kind = METAREF_NULL; 00090 COMTHROW( meta_of_copied_f->get_MetaRef( &copied_kind)); 00091 00092 if( copied_kind == METAREF_NULL) 00093 COMTHROW(E_MGA_INVALID_ROLE); //E_MGA_INVALID_KIND ? instead 00094 00095 (nobjs[i])[ATTRID_META] = copied_kind; 00096 00097 i++; 00098 00099 } MGACOLL_ITERATE_END; 00100 00101 // Reroute references 00102 for(i = 0; i< cnt; i++) { 00103 ObjTreeReconnectFoldersToo(nobjs[i], crealist); 00104 } 00105 00106 coreobjhash newcrealist; 00107 shiftlist(crealist, newcrealist); 00108 00109 for(i = 0; i< cnt; i++) { 00110 ObjTreeCheckRelationsFoldersToo(mgaproject, nobjs[i], newcrealist); 00111 } 00112 00113 docheck(mgaproject); 00114 00115 // Assemble return array: 00116 if(objs) { 00117 CREATEEXCOLLECTION_FOR(MgaFolder, q); 00118 for(i = 0; i< cnt; i++) { 00119 CComPtr<IMgaFolder> ff; 00120 ObjForCore(nobjs[i])->getinterface(&ff); 00121 q->Add(ff); 00122 } 00123 *objs = q.Detach(); 00124 } 00125 00126 SelfMark(OBJEVENT_NEWCHILD); 00127 00128 } COMCATCH_IN_TRANSACTION(;); 00129 } 00130 00131 HRESULT FCO::MoveFolders( IMgaFolders *movelist, IMgaFolders **objs) 00132 { 00133 COMTRY_IN_TRANSACTION { 00134 CheckWrite(); 00135 CHECK_MYINPTRSPARFOLDER(movelist); 00136 long cnt; 00137 COMTHROW(movelist->get_Count(&cnt)); 00138 00139 bool valid = (cnt > 0); 00140 if ( cnt == 1) // check whether the only selected folder is drag-and-dropped onto itself (*this == movelist[0]) 00141 { 00142 valid = false; 00143 CComPtr<IMgaFolder> mf; 00144 MGACOLL_ITERATE( IMgaFolder, movelist) { 00145 mf = MGACOLL_ITER; 00146 } MGACOLL_ITERATE_END; 00147 00148 VARIANT_BOOL is_equal; 00149 IMgaFolder * thisptr; 00150 getinterface( &thisptr); 00151 COMTHROW( mf->get_IsEqual( thisptr, &is_equal)); 00152 00153 if (is_equal == VARIANT_FALSE) // not equal 00154 valid = true; 00155 } 00156 00157 if ( valid) 00158 { 00159 00160 metaid_type targettype = GetMetaID(self); 00161 int targetlevel = 0; 00162 CoreObj rootp; 00163 00164 // Pre check: 00165 if(targettype == DTID_FOLDER) 00166 { 00167 if(self[ATTRID_PERMISSIONS] & ~EXEMPT_FLAG) 00168 COMTHROW(E_MGA_NOT_CHANGEABLE); 00169 } 00170 else 00171 ASSERT(0); // where else can a a folder be moved? 00172 00173 00174 // move trees 00175 coreobjhash moveslist; // will contain the movements which are needed to proceed 00176 int i = 0; 00177 00178 std::vector<CoreObj> nobjs(cnt); 00179 std::vector<int> moved_into(cnt); // >= 0 for objects moved inside the tree, -1 for newcomers 00180 MGACOLL_ITERATE(IMgaFolder, movelist) { 00181 00182 CoreObj cur = nobjs[i] = CoreObj(MGACOLL_ITER); 00183 00184 CoreObj curr_parent = cur[ATTRID_FCOPARENT]; 00185 if( IsFolderContained( self, cur)) COMTHROW(E_MGA_INVALID_ARG);// do not allow moving a parent (grandparent...) into its child 00186 00187 if( !COM_EQUAL( curr_parent, self)) { 00188 CoreObjMark( curr_parent, OBJEVENT_LOSTCHILD); // the old parent will lose its child 00189 assignnewchild( cur); 00190 CoreObjMark( cur, OBJEVENT_PARENT); // obj has been moved 00191 } 00192 00193 ObjTreeCollectFoldersToo( mgaproject, cur, moveslist, CHK_MOVED); 00194 00195 CComPtr<IMgaMetaFolder> meta_of_moved_f; 00196 COMTHROW( MGACOLL_ITER->get_MetaFolder( &meta_of_moved_f)); 00197 00198 if( !meta_of_moved_f) 00199 COMTHROW(E_MGA_META_INCOMPATIBILITY); 00200 00201 metaref_type moved_kind = METAREF_NULL; 00202 COMTHROW( meta_of_moved_f->get_MetaRef( &moved_kind)); 00203 00204 if(moved_kind == METAREF_NULL) 00205 COMTHROW(E_MGA_INVALID_ROLE); //E_MGA_INVALID_KIND ? instead 00206 00207 cur[ATTRID_META] = moved_kind; 00208 00209 i++; 00210 } MGACOLL_ITERATE_END; 00211 00212 for(i = 0; i< cnt; i++) { 00213 ObjTreeCheckRelationsFoldersToo(mgaproject, nobjs[i], moveslist); 00214 } 00215 00216 DeriveMoveds(mgaproject, nobjs, moved_into, cnt, targetlevel); 00217 00218 // Reroute references 00219 for(i = 0; i< cnt; i++) { 00220 ObjTreeCheckINTORelationsFoldersToo(mgaproject, nobjs[i], moveslist); 00221 } 00222 00223 docheck(mgaproject); // this method check whether the operations are valid 00224 00225 // Assemble return array: 00226 CREATEEXCOLLECTION_FOR(MgaFolder, q); 00227 for(i = 0; i< cnt; i++) { 00228 CComPtr<IMgaFolder> n; 00229 ObjForCore(nobjs[i])->getinterface(&n); 00230 q->Add(n); 00231 } 00232 00233 if(objs) { 00234 *objs = q.Detach(); 00235 } 00236 00237 //SelfMark(OBJEVENT_NEWCHILD); - omitted, done by separate method: RefreshParent 00238 00239 } // if valid 00240 00241 } COMCATCH_IN_TRANSACTION(;); 00242 } 00243 00244 HRESULT FCO::CopyFolderDisp(IMgaFolder *copyfold, IMgaFolder **nobj) 00245 { 00246 COMTRY_IN_TRANSACTION { 00247 CComPtr<IMgaFolder> new_fol; 00248 00249 // copy in param to a folder coll 00250 CREATEEXCOLLECTION_FOR(MgaFolder, q); 00251 q->Add( CComPtr<IMgaFolder>( copyfold)); 00252 00253 CComPtr<IMgaFolders> newfols; 00254 COMTHROW(CopyFolders( q, &newfols)); 00255 00256 // extract ret value from returned coll 00257 long cnt = 0; 00258 if( newfols) COMTHROW( newfols->get_Count( &cnt)); 00259 if( cnt == 1) COMTHROW( newfols->get_Item( 1, &new_fol)); 00260 00261 if( nobj) { 00262 *nobj = new_fol.Detach(); 00263 } 00264 } COMCATCH_IN_TRANSACTION(;); 00265 } 00266 00267 HRESULT FCO::MoveFolderDisp(IMgaFolder *movefold, IMgaFolder **nobj) 00268 { 00269 COMTRY_IN_TRANSACTION { 00270 CComPtr<IMgaFolder> new_fol; 00271 00272 // copy in param to a folder coll 00273 CREATEEXCOLLECTION_FOR(MgaFolder, q); 00274 q->Add( CComPtr<IMgaFolder>( movefold)); 00275 00276 CComPtr<IMgaFolders> newfols; 00277 COMTHROW(MoveFolders( q, &newfols)); 00278 00279 // extract ret value from returned coll 00280 long cnt = 0; 00281 if( newfols) COMTHROW( newfols->get_Count( &cnt)); 00282 if( cnt == 1) COMTHROW( newfols->get_Item( 1, &new_fol)); 00283 00284 if( nobj) { 00285 *nobj = new_fol.Detach(); 00286 } 00287 } COMCATCH_IN_TRANSACTION(;); 00288 } 00289 00290 HRESULT FCO::RefreshParent( IMgaFolder * folder) 00291 { 00292 COMTRY_IN_TRANSACTION { 00293 SelfMark(OBJEVENT_NEWCHILD); 00294 } COMCATCH_IN_TRANSACTION(;); 00295 } 00296 00297 HRESULT FCO::get_ChildFolders(IMgaFolders **pVal) { 00298 COMTRY { 00299 CheckRead(); 00300 00301 CoreObjs children = self[ATTRID_FPARENT+ATTRID_COLLECTION]; 00302 00303 CREATECOLLECTION_FOR(IMgaFolder,q) 00304 00305 ITERATE_THROUGH(children) { 00306 if(ITER.IsFCO()) continue; 00307 CComPtr<IMgaFolder> ff; 00308 ObjForCore(ITER)->getinterface(&ff); 00309 q->Add(ff); 00310 } 00311 *pVal = q.Detach(); 00312 } 00313 COMCATCH(;); 00314 } 00315 00316 00317 HRESULT FCO::CreateRootObject(IMgaMetaFCO *meta, IMgaFCO **nobj) { 00318 00319 COMTRY_IN_TRANSACTION { 00320 CHECK_INPTRPAR(meta); 00321 CHECK_OUTPTRPAR(nobj); 00322 CheckWrite(); 00323 if(self[ATTRID_PERMISSIONS] & LIBROOT_FLAG) COMTHROW(E_MGA_NOT_CHANGEABLE); 00324 CoreObj newobj; 00325 COMTHROW(ContainerCreateFCO(meta, newobj)); 00326 auto nfco = ObjForCore(newobj); 00327 nfco->initialname(); 00328 COMTHROW(nfco->Check()); 00329 nfco->SelfMark(OBJEVENT_CREATED); 00330 SelfMark(OBJEVENT_NEWCHILD); 00331 nfco->getinterface(nobj); 00332 } 00333 COMCATCH_IN_TRANSACTION(;) 00334 } 00335 00336 00337 00338 00339 00343 00344 00345 00346 // relid: 00347 // on create: next 00348 // on copy: next 00349 // on move: next (only if moving to another parent) 00350 // on derive: base object + RELIDSPACE 00351 // detach: relid change!!!!! 00352 // attach: 00353 00354 #define RELIDSPACEMASK (RELIDSPACE-1) 00355 00356 void FCO::assignnewchild(CoreObj &ss) { 00357 ASSERT(RELIDSPACE_OVERFLOWED%RELIDSPACE == 0); 00358 ss[ATTRID_PARENT] = self; 00359 if(mgaproject->mgaversion < 1) return; 00360 ss[ATTRID_RELID] = 0; 00361 if(mgaproject->preferences & MGAPREF_MANUAL_RELIDS) return; 00362 long candidate = self[ATTRID_LASTRELID] + 1; 00363 if((unsigned long)candidate < RELIDSPACE) { // simple case: no overflow yet. 00364 ss[ATTRID_RELID] = candidate; 00365 self[ATTRID_LASTRELID] = candidate; 00366 return; 00367 } 00368 if(candidate == RELIDSPACE) { // this is the first time an overflow happens 00369 // TODO: Notify user that an overflow happened 00370 } 00371 candidate &= RELIDSPACEMASK; 00372 int incr = 1; 00373 CoreObjs children = ss[ATTRID_PARENT+ATTRID_COLLECTION]; 00374 int tries = 0; 00375 while(true) { 00376 for(int i = 0; i < 9; i++) { 00377 ITERATE_THROUGH(children) { 00378 if(ITER[ATTRID_RELID] == candidate) break; 00379 } 00380 if(!ITER_BROKEN) { 00381 ss[ATTRID_RELID] = candidate; 00382 self[ATTRID_LASTRELID] = long(candidate | RELIDSPACE_OVERFLOWED); 00383 } 00384 if(tries++ > RELIDSPACE) COMTHROW(E_MGA_GEN_OUT_OF_SPACE); // infinite search 00385 candidate += incr; 00386 candidate &= RELIDSPACEMASK; 00387 } 00388 incr *= 9; 00389 } 00390 } 00391 void traversechildren( CoreObj& ss) 00392 { 00393 ASSERT( DTID_MODEL == GetMetaID(ss)); 00394 CoreObjs children = ss[ATTRID_PARENT+ATTRID_COLLECTION]; 00395 long candidate = ss[ATTRID_LASTRELID] + 1; 00396 ITERATE_THROUGH(children) { 00397 if((unsigned long)candidate < RELIDSPACE) { // simple case: no overflow yet. 00398 00399 CoreObj base = ITER[ATTRID_DERIVED]; 00400 if( !base) 00401 { 00402 ITER[ATTRID_RELID] = candidate++; 00403 if( DTID_MODEL == GetMetaID(ITER)) 00404 traversechildren( ITER ); 00405 } // else : still derived, no need for relid assignment 00406 } 00407 else ASSERT(0); 00408 } 00409 ss[ATTRID_LASTRELID] = candidate-1; 00410 } 00411 00412 void FCO::newrelidforchildren(CoreObj &prnt) { 00413 ASSERT(RELIDSPACE_OVERFLOWED%RELIDSPACE == 0); 00414 // not tested for the cases when mgaversion<1, or manual relids: 00415 if(mgaproject->mgaversion < 1) return; 00416 if(mgaproject->preferences & MGAPREF_MANUAL_RELIDS) return; 00417 00418 // for all children of prnt if an object is not derived any more (it was a secondary derived) 00419 // then assign a new relid in [1, RELIDSPACE) interval, because secondary derived objects 00420 // had special relids (greater then RELIDSPACE) which now need to be modified back to regular relids 00421 long candidate = self[ATTRID_LASTRELID] + 1; 00422 if((unsigned long)candidate < RELIDSPACE) { // simple case: no overflow yet. 00423 prnt[ATTRID_RELID] = candidate; 00424 self[ATTRID_LASTRELID] = candidate; 00425 if( DTID_MODEL == GetMetaID(prnt)) 00426 traversechildren( prnt); 00427 } 00428 } 00429 00430 HRESULT FCO::ContainerCreateFCO(IMgaMetaFCO *meta, CoreObj &fco) { 00431 COMTRY_IN_TRANSACTION_MAYBE { 00432 metaref_type rr; 00433 objtype_enum tt; 00434 COMTHROW(meta->get_MetaRef(&rr)); 00435 COMTHROW(meta->get_ObjType(&tt)); 00436 00437 COMTHROW(mgaproject->dataproject->CreateObject(tt+DTID_BASE,&fco.ComPtr())); 00438 assignGuid( mgaproject, fco); 00439 assignnewchild(fco); 00440 fco[ATTRID_META]=rr; 00441 } 00442 COMCATCH_IN_TRANSACTION_MAYBE(;); 00443 00444 } 00445 00446 HRESULT FCO::get_ChildRelIDCounter(long *pVal) { 00447 COMTRY { 00448 CheckRead(); 00449 ASSERT(self.IsContainer()); 00450 CHECK_OUTPAR(pVal); 00451 *pVal = self[ATTRID_LASTRELID]; 00452 } COMCATCH(;); 00453 } 00454 00455 HRESULT FCO::put_ChildRelIDCounter(long pVal) { 00456 COMTRY_IN_TRANSACTION { 00457 CheckWrite(); 00458 ASSERT(self.IsContainer()); 00459 self[ATTRID_LASTRELID] = pVal; 00460 } COMCATCH_IN_TRANSACTION(;); 00461 } 00462 00463 HRESULT FCO::get_ChildFCOs(IMgaFCOs ** pVal) { 00464 COMTRY { 00465 CheckRead(); 00466 00467 CoreObjs children = self[ATTRID_FCOPARENT+ATTRID_COLLECTION]; 00468 00469 CREATEEXCOLLECTION_FOR(MgaFCO,q); 00470 00471 ITERATE_THROUGH(children) { 00472 if(!ITER.IsFCO()) continue; 00473 CComPtr<IMgaFCO> ff; 00474 ObjForCore(ITER)->getinterface(&ff); 00475 q->Add(ff); 00476 } 00477 *pVal = q.Detach(); 00478 } 00479 COMCATCH(;); 00480 } 00481 00482 HRESULT FCO::get_ChildObjects(IMgaObjects ** pVal) { 00483 COMTRY { 00484 CHECK_OUTPTRPAR(pVal); 00485 CheckRead(); 00486 00487 CoreObjs children = self[ATTRID_FCOPARENT+ATTRID_COLLECTION]; 00488 00489 CREATEEXCOLLECTION_FOR(MgaObject,q); 00490 00491 ITERATE_THROUGH(children) { 00492 CComPtr<IMgaObject> ff; 00493 ObjForCore(ITER)->getinterface(&ff); 00494 q->Add(ff); 00495 } 00496 *pVal = q.Detach(); 00497 } 00498 COMCATCH(;); 00499 } 00500 00501 HRESULT FCO::get_ChildObjectByRelID(long relid, IMgaObject ** pVal) { 00502 COMTRY { 00503 CHECK_OUTPTRPAR(pVal); 00504 CheckRead(); 00505 00506 CoreObjs children = self[ATTRID_FCOPARENT+ATTRID_COLLECTION]; 00507 ITERATE_THROUGH(children) { 00508 if(ITER[ATTRID_RELID] == relid) { 00509 ObjForCore(ITER)->getinterface(pVal); 00510 break; 00511 } 00512 } 00513 } 00514 COMCATCH(;); 00515 } 00516 00517 00518 // returns true if the short file names are equal 00519 // i.e. for the following strings 'true' is given back 00520 // MGA=C:\Program Files\gme\paradigms\SF\tmp2.mga 00521 // MGA=F:\Files\gm2e\paradigms2\mySF\tMp2.mGa 00522 // MGA=F:tMp2.MGA 00523 // MGA=tMp2.MGA 00524 bool libraryNameEqual( CComBSTR n1, CComBSTR n2) 00525 { 00526 COMTHROW(n1.ToUpper()); 00527 COMTHROW(n2.ToUpper()); 00528 std::string s1, s2; 00529 CopyTo( n1, s1); CopyTo( n2, s2); 00530 00531 // return false if both are not libraries 00532 if ( s1.find("MGA=") == std::string::npos || s2.find("MGA=") == std::string::npos) return false; 00533 00534 int i1 = s1.length() - 1; while ( i1 >= 0 && s1[i1] != '\\' && s1[i1] != ':' && s1[i1] != '=') --i1; //int i1 = s1.rfind( '\\' || '='); 00535 int i2 = s2.length() - 1; while ( i2 >= 0 && s2[i2] != '\\' && s2[i2] != ':' && s2[i2] != '=') --i2; //int i2 = s2.rfind( '\\' || '='); 00536 00537 if ( i1 >= 0) s1 = s1.substr( i1 + 1, s1.length() - i1 - 1); 00538 if ( i2 >= 0) s2 = s2.substr( i2 + 1, s2.length() - i2 - 1); 00539 00540 return s1.compare( s2) == 0; 00541 } 00542 00543 void str_scan_name( OLECHAR ** p_ptr, int len_of, CComBSTR& p_name, CComBSTR& p_kind, CComBSTR& p_relpos) 00544 { 00545 wchar_t str_to_find1[] = L"|kind="; 00546 wchar_t str_to_find2[] = L"|relpos="; 00547 00548 OLECHAR * pi = *p_ptr; 00549 std::wstring id; 00550 00551 while( len_of > 0 && *pi != L'/') // goes to the next separator 00552 { 00553 id += *pi; 00554 ++pi;--len_of; 00555 } 00556 00557 std::string::size_type f = id.find( str_to_find1); 00558 if( std::string::npos == f) // kind not found 00559 { 00560 p_name = id.c_str(); // only name is present 00561 id = L""; 00562 } 00563 else 00564 { 00565 p_name = id.substr( 0, f).c_str(); // f might be 0, so p_name might be "" 00566 id = id.substr( f + wcslen( str_to_find1)); 00567 00568 std::string::size_type k = id.find( str_to_find2); 00569 if( std::string::npos == k) // relid not found 00570 { 00571 p_kind = id.c_str(); // the remaining part is the kind 00572 id = L""; 00573 } 00574 else 00575 { 00576 p_kind = id.substr( 0, k).c_str(); 00577 id = id.substr( k + wcslen( str_to_find2)); 00578 00579 // the remaining part is the relpos 00580 p_relpos = id.c_str(); 00581 } 00582 } 00583 00584 *p_ptr = pi; // the processing will go on from this OLECHAR* value 00585 } 00586 00587 00588 // Delimiter in the path is the slash character: '/' 00589 // searches based on name and kind: "/@MyFolder|kind=OneFolder/@MySubFolder|kind=AnotherFolder" (the project or root folder name must not be included) 00590 // or based on plain name: "/MyFolder/MySubFolder" 00591 // or based on relid: "/#1/#3" 00592 // these may be mixed like: "/@MyFolder|kind=OneFolder|relpos=1/#2" which means that look for MyFolder, then select its child with Relid = 2 00593 // incoming path may contain 'misleading' relpos tokens as well: /@MyFolder|kind=OneFolder|relpos=1/@MySubFolder|kind=AnotherFolder|relpos=2" these are disregarded 00594 // If several objects are found, NULL is returned 00595 // 00596 // FCO::get_ObjectByPath ignores the leading '/' 00597 HRESULT FCO::get_ObjectByPath(BSTR path, IMgaObject ** pVal) { 00598 COMTRY { 00599 CHECK_OUTPTRPAR(pVal); 00600 CheckRead(); 00601 00602 OLECHAR *p = path; 00603 int lenOf = SysStringLen( path); 00604 00605 if(*p == '/') p++; 00606 CComPtr<IMgaObject> pp; 00607 if(*p == '@') { // implemented by ZolMol 00608 p++; 00609 00610 CComBSTR name_b, kind_b, relpos_b; 00611 name_b.Attach(SysAllocString(L""));//prepare for empty names, name_b.p is not 0 anymore 00612 if (name_b.m_str == NULL) 00613 COMTHROW(E_OUTOFMEMORY); 00614 OLECHAR * p2 = p; 00615 00616 str_scan_name( &p2, lenOf + path - p2, name_b, kind_b, relpos_b); // 2nd parameter = the # of characters left 00617 ASSERT( name_b != 0); 00618 00619 int relpos = -1; 00620 if (relpos_b.Length()) 00621 { 00622 if (swscanf(static_cast<const wchar_t*>(relpos_b), L"%d", &relpos) != 1) 00623 return E_INVALIDARG; 00624 } 00625 00626 bool found = false; 00627 bool conflict = false; 00628 int n_found = 0; 00629 CoreObjs children = self[ATTRID_FCOPARENT+ATTRID_COLLECTION]; 00630 ITERATE_THROUGH(children) { 00631 CComBSTR n = ITER[ATTRID_NAME];//if name is empty then n = "" and n.p != 0 that is why we added to name_b the "" value 00632 CComBSTR kind; 00633 COMTHROW( mgaproject->FindMetaRef( ITER[ATTRID_META])->get_Name( &kind)); 00634 00635 bool similar = n == name_b; 00636 similar = similar || ITER[ATTRID_PERMISSIONS] == LIBROOT_FLAG && libraryNameEqual(n, name_b); 00637 similar = similar && (kind_b == L"" || kind == kind_b); 00638 if (similar && (!found || relpos != -1)) 00639 { 00640 if (relpos == -1 || relpos == n_found) 00641 { 00642 if ( *p2 != 0) 00643 { 00644 ObjForCore(ITER)->get_ObjectByPath( CComBSTR(p2), pVal); 00645 } 00646 else 00647 { 00648 ObjForCore(ITER)->getinterface( pVal); 00649 } 00650 00651 if ( *pVal) 00652 found = true; 00653 } 00654 n_found++; 00655 } 00656 else if( similar && found) // found at least two objects with similar names at this level (samename siblings) and the first sibling contains the needed object already 00657 { 00658 if ( *p2 != 0) 00659 { 00660 CComObjPtr<IMgaObject> pdummyVal; 00661 ObjForCore(ITER)->get_ObjectByPath( CComBSTR(p2), PutOut(pdummyVal)); 00662 if( pdummyVal) 00663 { 00664 //COMTHROW(); //identical name found at this level and down below to the bottom 00665 conflict = true; 00666 *pVal = 0; 00667 } 00668 00669 } 00670 else 00671 { 00672 //COMTHROW(); //identical name found 00673 conflict = true; 00674 *pVal = 0; 00675 00676 } 00677 } 00678 } 00679 } 00680 else if(*p == '#') 00681 { 00682 p++; 00683 long relid = wcstol(p,&p,0); 00684 COMTHROW(get_ChildObjectByRelID(relid, &pp)); 00685 00686 if(pp) { 00687 if(*p != 0) COMTHROW(pp->get_ObjectByPath( CComBSTR(p), pVal)); // corr by ZolMol 00688 else *pVal = pp.Detach(); 00689 } 00690 } 00691 else // regular name 00692 { 00693 CComBSTR name_b; 00694 name_b.Attach(SysAllocString(L""));//prepare for empty names, name_b.p is not 0 anymore 00695 if (name_b.m_str == NULL) 00696 COMTHROW(E_OUTOFMEMORY); 00697 OLECHAR * p2 = p; 00698 00699 str_scan_name( &p2, lenOf + path - p2, name_b, CComBSTR(), CComBSTR()); // disregard kind and relpos 00700 ASSERT( name_b != 0); 00701 00702 bool found = false; 00703 bool conflict = false; 00704 CoreObjs children = self[ATTRID_FCOPARENT+ATTRID_COLLECTION]; 00705 ITERATE_THROUGH(children) { 00706 CComBSTR n = ITER[ATTRID_NAME];//if name is empty then n = "" and n.p != 0 that is why we added to name_b the "" value 00707 00708 bool similar = n == name_b; 00709 if( similar && !found) 00710 { 00711 if ( *p2 != 0) 00712 { 00713 ObjForCore(ITER)->get_ObjectByPath( CComBSTR(p2), pVal); 00714 } 00715 else 00716 { 00717 ObjForCore(ITER)->getinterface( pVal); 00718 } 00719 00720 if ( *pVal) 00721 found = true; 00722 } 00723 else if( similar && found) // found at least two objects with similar names at this level (samename syblings) and the first sibling contains the needed object already 00724 { 00725 if ( *p2 != 0) 00726 { 00727 CComObjPtr<IMgaObject> pdummyVal; 00728 ObjForCore(ITER)->get_ObjectByPath( CComBSTR(p2), PutOut(pdummyVal)); 00729 if( pdummyVal) 00730 { 00731 //identical name found at this level and down below to the bottom 00732 conflict = true; 00733 *pVal = 0; 00734 } 00735 00736 } 00737 else 00738 { 00739 //identical name found 00740 conflict = true; 00741 *pVal = 0; 00742 00743 } 00744 } 00745 } 00746 } 00747 } COMCATCH(;); 00748 } 00749 00750 // main delimiter in the path is the slash character: '/' 00751 // searches based on name, kind and relpos: "/@MyFolder|kind=OneFolder/@MySubFolder|kind=AnotherFolder" (the project name must not be included) 00752 // if several objects are found with the same name and kind then relpos decides among them (relpos <==> the order of creation) 00753 // if relpos indicates larger number then the existing samename children then the one with the largest id (the youngest) is selected 00754 HRESULT FCO::get_NthObjectByPath(long n_th, BSTR path, IMgaObject ** pVal) { 00755 COMTRY { 00756 CHECK_OUTPTRPAR(pVal); 00757 CheckRead(); 00758 00759 OLECHAR *p = path; 00760 int lenOf = SysStringLen( path); 00761 00762 if(*p == '/') p++; 00763 CComPtr<IMgaObject> pp; 00764 if(*p == '@') { // implemented by ZolMol 00765 p++; 00766 00767 CComBSTR name_b, kind_b, relpos_b; 00768 name_b.Attach(SysAllocString(L""));//prepare for empty names, name_b.p is not 0 anymore 00769 if (name_b.m_str == NULL) 00770 COMTHROW(E_OUTOFMEMORY); 00771 OLECHAR * p2 = p; 00772 00773 str_scan_name( &p2, lenOf + path - p2, name_b, kind_b, relpos_b); 00774 ASSERT( name_b != 0); 00775 00776 bool found = false; 00777 std::map< objid_type, std::vector<CoreObj> > samename_objs; 00778 CoreObjs children = self[ATTRID_FCOPARENT+ATTRID_COLLECTION]; 00779 ITERATE_THROUGH(children) { 00780 CComBSTR n = ITER[ATTRID_NAME];//if name is empty then n = "" and n.p != 0 that is why we added to name_b the "" value 00781 CComBSTR kind; 00782 COMTHROW( mgaproject->FindMetaRef( ITER[ATTRID_META])->get_Name( &kind)); 00783 00784 bool similar = n == name_b; 00785 similar = similar || ITER[ATTRID_PERMISSIONS] == LIBROOT_FLAG && libraryNameEqual(n, name_b); 00786 similar = similar && kind == kind_b; 00787 if( similar) 00788 { 00789 objid_type id = ITER.GetObjID(); 00790 ASSERT( samename_objs.find( id) == samename_objs.end()); 00791 00792 samename_objs[ id].push_back( ITER); 00793 } 00794 } 00795 00796 if( samename_objs.empty()) return S_OK; 00797 00798 #ifdef DEBUG 00799 std::map< objid_type, std::vector<CoreObj> >::iterator i = samename_objs.begin(); 00800 std::map< objid_type, std::vector<CoreObj> >::iterator e = samename_objs.end(); 00801 for( ; i != e; ++i) 00802 { 00803 ASSERT( i->second.size() == 1); // the id is unique, one element in the vector 00804 } 00805 #endif 00806 00807 std::string relpos_str; 00808 CopyTo( relpos_b, relpos_str); 00809 00810 int relpos; 00811 if (sscanf( relpos_str.c_str(), "%d", &relpos) != 1) 00812 return E_INVALIDARG; 00813 00814 // take from the samename_objs map the element at relpos relative position 00815 std::map< objid_type, std::vector<CoreObj> >::iterator ii = samename_objs.begin(); 00816 std::map< objid_type, std::vector<CoreObj> >::iterator ee = samename_objs.end(); 00817 for( int count = 0; count < relpos && ii != ee; ++ii) 00818 ++count; 00819 00820 CoreObj the_right_one; 00821 if( ii == ee) // no samename objects are present in such number 00822 { 00823 std::map< objid_type, std::vector<CoreObj> >::reverse_iterator rev_i = samename_objs.rbegin(); 00824 the_right_one = *(rev_i->second.begin()); 00825 } 00826 else if( ii->second.size() > 0) 00827 the_right_one = *(ii->second.begin()); 00828 00829 00830 // continue the search for the remaining part of the string: p2 00831 if ( *p2 != 0) 00832 { 00833 ObjForCore(the_right_one)->get_NthObjectByPath(n_th, CComBSTR(p2), pVal); 00834 } 00835 else 00836 { 00837 ObjForCore(the_right_one)->getinterface( pVal); 00838 } 00839 00840 if ( *pVal) 00841 found = true; 00842 } 00843 } COMCATCH(;); 00844 } 00845 00846 HRESULT FCO::get_ChildFCO(BSTR name, IMgaFCO ** pVal) { 00847 COMTRY { 00848 CHECK_INSTRPAR(name); 00849 CHECK_OUTPTRPAR(pVal); 00850 CheckRead(); 00851 00852 CoreObjs children = self[ATTRID_FCOPARENT+ATTRID_COLLECTION]; 00853 00854 00855 ITERATE_THROUGH(children) { 00856 if(!ITER.IsFCO()) continue; 00857 if(CComBSTR(ITER[ATTRID_NAME]) == name) { 00858 ObjForCore(ITER)->getinterface(pVal); 00859 break; 00860 } 00861 } 00862 } 00863 COMCATCH(;); 00864 } 00865 00866 00867 00868 00869 00870 00871 //should be namespace aware 00872 HRESULT FCO::GetChildrenOfKind(BSTR kindname, IMgaFCOs ** pVal) { 00873 COMTRY { 00874 CheckRead(); 00875 metaref_type tgood = 0; 00876 CComBSTR kindname_m = mgaproject->prefixWNmspc( kindname); 00877 00878 CoreObjs children = self[ATTRID_FCOPARENT+ATTRID_COLLECTION]; 00879 00880 CREATEEXCOLLECTION_FOR(MgaFCO,q); 00881 00882 ITERATE_THROUGH(children) { 00883 metaref_type t = CoreObj(ITER)[ATTRID_META]; 00884 if(!tgood) { 00885 CComQIPtr<IMgaMetaFCO> meta = mgaproject->FindMetaRef(t); 00886 ASSERT(meta); 00887 CComBSTR str; 00888 meta->get_Name(&str); 00889 if( str == kindname || str == kindname_m) tgood = t; 00890 } 00891 if(t == tgood) { 00892 CComPtr<IMgaFCO> ff; 00893 ObjForCore(ITER)->getinterface(&ff); 00894 q->Add(ff); 00895 } 00896 } 00897 *pVal = q.Detach(); 00898 } 00899 COMCATCH(;); 00900 } 00901 00902 00903 00904 HRESULT FCO::ChangeObject(IMgaMetaRole *newrole, IMgaMetaFCO *kind) { 00905 CoreObj selfsave = self; 00906 COMTRY_IN_TRANSACTION { 00907 CheckWrite(); 00908 objtype_enum nt; 00909 COMTHROW(kind->get_ObjType(&nt)); 00910 metaid_type currenttype = self.GetMetaID(), newtype = nt + DTID_BASE + nt - OBJTYPE_NULL; 00911 // no changing real types yet: 00912 CoreObjs subtypes = self[ATTRID_DERIVED+ATTRID_COLLECTION]; 00913 if(self[ATTRID_DERIVED] != NULL || subtypes.Count()) COMTHROW(E_MGA_OP_REFUSED); 00914 00915 if(currenttype != newtype) { 00916 static const attrid_type collids[DTID_SET-DTID_BASE+1] = { 00917 0, ATTRID_FCOPARENT, 0, ATTRID_SEGREF, ATTRID_SETMEMBER, ATTRID_CONNROLE }; 00918 attrid_type collid = collids[currenttype]; 00919 if(collid) { 00920 CoreObjs coll = self[collid+ATTRID_COLLECTION]; 00921 if(coll.Count()) COMTHROW(E_MGA_META_VIOLATION); 00922 } 00923 // now it is sure that the Masterobj collection of the reference is empty 00924 if(currenttype == DTID_REFERENCE && self[ATTRID_REFERENCE] != NULL) { 00925 COMTHROW(E_MGA_META_VIOLATION); 00926 } 00927 } 00928 00929 CComPtr<IMgaMetaFCO> okind, newkind = kind; 00930 COMTHROW(get_Meta(&okind)); 00931 if(!newkind) COMTHROW(newrole->get_Kind(&newkind)); 00932 if(okind != newkind) { 00933 if(currenttype == DTID_MODEL) { 00934 CoreObjs chds = self[ATTRID_FCOPARENT+ATTRID_COLLECTION]; 00935 if(chds.Count()) COMTHROW(E_MGA_META_VIOLATION); 00936 } 00937 CoreObjs attrs = self[ATTRID_ATTRPARENT+ATTRID_COLLECTION]; 00938 CComPtr<IMgaMetaAttributes> newattrs; 00939 COMTHROW(newkind->get_Attributes(&newattrs)); 00940 ITERATE_THROUGH(attrs) { 00941 CComPtr<IMgaMetaBase> ameta = mgaproject->FindMetaRef(ITER[ATTRID_META]); 00942 MGACOLL_ITERATE(IMgaMetaAttribute, newattrs) { 00943 if(COM_EQUAL(ameta, MGACOLL_ITER)) break; 00944 } 00945 if(MGACOLL_AT_END) COMTHROW(E_MGA_META_VIOLATION); 00946 MGACOLL_ITERATE_END; 00947 } 00948 } 00949 00950 if(currenttype != newtype) { 00951 CoreObj nnode; 00952 COMTHROW(mgaproject->dataproject->CreateObject(newtype, &nnode.ComPtr())); 00953 nnode[ATTRID_FCOPARENT] = self[ATTRID_FCOPARENT]; 00954 self[ATTRID_FCOPARENT] = NULLCOREOBJ; 00955 nnode[ATTRID_NAME] = self[ATTRID_NAME]; 00956 nnode[ATTRID_RELID] = self[ATTRID_RELID]; 00957 nnode[ATTRID_DERIVED] = NULL; 00958 nnode[ATTRID_PERMISSIONS] = 0; 00959 { ITERATE_THROUGH(self[ATTRID_CONSTROWNER+ATTRID_COLLECTION]) ITER[ATTRID_CONSTROWNER] = nnode; } 00960 // FIXME: should copy registry 00961 { ITERATE_THROUGH(self[ATTRID_XREF+ATTRID_COLLECTION]) ITER[ATTRID_XREF] = nnode; } 00962 { ITERATE_THROUGH(self[ATTRID_XREF+ATTRID_REFERENCE]) ITER[ATTRID_REFERENCE] = nnode; } 00963 COMTHROW(self->Delete()); 00964 /* this has to be fixed!!!! */ ASSERT(false); 00965 self = nnode; 00966 } 00967 metaref_type mr; 00968 COMTHROW(newkind->get_MetaRef(&mr)); 00969 self[ATTRID_META] = mr; 00970 if(newrole) 00971 { 00972 COMTHROW(newrole->get_MetaRef(&mr)); 00973 } 00974 else mr = METAREF_NULL; 00975 self[ATTRID_ROLEMETA] = mr; 00976 00977 } COMCATCH_IN_TRANSACTION( self = selfsave;); 00978 } 00979 00980 HRESULT FCO::GetSourceControlInfo( long* p_scInfo) 00981 { 00982 COMTRY 00983 { 00984 if( p_scInfo) 00985 { 00986 CheckRead(); 00987 *p_scInfo = self[ATTRID_FILESTATUS]; 00988 } 00989 } 00990 COMCATCH(;) 00991 } 00992 00996 00997 /* Only the real reference ones, does not work for XREFS */ 00998 00999 01000 typedef stdext::hash_set<CoreObj, coreobj_hashfunc> coreobjset; 01001 01002 void EnumRefs(CoreObj &self, coreobjset fcoset, EXCOLLECTIONTYPE_FOR(MgaFCO) *q) { 01003 metaid_type n = GetMetaID(self); 01004 if(n == DTID_MODEL) { 01005 CoreObjs children = self[ATTRID_FCOPARENT+ATTRID_COLLECTION]; 01006 ITERATE_THROUGH(children) { 01007 EnumRefs(ITER,fcoset,q); 01008 } 01009 } 01010 CoreObjs refs = self[DTID_REFERENCE+ATTRID_COLLECTION]; 01011 ITERATE_THROUGH(refs) { 01012 CoreObj cur = ITER; 01013 do { 01014 coreobjset::iterator i; 01015 if((i = fcoset.find(ITER)) != fcoset.end()) return; // internal ref found 01016 cur = cur[ATTRID_FCOPARENT]; 01017 } while(GetMetaID(cur) == DTID_MODEL); 01018 CComPtr<IMgaReference> r; 01019 ObjForCore(ITER)->getinterface(&r); 01020 q->Add(r); 01021 } 01022 } 01023 01024 STDMETHODIMP CMgaProject::EnumExtReferences(IMgaFCOs *fcos, IMgaFCOs **pVal) { 01025 COMTRY { 01026 coreobjset fcoobjs; 01027 CHECK_MYINPTRSPAR(fcos); 01028 CHECK_OUTPTRPAR(pVal); 01029 CREATEEXCOLLECTION_FOR(MgaFCO,q); 01030 01031 MGACOLL_ITERATE(IMgaFCO, fcos) { 01032 fcoobjs.insert(CoreObj(MGACOLL_ITER)); 01033 } MGACOLL_ITERATE_END; 01034 01035 MGACOLL_ITERATE(IMgaFCO, fcos) { 01036 EnumRefs(CoreObj(MGACOLL_ITER), fcoobjs, q); 01037 } MGACOLL_ITERATE_END; 01038 *pVal = q.Detach(); 01039 } COMCATCH(;); 01040 } 01041