2193 lines
56 KiB
C++
Executable File
2193 lines
56 KiB
C++
Executable File
#include "xmlctrl.h"
|
|
#include "xmlpromptgenerator.h"
|
|
#include "xmlshallowvalidator.h"
|
|
#include "xmlencodinghandler.h"
|
|
#include <utility>
|
|
|
|
// 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 <eranif@bezeqint.net>
|
|
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<std::string> childSet = elementMap[parent];
|
|
std::set<std::string>::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<std::string, std::set<std::string> > 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("</");
|
|
insertBuffer += elementName;
|
|
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<std::string> valueSet;
|
|
|
|
valueSet = attributeMap[elementNameUtf8][attributeNameUtf8];
|
|
if (valueSet.empty())
|
|
return;
|
|
|
|
std::set<std::string>::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<std::string, std::set<std::string> > currentAttributeMap;
|
|
std::map<std::string, std::set<std::string> >::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<std::string>::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<wxString> XmlCtrl::getChildren(const wxString& parent)
|
|
{
|
|
std::string parentUtf8 = (const char *)parent.mb_str(wxConvUTF8);
|
|
std::set<wxString> mySet;
|
|
|
|
if (elementMap.find(parentUtf8) == elementMap.end())
|
|
return mySet;
|
|
|
|
std::set<std::string> myUtf8Set = elementMap[parentUtf8];
|
|
std::string currentUtf8;
|
|
wxString currentWide;
|
|
|
|
std::set<std::string>::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<XmlPromptGenerator> 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<std::string> requiredAttributeSet;
|
|
std::set<std::string>::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("</") + child + _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("</") + child + _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("</") + parent + _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("</") + sibling + _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<std::string> 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<std::pair<int, int> > positionVector = validator->getPositionVector();
|
|
|
|
if (res == XML_STATUS_ERROR)
|
|
{
|
|
positionVector.push_back(validator->getErrorPosition());
|
|
}
|
|
|
|
std::vector<std::pair<int, int> >::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<XmlShallowValidator> 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<std::pair<int, int> > positionVector = validator->getPositionVector();
|
|
|
|
if (res == XML_STATUS_ERROR)
|
|
{
|
|
positionVector.push_back(validator->getErrorPosition());
|
|
}
|
|
|
|
std::vector<std::pair<int, int> >::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();
|
|
}
|