www.pudn.com > TurboPadSource.tar.gz > stextctrl.cpp


/** 
*    \file Styled Text Control implementation 
* 
*    Implementation of STextCtrl functions. 
*/ 
 
#include "stextctrl.h" 
 
STextCtrl::STextCtrl(CPtr parent, wxWindowID id, 
                     const wxPoint &pos, const wxSize& size, long style) 
         : wxStyledTextCtrl(parent, id, pos, size, style), 
         findFlags(0), braceLoc(-1), recording(false) 
{ 
    InitOptions(); 
    InitMargins(); 
    InitDefaultStyles(); 
 
    wxAcceleratorEntry accEntry[3]; 
    accEntry[0].Set(wxACCEL_CTRL, (int) WXK_RETURN, Txt_AutoComplete); 
    accEntry[1].Set(wxACCEL_CTRL, (int) WXK_F3, Txt_FindWord); 
    accEntry[2].Set(wxACCEL_SHIFT | wxACCEL_CTRL, (int) WXK_F3, Txt_FindPreviousWord); 
    wxAcceleratorTable accTable(3, accEntry); 
    SetAcceleratorTable(accTable); 
 
    SetFocus(); 
} 
 
void STextCtrl::BlockCommentSelection(const wxString &comment) 
{ 
    int lines = LinesSelected(); 
    int cline = GetCurrentLine(); 
 
    BeginUndoAction(); 
 
    for (int i = cline; i <= cline + lines; i++) 
        InsertText(PositionFromLine(i), comment); 
 
    EndUndoAction(); 
} 
 
void STextCtrl::CharAdded(wxStyledTextEvent &event) 
{ 
    char chr = event.GetKey(); 
    int currentLine = GetCurrentLine(); 
     
    if (recording) 
        mac.Add(chr); 
 
    if (chr == '\r' || chr == '\n') 
    { 
        int lineInd = 0; 
 
        if (currentLine > 0) 
            lineInd = GetLineIndentation(currentLine-1); 
 
        if ((GetLine(currentLine-1).Contains('{') && !GetLine(currentLine-1).Contains('}') 
                && GetParent()->GetHil() != "Pascal") 
                || (GetGrandParent()->GetSyntax()->HasIndentationWord(GetLine(currentLine-1)))) 
            lineInd += GetTabWidth(); 
 
        if ((GetGrandParent()->GetSyntax()->HasIndentationWord(GetLine(currentLine-2))) 
                && !GetLine(currentLine-2).Contains('{') 
                && !GetLine(currentLine-1).Contains('{') 
                && GetParent()->GetHil() != "Pascal") 
            lineInd -= GetTabWidth(); 
 
        SetLineIndentation(currentLine, lineInd); 
        GotoPos(PositionFromLine(currentLine) + lineInd); 
        return; 
    } 
 
    // Don't auto-indent comments. 
    if (GetParent()->GetHil() == "Pascal") return; 
 
    if (chr == '{' && !GetGrandParent()->GetSyntax()->HasIndentationWord(GetLine(currentLine)) 
            && !GetLine(GetCurrentLine()-1).Contains('{')) 
        SetLineIndentation(currentLine, GetLineIndentation(currentLine-1)); 
 
    if (chr == '}') 
    { 
        Colourise(GetCurrentPos()-1, GetCurrentPos()); 
        int pos = BraceMatch(GetCurrentPos()-1); 
        SetLineIndentation(currentLine, GetLineIndentation(LineFromPosition(pos))); 
    } 
} 
 
bool STextCtrl::FindCurrentWord(bool findNext = true) 
{ 
    wxString findText; 
 
    if (findNext) 
    { 
        if (HasSelection()) 
        { 
            findText = GetSelectedText(); 
            return FindNextOccurence(findText, 0); 
        } 
 
        else 
        { 
            findText = GetTextUnderCursor(); 
            return FindNextOccurence(findText, wxSTC_FIND_WHOLEWORD); 
        } 
    } 
 
    else if (!findNext) 
    { 
        if (HasSelection()) 
        { 
            findText = GetSelectedText(); 
            return FindPreviousOccurence(findText, 0); 
        } 
 
        else 
        { 
            findText = GetTextUnderCursor(); 
            return FindPreviousOccurence(findText, wxSTC_FIND_WHOLEWORD); 
        } 
    } 
 
    return false; 
} 
 
void STextCtrl::FindWord(wxCommandEvent &event) 
{ 
    FindCurrentWord(); 
} 
 
void STextCtrl::FindPreviousWord(wxCommandEvent &event) 
{ 
    FindCurrentWord(false); 
} 
 
bool STextCtrl::FindNext() 
{ 
    return FindNextOccurence(findString, findFlags); 
} 
 
bool STextCtrl::FindPrevious() 
{ 
    return FindPreviousOccurence(findString, findFlags); 
} 
// \todo Merge FindNextOccurence and FindPreviousOccurence into FindOccurence 
bool STextCtrl::FindNextOccurence(const wxString &findStr, int flags = 0) 
{ 
    findString = findStr; 
    findFlags = flags; 
 
    int targetStart = GetCurrentPos(); 
 
    if (GetSelectedText() == findStr) 
        targetStart = GetSelectionEnd(); 
 
    SetTargetStart(targetStart); 
    SetTargetEnd(GetLength()); 
    SetSearchFlags(flags); 
 
    if (SearchInTarget(findStr) != -1) 
    { 
        SetSelection(GetTargetStart(), GetTargetEnd()); 
        EnsureCaretVisible(); 
        return true; 
    } 
 
    else 
        return false; 
} 
 
bool STextCtrl::FindPreviousOccurence(const wxString &findStr, int flags = 0) 
{ 
    findString = findStr; 
    findFlags = flags; 
 
    int targetStart = GetCurrentPos(); 
 
    if (GetSelectedText() == findStr) 
        targetStart = (GetSelectionStart() GetParent(); 
} 
 
inline CPtr STextCtrl::GetParent() 
{ 
    return static_cast  (wxStyledTextCtrl::GetParent()); 
} 
 
void STextCtrl::GetSelection(int &from, int &to) 
{ 
    from = GetSelectionStart(); 
    to = GetSelectionEnd(); 
} 
 
wxString STextCtrl::GetTextUnderCursor() 
{ 
    int startpos, endpos; 
    startpos = WordStartPosition(GetCurrentPos(), true); 
    endpos = WordEndPosition(GetCurrentPos(), true); 
 
    return GetTextRange(startpos, endpos); 
} 
 
wxString STextCtrl::GetTextUnderCursor(int &startPos, int &endPos) 
{ 
    startPos = WordStartPosition(GetCurrentPos(), true); 
    endPos = WordEndPosition(GetCurrentPos(), true); 
 
    return GetTextRange(startPos, endPos); 
} 
 
inline bool STextCtrl::IsBrace(char brace) 
{ 
    return brace == '{' || brace == '}' || 
           brace == '[' || brace == ']' || 
           brace == '(' || brace == ')'; 
} 
 
inline void STextCtrl::InitDefaultStyles() 
{ 
    wxFont font (10, wxMODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, 
                 "Courier New", wxFONTENCODING_SYSTEM); 
 
    StyleSetFont(wxSTC_STYLE_DEFAULT, font); 
    StyleSetBold(wxSTC_STYLE_BRACELIGHT, true); 
    StyleSetBold(wxSTC_STYLE_BRACEBAD, true); 
    StyleSetForeground(wxSTC_STYLE_DEFAULT, wxColour(0, 0, 0)); 
    StyleSetForeground(wxSTC_STYLE_LINENUMBER, wxColour(0, 0, 0)); 
    StyleSetForeground(wxSTC_STYLE_BRACELIGHT, wxColour(0, 0, 255)); 
    StyleSetForeground(wxSTC_STYLE_BRACEBAD, wxColour(255, 0, 0)); 
    StyleSetForeground(wxSTC_STYLE_BRACEBAD, wxColour(255, 0, 0)); 
} 
 
inline void STextCtrl::InitMargins() 
{ 
    SetMarginWidth(0, TextWidth(wxSTC_STYLE_LINENUMBER, "9999999")); 
    SetMarginType(0, 1); 
 
    SetMarginType(1, wxSTC_MARGIN_SYMBOL); 
    SetMarginMask(1, ~wxSTC_MASK_FOLDERS); 
    SetMarginSensitive(1, true); 
    SetMarginWidth(1, 16); 
 
    SetMarginType(2, wxSTC_MARGIN_SYMBOL); 
    SetMarginMask(2, wxSTC_MASK_FOLDERS); 
    SetMarginSensitive(2, true); 
    SetMarginWidth(2, 16); 
 
    MarkerDefine(wxSTC_MARKNUM_FOLDER, wxSTC_MARK_BOXPLUS, "white", "black"); 
    MarkerDefine(wxSTC_MARKNUM_FOLDEREND, wxSTC_MARK_BOXPLUSCONNECTED, "white", "black"); 
    MarkerDefine(wxSTC_MARKNUM_FOLDERMIDTAIL,wxSTC_MARK_TCORNER, "white", "black"); 
    MarkerDefine(wxSTC_MARKNUM_FOLDEROPEN, wxSTC_MARK_BOXMINUS, "white", "black"); 
    MarkerDefine(wxSTC_MARKNUM_FOLDEROPENMID,wxSTC_MARK_BOXMINUSCONNECTED, "white", "black"); 
    MarkerDefine(wxSTC_MARKNUM_FOLDERSUB, wxSTC_MARK_VLINE, "white", "black"); 
    MarkerDefine(wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_LCORNER, "white", "black"); 
 
    MarkerDefine(0, wxSTC_MARK_CIRCLE, wxColour(0, 0, 0), wxColour(128, 255, 255)); 
} 
 
inline void STextCtrl::InitOptions() 
{ 
    AutoCompSetChooseSingle(true); 
    SetUseTabs(false); 
    SetTabWidth(4); 
 
    SetBackSpaceUnIndents(true); 
    SetModEventMask(wxSTC_MOD_INSERTTEXT | wxSTC_MOD_DELETETEXT 
                    | wxSTC_MOD_BEFOREINSERT | wxSTC_MOD_BEFOREDELETE); 
 
    SetProperty("fold", "1"); 
    SetProperty("fold.comment", "1"); 
    SetProperty("fold.comment.python", "1"); 
    SetProperty("fold.compact", "1"); 
    SetProperty("fold.html", "1"); 
    SetProperty("fold.html.preprocessor", "1"); 
    SetProperty("fold.preprocessor", "1"); 
    SetProperty("fold.quotes.python", "1"); 
    SetProperty("tab.timmy.whinge.level", "1"); 
} 
 
inline int STextCtrl::LinesSelected() 
{ 
    return LineFromPosition(GetSelectionEnd()) - LineFromPosition(GetSelectionStart()); 
} 
 
bool STextCtrl::LoadFile(const wxString& fileName) 
{ 
    wxFile file(fileName); 
    wxString st; 
 
    ClearAll(); 
    char* buff = st.GetWriteBuf(file.Length()); 
    file.Read(buff, file.Length()); 
    st.UngetWriteBuf(); 
 
    if (st.Contains('\n') && !st.Contains('\r')) // Unix text file 
        SetEOL(LF); 
 
    else if (st.Contains('\r') && !st.Contains('\n')) // Mac text file 
        SetEOL(CR); 
 
    else  // Windows text file 
        SetEOL(CRLF); 
 
    InsertText(0, st); 
    EmptyUndoBuffer(); 
 
    return true; 
} 
 
void STextCtrl::MacroRecord(wxStyledTextEvent &event) 
{ 
    mac.Add(event.GetMessage()); 
} 
 
void STextCtrl::MakeLower() 
{ 
    BeginUndoAction(); 
    int start, end; 
    GetSelection(start, end); 
 
    wxString sel = GetSelectedText(); 
    sel.MakeLower(); 
 
    ReplaceText(start, end, sel); 
    EndUndoAction(); 
} 
 
void STextCtrl::MakeUpper() 
{ 
    BeginUndoAction(); 
    int start, end; 
    GetSelection(start, end); 
 
    wxString sel = GetSelectedText(); 
    sel.MakeUpper(); 
 
    ReplaceText(start, end, sel); 
    EndUndoAction(); 
} 
 
void STextCtrl::MarginClicked(wxStyledTextEvent &event) 
{ 
    if (event.GetMargin() == 1) // The bookmark margin was clicked 
    { 
        int line = LineFromPosition(event.GetPosition()); 
        ToggleBookMark(line); 
    } 
 
    if (event.GetMargin() == 2) // The fold margin was clicked 
    { 
        int line = LineFromPosition(event.GetPosition()); 
        if (GetFoldLevel(line) & wxSTC_FOLDLEVELHEADERFLAG) 
            ToggleFold(line); 
    } 
} 
 
void STextCtrl::Modified(wxStyledTextEvent &event) 
{ 
    wxString title = GetParent()->GetTitle(); 
    int currentStatus = GetGrandParent()->GetWindowStatus()->GetStatus(); 
 
    if (!title.Contains('*') && currentStatus != OpeningWindows) 
        GetParent()->SetTitle(title + '*'); 
 
    GetGrandParent()->UpdateMenus();   // \todo Optimize this code. 
} 
 
void STextCtrl::PlayMacro(const wxArrayInt ¯o) 
{ 
    for (unsigned int i = 0; i < macro.GetCount(); i++) 
    { 
        if (macro[i] < 255) 
            AddText((char) macro[i]); 
         
        else 
            CmdKeyExecute(macro[i]); 
    } 
} 
 
void STextCtrl::PosChange(wxStyledTextEvent &event) 
{ 
    if (IsBrace(GetPreviousChar())) 
    { 
        braceLoc = BraceMatch(GetCurrentPos()-1); 
 
        if (braceLoc != -1) 
        { 
            BraceHighlight(GetCurrentPos()-1, braceLoc); 
            Colourise(braceLoc, braceLoc+1); 
        } 
 
        else 
        { 
            BraceBadLight(GetCurrentPos()-1); 
            braceLoc = GetCurrentPos()-1; 
        } 
    } 
 
    else if (IsBrace(GetCurrentChar())) 
    { 
        braceLoc = BraceMatch(GetCurrentPos()); 
 
        if (braceLoc != -1) 
        { 
            BraceHighlight(GetCurrentPos(), braceLoc); 
            Colourise(braceLoc, braceLoc+1); 
        } 
 
        else 
        { 
            BraceBadLight(GetCurrentPos()); 
            braceLoc = GetCurrentPos(); 
        } 
    } 
 
    else 
    { 
        if (braceLoc != -1)   // Position has moved and a brace was being highlighted 
        {                     // but the caret is no longer next to the brace 
            BraceHighlight(-1, -1); 
            if ((braceLoc+1) < GetLength()) Colourise(braceLoc, braceLoc+1); 
 
            if (BraceMatch(braceLoc) != -1 && BraceMatch(braceLoc)+1 < GetLength()) 
                Colourise(BraceMatch(braceLoc), BraceMatch(braceLoc)+1); 
 
            braceLoc = -1; 
        } 
    } 
 
    // \todo Remove this call to UpdateMenus and find a faster way to do the same thing 
    GetGrandParent()->UpdateMenus(); 
 
    GetParent()->UpdatePos(); 
} 
 
void STextCtrl::Remove(int from, int to) 
{ 
    SetTargetStart(from ? from); 
    ReplaceTarget(""); 
} 
 
void STextCtrl::RemoveAllBookMarks() 
{ 
    MarkerDeleteAll(0); 
} 
 
void STextCtrl::Replace(const wxString &findStr, const wxString &replaceStr, int flags) 
{ 
    replaceString = replaceStr; 
 
    if (!HasSelection()) 
    { 
        wxBell(); 
        return; 
    } 
 
    if (flags & wxSTC_FIND_MATCHCASE && GetSelectedText() != findStr) 
    { 
        wxBell(); 
        return; 
    } 
 
    else if (GetSelectedText().Lower() != findStr.Lower()) 
    { 
        wxBell(); 
        return; 
    } 
 
    ReplaceSelection(replaceStr); 
    FindNextOccurence(findStr, flags); 
} 
 
void STextCtrl::ReplaceAll(const wxString &findStr, const wxString &replaceStr, int flags) 
{ 
    replaceString = replaceStr; 
    int find; 
 
    BeginUndoAction(); 
    SetTargetStart(GetCurrentPos()-1); 
    SetTargetEnd(GetLength()); 
    SetSearchFlags(flags); 
 
    do 
    { 
        find = SearchInTarget(findStr); 
 
        if (find != -1) 
        { 
            ReplaceTarget(replaceStr); 
            SetTargetStart(GetTargetEnd()); 
            SetTargetEnd(GetLength()); 
        } 
    } 
    while (find != -1); 
    EndUndoAction(); 
} 
 
void STextCtrl::ReplaceText(int from, int to, const wxString& value) 
{ 
    Remove(from, to); 
    InsertText(from, value); 
} 
 
void STextCtrl::SetEOL(int eolMode) 
{ 
    if (GetEOLMode() != eolMode) 
    { 
        ConvertEOLs(eolMode); 
        SetEOLMode(eolMode); 
    } 
} 
 
bool STextCtrl::SaveFile(const wxString& fileName) 
{ 
    if (!GetModify()) return false; // Don't do anything if the file wasn't modified 
 
    wxFile file; 
    wxString st; 
 
    if (!file.Exists(fileName)) 
        file.Create(fileName); 
 
    file.Open(fileName, wxFile::write); 
 
    st = GetText(); 
    file.Write(st); 
    file.Close(); 
 
    SetSavePoint(); 
    return true; 
} 
 
void STextCtrl::ShowAutoComplete(wxCommandEvent &event) 
{ 
    wxSortedArrayString comp; 
    wxString complist, word; 
    wxString cword = GetTextUnderCursor(); 
    int loc, end; 
 
    SetTargetStart(0); 
    SetTargetEnd(GetLength()); 
    SetSearchFlags(wxSTC_FIND_WORDSTART + wxSTC_FIND_MATCHCASE); 
 
    for (;;) 
    { 
        loc = SearchInTarget(cword); 
 
        if (loc == -1) break; 
 
        end = WordEndPosition(loc, true); 
        word = GetTextRange(GetTargetStart(), end); 
 
        if (comp.Index(word) == wxNOT_FOUND && word != cword) 
            comp.Add(word); 
 
        SetTargetStart(end); 
        SetTargetEnd(GetLength()); 
    } 
 
    // Convert the wxSortedArrayString to a sorted string delimited by spaces 
    for (unsigned int i = 0; i < comp.GetCount(); i++) 
    { 
        complist += comp[i]; 
        if (i != comp.GetCount() - 1) complist += ' '; // Pad every word with spaces except the last 
    } 
 
    if (complist != "") 
        AutoCompShow(cword.length(), complist); 
} 
 
void STextCtrl::ShowMatchingBrace(int pos) 
{ 
    if (IsBrace(GetPreviousChar())) 
        GotoPos(BraceMatch(pos-1)); 
 
    else if (IsBrace(GetCurrentChar())) 
        GotoPos(BraceMatch(pos)+1); 
 
    else 
        wxBell(); 
} 
 
void STextCtrl::ShowNextBookMark(int line) 
{ 
    if (MarkerGet(line) & (1 << 0)) line++; 
    int nextMarker = MarkerNext(line, 1 << 0); 
 
    if (nextMarker == -1 && (MarkerNext(0, 1 << 0) != -1)) 
        nextMarker = MarkerNext(0, 1 << 0); 
 
    if (nextMarker != -1) GotoLine(nextMarker); 
} 
 
void STextCtrl::ShowPreviousBookMark(int line) 
{ 
    if (MarkerGet(line) & (1 << 0)) line--; 
    int previousMarker = MarkerPrevious(line, 1 << 0); 
 
    if (previousMarker == -1 && (MarkerPrevious(GetLastLine(), 1 << 0) != -1)) 
        previousMarker = MarkerPrevious(GetLastLine(), 1 << 0); 
 
    if (previousMarker != -1) GotoLine(previousMarker); 
} 
 
void STextCtrl::SortSelection() 
{ 
    if (HasSelection()) 
    { 
        BeginUndoAction(); 
        wxArrayString lines; 
 
        int firstLine = LineFromPosition(GetSelectionStart()); 
        int lastLine = LineFromPosition(GetSelectionEnd()); 
 
        for (int i = firstLine; i <= lastLine; i++) 
            lines.Add(GetTextRange(PositionFromLine(i), GetLineEndPosition(i))); 
 
        lines.Sort(); 
 
        for (int i = firstLine; i <= lastLine; i++) 
        { 
            SetTargetStart(PositionFromLine(i)); 
            SetTargetEnd(PositionFromLine(i)+LineLength(i));  // This code is very slow. \todo Optimize this. 
 
            // If this is the last line don't add an extra newline character 
            if (i == lastLine && lastLine == GetLineCount()-1) ReplaceTarget(lines[i-firstLine]); 
            else ReplaceTarget(lines[i-firstLine]+'\n'); 
        } 
 
        SetSelection(GetSelectionStart(), GetLineEndPosition(lastLine)); 
        EndUndoAction(); 
    } 
} 
 
void STextCtrl::StreamCommentSelection(const wxString &streamStart, const wxString &streamEnd) 
{ 
    int selStart, selEnd; 
    GetSelection(selStart, selEnd); 
 
    BeginUndoAction(); 
    InsertText(selStart, streamStart); 
    // Allocate space for the first comment 
    InsertText(selEnd + streamStart.length(), streamEnd); 
    EndUndoAction(); 
} 
 
void STextCtrl::ToggleBookMark(int line) 
{ 
    if (MarkerGet(line) & (1 << 0)) 
        MarkerDelete(line, 0); 
    else 
        MarkerAdd(line, 0); 
} 
 
void STextCtrl::ToggleMacroRecord() 
{ 
    if (!recording) 
    { 
        mac.Empty(); 
        StartRecord(); 
        recording = true; 
    } 
     
    else 
    { 
        StopRecord(); 
        recording = false; 
         
        #ifdef __WXDEBUG__ 
        wxTextFile f("C:\\Macro.mac"); 
        if (!f.Exists()) f.Create(); 
        f.Open(); 
         
        wxString command; 
         
        f.AddLine("--Start Macro--"); 
        for (unsigned int i = 0; i < mac.GetCount(); i++) 
        { 
            if (mac[i] == 2170) continue; // Don't need char added notifications 
            command = ""; 
            command << mac[i]; 
            f.AddLine(command); 
        } 
        f.AddLine("--End Macro--"); 
        f.Write(); 
        f.Close(); 
        #endif             
    } 
} 
 
BEGIN_EVENT_TABLE(STextCtrl, wxStyledTextCtrl) 
    EVT_MENU(Txt_AutoComplete, STextCtrl::ShowAutoComplete) 
    EVT_MENU(Txt_FindWord, STextCtrl::FindWord) 
    EVT_MENU(Txt_FindPreviousWord, STextCtrl::FindPreviousWord) 
    EVT_STC_CHANGE(-1, STextCtrl::Modified) 
    EVT_STC_CHARADDED(-1, STextCtrl::CharAdded) 
    EVT_STC_MACRORECORD(-1, STextCtrl::MacroRecord)  
    EVT_STC_MARGINCLICK (-1, STextCtrl::MarginClicked) 
    EVT_STC_UPDATEUI(-1, STextCtrl::PosChange) 
END_EVENT_TABLE()