/* ************************************************************************** description -------------------- copyright : (C) 2002-2003 by Andreas Zehender email : zehender@kde.org ************************************************************************** ************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * **************************************************************************/ #include "pminsertrulesystem.h" #include "pmprototypemanager.h" #include "pmpart.h" #include "pmvariant.h" #include "pmdebug.h" #include #include bool isCategory( TQDomElement& e ) { return( e.tagName( ) == "class" || e.tagName( ) == "group" ); } PMRuleCategory* newCategory( TQDomElement& e, TQPtrList& globalGroups, TQPtrList& 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( TQDomElement& 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 TQString& className ) { return m_pPrototypeManager->isA( className, m_className ); } PMRuleGroup::PMRuleGroup( TQDomElement& e, TQPtrList& globalGroups, TQPtrList& localGroups ) : PMRuleCategory( ) { m_pGroup = 0; TQString groupName = e.attribute( "name" ); if( groupName.isEmpty( ) ) kdError( PMArea ) << "RuleSystem: Invalid group name" << endl; // find group TQPtrListIterator lit( localGroups ); for( ; lit.current( ) && !m_pGroup; ++lit ) if( lit.current( )->name( ) == groupName ) m_pGroup = lit.current( ); TQPtrListIterator 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 TQString& className ) { if( m_pGroup ) return m_pGroup->matches( className ); return false; } PMRuleDefineGroup::PMRuleDefineGroup( TQDomElement& e, TQPtrList& globalGroups, TQPtrList& localGroups ) { m_name = e.attribute( "name" ); if( m_name.isEmpty( ) ) kdError( PMArea ) << "RuleSystem: Invalid group name" << endl; TQDomNode m = e.firstChild( ); while( !m.isNull( ) ) { if( m.isElement( ) ) { TQDomElement 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 TQString& className ) { bool m = false; TQPtrListIterator it( m_categories ); for( ; it.current( ) && !m; ++it ) m = it.current( )->matches( className ); return m; } bool isValue( TQDomElement& e ) { return( e.tagName( ) == "property" || e.tagName( ) == "const" || e.tagName( ) == "count" ); } bool isCondition( TQDomElement& 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( TQDomElement& e, TQPtrList& globalGroups, TQPtrList& 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( TQDomElement& e, TQPtrList& globalGroups, TQPtrList& 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 TQString& className, bool afterInsertPoint ) { countChildProtected( className, afterInsertPoint ); TQPtrListIterator it( m_children ); for( ; it.current( ); ++it ) it.current( )->countChild( className, afterInsertPoint ); } void PMRuleBase::reset( ) { resetProtected( ); TQPtrListIterator it( m_children ); for( ; it.current( ); ++it ) it.current( )->reset( ); } PMRuleProperty::PMRuleProperty( TQDomElement& 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( TQDomElement& e ) : PMRuleValue( ) { TQString 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( TQDomElement& e, TQPtrList& globalGroups, TQPtrList& localGroups ) : PMRuleValue( ) { m_number = 0; TQDomNode m = e.firstChild( ); while( !m.isNull( ) ) { if( m.isElement( ) ) { TQDomElement 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 TQString& className, bool ) { bool m = false; TQPtrListIterator 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( TQDomElement& e, TQPtrList& globalGroups, TQPtrList& localGroups ) : PMRuleCondition( ) { m_pChild = 0; TQDomNode m = e.firstChild( ); while( !m.isNull( ) && !m_pChild ) { if( m.isElement( ) ) { TQDomElement 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( TQDomElement& e, TQPtrList& globalGroups, TQPtrList& localGroups ) : PMRuleCondition( ) { TQDomNode m = e.firstChild( ); while( !m.isNull( ) ) { if( m.isElement( ) ) { TQDomElement 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; TQPtrListIterator it( m_conditions ); for( ; it.current( ) && b; ++it ) b = it.current( )->evaluate( object ); return b; } PMRuleOr::PMRuleOr( TQDomElement& e, TQPtrList& globalGroups, TQPtrList& localGroups ) : PMRuleCondition( ) { TQDomNode m = e.firstChild( ); while( !m.isNull( ) ) { if( m.isElement( ) ) { TQDomElement 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; TQPtrListIterator it( m_conditions ); for( ; it.current( ) && !b; ++it ) b = it.current( )->evaluate( object ); return b; } PMRuleBefore::PMRuleBefore( TQDomElement& e, TQPtrList& globalGroups, TQPtrList& localGroups ) : PMRuleCondition( ) { m_contains = false; TQDomNode m = e.firstChild( ); while( !m.isNull( ) ) { if( m.isElement( ) ) { TQDomElement 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 TQString& className, bool afterInsertPoint ) { if( afterInsertPoint && !m_contains ) { TQPtrListIterator it( m_categories ); for( ; it.current( ) && !m_contains; ++it ) m_contains = it.current( )->matches( className ); } } void PMRuleBefore::resetProtected( ) { m_contains = false; } PMRuleAfter::PMRuleAfter( TQDomElement& e, TQPtrList& globalGroups, TQPtrList& localGroups ) : PMRuleCondition( ) { m_contains = false; TQDomNode m = e.firstChild( ); while( !m.isNull( ) ) { if( m.isElement( ) ) { TQDomElement 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 TQString& className, bool afterInsertPoint ) { if( !afterInsertPoint && !m_contains ) { TQPtrListIterator it( m_categories ); for( ; it.current( ) && !m_contains; ++it ) m_contains = it.current( )->matches( className ); } } void PMRuleAfter::resetProtected( ) { m_contains = false; } PMRuleContains::PMRuleContains( TQDomElement& e, TQPtrList& globalGroups, TQPtrList& localGroups ) : PMRuleCondition( ) { m_contains = false; TQDomNode m = e.firstChild( ); while( !m.isNull( ) ) { if( m.isElement( ) ) { TQDomElement 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 TQString& className, bool ) { if( !m_contains ) { TQPtrListIterator it( m_categories ); for( ; it.current( ) && !m_contains; ++it ) m_contains = it.current( )->matches( className ); } } void PMRuleContains::resetProtected( ) { m_contains = false; } PMRuleCompare::PMRuleCompare( TQDomElement& e, TQPtrList& globalGroups, TQPtrList& localGroups ) : PMRuleCondition( ) { m_pValue[0] = 0; m_pValue[1] = 0; int i = 0; TQDomNode m = e.firstChild( ); while( !m.isNull( ) && !m_pValue[1] ) { if( m.isElement( ) ) { TQDomElement 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( TQDomElement& e, TQPtrList& globalGroups, TQPtrList& 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( TQDomElement& e, TQPtrList& globalGroups, TQPtrList& 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( TQDomElement& e, TQPtrList& globalGroups, TQPtrList& 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( TQDomElement& e, TQPtrList& globalGroups, TQPtrList& localGroups ) : PMRuleBase( ) { m_pCondition = 0; TQDomNode m = e.firstChild( ); while( !m.isNull( ) && !m_pCondition ) { if( m.isElement( ) ) { TQDomElement 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 TQString& className ) { bool m = false; TQPtrListIterator 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( TQDomElement& e, TQPtrList& globalGroups ) { m_class = e.attribute( "name" ); if( m_class.isEmpty( ) ) kdError( PMArea ) << "RuleSystem: Invalid class name" << endl; appendRules( e, globalGroups ); } void PMRuleTargetClass::appendRules( TQDomElement& e, TQPtrList& globalGroups ) { TQDomNode m = e.firstChild( ); while( !m.isNull( ) ) { if( m.isElement( ) ) { TQDomElement 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 TQString& fileName ) { PMRuleClass::s_pPrototypeManager = m_pPart->prototypeManager( ); if( m_loadedFiles.find( fileName ) != m_loadedFiles.end( ) ) return; m_loadedFiles.push_back( fileName ); TQString ruleFile = locate( "data", TQString( "kpovmodeler/" + fileName ) ); if( ruleFile.isEmpty( ) ) { kdError( PMArea ) << "Rule file 'kpovmodeler/" << fileName << "' not found." << endl; return; } TQFile file( ruleFile ); if( !file.open( IO_ReadOnly ) ) { kdError( PMArea ) << "Could not open rule file 'kpovmodeler/" << fileName << "'" << endl; return; } TQDomDocument doc( "insertrules" ); doc.setContent( &file ); TQDomElement e = doc.documentElement( ); if( e.attribute( "format" ) != "1.0" ) kdError( PMArea ) << "Rule format " << e.attribute( "format" ) << " not supported." << endl; else { TQDomNode c = e.firstChild( ); TQPtrList dummyLocalGroups; while( !c.isNull( ) ) { if( c.isElement( ) ) { TQDomElement ce = c.toElement( ); if( ce.tagName( ) == "definegroup" ) m_groups.append( new PMRuleDefineGroup( ce, m_groups, dummyLocalGroups ) ); else if( ce.tagName( ) == "targetclass" ) { TQString 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 TQString& 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 TQStringList exceptions = tc->exceptions( ); bool exceptionFound = false; TQStringList::ConstIterator it; for( it = exceptions.begin( ); it != exceptions.end( ) && !exceptionFound; ++it ) if( parentObject->isA( *it ) ) exceptionFound = true; if( !exceptionFound ) { TQPtrListIterator 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 ); TQStringList classes; for( ; it.current( ); ++it ) classes.append( it.current( )->type( ) ); return canInsert( parentObject, classes, after ); } int PMInsertRuleSystem::canInsert( const PMObject* parentObject, const TQStringList& 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 TQPtrList 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 TQPtrListIterator tit( targetClassList ); for( ; tit.current( ); ++tit ) // ... for all target classes { TQPtrListIterator 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; TQStringList::const_iterator oit; for( oit = list.begin( ); oit != list.end( ); ++oit ) { bool possible = false; for( tit.toFirst( ); tit.current( ) && !possible; ++tit ) { TQPtrListIterator 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 ) { TQPtrListIterator rit = tit.current( )->rules( ); for( ; rit.current( ); ++rit ) rit.current( )->countChild( *oit, false ); } number++; } } return number; }