You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
353 lines
11 KiB
353 lines
11 KiB
9 years ago
|
/***************************************************************************
|
||
|
qdom_add.cpp - description
|
||
|
-------------------
|
||
|
begin : Wed Nov 21 2001
|
||
|
copyright : (C) 2001, 2002, 2003 by The KXMLEditor Team
|
||
|
email : lvanek@users.sourceforge.net
|
||
|
***************************************************************************/
|
||
|
|
||
|
/***************************************************************************
|
||
|
* *
|
||
|
* 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. *
|
||
|
* *
|
||
|
***************************************************************************/
|
||
|
|
||
|
/** This file contains useful datatypes and functions in addition to the Qt DOM classes. */
|
||
|
|
||
|
#include "qdom_add.h"
|
||
|
|
||
|
#include <kiconloader.h>
|
||
|
#include <kdebug.h>
|
||
|
|
||
|
#include <qtextstream.h>
|
||
|
|
||
|
#include "kxmleditorfactory.h"
|
||
|
#include "kxesearchdialog.h"
|
||
|
|
||
|
QPixmap g_iconElement( UserIcon("xml_element",KXMLEditorFactory::instance()) );
|
||
|
QPixmap g_iconText( UserIcon("xml_text",KXMLEditorFactory::instance()) );
|
||
|
QPixmap g_iconComment( UserIcon("xml_comment",KXMLEditorFactory::instance()) );
|
||
|
QPixmap g_iconCDATASection( UserIcon("xml_cdata",KXMLEditorFactory::instance()) );
|
||
|
QPixmap g_iconProcessingInstruction( UserIcon("xml_procinstr",KXMLEditorFactory::instance()) );
|
||
|
QPixmap g_iconElement_b( UserIcon("xml_element_b",KXMLEditorFactory::instance()) );
|
||
|
QPixmap g_iconText_b( UserIcon("xml_text_b",KXMLEditorFactory::instance()) );
|
||
|
QPixmap g_iconComment_b( UserIcon("xml_comment_b",KXMLEditorFactory::instance()) );
|
||
|
QPixmap g_iconCDATASection_b( UserIcon("xml_cdata_b",KXMLEditorFactory::instance()) );
|
||
|
QPixmap g_iconProcessingInstruction_b( UserIcon("xml_procinstr_b",KXMLEditorFactory::instance()) );
|
||
|
QPixmap g_iconUnknown;
|
||
|
|
||
|
const QPixmap & domTool_getIconForNodeType( QDomNode::NodeType type, bool bBookmarked )
|
||
|
{
|
||
|
if(!bBookmarked)
|
||
|
{ switch(type)
|
||
|
{ case QDomNode::ElementNode: return g_iconElement; break;
|
||
|
case QDomNode::TextNode: return g_iconText; break;
|
||
|
case QDomNode::CDATASectionNode: return g_iconCDATASection; break;
|
||
|
case QDomNode::CommentNode: return g_iconComment; break;
|
||
|
case QDomNode::ProcessingInstructionNode: return g_iconProcessingInstruction; break;
|
||
|
|
||
|
default:
|
||
|
kdDebug() << "domTool_getIconForNodeType: unknown node type (" << type << ")" << endl;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{ switch(type)
|
||
|
{ case QDomNode::ElementNode: return g_iconElement_b; break;
|
||
|
case QDomNode::TextNode: return g_iconText_b; break;
|
||
|
case QDomNode::CDATASectionNode: return g_iconCDATASection_b; break;
|
||
|
case QDomNode::CommentNode: return g_iconComment_b; break;
|
||
|
case QDomNode::ProcessingInstructionNode: return g_iconProcessingInstruction_b; break;
|
||
|
|
||
|
default:
|
||
|
kdDebug() << "domTool_getIconForNodeType: unknown node type (" << type << ")" << endl;
|
||
|
}
|
||
|
}
|
||
|
return g_iconUnknown;
|
||
|
}
|
||
|
|
||
|
// Obtain XPath for all nodes, instead of elements
|
||
|
QString domTool_getPath( const QDomNode & node )
|
||
|
{
|
||
|
if ( node.isNull() )
|
||
|
{
|
||
|
kdDebug() << "domTool_getPath: elelent given" << endl;
|
||
|
return QString();
|
||
|
}
|
||
|
|
||
|
if(node.isElement())
|
||
|
{
|
||
|
kdDebug() << "use domTool_getPath( const QDomElement & domElement ) for elements" << endl;
|
||
|
}
|
||
|
|
||
|
QString strReturn;
|
||
|
|
||
|
QDomNode parentNode = node.parentNode();
|
||
|
if ( (!parentNode.isNull()) && (!parentNode.isDocument()) )
|
||
|
{
|
||
|
strReturn = domTool_getPath( parentNode.toElement() ); // get the parent's path
|
||
|
strReturn += "/"; // append slash
|
||
|
strReturn += node.nodeName(); // append the given node's name
|
||
|
}
|
||
|
else
|
||
|
strReturn = node.nodeName(); // set the given node's name (must be root element)
|
||
|
|
||
|
return strReturn;
|
||
|
}
|
||
|
|
||
|
// Obtain XPath for elements
|
||
|
QString domTool_getPath( const QDomElement & domElement )
|
||
|
{
|
||
|
if ( domElement.isNull() )
|
||
|
{
|
||
|
kdDebug() << "domTool_getPath: no node given" << endl;
|
||
|
return QString();
|
||
|
}
|
||
|
|
||
|
QString strReturn;
|
||
|
QDomNode parentNode = domElement.parentNode();
|
||
|
if ( (!parentNode.isNull()) && (!parentNode.isDocument()) )
|
||
|
{
|
||
|
// calculate index - only for elements with the same name
|
||
|
int i = 0;
|
||
|
bool bUseIndex = false; // index is used only when exist sibling(s) with the same name
|
||
|
|
||
|
// traverse previous sibling elements with same name and calculate index
|
||
|
QDomNode tmpNode = domElement.previousSibling();
|
||
|
while ( ! tmpNode.isNull() )
|
||
|
{
|
||
|
if(tmpNode.isElement())
|
||
|
{
|
||
|
QDomElement domSiblingElement = tmpNode.toElement();
|
||
|
|
||
|
if(domElement.tagName() == domSiblingElement.tagName())
|
||
|
{ i++; bUseIndex = true;
|
||
|
}
|
||
|
}
|
||
|
tmpNode = tmpNode.previousSibling();
|
||
|
}
|
||
|
|
||
|
if(bUseIndex == false)
|
||
|
{
|
||
|
// traverse next sibling elements with same name
|
||
|
// and decide, if index is necessary
|
||
|
QDomNode tmpNode = domElement.nextSibling();
|
||
|
while ( ! tmpNode.isNull() )
|
||
|
{
|
||
|
if(tmpNode.isElement())
|
||
|
{
|
||
|
QDomElement domSiblingElement = tmpNode.toElement();
|
||
|
|
||
|
if(domElement.tagName() == domSiblingElement.tagName())
|
||
|
bUseIndex = true;
|
||
|
}
|
||
|
|
||
|
tmpNode = tmpNode.nextSibling();
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
strReturn = domTool_getPath( parentNode.toElement() ); // get the parent's path
|
||
|
strReturn += "/"; // append slash
|
||
|
strReturn += domElement.nodeName(); // append the given node's name
|
||
|
|
||
|
if(bUseIndex)
|
||
|
{
|
||
|
QString strIndex;
|
||
|
strIndex.setNum(i+1);
|
||
|
strReturn += "[" + strIndex + "]"; // append the index
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
strReturn = domElement.nodeName(); // set the given node's name (must be root element)
|
||
|
|
||
|
return strReturn;
|
||
|
}
|
||
|
|
||
|
unsigned int domTool_getLevel( const QDomNode & node )
|
||
|
{
|
||
|
if ( node.isNull() )
|
||
|
{
|
||
|
kdDebug() << "domTool_getLevel: internal implementation error - the given node is an empty one" << endl;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
unsigned int iLevel = 0;
|
||
|
QDomNode parentNode = node.parentNode();
|
||
|
while ( ! parentNode.isNull() )
|
||
|
{
|
||
|
iLevel++;
|
||
|
parentNode = parentNode.parentNode();
|
||
|
}
|
||
|
|
||
|
return iLevel - 1;
|
||
|
}
|
||
|
|
||
|
QString domTool_save( const QDomNode & node, int iIndent )
|
||
|
{
|
||
|
QString strXML;
|
||
|
QTextStream ts( & strXML, IO_WriteOnly );
|
||
|
|
||
|
node.save(ts, iIndent);
|
||
|
return strXML;
|
||
|
}
|
||
|
|
||
|
QDomNode domTool_prevNode( const QDomNode & node )
|
||
|
{
|
||
|
if ( node.isNull() )
|
||
|
{
|
||
|
kdDebug() << "domTool_prevNode: internal implementation error - the given node is an empty one" << endl;
|
||
|
return QDomNode();
|
||
|
}
|
||
|
|
||
|
if ( ! node.previousSibling().isNull() ) // if there is a prev. sibling
|
||
|
{ // return its last grand child (if there is any)
|
||
|
QDomNode prevNode = node.previousSibling();
|
||
|
while ( ! prevNode.lastChild().isNull() )
|
||
|
prevNode = prevNode.lastChild();
|
||
|
return prevNode;
|
||
|
}
|
||
|
else // if there is no prev. sibling, return
|
||
|
return node.parentNode(); // the nodes parent (if there is any)
|
||
|
|
||
|
}
|
||
|
|
||
|
QDomNode domTool_nextNode( const QDomNode & node )
|
||
|
{
|
||
|
if ( node.isNull() )
|
||
|
{
|
||
|
kdDebug() << "domTool_nextNode: internal implementation error - the given node is an empty one" << endl;
|
||
|
return QDomNode();
|
||
|
}
|
||
|
|
||
|
// checking for a child
|
||
|
if ( ! node.firstChild().isNull() )
|
||
|
return node.firstChild();
|
||
|
|
||
|
// there is no child -> checking for the next sibling
|
||
|
if ( ! node.nextSibling().isNull() )
|
||
|
return node.nextSibling();
|
||
|
|
||
|
// there is no next sibling -> checking for parents' next sibling(s)
|
||
|
QDomNode nodeParent = node.parentNode();
|
||
|
while ( ! nodeParent.isNull() )
|
||
|
{
|
||
|
if ( ! nodeParent.nextSibling().isNull() )
|
||
|
return nodeParent.nextSibling();
|
||
|
|
||
|
nodeParent = nodeParent.parentNode(); // parent has no sibling - try its parent
|
||
|
}
|
||
|
|
||
|
// parent has no parents anymore
|
||
|
return QDomNode(); // return empty node
|
||
|
}
|
||
|
|
||
|
QDomNode domTool_matchingNode( const QDomNode & node, const QString & szPath )
|
||
|
{
|
||
|
if(szPath.length() == 0)
|
||
|
return QDomNode(); // return void node
|
||
|
|
||
|
QString szNodePath = node.isDocument() ? QString("") : domTool_getPath(node);
|
||
|
if ( szPath == szNodePath ) // test if the strings match
|
||
|
return node;
|
||
|
|
||
|
/* L.V. those optimalizations disallow find proc. instr. at doc. level
|
||
|
|
||
|
// we will find any node in root element subtree
|
||
|
if ( szPath.length() <= szNodePath.length() ) // the given string must be longer
|
||
|
return QDomNode(); // otherwise we don't need to check the childs
|
||
|
|
||
|
if ( szPath.left(szNodePath.length()) != szNodePath ) // the nodes path must be left part of the given path
|
||
|
return QDomNode(); // otherwise we don't need to check the childs
|
||
|
*/
|
||
|
|
||
|
// recursively check the childs
|
||
|
QDomNode nodeChild = node.firstChild();
|
||
|
QDomNode nodeTmp;
|
||
|
while ( ! nodeChild.isNull() )
|
||
|
{
|
||
|
nodeTmp = domTool_matchingNode( nodeChild, szPath );
|
||
|
if ( ! nodeTmp.isNull() )
|
||
|
return nodeTmp;
|
||
|
nodeChild = nodeChild.nextSibling();
|
||
|
}
|
||
|
|
||
|
return QDomNode(); // nothing found -> return empty node
|
||
|
}
|
||
|
|
||
|
bool domTool_match( QDomNode node, const KXESearchDialog * const pConditions )
|
||
|
{
|
||
|
if ( node.isNull() )
|
||
|
{
|
||
|
kdDebug() << "domTool_match: internal implementation error - the given node is an empty one" << endl;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if ( ! pConditions )
|
||
|
{
|
||
|
kdDebug() << "domTool_match: internal implementation error - the given pointer is a null pointer" << endl;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
switch ( node.nodeType() )
|
||
|
{
|
||
|
case QDomNode::ElementNode: // ----------------------------------------
|
||
|
{
|
||
|
if ( pConditions->getInElementNames() )
|
||
|
{
|
||
|
if ( node.toElement().tagName().find( pConditions->getSearchString(), 0, pConditions->getMatchCase() ) >= 0 )
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if ( ( pConditions->getInAttributeNames() ) || ( pConditions->getInAttributeValues() ) )
|
||
|
{
|
||
|
QDomNamedNodeMap list = node.toElement().attributes();
|
||
|
unsigned int iLength = list.length();
|
||
|
if ( iLength <= 0 )
|
||
|
return false; // no attributes
|
||
|
|
||
|
for ( unsigned int iRow = 0; iRow < iLength; iRow++ )
|
||
|
{
|
||
|
if ( pConditions->getInAttributeNames() )
|
||
|
if ( list.item(iRow).toAttr().name().find( pConditions->getSearchString(), 0, pConditions->getMatchCase() ) >= 0 )
|
||
|
return true;
|
||
|
if ( pConditions->getInAttributeValues() )
|
||
|
if ( list.item(iRow).toAttr().value().find( pConditions->getSearchString(), 0, pConditions->getMatchCase() ) >= 0 )
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case QDomNode::TextNode: // ----------------------------------------
|
||
|
case QDomNode::CDATASectionNode:
|
||
|
case QDomNode::CommentNode:
|
||
|
{
|
||
|
if ( pConditions->getInContents() )
|
||
|
{
|
||
|
if ( node.toCharacterData().data().find( pConditions->getSearchString(), 0, pConditions->getMatchCase() ) >= 0 )
|
||
|
return true;
|
||
|
else
|
||
|
return false;
|
||
|
}
|
||
|
else
|
||
|
return false;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// TODO implement this for the other node types (eg proc.instr.)
|
||
|
|
||
|
default:
|
||
|
kdDebug() << "domTool_match: unknown node type (" << node.nodeType() << ")" << endl;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|