SOL9 2.0 Sample: ClassTreeView

SOL9 2.0 Samples

1 Screenshot


2 Source code

/*
 * 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 (...) {

    }
}

Last modified: 11 Nov 2009

Copyright (c) 2009 Antillia.com ALL RIGHTS RESERVED.