diff --git a/src/Makefile.am b/src/Makefile.am index 1847a83..78e40f4 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,7 +24,7 @@ xmlcopyeditor_SOURCES = xmlcopyeditor.cpp associatedialog.cpp casehandler.cpp \ insertpanel.cpp xmlwordcount.cpp getword.cpp locationpanel.cpp catalogresolver.cpp getlinuxappdir.cpp \ xmlparseschemans.cpp xmlshallowvalidator.cpp wrapxerces.cpp \ findreplacepanel.cpp commandpanel.cpp \ - binaryfile.cpp xmlencodingspy.cpp wrapaspell.cpp \ + binaryfile.cpp xmlencodingspy.cpp wrapaspell.cpp validationthread.cpp \ rulesets png rng xpm templates copying help po \ xmlcopyeditor.spec xmlcopyeditor.png custom.xpm \ xmlcopyeditor.desktop diff --git a/src/Makefile.in b/src/Makefile.in index 063f1bd..7d63299 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -70,7 +70,7 @@ am_xmlcopyeditor_OBJECTS = xmlcopyeditor.$(OBJEXT) \ xmlshallowvalidator.$(OBJEXT) wrapxerces.$(OBJEXT) \ findreplacepanel.$(OBJEXT) commandpanel.$(OBJEXT) \ binaryfile.$(OBJEXT) xmlencodingspy.$(OBJEXT) \ - wrapaspell.$(OBJEXT) + wrapaspell.$(OBJEXT) validationthread.$($OBJEXT) xmlcopyeditor_OBJECTS = $(am_xmlcopyeditor_OBJECTS) xmlcopyeditor_LDADD = $(LDADD) xmlcopyeditor_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ @@ -209,7 +209,7 @@ xmlcopyeditor_SOURCES = xmlcopyeditor.cpp associatedialog.cpp casehandler.cpp \ insertpanel.cpp xmlwordcount.cpp getword.cpp locationpanel.cpp catalogresolver.cpp getlinuxappdir.cpp \ xmlparseschemans.cpp xmlshallowvalidator.cpp wrapxerces.cpp \ findreplacepanel.cpp commandpanel.cpp \ - binaryfile.cpp xmlencodingspy.cpp wrapaspell.cpp \ + binaryfile.cpp xmlencodingspy.cpp wrapaspell.cpp validationthread.cpp \ rulesets png rng xpm templates copying help po \ xmlcopyeditor.spec xmlcopyeditor.png custom.xpm \ xmlcopyeditor.desktop @@ -351,6 +351,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rule.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/styledialog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrapaspell.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/validationthread.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrapexpat.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wraplibxml.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrapregex.Po@am__quote@ diff --git a/src/wrapxerces.cpp b/src/wrapxerces.cpp index fc67c39..ce71135 100755 --- a/src/wrapxerces.cpp +++ b/src/wrapxerces.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,7 @@ bool WrapXerces::validate ( const std::string& fileName ) parser->setFeature ( XMLUni::fgXercesSchema, true ); parser->setFeature ( XMLUni::fgXercesSchemaFullChecking, true ); parser->setFeature ( XMLUni::fgXercesValidationErrorAsFatal, true ); + parser->setFeature ( XMLUni::fgXercesLoadExternalDTD, true ); DefaultHandler handler; MySAX2Handler mySAX2Handler; @@ -98,8 +100,75 @@ bool WrapXerces::validate ( const std::string& fileName ) return true; } +// tbd: cache grammar +bool WrapXerces::validateMemory ( + const char *buffer, + const char *system, + unsigned len ) +{ + SAX2XMLReader *parser = XMLReaderFactory::createXMLReader(); + + parser->setFeature ( XMLUni::fgSAX2CoreNameSpaces, true ); + parser->setFeature ( XMLUni::fgSAX2CoreValidation, true ); + parser->setFeature ( XMLUni::fgXercesDynamic, true ); + parser->setFeature ( XMLUni::fgXercesSchema, true ); + parser->setFeature ( XMLUni::fgXercesSchemaFullChecking, true ); + parser->setFeature ( XMLUni::fgXercesValidationErrorAsFatal, true ); + parser->setFeature ( XMLUni::fgXercesLoadExternalDTD, true ); + + DefaultHandler handler; + MySAX2Handler mySAX2Handler; + parser->setContentHandler ( &handler ); + parser->setErrorHandler ( &mySAX2Handler ); + parser->setEntityResolver ( &handler ); + + XMLByte* xmlBuffer = (XMLByte*) buffer; + MemBufInputSource source ( + xmlBuffer, + len, + system ); + + try + { + parser->parse ( source ); + } + catch ( XMLException& e ) + { + delete parser; + lastError = ""; + return false; + } + catch ( SAXParseException& e ) + { + delete parser; + char *err = XMLString::transcode ( e.getMessage() ); + std::stringstream ss; + ss << "Ln " << e.getLineNumber() << " Col " << e.getColumnNumber() << ": " << err; + lastError = ss.str(); + errorPosition = std::make_pair ( e.getLineNumber(), e.getColumnNumber() ); + XMLString::release ( &err ); + return false; + } + catch ( ... ) + { + delete parser; + lastError = ""; + return false; + } + delete parser; + return true; +} + std::string WrapXerces::getLastError() { + char *rawError, *it; + rawError = (char *)lastError.c_str(); + it = strstr ( rawError, "Message:" ); + if ( it ) + { + lastError = it + 8; + } + return lastError; } diff --git a/src/wrapxerces.h b/src/wrapxerces.h index e91a724..f1c8bbe 100755 --- a/src/wrapxerces.h +++ b/src/wrapxerces.h @@ -34,6 +34,7 @@ class WrapXerces WrapXerces(); ~WrapXerces(); bool validate ( const std::string& fileName ); + bool validateMemory ( const char *buffer, const char *system, unsigned len ); std::string getLastError(); std::pair getErrorPosition(); private: diff --git a/src/xmlcopyeditor.cpp b/src/xmlcopyeditor.cpp index a55fe61..ab7d307 100755 --- a/src/xmlcopyeditor.cpp +++ b/src/xmlcopyeditor.cpp @@ -3112,7 +3112,7 @@ bool MyFrame::openFile ( wxString& fileName, bool largeFile ) if ( !largeFile && ( properties.validateAsYouType && doc->getGrammarFound() ) ) { statusProgress ( _T ( "Validating document..." ) ); - doc->shallowValidate ( finalBuffer, finalBufferLen ); + doc->shallowValidate ( finalBuffer, doc->getFullFileName().mb_str(wxConvUTF8), finalBufferLen ); statusProgress ( wxEmptyString ); } @@ -3811,7 +3811,7 @@ void MyFrame::OnValidateSchema ( wxCommandEvent& event ) int cursorPos = doc->PositionFromLine ( posPair.first - 1 ); doc->SetSelection ( cursorPos, cursorPos ); - doc->setErrorIndicator ( posPair.first - 1, posPair.second ); + doc->setErrorIndicator ( posPair.first - 1, 0 ); //posPair.second ); } else documentOk ( _ ( "valid" ) ); @@ -4744,7 +4744,7 @@ bool MyFrame::saveFile ( XmlDoc *doc, wxString& fileName, bool checkLastModified if ( properties.validateAsYouType && isXml ) { doc->clearErrorIndicators(); - doc->shallowValidate ( utf8Buffer.c_str(), utf8Buffer.size() ); + doc->shallowValidate ( utf8Buffer.c_str(), doc->getFullFileName().mb_str(wxConvUTF8), utf8Buffer.size() ); } if ( !unlimitedUndo ) diff --git a/src/xmlcopyeditorcopy.h b/src/xmlcopyeditorcopy.h index 223a343..b40d667 100755 --- a/src/xmlcopyeditorcopy.h +++ b/src/xmlcopyeditorcopy.h @@ -41,5 +41,5 @@ "License along with this program; if not, write to the Free\n"\ "Software Foundation, Inc., 59 Temple Place, Suite 330,\n"\ "Boston, MA 02111-1307 USA.") -#define ABOUT_VERSION _T("1.1.0.7") +#define ABOUT_VERSION _T("1.2.0") #define XMLCE_VAR _T("XMLCE_VAR") diff --git a/src/xmlctrl.cpp b/src/xmlctrl.cpp index 5dde2fb..a44d547 100755 --- a/src/xmlctrl.cpp +++ b/src/xmlctrl.cpp @@ -21,7 +21,10 @@ #include "xmlpromptgenerator.h" #include "xmlshallowvalidator.h" #include "xmlencodinghandler.h" +#include "wrapxerces.h" +#include "xmlcopyeditor.h" // needed to enable validation-as-you-type alerts #include +#include // adapted from wxSTEdit (c) 2005 John Labenski, Otto Wyss #define XMLCTRL_HASBIT(value, bit) (((value) & (bit)) != 0) @@ -59,8 +62,13 @@ XmlCtrl::XmlCtrl ( basePath ( basePathParameter ), auxPath ( auxPathParameter ) { + validationThread = NULL; + validationStarted = false; + validationFinished = false; + grammarFound = false; + validationRequired = (buffer) ? true : false; // NULL for plain XML template + currentMaxLine = 1; - validationRequired = grammarFound = false; applyProperties ( propertiesParameter ); @@ -130,6 +138,24 @@ static wxColor LightColour ( const wxColour& color, int percent ) void XmlCtrl::OnIdle ( wxIdleEvent& event ) { + // poll validation thread output if any + if (validationStarted && validationFinished) + { + validationStarted = false; + MyFrame *frame = (MyFrame *)GetGrandParent(); + if ( validationSuccess ) + { + clearErrorIndicators ( GetLineCount() ); + frame->statusProgress ( wxEmptyString ); + } + else + { + clearErrorIndicators ( validationPosition.first -1 ); + setErrorIndicator ( validationPosition.first - 1, 0 ); + frame->statusProgress ( wxString ( validationMessage.c_str(), wxConvUTF8, validationMessage.size() ) ); + } + } + if ( properties.number && type != FILE_TYPE_BINARY ) adjustNoColumnWidth(); } @@ -1968,91 +1994,59 @@ 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 ); - - // 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 ); + clearErrorIndicators ( GetLineCount() ); + std::string bufferUtf8 = myGetTextRaw(); + + return shallowValidate ( + bufferUtf8.c_str(), + basePath.c_str(), + bufferUtf8.size() ); } -bool XmlCtrl::shallowValidate ( const char *buffer, - size_t bufferLen, - int startLine, - int maxLine, - int columnOffset, - bool segmentOnly ) +bool XmlCtrl::shallowValidate ( + const char *buffer, + const char *system, + size_t bufferLen//, + //int startLine, + //int maxLine, + //int columnOffset, + //bool segmentOnly + ) { + if ( !validationRequired ) + return true; + + validationRequired = false; + + if (validationThread && !validationFinished) + { + validationThread->Delete(); + validationThread = NULL; + } + + validationThread = new ValidationThread( + buffer, + system, + &validationFinished, + &validationSuccess, + &validationPosition, + &validationMessage + ); + + if ( validationThread->Create() != wxTHREAD_NO_ERROR ) + { + validationFinished = true; + return false; + } + + validationStarted = true; + validationFinished = false; + + + validationThread->Run(); + return true; + +/* std::auto_ptr validator ( new XmlShallowValidator ( elementMap, attributeMap, @@ -2084,6 +2078,7 @@ bool XmlCtrl::shallowValidate ( const char *buffer, return false; } return true; +*/ } std::string XmlCtrl::myGetTextRaw() diff --git a/src/xmlctrl.h b/src/xmlctrl.h index 529de53..135b0b2 100755 --- a/src/xmlctrl.h +++ b/src/xmlctrl.h @@ -1,3 +1,4 @@ + /* * Copyright 2005-2007 Gerald Schmidt. * @@ -27,6 +28,7 @@ #include #include #include +#include "validationthread.h" struct XmlCtrlProperties { @@ -111,6 +113,7 @@ class XmlCtrl: public wxStyledTextCtrl attributeMap.clear(); elementMap.clear(); entitySet.clear(); + // don't delete validationThread in case it's gone } int getType(); int getParentCloseAngleBracket ( int pos, int range = USHRT_MAX * 4 ); @@ -141,15 +144,25 @@ class XmlCtrl: public wxStyledTextCtrl int getTagStartPos ( int pos ); void toggleLineBackground(); bool shallowValidate ( int maxLine = 0, bool segmentOnly = false ); - bool shallowValidate ( const char *buffer, size_t bufferLen, - int startLine = 0, - int maxLine = 0, - int columnOffset = 0, - bool segmentOnly = false ); + bool shallowValidate ( + const char *buffer, + const char *system, + size_t bufferLen//, + //int startLine = 0, + //int maxLine = 0, + //int columnOffset = 0, + //bool segmentOnly = false + ); std::string myGetTextRaw(); // alternative to faulty stc implementation bool getValidationRequired(); void setValidationRequired ( bool b ); private: + // the following are used for background validation + ValidationThread *validationThread; + bool validationStarted, validationFinished, validationSuccess; + std::pair validationPosition; + std::string validationMessage; + int type; bool *protectTags; bool validationRequired, grammarFound;