⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spellcheckerdialog.cpp

📁 SpellChecker平写检测程序原代码,希望大家喜欢,他非常好用
💻 CPP
字号:
/*
This file is part of SpellChecker Plugin for Notepad++
Copyright (C)2007 Jens Lorenz <jens.plugin.npp@gmx.de>

This program 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.

This program 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 this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/


#include "SpellCheckerDialog.h"
#include "resource.h"
#include "Scintilla.h"
#include "resource.h"


HANDLE	hThread				= NULL;
HANDLE	hEvent[EID_MAX]	    = {NULL};


DWORD WINAPI GUIThread(LPVOID lpParam)
{
    RTHR                bRun            = SC_NEXT;
    DWORD               dwWaitResult    = EID_MAX;
	SpellCheckerDialog*	dlg             = (SpellCheckerDialog*)lpParam;

	bRun = dlg->NotifyEvent(EID_MAX);

	while (bRun)
	{
		dwWaitResult = ::WaitForMultipleObjects(EID_MAX, hEvent, FALSE, INFINITE);

		if (dwWaitResult == EID_CANCEL)
		{
			bRun = SC_STOP;
		}
		else
		{
			bRun = dlg->NotifyEvent(dwWaitResult);
		}
	}

	::EndDialog(dlg->getHSelf(), TRUE);
	return 0;
}


SpellCheckerDialog::SpellCheckerDialog(void)
{
    _bUpdateNewEdit     = TRUE;
	_bAspellIsWorking   = FALSE;
}

SpellCheckerDialog::~SpellCheckerDialog(void)
{
}


void SpellCheckerDialog::init(HINSTANCE hInst, NppData nppData, tSCProp *prop)
{
	_nppData = nppData;
	StaticDialog::init(hInst, nppData._nppHandle);

	_pSCProp = prop;
}


UINT SpellCheckerDialog::doDialog(void)
{
	::ZeroMemory(&_aspToken, sizeof(AspellToken));
	_iStartLine			= 0;
	_iCurLine			= 0;
	_iLastLine			= 0;
	_iEndPos			= 0;
	_iLineStartPos		= 0;
	_iLineEndPos		= 0;
	_uSizeLineBuf		= 0;
	_pszLine			= NULL;

	return ::DialogBoxParam(_hInst, MAKEINTRESOURCE(IDD_SPELLCHECKER_DLG), _hParent, (DLGPROC)dlgProc, (LPARAM)this);
}


BOOL CALLBACK SpellCheckerDialog::run_dlgProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
	switch (Message)
	{
		case WM_INITDIALOG:
		{
			_hStaticWord	= ::GetDlgItem(_hSelf, IDC_STATIC_WORD);
            _hNewEdit		= ::GetDlgItem(_hSelf, IDC_EDIT_REPLACE);
            _hSuggList		= ::GetDlgItem(_hSelf, IDC_LIST_SUGGESTION);
            _hLang			= ::GetDlgItem(_hSelf, IDC_COMBO_LANG);

			InitialDialog();
			break;
		}
		case WM_COMMAND:
		{
            if (HIWORD(wParam) == BN_CLICKED)
            {
			    switch (LOWORD(wParam))
			    {
                    case IDC_BUTTON_REPLACE:
                    {
                        ::SetEvent(hEvent[EID_REPLACE]);
                        break;
                    }
                    case IDC_BUTTON_LERN:
                    {
                        ::SetEvent(hEvent[EID_LERN]);
                        break;
                    }
                    case IDC_BUTTON_IGNORE:
                    {
                        ::SetEvent(hEvent[EID_IGNORE]);
                        break;
                    }
				    case IDCANCEL:
				    {
					    ::SetEvent(hEvent[EID_CANCEL]);
					    break;
				    }
				    default:
					    break;
			    }
            }

            if (((HWND)lParam == _hNewEdit) && (HIWORD(wParam) == EN_CHANGE) && (_bUpdateNewEdit == TRUE))
            {
                /* get typed word */
                CheckWord(false);
                return TRUE;
            }

			if (((HWND)lParam == _hLang) && (HIWORD(wParam) == CBN_SELCHANGE))
			{
                ::SetWindowText(_hNewEdit, _szWord);
                ::SetEvent(hEvent[EID_CHANGE_LANG]);
				return TRUE;
			}

            if ((HWND)lParam == _hSuggList)
            {
                if (HIWORD(wParam) == LBN_SELCHANGE)
                {
		            onSelSugg();
                }
                else if (HIWORD(wParam) == LBN_DBLCLK)
                {
                    /* replace text */
                    ::SetEvent(hEvent[EID_REPLACE]);
                }
            }
			break;
		}
        case WM_CLOSE:
        {
            ::SetEvent(hEvent[EID_CANCEL]);
            break;
        }
		case WM_DESTROY:
		{
			delete_aspell_document_checker(_aspChecker);
			delete_aspell_speller(_aspSpeller);

			if (_pszLine != NULL)
				delete [] _pszLine;

			if (_bAspellIsWorking  == TRUE)
			{
				DestroyThreadResources();
				_bAspellIsWorking = FALSE;
			}
			break;
		}
		default:
			break;
	}

	return FALSE;
}


RTHR SpellCheckerDialog::NotifyEvent(DWORD event)
{

	switch (event)
    {
        case EID_REPLACE :
        {
			TCHAR   pszReplaceWord[MAX_PATH];

			/* get current word and replace */
			::GetWindowText(_hNewEdit, pszReplaceWord, MAX_PATH);
			ScintillaMsg(SCI_TARGETFROMSELECTION);
			ScintillaMsg(SCI_REPLACETARGET, strlen(pszReplaceWord), (LPARAM)pszReplaceWord);

			_iLineDiff += strlen(pszReplaceWord) - strlen(_szWord);
			_iEndPos   += _iLineDiff;
            break;
        }
        case EID_LERN :
        {
			TCHAR   pszLernWord[MAX_PATH];

			/* lern word */
			::GetWindowText(_hNewEdit, pszLernWord, MAX_PATH);
			aspell_speller_add_to_personal(_aspSpeller, pszLernWord, strlen(pszLernWord));
            aspell_speller_save_all_word_lists(_aspSpeller);
            if (aspell_speller_error(_aspSpeller) != 0)
            {
		        TCHAR	szErrorMsg[MAX_PATH];
		        sprintf(szErrorMsg, _T("Error: %s"), aspell_speller_error_message(_aspSpeller));
		        ::MessageBox(_hSelf, szErrorMsg, _T("Spell-Checker"), MB_OK);
            }
            break;
        }
        case EID_IGNORE :
        {
            break;
        }
        case EID_CHANGE_LANG :
        {
			UpdateLanguage();

			/* calculate offset on begin */
			_iLineStartPos	+= _aspToken.offset + _iLineDiff;
			UpdateCheckerNextMisspelling();
            break;
        }
        default :
            break;
    }

	return NextMisspelling();
}


void SpellCheckerDialog::onSelSugg(void)
{
    /* get selected text and set in edit field */
    INT iSel    = (INT)::SendMessage(_hSuggList, LB_GETCURSEL, 0, 0);

	if (iSel != LB_ERR)
	{
		LPTSTR  pszSel  = new TCHAR[::SendMessage(_hSuggList, LB_GETTEXTLEN, iSel, 0)+1];
		::SendMessage(_hSuggList, LB_GETTEXT, iSel, (LPARAM)pszSel);

		/* avoid new test of word */
		_bUpdateNewEdit = FALSE;
		::SetWindowText(_hNewEdit, pszSel);
		_bUpdateNewEdit = TRUE;
		delete [] pszSel;
	}
}


void SpellCheckerDialog::InitialDialog(void)
{
    ::SendMessage(_hParent, WM_MODELESSDIALOG, MODELESSDIALOGADD, (LPARAM)_hSelf);
	goToCenter();

	/* set current focused scintilla as used window */
	UpdateHSCI();

	/* when is in rectangle mode, do not check */
	if ((BOOL)ScintillaMsg(SCI_SELECTIONISRECTANGLE) == TRUE)
	{
		::MessageBox(_hSelf, _T("Checking of misspelling is not possible in rectanlge mode!"), _T("Spell-Checker"), MB_OK);
	}

	/* fill out combo box to set language */
	if (FillLanguages() == TRUE)
	{
		/* set default language */
		if (_pSCProp->szLang[0] == '\0')
		{
			::SendMessage(_hLang, CB_SETCURSEL, 0, 0);
		}
		else
		{
			LRESULT	lResult	= ::SendMessage(_hLang, CB_FINDSTRINGEXACT, -1, (LPARAM)_pSCProp->szLang);
			if (lResult >= 0) ::SendMessage(_hLang, CB_SETCURSEL, lResult, 0);
		}

		/* Note: Creates aspell config and speller */
		UpdateLanguage();

		if (_bAspellIsWorking == TRUE)
		{
			CreateThreadResources();
		}
	}
	else
	{
		howToDlg();
		::EndDialog(_hSelf, TRUE);
	}
}


BOOL SpellCheckerDialog::FillLanguages(void)
{
	AspellConfig*				aspCfg;
	AspellDictInfoList*			dlist;	AspellDictInfoEnumeration*	dels;	const AspellDictInfo*		entry;	aspCfg = new_aspell_config();	/* the returned pointer should _not_ need to be deleted */	dlist = get_aspell_dict_info_list(aspCfg);	/* config is no longer needed */
	delete_aspell_config(aspCfg);	dels = aspell_dict_info_list_elements(dlist);

	if (aspell_dict_info_enumeration_at_end(dels) == TRUE)
	{
		delete_aspell_dict_info_enumeration(dels);
		return FALSE;
	}	while ((entry = aspell_dict_info_enumeration_next(dels)) != 0) 	{		::SendMessage(_hLang, CB_ADDSTRING, strlen(entry->name), (LPARAM)entry->name);	}	delete_aspell_dict_info_enumeration(dels);
	return TRUE;
}


void SpellCheckerDialog::UpdateLanguage(void)
{
	/* get current selected language */
	INT		curSel		= (INT)::SendMessage(_hLang, CB_GETCURSEL, 0, 0);

	if (curSel != CB_ERR)
	{
		if (MAX_OF_LANG > ::SendMessage(_hLang, CB_GETLBTEXTLEN, curSel, 0))
		{
			::SendMessage(_hLang, CB_GETLBTEXT, curSel, (LPARAM)_pSCProp->szLang);
		}
	}

	if (_bAspellIsWorking == TRUE)
	{
		delete_aspell_document_checker(_aspChecker);
		delete_aspell_speller(_aspSpeller);
		_bAspellIsWorking = FALSE;
	}

	/* configure aspell */
	AspellCanHaveError*		aspRet;
	AspellConfig*			aspCfg;

	aspCfg = new_aspell_config();
	aspell_config_replace(aspCfg, "lang", _pSCProp->szLang);
	aspRet = new_aspell_speller(aspCfg);
	delete_aspell_config(aspCfg);

	if (aspell_error(aspRet) != 0)
	{
		TCHAR	szErrorMsg[MAX_PATH];
		sprintf(szErrorMsg, _T("Error: %s"), aspell_error_message(aspRet));
		::MessageBox(_hSelf, szErrorMsg, _T("Spell-Checker"), MB_OK);
		delete_aspell_can_have_error(aspRet);
		return;
	}

	/* create speller */
	_aspSpeller = to_aspell_speller(aspRet);

	/* create checker */
	aspRet = new_aspell_document_checker(_aspSpeller);

	if (aspell_error(aspRet) != 0)
	{
		TCHAR	szErrorMsg[MAX_PATH];
		sprintf(szErrorMsg, _T("Error: %s"), aspell_error_message(aspRet));
		::MessageBox(_hSelf, szErrorMsg, _T("Spell-Checker"), MB_OK);
	    return;
	}
	_aspChecker = to_aspell_document_checker(aspRet);

	_bAspellIsWorking	= TRUE;
}


void SpellCheckerDialog::FillSuggList(const AspellWordList *wl) 
{
	LVITEM	item	= {0};

	if (wl == 0)
	{
		TCHAR	szErrorMsg[MAX_PATH];
		sprintf(szErrorMsg, _T("Error: %s"), aspell_speller_error_message(_aspSpeller));
		::MessageBox(_hSelf, szErrorMsg, _T("Spell-Checker"), MB_OK);
	}
	else
	{
		AspellStringEnumeration * els = aspell_word_list_elements(wl);
		const char * pWord;
		while ((pWord = aspell_string_enumeration_next(els)) != 0)
		{
			::SendMessage(_hSuggList, LB_ADDSTRING, 0, (LPARAM)pWord);
		}
	}
}


RTHR SpellCheckerDialog::NextMisspelling(void)
{
	/* calculate the marked line on first start */
	if (_pszLine == NULL)
	{
		_iLineStartPos	= (INT)ScintillaMsg(SCI_GETSELECTIONSTART);
		_iEndPos		= (INT)ScintillaMsg(SCI_GETSELECTIONEND);

		if (_iLineStartPos == _iEndPos)
		{
			/* spell check over the complete document */

			/* get line positions */
			_iLineStartPos	= 0;
			_iEndPos		= (INT)ScintillaMsg(SCI_GETTEXTLENGTH);

			/* get line infos */
			_iCurLine		= 1;
			_iStartLine		= _iCurLine;
			_iLastLine		= (INT)ScintillaMsg(SCI_GETLINECOUNT);
		}
		else
		{
			/* get line infos */
			_iCurLine		= (INT)ScintillaMsg(SCI_LINEFROMPOSITION, _iLineStartPos);
			_iStartLine		= _iCurLine;
			_iLastLine		= (INT)ScintillaMsg(SCI_LINEFROMPOSITION, _iEndPos);
		}
	}

	if (_aspToken.len != 0)
	{
		/* find next misspell */
		_aspToken = aspell_document_checker_next_misspelling(_aspChecker);
	}

	/* get line end position */
	while ((_iCurLine <= _iLastLine) && (_aspToken.len == 0))
	{
		/* get line length */
		if (_iStartLine == _iLastLine)
		{
			_iLineEndPos	= _iEndPos;
		}
		else if (_iCurLine == _iStartLine)
		{
			_iLineEndPos	= (INT)ScintillaMsg(SCI_GETLINEENDPOSITION, _iCurLine);
		}
		else if (_iCurLine == _iLastLine)
		{
			_iLineStartPos	= (INT)ScintillaMsg(SCI_POSITIONFROMLINE, _iCurLine);
			_iLineEndPos	= _iEndPos;
		}
		else
		{
			_iLineStartPos	= (INT)ScintillaMsg(SCI_POSITIONFROMLINE, _iCurLine);
			_iLineEndPos	= (INT)ScintillaMsg(SCI_GETLINEENDPOSITION, _iCurLine);
		}
		_iCurLine++;

		/* calculate buffer size */
		if (_uSizeLineBuf < (UINT)(_iLineEndPos-_iLineStartPos+1))
		{
			if (_pszLine != NULL) delete [] _pszLine;
			_uSizeLineBuf = _iLineEndPos-_iLineStartPos+1;
			_pszLine = (LPTSTR) new TCHAR[_uSizeLineBuf];
		}

		/* get line for test */
		UpdateCheckerNextMisspelling();

		/* find next misspell */
		_aspToken = aspell_document_checker_next_misspelling(_aspChecker);
	}

	if (_aspToken.len != 0)
	{
		/* select word */
		INT	iPos	= _iLineStartPos + _aspToken.offset + _iLineDiff;
		ScintillaMsg(SCI_SETSEL, iPos, iPos + _aspToken.len);

		/* get word */
		ScintillaGetText(_szWord, iPos, iPos + _aspToken.len);

		/* set text and make suggestions */
		::SetWindowText(_hStaticWord, _szWord);
		::SetWindowText(_hNewEdit, _szWord);
	}

	if ((_iCurLine > _iLastLine) && (_aspToken.len == 0))
	{
		::MessageBox(_hSelf, _T("Done"), _T("Spell-Checker"), MB_OK);
		return SC_STOP;
	}
	return SC_NEXT;
}


RTHR SpellCheckerDialog::CheckWord(bool showAspellError)
{
    TCHAR   pszReplaceWord[MAX_PATH];

    /* get current word */
    ::GetWindowText(_hNewEdit, pszReplaceWord, MAX_PATH);

    /* clear list */
	::SendMessage(_hSuggList, LB_RESETCONTENT, 0, 0);

	int error = aspell_speller_check(_aspSpeller, pszReplaceWord, -1);

	if (error == 0)
	{
		FillSuggList(aspell_speller_suggest(_aspSpeller, pszReplaceWord, -1));
	}
	else if ((error != 1) && (showAspellError))
	{
		TCHAR	szErrorMsg[MAX_PATH];
		sprintf(szErrorMsg, _T("Error: %s"), aspell_speller_error_message(_aspSpeller));
		::MessageBox(_hSelf, szErrorMsg, _T("Spell-Checker"), MB_OK);
        ::SetEvent(hEvent[EID_CANCEL]);
    }
    return SC_NEXT;
}


void SpellCheckerDialog::UpdateCheckerNextMisspelling(void)
{
	/* get line content */
	_iLineDiff	= 0;
	ScintillaGetText(_pszLine, _iLineStartPos, _iLineEndPos);

	/* First process the line */
	aspell_document_checker_process(_aspChecker, _pszLine, -1);
}


void SpellCheckerDialog::CreateThreadResources(void)
{
	DWORD	dwThreadId	= 0;

	/* create events */
	for (int i = 0; i < EID_MAX; i++)
		hEvent[i] = ::CreateEvent(NULL, FALSE, FALSE, NULL);

	/* create thread */
	hThread = ::CreateThread(NULL, 0, GUIThread, this, 0, &dwThreadId);
}


void SpellCheckerDialog::DestroyThreadResources(void)
{
	DWORD	dwThreadId	= 0;

	/* destroy thread */
    ::CloseHandle(hThread);

	/* create events */
	for (int i = 0; i < EID_MAX; i++)
		::CloseHandle(hEvent[i]);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -