summaryrefslogtreecommitdiffstats
path: root/kpovmodeler/pminsertrulesystem.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kpovmodeler/pminsertrulesystem.cpp')
-rw-r--r--kpovmodeler/pminsertrulesystem.cpp1061
1 files changed, 1061 insertions, 0 deletions
diff --git a/kpovmodeler/pminsertrulesystem.cpp b/kpovmodeler/pminsertrulesystem.cpp
new file mode 100644
index 00000000..0e7b7be2
--- /dev/null
+++ b/kpovmodeler/pminsertrulesystem.cpp
@@ -0,0 +1,1061 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002-2003 by Andreas Zehender
+**************************************************************************
+
+**************************************************************************
+* *
+* 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 "pminsertrulesystem.h"
+#include "pmprototypemanager.h"
+#include "pmpart.h"
+#include "pmvariant.h"
+#include "pmdebug.h"
+
+#include <qfile.h>
+#include <kstandarddirs.h>
+
+bool isCategory( QDomElement& e )
+{
+ return( e.tagName( ) == "class" || e.tagName( ) == "group" );
+}
+
+PMRuleCategory* newCategory( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+{
+ if( e.tagName( ) == "class" )
+ return new PMRuleClass( e );
+ if( e.tagName( ) == "group" )
+ return new PMRuleGroup( e, globalGroups, localGroups );
+ return 0;
+}
+
+PMPrototypeManager* PMRuleClass::s_pPrototypeManager = 0;
+
+PMRuleClass::PMRuleClass( QDomElement& e )
+ : PMRuleCategory( )
+{
+ m_pPrototypeManager = s_pPrototypeManager;
+ m_className = e.attribute( "name" );
+ if( m_className.isEmpty( ) )
+ kdError( PMArea ) << "RuleSystem: Invalid class name" << endl;
+ if( !m_pPrototypeManager->existsClass( m_className ) )
+ kdError( PMArea ) << "RuleSystem: Unknown class: "
+ << m_className << endl;
+}
+
+bool PMRuleClass::matches( const QString& className )
+{
+ return m_pPrototypeManager->isA( className, m_className );
+}
+
+PMRuleGroup::PMRuleGroup( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleCategory( )
+{
+ m_pGroup = 0;
+ QString groupName = e.attribute( "name" );
+ if( groupName.isEmpty( ) )
+ kdError( PMArea ) << "RuleSystem: Invalid group name" << endl;
+ // find group
+ QPtrListIterator<PMRuleDefineGroup> lit( localGroups );
+ for( ; lit.current( ) && !m_pGroup; ++lit )
+ if( lit.current( )->name( ) == groupName )
+ m_pGroup = lit.current( );
+ QPtrListIterator<PMRuleDefineGroup> git( globalGroups );
+ for( ; git.current( ) && !m_pGroup; ++git )
+ if( git.current( )->name( ) == groupName )
+ m_pGroup = git.current( );
+ if( !m_pGroup )
+ kdError( PMArea ) << "RuleSystem: Group not defined: "
+ << groupName << endl;
+}
+
+bool PMRuleGroup::matches( const QString& className )
+{
+ if( m_pGroup )
+ return m_pGroup->matches( className );
+ return false;
+}
+
+PMRuleDefineGroup::PMRuleDefineGroup( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+{
+ m_name = e.attribute( "name" );
+ if( m_name.isEmpty( ) )
+ kdError( PMArea ) << "RuleSystem: Invalid group name" << endl;
+
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ if( isCategory( me ) )
+ m_categories.append( newCategory( me, globalGroups, localGroups ) );
+ }
+ m = m.nextSibling( );
+ }
+}
+
+PMRuleDefineGroup::~PMRuleDefineGroup( )
+{
+ m_categories.setAutoDelete( true );
+ m_categories.clear( );
+}
+
+bool PMRuleDefineGroup::matches( const QString& className )
+{
+ bool m = false;
+ QPtrListIterator<PMRuleCategory> it( m_categories );
+ for( ; it.current( ) && !m; ++it )
+ m = it.current( )->matches( className );
+ return m;
+}
+
+
+bool isValue( QDomElement& e )
+{
+ return( e.tagName( ) == "property" || e.tagName( ) == "const" ||
+ e.tagName( ) == "count" );
+}
+
+bool isCondition( QDomElement& e )
+{
+ return( e.tagName( ) == "not" || e.tagName( ) == "and" ||
+ e.tagName( ) == "or" || e.tagName( ) == "before" ||
+ e.tagName( ) == "after" || e.tagName( ) == "contains" ||
+ e.tagName( ) == "greater" || e.tagName( ) == "less" ||
+ e.tagName( ) == "equal" );
+}
+
+PMRuleValue* newValue( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+{
+ if( e.tagName( ) == "property" )
+ return new PMRuleProperty( e );
+ if( e.tagName( ) == "const" )
+ return new PMRuleConstant( e );
+ if( e.tagName( ) == "count" )
+ return new PMRuleCount( e, globalGroups, localGroups );
+ return 0;
+}
+
+PMRuleCondition* newCondition( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+{
+ if( e.tagName( ) == "not" )
+ return new PMRuleNot( e, globalGroups, localGroups );
+ if( e.tagName( ) == "and" )
+ return new PMRuleAnd( e, globalGroups, localGroups );
+ if( e.tagName( ) == "or" )
+ return new PMRuleOr( e, globalGroups, localGroups );
+ if( e.tagName( ) == "before" )
+ return new PMRuleBefore( e, globalGroups, localGroups );
+ if( e.tagName( ) == "after" )
+ return new PMRuleAfter( e, globalGroups, localGroups );
+ if( e.tagName( ) == "contains" )
+ return new PMRuleContains( e, globalGroups, localGroups );
+ if( e.tagName( ) == "greater" )
+ return new PMRuleGreater( e, globalGroups, localGroups );
+ if( e.tagName( ) == "less" )
+ return new PMRuleLess( e, globalGroups, localGroups );
+ if( e.tagName( ) == "equal" )
+ return new PMRuleEqual( e, globalGroups, localGroups );
+ return 0;
+}
+
+PMRuleBase::~PMRuleBase( )
+{
+ m_children.setAutoDelete( true );
+ m_children.clear( );
+}
+
+void PMRuleBase::countChild( const QString& className, bool afterInsertPoint )
+{
+ countChildProtected( className, afterInsertPoint );
+
+ QPtrListIterator<PMRuleBase> it( m_children );
+ for( ; it.current( ); ++it )
+ it.current( )->countChild( className, afterInsertPoint );
+}
+
+void PMRuleBase::reset( )
+{
+ resetProtected( );
+
+ QPtrListIterator<PMRuleBase> it( m_children );
+ for( ; it.current( ); ++it )
+ it.current( )->reset( );
+}
+
+PMRuleProperty::PMRuleProperty( QDomElement& e )
+ : PMRuleValue( )
+{
+ m_property = e.attribute( "name" );
+ if( m_property.isNull( ) )
+ kdError( PMArea ) << "RuleSystem: Invalid property name" << endl;
+}
+
+PMVariant PMRuleProperty::evaluate( const PMObject* o )
+{
+ PMVariant v = o->property( m_property );
+ if( v.isNull( ) )
+ kdError( PMArea ) << "RuleSystem: Invalid property name: "
+ << m_property << endl;
+ return v;
+}
+
+
+PMRuleConstant::PMRuleConstant( QDomElement& e )
+ : PMRuleValue( )
+{
+ QString v = e.attribute( "value" );
+ if( v.isNull( ) )
+ kdError( PMArea ) << "RuleSystem: Invalid value" << endl;
+
+ m_value = PMVariant( v );
+}
+
+PMVariant PMRuleConstant::evaluate( const PMObject* )
+{
+ return m_value;
+}
+
+bool PMRuleConstant::convertTo( PMVariant::PMVariantDataType type )
+{
+ return m_value.convertTo( type );
+}
+
+
+PMRuleCount::PMRuleCount( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleValue( )
+{
+ m_number = 0;
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ if( isCategory( me ) )
+ m_categories.append( newCategory( me, globalGroups, localGroups ) );
+ }
+ m = m.nextSibling( );
+ }
+}
+
+PMRuleCount::~PMRuleCount( )
+{
+ m_categories.setAutoDelete( true );
+ m_categories.clear( );
+}
+
+PMVariant PMRuleCount::evaluate( const PMObject* )
+{
+ return PMVariant( m_number );
+}
+
+void PMRuleCount::countChildProtected( const QString& className, bool )
+{
+ bool m = false;
+ QPtrListIterator<PMRuleCategory> it( m_categories );
+ for( ; it.current( ) && !m; ++it )
+ m = it.current( )->matches( className );
+ if( m )
+ m_number++;
+}
+
+void PMRuleCount::resetProtected( )
+{
+ m_number = 0;
+}
+
+PMRuleNot::PMRuleNot( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleCondition( )
+{
+ m_pChild = 0;
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) && !m_pChild )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ if( isCondition( me ) )
+ {
+ m_pChild = newCondition( me, globalGroups, localGroups );
+ m_children.append( m_pChild );
+ }
+ }
+ m = m.nextSibling( );
+ }
+}
+
+bool PMRuleNot::evaluate( const PMObject* object )
+{
+ if( m_pChild )
+ return !m_pChild->evaluate( object );
+ return true;
+}
+
+PMRuleAnd::PMRuleAnd( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleCondition( )
+{
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ if( isCondition( me ) )
+ {
+ PMRuleCondition* c = newCondition( me, globalGroups, localGroups );
+ m_children.append( c );
+ m_conditions.append( c );
+ }
+ }
+ m = m.nextSibling( );
+ }
+}
+
+bool PMRuleAnd::evaluate( const PMObject* object )
+{
+ bool b = true;
+ QPtrListIterator<PMRuleCondition> it( m_conditions );
+ for( ; it.current( ) && b; ++it )
+ b = it.current( )->evaluate( object );
+ return b;
+}
+
+PMRuleOr::PMRuleOr( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleCondition( )
+{
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ if( isCondition( me ) )
+ {
+ PMRuleCondition* c = newCondition( me, globalGroups, localGroups );
+ m_children.append( c );
+ m_conditions.append( c );
+ }
+ }
+ m = m.nextSibling( );
+ }
+}
+
+bool PMRuleOr::evaluate( const PMObject* object )
+{
+ bool b = false;
+ QPtrListIterator<PMRuleCondition> it( m_conditions );
+ for( ; it.current( ) && !b; ++it )
+ b = it.current( )->evaluate( object );
+ return b;
+}
+
+PMRuleBefore::PMRuleBefore( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleCondition( )
+{
+ m_contains = false;
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ if( isCategory( me ) )
+ m_categories.append( newCategory( me, globalGroups, localGroups ) );
+ }
+ m = m.nextSibling( );
+ }
+}
+
+PMRuleBefore::~PMRuleBefore( )
+{
+ m_categories.setAutoDelete( true );
+ m_categories.clear( );
+}
+
+bool PMRuleBefore::evaluate( const PMObject* )
+{
+ return m_contains;
+}
+
+void PMRuleBefore::countChildProtected( const QString& className,
+ bool afterInsertPoint )
+{
+ if( afterInsertPoint && !m_contains )
+ {
+ QPtrListIterator<PMRuleCategory> it( m_categories );
+ for( ; it.current( ) && !m_contains; ++it )
+ m_contains = it.current( )->matches( className );
+ }
+}
+
+void PMRuleBefore::resetProtected( )
+{
+ m_contains = false;
+}
+
+PMRuleAfter::PMRuleAfter( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleCondition( )
+{
+ m_contains = false;
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ if( isCategory( me ) )
+ m_categories.append( newCategory( me, globalGroups, localGroups ) );
+ }
+ m = m.nextSibling( );
+ }
+}
+
+PMRuleAfter::~PMRuleAfter( )
+{
+ m_categories.setAutoDelete( true );
+ m_categories.clear( );
+}
+
+bool PMRuleAfter::evaluate( const PMObject* )
+{
+ return m_contains;
+}
+
+void PMRuleAfter::countChildProtected( const QString& className,
+ bool afterInsertPoint )
+{
+ if( !afterInsertPoint && !m_contains )
+ {
+ QPtrListIterator<PMRuleCategory> it( m_categories );
+ for( ; it.current( ) && !m_contains; ++it )
+ m_contains = it.current( )->matches( className );
+ }
+}
+
+void PMRuleAfter::resetProtected( )
+{
+ m_contains = false;
+}
+
+PMRuleContains::PMRuleContains( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleCondition( )
+{
+ m_contains = false;
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ if( isCategory( me ) )
+ m_categories.append( newCategory( me, globalGroups, localGroups ) );
+ }
+ m = m.nextSibling( );
+ }
+}
+
+PMRuleContains::~PMRuleContains( )
+{
+ m_categories.setAutoDelete( true );
+ m_categories.clear( );
+}
+
+bool PMRuleContains::evaluate( const PMObject* )
+{
+ return m_contains;
+}
+
+void PMRuleContains::countChildProtected( const QString& className, bool )
+{
+ if( !m_contains )
+ {
+ QPtrListIterator<PMRuleCategory> it( m_categories );
+ for( ; it.current( ) && !m_contains; ++it )
+ m_contains = it.current( )->matches( className );
+ }
+}
+
+void PMRuleContains::resetProtected( )
+{
+ m_contains = false;
+}
+
+PMRuleCompare::PMRuleCompare( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleCondition( )
+{
+ m_pValue[0] = 0;
+ m_pValue[1] = 0;
+
+ int i = 0;
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) && !m_pValue[1] )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ if( isValue( me ) )
+ {
+ m_pValue[i] = newValue( me, globalGroups, localGroups );
+ m_children.append( m_pValue[i] );
+ i++;
+ }
+ }
+ m = m.nextSibling( );
+ }
+ if( !m_pValue[1] )
+ kdError( PMArea ) << "RuleSystem: Comparison needs two values" << endl;
+}
+
+bool PMRuleCompare::evaluate( const PMObject* object )
+{
+ if( !m_pValue[1] )
+ return false;
+
+ PMVariant v[2];
+ v[0] = m_pValue[0]->evaluate( object );
+ v[1] = m_pValue[1]->evaluate( object );
+
+ if( v[0].isNull( ) || v[1].isNull( ) )
+ return false;
+
+ bool convertError = false;
+
+ if( v[0].dataType( ) != v[1].dataType( ) )
+ {
+ if( m_pValue[1]->type( ) == "Constant" )
+ {
+ if( v[1].convertTo( v[0].dataType( ) ) )
+ ( ( PMRuleConstant* ) m_pValue[1] )->convertTo( v[0].dataType( ) );
+ else
+ convertError = true;
+ }
+ else if( m_pValue[0]->type( ) == "Constant" )
+ {
+ if( v[0].convertTo( v[1].dataType( ) ) )
+ ( ( PMRuleConstant* ) m_pValue[0] )->convertTo( v[1].dataType( ) );
+ else
+ convertError = true;
+ }
+ else
+ convertError = true;
+ }
+ if( convertError )
+ {
+ kdError( PMArea ) << "RuleSystem: Types in comparison must match" << endl;
+ return false;
+ }
+
+ return compare( v[0], v[1] );
+}
+
+PMRuleLess::PMRuleLess( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleCompare( e, globalGroups, localGroups )
+{
+}
+
+bool PMRuleLess::compare( const PMVariant& v1, const PMVariant& v2 )
+{
+ bool c = false;
+
+ switch( v1.dataType( ) )
+ {
+ case PMVariant::Integer:
+ c = v1.intData( ) < v2.intData( );
+ break;
+ case PMVariant::Unsigned:
+ c = v1.unsignedData( ) < v2.unsignedData( );
+ break;
+ case PMVariant::Double:
+ c = v1.doubleData( ) < v2.doubleData( );
+ break;
+ case PMVariant::String:
+ c = v1.stringData( ) < v2.stringData( );
+ break;
+ case PMVariant::Bool:
+ kdError( PMArea ) << "RuleSystem: Less: Can't compare booleans" << endl;
+ break;
+ case PMVariant::ThreeState:
+ kdError( PMArea ) << "RuleSystem: Less: Can't compare ThreeStates" << endl;
+ break;
+ case PMVariant::Vector:
+ kdError( PMArea ) << "RuleSystem: Less: Can't compare vectors" << endl;
+ break;
+ case PMVariant::Color:
+ kdError( PMArea ) << "RuleSystem: Less: Can't compare colors" << endl;
+ break;
+ case PMVariant::ObjectPointer:
+ kdError( PMArea ) << "RuleSystem: Less: Can't compare object pointers" << endl;
+ break;
+ case PMVariant::None:
+ kdError( PMArea ) << "RuleSystem: Less: Value has type none" << endl;
+ break;
+ }
+ return c;
+}
+
+PMRuleGreater::PMRuleGreater( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleCompare( e, globalGroups, localGroups )
+{
+}
+
+bool PMRuleGreater::compare( const PMVariant& v1, const PMVariant& v2 )
+{
+ bool c = false;
+
+ switch( v1.dataType( ) )
+ {
+ case PMVariant::Integer:
+ c = v1.intData( ) > v2.intData( );
+ break;
+ case PMVariant::Unsigned:
+ c = v1.unsignedData( ) > v2.unsignedData( );
+ break;
+ case PMVariant::Double:
+ c = v1.doubleData( ) > v2.doubleData( );
+ break;
+ case PMVariant::String:
+ c = v1.stringData( ) > v2.stringData( );
+ break;
+ case PMVariant::Bool:
+ kdError( PMArea ) << "RuleSystem: Greater: Can't compare booleans" << endl;
+ break;
+ case PMVariant::ThreeState:
+ kdError( PMArea ) << "RuleSystem: Greater: Can't compare ThreeStates" << endl;
+ break;
+ case PMVariant::Vector:
+ kdError( PMArea ) << "RuleSystem: Greater: Can't compare vectors" << endl;
+ break;
+ case PMVariant::Color:
+ kdError( PMArea ) << "RuleSystem: Greater: Can't compare colors" << endl;
+ break;
+ case PMVariant::ObjectPointer:
+ kdError( PMArea ) << "RuleSystem: Greater: Can't compare object pointers" << endl;
+ break;
+ case PMVariant::None:
+ kdError( PMArea ) << "RuleSystem: Greater: Value has type none" << endl;
+ break;
+ }
+ return c;
+}
+
+PMRuleEqual::PMRuleEqual( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleCompare( e, globalGroups, localGroups )
+{
+}
+
+bool PMRuleEqual::compare( const PMVariant& v1, const PMVariant& v2 )
+{
+ bool c = false;
+
+ switch( v1.dataType( ) )
+ {
+ case PMVariant::Integer:
+ c = v1.intData( ) == v2.intData( );
+ break;
+ case PMVariant::Unsigned:
+ c = v1.unsignedData( ) == v2.unsignedData( );
+ break;
+ case PMVariant::Double:
+ c = v1.doubleData( ) == v2.doubleData( );
+ break;
+ case PMVariant::String:
+ c = v1.stringData( ) == v2.stringData( );
+ break;
+ case PMVariant::Bool:
+ c = v1.boolData( ) == v2.boolData( );
+ break;
+ case PMVariant::ThreeState:
+ c = v1.threeStateData( ) == v2.threeStateData( );
+ break;
+ case PMVariant::Vector:
+ kdError( PMArea ) << "RuleSystem: Equal: Can't compare vectors" << endl;
+ break;
+ case PMVariant::Color:
+ kdError( PMArea ) << "RuleSystem: Equal: Can't compare colors" << endl;
+ break;
+ case PMVariant::ObjectPointer:
+ kdError( PMArea ) << "RuleSystem: Equal: Can't compare object pointers" << endl;
+ break;
+ case PMVariant::None:
+ kdError( PMArea ) << "RuleSystem: Equal: Value has type none" << endl;
+ break;
+ }
+ return c;
+}
+
+
+PMRule::PMRule( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleBase( )
+{
+ m_pCondition = 0;
+
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) && !m_pCondition )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ if( isCategory( me ) )
+ m_categories.append( newCategory( me, globalGroups, localGroups ) );
+ else if( isCondition( me ) )
+ {
+ m_pCondition = newCondition( me, globalGroups, localGroups );
+ m_children.append( m_pCondition );
+ }
+ }
+ m = m.nextSibling( );
+ }
+}
+
+PMRule::~PMRule( )
+{
+ m_categories.setAutoDelete( true );
+ m_categories.clear( );
+}
+
+bool PMRule::matches( const QString& className )
+{
+ bool m = false;
+ QPtrListIterator<PMRuleCategory> it( m_categories );
+ for( ; it.current( ) && !m; ++it )
+ m = it.current( )->matches( className );
+ return m;
+}
+
+bool PMRule::evaluate( const PMObject* parent )
+{
+ if( !m_pCondition )
+ return true;
+ else
+ return m_pCondition->evaluate( parent );
+}
+
+PMRuleTargetClass::PMRuleTargetClass( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups )
+{
+ m_class = e.attribute( "name" );
+ if( m_class.isEmpty( ) )
+ kdError( PMArea ) << "RuleSystem: Invalid class name" << endl;
+
+ appendRules( e, globalGroups );
+}
+
+void PMRuleTargetClass::appendRules( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups )
+{
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ if( me.tagName( ) == "definegroup" )
+ m_groups.append( new PMRuleDefineGroup( me, globalGroups, m_groups ) );
+ if( me.tagName( ) == "rule" )
+ m_rules.append( new PMRule( me, globalGroups, m_groups ) );
+ if( me.tagName( ) == "exception" )
+ m_exceptions.append( me.attribute( "class" ) );
+ }
+ m = m.nextSibling( );
+ }
+}
+
+PMRuleTargetClass::~PMRuleTargetClass( )
+{
+ m_groups.setAutoDelete( true );
+ m_groups.clear( );
+ m_rules.setAutoDelete( true );
+ m_rules.clear( );
+}
+
+PMInsertRuleSystem::PMInsertRuleSystem( PMPart* part )
+{
+ m_pPart = part;
+}
+
+PMInsertRuleSystem::~PMInsertRuleSystem( )
+{
+ m_groups.setAutoDelete( true );
+ m_groups.clear( );
+ m_classRules.setAutoDelete( true );
+ m_classRules.clear( );
+}
+
+void PMInsertRuleSystem::loadRules( const QString& fileName )
+{
+ PMRuleClass::s_pPrototypeManager = m_pPart->prototypeManager( );
+ if( m_loadedFiles.find( fileName ) != m_loadedFiles.end( ) )
+ return;
+ m_loadedFiles.push_back( fileName );
+
+
+ QString ruleFile = locate( "data", QString( "kpovmodeler/" + fileName ) );
+ if( ruleFile.isEmpty( ) )
+ {
+ kdError( PMArea ) << "Rule file 'kpovmodeler/" << fileName
+ << "' not found." << endl;
+ return;
+ }
+
+ QFile file( ruleFile );
+ if( !file.open( IO_ReadOnly ) )
+ {
+ kdError( PMArea ) << "Could not open rule file 'kpovmodeler/" << fileName
+ << "'" << endl;
+ return;
+ }
+
+ QDomDocument doc( "insertrules" );
+ doc.setContent( &file );
+
+ QDomElement e = doc.documentElement( );
+ if( e.attribute( "format" ) != "1.0" )
+ kdError( PMArea ) << "Rule format " << e.attribute( "format" )
+ << " not supported." << endl;
+ else
+ {
+ QDomNode c = e.firstChild( );
+ QPtrList<PMRuleDefineGroup> dummyLocalGroups;
+
+ while( !c.isNull( ) )
+ {
+ if( c.isElement( ) )
+ {
+ QDomElement ce = c.toElement( );
+ if( ce.tagName( ) == "definegroup" )
+ m_groups.append( new PMRuleDefineGroup( ce, m_groups,
+ dummyLocalGroups ) );
+ else if( ce.tagName( ) == "targetclass" )
+ {
+ QString className = ce.attribute( "name" );
+ // find a target class with the same name
+ PMRuleTargetClass* target = 0;
+
+ if( !m_rulesDict.isEmpty( ) )
+ target = m_rulesDict.find( className );
+
+ if( target )
+ target->appendRules( ce, m_groups );
+ else
+ {
+ target = new PMRuleTargetClass( ce, m_groups );
+ m_rulesDict.insert( className, target );
+ m_classRules.append( target );
+ }
+ }
+ }
+ c = c.nextSibling( );
+ }
+ }
+ file.close( );
+
+ PMRuleClass::s_pPrototypeManager = 0;
+}
+
+bool PMInsertRuleSystem::canInsert( const PMObject* parentObject,
+ const QString& className,
+ const PMObject* after,
+ const PMObjectList* objectsBetween )
+{
+ bool possible = false;
+
+ // find rules for target class
+ PMMetaObject* meta = parentObject->metaObject( );
+ for( ; meta && !possible; meta = meta->superClass( ) )
+ {
+ PMRuleTargetClass* tc = m_rulesDict.find( meta->className( ) );
+ if( tc )
+ {
+ // check the exception list
+ QStringList exceptions = tc->exceptions( );
+ bool exceptionFound = false;
+ QStringList::ConstIterator it;
+ for( it = exceptions.begin( );
+ it != exceptions.end( ) && !exceptionFound; ++it )
+ if( parentObject->isA( *it ) )
+ exceptionFound = true;
+
+ if( !exceptionFound )
+ {
+ QPtrListIterator<PMRule> rit = tc->rules( );
+ // find matching rules for class name
+ for( ; rit.current( ) && !possible; ++rit )
+ {
+ PMRule* rule = rit.current( );
+ if( rule->matches( className ) )
+ {
+ // matching rule found
+ // reset the rule
+ rit.current( )->reset( );
+
+ // count already inserted child objects
+ bool afterInsertPoint = false;
+ PMObject* o = parentObject->firstChild( );
+ if( !after )
+ afterInsertPoint = true;
+ for( ; o; o = o->nextSibling( ) )
+ {
+ rule->countChild( o->className( ), afterInsertPoint );
+ if( o == after )
+ afterInsertPoint = true;
+ }
+ if( objectsBetween )
+ {
+ PMObjectListIterator it( *objectsBetween );
+ for( ; it.current( ); ++it )
+ rule->countChild( it.current( )->type( ), false );
+ }
+
+ // evaluate condition value
+ possible = rule->evaluate( parentObject );
+ }
+ }
+ }
+ }
+ }
+
+ return possible;
+}
+
+bool PMInsertRuleSystem::canInsert( const PMObject* parentObject,
+ const PMObject* object,
+ const PMObject* after,
+ const PMObjectList* objectsBetween )
+{
+ return canInsert( parentObject, object->type( ), after, objectsBetween );
+}
+
+int PMInsertRuleSystem::canInsert( const PMObject* parentObject,
+ const PMObjectList& list,
+ const PMObject* after )
+{
+ PMObjectListIterator it( list );
+ QStringList classes;
+ for( ; it.current( ); ++it )
+ classes.append( it.current( )->type( ) );
+ return canInsert( parentObject, classes, after );
+}
+
+int PMInsertRuleSystem::canInsert( const PMObject* parentObject,
+ const QStringList& list,
+ const PMObject* after )
+{
+ if( list.size( ) == 1 )
+ {
+ // more efficient
+ if( canInsert( parentObject, list.first( ), after ) )
+ return 1;
+ else
+ return 0;
+ }
+
+ // find rules for target class
+ QPtrList<PMRuleTargetClass> targetClassList;
+ PMMetaObject* meta = parentObject->metaObject( );
+ for( ; meta; meta = meta->superClass( ) )
+ {
+ PMRuleTargetClass* tc = m_rulesDict.find( meta->className( ) );
+ if( tc )
+ targetClassList.append( tc );
+ }
+ if( targetClassList.isEmpty( ) )
+ return 0; // not rules found
+
+ // count already inserted children
+ QPtrListIterator<PMRuleTargetClass> tit( targetClassList );
+ for( ; tit.current( ); ++tit ) // ... for all target classes
+ {
+ QPtrListIterator<PMRule> rit = tit.current( )->rules( );
+ for( ; rit.current( ); ++rit ) // ... and all rules
+ {
+ rit.current( )->reset( );
+ bool afterInsertPoint = false;
+ PMObject* o = parentObject->firstChild( );
+ if( !after )
+ afterInsertPoint = true;
+ for( ; o; o = o->nextSibling( ) )
+ {
+ rit.current( )->countChild( o->className( ), afterInsertPoint );
+ if( o == after )
+ afterInsertPoint = true;
+ }
+ }
+ }
+
+ int number = 0;
+ QStringList::const_iterator oit;
+
+ for( oit = list.begin( ); oit != list.end( ); ++oit )
+ {
+ bool possible = false;
+ for( tit.toFirst( ); tit.current( ) && !possible; ++tit )
+ {
+ QPtrListIterator<PMRule> rit = tit.current( )->rules( );
+
+ for( ; rit.current( ) && !possible; ++rit )
+ {
+ PMRule* rule = rit.current( );
+ if( rule->matches( *oit ) )
+ possible = rule->evaluate( parentObject );
+ }
+ }
+ if( possible )
+ {
+ // object can be inserted, count it
+ for( ; tit.current( ); ++tit )
+ {
+ QPtrListIterator<PMRule> rit = tit.current( )->rules( );
+ for( ; rit.current( ); ++rit )
+ rit.current( )->countChild( *oit, false );
+ }
+ number++;
+ }
+ }
+
+ return number;
+}