Click here to Skip to main content
15,896,154 members
Articles / Desktop Programming / MFC

SmartLexicon

Rate me:
Please Sign up or sign in to vote.
4.93/5 (14 votes)
30 Aug 2006GPL310 min read 86.2K   3.3K   51  
A multilingual dictionary engine with regular expressions support and Web browser integration.
/*  This file is a part of SmartLexicon, a multi-lingual dictionary engine.

    Copyright (C) 2005, Kostas Giannakakis

    SmartLexicon is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    SmartLexicon is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with SmartLexicon; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "stdafx.h"
#include "SmartLexicon.h"
#include "SmartLexiconDoc.h"
#include "SmartLexiconView.h"
#include "MeaningView.h"
#include "SettingsDlg.h"
#include "LoadingDlg.h"
#include <locale>

#define REG_EX_SUPPORT
#ifdef REG_EX_SUPPORT
#include <boost/regex.hpp>
#endif //REG_EX_SUPPORT

using namespace std;

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define HORIZONTAL_EXTENT_START	100

// CSmartLexiconView

IMPLEMENT_DYNCREATE(CSmartLexiconView, CListView)

BEGIN_MESSAGE_MAP(CSmartLexiconView, CListView)
    ON_WM_CREATE()
    ON_NOTIFY_REFLECT(LVN_ITEMCHANGED, OnLvnItemchanged)
    ON_NOTIFY_REFLECT(LVN_GETDISPINFO, OnLvnGetdispinfo)
END_MESSAGE_MAP()

// CSmartLexiconView construction/destruction

CSmartLexiconView::CSmartLexiconView()
{
#ifdef _TEST
    TRACE0("Testing started!\n");
    LexEngineTest();
    TRACE0("Testing ended!\n");
#endif
    wordToSearch = _T("");
    regExSearch = FALSE;

    dlg = new CStartUpDlg(this);
    dlg->Create(IDD_INIT_DIALOG);
    dlg->ShowWindow(SW_SHOW);

    newDictMsg = RegisterWindowMessage(UWM_START_UP_DIALOG_NEW_DICT_LOADED);
    LoadDictionaries();
    dlg->DestroyWindow();
    delete dlg;
	horizontalBorder = 0;
}

CSmartLexiconView::~CSmartLexiconView()
{
}

BOOL CSmartLexiconView::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName,
                          DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
                          UINT nID, CCreateContext* pContext)
{
    // TODO: Add your specialized code here and/or call the base class

    dwStyle |= LVS_OWNERDATA;
    return CListView::Create(lpszClassName, lpszWindowName, dwStyle,
                             rect, pParentWnd, nID, pContext);
}

BOOL CSmartLexiconView::PreCreateWindow(CREATESTRUCT& cs)
{
    // TODO: Modify the Window class or styles here by modifying
    //  the CREATESTRUCT cs

    return CListView::PreCreateWindow(cs);
}

void CSmartLexiconView::OnInitialUpdate()
{
    CListView::OnInitialUpdate();

    // TODO: You may populate your ListView with items by directly accessing
    //  its list control through a call to GetListCtrl().
    ModifyStyle(LVS_TYPEMASK, LVS_REPORT & LVS_TYPEMASK);
    ModifyStyle(LVS_TYPESTYLEMASK, LVS_NOCOLUMNHEADER & LVS_TYPESTYLEMASK);
    ModifyStyle(0, LVS_SINGLESEL);
	horizontalExtent = 0;
    GetListCtrl().InsertColumn(0, _T(""), 0, HORIZONTAL_EXTENT_START);
	indexItemMax = -1;
	//GetListCtrl().SetColumnWidth(0, LVSCW_AUTOSIZE);

    if (dictionaryNames.GetCount() > 0)
    {
        GetDocument()->SetTitle(dictionaryNames.GetAt(0));
    }
    else
    {
        GetDocument()->SetTitle(_T("No dictionary loaded"));
    }
}


// CSmartLexiconView diagnostics

#ifdef _DEBUG
void CSmartLexiconView::AssertValid() const
{
    CListView::AssertValid();
}

void CSmartLexiconView::Dump(CDumpContext& dc) const
{
    CListView::Dump(dc);
}

CSmartLexiconDoc* CSmartLexiconView::GetDocument() const // non-debug version is inline
{
    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CSmartLexiconDoc)));
    return (CSmartLexiconDoc*)m_pDocument;
}
#endif //_DEBUG

// Implementation Functions
void CSmartLexiconView::LoadDictionaries()
{
    currentLexicon = -1;

    lexDB.LoadDictionariesTable(_T("Software\\KG\\SmartLexicon"));
    CString name, sourceFilePath, indexFilePath, lang1, lang2;
    BOOL autoload;
    int type, state;
    CLexiconObject *lexObject;
    int dictionariesCount = lexDB.GetDictionariesTableSize();
    for(int i=0; i<dictionariesCount; i++)
    {
        if (lexDB.GetDictionaryProperties(i, name, sourceFilePath, indexFilePath,
                                          lang1, lang2, type, autoload, state))
        {
            dlg->SendMessage(newDictMsg,
                             (WPARAM) &name,
                             (i & 0xFF) | ((dictionariesCount << 8) & 0xFF00));

            if (autoload)
            {
                lexObject = lexMng.CreateNewObject(type, lang1);

                lexObject->SetName(name);
                lexObject->SetSourceFileName(sourceFilePath);
                lexObject->SetSourceFilePath(sourceFilePath);
            }
            else
            {
                lexDB.UpdateDictionaryProperties(i,name,autoload,
                                                 CLexDataBaseEntry::UNLOADED);
                continue;
            }

            BOOL OK = lexObject->GetSourceFile()->Open(sourceFilePath);
            if (!OK)
            {
                lexMng.Delete(lexObject);
                lexDB.UpdateDictionaryProperties(i,name,autoload,
                                                 CLexDataBaseEntry::CORRUPT);
                continue;
            }
            lexObject->GetSourceFile()->Analyse();

            int result = lexObject->GetIndexFile()->Load(lexObject->GetSourceFile(),
                                                         indexFilePath);
            if (result!=CLexIndexFileBase::LOADING_SUCCESSFUL)
            {
                if (result == CLexIndexFileBase::LOADING_PENDING)
                {
                    lexObject->GetIndexFile()->StopLoading();
                }
                lexMng.Delete(lexObject);
                lexDB.UpdateDictionaryProperties(i,name,autoload,
                                                 CLexDataBaseEntry::CORRUPT);
                continue;
            }
            else
            {
                dictionaryNames.Add(name);
                lexDB.LoadDictionary(i,name,autoload);
            }
        }
        else
        {
            break;
        }
    }
    currentLexicon = -1;
    if (lexDB.GetDictionariesLoadedCount()>0)
    {
        int pos = lexDB.GetLoadedDictIndex(0);
        ASSERT(pos == 0);
        if (pos >= 0)
        {
            currentLexicon = 0;
            lexObject = (CLexiconObject *) lexMng.GetAt(pos);
            lexSourceFile = lexObject->GetSourceFile();
            lexIndexFile = lexObject->GetIndexFile();
        }
    }
}

int CSmartLexiconView::SearchWord(CString aWordToSearch,
                             BOOL exactMatch,
                             BOOL completeWord)
{
    CWaitCursor waitCursor;
    int count = 0;

    wordToSearch = aWordToSearch;
    GetDocument()->mWordEntryVector.clear();
    keyWordTable.clear();
    wordAppearancesVector.clear();
    GetListCtrl().DeleteAllItems();
	indexItemMax = -1;
	horizontalExtent = 0;
	GetListCtrl().SetColumnWidth(0, HORIZONTAL_EXTENT_START);
    GetListCtrl().SetItemCount(0);
    if (wordToSearch.GetLength() > 0)
    {
        if (!regExSearch)
        {
            count = lexIndexFile->FindWords(wordToSearch,
                                            &wordAppearancesVector,
                                            completeWord,
                                            exactMatch);
        }
        else
        {
#ifdef REG_EX_SUPPORT
            CString keyWord;
            try
            {
                boost::wregex regEx(wordToSearch.GetBuffer());
                int index = 0;

                keyWord = lexSourceFile->GetHeadWord(index);
                while (keyWord != _T(""))
                {
                    if (boost::regex_match(keyWord.GetBuffer(), regEx))
                    {
                        wordAppearancesVector.push_back(index);
                        count++;
                    }

                    index++;
                    keyWord = lexSourceFile->GetHeadWord(index);
                }
            }
            catch (...)
            {
            }
#endif //REG_EX_SUPPORT
        }
        vector<int>::iterator it;

        int i = 0;
		CLang *lang = lexSourceFile->GetLang();
		CString tempLocale;
		lang->GetLocale(tempLocale);
		_wsetlocale(LC_ALL, tempLocale);
		for(it = wordAppearancesVector.begin(); it < wordAppearancesVector.end(); it++)
        {
            int entryLine = *it;
            CString entryWord = lexSourceFile->GetHeadWord(*it, wordToSearch);

			if (entryWord!= _T(""))
            {
                wstring wstr(entryWord.GetBuffer());
				
				//keyWordTable.insert(pair<CString, int>(entryWord, entryLine));
				keyWordTable.insert(pair<wstring, int>(wstr, entryLine));
            }
        }
		_wsetlocale(LC_ALL, L"C");

        GetListCtrl().SetItemCount((int) keyWordTable.size());	
		//GetListCtrl().SetColumnWidth(0, LVSCW_AUTOSIZE);

        if (keyWordTable.size() > 0)
        {
            GetListCtrl().SetItemState(0,
                                       LVIS_SELECTED,
                                       LVIS_SELECTED);
        }
    }

    return (int) keyWordTable.size();
}

void CSmartLexiconView::UpdateDictionariesList()
{
    CString name, sourceFilePath, indexFilePath, lang1, lang2;
    BOOL autoload;
    int type, state;
    CLexiconObject *lexObject;

    dictionaryNames.RemoveAll();

    for(int i=0; i<lexDB.GetDictionariesTableSize(); i++)
    {
        if (lexDB.GetDictionaryProperties(i, name, sourceFilePath, indexFilePath,
                                          lang1, lang2, type, autoload, state))
        {
            if (state == CLexDataBaseEntry::LOADED)
                dictionaryNames.Add(name);
        }
        else
        {
            break;
        }
    }

    if (lexDB.GetDictionariesLoadedCount()>0)
    {
        currentLexicon = 0;
        int pos = lexDB.GetLoadedDictIndex(currentLexicon);
        if (pos >= 0)
        {
            lexObject = (CLexiconObject *) lexMng.GetAt(pos);
            lexSourceFile = lexObject->GetSourceFile();
            lexIndexFile = lexObject->GetIndexFile();
            GetDocument()->SetTitle(dictionaryNames.GetAt(0));
        }
        else
        {
            currentLexicon = -1;
            GetDocument()->mWordEntryVector.clear();
            GetDocument()->SetTitle(_T("No dictionary loaded"));
        }
    }
    else
    {
        currentLexicon = - 1;
        GetDocument()->mWordEntryVector.clear();
        GetDocument()->SetTitle(_T("No dictionary loaded"));
    }
    GetDocument()->UpdateAllViews(this);
}

int CSmartLexiconView::GetDictionariesCount()
{
    return (int) dictionaryNames.GetCount();
}

BOOL CSmartLexiconView::GetDictionaryName(int index, CString& name)
{
    if (index<0 || index>= GetDictionariesCount())
        return FALSE;

    name = dictionaryNames.GetAt(index);
    return TRUE;
}

void CSmartLexiconView::ChangeDictionary(int index)
{
    CLexiconObject *lexObj;
    int count = lexDB.GetDictionariesLoadedCount();

    if (count > 0 &&
        index >=0 &&
        index < count)
    {
        currentLexicon = index;
        int pos = lexDB.GetLoadedDictIndex(currentLexicon);
        lexObj = lexMng.GetAt(pos);
        lexSourceFile = lexObj->GetSourceFile();
        lexIndexFile = lexObj->GetIndexFile();

        GetDocument()->SetTitle(dictionaryNames.GetAt(index));
    }
}

// CSmartLexiconView message handlers

int CSmartLexiconView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CListView::OnCreate(lpCreateStruct) == -1)
        return -1;
    GetDocument()->mSmartLexiconView = this;
    return 0;
}

void CSmartLexiconView::OnLvnItemchanged(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
    *pResult = 0;

    int itemIndex = pNMLV->iItem;

    if ((pNMLV->uNewState & LVIS_SELECTED) == LVIS_SELECTED)
    {
        vector<WordEntry>::iterator it;

        MultimapKeyWord::iterator mm_it = keyWordTable.begin();
        for(int i=0; i<itemIndex; i++)
            mm_it++;
        lexSourceFile->GetWordEntryAt(mm_it->second,
                                      GetDocument()->mWordEntryVector);
        GetDocument()->UpdateAllViews(this);
    }
}

void CSmartLexiconView::SetListBoxExtent(CString &newStr)
{
	CDC* pDC = GetListCtrl().GetDC();
	CFont* pFont = GetListCtrl().GetFont();

	// Select the listbox font, save the old font
	CFont* pOldFont = pDC->SelectObject(pFont);

	// Get size of text
	CSize sz =  pDC->GetTextExtent(newStr);

	if (horizontalBorder == 0)
	{
		TEXTMETRIC tm;
		
		// Get the text metrics for avg char width
		pDC->GetTextMetrics(&tm);
		// Add the avg width to prevent clipping
		horizontalBorder = 5 + tm.tmMaxCharWidth;
	}

	// Select the old font back into the DC
	pDC->SelectObject(pOldFont);
	GetListCtrl().ReleaseDC(pDC);

	if (sz.cx > horizontalExtent)
	{
		horizontalExtent = sz.cx;
		GetListCtrl().SetColumnWidth(0, horizontalExtent + horizontalBorder);
	}
}

void CSmartLexiconView::OnLvnGetdispinfo(NMHDR *pNMHDR, LRESULT *pResult)
{
    NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
    *pResult = 0;

    if (wordToSearch == _T(""))
        return;

    LV_ITEM* pItem= &(pDispInfo)->item;

    int itemIndex = pItem->iItem;

    if (pItem->mask & LVIF_TEXT) //valid text buffer?
    {
        CString str;
        MultimapKeyWord::iterator mm_it = keyWordTable.begin();
        for(int i=0; i<itemIndex; i++)
            mm_it++;
        str = lexSourceFile->GetHeadWordLabel(mm_it->second,
                                              wordToSearch);
        if (pItem->iSubItem == 0)
        {
            lstrcpy(pItem->pszText, str);

			if (itemIndex > indexItemMax)
			{
				indexItemMax = itemIndex;
				SetListBoxExtent(str);
			}
        }
    }
}

void CSmartLexiconView::OnLexNew()
{
    CLexiconObject *lexObj;
    CLoadingDlg loadingDlg;
    BOOL OK;
    CString name, path, indexFilePath, lang1, lang2;
    BOOL autoload;
    int type;

    loadingDlg.Initialise(&lexDB, &lexMng);
    OK = (loadingDlg.DoModal() == IDOK);
    lexObj = loadingDlg.GetLexObject();
    loadingDlg.GetProperties(lang1, lang2, autoload, type);

    if (OK && lexObj != NULL)
    {
        lexObj->GetName(name);
        lexObj->GetSourceFilePath(path);
        lexObj->GetIndexFile()->GetName(indexFilePath);

        int lex = (int) dictionaryNames.Add(name);
        if (lex >= 0)
        {
            int lexMngCount = lexMng.GetCount();

            currentLexicon = lex;
            ASSERT(currentLexicon == lexMngCount - 1);
            ASSERT(currentLexicon == lexDB.GetDictionariesLoadedCount());
            lexDB.AddDictionary(name, path, indexFilePath,
                                lang1, lang2, type,
                                CLexDataBaseEntry::LOADED,
                                autoload);
            GetDocument()->SetTitle(dictionaryNames.GetAt(lex));
        }
        else
        {
            lexMng.Delete(lexObj);
            lexObj = NULL;
            OK = FALSE;
        }
    }
    if (lexObj)
    {
        lexSourceFile = lexObj->GetSourceFile();
        lexIndexFile = lexObj->GetIndexFile();
    }
}

void CSmartLexiconView::OnLexOpen()
{
    CSettingsDlg settingsDlg;

    GetListCtrl().SetItemCount(0);
    settingsDlg.SetLexDB(&lexDB, &lexMng);

    //int i;
    //TRACE("BEFORE\n");
    //for(i=0; i<lexDB.GetDictionariesLoadedCount(); i++)
    //{
    //  int pos = lexDB.GetLoadedDictIndex(i);
    //  CLexiconObject *obj = lexMng.GetAt(pos);
    //  TRACE3("%d: %X %X\n", pos, obj->GetSourceFile(), obj->GetIndexFile());
    //}
    settingsDlg.DoModal();
    //TRACE("AFTER\n");
    //for(i=0; i<lexDB.GetDictionariesLoadedCount(); i++)
    //{
    //  int pos = lexDB.GetLoadedDictIndex(i);
    //  CLexiconObject *obj = lexMng.GetAt(pos);
    //  TRACE3("%d: %X %X\n", pos, obj->GetSourceFile(), obj->GetIndexFile());
    //}
    UpdateDictionariesList();
}


#ifdef _TEST

#include "LangSpanish.h"
#include "LangItalian.h"

void CSmartLexiconView::LexEngineTest()
{
    //CLexDataBaseStoreTest lexDBStoreTest;

    //lexDBStoreTest.Test1();
    //lexDBStoreTest.Test2();
    //lexDBStoreTest.Test3();

    //CLexDataBaseTest lexDBTest;

    //lexDBTest.Test1();
    //lexDBTest.Test2();
    //lexDBTest.Test3();
    //lexDBTest.Test4();
    //lexDBTest.Test5();
    //lexDBTest.Test6();
    //lexDBTest.Test7();
    //lexDBTest.Test8();
    //lexDBTest.Test9();
    //lexDBTest.Test10();

    //CLangSpanishTest::TestAll();
    //CLangItalianTest::TestAll();
}
#endif

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Software Developer (Senior) Self employed
Greece Greece
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions