GME  13
MgaFolder.cpp
Go to the documentation of this file.
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