//----------------------------------------------------------------------------
// ObjectWindow - OWL NExt
// Copyright 1999. Yura Bidus. All Rights reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library 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
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
//
// OVERVIEW
// ~~~~~~~~
// Syntax coloring text editor.
//----------------------------------------------------------------------------
#include <coolprj/pch.h>
#pragma hdrstop
#include <owl/template.h>
#include <owl/file.h>
#include <owl/filename.h>
#include <owl/scroller.h>
#include <owl/celarray.h>
#include <owl/glyphbtn.h>
#include <owl/uimetric.h>
#include <owl/configfl.h>
#include <owl/checkbox.h>
#include <owl/radiobut.h>
#include <owl/memcbox.h>
#include <owl/editfile.rh>
#include <coolprj/cooledit.rh>
#include <coolprj/cooledit.h>
#include <algorithm>
using namespace owl;
using namespace std;
// Scroller->AutoOrg == true
//#define USE_AUTOORG
//------------------------------------------------------------------------------
void __Trace(LPCTSTR lpszFormat, ...);
//------------------------------------------------------------------------------
inline void __NoTrace(LPCTSTR /*lpszFormat*/, ...){}
//------------------------------------------------------------------------------
#if 0
#define _TRACE __Trace
#else
#define _TRACE __NoTrace
#endif
// Line allocation granularity
#define CHAR_ALIGN 16
#define ALIGN_BUF_SIZE(size) (((size)/CHAR_ALIGN)*CHAR_ALIGN+CHAR_ALIGN);
#define TAB_CHARACTER _T('\xBB')
#define SPACE_CHARACTER _T('\xB7')
#define DEFAULT_PRINT_MARGIN 1000 // 10 millimeters
//#define SMOOTH_SCROLL_FACTOR 6
#define COOL_TIMER_DEBOUNCE 1001
static const _TCHAR crlf[] = _T("\r\n");
static const _TCHAR chTab = _T('\t');
static const _TCHAR szTab[] = _T("\t");
#ifdef WIN32
const int MSB=0x80000000;
#else
const int MSB=0x8000;
#endif
#define NULL_POS TEditPos(-1,-1)
//const int ciDigitsInLine = 5;
static const _TCHAR* streamSelectionId = _T("COOL000");
static const _TCHAR* lineSelectionId = _T("COOL001");
static const _TCHAR* columnSelection = _T("COOL002");
const int IdSelSize = 7;
static const _TCHAR* configSection = _T("SyntaxFormat");
static const _TCHAR* configBaseFont = _T("BaseFont");
static const _TCHAR* configFormatIdx = _T("FormatIdx%d");
static const _TCHAR* configOWLNExt = _T("OWL NExt");
//--------------------------------------------------------
// class TEditRange
// ~~~~~ ~~~~~~~~~~
//
void TEditRange::Normalize()
{
if(srow > erow){
std::swap(srow, erow);
std::swap(scol, ecol);
}
if(srow == erow && scol > ecol)
std::swap(scol, ecol);
}
//////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
//{{TCoolTextBuffer Implementation}}
//
TCoolTextBuffer::TCoolTextBuffer(TCrLfStyle style)
:
UndoList(0),
UndoCnt(0),
UndoSize(100),
RedoList(0),
RedoCnt(0),
RedoSize(100),
SyntaxArray(0),
Flags(bfCreateBackup),
CRLFMode(style)
{
memset(&BaseFont, 0, sizeof(BaseFont));
_tcscpy(BaseFont.lfFaceName, _T("Consolas"));
BaseFont.lfHeight = -13;
BaseFont.lfWeight = FW_NORMAL;
BaseFont.lfItalic = FALSE;
BaseFont.lfCharSet = DEFAULT_CHARSET;
BaseFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
BaseFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
BaseFont.lfQuality = DEFAULT_QUALITY;
BaseFont.lfPitchAndFamily = FIXED_PITCH;
//InsertLine(_T(""));
}
//
TCoolTextBuffer::~TCoolTextBuffer()
{
ClearUndoBuffer();
ClearRedoBuffer();
delete SyntaxArray;
}
//
void
TCoolTextBuffer::Clear(bool addempty)
{
ClearUndoBuffer();
ClearRedoBuffer();
if(addempty)
InsertLine(_T("")); // alwas first line
}
//
static int Flag2Index(uint32 flag)
{
int index = 0;
while ((flag & 1) == 0){
flag = flag >> 1;
index++;
if (index == 32)
return -1;
}
// flag = flag & 0xFFFFFFFE;
// if (flag != 0)
// return -1;
return index;
}
//-----------------------------------------------------------------------------
int
TCoolTextBuffer::GetLineWithFlag(uint32 flag)
{
int index = ::Flag2Index(flag);
if (index < 0){
CHECK(false); // Invalid flag passed in
return -1;
}
return FindLineWithFlag(flag);
}
//-----------------------------------------------------------------------------
int
TCoolTextBuffer::SetLineFlag(int line, uint32 flag, bool bSet,
bool bRemoveFromPreviousLine /*= true*/)
{
int index = ::Flag2Index(flag);
if (index < 0){
CHECK(false); // Invalid flag passed in
return -1;
}
int retval = -1;
if(line == -1){
CHECK(!bSet);
retval = line = FindLineWithFlag(flag);
if (line == -1)
return -1;
bRemoveFromPreviousLine = false;
}
uint32 oldFlags = GetLineFlags(line);
uint32 newFlags = oldFlags;
if (bSet)
newFlags = newFlags | flag;
else
newFlags = newFlags & ~flag;
if(oldFlags != newFlags){
if(bRemoveFromPreviousLine){
int prevLine = FindLineWithFlag(flag);
if (bSet){
if (prevLine >= 0){
CHECK((GetLineFlags(prevLine) & flag) != 0);
SetLineFlags(prevLine, GetLineFlags(prevLine) & ~flag);
retval = prevLine;
}
}
else{
CHECK(prevLine == line);
}
}
SetLineFlags(line, newFlags);
}
return retval;
}
//-----------------------------------------------------------------------------
bool
TCoolTextBuffer::Undo(TEditPos* newPos)
{
TUndoNode* node = UndoList;
if(!node)
return false;
UndoList = UndoList->Next;
bool retval = node->Undo(*this,newPos);
delete node;
UndoCnt--;
return retval;
}
//-----------------------------------------------------------------------------
bool
TCoolTextBuffer::Redo(TEditPos* newPos)
{
TRedoNode* node = RedoList;
if(!node)
return false;
RedoList = RedoList->Next;
bool retval = node->Redo(*this,newPos);
delete node;
RedoCnt--;
return retval;
}
//-----------------------------------------------------------------------------
void
TCoolTextBuffer::AdjustUndoSize()
{
if(UndoCnt >= UndoSize){
TUndoNode* uList = UndoList;
if(!uList || !uList->Next)
return;
while(uList->Next->Next)
uList = uList->Next;
delete uList->Next;
uList->Next = 0;
UndoCnt--;
}
}
//-----------------------------------------------------------------------------
void
TCoolTextBuffer::AdjustRedoSize()
{
if(RedoCnt >= RedoSize){
TRedoNode* rList = RedoList;
if(!rList || !rList->Next)
return;
while(rList->Next->Next)
rList = rList->Next;
delete rList->Next;
rList->Next = 0;
RedoCnt--;
}
}
//-----------------------------------------------------------------------------
bool
TCoolTextBuffer::AddUndoNode(TUndoNode* node)
{
PRECONDITION(node);
node->Next = UndoList;
UndoList = node;
UndoCnt++;
AdjustUndoSize();
return true;
}
//-----------------------------------------------------------------------------
bool
TCoolTextBuffer::AddRedoNode(TRedoNode* node)
{
PRECONDITION(node);
node->Next = RedoList;
RedoList = node;
RedoCnt++;
AdjustRedoSize();
return true;
}
//-----------------------------------------------------------------------------
void
TCoolTextBuffer::ClearUndoBuffer()
{
while(UndoList){
TUndoNode* tmp = UndoList->Next;
delete UndoList;
UndoList = tmp;
}
UndoCnt = 0;
}
//-----------------------------------------------------------------------------
void
TCoolTextBuffer::ClearRedoBuffer()
{
while(RedoList){
TRedoNode* tmp = RedoList->Next;
delete RedoList;
RedoList = tmp;
}
RedoCnt = 0;
}
//-----------------------------------------------------------------------------
bool
TCoolTextBuffer::GetUndoDescription(_TCHAR* buffer, int len, TModule* module)
{
if(UndoList)
return UndoList->GetDescription(buffer, len, module);
return LoadStringIndex(buffer, len, IDS_COOLUNDOSTRINGS, 0, _T('|'), module);
}
//-----------------------------------------------------------------------------
bool
TCoolTextBuffer::GetRedoDescription(_TCHAR* buffer, int len, TModule* module)
{
if(RedoList)
return RedoList->GetDescription(buffer, len, module);
return LoadStringIndex(buffer, len, IDS_COOLREDOSTRINGS, 0, _T('|'), module);
}
//-----------------------------------------------------------------------------
bool
TCoolTextBuffer::LoadStringIndex(_TCHAR* buffer, int len, int resId,
int index, _TCHAR delimCh, TModule* module)
{
if(!module)
module = &owl::GetGlobalModule();
TTmpBuffer<_TCHAR> __ClnObj(512);
LPTSTR ptr = __ClnObj;
if(!module->LoadString(resId, ptr, 512))
return false;
LPTSTR p = _tcschr(ptr, delimCh);
int lastIdx = 0;
bool found = false;
do{
if(p){
if(lastIdx>=index){
_TCHAR c = *p;
*p = 0;
_tcsncpy(buffer, ptr, len);
found = true;
*p = c;
break;
}
ptr = p+1;
p = _tcschr(ptr, delimCh);
lastIdx++;
}
else if(lastIdx>=index){
_tcsncpy(buffer, ptr, len);
found = _tcslen(ptr) > 0;
}
}
while(p);
buffer[len-1] = 0;
return found;
}
//-----------------------------------------------------------------------------
int
TCoolTextBuffer::FindNextBookmarkLine(int curLine)
{
bool bWrapIt = true;
uint32 flags = GetLineFlags(curLine);
if ((flags & lfBookMarks) != 0)
curLine++;
int size = GetLineCount();
for (;;){
while (curLine < size){
if ((GetLineFlags(curLine) & lfBookMarks) != 0)
return curLine;
// Keep going
curLine++;
}
// End of text reached
if (!bWrapIt)
return -1;
// Start from the beginning of text
bWrapIt = false;
curLine = 0;
}
//return -1;
}
//-----------------------------------------------------------------------------
int TCoolTextBuffer::FindPrevBookmarkLine(int curLine)
{
bool bWrapIt = true;
uint32 flags = GetLineFlags(curLine);
if((flags & lfBookMarks) != 0)
curLine--;
int size = GetLineCount();
for (;;){
while (curLine >= 0){
if ((GetLineFlags(curLine) & lfBookMarks) != 0)
return curLine;
// Keep moving up
curLine--;
}
// Beginning of text reached
if (!bWrapIt)
return -1;
// Start from the end of text
bWrapIt = false;
curLine = size - 1;
}
}
//-----------------------------------------------------------------------------
static void
SetSyntaxNode(TCoolTextBuffer::TSyntaxDescr& node,
TCoolTextBuffer::TSyntaxDescr* descr)
{
// white Space
if(descr){
node.TxColor = descr->TxColor;
node.BkColor = descr->BkColor;
node.FontIndex = descr->FontIndex;
}
}
//-----------------------------------------------------------------------------
TCoolTextBuffer::TSyntaxDescr*
TCoolTextBuffer::GetDefSyntaxDescr(int index)
{
static TSyntaxDescr array[] =
{
TSyntaxDescr(TColor::Black, TColor::White, 0), // COLORINDEX_WHITESPACE
// Normal Text
//
TSyntaxDescr(TColor::Black, TColor::White, 0), // COLORINDEX_NORMALTEXT
// Margin
//
TSyntaxDescr(TColor::Black, TColor::SysScrollbar, 0), // COLORINDEX_MARGIN
// Selected Text
//
TSyntaxDescr(TColor::Black, TColor{173, 214, 255}, 0), // COLORINDEX_SELECTION
// Syntax Check
//
TSyntaxDescr(TColor::LtRed, TColor::White, 0), // COLORINDEX_SYNTAXCHECK
// Syntax colors
//
TSyntaxDescr(TColor{16, 16, 128}, TColor::White, 0), // COLORINDEX_KEYWORD
TSyntaxDescr(TColor{0, 128, 0}, TColor::White, 0), // COLORINDEX_COMMENT
TSyntaxDescr(TColor::Black, TColor::White, 0), // COLORINDEX_NUMBER
TSyntaxDescr(TColor::Black, TColor::White, 0), // COLORINDEX_OPERATOR
TSyntaxDescr(TColor{163, 21, 21}, TColor::White, 0), // COLORINDEX_STRING
TSyntaxDescr(TColor{163, 21, 21}, TColor::White, 0), // COLORINDEX_CHARACTER
TSyntaxDescr(TColor{128, 128, 128}, TColor::White, 0), // COLORINDEX_PREPROCESSOR
TSyntaxDescr(TColor::Black, TColor::White, 0), // COLORINDEX_FUNCNAME
// Compiler/debugger colors
//
TSyntaxDescr(TColor{255, 0, 0}, TColor::White, 0), // COLORINDEX_ERROR
TSyntaxDescr(TColor::Black, TColor(255, 238, 98), 0), // COLORINDEX_EXECUTION
TSyntaxDescr(TColor::White, TColor{150, 58, 70}, 0), // COLORINDEX_BREAKPOINT
TSyntaxDescr(TColor(255, 219, 163), TColor{150, 58, 70}, 0), // COLORINDEX_INVALIDBREAK
// Expandable (custom elements are allowed)
//
TSyntaxDescr(TColor::Black, TColor::White, 0), // COLORINDEX_CUSTOM0
TSyntaxDescr(TColor::Black, TColor::White, 0), // COLORINDEX_CUSTOM1
TSyntaxDescr(TColor::Black, TColor::White, 0), // COLORINDEX_CUSTOM2
TSyntaxDescr(TColor::Black, TColor::White, 0), // COLORINDEX_CUSTOM3
TSyntaxDescr(TColor::Black, TColor::White, 0), // COLORINDEX_CUSTOM4
TSyntaxDescr(TColor::Black, TColor::White, 0), // COLORINDEX_CUSTOM5
TSyntaxDescr(TColor::Black, TColor::White, 0), // COLORINDEX_CUSTOM6
TSyntaxDescr(TColor::Black, TColor::White, 0), // COLORINDEX_CUSTOM7
TSyntaxDescr(TColor::Black, TColor::White, 0), // COLORINDEX_CUSTOM8
TSyntaxDescr(TColor::Black, TColor::White, 0), // COLORINDEX_CUSTOM9
};
return index < COUNTOF(array) ? &array[index] : 0;
}
//-----------------------------------------------------------------------------
void
TCoolTextBuffer::BuildDefSyntaxDescr()
{
if(!SyntaxArray)
SyntaxArray = new TSyntaxDescr[COLORINDEX_LAST];
for(int i = 0; i < COLORINDEX_LAST; i++)
SetSyntaxNode(SyntaxArray[i], GetDefSyntaxDescr(i));
}
//-----------------------------------------------------------------------------
void
TCoolTextBuffer::SetSyntaxDescr(int index, const TSyntaxDescr& node)
{
if(!SyntaxArray)
SyntaxArray = new TSyntaxDescr[COLORINDEX_LAST];
SyntaxArray[index] = node;
}
//-----------------------------------------------------------------------------
void
TCoolTextBuffer::SetSyntaxArray(TSyntaxDescr* array)
{
PRECONDITION(array);
delete SyntaxArray;
SyntaxArray = array;
}
//-----------------------------------------------------------------------------
void TCoolTextBuffer::SaveSyntaxDescr(TConfigFile& file)
{
PRECONDITION(SyntaxDescrExist());
TConfigFileSection section(file,configSection);
// 1. Save Font Info
section.WriteFont(configBaseFont, BaseFont);
// 2. Write color data + special flag, so WriteColor not applicable
// maybe better WriteInteger???
_TCHAR buffer[40];
for(int i = 0; i < COLORINDEX_LAST; i++){
wsprintf(buffer, configFormatIdx, i);
section.WriteData(buffer, (void*)&(SyntaxArray[i]), sizeof(SyntaxArray[i]));
}
}
//-----------------------------------------------------------------------------
void
TCoolTextBuffer::RestoreSyntaxDescr(TConfigFile& file)
{
if(!SyntaxArray)
SyntaxArray = new TSyntaxDescr[COLORINDEX_LAST];
if(!file.SectionExists(configSection))
BuildDefSyntaxDescr();
else{
TConfigFileSection section(file,configSection);
// 1. Restore Font Info
LOGFONT lf;
if(section.ReadFont(configBaseFont, lf))
SetFont(lf);
// 2. Read all Syntax format items
_TCHAR buffer[40];
TSyntaxDescr synVal;
for(int i = 0; i < COLORINDEX_LAST; i++){
wsprintf(buffer, configFormatIdx, i);
if(section.ReadData(buffer, (void*)&synVal, sizeof(synVal)))
SyntaxArray[i] = synVal;
}
}
}
//-----------------------------------------------------------------------------
//
// Similar to strstr(), but is case sensitive or insensitive, uses Windows
// string functions to work with different language drivers
//
static LPCTSTR
strstrcd(LPCTSTR str1, LPCTSTR str2, bool caseSens, uint len)
{
PRECONDITION(str1 && str2);
int len2 = static_cast<int>(_tcslen(str2));
LPTSTR p = (LPTSTR)str1;
LPCTSTR endp = str1 + len - len2 + 1;
if (caseSens)
while (p < endp) {
_TCHAR c = p[len2]; // must term p to match str2 len
p[len2] = 0; // for _tcscmp to work.
if (_tcscmp(p, str2) == 0) {
p[len2] = c;
return p;
}
p[len2] = c;
#if defined(BI_DBCS_SUPPORT) && !defined(UNICODE)
LPTSTR p2 = ::AnsiNext(p);
if (p2 <= p)
break;
p = p2;
#else
p++;
#endif
}
else
while (p < endp) {
TCHAR c = p[len2];
p[len2] = 0;
if (_tcsicmp(p, str2) == 0) {
p[len2] = c;
return p;
}
p[len2] = c;
#if defined(BI_DBCS_SUPPORT) && !defined(UNICODE)
LPTSTR p2 = ::AnsiNext(p);
if (p2 <= p)
break;
p = p2;
#else
p++;
#endif
}
return 0;
}
//-----------------------------------------------------------------------------
// Similar to strstrcd(), but searches backwards. Needs the length of str1
// to know where to start.
//
static LPCTSTR
strrstrcd(LPCTSTR str1, uint len1, LPCTSTR str2, bool caseSens)
{
PRECONDITION(str1 && str2);
int len2 = static_cast<int>(_tcslen(str2));
LPTSTR p = (LPTSTR)(str1 + len1 - len2);
#if defined(BI_DBCS_SUPPORT) && !defined(UNICODE)
if (p >= str1)
p = ::AnsiPrev(str1, p+1);
#endif
if (caseSens)
while (p >= str1) {
TCHAR c = p[len2]; // must term p to match str2 len
p[len2] = 0; // for _tcscmp to work.
if (_tcscmp(p, str2) == 0) {
p[len2] = c;
return p;
}
p[len2] = c;
#if defined(BI_DBCS_SUPPORT) && !defined(UNICODE)
LPTSTR p2 = ::AnsiPrev(str1, p);
if (p2 >= p)
break;
p = p2;
#else
p--;
#endif
}
else
while (p >= str1) {
TCHAR c = p[len2];
p[len2] = 0;
if (_tcsicmp(p, str2) == 0) {
p[len2] = c;
return p;
}
p[len2] = c;
#if defined(BI_DBCS_SUPPORT) && !defined(UNICODE)
LPTSTR p2 = ::AnsiPrev(str1, p);
if (p2 >= p)
break;
p = p2;
#else
p--;
#endif
}
return 0;
}
//-----------------------------------------------------------------------------
TEditPos
TCoolTextBuffer::Search(const TEditRange& _searchRange, LPCTSTR text,
bool caseSensitive, bool wholeWord, bool up)
{
if (!text || !text[0])
return TEditPos();
TEditRange searchRange(_searchRange);
if(!searchRange.Valid()){
// if not valid -> all file
searchRange.scol = 0;
searchRange.srow = 0;
searchRange.erow = GetLineCount()-1;
searchRange.ecol = GetLineLength(searchRange.srow);
}
int textLen = static_cast<int>(_tcslen(text));
// Lock the text buffer to get the pointer, and search thru it for the text
//
LPCTSTR pos = 0;
int lineIndex = up ? searchRange.erow : searchRange.srow;
int posIndex = searchRange.scol;
LPTSTR buffer = GetLineText(lineIndex);
uint bufLen = GetLineLength(lineIndex);
while(true){
if(up){
if(posIndex < searchRange.srow){
lineIndex--;
if(lineIndex < searchRange.srow)
break;
buffer = GetLineText(lineIndex);
bufLen = posIndex = GetLineLength(lineIndex);
}
pos = strrstrcd(buffer+posIndex, posIndex, text, caseSensitive);
}
else{
if(posIndex > (int)bufLen){
lineIndex++;
if(lineIndex>=GetLineCount() || lineIndex>=searchRange.erow)
break;
buffer = GetLineText(lineIndex);
bufLen = GetLineLength(lineIndex);
posIndex = 0;
}
pos = strstrcd(buffer+posIndex, text, caseSensitive, bufLen-posIndex);
}
// If whole-word matching is enabled and we have a match so far, then make
// sure the match is on word boundaries.
//
if (wholeWord && pos){
#if defined(BI_DBCS_SUPPORT)
LPTSTR prevPos;
if (pos > buffer)
prevPos = ::AnsiPrev(buffer, pos);
if (pos > buffer && _istalnum((_TCHAR)*prevPos) || // Match is in preceding word
textLen < _tcslen(pos) && _istalnum((uint)pos[textLen])) {
if(up)
posIndex = (uint)(prevPos - buffer) + _tcslen(text);
else
posIndex = (uint)(::AnsiNext(pos) - buffer);
continue; // Skip this match and keep searching
}
#else
if ((pos > buffer && _istalnum(pos[-1])) || // Match is in preceding word
(textLen < static_cast<int>(_tcslen(pos)) && _istalnum(pos[textLen])))
{
posIndex = (uint)(pos-buffer) + !up;
continue; // Skip this match and keep searching
}
#endif
}
if(pos)
break;
else
posIndex = up ? -1 : GetLineLength(lineIndex)+1;
}
// If we've got a match, select that text, cleanup & return.
//
if(pos)
return TEditPos(static_cast<int>(pos - buffer), lineIndex);
return TEditPos();
}
//-----------------------------------------------------------------------------
//
//
// class TCoolTextBuffer::TLineInfo
// ~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
TCoolTextBuffer::TLineInfo::TLineInfo(LPCTSTR text, int len/* = -1*/)
:
Text(0),
Length(0),
MaxChar(0),
Flags(0)
{
SetText(text, len);
}
//-----------------------------------------------------------------------------
TCoolTextBuffer::TLineInfo::~TLineInfo()
{
delete [] Text;
}
//-----------------------------------------------------------------------------
void TCoolTextBuffer::TLineInfo::SetText(LPCTSTR text, int len)
{
if(len == -1){
if (!text)
Length = 0;
else
Length = static_cast<int>(_tcslen(text));
}
else
Length = len;
int maxChar = ALIGN_BUF_SIZE(Length);
CHECK(maxChar >= Length);
if (maxChar > MaxChar){
delete[] Text;
MaxChar = maxChar;
Text = new _TCHAR[MaxChar+1];
CHECK(Text);
}
if (Length > 0)
memcpy(Text, text, sizeof(_TCHAR) * Length);
}
//-----------------------------------------------------------------------------
bool
TCoolTextBuffer::TLineInfo::Append(LPCTSTR text, int len /*= -1*/)
{
if (len == -1){
if (text == NULL)
return false;
len = static_cast<int>(_tcslen(text));
}
if (len == 0)
return false;
int bufNeeded = Length + len;
if (bufNeeded > MaxChar){
MaxChar = ALIGN_BUF_SIZE(bufNeeded);
CHECK(MaxChar >= Length + len);
TCHAR *newBuf = new TCHAR[MaxChar];
if (Length > 0)
memcpy(newBuf, Text, sizeof(TCHAR) * Length);
delete[] Text;
Text = newBuf;
}
memcpy(Text + Length, text, sizeof(TCHAR) * len);
Length += len;
CHECK(Length <= MaxChar);
return true;
}
//-----------------------------------------------------------------------------
void
TCoolFileBuffer::InsertLine(LPCTSTR text, int len /*= -1*/, int pos /*= -1*/)
{
TLineInfo* li = new TLineInfo(text, len);
if (pos == -1)
LineArray.Add(li);
else
LineArray.AddAt(li, pos);
#ifdef __TRACE
int lines = static_cast<int>(LineArray.Size());
if (lines % 5000 == 0)
TRACE("TCoolFileBuffer::InsertLine(): " << lines << " lines loaded!");
#endif
}
//-----------------------------------------------------------------------------
bool
TCoolFileBuffer::AppendText(int index, LPCTSTR text, int len /*= -1*/)
{
PRECONDITION(index >=0 && index < (int)LineArray.Size());
return LineArray[index]->Append(text, len);
}
//-----------------------------------------------------------------------------
void
TCoolFileBuffer::Clear(bool addempty)
{
// Free text
LineArray.Flush(true);
Inherited::Clear(addempty);
}
//-----------------------------------------------------------------------------
static const _TCHAR* crlfs[] =
{
_T("\x0d\x0a"), // DOS/Windows style
_T("\x0a"), // UNIX style
_T("\x0a") // Macintosh style
};
//-----------------------------------------------------------------------------
bool
TCoolFileBuffer::Load(LPCTSTR filename, TCrLfStyle style)
{
TFile file(filename);
if(file.IsOpen())
return Load(file, style);
return false;
}
//-----------------------------------------------------------------------------
bool
TCoolFileBuffer::Load(TFile& file, TCrLfStyle style /*= clStyleAutomatic*/)
{
int curMax = 256;
TAPointer<_TCHAR> __ClnObj(new TCHAR[curMax]);
_TCHAR* lineBuf = __ClnObj;
int curLength = 0;
const uint32 bufSize = 32768L;
#if defined(_DEBUG) // && (_DEBUG > 0)
TAPointer<_TCHAR> __ClnObj1(new _TCHAR[bufSize]);
_TCHAR* pcBuf = (_TCHAR*)__ClnObj1;
#else
TTmpBuffer<_TCHAR> __tmpBuffer(bufSize);
_TCHAR* pcBuf = (_TCHAR*)__tmpBuffer;
#endif
uint32 curSize;
if((curSize = file.Read(pcBuf, bufSize*sizeof(_TCHAR))) == TFILE_ERROR)
return false;
// Free all data if file opened and readable
LineArray.Flush(true);
ClearUndoBuffer();
ClearRedoBuffer();
//
if (style == clStyleAutomatic){
// Try to determine current CRLF mode
int i = 0;
for(; i < (int)curSize; i++){
if(pcBuf[i] == _T('\x0a') || pcBuf[i] == _T('\x0d'))
break;
}
if (i == (int)curSize){
// By default (or in the case of empty file), set DOS style
style = clStyleDos;
}
else{
// Otherwise, analyse the first occurance of line-feed character
if(pcBuf[i] == _T('\x0a'))
style = clStyleUnix;
else{
if (i < int(curSize-1) && pcBuf[i+1] == _T('\x0a'))
style = clStyleDos;
else
style = clStyleMac;
}
}
}
CHECK(style >= clStyleDos && style <= clStyleMac);
CRLFMode = style;
const _TCHAR* crlf = crlfs[style];
//LineArray.Grow(4096);
uint32 bufPtr = 0;
int crlfPtr = 0;
USES_CONVERSION;
while (bufPtr < curSize){
int c = pcBuf[bufPtr];
bufPtr++;
if (bufPtr == curSize && curSize == bufSize){
if((curSize = file.Read(pcBuf, bufSize*sizeof(_TCHAR))) == TFILE_ERROR){
if(GetLineCount()==0)
InsertLine(_T("")); // always one line
return false;
}
bufPtr = 0;
}
lineBuf[curLength] = (_TCHAR) c;
curLength++;
if(curLength == curMax){
// Reallocate line buffer
curMax += 256;
_TCHAR* newBuf = new _TCHAR[curMax];
memcpy(newBuf, lineBuf, curLength * sizeof(_TCHAR));
lineBuf = newBuf;
__ClnObj = lineBuf;
}
if(crlf[crlfPtr] == (_TCHAR)c){
crlfPtr ++;
if (crlf[crlfPtr] == 0){
lineBuf[curLength - crlfPtr] = 0;
InsertLine(lineBuf,curLength - crlfPtr);
curLength = 0;
crlfPtr = 0;
}
}
else
crlfPtr = 0;
}
lineBuf[curLength] = 0;
InsertLine(lineBuf, curLength);
CHECK(LineArray.Size() > 0); // At least one empty line must be present
EnableReadOnly(false);
TFileStatus status;
if(file.GetStatus(status) && (status.attribute&TFile::RdOnly) !=0)
EnableReadOnly(true);
SetDirty(false);
CHECK(GetLineCount());
return true;
}
//-----------------------------------------------------------------------------
bool
TCoolFileBuffer::Save(LPCTSTR filename, TCrLfStyle style, bool clearDirty)
{
// save to tmp file and create backup
TFileName savename(filename);
TFileName tmpname(TFileName::TempFile);
TFile file;
if(file.Open(tmpname.CanonicalStr(), TFile::WriteOnly | TFile::PermExclusive | TFile::CreateAlways)){
if(Save(file, style, clearDirty)){
if((Flags&bfCreateBackup)!=0 && savename.Exists()){
TFileName bakname(savename);
//<Jogy
TFileName origname(savename);
//Jogy>
tstring backupExt = bakname.GetParts(TFileName::Ext);
//<Jogy
if (backupExt.length() < 2)
backupExt = _T("~");
else
//Jogy>
backupExt[1] = _T('~');
bakname.SetPart(TFileName::Ext, backupExt);
savename.Move(bakname, TFileName::ReplaceExisting|
TFileName::CopyAllowed);
//<Jogy
savename = origname;
//Jogy>
}
//<Jogy
file.Close();
tmpname.Move(savename, TFileName::ReplaceExisting|TFileName::CopyAllowed);
//Jogy>
return true;
}
file.Close();
}
return false;
}
//-----------------------------------------------------------------------------
bool
TCoolFileBuffer::Save(TFile& file, TCrLfStyle style, bool clearDirty)
{
if(style == clStyleAutomatic)
style = CRLFMode == clStyleAutomatic ? clStyleDos : CRLFMode;
LPCTSTR pszCRLF = crlfs[style];
int CRLFLength = static_cast<int>(_tcsclen(pszCRLF));
USES_CONVERSION;
for (int line = 0; line < (int)LineArray.Size(); line++){
int length = LineArray[line]->Length;
if (length > 0){
if(!file.Write(_W2A(LineArray[line]->Text), length))
return false;
}
if (line < (int)LineArray.Size() - 1){ // Last line must not
if(!file.Write(pszCRLF, CRLFLength)) // end with CRLF
return false;
}
}
if(clearDirty)
SetDirty(false);
return true;
}
//-----------------------------------------------------------------------------
int
TCoolFileBuffer::FindLineWithFlag(uint32 flag)
{
for(int i = 0; i < (int)LineArray.Size(); i++){
if((LineArray[i]->Flags & flag) != 0)
return i;
}
return -1;
}
//-----------------------------------------------------------------------------
void
TCoolFileBuffer::GetText(const TEditPos& startPos,const TEditPos& endPos,
LPTSTR buffer, int buflen, LPCTSTR pszCRLF /*= NULL*/)
{
PRECONDITION(startPos.row >= 0 && startPos.row < (int)LineArray.Size());
PRECONDITION(startPos.col >= 0 && startPos.col <= LineArray[startPos.row]->Length);
PRECONDITION(endPos.row >= 0 && endPos.row < (int)LineArray.Size());
PRECONDITION(endPos.col >= 0 && endPos.col <= LineArray[endPos.row]->Length);
PRECONDITION(startPos.row < endPos.row ||
(startPos.row == endPos.row && startPos.col < endPos.col));
if (pszCRLF == NULL)
pszCRLF = crlf;
int clLength = static_cast<int>(_tcslen(pszCRLF));
CHECK(clLength > 0);
int bufSize = 0;
for (int i = startPos.row; i <= endPos.row; i++){
bufSize += LineArray[i]->Length;
bufSize += clLength;
}
TTmpBuffer<_TCHAR> __clnObj(bufSize+10);
LPTSTR pszBuf = __clnObj;
if (startPos.row < endPos.row){
int count = LineArray[startPos.row]->Length - startPos.col;
if (count > 0){
memcpy(pszBuf, LineArray[startPos.row]->Text + startPos.col,
sizeof(_TCHAR)*count);
pszBuf += count;
}
memcpy(pszBuf, pszCRLF, sizeof(TCHAR) * clLength);
pszBuf += clLength;
for(int j = startPos.row + 1; j < endPos.row; j++){
count = LineArray[j]->Length;
if (count > 0){
memcpy(pszBuf, LineArray[j]->Text, sizeof(_TCHAR) * count);
pszBuf += count;
}
memcpy(pszBuf, pszCRLF, sizeof(_TCHAR) * clLength);
pszBuf += clLength;
}
if (endPos.col > 0){
memcpy(pszBuf, LineArray[endPos.row]->Text, sizeof(_TCHAR) * endPos.col);
pszBuf += endPos.col;
}
}
else{
int count = endPos.col - startPos.col;
memcpy(pszBuf, LineArray[startPos.row]->Text + startPos.col,
sizeof(_TCHAR) * count);
pszBuf += count;
}
pszBuf[0] = 0;
int count = endPos.col - startPos.col;
if(count > buflen){
memcpy(buffer,(_TCHAR*)__clnObj, sizeof(_TCHAR) * (buflen-1));
buffer[buflen-1] = 0;
}
else
_tcscpy(buffer,(_TCHAR*)__clnObj);
}
//-----------------------------------------------------------------------------
bool
TCoolFileBuffer::DeleteText(const TEditRange& range)
{
PRECONDITION(range.srow >= 0 && range.srow < (int)LineArray.Size());
PRECONDITION(range.scol >= 0 && range.scol <= LineArray[range.srow]->Length);
PRECONDITION(range.erow >= 0 && range.erow < (int)LineArray.Size());
PRECONDITION((range.ecol >= 0 && range.ecol <= LineArray[range.erow]->Length) ||
(range.ecol == -1 && range.scol == 0));
PRECONDITION(range.srow < range.erow || (range.srow == range.erow &&
(range.scol < range.ecol || (range.scol == 0 && range.ecol == -1))));
if(IsReadOnly())
return false;
if(range.srow == range.erow){
// if endPos.col == -1 and startpos == 0
if(range.ecol == -1 && range.scol == 0)
LineArray.Destroy(range.srow);
else {
TLineInfo& li = *LineArray[range.srow];
memcpy(li.Text + range.scol, li.Text + range.ecol,
sizeof(TCHAR)*(li.Length - range.ecol));
li.Length -= (range.ecol - range.scol);
}
}
else{
int restCount = LineArray[range.erow]->Length - range.ecol;
TAPointer<_TCHAR> restChars;
if (restCount > 0){
restChars = new _TCHAR[restCount];
memcpy((_TCHAR*)restChars, LineArray[range.erow]->Text + range.ecol,
restCount * sizeof(TCHAR));
}
//for (int i = range.srow + 1; i <= range.erow; i++)
for (int i = range.erow; i > range.srow; i--)
LineArray.Destroy(i);
// endPos.row is no more valid
LineArray[range.srow]->Length = range.scol;
if (restCount > 0)
AppendText(range.srow, (_TCHAR*)restChars, restCount);
}
SetDirty(true);
return true;
}
//-----------------------------------------------------------------------------
bool
TCoolFileBuffer::InsertText(const TEditPos& startPos, LPCTSTR text,
TEditPos& endPos)
{
PRECONDITION(startPos.row >= 0 && startPos.row < (int)LineArray.Size());
PRECONDITION(startPos.col >= 0 && startPos.col <= LineArray[startPos.row]->Length);
if (IsReadOnly())
return false;
int restCount = LineArray[startPos.row]->Length - startPos.col;
TAPointer<_TCHAR> restChars;
if(restCount > 0){
restChars = new TCHAR[restCount];
memcpy((_TCHAR*)restChars, LineArray[startPos.row]->Text + startPos.col,
restCount * sizeof(_TCHAR));
LineArray[startPos.row]->Length = startPos.col;
}
int currentLine = startPos.row;
int textPos;
for (;;){
textPos = 0;
while (text[textPos] != 0 && text[textPos] != _T('\r'))
textPos++;
if (currentLine == startPos.row)
AppendText(startPos.row, text, textPos);
else{
InsertLine(text, textPos, currentLine);
}
if (text[textPos] == 0 || text[textPos+1] == 0){
endPos.row = currentLine;
endPos.col = LineArray[currentLine]->Length;
if(restCount)
AppendText(currentLine, (_TCHAR*)restChars, restCount);
break;
}
currentLine++;
textPos++;
if(text[textPos] == _T('\n'))
textPos++;
else{
CHECK(false); // Invalid line-end format passed
}
text += textPos;
}
SetDirty(true);
return true;
}
//-----------------------------------------------------------------------------
//
//
//
//{{TCoolTextWnd Implementation}}
UINT TCoolTextWnd::SelClipFormat = 0;
//
// Build a response table for all messages/commands handled
// by the application.
//
DEFINE_RESPONSE_TABLE1(TCoolTextWnd, TControl)
EV_WM_SIZE,
EV_WM_SETCURSOR,
EV_WM_KILLFOCUS,
EV_WM_SETFOCUS,
EV_WM_HSCROLL,
EV_WM_VSCROLL,
EV_WM_MOUSEMOVE,
EV_WM_LBUTTONDOWN,
EV_WM_LBUTTONUP,
EV_WM_KEYDOWN,
EV_WM_LBUTTONDBLCLK,
EV_COMMAND(CM_EDITCOPY, CmEditCopy),
EV_COMMAND_ENABLE(CM_EDITCOPY, CeSelectEnable),
EV_WM_SYSCOLORCHANGE,
EV_WM_MOUSEWHEEL,
#if !defined(COOL_NODRAGDROP)
EV_WM_TIMER,
#endif
END_RESPONSE_TABLE;
//-----------------------------------------------------------------------------
bool
TCoolTextWnd::TTextSelection::TextToClipboard(TClipboard& cb, LPCTSTR text,
int len)
{
// Allocate a global memory object for the text.
HGLOBAL hHandle = ::GlobalAlloc(GMEM_DDESHARE, len + 1);
if (hHandle){
// Lock the handle and copy the text to the buffer.
char* pBlock = (char*)::GlobalLock(hHandle);
memcpy(pBlock, text, len);
pBlock[len] = 0;
::GlobalUnlock(hHandle);
// Place the handle on the clipboard, as internal format.
cb.SetClipboardData(GetFormat(), hHandle);
}
else
return false;
// Copy as Text Format
// Allocate a global memory object for the text.
HGLOBAL hHandle1 = ::GlobalAlloc(GMEM_DDESHARE, len-7+1);
if (hHandle1){
// Lock the handle and copy the text to the buffer.
char* pBlock = (char*)::GlobalLock(hHandle1);
memcpy(pBlock, text+7, len-7);
pBlock[len-7]=0;
::GlobalUnlock(hHandle1);
// Place the handle on the clipboard, as visible format.
#ifdef _UNICODE
cb.SetClipboardData(CF_UNICODETEXT, hHandle1);
#else
cb.SetClipboardData(CF_TEXT, hHandle1);
#endif
}
else
return false;
return true;
}
//-----------------------------------------------------------------------------
bool
TCoolTextWnd::TTextSelection::Copy()
{
bool retval = false;
TClipboard clipboard(*GetParent());
if (clipboard.EmptyClipboard()){
tostringstream ostrm;
if(Copy(ostrm)){
const tstring text = ostrm.str();
retval = TextToClipboard(clipboard, text.c_str(), static_cast<int>(text.size()));
}
}
return retval;
}
//-----------------------------------------------------------------------------
// TLineSelection
//
TCoolTextWnd::TLineSelection::TLineSelection(TCoolTextWnd* parent,
int start, int end)
:
TTextSelection(parent), Start(start), End(end)
{
}
//-----------------------------------------------------------------------------
bool
TCoolTextWnd::TLineSelection::GetSelection(int line, int& startChar,
int& endChar)
{
if(HasSelection(line)){
startChar = 0;
endChar = GetParent()->GetLineLength(line)+1;
}
return true;
}
//-----------------------------------------------------------------------------
bool
TCoolTextWnd::TLineSelection::Delete()
{
int start = Start, end = End;
if(start > end)
std::swap(start,end);
GetBuffer()->DeleteText(TEditRange(0, start, -1, end));
return true;
}
//-----------------------------------------------------------------------------
bool
TCoolTextWnd::TLineSelection::Copy(tostream& os)
{
TCoolTextBuffer* buffer = GetBuffer();
int start = Start, end = End;
if(start > end)
std::swap(start,end);
os << lineSelectionId;
for(int i = start; i <= end; i++){
int length = buffer->GetLineLength(i);
LPTSTR text = (LPTSTR)buffer->GetLineText(i);
if(text){
_TCHAR ch = text[length];
text[length] = 0;
os << text;
text[length] = ch;
}
os << crlf;
}
os << ends;
return true;
}
//-----------------------------------------------------------------------------
bool
TCoolTextWnd::TStreamSelection::GetSelection(int line, int& startChar,
int& endChar)
{
if(HasSelection(line)){
TEditRange range(Range);
range.Normalize();
startChar = line > range.srow ? 0 : std::min(range.ecol, range.scol);
endChar = line < range.erow ? GetParent()->GetLineLength(line)+1
: std::max(range.ecol, range.scol);
}
return true;
}
//-----------------------------------------------------------------------------
bool
TCoolTextWnd::TStreamSelection::Delete()
{
TEditRange range(Range);
range.Normalize();
GetBuffer()->DeleteText(range);
return true;
}
//-----------------------------------------------------------------------------
bool TCoolTextWnd::TStreamSelection::Copy(tostream& os)
{
TCoolTextBuffer* buffer = GetBuffer();
TEditRange range(Range);
range.Normalize();
os << streamSelectionId;
for(int i = range.srow; i <= range.erow; i++){
LPTSTR text = (LPTSTR)buffer->GetLineText(i);
int length = buffer->GetLineLength(i);
if(i == range.srow){
if(range.srow == range.erow && range.ecol < length)
length = range.ecol;
text += range.scol;
}
else if(i == range.erow && range.ecol < length)
length = range.ecol;
if(length)
length -= range.scol;
if(length < 0)
length = 0;
if(text){
_TCHAR ch = text[length];
text[length] = 0;
os << text;
text[length] = ch;
}
if(i < range.erow)
os << crlf;
}
os << ends;
return true;
}
//-----------------------------------------------------------------------------
TCoolTextWnd::TColumnSelection::TColumnSelection(TCoolTextWnd* parent,
const TEditRange& range)
:
TStreamSelection(parent, range)
{
}
//-----------------------------------------------------------------------------
bool
TCoolTextWnd::TColumnSelection::GetSelection(int line, int& startChar,
int& endChar)
{
if(HasSelection(line)){
TEditRange range(Range);
range.Normalize();
startChar = range.scol;
endChar = range.ecol;
}
return true;
}
//-----------------------------------------------------------------------------
bool
TCoolTextWnd::TColumnSelection::Delete()
{
TCoolTextBuffer* buffer = GetBuffer();
TEditRange range(Range);
range.Normalize();
for(int i = range.srow; i <= range.erow; i++){
int length = buffer->GetLineLength(i);
int startP = range.scol < length ? range.scol : -1;
int endP = range.srow < length ? range.srow : length;
if(startP > 0)
buffer->DeleteText(TEditRange(startP, i, endP, i));
}
return true;
}
//-----------------------------------------------------------------------------
bool
TCoolTextWnd::TColumnSelection::Copy(tostream& os)
{
TCoolTextBuffer* buffer = GetBuffer();
TEditRange range(Range);
range.Normalize();
os << columnSelection;
for(int i = range.srow; i <= range.erow; i++){
LPTSTR text = (LPTSTR)buffer->GetLineText(i);
int length = buffer->GetLineLength(i);
int startP = range.scol;
if(startP > length)
os << crlf;
else{
int endP = range.erow;
if(endP > length)
endP = length;
if(text){
_TCHAR ch = text[endP];
text[range.ecol] = 0;
os << &text[startP];
text[endP] = ch;
}
os << crlf;
}
}
os << ends;
return true;
}
//-----------------------------------------------------------------------------
// class TCoolScroller
// ~~~~~ ~~~~~~~~~~~~~
TCoolScroller::TCoolScroller(TWindow* window, int xUnit, int yUnit,
long xRange, long yRange)
:
TScroller(window,xUnit,yUnit,xRange,yRange)
{
}
#if 0 //OWLInternalVersion < 0x06001020L
//-----------------------------------------------------------------------------
void
TCoolScroller::SetSBarRange()
{
PRECONDITION(Window);
PRECONDITION(Window->GetHandle());
if (Window && Window->GetHandle()) {
if (HasHScrollBar) {
int curMin, curMax;
GetScrollRange(SB_HORZ, curMin, curMax);
int newMax = std::max(0, std::min(XRange - 1, SHRT_MAX));
if (newMax != curMax || curMin != 0)
SetScrollRange(SB_HORZ, 0, newMax, true);
}
if (HasVScrollBar) {
int curMin, curMax;
GetScrollRange(SB_VERT, curMin, curMax);
int newMax = std::max(0, std::min(YRange - 1, SHRT_MAX));
if (newMax != curMax || curMin != 0)
SetScrollRange(SB_VERT, 0, newMax, true);
}
}
}
#endif //
//-----------------------------------------------------------------------------
void TCoolScroller::ScrollTo(long x, long y)
{
PRECONDITION(Window);
PRECONDITION(Window->GetHandle());
if (Window && Window->GetHandle()) {
long newXPos = std::max(0L, std::min(x, XRange - XPage));
long newYPos = std::max(0L, std::min(y, YRange - YPage));
if (newXPos != XPos || newYPos != YPos) {
//
// scaling isn't needed here. if condition is met, ScrollWindow()
// will succeed since XPage and YPage are ints
//
// if condition isn't met, ScrollWindow() is called in EndScroll()
// as a result of calling UpdateWindow()
//
// EndScroll() performs the necessary scaling
//
TCoolTextWnd* wnd = TYPESAFE_DOWNCAST(Window, TCoolTextWnd);
CHECK(wnd);
if (AutoOrg || (abs(YPos - newYPos) < YPage && abs(XPos - newXPos) < XPage))
{
TRect clientRect;
Window->GetClientRect(clientRect);
if((YPos - newYPos) == 0)
clientRect.left += wnd->GetMarginWidth();
Window->ScrollWindow((int)(XPos - newXPos) * XUnit,
(int)(YPos - newYPos) * YUnit, &clientRect, &clientRect);
}
else
wnd->InvalidateLines(0, -1);
XPos = newXPos;
YPos = newYPos;
Window->UpdateWindow();
}
}
}
//-----------------------------------------------------------------------------
// class TCoolTextWnd
// ~~~~~ ~~~~~~~~~~~~
//
TCoolTextWnd::TCoolTextWnd(TWindow* parent,int id,LPCTSTR title,int x, int y,
int w, int h, TModule* module)
:
TControl(parent,id,title,x,y,w,h,module),
CursorPos(0,0),
Flags(cfSelMargin|cfSmartCursor|cfNoUseCaret|cfLookWrdUnderCur|cfAutoIntend),
TabSize(4),
LineHeight(-1),
CharWidth(-1),
ScreenLines(-1),
ScreenChars(-1),
MaxLineLength(-1),
IdealCharPos(-1),
MemoryBitmap(0),
CelArray(0),
SelType(stStreamSelection),
Selection(0),
SyntaxParser(0),
ParseCookies(0),
ParseArraySize(0),
ActualLengthArraySize(0),
ActualLineLength(0),
Cursor(0),
LastHit(-1,-1),
MarginWidth(16),
LineDigits(5),
CurbPos(80),
TmpCurbPos(0)
#if !defined(COOL_NODRAGDROP)
,DragDropProxy(new TTextDragDropProxy)
,DragDropSupport(DragDropProxy)
,DragSelTimer(0)
#endif
{
ModifyStyle(0, WS_VSCROLL|WS_HSCROLL);
SetBkgndColor(TColor::Transparent);
memset(TextFonts,0,sizeof(TextFonts));
if(!SelClipFormat)
SelClipFormat = ::RegisterClipboardFormat(_T("CoolEdit Text Block"));
}
//-----------------------------------------------------------------------------
TCoolTextWnd::~TCoolTextWnd()
{
#if !defined(COOL_NODRAGDROP)
delete DragDropProxy;
#endif
for(int i = 0; i < 8; i++)
delete TextFonts[i];
delete SyntaxParser;
delete MemoryBitmap;
delete CelArray;
delete Selection;
delete[] ParseCookies;
delete[] ActualLineLength;
delete Cursor;
}
//
void
TCoolTextWnd::SetupWindow()
{
if(!Scroller)
Scroller = new TCoolScroller(this, 7, 16, 80, 60);
#if !defined(USE_AUTOORG)
Scroller->AutoOrg = false;
#endif
// Call base class function.
Inherited::SetupWindow();
#if !defined(COOL_NODRAGDROP)
DragDropSupport.Register(*this);
#endif
if(!CelArray)
CelArray = new TCelArray(new TBtnBitmap(*GetModule(),IDR_MARGIN_ICONS), 26);
if(!Cursor)
Cursor = new TCursor(*GetModule(), TResId(IDR_MARGIN_CURSOR));
SetCursor(0, IDC_IBEAM);
TCoolTextBuffer* buffer = GetBuffer();
if(!buffer->SyntaxDescrExist())
buffer->BuildDefSyntaxDescr();
// setup scroll page size
Scroller->SetUnits(GetCharWidth(), GetLineHeight());
AdjustScroller();
}
//-----------------------------------------------------------------------------
void
TCoolTextWnd::CleanupWindow()
{
#if !defined(COOL_NODRAGDROP)
DragDropSupport.UnRegister(*this);
if(DragSelTimer)
KillTimer(DragSelTimer);
DragSelTimer = 0;
#endif
// Call base class function.
Inherited::CleanupWindow();
}
//-----------------------------------------------------------------------------
void TCoolTextWnd::SetSyntaxParser(TSyntaxParser* parser)
{
delete SyntaxParser;
SyntaxParser = parser;
}
//-----------------------------------------------------------------------------
TConfigFile* TCoolTextWnd::CreateConfigFile()
{
return new TRegConfigFile(configOWLNExt);
}
//-----------------------------------------------------------------------------
void TCoolTextWnd::FileNew()
{
PRECONDITION(GetBuffer());
GetBuffer()->Clear(true);// add empty line
ResetView();
AdjustScroller();
InvalidateLines(0, -1, false);
}
//-----------------------------------------------------------------------------
bool TCoolTextWnd::FileOpen(LPCTSTR filename)
{
PRECONDITION(GetBuffer());
if(!GetBuffer()->Load(filename))
return false;
ResetView();
if(GetHandle()){
AdjustScroller();
InvalidateLines(0, -1, false);
}
return true;
}
//-----------------------------------------------------------------------------
void TCoolTextWnd::GetWindowClass(WNDCLASS& wndClass)
{
// Call base class function.
Inherited::GetWindowClass(wndClass);
wndClass.style |= CS_DBLCLKS;
}
//-----------------------------------------------------------------------------
auto TCoolTextWnd::GetWindowClassName() -> TWindowClassName
{
return TWindowClassName{_T("COOLEDIT")};
}
//-----------------------------------------------------------------------------
void TCoolTextWnd::Paint(TDC& dc, bool /*erase*/, TRect& /*rect*/)
{
TRect clientRect;
GetClientRect(clientRect);
int lineCount = GetNumLines();
int lineHeight = GetLineHeight();
// must be member variables
TMemoryDC memDC(dc);
if(!MemoryBitmap)
MemoryBitmap = new TBitmap(dc, clientRect.Width(), lineHeight);
memDC.SelectObject(*MemoryBitmap);
TRect lineRect(clientRect.left, clientRect.top,
clientRect.right, clientRect.top + lineHeight);
TRect cacheMargin(0, 0, GetMarginWidth(), lineHeight);
TRect cacheLine(GetMarginWidth(), 0, lineRect.Width(), lineHeight);
int currentLine = GetTopLine();
#if !defined(USE_AUTOORG)
int leftPos = CurbPos == -1 ? -1 : (cacheLine.left+(CurbPos-GetOffsetChar())*GetCharWidth());
#else
int leftPos = CurbPos == -1 ? -1 : (cacheLine.left+CurbPos*GetCharWidth());
#endif
while (lineRect.Top() < clientRect.Bottom()){
if(currentLine < lineCount){
DrawMargin(memDC, cacheMargin, currentLine);
DrawLine(memDC, cacheLine, currentLine);
}
else{
DrawMargin(memDC, cacheMargin, -1);
DrawLine(memDC, cacheLine, -1);
}
// paint line 80 characters
if(leftPos >= 0){
memDC.SelectObject(TUIFace::GetDitherBrush());
VERIFY(memDC.PatBlt(leftPos-1, cacheLine.top, 1, cacheLine.bottom, PATCOPY));
memDC.RestoreBrush();
}
// Now transfer what was drawn on the (invisible) memory DC onto the
// visible dc This one BitBlt transfer is much faster than the many
// individual operations that were performed above.
//
VERIFY(dc.BitBlt(lineRect, memDC, TPoint(0,0)));
currentLine++;
lineRect.Offset(0, lineHeight);
}
// Restore original bitmap before leaving
//
memDC.RestoreBitmap();
}
//
bool
TCoolTextWnd::GetLine(LPTSTR str, int strSize, int lineNumber) const
{
TCoolTextBuffer* buffer = CONST_CAST(TCoolTextWnd*,this)->GetBuffer();
PRECONDITION(buffer);
if(lineNumber >= GetNumLines())
return false;
int endPos = GetLineLength(lineNumber);
if(endPos > strSize)
endPos = strSize-1;
buffer->GetText(TEditPos(lineNumber, 0), TEditPos(lineNumber, endPos), str, strSize);
return true;
}
//
void
TCoolTextWnd::CalcLineCharDim()
{
TClientDC clientDC(*this);
TSize extent = GetFont()->GetTextExtent(clientDC, _T("X"));
LineHeight = extent.cy;
if (LineHeight < 1)
LineHeight = 1;
CharWidth = extent.cx;
}
//
int
TCoolTextWnd::GetLineHeight() const
{
if (LineHeight == -1)
CONST_CAST(TCoolTextWnd*,this)->CalcLineCharDim();
return LineHeight;
}
//
int
TCoolTextWnd::GetCharWidth() const
{
if (CharWidth == -1)
CONST_CAST(TCoolTextWnd*,this)->CalcLineCharDim();
return CharWidth;
}
//
TFont*
TCoolTextWnd::CreateFont(int index)
{
if(!TextFonts[index]){
PRECONDITION(GetBuffer());
LOGFONT lf;
GetBuffer()->GetFont(lf);
lf.lfWeight = (index & 0x01) ? FW_BOLD : FW_NORMAL;
lf.lfItalic = (uint8)((index & 0x02)!=0);
lf.lfUnderline= (uint8)((index & 0x04)!=0);
TextFonts[index] = new TFont(lf);
}
return TextFonts[index];
}
//
TFont*
TCoolTextWnd::GetFont(bool italic, bool bold, bool underline)
{
int index = 0;
if(bold)
index |= 0x0001;
if(italic)
index |= 0x0002;
if(underline)
index |= 0x0004;
return CreateFont(index);
}
//
void
TCoolTextWnd::SetFont(const LOGFONT &lf)
{
PRECONDITION(GetBuffer());
GetBuffer()->SetFont(lf);
LineHeight = -1;
CharWidth = -1;
ScreenLines = -1;
ScreenChars = -1;
delete MemoryBitmap;
MemoryBitmap = 0;
for (int i = 0; i < 8; i ++){
if (TextFonts[i]){
delete TextFonts[i];
TextFonts[i] = 0;
}
}
if(GetHandle()){
// setup scroll page size
Scroller->SetUnits(GetCharWidth(), GetLineHeight());
AdjustScroller();
UpdateCaret();
}
}
//
void
TCoolTextWnd::SetSyntaxFormat(TDC& dc, int index)
{
TCoolTextBuffer::TSyntaxDescr& node = GetSyntaxDescr(index);
dc.SetTextColor(node.TxColor);
dc.SetBkColor(node.BkColor);
dc.SelectObject(*GetFont(node.FontIndex));
}
//
void
TCoolTextWnd::FormatLineNumber(LPTSTR buffer, int len, int index)
{
_stprintf_s(buffer, len, _T("%05u"), index);
}
//
int
TCoolTextWnd::CellImageIndex(int lineIndex)
{
int imageIndex = -1;
if (lineIndex >= 0){
PRECONDITION(GetBuffer());
uint32 lineFlags = GetBuffer()->GetLineFlags(lineIndex);
if(lineFlags==0)
return -1;
static const TCoolTextBuffer::TLineFlags adwFlags[] = {
LF_BOOKMARKID(1),
LF_BOOKMARKID(2),
LF_BOOKMARKID(3),
LF_BOOKMARKID(4),
LF_BOOKMARKID(5),
LF_BOOKMARKID(6),
LF_BOOKMARKID(7),
LF_BOOKMARKID(8),
LF_BOOKMARKID(9),
LF_BOOKMARKID(0),
TCoolTextBuffer::lfBreakPoint,
TCoolTextBuffer::lfCompError,
TCoolTextBuffer::lfBookMarks,
TCoolTextBuffer::lfInvalidBPoint,
TCoolTextBuffer::lfDisabledBPoint,
TCoolTextBuffer::lfReserved1,
TCoolTextBuffer::lfReserved2,
TCoolTextBuffer::lfExecution,
};
for (int i = 0; i <= COUNTOF(adwFlags); i++){
if((lineFlags & adwFlags[i]) != 0){
imageIndex = i;
break;
}
}
if((lineFlags & TCoolTextBuffer::lfExecution) != 0){
#define ALL_FLAGS (TCoolTextBuffer::lfBreakPoint|TCoolTextBuffer::lfCompError|\
TCoolTextBuffer::lfBookMarks|TCoolTextBuffer::lfInvalidBPoint|\
TCoolTextBuffer::lfDisabledBPoint|TCoolTextBuffer::lfReserved1|\
TCoolTextBuffer::lfReserved2)
if((lineFlags&ALL_FLAGS)!=0)
imageIndex += 9;
else if(imageIndex < COUNTOF(adwFlags)-1)
imageIndex = 18;
}
}
return imageIndex;
}
//
void
TCoolTextWnd::DrawMargin(TDC& dc, const TRect& rect, int lineIndex)
{
if(!IsSelectionMargin()){
dc.SetBkColor(GetBkColor(COLORINDEX_WHITESPACE));
dc.TextRect(rect);
return;
}
TRect imageRect(rect);
if(IsLineNumbers())
imageRect.right -= LineDigits * GetCharWidth();
dc.SetBkColor(GetBkColor(COLORINDEX_MARGIN));
dc.TextRect(imageRect);
int imageIndex = CellImageIndex(lineIndex);
if (imageIndex >= 0)
VERIFY(CelArray->BitBlt(imageIndex, dc, imageRect.left+2,
imageRect.top+(imageRect.Height()-16)/2));
// draw line number
if(IsLineNumbers()){
TTmpBuffer<_TCHAR> buffer(MAX_PATH);
FormatLineNumber(buffer, MAX_PATH, lineIndex+1);
TRect textRect(rect);
textRect.left = textRect.right - LineDigits * GetCharWidth();
SetSyntaxFormat(dc, COLORINDEX_MARGIN);
dc.ExtTextOut(textRect.left, textRect.top, ETO_OPAQUE, &textRect, &buffer[0], -1);
}
dc.SelectObject(TUIFace::GetDitherBrush());
dc.PatBlt(rect.right-1, rect.top, 1, rect.bottom, PATCOPY);
dc.RestoreBrush();
}
//
void
TCoolTextWnd::DrawLine(TDC& dc, const TRect& rect, int lineIndex)
{
PRECONDITION(lineIndex >= -1 && lineIndex < GetNumLines());
PRECONDITION(GetBuffer());
if(lineIndex == -1){
// Draw line beyond the text
dc.SetBkColor(GetBkColor(COLORINDEX_WHITESPACE));
dc.TextRect(rect);
return;
}
// Acquire the background color for the current line
uint32 lineFlags = GetBuffer()->GetLineFlags(lineIndex);
bool drawWhitespace = false;
int colorIdx;
if(lineFlags&TCoolTextBuffer::lfExecution){
drawWhitespace = true;
colorIdx = COLORINDEX_EXECUTION;
}
else if(lineFlags&TCoolTextBuffer::lfBreakPoint){
drawWhitespace = true;
colorIdx = COLORINDEX_BREAKPOINT;
}
else if(lineFlags&TCoolTextBuffer::lfCompError){
drawWhitespace = true;
colorIdx = COLORINDEX_ERROR;
}
else if(lineFlags&TCoolTextBuffer::lfInvalidBPoint){
drawWhitespace = true;
colorIdx = COLORINDEX_INVALIDBREAK;
}
else
colorIdx = COLORINDEX_NORMALTEXT;
int length = GetLineLength(lineIndex);
if (!length){
// Draw the empty line
TRect r(rect);
TEditPos editPos(0,lineIndex);
if(IsFlagSet(cfFocused|cfShowInactiveSel) && IsInSelection(editPos)){
dc.SetBkColor(GetBkColor(COLORINDEX_SELECTION));
TRect rc(r.left, r.top, r.left + GetCharWidth(), r.bottom);
dc.TextRect(rc);
r.left += GetCharWidth();
}
dc.SetBkColor(GetBkColor(drawWhitespace ? colorIdx : COLORINDEX_WHITESPACE));
dc.TextRect(r);
return;
}
int blocks = 0;
TAPointer<TTextBlock> __ClnObj;
TTextBlock* pBuf = 0;
LPCTSTR pszChars = GetLineText(lineIndex);
if(!drawWhitespace){
// Parse the line
uint32 cookie = GetParseCookie(lineIndex - 1);
GetParseCookie(lineIndex); //Jogy - ensure that ParseCookies[lineIndex] is allocated!
if(SyntaxParser){
__ClnObj = pBuf = new TTextBlock[length*3];
ParseCookies[lineIndex] =
SyntaxParser->ParseLine(cookie, lineIndex, pBuf, blocks);
}
else
ParseCookies[lineIndex] = 0;
CHECK(ParseCookies[lineIndex] != (uint32)-1);
}
// Draw the line text
#if !defined(USE_AUTOORG)
TPoint origin(rect.left - GetOffsetChar() * GetCharWidth(), rect.top);
#else
TPoint origin(rect.left, rect.top);
#endif
if (blocks > 0){
CHECK(pBuf[0].CharPos >= 0 && pBuf[0].CharPos <= length);
if(pBuf[0].CharPos){
SetSyntaxFormat(dc, colorIdx);
DrawLineBlock(dc, origin, rect, COLORINDEX_NORMALTEXT, pszChars,
0, pBuf[0].CharPos, TEditPos(0, lineIndex));
}
for (int i = 0; i < blocks - 1; i ++){
CHECK(pBuf[i].CharPos >= 0 && pBuf[i].CharPos <= length);
if(pBuf[i + 1].CharPos - pBuf[i].CharPos){
SetSyntaxFormat(dc, pBuf[i].SyntaxIndex);
DrawLineBlock(dc, origin, rect, pBuf[i].SyntaxIndex,
pszChars,pBuf[i].CharPos,
pBuf[i + 1].CharPos - pBuf[i].CharPos,
TEditPos(pBuf[i].CharPos, lineIndex));
}
}
CHECK(pBuf[blocks - 1].CharPos >= 0 && pBuf[blocks - 1].CharPos <= length);
if(length - pBuf[blocks - 1].CharPos){
SetSyntaxFormat(dc, pBuf[blocks - 1].SyntaxIndex); //<<----------------
DrawLineBlock(dc, origin, rect, pBuf[blocks - 1].SyntaxIndex,
pszChars,pBuf[blocks - 1].CharPos,
length - pBuf[blocks - 1].CharPos,
TEditPos(pBuf[blocks - 1].CharPos, lineIndex));
}
}
else if(length){
SetSyntaxFormat(dc, drawWhitespace ? colorIdx : COLORINDEX_NORMALTEXT);
DrawLineBlock(dc, origin, rect, drawWhitespace ? colorIdx : COLORINDEX_NORMALTEXT,
pszChars, 0, length, TEditPos(0, lineIndex));
}
// Draw whitespaces to the left of the text
TRect frect(rect);
if (origin.x > frect.left)
frect.left = origin.x;
if (frect.right > frect.left){
if((IsFlagSet(cfFocused|cfShowInactiveSel)) && IsInSelection(TEditPos(length, lineIndex))){
dc.SetBkColor(GetBkColor(COLORINDEX_SELECTION));
TRect rc(frect.left, frect.top, frect.left+GetCharWidth(), frect.bottom);
dc.TextRect(rc);
frect.left += GetCharWidth();
}
if(frect.right > frect.left){
dc.SetBkColor(GetBkColor(drawWhitespace ? colorIdx : COLORINDEX_WHITESPACE));
dc.TextRect(frect);
}
}
}
//
uint32
TCoolTextWnd::GetParseCookie(int lineIndex)
{
if(!ParseCookies){
int lineCount = GetNumLines();
ParseArraySize = lineCount;
ParseCookies = new uint32[lineCount];
memset(ParseCookies, 0xff, lineCount * sizeof(uint32));
}
if(lineIndex < 0)
return 0;
if(lineIndex >= ParseArraySize){
uint32* cookie = new uint32[lineIndex*2];
uint size = ParseArraySize * sizeof(uint32);
memcpy(cookie, ParseCookies, size);
memset((uint8*)cookie+size, 0xff, (lineIndex*2-ParseArraySize)*sizeof(uint32));
delete[] ParseCookies;
ParseCookies = cookie;
ParseArraySize = lineIndex*2;
}
if (ParseCookies[lineIndex] != (uint32)-1)
return ParseCookies[lineIndex];
int l = lineIndex;
while(l >= 0 && ParseCookies[l] == (uint32)-1)
l--;
l++;
int blocks;
while(l <= lineIndex){
uint32 cookie = 0;
if (l > 0)
cookie = ParseCookies[l - 1];
CHECK(cookie != (uint32) -1);
if(SyntaxParser)
ParseCookies[l] = SyntaxParser->ParseLine(cookie, l, 0, blocks);
else
ParseCookies[l] = 0l;
//_TRACE("TCoolTextWnd::GetParseCookie() index: %d, cookie %ld\n", l, ParseCookies[l]);
CHECK(ParseCookies[l] != (uint32)-1);
l++;
}
return ParseCookies[lineIndex];
}
//
void
TCoolTextWnd::DrawLineBlock(TDC& dc, TPoint& origin,
const TRect& clipRect, int clrIndex,
LPCTSTR text, int offset, int count,
const TEditPos& textPos)
{
if (count>0){
if(IsFlagSet(cfFocused|cfShowInactiveSel) && Selection){
int selBegin = 0, selEnd = 0;
if(Selection->HasSelection(textPos.row)){
int startSel, endSel;
if(Selection->GetSelection(textPos.row, startSel, endSel)){
selBegin = startSel - textPos.col;
if (selBegin < 0)
selBegin = 0;
if (selBegin > count)
selBegin = count;
selEnd = endSel - textPos.col;
if (selEnd < 0)
selEnd = 0;
if (selEnd > count)
selEnd = count;
}
}
else{
selBegin = count;
selEnd = count;
}
CHECK(selBegin >= 0 && selBegin <= count);
CHECK(selEnd >= 0 && selEnd <= count);
CHECK(selBegin <= selEnd);
// Draw part of the text before selection
if (selBegin > 0)
DrawTextBlock(dc, origin, clipRect, text, offset, selBegin);
// Draw selected block
if (selBegin < selEnd){
SetSyntaxFormat(dc, COLORINDEX_SELECTION);
DrawTextBlock(dc, origin, clipRect, text,
offset+selBegin, selEnd-selBegin);
SetSyntaxFormat(dc, clrIndex);
}
// draw block after selection
if (selEnd < count)
DrawTextBlock(dc, origin, clipRect, text,
offset + selEnd, count - selEnd);
}
else
DrawTextBlock(dc, origin, clipRect, text, offset, count);
}
}
//
void
TCoolTextWnd::DrawTextBlock(TDC& dc, TPoint& origin, const TRect& clipRect,
LPCTSTR text, int offset, int len)
{
PRECONDITION(len >= 0);
if (len > 0){
tstring line;
ExpandText(text, offset, len, line);
int width = clipRect.right - origin.x;
int count = static_cast<int>(_tcslen(line.c_str()));
if (width > 0){
int countFit = width / GetCharWidth() + 1;
if (count > countFit)
count = countFit;
VERIFY(dc.ExtTextOut(origin, ETO_CLIPPED, &clipRect,
line.c_str(), count));
}
origin.x += GetCharWidth() * count;
}
}
//
void
TCoolTextWnd::ExpandText(LPCTSTR text, int offset, int count, tstring& line)
{
if(count <= 0){
line = _T("");
return;
}
int tabSize = GetTabSize();
int actualOffset = 0;
for(int i = 0; i < offset; i++){
if (text[i] == chTab)
actualOffset += (tabSize - actualOffset % tabSize);
else
actualOffset ++;
}
text += offset;
int length = count;
int tabCount = 0;
for(int j = 0; j < length; j++){
if (text[j] == chTab)
tabCount++;
}
line.resize(length + tabCount * (tabSize - 1)+1);
LPTSTR pszBuf = (LPTSTR)line.c_str();
int curPos = 0;
if (tabCount > 0 || IsFlagSet(cfViewTabs)){
for (int i = 0; i < length; i++){
if(text[i] == chTab){
int spaces = tabSize - (actualOffset + curPos) % tabSize;
if (IsFlagSet(cfViewTabs)){
pszBuf[curPos++] = TAB_CHARACTER;
spaces--;
}
while (spaces > 0){
pszBuf[curPos++] = _T(' ');
spaces--;
}
}
else{
if(text[i] == _T(' ') && IsFlagSet(cfViewTabs))
pszBuf[curPos] = SPACE_CHARACTER;
else
pszBuf[curPos] = text[i];
curPos++;
}
}
}
else{
memcpy(pszBuf, text, sizeof(_TCHAR)*length);
curPos = length;
}
pszBuf[curPos] = 0;
}
//
bool
TCoolTextWnd::IsInSelection(const TEditPos& textPos)
{
//return Selection && Selection->HasSelection(textPos.row);
if(Selection && Selection->HasSelection(textPos.row)){
int startSel, endSel;
if(Selection->GetSelection(textPos.row, startSel, endSel))
return textPos.col >= startSel && textPos.col < endSel;
}
return false;
}
//
void
TCoolTextWnd::EnableTabs(bool viewTabs)
{
if(viewTabs != IsFlagSet(cfViewTabs)){
viewTabs ? SetFlag(cfViewTabs) : ClearFlag(cfViewTabs);
if (IsWindow())
InvalidateLines(0, -1);
}
}
//
void
TCoolTextWnd::EnableCaret(bool enable)
{
if(enable != IsCaretEnable()){
enable ? ClearFlag(cfNoUseCaret) : SetFlag(cfNoUseCaret);
if (IsWindow() && IsFlagSet(cfFocused)){
if(IsFlagSet(cfNoUseCaret)){
HideCaret();
DestroyCaret();
}
else {
ClearFlag(cfCursorHidden);
ClearFlag(cfHasCaret);
UpdateCaret();
ShowCaret();
}
}
}
}
//
void
TCoolTextWnd::EnableShowInactiveSel(bool enable)
{
if(enable != IsShowInactiveSel()){
enable ? SetFlag(cfShowInactiveSel) : ClearFlag(cfShowInactiveSel);
if (IsWindow())
InvalidateLines(0, -1);
}
}
//
void TCoolTextWnd::EnableSmartCursor(bool enable)
{
if(enable != IsSmartCursor()){
enable ? SetFlag(cfSmartCursor) : ClearFlag(cfSmartCursor);
if(IsWindow())
InvalidateLines(0, -1);
}
}
//
void
TCoolTextWnd::EnableSelectionMargin(bool selMargin)
{
if(IsFlagSet(cfSelMargin) != selMargin){
selMargin ? SetFlag(cfSelMargin) : ClearFlag(cfSelMargin);
if(GetHandle()){
ScreenChars = -1;
InvalidateLines(0, -1);
AdjustScroller();
}
}
}
//
void TCoolTextWnd::EnableDragDrop(bool enable)
{
if(IsFlagSet(cfNoDragDrop) != enable){
enable ? SetFlag(cfNoDragDrop) : ClearFlag(cfNoDragDrop);
}
}
//
void TCoolTextWnd::EnableAutoIndent(bool enable)
{
if(IsFlagSet(cfAutoIntend) != enable){
enable ? SetFlag(cfAutoIntend) : ClearFlag(cfAutoIntend);
if (IsWindow())
InvalidateLines(0, -1);
}
}
//
void
TCoolTextWnd::ShowLineNumbers(bool enable)
{
if(IsFlagSet(cfShowLineNumber) != enable){
enable ? SetFlag(cfShowLineNumber) : ClearFlag(cfShowLineNumber);
if (IsWindow()){
UpdateCaret();
InvalidateLines(0, -1);
}
}
}
//
int
TCoolTextWnd::GetMarginWidth() const
{
int retval = IsFlagSet(cfSelMargin) ? MarginWidth : 1;
if(IsLineNumbers())
retval += LineDigits * GetCharWidth(); // 5 chars
return retval;
}
//-----------------------------------------------------------------------------
void
TCoolTextWnd::SetMarginWidth(int width)
{
if(MarginWidth != width){
MarginWidth = width;
if (IsWindow())
InvalidateLines(0, -1);
}
}
//-----------------------------------------------------------------------------
void
TCoolTextWnd::SetLineNumberWidth(int width)
{
if(LineDigits != width){
LineDigits = width;
InvalidateLines(0, -1);
}
}
//-----------------------------------------------------------------------------
void
TCoolTextWnd::SetTabSize(int tabSize)
{
PRECONDITION(tabSize >= 0 && tabSize <= 64);
if (TabSize != tabSize){
TabSize = tabSize;
if(ActualLineLength){
delete ActualLineLength;
ActualLineLength = 0;
}
ActualLengthArraySize = 0;
MaxLineLength = -1;
if(GetHandle()){
AdjustScroller();
UpdateCaret();
InvalidateLines(0, -1);
}
}
}
//
void
TCoolTextWnd::AdjustScroller()
{
static bool in_work = false;
if(!Scroller || in_work)
return;
in_work = true;
TRect clientRect;
GetClientRect(clientRect);
// Only show scrollbars when image is larger than
// the client area and we are not stretching to fit.
//
//int countChars = clientRect.Width()/GetCharWidth();
//int countLines = clientRect.Height()/GetLineHeight();
TPoint range(10000, GetNumLines()-1);
//MaxLineLength = -1;
//TPoint range(GetMaxLineLength(), GetNumLines());
//??????
//Scroller->SetUnits(GetCharWidth(), GetLineHeight());
Scroller->SetRange(range.x, range.y);
//Scroller->ScrollTo(0, 0);
if (!GetUpdateRect(clientRect, false))
InvalidateLines(0, -1, false);
in_work = false;
}
//
void
TCoolTextWnd::EvSize(uint sizeType, const TSize& size)
{
Inherited::EvSize(sizeType, size);
if (sizeType != SIZEICONIC) {
delete MemoryBitmap;
MemoryBitmap = 0;
ScreenLines = -1;
ScreenChars = -1;
//AdjustScroller();
//Invalidate(false);
}
}
//
bool
TCoolTextWnd::EvSetCursor(HWND hWndCursor, uint hitTest, uint mouseMsg)
{
if (hitTest == HTCLIENT){
TPoint point;
Inherited::GetCursorPos(point);
ScreenToClient(point);
int lineCurb = CurbPos==-1 ? -1 : ((CurbPos-GetOffsetChar())*GetCharWidth()+GetMarginWidth());
if(point.x < GetMarginWidth())
::SetCursor(*Cursor);
else if(lineCurb >= 0 && (point.x < (int)(lineCurb+3) && point.x > (int)(lineCurb-3)))
::SetCursor(::LoadCursor(0, TResId(IDC_SIZEWE))); // Set To Arrow Cursor
else{
if(Selection && IsInSelection(Client2Text(point))){
#if !defined(COOL_NODRAGDROP)
if(!IsFlagSet(cfNoDragDrop))
#endif
::SetCursor(::LoadCursor(0, TResId(IDC_ARROW))); // Set To Arrow Cursor
}
else
return Inherited::EvSetCursor(hWndCursor, hitTest, mouseMsg);
}
return true;
}
return Inherited::EvSetCursor(hWndCursor, hitTest, mouseMsg);
}
//
TEditPos
TCoolTextWnd::Client2Text(const TPoint& point)
{
int lineCount = GetNumLines();
TEditPos p(0, GetTopLine() + point.y / GetLineHeight());
if(p.row >= lineCount)
p.row = lineCount - 1;
if(p.row < 0)
p.row = 0;
int length = 0;
LPCTSTR text = 0;
if(p.row >= 0 && p.row < lineCount){
length = GetLineLength(p.row);
text = GetLineText(p.row);
}
int pos = GetOffsetChar() + (point.x - GetMarginWidth()) / GetCharWidth();
if(pos < 0)
pos = 0;
int index = 0;
int curPos = 0;
int tabSize = GetTabSize();
while(index < length){
if (text[index] == chTab)
curPos += (tabSize - curPos % tabSize);
else
curPos++;
if (curPos > pos)
break;
index++;
}
CHECK(index >= 0 && index <= length);
p.col = index;
return p;
}
//
TPoint
TCoolTextWnd::Text2Client(const TEditPos& pos)
{
PRECONDITION(GetBuffer());
// VERIFY_TEXTPOS(pos);
LPCTSTR text = GetLineText(pos.row);
TPoint p(0,(pos.row - GetTopLine())*GetLineHeight());
int tabSize = GetTabSize();
for(int index = 0; index < pos.col; index ++){
if (text[index] == chTab)
p.x += (tabSize - p.x % tabSize);
else
p.x++;
}
p.x = (p.x - GetOffsetChar()) * GetCharWidth() + GetMarginWidth();
return p;
}
//
void
TCoolTextWnd::ShowCursor()
{
if(!IsFlagSet(cfNoUseCaret)){
ClearFlag(cfCursorHidden);
UpdateCaret();
ShowCaret();
}
}
//
void
TCoolTextWnd::HideCursor()
{
if(!IsFlagSet(cfNoUseCaret)){
SetFlag(cfCursorHidden);
UpdateCaret();
HideCaret();
}
}
//
void
TCoolTextWnd::SetCursorPos(const TEditPos& newPos)
{
VERIFY_TEXTPOS(newPos);
CursorPos = newPos;
IdealCharPos = CalculateActualOffset(CursorPos.row, CursorPos.col);
UpdateCaret();
}
//
bool
TCoolTextWnd::CreateCaret(bool overType)
{
if(overType)
Inherited::CreateCaret(false, GetCharWidth(), GetLineHeight());
else
Inherited::CreateCaret(false, 3, GetLineHeight()-1);
return true;
}
//
void
TCoolTextWnd::UpdateCaret()
{
if(IsFlagSet(cfNoUseCaret))
return;
if (IsFlagSet(cfFocused) && !IsFlagSet(cfCursorHidden) &&
CalculateActualOffset(CursorPos.row, CursorPos.col) >= GetOffsetChar())
{
if(!IsFlagSet(cfHasCaret))
{
if(CreateCaret(IsFlagSet(cfOverType)))
SetFlag(cfHasCaret);
}
if(IsFlagSet(cfHasCaret))
{
SetCaretPos(Text2Client(CursorPos));
}
DisplayCursorPosition(CursorPos.row, CursorPos.col);
}
}
//
int
TCoolTextWnd::CalculateActualOffset(int lineIndex, int charIndex)
{
int length = GetLineLength(lineIndex);
//PRECONDITION(charIndex >= 0 && charIndex <= length);
LPCTSTR text = GetLineText(lineIndex);
int offset = 0;
int tabSize = GetTabSize();
int i = 0;
// for text
for (; i < charIndex && i < length; i++){
if (text[i] == chTab)
offset += (tabSize - offset % tabSize);
else
offset++;
}
// after text
for (; i < charIndex; i++)
offset++;
return offset;
}
//
void
TCoolTextWnd::EvKillFocus(HWND hWndGetFocus)
{
ClearFlag(cfFocused);
ClearFlag(cfHasCaret);
if(!IsFlagSet(cfNoUseCaret)){
HideCursor();
DestroyCaret();
}
if (Selection)
InvalidateLines(Selection->GetStart().row, Selection->GetEnd().row);
#if !defined(COOL_NODRAGDROP)
if(IsFlagSet(cfDragPending)){
ReleaseCapture();
if(DragSelTimer)
KillTimer(DragSelTimer);
DragSelTimer = 0;
ClearFlag(cfDragPending);
}
#endif
Inherited::EvKillFocus(hWndGetFocus);
}
//
void
TCoolTextWnd::EvSysColorChange()
{
Inherited::EvSysColorChange();
InvalidateLines(0, -1);
}
//
#if !defined(COOL_NODRAGDROP)
void TCoolTextWnd::EvTimer(uint timerId)
{
if(timerId == COOL_TIMER_DEBOUNCE){
CHECK(DragSelTimer);
if(IsFlagSet(cfDragPending)){
//_TRACE("TCoolTextWnd::EvTimer()\n");
ExecuteDragDrop();
}
}
}
#endif
//
bool
TCoolTextWnd::ToggleInsertStatus()
{
if(IsFlagSet(cfOverType))
ClearFlag(cfOverType);
else
SetFlag(cfOverType);
return true;
}
//
void
TCoolTextWnd::EnableOverType(bool enable)
{
if(IsFlagSet(cfOverType) != enable){
enable ? SetFlag(cfOverType) : ClearFlag(cfOverType);
ClearFlag(cfHasCaret);
ShowCursor();
}
}
//
void
TCoolTextWnd::EvSetFocus(HWND hWndLostFocus)
{
Inherited::EvSetFocus(hWndLostFocus);
SetFlag(cfFocused);
if (Selection)
InvalidateLines(Selection->GetStart().row, Selection->GetEnd().row);
ShowCursor();
}
//
int
TCoolTextWnd::GetMaxLineLength() const
{
if (MaxLineLength == -1){
TCoolTextWnd* wnd = CONST_CAST(TCoolTextWnd*,this);
wnd->MaxLineLength = 0;
int lineCount = GetNumLines();
for (int i = 0; i < lineCount; i++){
int actualLength = wnd->GetLineActualLength(i);
if (MaxLineLength < actualLength)
wnd->MaxLineLength = actualLength;
}
}
return MaxLineLength;
}
//
int
TCoolTextWnd::GetLineActualLength(int lineIndex)
{
PRECONDITION(GetBuffer());
int lineCount = GetNumLines();
CHECK(lineCount > 0);
CHECK(lineIndex >= 0 && lineIndex < lineCount);
if(!ActualLineLength){
ActualLineLength = new int[lineCount];
memset(ActualLineLength, 0xff, sizeof(int) * lineCount);
ActualLengthArraySize = lineCount;
}
if(ActualLineLength[lineIndex] >= 0)
return ActualLineLength[lineIndex];
// Actual line length is not determined yet, let's calculate a little
int actualLength = 0;
int length = GetLineLength(lineIndex);
if(length > 0){
LPCTSTR text = GetLineText(lineIndex);
//Jogy: _alloca() -> alloca()
LPTSTR pszChars = (LPTSTR)alloca(sizeof(TCHAR) * (length + 1));
memcpy(pszChars, text, sizeof(TCHAR) * length);
pszChars[length] = 0;
LPTSTR pszCurrent = pszChars;
int tabSize = GetTabSize();
for (;;){
LPTSTR psz = _tcschr(pszCurrent, chTab);
if (!psz){
actualLength += static_cast<int>(pszChars + length - pszCurrent);
break;
}
actualLength += static_cast<int>(psz - pszCurrent);
actualLength += (tabSize - actualLength % tabSize);
pszCurrent = psz + 1;
}
}
ActualLineLength[lineIndex] = actualLength;
return actualLength;
}
//
void
TCoolTextWnd::GoToLine(int lineIndex, bool relative)
{
int lineCount = GetNumLines() - 1;
TEditPos cursorPos(CursorPos);
if(relative)
lineIndex += cursorPos.row;
if(lineIndex)
lineIndex--;
if(lineIndex > lineCount)
lineIndex = lineCount;
if(lineIndex >= 0){
int charIndex = GetLineLength(lineIndex);
if (charIndex)
charIndex--;
if(cursorPos.col > charIndex)
cursorPos.col = charIndex;
if (cursorPos.col >= 0){
cursorPos.row = lineIndex;
VERIFY_TEXTPOS(cursorPos);
SetCursorPos(cursorPos);
SetSelection(TEditRange(cursorPos, cursorPos));
ScrollToCaret(cursorPos);
}
}
}
//
void
TCoolTextWnd::ClearSelection()
{
if(Selection){
InvalidateLines(Selection->GetStart().row, Selection->GetEnd().row);
delete Selection;
Selection = 0;
}
}
//
void
TCoolTextWnd::SetSelection(const TEditRange& range)
{
VERIFY_TEXTPOS(range.Start());
VERIFY_TEXTPOS(range.End());
if(Selection && Selection->GetStart().row == range.srow){
if(Selection->GetStart().row != range.erow)
InvalidateLines(range.erow, Selection->GetEnd().row);
}
else{
InvalidateLines(range.srow, range.erow);
if(Selection)
InvalidateLines(Selection->GetStart().row, Selection->GetEnd().row);
}
delete Selection;
Selection = 0;
if(range.Start() == range.End())
return;
Selection = CreateSelection(range);
}
//
TCoolTextWnd::TTextSelection*
TCoolTextWnd::CreateSelection(const TEditRange& range)
{
switch(SelType){
case stStreamSelection:
return new TStreamSelection(this, range);
case stLineSelection:
return new TLineSelection(this, range.srow, range.srow);
case stColumnSelection :
return new TColumnSelection(this, range);
}
return 0;
}
//
void
TCoolTextWnd::InvalidateLines(int index1, int index2, bool invalidateMargin)
{
invalidateMargin = true;
if(index2 == -1){
TRect rect;
GetClientRect(rect);
if (!invalidateMargin)
rect.left += GetMarginWidth();
rect.top = (index1 - GetTopLine()) * GetLineHeight();
InvalidateRect(rect, false);
}
else{
if (index2 < index1)
std::swap(index1, index2);
TRect rect;
GetClientRect(rect);
if (!invalidateMargin)
rect.left += GetMarginWidth();
rect.top = (index1 - GetTopLine()) * GetLineHeight();
rect.bottom = (index2 - GetTopLine() + 1) * GetLineHeight();
InvalidateRect(rect, false);
}
}
//
int
TCoolTextWnd::GetScreenLines()
{
if (ScreenLines == -1){
TRect rect;
GetClientRect(rect);
ScreenLines = rect.Height() / GetLineHeight();
}
return ScreenLines;
}
//
int
TCoolTextWnd::GetScreenChars()
{
if (ScreenChars == -1){
TRect rect;
GetClientRect(rect);
ScreenChars = (rect.Width() - GetMarginWidth()) / GetCharWidth();
}
return ScreenChars;
}
//
void
TCoolTextWnd::ToggleBookmark(int bookmarkId)
{
TCoolTextBuffer* buffer = GetBuffer();
PRECONDITION(buffer);
PRECONDITION(bookmarkId >= 0 && bookmarkId <= 9);
uint32 flags = buffer->GetLineFlags(CursorPos.row);
uint32 mask = LF_BOOKMARKID(bookmarkId);
int retval = buffer->SetLineFlag(CursorPos.row, mask, (flags & mask)==0);
if(retval >= 0)
InvalidateLines(retval,retval,true);
InvalidateLines(CursorPos.row,CursorPos.row,true);
}
//
void
TCoolTextWnd::GoBookmark(int bookmarkId)
{
PRECONDITION(bookmarkId >= 0 && bookmarkId <= 9);
PRECONDITION(GetBuffer());
int lineIdx = GetBuffer()->GetLineWithFlag(LF_BOOKMARKID(bookmarkId));
if(lineIdx >= 0){
TEditPos pos(0, lineIdx);
VERIFY_TEXTPOS(pos);
SetCursorPos(pos);
SetSelection(TEditRange(pos, pos));
ScrollToCaret(CursorPos);
}
}
//
void
TCoolTextWnd::ClearBookmarks()
{
TCoolTextBuffer* buffer = GetBuffer();
PRECONDITION(buffer);
for(int bookmarkId = 0; bookmarkId <= 9; bookmarkId++){
int lineIdx = buffer->GetLineWithFlag(LF_BOOKMARKID(bookmarkId));
if (lineIdx >= 0){
buffer->SetLineFlag(lineIdx, LF_BOOKMARKID(bookmarkId), false);
InvalidateLines(CursorPos.row,CursorPos.row,true);
}
}
}
//
void
TCoolTextWnd::ToggleRandBookmark()
{
TCoolTextBuffer* buffer = GetBuffer();
PRECONDITION(buffer);
uint32 flags = buffer->GetLineFlags(CursorPos.row);
uint32 mask = TCoolTextBuffer::lfBookMarks;
buffer->SetLineFlag(CursorPos.row, mask, (flags & mask) == 0, false);
int lineIdx = buffer->GetLineWithFlag(TCoolTextBuffer::lfBookMarks);
if (lineIdx >= 0)
SetFlag(cfBookmarkExist);
else
ClearFlag(cfBookmarkExist);
InvalidateLines(CursorPos.row, CursorPos.row, true);
}
//
void
TCoolTextWnd::NextRandBookmark()
{
PRECONDITION(GetBuffer());
int lineIndex = GetBuffer()->FindNextBookmarkLine(CursorPos.row);
if (lineIndex >= 0) {
TEditPos pos(0, lineIndex);
VERIFY_TEXTPOS(pos);
SetCursorPos(pos);
SetSelection(TEditRange(pos, pos));
ScrollToCaret(CursorPos);
}
}
//
void
TCoolTextWnd::PrevRandBookmark()
{
PRECONDITION(GetBuffer());
int lineIndex = GetBuffer()->FindPrevBookmarkLine(CursorPos.row);
if (lineIndex >= 0){
TEditPos pos(0, lineIndex);
VERIFY_TEXTPOS(pos);
SetCursorPos(pos);
SetSelection(TEditRange(pos, pos));
ScrollToCaret(CursorPos);
}
}
//
void
TCoolTextWnd::ClearRandBookmarks()
{
PRECONDITION(GetBuffer());
TCoolTextBuffer* buffer = GetBuffer();
int lineCount = GetNumLines();
for (int i = 0; i < lineCount; i++){
if(buffer->GetLineFlags(i) & TCoolTextBuffer::lfBookMarks)
buffer->SetLineFlag(i, TCoolTextBuffer::lfBookMarks, false);
}
ClearFlag(cfBookmarkExist);
}
//
void
TCoolTextWnd::EnablerNextBookmark(TCommandEnabler& tce)
{
tce.Enable(IsFlagSet(cfBookmarkExist));
}
//
void
TCoolTextWnd::EnablerPrevBookmark(TCommandEnabler& tce)
{
tce.Enable(IsFlagSet(cfBookmarkExist));
}
//
void
TCoolTextWnd::EnablerClearRandBookmarks(TCommandEnabler& tce)
{
tce.Enable(IsFlagSet(cfBookmarkExist));
}
//
int
TCoolTextWnd::GetTopLine()
{
return Scroller->YPos;
}
//
int
TCoolTextWnd::GetOffsetChar()
{
return Scroller->XPos;
}
//
void
TCoolTextWnd::EvHScroll(uint scrollCode, uint thumbPos, HWND hWndCtl)
{
Inherited::EvHScroll(scrollCode,thumbPos,hWndCtl);
if(IsFlagSet(cfHasCaret))
SetCaretPos(Text2Client(CursorPos));
}
//
void
TCoolTextWnd::EvVScroll(uint scrollCode, uint thumbPos, HWND hWndCtl)
{
Inherited::EvVScroll(scrollCode,thumbPos,hWndCtl);
if(IsFlagSet(cfHasCaret))
SetCaretPos(Text2Client(CursorPos));
}
//
void
TCoolTextWnd::EvMouseWheel(uint modKeys, int zDelta, const TPoint& point)
{
Inherited::EvMouseWheel(modKeys, zDelta, point);
if(IsFlagSet(cfHasCaret))
SetCaretPos(Text2Client(CursorPos));
}
//
void
TCoolTextWnd::AdjustTextPoint(TPoint& point)
{
point.x += GetCharWidth()/ 2; //todo
}
//
void
TCoolTextWnd::SelectAll()
{
int lineCount = GetNumLines();
CursorPos.col = GetLineLength(lineCount - 1);
CursorPos.row = lineCount - 1;
SetSelection(TEditRange(0, 0, CursorPos.col, CursorPos.row));
UpdateCaret();
}
//
void
TCoolTextWnd::DrawDraggedCurb(int position, bool redraw)
{
TRect rect;
GetClientRect(rect);
TClientDC dc(GetHandle());
if(redraw){
rect.left = TmpCurbPos-1;
rect.right = TmpCurbPos+1;
dc.DrawFocusRect(rect);
}
if(position < GetMarginWidth())
position = GetMarginWidth();
position = (position-GetMarginWidth())/GetCharWidth()*GetCharWidth()+GetMarginWidth();
rect.left = position-1;
rect.right = position+1;
dc.DrawFocusRect(rect);
TmpCurbPos = position;
}
//
void
TCoolTextWnd::EvLButtonDown(uint modKeys, const TPoint& point)
{
//_TRACE("TCoolTextWnd::EvLButtonDown()\n");
bool needRedraw = false;
bool bShift = modKeys & MK_SHIFT;
bool bControl = modKeys & MK_CONTROL;
bool bAlt = GetKeyState(VK_MENU)&0x8000;
//We don't need to capture the mouse - TScroller does it.
SetFlag(cfMouseDown);
if(point.x < GetMarginWidth()){
TPoint p(point);
AdjustTextPoint(p);
if(bControl){
SelectAll();
ClearFlag(cfMouseDown);
return;
}
else{
CursorPos = Client2Text(p);
CursorPos.col = 0; // set new position on start of line
TEditPos endPos(CursorPos);
endPos.col = GetLineLength(CursorPos.row); // Force full line
SetSelection(TEditRange(CursorPos, endPos));
UpdateCaret();
Inherited::EvLButtonDown(modKeys, p);
return;
}
}
// check Curb
int lineCurb = CurbPos == -1 ? -1 : ((CurbPos-GetOffsetChar())*GetCharWidth()+GetMarginWidth());
if(lineCurb >=0 && (point.x < (int)(lineCurb+3) && point.x > (int)(lineCurb-3))){
SetFlag(cfCurbDrag);
DrawDraggedCurb(point.x);
Inherited::EvLButtonDown(modKeys, point);
return;
}
CursorPos = Client2Text(point);
if(LastHit == point){
if(!Selection){
TEditPos startSel = StartWord(CursorPos);
CursorPos = EndWord(CursorPos);
if(startSel.Valid())
SetSelection(TEditRange(startSel, CursorPos));
}
else{
CursorPos.col = 0; // set new position on start of line
TEditPos endPos(CursorPos);
endPos.col = GetLineLength(CursorPos.row); // Force full line
SetSelection(TEditRange(CursorPos, endPos));
LastHit = TPoint(-1,-1);
}
ClearFlag(cfMouseDown);
UpdateCaret();
InvalidateLines(CursorPos.row, CursorPos.row);
return;
}
LastHit = point;
if(Selection){
if(bShift)
Selection->Extend(CursorPos);
else{
#if !defined(COOL_NODRAGDROP)
TEditPos textPos = Client2Text(point);
if(!IsFlagSet(cfNoDragDrop) && IsInSelection(textPos)){
//_TRACE("TCoolTextWnd::EvLButtonDown() Start pending\n");
SavedDragPos = point;
SetFlag(cfDragPending);
DragSelTimer = SetTimer(COOL_TIMER_DEBOUNCE, DragDropSupport.GetDelay());
}
else
#endif
{
delete Selection;
Selection = 0;
}
}
needRedraw = true;
}
// start selection
if(!Selection){
TSelType selType = SelType;
SelType = stStreamSelection;
if(bAlt)
SelType = stColumnSelection;
Selection = CreateSelection(TEditRange(CursorPos, CursorPos));
SelType = selType;
}
UpdateCaret();
if(needRedraw){
InvalidateLines(0, -1, false);
}
Inherited::EvLButtonDown(modKeys, point);
}
//
#if !defined(COOL_NODRAGDROP)
void
TCoolTextWnd::ExecuteDragDrop()
{
//_TRACE("TCoolTextWnd::ExecuteDragDrop() START\n");
if(DragSelTimer)
KillTimer(DragSelTimer);
DragSelTimer = 0;
ClearFlag(cfMouseDown);
ClearFlag(cfDragPending);
ReleaseCapture();
if (SetDragData()){
SetFlag(cfDraggingText);
Scroller->AutoMode = false; //workaround
//_TRACE("TCoolTextWnd::ExecuteDragDrop() Scroller->AutoMode = false\n");
DROPEFFECT de = DragDropSupport.DoDragDrop(GetDropEffect());
if (de != DROPEFFECT_NONE)
DropSource(de);
ClearFlag(cfDraggingText);
DragDropProxy->ResetDragData();
//_TRACE("TCoolTextWnd::ExecuteDragDrop() ResetDragData\n");
}
//_TRACE("TCoolTextWnd::ExecuteDragDrop() END\n");
}
//
TDragDropProxy*
TCoolTextWnd::SetDragDropProxy(TDragDropProxy* proxy)
{
TDragDropProxy* tmp = DragDropProxy;
DragDropProxy = proxy;
DragDropSupport.SetProxy(DragDropProxy);
return tmp;
}
#endif
//
void
TCoolTextWnd::EvMouseMove(uint modKeys, const TPoint& point)
{
if(IsFlagSet(cfMouseDown)){
if(IsFlagSet(cfCurbDrag)){
DrawDraggedCurb(point.x, true);
Inherited::EvMouseMove(modKeys, point);
return;
}
TEditPos startPos = CursorPos;
CursorPos = Client2Text(point);
if(point.x < GetMarginWidth()){
if(Selection){
TEditRange range(Selection->GetStart(), CursorPos);
range.ecol = GetLineLength(CursorPos.row); // Force full line
CursorPos.col = 0;
SetSelection(range);
}
}
else{
#if !defined(COOL_NODRAGDROP)
if(IsFlagSet(cfDragPending)){
if(DragDropSupport.CanDragDrop(SavedDragPos, point))
ExecuteDragDrop();
}
else
#endif
if(Selection)
Selection->Extend(CursorPos);
}
UpdateCaret();
InvalidateLines(startPos.row, CursorPos.row);
UpdateWindow();
}
Inherited::EvMouseMove(modKeys, point);
}
//
void
TCoolTextWnd::EvLButtonUp(uint modKeys, const TPoint& point)
{
//_TRACE("TCoolTextWnd::EvLButtonUp() START\n");
#if !defined(COOL_NODRAGDROP)
// Workaround in conflict Scroller->AutoMode and Drag-and-Drop
if(!Scroller->AutoMode){
Scroller->AutoMode = true;
return;
}
#endif
if(IsFlagSet(cfMouseDown)){
ClearFlag(cfMouseDown);
if(IsFlagSet(cfCurbDrag)){
ClearFlag(cfCurbDrag);
CurbPos = (((point.x-GetMarginWidth())/GetCharWidth()*GetCharWidth())/GetCharWidth())+GetOffsetChar();
DrawDraggedCurb(TmpCurbPos);
Inherited::EvLButtonUp(modKeys, point);
InvalidateLines(0, -1, false);
return;
}
InvalidateLines(0, -1, false);
CursorPos = Client2Text(point);
if(point.x < GetMarginWidth()){
if(Selection){
TEditRange range(Selection->GetStart(), CursorPos);
range.ecol = GetLineLength(CursorPos.row); // Force full line
CursorPos.col = 0;
SetSelection(range);
}
}
else{
#if !defined(COOL_NODRAGDROP)
if(IsFlagSet(cfDragPending)){
ClearFlag(cfDragPending);
delete Selection;
Selection = 0;
}
else
#endif
if(Selection)
Selection->Extend(CursorPos);
}
#if !defined(COOL_NODRAGDROP)
if(DragSelTimer)
KillTimer(DragSelTimer);
DragSelTimer = 0;
#endif
PostCheckSelection();
ReleaseCapture();
UpdateCaret();
}
//_TRACE("TCoolTextWnd::EvLButtonUp() Scroller->AutoMode = true\n");
Inherited::EvLButtonUp(modKeys, point);
}
//
void
TCoolTextWnd::EvLButtonDblClk(uint modKeys, const TPoint& point)
{
LastHit = point;
CursorPos = Client2Text(point);
TEditPos startSel = StartWord(CursorPos);
CursorPos = EndWord(CursorPos);
if(startSel.Valid())
SetSelection(TEditRange(startSel, CursorPos));
ClearFlag(cfMouseDown);
UpdateCaret();
InvalidateLines(CursorPos.row, CursorPos.row);
Inherited::EvLButtonDblClk(modKeys, point);
}
//
void
TCoolTextWnd::ResetView()
{
ClearFlag(cfBookmarkExist);
MaxLineLength = -1;
IdealCharPos = -1;
SelType = stStreamSelection;
delete Selection;
Selection = 0;
delete[] ParseCookies;
ParseCookies = 0;
ParseArraySize = 0;
ActualLengthArraySize = 0;
ActualLineLength = 0;
CursorPos.row = 0;
CursorPos.col = 0;
LastHit.x = -1;
LastHit.y = -1;
if(Scroller){
Scroller->XPos = 0;
Scroller->YPos = 0;
}
if(GetHandle())
UpdateCaret();
}
//
void
TCoolTextWnd::ScrollToCaret(const TEditPos& cursorPos)
{
int dx=0,dy=0;
VERIFY_TEXTPOS(cursorPos);
TPoint caretPos = Text2Client(cursorPos);
TRect clientRect;
GetClientRect(clientRect);
if(clientRect.IsEmpty())
return;
//
if(Scroller->YRange){
clientRect.bottom -= TUIMetric::CyHScroll;
if(clientRect.bottom%GetLineHeight())
clientRect.bottom -= clientRect.bottom%GetLineHeight();
}
if(Scroller->XRange){
clientRect.right -= TUIMetric::CyVScroll;
if(clientRect.right%GetCharWidth())
clientRect.right -= clientRect.right%GetCharWidth();
}
clientRect.left += GetMarginWidth();
if(!clientRect.Contains(caretPos)){
if(caretPos.x > clientRect.right)
dx = caretPos.x - clientRect.right;
else if (caretPos.x < clientRect.left)
dx = caretPos.x - clientRect.left;
if (caretPos.y > clientRect.bottom)
dy = caretPos.y - clientRect.bottom;
else if (caretPos.y < clientRect.top)
dy = caretPos.y - clientRect.top;
Scroller->ScrollBy(dx/GetCharWidth(),dy/GetLineHeight());
VERIFY_TEXTPOS(cursorPos);
caretPos = Text2Client(cursorPos);
}
SetCursorPos(Client2Text(caretPos));
}
//
#if __DEBUG > 0
void
TCoolTextWnd::VerifyTextPos(const TEditPos& pos)
{
if (GetNumLines() > 0){
CHECK(GetTopLine() >= 0 && GetOffsetChar() >= 0);
CHECK(pos.row >= 0 && pos.row < GetNumLines());
CHECK(pos.col >= 0 && (IsSmartCursor() && pos.col <= GetLineLength(pos.row)));
}
}
#endif
//
void
TCoolTextWnd::EvKeyDown(uint key, uint repeatCount, uint /*flags*/)
{
#if 1
bool is_shift = ::GetAsyncKeyState(VK_SHIFT) & MSB;
bool is_ctrl = ::GetAsyncKeyState(VK_CONTROL) & MSB;
#else
bool is_shift = flags & MK_SHIFT; //?????
bool is_ctrl = flags & MK_CONTROL;// ????
#endif
switch (key){
case VK_ESCAPE:
KeyEscape(repeatCount);
break;
case VK_RIGHT:
if(is_shift || IsColumnSelMode()){
if(is_ctrl)
ExtendWordRight(repeatCount);
else
ExtendRight(repeatCount);
}
else{
ClearSelection();
if(is_ctrl)
MoveWordRight(repeatCount);
else
MoveRight(repeatCount);
}
break;
case VK_LEFT:
if(is_shift || IsColumnSelMode()){
if(is_ctrl)
ExtendWordLeft(repeatCount);
else
ExtendLeft(repeatCount);
}
else{
ClearSelection();
if(is_ctrl)
MoveWordLeft(repeatCount);
else{
MoveLeft(repeatCount);
}
}
break;
case VK_DOWN:
if(is_ctrl){
if(!is_shift)
ScrollDown(repeatCount);
}
else{
if(is_shift || IsColumnSelMode())
ExtendDown(repeatCount);
else{
ClearSelection();
MoveDown(repeatCount);
}
}
break;
case VK_UP:
if(is_ctrl){
if(!is_shift)
ScrollUp(repeatCount);
}
else{
if(is_shift || IsColumnSelMode())
ExtendUp(repeatCount);
else{
ClearSelection();
MoveUp(repeatCount);
}
}
break;
case VK_NEXT: //Page Down
if(!is_ctrl){
if(is_shift || IsColumnSelMode())
ExtendPgDown(repeatCount);
else{
ClearSelection();
MovePgDown(repeatCount);
}
}
break;
case VK_PRIOR: //Page up
if(!is_ctrl){
if(is_shift || IsColumnSelMode())
ExtendPgUp(repeatCount);
else{
ClearSelection();
MovePgUp(repeatCount);
}
}
break;
case VK_HOME:
if(is_shift || IsColumnSelMode()){
if(is_ctrl)
ExtendCtrlHome(repeatCount);
else
ExtendHome(repeatCount);
}
else{
ClearSelection();
if(is_ctrl)
MoveCtrlHome(repeatCount);
else
MoveHome(repeatCount);
}
break;
case VK_END:
if(is_shift || IsColumnSelMode()){
if(is_ctrl)
ExtendCtrlEnd(repeatCount);
else
ExtendEnd(repeatCount);
}
else{
ClearSelection();
if(is_ctrl)
MoveCtrlEnd(repeatCount);
else
MoveEnd(repeatCount);
}
break;
//Also, we toggle the insert mode bit here
case VK_INSERT:
if(ToggleInsertStatus()){
ClearFlag(cfHasCaret);
ShowCursor();
}
break;
//Anything else is a character key - let windows have it
//back and we will catch it in EvChar.
default:
DefaultProcessing();
return; //NOTE - return not break!
}
//Inherited::EvKeyDown(key, repeatCount, flags); //????
}
//
void
TCoolTextWnd::KeyEscape(int /*repeatCount*/)
{
if(!IsStreamSelMode())
SelType = stStreamSelection;
else if(Selection)
ClearSelection();
else
DefaultProcessing();
}
//
void
TCoolTextWnd::ExtendWordRight(int repeatCount)
{
int lastLine = GetNumLines()-1;
if(CursorPos.row < lastLine ||
(CursorPos.row == lastLine && CursorPos.col < GetLineLength(lastLine))){
PreCheckSelection();
MoveWordRight(repeatCount);
Selection->Extend(CursorPos);
PostCheckSelection();
}
}
//
void
TCoolTextWnd::ExtendRight(int repeatCount)
{
int lastLine = GetNumLines()-1;
if(CursorPos.row < lastLine ||
(CursorPos.row == lastLine && CursorPos.col < GetLineLength(lastLine))){
PreCheckSelection();
int startPos = CursorPos.row;
CursorPos.col += repeatCount;
if( IsFlagSet(cfSmartCursor) && !IsColumnSelMode() &&
CursorPos.col > GetLineLength(CursorPos.row)){
if(CursorPos.row < GetNumLines()-1){
CursorPos.row++;
CursorPos.col = 0;
}
}
Selection->Extend(CursorPos);
PostCheckSelection();
ScrollToCaret(CursorPos);
InvalidateLines(startPos, CursorPos.row);
}
}
//
void
TCoolTextWnd::MoveWordRight(int repeatCount)
{
int lastLine = GetNumLines()-1;
if(CursorPos.row < lastLine ||
(CursorPos.row == lastLine && CursorPos.col < GetLineLength(lastLine))){
TEditPos pos(CursorPos);
while(repeatCount--){
if(pos.col == GetLineLength(pos.row)){
pos.col = 0;
if(pos.row < GetNumLines())
pos.row++;
}
pos = NextBreak(pos);
}
InvalidateLines(CursorPos.row, pos.row);
CursorPos = pos;
IdealCharPos = CalculateActualOffset(CursorPos.row, CursorPos.col);
ScrollToCaret(CursorPos);
}
}
//
void
TCoolTextWnd::MoveRight(int repeatCount)
{
int lastLine = GetNumLines()-1;
if(CursorPos.row < lastLine ||
(CursorPos.row == lastLine && CursorPos.col < GetLineLength(lastLine))){
int startPos = CursorPos.row;
CursorPos.col += repeatCount;
if(IsFlagSet(cfSmartCursor) && CursorPos.col > GetLineLength(CursorPos.row)){
if(CursorPos.row < GetNumLines()-1){
CursorPos.row++;
CursorPos.col = 0;
}
}
IdealCharPos = CalculateActualOffset(CursorPos.row, CursorPos.col);
ScrollToCaret(CursorPos);
InvalidateLines(startPos, CursorPos.row);
}
}
//
void
TCoolTextWnd::ExtendWordLeft(int repeatCount)
{
if(CursorPos.row > 0 || (CursorPos.row == 0 && CursorPos.col > 0)){
PreCheckSelection();
MoveWordLeft(repeatCount);
Selection->Extend(CursorPos);
PostCheckSelection();
}
}
//
void
TCoolTextWnd::PreCheckSelection()
{
if(!Selection)
Selection = CreateSelection(TEditRange(CursorPos, CursorPos));
}
//
void
TCoolTextWnd::PostCheckSelection()
{
if(Selection && Selection->IsEmpty() && !IsColumnSelMode()){
delete Selection;
Selection = 0;
}
}
//
void
TCoolTextWnd::ExtendLeft(int repeatCount)
{
if(CursorPos.row > 0 || (CursorPos.row == 0 && CursorPos.col > 0)){
int startPos = CursorPos.row;
PreCheckSelection();
CursorPos.col -= repeatCount;
if(CursorPos.col < 0){
if(CursorPos.row > 0 && !IsColumnSelMode() &&
IsFlagSet(cfSmartCursor)){
CursorPos.row--;
CursorPos.col = GetLineLength(CursorPos.row);
}
else
CursorPos.col = 0;
}
IdealCharPos = CalculateActualOffset(CursorPos.row, CursorPos.col);
ScrollToCaret(CursorPos);
InvalidateLines(startPos, CursorPos.row);
Selection->Extend(CursorPos);
PostCheckSelection();
}
}
//
void
TCoolTextWnd::MoveWordLeft(int repeatCount)
{
if(CursorPos.row>0 || (CursorPos.row==0 && CursorPos.col>0)){
TEditPos pos = CursorPos;
while(repeatCount--){
if(pos.col <= 0){
if(pos.row > 0)
pos.row--;
pos.col = GetLineLength(pos.row);
}
pos = PrevBreak(pos);
}
InvalidateLines(CursorPos.row, pos.row);
CursorPos = pos;
IdealCharPos = CalculateActualOffset(CursorPos.row, CursorPos.col);
ScrollToCaret(CursorPos);
}
}
//
void
TCoolTextWnd::MoveLeft(int repeatCount)
{
if(CursorPos.row>0 || (CursorPos.row==0 && CursorPos.col>0)){
int startPos = CursorPos.row;
CursorPos.col -= repeatCount;
if(CursorPos.col < 0){
if(CursorPos.row > 0 && IsFlagSet(cfSmartCursor)){
CursorPos.row--;
CursorPos.col = GetLineLength(CursorPos.row);
}
else
CursorPos.col = 0;
}
IdealCharPos = CalculateActualOffset(CursorPos.row, CursorPos.col);
ScrollToCaret(CursorPos);
InvalidateLines(startPos, CursorPos.row);
}
}
//
void
TCoolTextWnd::ExtendDown(int repeatCount)
{
if(CursorPos.row < GetNumLines()-1){
int startPos = CursorPos.row;
PreCheckSelection();
CursorPos.row += repeatCount;
if(CursorPos.row > GetNumLines()-1)
CursorPos.row = GetNumLines()-1;
if(!IsColumnSelMode())
AdjustXCurPos();
Selection->Extend(CursorPos);
PostCheckSelection();
ScrollToCaret(CursorPos);
InvalidateLines(startPos, CursorPos.row);
}
}
//
void
TCoolTextWnd::MoveDown(int repeatCount)
{
if(CursorPos.row < GetNumLines()-1){
int startPos = CursorPos.row;
CursorPos.row += repeatCount;
if(CursorPos.row > GetNumLines()-1)
CursorPos.row = GetNumLines()-1;
AdjustXCurPos();
ScrollToCaret(CursorPos);
InvalidateLines(startPos, CursorPos.row);
}
}
//
void
TCoolTextWnd::ExtendUp(int repeatCount)
{
if(CursorPos.row > 0){
int startPos = CursorPos.row;
PreCheckSelection();
CursorPos.row -= repeatCount;
if(CursorPos.row < 0)
CursorPos.row = 0;
if(!IsColumnSelMode())
AdjustXCurPos();
Selection->Extend(CursorPos);
PostCheckSelection();
ScrollToCaret(CursorPos);
InvalidateLines(startPos, CursorPos.row);
}
}
//
void
TCoolTextWnd::MoveUp(int repeatCount)
{
if(CursorPos.row > 0){
int startPos = CursorPos.row;
CursorPos.row -= repeatCount;
if(CursorPos.row < 0)
CursorPos.row = 0;
AdjustXCurPos();
ScrollToCaret(CursorPos);
InvalidateLines(startPos, CursorPos.row);
}
}
//
void
TCoolTextWnd::ExtendPgDown(int repeatCount)
{
if(CursorPos.row < GetNumLines()-1){
int startPos = CursorPos.row;
int topLine = GetTopLine();
int delta = repeatCount*GetScreenLines() - 1;
int newTopLine= topLine + delta;
if(newTopLine >= GetNumLines())
newTopLine = GetNumLines() - 1;
if(topLine != newTopLine){
PreCheckSelection();
CursorPos.row += delta;
if(CursorPos.row >= GetNumLines())
CursorPos.row = GetNumLines() - 1;
if(!IsColumnSelMode())
AdjustXCurPos();
Scroller->ScrollBy(0, newTopLine-topLine);
Selection->Extend(CursorPos);
PostCheckSelection();
ScrollToCaret(CursorPos);
InvalidateLines(startPos, CursorPos.row);
}
}
}
//
void
TCoolTextWnd::MovePgDown(int repeatCount)
{
if(CursorPos.row < GetNumLines()-1){
int startPos = CursorPos.row;
int topLine = GetTopLine();
int delta = repeatCount*GetScreenLines() - 1;
int newTopLine= topLine + delta;
if(newTopLine >= GetNumLines())
newTopLine = GetNumLines() - 1;
if(topLine != newTopLine){
CursorPos.row += delta;
if(CursorPos.row >= GetNumLines())
CursorPos.row = GetNumLines() - 1;
AdjustXCurPos();
Scroller->ScrollBy(0, newTopLine-topLine);
ScrollToCaret(CursorPos);
InvalidateLines(startPos, CursorPos.row);
}
}
}
//
void
TCoolTextWnd::ExtendPgUp(int repeatCount)
{
if(CursorPos.row > 0){
int startPos = CursorPos.row;
int topLine = GetTopLine();
int delta = repeatCount*GetScreenLines() - 1;
int newTopLine = topLine - delta;
if (newTopLine < 0)
newTopLine = 0;
if(topLine != newTopLine || CursorPos.row>0){
PreCheckSelection();
CursorPos.row -= delta;
if(CursorPos.row < 0)
CursorPos.row = 0;
if(!IsColumnSelMode())
AdjustXCurPos();
Scroller->ScrollBy(0, newTopLine-topLine);
Selection->Extend(CursorPos);
PostCheckSelection();
ScrollToCaret(CursorPos);
InvalidateLines(startPos, CursorPos.row);
}
}
}
//
void
TCoolTextWnd::MovePgUp(int repeatCount)
{
if(CursorPos.row > 0){
int startPos = CursorPos.row;
int topLine = GetTopLine();
int delta = repeatCount*GetScreenLines() - 1;
int newTopLine = topLine - delta;
if (newTopLine < 0)
newTopLine = 0;
if(topLine != newTopLine || CursorPos.row>0){
CursorPos.row -= delta;
if(CursorPos.row < 0)
CursorPos.row = 0;
AdjustXCurPos();
Scroller->ScrollBy(0, newTopLine-topLine);
ScrollToCaret(CursorPos);
InvalidateLines(startPos, CursorPos.row);
}
}
}
//
void
TCoolTextWnd::ExtendCtrlHome(int /*repeatCount*/)
{
if(CursorPos.col || CursorPos.row){
int startPos = CursorPos.row;
PreCheckSelection();
CursorPos.col = 0;
CursorPos.row = 0;
Selection->Extend(CursorPos);
PostCheckSelection();
ScrollToCaret(CursorPos);
InvalidateLines(startPos, CursorPos.row);
}
}
//
void
TCoolTextWnd::MoveCtrlHome(int /*repeatCount*/)
{
if(CursorPos.col || CursorPos.row){
int startPos = CursorPos.row;
CursorPos.col = 0;
CursorPos.row = 0;
ScrollToCaret(CursorPos);
InvalidateLines(startPos, CursorPos.row);
}
}
//
void
TCoolTextWnd::ExtendHome(int /*repeatCount*/)
{
if(CursorPos.col){
int startPos = CursorPos.row;
PreCheckSelection();
CursorPos.col = 0;
Selection->Extend(CursorPos);
PostCheckSelection();
ScrollToCaret(CursorPos);
InvalidateLines(startPos, CursorPos.row);
}
}
//
void
TCoolTextWnd::MoveHome(int /*repeatCount*/)
{
if(CursorPos.col){
int startPos = CursorPos.row;
CursorPos.col = 0;
ScrollToCaret(CursorPos);
InvalidateLines(startPos, CursorPos.row);
}
}
//
void
TCoolTextWnd::ExtendCtrlEnd(int /*repeatCount*/)
{
int endLine = GetNumLines()-1;
TEditPos endPos(GetLineLength(endLine), endLine);
if(CursorPos != endPos){
int startPos = CursorPos.row;
PreCheckSelection();
CursorPos = endPos;
Selection->Extend(CursorPos);
PostCheckSelection();
ScrollToCaret(CursorPos);
InvalidateLines(startPos, CursorPos.row);
}
}
//
void
TCoolTextWnd::MoveCtrlEnd(int /*repeatCount*/)
{
int endLine = GetNumLines()-1;
TEditPos endPos(GetLineLength(endLine), endLine);
if(CursorPos != endPos){
int startPos = CursorPos.row;
CursorPos = endPos;
ScrollToCaret(CursorPos);
InvalidateLines(startPos, CursorPos.row);
}
}
//
void
TCoolTextWnd::ExtendEnd(int /*repeatCount*/)
{
int endPos = GetLineLength(CursorPos.row);
if(CursorPos.col != endPos){
PreCheckSelection();
CursorPos.col = endPos;
Selection->Extend(CursorPos);
PostCheckSelection();
ScrollToCaret(CursorPos);
InvalidateLines(CursorPos.row, CursorPos.row);
}
}
//
void
TCoolTextWnd::MoveEnd(int /*repeatCount*/)
{
int endPos = GetLineLength(CursorPos.row);
if(CursorPos.col != endPos){
CursorPos.col = endPos;
ScrollToCaret(CursorPos);
InvalidateLines(CursorPos.row, CursorPos.row);
}
}
//
void
TCoolTextWnd::ScrollDown(int repeatCount)
{
if(Scroller->YPos < Scroller->YRange){
if((int)repeatCount > (Scroller->YRange-Scroller->YPos))
repeatCount = Scroller->YRange - Scroller->YPos;
Scroller->ScrollBy(0,repeatCount);
CursorPos.row += repeatCount;
if(CursorPos.row >= GetNumLines())
CursorPos.row = GetNumLines()-1;
if(IsFlagSet(cfSmartCursor)){
int len = GetLineLength(CursorPos.row);
if(CursorPos.col > len)
CursorPos.col = len;
}
SetCursorPos(CursorPos);
}
}
//
void
TCoolTextWnd::ScrollUp(int repeatCount)
{
if (Scroller->YPos > 0)
{
if ((int)repeatCount > Scroller->YPos)
repeatCount = Scroller->YPos;
Scroller->ScrollBy(0,-(int)repeatCount);
CursorPos.row -= repeatCount;
if(CursorPos.row < 0)
CursorPos.row = 0;
if(IsFlagSet(cfSmartCursor))
{
int len = GetLineLength(CursorPos.row);
if(CursorPos.col > len)
CursorPos.col = len;
}
SetCursorPos(CursorPos);
}
}
//
LPCTSTR TCoolTextWnd::GetBreakChars() const
{
static const _TCHAR* breakChars = _T("\"\\\t +-=*/~!@#$%^&(){}[]<>'?.,;:");
return breakChars;
}
//
static bool isWordChar(_TCHAR c)
{
return _istalnum(c) || c==_T('_');
}
//
TEditPos TCoolTextWnd::StartWord(const TEditPos& pos)
{
//First skip over any non aski or digit char
LPCTSTR pszChars = GetLineText(pos.row);
int nPos = pos.col;
if(nPos == GetLineLength(pos.row))
nPos--;
// if on whitespace -> find start of word
while(nPos > 0 && isWordChar(pszChars[nPos]))
nPos--;
if(nPos) // if not start position -> nPos points on first space
nPos++;
return TEditPos(nPos, pos.row);
}
//
TEditPos
TCoolTextWnd::EndWord(const TEditPos& pos)
{
//First skip over any non aski or digit char
LPCTSTR pszChars = GetLineText(pos.row);
int len = GetLineLength(pos.row);
int nPos = pos.col;
// if on whitespace -> find start of word
while(nPos < len && isWordChar(pszChars[nPos]))
nPos++;
return TEditPos(nPos, pos.row);
}
//
TEditPos
TCoolTextWnd::NextBreak(const TEditPos& pos)
{
//Find the first break char AFTER Col
//First skip over any break chars we are sitting on
LPCTSTR breakChars = GetBreakChars();
LPCTSTR pszChars = GetLineText(pos.row);
int len = GetLineLength(pos.row);
int nPos = pos.col;
bool isBreakChar = _tcschr(breakChars, pszChars[nPos]);
// if BreakChar -> skip until non break
if(isBreakChar){
while(nPos < len && _tcschr(breakChars, pszChars[nPos]))
nPos++;
}
else{ // else find next break char
int npos = len>0 ? static_cast<int>(_tcscspn(&pszChars[nPos], breakChars)) : 0;
if(npos)
nPos += npos;
else
nPos = GetLineLength(pos.row);
}
return TEditPos(nPos, pos.row);
}
//
TEditPos
TCoolTextWnd::PrevBreak(const TEditPos& pos)
{
//Find the first break char BEFORE Col
//First skip over any break chars we are sitting on
LPCTSTR breakChars = GetBreakChars();
LPCTSTR pszChars = GetLineText(pos.row);
int nPos = pos.col-1;
bool isBreakChar = _tcschr(breakChars, pszChars[nPos]);
if(isBreakChar){
// skip any break characters
while(nPos > 0 && _tcschr(breakChars, pszChars[nPos]))
nPos--;
}
else{
//Then Skip over any non-break chars to the next break
while(nPos > 0 && _tcsrchr(breakChars, pszChars[nPos])==0)
nPos--;
}
if(nPos)
nPos++;
return TEditPos(nPos,pos.row);
}
//
void
TCoolTextWnd::AdjustXCurPos()
{
if(IsFlagSet(cfSmartCursor)){
int len = GetLineLength(CursorPos.row);
if(CursorPos.col > len)
CursorPos.col = len;
}
}
//
void
TCoolTextWnd::SetSelMode(TSelType newType)
{
if(newType != SelType){
SelType = newType;
if(Selection){
TEditRange range(Selection->GetStart(),Selection->GetEnd());
SetSelection(range);
}
}
}
//
bool
TCoolTextWnd::GetSelection(TEditRange& range)
{
range = TEditRange();
if(Selection){
range = TEditRange(Selection->GetStart(), Selection->GetEnd());
range.Normalize();
}
return true;
}
//
#if !defined(COOL_NODRAGDROP)
DROPEFFECT
TCoolTextWnd::GetDropEffect()
{
//_TRACE("TCoolTextWnd::GetDropEffect\n");
return DROPEFFECT_COPY;
}
//
void
TCoolTextWnd::DropSource(DROPEFFECT de)
{
CHECK(de == DROPEFFECT_COPY); InUse(de);
//_TRACE("TCoolTextWnd::DropSource\n");
}
//
void
TCoolTextWnd::DropText(IDataObject*, const TPoint&, DROPEFFECT)
{
//_TRACE("TCoolTextWnd::DropText\n");
// nothing
}
//
bool
TCoolTextWnd::SetDragData()
{
if(Selection){
tostringstream ostrm;
Selection->Copy(ostrm);
LPCTSTR text = ostrm.str().c_str();
uint len = static_cast<int>(_tcslen(text));
// Allocate a global memory object for the text.
HGLOBAL hHandle = ::GlobalAlloc(GMEM_DDESHARE, len);
if (hHandle){
// Lock the handle and copy the text to the buffer.
void* pBlock = ::GlobalLock(hHandle);
memcpy(pBlock, text, len);
::GlobalUnlock(hHandle);
// Place the handle on the clipboard, as internal format.
DragDropProxy->SetDragData(SelClipFormat, hHandle);
}
else
{
return false;
}
// Allocate a global memory object for the text.
HGLOBAL hHandle1 = ::GlobalAlloc(GMEM_DDESHARE, len-7);
if (hHandle1){
// Lock the handle and copy the text to the buffer.
void* pBlock = ::GlobalLock(hHandle1);
memcpy(pBlock, text+7, len-7);
::GlobalUnlock(hHandle1);
// Place the handle on the clipboard, as visible format.
#ifdef _UNICODE
DragDropProxy->SetDragData(CF_UNICODETEXT, hHandle1);
#else
DragDropProxy->SetDragData(CF_TEXT, hHandle1);
#endif
}
// Allocate a global memory object for the text.
HGLOBAL hHandle2 = ::GlobalAlloc(GMEM_DDESHARE, len-7);
if (hHandle1){
// Lock the handle and copy the text to the buffer.
void* pBlock = ::GlobalLock(hHandle2);
USES_CONVERSION;
#ifdef _UNICODE
memcpy(pBlock, W2A(text+7), len-7);
#else
memcpy(pBlock, A2W(text+7), len-7);
#endif
::GlobalUnlock(hHandle2);
// Place the handle on the clipboard, as visible format.
#ifdef _UNICODE
DragDropProxy->SetDragData(CF_TEXT, hHandle2);
#else
DragDropProxy->SetDragData(CF_UNICODETEXT, hHandle2);
#endif
}
return true;
}
return false;
}
#endif
//
void
TCoolTextWnd::WordUnderCursor(LPTSTR text, uint size)
{
*text = 0;
TEditRange range;
if(IsSelection()){
GetSelection(range);
}
else{
range = TEditRange(StartWord(GetCursorPos()), EndWord(GetCursorPos()));
range.Normalize();
}
if(range.Valid() && !range.Empty()){
GetBuffer()->GetText(range.Start(), range.End(), text, size);
}
}
//
bool
TCoolTextWnd::Search(const TEditPos& _startPos, LPCTSTR text,
TFindFlags flags /*= ffNone*/)
{
if (!text || !text[0])
return false;
TCoolTextBuffer* buffer = GetBuffer();
TEditPos startPos(_startPos);
if(!startPos.Valid())
startPos = CursorPos;
TEditPos endPos;
if(flags&ffWholeDoc){
startPos = TEditPos(-1,-1);
endPos = TEditPos(-1,-1);
}
else{
if(flags&ffDirectionUp)
endPos = TEditPos(0,0);
else{
int lastLine = buffer->GetLineCount()-1;
TEditPos(buffer->GetLineLength(lastLine),lastLine);
}
}
TEditRange searchRange(startPos,endPos);
searchRange.Normalize();
TEditPos resPos = buffer->Search(searchRange, text,
ToBool(flags&ffMatchCase),
ToBool(flags&ffWholeWord),
ToBool(flags&ffDirectionUp));
// If we've got a match, select that text, cleanup & return.
//
if(resPos.Valid()){
TEditRange resRange(resPos.col, resPos.row, resPos.col + static_cast<int>(_tcslen(text)), resPos.row);
SetSelection(resRange);
CursorPos = resRange.End();
ScrollToCaret(CursorPos);
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// class TBruteForceEngine
// ~~~~~ ~~~~~~~~~~~~~~~~~~
//
//
TEditRange
TBruteForceEngine::Search(TCoolTextBuffer& buffer,const TEditRange& searchRange)
{
TEditPos resPos = buffer.Search(searchRange,Pattern.c_str(),CaseSens,
WholeWord, DirectUp);
return
resPos.Valid()
?
TEditRange(resPos.col, resPos.row, resPos.col + static_cast<int>(Pattern.length()), resPos.row)
:
TEditRange();
}
//-----------------------------------------------------------------------------
// class TBoyerMooreEngine
// ~~~~~ ~~~~~~~~~~~~~~~~~
//
//
const size_t TBoyerMooreEngine::DeltaSize = 256;
//
TBoyerMooreEngine::TBoyerMooreEngine(const tstring& pattern, bool caseSens,
bool wholeWord, bool up)
:
Pattern(pattern.c_str()),
CaseSens(caseSens),
WholeWord(wholeWord),
DirectUp(up)
{
if(!CaseSens)
_tcslwr((LPTSTR)Pattern.c_str());
// allocate delta table
DeltaTable = new uint[DeltaSize];
// clear table
int i;
// get length of pattern
int patlen = static_cast<int>(Pattern.length());
for(i = 0; i < DeltaSize; i++)
DeltaTable[i] = patlen;
if(DirectUp){
// set table values
for (i = patlen-1; i >= 0; i--)
DeltaTable[(size_t)Pattern[i]] = i;
// set value for first pattern character
//DeltaTable[(size_t)Pattern[patlen-1]] = patlen-1;
}
else{
// set table values
for (i = 1; i < patlen; i++)
DeltaTable[(size_t)Pattern[i-1]] = patlen - i;
// set value for last pattern character
DeltaTable[(size_t)Pattern[patlen - 1]] = 1;
}
}
//
TBoyerMooreEngine::~TBoyerMooreEngine()
{
delete DeltaTable;
}
//
static bool
charCompare(_TCHAR ch1, _TCHAR ch2, bool caseSens)
{
if(!caseSens)
return ch1 == _totlower(ch2);
return ch1 == ch2;
}
//
static LPCTSTR
BoyerMooreSearchFrw(int patlen, LPCTSTR pattern, LPCTSTR text, int strLength,
uint* table, bool caseSens)
{
// i is the index into the target
int j, lastIndex, i = patlen;
lastIndex = i;
while(i <= strLength){
// j is an index into pattern
j = patlen;
// while corresponding characters match
while(charCompare(pattern[j - 1], text[i - 1], caseSens)){
if(j > 1){// move left one character for next comparison
j--,i--;
}
else// we've reached the beginning of the pattern pattern found!
return &text[i - 1];
}
// move target index by delta value of mismatched character
while(true){
if(caseSens)
i += table[text[i - 1]];
else
i += table[_totlower(text[i - 1])];
if(lastIndex < i)
break;
}
lastIndex = i;
}
return 0;
}
//
static LPCTSTR
BoyerMooreSearchBk(int patlen, LPCTSTR pattern, LPCTSTR text, int posIndex,
uint* table, bool caseSens)
{
// i is the index into the target
int j, i = posIndex-patlen;
while(i >= 0){
// j is an index into pattern
j = 0;
// while corresponding characters match
while(charCompare(pattern[j], text[i], caseSens)){
if(j < patlen-1){
// move right one character for next comparison
j++;i++;
}
else{
// we've reached the end of the pattern found!
return &text[i - patlen+1];
}
}
// move target index by delta value of mismatched character
if(caseSens)
i -= table[text[i]];
else
i -= table[_totlower(text[i])];
}
return 0;
}
//
TEditRange
TBoyerMooreEngine::Search(TCoolTextBuffer& buffer, const TEditRange& _range)
{
// store pattern length locally (it gets used a lot)
int patlen = static_cast<int>(Pattern.length());
TEditRange searchRange(_range);
if(!searchRange.Valid()){
// if not valid -> all file
searchRange.scol = 0;
searchRange.srow = 0;
searchRange.erow = buffer.GetLineCount()-1;
searchRange.ecol = buffer.GetLineLength(searchRange.srow);
}
searchRange.Normalize();
LPCTSTR pos = 0;
int lineIndex = DirectUp ? searchRange.erow : searchRange.srow;
int posIndex = searchRange.scol;
LPTSTR text = buffer.GetLineText(lineIndex);
while(true){
if(DirectUp){
if(posIndex < searchRange.srow){
lineIndex--;
if(lineIndex < searchRange.srow)
break;
text = buffer.GetLineText(lineIndex);
posIndex = buffer.GetLineLength(lineIndex);
}
pos = BoyerMooreSearchBk(patlen,
Pattern.c_str(),
text,
posIndex,
DeltaTable,
CaseSens);
}
else {
if(posIndex > buffer.GetLineLength(lineIndex)){
lineIndex++;
if(lineIndex>=buffer.GetLineCount() || lineIndex>=searchRange.erow)
break;
text = buffer.GetLineText(lineIndex);
posIndex = 0;
}
pos = BoyerMooreSearchFrw(patlen,
Pattern.c_str(),
text+posIndex,
buffer.GetLineLength(lineIndex)-posIndex,
DeltaTable,
CaseSens);
}
// If whole-word matching is enabled and we have a match so far, then make
// sure the match is on word boundaries.
//
if (WholeWord && pos){
#if defined(BI_DBCS_SUPPORT)
LPTSTR prevPos;
if (pos > text)
prevPos = ::AnsiPrev(text, pos);
if ((pos > text && _istalnum((_TCHAR)*prevPos)) || // Match is in preceding word
(Pattern.length() < static_cast<int>(_tcslen(pos)) && _istalnum(pos[Pattern.length()])))
{
if(DirectUp)
posIndex = (uint)(prevPos - text) + Pattern.length();
else
posIndex = (uint)(::AnsiNext(pos) - text);
continue; // Skip this match and keep searching
}
#else
if ((pos > text && _istalnum(pos[-1])) || // Match is in preceding word
(Pattern.length() < static_cast<int>(_tcslen(pos)) && _istalnum(pos[Pattern.length()])))
{
//Jogy: up -> DirectUp
posIndex = (uint)(pos-text) + !DirectUp;
continue; // Skip this match and keep searching
}
#endif
}
if(pos)
break;
else
posIndex = DirectUp ? -1 : buffer.GetLineLength(lineIndex)+1;
}
// If we've got a match, select that text, cleanup & return.
//
if(pos)
return TEditRange(static_cast<int>(pos - text), lineIndex, static_cast<int>(pos - text + Pattern.length()), lineIndex);
return TEditRange();
}
//-----------------------------------------------------------------------------
// class TRegularExEngine
// ~~~~~ ~~~~~~~~~~~~~~~~
// regular expressions
typedef _TUCHAR PatternType;
//
static int makepat(const _TCHAR* exp, PatternType* pat, size_t maxpattern);
//
const size_t TRegularExEngine::MaxPat=128;
//
TRegularExEngine::TRegularExEngine(const tstring& pattern, bool caseSens,
bool wholeWord, bool up)
:
CaseSens(caseSens),
WholeWord(wholeWord),
DirectUp(up)
{
Pattern = new PatternType[MaxPat];
Status = makepat(pattern.c_str(), Pattern, MaxPat);
}
//
typedef _TUCHAR pattern; /* pattern strings are unsigned char / t_wchar */
static const _TCHAR* matchs( const _TCHAR*, const _TCHAR*, const pattern*, _TCHAR**);
//
TEditRange
TRegularExEngine::Search(TCoolTextBuffer& buffer, const TEditRange& _sRange)
{
TEditRange searchRange(_sRange);
if(!searchRange.Valid()){
// if not valid -> all file
searchRange.scol = 0;
searchRange.srow = 0;
searchRange.erow = buffer.GetLineCount()-1;
searchRange.ecol = buffer.GetLineLength(searchRange.srow);
}
searchRange.Normalize();
PRECONDITION(Status==0);
int lineIndex = DirectUp ? searchRange.erow : searchRange.srow;
//int posIndex = DirectUp ? searchRange.ecol : searchRange.scol;
int posIndex = searchRange.scol;
uint numLines = buffer.GetLineCount();
_TCHAR* startp = 0;
const _TCHAR* endp = 0; InUse(endp);
LPCTSTR text = 0; InUse(text);
while(true){
text = buffer.GetLineText(lineIndex);
int lineLen = buffer.GetLineLength(lineIndex);
LPCTSTR endpos = text + lineLen;
if(searchRange.erow == searchRange.srow && searchRange.ecol < lineLen)
endpos = text + searchRange.ecol;
endp = matchs(text+posIndex, endpos, Pattern, &startp);
if(endp)
break;
if(DirectUp){
lineIndex--;
if(lineIndex < 0)
break;
}
else{
lineIndex++;
if(lineIndex >= (int)numLines)
break;
}
}
if(endp)
return TEditRange(static_cast<int>(startp - text), lineIndex, static_cast<int>(endp - text + 1), lineIndex);
return TEditRange();
}
/*
*
* Author: Allen I. Holub
*
* (c) C Gazette. May be used freely as long as author and publication are
* acknowledged
*
*/
/*
*
* Modified by Borland International to compile without warnings as C++.
*
* Modified by Yura Bidus to support UNICODE.
*/
/* Metacharacters in the input: */
#define BOL _T('^') /* start-of-line anchor */
#define EOL _T('$') /* end-of-line anchor */
#define ANY _T('.') /* matches any character */
#define CCL _T('[') /* start a character class */
#define CCLEND _T(']') /* end a character class */
#define NCCL _T('^') /* negates character class if 1st char. */
#define CLOSURE _T('*') /* Kleene closure (matches 0 or more) */
#define PCLOSE _T('+') /* Positive closure (1 or more) */
#define OPT _T('?') /* Optional closure (0 or 1) */
//
typedef enum action { /* These are put in the pattern string */
/* to represent metacharacters. */
M_BOL = (0x80 | _T('^')),
M_EOL = (0x80 | _T('$')),
M_ANY = (0x80 | _T('.')),
M_CCL = (0x80 | _T('[')),
M_OPT = (0x80 | _T('?')),
M_CLOSE = (0x80 | _T('*')),
M_PCLOSE = (0x80 | _T('+'))
} action;
#define IS_ACTION(x) ((x)&0x80) /* true => element of pat. string is an */
/* action that represents a metacharacter */
/*--------------------------------------------------------------------------*/
#define MAPSIZE 16 /* need this many bytes for character class bit map */
/* Advance a pointer into the pattern template */
/* to the next pattern element, this is a +1 for */
/* all pattern elements but M_CCL, where you */
/* to skip past both the M_CCL character and the */
/* bitmap that follows that character */
#define ADVANCE(pat) (pat += (*pat == (pattern)M_CCL) ? (MAPSIZE+1) : 1)
/* Bitmap functions. Set bit b in the map and */
/* test bit b to see if it was set previously. */
#define SETBIT(b,map) ((map)[((b) & 0x7f) >>3] |= (1<< ((b) & 0x07)) )
#define TSTBIT(b,map) ((map)[((b) & 0x7f) >>3] & (1<< ((b) & 0x07)) )
/*----------------------------------------------------------------------*/
#define E_NONE 0 /* Possible return values from pat_err. */
#define E_ILLEGAL 1 /* Set in makepat() to indicate prob- */
#define E_NOMEM 2 /* lems that came up while making the */
#define E_PAT 3 /* pattern template. */
/*----------------------------------------------------------------------*/
static const _TCHAR* doccl(pattern*, const _TCHAR*);
static int hex2bin(int);
static int makepat( const _TCHAR*, pattern*, size_t);
static int oct2bin(int);
static int omatch(const _TCHAR**, const pattern*, const _TCHAR*);
static const _TCHAR* patcmp(const _TCHAR*, const pattern*, const _TCHAR*);
static int esc( const _TCHAR**);
/*----------------------------------------------------------------------*/
static int
makepat(const _TCHAR* exp, pattern* pat, size_t maxpat)
// char *exp; /* Regular expression */
// pattern *pat; /* Assembled compiled pattern */
// int maxpat; /* Length of pat */
{
/* Make a pattern template from the string pointed to by exp. Stop when */
/* '\0' or '\n' is found in exp. The pattern template is assembled */
/* in pat whose length is given by maxpat. */
/* */
/* Return: */
/* E_ILLEGAL Illegal input pattern. */
/* E_NOMEM out of memory. */
/* E_PAT pattern too long. */
pattern* cur; /* pointer to current pattern element */
pattern* prev; /* pointer to previous pattern element */
int Error = E_ILLEGAL;
if(!*exp || *exp == _T('\n'))
goto exit;
if (*exp == CLOSURE || *exp == PCLOSE || *exp == OPT)
goto exit;
Error = E_NOMEM;
if (!pat)
goto exit; /* Check for bad pat */
prev = cur = pat;
Error = E_PAT;
while(*exp && *exp != _T('\n')) {
if(cur >= &pat[maxpat - 1])
goto exit;
switch (*exp) {
case ANY:
*cur = (pattern)M_ANY;
prev = cur++;
++exp;
break;
case BOL:
*cur = (cur == pat) ? (pattern)M_BOL : *exp;
prev = cur++;
++exp;
break;
case EOL:
*cur = (!exp[1] || exp[1] == _T('\n')) ? (pattern)M_EOL : *exp;
prev = cur++;
++exp;
break;
case CCL:
if (uint((cur - pat) + MAPSIZE) >= maxpat)
goto exit; /* not enough room for bit map */
prev = cur;
*cur++ = (pattern)M_CCL;
exp = doccl(cur, exp);
cur += MAPSIZE;
break;
case OPT:
case CLOSURE:
case PCLOSE:
switch (*prev){
case M_BOL:
case M_EOL:
case M_OPT:
case M_PCLOSE:
case M_CLOSE:
goto exit;
}
/* memmove( prev+1, prev, cur-prev ); */
{
pattern *p = cur;
while (p > prev) {
*p = *(p - 1);
p--;
}
}
*prev = (*exp == OPT) ? (pattern)M_OPT :
((*exp == PCLOSE) ? (pattern)M_PCLOSE : (pattern)M_CLOSE);
++cur;
++exp;
break;
default:
prev = cur;
*cur++ = (pattern)esc(&exp);
break;
}
}
*cur = _T('\0');
Error = E_NONE;
exit:
return Error;
}
/*----------------------------------------------------------------------*/
static const _TCHAR*
doccl( pattern* map, const _TCHAR* src)
{
/* Set bits in the map corresponding to characters specified in the src */
/* character class. */
int first, last, negative;
const _TCHAR* start;
++src; /* skip past the [ */
negative = (*src == NCCL);
if (negative) /* check for negative ccl */
++src;
start = src; /* start of characters in class */
memset(map, 0, MAPSIZE); /* bitmap initially empty */
while (*src && *src != CCLEND) {
if (*src != _T('-')) {
first = esc(&src); /* Use temp. to avoid macro */
SETBIT(first, map); /* side effects. */
}
else if (src == start) {
SETBIT(_T('-'), map); /* literal dash at start or end */
++src;
}
else{
++src; /* skip to end-of-sequence char */
if (*src < src[-2]) {
first = *src;
last = src[-2];
}
else {
first = src[-2];
last = *src;
}
while (++first <= last)
SETBIT(first, map);
src++;
}
}
if (*src == CCLEND)
++src; /* Skip CCLEND */
if (negative)
for (first = MAPSIZE; --first >= 0;)
*map++ ^= ~0; /* invert all bits */
return src;
}
/*----------------------------------------------------------------------*/
static const _TCHAR*
matchs( const _TCHAR* str, const _TCHAR* ends, const pattern* pat, _TCHAR** startpat)
{
const _TCHAR * endp = 0;
const _TCHAR * start;
if (!pat)
return NULL;
if(str == ends){
if ((*pat == (pattern)M_EOL) || (*pat == (pattern)M_BOL && (!pat[1] || pat[1] == (pattern)M_EOL)))
endp = str;
}
else{
start = str; /* Do a brute-force substring search, */
/* comparing a pattern against the input string */
while( str != ends) {
endp = patcmp(str, pat, start);
if(endp)
break;
str++;
}
}
*startpat = (_TCHAR*)str;
return endp;
}
/*----------------------------------------------------------------------*/
static const _TCHAR*
patcmp( const _TCHAR* str, const pattern* pat, const _TCHAR* start)
{
/* Like strcmp, but compares str against pat. Each element of str is */
/* compared with the template until either a mis-match is found or the end */
/* of the template is reached. In the former case a 0 is returned; in the */
/* latter, a pointer into str (pointing to the last character in the */
/* matched pattern) is returned. Strstart points at the first character in */
/* the string, which might not be the same thing as line if the search */
/* started in the middle of the string. */
const _TCHAR* bocl; /* beginning of closure string. */
const _TCHAR* end=0; /* return value: end-of-string pointer. */
if (!pat) /* make sure pattern is valid */
return (NULL);
while (*pat) {
if (*pat == (pattern)M_OPT) {
/* Zero or one matches. It doesn't matter if omatch fails---it will */
/* advance str past the character on success, though. Always advance */
/* the pattern past both the M_OPT and the operand. */
omatch(&str, ++pat, start);
ADVANCE(pat);
}
else if (!(*pat == (pattern)M_CLOSE || *pat == (pattern)M_PCLOSE)) {
/* Do a simple match. Note that omatch() fails if there's still */
/* something in pat but we're at end of string. */
if (!omatch(&str, pat, start))
return NULL;
ADVANCE(pat);
}
else { /* Process a Kleene or positive closure */
if (*pat++ == (pattern)M_PCLOSE) /* one match required */
if (!omatch(&str, pat, start))
return NULL;
/* Match as many as possible, zero is okay */
bocl = str;
while (*str && omatch(&str, pat, start)) { /* do nothing */ }
/* 'str' now points to the character that made made us fail. Try to */
/* process the rest of the string. If the character following the */
/* closure could have been in the closure (as in the pattern "[a-z]*t") */
/* the final 't' will be sucked up in the while loop. So, if the match */
/* fails, back up a notch and try to match the rest of the string */
/* again, repeating this process recursively until we get back to the */
/* beginning of the closure. The recursion goes, at most, one levels */
/* deep. */
if (*ADVANCE(pat)){
for (; bocl <= str; --str){
end = patcmp(str, pat, start);
if (end)
break;
}
return end;
}
break;
}
}
/* omatch() advances str to point at the next character to be matched. So */
/* str points at the character following the last character matched when */
/* you reach the end of the template. The exceptions are templates */
/* containing only a BOLN or EOLN token. In these cases omatch doesn't */
/* advance. Since we must return a pointer to the last matched character, */
/* decrement str to make it point at the end of the matched string, making */
/* sure that the decrement hasn't gone past the beginning of the string. */
/* */
/* Note that $ is a position, not a character, but in the case of a pattern */
/* ^$, a pointer to the end of line character is returned. In ^xyz$, a */
/* pointer to the z is returned. */
/* */
/* The --str is done outside the return statement because __max() was a macro */
/* with side-effects. */
--str;
return std::max(start, str);
}
/*----------------------------------------------------------------------*/
static int
omatch( const _TCHAR * * strp,
const pattern * pat,
const _TCHAR * start )
{
/* Match one pattern element, pointed at by pat, against the character at */
/* **strp. Return 0 on a failure, 1 on success. *strp is advanced to skip */
/* over the matched character on a successful match. Closure is handled one */
/* level up by patcmp(). */
/* */
/* "start" points at the character at the left edge of the line. This might */
/* not be the same thing as *strp if the search is starting in the middle */
/* of the string. An end-of- line anchor matches '\n' or '\0'. */
int advance = -1; /* amount to advance *strp, -1 == error */
switch (*pat) {
case M_BOL: /* First char in string? */
if (*strp == start) /* Only one star here. */
advance = 0;
break;
case M_ANY: /* . = anything but newline */
if (**strp != _T('\n'))
advance = 1;
break;
case M_EOL:
if (**strp == _T('\n') || **strp == _T('\0'))
advance = 0;
break;
case M_CCL:
if (TSTBIT(**strp, pat + 1))
advance = 1;
break;
default: /* literal match */
if (**strp == *pat)
advance = 1;
break;
}
if (advance > 0)
*strp += advance;
return (advance + 1);
}
#define ISHEXDIGIT(x) (_istdigit(x) \
|| (_T('a')<=(x) && (x)<=_T('f')) \
|| (_T('A')<=(x) && (x)<=_T('F')) )
#define ISOCTDIGIT(x) (_T('0')<=(x) && (x)<=_T('7'))
static int hex2bin( int c )
{
/* Convert the hex digit represented by 'c' to an int. 'c' */
/* must be one of: 0123456789abcdefABCDEF */
return (_istdigit(c) ? (c)-_T('0') : ((_totupper(c))-_T('A'))+10) & 0xf;
}
static int oct2bin( int c )
{
/* Convert the hex digit represented by 'c' to an int. 'c' */
/* must be a digit in the range '0'-'7'. */
return ( ((c)-_T('0')) & 0x7 );
}
/*------------------------------------------------------------*/
static int
esc( const _TCHAR** s)
{
/* Map escape sequences into their equivalent symbols. Return */
/* the equivalent ASCII character. *s is advanced past the */
/* escape sequence. If no escape sequence is present, the */
/* current character is returned and the string is advanced by */
/* one. The following are recognized: */
/* */
/* \b backspace */
/* \f formfeed */
/* \n newline */
/* \r carriage return */
/* \s space */
/* \t tab */
/* \e ASCII ESC character ('\033') */
/* \DDD number formed of 1-3 octal digits */
/* \xDDD number formed of 1-3 hex digits */
/* \^C C = any letter. Control code */
int rval;
if( **s != _T('\\') )
rval = *( (*s)++ );
else {
++(*s); /* Skip the \ */
switch( _totupper(**s) ) {
case _T('\0'): rval = _T('\\'); break;
case _T('B'): rval = _T('\b'); break;
case _T('F'): rval = _T('\f'); break;
case _T('N'): rval = _T('\n'); break;
case _T('R'): rval = _T('\r'); break;
case _T('S'): rval = _T(' '); break;
case _T('T'): rval = _T('\t'); break;
case _T('E'): rval = _T('\033'); break;
case _T('^'):
rval = *++(*s) ;
rval = _totupper(rval) - _T('@') ;
break;
case _T('X'):
rval = 0;
++(*s);
if( ISHEXDIGIT(**s) ) {
rval = hex2bin( *(*s)++ );
}
if( ISHEXDIGIT(**s) ) {
rval <<= 4;
rval |= hex2bin( *(*s)++ );
}
if( ISHEXDIGIT(**s) ) {
rval <<= 4;
rval |= hex2bin( *(*s)++ );
}
--(*s);
break;
default:
if( !ISOCTDIGIT(**s) )
rval = **s;
else {
++(*s);
rval = oct2bin( *(*s)++ );
if( ISOCTDIGIT(**s) ) {
rval <<= 3;
rval |= oct2bin( *(*s)++ );
}
if( ISOCTDIGIT(**s) ) {
rval <<= 3;
rval |= oct2bin( *(*s)++ );
}
--(*s);
}
break;
}
++(*s);
}
return rval;
}
//
//-----------------------------------------------------------------------------
// class TPhoneticEngine
// ~~~~~ ~~~~~~~~~~~~~~~~~~
//
/*
** The Metaphone algorithm was developed by Lawrence Phillips. Like the
** Soundex algorithm, it compares words that sound alike but are spelled
** differently. Metaphone was designed to overcome difficulties encountered
** with Soundex.
**
** This implementation was written by Gary A. Parker and originally published
** in the June/July, 1991 (vol. 5 nr. 4) issue of C Gazette. As published,
** this code was explicitly placed in the public domain by the author.
*/
//
//const uint TPhoneticEngine::MaxMetaph = 5;
#define MAXMETAPH 5
typedef enum {COMPARE, GENERATE} metaphlag;
/*
** Character coding array
*/
static _TCHAR vsvfn[26] = {
1,16,4,16,9,2,4,16,9,2,0,2,2,2,1,4,0,2,4,4,1,0,0,0,8,0};
/* A B C D E F G H I J K L M N O P Q R S T U V W X Y Z */
/*
** Macros to access the character coding array
*/
#define MT_vowel(x) (vsvfn[(x) - _T('A')] & 1) /* AEIOU */
#define MT_same(x) (vsvfn[(x) - _T('A')] & 2) /* FJLMNR */
#define MT_varson(x) (vsvfn[(x) - _T('A')] & 4) /* CGPST */
#define MT_frontv(x) (vsvfn[(x) - _T('A')] & 8) /* EIY */
#define MT_noghf(x) (vsvfn[(x) - _T('A')] & 16) /* BDH */
/*
** metaphone()
**
** Arguments: 1 - The word to be converted to a metaphone code.
** 2 - A MAXMETAPH+1 char field for the result.
** 3 - Function flag:
** If 0: Compute the Metaphone code for the first argument,
** then compare it to the Metaphone code passed in
** the second argument.
** If 1: Compute the Metaphone code for the first argument,
** then store the result in the area pointed to by the
** second argument.
**
** Returns: If function code is 0, returns Success_ for a match, else Error_.
** If function code is 1, returns Success_.
*/
bool metaphone(const _TCHAR* Word, _TCHAR* Metaph, metaphlag flag)
{
_TCHAR *n, *n_start, *n_end; /* Pointers to string */
_TCHAR *metaph = 0, *metaph_end = 0; /* Pointers to metaph */
InUse(metaph); InUse(metaph_end); // Eliminate warnings.
_TCHAR ntrans[512]; /* Word with uppercase letters */
_TCHAR newm[MAXMETAPH + 4]; /* New metaph for comparison */
bool KSflag; /* State flag for X translation */
/** Copy word to internal buffer, dropping non-alphabetic characters */
/** and converting to upper case. */
for (n = ntrans + 1, n_end = ntrans + COUNTOF(ntrans) - 2;
*Word && n < n_end; ++Word){
if (isalpha(*Word))
*n++ = toupper(*Word);
}
if (n == ntrans + 1)
return false; /* Return if zero characters */
else
n_end = n; /* Set end of string pointer */
/* Pad with NULs, front and rear */
*n++ = NULL;
*n = NULL;
n = ntrans;
*n++ = NULL;
/* If doing comparison, redirect pointers */
if (COMPARE == flag){
metaph = Metaph;
Metaph = newm;
}
/* Check for PN, KN, GN, WR, WH, and X at start */
switch (*n){
case _T('P'):
case _T('K'):
case _T('G'):
if (_T('N') == *(n + 1))
*n++ = NULL;
break;
case _T('A'):
if (_T('E') == *(n + 1))
*n++ = NULL;
break;
case _T('W'):
if (_T('R') == *(n + 1))
*n++ = NULL;
else if (_T('H') == *(n + 1)){
*(n + 1) = *n;
*n++ = NULL;
}
break;
case _T('X'):
*n = _T('S');
break;
}
/* Now loop through the string, stopping at the end of the string */
/* or when the computed Metaphone code is MAXMETAPH characters long.*/
KSflag = false; /* State flag for KStranslation */
for (metaph_end = Metaph + MAXMETAPH, n_start = n;
n <= n_end && Metaph < metaph_end; ++n){
if (KSflag){
KSflag = false;
*Metaph++ = *n;
}
else{
/* Drop duplicates except for CC */
if (*(n - 1) == *n && *n != _T('C'))
continue;
/* Check for F J L M N R or first letter vowel */
if (MT_same(*n) || (n == n_start && MT_vowel(*n)))
*Metaph++ = *n;
else
switch (*n){
case _T('B'):
if (n < n_end || *(n - 1) != _T('M'))
*Metaph++ = *n;
break;
case _T('C'):
if (*(n - 1) != _T('S') || !MT_frontv(*(n + 1))){
if (_T('I') == *(n + 1) && _T('A') == *(n + 2))
*Metaph++ = _T('X');
else if (MT_frontv(*(n + 1)))
*Metaph++ = _T('S');
else if (_T('H') == *(n + 1))
*Metaph++ = ((n == n_start && !MT_vowel(*(n + 2))) || _T('S') == *(n - 1)) ? _T('K') : _T('X');
else
*Metaph++ = _T('K');
}
break;
case _T('D'):
*Metaph++ = (_T('G') == *(n + 1) && MT_frontv(*(n + 2))) ? _T('J') : _T('T');
break;
case _T('G'):
if ((*(n + 1) != _T('H') || MT_vowel(*(n + 2))) &&
(*(n + 1) != _T('N') || ((n + 1) < n_end &&
(*(n + 2) != _T('E') || *(n + 3) != _T('D')))) &&
(*(n - 1) != _T('D') || !MT_frontv(*(n + 1)))){
*Metaph++ = (MT_frontv(*(n + 1)) && *(n + 2) != _T('G')) ? _T('J') : _T('K');
}
else if (_T('H') == *(n + 1) && !MT_noghf(*(n - 3)) && *(n - 4) != _T('H')){
*Metaph++ = _T('F');
}
break;
case _T('H'):
if (!MT_varson(*(n - 1)) && (!MT_vowel(*(n - 1)) || MT_vowel(*(n + 1)))){
*Metaph++ = _T('H');
}
break;
case _T('K'):
if (*(n - 1) != _T('C'))
*Metaph++ = _T('K');
break;
case _T('P'):
*Metaph++ = (_T('H') == *(n + 1)) ? _T('F') : _T('P');
break;
case _T('Q'):
*Metaph++ = _T('K');
break;
case _T('S'):
*Metaph++ = (_T('H') == *(n + 1) || (_T('I') == *(n + 1) &&
(_T('O') == *(n + 2) || _T('A') == *(n + 2)))) ? _T('X') : _T('S');
break;
case _T('T'):
if(_T('I') == *(n + 1) && (_T('O') == *(n + 2) || _T('A') == *(n + 2))){
*Metaph++ = _T('X');
}
else if (_T('H') == *(n + 1))
*Metaph++ = _T('O');
else if (*(n + 1) != _T('C')|| *(n + 2) != _T('H'))
*Metaph++ = _T('T');
break;
case _T('V'):
*Metaph++ = _T('F');
break;
case _T('W'):
case _T('Y'):
if (MT_vowel(*(n + 1)))
*Metaph++ = *n;
break;
case _T('X'):
if (n == n_start)
*Metaph++ = _T('S');
else{
*Metaph++ = _T('K');
KSflag = true;
}
break;
case _T('Z'):
*Metaph++ = _T('S');
break;
}
}
/* Compare new Metaphone code with old */
if (COMPARE == flag && *(Metaph - 1) != metaph[(Metaph - newm) - 1]){
return false;
}
}
/* If comparing, check if Metaphone codes were equal in length */
if (COMPARE == flag && metaph[Metaph - newm])
return false;
*Metaph = NULL;
return true;
}
//
TPhoneticEngine::TPhoneticEngine(const tstring& pattern, bool up)
: Pattern(pattern),
DirectUp(up)
{
// only first word excluding whitespace ??
auto pos = Pattern.find_first_not_of(_T(' '));
if (pos != Pattern.npos)
Pattern.erase(0, pos);
pos = Pattern.find_first_of(_T(' '));
if (pos != Pattern.npos)
Pattern.erase(pos);
_TCHAR meta[MAXMETAPH + 4];
metaphone(Pattern.c_str(), meta, GENERATE);
Pattern = meta;
}
//
static LPCTSTR meta_match_word(LPCTSTR text, int lineLen, const tstring& pattern, int& len)
{
LPTSTR curptr = (LPTSTR)text;
LPTSTR endword = curptr;
while(lineLen > 0){
// if on whitespace -> find start of word
while(lineLen > 0 && !isWordChar(*curptr)){
curptr++; lineLen--;
}
endword = curptr;
while(lineLen > 0 && isWordChar(*endword)){
endword++; lineLen--;
}
if(lineLen > 0){
_TCHAR ch = *endword;
*endword = 0;
if(metaphone(curptr, (LPTSTR)pattern.c_str(), COMPARE)){
*endword = ch;
break;
}
*endword = ch;
}
curptr = endword;
}
if(lineLen > 0){
len = static_cast<int>(endword - curptr);
return curptr;
}
return 0;
}
//
TEditRange
TPhoneticEngine::Search(TCoolTextBuffer& buffer,const TEditRange& _sRange)
{
TEditRange searchRange(_sRange);
if(!searchRange.Valid()){
// if not valid -> all file
searchRange.scol = 0;
searchRange.srow = 0;
searchRange.erow = buffer.GetLineCount()-1;
searchRange.ecol = buffer.GetLineLength(searchRange.srow);
}
searchRange.Normalize();
TEditRange range;
int lineIndex = DirectUp ? searchRange.erow : searchRange.srow;
uint numLines = buffer.GetLineCount();
while(true){
LPCTSTR text = buffer.GetLineText(lineIndex);
int lineLen = buffer.GetLineLength(lineIndex);
if(searchRange.erow == lineIndex && searchRange.ecol < lineLen)
lineLen -= lineLen-searchRange.ecol;
if(searchRange.srow==lineIndex && searchRange.scol < lineLen){
text += searchRange.srow;
lineLen -= searchRange.srow;
}
int wordLen;
LPCTSTR endp = meta_match_word(text, lineLen, Pattern, wordLen);
if(endp){
range.srow = range.erow = lineIndex;
range.scol = static_cast<int>(endp - buffer.GetLineText(lineIndex));
range.ecol = range.scol + wordLen;
break;
}
if(DirectUp){
lineIndex--;
if(lineIndex < 0)
break;
}
else{
lineIndex++;
if(lineIndex >= (int)numLines)
break;
}
}
return range;
}
//
//
//
//-----------------------------------------------------------------------------
//
void TFuzzyEngine::Next(_TCHAR **start, _TCHAR **end, int *howclose,
int textlen, LPCTSTR Text)
{
int *temp, a, b, c, i;
*start = NULL;
LPCTSTR pat = Pattern.c_str();
int Textloc = -1;
while(*start == NULL){ /* start computing columns */
if (++Textloc >= textlen) /* out of text to search! */
break;
temp = Rdiff; /* move right-hand column to left ... */
Rdiff = Ldiff; /* ... so that we can compute new ... */
Ldiff = temp; /* ... right-hand column */
Rdiff[0] = 0; /* top (boundary) row */
temp = Roff; /* and swap offset arrays, too */
Roff = Loff;
Loff = temp;
Roff[1] = 0;
for (i = 0; i < Plen; i++){ /* run through pattern */
/* compute a, b, & c as the three adjacent cells ... */
if (pat[i] == Text[Textloc])
a = Ldiff[i];
else
a = Ldiff[i] + 1;
b = Ldiff[i+1] + 1;
c = Rdiff[i] + 1;
/* ... now pick minimum ... */
if (b < a)
a = b;
if (c < a)
a = c;
/* ... and store */
Rdiff[i+1] = a;
}
/* now update offset array */
/* the values in the offset arrays are added to the */
/* current location to determine the beginning of the */
/* mismatched substring. (see text for details) */
if (Plen > 1){
for (i=2; i<=Plen; i++){
if (Ldiff[i-1] < Rdiff[i])
Roff[i] = Loff[i-1] - 1;
else if (Rdiff[i-1] < Rdiff[i])
Roff[i] = Roff[i-1];
else if (Ldiff[i] < Rdiff[i])
Roff[i] = Loff[i] - 1;
else /* Ldiff[i-1] == Rdiff[i] */
Roff[i] = Loff[i-1] - 1;
}
}
/* now, do we have an approximate match? */
if (Rdiff[Plen] <= Degree){ /* indeed so! */
*end = (LPTSTR)Text + Textloc;
*start = *end + Roff[Plen];
*howclose = Rdiff[Plen];
}
}
}
//
//
TFuzzyEngine::TFuzzyEngine(const tstring& pattern, bool up, uint level)
:
DirectUp(up),
Degree(level)
{
// only first word excluding whitespace ??
Pattern = pattern;
/* initialize */
Plen = static_cast<int>(pattern.length());
Ldiff = new int[(Plen+1)*4];
Rdiff = Ldiff + Plen + 1;
Loff = Rdiff + Plen + 1;
Roff = Loff + Plen + 1;
for(int i = 0; i <= Plen; i++){
Rdiff[i] = i; /* initial values for right-hand column */
Roff[i] = 1;
}
}
//
TFuzzyEngine::~TFuzzyEngine()
{
delete[] Ldiff;
}
//
TEditRange
TFuzzyEngine::Search(TCoolTextBuffer& buffer,const TEditRange& _sRange)
{
TEditRange searchRange(_sRange);
if(!searchRange.Valid()){
// if not valid -> all file
searchRange.scol = 0;
searchRange.srow = 0;
searchRange.erow = buffer.GetLineCount()-1;
searchRange.ecol = buffer.GetLineLength(searchRange.srow);
}
searchRange.Normalize();
TEditRange range;
int howclose;
int lineIndex = DirectUp ? searchRange.erow : searchRange.srow;
uint numLines = buffer.GetLineCount();
while(true){
LPCTSTR text = buffer.GetLineText(lineIndex);
int lineLen = buffer.GetLineLength(lineIndex);
if(searchRange.erow == lineIndex && searchRange.ecol < lineLen)
lineLen -= lineLen-searchRange.ecol;
if(searchRange.srow==lineIndex && searchRange.scol < lineLen){
text += searchRange.srow;
lineLen -= searchRange.srow;
}
_TCHAR *textBegin, *textEnd;
Next(&textBegin, &textEnd, &howclose, lineLen, text);
if(textBegin){
range.srow = range.erow = lineIndex;
range.scol = static_cast<int>(textBegin - buffer.GetLineText(lineIndex));
range.ecol = static_cast<int>(range.scol + textEnd - textBegin);
break;
}
if(DirectUp){
lineIndex--;
if(lineIndex < 0)
break;
}
else{
lineIndex++;
if(lineIndex >= (int)numLines)
break;
}
}
return range;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// class TCoolFindDlg::TData
// ~~~~~ ~~~~~~~~~~~~~~~~~~~
//
//
TCoolFindDlg::TData::TData(TFindFlags flags, int buffSize)
:
Flags(flags), BuffSize(buffSize), Error(0), EngineIndex(0)
{
FindWhat = new _TCHAR[BuffSize];
ReplaceWith = new _TCHAR[BuffSize];
*FindWhat = *ReplaceWith = 0;
}
//
TCoolFindDlg::TData::~TData()
{
delete[] FindWhat;
delete[] ReplaceWith;
}
//
void
TCoolFindDlg::TData::AddDefaultEngines(TData& data)
{
data.EngineDescr.Add(new TBruteForceDescr);
data.EngineDescr.Add(new TBoyerMooreDescr);
data.EngineDescr.Add(new TRegularExDescr);
data.EngineDescr.Add(new TPhoneticDescr);
data.EngineDescr.Add(new TFuzzyDescrLevel1);
data.EngineDescr.Add(new TFuzzyDescrLevel2);
data.EngineDescr.Add(new TFuzzyDescrLevel3);
}
/////////////////////////////////////////////////////////////////////////////
//
class TCoolHistComboBox: public TMemComboBox{
public:
TCoolHistComboBox(TWindow* parent, int resId, const tstring& name, uint textLimit = 255, uint itemLimit = 25, TModule* module = 0)
:TMemComboBox(parent,resId,name,textLimit,itemLimit,module){}
TConfigFile* CreateConfigFile();
};
//
TConfigFile*
TCoolHistComboBox::CreateConfigFile()
{
TCoolFindDlg* dlg = TYPESAFE_DOWNCAST(GetParentO(), TCoolFindDlg);
if(dlg)
return dlg->CreateConfigFile();
return TMemComboBox::CreateConfigFile();
}
/////////////////////////////////////////////////////////////////////////////
//
//{{TCoolFindDlg Implementation}}
//
// Build a response table for all messages/commands handled
// by the application.
//
DEFINE_RESPONSE_TABLE1(TCoolFindDlg, TDialog)
EV_COMMAND_ENABLE(IDOK, EvCommandEnableOk),
EV_COMMAND(IDOK, CmOk),
EV_COMMAND_ENABLE(IDC_FINDWORD, EvCommandenableFindword),
EV_COMMAND_ENABLE(IDC_FINDCASE, EvCommandenableFindcase),
EV_COMMAND_ENABLE(IDC_FINDFRW, EvCommandenableFindfrw),
EV_COMMAND_ENABLE(IDC_FINDBACK, EvCommandenableFindback),
EV_COMMAND_ENABLE(IDC_FINDGLOBAL, EvCommandenableFindglobal),
END_RESPONSE_TABLE;
//--------------------------------------------------------
// TCoolFindDlg Constructor
//
uint TCoolFindDlg::MessageId = 0;
//
TCoolFindDlg::TCoolFindDlg(TWindow* parent, TData& data, TResId resId, TModule* module)
:
//Jogy IDD_FINDTEXTDLG -> TResId(IDD_FINDTEXTDLG)
TDialog(parent, resId ? resId : TResId(IDD_FINDTEXTDLG), module),
Data(data)
{
FindTextBox = new TCoolHistComboBox(this, IDC_FINDTEXT, _T("FindText"));
FindEngine = new TComboBox(this, IDC_FINDENGINE, 1);
FindWord = new TCheckBox(this, IDC_FINDWORD, 0);
FindCase = new TCheckBox(this, IDC_FINDCASE, 0);
FindGlobal = new TCheckBox(this, IDC_FINDGLOBAL, 0);
FindFrw = new TRadioButton(this, IDC_FINDFRW, 0);
FindBack = new TRadioButton(this, IDC_FINDBACK, 0);
//<--Jogy
// new TGlyphButton(this, IDOK, TGlyphButton::btOk);
// new TGlyphButton(this, IDCANCEL, TGlyphButton::btCancel);
//Jogy-->
// new TGlyphButton(this, IDHELP, TGlyphButton::btHelp);
if(!TCoolFindDlg::MessageId)
TCoolFindDlg::MessageId = ::RegisterWindowMessage(FINDMSGSTRING);
}
//--------------------------------------------------------
// TCoolFindDlg Destructor
//
TCoolFindDlg::~TCoolFindDlg()
{
Destroy(IDCANCEL);
}
//
void
TCoolFindDlg::SetupWindow()
{
TDialog::SetupWindow();
Data.Flags &= ~TCoolTextWnd::ffMaskFlags;
if(Data.FindWhat && Data.FindWhat[0])
FindTextBox->SetText(Data.FindWhat);
for(int i = 0; i < (int)Data.EngineDescr.Size(); i++)
FindEngine->AddString(Data.EngineDescr[i]->GetName().c_str());
FindEngine->SetSelIndex(Data.EngineIndex);
Data.Error = 0;
if(Data.Flags&TCoolTextWnd::ffMatchCase)
FindCase->SetCheck(BF_CHECKED);
if(Data.Flags&TCoolTextWnd::ffWholeWord)
FindWord->SetCheck(BF_CHECKED);
if(Data.Flags&TCoolTextWnd::ffWholeDoc)
FindGlobal->SetCheck(BF_CHECKED);
if(Data.Flags&TCoolTextWnd::ffDirectionUp){
FindFrw->SetCheck(BF_UNCHECKED);
FindBack->SetCheck(BF_CHECKED);
}
else{
FindFrw->SetCheck(BF_CHECKED);
FindBack->SetCheck(BF_UNCHECKED);
}
}
//
void
TCoolFindDlg::CleanupWindow()
{
Data.Flags &= ~TCoolTextWnd::ffMaskFlags;
Data.Flags |= TCoolTextWnd::ffDlgTerm;
GetParentO()->SendMessage(MessageId);
TDialog::CleanupWindow();
}
//
TConfigFile*
TCoolFindDlg::CreateConfigFile()
{
TCoolTextWnd* wnd = TYPESAFE_DOWNCAST(GetParentO(), TCoolTextWnd);
if(wnd)
return wnd->CreateConfigFile();
return new TRegConfigFile(configOWLNExt);
}
//
void
TCoolFindDlg::GetSelection()
{
TTmpBuffer<_TCHAR> buffer(MAX_PATH);
FindTextBox->GetText(buffer, MAX_PATH);
if(_tcscmp(buffer,Data.FindWhat) != 0){
_tcscpy(Data.FindWhat, buffer);
Data.Flags |= TCoolTextWnd::ffSEChanged;
}
int selIdx = FindEngine->GetSelIndex();
if(selIdx != CB_ERR && selIdx != Data.EngineIndex){
Data.EngineIndex = selIdx;
Data.Flags |= TCoolTextWnd::ffSEChanged;
}
bool checked = FindWord->GetCheck() == BF_CHECKED;
bool flagState = Data.Flags&TCoolTextWnd::ffWholeWord;
if(checked != flagState){
if(checked)
Data.Flags |= TCoolTextWnd::ffWholeWord;
else
Data.Flags &= ~TCoolTextWnd::ffWholeWord;
Data.Flags |= TCoolTextWnd::ffSEChanged;
}
checked = FindCase->GetCheck() == BF_CHECKED;
flagState = Data.Flags&TCoolTextWnd::ffMatchCase;
if(checked != flagState){
if(checked)
Data.Flags |= TCoolTextWnd::ffMatchCase;
else
Data.Flags &= ~TCoolTextWnd::ffMatchCase;
Data.Flags |= TCoolTextWnd::ffSEChanged;
}
checked = FindGlobal->GetCheck() == BF_CHECKED;
flagState = Data.Flags&TCoolTextWnd::ffWholeDoc;
if(checked != flagState){
if(checked)
Data.Flags |= TCoolTextWnd::ffWholeDoc;
else
Data.Flags &= ~TCoolTextWnd::ffWholeDoc;
}
checked = FindBack->GetCheck() == BF_CHECKED;
flagState = Data.Flags&TCoolTextWnd::ffDirectionUp;
if(checked != flagState){
if(checked)
Data.Flags |= TCoolTextWnd::ffDirectionUp;
else
Data.Flags &= ~TCoolTextWnd::ffDirectionUp;
Data.Flags |= TCoolTextWnd::ffSEChanged;
}
}
//
void
TCoolFindDlg::CmOk()
{
Data.Flags &= ~TCoolTextWnd::ffMaskFlags;
GetSelection();
Data.Flags |= TCoolTextWnd::ffFindNext;
GetParentO()->SendMessage(MessageId);
Data.Flags &= ~TCoolTextWnd::ffMaskFlags;
}
//
void
TCoolFindDlg::EvCommandEnableOk(TCommandEnabler& tce)
{
TTmpBuffer<_TCHAR> buffer(MAX_PATH);
FindTextBox->GetText(buffer, MAX_PATH);
tce.Enable(_tcslen(buffer));
}
//
void TCoolFindDlg::EvCommandenableFindword(TCommandEnabler& tce)
{
int selIdx = FindEngine->GetSelIndex();
if(selIdx != -1)
tce.Enable((Data.EngineDescr[selIdx]->GetCapability()&TCoolEngineDescr::ecNoWholeWord)==0);
else
tce.Enable(false);
}
//
void TCoolFindDlg::EvCommandenableFindcase(TCommandEnabler& tce)
{
int selIdx = FindEngine->GetSelIndex();
if(selIdx != -1)
tce.Enable((Data.EngineDescr[selIdx]->GetCapability()&TCoolEngineDescr::ecNoCaseSens)==0);
else
tce.Enable(false);
}
//
void TCoolFindDlg::EvCommandenableFindfrw(TCommandEnabler& tce)
{
int selIdx = FindEngine->GetSelIndex();
if(selIdx != -1)
tce.Enable((Data.EngineDescr[selIdx]->GetCapability()&TCoolEngineDescr::ecNoDirection)==0);
else
tce.Enable(false);
}
//
void TCoolFindDlg::EvCommandenableFindback(TCommandEnabler& tce)
{
int selIdx = FindEngine->GetSelIndex();
if(selIdx != -1)
tce.Enable((Data.EngineDescr[selIdx]->GetCapability()&TCoolEngineDescr::ecNoDirection)==0);
else
tce.Enable(false);
}
//
void TCoolFindDlg::EvCommandenableFindglobal(TCommandEnabler& tce)
{
int selIdx = FindEngine->GetSelIndex();
if(selIdx != -1)
tce.Enable((Data.EngineDescr[selIdx]->GetCapability()&TCoolEngineDescr::ecNoGlobal)==0);
else
tce.Enable(false);
}
//
//
//
//{{TCoolReplaceDlg Implementation}}
//
// Build a response table for all messages/commands handled
// by the application.
//
DEFINE_RESPONSE_TABLE1(TCoolReplaceDlg, TCoolFindDlg)
EV_COMMAND(IDC_REPLACE, CmReplace),
EV_COMMAND_ENABLE(IDC_REPLACEALL, CeReplace),
EV_COMMAND(IDC_REPLACEALL, CmReplaceAll),
EV_COMMAND_ENABLE(IDC_REPLACEALL, CeReplaceAll),
END_RESPONSE_TABLE;
//--------------------------------------------------------
// TCoolReplaceDlg Constructor
//
TCoolReplaceDlg::TCoolReplaceDlg(TWindow* parent, TData& data, TResId resId, TModule* module)
:
//Jogy: IDD_REPLACEDLG -> TResId(IDD_REPLACEDLG)
TCoolFindDlg(parent, data, resId ? resId : TResId(IDD_REPLACEDLG), module)
{
ReplaceTextBox = new TCoolHistComboBox(this, IDC_REPLACETEXT, _T("ReplaceText"));
new TGlyphButton(this, IDC_REPLACE, TGlyphButton::btEdit);
new TGlyphButton(this, IDC_REPLACEALL, TGlyphButton::btRevert);
// INSERT>> Your constructor code here.
}
//--------------------------------------------------------
// TCoolReplaceDlg Destructor
//
TCoolReplaceDlg::~TCoolReplaceDlg()
{
Destroy(IDCANCEL);
}
//
void
TCoolReplaceDlg::CmReplace()
{
Data.Flags &= ~TCoolTextWnd::ffMaskFlags;
GetSelection();
TTmpBuffer<_TCHAR> buffer(MAX_PATH);
ReplaceTextBox->GetText(buffer, MAX_PATH);
if(_tcscmp(buffer,Data.ReplaceWith) != 0){
_tcscpy(Data.ReplaceWith, buffer);
Data.Flags |= TCoolTextWnd::ffSEChanged;
}
Data.Flags |= TCoolTextWnd::ffReplace;
GetParentO()->SendMessage(MessageId);
Data.Flags &= ~TCoolTextWnd::ffMaskFlags;
}
//
void
TCoolReplaceDlg::CeReplace(TCommandEnabler& tce)
{
TTmpBuffer<_TCHAR> buffer(MAX_PATH);
ReplaceTextBox->GetText(buffer, MAX_PATH);
tce.Enable(_tcslen(buffer));
}
//
void
TCoolReplaceDlg::CmReplaceAll()
{
Data.Flags &= ~TCoolTextWnd::ffMaskFlags;
GetSelection();
TTmpBuffer<_TCHAR> buffer(MAX_PATH);
ReplaceTextBox->GetText(buffer, MAX_PATH);
if(_tcscmp(buffer,Data.ReplaceWith) != 0){
_tcscpy(Data.ReplaceWith, buffer);
Data.Flags |= TCoolTextWnd::ffSEChanged;
}
Data.Flags |= TCoolTextWnd::ffReplaceAll;
GetParentO()->SendMessage(MessageId);
Data.Flags &= ~TCoolTextWnd::ffMaskFlags;
}
//
void
TCoolReplaceDlg::CeReplaceAll(TCommandEnabler& tce)
{
TTmpBuffer<_TCHAR> buffer(MAX_PATH);
ReplaceTextBox->GetText(buffer, MAX_PATH);
tce.Enable(_tcslen(buffer));
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
//{{TCoolSearchWnd Implementation}}
//
// Build a response table for all messages/commands handled
// by the application.
//
DEFINE_RESPONSE_TABLE1(TCoolSearchWnd, TCoolTextWnd)
EV_COMMAND(CM_EDITFIND, CmEditFind),
EV_COMMAND(CM_EDITFINDNEXT, CmEditFindNext),
EV_COMMAND_ENABLE(CM_EDITFINDNEXT, CeEditFindNext),
EV_REGISTERED(FINDMSGSTRING, EvFindMsg),
END_RESPONSE_TABLE;
//--------------------------------------------------------
// TCoolSearchWnd
//
TCoolSearchWnd::TCoolSearchWnd(TWindow* parent, int id, LPCTSTR title,
int x, int y,int w, int h, TModule* module)
:
TCoolTextWnd(parent,id,title,x,y,w,h,module),
SearchCmd(0),
SearchDialog(0),
SearchEngine(0)
{
SearchData.AddDefaultEngines(SearchData);
}
//
TCoolSearchWnd::~TCoolSearchWnd()
{
delete SearchDialog;
delete SearchEngine;
}
//
// Post a CM_EDITFIND or a CM_EDITREPLACE to re-open a previously open
// find or replace modeless dialog
//
void
TCoolSearchWnd::SetupWindow()
{
TCoolTextWnd::SetupWindow();
if (SearchCmd)
PostMessage(WM_COMMAND, SearchCmd);
}
//
bool
TCoolSearchWnd::Search(const TEditPos& _startPos, LPCTSTR text, TFindFlags flags)
{
if (!text || !text[0])
return false;
bool firstTime = false;
if(!SearchEngine)
firstTime = true;
if(flags&ffSEChanged){
delete SearchEngine;
SearchEngine = 0;
}
if(!SearchEngine)
SearchEngine = SearchData.EngineDescr[SearchData.EngineIndex]->Create(text,
ToBool(flags&TCoolTextWnd::ffMatchCase),
ToBool(flags&TCoolTextWnd::ffWholeWord),
ToBool(flags&TCoolTextWnd::ffDirectionUp));
CHECK(SearchEngine);
TCoolTextBuffer& buffer = *GetBuffer();
TEditPos startPos(_startPos);
if(!startPos.Valid())
startPos = CursorPos;
TEditPos endPos;
if(flags&ffWholeDoc){
if(firstTime)
startPos = TEditPos(-1,-1);
endPos = TEditPos(-1,-1);
}
else{
if(flags&ffDirectionUp)
endPos = TEditPos(0,0);
else{
int lastLine = buffer.GetLineCount()-1;
endPos = TEditPos(buffer.GetLineLength(lastLine),lastLine);
}
}
TEditRange searchRange(startPos,endPos);
searchRange.Normalize();
TEditRange resRange = SearchEngine->Search(buffer, searchRange);
// If we've got a match, select that text, cleanup & return.
//
if(resRange.Valid()){
SetSelection(resRange);
CursorPos = flags&TCoolTextWnd::ffDirectionUp ? resRange.Start() : resRange.End();
ScrollToCaret(CursorPos);
return true;
}
return false;
}
//
// Perform a search or replace operation based on information in SearchData
//
void
TCoolSearchWnd::DoSearch()
{
if(Search(NULL_POS, SearchData.FindWhat, (TFindFlags)SearchData.Flags)){
;// All for this
}
else {
if(ToBool(SearchData.Flags&ffFindNext)){
tstring errTemplate(GetModule()->LoadString(IDS_CANNOTFIND));
TTmpBuffer<_TCHAR> errMsg(MAX_PATH);
_stprintf(errMsg, errTemplate.c_str(), (LPCTSTR)SearchData.FindWhat);
SearchDialog->MessageBox(errMsg, 0, MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
}
}
}
//
// Open the modeless Find commdlg
//
void
TCoolSearchWnd::CmEditFind()
{
if(!SearchCmd) {
SearchCmd = CM_EDITFIND;
delete SearchDialog;
delete SearchEngine;
SearchEngine = 0;
SetFlag(cfShowInactiveSel);
if(IsFlagSet(cfLookWrdUnderCur))
WordUnderCursor(SearchData.FindWhat, SearchData.BuffSize);
SearchDialog = new TCoolFindDlg(this, SearchData);
SearchDialog->Create();
SearchDialog->ShowWindow(SW_SHOWDEFAULT);
}
}
//
void
TCoolSearchWnd::CmEditFindNext()
{
SearchData.Flags |= ffFindNext;
DoSearch();
}
//
void
TCoolSearchWnd::CeEditFindNext(TCommandEnabler& ce)
{
ce.Enable(SearchData.FindWhat && *SearchData.FindWhat);
}
//
TResult
TCoolSearchWnd::EvFindMsg(TParam1, TParam2)
{
PRECONDITION(SearchDialog);
if(SearchData.Flags&ffDlgTerm){
SearchCmd = 0;
ClearFlag(cfShowInactiveSel);
delete SearchEngine;
SearchEngine = 0;
}
else
DoSearch();
return 0;
}
//-------------------------------------------------------------------------------------
//
// Undo/Redo handling
// ~~~~~~~~~~~~~~~~~~
// TODO>> Redo handling
//
//-----------------------------------------------------------
// class TUndoInsertChar
// ~~~~~ ~~~~~~~~~~~~~~~
//
class TUndoInsertChar: public TCoolTextBuffer::TUndoNode{
typedef TCoolTextBuffer::TUndoNode TUNode;
public:
TUndoInsertChar(uint key, int endLine, int endChar,
TUNode* undoSel, bool overType, bool dirtyFlag);
~TUndoInsertChar();
virtual bool Undo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
private:
TUndoInsertChar(const TUndoInsertChar&);
TUndoInsertChar& operator=(const TUndoInsertChar&);
_TCHAR Char;
TUNode* UndoSel;
};
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!111
class TRedoInsertChar: public TCoolTextBuffer::TRedoNode{
typedef TCoolTextBuffer::TUndoNode TUNode;
public:
TRedoInsertChar(TCoolEdit& wnd);
virtual bool Redo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
private:
TRedoInsertChar(const TRedoInsertChar&);
TRedoInsertChar& operator=(const TRedoInsertChar&);
};
//
TUndoInsertChar::TUndoInsertChar(uint key, int endLine, int endChar,
TUNode* undoSel, bool overType, bool dirtyFlag)
:
TUNode(TEditPos(endChar,endLine),dirtyFlag),
Char((_TCHAR)0xFF),
UndoSel(undoSel)
{
if(overType)
Char = (_TCHAR)key;
}
//
TUndoInsertChar::~TUndoInsertChar()
{
delete UndoSel;
}
//
bool
TUndoInsertChar::Undo(TCoolTextBuffer& buffer, TEditPos* newPos)
{
// create redo node??
//buffer->AddRedoNode(new TRedoInsertChar());
if(Char != (_TCHAR)0xFF)
buffer.GetLineText(SavedPos.row)[SavedPos.col] = Char;
else{
TEditRange range(SavedPos.col,SavedPos.row,SavedPos.col+1, SavedPos.row);
buffer.DeleteText(range);
}
if(newPos)
*newPos = SavedPos;
buffer.SetDirty(Dirty);
if(UndoSel)
return UndoSel->Undo(buffer, newPos);
return true;
}
//
bool
TUndoInsertChar::GetDescription(_TCHAR* buffer, int len, TModule* module)
{
return TCoolTextBuffer::LoadStringIndex(buffer, len, IDS_COOLUNDOSTRINGS, 1, _T('|'), module);
}
//
TRedoInsertChar::TRedoInsertChar(TCoolEdit&)
{ }
//
bool
TRedoInsertChar::Redo(TCoolTextBuffer&, TEditPos* /*newPos*/)
{ return true; }
//
bool
TRedoInsertChar::GetDescription(_TCHAR* /*buffer*/, int /*len*/, TModule*)
{ return true; }
//////////////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------
// class TUndoReplaceText
// ~~~~~ ~~~~~~~~~~~~~~~~
//
class TUndoReplaceText: public TCoolTextBuffer::TUndoNode {
typedef TCoolTextBuffer::TUndoNode TUNode;
public:
TUndoReplaceText(const TEditPos& curPos, const TEditPos& endPos, TUNode* undoSel, bool dirtyFlag);
~TUndoReplaceText();
virtual bool Undo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
protected:
TEditPos EndPos;
private:
TUndoReplaceText(const TUndoReplaceText&);
TUndoReplaceText& operator=(const TUndoReplaceText&);
TUNode* UndoSel;
};
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
class TRedoReplaceText: public TCoolTextBuffer::TRedoNode{
public:
TRedoReplaceText(TCoolEdit& wnd);
virtual bool Redo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
private:
TRedoReplaceText(const TRedoReplaceText&);
TRedoReplaceText& operator=(const TRedoReplaceText&);
};
//
TUndoReplaceText::TUndoReplaceText(const TEditPos& curPos, const TEditPos& endPos,
TUNode* undoSel, bool dirtyFlag)
:
TUNode(curPos,dirtyFlag),
UndoSel(undoSel),
EndPos(endPos)
{
}
//
TUndoReplaceText::~TUndoReplaceText()
{
delete UndoSel;
}
//
bool
TUndoReplaceText::Undo(TCoolTextBuffer& buffer, TEditPos* newPos)
{
// create redo node??
//buffer->AddRedoNode(new TRedoInsertChar());
TEditRange range(SavedPos, EndPos);
buffer.DeleteText(range);
if(newPos)
*newPos = SavedPos;
buffer.SetDirty(Dirty);
if(UndoSel)
return UndoSel->Undo(buffer, newPos);
return true;
}
//
bool
TUndoReplaceText::GetDescription(_TCHAR* buffer, int len, TModule* module)
{
return TCoolTextBuffer::LoadStringIndex(buffer, len, IDS_COOLUNDOSTRINGS, 2, _T('|'), module);
}
//-----------------------------------------------------------
// class TUndoKeyEnter
// ~~~~~ ~~~~~~~~~~~~~
//
class TUndoKeyEnter: public TCoolTextBuffer::TUndoNode{
typedef TCoolTextBuffer::TUndoNode TUNode;
public:
TUndoKeyEnter(int endLine, int endChar, TUNode* undoSel, bool dirtyFlag);
virtual bool Undo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
void SetNewPos(int newPos);
private:
TUndoKeyEnter(const TUndoKeyEnter&);
TUndoKeyEnter& operator=(const TUndoKeyEnter&);
TUNode* UndoSel;
int SmartScip;
};
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
class TRedoKeyEnter: public TCoolTextBuffer::TRedoNode{
public:
TRedoKeyEnter(TCoolEdit& wnd);
virtual bool Redo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
private:
TRedoKeyEnter(const TRedoKeyEnter&);
TRedoKeyEnter& operator=(const TRedoKeyEnter&);
};
//
TUndoKeyEnter::TUndoKeyEnter(int endLine, int endChar, TUNode* undoSel,
bool dirtyFlag)
:
TUNode(TEditPos(endChar,endLine),dirtyFlag),
UndoSel(undoSel),
SmartScip(0)
{
}
//
void
TUndoKeyEnter::SetNewPos(int newPos)
{
SmartScip = newPos;
}
//
bool
TUndoKeyEnter::Undo(TCoolTextBuffer& buffer, TEditPos* newPos)
{
//buffer.AddRedoNode(new TRedoInsertChar());
if(newPos)
*newPos = SavedPos;
TEditRange range(SavedPos.col,SavedPos.row, SmartScip, SavedPos.row+1);
buffer.DeleteText(range);
buffer.SetDirty(Dirty);
if(UndoSel)
return UndoSel->Undo(buffer, newPos);
return true;
}
//
bool
TUndoKeyEnter::GetDescription(_TCHAR* buffer, int len, TModule* module)
{
return TCoolTextBuffer::LoadStringIndex(buffer, len, IDS_COOLUNDOSTRINGS, 3, _T('|'), module);
}
//
TRedoKeyEnter::TRedoKeyEnter(TCoolEdit&)
{}
bool TRedoKeyEnter::Redo(TCoolTextBuffer&, TEditPos* /*newPos*/)
{ return true;}
bool TRedoKeyEnter::GetDescription(_TCHAR* /*buffer*/, int /*len*/, TModule*)
{ return true;}
//////////////////////////////////////////////////////////////////////////////////////////
//TUndoKeyTab(this,repeatCount));
// problems when undo lines
class TUndoKeyTab: public TCoolTextBuffer::TUndoNode{
typedef TCoolTextBuffer::TUndoNode TUNode;
public:
TUndoKeyTab(TCoolEdit& wnd, const TEditPos& pos, int count,
bool ins, bool dirtyFlag);
virtual bool Undo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
protected:
int Count;
bool Insert;
private:
TUndoKeyTab(const TUndoKeyTab&);
};
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
class TRedoKeyTab: public TCoolTextBuffer::TRedoNode{
public:
TRedoKeyTab(TCoolEdit& wnd);
virtual bool Redo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
private:
TRedoKeyTab(const TRedoKeyTab&);
};
//
TUndoKeyTab::TUndoKeyTab(TCoolEdit&, const TEditPos& pos,
int count, bool ins, bool dirtyFlag)
:
TUNode(pos, dirtyFlag),Count(count),Insert(ins)
{
}
//
bool
TUndoKeyTab::Undo(TCoolTextBuffer& buffer, TEditPos* newPos)
{
//buffer.AddRedoNode(new TRedoInsertChar());
if(newPos)
*newPos = SavedPos;
if(Insert){
TEditRange range(SavedPos.col,SavedPos.row, SavedPos.col+Count, SavedPos.row);
buffer.DeleteText(range);
buffer.SetDirty(Dirty);
}
return true;
}
//
bool
TUndoKeyTab::GetDescription(_TCHAR* buffer, int len, TModule* module)
{
return TCoolTextBuffer::LoadStringIndex(buffer, len, IDS_COOLUNDOSTRINGS, 4, _T('|'), module);
}
//
TRedoKeyTab::TRedoKeyTab(TCoolEdit&)
{}
bool TRedoKeyTab::Redo(TCoolTextBuffer& /*buffer*/, TEditPos* /*newPos*/)
{ return true;}
bool TRedoKeyTab::GetDescription(_TCHAR* /*buffer*/, int /*len*/, TModule*)
{ return true;}
//////////////////////////////////////////////////////////////////////////////////////////
//TUndoKeyTabify(this,repeatCount));
class TUndoKeyTabify: public TCoolTextBuffer::TUndoNode{
typedef TCoolTextBuffer::TUndoNode TUNode;
public:
TUndoKeyTabify(int xPos, int yPos1, int yPos2, bool dirtyFlag);
virtual bool Undo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
private:
TUndoKeyTabify(const TUndoKeyTab&);
int yPos;
};
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!111
class TRedoKeyTabify: public TCoolTextBuffer::TRedoNode{
public:
TRedoKeyTabify(TCoolEdit& wnd);
virtual bool Redo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
private:
TRedoKeyTabify(const TRedoKeyTab&);
};
//
TUndoKeyTabify::TUndoKeyTabify(int xPos, int yPos1, int yPos2, bool dirtyFlag)
:
TUNode(TEditPos(xPos,yPos1), dirtyFlag),
yPos(yPos2)
{
}
//
bool TUndoKeyTabify::Undo(TCoolTextBuffer& buffer, TEditPos* newPos)
{
//buffer->AddRedoNode(new TRedoKeyTabify());
if(newPos)
*newPos = SavedPos;
for(int curLine = SavedPos.row; curLine < yPos; curLine++){
TEditRange range(SavedPos.col,curLine, SavedPos.col+1, curLine);
buffer.DeleteText(range);
}
buffer.SetDirty(Dirty);
return true;
}
//
bool
TUndoKeyTabify::GetDescription(_TCHAR* buffer, int len, TModule* module)
{
return TCoolTextBuffer::LoadStringIndex(buffer, len, IDS_COOLUNDOSTRINGS, 5, _T('|'), module);
}
//
TRedoKeyTabify::TRedoKeyTabify(TCoolEdit&)
{}
bool TRedoKeyTabify::Redo(TCoolTextBuffer& /*buffer*/, TEditPos* /*newPos*/)
{ return true;}
bool TRedoKeyTabify::GetDescription(_TCHAR* /*buffer*/, int /*len*/, TModule*)
{ return true;}
//////////////////////////////////////////////////////////////////////////////////////////
//TUndoDeleteChar
class TUndoDeleteChar: public TCoolTextBuffer::TUndoNode {
typedef TCoolTextBuffer::TUndoNode TUNode;
public:
TUndoDeleteChar(TCoolTextBuffer& buffer, int pos_y, int pos_x,
TUNode* sel);
virtual bool Undo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
private:
TUndoDeleteChar(const TUndoDeleteChar&);
TUNode* UndoSel;
_TCHAR Char;
};
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!111
class TRedoDeleteChar: public TCoolTextBuffer::TRedoNode{
public:
TRedoDeleteChar(TCoolEdit& wnd);
virtual bool Redo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
private:
TRedoDeleteChar(const TRedoDeleteChar&);
};
//
TUndoDeleteChar::TUndoDeleteChar(TCoolTextBuffer& buffer, int pos_y, int pos_x,
TUNode* /*sel*/)
:
TUNode(TEditPos(pos_x, pos_y), buffer.IsDirty())
{
if(pos_x == buffer.GetLineLength(pos_y))
Char = (_TCHAR)0xFF;
else
Char = buffer.GetLineText(pos_y)[pos_x];
}
//
bool
TUndoDeleteChar::Undo(TCoolTextBuffer& buffer, TEditPos* newPos)
{
if(newPos)
*newPos = SavedPos;
TEditPos endPos;
if(Char == (_TCHAR)0xFF)
buffer.InsertText(SavedPos, crlf, endPos);
else{
_TCHAR buf[2] = {Char, 0};
buffer.InsertText(SavedPos, buf, endPos);
}
buffer.SetDirty(Dirty);
return true;
}
//
bool
TUndoDeleteChar::GetDescription(_TCHAR* buffer, int len, TModule* module)
{
return TCoolTextBuffer::LoadStringIndex(buffer, len, IDS_COOLUNDOSTRINGS, 6, _T('|'), module);
}
//
TRedoDeleteChar::TRedoDeleteChar(TCoolEdit&)
{}
bool TRedoDeleteChar::Redo(TCoolTextBuffer& /*buffer*/, TEditPos* /*newPos*/)
{ return true;}
bool TRedoDeleteChar::GetDescription(_TCHAR* /*buffer*/, int /*len*/, TModule* /*module*/)
{ return true;}
//////////////////////////////////////////////////////////////////////////////////////////
//TUndoDeleteWord(this,repeatCount);
class TUndoDeleteWord: public TCoolTextBuffer::TUndoNode{
typedef TCoolTextBuffer::TUndoNode TUNode;
public:
TUndoDeleteWord(TCoolTextBuffer& buffer, const TEditPos& savedPos,
const TEditPos& endPos, TUNode* undoSel);
virtual bool Undo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
private:
TUndoDeleteWord(const TUndoDeleteWord&);
protected:
TUNode* UndoSel;
tstring Text;
};
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!111
class TRedoDeleteWord: public TCoolTextBuffer::TRedoNode{
public:
TRedoDeleteWord(TCoolEdit& wnd);
virtual bool Redo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
private:
TRedoDeleteWord(const TRedoDeleteWord&);
};
//
TUndoDeleteWord::TUndoDeleteWord(TCoolTextBuffer& buffer,
const TEditPos& savedPos, const TEditPos& endPos, TUNode* undoSel)
:
TUNode(savedPos, buffer.IsDirty()),UndoSel(undoSel)
{
TTmpBuffer<_TCHAR> buf(MAX_PATH);
buffer.GetText(savedPos, endPos, (_TCHAR*)buf, MAX_PATH);
//Jogy: buf -> (_TCHAR *)buf
Text = (_TCHAR *)buf;
}
//
bool
TUndoDeleteWord::Undo(TCoolTextBuffer& buffer, TEditPos* newPos)
{
if(newPos)
*newPos = SavedPos;
TEditPos endPos;
buffer.InsertText(SavedPos, Text.c_str(), endPos);
buffer.SetDirty(Dirty);
return true;
}
//
bool
TUndoDeleteWord::GetDescription(_TCHAR* buffer, int len, TModule* module)
{
return TCoolTextBuffer::LoadStringIndex(buffer, len, IDS_COOLUNDOSTRINGS, 7, _T('|'), module);
}
//
TRedoDeleteWord::TRedoDeleteWord(TCoolEdit&)
{}
bool TRedoDeleteWord::Redo(TCoolTextBuffer& /*buffer*/, TEditPos* /*newPos*/)
{ return true;}
bool TRedoDeleteWord::GetDescription(_TCHAR* /*buffer*/, int /*len*/, TModule*)
{ return true;}
//////////////////////////////////////////////////////////////////////////////////////////
// class TUndoDeleteCharBack
// ~~~~~ ~~~~~~~~~~~~~~~~~~~
//
class TUndoDeleteCharBack: public TCoolTextBuffer::TUndoNode{
typedef TCoolTextBuffer::TUndoNode TUNode;
public:
TUndoDeleteCharBack(TCoolTextBuffer& buffer, int pos_y, int pos_x,
TUNode* sel);
virtual bool Undo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
protected:
TUNode* UndoSel;
int PrevLen;
_TCHAR Char;
};
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!111
class TRedoDeleteCharBack: public TCoolTextBuffer::TRedoNode{
public:
TRedoDeleteCharBack(TCoolEdit& wnd);
virtual bool Redo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
};
//
TUndoDeleteCharBack::TUndoDeleteCharBack(TCoolTextBuffer& buffer, int pos_y,
int pos_x, TUNode* /*sel*/)
:
TUNode(TEditPos(pos_x, pos_y), buffer.IsDirty())
{
if(pos_x == 0){
Char = (_TCHAR)0xFF;
PrevLen = buffer.GetLineLength(pos_y-1);
}else
Char = buffer.GetLineText(pos_y)[pos_x-1];
}
//
bool
TUndoDeleteCharBack::Undo(TCoolTextBuffer& buffer, TEditPos* newPos)
{
if(newPos)
*newPos = SavedPos;
TEditPos endPos;
if(Char == (_TCHAR)0xFF)
buffer.InsertText(TEditPos(PrevLen,SavedPos.row-1), crlf, endPos);
else{
_TCHAR buf[2] = {Char, 0};
buffer.InsertText(TEditPos(SavedPos.col-1,SavedPos.row), buf, endPos);
}
buffer.SetDirty(Dirty);
return true;
}
//
bool
TUndoDeleteCharBack::GetDescription(_TCHAR* buffer, int len, TModule* module)
{
return TCoolTextBuffer::LoadStringIndex(buffer, len, IDS_COOLUNDOSTRINGS, 8, _T('|'), module);
}
//
TRedoDeleteCharBack::TRedoDeleteCharBack(TCoolEdit&)
{}
bool TRedoDeleteCharBack::Redo(TCoolTextBuffer& /*buffer*/, TEditPos* /*newPos*/)
{ return true;}
bool TRedoDeleteCharBack::GetDescription(_TCHAR* /*buffer*/, int /*len*/, TModule*)
{ return true;}
//-----------------------------------------------------------
// class TUndoDeleteWordBack
// ~~~~~ ~~~~~~~~~~~~~~~~~~~
//
class TUndoDeleteWordBack: public TCoolTextBuffer::TUndoNode{
typedef TCoolTextBuffer::TUndoNode TUNode;
public:
TUndoDeleteWordBack(TCoolTextBuffer& buffer, const TEditPos& savedPos,
const TEditPos& startPos, TUNode* undoSel);
virtual bool Undo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
protected:
TUNode* UndoSel;
TEditPos SPos;
tstring Text;
};
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!111
class TRedoDeleteWordBack: public TCoolTextBuffer::TRedoNode{
public:
TRedoDeleteWordBack(TCoolEdit& wnd);
virtual bool Redo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
};
//
TUndoDeleteWordBack::TUndoDeleteWordBack(TCoolTextBuffer& buffer,
const TEditPos& savedPos, const TEditPos& startPos, TUNode* undoSel)
:
TUNode(savedPos, buffer.IsDirty()),UndoSel(undoSel),SPos(startPos)
{
TTmpBuffer<_TCHAR> buf(MAX_PATH);
buffer.GetText(startPos, savedPos, buf, MAX_PATH);
//Jogy: buf -> (_TCHAR *)buf
Text = (_TCHAR *)buf;
}
//
bool
TUndoDeleteWordBack::Undo(TCoolTextBuffer& buffer, TEditPos* newPos)
{
if(newPos)
*newPos = SavedPos;
TEditPos endPos;
buffer.InsertText(SPos, Text.c_str(), endPos);
buffer.SetDirty(Dirty);
return true;
}
//
bool
TUndoDeleteWordBack::GetDescription(_TCHAR* buffer, int len, TModule* module)
{
return TCoolTextBuffer::LoadStringIndex(buffer, len, IDS_COOLUNDOSTRINGS, 9, _T('|'), module);
}
//
TRedoDeleteWordBack::TRedoDeleteWordBack(TCoolEdit&)
{}
bool TRedoDeleteWordBack::Redo(TCoolTextBuffer& /*buffer*/, TEditPos* /*newPos*/)
{ return true;}
bool TRedoDeleteWordBack::GetDescription(_TCHAR* /*buffer*/, int /*len*/, TModule*)
{ return true;}
//-----------------------------------------------------------
// class TUndoDeleteSelection
// ~~~~~ ~~~~~~~~~~~~~~~~~~~~
//
class TUndoDeleteSelection: public TCoolTextBuffer::TUndoNode{
typedef TCoolTextBuffer::TUndoNode TUNode;
public:
TUndoDeleteSelection(TCoolEdit& wnd, bool dirtyFlag);
virtual bool Undo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
protected:
tostringstream Os;
TEditPos StartPos;
private:
TUndoDeleteSelection(const TUndoDeleteSelection&);
};
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!111
class TRedoDeleteSelection: public TCoolTextBuffer::TRedoNode{
public:
TRedoDeleteSelection(TCoolEdit& wnd);
virtual bool Redo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
private:
TRedoDeleteSelection(const TRedoDeleteSelection&);
};
//
TUndoDeleteSelection::TUndoDeleteSelection(TCoolEdit& wnd, bool dirtyFlag)
:
TUNode(wnd.CursorPos, dirtyFlag)
{
PRECONDITION(wnd.Selection);
wnd.Selection->Copy(Os);
TEditPos startPos = wnd.Selection->GetStart();
TEditPos endPos = wnd.Selection->GetEnd();
if(startPos.row < endPos.row)
StartPos = startPos;
else if(startPos.row == endPos.row)
StartPos = startPos.col < endPos.col ? startPos : endPos;
else
StartPos = endPos;
}
//
static void PasteFromMemoryImp(_TCHAR* pMemory, int size,
TCoolEdit::TSelType selection,
TEditPos& cursorPos, TCoolTextBuffer& buffer);
//
bool TUndoDeleteSelection::Undo(TCoolTextBuffer& buffer, TEditPos* newPos)
{
//buffer.AddRedoNode(new TRedoDelSelection());
if(newPos)
*newPos = SavedPos;
_TCHAR* pMemory = (_TCHAR*)Os.str().c_str();
TCoolEdit::TSelType selection;
if(memcmp(pMemory,streamSelectionId,IdSelSize)==0)
selection = TCoolEdit::stStreamSelection;
else if(memcmp(pMemory,lineSelectionId,IdSelSize)==0)
selection = TCoolEdit::stLineSelection;
else if(memcmp(pMemory,lineSelectionId,IdSelSize)==0)
selection = TCoolEdit::stColumnSelection;
else{
CHECK(false);
selection = TCoolEdit::stStreamSelection;
}
pMemory += IdSelSize;
PasteFromMemoryImp(pMemory, static_cast<int>(_tcslen(pMemory)), selection, StartPos, buffer);
buffer.SetDirty(Dirty);
return true;
}
//
bool
TUndoDeleteSelection::GetDescription(_TCHAR* buffer, int len, TModule* module)
{
return TCoolTextBuffer::LoadStringIndex(buffer, len, IDS_COOLUNDOSTRINGS, 10, _T('|'), module);
}
//
TRedoDeleteSelection::TRedoDeleteSelection(TCoolEdit&)
{}
bool TRedoDeleteSelection::Redo(TCoolTextBuffer& /*buffer*/, TEditPos* /*newPos*/)
{ return true;}
bool TRedoDeleteSelection::GetDescription(_TCHAR* /*buffer*/, int /*len*/, TModule*)
{ return true;}
//-----------------------------------------------------------
// class TUndoPaste
// ~~~~~ ~~~~~~~~~~
//
class TUndoPaste: public TCoolTextBuffer::TUndoNode{
typedef TCoolTextBuffer::TUndoNode TUNode;
public:
TUndoPaste(const TEditPos& savedPos, const TEditPos& currPos,
TUNode* undoSel, bool dirty);
virtual bool Undo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
private:
TUndoPaste(const TUndoPaste&);
TUNode* UndoSel;
TEditPos LastPos;
};
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
class TRedoPaste: public TCoolTextBuffer::TRedoNode{
public:
TRedoPaste(TCoolEdit& end);
virtual bool Redo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
private:
TRedoPaste(const TRedoPaste&);
};
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
TUndoPaste::TUndoPaste(const TEditPos& savedPos, const TEditPos& currPos,
TUNode* undoSel, bool dirty)
:
TUNode(savedPos, dirty),UndoSel(undoSel),LastPos(currPos)
{
}
//
bool
TUndoPaste::Undo(TCoolTextBuffer& buffer, TEditPos* newPos)
{
if(newPos)
*newPos = SavedPos;
TEditRange range(SavedPos, LastPos);
buffer.DeleteText(range);
buffer.SetDirty(Dirty);
if(UndoSel)
return UndoSel->Undo(buffer, newPos);
return true;
}
//
bool
TUndoPaste::GetDescription(_TCHAR* buffer, int len, TModule* module)
{
return TCoolTextBuffer::LoadStringIndex(buffer, len, IDS_COOLUNDOSTRINGS, 11, _T('|'), module);
}
//
TRedoPaste::TRedoPaste(TCoolEdit&)
{}
bool TRedoPaste::Redo(TCoolTextBuffer& /*buffer*/, TEditPos* /*newPos*/)
{ return true;}
bool TRedoPaste::GetDescription(_TCHAR* /*buffer*/, int /*len*/, TModule*)
{ return true;}
//////////////////////////////////////////////////////////////////////////////////////////
//TUndoClearAll(this);
class TUndoClearAll: public TCoolTextBuffer::TUndoNode{
typedef TCoolTextBuffer::TUndoNode TUNode;
public:
TUndoClearAll(TCoolEdit& wnd, TEditPos& pos, bool dirtyFlag);
virtual bool Undo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
protected:
TIPtrArray<TCoolTextBuffer::TLineInfo*> LineArray;
};
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
class TRedoClearAll: public TCoolTextBuffer::TRedoNode {
public:
TRedoClearAll(TCoolEdit& end);
virtual bool Redo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
};
//
TUndoClearAll::TUndoClearAll(TCoolEdit& wnd, TEditPos& pos, bool dirtyFlag)
:
TUNode(pos, dirtyFlag)
{
PRECONDITION(wnd.GetBuffer());
TCoolTextBuffer& buffer = *wnd.GetBuffer();
int size = buffer.GetLineCount();
for(int i = 0; i < size; i++)
LineArray.Add(new TCoolTextBuffer::TLineInfo(buffer.GetLineText(i),
buffer.GetLineLength(i)));
}
//
bool
TUndoClearAll::Undo(TCoolTextBuffer& buffer, TEditPos* newPos)
{
if(newPos)
*newPos = SavedPos;
// delete first line
TEditRange range(0, 0, -1, 0);
buffer.DeleteText(range);
int size = LineArray.Size();
for(int i = 0; i < size; i++)
buffer.InsertLine(LineArray[i]->Text, LineArray[i]->Length);
buffer.SetDirty(Dirty);
return true;
}
//
bool
TUndoClearAll::GetDescription(_TCHAR* buffer, int len, TModule* module)
{
return TCoolTextBuffer::LoadStringIndex(buffer, len, IDS_COOLUNDOSTRINGS, 11, _T('|'), module);
}
//
TRedoClearAll::TRedoClearAll(TCoolEdit&)
{}
bool TRedoClearAll::Redo(TCoolTextBuffer& /*buffer*/, TEditPos* /*newPos*/)
{ return true;}
bool TRedoClearAll::GetDescription(_TCHAR* /*buffer*/, int /*len*/, TModule*)
{ return true;}
/////////////////////////////////////////////////////////////////////////////////////////////
#if !defined(COOL_NODRAGDROP)
//-----------------------------------------------------------
// class TUndoDragDropMoveExt
// ~~~~~ ~~~~~~~~~~~~~~~~~~~~
//
class TUndoDragDropMoveExt: public TCoolTextBuffer::TUndoNode{
typedef TCoolTextBuffer::TUndoNode TUNode;
public:
TUndoDragDropMoveExt(TCoolEdit& wnd, bool dirtyFlag);
virtual bool Undo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
protected:
tostringstream Os;
TEditPos StartPos;
private:
TUndoDragDropMoveExt(const TUndoDragDropMoveExt&);
};
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!111
class TRedoDragDropMoveExt: public TCoolTextBuffer::TRedoNode{
public:
TRedoDragDropMoveExt(TCoolEdit& wnd);
virtual bool Redo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
private:
TRedoDragDropMoveExt(const TRedoDragDropMoveExt&);
};
//
TUndoDragDropMoveExt::TUndoDragDropMoveExt(TCoolEdit& wnd, bool dirtyFlag)
:
TUNode(wnd.CursorPos, dirtyFlag)
{
PRECONDITION(wnd.Selection);
wnd.Selection->Copy(Os);
TEditPos startPos = wnd.Selection->GetStart();
TEditPos endPos = wnd.Selection->GetEnd();
if(startPos.row < endPos.row)
StartPos = startPos;
else if(startPos.row == endPos.row)
StartPos = startPos.col < endPos.col ? startPos : endPos;
else
StartPos = endPos;
}
//
bool TUndoDragDropMoveExt::Undo(TCoolTextBuffer& buffer, TEditPos* newPos)
{
//buffer.AddRedoNode(new TRedoDragDropMoveExt());
if(newPos)
*newPos = SavedPos;
_TCHAR* pMemory = (_TCHAR*)Os.str().c_str();
TCoolEdit::TSelType selection;
if(memcmp(pMemory,streamSelectionId,IdSelSize)==0)
selection = TCoolEdit::stStreamSelection;
else if(memcmp(pMemory,lineSelectionId,IdSelSize)==0)
selection = TCoolEdit::stLineSelection;
else if(memcmp(pMemory,lineSelectionId,IdSelSize)==0)
selection = TCoolEdit::stColumnSelection;
else{
CHECK(false);
selection = TCoolEdit::stStreamSelection;
}
pMemory += IdSelSize;
PasteFromMemoryImp(pMemory, static_cast<int>(_tcslen(pMemory)), selection, StartPos, buffer);
buffer.SetDirty(Dirty);
return true;
}
//
bool
TUndoDragDropMoveExt::GetDescription(_TCHAR* buffer, int len, TModule* module)
{
return TCoolTextBuffer::LoadStringIndex(buffer, len, IDS_COOLUNDOSTRINGS, 12, _T('|'), module);
}
//
TRedoDragDropMoveExt::TRedoDragDropMoveExt(TCoolEdit&)
{}
bool TRedoDragDropMoveExt::Redo(TCoolTextBuffer& /*buffer*/, TEditPos* /*newPos*/)
{ return true;}
bool TRedoDragDropMoveExt::GetDescription(_TCHAR* /*buffer*/, int /*len*/, TModule*)
{ return true;}
//-----------------------------------------------------------
// class TUndoDragDropCopy
// ~~~~~ ~~~~~~~~~~~~~~~~~
//
class TUndoDragDropCopy: public TCoolTextBuffer::TUndoNode{
typedef TCoolTextBuffer::TUndoNode TUNode;
public:
TUndoDragDropCopy(const TEditPos& savedPos, const TEditPos& currPos, bool dirty);
virtual bool Undo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
private:
TUndoDragDropCopy(const TUndoDragDropCopy&);
TEditPos LastPos;
};
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
class TRedoDragDropCopy: public TCoolTextBuffer::TRedoNode{
public:
TRedoDragDropCopy(TCoolEdit& end);
virtual bool Redo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
private:
TRedoDragDropCopy(const TRedoDragDropCopy&);
};
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
TUndoDragDropCopy::TUndoDragDropCopy(const TEditPos& savedPos,
const TEditPos& currPos,
bool dirty)
:
TUNode(savedPos, dirty), LastPos(currPos)
{
}
//
bool
TUndoDragDropCopy::Undo(TCoolTextBuffer& buffer, TEditPos* newPos)
{
if(newPos)
*newPos = SavedPos;
TEditRange range(SavedPos, LastPos);
buffer.DeleteText(range);
buffer.SetDirty(Dirty);
return true;
}
//
bool
TUndoDragDropCopy::GetDescription(_TCHAR* buffer, int len, TModule* module)
{
return TCoolTextBuffer::LoadStringIndex(buffer, len, IDS_COOLUNDOSTRINGS, 13, _T('|'), module);
}
//
TRedoDragDropCopy::TRedoDragDropCopy(TCoolEdit&)
{}
bool TRedoDragDropCopy::Redo(TCoolTextBuffer& /*buffer*/, TEditPos* /*newPos*/)
{ return true;}
bool TRedoDragDropCopy::GetDescription(_TCHAR* /*buffer*/, int /*len*/, TModule*)
{ return true;}
//-----------------------------------------------------------
// class TUndoDragDropMove
// ~~~~~ ~~~~~~~~~~~~~~~~~
//
class TUndoDragDropMove: public TCoolTextBuffer::TUndoNode{
typedef TCoolTextBuffer::TUndoNode TUNode;
public:
TUndoDragDropMove(const TEditPos& savedPos, const TEditPos& currPos,
TUNode* undoSel, bool dirty);
virtual bool Undo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
private:
TUndoDragDropMove(const TUndoDragDropMove&);
TUNode* UndoSel;
TEditPos LastPos;
};
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
class TRedoDragDropMove: public TCoolTextBuffer::TRedoNode{
public:
TRedoDragDropMove(TCoolEdit& end);
virtual bool Redo(TCoolTextBuffer& buffer, TEditPos* newPos=0);
virtual bool GetDescription(_TCHAR* buffer, int len, TModule* module = owl::Module);
private:
TRedoDragDropMove(const TRedoDragDropMove&);
};
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
TUndoDragDropMove::TUndoDragDropMove(const TEditPos& savedPos,
const TEditPos& currPos,
TUNode* undoSel, bool dirty)
:
TUNode(savedPos, dirty), UndoSel(undoSel), LastPos(currPos)
{
}
//
bool
TUndoDragDropMove::Undo(TCoolTextBuffer& buffer, TEditPos* newPos)
{
if(newPos)
*newPos = SavedPos;
TEditRange range(SavedPos, LastPos);
buffer.DeleteText(range);
buffer.SetDirty(Dirty);
if(UndoSel)
return UndoSel->Undo(buffer, newPos);
return true;
}
//
bool
TUndoDragDropMove::GetDescription(_TCHAR* buffer, int len, TModule* module)
{
return TCoolTextBuffer::LoadStringIndex(buffer, len, IDS_COOLUNDOSTRINGS, 14, _T('|'), module);
}
//
TRedoDragDropMove::TRedoDragDropMove(TCoolEdit&)
{}
bool TRedoDragDropMove::Redo(TCoolTextBuffer& /*buffer*/, TEditPos* /*newPos*/)
{ return true;}
bool TRedoDragDropMove::GetDescription(_TCHAR* /*buffer*/, int /*len*/, TModule*)
{ return true;}
#endif
/////////////////////////////////////////////////////////////////////////////////////////////
//
#if !defined(COOL_NODRAGDROP)
//-------------------------------------------------------------------------------------------
// class TCoolEdit::TEditDragDropProxy
// ~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
TCoolEdit::TEditDragDropProxy::TEditDragDropProxy(TCoolEdit* wnd)
:
TDragDropProxy(wnd)
{
}
//
void TCoolEdit::TEditDragDropProxy::ShowDropIndicator(TPoint& point)
{
TYPESAFE_DOWNCAST(Parent, TCoolEdit)->ShowDropIndicator(point);
}
//
void TCoolEdit::TEditDragDropProxy::HideDropIndicator()
{
TYPESAFE_DOWNCAST(Parent, TCoolEdit)->HideDropIndicator();
}
//
uint
TCoolEdit::TEditDragDropProxy::IsDroppable(const TPoint& point, const TRect& clientRect)
{
TRect rect(clientRect);
rect.left += TYPESAFE_DOWNCAST(Parent, TCoolEdit)->GetMarginWidth();
return TDragDropProxy::IsDroppable(point, rect);
}
//
STDMETHODIMP
TCoolEdit::TEditDragDropProxy::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
{
*pdwEffect=DROPEFFECT_NONE;
if (DataObject == 0)
return NOERROR;
TCoolEdit* coolEdit = TYPESAFE_DOWNCAST(Parent, TCoolEdit);
if(coolEdit->IsReadOnly() || !coolEdit->IsDragDrop()){
if(ShowIndicator)
HideDropIndicator(); // Hide Drop Caret
ShowIndicator = false;
return NOERROR;
}
return TDragDropProxy::DragOver(grfKeyState, pt, pdwEffect);
}
//
bool
TCoolEdit::TEditDragDropProxy::PerformDrop(IDataObject* dataObj, const TPoint& point, DROPEFFECT de)
{
TCoolEdit* coolEdit = TYPESAFE_DOWNCAST(Parent, TCoolEdit);
coolEdit->DropText(dataObj, point, de);
if(coolEdit->IsFlagSet(cfDraggingText))
return true;
return false;
}
//
#endif
//-------------------------------------------------------------------------------------------
//
//{{TCoolEdit Implementation}}
//
// Build a response table for all messages/commands handled
// by the application.
//
DEFINE_RESPONSE_TABLE1(TCoolEdit, TCoolSearchWnd)
EV_COMMAND_ENABLE(CM_EDITFIND, CeEditFindReplace),
EV_COMMAND(CM_EDITREPLACE, CmEditReplace),
EV_COMMAND_ENABLE(CM_EDITREPLACE, CeEditFindReplace),
EV_COMMAND(CM_EDITCUT, CmEditCut),
EV_COMMAND(CM_EDITPASTE, CmEditPaste),
// EV_COMMAND(CM_EDITDELETE, CmEditDelete), // no Delete
EV_COMMAND(CM_EDITCLEAR, CmEditClear), // ???
EV_COMMAND(CM_EDITUNDO, CmEditUndo),
EV_COMMAND(CM_EDITREDO, CmEditRedo),
// EV_COMMAND_ENABLE(CM_EDITCUT, CeSelectEnable),
// EV_COMMAND_ENABLE(CM_EDITDELETE, CeSelectEnable), // No Delete
EV_COMMAND_ENABLE(CM_EDITPASTE, CePasteEnable),
EV_COMMAND_ENABLE(CM_EDITCLEAR, CeCharsEnable),
EV_COMMAND_ENABLE(CM_EDITUNDO, CeUndoEnable),
EV_COMMAND_ENABLE(CM_EDITREDO, CeRedoEnable),
EV_WM_CHAR,
EV_WM_KEYDOWN,
END_RESPONSE_TABLE;
//--------------------------------------------------------
// TCoolEdit
//
TCoolEdit::TCoolEdit(TWindow* parent, int id, LPCTSTR title, int x, int y,
int w, int h, TModule* module)
:
TCoolSearchWnd(parent,id,title,x,y,w,h,module)
{
EnableCaret();
#if !defined(COOL_NODRAGDROP)
delete SetDragDropProxy(new TEditDragDropProxy(this));
#endif
}
//
TCoolEdit::~TCoolEdit()
{
// INSERT>> Your destructor code here.
}
//
// Perform a search or replace operation based on information in SearchData
//
void
TCoolEdit::DoSearch()
{
do{
if(Search(NULL_POS, SearchData.FindWhat, (TFindFlags)SearchData.Flags)){
if(SearchData.Flags & (ffReplace|ffReplaceAll))
ReplaceText(SearchData.ReplaceWith);
}
else {
if (SearchData.Flags & (ffFindNext|ffReplace)) {
tstring errTemplate(GetModule()->LoadString(IDS_CANNOTFIND));
TCHAR errMsg[81];
_stprintf(errMsg, errTemplate.c_str(), (LPCTSTR)SearchData.FindWhat);
/*SearchDialog->*/MessageBox(errMsg, 0, MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
}
else if (SearchData.Flags&ffReplaceAll)
break;
}
}
while (SearchData.Flags&ffReplaceAll);
}
//
void
TCoolEdit::InsertText(LPCTSTR text)
{
ClearSelection();
ReplaceText(text);
}
//
void
TCoolEdit::ReplaceText(LPCTSTR text)
{
if(IsReadOnly())
return;
PRECONDITION(GetBuffer());
TCoolTextBuffer& buffer = *GetBuffer();
TUndoDeleteSelection* undoSel = 0;
if(Selection)
undoSel = new TUndoDeleteSelection(*this, buffer.IsDirty());
DeleteSelection(1);
TEditPos savedPos = CursorPos;
buffer.InsertText(CursorPos, text, CursorPos);
buffer.AddUndoNode(new TUndoReplaceText(savedPos, CursorPos,
undoSel, buffer.IsDirty()));
InvalidateLines(savedPos.row, CursorPos.row);
AdjustScroller();
ScrollToCaret(CursorPos);
}
//
#if !defined(COOL_NODRAGDROP)
DROPEFFECT
TCoolEdit::GetDropEffect()
{
//_TRACE("TCoolEdit::GetDropEffect\n");
return DROPEFFECT_COPY|DROPEFFECT_MOVE;
}
//
void
TCoolEdit::DropSource(DROPEFFECT de)
{
//_TRACE("TCoolEdit::DropSource()\n");
// if not our window and move -> delete selection
if(de == DROPEFFECT_MOVE){
TCoolTextBuffer& buffer = *GetBuffer();
buffer.AddUndoNode(new TUndoDragDropMoveExt(*this, buffer.IsDirty()));
DeleteSelection(1);
}
}
//
void
TCoolEdit::PastFromDataObject(IDataObject* dataObj)
{
//_TRACE("TCoolEdit::PastFromDataObject() START\n");
// Actual Paste
HGLOBAL hGlobal = 0;
_TCHAR* pMemory = 0;
TSelType selection = stStreamSelection;
TStorageMedium stm;
TFormatEtc sfe(TCoolEdit::SelClipFormat, TYMED_HGLOBAL);
#ifdef _UNICODE
TFormatEtc tfe(CF_UNICODETEXT, TYMED_HGLOBAL);
#else
TFormatEtc tfe(CF_TEXT, TYMED_HGLOBAL);
#endif
if(dataObj->QueryGetData(&sfe) == NOERROR){
HRESULT hr = dataObj->GetData(&sfe, &stm);
if (SUCCEEDED(hr))
hGlobal = stm.hGlobal;
if(hGlobal)
pMemory = (_TCHAR*)::GlobalLock(hGlobal);
if(pMemory){
if(memcmp(pMemory,streamSelectionId,IdSelSize)==0)
selection = stStreamSelection;
else if(memcmp(pMemory,lineSelectionId,IdSelSize)==0)
selection = stLineSelection;
else if(memcmp(pMemory,lineSelectionId,IdSelSize)==0)
selection = stColumnSelection;
else{
pMemory = 0;
}
if(pMemory)
pMemory += IdSelSize;
}
}
else if(dataObj->QueryGetData(&tfe) == NOERROR){
HRESULT hr = dataObj->GetData(&tfe, &stm);
if (SUCCEEDED(hr))
hGlobal = stm.hGlobal;
if(hGlobal)
pMemory = (_TCHAR*)::GlobalLock(hGlobal);
}
else { // check additional source
#ifdef _UNICODE
TFormatEtc afe(CF_TEXT, TYMED_HGLOBAL);
#else
TFormatEtc afe(CF_UNICODETEXT, TYMED_HGLOBAL);
#endif
if(dataObj->QueryGetData(&afe) == NOERROR){
HRESULT hr = dataObj->GetData(&tfe, &stm);
if (SUCCEEDED(hr))
hGlobal = stm.hGlobal;
if(hGlobal){
USES_CONVERSION;
#ifdef _UNICODE
LPTSTR ptr = A2W((LPSTR)::GlobalLock(hGlobal));
#else
LPTSTR ptr = W2A((LPWSTR)::GlobalLock(hGlobal));
#endif
if(ptr)
PasteFromMemory(ptr, static_cast<int>(_tcslen(ptr)), selection);
}
pMemory = 0;
}
}
if(pMemory)
PasteFromMemory(pMemory, static_cast<int>(_tcslen(pMemory)), selection);
if(hGlobal)
::GlobalUnlock(hGlobal);
ReleaseStgMedium(&stm);
//_TRACE("TCoolEdit::PastFromDataObject() END\n");
}
//
void
TCoolEdit::DropText(IDataObject* src, const TPoint& point, DROPEFFECT de)
{
//_TRACE("TCoolEdit::DropText() START\n");
bool our_source = IsFlagSet(cfDraggingText);
//TEditPos pastePos = Client2Text(Text2Client(Client2Text(point)));
// if cursor under active selection and our source -> do nothig
if(our_source && IsInSelection(Client2Text(point))){
ClearSelection();
return;
}
TUndoDeleteSelection* undoSel = 0;
if(de == DROPEFFECT_COPY || !our_source){
ClearSelection();
}
TCoolTextBuffer& buffer = *GetBuffer();
if(our_source && Selection){
undoSel = new TUndoDeleteSelection(*this, buffer.IsDirty());
DeleteSelection(1);
}
bool savedDirty = buffer.IsDirty();
TEditPos pastePos = Client2Text(point);
SetCursorPos(pastePos); // new paste position
PastFromDataObject(src);
if(de == DROPEFFECT_COPY)
buffer.AddUndoNode(new TUndoDragDropCopy(pastePos, CursorPos, savedDirty));
else
buffer.AddUndoNode(new TUndoDragDropMove(pastePos, CursorPos, undoSel, savedDirty));
// and last Select new region
SetSelection(TEditRange(pastePos, CursorPos));
//_TRACE("TCoolEdit::DropText() END\n");
}
//
void TCoolEdit::ShowDropIndicator(const TPoint& point)
{
if(!IsFlagSet(cfDropPosVisible)){
HideCursor();
SavedCaretPos = GetCursorPos();
SetFlag(cfDropPosVisible);
::CreateCaret(GetHandle(), (HBITMAP)1, 2, GetLineHeight());
}
//if(dropPos.col >= GetOffsetChar()){
if(point.x >= GetOffsetChar()){
TEditPos dropPos = Client2Text(point);
SetCaretPos(Text2Client(dropPos));
ShowCaret();
}
else{
HideCaret();
}
}
//
void TCoolEdit::HideDropIndicator()
{
if(IsFlagSet(cfDropPosVisible)){
ClearFlag(cfHasCaret);
SetCursorPos(SavedCaretPos);
ClearFlag(cfDropPosVisible);
ShowCursor();
}
}
#endif
//
void
TCoolEdit::EvKeyDown(uint key, uint repeatCount, uint flags)
{
//We also need to handle delete & backspace here. Note that
//we don't use the repeat count - it's a little safer that
//way as Windows can stack up a *lot* of them if it was busy
//elsewhere for a while.
bool is_ctrl = ::GetAsyncKeyState(VK_CONTROL) & MSB;
switch (key){
case VK_BACK:
if(is_ctrl)
DeleteWordBack(1 /*repeatCount*/);
else
DeleteCharBack(1 /*repeatCount*/);
return;
case VK_DELETE:
if(is_ctrl)
DeleteWord(1 /*repeatCount*/);
else
DeleteChar(1 /*repeatCount*/);
return;
}
TCoolSearchWnd::EvKeyDown(key, repeatCount, flags);
}
//
void
TCoolEdit::EvChar(uint key, uint repeatCount, uint flags)
{
//We don't deal with console bells etc.
if (key < VK_ESCAPE && key != VK_TAB && key != VK_RETURN)
return;
if(key > 31 && key < 127)
InsertChar(key, repeatCount);
else if(key == VK_RETURN)
KeyEnter(repeatCount);
else if(key == VK_TAB){
bool is_shift = ::GetAsyncKeyState(VK_SHIFT) & MSB;
if(is_shift)
KeyUnTab(repeatCount);
else
KeyTab(repeatCount);
}
else
TCoolSearchWnd::EvChar(key, repeatCount, flags);
//ScrollToCaret();
//UpdateWindow();//?????????? or Invaliadte(false)???
}
//
int TCoolEdit::DeleteSelection(uint repeatCount)
{
if(Selection){
// calculate endpos
TEditRange range(Selection->GetStart(), Selection->GetEnd());
range.Normalize();
CursorPos = range.Start();
Selection->Delete();
ClearSelection();
AdjustScroller();
ScrollToCaret(CursorPos);
InvalidateLines(0, -1, false);
repeatCount--;
}
return repeatCount;
}
//
void
TCoolEdit::InsertChar(uint key, uint repeatCount)
{
if(IsReadOnly())
return;
PRECONDITION(GetBuffer());
TCoolTextBuffer& buffer = *GetBuffer();
_TCHAR text[2] = {static_cast<_TCHAR>(key), 0};
TUndoDeleteSelection* undoSel = 0;
if(Selection)
undoSel = new TUndoDeleteSelection(*this, buffer.IsDirty());
DeleteSelection(repeatCount);
TEditPos endPos(CursorPos);
while(repeatCount--){
buffer.AddUndoNode(new TUndoInsertChar(key, endPos.row, endPos.col,
undoSel, IsFlagSet(cfOverType), buffer.IsDirty()));
if(IsFlagSet(cfOverType)){
if(buffer.GetLineLength(endPos.row) > endPos.col)
buffer.GetLineText(endPos.row)[endPos.col++] = key;
else
buffer.InsertText(endPos, text, endPos);
}
else
buffer.InsertText(endPos, text, endPos);
undoSel = 0;
}
InvalidateLines(CursorPos.row, endPos.row);
CursorPos = endPos;
ScrollToCaret(CursorPos);
}
//
void
TCoolEdit::KeyEnter(uint repeatCount)
{
if(IsReadOnly())
return;
PRECONDITION(GetBuffer());
TCoolTextBuffer& buffer = *GetBuffer();
TUndoDeleteSelection* undoSel = 0;
if(Selection && !IsFlagSet(cfOverType)){
undoSel = new TUndoDeleteSelection(*this, buffer.IsDirty());
DeleteSelection(repeatCount);
}
TEditPos endPos(CursorPos);
while(repeatCount--){
if(!IsFlagSet(cfOverType)){
TUndoKeyEnter* node = new TUndoKeyEnter(endPos.row, endPos.col,
undoSel, buffer.IsDirty());
buffer.AddUndoNode(node);
buffer.InsertText(endPos, crlf, endPos);
endPos.col = GetSmartPosition(endPos);
TEditPos pos(0, endPos.row);
for(int i = 0; i < endPos.col; i++){
buffer.InsertText(pos, _T(" "), pos);
}
node->SetNewPos(endPos.col);
}
else{
endPos.row++;
endPos.col = GetSmartPosition(endPos);
}
undoSel = 0;
}
CursorPos = endPos;
AdjustScroller();
ScrollToCaret(CursorPos);
InvalidateLines(0, -1, false);
}
//
void
TCoolEdit::KeyTab(uint repeatCount)
{
if(IsReadOnly())
return;
// do nothing if selection and overtype
if(Selection && IsFlagSet(cfOverType))
return;
PRECONDITION(GetBuffer());
TCoolTextBuffer& buffer = *GetBuffer();
int startLine=0, endLine=0; InUse(endLine);
if(Selection){
// adjust selection
bool fixedCursor = false;
TEditPos startSel(Selection->GetStart());
TEditPos endSel(Selection->GetEnd());
if(Selection->GetType() == stStreamSelection){
// in case current SelType changed
TSelType saveType = SelType;
SelType = stStreamSelection;
startSel.col = 0;
endSel.col = endSel.col > 0 ? buffer.GetLineLength(endSel.row) : 0;
SetSelection(TEditRange(startSel, endSel));
SelType = saveType;
if(endSel.col > 0)
CursorPos.row = endSel.row+1;
else{
CursorPos.row = endSel.row;
endSel.row--;
}
CursorPos.col = 0;
fixedCursor = true;
startLine = startSel.row;
}
int endChar = CursorPos.col;
while(repeatCount--){
buffer.AddUndoNode(new TUndoKeyTabify(endChar, startSel.row, CursorPos.row,
buffer.IsDirty()));
// shift all characters right
TEditPos deltaPos;//deltaChar;
for(deltaPos.row = startSel.row; deltaPos.row <= endSel.row; deltaPos.row++){
deltaPos.col = endChar;
buffer.InsertText(deltaPos, szTab, deltaPos);
}
endChar = deltaPos.col;
}
//CursorPos.row = endLine;
if(!fixedCursor)
CursorPos.col = endChar;
endLine = endSel.row;
}
else{
int tabSize = GetTabSize();
int lineLength = buffer.GetLineLength(CursorPos.row);
LPCTSTR text = buffer.GetLineText(CursorPos.row);
startLine = CursorPos.row;
while(repeatCount--){
if(CursorPos.col>=lineLength || !IsFlagSet(cfOverType)){
buffer.AddUndoNode(new TUndoKeyTab(*this, CursorPos, 1, true,
buffer.IsDirty()));
buffer.InsertText(CursorPos, szTab, CursorPos);
}
else{
if(text[CursorPos.col] == chTab){
buffer.AddUndoNode(new TUndoKeyTab(*this, CursorPos, 1, false,
buffer.IsDirty()));
CursorPos.col++;
}
else{
buffer.AddUndoNode(new TUndoKeyTab(*this, CursorPos, tabSize, false,
buffer.IsDirty()));
CursorPos.col += tabSize;
}
}
}
endLine = CursorPos.row;
}
ScrollToCaret(CursorPos);
InvalidateLines(startLine, endLine);
}
//
void
TCoolEdit::KeyUnTab(uint /*repeatCount*/)
{
ClearSelection();
if(IsReadOnly() || CursorPos.col == 0)
return;
PRECONDITION(GetBuffer());
TCoolTextBuffer& buffer = *GetBuffer();
LPCTSTR text= buffer.GetLineText(CursorPos.row);
int length = buffer.GetLineLength(CursorPos.row);
if(CursorPos.col < length && text[CursorPos.col-1] == chTab)
CursorPos.col--;
else
CursorPos.col -= GetTabSize();
ScrollToCaret(CursorPos);
InvalidateLines(CursorPos.row, CursorPos.row);
}
//
void
TCoolEdit::DeleteWordBack(uint repeatCount)
{
if(IsReadOnly())
return;
PRECONDITION(GetBuffer());
TCoolTextBuffer& buffer = *GetBuffer();
int startLine = CursorPos.row;
TUndoDeleteSelection* undoSel = 0;
if(Selection)
undoSel = new TUndoDeleteSelection(*this, buffer.IsDirty());
DeleteSelection(repeatCount);
if(CursorPos.row==0 && CursorPos.col==0){
if(undoSel)
buffer.AddUndoNode(undoSel);
return;
}
while(repeatCount--){
TEditPos savedPos = CursorPos;
CursorPos.col--;
if(CursorPos.col < 0){
if(CursorPos.row==0){
CursorPos.col = 0;
break;
}
CursorPos.row--;
CursorPos.col = buffer.GetLineLength(CursorPos.row);
}
TEditPos startSel = StartWord(CursorPos);
buffer.AddUndoNode(new TUndoDeleteWordBack(buffer, savedPos, startSel, undoSel));
undoSel = 0;
buffer.DeleteText(TEditRange(startSel, savedPos));
CursorPos = startSel;
}
AdjustScroller();
ScrollToCaret(CursorPos);
InvalidateLines(CursorPos.row, startLine);
}
//
void
TCoolEdit::DeleteCharBack(uint repeatCount)
{
if(IsReadOnly())
return;
PRECONDITION(GetBuffer());
TCoolTextBuffer& buffer = *GetBuffer();
TUndoDeleteSelection* undoSel = 0;
if(Selection)
undoSel = new TUndoDeleteSelection(*this, buffer.IsDirty());
repeatCount = DeleteSelection(repeatCount);
if(!repeatCount){
if(undoSel)
buffer.AddUndoNode(undoSel);
return;
}
TEditPos curPos(CursorPos);
while(repeatCount--){
if(curPos.col==0){
if(curPos.row==0)
break;
buffer.AddUndoNode(new TUndoDeleteCharBack(buffer,
curPos.row, curPos.col, undoSel));
undoSel = 0;
//insert next line
int len = buffer.GetLineLength(curPos.row);
TTmpBuffer<_TCHAR> __tmpObj(len+1);
memcpy((_TCHAR*)__tmpObj,buffer.GetLineText(curPos.row),len);
((_TCHAR*)__tmpObj)[len] = 0;
curPos.row--;
curPos.col = buffer.GetLineLength(curPos.row);
TEditPos endPos;
buffer.InsertText(curPos, __tmpObj, endPos);
// delete entare line
TEditRange range(0, curPos.row+1, -1, curPos.row+1);
buffer.DeleteText(range);
InvalidateLines(0, -1);
continue;
}
buffer.AddUndoNode(new TUndoDeleteCharBack(buffer,
curPos.row, curPos.col, undoSel));
undoSel = 0;
TEditRange range(curPos.col-1,curPos.row, curPos.col, curPos.row);
buffer.DeleteText(range);
curPos.col--;
}
InvalidateLines(curPos.row, CursorPos.row);
CursorPos = curPos;
AdjustScroller();
ScrollToCaret(CursorPos);
}
//
void
TCoolEdit::DeleteWord(uint repeatCount)
{
if(IsReadOnly())
return;
PRECONDITION(GetBuffer());
TCoolTextBuffer& buffer = *GetBuffer();
TUndoDeleteSelection* undoSel = 0;
if(Selection)
undoSel = new TUndoDeleteSelection(*this, buffer.IsDirty());
DeleteSelection(repeatCount);
while(repeatCount--){
if(CursorPos.col == buffer.GetLineLength(CursorPos.row))
break;
LPCTSTR p = buffer.GetLineText(CursorPos.row);
TEditPos endpos(CursorPos);
if(isWordChar(p[endpos.col]))
endpos = EndWord(endpos);
else{
while(!isWordChar(p[endpos.col]))
endpos.col++;
}
buffer.AddUndoNode(new TUndoDeleteWord(buffer, CursorPos, endpos, undoSel));
undoSel = 0;
buffer.DeleteText(TEditRange(CursorPos, endpos));
//CursorPos.col = endpos.col;
}
if(undoSel)
buffer.AddUndoNode(undoSel);
ScrollToCaret(CursorPos);
InvalidateLines(CursorPos.row, CursorPos.row);
}
//
void
TCoolEdit::DeleteChar(uint repeatCount)
{
if(IsReadOnly())
return;
PRECONDITION(GetBuffer());
TCoolTextBuffer& buffer = *GetBuffer();
TUndoDeleteSelection* undoSel = 0;
if(Selection)
undoSel = new TUndoDeleteSelection(*this, buffer.IsDirty());
repeatCount = DeleteSelection(repeatCount);
if(!repeatCount){
if(undoSel)
buffer.AddUndoNode(undoSel);
return;
}
TEditPos curPos(CursorPos);
while(repeatCount--){
if(curPos.col == buffer.GetLineLength(curPos.row)){
if(curPos.row >= buffer.GetLineCount()-1)
break;
buffer.AddUndoNode(new TUndoDeleteChar(buffer, curPos.row, curPos.col, undoSel));
undoSel = 0;
//insert next line
int len = buffer.GetLineLength(curPos.row+1);
TTmpBuffer<_TCHAR> __tmpObj(len+1);
memcpy((_TCHAR*)__tmpObj,buffer.GetLineText(curPos.row+1),len);
((_TCHAR*)__tmpObj)[len] = 0;
TEditPos endPos;
buffer.InsertText(curPos, __tmpObj, endPos);
// delete entare line
buffer.DeleteText(TEditRange(0,curPos.row+1, -1, curPos.row+1));
InvalidateLines(0, -1);
continue;
}
buffer.AddUndoNode(new TUndoDeleteChar(buffer, curPos.row, curPos.col, undoSel));
undoSel = 0;
buffer.DeleteText(TEditRange(curPos.col, curPos.row, curPos.col+1, curPos.row));
}
if(curPos.row != CursorPos.row)
InvalidateLines(0, -1);
else
InvalidateLines(curPos.row, CursorPos.row);
AdjustScroller();
}
//
void
TCoolEdit::CmEditReplace()
{
if(IsReadOnly())
return;
if (!SearchCmd) {
SearchCmd = CM_EDITREPLACE;
delete SearchDialog;
SearchDialog = new TCoolReplaceDlg(this, SearchData);
SetFlag(cfShowInactiveSel);
SearchDialog->Create();
SearchDialog->ShowWindow(SW_SHOWDEFAULT);
}
}
//
void
TCoolEdit::CeEditFindReplace(TCommandEnabler& ce)
{
ce.Enable(!SearchCmd && !IsReadOnly());
}
//
void
TCoolEdit::Delete()
{
if(IsReadOnly())
return;
PRECONDITION(GetBuffer());
TCoolTextBuffer& buffer = *GetBuffer();
if(Selection)
buffer.AddUndoNode(new TUndoDeleteSelection(*this, buffer.IsDirty()));
DeleteSelection(1);
//AdjustScroller();
//Invalidate();
}
//
void
TCoolEdit::CmEditDelete()
{
Delete();
}
//
static _TCHAR*
FindEndLine(_TCHAR* text, int& size)
{
int textPos = 0;
while(text[textPos] != 0 && text[textPos] != _T('\r'))
textPos++;
if(text[textPos]){
if(text[textPos] == _T('\n'))
textPos++;
size -= textPos;
}
return &text[textPos];
}
//
static void
PasteFromMemoryImp(_TCHAR* pMemory, int size, TCoolEdit::TSelType selection,
TEditPos& cursorPos, TCoolTextBuffer& buffer)
{
switch(selection){
case TCoolEdit::stStreamSelection:
case TCoolEdit::stLineSelection:{
TEditPos curPos(cursorPos);
buffer.InsertText(curPos, pMemory, curPos);
cursorPos = curPos;
}
break;
case TCoolEdit::stColumnSelection:{
TEditPos curPos(cursorPos);
_TCHAR* text = pMemory;
while(size){
_TCHAR* endTxt = FindEndLine(pMemory, size);
if(endTxt){
_TCHAR c = *endTxt;
*endTxt = 0;
buffer.InsertText(curPos, text, curPos);
*endTxt = c;
text = endTxt + 1; // next
size--;
}
else{
_TCHAR c = text[size-1];
text[size-1] = 0;
buffer.InsertText(curPos, text, curPos);
text[size-1] = c;
break;
}
}
cursorPos = curPos;
}
break;
}
}
//
void
TCoolEdit::PasteFromMemory(_TCHAR* pMemory, int size, TSelType selection)
{
PasteFromMemoryImp(pMemory, size, selection, CursorPos, *GetBuffer());
ScrollToCaret(CursorPos);
AdjustScroller();
InvalidateLines(0, -1);
}
//
bool
TCoolEdit::Paste()
{
if(IsReadOnly())
return false;
TCoolTextBuffer& buffer = *GetBuffer();
TUndoDeleteSelection* undoSel = 0;
if(Selection)
undoSel = new TUndoDeleteSelection(*this, buffer.IsDirty());
DeleteSelection(1);
TEditPos savedPos = CursorPos;
bool savedDirty = buffer.IsDirty();
TClipboard clipboard(*this);
if (!clipboard)
return false;
HGLOBAL hGlobal = 0;
_TCHAR* pMemory = 0;
TSelType selection = stStreamSelection;
if(clipboard.IsClipboardFormatAvailable(SelClipFormat)){
hGlobal = clipboard.GetClipboardData(SelClipFormat);
if(hGlobal)
pMemory = (_TCHAR*)::GlobalLock(hGlobal);
if(pMemory){
if(memcmp(pMemory,streamSelectionId,IdSelSize)==0)
selection = stStreamSelection;
else if(memcmp(pMemory,lineSelectionId,IdSelSize)==0)
selection = stLineSelection;
else if(memcmp(pMemory,lineSelectionId,IdSelSize)==0)
selection = stColumnSelection;
else{
pMemory = 0;
}
if(pMemory)
pMemory += IdSelSize;
}
}
#ifdef _UNICODE
else if(clipboard.IsClipboardFormatAvailable(CF_UNICODETEXT)){
hGlobal = clipboard.GetClipboardData(CF_UNICODETEXT);
#else
else if(clipboard.IsClipboardFormatAvailable(CF_TEXT)){
hGlobal = clipboard.GetClipboardData(CF_TEXT);
#endif
if(hGlobal)
pMemory = (_TCHAR*)::GlobalLock(hGlobal);
}
if(pMemory){
PasteFromMemory(pMemory, static_cast<int>(_tcslen(pMemory)), selection);
buffer.AddUndoNode(new TUndoPaste(savedPos, CursorPos, undoSel, savedDirty));
}
if(hGlobal)
::GlobalUnlock(hGlobal);
return pMemory!=0;
}
//
void
TCoolEdit::ClearAll()
{
if(IsReadOnly())
return;
PRECONDITION(GetBuffer());
TCoolTextBuffer& buffer = *GetBuffer();
TUndoClearAll* node = new TUndoClearAll(*this, CursorPos, buffer.IsDirty());
buffer.Clear();
buffer.SetDirty(true);
buffer.AddUndoNode(node);
CursorPos.col = 0;
CursorPos.row = 0;
ScrollToCaret(CursorPos);
AdjustScroller();
InvalidateLines(0, -1);
}
//
void
TCoolEdit::Cut()
{
if(IsReadOnly())
return;
PRECONDITION(GetBuffer());
TCoolTextBuffer& buffer = *GetBuffer();
buffer.AddUndoNode(new TUndoDeleteSelection(*this, buffer.IsDirty()));
CopySelection();
DeleteSelection(1);
AdjustScroller();
InvalidateLines(0, -1);
}
//
void
TCoolEdit::CePasteEnable(TCommandEnabler& tce)
{
TClipboard cb(*this, false);
tce.Enable(!IsReadOnly() && (cb.IsClipboardFormatAvailable(SelClipFormat) ||
#ifdef _UNICODE
cb.IsClipboardFormatAvailable(CF_UNICODETEXT)
#else
cb.IsClipboardFormatAvailable(CF_TEXT)
#endif
));
}
//
void
TCoolEdit::CeCharsEnable(TCommandEnabler& tce)
{
tce.Enable((GetNumLines()>1 || GetLineLength(0)>0) && !IsReadOnly());
}
//
void
TCoolEdit::CmEditUndo()
{
PRECONDITION(GetBuffer());
TEditPos pos;
TCoolTextBuffer* buffer = GetBuffer();
if(buffer->Undo(&pos)){
InvalidateLines(0, -1); // Y.B. Can we query invalid region???
CursorPos = pos;
ScrollToCaret(CursorPos);
AdjustScroller();
}
}
//
void
TCoolEdit::CmEditRedo()
{
PRECONDITION(GetBuffer());
GetBuffer()->Redo();
}
//
void
TCoolEdit::CeUndoEnable(TCommandEnabler& tce)
{
PRECONDITION(GetBuffer());
tce.Enable(GetBuffer()->CanUndo());
//can also set text
//TCoolTextBuffer::TUndoNode* node = GetBuffer()->GetTopUndoNode();
//if(node){
// _TCHAR buffer[256];
// if(node->GetDescription(buffer,256, GetApplication()))
// tce.SetTex(buffer)
//}
}
//
void
TCoolEdit::CeRedoEnable(TCommandEnabler& tce)
{
PRECONDITION(GetBuffer());
tce.Enable(GetBuffer()->CanRedo());
//can also set text
//TCoolTextBuffer::TRedoNode* node = GetBuffer()->GetTopRedoNode();
//if(node){
// _TCHAR buffer[256];
// if(node->GetDescription(buffer,256,GetApplication()))
// tce.SetTex(buffer)
//}
}
//
// Smart AutoIntend
//
int
TCoolEdit::GetSmartPosition(const TEditPos& pos)
{
int index = 0;
if(IsAutoIndent() && !IsFlagSet(cfOverType)){
// Take indentation from the previos line
TCoolTextBuffer* buffer = GetBuffer();
int len = buffer->GetLineLength(pos.row - 1);
LPCTSTR text = buffer->GetLineText(pos.row - 1);
while(index < len && _istspace(text[index])){
if(text[index] == chTab)
index += GetTabSize();
else
index++;
}
}
return index;
}
//----------------------------------------------------------------------------
// TCoolEditFile Implementation
//
DEFINE_RESPONSE_TABLE1(TCoolEditFile, TCoolEdit)
// !!! BUG EV_COMMAND(CM_FILENEW, CmFileNew), // BUG !!!!!!!
// !!! BUG EV_COMMAND(CM_FILEOPEN, CmFileOpen), // BUG !!!!!!!
EV_COMMAND(CM_FILESAVE, CmFileSave),
EV_COMMAND(CM_FILESAVEAS, CmFileSaveAs),
EV_COMMAND_ENABLE(CM_FILESAVE, CmSaveEnable),
END_RESPONSE_TABLE;
//
TCoolEditFile::TCoolEditFile(TWindow* parent, int id, LPCTSTR title, int x,
int y, int w, int h, LPCTSTR fileName,
TModule* module)
:
TCoolEdit(parent, id, title, x, y, w, h, module)
{
FileName = fileName ? strnewdup(fileName) : 0;
}
//
TCoolEditFile::~TCoolEditFile()
{
delete[] FileName;
}
//
// performs setup for a TEditFile
//
void
TCoolEditFile::SetupWindow()
{
TCoolEdit::SetupWindow();
FileData.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_EXPLORER|OFN_ENABLESIZING;
FileData.SetFilter(GetModule()->LoadString(IDS_FILEFILTER).c_str());
SetFileName(FileName);
if (FileName && !TCoolEdit::FileOpen(FileName)){
tstring msgTemplate(GetModule()->LoadString(IDS_UNABLEREAD));
LPTSTR msg = new _TCHAR[_MAX_PATH + msgTemplate.length()];
_stprintf(msg, msgTemplate.c_str(), FileName);
MessageBox(msg, 0, MB_ICONEXCLAMATION | MB_OK);
delete[] msg;
SetFileName(0);
}
}
//
// sets the file name of the window and updates the caption
// replacing an empty name with 'Untitled' in its caption
//
void
TCoolEditFile::SetFileName(LPCTSTR fileName)
{
if (fileName != FileName) {
delete[] FileName;
FileName = fileName ? strnewdup(fileName) : 0;
}
tstring untitled(GetModule()->LoadString(IDS_UNTITLEDFILE));
SetDocTitle(FileName ? (LPCTSTR)FileName : untitled.c_str(), 0);
}
//
void
TCoolEditFile::FileNew()
{
if(CanClear()){
TCoolEdit::FileNew();
SetFileName(0);
}
}
//
bool
TCoolEditFile::FileOpen(LPCTSTR filename)
{
if (filename==0 && CanClear()){
*FileData.FileName = 0;
if (TFileOpenDialog(this, FileData).Execute() == IDOK){
if(TCoolEdit::FileOpen(FileData.FileName))
SetFileName(FileData.FileName);
else{
tstring msgTemplate(GetModule()->LoadString(IDS_UNABLEREAD));
LPTSTR msg = new TCHAR[_MAX_PATH + msgTemplate.length()];
_stprintf(msg, msgTemplate.c_str(), FileData.FileName);
MessageBox(msg, 0, MB_ICONEXCLAMATION | MB_OK);
delete[] msg;
return false;
}
}
}
else {
if(TCoolEdit::FileOpen(filename)){
SetFileName(filename);
return true;
}
else{
tstring msgTemplate(GetModule()->LoadString(IDS_UNABLEREAD));
LPTSTR msg = new TCHAR[_MAX_PATH + msgTemplate.length()];
_stprintf(msg, msgTemplate.c_str(), filename);
MessageBox(msg, 0, MB_ICONEXCLAMATION | MB_OK);
delete[] msg;
return false;
}
}
return false;
}
//
bool
TCoolEditFile::FileSave()
{
if (GetBuffer()->IsDirty()) {
if(!FileName)
return FileSaveAs();
if (!GetBuffer()->Save(FileName)) {
tstring msgTemplate(GetModule()->LoadString(IDS_UNABLEWRITE));
LPTSTR msg = new TCHAR[_MAX_PATH + msgTemplate.length()];
_stprintf(msg, msgTemplate.c_str(), FileName);
MessageBox(msg, 0, MB_ICONEXCLAMATION | MB_OK);
delete[] msg;
return false;
}
}
return true;
}
//
bool
TCoolEditFile::FileSaveAs()
{
if (FileName)
_tcscpy(FileData.FileName, FileName);
else
*FileData.FileName = 0;
if (TFileSaveDialog(this, FileData).Execute() == IDOK) {
if(GetBuffer()->Save(FileData.FileName)){
SetFileName(FileData.FileName);
return true;
}
tstring msgTemplate(GetModule()->LoadString(IDS_UNABLEWRITE));
LPTSTR msg = new TCHAR[_MAX_PATH + msgTemplate.length()];
_stprintf(msg, msgTemplate.c_str(), FileName);
MessageBox(msg, 0, MB_ICONEXCLAMATION | MB_OK);
delete[] msg;
}
return false;
}
//
void
TCoolEditFile::CmSaveEnable(TCommandEnabler& tce)
{
tce.Enable(GetBuffer()->IsDirty());
}
//
// returns a bool value indicating whether or not it is Ok to clear
// the TEdit's text
//
// returns true if the text has not been changed, or if the user Oks the
// clearing of the text
//
bool
TCoolEditFile::CanClear()
{
if (GetBuffer()->IsDirty()) {
tstring msgTemplate(GetModule()->LoadString(IDS_FILECHANGED));
tstring untitled(GetModule()->LoadString(IDS_UNTITLEDFILE));
LPTSTR msg = new TCHAR[_MAX_PATH+msgTemplate.length()];
_stprintf(msg, msgTemplate.c_str(),
FileName ? (LPCTSTR)FileName : untitled.c_str());
int result = MessageBox(msg, 0, MB_YESNOCANCEL|MB_ICONQUESTION);
delete[] msg;
return result==IDYES ? FileSave() : result != IDCANCEL;
}
return true;
}
//
bool
TCoolEditFile::CanClose()
{
return TCoolEdit::CanClose();
}
//----------------------------------------------------------------------------
// TCoolSearchView Implementation
//
//
// Build a response table for all messages/commands handled
// by TCoolSearchView derived from TCoolSearchWnd.
//
DEFINE_RESPONSE_TABLE1(TCoolSearchView, TCoolSearchWnd)
EV_VN_ISWINDOW,
END_RESPONSE_TABLE;
//
TCoolSearchView::TCoolSearchView(TDocument& doc, TWindow* parent)
:
TCoolSearchWnd(parent, 0, _T(""), 0, 0, 0, 0, 0),
TView(doc)
{
}
//
//----------------------------------------------------------------------------
// TCoolEditView Implementation
//
//
// Build a response table for all messages/commands handled
// by TCoolEditView derived from TCoolEdit.
//
DEFINE_RESPONSE_TABLE1(TCoolEditView, TCoolEdit)
EV_VN_ISWINDOW,
END_RESPONSE_TABLE;
//
TCoolEditView::TCoolEditView(TDocument& doc, TWindow* parent)
:
TCoolEdit(parent, 0, _T(""), 0, 0, 0, 0, 0),
TView(doc)
{
}
//
/////////////////////////////////////////////////////////////////////////////////////////
//
↑ V220 Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize. The value being cast: 'strlen(pos)'.
↑ V220 Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize. The value being cast: '(cur - pat) + 16'.
↑ V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 6814, 6816.
↑ V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 7016, 7018.
↑ V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 7366, 7368.
↑ V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 8068, 8070.
↑ V595 The 'Window' pointer was utilized before it was verified against nullptr. Check lines: 1544, 1546.
↑ V611 The memory was allocated using 'new T[]' operator but was released using the 'delete' operator. Consider inspecting this code. It's probably better to use 'delete [] SyntaxArray;'.
↑ V611 The memory was allocated using 'new T[]' operator but was released using the 'delete' operator. Consider inspecting this code. It's probably better to use 'delete [] DeltaTable;'. Check lines: 4419, 4391.
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: UndoSel.
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: UndoSel.
↑ V758 The 'text' reference becomes invalid when temporary object returned by a function is destroyed.
↑ V763 Parameter 'invalidateMargin' is always rewritten in function body before being used.
↑ V765 A compound assignment expression 'lineLen -= lineLen - searchRange.ecol' is suspicious. Consider inspecting it for a possible error.
↑ V765 A compound assignment expression 'lineLen -= lineLen - searchRange.ecol' is suspicious. Consider inspecting it for a possible error.
↑ V773 The function was exited without releasing the 'undoSel' pointer. A memory leak is possible.
↑ V1004 The 'node' pointer was used unsafely after it was verified against nullptr. Check lines: 287, 288.
↑ V1004 The 'node' pointer was used unsafely after it was verified against nullptr. Check lines: 298, 299.
↑ V1004 The 'str2' pointer was used unsafely after it was verified against nullptr. Check lines: 579, 580.
↑ V1004 The 'str1' pointer was used unsafely after it was verified against nullptr. Check lines: 579, 582.
↑ V1004 The 'str2' pointer was used unsafely after it was verified against nullptr. Check lines: 629, 630.
↑ V1004 The 'str1' pointer was used unsafely after it was verified against nullptr. Check lines: 629, 631.
↑ V1004 The 'buffer' pointer was used unsafely after it was verified against nullptr. Check lines: 1790, 1796.
↑ V1004 The 'buffer' pointer was used unsafely after it was verified against nullptr. Check lines: 2922, 2924.
↑ V1004 The 'buffer' pointer was used unsafely after it was verified against nullptr. Check lines: 2965, 2966.
↑ V1004 The 'wnd.Selection' pointer was used unsafely after it was verified against nullptr. Check lines: 6785, 6786.
↑ V1004 The 'wnd.Selection' pointer was used unsafely after it was verified against nullptr. Check lines: 6991, 6992.
↑ V522 There might be dereferencing of a potential null pointer 'wnd'.
↑ V522 There might be dereferencing of a potential null pointer 'dynamic_cast< TCoolEdit * > (Parent)'.
↑ V522 There might be dereferencing of a potential null pointer 'dynamic_cast< TCoolEdit * > (Parent)'.
↑ V522 There might be dereferencing of a potential null pointer 'dynamic_cast< TCoolEdit * > (Parent)'.
↑ V522 There might be dereferencing of a potential null pointer 'coolEdit'.
↑ V522 There might be dereferencing of a potential null pointer 'coolEdit'.
↑ V536 Be advised that the utilized constant value is represented by an octal form. Oct: '\033', Dec: 27.
↑ V547 Expression '!invalidateMargin' is always false.
↑ V547 Expression '!invalidateMargin' is always false.
↑ V557 Array overrun is possible. The value of 'i' index could reach 18.
↑ V560 A part of conditional expression is always true: selBegin >= 0.
↑ V560 A part of conditional expression is always true: selEnd >= 0.
↑ V560 A part of conditional expression is always true: p.row >= 0.
↑ V560 A part of conditional expression is always true: index >= 0.
↑ V605 Consider verifying the expression. An unsigned value is compared to the number belonging to the range [-1..18].
↑ V678 An object is used as an argument to its own method. Consider checking the first actual argument of the 'AddDefaultEngines' function.
↑ V690 The copy constructor is declared as private in the 'TUndoDeleteChar' class, but the default copy assignment operator will still be generated by compiler. It is dangerous to use such a class.
↑ V690 The copy constructor is declared as private in the 'TUndoDeleteWord' class, but the default copy assignment operator will still be generated by compiler. It is dangerous to use such a class.
↑ V690 The copy constructor is declared as private in the 'TUndoPaste' class, but the default copy assignment operator will still be generated by compiler. It is dangerous to use such a class.
↑ V690 The copy constructor is declared as private in the 'TUndoDragDropMove' class, but the default copy assignment operator will still be generated by compiler. It is dangerous to use such a class.
↑ V773 The 'SearchDialog' pointer was not released in destructor. A memory leak is possible.
↑ V1004 The 'buffer' pointer was used unsafely after it was verified against nullptr. Check lines: 2951, 2953.
↑ V522 There might be dereferencing of a potential null pointer 'pBuf'.
↑ V522 There might be dereferencing of a potential null pointer 'text'.
↑ V522 There might be dereferencing of a potential null pointer 'metaph'.
↑ V524 It is odd that the body of 'EvCommandenableFindback' function is fully equivalent to the body of 'EvCommandenableFindfrw' function.
↑ V524 It is odd that the body of 'CeReplaceAll' function is fully equivalent to the body of 'CeReplace' function.
↑ V547 Expression 'length' is always true.
↑ V576 Incorrect format. Consider checking the fourth actual argument of the 'sprintf_s' function. The UNSIGNED integer type argument is expected.
↑ V690 The copy constructor is declared as private in the 'TUndoKeyTab' class, but the default copy assignment operator will still be generated by compiler. It is dangerous to use such a class.
↑ V690 The copy constructor is declared as private in the 'TUndoDeleteSelection' class, but the default copy assignment operator will still be generated by compiler. It is dangerous to use such a class.
↑ V690 The copy constructor is declared as private in the 'TUndoDragDropMoveExt' class, but the default copy assignment operator will still be generated by compiler. It is dangerous to use such a class.
↑ V690 The copy constructor is declared as private in the 'TUndoDragDropCopy' class, but the default copy assignment operator will still be generated by compiler. It is dangerous to use such a class.
↑ V793 It is odd that the result of the 'pBuf[i + 1].CharPos - pBuf[i].CharPos' statement is a part of the condition. Perhaps, this statement should have been compared with something else.
↑ V793 It is odd that the result of the 'length - pBuf[blocks - 1].CharPos' statement is a part of the condition. Perhaps, this statement should have been compared with something else.
↑ V805 Decreased performance. It is inefficient to identify an empty string by using 'strlen(str) > 0' construct. A more efficient way is to check: str[0] != '\0'.
↑ V806 Decreased performance. The expression of strlen(MyStr.c_str()) kind can be rewritten as MyStr.length().
↑ V818 It is more efficient to use an initialization list 'Pattern(pattern)' rather than an assignment operator.
↑ V815 Decreased performance. Consider replacing the expression 'line = ""' with 'line.clear()'.
↑ V821 Decreased performance. The 'savename' variable can be constructed in a lower level scope.
↑ V821 Decreased performance. The 'savedPos' variable can be constructed in a lower level scope.