#include "stdafx.h" #include "Common.h" #if defined(JPN) //日本語 #include "pj_msg_jpn.h" #else //英語 #include "pj_msg_eng.h" #endif CClassTreeView *pobj_ClassTreeView; BOOL bSearchingClasses,bRetrySearchingClasses; int CClassTreeView::hash_default(LONG_PTR lpdata){ return lpdata%MAX_HASH; } void CClassTreeView::AddValidItem(HTREEITEM hItem,HTREEITEM hFileTreeItem){ //ハッシュ値を取得 int key; key=hash_default((LONG_PTR)hItem); //格納位置を取得 TREEHASH *pth; pth=&tree_data[key]; while(pth->hItem){ if(pth->hItem==hItem){ //既に存在するときは抜け出す return; } if(pth->pNextData==0){ pth->pNextData=(TREEHASH *)HeapAlloc(hHeap,0,sizeof(TREEHASH)); pth=pth->pNextData; break; } pth=pth->pNextData; } pth->hItem=hItem; pth->hFileTreeItem = hFileTreeItem; pth->pNextData=0; } BOOL CClassTreeView::delete_check(HTREEITEM hItem){ //ハッシュ値を取得 int key; key=hash_default((LONG_PTR)hItem); TREEHASH *pth; pth=&tree_data[key]; while(pth->hItem){ if(pth->hItem==hItem) return 1; if(pth->pNextData==0) break; pth=pth->pNextData; } return 0; } void CClassTreeView::DeleteInvalidItems(HTREEITEM hItem){ HTREEITEM hChildItem; while(hItem){ if(!delete_check(hItem)){ HTREEITEM hTemp; hTemp=hItem; hItem=TreeView_GetNextSibling(hTreeWnd,hItem); TreeView_DeleteItem(hTreeWnd,hTemp); continue; } hChildItem=TreeView_GetChild(hTreeWnd,hItem); if(hChildItem){ DeleteInvalidItems(hChildItem); } hItem=TreeView_GetNextSibling(hTreeWnd,hItem); } } void CClassTreeView::DeleteTreeHash(TREEHASH *pth){ if(pth->hItem && (hNowFileTreeItem==(HTREEITEM)-1 || hNowFileTreeItem==pth->hFileTreeItem)){ if(pth->pNextData){ DeleteTreeHash(pth->pNextData); HeapDefaultFree(pth->pNextData); pth->pNextData=0; } pth->hItem=0; } } HTREEITEM CClassTreeView::insert(HTREEITEM hParentItem,int flag,char *lpszName,HTREEITEM hFileTreeItem){ char temporary[255]; TVITEM tvItem; tvItem.pszText=temporary; tvItem.cchTextMax=255; HTREEITEM hNextItem; hNextItem=TreeView_GetChild(hTreeWnd,hParentItem); while(hNextItem){ tvItem.mask=TVIF_HANDLE|TVIF_TEXT; tvItem.hItem=hNextItem; TreeView_GetItem(hTreeWnd,&tvItem); if(lstrcmp(lpszName,tvItem.pszText)==0){ //既に挿入済みの場合 AddValidItem(hNextItem,hFileTreeItem); return hNextItem; } hNextItem=TreeView_GetNextSibling(hTreeWnd,hNextItem); } TV_INSERTSTRUCT tv; tv.hInsertAfter=TVI_SORT; tv.item.mask=TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIS_EXPANDED ; tv.hParent=hParentItem; tv.item.pszText=lpszName; if(flag==CTV_ROOT){ tv.item.iImage=3; tv.item.iSelectedImage=3; } if(flag==CTV_FOLDER){ tv.item.iImage=0; tv.item.iSelectedImage=0; } else if(flag==CTV_GLOBAL_PROC){ tv.item.iImage=5; tv.item.iSelectedImage=5; } else if(flag==CTV_CLASS){ tv.item.iImage=2; tv.item.iSelectedImage=2; } else if(flag==CTV_PUBLIC_MEMBER){ tv.item.iImage=4; tv.item.iSelectedImage=4; } else if(flag==CTV_PUBLIC_METHOD){ tv.item.iImage=5; tv.item.iSelectedImage=5; } else if(flag==CTV_PRIVATE_MEMBER){ tv.item.iImage=6; tv.item.iSelectedImage=6; } else if(flag==CTV_PRIVATE_METHOD){ tv.item.iImage=7; tv.item.iSelectedImage=7; } hNextItem=TreeView_InsertItem(hTreeWnd,&tv); AddValidItem(hNextItem,hFileTreeItem); return hNextItem; } CClassTreeView::CClassTreeView(){ memset(this,0,sizeof(CClassTreeView)); } CClassTreeView::~CClassTreeView(){ while(bSearchingClasses) Sleep(10); this->hNowFileTreeItem = (HTREEITEM)-1; int i; for(i=0;ipProcInfo){ //プロシージャ情報のメモリを解放 for(i=0;iNumberOfProcedures;i++){ HeapDefaultFree(pobj_ClassTreeView->pProcInfo[i].name); } HeapDefaultFree(pobj_ClassTreeView->pProcInfo); pobj_ClassTreeView->pProcInfo=0; } } void CClassTreeView::init(HWND hwnd,HTREEITEM hFileTreeItem){ hTreeWnd=hwnd; this->hNowFileTreeItem = hFileTreeItem; int i; for(i=0;iinsert( hGlobalProcedureFolder, CTV_GLOBAL_PROC, lpszName, hFileTreeItem); } HTREEITEM CClassTreeView::insert_code_item(HTREEITEM hParentItem,int flag,char *lpszName,HTREEITEM hFileTreeItem,char *pBuf,int p){ int i4; i4=NumberOfProcedures; pProcInfo=(PROCINFO *)HeapReAlloc(hHeap,0,pProcInfo,sizeof(PROCINFO)*(i4+1)); pProcInfo[i4].name=(char *)HeapAlloc(hHeap,0,lstrlen(lpszName)+1); lstrcpy(pProcInfo[i4].name,lpszName); pProcInfo[i4].hFileTreeItem = hFileTreeItem; //コード位置 pProcInfo[i4].code_pos=p; //ツリーアイテムを挿入 HTREEITEM hTempItem; hTempItem=insert( hParentItem, flag, lpszName, hFileTreeItem); pProcInfo[i4].hTreeItem=hTempItem; NumberOfProcedures++; return hTempItem; } void CClassTreeView::InsertClassFolder(char *lpszName,HTREEITEM hFileTreeItem,char *pBuf,int p){ hNowClassFolder=insert_code_item(hRootFolder,CTV_CLASS,lpszName,hFileTreeItem,pBuf,p); } void CClassTreeView::InsertClassMember(int flag,char *lpszName,HTREEITEM hFileTreeItem,char *pBuf,int p){ insert_code_item(hNowClassFolder,flag,lpszName,hFileTreeItem,pBuf,p); } void CClassTreeView::finish(){ DeleteInvalidItems(TreeView_GetRoot(hTreeWnd)); } void AnalysisClass(char *pBuf,int *p,HTREEITEM hFileTreeItem){ int i2; i2=*p; CClassInfo *pobj_ClassInfo; pobj_ClassInfo=new CClassInfo(); pobj_ClassInfo->Analyze(pBuf,p); //クラスフォルダを挿入 pobj_ClassTreeView->InsertClassFolder( pobj_ClassInfo->ClassName, hFileTreeItem, pBuf, i2); /////////////////////////////// // メンバ及びメソッドを挿入 /////////////////////////////// int i; for(i=0;iMemberNum;i++){ int flag; if(pobj_ClassInfo->pMemberInfo[i].dwProc==0){ //メンバ変数 if(pobj_ClassInfo->pMemberInfo[i].dwAccess==ACCESS_PUBLIC){ //公開 flag=CTV_PUBLIC_MEMBER; } else{ //非公開 flag=CTV_PRIVATE_MEMBER; } } else{ //メソッド if(pobj_ClassInfo->pMemberInfo[i].dwAccess==ACCESS_PUBLIC){ //公開 flag=CTV_PUBLIC_METHOD; } else{ //非公開 flag=CTV_PRIVATE_METHOD; } } pobj_ClassTreeView->InsertClassMember(flag,pobj_ClassInfo->pMemberInfo[i].pName,hFileTreeItem,pBuf,pobj_ClassInfo->pMemberInfo[i].code_pos); } delete pobj_ClassInfo; pobj_ClassInfo=0; } void SetClassTreeFromOneFile_Buf( char *pBuf, HTREEITEM hFileTreeItem ){ int i2,i3,i4; char temporary[GENERAL_SIZE]; for(i2=0;;i2++){ if(pBuf[i2]=='\0') break; while(pBuf[i2]=='\r'&&pBuf[i2+1]=='\n'&&pBuf[i2+2]=='\r'&&pBuf[i2+3]=='\n') i2+=2; if(i2==0||(pBuf[i2]=='\r'&&pBuf[i2+1]=='\n')){ if(pBuf[i2]=='\r'&&pBuf[i2+1]=='\n') i2+=2; while(pBuf[i2]>='0'&&pBuf[i2]<='9') i2++; while(pBuf[i2]==' '||pBuf[i2]=='\t') i2++; i4=i2; for(i3=0;;i2++,i3++){ if(!IsVariableChar(pBuf[i2])){ temporary[i3]=0; break; } temporary[i3]=pBuf[i2]; } if(pBuf[i2]=='\0') break; if(lstrcmpi(temporary,"Class")==0|| lstrcmpi(temporary,"Type")==0|| lstrcmpi(temporary,"Interface")==0){ ///////////////////////////// // クラスの解析 ///////////////////////////// AnalysisClass(pBuf,&i4,hFileTreeItem); i2=i4-1; continue; } int sw; if(lstrcmpi(temporary,"Sub")==0) sw=1; else if(lstrcmpi(temporary,"Function")==0) sw=2; else sw=0; if(sw){ //Sub/Function while(pBuf[i2]==' '||pBuf[i2]=='\t') i2++; for(i3=0;;i2++,i3++){ if(!IsVariableChar(pBuf[i2])){ temporary[i3]=0; break; } temporary[i3]=pBuf[i2]; } if(lstrcmpi(temporary,"Export")==0){ //Export修飾子はとばす while(pBuf[i2]==' '||pBuf[i2]=='\t') i2++; for(i3=0;;i2++,i3++){ if(!IsVariableChar(pBuf[i2])){ temporary[i3]=0; break; } temporary[i3]=pBuf[i2]; } } i4=pobj_ClassTreeView->NumberOfProcedures; pobj_ClassTreeView->pProcInfo=(PROCINFO *)HeapReAlloc(hHeap,0,pobj_ClassTreeView->pProcInfo,sizeof(PROCINFO)*(i4+1)); pobj_ClassTreeView->pProcInfo[i4].name=(char *)HeapAlloc(hHeap,0,lstrlen(temporary)+1); lstrcpy(pobj_ClassTreeView->pProcInfo[i4].name,temporary); pobj_ClassTreeView->pProcInfo[i4].hFileTreeItem = hFileTreeItem; //定義行の選択範囲 pobj_ClassTreeView->pProcInfo[i4].code_pos=i2; //パラメータ部 while(pBuf[i2]==' '||pBuf[i2]=='\t') i2++; if(pBuf[i2]=='('){ int IsStr,PareNum; for(i2++,i3=0,IsStr=0,PareNum=0;;i2++,i3++){ if(pBuf[i2]=='\"') IsStr^=1; if(pBuf[i2]=='('&&IsStr==0) PareNum++; if(pBuf[i2]==')'&&IsStr==0){ PareNum--; if(PareNum<0){ temporary[i3]=0; break; } } if(pBuf[i2]=='\0') break; temporary[i3]=pBuf[i2]; } //temporaryはパラメータの内容が格納されるが、不要 } for(;;i2++){ if(IsCommandDelimitation(pBuf,i2)){ break; } if((pBuf[i2]=='a'||pBuf[i2]=='A')&&(pBuf[i2+1]=='s'||pBuf[i2+1]=='S')&&(pBuf[i2+2]==' '||pBuf[i2+2]=='\t')){ i2+=3; while(pBuf[i2]==' '||pBuf[i2]=='\t') i2++; for(i3=0;;i2++,i3++){ if(!IsVariableChar(pBuf[i2])){ temporary[i3]=0; break; } temporary[i3]=pBuf[i2]; } //temporaryには型情報が格納されるが、不要 break; } } //ツリーアイテムを挿入 HTREEITEM hTempItem; hTempItem=pobj_ClassTreeView->InsertGlobalProcedure( CTV_GLOBAL_PROC, pobj_ClassTreeView->pProcInfo[i4].name, hFileTreeItem); pobj_ClassTreeView->pProcInfo[i4].hTreeItem=hTempItem; pobj_ClassTreeView->NumberOfProcedures++; i2--; } } } } void SetClassTreeFromOneFile( const ActiveBasic::PM::FM::File &file){ int WndNum; HWND hChild=GetWindow(hClient,GW_CHILD); while(hChild){ WndNum=GetWndNum(hChild); if( WndNum != -1 ) { if(IS_DOCUMENT_TEXT(MdiInfo[WndNum]->DocType)){ if(lstrcmpi(MdiInfo[WndNum]->path.c_str(),file.GetFullPath().c_str())==0) break; } hChild=GetNextWindow(hChild,GW_HWNDNEXT); } } char *pBuf; if(hChild){ //すでに指定されたファイルが開かれている場合 pBuf=MdiInfo[WndNum]->pMdiTextEdit->buffer; } else{ //開かれていない場合 pBuf=ReadBuffer(file.GetFullPath()); if(!pBuf) pBuf=(char *)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,1); } SetClassTreeFromOneFile_Buf( pBuf, file.GetTreeItemHandle() ); if(!hChild) HeapDefaultFree(pBuf); } void SetClassTreeFromAllFile( ActiveBasic::PM::FM::Folder &folder ) { BOOST_FOREACH( ActiveBasic::PM::FM::Folder &childFolder, folder.folders ) { SetClassTreeFromAllFile( childFolder ); } BOOST_FOREACH( ActiveBasic::PM::FM::File &file, folder.files ) { SetClassTreeFromOneFile( file ); } } void SetProcedureTreeData(void *temp_hFileTreeItem) { BOOL bExpand; TVITEM tvItem; SCROLLINFO si; HTREEITEM hFileTreeItem = (HTREEITEM)temp_hFileTreeItem; if(bSearchingClasses){ bRetrySearchingClasses=1; _endthread(); return; } bSearchingClasses=1; if(pobj_ClassTreeView->pProcInfo){ wait_repeat: Sleep(700); if(bRetrySearchingClasses){ bRetrySearchingClasses=0; goto wait_repeat; } PROCINFO *pNewProcInfo; pNewProcInfo=(PROCINFO *)HeapAlloc(hHeap,0,pobj_ClassTreeView->NumberOfProcedures*sizeof(PROCINFO)); int NewProcNum; NewProcNum=0; //プロシージャ情報のメモリを解放 for(int i=0;iNumberOfProcedures;i++){ if(hFileTreeItem==(HTREEITEM)-1 || hFileTreeItem==pobj_ClassTreeView->pProcInfo[i].hFileTreeItem){ HeapDefaultFree(pobj_ClassTreeView->pProcInfo[i].name); } else{ pNewProcInfo[NewProcNum]=pobj_ClassTreeView->pProcInfo[i]; NewProcNum++; } } HeapDefaultFree(pobj_ClassTreeView->pProcInfo); pobj_ClassTreeView->pProcInfo=pNewProcInfo; pobj_ClassTreeView->NumberOfProcedures=NewProcNum; } else{ pobj_ClassTreeView->pProcInfo=(PROCINFO *)HeapAlloc(hHeap,0,1); pobj_ClassTreeView->NumberOfProcedures=0; } extern HWND hProcedureTreeView; tvItem.hItem=TreeView_GetRoot(hProcedureTreeView); if(tvItem.hItem){ TreeView_GetItem(hProcedureTreeView,&tvItem); if(tvItem.state&TVIS_EXPANDED){ bExpand=1; si.cbSize=sizeof(SCROLLINFO); si.fMask=SIF_POS; GetScrollInfo(hProcedureTreeView,SB_VERT,&si); } else bExpand=0; } else bExpand=1; pobj_ClassTreeView->init(hProcedureTreeView,hFileTreeItem); //ルートフォルダ pobj_ClassTreeView->InsertRootFolder(); //グローバル関数フォルダ pobj_ClassTreeView->InsertGlobalProcedureFolder(); //描画をロック LockWindowUpdate(hProcedureTreeView); if( projectInfo.IsOpened() ){ // プロジェクトが開かれているとき if(hFileTreeItem==(HTREEITEM)-1){ boost::mutex::scoped_lock lock( projectInfo.fileSystem.mutex ); //プロジェクトのすべてのファイルを解析 SetClassTreeFromAllFile( projectInfo.fileSystem.root ); //不要になったアイテムを除去 //pobj_ClassTreeView->finish(); } else{ ///////////////////////////////// // 編集中のファイルのみを解析 ///////////////////////////////// SetClassTreeFromOneFile( projectInfo.fileSystem.root.FindFile( hFileTreeItem ) ); } } else{ // 編集中の単体ファイルを解析 HWND hChild=GetWindow(hClient,GW_CHILD); int WndNum=GetWndNum(hChild); char *pBuf=MdiInfo[WndNum]->pMdiTextEdit->buffer; SetClassTreeFromOneFile_Buf( pBuf, (HTREEITEM)-1 ); } //不要になったアイテムを除去 pobj_ClassTreeView->finish(); //描画ロックを解除 LockWindowUpdate(0); if(bExpand){ TreeView_Expand(hProcedureTreeView,pobj_ClassTreeView->hRootFolder,TVE_EXPAND); SetScrollInfo(hProcedureTreeView,SB_VERT,&si,1); } bSearchingClasses=0; if(bRetrySearchingClasses){ bRetrySearchingClasses=0; ResetClassTree(hFileTreeItem); } if(pobj_ClassTreeView->bCloseSwitch){ //コード解析中に終了ボタンが押されたとき PostMessage(hOwner,WM_CLOSE,0,0); } if(pobj_ClassTreeView->bShowSwitch){ //コード解析中にクラスビューがダブルクリックされたとき extern HWND hProjectViewTab; PostMessage(hProjectViewTab,WM_COMMAND,IDM_PROCEDURETREE_SHOW,0); pobj_ClassTreeView->bShowSwitch=0; } _endthread(); } void ResetClassTree(HTREEITEM hFileTreeItem){ _beginthread(SetProcedureTreeData,0,(void *)hFileTreeItem); }