summaryrefslogtreecommitdiffstats
path: root/kpovmodeler/pmmovecommand.cpp
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit47d455dd55be855e4cc691c32f687f723d9247ee (patch)
tree52e236aaa2576bdb3840ebede26619692fed6d7d /kpovmodeler/pmmovecommand.cpp
downloadtdegraphics-47d455dd55be855e4cc691c32f687f723d9247ee.tar.gz
tdegraphics-47d455dd55be855e4cc691c32f687f723d9247ee.zip
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/kdegraphics@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kpovmodeler/pmmovecommand.cpp')
-rw-r--r--kpovmodeler/pmmovecommand.cpp478
1 files changed, 478 insertions, 0 deletions
diff --git a/kpovmodeler/pmmovecommand.cpp b/kpovmodeler/pmmovecommand.cpp
new file mode 100644
index 00000000..1d70f3e0
--- /dev/null
+++ b/kpovmodeler/pmmovecommand.cpp
@@ -0,0 +1,478 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 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 "pmmovecommand.h"
+#include "pmobject.h"
+#include "pmpart.h"
+#include "pmcommandmanager.h"
+#include "pmdeclare.h"
+#include "pmerrorflags.h"
+#include "pmrecursiveobjectiterator.h"
+#include "pmmemento.h"
+#include "pmdebug.h"
+
+#include <klocale.h>
+#include <qptrdict.h>
+
+PMMoveCommand::PMMoveCommand( PMObject* obj, PMObject* parent, PMObject* after )
+ : PMCommand( i18n( "Move %1" ).arg( obj->description( ) ) )
+{
+ m_pParent = parent;
+ m_pAfter = after;
+
+ if( obj->parent( ) )
+ {
+ m_infoList.append( new PMDeleteInfo( obj ) );
+ }
+ else
+ {
+ // object has no parent!
+ // top level objects can't be moved, move all child items
+ PMObject* tmp;
+ for( tmp = obj->firstChild( ); tmp; tmp = tmp->nextSibling( ) )
+ m_infoList.append( new PMDeleteInfo( tmp ) );
+ }
+
+ m_executed = false;
+ m_firstExecution = true;
+}
+
+PMMoveCommand::PMMoveCommand( const PMObjectList& list, PMObject* parent,
+ PMObject* after )
+ : PMCommand( i18n( "Move Objects" ) )
+{
+ PMObjectListIterator it( list );
+
+ for( ; it.current( ); ++it )
+ {
+ if( it.current( )->parent( ) )
+ m_infoList.append( new PMDeleteInfo( it.current( ) ) );
+ else
+ {
+ // object has no parent!
+ // top level objects can't be moved, move all child items
+ PMObject* tmp;
+ for( tmp = it.current( )->firstChild( ); tmp; tmp = tmp->nextSibling( ) )
+ m_infoList.append( new PMDeleteInfo( tmp ) );
+ }
+ }
+
+ m_pParent = parent;
+ m_pAfter = after;
+ m_executed = false;
+ m_firstExecution = true;
+}
+
+PMMoveCommand::~PMMoveCommand( )
+{
+ if( m_executed )
+ {
+ m_insertErrors.setAutoDelete( true );
+ m_insertErrors.clear( );
+ }
+}
+
+void PMMoveCommand::execute( PMCommandManager* theManager )
+{
+ if( !m_executed )
+ {
+ // remove objects
+ PMDeleteInfoListIterator it( m_infoList );
+ PMObject* prev = m_pAfter;
+ PMObject* obj;
+ bool error = false;
+ PMDeleteInfo* info = 0;
+ PMObject* parent;
+
+ for( it.toLast( ); it.current( ); --it )
+ {
+ info = it.current( );
+ parent = info->parent( );
+ // signal has to be emitted before the item is removed
+ theManager->cmdObjectChanged( info->deletedObject( ), PMCRemove );
+ if( m_firstExecution )
+ if( parent->dataChangeOnInsertRemove( )
+ && !parent->mementoCreated( ) )
+ parent->createMemento( );
+ parent->takeChild( info->deletedObject( ) );
+ }
+
+ // insert at new position
+ if( m_firstExecution )
+ if( m_pParent->dataChangeOnInsertRemove( )
+ && !m_pParent->mementoCreated( ) )
+ m_pParent->createMemento( );
+
+ for( it.toFirst( ); it.current( ); ++it )
+ {
+ if( !it.current( )->insertError( ) )
+ {
+ obj = it.current( )->deletedObject( );
+
+ if( !prev )
+ {
+ if( m_pParent->canInsert( obj, 0 ) )
+ {
+ m_pParent->insertChild( obj, 0 );
+ prev = obj;
+ theManager->cmdObjectChanged( obj, PMCAdd );
+ }
+ else
+ error = true;
+ }
+ else
+ {
+ if( m_pParent->canInsert( obj, prev ) )
+ {
+ m_pParent->insertChildAfter( obj, prev );
+ prev = obj;
+ theManager->cmdObjectChanged( obj, PMCAdd );
+ }
+ else
+ error = true;
+ }
+
+ if( error )
+ {
+ m_insertErrors.append( it.current( )->deletedObject( ) );
+ it.current( )->setInsertError( );
+ theManager->cmdObjectChanged( obj, PMCAdd | PMCInsertError );
+ error = false;
+ }
+ }
+ }
+
+ if( m_firstExecution )
+ {
+ if( m_pParent->mementoCreated( ) )
+ m_dataChanges.append( m_pParent->takeMemento( ) );
+
+ for( it.toLast( ); it.current( ); --it )
+ {
+ info = it.current( );
+ parent = info->parent( );
+
+ if( parent->mementoCreated( ) )
+ m_dataChanges.append( parent->takeMemento( ) );
+ }
+ }
+
+ QPtrListIterator<PMMemento> mit( m_dataChanges );
+ for( ; mit.current( ); ++mit )
+ {
+ PMObjectChangeListIterator change = mit.current( )->changedObjects( );
+ for( ; change.current( ); ++change )
+ theManager->cmdObjectChanged( change.current( )->object( ),
+ change.current( )->mode( ) );
+ }
+
+ m_executed = true;
+ m_firstExecution = true;
+ }
+}
+
+void PMMoveCommand::undo( PMCommandManager* theManager )
+{
+ if( m_executed )
+ {
+ PMDeleteInfoListIterator it( m_infoList );
+ PMObject* obj;
+ for( it.toLast( ) ; it.current( ); --it )
+ {
+ // signal has to be emitted before the item is removed
+ obj = it.current( )->deletedObject( );
+ theManager->cmdObjectChanged( obj, PMCRemove );
+ if( obj->parent( ) )
+ obj->parent( )->takeChild( obj );
+ }
+
+ for( it.toFirst( ); it.current( ); ++it )
+ {
+ obj = it.current( )->deletedObject( );
+ if( it.current( )->prevSibling( ) )
+ it.current( )->parent( )
+ ->insertChildAfter( obj, it.current( )->prevSibling( ) );
+ else
+ it.current( )->parent( )->insertChild( obj, 0 );
+ theManager->cmdObjectChanged( obj, PMCAdd );
+ }
+
+ QPtrListIterator<PMMemento> mit( m_dataChanges );
+ for( ; mit.current( ); ++mit )
+ {
+ mit.current( )->originator( )->restoreMemento( mit.current( ) );
+ PMObjectChangeListIterator change = mit.current( )->changedObjects( );
+ for( ; change.current( ); ++change )
+ theManager->cmdObjectChanged( change.current( )->object( ),
+ change.current( )->mode( ) );
+ }
+
+ m_executed = false;
+ }
+}
+
+int PMMoveCommand::errorFlags( PMPart* )
+{
+ PMDeleteInfo* info;
+ PMDeclare* decl = 0;
+ PMObject* obj;
+ bool insideSelection;
+ bool ok = true;
+ bool declareInsertError = false;
+ bool error = false;
+ bool stop;
+
+ // dictionary of deleted objects
+ QPtrDict<bool> deletedObjects( 1009 );
+ deletedObjects.setAutoDelete( true );
+ QPtrDict<bool> objectsAfterInsertPosition( 1009 );
+ objectsAfterInsertPosition.setAutoDelete( true );
+ QPtrDict<bool> declaresBeforeInsertPosition( 199 );
+ declaresBeforeInsertPosition.setAutoDelete( true );
+
+
+ PMDeleteInfoListIterator it( m_infoList );
+ for( ; it.current( ); ++it )
+ deletedObjects.insert( it.current( )->deletedObject( ),
+ new bool( true ) );
+
+ // declares can only be moved, if all linked
+ // objects are moved as well or the insert position is before the first
+ // linked object and all declares can be inserted
+
+ info = m_infoList.last( );
+
+ while( info )
+ {
+ ok = true;
+ declareInsertError = false;
+
+ if( info->deletedObject( )->isA( "Declare" ) )
+ {
+ decl = ( PMDeclare* ) ( info->deletedObject( ) );
+
+ if( !m_pParent->canInsert( decl, m_pAfter ) )
+ {
+ declareInsertError = true;
+ ok = false;
+ }
+ else
+ {
+ PMObjectListIterator links = decl->linkedObjects( );
+
+ for( ; links.current( ) && ok; ++links )
+ {
+ insideSelection = false;
+ for( obj = links.current( ); obj && !insideSelection;
+ obj = obj->parent( ) )
+ {
+ if( deletedObjects.find( obj ) )
+ insideSelection = true;
+ }
+
+ if( insideSelection )
+ {
+ bool stop = false;
+ for( obj = links.current( ); obj && !stop; obj = obj->parent( ) )
+ {
+ if( deletedObjects.find( obj ) )
+ stop = true;
+ else
+ deletedObjects.insert( obj, new bool( true ) );
+ }
+ }
+ else
+ {
+ // link will not be moved
+ // check, if after insert position
+ // declares can only be inserted as childs of the scene
+
+ if( m_pAfter )
+ {
+ // insert point is not the first item
+ // find the top level parent item
+ stop = false;
+ obj = links.current( );
+ do
+ {
+ if( obj->parent( ) )
+ {
+ if( obj->parent( )->type( ) == "Scene" )
+ stop = true;
+ else
+ obj = obj->parent( );
+ }
+ else
+ stop = true; // error
+ }
+ while( !stop );
+
+ PMObject* topParent = obj;
+
+ // check if insert point is before the top level
+ // parent object
+
+ if( !objectsAfterInsertPosition.find( obj ) )
+ {
+ stop = false;
+ obj = obj->prevSibling( );
+ while( obj && !stop )
+ {
+ if( obj == m_pAfter )
+ stop = true;
+ else if( objectsAfterInsertPosition.find( obj ) )
+ stop = true;
+ else
+ obj = obj->prevSibling( );
+ }
+
+ if( stop )
+ objectsAfterInsertPosition.insert( topParent, new bool( true ) );
+ else
+ ok = false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if( !ok )
+ {
+ if( declareInsertError )
+ m_errors.prepend( i18n( "Can't insert the declare \"%1\" at that point." )
+ .arg( decl->id( ) ) );
+ else
+ m_errors.prepend( i18n( "The declare \"%1\" can't be moved behind linked objects." )
+ .arg( decl->id( ) ) );
+
+ PMDeleteInfo* tmp = info;
+ info = m_infoList.prev( );
+ deletedObjects.remove( tmp->deletedObject( ) );
+ m_infoList.removeRef( tmp );
+
+ error = true;
+ }
+ else
+ info = m_infoList.prev( );
+ }
+
+ // check if links are moved before the declare object
+
+ // find all declares bevore the insert position
+ if( m_pParent->type( ) == "Scene" )
+ obj = m_pAfter;
+ else
+ {
+ stop = false;
+ obj = m_pParent;
+ do
+ {
+ if( obj->parent( ) )
+ {
+ if( obj->parent( )->type( ) == "Scene" )
+ stop = true;
+ else
+ obj = obj->parent( );
+ }
+ else
+ stop = true; // error
+ }
+ while( !stop );
+
+ if( obj )
+ obj = obj->prevSibling( );
+ }
+
+ while( obj )
+ {
+ if( obj->isA( "Declare" ) )
+ declaresBeforeInsertPosition.insert( obj, new bool( true ) );
+ obj = obj->prevSibling( );
+ }
+
+ info = m_infoList.first( );
+ while( info )
+ {
+ ok = true;
+ PMRecursiveObjectIterator it( info->deletedObject( ) );
+ PMObject* linked = 0;
+
+ while( it.current( ) && ok )
+ {
+ linked = it.current( )->linkedObject( );
+
+ if( linked )
+ {
+ if( !deletedObjects.find( linked ) )
+ {
+ // Object is linked to a declare and the declare
+ // will not be moved.
+ // Check, if the insert point is after the declare
+
+ if( !declaresBeforeInsertPosition.find( linked ) )
+ ok = false;
+ }
+ }
+
+ if( ok )
+ ++it;
+ }
+
+ if( ok )
+ info = m_infoList.next( );
+ else
+ {
+ if( linked )
+ {
+ obj = info->deletedObject( );
+ QString name = obj->name( );
+ decl = ( PMDeclare* ) linked;
+
+ if( name.isEmpty( ) )
+ name = i18n( "(unnamed)" );
+ m_errors.append( i18n( "The %1 \"%2\" can't be moved because it "
+ "contains a link to the declare \"%3\" "
+ "and the insert point is not after "
+ "the declare." )
+ .arg( obj->description( ) ).arg( name )
+ .arg( decl->id( ) ) );
+ }
+ else
+ kdError( PMArea ) << "linked is 0 in PMMoveCommand::errorFlags\n";
+
+
+ PMDeleteInfo* tmp = info;
+ info = m_infoList.next( );
+ deletedObjects.remove( tmp->deletedObject( ) );
+ m_infoList.removeRef( tmp );
+
+ error = true;
+ }
+ }
+
+ if( error )
+ {
+ if( m_infoList.count( ) == 0 )
+ return PMEError | PMEFatal;
+ else
+ return PMEError;
+ }
+
+ return PMENone;
+}