From e9ae80694875f869892f13f4fcaf1170a00dea41 Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdewebdev@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- quanta/parsers/Makefile.am | 16 + quanta/parsers/dtd/Makefile.am | 11 + quanta/parsers/dtd/dtd.cpp | 415 ++++++++ quanta/parsers/dtd/dtd.h | 64 ++ quanta/parsers/dtd/dtdparser.cpp | 362 +++++++ quanta/parsers/dtd/dtdparser.h | 55 ++ quanta/parsers/dtd/dtepcreationdlg.ui | 152 +++ quanta/parsers/node.cpp | 559 +++++++++++ quanta/parsers/node.h | 185 ++++ quanta/parsers/parser.cpp | 1757 +++++++++++++++++++++++++++++++++ quanta/parsers/parser.h | 160 +++ quanta/parsers/parsercommon.cpp | 256 +++++ quanta/parsers/parsercommon.h | 59 ++ quanta/parsers/qtag.cpp | 260 +++++ quanta/parsers/qtag.h | 283 ++++++ quanta/parsers/sagroupparser.cpp | 311 ++++++ quanta/parsers/sagroupparser.h | 63 ++ quanta/parsers/saparser.cpp | 986 ++++++++++++++++++ quanta/parsers/saparser.h | 150 +++ quanta/parsers/tag.cpp | 672 +++++++++++++ quanta/parsers/tag.h | 212 ++++ 21 files changed, 6988 insertions(+) create mode 100644 quanta/parsers/Makefile.am create mode 100644 quanta/parsers/dtd/Makefile.am create mode 100644 quanta/parsers/dtd/dtd.cpp create mode 100644 quanta/parsers/dtd/dtd.h create mode 100644 quanta/parsers/dtd/dtdparser.cpp create mode 100644 quanta/parsers/dtd/dtdparser.h create mode 100644 quanta/parsers/dtd/dtepcreationdlg.ui create mode 100644 quanta/parsers/node.cpp create mode 100644 quanta/parsers/node.h create mode 100644 quanta/parsers/parser.cpp create mode 100644 quanta/parsers/parser.h create mode 100644 quanta/parsers/parsercommon.cpp create mode 100644 quanta/parsers/parsercommon.h create mode 100644 quanta/parsers/qtag.cpp create mode 100644 quanta/parsers/qtag.h create mode 100644 quanta/parsers/sagroupparser.cpp create mode 100644 quanta/parsers/sagroupparser.h create mode 100644 quanta/parsers/saparser.cpp create mode 100644 quanta/parsers/saparser.h create mode 100644 quanta/parsers/tag.cpp create mode 100644 quanta/parsers/tag.h (limited to 'quanta/parsers') diff --git a/quanta/parsers/Makefile.am b/quanta/parsers/Makefile.am new file mode 100644 index 00000000..ef11528d --- /dev/null +++ b/quanta/parsers/Makefile.am @@ -0,0 +1,16 @@ +SUBDIRS = dtd +METASOURCES = AUTO + +noinst_LTLIBRARIES = libparser.la +libparser_la_SOURCES = qtag.cpp node.cpp tag.cpp parser.cpp saparser.cpp \ + parsercommon.cpp sagroupparser.cpp + +AM_CPPFLAGS = -I$(top_srcdir)/quanta/utility \ + -I$(top_srcdir)/quanta/src \ + -I$(top_srcdir)/quanta/parts/kafka \ + -I$(top_srcdir)/quanta/treeviews \ + -I$(top_srcdir)/lib \ + $(KMDI_INCLUDES) $(all_includes) + + +noinst_HEADERS = saparser.h parsercommon.h sagroupparser.h diff --git a/quanta/parsers/dtd/Makefile.am b/quanta/parsers/dtd/Makefile.am new file mode 100644 index 00000000..80f647fb --- /dev/null +++ b/quanta/parsers/dtd/Makefile.am @@ -0,0 +1,11 @@ +noinst_LTLIBRARIES = libdtdparser.la +libdtdparser_la_SOURCES = dtepcreationdlg.ui dtdparser.cpp + +METASOURCES = AUTO + +AM_CPPFLAGS = -I$(top_srcdir)/quanta/parsers \ + -I$(top_srcdir)/quanta/utility \ + -I$(top_srcdir)/quanta/dialogs \ + -I$(top_builddir)/quanta/dialogs \ + -I$(top_srcdir)/lib \ + $(LIBXML_CFLAGS) $(all_includes) diff --git a/quanta/parsers/dtd/dtd.cpp b/quanta/parsers/dtd/dtd.cpp new file mode 100644 index 00000000..18e3d712 --- /dev/null +++ b/quanta/parsers/dtd/dtd.cpp @@ -0,0 +1,415 @@ +/*************************************************************************** + dtdparser.cpp - description + ------------------- + begin : Tue Jul 30 15:26:20 EEST 2002 + copyright : (C) 2002 by Jason P. Hanley + (C) 2002, 2003 Andras Mantia + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "dtd.h" +#include "../quantacommon.h" +#include "../qextfileinfo.h" + + +DTD::DTD(const KURL &dtdURL, const QString &dtepDir) +{ + m_dtdURL = dtdURL; + m_dtepDir = dtepDir + "/"+QFileInfo(dtdURL.fileName()).baseName(); //TODO: get the dir name from the DTD or from the user +} + +DTD::~DTD() +{ +} + +QStringList DTD::getTags() +{ + return tags; +} + +AttributeList* DTD::getTagAttributes(QString tag) +{ + return tagAttributes.find(tag); +} + + +QStringList DTD::getTextCompletion(QString tag) +{ + return QStringList(); +} + +void DTD::printContents() +{ + for ( QStringList::Iterator tagIt = tags.begin(); tagIt != tags.end(); ++tagIt ) { + QString tag = *tagIt; + kdDebug(24000) << tag << endl; + AttributeList *attributes = getTagAttributes(tag); + for ( uint i = 0; i < attributes->count(); i++) + { + Attribute *attribute = attributes->at(i); + QString s = " " + attribute->name + ": "; + for (uint j = 0; j < attribute->values.count(); j++) + { + s += attribute->values[j] + ", "; + } + kdDebug(24000) << s << endl; + } + } +} + +void DTD::writeTagFiles() +{ + QString dirName = m_dtepDir; + KURL u; + u.setPath(dirName); + if (!QExtFileInfo::createDir(dirName)) { + QuantaCommon::dirCreationError(0, u); + return; + } + dirName.append("/"); + for ( QStringList::Iterator tagIt = tags.begin(); tagIt != tags.end(); ++tagIt ) { + QString tag = *tagIt; + + QFile file( dirName + tag.lower() + ".tag" ); + if ( file.open( IO_WriteOnly ) ) { + QTextStream stream( &file ); + stream.setEncoding(QTextStream::UnicodeUTF8); + stream << "" << endl + << "" << endl + << "" << endl << endl; + + AttributeList *attributes = getTagAttributes(tag); + stream << QuantaCommon::xmlFromAttributes(attributes); + + stream << "" << endl + << "" << endl; + + file.close(); + } else { + kdDebug(24000) << "Unable to write tag file: " << file.name() << endl; + } + } + + KConfig config(dirName + "description.rc"); + config.setGroup("General"); + config.writeEntry("Name", QFileInfo(m_dtdURL.fileName()).baseName()); //TODO: get from the DTD! + config.writeEntry("NickName", QFileInfo(m_dtdURL.fileName()).baseName()); //TODO: get from the user! + config.sync(); +} + +bool DTD::parseDTD(const KURL &url) +{ + QString fileName = QString::null; + if (!KIO::NetAccess::download(url, fileName)) + { + KMessageBox::error(0, i18n("Cannot download the DTD from %1.").arg(url.prettyURL(0, KURL::StripFileProtocol))); + return false; + } + QFile file(fileName); + if (file.open(IO_ReadOnly)) + { + QTextStream fileStream(&file); + fileStream.setEncoding(QTextStream::UnicodeUTF8); + QString entireDTD = fileStream.read(); + file.close(); + removeComments(entireDTD); + + QString line; + QStringList lines = QStringList::split("\n",entireDTD); + QStringList::Iterator it = lines.begin(); + while (it != lines.end()) { + line = *it; + + if (line.startsWith("<")) { + while (!line.endsWith(">") && it != lines.end()) { + ++it; + line += " \\end" + *it; + } + } else if (line.startsWith("%")) { + while (!line.endsWith(";") && it != lines.end()) { + ++it; + line += *it; + } + } + + line = line.stripWhiteSpace(); + line = line.simplifyWhiteSpace(); + + //kdDebug(24000) << "Parsed line is: " << line << endl; + + if ( line.startsWith("")) + { + parseDTDEntity(line); + } + else + if (line.startsWith("")) + { + parseDTDElement(line); + } + else + if (line.startsWith("")) + { + parseDTDAttlist(line); + } + else + if (line.startsWith("%") && line.endsWith(";")) + { + line.remove(0,1); + line.truncate(line.length()-1); + KURL entityURL = url; + entityURL.setPath(url.directory()+ "/" + line + ".ent"); + parseDTD(entityURL); + } else + { + kdDebug(24000) << QString("Unknown tag: [%1]").arg(line) << endl; + } + + if (it != lines.end()) ++it; + } + } +} + +void DTD::parseDTDEntity(QString line) { + QString name; + QString *value; + + line.replace("\\end", " "); + name = line.mid(11); + int firstSpace = name.find(' '); + name = name.remove(firstSpace, name.length()-firstSpace); + + value = new QString(line.mid(11+firstSpace)); + value->remove(0, value->find("\"")+1); + value->remove(value->findRev("\""), value->length()); + + parseDTDReplace(value); + stripSpaces(value); + + entities.insert(name, value); + + //kdDebug() << "Entity --- Name: " << name << " --- Value: " << *value << endl; +} + +void DTD::parseDTDElement(const QString &l) { + QString name; + QString *value; + + QString line = l; + line.replace("\\end", " "); + name = line.mid(10); + int firstSpace = name.find(' '); + name.remove(firstSpace, name.length()-firstSpace); + + value = new QString(line.mid(10+firstSpace)); + //value->remove(0, value->find("\"")+1); + value->remove(value->find(">"), 10000); + + parseDTDReplace(&name); + parseDTDReplace(value); + + if ( name.startsWith("(") && name.endsWith(")") ) { + name.remove(0,1); + name.remove(name.length()-1,1); + QStringList multipleTags = QStringList::split("|", name); + QStringList::Iterator it = multipleTags.begin(); + while(it != multipleTags.end()) { + name = *it; + name = name.stripWhiteSpace(); + elements.insert(name, value); + tags.append(name); + //kdDebug() << "Element --- Name: " << name << " --- Value: " << *value << endl; + ++it; + } + } else { + elements.insert(name, value); + tags.append(name); + //kdDebug() << "Element --- Name: " << name << " --- Value: " << *value << endl; + } +} + +void DTD::parseDTDAttlist(const QString &l) { + QString name; + QString *value; + + QString line = l; + line.replace("\\end", " "); + name = line.mid(10); + int firstSpace = name.find(' '); + name.remove(firstSpace, name.length()-firstSpace); + + value = new QString(line.mid(10+firstSpace)); + //value->remove(0, value->find("\"")+1); + value->remove(value->find(">"), 10000); + + parseDTDReplace(&name); + parseDTDReplace(value); + + if ( name.startsWith("(") && name.endsWith(")") ) { + name.remove(0,1); + name.remove(name.length()-1,1); + QStringList multipleTags = QStringList::split("|", name); + QStringList::Iterator it = multipleTags.begin(); + while(it != multipleTags.end()) { + name = *it; + name = name.stripWhiteSpace(); + //elements.insert(name, value); + parseTagAttributeValues(name, value); + //kdDebug() << "Attlist --- Name: " << name << " --- Value: " << *value << endl; + ++it; + } + } else { + //elements.insert(name, value); + parseTagAttributeValues(name, value); + //kdDebug() << "Attlist --- Name: " << name << " --- Value: " << *value << endl; + } + +} + +void DTD::parseTagAttributeValues(const QString &name, QString *value) { + AttributeList *attributes = new AttributeList(); + + QStringList attrLines = QStringList::split("\\end",*value); + QStringList::Iterator lineIt = attrLines.begin(); + while (lineIt != attrLines.end()) //iterate through the attribute lines + { + //split the attribute line + QStringList all = QStringList::split(" ", *lineIt); + QStringList::Iterator it = all.begin(); + while(it != all.end()) + { + Attribute *attr = new Attribute(); + attr->name = *it; + //kdDebug() << "Inserting for tag " << name << ": " << *it << endl; + ++it; + + QString values = *it; + //list of possible values + if ( values.startsWith("(") && values.endsWith(")") ) + { + values.remove(0,1); + values.remove(values.length()-1,1); + attr->values = QStringList::split("|", values); + QString s = (attr->values[0]+attr->values[1]).lower(); + stripSpaces(&s); + if ((s == "truefalse") || (s == "falsetrue")) + { + attr->type = "check"; + } else + { + attr->type = "list"; + } + } else + { + attr->values = values; + attr->type = "input"; + } + + //kdDebug() << " --- values: " << *it << endl; + if (it != all.end()) + { + ++it; + QString s=*it; + if (s.startsWith("\"") && s.endsWith("\"") && it!=all.end()) + { + s.remove(0,1); + s.remove(s.length()-1,1); + attr->defaultValue = s; + } + if (s.startsWith("#") && it != all.end()) + { + s.remove(0,1); + attr->status = s.lower(); + } + if (*it == "#FIXED" && it != all.end()) + { + ++it; + attr->values.append(*it); + } + } + + if (it != all.end()) + { + ++it; + } + attributes->append(attr); + } + ++lineIt; + } + tagAttributes.insert(name, attributes); +} + +void DTD::parseDTDReplace(QString *value) { + int begin, end; + begin = value->find("%"); + end = value->find(";"); + while (begin != -1 && end != -1) { + QString replaceText = value->mid(begin+1, end-begin-1); + QString *replaceValue = entities.find(replaceText); + + if (replaceValue != 0L) { + value->replace(begin, end-begin+1, *replaceValue); + } else { + kdDebug(24000) << "Can not find entity: " << replaceText << endl; + return; + } + + begin = value->find("%"); + end = value->find(";"); + } +} + +void DTD::stripSpaces(QString *value) { + int index=-1; + while ( (index=value->find(' ',++index)) != -1 ) { + if ( value->findRev('(',index) != -1 && value->find(')',index) != -1) + value->remove(index,1); + } +} + +void DTD::removeComments(QString &value) { + int begin, end; + begin = value.find("",begin+2); + while (begin != -1 && end != -1) { + value.remove(begin, end-begin+3); + begin = value.find("",begin+2); + } + + begin = value.find("--"); + end = value.find("--",begin+2); + while (begin != -1 && end != -1) { + value.remove(begin, end-begin+2); + begin = value.find("--"); + end = value.find("--",begin+2); + } + + value.replace(QRegExp(""), ""); +} + +bool DTD::parseDTD() +{ + return parseDTD(m_dtdURL); +} diff --git a/quanta/parsers/dtd/dtd.h b/quanta/parsers/dtd/dtd.h new file mode 100644 index 00000000..45b0e213 --- /dev/null +++ b/quanta/parsers/dtd/dtd.h @@ -0,0 +1,64 @@ +/*************************************************************************** + dtdparser.cpp - description + ------------------- + begin : Tue Jul 30 15:26:20 EEST 2002 + copyright : (C) 2002 by Jason P. Hanley + (C) 2002, 2003 Andras Mantia + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef DTD_H +#define DTD_H + +//qt includes +#include + +//app includes +#include "qtag.h" + +class KURL; + +class DTD +{ + +public: + DTD(const KURL &dtdURL, const QString& dtepDir); + ~DTD(); + +public: + QStringList getTags(); + AttributeList* getTagAttributes(QString tag); + QStringList getTextCompletion(QString tag); + void printContents(); + void writeTagFiles(); + /** No descriptions */ + bool parseDTD(); + +private: + bool parseDTD(const KURL& url); + void parseDTDEntity(const QString &line); + void parseDTDElement(const QString &line); + void parseDTDAttlist(const QString &line); + void parseTagAttributeValues(const QString &name, QString *value); + void parseDTDReplace(QString *value); + void stripSpaces(QString *value); + void removeComments(QString &value); + + QDict entities; + QDict elements; + QStringList tags; + QDict tagAttributes; + /** From where to load the DTD file. */ + KURL m_dtdURL; + QString m_dtepDir; +}; + +#endif diff --git a/quanta/parsers/dtd/dtdparser.cpp b/quanta/parsers/dtd/dtdparser.cpp new file mode 100644 index 00000000..86060967 --- /dev/null +++ b/quanta/parsers/dtd/dtdparser.cpp @@ -0,0 +1,362 @@ +/*************************************************************************** + dtdparser.cpp - description + ------------------- + begin : Sun Oct 19 16:47:20 EEST 2003 + copyright : (C) 2003 Andras Mantia + ***************************************************************************/ + +/*************************************************************************** + * * + * 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; version 2 of the License. * + * * + ***************************************************************************/ + +//qt includes +#include +#include +#include +#include +#include +#include +#include + +//kde includes +#include +#include +#include +#include +#include +#include +#include + +//other includes +#ifdef LIBXML_2_5 +#include +#endif + +#include +#include + +//own includes +#include "dtepeditdlg.h" +#include "dtdparser.h" +#include "qtag.h" +#include "dtepcreationdlg.h" +#include "quantacommon.h" +#include "qextfileinfo.h" + +#define MAX_CHILD_ELEMENTS 100 + +namespace DTD +{ + QString dirName; + xmlDtdPtr dtd_ptr; /* Pointer to the parsed DTD */ + QTextStream entityStream; +} + +void saveElement(xmlElementPtr elem, xmlBufferPtr buf); +void saveEntity(xmlEntityPtr entity, xmlBufferPtr buf); + +DTDParser::DTDParser(const KURL& dtdURL, const QString &dtepDir) +{ + m_dtdURL = dtdURL; + m_dtepDir = dtepDir; +} + +DTDParser::~DTDParser() +{ +} + +bool DTDParser::parse(const QString &targetDir, bool entitiesOnly) +{ + bool fineTune = false; + QString fileName = QString::null; + if (!KIO::NetAccess::download(m_dtdURL, fileName, 0)) + { + KMessageBox::error(0, i18n("Cannot download the DTD from %1.").arg( m_dtdURL.prettyURL(0, KURL::StripFileProtocol))); + return false; + } + DTD::dtd_ptr = xmlParseDTD(NULL, xmlCharStrndup(fileName.utf8(), fileName.utf8().length())); + if( DTD::dtd_ptr == NULL ) + { + QString errorStr = i18n("Unknown"); +#ifndef LIBXML_2_5 + xmlErrorPtr errorPtr = xmlGetLastError(); + if (errorPtr != NULL) + { + QString s = QString::fromLatin1(errorPtr->message); + if (!s.isEmpty()) + errorStr = s; + s = QString::fromLatin1(errorPtr->str1); + if (!s.isEmpty()) + errorStr += "
" + s; + s = QString::fromLatin1(errorPtr->str2); + if (!s.isEmpty()) + errorStr += "
" + s; + s = QString::fromLatin1(errorPtr->str2); + if (!s.isEmpty()) + errorStr += "
" + s; + errorStr += QString("(%1, %2)").arg(errorPtr->line).arg(errorPtr->int2); + xmlResetError(errorPtr); + } +#endif + KMessageBox::error(0, i18n("Error while parsing the DTD.
The error message is:
%1
").arg(errorStr)); + return false; + } + if (targetDir.isEmpty()) + { + KDialogBase dlg(0L, 0L, true, i18n("DTD - > DTEP Conversion"), KDialogBase::Ok | KDialogBase::Cancel); + DTEPCreationDlg w(&dlg); + dlg.setMainWidget(&w); + QString name = QString((const char*)DTD::dtd_ptr->name); + if (name == "none") + name = QFileInfo(m_dtdURL.fileName()).baseName(); + w.dtdName->setText(name); + w.nickName->setText(name); + w.directory->setText(QFileInfo(m_dtdURL.fileName()).baseName()); + w.doctype->setText(QString((const char*)DTD::dtd_ptr->ExternalID)); + w.dtdURL->setText(QString((const char*)DTD::dtd_ptr->SystemID)); + if (!dlg.exec()) + return false; + m_name = w.dtdName->text(); + m_nickName = w.nickName->text(); + m_doctype = w.doctype->text(); + m_doctype.replace(QRegExp("")); + m_dtdURLLine = w.dtdURL->text(); + m_defaultExtension = w.defaultExtension->text(); + m_caseSensitive = w.caseSensitive->isChecked(); + DTD::dirName = m_dtepDir + "/" + w.directory->text(); + fineTune = w.fineTune->isChecked(); + } else + DTD::dirName = targetDir; + KURL u; + u.setPath(DTD::dirName); + if (!QExtFileInfo::createDir(u, 0L)) { + QuantaCommon::dirCreationError(0L, u); + return false; + } + DTD::dirName.append("/"); + if (DTD::dtd_ptr->entities) + { + QFile file( DTD::dirName + "entities.tag" ); + if ( file.open( IO_WriteOnly ) ) + { + DTD::entityStream.setDevice(&file); + DTD::entityStream.setEncoding(QTextStream::UnicodeUTF8); + DTD::entityStream << "" << endl; + DTD::entityStream << "" << endl + << "" << endl; + xmlHashScan((xmlEntitiesTablePtr)DTD::dtd_ptr->entities, (xmlHashScanner)saveEntity, 0); + DTD::entityStream << "" << endl; + file.close(); + } else + { + KMessageBox::error(0L, i18n("Cannot create the
%1 file.
Check that you have write permission in the parent folder.
") + .arg(file.name())); + return false; + } + } + if (!entitiesOnly) + { + if (DTD::dtd_ptr->elements) + { + xmlHashScan((xmlElementTablePtr)DTD::dtd_ptr->elements, (xmlHashScanner)saveElement, 0); + } else + { + KMessageBox::error(0, i18n("No elements were found in the DTD.")); + return false; + } + } + xmlFreeDtd(DTD::dtd_ptr); + if (!entitiesOnly) + { + writeDescriptionRC(); + if (fineTune) + { + KDialogBase editDlg(0L, "edit_dtep", true, i18n("Configure DTEP"), KDialogBase::Ok | KDialogBase::Cancel); + DTEPEditDlg dtepDlg(DTD::dirName + "description.rc", &editDlg); + editDlg.setMainWidget(&dtepDlg); + if (editDlg.exec()) + { + dtepDlg.saveResult(); + } + } + } + return true; +} + +void DTDParser::writeDescriptionRC() +{ + KConfig config(DTD::dirName + "description.rc"); + config.setGroup("General"); + config.writeEntry("Name", m_name); + config.writeEntry("NickName", m_nickName); + config.writeEntry("DoctypeString", m_doctype); + config.writeEntry("URL", m_dtdURLLine); + config.writeEntry("DefaultExtension", m_defaultExtension); + config.writeEntry("Family", "1"); + config.writeEntry("CaseSensitive", m_caseSensitive); +// config.setGroup("Parsing rules"); +// config.writeEntry("SpecialAreas",",,"); +// config.writeEntry("SpecialAreaNames","comment,XML PI,DTD"); + + config.sync(); +} + +void saveElement(xmlElementPtr elem, xmlBufferPtr buf) +{ + Q_UNUSED(buf); + if (elem) + { + QString elemName = QString((const char*)elem->name); + QFile file( DTD::dirName + elemName + ".tag" ); + if ( file.open( IO_WriteOnly ) ) + { + QTextStream stream( &file ); + stream.setEncoding(QTextStream::UnicodeUTF8); + stream << "" << endl; + stream << "" << endl + << "" << endl + << "" << endl << endl; + + xmlElementPtr el_ptr; /* Pointer to an element description */ + xmlAttributePtr at_ptr; + el_ptr = xmlGetDtdElementDesc(DTD::dtd_ptr, elem->name); + AttributeList attributes; + attributes.setAutoDelete(true); + if (el_ptr) + { + at_ptr = el_ptr->attributes; + while (at_ptr) { + Attribute *attr = new Attribute; + attr->name = QString((const char*)at_ptr->name); + switch (at_ptr->def) { + case 1: {attr->status = "optional"; break;} //NONE + case 2: {attr->status = "required"; break;} //REQUIRED + case 3: {attr->status = "implied"; break;} //IMPLIED + case 4: {attr->status = "fixed"; break;} //FIXED + } + attr->defaultValue = QString((const char*)at_ptr->defaultValue); + xmlEnumerationPtr enum_ptr; + enum_ptr = at_ptr->tree; + while (enum_ptr) { + attr->values += QString((const char*)enum_ptr->name); + enum_ptr = enum_ptr->next; + } + QString attrtype; + switch (at_ptr->atype) { + case 9: {attrtype = "list"; break;} + default: {attrtype = "input"; break;} //TODO handle the rest of types + } + attr->type = attrtype; + attributes.append(attr); + at_ptr = at_ptr->nexth; + } + + if (!attributes.isEmpty()) + stream << QuantaCommon::xmlFromAttributes(&attributes); + const xmlChar *list_ptr[MAX_CHILD_ELEMENTS]; + int childNum = 0; + childNum = xmlValidGetPotentialChildren(el_ptr->content, list_ptr, + &childNum, MAX_CHILD_ELEMENTS); + + if (childNum > 0) + { + stream << "" << endl; + for( int i = 0; i < childNum; i++ ) + { + stream << " content && child_ptr->content->ocur) + { + //if (child_ptr->content->ocur == XML_ELEMENT_CONTENT_PLUS) + //{ + // stream << " usage=\"required\""; + // } + QString ocur; + switch (child_ptr->content->ocur) + { + case 1: {ocur = "once"; break;} + case 2: {ocur = "opt"; break;} + case 3: {ocur = "mult"; break;} + case 4: {ocur = "plus"; break;} + } + stream << " usage=\"" << ocur << "\""; + QString name = QString((const char*)child_ptr->content->name); + if (name == "#PCDATA") + name == "#text"; + stream << " name2=\"" << name << "\""; + } + stream << " />" << endl; + } + + stream << "" << endl; + stream << endl; + } + /* + xmlElementContentPtr content_ptr = el_ptr->content; + if (content_ptr) + { + stream << "" << endl; + while (content_ptr) + { + if (!QString((const char*)content_ptr->name).isEmpty()) + { + stream << " name) << "\""; + QString ocur; + switch (content_ptr->ocur) + { + case 1: {ocur = "once"; break;} + case 2: {ocur = "opt"; break;} + case 3: {ocur = "mult"; break;} + case 4: {ocur = "plus"; break;} + } + stream << " usage=\"" << ocur << "\""; + stream << " />" << endl; + } + if (content_ptr->c1) + content_ptr = content_ptr->c1; + else if (content_ptr->c2) + content_ptr = content_ptr->c2; + else + { + if (content_ptr == el_ptr->content) + break; + if (content_ptr->parent) + { + if (content_ptr == content_ptr->parent->c1) + content_ptr->c1 = 0L; + else + content_ptr->c2 = 0L; + } + content_ptr = content_ptr->parent; + } + } + stream << "" << endl; + } */ + } + stream << "" << endl + << "" << endl; + file.close(); + } + } +} + +void saveEntity(xmlEntityPtr entity, xmlBufferPtr buf) +{ + Q_UNUSED(buf); + if (entity) + { + QString name = QString((const char*)entity->name); + DTD::entityStream << "" << endl << endl; + } +} + +QString DTDParser::dirName() +{ + return DTD::dirName; +} + diff --git a/quanta/parsers/dtd/dtdparser.h b/quanta/parsers/dtd/dtdparser.h new file mode 100644 index 00000000..b5b66d01 --- /dev/null +++ b/quanta/parsers/dtd/dtdparser.h @@ -0,0 +1,55 @@ +/*************************************************************************** + dtdparser.h - description + ------------------- + begin : Sun Oct 19 16:47:20 EEST 2003 + copyright : (C) 2003 Andras Mantia + ***************************************************************************/ + +/*************************************************************************** + * * + * 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; version 2 of the License. * + * * + ***************************************************************************/ +#ifndef DTDPARSER_H +#define DTDPARSER_H + +//qt includes +#include + +//forward declarations +class KURL; +class QString; +struct Attribute; + +/** libxml2 based XML DTD parser and DTEP creation class*/ +class DTDParser { +public: + DTDParser(const KURL& dtdURL, const QString &dtepDir); + ~DTDParser(); + QString dirName(); + /** + * Parse the DTD file. + * @param targetDir the directory of the destination DTEP. If empty, a dialog is shown to configure the destination. + * @param entitiesOnly if true, only the entities are extracted from the DTD into the entities.tag file + * @return true on success, false if some error happened + */ + bool parse(const QString &targetDir = QString::null, bool entitiesOnly = false); + +protected: + void writeDescriptionRC(); + +private: + KURL m_dtdURL; + QString m_dtepDir; + QString m_name; + QString m_nickName; + QString m_doctype; + QString m_dtdURLLine; + bool m_caseSensitive; + QString m_defaultExtension; + QDict m_tags; +}; + +#endif diff --git a/quanta/parsers/dtd/dtepcreationdlg.ui b/quanta/parsers/dtd/dtepcreationdlg.ui new file mode 100644 index 00000000..3247c7ae --- /dev/null +++ b/quanta/parsers/dtd/dtepcreationdlg.ui @@ -0,0 +1,152 @@ + +DTEPCreationDlg +/*************************************************************************** + * * + * 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; version 2 of the License. * + * * + ***************************************************************************/ + +(C) 2003 Andras Mantia <amantia@kde.org> + + + DTEPCreationDlg + + + + 0 + 0 + 500 + 285 + + + + + 500 + 200 + + + + DTD - > DTEP Conversion + + + true + + + + unnamed + + + + nickName + + + + + dtdURL + + + + + textLabel1 + + + Name: + + + + + textLabel2 + + + Nickname: + + + + + textLabel3 + + + !DOCTYPE definition line: + + + + + directory + + + + + doctype + + + + + dtdName + + + + + textLabel5 + + + DTD URL: + + + + + textLabel4 + + + Target directory name: + + + + + textLabel1_2 + + + Default extension: + + + + + defaultExtension + + + + + caseSensitive + + + Case-sensitive tags and attributes + + + true + + + + + fineTune + + + &Fine-tune the DTEP after conversion + + + true + + + + + + directory + dtdName + nickName + doctype + dtdURL + defaultExtension + caseSensitive + + + diff --git a/quanta/parsers/node.cpp b/quanta/parsers/node.cpp new file mode 100644 index 00000000..0831a67c --- /dev/null +++ b/quanta/parsers/node.cpp @@ -0,0 +1,559 @@ +/*************************************************************************** + node.cpp - description + ------------------- + begin : Sun Apr 16 2000 + copyright : (C) 2000 by Dmitry Poplavsky + (C) 2001-2003 Andras Mantia + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 +#include + +#include + +#include "node.h" +#include "tag.h" +#include "qtag.h" +#include "quantacommon.h" +#include "structtreetag.h" +#include "kafkacommon.h" + +QMap nodes; //list of all created nodes. Used to do some own memory management and avoid double deletes, for whatever reason they happen... + +int NN = 0; //for debugging purposes: count the Node objects + +GroupElementMapList globalGroupMap; + +Node::Node(Node *parent) +{ + this->parent = parent; + prev = next = child = 0L; + tag = 0L; + mainListItem = 0L; + opened = false; + removeAll = true; + closesPrevious = false; + insideSpecial = false; + _closingNode = 0L; + m_rootNode = 0L; + m_leafNode = 0L; + m_groupElements.clear(); + NN++; +// if (nodes.contains(this) == 0) + nodes[this] = 1; +// else +// { +// kdError(24000) << "A node with this address " << this << " already exists!" << endl; +// } +} + +bool Node::deleteNode(Node *node) +{ + if (!node) + return true; + if (!nodes.contains(node)) + { + kdDebug(24000) << "Trying to delete a node with address " << node << " that was not allocated!" << endl; + return false; + } + delete node; + return true; +} + +Node::~Node() +{ +// if (!nodes.contains(this)) +// { +// kdError(24000) << "No node with this address " << this << " was allocated!" << endl; +// return; +// } + + //It has no use, except to know when it crash why it has crashed. + //If it has crashed here, the Node doesn't exist anymore. + // If it has crashed the next line, it is a GroupElements bug. + //FIXME: Andras: or it is a VPL undo/redo bug... + Q_ASSERT(tag); + if (tag) + tag->setCleanStrBuilt(false); + + detachNode(); + nodes.erase(this); + if (prev && prev->next == this) + prev->next = 0L; + if (parent && parent->child == this) + parent->child = 0L; + if (removeAll) + { + deleteNode(child); + child = 0L; + deleteNode(next); + next = 0L; + } else + { + if (next && next->prev == this) + next->prev = 0L; + if (child && child->parent == this) + child->parent = 0L; + } + + delete tag; + tag = 0L; + delete m_rootNode; + delete m_leafNode; + NN--; +} + +void Node::save(QDomElement& element) const +{ + //kdDebug(25001) << "Save:\n" << element.ownerDocument().toString() << endl; + QDomElement child_element; + if(next) + { + child_element = element.ownerDocument().createElement("nodeNext"); + element.appendChild(child_element); + next->save(child_element); + } + if(child) + { + child_element = element.ownerDocument().createElement("nodeChild"); + element.appendChild(child_element); + child->save(child_element); + } + if(_closingNode) + { + if(_closingNode != next) + { + child_element = element.ownerDocument().createElement("nodeClosing"); + element.appendChild(child_element); + _closingNode->save(child_element); + } + } + + Q_ASSERT(tag); + child_element = element.ownerDocument().createElement("tag"); + element.appendChild(child_element); + tag->save(child_element); + + element.setAttribute("closesPrevious", closesPrevious); // bool + element.setAttribute("opened", opened); // bool + element.setAttribute("removeAll", removeAll); // bool + element.setAttribute("insideSpecial", insideSpecial); // bool + element.setAttribute("specialInsideXml", specialInsideXml); // bool + element.setAttribute("fileName", fileName); // QString + +/* QString s_element; + QTextStream stream(&s_element, IO_WriteOnly); + element.save(stream, 3);*/ + //kdDebug(25001) << "Load:\n" << s_element << endl; + //kdDebug(25001) << "Save:\n" << element.ownerDocument().toString() << endl; +} + +bool Node::load(QDomElement const& element) +{ +/* QString s_element; + QTextStream stream(&s_element, IO_WriteOnly); + element.save(stream, 3);*/ + //kdDebug(25001) << "Load:\n" << s_element << endl; + + QDomNodeList list = element.childNodes(); + for(unsigned int i = 0; i != list.count(); ++i) + { + if(list.item(i).isElement()) + { + QDomElement e = list.item(i).toElement(); + if(e.tagName() == "nodeNext") + { + next = new Node(0); + next->prev = this; + next->parent = this->parent; + next->load(e); + } + else if(e.tagName() == "nodeChild") + { + child = new Node(0); + child->parent = this; + child->load(e); + } + else if(e.tagName() == "nodeClosing") + { + _closingNode = new Node(0); + _closingNode->load(e); + } + else if(e.tagName() == "tag") + { + tag = new Tag(); + tag->load(e); + } + } + } + + closesPrevious = QString(element.attribute("closesPrevious")).toInt(); // bool + opened = QString(element.attribute("opened")).toInt(); // bool + removeAll = QString(element.attribute("removeAll")).toInt(); // bool + insideSpecial = QString(element.attribute("insideSpecial")).toInt(); // bool + specialInsideXml = QString(element.attribute("specialInsideXml")).toInt(); // bool + fileName = element.attribute("fileName"); // QString + + //kafkaCommon::coutTree(this, 3); + + return true; +} + +Node *Node::nextSibling() +{ + Node *result = 0L; + if (child) + { + result = child; + } + else + if (next) + { + result = next; + } + else + { + Node *n = this; + while (n) + { + if (n->parent && n->parent->next) + { + result = n->parent->next; + break; + } + else + { + n = n->parent; + } + } + } + + return result; +} + + +Node *Node::previousSibling() +{ + Node *result = 0L; + if (prev) + { + Node *n = prev; + while (n->child) + { + n = n->child; + while (n->next) + n = n->next; + } + result = n; + } + else + { + result = parent; + } + + return result; +} + +Node *Node::nextNotChild() +{ + if (next) + return next; + else + { + Node *n = this; + while (n) + { + if (n->parent && n->parent->next) + { + n = n->parent->next; + break; + } + else + { + n = n->parent; + } + } + + return n; + } +} + +QString Node::nodeName() +{ + if(tag) + return tag->name; + return QString::null; +} + +QString Node::nodeValue() +{ + if(tag) + return tag->tagStr(); + return QString::null; +} + +void Node::setNodeValue(const QString &value) +{ + if(!tag) + tag = new Tag(); + tag->setStr(value); + kdDebug(24000) << "Node::setNodeValue: dtd is 0L for " << value << endl; +} + +Node* Node::lastChild() +{ + Node *n, *m = 0; + n = child; + while(n) + { + m = n; + n = n->next; + } + return m; +} + +Node *Node::nextNE() +{ + Node *n = next; + while(n && n->tag->type == Tag::Empty) + n = n->next; + return n; +} + +Node *Node::prevNE() +{ + Node *n = prev; + while(n && n->tag->type == Tag::Empty) + n = n->prev; + return n; +} + +Node *Node::firstChildNE() +{ + Node *n = child; + while(n && n->tag->type == Tag::Empty) + n = n->next; + return n; +} + +Node *Node::lastChildNE() +{ + Node *n = lastChild(); + while(n && n->tag->type == Tag::Empty) + n = n->prev; + return n; +} + +Node *Node::SPrev() +{ + Node *node = prev; + int bCol, bLine, eCol, eLine, col, line; + + if(parent) + { + parent->tag->beginPos(bLine, bCol); + parent->tag->endPos(eLine, eCol); + } + + while(node && node->tag->type != Tag::XmlTag && node->tag->type != Tag::Text) + { + if (parent && node->tag->type == Tag::ScriptTag) + { + //Check if it is an embedded ScriptTag. If it is, continue. + node->tag->beginPos(line, col); + if(QuantaCommon::isBetween(line, col, bLine, bCol, eLine, eCol) != 0) + break; + } + node = node->prev; + } + + return node; +} + +Node *Node::SNext() +{ + Node *node = next; + int bCol, bLine, eCol, eLine, col, line; + + if(parent) + { + tag->beginPos(bLine, bCol); + tag->endPos(eLine, eCol); + } + + while(node && node->tag->type != Tag::XmlTag && node->tag->type != Tag::Text) + { + if (parent && node->tag->type == Tag::ScriptTag) + { + //Check if it is an embedded ScriptTag. If it is, continue. + node->tag->beginPos(line, col); + if(QuantaCommon::isBetween(line, col, bLine, bCol, eLine, eCol) != 0) + break; + } + node = node->next; + } + + return node; +} + +Node *Node::SFirstChild() +{ + Node *node = child; + int bCol, bLine, eCol, eLine, col, line; + + tag->beginPos(bLine, bCol); + tag->endPos(eLine, eCol); + while(node && node->tag->type != Tag::XmlTag && node->tag->type != Tag::Text) + { + if(node->tag->type == Tag::ScriptTag) + { + //Check if it is an embedded ScriptTag. If it is, continue. + node->tag->beginPos(line, col); + if(QuantaCommon::isBetween(line, col, bLine, bCol, eLine, eCol) != 0) + break; + } + node = node->next; + } + + return node; +} + +Node *Node::SLastChild() +{ + Node *node = lastChild(); + int bCol, bLine, eCol, eLine, col, line; + + tag->beginPos(bLine, bCol); + tag->endPos(eLine, eCol); + while(node && node->tag->type != Tag::XmlTag && node->tag->type != Tag::Text) + { + if(node->tag->type == Tag::ScriptTag) + { + //Check if it is an embedded ScriptTag. If it is, continue. + node->tag->beginPos(line, col); + if(QuantaCommon::isBetween(line, col, bLine, bCol, eLine, eCol) != 0) + break; + } + node = node->prev; + } + + return node; +} + +bool Node::hasForChild(Node *node) +{ + //TODO: NOT EFFICIENT AT ALL!! Change by using kafkaCommon::getLocation() and compare! + Node *n; + bool goUp = false; + + if(child) + { + n = child; + goUp = false; + while(n) + { + if(n == node) + return true; + n = kafkaCommon::getNextNode(n, goUp, this); + } + } + return false; +} + +Node *Node::getClosingNode() +{ + Node* n = next; + + if(next && tag && (tag->type == Tag::XmlTag || tag->type == Tag::ScriptTag) && !tag->single) + { + while (n && n->tag->type == Tag::Empty) + n = n->next; + if (n && n->tag->type == Tag::XmlTagEnd && ((tag->type == Tag::XmlTag && QuantaCommon::closesTag(tag, n->tag)) || (tag->type == Tag::ScriptTag && n->tag->name.isEmpty()))) + return n; + } + return 0L; +} + +Node *Node::getOpeningNode() +{ + Node *n = prev; + if(prev && tag && tag->type == Tag::XmlTagEnd) + { + while(n && n->tag->type == Tag::Empty) + n = n->prev; + if(n && ((n->tag->type == Tag::XmlTag && QuantaCommon::closesTag(n->tag, tag)) + || (n->tag->type == Tag::ScriptTag && tag->name.isEmpty()))) + return n; + } + return 0L; +} + +int Node::size() +{ + int l = tag->size(); + l += 5*sizeof(Node*) + sizeof(QListViewItem*) + 2*sizeof(Tag*) + 2*sizeof(DOM::Node); + return l; +} + +void Node::operator =(Node* node) +{ + (*this) = (*node); + prev = 0L; + next = 0L; + parent = 0L; + child = 0L; + mainListItem = 0L; + m_groupElements.clear(); + setRootNode(0L); + setLeafNode(0L); + tag = new Tag(*(node->tag)); +} + +void Node::detachNode() +{ + if (nodes.contains(this) == 0) + { + kdError(24000) << "No node with this address " << this << " was allocated!" << endl; + return; + } + + int count = 0; + //kdDebug(24000) << &m_groupElements << " " << this << endl; + //Remove the references to this node from the list of group elements. + //They are actually stored in globalGroupMap. + for (QValueListIterator it = m_groupElements.begin(); it != m_groupElements.end(); ++it) + { + GroupElement *groupElement = (*it); + groupElement->node = 0L; + groupElement->deleted = true; + groupElement->group = 0L; +#ifdef DEBUG_PARSER + kdDebug(24001) << "GroupElement scheduled for deletion: " << groupElement << " "<< groupElement->tag->area().bLine << " " << groupElement->tag->area().bCol << " "<< groupElement->tag->area().eLine << " "<< groupElement->tag->area().eCol << " " << groupElement->tag->tagStr() << " " << groupElement->type << endl; +#endif + count++; + } +#ifdef DEBUG_PARSER + if (count > 0) + kdDebug(24001) << count << " GroupElement scheduled for deletion. " << &m_groupElements << endl; +#endif + + QValueListIterator listItem; + for ( listItem = listItems.begin(); listItem != listItems.end(); ++listItem) + { + static_cast(*listItem)->node = 0L; + static_cast(*listItem)->groupTag = 0L; + } + mainListItem = 0L; + listItems.clear(); + m_groupElements.clear(); + //kdDebug(24000) << m_groupElements.count() << " " << this << endl; +} diff --git a/quanta/parsers/node.h b/quanta/parsers/node.h new file mode 100644 index 00000000..e3587c05 --- /dev/null +++ b/quanta/parsers/node.h @@ -0,0 +1,185 @@ +/*************************************************************************** + node.h - description + ------------------- + begin : Sun Apr 16 2000 + copyright : (C) 2000 by Dmitry Poplavsky + (C) 2001-2004 Andras Mantia + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef NODE_H +#define NODE_H + +#include +#include +#include +#include + +class QDomElement; +class QListViewItem; + +class Tag; +class Node; +class StructTreeGroup; +class XMLStructGroup; + +struct GroupElement{ + /*The node which contains the element */ + Node *node; + /* The tag which point to the actual place in the node */ + Tag *tag; + /*The parent node indicating the beginning of a structure */ + Node *parentNode; + bool global; + bool deleted; + QString type; + XMLStructGroup *group; /// GroupElementList; +typedef QMap GroupElementMapList; + +/** + * A Node is a basic unit of a Tree. It keeps track of his parent, his left neighbour, his right neighbour + * and his first child. + * It contains some functions to navigate through the tree, but some more are located at kafkacommon.h + * (and should be moved here...) + * It also contains a pointer to a Tag object which contains informations about the contents of the Node. + * We use this class to represent the XML/SGML document as a tree ( a DOM like tree) when each Node represent + * a part of the document ( A tag, a text, ... see tag.h) + * The tree is built with the parser (see parser.h) + */ + +class Node { + +public: + Node( Node *parent ); + ~Node(); + + /** + * Deletes the node. Use this instead of delete node; as it checkes if there + * node was really allocated or not and avoid nasty crashes. + * @return true - if node existed and is deleted + * false - if the node did not exist + */ + static bool deleteNode(Node *node); + + /** + * Copy everything from node except prev, next, child, parent, listItem, group, groupTag, which are set to Null + * The groupElementsList is cleared. + */ + void operator =(Node* node); + + /** For Kafka copy/paste */ + void save(QDomElement& element) const; + bool load(QDomElement const& element); + + Node *next; + Node *prev; + Node *parent; + Node *child; + + /** Returns the child if available, else the next node, else the next node of the first parent which has one, else 0L. + WARNING: it doesn't behave like DOM::Node::nextSibling() which give the next Node, or 0L if there is no next Node */ + Node *nextSibling(); + Node *previousSibling(); + /** Returns the next node, or the parent's next, if next doesn't exists, + or the granparent's next, if parent's next doesn't exists, etc. */ + Node *nextNotChild(); + +/** DOM like functions cf dom/dom_node.h */ + QString nodeName(); + QString nodeValue(); + void setNodeValue(const QString &value); + Node* parentNode() {return parent;} + Node* firstChild() {return child;} + Node* lastChild(); + Node* DOMpreviousSibling() {return prev;} + Node* DOMnextSibling() {return next;} + /**Node* insertBefore(Node *newChild, Node *refChild); + Node* replaceChild(Node *newChild, Node *oldChild); + Node* removeChild(Node *oldChild); + Node* appendChild(Node *newChild);*/ + bool hasChildNodes() {return child;} + + /** Others functions. */ + // check if Node has node in its child subtree (and grand-child,...) + bool hasForChild(Node *node); + void setParent(Node *nodeParent) {parent = nodeParent;} + //If Node is of type XmlTag or ScriptTag, return the corresponding XmlTagEnd if available + Node *getClosingNode(); + //If Node is of type XmlTagEnd, return the corresponding XmlTag or ScriptTag if available + Node *getOpeningNode(); + + /** The Node link skipping Empty Nodes. */ + //Returns the first next non-Empty Node + Node *nextNE(); + //Returns the first prev non-Empty Node + Node *prevNE(); + //Returns the first non-Empty child + Node *firstChildNE(); + //Returns the last non-Empty child + Node *lastChildNE(); + +/** + * The main problem manipulating the default links prev/next/parent/child is that we often want + * to manipulate only the "significant" Nodes e.g. XmlTag, Text, ScriptNode, like in a DOM::Node tree. + * These functions, prefixed with "S" which stands for "simplified" or "significant", will only return + * and manipulate XmlTag, Text and ScriptNode. + */ + //Returns the first significant previous sibling. + Node *SPrev(); + //Returns the first significant next sibling. + Node *SNext(); + //Returns the first significant child. + Node *SFirstChild(); + //Returns the last significant child. + Node *SLastChild(); + void detachNode(); + + + + int size(); + +//set/get the corresponding DOM::Node of this node. +//See more informations about rootNode/leafNode below. + DOM::Node* rootNode() {return m_rootNode;} + DOM::Node* leafNode() { return m_leafNode;} + void setRootNode(DOM::Node *rootNode) {m_rootNode = rootNode;} + void setLeafNode(DOM::Node *leafNode) {m_leafNode = leafNode;} + Node* _closingNode; + + /** + * The contents of the Node is inside the Tag. Should _never_ be null. + */ + Tag *tag; + + QValueList listItems; /// + QString fileName; //the node is in this file. If empty, it's in the current document + QValueList m_groupElements; ///< all the group elements pointing to this node + +private: + /** + * For VPL use. + * Usually for a XmlTag or Text Node there is one corresponding DOM::Node. But sdmetimes there are more + * e.g. in the DOM::Node tree the TABLE DOM::Node require the TBODY DOM::Node even if not necessary according + * to the specs. So m_rootNode points to the TABLE DOM::Node and m_leafNode points to the TBODY DOM::Node. + */ + DOM::Node *m_rootNode, *m_leafNode; +}; + +#endif diff --git a/quanta/parsers/parser.cpp b/quanta/parsers/parser.cpp new file mode 100644 index 00000000..7559f1ec --- /dev/null +++ b/quanta/parsers/parser.cpp @@ -0,0 +1,1757 @@ +/*************************************************************************** + parser.cpp - description + ------------------- + begin : Sun Sep 1 2002 + copyright : (C) 2002, 2003 by Andras Mantia + ***************************************************************************/ + +/*************************************************************************** + * * + * 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; version 2 of the License. * + * * + ***************************************************************************/ + +//qt includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//standard library includes +#include +#include +//#include + +//app includes +#include "parser.h" +#include "saparser.h" +#include "parsercommon.h" +#include "node.h" +#include "tag.h" +#include "resource.h" +#include "quantaview.h" +#include "quantacommon.h" +#include "document.h" +#include "qextfileinfo.h" + + +#include "kafkacommon.h" +#include "undoredo.h" + +#include "dtds.h" +#include "structtreetag.h" + +#include "viewmanager.h" + +//kde includes +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern GroupElementMapList globalGroupMap; +static const QChar space(' '); + +extern int NN; +extern QMap nodes; + +Parser::Parser() +{ + m_node = 0L; + write = 0L; + oldMaxLines = 0; + m_parsingEnabled = true; + m_parsingNeeded = true; + m_parseIncludedFiles = true; + m_saParser = new SAParser(); + connect(m_saParser, SIGNAL(rebuildStructureTree(bool)), SIGNAL(rebuildStructureTree(bool))); + connect(m_saParser, SIGNAL(cleanGroups()), SLOT(cleanGroups())); + ParserCommon::includeWatch = new KDirWatch(); + connect(ParserCommon::includeWatch, SIGNAL(dirty(const QString&)), SLOT(slotIncludedFileChanged(const QString&))); +} + +Parser::~Parser() +{ + delete m_saParser; +} + +/** Parse a string, using as start position sLine, sCol. */ +Node *Parser::parseArea(int startLine, int startCol, int endLine, int endCol, Node **lastNode, Node *a_node) +{ + //first parse as an XML document + QString textLine; + textLine.fill(space, startCol); + int line = startLine; + int col = 0; + int tagStartLine = 0; + int tagEndLine, tagEndCol; + int tagStartPos, specialStartPos; + int lastLineLength; + // if (endCol == 0) + if (endLine > maxLines) + { + if (endLine > 0) + endLine--; + lastLineLength = write->editIf->lineLength(endLine) - 1; + endCol = lastLineLength + 1; + } else + lastLineLength = write->editIf->lineLength(endLine) - 1; + int specialAreaCount = m_dtd->specialAreas.count(); + bool nodeFound = false; + bool goUp; + Node *rootNode = 0L; + Node *parentNode = a_node; + Node *currentNode = a_node; + if (currentNode && (currentNode->tag->type != Tag::XmlTag || + currentNode->tag->single)) + parentNode = currentNode->parent; + Tag *tag = 0L; + QTag *qTag = 0L; + textLine.append(write->text(startLine, startCol, startLine, write->editIf->lineLength(startLine))); + if (line == endLine) + { + if (endCol > 0) + textLine.truncate(endCol + 1); + else + textLine = ""; + } + if (m_dtd->family == Xml) + { + while (line <= endLine) + { + nodeFound = false; + goUp = false; + //find the first "<" and the first special area start definition in this line + tagStartPos = textLine.find('<', col); + specialStartPos = specialAreaCount ? textLine.find(m_dtd->specialAreaStartRx, col): -1; + //if the special area start definition is before the first "<" it means + //that we have found a special area + if ( specialStartPos != -1 && + (specialStartPos <= tagStartPos || tagStartPos == -1) ) + { + currentNode = ParserCommon::createTextNode(write, currentNode, line, specialStartPos, parentNode); + if (!rootNode) + rootNode = currentNode; + QString foundText = m_dtd->specialAreaStartRx.cap(); + //create a toplevel node for the special area + AreaStruct area(line, specialStartPos, line, specialStartPos + foundText.length() - 1); + Node *node = ParserCommon::createScriptTagNode(write, area, foundText, m_dtd, parentNode, currentNode); + if (node->parent && node->prev == node->parent) //some strange cases, but it's possible, eg.: + { + node->prev->next = 0L; + node->prev = 0L; + } + if (node->tag->name.lower().startsWith("comment")) + node->tag->type = Tag::Comment; + + if (!rootNode) + rootNode = node; + + area.eLine = endLine; + area.eCol = endCol; + currentNode = m_saParser->parseArea(area, foundText, "", node, false, true); + line = m_saParser->lastParsedLine(); + textLine = ParserCommon::getLine(write, line, endLine, endCol); + col = m_saParser->lastParsedColumn() + 1; + continue; + } else + //if we have found an XML tag start ("<") + if ( tagStartPos != -1 /*&& + (tagStartPos < specialStartPos || specialStartPos == -1) */) + { + int openNum = 1; + tagStartLine = line; + tagEndLine = endLine; + tagEndCol = lastLineLength; + int sCol = tagStartPos + 1; + int firstStartCol = lastLineLength + 1; + int firstStartLine = endLine; + bool firstOpenFound = false; + bool insideSingleQuotes = false; + bool insideDoubleQuotes = false; + //find the matching ">" in the document + while (line <= endLine && openNum > 0 && !firstOpenFound) + { + textLine = ParserCommon::getLine(write, line, endLine, endCol); + uint textLineLen = textLine.length(); + for (uint i = sCol; i < textLineLen; i++) + { + if (i == 0 || (i > 0 && textLine[i-1] != '\\')) + { + if (textLine[i] == '\'' && !insideDoubleQuotes) + insideSingleQuotes = !insideSingleQuotes; + if (textLine[i] == '"' && !insideSingleQuotes) + insideDoubleQuotes = !insideDoubleQuotes; + } + if (!insideSingleQuotes && !insideDoubleQuotes) + { + if (textLine[i] == '<') + { + openNum++; + if (!firstOpenFound && + (i < textLineLen -1 && (textLine[i + 1] == '/' || textLine[i + 1].isLetter()) || + i == textLineLen -1) + ) + { + firstStartCol = i; + firstStartLine = line; + firstOpenFound = true; + break; + } + } else + if (textLine[i] == '>') openNum--; + } + if (openNum == 0) + { + tagEndCol = i; + tagEndLine = line; + break; + } + } + sCol = 0; + if (openNum != 0) + line++; + } + //the matching closing tag was not found + if (openNum != 0) + { + tagEndLine = firstStartLine; + tagEndCol = firstStartCol - 1; + if (tagEndCol < 0) + { + tagEndLine--; + if (tagEndLine < 0) + tagEndLine = 0; + tagEndCol = write->editIf->lineLength(tagEndLine); + } + line = tagEndLine; + textLine = ParserCommon::getLine(write, line, endLine, endCol); + } + col = tagEndCol; + nodeFound = true; + //build an xml tag node here + AreaStruct area(tagStartLine, tagStartPos, tagEndLine, tagEndCol); + tag = new Tag(area, write, m_dtd, true); + QString tagStr = tag->tagStr(); + tag->type = Tag::XmlTag; + tag->validXMLTag = (openNum == 0); + tag->single = QuantaCommon::isSingleTag(m_dtd->name, tag->name); + if (tag->isClosingTag()) + { + tag->type = Tag::XmlTagEnd; + tag->single = true; + } + if (tagStr.right(2) == "/>" || tag->name.isEmpty()) + { + tag->single = true; + if (tag->name.length() > 1 && tag->name.endsWith("/")) + tag->name.truncate(tag->name.length() - 1); + } + //the tag we found indicates the beginning of a special area, like