/*
* ClassTreeView.cpp
* Copyright (c) 2009 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED.
*/
// SOL++2000
// 2000.02.18
// 2009/10/15 Modified to walk recursively subdirectories of the specifed
// folder to find C++ class header files.
#include <sol\Stdio.h>
#include <sol\Profile.h>
#include <sol\FileFinder.h>
#include <sol\TreeView.h>
#include <sol\ApplicationView.h>
#include <sol\MessageFont.h>
#include <sol\StringTokenizer.h>
#include <sol\Node.h>
#include <sol\LinkedList.h>
#include <sol\FileStream.h>
//#include <sol\ScrolledRichText.h>
#include <sol\ScrolledText.h>
#include <sol\SplitPane.h>
#include <sol\StringTokenizerT.h>
#include <sol/StringT.h>
#include <sol/FolderBrowser.h>
#include <sol\ClientDC.h>
#include "Pair.h"
#include "InheritanceTreeView.h"
#include "resource.h"
namespace SOL {
class ClassTreeView :public ApplicationView {
private:
static const UINT WM_SHOW_INITIAL_TREE = (WM_USER+2009);
private:
Node* root;
LinkedList* pairList;
MessageFont font;
ScrolledText richText;
InheritanceTreeView treev;
SplitPane hpanedw;
int initialized;
FolderBrowser browser;
TCHAR libPath[MAX_PATH];
public:
ClassTreeView(Application& applet, const TCHAR* name, Args& args)
:ApplicationView(applet, name, args)
{
initialized = FALSE;
root = NULL;
pairList = new LinkedList();
Args ar;
font.create(9);
ar.reset();
ar.set(XmNexStyle, (ulong)WS_EX_CONTROLPARENT);
ar.set(XmNdirection, SplitPane::HORIZONTAL);
hpanedw.create(this, _T(""), ar);
ar.reset();
ar.set(XmNexStyle, (ulong)WS_EX_CLIENTEDGE);
ar.set(XmNstyle, (ulong)(WS_GROUP|\
TVS_HASBUTTONS|TVS_SHOWSELALWAYS|
TVS_HASLINES|TVS_LINESATROOT));
treev.create(&hpanedw, NULL, ar);
hpanedw.add(&treev);
treev.addCallback(XmNselChangedCallback, this,
(Callback)&ClassTreeView::selChanged, NULL);
addCallback(XmNmenuCallback, IDM_DIR, this,
(Callback)&ClassTreeView::selectDir, NULL);
addCallback(XmNmenuCallback,
IDM_EXIT, this, (Callback)&ClassTreeView::exit, NULL);
addCallback(XmNmenuCallback,
IDM_VERSION, this, (Callback)&ClassTreeView::version, NULL);
addEventHandler(WM_CLOSE, this,
(Handler)&ClassTreeView::close, NULL);
addEventHandler(WM_SHOW_INITIAL_TREE, this,
(Handler)&ClassTreeView::showInitialTree, NULL);
ar.reset();
richText.create(&hpanedw, NULL, ar);
richText.setFont(&font);
hpanedw.add(&richText);
restorePlacement();
Profile profile;
memset(libPath, (TCHAR)0, SizeOf(libPath));
wchar_t classLibrary[MAX_PATH];
profile.get(_T("PATH"), _T("ClassLibrary"), classLibrary,
SizeOf(classLibrary)-1);
if (strlen(classLibrary)>0 &&
GetFileAttributesW(classLibrary) !=0xffffffff) {
StringT<TCHAR> tstring;
StringConverter converter;
converter.convert(classLibrary, tstring);
strcpy(libPath, (const TCHAR*)tstring);
post(WM_SHOW_INITIAL_TREE, 0, 0);
}
}
public:
~ClassTreeView()
{
delete root;
delete pairList;
}
private:
long showInitialTree(Event& event)
{
if (strlen(libPath)>0) {
showClassTree(libPath);
TCHAR text[_MAX_PATH*2];
_stprintf_s(text, SizeOf(text), _T("%s - ClassTreeView"), libPath);
setText(text);
}
return 0L;
}
private:
void version(Action& action)
{
showMessageDialog(_T("Version"),
_T("ClassTreeView Version 1.0.0.2\r\nCopyright(C) 2009 Antillia.com"),
MB_OK|MB_ICONINFORMATION);
}
private:
long close(Event& event)
{
StringConverter converter;
wchar_t* classlib= converter.toWideChar(libPath);
Profile profile;
profile.set(_T("PATH"), _T("ClassLibrary"), classlib,
strlen(classlib)+1);
savePlacement();
return defaultProc(event);
}
private:
void showClassTree(const TCHAR* dir)
{
if(dir) {
delete root;
root = new Node(dir, 0);
delete pairList;
pairList = new LinkedList();
setSysCursor(IDC_WAIT);
findClass(dir);
// DumpPairList();
if(root) {
treev.deleteAllItems();
TCHAR* name = root -> getName();
HTREEITEM ritem = treev.addItem(NULL, TVI_ROOT, name);
treev.buildTree(ritem, name, pairList);
treev.sortAllChildren(ritem);
treev.expandChildren(ritem, TVE_EXPAND);
}
setSysCursor(IDC_ARROW);
}
}
private:
void selectDir(Action& action)
{
String path;
int rc = browser.show(libPath, path);
if(rc == IDOK) {
const TCHAR* dir = (const TCHAR*)path;
strcpy(libPath, dir);
//Printf("Directory %s\r\n", dir);
TCHAR text[_MAX_PATH+40];
_stprintf_s(text, SizeOf(text), _T("%s - ClassTreeView"), dir);
setText(text);
showClassTree(dir);
}
}
private:
long size(Event& event)
{
int w, h;
event.getSize(w, h);
hpanedw.reshape(0, 0, w, h);
if (initialized == FALSE) {
hpanedw.setSashPosition(300);
initialized = TRUE;
}
return 0;
}
private:
void selChanged(Action& action)
{
Event& event = action.getEvent();
NM_TREEVIEW* nmtr = (NM_TREEVIEW*)event.getLParam();
TV_ITEM tvItem = nmtr -> itemNew;
HTREEITEM hselItem = tvItem.hItem;
TV_ITEM hitem;
memset(&hitem, 0, sizeof(hitem));
hitem.mask = TVIF_HANDLE|TVIF_PARAM;
hitem.hItem = hselItem;
treev.getItem(&hitem);
Pair* nodeInfo = (Pair*)hitem.lParam;
if(nodeInfo) {
//Printf("Node name %s\r\n", nodeInfo->getName() );
TCHAR prevFileName[MAX_PATH];
prevFileName[0] = Zero;
getText(prevFileName, sizeof(prevFileName)-1);
TCHAR* fileName = nodeInfo -> getName();
richText.clear();
// Printf("Loading a file %s\r\n", fileName);
// richText.streamIn(fileName, SF_TEXT);
richText.load(fileName);
setText(fileName);
//Printf(">Scroll %d\r\n", nodeInfo->getLine());
int line = nodeInfo->getLine()-1;
DWORD indx = richText.lineIndex(line);
TCHAR buff[512];
int len = richText.getLine(line, buff, sizeof(buff)-1);
if (len>0) {
buff[len] = '\0';
}
//Printf("line %d [%s]\r\n", line, buff);
richText.lineScroll(line, 1);
}
}
private:
void doMessageLoop()
{
MSG msg;
while(PeekMessage (&msg,NULL,0,0,PM_REMOVE)) {
Sleep(10);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
private:
/**
* Recursively traversee subfolder to find all C++ header files for the parameter
* dir.
*/
void findClass(const TCHAR* dir)
{
TCHAR name[_MAX_PATH];
strcpy(name, dir);
strcat(name, _T("\\*.*"));
FindData data;
FileFinder finder(name);
if (finder.getFirst(&data)) {
do {
String fileName = data.cFileName;
TCHAR path[_MAX_PATH];
_stprintf_s(path, SizeOf(path), _T("%s\\%s"), dir, data.cFileName);
if(!(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
//String fileName = data.cFileName;
if (fileName.endsWithIgnoreCase(_T(".h"))) {
searchClass(path);
}
}
else if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
if (!(strcmp(data.cFileName, _T(".")) == 0 ||
strcmp(data.cFileName, _T("..")) == 0)) {
//Recursively call findClass method.
findClass(path);
}
}
doMessageLoop();
} while(finder.getNext(&data));
}
}
private:
int searchClass(TCHAR* name)
{
TCHAR child[MAX_PATH];
TCHAR parent[MAX_PATH];
TCHAR delim[MAX_PATH];
TCHAR keyword[MAX_PATH];
FileStream stream;
if(stream.openReadOnly(name) == False) {
showMessageDialog(name, _T("Cannot open!"), MB_OK);
return False;
}
char buffer[512];
int lno= 0; //line number to indicate "class XXX :public Object {"
TCHAR* rootName = root->getName();
while(stream.getLine(buffer, SizeOf(buffer)) ) {
lno++;
if (strlen(buffer)==0) {
continue;
}
parent[0] = Zero;
child[0] = Zero;
TCHAR* lparen = NULL;
StringT<TCHAR> tstring;
StringConverter converter;
converter.convert(buffer, tstring);
TCHAR* line = (TCHAR*)tstring;
const TCHAR* ptr = line;
//lno++;
StringTokenizer tokenizer(line);
TCHAR token[MAX_PATH];
TCHAR* comment = (TCHAR*)strstr(line, _T("//"));
if(comment) {
*comment = Zero;
}
ptr = tokenizer.getToken(token, SizeOf(token)-1);
if(ptr && strcmp(token, _T("class")) == 0 && strrchr(line, (TCHAR)';') != NULL) {
//Printf(_T("1 Line [%s] Token [%s]\n"), line, token);
continue;
}
if(ptr && strcmp(token, _T("class")) == 0 && strrchr(line, (TCHAR)':') ==NULL) {
if (ptr) {
ptr = tokenizer.getToken(parent, SizeOf(parent));
//Printf(_T("No parent className =[%s]\r\n"), parent);
lparen = strrchr(parent, '{');
if(lparen) {
*lparen = Zero;
}
Node* parentNode = new Node(parent, lno);
Pair* pair = new Pair(new Node(rootName, 0), parentNode);
pair -> setName(name);
pair -> setLine(lno);
pairList->add(pair);
continue;
}
}
if(ptr && strcmp(token, _T("class")) == 0 && strrchr(line, (TCHAR)':') !=NULL) {
//Printf(_T("2 Line [%s] Token [%s]\r\n"), line, token);
TCHAR* d = (TCHAR*)strrchr(line, (TCHAR)':');
if (d) {
*d = (TCHAR)' ';
}
ptr = tokenizer.getToken(child, SizeOf(child));
if(ptr && strstr(child, _T("AFX_EXT_CLASS"))) {
ptr = tokenizer.getToken(child, SizeOf(child));
}
if(ptr && (strstr(child, _T("_OWLCLASS")) ||
strstr(child, _T("_USERCLASS")) ) ) {
ptr = tokenizer.getToken(child, SizeOf(child));
}
if(ptr) {
ptr = tokenizer.getToken(delim, SizeOf(delim));
//Printf(_T("3 Line [%s] Delim [%s]\r\n"), line, delim);
}
if (ptr) {
ptr = tokenizer.getToken(parent, SizeOf(parent));
//Printf(_T("Parent:[%s] Child:[%s]\r\n"), parent, child);
lparen = strrchr(parent, '{');
if(lparen) {
*lparen = Zero;
}
Node* parentNode = new Node(parent, 0);
Node* childNode = new Node(child, 0);
Pair* pair = new Pair(parentNode, childNode);
pair -> setName(name);
pair -> setLine(lno);
pairList->add(pair);
}
}
}
stream.close();
return True;
}
public:
// Only for debugging.
void dumpPairList()
{
ListEntry* ptr = pairList->getEntry();
while(ptr) {
Pair* pair = (Pair*) ptr ->getObject();
Printf(_T("%s -> %s\r\n"), pair->getParentName(),
pair->getChildName());
ptr = ptr ->getNext();
}
}
};
}
///////////////////////////////////////////////////
// ClassTreeView Main
void Main(int argc, TCHAR** argv)
{
const String appClass = "ClassTreeView";
try {
Application applet(appClass, argc, argv);
Args args;
args.set(XmNbackground, (COLOR_BTNFACE+1));
//args.set(XmNclassName, appClass);
ClassTreeView classTree(applet, appClass, args);
classTree.realize();
applet.run();
} catch (...) {
}
}
|