#include "xmlctrl.h" #include "xmlpromptgenerator.h" #include "xmlshallowvalidator.h" #include "xmlencodinghandler.h" #include // adapted from wxSTEdit (c) 2005 John Labenski, Otto Wyss #define XMLCTRL_HASBIT(value, bit) (((value) & (bit)) != 0) BEGIN_EVENT_TABLE(XmlCtrl, wxStyledTextCtrl) EVT_CHAR(XmlCtrl::OnChar) EVT_KEY_DOWN(XmlCtrl::OnKeyPressed) EVT_IDLE(XmlCtrl::OnIdle) EVT_STC_MARGINCLICK(wxID_ANY, XmlCtrl::OnMarginClick) EVT_LEFT_DOWN(XmlCtrl::OnMouseLeftDown) EVT_LEFT_UP(XmlCtrl::OnMouseLeftUp) EVT_RIGHT_UP(XmlCtrl::OnMouseRightUp) EVT_MIDDLE_DOWN(XmlCtrl::OnMiddleDown) END_EVENT_TABLE() XmlCtrl::XmlCtrl( wxWindow *parent, XmlCtrlProperties propertiesParameter, bool *protectTagsParameter, int visibilityStateParameter, int typeParameter, wxWindowID id, const char *buffer, // could be NULL size_t bufferLen, const std::string& catalogPathParameter, const std::string& basePathParameter, const std::string& auxPathParameter, const wxPoint& position, const wxSize& size, long style) : wxStyledTextCtrl(parent, id, position, size, style), type(typeParameter), protectTags(protectTagsParameter), visibilityState(visibilityStateParameter), catalogPath(catalogPathParameter), basePath(basePathParameter), auxPath(auxPathParameter) { SetEOLMode(wxSTC_EOL_LF); SetPasteConvertEndings(true); // essential to avoid double-spaced paste currentMaxLine = 1; validationRequired = dtdFound = false; applyProperties(propertiesParameter); SetTabWidth(2); SetWrapStartIndent(2); SetWrapVisualFlags(wxSTC_WRAPVISUALFLAG_START); SetUseTabs(false); SetBackSpaceUnIndents(true); SetTabIndents(false); SetUndoCollection(false); // handle NULL buffer if (!buffer) { buffer = DEFAULT_XML_DECLARATION_UTF8; bufferLen = strlen(DEFAULT_XML_DECLARATION_UTF8); } SendMsg(2001, bufferLen, (long)(const char *)buffer); SetSelection(0, 0); // position cursor if (type == FILE_TYPE_XML && bufferLen > 5 && buffer[0] == '<' && buffer[1] == '?' && buffer[2] == 'x' && buffer[3] == 'm' && buffer[4] == 'l' && GetLineCount() > 1) { GotoLine(1); // == line 2 of the document } SetSavePoint(); SetUndoCollection(true); AutoCompSetSeparator('<'); applyVisibilityState(visibilityState); lineBackgroundState = BACKGROUND_STATE_NORMAL; for (int i = 0; i < wxSTC_INDIC_MAX; ++i) // start from 1 to disable faulty default indication IndicatorSetStyle(i, wxSTC_INDIC_HIDDEN); IndicatorSetStyle(2, wxSTC_INDIC_SQUIGGLE); IndicatorSetForeground(0, *wxRED); } // taken from wxStyledNotebook (c) Eran Ifrah static wxColor LightColour(const wxColour& color, int percent) { int rd, gd, bd, high = 0; wxColor end_color = wxT("WHITE"); rd = end_color.Red() - color.Red(); gd = end_color.Green() - color.Green(); bd = end_color.Blue() - color.Blue(); high = 100; // We take the percent way of the color from color --> white int i = percent; int r = color.Red() + ((i*rd*100)/high)/100; int g = color.Green() + ((i*gd*100)/high)/100; int b = color.Blue() + ((i*bd*100)/high)/100; return wxColor(r, g, b); } void XmlCtrl::OnIdle(wxIdleEvent& event) { if (properties.number && type != FILE_TYPE_BINARY) adjustNoColumnWidth(); } void XmlCtrl::OnChar(wxKeyEvent& event) { if (*protectTags) { SetOvertype(false); if (GetSelectionStart() != GetSelectionEnd()) adjustSelection(); if (!canInsertAt(GetCurrentPos())) adjustPosRight(); } if ((!properties.completion || GetOvertype()) && !*protectTags) { event.Skip(); return; } switch (event.GetKeyCode()) { case '<': handleOpenAngleBracket(event); return; case '>': handleCloseAngleBracket(event); return; case ' ': handleSpace(event); return; case '=': handleEquals(event); return; case '&': handleAmpersand(event); return; case '/': handleForwardSlash(event); return; default: break; } event.Skip(); } void XmlCtrl::handleBackspace(wxKeyEvent& event) { protectHeadLine(); validationRequired = true; if (canMoveLeftAt(GetCurrentPos())) { event.Skip(); return; } int currentPos, limitPos; currentPos = GetCurrentPos(); if (currentPos < 1) return; limitPos = currentPos - 1; // tag int limitStyle = getLexerStyleAt(limitPos); //limitStyle &= ~wxSTC_INDIC2_MASK; if (GetCharAt(limitPos) == '>' && (limitStyle == wxSTC_H_TAG || limitStyle == wxSTC_H_TAGUNKNOWN || limitStyle == wxSTC_H_TAGEND || limitStyle == wxSTC_H_XMLSTART || limitStyle == wxSTC_H_XMLEND)) { if (GetSelectionStart() != GetSelectionEnd()) { if (*protectTags) adjustSelection(); else event.Skip(); return; } if (!properties.deleteWholeTag) { if (!(*protectTags)) event.Skip(); return; } // delete tag to left of caret for (; limitPos && GetCharAt(limitPos) != '<'; limitPos--) ; SetSelection(currentPos, limitPos);//(limitPos, currentPos); if (*protectTags) { SetReadOnly(true); // needed to prevent erroneous BS insertion by control int ret = wxMessageBox(_("Delete tag?"), _("Tags Locked"), wxOK | wxCANCEL | wxICON_QUESTION); SetReadOnly(false); if (ret != wxOK) { return; } // ensure selection is set correctly if (GetSelectionStart() != currentPos || GetSelectionEnd() != limitPos) SetSelection(currentPos, limitPos); } DeleteBack(); return; } // entity reference else if (GetCharAt(limitPos) == ';' && getLexerStyleAt(limitPos) == wxSTC_H_ENTITY) { // delete entity to left of caret for (; limitPos && getLexerStyleAt(limitPos) == wxSTC_H_ENTITY && GetCharAt(limitPos) != '&'; limitPos--) ; SetSelection(limitPos, currentPos); if (*protectTags) { SetReadOnly(true); // needed to prevent erroneous BS insertion by control int ret = wxMessageBox(_("Delete entity reference?"), _("Tags Locked"), wxOK | wxCANCEL | wxICON_QUESTION); SetReadOnly(false); if (ret != wxOK) return; // ensure selection is set correctly if (GetSelectionStart() != currentPos || GetSelectionEnd() != limitPos) SetSelection(currentPos, limitPos); } DeleteBack(); return; } else if (*protectTags) { return; } event.Skip(); } void XmlCtrl::handleDelete(wxKeyEvent& event) { protectHeadLine(); validationRequired = true; // unindent range int start, end, startLine, endLine; start = GetSelectionStart(); end = GetSelectionEnd(); startLine = LineFromPosition(start); endLine = LineFromPosition(end); if (startLine != endLine) { if (startLine > endLine) { int temp; temp = startLine; startLine = endLine; endLine = temp; temp = start; start = end; end = temp; } if (GetColumn(start) < GetLineIndentation(startLine) && GetColumn(end) < GetLineIndentation(endLine)) { for (int i = startLine; i <= endLine; i++) { int current = GetLineIndentation(i); if (current > 0) SetLineIndentation(i, current - 1); } return; } } if (!canMoveRightAt(GetCurrentPos()) && GetSelectionStart() == GetSelectionEnd()) { int currentPos, limitPos; limitPos = currentPos = GetCurrentPos(); // tag int limitStyle = getLexerStyleAt(limitPos); if (GetCharAt(limitPos) == '<' && (limitStyle == wxSTC_H_TAG || limitStyle == wxSTC_H_TAGUNKNOWN || limitStyle == wxSTC_H_TAGEND || limitStyle == wxSTC_H_XMLSTART || limitStyle == wxSTC_H_XMLEND )) { if (GetSelectionStart() != GetSelectionEnd()) { if (*protectTags) adjustSelection(); else event.Skip(); return; } if (!properties.deleteWholeTag) { if (!(*protectTags)) event.Skip(); return; } for (; GetCharAt(limitPos) != '>' && limitPos < GetLength(); limitPos++) { if (limitPos > (currentPos + BUFSIZ)) { event.Skip(); return; } } if (currentPos != limitPos) { SetSelection(currentPos, limitPos + 1); if (*protectTags) { int ret = wxMessageBox(_("Delete tag?"), _("Tags Locked"), wxOK | wxCANCEL | wxICON_QUESTION); if (ret != wxOK) return; } DeleteBack(); return; } } // entity else if (GetCharAt(limitPos) == '&' && getLexerStyleAt(limitPos) == wxSTC_H_ENTITY) { for (; getLexerStyleAt(limitPos) == wxSTC_H_ENTITY && limitPos <= GetLength(); limitPos++) { if (GetCharAt(limitPos) == ';') break; else if (GetCharAt(limitPos) == '\n' || limitPos > (currentPos + BUFSIZ)) { event.Skip(); return; } } if (currentPos != limitPos) { SetSelection(currentPos, limitPos + 1); if (*protectTags) { int ret = wxMessageBox(_("Delete entity reference?"), _("Tags Locked"), wxOK | wxCANCEL | wxICON_QUESTION); if (ret != wxOK) return; } DeleteBack(); return; } } else if (*protectTags) return; } event.Skip(); } void XmlCtrl::handleOpenAngleBracket(wxKeyEvent& event) { if (AutoCompActive()) AutoCompCancel(); if (*protectTags) { AddText(_T("<")); return; } validationRequired = true; AddText(_T("<")); int pos = GetCurrentPos(); // exit conditions based on style int style = getLexerStyleAt(pos); //style &= ~wxSTC_INDIC2_MASK; switch (style) { case wxSTC_H_DOUBLESTRING: case wxSTC_H_SINGLESTRING: return; default: break; } // determine parent element int parentCloseAngleBracket; parentCloseAngleBracket = getParentCloseAngleBracket(pos); if (parentCloseAngleBracket < 0) return; wxString wideParent = getLastElementName(parentCloseAngleBracket); if (wideParent.empty()) return; std::string parent = (const char *)wideParent.mb_str(wxConvUTF8); if (elementMap.find(parent) == elementMap.end()) return; wxString choice, conversion; std::set childSet = elementMap[parent]; std::set::iterator it; for (it = childSet.begin(); it != childSet.end(); it++) { if (!choice.empty()) choice.append(_T("<")); conversion = wxString(it->c_str(), wxConvUTF8, it->size()); choice.append(conversion); } if (!choice.empty()) UserListShow(0, choice); } void XmlCtrl::handleCloseAngleBracket(wxKeyEvent& event) { if (AutoCompActive()) AutoCompCancel(); if (*protectTags) { AddText(_T(">")); return; } validationRequired = true; wxString insertBuffer; int pos; pos = GetCurrentPos(); wxString elementName = getLastElementName(pos); if (!elementName.empty()) { std::map > map; std::string elementNameUtf8 = (const char *)elementName.mb_str(wxConvUTF8); attributeMap.insert(make_pair(elementNameUtf8, map)); } // exit condition 1 if (pos <= 1) { event.Skip(); return; } // exit condition 2 (empty tag/end of CDATA section) else if (GetCharAt(pos - 1) == '/' || GetCharAt(pos - 1) == ']') { event.Skip(); return; } // exit condition 3 (comment/CDATA) else if (getLexerStyleAt(pos - 1) == wxSTC_H_COMMENT || getLexerStyleAt(pos - 1) == wxSTC_H_CDATA || (getLexerStyleAt(pos - 1) == wxSTC_H_DOUBLESTRING && (GetCharAt(pos - 1) != '"')) || (getLexerStyleAt(pos - 1) == wxSTC_H_SINGLESTRING && (GetCharAt(pos - 1) != '\''))) { event.Skip(); return; } if (!elementName.empty()) { if (!properties.insertCloseTag) { event.Skip(); return; } AddText(_T(">")); insertBuffer += _T(""); InsertText(pos + 1, insertBuffer); SetSelection(pos + 1, pos + 1); } else event.Skip(); } void XmlCtrl::handleEquals(wxKeyEvent& event) { if (AutoCompActive()) AutoCompCancel(); wxString choice, elementName, attributeName, conversion; std::string elementNameUtf8, attributeNameUtf8; int pos = GetCurrentPos(); if (pos <= 0 || getLexerStyleAt(pos - 1) != wxSTC_H_ATTRIBUTE) { event.Skip(); return; } AddText(_T("=\"\"")); SetSelection(pos + 2, pos + 2); // tbd: identify possible attribute values elementName = getLastElementName(pos); attributeName = getLastAttributeName(pos); elementNameUtf8 = elementName.mb_str(wxConvUTF8); attributeNameUtf8 = attributeName.mb_str(wxConvUTF8); std::set valueSet; valueSet = attributeMap[elementNameUtf8][attributeNameUtf8]; if (valueSet.empty()) return; std::set::iterator valueSetIterator; int cutoff = BUFSIZ; for (valueSetIterator = valueSet.begin(); valueSetIterator != valueSet.end(); valueSetIterator++) { if (!(cutoff--)) break; if (!choice.empty()) choice.Append(_T("<")); conversion = wxString( valueSetIterator->c_str(), wxConvUTF8, valueSetIterator->size()); choice.Append(conversion); } if (!choice.empty()) UserListShow(0, choice); } void XmlCtrl::handleSpace(wxKeyEvent& event) { if (AutoCompActive()) AutoCompCancel(); wxString elementName, choice, conversion; std::string elementNameUtf8; int pos = GetCurrentPos(); std::map > currentAttributeMap; std::map >::iterator attributeIterator; if (pos <= 2) { event.Skip(); return; } int style = getLexerStyleAt(pos - 1); //style &= ~wxSTC_INDIC2_MASK; char c = GetCharAt(pos - 1); bool proceed = false; // space pressed after element name if ( style == wxSTC_H_TAG || style == wxSTC_H_TAGUNKNOWN || style == wxSTC_H_ATTRIBUTEUNKNOWN || style == wxSTC_H_ATTRIBUTE) { proceed = true; } // space pressed after attribute value else if ( (style == wxSTC_H_DOUBLESTRING || style == wxSTC_H_SINGLESTRING) && (c == '\'' || c == '"') && GetCharAt(pos - 2) != '=') { proceed = true; } int tagStartPos = getTagStartPos(pos); if (!proceed || tagStartPos == -1) { event.Skip(); return; } AddText(_T(" ")); elementName = getLastElementName(pos); wxString tag = GetTextRange(tagStartPos, pos); elementNameUtf8 = elementName.mb_str(wxConvUTF8); if (attributeMap.find(elementNameUtf8) == attributeMap.end()) return; currentAttributeMap = attributeMap[elementNameUtf8]; for ( attributeIterator = currentAttributeMap.begin(); attributeIterator != currentAttributeMap.end(); attributeIterator++) { conversion = wxString( attributeIterator->first.c_str(), wxConvUTF8, attributeIterator->first.size()); // avoid duplicate attributes if (tag.Contains(conversion + _T("="))) continue; if (!choice.empty()) choice.Append(_T("<")); choice.Append(conversion); } if (!choice.empty()) UserListShow(0, choice); } void XmlCtrl::handleAmpersand(wxKeyEvent& event) { if (AutoCompActive()) AutoCompCancel(); validationRequired = true; if (*protectTags) { AddText(_T("&")); return; } int pos, style; pos = GetCurrentPos(); style = getLexerStyleAt(pos); if (style != wxSTC_H_COMMENT && style != wxSTC_H_CDATA && style != wxSTC_H_TAGUNKNOWN && entitySet.size() >= 4) // min. 4 default entities { AddText(_T("&")); wxString choice; std::set::iterator it; it = entitySet.begin(); choice += wxString(it->c_str(), wxConvUTF8, it->size()); choice += _T(";"); for (it++; it != entitySet.end(); it++) { choice += _T("<"); choice += wxString(it->c_str(), wxConvUTF8, it->size()); choice += _T(";"); } UserListShow(0, choice); } else event.Skip(); } void XmlCtrl::handleForwardSlash(wxKeyEvent& event) { if (AutoCompActive()) AutoCompCancel(); int pos = GetCurrentPos(); if ( (pos <= 0) || GetCharAt(pos - 1) != '<' || getLexerStyleAt(pos) == wxSTC_H_COMMENT || getLexerStyleAt(pos) == wxSTC_H_CDATA) { event.Skip(); return; } AddText(_T("/")); int parentCloseAngleBracket = getParentCloseAngleBracket(pos); if (parentCloseAngleBracket < 0) return; wxString wideParent = getLastElementName(parentCloseAngleBracket); if (wideParent.empty()) return; AddText(wideParent + _T(">")); } void XmlCtrl::OnKeyPressed(wxKeyEvent& event) { if (*protectTags && GetSelectionStart() != GetSelectionEnd()) { adjustSelection(); } if (*protectTags) SetOvertype(false); //bool autoindent; int pos, iteratorPos, maxPos; // omitted startPos, line, newPos char c; wxString s; switch (event.GetKeyCode()) { case WXK_RETURN: if (AutoCompActive()) { AutoCompComplete(); return; } if (*protectTags) adjustPosRight(); insertNewLine(); return; case WXK_RIGHT: pos = GetCurrentPos(); if (*protectTags && !canMoveRightAt(pos)) { SetSelection(pos + 1, pos + 1); adjustPosRight(); return; } maxPos = GetLength(); c = GetCharAt(pos); if (c == '<' && event.ControlDown() && !event.ShiftDown()) { for ( iteratorPos = pos; iteratorPos < maxPos && GetCharAt(iteratorPos) != ' ' && GetCharAt(iteratorPos) != '>' && GetCharAt(iteratorPos) != '\n'; ++iteratorPos) ; ++iteratorPos; SetSelection(iteratorPos, iteratorPos); return; } else break; case WXK_LEFT: pos = GetCurrentPos(); if (*protectTags && !canMoveLeftAt(pos)) { adjustPosLeft(); return; } if (pos < 3) break; c = GetCharAt(pos - 1); if (c == '>' && event.ControlDown() && !event.ShiftDown()) { for ( iteratorPos = pos - 1; iteratorPos > 0 && GetCharAt(iteratorPos) != '<' && GetCharAt(iteratorPos) != ' ' && GetCharAt(iteratorPos) != '=' && GetCharAt(iteratorPos) != '\n'; --iteratorPos) ; if ( GetCharAt(iteratorPos) != '<' && GetCharAt(iteratorPos) != '=') ++iteratorPos; SetSelection(iteratorPos, iteratorPos); return; } else break; case WXK_UP: if (*protectTags) { LineUp(); if (!canInsertAt(GetCurrentPos())) adjustPosLeft(); return; } break; case WXK_DOWN: if (*protectTags) { LineDown(); if (!canInsertAt(GetCurrentPos())) adjustPosRight(); return; } break; case WXK_INSERT: if (*protectTags) return; break; case WXK_BACK: handleBackspace(event); return; case WXK_TAB: if (*protectTags) { if (!canInsertAt(GetCurrentPos())) adjustPosRight(); } break; case WXK_HOME: if (*protectTags && !event.ControlDown() && !event.ShiftDown()) { Home(); if (!canInsertAt(GetCurrentPos())) adjustPosLeft(); return; } break; case WXK_END: if (*protectTags && !event.ControlDown() && !event.ShiftDown()) { LineEnd(); if (!canInsertAt(GetCurrentPos())) adjustPosRight(); return; } break; case WXK_PAGEUP: if (*protectTags) { PageUp(); if (!canInsertAt(GetCurrentPos())) adjustPosLeft(); return; } break; case WXK_PAGEDOWN: if (*protectTags) { PageDown(); if (!canInsertAt(GetCurrentPos())) adjustPosRight(); return; } break; case WXK_DELETE: handleDelete(event); return; default: break; } event.Skip(); } wxString XmlCtrl::getLastElementName(int pos) { if (pos < 1) return _T(""); int startPos, iteratorPos; for (startPos = pos - 1; startPos >= 0; --startPos) { char c = GetCharAt(startPos); if (c == '>') return _T(""); else if (c == '<') break; } // exit if not found or closing/declaration/command tag if (GetCharAt(startPos) != '<' || GetCharAt(startPos + 1) == '/' || GetCharAt(startPos + 1) == '?' || GetCharAt(startPos + 1) == '!') return _T(""); ++startPos; for (iteratorPos = startPos; iteratorPos < pos && GetCharAt(iteratorPos) != ' ' && GetCharAt(iteratorPos) != '\n' && GetCharAt(iteratorPos) != '\t' && GetCharAt(iteratorPos) != '/' && GetCharAt(iteratorPos) != '>'; ++iteratorPos) ; if (startPos == iteratorPos) return _T(""); return GetTextRange(startPos, iteratorPos); } std::set XmlCtrl::getChildren(const wxString& parent) { std::string parentUtf8 = (const char *)parent.mb_str(wxConvUTF8); std::set mySet; if (elementMap.find(parentUtf8) == elementMap.end()) return mySet; std::set myUtf8Set = elementMap[parentUtf8]; std::string currentUtf8; wxString currentWide; std::set::iterator it; for (it = myUtf8Set.begin(); it != myUtf8Set.end(); it++) { currentUtf8 = *it; currentWide = wxString(currentUtf8.c_str(), wxConvUTF8, currentUtf8.size()); mySet.insert(currentWide); } return mySet; } wxString XmlCtrl::getLastAttributeName(int pos) { if (pos < 1) return _T(""); int startPos; for (startPos = pos - 1; startPos >= 0; --startPos) { char c = GetCharAt(startPos); if (c == ' ' || c == '<') break; } if (GetCharAt(startPos) != ' ' || startPos >= pos - 1) return _T(""); return GetTextRange(startPos + 1, pos); } int XmlCtrl::getParentCloseAngleBracket(int pos, int range) { int cutoff, iteratorPos, depth; cutoff = ((pos - range) > 2) ? pos - range : 2; depth = 1; for ( iteratorPos = pos; iteratorPos > cutoff; --iteratorPos) { int type, style; style = getLexerStyleAt(iteratorPos); //style &= ~wxSTC_INDIC2_MASK; if (GetCharAt(iteratorPos) == '>' && (style == wxSTC_H_TAG || style == wxSTC_H_TAGUNKNOWN)) { type = getTagType(iteratorPos); switch (type) { case (TAG_TYPE_CLOSE): ++depth; break; case (TAG_TYPE_OPEN): --depth; break; case (TAG_TYPE_EMPTY): case (TAG_TYPE_OTHER): case (TAG_TYPE_ERROR): break; } //(isCloseTag(iteratorPos)) ? ++depth : --depth; if (!depth) return iteratorPos; } } return -1; } void XmlCtrl::adjustNoColumnWidth() { int maxLine = GetLineCount(); if (maxLine == currentMaxLine) return; int digits, charWidth, width; digits = 0; do { ++digits; maxLine /= 10; } while (maxLine); digits = (digits > 2) ? digits : 2; charWidth = TextWidth(wxSTC_STYLE_LINENUMBER, _T("9")); width = (digits + 2) * charWidth; SetMarginWidth(0, width); currentMaxLine = maxLine; } void XmlCtrl::updatePromptMaps() { wxString buffer = GetText(); std::string bufferUtf8; bufferUtf8 = (const char *)buffer.mb_str(wxConvUTF8); XmlEncodingHandler::setUtf8(bufferUtf8, true); updatePromptMaps(bufferUtf8.c_str(), bufferUtf8.size()); } void XmlCtrl::updatePromptMaps(const char *buffer, size_t bufferLen) { attributeMap.clear(); elementMap.clear(); std::auto_ptr xpg(new XmlPromptGenerator( catalogPath, basePath, auxPath)); xpg->parse(buffer, bufferLen); xpg->getAttributeMap(attributeMap); xpg->getRequiredAttributeMap(requiredAttributeMap); xpg->getElementMap(elementMap); xpg->getEntitySet(entitySet); dtdFound = xpg->getDtdFound(); entitySet.insert("apos"); entitySet.insert("quot"); entitySet.insert("lt"); entitySet.insert("gt"); } void XmlCtrl::applyProperties( XmlCtrlProperties propertiesParameter, bool zoomOnly) { properties = propertiesParameter; SetZoom((type != FILE_TYPE_BINARY) ? properties.zoom : 0); if (zoomOnly) return; SetCaretLineVisible(properties.currentLine); SetIndentationGuides( (type != FILE_TYPE_BINARY) ? properties.indentLines : false); SetWrapMode((type != FILE_TYPE_BINARY) ? properties.wrap : false); SetViewWhiteSpace( (properties.whitespaceVisible) ? wxSTC_WS_VISIBLEAFTERINDENT : wxSTC_WS_INVISIBLE); switch (type) { case FILE_TYPE_BINARY: SetLexer(wxSTC_LEX_NULL); break; case FILE_TYPE_CSS: SetLexer(wxSTC_LEX_CSS); break; default: SetLexer(wxSTC_LEX_XML); break; } setColorScheme( (type != FILE_TYPE_BINARY) ? properties.colorScheme : COLOR_SCHEME_NONE); // line no margin if (properties.number) // permit line nos for large files { SetMarginType(0, wxSTC_MARGIN_NUMBER); // width set at idle time adjustNoColumnWidth(); } else SetMarginWidth(0, 0); SetMarginWidth(1, 0); if (properties.fold && type != FILE_TYPE_BINARY) { // folding margin SetMarginType(2, wxSTC_MARGIN_SYMBOL); SetMarginMask(2, wxSTC_MASK_FOLDERS); SetMarginSensitive(2, true); SetMarginWidth(2, 16); // define folding markers MarkerDefine(wxSTC_MARKNUM_FOLDEREND, wxSTC_MARK_BOXPLUSCONNECTED, *wxWHITE, *wxBLACK); MarkerDefine(wxSTC_MARKNUM_FOLDEROPENMID, wxSTC_MARK_BOXMINUSCONNECTED, *wxWHITE, *wxBLACK); MarkerDefine(wxSTC_MARKNUM_FOLDERMIDTAIL, wxSTC_MARK_TCORNER, *wxWHITE, *wxBLACK); MarkerDefine(wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_LCORNER, *wxWHITE, *wxBLACK); MarkerDefine(wxSTC_MARKNUM_FOLDERSUB, wxSTC_MARK_VLINE, *wxWHITE, *wxBLACK); MarkerDefine(wxSTC_MARKNUM_FOLDER, wxSTC_MARK_BOXPLUS, *wxWHITE, *wxBLACK); MarkerDefine(wxSTC_MARKNUM_FOLDEROPEN, wxSTC_MARK_BOXMINUS, *wxWHITE, *wxBLACK); } else { SetMarginWidth(2, 0); } if (type != FILE_TYPE_BINARY) { Colourise(0, -1); } wxString value = (properties.fold && type != FILE_TYPE_BINARY) ? _T("1") : _T("0"); SetProperty(_T("fold"), value); SetProperty(_T("fold.compact"), value); SetProperty(_T("fold.html"), value); } void XmlCtrl::OnMarginClick(wxStyledTextEvent& event) { const int line = LineFromPosition(event.GetPosition()); const int margin = event.GetMargin(); // let others process this first if (GetParent()->GetEventHandler()->ProcessEvent(event)) return; if (margin == 2) { const int level = GetFoldLevel(line); if (((level) & (wxSTC_FOLDLEVELHEADERFLAG)) != 0) ToggleFold(line); } else event.Skip(); } void XmlCtrl::OnMouseLeftDown(wxMouseEvent& event) { SetMouseDownCaptures(!*protectTags); event.Skip(); } void XmlCtrl::OnMouseLeftUp(wxMouseEvent& event) { event.Skip(); if (*protectTags && !canInsertAt(GetCurrentPos())) adjustPosRight(); } void XmlCtrl::OnMouseRightUp(wxMouseEvent& event) { if (*protectTags) return; event.Skip(); } bool XmlCtrl::isCloseTag(int pos) { int iteratorPos; for (iteratorPos = pos; iteratorPos >= 0; --iteratorPos) { if (GetCharAt(iteratorPos) == '<' && getLexerStyleAt(iteratorPos) == wxSTC_H_TAG) return (GetCharAt(iteratorPos + 1) == '/') ? true : false; } return false; } int XmlCtrl::getTagStartPos(int pos) { int iteratorPos; for (iteratorPos = pos; iteratorPos >= 0; --iteratorPos) { if (GetCharAt(iteratorPos) == '<' && getLexerStyleAt(iteratorPos) == wxSTC_H_TAG) return iteratorPos; } return -1; } int XmlCtrl::getAttributeStartPos(int pos) { int iteratorPos; char c; bool attributeSeen = false; for (iteratorPos = pos; iteratorPos > 0; iteratorPos--) { c = GetCharAt(iteratorPos); if ((getLexerStyleAt(iteratorPos)) == wxSTC_H_ATTRIBUTE) attributeSeen = true; else if ((c == ' ' || c == '\t' || c == '\n') && attributeSeen) return iteratorPos; } return -1; } int XmlCtrl::getAttributeSectionEndPos(int pos, int range) { int iteratorPos, limit, style; limit = pos + range; for (iteratorPos = pos; iteratorPos < limit; iteratorPos++) { style = getLexerStyleAt(iteratorPos); switch (style) { case wxSTC_H_TAG: case wxSTC_H_TAGEND: case wxSTC_H_XMLEND: case wxSTC_H_QUESTION: return iteratorPos; default: continue; } } return -1; } void XmlCtrl::adjustCursor() { if (!canInsertAt(GetCurrentPos())) adjustPosRight(); } bool XmlCtrl::canInsertAt(int pos) { if (pos < 0) return false; int style = getLexerStyleAt(pos); //style &= ~wxSTC_INDIC2_MASK; switch (style) { case wxSTC_H_TAG: case wxSTC_H_TAGUNKNOWN: case wxSTC_H_QUESTION: case wxSTC_H_CDATA: case wxSTC_H_COMMENT: case wxSTC_H_SGML_DEFAULT: return (GetCharAt(pos) == '<') ? true : false; case wxSTC_H_ENTITY: return (GetCharAt(pos) == '&') ? true : false; case wxSTC_H_DEFAULT: return true; } return false; } bool XmlCtrl::canMoveRightAt(int pos) { int style = getLexerStyleAt(pos); //style &= ~wxSTC_INDIC2_MASK; switch (style) { case wxSTC_H_DEFAULT: return true; } return false; } bool XmlCtrl::canMoveLeftAt(int pos) { if (pos < 1) return false; int style = getLexerStyleAt(pos - 1); //style &= ~wxSTC_INDIC2_MASK; switch (style) { case wxSTC_H_DEFAULT: return true; } return false; } void XmlCtrl::adjustPosRight() { int pos, max; bool canInsert = false; pos = GetCurrentPos(); max = GetLength(); for (; pos <= max; pos++) if (canInsertAt(pos)) { canInsert = true; break; } SetSelection(pos, pos); } void XmlCtrl::adjustPosLeft() { int pos; bool canInsert = false; pos = GetCurrentPos() - 1; if (pos < 0) { SetSelection(0, 0); return; } for (; pos > 0; pos--) if (canInsertAt(pos)) { canInsert = true; break; } SetSelection(pos, pos); } void XmlCtrl::adjustSelection() { int start, end, iterator; start = GetSelectionStart(); end = GetSelectionEnd(); // exit condition 1 if (start == end && canInsertAt(start)) return; // exit condition 2 else if (!canInsertAt(start) || start > end) { SetSelection(start, start); return; } for (iterator = start; iterator < end; iterator++) { if (!canMoveRightAt(iterator)) break; } SetSelection(start, iterator); } void XmlCtrl::setColorScheme(int scheme) { StyleSetFaceName(wxSTC_STYLE_DEFAULT, properties.font); switch (scheme) { case COLOR_SCHEME_DEFAULT: StyleSetForeground(wxSTC_STYLE_DEFAULT, *wxBLACK); StyleSetBackground(wxSTC_STYLE_DEFAULT, *wxWHITE); StyleClearAll(); baseBackground = LightColour(wxTheColourDatabase->Find(_T("YELLOW")), 20); alternateBackground = LightColour(wxTheColourDatabase->Find(_T("YELLOW")), 60); SetCaretLineBackground(baseBackground); SetCaretForeground(*wxBLACK); SetSelBackground(true, wxTheColourDatabase->Find(_T("LIGHT GREY"))); if (type == FILE_TYPE_CSS) { // CSS colours StyleSetForeground(wxSTC_CSS_DEFAULT, *wxBLACK); StyleSetForeground(wxSTC_CSS_TAG, *wxBLUE); StyleSetForeground(wxSTC_CSS_CLASS, *wxBLUE); StyleSetForeground(wxSTC_CSS_PSEUDOCLASS, *wxBLUE); StyleSetForeground(wxSTC_CSS_UNKNOWN_PSEUDOCLASS, *wxBLUE); StyleSetForeground(wxSTC_CSS_OPERATOR, *wxBLUE); StyleSetForeground(wxSTC_CSS_IDENTIFIER, *wxBLUE); StyleSetForeground(wxSTC_CSS_UNKNOWN_IDENTIFIER, *wxBLUE); StyleSetForeground(wxSTC_CSS_VALUE, *wxBLACK); StyleSetForeground(wxSTC_CSS_COMMENT, wxTheColourDatabase->Find(_T("GREY"))); StyleSetForeground(wxSTC_CSS_ID, *wxBLACK); StyleSetForeground(wxSTC_CSS_IMPORTANT, *wxRED); StyleSetForeground(wxSTC_CSS_DIRECTIVE, *wxBLUE); StyleSetForeground(wxSTC_CSS_DOUBLESTRING, *wxRED); StyleSetForeground(wxSTC_CSS_SINGLESTRING, *wxRED); StyleSetForeground(wxSTC_CSS_IDENTIFIER2, *wxRED); StyleSetForeground(wxSTC_CSS_ATTRIBUTE, *wxBLUE); } else // XML { StyleSetForeground(wxSTC_H_DEFAULT, *wxBLACK); StyleSetForeground(wxSTC_H_TAG, *wxBLUE); StyleSetForeground(wxSTC_H_TAGUNKNOWN, *wxBLUE); StyleSetForeground(wxSTC_H_ATTRIBUTE, *wxRED); StyleSetForeground(wxSTC_H_ATTRIBUTEUNKNOWN, *wxRED); StyleSetForeground(wxSTC_H_NUMBER, *wxBLACK); StyleSetForeground(wxSTC_H_DOUBLESTRING, *wxBLACK); StyleSetForeground(wxSTC_H_SINGLESTRING, *wxBLACK); StyleSetForeground(wxSTC_H_OTHER, *wxBLUE); StyleSetForeground(wxSTC_H_COMMENT, wxTheColourDatabase->Find(_T("GREY"))); StyleSetForeground(wxSTC_H_ENTITY, *wxRED); StyleSetForeground(wxSTC_H_TAGEND, *wxBLUE); StyleSetForeground(wxSTC_H_XMLSTART, wxTheColourDatabase->Find(_T("GREY"))); StyleSetForeground(wxSTC_H_XMLEND, wxTheColourDatabase->Find(_T("GREY"))); StyleSetForeground(wxSTC_H_CDATA, *wxRED); StyleSetForeground(wxSTC_H_QUESTION, wxTheColourDatabase->Find(_T("GREY"))); for (int i = wxSTC_H_SGML_DEFAULT; i <= wxSTC_H_SGML_BLOCK_DEFAULT; i++) StyleSetForeground(i, *wxBLUE); StyleSetForeground(wxSTC_H_SGML_ENTITY, *wxRED); StyleSetForeground(wxSTC_H_SGML_SPECIAL, *wxBLACK); StyleSetForeground(wxSTC_H_SGML_SIMPLESTRING, *wxRED); StyleSetForeground(wxSTC_H_SGML_DEFAULT, wxTheColourDatabase->Find(_T("GREY"))); } break; case COLOR_SCHEME_DEFAULT_BACKGROUND: StyleSetForeground(wxSTC_STYLE_DEFAULT, *wxBLACK); StyleSetBackground(wxSTC_STYLE_DEFAULT, *wxWHITE); StyleClearAll(); baseBackground = LightColour(wxTheColourDatabase->Find(_T("YELLOW")), 20); alternateBackground = LightColour(wxTheColourDatabase->Find(_T("YELLOW")), 60); SetCaretLineBackground(baseBackground); SetCaretForeground(*wxBLACK); SetSelBackground(true, wxTheColourDatabase->Find(_T("LIGHT GREY"))); if (type == FILE_TYPE_CSS) { // CSS colours StyleSetForeground(wxSTC_CSS_DEFAULT, *wxBLACK); StyleSetForeground(wxSTC_CSS_TAG, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_CSS_CLASS, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_CSS_PSEUDOCLASS, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_CSS_UNKNOWN_PSEUDOCLASS, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_CSS_OPERATOR, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_CSS_IDENTIFIER, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_CSS_UNKNOWN_IDENTIFIER, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_CSS_VALUE, *wxBLACK); StyleSetForeground(wxSTC_CSS_COMMENT, wxTheColourDatabase->Find(_T("GREY"))); StyleSetForeground(wxSTC_CSS_ID, *wxBLACK); StyleSetForeground(wxSTC_CSS_IMPORTANT, wxTheColourDatabase->Find(_T("ORANGE"))); StyleSetForeground(wxSTC_CSS_DIRECTIVE, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_CSS_DOUBLESTRING, wxTheColourDatabase->Find(_T("ORANGE"))); StyleSetForeground(wxSTC_CSS_SINGLESTRING, wxTheColourDatabase->Find(_T("ORANGE"))); StyleSetForeground(wxSTC_CSS_IDENTIFIER2, wxTheColourDatabase->Find(_T("ORANGE"))); StyleSetForeground(wxSTC_CSS_ATTRIBUTE, wxTheColourDatabase->Find(_T("SKY BLUE"))); } else // XML { StyleSetForeground(wxSTC_H_DEFAULT, *wxBLACK); StyleSetForeground(wxSTC_H_TAG, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_H_TAGUNKNOWN, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_H_ATTRIBUTE, wxTheColourDatabase->Find(_T("ORANGE"))); StyleSetForeground(wxSTC_H_ATTRIBUTEUNKNOWN, wxTheColourDatabase->Find(_T("ORANGE"))); StyleSetForeground(wxSTC_H_NUMBER, wxTheColourDatabase->Find(_T("GREY"))); StyleSetForeground(wxSTC_H_DOUBLESTRING, wxTheColourDatabase->Find(_T("GREY"))); StyleSetForeground(wxSTC_H_SINGLESTRING, wxTheColourDatabase->Find(_T("GREY"))); StyleSetForeground(wxSTC_H_OTHER, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_H_COMMENT, wxTheColourDatabase->Find(_T("GREY"))); StyleSetForeground(wxSTC_H_ENTITY, wxTheColourDatabase->Find(_T("ORANGE"))); StyleSetForeground(wxSTC_H_TAGEND, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_H_XMLSTART, wxTheColourDatabase->Find(_T("GREY"))); StyleSetForeground(wxSTC_H_XMLEND, wxTheColourDatabase->Find(_T("GREY"))); StyleSetForeground(wxSTC_H_CDATA, wxTheColourDatabase->Find(_T("ORANGE"))); StyleSetForeground(wxSTC_H_QUESTION, wxTheColourDatabase->Find(_T("GREY"))); for (int i = wxSTC_H_SGML_DEFAULT; i <= wxSTC_H_SGML_BLOCK_DEFAULT; i++) StyleSetForeground(i, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_H_SGML_ENTITY, wxTheColourDatabase->Find(_T("ORANGE"))); StyleSetForeground(wxSTC_H_SGML_SPECIAL, *wxBLACK); StyleSetForeground(wxSTC_H_SGML_SIMPLESTRING, wxTheColourDatabase->Find(_T("ORANGE"))); StyleSetForeground(wxSTC_H_SGML_DEFAULT, wxTheColourDatabase->Find(_T("GREY"))); } break; case COLOR_SCHEME_REDUCED_GLARE: StyleSetForeground(wxSTC_STYLE_DEFAULT, wxTheColourDatabase->Find(_T("LIGHT GREY"))); StyleSetBackground(wxSTC_STYLE_DEFAULT, wxTheColourDatabase->Find(_T("MIDNIGHT BLUE"))); StyleClearAll(); baseBackground = LightColour(wxTheColourDatabase->Find(_T("NAVY")), 0); alternateBackground = LightColour(wxTheColourDatabase->Find(_T("NAVY")), 10); SetCaretLineBackground(baseBackground); StyleSetForeground(wxSTC_STYLE_LINENUMBER, *wxBLACK); SetCaretForeground(*wxWHITE); SetSelBackground(true, wxTheColourDatabase->Find(_T("GREY"))); if (type == FILE_TYPE_CSS) { // CSS colours StyleSetForeground(wxSTC_CSS_DEFAULT, wxTheColourDatabase->Find(_T("LIGHT GREY"))); StyleSetForeground(wxSTC_CSS_TAG, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_CSS_CLASS, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_CSS_PSEUDOCLASS, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_CSS_UNKNOWN_PSEUDOCLASS, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_CSS_OPERATOR, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_CSS_IDENTIFIER, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_CSS_UNKNOWN_IDENTIFIER, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_CSS_VALUE, *wxWHITE); StyleSetForeground(wxSTC_CSS_COMMENT, wxTheColourDatabase->Find(_T("LIGHT GREY"))); StyleSetForeground(wxSTC_CSS_ID, *wxWHITE); StyleSetForeground(wxSTC_CSS_IMPORTANT, wxTheColourDatabase->Find(_T("ORANGE"))); StyleSetForeground(wxSTC_CSS_DIRECTIVE, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_CSS_DOUBLESTRING, wxTheColourDatabase->Find(_T("ORANGE"))); StyleSetForeground(wxSTC_CSS_SINGLESTRING, wxTheColourDatabase->Find(_T("ORANGE"))); StyleSetForeground(wxSTC_CSS_IDENTIFIER2, wxTheColourDatabase->Find(_T("ORANGE"))); StyleSetForeground(wxSTC_CSS_ATTRIBUTE, wxTheColourDatabase->Find(_T("SKY BLUE"))); } else // XML { StyleSetForeground(wxSTC_H_DEFAULT, *wxWHITE); StyleSetForeground(wxSTC_H_TAG, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_H_TAGUNKNOWN, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_H_ATTRIBUTE, wxTheColourDatabase->Find(_T("ORANGE"))); StyleSetForeground(wxSTC_H_ATTRIBUTEUNKNOWN, wxTheColourDatabase->Find(_T("ORANGE"))); StyleSetForeground(wxSTC_H_NUMBER, wxTheColourDatabase->Find(_T("LIGHT GREY"))); StyleSetForeground(wxSTC_H_DOUBLESTRING, wxTheColourDatabase->Find(_T("LIGHT GREY"))); StyleSetForeground(wxSTC_H_SINGLESTRING, wxTheColourDatabase->Find(_T("LIGHT GREY"))); StyleSetForeground(wxSTC_H_OTHER, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_H_COMMENT, wxTheColourDatabase->Find(_T("LIGHT GREY"))); StyleSetForeground(wxSTC_H_ENTITY, wxTheColourDatabase->Find(_T("ORANGE"))); StyleSetForeground(wxSTC_H_TAGEND, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_H_XMLSTART, wxTheColourDatabase->Find(_T("LIGHT GREY"))); StyleSetForeground(wxSTC_H_XMLEND, wxTheColourDatabase->Find(_T("LIGHT GREY"))); StyleSetForeground(wxSTC_H_CDATA, wxTheColourDatabase->Find(_T("ORANGE"))); StyleSetForeground(wxSTC_H_QUESTION, wxTheColourDatabase->Find(_T("LIGHT GREY"))); for (int i = wxSTC_H_SGML_DEFAULT; i <= wxSTC_H_SGML_BLOCK_DEFAULT; i++) StyleSetForeground(i, wxTheColourDatabase->Find(_T("SKY BLUE"))); StyleSetForeground(wxSTC_H_SGML_ENTITY, wxTheColourDatabase->Find(_T("ORANGE"))); StyleSetForeground(wxSTC_H_SGML_SPECIAL, *wxWHITE); StyleSetForeground(wxSTC_H_SGML_SIMPLESTRING, wxTheColourDatabase->Find(_T("ORANGE"))); StyleSetForeground(wxSTC_H_SGML_DEFAULT, wxTheColourDatabase->Find(_T("LIGHT GREY"))); } break; case COLOR_SCHEME_NONE: baseBackground = LightColour(wxTheColourDatabase->Find(_T("YELLOW")), 20); alternateBackground = LightColour(wxTheColourDatabase->Find(_T("YELLOW")), 60); SetCaretLineBackground(baseBackground); SetSelBackground(true, wxTheColourDatabase->Find(_T("LIGHT GREY"))); SetCaretForeground(*wxBLACK); StyleSetForeground(wxSTC_STYLE_DEFAULT, *wxBLACK); StyleSetBackground(wxSTC_STYLE_DEFAULT, *wxWHITE); StyleClearAll(); break; default: break; } if (type == FILE_TYPE_CSS) { StyleSetBold(wxSTC_CSS_CLASS, true); StyleSetBold(wxSTC_CSS_PSEUDOCLASS, true); StyleSetBold(wxSTC_CSS_UNKNOWN_PSEUDOCLASS, true); StyleSetBold(wxSTC_CSS_DOUBLESTRING, true); StyleSetBold(wxSTC_CSS_SINGLESTRING, true); StyleSetBold(wxSTC_CSS_DIRECTIVE, true); } else { StyleSetBold(wxSTC_H_XMLSTART, true); StyleSetBold(wxSTC_H_XMLEND, true); StyleSetBold(wxSTC_H_ATTRIBUTEUNKNOWN, true); StyleSetBold(wxSTC_H_ENTITY, true); StyleSetBold(wxSTC_H_QUESTION, true); StyleSetBold(wxSTC_H_SGML_ENTITY, true); StyleSetBold(wxSTC_H_SGML_DEFAULT, true); } applyVisibilityState(visibilityState); } void XmlCtrl::applyVisibilityState(int state) { if (type == FILE_TYPE_BINARY) return; visibilityState = state; bool visible; // hide tags/attributes visible = (state == HIDE_ATTRIBUTES || state == HIDE_TAGS) ? false : true; StyleSetVisible(wxSTC_H_OTHER, visible); StyleSetVisible(wxSTC_H_ATTRIBUTE, visible); StyleSetVisible(wxSTC_H_ATTRIBUTEUNKNOWN, visible); StyleSetVisible(wxSTC_H_DOUBLESTRING, visible); StyleSetVisible(wxSTC_H_SINGLESTRING, visible); // hide tags visible = (state == HIDE_TAGS) ? false : true; StyleSetVisible(wxSTC_H_TAG, visible); StyleSetVisible(wxSTC_H_TAGUNKNOWN, visible); StyleSetVisible(wxSTC_H_TAGEND, visible); StyleSetVisible(wxSTC_H_XMLSTART, visible); StyleSetVisible(wxSTC_H_XMLEND, visible); StyleSetVisible(wxSTC_H_CDATA, visible); StyleSetVisible(wxSTC_H_QUESTION, visible); StyleSetVisible(wxSTC_H_COMMENT, visible); for (int i = wxSTC_H_SGML_DEFAULT; i <= wxSTC_H_SGML_BLOCK_DEFAULT; i++) StyleSetVisible(i, visible); Colourise(0, -1); } int XmlCtrl::getType() { return type; } void XmlCtrl::foldAll() { expandFoldsToLevel(1, false); } void XmlCtrl::unfoldAll() { expandFoldsToLevel(wxSTC_FOLDLEVELNUMBERMASK, true); } void XmlCtrl::toggleFold() { int pos, line, level; pos = GetCurrentPos(); if (pos == -1) return; line = LineFromPosition(pos); level = GetFoldLevel(line); if (XMLCTRL_HASBIT(level, wxSTC_FOLDLEVELHEADERFLAG)) ToggleFold(line); } // adapted from wxSTEdit (c) 2005 John Labenski, Otto Wyss void XmlCtrl::expandFoldsToLevel(int level, bool expand) { Colourise(0, -1); const int line_n = GetLineCount(); for (int n = 0; n < line_n; n++) { int line_level = GetFoldLevel(n); if (XMLCTRL_HASBIT(line_level, wxSTC_FOLDLEVELHEADERFLAG)) { line_level -= wxSTC_FOLDLEVELBASE; line_level &= wxSTC_FOLDLEVELNUMBERMASK; if ((( expand && (line_level <= level)) || (!expand && (line_level >= level))) && (GetFoldExpanded(n) != expand)) ToggleFold(n); } } EnsureCaretVisible(); // seems to keep it in nearly the same place } void XmlCtrl::protectHeadLine() { if (*protectTags || !properties.fold) return; int pos1, pos2, line1, line2, level; pos1 = GetSelectionStart(); pos2 = GetSelectionEnd(); line1 = LineFromPosition(pos1); line2 = LineFromPosition(pos2); if (line2 < line1) { int temp = line1; line1 = line2; line2 = temp; } for (int i = line1; i <= line2; i++) { level = GetFoldLevel(i); if (XMLCTRL_HASBIT(level, wxSTC_FOLDLEVELHEADERFLAG) && !GetFoldExpanded(i)) ToggleFold(i); } } wxString XmlCtrl::getOpenTag(const wxString& element) { wxString openTag; openTag = _T("<") + element; std::set requiredAttributeSet; std::set::iterator it; std::string key = (const char *)element.mb_str(wxConvUTF8); requiredAttributeSet = requiredAttributeMap[key]; if (!requiredAttributeSet.empty()) { for (it = requiredAttributeSet.begin(); it != requiredAttributeSet.end(); it++) { openTag += _T(" "); openTag += wxString(it->c_str(), wxConvUTF8, it->size()); openTag += _T("=\"\""); } } openTag += _T(">"); return openTag; } bool XmlCtrl::insertChild(const wxString& child) { int start, end; start = GetSelectionStart(); end = GetSelectionEnd(); int offset; wxString openTag, closeTag; openTag = getOpenTag(child); closeTag = _T(""); if (start == end) { if (!canInsertAt(start)) return false; //tag = _T("<") + child + _T(">"); offset = openTag.Length(); wxString tag; tag = openTag + closeTag; InsertText(start, tag); SetSelection(start + offset, start + offset); SetFocus(); return true; } if (*protectTags) adjustSelection(); //wxString openTag, closeTag; //openTag = _T("<") + child + _T(">"); //closeTag = _T(""); offset = openTag.Length(); if (start > end) { int temp = end; start = end; end = temp; } InsertText(start, openTag); InsertText(end + offset, closeTag); SetSelection(start + offset, end + offset); return true; } bool XmlCtrl::insertSibling(const wxString& sibling, const wxString& parent) { int start = GetSelectionStart(); int limit = GetLength(); wxString parentCloseTag = _T(""); int parentCloseTagStart = FindText(start, limit, parentCloseTag); if (parentCloseTagStart == -1 || !canInsertAt(parentCloseTagStart + parentCloseTag.Length())) return false; int insertionPoint = parentCloseTagStart + parentCloseTag.Length(); SetSelection(insertionPoint, insertionPoint); insertNewLine(); wxString openTag, closeTag; int newCurrentPos, newAdjustedPos; newCurrentPos = GetCurrentPos(); openTag = getOpenTag(sibling); closeTag = _T(""); InsertText(newCurrentPos, openTag + closeTag); newAdjustedPos = newCurrentPos + openTag.Length(); SetSelection(newAdjustedPos, newAdjustedPos); return true; } bool XmlCtrl::insertEntity(const wxString& entity) { if (*protectTags) adjustCursor(); wxString insertBuffer; insertBuffer.Printf(_T("&%s;"), entity.c_str()); int pos = GetCurrentPos(); InsertText(GetCurrentPos(), insertBuffer); pos += insertBuffer.size(); SetSelection(pos, pos); return true; } wxString XmlCtrl::getParent() { int current, parentCloseAngleBracket; current = GetCurrentPos(); parentCloseAngleBracket = getParentCloseAngleBracket(current); return getLastElementName(parentCloseAngleBracket); } void XmlCtrl::insertNewLine() { bool autoindent = false; int pos, line, startPos, iteratorPos, newPos; pos = GetCurrentPos(); line = LineFromPosition(pos); startPos = PositionFromLine(line); iteratorPos = startPos; for (iteratorPos = startPos; (GetCharAt(iteratorPos) == ' ' || GetCharAt(iteratorPos) == '\t') && iteratorPos < pos; ++iteratorPos) autoindent = true; wxString s = GetTextRange(startPos, iteratorPos); NewLine(); if (autoindent) { newPos = PositionFromLine(line + 1); InsertText(newPos, s); SetSelection(newPos + s.size(), newPos + s.size()); } } void XmlCtrl::toggleLineBackground() { if (!properties.toggleLineBackground || visibilityState != HIDE_TAGS) { if (lineBackgroundState != BACKGROUND_STATE_NORMAL) { SetCaretLineBackground(baseBackground); lineBackgroundState = BACKGROUND_STATE_NORMAL; } return; } lineBackgroundState = (lineBackgroundState == BACKGROUND_STATE_NORMAL) ? BACKGROUND_STATE_LIGHT : BACKGROUND_STATE_NORMAL; SetCaretLineBackground((lineBackgroundState == BACKGROUND_STATE_NORMAL) ? baseBackground : alternateBackground); } std::set XmlCtrl::getEntitySet() { return entitySet; } bool XmlCtrl::shallowValidate(int maxLine, bool segmentOnly) { if (!properties.validateAsYouType || type != FILE_TYPE_XML) return true; validationRequired = false; if (!maxLine) maxLine = GetLineCount(); std::string bufferUtf8; int startLine, columnOffset; startLine = columnOffset = 0; if (!segmentOnly) { clearErrorIndicators(maxLine); bufferUtf8 = myGetTextRaw(); } else { int current, line, lineEnd, parentCloseAngleBracket, parentStartAngleBracket, memory; current = GetCurrentPos(); line = LineFromPosition(current);//PositionFromLine(current); // try to include next line lineEnd = GetLineEndPosition(line + 1); if (lineEnd == -1) lineEnd = GetLineEndPosition(line); // fetch parent parentCloseAngleBracket = getParentCloseAngleBracket(current); parentStartAngleBracket = getTagStartPos(parentCloseAngleBracket); if (parentStartAngleBracket == -1) return false; memory = parentStartAngleBracket; // fetch grandparent if not at start of document if (parentStartAngleBracket > 1) { parentCloseAngleBracket = getParentCloseAngleBracket(parentStartAngleBracket - 1); parentStartAngleBracket = getTagStartPos(parentCloseAngleBracket); if (parentStartAngleBracket == -1) parentStartAngleBracket = memory; } startLine = LineFromPosition(parentStartAngleBracket); if (startLine == line) { columnOffset = parentStartAngleBracket - PositionFromLine(line); // disallow negative offsets if (columnOffset < 0) columnOffset = 0; } // sanity-check range if (lineEnd <= parentStartAngleBracket) return false; // clear indicators within range StartStyling(parentStartAngleBracket, wxSTC_INDIC2_MASK); int length = lineEnd - parentStartAngleBracket; SetStyling(length, 0); // tweak raw getTextRange variant wxString wideBuffer = GetTextRange(parentStartAngleBracket, lineEnd); bufferUtf8 = (const char *)wideBuffer.mb_str(wxConvUTF8); } return shallowValidate(bufferUtf8.c_str(), bufferUtf8.size(), startLine, maxLine, columnOffset, segmentOnly); /* bool res = validator->parse(bufferUtf8, (segmentOnly) ? false : true); if (!validator->getOverrideFailure() && (!res || !validator->isValid())) { std::vector > positionVector = validator->getPositionVector(); if (res == XML_STATUS_ERROR) { positionVector.push_back(validator->getErrorPosition()); } std::vector >::iterator it; for (it = positionVector.begin(); it != positionVector.end(); it++) { int line, column; line = (it->first - 1) + startLine; column = it->second + columnOffset; setErrorIndicator(line, column); } return false; } return true; */ } bool XmlCtrl::shallowValidate(const char *buffer, size_t bufferLen, int startLine, int maxLine, int columnOffset, bool segmentOnly) { std::auto_ptr validator(new XmlShallowValidator( elementMap, attributeMap, requiredAttributeMap, entitySet, maxLine, segmentOnly)); bool res = validator->parse(buffer, bufferLen, (segmentOnly) ? false : true); if (!validator->getOverrideFailure() && (!res || !validator->isValid())) { std::vector > positionVector = validator->getPositionVector(); if (res == XML_STATUS_ERROR) { positionVector.push_back(validator->getErrorPosition()); } std::vector >::iterator it; for (it = positionVector.begin(); it != positionVector.end(); it++) { int line, column; line = (it->first - 1) + startLine; column = it->second + columnOffset; setErrorIndicator(line, column); } return false; } return true; } std::string XmlCtrl::myGetTextRaw() { int len = GetTextLength(); char *buf = new char[len+1]; SendMsg(2182, len+1, (long)buf); buf[len] = '\0'; std::string ret(buf); delete[] buf; return ret; } void XmlCtrl::setErrorIndicator(int line, int column) { int startPos, endPos; startPos = PositionFromLine(line) + column; endPos = GetLineEndPosition(line); StartStyling(startPos, wxSTC_INDIC2_MASK); int length = endPos - startPos; /* from CellBuffer.cxx: PLATFORM_ASSERT(lengthStyle == 0 || (lengthStyle > 0 && lengthStyle + position < length)); */ if (length == 0 || (length > 0 && length + startPos < GetLength())) { SetStyling(length, wxSTC_INDIC2_MASK); } } void XmlCtrl::clearErrorIndicators(int maxLine) { if (maxLine < 1) return; int documentLength = GetLength(); if (!documentLength) return; StartStyling(0, wxSTC_INDIC2_MASK); int length; length = (maxLine) ? GetLineEndPosition(maxLine) : documentLength; SetStyling(length, 0); } bool XmlCtrl::getValidationRequired() { return validationRequired; } void XmlCtrl::setValidationRequired(bool b) { validationRequired = b; } int XmlCtrl::getTagType(int pos) { int iteratorPos; // preliminary checks if (pos < 2) { return TAG_TYPE_ERROR; } else if (GetCharAt(pos - 1) == '/') { return TAG_TYPE_EMPTY; } // go to start of tag for (iteratorPos = pos; iteratorPos >= 0; --iteratorPos) { int style = getLexerStyleAt(iteratorPos); //style &= ~wxSTC_INDIC2_MASK; if (GetCharAt(iteratorPos) == '<' && (style == wxSTC_H_TAG || style == wxSTC_H_TAGUNKNOWN)) break; } if (GetCharAt(iteratorPos) != '<') return TAG_TYPE_ERROR; char c = GetCharAt(iteratorPos + 1); if (c == '!' || c == '?') return TAG_TYPE_OTHER; else if (c == '/') { return TAG_TYPE_CLOSE; } else { return TAG_TYPE_OPEN; } } // fetch style int disregarding indicator int XmlCtrl::getLexerStyleAt(int pos) { int style = GetStyleAt(pos); style &= ~wxSTC_INDIC2_MASK; return style; } bool XmlCtrl::getDtdFound() { return dtdFound; } void XmlCtrl::OnMiddleDown(wxMouseEvent& event) { if (GetSelectionStart() == GetSelectionEnd()) { event.Skip(); return; } Copy(); long x, y; event.GetPosition(&x, &y); int pastePosition = PositionFromPointClose(x, y); if (pastePosition == wxSTC_INVALID_POSITION) { event.Skip(); return; } SetSelection(pastePosition, pastePosition); Paste(); }