summaryrefslogtreecommitdiffstats
path: root/quanta/parsers/saparser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'quanta/parsers/saparser.cpp')
-rw-r--r--quanta/parsers/saparser.cpp986
1 files changed, 986 insertions, 0 deletions
diff --git a/quanta/parsers/saparser.cpp b/quanta/parsers/saparser.cpp
new file mode 100644
index 00000000..230ddbe0
--- /dev/null
+++ b/quanta/parsers/saparser.cpp
@@ -0,0 +1,986 @@
+/***************************************************************************
+ saparser.cpp - description
+ -------------------
+ begin : Wed Feb 11 2004
+ copyright : (C) 2004 Andras Mantia <amantia@kde.org>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+//qt includes
+#include <qtimer.h>
+
+//kde includes
+#include <kdebug.h>
+#include <ktexteditor/editinterface.h>
+
+//own includes
+#include "saparser.h"
+#include "sagroupparser.h"
+#include "document.h"
+#include "dtds.h"
+#include "node.h"
+#include "parsercommon.h"
+#include "qtag.h"
+#include "quantacommon.h"
+#include "resource.h"
+
+//#define DEBUG_PARSER
+
+SAParser::SAParser()
+{
+ m_write = 0L;
+ m_baseNode = 0L;
+ m_currentNode = 0L;
+ m_quotesRx = QRegExp("\"|'");
+ m_specialInsideXml = false;
+ m_parsingEnabled = true;
+ m_synchronous = true;
+ m_parseOneLineTimer = new QTimer(this);
+ connect(m_parseOneLineTimer, SIGNAL(timeout()), this, SLOT(slotParseOneLine()));
+ m_parseInDetailTimer = new QTimer(this);
+ connect(m_parseInDetailTimer, SIGNAL(timeout()), this, SLOT(slotParseNodeInDetail()));
+}
+
+SAParser::~SAParser()
+{
+}
+
+void SAParser::init(Node *node, Document* write)
+{
+ m_baseNode = node;
+ m_write = write;
+ m_dtd = write->defaultDTD();
+}
+
+
+bool SAParser::slotParseOneLine()
+{
+ if ((!m_parsingEnabled || !baseNode) && !m_synchronous)
+ {
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "slotParseOneLine - interrupted" << endl;
+#endif
+ return false;
+ }
+ if (s_line <= s_endLine)
+ {
+ s_contextFound = false;
+ switch (s_currentContext.type)
+ {
+ case Group:
+ case Text: {
+ int areaEndPos = -1;
+ int quotedStringPos = -1;
+ int commentPos = -1;
+ int groupKeywordPos = -1;
+ if (s_searchContent || (s_parentNode && s_parentNode->tag->dtd()->family == Xml))
+ {
+ //search for different s_contexts
+ if (s_searchContent) //search for quoted strings, comments, groups only in non-comment special areas
+ {
+ quotedStringPos = s_textLine.find(m_quotesRx, s_col); //quoted strings
+ s_searchedString = s_textLine.left(quotedStringPos);
+ commentPos = s_searchedString.find(s_dtd->commentsStartRx, s_col); //comments
+ s_searchedString = s_textLine.left(commentPos);
+ if (s_fullParse)
+ groupKeywordPos = s_searchedString.find(s_dtd->structRx, s_col); //groups, like { }
+ } else
+ s_searchedString = s_textLine;
+ int specialAreaPos = -1;
+ if (s_searchForSpecialAreas) //special area inside special area
+ {
+ s_searchedString = s_textLine.left(groupKeywordPos);
+ specialAreaPos = s_searchedString.find(s_dtd->specialAreaStartRx, s_col);
+ }
+ if (s_searchForAreaEnd) //the end of the special area
+ {
+ s_searchedString = s_textLine.left(specialAreaPos);
+ areaEndPos = s_searchedString.find(s_areaEndString, s_col);
+ } else
+ if (s_searchForForcedAreaEnd) //the end of the special area if a forcing string was specified
+ {
+ s_searchedString = s_textLine.left(specialAreaPos);
+ areaEndPos = s_searchedString.find(s_forcedAreaRx, s_col);
+ if (areaEndPos != -1)
+ s_areaEndString = s_forcedAreaRx.cap();
+ }
+ //check which s_context was found first
+ if (quotedStringPos != -1) //is it a quoted string?
+ {
+ if ( (quotedStringPos < commentPos || commentPos == -1) &&
+ (quotedStringPos < groupKeywordPos || groupKeywordPos == -1) &&
+ (quotedStringPos < specialAreaPos || specialAreaPos == -1) &&
+ (quotedStringPos < areaEndPos || areaEndPos == -1) )
+ {
+ s_context.type = QuotedString;
+ s_context.area.bCol = quotedStringPos;
+ s_context.startString = s_textLine.mid(quotedStringPos, 1);
+ s_contextFound = true;
+ }
+ }
+ if (!s_contextFound && commentPos != -1) //is it a comment?
+ {
+ if ( (commentPos < groupKeywordPos || groupKeywordPos == -1) &&
+ (commentPos < specialAreaPos || specialAreaPos == -1) &&
+ (commentPos < areaEndPos || areaEndPos == -1) )
+ {
+ s_context.type = Comment;
+ s_context.area.bCol = commentPos;
+ s_context.startString = s_dtd->commentsStartRx.cap();
+ s_contextFound = true;
+ }
+ }
+ if (!s_contextFound && groupKeywordPos != -1) //is it a group structure?
+ {
+ if ( (groupKeywordPos < specialAreaPos || specialAreaPos == -1) &&
+ (groupKeywordPos < areaEndPos || areaEndPos == -1) )
+ {
+ QString foundText = s_dtd->structRx.cap();
+ if (foundText == s_dtd->structBeginStr)
+ {
+ s_context.type = Group;
+ s_context.area.bCol = groupKeywordPos;
+ s_context.startString = foundText;
+ //create a text node until the struct. beginning
+ s_currentContext.area.eLine = s_line;
+ s_currentContext.area.eCol = groupKeywordPos + foundText.length() - 1;
+ if (s_currentNode &&
+ (s_currentNode->tag->type == Tag::Text ||
+ s_currentNode->tag->type == Tag::Empty) )
+ ParserCommon::appendAreaToTextNode(m_write, s_currentContext.area, s_currentNode);
+ else
+ s_currentNode = ParserCommon::createTextNode(m_write, s_currentNode, s_line, s_currentContext.area.eCol + 1, s_currentContext.parentNode);
+
+ s_currentNode->tag->type = Tag::ScriptStructureBegin;
+ s_currentNode->tag->single = false;
+ s_currentNode->insideSpecial = true;
+ s_currentNode->specialInsideXml = m_specialInsideXml;
+ s_currentContext.lastNode = s_currentNode;
+
+ s_contextStack.push(s_currentContext);
+ s_currentContext.parentNode = s_currentNode;
+ s_col = s_context.area.bCol + s_context.startString.length();
+ s_currentContext.area.bLine = s_line;
+ s_currentContext.area.bCol = s_col;
+ s_currentContext.type = Group;
+ if (m_synchronous)
+ //slotParseOneLine();
+ return true;
+ else
+ {
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "Calling slotParseOneLine from parseArea (opening group struct)." << endl;
+#endif
+ m_parseOneLineTimer->start(0, true);
+ }
+ return true;
+ } else //it's a closing group structure element (like "}")
+ {
+ if (s_currentContext.type != Group)
+ {
+ s_col = groupKeywordPos + foundText.length();
+ if (m_synchronous)
+ //slotParseOneLine();
+ return true;
+ else
+ {
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "Calling slotParseOneLine from parseArea (closing group struct)." << endl;
+#endif
+ m_parseOneLineTimer->start(0, true);
+ }
+ return true;
+ }
+ s_currentContext.area.eLine = s_line;
+ s_currentContext.area.eCol = groupKeywordPos - 1;
+ //kdDebug(24000) << QString("Group Struct s_context: %1, %2, %3, %4").arg( s_currentContext.bLine).arg(s_currentContext.bCol).arg(s_currentContext.eLine).arg(s_currentContext.eCol) << endl;
+
+ if (s_currentNode &&
+ (s_currentNode->tag->type == Tag::Text ||
+ s_currentNode->tag->type == Tag::Empty) )
+ ParserCommon::appendAreaToTextNode(m_write, s_currentContext.area, s_currentNode);
+ else
+ s_currentNode = ParserCommon::createTextNode(m_write, s_currentNode, s_line, groupKeywordPos, s_currentContext.parentNode);
+ if (s_currentNode)
+ {
+ s_currentNode->insideSpecial = true;
+ s_currentNode->specialInsideXml = m_specialInsideXml;
+ }
+ s_previousContext = s_contextStack.pop();
+ s_currentContext.parentNode = s_previousContext.parentNode;
+ s_currentContext.lastNode = s_previousContext.lastNode;
+ s_currentContext.type = s_previousContext.type;
+ s_currentContext.area.bLine = s_line;
+ s_currentContext.area.bCol = groupKeywordPos + foundText.length();
+ s_currentContext.area.eLine = s_currentContext.area.eCol = -1;
+ s_currentContext.startString = s_previousContext.startString;
+ s_col = s_currentContext.area.bCol;
+
+ Tag *tag = new Tag();
+ tag->name = foundText;
+ tag->setStr(foundText);
+ tag->setWrite(m_write);
+ tag->setTagPosition(s_line, groupKeywordPos, s_line, s_col - 1);
+ tag->setDtd(s_dtd);
+ tag->type = Tag::ScriptStructureEnd;
+ tag->single = true;
+ Node *node = new Node(s_currentContext.parentNode);
+ nodeNum++;
+ node->tag = tag;
+ node->insideSpecial = true;
+ node->specialInsideXml = m_specialInsideXml;
+ if (s_currentContext.parentNode && !s_currentContext.parentNode->child)
+ {
+ s_currentContext.parentNode->child = node;
+ }
+ else if (s_currentContext.lastNode)
+ {
+ node->prev = s_currentContext.lastNode;
+ s_currentContext.lastNode->next = node;
+ }
+ s_currentNode = node;
+
+ if (m_synchronous)
+ return true;
+ else
+ {
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "Calling slotParseOneLine from parseArea (group structure)." << endl;
+#endif
+ m_parseOneLineTimer->start(0, true);
+ }
+ return true;
+ }
+ }
+ }
+ if (!s_contextFound && specialAreaPos != -1) //is it a special area?
+ {
+ if (specialAreaPos < areaEndPos || areaEndPos == -1)
+ {
+ QString foundText = s_dtd->specialAreaStartRx.cap();
+ s_currentContext.area.eLine = s_line;
+ s_currentContext.area.eCol = specialAreaPos - 1;
+ if (s_fullParse)
+ {
+ if ( s_currentNode &&
+ (s_currentNode->tag->type == Tag::Text ||
+ s_currentNode->tag->type == Tag::Empty) )
+ ParserCommon::appendAreaToTextNode(m_write, s_currentContext.area, s_currentNode);
+ else
+ s_currentNode = ParserCommon::createTextNode(m_write, s_currentNode, s_line, specialAreaPos, s_currentContext.parentNode);
+ if (s_currentNode)
+ {
+ s_currentNode->insideSpecial = true;
+ s_currentNode->specialInsideXml = m_specialInsideXml;
+ }
+ }
+ //create a toplevel node for the included special area
+ AreaStruct area(s_line, specialAreaPos, s_line, specialAreaPos + foundText.length() - 1);
+ Node *node = ParserCommon::createScriptTagNode(m_write, area, foundText, s_dtd, s_currentContext.parentNode, s_currentNode);
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "Parsing a nested area." << endl;
+#endif
+ AreaStruct area2(s_line, specialAreaPos, s_endLine, s_endCol);
+ SAParser *p = new SAParser();
+ p->init(m_baseNode, m_write);
+ s_currentNode = p->parseArea(area2, foundText, "", node, s_fullParse, true);
+ s_line = p->lastParsedLine();
+ s_col = p->lastParsedColumn();
+ delete p;
+ s_currentContext.area.bLine = s_line;
+ s_currentContext.area.bCol = s_col + 1;
+ s_textLine = ParserCommon::getLine(m_write, s_line, s_endLine, s_endCol);
+ s_col++;
+ if (m_synchronous)
+ {
+ return true;
+ }
+ else
+ {
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "Calling slotParseOneLine from slotParseOneLine (nested area)." << endl;
+#endif
+ m_parseOneLineTimer->start(0, true);
+ return true;
+ }
+ }
+ }
+ } else //when we look only for the area end string
+ if (s_searchForAreaEnd)
+ {
+ areaEndPos = s_textLine.find(s_areaEndString, s_col);
+ } else
+ if (s_searchForForcedAreaEnd)
+ {
+ areaEndPos = s_textLine.find(s_forcedAreaRx, s_col);
+ if (areaEndPos != -1)
+ s_areaEndString = s_forcedAreaRx.cap();
+ }
+
+ if (!s_contextFound && areaEndPos != -1) //did we find the end of the special area?
+ {
+ m_lastParsedLine = s_line;
+ m_lastParsedCol = areaEndPos + s_areaEndString.length() - 1;
+
+ s_currentContext.area.eLine = s_line;
+ s_currentContext.area.eCol = areaEndPos - 1;
+ //Always create a node between the opening and closing special area nodes.
+ //This fixes the "commnet loss" bug when editing in VPL and autocompletion
+ //for simple special areas like <? a ?>
+ if (s_fullParse || !s_parentNode->child)
+ {
+ if ( s_currentNode &&
+ (s_currentNode->tag->type == Tag::Text ||
+ s_currentNode->tag->type == Tag::Empty) )
+ ParserCommon::appendAreaToTextNode(m_write, s_currentContext.area, s_currentNode);
+ else
+ {
+ s_currentNode = ParserCommon::createTextNode(m_write, s_currentNode, s_line, areaEndPos, s_parentNode);
+ }
+ if (s_currentNode)
+ {
+ s_currentNode->insideSpecial = true;
+ s_currentNode->specialInsideXml = m_specialInsideXml;
+ }
+ }
+ //kdDebug(24000) << QString("Special area %1 ends at %2, %3").arg(s_dtd->name).arg(s_line).arg(lastCol) << endl;
+
+ //create a closing node for the special area
+ Tag *tag = new Tag();
+ tag->setTagPosition(s_line, areaEndPos, s_line, m_lastParsedCol);
+ tag->parse(s_areaEndString, m_write);
+ tag->setDtd(s_dtd);
+ tag->type = Tag::XmlTagEnd;
+ tag->validXMLTag = false; //FIXME: this is more or less a workaround. We should introduce and handle Tag::ScriptTagEnd
+ tag->single = true;
+ //at this point s_parentNode = the opening node of the special area (eg. <?)
+ //and it should always exist
+ Node *node = new Node(s_parentNode->parent);
+ nodeNum++;
+ s_parentNode->next = node;
+ node->prev = s_parentNode;
+ node->tag = tag;
+ node->closesPrevious = true;
+
+ if (s_fullParse)
+ {
+ Node *g_node, *g_endNode;
+ g_node = s_parentNode->child;
+ /* g_endNode = s_currentNode;
+ if (g_node && g_node == g_endNode)
+ g_endNode = s_parentNode->next;*/
+ g_endNode = node;
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "Calling slotParseForScriptGroup from slotParseOneLine." << endl;
+#endif
+// slotParseForScriptGroup();
+ if (!m_synchronous)
+ {
+ bool parsingLastNode = true;
+ Node *n = g_endNode;
+ while (n)
+ {
+ n = n->nextSibling();
+ if (n && n->insideSpecial)
+ {
+ parsingLastNode = false;
+ break;
+ }
+ }
+ SAGroupParser *groupParser = new SAGroupParser(this, write(), g_node, g_endNode, m_synchronous, parsingLastNode, true);
+ connect(groupParser, SIGNAL(rebuildStructureTree(bool)), SIGNAL(rebuildStructureTree(bool)));
+ connect(groupParser, SIGNAL(cleanGroups()), SIGNAL(cleanGroups()));
+ connect(groupParser, SIGNAL(parsingDone(SAGroupParser*)), SLOT(slotGroupParsingDone(SAGroupParser*)));
+ groupParser->slotParseForScriptGroup();
+ m_groupParsers.append(groupParser);
+ }
+ }
+
+ m_lastParsedNode = node;
+ s_useReturnVars = true;
+ if (!m_synchronous)
+ {
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "Calling parsingDone from slotParseOneLine (area end found)." << endl;
+#endif
+ m_lastParsedNode = parsingDone();
+ }
+ return false; //parsing finished
+ }
+ if (s_contextFound)
+ {
+ s_context.area.bLine = s_line;
+ s_context.area.eLine = s_context.area.eCol = -1;
+ s_context.parentNode = s_currentContext.parentNode;
+ s_currentContext.area.eLine = s_context.area.bLine;
+ s_currentContext.area.eCol = s_context.area.bCol - 1;
+ // s_currentContext.parentNode = s_parentNode;
+ s_contextStack.push(s_currentContext);
+ if (s_fullParse)
+ {
+ if (s_currentNode &&
+ (s_currentNode->tag->type == Tag::Text || s_currentNode->tag->type == Tag::Empty) )
+ {
+ ParserCommon::appendAreaToTextNode(m_write, s_currentContext.area, s_currentNode);
+ s_currentNode->insideSpecial = true;
+ s_currentNode->specialInsideXml = m_specialInsideXml;
+ } else
+ if (s_currentContext.area.bLine < s_currentContext.area.eLine ||
+ (s_currentContext.area.bLine == s_currentContext.area.eLine &&
+ s_currentContext.area.bCol < s_currentContext.area.eCol))
+ {
+ //create a tag from the s_currentContext
+ Tag *tag = new Tag(s_currentContext.area, m_write, s_dtd);
+ QString tagStr = tag->tagStr();
+ tag->cleanStr = tagStr;
+ QuantaCommon::removeCommentsAndQuotes(tag->cleanStr, s_dtd);
+ if (tagStr.simplifyWhiteSpace().isEmpty())
+ {
+ tag->type = Tag::Empty;
+ } else
+ {
+ tag->type = Tag::Text;
+ }
+ tag->single = true;
+ //create a node with the above tag
+ Node *node = new Node(s_currentContext.parentNode);
+ nodeNum++;
+ node->tag = tag;
+ node->insideSpecial = true;
+ node->specialInsideXml = m_specialInsideXml;
+ if (s_currentContext.parentNode && !s_currentContext.parentNode->child)
+ {
+ s_currentContext.parentNode->child = node;
+ }
+ else if (s_currentNode)
+ {
+ node->prev = s_currentNode;
+ s_currentNode->next = node;
+ }
+ s_currentNode = node;
+ }
+ }
+ //kdDebug(24000) << QString("%1 s_context: %2, %3, %4, %5").arg(s_currentContext.type).arg( s_currentContext.bLine).arg(s_currentContext.bCol).arg(s_currentContext.eLine).arg(s_currentContext.eCol) << endl;
+
+ s_currentContext = s_context;
+ s_col = s_context.area.bCol + s_context.startString.length();
+ } else
+ {
+ s_line++;
+ s_col = 0;
+ s_textLine = ParserCommon::getLine(m_write, s_line, s_endLine, s_endCol);
+ }
+ break;
+ }
+ case QuotedString:
+ {
+ int pos = -1;
+ int p = s_col;
+ int l = s_textLine.length();
+ while (p < l)
+ {
+ p = s_textLine.find(s_currentContext.startString, p);
+ if (p != -1)
+ {
+ if (p >= 0)
+ {
+ int i = p - 1;
+ int slahNum = 0;
+ while (i > 0 && s_textLine[i] == '\\')
+ {
+ slahNum++;
+ i--;
+ }
+ if (p == 0 || (slahNum % 2 == 0))
+ {
+ pos = p;
+ break;
+ }
+ }
+ } else
+ break;
+ p++;
+ }
+ if (pos != -1)
+ {
+ // if (pos != 0) pos++;
+ s_currentContext.area.eLine = s_line;
+ s_currentContext.area.eCol = pos;
+ //kdDebug(24000) << QString("Quoted String s_context: %1, %2, %3, %4").arg( s_currentContext.bLine).arg(s_currentContext.bCol).arg(s_currentContext.eLine).arg(s_currentContext.eCol) << endl;
+ if (s_fullParse)
+ {
+ if ( s_currentNode &&
+ (s_currentNode->tag->type == Tag::Text ||
+ s_currentNode->tag->type == Tag::Empty) )
+ ParserCommon::appendAreaToTextNode(m_write, s_currentContext.area, s_currentNode);
+ else
+ s_currentNode = ParserCommon::createTextNode(m_write, 0L, s_line, pos, s_currentContext.parentNode);
+ s_currentNode->insideSpecial = true;
+ s_currentNode->specialInsideXml = m_specialInsideXml;
+ }
+ s_previousContext = s_contextStack.pop();
+ s_currentContext.parentNode = s_previousContext.parentNode;
+ s_currentContext.type = s_previousContext.type;
+ s_currentContext.area.bLine = s_line;
+ s_currentContext.area.bCol = pos + 1;
+ s_currentContext.area.eLine = s_currentContext.area.eCol = -1;
+ s_currentContext.startString = s_previousContext.startString;
+ s_col = pos + 1;
+ } else
+ {
+ s_line++;
+ s_col = 0;
+ s_textLine = ParserCommon::getLine(m_write, s_line, s_endLine, s_endCol);
+ }
+ break;
+ }
+ case Comment:
+ {
+ int pos = s_textLine.find(s_dtd->comments[s_currentContext.startString], s_col);
+ if (pos == -1 && s_dtd->comments[s_currentContext.startString] == "\n")
+ {
+ int pos2 = s_textLine.find(s_areaEndString, s_col);
+ if (pos2 != -1)
+ {
+ pos = pos2 - 1;
+ } else
+ {
+ pos = s_textLine.length();
+ }
+ }
+ if (pos != -1)
+ {
+ s_currentContext.area.eLine = s_line;
+ s_currentContext.area.eCol = pos + s_dtd->comments[s_currentContext.startString].length() - 1;
+ s_currentContext.type = s_previousContext.type;
+ //kdDebug(24000) << QString("Comment s_context: %1, %2, %3, %4").arg( s_currentContext.bLine).arg(s_currentContext.bCol).arg(s_currentContext.eLine).arg(s_currentContext.eCol) << endl;
+
+ if (s_fullParse)
+ {
+ //create a tag with the comment
+ Tag *tag = new Tag(s_currentContext.area, m_write, s_dtd);
+ tag->type = Tag::Comment;
+ tag->single = true;
+ //create a node with the above tag
+ Node *node = new Node(s_currentContext.parentNode);
+ nodeNum++;
+ node->tag = tag;
+ node->insideSpecial = true;
+ node->specialInsideXml = m_specialInsideXml;
+ if (s_currentNode && s_currentNode != node->parent)
+ {
+ s_currentNode->next = node;
+ node->prev = s_currentNode;
+ } else
+ if (node->parent && !node->parent->child)
+ node->parent->child = node;
+ s_currentNode = node;
+ }
+ s_previousContext = s_contextStack.pop();
+ s_currentContext.parentNode = s_previousContext.parentNode;
+ s_currentContext.type = s_previousContext.type;
+ s_currentContext.area.bLine = s_line;
+ s_currentContext.area.bCol = s_currentContext.area.eCol + 1;
+ s_currentContext.area.eLine = s_currentContext.area.eCol = -1;
+ s_currentContext.startString = s_previousContext.startString;
+ s_col = s_currentContext.area.bCol;
+ } else
+ {
+ s_line++;
+ s_col = 0;
+ s_textLine = ParserCommon::getLine(m_write, s_line, s_endLine, s_endCol);
+ }
+ break;
+ }
+ default:
+ {
+ s_line++;
+ s_col = 0;
+ s_textLine = ParserCommon::getLine(m_write, s_line, s_endLine, s_endCol);
+ }
+ }
+ if (m_synchronous)
+ {
+ //slotParseOneLine();
+ }
+ else
+ {
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "Calling slotParseOneLine from slotParseOneLine." << endl;
+#endif
+ m_parseOneLineTimer->start(0, true);
+ }
+ } else
+ {
+ if (!m_synchronous)
+ {
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "Calling parsingDone from slotParseOneLine." << endl;
+#endif
+ parsingDone();
+ }
+ return false; //parsing finished
+ }
+ return true;
+}
+
+Node* SAParser::parseArea(const AreaStruct &specialArea,
+ const QString &areaStartString,
+ const QString &forcedAreaEndString,
+ Node *parentNode,
+ bool fullParse, bool synchronous)
+{
+ m_synchronous = synchronous;
+ s_parentNode = parentNode;
+ s_fullParse = fullParse;
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "parseArea full: " << s_fullParse << " synch: " << m_synchronous <<endl;
+#endif
+
+ int s_startLine = specialArea.bLine;
+ int s_startCol = specialArea.bCol;
+ s_endLine = specialArea.eLine;
+ s_endCol = specialArea.eCol;
+ //kdDebug(24000) << QString("Starting to parse at %1, %2 for %3").arg(s_startLine).arg(s_startCol).arg(areaStartString) << endl;
+
+ s_searchForAreaEnd = false;
+ s_searchForForcedAreaEnd = false;
+ s_dtd = 0L;
+ if (s_parentNode && !areaStartString.isEmpty())
+ {
+ const DTDStruct *parentDTD = m_dtd;
+ if (s_parentNode->parent)
+ parentDTD = s_parentNode->parent->tag->dtd();
+ s_dtd = DTDs::ref()->find(parentDTD->specialAreaNames[areaStartString]);
+ s_areaEndString = parentDTD->specialAreas[areaStartString];
+ s_searchForAreaEnd = true;
+ }
+ if (!forcedAreaEndString.isEmpty())
+ {
+ s_forcedAreaRx.setPattern(forcedAreaEndString);
+ s_forcedAreaRx.setCaseSensitive(m_dtd->caseSensitive);
+ s_searchForForcedAreaEnd = true;
+ s_searchForAreaEnd = false;
+ if (s_parentNode)
+ s_dtd = s_parentNode->tag->dtd();
+ }
+ s_searchContent = true;
+ if (s_parentNode && s_parentNode->tag->type == Tag::Comment)
+ s_searchContent = false;
+ if (!s_dtd)
+ {
+ if (s_parentNode)
+ s_dtd = s_parentNode->tag->dtd(); //fallback, usually when the special area is a comment
+ else
+ s_dtd = m_dtd; //fallback when there is no s_parentNode
+ }
+ m_write->addDTEP(s_dtd->name);
+ s_searchForSpecialAreas = (s_dtd->specialAreas.count() > 0);
+ if (s_parentNode && s_parentNode->tag->type == Tag::Comment)
+ s_searchForSpecialAreas = false;
+ s_col = s_startCol + areaStartString.length();
+ s_line = s_startLine;
+ s_textLine = m_write->text(s_startLine, 0, s_startLine, m_write->editIf->lineLength(s_startLine));
+ if (s_line == s_endLine)
+ {
+ if (s_endCol > 0)
+ s_textLine.truncate(s_endCol + 1);
+ else
+ s_textLine = "";
+ }
+
+ s_previousContext.type = Unknown;
+ s_currentContext.type = Text;
+ s_currentContext.area.bLine = s_line;
+ s_currentContext.area.bCol = s_col;
+ s_currentContext.area.eLine = s_currentContext.area.eCol = -1;
+ s_currentContext.parentNode = s_parentNode;
+ s_currentNode = s_parentNode;
+ m_lastParsedNode = 0L;
+ s_useReturnVars = false;
+ if (s_line <= s_endLine)
+ {
+ if (m_synchronous)
+ {
+ while (slotParseOneLine()); //actually this parses the whole area, as synchronous == true
+ if (s_useReturnVars) //this is true if the special area end was found
+ {
+ return m_lastParsedNode;
+ }
+ }
+ else
+ {
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "Calling slotParseOneLine from parseArea." << endl;
+#endif
+ m_parseOneLineTimer->start(0, true);
+ return 0L;
+ }
+ }
+ if (m_synchronous) //if the special area end was not found and we are in synchronous mode
+ {
+ s_next = 0L;
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "Calling parsingDone from parseArea." << endl;
+#endif
+ s_currentNode = parsingDone();
+ return s_currentNode;
+ }
+ return 0L;
+}
+
+Node *SAParser::parsingDone()
+{
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "parsingDone. Use return values:" << s_useReturnVars << endl;
+#endif
+ if (s_useReturnVars)
+ {
+ if (s_fullParse)
+ {
+ Node *n = m_lastParsedNode;
+ if (m_useNext)
+ {
+// kdDebug(24000) << "m_lastParsedNode: " << m_lastParsedNode << " " << m_lastParsedNode->tag->tagStr() << endl;
+ n->next = s_next;
+ if (s_next)
+ {
+ s_next->prev = n;
+ }
+ n->prev = s_parentNode;
+ }
+ m_currentNode = n->nextSibling();
+ if (m_currentNode)
+ {
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "Calling slotParseNodeInDetail from parsingDone (use return values)" << endl;
+#endif
+ m_parseInDetailTimer->start(0, true);
+ return m_lastParsedNode;
+ }
+ else
+ {
+ m_parsingEnabled = true;
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "Emitting rebuildStructureTree from parsingDone (use return values). Enable parsing." << endl;
+#endif
+ emit rebuildStructureTree(false);
+#ifdef DEBUG_PARSER
+// kdDebug(24000) << "Calling cleanGroups from SAParser::parsingDone" << endl;
+#endif
+ emit cleanGroups();
+ }
+ }
+ m_currentNode = 0L;
+ return m_lastParsedNode;
+ }
+ if (!s_currentNode)
+ {
+ s_currentNode = ParserCommon::createTextNode(m_write, s_parentNode, s_endLine, s_endCol, s_parentNode);
+ if (s_currentNode)
+ {
+ s_currentNode->insideSpecial = true;
+ s_currentNode->specialInsideXml = m_specialInsideXml;
+ }
+ }
+ else if (s_parentNode && !s_parentNode->next)
+ {
+ s_currentNode = ParserCommon::createTextNode(m_write, s_currentNode, s_endLine, s_endCol, s_parentNode);
+ s_currentNode->insideSpecial = true;
+ s_currentNode->specialInsideXml = m_specialInsideXml;
+ }
+ if (s_fullParse)
+ {
+ Node *n;
+ if (s_parentNode)
+ {
+ n = s_parentNode;//->child;
+ } else
+ {
+ n = s_currentNode;
+ while (n && n->prev)
+ n = n->prev;
+ s_currentNode = n;
+ }
+ Node *g_node = n;
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "Calling slotParseForScriptGroup from parsingDone. Synch:" << m_synchronous << endl;
+#endif
+ //parse for groups only when doing aynchronous detailed parsing
+ if (!m_synchronous)
+ {
+ SAGroupParser *groupParser = new SAGroupParser(this, write(), g_node, 0L, m_synchronous, true /*last node*/, true);
+ connect(groupParser, SIGNAL(rebuildStructureTree(bool)), SIGNAL(rebuildStructureTree(bool)));
+ connect(groupParser, SIGNAL(cleanGroups()), SIGNAL(cleanGroups()));
+ connect(groupParser, SIGNAL(parsingDone(SAGroupParser*)), SLOT(slotGroupParsingDone(SAGroupParser*)));
+ groupParser->slotParseForScriptGroup();
+ m_groupParsers.append(groupParser);
+ }
+ }
+
+ m_lastParsedLine = s_endLine;
+ m_lastParsedCol = s_endCol + 1;
+
+ if (s_fullParse && m_currentNode)
+ {
+ if (m_useNext && s_currentNode)
+ {
+// kdDebug(24000) << "s_currentNode: " << s_currentNode << endl;
+ Node *n = s_currentNode;
+ n->next = s_next;
+ if (s_next)
+ s_next->prev = n;
+ }
+ m_currentNode = m_currentNode->nextSibling();
+ if (m_currentNode)
+ {
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "Calling slotParseNodeInDetail from parsingDone." << endl;
+#endif
+ m_parseInDetailTimer->start(0, true);
+ emit rebuildStructureTree(false);
+ }
+ else
+ {
+ m_parsingEnabled = true;
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "Emitting detailedParsingDone from parsingDone. Enable parsing." << endl;
+#endif
+ emit rebuildStructureTree(false);
+ }
+ }
+ m_currentNode = 0L;
+ return s_currentNode;
+}
+
+void SAParser::parseInDetail(bool synchronous)
+{
+// synchronous = true; //for testing. Uncomment to test the parser in synchronous mode
+// return; //for testing. Uncomment to disable the detailed parser
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "parseInDetail. Enabled: " << m_parsingEnabled << endl;
+#endif
+ if (!m_parsingEnabled)
+ {
+ m_currentNode = m_baseNode;
+ m_parsingEnabled = true;
+ m_synchronous = synchronous;
+ if (m_currentNode)
+ {
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "Calling slotParseNodeInDetail from parseInDetail." << endl;
+#endif
+ slotParseNodeInDetail();
+ }
+ }
+}
+
+void SAParser::slotParseNodeInDetail()
+{
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "slotParseNodeInDetail. Enabled: " << m_parsingEnabled << " Synch: " << m_synchronous << endl; //this is really heavy debug information, enable only when really needed
+#endif
+ if (m_currentNode && m_parsingEnabled && baseNode)
+ {
+ if (m_currentNode->insideSpecial &&
+ m_currentNode->tag->type != Tag::Comment &&
+ m_currentNode->tag->type != Tag::Text &&
+ m_currentNode->tag->type != Tag::Empty)
+ {
+ Node::deleteNode(m_currentNode->child);
+ m_currentNode->child = 0L;
+ AreaStruct area(m_currentNode->tag->area());
+ s_next = 0L;
+ m_useNext = false;
+ //FIXME: Find out why can the tag become 0L
+ if (m_currentNode->next && m_currentNode->next->tag)
+ {
+ AreaStruct area2(m_currentNode->next->tag->area());
+ area.eLine = area2.eLine;
+ area.eCol = area2.eCol + 1;
+ s_next = m_currentNode->next->next;
+ if (m_currentNode->next->closesPrevious)
+ {
+ m_currentNode->next->removeAll = false;
+ Node *secondNext = m_currentNode->next->next;
+ if (secondNext)
+ secondNext->prev = m_currentNode;
+ Node::deleteNode(m_currentNode->next);
+ m_currentNode->next = secondNext;
+ m_useNext = true;
+ }
+ } else
+ {
+ area.eLine = m_write->editIf->numLines() - 1;
+ area.eCol = m_write->editIf->lineLength(area.eLine);
+ }
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "Calling parseArea from slotParseNodeInDetail." << endl;
+#endif
+ QString areaStartString = m_currentNode->tag->tagStr();
+ if (m_currentNode->tag->dtd()->specialAreaNames[areaStartString].isEmpty())
+ {
+ AreaStruct area2(m_currentNode->tag->area());
+ area.bLine = area2.eLine;
+ area.bCol = area2.eCol + 1;
+ parseArea(area, "", "</"+m_currentNode->tag->name+"\\s*>", m_currentNode, true, m_synchronous);
+ }
+ else
+ parseArea(area, m_currentNode->tag->tagStr(), "", m_currentNode, true, m_synchronous);
+ } else
+ {
+// Node *node = m_currentNode;
+ m_currentNode = m_currentNode->nextSibling();
+ if (m_currentNode)
+ {
+#ifdef DEBUG_PARSER
+// kdDebug(24001) << "Calling slotParseNodeInDetail from slotParseNodeInDetail." << endl; //this is really heavy debug information, enable only when really needed
+#endif
+ m_parseInDetailTimer->start(0, true);
+ } else
+ {
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "Emitting rebuildStructureTree from slotParseNodeInDetail." << endl;
+#endif
+ emit rebuildStructureTree(false);
+ }
+ }
+ }
+}
+
+
+void SAParser::setParsingEnabled(bool enabled)
+{
+#ifdef DEBUG_PARSER
+ kdDebug(24001) << "Parsing enabled: " << enabled << endl;
+#endif
+ m_parsingEnabled = enabled;
+ if (!enabled)
+ {
+ m_parseOneLineTimer->stop();
+ m_parseInDetailTimer->stop();
+ for (QValueList<SAGroupParser*>::Iterator it = m_groupParsers.begin(); it != m_groupParsers.end(); ++it)
+ {
+ (*it)->m_parseForGroupTimer->stop();
+ delete (*it);
+ }
+ m_groupParsers.clear();
+ }
+}
+
+void SAParser::slotGroupParsingDone(SAGroupParser *groupParser)
+{
+ m_groupParsers.remove(groupParser);
+ delete groupParser;
+}
+
+
+#include "saparser.moc"